Bug 1535124 part 2. Mark Web IDL callbacks MOZ_CAN_RUN_SCRIPT by default. r=qdot
authorBoris Zbarsky <bzbarsky@mit.edu>
Tue, 19 Mar 2019 12:59:54 +0000
changeset 465262 b0af7322659c66d6bd72958713c5737f3ce30822
parent 465261 687da2cdbee54115e0a86fca32246402b37ac6d6
child 465263 3ab48ce01773af9a130477e46c50e17f9042ea4b
push id112496
push usershindli@mozilla.com
push dateThu, 21 Mar 2019 04:37:39 +0000
treeherdermozilla-inbound@29476d3ca61d [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersqdot
bugs1535124
milestone68.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 1535124 part 2. Mark Web IDL callbacks MOZ_CAN_RUN_SCRIPT by default. r=qdot We add a [MOZ_CAN_RUN_SCRIPT_BOUNDARY] opt-out for now to keep the tree compiling. The naming purposefully matches the C++ annotation that has a similar effect, top make it easy to search for. Differential Revision: https://phabricator.services.mozilla.com/D23520
dom/bindings/Codegen.py
dom/bindings/parser/WebIDL.py
dom/bindings/test/TestFunctions.h
dom/chrome-webidl/PlacesObservers.webidl
dom/chrome-webidl/SessionStoreUtils.webidl
dom/chrome-webidl/WebExtensionPolicy.webidl
dom/webidl/BaseAudioContext.webidl
dom/webidl/Console.webidl
dom/webidl/CustomElementRegistry.webidl
dom/webidl/DataTransferItem.webidl
dom/webidl/EventHandler.webidl
dom/webidl/FileSystem.webidl
dom/webidl/FileSystemDirectoryReader.webidl
dom/webidl/FileSystemFileEntry.webidl
dom/webidl/FontFaceSet.webidl
dom/webidl/Function.webidl
dom/webidl/Geolocation.webidl
dom/webidl/HTMLCanvasElement.webidl
dom/webidl/IntersectionObserver.webidl
dom/webidl/L10nUtils.webidl
dom/webidl/MutationObserver.webidl
dom/webidl/Navigator.webidl
dom/webidl/Notification.webidl
dom/webidl/PerformanceObserver.webidl
dom/webidl/Promise.webidl
dom/webidl/RTCIdentityProvider.webidl
dom/webidl/Reporting.webidl
dom/webidl/U2F.webidl
dom/webidl/WebComponents.webidl
dom/webidl/WebrtcGlobalInformation.webidl
dom/webidl/Window.webidl
--- a/dom/bindings/Codegen.py
+++ b/dom/bindings/Codegen.py
@@ -10640,17 +10640,17 @@ class ClassBase(ClassItem):
         return ''
 
 
 class ClassMethod(ClassItem):
     def __init__(self, name, returnType, args, inline=False, static=False,
                  virtual=False, const=False, bodyInHeader=False,
                  templateArgs=None, visibility='public', body=None,
                  breakAfterReturnDecl="\n",
-                 breakAfterSelf="\n", override=False):
+                 breakAfterSelf="\n", override=False, canRunScript=False):
         """
         override indicates whether to flag the method as override
         """
         assert not override or virtual
         assert not (override and static)
         self.returnType = returnType
         self.args = args
         self.inline = inline or bodyInHeader
@@ -10658,20 +10658,23 @@ class ClassMethod(ClassItem):
         self.virtual = virtual
         self.const = const
         self.bodyInHeader = bodyInHeader
         self.templateArgs = templateArgs
         self.body = body
         self.breakAfterReturnDecl = breakAfterReturnDecl
         self.breakAfterSelf = breakAfterSelf
         self.override = override
+        self.canRunScript = canRunScript;
         ClassItem.__init__(self, name, visibility)
 
     def getDecorators(self, declaring):
         decorators = []
+        if self.canRunScript:
+            decorators.append('MOZ_CAN_RUN_SCRIPT')
         if self.inline:
             decorators.append('inline')
         if declaring:
             if self.static:
                 decorators.append('static')
             if self.virtual:
                 decorators.append('virtual')
         if decorators:
