• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /**
2  * Copyright (c) 2021-2024 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  * http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #include "runtime/compiler.h"
17 
18 #include "intrinsics.h"
19 #include "libpandafile/bytecode_instruction.h"
20 #include "libpandafile/type_helper.h"
21 #include "runtime/cha.h"
22 #include "runtime/jit/profiling_data.h"
23 #include "runtime/include/class_linker-inl.h"
24 #include "runtime/include/exceptions.h"
25 #include "runtime/include/field.h"
26 #include "runtime/include/runtime.h"
27 #include "runtime/include/thread.h"
28 #include "runtime/include/coretypes/native_pointer.h"
29 #include "runtime/mem/heap_manager.h"
30 #include "compiler/inplace_task_runner.h"
31 #include "compiler/background_task_runner.h"
32 
33 namespace ark {
34 
35 #ifdef PANDA_COMPILER_DEBUG_INFO
36 namespace compiler {
37 void CleanJitDebugCode();
38 }  // namespace compiler
39 #endif
40 
41 #include <get_intrinsics.inl>
42 
43 class ErrorHandler : public ClassLinkerErrorHandler {
OnError(ClassLinker::Error error,const PandaString & message)44     void OnError([[maybe_unused]] ClassLinker::Error error, [[maybe_unused]] const PandaString &message) override {}
45 };
46 
IsCompilationExpired(Method * method,bool isOsr)47 bool Compiler::IsCompilationExpired(Method *method, bool isOsr)
48 {
49     return (isOsr && GetOsrCode(method) != nullptr) || (!isOsr && method->HasCompiledCode());
50 }
51 
52 /// Intrinsics fast paths are supported only for G1 GC.
IsGcValidForFastPath(SourceLanguage lang) const53 bool PandaRuntimeInterface::IsGcValidForFastPath(SourceLanguage lang) const
54 {
55     auto runtime = Runtime::GetCurrent();
56     if (lang == SourceLanguage::INVALID) {
57         lang = ManagedThread::GetCurrent()->GetThreadLang();
58     }
59     auto gcType = runtime->GetGCType(runtime->GetOptions(), lang);
60     return gcType == mem::GCType::G1_GC;
61 }
62 
ResolveMethodIndex(MethodPtr parentMethod,MethodIndex index) const63 compiler::RuntimeInterface::MethodId PandaRuntimeInterface::ResolveMethodIndex(MethodPtr parentMethod,
64                                                                                MethodIndex index) const
65 {
66     return MethodCast(parentMethod)->GetClass()->ResolveMethodIndex(index).GetOffset();
67 }
68 
ResolveFieldIndex(MethodPtr parentMethod,FieldIndex index) const69 compiler::RuntimeInterface::FieldId PandaRuntimeInterface::ResolveFieldIndex(MethodPtr parentMethod,
70                                                                              FieldIndex index) const
71 {
72     return MethodCast(parentMethod)->GetClass()->ResolveFieldIndex(index).GetOffset();
73 }
74 
ResolveTypeIndex(MethodPtr parentMethod,TypeIndex index) const75 compiler::RuntimeInterface::IdType PandaRuntimeInterface::ResolveTypeIndex(MethodPtr parentMethod,
76                                                                            TypeIndex index) const
77 {
78     return MethodCast(parentMethod)->GetClass()->ResolveClassIndex(index).GetOffset();
79 }
80 
GetMethodById(MethodPtr parentMethod,MethodId id) const81 compiler::RuntimeInterface::MethodPtr PandaRuntimeInterface::GetMethodById(MethodPtr parentMethod, MethodId id) const
82 {
83     ScopedMutatorLock lock;
84     ErrorHandler errorHandler;
85     return Runtime::GetCurrent()->GetClassLinker()->GetMethod(*MethodCast(parentMethod), panda_file::File::EntityId(id),
86                                                               &errorHandler);
87 }
88 
GetMethodId(MethodPtr method) const89 compiler::RuntimeInterface::MethodId PandaRuntimeInterface::GetMethodId(MethodPtr method) const
90 {
91     return MethodCast(method)->GetFileId().GetOffset();
92 }
93 
GetIntrinsicId(MethodPtr method) const94 compiler::RuntimeInterface::IntrinsicId PandaRuntimeInterface::GetIntrinsicId(MethodPtr method) const
95 {
96     return GetIntrinsicEntryPointId(MethodCast(method)->GetIntrinsic());
97 }
98 
GetUniqMethodId(MethodPtr method) const99 uint64_t PandaRuntimeInterface::GetUniqMethodId(MethodPtr method) const
100 {
101     return MethodCast(method)->GetUniqId();
102 }
103 
ResolveVirtualMethod(ClassPtr cls,MethodPtr method) const104 compiler::RuntimeInterface::MethodPtr PandaRuntimeInterface::ResolveVirtualMethod(ClassPtr cls, MethodPtr method) const
105 {
106     ScopedMutatorLock lock;
107     ASSERT(method != nullptr);
108     return ClassCast(cls)->ResolveVirtualMethod(MethodCast(method));
109 }
110 
ResolveInterfaceMethod(ClassPtr cls,MethodPtr method) const111 compiler::RuntimeInterface::MethodPtr PandaRuntimeInterface::ResolveInterfaceMethod(ClassPtr cls,
112                                                                                     MethodPtr method) const
113 {
114     ScopedMutatorLock lock;
115     ASSERT(method != nullptr);
116     return ClassCast(cls)->ResolveVirtualMethod(MethodCast(method));
117 }
118 
GetMethodReturnTypeId(MethodPtr method) const119 compiler::RuntimeInterface::IdType PandaRuntimeInterface::GetMethodReturnTypeId(MethodPtr method) const
120 {
121     auto *pf = MethodCast(method)->GetPandaFile();
122     panda_file::ProtoDataAccessor pda(*pf,
123                                       panda_file::MethodDataAccessor::GetProtoId(*pf, MethodCast(method)->GetFileId()));
124     return pda.GetReferenceType(0).GetOffset();
125 }
126 
GetMethodArgReferenceTypeId(MethodPtr method,uint16_t num) const127 compiler::RuntimeInterface::IdType PandaRuntimeInterface::GetMethodArgReferenceTypeId(MethodPtr method,
128                                                                                       uint16_t num) const
129 {
130     auto *pf = MethodCast(method)->GetPandaFile();
131     panda_file::ProtoDataAccessor pda(*pf,
132                                       panda_file::MethodDataAccessor::GetProtoId(*pf, MethodCast(method)->GetFileId()));
133     return pda.GetReferenceType(num).GetOffset();
134 }
135 
GetClass(MethodPtr method,IdType id) const136 compiler::RuntimeInterface::ClassPtr PandaRuntimeInterface::GetClass(MethodPtr method, IdType id) const
137 {
138     ScopedMutatorLock lock;
139     auto *caller = MethodCast(method);
140     LanguageContext ctx = Runtime::GetCurrent()->GetLanguageContext(*caller);
141     ErrorHandler handler;
142     return Runtime::GetCurrent()->GetClassLinker()->GetExtension(ctx)->GetClass(
143         *caller->GetPandaFile(), panda_file::File::EntityId(id), caller->GetClass()->GetLoadContext(), &handler);
144 }
145 
GetStringClass(MethodPtr method) const146 compiler::RuntimeInterface::ClassPtr PandaRuntimeInterface::GetStringClass(MethodPtr method) const
147 {
148     ScopedMutatorLock lock;
149     auto *caller = MethodCast(method);
150     LanguageContext ctx = Runtime::GetCurrent()->GetLanguageContext(*caller);
151     return Runtime::GetCurrent()->GetClassLinker()->GetExtension(ctx)->GetClassRoot(ClassRoot::STRING);
152 }
153 
GetArrayU16Class(MethodPtr method) const154 compiler::RuntimeInterface::ClassPtr PandaRuntimeInterface::GetArrayU16Class(MethodPtr method) const
155 {
156     ScopedMutatorLock lock;
157     auto *caller = MethodCast(method);
158     LanguageContext ctx = Runtime::GetCurrent()->GetLanguageContext(*caller);
159     return Runtime::GetCurrent()->GetClassLinker()->GetExtension(ctx)->GetClassRoot(ClassRoot::ARRAY_U16);
160 }
161 
GetClassType(ClassPtr klassPtr) const162 compiler::ClassType PandaRuntimeInterface::GetClassType(ClassPtr klassPtr) const
163 {
164     if (klassPtr == nullptr) {
165         return compiler::ClassType::UNRESOLVED_CLASS;
166     }
167     auto klass = ClassCast(klassPtr);
168     if (klass == nullptr) {
169         return compiler::ClassType::UNRESOLVED_CLASS;
170     }
171     if (klass->IsObjectClass()) {
172         return compiler::ClassType::OBJECT_CLASS;
173     }
174     if (klass->IsInterface()) {
175         return compiler::ClassType::INTERFACE_CLASS;
176     }
177     if (klass->IsArrayClass()) {
178         auto componentClass = klass->GetComponentType();
179         ASSERT(componentClass != nullptr);
180         if (componentClass->IsObjectClass()) {
181             return compiler::ClassType::ARRAY_OBJECT_CLASS;
182         }
183         if (componentClass->IsPrimitive()) {
184             return compiler::ClassType::FINAL_CLASS;
185         }
186         return compiler::ClassType::ARRAY_CLASS;
187     }
188     if (klass->IsFinal()) {
189         return compiler::ClassType::FINAL_CLASS;
190     }
191     return compiler::ClassType::OTHER_CLASS;
192 }
193 
GetClassType(MethodPtr method,IdType id) const194 compiler::ClassType PandaRuntimeInterface::GetClassType(MethodPtr method, IdType id) const
195 {
196     if (method == nullptr) {
197         return compiler::ClassType::UNRESOLVED_CLASS;
198     }
199     ScopedMutatorLock lock;
200     auto *caller = MethodCast(method);
201     LanguageContext ctx = Runtime::GetCurrent()->GetLanguageContext(*caller);
202     ErrorHandler handler;
203     auto klass = Runtime::GetCurrent()->GetClassLinker()->GetExtension(ctx)->GetClass(
204         *caller->GetPandaFile(), panda_file::File::EntityId(id), caller->GetClass()->GetLoadContext(), &handler);
205     if (klass == nullptr) {
206         return compiler::ClassType::UNRESOLVED_CLASS;
207     }
208     if (klass->IsObjectClass()) {
209         return compiler::ClassType::OBJECT_CLASS;
210     }
211     if (klass->IsInterface()) {
212         return compiler::ClassType::INTERFACE_CLASS;
213     }
214     if (klass->IsArrayClass()) {
215         auto componentClass = klass->GetComponentType();
216         ASSERT(componentClass != nullptr);
217         if (componentClass->IsObjectClass()) {
218             return compiler::ClassType::ARRAY_OBJECT_CLASS;
219         }
220         if (componentClass->IsPrimitive()) {
221             return compiler::ClassType::FINAL_CLASS;
222         }
223         return compiler::ClassType::ARRAY_CLASS;
224     }
225     if (klass->IsFinal()) {
226         return compiler::ClassType::FINAL_CLASS;
227     }
228     return compiler::ClassType::OTHER_CLASS;
229 }
230 
IsArrayClass(MethodPtr method,IdType id) const231 bool PandaRuntimeInterface::IsArrayClass(MethodPtr method, IdType id) const
232 {
233     panda_file::File::EntityId cid(id);
234     auto *pf = MethodCast(method)->GetPandaFile();
235     return ClassHelper::IsArrayDescriptor(pf->GetStringData(cid).data);
236 }
237 
IsStringClass(MethodPtr method,IdType id) const238 bool PandaRuntimeInterface::IsStringClass(MethodPtr method, IdType id) const
239 {
240     auto cls = GetClass(method, id);
241     if (cls == nullptr) {
242         return false;
243     }
244     return ClassCast(cls)->IsStringClass();
245 }
246 
GetArrayElementClass(ClassPtr cls) const247 compiler::RuntimeInterface::ClassPtr PandaRuntimeInterface::GetArrayElementClass(ClassPtr cls) const
248 {
249     ScopedMutatorLock lock;
250     ASSERT(ClassCast(cls)->IsArrayClass());
251     return ClassCast(cls)->GetComponentType();
252 }
253 
CheckStoreArray(ClassPtr arrayCls,ClassPtr strCls) const254 bool PandaRuntimeInterface::CheckStoreArray(ClassPtr arrayCls, ClassPtr strCls) const
255 {
256     ASSERT(arrayCls != nullptr);
257     auto *elementClass = ClassCast(arrayCls)->GetComponentType();
258     if (strCls == nullptr) {
259         return elementClass->IsObjectClass();
260     }
261     ASSERT(strCls != nullptr);
262     return elementClass->IsAssignableFrom(ClassCast(strCls));
263 }
264 
IsAssignableFrom(ClassPtr cls1,ClassPtr cls2) const265 bool PandaRuntimeInterface::IsAssignableFrom(ClassPtr cls1, ClassPtr cls2) const
266 {
267     ASSERT(cls1 != nullptr);
268     ASSERT(cls2 != nullptr);
269     return ClassCast(cls1)->IsAssignableFrom(ClassCast(cls2));
270 }
271 
IsInterfaceMethod(MethodPtr parentMethod,MethodId id) const272 bool PandaRuntimeInterface::IsInterfaceMethod(MethodPtr parentMethod, MethodId id) const
273 {
274     ScopedMutatorLock lock;
275     ErrorHandler handler;
276     auto method = Runtime::GetCurrent()->GetClassLinker()->GetMethod(*MethodCast(parentMethod),
277                                                                      panda_file::File::EntityId(id), &handler);
278     return (method->GetClass()->IsInterface() && !method->IsDefaultInterfaceMethod());
279 }
280 
CanThrowException(MethodPtr method) const281 bool PandaRuntimeInterface::CanThrowException(MethodPtr method) const
282 {
283     ScopedMutatorLock lock;
284     auto *pandaMethod = MethodCast(method);
285     LanguageContext ctx = Runtime::GetCurrent()->GetLanguageContext(*pandaMethod);
286     return Runtime::GetCurrent()->GetClassLinker()->GetExtension(ctx)->CanThrowException(pandaMethod);
287 }
288 
FindCatchBlock(MethodPtr m,ClassPtr cls,uint32_t pc) const289 uint32_t PandaRuntimeInterface::FindCatchBlock(MethodPtr m, ClassPtr cls, uint32_t pc) const
290 {
291     ScopedMutatorLock lock;
292     return MethodCast(m)->FindCatchBlockInPandaFile(ClassCast(cls), pc);
293 }
294 
IsInterfaceMethod(MethodPtr method) const295 bool PandaRuntimeInterface::IsInterfaceMethod(MethodPtr method) const
296 {
297     ScopedMutatorLock lock;
298     return (MethodCast(method)->GetClass()->IsInterface() && !MethodCast(method)->IsDefaultInterfaceMethod());
299 }
300 
HasNativeException(MethodPtr method) const301 bool PandaRuntimeInterface::HasNativeException(MethodPtr method) const
302 {
303     if (!MethodCast(method)->IsNative()) {
304         return false;
305     }
306     return CanThrowException(method);
307 }
308 
IsMethodExternal(MethodPtr parentMethod,MethodPtr calleeMethod) const309 bool PandaRuntimeInterface::IsMethodExternal(MethodPtr parentMethod, MethodPtr calleeMethod) const
310 {
311     if (calleeMethod == nullptr) {
312         return true;
313     }
314     return MethodCast(parentMethod)->GetPandaFile() != MethodCast(calleeMethod)->GetPandaFile();
315 }
316 
GetMethodReturnType(MethodPtr parentMethod,MethodId id) const317 compiler::DataType::Type PandaRuntimeInterface::GetMethodReturnType(MethodPtr parentMethod, MethodId id) const
318 {
319     auto *pf = MethodCast(parentMethod)->GetPandaFile();
320     panda_file::MethodDataAccessor mda(*pf, panda_file::File::EntityId(id));
321     panda_file::ProtoDataAccessor pda(*pf, mda.GetProtoId());
322     return ToCompilerType(panda_file::GetEffectiveType(pda.GetReturnType()));
323 }
324 
GetMethodArgumentType(MethodPtr parentMethod,MethodId id,size_t index) const325 compiler::DataType::Type PandaRuntimeInterface::GetMethodArgumentType(MethodPtr parentMethod, MethodId id,
326                                                                       size_t index) const
327 {
328     auto *pf = MethodCast(parentMethod)->GetPandaFile();
329     panda_file::MethodDataAccessor mda(*pf, panda_file::File::EntityId(id));
330     panda_file::ProtoDataAccessor pda(*pf, mda.GetProtoId());
331     return ToCompilerType(panda_file::GetEffectiveType(pda.GetArgType(index)));
332 }
333 
GetMethodArgumentsCount(MethodPtr parentMethod,MethodId id) const334 size_t PandaRuntimeInterface::GetMethodArgumentsCount(MethodPtr parentMethod, MethodId id) const
335 {
336     auto *pf = MethodCast(parentMethod)->GetPandaFile();
337     panda_file::MethodDataAccessor mda(*pf, panda_file::File::EntityId(id));
338     panda_file::ProtoDataAccessor pda(*pf, mda.GetProtoId());
339     return pda.GetNumArgs();
340 }
341 
IsMethodStatic(MethodPtr parentMethod,MethodId id) const342 bool PandaRuntimeInterface::IsMethodStatic(MethodPtr parentMethod, MethodId id) const
343 {
344     auto *pf = MethodCast(parentMethod)->GetPandaFile();
345     panda_file::MethodDataAccessor mda(*pf, panda_file::File::EntityId(id));
346     return mda.IsStatic();
347 }
348 
IsMethodStatic(MethodPtr method) const349 bool PandaRuntimeInterface::IsMethodStatic(MethodPtr method) const
350 {
351     return MethodCast(method)->IsStatic();
352 }
353 
IsMethodStaticConstructor(MethodPtr method) const354 bool PandaRuntimeInterface::IsMethodStaticConstructor(MethodPtr method) const
355 {
356     return MethodCast(method)->IsStaticConstructor();
357 }
358 
IsMemoryBarrierRequired(MethodPtr method) const359 bool PandaRuntimeInterface::IsMemoryBarrierRequired(MethodPtr method) const
360 {
361     if (!MethodCast(method)->IsInstanceConstructor()) {
362         return false;
363     }
364     for (auto &field : MethodCast(method)->GetClass()->GetFields()) {
365         // We insert memory barrier after call to constructor to ensure writes
366         // to final fields will be visible after constructor finishes
367         // Static fields are initialized in runtime entrypoints like InitializeClass,
368         // so barrier is not needed here if they are final
369         if (field.IsFinal() && !field.IsStatic()) {
370             return true;
371         }
372     }
373     return false;
374 }
375 
IsMethodIntrinsic(MethodPtr parentMethod,MethodId id) const376 bool PandaRuntimeInterface::IsMethodIntrinsic(MethodPtr parentMethod, MethodId id) const
377 {
378     Method *caller = MethodCast(parentMethod);
379     auto *pf = caller->GetPandaFile();
380     panda_file::MethodDataAccessor mda(*pf, panda_file::File::EntityId(id));
381 
382     auto *className = pf->GetStringData(mda.GetClassId()).data;
383     auto *classLinker = Runtime::GetCurrent()->GetClassLinker();
384 
385     auto *klass = classLinker->FindLoadedClass(className, caller->GetClass()->GetLoadContext());
386 
387     // Class should be loaded during intrinsics initialization
388     if (klass == nullptr) {
389         return false;
390     }
391 
392     auto name = pf->GetStringData(mda.GetNameId());
393     bool isArrayClone = ClassHelper::IsArrayDescriptor(className) &&
394                         (utf::CompareMUtf8ToMUtf8(name.data, utf::CStringAsMutf8("clone")) == 0);
395     Method::Proto proto(*pf, mda.GetProtoId());
396     auto *method = klass->GetDirectMethod(name.data, proto);
397     if (method == nullptr) {
398         if (isArrayClone) {
399             method = klass->GetClassMethod(name.data, proto);
400         } else {
401             return false;
402         }
403     }
404 
405     return method->IsIntrinsic();
406 }
407 
GetBytecodeString(MethodPtr method,uintptr_t pc) const408 std::string PandaRuntimeInterface::GetBytecodeString(MethodPtr method, uintptr_t pc) const
409 {
410     // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
411     BytecodeInstruction inst(MethodCast(method)->GetInstructions() + pc);
412     std::stringstream ss;
413     ss << inst;
414     return ss.str();
415 }
416 
ResolveField(PandaRuntimeInterface::MethodPtr m,size_t id,bool allowExternal,uint32_t * pclassId)417 PandaRuntimeInterface::FieldPtr PandaRuntimeInterface::ResolveField(PandaRuntimeInterface::MethodPtr m, size_t id,
418                                                                     bool allowExternal, uint32_t *pclassId)
419 {
420     ScopedMutatorLock lock;
421     ErrorHandler handler;
422     auto method = MethodCast(m);
423     auto pfile = method->GetPandaFile();
424     auto field = Runtime::GetCurrent()->GetClassLinker()->GetField(*method, panda_file::File::EntityId(id), &handler);
425     if (field == nullptr) {
426         return nullptr;
427     }
428     auto klass = field->GetClass();
429     if (pfile == field->GetPandaFile() || allowExternal) {
430         if (pclassId != nullptr) {
431             *pclassId = klass->GetFileId().GetOffset();
432         }
433         return field;
434     }
435 
436     auto classId = GetClassIdWithinFile(m, klass);
437     if (classId != 0) {
438         if (pclassId != nullptr) {
439             *pclassId = classId;
440         }
441         return field;
442     }
443     return nullptr;
444 }
445 
446 template <typename T>
FillLiteralArrayData(const panda_file::File * pfile,pandasm::LiteralArray * litArray,const panda_file::LiteralTag & tag,const panda_file::LiteralDataAccessor::LiteralValue & value)447 void FillLiteralArrayData(const panda_file::File *pfile, pandasm::LiteralArray *litArray,
448                           const panda_file::LiteralTag &tag, const panda_file::LiteralDataAccessor::LiteralValue &value)
449 {
450     panda_file::File::EntityId id(std::get<uint32_t>(value));
451     auto sp = pfile->GetSpanFromId(id);
452     auto len = panda_file::helpers::Read<sizeof(uint32_t)>(&sp);
453 
454     for (size_t i = 0; i < len; i++) {
455         pandasm::LiteralArray::Literal lit;
456         lit.tag = tag;
457         lit.value = bit_cast<T>(panda_file::helpers::Read<sizeof(T)>(&sp));
458         litArray->literals.push_back(lit);
459     }
460 }
461 
FillLiteralArrayTyped(const panda_file::File * pfile,pandasm::LiteralArray & litArray,const panda_file::LiteralTag & tag,const panda_file::LiteralDataAccessor::LiteralValue & value)462 static void FillLiteralArrayTyped(const panda_file::File *pfile, pandasm::LiteralArray &litArray,
463                                   const panda_file::LiteralTag &tag,
464                                   const panda_file::LiteralDataAccessor::LiteralValue &value)
465 {
466     switch (tag) {
467         case panda_file::LiteralTag::ARRAY_U1: {
468             FillLiteralArrayData<bool>(pfile, &litArray, tag, value);
469             break;
470         }
471         case panda_file::LiteralTag::ARRAY_I8:
472         case panda_file::LiteralTag::ARRAY_U8: {
473             FillLiteralArrayData<uint8_t>(pfile, &litArray, tag, value);
474             break;
475         }
476         case panda_file::LiteralTag::ARRAY_I16:
477         case panda_file::LiteralTag::ARRAY_U16: {
478             FillLiteralArrayData<uint16_t>(pfile, &litArray, tag, value);
479             break;
480         }
481         // in the case of ARRAY_STRING, the array stores strings ids
482         case panda_file::LiteralTag::ARRAY_STRING:
483         case panda_file::LiteralTag::ARRAY_I32:
484         case panda_file::LiteralTag::ARRAY_U32: {
485             FillLiteralArrayData<uint32_t>(pfile, &litArray, tag, value);
486             break;
487         }
488         case panda_file::LiteralTag::ARRAY_I64:
489         case panda_file::LiteralTag::ARRAY_U64: {
490             FillLiteralArrayData<uint64_t>(pfile, &litArray, tag, value);
491             break;
492         }
493         case panda_file::LiteralTag::ARRAY_F32: {
494             FillLiteralArrayData<float>(pfile, &litArray, tag, value);
495             break;
496         }
497         case panda_file::LiteralTag::ARRAY_F64: {
498             FillLiteralArrayData<double>(pfile, &litArray, tag, value);
499             break;
500         }
501         case panda_file::LiteralTag::TAGVALUE:
502         case panda_file::LiteralTag::ACCESSOR:
503         case panda_file::LiteralTag::NULLVALUE: {
504             break;
505         }
506         default: {
507             UNREACHABLE();
508             break;
509         }
510     }
511 }
512 
GetLiteralArray(MethodPtr m,LiteralArrayId id) const513 ark::pandasm::LiteralArray PandaRuntimeInterface::GetLiteralArray(MethodPtr m, LiteralArrayId id) const
514 {
515     auto method = MethodCast(m);
516     auto pfile = method->GetPandaFile();
517     id = pfile->GetLiteralArrays()[id];
518     pandasm::LiteralArray litArray;
519 
520     panda_file::LiteralDataAccessor litArrayAccessor(*pfile, pfile->GetLiteralArraysId());
521 
522     litArrayAccessor.EnumerateLiteralVals(
523         panda_file::File::EntityId(id),
524         [&litArray, pfile](const panda_file::LiteralDataAccessor::LiteralValue &value,
525                            const panda_file::LiteralTag &tag) { FillLiteralArrayTyped(pfile, litArray, tag, value); });
526 
527     return litArray;
528 }
529 
FindClassIdInFile(MethodPtr method,ClassPtr cls) const530 std::optional<RuntimeInterface::IdType> PandaRuntimeInterface::FindClassIdInFile(MethodPtr method, ClassPtr cls) const
531 {
532     auto klass = ClassCast(cls);
533     auto pfile = MethodCast(method)->GetPandaFile();
534     auto className = klass->GetName();
535     PandaString storage;
536     auto classId = pfile->GetClassId(ClassHelper::GetDescriptor(utf::CStringAsMutf8(className.c_str()), &storage));
537     if (classId.IsValid() && className == ClassHelper::GetName(pfile->GetStringData(classId).data)) {
538         return std::optional<RuntimeInterface::IdType>(classId.GetOffset());
539     }
540     return std::nullopt;
541 }
542 
GetClassIdWithinFile(MethodPtr method,ClassPtr cls) const543 RuntimeInterface::IdType PandaRuntimeInterface::GetClassIdWithinFile(MethodPtr method, ClassPtr cls) const
544 {
545     auto classId = FindClassIdInFile(method, cls);
546     return classId ? classId.value() : 0;
547 }
548 
GetLiteralArrayClassIdWithinFile(PandaRuntimeInterface::MethodPtr method,panda_file::LiteralTag tag) const549 RuntimeInterface::IdType PandaRuntimeInterface::GetLiteralArrayClassIdWithinFile(
550     PandaRuntimeInterface::MethodPtr method, panda_file::LiteralTag tag) const
551 {
552     ScopedMutatorLock lock;
553     ErrorHandler handler;
554     auto ctx = Runtime::GetCurrent()->GetLanguageContext(*MethodCast(method));
555     auto cls = Runtime::GetCurrent()->GetClassRootForLiteralTag(
556         *Runtime::GetCurrent()->GetClassLinker()->GetExtension(ctx), tag);
557 
558     auto pfile = MethodCast(method)->GetPandaFile();
559     auto className = cls->GetName();
560     for (decltype(auto) classRawId : pfile->GetClasses()) {
561         auto classId = panda_file::File::EntityId(classRawId);
562         if (classId.IsValid() && className == ClassHelper::GetName(pfile->GetStringData(classId).data)) {
563             return classId.GetOffset();
564         }
565     }
566     UNREACHABLE();
567 }
568 
CanUseTlabForClass(ClassPtr klass) const569 bool PandaRuntimeInterface::CanUseTlabForClass(ClassPtr klass) const
570 {
571     auto cls = ClassCast(klass);
572     return !Thread::GetCurrent()->GetVM()->GetHeapManager()->IsObjectFinalized(cls) && !cls->IsVariableSize() &&
573            cls->IsInstantiable();
574 }
575 
GetTLABMaxSize() const576 size_t PandaRuntimeInterface::GetTLABMaxSize() const
577 {
578     return Thread::GetCurrent()->GetVM()->GetHeapManager()->GetTLABMaxAllocSize();
579 }
580 
CanScalarReplaceObject(ClassPtr klass) const581 bool PandaRuntimeInterface::CanScalarReplaceObject(ClassPtr klass) const
582 {
583     auto cls = ClassCast(klass);
584     auto ctx = Runtime::GetCurrent()->GetLanguageContext(*cls);
585     return Runtime::GetCurrent()->GetClassLinker()->GetExtension(ctx)->CanScalarReplaceObject(cls);
586 }
587 
ResolveType(PandaRuntimeInterface::MethodPtr method,size_t id) const588 PandaRuntimeInterface::ClassPtr PandaRuntimeInterface::ResolveType(PandaRuntimeInterface::MethodPtr method,
589                                                                    size_t id) const
590 {
591     ScopedMutatorLock lock;
592     ErrorHandler handler;
593     auto klass = Runtime::GetCurrent()->GetClassLinker()->GetClass(*MethodCast(method), panda_file::File::EntityId(id),
594                                                                    &handler);
595     return klass;
596 }
597 
IsClassInitialized(uintptr_t klass) const598 bool PandaRuntimeInterface::IsClassInitialized(uintptr_t klass) const
599 {
600     return TypeCast(klass)->IsInitialized();
601 }
602 
GetManagedType(uintptr_t klass) const603 uintptr_t PandaRuntimeInterface::GetManagedType(uintptr_t klass) const
604 {
605     return reinterpret_cast<uintptr_t>(TypeCast(klass)->GetManagedObject());
606 }
607 
GetFieldType(FieldPtr field) const608 compiler::DataType::Type PandaRuntimeInterface::GetFieldType(FieldPtr field) const
609 {
610     return ToCompilerType(FieldCast(field)->GetType());
611 }
612 
GetArrayComponentType(ClassPtr klass) const613 compiler::DataType::Type PandaRuntimeInterface::GetArrayComponentType(ClassPtr klass) const
614 {
615     return ToCompilerType(ClassCast(klass)->GetComponentType()->GetType());
616 }
617 
GetFieldTypeById(MethodPtr parentMethod,IdType id) const618 compiler::DataType::Type PandaRuntimeInterface::GetFieldTypeById(MethodPtr parentMethod, IdType id) const
619 {
620     auto *pf = MethodCast(parentMethod)->GetPandaFile();
621     panda_file::FieldDataAccessor fda(*pf, panda_file::File::EntityId(id));
622     return ToCompilerType(panda_file::Type::GetTypeFromFieldEncoding(fda.GetType()));
623 }
624 
GetFieldValueTypeId(MethodPtr method,IdType id) const625 compiler::RuntimeInterface::IdType PandaRuntimeInterface::GetFieldValueTypeId(MethodPtr method, IdType id) const
626 {
627     auto *pf = MethodCast(method)->GetPandaFile();
628     auto typeId = panda_file::FieldDataAccessor::GetTypeId(*pf, panda_file::File::EntityId(id));
629     return typeId.GetOffset();
630 }
631 
GetClassForField(FieldPtr field) const632 RuntimeInterface::ClassPtr PandaRuntimeInterface::GetClassForField(FieldPtr field) const
633 {
634     return FieldCast(field)->GetClass();
635 }
636 
GetArrayElementSize(MethodPtr method,IdType id) const637 uint32_t PandaRuntimeInterface::GetArrayElementSize(MethodPtr method, IdType id) const
638 {
639     auto *pf = MethodCast(method)->GetPandaFile();
640     auto *descriptor = pf->GetStringData(panda_file::File::EntityId(id)).data;
641     // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
642     ASSERT(descriptor[0] == '[');
643     // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
644     return Class::GetTypeSize(panda_file::Type::GetTypeIdBySignature(static_cast<char>(descriptor[1])));
645 }
646 
GetMaxArrayLength(ClassPtr klass) const647 uint32_t PandaRuntimeInterface::GetMaxArrayLength(ClassPtr klass) const
648 {
649     ScopedMutatorLock lock;
650     if (ClassCast(klass)->IsArrayClass()) {
651         return INT32_MAX / ClassCast(klass)->GetComponentSize();
652     }
653     return INT32_MAX;
654 }
655 
GetPointerToConstArrayData(MethodPtr method,IdType id) const656 uintptr_t PandaRuntimeInterface::GetPointerToConstArrayData(MethodPtr method, IdType id) const
657 {
658     auto *pf = MethodCast(method)->GetPandaFile();
659     return Runtime::GetCurrent()->GetPointerToConstArrayData(*pf, pf->GetLiteralArrays()[id]);
660 }
661 
GetOffsetToConstArrayData(MethodPtr method,IdType id) const662 size_t PandaRuntimeInterface::GetOffsetToConstArrayData(MethodPtr method, IdType id) const
663 {
664     auto *pf = MethodCast(method)->GetPandaFile();
665     auto offset = Runtime::GetCurrent()->GetPointerToConstArrayData(*pf, pf->GetLiteralArrays()[id]) -
666                   reinterpret_cast<uintptr_t>(pf->GetBase());
667     return static_cast<size_t>(offset);
668 }
669 
GetFieldOffset(FieldPtr field) const670 size_t PandaRuntimeInterface::GetFieldOffset(FieldPtr field) const
671 {
672     if (!HasFieldMetadata(field)) {
673         return reinterpret_cast<uintptr_t>(field) >> 1U;
674     }
675     return FieldCast(field)->GetOffset();
676 }
677 
GetFieldByOffset(size_t offset) const678 RuntimeInterface::FieldPtr PandaRuntimeInterface::GetFieldByOffset(size_t offset) const
679 {
680     ASSERT(MinimumBitsToStore(offset) < std::numeric_limits<uintptr_t>::digits);
681     return reinterpret_cast<FieldPtr>((offset << 1U) | 1U);
682 }
683 
GetFieldClass(FieldPtr field) const684 uintptr_t PandaRuntimeInterface::GetFieldClass(FieldPtr field) const
685 {
686     return reinterpret_cast<uintptr_t>(FieldCast(field)->GetClass());
687 }
688 
IsFieldVolatile(FieldPtr field) const689 bool PandaRuntimeInterface::IsFieldVolatile(FieldPtr field) const
690 {
691     return FieldCast(field)->IsVolatile();
692 }
693 
IsFieldFinal(FieldPtr field) const694 bool PandaRuntimeInterface::IsFieldFinal(FieldPtr field) const
695 {
696     return FieldCast(field)->IsFinal();
697 }
698 
IsFieldReadonly(FieldPtr field) const699 bool PandaRuntimeInterface::IsFieldReadonly(FieldPtr field) const
700 {
701     return FieldCast(field)->IsReadonly();
702 }
703 
HasFieldMetadata(FieldPtr field) const704 bool PandaRuntimeInterface::HasFieldMetadata(FieldPtr field) const
705 {
706     return (reinterpret_cast<uintptr_t>(field) & 1U) == 0;
707 }
708 
GetStaticFieldValue(FieldPtr fieldPtr) const709 uint64_t PandaRuntimeInterface::GetStaticFieldValue(FieldPtr fieldPtr) const
710 {
711     auto *field = FieldCast(fieldPtr);
712     auto type = GetFieldType(fieldPtr);
713     auto klass = field->GetClass();
714     ASSERT(compiler::DataType::GetCommonType(type) == compiler::DataType::INT64);
715     // NB: must be sign-extended for signed types at call-site
716     switch (compiler::DataType::ShiftByType(type, Arch::NONE)) {
717         case 0U:
718             return klass->GetFieldPrimitive<uint8_t>(*field);
719         case 1U:
720             return klass->GetFieldPrimitive<uint16_t>(*field);
721         case 2U:
722             return klass->GetFieldPrimitive<uint32_t>(*field);
723         case 3U:
724             return klass->GetFieldPrimitive<uint64_t>(*field);
725         default:
726             UNREACHABLE();
727     }
728 }
729 
GetFieldId(FieldPtr field) const730 RuntimeInterface::FieldId PandaRuntimeInterface::GetFieldId(FieldPtr field) const
731 {
732     return FieldCast(field)->GetFileId().GetOffset();
733 }
734 
GetPreType() const735 ark::mem::BarrierType PandaRuntimeInterface::GetPreType() const
736 {
737     return Thread::GetCurrent()->GetBarrierSet()->GetPreType();
738 }
739 
GetPostType() const740 ark::mem::BarrierType PandaRuntimeInterface::GetPostType() const
741 {
742     return Thread::GetCurrent()->GetBarrierSet()->GetPostType();
743 }
744 
GetBarrierOperand(ark::mem::BarrierPosition barrierPosition,std::string_view operandName) const745 ark::mem::BarrierOperand PandaRuntimeInterface::GetBarrierOperand(ark::mem::BarrierPosition barrierPosition,
746                                                                   std::string_view operandName) const
747 {
748     return Thread::GetCurrent()->GetBarrierSet()->GetBarrierOperand(barrierPosition, operandName);
749 }
750 
GetFunctionTargetOffset(Arch arch) const751 uint32_t PandaRuntimeInterface::GetFunctionTargetOffset([[maybe_unused]] Arch arch) const
752 {
753     // NOTE(wengchangcheng): return offset of method in JSFunction
754     return 0;
755 }
756 
GetNativePointerTargetOffset(Arch arch) const757 uint32_t PandaRuntimeInterface::GetNativePointerTargetOffset(Arch arch) const
758 {
759     return cross_values::GetCoretypesNativePointerExternalPointerOffset(arch);
760 }
761 
AddDependency(PandaRuntimeInterface::MethodPtr callee,RuntimeInterface::MethodPtr caller)762 void ClassHierarchyAnalysisWrapper::AddDependency(PandaRuntimeInterface::MethodPtr callee,
763                                                   RuntimeInterface::MethodPtr caller)
764 {
765     Runtime::GetCurrent()->GetCha()->AddDependency(MethodCast(callee), MethodCast(caller));
766 }
767 
768 /// With 'no-async-jit' compilation inside of c2i bridge can forced and it can trigger GC
HasSafepointDuringCall() const769 bool PandaRuntimeInterface::HasSafepointDuringCall() const
770 {
771 #ifdef PANDA_PRODUCT_BUILD
772     return false;
773 #else
774     if (Runtime::GetOptions().IsArkAot()) {
775         return false;
776     }
777     return Runtime::GetOptions().IsNoAsyncJit();
778 #endif
779 }
780 
CreateCompilerThread()781 RuntimeInterface::ThreadPtr PandaRuntimeInterface::CreateCompilerThread()
782 {
783     ASSERT(Thread::GetCurrent() != nullptr);
784     auto allocator = Runtime::GetCurrent()->GetInternalAllocator();
785     return allocator->New<Thread>(PandaVM::GetCurrent(), Thread::ThreadType::THREAD_TYPE_COMPILER);
786 }
787 
DestroyCompilerThread(ThreadPtr thread)788 void PandaRuntimeInterface::DestroyCompilerThread(ThreadPtr thread)
789 {
790     ASSERT(thread != nullptr);
791     auto allocator = Runtime::GetCurrent()->GetInternalAllocator();
792     allocator->Delete(static_cast<Thread *>(thread));
793 }
794 
GetClasses(PandaRuntimeInterface::MethodPtr m,uintptr_t pc,ArenaVector<RuntimeInterface::ClassPtr> * classes)795 InlineCachesWrapper::CallKind InlineCachesWrapper::GetClasses(PandaRuntimeInterface::MethodPtr m, uintptr_t pc,
796                                                               ArenaVector<RuntimeInterface::ClassPtr> *classes)
797 {
798     ASSERT(classes != nullptr);
799     classes->clear();
800     auto method = static_cast<Method *>(m);
801     auto profilingData = method->GetProfilingData();
802     if (profilingData == nullptr) {
803         return CallKind::UNKNOWN;
804     }
805     auto ic = profilingData->FindInlineCache(pc);
806     if (ic == nullptr) {
807         return CallKind::UNKNOWN;
808     }
809     auto icClasses = ic->GetClassesCopy();
810     classes->insert(classes->end(), icClasses.begin(), icClasses.end());
811     if (classes->empty()) {
812         return CallKind::UNKNOWN;
813     }
814     if (classes->size() == 1) {
815         return CallKind::MONOMORPHIC;
816     }
817     if (CallSiteInlineCache::IsMegamorphic(reinterpret_cast<Class *>((*classes)[0]))) {
818         return CallKind::MEGAMORPHIC;
819     }
820     return CallKind::POLYMORPHIC;
821 }
822 
AddTableSlot(RuntimeInterface::MethodPtr method,uint32_t typeId,SlotKind kind)823 bool UnresolvedTypesWrapper::AddTableSlot(RuntimeInterface::MethodPtr method, uint32_t typeId, SlotKind kind)
824 {
825     std::pair<uint32_t, UnresolvedTypesInterface::SlotKind> key {typeId, kind};
826     if (slots_.find(method) == slots_.end()) {
827         slots_[method][key] = 0;
828         return true;
829     }
830     auto &table = slots_.at(method);
831     if (table.find(key) == table.end()) {
832         table[key] = 0;
833         return true;
834     }
835     return false;
836 }
837 
GetTableSlot(RuntimeInterface::MethodPtr method,uint32_t typeId,SlotKind kind) const838 uintptr_t UnresolvedTypesWrapper::GetTableSlot(RuntimeInterface::MethodPtr method, uint32_t typeId, SlotKind kind) const
839 {
840     ASSERT(slots_.find(method) != slots_.end());
841     auto &table = slots_.at(method);
842     ASSERT(table.find({typeId, kind}) != table.end());
843     return reinterpret_cast<uintptr_t>(&table.at({typeId, kind}));
844 }
845 
CompileMethod(Method * method,uintptr_t bytecodeOffset,bool osr,TaggedValue func)846 bool Compiler::CompileMethod(Method *method, uintptr_t bytecodeOffset, bool osr, TaggedValue func)
847 {
848     if (method->IsAbstract()) {
849         return false;
850     }
851 
852     if (osr && GetOsrCode(method) != nullptr) {
853         ASSERT(method == ManagedThread::GetCurrent()->GetCurrentFrame()->GetMethod());
854         ASSERT(method->HasCompiledCode());
855         return OsrEntry(bytecodeOffset, GetOsrCode(method));
856     }
857     // In case if some thread raise compilation when another already compiled it, we just exit.
858     if (method->HasCompiledCode() && !osr) {
859         return false;
860     }
861     bool ctxOsr = method->HasCompiledCode() ? osr : false;
862     if (method->AtomicSetCompilationStatus(ctxOsr ? Method::COMPILED : Method::NOT_COMPILED, Method::WAITING)) {
863         CompilerTask ctx {method, ctxOsr, ManagedThread::GetCurrent()->GetVM()};
864         AddTask(std::move(ctx), func);
865     }
866     if (noAsyncJit_) {
867         auto status = method->GetCompilationStatus();
868         for (; (status == Method::WAITING) || (status == Method::COMPILATION);
869              status = method->GetCompilationStatus()) {
870             if (compilerWorker_ == nullptr || compilerWorker_->IsWorkerJoined()) {
871                 // JIT thread is destroyed, wait makes no sence
872                 return false;
873             }
874             auto thread = MTManagedThread::GetCurrent();
875             // NOTE(asoldatov): Remove this workaround for invoking compiler from ECMA VM
876             if (thread != nullptr) {
877                 static constexpr uint64_t SLEEP_MS = 10;
878                 thread->TimedWait(ThreadStatus::IS_COMPILER_WAITING, SLEEP_MS, 0);
879             }
880         }
881     }
882     return false;
883 }
884 
885 template <compiler::TaskRunnerMode RUNNER_MODE>
CompileMethodLocked(compiler::CompilerTaskRunner<RUNNER_MODE> taskRunner)886 void Compiler::CompileMethodLocked(compiler::CompilerTaskRunner<RUNNER_MODE> taskRunner)
887 {
888     os::memory::LockHolder lock(compilationLock_);
889     StartCompileMethod<RUNNER_MODE>(std::move(taskRunner));
890 }
891 
892 template <compiler::TaskRunnerMode RUNNER_MODE>
StartCompileMethod(compiler::CompilerTaskRunner<RUNNER_MODE> taskRunner)893 void Compiler::StartCompileMethod(compiler::CompilerTaskRunner<RUNNER_MODE> taskRunner)
894 {
895     ASSERT(runtimeIface_ != nullptr);
896     auto &taskCtx = taskRunner.GetContext();
897     auto *method = taskCtx.GetMethod();
898 
899     method->ResetHotnessCounter();
900 
901     if (IsCompilationExpired(method, taskCtx.IsOsr())) {
902         ASSERT(!noAsyncJit_);
903         compiler::CompilerTaskRunner<RUNNER_MODE>::EndTask(std::move(taskRunner), false);
904         return;
905     }
906 
907     mem::MemStatsType *memStats = taskCtx.GetVM()->GetMemStats();
908 
909     auto allocator = std::make_unique<ark::ArenaAllocator>(ark::SpaceType::SPACE_TYPE_COMPILER, memStats);
910     auto localAllocator = std::make_unique<ark::ArenaAllocator>(ark::SpaceType::SPACE_TYPE_COMPILER, memStats, true);
911 
912     if constexpr (RUNNER_MODE == compiler::BACKGROUND_MODE) {
913         taskCtx.SetAllocator(std::move(allocator));
914         taskCtx.SetLocalAllocator(std::move(localAllocator));
915     } else {
916         taskCtx.SetAllocator(allocator.get());
917         taskCtx.SetLocalAllocator(localAllocator.get());
918     }
919 
920     taskRunner.AddFinalize([](compiler::CompilerContext<RUNNER_MODE> &compilerCtx) {
921         auto *compiledMethod = compilerCtx.GetMethod();
922         auto isCompiled = compilerCtx.GetCompilationStatus();
923         if (isCompiled) {
924             // Check that method was not deoptimized
925             compiledMethod->AtomicSetCompilationStatus(Method::COMPILATION, Method::COMPILED);
926             return;
927         }
928         // If deoptimization occurred during OSR compilation, the compilation returns false.
929         // For the case we need reset compiation status
930         if (compilerCtx.IsOsr()) {
931             compiledMethod->SetCompilationStatus(Method::NOT_COMPILED);
932             return;
933         }
934         // Failure during compilation, should we retry later?
935         compiledMethod->SetCompilationStatus(Method::FAILED);
936     });
937 
938     compiler::JITCompileMethod<RUNNER_MODE>(runtimeIface_, codeAllocator_, &gdbDebugInfoAllocator_, jitStats_,
939                                             std::move(taskRunner));
940 }
941 
JoinWorker()942 void Compiler::JoinWorker()
943 {
944     if (compilerWorker_ != nullptr) {
945         compilerWorker_->JoinWorker();
946     }
947 #ifdef PANDA_COMPILER_DEBUG_INFO
948     if (!Runtime::GetOptions().IsArkAot() && compiler::g_options.IsCompilerEmitDebugInfo()) {
949         compiler::CleanJitDebugCode();
950     }
951 #endif
952 }
953 
GetNonMovableString(MethodPtr method,StringId id) const954 ObjectPointerType PandaRuntimeInterface::GetNonMovableString(MethodPtr method, StringId id) const
955 {
956     auto vm = Runtime::GetCurrent()->GetPandaVM();
957     auto pf = MethodCast(method)->GetPandaFile();
958     return ToObjPtrType(vm->GetNonMovableString(*pf, panda_file::File::EntityId {id}));
959 }
960 
961 #ifndef PANDA_PRODUCT_BUILD
CompileMethodImpl(coretypes::String * fullMethodName,panda_file::SourceLang sourceLang)962 uint8_t CompileMethodImpl(coretypes::String *fullMethodName, panda_file::SourceLang sourceLang)
963 {
964     auto name = ConvertToString(fullMethodName);
965     auto *classLinker = Runtime::GetCurrent()->GetClassLinker();
966 
967     size_t pos = name.find_last_of("::");
968     if (pos == std::string_view::npos) {
969         return 1;
970     }
971     auto className = PandaString(name.substr(0, pos - 1));
972     auto methodName = PandaString(name.substr(pos + 1));
973 
974     PandaString descriptor;
975     auto classNameBytes = ClassHelper::GetDescriptor(utf::CStringAsMutf8(className.c_str()), &descriptor);
976     auto methodNameBytes = utf::CStringAsMutf8(methodName.c_str());
977 
978     ClassLinkerExtension *ext = classLinker->GetExtension(sourceLang);
979     Class *cls = classLinker->GetClass(classNameBytes, true, ext->GetBootContext());
980     if (cls == nullptr) {
981         static constexpr uint8_t CLASS_IS_NULL = 2;
982         return CLASS_IS_NULL;
983     }
984 
985     auto method = cls->GetDirectMethod(methodNameBytes);
986     if (method == nullptr) {
987         static constexpr uint8_t METHOD_IS_NULL = 3;
988         return METHOD_IS_NULL;
989     }
990 
991     if (method->IsAbstract()) {
992         static constexpr uint8_t ABSTRACT_ERROR = 4;
993         return ABSTRACT_ERROR;
994     }
995     if (method->HasCompiledCode()) {
996         return 0;
997     }
998     auto *compiler = Runtime::GetCurrent()->GetPandaVM()->GetCompiler();
999     auto status = method->GetCompilationStatus();
1000     for (; (status != Method::COMPILED) && (status != Method::FAILED); status = method->GetCompilationStatus()) {
1001         if (status == Method::NOT_COMPILED) {
1002             ASSERT(!method->HasCompiledCode());
1003             compiler->CompileMethod(method, 0, false, TaggedValue::Hole());
1004         }
1005         static constexpr uint64_t SLEEP_MS = 10;
1006         MTManagedThread::GetCurrent()->TimedWait(ThreadStatus::IS_COMPILER_WAITING, SLEEP_MS, 0);
1007     }
1008     static constexpr uint8_t COMPILATION_FAILED = 5;
1009     return (status == Method::COMPILED ? 0 : COMPILATION_FAILED);
1010 }
1011 #endif  // PANDA_PRODUCT_BUILD
1012 
1013 template void Compiler::CompileMethodLocked<compiler::BACKGROUND_MODE>(
1014     compiler::CompilerTaskRunner<compiler::BACKGROUND_MODE>);
1015 template void Compiler::CompileMethodLocked<compiler::INPLACE_MODE>(
1016     compiler::CompilerTaskRunner<compiler::INPLACE_MODE>);
1017 template void Compiler::StartCompileMethod<compiler::BACKGROUND_MODE>(
1018     compiler::CompilerTaskRunner<compiler::BACKGROUND_MODE>);
1019 template void Compiler::StartCompileMethod<compiler::INPLACE_MODE>(
1020     compiler::CompilerTaskRunner<compiler::INPLACE_MODE>);
1021 
1022 }  // namespace ark
1023