diff options
Diffstat (limited to 'Libraries/LibJS/Runtime')
-rw-r--r-- | Libraries/LibJS/Runtime/BigIntConstructor.cpp | 2 | ||||
-rw-r--r-- | Libraries/LibJS/Runtime/ErrorTypes.h | 7 | ||||
-rw-r--r-- | Libraries/LibJS/Runtime/Function.h | 23 | ||||
-rw-r--r-- | Libraries/LibJS/Runtime/LexicalEnvironment.cpp | 69 | ||||
-rw-r--r-- | Libraries/LibJS/Runtime/LexicalEnvironment.h | 43 | ||||
-rw-r--r-- | Libraries/LibJS/Runtime/NativeFunction.cpp | 5 | ||||
-rw-r--r-- | Libraries/LibJS/Runtime/NativeFunction.h | 2 | ||||
-rw-r--r-- | Libraries/LibJS/Runtime/Object.cpp | 2 | ||||
-rw-r--r-- | Libraries/LibJS/Runtime/ScriptFunction.cpp | 14 | ||||
-rw-r--r-- | Libraries/LibJS/Runtime/SymbolConstructor.cpp | 2 |
10 files changed, 149 insertions, 20 deletions
diff --git a/Libraries/LibJS/Runtime/BigIntConstructor.cpp b/Libraries/LibJS/Runtime/BigIntConstructor.cpp index b7d263d90b..fb0ccf7dc0 100644 --- a/Libraries/LibJS/Runtime/BigIntConstructor.cpp +++ b/Libraries/LibJS/Runtime/BigIntConstructor.cpp @@ -74,7 +74,7 @@ Value BigIntConstructor::call(Interpreter& interpreter) Value BigIntConstructor::construct(Interpreter& interpreter) { - interpreter.throw_exception<TypeError>(ErrorType::NotACtor, "BigInt"); + interpreter.throw_exception<TypeError>(ErrorType::NotAConstructor, "BigInt"); return {}; } diff --git a/Libraries/LibJS/Runtime/ErrorTypes.h b/Libraries/LibJS/Runtime/ErrorTypes.h index 3dfaccdc95..883ed1962b 100644 --- a/Libraries/LibJS/Runtime/ErrorTypes.h +++ b/Libraries/LibJS/Runtime/ErrorTypes.h @@ -36,6 +36,7 @@ M(BigIntBadOperatorOtherType, "Cannot use %s operator with BigInt and other type") \ M(BigIntIntArgument, "BigInt argument must be an integer") \ M(BigIntInvalidValue, "Invalid value for BigInt: %s") \ + M(ClassDoesNotExtendAConstructorOrNull, "Class extends value %s is not a constructor or null") \ M(Convert, "Cannot convert %s to %s") \ M(ConvertUndefinedToObject, "Cannot convert undefined to object") \ M(DescChangeNonConfigurable, "Cannot change attributes of non-configurable property '%s'") \ @@ -51,7 +52,7 @@ M(JsonCircular, "Cannot stringify circular object") \ M(JsonMalformed, "Malformed JSON string") \ M(NotA, "Not a %s object") \ - M(NotACtor, "%s is not a constructor") \ + M(NotAConstructor, "%s is not a constructor") \ M(NotAFunction, "%s is not a function") \ M(NotAFunctionNoParam, "Not a function") \ M(NotAn, "Not an %s object") \ @@ -63,6 +64,8 @@ M(ObjectSetPrototypeOfReturnedFalse, "Object's [[SetPrototypeOf]] method returned false") \ M(ObjectSetPrototypeOfTwoArgs, "Object.setPrototypeOf requires at least two arguments") \ M(ObjectPreventExtensionsReturnedFalse, "Object's [[PreventExtensions]] method returned false") \ + M(ObjectPrototypeNullOrUndefinedOnSuperPropertyAccess, \ + "Object prototype must not be %s on a super property access") \ M(ObjectPrototypeWrongType, "Prototype must be an object or null") \ M(ProxyCallWithNew, "Proxy must be called with the 'new' operator") \ M(ProxyConstructorBadType, "Expected %s argument of Proxy constructor to be object, got %s") \ @@ -138,6 +141,8 @@ M(ReflectBadDescriptorArgument, "Descriptor argument is not an object") \ M(StringRawCannotConvert, "Cannot convert property 'raw' to object from %s") \ M(StringRepeatCountMustBe, "repeat count must be a %s number") \ + M(ThisHasNotBeenInitialized, "|this| has not been initialized") \ + M(ThisIsAlreadyInitialized, "|this| is already initialized") \ M(ToObjectNullOrUndef, "ToObject on null or undefined") \ M(UnknownIdentifier, "'%s' is not defined") \ /* LibWeb bindings */ \ diff --git a/Libraries/LibJS/Runtime/Function.h b/Libraries/LibJS/Runtime/Function.h index 8e19472fcc..bd25fcb0e9 100644 --- a/Libraries/LibJS/Runtime/Function.h +++ b/Libraries/LibJS/Runtime/Function.h @@ -35,6 +35,11 @@ class Function : public Object { JS_OBJECT(Function, Object); public: + enum class ConstructorKind { + Base, + Derived, + }; + virtual ~Function(); virtual void initialize(Interpreter&, GlobalObject&) override { } @@ -49,15 +54,15 @@ public: BoundFunction* bind(Value bound_this_value, Vector<Value> arguments); - Value bound_this() const - { - return m_bound_this; - } + Value bound_this() const { return m_bound_this; } + + const Vector<Value>& bound_arguments() const { return m_bound_arguments; } + + Value home_object() const { return m_home_object; } + void set_home_object(Value home_object) { m_home_object = home_object; } - const Vector<Value>& bound_arguments() const - { - return m_bound_arguments; - } + ConstructorKind constructor_kind() const { return m_constructor_kind; }; + void set_constructor_kind(ConstructorKind constructor_kind) { m_constructor_kind = constructor_kind; } protected: explicit Function(Object& prototype); @@ -67,6 +72,8 @@ private: virtual bool is_function() const final { return true; } Value m_bound_this; Vector<Value> m_bound_arguments; + Value m_home_object; + ConstructorKind m_constructor_kind = ConstructorKind::Base; }; } diff --git a/Libraries/LibJS/Runtime/LexicalEnvironment.cpp b/Libraries/LibJS/Runtime/LexicalEnvironment.cpp index 518126e0d5..0dae1029ce 100644 --- a/Libraries/LibJS/Runtime/LexicalEnvironment.cpp +++ b/Libraries/LibJS/Runtime/LexicalEnvironment.cpp @@ -24,7 +24,11 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +#include <LibJS/Interpreter.h> +#include <LibJS/Runtime/Error.h> +#include <LibJS/Runtime/Function.h> #include <LibJS/Runtime/LexicalEnvironment.h> +#include <LibJS/Runtime/Value.h> namespace JS { @@ -32,12 +36,24 @@ LexicalEnvironment::LexicalEnvironment() { } +LexicalEnvironment::LexicalEnvironment(EnvironmentRecordType environment_record_type) + : m_environment_record_type(environment_record_type) +{ +} + LexicalEnvironment::LexicalEnvironment(HashMap<FlyString, Variable> variables, LexicalEnvironment* parent) : m_parent(parent) , m_variables(move(variables)) { } +LexicalEnvironment::LexicalEnvironment(HashMap<FlyString, Variable> variables, LexicalEnvironment* parent, EnvironmentRecordType environment_record_type) + : m_parent(parent) + , m_variables(move(variables)) + , m_environment_record_type(environment_record_type) +{ +} + LexicalEnvironment::~LexicalEnvironment() { } @@ -46,6 +62,10 @@ void LexicalEnvironment::visit_children(Visitor& visitor) { Cell::visit_children(visitor); visitor.visit(m_parent); + visitor.visit(m_this_value); + visitor.visit(m_home_object); + visitor.visit(m_new_target); + visitor.visit(m_current_function); for (auto& it : m_variables) visitor.visit(it.value.value); } @@ -60,4 +80,53 @@ void LexicalEnvironment::set(const FlyString& name, Variable variable) m_variables.set(name, variable); } +bool LexicalEnvironment::has_super_binding() const +{ + return m_environment_record_type == EnvironmentRecordType::Function && this_binding_status() != ThisBindingStatus::Lexical && m_home_object.is_object(); +} + +Value LexicalEnvironment::get_super_base() +{ + ASSERT(has_super_binding()); + if (m_home_object.is_object()) + return m_home_object.as_object().prototype(); + return {}; +} + +bool LexicalEnvironment::has_this_binding() const +{ + // More like "is_capable_of_having_a_this_binding". + switch (m_environment_record_type) { + case EnvironmentRecordType::Declarative: + case EnvironmentRecordType::Object: + return false; + case EnvironmentRecordType::Function: + return this_binding_status() != ThisBindingStatus::Lexical; + case EnvironmentRecordType::Module: + case EnvironmentRecordType::Global: + return true; + } + ASSERT_NOT_REACHED(); +} + +Value LexicalEnvironment::get_this_binding() const +{ + ASSERT(has_this_binding()); + if (this_binding_status() == ThisBindingStatus::Uninitialized) + return interpreter().throw_exception<ReferenceError>(ErrorType::ThisHasNotBeenInitialized); + + return m_this_value; +} + +void LexicalEnvironment::bind_this_value(Value this_value) +{ + ASSERT(has_this_binding()); + if (m_this_binding_status == ThisBindingStatus::Initialized) { + interpreter().throw_exception<ReferenceError>(ErrorType::ThisIsAlreadyInitialized); + return; + } + m_this_value = this_value; + m_this_binding_status = ThisBindingStatus::Initialized; +} + } diff --git a/Libraries/LibJS/Runtime/LexicalEnvironment.h b/Libraries/LibJS/Runtime/LexicalEnvironment.h index c2cf3d8651..a4c9deda13 100644 --- a/Libraries/LibJS/Runtime/LexicalEnvironment.h +++ b/Libraries/LibJS/Runtime/LexicalEnvironment.h @@ -40,11 +40,27 @@ struct Variable { class LexicalEnvironment final : public Cell { public: + enum class ThisBindingStatus { + Lexical, + Initialized, + Uninitialized, + }; + + enum class EnvironmentRecordType { + Declarative, + Function, + Global, + Object, + Module, + }; + LexicalEnvironment(); + LexicalEnvironment(EnvironmentRecordType); LexicalEnvironment(HashMap<FlyString, Variable> variables, LexicalEnvironment* parent); + LexicalEnvironment(HashMap<FlyString, Variable> variables, LexicalEnvironment* parent, EnvironmentRecordType); virtual ~LexicalEnvironment() override; - LexicalEnvironment* parent() { return m_parent; } + LexicalEnvironment* parent() const { return m_parent; } Optional<Variable> get(const FlyString&) const; void set(const FlyString&, Variable); @@ -53,12 +69,37 @@ public: const HashMap<FlyString, Variable>& variables() const { return m_variables; } + void set_home_object(Value object) { m_home_object = object; } + bool has_super_binding() const; + Value get_super_base(); + + bool has_this_binding() const; + ThisBindingStatus this_binding_status() const { return m_this_binding_status; } + Value get_this_binding() const; + void bind_this_value(Value this_value); + + // Not a standard operation. + void replace_this_binding(Value this_value) { m_this_value = this_value; } + + Value new_target() const { return m_new_target; }; + void set_new_target(Value new_target) { m_new_target = new_target; } + + Function* current_function() const { return m_current_function; } + void set_current_function(Function& function) { m_current_function = &function; } + private: virtual const char* class_name() const override { return "LexicalEnvironment"; } virtual void visit_children(Visitor&) override; LexicalEnvironment* m_parent { nullptr }; HashMap<FlyString, Variable> m_variables; + EnvironmentRecordType m_environment_record_type = EnvironmentRecordType::Declarative; + ThisBindingStatus m_this_binding_status = ThisBindingStatus::Uninitialized; + Value m_home_object; + Value m_this_value; + Value m_new_target; + // Corresponds to [[FunctionObject]] + Function* m_current_function { nullptr }; }; } diff --git a/Libraries/LibJS/Runtime/NativeFunction.cpp b/Libraries/LibJS/Runtime/NativeFunction.cpp index 070632bef0..6d350ee9af 100644 --- a/Libraries/LibJS/Runtime/NativeFunction.cpp +++ b/Libraries/LibJS/Runtime/NativeFunction.cpp @@ -68,4 +68,9 @@ Value NativeFunction::construct(Interpreter&) return {}; } +LexicalEnvironment* NativeFunction::create_environment() +{ + return interpreter().heap().allocate<LexicalEnvironment>(global_object(), LexicalEnvironment::EnvironmentRecordType::Function); +} + } diff --git a/Libraries/LibJS/Runtime/NativeFunction.h b/Libraries/LibJS/Runtime/NativeFunction.h index f569e382ac..19cb64bd4e 100644 --- a/Libraries/LibJS/Runtime/NativeFunction.h +++ b/Libraries/LibJS/Runtime/NativeFunction.h @@ -53,7 +53,7 @@ protected: private: virtual bool is_native_function() const override { return true; } - virtual LexicalEnvironment* create_environment() override final { return nullptr; } + virtual LexicalEnvironment* create_environment() override final; FlyString m_name; AK::Function<Value(Interpreter&, GlobalObject&)> m_native_function; diff --git a/Libraries/LibJS/Runtime/Object.cpp b/Libraries/LibJS/Runtime/Object.cpp index 2d1feb8ebd..7abeeaf997 100644 --- a/Libraries/LibJS/Runtime/Object.cpp +++ b/Libraries/LibJS/Runtime/Object.cpp @@ -437,7 +437,7 @@ bool Object::define_accessor(PropertyName property_name, Function& getter_or_set accessor = &existing_property.as_accessor(); } if (!accessor) { - accessor = Accessor::create(interpreter(), nullptr, nullptr); + accessor = Accessor::create(interpreter(), global_object(), nullptr, nullptr); bool definition_success = define_property(property_name, accessor, attributes, throw_exceptions); if (interpreter().exception()) return {}; diff --git a/Libraries/LibJS/Runtime/ScriptFunction.cpp b/Libraries/LibJS/Runtime/ScriptFunction.cpp index 11fa9c5da0..7c3b461649 100644 --- a/Libraries/LibJS/Runtime/ScriptFunction.cpp +++ b/Libraries/LibJS/Runtime/ScriptFunction.cpp @@ -66,8 +66,8 @@ ScriptFunction::ScriptFunction(GlobalObject& global_object, const FlyString& nam void ScriptFunction::initialize(Interpreter& interpreter, GlobalObject& global_object) { Function::initialize(interpreter, global_object); - if (!is_arrow_function) { - Object* prototype = Object::create_empty(interpreter(), interpreter().global_object()); + if (!m_is_arrow_function) { + Object* prototype = Object::create_empty(interpreter, global_object); prototype->define_property("constructor", this, Attribute::Writable | Attribute::Configurable); define_property("prototype", prototype, 0); } @@ -99,9 +99,11 @@ LexicalEnvironment* ScriptFunction::create_environment() } } } - if (variables.is_empty()) - return m_parent_environment; - return heap().allocate<LexicalEnvironment>(global_object(), move(variables), m_parent_environment); + + auto* environment = heap().allocate<LexicalEnvironment>(global_object(), move(variables), m_parent_environment, LexicalEnvironment::EnvironmentRecordType::Function); + environment->set_home_object(home_object()); + environment->set_current_function(*this); + return environment; } Value ScriptFunction::call(Interpreter& interpreter) @@ -134,7 +136,7 @@ Value ScriptFunction::call(Interpreter& interpreter) Value ScriptFunction::construct(Interpreter& interpreter) { if (m_is_arrow_function) - return interpreter.throw_exception<TypeError>(ErrorType::NotACtor, m_name.characters()); + return interpreter.throw_exception<TypeError>(ErrorType::NotAConstructor, m_name.characters()); return call(interpreter); } diff --git a/Libraries/LibJS/Runtime/SymbolConstructor.cpp b/Libraries/LibJS/Runtime/SymbolConstructor.cpp index 4a74c4d0bc..9080b2d56b 100644 --- a/Libraries/LibJS/Runtime/SymbolConstructor.cpp +++ b/Libraries/LibJS/Runtime/SymbolConstructor.cpp @@ -76,7 +76,7 @@ Value SymbolConstructor::call(Interpreter& interpreter) Value SymbolConstructor::construct(Interpreter& interpreter) { - interpreter.throw_exception<TypeError>(ErrorType::NotACtor, "Symbol"); + interpreter.throw_exception<TypeError>(ErrorType::NotAConstructor, "Symbol"); return {}; } |