/* * Copyright (c) 2022 Huawei Device Co., Ltd. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "ecmascript/ic/ic_runtime.h" #include "ecmascript/ic/profile_type_info.h" #include "ecmascript/interpreter/slow_runtime_stub.h" #include "ecmascript/global_env.h" #include "ecmascript/object_operator.h" #include "ecmascript/tests/test_helper.h" using namespace panda; using namespace panda::ecmascript; namespace panda::test { class ICRunTimeTest : public testing::Test { public: static void SetUpTestCase() { GTEST_LOG_(INFO) << "SetUpTestCase"; } static void TearDownTestCase() { GTEST_LOG_(INFO) << "TearDownCase"; } void SetUp() override { TestHelper::CreateEcmaVMWithScope(instance, thread, scope); } void TearDown() override { TestHelper::DestroyEcmaVMWithScope(instance, scope); } EcmaVM *instance {nullptr}; EcmaHandleScope *scope {nullptr}; JSThread *thread {nullptr}; }; HWTEST_F_L0(ICRunTimeTest, UpdateLoadHandler) { ObjectFactory *factory = thread->GetEcmaVM()->GetFactory(); JSHandle env = thread->GetEcmaVM()->GetGlobalEnv(); auto globalConst = thread->GlobalConstants(); uint32_t arrayLength = 5; JSHandle objFun = env->GetArrayFunction(); JSHandle handleReceiver(factory->NewJSObjectByConstructor(JSHandle(objFun), objFun)); JSHandle handleKeyWithElement(factory->NewFromASCII("2")); JSHandle handleKeyWithString(factory->NewFromASCII("key")); JSHandle handleStoreArray(factory->NewTaggedArray(2)); JSHandle undefinedVal; JSHandle handleProfileTypeInfo = factory->NewProfileTypeInfo(arrayLength); for (uint32_t i = 0; i < arrayLength; i++) { undefinedVal = globalConst->GetHandledUndefinedString(); if (i == static_cast(ICKind::NamedLoadIC) || i == static_cast(ICKind::LoadIC)) { undefinedVal = handleStoreArray; } else if (i == static_cast(ICKind::NamedLoadIC) + 1 || i == static_cast(ICKind::LoadIC) + 1) { undefinedVal = JSHandle(thread, JSTaggedValue::Hole()); } handleProfileTypeInfo->Set(thread, i, undefinedVal.GetTaggedValue()); } // test op is Element ObjectOperator handleOp1(thread, handleKeyWithElement); uint32_t slotId = 2; ICRuntime icRuntime(thread, handleProfileTypeInfo, slotId, ICKind::LoadIC); icRuntime.UpdateLoadHandler(handleOp1, handleKeyWithElement, handleReceiver); EXPECT_TRUE(handleProfileTypeInfo->Get(slotId).IsTaggedArray()); EXPECT_TRUE(handleProfileTypeInfo->Get(slotId + 1).IsHole()); // test op is not Element ObjectOperator handleOp2(thread, handleKeyWithString); slotId = 0; ICRuntime icRuntime1(thread, handleProfileTypeInfo, slotId, ICKind::NamedLoadIC); icRuntime1.UpdateLoadHandler(handleOp2, handleKeyWithString, handleReceiver); EXPECT_TRUE(handleProfileTypeInfo->Get(slotId).IsTaggedArray()); EXPECT_TRUE(handleProfileTypeInfo->Get(slotId + 1).IsHole()); } HWTEST_F_L0(ICRunTimeTest, UpdateStoreHandler) { ObjectFactory *factory = thread->GetEcmaVM()->GetFactory(); JSHandle env = thread->GetEcmaVM()->GetGlobalEnv(); auto globalConst = thread->GlobalConstants(); uint32_t arrayLength = 5; JSHandle objFun = env->GetArrayFunction(); JSHandle handleReceiver(factory->NewJSObjectByConstructor(JSHandle(objFun), objFun)); JSHandle handleKeyWithElement(factory->NewFromASCII("2")); JSHandle handleKeyWithString(factory->NewFromASCII("key")); JSHandle handleStoreArray(factory->NewTaggedArray(2)); JSHandle undefinedVal; JSHandle handleProfileTypeInfo = factory->NewProfileTypeInfo(arrayLength); for (uint32_t i = 0; i < arrayLength; i++) { undefinedVal = globalConst->GetHandledUndefinedString(); if (i == static_cast(ICKind::NamedStoreIC) || i == static_cast(ICKind::StoreIC)) { undefinedVal = JSHandle(thread, JSTaggedValue::Undefined()); } else if (i == static_cast(ICKind::NamedStoreIC) + 1 || i == static_cast(ICKind::StoreIC) + 1) { undefinedVal = handleStoreArray; } handleProfileTypeInfo->Set(thread, i, undefinedVal.GetTaggedValue()); } // test op is Element uint32_t slotId = 3; ObjectOperator handleOp1(thread, handleKeyWithElement); handleOp1.SetIsOnPrototype(true); handleOp1.SetIndex(slotId); ICRuntime icRuntime(thread, handleProfileTypeInfo, slotId, ICKind::StoreIC); icRuntime.UpdateReceiverHClass(JSHandle(thread, JSHandle(handleReceiver)->GetJSHClass())); icRuntime.UpdateStoreHandler(handleOp1, handleKeyWithElement, handleReceiver); EXPECT_TRUE(handleProfileTypeInfo->Get(slotId).IsWeak()); EXPECT_TRUE(handleProfileTypeInfo->Get(slotId + 1).IsPrototypeHandler()); // test op is Transition slotId = 1; ObjectOperator handleOp2(thread, handleReceiver, handleKeyWithString, OperatorType::OWN); handleOp2.SetIsTransition(true); handleOp2.SetFastMode(true); handleOp2.SetIndex(slotId); ICRuntime icRuntime1(thread, handleProfileTypeInfo, slotId, ICKind::NamedStoreIC); icRuntime1.UpdateReceiverHClass(env->GetArgumentsClass()); icRuntime1.UpdateStoreHandler(handleOp2, handleKeyWithString, handleReceiver); EXPECT_TRUE(handleProfileTypeInfo->Get(slotId).IsWeak()); EXPECT_TRUE(handleProfileTypeInfo->Get(slotId + 1).IsTransitionHandler()); } HWTEST_F_L0(ICRunTimeTest, TraceIC) { ObjectFactory *factory = thread->GetEcmaVM()->GetFactory(); JSHandle env = thread->GetEcmaVM()->GetGlobalEnv(); uint32_t arrayLength = 5; JSHandle objFun = env->GetArrayFunction(); JSHandle handleReceiver(factory->NewJSObjectByConstructor(JSHandle(objFun), objFun)); JSHandle handleKeyWithString(factory->NewFromASCII("key")); JSHandle handleKeyWithElement(thread, JSTaggedValue(2)); JSHandle handleProfileTypeInfo = factory->NewProfileTypeInfo(arrayLength); ICRuntime icRuntime(thread, handleProfileTypeInfo, 4, ICKind::NamedGlobalLoadIC); // 4: means the NamedGlobalLoadIC icRuntime.TraceIC(handleReceiver, handleKeyWithString); icRuntime.TraceIC(handleReceiver, handleKeyWithElement); } HWTEST_F_L0(ICRunTimeTest, StoreMiss) { ObjectFactory *factory = thread->GetEcmaVM()->GetFactory(); JSHandle env = thread->GetEcmaVM()->GetGlobalEnv(); uint32_t arrayLength = 2; JSHandle objFun = env->GetTypedArrayFunction(); JSHandle handleReceiver(factory->NewJSObjectByConstructor(JSHandle(objFun), objFun)); JSHandle handleReceiver1(factory->NewJSArray()); JSHandle handleKeyWithString(factory->NewFromASCII("key")); JSHandle handleValueWithElement(thread, JSTaggedValue(2)); JSHandle handleProfileTypeInfo = factory->NewProfileTypeInfo(arrayLength); handleProfileTypeInfo->Set(thread, 0, JSTaggedValue::Hole()); handleProfileTypeInfo->Set(thread, 1, JSTaggedValue::Hole()); StoreICRuntime storeICRuntime(thread, handleProfileTypeInfo, 0, ICKind::NamedGlobalStoreIC); storeICRuntime.StoreMiss(handleReceiver, handleKeyWithString, handleValueWithElement); EXPECT_EQ(JSObject::GetProperty(thread, handleReceiver, handleKeyWithString).GetValue(), handleValueWithElement); EXPECT_TRUE(handleProfileTypeInfo->Get(0).IsHole()); EXPECT_TRUE(handleProfileTypeInfo->Get(1).IsHole()); SlowRuntimeStub::StGlobalRecord(thread, handleKeyWithString.GetTaggedValue(), handleKeyWithString.GetTaggedValue(), false); handleProfileTypeInfo->Set(thread, 0, JSTaggedValue::Undefined()); storeICRuntime.StoreMiss(handleReceiver1, handleKeyWithString, handleValueWithElement); EXPECT_TRUE(handleProfileTypeInfo->Get(0).IsPropertyBox()); } HWTEST_F_L0(ICRunTimeTest, LoadMiss) { ObjectFactory *factory = thread->GetEcmaVM()->GetFactory(); JSHandle env = thread->GetEcmaVM()->GetGlobalEnv(); uint32_t arrayLength = 2; JSHandle objFun = env->GetTypedArrayFunction(); JSHandle handleReceiver(factory->NewJSObjectByConstructor(JSHandle(objFun), objFun)); JSHandle handleReceiver1(factory->NewJSArray()); JSHandle handleKeyWithString(factory->NewFromASCII("key")); JSHandle handleValueWithElement(thread, JSTaggedValue(2)); JSObject::SetProperty(thread, handleReceiver, handleKeyWithString, handleValueWithElement); JSHandle handleProfileTypeInfo = factory->NewProfileTypeInfo(arrayLength); handleProfileTypeInfo->Set(thread, 0, JSTaggedValue::Hole()); handleProfileTypeInfo->Set(thread, 1, JSTaggedValue::Hole()); LoadICRuntime loadICRuntime(thread, handleProfileTypeInfo, 0, ICKind::NamedGlobalStoreIC); EXPECT_EQ(loadICRuntime.LoadMiss(handleReceiver, handleKeyWithString), handleValueWithElement.GetTaggedValue()); EXPECT_TRUE(handleProfileTypeInfo->Get(0).IsHole()); EXPECT_TRUE(handleProfileTypeInfo->Get(1).IsHole()); } } // namespace panda::test