mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2024-11-22 07:30:19 +00:00
LibJS: Add basic monomorphic caching for PutById property access
This patch makes it possible for JS::Object::internal_set() to populate a CacheablePropertyMetadata, and uses this to implement a basic monomorphic cache for the most common form of property write access.
This commit is contained in:
parent
28118623f5
commit
b1b2ca1485
Notes:
sideshowbarker
2024-07-17 00:47:29 +09:00
Author: https://github.com/awesomekling Commit: https://github.com/SerenityOS/serenity/commit/b1b2ca1485 Pull-request: https://github.com/SerenityOS/serenity/pull/21859
28 changed files with 99 additions and 54 deletions
|
@ -129,7 +129,7 @@ JS::ThrowCompletionOr<JS::Value> SheetGlobalObject::internal_get(const JS::Prope
|
|||
return Base::internal_get(property_name, receiver);
|
||||
}
|
||||
|
||||
JS::ThrowCompletionOr<bool> SheetGlobalObject::internal_set(const JS::PropertyKey& property_name, JS::Value value, JS::Value receiver)
|
||||
JS::ThrowCompletionOr<bool> SheetGlobalObject::internal_set(const JS::PropertyKey& property_name, JS::Value value, JS::Value receiver, JS::CacheablePropertyMetadata*)
|
||||
{
|
||||
if (property_name.is_string()) {
|
||||
if (auto pos = m_sheet.parse_cell_name(property_name.as_string()); pos.has_value()) {
|
||||
|
|
|
@ -29,7 +29,7 @@ public:
|
|||
|
||||
virtual JS::ThrowCompletionOr<bool> internal_has_property(JS::PropertyKey const& name) const override;
|
||||
virtual JS::ThrowCompletionOr<JS::Value> internal_get(JS::PropertyKey const&, JS::Value receiver, JS::CacheablePropertyMetadata*) const override;
|
||||
virtual JS::ThrowCompletionOr<bool> internal_set(JS::PropertyKey const&, JS::Value value, JS::Value receiver) override;
|
||||
virtual JS::ThrowCompletionOr<bool> internal_set(JS::PropertyKey const&, JS::Value value, JS::Value receiver, JS::CacheablePropertyMetadata*) override;
|
||||
|
||||
JS_DECLARE_NATIVE_FUNCTION(get_real_cell_contents);
|
||||
JS_DECLARE_NATIVE_FUNCTION(set_real_cell_contents);
|
||||
|
|
|
@ -482,9 +482,9 @@ Bytecode::CodeGenerationErrorOr<void> AssignmentExpression::generate_bytecode(By
|
|||
} else if (expression.property().is_identifier()) {
|
||||
auto identifier_table_ref = generator.intern_identifier(verify_cast<Identifier>(expression.property()).string());
|
||||
if (!lhs_is_super_expression)
|
||||
generator.emit<Bytecode::Op::PutById>(*base_object_register, identifier_table_ref);
|
||||
generator.emit<Bytecode::Op::PutById>(*base_object_register, identifier_table_ref, Bytecode::Op::PropertyKind::KeyValue, generator.next_property_lookup_cache());
|
||||
else
|
||||
generator.emit<Bytecode::Op::PutByIdWithThis>(*base_object_register, *this_value_register, identifier_table_ref);
|
||||
generator.emit<Bytecode::Op::PutByIdWithThis>(*base_object_register, *this_value_register, identifier_table_ref, Bytecode::Op::PropertyKind::KeyValue, generator.next_property_lookup_cache());
|
||||
} else if (expression.property().is_private_identifier()) {
|
||||
auto identifier_table_ref = generator.intern_identifier(verify_cast<PrivateIdentifier>(expression.property()).string());
|
||||
generator.emit<Bytecode::Op::PutPrivateById>(*base_object_register, identifier_table_ref);
|
||||
|
@ -985,7 +985,7 @@ Bytecode::CodeGenerationErrorOr<void> ObjectExpression::generate_bytecode(Byteco
|
|||
TRY(generator.emit_named_evaluation_if_anonymous_function(property->value(), name));
|
||||
}
|
||||
|
||||
generator.emit<Bytecode::Op::PutById>(object_reg, key_name, property_kind);
|
||||
generator.emit<Bytecode::Op::PutById>(object_reg, key_name, property_kind, generator.next_property_lookup_cache());
|
||||
} else {
|
||||
TRY(property->key().generate_bytecode(generator));
|
||||
auto property_reg = generator.allocate_register();
|
||||
|
@ -1695,7 +1695,7 @@ static void generate_yield(Bytecode::Generator& generator, Bytecode::Label conti
|
|||
|
||||
// 5. Return Completion Record { [[Type]]: return, [[Value]]: awaited.[[Value]], [[Target]]: empty }.
|
||||
generator.emit<Bytecode::Op::LoadImmediate>(Value(to_underlying(Completion::Type::Return)));
|
||||
generator.emit<Bytecode::Op::PutById>(received_completion_register, type_identifier);
|
||||
generator.emit<Bytecode::Op::PutById>(received_completion_register, type_identifier, Bytecode::Op::PropertyKind::KeyValue, generator.next_property_lookup_cache());
|
||||
generator.emit<Bytecode::Op::Jump>(Bytecode::Label { load_completion_and_jump_to_continuation_label_block });
|
||||
|
||||
generator.switch_to_basic_block(load_completion_and_jump_to_continuation_label_block);
|
||||
|
@ -2240,7 +2240,7 @@ Bytecode::CodeGenerationErrorOr<void> TaggedTemplateLiteral::generate_bytecode(B
|
|||
auto raw_strings_reg = generator.allocate_register();
|
||||
generator.emit<Bytecode::Op::Store>(raw_strings_reg);
|
||||
|
||||
generator.emit<Bytecode::Op::PutById>(strings_reg, generator.intern_identifier("raw"));
|
||||
generator.emit<Bytecode::Op::PutById>(strings_reg, generator.intern_identifier("raw"), Bytecode::Op::PropertyKind::KeyValue, generator.next_property_lookup_cache());
|
||||
|
||||
generator.emit<Bytecode::Op::LoadImmediate>(js_undefined());
|
||||
auto this_reg = generator.allocate_register();
|
||||
|
|
|
@ -137,7 +137,7 @@ ThrowCompletionOr<Value> get_global(Bytecode::Interpreter& interpreter, Deprecat
|
|||
return vm.throw_completion<ReferenceError>(ErrorType::UnknownIdentifier, identifier);
|
||||
}
|
||||
|
||||
ThrowCompletionOr<void> put_by_property_key(VM& vm, Value base, Value this_value, Value value, PropertyKey name, Op::PropertyKind kind)
|
||||
ThrowCompletionOr<void> put_by_property_key(VM& vm, Value base, Value this_value, Value value, PropertyKey name, Op::PropertyKind kind, PropertyLookupCache* cache)
|
||||
{
|
||||
// Better error message than to_object would give
|
||||
if (vm.in_strict_mode() && base.is_nullish())
|
||||
|
@ -165,7 +165,22 @@ ThrowCompletionOr<void> put_by_property_key(VM& vm, Value base, Value this_value
|
|||
break;
|
||||
}
|
||||
case Op::PropertyKind::KeyValue: {
|
||||
bool succeeded = TRY(object->internal_set(name, value, this_value));
|
||||
if (cache
|
||||
&& cache->shape == &object->shape()
|
||||
&& (!object->shape().is_unique() || object->shape().unique_shape_serial_number() == cache->unique_shape_serial_number)) {
|
||||
object->put_direct(*cache->property_offset, value);
|
||||
return {};
|
||||
}
|
||||
|
||||
CacheablePropertyMetadata cacheable_metadata;
|
||||
bool succeeded = TRY(object->internal_set(name, value, this_value, &cacheable_metadata));
|
||||
|
||||
if (succeeded && cache && cacheable_metadata.type == CacheablePropertyMetadata::Type::OwnProperty) {
|
||||
cache->shape = object->shape();
|
||||
cache->property_offset = cacheable_metadata.property_offset.value();
|
||||
cache->unique_shape_serial_number = object->shape().unique_shape_serial_number();
|
||||
}
|
||||
|
||||
if (!succeeded && vm.in_strict_mode()) {
|
||||
if (base.is_object())
|
||||
return vm.throw_completion<TypeError>(ErrorType::ReferenceNullishSetProperty, name, base.to_string_without_side_effects());
|
||||
|
|
|
@ -16,7 +16,7 @@ ThrowCompletionOr<NonnullGCPtr<Object>> base_object_for_get(VM&, Value base_valu
|
|||
ThrowCompletionOr<Value> get_by_id(VM&, DeprecatedFlyString const& property, Value base_value, Value this_value, PropertyLookupCache&);
|
||||
ThrowCompletionOr<Value> get_by_value(VM&, Value base_value, Value property_key_value);
|
||||
ThrowCompletionOr<Value> get_global(Bytecode::Interpreter&, DeprecatedFlyString const& identifier, GlobalVariableCache&);
|
||||
ThrowCompletionOr<void> put_by_property_key(VM&, Value base, Value this_value, Value value, PropertyKey name, Op::PropertyKind kind);
|
||||
ThrowCompletionOr<void> put_by_property_key(VM&, Value base, Value this_value, Value value, PropertyKey name, Op::PropertyKind kind, PropertyLookupCache* = nullptr);
|
||||
ThrowCompletionOr<Value> perform_call(Interpreter&, Value this_value, Op::CallType, Value callee, MarkedVector<Value> argument_values);
|
||||
ThrowCompletionOr<void> throw_if_needed_for_call(Interpreter&, Value callee, Op::CallType, Optional<StringTableIndex> const& expression_string);
|
||||
ThrowCompletionOr<Value> typeof_variable(VM&, DeprecatedFlyString const&);
|
||||
|
|
|
@ -297,7 +297,7 @@ CodeGenerationErrorOr<void> Generator::emit_store_to_reference(JS::ASTNode const
|
|||
} else {
|
||||
// 3. Let propertyKey be StringValue of IdentifierName.
|
||||
auto identifier_table_ref = intern_identifier(verify_cast<Identifier>(expression.property()).string());
|
||||
emit<Bytecode::Op::PutByIdWithThis>(super_reference.base, super_reference.this_value, identifier_table_ref);
|
||||
emit<Bytecode::Op::PutByIdWithThis>(super_reference.base, super_reference.this_value, identifier_table_ref, Bytecode::Op::PropertyKind::KeyValue, next_property_lookup_cache());
|
||||
}
|
||||
} else {
|
||||
TRY(expression.object().generate_bytecode(*this));
|
||||
|
@ -314,7 +314,7 @@ CodeGenerationErrorOr<void> Generator::emit_store_to_reference(JS::ASTNode const
|
|||
} else if (expression.property().is_identifier()) {
|
||||
emit<Bytecode::Op::Load>(value_reg);
|
||||
auto identifier_table_ref = intern_identifier(verify_cast<Identifier>(expression.property()).string());
|
||||
emit<Bytecode::Op::PutById>(object_reg, identifier_table_ref);
|
||||
emit<Bytecode::Op::PutById>(object_reg, identifier_table_ref, Bytecode::Op::PropertyKind::KeyValue, next_property_lookup_cache());
|
||||
} else if (expression.property().is_private_identifier()) {
|
||||
emit<Bytecode::Op::Load>(value_reg);
|
||||
auto identifier_table_ref = intern_identifier(verify_cast<PrivateIdentifier>(expression.property()).string());
|
||||
|
|
|
@ -236,6 +236,7 @@ public:
|
|||
|
||||
[[nodiscard]] size_t next_global_variable_cache() { return m_next_global_variable_cache++; }
|
||||
[[nodiscard]] size_t next_environment_variable_cache() { return m_next_environment_variable_cache++; }
|
||||
[[nodiscard]] size_t next_property_lookup_cache() { return m_next_property_lookup_cache++; }
|
||||
|
||||
private:
|
||||
enum class JumpType {
|
||||
|
|
|
@ -811,7 +811,8 @@ ThrowCompletionOr<void> PutById::execute_impl(Bytecode::Interpreter& interpreter
|
|||
auto value = interpreter.accumulator();
|
||||
auto base = interpreter.reg(m_base);
|
||||
PropertyKey name = interpreter.current_executable().get_identifier(m_property);
|
||||
TRY(put_by_property_key(vm, base, base, value, name, m_kind));
|
||||
auto& cache = interpreter.current_executable().property_lookup_caches[m_cache_index];
|
||||
TRY(put_by_property_key(vm, base, base, value, name, m_kind, &cache));
|
||||
interpreter.accumulator() = value;
|
||||
return {};
|
||||
}
|
||||
|
@ -823,7 +824,8 @@ ThrowCompletionOr<void> PutByIdWithThis::execute_impl(Bytecode::Interpreter& int
|
|||
auto value = interpreter.accumulator();
|
||||
auto base = interpreter.reg(m_base);
|
||||
PropertyKey name = interpreter.current_executable().get_identifier(m_property);
|
||||
TRY(put_by_property_key(vm, base, interpreter.reg(m_this_value), value, name, m_kind));
|
||||
auto& cache = interpreter.current_executable().property_lookup_caches[m_cache_index];
|
||||
TRY(put_by_property_key(vm, base, interpreter.reg(m_this_value), value, name, m_kind, &cache));
|
||||
interpreter.accumulator() = value;
|
||||
return {};
|
||||
}
|
||||
|
|
|
@ -668,11 +668,12 @@ enum class PropertyKind {
|
|||
|
||||
class PutById final : public Instruction {
|
||||
public:
|
||||
explicit PutById(Register base, IdentifierTableIndex property, PropertyKind kind = PropertyKind::KeyValue)
|
||||
explicit PutById(Register base, IdentifierTableIndex property, PropertyKind kind, u32 cache_index)
|
||||
: Instruction(Type::PutById, sizeof(*this))
|
||||
, m_base(base)
|
||||
, m_property(property)
|
||||
, m_kind(kind)
|
||||
, m_cache_index(cache_index)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -682,21 +683,24 @@ public:
|
|||
Register base() const { return m_base; }
|
||||
IdentifierTableIndex property() const { return m_property; }
|
||||
PropertyKind kind() const { return m_kind; }
|
||||
u32 cache_index() const { return m_cache_index; }
|
||||
|
||||
private:
|
||||
Register m_base;
|
||||
IdentifierTableIndex m_property;
|
||||
PropertyKind m_kind;
|
||||
u32 m_cache_index { 0 };
|
||||
};
|
||||
|
||||
class PutByIdWithThis final : public Instruction {
|
||||
public:
|
||||
PutByIdWithThis(Register base, Register this_value, IdentifierTableIndex property, PropertyKind kind = PropertyKind::KeyValue)
|
||||
PutByIdWithThis(Register base, Register this_value, IdentifierTableIndex property, PropertyKind kind, u32 cache_index)
|
||||
: Instruction(Type::PutByIdWithThis, sizeof(*this))
|
||||
, m_base(base)
|
||||
, m_this_value(this_value)
|
||||
, m_property(property)
|
||||
, m_kind(kind)
|
||||
, m_cache_index(cache_index)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -707,12 +711,14 @@ public:
|
|||
Register this_value() const { return m_this_value; }
|
||||
IdentifierTableIndex property() const { return m_property; }
|
||||
PropertyKind kind() const { return m_kind; }
|
||||
u32 cache_index() const { return m_cache_index; }
|
||||
|
||||
private:
|
||||
Register m_base;
|
||||
Register m_this_value;
|
||||
IdentifierTableIndex m_property;
|
||||
PropertyKind m_kind;
|
||||
u32 m_cache_index { 0 };
|
||||
};
|
||||
|
||||
class PutPrivateById final : public Instruction {
|
||||
|
|
|
@ -1341,10 +1341,9 @@ void Compiler::compile_resolve_this_binding(Bytecode::Op::ResolveThisBinding con
|
|||
end.link(m_assembler);
|
||||
}
|
||||
|
||||
static Value cxx_put_by_id(VM& vm, Value base, Bytecode::IdentifierTableIndex property, Value value, Bytecode::Op::PropertyKind kind)
|
||||
static Value cxx_put_by_id(VM& vm, Value base, DeprecatedFlyString const& property, Value value, Bytecode::Op::PropertyKind kind, Bytecode::PropertyLookupCache& cache)
|
||||
{
|
||||
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));
|
||||
TRY_OR_SET_EXCEPTION(Bytecode::put_by_property_key(vm, base, base, value, property, kind, &cache));
|
||||
return value;
|
||||
}
|
||||
|
||||
|
@ -1353,11 +1352,14 @@ 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::Imm(op.property().value()));
|
||||
Assembler::Operand::Imm(bit_cast<u64>(&m_bytecode_executable.get_identifier(op.property()))));
|
||||
load_accumulator(ARG3);
|
||||
m_assembler.mov(
|
||||
Assembler::Operand::Register(ARG4),
|
||||
Assembler::Operand::Imm(to_underlying(op.kind())));
|
||||
m_assembler.mov(
|
||||
Assembler::Operand::Register(ARG5),
|
||||
Assembler::Operand::Imm(bit_cast<u64>(&m_bytecode_executable.property_lookup_caches[op.cache_index()])));
|
||||
native_call((void*)cxx_put_by_id);
|
||||
store_accumulator(RET);
|
||||
check_exception();
|
||||
|
@ -1896,9 +1898,9 @@ void Compiler::compile_delete_by_id_with_this(Bytecode::Op::DeleteByIdWithThis c
|
|||
store_accumulator(RET);
|
||||
}
|
||||
|
||||
static Value cxx_put_by_id_with_this(VM& vm, Value base, Value value, DeprecatedFlyString const& name, Value this_value, Bytecode::Op::PropertyKind kind)
|
||||
static Value cxx_put_by_id_with_this(VM& vm, Value base, Value value, DeprecatedFlyString const& name, Value this_value, Bytecode::Op::PropertyKind kind, Bytecode::PropertyLookupCache& cache)
|
||||
{
|
||||
TRY_OR_SET_EXCEPTION(Bytecode::put_by_property_key(vm, base, this_value, value, name, kind));
|
||||
TRY_OR_SET_EXCEPTION(Bytecode::put_by_property_key(vm, base, this_value, value, name, kind, &cache));
|
||||
return {};
|
||||
}
|
||||
|
||||
|
@ -1913,7 +1915,10 @@ void Compiler::compile_put_by_id_with_this(Bytecode::Op::PutByIdWithThis const&
|
|||
m_assembler.mov(
|
||||
Assembler::Operand::Register(ARG5),
|
||||
Assembler::Operand::Imm(to_underlying(op.kind())));
|
||||
native_call((void*)cxx_put_by_id_with_this);
|
||||
m_assembler.mov(
|
||||
Assembler::Operand::Register(GPR0),
|
||||
Assembler::Operand::Imm(bit_cast<u64>(&m_bytecode_executable.property_lookup_caches[op.cache_index()])));
|
||||
native_call((void*)cxx_put_by_id_with_this, { Assembler::Operand::Register(GPR0) });
|
||||
check_exception();
|
||||
}
|
||||
|
||||
|
|
|
@ -52,7 +52,7 @@ ThrowCompletionOr<Value> ArgumentsObject::internal_get(PropertyKey const& proper
|
|||
}
|
||||
|
||||
// 10.4.4.4 [[Set]] ( P, V, Receiver ), https://tc39.es/ecma262/#sec-arguments-exotic-objects-set-p-v-receiver
|
||||
ThrowCompletionOr<bool> ArgumentsObject::internal_set(PropertyKey const& property_key, Value value, Value receiver)
|
||||
ThrowCompletionOr<bool> ArgumentsObject::internal_set(PropertyKey const& property_key, Value value, Value receiver, CacheablePropertyMetadata*)
|
||||
{
|
||||
bool is_mapped = false;
|
||||
|
||||
|
|
|
@ -24,7 +24,7 @@ public:
|
|||
virtual ThrowCompletionOr<Optional<PropertyDescriptor>> internal_get_own_property(PropertyKey const&) const override;
|
||||
virtual ThrowCompletionOr<bool> internal_define_own_property(PropertyKey const&, PropertyDescriptor const&) override;
|
||||
virtual ThrowCompletionOr<Value> internal_get(PropertyKey const&, Value receiver, CacheablePropertyMetadata*) const override;
|
||||
virtual ThrowCompletionOr<bool> internal_set(PropertyKey const&, Value value, Value receiver) override;
|
||||
virtual ThrowCompletionOr<bool> internal_set(PropertyKey const&, Value value, Value receiver, CacheablePropertyMetadata*) override;
|
||||
virtual ThrowCompletionOr<bool> internal_delete(PropertyKey const&) override;
|
||||
|
||||
virtual bool may_interfere_with_indexed_property_access() const final { return true; }
|
||||
|
|
|
@ -1153,6 +1153,8 @@ template void async_function_start(VM&, PromiseCapability const&, NonnullRefPtr<
|
|||
template void async_block_start(VM&, SafeFunction<Completion()> const& async_body, PromiseCapability const&, ExecutionContext&);
|
||||
template void async_function_start(VM&, PromiseCapability const&, SafeFunction<Completion()> const& async_function_body);
|
||||
|
||||
static HashMap<NonnullRefPtr<Statement const>, RefPtr<Bytecode::Executable>> executable_cache;
|
||||
|
||||
// 10.2.1.4 OrdinaryCallEvaluateBody ( F, argumentsList ), https://tc39.es/ecma262/#sec-ordinarycallevaluatebody
|
||||
// 15.8.4 Runtime Semantics: EvaluateAsyncFunctionBody, https://tc39.es/ecma262/#sec-runtime-semantics-evaluatefunctionbody
|
||||
Completion ECMAScriptFunctionObject::ordinary_call_evaluate_body()
|
||||
|
@ -1166,8 +1168,11 @@ Completion ECMAScriptFunctionObject::ordinary_call_evaluate_body()
|
|||
// This is why FunctionDeclarationInstantiation is invoked in the middle.
|
||||
// The issue is that FunctionDeclarationInstantiation may mark certain functions as hoisted
|
||||
// per Annex B. This affects code generation for FunctionDeclaration nodes.
|
||||
|
||||
if (!m_bytecode_executable) {
|
||||
auto maybe_cached_executable = executable_cache.get(m_ecmascript_code);
|
||||
if (maybe_cached_executable.has_value()) {
|
||||
m_bytecode_executable = maybe_cached_executable.value();
|
||||
} else {
|
||||
size_t default_parameter_index = 0;
|
||||
for (auto& parameter : m_formal_parameters) {
|
||||
if (!parameter.default_value)
|
||||
|
@ -1176,6 +1181,7 @@ Completion ECMAScriptFunctionObject::ordinary_call_evaluate_body()
|
|||
m_default_parameter_bytecode_executables.append(move(executable));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
auto declaration_result = function_declaration_instantiation();
|
||||
|
||||
|
@ -1184,8 +1190,10 @@ Completion ECMAScriptFunctionObject::ordinary_call_evaluate_body()
|
|||
return declaration_result.release_error();
|
||||
}
|
||||
|
||||
if (!m_bytecode_executable)
|
||||
if (!m_bytecode_executable) {
|
||||
m_bytecode_executable = TRY(Bytecode::compile(vm, *m_ecmascript_code, m_kind, m_name));
|
||||
executable_cache.set(m_ecmascript_code, m_bytecode_executable);
|
||||
}
|
||||
|
||||
if (m_kind == FunctionKind::Async) {
|
||||
if (declaration_result.is_throw_completion()) {
|
||||
|
|
|
@ -182,7 +182,7 @@ ThrowCompletionOr<Value> ModuleNamespaceObject::internal_get(PropertyKey const&
|
|||
}
|
||||
|
||||
// 10.4.6.9 [[Set]] ( P, V, Receiver ), https://tc39.es/ecma262/#sec-module-namespace-exotic-objects-set-p-v-receiver
|
||||
ThrowCompletionOr<bool> ModuleNamespaceObject::internal_set(PropertyKey const&, Value, Value)
|
||||
ThrowCompletionOr<bool> ModuleNamespaceObject::internal_set(PropertyKey const&, Value, Value, CacheablePropertyMetadata*)
|
||||
{
|
||||
// 1. Return false.
|
||||
return false;
|
||||
|
|
|
@ -26,7 +26,7 @@ public:
|
|||
virtual ThrowCompletionOr<bool> internal_define_own_property(PropertyKey const&, PropertyDescriptor const&) override;
|
||||
virtual ThrowCompletionOr<bool> internal_has_property(PropertyKey const&) const override;
|
||||
virtual ThrowCompletionOr<Value> internal_get(PropertyKey const&, Value receiver, CacheablePropertyMetadata* = nullptr) const override;
|
||||
virtual ThrowCompletionOr<bool> internal_set(PropertyKey const&, Value value, Value receiver) override;
|
||||
virtual ThrowCompletionOr<bool> internal_set(PropertyKey const&, Value value, Value receiver, CacheablePropertyMetadata*) override;
|
||||
virtual ThrowCompletionOr<bool> internal_delete(PropertyKey const&) override;
|
||||
virtual ThrowCompletionOr<MarkedVector<Value>> internal_own_property_keys() const override;
|
||||
virtual void initialize(Realm&) override;
|
||||
|
|
|
@ -887,7 +887,7 @@ ThrowCompletionOr<Value> Object::internal_get(PropertyKey const& property_key, V
|
|||
}
|
||||
|
||||
// 10.1.9 [[Set]] ( P, V, Receiver ), https://tc39.es/ecma262/#sec-ordinary-object-internal-methods-and-internal-slots-set-p-v-receiver
|
||||
ThrowCompletionOr<bool> Object::internal_set(PropertyKey const& property_key, Value value, Value receiver)
|
||||
ThrowCompletionOr<bool> Object::internal_set(PropertyKey const& property_key, Value value, Value receiver, CacheablePropertyMetadata* cacheable_metadata)
|
||||
{
|
||||
VERIFY(property_key.is_valid());
|
||||
VERIFY(!value.is_empty());
|
||||
|
@ -897,11 +897,11 @@ ThrowCompletionOr<bool> Object::internal_set(PropertyKey const& property_key, Va
|
|||
auto own_descriptor = TRY(internal_get_own_property(property_key));
|
||||
|
||||
// 3. Return ? OrdinarySetWithOwnDescriptor(O, P, V, Receiver, ownDesc).
|
||||
return ordinary_set_with_own_descriptor(property_key, value, receiver, own_descriptor);
|
||||
return ordinary_set_with_own_descriptor(property_key, value, receiver, own_descriptor, cacheable_metadata);
|
||||
}
|
||||
|
||||
// 10.1.9.2 OrdinarySetWithOwnDescriptor ( O, P, V, Receiver, ownDesc ), https://tc39.es/ecma262/#sec-ordinarysetwithowndescriptor
|
||||
ThrowCompletionOr<bool> Object::ordinary_set_with_own_descriptor(PropertyKey const& property_key, Value value, Value receiver, Optional<PropertyDescriptor> own_descriptor)
|
||||
ThrowCompletionOr<bool> Object::ordinary_set_with_own_descriptor(PropertyKey const& property_key, Value value, Value receiver, Optional<PropertyDescriptor> own_descriptor, CacheablePropertyMetadata* cacheable_metadata)
|
||||
{
|
||||
VERIFY(property_key.is_valid());
|
||||
VERIFY(!value.is_empty());
|
||||
|
@ -957,6 +957,13 @@ ThrowCompletionOr<bool> Object::ordinary_set_with_own_descriptor(PropertyKey con
|
|||
// iii. Let valueDesc be the PropertyDescriptor { [[Value]]: V }.
|
||||
auto value_descriptor = PropertyDescriptor { .value = value };
|
||||
|
||||
if (cacheable_metadata && own_descriptor.has_value() && own_descriptor->property_offset.has_value()) {
|
||||
*cacheable_metadata = CacheablePropertyMetadata {
|
||||
.type = CacheablePropertyMetadata::Type::OwnProperty,
|
||||
.property_offset = own_descriptor->property_offset.value(),
|
||||
};
|
||||
}
|
||||
|
||||
// iv. Return ? Receiver.[[DefineOwnProperty]](P, valueDesc).
|
||||
return TRY(receiver.as_object().internal_define_own_property(property_key, value_descriptor));
|
||||
}
|
||||
|
|
|
@ -131,7 +131,7 @@ public:
|
|||
virtual ThrowCompletionOr<bool> internal_define_own_property(PropertyKey const&, PropertyDescriptor const&);
|
||||
virtual ThrowCompletionOr<bool> internal_has_property(PropertyKey const&) const;
|
||||
virtual ThrowCompletionOr<Value> internal_get(PropertyKey const&, Value receiver, CacheablePropertyMetadata* = nullptr) const;
|
||||
virtual ThrowCompletionOr<bool> internal_set(PropertyKey const&, Value value, Value receiver);
|
||||
virtual ThrowCompletionOr<bool> internal_set(PropertyKey const&, Value value, Value receiver, CacheablePropertyMetadata* = nullptr);
|
||||
virtual ThrowCompletionOr<bool> internal_delete(PropertyKey const&);
|
||||
virtual ThrowCompletionOr<MarkedVector<Value>> internal_own_property_keys() const;
|
||||
|
||||
|
@ -141,7 +141,7 @@ public:
|
|||
// might not hold when property access behaves differently.
|
||||
virtual bool may_interfere_with_indexed_property_access() const { return false; }
|
||||
|
||||
ThrowCompletionOr<bool> ordinary_set_with_own_descriptor(PropertyKey const&, Value, Value, Optional<PropertyDescriptor>);
|
||||
ThrowCompletionOr<bool> ordinary_set_with_own_descriptor(PropertyKey const&, Value, Value, Optional<PropertyDescriptor>, CacheablePropertyMetadata* = nullptr);
|
||||
|
||||
// 10.4.7 Immutable Prototype Exotic Objects, https://tc39.es/ecma262/#sec-immutable-prototype-exotic-objects
|
||||
|
||||
|
@ -193,6 +193,7 @@ public:
|
|||
virtual void visit_edges(Cell::Visitor&) override;
|
||||
|
||||
Value get_direct(size_t index) const { return m_storage[index]; }
|
||||
void put_direct(size_t index, Value value) { m_storage[index] = value; }
|
||||
|
||||
IndexedProperties const& indexed_properties() const { return m_indexed_properties; }
|
||||
IndexedProperties& indexed_properties() { return m_indexed_properties; }
|
||||
|
|
|
@ -525,7 +525,7 @@ ThrowCompletionOr<Value> ProxyObject::internal_get(PropertyKey const& property_k
|
|||
}
|
||||
|
||||
// 10.5.9 [[Set]] ( P, V, Receiver ), https://tc39.es/ecma262/#sec-proxy-object-internal-methods-and-internal-slots-set-p-v-receiver
|
||||
ThrowCompletionOr<bool> ProxyObject::internal_set(PropertyKey const& property_key, Value value, Value receiver)
|
||||
ThrowCompletionOr<bool> ProxyObject::internal_set(PropertyKey const& property_key, Value value, Value receiver, CacheablePropertyMetadata*)
|
||||
{
|
||||
auto& vm = this->vm();
|
||||
|
||||
|
|
|
@ -39,7 +39,7 @@ public:
|
|||
virtual ThrowCompletionOr<bool> internal_define_own_property(PropertyKey const&, PropertyDescriptor const&) override;
|
||||
virtual ThrowCompletionOr<bool> internal_has_property(PropertyKey const&) const override;
|
||||
virtual ThrowCompletionOr<Value> internal_get(PropertyKey const&, Value receiver, CacheablePropertyMetadata*) const override;
|
||||
virtual ThrowCompletionOr<bool> internal_set(PropertyKey const&, Value value, Value receiver) override;
|
||||
virtual ThrowCompletionOr<bool> internal_set(PropertyKey const&, Value value, Value receiver, CacheablePropertyMetadata*) override;
|
||||
virtual ThrowCompletionOr<bool> internal_delete(PropertyKey const&) override;
|
||||
virtual ThrowCompletionOr<MarkedVector<Value>> internal_own_property_keys() const override;
|
||||
virtual ThrowCompletionOr<Value> internal_call(Value this_argument, MarkedVector<Value> arguments_list) override;
|
||||
|
|
|
@ -314,7 +314,7 @@ public:
|
|||
}
|
||||
|
||||
// 10.4.5.5 [[Set]] ( P, V, Receiver ), https://tc39.es/ecma262/#sec-integer-indexed-exotic-objects-set-p-v-receiver
|
||||
virtual ThrowCompletionOr<bool> internal_set(PropertyKey const& property_key, Value value, Value receiver) override
|
||||
virtual ThrowCompletionOr<bool> internal_set(PropertyKey const& property_key, Value value, Value receiver, CacheablePropertyMetadata*) override
|
||||
{
|
||||
VERIFY(!value.is_empty());
|
||||
VERIFY(!receiver.is_empty());
|
||||
|
|
|
@ -156,7 +156,7 @@ JS::ThrowCompletionOr<Optional<JS::PropertyDescriptor>> LegacyPlatformObject::in
|
|||
}
|
||||
|
||||
// https://webidl.spec.whatwg.org/#legacy-platform-object-set
|
||||
JS::ThrowCompletionOr<bool> LegacyPlatformObject::internal_set(JS::PropertyKey const& property_name, JS::Value value, JS::Value receiver)
|
||||
JS::ThrowCompletionOr<bool> LegacyPlatformObject::internal_set(JS::PropertyKey const& property_name, JS::Value value, JS::Value receiver, JS::CacheablePropertyMetadata*)
|
||||
{
|
||||
auto& vm = this->vm();
|
||||
|
||||
|
|
|
@ -23,7 +23,7 @@ public:
|
|||
virtual ~LegacyPlatformObject() override;
|
||||
|
||||
virtual JS::ThrowCompletionOr<Optional<JS::PropertyDescriptor>> internal_get_own_property(JS::PropertyKey const&) const override;
|
||||
virtual JS::ThrowCompletionOr<bool> internal_set(JS::PropertyKey const&, JS::Value, JS::Value) override;
|
||||
virtual JS::ThrowCompletionOr<bool> internal_set(JS::PropertyKey const&, JS::Value, JS::Value, JS::CacheablePropertyMetadata*) override;
|
||||
virtual JS::ThrowCompletionOr<bool> internal_define_own_property(JS::PropertyKey const&, JS::PropertyDescriptor const&) override;
|
||||
virtual JS::ThrowCompletionOr<bool> internal_delete(JS::PropertyKey const&) override;
|
||||
virtual JS::ThrowCompletionOr<bool> internal_prevent_extensions() override;
|
||||
|
|
|
@ -419,14 +419,14 @@ JS::ThrowCompletionOr<JS::Value> CSSStyleDeclaration::internal_get(JS::PropertyK
|
|||
return { JS::PrimitiveString::create(vm(), String {}) };
|
||||
}
|
||||
|
||||
JS::ThrowCompletionOr<bool> CSSStyleDeclaration::internal_set(JS::PropertyKey const& name, JS::Value value, JS::Value receiver)
|
||||
JS::ThrowCompletionOr<bool> CSSStyleDeclaration::internal_set(JS::PropertyKey const& name, JS::Value value, JS::Value receiver, JS::CacheablePropertyMetadata* cacheable_metadata)
|
||||
{
|
||||
auto& vm = this->vm();
|
||||
if (!name.is_string())
|
||||
return Base::internal_set(name, value, receiver);
|
||||
return Base::internal_set(name, value, receiver, cacheable_metadata);
|
||||
auto property_id = property_id_from_name(name.to_string());
|
||||
if (property_id == CSS::PropertyID::Invalid)
|
||||
return Base::internal_set(name, value, receiver);
|
||||
return Base::internal_set(name, value, receiver, cacheable_metadata);
|
||||
|
||||
auto css_text = TRY(value.to_deprecated_string(vm));
|
||||
|
||||
|
|
|
@ -42,7 +42,7 @@ public:
|
|||
|
||||
virtual JS::ThrowCompletionOr<bool> internal_has_property(JS::PropertyKey const& name) const override;
|
||||
virtual JS::ThrowCompletionOr<JS::Value> internal_get(JS::PropertyKey const&, JS::Value receiver, JS::CacheablePropertyMetadata*) const override;
|
||||
virtual JS::ThrowCompletionOr<bool> internal_set(JS::PropertyKey const&, JS::Value value, JS::Value receiver) override;
|
||||
virtual JS::ThrowCompletionOr<bool> internal_set(JS::PropertyKey const&, JS::Value value, JS::Value receiver, JS::CacheablePropertyMetadata*) override;
|
||||
|
||||
protected:
|
||||
explicit CSSStyleDeclaration(JS::Realm&);
|
||||
|
|
|
@ -507,13 +507,13 @@ JS::ThrowCompletionOr<JS::Value> Location::internal_get(JS::PropertyKey const& p
|
|||
}
|
||||
|
||||
// 7.10.5.8 [[Set]] ( P, V, Receiver ), https://html.spec.whatwg.org/multipage/history.html#location-set
|
||||
JS::ThrowCompletionOr<bool> Location::internal_set(JS::PropertyKey const& property_key, JS::Value value, JS::Value receiver)
|
||||
JS::ThrowCompletionOr<bool> Location::internal_set(JS::PropertyKey const& property_key, JS::Value value, JS::Value receiver, JS::CacheablePropertyMetadata* cacheable_metadata)
|
||||
{
|
||||
auto& vm = this->vm();
|
||||
|
||||
// 1. If IsPlatformObjectSameOrigin(this) is true, then return ? OrdinarySet(this, P, V, Receiver).
|
||||
if (HTML::is_platform_object_same_origin(*this))
|
||||
return JS::Object::internal_set(property_key, value, receiver);
|
||||
return JS::Object::internal_set(property_key, value, receiver, cacheable_metadata);
|
||||
|
||||
// 2. Return ? CrossOriginSet(this, P, V, Receiver).
|
||||
return HTML::cross_origin_set(vm, static_cast<JS::Object&>(*this), property_key, value, receiver);
|
||||
|
|
|
@ -60,7 +60,7 @@ public:
|
|||
virtual JS::ThrowCompletionOr<Optional<JS::PropertyDescriptor>> internal_get_own_property(JS::PropertyKey const&) const override;
|
||||
virtual JS::ThrowCompletionOr<bool> internal_define_own_property(JS::PropertyKey const&, JS::PropertyDescriptor const&) override;
|
||||
virtual JS::ThrowCompletionOr<JS::Value> internal_get(JS::PropertyKey const&, JS::Value receiver, JS::CacheablePropertyMetadata*) const override;
|
||||
virtual JS::ThrowCompletionOr<bool> internal_set(JS::PropertyKey const&, JS::Value value, JS::Value receiver) override;
|
||||
virtual JS::ThrowCompletionOr<bool> internal_set(JS::PropertyKey const&, JS::Value value, JS::Value receiver, JS::CacheablePropertyMetadata*) override;
|
||||
virtual JS::ThrowCompletionOr<bool> internal_delete(JS::PropertyKey const&) override;
|
||||
virtual JS::ThrowCompletionOr<JS::MarkedVector<JS::Value>> internal_own_property_keys() const override;
|
||||
|
||||
|
|
|
@ -169,7 +169,7 @@ JS::ThrowCompletionOr<JS::Value> WindowProxy::internal_get(JS::PropertyKey const
|
|||
}
|
||||
|
||||
// 7.4.8 [[Set]] ( P, V, Receiver ), https://html.spec.whatwg.org/multipage/window-object.html#windowproxy-set
|
||||
JS::ThrowCompletionOr<bool> WindowProxy::internal_set(JS::PropertyKey const& property_key, JS::Value value, JS::Value receiver)
|
||||
JS::ThrowCompletionOr<bool> WindowProxy::internal_set(JS::PropertyKey const& property_key, JS::Value value, JS::Value receiver, JS::CacheablePropertyMetadata*)
|
||||
{
|
||||
auto& vm = this->vm();
|
||||
|
||||
|
|
|
@ -27,7 +27,7 @@ public:
|
|||
virtual JS::ThrowCompletionOr<Optional<JS::PropertyDescriptor>> internal_get_own_property(JS::PropertyKey const&) const override;
|
||||
virtual JS::ThrowCompletionOr<bool> internal_define_own_property(JS::PropertyKey const&, JS::PropertyDescriptor const&) override;
|
||||
virtual JS::ThrowCompletionOr<JS::Value> internal_get(JS::PropertyKey const&, JS::Value receiver, JS::CacheablePropertyMetadata*) const override;
|
||||
virtual JS::ThrowCompletionOr<bool> internal_set(JS::PropertyKey const&, JS::Value value, JS::Value receiver) override;
|
||||
virtual JS::ThrowCompletionOr<bool> internal_set(JS::PropertyKey const&, JS::Value value, JS::Value receiver, JS::CacheablePropertyMetadata*) override;
|
||||
virtual JS::ThrowCompletionOr<bool> internal_delete(JS::PropertyKey const&) override;
|
||||
virtual JS::ThrowCompletionOr<JS::MarkedVector<JS::Value>> internal_own_property_keys() const override;
|
||||
|
||||
|
|
Loading…
Reference in a new issue