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

LibJS: Pass prototype to Function constructors

Andreas Kling 5 роки тому
батько
коміт
f6d57c82f6

+ 2 - 2
Libraries/LibJS/AST.cpp

@@ -48,14 +48,14 @@ Value ScopeNode::execute(Interpreter& interpreter) const
 
 Value FunctionDeclaration::execute(Interpreter& interpreter) const
 {
-    auto* function = interpreter.heap().allocate<ScriptFunction>(name(), body(), parameters(), interpreter.current_environment());
+    auto* function = ScriptFunction::create(interpreter.global_object(), name(), body(), parameters(), interpreter.current_environment());
     interpreter.set_variable(name(), function);
     return js_undefined();
 }
 
 Value FunctionExpression::execute(Interpreter& interpreter) const
 {
-    return interpreter.heap().allocate<ScriptFunction>(name(), body(), parameters(), interpreter.current_environment());
+    return ScriptFunction::create(interpreter.global_object(), name(), body(), parameters(), interpreter.current_environment());
 }
 
 Value ExpressionStatement::execute(Interpreter& interpreter) const

+ 3 - 0
Libraries/LibJS/Interpreter.cpp

@@ -54,6 +54,9 @@ Interpreter::Interpreter()
     m_object_prototype = heap().allocate<ObjectPrototype>();
     m_function_prototype = heap().allocate<FunctionPrototype>();
 
