Bug 1048699 - Make Exposed=SpecificWorkerType work automatically. r=bz
authorNikhil Marathe <nsm.nikhil@gmail.com>
Wed, 27 Aug 2014 10:17:36 -0700
changeset 202256 8e5931282ddddfd219410e5036d98f3c868b896b
parent 202255 f5d3c0ab2837a9e1a4837b565ae237218d2e2aa6
child 202257 e3ba68954c27a7104aabfa3158fa17dfe9c4b413
push id27395
push usercbook@mozilla.com
push dateFri, 29 Aug 2014 12:55:06 +0000
treeherdermozilla-central@5f66dd3d63f2 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbz
bugs1048699
milestone34.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 1048699 - Make Exposed=SpecificWorkerType work automatically. r=bz
dom/bindings/Codegen.py
dom/bindings/Configuration.py
dom/bindings/parser/WebIDL.py
--- a/dom/bindings/Codegen.py
+++ b/dom/bindings/Codegen.py
@@ -737,16 +737,19 @@ class CGList(CGThing):
     def deps(self):
         deps = set()
         for child in self.children:
             if child is None:
                 continue
             deps = deps.union(child.deps())
         return deps
 
+    def __len__(self):
+        return len(self.children)
+
 
 class CGGeneric(CGThing):
     """
     A class that spits out a fixed string into the codegen.  Can spit out a
     separate string for the declaration too.
     """
     def __init__(self, define="", declare=""):
         self.declareText = declare
