• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /**
2  * Copyright (c) 2021-2022 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  * http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #include "runtime/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 panda {
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 
GetLiteralArray(MethodPtr m,LiteralArrayId id) const462 panda::pandasm::LiteralArray PandaRuntimeInterface::GetLiteralArray(MethodPtr m, LiteralArrayId id) const
463 {
464     auto method = MethodCast(m);
465     auto pfile = method->GetPandaFile();
466     id = pfile->GetLiteralArrays()[id];
467     pandasm::LiteralArray litArray;
468 
469     panda_file::LiteralDataAccessor litArrayAccessor(*pfile, pfile->GetLiteralArraysId());
470     // clang-format off
471     litArrayAccessor.EnumerateLiteralVals(panda_file::File::EntityId(id),
472                                             [&litArray, pfile](const panda_file::LiteralDataAccessor::LiteralValue &value,
473                                                                const panda_file::LiteralTag &tag) {
474                                                 switch (tag) {
475                                                     case panda_file::LiteralTag::ARRAY_U1: {
476                                                         FillLiteralArrayData<bool>(pfile, &litArray, tag, value);
477                                                         break;
478                                                     }
479                                                     case panda_file::LiteralTag::ARRAY_I8:
480                                                     case panda_file::LiteralTag::ARRAY_U8: {
481                                                         FillLiteralArrayData<uint8_t>(pfile, &litArray, tag, value);
482                                                         break;
483                                                     }
484                                                     case panda_file::LiteralTag::ARRAY_I16:
485                                                     case panda_file::LiteralTag::ARRAY_U16: {
486                                                         FillLiteralArrayData<uint16_t>(pfile, &litArray, tag, value);
487                                                         break;
488                                                     }
489                                                     // in the case of ARRAY_STRING, the array stores strings ids
490                                                     case panda_file::LiteralTag::ARRAY_STRING:
491                                                     case panda_file::LiteralTag::ARRAY_I32:
492                                                     case panda_file::LiteralTag::ARRAY_U32: {
493                                                         FillLiteralArrayData<uint32_t>(pfile, &litArray, tag, value);
494                                                         break;
495                                                     }
496                                                     case panda_file::LiteralTag::ARRAY_I64:
497                                                     case panda_file::LiteralTag::ARRAY_U64: {
498                                                         FillLiteralArrayData<uint64_t>(pfile, &litArray, tag, value);
499                                                         break;
500                                                     }
501                                                     case panda_file::LiteralTag::ARRAY_F32: {
502                                                         FillLiteralArrayData<float>(pfile, &litArray, tag, value);
503                                                         break;
504                                                     }
505                                                     case panda_file::LiteralTag::ARRAY_F64: {
506                                                         FillLiteralArrayData<double>(pfile, &litArray, tag, value);
507                                                         break;
508                                                     }
509                                                     case panda_file::LiteralTag::TAGVALUE:
510                                                     case panda_file::LiteralTag::ACCESSOR:
511                                                     case panda_file::LiteralTag::NULLVALUE: {
512                                                         break;
513                                                     }
514                                                     default: {
515                                                         UNREACHABLE();
516                                                         break;
517                                                     }
518                                                 }
519                                             });
520     // clang-format on
521     return litArray;
522 }
523 
FindClassIdInFile(MethodPtr method,ClassPtr cls) const524 std::optional<RuntimeInterface::IdType> PandaRuntimeInterface::FindClassIdInFile(MethodPtr method, ClassPtr cls) const
525 {
526     auto klass = ClassCast(cls);
527     auto pfile = MethodCast(method)->GetPandaFile();
528     auto className = klass->GetName();
529     PandaString storage;
530     auto classId = pfile->GetClassId(ClassHelper::GetDescriptor(utf::CStringAsMutf8(className.c_str()), &storage));
531     if (classId.IsValid() && className == ClassHelper::GetName(pfile->GetStringData(classId).data)) {
532         return std::optional<RuntimeInterface::IdType>(classId.GetOffset());
533     }
534     return std::nullopt;
535 }
536 
GetClassIdWithinFile(MethodPtr method,ClassPtr cls) const537 RuntimeInterface::IdType PandaRuntimeInterface::GetClassIdWithinFile(MethodPtr method, ClassPtr cls) const
538 {
539     auto classId = FindClassIdInFile(method, cls);
540     return classId ? classId.value() : 0;
541 }
542 
GetLiteralArrayClassIdWithinFile(PandaRuntimeInterface::MethodPtr method,panda_file::LiteralTag tag) const543 RuntimeInterface::IdType PandaRuntimeInterface::GetLiteralArrayClassIdWithinFile(
544     PandaRuntimeInterface::MethodPtr method, panda_file::LiteralTag tag) const
545 {
546     ScopedMutatorLock lock;
547     ErrorHandler handler;
548     auto ctx = Runtime::GetCurrent()->GetLanguageContext(*MethodCast(method));
549     auto cls = Runtime::GetCurrent()->GetClassRootForLiteralTag(
550         *Runtime::GetCurrent()->GetClassLinker()->GetExtension(ctx), tag);
551 
552     auto pfile = MethodCast(method)->GetPandaFile();
553     auto className = cls->GetName();
554     for (decltype(auto) classRawId : pfile->GetClasses()) {
555         auto classId = panda_file::File::EntityId(classRawId);
556         if (classId.IsValid() && className == ClassHelper::GetName(pfile->GetStringData(classId).data)) {
557             return classId.GetOffset();
558         }
559     }
560     UNREACHABLE();
561 }
562 
CanUseTlabForClass(ClassPtr klass) const563 bool PandaRuntimeInterface::CanUseTlabForClass(ClassPtr klass) const
564 {
565     auto cls = ClassCast(klass);
566     return !Thread::GetCurrent()->GetVM()->GetHeapManager()->IsObjectFinalized(cls) && !cls->IsVariableSize() &&
567            cls->IsInstantiable();
568 }
569 
GetTLABMaxSize() const570 size_t PandaRuntimeInterface::GetTLABMaxSize() const
571 {
572     return Thread::GetCurrent()->GetVM()->GetHeapManager()->GetTLABMaxAllocSize();
573 }
574 
CanScalarReplaceObject(ClassPtr klass) const575 bool PandaRuntimeInterface::CanScalarReplaceObject(ClassPtr klass) const
576 {
577     auto cls = ClassCast(klass);
578     auto ctx = Runtime::GetCurrent()->GetLanguageContext(*cls);
579     return Runtime::GetCurrent()->GetClassLinker()->GetExtension(ctx)->CanScalarReplaceObject(cls);
580 }
581 
ResolveType(PandaRuntimeInterface::MethodPtr method,size_t id) const582 PandaRuntimeInterface::ClassPtr PandaRuntimeInterface::ResolveType(PandaRuntimeInterface::MethodPtr method,
583                                                                    size_t id) const
584 {
585     ScopedMutatorLock lock;
586     ErrorHandler handler;
587     auto klass = Runtime::GetCurrent()->GetClassLinker()->GetClass(*MethodCast(method), panda_file::File::EntityId(id),
588                                                                    &handler);
589     return klass;
590 }
591 
IsClassInitialized(uintptr_t klass) const592 bool PandaRuntimeInterface::IsClassInitialized(uintptr_t klass) const
593 {
594     return TypeCast(klass)->IsInitialized();
595 }
596 
GetManagedType(uintptr_t klass) const597 uintptr_t PandaRuntimeInterface::GetManagedType(uintptr_t klass) const
598 {
599     return reinterpret_cast<uintptr_t>(TypeCast(klass)->GetManagedObject());
600 }
601 
GetFieldType(FieldPtr field) const602 compiler::DataType::Type PandaRuntimeInterface::GetFieldType(FieldPtr field) const
603 {
604     return ToCompilerType(FieldCast(field)->GetType());
605 }
606 
GetFieldTypeById(MethodPtr parentMethod,IdType id) const607 compiler::DataType::Type PandaRuntimeInterface::GetFieldTypeById(MethodPtr parentMethod, IdType id) const
608 {
609     auto *pf = MethodCast(parentMethod)->GetPandaFile();
610     panda_file::FieldDataAccessor fda(*pf, panda_file::File::EntityId(id));
611     return ToCompilerType(panda_file::Type::GetTypeFromFieldEncoding(fda.GetType()));
612 }
613 
GetFieldValueTypeId(MethodPtr method,IdType id) const614 compiler::RuntimeInterface::IdType PandaRuntimeInterface::GetFieldValueTypeId(MethodPtr method, IdType id) const
615 {
616     auto *pf = MethodCast(method)->GetPandaFile();
617     auto typeId = panda_file::FieldDataAccessor::GetTypeId(*pf, panda_file::File::EntityId(id));
618     return typeId.GetOffset();
619 }
620 
GetClassForField(FieldPtr field) const621 RuntimeInterface::ClassPtr PandaRuntimeInterface::GetClassForField(FieldPtr field) const
622 {
623     return FieldCast(field)->GetClass();
624 }
625 
GetArrayElementSize(MethodPtr method,IdType id) const626 uint32_t PandaRuntimeInterface::GetArrayElementSize(MethodPtr method, IdType id) const
627 {
628     auto *pf = MethodCast(method)->GetPandaFile();
629     auto *descriptor = pf->GetStringData(panda_file::File::EntityId(id)).data;
630     // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
631     ASSERT(descriptor[0] == '[');
632     // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
633     return Class::GetTypeSize(panda_file::Type::GetTypeIdBySignature(static_cast<char>(descriptor[1])));
634 }
635 
GetMaxArrayLength(ClassPtr klass) const636 uint32_t PandaRuntimeInterface::GetMaxArrayLength(ClassPtr klass) const
637 {
638     ScopedMutatorLock lock;
639     if (ClassCast(klass)->IsArrayClass()) {
640         return INT32_MAX / ClassCast(klass)->GetComponentSize();
641     }
642     return INT32_MAX;
643 }
644 
GetPointerToConstArrayData(MethodPtr method,IdType id) const645 uintptr_t PandaRuntimeInterface::GetPointerToConstArrayData(MethodPtr method, IdType id) const
646 {
647     auto *pf = MethodCast(method)->GetPandaFile();
648     return Runtime::GetCurrent()->GetPointerToConstArrayData(*pf, pf->GetLiteralArrays()[id]);
649 }
650 
GetOffsetToConstArrayData(MethodPtr method,IdType id) const651 size_t PandaRuntimeInterface::GetOffsetToConstArrayData(MethodPtr method, IdType id) const
652 {
653     auto *pf = MethodCast(method)->GetPandaFile();
654     auto offset = Runtime::GetCurrent()->GetPointerToConstArrayData(*pf, pf->GetLiteralArrays()[id]) -
655                   reinterpret_cast<uintptr_t>(pf->GetBase());
656     return static_cast<size_t>(offset);
657 }
658 
GetFieldOffset(FieldPtr field) const659 size_t PandaRuntimeInterface::GetFieldOffset(FieldPtr field) const
660 {
661     if (!HasFieldMetadata(field)) {
662         return reinterpret_cast<uintptr_t>(field) >> 1U;
663     }
664     return FieldCast(field)->GetOffset();
665 }
666 
GetFieldByOffset(size_t offset) const667 RuntimeInterface::FieldPtr PandaRuntimeInterface::GetFieldByOffset(size_t offset) const
668 {
669     ASSERT(MinimumBitsToStore(offset) < std::numeric_limits<uintptr_t>::digits);
670     return reinterpret_cast<FieldPtr>((offset << 1U) | 1U);
671 }
672 
GetFieldClass(FieldPtr field) const673 uintptr_t PandaRuntimeInterface::GetFieldClass(FieldPtr field) const
674 {
675     return reinterpret_cast<uintptr_t>(FieldCast(field)->GetClass());
676 }
677 
IsFieldVolatile(FieldPtr field) const678 bool PandaRuntimeInterface::IsFieldVolatile(FieldPtr field) const
679 {
680     return FieldCast(field)->IsVolatile();
681 }
682 
HasFieldMetadata(FieldPtr field) const683 bool PandaRuntimeInterface::HasFieldMetadata(FieldPtr field) const
684 {
685     return (reinterpret_cast<uintptr_t>(field) & 1U) == 0;
686 }
687 
GetFieldId(FieldPtr field) const688 RuntimeInterface::FieldId PandaRuntimeInterface::GetFieldId(FieldPtr field) const
689 {
690     return FieldCast(field)->GetFileId().GetOffset();
691 }
692 
GetPreType() const693 panda::mem::BarrierType PandaRuntimeInterface::GetPreType() const
694 {
695     return Thread::GetCurrent()->GetBarrierSet()->GetPreType();
696 }
697 
GetPostType() const698 panda::mem::BarrierType PandaRuntimeInterface::GetPostType() const
699 {
700     return Thread::GetCurrent()->GetBarrierSet()->GetPostType();
701 }
702 
GetBarrierOperand(panda::mem::BarrierPosition barrierPosition,std::string_view operandName) const703 panda::mem::BarrierOperand PandaRuntimeInterface::GetBarrierOperand(panda::mem::BarrierPosition barrierPosition,
704                                                                     std::string_view operandName) const
705 {
706     return Thread::GetCurrent()->GetBarrierSet()->GetBarrierOperand(barrierPosition, operandName);
707 }
708 
GetFunctionTargetOffset(Arch arch) const709 uint32_t PandaRuntimeInterface::GetFunctionTargetOffset([[maybe_unused]] Arch arch) const
710 {
711     // NOTE(wengchangcheng): return offset of method in JSFunction
712     return 0;
713 }
714 
GetNativePointerTargetOffset(Arch arch) const715 uint32_t PandaRuntimeInterface::GetNativePointerTargetOffset(Arch arch) const
716 {
717     return cross_values::GetCoretypesNativePointerExternalPointerOffset(arch);
718 }
719 
AddDependency(PandaRuntimeInterface::MethodPtr callee,RuntimeInterface::MethodPtr caller)720 void ClassHierarchyAnalysisWrapper::AddDependency(PandaRuntimeInterface::MethodPtr callee,
721                                                   RuntimeInterface::MethodPtr caller)
722 {
723     Runtime::GetCurrent()->GetCha()->AddDependency(MethodCast(callee), MethodCast(caller));
724 }
725 
726 /// With 'no-async-jit' compilation inside of c2i bridge can forced and it can trigger GC
HasSafepointDuringCall() const727 bool PandaRuntimeInterface::HasSafepointDuringCall() const
728 {
729 #ifdef PANDA_PRODUCT_BUILD
730     return false;
731 #else
732     if (Runtime::GetOptions().IsArkAot()) {
733         return false;
734     }
735     return Runtime::GetOptions().IsNoAsyncJit();
736 #endif
737 }
738 
GetClasses(PandaRuntimeInterface::MethodPtr m,uintptr_t pc,ArenaVector<RuntimeInterface::ClassPtr> * classes)739 InlineCachesWrapper::CallKind InlineCachesWrapper::GetClasses(PandaRuntimeInterface::MethodPtr m, uintptr_t pc,
740                                                               ArenaVector<RuntimeInterface::ClassPtr> *classes)
741 {
742     ASSERT(classes != nullptr);
743     classes->clear();
744     auto method = static_cast<Method *>(m);
745     auto profilingData = method->GetProfilingData();
746     if (profilingData == nullptr) {
747         return CallKind::UNKNOWN;
748     }
749     auto ic = profilingData->FindInlineCache(pc);
750     if (ic == nullptr) {
751         return CallKind::UNKNOWN;
752     }
753     auto icClasses = ic->GetClassesCopy();
754     classes->insert(classes->end(), icClasses.begin(), icClasses.end());
755     if (classes->empty()) {
756         return CallKind::UNKNOWN;
757     }
758     if (classes->size() == 1) {
759         return CallKind::MONOMORPHIC;
760     }
761     if (CallSiteInlineCache::IsMegamorphic(reinterpret_cast<Class *>((*classes)[0]))) {
762         return CallKind::MEGAMORPHIC;
763     }
764     return CallKind::POLYMORPHIC;
765 }
766 
AddTableSlot(RuntimeInterface::MethodPtr method,uint32_t typeId,SlotKind kind)767 bool UnresolvedTypesWrapper::AddTableSlot(RuntimeInterface::MethodPtr method, uint32_t typeId, SlotKind kind)
768 {
769     std::pair<uint32_t, UnresolvedTypesInterface::SlotKind> key {typeId, kind};
770     if (slots_.find(method) == slots_.end()) {
771         slots_[method][key] = 0;
772         return true;
773     }
774     auto &table = slots_.at(method);
775     if (table.find(key) == table.end()) {
776         table[key] = 0;
777         return true;
778     }
779     return false;
780 }
781 
GetTableSlot(RuntimeInterface::MethodPtr method,uint32_t typeId,SlotKind kind) const782 uintptr_t UnresolvedTypesWrapper::GetTableSlot(RuntimeInterface::MethodPtr method, uint32_t typeId, SlotKind kind) const
783 {
784     ASSERT(slots_.find(method) != slots_.end());
785     auto &table = slots_.at(method);
786     ASSERT(table.find({typeId, kind}) != table.end());
787     return reinterpret_cast<uintptr_t>(&table.at({typeId, kind}));
788 }
789 
CompileMethod(Method * method,uintptr_t bytecodeOffset,bool osr,TaggedValue func)790 bool Compiler::CompileMethod(Method *method, uintptr_t bytecodeOffset, bool osr, TaggedValue func)
791 {
792     if (method->IsAbstract()) {
793         return false;
794     }
795 
796     if (osr && GetOsrCode(method) != nullptr) {
797         ASSERT(method == ManagedThread::GetCurrent()->GetCurrentFrame()->GetMethod());
798         ASSERT(method->HasCompiledCode());
799         return OsrEntry(bytecodeOffset, GetOsrCode(method));
800     }
801     // In case if some thread raise compilation when another already compiled it, we just exit.
802     if (method->HasCompiledCode() && !osr) {
803         return false;
804     }
805     bool ctxOsr = method->HasCompiledCode() ? osr : false;
806     if (method->AtomicSetCompilationStatus(ctxOsr ? Method::COMPILED : Method::NOT_COMPILED, Method::WAITING)) {
807         CompilerTask ctx {method, ctxOsr, ManagedThread::GetCurrent()->GetVM()};
808         AddTask(std::move(ctx), func);
809     }
810     if (noAsyncJit_) {
811         auto status = method->GetCompilationStatus();
812         for (; (status == Method::WAITING) || (status == Method::COMPILATION);
813              status = method->GetCompilationStatus()) {
814             if (compilerWorker_ == nullptr || compilerWorker_->IsWorkerJoined()) {
815                 // JIT thread is destroyed, wait makes no sence
816                 return false;
817             }
818             auto thread = MTManagedThread::GetCurrent();
819             // NOTE(asoldatov): Remove this workaround for invoking compiler from ECMA VM
820             if (thread != nullptr) {
821                 static constexpr uint64_t SLEEP_MS = 10;
822                 thread->TimedWait(ThreadStatus::IS_COMPILER_WAITING, SLEEP_MS, 0);
823             }
824         }
825     }
826     return false;
827 }
828 
829 template <compiler::TaskRunnerMode RUNNER_MODE>
CompileMethodLocked(compiler::CompilerTaskRunner<RUNNER_MODE> taskRunner)830 void Compiler::CompileMethodLocked(compiler::CompilerTaskRunner<RUNNER_MODE> taskRunner)
831 {
832     os::memory::LockHolder lock(compilationLock_);
833     StartCompileMethod<RUNNER_MODE>(std::move(taskRunner));
834 }
835 
836 template <compiler::TaskRunnerMode RUNNER_MODE>
StartCompileMethod(compiler::CompilerTaskRunner<RUNNER_MODE> taskRunner)837 void Compiler::StartCompileMethod(compiler::CompilerTaskRunner<RUNNER_MODE> taskRunner)
838 {
839     ASSERT(runtimeIface_ != nullptr);
840     auto &taskCtx = taskRunner.GetContext();
841     auto *method = taskCtx.GetMethod();
842 
843     method->ResetHotnessCounter();
844 
845     if (IsCompilationExpired(method, taskCtx.IsOsr())) {
846         ASSERT(!noAsyncJit_);
847         compiler::CompilerTaskRunner<RUNNER_MODE>::EndTask(std::move(taskRunner), false);
848         return;
849     }
850 
851     mem::MemStatsType *memStats = taskCtx.GetVM()->GetMemStats();
852 
853     auto allocator = std::make_unique<panda::ArenaAllocator>(panda::SpaceType::SPACE_TYPE_COMPILER, memStats);
854     auto localAllocator =
855         std::make_unique<panda::ArenaAllocator>(panda::SpaceType::SPACE_TYPE_COMPILER, memStats, true);
856 
857     if constexpr (RUNNER_MODE == compiler::BACKGROUND_MODE) {
858         taskCtx.SetAllocator(std::move(allocator));
859         taskCtx.SetLocalAllocator(std::move(localAllocator));
860     } else {
861         taskCtx.SetAllocator(allocator.get());
862         taskCtx.SetLocalAllocator(localAllocator.get());
863     }
864 
865     taskRunner.AddFinalize([](compiler::CompilerContext<RUNNER_MODE> &compilerCtx) {
866         auto *compiledMethod = compilerCtx.GetMethod();
867         auto isCompiled = compilerCtx.GetCompilationStatus();
868         if (isCompiled) {
869             // Check that method was not deoptimized
870             compiledMethod->AtomicSetCompilationStatus(Method::COMPILATION, Method::COMPILED);
871             return;
872         }
873         // If deoptimization occurred during OSR compilation, the compilation returns false.
874         // For the case we need reset compiation status
875         if (compilerCtx.IsOsr()) {
876             compiledMethod->SetCompilationStatus(Method::NOT_COMPILED);
877             return;
878         }
879         // Failure during compilation, should we retry later?
880         compiledMethod->SetCompilationStatus(Method::FAILED);
881     });
882 
883     compiler::JITCompileMethod<RUNNER_MODE>(runtimeIface_, codeAllocator_, &gdbDebugInfoAllocator_, jitStats_,
884                                             std::move(taskRunner));
885 }
886 
JoinWorker()887 void Compiler::JoinWorker()
888 {
889     if (compilerWorker_ != nullptr) {
890         compilerWorker_->JoinWorker();
891     }
892 #ifdef PANDA_COMPILER_DEBUG_INFO
893     if (!Runtime::GetOptions().IsArkAot() && compiler::g_options.IsCompilerEmitDebugInfo()) {
894         compiler::CleanJitDebugCode();
895     }
896 #endif
897 }
898 
GetNonMovableString(MethodPtr method,StringId id) const899 ObjectPointerType PandaRuntimeInterface::GetNonMovableString(MethodPtr method, StringId id) const
900 {
901     auto vm = Runtime::GetCurrent()->GetPandaVM();
902     auto pf = MethodCast(method)->GetPandaFile();
903     return ToObjPtrType(vm->GetNonMovableString(*pf, panda_file::File::EntityId {id}));
904 }
905 
906 #ifndef PANDA_PRODUCT_BUILD
CompileMethodImpl(coretypes::String * fullMethodName,panda_file::SourceLang sourceLang)907 uint8_t CompileMethodImpl(coretypes::String *fullMethodName, panda_file::SourceLang sourceLang)
908 {
909     auto name = ConvertToString(fullMethodName);
910     auto *classLinker = Runtime::GetCurrent()->GetClassLinker();
911 
912     size_t pos = name.find_last_of("::");
913     if (pos == std::string_view::npos) {
914         return 1;
915     }
916     auto className = PandaString(name.substr(0, pos - 1));
917     auto methodName = PandaString(name.substr(pos + 1));
918 
919     PandaString descriptor;
920     auto classNameBytes = ClassHelper::GetDescriptor(utf::CStringAsMutf8(className.c_str()), &descriptor);
921     auto methodNameBytes = utf::CStringAsMutf8(methodName.c_str());
922 
923     ClassLinkerExtension *ext = classLinker->GetExtension(sourceLang);
924     Class *cls = classLinker->GetClass(classNameBytes, true, ext->GetBootContext());
925     if (cls == nullptr) {
926         static constexpr uint8_t CLASS_IS_NULL = 2;
927         return CLASS_IS_NULL;
928     }
929 
930     auto method = cls->GetDirectMethod(methodNameBytes);
931     if (method == nullptr) {
932         static constexpr uint8_t METHOD_IS_NULL = 3;
933         return METHOD_IS_NULL;
934     }
935 
936     if (method->IsAbstract()) {
937         static constexpr uint8_t ABSTRACT_ERROR = 4;
938         return ABSTRACT_ERROR;
939     }
940     if (method->HasCompiledCode()) {
941         return 0;
942     }
943     auto *compiler = Runtime::GetCurrent()->GetPandaVM()->GetCompiler();
944     auto status = method->GetCompilationStatus();
945     for (; (status != Method::COMPILED) && (status != Method::FAILED); status = method->GetCompilationStatus()) {
946         if (status == Method::NOT_COMPILED) {
947             ASSERT(!method->HasCompiledCode());
948             compiler->CompileMethod(method, 0, false, TaggedValue::Hole());
949         }
950         static constexpr uint64_t SLEEP_MS = 10;
951         MTManagedThread::GetCurrent()->TimedWait(ThreadStatus::IS_COMPILER_WAITING, SLEEP_MS, 0);
952     }
953     static constexpr uint8_t COMPILATION_FAILED = 5;
954     return (status == Method::COMPILED ? 0 : COMPILATION_FAILED);
955 }
956 #endif  // PANDA_PRODUCT_BUILD
957 
958 template void Compiler::CompileMethodLocked<compiler::BACKGROUND_MODE>(
959     compiler::CompilerTaskRunner<compiler::BACKGROUND_MODE>);
960 template void Compiler::CompileMethodLocked<compiler::INPLACE_MODE>(
961     compiler::CompilerTaskRunner<compiler::INPLACE_MODE>);
962 template void Compiler::StartCompileMethod<compiler::BACKGROUND_MODE>(
963     compiler::CompilerTaskRunner<compiler::BACKGROUND_MODE>);
964 template void Compiler::StartCompileMethod<compiler::INPLACE_MODE>(
965     compiler::CompilerTaskRunner<compiler::INPLACE_MODE>);
966 
967 }  // namespace panda
968