1 /**
2 * Copyright (c) 2021-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 #ifndef PANDA_RUNTIME_TESTS_INTERPRETER_TEST_RUNTIME_INTERFACE_H_
16 #define PANDA_RUNTIME_TESTS_INTERPRETER_TEST_RUNTIME_INTERFACE_H_
17
18 #include <gtest/gtest.h>
19
20 #include <cstdint>
21
22 #include "libpandafile/file.h"
23 #include "libpandafile/file_items.h"
24 #include "runtime/include/coretypes/array-inl.h"
25 #include "runtime/include/coretypes/string.h"
26 #include "runtime/include/method.h"
27 #include "runtime/include/runtime.h"
28 #include "runtime/include/panda_vm.h"
29 #include "runtime/include/runtime_notification.h"
30 #include "runtime/interpreter/frame.h"
31 #include "runtime/mem/gc/gc.h"
32
33 namespace panda::interpreter::test {
34
35 class DummyGC : public panda::mem::GC {
36 public:
37 explicit DummyGC(panda::mem::ObjectAllocatorBase *object_allocator, const panda::mem::GCSettings &settings);
~DummyGC()38 ~DummyGC() {}
39 // NOLINTNEXTLINE(misc-unused-parameters)
WaitForGC(GCTask task)40 void WaitForGC([[maybe_unused]] GCTask task) override {}
InitGCBits(panda::ObjectHeader * obj_header)41 void InitGCBits([[maybe_unused]] panda::ObjectHeader *obj_header) override {}
InitGCBitsForAllocationInTLAB(panda::ObjectHeader * obj_header)42 void InitGCBitsForAllocationInTLAB([[maybe_unused]] panda::ObjectHeader *obj_header) override {}
Trigger()43 void Trigger() override {}
44
45 private:
VerifyHeap()46 size_t VerifyHeap() override
47 {
48 return 0;
49 }
InitializeImpl()50 void InitializeImpl() override {}
51
PreRunPhasesImpl()52 void PreRunPhasesImpl() override {}
RunPhasesImpl(GCTask & task)53 void RunPhasesImpl([[maybe_unused]] GCTask &task) override {}
IsMarked(const ObjectHeader * object)54 bool IsMarked([[maybe_unused]] const ObjectHeader *object) const override
55 {
56 return false;
57 }
MarkObject(ObjectHeader * object)58 void MarkObject([[maybe_unused]] ObjectHeader *object) override {}
MarkObjectIfNotMarked(ObjectHeader * object)59 bool MarkObjectIfNotMarked([[maybe_unused]] ObjectHeader *object) override
60 {
61 return false;
62 }
MarkReferences(mem::GCMarkingStackType * references,panda::mem::GCPhase gc_phase)63 void MarkReferences([[maybe_unused]] mem::GCMarkingStackType *references,
64 [[maybe_unused]] panda::mem::GCPhase gc_phase) override
65 {
66 }
VisitRoots(const GCRootVisitor & gc_root_visitor,mem::VisitGCRootFlags flags)67 void VisitRoots([[maybe_unused]] const GCRootVisitor &gc_root_visitor,
68 [[maybe_unused]] mem::VisitGCRootFlags flags) override
69 {
70 }
VisitClassRoots(const GCRootVisitor & gc_root_visitor)71 void VisitClassRoots([[maybe_unused]] const GCRootVisitor &gc_root_visitor) override {}
VisitCardTableRoots(mem::CardTable * card_table,const GCRootVisitor & gc_root_visitor,const MemRangeChecker & range_checker,const ObjectChecker & range_object_checker,const ObjectChecker & from_object_checker,const uint32_t processed_flag)72 void VisitCardTableRoots([[maybe_unused]] mem::CardTable *card_table,
73 [[maybe_unused]] const GCRootVisitor &gc_root_visitor,
74 [[maybe_unused]] const MemRangeChecker &range_checker,
75 [[maybe_unused]] const ObjectChecker &range_object_checker,
76 [[maybe_unused]] const ObjectChecker &from_object_checker,
77 [[maybe_unused]] const uint32_t processed_flag) override
78 {
79 }
CommonUpdateRefsToMovedObjects()80 void CommonUpdateRefsToMovedObjects() override {}
UpdateRefsToMovedObjectsInPygoteSpace()81 void UpdateRefsToMovedObjectsInPygoteSpace() override {}
UpdateVmRefs()82 void UpdateVmRefs() override {}
UpdateGlobalObjectStorage()83 void UpdateGlobalObjectStorage() override {}
UpdateClassLinkerContextRoots()84 void UpdateClassLinkerContextRoots() override {}
UpdateThreadLocals()85 void UpdateThreadLocals() override {}
ClearLocalInternalAllocatorPools()86 void ClearLocalInternalAllocatorPools() override {}
87 };
88
89 template <class T>
ToPointer(size_t value)90 static T *ToPointer(size_t value)
91 {
92 return reinterpret_cast<T *>(AlignUp(value, alignof(T)));
93 }
94
95 class RuntimeInterface {
96 public:
97 static constexpr bool NEED_READ_BARRIER = false;
98 static constexpr bool NEED_WRITE_BARRIER = false;
99
100 using InvokeMethodHandler = std::function<Value(ManagedThread *, Method *, Value *)>;
101
102 struct NullPointerExceptionData {
103 bool expected {false};
104 };
105
106 struct ArithmeticException {
107 bool expected {false};
108 };
109
110 struct ArrayIndexOutOfBoundsExceptionData {
111 bool expected {false};
112 coretypes::array_ssize_t idx;
113 coretypes::array_size_t length;
114 };
115
116 struct NegativeArraySizeExceptionData {
117 bool expected {false};
118 coretypes::array_ssize_t size;
119 };
120
121 struct ClassCastExceptionData {
122 bool expected {false};
123 Class *dst_type;
124 Class *src_type;
125 };
126
127 struct AbstractMethodError {
128 bool expected {false};
129 Method *method;
130 };
131
132 struct ArrayStoreExceptionData {
133 bool expected {false};
134 Class *array_class;
135 Class *elem_class;
136 };
137
138 static constexpr BytecodeId METHOD_ID {0xaabb};
139 static constexpr BytecodeId FIELD_ID {0xeeff};
140 static constexpr BytecodeId TYPE_ID {0x5566};
141 static constexpr BytecodeId LITERALARRAY_ID {0x7788};
142
ResolveLiteralArray(PandaVM * vm,const Method & caller,BytecodeId id)143 static coretypes::Array *ResolveLiteralArray([[maybe_unused]] PandaVM *vm, [[maybe_unused]] const Method &caller,
144 BytecodeId id)
145 {
146 EXPECT_EQ(id, LITERALARRAY_ID);
147 return ToPointer<coretypes::Array>(0x7788);
148 }
149
ResolveMethod(ManagedThread * thread,const Method & caller,BytecodeId id)150 static Method *ResolveMethod([[maybe_unused]] ManagedThread *thread, [[maybe_unused]] const Method &caller,
151 BytecodeId id)
152 {
153 EXPECT_EQ(id, METHOD_ID);
154 return resolved_method;
155 }
156
ResolveField(ManagedThread * thread,const Method & caller,BytecodeId id)157 static Field *ResolveField([[maybe_unused]] ManagedThread *thread, [[maybe_unused]] const Method &caller,
158 BytecodeId id)
159 {
160 EXPECT_EQ(id, FIELD_ID);
161 return resolved_field;
162 }
163
164 template <bool need_init>
ResolveClass(ManagedThread * thread,const Method & caller,BytecodeId id)165 static Class *ResolveClass([[maybe_unused]] ManagedThread *thread, [[maybe_unused]] const Method &caller,
166 BytecodeId id)
167 {
168 EXPECT_EQ(id, TYPE_ID);
169 return resolved_class;
170 }
171
FindCatchBlock(const Method & method,ObjectHeader * exception,uint32_t pc)172 static uint32_t FindCatchBlock([[maybe_unused]] const Method &method, [[maybe_unused]] ObjectHeader *exception,
173 [[maybe_unused]] uint32_t pc)
174 {
175 return catch_block_pc_offset;
176 }
177
SetCatchBlockPcOffset(uint32_t pc_offset)178 static void SetCatchBlockPcOffset(uint32_t pc_offset)
179 {
180 catch_block_pc_offset = pc_offset;
181 }
182
GetCompilerHotnessThreshold()183 static uint32_t GetCompilerHotnessThreshold()
184 {
185 return jit_threshold;
186 }
187
IsCompilerEnableJit()188 static bool IsCompilerEnableJit()
189 {
190 return true;
191 }
192
SetCompilerHotnessThreshold(uint32_t threshold)193 static void SetCompilerHotnessThreshold(uint32_t threshold)
194 {
195 jit_threshold = threshold;
196 }
197
JITCompileMethod(Method * method)198 static void JITCompileMethod(Method *method)
199 {
200 method->SetCompiledEntryPoint(entry_point);
201 }
202
SetCurrentFrame(ManagedThread * thread,Frame * frame)203 static void SetCurrentFrame([[maybe_unused]] ManagedThread *thread, Frame *frame)
204 {
205 ASSERT_NE(frame, nullptr);
206 }
207
GetNotificationManager()208 static RuntimeNotificationManager *GetNotificationManager()
209 {
210 return nullptr;
211 }
212
SetupResolvedMethod(Method * method)213 static void SetupResolvedMethod(Method *method)
214 {
215 ManagedThread::GetCurrent()->GetInterpreterCache()->Clear();
216 resolved_method = method;
217 }
218
SetupResolvedField(Field * field)219 static void SetupResolvedField(Field *field)
220 {
221 ManagedThread::GetCurrent()->GetInterpreterCache()->Clear();
222 resolved_field = field;
223 }
224
SetupResolvedClass(Class * klass)225 static void SetupResolvedClass(Class *klass)
226 {
227 ManagedThread::GetCurrent()->GetInterpreterCache()->Clear();
228 resolved_class = klass;
229 }
230
SetupCatchBlockPcOffset(uint32_t pc_offset)231 static void SetupCatchBlockPcOffset(uint32_t pc_offset)
232 {
233 catch_block_pc_offset = pc_offset;
234 }
235
SetupNativeEntryPoint(const void * p)236 static void SetupNativeEntryPoint(const void *p)
237 {
238 entry_point = p;
239 }
240
CreateArray(Class * klass,coretypes::array_size_t length)241 static coretypes::Array *CreateArray(Class *klass, coretypes::array_size_t length)
242 {
243 EXPECT_EQ(klass, array_class);
244 EXPECT_EQ(length, array_length);
245 return array_object;
246 }
247
SetupArrayClass(Class * klass)248 static void SetupArrayClass(Class *klass)
249 {
250 array_class = klass;
251 }
252
SetupArrayLength(coretypes::array_size_t length)253 static void SetupArrayLength(coretypes::array_size_t length)
254 {
255 array_length = length;
256 }
257
SetupArrayObject(coretypes::Array * obj)258 static void SetupArrayObject(coretypes::Array *obj)
259 {
260 array_object = obj;
261 }
262
CreateObject(Class * klass)263 static ObjectHeader *CreateObject(Class *klass)
264 {
265 EXPECT_EQ(klass, object_class);
266 return object;
267 }
268
SetupObjectClass(Class * klass)269 static void SetupObjectClass(Class *klass)
270 {
271 object_class = klass;
272 }
273
SetupObject(ObjectHeader * obj)274 static void SetupObject(ObjectHeader *obj)
275 {
276 object = obj;
277 }
278
InvokeMethod(ManagedThread * thread,Method * method,Value * args)279 static Value InvokeMethod(ManagedThread *thread, Method *method, Value *args)
280 {
281 return invoke_handler(thread, method, args);
282 }
283
SetupInvokeMethodHandler(InvokeMethodHandler handler)284 static void SetupInvokeMethodHandler(InvokeMethodHandler handler)
285 {
286 invoke_handler = handler;
287 }
288
289 // Throw exceptions
290
ThrowNullPointerException()291 static void ThrowNullPointerException()
292 {
293 ASSERT_TRUE(npe_data.expected);
294 }
295
ThrowArrayIndexOutOfBoundsException(coretypes::array_ssize_t idx,coretypes::array_size_t length)296 static void ThrowArrayIndexOutOfBoundsException(coretypes::array_ssize_t idx, coretypes::array_size_t length)
297 {
298 ASSERT_TRUE(array_oob_exception_data.expected);
299 ASSERT_EQ(array_oob_exception_data.idx, idx);
300 ASSERT_EQ(array_oob_exception_data.length, length);
301 }
302
ThrowNegativeArraySizeException(coretypes::array_ssize_t size)303 static void ThrowNegativeArraySizeException(coretypes::array_ssize_t size)
304 {
305 ASSERT_TRUE(array_neg_size_exception_data.expected);
306 ASSERT_EQ(array_neg_size_exception_data.size, size);
307 }
308
ThrowArithmeticException()309 static void ThrowArithmeticException()
310 {
311 ASSERT_TRUE(arithmetic_exception_data.expected);
312 }
313
ThrowClassCastException(Class * dst_type,Class * src_type)314 static void ThrowClassCastException(Class *dst_type, Class *src_type)
315 {
316 ASSERT_TRUE(class_cast_exception_data.expected);
317 ASSERT_EQ(class_cast_exception_data.dst_type, dst_type);
318 ASSERT_EQ(class_cast_exception_data.src_type, src_type);
319 }
320
ThrowAbstractMethodError(Method * method)321 static void ThrowAbstractMethodError(Method *method)
322 {
323 ASSERT_TRUE(abstract_method_error_data.expected);
324 ASSERT_EQ(abstract_method_error_data.method, method);
325 }
326
ThrowIncompatibleClassChangeErrorForMethodConflict(Method * method)327 static void ThrowIncompatibleClassChangeErrorForMethodConflict([[maybe_unused]] Method *method) {}
328
ThrowOutOfMemoryError(const PandaString & msg)329 static void ThrowOutOfMemoryError([[maybe_unused]] const PandaString &msg) {}
330
ThrowVerificationException(const PandaString & msg)331 static void ThrowVerificationException([[maybe_unused]] const PandaString &msg)
332 {
333 // ASSERT_TRUE verification_of_method_exception_data.expected
334 // ASSERT_EQ verification_of_method_exception_data.msg, msg
335 }
336
ThrowArrayStoreException(Class * array_klass,Class * elem_class)337 static void ThrowArrayStoreException(Class *array_klass, Class *elem_class)
338 {
339 ASSERT_TRUE(array_store_exception_data.expected);
340 ASSERT_EQ(array_store_exception_data.array_class, array_klass);
341 ASSERT_EQ(array_store_exception_data.elem_class, elem_class);
342 }
343
SetArrayStoreException(ArrayStoreExceptionData data)344 static void SetArrayStoreException(ArrayStoreExceptionData data)
345 {
346 array_store_exception_data = data;
347 }
348
SetNullPointerExceptionData(NullPointerExceptionData data)349 static void SetNullPointerExceptionData(NullPointerExceptionData data)
350 {
351 npe_data = data;
352 }
353
SetArrayIndexOutOfBoundsExceptionData(ArrayIndexOutOfBoundsExceptionData data)354 static void SetArrayIndexOutOfBoundsExceptionData(ArrayIndexOutOfBoundsExceptionData data)
355 {
356 array_oob_exception_data = data;
357 }
358
SetNegativeArraySizeExceptionData(NegativeArraySizeExceptionData data)359 static void SetNegativeArraySizeExceptionData(NegativeArraySizeExceptionData data)
360 {
361 array_neg_size_exception_data = data;
362 }
363
SetArithmeticExceptionData(ArithmeticException data)364 static void SetArithmeticExceptionData(ArithmeticException data)
365 {
366 arithmetic_exception_data = data;
367 }
368
SetClassCastExceptionData(ClassCastExceptionData data)369 static void SetClassCastExceptionData(ClassCastExceptionData data)
370 {
371 class_cast_exception_data = data;
372 }
373
SetAbstractMethodErrorData(AbstractMethodError data)374 static void SetAbstractMethodErrorData(AbstractMethodError data)
375 {
376 abstract_method_error_data = data;
377 }
378
379 template <bool is_dynamic = false>
CreateFrame(size_t nregs,Method * method,Frame * prev)380 static Frame *CreateFrame(size_t nregs, Method *method, Frame *prev)
381 {
382 uint32_t ext_sz = EmptyExtFrameDataSize;
383 auto allocator = Thread::GetCurrent()->GetVM()->GetHeapManager()->GetInternalAllocator();
384 void *mem =
385 allocator->Allocate(panda::Frame::GetAllocSize(panda::Frame::GetActualSize<is_dynamic>(nregs), ext_sz),
386 GetLogAlignment(8), ManagedThread::GetCurrent());
387 return new (Frame::FromExt(mem, ext_sz)) panda::Frame(mem, method, prev, nregs);
388 }
389
CreateFrameWithActualArgsAndSize(uint32_t size,uint32_t nregs,uint32_t num_actual_args,Method * method,Frame * prev)390 static Frame *CreateFrameWithActualArgsAndSize(uint32_t size, uint32_t nregs, uint32_t num_actual_args,
391 Method *method, Frame *prev)
392 {
393 uint32_t ext_sz = EmptyExtFrameDataSize;
394 auto allocator = Thread::GetCurrent()->GetVM()->GetHeapManager()->GetInternalAllocator();
395 void *mem = allocator->Allocate(panda::Frame::GetAllocSize(size, ext_sz), GetLogAlignment(8),
396 ManagedThread::GetCurrent());
397 if (UNLIKELY(mem == nullptr)) {
398 return nullptr;
399 }
400 return new (Frame::FromExt(mem, ext_sz)) panda::Frame(mem, method, prev, nregs, num_actual_args);
401 }
402
FreeFrame(ManagedThread * thread,Frame * frame)403 static void FreeFrame(ManagedThread *thread, Frame *frame)
404 {
405 auto allocator = thread->GetVM()->GetHeapManager()->GetInternalAllocator();
406 allocator->Free(frame->GetExt());
407 }
408
GetGC()409 static mem::GC *GetGC()
410 {
411 return &panda::interpreter::test::RuntimeInterface::dummy_gc;
412 }
413
GetMethodName(Method * caller,BytecodeId method_id)414 static const uint8_t *GetMethodName([[maybe_unused]] Method *caller, [[maybe_unused]] BytecodeId method_id)
415 {
416 return nullptr;
417 }
418
GetMethodClass(Method * caller,BytecodeId method_id)419 static Class *GetMethodClass([[maybe_unused]] Method *caller, [[maybe_unused]] BytecodeId method_id)
420 {
421 return resolved_class;
422 }
423
GetMethodArgumentsCount(Method * caller,BytecodeId method_id)424 static uint32_t GetMethodArgumentsCount([[maybe_unused]] Method *caller, [[maybe_unused]] BytecodeId method_id)
425 {
426 return 0;
427 }
428
CollectRoots(Frame * frame)429 static void CollectRoots([[maybe_unused]] Frame *frame) {}
430
Safepoint()431 static void Safepoint() {}
432
GetLanguageContext(const Method & method)433 static LanguageContext GetLanguageContext(const Method &method)
434 {
435 return Runtime::GetCurrent()->GetLanguageContext(*method.GetClass());
436 }
437
438 private:
439 static ArrayIndexOutOfBoundsExceptionData array_oob_exception_data;
440
441 static NegativeArraySizeExceptionData array_neg_size_exception_data;
442
443 static NullPointerExceptionData npe_data;
444
445 static ArithmeticException arithmetic_exception_data;
446
447 static ClassCastExceptionData class_cast_exception_data;
448
449 static AbstractMethodError abstract_method_error_data;
450
451 static ArrayStoreExceptionData array_store_exception_data;
452
453 static coretypes::Array *array_object;
454
455 static Class *array_class;
456
457 static coretypes::array_size_t array_length;
458
459 static ObjectHeader *object;
460
461 static Class *object_class;
462
463 static Class *resolved_class;
464
465 static uint32_t catch_block_pc_offset;
466
467 static Method *resolved_method;
468
469 static Field *resolved_field;
470
471 static InvokeMethodHandler invoke_handler;
472
473 static const void *entry_point;
474
475 static uint32_t jit_threshold;
476
477 static panda::interpreter::test::DummyGC dummy_gc;
478 };
479
480 } // namespace panda::interpreter::test
481
482 #endif // PANDA_RUNTIME_TESTS_INTERPRETER_TEST_RUNTIME_INTERFACE_H_
483