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