!5828 Reuse StObjByValue IC to add StOwnByIndex IC

Merge pull request !5828 from YuliCheng/StOwnByIndex
This commit is contained in:
openharmony_ci 2024-01-23 13:22:16 +00:00 committed by Gitee
commit aafa9df6bb
No known key found for this signature in database
GPG Key ID: 173E9B9CA92EEF8F
14 changed files with 324 additions and 76 deletions

View File

@ -230,6 +230,45 @@ GateRef AccessObjectStubBuilder::StoreObjByValue(GateRef glue, GateRef receiver,
return ret;
}
GateRef AccessObjectStubBuilder::StoreOwnByIndex(GateRef glue, GateRef receiver, GateRef index, GateRef value,
GateRef profileTypeInfo, GateRef slotId, ProfileOperation callback)
{
auto env = GetEnvironment();
Label entry(env);
env->SubCfgEntry(&entry);
Label exit(env);
Label tryFastPath(env);
Label slowPath(env);
Label isHeapObject(env);
DEFVARIABLE(result, VariableType::JS_ANY(), Hole());
ICStubBuilder builder(this);
builder.SetParameters(glue, receiver, profileTypeInfo, value, slotId, IntToTaggedPtr(index), callback);
builder.StoreICByValue(&result, &tryFastPath, &slowPath, &exit);
Bind(&tryFastPath);
{
Branch(TaggedIsHeapObject(receiver), &isHeapObject, &slowPath);
Bind(&isHeapObject);
Label notClassConstructor(env);
Branch(IsClassConstructor(receiver), &slowPath, &notClassConstructor);
Bind(&notClassConstructor);
Label notClassPrototype(env);
Branch(IsClassPrototype(receiver), &slowPath, &notClassPrototype);
Bind(&notClassPrototype);
result = SetPropertyByIndex(glue, receiver, index, value, true);
Branch(TaggedIsHole(*result), &slowPath, &exit);
}
Bind(&slowPath);
{
result = CallRuntime(glue, RTSTUB_ID(StOwnByIndex), { receiver, IntToTaggedInt(index), value });
callback.TryPreDump();
Jump(&exit);
}
Bind(&exit);
auto ret = *result;
env->SubCfgExit();
return ret;
}
GateRef AccessObjectStubBuilder::TryLoadGlobalByName(GateRef glue, GateRef prop, const StringIdInfo &info,
GateRef profileTypeInfo, GateRef slotId,
ProfileOperation callback)

View File

@ -42,6 +42,8 @@ public:
ProfileOperation callback = ProfileOperation());
GateRef StoreObjByValue(GateRef glue, GateRef receiver, GateRef key, GateRef value, GateRef profileTypeInfo,
GateRef slotId, ProfileOperation callback = ProfileOperation());
GateRef StoreOwnByIndex(GateRef glue, GateRef receiver, GateRef index, GateRef value, GateRef profileTypeInfo,
GateRef slotId, ProfileOperation callback = ProfileOperation());
GateRef DeprecatedLoadObjByValue(GateRef glue, GateRef receiver, GateRef key);
GateRef TryLoadGlobalByName(GateRef glue, GateRef prop, const StringIdInfo &info,
GateRef profileTypeInfo, GateRef slotId, ProfileOperation callback);

View File

