• 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 
31 namespace panda {
32 
33 #ifdef PANDA_COMPILER_CFI
34 namespace compiler {
35 void CleanJitDebugCode();
36 }  // namespace compiler
37 #endif
38 
39 #include <get_intrinsics.inl>
40 
41 class ErrorHandler : public ClassLinkerErrorHandler {
OnError(ClassLinker::Error error,const PandaString & message)42     void OnError([[maybe_unused]] ClassLinker::Error error, [[maybe_unused]] const PandaString &message) override {}
43 };
44 
IsCompilationExpired(const CompilerTask & ctx)45 bool Compiler::IsCompilationExpired(const CompilerTask &ctx)
46 {
47     return (ctx.IsOsr() && GetOsrCode(ctx.GetMethod()) != nullptr) ||
48            (!ctx.IsOsr() && ctx.GetMethod()->HasCompiledCode());
49 }
50 
CompilerProcessor(Compiler * compiler)51 CompilerProcessor::CompilerProcessor(Compiler *compiler)
52 {
53     compiler_ = compiler;
54 }
55 
Process(CompilerTask task)56 bool CompilerProcessor::Process(CompilerTask task)
57 {
58     Method::CompilationStage status = task.GetMethod()->GetCompilationStatus();
59     if (status == Method::WAITING) {
60         // It is possible when main thread compile the mathod without queue
61         if (task.GetMethod()->AtomicSetCompilationStatus(Method::WAITING, Method::COMPILATION)) {
62             compiler_->CompileMethodLocked(task);
63         }
64     }
65     return true;
66 }
67 
ResolveMethodIndex(MethodPtr parent_method,MethodIndex index) const68 compiler::RuntimeInterface::MethodId PandaRuntimeInterface::ResolveMethodIndex(MethodPtr parent_method,
69                                                                                MethodIndex index) const
70 {
71     return MethodCast(parent_method)->GetClass()->ResolveMethodIndex(index).GetOffset();
72 }
73 
ResolveFieldIndex(MethodPtr parent_method,FieldIndex index) const74 compiler::RuntimeInterface::FieldId PandaRuntimeInterface::ResolveFieldIndex(MethodPtr parent_method,
75                                                                              FieldIndex index) const
76 {
77     return MethodCast(parent_method)->GetClass()->ResolveFieldIndex(index).GetOffset();
78 }
79 
ResolveTypeIndex(MethodPtr parent_method,TypeIndex index) const80 compiler::RuntimeInterface::IdType PandaRuntimeInterface::ResolveTypeIndex(MethodPtr parent_method,
81                                                                            TypeIndex index) const
82 {
83     return MethodCast(parent_method)->GetClass()->ResolveClassIndex(index).GetOffset();
84 }
85 
GetMethodById(MethodPtr parent_method,MethodId id) const86 compiler::RuntimeInterface::MethodPtr PandaRuntimeInterface::GetMethodById(MethodPtr parent_method, MethodId id) const
87 {
88     ScopedMutatorLock lock;
89     ErrorHandler error_handler;
90     return Runtime::GetCurrent()->GetClassLinker()->GetMethod(*MethodCast(parent_method),
91                                                               panda_file::File::EntityId(id), &error_handler);
92 }
93 
GetMethodId(MethodPtr method) const94 compiler::RuntimeInterface::MethodId PandaRuntimeInterface::GetMethodId(MethodPtr method) const
95 {
96     return MethodCast(method)->GetFileId().GetOffset();
97 }
98 
GetIntrinsicId(MethodPtr method) const99 compiler::RuntimeInterface::IntrinsicId PandaRuntimeInterface::GetIntrinsicId(MethodPtr method) const
100 {
101     return GetIntrinsicEntryPointId(MethodCast(method)->GetIntrinsic());
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 
GetClass(MethodPtr method,IdType id) const119 compiler::RuntimeInterface::ClassPtr PandaRuntimeInterface::GetClass(MethodPtr method, IdType id) const
120 {
121     ScopedMutatorLock lock;
122     auto *caller = MethodCast(method);
123     LanguageContext ctx = Runtime::GetCurrent()->GetLanguageContext(*caller);
124     ErrorHandler handler;
125     return Runtime::GetCurrent()->GetClassLinker()->GetExtension(ctx)->GetClass(
126         *caller->GetPandaFile(), panda_file::File::EntityId(id), caller->GetClass()->GetLoadContext(), &handler);
127 }
128 
GetStringClass(MethodPtr method) const129 compiler::RuntimeInterface::ClassPtr PandaRuntimeInterface::GetStringClass(MethodPtr method) const
130 {
131     ScopedMutatorLock lock;
132     auto *caller = MethodCast(method);
133     LanguageContext ctx = Runtime::GetCurrent()->GetLanguageContext(*caller);
134     return Runtime::GetCurrent()->GetClassLinker()->GetExtension(ctx)->GetClassRoot(ClassRoot::STRING);
135 }
136 
GetClassType(MethodPtr method,IdType id) const137 compiler::ClassType PandaRuntimeInterface::GetClassType(MethodPtr method, IdType id) const
138 {
139     if (method == nullptr) {
140         return compiler::ClassType::UNRESOLVED_CLASS;
141     }
142     ScopedMutatorLock lock;
143     auto *caller = MethodCast(method);
144     LanguageContext ctx = Runtime::GetCurrent()->GetLanguageContext(*caller);
145     ErrorHandler handler;
146     auto klass = Runtime::GetCurrent()->GetClassLinker()->GetExtension(ctx)->GetClass(
147         *caller->GetPandaFile(), panda_file::File::EntityId(id), caller->GetClass()->GetLoadContext(), &handler);
148     if (klass == nullptr) {
149         return compiler::ClassType::UNRESOLVED_CLASS;
150     }
151     if (klass->IsObjectClass()) {
152         return compiler::ClassType::OBJECT_CLASS;
153     }
154     if (klass->IsInterface()) {
155         return compiler::ClassType::INTERFACE_CLASS;
156     }
157     if (klass->IsArrayClass()) {
158         auto component_class = klass->GetComponentType();
159         ASSERT(component_class != nullptr);
160         if (component_class->IsObjectClass()) {
161             return compiler::ClassType::ARRAY_OBJECT_CLASS;
162         }
163         if (component_class->IsPrimitive()) {
164             return compiler::ClassType::FINAL_CLASS;
165         }
166         return compiler::ClassType::ARRAY_CLASS;
167     }
168     if (klass->IsFinal()) {
169         return compiler::ClassType::FINAL_CLASS;
170     }
171     return compiler::ClassType::OTHER_CLASS;
172 }
173 
IsArrayClass(MethodPtr method,IdType id) const174 bool PandaRuntimeInterface::IsArrayClass(MethodPtr method, IdType id) const
175 {
176     panda_file::File::EntityId cid(id);
177     auto *pf = MethodCast(method)->GetPandaFile();
178     return ClassHelper::IsArrayDescriptor(pf->GetStringData(cid).data);
179 }
180 
GetArrayElementClass(ClassPtr cls) const181 compiler::RuntimeInterface::ClassPtr PandaRuntimeInterface::GetArrayElementClass(ClassPtr cls) const
182 {
183     ScopedMutatorLock lock;
184     ASSERT(ClassCast(cls)->IsArrayClass());
185     return ClassCast(cls)->GetComponentType();
186 }
187 
CheckStoreArray(ClassPtr array_cls,ClassPtr str_cls) const188 bool PandaRuntimeInterface::CheckStoreArray(ClassPtr array_cls, ClassPtr str_cls) const
189 {
190     ASSERT(array_cls != nullptr);
191     auto *element_class = ClassCast(array_cls)->GetComponentType();
192     if (str_cls == nullptr) {
193         return element_class->IsObjectClass();
194     }
195     ASSERT(str_cls != nullptr);
196     return element_class->IsAssignableFrom(ClassCast(str_cls));
197 }
198 
IsAssignableFrom(ClassPtr cls1,ClassPtr cls2) const199 bool PandaRuntimeInterface::IsAssignableFrom(ClassPtr cls1, ClassPtr cls2) const
200 {
201     ASSERT(cls1 != nullptr);
202     ASSERT(cls2 != nullptr);
203     return ClassCast(cls1)->IsAssignableFrom(ClassCast(cls2));
204 }
205 
IsInterfaceMethod(MethodPtr parent_method,MethodId id) const206 bool PandaRuntimeInterface::IsInterfaceMethod(MethodPtr parent_method, MethodId id) const
207 {
208     ScopedMutatorLock lock;
209     ErrorHandler handler;
210     auto method = Runtime::GetCurrent()->GetClassLinker()->GetMethod(*MethodCast(parent_method),
211                                                                      panda_file::File::EntityId(id), &handler);
212     return (method->GetClass()->IsInterface() && !method->IsDefaultInterfaceMethod());
213 }
214 
CanThrowException(MethodPtr method) const215 bool PandaRuntimeInterface::CanThrowException(MethodPtr method) const
216 {
217     ScopedMutatorLock lock;
218     auto *panda_method = MethodCast(method);
219     LanguageContext ctx = Runtime::GetCurrent()->GetLanguageContext(*panda_method);
220     return Runtime::GetCurrent()->GetClassLinker()->GetExtension(ctx)->CanThrowException(panda_method);
221 }
IsInterfaceMethod(MethodPtr method) const222 bool PandaRuntimeInterface::IsInterfaceMethod(MethodPtr method) const
223 {
224     ScopedMutatorLock lock;
225     return (MethodCast(method)->GetClass()->IsInterface() && !MethodCast(method)->IsDefaultInterfaceMethod());
226 }
227 
HasNativeException(MethodPtr method) const228 bool PandaRuntimeInterface::HasNativeException(MethodPtr method) const
229 {
230     if (!MethodCast(method)->IsNative()) {
231         return false;
232     }
233     return CanThrowException(method);
234 }
235 
IsMethodExternal(MethodPtr parent_method,MethodPtr callee_method) const236 bool PandaRuntimeInterface::IsMethodExternal(MethodPtr parent_method, MethodPtr callee_method) const
237 {
238     if (callee_method == nullptr) {
239         return true;
240     }
241     return MethodCast(parent_method)->GetPandaFile() != MethodCast(callee_method)->GetPandaFile();
242 }
243 
GetMethodReturnType(MethodPtr parent_method,MethodId id) const244 compiler::DataType::Type PandaRuntimeInterface::GetMethodReturnType(MethodPtr parent_method, MethodId id) const
245 {
246     auto *pf = MethodCast(parent_method)->GetPandaFile();
247     panda_file::MethodDataAccessor mda(*pf, panda_file::File::EntityId(id));
248     panda_file::ProtoDataAccessor pda(*pf, mda.GetProtoId());
249     return ToCompilerType(panda_file::GetEffectiveType(pda.GetReturnType()));
250 }
251 
GetMethodArgumentType(MethodPtr parent_method,MethodId id,size_t index) const252 compiler::DataType::Type PandaRuntimeInterface::GetMethodArgumentType(MethodPtr parent_method, MethodId id,
253                                                                       size_t index) const
254 {
255     auto *pf = MethodCast(parent_method)->GetPandaFile();
256     panda_file::MethodDataAccessor mda(*pf, panda_file::File::EntityId(id));
257     panda_file::ProtoDataAccessor pda(*pf, mda.GetProtoId());
258     return ToCompilerType(panda_file::GetEffectiveType(pda.GetArgType(index)));
259 }
260 
GetMethodArgumentsCount(MethodPtr parent_method,MethodId id) const261 size_t PandaRuntimeInterface::GetMethodArgumentsCount(MethodPtr parent_method, MethodId id) const
262 {
263     auto *pf = MethodCast(parent_method)->GetPandaFile();
264     panda_file::MethodDataAccessor mda(*pf, panda_file::File::EntityId(id));
265     panda_file::ProtoDataAccessor pda(*pf, mda.GetProtoId());
266     return pda.GetNumArgs();
267 }
268 
IsMethodStatic(MethodPtr parent_method,MethodId id) const269 bool PandaRuntimeInterface::IsMethodStatic(MethodPtr parent_method, MethodId id) const
270 {
271     auto *pf = MethodCast(parent_method)->GetPandaFile();
272     panda_file::MethodDataAccessor mda(*pf, panda_file::File::EntityId(id));
273     return mda.IsStatic();
274 }
275 
IsMethodStatic(MethodPtr method) const276 bool PandaRuntimeInterface::IsMethodStatic(MethodPtr method) const
277 {
278     return MethodCast(method)->IsStatic();
279 }
280 
IsMethodStaticConstructor(MethodPtr method) const281 bool PandaRuntimeInterface::IsMethodStaticConstructor(MethodPtr method) const
282 {
283     return MethodCast(method)->IsStaticConstructor();
284 }
285 
IsMemoryBarrierRequired(MethodPtr method) const286 bool PandaRuntimeInterface::IsMemoryBarrierRequired(MethodPtr method) const
287 {
288     if (!MethodCast(method)->IsInstanceConstructor()) {
289         return false;
290     }
291     for (auto &field : MethodCast(method)->GetClass()->GetFields()) {
292         if (field.IsFinal()) {
293             return true;
294         }
295     }
296     return false;
297 }
298 
IsMethodIntrinsic(MethodPtr parent_method,MethodId id) const299 bool PandaRuntimeInterface::IsMethodIntrinsic(MethodPtr parent_method, MethodId id) const
300 {
301     Method *caller = MethodCast(parent_method);
302     auto *pf = caller->GetPandaFile();
303     panda_file::MethodDataAccessor mda(*pf, panda_file::File::EntityId(id));
304 
305     auto *class_name = pf->GetStringData(mda.GetClassId()).data;
306     auto *class_linker = Runtime::GetCurrent()->GetClassLinker();
307 
308     auto *klass = class_linker->FindLoadedClass(class_name, caller->GetClass()->GetLoadContext());
309 
310     // Class should be loaded during intrinsics initialization
311     if (klass == nullptr) {
312         return false;
313     }
314 
315     auto name = pf->GetStringData(mda.GetNameId());
316     bool is_array_clone = ClassHelper::IsArrayDescriptor(class_name) &&
317                           (utf::CompareMUtf8ToMUtf8(name.data, utf::CStringAsMutf8("clone")) == 0);
318     Method::Proto proto(*pf, mda.GetProtoId());
319     auto *method = klass->GetDirectMethod(name.data, proto);
320     if (method == nullptr) {
321         if (is_array_clone) {
322             method = klass->GetClassMethod(name.data, proto);
323         } else {
324             return false;
325         }
326     }
327 
328     return method->IsIntrinsic();
329 }
330 
GetBytecodeString(MethodPtr method,uintptr_t pc) const331 std::string PandaRuntimeInterface::GetBytecodeString(MethodPtr method, uintptr_t pc) const
332 {
333     // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
334     BytecodeInstruction inst(MethodCast(method)->GetInstructions() + pc);
335     std::stringstream ss;
336     ss << inst;
337     return ss.str();
338 }
339 
ResolveField(PandaRuntimeInterface::MethodPtr m,size_t id,bool allow_external,uint32_t * pclass_id)340 PandaRuntimeInterface::FieldPtr PandaRuntimeInterface::ResolveField(PandaRuntimeInterface::MethodPtr m, size_t id,
341                                                                     bool allow_external, uint32_t *pclass_id)
342 {
343     ScopedMutatorLock lock;
344     ErrorHandler handler;
345     auto method = MethodCast(m);
346     auto pfile = method->GetPandaFile();
347     auto field = Runtime::GetCurrent()->GetClassLinker()->GetField(*method, panda_file::File::EntityId(id), &handler);
348     if (field == nullptr) {
349         return nullptr;
350     }
351     auto klass = field->GetClass();
352     if (pfile == field->GetPandaFile() || allow_external) {
353         if (pclass_id != nullptr) {
354             *pclass_id = klass->GetFileId().GetOffset();
355         }
356         return field;
357     }
358 
359     auto class_id = GetClassIdWithinFile(m, klass);
360     if (class_id != 0) {
361         if (pclass_id != nullptr) {
362             *pclass_id = class_id;
363         }
364         return field;
365     }
366     return nullptr;
367 }
368 
369 template <typename T>
FillLiteralArrayData(const panda_file::File * pfile,pandasm::LiteralArray * lit_array,const panda_file::LiteralTag & tag,const panda_file::LiteralDataAccessor::LiteralValue & value)370 void FillLiteralArrayData(const panda_file::File *pfile, pandasm::LiteralArray *lit_array,
371                           const panda_file::LiteralTag &tag, const panda_file::LiteralDataAccessor::LiteralValue &value)
372 {
373     panda_file::File::EntityId id(std::get<uint32_t>(value));
374     auto sp = pfile->GetSpanFromId(id);
375     auto len = panda_file::helpers::Read<sizeof(uint32_t)>(&sp);
376 
377     for (size_t i = 0; i < len; i++) {
378         pandasm::LiteralArray::Literal lit;
379         lit.tag_ = tag;
380         lit.value_ = bit_cast<T>(panda_file::helpers::Read<sizeof(T)>(&sp));
381         lit_array->literals_.push_back(lit);
382     }
383 }
384 
GetLiteralArray(MethodPtr m,LiteralArrayId id) const385 panda::pandasm::LiteralArray PandaRuntimeInterface::GetLiteralArray(MethodPtr m, LiteralArrayId id) const
386 {
387     auto method = MethodCast(m);
388     auto pfile = method->GetPandaFile();
389     pandasm::LiteralArray lit_array;
390 
391     panda_file::LiteralDataAccessor lit_array_accessor(*pfile, pfile->GetLiteralArraysId());
392     lit_array_accessor.EnumerateLiteralVals(
393         panda_file::File::EntityId(id), [&lit_array, pfile](const panda_file::LiteralDataAccessor::LiteralValue &value,
394                                                             const panda_file::LiteralTag &tag) {
395             switch (tag) {
396                 case panda_file::LiteralTag::ARRAY_U1: {
397                     FillLiteralArrayData<bool>(pfile, &lit_array, tag, value);
398                     break;
399                 }
400                 case panda_file::LiteralTag::ARRAY_I8:
401                 case panda_file::LiteralTag::ARRAY_U8: {
402                     FillLiteralArrayData<uint8_t>(pfile, &lit_array, tag, value);
403                     break;
404                 }
405                 case panda_file::LiteralTag::ARRAY_I16:
406                 case panda_file::LiteralTag::ARRAY_U16: {
407                     FillLiteralArrayData<uint16_t>(pfile, &lit_array, tag, value);
408                     break;
409                 }
410                 // in the case of ARRAY_STRING, the array stores strings ids
411                 case panda_file::LiteralTag::ARRAY_STRING:
412                 case panda_file::LiteralTag::ARRAY_I32:
413                 case panda_file::LiteralTag::ARRAY_U32: {
414                     FillLiteralArrayData<uint32_t>(pfile, &lit_array, tag, value);
415                     break;
416                 }
417                 case panda_file::LiteralTag::ARRAY_I64:
418                 case panda_file::LiteralTag::ARRAY_U64: {
419                     FillLiteralArrayData<uint64_t>(pfile, &lit_array, tag, value);
420                     break;
421                 }
422                 case panda_file::LiteralTag::ARRAY_F32: {
423                     FillLiteralArrayData<float>(pfile, &lit_array, tag, value);
424                     break;
425                 }
426                 case panda_file::LiteralTag::ARRAY_F64: {
427                     FillLiteralArrayData<double>(pfile, &lit_array, tag, value);
428                     break;
429                 }
430                 case panda_file::LiteralTag::TAGVALUE:
431                 case panda_file::LiteralTag::ACCESSOR:
432                 case panda_file::LiteralTag::NULLVALUE: {
433                     break;
434                 }
435                 default: {
436                     UNREACHABLE();
437                     break;
438                 }
439             }
440         });
441     return lit_array;
442 }
443 
FindClassIdInFile(MethodPtr method,ClassPtr cls) const444 std::optional<RuntimeInterface::IdType> PandaRuntimeInterface::FindClassIdInFile(MethodPtr method, ClassPtr cls) const
445 {
446     auto klass = ClassCast(cls);
447     auto pfile = MethodCast(method)->GetPandaFile();
448     auto class_name = klass->GetName();
449     PandaString storage;
450     auto class_id = pfile->GetClassId(ClassHelper::GetDescriptor(utf::CStringAsMutf8(class_name.c_str()), &storage));
451     if (class_id.IsValid() && class_name == ClassHelper::GetName(pfile->GetStringData(class_id).data)) {
452         return std::optional<RuntimeInterface::IdType>(class_id.GetOffset());
453     }
454     return std::nullopt;
455 }
456 
GetClassIdWithinFile(MethodPtr method,ClassPtr cls) const457 RuntimeInterface::IdType PandaRuntimeInterface::GetClassIdWithinFile(MethodPtr method, ClassPtr cls) const
458 {
459     auto class_id = FindClassIdInFile(method, cls);
460     return class_id ? class_id.value() : 0;
461 }
462 
GetLiteralArrayClassIdWithinFile(PandaRuntimeInterface::MethodPtr method,panda_file::LiteralTag tag) const463 RuntimeInterface::IdType PandaRuntimeInterface::GetLiteralArrayClassIdWithinFile(
464     PandaRuntimeInterface::MethodPtr method, panda_file::LiteralTag tag) const
465 {
466     ScopedMutatorLock lock;
467     ErrorHandler handler;
468     auto ctx = Runtime::GetCurrent()->GetLanguageContext(*MethodCast(method));
469     auto cls = Runtime::GetCurrent()->GetClassRootForLiteralTag(
470         *Runtime::GetCurrent()->GetClassLinker()->GetExtension(ctx), tag);
471 
472     auto pfile = MethodCast(method)->GetPandaFile();
473     auto class_name = cls->GetName();
474     for (decltype(auto) class_raw_id : pfile->GetClasses()) {
475         auto class_id = panda_file::File::EntityId(class_raw_id);
476         if (class_id.IsValid() && class_name == ClassHelper::GetName(pfile->GetStringData(class_id).data)) {
477             return class_id.GetOffset();
478         }
479     }
480     UNREACHABLE();
481 }
482 
CanUseTlabForClass(ClassPtr klass) const483 bool PandaRuntimeInterface::CanUseTlabForClass(ClassPtr klass) const
484 {
485     auto cls = ClassCast(klass);
486     return !Thread::GetCurrent()->GetVM()->GetHeapManager()->IsObjectFinalized(cls) && !cls->IsVariableSize() &&
487            cls->IsInstantiable();
488 }
489 
GetTLABMaxSize() const490 size_t PandaRuntimeInterface::GetTLABMaxSize() const
491 {
492     return Thread::GetCurrent()->GetVM()->GetHeapManager()->GetTLABMaxAllocSize();
493 }
494 
ResolveType(PandaRuntimeInterface::MethodPtr method,size_t id) const495 PandaRuntimeInterface::ClassPtr PandaRuntimeInterface::ResolveType(PandaRuntimeInterface::MethodPtr method,
496                                                                    size_t id) const
497 {
498     ScopedMutatorLock lock;
499     ErrorHandler handler;
500     auto klass = Runtime::GetCurrent()->GetClassLinker()->GetClass(*MethodCast(method), panda_file::File::EntityId(id),
501                                                                    &handler);
502     return klass;
503 }
504 
IsClassInitialized(uintptr_t klass) const505 bool PandaRuntimeInterface::IsClassInitialized(uintptr_t klass) const
506 {
507     return TypeCast(klass)->IsInitialized();
508 }
509 
GetManagedType(uintptr_t klass) const510 uintptr_t PandaRuntimeInterface::GetManagedType(uintptr_t klass) const
511 {
512     return reinterpret_cast<uintptr_t>(TypeCast(klass)->GetManagedObject());
513 }
514 
GetFieldType(FieldPtr field) const515 compiler::DataType::Type PandaRuntimeInterface::GetFieldType(FieldPtr field) const
516 {
517     return ToCompilerType(FieldCast(field)->GetType());
518 }
519 
GetFieldTypeById(MethodPtr parent_method,IdType id) const520 compiler::DataType::Type PandaRuntimeInterface::GetFieldTypeById(MethodPtr parent_method, IdType id) const
521 {
522     auto *pf = MethodCast(parent_method)->GetPandaFile();
523     panda_file::FieldDataAccessor fda(*pf, panda_file::File::EntityId(id));
524     return ToCompilerType(panda_file::Type::GetTypeFromFieldEncoding(fda.GetType()));
525 }
526 
GetClassForField(FieldPtr field) const527 RuntimeInterface::ClassPtr PandaRuntimeInterface::GetClassForField(FieldPtr field) const
528 {
529     return FieldCast(field)->GetClass();
530 }
531 
GetArrayElementSize(MethodPtr method,IdType id) const532 uint32_t PandaRuntimeInterface::GetArrayElementSize(MethodPtr method, IdType id) const
533 {
534     auto *pf = MethodCast(method)->GetPandaFile();
535     auto *descriptor = pf->GetStringData(panda_file::File::EntityId(id)).data;
536     // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
537     ASSERT(descriptor[0] == '[');
538     // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
539     return Class::GetTypeSize(panda_file::Type::GetTypeIdBySignature(static_cast<char>(descriptor[1])));
540 }
541 
GetPointerToConstArrayData(MethodPtr method,IdType id) const542 uintptr_t PandaRuntimeInterface::GetPointerToConstArrayData(MethodPtr method, IdType id) const
543 {
544     auto *pf = MethodCast(method)->GetPandaFile();
545     return Runtime::GetCurrent()->GetPointerToConstArrayData(*pf, id);
546 }
547 
GetOffsetToConstArrayData(MethodPtr method,IdType id) const548 size_t PandaRuntimeInterface::GetOffsetToConstArrayData(MethodPtr method, IdType id) const
549 {
550     auto *pf = MethodCast(method)->GetPandaFile();
551     auto offset =
552         Runtime::GetCurrent()->GetPointerToConstArrayData(*pf, id) - reinterpret_cast<uintptr_t>(pf->GetBase());
553     return static_cast<size_t>(offset);
554 }
555 
GetFieldOffset(FieldPtr field) const556 size_t PandaRuntimeInterface::GetFieldOffset(FieldPtr field) const
557 {
558     if (!HasFieldMetadata(field)) {
559         return reinterpret_cast<uintptr_t>(field) >> 1U;
560     }
561     return FieldCast(field)->GetOffset();
562 }
563 
GetFieldByOffset(size_t offset) const564 RuntimeInterface::FieldPtr PandaRuntimeInterface::GetFieldByOffset(size_t offset) const
565 {
566     ASSERT(MinimumBitsToStore(offset) < std::numeric_limits<uintptr_t>::digits);
567     return reinterpret_cast<FieldPtr>((offset << 1U) | 1U);
568 }
569 
GetFieldClass(FieldPtr field) const570 uintptr_t PandaRuntimeInterface::GetFieldClass(FieldPtr field) const
571 {
572     return reinterpret_cast<uintptr_t>(FieldCast(field)->GetClass());
573 }
574 
IsFieldVolatile(FieldPtr field) const575 bool PandaRuntimeInterface::IsFieldVolatile(FieldPtr field) const
576 {
577     return FieldCast(field)->IsVolatile();
578 }
579 
HasFieldMetadata(FieldPtr field) const580 bool PandaRuntimeInterface::HasFieldMetadata(FieldPtr field) const
581 {
582     return (reinterpret_cast<uintptr_t>(field) & 1U) == 0;
583 }
584 
GetPreType() const585 panda::mem::BarrierType PandaRuntimeInterface::GetPreType() const
586 {
587     return Thread::GetCurrent()->GetBarrierSet()->GetPreType();
588 }
589 
GetPostType() const590 panda::mem::BarrierType PandaRuntimeInterface::GetPostType() const
591 {
592     return Thread::GetCurrent()->GetBarrierSet()->GetPostType();
593 }
594 
GetBarrierOperand(panda::mem::BarrierPosition barrier_position,std::string_view operand_name) const595 panda::mem::BarrierOperand PandaRuntimeInterface::GetBarrierOperand(panda::mem::BarrierPosition barrier_position,
596                                                                     std::string_view operand_name) const
597 {
598     return Thread::GetCurrent()->GetBarrierSet()->GetBarrierOperand(barrier_position, operand_name);
599 }
600 
GetFunctionTargetOffset(Arch arch) const601 uint32_t PandaRuntimeInterface::GetFunctionTargetOffset([[maybe_unused]] Arch arch) const
602 {
603     // TODO(wengchangcheng): return offset of method in JSFunction
604     return 0;
605 }
606 
GetNativePointerTargetOffset(Arch arch) const607 uint32_t PandaRuntimeInterface::GetNativePointerTargetOffset(Arch arch) const
608 {
609     return cross_values::GetCoretypesNativePointerExternalPointerOffset(arch);
610 }
611 
AddDependency(PandaRuntimeInterface::MethodPtr callee,RuntimeInterface::MethodPtr caller)612 void ClassHierarchyAnalysisWrapper::AddDependency(PandaRuntimeInterface::MethodPtr callee,
613                                                   RuntimeInterface::MethodPtr caller)
614 {
615     Runtime::GetCurrent()->GetCha()->AddDependency(MethodCast(callee), MethodCast(caller));
616 }
617 
618 /**
619  * With 'no-async-jit' compilation inside of c2i bridge can forced and it can trigger GC
620  */
HasSafepointDuringCall() const621 bool PandaRuntimeInterface::HasSafepointDuringCall() const
622 {
623 #ifdef PANDA_PRODUCT_BUILD
624     return false;
625 #else
626     if (Runtime::GetOptions().IsArkAot()) {
627         return false;
628     }
629     return Runtime::GetOptions().IsNoAsyncJit();
630 #endif
631 }
632 
GetClasses(PandaRuntimeInterface::MethodPtr m,uintptr_t pc,ArenaVector<RuntimeInterface::ClassPtr> * classes)633 InlineCachesWrapper::CallKind InlineCachesWrapper::GetClasses(PandaRuntimeInterface::MethodPtr m, uintptr_t pc,
634                                                               ArenaVector<RuntimeInterface::ClassPtr> *classes)
635 {
636     ASSERT(classes != nullptr);
637     classes->clear();
638     auto method = static_cast<Method *>(m);
639     auto profiling_data = method->GetProfilingData();
640     if (profiling_data == nullptr) {
641         return CallKind::UNKNOWN;
642     }
643     auto ic = profiling_data->FindInlineCache(pc);
644     if (ic == nullptr) {
645         return CallKind::UNKNOWN;
646     }
647     auto ic_classes = ic->GetClassesCopy();
648     classes->insert(classes->end(), ic_classes.begin(), ic_classes.end());
649     if (classes->empty()) {
650         return CallKind::UNKNOWN;
651     }
652     if (classes->size() == 1) {
653         return CallKind::MONOMORPHIC;
654     }
655     if (CallSiteInlineCache::IsMegamorphic(reinterpret_cast<Class *>((*classes)[0]))) {
656         return CallKind::MEGAMORPHIC;
657     }
658     return CallKind::POLYMORPHIC;
659 }
660 
AddTableSlot(RuntimeInterface::MethodPtr method,uint32_t type_id,SlotKind kind)661 bool UnresolvedTypesWrapper::AddTableSlot(RuntimeInterface::MethodPtr method, uint32_t type_id, SlotKind kind)
662 {
663     std::pair<uint32_t, UnresolvedTypesInterface::SlotKind> key {type_id, kind};
664     if (slots_.find(method) == slots_.end()) {
665         slots_[method][key] = 0;
666         return true;
667     }
668     auto &table = slots_.at(method);
669     if (table.find(key) == table.end()) {
670         table[key] = 0;
671         return true;
672     }
673     return false;
674 }
675 
GetTableSlot(RuntimeInterface::MethodPtr method,uint32_t type_id,SlotKind kind) const676 uintptr_t UnresolvedTypesWrapper::GetTableSlot(RuntimeInterface::MethodPtr method, uint32_t type_id,
677                                                SlotKind kind) const
678 {
679     ASSERT(slots_.find(method) != slots_.end());
680     auto &table = slots_.at(method);
681     ASSERT(table.find({type_id, kind}) != table.end());
682     return reinterpret_cast<uintptr_t>(&table.at({type_id, kind}));
683 }
684 
CompileMethod(Method * method,uintptr_t bytecode_offset,bool osr)685 bool Compiler::CompileMethod(Method *method, uintptr_t bytecode_offset, bool osr)
686 {
687     if (method->IsAbstract()) {
688         return false;
689     }
690 
691     if (osr && GetOsrCode(method) != nullptr) {
692         ASSERT(method == ManagedThread::GetCurrent()->GetCurrentFrame()->GetMethod());
693         ASSERT(method->HasCompiledCode());
694         return OsrEntry(bytecode_offset, GetOsrCode(method));
695     }
696     // In case if some thread raise compilation when another already compiled it, we just exit.
697     if (method->HasCompiledCode() && !osr) {
698         return false;
699     }
700     CompilerTask ctx {method, method->HasCompiledCode() ? osr : false, ManagedThread::GetCurrent()->GetVM()};
701     CompileMethodAsync(ctx);
702     if (no_async_jit_) {
703         auto status = method->GetCompilationStatus();
704         for (; (status == Method::WAITING) || (status == Method::COMPILATION);
705              status = method->GetCompilationStatus()) {
706             auto thread = MTManagedThread::GetCurrent();
707             // TODO(asoldatov): Remove this workaround for invoking compiler from ECMA VM
708             if (thread != nullptr) {
709                 static constexpr uint64_t SLEEP_MS = 10;
710                 thread->TimedWait(ThreadStatus::IS_COMPILER_WAITING, SLEEP_MS, 0);
711             }
712         }
713     }
714     return false;
715 }
716 
CompileMethodLocked(const CompilerTask & ctx)717 void Compiler::CompileMethodLocked(const CompilerTask &ctx)
718 {
719     ASSERT(runtime_iface_ != nullptr);
720     auto method = ctx.GetMethod();
721     os::memory::LockHolder lock(compilation_lock_);
722 
723     method->ResetHotnessCounter();
724 
725     if (IsCompilationExpired(ctx)) {
726         return;
727     }
728 
729     PandaVM *vm = ctx.GetVM();
730 
731     // Set current thread to have access to vm during compilation
732     Thread compiler_thread(vm, Thread::ThreadType::THREAD_TYPE_COMPILER);
733     ScopedCurrentThread sct(&compiler_thread);
734 
735     mem::MemStatsType *mem_stats = vm->GetMemStats();
736     panda::ArenaAllocator allocator(panda::SpaceType::SPACE_TYPE_COMPILER, mem_stats);
737     panda::ArenaAllocator graph_local_allocator(panda::SpaceType::SPACE_TYPE_COMPILER, mem_stats, true);
738     if (!compiler::JITCompileMethod(runtime_iface_, method, ctx.IsOsr(), code_allocator_, &allocator,
739                                     &graph_local_allocator, &gdb_debug_info_allocator_)) {
740         // Failure during compilation, should we retry later?
741         method->SetCompilationStatus(Method::FAILED);
742         return;
743     }
744     method->SetCompilationStatus(Method::COMPILED);
745 }
746 
747 class ScopedDisableManagedCode {
748 public:
ScopedDisableManagedCode(ManagedThread * thread)749     explicit ScopedDisableManagedCode(ManagedThread *thread)
750         : thread_(thread), was_allowed_(thread->IsManagedCodeAllowed())
751     {
752         thread_->SetManagedCodeAllowed(false);
753     }
754 
~ScopedDisableManagedCode()755     ~ScopedDisableManagedCode()
756     {
757         thread_->SetManagedCodeAllowed(was_allowed_);
758     }
759 
760     NO_COPY_SEMANTIC(ScopedDisableManagedCode);
761     NO_MOVE_SEMANTIC(ScopedDisableManagedCode);
762 
763 private:
764     ManagedThread *thread_;
765     bool was_allowed_;
766 };
767 
CompileMethodSync(const CompilerTask & ctx)768 void Compiler::CompileMethodSync(const CompilerTask &ctx)
769 {
770     auto method = ctx.GetMethod();
771     Method::CompilationStage status = method->GetCompilationStatus();
772     // The main thread compiles the method even if it is inside waiting queue
773     // Note, search inside the queue may be inefficient, so just wait untill it will be handled by worker thread
774     // TODO: in future with more smart queue, we should update it here
775     if (method->AtomicSetCompilationStatus(status, Method::COMPILATION)) {
776         ScopedDisableManagedCode sdmc(ManagedThread::GetCurrent());
777         CompileMethodLocked(ctx);
778     }
779 }
780 
CompileMethodAsync(const CompilerTask & ctx)781 void Compiler::CompileMethodAsync(const CompilerTask &ctx)
782 {
783     // We should enter here only with NOT_COMPILED, so avoid extra check
784     if (ctx.GetMethod()->AtomicSetCompilationStatus(ctx.IsOsr() ? Method::COMPILED : Method::NOT_COMPILED,
785                                                     Method::WAITING)) {
786         AddTask(ctx);
787     }
788 }
789 
JoinWorker()790 void Compiler::JoinWorker()
791 {
792     is_thread_pool_created_ = false;
793     if (thread_pool_ != nullptr) {
794         internal_allocator_->Delete(thread_pool_);
795         thread_pool_ = nullptr;
796     }
797 #ifdef PANDA_COMPILER_CFI
798     if (!Runtime::GetOptions().IsArkAot() && compiler::options.IsCompilerEmitDebugInfo()) {
799         compiler::CleanJitDebugCode();
800     }
801 #endif
802 }
803 
GetNonMovableString(MethodPtr method,StringId id) const804 object_pointer_type PandaRuntimeInterface::GetNonMovableString(MethodPtr method, StringId id) const
805 {
806     auto vm = Runtime::GetCurrent()->GetPandaVM();
807     auto pf = MethodCast(method)->GetPandaFile();
808     return ToObjPtrType(vm->GetNonMovableString(*pf, panda_file::File::EntityId {id}));
809 }
810 
811 }  // namespace panda
812