• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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