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:
dingding 2023-08-11 05:07:42 +08:00
parent 319fb3ff9c
commit b37e3f5995
13 changed files with 136 additions and 20 deletions

View File

@ -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);

View File

@ -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);

View File

@ -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;

View File

@ -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

View File

@ -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
{

View File

@ -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

View File

@ -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);
}

View File

@ -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;

View File

@ -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;

View File

@ -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)
{

View File

@ -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();

View File

@ -15,3 +15,5 @@
2.2
[object Object]
undefined
1
2

View File

@ -15,3 +15,5 @@
2.2
[object Object]
undefined
1
2