@@ -14778,17 +14781,17 @@ class CGBindingRoot(CGThing):
         return self.root.deps()
 
 
 class CGNativeMember(ClassMethod):
     def __init__(self, descriptorProvider, member, name, signature, extendedAttrs,
                  breakAfter=True, passJSBitsAsNeeded=True, visibility="public",
                  spiderMonkeyInterfacesAreStructs=True,
                  variadicIsSequence=False, resultNotAddRefed=False,
-                 virtual=False, override=False):
+                 virtual=False, override=False, canRunScript=False):
         """
         If spiderMonkeyInterfacesAreStructs is false, SpiderMonkey interfaces
         will be passed as JS::Handle<JSObject*>.  If it's true they will be
         passed as one of the dom::SpiderMonkeyInterfaceObjectStorage subclasses.
 
         If passJSBitsAsNeeded is false, we don't automatically pass in a
         JSContext* or a JSObject* based on the return and argument types.  We
         can still pass it based on 'implicitJSContext' annotations.
@@ -14808,17 +14811,18 @@ class CGNativeMember(ClassMethod):
                              # Mark our getters, which are attrs that
                              # have a non-void return type, as const.
                              const=(not member.isStatic() and member.isAttr() and
                                     not signature[0].isVoid()),
                              breakAfterReturnDecl=" ",
                              breakAfterSelf=breakAfterSelf,
                              visibility=visibility,
                              virtual=virtual,
-                             override=override)
+                             override=override,
+                             canRunScript=canRunScript)
 
     def getReturnType(self, type, isMember):
         return self.getRetvalInfo(type, isMember)[0]
 
     def getRetvalInfo(self, type, isMember):
         """
         Returns a tuple:
 
