Bug 1117172 part 1. Allow passing an optional aGivenProto to binding Wrap methods. r=peterv

This commit is contained in:
Boris Zbarsky 2015-03-19 10:13:32 -04:00
parent e4b471f346
commit 14dff9a0e8

View File

@ -3182,11 +3182,8 @@ def CopyUnforgeablePropertiesToInstance(descriptor, wrapperCache):
copyFunc = "JS_InitializePropertiesFromCompatibleNativeObject"
copyCode.append(CGGeneric(fill(
"""
// XXXbz Once we allow subclassing, we'll want to make sure that
// this uses the canonical proto, not whatever random passed-in
// proto we end up using for the object.
JS::Rooted<JSObject*> unforgeableHolder(aCx,
&js::GetReservedSlot(proto, DOM_INTERFACE_PROTO_SLOTS_BASE).toObject());
&js::GetReservedSlot(canonicalProto, DOM_INTERFACE_PROTO_SLOTS_BASE).toObject());
if (!${copyFunc}(aCx, ${obj}, unforgeableHolder)) {
$*{cleanup}
return false;
@ -3243,6 +3240,30 @@ def InitMemberSlots(descriptor, wrapperCache):
clearWrapper=clearWrapper)
def DeclareProto():
"""
Declare the canonicalProto and proto we have for our wrapping operation.
"""
return dedent(
"""
JS::Handle<JSObject*> canonicalProto = GetProtoObjectHandle(aCx, global);
if (!canonicalProto) {
return false;
}
JS::Rooted<JSObject*> proto(aCx);
if (aGivenProto) {
proto = aGivenProto;
if (js::GetContextCompartment(aCx) != js::GetObjectCompartment(proto)) {
if (!JS_WrapObject(aCx, &proto)) {
return false;
}
}
} else {
proto = canonicalProto;
}
""")
class CGWrapWithCacheMethod(CGAbstractMethod):
"""
Create a wrapper JSObject for a given native that implements nsWrapperCache.
@ -3254,6 +3275,7 @@ class CGWrapWithCacheMethod(CGAbstractMethod):
args = [Argument('JSContext*', 'aCx'),
Argument(descriptor.nativeType + '*', 'aObject'),
Argument('nsWrapperCache*', 'aCache'),
Argument('JS::Handle<JSObject*>', 'aGivenProto'),
Argument('JS::MutableHandle<JSObject*>', 'aReflector')]
CGAbstractMethod.__init__(self, descriptor, 'Wrap', 'bool', args)
self.properties = properties
@ -3261,7 +3283,8 @@ class CGWrapWithCacheMethod(CGAbstractMethod):
def definition_body(self):
return fill(
"""
$*{assertion}
$*{assertInheritance}
MOZ_ASSERT_IF(aGivenProto, !aCache->GetWrapper());
MOZ_ASSERT(ToSupportsIsOnPrimaryInheritanceChain(aObject, aCache),
"nsISupports must be on our primary inheritance chain");
@ -3275,15 +3298,14 @@ class CGWrapWithCacheMethod(CGAbstractMethod):
// of XBL. Check for that, and bail out as needed.
aReflector.set(aCache->GetWrapper());
if (aReflector) {
MOZ_ASSERT(!aGivenProto,
"How are we supposed to change the proto now?");
return true;
}
JSAutoCompartment ac(aCx, parent);
JS::Rooted<JSObject*> global(aCx, js::GetGlobalForObjectCrossCompartment(parent));
JS::Handle<JSObject*> proto = GetProtoObjectHandle(aCx, global);
if (!proto) {
return false;
}
$*{declareProto}
$*{createObject}
@ -3293,7 +3315,8 @@ class CGWrapWithCacheMethod(CGAbstractMethod):
creator.InitializationSucceeded();
return true;
""",
assertion=AssertInheritanceChain(self.descriptor),
assertInheritance=AssertInheritanceChain(self.descriptor),
declareProto=DeclareProto(),
createObject=CreateBindingJSObject(self.descriptor, self.properties),
unforgeable=CopyUnforgeablePropertiesToInstance(self.descriptor, True),
slots=InitMemberSlots(self.descriptor, True))
@ -3304,14 +3327,15 @@ class CGWrapMethod(CGAbstractMethod):
# XXX can we wrap if we don't have an interface prototype object?
assert descriptor.interface.hasInterfacePrototypeObject()
args = [Argument('JSContext*', 'aCx'),
Argument('T*', 'aObject')]
Argument('T*', 'aObject'),
Argument('JS::Handle<JSObject*>', 'aGivenProto', 'JS::NullPtr()')]
CGAbstractMethod.__init__(self, descriptor, 'Wrap', 'JSObject*', args,
inline=True, templateArgs=["class T"])
def definition_body(self):
return dedent("""
JS::Rooted<JSObject*> reflector(aCx);
return Wrap(aCx, aObject, aObject, &reflector) ? reflector.get() : nullptr;
return Wrap(aCx, aObject, aObject, aGivenProto, &reflector) ? reflector.get() : nullptr;
""")
@ -3327,7 +3351,8 @@ class CGWrapNonWrapperCacheMethod(CGAbstractMethod):
assert descriptor.interface.hasInterfacePrototypeObject()
args = [Argument('JSContext*', 'aCx'),
Argument(descriptor.nativeType + '*', 'aObject'),
Argument('JS::MutableHandle<JSObject*>', 'aReflector')]
Argument('JS::MutableHandle<JSObject*>', 'aReflector'),
Argument('JS::Handle<JSObject*>', 'aGivenProto', 'JS::NullPtr()')]
CGAbstractMethod.__init__(self, descriptor, 'Wrap', 'bool', args)
self.properties = properties
@ -3337,10 +3362,7 @@ class CGWrapNonWrapperCacheMethod(CGAbstractMethod):
$*{assertions}
JS::Rooted<JSObject*> global(aCx, JS::CurrentGlobalOrNull(aCx));
JS::Handle<JSObject*> proto = GetProtoObjectHandle(aCx, global);
if (!proto) {
return false;
}
$*{declareProto}
$*{createObject}
@ -3351,6 +3373,7 @@ class CGWrapNonWrapperCacheMethod(CGAbstractMethod):
return true;
""",
assertions=AssertInheritanceChain(self.descriptor),
declareProto=DeclareProto(),
createObject=CreateBindingJSObject(self.descriptor, self.properties),
unforgeable=CopyUnforgeablePropertiesToInstance(self.descriptor, False),
slots=InitMemberSlots(self.descriptor, False))
@ -3394,10 +3417,10 @@ class CGWrapGlobalMethod(CGAbstractMethod):
fireOnNewGlobal = ""
if self.descriptor.hasUnforgeableMembers:
declareProto = "JS::Handle<JSObject*> proto =\n"
declareProto = "JS::Handle<JSObject*> canonicalProto =\n"
assertProto = (
"MOZ_ASSERT(proto &&\n"
" IsDOMIfaceAndProtoClass(js::GetObjectClass(proto)));\n")
"MOZ_ASSERT(canonicalProto &&\n"
" IsDOMIfaceAndProtoClass(js::GetObjectClass(canonicalProto)));\n")
else:
declareProto = ""
assertProto = ""