diff --git a/js/src/jsapi.cpp b/js/src/jsapi.cpp index 620591fd7ec..dd1f50fb46e 100644 --- a/js/src/jsapi.cpp +++ b/js/src/jsapi.cpp @@ -3900,7 +3900,7 @@ JS_Enumerate(JSContext *cx, JSObject *obj) CHECK_REQUEST(cx); JSIdArray *ida; - if (!EnumerateOwnProperties(cx, obj, &ida)) + if (!GetPropertyNames(cx, obj, JSITER_OWNONLY, &ida)) return false; for (size_t n = 0; n < size_t(ida->length); ++n) JS_ASSERT(js_CheckForStringIndex(ida->vector[n]) == ida->vector[n]); diff --git a/js/src/jsatom.cpp b/js/src/jsatom.cpp index 08a77c95934..f12df242773 100644 --- a/js/src/jsatom.cpp +++ b/js/src/jsatom.cpp @@ -191,11 +191,12 @@ const char *const js_common_atom_names[] = { "delete", /* deleteAtom */ "getOwnPropertyNames", /* getOwnPropertyNames */ "enumerate", /* enumerateAtom */ - "fix", + "fix", /* fixAtom */ "has", /* hasAtom */ "hasOwn", /* hasOwnAtom */ - "enumerateOwn" /* enumerateOwnAtom */ + "enumerateOwn", /* enumerateOwnAtom */ + "iterate" /* iterateAtom */ }; JS_STATIC_ASSERT(JS_ARRAY_LENGTH(js_common_atom_names) * sizeof(JSAtom *) == diff --git a/js/src/jsatom.h b/js/src/jsatom.h index 1cb5a1880fd..05b820b945d 100644 --- a/js/src/jsatom.h +++ b/js/src/jsatom.h @@ -308,6 +308,7 @@ struct JSAtomState { JSAtom *hasAtom; JSAtom *hasOwnAtom; JSAtom *enumerateOwnAtom; + JSAtom *iterateAtom; /* Less frequently used atoms, pinned lazily by JS_ResolveStandardClass. */ struct { diff --git a/js/src/jsiter.cpp b/js/src/jsiter.cpp index 0a94f39cace..75110ac0559 100644 --- a/js/src/jsiter.cpp +++ b/js/src/jsiter.cpp @@ -233,15 +233,15 @@ EnumerateDenseArrayProperties(JSContext *cx, JSObject *obj, JSObject *pobj, uint return true; } -static bool -MakeNativeIterator(JSContext *cx, uintN flags, uint32 *sarray, uint32 slength, uint32 key, - jsval *parray, uint32 plength, NativeIterator **nip) +NativeIterator * +NativeIterator::allocate(JSContext *cx, uintN flags, uint32 *sarray, uint32 slength, uint32 key, + jsval *parray, uint32 plength) { NativeIterator *ni = (NativeIterator *) cx->malloc(sizeof(NativeIterator) + plength * sizeof(jsval) + slength * sizeof(uint32)); if (!ni) { JS_ReportOutOfMemory(cx); - return false; + return NULL; } ni->props_array = ni->props_cursor = (jsval *) (ni + 1); ni->props_end = ni->props_array + plength; @@ -253,19 +253,15 @@ MakeNativeIterator(JSContext *cx, uintN flags, uint32 *sarray, uint32 slength, u ni->flags = flags; if (slength) memcpy(ni->shapes_array, sarray, slength * sizeof(uint32)); - - *nip = ni; - - return true; + return ni; } -static bool -InitNativeIterator(JSContext *cx, JSObject *obj, uintN flags, uint32 *sarray, uint32 slength, - uint32 key, NativeIterator **nip) +static NativeIterator * +Snapshot(JSContext *cx, JSObject *obj, uintN flags, uint32 *sarray, uint32 slength, uint32 key) { HashSet ht(cx); if (!(flags & JSITER_OWNONLY) && !ht.init(32)) - return false; + return NULL; AutoValueVector props(cx); @@ -276,45 +272,45 @@ InitNativeIterator(JSContext *cx, JSObject *obj, uintN flags, uint32 *sarray, ui pobj->map->ops->enumerate == js_Enumerate && !(clasp->flags & JSCLASS_NEW_ENUMERATE)) { if (!clasp->enumerate(cx, pobj)) - return false; + return NULL; if (!EnumerateNativeProperties(cx, obj, pobj, flags, ht, props)) - return false; + return NULL; } else if (pobj->isDenseArray()) { if (!EnumerateDenseArrayProperties(cx, obj, pobj, flags, ht, props)) - return false; + return NULL; } else { if (pobj->isProxy()) { JSIdArray *ida; if (flags & JSITER_OWNONLY) { if (!JSProxy::enumerateOwn(cx, pobj, &ida)) - return false; + return NULL; } else { if (!JSProxy::enumerate(cx, pobj, &ida)) - return false; + return NULL; } AutoIdArray idar(cx, ida); for (size_t n = 0; n < size_t(ida->length); ++n) { if (!Enumerate(cx, obj, pobj, ida->vector[n], true, flags, ht, props)) - return false; + return NULL; } /* Proxy objects enumerate the prototype on their own, so we are done here. */ break; } jsval state; if (!pobj->enumerate(cx, JSENUMERATE_INIT, &state, NULL)) - return false; + return NULL; if (state == JSVAL_NATIVE_ENUMERATE_COOKIE) { if (!EnumerateNativeProperties(cx, obj, pobj, flags, ht, props)) - return false; + return NULL; } else { while (true) { jsid id; if (!pobj->enumerate(cx, JSENUMERATE_NEXT, &state, &id)) - return false; + return NULL; if (state == JSVAL_NULL) break; if (!Enumerate(cx, obj, pobj, id, true, flags, ht, props)) - return false; + return NULL; } } } @@ -325,7 +321,7 @@ InitNativeIterator(JSContext *cx, JSObject *obj, uintN flags, uint32 *sarray, ui pobj = pobj->getProto(); } - return MakeNativeIterator(cx, flags, sarray, slength, key, props.begin(), props.length(), nip); + return NativeIterator::allocate(cx, flags, sarray, slength, key, props.begin(), props.length()); } bool @@ -335,7 +331,7 @@ NativeIteratorToJSIdArray(JSContext *cx, NativeIterator *ni, JSIdArray **idap) JS_ASSERT(sizeof(NativeIterator) > sizeof(JSIdArray)); JS_ASSERT(ni->props_array == (jsid *) (ni + 1)); size_t length = size_t(ni->props_end - ni->props_array); - JSIdArray *ida = (JSIdArray *) (uintptr_t(ni->props_array) - (sizeof(JSIdArray) - sizeof(jsid))); + JSIdArray *ida = (JSIdArray *) uintptr_t(ni->props_array) - (sizeof(JSIdArray) - sizeof(jsid)); ida->self = ni; ida->length = length; JS_ASSERT(&ida->vector[0] == &ni->props_array[0]); @@ -344,28 +340,10 @@ NativeIteratorToJSIdArray(JSContext *cx, NativeIterator *ni, JSIdArray **idap) } bool -EnumerateOwnProperties(JSContext *cx, JSObject *obj, JSIdArray **idap) +GetPropertyNames(JSContext *cx, JSObject *obj, uintN flags, JSIdArray **idap) { - NativeIterator *ni; - if (!InitNativeIterator(cx, obj, JSITER_OWNONLY, NULL, 0, true, &ni)) - return false; - return NativeIteratorToJSIdArray(cx, ni, idap); -} - -bool -EnumerateAllProperties(JSContext *cx, JSObject *obj, JSIdArray **idap) -{ - NativeIterator *ni; - if (!InitNativeIterator(cx, obj, 0, NULL, 0, true, &ni)) - return false; - return NativeIteratorToJSIdArray(cx, ni, idap); -} - -bool -GetOwnProperties(JSContext *cx, JSObject *obj, JSIdArray **idap) -{ - NativeIterator *ni; - if (!InitNativeIterator(cx, obj, JSITER_OWNONLY | JSITER_HIDDEN, NULL, 0, true, &ni)) + NativeIterator *ni = Snapshot(cx, obj, flags & (JSITER_OWNONLY | JSITER_HIDDEN), NULL, 0, true); + if (!ni) return false; return NativeIteratorToJSIdArray(cx, ni, idap); } @@ -413,16 +391,40 @@ Compare(T *a, T *b, size_t c) return true; } -static inline bool +static JSObject * +NewIteratorObject(JSContext *cx, uintN flags) +{ + return !(flags & JSITER_ENUMERATE) + ? NewObject(cx, &js_IteratorClass.base, NULL, NULL) + : NewObjectWithGivenProto(cx, &js_IteratorClass.base, NULL, NULL); +} + +bool +JSIdArrayToIterator(JSContext *cx, uintN flags, JSIdArray *ida, jsval *vp) +{ + JSObject *iterobj = NewIteratorObject(cx, flags); + if (!iterobj) + return false; + + *vp = OBJECT_TO_JSVAL(iterobj); + + NativeIterator *ni = NativeIterator::allocate(cx, flags, NULL, 0, 0, + ida->vector, ida->length); + if (!ni) + return false; + + iterobj->setNativeIterator(ni); + return true; +} + +bool GetIterator(JSContext *cx, JSObject *obj, uintN flags, jsval *vp) { uint32 hash; JSObject **hp; - NativeIterator *ni; Vector shapes(cx); uint32 key = 0; - bool escaping = !(flags & JSITER_ENUMERATE); bool keysOnly = (flags == JSITER_ENUMERATE); if (obj) { @@ -452,7 +454,7 @@ GetIterator(JSContext *cx, JSObject *obj, uintN flags, jsval *vp) hp = &JS_THREAD_DATA(cx)->cachedNativeIterators[hash]; JSObject *iterobj = *hp; if (iterobj) { - ni = iterobj->getNativeIterator(); + NativeIterator *ni = iterobj->getNativeIterator(); if (ni->shapes_key == key && ni->shapes_length == shapes.length() && Compare(ni->shapes_array, shapes.begin(), ni->shapes_length)) { @@ -464,27 +466,26 @@ GetIterator(JSContext *cx, JSObject *obj, uintN flags, jsval *vp) } miss: - if (!obj->isProxy()) { - if (!GetCustomIterator(cx, obj, flags, vp)) - return false; - if (*vp != JSVAL_VOID) - return true; - } + if (obj->isProxy()) + return JSProxy::iterate(cx, obj, flags, vp); + if (!GetCustomIterator(cx, obj, flags, vp)) + return false; + if (*vp != JSVAL_VOID) + return true; } - JSObject *iterobj = escaping - ? NewObject(cx, &js_IteratorClass.base, NULL, NULL) - : NewObjectWithGivenProto(cx, &js_IteratorClass.base, NULL, NULL); + JSObject *iterobj = NewIteratorObject(cx, flags); if (!iterobj) return false; /* Store in *vp to protect it from GC (callers must root vp). */ *vp = OBJECT_TO_JSVAL(iterobj); - if (!InitNativeIterator(cx, obj, flags, shapes.begin(), shapes.length(), key, &ni)) + NativeIterator *ni = Snapshot(cx, obj, flags, shapes.begin(), shapes.length(), key); + if (!ni) return false; - iterobj->setNativeIterator(ni); + iterobj->setNativeIterator(ni); return true; } @@ -629,7 +630,7 @@ js_CloseIterator(JSContext *cx, jsval v) /* Cache the iterator object if possible. */ NativeIterator *ni = obj->getNativeIterator(); if (ni->shapes_length) { - uint32 hash = ni->shapes_key % JS_ARRAY_LENGTH(JS_THREAD_DATA(cx)->cachedNativeIterators); + uint32 hash = ni->shapes_key % NATIVE_ITER_CACHE_SIZE; JSObject **hp = &JS_THREAD_DATA(cx)->cachedNativeIterators[hash]; ni->props_cursor = ni->props_array; ni->next = *hp; diff --git a/js/src/jsiter.h b/js/src/jsiter.h index 95c430a00c8..f29789172dc 100644 --- a/js/src/jsiter.h +++ b/js/src/jsiter.h @@ -70,6 +70,10 @@ struct NativeIterator { uintN flags; JSObject *next; + static NativeIterator *allocate(JSContext *cx, uintN flags, + uint32 *sarray, uint32 slength, uint32 key, + jsval *parray, uint32 plength); + void mark(JSTracer *trc); }; @@ -81,13 +85,13 @@ struct NativeIterator { static const jsval JSVAL_NATIVE_ENUMERATE_COOKIE = SPECIAL_TO_JSVAL(0x220576); bool -EnumerateOwnProperties(JSContext *cx, JSObject *obj, JSIdArray **idap); +GetPropertyNames(JSContext *cx, JSObject *obj, uintN flags, JSIdArray **idap); bool -EnumerateAllProperties(JSContext *cx, JSObject *obj, JSIdArray **idap); +GetIterator(JSContext *cx, JSObject *obj, uintN flags, jsval *vp); bool -GetOwnProperties(JSContext *cx, JSObject *obj, JSIdArray **idap); +JSIdArrayToIterator(JSContext *cx, uintN flags, JSIdArray *ida, jsval *vp); /* * Convert the value stored in *vp to its iteration object. The flags should diff --git a/js/src/jsproxy.cpp b/js/src/jsproxy.cpp index 369fa9ceec4..f3341ea0359 100644 --- a/js/src/jsproxy.cpp +++ b/js/src/jsproxy.cpp @@ -170,6 +170,16 @@ JSProxyHandler::enumerateOwn(JSContext *cx, JSObject *proxy, JSIdArray **idap) return true; } +bool +JSProxyHandler::iterate(JSContext *cx, JSObject *proxy, uintN flags, jsval *vp) +{ + JSIdArray *ida; + if (!enumerate(cx, proxy, &ida)) + return false; + AutoIdArray idar(cx, ida); + return JSIdArrayToIterator(cx, flags, ida, vp); +} + void JSProxyHandler::finalize(JSContext *cx, JSObject *proxy) { @@ -189,20 +199,23 @@ JSNoopProxyHandler::~JSNoopProxyHandler() } bool -JSNoopProxyHandler::getPropertyDescriptor(JSContext *cx, JSObject *proxy, jsid id, JSPropertyDescriptor *desc) +JSNoopProxyHandler::getPropertyDescriptor(JSContext *cx, JSObject *proxy, jsid id, + JSPropertyDescriptor *desc) { JSObject *wobj = wrappedObject(proxy); return JS_GetPropertyDescriptorById(cx, wobj, id, JSRESOLVE_QUALIFIED, desc); } bool -JSNoopProxyHandler::getOwnPropertyDescriptor(JSContext *cx, JSObject *proxy, jsid id, JSPropertyDescriptor *desc) +JSNoopProxyHandler::getOwnPropertyDescriptor(JSContext *cx, JSObject *proxy, jsid id, + JSPropertyDescriptor *desc) { return JS_GetPropertyDescriptorById(cx, wrappedObject(proxy), id, JSRESOLVE_QUALIFIED, desc); } bool -JSNoopProxyHandler::defineProperty(JSContext *cx, JSObject *proxy, jsid id, JSPropertyDescriptor *desc) +JSNoopProxyHandler::defineProperty(JSContext *cx, JSObject *proxy, jsid id, + JSPropertyDescriptor *desc) { return JS_DefinePropertyById(cx, wrappedObject(proxy), id, desc->value, desc->getter, desc->setter, desc->attrs); @@ -211,7 +224,7 @@ JSNoopProxyHandler::defineProperty(JSContext *cx, JSObject *proxy, jsid id, JSPr bool JSNoopProxyHandler::getOwnPropertyNames(JSContext *cx, JSObject *proxy, JSIdArray **idap) { - return GetOwnProperties(cx, wrappedObject(proxy), idap); + return GetPropertyNames(cx, wrappedObject(proxy), JSITER_OWNONLY | JSITER_HIDDEN, idap); } bool @@ -227,7 +240,7 @@ JSNoopProxyHandler::delete_(JSContext *cx, JSObject *proxy, jsid id, bool *bp) bool JSNoopProxyHandler::enumerate(JSContext *cx, JSObject *proxy, JSIdArray **idap) { - return EnumerateAllProperties(cx, wrappedObject(proxy), idap); + return GetPropertyNames(cx, wrappedObject(proxy), 0, idap); } bool @@ -273,7 +286,13 @@ JSNoopProxyHandler::set(JSContext *cx, JSObject *proxy, JSObject *receiver, jsid bool JSNoopProxyHandler::enumerateOwn(JSContext *cx, JSObject *proxy, JSIdArray **idap) { - return EnumerateOwnProperties(cx, wrappedObject(proxy), idap); + return GetPropertyNames(cx, wrappedObject(proxy), JSITER_OWNONLY, idap); +} + +bool +JSNoopProxyHandler::iterate(JSContext *cx, JSObject *proxy, uintN flags, jsval *vp) +{ + return GetIterator(cx, wrappedObject(proxy), flags, vp); } void @@ -290,7 +309,7 @@ JSNoopProxyHandler::trace(JSTracer *trc, JSObject *proxy) JS_CALL_OBJECT_TRACER(trc, mWrappedObject, "wrappedObject"); } -void * +const void * JSNoopProxyHandler::family() { return &singleton; @@ -301,17 +320,7 @@ JSNoopProxyHandler JSNoopProxyHandler::singleton(NULL); static bool GetTrap(JSContext *cx, JSObject *handler, JSAtom *atom, jsval *fvalp) { - if (!handler->getProperty(cx, ATOM_TO_JSID(atom), fvalp)) { - JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_UNDEFINED_PROP, - JS_GetStringBytes(JSVAL_TO_STRING(ID_TO_VALUE(atom)))); - return false; - } - if (!js_IsCallable(*fvalp)) { - JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_NOT_FUNCTION, - JS_GetStringBytes(JSVAL_TO_STRING(ID_TO_VALUE(atom)))); - return false; - } - return true; + return handler->getProperty(cx, ATOM_TO_JSID(atom), fvalp); } static bool @@ -325,39 +334,65 @@ TryHandlerTrap(JSContext *cx, JSObject *proxy, bool ok = true) } static bool -Trap(JSContext *cx, JSObject *handler, JSAtom *atom, uintN argc, jsval* argv, jsval *rval) +FundamentalTrap(JSContext *cx, JSObject *handler, JSAtom *atom, jsval *fvalp) +{ + if (!GetTrap(cx, handler, atom, fvalp)) + return false; + + if (!js_IsCallable(*fvalp)) { + JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_NOT_FUNCTION, + js_AtomToPrintableString(cx, atom)); + return false; + } + + return true; +} + +static bool +DerivedTrap(JSContext *cx, JSObject *handler, JSAtom *atom, jsval *fvalp) +{ + JS_ASSERT(atom == ATOM(has) || + atom == ATOM(hasOwn) || + atom == ATOM(get) || + atom == ATOM(set) || + atom == ATOM(enumerateOwn) || + atom == ATOM(iterate)); + + return GetTrap(cx, handler, atom, fvalp); +} + +static bool +Trap(JSContext *cx, JSObject *handler, jsval fval, uintN argc, jsval* argv, jsval *rval) { JS_CHECK_RECURSION(cx, return false); - jsval fval; - if (!GetTrap(cx, handler, atom, &fval)) - return false; return js_InternalCall(cx, handler, fval, argc, argv, rval); } static bool -Trap1(JSContext *cx, JSObject *handler, JSAtom *atom, jsid id, jsval *rval) +Trap1(JSContext *cx, JSObject *handler, jsval fval, jsid id, jsval *rval) { JSString *str = js_ValueToString(cx, ID_TO_VALUE(id)); if (!str) return false; *rval = STRING_TO_JSVAL(str); - return Trap(cx, handler, atom, 1, rval, rval); + return Trap(cx, handler, fval, 1, rval, rval); } static bool -Trap2(JSContext *cx, JSObject *handler, JSAtom *atom, jsid id, jsval v, jsval *rval) +Trap2(JSContext *cx, JSObject *handler, jsval fval, jsid id, jsval v, jsval *rval) { JSString *str = js_ValueToString(cx, ID_TO_VALUE(id)); if (!str) return false; *rval = STRING_TO_JSVAL(str); jsval argv[2] = { *rval, v }; - return Trap(cx, handler, atom, 2, argv, rval); + return Trap(cx, handler, fval, 2, argv, rval); } static bool -ParsePropertyDescriptorObject(JSContext *cx, JSObject *obj, jsid id, jsval v, JSPropertyDescriptor *desc) +ParsePropertyDescriptorObject(JSContext *cx, JSObject *obj, jsid id, jsval v, + JSPropertyDescriptor *desc) { AutoDescriptorArray descs(cx); PropertyDescriptor *d = descs.append(); @@ -386,80 +421,18 @@ MakePropertyDescriptorObject(JSContext *cx, jsid id, JSPropertyDescriptor *desc, return js_NewPropertyDescriptorObject(cx, id, attrs, getter, setter, desc->value, vp); } -bool -JSProxy::getPropertyDescriptor(JSContext *cx, JSObject *proxy, jsid id, JSPropertyDescriptor *desc) +static bool +ValueToBool(JSContext *cx, jsval v, bool *bp) { - jsval handler = proxy->getProxyHandler(); - if (JSVAL_IS_OBJECT(handler)) { - AutoValueRooter tvr(cx); - return TryHandlerTrap(cx, proxy, Trap1(cx, JSVAL_TO_OBJECT(handler), ATOM(getPropertyDescriptor), id, tvr.addr())) && - ParsePropertyDescriptorObject(cx, proxy, id, tvr.value(), desc); - } - return TryHandlerTrap(cx, proxy, ((JSProxyHandler *) JSVAL_TO_PRIVATE(handler))->getPropertyDescriptor(cx, proxy, id, desc)); + JSBool b; + if (!JS_ValueToBoolean(cx, v, &b)) + return false; + *bp = !!b; + return true; } bool -JSProxy::getPropertyDescriptor(JSContext *cx, JSObject *proxy, jsid id, jsval *vp) -{ - jsval handler = proxy->getProxyHandler(); - if (JSVAL_IS_OBJECT(handler)) { - return TryHandlerTrap(cx, proxy, Trap1(cx, JSVAL_TO_OBJECT(handler), ATOM(getPropertyDescriptor), id, vp)); - } - AutoDescriptor desc(cx); - return TryHandlerTrap(cx, proxy, ((JSProxyHandler *) JSVAL_TO_PRIVATE(handler))->getPropertyDescriptor(cx, proxy, id, &desc)) && - MakePropertyDescriptorObject(cx, id, &desc, vp); -} - -bool -JSProxy::getOwnPropertyDescriptor(JSContext *cx, JSObject *proxy, jsid id, JSPropertyDescriptor *desc) -{ - jsval handler = proxy->getProxyHandler(); - if (JSVAL_IS_OBJECT(handler)) { - AutoValueRooter tvr(cx); - return TryHandlerTrap(cx, proxy, Trap1(cx, JSVAL_TO_OBJECT(handler), ATOM(getOwnPropertyDescriptor), id, tvr.addr())) && - ParsePropertyDescriptorObject(cx, proxy, id, tvr.value(), desc); - } - return TryHandlerTrap(cx, proxy, ((JSProxyHandler *) JSVAL_TO_PRIVATE(handler))->getOwnPropertyDescriptor(cx, proxy, id, desc)); -} - -bool -JSProxy::getOwnPropertyDescriptor(JSContext *cx, JSObject *proxy, jsid id, jsval *vp) -{ - jsval handler = proxy->getProxyHandler(); - if (JSVAL_IS_OBJECT(handler)) - return TryHandlerTrap(cx, proxy, Trap1(cx, JSVAL_TO_OBJECT(handler), ATOM(getOwnPropertyDescriptor), id, vp)); - AutoDescriptor desc(cx); - return TryHandlerTrap(cx, proxy, ((JSProxyHandler *) JSVAL_TO_PRIVATE(handler))->getOwnPropertyDescriptor(cx, proxy, id, &desc)) && - MakePropertyDescriptorObject(cx, id, &desc, vp); -} - -bool -JSProxy::defineProperty(JSContext *cx, JSObject *proxy, jsid id, JSPropertyDescriptor *desc) -{ - jsval handler = proxy->getProxyHandler(); - if (JSVAL_IS_OBJECT(handler)) { - AutoValueRooter tvr(cx); - return MakePropertyDescriptorObject(cx, id, desc, tvr.addr()) && - TryHandlerTrap(cx, proxy, Trap2(cx, JSVAL_TO_OBJECT(handler), ATOM(defineProperty), id, tvr.value(), tvr.addr())); - } - return TryHandlerTrap(cx, proxy, ((JSProxyHandler *) JSVAL_TO_PRIVATE(handler))->defineProperty(cx, proxy, id, desc)); -} - -bool -JSProxy::defineProperty(JSContext *cx, JSObject *proxy, jsid id, jsval v) -{ - jsval handler = proxy->getProxyHandler(); - if (JSVAL_IS_OBJECT(handler)) { - AutoValueRooter tvr(cx); - return TryHandlerTrap(cx, proxy, Trap2(cx, JSVAL_TO_OBJECT(handler), ATOM(defineProperty), id, v, tvr.addr())); - } - AutoDescriptor desc(cx); - return ParsePropertyDescriptorObject(cx, proxy, id, v, &desc) && - TryHandlerTrap(cx, proxy, ((JSProxyHandler *) JSVAL_TO_PRIVATE(handler))->defineProperty(cx, proxy, id, &desc)); -} - -bool -ArrayToJSIDArray(JSContext *cx, jsval array, JSIdArray **idap) +ArrayToJSIdArray(JSContext *cx, jsval array, JSIdArray **idap) { if (JSVAL_IS_PRIMITIVE(array)) return (*idap = NewIdArray(cx, 0)) != NULL; @@ -488,48 +461,298 @@ ArrayToJSIDArray(JSContext *cx, jsval array, JSIdArray **idap) return true; } +/* Derived class for all scripted proxy handlers. */ +class JSScriptedProxyHandler : public JSProxyHandler { + public: + JSScriptedProxyHandler(); + virtual ~JSScriptedProxyHandler(); + + /* ES5 Harmony fundamental proxy traps. */ + virtual bool getPropertyDescriptor(JSContext *cx, JSObject *proxy, jsid id, + JSPropertyDescriptor *desc); + virtual bool getOwnPropertyDescriptor(JSContext *cx, JSObject *proxy, jsid id, + JSPropertyDescriptor *desc); + virtual bool defineProperty(JSContext *cx, JSObject *proxy, jsid id, + JSPropertyDescriptor *desc); + virtual bool getOwnPropertyNames(JSContext *cx, JSObject *proxy, JSIdArray **idap); + virtual bool delete_(JSContext *cx, JSObject *proxy, jsid id, bool *bp); + virtual bool enumerate(JSContext *cx, JSObject *proxy, JSIdArray **idap); + virtual bool fix(JSContext *cx, JSObject *proxy, jsval *vp); + + /* ES5 Harmony derived proxy traps. */ + virtual bool has(JSContext *cx, JSObject *proxy, jsid id, bool *bp); + virtual bool hasOwn(JSContext *cx, JSObject *proxy, jsid id, bool *bp); + virtual bool get(JSContext *cx, JSObject *proxy, JSObject *receiver, jsid id, jsval *vp); + virtual bool set(JSContext *cx, JSObject *proxy, JSObject *receiver, jsid id, jsval *vp); + virtual bool enumerateOwn(JSContext *cx, JSObject *proxy, JSIdArray **idap); + virtual bool iterate(JSContext *cx, JSObject *proxy, uintN flags, jsval *vp); + + /* Spidermonkey extensions. */ + virtual const void *family(); + + static JSScriptedProxyHandler singleton; +}; + +JSScriptedProxyHandler::JSScriptedProxyHandler() +{ +} + +JSScriptedProxyHandler::~JSScriptedProxyHandler() +{ +} + +bool +JSScriptedProxyHandler::getPropertyDescriptor(JSContext *cx, JSObject *proxy, jsid id, + JSPropertyDescriptor *desc) +{ + JSObject *handler = JSVAL_TO_OBJECT(proxy->getProxyHandler()); + AutoValueRooter tvr(cx); + return FundamentalTrap(cx, handler, ATOM(getPropertyDescriptor), tvr.addr()) && + TryHandlerTrap(cx, proxy, Trap1(cx, handler, tvr.value(), id, tvr.addr())) && + ParsePropertyDescriptorObject(cx, proxy, id, tvr.value(), desc); +} + +bool +JSScriptedProxyHandler::getOwnPropertyDescriptor(JSContext *cx, JSObject *proxy, jsid id, + JSPropertyDescriptor *desc) +{ + JSObject *handler = JSVAL_TO_OBJECT(proxy->getProxyHandler()); + AutoValueRooter tvr(cx); + return FundamentalTrap(cx, handler, ATOM(getOwnPropertyDescriptor), tvr.addr()) && + TryHandlerTrap(cx, proxy, Trap1(cx, handler, tvr.value(), id, tvr.addr())) && + ParsePropertyDescriptorObject(cx, proxy, id, tvr.value(), desc); +} + +bool +JSScriptedProxyHandler::defineProperty(JSContext *cx, JSObject *proxy, jsid id, + JSPropertyDescriptor *desc) +{ + JSObject *handler = JSVAL_TO_OBJECT(proxy->getProxyHandler()); + AutoValueRooter tvr(cx); + AutoValueRooter fval(cx); + return FundamentalTrap(cx, handler, ATOM(defineProperty), fval.addr()) && + MakePropertyDescriptorObject(cx, id, desc, tvr.addr()) && + TryHandlerTrap(cx, proxy, Trap2(cx, handler, fval.value(), id, tvr.value(), tvr.addr())); +} + +bool +JSScriptedProxyHandler::getOwnPropertyNames(JSContext *cx, JSObject *proxy, JSIdArray **idap) +{ + JSObject *handler = JSVAL_TO_OBJECT(proxy->getProxyHandler()); + AutoValueRooter tvr(cx); + return FundamentalTrap(cx, handler, ATOM(getOwnPropertyNames), tvr.addr()) && + TryHandlerTrap(cx, proxy, Trap(cx, handler, tvr.value(), 0, NULL, tvr.addr())) && + ArrayToJSIdArray(cx, tvr.value(), idap); +} + +bool +JSScriptedProxyHandler::delete_(JSContext *cx, JSObject *proxy, jsid id, bool *bp) +{ + JSObject *handler = JSVAL_TO_OBJECT(proxy->getProxyHandler()); + AutoValueRooter tvr(cx); + return FundamentalTrap(cx, handler, ATOM(delete), tvr.addr()) && + TryHandlerTrap(cx, proxy, Trap1(cx, handler, tvr.value(), id, tvr.addr())) && + ValueToBool(cx, tvr.value(), bp); +} + +bool +JSScriptedProxyHandler::enumerate(JSContext *cx, JSObject *proxy, JSIdArray **idap) +{ + JSObject *handler = JSVAL_TO_OBJECT(proxy->getProxyHandler()); + AutoValueRooter tvr(cx); + return FundamentalTrap(cx, handler, ATOM(enumerate), tvr.addr()) && + TryHandlerTrap(cx, proxy, Trap(cx, handler, tvr.value(), 0, NULL, tvr.addr())) && + ArrayToJSIdArray(cx, tvr.value(), idap); +} + +bool +JSScriptedProxyHandler::fix(JSContext *cx, JSObject *proxy, jsval *vp) +{ + JSObject *handler = JSVAL_TO_OBJECT(proxy->getProxyHandler()); + return FundamentalTrap(cx, handler, ATOM(fix), vp) && + Trap(cx, handler, *vp, 0, NULL, vp); +} + +bool +JSScriptedProxyHandler::has(JSContext *cx, JSObject *proxy, jsid id, bool *bp) +{ + JSObject *handler = JSVAL_TO_OBJECT(proxy->getProxyHandler()); + AutoValueRooter tvr(cx); + if (!DerivedTrap(cx, handler, ATOM(has), tvr.addr())) + return false; + if (!js_IsCallable(tvr.value())) + return JSProxyHandler::has(cx, proxy, id, bp); + return TryHandlerTrap(cx, proxy, Trap1(cx, handler, tvr.value(), id, tvr.addr())) && + ValueToBool(cx, tvr.value(), bp); +} + +bool +JSScriptedProxyHandler::hasOwn(JSContext *cx, JSObject *proxy, jsid id, bool *bp) +{ + JSObject *handler = JSVAL_TO_OBJECT(proxy->getProxyHandler()); + AutoValueRooter tvr(cx); + if (!DerivedTrap(cx, handler, ATOM(hasOwn), tvr.addr())) + return false; + if (!js_IsCallable(tvr.value())) + return JSProxyHandler::hasOwn(cx, proxy, id, bp); + return TryHandlerTrap(cx, proxy, Trap1(cx, handler, tvr.value(), id, tvr.addr())) && + ValueToBool(cx, tvr.value(), bp); +} + +bool +JSScriptedProxyHandler::get(JSContext *cx, JSObject *proxy, JSObject *receiver, jsid id, jsval *vp) +{ + JSObject *handler = JSVAL_TO_OBJECT(proxy->getProxyHandler()); + JSString *str = js_ValueToString(cx, ID_TO_VALUE(id)); + if (!str) + return false; + AutoValueRooter tvr(cx, STRING_TO_JSVAL(str)); + jsval argv[] = { OBJECT_TO_JSVAL(receiver), tvr.value() }; + AutoValueRooter fval(cx); + if (!DerivedTrap(cx, handler, ATOM(get), fval.addr())) + return false; + if (!js_IsCallable(fval.value())) + return JSProxyHandler::get(cx, proxy, receiver, id, vp); + return TryHandlerTrap(cx, proxy, Trap(cx, handler, fval.value(), 2, argv, vp)); +} + +bool +JSScriptedProxyHandler::set(JSContext *cx, JSObject *proxy, JSObject *receiver, jsid id, jsval *vp) +{ + JSObject *handler = JSVAL_TO_OBJECT(proxy->getProxyHandler()); + JSString *str = js_ValueToString(cx, ID_TO_VALUE(id)); + if (!str) + return false; + AutoValueRooter tvr(cx, STRING_TO_JSVAL(str)); + jsval argv[] = { OBJECT_TO_JSVAL(receiver), tvr.value(), *vp }; + AutoValueRooter fval(cx); + if (!DerivedTrap(cx, handler, ATOM(set), fval.addr())) + return false; + if (!js_IsCallable(fval.value())) + return JSProxyHandler::set(cx, proxy, receiver, id, vp); + return TryHandlerTrap(cx, proxy, Trap(cx, handler, fval.value(), 3, argv, tvr.addr())); +} + +bool +JSScriptedProxyHandler::enumerateOwn(JSContext *cx, JSObject *proxy, JSIdArray **idap) +{ + JSObject *handler = JSVAL_TO_OBJECT(proxy->getProxyHandler()); + AutoValueRooter tvr(cx); + if (!DerivedTrap(cx, handler, ATOM(enumerateOwn), tvr.addr())) + return false; + if (!js_IsCallable(tvr.value())) + return JSProxyHandler::enumerateOwn(cx, proxy, idap); + return TryHandlerTrap(cx, proxy, Trap(cx, handler, tvr.value(), 0, NULL, tvr.addr())) && + ArrayToJSIdArray(cx, tvr.value(), idap); +} + +bool +JSScriptedProxyHandler::iterate(JSContext *cx, JSObject *proxy, uintN flags, jsval *vp) +{ + JSObject *handler = JSVAL_TO_OBJECT(proxy->getProxyHandler()); + AutoValueRooter tvr(cx); + if (!DerivedTrap(cx, handler, ATOM(iterate), tvr.addr())) + return false; + if (!js_IsCallable(tvr.value())) + return JSProxyHandler::iterate(cx, proxy, flags, vp); + return TryHandlerTrap(cx, proxy, Trap(cx, handler, tvr.value(), 0, NULL, vp)); +} + +const void * +JSScriptedProxyHandler::family() +{ + return &singleton; +} + +JSScriptedProxyHandler JSScriptedProxyHandler::singleton; + +static JSProxyHandler * +JSVAL_TO_HANDLER(jsval handler) +{ + return (JSProxyHandler *) JSVAL_TO_PRIVATE(handler); +} + +bool +JSProxy::getPropertyDescriptor(JSContext *cx, JSObject *proxy, jsid id, JSPropertyDescriptor *desc) +{ + jsval handler = proxy->getProxyHandler(); + if (JSVAL_IS_OBJECT(handler)) + return JSScriptedProxyHandler::singleton.getPropertyDescriptor(cx, proxy, id, desc); + return TryHandlerTrap(cx, proxy, + JSVAL_TO_HANDLER(handler)->getPropertyDescriptor(cx, proxy, id, desc)); +} + +bool +JSProxy::getPropertyDescriptor(JSContext *cx, JSObject *proxy, jsid id, jsval *vp) +{ + AutoDescriptor desc(cx); + return JSProxy::getPropertyDescriptor(cx, proxy, id, &desc) && + MakePropertyDescriptorObject(cx, id, &desc, vp); +} + +bool +JSProxy::getOwnPropertyDescriptor(JSContext *cx, JSObject *proxy, jsid id, + JSPropertyDescriptor *desc) +{ + jsval handler = proxy->getProxyHandler(); + if (JSVAL_IS_OBJECT(handler)) + return JSScriptedProxyHandler::singleton.getOwnPropertyDescriptor(cx, proxy, id, desc); + return TryHandlerTrap(cx, proxy, + JSVAL_TO_HANDLER(handler)->getOwnPropertyDescriptor(cx, proxy, id, desc)); +} + +bool +JSProxy::getOwnPropertyDescriptor(JSContext *cx, JSObject *proxy, jsid id, jsval *vp) +{ + AutoDescriptor desc(cx); + return JSProxy::getOwnPropertyDescriptor(cx, proxy, id, &desc) && + MakePropertyDescriptorObject(cx, id, &desc, vp); +} + +bool +JSProxy::defineProperty(JSContext *cx, JSObject *proxy, jsid id, JSPropertyDescriptor *desc) +{ + jsval handler = proxy->getProxyHandler(); + if (JSVAL_IS_OBJECT(handler)) + return JSScriptedProxyHandler::singleton.defineProperty(cx, proxy, id, desc); + return TryHandlerTrap(cx, proxy, + JSVAL_TO_HANDLER(handler)->defineProperty(cx, proxy, id, desc)); +} + +bool +JSProxy::defineProperty(JSContext *cx, JSObject *proxy, jsid id, jsval v) +{ + AutoDescriptor desc(cx); + return ParsePropertyDescriptorObject(cx, proxy, id, v, &desc) && + JSProxy::defineProperty(cx, proxy, id, &desc); +} + bool JSProxy::getOwnPropertyNames(JSContext *cx, JSObject *proxy, JSIdArray **idap) { jsval handler = proxy->getProxyHandler(); - if (JSVAL_IS_OBJECT(handler)) { - AutoValueRooter tvr(cx); - if (!TryHandlerTrap(cx, proxy, Trap(cx, JSVAL_TO_OBJECT(handler), ATOM(getOwnPropertyNames), - 0, NULL, tvr.addr()))) - return false; - return ArrayToJSIDArray(cx, tvr.value(), idap); - } - return TryHandlerTrap(cx, proxy, ((JSProxyHandler *) JSVAL_TO_PRIVATE(handler))->getOwnPropertyNames(cx, proxy, idap)); + if (JSVAL_IS_OBJECT(handler)) + return JSScriptedProxyHandler::singleton.getOwnPropertyNames(cx, proxy, idap); + return TryHandlerTrap(cx, proxy, + JSVAL_TO_HANDLER(handler)->getOwnPropertyNames(cx, proxy, idap)); } bool JSProxy::delete_(JSContext *cx, JSObject *proxy, jsid id, bool *bp) { jsval handler = proxy->getProxyHandler(); - if (JSVAL_IS_OBJECT(handler)) { - AutoValueRooter tvr(cx); - if (!TryHandlerTrap(cx, proxy, Trap1(cx, JSVAL_TO_OBJECT(handler), ATOM(delete), id, tvr.addr()))) - return false; - JSBool deleted; - if (!JS_ValueToBoolean(cx, tvr.value(), &deleted)) - return false; - *bp = !!deleted; - return true; - } - return TryHandlerTrap(cx, proxy, ((JSProxyHandler *) JSVAL_TO_PRIVATE(handler))->delete_(cx, proxy, id, bp)); + if (JSVAL_IS_OBJECT(handler)) + return JSScriptedProxyHandler::singleton.delete_(cx, proxy, id, bp); + return TryHandlerTrap(cx, proxy, JSVAL_TO_HANDLER(handler)->delete_(cx, proxy, id, bp)); } bool JSProxy::enumerate(JSContext *cx, JSObject *proxy, JSIdArray **idap) { jsval handler = proxy->getProxyHandler(); - if (JSVAL_IS_OBJECT(handler)) { - AutoValueRooter tvr(cx); - if (!TryHandlerTrap(cx, proxy, Trap(cx, JSVAL_TO_OBJECT(handler), ATOM(enumerate), 0, NULL, tvr.addr()))) - return false; - return ArrayToJSIDArray(cx, tvr.value(), idap); - } - return TryHandlerTrap(cx, proxy, ((JSProxyHandler *) JSVAL_TO_PRIVATE(handler))->enumerate(cx, proxy, idap)); + if (JSVAL_IS_OBJECT(handler)) + return JSScriptedProxyHandler::singleton.enumerate(cx, proxy, idap); + return TryHandlerTrap(cx, proxy, JSVAL_TO_HANDLER(handler)->enumerate(cx, proxy, idap)); } bool @@ -537,85 +760,62 @@ JSProxy::fix(JSContext *cx, JSObject *proxy, jsval *vp) { jsval handler = proxy->getProxyHandler(); if (JSVAL_IS_OBJECT(handler)) - return Trap(cx, JSVAL_TO_OBJECT(handler), ATOM(fix), 0, NULL, vp); - return ((JSProxyHandler *) JSVAL_TO_PRIVATE(handler))->fix(cx, proxy, vp); + return JSScriptedProxyHandler::singleton.fix(cx, proxy, vp); + return JSVAL_TO_HANDLER(handler)->fix(cx, proxy, vp); } bool JSProxy::has(JSContext *cx, JSObject *proxy, jsid id, bool *bp) { jsval handler = proxy->getProxyHandler(); - if (JSVAL_IS_OBJECT(handler)) { - AutoValueRooter tvr(cx); - if (!TryHandlerTrap(cx, proxy, Trap1(cx, JSVAL_TO_OBJECT(handler), ATOM(has), id, tvr.addr()))) - return false; - JSBool has; - if (!JS_ValueToBoolean(cx, tvr.value(), &has)) - return false; - *bp = !!has; - return true; - } - return TryHandlerTrap(cx, proxy, ((JSProxyHandler *) JSVAL_TO_PRIVATE(handler))->has(cx, proxy, id, bp)); + if (JSVAL_IS_OBJECT(handler)) + return JSScriptedProxyHandler::singleton.has(cx, proxy, id, bp); + return TryHandlerTrap(cx, proxy, JSVAL_TO_HANDLER(handler)->has(cx, proxy, id, bp)); } bool JSProxy::hasOwn(JSContext *cx, JSObject *proxy, jsid id, bool *bp) { jsval handler = proxy->getProxyHandler(); - if (JSVAL_IS_OBJECT(handler)) { - AutoValueRooter tvr(cx); - if (!TryHandlerTrap(cx, proxy, Trap1(cx, JSVAL_TO_OBJECT(handler), ATOM(hasOwn), id, tvr.addr()))) - return false; - JSBool has; - if (!JS_ValueToBoolean(cx, tvr.value(), &has)) - return false; - *bp = !!has; - return true; - } - return TryHandlerTrap(cx, proxy, ((JSProxyHandler *) JSVAL_TO_PRIVATE(handler))->hasOwn(cx, proxy, id, bp)); + if (JSVAL_IS_OBJECT(handler)) + return JSScriptedProxyHandler::singleton.hasOwn(cx, proxy, id, bp); + return TryHandlerTrap(cx, proxy, JSVAL_TO_HANDLER(handler)->hasOwn(cx, proxy, id, bp)); } bool JSProxy::get(JSContext *cx, JSObject *proxy, JSObject *receiver, jsid id, jsval *vp) { jsval handler = proxy->getProxyHandler(); - if (JSVAL_IS_OBJECT(handler)) { - JSString *str = js_ValueToString(cx, ID_TO_VALUE(id)); - if (!str) - return false; - AutoValueRooter tvr(cx, STRING_TO_JSVAL(str)); - jsval argv[] = { OBJECT_TO_JSVAL(receiver), tvr.value() }; - return TryHandlerTrap(cx, proxy, Trap(cx, JSVAL_TO_OBJECT(handler), ATOM(get), 2, argv, vp)); - } - return TryHandlerTrap(cx, proxy, ((JSProxyHandler *) JSVAL_TO_PRIVATE(handler))->get(cx, proxy, receiver, id, vp)); + if (JSVAL_IS_OBJECT(handler)) + return JSScriptedProxyHandler::singleton.get(cx, proxy, receiver, id, vp); + return TryHandlerTrap(cx, proxy, JSVAL_TO_HANDLER(handler)->get(cx, proxy, receiver, id, vp)); } bool JSProxy::set(JSContext *cx, JSObject *proxy, JSObject *receiver, jsid id, jsval *vp) { jsval handler = proxy->getProxyHandler(); - if (JSVAL_IS_OBJECT(handler)) { - JSString *str = js_ValueToString(cx, ID_TO_VALUE(id)); - if (!str) - return false; - AutoValueRooter tvr(cx, STRING_TO_JSVAL(str)); - jsval argv[] = { OBJECT_TO_JSVAL(receiver), tvr.value(), *vp }; - return TryHandlerTrap(cx, proxy, Trap(cx, JSVAL_TO_OBJECT(handler), ATOM(set), 3, argv, tvr.addr())); - } - return TryHandlerTrap(cx, proxy, ((JSProxyHandler *) JSVAL_TO_PRIVATE(handler))->set(cx, proxy, receiver, id, vp)); + if (JSVAL_IS_OBJECT(handler)) + return JSScriptedProxyHandler::singleton.set(cx, proxy, receiver, id, vp); + return TryHandlerTrap(cx, proxy, JSVAL_TO_HANDLER(handler)->set(cx, proxy, receiver, id, vp)); } bool JSProxy::enumerateOwn(JSContext *cx, JSObject *proxy, JSIdArray **idap) { jsval handler = proxy->getProxyHandler(); - if (JSVAL_IS_OBJECT(handler)) { - AutoValueRooter rval(cx); - if (!TryHandlerTrap(cx, proxy, Trap(cx, JSVAL_TO_OBJECT(handler), ATOM(enumerateOwn), 0, NULL, rval.addr()))) - return false; - return ArrayToJSIDArray(cx, rval.value(), idap); - } - return TryHandlerTrap(cx, proxy, ((JSProxyHandler *) JSVAL_TO_PRIVATE(handler))->enumerateOwn(cx, proxy, idap)); + if (JSVAL_IS_OBJECT(handler)) + return JSScriptedProxyHandler::singleton.enumerateOwn(cx, proxy, idap); + return TryHandlerTrap(cx, proxy, JSVAL_TO_HANDLER(handler)->enumerateOwn(cx, proxy, idap)); +} + +bool +JSProxy::iterate(JSContext *cx, JSObject *proxy, uintN flags, jsval *vp) +{ + jsval handler = proxy->getProxyHandler(); + if (JSVAL_IS_OBJECT(handler)) + return JSScriptedProxyHandler::singleton.iterate(cx, proxy, flags, vp); + return TryHandlerTrap(cx, proxy, JSVAL_TO_HANDLER(handler)->iterate(cx, proxy, flags, vp)); } JS_FRIEND_API(JSBool) @@ -743,7 +943,7 @@ proxy_TraceObject(JSTracer *trc, JSObject *obj) if (!JSVAL_IS_PRIMITIVE(handler)) JS_CALL_OBJECT_TRACER(trc, JSVAL_TO_OBJECT(handler), "handler"); else - ((JSProxyHandler *) JSVAL_TO_PRIVATE(handler))->trace(trc, obj); + JSVAL_TO_HANDLER(handler)->trace(trc, obj); if (obj->isFunctionProxy()) { JS_CALL_VALUE_TRACER(trc, obj->fslots[JSSLOT_PROXY_CALL], "call"); JS_CALL_VALUE_TRACER(trc, obj->fslots[JSSLOT_PROXY_CONSTRUCT], "construct"); @@ -788,9 +988,8 @@ obj_proxy_getObjectOps(JSContext *cx, JSClass *clasp) } JS_FRIEND_API(JSClass) ObjectProxyClass = { - "ObjectProxy", - JSCLASS_HAS_RESERVED_SLOTS(3) | - JSCLASS_NEW_ENUMERATE, + "Proxy", + JSCLASS_HAS_RESERVED_SLOTS(3), JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, NULL, obj_proxy_getObjectOps, NULL, NULL, NULL, @@ -812,11 +1011,17 @@ proxy_Construct(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rv JS_ASSERT(proxy->isProxy()); jsval fval = proxy->fslots[JSSLOT_PROXY_CONSTRUCT]; if (fval == JSVAL_VOID) { - /* We don't have an explicit constructor trap so allocate a new object and use the call trap. */ + /* + * We don't have an explicit constructor trap so allocate a new + * object and use the call trap. + */ fval = proxy->fslots[JSSLOT_PROXY_CALL]; JS_ASSERT(JSVAL_IS_OBJECT(fval)); - /* proxy is the constructor, so get proxy.prototype as the proto of the new object. */ + /* + * proxy is the constructor, so get proxy.prototype as the proto + * of the new object. + */ if (!JSProxy::get(cx, proxy, obj, ATOM_TO_JSID(ATOM(classPrototype)), rval)) return false; JSObject *proto = !JSVAL_IS_PRIMITIVE(*rval) ? JSVAL_TO_OBJECT(*rval) : NULL; @@ -867,9 +1072,8 @@ fun_proxy_getObjectOps(JSContext *cx, JSClass *clasp) } JS_FRIEND_API(JSClass) FunctionProxyClass = { - "FunctionProxy", - JSCLASS_HAS_RESERVED_SLOTS(3) | - JSCLASS_NEW_ENUMERATE, + "Proxy", + JSCLASS_HAS_RESERVED_SLOTS(3), JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, NULL, fun_proxy_getObjectOps, NULL, NULL, NULL, @@ -916,7 +1120,7 @@ proxy_create(JSContext *cx, uintN argc, jsval *vp) { if (argc < 1) { JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_MORE_ARGS_NEEDED, - "Proxy.create", "0", "s"); + "create", "0", "s"); return false; } JSObject *handler; @@ -945,7 +1149,7 @@ proxy_createFunction(JSContext *cx, uintN argc, jsval *vp) { if (argc < 2) { JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_MORE_ARGS_NEEDED, - "Proxy.createFunction", "1", ""); + "createFunction", "1", ""); return false; } JSObject *handler; @@ -967,7 +1171,8 @@ proxy_createFunction(JSContext *cx, uintN argc, jsval *vp) return false; } - JSObject *proxy = NewFunctionProxy(cx, OBJECT_TO_JSVAL(handler), proto, parent, call, construct); + JSObject *proxy = NewFunctionProxy(cx, OBJECT_TO_JSVAL(handler), proto, parent, + call, construct); if (!proxy) return false; @@ -982,7 +1187,7 @@ proxy_isTrapping(JSContext *cx, uintN argc, jsval *vp) { if (argc < 1) { JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_MORE_ARGS_NEEDED, - "Proxy.isTrapping", "0", "s"); + "isTrapping", "0", "s"); return false; } JSObject *obj; @@ -997,7 +1202,7 @@ proxy_fix(JSContext *cx, uintN argc, jsval *vp) { if (argc < 1) { JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_MORE_ARGS_NEEDED, - "Proxy.fix", "0", "s"); + "fix", "0", "s"); return false; } JSObject *obj; @@ -1071,9 +1276,8 @@ callable_Construct(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval } JSClass CallableObjectClass = { - "CallableObject", - JSCLASS_HAS_RESERVED_SLOTS(2) | - JSCLASS_NEW_ENUMERATE, + "Function", + JSCLASS_HAS_RESERVED_SLOTS(2), JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, NULL, NULL, NULL, callable_Call, callable_Construct, diff --git a/js/src/jsproxy.h b/js/src/jsproxy.h index 629afb0ef58..df657f61e9b 100644 --- a/js/src/jsproxy.h +++ b/js/src/jsproxy.h @@ -53,9 +53,12 @@ class JSProxyHandler { virtual ~JSProxyHandler(); /* ES5 Harmony fundamental proxy traps. */ - virtual bool getPropertyDescriptor(JSContext *cx, JSObject *proxy, jsid id, JSPropertyDescriptor *desc) = 0; - virtual bool getOwnPropertyDescriptor(JSContext *cx, JSObject *proxy, jsid id, JSPropertyDescriptor *desc) = 0; - virtual bool defineProperty(JSContext *cx, JSObject *proxy, jsid id, JSPropertyDescriptor *desc) = 0; + virtual bool getPropertyDescriptor(JSContext *cx, JSObject *proxy, jsid id, + JSPropertyDescriptor *desc) = 0; + virtual bool getOwnPropertyDescriptor(JSContext *cx, JSObject *proxy, jsid id, + JSPropertyDescriptor *desc) = 0; + virtual bool defineProperty(JSContext *cx, JSObject *proxy, jsid id, + JSPropertyDescriptor *desc) = 0; virtual bool getOwnPropertyNames(JSContext *cx, JSObject *proxy, JSIdArray **idap) = 0; virtual bool delete_(JSContext *cx, JSObject *proxy, jsid id, bool *bp) = 0; virtual bool enumerate(JSContext *cx, JSObject *proxy, JSIdArray **idap) = 0; @@ -67,11 +70,12 @@ class JSProxyHandler { virtual bool get(JSContext *cx, JSObject *proxy, JSObject *receiver, jsid id, jsval *vp); virtual bool set(JSContext *cx, JSObject *proxy, JSObject *receiver, jsid id, jsval *vp); virtual bool enumerateOwn(JSContext *cx, JSObject *proxy, JSIdArray **idap); + virtual bool iterate(JSContext *cx, JSObject *proxy, uintN flags, jsval *vp); /* Spidermonkey extensions. */ virtual void finalize(JSContext *cx, JSObject *proxy); virtual void trace(JSTracer *trc, JSObject *proxy); - virtual void *family() = 0; + virtual const void *family() = 0; }; /* No-op wrapper handler base class. */ @@ -85,10 +89,14 @@ class JSNoopProxyHandler { JS_FRIEND_API(virtual ~JSNoopProxyHandler()); /* ES5 Harmony fundamental proxy traps. */ - virtual JS_FRIEND_API(bool) getPropertyDescriptor(JSContext *cx, JSObject *proxy, jsid id, JSPropertyDescriptor *desc); - virtual JS_FRIEND_API(bool) getOwnPropertyDescriptor(JSContext *cx, JSObject *proxy, jsid id, JSPropertyDescriptor *desc); - virtual JS_FRIEND_API(bool) defineProperty(JSContext *cx, JSObject *proxy, jsid id, JSPropertyDescriptor *desc); - virtual JS_FRIEND_API(bool) getOwnPropertyNames(JSContext *cx, JSObject *proxy, JSIdArray **idap); + virtual JS_FRIEND_API(bool) getPropertyDescriptor(JSContext *cx, JSObject *proxy, jsid id, + JSPropertyDescriptor *desc); + virtual JS_FRIEND_API(bool) getOwnPropertyDescriptor(JSContext *cx, JSObject *proxy, jsid id, + JSPropertyDescriptor *desc); + virtual JS_FRIEND_API(bool) defineProperty(JSContext *cx, JSObject *proxy, jsid id, + JSPropertyDescriptor *desc); + virtual JS_FRIEND_API(bool) getOwnPropertyNames(JSContext *cx, JSObject *proxy, + JSIdArray **idap); virtual JS_FRIEND_API(bool) delete_(JSContext *cx, JSObject *proxy, jsid id, bool *bp); virtual JS_FRIEND_API(bool) enumerate(JSContext *cx, JSObject *proxy, JSIdArray **idap); virtual JS_FRIEND_API(bool) fix(JSContext *cx, JSObject *proxy, jsval *vp); @@ -96,19 +104,23 @@ class JSNoopProxyHandler { /* ES5 Harmony derived proxy traps. */ virtual JS_FRIEND_API(bool) has(JSContext *cx, JSObject *proxy, jsid id, bool *bp); virtual JS_FRIEND_API(bool) hasOwn(JSContext *cx, JSObject *proxy, jsid id, bool *bp); - virtual JS_FRIEND_API(bool) get(JSContext *cx, JSObject *proxy, JSObject *receiver, jsid id, jsval *vp); - virtual JS_FRIEND_API(bool) set(JSContext *cx, JSObject *proxy, JSObject *receiver, jsid id, jsval *vp); + virtual JS_FRIEND_API(bool) get(JSContext *cx, JSObject *proxy, JSObject *receiver, jsid id, + jsval *vp); + virtual JS_FRIEND_API(bool) set(JSContext *cx, JSObject *proxy, JSObject *receiver, jsid id, + jsval *vp); virtual JS_FRIEND_API(bool) enumerateOwn(JSContext *cx, JSObject *proxy, JSIdArray **idap); + virtual JS_FRIEND_API(bool) iterate(JSContext *cx, JSObject *proxy, uintN flags, jsval *vp); /* Spidermonkey extensions. */ virtual JS_FRIEND_API(void) finalize(JSContext *cx, JSObject *proxy); virtual JS_FRIEND_API(void) trace(JSTracer *trc, JSObject *proxy); - virtual JS_FRIEND_API(void) *family(); + virtual JS_FRIEND_API(const void *) family(); static JSNoopProxyHandler singleton; template - static JSObject *wrap(JSContext *cx, JSObject *obj, JSObject *proto, JSObject *parent, JSString *className); + static JSObject *wrap(JSContext *cx, JSObject *obj, JSObject *proto, JSObject *parent, + JSString *className); inline JSObject *wrappedObject(JSObject *proxy) { return mWrappedObject ? mWrappedObject : JSVAL_TO_OBJECT(proxy->getProxyPrivate()); @@ -119,9 +131,11 @@ class JSNoopProxyHandler { class JSProxy { public: /* ES5 Harmony fundamental proxy traps. */ - static bool getPropertyDescriptor(JSContext *cx, JSObject *proxy, jsid id, JSPropertyDescriptor *desc); + static bool getPropertyDescriptor(JSContext *cx, JSObject *proxy, jsid id, + JSPropertyDescriptor *desc); static bool getPropertyDescriptor(JSContext *cx, JSObject *proxy, jsid id, jsval *vp); - static bool getOwnPropertyDescriptor(JSContext *cx, JSObject *proxy, jsid id, JSPropertyDescriptor *desc); + static bool getOwnPropertyDescriptor(JSContext *cx, JSObject *proxy, jsid id, + JSPropertyDescriptor *desc); static bool getOwnPropertyDescriptor(JSContext *cx, JSObject *proxy, jsid id, jsval *vp); static bool defineProperty(JSContext *cx, JSObject *proxy, jsid id, JSPropertyDescriptor *desc); static bool defineProperty(JSContext *cx, JSObject *proxy, jsid id, jsval v); @@ -136,6 +150,7 @@ class JSProxy { static bool get(JSContext *cx, JSObject *proxy, JSObject *receiver, jsid id, jsval *vp); static bool set(JSContext *cx, JSObject *proxy, JSObject *receiver, jsid id, jsval *vp); static bool enumerateOwn(JSContext *cx, JSObject *proxy, JSIdArray **idap); + static bool iterate(JSContext *cx, JSObject *proxy, uintN flags, jsval *vp); }; /* Shared between object and function proxies. */ @@ -197,10 +212,12 @@ JSObject::setProxyPrivate(jsval priv) namespace js { JS_FRIEND_API(JSObject *) -NewObjectProxy(JSContext *cx, jsval handler, JSObject *proto, JSObject *parent, JSString *className); +NewObjectProxy(JSContext *cx, jsval handler, JSObject *proto, JSObject *parent, + JSString *className); JS_FRIEND_API(JSObject *) -NewFunctionProxy(JSContext *cx, jsval handler, JSObject *proto, JSObject *parent, JSObject *call, JSObject *construct); +NewFunctionProxy(JSContext *cx, jsval handler, JSObject *proto, JSObject *parent, + JSObject *call, JSObject *construct); JS_FRIEND_API(JSBool) GetProxyObjectClass(JSContext *cx, JSObject *proxy, const char **namep); @@ -210,18 +227,21 @@ FixProxy(JSContext *cx, JSObject *proxy, JSBool *bp); template JSObject * -JSNoopProxyHandler::wrap(JSContext *cx, JSObject *obj, JSObject *proto, JSObject *parent, JSString *className) +JSNoopProxyHandler::wrap(JSContext *cx, JSObject *obj, JSObject *proto, JSObject *parent, + JSString *className) { if (obj->isCallable()) { JSNoopProxyHandler *handler = new T(obj); if (!handler) return NULL; - JSObject *wrapper = NewFunctionProxy(cx, PRIVATE_TO_JSVAL(handler), proto, parent, obj, NULL); + JSObject *wrapper = NewFunctionProxy(cx, PRIVATE_TO_JSVAL(handler), proto, parent, + obj, NULL); if (!wrapper) delete handler; return wrapper; } - JSObject *wrapper = NewObjectProxy(cx, PRIVATE_TO_JSVAL(&T::singleton), proto, parent, className); + JSObject *wrapper = NewObjectProxy(cx, PRIVATE_TO_JSVAL(&T::singleton), proto, parent, + className); if (wrapper) wrapper->setProxyPrivate(OBJECT_TO_JSVAL(obj)); return wrapper; diff --git a/js/src/jsprvtd.h b/js/src/jsprvtd.h index 6ac2e76030a..56d78056535 100644 --- a/js/src/jsprvtd.h +++ b/js/src/jsprvtd.h @@ -69,6 +69,7 @@ #define INT_TO_JSID(i) ((jsid)INT_TO_JSVAL(i)) #define INT_JSVAL_TO_JSID(v) ((jsid)(v)) #define INT_JSID_TO_JSVAL(id) ((jsval)(id)) +#define INT_FITS_IN_JSID(i) INT_FITS_IN_JSVAL(i) #define JSID_IS_OBJECT(id) JSVAL_IS_OBJECT((jsval)(id)) #define JSID_TO_OBJECT(id) JSVAL_TO_OBJECT((jsval)(id))