Bug 1019160 - part 4 - use jsids to access JS-implemented interface properties; r=bz
authorNathan Froyd <froydnj@mozilla.com>
Thu, 05 Jun 2014 14:47:13 -0400
changeset 206469 a8d88faf925bcd39e0cfe7a5cd33bd83a0fb8ffe
parent 206468 c2489880460061daf12d414cb2dbceecc14a41d5
child 206470 5ba654b54620ad47e37e33c2d03763d70fd0d692
push id3741
push userasasaki@mozilla.com
push dateMon, 21 Jul 2014 20:25:18 +0000
treeherdermozilla-beta@4d6f46f5af68 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbz
bugs1019160
milestone32.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1019160 - part 4 - use jsids to access JS-implemented interface properties; r=bz
dom/bindings/CallbackInterface.cpp
dom/bindings/CallbackInterface.h
dom/bindings/Codegen.py
--- a/dom/bindings/CallbackInterface.cpp
+++ b/dom/bindings/CallbackInterface.cpp
@@ -8,25 +8,28 @@
 #include "jsapi.h"
 #include "mozilla/dom/BindingUtils.h"
 #include "nsPrintfCString.h"
 
 namespace mozilla {
 namespace dom {
 
 bool
-CallbackInterface::GetCallableProperty(JSContext* cx, const char* aPropName,
+CallbackInterface::GetCallableProperty(JSContext* cx, JS::Handle<jsid> aPropId,
                                        JS::MutableHandle<JS::Value> aCallable)
 {
-  if (!JS_GetProperty(cx, CallbackPreserveColor(), aPropName, aCallable)) {
+  if (!JS_GetPropertyById(cx, CallbackPreserveColor(), aPropId, aCallable)) {
     return false;
   }
   if (!aCallable.isObject() ||
       !JS_ObjectIsCallable(cx, &aCallable.toObject())) {
-    nsPrintfCString description("Property '%s'", aPropName);
+    char* propName =
+      JS_EncodeString(cx, JS_FORGET_STRING_FLATNESS(JSID_TO_FLAT_STRING(aPropId)));
+    nsPrintfCString description("Property '%s'", propName);
+    JS_free(cx, propName);
     ThrowErrorMessage(cx, MSG_NOT_CALLABLE, description.get());
     return false;
   }
 
   return true;
 }
 
 } // namespace dom
--- a/dom/bindings/CallbackInterface.h
+++ b/dom/bindings/CallbackInterface.h
@@ -26,17 +26,17 @@ class CallbackInterface : public Callbac
 public:
   explicit CallbackInterface(JS::Handle<JSObject*> aCallback,
                              nsIGlobalObject *aIncumbentGlobal)
     : CallbackObject(aCallback, aIncumbentGlobal)
   {
   }
 
 protected:
-  bool GetCallableProperty(JSContext* cx, const char* aPropName,
+  bool GetCallableProperty(JSContext* cx, JS::Handle<jsid> aPropId,
                            JS::MutableHandle<JS::Value> aCallable);
 
 };
 
 } // namespace dom
 } // namespace mozilla
 
 #endif // mozilla_dom_CallbackFunction_h
--- a/dom/bindings/Codegen.py
+++ b/dom/bindings/Codegen.py
@@ -11177,29 +11177,33 @@ class CGForwardDeclarations(CGWrapper):
 
         # Needed for at least Wrap.
         for d in descriptors:
             builder.add(d.nativeType)
 
         # We just about always need NativePropertyHooks
         builder.addInMozillaDom("NativePropertyHooks")
         builder.addInMozillaDom("ProtoAndIfaceCache")
+        # Add the atoms cache type, even if we don't need it.
+        for d in descriptors:
+            builder.add(d.nativeType + "Atoms", isStruct=True)
 
         for callback in mainCallbacks:
             forwardDeclareForType(callback)
             for t in getTypesFromCallback(callback):
                 forwardDeclareForType(t, workerness='mainthreadonly')
 
         for callback in workerCallbacks:
             forwardDeclareForType(callback)
             for t in getTypesFromCallback(callback):
                 forwardDeclareForType(t, workerness='workeronly')
 
         for d in callbackInterfaces:
             builder.add(d.nativeType)
+            builder.add(d.nativeType + "Atoms", isStruct=True)
             for t in getTypesFromDescriptor(d):
                 forwardDeclareForType(t)
 
         for d in dictionaries:
             if len(d.members) > 0:
                 builder.addInMozillaDom(d.identifier.name + "Atoms", isStruct=True)
             for t in getTypesFromDictionary(d):
                 forwardDeclareForType(t)
@@ -11243,27 +11247,28 @@ class CGBindingRoot(CGThing):
         bindingHeaders['xpcprivate.h'] = webIDLFile.endswith("EventTarget.webidl")
         hasWorkerStuff = len(config.getDescriptors(webIDLFile=webIDLFile,
                                                    workers=True)) != 0
         bindingHeaders["WorkerPrivate.h"] = hasWorkerStuff
         bindingHeaders["nsThreadUtils.h"] = hasWorkerStuff
 
         dictionaries = config.getDictionaries(webIDLFile=webIDLFile)
         bindingHeaders["nsCxPusher.h"] = dictionaries
-        bindingHeaders["AtomList.h"] = any(
+        hasNonEmptyDictionaries = any(
             len(dict.members) > 0 for dict in dictionaries)
         mainCallbacks = config.getCallbacks(webIDLFile=webIDLFile,
                                             workers=False)
         workerCallbacks = config.getCallbacks(webIDLFile=webIDLFile,
                                               workers=True)
         callbackDescriptors = config.getDescriptors(webIDLFile=webIDLFile,
                                                     isCallback=True)
         jsImplemented = config.getDescriptors(webIDLFile=webIDLFile,
                                               isJSImplemented=True)
         bindingHeaders["nsPIDOMWindow.h"] = jsImplemented
+        bindingHeaders["AtomList.h"] = hasNonEmptyDictionaries or jsImplemented or callbackDescriptors
 
         def addHeaderBasedOnTypes(header, typeChecker):
             bindingHeaders[header] = (
                 bindingHeaders.get(header, False) or
                 any(map(typeChecker,
                         getAllTypes(descriptors + callbackDescriptors,
                                     dictionaries,
                                     mainCallbacks + workerCallbacks))))
@@ -12529,17 +12534,17 @@ class CGCallback(CGClass):
         # For our public methods that needThisHandling we want most of the
         # same args and the same return type as what CallbackMember
         # generates.  So we want to take advantage of all its
         # CGNativeMember infrastructure, but that infrastructure can't deal
         # with templates and most especially template arguments.  So just
         # cheat and have CallbackMember compute all those things for us.
         realMethods = []
         for method in methods:
-            if not method.needThisHandling:
+            if not isinstance(method, CallbackMember) or not method.needThisHandling:
                 realMethods.append(method)
             else:
                 realMethods.extend(self.getMethodImpls(method))
         realMethods.append(
             ClassMethod("operator==", "bool",
                         [Argument("const %s&" % name, "aOther")],
                         inline=True, bodyInHeader=True,
                         const=True,
@@ -12669,16 +12674,22 @@ class CGCallbackInterface(CGCallback):
                    if m.isMethod() and not m.isStatic() and not m.isIdentifierLess()]
         methods = [CallbackOperation(m, sig, descriptor) for m in methods
                    for sig in m.signatures()]
         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 []),
+                                              iface.identifier.name + "Atoms"))
         CGCallback.__init__(self, iface, descriptor, "CallbackInterface",
                             methods, getters=getters, setters=setters)
 
 
 class FakeMember():
     def __init__(self, name=None):
         self.treatNullAs = "Default"
         if name is not None:
