Bug 1396613 - Make proxy objects override handler's objectMoved method rather than using class hook r=sfink r=mccr8 r=peterv

This commit is contained in:
Jon Coppeard 2017-09-19 12:31:30 +01:00
Родитель 2a663c4c5a
Коммит 8bd8591183
8 изменённых файлов: 68 добавлений и 78 удалений

Просмотреть файл

@ -1144,6 +1144,7 @@ public:
JS::Handle<JSObject*> 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<JSObject*> proxy,
JS::Handle<jsid> 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<JSObject*> proxy) const
@ -1527,7 +1521,7 @@ nsOuterWindowProxy::unwatch(JSContext *cx, JS::Handle<JSObject*> proxy,
}
size_t
nsOuterWindowProxy::ObjectMoved(JSObject *obj, const JSObject *old)
nsOuterWindowProxy::objectMoved(JSObject *obj, JSObject *old) const
{
nsGlobalWindow* outerWindow = GetOuterWindow(obj);
if (outerWindow) {

Просмотреть файл

@ -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.

Просмотреть файл

@ -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<JSObject*> obj, JS::Handle<jsid> id,
bool* resolved, JS::MutableHandle<JSObject*> 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<jsid> id, NPVariant* getPropertyResult,
JS::MutableHandle<JS::Value> 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<JSObject *> 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.

Просмотреть файл

@ -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 <unsigned Flags>
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<flags>(), \
&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 */

Просмотреть файл

@ -2976,17 +2976,9 @@ js::TenuringTracer::moveObjectToTenured(JSObject* dst, JSObject* src, AllocKind
// shape list. This is updated in Nursery::sweepDictionaryModeObjects().
}
if (src->is<ProxyObject>()) {
// 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<ProxyObject>().usingInlineValueArray());
dst->as<ProxyObject>().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<ProxyObject>(), op == proxy_ObjectMoved);
if (op) {
tenuredSize += op(dst, src);
} else {
MOZ_ASSERT_IF(src->getClass()->hasFinalize(),

Просмотреть файл

@ -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)

Просмотреть файл

@ -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<ProxyObject>());
return obj->as<ProxyObject>().handler()->objectMoved(obj, old);
ProxyObject& proxy = obj->as<ProxyObject>();
if (IsInsideNursery(old)) {
// Objects in the nursery are never swapped so the proxy must have an
// inline ProxyValueArray.
MOZ_ASSERT(old->as<ProxyObject>().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,

Просмотреть файл

@ -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