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