From b1b2ca1485975cc333172c8f351cc8df3468394b Mon Sep 17 00:00:00 2001 From: Andreas Kling Date: Wed, 8 Nov 2023 20:51:26 +0100 Subject: [PATCH] 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. --- .../Spreadsheet/JSIntegration.cpp | 2 +- .../Applications/Spreadsheet/JSIntegration.h | 2 +- .../Libraries/LibJS/Bytecode/ASTCodegen.cpp | 10 ++++---- .../LibJS/Bytecode/CommonImplementations.cpp | 19 +++++++++++++-- .../LibJS/Bytecode/CommonImplementations.h | 2 +- .../Libraries/LibJS/Bytecode/Generator.cpp | 4 ++-- Userland/Libraries/LibJS/Bytecode/Generator.h | 1 + .../Libraries/LibJS/Bytecode/Interpreter.cpp | 6 +++-- Userland/Libraries/LibJS/Bytecode/Op.h | 10 ++++++-- Userland/Libraries/LibJS/JIT/Compiler.cpp | 19 +++++++++------ .../LibJS/Runtime/ArgumentsObject.cpp | 2 +- .../Libraries/LibJS/Runtime/ArgumentsObject.h | 2 +- .../Runtime/ECMAScriptFunctionObject.cpp | 24 ++++++++++++------- .../LibJS/Runtime/ModuleNamespaceObject.cpp | 2 +- .../LibJS/Runtime/ModuleNamespaceObject.h | 2 +- Userland/Libraries/LibJS/Runtime/Object.cpp | 13 +++++++--- Userland/Libraries/LibJS/Runtime/Object.h | 5 ++-- .../Libraries/LibJS/Runtime/ProxyObject.cpp | 2 +- .../Libraries/LibJS/Runtime/ProxyObject.h | 2 +- Userland/Libraries/LibJS/Runtime/TypedArray.h | 2 +- .../LibWeb/Bindings/LegacyPlatformObject.cpp | 2 +- .../LibWeb/Bindings/LegacyPlatformObject.h | 2 +- .../LibWeb/CSS/CSSStyleDeclaration.cpp | 6 ++--- .../LibWeb/CSS/CSSStyleDeclaration.h | 2 +- Userland/Libraries/LibWeb/HTML/Location.cpp | 4 ++-- Userland/Libraries/LibWeb/HTML/Location.h | 2 +- .../Libraries/LibWeb/HTML/WindowProxy.cpp | 2 +- Userland/Libraries/LibWeb/HTML/WindowProxy.h | 2 +- 28 files changed, 99 insertions(+), 54 deletions(-) diff --git a/Userland/Applications/Spreadsheet/JSIntegration.cpp b/Userland/Applications/Spreadsheet/JSIntegration.cpp index 01de13e9824..2cf362ede21 100644 --- a/Userland/Applications/Spreadsheet/JSIntegration.cpp +++ b/Userland/Applications/Spreadsheet/JSIntegration.cpp @@ -129,7 +129,7 @@ JS::ThrowCompletionOr SheetGlobalObject::internal_get(const JS::Prope return Base::internal_get(property_name, receiver); } -JS::ThrowCompletionOr SheetGlobalObject::internal_set(const JS::PropertyKey& property_name, JS::Value value, JS::Value receiver) +JS::ThrowCompletionOr 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()) { diff --git a/Userland/Applications/Spreadsheet/JSIntegration.h b/Userland/Applications/Spreadsheet/JSIntegration.h index 586d55c8f9f..7122e160e27 100644 --- a/Userland/Applications/Spreadsheet/JSIntegration.h +++ b/Userland/Applications/Spreadsheet/JSIntegration.h @@ -29,7 +29,7 @@ public: virtual JS::ThrowCompletionOr internal_has_property(JS::PropertyKey const& name) const override; virtual JS::ThrowCompletionOr internal_get(JS::PropertyKey const&, JS::Value receiver, JS::CacheablePropertyMetadata*) const override; - virtual JS::ThrowCompletionOr internal_set(JS::PropertyKey const&, JS::Value value, JS::Value receiver) override; + virtual JS::ThrowCompletionOr 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); diff --git a/Userland/Libraries/LibJS/Bytecode/ASTCodegen.cpp b/Userland/Libraries/LibJS/Bytecode/ASTCodegen.cpp index 2e73b7303d8..49c4314f300 100644 --- a/Userland/Libraries/LibJS/Bytecode/ASTCodegen.cpp +++ b/Userland/Libraries/LibJS/Bytecode/ASTCodegen.cpp @@ -482,9 +482,9 @@ Bytecode::CodeGenerationErrorOr AssignmentExpression::generate_bytecode(By } else if (expression.property().is_identifier()) { auto identifier_table_ref = generator.intern_identifier(verify_cast(expression.property()).string()); if (!lhs_is_super_expression) - generator.emit(*base_object_register, identifier_table_ref); + generator.emit(*base_object_register, identifier_table_ref, Bytecode::Op::PropertyKind::KeyValue, generator.next_property_lookup_cache()); else - generator.emit(*base_object_register, *this_value_register, identifier_table_ref); + generator.emit(*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(expression.property()).string()); generator.emit(*base_object_register, identifier_table_ref); @@ -985,7 +985,7 @@ Bytecode::CodeGenerationErrorOr ObjectExpression::generate_bytecode(Byteco TRY(generator.emit_named_evaluation_if_anonymous_function(property->value(), name)); } - generator.emit(object_reg, key_name, property_kind); + generator.emit(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(Value(to_underlying(Completion::Type::Return))); - generator.emit(received_completion_register, type_identifier); + generator.emit(received_completion_register, type_identifier, Bytecode::Op::PropertyKind::KeyValue, generator.next_property_lookup_cache()); generator.emit(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 TaggedTemplateLiteral::generate_bytecode(B auto raw_strings_reg = generator.allocate_register(); generator.emit(raw_strings_reg); - generator.emit(strings_reg, generator.intern_identifier("raw")); + generator.emit(strings_reg, generator.intern_identifier("raw"), Bytecode::Op::PropertyKind::KeyValue, generator.next_property_lookup_cache()); generator.emit(js_undefined()); auto this_reg = generator.allocate_register(); diff --git a/Userland/Libraries/LibJS/Bytecode/CommonImplementations.cpp b/Userland/Libraries/LibJS/Bytecode/CommonImplementations.cpp index 1e5dd48b9f9..124cf5f3ada 100644 --- a/Userland/Libraries/LibJS/Bytecode/CommonImplementations.cpp +++ b/Userland/Libraries/LibJS/Bytecode/CommonImplementations.cpp @@ -137,7 +137,7 @@ ThrowCompletionOr get_global(Bytecode::Interpreter& interpreter, Deprecat return vm.throw_completion(ErrorType::UnknownIdentifier, identifier); } -ThrowCompletionOr put_by_property_key(VM& vm, Value base, Value this_value, Value value, PropertyKey name, Op::PropertyKind kind) +ThrowCompletionOr 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 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(ErrorType::ReferenceNullishSetProperty, name, base.to_string_without_side_effects()); diff --git a/Userland/Libraries/LibJS/Bytecode/CommonImplementations.h b/Userland/Libraries/LibJS/Bytecode/CommonImplementations.h index e818e4e8996..369b15af011 100644 --- a/Userland/Libraries/LibJS/Bytecode/CommonImplementations.h +++ b/Userland/Libraries/LibJS/Bytecode/CommonImplementations.h @@ -16,7 +16,7 @@ ThrowCompletionOr> base_object_for_get(VM&, Value base_valu ThrowCompletionOr get_by_id(VM&, DeprecatedFlyString const& property, Value base_value, Value this_value, PropertyLookupCache&); ThrowCompletionOr get_by_value(VM&, Value base_value, Value property_key_value); ThrowCompletionOr get_global(Bytecode::Interpreter&, DeprecatedFlyString const& identifier, GlobalVariableCache&); -ThrowCompletionOr put_by_property_key(VM&, Value base, Value this_value, Value value, PropertyKey name, Op::PropertyKind kind); +ThrowCompletionOr put_by_property_key(VM&, Value base, Value this_value, Value value, PropertyKey name, Op::PropertyKind kind, PropertyLookupCache* = nullptr); ThrowCompletionOr perform_call(Interpreter&, Value this_value, Op::CallType, Value callee, MarkedVector argument_values); ThrowCompletionOr throw_if_needed_for_call(Interpreter&, Value callee, Op::CallType, Optional const& expression_string); ThrowCompletionOr typeof_variable(VM&, DeprecatedFlyString const&); diff --git a/Userland/Libraries/LibJS/Bytecode/Generator.cpp b/Userland/Libraries/LibJS/Bytecode/Generator.cpp index 678904f690b..2d555df9058 100644 --- a/Userland/Libraries/LibJS/Bytecode/Generator.cpp +++ b/Userland/Libraries/LibJS/Bytecode/Generator.cpp @@ -297,7 +297,7 @@ CodeGenerationErrorOr Generator::emit_store_to_reference(JS::ASTNode const } else { // 3. Let propertyKey be StringValue of IdentifierName. auto identifier_table_ref = intern_identifier(verify_cast(expression.property()).string()); - emit(super_reference.base, super_reference.this_value, identifier_table_ref); + emit(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 Generator::emit_store_to_reference(JS::ASTNode const } else if (expression.property().is_identifier()) { emit(value_reg); auto identifier_table_ref = intern_identifier(verify_cast(expression.property()).string()); - emit(object_reg, identifier_table_ref); + emit(object_reg, identifier_table_ref, Bytecode::Op::PropertyKind::KeyValue, next_property_lookup_cache()); } else if (expression.property().is_private_identifier()) { emit(value_reg); auto identifier_table_ref = intern_identifier(verify_cast(expression.property()).string()); diff --git a/Userland/Libraries/LibJS/Bytecode/Generator.h b/Userland/Libraries/LibJS/Bytecode/Generator.h index 4945259277a..30c122e6a26 100644 --- a/Userland/Libraries/LibJS/Bytecode/Generator.h +++ b/Userland/Libraries/LibJS/Bytecode/Generator.h @@ -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 { diff --git a/Userland/Libraries/LibJS/Bytecode/Interpreter.cpp b/Userland/Libraries/LibJS/Bytecode/Interpreter.cpp index 72ff4e3be1b..89b2f90ece9 100644 --- a/Userland/Libraries/LibJS/Bytecode/Interpreter.cpp +++ b/Userland/Libraries/LibJS/Bytecode/Interpreter.cpp @@ -811,7 +811,8 @@ ThrowCompletionOr 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 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 {}; } diff --git a/Userland/Libraries/LibJS/Bytecode/Op.h b/Userland/Libraries/LibJS/Bytecode/Op.h index 8b004c4144f..0dc29512d30 100644 --- a/Userland/Libraries/LibJS/Bytecode/Op.h +++ b/Userland/Libraries/LibJS/Bytecode/Op.h @@ -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 { diff --git a/Userland/Libraries/LibJS/JIT/Compiler.cpp b/Userland/Libraries/LibJS/JIT/Compiler.cpp index 59416c1ebb6..8a214e83b02 100644 --- a/Userland/Libraries/LibJS/JIT/Compiler.cpp +++ b/Userland/Libraries/LibJS/JIT/Compiler.cpp @@ -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(&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(&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(&m_bytecode_executable.property_lookup_caches[op.cache_index()]))); + native_call((void*)cxx_put_by_id_with_this, { Assembler::Operand::Register(GPR0) }); check_exception(); } diff --git a/Userland/Libraries/LibJS/Runtime/ArgumentsObject.cpp b/Userland/Libraries/LibJS/Runtime/ArgumentsObject.cpp index 18b2aa5cf5d..af794c7522c 100644 --- a/Userland/Libraries/LibJS/Runtime/ArgumentsObject.cpp +++ b/Userland/Libraries/LibJS/Runtime/ArgumentsObject.cpp @@ -52,7 +52,7 @@ ThrowCompletionOr 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 ArgumentsObject::internal_set(PropertyKey const& property_key, Value value, Value receiver) +ThrowCompletionOr ArgumentsObject::internal_set(PropertyKey const& property_key, Value value, Value receiver, CacheablePropertyMetadata*) { bool is_mapped = false; diff --git a/Userland/Libraries/LibJS/Runtime/ArgumentsObject.h b/Userland/Libraries/LibJS/Runtime/ArgumentsObject.h index f2d41b4e146..7b9e3f0e63a 100644 --- a/Userland/Libraries/LibJS/Runtime/ArgumentsObject.h +++ b/Userland/Libraries/LibJS/Runtime/ArgumentsObject.h @@ -24,7 +24,7 @@ public: virtual ThrowCompletionOr> internal_get_own_property(PropertyKey const&) const override; virtual ThrowCompletionOr internal_define_own_property(PropertyKey const&, PropertyDescriptor const&) override; virtual ThrowCompletionOr internal_get(PropertyKey const&, Value receiver, CacheablePropertyMetadata*) const override; - virtual ThrowCompletionOr internal_set(PropertyKey const&, Value value, Value receiver) override; + virtual ThrowCompletionOr internal_set(PropertyKey const&, Value value, Value receiver, CacheablePropertyMetadata*) override; virtual ThrowCompletionOr internal_delete(PropertyKey const&) override; virtual bool may_interfere_with_indexed_property_access() const final { return true; } diff --git a/Userland/Libraries/LibJS/Runtime/ECMAScriptFunctionObject.cpp b/Userland/Libraries/LibJS/Runtime/ECMAScriptFunctionObject.cpp index 3f6cf757683..fb4a97279f9 100644 --- a/Userland/Libraries/LibJS/Runtime/ECMAScriptFunctionObject.cpp +++ b/Userland/Libraries/LibJS/Runtime/ECMAScriptFunctionObject.cpp @@ -1153,6 +1153,8 @@ template void async_function_start(VM&, PromiseCapability const&, NonnullRefPtr< template void async_block_start(VM&, SafeFunction const& async_body, PromiseCapability const&, ExecutionContext&); template void async_function_start(VM&, PromiseCapability const&, SafeFunction const& async_function_body); +static HashMap, RefPtr> 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,14 +1168,18 @@ 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) { - size_t default_parameter_index = 0; - for (auto& parameter : m_formal_parameters) { - if (!parameter.default_value) - continue; - auto executable = TRY(Bytecode::compile(vm, *parameter.default_value, FunctionKind::Normal, DeprecatedString::formatted("default parameter #{} for {}", default_parameter_index, m_name))); - m_default_parameter_bytecode_executables.append(move(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) + continue; + auto executable = TRY(Bytecode::compile(vm, *parameter.default_value, FunctionKind::Normal, DeprecatedString::formatted("default parameter #{} for {}", default_parameter_index, m_name))); + m_default_parameter_bytecode_executables.append(move(executable)); + } } } @@ -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()) { diff --git a/Userland/Libraries/LibJS/Runtime/ModuleNamespaceObject.cpp b/Userland/Libraries/LibJS/Runtime/ModuleNamespaceObject.cpp index d6cb4241247..390209971a7 100644 --- a/Userland/Libraries/LibJS/Runtime/ModuleNamespaceObject.cpp +++ b/Userland/Libraries/LibJS/Runtime/ModuleNamespaceObject.cpp @@ -182,7 +182,7 @@ ThrowCompletionOr 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 ModuleNamespaceObject::internal_set(PropertyKey const&, Value, Value) +ThrowCompletionOr ModuleNamespaceObject::internal_set(PropertyKey const&, Value, Value, CacheablePropertyMetadata*) { // 1. Return false. return false; diff --git a/Userland/Libraries/LibJS/Runtime/ModuleNamespaceObject.h b/Userland/Libraries/LibJS/Runtime/ModuleNamespaceObject.h index bddf8e40cd4..25e4d0eb49a 100644 --- a/Userland/Libraries/LibJS/Runtime/ModuleNamespaceObject.h +++ b/Userland/Libraries/LibJS/Runtime/ModuleNamespaceObject.h @@ -26,7 +26,7 @@ public: virtual ThrowCompletionOr internal_define_own_property(PropertyKey const&, PropertyDescriptor const&) override; virtual ThrowCompletionOr internal_has_property(PropertyKey const&) const override; virtual ThrowCompletionOr internal_get(PropertyKey const&, Value receiver, CacheablePropertyMetadata* = nullptr) const override; - virtual ThrowCompletionOr internal_set(PropertyKey const&, Value value, Value receiver) override; + virtual ThrowCompletionOr internal_set(PropertyKey const&, Value value, Value receiver, CacheablePropertyMetadata*) override; virtual ThrowCompletionOr internal_delete(PropertyKey const&) override; virtual ThrowCompletionOr> internal_own_property_keys() const override; virtual void initialize(Realm&) override; diff --git a/Userland/Libraries/LibJS/Runtime/Object.cpp b/Userland/Libraries/LibJS/Runtime/Object.cpp index 86efbcb4fd9..dc2b98b3841 100644 --- a/Userland/Libraries/LibJS/Runtime/Object.cpp +++ b/Userland/Libraries/LibJS/Runtime/Object.cpp @@ -887,7 +887,7 @@ ThrowCompletionOr 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 Object::internal_set(PropertyKey const& property_key, Value value, Value receiver) +ThrowCompletionOr 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 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 Object::ordinary_set_with_own_descriptor(PropertyKey const& property_key, Value value, Value receiver, Optional own_descriptor) +ThrowCompletionOr Object::ordinary_set_with_own_descriptor(PropertyKey const& property_key, Value value, Value receiver, Optional own_descriptor, CacheablePropertyMetadata* cacheable_metadata) { VERIFY(property_key.is_valid()); VERIFY(!value.is_empty()); @@ -957,6 +957,13 @@ ThrowCompletionOr 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)); } diff --git a/Userland/Libraries/LibJS/Runtime/Object.h b/Userland/Libraries/LibJS/Runtime/Object.h index 2885ba6bfa0..5892147d911 100644 --- a/Userland/Libraries/LibJS/Runtime/Object.h +++ b/Userland/Libraries/LibJS/Runtime/Object.h @@ -131,7 +131,7 @@ public: virtual ThrowCompletionOr internal_define_own_property(PropertyKey const&, PropertyDescriptor const&); virtual ThrowCompletionOr internal_has_property(PropertyKey const&) const; virtual ThrowCompletionOr internal_get(PropertyKey const&, Value receiver, CacheablePropertyMetadata* = nullptr) const; - virtual ThrowCompletionOr internal_set(PropertyKey const&, Value value, Value receiver); + virtual ThrowCompletionOr internal_set(PropertyKey const&, Value value, Value receiver, CacheablePropertyMetadata* = nullptr); virtual ThrowCompletionOr internal_delete(PropertyKey const&); virtual ThrowCompletionOr> 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 ordinary_set_with_own_descriptor(PropertyKey const&, Value, Value, Optional); + ThrowCompletionOr ordinary_set_with_own_descriptor(PropertyKey const&, Value, Value, Optional, 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; } diff --git a/Userland/Libraries/LibJS/Runtime/ProxyObject.cpp b/Userland/Libraries/LibJS/Runtime/ProxyObject.cpp index 97ec6f01716..8d1133a8f28 100644 --- a/Userland/Libraries/LibJS/Runtime/ProxyObject.cpp +++ b/Userland/Libraries/LibJS/Runtime/ProxyObject.cpp @@ -525,7 +525,7 @@ ThrowCompletionOr 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 ProxyObject::internal_set(PropertyKey const& property_key, Value value, Value receiver) +ThrowCompletionOr ProxyObject::internal_set(PropertyKey const& property_key, Value value, Value receiver, CacheablePropertyMetadata*) { auto& vm = this->vm(); diff --git a/Userland/Libraries/LibJS/Runtime/ProxyObject.h b/Userland/Libraries/LibJS/Runtime/ProxyObject.h index 8492aaeb914..2b9c44be254 100644 --- a/Userland/Libraries/LibJS/Runtime/ProxyObject.h +++ b/Userland/Libraries/LibJS/Runtime/ProxyObject.h @@ -39,7 +39,7 @@ public: virtual ThrowCompletionOr internal_define_own_property(PropertyKey const&, PropertyDescriptor const&) override; virtual ThrowCompletionOr internal_has_property(PropertyKey const&) const override; virtual ThrowCompletionOr internal_get(PropertyKey const&, Value receiver, CacheablePropertyMetadata*) const override; - virtual ThrowCompletionOr internal_set(PropertyKey const&, Value value, Value receiver) override; + virtual ThrowCompletionOr internal_set(PropertyKey const&, Value value, Value receiver, CacheablePropertyMetadata*) override; virtual ThrowCompletionOr internal_delete(PropertyKey const&) override; virtual ThrowCompletionOr> internal_own_property_keys() const override; virtual ThrowCompletionOr internal_call(Value this_argument, MarkedVector arguments_list) override; diff --git a/Userland/Libraries/LibJS/Runtime/TypedArray.h b/Userland/Libraries/LibJS/Runtime/TypedArray.h index d984321eb51..0ec9cfffeba 100644 --- a/Userland/Libraries/LibJS/Runtime/TypedArray.h +++ b/Userland/Libraries/LibJS/Runtime/TypedArray.h @@ -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 internal_set(PropertyKey const& property_key, Value value, Value receiver) override + virtual ThrowCompletionOr internal_set(PropertyKey const& property_key, Value value, Value receiver, CacheablePropertyMetadata*) override { VERIFY(!value.is_empty()); VERIFY(!receiver.is_empty()); diff --git a/Userland/Libraries/LibWeb/Bindings/LegacyPlatformObject.cpp b/Userland/Libraries/LibWeb/Bindings/LegacyPlatformObject.cpp index 9d95a89f06c..f10d750baa5 100644 --- a/Userland/Libraries/LibWeb/Bindings/LegacyPlatformObject.cpp +++ b/Userland/Libraries/LibWeb/Bindings/LegacyPlatformObject.cpp @@ -156,7 +156,7 @@ JS::ThrowCompletionOr> LegacyPlatformObject::in } // https://webidl.spec.whatwg.org/#legacy-platform-object-set -JS::ThrowCompletionOr LegacyPlatformObject::internal_set(JS::PropertyKey const& property_name, JS::Value value, JS::Value receiver) +JS::ThrowCompletionOr LegacyPlatformObject::internal_set(JS::PropertyKey const& property_name, JS::Value value, JS::Value receiver, JS::CacheablePropertyMetadata*) { auto& vm = this->vm(); diff --git a/Userland/Libraries/LibWeb/Bindings/LegacyPlatformObject.h b/Userland/Libraries/LibWeb/Bindings/LegacyPlatformObject.h index 3316370241b..1feb19ab9fc 100644 --- a/Userland/Libraries/LibWeb/Bindings/LegacyPlatformObject.h +++ b/Userland/Libraries/LibWeb/Bindings/LegacyPlatformObject.h @@ -23,7 +23,7 @@ public: virtual ~LegacyPlatformObject() override; virtual JS::ThrowCompletionOr> internal_get_own_property(JS::PropertyKey const&) const override; - virtual JS::ThrowCompletionOr internal_set(JS::PropertyKey const&, JS::Value, JS::Value) override; + virtual JS::ThrowCompletionOr internal_set(JS::PropertyKey const&, JS::Value, JS::Value, JS::CacheablePropertyMetadata*) override; virtual JS::ThrowCompletionOr internal_define_own_property(JS::PropertyKey const&, JS::PropertyDescriptor const&) override; virtual JS::ThrowCompletionOr internal_delete(JS::PropertyKey const&) override; virtual JS::ThrowCompletionOr internal_prevent_extensions() override; diff --git a/Userland/Libraries/LibWeb/CSS/CSSStyleDeclaration.cpp b/Userland/Libraries/LibWeb/CSS/CSSStyleDeclaration.cpp index 660dbabf788..2310f7f9082 100644 --- a/Userland/Libraries/LibWeb/CSS/CSSStyleDeclaration.cpp +++ b/Userland/Libraries/LibWeb/CSS/CSSStyleDeclaration.cpp @@ -419,14 +419,14 @@ JS::ThrowCompletionOr CSSStyleDeclaration::internal_get(JS::PropertyK return { JS::PrimitiveString::create(vm(), String {}) }; } -JS::ThrowCompletionOr CSSStyleDeclaration::internal_set(JS::PropertyKey const& name, JS::Value value, JS::Value receiver) +JS::ThrowCompletionOr 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)); diff --git a/Userland/Libraries/LibWeb/CSS/CSSStyleDeclaration.h b/Userland/Libraries/LibWeb/CSS/CSSStyleDeclaration.h index f5e8b127dac..e03474272cc 100644 --- a/Userland/Libraries/LibWeb/CSS/CSSStyleDeclaration.h +++ b/Userland/Libraries/LibWeb/CSS/CSSStyleDeclaration.h @@ -42,7 +42,7 @@ public: virtual JS::ThrowCompletionOr internal_has_property(JS::PropertyKey const& name) const override; virtual JS::ThrowCompletionOr internal_get(JS::PropertyKey const&, JS::Value receiver, JS::CacheablePropertyMetadata*) const override; - virtual JS::ThrowCompletionOr internal_set(JS::PropertyKey const&, JS::Value value, JS::Value receiver) override; + virtual JS::ThrowCompletionOr internal_set(JS::PropertyKey const&, JS::Value value, JS::Value receiver, JS::CacheablePropertyMetadata*) override; protected: explicit CSSStyleDeclaration(JS::Realm&); diff --git a/Userland/Libraries/LibWeb/HTML/Location.cpp b/Userland/Libraries/LibWeb/HTML/Location.cpp index f55cdc20552..822c7e0fa7d 100644 --- a/Userland/Libraries/LibWeb/HTML/Location.cpp +++ b/Userland/Libraries/LibWeb/HTML/Location.cpp @@ -507,13 +507,13 @@ JS::ThrowCompletionOr 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 Location::internal_set(JS::PropertyKey const& property_key, JS::Value value, JS::Value receiver) +JS::ThrowCompletionOr 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(*this), property_key, value, receiver); diff --git a/Userland/Libraries/LibWeb/HTML/Location.h b/Userland/Libraries/LibWeb/HTML/Location.h index 756a98014ca..ce769a017ca 100644 --- a/Userland/Libraries/LibWeb/HTML/Location.h +++ b/Userland/Libraries/LibWeb/HTML/Location.h @@ -60,7 +60,7 @@ public: virtual JS::ThrowCompletionOr> internal_get_own_property(JS::PropertyKey const&) const override; virtual JS::ThrowCompletionOr internal_define_own_property(JS::PropertyKey const&, JS::PropertyDescriptor const&) override; virtual JS::ThrowCompletionOr internal_get(JS::PropertyKey const&, JS::Value receiver, JS::CacheablePropertyMetadata*) const override; - virtual JS::ThrowCompletionOr internal_set(JS::PropertyKey const&, JS::Value value, JS::Value receiver) override; + virtual JS::ThrowCompletionOr internal_set(JS::PropertyKey const&, JS::Value value, JS::Value receiver, JS::CacheablePropertyMetadata*) override; virtual JS::ThrowCompletionOr internal_delete(JS::PropertyKey const&) override; virtual JS::ThrowCompletionOr> internal_own_property_keys() const override; diff --git a/Userland/Libraries/LibWeb/HTML/WindowProxy.cpp b/Userland/Libraries/LibWeb/HTML/WindowProxy.cpp index 5d9efbce4fe..443a2f2ab14 100644 --- a/Userland/Libraries/LibWeb/HTML/WindowProxy.cpp +++ b/Userland/Libraries/LibWeb/HTML/WindowProxy.cpp @@ -169,7 +169,7 @@ JS::ThrowCompletionOr 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 WindowProxy::internal_set(JS::PropertyKey const& property_key, JS::Value value, JS::Value receiver) +JS::ThrowCompletionOr WindowProxy::internal_set(JS::PropertyKey const& property_key, JS::Value value, JS::Value receiver, JS::CacheablePropertyMetadata*) { auto& vm = this->vm(); diff --git a/Userland/Libraries/LibWeb/HTML/WindowProxy.h b/Userland/Libraries/LibWeb/HTML/WindowProxy.h index 6d203ce05ce..20ba10b7422 100644 --- a/Userland/Libraries/LibWeb/HTML/WindowProxy.h +++ b/Userland/Libraries/LibWeb/HTML/WindowProxy.h @@ -27,7 +27,7 @@ public: virtual JS::ThrowCompletionOr> internal_get_own_property(JS::PropertyKey const&) const override; virtual JS::ThrowCompletionOr internal_define_own_property(JS::PropertyKey const&, JS::PropertyDescriptor const&) override; virtual JS::ThrowCompletionOr internal_get(JS::PropertyKey const&, JS::Value receiver, JS::CacheablePropertyMetadata*) const override; - virtual JS::ThrowCompletionOr internal_set(JS::PropertyKey const&, JS::Value value, JS::Value receiver) override; + virtual JS::ThrowCompletionOr internal_set(JS::PropertyKey const&, JS::Value value, JS::Value receiver, JS::CacheablePropertyMetadata*) override; virtual JS::ThrowCompletionOr internal_delete(JS::PropertyKey const&) override; virtual JS::ThrowCompletionOr> internal_own_property_keys() const override;