summaryrefslogtreecommitdiff
path: root/Libraries/LibJS/Runtime
diff options
context:
space:
mode:
Diffstat (limited to 'Libraries/LibJS/Runtime')
-rw-r--r--Libraries/LibJS/Runtime/BigIntConstructor.cpp2
-rw-r--r--Libraries/LibJS/Runtime/ErrorTypes.h7
-rw-r--r--Libraries/LibJS/Runtime/Function.h23
-rw-r--r--Libraries/LibJS/Runtime/LexicalEnvironment.cpp69
-rw-r--r--Libraries/LibJS/Runtime/LexicalEnvironment.h43
-rw-r--r--Libraries/LibJS/Runtime/NativeFunction.cpp5
-rw-r--r--Libraries/LibJS/Runtime/NativeFunction.h2
-rw-r--r--Libraries/LibJS/Runtime/Object.cpp2
-rw-r--r--Libraries/LibJS/Runtime/ScriptFunction.cpp14
-rw-r--r--Libraries/LibJS/Runtime/SymbolConstructor.cpp2
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 {};
}