1 /*
2 * Copyright (c) 2022 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include "ecmascript/ic/ic_runtime.h"
17 #include "ecmascript/interpreter/slow_runtime_stub.h"
18 #include "ecmascript/global_env.h"
19 #include "ecmascript/object_operator.h"
20 #include "ecmascript/tests/test_helper.h"
21
22 using namespace panda;
23 using namespace panda::ecmascript;
24
25 namespace panda::test {
26 class ICRunTimeTest : public testing::Test {
27 public:
SetUpTestCase()28 static void SetUpTestCase()
29 {
30 GTEST_LOG_(INFO) << "SetUpTestCase";
31 }
32
TearDownTestCase()33 static void TearDownTestCase()
34 {
35 GTEST_LOG_(INFO) << "TearDownCase";
36 }
37
SetUp()38 void SetUp() override
39 {
40 TestHelper::CreateEcmaVMWithScope(instance, thread, scope);
41 }
42
TearDown()43 void TearDown() override
44 {
45 TestHelper::DestroyEcmaVMWithScope(instance, scope);
46 }
47
48 EcmaVM *instance {nullptr};
49 EcmaHandleScope *scope {nullptr};
50 JSThread *thread {nullptr};
51 };
52
HWTEST_F_L0(ICRunTimeTest,UpdateLoadHandler)53 HWTEST_F_L0(ICRunTimeTest, UpdateLoadHandler)
54 {
55 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
56 JSHandle<GlobalEnv> env = thread->GetEcmaVM()->GetGlobalEnv();
57 auto globalConst = thread->GlobalConstants();
58 uint32_t arrayLength = 5;
59
60 JSHandle<JSTaggedValue> objFun = env->GetArrayFunction();
61 JSHandle<JSTaggedValue> handleReceiver(factory->NewJSObjectByConstructor(JSHandle<JSFunction>(objFun), objFun));
62 JSHandle<JSTaggedValue> handleKeyWithElement(factory->NewFromASCII("2"));
63 JSHandle<JSTaggedValue> handleKeyWithString(factory->NewFromASCII("key"));
64 JSHandle<JSTaggedValue> handleStoreArray(factory->NewTaggedArray(2));
65 JSHandle<JSTaggedValue> undefinedVal;
66
67 JSHandle<TaggedArray> handleTaggedArray = factory->NewTaggedArray(arrayLength);
68 for (uint32_t i = 0; i < arrayLength; i++) {
69 undefinedVal = globalConst->GetHandledUndefinedString();
70 if (i == static_cast<uint32_t>(ICKind::NamedLoadIC) || i == static_cast<uint32_t>(ICKind::LoadIC)) {
71 undefinedVal = handleStoreArray;
72 }
73 else if (i == static_cast<uint32_t>(ICKind::NamedLoadIC) + 1 ||
74 i == static_cast<uint32_t>(ICKind::LoadIC) + 1) {
75 undefinedVal = JSHandle<JSTaggedValue>(thread, JSTaggedValue::Hole());
76 }
77 handleTaggedArray->Set(thread, i, undefinedVal.GetTaggedValue());
78 }
79 JSHandle<ProfileTypeInfo> handleProfileTypeInfo = JSHandle<ProfileTypeInfo>::Cast(handleTaggedArray);
80 // test op is Element
81 ObjectOperator handleOp1(thread, handleKeyWithElement);
82 uint32_t slotId = 2;
83 ICRuntime icRuntime(thread, handleProfileTypeInfo, slotId, ICKind::LoadIC);
84 icRuntime.UpdateLoadHandler(handleOp1, handleKeyWithElement, handleReceiver);
85 EXPECT_TRUE(handleProfileTypeInfo->Get(slotId).IsTaggedArray());
86 EXPECT_TRUE(handleProfileTypeInfo->Get(slotId + 1).IsHole());
87 // test op is not Element
88 ObjectOperator handleOp2(thread, handleKeyWithString);
89 slotId = 0;
90 ICRuntime icRuntime1(thread, handleProfileTypeInfo, slotId, ICKind::NamedLoadIC);
91 icRuntime1.UpdateLoadHandler(handleOp2, handleKeyWithString, handleReceiver);
92 EXPECT_TRUE(handleProfileTypeInfo->Get(slotId).IsTaggedArray());
93 EXPECT_TRUE(handleProfileTypeInfo->Get(slotId + 1).IsHole());
94 }
95
HWTEST_F_L0(ICRunTimeTest,UpdateStoreHandler)96 HWTEST_F_L0(ICRunTimeTest, UpdateStoreHandler)
97 {
98 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
99 JSHandle<GlobalEnv> env = thread->GetEcmaVM()->GetGlobalEnv();
100 auto globalConst = thread->GlobalConstants();
101 uint32_t arrayLength = 5;
102
103 JSHandle<JSTaggedValue> objFun = env->GetArrayFunction();
104 JSHandle<JSTaggedValue> handleReceiver(factory->NewJSObjectByConstructor(JSHandle<JSFunction>(objFun), objFun));
105 JSHandle<JSTaggedValue> handleKeyWithElement(factory->NewFromASCII("2"));
106 JSHandle<JSTaggedValue> handleKeyWithString(factory->NewFromASCII("key"));
107 JSHandle<JSTaggedValue> handleStoreArray(factory->NewTaggedArray(2));
108 JSHandle<JSTaggedValue> undefinedVal;
109
110 JSHandle<TaggedArray> handleTaggedArray = factory->NewTaggedArray(arrayLength);
111 for (uint32_t i = 0; i < arrayLength; i++) {
112 undefinedVal = globalConst->GetHandledUndefinedString();
113 if (i == static_cast<uint32_t>(ICKind::NamedStoreIC) || i == static_cast<uint32_t>(ICKind::StoreIC)) {
114 undefinedVal = JSHandle<JSTaggedValue>(thread, JSTaggedValue::Undefined());
115 }
116 else if (i == static_cast<uint32_t>(ICKind::NamedStoreIC) + 1 ||
117 i == static_cast<uint32_t>(ICKind::StoreIC) + 1) {
118 undefinedVal = handleStoreArray;
119 }
120 handleTaggedArray->Set(thread, i, undefinedVal.GetTaggedValue());
121 }
122 JSHandle<ProfileTypeInfo> handleProfileTypeInfo = JSHandle<ProfileTypeInfo>::Cast(handleTaggedArray);
123 // test op is Element
124 uint32_t slotId = 3;
125 ObjectOperator handleOp1(thread, handleKeyWithElement);
126 handleOp1.SetIsOnPrototype(true);
127 handleOp1.SetIndex(slotId);
128 ICRuntime icRuntime(thread, handleProfileTypeInfo, slotId, ICKind::StoreIC);
129 icRuntime.UpdateReceiverHClass(JSHandle<JSTaggedValue>(thread, JSHandle<JSObject>(handleReceiver)->GetJSHClass()));
130 icRuntime.UpdateStoreHandler(handleOp1, handleKeyWithElement, handleReceiver);
131 EXPECT_TRUE(handleProfileTypeInfo->Get(slotId).IsWeak());
132 EXPECT_TRUE(handleProfileTypeInfo->Get(slotId + 1).IsPrototypeHandler());
133 // test op is Transition
134 slotId = 1;
135 ObjectOperator handleOp2(thread, handleReceiver, handleKeyWithString, OperatorType::OWN);
136 handleOp2.SetIsTransition(true);
137 handleOp2.SetFastMode(true);
138 handleOp2.SetIndex(slotId);
139 ICRuntime icRuntime1(thread, handleProfileTypeInfo, slotId, ICKind::NamedStoreIC);
140 icRuntime1.UpdateReceiverHClass(env->GetArgumentsClass());
141 icRuntime1.UpdateStoreHandler(handleOp2, handleKeyWithString, handleReceiver);
142 EXPECT_TRUE(handleProfileTypeInfo->Get(slotId).IsWeak());
143 EXPECT_TRUE(handleProfileTypeInfo->Get(slotId + 1).IsTransitionHandler());
144 }
145
HWTEST_F_L0(ICRunTimeTest,TraceIC)146 HWTEST_F_L0(ICRunTimeTest, TraceIC)
147 {
148 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
149 JSHandle<GlobalEnv> env = thread->GetEcmaVM()->GetGlobalEnv();
150 uint32_t arrayLength = 5;
151 JSHandle<JSTaggedValue> objFun = env->GetArrayFunction();
152 JSHandle<JSTaggedValue> handleReceiver(factory->NewJSObjectByConstructor(JSHandle<JSFunction>(objFun), objFun));
153 JSHandle<JSTaggedValue> handleKeyWithString(factory->NewFromASCII("key"));
154 JSHandle<JSTaggedValue> handleKeyWithElement(thread, JSTaggedValue(2));
155
156 JSHandle<TaggedArray> handleTaggedArray = factory->NewTaggedArray(arrayLength);
157 JSHandle<ProfileTypeInfo> handleProfileTypeInfo = JSHandle<ProfileTypeInfo>::Cast(handleTaggedArray);
158
159 ICRuntime icRuntime(thread, handleProfileTypeInfo, 4, ICKind::NamedGlobalLoadIC); // 4: means the NamedGlobalLoadIC
160 icRuntime.TraceIC(handleReceiver, handleKeyWithString);
161 icRuntime.TraceIC(handleReceiver, handleKeyWithElement);
162 }
163
HWTEST_F_L0(ICRunTimeTest,StoreMiss)164 HWTEST_F_L0(ICRunTimeTest, StoreMiss)
165 {
166 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
167 JSHandle<GlobalEnv> env = thread->GetEcmaVM()->GetGlobalEnv();
168 uint32_t arrayLength = 2;
169
170 JSHandle<JSTaggedValue> objFun = env->GetTypedArrayFunction();
171 JSHandle<JSTaggedValue> handleReceiver(factory->NewJSObjectByConstructor(JSHandle<JSFunction>(objFun), objFun));
172 JSHandle<JSTaggedValue> handleReceiver1(factory->NewJSArray());
173 JSHandle<JSTaggedValue> handleKeyWithString(factory->NewFromASCII("key"));
174 JSHandle<JSTaggedValue> handleValueWithElement(thread, JSTaggedValue(2));
175
176 JSHandle<TaggedArray> handleTaggedArray = factory->NewTaggedArray(arrayLength);
177 JSHandle<ProfileTypeInfo> handleProfileTypeInfo = JSHandle<ProfileTypeInfo>::Cast(handleTaggedArray);
178 StoreICRuntime storeICRuntime(thread, handleProfileTypeInfo, 0, ICKind::NamedGlobalStoreIC);
179 storeICRuntime.StoreMiss(handleReceiver, handleKeyWithString, handleValueWithElement);
180 EXPECT_EQ(JSObject::GetProperty(thread, handleReceiver, handleKeyWithString).GetValue(), handleValueWithElement);
181 EXPECT_TRUE(handleProfileTypeInfo->Get(0).IsHole());
182 EXPECT_TRUE(handleProfileTypeInfo->Get(1).IsHole());
183
184 SlowRuntimeStub::StGlobalRecord(thread, handleKeyWithString.GetTaggedValue(),
185 handleKeyWithString.GetTaggedValue(), false);
186 handleTaggedArray->Set(thread, 0, JSTaggedValue::Undefined());
187 storeICRuntime.StoreMiss(handleReceiver1, handleKeyWithString, handleValueWithElement);
188 EXPECT_TRUE(handleProfileTypeInfo->Get(0).IsPropertyBox());
189 }
190
HWTEST_F_L0(ICRunTimeTest,LoadMiss)191 HWTEST_F_L0(ICRunTimeTest, LoadMiss)
192 {
193 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
194 JSHandle<GlobalEnv> env = thread->GetEcmaVM()->GetGlobalEnv();
195 uint32_t arrayLength = 2;
196
197 JSHandle<JSTaggedValue> objFun = env->GetTypedArrayFunction();
198 JSHandle<JSTaggedValue> handleReceiver(factory->NewJSObjectByConstructor(JSHandle<JSFunction>(objFun), objFun));
199 JSHandle<JSTaggedValue> handleReceiver1(factory->NewJSArray());
200 JSHandle<JSTaggedValue> handleKeyWithString(factory->NewFromASCII("key"));
201 JSHandle<JSTaggedValue> handleValueWithElement(thread, JSTaggedValue(2));
202 JSObject::SetProperty(thread, handleReceiver, handleKeyWithString, handleValueWithElement);
203
204 JSHandle<TaggedArray> handleTaggedArray = factory->NewTaggedArray(arrayLength);
205 JSHandle<ProfileTypeInfo> handleProfileTypeInfo = JSHandle<ProfileTypeInfo>::Cast(handleTaggedArray);
206 LoadICRuntime loadICRuntime(thread, handleProfileTypeInfo, 0, ICKind::NamedGlobalStoreIC);
207 EXPECT_EQ(loadICRuntime.LoadMiss(handleReceiver, handleKeyWithString), handleValueWithElement.GetTaggedValue());
208 EXPECT_TRUE(handleProfileTypeInfo->Get(0).IsHole());
209 EXPECT_TRUE(handleProfileTypeInfo->Get(1).IsHole());
210 }
211 } // namespace panda::test
212