From 580249d650a4e9a21b081485e789580c78d627c0 Mon Sep 17 00:00:00 2001 From: Andreas Kling Date: Fri, 20 Oct 2023 13:09:35 +0200 Subject: [PATCH] LibJS/JIT: Compile the PutById bytecode instruction --- .../LibJS/Bytecode/CommonImplementations.cpp | 45 +++++++++++++++++++ .../LibJS/Bytecode/CommonImplementations.h | 2 + .../Libraries/LibJS/Bytecode/Interpreter.cpp | 43 ------------------ Userland/Libraries/LibJS/Bytecode/Op.h | 4 ++ Userland/Libraries/LibJS/JIT/Compiler.cpp | 24 ++++++++++ Userland/Libraries/LibJS/JIT/Compiler.h | 3 ++ 6 files changed, 78 insertions(+), 43 deletions(-) diff --git a/Userland/Libraries/LibJS/Bytecode/CommonImplementations.cpp b/Userland/Libraries/LibJS/Bytecode/CommonImplementations.cpp index 2048213c60..00359a01b3 100644 --- a/Userland/Libraries/LibJS/Bytecode/CommonImplementations.cpp +++ b/Userland/Libraries/LibJS/Bytecode/CommonImplementations.cpp @@ -6,7 +6,9 @@ #include #include +#include #include +#include #include #include @@ -139,4 +141,47 @@ ThrowCompletionOr get_global(Bytecode::Interpreter& interpreter, Identifi return vm.throw_completion(ErrorType::UnknownIdentifier, name); } +ThrowCompletionOr put_by_property_key(VM& vm, Value base, Value this_value, Value value, PropertyKey name, Op::PropertyKind kind) +{ + auto object = TRY(base.to_object(vm)); + if (kind == Op::PropertyKind::Getter || kind == Op::PropertyKind::Setter) { + // The generator should only pass us functions for getters and setters. + VERIFY(value.is_function()); + } + switch (kind) { + case Op::PropertyKind::Getter: { + auto& function = value.as_function(); + if (function.name().is_empty() && is(function)) + static_cast(&function)->set_name(DeprecatedString::formatted("get {}", name)); + object->define_direct_accessor(name, &function, nullptr, Attribute::Configurable | Attribute::Enumerable); + break; + } + case Op::PropertyKind::Setter: { + auto& function = value.as_function(); + if (function.name().is_empty() && is(function)) + static_cast(&function)->set_name(DeprecatedString::formatted("set {}", name)); + object->define_direct_accessor(name, nullptr, &function, Attribute::Configurable | Attribute::Enumerable); + break; + } + case Op::PropertyKind::KeyValue: { + bool succeeded = TRY(object->internal_set(name, value, this_value)); + if (!succeeded && vm.in_strict_mode()) + return vm.throw_completion(ErrorType::ReferenceNullishSetProperty, name, base.to_string_without_side_effects()); + break; + } + case Op::PropertyKind::DirectKeyValue: + object->define_direct_property(name, value, Attribute::Enumerable | Attribute::Writable | Attribute::Configurable); + break; + case Op::PropertyKind::Spread: + TRY(object->copy_data_properties(vm, value, {})); + break; + case Op::PropertyKind::ProtoSetter: + if (value.is_object() || value.is_null()) + MUST(object->internal_set_prototype_of(value.is_object() ? &value.as_object() : nullptr)); + break; + } + + return {}; +} + } diff --git a/Userland/Libraries/LibJS/Bytecode/CommonImplementations.h b/Userland/Libraries/LibJS/Bytecode/CommonImplementations.h index 222e4ad327..81edbbb8c7 100644 --- a/Userland/Libraries/LibJS/Bytecode/CommonImplementations.h +++ b/Userland/Libraries/LibJS/Bytecode/CommonImplementations.h @@ -7,6 +7,7 @@ #pragma once #include +#include #include namespace JS::Bytecode { @@ -15,5 +16,6 @@ ThrowCompletionOr> base_object_for_get(Bytecode::Interprete ThrowCompletionOr get_by_id(Bytecode::Interpreter&, IdentifierTableIndex, Value base_value, Value this_value, u32 cache_index); ThrowCompletionOr get_by_value(Bytecode::Interpreter&, Value base_value, Value property_key_value); ThrowCompletionOr get_global(Bytecode::Interpreter&, IdentifierTableIndex, u32 cache_index); +ThrowCompletionOr put_by_property_key(VM&, Value base, Value this_value, Value value, PropertyKey name, Op::PropertyKind kind); } diff --git a/Userland/Libraries/LibJS/Bytecode/Interpreter.cpp b/Userland/Libraries/LibJS/Bytecode/Interpreter.cpp index 0cec07fcff..5a0417160a 100644 --- a/Userland/Libraries/LibJS/Bytecode/Interpreter.cpp +++ b/Userland/Libraries/LibJS/Bytecode/Interpreter.cpp @@ -479,49 +479,6 @@ DeprecatedString Instruction::to_deprecated_string(Bytecode::Executable const& e namespace JS::Bytecode::Op { -static ThrowCompletionOr put_by_property_key(VM& vm, Value base, Value this_value, Value value, PropertyKey name, PropertyKind kind) -{ - auto object = TRY(base.to_object(vm)); - if (kind == PropertyKind::Getter || kind == PropertyKind::Setter) { - // The generator should only pass us functions for getters and setters. - VERIFY(value.is_function()); - } - switch (kind) { - case PropertyKind::Getter: { - auto& function = value.as_function(); - if (function.name().is_empty() && is(function)) - static_cast(&function)->set_name(DeprecatedString::formatted("get {}", name)); - object->define_direct_accessor(name, &function, nullptr, Attribute::Configurable | Attribute::Enumerable); - break; - } - case PropertyKind::Setter: { - auto& function = value.as_function(); - if (function.name().is_empty() && is(function)) - static_cast(&function)->set_name(DeprecatedString::formatted("set {}", name)); - object->define_direct_accessor(name, nullptr, &function, Attribute::Configurable | Attribute::Enumerable); - break; - } - case PropertyKind::KeyValue: { - bool succeeded = TRY(object->internal_set(name, value, this_value)); - if (!succeeded && vm.in_strict_mode()) - return vm.throw_completion(ErrorType::ReferenceNullishSetProperty, name, base.to_string_without_side_effects()); - break; - } - case PropertyKind::DirectKeyValue: - object->define_direct_property(name, value, Attribute::Enumerable | Attribute::Writable | Attribute::Configurable); - break; - case PropertyKind::Spread: - TRY(object->copy_data_properties(vm, value, {})); - break; - case PropertyKind::ProtoSetter: - if (value.is_object() || value.is_null()) - MUST(object->internal_set_prototype_of(value.is_object() ? &value.as_object() : nullptr)); - break; - } - - return {}; -} - ThrowCompletionOr Load::execute_impl(Bytecode::Interpreter&) const { // Handled in the interpreter loop. diff --git a/Userland/Libraries/LibJS/Bytecode/Op.h b/Userland/Libraries/LibJS/Bytecode/Op.h index 0ee7b949a0..14052dd181 100644 --- a/Userland/Libraries/LibJS/Bytecode/Op.h +++ b/Userland/Libraries/LibJS/Bytecode/Op.h @@ -641,6 +641,10 @@ public: ThrowCompletionOr execute_impl(Bytecode::Interpreter&) const; DeprecatedString to_deprecated_string_impl(Bytecode::Executable const&) const; + Register base() const { return m_base; } + IdentifierTableIndex property() const { return m_property; } + PropertyKind kind() const { return m_kind; } + private: Register m_base; IdentifierTableIndex m_property; diff --git a/Userland/Libraries/LibJS/JIT/Compiler.cpp b/Userland/Libraries/LibJS/JIT/Compiler.cpp index b403ce5252..abbd9c5125 100644 --- a/Userland/Libraries/LibJS/JIT/Compiler.cpp +++ b/Userland/Libraries/LibJS/JIT/Compiler.cpp @@ -459,6 +459,27 @@ void Compiler::compile_resolve_this_binding(Bytecode::Op::ResolveThisBinding con check_exception(); } +static Value cxx_put_by_id(VM& vm, Value base, Bytecode::IdentifierTableIndex property, Value value, Bytecode::Op::PropertyKind kind) +{ + PropertyKey name = vm.bytecode_interpreter().current_executable().get_identifier(property); + TRY_OR_SET_EXCEPTION(Bytecode::put_by_property_key(vm, base, base, value, name, kind)); + return {}; +} + +void Compiler::compile_put_by_id(Bytecode::Op::PutById const& op) +{ + load_vm_register(ARG1, op.base()); + m_assembler.mov( + Assembler::Operand::Register(ARG2), + Assembler::Operand::Imm64(op.property().value())); + load_vm_register(ARG3, Bytecode::Register::accumulator()); + m_assembler.mov( + Assembler::Operand::Register(ARG4), + Assembler::Operand::Imm64(to_underlying(op.kind()))); + m_assembler.native_call((void*)cxx_put_by_id); + check_exception(); +} + OwnPtr Compiler::compile(Bytecode::Executable& bytecode_executable) { if (getenv("LIBJS_NO_JIT")) @@ -535,6 +556,9 @@ OwnPtr Compiler::compile(Bytecode::Executable& bytecode_execut case Bytecode::Instruction::Type::GetGlobal: compiler.compile_get_global(static_cast(op)); break; + case Bytecode::Instruction::Type::PutById: + compiler.compile_put_by_id(static_cast(op)); + break; case Bytecode::Instruction::Type::ToNumeric: compiler.compile_to_numeric(static_cast(op)); break; diff --git a/Userland/Libraries/LibJS/JIT/Compiler.h b/Userland/Libraries/LibJS/JIT/Compiler.h index 5941172249..9206b08039 100644 --- a/Userland/Libraries/LibJS/JIT/Compiler.h +++ b/Userland/Libraries/LibJS/JIT/Compiler.h @@ -24,6 +24,7 @@ private: static constexpr auto ARG1 = Assembler::Reg::RSI; static constexpr auto ARG2 = Assembler::Reg::RDX; static constexpr auto ARG3 = Assembler::Reg::RCX; + static constexpr auto ARG4 = Assembler::Reg::R8; static constexpr auto RET = Assembler::Reg::RAX; static constexpr auto STACK_POINTER = Assembler::Reg::RSP; static constexpr auto REGISTER_ARRAY_BASE = Assembler::Reg::R13; @@ -57,6 +58,8 @@ private: void compile_get_by_value(Bytecode::Op::GetByValue const&); void compile_get_global(Bytecode::Op::GetGlobal const&); + void compile_put_by_id(Bytecode::Op::PutById const&); + void store_vm_register(Bytecode::Register, Assembler::Reg); void load_vm_register(Assembler::Reg, Bytecode::Register);