Bug 1874684 - Part 21: Rename SecondsAndNanoseconds::toTotalNanoseconds. r=dminor
[gecko.git] / js / src / builtin / ShadowRealm.cpp
blob0f4efcde148ec5a7ebc1a8753c1b258adda2ffda
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
2 * vim: set ts=8 sts=2 et sw=2 tw=80:
3 * This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 #include "builtin/ShadowRealm.h"
9 #include "mozilla/Assertions.h"
11 #include "jsapi.h"
12 #include "jsfriendapi.h"
13 #include "builtin/ModuleObject.h"
14 #include "builtin/Promise.h"
15 #include "builtin/WrappedFunctionObject.h"
16 #include "frontend/BytecodeCompiler.h" // CompileEvalScript
17 #include "js/ErrorReport.h"
18 #include "js/Exception.h"
19 #include "js/GlobalObject.h"
20 #include "js/Principals.h"
21 #include "js/Promise.h"
22 #include "js/PropertyAndElement.h"
23 #include "js/PropertyDescriptor.h"
24 #include "js/ShadowRealmCallbacks.h"
25 #include "js/SourceText.h"
26 #include "js/StableStringChars.h"
27 #include "js/StructuredClone.h"
28 #include "js/TypeDecls.h"
29 #include "js/Wrapper.h"
30 #include "vm/GlobalObject.h"
31 #include "vm/Interpreter.h"
32 #include "vm/JSObject.h"
33 #include "vm/ObjectOperations.h"
35 #include "builtin/HandlerFunction-inl.h"
36 #include "vm/Compartment-inl.h"
37 #include "vm/JSObject-inl.h"
38 #include "vm/Realm-inl.h"
40 using namespace js;
42 using JS::AutoStableStringChars;
43 using JS::CompileOptions;
44 using JS::SourceOwnership;
45 using JS::SourceText;
47 static JSObject* DefaultNewShadowRealmGlobal(JSContext* cx,
48 JS::RealmOptions& options,
49 JSPrincipals* principals,
50 Handle<JSObject*> unused) {
51 static const JSClass shadowRealmGlobal = {
52 "ShadowRealmGlobal", JSCLASS_GLOBAL_FLAGS, &JS::DefaultGlobalClassOps};
54 return JS_NewGlobalObject(cx, &shadowRealmGlobal, principals,
55 JS::FireOnNewGlobalHook, options);
58 // https://tc39.es/proposal-shadowrealm/#sec-shadowrealm-constructor
59 /*static*/
60 bool ShadowRealmObject::construct(JSContext* cx, unsigned argc, Value* vp) {
61 CallArgs args = CallArgsFromVp(argc, vp);
63 // Step 1. If NewTarget is undefined, throw a TypeError exception.
64 if (!args.isConstructing()) {
65 JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
66 JSMSG_NOT_CONSTRUCTOR, "ShadowRealm");
67 return false;
70 // Step 2. Let O be ? OrdinaryCreateFromConstructor(NewTarget,
71 // "%ShadowRealm.prototype%", « [[ShadowRealm]], [[ExecutionContext]] »).
72 Rooted<JSObject*> proto(cx);
73 if (!GetPrototypeFromBuiltinConstructor(cx, args, JSProto_ShadowRealm,
74 &proto)) {
75 return false;
78 Rooted<ShadowRealmObject*> shadowRealmObj(
79 cx, NewObjectWithClassProto<ShadowRealmObject>(cx, proto));
80 if (!shadowRealmObj) {
81 return false;
84 // Instead of managing Realms, spidermonkey associates a realm with a global
85 // object, and so we will manage and store a global.
87 // Step 3. Let realmRec be CreateRealm().
89 // Initially steal creation options from current realm:
90 JS::RealmOptions options(cx->realm()->creationOptions(),
91 cx->realm()->behaviors());
93 // We don't want to have to deal with CCWs in addition to
94 // WrappedFunctionObjects.
95 options.creationOptions().setExistingCompartment(cx->compartment());
97 JS::GlobalCreationCallback newGlobal =
98 cx->runtime()->getShadowRealmGlobalCreationCallback();
99 // If an embedding didn't provide a callback to initialize the global,
100 // use the basic default one.
101 if (!newGlobal) {
102 newGlobal = DefaultNewShadowRealmGlobal;
105 // Our shadow realm inherits the principals of the current realm,
106 // but is otherwise constrained.
107 JSPrincipals* principals = JS::GetRealmPrincipals(cx->realm());
109 // Steps 5-11: In SpiderMonkey these fall under the aegis of the global
110 // creation. It's worth noting that the newGlobal callback
111 // needs to respect the SetRealmGlobalObject call below, which
112 // sets the global to
113 // OrdinaryObjectCreate(intrinsics.[[%Object.prototype%]]).
115 // Step 5. Let context be a new execution context.
116 // Step 6. Set the Function of context to null.
117 // Step 7. Set the Realm of context to realmRec.
118 // Step 8. Set the ScriptOrModule of context to null.
119 // Step 9. Set O.[[ExecutionContext]] to context.
120 // Step 10. Perform ? SetRealmGlobalObject(realmRec, undefined, undefined).
121 // Step 11. Perform ? SetDefaultGlobalBindings(O.[[ShadowRealm]]).
122 Rooted<JSObject*> global(cx,
123 newGlobal(cx, options, principals, cx->global()));
124 if (!global) {
125 return false;
128 // Make sure the new global hook obeyed our request in the
129 // creation options to have a same compartment global.
130 MOZ_RELEASE_ASSERT(global->compartment() == cx->compartment());
132 // Step 4. Set O.[[ShadowRealm]] to realmRec.
133 shadowRealmObj->initFixedSlot(GlobalSlot, ObjectValue(*global));
135 // Step 12. Perform ? HostInitializeShadowRealm(O.[[ShadowRealm]]).
136 JS::GlobalInitializeCallback hostInitializeShadowRealm =
137 cx->runtime()->getShadowRealmInitializeGlobalCallback();
138 if (hostInitializeShadowRealm) {
139 if (!hostInitializeShadowRealm(cx, global)) {
140 return false;
144 // Step 13. Return O.
145 args.rval().setObject(*shadowRealmObj);
146 return true;
149 // https://tc39.es/proposal-shadowrealm/#sec-validateshadowrealmobject
150 // (slightly modified into a cast operator too)
151 static ShadowRealmObject* ValidateShadowRealmObject(JSContext* cx,
152 Handle<Value> value) {
153 // Step 1. Perform ? RequireInternalSlot(O, [[ShadowRealm]]).
154 // Step 2. Perform ? RequireInternalSlot(O, [[ExecutionContext]]).
155 return UnwrapAndTypeCheckValue<ShadowRealmObject>(cx, value, [cx]() {
156 JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
157 JSMSG_NOT_SHADOW_REALM);
161 void js::ReportPotentiallyDetailedMessage(JSContext* cx,
162 const unsigned detailedError,
163 const unsigned genericError) {
164 // Return for non-catchable exceptions like interrupt requests.
165 if (!cx->isExceptionPending()) {
166 return;
169 Rooted<Value> exception(cx);
170 if (!cx->getPendingException(&exception)) {
171 return;
173 cx->clearPendingException();
175 JS::ErrorReportBuilder jsReport(cx);
176 JS::ExceptionStack exnStack(cx, exception, nullptr);
177 if (!jsReport.init(cx, exnStack, JS::ErrorReportBuilder::NoSideEffects)) {
178 cx->clearPendingException();
179 JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, genericError);
180 return;
183 JS_ReportErrorNumberUTF8(cx, GetErrorMessage, nullptr, detailedError,
184 jsReport.toStringResult().c_str());
187 // PerformShadowRealmEval ( sourceText: a String, callerRealm: a Realm Record,
188 // evalRealm: a Realm Record, )
190 // https://tc39.es/proposal-shadowrealm/#sec-performshadowrealmeval
191 static bool PerformShadowRealmEval(JSContext* cx, Handle<JSString*> sourceText,
192 Realm* callerRealm, Realm* evalRealm,
193 MutableHandle<Value> rval) {
194 MOZ_ASSERT(callerRealm != evalRealm);
196 // Step 1. Perform ? HostEnsureCanCompileStrings(callerRealm, evalRealm).
197 if (!cx->isRuntimeCodeGenEnabled(JS::RuntimeCode::JS, sourceText)) {
198 JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
199 JSMSG_CSP_BLOCKED_SHADOWREALM);
200 return false;
203 // Need to compile the script into the realm we will execute into.
205 // We hoist the error handling out however to ensure that errors
206 // are thrown from the correct realm.
207 bool compileSuccess = false;
208 bool evalSuccess = false;
210 do {
211 Rooted<GlobalObject*> evalRealmGlobal(cx, evalRealm->maybeGlobal());
212 AutoRealm ar(cx, evalRealmGlobal);
214 // Step 2. Perform the following substeps in an implementation-defined
215 // order, possibly interleaving parsing and error detection:
216 // a. Let script be ParseText(! StringToCodePoints(sourceText), Script).
217 // b. If script is a List of errors, throw a SyntaxError exception.
218 // c. If script Contains ScriptBody is false, return undefined.
219 // d. Let body be the ScriptBody of script.
220 // e. If body Contains NewTarget is true, throw a SyntaxError exception.
221 // f. If body Contains SuperProperty is true, throw a SyntaxError
222 // exception. g. If body Contains SuperCall is true, throw a SyntaxError
223 // exception.
225 AutoStableStringChars linearChars(cx);
226 if (!linearChars.initTwoByte(cx, sourceText)) {
227 return false;
229 SourceText<char16_t> srcBuf;
230 if (!srcBuf.initMaybeBorrowed(cx, linearChars)) {
231 return false;
234 // Lets propagate some information into the compilation here.
236 // We may need to censor the stacks eventually, see
237 // https://bugzilla.mozilla.org/show_bug.cgi?id=1770017
238 RootedScript callerScript(cx);
239 const char* filename;
240 uint32_t lineno;
241 uint32_t pcOffset;
242 bool mutedErrors;
243 DescribeScriptedCallerForCompilation(cx, &callerScript, &filename, &lineno,
244 &pcOffset, &mutedErrors);
246 CompileOptions options(cx);
247 options.setIsRunOnce(true)
248 .setNoScriptRval(false)
249 .setMutedErrors(mutedErrors)
250 .setFileAndLine(filename, lineno);
252 Rooted<Scope*> enclosing(cx, &evalRealmGlobal->emptyGlobalScope());
253 RootedScript script(
254 cx, frontend::CompileEvalScript(cx, options, srcBuf, enclosing,
255 evalRealmGlobal));
257 compileSuccess = !!script;
258 if (!compileSuccess) {
259 break;
262 // Step 3. Let strictEval be IsStrict of script.
263 // Step 4. Let runningContext be the running execution context.
264 // Step 5. Let lexEnv be NewDeclarativeEnvironment(evalRealm.[[GlobalEnv]]).
265 // Step 6. Let varEnv be evalRealm.[[GlobalEnv]].
266 // Step 7. If strictEval is true, set varEnv to lexEnv.
267 // Step 8. If runningContext is not already suspended, suspend
268 // runningContext. Step 9. Let evalContext be a new ECMAScript code
269 // execution context. Step 10. Set evalContext's Function to null. Step 11.
270 // Set evalContext's Realm to evalRealm. Step 12. Set evalContext's
271 // ScriptOrModule to null. Step 13. Set evalContext's VariableEnvironment to
272 // varEnv. Step 14. Set evalContext's LexicalEnvironment to lexEnv. Step 15.
273 // Push evalContext onto the execution context stack; evalContext is
274 // now the running execution context.
275 // Step 16. Let result be EvalDeclarationInstantiation(body, varEnv,
276 // lexEnv, null, strictEval).
277 // Step 17. If result.[[Type]] is normal, then
278 // a. Set result to the result of evaluating body.
279 // Step 18. If result.[[Type]] is normal and result.[[Value]] is empty, then
280 // a. Set result to NormalCompletion(undefined).
282 // Step 19. Suspend evalContext and remove it from the execution context
283 // stack.
284 // Step 20. Resume the context that is now on the top of the execution
285 // context stack as the running execution context.
286 Rooted<JSObject*> environment(cx, &evalRealmGlobal->lexicalEnvironment());
287 evalSuccess = ExecuteKernel(cx, script, environment,
288 /* evalInFrame = */ NullFramePtr(), rval);
289 } while (false); // AutoRealm
291 if (!compileSuccess) {
292 if (!cx->isExceptionPending()) {
293 return false;
296 // Clone the exception into the current global and re-throw, as the
297 // exception has to come from the current global.
298 Rooted<Value> exception(cx);
299 if (!cx->getPendingException(&exception)) {
300 return false;
303 // Clear our exception now that we've got it, so that we don't
304 // do the following call with an exception already pending.
305 cx->clearPendingException();
307 Rooted<Value> clonedException(cx);
308 if (!JS_StructuredClone(cx, exception, &clonedException, nullptr,
309 nullptr)) {
310 return false;
313 cx->setPendingException(clonedException, ShouldCaptureStack::Always);
314 return false;
317 if (!evalSuccess) {
318 // Step 21. If result.[[Type]] is not normal, throw a TypeError
319 // exception.
321 // The type error here needs to come from the calling global, so has to
322 // happen outside the AutoRealm above.
323 ReportPotentiallyDetailedMessage(cx,
324 JSMSG_SHADOW_REALM_EVALUATE_FAILURE_DETAIL,
325 JSMSG_SHADOW_REALM_EVALUATE_FAILURE);
327 return false;
330 // Wrap |rval| into the current compartment.
331 if (!cx->compartment()->wrap(cx, rval)) {
332 return false;
335 // Step 22. Return ? GetWrappedValue(callerRealm, result.[[Value]]).
336 return GetWrappedValue(cx, callerRealm, rval, rval);
339 // ShadowRealm.prototype.evaluate ( sourceText )
340 // https://tc39.es/proposal-shadowrealm/#sec-shadowrealm.prototype.evaluate
341 static bool ShadowRealm_evaluate(JSContext* cx, unsigned argc, Value* vp) {
342 CallArgs args = CallArgsFromVp(argc, vp);
344 // Step 1. Let O be this value.
345 HandleValue obj = args.thisv();
347 // Step 2. Perform ? ValidateShadowRealmObject(O)
348 Rooted<ShadowRealmObject*> shadowRealm(cx,
349 ValidateShadowRealmObject(cx, obj));
350 if (!shadowRealm) {
351 return false;
354 // Step 3. If Type(sourceText) is not String, throw a TypeError exception.
355 if (!args.get(0).isString()) {
356 JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
357 JSMSG_SHADOW_REALM_EVALUATE_NOT_STRING);
358 return false;
360 Rooted<JSString*> sourceText(cx, args.get(0).toString());
362 // Step 4. Let callerRealm be the current Realm Record.
363 Realm* callerRealm = cx->realm();
365 // Step 5. Let evalRealm be O.[[ShadowRealm]].
366 Realm* evalRealm = shadowRealm->getShadowRealm();
367 // Step 6. Return ? PerformShadowRealmEval(sourceText, callerRealm,
368 // evalRealm).
369 return PerformShadowRealmEval(cx, sourceText, callerRealm, evalRealm,
370 args.rval());
373 enum class ImportValueIndices : uint32_t {
374 CalleRealm = 0,
376 ExportNameString,
378 Length,
381 // MG:XXX: Cribbed/Overlapping with StartDynamicModuleImport; may need to
382 // refactor to share.
383 // https://tc39.es/proposal-shadowrealm/#sec-shadowrealmimportvalue
384 static JSObject* ShadowRealmImportValue(JSContext* cx,
385 Handle<JSString*> specifierString,
386 Handle<JSString*> exportName,
387 Realm* callerRealm, Realm* evalRealm) {
388 // Step 1. Assert: evalContext is an execution context associated to a
389 // ShadowRealm instance's [[ExecutionContext]].
391 // Step 2. Let innerCapability be ! NewPromiseCapability(%Promise%).
392 Rooted<JSObject*> promiseConstructor(cx, JS::GetPromiseConstructor(cx));
393 if (!promiseConstructor) {
394 return nullptr;
397 Rooted<JSObject*> promiseObject(cx, JS::NewPromiseObject(cx, nullptr));
398 if (!promiseObject) {
399 return nullptr;
402 Handle<PromiseObject*> promise = promiseObject.as<PromiseObject>();
404 JS::ModuleDynamicImportHook importHook =
405 cx->runtime()->moduleDynamicImportHook;
407 if (!importHook) {
408 // Dynamic import can be disabled by a pref and is not supported in all
409 // contexts (e.g. web workers).
410 JS_ReportErrorASCII(
412 "Dynamic module import is disabled or not supported in this context");
413 if (!RejectPromiseWithPendingError(cx, promise)) {
414 return nullptr;
416 return promise;
420 // Step 3. Let runningContext be the running execution context. (Implicit)
421 // Step 4. If runningContext is not already suspended, suspend
422 // runningContext. (Implicit)
423 // Step 5. Push evalContext onto the execution context stack; evalContext is
424 // now the running execution context. (Implicit)
425 Rooted<GlobalObject*> evalRealmGlobal(cx, evalRealm->maybeGlobal());
426 AutoRealm ar(cx, evalRealmGlobal);
428 // Not Speced: Get referencing private to pass to importHook.
429 RootedScript script(cx);
430 const char* filename;
431 uint32_t lineno;
432 uint32_t pcOffset;
433 bool mutedErrors;
434 DescribeScriptedCallerForCompilation(cx, &script, &filename, &lineno,
435 &pcOffset, &mutedErrors);
437 MOZ_ASSERT(script);
439 Rooted<JSAtom*> specifierAtom(cx, AtomizeString(cx, specifierString));
440 if (!specifierAtom) {
441 if (!RejectPromiseWithPendingError(cx, promise)) {
442 return nullptr;
444 return promise;
447 Rooted<ArrayObject*> assertionArray(cx);
448 Rooted<JSObject*> moduleRequest(
449 cx, ModuleRequestObject::create(cx, specifierAtom, assertionArray));
450 if (!moduleRequest) {
451 if (!RejectPromiseWithPendingError(cx, promise)) {
452 return nullptr;
454 return promise;
457 // Step 6. Perform ! HostImportModuleDynamically(null, specifierString,
458 // innerCapability).
460 // By specification, this is supposed to take ReferencingScriptOrModule as
461 // null, see first parameter above. However, if we do that, we don't end up
462 // with a script reference, which is used to figure out what the base-URI
463 // should be So then we end up using the default one for the module loader;
464 // which because of the way we set the parent module loader up, means we end
465 // up having the incorrect base URI, as the module loader ends up just using
466 // the document's base URI.
468 // I have filed https://github.com/tc39/proposal-shadowrealm/issues/363 to
469 // discuss this.
470 Rooted<Value> referencingPrivate(cx, script->sourceObject()->getPrivate());
471 if (!importHook(cx, referencingPrivate, moduleRequest, promise)) {
472 // If there's no exception pending then the script is terminating
473 // anyway, so just return nullptr.
474 if (!cx->isExceptionPending() ||
475 !RejectPromiseWithPendingError(cx, promise)) {
476 return nullptr;
478 return promise;
481 // Step 7. Suspend evalContext and remove it from the execution context
482 // stack. (Implicit)
483 // Step 8. Resume the context that is now on the top of the execution
484 // context stack as the running execution context (Implicit)
487 // Step 9. Let steps be the steps of an ExportGetter function as described
488 // below.
489 // Step 10. Let onFulfilled be ! CreateBuiltinFunction(steps, 1, "", «
490 // [[ExportNameString]] », callerRealm).
492 // The handler can only hold onto a single object, so we pack that into a new
493 // array, and store there.
494 Rooted<ArrayObject*> handlerObject(
496 NewDenseFullyAllocatedArray(cx, uint32_t(ImportValueIndices::Length)));
497 if (!handlerObject) {
498 return nullptr;
501 handlerObject->setDenseInitializedLength(
502 uint32_t(ImportValueIndices::Length));
503 handlerObject->initDenseElement(uint32_t(ImportValueIndices::CalleRealm),
504 PrivateValue(callerRealm));
505 handlerObject->initDenseElement(
506 uint32_t(ImportValueIndices::ExportNameString), StringValue(exportName));
508 Rooted<JSFunction*> onFulfilled(
510 NewHandlerWithExtra(
512 [](JSContext* cx, unsigned argc, Value* vp) {
513 // This is the export getter function from
514 // https://tc39.es/proposal-shadowrealm/#sec-shadowrealmimportvalue
515 CallArgs args = CallArgsFromVp(argc, vp);
516 MOZ_ASSERT(args.length() == 1);
518 auto* handlerObject = ExtraFromHandler<ArrayObject>(args);
520 Rooted<Value> realmValue(
521 cx, handlerObject->getDenseElement(
522 uint32_t(ImportValueIndices::CalleRealm)));
523 Rooted<Value> exportNameValue(
524 cx, handlerObject->getDenseElement(
525 uint32_t(ImportValueIndices::ExportNameString)));
527 // Step 1. Assert: exports is a module namespace exotic object.
528 Handle<Value> exportsValue = args[0];
529 MOZ_ASSERT(exportsValue.isObject() &&
530 exportsValue.toObject().is<ModuleNamespaceObject>());
532 Rooted<ModuleNamespaceObject*> exports(
533 cx, &exportsValue.toObject().as<ModuleNamespaceObject>());
535 // Step 2. Let f be the active function object. (not implemented
536 // this way)
538 // Step 3. Let string be f.[[ExportNameString]]. Step 4.
539 // Assert: Type(string) is String.
540 MOZ_ASSERT(exportNameValue.isString());
542 Rooted<JSAtom*> stringAtom(
543 cx, AtomizeString(cx, exportNameValue.toString()));
544 if (!stringAtom) {
545 return false;
547 Rooted<jsid> stringId(cx, AtomToId(stringAtom));
549 // Step 5. Let hasOwn be ? HasOwnProperty(exports, string).
550 bool hasOwn = false;
551 if (!HasOwnProperty(cx, exports, stringId, &hasOwn)) {
552 return false;
555 // Step 6. If hasOwn is false, throw a TypeError exception.
556 if (!hasOwn) {
557 JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
558 JSMSG_SHADOW_REALM_VALUE_NOT_EXPORTED);
559 return false;
562 // Step 7. Let value be ? Get(exports, string).
563 Rooted<Value> value(cx);
564 if (!GetProperty(cx, exports, exports, stringId, &value)) {
565 return false;
568 // Step 8. Let realm be f.[[Realm]].
569 Realm* callerRealm = static_cast<Realm*>(realmValue.toPrivate());
571 // Step 9. Return ? GetWrappedValue(realm, value).
572 return GetWrappedValue(cx, callerRealm, value, args.rval());
574 promise, handlerObject));
575 if (!onFulfilled) {
576 return nullptr;
579 Rooted<JSFunction*> onRejected(
580 cx, NewHandler(
582 [](JSContext* cx, unsigned argc, Value* vp) {
583 JS_ReportErrorNumberASCII(
584 cx, GetErrorMessage, nullptr,
585 JSMSG_SHADOW_REALM_IMPORTVALUE_FAILED);
586 return false;
588 promise));
589 if (!onRejected) {
590 return nullptr;
593 // Step 11. Set onFulfilled.[[ExportNameString]] to exportNameString.
594 // Step 12. Let promiseCapability be ! NewPromiseCapability(%Promise%).
595 // Step 13. Return ! PerformPromiseThen(innerCapability.[[Promise]],
596 // onFulfilled, callerRealm.[[Intrinsics]].[[%ThrowTypeError%]],
597 // promiseCapability).
598 return OriginalPromiseThen(cx, promise, onFulfilled, onRejected);
601 // ShadowRealm.prototype.importValue ( specifier, exportName )
602 // https://tc39.es/proposal-shadowrealm/#sec-shadowrealm.prototype.importvalue
603 static bool ShadowRealm_importValue(JSContext* cx, unsigned argc, Value* vp) {
604 CallArgs args = CallArgsFromVp(argc, vp);
606 // Step 1. Let O be this value.
607 HandleValue obj = args.thisv();
609 // Step 2. Perform ? ValidateShadowRealmObject(O).
610 Rooted<ShadowRealmObject*> shadowRealm(cx,
611 ValidateShadowRealmObject(cx, obj));
612 if (!shadowRealm) {
613 return false;
616 // Step 3. Let specifierString be ? ToString(specifier).
617 Rooted<JSString*> specifierString(cx, ToString<CanGC>(cx, args.get(0)));
618 if (!specifierString) {
619 return false;
622 // Step 4. If Type(exportName) is not String, throw a TypeError exception.
623 if (!args.get(1).isString()) {
624 JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
625 JSMSG_SHADOW_REALM_EXPORT_NOT_STRING);
626 return false;
629 Rooted<JSString*> exportName(cx, args.get(1).toString());
630 if (!exportName) {
631 return false;
634 // Step 5. Let callerRealm be the current Realm Record.
635 Realm* callerRealm = cx->realm();
637 // Step 6. Let evalRealm be O.[[ShadowRealm]].
638 Realm* evalRealm = shadowRealm->getShadowRealm();
640 // Step 7. Let evalContext be O.[[ExecutionContext]]
641 // (we dont' pass this explicitly, instead using the realm+global to
642 // represent)
644 // Step 8. Return ?
645 // ShadowRealmImportValue(specifierString, exportName,
646 // callerRealm, evalRealm,
647 // evalContext).
649 JSObject* res = ShadowRealmImportValue(cx, specifierString, exportName,
650 callerRealm, evalRealm);
651 if (!res) {
652 return false;
655 args.rval().set(ObjectValue(*res));
656 return true;
659 static const JSFunctionSpec shadowrealm_methods[] = {
660 JS_FN("evaluate", ShadowRealm_evaluate, 1, 0),
661 JS_FN("importValue", ShadowRealm_importValue, 2, 0),
662 JS_FS_END,
665 static const JSPropertySpec shadowrealm_properties[] = {
666 JS_STRING_SYM_PS(toStringTag, "ShadowRealm", JSPROP_READONLY),
667 JS_PS_END,
670 static const ClassSpec ShadowRealmObjectClassSpec = {
671 GenericCreateConstructor<ShadowRealmObject::construct, 0,
672 gc::AllocKind::FUNCTION>,
673 GenericCreatePrototype<ShadowRealmObject>,
674 nullptr, // Static methods
675 nullptr, // Static properties
676 shadowrealm_methods, // Methods
677 shadowrealm_properties, // Properties
680 const JSClass ShadowRealmObject::class_ = {
681 "ShadowRealm",
682 JSCLASS_HAS_CACHED_PROTO(JSProto_ShadowRealm) |
683 JSCLASS_HAS_RESERVED_SLOTS(ShadowRealmObject::SlotCount),
684 JS_NULL_CLASS_OPS,
685 &ShadowRealmObjectClassSpec,
688 const JSClass ShadowRealmObject::protoClass_ = {
689 "ShadowRealm.prototype",
690 JSCLASS_HAS_CACHED_PROTO(JSProto_ShadowRealm),
691 JS_NULL_CLASS_OPS,
692 &ShadowRealmObjectClassSpec,