From e620338f1a11e863be14480ed1c51df107baed25 Mon Sep 17 00:00:00 2001 From: Boris Zbarsky Date: Fri, 11 Jul 2014 19:30:27 -0400 Subject: [PATCH] Bug 832014 part 2. Add codegen support for [Unforgeable] interfaces. r=peterv --- dom/bindings/BindingUtils.cpp | 8 +++++ dom/bindings/BindingUtils.h | 3 ++ dom/bindings/Codegen.py | 57 ++++++++++++++++++++++++++++++----- 3 files changed, 61 insertions(+), 7 deletions(-) diff --git a/dom/bindings/BindingUtils.cpp b/dom/bindings/BindingUtils.cpp index 7153836c3244..7bbd893b44d0 100644 --- a/dom/bindings/BindingUtils.cpp +++ b/dom/bindings/BindingUtils.cpp @@ -909,6 +909,14 @@ GetInterfaceImpl(JSContext* aCx, nsIInterfaceRequestor* aRequestor, } } +bool +UnforgeableValueOf(JSContext* cx, unsigned argc, JS::Value* vp) +{ + JS::CallArgs args = JS::CallArgsFromVp(argc, vp); + args.rval().set(args.thisv()); + return true; +} + bool ThrowingConstructor(JSContext* cx, unsigned argc, JS::Value* vp) { diff --git a/dom/bindings/BindingUtils.h b/dom/bindings/BindingUtils.h index 30ec98c95bb7..492358459ab9 100644 --- a/dom/bindings/BindingUtils.h +++ b/dom/bindings/BindingUtils.h @@ -1700,6 +1700,9 @@ GetInterface(JSContext* aCx, T* aThis, nsIJSID* aIID, GetInterfaceImpl(aCx, aThis, aThis, aIID, aRetval, aError); } +bool +UnforgeableValueOf(JSContext* cx, unsigned argc, JS::Value* vp); + bool ThrowingConstructor(JSContext* cx, unsigned argc, JS::Value* vp); diff --git a/dom/bindings/Codegen.py b/dom/bindings/Codegen.py index 3755edd20153..8c350b4fc171 100644 --- a/dom/bindings/Codegen.py +++ b/dom/bindings/Codegen.py @@ -489,10 +489,22 @@ def PrototypeIDAndDepth(descriptor): return (prototypeID, depth) +def MemberIsUnforgeable(member, descriptor): + # Note: "or" and "and" return either their LHS or RHS, not + # necessarily booleans. Make sure to return a boolean from this + # method, because callers will compare its return value to + # booleans. + return bool((member.isAttr() or member.isMethod()) and + not member.isStatic() and + (member.isUnforgeable() or + descriptor.interface.getExtendedAttribute("Unforgeable"))) + + def UseHolderForUnforgeable(descriptor): return (descriptor.concrete and descriptor.proxy and - any(m for m in descriptor.interface.members if (m.isAttr() or m.isMethod()) and m.isUnforgeable())) + any(m for m in descriptor.interface.members + if MemberIsUnforgeable(m, descriptor))) def CallOnUnforgeableHolder(descriptor, code, isXrayCheck=None, @@ -1999,7 +2011,7 @@ class MethodDefiner(PropertyDefiner): if descriptor.interface.hasInterfacePrototypeObject() or static: methods = [m for m in descriptor.interface.members if m.isMethod() and m.isStatic() == static and - m.isUnforgeable() == unforgeable and + MemberIsUnforgeable(m, descriptor) == unforgeable and not m.isIdentifierLess()] else: methods = [] @@ -2072,7 +2084,8 @@ class MethodDefiner(PropertyDefiner): if not static: stringifier = descriptor.operations['Stringifier'] - if stringifier: + if (stringifier and + unforgeable == MemberIsUnforgeable(stringifier, descriptor)): toStringDesc = { "name": "toString", "nativeName": stringifier.identifier.name, @@ -2097,6 +2110,18 @@ class MethodDefiner(PropertyDefiner): self.chrome.append(toJSONDesc) else: self.regular.append(toJSONDesc) + if (unforgeable and + descriptor.interface.getExtendedAttribute("Unforgeable")): + # Synthesize our valueOf method + self.regular.append({ + "name": 'valueOf', + "nativeName": "UnforgeableValueOf", + "methodInfo": False, + "length": 0, + "flags": "JSPROP_ENUMERATE", # readonly/permanent added + # automatically. + "condition": MemberCondition(None, None) + }) elif (descriptor.interface.isJSImplemented() and descriptor.interface.hasInterfaceObject()): self.chrome.append({ @@ -2127,7 +2152,7 @@ class MethodDefiner(PropertyDefiner): return m["condition"] def flags(m): - unforgeable = " | JSPROP_PERMANENT" if self.unforgeable else "" + unforgeable = " | JSPROP_PERMANENT | JSPROP_READONLY" if self.unforgeable else "" return m["flags"] + unforgeable def specData(m): @@ -2184,7 +2209,7 @@ class AttrDefiner(PropertyDefiner): if descriptor.interface.hasInterfacePrototypeObject() or static: attributes = [m for m in descriptor.interface.members if m.isAttr() and m.isStatic() == static and - m.isUnforgeable() == unforgeable] + MemberIsUnforgeable(m, descriptor) == unforgeable] else: attributes = [] self.chrome = [m for m in attributes if isChromeOnly(m)] @@ -2786,6 +2811,11 @@ def InitUnforgeablePropertiesOnObject(descriptor, obj, properties, failureReturn """ unforgeables = [] + if failureReturnValue: + failureReturnValue = " " + failureReturnValue + else: + failureReturnValue = "" + defineUnforgeableAttrs = fill( """ if (!DefineUnforgeableAttributes(aCx, ${obj}, %s)) { @@ -2793,7 +2823,7 @@ def InitUnforgeablePropertiesOnObject(descriptor, obj, properties, failureReturn } """, obj=obj, - rv=" " + failureReturnValue if failureReturnValue else "") + rv=failureReturnValue) defineUnforgeableMethods = fill( """ if (!DefineUnforgeableMethods(aCx, ${obj}, %s)) { @@ -2801,7 +2831,7 @@ def InitUnforgeablePropertiesOnObject(descriptor, obj, properties, failureReturn } """, obj=obj, - rv=" " + failureReturnValue if failureReturnValue else "") + rv=failureReturnValue) unforgeableMembers = [ (defineUnforgeableAttrs, properties.unforgeableAttrs), @@ -2815,6 +2845,19 @@ def InitUnforgeablePropertiesOnObject(descriptor, obj, properties, failureReturn CGIfWrapper(CGGeneric(template % array.variableName(True)), "nsContentUtils::ThreadsafeIsCallerChrome()")) + if descriptor.interface.getExtendedAttribute("Unforgeable"): + # We do our undefined toJSON here, not as a regular property + # because we don't have a concept of value props anywhere. + unforgeables.append(CGGeneric(fill( + """ + if (!JS_DefineProperty(aCx, ${obj}, "toJSON", JS::UndefinedHandleValue, + JSPROP_READONLY | JSPROP_ENUMERATE | JSPROP_PERMANENT)) { + return${rv}; + } + """, + obj=obj, + rv=failureReturnValue))) + return CGList(unforgeables)