diff --git a/irtoc_scripts/interpreter_handlers.irt b/irtoc_scripts/interpreter_handlers.irt index 84faa434dc3009802ccbb69bb849d016dc55c2e9..f41b4482218686bdbe1fa98ee06642d3d2797dcb 100644 --- a/irtoc_scripts/interpreter_handlers.irt +++ b/irtoc_scripts/interpreter_handlers.irt @@ -1147,7 +1147,7 @@ end macro(:map_ic_slot) do |ic_slot| method_ptr := LoadObject(get_this_func()).ObjField(Constants::JS_FUNCTION_METHOD_FIELD).ptr - mapping := Load(method_ptr, "JSMETHOD_IC_OFFSET_MAPPING_OFFSET").ptr + mapping := Load(method_ptr, "JSMETHOD_IC_MAPPING_OFFSET").ptr Load(mapping, ic_slot).u8 end diff --git a/runtime/asm_defines/asm_defines.def b/runtime/asm_defines/asm_defines.def index 53a5d60e280e6379574a49f18a52c3294c887bec..fa8cb1aa9850da4c7f8e64466a11b5626706962c 100644 --- a/runtime/asm_defines/asm_defines.def +++ b/runtime/asm_defines/asm_defines.def @@ -54,5 +54,5 @@ DEFINE_VALUE(IC_HANDLER_INLINED_PROPS_BIT_START_BIT, panda::ecmascript::HandlerB DEFINE_VALUE(IC_HANDLER_INLINED_PROPS_BIT_MASK, panda::ecmascript::HandlerBase::InlinedPropsBit::MaxValue()) DEFINE_VALUE(IC_HANDLER_HANDLER_KIND_FIELD, static_cast(panda::ecmascript::HandlerBase::HandlerKind::FIELD)) DEFINE_VALUE(HCLASS_DATA_OFFSET, HClass::GetDataOffset()) -DEFINE_VALUE(JSMETHOD_IC_OFFSET_MAPPING_OFFSET, panda::ecmascript::JSMethod::GetICOffsetMappingOffset()) +DEFINE_VALUE(JSMETHOD_IC_MAPPING_OFFSET, panda::ecmascript::JSMethod::GetICMappingOffset()) DEFINE_VALUE(JSTHREAD_GLOBAL_OBJECT_OFFSET, panda::ecmascript::JSThread::GetGlobalObjectOffset()) diff --git a/runtime/class_linker/panda_file_translator.cpp b/runtime/class_linker/panda_file_translator.cpp index 4d2259bdcd229104b07ab94538dade792372e66d..7582a1b1f305b7523fec1be813f8e515446f7065 100644 --- a/runtime/class_linker/panda_file_translator.cpp +++ b/runtime/class_linker/panda_file_translator.cpp @@ -487,15 +487,19 @@ void PandaFileTranslator::UpdateICOffset(JSMethod *method, uint32_t insSz, const default: return; } - uint8_t *icOffsetMapping = method->GetICOffsetMapping(); - if (icOffsetMapping == nullptr && insSz < ProfileTypeInfo::INVALID_SLOT_INDEX) { - icOffsetMapping = mem::InternalAllocator<>::GetInternalAllocatorFromRuntime()->AllocArray(insSz); - memset_s(icOffsetMapping, insSz, 0, insSz); - method->SetICOffsetMapping(icOffsetMapping); + using ICMappingType = JSMethod::ICMappingType; + static_assert(std::is_pointer::value); + using ICMappingElementType = std::remove_pointer::type; + ICMappingType icMapping = method->GetICMapping(); + if (icMapping == nullptr && insSz < ProfileTypeInfo::MAX_FUNCTION_SIZE) { + icMapping = + mem::InternalAllocator<>::GetInternalAllocatorFromRuntime()->AllocArray(insSz); + memset_s(icMapping, insSz, 0, insSz); + method->SetICMapping(icMapping); } - if (icOffsetMapping != nullptr) { + if (icMapping != nullptr) { // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic) - icOffsetMapping[bc_offset] = method->GetSlotSize(); + icMapping[bc_offset] = method->GetSlotSize(); method->AddSlotSize(slotSize); } } diff --git a/runtime/ic/ic_runtime_stub-inl.h b/runtime/ic/ic_runtime_stub-inl.h index 6998d9b8a4604633505b4d8b266a4669244ad7e6..1340d676e9473e38178c94a77a3557dd151bf804 100644 --- a/runtime/ic/ic_runtime_stub-inl.h +++ b/runtime/ic/ic_runtime_stub-inl.h @@ -45,7 +45,7 @@ bool ICRuntimeStub::HaveICForFunction(JSThread *thread) uint32_t ICRuntimeStub::MapSlotId(JSThread *thread, uint32_t slotId) { auto *func = JSFunction::Cast(GetThisFunc(thread).GetHeapObject()); - uint8_t *mapping = func->GetMethod()->GetICOffsetMapping(); + uint8_t *mapping = func->GetMethod()->GetICMapping(); ASSERT(mapping != nullptr); // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic) return mapping[slotId]; diff --git a/runtime/ic/profile_type_info.cpp b/runtime/ic/profile_type_info.cpp index 306d1aeed291aacda784c30b87a2b778da4ae394..3f72ad55ebadefefcd4958c7f57fa816e9f35d0a 100644 --- a/runtime/ic/profile_type_info.cpp +++ b/runtime/ic/profile_type_info.cpp @@ -33,7 +33,7 @@ void ProfileTypeAccessor::AddElementHandler(JSHandle dynclass, JS } // clear key ic if (profileData.IsString() || profileData.IsSymbol()) { - profileTypeInfo_->Set(thread_, index, GetWeakRef(dynclass.GetTaggedValue())); + profileTypeInfo_->Set(thread_, index, dynclass.GetTaggedValue()); profileTypeInfo_->Set(thread_, index + 1, handler.GetTaggedValue()); return; } diff --git a/runtime/ic/profile_type_info.h b/runtime/ic/profile_type_info.h index a8584fbf28d5dcb6b4dd9904c797ea5ab290b247..55910ebe92b4992052333ce5206c8f8c6beed0cc 100644 --- a/runtime/ic/profile_type_info.h +++ b/runtime/ic/profile_type_info.h @@ -86,7 +86,8 @@ std::string ICKindToString(ICKind kind); class ProfileTypeInfo : public TaggedArray { public: static const uint32_t MAX_FUNC_CACHE_INDEX = std::numeric_limits::max(); - static constexpr uint32_t INVALID_SLOT_INDEX = 0xFF; + // Maximal function's bytecode size in byte to create IC for it. + static constexpr uint32_t MAX_FUNCTION_SIZE = 512; static ProfileTypeInfo *Cast(TaggedObject *object) { @@ -123,15 +124,6 @@ public: void AddGlobalHandlerKey(JSHandle key, JSHandle handler) const; void AddGlobalRecordHandler(JSHandle handler) const; - JSTaggedValue GetWeakRef(JSTaggedValue value) const - { - return JSTaggedValue(value.CreateAndGetWeakRef()); - } - - JSTaggedValue GetRefFromWeak(const JSTaggedValue &value) const - { - return JSTaggedValue(value.GetWeakReferent()); - } void SetAsMega() const; ICKind GetKind() const diff --git a/runtime/interpreter/slow_runtime_stub.cpp b/runtime/interpreter/slow_runtime_stub.cpp index 5682c950e0ffeaa3b097a6ba4b3e0c3d516d6f7c..d2b09630c3d2b27ebf9c0692ff1d08cdd08412be 100644 --- a/runtime/interpreter/slow_runtime_stub.cpp +++ b/runtime/interpreter/slow_runtime_stub.cpp @@ -1888,10 +1888,15 @@ JSTaggedValue SlowRuntimeStub::NotifyInlineCache(JSThread *thread, JSFunction *f thread->GetEcmaVM()->AddMethodToProfile(method); } - if (method->GetICOffsetMapping() == nullptr) { + if (method->GetICMapping() == nullptr) { return JSTaggedValue::Undefined(); } uint32_t icSlotSize = method->GetSlotSize(); + static_assert(std::is_pointer::value); + using ICMappingElementType = std::remove_pointer::type; + if (icSlotSize > std::numeric_limits::max()) { + return JSTaggedValue::Undefined(); + } ObjectFactory *factory = thread->GetEcmaVM()->GetFactory(); [[maybe_unused]] EcmaHandleScope handleScope(thread); diff --git a/runtime/js_method.cpp b/runtime/js_method.cpp index bc29b674bbc8da47701fe462746d1e7b63c0e4b5..61fbe03bdd28dc8d4949a58c011a71181a2e240d 100644 --- a/runtime/js_method.cpp +++ b/runtime/js_method.cpp @@ -20,7 +20,7 @@ namespace panda::ecmascript { JSMethod::~JSMethod() { - mem::InternalAllocator<>::GetInternalAllocatorFromRuntime()->Free(icOffsetMapping_); + mem::InternalAllocator<>::GetInternalAllocatorFromRuntime()->Free(icMapping_); } // It's not allowed '#' token appear in ECMA function(method) name, which discriminates same names in panda methods. diff --git a/runtime/js_method.h b/runtime/js_method.h index 04060e7dff478b0a80c6ef2d8c1f1bb309ffbe1f..638ba9715b0be5c870a3c2187340a376f5af26c3 100644 --- a/runtime/js_method.h +++ b/runtime/js_method.h @@ -34,6 +34,8 @@ static constexpr uint32_t HAVE_FUNC_BIT = 8; // 8: the 4th to last bit mea namespace panda::ecmascript { class JSMethod : public Method { public: + using ICMappingType = uint8_t *; + using ConstICMappingType = const uint8_t *; static constexpr uint32_t MAX_SLOT_SIZE = 0xFFFFFFFF; static JSMethod *Cast(Method *method) @@ -92,24 +94,24 @@ public: slotSize_ += size; } - uint8_t *GetICOffsetMapping() + ICMappingType GetICMapping() { - return icOffsetMapping_; + return icMapping_; } - const uint8_t *GetICOffsetMapping() const + ConstICMappingType GetICMapping() const { - return icOffsetMapping_; + return icMapping_; } - void SetICOffsetMapping(uint8_t *mapping) + void SetICMapping(ICMappingType mapping) { - icOffsetMapping_ = mapping; + icMapping_ = mapping; } - static constexpr size_t GetICOffsetMappingOffset() + static constexpr size_t GetICMappingOffset() { - return MEMBER_OFFSET(JSMethod, icOffsetMapping_); + return MEMBER_OFFSET(JSMethod, icMapping_); } uint32_t GetCallType() const @@ -139,7 +141,7 @@ private: PandaUniquePtr profiling_data_; uint32_t bytecodeArraySize_ {0}; uint32_t slotSize_ {0}; - uint8_t *icOffsetMapping_ {nullptr}; + ICMappingType icMapping_ {nullptr}; uint32_t callType_ {UINT32_MAX}; // UINT32_MAX means not found uint32_t profile_size_ {0}; }; diff --git a/runtime/js_object.h b/runtime/js_object.h index 9759e775c3de33605a77ad633eb2ad25749b6149..7dcab9c4c30b592ecab1fbe40818629e1b895e07 100644 --- a/runtime/js_object.h +++ b/runtime/js_object.h @@ -31,6 +31,10 @@ #include "plugins/ecmascript/runtime/property_attributes.h" #include "plugins/ecmascript/runtime/tagged_array.h" +namespace panda::test { +class JSArrayTest; +} // namespace panda::test + namespace panda::ecmascript { class ObjectOperator; @@ -609,6 +613,7 @@ private: friend class FastRuntimeStub; friend class ICRuntimeStub; friend class RuntimeTrampolines; + friend class panda::test::JSArrayTest; static bool AddElementInternal( JSThread *thread, const JSHandle &receiver, uint32_t index, const JSHandle &value, diff --git a/runtime/object_operator.cpp b/runtime/object_operator.cpp index 42fcbc14dd668a3c8efbcdd7e358dd9864658a41..fee65247536b156a8bb1e654b329f6b6f56d65ac 100644 --- a/runtime/object_operator.cpp +++ b/runtime/object_operator.cpp @@ -538,7 +538,10 @@ bool ObjectOperator::AddProperty(const JSHandle &receiver, const JSHan PropertyAttributes attr) { if (IsElement()) { - return JSObject::AddElementInternal(thread_, receiver, elementIndex_, value, attr); + bool ret = JSObject::AddElementInternal(thread_, receiver, elementIndex_, value, attr); + bool isDict = receiver->GetJSHClass()->IsDictionaryElement(); + SetFound(elementIndex_, value.GetTaggedValue(), attr.GetValue(), !isDict); + return ret; } ResetState(); diff --git a/tests/runtime/common/js_array_test.cpp b/tests/runtime/common/js_array_test.cpp index 5625398ee303dad7a04ded86c4a5f2a110cbf247..5adf064b8a80582bdc124d23ca0c3ca925be1276 100644 --- a/tests/runtime/common/js_array_test.cpp +++ b/tests/runtime/common/js_array_test.cpp @@ -47,6 +47,12 @@ public: { TestHelper::DestroyEcmaVMWithScope(instance, scope); } + + bool SetProperty(ObjectOperator *op, const JSHandle &value) + { + return JSObject::SetProperty(op, value, true); + } + PandaVM *instance {nullptr}; EcmaHandleScope *scope {nullptr}; JSThread *thread {nullptr}; @@ -186,4 +192,19 @@ TEST_F(JSArrayTest, Iterator) EXPECT_EQ(i, JSObject::GetProperty(thread, iter_value, element_key).GetValue()->GetInt()); } } + +TEST_F(JSArrayTest, AddProperty) +{ + JSArray *arr = JSArray::ArrayCreate(thread, JSTaggedNumber(0)).GetObject(); + ASSERT_TRUE(arr != nullptr); + JSHandle obj(thread, arr); + JSHandle key(thread, JSTaggedValue(1)); + JSHandle value(thread, JSTaggedValue(true)); + + ObjectOperator op(thread, obj, key); + ASSERT_TRUE(SetProperty(&op, value)); + ASSERT_TRUE(op.IsFound()); + ASSERT_TRUE(op.IsFastMode()); +} + } // namespace panda::test