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