Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

LibWeb: ShadowRealms part 4 - enough for it to not crash #1993

Merged
merged 5 commits into from
Nov 5, 2024
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
PASS: Exception thrown 'TypeError: Wrapped value must be primitive or a function object, got [object Promise]'
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Shadow realm evaluation returned: 2
13 changes: 13 additions & 0 deletions Tests/LibWeb/Text/input/HTML/shadow-realm-async-evaluate.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<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>
8 changes: 8 additions & 0 deletions Tests/LibWeb/Text/input/HTML/shadow-realm-sync-evaluate.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
<script src="../include.js"></script>
<script>
test(() => {
const realm = new ShadowRealm();
const result = realm.evaluate(`() => 1 + 1`)();
println(`Shadow realm evaluation returned: ${result}`);
});
</script>
3 changes: 3 additions & 0 deletions Userland/Libraries/LibJS/Runtime/Realm.h
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,10 @@ class Realm final : public Cell {
static ThrowCompletionOr<NonnullOwnPtr<ExecutionContext>> initialize_host_defined_realm(VM&, Function<Object*(Realm&)> create_global_object, Function<Object*(Realm&)> create_global_this_value);

[[nodiscard]] Object& global_object() const { return *m_global_object; }
void set_global_object(NonnullGCPtr<Object> global) { m_global_object = global; }

[[nodiscard]] GlobalEnvironment& global_environment() const { return *m_global_environment; }
void set_global_environment(NonnullGCPtr<GlobalEnvironment> environment) { m_global_environment = environment; }

[[nodiscard]] Intrinsics const& intrinsics() const { return *m_intrinsics; }
[[nodiscard]] Intrinsics& intrinsics() { return *m_intrinsics; }
Expand Down
44 changes: 44 additions & 0 deletions Userland/Libraries/LibWeb/Bindings/MainThreadVM.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,16 @@
#include <LibJS/Runtime/Array.h>
#include <LibJS/Runtime/Environment.h>
#include <LibJS/Runtime/FinalizationRegistry.h>
#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>
#include <LibWeb/Bindings/Intrinsics.h>
#include <LibWeb/Bindings/MainThreadVM.h>
#include <LibWeb/Bindings/SyntheticHostDefined.h>
#include <LibWeb/Bindings/WindowExposedInterfaces.h>
#include <LibWeb/DOM/Document.h>
#include <LibWeb/DOM/MutationType.h>
Expand All @@ -35,7 +38,9 @@
#include <LibWeb/HTML/Scripting/Fetching.h>
#include <LibWeb/HTML/Scripting/ModuleScript.h>
#include <LibWeb/HTML/Scripting/Script.h>
#include <LibWeb/HTML/Scripting/SyntheticRealmSettings.h>
#include <LibWeb/HTML/Scripting/TemporaryExecutionContext.h>
#include <LibWeb/HTML/ShadowRealmGlobalScope.h>
#include <LibWeb/HTML/TagNames.h>
#include <LibWeb/HTML/Window.h>
#include <LibWeb/HTML/WindowProxy.h>
Expand Down Expand Up @@ -560,6 +565,45 @@ ErrorOr<void> initialize_main_thread_vm(HTML::EventLoop::Type 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
.principal_realm = object.shape().realm(),

// 6. Set settings's underlying realm to realm.
.underlying_realm = realm,

// 7. Set settings's module map to a new module map, initially empty.
.module_map = realm.heap().allocate<HTML::ModuleMap>(realm),
};

// 8. Set realm.[[HostDefined]] to settings.
realm.set_host_defined(make<Bindings::SyntheticHostDefined>(move(settings)));

// 9. Set realm.[[GlobalObject]] to globalObject.
realm.set_global_object(global_object);

// 10. Set realm.[[GlobalEnv]] to NewGlobalEnvironment(globalObject, globalObject).
realm.set_global_environment(realm.vm().heap().allocate_without_realm<JS::GlobalEnvironment>(global_object, global_object));

// 11. Perform ? SetDefaultGlobalBindings(realm).
set_default_global_bindings(realm);

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we should call ShadowRealmGlobalScopeGlobalMixin::initialize(realm, *this); here, as well as add_shadow_realm_exposed_interfaces(*this) (in a helper on the global scope/global object variable)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

speaking of which, did the spec folks decide what things should be exposed to shadow realms? We'll need to go around sprinkling annotations all over our idl files for the idl generator to pick them up

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, spec folks have done so - those are all of the crashing IDL tests that we have currently. Here's a meta issue that shows what has been done: tc39/proposal-shadowrealm#393

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Well, not crashing after these changes, but still doesn't work :D

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ah perfect, then it should be straightforward to add ShadowRealm as an option in GenerateWindowOrWorkerInterfaces ... which I guess should be renamed to GenerateGlobalExposedInterfaces or some such.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Right, yeah that's why I've left those other FIXME's you mentioned in the initialize steps. I need to implement that universal global scope and reshuffling some implementations from windoworworkerglobal scope mixin to a new universalglobalscope mixin

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

gotcha. well, given that, I think we're good to go on this part once CI is happy. Feel free to add more fixmes if you want though.

// 12. Return NormalCompletion(unused).
return {};
};

s_main_thread_vm->host_unrecognized_date_string = [](StringView date) {
dbgln("Unable to parse date string: \"{}\"", date);
};
Expand Down
Loading