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