Bug 1119490 - Expose the URL constructor to WorkerDebuggerGlobalScope;r=khuey
authorEddy Bruel <ejpbruel@mozilla.com>
Mon, 22 Feb 2016 10:41:09 +0100
changeset 321436 758daaf1723f377d853d2547b072d49559d8b494
parent 321435 f4da8a4682a8baf7ddeb487ebcccf63d8b17649e
child 321437 457f567214ca3f744c886f8aef314e343544d1fe
push id5913
push userjlund@mozilla.com
push dateMon, 25 Apr 2016 16:57:49 +0000
treeherdermozilla-beta@dcaf0a6fa115 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerskhuey
bugs1119490
milestone47.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 1119490 - Expose the URL constructor to WorkerDebuggerGlobalScope;r=khuey
dom/bindings/Codegen.py
dom/bindings/Configuration.py
dom/bindings/mozwebidlcodegen/__init__.py
dom/bindings/parser/WebIDL.py
dom/webidl/URL.webidl
dom/webidl/URLSearchParams.webidl
dom/workers/RegisterBindings.cpp
dom/workers/WorkerPrivate.cpp
dom/workers/WorkerPrivate.h
--- a/dom/bindings/Codegen.py
+++ b/dom/bindings/Codegen.py
@@ -12821,16 +12821,56 @@ class CGRegisterWorkerBindings(CGAbstrac
                     "%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 CGRegisterWorkerDebuggerBindings(CGAbstractMethod):
+    def __init__(self, config):
+        CGAbstractMethod.__init__(self, None, 'RegisterWorkerDebuggerBindings', 'bool',
+                                  [Argument('JSContext*', 'aCx'),
+                                   Argument('JS::Handle<JSObject*>', 'aObj')])
+        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,
+                                                 isExposedInWorkerDebugger=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,
+                                           isExposedInWorkerDebugger=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 CGResolveSystemBinding(CGAbstractMethod):
     def __init__(self, config):
         CGAbstractMethod.__init__(self, None, 'ResolveSystemBinding', 'bool',
                                   [Argument('JSContext*', 'aCx'),
                                    Argument('JS::Handle<JSObject*>', 'aObj'),
                                    Argument('JS::Handle<jsid>', 'aId'),
                                    Argument('bool*', 'aResolvedp')])
@@ -16077,16 +16117,42 @@ class GlobalGenRoots():
 
         # Add include guards.
         curr = CGIncludeGuard('RegisterWorkerBindings', curr)
 
         # Done.
         return curr
 
     @staticmethod
+    def RegisterWorkerDebuggerBindings(config):
+
+        curr = CGRegisterWorkerDebuggerBindings(config)
+
+        # Wrap all of that in our namespaces.
+        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,
+                                                            isExposedInWorkerDebugger=True,
+                                                            skipGen=False)]
+
+        curr = CGHeaders([], [], [], [], [], defineIncludes,
+                         'RegisterWorkerDebuggerBindings', curr)
+
+        # Add include guards.
+        curr = CGIncludeGuard('RegisterWorkerDebuggerBindings', curr)
+
+        # Done.
+        return curr
+
+    @staticmethod
     def ResolveSystemBinding(config):
 
         curr = CGResolveSystemBinding(config)
 
         # Wrap all of that in our namespaces.
         curr = CGNamespace.build(['mozilla', 'dom'],
                                  CGWrapper(curr, post='\n'))
         curr = CGWrapper(curr, post='\n')
--- a/dom/bindings/Configuration.py
+++ b/dom/bindings/Configuration.py
@@ -223,16 +223,18 @@ class Configuration:
             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() is not None
             elif key == 'isExposedInAnyWorker':
                 getter = lambda x: x.interface.isExposedInAnyWorker()
+            elif key == 'isExposedInWorkerDebugger':
+                getter = lambda x: x.interface.isExposedInWorkerDebugger()
             elif key == 'isExposedInSystemGlobals':
                 getter = lambda x: x.interface.isExposedInSystemGlobals()
             elif key == 'isExposedInWindow':
                 getter = lambda x: x.interface.isExposedInWindow()
             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)
