1 /*
2 * Copyright (c) 2021 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_handler.h"
17 #include "ecmascript/ic/proto_change_details.h"
18 #include "ecmascript/global_env.h"
19 #include "ecmascript/js_array.h"
20 #include "ecmascript/js_hclass.h"
21 #include "ecmascript/js_object-inl.h"
22 #include "ecmascript/object_operator.h"
23 #include "ecmascript/tests/test_helper.h"
24
25 using namespace panda::ecmascript;
26
27 namespace panda::test {
28 using HandlerKind = ecmascript::HandlerBase::HandlerKind;
29 class ICHandlerTest : public testing::Test {
30 public:
SetUpTestCase()31 static void SetUpTestCase()
32 {
33 GTEST_LOG_(INFO) << "SetUpTestCase";
34 }
35
TearDownTestCase()36 static void TearDownTestCase()
37 {
38 GTEST_LOG_(INFO) << "TearDownCase";
39 }
40
SetUp()41 void SetUp() override
42 {
43 TestHelper::CreateEcmaVMWithScope(instance, thread, scope);
44 }
45
TearDown()46 void TearDown() override
47 {
48 TestHelper::DestroyEcmaVMWithScope(instance, scope);
49 }
50
51 EcmaVM *instance {nullptr};
52 EcmaHandleScope *scope {nullptr};
53 JSThread *thread {nullptr};
54 };
55
56 /**
57 * @tc.name: LoadElement
58 * @tc.desc: Call "LoadElement" function,check whether the Element is loaded successfully by checking returned value.
59 * @tc.type: FUNC
60 * @tc.require:
61 */
HWTEST_F_L0(ICHandlerTest,LoadElement)62 HWTEST_F_L0(ICHandlerTest, LoadElement)
63 {
64 JSTaggedValue result = LoadHandler::LoadElement(thread).GetTaggedValue();
65 EXPECT_TRUE(HandlerBase::IsElement(result.GetInt()));
66 EXPECT_EQ(HandlerBase::GetKind(result.GetInt()), HandlerKind::ELEMENT);
67 }
68
69 /**
70 * @tc.name: LoadProperty
71 * @tc.desc: Call "LoadProperty" function,check whether the Property is loaded successfully by checking returned value.
72 * @tc.type: FUNC
73 * @tc.require:
74 */
HWTEST_F_L0(ICHandlerTest,LoadProperty)75 HWTEST_F_L0(ICHandlerTest, LoadProperty)
76 {
77 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
78 JSHandle<GlobalEnv> env = thread->GetEcmaVM()->GetGlobalEnv();
79
80 JSHandle<JSTaggedValue> objFun = env->GetArrayFunction();
81 JSHandle<JSTaggedValue> handleValue(thread, JSTaggedValue(1));
82 JSHandle<JSTaggedValue> handleKey(factory->NewFromASCII("key"));
83 int index = 1;
84 PropertyAttributes handleAttriButes(2);
85 handleAttriButes.SetIsInlinedProps(true);
86 // test op is not Found
87 ObjectOperator handleOp1(thread, handleKey);
88 JSHandle<JSTaggedValue> handlerInfo1 = LoadHandler::LoadProperty(thread, handleOp1);
89 EXPECT_TRUE(HandlerBase::IsNonExist(handlerInfo1->GetInt()));
90 EXPECT_EQ(HandlerBase::GetKind(handlerInfo1->GetInt()), HandlerKind::NON_EXIST);
91 // test op is Found and FastMode
92 JSHandle<JSTaggedValue> handleHolder(factory->NewJSObjectByConstructor(JSHandle<JSFunction>(objFun), objFun));
93 ObjectOperator handleOp2(thread, handleHolder, handleKey);
94 handleOp2.SetFastMode(true);
95 handleOp2.SetIndex(index);
96 JSHandle<JSTaggedValue> handlerInfo2 = LoadHandler::LoadProperty(thread, handleOp2);
97 EXPECT_EQ(HandlerBase::GetOffset(handlerInfo2->GetInt()), 1);
98 // test op is Found and InlinedProps
99 handleOp2.SetAttr(handleAttriButes);
100 JSHandle<JSTaggedValue> handlerInfo3 = LoadHandler::LoadProperty(thread, handleOp2);
101 EXPECT_EQ(HandlerBase::GetKind(handlerInfo3->GetInt()), HandlerKind::FIELD);
102 EXPECT_EQ(HandlerBase::GetOffset(handlerInfo3->GetInt()), 5);
103 EXPECT_TRUE(HandlerBase::IsInlinedProps(handlerInfo3->GetInt()));
104 }
105
106 /**
107 * @tc.name: StoreElement
108 * @tc.desc: Call "StoreElement" function,check whether the Element is stored successfully by checking returned value.
109 * @tc.type: FUNC
110 * @tc.require:
111 */
HWTEST_F_L0(ICHandlerTest,StoreElement)112 HWTEST_F_L0(ICHandlerTest, StoreElement)
113 {
114 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
115
116 JSArray *handleArr = JSArray::ArrayCreate(thread, JSTaggedNumber(0)).GetObject<JSArray>();
117 JSHandle<JSTaggedValue> handleReceiver1(thread, handleArr);
118 JSHandle<JSTaggedValue> handleReceiver2(factory->NewJSArray());
119 JSHandle<JSTaggedValue> handleValue(thread, JSTaggedValue(1));
120
121 JSHandle<JSTaggedValue> handlerInfo1 = StoreHandler::StoreElement(thread, handleReceiver1);
122 JSHandle<JSTaggedValue> handlerInfo2 = StoreHandler::StoreElement(thread, handleReceiver2);
123 JSHandle<JSTaggedValue> handlerInfo3 = StoreHandler::StoreElement(thread, handleValue);
124
125 EXPECT_EQ(HandlerBase::GetKind(handlerInfo1->GetInt()), HandlerKind::ELEMENT);
126 EXPECT_EQ(HandlerBase::GetKind(handlerInfo2->GetInt()), HandlerKind::ELEMENT);
127 EXPECT_EQ(HandlerBase::GetKind(handlerInfo3->GetInt()), HandlerKind::ELEMENT);
128
129 EXPECT_TRUE(HandlerBase::IsJSArray(handlerInfo1->GetInt()));
130 EXPECT_TRUE(HandlerBase::IsJSArray(handlerInfo2->GetInt()));
131 EXPECT_FALSE(HandlerBase::IsJSArray(handlerInfo3->GetInt()));
132 }
133
134 /**
135 * @tc.name: StoreProperty
136 * @tc.desc: Call "StoreProperty" function,check whether the Property is stored successfully by checking returned value.
137 * according to the ObjectOperation object,the stored Property is different,the stored ObjectOperation object
138 * is Found.
139 * @tc.type: FUNC
140 * @tc.require:
141 */
HWTEST_F_L0(ICHandlerTest,StoreProperty)142 HWTEST_F_L0(ICHandlerTest, StoreProperty)
143 {
144 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
145 JSHandle<GlobalEnv> env = thread->GetEcmaVM()->GetGlobalEnv();
146
147 JSHandle<JSTaggedValue> objFun = env->GetObjectFunction();
148 JSHandle<JSTaggedValue> handleValue(thread, JSTaggedValue(1));
149 JSHandle<JSTaggedValue> handleKey(factory->NewFromASCII("key"));
150 int index = 2;
151 PropertyAttributes handleAttriButes(2);
152 handleAttriButes.SetIsInlinedProps(true);
153
154 JSHandle<PropertyBox> cellHandle = factory->NewPropertyBox(handleKey);
155 ObjectOperator handleOp1(thread, handleKey);
156 handleOp1.SetValue(cellHandle.GetTaggedValue());
157 // test op value is PropertyBox
158 JSHandle<JSTaggedValue> handlerInfo1 = StoreHandler::StoreProperty(thread, handleOp1);
159 EXPECT_TRUE(handlerInfo1->IsPropertyBox());
160 // test op is FastMode/Found and not AccessorDescriptor
161 JSHandle<JSTaggedValue> handleReceiver(factory->NewJSObjectByConstructor(JSHandle<JSFunction>(objFun), objFun));
162 ObjectOperator handleOp2(thread, handleReceiver, handleKey);
163 handleOp2.SetFastMode(true);
164 handleOp2.SetIndex(index);
165 JSHandle<JSTaggedValue> handlerInfo2 = StoreHandler::StoreProperty(thread, handleOp2);
166 EXPECT_EQ(HandlerBase::GetOffset(handlerInfo2->GetInt()), 2);
167 EXPECT_FALSE(HandlerBase::IsAccessor(handlerInfo2->GetInt()));
168 // test op is InlinedProps/Found and not AccessorDescriptor
169 handleOp2.SetAttr(handleAttriButes);
170 JSHandle<JSTaggedValue> handlerInfo3 = StoreHandler::StoreProperty(thread, handleOp2);
171 EXPECT_EQ(HandlerBase::GetKind(handlerInfo3->GetInt()), HandlerKind::FIELD);
172 EXPECT_EQ(HandlerBase::GetOffset(handlerInfo3->GetInt()), 6);
173 EXPECT_TRUE(HandlerBase::IsInlinedProps(handlerInfo3->GetInt()));
174 }
175
176 /**
177 * @tc.name: StoreTransition
178 * @tc.desc: Call "StoreTransition" function,check whether the Transition is stored successfully by checking
179 * returned value.
180 * @tc.type: FUNC
181 * @tc.require:
182 */
HWTEST_F_L0(ICHandlerTest,StoreTransition)183 HWTEST_F_L0(ICHandlerTest, StoreTransition)
184 {
185 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
186 JSHandle<GlobalEnv> env = thread->GetEcmaVM()->GetGlobalEnv();
187 JSHandle<JSTaggedValue> objFun = env->GetObjectFunction();
188 JSHandle<JSTaggedValue> handleValue(thread, JSTaggedValue(1));
189 JSHandle<JSTaggedValue> handleKey(factory->NewFromASCII("key"));
190
191 JSHandle<PropertyBox> cellHandle = factory->NewPropertyBox(handleKey);
192 JSHandle<JSTaggedValue> handleHolder(factory->NewJSObjectByConstructor(JSHandle<JSFunction>(objFun), objFun));
193
194 ObjectOperator handleOp(thread, handleHolder, handleKey);
195 handleOp.SetValue(cellHandle.GetTaggedValue());
196
197 JSHandle<JSTaggedValue> handlerValue = TransitionHandler::StoreTransition(thread, handleOp);
198 JSHandle<TransitionHandler> handler = JSHandle<TransitionHandler>::Cast(handlerValue);
199 EXPECT_TRUE(handler->GetHandlerInfo().IsPropertyBox());
200 EXPECT_TRUE(handler->GetTransitionHClass().IsHeapObject());
201 }
202
203 /**
204 * @tc.name: LoadPrototype
205 * @tc.desc: Call "LoadPrototype" function,check whether the Prototype is loaded successfully by checking returned value
206 * according to the ObjectOperation object,the stored Property is different.
207 * @tc.type: FUNC
208 * @tc.require:
209 */
HWTEST_F_L0(ICHandlerTest,LoadPrototype)210 HWTEST_F_L0(ICHandlerTest, LoadPrototype)
211 {
212 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
213
214 JSHandle<JSTaggedValue> handleKey(factory->NewFromASCII("key"));
215 JSHandle<JSTaggedValue> handleValue(thread, JSTaggedValue(3));
216
217 JSHandle<JSObject> nullHandle(thread, JSTaggedValue::Null());
218 JSHandle<JSObject> handleObj1 = JSObject::ObjectCreate(thread, nullHandle);
219 JSHandle<JSObject> handleObj2 = JSObject::ObjectCreate(thread, handleObj1);
220
221 JSHandle<JSHClass> obj1Class(thread, handleObj1->GetJSHClass());
222 JSHandle<JSHClass> obj2Class(thread, handleObj2->GetJSHClass());
223
224 ObjectOperator handleOp1(thread, handleKey, OperatorType::OWN);
225 ObjectOperator handleOp2(thread, handleKey, OperatorType::OWN);
226 handleOp1.SetFastMode(true);
227 handleOp2.SetFastMode(true);
228 handleOp2.SetIndex(2);
229 // test op is not Found and hclass has no Prototype
230 JSHandle<JSTaggedValue> handlerValue1 = LoadHandler::LoadProperty(thread, handleOp1);
231 EXPECT_TRUE(HandlerBase::IsNonExist(handlerValue1->GetInt()));
232 // test op is Found and hclass has Prototype
233 JSHandle<JSTaggedValue> handlerValue2 = PrototypeHandler::LoadPrototype(thread, handleOp2, obj2Class);
234 JSHandle<PrototypeHandler> handler2 = JSHandle<PrototypeHandler>::Cast(handlerValue2);
235 JSHandle<JSTaggedValue> handlerInfo2(thread, handler2->GetHandlerInfo());
236 EXPECT_EQ(HandlerBase::GetOffset(handlerInfo2->GetInt()), 2);
237 JSHandle<JSTaggedValue> resultMarker(thread, handler2->GetProtoCell());
238 EXPECT_TRUE(resultMarker->IsProtoChangeMarker());
239 EXPECT_TRUE(handler2->GetHolder().IsJSGlobalObject());
240 }
241
242 /**
243 * @tc.name: StorePrototype
244 * @tc.desc: Call StorePrototype function,check whether the Prototype is stored successfully by checking returned value
245 * according to the ObjectOperation object,the stored Property is different.the stored ObjectOperation object
246 * must be Found.
247 * @tc.type: FUNC
248 * @tc.require:
249 */
HWTEST_F_L0(ICHandlerTest,StorePrototype)250 HWTEST_F_L0(ICHandlerTest, StorePrototype)
251 {
252 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
253
254 JSHandle<JSTaggedValue> handleKey(factory->NewFromASCII("key"));
255 JSHandle<JSTaggedValue> handleValue(thread, JSTaggedValue(3));
256
257 JSHandle<JSObject> nullHandle(thread, JSTaggedValue::Null());
258 JSHandle<JSObject> nullObj = JSObject::ObjectCreate(thread, nullHandle);
259 JSHandle<JSObject> handleObj = JSObject::ObjectCreate(thread, nullObj);
260
261 JSHandle<JSHClass> objClass(thread, handleObj->GetJSHClass());
262
263 ObjectOperator handleOp(thread, handleKey, OperatorType::OWN);
264 handleOp.SetFastMode(true);
265 handleOp.SetIndex(2);
266 // test hclass has Prototype
267 JSHandle<JSTaggedValue> handlerValue = PrototypeHandler::StorePrototype(thread, handleOp, objClass);
268 JSHandle<PrototypeHandler> handler = JSHandle<PrototypeHandler>::Cast(handlerValue);
269 JSHandle<JSTaggedValue> handlerInfo(thread, handler->GetHandlerInfo());
270 EXPECT_EQ(HandlerBase::GetOffset(handlerInfo->GetInt()), 2);
271 JSHandle<JSTaggedValue> resultMarker(thread, handler->GetProtoCell());
272 EXPECT_TRUE(resultMarker->IsProtoChangeMarker());
273 EXPECT_TRUE(handler->GetHolder().IsJSGlobalObject());
274 }
275 } // namespace panda::test
276