Ver código fonte

LibJS: Ensure get_new_target() never returns an empty value

Also add spec comments and remove a redundant exception check while
we're here :^)
Linus Groh 3 anos atrás
pai
commit
451149df0b

+ 1 - 3
Userland/Libraries/LibJS/AST.cpp

@@ -347,8 +347,6 @@ Value SuperCall::execute(Interpreter& interpreter, GlobalObject& global_object)
 
     // 1. Let newTarget be GetNewTarget().
     auto new_target = vm.get_new_target();
-    if (vm.exception())
-        return {};
 
     // 2. Assert: Type(newTarget) is Object.
     VERIFY(new_target.is_function());
@@ -2873,7 +2871,7 @@ Value MetaProperty::execute(Interpreter& interpreter, GlobalObject& global_objec
     InterpreterNodeScope node_scope { interpreter, *this };
 
     if (m_type == MetaProperty::Type::NewTarget)
-        return interpreter.vm().get_new_target().value_or(js_undefined());
+        return interpreter.vm().get_new_target();
     if (m_type == MetaProperty::Type::ImportMeta) {
         interpreter.vm().throw_exception<InternalError>(global_object, ErrorType::NotImplemented, "'import.meta' in modules");
         return {};

+ 2 - 0
Userland/Libraries/LibJS/Runtime/FunctionEnvironment.cpp

@@ -81,6 +81,8 @@ ThrowCompletionOr<Value> FunctionEnvironment::get_this_binding(GlobalObject& glo
 // 9.1.1.3.1 BindThisValue ( V ), https://tc39.es/ecma262/#sec-bindthisvalue
 ThrowCompletionOr<Value> FunctionEnvironment::bind_this_value(GlobalObject& global_object, Value this_value)
 {
+    VERIFY(!this_value.is_empty());
+
     // 1. Assert: envRec.[[ThisBindingStatus]] is not lexical.
     VERIFY(m_this_binding_status != ThisBindingStatus::Lexical);
 

+ 9 - 9
Userland/Libraries/LibJS/Runtime/FunctionEnvironment.h

@@ -25,22 +25,22 @@ public:
     explicit FunctionEnvironment(Environment* parent_scope);
     virtual ~FunctionEnvironment() override;
 
-    // [[ThisValue]]
     Value this_value() const { return m_this_value; }
     void set_this_value(Value value) { m_this_value = value; }
 
-    // [[ThisBindingStatus]]
     ThisBindingStatus this_binding_status() const { return m_this_binding_status; }
     void set_this_binding_status(ThisBindingStatus status) { m_this_binding_status = status; }
 
-    // [[FunctionObject]]
     ECMAScriptFunctionObject& function_object() { return *m_function_object; }
     ECMAScriptFunctionObject const& function_object() const { return *m_function_object; }
     void set_function_object(ECMAScriptFunctionObject& function) { m_function_object = &function; }
 
-    // [[NewTarget]]
     Value new_target() const { return m_new_target; }
-    void set_new_target(Value new_target) { m_new_target = new_target; }
+    void set_new_target(Value new_target)
+    {
+        VERIFY(!new_target.is_empty());
+        m_new_target = new_target;
+    }
 
     // Abstract operations
     ThrowCompletionOr<Value> get_super_base() const;
@@ -53,10 +53,10 @@ private:
     virtual bool is_function_environment() const override { return true; }
     virtual void visit_edges(Visitor&) override;
 
-    Value m_this_value;
-    ThisBindingStatus m_this_binding_status { ThisBindingStatus::Uninitialized };
-    ECMAScriptFunctionObject* m_function_object { nullptr };
-    Value m_new_target;
+    Value m_this_value;                                                           // [[ThisValue]]
+    ThisBindingStatus m_this_binding_status { ThisBindingStatus::Uninitialized }; // [[ThisBindingStatus]]
+    ECMAScriptFunctionObject* m_function_object { nullptr };                      // [[FunctionObject]]
+    Value m_new_target { js_undefined() };                                        // [[NewTarget]]
 };
 
 template<>

+ 5 - 0
Userland/Libraries/LibJS/Runtime/VM.cpp

@@ -497,9 +497,14 @@ String VM::join_arguments(size_t start_index) const
     return joined_arguments.build();
 }
 
+// 9.4.5 GetNewTarget ( ), https://tc39.es/ecma262/#sec-getnewtarget
 Value VM::get_new_target()
 {
+    // 1. Let envRec be GetThisEnvironment().
     auto& env = get_this_environment(*this);
+
+    // 2. Assert: envRec has a [[NewTarget]] field.
+    // 3. Return envRec.[[NewTarget]].
     return verify_cast<FunctionEnvironment>(env).new_target();
 }