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