1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-07-26 06:37:35 +00:00

LibJS/JIT: Compile the PutById bytecode instruction

This commit is contained in:
Andreas Kling 2023-10-20 13:09:35 +02:00
parent 10bf25999c
commit 580249d650
6 changed files with 78 additions and 43 deletions

View file

@ -6,7 +6,9 @@
#include <LibJS/Bytecode/CommonImplementations.h>
#include <LibJS/Bytecode/Interpreter.h>
#include <LibJS/Bytecode/Op.h>
#include <LibJS/Runtime/DeclarativeEnvironment.h>
#include <LibJS/Runtime/ECMAScriptFunctionObject.h>
#include <LibJS/Runtime/GlobalEnvironment.h>
#include <LibJS/Runtime/ObjectEnvironment.h>
@ -139,4 +141,47 @@ ThrowCompletionOr<Value> get_global(Bytecode::Interpreter& interpreter, Identifi
return vm.throw_completion<ReferenceError>(ErrorType::UnknownIdentifier, name);
}
ThrowCompletionOr<void> 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<ECMAScriptFunctionObject>(function))
static_cast<ECMAScriptFunctionObject*>(&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<ECMAScriptFunctionObject>(function))
static_cast<ECMAScriptFunctionObject*>(&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<TypeError>(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 {};
}
}

View file

@ -7,6 +7,7 @@
#pragma once
#include <LibJS/Bytecode/IdentifierTable.h>
#include <LibJS/Bytecode/Op.h>
#include <LibJS/Runtime/Completion.h>
namespace JS::Bytecode {
@ -15,5 +16,6 @@ ThrowCompletionOr<NonnullGCPtr<Object>> base_object_for_get(Bytecode::Interprete
ThrowCompletionOr<Value> get_by_id(Bytecode::Interpreter&, IdentifierTableIndex, Value base_value, Value this_value, u32 cache_index);
ThrowCompletionOr<Value> get_by_value(Bytecode::Interpreter&, Value base_value, Value property_key_value);
ThrowCompletionOr<Value> get_global(Bytecode::Interpreter&, IdentifierTableIndex, u32 cache_index);
ThrowCompletionOr<void> put_by_property_key(VM&, Value base, Value this_value, Value value, PropertyKey name, Op::PropertyKind kind);
}

View file

@ -479,49 +479,6 @@ DeprecatedString Instruction::to_deprecated_string(Bytecode::Executable const& e
namespace JS::Bytecode::Op {
static ThrowCompletionOr<void> 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<ECMAScriptFunctionObject>(function))
static_cast<ECMAScriptFunctionObject*>(&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<ECMAScriptFunctionObject>(function))
static_cast<ECMAScriptFunctionObject*>(&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<TypeError>(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<void> Load::execute_impl(Bytecode::Interpreter&) const
{
// Handled in the interpreter loop.

View file

@ -641,6 +641,10 @@ public:
ThrowCompletionOr<void> 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;