--- a/dom/bindings/mozwebidlcodegen/__init__.py
+++ b/dom/bindings/mozwebidlcodegen/__init__.py
@@ -128,25 +128,27 @@ class WebIDLCodegenManager(LoggingMixin)
     # Global parser derived declaration files.
     GLOBAL_DECLARE_FILES = {
         'FeatureList.h',
         'GeneratedAtomList.h',
         'GeneratedEventList.h',
         'PrototypeList.h',
         'RegisterBindings.h',
         'RegisterWorkerBindings.h',
+        'RegisterWorkerDebuggerBindings.h',
         'ResolveSystemBinding.h',
         'UnionConversions.h',
         'UnionTypes.h',
     }
 
     # Global parser derived definition files.
     GLOBAL_DEFINE_FILES = {
         'RegisterBindings.cpp',
         'RegisterWorkerBindings.cpp',
+        'RegisterWorkerDebuggerBindings.cpp',
         'ResolveSystemBinding.cpp',
         'UnionTypes.cpp',
         'PrototypeList.cpp',
     }
 
     def __init__(self, config_path, inputs, exported_header_dir,
                  codegen_dir, state_path, cache_dir=None, make_deps_path=None,
                  make_deps_target=None):
--- a/dom/bindings/parser/WebIDL.py
+++ b/dom/bindings/parser/WebIDL.py
@@ -503,16 +503,19 @@ class IDLExposureMixins():
 
     def isExposedOnMainThread(self):
         return (self.isExposedInWindow() or
                 self.isExposedInSystemGlobals())
 
     def isExposedInAnyWorker(self):
         return len(self.getWorkerExposureSet()) > 0
 