@@ -16222,27 +16226,31 @@ class CGCallback(CGClass):
             return ${methodName}(${callArgs});
             """,
             methodName=method.name,
             callArgs=", ".join(argnamesWithoutThisAndRv))
 
         return [ClassMethod(method.name, method.returnType, args,
                             bodyInHeader=True,
                             templateArgs=["typename T"],
-                            body=bodyWithThis),
+                            body=bodyWithThis,
+                            canRunScript=method.canRunScript),
                 ClassMethod(method.name, method.returnType, argsWithoutThis,
                             bodyInHeader=True,
-                            body=bodyWithoutThis),
+                            body=bodyWithoutThis,
+                            canRunScript=method.canRunScript),
                 ClassMethod(method.name, method.returnType, argsWithoutRv,
                             bodyInHeader=True,
                             templateArgs=["typename T"],
-                            body=bodyWithThisWithoutRv),
+                            body=bodyWithThisWithoutRv,
+                            canRunScript=method.canRunScript),
                 ClassMethod(method.name, method.returnType, argsWithoutThisAndRv,
                             bodyInHeader=True,
-                            body=bodyWithoutThisAndRv),
+                            body=bodyWithoutThisAndRv,
+                            canRunScript=method.canRunScript),
                 method]
 
     def deps(self):
         return self._deps
 
 
 class CGCallbackFunction(CGCallback):
     def __init__(self, callback, descriptorProvider):
@@ -16383,17 +16391,18 @@ class FakeMember():
 
 class CallbackMember(CGNativeMember):
     # XXXbz It's OK to use CallbackKnownNotGray for wrapScope because
     # CallSetup already handled the unmark-gray bits for us. we don't have
     # anything better to use for 'obj', really...
     def __init__(self, sig, name, descriptorProvider, needThisHandling,
                  rethrowContentException=False,
                  spiderMonkeyInterfacesAreStructs=False,
-                 wrapScope='CallbackKnownNotGray()'):
+                 wrapScope='CallbackKnownNotGray()',
+                 canRunScript=False):
         """
         needThisHandling is True if we need to be able to accept a specified
         thisObj, False otherwise.
         """
         assert not rethrowContentException or not needThisHandling
 
         self.retvalType = sig[0]
         self.originalSig = sig
@@ -16417,17 +16426,18 @@ class CallbackMember(CGNativeMember):
         # We don't care, for callback codegen, whether our original member was
         # a method or attribute or whatnot.  Just always pass FakeMember()
         # here.
         CGNativeMember.__init__(self, descriptorProvider, FakeMember(),
                                 name, (self.retvalType, args),
                                 extendedAttrs={},
                                 passJSBitsAsNeeded=False,
                                 visibility=visibility,
-                                spiderMonkeyInterfacesAreStructs=spiderMonkeyInterfacesAreStructs)
+                                spiderMonkeyInterfacesAreStructs=spiderMonkeyInterfacesAreStructs,
+                                canRunScript=canRunScript)
         # We have to do all the generation of our body now, because
         # the caller relies on us throwing if we can't manage it.
         self.exceptionCode = ("aRv.Throw(NS_ERROR_UNEXPECTED);\n"
                               "return%s;\n" % self.getDefaultRetval())
         self.body = self.getImpl()
 
     def getImpl(self):
         setupCall = self.getCallSetup()
@@ -16639,20 +16649,22 @@ class CallbackMember(CGNativeMember):
                               "that.  %s" %
                               (type, idlObject.identifier.name,
                                idlObject.location))
 
 
 class CallbackMethod(CallbackMember):
     def __init__(self, sig, name, descriptorProvider, needThisHandling,
                  rethrowContentException=False,
-                 spiderMonkeyInterfacesAreStructs=False):
+                 spiderMonkeyInterfacesAreStructs=False,
+                 canRunScript=False):
         CallbackMember.__init__(self, sig, name, descriptorProvider,
                                 needThisHandling, rethrowContentException,
-                                spiderMonkeyInterfacesAreStructs=spiderMonkeyInterfacesAreStructs)
+                                spiderMonkeyInterfacesAreStructs=spiderMonkeyInterfacesAreStructs,
+                                canRunScript=canRunScript)
 
     def getRvalDecl(self):
         return "JS::Rooted<JS::Value> rval(cx, JS::UndefinedValue());\n"
 
     def getCall(self):
         if self.argCount > 0:
             args = "JS::HandleValueArray::subarray(argv, 0, argc)"
         else:
@@ -16675,17 +16687,18 @@ class CallbackMethod(CallbackMember):
             args=args,
             errorReturn=self.getDefaultRetval())
 
 
 class CallCallback(CallbackMethod):
     def __init__(self, callback, descriptorProvider):
         self.callback = callback
         CallbackMethod.__init__(self, callback.signatures()[0], "Call",
-                                descriptorProvider, needThisHandling=True)
+                                descriptorProvider, needThisHandling=True,
+                                canRunScript=not callback.isRunScriptBoundary())
 
     def getThisDecl(self):
         return ""
 
     def getThisVal(self):
         return "aThisVal"
 
     def getCallableDecl(self):
--- a/dom/bindings/parser/WebIDL.py
+++ b/dom/bindings/parser/WebIDL.py
@@ -4659,16 +4659,17 @@ class IDLCallback(IDLObjectWithScope):
         IDLObjectWithScope.__init__(self, location, parentScope, identifier)
 
         for (returnType, arguments) in self.signatures():
             for argument in arguments:
                 argument.resolve(self)
 
         self._treatNonCallableAsNull = False
         self._treatNonObjectAsNull = False
+        self._isRunScriptBoundary = False
 
     def isCallback(self):
         return True
 
     def signatures(self):
         return [(self._returnType, self._arguments)]
 
     def finish(self, scope):
@@ -4696,27 +4697,32 @@ class IDLCallback(IDLObjectWithScope):
 
     def addExtendedAttributes(self, attrs):
         unhandledAttrs = []
         for attr in attrs:
             if attr.identifier() == "TreatNonCallableAsNull":
                 self._treatNonCallableAsNull = True
             elif attr.identifier() == "TreatNonObjectAsNull":
                 self._treatNonObjectAsNull = True
+            elif attr.identifier() == "MOZ_CAN_RUN_SCRIPT_BOUNDARY":
+                self._isRunScriptBoundary = True
             else:
                 unhandledAttrs.append(attr)
         if self._treatNonCallableAsNull and self._treatNonObjectAsNull:
             raise WebIDLError("Cannot specify both [TreatNonCallableAsNull] "
                               "and [TreatNonObjectAsNull]", [self.location])
         if len(unhandledAttrs) != 0:
             IDLType.addExtendedAttributes(self, unhandledAttrs)
 
     def _getDependentObjects(self):
         return set([self._returnType] + self._arguments)
 
+    def isRunScriptBoundary(self):
+        return self._isRunScriptBoundary;
+
 
 class IDLCallbackType(IDLType):
     def __init__(self, location, callback):
         IDLType.__init__(self, location, callback.identifier.name)
         self.callback = callback
 
     def isCallback(self):
         return True
--- a/dom/bindings/test/TestFunctions.h
+++ b/dom/bindings/test/TestFunctions.h
@@ -23,16 +23,17 @@ class TestFunctions : public NonRefcount
  public:
   static TestFunctions* Constructor(GlobalObject& aGlobal, ErrorResult& aRv);
 
   static void ThrowUncatchableException(GlobalObject& aGlobal,
                                         ErrorResult& aRv);
 
   static Promise* PassThroughPromise(GlobalObject& aGlobal, Promise& aPromise);
 
+  MOZ_CAN_RUN_SCRIPT
   static already_AddRefed<Promise> PassThroughCallbackPromise(
       GlobalObject& aGlobal, PromiseReturner& aCallback, ErrorResult& aRv);
 
   void SetStringData(const nsAString& aString);
 
   void GetStringDataAsAString(nsAString& aString);
   void GetStringDataAsAString(uint32_t aLength, nsAString& aString);
   void GetStringDataAsDOMString(const Optional<uint32_t>& aLength,
--- a/dom/chrome-webidl/PlacesObservers.webidl
+++ b/dom/chrome-webidl/PlacesObservers.webidl
@@ -1,14 +1,15 @@
 /* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/.
  */
 
+[MOZ_CAN_RUN_SCRIPT_BOUNDARY]
 callback PlacesEventCallback = void (sequence<PlacesEvent> events);
 
 [ChromeOnly, Exposed=Window,
  Constructor(PlacesEventCallback callback)]
 interface PlacesWeakCallbackWrapper {
 };
 
 // Global singleton which should handle all events for places.
--- a/dom/chrome-webidl/SessionStoreUtils.webidl
+++ b/dom/chrome-webidl/SessionStoreUtils.webidl
@@ -3,16 +3,17 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 interface nsIDocShell;
 interface nsISupports;
 
 /**
  * A callback passed to SessionStoreUtils.forEachNonDynamicChildFrame().
  */
+[MOZ_CAN_RUN_SCRIPT_BOUNDARY]
 callback SessionStoreUtilsFrameCallback = void (WindowProxy frame, unsigned long index);
 
 /**
  * SessionStore utility functions implemented in C++ for performance reasons.
  */
 [ChromeOnly, Exposed=Window]
 namespace SessionStoreUtils {
   /**
--- a/dom/chrome-webidl/WebExtensionPolicy.webidl
+++ b/dom/chrome-webidl/WebExtensionPolicy.webidl
@@ -1,15 +1,16 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 interface URI;
 interface WindowProxy;
 
+[MOZ_CAN_RUN_SCRIPT_BOUNDARY]
 callback WebExtensionLocalizeCallback = DOMString (DOMString unlocalizedText);
 
 /**
  * Defines the platform-level policies for a WebExtension, including its
  * permissions and the characteristics of its moz-extension: URLs.
  */
 [Constructor(WebExtensionInit options), ChromeOnly, Exposed=Window]
 interface WebExtensionPolicy {
--- a/dom/webidl/BaseAudioContext.webidl
+++ b/dom/webidl/BaseAudioContext.webidl
@@ -5,17 +5,19 @@
  *
  * The origin of this IDL file is
  * https://webaudio.github.io/web-audio-api/#idl-def-BaseAudioContext
  *
  * Copyright © 2012 W3C® (MIT, ERCIM, Keio), All Rights Reserved. W3C
  * liability, trademark and document use rules apply.
  */
 
+[MOZ_CAN_RUN_SCRIPT_BOUNDARY]
 callback DecodeSuccessCallback = void (AudioBuffer decodedData);
+[MOZ_CAN_RUN_SCRIPT_BOUNDARY]
 callback DecodeErrorCallback = void (DOMException error);
 
 enum AudioContextState {
     "suspended",
     "running",
     "closed"
 };
 
--- a/dom/webidl/Console.webidl
+++ b/dom/webidl/Console.webidl
@@ -184,16 +184,17 @@ interface ConsoleInstance {
 
   void _exception(any... data);
   void timeStamp(optional any data);
 
   void profile(any... data);
   void profileEnd(any... data);
 };
 
+[MOZ_CAN_RUN_SCRIPT_BOUNDARY]
 callback ConsoleInstanceDumpCallback = void (DOMString message);
 
 enum ConsoleLogLevel {
   "All", "Debug", "Log", "Info", "Clear", "Trace", "TimeLog", "TimeEnd", "Time",
   "Group", "GroupEnd", "Profile", "ProfileEnd", "Dir", "Dirxml", "Warn", "Error",
   "Off"
 };
 
--- a/dom/webidl/CustomElementRegistry.webidl
+++ b/dom/webidl/CustomElementRegistry.webidl
@@ -14,9 +14,10 @@ interface CustomElementRegistry {
   Promise<void> whenDefined(DOMString name);
   [CEReactions] void upgrade(Node root);
 };
 
 dictionary ElementDefinitionOptions {
   DOMString extends;
 };
 
+[MOZ_CAN_RUN_SCRIPT_BOUNDARY]
 callback CustomElementCreationCallback = void (DOMString name);
--- a/dom/webidl/DataTransferItem.webidl
+++ b/dom/webidl/DataTransferItem.webidl
@@ -12,16 +12,17 @@ interface DataTransferItem {
   readonly attribute DOMString kind;
   readonly attribute DOMString type;
   [Throws, NeedsSubjectPrincipal]
   void getAsString(FunctionStringCallback? _callback);
   [Throws, NeedsSubjectPrincipal]
   File? getAsFile();
 };
 
+[MOZ_CAN_RUN_SCRIPT_BOUNDARY]
 callback FunctionStringCallback = void (DOMString data);
 
 // https://wicg.github.io/entries-api/#idl-index
 partial interface DataTransferItem {
   [Pref="dom.webkitBlink.filesystem.enabled", BinaryName="getAsEntry", Throws,
    NeedsSubjectPrincipal]
   FileSystemEntry? webkitGetAsEntry();
 };
--- a/dom/webidl/EventHandler.webidl
+++ b/dom/webidl/EventHandler.webidl
@@ -5,25 +5,25 @@
  *
  * The origin of this IDL file is
  * http://www.whatwg.org/specs/web-apps/current-work/#eventhandler
  *
  * © Copyright 2004-2011 Apple Computer, Inc., Mozilla Foundation, and
  * Opera Software ASA. You are granted a license to use, reproduce
  * and create derivative works of this document.
  */
-[TreatNonObjectAsNull]
+[TreatNonObjectAsNull, MOZ_CAN_RUN_SCRIPT_BOUNDARY]
 callback EventHandlerNonNull = any (Event event);
 typedef EventHandlerNonNull? EventHandler;
 
-[TreatNonObjectAsNull]
+[TreatNonObjectAsNull, MOZ_CAN_RUN_SCRIPT_BOUNDARY]
 callback OnBeforeUnloadEventHandlerNonNull = DOMString? (Event event);
 typedef OnBeforeUnloadEventHandlerNonNull? OnBeforeUnloadEventHandler;
 
-[TreatNonObjectAsNull]
+[TreatNonObjectAsNull, MOZ_CAN_RUN_SCRIPT_BOUNDARY]
 callback OnErrorEventHandlerNonNull = any ((Event or DOMString) event, optional DOMString source, optional unsigned long lineno, optional unsigned long column, optional any error);
 typedef OnErrorEventHandlerNonNull? OnErrorEventHandler;
 
 [NoInterfaceObject]
 interface GlobalEventHandlers {
            attribute EventHandler onabort;
            attribute EventHandler onblur;
 // We think the spec is wrong here. See OnErrorEventHandlerForNodes/Window
--- a/dom/webidl/FileSystem.webidl
+++ b/dom/webidl/FileSystem.webidl
@@ -6,16 +6,18 @@
  * https://wicg.github.io/entries-api/#idl-index
  */
 
 dictionary FileSystemFlags {
     boolean create = false;
     boolean exclusive = false;
 };
 
+[MOZ_CAN_RUN_SCRIPT_BOUNDARY]
 callback FileSystemEntryCallback = void (FileSystemEntry entry);
 
+[MOZ_CAN_RUN_SCRIPT_BOUNDARY]
 callback ErrorCallback = void (DOMException err);
 
 interface FileSystem {
     readonly    attribute USVString name;
     readonly    attribute FileSystemDirectoryEntry root;
 };
--- a/dom/webidl/FileSystemDirectoryReader.webidl
+++ b/dom/webidl/FileSystemDirectoryReader.webidl
@@ -1,16 +1,17 @@
 /* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/.
  *
  * https://wicg.github.io/entries-api/#idl-index
  */
 
+[MOZ_CAN_RUN_SCRIPT_BOUNDARY]
 callback FileSystemEntriesCallback = void (sequence<FileSystemEntry> entries);
 
 interface FileSystemDirectoryReader {
 
     // readEntries can be called just once. The second time it returns no data.
 
     [Throws]
     void readEntries(FileSystemEntriesCallback successCallback,
--- a/dom/webidl/FileSystemFileEntry.webidl
+++ b/dom/webidl/FileSystemFileEntry.webidl
@@ -1,15 +1,16 @@
 /* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/.
  *
  * https://wicg.github.io/entries-api/#idl-index
  */
 
+[MOZ_CAN_RUN_SCRIPT_BOUNDARY]
 callback FileCallback = void (File file);
 
 interface FileSystemFileEntry : FileSystemEntry {
     [BinaryName="GetFile"]
     void file (FileCallback successCallback,
                optional ErrorCallback errorCallback);
 };
--- a/dom/webidl/FontFaceSet.webidl
+++ b/dom/webidl/FontFaceSet.webidl
@@ -18,16 +18,17 @@ dictionary FontFaceSetIteratorResult
 };
 
 // To implement FontFaceSet's iterator until we can use setlike.
 [NoInterfaceObject]
 interface FontFaceSetIterator {
   [Throws] FontFaceSetIteratorResult next();
 };
 
+[MOZ_CAN_RUN_SCRIPT_BOUNDARY]
 callback FontFaceSetForEachCallback = void (FontFace value, FontFace key, FontFaceSet set);
 
 enum FontFaceSetLoadStatus { "loading", "loaded" };
 
 // Bug 1072762 is for the FontFaceSet constructor.
 // [Constructor(sequence<FontFace> initialFaces)]
 [Pref="layout.css.font-loading-api.enabled"]
 interface FontFaceSet : EventTarget {
--- a/dom/webidl/Function.webidl
+++ b/dom/webidl/Function.webidl
@@ -5,12 +5,12 @@
  *
  * The origin of this IDL file is
  * http://www.whatwg.org/specs/web-apps/current-work/#functiocn
  *
  * © Copyright 2004-2011 Apple Computer, Inc., Mozilla Foundation, and
  * Opera Software ASA. You are granted a license to use, reproduce
  * and create derivative works of this document.
  */
-
+[MOZ_CAN_RUN_SCRIPT_BOUNDARY]
 callback Function = any(any... arguments);
 
 callback VoidFunction = void ();
--- a/dom/webidl/Geolocation.webidl
+++ b/dom/webidl/Geolocation.webidl
@@ -26,11 +26,13 @@ interface Geolocation {
   [Throws, NeedsCallerType]
   long watchPosition(PositionCallback successCallback,
                      optional PositionErrorCallback? errorCallback = null,
                      optional PositionOptions options);
 
   void clearWatch(long watchId);
 };
 
+[MOZ_CAN_RUN_SCRIPT_BOUNDARY]
 callback PositionCallback = void (Position position);
 
+[MOZ_CAN_RUN_SCRIPT_BOUNDARY]
 callback PositionErrorCallback = void (PositionError positionError);
--- a/dom/webidl/HTMLCanvasElement.webidl
+++ b/dom/webidl/HTMLCanvasElement.webidl
@@ -61,11 +61,13 @@ interface MozCanvasPrintState
 {
   // A canvas rendering context.
   readonly attribute nsISupports context;
 
   // To be called when rendering to the context is done.
   void done();
 };
 
+[MOZ_CAN_RUN_SCRIPT_BOUNDARY]
 callback PrintCallback = void(MozCanvasPrintState ctx);
 
+[MOZ_CAN_RUN_SCRIPT_BOUNDARY]
 callback BlobCallback = void(Blob? blob);
--- a/dom/webidl/IntersectionObserver.webidl
+++ b/dom/webidl/IntersectionObserver.webidl
@@ -39,16 +39,17 @@ interface IntersectionObserver {
   void unobserve(Element target);
   void disconnect();
   sequence<IntersectionObserverEntry> takeRecords();
 
   [ChromeOnly]
   readonly attribute IntersectionCallback intersectionCallback;
 };
 
+[MOZ_CAN_RUN_SCRIPT_BOUNDARY]
 callback IntersectionCallback =
   void (sequence<IntersectionObserverEntry> entries, IntersectionObserver observer);
 
 dictionary IntersectionObserverEntryInit {
   required DOMHighResTimeStamp time;
   required DOMRectInit rootBounds;
   required DOMRectInit boundingClientRect;
   required DOMRectInit intersectionRect;
--- a/dom/webidl/L10nUtils.webidl
+++ b/dom/webidl/L10nUtils.webidl
@@ -29,10 +29,11 @@ dictionary AttributeNameValue {
   required DOMString value;
 };
 
 dictionary L10nValue {
   DOMString? value = null;
   sequence<AttributeNameValue>? attributes = null;
 };
 
+[MOZ_CAN_RUN_SCRIPT_BOUNDARY]
 callback L10nCallback =
   Promise<sequence<L10nValue>> (sequence<L10nElement> l10nElements);
--- a/dom/webidl/MutationObserver.webidl
+++ b/dom/webidl/MutationObserver.webidl
@@ -47,16 +47,17 @@ interface MutationObserver {
   [ChromeOnly, Throws]
   sequence<MutationObservingInfo?> getObservingInfo();
   [ChromeOnly]
   readonly attribute MutationCallback mutationCallback;
   [ChromeOnly]
   attribute boolean mergeAttributeRecords;
 };
 
+[MOZ_CAN_RUN_SCRIPT_BOUNDARY]
 callback MutationCallback = void (sequence<MutationRecord> mutations, MutationObserver observer);
 
 dictionary MutationObserverInit {
   boolean childList = false;
   boolean attributes;
   boolean characterData;
   boolean subtree = false;
   boolean attributeOldValue;
--- a/dom/webidl/Navigator.webidl
+++ b/dom/webidl/Navigator.webidl
@@ -229,33 +229,36 @@ partial interface Navigator {
 };
 
 // http://webaudio.github.io/web-midi-api/#requestmidiaccess
 partial interface Navigator {
   [Throws, Pref="dom.webmidi.enabled"]
   Promise<MIDIAccess> requestMIDIAccess(optional MIDIOptions options);
 };
 
+[MOZ_CAN_RUN_SCRIPT_BOUNDARY]
 callback NavigatorUserMediaSuccessCallback = void (MediaStream stream);
+[MOZ_CAN_RUN_SCRIPT_BOUNDARY]
 callback NavigatorUserMediaErrorCallback = void (MediaStreamError error);
 
 partial interface Navigator {
   [Throws, Func="Navigator::HasUserMediaSupport"]
   readonly attribute MediaDevices mediaDevices;
 
   // Deprecated. Use mediaDevices.getUserMedia instead.
   [Deprecated="NavigatorGetUserMedia", Throws,
    Func="Navigator::HasUserMediaSupport",
    NeedsCallerType]
   void mozGetUserMedia(MediaStreamConstraints constraints,
                        NavigatorUserMediaSuccessCallback successCallback,
                        NavigatorUserMediaErrorCallback errorCallback);
 };
 
 // nsINavigatorUserMedia
+[MOZ_CAN_RUN_SCRIPT_BOUNDARY]
 callback MozGetUserMediaDevicesSuccessCallback = void (nsIVariant? devices);
 partial interface Navigator {
   [Throws, ChromeOnly]
   void mozGetUserMediaDevices(MediaStreamConstraints constraints,
                               MozGetUserMediaDevicesSuccessCallback onsuccess,
                               NavigatorUserMediaErrorCallback onerror,
                               // The originating innerWindowID is needed to
                               // avoid calling the callbacks if the window has
--- a/dom/webidl/Notification.webidl
+++ b/dom/webidl/Notification.webidl
@@ -83,15 +83,16 @@ dictionary NotificationBehavior {
 };
 
 enum NotificationPermission {
   "default",
   "denied",
   "granted"
 };
 
+[MOZ_CAN_RUN_SCRIPT_BOUNDARY]
 callback NotificationPermissionCallback = void (NotificationPermission permission);
 
 enum NotificationDirection {
   "auto",
   "ltr",
   "rtl"
 };
--- a/dom/webidl/PerformanceObserver.webidl
+++ b/dom/webidl/PerformanceObserver.webidl
@@ -7,16 +7,17 @@
  * https://w3c.github.io/performance-timeline/#the-performanceobserver-interface
  */
 
 dictionary PerformanceObserverInit {
   required sequence<DOMString> entryTypes;
   boolean buffered = false;
 };
 
+[MOZ_CAN_RUN_SCRIPT_BOUNDARY]
 callback PerformanceObserverCallback = void (PerformanceObserverEntryList entries,
                                              PerformanceObserver observer);
 
 [Func="mozilla::dom::DOMPrefs::dom_enable_performance_observer",
  Constructor(PerformanceObserverCallback callback),
  Exposed=(Window,Worker)]
 interface PerformanceObserver {
     void observe(PerformanceObserverInit options);
--- a/dom/webidl/Promise.webidl
+++ b/dom/webidl/Promise.webidl
@@ -2,18 +2,19 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/.
  *
  * This IDL file contains utilities to help connect JS promises to our
  * Web IDL infrastructure.
  */
 
+[MOZ_CAN_RUN_SCRIPT_BOUNDARY]
 callback PromiseJobCallback = void();
 
-[TreatNonCallableAsNull]
+[TreatNonCallableAsNull, MOZ_CAN_RUN_SCRIPT_BOUNDARY]
 callback AnyCallback = any (any value);
 
 // Hack to allow us to have JS owning and properly tracing/CCing/etc a
 // PromiseNativeHandler.
 [NoInterfaceObject, Exposed=(Window,Worker)]
 interface PromiseNativeHandler {
 };
--- a/dom/webidl/RTCIdentityProvider.webidl
+++ b/dom/webidl/RTCIdentityProvider.webidl
@@ -30,20 +30,22 @@ interface RTCIdentityProviderRegistrar {
   validateAssertion(DOMString assertion, DOMString origin);
 };
 
 dictionary RTCIdentityProvider {
   required GenerateAssertionCallback generateAssertion;
   required ValidateAssertionCallback validateAssertion;
 };
 
+[MOZ_CAN_RUN_SCRIPT_BOUNDARY]
 callback GenerateAssertionCallback =
   Promise<RTCIdentityAssertionResult>
     (DOMString contents, DOMString origin,
      RTCIdentityProviderOptions options);
+[MOZ_CAN_RUN_SCRIPT_BOUNDARY]
 callback ValidateAssertionCallback =
   Promise<RTCIdentityValidationResult> (DOMString assertion, DOMString origin);
 
 dictionary RTCIdentityAssertionResult {
   required RTCIdentityProviderDetails idp;
   required DOMString assertion;
 };
 
--- a/dom/webidl/Reporting.webidl
+++ b/dom/webidl/Reporting.webidl
@@ -21,16 +21,17 @@ interface Report {
 [Constructor(ReportingObserverCallback callback, optional ReportingObserverOptions options),
  Func="mozilla::dom::DOMPrefs::dom_reporting_enabled"]
 interface ReportingObserver {
   void observe();
   void disconnect();
   ReportList takeRecords();
 };
 
+[MOZ_CAN_RUN_SCRIPT_BOUNDARY]
 callback ReportingObserverCallback = void (sequence<Report> reports, ReportingObserver observer);
 
 dictionary ReportingObserverOptions {
   sequence<DOMString> types;
   boolean buffered = false;
 };
 
 typedef sequence<Report> ReportList;
--- a/dom/webidl/U2F.webidl
+++ b/dom/webidl/U2F.webidl
@@ -59,17 +59,19 @@ dictionary SignResponse {
     DOMString signatureData;
     DOMString clientData;
 
     // From Error
     ErrorCode? errorCode;
     DOMString? errorMessage;
 };
 
+[MOZ_CAN_RUN_SCRIPT_BOUNDARY]
 callback U2FRegisterCallback = void(RegisterResponse response);
+[MOZ_CAN_RUN_SCRIPT_BOUNDARY]
 callback U2FSignCallback = void(SignResponse response);
 
 [SecureContext, Pref="security.webauth.u2f"]
 interface U2F {
   // These enumerations are defined in the FIDO U2F Javascript API under the
   // interface "ErrorCode" as constant integers, and also in the U2F.cpp file.
   // Any changes to these must occur in both locations.
   const unsigned short OK = 0;
--- a/dom/webidl/WebComponents.webidl
+++ b/dom/webidl/WebComponents.webidl
@@ -5,24 +5,29 @@
  *
  * The origin of this IDL file is
  * http://dvcs.w3.org/hg/webcomponents/raw-file/tip/spec/custom/index.html
  *
  * Copyright © 2012 W3C® (MIT, ERCIM, Keio), All Rights Reserved. W3C
  * liability, trademark and document use rules apply.
  */
 
+[MOZ_CAN_RUN_SCRIPT_BOUNDARY]
 callback LifecycleConnectedCallback = void();
+[MOZ_CAN_RUN_SCRIPT_BOUNDARY]
 callback LifecycleDisconnectedCallback = void();
+[MOZ_CAN_RUN_SCRIPT_BOUNDARY]
 callback LifecycleAdoptedCallback = void(Document? oldDocument,
                                          Document? newDocment);
+[MOZ_CAN_RUN_SCRIPT_BOUNDARY]
 callback LifecycleAttributeChangedCallback = void(DOMString attrName,
                                                   DOMString? oldValue,
                                                   DOMString? newValue,
                                                   DOMString? namespaceURI);
+[MOZ_CAN_RUN_SCRIPT_BOUNDARY]
 callback LifecycleGetCustomInterfaceCallback = object?(any iid);
 
 dictionary LifecycleCallbacks {
   LifecycleConnectedCallback connectedCallback;
   LifecycleDisconnectedCallback disconnectedCallback;
   LifecycleAdoptedCallback adoptedCallback;
   LifecycleAttributeChangedCallback attributeChangedCallback;
   [ChromeOnly] LifecycleGetCustomInterfaceCallback getCustomInterfaceCallback;
--- a/dom/webidl/WebrtcGlobalInformation.webidl
+++ b/dom/webidl/WebrtcGlobalInformation.webidl
@@ -3,17 +3,19 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/.
  */
 
 dictionary WebrtcGlobalStatisticsReport {
   sequence<RTCStatsReportInternal> reports;
 };
 
+[MOZ_CAN_RUN_SCRIPT_BOUNDARY]
 callback WebrtcGlobalStatisticsCallback = void (WebrtcGlobalStatisticsReport reports);
+[MOZ_CAN_RUN_SCRIPT_BOUNDARY]
 callback WebrtcGlobalLoggingCallback = void (sequence<DOMString> logMessages);
 
 [ChromeOnly]
 interface WebrtcGlobalInformation {
 
   [Throws]
   static void getAllStats(WebrtcGlobalStatisticsCallback callback,
                           optional DOMString pcIdFilter);
--- a/dom/webidl/Window.webidl
+++ b/dom/webidl/Window.webidl
@@ -206,16 +206,17 @@ partial interface Window {
   [Throws, NeedsCallerType] attribute any outerHeight;
 };
 
 // https://dvcs.w3.org/hg/webperf/raw-file/tip/specs/RequestAnimationFrame/Overview.html
 partial interface Window {
   [Throws] long requestAnimationFrame(FrameRequestCallback callback);
   [Throws] void cancelAnimationFrame(long handle);
 };
+[MOZ_CAN_RUN_SCRIPT_BOUNDARY]
 callback FrameRequestCallback = void (DOMHighResTimeStamp time);
 
 // https://dvcs.w3.org/hg/webperf/raw-file/tip/specs/NavigationTiming/Overview.html
 partial interface Window {
   [Replaceable, Pure, StoreInSlot] readonly attribute Performance? performance;
 };
 
 // https://dvcs.w3.org/hg/webcrypto-api/raw-file/tip/spec/Overview.html
@@ -391,16 +392,17 @@ partial interface Window {
 #ifdef HAVE_SIDEBAR
 // Mozilla extension
 partial interface Window {
   [Replaceable, Throws, UseCounter, Pref="dom.sidebar.enabled"]
   readonly attribute (External or WindowProxy) sidebar;
 };
 #endif
 
+[MOZ_CAN_RUN_SCRIPT_BOUNDARY]
 callback PromiseDocumentFlushedCallback = any ();
 
 // Mozilla extensions for Chrome windows.
 partial interface Window {
   // The STATE_* constants need to match the corresponding enum in nsGlobalWindow.cpp.
   [Func="nsGlobalWindowInner::IsPrivilegedChromeWindow"]
   const unsigned short STATE_MAXIMIZED = 1;
   [Func="nsGlobalWindowInner::IsPrivilegedChromeWindow"]
@@ -550,16 +552,17 @@ partial interface Window {
   [Func="nsGlobalWindowInner::IsRequestIdleCallbackEnabled"]
   void          cancelIdleCallback(unsigned long handle);
 };
 
 dictionary IdleRequestOptions {
   unsigned long timeout;
 };
 
+[MOZ_CAN_RUN_SCRIPT_BOUNDARY]
 callback IdleRequestCallback = void (IdleDeadline deadline);
 
 partial interface Window {
   /**
    * Returns a list of locales that the internationalization components
    * should be localized to.
    *
    * The function name refers to Regional Preferences which can be either