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