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