+    static_cast<FunctionPrototype*>(m_function_prototype)->initialize();
+    static_cast<ObjectPrototype*>(m_object_prototype)->initialize();
+
 #define __JS_ENUMERATE(ClassName, snake_name, PrototypeName, ConstructorName) \
     if (!m_##snake_name##_prototype)                                          \
         m_##snake_name##_prototype = heap().allocate<PrototypeName>();

+ 1 - 1
Libraries/LibJS/Runtime/ArrayConstructor.cpp

@@ -34,7 +34,7 @@
 namespace JS {
 
 ArrayConstructor::ArrayConstructor()
-    : NativeFunction("Array")
+    : NativeFunction("Array", *interpreter().function_prototype())
 {
     put("prototype", interpreter().array_prototype());
     put("length", Value(1));

+ 1 - 1
Libraries/LibJS/Runtime/BooleanConstructor.cpp

@@ -33,7 +33,7 @@
 namespace JS {
 
 BooleanConstructor::BooleanConstructor()
-    : NativeFunction("Boolean")
+    : NativeFunction("Boolean", *interpreter().function_prototype())
 {
     put("prototype", Value(interpreter().boolean_prototype()));
     put("length", Value(1));

+ 1 - 1
Libraries/LibJS/Runtime/DateConstructor.cpp

@@ -34,7 +34,7 @@
 namespace JS {
 
 DateConstructor::DateConstructor()
-    : NativeFunction("Date")
+    : NativeFunction("Date", *interpreter().function_prototype())
 {
     put("prototype", interpreter().date_prototype());
     put("length", Value(7));

+ 2 - 1
Libraries/LibJS/Runtime/ErrorConstructor.cpp

@@ -31,7 +31,7 @@
 namespace JS {
 
 ErrorConstructor::ErrorConstructor()
-    : NativeFunction("Error")
+    : NativeFunction("Error", *interpreter().function_prototype())
 {
     put("prototype", interpreter().error_prototype());
     put("length", Value(1));
@@ -56,6 +56,7 @@ Value ErrorConstructor::construct(Interpreter& interpreter)
 
 #define __JS_ENUMERATE(ClassName, snake_name, PrototypeName, ConstructorName)                                        \
     ConstructorName::ConstructorName()                                                                               \
+        : NativeFunction(*interpreter().function_prototype())                                                        \
     {                                                                                                                \
         put("prototype", interpreter().snake_name##_prototype());                                                    \
         put("length", Value(1));                                                                                     \

+ 2 - 2
Libraries/LibJS/Runtime/Function.cpp

@@ -29,9 +29,9 @@
 
 namespace JS {
 
-Function::Function()
+Function::Function(Object& prototype)
 {
-    set_prototype(interpreter().function_prototype());
+    set_prototype(&prototype);
 }
 
 Function::~Function()

+ 1 - 1
Libraries/LibJS/Runtime/Function.h

@@ -41,7 +41,7 @@ public:
     virtual LexicalEnvironment* create_environment() = 0;
 
 protected:
-    Function();
+    explicit Function(Object& prototype);
     virtual const char* class_name() const override { return "Function"; }
 
 private:

+ 1 - 1
Libraries/LibJS/Runtime/FunctionConstructor.cpp

@@ -35,7 +35,7 @@
 namespace JS {
 
 FunctionConstructor::FunctionConstructor()
-    : NativeFunction("Function")
+    : NativeFunction("Function", *interpreter().function_prototype())
 {
     put("prototype", interpreter().function_prototype());
     put("length", Value(1));

+ 4 - 0
Libraries/LibJS/Runtime/FunctionPrototype.cpp

@@ -36,6 +36,10 @@
 namespace JS {
 
 FunctionPrototype::FunctionPrototype()
+{
+}
+
+void FunctionPrototype::initialize()
 {
     put_native_function("apply", apply, 2);
     put_native_function("bind", bind, 1);

+ 2 - 0
Libraries/LibJS/Runtime/FunctionPrototype.h

@@ -33,6 +33,8 @@ namespace JS {
 class FunctionPrototype final : public Object {
 public:
     FunctionPrototype();
+    void initialize();
+
     virtual ~FunctionPrototype() override;
 
 private:

+ 17 - 4
Libraries/LibJS/Runtime/NativeFunction.cpp

@@ -25,19 +25,32 @@
  */
 
 #include <LibJS/Interpreter.h>
+#include <LibJS/Runtime/GlobalObject.h>
 #include <LibJS/Runtime/NativeFunction.h>
 #include <LibJS/Runtime/Value.h>
 
 namespace JS {
 
-NativeFunction::NativeFunction(const FlyString& name, AK::Function<Value(Interpreter&)> native_function)
-    : m_name(name)
+NativeFunction* NativeFunction::create(Interpreter& interpreter, GlobalObject&, const FlyString& name, AK::Function<Value(Interpreter&)> function)
+{
+    return interpreter.heap().allocate<NativeFunction>(name, move(function), *interpreter.function_prototype());
+}
+
+NativeFunction::NativeFunction(Object& prototype)
+    : Function(prototype)
+{
+}
+
+NativeFunction::NativeFunction(const FlyString& name, AK::Function<Value(Interpreter&)> native_function, Object& prototype)
+    : Function(prototype)
+    , m_name(name)
     , m_native_function(move(native_function))
 {
 }
 
-NativeFunction::NativeFunction(const FlyString& name)
-    : m_name(name)
+NativeFunction::NativeFunction(const FlyString& name, Object& prototype)
+    : Function(prototype)
+    , m_name(name)
 {
 }
 

+ 5 - 3
Libraries/LibJS/Runtime/NativeFunction.h

@@ -33,7 +33,9 @@ namespace JS {
 
 class NativeFunction : public Function {
 public:
-    explicit NativeFunction(const FlyString& name, AK::Function<Value(Interpreter&)>);
+    static NativeFunction* create(Interpreter&, GlobalObject&, const FlyString& name, AK::Function<Value(Interpreter&)>);
+
+    explicit NativeFunction(const FlyString& name, AK::Function<Value(Interpreter&)>, Object& prototype);
     virtual ~NativeFunction() override;
 
     virtual Value call(Interpreter&) override;
@@ -43,8 +45,8 @@ public:
     virtual bool has_constructor() const { return false; }
 
 protected:
-    NativeFunction(const FlyString& name);
-    NativeFunction() {}
+    NativeFunction(const FlyString& name, Object& prototype);
+    explicit NativeFunction(Object& prototype);
 
 private:
     virtual bool is_native_function() const override { return true; }

+ 1 - 1
Libraries/LibJS/Runtime/NumberConstructor.cpp

@@ -37,7 +37,7 @@
 namespace JS {
 
 NumberConstructor::NumberConstructor()
-    : NativeFunction("Number")
+    : NativeFunction("Number", *interpreter().function_prototype())
 {
     put_native_function("isSafeInteger", is_safe_integer, 1);
 

+ 1 - 1
Libraries/LibJS/Runtime/Object.cpp

@@ -235,7 +235,7 @@ void Object::put(PropertyName property_name, Value value)
 
 void Object::put_native_function(const FlyString& property_name, AK::Function<Value(Interpreter&)> native_function, i32 length)
 {
-    auto* function = heap().allocate<NativeFunction>(property_name, move(native_function));
+    auto* function = NativeFunction::create(interpreter(), interpreter().global_object(), property_name, move(native_function));
     function->put("length", Value(length));
     put(property_name, function);
 }

+ 1 - 1
Libraries/LibJS/Runtime/ObjectConstructor.cpp

@@ -35,7 +35,7 @@
 namespace JS {
 
 ObjectConstructor::ObjectConstructor()
-    : NativeFunction("Object")
+    : NativeFunction("Object", *interpreter().function_prototype())
 {
     put("prototype", interpreter().object_prototype());
 

+ 5 - 0
Libraries/LibJS/Runtime/ObjectPrototype.cpp

@@ -36,7 +36,12 @@ namespace JS {
 ObjectPrototype::ObjectPrototype()
 {
     set_prototype(nullptr);
+}
 
+void ObjectPrototype::initialize()
+{
+    // This must be called after the constructor has returned, so that the below code
+    // can find the ObjectPrototype through normal paths.
     put_native_function("hasOwnProperty", has_own_property, 1);
     put_native_function("toString", to_string);
     put_native_function("valueOf", value_of);

+ 2 - 0
Libraries/LibJS/Runtime/ObjectPrototype.h

@@ -33,6 +33,8 @@ namespace JS {
 class ObjectPrototype final : public Object {
 public:
     ObjectPrototype();
+    void initialize();
+
     virtual ~ObjectPrototype() override;
 
 private:

+ 10 - 2
Libraries/LibJS/Runtime/ScriptFunction.cpp

@@ -28,13 +28,21 @@
 #include <LibJS/AST.h>
 #include <LibJS/Interpreter.h>
 #include <LibJS/Runtime/Error.h>
+#include <LibJS/Runtime/GlobalObject.h>
 #include <LibJS/Runtime/ScriptFunction.h>
 #include <LibJS/Runtime/Value.h>
 
 namespace JS {
 
-ScriptFunction::ScriptFunction(const FlyString& name, const Statement& body, Vector<FlyString> parameters, LexicalEnvironment* parent_environment)
-    : m_name(name)
+ScriptFunction* ScriptFunction::create(GlobalObject& global_object, const FlyString& name, const Statement& body, Vector<FlyString> parameters, LexicalEnvironment* parent_environment)
+{
+    auto& interpreter = global_object.interpreter();
+    return interpreter.heap().allocate<ScriptFunction>(name, body, move(parameters), parent_environment, *interpreter.function_prototype());
+}
+
+ScriptFunction::ScriptFunction(const FlyString& name, const Statement& body, Vector<FlyString> parameters, LexicalEnvironment* parent_environment, Object& prototype)
+    : Function(prototype)
+    , m_name(name)
     , m_body(body)
     , m_parameters(move(parameters))
     , m_parent_environment(parent_environment)

+ 3 - 1
Libraries/LibJS/Runtime/ScriptFunction.h

@@ -32,7 +32,9 @@ namespace JS {
 
 class ScriptFunction final : public Function {
 public:
-    ScriptFunction(const FlyString& name, const Statement& body, Vector<FlyString> parameters, LexicalEnvironment* parent_environment);
+    static ScriptFunction* create(GlobalObject&, const FlyString& name, const Statement& body, Vector<FlyString> parameters, LexicalEnvironment* parent_environment);
+
+    ScriptFunction(const FlyString& name, const Statement& body, Vector<FlyString> parameters, LexicalEnvironment* parent_environment, Object& prototype);
     virtual ~ScriptFunction();
 
     const Statement& body() const { return m_body; }

+ 1 - 1
Libraries/LibJS/Runtime/StringConstructor.cpp

@@ -33,7 +33,7 @@
 namespace JS {
 
 StringConstructor::StringConstructor()
-    : NativeFunction("String")
+    : NativeFunction("String", *interpreter().function_prototype())
 {
     put("prototype", interpreter().string_prototype());
     put("length", Value(1));