From cbbf4abb0dbb70c527e2638c6801f5d1b585b4db Mon Sep 17 00:00:00 2001 From: Linus Groh Date: Thu, 14 Oct 2021 12:04:10 +0100 Subject: [PATCH] LibJS: Add a way to get from a GlobalObject to its associated Realm This is just another workaround, but it should be much more reliable than Interpreter::realm(), especially when allocating NativeFunctions and ECMAScriptFunctionObjects: we're guaranteed to have a GlobalObject at that point, and it likely was set as the GlobalObject of a Realm and can lead us back to it. We're however not guaranteed that the VM can give us an Interpreter, which is why functions in LibWeb can be a bit crashy at the moment. We use a WeakPtr to properly handle the unlikely case where the Realm goes away after associating a GlobalObject to it. We'll always need _something_ of this sort if we want to support OrdinaryFunctionCreate and CreateBuiltinFunction without the explicit realm argument while no JS is running, because they want to use the current Realm Record (always in the first and as fallback in the second case). --- Userland/Libraries/LibJS/Runtime/GlobalObject.cpp | 11 +++++++++++ Userland/Libraries/LibJS/Runtime/GlobalObject.h | 5 +++++ Userland/Libraries/LibJS/Runtime/Realm.cpp | 3 +++ Userland/Libraries/LibJS/Runtime/Realm.h | 5 ++++- 4 files changed, 23 insertions(+), 1 deletion(-) diff --git a/Userland/Libraries/LibJS/Runtime/GlobalObject.cpp b/Userland/Libraries/LibJS/Runtime/GlobalObject.cpp index 48ed9b3c8d..a133fac961 100644 --- a/Userland/Libraries/LibJS/Runtime/GlobalObject.cpp +++ b/Userland/Libraries/LibJS/Runtime/GlobalObject.cpp @@ -65,6 +65,7 @@ #include #include #include +#include #include #include #include @@ -318,6 +319,16 @@ void GlobalObject::visit_edges(Visitor& visitor) #undef __JS_ENUMERATE } +Realm* GlobalObject::associated_realm() +{ + return m_associated_realm; +} + +void GlobalObject::set_associated_realm(Badge, Realm& realm) +{ + m_associated_realm = &realm; +} + JS_DEFINE_NATIVE_FUNCTION(GlobalObject::gc) { #ifdef __serenity__ diff --git a/Userland/Libraries/LibJS/Runtime/GlobalObject.h b/Userland/Libraries/LibJS/Runtime/GlobalObject.h index 321fd3aeed..32387a0eef 100644 --- a/Userland/Libraries/LibJS/Runtime/GlobalObject.h +++ b/Userland/Libraries/LibJS/Runtime/GlobalObject.h @@ -23,6 +23,9 @@ public: Console& console() { return *m_console; } + Realm* associated_realm(); + void set_associated_realm(Badge, Realm&); + Shape* empty_object_shape() { return m_empty_object_shape; } Shape* new_object_shape() { return m_new_object_shape; } @@ -88,6 +91,8 @@ private: NonnullOwnPtr m_console; + WeakPtr m_associated_realm; + Shape* m_empty_object_shape { nullptr }; Shape* m_new_object_shape { nullptr }; Shape* m_new_ordinary_function_prototype_object_shape { nullptr }; diff --git a/Userland/Libraries/LibJS/Runtime/Realm.cpp b/Userland/Libraries/LibJS/Runtime/Realm.cpp index 1082f0804f..eb324077be 100644 --- a/Userland/Libraries/LibJS/Runtime/Realm.cpp +++ b/Userland/Libraries/LibJS/Runtime/Realm.cpp @@ -14,6 +14,9 @@ void Realm::set_global_object(GlobalObject& global_object, Object* this_value) // NOTE: Step 1 is not supported, the global object must be allocated elsewhere. // 2. Assert: Type(globalObj) is Object. + // Non-standard + global_object.set_associated_realm({}, *this); + // 3. If thisValue is undefined, set thisValue to globalObj. if (!this_value) this_value = &global_object; diff --git a/Userland/Libraries/LibJS/Runtime/Realm.h b/Userland/Libraries/LibJS/Runtime/Realm.h index bd4d25d5e2..3c3820433a 100644 --- a/Userland/Libraries/LibJS/Runtime/Realm.h +++ b/Userland/Libraries/LibJS/Runtime/Realm.h @@ -6,6 +6,7 @@ #pragma once +#include #include #include #include @@ -13,7 +14,9 @@ namespace JS { // 9.3 Realms, https://tc39.es/ecma262/#realm-record -class Realm final : public Cell { +class Realm final + : public Cell + , public Weakable { public: Realm() = default;