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/ic/profile_type_info.h"
18#include "ecmascript/interpreter/slow_runtime_stub.h"
19#include "ecmascript/global_env.h"
20#include "ecmascript/object_operator.h"
21#include "ecmascript/tests/test_helper.h"
22
23using namespace panda;
24using namespace panda::ecmascript;
25
26namespace panda::test {
27class ICRunTimeTest : public testing::Test {
28public:
29    static void SetUpTestCase()
30    {
31        GTEST_LOG_(INFO) << "SetUpTestCase";
32    }
33
34    static void TearDownTestCase()
35    {
36        GTEST_LOG_(INFO) << "TearDownCase";
37    }
38
39    void SetUp() override
40    {
41        TestHelper::CreateEcmaVMWithScope(instance, thread, scope);
42    }
43
44    void TearDown() override
45    {
46        TestHelper::DestroyEcmaVMWithScope(instance, scope);
47    }
48
49    EcmaVM *instance {nullptr};
50    EcmaHandleScope *scope {nullptr};
51    JSThread *thread {nullptr};
52};
53
54HWTEST_F_L0(ICRunTimeTest, UpdateLoadHandler)
55{
56    ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
57    JSHandle<GlobalEnv> env = thread->GetEcmaVM()->GetGlobalEnv();
58    auto globalConst = thread->GlobalConstants();
59    uint32_t arrayLength = 5;
60
61    JSHandle<JSTaggedValue> objFun = env->GetArrayFunction();
62    JSHandle<JSTaggedValue> handleReceiver(factory->NewJSObjectByConstructor(JSHandle<JSFunction>(objFun), objFun));
63    JSHandle<JSTaggedValue> handleKeyWithElement(factory->NewFromASCII("2"));
64    JSHandle<JSTaggedValue> handleKeyWithString(factory->NewFromASCII("key"));
65    JSHandle<JSTaggedValue> handleStoreArray(factory->NewTaggedArray(2));
66    JSHandle<JSTaggedValue> undefinedVal;
67
68    JSHandle<ProfileTypeInfo> handleProfileTypeInfo = factory->NewProfileTypeInfo(arrayLength);
69    for (uint32_t i = 0; i < arrayLength; i++) {
70        undefinedVal = globalConst->GetHandledUndefinedString();
71        if (i == static_cast<uint32_t>(ICKind::NamedLoadIC) || i == static_cast<uint32_t>(ICKind::LoadIC)) {
72            undefinedVal = handleStoreArray;
73        }
74        else if (i == static_cast<uint32_t>(ICKind::NamedLoadIC) + 1 ||
75                 i == static_cast<uint32_t>(ICKind::LoadIC) + 1) {
76            undefinedVal = JSHandle<JSTaggedValue>(thread, JSTaggedValue::Hole());
77        }
78        handleProfileTypeInfo->Set(thread, i, undefinedVal.GetTaggedValue());
79    }
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
96HWTEST_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<ProfileTypeInfo> handleProfileTypeInfo = factory->NewProfileTypeInfo(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        handleProfileTypeInfo->Set(thread, i, undefinedVal.GetTaggedValue());
121    }
122    // test op is Element
123    uint32_t slotId = 3;
124    ObjectOperator handleOp1(thread, handleKeyWithElement);
125    handleOp1.SetIsOnPrototype(true);
126    handleOp1.SetIndex(slotId);
127    ICRuntime icRuntime(thread, handleProfileTypeInfo, slotId, ICKind::StoreIC);
128    icRuntime.UpdateReceiverHClass(JSHandle<JSTaggedValue>(thread, JSHandle<JSObject>(handleReceiver)->GetJSHClass()));
129    icRuntime.UpdateStoreHandler(handleOp1, handleKeyWithElement, handleReceiver);
130    EXPECT_TRUE(handleProfileTypeInfo->Get(slotId).IsWeak());
131    EXPECT_TRUE(handleProfileTypeInfo->Get(slotId + 1).IsPrototypeHandler());
132    // test op is Transition
133    slotId = 1;
134    ObjectOperator handleOp2(thread, handleReceiver, handleKeyWithString, OperatorType::OWN);
135    handleOp2.SetIsTransition(true);
136    handleOp2.SetFastMode(true);
137    handleOp2.SetIndex(slotId);
138    ICRuntime icRuntime1(thread, handleProfileTypeInfo, slotId, ICKind::NamedStoreIC);
139    icRuntime1.UpdateReceiverHClass(env->GetArgumentsClass());
140    icRuntime1.UpdateStoreHandler(handleOp2, handleKeyWithString, handleReceiver);
141    EXPECT_TRUE(handleProfileTypeInfo->Get(slotId).IsWeak());
142    EXPECT_TRUE(handleProfileTypeInfo->Get(slotId + 1).IsTransitionHandler());
143}
144
145HWTEST_F_L0(ICRunTimeTest, TraceIC)
146{
147    ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
148    JSHandle<GlobalEnv> env = thread->GetEcmaVM()->GetGlobalEnv();
149    uint32_t arrayLength = 5;
150    JSHandle<JSTaggedValue> objFun = env->GetArrayFunction();
151    JSHandle<JSTaggedValue> handleReceiver(factory->NewJSObjectByConstructor(JSHandle<JSFunction>(objFun), objFun));
152    JSHandle<JSTaggedValue> handleKeyWithString(factory->NewFromASCII("key"));
153    JSHandle<JSTaggedValue> handleKeyWithElement(thread, JSTaggedValue(2));
154
155    JSHandle<ProfileTypeInfo> handleProfileTypeInfo = factory->NewProfileTypeInfo(arrayLength);
156
157    ICRuntime icRuntime(thread, handleProfileTypeInfo, 4, ICKind::NamedGlobalLoadIC);  // 4: means the NamedGlobalLoadIC
158    icRuntime.TraceIC(handleReceiver, handleKeyWithString);
159    icRuntime.TraceIC(handleReceiver, handleKeyWithElement);
160}
161
162HWTEST_F_L0(ICRunTimeTest, StoreMiss)
163{
164    ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
165    JSHandle<GlobalEnv> env = thread->GetEcmaVM()->GetGlobalEnv();
166    uint32_t arrayLength = 2;
167
168    JSHandle<JSTaggedValue> objFun = env->GetTypedArrayFunction();
169    JSHandle<JSTaggedValue> handleReceiver(factory->NewJSObjectByConstructor(JSHandle<JSFunction>(objFun), objFun));
170    JSHandle<JSTaggedValue> handleReceiver1(factory->NewJSArray());
171    JSHandle<JSTaggedValue> handleKeyWithString(factory->NewFromASCII("key"));
172    JSHandle<JSTaggedValue> handleValueWithElement(thread, JSTaggedValue(2));
173
174    JSHandle<ProfileTypeInfo> handleProfileTypeInfo = factory->NewProfileTypeInfo(arrayLength);
175    handleProfileTypeInfo->Set(thread, 0, JSTaggedValue::Hole());
176    handleProfileTypeInfo->Set(thread, 1, JSTaggedValue::Hole());
177    StoreICRuntime storeICRuntime(thread, handleProfileTypeInfo, 0, ICKind::NamedGlobalStoreIC);
178    storeICRuntime.StoreMiss(handleReceiver, handleKeyWithString, handleValueWithElement);
179    EXPECT_EQ(JSObject::GetProperty(thread, handleReceiver, handleKeyWithString).GetValue(), handleValueWithElement);
180    EXPECT_TRUE(handleProfileTypeInfo->Get(0).IsHole());
181    EXPECT_TRUE(handleProfileTypeInfo->Get(1).IsHole());
182
183    SlowRuntimeStub::StGlobalRecord(thread, handleKeyWithString.GetTaggedValue(),
184                                    handleKeyWithString.GetTaggedValue(), false);
185    handleProfileTypeInfo->Set(thread, 0, JSTaggedValue::Undefined());
186    storeICRuntime.StoreMiss(handleReceiver1, handleKeyWithString, handleValueWithElement);
187    EXPECT_TRUE(handleProfileTypeInfo->Get(0).IsPropertyBox());
188}
189
190HWTEST_F_L0(ICRunTimeTest, LoadMiss)
191{
192    ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
193    JSHandle<GlobalEnv> env = thread->GetEcmaVM()->GetGlobalEnv();
194    uint32_t arrayLength = 2;
195
196    JSHandle<JSTaggedValue> objFun = env->GetTypedArrayFunction();
197    JSHandle<JSTaggedValue> handleReceiver(factory->NewJSObjectByConstructor(JSHandle<JSFunction>(objFun), objFun));
198    JSHandle<JSTaggedValue> handleReceiver1(factory->NewJSArray());
199    JSHandle<JSTaggedValue> handleKeyWithString(factory->NewFromASCII("key"));
200    JSHandle<JSTaggedValue> handleValueWithElement(thread, JSTaggedValue(2));
201    JSObject::SetProperty(thread, handleReceiver, handleKeyWithString, handleValueWithElement);
202
203    JSHandle<ProfileTypeInfo> handleProfileTypeInfo = factory->NewProfileTypeInfo(arrayLength);
204    handleProfileTypeInfo->Set(thread, 0, JSTaggedValue::Hole());
205    handleProfileTypeInfo->Set(thread, 1, JSTaggedValue::Hole());
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