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 #ifndef ECMASCRIPT_TESTS_TEST_HELPER_H 17 #define ECMASCRIPT_TESTS_TEST_HELPER_H 18 19 #include "ecmascript/interpreter/interpreter.h" 20 #include "ecmascript/ecma_runtime_call_info.h" 21 #include "ecmascript/ecma_string-inl.h" 22 #include "ecmascript/ecma_vm.h" 23 #include "ecmascript/js_function.h" 24 #include "ecmascript/js_handle.h" 25 #include "ecmascript/js_thread.h" 26 #include "ecmascript/mem/mem_common.h" 27 #include "ecmascript/napi/include/jsnapi.h" 28 #include "ecmascript/object_factory-inl.h" 29 #include "ecmascript/checkpoint/thread_state_transition.h" 30 #include "gtest/gtest.h" 31 32 namespace panda::test { 33 using panda::ecmascript::EcmaHandleScope; 34 using panda::ecmascript::EcmaRuntimeCallInfo; 35 using panda::ecmascript::EcmaVM; 36 using panda::ecmascript::InterpretedFrame; 37 using panda::ecmascript::InterpretedBuiltinFrame; 38 using panda::ecmascript::InterpretedEntryFrame; 39 using panda::ecmascript::JSTaggedType; 40 using panda::ecmascript::JSTaggedValue; 41 using panda::ecmascript::JSThread; 42 using panda::ecmascript::NUM_MANDATORY_JSFUNC_ARGS; 43 using panda::ecmascript::JSRuntimeOptions; 44 using panda::ecmascript::JSFunction; 45 using panda::ecmascript::JSHandle; 46 47 #define HWTEST_F_L0(testsuit, testcase) HWTEST_F(testsuit, testcase, testing::ext::TestSize.Level0) 48 #define HWTEST_P_L0(testsuit, testcase) HWTEST_P(testsuit, testcase, testing::ext::TestSize.Level0) 49 #define EXPECT_EXCEPTION() \ 50 EXPECT_TRUE(thread->HasPendingException()); \ 51 EXPECT_TRUE(thread->GetException().IsJSError()); \ 52 thread->ClearException() 53 54 class TestHelper { 55 public: CreateEcmaRuntimeCallInfo(JSThread * thread,JSTaggedValue newTgt,uint32_t argvLength)56 static EcmaRuntimeCallInfo* CreateEcmaRuntimeCallInfo(JSThread *thread, JSTaggedValue newTgt, uint32_t argvLength) 57 { 58 const uint8_t testDecodedSize = 2; 59 // argvLength includes number of int64_t to store value and tag of function, 'this' and call args 60 // It doesn't include new.target argument 61 int32_t numActualArgs = argvLength / testDecodedSize + 1; 62 JSTaggedType *sp = const_cast<JSTaggedType *>(thread->GetCurrentSPFrame()); 63 64 size_t frameSize = 0; 65 if (thread->IsAsmInterpreter()) { 66 frameSize = InterpretedEntryFrame::NumOfMembers() + numActualArgs; 67 } else { 68 frameSize = InterpretedFrame::NumOfMembers() + numActualArgs; 69 } 70 JSTaggedType *newSp = sp - frameSize; // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic) 71 for (int i = numActualArgs; i > 0; i--) { 72 newSp[i - 1] = JSTaggedValue::Undefined().GetRawData(); 73 } 74 EcmaRuntimeCallInfo *ecmaRuntimeCallInfo = reinterpret_cast<EcmaRuntimeCallInfo *>(newSp - 2); 75 *(--newSp) = numActualArgs; 76 *(--newSp) = panda::ecmascript::ToUintPtr(thread); 77 ecmaRuntimeCallInfo->SetNewTarget(newTgt); 78 return ecmaRuntimeCallInfo; 79 } 80 SetupFrame(JSThread * thread,EcmaRuntimeCallInfo * info)81 static JSTaggedType *SetupFrame(JSThread *thread, EcmaRuntimeCallInfo *info) 82 { 83 JSTaggedType *sp = const_cast<JSTaggedType *>(thread->GetCurrentSPFrame()); 84 size_t frameSize = 0; 85 if (thread->IsAsmInterpreter()) { 86 // 2 means thread and numArgs 87 frameSize = InterpretedEntryFrame::NumOfMembers() + info->GetArgsNumber() + NUM_MANDATORY_JSFUNC_ARGS + 2; 88 } else { 89 // 2 means thread and numArgs 90 frameSize = InterpretedFrame::NumOfMembers() + info->GetArgsNumber() + NUM_MANDATORY_JSFUNC_ARGS + 2; 91 } 92 JSTaggedType *newSp = sp - frameSize; // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic) 93 94 InterpretedEntryFrame *state = reinterpret_cast<InterpretedEntryFrame *>(newSp) - 1; 95 state->base.type = ecmascript::FrameType::INTERPRETER_ENTRY_FRAME; 96 state->base.prev = sp; 97 state->pc = nullptr; 98 thread->SetCurrentSPFrame(newSp); 99 return sp; 100 } 101 TearDownFrame(JSThread * thread,JSTaggedType * prev)102 static void TearDownFrame(JSThread *thread, JSTaggedType *prev) 103 { 104 thread->SetCurrentSPFrame(prev); 105 } 106 107 // If you want to call once create, you can refer to BuiltinsMathTest for detail. 108 static void CreateEcmaVMWithScope(EcmaVM *&instance, JSThread *&thread, EcmaHandleScope *&scope, 109 bool tryLoadStubFile = false, bool useCInterpreter = false, bool startManagedCode = true, 110 bool enableFastJit = false) 111 { 112 JSRuntimeOptions options; 113 options.SetEnableForceGC(true); 114 if (tryLoadStubFile) { 115 options.SetEnableAsmInterpreter(true); 116 } 117 if (useCInterpreter) { 118 options.SetEnableAsmInterpreter(false); 119 } 120 if (enableFastJit) { 121 options.SetEnableJIT(true); 122 } 123 instance = JSNApi::CreateEcmaVM(options); 124 instance->SetEnableForceGC(true); 125 ASSERT_TRUE(instance != nullptr) << "Cannot create EcmaVM"; 126 thread = instance->GetJSThread(); 127 if (startManagedCode) { 128 thread->ManagedCodeBegin(); 129 } 130 scope = new EcmaHandleScope(thread); 131 } 132 133 static inline void DestroyEcmaVMWithScope(EcmaVM *instance, EcmaHandleScope *scope, bool exitManagedCode = true) 134 { 135 delete scope; 136 scope = nullptr; 137 if (exitManagedCode) { 138 instance->GetJSThread()->ManagedCodeEnd(); 139 } 140 instance->SetEnableForceGC(false); 141 JSNApi::DestroyJSVM(instance); 142 } 143 144 static EcmaRuntimeCallInfo* CreateEcmaRuntimeCallInfo(JSThread *thread, std::vector<JSTaggedValue>& args, 145 int32_t maxArgLen, JSTaggedValue thisValue = JSTaggedValue::Undefined()) 146 { 147 auto ecmaRuntimeCallInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), maxArgLen); 148 ecmaRuntimeCallInfo->SetFunction(JSTaggedValue::Undefined()); 149 ecmaRuntimeCallInfo->SetThis(thisValue); 150 for (size_t i = 0; i < args.size(); i++) { 151 ecmaRuntimeCallInfo->SetCallArg(i, args[i]); 152 } 153 return ecmaRuntimeCallInfo; 154 } 155 156 static EcmaRuntimeCallInfo* CreateEcmaRuntimeCallInfo(JSThread *thread, JSHandle<JSFunction>& newTarget, 157 std::vector<JSTaggedValue>& args, int32_t maxArgLen, JSTaggedValue thisValue = JSTaggedValue::Undefined()) 158 { 159 auto ecmaRuntimeCallInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue(*newTarget), maxArgLen); 160 ecmaRuntimeCallInfo->SetFunction(newTarget.GetTaggedValue()); 161 ecmaRuntimeCallInfo->SetThis(thisValue); 162 for (size_t i = 0; i < args.size(); i++) { 163 ecmaRuntimeCallInfo->SetCallArg(i, args[i]); 164 } 165 return ecmaRuntimeCallInfo; 166 } 167 }; 168 169 class BaseTestWithOutScope : public testing::Test { 170 public: SetUpTestCase()171 static void SetUpTestCase() 172 { 173 GTEST_LOG_(INFO) << "SetUpTestCase"; 174 } 175 TearDownTestCase()176 static void TearDownTestCase() 177 { 178 GTEST_LOG_(INFO) << "TearDownCase"; 179 } 180 SetUp()181 void SetUp() override {} 182 TearDown()183 void TearDown() override {} 184 }; 185 186 template<bool icuPath = false> 187 class BaseTestWithScope : public BaseTestWithOutScope { 188 public: SetUp()189 void SetUp() override 190 { 191 if (!icuPath) { 192 TestHelper::CreateEcmaVMWithScope(instance, thread, scope); 193 } else { 194 JSRuntimeOptions options; 195 #if defined(PANDA_TARGET_LINUX) && defined(ICU_PATH) 196 // for consistency requirement, use ohos_icu4j/data as icu-data-path 197 options.SetIcuDataPath(ICU_PATH); 198 #endif 199 options.SetEnableForceGC(true); 200 instance = JSNApi::CreateEcmaVM(options); 201 instance->SetEnableForceGC(true); 202 ASSERT_TRUE(instance != nullptr) << "Cannot create EcmaVM"; 203 thread = instance->GetJSThread(); 204 thread->ManagedCodeBegin(); 205 scope = new EcmaHandleScope(thread); 206 } 207 } 208 TearDown()209 void TearDown() override 210 { 211 TestHelper::DestroyEcmaVMWithScope(instance, scope); 212 } 213 214 EcmaVM *instance {nullptr}; 215 EcmaHandleScope *scope {nullptr}; 216 JSThread *thread {nullptr}; 217 }; 218 } // namespace panda::test 219 #endif // ECMASCRIPT_TESTS_TEST_HELPER_H 220