mirror of
https://gitee.com/openharmony/arkcompiler_ets_runtime
synced 2024-10-07 08:03:29 +00:00
Eliminate HeapObject Check on the Elements of JSArray based on ElementsKind
1. If the PGO ElementsKind of a JSArray is OBJECT, and the named property of the JSArray element is loaded, the HeapObject check is not required. 2. The AOT stroing of OBJECT JSArray should be checked to prevent damage to the ElementsKind. Issue: https://gitee.com/openharmony/arkcompiler_ets_runtime/issues/I7SHUY Signed-off-by: dingding <dingding5@huawei.com> Change-Id: Ia55a75cf9d8ebe269e114bc6666718940629eb07
This commit is contained in:
parent
319fb3ff9c
commit
b37e3f5995
@ -138,26 +138,28 @@ GateRef CircuitBuilder::Arguments(size_t index)
|
||||
return GetCircuit()->NewArg(MachineType::I64, index, GateType::NJSValue(), argListOfCircuit);
|
||||
}
|
||||
|
||||
GateRef CircuitBuilder::ObjectTypeCheck(GateType type, GateRef gate, GateRef hclassIndex)
|
||||
GateRef CircuitBuilder::ObjectTypeCheck(GateType type, bool isHeapObject, GateRef gate, GateRef hclassIndex)
|
||||
{
|
||||
auto currentLabel = env_->GetCurrentLabel();
|
||||
auto currentControl = currentLabel->GetControl();
|
||||
auto currentDepend = currentLabel->GetDepend();
|
||||
auto frameState = acc_.FindNearestFrameState(currentDepend);
|
||||
GateRef ret = GetCircuit()->NewGate(circuit_->ObjectTypeCheck(static_cast<size_t>(type.Value())), MachineType::I1,
|
||||
ObjectTypeAccessor accessor(type, isHeapObject);
|
||||
GateRef ret = GetCircuit()->NewGate(circuit_->ObjectTypeCheck(accessor.ToValue()), MachineType::I1,
|
||||
{currentControl, currentDepend, gate, hclassIndex, frameState}, GateType::NJSValue());
|
||||
currentLabel->SetControl(ret);
|
||||
currentLabel->SetDepend(ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
GateRef CircuitBuilder::ObjectTypeCompare(GateType type, GateRef gate, GateRef hclassIndex)
|
||||
GateRef CircuitBuilder::ObjectTypeCompare(GateType type, bool isHeapObject, GateRef gate, GateRef hclassIndex)
|
||||
{
|
||||
auto currentLabel = env_->GetCurrentLabel();
|
||||
auto currentControl = currentLabel->GetControl();
|
||||
auto currentDepend = currentLabel->GetDepend();
|
||||
auto frameState = acc_.FindNearestFrameState(currentDepend);
|
||||
GateRef ret = GetCircuit()->NewGate(circuit_->ObjectTypeCompare(static_cast<size_t>(type.Value())), MachineType::I1,
|
||||
ObjectTypeAccessor accessor(type, isHeapObject);
|
||||
GateRef ret = GetCircuit()->NewGate(circuit_->ObjectTypeCompare(accessor.ToValue()), MachineType::I1,
|
||||
{currentControl, currentDepend, gate, hclassIndex, frameState}, GateType::NJSValue());
|
||||
currentLabel->SetControl(ret);
|
||||
currentLabel->SetDepend(ret);
|
||||
|
@ -258,8 +258,8 @@ public:
|
||||
GateRef LoadTypedArrayLength(GateType type, GateRef gate);
|
||||
GateRef RangeGuard(GateRef gate, uint32_t left, uint32_t right);
|
||||
GateRef IndexCheck(GateType type, GateRef gate, GateRef index);
|
||||
GateRef ObjectTypeCheck(GateType type, GateRef gate, GateRef hclassIndex);
|
||||
GateRef ObjectTypeCompare(GateType type, GateRef gate, GateRef hclassIndex);
|
||||
GateRef ObjectTypeCheck(GateType type, bool isHeapObject, GateRef gate, GateRef hclassIndex);
|
||||
GateRef ObjectTypeCompare(GateType type, bool isHeapObject, GateRef gate, GateRef hclassIndex);
|
||||
GateRef TryPrimitiveTypeCheck(GateType type, GateRef gate);
|
||||
GateRef CallTargetCheck(GateRef gate, GateRef function, GateRef id, GateRef param, const char* comment = nullptr);
|
||||
GateRef JSCallTargetFromDefineFuncCheck(GateType type, GateRef func, GateRef gate);
|
||||
|
@ -329,14 +329,19 @@ bool EarlyElimination::CheckReplacement(GateRef lhs, GateRef rhs)
|
||||
break;
|
||||
}
|
||||
case OpCode::TYPED_ARRAY_CHECK:
|
||||
case OpCode::OBJECT_TYPE_CHECK:
|
||||
case OpCode::OBJECT_TYPE_COMPARE:
|
||||
case OpCode::INDEX_CHECK: {
|
||||
if (acc_.GetParamGateType(lhs) != acc_.GetParamGateType(rhs)) {
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case OpCode::OBJECT_TYPE_CHECK:
|
||||
case OpCode::OBJECT_TYPE_COMPARE: {
|
||||
if (acc_.GetObjectTypeAccessor(lhs).GetType() != acc_.GetObjectTypeAccessor(rhs).GetType()) {
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case OpCode::LOAD_CONST_OFFSET: {
|
||||
if (acc_.GetOffset(lhs) != acc_.GetOffset(rhs)) {
|
||||
return false;
|
||||
|
@ -143,6 +143,14 @@ ArrayMetaDataAccessor GateAccessor::GetArrayMetaDataAccessor(GateRef gate) const
|
||||
return ArrayMetaDataAccessor(gatePtr->GetOneParameterMetaData()->GetValue());
|
||||
}
|
||||
|
||||
ObjectTypeAccessor GateAccessor::GetObjectTypeAccessor(GateRef gate) const
|
||||
{
|
||||
ASSERT(GetOpCode(gate) == OpCode::OBJECT_TYPE_CHECK ||
|
||||
GetOpCode(gate) == OpCode::OBJECT_TYPE_COMPARE);
|
||||
Gate *gatePtr = circuit_->LoadGatePtr(gate);
|
||||
return ObjectTypeAccessor(gatePtr->GetOneParameterMetaData()->GetValue());
|
||||
}
|
||||
|
||||
TypedLoadOp GateAccessor::GetTypedLoadOp(GateRef gate) const
|
||||
{
|
||||
ASSERT(GetOpCode(gate) == OpCode::LOAD_ELEMENT);
|
||||
@ -212,8 +220,6 @@ GlobalTSTypeRef GateAccessor::GetFuncGT(GateRef gate) const
|
||||
GateType GateAccessor::GetParamGateType(GateRef gate) const
|
||||
{
|
||||
ASSERT(GetOpCode(gate) == OpCode::PRIMITIVE_TYPE_CHECK ||
|
||||
GetOpCode(gate) == OpCode::OBJECT_TYPE_CHECK ||
|
||||
GetOpCode(gate) == OpCode::OBJECT_TYPE_COMPARE ||
|
||||
GetOpCode(gate) == OpCode::TYPED_ARRAY_CHECK ||
|
||||
GetOpCode(gate) == OpCode::INDEX_CHECK ||
|
||||
GetOpCode(gate) == OpCode::TYPED_CALLTARGETCHECK_OP ||
|
||||
@ -1288,4 +1294,25 @@ bool GateAccessor::HasIfExceptionUse(GateRef gate) const
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool GateAccessor::IsHeapObjectFromElementsKind(GateRef gate)
|
||||
{
|
||||
OpCode opcode = GetOpCode(gate);
|
||||
if (opcode == OpCode::JS_BYTECODE) {
|
||||
auto bc = GetByteCodeOpcode(gate);
|
||||
if (bc == EcmaOpcode::LDOBJBYVALUE_IMM8_V8 || bc == EcmaOpcode::LDOBJBYVALUE_IMM16_V8 ||
|
||||
bc == EcmaOpcode::LDTHISBYVALUE_IMM8 || bc == EcmaOpcode::LDTHISBYVALUE_IMM16) {
|
||||
ElementsKind kind = TryGetElementsKind(gate);
|
||||
return Elements::IsObject(kind);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
if (opcode == OpCode::LOAD_ELEMENT) {
|
||||
TypedLoadOp typedOp = GetTypedLoadOp(gate);
|
||||
return typedOp == TypedLoadOp::ARRAY_LOAD_OBJECT_ELEMENT;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
} // namespace panda::ecmascript::kungfu
|
||||
|
@ -396,6 +396,7 @@ public:
|
||||
TypedUnaryAccessor GetTypedUnAccessor(GateRef gate) const;
|
||||
TypedJumpAccessor GetTypedJumpAccessor(GateRef gate) const;
|
||||
ArrayMetaDataAccessor GetArrayMetaDataAccessor(GateRef gate) const;
|
||||
ObjectTypeAccessor GetObjectTypeAccessor(GateRef gate) const;
|
||||
uint64_t GetConstantValue(GateRef gate) const;
|
||||
const ChunkVector<char>& GetConstantString(GateRef gate) const;
|
||||
bool IsVtable(GateRef gate) const;
|
||||
@ -507,6 +508,7 @@ public:
|
||||
GateRef GetDependSelectorFromMerge(GateRef gate);
|
||||
bool HasIfExceptionUse(GateRef gate) const;
|
||||
bool IsIn(GateRef g, GateRef in) const;
|
||||
bool IsHeapObjectFromElementsKind(GateRef gate);
|
||||
|
||||
GateRef GetCircuitRoot() const
|
||||
{
|
||||
|
@ -175,6 +175,7 @@ enum class MemoryType : uint8_t {
|
||||
enum class TypedLoadOp : uint8_t {
|
||||
ARRAY_LOAD_INT_ELEMENT = 0,
|
||||
ARRAY_LOAD_DOUBLE_ELEMENT,
|
||||
ARRAY_LOAD_OBJECT_ELEMENT,
|
||||
ARRAY_LOAD_TAGGED_ELEMENT,
|
||||
ARRAY_LOAD_HOLE_TAGGED_ELEMENT,
|
||||
INT8ARRAY_LOAD_ELEMENT,
|
||||
@ -324,8 +325,6 @@ std::string MachineTypeToStr(MachineType machineType);
|
||||
|
||||
#define GATE_META_DATA_LIST_WITH_GATE_TYPE(V) \
|
||||
V(PrimitiveTypeCheck, PRIMITIVE_TYPE_CHECK, GateFlags::CHECKABLE, 1, 1, 1) \
|
||||
V(ObjectTypeCheck, OBJECT_TYPE_CHECK, GateFlags::CHECKABLE, 1, 1, 2) \
|
||||
V(ObjectTypeCompare, OBJECT_TYPE_COMPARE, GateFlags::CHECKABLE, 1, 1, 2) \
|
||||
V(TypedArrayCheck, TYPED_ARRAY_CHECK, GateFlags::CHECKABLE, 1, 1, 1) \
|
||||
V(LoadTypedArrayLength, LOAD_TYPED_ARRAY_LENGTH, GateFlags::NO_WRITE, 1, 1, 1) \
|
||||
V(IndexCheck, INDEX_CHECK, GateFlags::CHECKABLE, 1, 1, 2) \
|
||||
@ -359,7 +358,9 @@ std::string MachineTypeToStr(MachineType machineType);
|
||||
V(CreateArrayWithBuffer, CREATE_ARRAY_WITH_BUFFER, GateFlags::CHECKABLE, 1, 1, 2) \
|
||||
V(RangeGuard, RANGE_GUARD, GateFlags::NO_WRITE, 1, 1, 1) \
|
||||
V(StableArrayCheck, STABLE_ARRAY_CHECK, GateFlags::CHECKABLE, 1, 1, 1) \
|
||||
V(HClassStableArrayCheck, HCLASS_STABLE_ARRAY_CHECK, GateFlags::CHECKABLE, 1, 1, 1)
|
||||
V(HClassStableArrayCheck, HCLASS_STABLE_ARRAY_CHECK, GateFlags::CHECKABLE, 1, 1, 1) \
|
||||
V(ObjectTypeCheck, OBJECT_TYPE_CHECK, GateFlags::CHECKABLE, 1, 1, 2) \
|
||||
V(ObjectTypeCompare, OBJECT_TYPE_COMPARE, GateFlags::CHECKABLE, 1, 1, 2)
|
||||
|
||||
#define GATE_META_DATA_LIST_WITH_ONE_PARAMETER(V) \
|
||||
V(Arg, ARG, GateFlags::HAS_ROOT, 0, 0, 0) \
|
||||
@ -1084,6 +1085,39 @@ private:
|
||||
|
||||
uint64_t bitField_;
|
||||
};
|
||||
|
||||
class ObjectTypeAccessor {
|
||||
public:
|
||||
static constexpr int TYPE_BITS_SIZE = 32;
|
||||
static constexpr int IS_HEAP_OBJECT_BIT_SIZE = 1;
|
||||
|
||||
explicit ObjectTypeAccessor(uint64_t value) : bitField_(value) {}
|
||||
explicit ObjectTypeAccessor(GateType type, bool isHeapObject = false)
|
||||
{
|
||||
bitField_ = TypeBits::Encode(type.Value()) | IsHeapObjectBit::Encode(isHeapObject);
|
||||
}
|
||||
|
||||
GateType GetType() const
|
||||
{
|
||||
return GateType(TypeBits::Get(bitField_));
|
||||
}
|
||||
|
||||
bool IsHeapObject() const
|
||||
{
|
||||
return IsHeapObjectBit::Get(bitField_);
|
||||
}
|
||||
|
||||
uint64_t ToValue() const
|
||||
{
|
||||
return bitField_;
|
||||
}
|
||||
|
||||
private:
|
||||
using TypeBits = panda::BitField<uint32_t, 0, TYPE_BITS_SIZE>;
|
||||
using IsHeapObjectBit = TypeBits::NextField<bool, IS_HEAP_OBJECT_BIT_SIZE>;
|
||||
|
||||
uint64_t bitField_;
|
||||
};
|
||||
} // namespace panda::ecmascript::kungfu
|
||||
|
||||
#endif // ECMASCRIPT_COMPILER_GATE_META_DATA_H
|
||||
|
@ -601,13 +601,17 @@ void TSHCRLowering::LowerNamedAccess(GateRef gate, GateRef receiver, AccessMode
|
||||
ASSERT(!infos.empty());
|
||||
AddProfiling(gate);
|
||||
|
||||
// If all elements of the array are objects, and receiver is one of the elements,
|
||||
// no HeapObjectCheck is required.
|
||||
bool isHeapObject = acc_.IsHeapObjectFromElementsKind(receiver);
|
||||
|
||||
// monomorphic
|
||||
if (infos.size() == 1) {
|
||||
int hclassIndex = infos[0].HClassIndex();
|
||||
PropertyLookupResult plr = infos[0].Plr();
|
||||
if (!Uncheck()) {
|
||||
GateRef hclassIndexGate = builder_.IntPtr(hclassIndex);
|
||||
builder_.ObjectTypeCheck(infos[0].Type(), receiver, hclassIndexGate);
|
||||
builder_.ObjectTypeCheck(infos[0].Type(), isHeapObject, receiver, hclassIndexGate);
|
||||
}
|
||||
|
||||
GateRef result = BuildNamedPropertyAccess(gate, accessHelper, plr);
|
||||
@ -631,11 +635,11 @@ void TSHCRLowering::LowerNamedAccess(GateRef gate, GateRef receiver, AccessMode
|
||||
builder_.SetState(fallthroughState);
|
||||
builder_.SetDepend(fallthroughDepend);
|
||||
if (i == size - 1) {
|
||||
builder_.ObjectTypeCheck(type, receiver, hclassIndexGate);
|
||||
builder_.ObjectTypeCheck(type, isHeapObject, receiver, hclassIndexGate);
|
||||
fallthroughState = Circuit::NullGate();
|
||||
fallthroughDepend = Circuit::NullGate();
|
||||
} else {
|
||||
GateRef compare = builder_.ObjectTypeCompare(type, receiver, hclassIndexGate);
|
||||
GateRef compare = builder_.ObjectTypeCompare(type, isHeapObject, receiver, hclassIndexGate);
|
||||
GateRef branch = builder_.Branch(builder_.GetState(), compare);
|
||||
GateRef ifTrue = builder_.IfTrue(branch);
|
||||
GateRef ifFalse = builder_.IfFalse(branch);
|
||||
@ -866,6 +870,8 @@ GateRef TSHCRLowering::LoadJSArrayByIndex(GateRef receiver, GateRef propKey, Ele
|
||||
result = builder_.LoadElement<TypedLoadOp::ARRAY_LOAD_INT_ELEMENT>(receiver, propKey);
|
||||
} else if (Elements::IsDouble(kind)) {
|
||||
result = builder_.LoadElement<TypedLoadOp::ARRAY_LOAD_DOUBLE_ELEMENT>(receiver, propKey);
|
||||
} else if (Elements::IsObject(kind)) {
|
||||
result = builder_.LoadElement<TypedLoadOp::ARRAY_LOAD_OBJECT_ELEMENT>(receiver, propKey);
|
||||
} else if (!Elements::IsHole(kind)) {
|
||||
result = builder_.LoadElement<TypedLoadOp::ARRAY_LOAD_TAGGED_ELEMENT>(receiver, propKey);
|
||||
} else {
|
||||
@ -920,6 +926,11 @@ void TSHCRLowering::StoreJSArrayByIndex(GateRef receiver, GateRef propKey, GateR
|
||||
GateRef length = builder_.LoadArrayLength(receiver);
|
||||
builder_.IndexCheck(receiverType, length, propKey);
|
||||
builder_.COWArrayCheck(receiver);
|
||||
|
||||
if (Elements::IsObject(kind)) {
|
||||
GateRef frameState = acc_.FindNearestFrameState(builder_.GetDepend());
|
||||
builder_.HeapObjectCheck(value, frameState);
|
||||
}
|
||||
}
|
||||
builder_.StoreElement<TypedStoreOp::ARRAY_STORE_ELEMENT>(receiver, propKey, value);
|
||||
}
|
||||
|
@ -319,7 +319,7 @@ void TypeMCRLowering::LowerLoadTypedArrayLength(GateRef gate)
|
||||
void TypeMCRLowering::LowerObjectTypeCheck(GateRef gate)
|
||||
{
|
||||
Environment env(gate, circuit_, &builder_);
|
||||
auto type = acc_.GetParamGateType(gate);
|
||||
GateType type = acc_.GetObjectTypeAccessor(gate).GetType();
|
||||
if (tsManager_->IsClassInstanceTypeKind(type)) {
|
||||
LowerTSSubtypingCheck(gate);
|
||||
} else if (tsManager_->IsClassTypeKind(type) ||
|
||||
@ -352,7 +352,7 @@ void TypeMCRLowering::LowerSimpleHClassCheck(GateRef gate)
|
||||
void TypeMCRLowering::LowerObjectTypeCompare(GateRef gate)
|
||||
{
|
||||
Environment env(gate, circuit_, &builder_);
|
||||
auto type = acc_.GetParamGateType(gate);
|
||||
auto type = acc_.GetObjectTypeAccessor(gate).GetType();
|
||||
if (tsManager_->IsClassInstanceTypeKind(type)) {
|
||||
LowerTSSubtypingCompare(gate);
|
||||
} else if (tsManager_->IsClassTypeKind(type) ||
|
||||
@ -383,7 +383,10 @@ void TypeMCRLowering::LowerTSSubtypingCompare(GateRef gate)
|
||||
GateRef TypeMCRLowering::BuildCompareSubTyping(GateRef gate, GateRef frameState, Label *levelValid, Label *exit)
|
||||
{
|
||||
GateRef receiver = acc_.GetValueIn(gate, 0);
|
||||
builder_.HeapObjectCheck(receiver, frameState);
|
||||
bool isHeapObject = acc_.GetObjectTypeAccessor(gate).IsHeapObject();
|
||||
if (!isHeapObject) {
|
||||
builder_.HeapObjectCheck(receiver, frameState);
|
||||
}
|
||||
|
||||
GateRef aotHCIndex = acc_.GetValueIn(gate, 1);
|
||||
ArgumentAccessor argAcc(circuit_);
|
||||
@ -423,7 +426,11 @@ GateRef TypeMCRLowering::BuildCompareSubTyping(GateRef gate, GateRef frameState,
|
||||
GateRef TypeMCRLowering::BuildCompareHClass(GateRef gate, GateRef frameState)
|
||||
{
|
||||
GateRef receiver = acc_.GetValueIn(gate, 0);
|
||||
builder_.HeapObjectCheck(receiver, frameState);
|
||||
bool isHeapObject = acc_.GetObjectTypeAccessor(gate).IsHeapObject();
|
||||
if (!isHeapObject) {
|
||||
builder_.HeapObjectCheck(receiver, frameState);
|
||||
}
|
||||
|
||||
GateRef aotHCIndex = acc_.GetValueIn(gate, 1);
|
||||
auto hclassIndex = acc_.GetConstantValue(aotHCIndex);
|
||||
ArgumentAccessor argAcc(circuit_);
|
||||
@ -688,6 +695,7 @@ void TypeMCRLowering::LowerLoadElement(GateRef gate)
|
||||
switch (op) {
|
||||
case TypedLoadOp::ARRAY_LOAD_INT_ELEMENT:
|
||||
case TypedLoadOp::ARRAY_LOAD_DOUBLE_ELEMENT:
|
||||
case TypedLoadOp::ARRAY_LOAD_OBJECT_ELEMENT:
|
||||
case TypedLoadOp::ARRAY_LOAD_TAGGED_ELEMENT:
|
||||
LowerArrayLoadElement(gate, ArrayState::PACKED);
|
||||
break;
|
||||
|
@ -52,6 +52,11 @@ bool Elements::IsDouble(ElementsKind kind)
|
||||
return kind == ElementsKind::DOUBLE;
|
||||
}
|
||||
|
||||
bool Elements::IsObject(ElementsKind kind)
|
||||
{
|
||||
return kind == ElementsKind::OBJECT;
|
||||
}
|
||||
|
||||
bool Elements::IsHole(ElementsKind kind)
|
||||
{
|
||||
static constexpr uint8_t EVEN_NUMBER = 2;
|
||||
|
@ -46,6 +46,7 @@ public:
|
||||
static std::string GetString(ElementsKind kind);
|
||||
static bool IsInt(ElementsKind kind);
|
||||
static bool IsDouble(ElementsKind kind);
|
||||
static bool IsObject(ElementsKind kind);
|
||||
static bool IsHole(ElementsKind kind);
|
||||
static bool IsGeneric(ElementsKind kind)
|
||||
{
|
||||
|
@ -31,3 +31,20 @@ function foo() {
|
||||
|
||||
foo();
|
||||
|
||||
|
||||
class C {
|
||||
x: number;
|
||||
constructor(v: number) {
|
||||
this.x = v;
|
||||
}
|
||||
}
|
||||
|
||||
function testObject() {
|
||||
let objArray: C[] = [new C(1), new C(2)];
|
||||
for (let i: number = 0; i < objArray.length; ++i) {
|
||||
print(objArray[i].x);
|
||||
}
|
||||
}
|
||||
|
||||
testObject();
|
||||
|
||||
|
@ -15,3 +15,5 @@
|
||||
2.2
|
||||
[object Object]
|
||||
undefined
|
||||
1
|
||||
2
|
||||
|
@ -15,3 +15,5 @@
|
||||
2.2
|
||||
[object Object]
|
||||
undefined
|
||||
1
|
||||
2
|
||||
|
Loading…
Reference in New Issue
Block a user