@ -242,7 +242,6 @@ void ICStubBuilder::StoreICByValue(Variable* result, Label* tryFastPath, Label *
auto env = GetEnvironment();
Label storeWithHandler(env);
Label storeElement(env);
SetLabels(tryFastPath, slowPath, success);
GateRef secondValue = GetValueFromTaggedArray(
profileTypeInfo_, Int32Add(slotId_, Int32(1)));

View File

@ -1751,70 +1751,30 @@ DECLARE_ASM_HANDLER(HandleWideStobjbyindexPrefV8Imm32)
}
}
DECLARE_ASM_HANDLER(HandleStownbyindexImm16V8Imm16)
{
auto env = GetEnvironment();
GateRef v0 = ReadInst8_2(pc);
GateRef receiver = GetVregValue(sp, ZExtInt8ToPtr(v0));
GateRef index = ZExtInt16ToInt32(ReadInst16_3(pc));
Label isHeapObject(env);
Label slowPath(env);
Branch(TaggedIsHeapObject(receiver), &isHeapObject, &slowPath);
Bind(&isHeapObject);
Label notClassConstructor(env);
Branch(IsClassConstructor(receiver), &slowPath, &notClassConstructor);
Bind(&notClassConstructor);
Label notClassPrototype(env);
Branch(IsClassPrototype(receiver), &slowPath, &notClassPrototype);
Bind(&notClassPrototype);
{
// fast path
GateRef result = SetPropertyByIndex(glue, receiver, index, acc, true); // acc is value
Label notHole(env);
Branch(TaggedIsHole(result), &slowPath, &notHole);
Bind(&notHole);
CHECK_EXCEPTION(result, INT_PTR(STOWNBYINDEX_IMM16_V8_IMM16));
}
Bind(&slowPath);
{
GateRef result = CallRuntime(glue, RTSTUB_ID(StOwnByIndex),
{ receiver, IntToTaggedInt(index), acc });
CHECK_EXCEPTION(result, INT_PTR(STOWNBYINDEX_IMM16_V8_IMM16));
}
}
DECLARE_ASM_HANDLER(HandleStownbyindexImm8V8Imm16)
{
auto env = GetEnvironment();
GateRef v0 = ReadInst8_1(pc);
GateRef receiver = GetVregValue(sp, ZExtInt8ToPtr(v0));
GateRef index = ZExtInt16ToInt32(ReadInst16_2(pc));
Label isHeapObject(env);
Label slowPath(env);
Branch(TaggedIsHeapObject(receiver), &isHeapObject, &slowPath);
Bind(&isHeapObject);
Label notClassConstructor(env);
Branch(IsClassConstructor(receiver), &slowPath, &notClassConstructor);
Bind(&notClassConstructor);
Label notClassPrototype(env);
Branch(IsClassPrototype(receiver), &slowPath, &notClassPrototype);
Bind(&notClassPrototype);
{
// fast path
GateRef result = SetPropertyByIndex(glue, receiver, index, acc, true); // acc is value
Label notHole(env);
Branch(TaggedIsHole(result), &slowPath, &notHole);
Bind(&notHole);
CHECK_EXCEPTION(result, INT_PTR(STOWNBYINDEX_IMM8_V8_IMM16));
}
Bind(&slowPath);
{
GateRef result = CallRuntime(glue, RTSTUB_ID(StOwnByIndex),
{ receiver, IntToTaggedInt(index), acc });
CHECK_EXCEPTION(result, INT_PTR(STOWNBYINDEX_IMM8_V8_IMM16));
}
GateRef value = acc;
GateRef slotId = ZExtInt8ToInt32(ReadInst8_0(pc));
AccessObjectStubBuilder builder(this);
GateRef result = builder.StoreOwnByIndex(glue, receiver, index, value, profileTypeInfo, slotId, callback);
CHECK_EXCEPTION(result, INT_PTR(STOWNBYINDEX_IMM8_V8_IMM16));
}
DECLARE_ASM_HANDLER(HandleStownbyindexImm16V8Imm16)
{
GateRef v0 = ReadInst8_2(pc);
GateRef receiver = GetVregValue(sp, ZExtInt8ToPtr(v0));
GateRef index = ZExtInt16ToInt32(ReadInst16_3(pc));
GateRef value = acc;
GateRef slotId = ZExtInt16ToInt32(ReadInst16_0(pc));
AccessObjectStubBuilder builder(this);
GateRef result = builder.StoreOwnByIndex(glue, receiver, index, value, profileTypeInfo, slotId, callback);
CHECK_EXCEPTION(result, INT_PTR(STOWNBYINDEX_IMM16_V8_IMM16));
}
DECLARE_ASM_HANDLER(HandleWideStownbyindexPrefV8Imm32)

View File