+    def isExposedInWorkerDebugger(self):
+        return len(self.getWorkerDebuggerExposureSet()) > 0
+
     def isExposedInSystemGlobals(self):
         return 'BackstagePass' in self.exposureSet
 
     def isExposedInSomeButNotAllWorkers(self):
         """
         Returns true if the Exposed extended attribute for this interface
         exposes it in some worker globals but not others.  The return value does
         not depend on whether the interface is exposed in Window or System
@@ -522,16 +525,20 @@ class IDLExposureMixins():
             return False
         workerScopes = self.parentScope.globalNameMapping["Worker"]
         return len(workerScopes.difference(self.exposureSet)) > 0
 
     def getWorkerExposureSet(self):
         workerScopes = self._globalScope.globalNameMapping["Worker"]
         return workerScopes.intersection(self.exposureSet)
 
+    def getWorkerDebuggerExposureSet(self):
+        workerDebuggerScopes = self._globalScope.globalNameMapping["WorkerDebugger"]
+        return workerDebuggerScopes.intersection(self.exposureSet)
+
 
 class IDLExternalInterface(IDLObjectWithIdentifier, IDLExposureMixins):
     def __init__(self, location, parentScope, identifier):
         assert isinstance(identifier, IDLUnresolvedIdentifier)
         assert isinstance(parentScope, IDLScope)
         self.parent = None
         IDLObjectWithIdentifier.__init__(self, location, parentScope, identifier)
         IDLExposureMixins.__init__(self, location)
--- a/dom/webidl/URL.webidl
+++ b/dom/webidl/URL.webidl
@@ -10,17 +10,17 @@
  *
  * Copyright © 2012 W3C® (MIT, ERCIM, Keio), All Rights Reserved. W3C
  * liability, trademark and document use rules apply.
  */
 
 // [Constructor(DOMString url, optional (URL or DOMString) base = "about:blank")]
 [Constructor(DOMString url, URL base),
  Constructor(DOMString url, optional DOMString base),
- Exposed=(Window,Worker)]
+ Exposed=(Window,Worker,WorkerDebugger)]
 interface URL {
   // Bug 824857: no support for stringifier attributes yet.
   //  stringifier attribute USVString href;
 
   // Bug 824857 should remove this.
   [Throws=Workers]
   stringifier;
 
--- a/dom/webidl/URLSearchParams.webidl
+++ b/dom/webidl/URLSearchParams.webidl
@@ -10,17 +10,17 @@
  * and related or neighboring rights to this work. In addition, as of 17
  * February 2013, the editors have made this specification available under
  * the Open Web Foundation Agreement Version 1.0, which is available at
  * http://www.openwebfoundation.org/legal/the-owf-1-0-agreements/owfa-1-0.
  */
 
 [Constructor(optional USVString init = ""),
  Constructor(URLSearchParams init),
- Exposed=(Window,Worker,System)]
+ Exposed=(Window,Worker,WorkerDebugger,System)]
 interface URLSearchParams {
   void append(USVString name, USVString value);
   void delete(USVString name);
   USVString? get(USVString name);
   sequence<USVString> getAll(USVString name);
   boolean has(USVString name);
   void set(USVString name, USVString value);
   iterable<USVString, USVString>;
--- a/dom/workers/RegisterBindings.cpp
+++ b/dom/workers/RegisterBindings.cpp
@@ -5,16 +5,17 @@
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "WorkerPrivate.h"
 #include "ChromeWorkerScope.h"
 #include "RuntimeService.h"
 
 #include "jsapi.h"
 #include "mozilla/dom/RegisterWorkerBindings.h"
+#include "mozilla/dom/RegisterWorkerDebuggerBindings.h"
 #include "mozilla/OSFileConstants.h"
 
 USING_WORKERS_NAMESPACE
 using namespace mozilla::dom;
 
 bool
 WorkerPrivate::RegisterBindings(JSContext* aCx, JS::Handle<JSObject*> aGlobal)
 {
@@ -31,8 +32,24 @@ WorkerPrivate::RegisterBindings(JSContex
   }
 
   if (!JS_DefineProfilingFunctions(aCx, aGlobal)) {
     return false;
   }
 
   return true;
 }
+
+bool
+WorkerPrivate::RegisterDebuggerBindings(JSContext* aCx,
+                                        JS::Handle<JSObject*> aGlobal)
+{
+  // Init Web IDL bindings
+  if (!RegisterWorkerDebuggerBindings(aCx, aGlobal)) {
+    return false;
+  }
+
+  if (!JS_DefineDebuggerObject(aCx, aGlobal)) {
+    return false;
+  }
+
+  return true;
+}
--- a/dom/workers/WorkerPrivate.cpp
+++ b/dom/workers/WorkerPrivate.cpp
@@ -6435,24 +6435,28 @@ WorkerPrivate::CreateDebuggerGlobalScope
   RefPtr<WorkerDebuggerGlobalScope> globalScope =
     new WorkerDebuggerGlobalScope(this);
 
   JS::Rooted<JSObject*> global(aCx);
   NS_ENSURE_TRUE(globalScope->WrapGlobalObject(aCx, &global), nullptr);
 
   JSAutoCompartment ac(aCx, global);
 
-  if (!JS_DefineDebuggerObject(aCx, global)) {
+  // RegisterDebuggerBindings() can spin a nested event loop so we have to set
+  // mDebuggerScope before calling it, and we have to make sure to unset
+  // mDebuggerScope if it fails.
+  mDebuggerScope = Move(globalScope);
+
+  if (!RegisterDebuggerBindings(aCx, global)) {
+    mDebuggerScope = nullptr;
     return nullptr;
   }
 
   JS_FireOnNewGlobalObject(aCx, global);
 
-  mDebuggerScope = globalScope.forget();
-
   return mDebuggerScope;
 }
 
 #ifdef DEBUG
 
 void
 WorkerPrivate::AssertIsOnWorkerThread() const
 {
--- a/dom/workers/WorkerPrivate.h
+++ b/dom/workers/WorkerPrivate.h
@@ -1259,16 +1259,19 @@ public:
   GetOrCreateGlobalScope(JSContext* aCx);
 
   WorkerDebuggerGlobalScope*
   CreateDebuggerGlobalScope(JSContext* aCx);
 
   bool
   RegisterBindings(JSContext* aCx, JS::Handle<JSObject*> aGlobal);
 
+  bool
+  RegisterDebuggerBindings(JSContext* aCx, JS::Handle<JSObject*> aGlobal);
+
 #define WORKER_SIMPLE_PREF(name, getter, NAME)                                \
   bool                                                                        \
   getter() const                                                              \
   {                                                                           \
     AssertIsOnWorkerThread();                                                 \
     return mPreferences[WORKERPREF_##NAME];                                   \
   }
 #define WORKER_PREF(name, callback)