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