@ -311,7 +311,7 @@ JSTaggedValue LoadICRuntime::LoadTypedArrayValueMiss(JSHandle<JSTaggedValue> rec
}
JSTaggedValue StoreICRuntime::StoreMiss(JSHandle<JSTaggedValue> receiver, JSHandle<JSTaggedValue> key,
JSHandle<JSTaggedValue> value)
JSHandle<JSTaggedValue> value, bool isOwn)
{
if (!receiver->IsJSObject() || receiver->HasOrdinaryGet()) {
icAccessor_.SetAsMega();
@ -322,7 +322,6 @@ JSTaggedValue StoreICRuntime::StoreMiss(JSHandle<JSTaggedValue> receiver, JSHand
if (receiver->IsTypedArray()) {
return StoreTypedArrayValueMiss(receiver, key, value);
}
ICKind kind = GetICKind();
// global variable find from global record firstly
if (kind == ICKind::NamedGlobalStoreIC || kind == ICKind::NamedGlobalTryStoreIC) {
@ -338,8 +337,7 @@ JSTaggedValue StoreICRuntime::StoreMiss(JSHandle<JSTaggedValue> receiver, JSHand
}
}
UpdateReceiverHClass(JSHandle<JSTaggedValue>(GetThread(), JSHandle<JSObject>::Cast(receiver)->GetClass()));
ObjectOperator op(GetThread(), receiver, key);
ObjectOperator op = ConstructOp(receiver, key, value, isOwn);
if (!op.IsFound()) {
if (kind == ICKind::NamedGlobalStoreIC) {
PropertyAttributes attr = PropertyAttributes::Default(true, true, false);

View File

@ -56,6 +56,20 @@ public:
return icAccessor_.GetKind();
}
ObjectOperator ConstructOp(JSHandle<JSTaggedValue> receiver, JSHandle<JSTaggedValue> key,
JSHandle<JSTaggedValue> value, bool isOwn) const
{
ObjectOperator op(GetThread(), receiver, key,
isOwn ? OperatorType::OWN : OperatorType::PROTOTYPE_CHAIN);
if (isOwn) {
bool enumerable = !(receiver->IsClassPrototype() || receiver->IsClassConstructor());
PropertyDescriptor desc(GetThread(), value, true, enumerable, true);
PropertyAttributes attr(desc);
op.SetAttr(attr);
}
return op;
}
void TraceIC(JSHandle<JSTaggedValue> receiver, JSHandle<JSTaggedValue> key) const;
protected:
@ -88,7 +102,8 @@ public:
~StoreICRuntime() = default;
JSTaggedValue StoreMiss(JSHandle<JSTaggedValue> receiver, JSHandle<JSTaggedValue> key,
JSHandle<JSTaggedValue> value);
JSHandle<JSTaggedValue> value, bool isOwn = false);
JSTaggedValue StoreTypedArrayValueMiss(JSHandle<JSTaggedValue> receiver, JSHandle<JSTaggedValue> key,
JSHandle<JSTaggedValue> value);
};

View File

@ -179,6 +179,14 @@ ARK_NOINLINE JSTaggedValue ICRuntimeStub::StoreICByValue(JSThread *thread, Profi
return StoreMiss(thread, profileTypeInfo, receiver, key, value, slotId, ICKind::StoreIC);
}
ARK_NOINLINE JSTaggedValue ICRuntimeStub::StoreOwnICByValue(JSThread *thread, ProfileTypeInfo *profileTypeInfo,
JSTaggedValue receiver, JSTaggedValue key,
JSTaggedValue value, uint32_t slotId)
{
INTERPRETER_TRACE(thread, StoreOwnICByValue);
return StoreMiss(thread, profileTypeInfo, receiver, key, value, slotId, ICKind::StoreIC, true);
}
ARK_INLINE JSTaggedValue ICRuntimeStub::TryStoreICByName(JSThread *thread, JSTaggedValue receiver,
JSTaggedValue firstValue, JSTaggedValue secondValue,
JSTaggedValue value)
@ -645,7 +653,7 @@ JSTaggedValue ICRuntimeStub::LoadValueMiss(JSThread *thread, ProfileTypeInfo *pr
}
JSTaggedValue ICRuntimeStub::StoreMiss(JSThread *thread, ProfileTypeInfo *profileTypeInfo, JSTaggedValue receiver,
JSTaggedValue key, JSTaggedValue value, uint32_t slotId, ICKind kind)
JSTaggedValue key, JSTaggedValue value, uint32_t slotId, ICKind kind, bool isOwn)
{
[[maybe_unused]] EcmaHandleScope handleScope(thread);
auto keyHandle = JSHandle<JSTaggedValue>(thread, key);
@ -653,7 +661,7 @@ JSTaggedValue ICRuntimeStub::StoreMiss(JSThread *thread, ProfileTypeInfo *profil
auto valueHandle = JSHandle<JSTaggedValue>(thread, value);
auto profileInfoHandle = JSHandle<JSTaggedValue>(thread, profileTypeInfo);
StoreICRuntime icRuntime(thread, JSHandle<ProfileTypeInfo>::Cast(profileInfoHandle), slotId, kind);
return icRuntime.StoreMiss(receiverHandle, keyHandle, valueHandle);
return icRuntime.StoreMiss(receiverHandle, keyHandle, valueHandle, isOwn);
}
} // namespace panda::ecmascript

View File

@ -70,6 +70,9 @@ public:
static inline JSTaggedValue StoreICByValue(JSThread *thread, ProfileTypeInfo *profileTypeInfo,
JSTaggedValue receiver, JSTaggedValue key, JSTaggedValue value,
uint32_t slotId);
static inline JSTaggedValue StoreOwnICByValue(JSThread *thread, ProfileTypeInfo *profileTypeInfo,
JSTaggedValue receiver, JSTaggedValue key,
JSTaggedValue value, uint32_t slotId);
static inline JSTaggedValue LoadElement(JSObject *receiver, JSTaggedValue key);
static inline JSTaggedValue LoadStringElement(JSThread *thread, JSTaggedValue receiver, JSTaggedValue key);
static inline JSTaggedValue LoadTypedArrayElement(JSThread *thread, JSTaggedValue receiver, JSTaggedValue key);
@ -83,7 +86,8 @@ public:
static inline JSTaggedValue LoadValueMiss(JSThread *thread, ProfileTypeInfo *profileTypeInfo,
JSTaggedValue receiver, JSTaggedValue key, uint32_t slotId, ICKind kind);
static inline JSTaggedValue StoreMiss(JSThread *thread, ProfileTypeInfo *profileTypeInfo, JSTaggedValue receiver,
JSTaggedValue key, JSTaggedValue value, uint32_t slotId, ICKind kind);
JSTaggedValue key, JSTaggedValue value, uint32_t slotId,
ICKind kind, bool isOwn = false);
};
} // namespace panda::ecmascript

