• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /**
2  * Copyright (c) 2021-2022 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  * http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #include "runtime/entrypoints/entrypoints.h"
17 
18 #include "libpandabase/events/events.h"
19 #include "macros.h"
20 #include "compiler/compiler_options.h"
21 #include "runtime/deoptimization.h"
22 #include "runtime/arch/memory_helpers.h"
23 #include "runtime/include/class_linker-inl.h"
24 #include "runtime/include/coretypes/array.h"
25 #include "runtime/include/exceptions.h"
26 #include "runtime/include/method-inl.h"
27 #include "runtime/include/object_header-inl.h"
28 #include "runtime/include/runtime.h"
29 #include "runtime/include/value-inl.h"
30 #include "runtime/include/panda_vm.h"
31 #include "runtime/interpreter/frame.h"
32 #include "runtime/interpreter/interpreter.h"
33 #include "runtime/interpreter/runtime_interface.h"
34 #include "runtime/mem/tlab.h"
35 #include "compiler/optimizer/ir/runtime_interface.h"
36 #include "runtime/handle_base-inl.h"
37 #include "libpandabase/utils/asan_interface.h"
38 #include "libpandabase/utils/tsan_interface.h"
39 #include "utils/cframe_layout.h"
40 #include "intrinsics.h"
41 
42 namespace panda {
43 
44 using panda::compiler::TraceId;
45 
46 #undef LOG_ENTRYPOINTS
47 
48 class ScopedLog {
49 public:
50     ScopedLog() = delete;
ScopedLog(const char * function)51     explicit ScopedLog(const char *function) : function_(function)
52     {
53         LOG(DEBUG, INTEROP) << "ENTRYPOINT: " << function;
54     }
~ScopedLog()55     ~ScopedLog()
56     {
57         LOG(DEBUG, INTEROP) << "EXIT ENTRYPOINT: " << function_;
58     }
59     NO_COPY_SEMANTIC(ScopedLog);
60     NO_MOVE_SEMANTIC(ScopedLog);
61 
62 private:
63     std::string function_;
64 };
65 
66 #ifdef LOG_ENTRYPOINTS
67 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
68 #define LOG_ENTRYPOINT() ScopedLog __log(__FUNCTION__)
69 #else
70 #define LOG_ENTRYPOINT()
71 #endif
72 
73 // enable stack walker dry run on each entrypoint to discover stack issues early
74 #ifndef NDEBUG
75 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
76 #define CHECK_STACK_WALKER                                         \
77     if (Runtime::GetOptions().IsVerifyEntrypoints()) {             \
78         StackWalker::Create(ManagedThread::GetCurrent()).Verify(); \
79     }
80 #else
81 #define CHECK_STACK_WALKER
82 #endif
83 
84 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
85 #define BEGIN_ENTRYPOINT() \
86     CHECK_STACK_WALKER;    \
87     LOG_ENTRYPOINT();
88 
HandlePendingException(UnwindPolicy policy=UnwindPolicy::ALL)89 static void HandlePendingException(UnwindPolicy policy = UnwindPolicy::ALL)
90 {
91     auto *thread = ManagedThread::GetCurrent();
92     ASSERT(thread->HasPendingException());
93     LOG(DEBUG, INTEROP) << "HandlePendingException";
94 
95     auto stack = StackWalker::Create(thread, policy);
96     ASSERT(stack.IsCFrame());
97 
98     FindCatchBlockInCFrames(thread, &stack, nullptr);
99 }
100 
HasCompiledCode(Method * method)101 extern "C" int HasCompiledCode(Method *method)
102 {
103     return method->HasCompiledCode() ? 1 : 0;
104 }
105 
IncrementHotnessCounter(Method * method)106 extern "C" bool IncrementHotnessCounter(Method *method)
107 {
108     method->IncrementHotnessCounter(0, nullptr);
109     return method->GetCompiledEntryPoint() != GetCompiledCodeToInterpreterBridge(method);
110 }
111 
InterpreterEntryPoint(Method * method,Frame * frame)112 extern "C" NO_ADDRESS_SANITIZE void InterpreterEntryPoint(Method *method, Frame *frame)
113 {
114     auto pc = method->GetInstructions();
115     Method *callee = frame->GetMethod();
116     ASSERT(callee != nullptr);
117 
118     if (callee->IsAbstract()) {
119         ASSERT(pc == nullptr);
120         panda::ThrowAbstractMethodError(callee);
121         HandlePendingException();
122         UNREACHABLE();
123     }
124 
125     ManagedThread *thread = ManagedThread::GetCurrent();
126     if (!thread->template StackOverflowCheck<true, false>()) {
127         HandlePendingException(UnwindPolicy::SKIP_INLINED);
128         UNREACHABLE();
129     }
130 
131     Frame *prev_frame = thread->GetCurrentFrame();
132     thread->SetCurrentFrame(frame);
133 
134     auto is_compiled_code = thread->IsCurrentFrameCompiled();
135     thread->SetCurrentFrameIsCompiled(false);
136     interpreter::Execute(thread, pc, frame);
137     thread->SetCurrentFrameIsCompiled(is_compiled_code);
138     if (prev_frame != nullptr && reinterpret_cast<uintptr_t>(prev_frame->GetMethod()) == COMPILED_CODE_TO_INTERPRETER) {
139         thread->SetCurrentFrame(prev_frame->GetPrevFrame());
140     } else {
141         thread->SetCurrentFrame(prev_frame);
142     }
143 }
144 
AnnotateSanitizersEntrypoint(void const * addr,size_t size)145 extern "C" void AnnotateSanitizersEntrypoint([[maybe_unused]] void const *addr, [[maybe_unused]] size_t size)
146 {
147 #ifdef PANDA_TSAN_ON
148     TSAN_ANNOTATE_HAPPENS_BEFORE(const_cast<void *>(addr));
149 #endif
150 #ifdef PANDA_ASAN_ON
151     __asan_unpoison_memory_region(addr, size);
152 #endif
153 }
154 
WriteTlabStatsEntrypoint(size_t size)155 extern "C" void WriteTlabStatsEntrypoint(size_t size)
156 {
157     LOG_ENTRYPOINT();
158 
159     ASSERT(size <= mem::PANDA_TLAB_SIZE);
160     if (mem::PANDA_TRACK_TLAB_ALLOCATIONS) {
161         auto mem_stats = Thread::GetCurrent()->GetVM()->GetHeapManager()->GetMemStats();
162         if (mem_stats == nullptr) {
163             return;
164         }
165         mem_stats->RecordAllocateObject(size, SpaceType::SPACE_TYPE_OBJECT);
166     }
167 }
168 
GetClassIdEntrypoint(const Method * caller,uint32_t class_id)169 extern "C" size_t GetClassIdEntrypoint(const Method *caller, uint32_t class_id)
170 {
171     BEGIN_ENTRYPOINT();
172     auto resolved_id = caller->GetClass()->ResolveClassIndex(BytecodeId(class_id).AsIndex());
173     return resolved_id.GetOffset();
174 }
175 
CreateArrayByIdEntrypoint(const Method * caller,uint32_t class_id,size_t length)176 extern "C" coretypes::Array *CreateArrayByIdEntrypoint(const Method *caller, uint32_t class_id, size_t length)
177 {
178     BEGIN_ENTRYPOINT();
179     size_t resolved_id = GetClassIdEntrypoint(caller, class_id);
180     auto *klass = reinterpret_cast<Class *>(ResolveClassEntrypoint(caller, resolved_id));
181     return CreateArraySlowPathEntrypoint(klass, length);
182 }
183 
CreateArraySlowPathEntrypoint(Class * klass,size_t length)184 extern "C" coretypes::Array *CreateArraySlowPathEntrypoint(Class *klass, size_t length)
185 {
186     BEGIN_ENTRYPOINT();
187 
188     TSAN_ANNOTATE_HAPPENS_AFTER(klass);
189     auto arr = coretypes::Array::Create(klass, length);
190     if (UNLIKELY(arr == nullptr)) {
191         HandlePendingException();
192         UNREACHABLE();
193     }
194     if (compiler::options.IsCompilerEnableTlabEvents()) {
195         EVENT_SLOWPATH_ALLOC(ManagedThread::GetCurrent()->GetId());
196     }
197     return arr;
198 }
199 
CreateMultiArrayRecEntrypoint(ManagedThread * thread,Class * klass,uint32_t nargs,size_t * sizes,uint32_t num)200 extern "C" coretypes::Array *CreateMultiArrayRecEntrypoint(ManagedThread *thread, Class *klass, uint32_t nargs,
201                                                            size_t *sizes, uint32_t num)
202 {
203     // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic,-warnings-as-errors)
204     auto arr_size = sizes[num];
205 
206     [[maybe_unused]] HandleScope<ObjectHeader *> scope(thread);
207     // SUPPRESS_CSA_NEXTLINE(alpha.core.CheckObjHeaderTypeRef)
208     VMHandle<coretypes::Array> handle(thread, coretypes::Array::Create(klass, arr_size));
209     if (handle.GetPtr() == nullptr) {
210         return nullptr;
211     }
212     auto *component = klass->GetComponentType();
213 
214     if (component->IsArrayClass() && num + 1 < nargs) {
215         for (size_t idx = 0; idx < arr_size; idx++) {
216             auto *array = CreateMultiArrayRecEntrypoint(thread, component, nargs, sizes, num + 1);
217 
218             if (array == nullptr) {
219                 return nullptr;
220             }
221             handle.GetPtr()->template Set<coretypes::Array *>(idx, array);
222         }
223     }
224 
225     return handle.GetPtr();
226 }
227 
ResolveLiteralArrayEntrypoint(const Method * caller,uint32_t type_id)228 extern "C" coretypes::Array *ResolveLiteralArrayEntrypoint(const Method *caller, uint32_t type_id)
229 {
230     BEGIN_ENTRYPOINT();
231 
232     auto arr = Runtime::GetCurrent()->ResolveLiteralArray(ManagedThread::GetCurrent()->GetVM(), *caller, type_id);
233     if (UNLIKELY(arr == nullptr)) {
234         HandlePendingException();
235         UNREACHABLE();
236     }
237     return arr;
238 }
239 
CreateMultiArrayEntrypoint(Class * klass,uint32_t nargs,size_t * sizes)240 extern "C" coretypes::Array *CreateMultiArrayEntrypoint(Class *klass, uint32_t nargs, size_t *sizes)
241 {
242     BEGIN_ENTRYPOINT();
243 
244     auto arr = CreateMultiArrayRecEntrypoint(ManagedThread::GetCurrent(), klass, nargs, sizes, 0);
245     if (UNLIKELY(arr == nullptr)) {
246         HandlePendingException();
247         UNREACHABLE();
248     }
249     return arr;
250 }
251 
CreateObjectByClassInterpreter(ManagedThread * thread,Class * klass)252 extern "C" ObjectHeader *CreateObjectByClassInterpreter(ManagedThread *thread, Class *klass)
253 {
254     if (!klass->IsInitialized()) {
255         auto *class_linker = Runtime::GetCurrent()->GetClassLinker();
256         if (!class_linker->InitializeClass(thread, klass)) {
257             return nullptr;
258         }
259     }
260     return interpreter::RuntimeInterface::CreateObject(klass);
261 }
262 
CreateObjectByIdEntrypoint(ManagedThread * thread,const Method * caller,uint32_t type_id)263 extern "C" ObjectHeader *CreateObjectByIdEntrypoint(ManagedThread *thread, const Method *caller, uint32_t type_id)
264 {
265     BEGIN_ENTRYPOINT();
266     size_t resolved_id = GetClassIdEntrypoint(caller, type_id);
267     auto *klass = reinterpret_cast<Class *>(ResolveClassEntrypoint(caller, resolved_id));
268     return CreateObjectByClassInterpreter(thread, klass);
269 }
270 
DebugPrintEntrypoint(panda::Frame * frame,const uint8_t * pc)271 extern "C" void DebugPrintEntrypoint([[maybe_unused]] panda::Frame *frame, [[maybe_unused]] const uint8_t *pc)
272 {
273     BEGIN_ENTRYPOINT();
274 #ifndef NDEBUG
275     if (!Logger::IsLoggingOn(Logger::Level::DEBUG, Logger::Component::INTERPRETER)) {
276         return;
277     }
278 
279     constexpr uint64_t standardDebugIndent = 5;
280     PandaString acc_dump;
281     if (frame->IsDynamic()) {
282         acc_dump = frame->template GetAccAsVReg<true>().DumpVReg();
283         LOG(DEBUG, INTERPRETER) << PandaString(standardDebugIndent, ' ') << "acc." << acc_dump;
284 
285         DynamicFrameHandler frame_handler(frame);
286         for (size_t i = 0; i < frame->GetSize(); ++i) {
287             LOG(DEBUG, INTERPRETER) << PandaString(standardDebugIndent, ' ') << "v" << i << "."
288                                     << frame_handler.GetVReg(i).DumpVReg();
289         }
290     } else {
291         acc_dump = frame->GetAccAsVReg().DumpVReg();
292         LOG(DEBUG, INTERPRETER) << PandaString(standardDebugIndent, ' ') << "acc." << acc_dump;
293 
294         StaticFrameHandler frame_handler(frame);
295         for (size_t i = 0; i < frame->GetSize(); ++i) {
296             LOG(DEBUG, INTERPRETER) << PandaString(standardDebugIndent, ' ') << "v" << i << "."
297                                     << frame_handler.GetVReg(i).DumpVReg();
298         }
299     }
300     LOG(DEBUG, INTERPRETER) << " pc: " << (void *)pc << " ---> " << BytecodeInstruction(pc);
301 #endif
302 }
303 
CreateObjectByClassEntrypoint(Class * klass)304 extern "C" ObjectHeader *CreateObjectByClassEntrypoint(Class *klass)
305 {
306     BEGIN_ENTRYPOINT();
307 
308     // We need annotation here for the FullMemoryBarrier used in InitializeClassByIdEntrypoint
309     TSAN_ANNOTATE_HAPPENS_AFTER(klass);
310     if (klass->IsStringClass()) {
311         LanguageContext ctx = Runtime::GetCurrent()->GetLanguageContext(*klass);
312         auto str = coretypes::String::CreateEmptyString(ctx, Runtime::GetCurrent()->GetPandaVM());
313         if (UNLIKELY(str == nullptr)) {
314             HandlePendingException();
315             UNREACHABLE();
316         }
317         return str;
318     }
319 
320     if (LIKELY(klass->IsInstantiable())) {
321         auto obj = ObjectHeader::Create(klass);
322         if (UNLIKELY(obj == nullptr)) {
323             HandlePendingException();
324             UNREACHABLE();
325         }
326         if (compiler::options.IsCompilerEnableTlabEvents()) {
327             EVENT_SLOWPATH_ALLOC(ManagedThread::GetCurrent()->GetId());
328         }
329         return obj;
330     }
331 
332     ThrowInstantiationErrorEntrypoint(klass);
333     UNREACHABLE();
334 }
335 
CloneObjectEntrypoint(ObjectHeader * obj)336 extern "C" ObjectHeader *CloneObjectEntrypoint(ObjectHeader *obj)
337 {
338     BEGIN_ENTRYPOINT();
339 
340     uint32_t flags = obj->ClassAddr<Class>()->GetFlags();  // SUPPRESS_CSA(alpha.core.WasteObjHeader)
341     if (UNLIKELY((flags & Class::IS_CLONEABLE) == 0)) {
342         ASSERT(!ManagedThread::GetCurrent()->HasPendingException());
343         ThrowCloneNotSupportedException();
344         HandlePendingException(UnwindPolicy::SKIP_INLINED);
345         return nullptr;
346     }
347     return ObjectHeader::Clone(obj);  // SUPPRESS_CSA(alpha.core.WasteObjHeader)
348 }
349 
PostBarrierWriteEntrypoint(ObjectHeader * obj,size_t size)350 extern "C" ObjectHeader *PostBarrierWriteEntrypoint(ObjectHeader *obj, size_t size)
351 {
352     LOG_ENTRYPOINT();
353     AnnotateSanitizersEntrypoint(obj, size);
354     auto object_class = obj->ClassAddr<Class>();
355     auto *barrier_set = ManagedThread::GetCurrent()->GetBarrierSet();
356     if (object_class->IsArrayClass()) {
357         if (object_class->IsObjectArrayClass()) {
358             barrier_set->PostBarrierArrayWrite(obj, size);
359         }
360     } else {
361         barrier_set->PostBarrierEveryObjectFieldWrite(obj, size);
362     }
363     return obj;
364 }
365 
CheckCastByBCIDEntrypoint(const Method * caller,ObjectHeader * obj,uint32_t type_id)366 extern "C" void CheckCastByBCIDEntrypoint(const Method *caller, ObjectHeader *obj, uint32_t type_id)
367 {
368     BEGIN_ENTRYPOINT();
369     auto thread = ManagedThread::GetCurrent();
370     VMHandle<ObjectHeader> handle_obj(thread, obj);  // SUPPRESS_CSA(alpha.core.WasteObjHeader)
371     size_t resolved_id = GetClassIdEntrypoint(caller, type_id);
372     auto klass = reinterpret_cast<Class *>(ResolveClassEntrypoint(caller, resolved_id));
373 
374     return CheckCastEntrypoint(handle_obj.GetPtr(), klass);
375 }
376 
CheckCastEntrypoint(const ObjectHeader * obj,Class * klass)377 extern "C" void CheckCastEntrypoint(const ObjectHeader *obj, Class *klass)
378 {
379     BEGIN_ENTRYPOINT();
380 
381     // Don't use obj after ClassLinker call because GC can move it.
382     // Since we need only class and class in a non-movalble object
383     // it is ok to get it here.
384     Class *obj_klass = obj == nullptr ? nullptr : obj->ClassAddr<Class>();  // SUPPRESS_CSA(alpha.core.WasteObjHeader)
385     if (UNLIKELY(obj_klass != nullptr && !klass->IsAssignableFrom(obj_klass))) {
386         panda::ThrowClassCastException(klass, obj_klass);
387         HandlePendingException();
388         UNREACHABLE();
389     }
390 }
391 
IsInstanceEntrypoint(ObjectHeader * obj,Class * klass)392 extern "C" uint8_t IsInstanceEntrypoint(ObjectHeader *obj, Class *klass)
393 {
394     BEGIN_ENTRYPOINT();
395 
396     // Don't use obj after ClassLinker call because GC can move it.
397     // Since we need only class and class in a non-movalble object
398     // it is ok to get it here.
399     Class *obj_klass = obj == nullptr ? nullptr : obj->ClassAddr<Class>();  // SUPPRESS_CSA(alpha.core.WasteObjHeader)
400     if (UNLIKELY(obj_klass != nullptr && klass->IsAssignableFrom(obj_klass))) {
401         return 1;
402     }
403     return 0;
404 }
405 
IsInstanceByBCIDEntrypoint(const Method * caller,ObjectHeader * obj,uint32_t type_id)406 extern "C" uint8_t IsInstanceByBCIDEntrypoint(const Method *caller, ObjectHeader *obj, uint32_t type_id)
407 {
408     BEGIN_ENTRYPOINT();
409     auto thread = ManagedThread::GetCurrent();
410     VMHandle<ObjectHeader> handle_obj(thread, obj);  // SUPPRESS_CSA(alpha.core.WasteObjHeader)
411     size_t resolved_id = GetClassIdEntrypoint(caller, type_id);
412     auto klass = reinterpret_cast<Class *>(ResolveClassEntrypoint(caller, resolved_id));
413 
414     return IsInstanceEntrypoint(handle_obj.GetPtr(), klass);
415 }
416 
SafepointEntrypoint()417 extern "C" void SafepointEntrypoint()
418 {
419     BEGIN_ENTRYPOINT();
420     interpreter::RuntimeInterface::Safepoint();
421 }
422 
ResolveClassObjectEntrypoint(const Method * caller,FileEntityId type_id)423 extern "C" void *ResolveClassObjectEntrypoint(const Method *caller, FileEntityId type_id)
424 {
425     BEGIN_ENTRYPOINT();
426     auto klass = reinterpret_cast<Class *>(ResolveClassEntrypoint(caller, type_id));
427     return reinterpret_cast<void *>(klass->GetManagedObject());
428 }
429 
ResolveClassEntrypoint(const Method * caller,FileEntityId type_id)430 extern "C" void *ResolveClassEntrypoint(const Method *caller, FileEntityId type_id)
431 {
432     BEGIN_ENTRYPOINT();
433     ClassLinker *class_linker = Runtime::GetCurrent()->GetClassLinker();
434     Class *klass = class_linker->GetClass(*caller, panda_file::File::EntityId(type_id));
435     if (UNLIKELY(klass == nullptr)) {
436         HandlePendingException();
437         UNREACHABLE();
438     }
439     return reinterpret_cast<void *>(klass);
440 }
441 
GetFieldIdEntrypoint(const Method * caller,uint32_t field_id)442 extern "C" size_t GetFieldIdEntrypoint(const Method *caller, uint32_t field_id)
443 {
444     BEGIN_ENTRYPOINT();
445     auto resolved_id = caller->GetClass()->ResolveFieldIndex(BytecodeId(field_id).AsIndex());
446     return resolved_id.GetOffset();
447 }
448 
ResolveStringEntrypoint(const Method * caller,FileEntityId id)449 extern "C" coretypes::String *ResolveStringEntrypoint(const Method *caller, FileEntityId id)
450 {
451     BEGIN_ENTRYPOINT();
452     return Runtime::GetCurrent()->ResolveStringFromCompiledCode(ManagedThread::GetCurrent()->GetVM(), *caller,
453                                                                 panda_file::File::EntityId(id));
454 }
455 
ResolveStringAotEntrypoint(const Method * caller,FileEntityId id,ObjectHeader ** slot)456 extern "C" coretypes::String *ResolveStringAotEntrypoint(const Method *caller, FileEntityId id, ObjectHeader **slot)
457 {
458     BEGIN_ENTRYPOINT();
459     auto runtime = Runtime::GetCurrent();
460     auto aot_manager = runtime->GetClassLinker()->GetAotManager();
461     auto vm = ManagedThread::GetCurrent()->GetVM();
462     auto str = runtime->ResolveStringFromCompiledCode(vm, *caller, panda::panda_file::File::EntityId(id));
463     if (UNLIKELY(str == nullptr)) {
464         return nullptr;
465     }
466 
467     // to many strings were saved to slots, so simply return the resolved string
468     if (aot_manager->GetAotStringRootsCount() >= Runtime::GetOptions().GetAotStringGcRootsLimit()) {
469         return str;
470     }
471 
472     auto counter = reinterpret_cast<std::atomic_uint32_t *>(slot);
473 
474     // Atomic with acquire order reason: data race with slot with dependecies on reads after the load which should
475     // become visible
476     auto counter_val = counter->load(std::memory_order_acquire);
477     if (counter_val >= compiler::RuntimeInterface::RESOLVE_STRING_AOT_COUNTER_LIMIT - 1) {
478         return str;
479     }
480 
481     if (counter_val < Runtime::GetOptions().GetResolveStringAotThreshold()) {
482         // try to update counter, but ignore result - in the worst case we'll save
483         // string's pointer to slot a bit later
484         counter->compare_exchange_strong(counter_val, counter_val + 1, std::memory_order_release,
485                                          std::memory_order_relaxed);
486     } else {
487         // try to replace the counter with string pointer and register the slot as GC root in case of success
488         if (counter->compare_exchange_strong(counter_val, static_cast<uint32_t>(reinterpret_cast<uint64_t>(str)),
489                                              std::memory_order_release, std::memory_order_relaxed)) {
490             auto allocator = vm->GetHeapManager()->GetObjectAllocator().AsObjectAllocator();
491             bool is_young =
492                 allocator->HasYoungSpace() && allocator->IsAddressInYoungSpace(reinterpret_cast<uintptr_t>(str));
493             aot_manager->RegisterAotStringRoot(slot, is_young);
494             EVENT_AOT_RESOLVE_STRING(ConvertToString(str));
495         }
496     }
497 
498     return str;
499 }
500 
CreateFrameWithSize(uint32_t size,uint32_t nregs,Method * method,Frame * prev)501 extern "C" Frame *CreateFrameWithSize(uint32_t size, uint32_t nregs, Method *method, Frame *prev)
502 {
503     uint32_t ext_sz = EmptyExtFrameDataSize;
504     if (LIKELY(method)) {
505         ext_sz = Runtime::GetCurrent()->GetLanguageContext(*method).GetFrameExtSize();
506     }
507     size_t alloc_sz = Frame::GetAllocSize(size, ext_sz);
508     Frame *frame = Thread::GetCurrent()->GetVM()->GetHeapManager()->AllocateExtFrame(alloc_sz, ext_sz);
509     if (UNLIKELY(frame == nullptr)) {
510         return nullptr;
511     }
512     return new (frame) Frame(Frame::ToExt(frame, ext_sz), method, prev, nregs);
513 }
514 
CreateFrameWithActualArgsAndSize(uint32_t size,uint32_t nregs,uint32_t num_actual_args,Method * method,Frame * prev)515 extern "C" Frame *CreateFrameWithActualArgsAndSize(uint32_t size, uint32_t nregs, uint32_t num_actual_args,
516                                                    Method *method, Frame *prev)
517 {
518     auto *thread = ManagedThread::GetCurrent();
519     uint32_t ext_sz = thread->GetVM()->GetFrameExtSize();
520     size_t alloc_sz = Frame::GetAllocSize(size, ext_sz);
521     void *mem = thread->GetStackFrameAllocator()->Alloc(alloc_sz);
522     if (UNLIKELY(mem == nullptr)) {
523         return nullptr;
524     }
525     return new (Frame::FromExt(mem, ext_sz)) Frame(mem, method, prev, nregs, num_actual_args);
526 }
527 
CreateNativeFrameWithActualArgsAndSize(uint32_t size,uint32_t nregs,uint32_t num_actual_args,Method * method,Frame * prev)528 extern "C" Frame *CreateNativeFrameWithActualArgsAndSize(uint32_t size, uint32_t nregs, uint32_t num_actual_args,
529                                                          Method *method, Frame *prev)
530 {
531     uint32_t ext_sz = EmptyExtFrameDataSize;
532     size_t alloc_sz = Frame::GetAllocSize(size, ext_sz);
533     void *mem = ManagedThread::GetCurrent()->GetStackFrameAllocator()->Alloc(alloc_sz);
534     if (UNLIKELY(mem == nullptr)) {
535         return nullptr;
536     }
537     return new (Frame::FromExt(mem, ext_sz)) Frame(mem, method, prev, nregs, num_actual_args);
538 }
539 
540 template <bool is_dynamic = false>
CreateFrame(uint32_t nregs,Method * method,Frame * prev)541 static Frame *CreateFrame(uint32_t nregs, Method *method, Frame *prev)
542 {
543     return CreateFrameWithSize(Frame::GetActualSize<is_dynamic>(nregs), nregs, method, prev);
544 }
545 
546 template <bool is_dynamic>
CreateFrameWithActualArgs(uint32_t nregs,uint32_t num_actual_args,Method * method,Frame * prev)547 static Frame *CreateFrameWithActualArgs(uint32_t nregs, uint32_t num_actual_args, Method *method, Frame *prev)
548 {
549     return CreateFrameWithActualArgsAndSize(Frame::GetActualSize<is_dynamic>(nregs), nregs, num_actual_args, method,
550                                             prev);
551 }
552 
CreateFrameForMethod(Method * method,Frame * prev)553 extern "C" Frame *CreateFrameForMethod(Method *method, Frame *prev)
554 {
555     auto nregs = method->GetNumArgs() + method->GetNumVregs();
556     return CreateFrame<false>(nregs, method, prev);
557 }
558 
CreateFrameForMethodDyn(Method * method,Frame * prev)559 extern "C" Frame *CreateFrameForMethodDyn(Method *method, Frame *prev)
560 {
561     auto nregs = method->GetNumArgs() + method->GetNumVregs();
562     return CreateFrame<true>(nregs, method, prev);
563 }
564 
CreateFrameForMethodWithActualArgs(uint32_t num_actual_args,Method * method,Frame * prev)565 extern "C" Frame *CreateFrameForMethodWithActualArgs(uint32_t num_actual_args, Method *method, Frame *prev)
566 {
567     auto nargs = std::max(num_actual_args, method->GetNumArgs());
568     auto nregs = nargs + method->GetNumVregs();
569     return CreateFrameWithActualArgs<false>(nregs, num_actual_args, method, prev);
570 }
571 
CreateFrameForMethodWithActualArgsDyn(uint32_t num_actual_args,Method * method,Frame * prev)572 extern "C" Frame *CreateFrameForMethodWithActualArgsDyn(uint32_t num_actual_args, Method *method, Frame *prev)
573 {
574     auto nargs = std::max(num_actual_args, method->GetNumArgs());
575     auto nregs = nargs + method->GetNumVregs();
576     return CreateFrameWithActualArgs<true>(nregs, num_actual_args, method, prev);
577 }
578 
FreeFrame(Frame * frame)579 extern "C" void FreeFrame(Frame *frame)
580 {
581     ASSERT(frame->GetExt() != nullptr);
582     ManagedThread::GetCurrent()->GetStackFrameAllocator()->Free(frame->GetExt());
583 }
584 
GetStaticFieldAddressEntrypoint(Method * method,uint32_t field_id)585 extern "C" uintptr_t GetStaticFieldAddressEntrypoint(Method *method, uint32_t field_id)
586 {
587     BEGIN_ENTRYPOINT();
588     auto *class_linker = Runtime::GetCurrent()->GetClassLinker();
589     auto field = class_linker->GetField(*method, panda_file::File::EntityId(field_id));
590     if (UNLIKELY(field == nullptr)) {
591         HandlePendingException();
592         UNREACHABLE();
593     }
594     auto *klass = field->GetClass();
595     ASSERT(klass != nullptr);
596     return reinterpret_cast<uintptr_t>(klass) + field->GetOffset();
597 }
598 
GetUnknownStaticFieldMemoryAddressEntrypoint(Method * method,uint32_t field_id,size_t * slot)599 extern "C" uintptr_t GetUnknownStaticFieldMemoryAddressEntrypoint(Method *method, uint32_t field_id, size_t *slot)
600 {
601     BEGIN_ENTRYPOINT();
602     auto *class_linker = Runtime::GetCurrent()->GetClassLinker();
603     auto field = class_linker->GetField(*method, panda_file::File::EntityId(field_id));
604     if (UNLIKELY(field == nullptr)) {
605         HandlePendingException();
606         UNREACHABLE();
607     }
608     auto *klass = field->GetClass();
609     ASSERT(klass != nullptr);
610     InitializeClassEntrypoint(klass);
611 
612     uintptr_t addr = reinterpret_cast<uintptr_t>(klass) + field->GetOffset();
613     if (klass->IsInitialized() && slot != nullptr) {
614         *slot = addr;
615     }
616     return addr;
617 }
618 
GetUnknownStaticFieldPtrEntrypoint(Method * method,uint32_t field_id,size_t * slot)619 extern "C" uintptr_t GetUnknownStaticFieldPtrEntrypoint(Method *method, uint32_t field_id, size_t *slot)
620 {
621     BEGIN_ENTRYPOINT();
622     auto *class_linker = Runtime::GetCurrent()->GetClassLinker();
623     auto field = class_linker->GetField(*method, panda_file::File::EntityId(field_id));
624     if (UNLIKELY(field == nullptr)) {
625         HandlePendingException();
626         UNREACHABLE();
627     }
628     auto *klass = field->GetClass();
629     ASSERT(klass != nullptr);
630     InitializeClassEntrypoint(klass);
631 
632     auto addr = reinterpret_cast<uintptr_t>(field);
633     if (klass->IsInitialized() && slot != nullptr) {
634         *slot = addr;
635     }
636     return addr;
637 }
638 
GetFieldOffsetByIdEntrypoint(Method * caller,uint32_t field_id)639 extern "C" size_t GetFieldOffsetByIdEntrypoint(Method *caller, uint32_t field_id)
640 {
641     BEGIN_ENTRYPOINT();
642     size_t resolved_id = GetFieldIdEntrypoint(caller, field_id);
643     return GetFieldOffsetEntrypoint(caller, resolved_id);
644 }
645 
GetStaticFieldAddressByIdEntrypoint(ManagedThread * thread,Method * caller,uint32_t field_id)646 extern "C" uintptr_t GetStaticFieldAddressByIdEntrypoint(ManagedThread *thread, Method *caller, uint32_t field_id)
647 {
648     BEGIN_ENTRYPOINT();
649     auto *field = interpreter::RuntimeInterface::ResolveField(thread, *caller, BytecodeId(field_id));
650     return reinterpret_cast<uintptr_t>(field->GetClass()) + field->GetOffset();
651 }
652 
GetFieldOffsetEntrypoint(Method * method,uint32_t field_id)653 extern "C" size_t GetFieldOffsetEntrypoint(Method *method, uint32_t field_id)
654 {
655     BEGIN_ENTRYPOINT();
656     auto *class_linker = Runtime::GetCurrent()->GetClassLinker();
657     auto field = class_linker->GetField(*method, panda_file::File::EntityId(field_id));
658     if (UNLIKELY(field == nullptr)) {
659         HandlePendingException();
660         UNREACHABLE();
661     }
662     return field->GetOffset();
663 }
664 
InitializeClassEntrypoint(Class * klass)665 extern "C" void InitializeClassEntrypoint(Class *klass)
666 {
667     BEGIN_ENTRYPOINT();
668     auto *class_linker = Runtime::GetCurrent()->GetClassLinker();
669     if (!klass->IsInitialized() && !class_linker->InitializeClass(ManagedThread::GetCurrent(), klass)) {
670         HandlePendingException();
671         UNREACHABLE();
672     }
673 }
674 
InitializeClassByIdEntrypoint(const Method * caller,FileEntityId id)675 extern "C" Class *InitializeClassByIdEntrypoint(const Method *caller, FileEntityId id)
676 {
677     BEGIN_ENTRYPOINT();
678     ClassLinker *class_linker = Runtime::GetCurrent()->GetClassLinker();
679     Class *klass = class_linker->GetClass(*caller, panda_file::File::EntityId(id));
680     if (UNLIKELY(klass == nullptr)) {
681         HandlePendingException();
682         UNREACHABLE();
683     }
684     // Later we store klass pointer into .aot_got section.
685     // Without full memory barrier on the architectures with weak memory order
686     // we can read klass pointer, but fetch klass data before it's set in GetClass and InitializeClass
687     arch::FullMemoryBarrier();
688     // Full barrier is not visible by TSAN so we need annotation here
689     TSAN_ANNOTATE_HAPPENS_BEFORE(klass);
690     InitializeClassEntrypoint(klass);
691     return klass;
692 }
693 
ResolveVirtualCallEntrypoint(const Method * callee,ObjectHeader * obj)694 extern "C" uintptr_t NO_ADDRESS_SANITIZE ResolveVirtualCallEntrypoint(const Method *callee, ObjectHeader *obj)
695 {
696     BEGIN_ENTRYPOINT();
697     if (UNLIKELY(callee == nullptr)) {
698         HandlePendingException();
699         UNREACHABLE();
700     }
701     auto *resolved = obj->ClassAddr<Class>()->ResolveVirtualMethod(callee);  // SUPPRESS_CSA(alpha.core.WasteObjHeader)
702     ASSERT(resolved != nullptr);
703 
704     return reinterpret_cast<uintptr_t>(resolved);
705 }
706 
ResolveVirtualCallAotEntrypoint(const Method * caller,ObjectHeader * obj,size_t callee_id,uintptr_t cache_addr)707 extern "C" uintptr_t NO_ADDRESS_SANITIZE ResolveVirtualCallAotEntrypoint(const Method *caller, ObjectHeader *obj,
708                                                                          size_t callee_id,
709                                                                          [[maybe_unused]] uintptr_t cache_addr)
710 {
711     BEGIN_ENTRYPOINT();
712     // Don't use obj after ClassLinker call because GC can move it.
713     // Since we need only class and class in a non-movalble object
714     // it is ok to get it here.
715     auto *obj_klass = obj->ClassAddr<Class>();  // SUPPRESS_CSA(alpha.core.WasteObjHeader)
716     Method *method = Runtime::GetCurrent()->GetClassLinker()->GetMethod(*caller, panda_file::File::EntityId(callee_id));
717     if (UNLIKELY(method == nullptr)) {
718         HandlePendingException();
719         UNREACHABLE();
720     }
721     auto *resolved = obj_klass->ResolveVirtualMethod(method);
722     ASSERT(resolved != nullptr);
723 
724 #if defined(PANDA_TARGET_ARM64)
725     // In arm64, use interface inlineCache
726     // TODO(liyiming): will support x86_64 in future
727     // issue #7018
728     auto method_head = obj_klass->GetRawFirstMethodAddr();
729     if (cache_addr == 0 || method_head == nullptr) {
730         return reinterpret_cast<uintptr_t>(resolved);
731     }
732 
733     constexpr uint32_t METHOD_COMPRESS = 3;
734     constexpr uint32_t CACHE_OFFSET_32 = 32;
735     constexpr uint32_t CACHE_OFFSET_34 = 34;
736     auto cache = reinterpret_cast<int64_t *>(cache_addr);
737     auto method_resolved = reinterpret_cast<int64_t>(resolved);
738     int64_t method_cache = method_resolved - reinterpret_cast<int64_t>(method_head);
739 
740     int64_t method_cache_judge = method_cache >> CACHE_OFFSET_34;  // NOLINT(hicpp-signed-bitwise)
741     if (method_cache_judge != 0 && method_cache_judge != -1) {
742         return reinterpret_cast<uintptr_t>(resolved);
743     }
744     method_cache = method_cache >> METHOD_COMPRESS;                            // NOLINT(hicpp-signed-bitwise)
745     method_cache = method_cache << CACHE_OFFSET_32;                            // NOLINT(hicpp-signed-bitwise)
746     int64_t save_cache = method_cache | reinterpret_cast<int64_t>(obj_klass);  // NOLINT(hicpp-signed-bitwise)
747     *cache = save_cache;
748 #endif
749     return reinterpret_cast<uintptr_t>(resolved);
750 }
751 
ResolveUnknownVirtualCallEntrypoint(const Method * caller,ObjectHeader * obj,size_t callee_id,size_t * slot)752 extern "C" uintptr_t NO_ADDRESS_SANITIZE ResolveUnknownVirtualCallEntrypoint(const Method *caller, ObjectHeader *obj,
753                                                                              size_t callee_id, size_t *slot)
754 {
755     {
756         auto thread = ManagedThread::GetCurrent();
757         [[maybe_unused]] HandleScope<ObjectHeader *> scope(thread);
758         VMHandle<ObjectHeader> handle_obj(thread, obj);
759 
760         BEGIN_ENTRYPOINT();
761         auto runtime = Runtime::GetCurrent();
762         Method *method = runtime->GetClassLinker()->GetMethod(*caller, panda_file::File::EntityId(callee_id));
763         if (LIKELY(method != nullptr)) {
764             // Cache a method index in vtable
765             if (slot != nullptr && (!method->GetClass()->IsInterface() || method->IsDefaultInterfaceMethod())) {
766                 // We save 'vtable index + 1' because 0 value means uninitialized.
767                 // Codegen must subtract index after loading from the slot.
768                 *slot = method->GetVTableIndex() + 1;
769             }
770 
771             auto *resolved = handle_obj.GetPtr()->ClassAddr<Class>()->ResolveVirtualMethod(method);
772             ASSERT(resolved != nullptr);
773 
774             return reinterpret_cast<uintptr_t>(resolved);
775         }
776     }
777 
778     HandlePendingException();
779     UNREACHABLE();
780 }
781 
CheckStoreArrayReferenceEntrypoint(coretypes::Array * array,ObjectHeader * store_obj)782 extern "C" void CheckStoreArrayReferenceEntrypoint(coretypes::Array *array, ObjectHeader *store_obj)
783 {
784     BEGIN_ENTRYPOINT();
785     ASSERT(array != nullptr);
786     ASSERT(store_obj != nullptr);
787 
788     // SUPPRESS_CSA_NEXTLINE(alpha.core.WasteObjHeader)
789     auto *array_class = array->ClassAddr<Class>();
790     auto *element_class = array_class->GetComponentType();
791     // SUPPRESS_CSA_NEXTLINE(alpha.core.WasteObjHeader)
792     if (UNLIKELY(!store_obj->IsInstanceOf(element_class))) {
793         // SUPPRESS_CSA_NEXTLINE(alpha.core.WasteObjHeader)
794         panda::ThrowArrayStoreException(array_class, store_obj->ClassAddr<Class>());
795         HandlePendingException();
796         UNREACHABLE();
797     }
798 }
799 
GetCalleeMethodEntrypoint(const Method * caller,size_t callee_id)800 extern "C" Method *GetCalleeMethodEntrypoint(const Method *caller, size_t callee_id)
801 {
802     BEGIN_ENTRYPOINT();
803     auto *method = Runtime::GetCurrent()->GetClassLinker()->GetMethod(*caller, panda_file::File::EntityId(callee_id));
804     if (UNLIKELY(method == nullptr)) {
805         HandlePendingException();
806         UNREACHABLE();
807     }
808 
809     return method;
810 }
811 
GetCalleeMethodFromBytecodeId(const Method * caller,size_t callee_id)812 extern "C" Method *GetCalleeMethodFromBytecodeId(const Method *caller, size_t callee_id)
813 {
814     BEGIN_ENTRYPOINT();
815     auto resolved_id = caller->GetClass()->ResolveMethodIndex(panda::BytecodeId(callee_id).AsIndex());
816     auto *method = Runtime::GetCurrent()->GetClassLinker()->GetMethod(*caller, resolved_id);
817     if (UNLIKELY(method == nullptr)) {
818         HandlePendingException();
819         UNREACHABLE();
820     }
821 
822     return method;
823 }
824 
ResolveVirtualMethod(const Method * method,const ObjectHeader * obj)825 extern "C" Method *ResolveVirtualMethod(const Method *method, const ObjectHeader *obj)
826 {
827     BEGIN_ENTRYPOINT();
828     // SUPPRESS_CSA_NEXTLINE(alpha.core.WasteObjHeader)
829     auto *cls = obj->ClassAddr<Class>();
830     ASSERT(cls != nullptr);
831     auto *resolved = cls->ResolveVirtualMethod(method);
832     ASSERT(resolved != nullptr);
833     return resolved;
834 }
835 
GetUnknownCalleeMethodEntrypoint(const Method * caller,size_t callee_id,size_t * slot)836 extern "C" Method *GetUnknownCalleeMethodEntrypoint(const Method *caller, size_t callee_id, size_t *slot)
837 {
838     BEGIN_ENTRYPOINT();
839     auto *method = Runtime::GetCurrent()->GetClassLinker()->GetMethod(*caller, panda_file::File::EntityId(callee_id));
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 
SetExceptionEvent(events::ExceptionType type)855 extern "C" void SetExceptionEvent([[maybe_unused]] events::ExceptionType type)
856 {
857 #ifdef PANDA_EVENTS_ENABLED
858     auto stack = StackWalker::Create(ManagedThread::GetCurrent());
859     EVENT_EXCEPTION(std::string(stack.GetMethod()->GetFullName()), stack.GetBytecodePc(), stack.GetNativePc(), type);
860 #endif
861 }
862 
ThrowExceptionEntrypoint(ObjectHeader * exception)863 extern "C" NO_ADDRESS_SANITIZE void ThrowExceptionEntrypoint(ObjectHeader *exception)
864 {
865     BEGIN_ENTRYPOINT();
866     LOG(DEBUG, INTEROP) << "ThrowExceptionEntrypoint \n";
867     ASSERT(!ManagedThread::GetCurrent()->HasPendingException());
868     if (exception == nullptr) {
869         NullPointerExceptionEntrypoint();
870         UNREACHABLE();
871     }
872     ManagedThread::GetCurrent()->SetException(exception);  // SUPPRESS_CSA(alpha.core.WasteObjHeader)
873 
874     SetExceptionEvent(events::ExceptionType::THROW);
875     HandlePendingException(UnwindPolicy::SKIP_INLINED);
876 }
877 
ThrowNativeExceptionEntrypoint()878 extern "C" NO_ADDRESS_SANITIZE void ThrowNativeExceptionEntrypoint()
879 {
880     BEGIN_ENTRYPOINT();
881     LOG(DEBUG, INTEROP) << "ThrowNativeExceptionEntrypoint \n";
882     SetExceptionEvent(events::ExceptionType::NATIVE);
883     HandlePendingException(UnwindPolicy::SKIP_INLINED);
884 }
885 
ArrayIndexOutOfBoundsExceptionEntrypoint(ssize_t idx,size_t length)886 extern "C" NO_ADDRESS_SANITIZE void ArrayIndexOutOfBoundsExceptionEntrypoint([[maybe_unused]] ssize_t idx,
887                                                                              [[maybe_unused]] size_t length)
888 {
889     BEGIN_ENTRYPOINT();
890     LOG(DEBUG, INTEROP) << "ArrayIndexOutOfBoundsExceptionEntrypoint \n";
891     ASSERT(!ManagedThread::GetCurrent()->HasPendingException());
892     ThrowArrayIndexOutOfBoundsException(idx, length);
893     SetExceptionEvent(events::ExceptionType::BOUND_CHECK);
894     HandlePendingException(UnwindPolicy::SKIP_INLINED);
895 }
896 
StringIndexOutOfBoundsExceptionEntrypoint(ssize_t idx,size_t length)897 extern "C" NO_ADDRESS_SANITIZE void StringIndexOutOfBoundsExceptionEntrypoint([[maybe_unused]] ssize_t idx,
898                                                                               [[maybe_unused]] size_t length)
899 {
900     BEGIN_ENTRYPOINT();
901     LOG(DEBUG, INTEROP) << "StringIndexOutOfBoundsExceptionEntrypoint \n";
902     ASSERT(!ManagedThread::GetCurrent()->HasPendingException());
903     ThrowStringIndexOutOfBoundsException(idx, length);
904     SetExceptionEvent(events::ExceptionType::BOUND_CHECK);
905     HandlePendingException(UnwindPolicy::SKIP_INLINED);
906 }
907 
NullPointerExceptionEntrypoint()908 extern "C" NO_ADDRESS_SANITIZE void NullPointerExceptionEntrypoint()
909 {
910     BEGIN_ENTRYPOINT();
911     LOG(DEBUG, INTEROP) << "NullPointerExceptionEntrypoint \n";
912     ASSERT(!ManagedThread::GetCurrent()->HasPendingException());
913     ThrowNullPointerException();
914     SetExceptionEvent(events::ExceptionType::NULL_CHECK);
915     HandlePendingException(UnwindPolicy::SKIP_INLINED);
916 }
917 
AbstractMethodErrorEntrypoint(Method * method)918 extern "C" NO_ADDRESS_SANITIZE void AbstractMethodErrorEntrypoint(Method *method)
919 {
920     BEGIN_ENTRYPOINT();
921     LOG(DEBUG, INTEROP) << "AbstractMethodErrorEntrypoint \n";
922     ManagedThread *thread = ManagedThread::GetCurrent();
923     ASSERT(!thread->HasPendingException());
924     auto stack = StackWalker::Create(thread, UnwindPolicy::SKIP_INLINED);
925     ThrowAbstractMethodError(method);
926     ASSERT(thread->HasPendingException());
927     SetExceptionEvent(events::ExceptionType::ABSTRACT_METHOD);
928     if (stack.IsCFrame()) {
929         FindCatchBlockInCFrames(thread, &stack, nullptr);
930     }
931 }
932 
ArithmeticExceptionEntrypoint()933 extern "C" NO_ADDRESS_SANITIZE void ArithmeticExceptionEntrypoint()
934 {
935     BEGIN_ENTRYPOINT();
936     LOG(DEBUG, INTEROP) << "ArithmeticExceptionEntrypoint \n";
937     ASSERT(!ManagedThread::GetCurrent()->HasPendingException());
938     ThrowArithmeticException();
939     SetExceptionEvent(events::ExceptionType::ARITHMETIC);
940     HandlePendingException(UnwindPolicy::SKIP_INLINED);
941 }
942 
NegativeArraySizeExceptionEntrypoint(ssize_t size)943 extern "C" NO_ADDRESS_SANITIZE void NegativeArraySizeExceptionEntrypoint(ssize_t size)
944 {
945     BEGIN_ENTRYPOINT();
946     LOG(DEBUG, INTEROP) << "NegativeArraySizeExceptionEntrypoint \n";
947     ASSERT(!ManagedThread::GetCurrent()->HasPendingException());
948     ThrowNegativeArraySizeException(size);
949     SetExceptionEvent(events::ExceptionType::NEGATIVE_SIZE);
950     HandlePendingException(UnwindPolicy::SKIP_INLINED);
951 }
952 
ClassCastExceptionEntrypoint(Class * inst_class,ObjectHeader * src_obj)953 extern "C" NO_ADDRESS_SANITIZE void ClassCastExceptionEntrypoint(Class *inst_class, ObjectHeader *src_obj)
954 {
955     BEGIN_ENTRYPOINT();
956     LOG(DEBUG, INTEROP) << "ClassCastExceptionEntrypoint \n";
957     ASSERT(!ManagedThread::GetCurrent()->HasPendingException());
958     ASSERT(src_obj != nullptr);
959     ThrowClassCastException(inst_class, src_obj->ClassAddr<Class>());  // SUPPRESS_CSA(alpha.core.WasteObjHeader)
960     SetExceptionEvent(events::ExceptionType::CAST_CHECK);
961     HandlePendingException(UnwindPolicy::SKIP_INLINED);
962 }
963 
StackOverflowExceptionEntrypoint()964 extern "C" NO_ADDRESS_SANITIZE void StackOverflowExceptionEntrypoint()
965 {
966     // WARNING: We should not add any heavy code constructions here, like events or other debug/testing stuff,
967     // because we have small stack here, see ManagedThread::STACK_OVERFLOW_RESERVED_SIZE.
968     auto thread = ManagedThread::GetCurrent();
969 
970     ASSERT(!thread->HasPendingException());
971     thread->DisableStackOverflowCheck();
972     ThrowStackOverflowException(thread);
973     thread->EnableStackOverflowCheck();
974     HandlePendingException(UnwindPolicy::SKIP_INLINED);
975 }
976 
DeoptimizeEntrypoint(uint8_t deoptimize_type)977 extern "C" NO_ADDRESS_SANITIZE void DeoptimizeEntrypoint(uint8_t deoptimize_type)
978 {
979     BEGIN_ENTRYPOINT();
980     auto type = static_cast<panda::compiler::DeoptimizeType>(deoptimize_type);
981     LOG(DEBUG, INTEROP) << "DeoptimizeEntrypoint (reason: " << panda::compiler::DeoptimizeTypeToString(type) << ")\n";
982     ASSERT(!ManagedThread::GetCurrent()->HasPendingException());
983     bool destroy = (type == panda::compiler::DeoptimizeType::INLINE_IC);
984     auto stack = StackWalker::Create(ManagedThread::GetCurrent());
985     Deoptimize(&stack, nullptr, false, destroy);
986 }
987 
ThrowInstantiationErrorEntrypoint(Class * klass)988 extern "C" NO_ADDRESS_SANITIZE void ThrowInstantiationErrorEntrypoint(Class *klass)
989 {
990     BEGIN_ENTRYPOINT();
991     LOG(DEBUG, INTEROP) << "ThrowInstantiationErrorEntrypoint \n";
992     ASSERT(!ManagedThread::GetCurrent()->HasPendingException());
993     const auto &name = klass->GetName();
994     PandaString pname(name.cbegin(), name.cend());
995     ThrowInstantiationError(pname);
996     SetExceptionEvent(events::ExceptionType::INSTANTIATION_ERROR);
997     HandlePendingException(UnwindPolicy::SKIP_INLINED);
998 }
999 
GetInitialTaggedValue(Method * method)1000 extern "C" DecodedTaggedValue GetInitialTaggedValue(Method *method)
1001 {
1002     BEGIN_ENTRYPOINT();
1003     return Runtime::GetCurrent()->GetLanguageContext(*method).GetInitialDecodedValue();
1004 }
1005 
LockObjectEntrypoint(ObjectHeader * obj)1006 extern "C" void LockObjectEntrypoint(ObjectHeader *obj)
1007 {
1008     BEGIN_ENTRYPOINT();
1009     panda::intrinsics::ObjectMonitorEnter(obj);  // SUPPRESS_CSA(alpha.core.WasteObjHeader)
1010 }
1011 
LockObjectSlowPathEntrypoint(ObjectHeader * obj)1012 extern "C" void LockObjectSlowPathEntrypoint(ObjectHeader *obj)
1013 {
1014     BEGIN_ENTRYPOINT();
1015     panda::intrinsics::ObjectMonitorEnter(obj);  // SUPPRESS_CSA(alpha.core.WasteObjHeader)
1016     if (!ManagedThread::GetCurrent()->HasPendingException()) {
1017         return;
1018     }
1019     LOG(DEBUG, INTEROP) << "ThrowNativeExceptionEntrypoint after LockObject \n";
1020     SetExceptionEvent(events::ExceptionType::NATIVE);
1021     HandlePendingException(UnwindPolicy::SKIP_INLINED);
1022 }
1023 
UnlockObjectEntrypoint(ObjectHeader * obj)1024 extern "C" void UnlockObjectEntrypoint(ObjectHeader *obj)
1025 {
1026     BEGIN_ENTRYPOINT();
1027     panda::intrinsics::ObjectMonitorExit(obj);  // SUPPRESS_CSA(alpha.core.WasteObjHeader)
1028 }
1029 
UnlockObjectSlowPathEntrypoint(ObjectHeader * obj)1030 extern "C" void UnlockObjectSlowPathEntrypoint(ObjectHeader *obj)
1031 {
1032     BEGIN_ENTRYPOINT();
1033     panda::intrinsics::ObjectMonitorExit(obj);  // SUPPRESS_CSA(alpha.core.WasteObjHeader)
1034     if (!ManagedThread::GetCurrent()->HasPendingException()) {
1035         return;
1036     }
1037     LOG(DEBUG, INTEROP) << "ThrowNativeExceptionEntrypoint after UnlockObject \n";
1038     SetExceptionEvent(events::ExceptionType::NATIVE);
1039     HandlePendingException(UnwindPolicy::SKIP_INLINED);
1040 }
1041 
IncompatibleClassChangeErrorForMethodConflictEntrypoint(Method * method)1042 extern "C" NO_ADDRESS_SANITIZE void IncompatibleClassChangeErrorForMethodConflictEntrypoint(Method *method)
1043 {
1044     BEGIN_ENTRYPOINT();
1045     LOG(DEBUG, INTEROP) << "IncompatibleClassChangeErrorForMethodConflictEntrypoint \n";
1046     ManagedThread *thread = ManagedThread::GetCurrent();
1047     ASSERT(!thread->HasPendingException());
1048     auto stack = StackWalker::Create(thread, UnwindPolicy::SKIP_INLINED);
1049     ThrowIncompatibleClassChangeErrorForMethodConflict(method);
1050     ASSERT(thread->HasPendingException());
1051     SetExceptionEvent(events::ExceptionType::ICCE_METHOD_CONFLICT);
1052     if (stack.IsCFrame()) {
1053         FindCatchBlockInCFrames(thread, &stack, nullptr);
1054     }
1055 }
1056 
GetInstructionsByMethod(const Method * method)1057 extern "C" const uint8_t *GetInstructionsByMethod(const Method *method)
1058 {
1059     BEGIN_ENTRYPOINT();
1060     return method->GetInstructions();
1061 }
1062 
GetNumVregsByMethod(const Method * method)1063 extern "C" size_t GetNumVregsByMethod(const Method *method)
1064 {
1065     BEGIN_ENTRYPOINT();
1066     return method->GetNumVregs();
1067 }
1068 
GetNumArgsByMethod(const Method * method)1069 extern "C" size_t GetNumArgsByMethod(const Method *method)
1070 {
1071     BEGIN_ENTRYPOINT();
1072     return method->GetNumArgs();
1073 }
1074 
1075 // NOLINTNEXTLINE(cppcoreguidelines-pro-type-vararg)
TraceEntrypoint(size_t pid,...)1076 extern "C" void TraceEntrypoint(size_t pid, ...)
1077 {
1078     LOG_ENTRYPOINT();
1079     auto id = static_cast<TraceId>(pid);
1080 
1081     va_list args;
1082     // NOLINTNEXTLINE(cppcoreguidelines-pro-type-vararg)
1083     va_start(args, pid);
1084     switch (id) {
1085         case TraceId::METHOD_ENTER: {
1086             // NOLINTNEXTLINE(cppcoreguidelines-pro-type-vararg)
1087             [[maybe_unused]] auto method = va_arg(args, const Method *);
1088             // NOLINTNEXTLINE(cppcoreguidelines-pro-type-vararg)
1089             [[maybe_unused]] auto kind = va_arg(args, events::MethodEnterKind);
1090             EVENT_METHOD_ENTER(method->GetFullName(), kind, ManagedThread::GetCurrent()->RecordMethodEnter());
1091             break;
1092         }
1093         case TraceId::METHOD_EXIT: {
1094             // NOLINTNEXTLINE(cppcoreguidelines-pro-type-vararg)
1095             [[maybe_unused]] auto method = va_arg(args, const Method *);
1096             // NOLINTNEXTLINE(cppcoreguidelines-pro-type-vararg)
1097             [[maybe_unused]] auto kind = va_arg(args, events::MethodExitKind);
1098             EVENT_METHOD_EXIT(method->GetFullName(), kind, ManagedThread::GetCurrent()->RecordMethodExit());
1099             break;
1100         }
1101         case TraceId::PRINT_ARG: {
1102             // NOLINTNEXTLINE(cppcoreguidelines-pro-type-vararg)
1103             size_t args_num = va_arg(args, size_t);
1104             std::cerr << "[TRACE ARGS] ";
1105             for (size_t i = 0; i < args_num; i++) {
1106                 // NOLINTNEXTLINE(cppcoreguidelines-pro-type-vararg)
1107                 std::cerr << i << "=" << va_arg(args, void *) << " ";
1108             }
1109             std::cerr << std::endl;
1110 
1111             break;
1112         }
1113         case TraceId::TLAB_EVENT: {
1114             // NOLINTNEXTLINE(cppcoreguidelines-pro-type-vararg)
1115             [[maybe_unused]] auto inst = va_arg(args, size_t);
1116             // NOLINTNEXTLINE(cppcoreguidelines-pro-type-vararg)
1117             [[maybe_unused]] PandaString inst_name = (inst == 0) ? "NewArray" : "NewObject";
1118             // NOLINTNEXTLINE(cppcoreguidelines-pro-type-vararg)
1119             [[maybe_unused]] auto memory = va_arg(args, size_t);
1120             // NOLINTNEXTLINE(cppcoreguidelines-pro-type-vararg)
1121             [[maybe_unused]] auto size = va_arg(args, size_t);
1122             [[maybe_unused]] auto tlab = reinterpret_cast<size_t>(ManagedThread::GetCurrent()->GetTLAB());
1123             // 1. Pointer to TLAB
1124             // 2. Instruction name
1125             // 3. Pointer to allocated memory
1126             // 4. size
1127             EVENT_TLAB_ALLOC(ManagedThread::GetCurrent()->GetId(), tlab, inst_name, memory, size);
1128             break;
1129         }
1130         default: {
1131             break;
1132         }
1133     }
1134     // NOLINTNEXTLINE(cppcoreguidelines-pro-type-vararg)
1135     va_end(args);
1136 }
1137 
LogEntrypoint(const char * fmt,...)1138 extern "C" void LogEntrypoint(const char *fmt, ...)
1139 {
1140     va_list args;
1141     // NOLINTNEXTLINE(cppcoreguidelines-pro-type-vararg)
1142     va_start(args, fmt);
1143     vfprintf(stderr, fmt, args);
1144     // NOLINTNEXTLINE(cppcoreguidelines-pro-type-vararg)
1145     va_end(args);
1146 }
1147 
1148 }  // namespace panda
1149