diff --git a/dom/base/nsGlobalWindow.cpp b/dom/base/nsGlobalWindow.cpp index 2f9bd20c81b5..e325b3f56879 100644 --- a/dom/base/nsGlobalWindow.cpp +++ b/dom/base/nsGlobalWindow.cpp @@ -1144,6 +1144,7 @@ public: JS::Handle wrapper) const override; void finalize(JSFreeOp *fop, JSObject *proxy) const override; + size_t objectMoved(JSObject* proxy, JSObject* old) const override; bool isCallable(JSObject *obj) const override { return false; @@ -1157,8 +1158,6 @@ public: bool unwatch(JSContext *cx, JS::Handle proxy, JS::Handle id) const override; - static size_t ObjectMoved(JSObject *obj, JSObject *old); - static const nsOuterWindowProxy singleton; protected: @@ -1188,17 +1187,12 @@ protected: JS::AutoIdVector &props) const; }; -static const js::ClassExtension OuterWindowProxyClassExtension = PROXY_MAKE_EXT( - nsOuterWindowProxy::ObjectMoved -); - // Give OuterWindowProxyClass 2 reserved slots, like the other wrappers, so // JSObject::swap can swap it with CrossCompartmentWrappers without requiring // malloc. -const js::Class OuterWindowProxyClass = PROXY_CLASS_WITH_EXT( +const js::Class OuterWindowProxyClass = PROXY_CLASS_DEF( "Proxy", - JSCLASS_HAS_RESERVED_SLOTS(2), /* additional class flags */ - &OuterWindowProxyClassExtension); + JSCLASS_HAS_RESERVED_SLOTS(2)); /* additional class flags */ const char * nsOuterWindowProxy::className(JSContext *cx, JS::Handle proxy) const @@ -1527,7 +1521,7 @@ nsOuterWindowProxy::unwatch(JSContext *cx, JS::Handle proxy, } size_t -nsOuterWindowProxy::ObjectMoved(JSObject *obj, const JSObject *old) +nsOuterWindowProxy::objectMoved(JSObject *obj, JSObject *old) const { nsGlobalWindow* outerWindow = GetOuterWindow(obj); if (outerWindow) { diff --git a/dom/bindings/Codegen.py b/dom/bindings/Codegen.py index 3b59d5e839ba..616f3f4c41b1 100644 --- a/dom/bindings/Codegen.py +++ b/dom/bindings/Codegen.py @@ -544,23 +544,16 @@ class CGDOMProxyJSClass(CGThing): # HTMLAllCollection. So just hardcode it here. if self.descriptor.interface.identifier.name == "HTMLAllCollection": flags.append("JSCLASS_EMULATES_UNDEFINED") - objectMovedHook = OBJECT_MOVED_HOOK_NAME if self.descriptor.wrapperCache else 'nullptr' return fill( """ - static const js::ClassExtension sClassExtension = PROXY_MAKE_EXT( - ${objectMoved} - ); - static const DOMJSClass sClass = { - PROXY_CLASS_WITH_EXT("${name}", - ${flags}, - &sClassExtension), + PROXY_CLASS_DEF("${name}", + ${flags}), $*{descriptor} }; """, name=self.descriptor.interface.identifier.name, flags=" | ".join(flags), - objectMoved=objectMovedHook, descriptor=DOMClass(self.descriptor)) @@ -1731,6 +1724,19 @@ class CGClassFinalizeHook(CGAbstractClassHook): self.args[0].name, self.args[1].name).define() +def objectMovedHook(descriptor, hookName, obj, old): + assert descriptor.wrapperCache + return fill(""" + if (self) { + UpdateWrapper(self, self, ${obj}, ${old}); + } + + return 0; + """, + obj=obj, + old=old) + + class CGClassObjectMovedHook(CGAbstractClassHook): """ A hook for objectMovedOp, used to update the wrapper cache when an object it @@ -1742,11 +1748,8 @@ class CGClassObjectMovedHook(CGAbstractClassHook): 'size_t', args) def generate_code(self): - assert self.descriptor.wrapperCache - return CGList([ - CGIfWrapper(CGGeneric("UpdateWrapper(self, self, obj, old);\n"), - "self"), - CGGeneric("return 0;\n")]).define() + return objectMovedHook(self.descriptor, self.name, + self.args[0].name, self.args[1].name) def JSNativeArguments(): @@ -12406,6 +12409,20 @@ class CGDOMJSProxyHandler_finalize(ClassMethod): self.args[0].name, self.args[1].name).define()) +class CGDOMJSProxyHandler_objectMoved(ClassMethod): + def __init__(self, descriptor): + args = [Argument('JSObject*', 'obj'), Argument('JSObject*', 'old')] + ClassMethod.__init__(self, "objectMoved", "size_t", args, + virtual=True, override=True, const=True) + self.descriptor = descriptor + + def getBody(self): + return (("%s* self = UnwrapPossiblyNotInitializedDOMObject<%s>(obj);\n" % + (self.descriptor.nativeType, self.descriptor.nativeType)) + + objectMovedHook(self.descriptor, OBJECT_MOVED_HOOK_NAME, + self.args[0].name, self.args[1].name)) + + class CGDOMJSProxyHandler_getElements(ClassMethod): def __init__(self, descriptor): assert descriptor.supportsIndexedProperties() @@ -12581,6 +12598,8 @@ class CGDOMJSProxyHandler(CGClass): raise TypeError("Need a wrapper cache to support nursery " "allocation of DOM objects") methods.append(CGDOMJSProxyHandler_canNurseryAllocate()) + if descriptor.wrapperCache: + methods.append(CGDOMJSProxyHandler_objectMoved(descriptor)) if descriptor.interface.getExtendedAttribute('OverrideBuiltins'): parentClass = 'ShadowingDOMProxyHandler' @@ -12837,7 +12856,7 @@ class CGDescriptor(CGThing): # wants a custom hook. cgThings.append(CGClassFinalizeHook(descriptor)) - if descriptor.concrete and descriptor.wrapperCache: + if descriptor.concrete and descriptor.wrapperCache and not descriptor.proxy: cgThings.append(CGClassObjectMovedHook(descriptor)) # Generate the _ClearCachedFooValue methods before the property arrays that use them. diff --git a/dom/plugins/base/nsJSNPRuntime.cpp b/dom/plugins/base/nsJSNPRuntime.cpp index 38bd7f072efa..b0cf985b74b1 100644 --- a/dom/plugins/base/nsJSNPRuntime.cpp +++ b/dom/plugins/base/nsJSNPRuntime.cpp @@ -232,6 +232,8 @@ public: return false; } void finalize(JSFreeOp* fop, JSObject* proxy) const override; + + size_t objectMoved(JSObject* obj, JSObject* old) const override; }; const char NPObjWrapperProxyHandler::family = 0; @@ -241,9 +243,6 @@ static bool NPObjWrapper_Resolve(JSContext *cx, JS::Handle obj, JS::Handle id, bool* resolved, JS::MutableHandle method); -static size_t -NPObjWrapper_ObjectMoved(JSObject *obj, JSObject *old); - static bool NPObjWrapper_toPrimitive(JSContext *cx, unsigned argc, JS::Value *vp); @@ -253,14 +252,9 @@ CreateNPObjectMember(NPP npp, JSContext *cx, JS::Handle id, NPVariant* getPropertyResult, JS::MutableHandle vp); -static const js::ClassExtension sNPObjWrapperProxyClassExtension = PROXY_MAKE_EXT( - NPObjWrapper_ObjectMoved -); - -const js::Class sNPObjWrapperProxyClass = PROXY_CLASS_WITH_EXT( +const js::Class sNPObjWrapperProxyClass = PROXY_CLASS_DEF( NPRUNTIME_JSCLASS_NAME, - JSCLASS_HAS_RESERVED_SLOTS(1), - &sNPObjWrapperProxyClassExtension); + JSCLASS_HAS_RESERVED_SLOTS(1)); typedef struct NPObjectMemberPrivate { JS::Heap npobjWrapper; @@ -1787,8 +1781,8 @@ NPObjWrapperProxyHandler::finalize(JSFreeOp* fop, JSObject* proxy) const sDelayedReleases->AppendElement(npobj); } -static size_t -NPObjWrapper_ObjectMoved(JSObject *obj, JSObject *old) +size_t +NPObjWrapperProxyHandler::objectMoved(JSObject *obj, JSObject *old) const { // The wrapper JSObject has been moved, so we need to update the entry in the // sNPObjWrappers hash table, if present. diff --git a/js/public/Proxy.h b/js/public/Proxy.h index 39b111096c05..125c11feb7d9 100644 --- a/js/public/Proxy.h +++ b/js/public/Proxy.h @@ -684,18 +684,6 @@ extern JS_FRIEND_DATA(const js::ClassOps) ProxyClassOps; extern JS_FRIEND_DATA(const js::ClassExtension) ProxyClassExtension; extern JS_FRIEND_DATA(const js::ObjectOps) ProxyObjectOps; -/* - * Helper Macros for creating JSClasses that function as proxies. - * - * NB: The macro invocation must be surrounded by braces, so as to - * allow for potential JSClass extensions. - */ -#define PROXY_MAKE_EXT(objectMoved) \ - { \ - js::proxy_WeakmapKeyDelegate, \ - objectMoved \ - } - template constexpr unsigned CheckProxyFlags() @@ -722,7 +710,7 @@ CheckProxyFlags() return Flags; } -#define PROXY_CLASS_WITH_EXT(name, flags, extPtr) \ +#define PROXY_CLASS_DEF(name, flags) \ { \ name, \ js::Class::NON_NATIVE | \ @@ -731,13 +719,10 @@ CheckProxyFlags() js::CheckProxyFlags(), \ &js::ProxyClassOps, \ JS_NULL_CLASS_SPEC, \ - extPtr, \ + &js::ProxyClassExtension, \ &js::ProxyObjectOps \ } -#define PROXY_CLASS_DEF(name, flags) \ - PROXY_CLASS_WITH_EXT(name, flags, &js::ProxyClassExtension) - } /* namespace js */ #endif /* js_Proxy_h */ diff --git a/js/src/gc/Marking.cpp b/js/src/gc/Marking.cpp index 39bc5811c090..4487594f97a8 100644 --- a/js/src/gc/Marking.cpp +++ b/js/src/gc/Marking.cpp @@ -2976,17 +2976,9 @@ js::TenuringTracer::moveObjectToTenured(JSObject* dst, JSObject* src, AllocKind // shape list. This is updated in Nursery::sweepDictionaryModeObjects(). } - if (src->is()) { - // TODO: Push this logic into proxy_ObjectMoved and make all proxies use - // this. - - // Objects in the nursery are never swapped so the proxy must have an - // inline ProxyValueArray. - MOZ_ASSERT(src->as().usingInlineValueArray()); - dst->as().setInlineValueArray(); - if (JSObjectMovedOp op = dst->getClass()->extObjectMovedOp()) - tenuredSize += op(dst, src); - } else if (JSObjectMovedOp op = dst->getClass()->extObjectMovedOp()) { + JSObjectMovedOp op = dst->getClass()->extObjectMovedOp(); + MOZ_ASSERT_IF(src->is(), op == proxy_ObjectMoved); + if (op) { tenuredSize += op(dst, src); } else { MOZ_ASSERT_IF(src->getClass()->hasFinalize(), diff --git a/js/src/jsapi-tests/testBug604087.cpp b/js/src/jsapi-tests/testBug604087.cpp index 3d415ced24b7..81f5e8ab7995 100644 --- a/js/src/jsapi-tests/testBug604087.cpp +++ b/js/src/jsapi-tests/testBug604087.cpp @@ -14,14 +14,9 @@ #include "vm/ProxyObject.h" -static const js::ClassExtension OuterWrapperClassExtension = PROXY_MAKE_EXT( - nullptr /* objectMoved */ -); - -const js::Class OuterWrapperClass = PROXY_CLASS_WITH_EXT( +const js::Class OuterWrapperClass = PROXY_CLASS_DEF( "Proxy", - JSCLASS_HAS_RESERVED_SLOTS(1), /* additional class flags */ - &OuterWrapperClassExtension); + JSCLASS_HAS_RESERVED_SLOTS(1) /* additional class flags */); static JSObject* wrap(JSContext* cx, JS::HandleObject toWrap, JS::HandleObject target) diff --git a/js/src/proxy/Proxy.cpp b/js/src/proxy/Proxy.cpp index 5cdc80800e50..bc46a65c1be1 100644 --- a/js/src/proxy/Proxy.cpp +++ b/js/src/proxy/Proxy.cpp @@ -741,11 +741,19 @@ proxy_Finalize(FreeOp* fop, JSObject* obj) js_free(js::detail::GetProxyDataLayout(obj)->values()); } -static size_t -proxy_ObjectMoved(JSObject* obj, JSObject* old) +size_t +js::proxy_ObjectMoved(JSObject* obj, JSObject* old) { - MOZ_ASSERT(obj->is()); - return obj->as().handler()->objectMoved(obj, old); + ProxyObject& proxy = obj->as(); + + if (IsInsideNursery(old)) { + // Objects in the nursery are never swapped so the proxy must have an + // inline ProxyValueArray. + MOZ_ASSERT(old->as().usingInlineValueArray()); + proxy.setInlineValueArray(); + } + + return proxy.handler()->objectMoved(obj, old); } bool @@ -780,9 +788,10 @@ const ClassOps js::ProxyClassOps = { ProxyObject::trace, /* trace */ }; -const ClassExtension js::ProxyClassExtension = PROXY_MAKE_EXT( +const ClassExtension js::ProxyClassExtension = { + proxy_WeakmapKeyDelegate, proxy_ObjectMoved -); +}; const ObjectOps js::ProxyObjectOps = { proxy_LookupProperty, diff --git a/js/src/proxy/Proxy.h b/js/src/proxy/Proxy.h index 1f564749d2bf..b6919605048a 100644 --- a/js/src/proxy/Proxy.h +++ b/js/src/proxy/Proxy.h @@ -80,6 +80,8 @@ bool proxy_Call(JSContext* cx, unsigned argc, Value* vp); bool proxy_Construct(JSContext* cx, unsigned argc, Value* vp); +size_t +proxy_ObjectMoved(JSObject* obj, JSObject* old); // These functions are used by JIT code