From 6477b1fb74ca7d5e2eb5777bb3b43e92551a2286 Mon Sep 17 00:00:00 2001 From: zhangyinlu Date: Thu, 7 Aug 2025 15:58:53 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E5=A4=8DStore=E5=9C=A8retype=E5=89=8D?= =?UTF-8?q?=E8=A2=AB=E8=AF=AF=E7=94=A8=E7=9A=84=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Issue:https://gitee.com/openharmony/arkcompiler_ets_runtime/issues/ICRUKE Description:修复Store在retype前被误用的问题 Signed-off-by: zhangyinlu Change-Id: I6a4b6622b1d0b1202410bb59875d27934b65dbf1 --- ecmascript/compiler/circuit_builder.cpp | 23 +++++++++++++++++++ ecmascript/compiler/circuit_builder.h | 5 ++++ ecmascript/compiler/early_elimination.cpp | 4 +++- ecmascript/compiler/gate_accessor.cpp | 6 +++-- ecmascript/compiler/hcr_circuit_builder.h | 8 +++++++ ecmascript/compiler/mcr_circuit_builder.cpp | 17 ++++++++++++++ ecmascript/compiler/mcr_lowering.cpp | 16 +++++++++++++ ecmascript/compiler/mcr_lowering.h | 1 + ecmascript/compiler/mcr_opcodes.h | 1 + .../compiler/number_speculative_retype.cpp | 1 + .../compiler/typed_bytecode_lowering.cpp | 4 ++-- ecmascript/message_string.h | 3 ++- test/jittest/jit_test_0001/expect_output.txt | 1 + test/jittest/jit_test_0001/jit_test_0001.ts | 19 +++++++++++++++ 14 files changed, 103 insertions(+), 6 deletions(-) diff --git a/ecmascript/compiler/circuit_builder.cpp b/ecmascript/compiler/circuit_builder.cpp index e38f53c00c..a5501bfac9 100644 --- a/ecmascript/compiler/circuit_builder.cpp +++ b/ecmascript/compiler/circuit_builder.cpp @@ -725,6 +725,29 @@ void CircuitBuilder::CheckHClassFieldInvalidAccess([[maybe_unused]]GateRef glue, #endif } +void CircuitBuilder::CheckHClassAddrInvalid([[maybe_unused]]GateRef glue, [[maybe_unused]] GateRef hClass) +{ +#ifndef NDEBUG + Label entryPass(env_); + SubCfgEntry(&entryPass); + Label exit(env_); + Label failed(env_); + constexpr uint64_t highHClassMask = 0xFFFFFFFF00000000ul; + GateRef highHClass = Int64And(TaggedPointerToInt64(hClass), Int64(highHClassMask)); + GateRef expectHighHClass = TaggedPointerToInt64(LoadWithoutBarrier(VariableType::JS_POINTER(), glue, + IntPtr(JSThread::GlueData::GetBaseAddressOffset(env_->Is32Bit())))); + BRANCH_UNLIKELY(Int64NotEqual(expectHighHClass, highHClass), &failed, &exit); + Bind(&failed); + { + CallNGCRuntime(glue, RTSTUB_ID(FatalPrint), Gate::InvalidGateRef, + {Int32(GET_MESSAGE_STRING_ID(HClassAddressIsInvalid))}, glue); + Jump(&exit); + } + Bind(&exit); + SubCfgExit(); +#endif +} + GateRef CircuitBuilder::GetPrototypeFromHClass(GateRef glue, GateRef hClass) { CheckHClassFieldInvalidAccess(glue, hClass); diff --git a/ecmascript/compiler/circuit_builder.h b/ecmascript/compiler/circuit_builder.h index 56220329c2..cd9328f6a1 100644 --- a/ecmascript/compiler/circuit_builder.h +++ b/ecmascript/compiler/circuit_builder.h @@ -363,6 +363,7 @@ public: GateRef GetEmptyArray(GateRef glue); GateRef IsCompositeHClass(GateRef hClass); void CheckHClassFieldInvalidAccess(GateRef glue, GateRef hClass); + void CheckHClassAddrInvalid(GateRef glue, GateRef hClass); GateRef GetPrototypeFromHClass(GateRef glue, GateRef hClass); GateRef GetEnumCacheFromHClass(GateRef glue, GateRef hClass); GateRef GetProtoChangeMarkerFromHClass(GateRef glue, GateRef hClass); @@ -568,6 +569,8 @@ public: // It must keeps high 32 bits field when store hclass to object header. inline void TransitionHClass(GateRef glue, GateRef object, GateRef hClass, MemoryAttribute mAttr = MemoryAttribute::NeedBarrier()); + inline void TransitionHClassByConstOffset(GateRef glue, GateRef object, GateRef hClass, + MemoryAttribute mAttr = MemoryAttribute::NeedBarrier()); inline void StorePrototype(GateRef glue, GateRef hclass, GateRef prototype); void SetExtensibleToBitfield(GateRef glue, GateRef obj, bool isExtensible); @@ -758,6 +761,8 @@ public: inline void SetValueToTaggedArray(VariableType valType, GateRef glue, GateRef array, GateRef index, GateRef val); GateRef StoreConstOffset(VariableType type, GateRef receiver, size_t offset, GateRef value, MemoryAttribute mAttr = MemoryAttribute::Default()); + GateRef StoreHClassConstOffset(VariableType type, GateRef receiver, GateRef value, GateRef compValue, + MemoryAttribute mAttr = MemoryAttribute::Default()); inline GateRef StoreToTaggedArray(GateRef array, size_t index, GateRef value); GateRef StringEqual(GateRef x, GateRef y); GateRef StringAdd(GateRef x, GateRef y, uint32_t stringStatus = 0); diff --git a/ecmascript/compiler/early_elimination.cpp b/ecmascript/compiler/early_elimination.cpp index f30f6a6f77..e49604a605 100644 --- a/ecmascript/compiler/early_elimination.cpp +++ b/ecmascript/compiler/early_elimination.cpp @@ -252,6 +252,7 @@ DependInfoNode* EarlyElimination::UpdateWrite(GateRef gate, DependInfoNode* depe case OpCode::STORE_PROPERTY: case OpCode::STORE_PROPERTY_NO_BARRIER: case OpCode::STORE_CONST_OFFSET: + case OpCode::STORE_HCLASS_CONST_OFFSET: case OpCode::STORE_ELEMENT: case OpCode::STORE_MEMORY: case OpCode::MIGRATE_ARRAY_WITH_KIND: @@ -302,7 +303,8 @@ bool EarlyElimination::MayAccessOneMemory(GateRef lhs, GateRef rhs) } break; } - case OpCode::STORE_CONST_OFFSET: { + case OpCode::STORE_CONST_OFFSET: + case OpCode::STORE_HCLASS_CONST_OFFSET: { if (lop == OpCode::LOAD_CONST_OFFSET || lop == OpCode::LOAD_HCLASS_CONST_OFFSET) { auto loff = acc_.GetOffset(lhs); auto roff = acc_.GetOffset(rhs); diff --git a/ecmascript/compiler/gate_accessor.cpp b/ecmascript/compiler/gate_accessor.cpp index 230cc03a32..d0ac83c726 100644 --- a/ecmascript/compiler/gate_accessor.cpp +++ b/ecmascript/compiler/gate_accessor.cpp @@ -104,7 +104,8 @@ size_t GateAccessor::GetOffset(GateRef gate) const { ASSERT(GetOpCode(gate) == OpCode::LOAD_CONST_OFFSET || GetOpCode(gate) == OpCode::LOAD_HCLASS_CONST_OFFSET || - GetOpCode(gate) == OpCode::STORE_CONST_OFFSET); + GetOpCode(gate) == OpCode::STORE_CONST_OFFSET || + GetOpCode(gate) == OpCode::STORE_HCLASS_CONST_OFFSET); Gate *gatePtr = circuit_->LoadGatePtr(gate); auto accessor = LoadStoreConstOffsetAccessor(gatePtr->GetOneParameterMetaData()->GetValue()); return accessor.GetOffset(); @@ -149,7 +150,8 @@ MemoryAttribute GateAccessor::GetMemoryAttribute(GateRef gate) const } case OpCode::LOAD_CONST_OFFSET: case OpCode::LOAD_HCLASS_CONST_OFFSET: - case OpCode::STORE_CONST_OFFSET: { + case OpCode::STORE_CONST_OFFSET: + case OpCode::STORE_HCLASS_CONST_OFFSET: { auto accessor = LoadStoreConstOffsetAccessor(gatePtr->GetOneParameterMetaData()->GetValue()); return accessor.GetMemoryAttribute(); } diff --git a/ecmascript/compiler/hcr_circuit_builder.h b/ecmascript/compiler/hcr_circuit_builder.h index 6769f968a1..3b02cf9e26 100644 --- a/ecmascript/compiler/hcr_circuit_builder.h +++ b/ecmascript/compiler/hcr_circuit_builder.h @@ -284,11 +284,19 @@ void CircuitBuilder::StoreHClass(GateRef glue, GateRef object, GateRef hClass, M void CircuitBuilder::TransitionHClass(GateRef glue, GateRef object, GateRef hClass, MemoryAttribute mAttr) { + CheckHClassAddrInvalid(glue, hClass); GateRef compValue = TruncInt64ToInt32(TaggedPointerToInt64(hClass)); StoreHClass(VariableType::JS_POINTER(), glue, object, IntPtr(TaggedObject::HCLASS_OFFSET), hClass, compValue, mAttr); } +void CircuitBuilder::TransitionHClassByConstOffset(GateRef glue, GateRef object, GateRef hClass, MemoryAttribute mAttr) +{ + CheckHClassAddrInvalid(glue, hClass); + GateRef compValue = TruncInt64ToInt32(TaggedPointerToInt64(hClass)); + StoreHClassConstOffset(VariableType::JS_POINTER(), object, hClass, compValue, mAttr); +} + void CircuitBuilder::StorePrototype(GateRef glue, GateRef hclass, GateRef prototype) { CheckHClassFieldInvalidAccess(glue, hclass); diff --git a/ecmascript/compiler/mcr_circuit_builder.cpp b/ecmascript/compiler/mcr_circuit_builder.cpp index 7154bc495a..00418a13ca 100644 --- a/ecmascript/compiler/mcr_circuit_builder.cpp +++ b/ecmascript/compiler/mcr_circuit_builder.cpp @@ -1106,6 +1106,23 @@ GateRef CircuitBuilder::StoreConstOffset(VariableType type, return ret; } +GateRef CircuitBuilder::StoreHClassConstOffset(VariableType type, GateRef receiver, GateRef value, + GateRef compValue, MemoryAttribute mAttr) +{ + auto currentLabel = env_->GetCurrentLabel(); + auto currentDepend = currentLabel->GetDepend(); + if (mAttr.GetBarrier() == MemoryAttribute::Barrier::UNKNOWN_BARRIER && acc_.IsConstant(value)) { + mAttr.SetBarrier(MemoryAttribute::Barrier::NO_BARRIER); + } + size_t offset = TaggedObject::HCLASS_OFFSET; + auto bits = LoadStoreConstOffsetAccessor::ToValue(offset, mAttr); + auto ret = GetCircuit()->NewGate(circuit_->StoreHClassConstOffset(bits), type.GetMachineType(), + { currentDepend, receiver, value, compValue }, type.GetGateType()); + currentLabel->SetDepend(ret); + return ret; +} + + GateRef CircuitBuilder::TaggedIsHeapObjectOp(GateRef value) { auto currentLabel = env_->GetCurrentLabel(); diff --git a/ecmascript/compiler/mcr_lowering.cpp b/ecmascript/compiler/mcr_lowering.cpp index 3e954de69d..08d11f8ad5 100644 --- a/ecmascript/compiler/mcr_lowering.cpp +++ b/ecmascript/compiler/mcr_lowering.cpp @@ -47,6 +47,9 @@ GateRef MCRLowering::VisitGate(GateRef gate) case OpCode::STORE_CONST_OFFSET: LowerStoreConstOffset(gate); break; + case OpCode::STORE_HCLASS_CONST_OFFSET: + LowerStoreHClassConstOffset(gate); + break; case OpCode::CONVERT_HOLE_AS_UNDEFINED: LowerConvertHoleAsUndefined(gate); break; @@ -210,6 +213,19 @@ void MCRLowering::LowerStoreConstOffset(GateRef gate) acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), Circuit::NullGate()); } +void MCRLowering::LowerStoreHClassConstOffset(GateRef gate) +{ + Environment env(gate, circuit_, &builder_); + + GateRef receiver = acc_.GetValueIn(gate, 0); + GateRef value = acc_.GetValueIn(gate, 1); + GateRef compValue = acc_.GetValueIn(gate, 2); // 2: compValue + GateRef offset = builder_.IntPtr(acc_.GetOffset(gate)); + VariableType type = VariableType(acc_.GetMachineType(gate), acc_.GetGateType(gate)); + builder_.StoreHClass(type, glue_, receiver, offset, value, compValue, acc_.GetMemoryAttribute(gate)); + acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), Circuit::NullGate()); +} + void MCRLowering::LowerHeapObjectCheck(GateRef gate) { Environment env(gate, circuit_, &builder_); diff --git a/ecmascript/compiler/mcr_lowering.h b/ecmascript/compiler/mcr_lowering.h index 0acfb6fd9d..f4bb85b1d1 100644 --- a/ecmascript/compiler/mcr_lowering.h +++ b/ecmascript/compiler/mcr_lowering.h @@ -50,6 +50,7 @@ private: void LowerLoadHClassConstOffset(GateRef gate); void LowerLoadHClassFromConstpool(GateRef gate); void LowerStoreConstOffset(GateRef gate); + void LowerStoreHClassConstOffset(GateRef gate); void LowerConvertHoleAsUndefined(GateRef gate); void LowerCheckAndConvert(GateRef gate); void LowerCheckUInt32AndConvert(GateRef gate, GateRef frameState); diff --git a/ecmascript/compiler/mcr_opcodes.h b/ecmascript/compiler/mcr_opcodes.h index 2b031c557d..fac5dbb8dc 100644 --- a/ecmascript/compiler/mcr_opcodes.h +++ b/ecmascript/compiler/mcr_opcodes.h @@ -189,6 +189,7 @@ namespace panda::ecmascript::kungfu { V(LoadHClassConstOffset, LOAD_HCLASS_CONST_OFFSET, GateFlags::NO_WRITE, 0, 1, 1) \ V(LoadHClassFromConstpool, LOAD_HCLASS_FROM_CONSTPOOL, GateFlags::NO_WRITE, 0, 1, 1) \ V(StoreConstOffset, STORE_CONST_OFFSET, GateFlags::NONE_FLAG, 0, 1, 2) \ + V(StoreHClassConstOffset, STORE_HCLASS_CONST_OFFSET, GateFlags::NONE_FLAG, 0, 1, 3) \ V(LoadElement, LOAD_ELEMENT, GateFlags::NO_WRITE, 1, 1, 2) \ V(StoreElement, STORE_ELEMENT, GateFlags::NONE_FLAG, 1, 1, 3) \ V(StoreMemory, STORE_MEMORY, GateFlags::NONE_FLAG, 1, 1, 3) \ diff --git a/ecmascript/compiler/number_speculative_retype.cpp b/ecmascript/compiler/number_speculative_retype.cpp index f8c2125ec1..6958624598 100644 --- a/ecmascript/compiler/number_speculative_retype.cpp +++ b/ecmascript/compiler/number_speculative_retype.cpp @@ -304,6 +304,7 @@ GateRef NumberSpeculativeRetype::VisitGate(GateRef gate) case OpCode::LOAD_CONST_OFFSET: case OpCode::LOAD_HCLASS_CONST_OFFSET: case OpCode::STORE_CONST_OFFSET: + case OpCode::STORE_HCLASS_CONST_OFFSET: case OpCode::LEX_VAR_IS_HOLE_CHECK: case OpCode::TYPE_OF_CHECK: case OpCode::TYPE_OF: diff --git a/ecmascript/compiler/typed_bytecode_lowering.cpp b/ecmascript/compiler/typed_bytecode_lowering.cpp index 68b785c4d5..8e320f31a8 100644 --- a/ecmascript/compiler/typed_bytecode_lowering.cpp +++ b/ecmascript/compiler/typed_bytecode_lowering.cpp @@ -1142,7 +1142,7 @@ void TypedBytecodeLowering::TypedStObjByNameTransition(GateRef gate, GateRef rec auto newHolderHC = builder_.GetHClassGateFromIndex(gate, tacc.GetAccessInfo(i).HClassIndex()); if (compilationEnv_->IsAotCompiler()) { auto prototype = builder_.LoadPrototype(glue_, receiverHC); - builder_.StorePrototype(glue_, newHolderHC, prototype); + builder_.StoreConstOffset(VariableType::JS_ANY(), newHolderHC, JSHClass::PROTOTYPE_OFFSET, prototype); } if (!tacc.IsPrototypeHclass(i)) { if (!TryLazyDeoptNotPrototype(tacc, i, gate)) { @@ -1162,7 +1162,7 @@ void TypedBytecodeLowering::TypedStObjByNameTransition(GateRef gate, GateRef rec builder_.Bind(¬Proto); } MemoryAttribute mAttr = MemoryAttribute::NeedBarrierAndAtomic(); - builder_.TransitionHClass(glue_, tacc.GetReceiver(), newHolderHC, mAttr); + builder_.TransitionHClassByConstOffset(glue_, tacc.GetReceiver(), newHolderHC, mAttr); if (!tacc.GetAccessInfo(i).Plr().IsInlinedProps()) { auto properties = builder_.LoadConstOffset(VariableType::JS_ANY(), tacc.GetReceiver(), JSObject::PROPERTIES_OFFSET); diff --git a/ecmascript/message_string.h b/ecmascript/message_string.h index 23abd8d258..f8820ab3e7 100644 --- a/ecmascript/message_string.h +++ b/ecmascript/message_string.h @@ -90,7 +90,8 @@ namespace panda::ecmascript { V(RecordNameMustBeString, "RecordName must be string") \ V(LexicalEnvIsInvalid, "LexicalEnv of native JSFunction is invalid, it should be GlobalEnv or Undefined") \ V(CurrentEnvIsInvalid, "CurrentEnv is invalid, it should be GlobalEnv, LexicalEnv or SFunctionEnv") \ - V(AccessCompositeClassField, "this field of CompositeClass is unavailable") + V(AccessCompositeClassField, "this field of CompositeClass is unavailable") \ + V(HClassAddressIsInvalid, "HClass address is invalid") #define DEBUG_CHECK_MESSAGE_STRING_LIST(V) \ V(IsCallable) \ diff --git a/test/jittest/jit_test_0001/expect_output.txt b/test/jittest/jit_test_0001/expect_output.txt index e8a583802f..3f2aad9a4c 100644 --- a/test/jittest/jit_test_0001/expect_output.txt +++ b/test/jittest/jit_test_0001/expect_output.txt @@ -12,3 +12,4 @@ # limitations under the License. true +true diff --git a/test/jittest/jit_test_0001/jit_test_0001.ts b/test/jittest/jit_test_0001/jit_test_0001.ts index 07be812bbb..0233355d77 100644 --- a/test/jittest/jit_test_0001/jit_test_0001.ts +++ b/test/jittest/jit_test_0001/jit_test_0001.ts @@ -33,3 +33,22 @@ for (var i = 0; i < 10; i++) { ArkTools.jitCompileAsync(Test); var ret = ArkTools.waitJitCompileFinish(Test); print(ret); + +function Test2() { + let v2 = new Uint8ClampedArray(42); + const v5 = new Int32Array(3); + ({"buffer": v2} = v5); + + function func() { + return v5; + } + let v21 = 10; + for (;v21--;) { + v2.valueOf = func; + } +} + +Test2(); +ArkTools.jitCompileAsync(Test2); +print(ArkTools.waitJitCompileFinish(Test2)); +Test2(); -- Gitee