Sfoglia il codice sorgente

LibJS: Don't create lexical environment for native (C++) function calls

This was creating a ton of pointless busywork for the garbage collector
and can be avoided simply by tolerating that the current call frame has
a null scope object for the duration of a NativeFunction activation.
Andreas Kling 4 anni fa
parent
commit
d69cd3f5bf

+ 1 - 2
Userland/Libraries/LibJS/Runtime/NativeFunction.cpp

@@ -5,7 +5,6 @@
  */
  */
 
 
 #include <LibJS/Runtime/GlobalObject.h>
 #include <LibJS/Runtime/GlobalObject.h>
-#include <LibJS/Runtime/LexicalEnvironment.h>
 #include <LibJS/Runtime/NativeFunction.h>
 #include <LibJS/Runtime/NativeFunction.h>
 #include <LibJS/Runtime/Value.h>
 #include <LibJS/Runtime/Value.h>
 
 
@@ -50,7 +49,7 @@ Value NativeFunction::construct(Function&)
 
 
 LexicalEnvironment* NativeFunction::create_environment()
 LexicalEnvironment* NativeFunction::create_environment()
 {
 {
-    return heap().allocate<LexicalEnvironment>(global_object(), LexicalEnvironment::EnvironmentRecordType::Function);
+    return nullptr;
 }
 }
 
 
 bool NativeFunction::is_strict_mode() const
 bool NativeFunction::is_strict_mode() const

+ 15 - 7
Userland/Libraries/LibJS/Runtime/VM.cpp

@@ -399,12 +399,14 @@ Value VM::construct(Function& function, Function& new_target, Optional<MarkedVal
         call_frame.arguments.append(arguments.value().values());
         call_frame.arguments.append(arguments.value().values());
     auto* environment = function.create_environment();
     auto* environment = function.create_environment();
     call_frame.scope = environment;
     call_frame.scope = environment;
-    environment->set_new_target(&new_target);
+    if (environment)
+        environment->set_new_target(&new_target);
 
 
     Object* new_object = nullptr;
     Object* new_object = nullptr;
     if (function.constructor_kind() == Function::ConstructorKind::Base) {
     if (function.constructor_kind() == Function::ConstructorKind::Base) {
         new_object = Object::create_empty(global_object);
         new_object = Object::create_empty(global_object);
-        environment->bind_this_value(global_object, new_object);
+        if (environment)
+            environment->bind_this_value(global_object, new_object);
         if (exception())
         if (exception())
             return {};
             return {};
         auto prototype = new_target.get(names.prototype);
         auto prototype = new_target.get(names.prototype);
@@ -422,15 +424,18 @@ Value VM::construct(Function& function, Function& new_target, Optional<MarkedVal
     call_frame.this_value = this_value;
     call_frame.this_value = this_value;
     auto result = function.construct(new_target);
     auto result = function.construct(new_target);
 
 
-    this_value = call_frame.scope->get_this_binding(global_object);
+    if (environment)
+        this_value = environment->get_this_binding(global_object);
     pop_call_frame();
     pop_call_frame();
     call_frame_popper.disarm();
     call_frame_popper.disarm();
 
 
     // If we are constructing an instance of a derived class,
     // If we are constructing an instance of a derived class,
     // set the prototype on objects created by constructors that return an object (i.e. NativeFunction subclasses).
     // set the prototype on objects created by constructors that return an object (i.e. NativeFunction subclasses).
     if (function.constructor_kind() == Function::ConstructorKind::Base && new_target.constructor_kind() == Function::ConstructorKind::Derived && result.is_object()) {
     if (function.constructor_kind() == Function::ConstructorKind::Base && new_target.constructor_kind() == Function::ConstructorKind::Derived && result.is_object()) {
-        VERIFY(is<LexicalEnvironment>(current_scope()));
-        static_cast<LexicalEnvironment*>(current_scope())->replace_this_binding(result);
+        if (environment) {
+            VERIFY(is<LexicalEnvironment>(current_scope()));
+            static_cast<LexicalEnvironment*>(current_scope())->replace_this_binding(result);
+        }
         auto prototype = new_target.get(names.prototype);
         auto prototype = new_target.get(names.prototype);
         if (exception())
         if (exception())
             return {};
             return {};
@@ -507,8 +512,11 @@ Value VM::call_internal(Function& function, Value this_value, Optional<MarkedVal
     auto* environment = function.create_environment();
     auto* environment = function.create_environment();
     call_frame.scope = environment;
     call_frame.scope = environment;
 
 
-    VERIFY(environment->this_binding_status() == LexicalEnvironment::ThisBindingStatus::Uninitialized);
-    environment->bind_this_value(function.global_object(), call_frame.this_value);
+    if (environment) {
+        VERIFY(environment->this_binding_status() == LexicalEnvironment::ThisBindingStatus::Uninitialized);
+        environment->bind_this_value(function.global_object(), call_frame.this_value);
+    }
+
     if (exception())
     if (exception())
         return {};
         return {};