mirror of
https://github.com/RGBCube/serenity
synced 2025-07-26 00:57:36 +00:00
LibJS: Make class definition evaluation work in bytecode mode
Instead of assuming that there's an active AST interpreter, this code now takes VM& everywhere and invokes the appropriate interpreter. 92 new passes on test262. :^)
This commit is contained in:
parent
66936a0d61
commit
8450948458
4 changed files with 38 additions and 39 deletions
|
@ -1660,18 +1660,16 @@ Completion ClassElement::execute(Interpreter&) const
|
||||||
VERIFY_NOT_REACHED();
|
VERIFY_NOT_REACHED();
|
||||||
}
|
}
|
||||||
|
|
||||||
static ThrowCompletionOr<ClassElementName> class_key_to_property_name(Interpreter& interpreter, Expression const& key)
|
static ThrowCompletionOr<ClassElementName> class_key_to_property_name(VM& vm, Expression const& key)
|
||||||
{
|
{
|
||||||
auto& vm = interpreter.vm();
|
|
||||||
|
|
||||||
if (is<PrivateIdentifier>(key)) {
|
if (is<PrivateIdentifier>(key)) {
|
||||||
auto& private_identifier = static_cast<PrivateIdentifier const&>(key);
|
auto& private_identifier = static_cast<PrivateIdentifier const&>(key);
|
||||||
auto private_environment = interpreter.vm().running_execution_context().private_environment;
|
auto private_environment = vm.running_execution_context().private_environment;
|
||||||
VERIFY(private_environment);
|
VERIFY(private_environment);
|
||||||
return ClassElementName { private_environment->resolve_private_identifier(private_identifier.string()) };
|
return ClassElementName { private_environment->resolve_private_identifier(private_identifier.string()) };
|
||||||
}
|
}
|
||||||
|
|
||||||
auto prop_key = TRY(key.execute(interpreter)).release_value();
|
auto prop_key = TRY(vm.execute_ast_node(key));
|
||||||
|
|
||||||
if (prop_key.is_object())
|
if (prop_key.is_object())
|
||||||
prop_key = TRY(prop_key.to_primitive(vm, Value::PreferredType::String));
|
prop_key = TRY(prop_key.to_primitive(vm, Value::PreferredType::String));
|
||||||
|
@ -1681,11 +1679,11 @@ static ThrowCompletionOr<ClassElementName> class_key_to_property_name(Interprete
|
||||||
}
|
}
|
||||||
|
|
||||||
// 15.4.5 Runtime Semantics: MethodDefinitionEvaluation, https://tc39.es/ecma262/#sec-runtime-semantics-methoddefinitionevaluation
|
// 15.4.5 Runtime Semantics: MethodDefinitionEvaluation, https://tc39.es/ecma262/#sec-runtime-semantics-methoddefinitionevaluation
|
||||||
ThrowCompletionOr<ClassElement::ClassValue> ClassMethod::class_element_evaluation(Interpreter& interpreter, Object& target) const
|
ThrowCompletionOr<ClassElement::ClassValue> ClassMethod::class_element_evaluation(VM& vm, Object& target) const
|
||||||
{
|
{
|
||||||
auto property_key_or_private_name = TRY(class_key_to_property_name(interpreter, *m_key));
|
auto property_key_or_private_name = TRY(class_key_to_property_name(vm, *m_key));
|
||||||
|
|
||||||
auto method_value = TRY(m_function->execute(interpreter)).release_value();
|
auto method_value = TRY(vm.execute_ast_node(*m_function));
|
||||||
|
|
||||||
auto function_handle = make_handle(&method_value.as_function());
|
auto function_handle = make_handle(&method_value.as_function());
|
||||||
|
|
||||||
|
@ -1739,10 +1737,10 @@ ThrowCompletionOr<ClassElement::ClassValue> ClassMethod::class_element_evaluatio
|
||||||
return ClassValue { PrivateElement { private_name, PrivateElement::Kind::Method, make_handle(method_value) } };
|
return ClassValue { PrivateElement { private_name, PrivateElement::Kind::Method, make_handle(method_value) } };
|
||||||
case Kind::Getter:
|
case Kind::Getter:
|
||||||
set_function_name("get");
|
set_function_name("get");
|
||||||
return ClassValue { PrivateElement { private_name, PrivateElement::Kind::Accessor, make_handle(Value(Accessor::create(interpreter.vm(), &method_function, nullptr))) } };
|
return ClassValue { PrivateElement { private_name, PrivateElement::Kind::Accessor, make_handle(Value(Accessor::create(vm, &method_function, nullptr))) } };
|
||||||
case Kind::Setter:
|
case Kind::Setter:
|
||||||
set_function_name("set");
|
set_function_name("set");
|
||||||
return ClassValue { PrivateElement { private_name, PrivateElement::Kind::Accessor, make_handle(Value(Accessor::create(interpreter.vm(), nullptr, &method_function))) } };
|
return ClassValue { PrivateElement { private_name, PrivateElement::Kind::Accessor, make_handle(Value(Accessor::create(vm, nullptr, &method_function))) } };
|
||||||
default:
|
default:
|
||||||
VERIFY_NOT_REACHED();
|
VERIFY_NOT_REACHED();
|
||||||
}
|
}
|
||||||
|
@ -1775,12 +1773,11 @@ void ClassFieldInitializerStatement::dump(int) const
|
||||||
}
|
}
|
||||||
|
|
||||||
// 15.7.10 Runtime Semantics: ClassFieldDefinitionEvaluation, https://tc39.es/ecma262/#sec-runtime-semantics-classfielddefinitionevaluation
|
// 15.7.10 Runtime Semantics: ClassFieldDefinitionEvaluation, https://tc39.es/ecma262/#sec-runtime-semantics-classfielddefinitionevaluation
|
||||||
ThrowCompletionOr<ClassElement::ClassValue> ClassField::class_element_evaluation(Interpreter& interpreter, Object& target) const
|
ThrowCompletionOr<ClassElement::ClassValue> ClassField::class_element_evaluation(VM& vm, Object& target) const
|
||||||
{
|
{
|
||||||
auto& vm = interpreter.vm();
|
|
||||||
auto& realm = *vm.current_realm();
|
auto& realm = *vm.current_realm();
|
||||||
|
|
||||||
auto property_key_or_private_name = TRY(class_key_to_property_name(interpreter, *m_key));
|
auto property_key_or_private_name = TRY(class_key_to_property_name(vm, *m_key));
|
||||||
Handle<ECMAScriptFunctionObject> initializer {};
|
Handle<ECMAScriptFunctionObject> initializer {};
|
||||||
if (m_initializer) {
|
if (m_initializer) {
|
||||||
auto copy_initializer = m_initializer;
|
auto copy_initializer = m_initializer;
|
||||||
|
@ -1794,7 +1791,7 @@ ThrowCompletionOr<ClassElement::ClassValue> ClassField::class_element_evaluation
|
||||||
|
|
||||||
// FIXME: A potential optimization is not creating the functions here since these are never directly accessible.
|
// FIXME: A potential optimization is not creating the functions here since these are never directly accessible.
|
||||||
auto function_code = create_ast_node<ClassFieldInitializerStatement>(m_initializer->source_range(), copy_initializer.release_nonnull(), name);
|
auto function_code = create_ast_node<ClassFieldInitializerStatement>(m_initializer->source_range(), copy_initializer.release_nonnull(), name);
|
||||||
initializer = make_handle(*ECMAScriptFunctionObject::create(realm, DeprecatedString::empty(), DeprecatedString::empty(), *function_code, {}, 0, interpreter.lexical_environment(), interpreter.vm().running_execution_context().private_environment, FunctionKind::Normal, true, false, m_contains_direct_call_to_eval, false, property_key_or_private_name));
|
initializer = make_handle(*ECMAScriptFunctionObject::create(realm, DeprecatedString::empty(), DeprecatedString::empty(), *function_code, {}, 0, vm.lexical_environment(), vm.running_execution_context().private_environment, FunctionKind::Normal, true, false, m_contains_direct_call_to_eval, false, property_key_or_private_name));
|
||||||
initializer->make_method(target);
|
initializer->make_method(target);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1824,16 +1821,15 @@ Optional<DeprecatedFlyString> ClassMethod::private_bound_identifier() const
|
||||||
}
|
}
|
||||||
|
|
||||||
// 15.7.11 Runtime Semantics: ClassStaticBlockDefinitionEvaluation, https://tc39.es/ecma262/#sec-runtime-semantics-classstaticblockdefinitionevaluation
|
// 15.7.11 Runtime Semantics: ClassStaticBlockDefinitionEvaluation, https://tc39.es/ecma262/#sec-runtime-semantics-classstaticblockdefinitionevaluation
|
||||||
ThrowCompletionOr<ClassElement::ClassValue> StaticInitializer::class_element_evaluation(Interpreter& interpreter, Object& home_object) const
|
ThrowCompletionOr<ClassElement::ClassValue> StaticInitializer::class_element_evaluation(VM& vm, Object& home_object) const
|
||||||
{
|
{
|
||||||
auto& vm = interpreter.vm();
|
|
||||||
auto& realm = *vm.current_realm();
|
auto& realm = *vm.current_realm();
|
||||||
|
|
||||||
// 1. Let lex be the running execution context's LexicalEnvironment.
|
// 1. Let lex be the running execution context's LexicalEnvironment.
|
||||||
auto lexical_environment = interpreter.vm().running_execution_context().lexical_environment;
|
auto lexical_environment = vm.running_execution_context().lexical_environment;
|
||||||
|
|
||||||
// 2. Let privateEnv be the running execution context's PrivateEnvironment.
|
// 2. Let privateEnv be the running execution context's PrivateEnvironment.
|
||||||
auto private_environment = interpreter.vm().running_execution_context().private_environment;
|
auto private_environment = vm.running_execution_context().private_environment;
|
||||||
|
|
||||||
// 3. Let sourceText be the empty sequence of Unicode code points.
|
// 3. Let sourceText be the empty sequence of Unicode code points.
|
||||||
// 4. Let formalParameters be an instance of the production FormalParameters : [empty] .
|
// 4. Let formalParameters be an instance of the production FormalParameters : [empty] .
|
||||||
|
@ -1856,7 +1852,7 @@ Completion ClassExpression::execute(Interpreter& interpreter) const
|
||||||
|
|
||||||
// 1. Let className be StringValue of BindingIdentifier.
|
// 1. Let className be StringValue of BindingIdentifier.
|
||||||
// 2. Let value be ? ClassDefinitionEvaluation of ClassTail with arguments className and className.
|
// 2. Let value be ? ClassDefinitionEvaluation of ClassTail with arguments className and className.
|
||||||
auto* value = TRY(class_definition_evaluation(interpreter, m_name, m_name.is_null() ? "" : m_name));
|
auto* value = TRY(class_definition_evaluation(interpreter.vm(), m_name, m_name.is_null() ? "" : m_name));
|
||||||
|
|
||||||
// 3. Set value.[[SourceText]] to the source text matched by ClassExpression.
|
// 3. Set value.[[SourceText]] to the source text matched by ClassExpression.
|
||||||
value->set_source_text(m_source_text);
|
value->set_source_text(m_source_text);
|
||||||
|
@ -1873,7 +1869,7 @@ static ThrowCompletionOr<Value> binding_class_declaration_evaluation(Interpreter
|
||||||
// ClassDeclaration : class ClassTail
|
// ClassDeclaration : class ClassTail
|
||||||
if (!class_expression.has_name()) {
|
if (!class_expression.has_name()) {
|
||||||
// 1. Let value be ? ClassDefinitionEvaluation of ClassTail with arguments undefined and "default".
|
// 1. Let value be ? ClassDefinitionEvaluation of ClassTail with arguments undefined and "default".
|
||||||
auto value = TRY(class_expression.class_definition_evaluation(interpreter, {}, "default"));
|
auto value = TRY(class_expression.class_definition_evaluation(vm, {}, "default"));
|
||||||
|
|
||||||
// 2. Set value.[[SourceText]] to the source text matched by ClassDeclaration.
|
// 2. Set value.[[SourceText]] to the source text matched by ClassDeclaration.
|
||||||
value->set_source_text(class_expression.source_text());
|
value->set_source_text(class_expression.source_text());
|
||||||
|
@ -1889,7 +1885,7 @@ static ThrowCompletionOr<Value> binding_class_declaration_evaluation(Interpreter
|
||||||
VERIFY(!class_name.is_empty());
|
VERIFY(!class_name.is_empty());
|
||||||
|
|
||||||
// 2. Let value be ? ClassDefinitionEvaluation of ClassTail with arguments className and className.
|
// 2. Let value be ? ClassDefinitionEvaluation of ClassTail with arguments className and className.
|
||||||
auto value = TRY(class_expression.class_definition_evaluation(interpreter, class_name, class_name));
|
auto value = TRY(class_expression.class_definition_evaluation(vm, class_name, class_name));
|
||||||
|
|
||||||
// 3. Set value.[[SourceText]] to the source text matched by ClassDeclaration.
|
// 3. Set value.[[SourceText]] to the source text matched by ClassDeclaration.
|
||||||
value->set_source_text(class_expression.source_text());
|
value->set_source_text(class_expression.source_text());
|
||||||
|
@ -1918,9 +1914,8 @@ Completion ClassDeclaration::execute(Interpreter& interpreter) const
|
||||||
}
|
}
|
||||||
|
|
||||||
// 15.7.14 Runtime Semantics: ClassDefinitionEvaluation, https://tc39.es/ecma262/#sec-runtime-semantics-classdefinitionevaluation
|
// 15.7.14 Runtime Semantics: ClassDefinitionEvaluation, https://tc39.es/ecma262/#sec-runtime-semantics-classdefinitionevaluation
|
||||||
ThrowCompletionOr<ECMAScriptFunctionObject*> ClassExpression::class_definition_evaluation(Interpreter& interpreter, DeprecatedFlyString const& binding_name, DeprecatedFlyString const& class_name) const
|
ThrowCompletionOr<ECMAScriptFunctionObject*> ClassExpression::class_definition_evaluation(VM& vm, DeprecatedFlyString const& binding_name, DeprecatedFlyString const& class_name) const
|
||||||
{
|
{
|
||||||
auto& vm = interpreter.vm();
|
|
||||||
auto& realm = *vm.current_realm();
|
auto& realm = *vm.current_realm();
|
||||||
|
|
||||||
auto* environment = vm.lexical_environment();
|
auto* environment = vm.lexical_environment();
|
||||||
|
@ -1954,12 +1949,17 @@ ThrowCompletionOr<ECMAScriptFunctionObject*> ClassExpression::class_definition_e
|
||||||
|
|
||||||
Value super_class;
|
Value super_class;
|
||||||
|
|
||||||
auto reference = TRY(m_super_class->to_reference(interpreter));
|
if (vm.bytecode_interpreter_if_exists()) {
|
||||||
if (reference.is_valid_reference()) {
|
super_class = TRY(vm.execute_ast_node(*m_super_class));
|
||||||
super_class = TRY(reference.get_value(vm));
|
|
||||||
} else {
|
} else {
|
||||||
super_class = TRY(m_super_class->execute(interpreter)).release_value();
|
auto reference = TRY(m_super_class->to_reference(vm.interpreter()));
|
||||||
|
if (reference.is_valid_reference()) {
|
||||||
|
super_class = TRY(reference.get_value(vm));
|
||||||
|
} else {
|
||||||
|
super_class = TRY(vm.execute_ast_node(*m_super_class));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
vm.running_execution_context().lexical_environment = environment;
|
vm.running_execution_context().lexical_environment = environment;
|
||||||
|
|
||||||
if (super_class.is_null()) {
|
if (super_class.is_null()) {
|
||||||
|
@ -1990,7 +1990,7 @@ ThrowCompletionOr<ECMAScriptFunctionObject*> ClassExpression::class_definition_e
|
||||||
};
|
};
|
||||||
|
|
||||||
// FIXME: Step 14.a is done in the parser. By using a synthetic super(...args) which does not call @@iterator of %Array.prototype%
|
// FIXME: Step 14.a is done in the parser. By using a synthetic super(...args) which does not call @@iterator of %Array.prototype%
|
||||||
auto class_constructor_value = TRY(m_constructor->execute(interpreter)).release_value();
|
auto class_constructor_value = TRY(vm.execute_ast_node(*m_constructor));
|
||||||
|
|
||||||
update_function_name(class_constructor_value, class_name);
|
update_function_name(class_constructor_value, class_name);
|
||||||
|
|
||||||
|
@ -2015,7 +2015,7 @@ ThrowCompletionOr<ECMAScriptFunctionObject*> ClassExpression::class_definition_e
|
||||||
|
|
||||||
for (auto const& element : m_elements) {
|
for (auto const& element : m_elements) {
|
||||||
// Note: All ClassElementEvaluation start with evaluating the name (or we fake it).
|
// Note: All ClassElementEvaluation start with evaluating the name (or we fake it).
|
||||||
auto element_value = TRY(element->class_element_evaluation(interpreter, element->is_static() ? *class_constructor : *prototype));
|
auto element_value = TRY(element->class_element_evaluation(vm, element->is_static() ? *class_constructor : *prototype));
|
||||||
|
|
||||||
if (element_value.has<PrivateElement>()) {
|
if (element_value.has<PrivateElement>()) {
|
||||||
auto& container = element->is_static() ? static_private_methods : instance_private_methods;
|
auto& container = element->is_static() ? static_private_methods : instance_private_methods;
|
||||||
|
|
|
@ -1301,7 +1301,7 @@ public:
|
||||||
|
|
||||||
// We use the Completion also as a ClassStaticBlockDefinition Record.
|
// We use the Completion also as a ClassStaticBlockDefinition Record.
|
||||||
using ClassValue = Variant<ClassFieldDefinition, Completion, PrivateElement>;
|
using ClassValue = Variant<ClassFieldDefinition, Completion, PrivateElement>;
|
||||||
virtual ThrowCompletionOr<ClassValue> class_element_evaluation(Interpreter&, Object& home_object) const = 0;
|
virtual ThrowCompletionOr<ClassValue> class_element_evaluation(VM&, Object& home_object) const = 0;
|
||||||
|
|
||||||
virtual Optional<DeprecatedFlyString> private_bound_identifier() const { return {}; };
|
virtual Optional<DeprecatedFlyString> private_bound_identifier() const { return {}; };
|
||||||
|
|
||||||
|
@ -1330,7 +1330,7 @@ public:
|
||||||
virtual ElementKind class_element_kind() const override { return ElementKind::Method; }
|
virtual ElementKind class_element_kind() const override { return ElementKind::Method; }
|
||||||
|
|
||||||
virtual void dump(int indent) const override;
|
virtual void dump(int indent) const override;
|
||||||
virtual ThrowCompletionOr<ClassValue> class_element_evaluation(Interpreter&, Object& home_object) const override;
|
virtual ThrowCompletionOr<ClassValue> class_element_evaluation(VM&, Object& home_object) const override;
|
||||||
virtual Optional<DeprecatedFlyString> private_bound_identifier() const override;
|
virtual Optional<DeprecatedFlyString> private_bound_identifier() const override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
@ -1357,7 +1357,7 @@ public:
|
||||||
virtual ElementKind class_element_kind() const override { return ElementKind::Field; }
|
virtual ElementKind class_element_kind() const override { return ElementKind::Field; }
|
||||||
|
|
||||||
virtual void dump(int indent) const override;
|
virtual void dump(int indent) const override;
|
||||||
virtual ThrowCompletionOr<ClassValue> class_element_evaluation(Interpreter&, Object& home_object) const override;
|
virtual ThrowCompletionOr<ClassValue> class_element_evaluation(VM&, Object& home_object) const override;
|
||||||
virtual Optional<DeprecatedFlyString> private_bound_identifier() const override;
|
virtual Optional<DeprecatedFlyString> private_bound_identifier() const override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
@ -1376,7 +1376,7 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual ElementKind class_element_kind() const override { return ElementKind::StaticInitializer; }
|
virtual ElementKind class_element_kind() const override { return ElementKind::StaticInitializer; }
|
||||||
virtual ThrowCompletionOr<ClassValue> class_element_evaluation(Interpreter&, Object& home_object) const override;
|
virtual ThrowCompletionOr<ClassValue> class_element_evaluation(VM&, Object& home_object) const override;
|
||||||
|
|
||||||
virtual void dump(int indent) const override;
|
virtual void dump(int indent) const override;
|
||||||
|
|
||||||
|
@ -1421,7 +1421,7 @@ public:
|
||||||
|
|
||||||
bool has_name() const { return !m_name.is_empty(); }
|
bool has_name() const { return !m_name.is_empty(); }
|
||||||
|
|
||||||
ThrowCompletionOr<ECMAScriptFunctionObject*> class_definition_evaluation(Interpreter&, DeprecatedFlyString const& binding_name = {}, DeprecatedFlyString const& class_name = {}) const;
|
ThrowCompletionOr<ECMAScriptFunctionObject*> class_definition_evaluation(VM&, DeprecatedFlyString const& binding_name = {}, DeprecatedFlyString const& class_name = {}) const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
virtual bool is_class_expression() const override { return true; }
|
virtual bool is_class_expression() const override { return true; }
|
||||||
|
|
|
@ -1137,16 +1137,15 @@ ThrowCompletionOr<void> IteratorResultValue::execute_impl(Bytecode::Interpreter&
|
||||||
|
|
||||||
ThrowCompletionOr<void> NewClass::execute_impl(Bytecode::Interpreter& interpreter) const
|
ThrowCompletionOr<void> NewClass::execute_impl(Bytecode::Interpreter& interpreter) const
|
||||||
{
|
{
|
||||||
|
auto& vm = interpreter.vm();
|
||||||
auto name = m_class_expression.name();
|
auto name = m_class_expression.name();
|
||||||
auto scope = interpreter.ast_interpreter_scope(interpreter.realm());
|
|
||||||
auto& ast_interpreter = scope.interpreter();
|
|
||||||
|
|
||||||
ECMAScriptFunctionObject* class_object = nullptr;
|
ECMAScriptFunctionObject* class_object = nullptr;
|
||||||
|
|
||||||
if (!m_class_expression.has_name() && m_lhs_name.has_value())
|
if (!m_class_expression.has_name() && m_lhs_name.has_value())
|
||||||
class_object = TRY(m_class_expression.class_definition_evaluation(ast_interpreter, {}, m_lhs_name.value()));
|
class_object = TRY(m_class_expression.class_definition_evaluation(vm, {}, m_lhs_name.value()));
|
||||||
else
|
else
|
||||||
class_object = TRY(m_class_expression.class_definition_evaluation(ast_interpreter, name, name.is_null() ? ""sv : name));
|
class_object = TRY(m_class_expression.class_definition_evaluation(vm, name, name.is_null() ? ""sv : name));
|
||||||
|
|
||||||
class_object->set_source_text(m_class_expression.source_text());
|
class_object->set_source_text(m_class_expression.source_text());
|
||||||
|
|
||||||
|
|
|
@ -291,7 +291,7 @@ ThrowCompletionOr<Value> VM::named_evaluation_if_anonymous_function(ASTNode cons
|
||||||
} else if (is<ClassExpression>(expression)) {
|
} else if (is<ClassExpression>(expression)) {
|
||||||
auto& class_expression = static_cast<ClassExpression const&>(expression);
|
auto& class_expression = static_cast<ClassExpression const&>(expression);
|
||||||
if (!class_expression.has_name()) {
|
if (!class_expression.has_name()) {
|
||||||
return TRY(class_expression.class_definition_evaluation(interpreter(), {}, name));
|
return TRY(class_expression.class_definition_evaluation(*this, {}, name));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue