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 25using namespace panda::ecmascript; 26 27namespace panda::test { 28using HandlerKind = ecmascript::HandlerBase::HandlerKind; 29class ICHandlerTest : public testing::Test { 30public: 31 static void SetUpTestCase() 32 { 33 GTEST_LOG_(INFO) << "SetUpTestCase"; 34 } 35 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 */ 62HWTEST_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 */ 78HWTEST_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 */ 115HWTEST_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 */ 145HWTEST_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 */ 186HWTEST_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 */ 213HWTEST_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 */ 253HWTEST_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