@@ -2850,18 +2853,45 @@ class CGConstructorEnabled(CGAbstractMet
     """
     def __init__(self, descriptor):
         CGAbstractMethod.__init__(self, descriptor,
                                   'ConstructorEnabled', 'bool',
                                   [Argument("JSContext*", "aCx"),
                                    Argument("JS::Handle<JSObject*>", "aObj")])
 
     def definition_body(self):
+        body = CGList([], "\n")
+
         conditions = []
         iface = self.descriptor.interface
+
+        if not iface.isExposedInWindow():
+            exposedInWindowCheck = dedent(
+              """
+              if (NS_IsMainThread()) {
+                return false;
+              }
+              """)
+            body.append(CGGeneric(exposedInWindowCheck))
+
+        if iface.isExposedInAnyWorker() and iface.isExposedOnlyInSomeWorkers():
+            workerGlobals = sorted(iface.getWorkerExposureSet())
+            workerCondition = CGList((CGGeneric('strcmp(name, "%s")'% workerGlobal)
+                                        for workerGlobal in workerGlobals), " && ")
+            exposedInWorkerCheck = fill(
+              """
+              if (!NS_IsMainThread()) {
+                const char* name = js::GetObjectClass(aObj)->name;
+                if (${workerCondition}) {
+                  return false;
+                }
+              }
+              """, workerCondition=workerCondition.define())
+            body.append(CGGeneric(exposedInWorkerCheck))
+
         pref = iface.getExtendedAttribute("Pref")
         if pref:
             assert isinstance(pref, list) and len(pref) == 1
             conditions.append('Preferences::GetBool("%s")' % pref[0])
         if iface.getExtendedAttribute("ChromeOnly"):
             conditions.append("nsContentUtils::ThreadsafeIsCallerChrome()")
         func = iface.getExtendedAttribute("Func")
         if func:
@@ -2869,20 +2899,28 @@ class CGConstructorEnabled(CGAbstractMet
             conditions.append("%s(aCx, aObj)" % func[0])
         availableIn = getAvailableInTestFunc(iface)
         if availableIn:
             conditions.append("%s(aCx, aObj)" % availableIn)
         checkPermissions = self.descriptor.checkPermissionsIndex
         if checkPermissions is not None:
             conditions.append("CheckPermissions(aCx, aObj, permissions_%i)" % checkPermissions)
         # We should really have some conditions
-        assert len(conditions)
-        return CGWrapper(CGList((CGGeneric(cond) for cond in conditions),
-                                " &&\n"),
-                         pre="return ", post=";\n", reindent=True).define()
+        assert len(body) or len(conditions)
+
+        conditionsWrapper = ""
+        if len(conditions):
+          conditionsWrapper = CGWrapper(CGList((CGGeneric(cond) for cond in conditions),
+                                        " &&\n"),
+                                        pre="return ", post=";\n", reindent=True)
+        else:
+          conditionsWrapper = CGGeneric("return true;\n")
+
+        body.append(conditionsWrapper)
+        return body.define()
 
 
 def CreateBindingJSObject(descriptor, properties, parent):
     # We don't always need to root obj, but there are a variety
     # of cases where we do, so for simplicity, just always root it.
     objDecl = "JS::Rooted<JSObject*> obj(aCx);\n"
     if descriptor.proxy:
         create = fill(
@@ -11612,38 +11650,39 @@ class CGRegisterWorkerBindings(CGAbstrac
         self.config = config
 
     def definition_body(self):
         # We have to be a bit careful: Some of the interfaces we want to expose
         # in workers only have one descriptor, while others have both a worker
         # and a non-worker descriptor.  When both are present we want the worker
         # descriptor, but otherwise we want whatever descriptor we've got.
         descriptors = self.config.getDescriptors(hasInterfaceObject=True,
-                                                 isExposedInAllWorkers=True,
+                                                 isExposedInAnyWorker=True,
                                                  register=True,
                                                  skipGen=False,
                                                  workers=True)
         workerDescriptorIfaceNames = set(d.interface.identifier.name for
                                          d in descriptors)
         descriptors.extend(
             filter(
                 lambda d: d.interface.identifier.name not in workerDescriptorIfaceNames,
                 self.config.getDescriptors(hasInterfaceObject=True,
-                                           isExposedInAllWorkers=True,
+                                           isExposedInAnyWorker=True,
                                            register=True,
                                            skipGen=False,
                                            workers=False)))
         conditions = []
         for desc in descriptors:
             bindingNS = toBindingNamespace(desc.name)
             condition = "!%s::GetConstructorObject(aCx, aObj)" % bindingNS
             if desc.isExposedConditionally():
                 condition = (
                     "%s::ConstructorEnabled(aCx, aObj) && " % bindingNS
                     + condition)
+
             conditions.append(condition)
         lines = [CGIfWrapper(CGGeneric("return false;\n"), condition) for
                  condition in conditions]
         lines.append(CGGeneric("return true;\n"))
         return CGList(lines, "\n").define()
 
 
 class CGRegisterProtos(CGAbstractMethod):
@@ -14093,17 +14132,17 @@ class GlobalGenRoots():
         curr = CGNamespace.build(['mozilla', 'dom'],
                                  CGWrapper(curr, post='\n'))
         curr = CGWrapper(curr, post='\n')
 
         # Add the includes
         defineIncludes = [CGHeaders.getDeclarationFilename(desc.interface)
                           for desc in config.getDescriptors(hasInterfaceObject=True,
                                                             register=True,
-                                                            isExposedInAllWorkers=True,
+                                                            isExposedInAnyWorker=True,
                                                             skipGen=False)]
 
         curr = CGHeaders([], [], [], [], [], defineIncludes,
                          'RegisterWorkerBindings', curr)
 
         # Add include guards.
         curr = CGIncludeGuard('RegisterWorkerBindings', curr)
 
--- a/dom/bindings/Configuration.py
+++ b/dom/bindings/Configuration.py
@@ -133,18 +133,19 @@ class Configuration:
             elif key == 'isCallback':
                 getter = lambda x: x.interface.isCallback()
             elif key == 'isExternal':
                 getter = lambda x: x.interface.isExternal()
             elif key == 'isJSImplemented':
                 getter = lambda x: x.interface.isJSImplemented()
             elif key == 'isNavigatorProperty':
                 getter = lambda x: x.interface.getNavigatorProperty() != None
-            elif key == 'isExposedInAllWorkers':
-                getter = lambda x: not x.interface.isExternal() and "Worker" in x.interface._exposureGlobalNames
+            elif key == 'isExposedInAnyWorker':
+                getter = lambda x: (not x.interface.isExternal() and
+                                    x.interface.isExposedInAnyWorker())
             else:
                 # Have to watch out: just closing over "key" is not enough,
                 # since we're about to mutate its value
                 getter = (lambda attrName: lambda x: getattr(x, attrName))(key)
             tofilter.append((getter, val))
         for f in tofilter:
             curr = filter(lambda x: f[0](x) == f[1], curr)
         return curr
@@ -544,17 +545,20 @@ class Descriptor(DescriptorProvider):
             any((m.isAttr() or m.isMethod()) and m.isStatic() for m
                 in self.interface.members))
 
     def isExposedConditionally(self):
         return (self.interface.getExtendedAttribute("Pref") or
                 self.interface.getExtendedAttribute("ChromeOnly") or
                 self.interface.getExtendedAttribute("Func") or
                 self.interface.getExtendedAttribute("AvailableIn") or
-                self.interface.getExtendedAttribute("CheckPermissions"))
+                self.interface.getExtendedAttribute("CheckPermissions") or
+                (not self.workers and not self.interface.isExposedInWindow()) or
+                (self.interface.isExposedInAnyWorker() and
+                 self.interface.isExposedOnlyInSomeWorkers()))
 
     def needsXrayResolveHooks(self):
         """
         Generally, any interface with NeedNewResolve needs Xray
         resolveOwnProperty and enumerateOwnProperties hooks.  But for
         the special case of plugin-loading elements, we do NOT want
         those, because we don't want to instantiate plug-ins simply
         due to chrome touching them and that's all those hooks do on
--- a/dom/bindings/parser/WebIDL.py
+++ b/dom/bindings/parser/WebIDL.py
@@ -1050,16 +1050,31 @@ class IDLInterface(IDLObjectWithScope):
             len(self.getConsequentialInterfaces()) == 0 and
             # No attributes of any kinds
             not any(m.isAttr() for m in self.members) and
             # There is at least one regular operation, and all regular
             # operations have the same identifier
             len(set(m.identifier.name for m in self.members if
                     m.isMethod() and not m.isStatic())) == 1)
 
+    def isExposedInWindow(self):
+        return 'Window' in self.exposureSet
+
+    def isExposedInAnyWorker(self):
+        return len(self.getWorkerExposureSet()) > 0
+
+    def isExposedOnlyInSomeWorkers(self):
+        assert self.isExposedInAnyWorker()
+        workerScopes = self.parentScope.globalNameMapping["Worker"]
+        return len(workerScopes.difference(self.exposureSet)) > 0
+
+    def getWorkerExposureSet(self):
+        workerScopes = self.parentScope.globalNameMapping["Worker"]
+        return workerScopes.intersection(self.exposureSet)
+
     def inheritanceDepth(self):
         depth = 0
         parent = self.parent
         while parent:
             depth = depth + 1
             parent = parent.parent
         return depth