• 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 
16 #include "runtime/entrypoints/entrypoints.h"
17 
18 #include "libpandabase/events/events.h"
19 #include "libpandabase/macros.h"
20 #include "libpandabase/utils/utils.h"
21 #include "compiler/compiler_options.h"
22 #include "runtime/deoptimization.h"
23 #include "runtime/arch/memory_helpers.h"
24 #include "runtime/jit/profiling_data.h"
25 #include "runtime/include/class_linker-inl.h"
26 #include "runtime/include/coretypes/array.h"
27 #include "runtime/include/exceptions.h"
28 #include "runtime/include/method-inl.h"
29 #include "runtime/include/object_header-inl.h"
30 #include "runtime/include/runtime.h"
31 #include "runtime/include/value-inl.h"
32 #include "runtime/include/panda_vm.h"
33 #include "runtime/interpreter/frame.h"
34 #include "runtime/interpreter/interpreter.h"
35 #include "runtime/interpreter/runtime_interface.h"
36 #include "runtime/mem/tlab.h"
37 #include "compiler/optimizer/ir/runtime_interface.h"
38 #include "runtime/handle_base-inl.h"
39 #include "libpandabase/utils/asan_interface.h"
40 #include "libpandabase/utils/tsan_interface.h"
41 #include "utils/cframe_layout.h"
42 #include "intrinsics.h"
43 #include "runtime/interpreter/vregister_iterator.h"
44 
45 namespace panda {
46 
47 using panda::compiler::TraceId;
48 
49 #undef LOG_ENTRYPOINTS
50 
51 class ScopedLog {
52 public:
53     ScopedLog() = delete;
ScopedLog(const char * function)54     explicit ScopedLog(const char *function) : function_(function)
55     {
56         LOG(DEBUG, INTEROP) << "ENTRYPOINT: " << function;
57     }
~ScopedLog()58     ~ScopedLog()
59     {
60         LOG(DEBUG, INTEROP) << "EXIT ENTRYPOINT: " << function_;
61     }
62     NO_COPY_SEMANTIC(ScopedLog);
63     NO_MOVE_SEMANTIC(ScopedLog);
64 
65 private:
66     std::string function_;
67 };
68 
69 #ifdef LOG_ENTRYPOINTS
70 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
71 #define LOG_ENTRYPOINT() ScopedLog __log(__FUNCTION__)
72 #else
73 #define LOG_ENTRYPOINT()
74 #endif
75 
76 // enable stack walker dry run on each entrypoint to discover stack issues early
77 #ifndef NDEBUG
78 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
79 #define CHECK_STACK_WALKER                                         \
80     if (Runtime::GetOptions().IsVerifyEntrypoints()) {             \
81         StackWalker::Create(ManagedThread::GetCurrent()).Verify(); \
82     }
83 #else
84 #define CHECK_STACK_WALKER
85 #endif
86 
87 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
88 #define BEGIN_ENTRYPOINT() \
89     CHECK_STACK_WALKER;    \
90     LOG_ENTRYPOINT()
91 
InterpreterEntryPoint(Method * method,Frame * frame)92 extern "C" NO_ADDRESS_SANITIZE void InterpreterEntryPoint(Method *method, Frame *frame)
93 {
94     auto pc = method->GetInstructions();
95     Method *callee = frame->GetMethod();
96     ASSERT(callee != nullptr);
97 
98     if (callee->IsAbstract()) {
99         ASSERT(pc == nullptr);
100         panda::ThrowAbstractMethodError(callee);
101         HandlePendingException();
102         UNREACHABLE();
103     }
104 
105     ManagedThread *thread = ManagedThread::GetCurrent();
106     if (!thread->template StackOverflowCheck<true, false>()) {
107         HandlePendingException(UnwindPolicy::SKIP_INLINED);
108         UNREACHABLE();
109     }
110 
111     Frame *prevFrame = thread->GetCurrentFrame();
112     thread->SetCurrentFrame(frame);
113 
114     auto isCompiledCode = thread->IsCurrentFrameCompiled();
115     thread->SetCurrentFrameIsCompiled(false);
116     interpreter::Execute(thread, pc, frame);
117     thread->SetCurrentFrameIsCompiled(isCompiledCode);
118     if (prevFrame != nullptr && reinterpret_cast<uintptr_t>(prevFrame->GetMethod()) == COMPILED_CODE_TO_INTERPRETER) {
119         thread->SetCurrentFrame(prevFrame->GetPrevFrame());
120     } else {
121         thread->SetCurrentFrame(prevFrame);
122     }
123 }
124 
AnnotateSanitizersEntrypoint(void const * addr,size_t size)125 extern "C" void AnnotateSanitizersEntrypoint([[maybe_unused]] void const *addr, [[maybe_unused]] size_t size)
126 {
127 #ifdef PANDA_TSAN_ON
128     TSAN_ANNOTATE_HAPPENS_BEFORE(const_cast<void *>(addr));
129 #endif
130 #ifdef PANDA_ASAN_ON
131     __asan_unpoison_memory_region(addr, size);
132 #endif
133 }
134 
WriteTlabStatsEntrypoint(void const * mem,size_t size)135 extern "C" void WriteTlabStatsEntrypoint([[maybe_unused]] void const *mem, size_t size)
136 {
137     LOG_ENTRYPOINT();
138 
139     LOG(DEBUG, MM_OBJECT_EVENTS) << "Alloc object in compiled code at " << mem << " size: " << size;
140     ASSERT(size <= Thread::GetCurrent()->GetVM()->GetHeapManager()->GetTLABMaxAllocSize());
141     // 1. Pointer to TLAB
142     // 2. Pointer to allocated memory
143     // 3. size
144     [[maybe_unused]] auto tlab = reinterpret_cast<size_t>(ManagedThread::GetCurrent()->GetTLAB());
145     EVENT_TLAB_ALLOC(ManagedThread::GetCurrent()->GetId(), tlab, reinterpret_cast<size_t>(mem), size);
146     if (mem::PANDA_TRACK_TLAB_ALLOCATIONS) {
147         auto memStats = Thread::GetCurrent()->GetVM()->GetHeapManager()->GetMemStats();
148         if (memStats == nullptr) {
149             return;
150         }
151         memStats->RecordAllocateObject(size, SpaceType::SPACE_TYPE_OBJECT);
152     }
153 }
154 
CreateArraySlowPathEntrypoint(Class * klass,size_t length)155 extern "C" coretypes::Array *CreateArraySlowPathEntrypoint(Class *klass, size_t length)
156 {
157     BEGIN_ENTRYPOINT();
158 
159     TSAN_ANNOTATE_HAPPENS_AFTER(klass);
160     auto arr = coretypes::Array::Create(klass, length);
161     if (UNLIKELY(arr == nullptr)) {
162         HandlePendingException();
163         UNREACHABLE();
164     }
165     if (compiler::g_options.IsCompilerEnableTlabEvents()) {
166         EVENT_SLOWPATH_ALLOC(ManagedThread::GetCurrent()->GetId());
167     }
168     return arr;
169 }
170 
CreateMultiArrayRecEntrypoint(ManagedThread * thread,Class * klass,uint32_t nargs,size_t * sizes,uint32_t num)171 extern "C" coretypes::Array *CreateMultiArrayRecEntrypoint(ManagedThread *thread, Class *klass, uint32_t nargs,
172                                                            size_t *sizes, uint32_t num)
173 {
174     // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic,-warnings-as-errors)
175     auto arrSize = sizes[num];
176 
177     [[maybe_unused]] HandleScope<ObjectHeader *> scope(thread);
178     // SUPPRESS_CSA_NEXTLINE(alpha.core.CheckObjHeaderTypeRef)
179     VMHandle<coretypes::Array> handle(thread, coretypes::Array::Create(klass, arrSize));
180     if (handle.GetPtr() == nullptr) {
181         return nullptr;
182     }
183     auto *component = klass->GetComponentType();
184 
185     if (component->IsArrayClass() && num + 1 < nargs) {
186         for (size_t idx = 0; idx < arrSize; idx++) {
187             auto *array = CreateMultiArrayRecEntrypoint(thread, component, nargs, sizes, num + 1);
188 
189             if (array == nullptr) {
190                 return nullptr;
191             }
192             handle.GetPtr()->template Set<coretypes::Array *>(idx, array);
193         }
194     }
195 
196     return handle.GetPtr();
197 }
198 
CreateEmptyStringEntrypoint()199 extern "C" coretypes::String *CreateEmptyStringEntrypoint()
200 {
201     BEGIN_ENTRYPOINT();
202 
203     auto vm = ManagedThread::GetCurrent()->GetVM();
204     auto str = coretypes::String::CreateEmptyString(vm->GetLanguageContext(), vm);
205     if (UNLIKELY(str == nullptr)) {
206         HandlePendingException();
207         UNREACHABLE();
208     }
209     return str;
210 }
211 
CreateStringFromStringEntrypoint(ObjectHeader * obj)212 extern "C" coretypes::String *CreateStringFromStringEntrypoint(ObjectHeader *obj)
213 {
214     BEGIN_ENTRYPOINT();
215     auto vm = ManagedThread::GetCurrent()->GetVM();
216     auto str = coretypes::String::CreateFromString(static_cast<coretypes::String *>(obj), vm->GetLanguageContext(), vm);
217     if (UNLIKELY(str == nullptr)) {
218         HandlePendingException();
219         UNREACHABLE();
220     }
221     return str;
222 }
223 
CreateStringFromCharsEntrypoint(ObjectHeader * obj)224 extern "C" coretypes::String *CreateStringFromCharsEntrypoint(ObjectHeader *obj)
225 {
226     BEGIN_ENTRYPOINT();
227     auto vm = ManagedThread::GetCurrent()->GetVM();
228     auto array = static_cast<coretypes::Array *>(obj);
229     auto str = coretypes::String::CreateNewStringFromChars(0, array->GetLength(), array, vm->GetLanguageContext(), vm);
230     if (UNLIKELY(str == nullptr)) {
231         HandlePendingException();
232         UNREACHABLE();
233     }
234     return str;
235 }
236 
CreateStringFromCharsWithOffsetEntrypoint(uint32_t offset,uint32_t length,ObjectHeader * obj,ObjectHeader * stringKlass)237 extern "C" coretypes::String *CreateStringFromCharsWithOffsetEntrypoint(uint32_t offset, uint32_t length,
238                                                                         ObjectHeader *obj,
239                                                                         [[maybe_unused]] ObjectHeader *stringKlass)
240 {
241     BEGIN_ENTRYPOINT();
242     auto vm = ManagedThread::GetCurrent()->GetVM();
243     auto array = static_cast<coretypes::Array *>(obj);
244     auto str = coretypes::String::CreateNewStringFromChars(offset, length, array, vm->GetLanguageContext(), vm);
245     if (UNLIKELY(str == nullptr)) {
246         HandlePendingException();
247         UNREACHABLE();
248     }
249     return str;
250 }
251 
CreateStringFromCharsZeroOffsetEntrypoint(uint32_t length,ObjectHeader * obj,ObjectHeader * stringKlass)252 extern "C" coretypes::String *CreateStringFromCharsZeroOffsetEntrypoint(uint32_t length, ObjectHeader *obj,
253                                                                         [[maybe_unused]] ObjectHeader *stringKlass)
254 {
255     BEGIN_ENTRYPOINT();
256     auto vm = ManagedThread::GetCurrent()->GetVM();
257     auto array = static_cast<coretypes::Array *>(obj);
258     auto str = coretypes::String::CreateNewStringFromChars(0, length, array, vm->GetLanguageContext(), vm);
259     if (UNLIKELY(str == nullptr)) {
260         HandlePendingException();
261         UNREACHABLE();
262     }
263     return str;
264 }
265 
SubStringFromStringEntrypoint(ObjectHeader * obj,int32_t begin,int32_t end)266 extern "C" coretypes::String *SubStringFromStringEntrypoint(ObjectHeader *obj, int32_t begin, int32_t end)
267 {
268     BEGIN_ENTRYPOINT();
269 
270     auto vm = ManagedThread::GetCurrent()->GetVM();
271     auto indexes = coretypes::String::NormalizeSubStringIndexes(begin, end, static_cast<coretypes::String *>(obj));
272     auto substrLength = indexes.second - indexes.first;
273     auto substr = coretypes::String::FastSubString(static_cast<coretypes::String *>(obj), indexes.first, substrLength,
274                                                    vm->GetLanguageContext(), vm);
275     if (UNLIKELY(substr == nullptr)) {
276         HandlePendingException();
277         UNREACHABLE();
278     }
279     return substr;
280 }
281 
StringGetCharsEntrypoint(ObjectHeader * obj,int32_t begin,int32_t end,ObjectHeader * arrayKlass)282 extern "C" coretypes::Array *StringGetCharsEntrypoint(ObjectHeader *obj, int32_t begin, int32_t end,
283                                                       [[maybe_unused]] ObjectHeader *arrayKlass)
284 {
285     BEGIN_ENTRYPOINT();
286 
287     auto length = static_cast<coretypes::String *>(obj)->GetLength();
288     if (UNLIKELY(static_cast<uint32_t>(end) > length)) {
289         ASSERT(!ManagedThread::GetCurrent()->HasPendingException());
290         panda::ThrowStringIndexOutOfBoundsException(end, length);
291         HandlePendingException(UnwindPolicy::SKIP_INLINED);
292         UNREACHABLE();
293     }
294     if (UNLIKELY(begin > end)) {
295         ASSERT(!ManagedThread::GetCurrent()->HasPendingException());
296         panda::ThrowStringIndexOutOfBoundsException(begin, length);
297         HandlePendingException(UnwindPolicy::SKIP_INLINED);
298         UNREACHABLE();
299     }
300 
301     if (UNLIKELY(begin < 0)) {
302         ASSERT(!ManagedThread::GetCurrent()->HasPendingException());
303         panda::ThrowStringIndexOutOfBoundsException(begin, length);
304         HandlePendingException(UnwindPolicy::SKIP_INLINED);
305         UNREACHABLE();
306     }
307     auto vm = ManagedThread::GetCurrent()->GetVM();
308     auto arrayLength = end - begin;
309     auto array = coretypes::String::GetChars(static_cast<coretypes::String *>(obj), begin, arrayLength,
310                                              vm->GetLanguageContext());
311     if (UNLIKELY(array == nullptr)) {
312         HandlePendingException();
313         UNREACHABLE();
314     }
315     return array;
316 }
317 
ResolveLiteralArrayEntrypoint(const Method * caller,uint32_t typeId)318 extern "C" coretypes::Array *ResolveLiteralArrayEntrypoint(const Method *caller, uint32_t typeId)
319 {
320     BEGIN_ENTRYPOINT();
321 
322     auto arr = Runtime::GetCurrent()->ResolveLiteralArray(ManagedThread::GetCurrent()->GetVM(), *caller, typeId);
323     if (UNLIKELY(arr == nullptr)) {
324         HandlePendingException();
325         UNREACHABLE();
326     }
327     return arr;
328 }
329 
CreateMultiArrayEntrypoint(Class * klass,uint32_t nargs,size_t * sizes)330 extern "C" coretypes::Array *CreateMultiArrayEntrypoint(Class *klass, uint32_t nargs, size_t *sizes)
331 {
332     BEGIN_ENTRYPOINT();
333 
334     auto arr = CreateMultiArrayRecEntrypoint(ManagedThread::GetCurrent(), klass, nargs, sizes, 0);
335     if (UNLIKELY(arr == nullptr)) {
336         HandlePendingException();
337         UNREACHABLE();
338     }
339     return arr;
340 }
341 
CreateObjectByClassEntrypoint(Class * klass)342 extern "C" ObjectHeader *CreateObjectByClassEntrypoint(Class *klass)
343 {
344     BEGIN_ENTRYPOINT();
345 
346     // We need annotation here for the FullMemoryBarrier used in InitializeClassByIdEntrypoint
347     TSAN_ANNOTATE_HAPPENS_AFTER(klass);
348     if (klass->IsStringClass()) {
349         LanguageContext ctx = Runtime::GetCurrent()->GetLanguageContext(*klass);
350         auto str = coretypes::String::CreateEmptyString(ctx, Runtime::GetCurrent()->GetPandaVM());
351         if (UNLIKELY(str == nullptr)) {
352             HandlePendingException();
353             UNREACHABLE();
354         }
355         return str;
356     }
357 
358     if (LIKELY(klass->IsInstantiable())) {
359         auto obj = ObjectHeader::Create(klass);
360         if (UNLIKELY(obj == nullptr)) {
361             HandlePendingException();
362             UNREACHABLE();
363         }
364         if (compiler::g_options.IsCompilerEnableTlabEvents()) {
365             EVENT_SLOWPATH_ALLOC(ManagedThread::GetCurrent()->GetId());
366         }
367         return obj;
368     }
369 
370     ThrowInstantiationErrorEntrypoint(klass);
371     UNREACHABLE();
372 }
373 
CloneObjectEntrypoint(ObjectHeader * obj)374 extern "C" ObjectHeader *CloneObjectEntrypoint(ObjectHeader *obj)
375 {
376     BEGIN_ENTRYPOINT();
377 
378     uint32_t flags = obj->ClassAddr<Class>()->GetFlags();
379     if (UNLIKELY((flags & Class::IS_CLONEABLE) == 0)) {
380         ASSERT(!ManagedThread::GetCurrent()->HasPendingException());
381         ThrowCloneNotSupportedException();
382         HandlePendingException(UnwindPolicy::SKIP_INLINED);
383         return nullptr;
384     }
385     return ObjectHeader::Clone(obj);
386 }
387 
PostBarrierWriteEntrypoint(ObjectHeader * obj,size_t size)388 extern "C" ObjectHeader *PostBarrierWriteEntrypoint(ObjectHeader *obj, size_t size)
389 {
390     LOG_ENTRYPOINT();
391     AnnotateSanitizersEntrypoint(obj, size);
392     auto *objectClass = obj->ClassAddr<Class>();
393     auto *barrierSet = ManagedThread::GetCurrent()->GetBarrierSet();
394     if (!objectClass->IsArrayClass() || !objectClass->GetComponentType()->IsPrimitive()) {
395         barrierSet->PostBarrier(obj, 0, size);
396     }
397     return obj;
398 }
399 
CheckCastEntrypoint(const ObjectHeader * obj,Class * klass)400 extern "C" void CheckCastEntrypoint(const ObjectHeader *obj, Class *klass)
401 {
402     BEGIN_ENTRYPOINT();
403 
404     // Don't use obj after ClassLinker call because GC can move it.
405     // Since we need only class and class in a non-movalble object
406     // it is ok to get it here.
407     Class *objKlass = obj == nullptr ? nullptr : obj->ClassAddr<Class>();
408     if (UNLIKELY(objKlass != nullptr && !klass->IsAssignableFrom(objKlass))) {
409         panda::ThrowClassCastException(klass, objKlass);
410         HandlePendingException();
411         UNREACHABLE();
412     }
413 }
414 
IsInstanceEntrypoint(ObjectHeader * obj,Class * klass)415 extern "C" uint8_t IsInstanceEntrypoint(ObjectHeader *obj, Class *klass)
416 {
417     BEGIN_ENTRYPOINT();
418 
419     // Don't use obj after ClassLinker call because GC can move it.
420     // Since we need only class and class in a non-movalble object
421     // it is ok to get it here.
422     Class *objKlass = obj == nullptr ? nullptr : obj->ClassAddr<Class>();
423     if (UNLIKELY(objKlass != nullptr && klass->IsAssignableFrom(objKlass))) {
424         return 1;
425     }
426     return 0;
427 }
428 
SafepointEntrypoint()429 extern "C" void SafepointEntrypoint()
430 {
431     BEGIN_ENTRYPOINT();
432     interpreter::RuntimeInterface::Safepoint();
433 }
434 
ResolveClassObjectEntrypoint(const Method * caller,FileEntityId typeId)435 extern "C" ObjectHeader *ResolveClassObjectEntrypoint(const Method *caller, FileEntityId typeId)
436 {
437     BEGIN_ENTRYPOINT();
438     auto klass = reinterpret_cast<Class *>(ResolveClassEntrypoint(caller, typeId));
439     return klass->GetManagedObject();
440 }
441 
ResolveClassEntrypoint(const Method * caller,FileEntityId typeId)442 extern "C" void *ResolveClassEntrypoint(const Method *caller, FileEntityId typeId)
443 {
444     BEGIN_ENTRYPOINT();
445     ClassLinker *classLinker = Runtime::GetCurrent()->GetClassLinker();
446     Class *klass = classLinker->GetClass(*caller, panda_file::File::EntityId(typeId));
447     if (UNLIKELY(klass == nullptr)) {
448         HandlePendingException();
449         UNREACHABLE();
450     }
451     return reinterpret_cast<void *>(klass);
452 }
453 
ResolveStringEntrypoint(const Method * caller,FileEntityId id)454 extern "C" coretypes::String *ResolveStringEntrypoint(const Method *caller, FileEntityId id)
455 {
456     BEGIN_ENTRYPOINT();
457     return Runtime::GetCurrent()->ResolveStringFromCompiledCode(ManagedThread::GetCurrent()->GetVM(), *caller,
458                                                                 panda_file::File::EntityId(id));
459 }
460 
ResolveStringAotEntrypoint(const Method * caller,FileEntityId id,ObjectHeader ** slot)461 extern "C" coretypes::String *ResolveStringAotEntrypoint(const Method *caller, FileEntityId id, ObjectHeader **slot)
462 {
463     BEGIN_ENTRYPOINT();
464     auto runtime = Runtime::GetCurrent();
465     auto aotManager = runtime->GetClassLinker()->GetAotManager();
466     auto vm = ManagedThread::GetCurrent()->GetVM();
467     auto str = runtime->ResolveStringFromCompiledCode(vm, *caller, panda::panda_file::File::EntityId(id));
468     if (UNLIKELY(str == nullptr)) {
469         return nullptr;
470     }
471 
472     // to many strings were saved to slots, so simply return the resolved string
473     if (aotManager->GetAotStringRootsCount() >= Runtime::GetOptions().GetAotStringGcRootsLimit()) {
474         return str;
475     }
476 
477     auto counter = reinterpret_cast<std::atomic_uint32_t *>(slot);
478 
479     // Atomic with acquire order reason: data race with slot with dependecies on reads after the load which should
480     // become visible
481     auto counterVal = counter->load(std::memory_order_acquire);
482     if (counterVal >= compiler::RuntimeInterface::RESOLVE_STRING_AOT_COUNTER_LIMIT - 1) {
483         return str;
484     }
485 
486     if (counterVal < Runtime::GetOptions().GetResolveStringAotThreshold()) {
487         // try to update counter, but ignore result - in the worst case we'll save
488         // string's pointer to slot a bit later
489         counter->compare_exchange_strong(counterVal, counterVal + 1, std::memory_order_release,
490                                          std::memory_order_relaxed);
491     } else {
492         // try to replace the counter with string pointer and register the slot as GC root in case of success
493         if (counter->compare_exchange_strong(counterVal, static_cast<uint32_t>(reinterpret_cast<uint64_t>(str)),
494                                              std::memory_order_release, std::memory_order_relaxed)) {
495             bool isYoung = vm->GetHeapManager()->IsObjectInYoungSpace(str);
496             aotManager->RegisterAotStringRoot(slot, isYoung);
497             EVENT_AOT_RESOLVE_STRING(ConvertToString(str));
498         }
499     }
500 
501     return str;
502 }
503 
CreateFrameWithSize(uint32_t size,uint32_t nregs,Method * method,Frame * prev)504 extern "C" Frame *CreateFrameWithSize(uint32_t size, uint32_t nregs, Method *method, Frame *prev)
505 {
506     uint32_t extSz = EMPTY_EXT_FRAME_DATA_SIZE;
507     if (LIKELY(method)) {
508         extSz = Runtime::GetCurrent()->GetLanguageContext(*method).GetFrameExtSize();
509     }
510     size_t allocSz = Frame::GetAllocSize(size, extSz);
511     Frame *frame = Thread::GetCurrent()->GetVM()->GetHeapManager()->AllocateExtFrame(allocSz, extSz);
512     if (UNLIKELY(frame == nullptr)) {
513         return nullptr;
514     }
515     return new (frame) Frame(Frame::ToExt(frame, extSz), method, prev, nregs);
516 }
517 
CreateFrameWithActualArgsAndSize(uint32_t size,uint32_t nregs,uint32_t numActualArgs,Method * method,Frame * prev)518 extern "C" Frame *CreateFrameWithActualArgsAndSize(uint32_t size, uint32_t nregs, uint32_t numActualArgs,
519                                                    Method *method, Frame *prev)
520 {
521     auto *thread = ManagedThread::GetCurrent();
522     uint32_t extSz = thread->GetVM()->GetFrameExtSize();
523     size_t allocSz = Frame::GetAllocSize(size, extSz);
524     void *mem = thread->GetStackFrameAllocator()->Alloc(allocSz);
525     if (UNLIKELY(mem == nullptr)) {
526         return nullptr;
527     }
528     return new (Frame::FromExt(mem, extSz)) Frame(mem, method, prev, nregs, numActualArgs);
529 }
530 
CreateNativeFrameWithActualArgsAndSize(uint32_t size,uint32_t nregs,uint32_t numActualArgs,Method * method,Frame * prev)531 extern "C" Frame *CreateNativeFrameWithActualArgsAndSize(uint32_t size, uint32_t nregs, uint32_t numActualArgs,
532                                                          Method *method, Frame *prev)
533 {
534     uint32_t extSz = EMPTY_EXT_FRAME_DATA_SIZE;
535     size_t allocSz = Frame::GetAllocSize(size, extSz);
536     void *mem = ManagedThread::GetCurrent()->GetStackFrameAllocator()->Alloc(allocSz);
537     if (UNLIKELY(mem == nullptr)) {
538         return nullptr;
539     }
540     return new (Frame::FromExt(mem, extSz)) Frame(mem, method, prev, nregs, numActualArgs);
541 }
542 
543 template <bool IS_DYNAMIC = false>
CreateFrame(uint32_t nregs,Method * method,Frame * prev)544 static Frame *CreateFrame(uint32_t nregs, Method *method, Frame *prev)
545 {
546     return CreateFrameWithSize(Frame::GetActualSize<IS_DYNAMIC>(nregs), nregs, method, prev);
547 }
548 
549 template <bool IS_DYNAMIC>
CreateFrameWithActualArgs(uint32_t nregs,uint32_t numActualArgs,Method * method,Frame * prev)550 static Frame *CreateFrameWithActualArgs(uint32_t nregs, uint32_t numActualArgs, Method *method, Frame *prev)
551 {
552     auto frame =
553         CreateFrameWithActualArgsAndSize(Frame::GetActualSize<IS_DYNAMIC>(nregs), nregs, numActualArgs, method, prev);
554     if (IS_DYNAMIC) {
555         LanguageContext ctx = Runtime::GetCurrent()->GetLanguageContext(*method);
556         coretypes::TaggedValue initialValue = ctx.GetInitialTaggedValue();
557         for (size_t i = 0; i < nregs; i++) {
558             frame->GetVReg(i).SetValue(initialValue.GetRawData());
559         }
560         frame->SetDynamic();
561     }
562     return frame;
563 }
564 
CreateFrameForMethod(Method * method,Frame * prev)565 extern "C" Frame *CreateFrameForMethod(Method *method, Frame *prev)
566 {
567     auto nregs = method->GetNumArgs() + method->GetNumVregs();
568     return CreateFrame<false>(nregs, method, prev);
569 }
570 
CreateFrameForMethodDyn(Method * method,Frame * prev)571 extern "C" Frame *CreateFrameForMethodDyn(Method *method, Frame *prev)
572 {
573     auto nregs = method->GetNumArgs() + method->GetNumVregs();
574     return CreateFrame<true>(nregs, method, prev);
575 }
576 
CreateFrameForMethodWithActualArgs(uint32_t numActualArgs,Method * method,Frame * prev)577 extern "C" Frame *CreateFrameForMethodWithActualArgs(uint32_t numActualArgs, Method *method, Frame *prev)
578 {
579     auto nargs = std::max(numActualArgs, method->GetNumArgs());
580     auto nregs = nargs + method->GetNumVregs();
581     return CreateFrameWithActualArgs<false>(nregs, numActualArgs, method, prev);
582 }
583 
CreateFrameForMethodWithActualArgsDyn(uint32_t numActualArgs,Method * method,Frame * prev)584 extern "C" Frame *CreateFrameForMethodWithActualArgsDyn(uint32_t numActualArgs, Method *method, Frame *prev)
585 {
586     auto nargs = std::max(numActualArgs, method->GetNumArgs());
587     auto nregs = nargs + method->GetNumVregs();
588     return CreateFrameWithActualArgs<true>(nregs, numActualArgs, method, prev);
589 }
590 
FreeFrame(Frame * frame)591 extern "C" void FreeFrame(Frame *frame)
592 {
593     ASSERT(frame->GetExt() != nullptr);
594     ManagedThread::GetCurrent()->GetStackFrameAllocator()->Free(frame->GetExt());
595 }
596 
GetStaticFieldAddressEntrypoint(Method * method,uint32_t fieldId)597 extern "C" uintptr_t GetStaticFieldAddressEntrypoint(Method *method, uint32_t fieldId)
598 {
599     BEGIN_ENTRYPOINT();
600     auto *classLinker = Runtime::GetCurrent()->GetClassLinker();
601     auto field = classLinker->GetField(*method, panda_file::File::EntityId(fieldId));
602     if (UNLIKELY(field == nullptr)) {
603         HandlePendingException();
604         UNREACHABLE();
605     }
606     auto *klass = field->GetClass();
607     ASSERT(klass != nullptr);
608     return reinterpret_cast<uintptr_t>(klass) + field->GetOffset();
609 }
610 
UnresolvedStoreStaticBarrieredEntrypoint(Method * method,uint32_t fieldId,ObjectHeader * obj)611 extern "C" void UnresolvedStoreStaticBarrieredEntrypoint(Method *method, uint32_t fieldId, ObjectHeader *obj)
612 {
613     BEGIN_ENTRYPOINT();
614     auto thread = ManagedThread::GetCurrent();
615     // One must not use plain ObjectHeader pointer here as GC can move obj.
616     // Wrap it in VMHandle.
617     [[maybe_unused]] HandleScope<ObjectHeader *> objHandleScope(thread);
618     VMHandle<ObjectHeader> objHandle(thread, obj);
619 
620     auto field = Runtime::GetCurrent()->GetClassLinker()->GetField(*method, panda_file::File::EntityId(fieldId));
621     if (UNLIKELY(field == nullptr)) {
622         HandlePendingException();
623         UNREACHABLE();
624     }
625     if (UNLIKELY(!field->GetType().IsReference())) {
626         HandlePendingException();
627         UNREACHABLE();
628     }
629 
630     auto *classPtr = field->GetClass();
631     ASSERT(classPtr != nullptr);
632     InitializeClassEntrypoint(classPtr);
633 
634     // field_addr = class_ptr + field's offset
635     auto fieldAddr = reinterpret_cast<uint32_t *>(reinterpret_cast<uintptr_t>(classPtr) + field->GetOffset());
636     auto *barrierSet = thread->GetBarrierSet();
637     // Pre-barrier
638     if (barrierSet->IsPreBarrierEnabled()) {
639         // Load
640         // Atomic with acquire order reason: assume load can be volatile
641         auto currentReference = __atomic_load_n(fieldAddr, std::memory_order_acquire);
642         barrierSet->PreBarrier(reinterpret_cast<void *>(currentReference));
643     }
644     // Store
645     // Atomic with release order reason: assume store can be volatile
646     auto ref = reinterpret_cast<uintptr_t>(objHandle.GetPtr());
647     ASSERT(sizeof(ref) == 4U || (ref & 0xFFFFFFFF00000000UL) == 0);
648     __atomic_store_n(fieldAddr, static_cast<uint32_t>(ref), std::memory_order_release);
649     // Post-barrier
650     if (!mem::IsEmptyBarrier(barrierSet->GetPostType())) {
651         auto objPtrPtr = reinterpret_cast<uintptr_t>(classPtr) + Class::GetManagedObjectOffset();
652         auto objPtr = *reinterpret_cast<uint32_t *>(objPtrPtr);
653         barrierSet->PostBarrier(reinterpret_cast<void *>(objPtr), 0, reinterpret_cast<void *>(ref));
654     }
655 }
656 
GetUnknownStaticFieldMemoryAddressEntrypoint(Method * method,uint32_t fieldId,size_t * slot)657 extern "C" uintptr_t GetUnknownStaticFieldMemoryAddressEntrypoint(Method *method, uint32_t fieldId, size_t *slot)
658 {
659     BEGIN_ENTRYPOINT();
660     auto *classLinker = Runtime::GetCurrent()->GetClassLinker();
661     auto field = classLinker->GetField(*method, panda_file::File::EntityId(fieldId));
662     if (UNLIKELY(field == nullptr)) {
663         HandlePendingException();
664         UNREACHABLE();
665     }
666     auto *klass = field->GetClass();
667     ASSERT(klass != nullptr);
668     InitializeClassEntrypoint(klass);
669 
670     uintptr_t addr = reinterpret_cast<uintptr_t>(klass) + field->GetOffset();
671     if (klass->IsInitialized() && slot != nullptr) {
672         *slot = addr;
673     }
674     return addr;
675 }
676 
GetFieldOffsetEntrypoint(Method * method,uint32_t fieldId)677 extern "C" size_t GetFieldOffsetEntrypoint(Method *method, uint32_t fieldId)
678 {
679     BEGIN_ENTRYPOINT();
680     auto *classLinker = Runtime::GetCurrent()->GetClassLinker();
681     auto field = classLinker->GetField(*method, panda_file::File::EntityId(fieldId));
682     if (UNLIKELY(field == nullptr)) {
683         HandlePendingException();
684         UNREACHABLE();
685     }
686     return field->GetOffset();
687 }
688 
InitializeClassEntrypoint(Class * klass)689 extern "C" void InitializeClassEntrypoint(Class *klass)
690 {
691     BEGIN_ENTRYPOINT();
692     auto *classLinker = Runtime::GetCurrent()->GetClassLinker();
693     if (!klass->IsInitialized() && !classLinker->InitializeClass(ManagedThread::GetCurrent(), klass)) {
694         HandlePendingException();
695         UNREACHABLE();
696     }
697 }
698 
InitializeClassByIdEntrypoint(const Method * caller,FileEntityId id)699 extern "C" Class *InitializeClassByIdEntrypoint(const Method *caller, FileEntityId id)
700 {
701     BEGIN_ENTRYPOINT();
702     ClassLinker *classLinker = Runtime::GetCurrent()->GetClassLinker();
703     Class *klass = classLinker->GetClass(*caller, panda_file::File::EntityId(id));
704     if (UNLIKELY(klass == nullptr)) {
705         HandlePendingException();
706         UNREACHABLE();
707     }
708     // Later we store klass pointer into .aot_got section.
709     // Without full memory barrier on the architectures with weak memory order
710     // we can read klass pointer, but fetch klass data before it's set in GetClass and InitializeClass
711     arch::FullMemoryBarrier();
712     // Full barrier is not visible by TSAN so we need annotation here
713     TSAN_ANNOTATE_HAPPENS_BEFORE(klass);
714     InitializeClassEntrypoint(klass);
715     return klass;
716 }
717 
ResolveVirtualCallEntrypoint(const Method * callee,ObjectHeader * obj)718 extern "C" uintptr_t NO_ADDRESS_SANITIZE ResolveVirtualCallEntrypoint(const Method *callee, ObjectHeader *obj)
719 {
720     BEGIN_ENTRYPOINT();
721     if (UNLIKELY(callee == nullptr)) {
722         HandlePendingException();
723         UNREACHABLE();
724     }
725     auto *resolved = obj->ClassAddr<Class>()->ResolveVirtualMethod(callee);
726     ASSERT(resolved != nullptr);
727 
728     return reinterpret_cast<uintptr_t>(resolved);
729 }
730 
ResolveVirtualCallAotEntrypoint(const Method * caller,ObjectHeader * obj,size_t calleeId,uintptr_t cacheAddr)731 extern "C" uintptr_t NO_ADDRESS_SANITIZE ResolveVirtualCallAotEntrypoint(const Method *caller, ObjectHeader *obj,
732                                                                          size_t calleeId,
733                                                                          [[maybe_unused]] uintptr_t cacheAddr)
734 {
735     BEGIN_ENTRYPOINT();
736     // Don't use obj after ClassLinker call because GC can move it.
737     // Since we need only class and class in a non-movalble object
738     // it is ok to get it here.
739     auto *objKlass = obj->ClassAddr<Class>();
740     Method *method = Runtime::GetCurrent()->GetClassLinker()->GetMethod(*caller, panda_file::File::EntityId(calleeId));
741     if (UNLIKELY(method == nullptr)) {
742         HandlePendingException();
743         UNREACHABLE();
744     }
745     auto *resolved = objKlass->ResolveVirtualMethod(method);
746     ASSERT(resolved != nullptr);
747 
748 #if defined(PANDA_TARGET_ARM64)
749     // In arm64, use interface inlineCache
750     // NOTE(liyiming): will support x86_64 in future
751     // issue #7018
752     auto methodHead = objKlass->GetRawFirstMethodAddr();
753     if (cacheAddr == 0 || methodHead == nullptr) {
754         return reinterpret_cast<uintptr_t>(resolved);
755     }
756 
757     constexpr uint32_t METHOD_COMPRESS = 3;
758     constexpr uint32_t CACHE_OFFSET_32 = 32;
759     constexpr uint32_t CACHE_OFFSET_34 = 34;
760     auto cache = reinterpret_cast<int64_t *>(cacheAddr);
761     auto methodResolved = reinterpret_cast<int64_t>(resolved);
762     int64_t methodCache = methodResolved - reinterpret_cast<int64_t>(methodHead);
763 
764     int64_t methodCacheJudge = methodCache >> CACHE_OFFSET_34;  // NOLINT(hicpp-signed-bitwise)
765     if (methodCacheJudge != 0 && methodCacheJudge != -1) {
766         return reinterpret_cast<uintptr_t>(resolved);
767     }
768     methodCache = methodCache >> METHOD_COMPRESS;                           // NOLINT(hicpp-signed-bitwise)
769     methodCache = methodCache << CACHE_OFFSET_32;                           // NOLINT(hicpp-signed-bitwise)
770     int64_t saveCache = methodCache | reinterpret_cast<int64_t>(objKlass);  // NOLINT(hicpp-signed-bitwise)
771     *cache = saveCache;
772 #endif
773     return reinterpret_cast<uintptr_t>(resolved);
774 }
775 
ResolveUnknownVirtualCallEntrypoint(const Method * caller,ObjectHeader * obj,size_t calleeId,size_t * slot)776 extern "C" uintptr_t NO_ADDRESS_SANITIZE ResolveUnknownVirtualCallEntrypoint(const Method *caller, ObjectHeader *obj,
777                                                                              size_t calleeId, size_t *slot)
778 {
779     {
780         auto thread = ManagedThread::GetCurrent();
781         [[maybe_unused]] HandleScope<ObjectHeader *> scope(thread);
782         VMHandle<ObjectHeader> handleObj(thread, obj);
783 
784         BEGIN_ENTRYPOINT();
785         auto runtime = Runtime::GetCurrent();
786         Method *method = runtime->GetClassLinker()->GetMethod(*caller, panda_file::File::EntityId(calleeId));
787         if (LIKELY(method != nullptr)) {
788             // Cache a method index in vtable
789             if (slot != nullptr && (!method->GetClass()->IsInterface() || method->IsDefaultInterfaceMethod())) {
790                 // We save 'vtable index + 1' because 0 value means uninitialized.
791                 // Codegen must subtract index after loading from the slot.
792                 *slot = method->GetVTableIndex() + 1;
793             }
794 
795             auto *resolved = handleObj.GetPtr()->ClassAddr<Class>()->ResolveVirtualMethod(method);
796             ASSERT(resolved != nullptr);
797 
798             return reinterpret_cast<uintptr_t>(resolved);
799         }
800     }
801 
802     HandlePendingException();
803     UNREACHABLE();
804 }
805 
CheckStoreArrayReferenceEntrypoint(coretypes::Array * array,ObjectHeader * storeObj)806 extern "C" void CheckStoreArrayReferenceEntrypoint(coretypes::Array *array, ObjectHeader *storeObj)
807 {
808     BEGIN_ENTRYPOINT();
809     ASSERT(array != nullptr);
810     ASSERT(storeObj != nullptr);
811 
812     // SUPPRESS_CSA_NEXTLINE(alpha.core.WasteObjHeader)
813     auto *arrayClass = array->ClassAddr<Class>();
814     auto *elementClass = arrayClass->GetComponentType();
815     // SUPPRESS_CSA_NEXTLINE(alpha.core.WasteObjHeader)
816     if (UNLIKELY(!storeObj->IsInstanceOf(elementClass))) {
817         // SUPPRESS_CSA_NEXTLINE(alpha.core.WasteObjHeader)
818         panda::ThrowArrayStoreException(arrayClass, storeObj->ClassAddr<Class>());
819         HandlePendingException();
820         UNREACHABLE();
821     }
822 }
823 
GetCalleeMethodEntrypoint(const Method * caller,size_t calleeId)824 extern "C" Method *GetCalleeMethodEntrypoint(const Method *caller, size_t calleeId)
825 {
826     BEGIN_ENTRYPOINT();
827     auto *method = Runtime::GetCurrent()->GetClassLinker()->GetMethod(*caller, panda_file::File::EntityId(calleeId));
828     if (UNLIKELY(method == nullptr)) {
829         HandlePendingException();
830         UNREACHABLE();
831     }
832 
833     return method;
834 }
835 
GetUnknownCalleeMethodEntrypoint(const Method * caller,size_t calleeId,size_t * slot)836 extern "C" Method *GetUnknownCalleeMethodEntrypoint(const Method *caller, size_t calleeId, size_t *slot)
837 {
838     BEGIN_ENTRYPOINT();
839     auto *method = Runtime::GetCurrent()->GetClassLinker()->GetMethod(*caller, panda_file::File::EntityId(calleeId));
840     if (UNLIKELY(method == nullptr)) {
841         HandlePendingException();
842         UNREACHABLE();
843     }
844     auto klass = method->GetClass();
845     ASSERT(klass != nullptr);
846     InitializeClassEntrypoint(klass);
847 
848     if (klass->IsInitialized() && slot != nullptr) {
849         *slot = reinterpret_cast<size_t>(method);
850     }
851 
852     return method;
853 }
854 
ThrowExceptionEntrypoint(ObjectHeader * exception)855 extern "C" NO_ADDRESS_SANITIZE void ThrowExceptionEntrypoint(ObjectHeader *exception)
856 {
857     BEGIN_ENTRYPOINT();
858     LOG(DEBUG, INTEROP) << "ThrowExceptionEntrypoint \n";
859     ASSERT(!ManagedThread::GetCurrent()->HasPendingException());
860     if (exception == nullptr) {
861         NullPointerExceptionEntrypoint();
862         UNREACHABLE();
863     }
864     ManagedThread::GetCurrent()->SetException(exception);
865 
866     SetExceptionEvent(events::ExceptionType::THROW, ManagedThread::GetCurrent());
867     HandlePendingException(UnwindPolicy::SKIP_INLINED);
868 }
869 
ThrowNativeExceptionEntrypoint()870 extern "C" NO_ADDRESS_SANITIZE void ThrowNativeExceptionEntrypoint()
871 {
872     BEGIN_ENTRYPOINT();
873     LOG(DEBUG, INTEROP) << "ThrowNativeExceptionEntrypoint \n";
874     SetExceptionEvent(events::ExceptionType::NATIVE, ManagedThread::GetCurrent());
875     HandlePendingException(UnwindPolicy::SKIP_INLINED);
876 }
877 
ArrayIndexOutOfBoundsExceptionEntrypoint(ssize_t idx,size_t length)878 extern "C" NO_ADDRESS_SANITIZE void ArrayIndexOutOfBoundsExceptionEntrypoint([[maybe_unused]] ssize_t idx,
879                                                                              [[maybe_unused]] size_t length)
880 {
881     BEGIN_ENTRYPOINT();
882     LOG(DEBUG, INTEROP) << "ArrayIndexOutOfBoundsExceptionEntrypoint \n";
883     ASSERT(!ManagedThread::GetCurrent()->HasPendingException());
884     ThrowArrayIndexOutOfBoundsException(idx, length);
885     HandlePendingException(UnwindPolicy::SKIP_INLINED);
886 }
887 
StringIndexOutOfBoundsExceptionEntrypoint(ssize_t idx,size_t length)888 extern "C" NO_ADDRESS_SANITIZE void StringIndexOutOfBoundsExceptionEntrypoint([[maybe_unused]] ssize_t idx,
889                                                                               [[maybe_unused]] size_t length)
890 {
891     BEGIN_ENTRYPOINT();
892     LOG(DEBUG, INTEROP) << "StringIndexOutOfBoundsExceptionEntrypoint \n";
893     ASSERT(!ManagedThread::GetCurrent()->HasPendingException());
894     ThrowStringIndexOutOfBoundsException(idx, length);
895     HandlePendingException(UnwindPolicy::SKIP_INLINED);
896 }
897 
NullPointerExceptionEntrypoint()898 extern "C" NO_ADDRESS_SANITIZE void NullPointerExceptionEntrypoint()
899 {
900     BEGIN_ENTRYPOINT();
901     LOG(DEBUG, INTEROP) << "NullPointerExceptionEntrypoint \n";
902     ASSERT(!ManagedThread::GetCurrent()->HasPendingException());
903     ThrowNullPointerException();
904     HandlePendingException(UnwindPolicy::SKIP_INLINED);
905 }
906 
AbstractMethodErrorEntrypoint(Method * method)907 extern "C" NO_ADDRESS_SANITIZE void AbstractMethodErrorEntrypoint(Method *method)
908 {
909     BEGIN_ENTRYPOINT();
910     LOG(DEBUG, INTEROP) << "AbstractMethodErrorEntrypoint \n";
911     ManagedThread *thread = ManagedThread::GetCurrent();
912     ASSERT(!thread->HasPendingException());
913     auto stack = StackWalker::Create(thread, UnwindPolicy::SKIP_INLINED);
914     ThrowAbstractMethodError(method);
915     ASSERT(thread->HasPendingException());
916     if (stack.IsCFrame()) {
917         FindCatchBlockInCFrames(thread, &stack, nullptr);
918     }
919 }
920 
ArithmeticExceptionEntrypoint()921 extern "C" NO_ADDRESS_SANITIZE void ArithmeticExceptionEntrypoint()
922 {
923     BEGIN_ENTRYPOINT();
924     LOG(DEBUG, INTEROP) << "ArithmeticExceptionEntrypoint \n";
925     ASSERT(!ManagedThread::GetCurrent()->HasPendingException());
926     ThrowArithmeticException();
927     HandlePendingException(UnwindPolicy::SKIP_INLINED);
928 }
929 
NegativeArraySizeExceptionEntrypoint(ssize_t size)930 extern "C" NO_ADDRESS_SANITIZE void NegativeArraySizeExceptionEntrypoint(ssize_t size)
931 {
932     BEGIN_ENTRYPOINT();
933     LOG(DEBUG, INTEROP) << "NegativeArraySizeExceptionEntrypoint \n";
934     ASSERT(!ManagedThread::GetCurrent()->HasPendingException());
935     ThrowNegativeArraySizeException(size);
936     HandlePendingException(UnwindPolicy::SKIP_INLINED);
937 }
938 
ClassCastExceptionEntrypoint(Class * instClass,ObjectHeader * srcObj)939 extern "C" NO_ADDRESS_SANITIZE void ClassCastExceptionEntrypoint(Class *instClass, ObjectHeader *srcObj)
940 {
941     BEGIN_ENTRYPOINT();
942     LOG(DEBUG, INTEROP) << "ClassCastExceptionEntrypoint \n";
943     ASSERT(!ManagedThread::GetCurrent()->HasPendingException());
944     ASSERT(srcObj != nullptr);
945     ThrowClassCastException(instClass, srcObj->ClassAddr<Class>());
946     HandlePendingException(UnwindPolicy::SKIP_INLINED);
947 }
948 
StackOverflowExceptionEntrypoint()949 extern "C" NO_ADDRESS_SANITIZE void StackOverflowExceptionEntrypoint()
950 {
951     // WARNING: We should not add any heavy code constructions here, like events or other debug/testing stuff,
952     // because we have small stack here, see ManagedThread::STACK_OVERFLOW_RESERVED_SIZE.
953     auto thread = ManagedThread::GetCurrent();
954 
955     ASSERT(!thread->HasPendingException());
956     thread->DisableStackOverflowCheck();
957     ThrowStackOverflowException(thread);
958     thread->EnableStackOverflowCheck();
959     HandlePendingException(UnwindPolicy::SKIP_INLINED);
960 }
961 
DeoptimizeEntrypoint(uint64_t deoptimizeType)962 extern "C" NO_ADDRESS_SANITIZE void DeoptimizeEntrypoint(uint64_t deoptimizeType)
963 {
964     BEGIN_ENTRYPOINT();
965     auto thread = ManagedThread::GetCurrent();
966     auto type = static_cast<panda::compiler::DeoptimizeType>(
967         deoptimizeType & ((1U << MinimumBitsToStore(panda::compiler::DeoptimizeType::COUNT)) - 1));
968     [[maybe_unused]] auto instId = deoptimizeType >> MinimumBitsToStore(panda::compiler::DeoptimizeType::COUNT);
969     LOG(INFO, INTEROP) << "DeoptimizeEntrypoint (reason: " << panda::compiler::DeoptimizeTypeToString(type)
970                        << ", inst_id: " << instId << ")\n";
971 
972     EVENT_DEOPTIMIZATION_REASON(std::string(StackWalker::Create(thread).GetMethod()->GetFullName()),
973                                 panda::compiler::DeoptimizeTypeToString(type));
974 
975     ASSERT(!thread->HasPendingException());
976     auto stack = StackWalker::Create(thread);
977     Method *destroyMethod = nullptr;
978     if (type >= panda::compiler::DeoptimizeType::CAUSE_METHOD_DESTRUCTION) {
979         // Get pointer to top method
980         destroyMethod = StackWalker::Create(thread, UnwindPolicy::SKIP_INLINED).GetMethod();
981     }
982     Deoptimize(&stack, nullptr, false, destroyMethod);
983 }
984 
ThrowInstantiationErrorEntrypoint(Class * klass)985 extern "C" NO_ADDRESS_SANITIZE void ThrowInstantiationErrorEntrypoint(Class *klass)
986 {
987     BEGIN_ENTRYPOINT();
988     LOG(DEBUG, INTEROP) << "ThrowInstantiationErrorEntrypoint \n";
989     ASSERT(!ManagedThread::GetCurrent()->HasPendingException());
990     const auto &name = klass->GetName();
991     PandaString pname(name.cbegin(), name.cend());
992     ThrowInstantiationError(pname);
993     HandlePendingException(UnwindPolicy::SKIP_INLINED);
994 }
995 
GetInitialTaggedValue(Method * method)996 coretypes::TaggedValue GetInitialTaggedValue(Method *method)
997 {
998     BEGIN_ENTRYPOINT();
999     return Runtime::GetCurrent()->GetLanguageContext(*method).GetInitialTaggedValue();
1000 }
1001 
LockObjectEntrypoint(ObjectHeader * obj)1002 extern "C" void LockObjectEntrypoint(ObjectHeader *obj)
1003 {
1004     BEGIN_ENTRYPOINT();
1005     panda::intrinsics::ObjectMonitorEnter(obj);
1006 }
1007 
LockObjectSlowPathEntrypoint(ObjectHeader * obj)1008 extern "C" void LockObjectSlowPathEntrypoint(ObjectHeader *obj)
1009 {
1010     BEGIN_ENTRYPOINT();
1011     panda::intrinsics::ObjectMonitorEnter(obj);
1012     if (!ManagedThread::GetCurrent()->HasPendingException()) {
1013         return;
1014     }
1015     LOG(DEBUG, INTEROP) << "ThrowNativeExceptionEntrypoint after LockObject \n";
1016     SetExceptionEvent(events::ExceptionType::NATIVE, ManagedThread::GetCurrent());
1017     HandlePendingException(UnwindPolicy::SKIP_INLINED);
1018 }
1019 
UnlockObjectEntrypoint(ObjectHeader * obj)1020 extern "C" void UnlockObjectEntrypoint(ObjectHeader *obj)
1021 {
1022     BEGIN_ENTRYPOINT();
1023     panda::intrinsics::ObjectMonitorExit(obj);
1024 }
1025 
UnlockObjectSlowPathEntrypoint(ObjectHeader * obj)1026 extern "C" void UnlockObjectSlowPathEntrypoint(ObjectHeader *obj)
1027 {
1028     BEGIN_ENTRYPOINT();
1029     panda::intrinsics::ObjectMonitorExit(obj);
1030     if (!ManagedThread::GetCurrent()->HasPendingException()) {
1031         return;
1032     }
1033     LOG(DEBUG, INTEROP) << "ThrowNativeExceptionEntrypoint after UnlockObject \n";
1034     SetExceptionEvent(events::ExceptionType::NATIVE, ManagedThread::GetCurrent());
1035     HandlePendingException(UnwindPolicy::SKIP_INLINED);
1036 }
1037 
IncompatibleClassChangeErrorForMethodConflictEntrypoint(Method * method)1038 extern "C" NO_ADDRESS_SANITIZE void IncompatibleClassChangeErrorForMethodConflictEntrypoint(Method *method)
1039 {
1040     BEGIN_ENTRYPOINT();
1041     LOG(DEBUG, INTEROP) << "IncompatibleClassChangeErrorForMethodConflictEntrypoint \n";
1042     ManagedThread *thread = ManagedThread::GetCurrent();
1043     ASSERT(!thread->HasPendingException());
1044     auto stack = StackWalker::Create(thread, UnwindPolicy::SKIP_INLINED);
1045     ThrowIncompatibleClassChangeErrorForMethodConflict(method);
1046     ASSERT(thread->HasPendingException());
1047     if (stack.IsCFrame()) {
1048         FindCatchBlockInCFrames(thread, &stack, nullptr);
1049     }
1050 }
1051 
1052 // NOLINTNEXTLINE(cppcoreguidelines-pro-type-vararg)
TraceEntrypoint(size_t pid,...)1053 extern "C" void TraceEntrypoint(size_t pid, ...)
1054 {
1055     LOG_ENTRYPOINT();
1056     auto id = static_cast<TraceId>(pid);
1057 
1058     // NOLINTNEXTLINE(cppcoreguidelines-pro-type-vararg)
1059     va_list args;
1060     // NOLINTNEXTLINE(cppcoreguidelines-pro-type-vararg)
1061     va_start(args, pid);
1062     switch (id) {
1063         case TraceId::METHOD_ENTER: {
1064             // NOLINTNEXTLINE(cppcoreguidelines-pro-type-vararg,clang-analyzer-valist.Uninitialized)
1065             [[maybe_unused]] auto method = va_arg(args, const Method *);
1066             // NOLINTNEXTLINE(cppcoreguidelines-pro-type-vararg)
1067             [[maybe_unused]] auto kind = va_arg(args, events::MethodEnterKind);
1068             EVENT_METHOD_ENTER(method->GetFullName(), kind, ManagedThread::GetCurrent()->RecordMethodEnter());
1069             break;
1070         }
1071         case TraceId::METHOD_EXIT: {
1072             // NOLINTNEXTLINE(cppcoreguidelines-pro-type-vararg,clang-analyzer-valist.Uninitialized)
1073             [[maybe_unused]] auto method = va_arg(args, const Method *);
1074             // NOLINTNEXTLINE(cppcoreguidelines-pro-type-vararg)
1075             [[maybe_unused]] auto kind = va_arg(args, events::MethodExitKind);
1076             EVENT_METHOD_EXIT(method->GetFullName(), kind, ManagedThread::GetCurrent()->RecordMethodExit());
1077             break;
1078         }
1079         case TraceId::PRINT_ARG: {
1080             // NOLINTNEXTLINE(cppcoreguidelines-pro-type-vararg,clang-analyzer-valist.Uninitialized)
1081             size_t argsNum = va_arg(args, size_t);
1082             std::cerr << "[TRACE ARGS] ";
1083             for (size_t i = 0; i < argsNum; i++) {
1084                 // NOLINTNEXTLINE(cppcoreguidelines-pro-type-vararg)
1085                 std::cerr << i << "=" << va_arg(args, void *) << " ";
1086             }
1087             std::cerr << std::endl;
1088 
1089             break;
1090         }
1091         default: {
1092             break;
1093         }
1094     }
1095     // NOLINTNEXTLINE(cppcoreguidelines-pro-type-vararg)
1096     va_end(args);
1097 }
1098 
LogEntrypoint(const char * fmt,...)1099 extern "C" void LogEntrypoint(const char *fmt, ...)
1100 {
1101     // NOLINTNEXTLINE(cppcoreguidelines-pro-type-vararg)
1102     va_list args;
1103     // NOLINTNEXTLINE(cppcoreguidelines-pro-type-vararg)
1104     va_start(args, fmt);
1105     // NOLINTNEXTLINE(clang-analyzer-valist.Uninitialized)
1106     vfprintf(stderr, fmt, args);
1107     // NOLINTNEXTLINE(cppcoreguidelines-pro-type-vararg)
1108     va_end(args);
1109 }
1110 
1111 // Irtoc Interpreter Entrypoints
1112 
FreeFrameInterp(Frame * frame,ManagedThread * current)1113 extern "C" void FreeFrameInterp(Frame *frame, ManagedThread *current)
1114 {
1115     ASSERT(frame->GetExt() != nullptr);
1116     current->GetStackFrameAllocator()->Free(frame->GetExt());
1117 }
1118 
AllocFrameInterp(ManagedThread * current,size_t allocSz)1119 extern "C" void *AllocFrameInterp(ManagedThread *current, size_t allocSz)
1120 {
1121     void *mem = current->GetStackFrameAllocator()->Alloc<false>(allocSz);
1122     if (UNLIKELY(mem == nullptr)) {
1123         current->DisableStackOverflowCheck();
1124         panda::ThrowStackOverflowException(current);
1125         current->EnableStackOverflowCheck();
1126     }
1127     return mem;
1128 }
1129 
InitializeFrame(void * mem,Method * method,Frame * prev,size_t nregs)1130 extern "C" Frame *InitializeFrame(void *mem, Method *method, Frame *prev, size_t nregs)
1131 {
1132     return new (Frame::FromExt(mem, CORE_EXT_FRAME_DATA_SIZE)) Frame(mem, method, prev, nregs);
1133 }
1134 
SafepointEntrypointInterp(ManagedThread * thread)1135 extern "C" void SafepointEntrypointInterp(ManagedThread *thread)
1136 {
1137     BEGIN_ENTRYPOINT();
1138     interpreter::RuntimeInterface::Safepoint(thread);
1139 }
1140 
IsCompiled(const void * entrypoint)1141 extern "C" int IsCompiled(const void *entrypoint)
1142 {
1143     return static_cast<int>(entrypoint != reinterpret_cast<const void *>(CompiledCodeToInterpreterBridge));
1144 }
1145 
GetClassIdEntrypoint(const Method * caller,uint32_t classId)1146 extern "C" size_t GetClassIdEntrypoint(const Method *caller, uint32_t classId)
1147 {
1148     auto resolvedId = caller->GetClass()->ResolveClassIndex(BytecodeId(classId).AsIndex());
1149     return resolvedId.GetOffset();
1150 }
1151 
CreateArrayByIdEntrypoint(ManagedThread * thread,const Method * caller,uint32_t classId,int32_t length)1152 extern "C" coretypes::Array *CreateArrayByIdEntrypoint(ManagedThread *thread, const Method *caller, uint32_t classId,
1153                                                        int32_t length)
1154 {
1155     CHECK_STACK_WALKER;
1156     auto *klass = interpreter::RuntimeInterface::ResolveClass<true>(thread, *caller, BytecodeId(classId));
1157     if (UNLIKELY(klass == nullptr)) {
1158         return nullptr;
1159     }
1160     return interpreter::RuntimeInterface::CreateArray(klass, length);
1161 }
1162 
1163 template <BytecodeInstruction::Format FORMAT>
CreateMultiDimArray(ManagedThread * thread,Frame * frame,Class * klass,Method * caller,uint32_t methodId,const uint8_t * pc)1164 static coretypes::Array *CreateMultiDimArray(ManagedThread *thread, Frame *frame, Class *klass, Method *caller,
1165                                              uint32_t methodId, const uint8_t *pc)
1166 {
1167     interpreter::DimIterator<FORMAT> dimIter {BytecodeInstruction(pc), frame};
1168     auto nargs = interpreter::RuntimeInterface::GetMethodArgumentsCount(caller, BytecodeId(methodId));
1169     auto obj =
1170         coretypes::Array::CreateMultiDimensionalArray<interpreter::DimIterator<FORMAT>>(thread, klass, nargs, dimIter);
1171     return obj;
1172 }
1173 
CreateMultiDimensionalArrayById(ManagedThread * thread,Frame * frame,Class * klass,Method * caller,uint32_t methodId,const uint8_t * pc,int32_t formatIdx)1174 extern "C" coretypes::Array *CreateMultiDimensionalArrayById(ManagedThread *thread, Frame *frame, Class *klass,
1175                                                              Method *caller, uint32_t methodId, const uint8_t *pc,
1176                                                              int32_t formatIdx)
1177 {
1178     switch (formatIdx) {
1179         case 0U:
1180             return CreateMultiDimArray<BytecodeInstruction::Format::V4_V4_ID16>(thread, frame, klass, caller, methodId,
1181                                                                                 pc);
1182         case 1U:
1183             return CreateMultiDimArray<BytecodeInstruction::Format::V4_V4_V4_V4_ID16>(thread, frame, klass, caller,
1184                                                                                       methodId, pc);
1185         case 2U:
1186             return CreateMultiDimArray<BytecodeInstruction::Format::V8_ID16>(thread, frame, klass, caller, methodId,
1187                                                                              pc);
1188         default:
1189             UNREACHABLE();
1190     }
1191     return nullptr;
1192 }
1193 
CreateObjectByClassInterpreter(ManagedThread * thread,Class * klass)1194 extern "C" ObjectHeader *CreateObjectByClassInterpreter(ManagedThread *thread, Class *klass)
1195 {
1196     ASSERT(klass != nullptr);
1197     ASSERT(!klass->IsArrayClass());
1198 
1199     if (!klass->IsInitialized()) {
1200         auto *classLinker = Runtime::GetCurrent()->GetClassLinker();
1201         if (!classLinker->InitializeClass(thread, klass)) {
1202             return nullptr;
1203         }
1204     }
1205 
1206     return interpreter::RuntimeInterface::CreateObject(thread, klass);
1207 }
1208 
CheckCastByIdEntrypoint(ObjectHeader * obj,Class * klass)1209 extern "C" uint32_t CheckCastByIdEntrypoint(ObjectHeader *obj, Class *klass)
1210 {
1211     CHECK_STACK_WALKER;
1212     ASSERT(IsAddressInObjectsHeapOrNull(obj));
1213     Class *objKlass = obj == nullptr ? nullptr : obj->ClassAddr<Class>();
1214     if (UNLIKELY(objKlass != nullptr && !klass->IsAssignableFrom(objKlass))) {
1215         panda::ThrowClassCastException(klass, objKlass);
1216         return 1;
1217     }
1218     return 0;
1219 }
1220 
IsInstanceByIdEntrypoint(ObjectHeader * obj,Class * klass)1221 extern "C" uint32_t IsInstanceByIdEntrypoint(ObjectHeader *obj, Class *klass)
1222 {
1223     CHECK_STACK_WALKER;
1224     ASSERT(IsAddressInObjectsHeapOrNull(obj));
1225 
1226     return IsInstanceEntrypoint(obj, klass);
1227 }
1228 
ResolveStringByIdEntrypoint(ManagedThread * thread,Frame * frame,FileEntityId id)1229 extern "C" coretypes::String *ResolveStringByIdEntrypoint(ManagedThread *thread, Frame *frame, FileEntityId id)
1230 {
1231     BEGIN_ENTRYPOINT();
1232     return thread->GetVM()->ResolveString(frame, panda_file::File::EntityId(id));
1233 }
1234 
ResolveLiteralArrayByIdEntrypoint(ManagedThread * thread,const Method * caller,uint32_t typeId)1235 extern "C" coretypes::Array *ResolveLiteralArrayByIdEntrypoint(ManagedThread *thread, const Method *caller,
1236                                                                uint32_t typeId)
1237 {
1238     BEGIN_ENTRYPOINT();
1239     return interpreter::RuntimeInterface::ResolveLiteralArray(thread->GetVM(), *caller, BytecodeId(typeId));
1240 }
1241 
ResolveTypeByIdEntrypoint(ManagedThread * thread,Method * caller,uint32_t id,InterpreterCache::Entry * entry,const uint8_t * pc)1242 extern "C" Class *ResolveTypeByIdEntrypoint(ManagedThread *thread, Method *caller, uint32_t id,
1243                                             InterpreterCache::Entry *entry, const uint8_t *pc)
1244 {
1245     CHECK_STACK_WALKER;
1246     auto klass = interpreter::RuntimeInterface::ResolveClass<false>(thread, *caller, BytecodeId(id));
1247     if (klass == nullptr) {
1248         return nullptr;
1249     }
1250     *entry = {pc, caller, static_cast<void *>(klass)};
1251     return klass;
1252 }
1253 
GetFieldByIdEntrypoint(ManagedThread * thread,Method * caller,uint32_t fieldId,InterpreterCache::Entry * entry,const uint8_t * pc)1254 extern "C" Field *GetFieldByIdEntrypoint([[maybe_unused]] ManagedThread *thread, Method *caller, uint32_t fieldId,
1255                                          InterpreterCache::Entry *entry, const uint8_t *pc)
1256 {
1257     CHECK_STACK_WALKER;
1258     auto resolvedId = caller->GetClass()->ResolveFieldIndex(BytecodeId(fieldId).AsIndex());
1259     auto *classLinker = Runtime::GetCurrent()->GetClassLinker();
1260     auto *field = classLinker->GetField(*caller, panda_file::File::EntityId(resolvedId));
1261     if (field != nullptr) {
1262         *entry = {pc, caller, static_cast<void *>(field)};
1263     }
1264     return field;
1265 }
1266 
GetStaticFieldByIdEntrypoint(ManagedThread * thread,Method * caller,uint32_t fieldId,InterpreterCache::Entry * entry,const uint8_t * pc)1267 extern "C" Field *GetStaticFieldByIdEntrypoint(ManagedThread *thread, Method *caller, uint32_t fieldId,
1268                                                InterpreterCache::Entry *entry, const uint8_t *pc)
1269 {
1270     CHECK_STACK_WALKER;
1271     auto *field = interpreter::RuntimeInterface::ResolveField(thread, *caller, BytecodeId(fieldId));
1272     if (field == nullptr) {
1273         return field;
1274     }
1275     ASSERT(field->IsStatic());
1276     *entry = {pc, caller, static_cast<void *>(field)};
1277     return field;
1278 }
1279 
GetCalleeMethodFromBytecodeId(ManagedThread * thread,Method * caller,uint32_t calleeId,InterpreterCache::Entry * entry,const uint8_t * pc)1280 extern "C" Method *GetCalleeMethodFromBytecodeId(ManagedThread *thread, Method *caller, uint32_t calleeId,
1281                                                  InterpreterCache::Entry *entry, const uint8_t *pc)
1282 {
1283     CHECK_STACK_WALKER;
1284     auto *method = interpreter::RuntimeInterface::ResolveMethod(thread, *caller, BytecodeId(calleeId));
1285     if (method == nullptr) {
1286         return nullptr;  // if nullptr we don't need to cache
1287     }
1288     *entry = {pc, caller, static_cast<void *>(method)};
1289     return method;
1290 }
1291 
GetMethodClassById(Method * method,uint32_t methodId)1292 extern "C" Class *GetMethodClassById(Method *method, uint32_t methodId)
1293 {
1294     CHECK_STACK_WALKER;
1295     Class *klass = interpreter::RuntimeInterface::GetMethodClass(method, BytecodeId(methodId));
1296     return klass;  // May be nullptr if exception occured
1297 }
1298 
ResolveVirtualMethod(const Method * callee,Frame * frame,const ObjectPointerType objPtr,const uint8_t * pc,Method * caller)1299 extern "C" Method *ResolveVirtualMethod(const Method *callee, Frame *frame, const ObjectPointerType objPtr,
1300                                         const uint8_t *pc, Method *caller)
1301 {
1302     auto *obj = reinterpret_cast<const ObjectHeader *>(objPtr);
1303     ASSERT(IsAddressInObjectsHeap(obj));
1304     auto *cls = obj->ClassAddr<Class>();
1305     ASSERT(cls != nullptr);
1306     auto *resolved = cls->ResolveVirtualMethod(callee);
1307     ASSERT(resolved != nullptr);
1308 
1309     ProfilingData *profData = caller->GetProfilingData();
1310     auto bytecodeOffset = pc - frame->GetInstruction();
1311     if (profData != nullptr) {
1312         profData->UpdateInlineCaches(bytecodeOffset, cls);
1313     }
1314 
1315     return resolved;
1316 }
1317 
Verify(Method * method)1318 extern "C" bool Verify(Method *method)
1319 {
1320     if (UNLIKELY(!method->Verify())) {
1321         interpreter::RuntimeInterface::ThrowVerificationException(method->GetFullName());
1322         return false;
1323     }
1324     return true;
1325 }
1326 
DecrementHotnessCounter(Method * method,ManagedThread * thread)1327 extern "C" bool DecrementHotnessCounter(Method *method, ManagedThread *thread)
1328 {
1329     method->DecrementHotnessCounter<true>(thread, 0, nullptr);
1330     if (thread->HasPendingException()) {
1331         return false;
1332     }
1333     return method->GetCompiledEntryPoint() != GetCompiledCodeToInterpreterBridge(method);
1334 }
1335 
DecrementHotnessCounterDyn(Method * method,TaggedValue funcObj,ManagedThread * thread)1336 extern "C" bool DecrementHotnessCounterDyn(Method *method, TaggedValue funcObj, ManagedThread *thread)
1337 {
1338     method->DecrementHotnessCounter<true>(thread, 0, nullptr, false, funcObj);
1339     if (thread->HasPendingException()) {
1340         return false;
1341     }
1342     return method->GetCompiledEntryPoint() != GetCompiledCodeToInterpreterBridge(method);
1343 }
1344 
CallCompilerSlowPath(ManagedThread * thread,Method * method)1345 extern "C" void CallCompilerSlowPath(ManagedThread *thread, Method *method)
1346 {
1347     CHECK_STACK_WALKER;
1348     method->DecrementHotnessCounter<false>(thread, 0, nullptr);
1349 }
1350 
CallCompilerSlowPathOSR(ManagedThread * thread,Method * method,Frame * frame,uint64_t acc,uint64_t accTag,uint32_t insOffset,int offset)1351 extern "C" bool CallCompilerSlowPathOSR(ManagedThread *thread, Method *method, Frame *frame, uint64_t acc,
1352                                         uint64_t accTag, uint32_t insOffset, int offset)
1353 {
1354     CHECK_STACK_WALKER;
1355     if constexpr (ArchTraits<RUNTIME_ARCH>::SUPPORT_OSR) {
1356         ASSERT(ArchTraits<RUNTIME_ARCH>::SUPPORT_OSR);
1357         if (!frame->IsDeoptimized() && Runtime::GetOptions().IsCompilerEnableOsr()) {
1358             frame->SetAcc(panda::interpreter::AccVRegister(acc, accTag));
1359             return method->DecrementHotnessCounter<false>(thread, insOffset + offset, &frame->GetAcc(), true);
1360         }
1361     }
1362     method->DecrementHotnessCounter<false>(thread, 0, nullptr);
1363     return false;
1364 }
1365 
UpdateBranchTaken(Method * method,Frame * frame,const uint8_t * pc,ProfilingData * profDataIrtoc)1366 extern "C" void UpdateBranchTaken([[maybe_unused]] Method *method, Frame *frame, const uint8_t *pc,
1367                                   ProfilingData *profDataIrtoc)
1368 {
1369     // Add a second prof_data loading because without it THREAD_SANITIZER crashes
1370     // NOTE(aantipina): investigate and delete the second loading (issue I6DTAA)
1371     [[maybe_unused]] ProfilingData *profData = method->GetProfilingDataWithoutCheck();
1372     profDataIrtoc->UpdateBranchTaken(pc - frame->GetInstruction());
1373 }
1374 
UpdateBranchUntaken(Method * method,Frame * frame,const uint8_t * pc,ProfilingData * profDataIrtoc)1375 extern "C" void UpdateBranchUntaken([[maybe_unused]] Method *method, Frame *frame, const uint8_t *pc,
1376                                     ProfilingData *profDataIrtoc)
1377 {
1378     // Add a second prof_data loading because without it THREAD_SANITIZER crashes
1379     // NOTE(aantipina): investigate and delete the second loading
1380     [[maybe_unused]] ProfilingData *profData = method->GetProfilingDataWithoutCheck();
1381     profDataIrtoc->UpdateBranchNotTaken(pc - frame->GetInstruction());
1382 }
1383 
ReadUlebEntrypoint(const uint8_t * ptr)1384 extern "C" uint32_t ReadUlebEntrypoint(const uint8_t *ptr)
1385 {
1386     uint32_t result;
1387     [[maybe_unused]] size_t n;
1388     [[maybe_unused]] bool isFull;
1389     std::tie(result, n, isFull) = leb128::DecodeUnsigned<uint32_t>(ptr);
1390     ASSERT(isFull);
1391     return result;
1392 }
1393 
GetInstructionsByMethod(const Method * method)1394 extern "C" const uint8_t *GetInstructionsByMethod(const Method *method)
1395 {
1396     return method->GetInstructions();
1397 }
1398 
GetNumVregsByMethod(const Method * method)1399 extern "C" size_t GetNumVregsByMethod(const Method *method)
1400 {
1401     return method->GetNumVregs();
1402 }
1403 
ThrowExceptionFromInterpreter(ManagedThread * thread,ObjectHeader * exception,Frame * frame,const uint8_t * pc)1404 extern "C" void ThrowExceptionFromInterpreter(ManagedThread *thread, ObjectHeader *exception, Frame *frame,
1405                                               const uint8_t *pc)
1406 {
1407     CHECK_STACK_WALKER;
1408     ASSERT(!thread->HasPendingException());
1409     ASSERT(IsAddressInObjectsHeap(exception));
1410     Method *method = frame->GetMethod();
1411     ProfilingData *profData = method->GetProfilingDataWithoutCheck();
1412     if (profData != nullptr) {
1413         profData->UpdateThrowTaken(pc - frame->GetInstruction());
1414     }
1415     thread->SetException(exception);
1416 }
1417 
ThrowArithmeticExceptionFromInterpreter()1418 extern "C" void ThrowArithmeticExceptionFromInterpreter()
1419 {
1420     CHECK_STACK_WALKER;
1421     ASSERT(!ManagedThread::GetCurrent()->HasPendingException());
1422     interpreter::RuntimeInterface::ThrowArithmeticException();
1423 }
1424 
ThrowNullPointerExceptionFromInterpreter()1425 extern "C" void ThrowNullPointerExceptionFromInterpreter()
1426 {
1427     CHECK_STACK_WALKER;
1428     ASSERT(!ManagedThread::GetCurrent()->HasPendingException());
1429     interpreter::RuntimeInterface::ThrowNullPointerException();
1430 }
1431 
ThrowNegativeArraySizeExceptionFromInterpreter(int32_t size)1432 extern "C" void ThrowNegativeArraySizeExceptionFromInterpreter(int32_t size)
1433 {
1434     CHECK_STACK_WALKER;
1435     ASSERT(!ManagedThread::GetCurrent()->HasPendingException());
1436     interpreter::RuntimeInterface::ThrowNegativeArraySizeException(size);
1437 }
1438 
ThrowArrayIndexOutOfBoundsExceptionFromInterpreter(ssize_t idx,size_t length)1439 extern "C" void ThrowArrayIndexOutOfBoundsExceptionFromInterpreter(ssize_t idx, size_t length)
1440 {
1441     CHECK_STACK_WALKER;
1442     ASSERT(!ManagedThread::GetCurrent()->HasPendingException());
1443     interpreter::RuntimeInterface::ThrowArrayIndexOutOfBoundsException(idx, length);
1444 }
1445 
CheckStoreArrayReferenceFromInterpreter(coretypes::Array * array,ObjectHeader * storeObj)1446 extern "C" uint8_t CheckStoreArrayReferenceFromInterpreter(coretypes::Array *array, ObjectHeader *storeObj)
1447 {
1448     CHECK_STACK_WALKER;
1449     ASSERT(array != nullptr);
1450     ASSERT(IsAddressInObjectsHeapOrNull(storeObj));
1451 
1452     if (storeObj == nullptr) {  // NOTE: may be moved to IRTOC
1453         return 0;
1454     }
1455 
1456     // SUPPRESS_CSA_NEXTLINE(alpha.core.WasteObjHeader)
1457     auto *arrayClass = array->ClassAddr<Class>();
1458     auto *elementClass = arrayClass->GetComponentType();
1459     // SUPPRESS_CSA_NEXTLINE(alpha.core.WasteObjHeader)
1460     if (!storeObj->IsInstanceOf(elementClass)) {
1461         // SUPPRESS_CSA_NEXTLINE(alpha.core.WasteObjHeader)
1462         interpreter::RuntimeInterface::ThrowArrayStoreException(arrayClass, storeObj->ClassAddr<Class>());
1463         return 1;
1464     }
1465     return 0;
1466 }
1467 
FindCatchBlockInIFramesStackless(ManagedThread ** currThread,Frame ** currFrame,const uint8_t * pc)1468 extern "C" uint32_t FindCatchBlockInIFramesStackless(ManagedThread **currThread, Frame **currFrame, const uint8_t *pc)
1469 {
1470     uint32_t inst = pc - (*currFrame)->GetInstruction();
1471     Frame *frame = *currFrame;
1472 
1473     while (frame != nullptr) {
1474         ManagedThread *thread = *currThread;
1475         Frame *prev = frame->GetPrevFrame();
1476         ASSERT(thread->HasPendingException());
1477 
1478         Method *method = frame->GetMethod();
1479         uint32_t pcOffset = interpreter::RuntimeInterface::FindCatchBlock(*method, thread->GetException(), inst);
1480         if (pcOffset != panda_file::INVALID_OFFSET) {
1481             return pcOffset;
1482         }
1483 
1484         if (!frame->IsStackless() || prev == nullptr || StackWalker::IsBoundaryFrame<FrameKind::INTERPRETER>(prev)) {
1485             return pcOffset;
1486         }
1487 
1488         EVENT_METHOD_EXIT(method->GetFullName(), events::MethodExitKind::INTERP, thread->RecordMethodExit());
1489 
1490         Runtime::GetCurrent()->GetNotificationManager()->MethodExitEvent(thread, method);
1491 
1492         inst = prev->GetBytecodeOffset();
1493         *currFrame = prev;
1494 
1495         thread->GetVM()->HandleReturnFrame();
1496 
1497         interpreter::RuntimeInterface::SetCurrentFrame(thread, prev);
1498 
1499         ASSERT(thread->HasPendingException());
1500 
1501         interpreter::RuntimeInterface::FreeFrame(*currThread, frame);
1502 
1503         LOG(DEBUG, INTERPRETER) << "Exit: Runtime Call.";
1504 
1505         frame = prev;
1506     }
1507 
1508     return panda_file::INVALID_OFFSET;
1509 }
1510 
FindCatchBlockInIFrames(ManagedThread * currThread,Frame * currFrame,const uint8_t * pc)1511 extern "C" const uint8_t *FindCatchBlockInIFrames(ManagedThread *currThread, Frame *currFrame, const uint8_t *pc)
1512 {
1513     CHECK_STACK_WALKER;
1514 
1515     uint32_t pcOffset = panda_file::INVALID_OFFSET;
1516 
1517     pcOffset = FindCatchBlockInIFramesStackless(&currThread, &currFrame, pc);
1518     if (pcOffset == panda_file::INVALID_OFFSET) {
1519         if constexpr (RUNTIME_ARCH == Arch::AARCH64 || RUNTIME_ARCH == Arch::AARCH32 || RUNTIME_ARCH == Arch::X86_64) {
1520             panda::FindCatchBlockInCallStack(currThread);
1521         }
1522         return pc;
1523     }
1524 
1525     Method *method = currFrame->GetMethod();
1526     ASSERT(method != nullptr);
1527     LanguageContext ctx = interpreter::RuntimeInterface::GetLanguageContext(*method);
1528     ObjectHeader *exceptionObject = currThread->GetException();
1529     ctx.SetExceptionToVReg(currFrame->GetAcc(), exceptionObject);
1530 
1531     currThread->ClearException();
1532     Span<const uint8_t> sp(currFrame->GetMethod()->GetInstructions(), pcOffset);
1533     return sp.cend();
1534 }
1535 
VmCreateString(ManagedThread * thread,Method * method,ObjectHeader * ctorArg)1536 extern "C" coretypes::String *VmCreateString(ManagedThread *thread, Method *method, ObjectHeader *ctorArg)
1537 {
1538     CHECK_STACK_WALKER;
1539     // If ctor has the only argument (object itself), ctor_arg is allowed to contain garbage
1540     ASSERT(method->GetNumArgs() == 1 || IsAddressInObjectsHeapOrNull(ctorArg));
1541 
1542     return thread->GetVM()->CreateString(method, ctorArg);
1543 }
1544 
DebugPrintEntrypoint(panda::Frame * frame,const uint8_t * pc,uint64_t accPayload,uint64_t accTag)1545 extern "C" void DebugPrintEntrypoint([[maybe_unused]] panda::Frame *frame, [[maybe_unused]] const uint8_t *pc,
1546                                      [[maybe_unused]] uint64_t accPayload, [[maybe_unused]] uint64_t accTag)
1547 {
1548     CHECK_STACK_WALKER;
1549 #ifndef NDEBUG
1550     if (!Logger::IsLoggingOn(Logger::Level::DEBUG, Logger::Component::INTERPRETER)) {
1551         return;
1552     }
1553 
1554     constexpr uint64_t STANDARD_DEBUG_INDENT = 5;
1555     PandaString accDump;
1556     auto accVreg = panda::interpreter::VRegister(accPayload);
1557     auto accTagVreg = panda::interpreter::VRegister(accTag);
1558     if (frame->IsDynamic()) {
1559         accDump = panda::interpreter::DynamicVRegisterRef(&accVreg).DumpVReg();
1560         LOG(DEBUG, INTERPRETER) << PandaString(STANDARD_DEBUG_INDENT, ' ') << "acc." << accDump;
1561 
1562         DynamicFrameHandler frameHandler(frame);
1563         for (size_t i = 0; i < frame->GetSize(); ++i) {
1564             LOG(DEBUG, INTERPRETER) << PandaString(STANDARD_DEBUG_INDENT, ' ') << "v" << i << "."
1565                                     << frameHandler.GetVReg(i).DumpVReg();
1566         }
1567     } else {
1568         accDump = panda::interpreter::StaticVRegisterRef(&accVreg, &accTagVreg).DumpVReg();
1569         LOG(DEBUG, INTERPRETER) << PandaString(STANDARD_DEBUG_INDENT, ' ') << "acc." << accDump;
1570 
1571         StaticFrameHandler frameHandler(frame);
1572         for (size_t i = 0; i < frame->GetSize(); ++i) {
1573             LOG(DEBUG, INTERPRETER) << PandaString(STANDARD_DEBUG_INDENT, ' ') << "v" << i << "."
1574                                     << frameHandler.GetVReg(i).DumpVReg();
1575         }
1576     }
1577     LOG(DEBUG, INTERPRETER) << " pc: " << (void *)pc << " ---> " << BytecodeInstruction(pc);
1578 #endif
1579 }
1580 
JsCastDoubleToInt32(double d)1581 extern "C" PANDA_PUBLIC_API int32_t JsCastDoubleToInt32(double d)
1582 {
1583     return coretypes::JsCastDoubleToInt(d, coretypes::INT32_BITS);
1584 }
1585 
JsCastDoubleToInt32Entrypoint(uint64_t d)1586 extern "C" int32_t JsCastDoubleToInt32Entrypoint(uint64_t d)
1587 {
1588     return coretypes::JsCastDoubleToInt(bit_cast<double>(d), coretypes::INT32_BITS);
1589 }
1590 
1591 /* The shared implementation of the StringBuilder.append() intrinsics */
1592 template <class T>
ToClassPtr(uintptr_t obj)1593 static T *ToClassPtr(uintptr_t obj)
1594 {
1595     return reinterpret_cast<T *>(*reinterpret_cast<ObjectPointerType *>(obj));
1596 }
1597 
1598 /* offset values to be aligned with the StringBuilder class layout */
1599 static constexpr uint32_t SB_COUNT_OFFSET = 12;
1600 static constexpr uint32_t SB_VALUE_OFFSET = 8;
1601 
GetCountValue(ObjectHeader * sb)1602 static uint32_t GetCountValue(ObjectHeader *sb)
1603 {
1604     /* StringBuilder is not thread safe, we are supposed to
1605      * provide just the regular access to it's fields */
1606     return sb->GetFieldPrimitive<uint32_t>(SB_COUNT_OFFSET);
1607 }
1608 
GetCapacity(ObjectHeader * self)1609 static uint32_t GetCapacity(ObjectHeader *self)
1610 {
1611     return ToClassPtr<coretypes::Array>(ToUintPtr(self) + SB_VALUE_OFFSET)->GetLength();
1612 }
1613 
GetStorageAddress(ObjectHeader * sb,uint32_t count)1614 static uint16_t *GetStorageAddress(ObjectHeader *sb, uint32_t count)
1615 {
1616     auto storage = ToClassPtr<coretypes::Array>(ToUintPtr(sb) + SB_VALUE_OFFSET);
1617     return reinterpret_cast<uint16_t *>(ToUintPtr(storage) + coretypes::Array::GetDataOffset() + (count << 1U));
1618 }
1619 
RecalculateCapacity(uint32_t capacity,uint32_t newsize)1620 static inline uint32_t RecalculateCapacity(uint32_t capacity, uint32_t newsize)
1621 {
1622     capacity = (capacity + 1) << 1U;
1623     capacity = newsize > capacity ? newsize : capacity;
1624     return capacity;
1625 }
1626 
MoveStorageData(ObjectHeader * sb,void * newstorage)1627 static void MoveStorageData(ObjectHeader *sb, void *newstorage)
1628 {
1629     auto size = GetCountValue(sb) << 1U;
1630     auto newbuf = ToVoidPtr(ToUintPtr(newstorage) + coretypes::Array::GetDataOffset());
1631     auto oldbuf = ToVoidPtr(ToUintPtr(GetStorageAddress(sb, 0U)));
1632     std::copy_n(reinterpret_cast<uint8_t *>(oldbuf), size, reinterpret_cast<uint8_t *>(newbuf));
1633 }
1634 
AssureCapacity(ObjectHeader * sb,uint32_t newsize,coretypes::String * str)1635 static std::tuple<bool, ObjectHeader *, coretypes::String *> AssureCapacity(ObjectHeader *sb, uint32_t newsize,
1636                                                                             coretypes::String *str)
1637 {
1638     if (GetCapacity(sb) >= newsize) {
1639         return std::make_tuple(true, sb, str);
1640     }
1641 
1642     auto thread = ManagedThread::GetCurrent();
1643     HandleScope<ObjectHeader *> scope(thread);
1644     VMHandle<ObjectHeader> handle(thread, sb);
1645     VMHandle<coretypes::String> strHandle {};
1646     strHandle = str != nullptr ? VMHandle<coretypes::String>(thread, str) : strHandle;
1647 
1648     auto *vm = Runtime::GetCurrent()->GetPandaVM();
1649     auto klass = Runtime::GetCurrent()
1650                      ->GetClassLinker()
1651                      ->GetExtension(vm->GetLanguageContext())
1652                      ->GetClassRoot(ClassRoot::ARRAY_U16);
1653 
1654     auto capacity = RecalculateCapacity(GetCapacity(sb), newsize);
1655     auto *newstorage = panda::coretypes::Array::Create(klass, capacity);
1656     sb = reinterpret_cast<ObjectHeader *>(handle.GetPtr());
1657     str = str != nullptr ? strHandle.GetPtr() : nullptr;
1658 
1659     if (newstorage == nullptr) {
1660         return std::make_tuple(false, sb, str);
1661     }
1662 
1663     MoveStorageData(sb, newstorage);
1664     handle->SetFieldObject(SB_VALUE_OFFSET, newstorage);
1665 
1666     return std::make_tuple(true, sb, str);
1667 }
1668 
1669 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
1670 #define CHECK_CAPACITY_FAST(sb, newsize)                                           \
1671     {                                                                              \
1672         auto success = false;                                                      \
1673         std::tie(success, sb, std::ignore) = AssureCapacity(sb, newsize, nullptr); \
1674                                                                                    \
1675         if (!success) {                                                            \
1676             return sb;                                                             \
1677         }                                                                          \
1678     }
1679 
StoreNumber(ObjectHeader * sb,int64_t n)1680 static ObjectHeader *StoreNumber(ObjectHeader *sb, int64_t n)
1681 {
1682     auto num = n < 0 ? -static_cast<uint64_t>(n) : n;
1683     auto size = CountDigits(num) + static_cast<uint32_t>(n < 0);
1684     auto count = GetCountValue(sb);
1685     auto newsize = count + size;
1686 
1687     CHECK_CAPACITY_FAST(sb, newsize);
1688     utf::UInt64ToUtf16Array(num, GetStorageAddress(sb, count), size, n < 0);
1689     sb->SetFieldPrimitive<uint32_t>(SB_COUNT_OFFSET, newsize);
1690     return sb;
1691 }
1692 
CoreStringBuilderLong(ObjectHeader * sb,int64_t n)1693 extern "C" ObjectHeader *CoreStringBuilderLong(ObjectHeader *sb, int64_t n)
1694 {
1695     return StoreNumber(sb, n);
1696 }
1697 
CoreStringBuilderInt(ObjectHeader * sb,int32_t n)1698 extern "C" ObjectHeader *CoreStringBuilderInt(ObjectHeader *sb, int32_t n)
1699 {
1700     return StoreNumber(sb, static_cast<int64_t>(n));
1701 }
1702 
CoreStringBuilderBool(ObjectHeader * sb,const uint8_t v)1703 extern "C" ObjectHeader *CoreStringBuilderBool(ObjectHeader *sb, const uint8_t v)
1704 {
1705     const uint64_t truestr = 0x0065007500720074;
1706     const uint64_t falsestr = 0x0073006c00610066;
1707     const uint16_t falsestr2 = 0x0065;
1708 
1709     auto count = GetCountValue(sb);
1710     auto size = 4U + (1U - v);  // v is actually u1
1711     auto newsize = count + size;
1712 
1713     CHECK_CAPACITY_FAST(sb, newsize);
1714     auto dst = reinterpret_cast<uint64_t *>(GetStorageAddress(sb, count));
1715 
1716     if (v != 0) {
1717         *dst = truestr;
1718     } else {
1719         // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
1720         auto dst2 = reinterpret_cast<uint16_t *>(dst + 1);
1721         *dst = falsestr;
1722         *dst2 = falsestr2;
1723     }
1724 
1725     sb->SetFieldPrimitive<uint32_t>(SB_COUNT_OFFSET, newsize);
1726     return sb;
1727 }
1728 
CoreStringBuilderChar(ObjectHeader * sb,const uint16_t c)1729 extern "C" ObjectHeader *CoreStringBuilderChar(ObjectHeader *sb, const uint16_t c)
1730 {
1731     auto count = GetCountValue(sb);
1732     auto newsize = count + 1;
1733 
1734     CHECK_CAPACITY_FAST(sb, newsize);
1735     auto dst = GetStorageAddress(sb, count);
1736 
1737     *dst = c;
1738     sb->SetFieldPrimitive<uint32_t>(SB_COUNT_OFFSET, newsize);
1739     return sb;
1740 }
1741 
CoreStringBuilderString(ObjectHeader * sb,void * s)1742 extern "C" ObjectHeader *CoreStringBuilderString(ObjectHeader *sb, void *s)
1743 {
1744     const uint64_t nullstr = 0x006c006c0075006e;
1745     auto str = static_cast<coretypes::String *>(s);
1746     auto isnull = str == nullptr;
1747     auto size = isnull ? sizeof(nullstr) / sizeof(uint16_t) : str->GetLength();
1748     if (size == 0) {
1749         return sb;
1750     }
1751 
1752     auto count = GetCountValue(sb);
1753     auto newsize = count + size;
1754 
1755     auto success = false;
1756     std::tie(success, sb, str) = AssureCapacity(sb, newsize, str);
1757 
1758     if (!success) {
1759         return sb;
1760     }
1761 
1762     auto dst = GetStorageAddress(sb, count);
1763 
1764     if (!isnull) {
1765         auto src = ToVoidPtr(ToUintPtr(str) + coretypes::String::GetDataOffset());
1766         str->IsUtf16() ? std::copy_n(reinterpret_cast<uint16_t *>(src), size, dst)
1767                        : std::copy_n(reinterpret_cast<uint8_t *>(src), size, dst);
1768     } else {
1769         /* store the 8-bytes chunk right away */
1770         *reinterpret_cast<uint64_t *>(dst) = nullstr;
1771     }
1772 
1773     sb->SetFieldPrimitive<uint32_t>(SB_COUNT_OFFSET, newsize);
1774     return sb;
1775 }
1776 }  // namespace panda
1777