View File

@ -5700,12 +5700,39 @@ NO_UB_SANITIZE void EcmaInterpreter::RunInternal(JSThread *thread, const uint8_t
HANDLE_OPCODE(STOWNBYINDEX_IMM8_V8_IMM16) {
uint8_t v0 = READ_INST_8_1();
uint16_t index = READ_INST_16_2();
JSTaggedValue receiver = GET_VREG_VALUE(v0);
LOG_INST() << "intrinsics::stownbyindex"
<< " v" << v0 << " imm" << index;
JSTaggedValue receiver = GET_VREG_VALUE(v0);
#if ECMASCRIPT_ENABLE_IC
auto profileTypeInfo = GetRuntimeProfileTypeInfo(sp);
if (!profileTypeInfo.IsUndefined()) {
SAVE_ACC();
uint32_t slotId = READ_INST_8_0();
auto profileTypeArray = ProfileTypeInfo::Cast(profileTypeInfo.GetTaggedObject());
JSTaggedValue firstValue = profileTypeArray->Get(slotId);
JSTaggedValue value = GET_ACC();
JSTaggedValue res = JSTaggedValue::Hole();
if (LIKELY(firstValue.IsHeapObject())) {
JSTaggedValue secondValue = profileTypeArray->Get(slotId + 1);
res = ICRuntimeStub::TryStoreICByValue(thread,
receiver, JSTaggedValue(index), firstValue, secondValue, value);
}
// IC miss and not enter the megamorphic state, store as polymorphic
if (res.IsHole() && !firstValue.IsHole()) {
res = ICRuntimeStub::StoreOwnICByValue(thread,
profileTypeArray, receiver, JSTaggedValue(index), value, slotId);
}
if (LIKELY(!res.IsHole())) {
INTERPRETER_RETURN_IF_ABRUPT(res);
RESTORE_ACC();
DISPATCH(STOWNBYINDEX_IMM8_V8_IMM16);
}
}
#endif
// fast path
if (receiver.IsHeapObject() && !receiver.IsClassConstructor() && !receiver.IsClassPrototype()) {
SAVE_ACC();
receiver = GET_VREG_VALUE(v0);
JSTaggedValue value = GET_ACC();
// fast path
JSTaggedValue res = FastRuntimeStub::SetPropertyByIndex<ObjectFastOperator::Status::UseOwn>
@ -5732,6 +5759,33 @@ NO_UB_SANITIZE void EcmaInterpreter::RunInternal(JSThread *thread, const uint8_t
LOG_INST() << "intrinsics::stownbyindex"
<< " v" << v0 << " imm" << index;
JSTaggedValue receiver = GET_VREG_VALUE(v0);
#if ECMASCRIPT_ENABLE_IC
auto profileTypeInfo = GetRuntimeProfileTypeInfo(sp);
if (!profileTypeInfo.IsUndefined()) {
SAVE_ACC();
uint16_t slotId = READ_INST_16_0();
auto profileTypeArray = ProfileTypeInfo::Cast(profileTypeInfo.GetTaggedObject());
JSTaggedValue firstValue = profileTypeArray->Get(slotId);
JSTaggedValue value = GET_ACC();
JSTaggedValue res = JSTaggedValue::Hole();
if (LIKELY(firstValue.IsHeapObject())) {
JSTaggedValue secondValue = profileTypeArray->Get(slotId + 1);
res = ICRuntimeStub::TryStoreICByValue(thread,
receiver, JSTaggedValue(index), firstValue, secondValue, value);
}
// IC miss and not enter the megamorphic state, store as polymorphic
if (res.IsHole() && !firstValue.IsHole()) {
res = ICRuntimeStub::StoreOwnICByValue(thread,
profileTypeArray, receiver, JSTaggedValue(index), value, slotId);
}
if (LIKELY(!res.IsHole())) {
INTERPRETER_RETURN_IF_ABRUPT(res);
RESTORE_ACC();
DISPATCH(STOWNBYINDEX_IMM16_V8_IMM16);
}
}
#endif
// fast path
if (receiver.IsHeapObject() && !receiver.IsClassConstructor() && !receiver.IsClassPrototype()) {
SAVE_ACC();

View File

@ -139,6 +139,7 @@ namespace panda::ecmascript {
V(TryLoadICByValue) \
V(LoadICByValue) \
V(TryStoreICByName) \
V(StoreOwnICByValue) \
V(StoreICByName) \
V(TryStoreICByValue) \
V(StoreICByValue) \

View File

@ -1088,6 +1088,24 @@ DEF_RUNTIME_STUBS(StoreICByValue)
return icRuntime.StoreMiss(receiver, propKey, value).GetRawData();
}
DEF_RUNTIME_STUBS(StoreOwnICByValue)
{
RUNTIME_STUBS_HEADER(StoreOwnICByValue);
JSHandle<JSTaggedValue> profileTypeInfo = GetHArg<JSTaggedValue>(argv, argc, 0); // 0: means the zeroth parameter
JSHandle<JSTaggedValue> receiver = GetHArg<JSTaggedValue>(argv, argc, 1); // 1: means the first parameter
JSHandle<JSTaggedValue> key = GetHArg<JSTaggedValue>(argv, argc, 2); // 2: means the second parameter
JSHandle<JSTaggedValue> value = GetHArg<JSTaggedValue>(argv, argc, 3); // 3: means the third parameter
JSTaggedValue slotId = GetArg(argv, argc, 4); // 4: means the fourth parameter
if (profileTypeInfo->IsUndefined()) {
return RuntimeStOwnByIndex(thread, receiver, key, value).GetRawData();
}
JSHandle<JSTaggedValue> propKey = JSTaggedValue::ToPropertyKey(thread, key);
RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, JSTaggedValue::Exception().GetRawData());
StoreICRuntime icRuntime(thread, JSHandle<ProfileTypeInfo>::Cast(profileTypeInfo), slotId.GetInt(),
ICKind::StoreIC);
return icRuntime.StoreMiss(receiver, propKey, value, true).GetRawData();
}
DEF_RUNTIME_STUBS(StOwnByValue)
{
RUNTIME_STUBS_HEADER(StOwnByValue);

View File

@ -229,6 +229,7 @@ using FastCallAotEntryType = JSTaggedValue (*)(uintptr_t glue, uint32_t argc, co
V(SetObjectWithProto) \
V(LoadICByValue) \
V(StoreICByValue) \
V(StoreOwnICByValue) \
V(StOwnByValue) \
V(LdSuperByValue) \
V(StSuperByValue) \

View File

@ -15,3 +15,27 @@
123
2
2.1
1
2
3
4
5
99.99
ark
-88.48
brk
-1024
crk
6666
drk
in 1 second,now,now,1 second ago
in 1 minute,this minute,this minute,1 minute ago
2
ok
1
2
3
yes
no
4
5

View File

@ -33,12 +33,137 @@ function foo(p) {
return p[1]
}
let a = [1, 2]
let b = [1, 2.1, 3]
for (let i = 0; i < 100000; i++) {
var a1 = foo(a)
var a2 = foo(b);
{
let a = [1, 2]
let b = [1, 2.1, 3]
for (let i = 0; i < 10000; i++) {
var a1 = foo(a)
var a2 = foo(b);
}
print(a1)
print(a2)
}
print(a1)
print(a2)
// test stownbyindex ic: (too many loop will fail at debug unittest timeout)
class Attrs {
constructor(a : number, b : number, c : number) {
this.x = a;
this.y = b;
this.z = c;
}
x : number;
y : number;
z : number;
}
function test() : void {
for (let j = 0; j < 5; ++j) {
var _attrs : Attrs[] = [
new Attrs(1, 1, 1),
new Attrs(2, 2, 2),
new Attrs(3, 3, 3),
new Attrs(4, 4, 4),
new Attrs(5, 5, 5),
];
}
}
for (let i = 0; i < 100; i++){
test();
}
for (let j = 0; j < 5; ++j) {
var _attrs : Attrs[] = [
new Attrs(1, 1, 1),
new Attrs(2, 2, 2),
new Attrs(3, 3, 3),
new Attrs(4, 4, 4),
new Attrs(5, 5, 5),
];
print(_attrs[j].x);
}
const tests = [
[99.99, "ark"],
[-88.48, "brk"],
[-1024, "crk"],
[6666, "drk"],
];
for (let i = 0; i < 100; i++){
for (const [number, strData] of tests) {
}
}
for (const [number, strData] of tests) {
print(number);
print(strData);
}
const exceptions = {
"minute" : {
"-1" : "1 minute ago",
'0' : 'this minute',
"1" : "in 1 minute",
},
"second" : {
"-1" : "1 second ago",
"0" : "now",
"1" : "in 1 second",
},
};
const units = [
"second",
"minute",
];
for (let i = 0; i < 100; i++){
for (const unit of units) {
const expected = unit in exceptions ?
[exceptions[unit]["1"], exceptions[unit]["0"], exceptions[unit]["0"], exceptions[unit]["-1"]] :
[`in 1 ${unit}`, `in 0 ${unit}s`, `0 ${unit}s ago`, `1 ${unit} ago`];
}
}
for (const unit of units) {
const expected = unit in exceptions ?
[exceptions[unit]["1"], exceptions[unit]["0"], exceptions[unit]["0"], exceptions[unit]["-1"]] :
[`in 1 ${unit}`, `in 0 ${unit}s`, `0 ${unit}s ago`, `1 ${unit} ago`];
print(expected);
}
for (let i = 0; i < 100; i++){
Object.defineProperty(Array.prototype, '0', {
value: 42,
});
let arr = [, 2, 3];
arr.pop();
}
Object.defineProperty(Array.prototype, '0', {
value: 42,
});
let arr = [, 2, 3];
arr.pop();
print(arr[1]);
for (let i = 0; i < 100; i++){
var a : any[] = [ ["ok"], [1, 2, 3] ];
var b = {
1 : ["yes", "no"],
"100" : [4, 5],
}
}
print(a[0][0]);
print(a[1][0]);
print(a[1][1]);
print(a[1][2]);
print(b[1][0]);
print(b[1][1]);
print(b["100"][0]);
print(b["100"][1]);