diff -r 719a2fb28324 js/src/jit-test/tests/basic/Proxy-function-freeze.js --- a/js/src/jit-test/tests/basic/Proxy-function-freeze.js Tue Apr 17 23:55:40 2012 +0300 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,115 +0,0 @@ -// Once a function proxy has been frozen, its handler's traps are no longer called, -// but its call traps are. - -var callTrapCalls; -function handleCall() { - print('call'); - callTrapCalls++; - return 'favor'; -} -function handleConstruct() { - print('construct'); - callTrapCalls++; - return 'compliment'; -} - -var descriptorForX = { configurable: true, enumerable: true, writable: true, value: 42 }; -var trapCalls; -var handler = { - getOwnPropertyNames: function () { - print('getOwnPropertyNames'); - trapCalls++; - return ['x']; - }, - getPropertyNames: function() { - print('getPropertyNames'); - trapCalls++; - return ['x']; - }, - getOwnPropertyDescriptor: function(name) { - print('getOwnPropertyDescriptor'); - trapCalls++; - assertEq(name, 'x'); - return descriptorForX; - }, - getPropertyDescriptor: function(name) { - print('getPropertyDescriptor'); - trapCalls++; - assertEq(name, 'x'); - return descriptorForX; - }, - defineProperty: function(name, propertyDescriptor) { - print('defineProperty'); - trapCalls++; - }, - delete: function(name) { - print('delete'); - trapCalls++; - return false; - }, - fix: function() { - print('fix'); - trapCalls++; - return { x: descriptorForX }; - } -}; - -var fp = Proxy.createFunction(handler, handleCall, handleConstruct); - -trapCalls = callTrapCalls = 0; -assertEq(Object.getOwnPropertyNames(fp)[0], 'x'); -assertEq(trapCalls > 0, true); -assertEq(callTrapCalls, 0); - -trapCalls = callTrapCalls = 0; -assertEq(Object.getOwnPropertyDescriptor(fp, 'x').value, 42); -assertEq(trapCalls > 0, true); -assertEq(callTrapCalls, 0); - -trapCalls = callTrapCalls = 0; -assertEq(delete fp.x, false); -assertEq(trapCalls > 0, true); -assertEq(callTrapCalls, 0); - -trapCalls = callTrapCalls = 0; -assertEq(fp(), 'favor'); -assertEq(trapCalls, 0); -assertEq(callTrapCalls, 1); - -trapCalls = callTrapCalls = 0; -assertEq(new fp, 'compliment'); -assertEq(trapCalls, 0); -assertEq(callTrapCalls, 1); - -trapCalls = callTrapCalls = 0; -Object.freeze(fp); -assertEq(trapCalls > 0, true); -assertEq(callTrapCalls, 0); - -// Once the proxy has been frozen, its traps should never be invoked any -// more. -trapCalls = callTrapCalls = 0; -assertEq(Object.getOwnPropertyNames(fp)[0], 'x'); -assertEq(trapCalls, 0); - -trapCalls = callTrapCalls = 0; -assertEq(Object.getOwnPropertyDescriptor(fp, 'x').value, 42); -assertEq(trapCalls, 0); - -trapCalls = callTrapCalls = 0; -assertEq(delete fp.x, false); -assertEq(trapCalls, 0); - -trapCalls = callTrapCalls = 0; -assertEq(fp(), 'favor'); -assertEq(trapCalls, 0); -assertEq(callTrapCalls, 1); - -trapCalls = callTrapCalls = 0; -assertEq(new fp, 'compliment'); -assertEq(trapCalls, 0); -assertEq(callTrapCalls, 1); - -trapCalls = callTrapCalls = 0; -Object.freeze(fp); -assertEq(trapCalls, 0); diff -r 719a2fb28324 js/src/jit-test/tests/basic/bug684348.js --- a/js/src/jit-test/tests/basic/bug684348.js Tue Apr 17 23:55:40 2012 +0300 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,4 +0,0 @@ -var x = Proxy.create({ fix: function() { return []; } }); -Object.__proto__ = x; -Object.freeze(x); -quit(); diff -r 719a2fb28324 js/src/jit-test/tests/for-of/proxy-4.js --- a/js/src/jit-test/tests/for-of/proxy-4.js Tue Apr 17 23:55:40 2012 +0300 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,10 +0,0 @@ -// for-of on a fixed (non-trapping) proxy does not call the iterate trap. - -load(libdir + "asserts.js"); - -var p = Proxy.create({ - iterate: function () { throw "FAIL"; }, - fix: function () { return {}; } -}); -Object.preventExtensions(p); -assertThrowsInstanceOf(function () { for (var v of p) {} }, TypeError); diff -r 719a2fb28324 js/src/jit-test/tests/jaeger/globalOptimize-3.js --- a/js/src/jit-test/tests/jaeger/globalOptimize-3.js Tue Apr 17 23:55:40 2012 +0300 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,18 +0,0 @@ - -y = 30; -function bar() { - assertEq(y, 30); - Object.defineProperty(this, 'y', {writable:false}); - y = 10; - assertEq(y, 30); -} -bar(); - -x = 30; -function foo() { - assertEq(x, 30); - Object.freeze(this); - x = 10; - assertEq(x, 30); -} -foo(); diff -r 719a2fb28324 js/src/jsarray.cpp --- a/js/src/jsarray.cpp Tue Apr 17 23:55:40 2012 +0300 +++ b/js/src/jsarray.cpp Thu Apr 19 16:04:41 2012 +0200 @@ -1233,35 +1233,16 @@ static void array_trace(JSTracer *trc, JSObject *obj) { JS_ASSERT(obj->isDenseArray()); uint32_t initLength = obj->getDenseArrayInitializedLength(); MarkArraySlots(trc, initLength, obj->getDenseArrayElements(), "element"); } -static JSBool -array_fix(JSContext *cx, JSObject *obj_, bool *success, AutoIdVector *props) -{ - RootedVarObject obj(cx, obj_); - - JS_ASSERT(obj->isDenseArray()); - - /* - * We must slowify dense arrays; otherwise, we'd need to detect assignments to holes, - * since that is effectively adding a new property to the array. - */ - if (!JSObject::makeDenseArraySlow(cx, obj) || - !GetPropertyNames(cx, obj, JSITER_HIDDEN | JSITER_OWNONLY, props)) - return false; - - *success = true; - return true; -} - Class js::ArrayClass = { "Array", Class::NON_NATIVE | JSCLASS_HAS_CACHED_PROTO(JSProto_Array) | JSCLASS_FOR_OF_ITERATION, JS_PropertyStub, /* addProperty */ JS_PropertyStub, /* delProperty */ JS_PropertyStub, /* getProperty */ JS_StrictPropertyStub, /* setProperty */ JS_EnumerateStub, @@ -1308,17 +1289,16 @@ Class js::ArrayClass = { array_setPropertyAttributes, array_setElementAttributes, array_setSpecialAttributes, array_deleteProperty, array_deleteElement, array_deleteSpecial, NULL, /* enumerate */ array_typeOf, - array_fix, NULL, /* thisObject */ NULL, /* clear */ } }; Class js::SlowArrayClass = { "Array", JSCLASS_HAS_CACHED_PROTO(JSProto_Array) | JSCLASS_FOR_OF_ITERATION, diff -r 719a2fb28324 js/src/jsclass.h --- a/js/src/jsclass.h Tue Apr 17 23:55:40 2012 +0300 +++ b/js/src/jsclass.h Thu Apr 19 16:04:41 2012 +0200 @@ -230,26 +230,16 @@ typedef JSBool (* DeletePropertyOp)(JSContext *cx, JSObject *obj, PropertyName *name, Value *vp, JSBool strict); typedef JSBool (* DeleteElementOp)(JSContext *cx, JSObject *obj, uint32_t index, Value *vp, JSBool strict); typedef JSBool (* DeleteSpecialOp)(JSContext *cx, JSObject *obj, SpecialId sid, Value *vp, JSBool strict); typedef JSType (* TypeOfOp)(JSContext *cx, JSObject *obj); -/* - * Prepare to make |obj| non-extensible; in particular, fully resolve its properties. - * On error, return false. - * If |obj| is now ready to become non-extensible, set |*fixed| to true and return true. - * If |obj| refuses to become non-extensible, set |*fixed| to false and return true; the - * caller will throw an appropriate error. - */ -typedef JSBool -(* FixOp)(JSContext *cx, JSObject *obj, bool *fixed, AutoIdVector *props); - typedef JSObject * (* ObjectOp)(JSContext *cx, JSObject *obj); typedef void (* FinalizeOp)(FreeOp *fop, JSObject *obj); typedef void (* ClearOp)(JSContext *cx, JSObject *obj); #define JS_CLASS_MEMBERS \ @@ -327,25 +317,24 @@ struct ObjectOps ElementAttributesOp setElementAttributes; SpecialAttributesOp setSpecialAttributes; DeletePropertyOp deleteProperty; DeleteElementOp deleteElement; DeleteSpecialOp deleteSpecial; JSNewEnumerateOp enumerate; TypeOfOp typeOf; - FixOp fix; ObjectOp thisObject; ClearOp clear; }; #define JS_NULL_OBJECT_OPS \ {NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL, \ NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL, \ - NULL,NULL,NULL,NULL,NULL,NULL} + NULL,NULL,NULL,NULL,NULL} struct Class { JS_CLASS_MEMBERS; ClassExtension ext; ObjectOps ops; uint8_t pad[sizeof(JSClass) - sizeof(ClassSizeMeasurement) - sizeof(ClassExtension) - sizeof(ObjectOps)]; diff -r 719a2fb28324 js/src/jsobj.cpp --- a/js/src/jsobj.cpp Tue Apr 17 23:55:40 2012 +0300 +++ b/js/src/jsobj.cpp Thu Apr 19 16:04:41 2012 +0200 @@ -2476,18 +2476,17 @@ obj_preventExtensions(JSContext *cx, uns JSObject *obj; if (!GetFirstArgumentAsObject(cx, argc, vp, "Object.preventExtensions", &obj)) return false; vp->setObject(*obj); if (!obj->isExtensible()) return true; - AutoIdVector props(cx); - return obj->preventExtensions(cx, &props); + return obj->preventExtensions(cx); } /* static */ inline unsigned JSObject::getSealedOrFrozenAttributes(unsigned attrs, ImmutabilityType it) { /* Make all attributes permanent; if freezing, make data attributes read-only. */ if (it == FREEZE && !(attrs & (JSPROP_GETTER | JSPROP_SETTER))) return JSPROP_PERMANENT | JSPROP_READONLY; @@ -2497,24 +2496,22 @@ JSObject::getSealedOrFrozenAttributes(un bool JSObject::sealOrFreeze(JSContext *cx, ImmutabilityType it) { assertSameCompartment(cx, this); JS_ASSERT(it == SEAL || it == FREEZE); RootedVarObject self(cx, this); + if (isExtensible() && !preventExtensions(cx)) + return false; + AutoIdVector props(cx); - if (isExtensible()) { - if (!preventExtensions(cx, &props)) - return false; - } else { - if (!GetPropertyNames(cx, this, JSITER_HIDDEN | JSITER_OWNONLY, &props)) - return false; - } + if (!GetPropertyNames(cx, this, JSITER_HIDDEN | JSITER_OWNONLY, &props)) + return false; /* preventExtensions must slowify dense arrays, so we can assign to holes without checks. */ JS_ASSERT(!self->isDenseArray()); if (self->isNative() && !self->inDictionaryMode()) { /* * Seal/freeze non-dictionary objects by constructing a new shape * hierarchy mirroring the original one, which can be shared if many diff -r 719a2fb28324 js/src/jsobj.h --- a/js/src/jsobj.h Tue Apr 17 23:55:40 2012 +0300 +++ b/js/src/jsobj.h Thu Apr 19 16:04:41 2012 +0200 @@ -553,17 +553,17 @@ struct JSObject : public js::ObjectImpl */ bool sealOrFreeze(JSContext *cx, ImmutabilityType it); bool isSealedOrFrozen(JSContext *cx, ImmutabilityType it, bool *resultp); static inline unsigned getSealedOrFrozenAttributes(unsigned attrs, ImmutabilityType it); public: - bool preventExtensions(JSContext *cx, js::AutoIdVector *props); + bool preventExtensions(JSContext *cx); /* ES5 15.2.3.8: non-extensible, all props non-configurable */ inline bool seal(JSContext *cx) { return sealOrFreeze(cx, SEAL); } /* ES5 15.2.3.9: non-extensible, all properties non-configurable, all data props read-only */ bool freeze(JSContext *cx) { return sealOrFreeze(cx, FREEZE); } bool isSealed(JSContext *cx, bool *resultp) { return isSealedOrFrozen(cx, SEAL, resultp); } bool isFrozen(JSContext *cx, bool *resultp) { return isSealedOrFrozen(cx, FREEZE, resultp); } diff -r 719a2fb28324 js/src/jsproxy.cpp --- a/js/src/jsproxy.cpp Tue Apr 17 23:55:40 2012 +0300 +++ b/js/src/jsproxy.cpp Thu Apr 19 16:04:41 2012 +0200 @@ -89,19 +89,16 @@ OperationInProgress(JSContext *cx, JSObj while (op) { if (op->object == proxy) return true; op = op->next; } return false; } -static bool -FixProxy(JSContext *cx, JSObject *proxy, JSBool *bp); - ProxyHandler::ProxyHandler(void *family) : mFamily(family) { } ProxyHandler::~ProxyHandler() { } @@ -529,17 +526,16 @@ class ScriptedProxyHandler : public Prox PropertyDescriptor *desc); virtual bool getOwnPropertyDescriptor(JSContext *cx, JSObject *proxy, jsid id, bool set, PropertyDescriptor *desc); virtual bool defineProperty(JSContext *cx, JSObject *proxy, jsid id, PropertyDescriptor *desc); virtual bool getOwnPropertyNames(JSContext *cx, JSObject *proxy, AutoIdVector &props); virtual bool delete_(JSContext *cx, JSObject *proxy, jsid id, bool *bp); virtual bool enumerate(JSContext *cx, JSObject *proxy, AutoIdVector &props); - virtual bool fix(JSContext *cx, JSObject *proxy, Value *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, Value *vp); virtual bool set(JSContext *cx, JSObject *proxy, JSObject *receiver, jsid id, bool strict, Value *vp); virtual bool keys(JSContext *cx, JSObject *proxy, AutoIdVector &props); @@ -643,24 +639,16 @@ ScriptedProxyHandler::enumerate(JSContex JSObject *handler = GetProxyHandlerObject(cx, proxy); AutoValueRooter tvr(cx); return GetFundamentalTrap(cx, handler, ATOM(enumerate), tvr.addr()) && Trap(cx, handler, tvr.value(), 0, NULL, tvr.addr()) && ArrayToIdVector(cx, tvr.value(), props); } bool -ScriptedProxyHandler::fix(JSContext *cx, JSObject *proxy, Value *vp) -{ - JSObject *handler = GetProxyHandlerObject(cx, proxy); - return GetFundamentalTrap(cx, handler, ATOM(fix), vp) && - Trap(cx, handler, *vp, 0, NULL, vp); -} - -bool ScriptedProxyHandler::has(JSContext *cx, JSObject *proxy, jsid id, bool *bp) { JSObject *handler = GetProxyHandlerObject(cx, proxy); AutoValueRooter tvr(cx); if (!GetDerivedTrap(cx, handler, ATOM(has), tvr.addr())) return false; if (!js_IsCallable(tvr.value())) return ProxyHandler::has(cx, proxy, id, bp); @@ -836,24 +824,16 @@ bool Proxy::enumerate(JSContext *cx, JSObject *proxy, AutoIdVector &props) { JS_CHECK_RECURSION(cx, return false); AutoPendingProxyOperation pending(cx, proxy); return GetProxyHandler(proxy)->enumerate(cx, proxy, props); } bool -Proxy::fix(JSContext *cx, JSObject *proxy, Value *vp) -{ - JS_CHECK_RECURSION(cx, return false); - AutoPendingProxyOperation pending(cx, proxy); - return GetProxyHandler(proxy)->fix(cx, proxy, vp); -} - -bool Proxy::has(JSContext *cx, JSObject *proxy, jsid id, bool *bp) { JS_CHECK_RECURSION(cx, return false); AutoPendingProxyOperation pending(cx, proxy); return GetProxyHandler(proxy)->has(cx, proxy, id, bp); } bool @@ -1267,29 +1247,16 @@ proxy_TraceFunction(JSTracer *trc, JSObj static JSBool proxy_Convert(JSContext *cx, JSObject *proxy, JSType hint, Value *vp) { JS_ASSERT(proxy->isProxy()); return Proxy::defaultValue(cx, proxy, hint, vp); } -static JSBool -proxy_Fix(JSContext *cx, JSObject *obj, bool *fixed, AutoIdVector *props) -{ - JS_ASSERT(obj->isProxy()); - JSBool isFixed; - bool ok = FixProxy(cx, obj, &isFixed); - if (ok) { - *fixed = isFixed; - return GetPropertyNames(cx, obj, JSITER_OWNONLY | JSITER_HIDDEN, props); - } - return false; -} - static void proxy_Finalize(FreeOp *fop, JSObject *obj) { JS_ASSERT(obj->isProxy()); if (!obj->getSlot(JSSLOT_PROXY_HANDLER).isUndefined()) GetProxyHandler(obj)->finalize(fop, obj); } @@ -1354,17 +1321,16 @@ JS_FRIEND_DATA(Class) js::ObjectProxyCla proxy_SetPropertyAttributes, proxy_SetElementAttributes, proxy_SetSpecialAttributes, proxy_DeleteProperty, proxy_DeleteElement, proxy_DeleteSpecial, NULL, /* enumerate */ proxy_TypeOf, - proxy_Fix, /* fix */ NULL, /* thisObject */ NULL, /* clear */ } }; JS_FRIEND_DATA(Class) js::OuterWindowProxyClass = { "Proxy", Class::NON_NATIVE | JSCLASS_IMPLEMENTS_BARRIERS | JSCLASS_HAS_RESERVED_SLOTS(4), @@ -1413,17 +1379,16 @@ JS_FRIEND_DATA(Class) js::OuterWindowPro proxy_SetPropertyAttributes, proxy_SetElementAttributes, proxy_SetSpecialAttributes, proxy_DeleteProperty, proxy_DeleteElement, proxy_DeleteSpecial, NULL, /* enumerate */ NULL, /* typeof */ - NULL, /* fix */ NULL, /* thisObject */ NULL, /* clear */ } }; static JSBool proxy_Call(JSContext *cx, unsigned argc, Value *vp) { @@ -1484,17 +1449,16 @@ JS_FRIEND_DATA(Class) js::FunctionProxyC proxy_SetPropertyAttributes, proxy_SetElementAttributes, proxy_SetSpecialAttributes, proxy_DeleteProperty, proxy_DeleteElement, proxy_DeleteSpecial, NULL, /* enumerate */ proxy_TypeOf, - proxy_Fix, /* fix */ NULL, /* thisObject */ NULL, /* clear */ } }; JS_FRIEND_API(JSObject *) js::NewProxyObject(JSContext *cx, ProxyHandler *handler, const Value &priv, JSObject *proto, JSObject *parent, JSObject *call, JSObject *construct) @@ -1597,198 +1561,38 @@ proxy_createFunction(JSContext *cx, unsi proto, parent, call, construct); if (!proxy) return false; vp->setObject(*proxy); return true; } -#ifdef DEBUG - -static JSBool -proxy_isTrapping(JSContext *cx, unsigned argc, Value *vp) -{ - if (argc < 1) { - JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_MORE_ARGS_NEEDED, - "isTrapping", "0", "s"); - return false; - } - JSObject *obj = NonNullObject(cx, vp[2]); - if (!obj) - return false; - vp->setBoolean(obj->isProxy()); - return true; -} - -static JSBool -proxy_fix(JSContext *cx, unsigned argc, Value *vp) -{ - if (argc < 1) { - JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_MORE_ARGS_NEEDED, - "fix", "0", "s"); - return false; - } - JSObject *obj = NonNullObject(cx, vp[2]); - if (!obj) - return false; - if (obj->isProxy()) { - JSBool flag; - if (!FixProxy(cx, obj, &flag)) - return false; - vp->setBoolean(flag); - } else { - vp->setBoolean(true); - } - return true; -} - -#endif - static JSFunctionSpec static_methods[] = { JS_FN("create", proxy_create, 2, 0), JS_FN("createFunction", proxy_createFunction, 3, 0), -#ifdef DEBUG - JS_FN("isTrapping", proxy_isTrapping, 1, 0), - JS_FN("fix", proxy_fix, 1, 0), -#endif JS_FS_END }; -static const uint32_t JSSLOT_CALLABLE_CALL = 0; -static const uint32_t JSSLOT_CALLABLE_CONSTRUCT = 1; - -static JSBool -callable_Call(JSContext *cx, unsigned argc, Value *vp) -{ - JSObject *callable = &JS_CALLEE(cx, vp).toObject(); - JS_ASSERT(callable->getClass() == &CallableObjectClass); - const Value &fval = callable->getSlot(JSSLOT_CALLABLE_CALL); - const Value &thisval = vp[1]; - bool ok = Invoke(cx, thisval, fval, argc, JS_ARGV(cx, vp), vp); - return ok; -} - -JSBool -callable_Construct(JSContext *cx, unsigned argc, Value *vp) -{ - JSObject *callable = &vp[0].toObject(); - JS_ASSERT(callable->getClass() == &CallableObjectClass); - Value fval = callable->getSlot(JSSLOT_CALLABLE_CONSTRUCT); - if (fval.isUndefined()) { - /* We don't have an explicit constructor so allocate a new object and use the call. */ - fval = callable->getSlot(JSSLOT_CALLABLE_CALL); - JS_ASSERT(fval.isObject()); - - /* callable is the constructor, so get callable.prototype is the proto of the new object. */ - Value protov; - if (!callable->getProperty(cx, ATOM(classPrototype), &protov)) - return false; - - JSObject *proto; - if (protov.isObject()) { - proto = &protov.toObject(); - } else { - proto = callable->global().getOrCreateObjectPrototype(cx); - if (!proto) - return false; - } - - JSObject *newobj = NewObjectWithGivenProto(cx, &ObjectClass, proto, NULL); - if (!newobj) - return false; - - /* If the call returns an object, return that, otherwise the original newobj. */ - Value rval; - if (!Invoke(cx, ObjectValue(*newobj), callable->getSlot(JSSLOT_CALLABLE_CALL), - argc, vp + 2, &rval)) { - return false; - } - if (rval.isPrimitive()) - vp->setObject(*newobj); - else - *vp = rval; - return true; - } - - bool ok = Invoke(cx, UndefinedValue(), fval, argc, vp + 2, vp); - return ok; -} - Class js::CallableObjectClass = { "Function", JSCLASS_HAS_RESERVED_SLOTS(2), JS_PropertyStub, /* addProperty */ JS_PropertyStub, /* delProperty */ JS_PropertyStub, /* getProperty */ JS_StrictPropertyStub, /* setProperty */ JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, NULL, /* finalize */ NULL, /* checkAccess */ - callable_Call, - callable_Construct, + NULL, /* call */ + NULL /* construct */ }; -static bool -FixProxy(JSContext *cx, JSObject *proxy, JSBool *bp) -{ - if (OperationInProgress(cx, proxy)) { - JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_BAD_PROXY_FIX); - return false; - } - - AutoValueRooter tvr(cx); - if (!Proxy::fix(cx, proxy, tvr.addr())) - return false; - if (tvr.value().isUndefined()) { - *bp = false; - return true; - } - - JSObject *props = NonNullObject(cx, tvr.value()); - if (!props) - return false; - - JSObject *proto = proxy->getProto(); - JSObject *parent = proxy->getParent(); - Class *clasp = IsFunctionProxy(proxy) ? &CallableObjectClass : &ObjectClass; - - /* - * Make a blank object from the recipe fix provided to us. This must have - * number of fixed slots as the proxy so that we can swap their contents. - */ - gc::AllocKind kind = proxy->getAllocKind(); - RootedVarObject newborn(cx); - newborn = NewObjectWithGivenProto(cx, clasp, proto, parent, kind); - if (!newborn) - return false; - - if (clasp == &CallableObjectClass) { - newborn->setSlot(JSSLOT_CALLABLE_CALL, GetCall(proxy)); - newborn->setSlot(JSSLOT_CALLABLE_CONSTRUCT, GetConstruct(proxy)); - } - - { - AutoPendingProxyOperation pending(cx, proxy); - if (!js_PopulateObject(cx, newborn, props)) - return false; - } - - /* Trade contents between the newborn object and the proxy. */ - if (!proxy->swap(cx, newborn)) - return false; - - /* The GC will dispose of the proxy object. */ - - *bp = true; - return true; -} - Class js::ProxyClass = { "Proxy", JSCLASS_HAS_CACHED_PROTO(JSProto_Proxy), JS_PropertyStub, /* addProperty */ JS_PropertyStub, /* delProperty */ JS_PropertyStub, /* getProperty */ JS_StrictPropertyStub, /* setProperty */ JS_EnumerateStub, diff -r 719a2fb28324 js/src/jsproxy.h --- a/js/src/jsproxy.h Tue Apr 17 23:55:40 2012 +0300 +++ b/js/src/jsproxy.h Thu Apr 19 16:04:41 2012 +0200 @@ -59,17 +59,16 @@ class JS_FRIEND_API(ProxyHandler) { PropertyDescriptor *desc) = 0; virtual bool getOwnPropertyDescriptor(JSContext *cx, JSObject *proxy, jsid id, bool set, PropertyDescriptor *desc) = 0; virtual bool defineProperty(JSContext *cx, JSObject *proxy, jsid id, PropertyDescriptor *desc) = 0; virtual bool getOwnPropertyNames(JSContext *cx, JSObject *proxy, AutoIdVector &props) = 0; virtual bool delete_(JSContext *cx, JSObject *proxy, jsid id, bool *bp) = 0; virtual bool enumerate(JSContext *cx, JSObject *proxy, AutoIdVector &props) = 0; - virtual bool fix(JSContext *cx, JSObject *proxy, Value *vp) = 0; /* 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, Value *vp); virtual bool set(JSContext *cx, JSObject *proxy, JSObject *receiver, jsid id, bool strict, Value *vp); virtual bool keys(JSContext *cx, JSObject *proxy, AutoIdVector &props); @@ -112,17 +111,16 @@ class Proxy { PropertyDescriptor *desc); static bool getOwnPropertyDescriptor(JSContext *cx, JSObject *proxy, jsid id, bool set, Value *vp); static bool defineProperty(JSContext *cx, JSObject *proxy, jsid id, PropertyDescriptor *desc); static bool defineProperty(JSContext *cx, JSObject *proxy, jsid id, const Value &v); static bool getOwnPropertyNames(JSContext *cx, JSObject *proxy, AutoIdVector &props); static bool delete_(JSContext *cx, JSObject *proxy, jsid id, bool *bp); static bool enumerate(JSContext *cx, JSObject *proxy, AutoIdVector &props); - static bool fix(JSContext *cx, JSObject *proxy, Value *vp); /* ES5 Harmony derived proxy traps. */ static bool has(JSContext *cx, JSObject *proxy, jsid id, bool *bp); static bool hasOwn(JSContext *cx, JSObject *proxy, jsid id, bool *bp); static bool get(JSContext *cx, JSObject *proxy, JSObject *receiver, jsid id, Value *vp); static bool getElementIfPresent(JSContext *cx, JSObject *proxy, JSObject *receiver, uint32_t index, Value *vp, bool *present); static bool set(JSContext *cx, JSObject *proxy, JSObject *receiver, jsid id, bool strict, diff -r 719a2fb28324 js/src/jsscope.cpp --- a/js/src/jsscope.cpp Tue Apr 17 23:55:40 2012 +0300 +++ b/js/src/jsscope.cpp Thu Apr 19 16:04:41 2012 +0200 @@ -1077,36 +1077,28 @@ Shape::setObjectParent(JSContext *cx, JS StackBaseShape base(last); base.parent = parent; return replaceLastProperty(cx, base, proto, last); } bool -JSObject::preventExtensions(JSContext *cx, js::AutoIdVector *props) +JSObject::preventExtensions(JSContext *cx) { JS_ASSERT(isExtensible()); RootedVarObject self(cx, this); - if (props) { - if (js::FixOp fix = getOps()->fix) { - bool success; - if (!fix(cx, this, &success, props)) - return false; - if (!success) { - JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_CANT_CHANGE_EXTENSIBILITY); - return false; - } - } else { - if (!js::GetPropertyNames(cx, this, JSITER_HIDDEN | JSITER_OWNONLY, props)) - return false; - } - } + AutoIdVector props(cx); + if (!js::GetPropertyNames(cx, this, JSITER_HIDDEN | JSITER_OWNONLY, &props)) + return false; + + if (this->isDenseArray()) + this->makeDenseArraySlow(cx, RootedVarObject(cx, this)); return self->setFlag(cx, BaseShape::NOT_EXTENSIBLE, GENERATE_SHAPE); } bool JSObject::setFlag(JSContext *cx, /*BaseShape::Flag*/ uint32_t flag_, GenerateShape generateShape) { BaseShape::Flag flag = (BaseShape::Flag) flag_; diff -r 719a2fb28324 js/src/jswrapper.cpp --- a/js/src/jswrapper.cpp Tue Apr 17 23:55:40 2012 +0300 +++ b/js/src/jswrapper.cpp Thu Apr 19 16:04:41 2012 +0200 @@ -204,23 +204,16 @@ AbstractWrapper::delete_(JSContext *cx, bool AbstractWrapper::enumerate(JSContext *cx, JSObject *wrapper, AutoIdVector &props) { // if we refuse to perform this action, props remains empty static jsid id = JSID_VOID; GET(GetPropertyNames(cx, wrappedObject(wrapper), 0, &props)); } -bool -AbstractWrapper::fix(JSContext *cx, JSObject *wrapper, Value *vp) -{ - vp->setUndefined(); - return true; -} - static bool Cond(JSBool b, bool *bp) { *bp = !!b; return true; } bool diff -r 719a2fb28324 js/src/jswrapper.h --- a/js/src/jswrapper.h Tue Apr 17 23:55:40 2012 +0300 +++ b/js/src/jswrapper.h Thu Apr 19 16:04:41 2012 +0200 @@ -66,17 +66,16 @@ class JS_FRIEND_API(AbstractWrapper) : p PropertyDescriptor *desc) MOZ_OVERRIDE; virtual bool getOwnPropertyDescriptor(JSContext *cx, JSObject *wrapper, jsid id, bool set, PropertyDescriptor *desc) MOZ_OVERRIDE; virtual bool defineProperty(JSContext *cx, JSObject *wrapper, jsid id, PropertyDescriptor *desc) MOZ_OVERRIDE; virtual bool getOwnPropertyNames(JSContext *cx, JSObject *wrapper, AutoIdVector &props) MOZ_OVERRIDE; virtual bool delete_(JSContext *cx, JSObject *wrapper, jsid id, bool *bp) MOZ_OVERRIDE; virtual bool enumerate(JSContext *cx, JSObject *wrapper, AutoIdVector &props) MOZ_OVERRIDE; - virtual bool fix(JSContext *cx, JSObject *wrapper, Value *vp) MOZ_OVERRIDE; /* Policy enforcement traps. * * enter() allows the policy to specify whether the caller may perform |act| * on the underlying object's |id| property. In the case when |act| is CALL, * |id| is generally JSID_VOID. * * leave() allows the policy to undo various scoped state changes taken in diff -r 719a2fb28324 js/src/jsxml.cpp --- a/js/src/jsxml.cpp Tue Apr 17 23:55:40 2012 +0300 +++ b/js/src/jsxml.cpp Thu Apr 19 16:04:41 2012 +0200 @@ -5159,24 +5159,16 @@ xml_trace(JSTracer *trc, JSObject *obj) * to fix somehow for generational. */ if (xml) { MarkXMLUnbarriered(trc, &xml, "private"); JS_ASSERT(xml == obj->getPrivate()); } } -static JSBool -xml_fix(JSContext *cx, JSObject *obj, bool *success, AutoIdVector *props) -{ - JS_ASSERT(obj->isExtensible()); - *success = false; - return true; -} - static void xml_clear(JSContext *cx, JSObject *obj) { } static JSBool HasSimpleContent(JSXML *xml) { @@ -5407,17 +5399,16 @@ JS_FRIEND_DATA(Class) js::XMLClass = { xml_setPropertyAttributes, xml_setElementAttributes, xml_setSpecialAttributes, xml_deleteProperty, xml_deleteElement, xml_deleteSpecial, xml_enumerate, xml_typeOf, - xml_fix, NULL, /* thisObject */ xml_clear } }; static JSXML * StartNonListXMLMethod(JSContext *cx, jsval *vp, JSObject **objp) { diff -r 719a2fb28324 js/src/vm/Debugger.cpp --- a/js/src/vm/Debugger.cpp Tue Apr 17 23:55:40 2012 +0300 +++ b/js/src/vm/Debugger.cpp Thu Apr 19 16:04:41 2012 +0200 @@ -3969,18 +3969,17 @@ DebuggerObject_sealHelper(JSContext *cx, } else if (op == Freeze) { ok = obj->freeze(cx); } else { JS_ASSERT(op == PreventExtensions); if (!obj->isExtensible()) { args.rval().setUndefined(); return true; } - AutoIdVector props(cx); - ok = obj->preventExtensions(cx, &props); + ok = obj->preventExtensions(cx); } if (!ok) return false; args.rval().setUndefined(); return true; } static JSBool diff -r 719a2fb28324 js/src/vm/GlobalObject.cpp --- a/js/src/vm/GlobalObject.cpp Tue Apr 17 23:55:40 2012 +0300 +++ b/js/src/vm/GlobalObject.cpp Thu Apr 19 16:04:41 2012 +0200 @@ -235,18 +235,17 @@ GlobalObject::initFunctionAndObjectClass return NULL; self->setOriginalEval(evalobj); /* ES5 13.2.3: Construct the unique [[ThrowTypeError]] function object. */ RootedVarFunction throwTypeError(cx); throwTypeError = js_NewFunction(cx, NULL, ThrowTypeError, 0, 0, self, NULL); if (!throwTypeError) return NULL; - AutoIdVector ids(cx); - if (!throwTypeError->preventExtensions(cx, &ids)) + if (!throwTypeError->preventExtensions(cx)) return NULL; self->setThrowTypeError(throwTypeError); /* * The global object should have |Object.prototype| as its [[Prototype]]. * Eventually we'd like to have standard classes be there from the start, * and thus we would know we were always setting what had previously been a * null [[Prototype]], but right now some code assumes it can set the diff -r 719a2fb28324 js/src/vm/ScopeObject.cpp --- a/js/src/vm/ScopeObject.cpp Tue Apr 17 23:55:40 2012 +0300 +++ b/js/src/vm/ScopeObject.cpp Thu Apr 19 16:04:41 2012 +0200 @@ -686,17 +686,16 @@ Class js::WithClass = { with_SetPropertyAttributes, with_SetElementAttributes, with_SetSpecialAttributes, with_DeleteProperty, with_DeleteElement, with_DeleteSpecial, with_Enumerate, with_TypeOf, - NULL, /* fix */ with_ThisObject, NULL, /* clear */ } }; ClonedBlockObject * ClonedBlockObject::create(JSContext *cx, StaticBlockObject &block, StackFrame *fp) { diff -r 719a2fb28324 js/xpconnect/src/XPCWrappedNativeJSOps.cpp --- a/js/xpconnect/src/XPCWrappedNativeJSOps.cpp Tue Apr 17 23:55:40 2012 +0300 +++ b/js/xpconnect/src/XPCWrappedNativeJSOps.cpp Thu Apr 19 16:04:41 2012 +0200 @@ -880,17 +880,16 @@ XPCWrappedNativeJSClass XPC_WN_NoHelper_ nsnull, // setAttributes nsnull, // setElementAttributes nsnull, // setSpecialAttributes nsnull, // deleteProperty nsnull, // deleteElement nsnull, // deleteSpecial XPC_WN_JSOp_Enumerate, XPC_WN_JSOp_TypeOf_Object, - nsnull, // fix XPC_WN_JSOp_ThisObject, XPC_WN_JSOp_Clear } }, 0 // interfacesBitmap }; diff -r 719a2fb28324 js/xpconnect/src/dombindings.cpp --- a/js/xpconnect/src/dombindings.cpp Tue Apr 17 23:55:40 2012 +0300 +++ b/js/xpconnect/src/dombindings.cpp Thu Apr 19 16:04:41 2012 +0200 @@ -788,24 +788,16 @@ ListBase::enumerate(JSContext *cx, J { JSObject *proto = JS_GetPrototype(proxy); return getOwnPropertyNames(cx, proxy, props) && (!proto || js::GetPropertyNames(cx, proto, 0, &props)); } template bool -ListBase::fix(JSContext *cx, JSObject *proxy, Value *vp) -{ - vp->setUndefined(); - return true; -} - -template -bool ListBase::hasOwn(JSContext *cx, JSObject *proxy, jsid id, bool *bp) { if (hasIndexGetter) { int32_t index = GetArrayIndexFromId(cx, id); if (index >= 0) { IndexGetterType result; *bp = getItemAt(getListObject(proxy), PRUint32(index), result); return true; diff -r 719a2fb28324 js/xpconnect/src/dombindings.h --- a/js/xpconnect/src/dombindings.h Tue Apr 17 23:55:40 2012 +0300 +++ b/js/xpconnect/src/dombindings.h Thu Apr 19 16:04:41 2012 +0200 @@ -208,17 +208,16 @@ public: JSPropertyDescriptor *desc); bool getOwnPropertyDescriptor(JSContext *cx, JSObject *proxy, jsid id, bool set, JSPropertyDescriptor *desc); bool defineProperty(JSContext *cx, JSObject *proxy, jsid id, JSPropertyDescriptor *desc); bool getOwnPropertyNames(JSContext *cx, JSObject *proxy, JS::AutoIdVector &props); bool delete_(JSContext *cx, JSObject *proxy, jsid id, bool *bp); bool enumerate(JSContext *cx, JSObject *proxy, JS::AutoIdVector &props); - bool fix(JSContext *cx, JSObject *proxy, JS::Value *vp); bool has(JSContext *cx, JSObject *proxy, jsid id, bool *bp); bool hasOwn(JSContext *cx, JSObject *proxy, jsid id, bool *bp); bool get(JSContext *cx, JSObject *proxy, JSObject *receiver, jsid id, JS::Value *vp); bool getElementIfPresent(JSContext *cx, JSObject *proxy, JSObject *receiver, uint32_t index, JS::Value *vp, bool *present); bool set(JSContext *cx, JSObject *proxy, JSObject *receiver, jsid id, bool strict, JS::Value *vp); diff -r 719a2fb28324 js/xpconnect/src/xpcprivate.h --- a/js/xpconnect/src/xpcprivate.h Tue Apr 17 23:55:40 2012 +0300 +++ b/js/xpconnect/src/xpcprivate.h Thu Apr 19 16:04:41 2012 +0200 @@ -1419,17 +1419,16 @@ XPC_WN_JSOp_ThisObject(JSContext *cx, JS nsnull, /* setAttributes */ \ nsnull, /* setElementAttributes */ \ nsnull, /* setSpecialAttributes */ \ nsnull, /* deleteProperty */ \ nsnull, /* deleteElement */ \ nsnull, /* deleteSpecial */ \ XPC_WN_JSOp_Enumerate, \ XPC_WN_JSOp_TypeOf_Function, \ - nsnull, /* fix */ \ XPC_WN_JSOp_ThisObject, \ XPC_WN_JSOp_Clear \ } #define XPC_WN_NoCall_ObjectOps \ { \ nsnull, /* lookupGeneric */ \ nsnull, /* lookupProperty */ \ @@ -1456,17 +1455,16 @@ XPC_WN_JSOp_ThisObject(JSContext *cx, JS nsnull, /* setAttributes */ \ nsnull, /* setElementAttributes */ \ nsnull, /* setSpecialAttributes */ \ nsnull, /* deleteProperty */ \ nsnull, /* deleteElement */ \ nsnull, /* deleteSpecial */ \ XPC_WN_JSOp_Enumerate, \ XPC_WN_JSOp_TypeOf_Object, \ - nsnull, /* fix */ \ XPC_WN_JSOp_ThisObject, \ XPC_WN_JSOp_Clear \ } // Maybe this macro should check for class->enumerate == // XPC_WN_Shared_Proto_Enumerate or something rather than checking for // 4 classes? static inline bool IS_PROTO_CLASS(js::Class *clazz) diff -r 719a2fb28324 js/xpconnect/wrappers/XrayWrapper.cpp --- a/js/xpconnect/wrappers/XrayWrapper.cpp Tue Apr 17 23:55:40 2012 +0300 +++ b/js/xpconnect/wrappers/XrayWrapper.cpp Thu Apr 19 16:04:41 2012 +0200 @@ -1324,24 +1324,16 @@ template ::enumerate(JSContext *cx, JSObject *wrapper, JS::AutoIdVector &props) { return enumerate(cx, wrapper, 0, props); } template bool -XrayWrapper::fix(JSContext *cx, JSObject *proxy, js::Value *vp) -{ - vp->setUndefined(); - return true; -} - -template -bool XrayWrapper::get(JSContext *cx, JSObject *wrapper, JSObject *receiver, jsid id, js::Value *vp) { // Skip our Base if it isn't already ProxyHandler. // NB: None of the functions we call are prepared for the receiver not // being the wrapper, so ignore the receiver here. return ProxyHandler::get(cx, wrapper, wrapper, id, vp); } diff -r 719a2fb28324 js/xpconnect/wrappers/XrayWrapper.h --- a/js/xpconnect/wrappers/XrayWrapper.h Tue Apr 17 23:55:40 2012 +0300 +++ b/js/xpconnect/wrappers/XrayWrapper.h Thu Apr 19 16:04:41 2012 +0200 @@ -81,17 +81,16 @@ class XrayWrapper : public Base { virtual bool getOwnPropertyDescriptor(JSContext *cx, JSObject *wrapper, jsid id, bool set, js::PropertyDescriptor *desc); virtual bool defineProperty(JSContext *cx, JSObject *wrapper, jsid id, js::PropertyDescriptor *desc); virtual bool getOwnPropertyNames(JSContext *cx, JSObject *wrapper, js::AutoIdVector &props); virtual bool delete_(JSContext *cx, JSObject *wrapper, jsid id, bool *bp); virtual bool enumerate(JSContext *cx, JSObject *wrapper, js::AutoIdVector &props); - virtual bool fix(JSContext *cx, JSObject *proxy, js::Value *vp); /* Derived proxy traps. */ virtual bool get(JSContext *cx, JSObject *wrapper, JSObject *receiver, jsid id, js::Value *vp); virtual bool set(JSContext *cx, JSObject *wrapper, JSObject *receiver, jsid id, bool strict, js::Value *vp); virtual bool has(JSContext *cx, JSObject *wrapper, jsid id, bool *bp); virtual bool hasOwn(JSContext *cx, JSObject *wrapper, jsid id, bool *bp);