diff --git a/ecmascript/compiler/circuit_builder.cpp b/ecmascript/compiler/circuit_builder.cpp index e38f53c00c7368324f50d4b08d2520f0153f3210..a5501bfac937b1a1b92f9e6249e658ca24f67855 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 56220329c245080b0229d568db83e9772456c942..cd9328f6a154953b2e038cff6d6ce6b2098113a6 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 f30f6a6f77b1835e681a11e1fec58f889dadc585..e49604a6050579ca504ac124c15516862c360a70 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 230cc03a323cfc1c896e8e736516c5732f204cd0..d0ac83c7267636a74abefc5e02272cb809f35f0b 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 6769f968a17ca9b7ed2abcc027ebcc9d4eaf6ad0..3b02cf9e267290a4c55bfd81ed14fe851c1c72d0 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 7154bc495af957827e97c67ac7c3b6778b2de459..00418a13ca01be26ad721b5aa8c058a994541474 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 3e954de69d0ab12ce5a71703630349a3b1e56fac..08d11f8ad561855b8325f412e0c7f71820b9fac9 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 0acfb6fd9d01452b57cea98e9bfd3eb760a626e1..f4bb85b1d1d0e6c2bb362593486c1aaef045ac1e 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 2b031c557dcc64109a07235249f0af52c78d9034..fac5dbb8dcfe825bc3a43d48dac03abd3f0d80ee 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 f8c2125ec135fb52137a379ce2076d4b8ccf1fae..695862459831eb1da1a0b7b462ed05f08444a643 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 68b785c4d52c999cc1190e1ce3d2d70e7387d6bf..8e320f31a8f598c53dc93dd1631a1eeed23877b0 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 23abd8d25819f500cd423d975e194a668be7542e..f8820ab3e784dff4ddb4c1f6dd912db918688dee 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 e8a583802fa636d0d7b4dde7d65c9f12e95add7c..3f2aad9a4c6aec97b5122bf88b9483e7c750ab5a 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 07be812bbb12926a4f13b7b6cbbf2fd0a4351893..0233355d772e5d0046c2c3ade417a98aea165f2c 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();