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