зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1747059 - Gecko support for ShadowRealms r=peterv,smaug
This connects [Exposed=*] in WebIDL to ShadowRealms Differential Revision: https://phabricator.services.mozilla.com/D146349
This commit is contained in:
Родитель
d390a7f144
Коммит
580a35d01e
|
@ -2809,7 +2809,8 @@ bool IsNonExposedGlobal(JSContext* aCx, JSObject* aGlobal,
|
|||
GlobalNames::WorkerDebuggerGlobalScope |
|
||||
GlobalNames::WorkletGlobalScope |
|
||||
GlobalNames::AudioWorkletGlobalScope |
|
||||
GlobalNames::PaintWorkletGlobalScope)) == 0,
|
||||
GlobalNames::PaintWorkletGlobalScope |
|
||||
GlobalNames::ShadowRealmGlobalScope)) == 0,
|
||||
"Unknown non-exposed global type");
|
||||
|
||||
const char* name = JS::GetClass(aGlobal)->name;
|
||||
|
@ -2854,6 +2855,11 @@ bool IsNonExposedGlobal(JSContext* aCx, JSObject* aGlobal,
|
|||
return true;
|
||||
}
|
||||
|
||||
if ((aNonExposedGlobals & GlobalNames::ShadowRealmGlobalScope) &&
|
||||
!strcmp(name, "ShadowRealmGlobalScope")) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
|
@ -17754,6 +17754,38 @@ class CGRegisterWorkletBindings(CGAbstractMethod):
|
|||
return CGList(lines, "\n").define()
|
||||
|
||||
|
||||
class CGRegisterShadowRealmBindings(CGAbstractMethod):
|
||||
def __init__(self, config):
|
||||
CGAbstractMethod.__init__(
|
||||
self,
|
||||
None,
|
||||
"RegisterShadowRealmBindings",
|
||||
"bool",
|
||||
[Argument("JSContext*", "aCx"), Argument("JS::Handle<JSObject*>", "aObj")],
|
||||
)
|
||||
self.config = config
|
||||
|
||||
def definition_body(self):
|
||||
descriptors = self.config.getDescriptors(
|
||||
hasInterfaceObject=True, isExposedInShadowRealms=True, register=True
|
||||
)
|
||||
conditions = []
|
||||
for desc in descriptors:
|
||||
bindingNS = toBindingNamespace(desc.name)
|
||||
condition = "!%s::GetConstructorObject(aCx)" % 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()
|
||||
|
||||
|
||||
def BindingNamesOffsetEnum(name):
|
||||
return CppKeywords.checkMethodName(name.replace(" ", "_"))
|
||||
|
||||
|
@ -23086,6 +23118,33 @@ class GlobalGenRoots:
|
|||
# Done.
|
||||
return curr
|
||||
|
||||
@staticmethod
|
||||
def RegisterShadowRealmBindings(config):
|
||||
|
||||
curr = CGRegisterShadowRealmBindings(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, isExposedInShadowRealms=True
|
||||
)
|
||||
]
|
||||
|
||||
curr = CGHeaders(
|
||||
[], [], [], [], [], defineIncludes, "RegisterShadowRealmBindings", curr
|
||||
)
|
||||
|
||||
# Add include guards.
|
||||
curr = CGIncludeGuard("RegisterShadowRealmBindings", curr)
|
||||
|
||||
# Done.
|
||||
return curr
|
||||
|
||||
@staticmethod
|
||||
def UnionTypes(config):
|
||||
unionTypes = UnionsForFile(config, None)
|
||||
|
|
|
@ -296,6 +296,8 @@ class Configuration(DescriptorProvider):
|
|||
getter = lambda x: x.interface.isExposedInAnyWorklet()
|
||||
elif key == "isExposedInWindow":
|
||||
getter = lambda x: x.interface.isExposedInWindow()
|
||||
elif key == "isExposedInShadowRealms":
|
||||
getter = lambda x: x.interface.isExposedInShadowRealms()
|
||||
elif key == "isSerializable":
|
||||
getter = lambda x: x.interface.isSerializable()
|
||||
else:
|
||||
|
|
|
@ -112,8 +112,9 @@ static const uint32_t WorkerDebuggerGlobalScope = 1u << 4;
|
|||
static const uint32_t WorkletGlobalScope = 1u << 5;
|
||||
static const uint32_t AudioWorkletGlobalScope = 1u << 6;
|
||||
static const uint32_t PaintWorkletGlobalScope = 1u << 7;
|
||||
static const uint32_t ShadowRealmGlobalScope = 1u << 8;
|
||||
|
||||
static constexpr uint32_t kCount = 8;
|
||||
static constexpr uint32_t kCount = 9;
|
||||
} // namespace GlobalNames
|
||||
|
||||
struct PrefableDisablers {
|
||||
|
|
|
@ -156,6 +156,7 @@ class WebIDLCodegenManager(LoggingMixin):
|
|||
"GeneratedEventList.h",
|
||||
"PrototypeList.h",
|
||||
"RegisterBindings.h",
|
||||
"RegisterShadowRealmBindings.h",
|
||||
"RegisterWorkerBindings.h",
|
||||
"RegisterWorkerDebuggerBindings.h",
|
||||
"RegisterWorkletBindings.h",
|
||||
|
@ -169,6 +170,7 @@ class WebIDLCodegenManager(LoggingMixin):
|
|||
GLOBAL_DEFINE_FILES = {
|
||||
"BindingNames.cpp",
|
||||
"RegisterBindings.cpp",
|
||||
"RegisterShadowRealmBindings.cpp",
|
||||
"RegisterWorkerBindings.cpp",
|
||||
"RegisterWorkerDebuggerBindings.cpp",
|
||||
"RegisterWorkletBindings.cpp",
|
||||
|
|
|
@ -492,7 +492,7 @@ class IDLExposureMixins:
|
|||
# and add global interfaces and [Exposed] annotations to all those
|
||||
# tests.
|
||||
if len(scope.globalNames) != 0:
|
||||
if len(self._exposureGlobalNames) == 0:
|
||||
if len(self._exposureGlobalNames) == 0 and not self.isPseudoInterface():
|
||||
raise WebIDLError(
|
||||
(
|
||||
"'%s' is not exposed anywhere even though we have "
|
||||
|
@ -528,6 +528,9 @@ class IDLExposureMixins:
|
|||
workerScopes = self.parentScope.globalNameMapping["Worker"]
|
||||
return len(workerScopes.difference(self.exposureSet)) > 0
|
||||
|
||||
def isExposedInShadowRealms(self):
|
||||
return "ShadowRealmGlobalScope" in self.exposureSet
|
||||
|
||||
def getWorkerExposureSet(self):
|
||||
workerScopes = self._globalScope.globalNameMapping["Worker"]
|
||||
return workerScopes.intersection(self.exposureSet)
|
||||
|
@ -959,6 +962,9 @@ class IDLInterfaceOrNamespace(IDLInterfaceOrInterfaceMixinOrNamespace):
|
|||
self.interfacesBasedOnSelf = set([self])
|
||||
self._hasChildInterfaces = False
|
||||
self._isOnGlobalProtoChain = False
|
||||
# Pseudo interfaces aren't exposed anywhere, and so shouldn't issue warnings
|
||||
self._isPseudo = False
|
||||
|
||||
# Tracking of the number of reserved slots we need for our
|
||||
# members and those of ancestor interfaces.
|
||||
self.totalMembersInSlots = 0
|
||||
|
@ -1713,13 +1719,14 @@ class IDLInterfaceOrNamespace(IDLInterfaceOrInterfaceMixinOrNamespace):
|
|||
def hasInterfaceObject(self):
|
||||
if self.isCallback():
|
||||
return self.hasConstants()
|
||||
return not hasattr(self, "_noInterfaceObject")
|
||||
return not hasattr(self, "_noInterfaceObject") and not self.isPseudoInterface()
|
||||
|
||||
def hasInterfacePrototypeObject(self):
|
||||
return (
|
||||
not self.isCallback()
|
||||
and not self.isNamespace()
|
||||
and self.getUserData("hasConcreteDescendant", False)
|
||||
and not self.isPseudoInterface()
|
||||
)
|
||||
|
||||
def addIncludedMixin(self, includedMixin):
|
||||
|
@ -1783,6 +1790,9 @@ class IDLInterfaceOrNamespace(IDLInterfaceOrInterfaceMixinOrNamespace):
|
|||
def isOnGlobalProtoChain(self):
|
||||
return self._isOnGlobalProtoChain
|
||||
|
||||
def isPseudoInterface(self):
|
||||
return self._isPseudo
|
||||
|
||||
def _getDependentObjects(self):
|
||||
deps = set(self.members)
|
||||
deps.update(self.includedMixins)
|
||||
|
|
|
@ -0,0 +1,122 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
/* 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/. */
|
||||
|
||||
#include "nsGlobalWindowInner.h"
|
||||
#include "nsIGlobalObject.h"
|
||||
#include "xpcpublic.h"
|
||||
#include "js/TypeDecls.h"
|
||||
|
||||
#include "mozilla/dom/Document.h"
|
||||
#include "mozilla/dom/BindingDeclarations.h"
|
||||
#include "mozilla/dom/ModuleLoader.h"
|
||||
#include "mozilla/dom/ShadowRealmGlobalScope.h"
|
||||
#include "mozilla/dom/ShadowRealmGlobalScopeBinding.h"
|
||||
|
||||
#include "js/loader/ModuleLoaderBase.h"
|
||||
|
||||
using namespace JS::loader;
|
||||
|
||||
namespace mozilla::dom {
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(ShadowRealmGlobalScope, mModuleLoader,
|
||||
mCreatingGlobal)
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTING_ADDREF(ShadowRealmGlobalScope)
|
||||
NS_IMPL_CYCLE_COLLECTING_RELEASE(ShadowRealmGlobalScope)
|
||||
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(ShadowRealmGlobalScope)
|
||||
NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
|
||||
NS_INTERFACE_MAP_ENTRY(nsISupports)
|
||||
NS_INTERFACE_MAP_ENTRY(nsIGlobalObject)
|
||||
NS_INTERFACE_MAP_ENTRY(ShadowRealmGlobalScope)
|
||||
NS_INTERFACE_MAP_END
|
||||
|
||||
JSObject* NewShadowRealmGlobal(JSContext* aCx, JS::RealmOptions& aOptions,
|
||||
JSPrincipals* aPrincipals,
|
||||
JS::Handle<JSObject*> aGlobalObj) {
|
||||
JS::Rooted<JSObject*> reflector(aCx);
|
||||
{
|
||||
RefPtr<ShadowRealmGlobalScope> scope;
|
||||
GlobalObject global(aCx, aGlobalObj);
|
||||
|
||||
nsCOMPtr<nsIGlobalObject> nsGlobal =
|
||||
do_QueryInterface(global.GetAsSupports());
|
||||
|
||||
MOZ_ASSERT(nsGlobal);
|
||||
|
||||
scope = new ShadowRealmGlobalScope(nsGlobal);
|
||||
ShadowRealmGlobalScope_Binding::Wrap(aCx, scope, scope, aOptions,
|
||||
aPrincipals, true, &reflector);
|
||||
}
|
||||
|
||||
return reflector;
|
||||
}
|
||||
|
||||
static nsIGlobalObject* FindEnclosingNonShadowRealmGlobal(
|
||||
ShadowRealmGlobalScope* scope) {
|
||||
nsCOMPtr<nsIGlobalObject> global = scope->GetCreatingGlobal();
|
||||
|
||||
do {
|
||||
nsCOMPtr<ShadowRealmGlobalScope> shadowRealmGlobalScope =
|
||||
do_QueryInterface(global);
|
||||
if (!shadowRealmGlobalScope) {
|
||||
break;
|
||||
}
|
||||
|
||||
// Our global was a ShadowRealmGlobal; that's a problem, as we can't find a
|
||||
// window or worker global associated with a ShadowRealmGlobal... so we
|
||||
// continue following the chain.
|
||||
//
|
||||
// This will happen if you have nested ShadowRealms.
|
||||
global = shadowRealmGlobalScope->GetCreatingGlobal();
|
||||
} while (true);
|
||||
|
||||
return global;
|
||||
}
|
||||
|
||||
ModuleLoaderBase* ShadowRealmGlobalScope::GetModuleLoader(JSContext* aCx) {
|
||||
if (mModuleLoader) {
|
||||
return mModuleLoader;
|
||||
}
|
||||
|
||||
// Note: if this fails, we don't need to report an exception, as one will be
|
||||
// reported by ModuleLoaderBase::GetCurrentModuleLoader.
|
||||
|
||||
// Don't bother asking the ShadowRealmGlobal itself for a host object to get a
|
||||
// module loader from, instead, delegate to the enclosing global of the shadow
|
||||
// realm
|
||||
nsCOMPtr<nsIGlobalObject> global = FindEnclosingNonShadowRealmGlobal(this);
|
||||
MOZ_RELEASE_ASSERT(global);
|
||||
|
||||
JSObject* object = global->GetGlobalJSObject();
|
||||
MOZ_ASSERT(object);
|
||||
|
||||
// Currently Workers will never get here, because dynamic import is disabled
|
||||
// in Worker context, and so importValue will throw before we get here.
|
||||
//
|
||||
// See https://bugzilla.mozilla.org/show_bug.cgi?id=1247687 and
|
||||
// https://bugzilla.mozilla.org/show_bug.cgi?id=1772162
|
||||
nsGlobalWindowInner* window = xpc::WindowGlobalOrNull(object);
|
||||
if (!window) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
RefPtr<Document> doc = window->GetExtantDoc();
|
||||
if (!doc) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
ScriptLoader* scriptLoader = doc->ScriptLoader();
|
||||
|
||||
mModuleLoader = new ModuleLoader(scriptLoader, this, ModuleLoader::Normal);
|
||||
|
||||
// Register the shadow realm module loader for tracing and ownership.
|
||||
scriptLoader->RegisterShadowRealmModuleLoader(
|
||||
static_cast<ModuleLoader*>(mModuleLoader.get()));
|
||||
|
||||
return mModuleLoader;
|
||||
}
|
||||
|
||||
} // namespace mozilla::dom
|
|
@ -0,0 +1,75 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
/* 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/. */
|
||||
|
||||
#ifndef mozilla_dom_ShadowRealmGlobalScope_h
|
||||
#define mozilla_dom_ShadowRealmGlobalScope_h
|
||||
|
||||
#include "js/TypeDecls.h"
|
||||
#include "mozilla/Attributes.h"
|
||||
#include "mozilla/Maybe.h"
|
||||
#include "mozilla/OriginTrials.h"
|
||||
#include "mozilla/dom/BindingDeclarations.h"
|
||||
#include "nsIGlobalObject.h"
|
||||
#include "nsWrapperCache.h"
|
||||
|
||||
#include "js/loader/ModuleLoaderBase.h"
|
||||
|
||||
namespace mozilla::dom {
|
||||
|
||||
#define SHADOWREALMGLOBALSCOPE_IID \
|
||||
{ /* 1b0a59dd-c1cb-429a-bb90-cea17994dba2 */ \
|
||||
0x1b0a59dd, 0xc1cb, 0x429a, { \
|
||||
0xbb, 0x90, 0xce, 0xa1, 0x79, 0x94, 0xdb, 0xa2 \
|
||||
} \
|
||||
}
|
||||
|
||||
// Required for providing the wrapper, as this is the global used inside a Gecko
|
||||
// backed ShadowRealm, but also required to power module resolution.
|
||||
class ShadowRealmGlobalScope : public nsIGlobalObject, public nsWrapperCache {
|
||||
public:
|
||||
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
|
||||
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(ShadowRealmGlobalScope)
|
||||
|
||||
NS_DECLARE_STATIC_IID_ACCESSOR(SHADOWREALMGLOBALSCOPE_IID)
|
||||
|
||||
explicit ShadowRealmGlobalScope(nsIGlobalObject* aCreatingGlobal)
|
||||
: mCreatingGlobal(aCreatingGlobal){};
|
||||
|
||||
nsIGlobalObject* GetCreatingGlobal() const { return mCreatingGlobal; }
|
||||
OriginTrials Trials() const override { return {}; }
|
||||
|
||||
JSObject* GetGlobalJSObject() override { return GetWrapper(); }
|
||||
JSObject* GetGlobalJSObjectPreserveColor() const override {
|
||||
return GetWrapperPreserveColor();
|
||||
}
|
||||
|
||||
virtual JSObject* WrapObject(JSContext* aCx,
|
||||
JS::Handle<JSObject*> aGivenProto) override {
|
||||
MOZ_CRASH("Shouldn't be here");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
JS::loader::ModuleLoaderBase* GetModuleLoader(JSContext* aCx) override;
|
||||
|
||||
private:
|
||||
virtual ~ShadowRealmGlobalScope() = default;
|
||||
|
||||
RefPtr<JS::loader::ModuleLoaderBase> mModuleLoader;
|
||||
|
||||
// The global which created this ShadowRealm
|
||||
nsCOMPtr<nsIGlobalObject> mCreatingGlobal;
|
||||
};
|
||||
|
||||
NS_DEFINE_STATIC_IID_ACCESSOR(ShadowRealmGlobalScope,
|
||||
SHADOWREALMGLOBALSCOPE_IID)
|
||||
|
||||
JSObject* NewShadowRealmGlobal(JSContext* aCx, JS::RealmOptions& aOptions,
|
||||
JSPrincipals* aPrincipals,
|
||||
JS::Handle<JSObject*> aGlobalObj);
|
||||
|
||||
} // namespace mozilla::dom
|
||||
|
||||
#endif
|
|
@ -27,6 +27,7 @@ EXPORTS.mozilla.dom += [
|
|||
"ScriptLoader.h",
|
||||
"ScriptSettings.h",
|
||||
"ScriptTrace.h",
|
||||
"ShadowRealmGlobalScope.h",
|
||||
]
|
||||
|
||||
UNIFIED_SOURCES += [
|
||||
|
@ -39,6 +40,7 @@ UNIFIED_SOURCES += [
|
|||
"ScriptLoader.cpp",
|
||||
"ScriptLoadHandler.cpp",
|
||||
"ScriptSettings.cpp",
|
||||
"ShadowRealmGlobalScope.cpp",
|
||||
]
|
||||
|
||||
LOCAL_INCLUDES += [
|
||||
|
|
|
@ -0,0 +1,11 @@
|
|||
/* -*- 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/.
|
||||
*/
|
||||
|
||||
// This interface exists purely to register a new global as part of
|
||||
// code generation so that we can properly hook this into
|
||||
// shadow realms.
|
||||
[Global=(ShadowRealmGlobal), Exposed=ShadowRealmGlobal]
|
||||
interface ShadowRealmGlobalScope { };
|
|
@ -812,6 +812,7 @@ WEBIDL_FILES = [
|
|||
"ServiceWorkerContainer.webidl",
|
||||
"ServiceWorkerGlobalScope.webidl",
|
||||
"ServiceWorkerRegistration.webidl",
|
||||
"ShadowRealmGlobalScope.webidl",
|
||||
"ShadowRoot.webidl",
|
||||
"SharedWorker.webidl",
|
||||
"SharedWorkerGlobalScope.webidl",
|
||||
|
|
|
@ -777,6 +777,7 @@ static mozilla::Atomic<bool> sWeakRefsEnabled(false);
|
|||
static mozilla::Atomic<bool> sWeakRefsExposeCleanupSome(false);
|
||||
static mozilla::Atomic<bool> sIteratorHelpersEnabled(false);
|
||||
static mozilla::Atomic<bool> sArrayFindLastEnabled(false);
|
||||
static mozilla::Atomic<bool> sShadowRealmsEnabled(false);
|
||||
#ifdef NIGHTLY_BUILD
|
||||
static mozilla::Atomic<bool> sArrayGroupingEnabled(true);
|
||||
#endif
|
||||
|
@ -802,6 +803,7 @@ void xpc::SetPrefableRealmOptions(JS::RealmOptions& options) {
|
|||
.setPropertyErrorMessageFixEnabled(sPropertyErrorMessageFixEnabled)
|
||||
.setWeakRefsEnabled(GetWeakRefsEnabled())
|
||||
.setIteratorHelpersEnabled(sIteratorHelpersEnabled)
|
||||
.setShadowRealmsEnabled(sShadowRealmsEnabled)
|
||||
#ifdef NIGHTLY_BUILD
|
||||
.setArrayGroupingEnabled(sArrayGroupingEnabled)
|
||||
#endif
|
||||
|
@ -1006,6 +1008,8 @@ static void ReloadPrefsCallback(const char* pref, void* aXpccx) {
|
|||
sArrayFindLastEnabled =
|
||||
Preferences::GetBool(JS_OPTIONS_DOT_STR "experimental.array_find_last");
|
||||
|
||||
sShadowRealmsEnabled =
|
||||
Preferences::GetBool(JS_OPTIONS_DOT_STR "experimental.shadow_realms");
|
||||
#ifdef NIGHTLY_BUILD
|
||||
sIteratorHelpersEnabled =
|
||||
Preferences::GetBool(JS_OPTIONS_DOT_STR "experimental.iterator_helpers");
|
||||
|
|
|
@ -40,13 +40,15 @@ support-files =
|
|||
private_field_worker.js
|
||||
class_static_worker.js
|
||||
bug1681664_helper.js
|
||||
shadow_realm_worker.js
|
||||
shadow_realm_module.js
|
||||
prefs =
|
||||
javascript.options.weakrefs=true
|
||||
javascript.options.experimental.ergonomic_brand_checks=true
|
||||
javascript.options.experimental.top_level_await=true
|
||||
javascript.options.experimental.enable_change_array_by_copy=false
|
||||
javascript.options.experimental.enable_new_set_methods=false
|
||||
|
||||
javascript.options.experimental.shadow_realms=true
|
||||
[test_bug384632.html]
|
||||
[test_bug390488.html]
|
||||
[test_bug393269.html]
|
||||
|
@ -130,3 +132,6 @@ skip-if = (debug == false)
|
|||
[test_private_field_worker.html]
|
||||
[test_class_static_block_worker.html]
|
||||
skip-if = !nightly_build
|
||||
[test_shadowRealm.html]
|
||||
[test_shadowRealm_worker.html]
|
||||
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
export var x = 1;
|
|
@ -0,0 +1,71 @@
|
|||
|
||||
var sr = new ShadowRealm();
|
||||
|
||||
self.onmessage = async function (e) {
|
||||
try {
|
||||
// Test evaluate
|
||||
if (e.data === 'evaluate') {
|
||||
sr.evaluate("var s = 'PASS set string in realm';")
|
||||
var res = sr.evaluate('s');
|
||||
postMessage(res);
|
||||
return;
|
||||
}
|
||||
|
||||
// If Import works in a worker, then it ought to work in a shadow realm
|
||||
//
|
||||
// See https://bugzilla.mozilla.org/show_bug.cgi?id=1247687 and
|
||||
// https://bugzilla.mozilla.org/show_bug.cgi?id=1772162
|
||||
if (e.data == 'import') {
|
||||
var import_worked = false;
|
||||
var importValue_worked = false;
|
||||
var importNested_worked = false;
|
||||
try {
|
||||
var module = await import("./shadow_realm_module.js");
|
||||
if (module.x != 1) {
|
||||
throw "mismatch";
|
||||
}
|
||||
import_worked = true;
|
||||
} catch (e) { }
|
||||
|
||||
try {
|
||||
await sr.importValue("./shadow_realm_module.js", 'x').then((x) => {
|
||||
if (x == 1) { importValue_worked = true; }
|
||||
});
|
||||
} catch (e) { }
|
||||
|
||||
try {
|
||||
sr.evaluate(`
|
||||
var imported = false;
|
||||
import("./shadow_realm_module.js").then((module) => {
|
||||
if (module.x == 1) {
|
||||
imported = true;
|
||||
}
|
||||
});
|
||||
true;
|
||||
`);
|
||||
|
||||
importNested_worked = sr.evaluate("imported");
|
||||
} catch (e) {
|
||||
|
||||
}
|
||||
|
||||
if (importValue_worked == import_worked && importValue_worked == importNested_worked) {
|
||||
postMessage(`PASS: importValue, import, and nested import all ${importValue_worked ? "worked" : "failed"} `);
|
||||
return;
|
||||
}
|
||||
|
||||
postMessage(`FAIL: importValue ${importValue_worked}, import ${import_worked}, importNested ${importNested_worked}`);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
// Reply back with finish
|
||||
if (e.data == 'finish') {
|
||||
postMessage("finish");
|
||||
return;
|
||||
}
|
||||
} catch (e) {
|
||||
postMessage("FAIL: " + e.message);
|
||||
}
|
||||
postMessage('Unknown message type.');
|
||||
}
|
|
@ -0,0 +1,34 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Test for ShadowRealms</title>
|
||||
<script src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
|
||||
<iframe id="ifr"></iframe>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<p id="display"></p>
|
||||
<script type="application/javascript">
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
info("running")
|
||||
|
||||
let realm = new ShadowRealm();
|
||||
|
||||
let install = (fun, internal_name) => {
|
||||
let installer = realm.evaluate(`var ${internal_name}; (x) => { ${internal_name} = x}`);
|
||||
installer(fun);
|
||||
}
|
||||
|
||||
install(info, "log");
|
||||
install(is, "is");
|
||||
realm.evaluate(`is(true, true, 'inside realm')`);
|
||||
|
||||
is(realm.evaluate("10"), 10, "ten is ten");
|
||||
|
||||
SimpleTest.finish();
|
||||
</script>
|
||||
</body>
|
||||
|
||||
</html>
|
|
@ -0,0 +1,63 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Test for ShadowRealms</title>
|
||||
<script src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
|
||||
<iframe id="ifr"></iframe>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<p id="display"></p>
|
||||
<script type="application/javascript">
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
var promise = (async ()=> {
|
||||
var module = await import("./shadow_realm_module.js");
|
||||
is(module.x, 1, "import works outside worker");
|
||||
|
||||
var sr = new ShadowRealm();
|
||||
await sr.importValue("./shadow_realm_module.js", 'x').then((x) => is(x,1, "imported x and got 1"));
|
||||
})();
|
||||
|
||||
promise.then(() => {
|
||||
var worker = new Worker("shadow_realm_worker.js");
|
||||
|
||||
var expected = 0;
|
||||
var recieved = 0;
|
||||
|
||||
function test(str) {
|
||||
worker.postMessage(str);
|
||||
expected++;
|
||||
}
|
||||
|
||||
worker.onmessage = function(e) {
|
||||
console.log("Received Message: "+e.data);
|
||||
recieved++;
|
||||
|
||||
if (e.data == "finish") {
|
||||
is(expected, recieved, "Got the appropriate Number of messages");
|
||||
SimpleTest.finish();
|
||||
return;
|
||||
}
|
||||
|
||||
if (e.data.startsWith("PASS")) {
|
||||
ok(true, e.data);
|
||||
return;
|
||||
}
|
||||
|
||||
ok(false, e.data);
|
||||
};
|
||||
|
||||
|
||||
test("evaluate");
|
||||
test("import");
|
||||
|
||||
|
||||
test("finish");
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
|
||||
</html>
|
|
@ -6771,6 +6771,14 @@
|
|||
value: false
|
||||
mirror: always
|
||||
|
||||
# ShadowRealms: https://github.com/tc39/proposal-shadowrealm
|
||||
- name: javascript.options.experimental.shadow_realms
|
||||
# Atomic, as we assert the preference, and that assertion may happen
|
||||
# in a worker.
|
||||
type: RelaxedAtomicBool
|
||||
value: false
|
||||
mirror: always
|
||||
|
||||
#ifdef NIGHTLY_BUILD
|
||||
# Experimental support for Iterator Helpers in JavaScript.
|
||||
- name: javascript.options.experimental.iterator_helpers
|
||||
|
|
|
@ -59,12 +59,14 @@
|
|||
#include <utility>
|
||||
|
||||
#include "js/Debug.h"
|
||||
#include "js/RealmOptions.h"
|
||||
#include "js/friend/DumpFunctions.h" // js::DumpHeap
|
||||
#include "js/GCAPI.h"
|
||||
#include "js/HeapAPI.h"
|
||||
#include "js/Object.h" // JS::GetClass, JS::GetCompartment, JS::GetPrivate
|
||||
#include "js/PropertyAndElement.h" // JS_DefineProperty
|
||||
#include "js/Warnings.h" // JS::SetWarningReporter
|
||||
#include "js/ShadowRealmCallbacks.h"
|
||||
#include "js/SliceBudget.h"
|
||||
#include "jsfriendapi.h"
|
||||
#include "mozilla/ArrayUtils.h"
|
||||
|
@ -75,6 +77,7 @@
|
|||
#include "mozilla/ProfilerLabels.h"
|
||||
#include "mozilla/ProfilerMarkers.h"
|
||||
#include "mozilla/Sprintf.h"
|
||||
#include "mozilla/StaticPrefs_javascript.h"
|
||||
#include "mozilla/Telemetry.h"
|
||||
#include "mozilla/TimelineConsumers.h"
|
||||
#include "mozilla/TimelineMarker.h"
|
||||
|
@ -87,6 +90,8 @@
|
|||
#include "mozilla/dom/PromiseBinding.h"
|
||||
#include "mozilla/dom/PromiseDebugging.h"
|
||||
#include "mozilla/dom/ScriptSettings.h"
|
||||
#include "mozilla/dom/ShadowRealmGlobalScope.h"
|
||||
#include "mozilla/dom/RegisterShadowRealmBindings.h"
|
||||
#include "nsContentUtils.h"
|
||||
#include "nsCycleCollectionNoteRootCallback.h"
|
||||
#include "nsCycleCollectionParticipant.h"
|
||||
|
@ -656,6 +661,14 @@ size_t JSHolderMap::SizeOfExcludingThis(MallocSizeOf aMallocSizeOf) const {
|
|||
return n;
|
||||
}
|
||||
|
||||
static bool InitializeShadowRealm(JSContext* aCx,
|
||||
JS::Handle<JSObject*> aGlobal) {
|
||||
MOZ_ASSERT(StaticPrefs::javascript_options_experimental_shadow_realms());
|
||||
|
||||
JSAutoRealm ar(aCx, aGlobal);
|
||||
return dom::RegisterShadowRealmBindings(aCx, aGlobal);
|
||||
}
|
||||
|
||||
CycleCollectedJSRuntime::CycleCollectedJSRuntime(JSContext* aCx)
|
||||
: mContext(nullptr),
|
||||
mGCThingCycleCollectorGlobal(sGCThingCycleCollectorGlobal),
|
||||
|
@ -705,6 +718,8 @@ CycleCollectedJSRuntime::CycleCollectedJSRuntime(JSContext* aCx)
|
|||
JS::SetWaitCallback(mJSRuntime, BeforeWaitCallback, AfterWaitCallback,
|
||||
sizeof(dom::AutoYieldJSThreadExecution));
|
||||
JS::SetWarningReporter(aCx, MozCrashWarningReporter);
|
||||
JS::SetShadowRealmInitializeGlobalCallback(aCx, InitializeShadowRealm);
|
||||
JS::SetShadowRealmGlobalCreationCallback(aCx, dom::NewShadowRealmGlobal);
|
||||
|
||||
js::AutoEnterOOMUnsafeRegion::setAnnotateOOMAllocationSizeCallback(
|
||||
CrashReporter::AnnotateOOMAllocationSize);
|
||||
|
|
Загрузка…
Ссылка в новой задаче