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