LibJS: Rename ECMAScriptFunctionObject members to match spec names

Also add the internal slot names as comments, and separate them into
groups of spec and non-spec members.
This will make it easier to compare the implementation code with the
spec, as well as identify internal slots currently missing or only
present on FunctionObject.
This commit is contained in:
Linus Groh 2021-09-24 23:10:21 +02:00
parent e37cf73300
commit d5f90cf187
Notes: sideshowbarker 2024-07-18 03:28:25 +09:00
4 changed files with 31 additions and 29 deletions

View file

@ -23,7 +23,7 @@
namespace JS { namespace JS {
ECMAScriptFunctionObject* ECMAScriptFunctionObject::create(GlobalObject& global_object, const FlyString& name, const Statement& body, Vector<FunctionNode::Parameter> parameters, i32 m_function_length, Environment* parent_scope, FunctionKind kind, bool is_strict, bool is_arrow_function) ECMAScriptFunctionObject* ECMAScriptFunctionObject::create(GlobalObject& global_object, FlyString name, Statement const& ecmascript_code, Vector<FunctionNode::Parameter> parameters, i32 m_function_length, Environment* parent_scope, FunctionKind kind, bool is_strict, bool is_arrow_function)
{ {
Object* prototype = nullptr; Object* prototype = nullptr;
switch (kind) { switch (kind) {
@ -34,31 +34,31 @@ ECMAScriptFunctionObject* ECMAScriptFunctionObject::create(GlobalObject& global_
prototype = global_object.generator_function_prototype(); prototype = global_object.generator_function_prototype();
break; break;
} }
return global_object.heap().allocate<ECMAScriptFunctionObject>(global_object, global_object, name, body, move(parameters), m_function_length, parent_scope, *prototype, kind, is_strict, is_arrow_function); return global_object.heap().allocate<ECMAScriptFunctionObject>(global_object, global_object, move(name), ecmascript_code, move(parameters), m_function_length, parent_scope, *prototype, kind, is_strict, is_arrow_function);
} }
ECMAScriptFunctionObject::ECMAScriptFunctionObject(GlobalObject& global_object, const FlyString& name, const Statement& body, Vector<FunctionNode::Parameter> parameters, i32 function_length, Environment* parent_scope, Object& prototype, FunctionKind kind, bool is_strict, bool is_arrow_function) ECMAScriptFunctionObject::ECMAScriptFunctionObject(GlobalObject& global_object, FlyString name, Statement const& ecmascript_code, Vector<FunctionNode::Parameter> formal_parameters, i32 function_length, Environment* parent_scope, Object& prototype, FunctionKind kind, bool strict, bool is_arrow_function)
: FunctionObject(is_arrow_function ? vm().this_value(global_object) : Value(), {}, prototype) : FunctionObject(is_arrow_function ? vm().this_value(global_object) : Value(), {}, prototype)
, m_name(name)
, m_body(body)
, m_parameters(move(parameters))
, m_environment(parent_scope) , m_environment(parent_scope)
, m_formal_parameters(move(formal_parameters))
, m_ecmascript_code(ecmascript_code)
, m_realm(vm().interpreter_if_exists() ? &vm().interpreter().realm() : nullptr) , m_realm(vm().interpreter_if_exists() ? &vm().interpreter().realm() : nullptr)
, m_strict(strict)
, m_name(move(name))
, m_function_length(function_length) , m_function_length(function_length)
, m_kind(kind) , m_kind(kind)
, m_is_strict(is_strict)
, m_is_arrow_function(is_arrow_function) , m_is_arrow_function(is_arrow_function)
{ {
// NOTE: This logic is from OrdinaryFunctionCreate, https://tc39.es/ecma262/#sec-ordinaryfunctioncreate // NOTE: This logic is from OrdinaryFunctionCreate, https://tc39.es/ecma262/#sec-ordinaryfunctioncreate
if (m_is_arrow_function) if (m_is_arrow_function)
set_this_mode(ThisMode::Lexical); set_this_mode(ThisMode::Lexical);
else if (m_is_strict) else if (m_strict)
set_this_mode(ThisMode::Strict); set_this_mode(ThisMode::Strict);
else else
set_this_mode(ThisMode::Global); set_this_mode(ThisMode::Global);
// 15.1.3 Static Semantics: IsSimpleParameterList, https://tc39.es/ecma262/#sec-static-semantics-issimpleparameterlist // 15.1.3 Static Semantics: IsSimpleParameterList, https://tc39.es/ecma262/#sec-static-semantics-issimpleparameterlist
set_has_simple_parameter_list(all_of(m_parameters, [&](auto& parameter) { set_has_simple_parameter_list(all_of(m_formal_parameters, [&](auto& parameter) {
if (parameter.is_rest) if (parameter.is_rest)
return false; return false;
if (parameter.default_value) if (parameter.default_value)
@ -104,7 +104,7 @@ void ECMAScriptFunctionObject::visit_edges(Visitor& visitor)
FunctionEnvironment* ECMAScriptFunctionObject::create_environment(FunctionObject& function_being_invoked) FunctionEnvironment* ECMAScriptFunctionObject::create_environment(FunctionObject& function_being_invoked)
{ {
HashMap<FlyString, Variable> variables; HashMap<FlyString, Variable> variables;
for (auto& parameter : m_parameters) { for (auto& parameter : m_formal_parameters) {
parameter.binding.visit( parameter.binding.visit(
[&](const FlyString& name) { variables.set(name, { js_undefined(), DeclarationKind::Var }); }, [&](const FlyString& name) { variables.set(name, { js_undefined(), DeclarationKind::Var }); },
[&](const NonnullRefPtr<BindingPattern>& binding) { [&](const NonnullRefPtr<BindingPattern>& binding) {
@ -114,8 +114,8 @@ FunctionEnvironment* ECMAScriptFunctionObject::create_environment(FunctionObject
}); });
} }
if (is<ScopeNode>(body())) { if (is<ScopeNode>(ecmascript_code())) {
for (auto& declaration : static_cast<const ScopeNode&>(body()).variables()) { for (auto& declaration : static_cast<const ScopeNode&>(ecmascript_code()).variables()) {
for (auto& declarator : declaration.declarations()) { for (auto& declarator : declaration.declarations()) {
declarator.target().visit( declarator.target().visit(
[&](const NonnullRefPtr<Identifier>& id) { [&](const NonnullRefPtr<Identifier>& id) {
@ -149,8 +149,8 @@ Value ECMAScriptFunctionObject::execute_function_body()
auto prepare_arguments = [&] { auto prepare_arguments = [&] {
auto& execution_context_arguments = vm.running_execution_context().arguments; auto& execution_context_arguments = vm.running_execution_context().arguments;
for (size_t i = 0; i < m_parameters.size(); ++i) { for (size_t i = 0; i < m_formal_parameters.size(); ++i) {
auto& parameter = m_parameters[i]; auto& parameter = m_formal_parameters[i];
parameter.binding.visit( parameter.binding.visit(
[&](const auto& param) { [&](const auto& param) {
Value argument_value; Value argument_value;
@ -182,7 +182,7 @@ Value ECMAScriptFunctionObject::execute_function_body()
if (bytecode_interpreter) { if (bytecode_interpreter) {
prepare_arguments(); prepare_arguments();
if (!m_bytecode_executable.has_value()) { if (!m_bytecode_executable.has_value()) {
m_bytecode_executable = Bytecode::Generator::generate(m_body, m_kind == FunctionKind::Generator); m_bytecode_executable = Bytecode::Generator::generate(m_ecmascript_code, m_kind == FunctionKind::Generator);
auto& passes = JS::Bytecode::Interpreter::optimization_pipeline(); auto& passes = JS::Bytecode::Interpreter::optimization_pipeline();
passes.perform(*m_bytecode_executable); passes.perform(*m_bytecode_executable);
if constexpr (JS_BYTECODE_DEBUG) { if constexpr (JS_BYTECODE_DEBUG) {
@ -213,7 +213,7 @@ Value ECMAScriptFunctionObject::execute_function_body()
if (vm.exception()) if (vm.exception())
return {}; return {};
return ast_interpreter->execute_statement(global_object(), m_body, ScopeType::Function); return ast_interpreter->execute_statement(global_object(), m_ecmascript_code, ScopeType::Function);
} }
} }

View file

@ -17,14 +17,14 @@ class ECMAScriptFunctionObject final : public FunctionObject {
JS_OBJECT(ECMAScriptFunctionObject, FunctionObject); JS_OBJECT(ECMAScriptFunctionObject, FunctionObject);
public: public:
static ECMAScriptFunctionObject* create(GlobalObject&, const FlyString& name, const Statement& body, Vector<FunctionNode::Parameter> parameters, i32 m_function_length, Environment* parent_scope, FunctionKind, bool is_strict, bool is_arrow_function = false); static ECMAScriptFunctionObject* create(GlobalObject&, FlyString name, Statement const& ecmascript_code, Vector<FunctionNode::Parameter> parameters, i32 m_function_length, Environment* parent_scope, FunctionKind, bool is_strict, bool is_arrow_function = false);
ECMAScriptFunctionObject(GlobalObject&, const FlyString& name, const Statement& body, Vector<FunctionNode::Parameter> parameters, i32 m_function_length, Environment* parent_scope, Object& prototype, FunctionKind, bool is_strict, bool is_arrow_function = false); ECMAScriptFunctionObject(GlobalObject&, FlyString name, Statement const& ecmascript_code, Vector<FunctionNode::Parameter> parameters, i32 m_function_length, Environment* parent_scope, Object& prototype, FunctionKind, bool is_strict, bool is_arrow_function = false);
virtual void initialize(GlobalObject&) override; virtual void initialize(GlobalObject&) override;
virtual ~ECMAScriptFunctionObject(); virtual ~ECMAScriptFunctionObject();
const Statement& body() const { return m_body; } Statement const& ecmascript_code() const { return m_ecmascript_code; }
const Vector<FunctionNode::Parameter>& parameters() const { return m_parameters; }; Vector<FunctionNode::Parameter> const& formal_parameters() const { return m_formal_parameters; };
virtual Value call() override; virtual Value call() override;
virtual Value construct(FunctionObject& new_target) override; virtual Value construct(FunctionObject& new_target) override;
@ -40,7 +40,7 @@ public:
virtual Realm* realm() const override { return m_realm; } virtual Realm* realm() const override { return m_realm; }
protected: protected:
virtual bool is_strict_mode() const final { return m_is_strict; } virtual bool is_strict_mode() const final { return m_strict; }
private: private:
virtual bool is_ecmascript_function_object() const override { return true; } virtual bool is_ecmascript_function_object() const override { return true; }
@ -49,17 +49,19 @@ private:
Value execute_function_body(); Value execute_function_body();
// Internal Slots of ECMAScript Function Objects, https://tc39.es/ecma262/#table-internal-slots-of-ecmascript-function-objects
Environment* m_environment { nullptr }; // [[Environment]]
Vector<FunctionNode::Parameter> const m_formal_parameters; // [[FormalParameters]]
NonnullRefPtr<Statement> m_ecmascript_code; // [[ECMAScriptCode]]
Realm* m_realm { nullptr }; // [[Realm]]
bool m_strict { false }; // [[Strict]]
bool m_is_class_constructor { false }; // [[IsClassConstructor]]
FlyString m_name; FlyString m_name;
NonnullRefPtr<Statement> m_body;
const Vector<FunctionNode::Parameter> m_parameters;
Optional<Bytecode::Executable> m_bytecode_executable; Optional<Bytecode::Executable> m_bytecode_executable;
Environment* m_environment { nullptr };
Realm* m_realm { nullptr };
i32 m_function_length { 0 }; i32 m_function_length { 0 };
FunctionKind m_kind { FunctionKind::Regular }; FunctionKind m_kind { FunctionKind::Regular };
bool m_is_strict { false };
bool m_is_arrow_function { false }; bool m_is_arrow_function { false };
bool m_is_class_constructor { false };
}; };
} }

View file

@ -121,7 +121,7 @@ JS_DEFINE_NATIVE_FUNCTION(FunctionPrototype::to_string)
auto& function = static_cast<ECMAScriptFunctionObject&>(*this_object); auto& function = static_cast<ECMAScriptFunctionObject&>(*this_object);
StringBuilder parameters_builder; StringBuilder parameters_builder;
auto first = true; auto first = true;
for (auto& parameter : function.parameters()) { for (auto& parameter : function.formal_parameters()) {
// FIXME: Also stringify binding patterns. // FIXME: Also stringify binding patterns.
if (auto* name_ptr = parameter.binding.get_pointer<FlyString>()) { if (auto* name_ptr = parameter.binding.get_pointer<FlyString>()) {
if (!first) if (!first)

View file

@ -377,7 +377,7 @@ Value VM::get_variable(const FlyString& name, GlobalObject& global_object)
if (context.function->is_strict_mode() || !context.function->has_simple_parameter_list()) { if (context.function->is_strict_mode() || !context.function->has_simple_parameter_list()) {
context.arguments_object = create_unmapped_arguments_object(global_object, context.arguments.span()); context.arguments_object = create_unmapped_arguments_object(global_object, context.arguments.span());
} else { } else {
context.arguments_object = create_mapped_arguments_object(global_object, *context.function, verify_cast<ECMAScriptFunctionObject>(context.function)->parameters(), context.arguments.span(), *lexical_environment()); context.arguments_object = create_mapped_arguments_object(global_object, *context.function, verify_cast<ECMAScriptFunctionObject>(context.function)->formal_parameters(), context.arguments.span(), *lexical_environment());
} }
} }
return context.arguments_object; return context.arguments_object;