mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2026-04-05 13:43:29 +00:00
Everywhere: Remove ShadowRealm support
The proposal has not seemed to progress for a while, and there is a open issue about module imports which breaks HTML integration. While we could probably make an AD-HOC change to fix that issue, it is deep enough in the JS engine that I am not particularly keen on making that change. Until other browsers begin to make positive signals about shipping ShadowRealms, let's remove our implementation for now. There is still some cleanup that can be done with regard to the HTML integration, but there are a few more items that need to be untangled there.
This commit is contained in:
committed by
Shannon Booth
parent
e2e3c7fcdf
commit
f27bc38aa7
Notes:
github-actions[bot]
2026-04-05 11:59:00 +00:00
Author: https://github.com/shannonbooth Commit: https://github.com/LadybirdBrowser/ladybird/commit/f27bc38aa7c Pull-request: https://github.com/LadybirdBrowser/ladybird/pull/8753
@@ -42,8 +42,6 @@ ErrorOr<ExposedTo> parse_exposure_set(StringView interface_name, StringView expo
|
||||
return ExposedTo::PaintWorklet;
|
||||
if (string == "Worklet"sv)
|
||||
return ExposedTo::Worklet;
|
||||
if (string == "ShadowRealm"sv)
|
||||
return ExposedTo::ShadowRealm;
|
||||
return {};
|
||||
};
|
||||
if (auto parsed_exposed = exposed_from_string(exposed_trimmed); parsed_exposed.has_value())
|
||||
|
||||
@@ -19,13 +19,12 @@ enum class ExposedTo {
|
||||
ServiceWorker = 0x4,
|
||||
AudioWorklet = 0x8,
|
||||
Window = 0x10,
|
||||
ShadowRealm = 0x20,
|
||||
Worklet = 0x40,
|
||||
PaintWorklet = 0x80,
|
||||
LayoutWorklet = 0x100,
|
||||
// FIXME: Categorize PaintWorklet and LayoutWorklet once we have them and know what they are.
|
||||
AllWorkers = DedicatedWorker | SharedWorker | ServiceWorker | AudioWorklet, // FIXME: Is "AudioWorklet" a Worker? We'll assume it is for now (here, and line below)
|
||||
All = AllWorkers | Window | ShadowRealm | Worklet,
|
||||
All = AllWorkers | Window | Worklet,
|
||||
};
|
||||
AK_ENUM_BITWISE_OPERATORS(ExposedTo);
|
||||
|
||||
|
||||
@@ -191,9 +191,6 @@ set(SOURCES
|
||||
Runtime/SetIterator.cpp
|
||||
Runtime/SetIteratorPrototype.cpp
|
||||
Runtime/SetPrototype.cpp
|
||||
Runtime/ShadowRealm.cpp
|
||||
Runtime/ShadowRealmConstructor.cpp
|
||||
Runtime/ShadowRealmPrototype.cpp
|
||||
Runtime/Shape.cpp
|
||||
Runtime/SharedArrayBufferConstructor.cpp
|
||||
Runtime/SharedArrayBufferPrototype.cpp
|
||||
@@ -257,7 +254,6 @@ set(SOURCES
|
||||
Runtime/WeakSetConstructor.cpp
|
||||
Runtime/WeakSetPrototype.cpp
|
||||
Runtime/WrapForValidIteratorPrototype.cpp
|
||||
Runtime/WrappedFunction.cpp
|
||||
Script.cpp
|
||||
SourceCode.cpp
|
||||
SourceTextModule.cpp
|
||||
|
||||
@@ -40,7 +40,6 @@
|
||||
__JS_ENUMERATE(Promise, promise, PromisePrototype, PromiseConstructor, void) \
|
||||
__JS_ENUMERATE(RegExpObject, regexp, RegExpPrototype, RegExpConstructor, void) \
|
||||
__JS_ENUMERATE(Set, set, SetPrototype, SetConstructor, void) \
|
||||
__JS_ENUMERATE(ShadowRealm, shadow_realm, ShadowRealmPrototype, ShadowRealmConstructor, void) \
|
||||
__JS_ENUMERATE(SharedArrayBuffer, shared_array_buffer, SharedArrayBufferPrototype, SharedArrayBufferConstructor, void) \
|
||||
__JS_ENUMERATE(StringObject, string, StringPrototype, StringConstructor, void) \
|
||||
__JS_ENUMERATE(SuppressedError, suppressed_error, SuppressedErrorPrototype, SuppressedErrorConstructor, void) \
|
||||
|
||||
@@ -43,7 +43,6 @@
|
||||
#include <LibJS/Runtime/ProxyObject.h>
|
||||
#include <LibJS/Runtime/RegExpObject.h>
|
||||
#include <LibJS/Runtime/Set.h>
|
||||
#include <LibJS/Runtime/ShadowRealm.h>
|
||||
#include <LibJS/Runtime/Shape.h>
|
||||
#include <LibJS/Runtime/StringObject.h>
|
||||
#include <LibJS/Runtime/StringPrototype.h>
|
||||
@@ -419,13 +418,6 @@ ErrorOr<void> print_array_buffer(JS::PrintContext& print_context, JS::ArrayBuffe
|
||||
return {};
|
||||
}
|
||||
|
||||
ErrorOr<void> print_shadow_realm(JS::PrintContext& print_context, JS::ShadowRealm const&, HashTable<JS::Object*>&)
|
||||
{
|
||||
// Not much we can show here that would be useful. Realm pointer address?!
|
||||
TRY(print_type(print_context, "ShadowRealm"sv));
|
||||
return {};
|
||||
}
|
||||
|
||||
ErrorOr<void> print_generator(JS::PrintContext& print_context, JS::GeneratorObject const& generator, HashTable<JS::Object*>&)
|
||||
{
|
||||
TRY(print_type(print_context, generator.class_name()));
|
||||
@@ -972,8 +964,6 @@ ErrorOr<void> print_value(JS::PrintContext& print_context, JS::Value value, Hash
|
||||
return print_promise(print_context, static_cast<JS::Promise&>(object), seen_objects);
|
||||
if (is<JS::ArrayBuffer>(object))
|
||||
return print_array_buffer(print_context, static_cast<JS::ArrayBuffer&>(object), seen_objects);
|
||||
if (is<JS::ShadowRealm>(object))
|
||||
return print_shadow_realm(print_context, static_cast<JS::ShadowRealm&>(object), seen_objects);
|
||||
if (is<JS::GeneratorObject>(object))
|
||||
return print_generator(print_context, static_cast<JS::GeneratorObject&>(object), seen_objects);
|
||||
if (is<JS::AsyncGenerator>(object))
|
||||
|
||||
@@ -237,8 +237,6 @@
|
||||
M(RestrictedGlobalProperty, "Cannot declare global property '{}'") \
|
||||
M(SetLegacyRegExpStaticPropertyThisValueMismatch, \
|
||||
"Legacy RegExp static property setter must be called with the RegExp constructor for the this value") \
|
||||
M(ShadowRealmEvaluateAbruptCompletion, "The evaluated script did not complete normally") \
|
||||
M(ShadowRealmWrappedValueNonFunctionObject, "Wrapped value must be primitive or a function object, got {}") \
|
||||
M(SharedArrayBuffer, "The array buffer object cannot be a SharedArrayBuffer") \
|
||||
M(SpeciesConstructorDidNotCreate, "Species constructor did not create {}") \
|
||||
M(SpeciesConstructorReturned, "Species constructor returned {}") \
|
||||
|
||||
@@ -15,7 +15,6 @@
|
||||
#include <LibJS/Runtime/FunctionPrototype.h>
|
||||
#include <LibJS/Runtime/GlobalObject.h>
|
||||
#include <LibJS/Runtime/NativeFunction.h>
|
||||
#include <LibJS/Runtime/ShadowRealm.h>
|
||||
|
||||
namespace JS {
|
||||
|
||||
@@ -94,7 +93,6 @@ JS_DEFINE_NATIVE_FUNCTION(FunctionPrototype::apply)
|
||||
}
|
||||
|
||||
// 20.2.3.2 Function.prototype.bind ( thisArg, ...args ), https://tc39.es/ecma262/#sec-function.prototype.bind
|
||||
// 3.1.2.1 Function.prototype.bind ( thisArg, ...args ), https://tc39.es/proposal-shadowrealm/#sec-function.prototype.bind
|
||||
JS_DEFINE_NATIVE_FUNCTION(FunctionPrototype::bind)
|
||||
{
|
||||
auto& realm = *vm.current_realm();
|
||||
@@ -115,16 +113,60 @@ JS_DEFINE_NATIVE_FUNCTION(FunctionPrototype::bind)
|
||||
arguments.append(vm.running_execution_context().arguments_span().slice(1).data(), vm.argument_count() - 1);
|
||||
}
|
||||
|
||||
// 3. Let F be ? BoundFunctionCreate(Target, thisArg, args).
|
||||
// 3. Let F be ? BoundFunctionCreate(Target, thisArg, args).
|
||||
auto function = TRY(BoundFunction::create(realm, target, this_argument, move(arguments)));
|
||||
|
||||
// 4. Let argCount be the number of elements in args.
|
||||
auto arg_count = vm.argument_count() > 0 ? vm.argument_count() - 1 : 0;
|
||||
// 4. Let L be 0.
|
||||
double length = 0;
|
||||
|
||||
// 5. Perform ? CopyNameAndLength(F, Target, "bound", argCount).
|
||||
TRY(copy_name_and_length(vm, *function, target, "bound"sv, arg_count));
|
||||
// 5. Let targetHasLength be ? HasOwnProperty(Target, "length").
|
||||
auto target_has_length = TRY(target.has_own_property(vm.names.length));
|
||||
|
||||
// 6. Return F.
|
||||
// 6. If targetHasLength is true, then
|
||||
if (target_has_length) {
|
||||
// a. Let targetLen be ? Get(Target, "length").
|
||||
auto target_length = TRY(target.get(vm.names.length));
|
||||
|
||||
// b. If targetLen is a Number, then
|
||||
if (target_length.is_number()) {
|
||||
// i. If targetLen is +∞𝔽, then
|
||||
if (target_length.is_positive_infinity()) {
|
||||
// 1. Set L to +∞.
|
||||
length = target_length.as_double();
|
||||
}
|
||||
// ii. Else if targetLen is -∞𝔽, then
|
||||
else if (target_length.is_negative_infinity()) {
|
||||
// 1. Set L to 0.
|
||||
length = 0;
|
||||
}
|
||||
// iii. Else,
|
||||
else {
|
||||
// 1. Let targetLenAsInt be ! ToIntegerOrInfinity(targetLen).
|
||||
auto target_length_as_int = MUST(target_length.to_integer_or_infinity(vm));
|
||||
|
||||
// 2. Assert: targetLenAsInt is finite.
|
||||
VERIFY(!isinf(target_length_as_int));
|
||||
|
||||
// 3. Let argCount be the number of elements in args.
|
||||
auto arg_count = vm.argument_count() > 1 ? vm.argument_count() - 1 : 0;
|
||||
|
||||
// 4. Set L to max(targetLenAsInt - argCount, 0).
|
||||
length = max(target_length_as_int - arg_count, 0.0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 7. Perform SetFunctionLength(F, L).
|
||||
function->set_function_length(length);
|
||||
|
||||
// 8. Let targetName be ? Get(Target, "name").
|
||||
auto target_name = TRY(target.get(vm.names.name));
|
||||
|
||||
// 9. If targetName is not a String, set targetName to the empty String.
|
||||
// 10. Perform SetFunctionName(F, targetName, "bound").
|
||||
function->set_function_name({ target_name.is_string() ? target_name.as_string().utf16_string() : Utf16String {} }, "bound"sv);
|
||||
|
||||
// 11. Return F.
|
||||
return function;
|
||||
}
|
||||
|
||||
|
||||
@@ -61,7 +61,6 @@
|
||||
#include <LibJS/Runtime/ReflectObject.h>
|
||||
#include <LibJS/Runtime/RegExpConstructor.h>
|
||||
#include <LibJS/Runtime/SetConstructor.h>
|
||||
#include <LibJS/Runtime/ShadowRealmConstructor.h>
|
||||
#include <LibJS/Runtime/Shape.h>
|
||||
#include <LibJS/Runtime/SharedArrayBufferConstructor.h>
|
||||
#include <LibJS/Runtime/StringConstructor.h>
|
||||
@@ -152,7 +151,6 @@ void set_default_global_bindings(Realm& realm)
|
||||
global.define_intrinsic_accessor(vm.names.ReferenceError, attr, [](auto& realm) -> Value { return realm.intrinsics().reference_error_constructor(); });
|
||||
global.define_intrinsic_accessor(vm.names.RegExp, attr, [](auto& realm) -> Value { return realm.intrinsics().regexp_constructor(); });
|
||||
global.define_intrinsic_accessor(vm.names.Set, attr, [](auto& realm) -> Value { return realm.intrinsics().set_constructor(); });
|
||||
global.define_intrinsic_accessor(vm.names.ShadowRealm, attr, [](auto& realm) -> Value { return realm.intrinsics().shadow_realm_constructor(); });
|
||||
global.define_intrinsic_accessor(vm.names.SharedArrayBuffer, attr, [](auto& realm) -> Value { return realm.intrinsics().shared_array_buffer_constructor(); });
|
||||
global.define_intrinsic_accessor(vm.names.String, attr, [](auto& realm) -> Value { return realm.intrinsics().string_constructor(); });
|
||||
global.define_intrinsic_accessor(vm.names.SuppressedError, attr, [](auto& realm) -> Value { return realm.intrinsics().suppressed_error_constructor(); });
|
||||
|
||||
@@ -94,8 +94,6 @@
|
||||
#include <LibJS/Runtime/SetConstructor.h>
|
||||
#include <LibJS/Runtime/SetIteratorPrototype.h>
|
||||
#include <LibJS/Runtime/SetPrototype.h>
|
||||
#include <LibJS/Runtime/ShadowRealmConstructor.h>
|
||||
#include <LibJS/Runtime/ShadowRealmPrototype.h>
|
||||
#include <LibJS/Runtime/Shape.h>
|
||||
#include <LibJS/Runtime/SharedArrayBufferConstructor.h>
|
||||
#include <LibJS/Runtime/SharedArrayBufferPrototype.h>
|
||||
|
||||
@@ -1,329 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2021-2022, Linus Groh <linusg@serenityos.org>
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
#include <LibJS/Bytecode/Executable.h>
|
||||
#include <LibJS/Bytecode/Interpreter.h>
|
||||
#include <LibJS/Runtime/AbstractOperations.h>
|
||||
#include <LibJS/Runtime/DeclarativeEnvironment.h>
|
||||
#include <LibJS/Runtime/GlobalEnvironment.h>
|
||||
#include <LibJS/Runtime/ModuleNamespaceObject.h>
|
||||
#include <LibJS/Runtime/NativeFunction.h>
|
||||
#include <LibJS/Runtime/PromiseCapability.h>
|
||||
#include <LibJS/Runtime/PromiseConstructor.h>
|
||||
#include <LibJS/Runtime/ShadowRealm.h>
|
||||
#include <LibJS/Runtime/WrappedFunction.h>
|
||||
#include <LibJS/RustIntegration.h>
|
||||
#include <LibJS/SourceCode.h>
|
||||
|
||||
namespace JS {
|
||||
|
||||
GC_DEFINE_ALLOCATOR(ShadowRealm);
|
||||
|
||||
ShadowRealm::ShadowRealm(Object& prototype)
|
||||
: Object(ConstructWithPrototypeTag::Tag, prototype)
|
||||
{
|
||||
}
|
||||
|
||||
void ShadowRealm::visit_edges(Visitor& visitor)
|
||||
{
|
||||
Base::visit_edges(visitor);
|
||||
|
||||
visitor.visit(m_shadow_realm);
|
||||
}
|
||||
|
||||
// 3.1.2 CopyNameAndLength ( F: a function object, Target: a function object, optional prefix: a String, optional argCount: a Number, ), https://tc39.es/proposal-shadowrealm/#sec-copynameandlength
|
||||
ThrowCompletionOr<void> copy_name_and_length(VM& vm, FunctionObject& function, FunctionObject& target, Optional<StringView> prefix, Optional<unsigned> arg_count)
|
||||
{
|
||||
// 1. If argCount is undefined, then set argCount to 0.
|
||||
if (!arg_count.has_value())
|
||||
arg_count = 0;
|
||||
|
||||
// 2. Let L be 0.
|
||||
double length = 0;
|
||||
|
||||
// 3. Let targetHasLength be ? HasOwnProperty(Target, "length").
|
||||
auto target_has_length = TRY(target.has_own_property(vm.names.length));
|
||||
|
||||
// 4. If targetHasLength is true, then
|
||||
if (target_has_length) {
|
||||
// a. Let targetLen be ? Get(Target, "length").
|
||||
auto target_length = TRY(target.get(vm.names.length));
|
||||
|
||||
// b. If Type(targetLen) is Number, then
|
||||
if (target_length.is_number()) {
|
||||
// i. If targetLen is +∞𝔽, set L to +∞.
|
||||
if (target_length.is_positive_infinity()) {
|
||||
length = target_length.as_double();
|
||||
}
|
||||
// ii. Else if targetLen is -∞𝔽, set L to 0.
|
||||
else if (target_length.is_negative_infinity()) {
|
||||
length = 0;
|
||||
}
|
||||
// iii. Else,
|
||||
else {
|
||||
// 1. Let targetLenAsInt be ! ToIntegerOrInfinity(targetLen).
|
||||
auto target_length_as_int = MUST(target_length.to_integer_or_infinity(vm));
|
||||
|
||||
// 2. Assert: targetLenAsInt is finite.
|
||||
VERIFY(!isinf(target_length_as_int));
|
||||
|
||||
// 3. Set L to max(targetLenAsInt - argCount, 0).
|
||||
length = max(target_length_as_int - *arg_count, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 5. Perform SetFunctionLength(F, L).
|
||||
function.set_function_length(length);
|
||||
|
||||
// 6. Let targetName be ? Get(Target, "name").
|
||||
auto target_name = TRY(target.get(vm.names.name));
|
||||
|
||||
// 7. If Type(targetName) is not String, set targetName to the empty String.
|
||||
if (!target_name.is_string())
|
||||
target_name = PrimitiveString::create(vm, String {});
|
||||
|
||||
// 8. Perform SetFunctionName(F, targetName, prefix).
|
||||
function.set_function_name({ target_name.as_string().utf16_string() }, move(prefix));
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
// 3.1.3 PerformShadowRealmEval ( sourceText: a String, callerRealm: a Realm Record, evalRealm: a Realm Record, ), https://tc39.es/proposal-shadowrealm/#sec-performshadowrealmeval
|
||||
ThrowCompletionOr<Value> perform_shadow_realm_eval(VM& vm, Value source, Realm& caller_realm, Realm& eval_realm)
|
||||
{
|
||||
// 1. Perform ? HostEnsureCanCompileStrings(evalRealm, « », sourceText, false).
|
||||
// FIXME: ShadowRealm doesn't yet intersect with the Dynamic Code Brand Checks proposal.
|
||||
// This is a close approximation, following the PerformEval implementation.
|
||||
// See: https://github.com/tc39/proposal-dynamic-code-brand-checks/issues/19
|
||||
// https://github.com/tc39/proposal-shadowrealm/issues/414
|
||||
GC::Ptr<PrimitiveString> source_text;
|
||||
|
||||
if (source.is_string()) {
|
||||
source_text = source.as_string();
|
||||
} else if (source.is_object()) {
|
||||
auto code = vm.host_get_code_for_eval(source.as_object());
|
||||
|
||||
if (code) {
|
||||
source_text = code;
|
||||
} else {
|
||||
return vm.throw_completion<TypeError>(ErrorType::NotAString, source);
|
||||
}
|
||||
} else {
|
||||
return vm.throw_completion<TypeError>(ErrorType::NotAString, source);
|
||||
}
|
||||
|
||||
VERIFY(source_text);
|
||||
|
||||
TRY(vm.host_ensure_can_compile_strings(eval_realm, {}, source_text->utf8_string_view(), source_text->utf8_string_view(), CompilationType::IndirectEval, {}, source));
|
||||
|
||||
// 2. Perform the following substeps in an implementation-defined order, possibly interleaving parsing and error detection:
|
||||
|
||||
auto rust_compilation = RustIntegration::compile_shadow_realm_eval(*source_text, vm);
|
||||
if (!rust_compilation.has_value())
|
||||
return vm.throw_completion<SyntaxError>("Failed to compile ShadowRealm eval code"_string);
|
||||
if (rust_compilation->is_error())
|
||||
return vm.throw_completion<SyntaxError>(rust_compilation->release_error());
|
||||
auto& compilation_result = rust_compilation->value();
|
||||
auto executable = compilation_result.executable;
|
||||
auto strict_eval = compilation_result.is_strict_mode;
|
||||
auto eval_declaration_data = move(compilation_result.declaration_data);
|
||||
|
||||
// 4. Let runningContext be the running execution context.
|
||||
// 5. If runningContext is not already suspended, suspend runningContext.
|
||||
// NOTE: This would be unused due to step 9 and is omitted for that reason.
|
||||
|
||||
// 6. Let evalContext be GetShadowRealmContext(evalRealm, strictEval).
|
||||
auto eval_context = get_shadow_realm_context(eval_realm, strict_eval, executable->registers_and_locals_count, executable->constants);
|
||||
|
||||
// 7. Let lexEnv be evalContext's LexicalEnvironment.
|
||||
auto lexical_environment = eval_context->lexical_environment;
|
||||
|
||||
// 8. Let varEnv be evalContext's VariableEnvironment.
|
||||
auto variable_environment = eval_context->variable_environment;
|
||||
|
||||
// 9. Push evalContext onto the execution context stack; evalContext is now the running execution context.
|
||||
TRY(vm.push_execution_context(*eval_context, {}));
|
||||
|
||||
// 10. Let result be Completion(EvalDeclarationInstantiation(body, varEnv, lexEnv, null, strictEval)).
|
||||
auto eval_result = eval_declaration_instantiation(vm, eval_declaration_data, variable_environment, lexical_environment, nullptr, strict_eval);
|
||||
|
||||
Completion result;
|
||||
|
||||
// 11. If result.[[Type]] is normal, then
|
||||
if (!eval_result.is_throw_completion()) {
|
||||
// a. Set result to the result of evaluating body.
|
||||
auto result_or_error = vm.bytecode_interpreter().run_executable(*eval_context, *executable, {});
|
||||
if (result_or_error.is_error()) {
|
||||
result = result_or_error.release_error();
|
||||
} else {
|
||||
result = result_or_error.value();
|
||||
}
|
||||
}
|
||||
|
||||
// 12. If result.[[Type]] is normal and result.[[Value]] is empty, then
|
||||
if (result.type() == Completion::Type::Normal && result.value().is_special_empty_value()) {
|
||||
// a. Set result to NormalCompletion(undefined).
|
||||
result = normal_completion(js_undefined());
|
||||
}
|
||||
|
||||
// 13. Suspend evalContext and remove it from the execution context stack.
|
||||
// NOTE: We don't support this concept yet.
|
||||
vm.pop_execution_context();
|
||||
|
||||
// 14. Resume the context that is now on the top of the execution context stack as the running execution context.
|
||||
// NOTE: We don't support this concept yet.
|
||||
|
||||
// 15. If result.[[Type]] is not normal, then
|
||||
if (result.type() != Completion::Type::Normal) {
|
||||
// a. Let copiedError be CreateTypeErrorCopy(callerRealm, result.[[Value]]).
|
||||
// b. Return ThrowCompletion(copiedError).
|
||||
return vm.throw_completion<TypeError>(ErrorType::ShadowRealmEvaluateAbruptCompletion);
|
||||
}
|
||||
|
||||
// 16. Return ? GetWrappedValue(callerRealm, result.[[Value]]).
|
||||
return get_wrapped_value(vm, caller_realm, result.value());
|
||||
|
||||
// NOTE: Also see "Editor's Note" in the spec regarding the TypeError above.
|
||||
}
|
||||
|
||||
// 3.1.4 ShadowRealmImportValue ( specifierString: a String, exportNameString: a String, callerRealm: a Realm Record, evalRealm: a Realm Record, evalContext: an execution context, ), https://tc39.es/proposal-shadowrealm/#sec-shadowrealmimportvalue
|
||||
ThrowCompletionOr<Value> shadow_realm_import_value(VM& vm, Utf16FlyString specifier_string, Utf16FlyString export_name_string, Realm& caller_realm, Realm& eval_realm)
|
||||
{
|
||||
auto& realm = *vm.current_realm();
|
||||
|
||||
// 1. Let evalContext be GetShadowRealmContext(evalRealm, true).
|
||||
auto eval_context = get_shadow_realm_context(eval_realm, true, 0, ReadonlySpan<Value> {});
|
||||
|
||||
// 2. Let innerCapability be ! NewPromiseCapability(%Promise%).
|
||||
auto inner_capability = MUST(new_promise_capability(vm, realm.intrinsics().promise_constructor()));
|
||||
|
||||
// 3. Let runningContext be the running execution context.
|
||||
// 4. If runningContext is not already suspended, suspend runningContext.
|
||||
// NOTE: We don't support this concept yet.
|
||||
|
||||
// 5. Push evalContext onto the execution context stack; evalContext is now the running execution context.
|
||||
TRY(vm.push_execution_context(*eval_context, {}));
|
||||
|
||||
// 6. Let referrer be the Realm component of evalContext.
|
||||
auto referrer = GC::Ref { *eval_context->realm };
|
||||
|
||||
// 7. Perform HostLoadImportedModule(referrer, specifierString, empty, innerCapability).
|
||||
vm.host_load_imported_module(referrer, ModuleRequest { move(specifier_string) }, nullptr, inner_capability);
|
||||
|
||||
// 7. Suspend evalContext and remove it from the execution context stack.
|
||||
// NOTE: We don't support this concept yet.
|
||||
vm.pop_execution_context();
|
||||
|
||||
// 8. Resume the context that is now on the top of the execution context stack as the running execution context.
|
||||
// NOTE: We don't support this concept yet.
|
||||
|
||||
// 9. Let steps be the steps of an ExportGetter function as described below.
|
||||
auto steps = [string = move(export_name_string)](auto& vm) -> ThrowCompletionOr<Value> {
|
||||
// 1. Assert: exports is a module namespace exotic object.
|
||||
VERIFY(vm.argument(0).is_object());
|
||||
auto& exports = vm.argument(0).as_object();
|
||||
VERIFY(is<ModuleNamespaceObject>(exports));
|
||||
|
||||
// 2. Let f be the active function object.
|
||||
auto function = vm.running_execution_context().function;
|
||||
|
||||
// 3. Let string be f.[[ExportNameString]].
|
||||
// 4. Assert: Type(string) is String.
|
||||
|
||||
// 5. Let hasOwn be ? HasOwnProperty(exports, string).
|
||||
auto has_own = TRY(exports.has_own_property(string));
|
||||
|
||||
// 6. If hasOwn is false, throw a TypeError exception.
|
||||
if (!has_own)
|
||||
return vm.template throw_completion<TypeError>(ErrorType::MissingRequiredProperty, string);
|
||||
|
||||
// 7. Let value be ? Get(exports, string).
|
||||
auto value = TRY(exports.get(string));
|
||||
|
||||
// 8. Let realm be f.[[Realm]].
|
||||
auto* realm = function->realm();
|
||||
VERIFY(realm);
|
||||
|
||||
// 9. Return ? GetWrappedValue(realm, value).
|
||||
return get_wrapped_value(vm, *realm, value);
|
||||
};
|
||||
|
||||
// 10. Let onFulfilled be CreateBuiltinFunction(steps, 1, "", « [[ExportNameString]] », callerRealm).
|
||||
// 11. Set onFulfilled.[[ExportNameString]] to exportNameString.
|
||||
auto on_fulfilled = NativeFunction::create(realm, move(steps), 1, Utf16FlyString {}, &caller_realm);
|
||||
|
||||
// 12. Let promiseCapability be ! NewPromiseCapability(%Promise%).
|
||||
auto promise_capability = MUST(new_promise_capability(vm, realm.intrinsics().promise_constructor()));
|
||||
|
||||
// NOTE: Even though the spec tells us to use %ThrowTypeError%, it's not observable if we actually do.
|
||||
// Throw a nicer TypeError forwarding the import error message instead (we know the argument is an Error object).
|
||||
auto throw_type_error = NativeFunction::create(realm, {}, [](auto& vm) -> ThrowCompletionOr<Value> {
|
||||
return vm.template throw_completion<TypeError>(vm.argument(0).as_object().get_without_side_effects(vm.names.message).as_string().utf8_string());
|
||||
});
|
||||
|
||||
// 13. Return PerformPromiseThen(innerCapability.[[Promise]], onFulfilled, callerRealm.[[Intrinsics]].[[%ThrowTypeError%]], promiseCapability).
|
||||
return as<Promise>(inner_capability->promise().ptr())->perform_then(on_fulfilled, throw_type_error, promise_capability);
|
||||
}
|
||||
|
||||
// 3.1.5 GetWrappedValue ( callerRealm: a Realm Record, value: unknown, ), https://tc39.es/proposal-shadowrealm/#sec-getwrappedvalue
|
||||
ThrowCompletionOr<Value> get_wrapped_value(VM& vm, Realm& caller_realm, Value value)
|
||||
{
|
||||
auto& realm = *vm.current_realm();
|
||||
|
||||
// 1. If Type(value) is Object, then
|
||||
if (value.is_object()) {
|
||||
// a. If IsCallable(value) is false, throw a TypeError exception.
|
||||
if (!value.is_function())
|
||||
return vm.throw_completion<TypeError>(ErrorType::ShadowRealmWrappedValueNonFunctionObject, value);
|
||||
|
||||
// b. Return ? WrappedFunctionCreate(callerRealm, value).
|
||||
return TRY(WrappedFunction::create(realm, caller_realm, value.as_function()));
|
||||
}
|
||||
|
||||
// 2. Return value.
|
||||
return value;
|
||||
}
|
||||
|
||||
// 3.1.7 GetShadowRealmContext ( shadowRealmRecord, strictEval ), https://tc39.es/proposal-shadowrealm/#sec-getshadowrealmcontext
|
||||
NonnullOwnPtr<ExecutionContext> get_shadow_realm_context(Realm& shadow_realm, bool strict_eval, u32 registers_and_locals_count, ReadonlySpan<Value> constants)
|
||||
{
|
||||
// 1. Let lexEnv be NewDeclarativeEnvironment(shadowRealmRecord.[[GlobalEnv]]).
|
||||
Environment* lexical_environment = new_declarative_environment(shadow_realm.global_environment()).ptr();
|
||||
|
||||
// 2. Let varEnv be shadowRealmRecord.[[GlobalEnv]].
|
||||
Environment* variable_environment = &shadow_realm.global_environment();
|
||||
|
||||
// 3. If strictEval is true, set varEnv to lexEnv.
|
||||
if (strict_eval)
|
||||
variable_environment = lexical_environment;
|
||||
|
||||
// 4. Let context be a new ECMAScript code execution context.
|
||||
auto context = ExecutionContext::create(registers_and_locals_count, constants, 0);
|
||||
|
||||
// 5. Set context's Function to null.
|
||||
context->function = nullptr;
|
||||
|
||||
// 6. Set context's Realm to shadowRealmRecord.
|
||||
context->realm = &shadow_realm;
|
||||
|
||||
// 7. Set context's ScriptOrModule to null.
|
||||
context->script_or_module = {};
|
||||
|
||||
// 8. Set context's VariableEnvironment to varEnv.
|
||||
context->variable_environment = variable_environment;
|
||||
|
||||
// 9. Set context's LexicalEnvironment to lexEnv.
|
||||
context->lexical_environment = lexical_environment;
|
||||
|
||||
// 10. Set context's PrivateEnvironment to null.
|
||||
context->private_environment = nullptr;
|
||||
|
||||
// 11. Return context.
|
||||
return context;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,43 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2021-2022, Linus Groh <linusg@serenityos.org>
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <AK/Span.h>
|
||||
#include <LibJS/Runtime/Completion.h>
|
||||
#include <LibJS/Runtime/ExecutionContext.h>
|
||||
#include <LibJS/Runtime/Object.h>
|
||||
#include <LibJS/Runtime/Realm.h>
|
||||
|
||||
namespace JS {
|
||||
|
||||
class ShadowRealm final : public Object {
|
||||
JS_OBJECT(ShadowRealm, Object);
|
||||
GC_DECLARE_ALLOCATOR(ShadowRealm);
|
||||
|
||||
public:
|
||||
virtual ~ShadowRealm() override = default;
|
||||
|
||||
[[nodiscard]] Realm const& shadow_realm() const { return *m_shadow_realm; }
|
||||
[[nodiscard]] Realm& shadow_realm() { return *m_shadow_realm; }
|
||||
void set_shadow_realm(GC::Ref<Realm> realm) { m_shadow_realm = realm; }
|
||||
|
||||
private:
|
||||
ShadowRealm(Object& prototype);
|
||||
|
||||
virtual void visit_edges(Visitor&) override;
|
||||
|
||||
// 3.5 Properties of ShadowRealm Instances, https://tc39.es/proposal-shadowrealm/#sec-properties-of-shadowrealm-instances
|
||||
GC::Ptr<Realm> m_shadow_realm; // [[ShadowRealm]]
|
||||
};
|
||||
|
||||
ThrowCompletionOr<void> copy_name_and_length(VM&, FunctionObject& function, FunctionObject& target, Optional<StringView> prefix = {}, Optional<unsigned> arg_count = {});
|
||||
ThrowCompletionOr<Value> perform_shadow_realm_eval(VM&, Value source, Realm& caller_realm, Realm& eval_realm);
|
||||
ThrowCompletionOr<Value> shadow_realm_import_value(VM&, Utf16FlyString specifier_string, Utf16FlyString export_name_string, Realm& caller_realm, Realm& eval_realm);
|
||||
ThrowCompletionOr<Value> get_wrapped_value(VM&, Realm& caller_realm, Value);
|
||||
NonnullOwnPtr<ExecutionContext> get_shadow_realm_context(Realm& shadow_realm, bool strict_eval, u32 registers_and_locals_count, ReadonlySpan<Value> constants);
|
||||
|
||||
}
|
||||
@@ -1,71 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2021-2023, Linus Groh <linusg@serenityos.org>
|
||||
* Copyright (c) 2024, Shannon Booth <shannon@serenityos.org>
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
#include <LibJS/Runtime/AbstractOperations.h>
|
||||
#include <LibJS/Runtime/ShadowRealm.h>
|
||||
#include <LibJS/Runtime/ShadowRealmConstructor.h>
|
||||
|
||||
namespace JS {
|
||||
|
||||
GC_DEFINE_ALLOCATOR(ShadowRealmConstructor);
|
||||
|
||||
// 3.2 The ShadowRealm Constructor, https://tc39.es/proposal-shadowrealm/#sec-shadowrealm-constructor
|
||||
ShadowRealmConstructor::ShadowRealmConstructor(Realm& realm)
|
||||
: NativeFunction(realm.vm().names.ShadowRealm.as_string(), realm.intrinsics().function_prototype())
|
||||
{
|
||||
}
|
||||
|
||||
void ShadowRealmConstructor::initialize(Realm& realm)
|
||||
{
|
||||
auto& vm = this->vm();
|
||||
Base::initialize(realm);
|
||||
|
||||
// 3.3.1 ShadowRealm.prototype, https://tc39.es/proposal-shadowrealm/#sec-shadowrealm.prototype
|
||||
define_direct_property(vm.names.prototype, realm.intrinsics().shadow_realm_prototype(), 0);
|
||||
|
||||
define_direct_property(vm.names.length, Value(0), Attribute::Configurable);
|
||||
}
|
||||
|
||||
// 3.2.1 ShadowRealm ( ), https://tc39.es/proposal-shadowrealm/#sec-shadowrealm
|
||||
ThrowCompletionOr<Value> ShadowRealmConstructor::call()
|
||||
{
|
||||
auto& vm = this->vm();
|
||||
|
||||
// 1. If NewTarget is undefined, throw a TypeError exception.
|
||||
return vm.throw_completion<TypeError>(ErrorType::ConstructorWithoutNew, vm.names.ShadowRealm);
|
||||
}
|
||||
|
||||
// 3.2.1 ShadowRealm ( ), https://tc39.es/proposal-shadowrealm/#sec-shadowrealm
|
||||
ThrowCompletionOr<GC::Ref<Object>> ShadowRealmConstructor::construct(FunctionObject& new_target)
|
||||
{
|
||||
auto& vm = this->vm();
|
||||
|
||||
// 2. Let O be ? OrdinaryCreateFromConstructor(NewTarget, "%ShadowRealm.prototype%", « [[ShadowRealm]] »).
|
||||
auto object = TRY(ordinary_create_from_constructor<ShadowRealm>(vm, new_target, &Intrinsics::shadow_realm_prototype));
|
||||
|
||||
// 3. Let callerContext be the running execution context.
|
||||
// 4. Perform ? InitializeHostDefinedRealm().
|
||||
// 5. Let innerContext be the running execution context.
|
||||
auto inner_context = TRY(Realm::initialize_host_defined_realm(vm, nullptr, nullptr));
|
||||
|
||||
// 6. Remove innerContext from the execution context stack and restore callerContext as the running execution context.
|
||||
vm.pop_execution_context();
|
||||
|
||||
// 7. Let realmRec be the Realm of innerContext.
|
||||
auto& realm_record = *inner_context->realm;
|
||||
|
||||
// 8. Set O.[[ShadowRealm]] to realmRec.
|
||||
object->set_shadow_realm(realm_record);
|
||||
|
||||
// 9. Perform ? HostInitializeShadowRealm(realmRec, innerContext, O).
|
||||
TRY(vm.host_initialize_shadow_realm(realm_record, move(inner_context), object));
|
||||
|
||||
// 10. Return O.
|
||||
return object;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,30 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2021-2022, Linus Groh <linusg@serenityos.org>
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <LibJS/Runtime/NativeFunction.h>
|
||||
|
||||
namespace JS {
|
||||
|
||||
class ShadowRealmConstructor final : public NativeFunction {
|
||||
JS_OBJECT(ShadowRealmConstructor, NativeFunction);
|
||||
GC_DECLARE_ALLOCATOR(ShadowRealmConstructor);
|
||||
|
||||
public:
|
||||
virtual void initialize(Realm&) override;
|
||||
virtual ~ShadowRealmConstructor() override = default;
|
||||
|
||||
virtual ThrowCompletionOr<Value> call() override;
|
||||
virtual ThrowCompletionOr<GC::Ref<Object>> construct(FunctionObject& new_target) override;
|
||||
|
||||
private:
|
||||
explicit ShadowRealmConstructor(Realm&);
|
||||
|
||||
virtual bool has_constructor() const override { return true; }
|
||||
};
|
||||
|
||||
}
|
||||
@@ -1,83 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2021-2023, Linus Groh <linusg@serenityos.org>
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
#include <LibJS/Runtime/GlobalObject.h>
|
||||
#include <LibJS/Runtime/ShadowRealm.h>
|
||||
#include <LibJS/Runtime/ShadowRealmPrototype.h>
|
||||
|
||||
namespace JS {
|
||||
|
||||
GC_DEFINE_ALLOCATOR(ShadowRealmPrototype);
|
||||
|
||||
// 3.4 Properties of the ShadowRealm Prototype Object, https://tc39.es/proposal-shadowrealm/#sec-properties-of-the-shadowrealm-prototype-object
|
||||
ShadowRealmPrototype::ShadowRealmPrototype(Realm& realm)
|
||||
: PrototypeObject(realm.intrinsics().object_prototype())
|
||||
{
|
||||
}
|
||||
|
||||
void ShadowRealmPrototype::initialize(Realm& realm)
|
||||
{
|
||||
auto& vm = this->vm();
|
||||
Base::initialize(realm);
|
||||
|
||||
u8 attr = Attribute::Writable | Attribute::Configurable;
|
||||
define_native_function(realm, vm.names.evaluate, evaluate, 1, attr);
|
||||
define_native_function(realm, vm.names.importValue, import_value, 2, attr);
|
||||
|
||||
// 3.4.3 ShadowRealm.prototype [ @@toStringTag ], https://tc39.es/proposal-shadowrealm/#sec-shadowrealm.prototype-@@tostringtag
|
||||
define_direct_property(vm.well_known_symbol_to_string_tag(), PrimitiveString::create(vm, vm.names.ShadowRealm.as_string()), Attribute::Configurable);
|
||||
}
|
||||
|
||||
// 3.4.1 ShadowRealm.prototype.evaluate ( sourceText ), https://tc39.es/proposal-shadowrealm/#sec-shadowrealm.prototype.evaluate
|
||||
JS_DEFINE_NATIVE_FUNCTION(ShadowRealmPrototype::evaluate)
|
||||
{
|
||||
auto source_text = vm.argument(0);
|
||||
|
||||
// 1. Let O be this value.
|
||||
// 2. Perform ? ValidateShadowRealmObject(O).
|
||||
auto object = TRY(typed_this_object(vm));
|
||||
|
||||
// 3. If Type(sourceText) is not String, throw a TypeError exception.
|
||||
// FIXME: This step is intentionally skipped, see perform_shadow_realm_eval.
|
||||
|
||||
// 4. Let callerRealm be the current Realm Record.
|
||||
auto* caller_realm = vm.current_realm();
|
||||
|
||||
// 5. Let evalRealm be O.[[ShadowRealm]].
|
||||
auto& eval_realm = object->shadow_realm();
|
||||
|
||||
// 6. Return ? PerformShadowRealmEval(sourceText, callerRealm, evalRealm).
|
||||
return perform_shadow_realm_eval(vm, source_text, *caller_realm, eval_realm);
|
||||
}
|
||||
|
||||
// 3.4.2 ShadowRealm.prototype.importValue ( specifier, exportName ), https://tc39.es/proposal-shadowrealm/#sec-shadowrealm.prototype.importvalue
|
||||
JS_DEFINE_NATIVE_FUNCTION(ShadowRealmPrototype::import_value)
|
||||
{
|
||||
auto specifier = vm.argument(0);
|
||||
auto export_name = vm.argument(1);
|
||||
|
||||
// 1. Let O be this value.
|
||||
// 2. Perform ? ValidateShadowRealmObject(O).
|
||||
auto object = TRY(typed_this_object(vm));
|
||||
|
||||
// 3. Let specifierString be ? ToString(specifier).
|
||||
auto specifier_string = TRY(specifier.to_utf16_string(vm));
|
||||
|
||||
// 4. If Type(exportName) is not String, throw a TypeError exception.
|
||||
if (!export_name.is_string())
|
||||
return vm.throw_completion<TypeError>(ErrorType::NotAString, export_name);
|
||||
|
||||
// 5. Let callerRealm be the current Realm Record.
|
||||
auto* caller_realm = vm.current_realm();
|
||||
|
||||
// 6. Let evalRealm be O.[[ShadowRealm]].
|
||||
auto& eval_realm = object->shadow_realm();
|
||||
|
||||
// 7. Return ShadowRealmImportValue(specifierString, exportName, callerRealm, evalRealm).
|
||||
return shadow_realm_import_value(vm, specifier_string, export_name.as_string().utf16_string(), *caller_realm, eval_realm);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,29 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2021, Linus Groh <linusg@serenityos.org>
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <LibJS/Runtime/PrototypeObject.h>
|
||||
#include <LibJS/Runtime/ShadowRealm.h>
|
||||
|
||||
namespace JS {
|
||||
|
||||
class ShadowRealmPrototype final : public PrototypeObject<ShadowRealmPrototype, ShadowRealm> {
|
||||
JS_PROTOTYPE_OBJECT(ShadowRealmPrototype, ShadowRealm, ShadowRealm);
|
||||
GC_DECLARE_ALLOCATOR(ShadowRealmPrototype);
|
||||
|
||||
public:
|
||||
virtual void initialize(Realm&) override;
|
||||
virtual ~ShadowRealmPrototype() override = default;
|
||||
|
||||
private:
|
||||
explicit ShadowRealmPrototype(Realm&);
|
||||
|
||||
JS_DECLARE_NATIVE_FUNCTION(evaluate);
|
||||
JS_DECLARE_NATIVE_FUNCTION(import_value);
|
||||
};
|
||||
|
||||
}
|
||||
@@ -215,18 +215,6 @@ VM::VM(ErrorMessages error_messages)
|
||||
return HandledByHost::Unhandled;
|
||||
};
|
||||
|
||||
// 3.6.1 HostInitializeShadowRealm ( realm, context, O ), https://tc39.es/proposal-shadowrealm/#sec-hostinitializeshadowrealm
|
||||
host_initialize_shadow_realm = [](Realm&, NonnullOwnPtr<ExecutionContext>, ShadowRealm&) -> ThrowCompletionOr<void> {
|
||||
// The host-defined abstract operation HostInitializeShadowRealm takes arguments realm (a Realm Record),
|
||||
// context (an execution context), and O (a ShadowRealm object) and returns either a normal completion
|
||||
// containing unused or a throw completion. It is used to inform the host of any newly created realms
|
||||
// from the ShadowRealm constructor. The idea of this hook is to initialize host data structures related
|
||||
// to the ShadowRealm, e.g., for module loading.
|
||||
//
|
||||
// The host may use this hook to add properties to the ShadowRealm's global object. Those properties must be configurable.
|
||||
return {};
|
||||
};
|
||||
|
||||
// 2.3.1 HostSystemUTCEpochNanoseconds ( global ), https://tc39.es/proposal-temporal/#sec-hostsystemutcepochnanoseconds
|
||||
host_system_utc_epoch_nanoseconds = [](Object const&) {
|
||||
// 1. Let ns be the approximate current UTC date and time, in nanoseconds since the epoch.
|
||||
|
||||
@@ -297,7 +297,6 @@ public:
|
||||
Function<ThrowCompletionOr<HandledByHost>(ArrayBuffer&, size_t)> host_resize_array_buffer;
|
||||
Function<ThrowCompletionOr<HandledByHost>(ArrayBuffer&, size_t)> host_grow_shared_array_buffer;
|
||||
Function<void(StringView)> host_unrecognized_date_string;
|
||||
Function<ThrowCompletionOr<void>(Realm&, NonnullOwnPtr<ExecutionContext>, ShadowRealm&)> host_initialize_shadow_realm;
|
||||
Function<Crypto::SignedBigInteger(Object const& global)> host_system_utc_epoch_nanoseconds;
|
||||
Function<bool()> host_promise_job_queue_is_empty;
|
||||
|
||||
|
||||
@@ -1,182 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2021-2022, Linus Groh <linusg@serenityos.org>
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
#include <LibJS/Runtime/AbstractOperations.h>
|
||||
#include <LibJS/Runtime/ShadowRealm.h>
|
||||
#include <LibJS/Runtime/WrappedFunction.h>
|
||||
|
||||
namespace JS {
|
||||
|
||||
GC_DEFINE_ALLOCATOR(WrappedFunction);
|
||||
|
||||
// 3.1.1 WrappedFunctionCreate ( callerRealm: a Realm Record, Target: a function object, ), https://tc39.es/proposal-shadowrealm/#sec-wrappedfunctioncreate
|
||||
ThrowCompletionOr<GC::Ref<WrappedFunction>> WrappedFunction::create(Realm& realm, Realm& caller_realm, FunctionObject& target)
|
||||
{
|
||||
auto& vm = realm.vm();
|
||||
|
||||
// 1. Let internalSlotsList be the internal slots listed in Table 2, plus [[Prototype]] and [[Extensible]].
|
||||
// 2. Let wrapped be MakeBasicObject(internalSlotsList).
|
||||
// 3. Set wrapped.[[Prototype]] to callerRealm.[[Intrinsics]].[[%Function.prototype%]].
|
||||
// 4. Set wrapped.[[Call]] as described in 2.1.
|
||||
// 5. Set wrapped.[[WrappedTargetFunction]] to Target.
|
||||
// 6. Set wrapped.[[Realm]] to callerRealm.
|
||||
auto& prototype = *caller_realm.intrinsics().function_prototype();
|
||||
auto wrapped = realm.create<WrappedFunction>(caller_realm, target, prototype);
|
||||
|
||||
// 7. Let result be CopyNameAndLength(wrapped, Target).
|
||||
auto result = copy_name_and_length(vm, *wrapped, target);
|
||||
|
||||
// 8. If result is an Abrupt Completion, throw a TypeError exception.
|
||||
if (result.is_throw_completion())
|
||||
return vm.throw_completion<TypeError>(ErrorType::WrappedFunctionCopyNameAndLengthThrowCompletion);
|
||||
|
||||
// 9. Return wrapped.
|
||||
return wrapped;
|
||||
}
|
||||
|
||||
// 2 Wrapped Function Exotic Objects, https://tc39.es/proposal-shadowrealm/#sec-wrapped-function-exotic-objects
|
||||
WrappedFunction::WrappedFunction(Realm& realm, FunctionObject& wrapped_target_function, Object& prototype)
|
||||
: FunctionObject(prototype)
|
||||
, m_wrapped_target_function(wrapped_target_function)
|
||||
, m_realm(realm)
|
||||
{
|
||||
}
|
||||
|
||||
void WrappedFunction::visit_edges(Visitor& visitor)
|
||||
{
|
||||
Base::visit_edges(visitor);
|
||||
|
||||
visitor.visit(m_wrapped_target_function);
|
||||
visitor.visit(m_realm);
|
||||
}
|
||||
|
||||
// 2.1 [[Call]] ( thisArgument, argumentsList ), https://tc39.es/proposal-shadowrealm/#sec-wrapped-function-exotic-objects-call-thisargument-argumentslist
|
||||
ThrowCompletionOr<Value> WrappedFunction::internal_call(ExecutionContext& callee_context, Value this_argument)
|
||||
{
|
||||
auto& vm = this->vm();
|
||||
|
||||
// 1. Let callerContext be the running execution context.
|
||||
// NOTE: No-op, kept by the VM in its execution context stack.
|
||||
|
||||
// 2. Let calleeContext be PrepareForWrappedFunctionCall(F).
|
||||
prepare_for_wrapped_function_call(*this, callee_context);
|
||||
|
||||
// 3. Assert: calleeContext is now the running execution context.
|
||||
VERIFY(&vm.running_execution_context() == &callee_context);
|
||||
|
||||
// 4. Let result be Completion(OrdinaryWrappedFunctionCall(F, thisArgument, argumentsList)).
|
||||
auto result = ordinary_wrapped_function_call(*this, this_argument, callee_context.arguments_span());
|
||||
|
||||
// 5. Remove calleeContext from the execution context stack and restore callerContext as the running execution context.
|
||||
vm.pop_execution_context();
|
||||
|
||||
// 6. Return ? result.
|
||||
return result;
|
||||
}
|
||||
|
||||
void WrappedFunction::get_stack_frame_info(size_t& registers_and_locals_count, ReadonlySpan<Value>& constants, size_t& argument_count)
|
||||
{
|
||||
m_wrapped_target_function->get_stack_frame_info(registers_and_locals_count, constants, argument_count);
|
||||
}
|
||||
|
||||
// 2.2 OrdinaryWrappedFunctionCall ( F: a wrapped function exotic object, thisArgument: an ECMAScript language value, argumentsList: a List of ECMAScript language values, ), https://tc39.es/proposal-shadowrealm/#sec-ordinary-wrapped-function-call
|
||||
ThrowCompletionOr<Value> ordinary_wrapped_function_call(WrappedFunction& function, Value this_argument, Span<Value> arguments_list)
|
||||
{
|
||||
auto& vm = function.vm();
|
||||
|
||||
// 1. Let target be F.[[WrappedTargetFunction]].
|
||||
auto& target = function.wrapped_target_function();
|
||||
|
||||
// 2. Assert: IsCallable(target) is true.
|
||||
VERIFY(Value(&target).is_function());
|
||||
|
||||
// 3. Let callerRealm be F.[[Realm]].
|
||||
auto* caller_realm = function.realm();
|
||||
|
||||
// 4. NOTE: Any exception objects produced after this point are associated with callerRealm.
|
||||
VERIFY(vm.current_realm() == caller_realm);
|
||||
|
||||
// 5. Let targetRealm be ? GetFunctionRealm(target).
|
||||
auto* target_realm = TRY(get_function_realm(vm, target));
|
||||
|
||||
// 6. Let wrappedArgs be a new empty List.
|
||||
auto wrapped_args = GC::RootVector<Value> { vm.heap() };
|
||||
wrapped_args.ensure_capacity(arguments_list.size());
|
||||
|
||||
// 7. For each element arg of argumentsList, do
|
||||
for (auto const& arg : arguments_list) {
|
||||
// a. Let wrappedValue be ? GetWrappedValue(targetRealm, arg).
|
||||
auto wrapped_value = TRY(get_wrapped_value(vm, *target_realm, arg));
|
||||
|
||||
// b. Append wrappedValue to wrappedArgs.
|
||||
wrapped_args.append(wrapped_value);
|
||||
}
|
||||
|
||||
// 8. Let wrappedThisArgument to ? GetWrappedValue(targetRealm, thisArgument).
|
||||
auto wrapped_this_argument = TRY(get_wrapped_value(vm, *target_realm, this_argument));
|
||||
|
||||
// 9. Let result be the Completion Record of Call(target, wrappedThisArgument, wrappedArgs).
|
||||
auto result = call(vm, &target, wrapped_this_argument, wrapped_args.span());
|
||||
|
||||
// 10. If result.[[Type]] is normal or result.[[Type]] is return, then
|
||||
if (!result.is_throw_completion()) {
|
||||
// a. Return ? GetWrappedValue(callerRealm, result.[[Value]]).
|
||||
return get_wrapped_value(vm, *caller_realm, result.value());
|
||||
}
|
||||
// 11. Else,
|
||||
else {
|
||||
// a. Throw a TypeError exception.
|
||||
return vm.throw_completion<TypeError>(ErrorType::WrappedFunctionCallThrowCompletion);
|
||||
}
|
||||
|
||||
// NOTE: Also see "Editor's Note" in the spec regarding the TypeError above.
|
||||
}
|
||||
|
||||
// 2.3 PrepareForWrappedFunctionCall ( F: a wrapped function exotic object, ), https://tc39.es/proposal-shadowrealm/#sec-prepare-for-wrapped-function-call
|
||||
void prepare_for_wrapped_function_call(WrappedFunction& function, ExecutionContext& callee_context)
|
||||
{
|
||||
auto& vm = function.vm();
|
||||
|
||||
// 1. Let callerContext be the running execution context.
|
||||
auto const& caller_context = vm.running_execution_context();
|
||||
|
||||
// 2. Let calleeContext be a new execution context.
|
||||
|
||||
// NOTE: In the specification, PrepareForWrappedFunctionCall "returns" a new callee execution context.
|
||||
// To avoid heap allocations, we put our ExecutionContext objects on the C++ stack instead.
|
||||
// Whoever calls us should put an ExecutionContext on their stack and pass that as the `callee_context`.
|
||||
|
||||
// 3. Set the Function of calleeContext to F.
|
||||
callee_context.function = &const_cast<WrappedFunction&>(function);
|
||||
|
||||
// 4. Let calleeRealm be F.[[Realm]].
|
||||
auto* callee_realm = function.realm();
|
||||
|
||||
// 5. Set the Realm of calleeContext to calleeRealm.
|
||||
callee_context.realm = callee_realm;
|
||||
|
||||
// 6. Set the ScriptOrModule of calleeContext to null.
|
||||
callee_context.script_or_module = {};
|
||||
|
||||
// 7. If callerContext is not already suspended, suspend callerContext.
|
||||
// NOTE: We don't support this concept yet.
|
||||
(void)caller_context;
|
||||
|
||||
// 8. Push calleeContext onto the execution context stack; calleeContext is now the running execution context.
|
||||
vm.push_execution_context(callee_context);
|
||||
|
||||
// 9. NOTE: Any exception objects produced after this point are associated with calleeRealm.
|
||||
|
||||
// 10. Return calleeContext.
|
||||
// NOTE: No-op, see NOTE after step 2.
|
||||
}
|
||||
|
||||
Utf16String WrappedFunction::name_for_call_stack() const
|
||||
{
|
||||
return "(Wrapped)"_utf16;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,47 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2021, Linus Groh <linusg@serenityos.org>
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <LibJS/Runtime/FunctionObject.h>
|
||||
#include <LibJS/Runtime/Realm.h>
|
||||
|
||||
namespace JS {
|
||||
|
||||
class WrappedFunction final : public FunctionObject {
|
||||
JS_OBJECT(WrappedFunction, FunctionObject);
|
||||
GC_DECLARE_ALLOCATOR(WrappedFunction);
|
||||
|
||||
public:
|
||||
static ThrowCompletionOr<GC::Ref<WrappedFunction>> create(Realm&, Realm& caller_realm, FunctionObject& target_function);
|
||||
|
||||
virtual ~WrappedFunction() = default;
|
||||
|
||||
virtual ThrowCompletionOr<Value> internal_call(ExecutionContext&, Value this_argument) override;
|
||||
|
||||
virtual Realm* realm() const override { return m_realm; }
|
||||
|
||||
FunctionObject const& wrapped_target_function() const { return m_wrapped_target_function; }
|
||||
FunctionObject& wrapped_target_function() { return m_wrapped_target_function; }
|
||||
|
||||
virtual void get_stack_frame_info(size_t& registers_and_locals_count, ReadonlySpan<Value>& constants, size_t& argument_count) override;
|
||||
|
||||
virtual Utf16String name_for_call_stack() const override;
|
||||
|
||||
private:
|
||||
WrappedFunction(Realm&, FunctionObject&, Object& prototype);
|
||||
|
||||
virtual void visit_edges(Visitor&) override;
|
||||
|
||||
// Internal Slots of Wrapped Function Exotic Objects, https://tc39.es/proposal-shadowrealm/#table-internal-slots-of-wrapped-function-exotic-objects
|
||||
GC::Ref<FunctionObject> m_wrapped_target_function; // [[WrappedTargetFunction]]
|
||||
GC::Ref<Realm> m_realm; // [[Realm]]
|
||||
};
|
||||
|
||||
ThrowCompletionOr<Value> ordinary_wrapped_function_call(WrappedFunction&, Value this_argument, Span<Value> arguments_list);
|
||||
void prepare_for_wrapped_function_call(WrappedFunction&, ExecutionContext& callee_context);
|
||||
|
||||
}
|
||||
@@ -443,32 +443,6 @@ Optional<Result<EvalResult, String>> compile_eval(
|
||||
return result;
|
||||
}
|
||||
|
||||
Optional<Result<EvalResult, String>> compile_shadow_realm_eval(
|
||||
PrimitiveString& source_text, VM& vm)
|
||||
{
|
||||
auto source_code = SourceCode::create({}, source_text.utf16_string());
|
||||
auto const& code_view = source_code->code_view();
|
||||
auto length = code_view.length_in_code_units();
|
||||
|
||||
GC::DeferGC defer_gc(vm.heap());
|
||||
EvalGdiBuilder builder;
|
||||
String parse_error;
|
||||
|
||||
auto const* source_ptr = source_code->utf16_data();
|
||||
|
||||
void* exec_ptr = rust_compile_eval(source_ptr, length, &vm, source_code.ptr(), &builder,
|
||||
false, false, false, false, false,
|
||||
&parse_error, collect_single_parse_error, nullptr, nullptr);
|
||||
|
||||
if (!exec_ptr)
|
||||
return parse_error;
|
||||
|
||||
builder.executable = static_cast<Bytecode::Executable*>(exec_ptr);
|
||||
builder.executable->name = "ShadowRealmEval"_utf16_fly_string;
|
||||
|
||||
return builder.to_result();
|
||||
}
|
||||
|
||||
Optional<Result<ModuleResult, Vector<ParserError>>> compile_parsed_module(ParsedProgram* parsed, NonnullRefPtr<SourceCode const> source_code, Realm& realm)
|
||||
{
|
||||
if (!parsed)
|
||||
|
||||
@@ -54,7 +54,7 @@ struct ScriptResult {
|
||||
Vector<Script::LexicalBinding> lexical_bindings;
|
||||
};
|
||||
|
||||
// Result type for compile_eval() and compile_shadow_realm_eval().
|
||||
// Result type for compile_eval().
|
||||
// NB: Uses GC::Root to prevent collection while the result is in transit.
|
||||
struct EvalResult {
|
||||
GC::Root<Bytecode::Executable> executable;
|
||||
@@ -110,11 +110,6 @@ Optional<Result<EvalResult, String>> compile_eval(
|
||||
CallerMode strict_caller, bool in_function, bool in_method,
|
||||
bool in_derived_constructor, bool in_class_field_initializer);
|
||||
|
||||
// Compile ShadowRealm eval code. Returns nullopt if Rust is not available.
|
||||
// On success, the executable's name is set to "ShadowRealmEval".
|
||||
Optional<Result<EvalResult, String>> compile_shadow_realm_eval(
|
||||
PrimitiveString& source_text, VM& vm);
|
||||
|
||||
// Compile a previously parsed module. Must be called on the main thread.
|
||||
// Consumes and frees the Rust ParsedProgram.
|
||||
// Returns nullopt if Rust is not available.
|
||||
|
||||
@@ -16,7 +16,6 @@
|
||||
#include <LibJS/Runtime/GlobalEnvironment.h>
|
||||
#include <LibJS/Runtime/ModuleRequest.h>
|
||||
#include <LibJS/Runtime/NativeFunction.h>
|
||||
#include <LibJS/Runtime/ShadowRealm.h>
|
||||
#include <LibJS/Runtime/VM.h>
|
||||
#include <LibJS/SourceTextModule.h>
|
||||
#include <LibWeb/Bindings/ExceptionOrUtils.h>
|
||||
@@ -43,7 +42,6 @@
|
||||
#include <LibWeb/HTML/Scripting/SyntheticRealmSettings.h>
|
||||
#include <LibWeb/HTML/Scripting/TemporaryExecutionContext.h>
|
||||
#include <LibWeb/HTML/Scripting/WorkerAgent.h>
|
||||
#include <LibWeb/HTML/ShadowRealmGlobalScope.h>
|
||||
#include <LibWeb/HTML/Window.h>
|
||||
#include <LibWeb/HTML/WindowProxy.h>
|
||||
#include <LibWeb/HTML/WorkletGlobalScope.h>
|
||||
@@ -646,45 +644,6 @@ void initialize_main_thread_vm(AgentType type)
|
||||
HTML::fetch_single_imported_module_script(*module_map_realm, url.release_value(), *fetch_client, destination, fetch_options, *module_map_realm, fetch_referrer, module_request, perform_fetch, on_single_fetch_complete);
|
||||
};
|
||||
|
||||
// https://whatpr.org/html/9893/webappapis.html#hostinitializeshadowrealm(realm,-context,-o)
|
||||
// 8.1.6.8 HostInitializeShadowRealm(realm, context, O)
|
||||
s_main_thread_vm->host_initialize_shadow_realm = [](JS::Realm& realm, NonnullOwnPtr<JS::ExecutionContext> context, JS::ShadowRealm& object) -> JS::ThrowCompletionOr<void> {
|
||||
// FIXME: 1. Set realm's is global prototype chain mutable to true.
|
||||
|
||||
// 2. Let globalObject be a new ShadowRealmGlobalScope object with realm.
|
||||
auto global_object = HTML::ShadowRealmGlobalScope::create(realm);
|
||||
|
||||
// 3. Let settings be a new synthetic realm settings object that this algorithm will subsequently initialize.
|
||||
auto settings = HTML::SyntheticRealmSettings {
|
||||
// 4. Set settings's execution context to context.
|
||||
.execution_context = move(context),
|
||||
|
||||
// 5. Set settings's principal realm to O's associated realm's principal realm
|
||||
.principal_realm = HTML::principal_realm(object.shape().realm()),
|
||||
|
||||
// 6. Set settings's module map to a new module map, initially empty.
|
||||
.module_map = realm.create<HTML::ModuleMap>(),
|
||||
};
|
||||
|
||||
// 7. Set realm.[[HostDefined]] to settings.
|
||||
realm.set_host_defined(make<Bindings::SyntheticHostDefined>(move(settings), realm.create<Bindings::Intrinsics>(realm)));
|
||||
|
||||
// 8. Set realm.[[GlobalObject]] to globalObject.
|
||||
realm.set_global_object(global_object);
|
||||
|
||||
// 9. Set realm.[[GlobalEnv]] to NewGlobalEnvironment(globalObject, globalObject).
|
||||
realm.set_global_environment(realm.heap().allocate<JS::GlobalEnvironment>(global_object, global_object));
|
||||
|
||||
// 10. Perform ? SetDefaultGlobalBindings(realm).
|
||||
set_default_global_bindings(realm);
|
||||
|
||||
// NOTE: This needs to be done after initialization so that the realm has an intrinsics in its [[HostDefined]]
|
||||
global_object->initialize_web_interfaces();
|
||||
|
||||
// 11. Return NormalCompletion(unused).
|
||||
return {};
|
||||
};
|
||||
|
||||
s_main_thread_vm->host_unrecognized_date_string = [](StringView date) {
|
||||
dbgln("Unable to parse date string: \"{}\"", date);
|
||||
};
|
||||
|
||||
@@ -670,7 +670,6 @@ set(SOURCES
|
||||
HTML/SerializedPolicyContainer.cpp
|
||||
HTML/SessionHistoryEntry.cpp
|
||||
HTML/SessionHistoryTraversalQueue.cpp
|
||||
HTML/ShadowRealmGlobalScope.cpp
|
||||
HTML/SharedResourceRequest.cpp
|
||||
HTML/AnimatedDecodedImageData.cpp
|
||||
HTML/SharedWorker.cpp
|
||||
|
||||
@@ -12,7 +12,6 @@
|
||||
#include <LibWeb/DOM/Document.h>
|
||||
#include <LibWeb/HTML/PolicyContainers.h>
|
||||
#include <LibWeb/HTML/Scripting/Environments.h>
|
||||
#include <LibWeb/HTML/ShadowRealmGlobalScope.h>
|
||||
#include <LibWeb/HTML/Window.h>
|
||||
#include <LibWeb/HTML/WorkerGlobalScope.h>
|
||||
|
||||
@@ -49,8 +48,7 @@ GC::Ptr<PolicyList> PolicyList::from_object(JS::Object& object)
|
||||
|
||||
// 2. If object is a Window or a WorkerGlobalScope or a WorkletGlobalScope, return environment settings object’s
|
||||
// policy container's CSP list.
|
||||
// FIXME: File a spec issue to make this look at ShadowRealmGlobalScope to support ShadowRealm.
|
||||
if (is<HTML::Window>(object) || is<HTML::WorkerGlobalScope>(object) || is<HTML::ShadowRealmGlobalScope>(object)) {
|
||||
if (is<HTML::Window>(object) || is<HTML::WorkerGlobalScope>(object)) {
|
||||
auto& settings = HTML::relevant_principal_settings_object(object);
|
||||
return settings.policy_container()->csp_list;
|
||||
}
|
||||
|
||||
@@ -98,7 +98,6 @@ URL::URL Violation::url() const
|
||||
return URL::URL {};
|
||||
}
|
||||
|
||||
// FIXME: File a spec issue about what to do for ShadowRealms here.
|
||||
auto& universal_scope = as<HTML::UniversalGlobalScopeMixin>(*m_global_object);
|
||||
auto& principal_global = HTML::relevant_principal_global_object(universal_scope.this_impl());
|
||||
|
||||
|
||||
@@ -1,43 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2024, Shannon Booth <shannon@serenityos.org>
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
#include <LibWeb/Bindings/ShadowRealmExposedInterfaces.h>
|
||||
#include <LibWeb/Bindings/ShadowRealmGlobalScopePrototype.h>
|
||||
#include <LibWeb/HTML/ShadowRealmGlobalScope.h>
|
||||
|
||||
namespace Web::HTML {
|
||||
|
||||
GC_DEFINE_ALLOCATOR(ShadowRealmGlobalScope);
|
||||
|
||||
ShadowRealmGlobalScope::ShadowRealmGlobalScope(JS::Realm& realm)
|
||||
: DOM::EventTarget(realm)
|
||||
{
|
||||
}
|
||||
|
||||
ShadowRealmGlobalScope::~ShadowRealmGlobalScope() = default;
|
||||
|
||||
GC::Ref<ShadowRealmGlobalScope> ShadowRealmGlobalScope::create(JS::Realm& realm)
|
||||
{
|
||||
return realm.create<ShadowRealmGlobalScope>(realm);
|
||||
}
|
||||
|
||||
void ShadowRealmGlobalScope::initialize_web_interfaces()
|
||||
{
|
||||
auto& realm = this->realm();
|
||||
|
||||
WEB_SET_PROTOTYPE_FOR_INTERFACE(ShadowRealmGlobalScope);
|
||||
|
||||
add_shadow_realm_exposed_interfaces(*this);
|
||||
Bindings::ShadowRealmGlobalScopeGlobalMixin::initialize(realm, *this);
|
||||
}
|
||||
|
||||
void ShadowRealmGlobalScope::visit_edges(Cell::Visitor& visitor)
|
||||
{
|
||||
Base::visit_edges(visitor);
|
||||
UniversalGlobalScopeMixin::visit_edges(visitor);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,54 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2024, Shannon Booth <shannon@serenityos.org>
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <LibWeb/Bindings/Intrinsics.h>
|
||||
#include <LibWeb/Bindings/ShadowRealmGlobalScopeGlobalMixin.h>
|
||||
#include <LibWeb/DOM/EventTarget.h>
|
||||
#include <LibWeb/HTML/UniversalGlobalScope.h>
|
||||
|
||||
namespace Web::HTML {
|
||||
|
||||
// https://whatpr.org/html/9893/webappapis.html#shadowrealmglobalscope
|
||||
class ShadowRealmGlobalScope
|
||||
: public DOM::EventTarget
|
||||
, public UniversalGlobalScopeMixin
|
||||
, public Bindings::ShadowRealmGlobalScopeGlobalMixin {
|
||||
WEB_PLATFORM_OBJECT(ShadowRealmGlobalScope, DOM::EventTarget);
|
||||
GC_DECLARE_ALLOCATOR(ShadowRealmGlobalScope);
|
||||
|
||||
public:
|
||||
virtual ~ShadowRealmGlobalScope() override;
|
||||
|
||||
static GC::Ref<ShadowRealmGlobalScope> create(JS::Realm&);
|
||||
|
||||
virtual DOM::EventTarget& this_impl() override { return *this; }
|
||||
virtual DOM::EventTarget const& this_impl() const override { return *this; }
|
||||
|
||||
// https://whatpr.org/html/9893/webappapis.html#dom-shadowrealmglobalscope-self
|
||||
GC::Ref<ShadowRealmGlobalScope> self()
|
||||
{
|
||||
// The self getter steps are to return this.
|
||||
return *this;
|
||||
}
|
||||
|
||||
using UniversalGlobalScopeMixin::atob;
|
||||
using UniversalGlobalScopeMixin::btoa;
|
||||
using UniversalGlobalScopeMixin::queue_microtask;
|
||||
using UniversalGlobalScopeMixin::structured_clone;
|
||||
|
||||
void initialize_web_interfaces();
|
||||
|
||||
protected:
|
||||
explicit ShadowRealmGlobalScope(JS::Realm&);
|
||||
|
||||
virtual bool is_universal_global_scope_mixin() const final { return true; }
|
||||
|
||||
virtual void visit_edges(Cell::Visitor&) override;
|
||||
};
|
||||
|
||||
}
|
||||
@@ -1,9 +0,0 @@
|
||||
#import <HTML/UniversalGlobalScope.idl>
|
||||
|
||||
// https://whatpr.org/html/9893/webappapis.html#shadowrealmglobalscope
|
||||
[Global, Exposed=ShadowRealm]
|
||||
interface ShadowRealmGlobalScope : EventTarget {
|
||||
readonly attribute ShadowRealmGlobalScope self;
|
||||
};
|
||||
|
||||
ShadowRealmGlobalScope includes UniversalGlobalScope;
|
||||
@@ -290,7 +290,6 @@ libweb_js_bindings(HTML/PluginArray)
|
||||
libweb_js_bindings(HTML/PopStateEvent)
|
||||
libweb_js_bindings(HTML/PromiseRejectionEvent)
|
||||
libweb_js_bindings(HTML/RadioNodeList)
|
||||
libweb_js_bindings(HTML/ShadowRealmGlobalScope GLOBAL)
|
||||
libweb_js_bindings(HTML/SharedWorker)
|
||||
libweb_js_bindings(HTML/SharedWorkerGlobalScope GLOBAL)
|
||||
libweb_js_bindings(HTML/Storage)
|
||||
|
||||
@@ -322,7 +322,6 @@ function (generate_js_bindings target)
|
||||
IntrinsicDefinitions.cpp IntrinsicDefinitions.h
|
||||
DedicatedWorkerExposedInterfaces.cpp DedicatedWorkerExposedInterfaces.h
|
||||
SharedWorkerExposedInterfaces.cpp SharedWorkerExposedInterfaces.h
|
||||
ShadowRealmExposedInterfaces.cpp ShadowRealmExposedInterfaces.h
|
||||
WindowExposedInterfaces.cpp WindowExposedInterfaces.h)
|
||||
list(TRANSFORM exposed_interface_sources PREPEND "Bindings/")
|
||||
set(LIBWEB_ALL_IDL_FILES_ARGUMENT ${LIBWEB_ALL_IDL_FILES})
|
||||
@@ -342,8 +341,6 @@ function (generate_js_bindings target)
|
||||
COMMAND "${CMAKE_COMMAND}" -E copy_if_different tmp/DedicatedWorkerExposedInterfaces.cpp "Bindings/DedicatedWorkerExposedInterfaces.cpp"
|
||||
COMMAND "${CMAKE_COMMAND}" -E copy_if_different tmp/SharedWorkerExposedInterfaces.h "Bindings/SharedWorkerExposedInterfaces.h"
|
||||
COMMAND "${CMAKE_COMMAND}" -E copy_if_different tmp/SharedWorkerExposedInterfaces.cpp "Bindings/SharedWorkerExposedInterfaces.cpp"
|
||||
COMMAND "${CMAKE_COMMAND}" -E copy_if_different tmp/ShadowRealmExposedInterfaces.h "Bindings/ShadowRealmExposedInterfaces.h"
|
||||
COMMAND "${CMAKE_COMMAND}" -E copy_if_different tmp/ShadowRealmExposedInterfaces.cpp "Bindings/ShadowRealmExposedInterfaces.cpp"
|
||||
COMMAND "${CMAKE_COMMAND}" -E copy_if_different tmp/WindowExposedInterfaces.h "Bindings/WindowExposedInterfaces.h"
|
||||
COMMAND "${CMAKE_COMMAND}" -E copy_if_different tmp/WindowExposedInterfaces.cpp "Bindings/WindowExposedInterfaces.cpp"
|
||||
COMMAND "${CMAKE_COMMAND}" -E remove_directory "${CMAKE_CURRENT_BINARY_DIR}/tmp"
|
||||
|
||||
@@ -21,7 +21,6 @@ struct InterfaceSets {
|
||||
Vector<IDL::Interface&> window_exposed;
|
||||
Vector<IDL::Interface&> dedicated_worker_exposed;
|
||||
Vector<IDL::Interface&> shared_worker_exposed;
|
||||
Vector<IDL::Interface&> shadow_realm_exposed;
|
||||
// TODO: service_worker_exposed
|
||||
};
|
||||
|
||||
@@ -131,8 +130,7 @@ static ErrorOr<void> generate_intrinsic_definitions_implementation(StringView ou
|
||||
#include <LibWeb/Export.h>
|
||||
#include <LibWeb/HTML/Window.h>
|
||||
#include <LibWeb/HTML/DedicatedWorkerGlobalScope.h>
|
||||
#include <LibWeb/HTML/SharedWorkerGlobalScope.h>
|
||||
#include <LibWeb/HTML/ShadowRealmGlobalScope.h>)~~~");
|
||||
#include <LibWeb/HTML/SharedWorkerGlobalScope.h>)~~~");
|
||||
|
||||
for (auto& interface : interface_sets.intrinsics) {
|
||||
auto gen = generator.fork();
|
||||
@@ -255,7 +253,6 @@ static constexpr bool is_@global_name@_exposed(InterfaceName name)
|
||||
generate_global_exposed("window"sv, interface_sets.window_exposed);
|
||||
generate_global_exposed("dedicated_worker"sv, interface_sets.dedicated_worker_exposed);
|
||||
generate_global_exposed("shared_worker"sv, interface_sets.shared_worker_exposed);
|
||||
generate_global_exposed("shadow_realm"sv, interface_sets.shadow_realm_exposed);
|
||||
|
||||
// https://webidl.spec.whatwg.org/#dfn-exposed
|
||||
generator.append(R"~~~(
|
||||
@@ -275,9 +272,6 @@ bool is_exposed(InterfaceName name, JS::Realm& realm)
|
||||
} else if (is<HTML::SharedWorkerGlobalScope>(global_object)) {
|
||||
if (!is_shared_worker_exposed(name))
|
||||
return false;
|
||||
} else if (is<HTML::ShadowRealmGlobalScope>(global_object)) {
|
||||
if (!is_shadow_realm_exposed(name))
|
||||
return false;
|
||||
} else {
|
||||
TODO(); // FIXME: ServiceWorkerGlobalScope and WorkletGlobalScope.
|
||||
}
|
||||
@@ -622,13 +616,11 @@ ErrorOr<int> ladybird_main(Main::Arguments arguments)
|
||||
TRY(generate_exposed_interface_header("Window"sv, output_path));
|
||||
TRY(generate_exposed_interface_header("DedicatedWorker"sv, output_path));
|
||||
TRY(generate_exposed_interface_header("SharedWorker"sv, output_path));
|
||||
TRY(generate_exposed_interface_header("ShadowRealm"sv, output_path));
|
||||
// TODO: ServiceWorkerExposed.h
|
||||
|
||||
TRY(generate_exposed_interface_implementation("Window"sv, output_path, interface_sets.window_exposed));
|
||||
TRY(generate_exposed_interface_implementation("DedicatedWorker"sv, output_path, interface_sets.dedicated_worker_exposed));
|
||||
TRY(generate_exposed_interface_implementation("SharedWorker"sv, output_path, interface_sets.shared_worker_exposed));
|
||||
TRY(generate_exposed_interface_implementation("ShadowRealm"sv, output_path, interface_sets.shadow_realm_exposed));
|
||||
// TODO: ServiceWorkerExposed.cpp
|
||||
|
||||
return 0;
|
||||
@@ -656,8 +648,5 @@ ErrorOr<void> add_to_interface_sets(IDL::Interface& interface, InterfaceSets& in
|
||||
if (has_flag(whom, IDL::ExposedTo::SharedWorker))
|
||||
interface_sets.shared_worker_exposed.append(interface);
|
||||
|
||||
if (has_flag(whom, IDL::ExposedTo::ShadowRealm))
|
||||
interface_sets.shadow_realm_exposed.append(interface);
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
@@ -207,9 +207,6 @@ shared_library("LibJS") {
|
||||
"Runtime/SetIterator.cpp",
|
||||
"Runtime/SetIteratorPrototype.cpp",
|
||||
"Runtime/SetPrototype.cpp",
|
||||
"Runtime/ShadowRealm.cpp",
|
||||
"Runtime/ShadowRealmConstructor.cpp",
|
||||
"Runtime/ShadowRealmPrototype.cpp",
|
||||
"Runtime/Shape.cpp",
|
||||
"Runtime/SharedArrayBufferConstructor.cpp",
|
||||
"Runtime/SharedArrayBufferPrototype.cpp",
|
||||
|
||||
@@ -132,8 +132,6 @@ describe("correct behavior", () => {
|
||||
new Proxy(function foo() {}, {}),
|
||||
// Bound function
|
||||
function foo() {}.bind(null),
|
||||
// Wrapped function
|
||||
new ShadowRealm().evaluate("function foo() {}; foo"),
|
||||
];
|
||||
for (const fn of values) {
|
||||
// Inner function name is not exposed
|
||||
|
||||
@@ -1,20 +0,0 @@
|
||||
describe("errors", () => {
|
||||
test("called without new", () => {
|
||||
expect(() => {
|
||||
ShadowRealm();
|
||||
}).toThrowWithMessage(TypeError, "ShadowRealm constructor must be called with 'new'");
|
||||
});
|
||||
});
|
||||
|
||||
describe("normal behavior", () => {
|
||||
test("length is 0", () => {
|
||||
expect(ShadowRealm).toHaveLength(0);
|
||||
});
|
||||
|
||||
test("basic functionality", () => {
|
||||
const shadowRealm = new ShadowRealm();
|
||||
expect(typeof shadowRealm).toBe("object");
|
||||
expect(shadowRealm).toBeInstanceOf(ShadowRealm);
|
||||
expect(Object.getPrototypeOf(shadowRealm)).toBe(ShadowRealm.prototype);
|
||||
});
|
||||
});
|
||||
@@ -1,3 +0,0 @@
|
||||
test("basic functionality", () => {
|
||||
expect(ShadowRealm.prototype[Symbol.toStringTag]).toBe("ShadowRealm");
|
||||
});
|
||||
@@ -1,138 +0,0 @@
|
||||
describe("normal behavior", () => {
|
||||
test("length is 1", () => {
|
||||
expect(ShadowRealm.prototype.evaluate).toHaveLength(1);
|
||||
});
|
||||
|
||||
test("basic functionality", () => {
|
||||
const shadowRealm = new ShadowRealm();
|
||||
expect(shadowRealm.evaluate("globalThis.foo = 'bar';")).toBe("bar");
|
||||
expect(shadowRealm.foo).toBeUndefined();
|
||||
expect(shadowRealm.evaluate("foo;")).toBe("bar");
|
||||
expect(shadowRealm.evaluate("foo;")).toBe("bar");
|
||||
});
|
||||
|
||||
test("global object initialization", () => {
|
||||
// Currently uses a plain JS::GlobalObject, i.e. no TestRunnerGlobalObject functions are available on the
|
||||
// shadow realm's global object. This may change in the future, update the test accordingly.
|
||||
const shadowRealm = new ShadowRealm();
|
||||
expect(shadowRealm.evaluate("globalThis.markAsGarbage")).toBeUndefined();
|
||||
});
|
||||
|
||||
test("strict mode behavior", () => {
|
||||
const shadowRealm = new ShadowRealm();
|
||||
|
||||
// sloppy mode
|
||||
expect(shadowRealm.evaluate("(function() { return !this; })()")).toBe(false);
|
||||
// strict mode
|
||||
expect(shadowRealm.evaluate("'use strict'; (function() { return !this; })()")).toBe(true);
|
||||
// Only the parsed script's strict mode changes the strictEval value used for EvalDeclarationInstantiation
|
||||
expect(
|
||||
(function () {
|
||||
"use strict";
|
||||
return shadowRealm.evaluate("(function() { return !this; })()");
|
||||
})()
|
||||
).toBe(false);
|
||||
});
|
||||
|
||||
test("wrapped function object", () => {
|
||||
const shadowRealm = new ShadowRealm();
|
||||
|
||||
const string = shadowRealm.evaluate("(function () { return 'foo'; })")();
|
||||
expect(string).toBe("foo");
|
||||
|
||||
const wrappedFunction = shadowRealm.evaluate("(function () { return 'foo'; })");
|
||||
expect(wrappedFunction()).toBe("foo");
|
||||
expect(typeof wrappedFunction).toBe("function");
|
||||
expect(Object.getPrototypeOf(wrappedFunction)).toBe(Function.prototype);
|
||||
|
||||
expect(shadowRealm.evaluate("(function () {})").name).toBe("");
|
||||
expect(shadowRealm.evaluate("(function foo() {})").name).toBe("foo");
|
||||
expect(shadowRealm.evaluate("(function () {})")).toHaveLength(0);
|
||||
expect(shadowRealm.evaluate("(function (foo, bar) {})")).toHaveLength(2);
|
||||
expect(
|
||||
shadowRealm.evaluate("Object.defineProperty(function () {}, 'length', { get() { return -Infinity } })")
|
||||
).toHaveLength(0);
|
||||
expect(
|
||||
shadowRealm.evaluate("Object.defineProperty(function () {}, 'length', { get() { return Infinity } })")
|
||||
).toHaveLength(Infinity);
|
||||
|
||||
for (const property of ["name", "length"]) {
|
||||
expect(() => {
|
||||
shadowRealm.evaluate(
|
||||
`
|
||||
function foo() {}
|
||||
Object.defineProperty(foo, "${property}", {
|
||||
get() { throw Error(); }
|
||||
});
|
||||
`
|
||||
);
|
||||
}).toThrowWithMessage(TypeError, "Trying to copy target name and length did not complete normally");
|
||||
}
|
||||
|
||||
expect(() => {
|
||||
shadowRealm.evaluate("(function () { throw Error(); })")();
|
||||
}).toThrowWithMessage(TypeError, "Call of wrapped target function did not complete normally");
|
||||
});
|
||||
});
|
||||
|
||||
describe("errors", () => {
|
||||
test("this value must be a ShadowRealm object", () => {
|
||||
expect(() => {
|
||||
ShadowRealm.prototype.evaluate.call("foo");
|
||||
}).toThrowWithMessage(TypeError, "Not an object of type ShadowRealm");
|
||||
});
|
||||
|
||||
test("throws for non-string input", () => {
|
||||
const shadowRealm = new ShadowRealm();
|
||||
const values = [
|
||||
[undefined, "undefined"],
|
||||
[42, "42"],
|
||||
[new String(), "[object StringObject]"],
|
||||
];
|
||||
for (const [value, errorString] of values) {
|
||||
expect(() => {
|
||||
shadowRealm.evaluate(value);
|
||||
}).toThrowWithMessage(TypeError, `${errorString} is not a string`);
|
||||
}
|
||||
});
|
||||
|
||||
test("throws if non-function object is returned from evaluation", () => {
|
||||
const shadowRealm = new ShadowRealm();
|
||||
const values = [
|
||||
["[]", "[object Array]"],
|
||||
["({})", "[object Object]"],
|
||||
["new String()", "[object StringObject]"],
|
||||
];
|
||||
for (const [value, errorString] of values) {
|
||||
expect(() => {
|
||||
shadowRealm.evaluate(value);
|
||||
}).toThrowWithMessage(
|
||||
TypeError,
|
||||
`Wrapped value must be primitive or a function object, got ${errorString}`
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
test("any exception is changed to a TypeError", () => {
|
||||
const shadowRealm = new ShadowRealm();
|
||||
expect(() => {
|
||||
shadowRealm.evaluate("(() => { throw 42; })()");
|
||||
}).toThrowWithMessage(TypeError, "The evaluated script did not complete normally");
|
||||
});
|
||||
|
||||
test("TypeError from revoked proxy is associated to caller realm", () => {
|
||||
const shadowRealm = new ShadowRealm();
|
||||
shadowRealm.evaluate("p = Proxy.revocable(() => {}, {}); undefined");
|
||||
const proxy = shadowRealm.evaluate("p.proxy");
|
||||
const revoke = shadowRealm.evaluate("p.revoke");
|
||||
const ShadowRealmTypeError = shadowRealm.evaluate("TypeError");
|
||||
revoke();
|
||||
try {
|
||||
proxy();
|
||||
expect.fail();
|
||||
} catch (e) {
|
||||
expect(e.constructor).toBe(TypeError);
|
||||
expect(e.constructor).not.toBe(ShadowRealmTypeError);
|
||||
}
|
||||
});
|
||||
});
|
||||
@@ -1,107 +0,0 @@
|
||||
describe("normal behavior", () => {
|
||||
test("length is 2", () => {
|
||||
expect(ShadowRealm.prototype.importValue).toHaveLength(2);
|
||||
});
|
||||
|
||||
test("fails if module cannot be loaded", () => {
|
||||
// NOTE: The actual import is currently not implemented and always pretends to fail for now.
|
||||
const shadowRealm = new ShadowRealm();
|
||||
const promise = shadowRealm.importValue("./file_should_not_exist.js", "foo");
|
||||
let error;
|
||||
promise.catch(value => {
|
||||
error = value;
|
||||
});
|
||||
expect(promise).toBeInstanceOf(Promise);
|
||||
runQueuedPromiseJobs();
|
||||
expect(error).toBeInstanceOf(TypeError);
|
||||
expect(error.message).toBe("Cannot find/open module: './file_should_not_exist.js'");
|
||||
});
|
||||
|
||||
test("basic functionality", () => {
|
||||
const shadowRealm = new ShadowRealm();
|
||||
const promise = shadowRealm.importValue("./external-module.mjs", "foo");
|
||||
expect(promise).toBeInstanceOf(Promise);
|
||||
let error = null;
|
||||
let passed = false;
|
||||
promise
|
||||
.then(value => {
|
||||
expect(value).toBe("Well hello shadows");
|
||||
expect(typeof value).toBe("string");
|
||||
|
||||
expect(value).not.toHaveProperty("default", null);
|
||||
expect(value).not.toHaveProperty("bar", null);
|
||||
passed = true;
|
||||
})
|
||||
.catch(value => {
|
||||
error = value;
|
||||
});
|
||||
runQueuedPromiseJobs();
|
||||
expect(error).toBeNull();
|
||||
expect(passed).toBeTrue();
|
||||
});
|
||||
|
||||
test("value from async module", () => {
|
||||
const shadowRealm = new ShadowRealm();
|
||||
const promise = shadowRealm.importValue("./async-module.mjs", "foo");
|
||||
expect(promise).toBeInstanceOf(Promise);
|
||||
let error = null;
|
||||
let passed = false;
|
||||
promise
|
||||
.then(value => {
|
||||
expect(value).toBe("Well hello async shadows");
|
||||
expect(typeof value).toBe("string");
|
||||
|
||||
expect(value).not.toHaveProperty("default", null);
|
||||
expect(value).not.toHaveProperty("bar", null);
|
||||
expect(value).not.toHaveProperty("baz", null);
|
||||
expect(value).not.toHaveProperty("qux", null);
|
||||
passed = true;
|
||||
})
|
||||
.catch(value => {
|
||||
error = value;
|
||||
});
|
||||
runQueuedPromiseJobs();
|
||||
expect(error).toBeNull();
|
||||
expect(passed).toBeTrue();
|
||||
});
|
||||
|
||||
test("value from async module from top-level awaited function", () => {
|
||||
const shadowRealm = new ShadowRealm();
|
||||
const promise = shadowRealm.importValue("./async-module.mjs", "qux");
|
||||
expect(promise).toBeInstanceOf(Promise);
|
||||
let error = null;
|
||||
let passed = false;
|
||||
promise
|
||||
.then(value => {
|
||||
expect(value).toBe("'qux' export");
|
||||
expect(typeof value).toBe("string");
|
||||
|
||||
expect(value).not.toHaveProperty("default", null);
|
||||
expect(value).not.toHaveProperty("foo", null);
|
||||
expect(value).not.toHaveProperty("bar", null);
|
||||
expect(value).not.toHaveProperty("baz", null);
|
||||
passed = true;
|
||||
})
|
||||
.catch(value => {
|
||||
error = value;
|
||||
});
|
||||
runQueuedPromiseJobs();
|
||||
expect(error).toBeNull();
|
||||
expect(passed).toBeTrue();
|
||||
});
|
||||
});
|
||||
|
||||
describe("errors", () => {
|
||||
test("this value must be a ShadowRealm object", () => {
|
||||
expect(() => {
|
||||
ShadowRealm.prototype.importValue.call("foo");
|
||||
}).toThrowWithMessage(TypeError, "Not an object of type ShadowRealm");
|
||||
});
|
||||
|
||||
test("export name must be string", () => {
|
||||
const shadowRealm = new ShadowRealm();
|
||||
expect(() => {
|
||||
shadowRealm.importValue("./whatever.mjs", 123);
|
||||
}).toThrowWithMessage(TypeError, "123 is not a string");
|
||||
});
|
||||
});
|
||||
@@ -169,7 +169,6 @@ Screenshot/input/css-background-blob-url.html
|
||||
Screenshot/input/font-variation-settings-applies-to-system-provided-font.html
|
||||
Screenshot/input/variable-font-weight.html
|
||||
Text/input/HTML/ModuleLoading/import-inside-of-a-module.html
|
||||
Text/input/HTML/ShadowRealm-importValue.html
|
||||
Text/input/HTML/pushState-navigation-event.html
|
||||
Text/input/HTML/storage-does-not-have-legacy-override-builtins-flag.html
|
||||
Text/input/Streams/init-from-cloned-fetch-response.html
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
My DOM Event
|
||||
@@ -1 +0,0 @@
|
||||
Well hello shadows
|
||||
@@ -1 +0,0 @@
|
||||
Some event...
|
||||
@@ -1 +0,0 @@
|
||||
Error: An error!
|
||||
@@ -1 +0,0 @@
|
||||
PASS: Exception thrown 'TypeError: Wrapped value must be primitive or a function object, got [object Promise]'
|
||||
@@ -1 +0,0 @@
|
||||
Shadow realm evaluation returned: SGVsbG8sIHdvcmxkIQ==
|
||||
@@ -1 +0,0 @@
|
||||
Shadow realm evaluation returned: 2
|
||||
@@ -1 +0,0 @@
|
||||
Shadow realm evaluation returned: example.com
|
||||
@@ -1,5 +1,2 @@
|
||||
CountQueuingStrategy | size1 === size2 -> true
|
||||
ByteLengthQueuingStrategy | size1 === size2 -> true
|
||||
|
||||
CountQueuingStrategy | size1 === size2 -> true
|
||||
ByteLengthQueuingStrategy | size1 === size2 -> true
|
||||
|
||||
@@ -461,7 +461,6 @@ ServiceWorker
|
||||
ServiceWorkerContainer
|
||||
ServiceWorkerRegistration
|
||||
Set
|
||||
ShadowRealm
|
||||
ShadowRoot
|
||||
SharedArrayBuffer
|
||||
SharedWorker
|
||||
|
||||
@@ -1,9 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<script src="../include.js"></script>
|
||||
<script>
|
||||
test(() => {
|
||||
const shadowRealm = new ShadowRealm();
|
||||
const result = shadowRealm.evaluate(`() => new Event("My DOM Event").type;`)();
|
||||
println(result);
|
||||
});
|
||||
</script>
|
||||
@@ -1,11 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<script src="../include.js"></script>
|
||||
<script>
|
||||
asyncTest(async done => {
|
||||
const shadowRealm = new ShadowRealm();
|
||||
const promise = shadowRealm.importValue("../../data/external-module.mjs", "foo");
|
||||
const value = await promise;
|
||||
println(value);
|
||||
done();
|
||||
});
|
||||
</script>
|
||||
@@ -1,42 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<script src="../include.js"></script>
|
||||
<script>
|
||||
function shadowRealmEvalAsync(realm, asyncBody) {
|
||||
return new Promise(realm.evaluate(`
|
||||
(resolve, reject) => {
|
||||
(async () => {
|
||||
${asyncBody}
|
||||
})().then(resolve, (e) => reject(e.toString()));
|
||||
}
|
||||
`));
|
||||
};
|
||||
|
||||
asyncTest(async done => {
|
||||
const outerShadowRealm = new ShadowRealm();
|
||||
|
||||
outerShadowRealm.evaluate(`
|
||||
var innerShadowRealm = new ShadowRealm();
|
||||
`);
|
||||
|
||||
const outerResult = await shadowRealmEvalAsync(outerShadowRealm, `
|
||||
function shadowRealmEvalAsync(realm, asyncBody) {
|
||||
return new Promise(realm.evaluate(\`
|
||||
(resolve, reject) => {
|
||||
(async () => {
|
||||
\${asyncBody}
|
||||
})().then(resolve, (e) => reject(e.toString()));
|
||||
}
|
||||
\`));
|
||||
};
|
||||
|
||||
const innerResult = await shadowRealmEvalAsync(innerShadowRealm, \`
|
||||
return new Event("Some event...").type;
|
||||
\`);
|
||||
|
||||
return innerResult;
|
||||
`);
|
||||
|
||||
println(outerResult);
|
||||
done();
|
||||
});
|
||||
</script>
|
||||
@@ -1,21 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<script src="../include.js"></script>
|
||||
<script>
|
||||
asyncTest(async done => {
|
||||
const shadowRealm = new ShadowRealm();
|
||||
|
||||
try {
|
||||
const result = await new Promise(shadowRealm.evaluate(`
|
||||
(resolve, reject) => {
|
||||
(async () => {
|
||||
throw new Error('An error!');
|
||||
})().then(resolve, (e) => reject(e.toString()));
|
||||
}
|
||||
`));
|
||||
} catch (e) {
|
||||
println(e);
|
||||
}
|
||||
|
||||
done();
|
||||
});
|
||||
</script>
|
||||
@@ -1,14 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<script src="../include.js"></script>
|
||||
<script>
|
||||
test(() => {
|
||||
const realm = new ShadowRealm()
|
||||
const aSync = realm.evaluate(`async () => 1 + 1`);
|
||||
try {
|
||||
aSync();
|
||||
println('Fail! No exception thrown');
|
||||
} catch (e) {
|
||||
println(`PASS: Exception thrown '${e}'`);
|
||||
}
|
||||
})
|
||||
</script>
|
||||
@@ -1,9 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<script src="../include.js"></script>
|
||||
<script>
|
||||
test(() => {
|
||||
const realm = new ShadowRealm();
|
||||
const result = realm.evaluate(`() => self.btoa('Hello, world!')`)();
|
||||
println(`Shadow realm evaluation returned: ${result}`);
|
||||
});
|
||||
</script>
|
||||
@@ -1,9 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<script src="../include.js"></script>
|
||||
<script>
|
||||
test(() => {
|
||||
const realm = new ShadowRealm();
|
||||
const result = realm.evaluate(`() => 1 + 1`)();
|
||||
println(`Shadow realm evaluation returned: ${result}`);
|
||||
});
|
||||
</script>
|
||||
@@ -1,9 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<script src="../include.js"></script>
|
||||
<script>
|
||||
test(() => {
|
||||
const realm = new ShadowRealm();
|
||||
const result = realm.evaluate(`() => new URL('https://example.com/path?name=value').hostname`)();
|
||||
println(`Shadow realm evaluation returned: ${result}`);
|
||||
});
|
||||
</script>
|
||||
@@ -2,21 +2,6 @@
|
||||
<script src="../include.js"></script>
|
||||
<script>
|
||||
test(() => {
|
||||
const realm = new ShadowRealm();
|
||||
const result = realm.evaluate(`
|
||||
(() => {
|
||||
let str = "";
|
||||
for (const QueuingStrategy of [CountQueuingStrategy, ByteLengthQueuingStrategy]) {
|
||||
const size1 = (new QueuingStrategy({ highWaterMark: 5 })).size;
|
||||
const size2 = (new QueuingStrategy({ highWaterMark: 10 })).size;
|
||||
str += \`\${QueuingStrategy.name} | size1 === size2 -> \${size1 === size2}\n\`;
|
||||
}
|
||||
return str;
|
||||
})()
|
||||
`);
|
||||
|
||||
println(result);
|
||||
|
||||
for (const QueuingStrategy of [CountQueuingStrategy, ByteLengthQueuingStrategy]) {
|
||||
const size1 = (new QueuingStrategy({ highWaterMark: 5 })).size;
|
||||
const size2 = (new QueuingStrategy({ highWaterMark: 10 })).size;
|
||||
|
||||
Reference in New Issue
Block a user