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