Bug 1395421 part 2. When a get() happens on a JS-implemented maplike, notify the JS implementation so it can take some sort of action (e.g. logging or warning). r=peterv

MozReview-Commit-ID: 9G115wOyzvm
This commit is contained in:
Boris Zbarsky 2017-08-31 22:45:53 -04:00
parent 2697cc0235
commit 056d8fe612
3 changed files with 86 additions and 7 deletions

View File

@ -15570,6 +15570,17 @@ class CGJSImplClass(CGBindingImplClass):
static=True,
body=self.getCreateFromExistingBody()))
if (descriptor.interface.isJSImplemented() and
descriptor.interface.maplikeOrSetlikeOrIterable and
descriptor.interface.maplikeOrSetlikeOrIterable.isMaplike()):
self.methodDecls.append(
ClassMethod("__OnGet",
"void",
[Argument("JS::Handle<JS::Value>", "aKey"),
Argument("JS::Handle<JS::Value>", "aValue"),
Argument("ErrorResult&", "aRv")],
body="mImpl->__OnGet(aKey, aValue, aRv);\n"))
CGClass.__init__(self, descriptor.name,
bases=baseClasses,
constructors=[constructor],
@ -15931,16 +15942,31 @@ class CGCallbackInterface(CGCallback):
not iface.isJSImplemented()))]
methods = [CallbackOperation(m, sig, descriptor, spiderMonkeyInterfacesAreStructs)
for m in methods for sig in m.signatures()]
needInitId = False
if iface.isJSImplemented() and iface.ctor():
sigs = descriptor.interface.ctor().signatures()
if len(sigs) != 1:
raise TypeError("We only handle one constructor. See bug 869268.")
methods.append(CGJSImplInitOperation(sigs[0], descriptor))
if any(m.isAttr() or m.isMethod() for m in iface.members) or (iface.isJSImplemented() and iface.ctor()):
methods.append(initIdsClassMethod([descriptor.binaryNameFor(m.identifier.name)
for m in iface.members
if m.isAttr() or m.isMethod()] +
(["__init"] if iface.isJSImplemented() and iface.ctor() else []),
needInitId = True
needOnGetId = False
if (iface.isJSImplemented() and
iface.maplikeOrSetlikeOrIterable and
iface.maplikeOrSetlikeOrIterable.isMaplike()):
methods.append(CGJSImplOnGetOperation(descriptor))
needOnGetId = True
idlist = [descriptor.binaryNameFor(m.identifier.name)
for m in iface.members
if m.isAttr() or m.isMethod()]
if needInitId:
idlist.append("__init")
if needOnGetId:
idlist.append("__onget")
if len(idlist) != 0:
methods.append(initIdsClassMethod(idlist,
iface.identifier.name + "Atoms"))
CGCallback.__init__(self, iface, descriptor, "CallbackInterface",
methods, getters=getters, setters=setters)
@ -16459,6 +16485,32 @@ class CGJSImplInitOperation(CallbackOperationBase):
return "__init"
class CGJSImplOnGetOperation(CallbackOperationBase):
"""
Codegen the __OnGet() method used to notify the JS impl that a get() is
happening on a JS-implemented maplike. This method takes two arguments
(key and value) and returns nothing.
"""
def __init__(self, descriptor):
CallbackOperationBase.__init__(
self,
(BuiltinTypes[IDLBuiltinType.Types.void],
[FakeArgument(BuiltinTypes[IDLBuiltinType.Types.any],
None,
"key"),
FakeArgument(BuiltinTypes[IDLBuiltinType.Types.any],
None,
"value")]),
"__onget", "__OnGet",
descriptor,
singleOperation=False,
rethrowContentException=True,
spiderMonkeyInterfacesAreStructs=True)
def getPrettyName(self):
return "__onget"
def getMaplikeOrSetlikeErrorReturn(helperImpl):
"""
Generate return values based on whether a maplike or setlike generated
@ -16741,7 +16793,21 @@ class CGMaplikeOrSetlikeMethodGenerator(CGThing):
JS::Rooted<JS::Value> result(cx);
"""))]
arguments = ["&result"]
return self.mergeTuples(r, (code, arguments, []))
if self.descriptor.interface.isJSImplemented():
callOnGet = [CGGeneric(dedent(
"""
{
JS::ExposeValueToActiveJS(result);
ErrorResult onGetResult;
self->__OnGet(arg0Val, result, onGetResult);
if (onGetResult.MaybeSetPendingException(cx)) {
return false;
}
}
"""))]
else:
callOnGet = []
return self.mergeTuples(r, (code, arguments, callOnGet))
def has(self):
"""
@ -17041,6 +17107,11 @@ class GlobalGenRoots():
if d.interface.isJSImplemented() and d.interface.ctor():
# We'll have an __init() method.
members.append(FakeMember('__init'))
if (d.interface.isJSImplemented() and
d.interface.maplikeOrSetlikeOrIterable and
d.interface.maplikeOrSetlikeOrIterable.isMaplike()):
# We'll have an __onget() method.
members.append(FakeMember('__onget'))
if len(members) == 0:
continue

View File

@ -32,7 +32,11 @@ TestInterfaceJSMaplike.prototype = {
clearInternal: function() {
return this.__DOM_IMPL__.__clear();
}
},
__onget: function(key, value) {
/* no-op */
},
};
this.NSGetFactory = XPCOMUtils.generateNSGetFactory([TestInterfaceJSMaplike])

View File

@ -327,6 +327,10 @@ class RTCStatsReport {
}
get mozPcid() { return this._pcid; }
__onget(key, value) {
/* Do whatever here */
}
}
setupPrototype(RTCStatsReport, {
classID: PC_STATS_CID,