Browse Source

LibJS: Perform function instantiation in bytecode

This replaces Bytecode::Op::EnterScope with a new NewFunction op that
instantiates a ScriptFunction from a given FunctionNode (AST).

This is then used to instantiate the local functions directly from
bytecode when entering a ScopeNode. :^)
Andreas Kling 4 năm trước cách đây
mục cha
commit
b3e6a6c1cd

+ 5 - 1
Userland/Libraries/LibJS/Bytecode/ASTCodegen.cpp

@@ -22,7 +22,11 @@ void ASTNode::generate_bytecode(Bytecode::Generator&) const
 
 void ScopeNode::generate_bytecode(Bytecode::Generator& generator) const
 {
-    generator.emit<Bytecode::Op::EnterScope>(*this);
+    for (auto& function : functions()) {
+        generator.emit<Bytecode::Op::NewFunction>(function);
+        generator.emit<Bytecode::Op::SetVariable>(generator.intern_string(function.name()));
+    }
+
     for (auto& child : children()) {
         child.generate_bytecode(generator);
         if (generator.is_current_block_terminated())

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

@@ -39,7 +39,7 @@
     O(JumpConditional)            \
     O(JumpNullish)                \
     O(Call)                       \
-    O(EnterScope)                 \
+    O(NewFunction)                \
     O(Return)                     \
     O(BitwiseAnd)                 \
     O(BitwiseOr)                  \

+ 4 - 14
Userland/Libraries/LibJS/Bytecode/Op.cpp

@@ -210,21 +210,11 @@ void Call::execute(Bytecode::Interpreter& interpreter) const
     interpreter.accumulator() = return_value;
 }
 
-void EnterScope::execute(Bytecode::Interpreter& interpreter) const
+void NewFunction::execute(Bytecode::Interpreter& interpreter) const
 {
     auto& vm = interpreter.vm();
     auto& global_object = interpreter.global_object();
-
-    for (auto& declaration : m_scope_node.functions())
-        vm.current_scope()->put_to_scope(declaration.name(), { js_undefined(), DeclarationKind::Var });
-
-    for (auto& declaration : m_scope_node.functions()) {
-        auto* function = ScriptFunction::create(global_object, declaration.name(), declaration.body(), declaration.parameters(), declaration.function_length(), vm.current_scope(), declaration.is_strict_mode());
-        vm.set_variable(declaration.name(), function, global_object);
-    }
-
-    // FIXME: Process variable declarations.
-    // FIXME: Whatever else JS::Interpreter::enter_scope() does.
+    interpreter.accumulator() = ScriptFunction::create(global_object, m_function_node.name(), m_function_node.body(), m_function_node.parameters(), m_function_node.function_length(), vm.current_scope(), m_function_node.is_strict_mode());
 }
 
 void Return::execute(Bytecode::Interpreter& interpreter) const
@@ -384,9 +374,9 @@ String Call::to_string(Bytecode::Executable const&) const
     return builder.to_string();
 }
 
-String EnterScope::to_string(Bytecode::Executable const&) const
+String NewFunction::to_string(Bytecode::Executable const&) const
 {
-    return "EnterScope";
+    return "NewFunction";
 }
 
 String Return::to_string(Bytecode::Executable const&) const

+ 5 - 5
Userland/Libraries/LibJS/Bytecode/Op.h

@@ -346,11 +346,11 @@ private:
     Register m_arguments[];
 };
 
-class EnterScope final : public Instruction {
+class NewFunction final : public Instruction {
 public:
-    explicit EnterScope(ScopeNode const& scope_node)
-        : Instruction(Type::EnterScope)
-        , m_scope_node(scope_node)
+    explicit NewFunction(FunctionNode const& function_node)
+        : Instruction(Type::NewFunction)
+        , m_function_node(function_node)
     {
     }
 
@@ -358,7 +358,7 @@ public:
     String to_string(Bytecode::Executable const&) const;
 
 private:
-    ScopeNode const& m_scope_node;
+    FunctionNode const& m_function_node;
 };
 
 class Return final : public Instruction {

+ 1 - 0
Userland/Libraries/LibJS/Forward.h

@@ -114,6 +114,7 @@ class Error;
 class ErrorType;
 class Exception;
 class Expression;
+class FunctionNode;
 class Accessor;
 class GlobalObject;
 class HandleImpl;