@@ -13030,22 +13041,25 @@ class CallbackOperationBase(CallbackMeth
             """)
 
     def getThisVal(self):
         return "thisValue"
 
     def getCallableDecl(self):
         getCallableFromProp = fill(
             """
-            if (!GetCallableProperty(cx, "${methodName}", &callable)) {
+            ${atomCacheName}* atomsCache = GetAtomCache<${atomCacheName}>(cx);
+            if ((!*reinterpret_cast<jsid**>(atomsCache) && !InitIds(cx, atomsCache)) ||
+                !GetCallableProperty(cx, atomsCache->${methodAtomName}, &callable)) {
               aRv.Throw(NS_ERROR_UNEXPECTED);
               return${errorReturn};
             }
             """,
-            methodName=self.methodName,
+            methodAtomName=CGDictionary.makeIdName(self.methodName),
+            atomCacheName=self.descriptorProvider.interface.identifier.name + "Atoms",
             errorReturn=self.getDefaultRetval())
         if not self.singleOperation:
             return 'JS::Rooted<JS::Value> callable(cx);\n' + getCallableFromProp
         return fill(
             """
             bool isCallable = JS_ObjectIsCallable(cx, mCallback);
             JS::Rooted<JS::Value> callable(cx);
             if (isCallable) {
@@ -13104,22 +13118,25 @@ class CallbackGetter(CallbackAccessor):
 
     def getRvalDecl(self):
         return "JS::Rooted<JS::Value> rval(cx, JS::UndefinedValue());\n"
 
     def getCall(self):
         return fill(
             """
             JS::Rooted<JSObject *> callback(cx, mCallback);
-            if (!JS_GetProperty(cx, callback, "${attrName}", &rval)) {
+            ${atomCacheName}* atomsCache = GetAtomCache<${atomCacheName}>(cx);
+            if ((!*reinterpret_cast<jsid**>(atomsCache) && !InitIds(cx, atomsCache)) ||
+                !JS_GetPropertyById(cx, callback, atomsCache->${attrAtomName}, &rval)) {
               aRv.Throw(NS_ERROR_UNEXPECTED);
               return${errorReturn};
             }
             """,
-            attrName=self.descriptorProvider.binaryNameFor(self.attrName),
+            atomCacheName=self.descriptorProvider.interface.identifier.name + "Atoms",
+            attrAtomName=CGDictionary.makeIdName(self.descriptorProvider.binaryNameFor(self.attrName)),
             errorReturn=self.getDefaultRetval())
 
 
 class CallbackSetter(CallbackAccessor):
     def __init__(self, attr, descriptor):
         CallbackAccessor.__init__(self, attr,
                                   (BuiltinTypes[IDLBuiltinType.Types.void],
                                    [FakeArgument(attr.type, attr)]),
@@ -13129,22 +13146,25 @@ class CallbackSetter(CallbackAccessor):
     def getRvalDecl(self):
         # We don't need an rval
         return ""
 
     def getCall(self):
         return fill(
             """
             MOZ_ASSERT(argv.length() == 1);
-            if (!JS_SetProperty(cx, CallbackPreserveColor(), "${attrName}", argv[0])) {
+            ${atomCacheName}* atomsCache = GetAtomCache<${atomCacheName}>(cx);
+            if ((!*reinterpret_cast<jsid**>(atomsCache) && !InitIds(cx, atomsCache)) ||
+                !JS_SetPropertyById(cx, CallbackPreserveColor(), atomsCache->${attrAtomName}, argv[0])) {
               aRv.Throw(NS_ERROR_UNEXPECTED);
               return${errorReturn};
             }
             """,
-            attrName=self.descriptorProvider.binaryNameFor(self.attrName),
+            atomCacheName=self.descriptorProvider.interface.identifier.name + "Atoms",
+            attrAtomName=CGDictionary.makeIdName(self.descriptorProvider.binaryNameFor(self.attrName)),
             errorReturn=self.getDefaultRetval())
 
     def getArgcDecl(self):
         return None
 
 
 class CGJSImplInitOperation(CallbackOperationBase):
     """