Переглянути джерело

LibJS: Implement import.meta for bytecode

Gabriel Dinner-David 2 роки тому
батько
коміт
d29bd55b48

+ 1 - 44
Userland/Libraries/LibJS/AST.cpp

@@ -3492,7 +3492,6 @@ Completion MetaProperty::execute(Interpreter& interpreter) const
 {
     InterpreterNodeScope node_scope { interpreter, *this };
     auto& vm = interpreter.vm();
-    auto& realm = *vm.current_realm();
 
     // NewTarget : new . target
     if (m_type == MetaProperty::Type::NewTarget) {
@@ -3502,49 +3501,7 @@ Completion MetaProperty::execute(Interpreter& interpreter) const
 
     // ImportMeta : import . meta
     if (m_type == MetaProperty::Type::ImportMeta) {
-        // 1. Let module be GetActiveScriptOrModule().
-        auto script_or_module = interpreter.vm().get_active_script_or_module();
-
-        // 2. Assert: module is a Source Text Module Record.
-        VERIFY(script_or_module.has<NonnullGCPtr<Module>>());
-        VERIFY(script_or_module.get<NonnullGCPtr<Module>>());
-        VERIFY(is<SourceTextModule>(*script_or_module.get<NonnullGCPtr<Module>>()));
-        auto& module = static_cast<SourceTextModule&>(*script_or_module.get<NonnullGCPtr<Module>>());
-
-        // 3. Let importMeta be module.[[ImportMeta]].
-        auto* import_meta = module.import_meta();
-
-        // 4. If importMeta is empty, then
-        if (import_meta == nullptr) {
-            // a. Set importMeta to OrdinaryObjectCreate(null).
-            import_meta = Object::create(realm, nullptr);
-
-            // b. Let importMetaValues be HostGetImportMetaProperties(module).
-            auto import_meta_values = interpreter.vm().host_get_import_meta_properties(module);
-
-            // c. For each Record { [[Key]], [[Value]] } p of importMetaValues, do
-            for (auto& entry : import_meta_values) {
-                // i. Perform ! CreateDataPropertyOrThrow(importMeta, p.[[Key]], p.[[Value]]).
-                MUST(import_meta->create_data_property_or_throw(entry.key, entry.value));
-            }
-
-            // d. Perform HostFinalizeImportMeta(importMeta, module).
-            interpreter.vm().host_finalize_import_meta(import_meta, module);
-
-            // e. Set module.[[ImportMeta]] to importMeta.
-            module.set_import_meta({}, import_meta);
-
-            // f. Return importMeta.
-            return Value { import_meta };
-        }
-        // 5. Else,
-        else {
-            // a. Assert: Type(importMeta) is Object.
-            // Note: This is always true by the type.
-
-            // b. Return importMeta.
-            return Value { import_meta };
-        }
+        return Value(vm.get_import_meta());
     }
 
     VERIFY_NOT_REACHED();

+ 2 - 4
Userland/Libraries/LibJS/Bytecode/ASTCodegen.cpp

@@ -2884,10 +2884,8 @@ Bytecode::CodeGenerationErrorOr<void> MetaProperty::generate_bytecode(Bytecode::
 
     // ImportMeta : import . meta
     if (m_type == MetaProperty::Type::ImportMeta) {
-        return Bytecode::CodeGenerationError {
-            this,
-            "Unimplemented meta property: import.meta"sv,
-        };
+        generator.emit<Bytecode::Op::GetImportMeta>();
+        return {};
     }
 
     VERIFY_NOT_REACHED();

+ 1 - 0
Userland/Libraries/LibJS/Bytecode/Instruction.h

@@ -42,6 +42,7 @@
     O(GetIterator)                   \
     O(GetMethod)                     \
     O(GetNewTarget)                  \
+    O(GetImportMeta)                 \
     O(GetObjectPropertyIterator)     \
     O(GetPrivateById)                \
     O(GetVariable)                   \

+ 12 - 0
Userland/Libraries/LibJS/Bytecode/Op.cpp

@@ -26,6 +26,7 @@
 #include <LibJS/Runtime/Reference.h>
 #include <LibJS/Runtime/RegExpObject.h>
 #include <LibJS/Runtime/Value.h>
+#include <LibJS/SourceTextModule.h>
 
 namespace JS::Bytecode {
 
@@ -762,6 +763,12 @@ ThrowCompletionOr<void> GetNewTarget::execute_impl(Bytecode::Interpreter& interp
     return {};
 }
 
+ThrowCompletionOr<void> GetImportMeta::execute_impl(Bytecode::Interpreter& interpreter) const
+{
+    interpreter.accumulator() = interpreter.vm().get_import_meta();
+    return {};
+}
+
 void Jump::replace_references_impl(BasicBlock const& from, BasicBlock const& to)
 {
     if (m_true_target.has_value() && &m_true_target->block() == &from)
@@ -1896,6 +1903,11 @@ DeprecatedString GetNewTarget::to_deprecated_string_impl(Bytecode::Executable co
     return "GetNewTarget"sv;
 }
 
+DeprecatedString GetImportMeta::to_deprecated_string_impl(Bytecode::Executable const&) const
+{
+    return "GetImportMeta"sv;
+}
+
 DeprecatedString TypeofVariable::to_deprecated_string_impl(Bytecode::Executable const& executable) const
 {
     return DeprecatedString::formatted("TypeofVariable {} ({})", m_identifier, executable.identifier_table->get(m_identifier));

+ 13 - 0
Userland/Libraries/LibJS/Bytecode/Op.h

@@ -1538,6 +1538,19 @@ public:
     void replace_references_impl(Register, Register) { }
 };
 
+class GetImportMeta final : public Instruction {
+public:
+    explicit GetImportMeta()
+        : Instruction(Type::GetImportMeta)
+    {
+    }
+
+    ThrowCompletionOr<void> execute_impl(Bytecode::Interpreter&) const;
+    DeprecatedString to_deprecated_string_impl(Bytecode::Executable const&) const;
+    void replace_references_impl(BasicBlock const&, BasicBlock const&) { }
+    void replace_references_impl(Register, Register) { }
+};
+
 class TypeofVariable final : public Instruction {
 public:
     explicit TypeofVariable(IdentifierTableIndex identifier)

+ 46 - 0
Userland/Libraries/LibJS/Runtime/VM.cpp

@@ -682,6 +682,52 @@ Value VM::get_new_target()
     return verify_cast<FunctionEnvironment>(*env).new_target();
 }
 
+// 13.3.12.1 Runtime Semantics: Evaluation, https://tc39.es/ecma262/#sec-meta-properties-runtime-semantics-evaluation
+// ImportMeta branch only
+Object* VM::get_import_meta()
+{
+    // 1. Let module be GetActiveScriptOrModule().
+    auto script_or_module = get_active_script_or_module();
+
+    // 2. Assert: module is a Source Text Module Record.
+    auto& module = verify_cast<SourceTextModule>(*script_or_module.get<NonnullGCPtr<Module>>());
+
+    // 3. Let importMeta be module.[[ImportMeta]].
+    auto* import_meta = module.import_meta();
+
+    // 4. If importMeta is empty, then
+    if (import_meta == nullptr) {
+        // a. Set importMeta to OrdinaryObjectCreate(null).
+        import_meta = Object::create(*current_realm(), nullptr);
+
+        // b. Let importMetaValues be HostGetImportMetaProperties(module).
+        auto import_meta_values = host_get_import_meta_properties(module);
+
+        // c. For each Record { [[Key]], [[Value]] } p of importMetaValues, do
+        for (auto& entry : import_meta_values) {
+            // i. Perform ! CreateDataPropertyOrThrow(importMeta, p.[[Key]], p.[[Value]]).
+            MUST(import_meta->create_data_property_or_throw(entry.key, entry.value));
+        }
+
+        // d. Perform HostFinalizeImportMeta(importMeta, module).
+        host_finalize_import_meta(import_meta, module);
+
+        // e. Set module.[[ImportMeta]] to importMeta.
+        module.set_import_meta({}, import_meta);
+
+        // f. Return importMeta.
+        return import_meta;
+    }
+    // 5. Else,
+    else {
+        // a. Assert: Type(importMeta) is Object.
+        // Note: This is always true by the type.
+
+        // b. Return importMeta.
+        return import_meta;
+    }
+}
+
 // 9.4.5 GetGlobalObject ( ), https://tc39.es/ecma262/#sec-getglobalobject
 Object& VM::get_global_object()
 {

+ 2 - 0
Userland/Libraries/LibJS/Runtime/VM.h

@@ -219,6 +219,8 @@ public:
 
     Value get_new_target();
 
+    Object* get_import_meta();
+
     Object& get_global_object();
 
     CommonPropertyNames names;

+ 1 - 1
Userland/Libraries/LibJS/SourceTextModule.h

@@ -26,7 +26,7 @@ public:
     virtual ThrowCompletionOr<ResolvedBinding> resolve_export(VM& vm, DeprecatedFlyString const& export_name, Vector<ResolvedBinding> resolve_set = {}) override;
 
     Object* import_meta() { return m_import_meta; }
-    void set_import_meta(Badge<MetaProperty>, Object* import_meta) { m_import_meta = import_meta; }
+    void set_import_meta(Badge<VM>, Object* import_meta) { m_import_meta = import_meta; }
 
 protected:
     virtual ThrowCompletionOr<void> initialize_environment(VM& vm) override;