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 #ifndef PANDA_RUNTIME_COMPILER_H_
16 #define PANDA_RUNTIME_COMPILER_H_
17
18 #include "compiler/compile_method.h"
19 #include "compiler/optimizer/ir/runtime_interface.h"
20 #include "libpandabase/mem/code_allocator.h"
21 #include "libpandabase/os/mutex.h"
22 #include "runtime/compiler_queue_aged_counter_priority.h"
23 #include "runtime/compiler_queue_interface.h"
24 #include "runtime/compiler_queue_simple.h"
25 #include "runtime/entrypoints/entrypoints.h"
26 #include "runtime/include/hclass.h"
27 #include "runtime/include/compiler_interface.h"
28 #include "runtime/include/coretypes/array.h"
29 #include "runtime/include/coretypes/tagged_value.h"
30 #include "runtime/include/locks.h"
31 #include "runtime/include/mem/panda_containers.h"
32 #include "runtime/include/method.h"
33 #include "runtime/include/runtime_options.h"
34 #include "runtime/interpreter/frame.h"
35 #include "runtime/mem/gc/gc_barrier_set.h"
36 #include "runtime/mem/tlab.h"
37
38 #include "runtime/thread_pool.h"
39 #include "runtime/osr.h"
40
41 namespace panda {
42
43 using compiler::RuntimeInterface;
44 using compiler::UnresolvedTypesInterface;
45
MethodCast(RuntimeInterface::MethodPtr method)46 inline panda::Method *MethodCast(RuntimeInterface::MethodPtr method)
47 {
48 return static_cast<panda::Method *>(method);
49 }
50
51 struct ScopedMutatorLock : public os::memory::ReadLockHolder<MutatorLock> {
ScopedMutatorLockScopedMutatorLock52 ScopedMutatorLock() : os::memory::ReadLockHolder<MutatorLock>(*Locks::mutator_lock) {}
53 };
54
55 class Compiler;
56
57 class CompilerProcessor : public ProcessorInterface<CompilerTask, Compiler *> {
58 public:
59 explicit CompilerProcessor(Compiler *compiler);
60 bool Process(CompilerTask task) override;
61
62 private:
63 Compiler *compiler_;
64 };
65
66 class ClassHierarchyAnalysisWrapper : public compiler::IClassHierarchyAnalysis {
67 public:
GetSingleImplementation(RuntimeInterface::MethodPtr method)68 RuntimeInterface::MethodPtr GetSingleImplementation(RuntimeInterface::MethodPtr method) override
69 {
70 return static_cast<Method *>(method)->GetSingleImplementation();
71 }
IsSingleImplementation(RuntimeInterface::MethodPtr method)72 bool IsSingleImplementation(RuntimeInterface::MethodPtr method) override
73 {
74 return static_cast<Method *>(method)->HasSingleImplementation();
75 }
76 void AddDependency(RuntimeInterface::MethodPtr callee, RuntimeInterface::MethodPtr caller) override;
77 };
78
79 class InlineCachesWrapper : public compiler::InlineCachesInterface {
80 public:
81 CallKind GetClasses(RuntimeInterface::MethodPtr m, uintptr_t pc,
82 ArenaVector<RuntimeInterface::ClassPtr> *classes) override;
83 };
84
85 class UnresolvedTypesWrapper : public UnresolvedTypesInterface {
86 public:
87 bool AddTableSlot(RuntimeInterface::MethodPtr method, uint32_t type_id, SlotKind kind) override;
88 uintptr_t GetTableSlot(RuntimeInterface::MethodPtr method, uint32_t type_id, SlotKind kind) const override;
89
90 private:
91 PandaMap<RuntimeInterface::MethodPtr, PandaMap<std::pair<uint32_t, SlotKind>, uintptr_t>> slots_;
92 };
93
94 class PandaRuntimeInterface : public RuntimeInterface {
95 public:
GetRuntimeEntry()96 void *GetRuntimeEntry() override
97 {
98 return nullptr;
99 }
100
GetCha()101 compiler::IClassHierarchyAnalysis *GetCha() override
102 {
103 return &cha_;
104 }
105
GetInlineCaches()106 compiler::InlineCachesInterface *GetInlineCaches() override
107 {
108 return &inline_caches_;
109 }
110
GetUnresolvedTypes()111 compiler::UnresolvedTypesInterface *GetUnresolvedTypes() override
112 {
113 return &unresolved_types_;
114 }
115
GetReturnReasonOk()116 unsigned GetReturnReasonOk() const override
117 {
118 return static_cast<unsigned>(CompilerInterface::ReturnReason::RET_OK);
119 }
GetReturnReasonDeopt()120 unsigned GetReturnReasonDeopt() const override
121 {
122 return static_cast<unsigned>(CompilerInterface::ReturnReason::RET_DEOPTIMIZATION);
123 }
124
ClassCast(ClassPtr cls)125 panda::Class *ClassCast(ClassPtr cls) const
126 {
127 return static_cast<panda::Class *>(cls);
128 }
129
GetStackOverflowCheckOffset()130 size_t GetStackOverflowCheckOffset() const override
131 {
132 return ManagedThread::GetStackOverflowCheckOffset();
133 }
134
135 /**************************************************************************
136 * Binary file information
137 */
GetBinaryFileForMethod(MethodPtr method)138 BinaryFilePtr GetBinaryFileForMethod(MethodPtr method) const override
139 {
140 return const_cast<panda_file::File *>(MethodCast(method)->GetPandaFile());
141 }
142
143 MethodId ResolveMethodIndex(MethodPtr parent_method, MethodIndex index) const override;
144
145 FieldId ResolveFieldIndex(MethodPtr parent_method, FieldIndex index) const override;
146
147 IdType ResolveTypeIndex(MethodPtr parent_method, TypeIndex index) const override;
148
149 /**************************************************************************
150 * Method information
151 */
152 MethodPtr GetMethodById(MethodPtr parent_method, MethodId id) const override;
153
154 MethodId GetMethodId(MethodPtr method) const override;
155
156 IntrinsicId GetIntrinsicId([[maybe_unused]] MethodPtr method) const override;
157
158 MethodPtr ResolveVirtualMethod(ClassPtr cls, MethodPtr method) const override;
159
160 MethodPtr ResolveInterfaceMethod(ClassPtr cls, MethodPtr method) const override;
161
GetMethodReturnType(MethodPtr method)162 compiler::DataType::Type GetMethodReturnType(MethodPtr method) const override
163 {
164 return ToCompilerType(MethodCast(method)->GetEffectiveReturnType());
165 }
GetMethodTotalArgumentType(MethodPtr method,size_t index)166 compiler::DataType::Type GetMethodTotalArgumentType(MethodPtr method, size_t index) const override
167 {
168 return ToCompilerType(MethodCast(method)->GetEffectiveArgType(index));
169 }
GetMethodTotalArgumentsCount(MethodPtr method)170 size_t GetMethodTotalArgumentsCount(MethodPtr method) const override
171 {
172 return MethodCast(method)->GetNumArgs();
173 }
174
175 bool IsMemoryBarrierRequired(MethodPtr method) const override;
176
177 compiler::DataType::Type GetMethodReturnType(MethodPtr parent_method, MethodId id) const override;
178
179 compiler::DataType::Type GetMethodArgumentType(MethodPtr parent_method, MethodId id, size_t index) const override;
180
181 size_t GetMethodArgumentsCount(MethodPtr parent_method, MethodId id) const override;
GetMethodArgumentsCount(MethodPtr method)182 size_t GetMethodArgumentsCount(MethodPtr method) const override
183 {
184 return MethodCast(method)->GetNumArgs();
185 }
GetMethodRegistersCount(MethodPtr method)186 size_t GetMethodRegistersCount(MethodPtr method) const override
187 {
188 return MethodCast(method)->GetNumVregs();
189 }
GetMethodCode(MethodPtr method)190 const uint8_t *GetMethodCode(MethodPtr method) const override
191 {
192 return MethodCast(method)->GetInstructions();
193 }
GetMethodCodeSize(MethodPtr method)194 size_t GetMethodCodeSize(MethodPtr method) const override
195 {
196 return MethodCast(method)->GetCodeSize();
197 }
GetMethodSourceLanguage(MethodPtr method)198 compiler::SourceLanguage GetMethodSourceLanguage(MethodPtr method) const override
199 {
200 return static_cast<compiler::SourceLanguage>(MethodCast(method)->GetClass()->GetSourceLang());
201 }
SetCompiledEntryPoint(MethodPtr method,void * ep)202 void SetCompiledEntryPoint(MethodPtr method, void *ep) override
203 {
204 MethodCast(method)->SetCompiledEntryPoint(ep);
205 }
SetOsrCode(MethodPtr method,void * ep)206 void SetOsrCode(MethodPtr method, void *ep) override
207 {
208 CompilerInterface *compiler = Thread::GetCurrent()->GetVM()->GetCompiler();
209 ASSERT(compiler->GetOsrCode(static_cast<const Method *>(method)) == nullptr);
210 compiler->SetOsrCode(static_cast<const Method *>(method), ep);
211 }
GetOsrCode(MethodPtr method)212 void *GetOsrCode(MethodPtr method) override
213 {
214 return Thread::GetCurrent()->GetVM()->GetCompiler()->GetOsrCode(static_cast<const Method *>(method));
215 }
HasCompiledCode(MethodPtr method)216 bool HasCompiledCode(MethodPtr method) override
217 {
218 return MethodCast(method)->HasCompiledCode();
219 }
220
GetAccessFlagAbstractMask()221 uint32_t GetAccessFlagAbstractMask() const override
222 {
223 return panda::ACC_ABSTRACT;
224 }
225
GetVTableIndex(MethodPtr method)226 uint32_t GetVTableIndex(MethodPtr method) const override
227 {
228 return MethodCast(method)->GetVTableIndex();
229 }
230
GetClassIdForField(MethodPtr method,size_t field_id)231 size_t GetClassIdForField(MethodPtr method, size_t field_id) const override
232 {
233 auto fda =
234 panda_file::FieldDataAccessor(*MethodCast(method)->GetPandaFile(), panda_file::File::EntityId(field_id));
235 return fda.GetClassId().GetOffset();
236 }
237
GetClassIdForField(FieldPtr field)238 size_t GetClassIdForField(FieldPtr field) const override
239 {
240 return FieldCast(field)->GetClass()->GetFileId().GetOffset();
241 }
242
243 ClassPtr GetClassForField(FieldPtr field) const override;
244
GetClassIdForMethod(MethodPtr method)245 size_t GetClassIdForMethod(MethodPtr method) const override
246 {
247 auto mda = panda_file::MethodDataAccessor(*MethodCast(method)->GetPandaFile(), MethodCast(method)->GetFileId());
248 return mda.GetClassId().GetOffset();
249 }
250
GetClassIdForMethod(MethodPtr parent_method,size_t method_id)251 size_t GetClassIdForMethod(MethodPtr parent_method, size_t method_id) const override
252 {
253 auto mda = panda_file::MethodDataAccessor(*MethodCast(parent_method)->GetPandaFile(),
254 panda_file::File::EntityId(method_id));
255 return mda.GetClassId().GetOffset();
256 }
257
258 bool HasNativeException(MethodPtr method) const override;
259 bool IsMethodExternal(MethodPtr parent_method, MethodPtr callee_method) const override;
260
IsMethodIntrinsic(MethodPtr method)261 bool IsMethodIntrinsic(MethodPtr method) const override
262 {
263 return MethodCast(method)->IsIntrinsic();
264 }
265
IsMethodAbstract(MethodPtr method)266 bool IsMethodAbstract(MethodPtr method) const override
267 {
268 return MethodCast(method)->IsAbstract();
269 }
270
271 bool IsMethodIntrinsic(MethodPtr parent_method, MethodId id) const override;
272
IsMethodFinal(MethodPtr method)273 bool IsMethodFinal(MethodPtr method) const override
274 {
275 return MethodCast(method)->IsFinal();
276 }
277
278 bool IsMethodStatic(MethodPtr parent_method, MethodId id) const override;
279 bool IsMethodStatic(MethodPtr method) const override;
280
IsMethodCanBeInlined(MethodPtr method)281 bool IsMethodCanBeInlined(MethodPtr method) const override
282 {
283 auto method_ptr = MethodCast(method);
284 return !(method_ptr->IsIntrinsic() || method_ptr->IsNative() || method_ptr->IsAbstract());
285 }
286
287 bool IsMethodStaticConstructor([[maybe_unused]] MethodPtr method) const override;
288
GetFileName(MethodPtr method)289 std::string GetFileName(MethodPtr method) const override
290 {
291 return MethodCast(method)->GetPandaFile()->GetFilename();
292 }
293
GetClassNameFromMethod(MethodPtr method)294 std::string GetClassNameFromMethod(MethodPtr method) const override
295 {
296 ScopedMutatorLock lock;
297 return MethodCast(method)->GetClass()->GetName();
298 }
299
GetClassName(ClassPtr cls)300 std::string GetClassName(ClassPtr cls) const override
301 {
302 ScopedMutatorLock lock;
303 return ClassCast(cls)->GetName();
304 }
305
GetMethodName(MethodPtr method)306 std::string GetMethodName(MethodPtr method) const override
307 {
308 return utf::Mutf8AsCString(MethodCast(method)->GetName().data);
309 }
310
GetBranchTakenCounter(MethodPtr method,uint32_t pc)311 int64_t GetBranchTakenCounter(MethodPtr method, uint32_t pc) const override
312 {
313 return MethodCast(method)->GetBranchTakenCounter(pc);
314 }
315
GetBranchNotTakenCounter(MethodPtr method,uint32_t pc)316 int64_t GetBranchNotTakenCounter(MethodPtr method, uint32_t pc) const override
317 {
318 return MethodCast(method)->GetBranchNotTakenCounter(pc);
319 }
320
GetMethodFullName(MethodPtr method,bool with_signature)321 std::string GetMethodFullName(MethodPtr method, bool with_signature) const override
322 {
323 return std::string(MethodCast(method)->GetFullName(with_signature));
324 }
325
GetClass(MethodPtr method)326 ClassPtr GetClass(MethodPtr method) const override
327 {
328 ScopedMutatorLock lock;
329 return reinterpret_cast<ClassPtr>(MethodCast(method)->GetClass());
330 }
331
332 std::string GetBytecodeString(MethodPtr method, uintptr_t pc) const override;
333
334 panda::pandasm::LiteralArray GetLiteralArray(MethodPtr method, LiteralArrayId id) const override;
335
336 bool IsInterfaceMethod(MethodPtr parent_method, MethodId id) const override;
337
338 bool IsInterfaceMethod(MethodPtr method) const override;
339
IsInstanceConstructor(MethodPtr method)340 bool IsInstanceConstructor(MethodPtr method) const override
341 {
342 return MethodCast(method)->IsInstanceConstructor();
343 }
344
345 bool CanThrowException(MethodPtr method) const override;
346
347 /**************************************************************************
348 * Thread information
349 */
350 ::panda::mem::BarrierType GetPreType() const override;
351
352 ::panda::mem::BarrierType GetPostType() const override;
353
354 ::panda::mem::BarrierOperand GetBarrierOperand(::panda::mem::BarrierPosition barrier_position,
355 std::string_view operand_name) const override;
356
357 /**************************************************************************
358 * Array information
359 */
360 uint32_t GetArrayElementSize(MethodPtr method, IdType id) const override;
361
362 uintptr_t GetPointerToConstArrayData(MethodPtr method, IdType id) const override;
363
364 size_t GetOffsetToConstArrayData(MethodPtr method, IdType id) const override;
365
366 /**************************************************************************
367 * String information
368 */
IsCompressedStringsEnabled()369 bool IsCompressedStringsEnabled() const override
370 {
371 return panda::coretypes::String::GetCompressedStringsEnabled();
372 }
373
374 object_pointer_type GetNonMovableString(MethodPtr method, StringId id) const override;
375
376 ClassPtr GetStringClass(MethodPtr method) const override;
377
378 /**************************************************************************
379 * TLAB information
380 */
381 size_t GetTLABMaxSize() const override;
382
GetTLABAlignment()383 size_t GetTLABAlignment() const override
384 {
385 return DEFAULT_ALIGNMENT_IN_BYTES;
386 }
387
IsTrackTlabAlloc()388 bool IsTrackTlabAlloc() const override
389 {
390 return panda::mem::PANDA_TRACK_TLAB_ALLOCATIONS;
391 }
392
393 /**************************************************************************
394 * Object information
395 */
396 ClassPtr GetClass(MethodPtr method, IdType id) const override;
397
398 compiler::ClassType GetClassType(MethodPtr method, IdType id) const override;
399
400 bool IsArrayClass(MethodPtr method, IdType id) const override;
401
IsArrayClass(ClassPtr cls)402 bool IsArrayClass(ClassPtr cls) const override
403 {
404 return ClassCast(cls)->IsArrayClass();
405 }
406
407 ClassPtr GetArrayElementClass(ClassPtr cls) const override;
408
409 bool CheckStoreArray(ClassPtr array_cls, ClassPtr str_cls) const override;
410
411 bool IsAssignableFrom(ClassPtr cls1, ClassPtr cls2) const override;
412
GetObjectHashedStatusBitNum()413 size_t GetObjectHashedStatusBitNum() const override
414 {
415 static_assert(MarkWord::MarkWordRepresentation::STATUS_SIZE == 2);
416 static_assert(MarkWord::MarkWordRepresentation::STATUS_HASHED == 2);
417 // preconditions above allow just check one bit
418 return MarkWord::MarkWordRepresentation::STATUS_SHIFT + 1;
419 }
420
GetObjectHashShift()421 size_t GetObjectHashShift() const override
422 {
423 return MarkWord::MarkWordRepresentation::HASH_SHIFT;
424 }
425
GetObjectHashMask()426 size_t GetObjectHashMask() const override
427 {
428 return MarkWord::MarkWordRepresentation::HASH_MASK;
429 }
430
431 /**************************************************************************
432 * Class information
433 */
GetClassInitializedValue()434 uint8_t GetClassInitializedValue() const override
435 {
436 return static_cast<uint8_t>(panda::Class::State::INITIALIZED);
437 }
438
439 std::optional<IdType> FindClassIdInFile(MethodPtr method, ClassPtr cls) const;
440 IdType GetClassIdWithinFile(MethodPtr method, ClassPtr cls) const override;
441 IdType GetLiteralArrayClassIdWithinFile(MethodPtr method, panda_file::LiteralTag tag) const override;
442 bool CanUseTlabForClass(ClassPtr klass) const override;
443
GetClassSize(ClassPtr klass)444 size_t GetClassSize(ClassPtr klass) const override
445 {
446 return ClassCast(klass)->GetObjectSize();
447 }
448
449 /**************************************************************************
450 * Field information
451 */
452
453 FieldPtr ResolveField(MethodPtr method, size_t id, bool allow_external, uint32_t *class_id) override;
454 compiler::DataType::Type GetFieldType(FieldPtr field) const override;
455 compiler::DataType::Type GetFieldTypeById(MethodPtr parent_method, IdType id) const override;
456 size_t GetFieldOffset(FieldPtr field) const override;
457 FieldPtr GetFieldByOffset(size_t offset) const override;
458 uintptr_t GetFieldClass(FieldPtr field) const override;
459 bool IsFieldVolatile(FieldPtr field) const override;
460 bool HasFieldMetadata(FieldPtr field) const override;
461
GetFieldName(FieldPtr field)462 std::string GetFieldName(FieldPtr field) const override
463 {
464 return utf::Mutf8AsCString(FieldCast(field)->GetName().data);
465 }
466
FieldCast(FieldPtr field)467 panda::Field *FieldCast(FieldPtr field) const
468 {
469 ASSERT(HasFieldMetadata(field));
470 return static_cast<panda::Field *>(field);
471 }
472
473 /**************************************************************************
474 * Type information
475 */
476
477 PandaRuntimeInterface::ClassPtr ResolveType(MethodPtr method, size_t id) const override;
478
479 bool IsClassInitialized(uintptr_t klass) const override;
480
IsClassFinal(ClassPtr klass)481 bool IsClassFinal(ClassPtr klass) const override
482 {
483 return ClassCast(klass)->IsFinal();
484 }
485
486 uintptr_t GetManagedType(uintptr_t klass) const override;
487
TypeCast(uintptr_t klass)488 panda::Class *TypeCast(uintptr_t klass) const
489 {
490 return reinterpret_cast<panda::Class *>(klass);
491 }
492
GetReferenceTypeMask()493 uint8_t GetReferenceTypeMask() const override
494 {
495 return static_cast<uint8_t>(panda_file::Type::TypeId::REFERENCE);
496 }
497
498 /**************************************************************************
499 * Entrypoints
500 */
501 uintptr_t GetIntrinsicAddress(bool runtime_call, IntrinsicId id) const override;
502
503 /**************************************************************************
504 * Dynamic object information
505 */
506
507 uint32_t GetFunctionTargetOffset(Arch arch) const override;
508
GetDynamicPrimitiveUndefined()509 uint64_t GetDynamicPrimitiveUndefined() const override
510 {
511 return static_cast<uint64_t>(coretypes::TaggedValue::Undefined().GetRawData());
512 }
513
GetDynamicPrimitiveFalse()514 uint64_t GetDynamicPrimitiveFalse() const override
515 {
516 return static_cast<uint64_t>(coretypes::TaggedValue::False().GetRawData());
517 }
518
GetDynamicPrimitiveTrue()519 uint64_t GetDynamicPrimitiveTrue() const override
520 {
521 return static_cast<uint64_t>(coretypes::TaggedValue::True().GetRawData());
522 }
523
524 uint32_t GetNativePointerTargetOffset(Arch arch) const override;
525
526 bool HasSafepointDuringCall() const override;
527
528 private:
ToCompilerType(panda_file::Type type)529 static compiler::DataType::Type ToCompilerType(panda_file::Type type)
530 {
531 switch (type.GetId()) {
532 case panda_file::Type::TypeId::VOID:
533 return compiler::DataType::VOID;
534 case panda_file::Type::TypeId::U1:
535 return compiler::DataType::BOOL;
536 case panda_file::Type::TypeId::I8:
537 return compiler::DataType::INT8;
538 case panda_file::Type::TypeId::U8:
539 return compiler::DataType::UINT8;
540 case panda_file::Type::TypeId::I16:
541 return compiler::DataType::INT16;
542 case panda_file::Type::TypeId::U16:
543 return compiler::DataType::UINT16;
544 case panda_file::Type::TypeId::I32:
545 return compiler::DataType::INT32;
546 case panda_file::Type::TypeId::U32:
547 return compiler::DataType::UINT32;
548 case panda_file::Type::TypeId::I64:
549 return compiler::DataType::INT64;
550 case panda_file::Type::TypeId::U64:
551 return compiler::DataType::UINT64;
552 case panda_file::Type::TypeId::F32:
553 return compiler::DataType::FLOAT32;
554 case panda_file::Type::TypeId::F64:
555 return compiler::DataType::FLOAT64;
556 case panda_file::Type::TypeId::REFERENCE:
557 return compiler::DataType::REFERENCE;
558 case panda_file::Type::TypeId::TAGGED:
559 return compiler::DataType::ANY;
560 default:
561 break;
562 }
563 UNREACHABLE();
564 }
565
566 private:
567 ClassHierarchyAnalysisWrapper cha_;
568 InlineCachesWrapper inline_caches_;
569 UnresolvedTypesWrapper unresolved_types_;
570 };
571
572 class Compiler : public CompilerInterface {
573 public:
Compiler(CodeAllocator * code_allocator,mem::InternalAllocatorPtr internal_allocator,const RuntimeOptions & options,mem::MemStatsType * mem_stats,compiler::RuntimeInterface * runtime_iface)574 explicit Compiler(CodeAllocator *code_allocator, mem::InternalAllocatorPtr internal_allocator,
575 const RuntimeOptions &options, mem::MemStatsType *mem_stats,
576 compiler::RuntimeInterface *runtime_iface)
577 : code_allocator_(code_allocator),
578 internal_allocator_(internal_allocator),
579 gdb_debug_info_allocator_(panda::SpaceType::SPACE_TYPE_COMPILER, mem_stats),
580 runtime_iface_(runtime_iface)
581 {
582 no_async_jit_ = options.IsNoAsyncJit();
583
584 thread_pool_ = nullptr;
585 if (options.IsArkAot()) {
586 return;
587 }
588
589 queue_ = CreateJITTaskQueue(no_async_jit_ ? "simple" : options.GetCompilerQueueType(),
590 options.GetCompilerQueueMaxLength(), options.GetCompilerTaskLifeSpan(),
591 options.GetCompilerDeathCounterValue(), options.GetCompilerEpochDuration());
592 if (queue_ == nullptr) {
593 // Because of problems (no memory) in allocator
594 LOG(ERROR, COMPILER) << "Cannot create a compiler queue";
595 no_async_jit_ = true;
596 }
597 CreateWorker();
598 }
599
PreZygoteFork()600 void PreZygoteFork() override
601 {
602 JoinWorker();
603 }
604
PostZygoteFork()605 void PostZygoteFork() override
606 {
607 CreateWorker();
608 }
609
Destroy()610 void Destroy() override
611 {
612 JoinWorker();
613 }
614
615 bool IsCompilationExpired(const CompilerTask &ctx);
616
~Compiler()617 ~Compiler() override
618 {
619 // We need to join thread first if runtime initialization fails and Destroy is not called
620 Destroy();
621 if (queue_ != nullptr) {
622 queue_->Finalize();
623 internal_allocator_->Delete(queue_);
624 }
625 }
626
627 bool CompileMethod(Method *method, uintptr_t bytecode_offset, bool osr) override;
628
AddTask(CompilerTask task)629 void AddTask(CompilerTask task)
630 {
631 if (!is_thread_pool_created_) {
632 // BUG: thread pool was not created
633 LOG(ERROR, COMPILER) << "Thread pool for compilation threads was not created";
634 return;
635 }
636 thread_pool_->PutTask(task);
637 }
638
639 /**
640 * Basic method, which starts compilation. Do not use.
641 */
642 void CompileMethodLocked(const CompilerTask &ctx);
643
ScaleThreadPool(size_t number_of_threads)644 void ScaleThreadPool(size_t number_of_threads)
645 {
646 // Required for testing
647 thread_pool_->Scale(number_of_threads);
648 }
649
GetOsrCode(const Method * method)650 void *GetOsrCode(const Method *method) override
651 {
652 return osr_code_map_.Get(method);
653 }
654
SetOsrCode(const Method * method,void * ptr)655 void SetOsrCode(const Method *method, void *ptr) override
656 {
657 osr_code_map_.Set(method, ptr);
658 }
659
RemoveOsrCode(const Method * method)660 void RemoveOsrCode(const Method *method) override
661 {
662 osr_code_map_.Remove(method);
663 }
664
665 private:
666 /**
667 * Add a method as a compilation task into a queue.
668 * The compilation will be performed in a worker thread
669 */
670 void CompileMethodAsync(const CompilerTask &ctx);
671
672 /**
673 * Performs compilation in the main thread
674 */
675 void CompileMethodSync(const CompilerTask &ctx);
676
CreateJITTaskQueue(const std::string & queue_type,uint64_t max_length,uint64_t task_life,uint64_t death_counter,uint64_t epoch_duration)677 CompilerQueueInterface *CreateJITTaskQueue(const std::string &queue_type, uint64_t max_length, uint64_t task_life,
678 uint64_t death_counter, uint64_t epoch_duration)
679 {
680 LOG(DEBUG, COMPILER) << "Creating " << queue_type << " task queue";
681 if (queue_type == "simple") {
682 return internal_allocator_->New<CompilerQueueSimple>(internal_allocator_);
683 }
684 if (queue_type == "counter-priority") {
685 return internal_allocator_->New<CompilerPriorityCounterQueue>(internal_allocator_, max_length, task_life);
686 }
687 if (queue_type == "aged-counter-priority") {
688 return internal_allocator_->New<CompilerPriorityAgedCounterQueue>(internal_allocator_, task_life,
689 death_counter, epoch_duration);
690 }
691 LOG(FATAL, COMPILER) << "Unknown queue type";
692 return nullptr;
693 }
694
695 void JoinWorker();
696
CreateWorker()697 void CreateWorker()
698 {
699 if (thread_pool_ == nullptr) {
700 thread_pool_ = internal_allocator_->New<ThreadPool<CompilerTask, CompilerProcessor, Compiler *>>(
701 internal_allocator_, queue_, this, 1, "JIT Thread");
702 }
703 is_thread_pool_created_ = true;
704 }
705
706 CodeAllocator *code_allocator_;
707 OsrCodeMap osr_code_map_;
708 mem::InternalAllocatorPtr internal_allocator_;
709 // This allocator is used for GDB debug structures in context of JIT unwind info.
710 ArenaAllocator gdb_debug_info_allocator_;
711 compiler::RuntimeInterface *runtime_iface_;
712 // The lock is used for compiler thread synchronization
713 os::memory::Mutex compilation_lock_;
714 // This queue is used only in ThreadPool. Do not use it from this class.
715 CompilerQueueInterface *queue_ {nullptr};
716 bool no_async_jit_;
717 std::atomic_bool is_thread_pool_created_ = false;
718 ThreadPool<CompilerTask, CompilerProcessor, Compiler *> *thread_pool_;
719 NO_COPY_SEMANTIC(Compiler);
720 NO_MOVE_SEMANTIC(Compiler);
721 };
722
723 } // namespace panda
724
725 #endif // PANDA_RUNTIME_COMPILER_H_
726