• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /**
2  * Copyright (c) 2021-2022 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  * http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #include "core_vm.h"
17 #include "utils/expected.h"
18 #include "runtime/compiler.h"
19 #include "runtime/handle_scope-inl.h"
20 #include "runtime/include/thread.h"
21 #include "runtime/include/class_linker.h"
22 #include "runtime/include/thread_scopes.h"
23 #include "runtime/mem/gc/reference-processor/empty_reference_processor.h"
24 #include "runtime/mem/refstorage/global_object_storage.h"
25 
26 namespace panda::core {
27 
28 // Create MemoryManager by RuntimeOptions
CreateMM(const LanguageContext & ctx,mem::InternalAllocatorPtr internal_allocator,const RuntimeOptions & options)29 static mem::MemoryManager *CreateMM(const LanguageContext &ctx, mem::InternalAllocatorPtr internal_allocator,
30                                     const RuntimeOptions &options)
31 {
32     mem::MemoryManager::HeapOptions heap_options {
33         nullptr,                                      // is_object_finalizeble_func
34         nullptr,                                      // register_finalize_reference_func
35         options.GetMaxGlobalRefSize(),                // max_global_ref_size
36         options.IsGlobalReferenceSizeCheckEnabled(),  // is_global_reference_size_check_enabled
37         false,                                        // is_single_thread
38         options.IsUseTlabForAllocations(),            // is_use_tlab_for_allocations
39         options.IsStartAsZygote(),                    // is_start_as_zygote
40     };
41 
42     mem::GCTriggerConfig gc_trigger_config(options, panda_file::SourceLang::PANDA_ASSEMBLY);
43 
44     mem::GCSettings gc_settings(options, panda_file::SourceLang::PANDA_ASSEMBLY);
45 
46     mem::GCType gc_type = Runtime::GetGCType(options, panda_file::SourceLang::PANDA_ASSEMBLY);
47 
48     return mem::MemoryManager::Create(ctx, internal_allocator, gc_type, gc_settings, gc_trigger_config, heap_options);
49 }
50 
51 /* static */
Create(Runtime * runtime,const RuntimeOptions & options)52 Expected<PandaCoreVM *, PandaString> PandaCoreVM::Create(Runtime *runtime, const RuntimeOptions &options)
53 {
54     LanguageContext ctx = Runtime::GetCurrent()->GetLanguageContext(panda_file::SourceLang::PANDA_ASSEMBLY);
55     mem::MemoryManager *mm = CreateMM(ctx, runtime->GetInternalAllocator(), options);
56     if (mm == nullptr) {
57         return Unexpected(PandaString("Cannot create MemoryManager"));
58     }
59 
60     auto allocator = mm->GetHeapManager()->GetInternalAllocator();
61     PandaCoreVM *core_vm = allocator->New<PandaCoreVM>(runtime, options, mm);
62     if (core_vm == nullptr) {
63         return Unexpected(PandaString("Cannot create PandaCoreVM"));
64     }
65 
66     core_vm->InitializeGC();
67 
68     // Create Main Thread
69     core_vm->main_thread_ = MTManagedThread::Create(runtime, core_vm);
70     core_vm->main_thread_->InitBuffers();
71     ASSERT(core_vm->main_thread_ == ManagedThread::GetCurrent());
72     core_vm->main_thread_->InitForStackOverflowCheck(ManagedThread::STACK_OVERFLOW_RESERVED_SIZE,
73                                                      ManagedThread::STACK_OVERFLOW_PROTECTED_SIZE);
74 
75     core_vm->thread_manager_->SetMainThread(core_vm->main_thread_);
76 
77     return core_vm;
78 }
79 
PandaCoreVM(Runtime * runtime,const RuntimeOptions & options,mem::MemoryManager * mm)80 PandaCoreVM::PandaCoreVM(Runtime *runtime, const RuntimeOptions &options, mem::MemoryManager *mm)
81     : runtime_(runtime), mm_(mm)
82 {
83     mem::HeapManager *heap_manager = mm_->GetHeapManager();
84     mem::InternalAllocatorPtr allocator = heap_manager->GetInternalAllocator();
85     runtime_iface_ = allocator->New<PandaRuntimeInterface>();
86     compiler_ = allocator->New<Compiler>(heap_manager->GetCodeAllocator(), allocator, options,
87                                          heap_manager->GetMemStats(), runtime_iface_);
88     string_table_ = allocator->New<StringTable>();
89     monitor_pool_ = allocator->New<MonitorPool>(allocator);
90     reference_processor_ = allocator->New<mem::EmptyReferenceProcessor>();
91     thread_manager_ = allocator->New<ThreadManager>(allocator);
92     rendezvous_ = allocator->New<Rendezvous>();
93 }
94 
~PandaCoreVM()95 PandaCoreVM::~PandaCoreVM()
96 {
97     delete main_thread_;
98 
99     mem::InternalAllocatorPtr allocator = mm_->GetHeapManager()->GetInternalAllocator();
100     allocator->Delete(rendezvous_);
101     allocator->Delete(runtime_iface_);
102     allocator->Delete(thread_manager_);
103     allocator->Delete(reference_processor_);
104     allocator->Delete(monitor_pool_);
105     allocator->Delete(string_table_);
106     allocator->Delete(compiler_);
107     mm_->Finalize();
108     mem::MemoryManager::Destroy(mm_);
109 }
110 
Initialize()111 bool PandaCoreVM::Initialize()
112 {
113     if (!intrinsics::Initialize(panda::panda_file::SourceLang::PANDA_ASSEMBLY)) {
114         LOG(ERROR, RUNTIME) << "Failed to initialize Core intrinsics";
115         return false;
116     }
117 
118     auto runtime = Runtime::GetCurrent();
119     if (runtime->GetOptions().ShouldLoadBootPandaFiles()) {
120         PreAllocOOMErrorObject();
121     }
122 
123     return true;
124 }
125 
PreAllocOOMErrorObject()126 void PandaCoreVM::PreAllocOOMErrorObject()
127 {
128     auto global_object_storage = GetGlobalObjectStorage();
129     auto runtime = Runtime::GetCurrent();
130     LanguageContext ctx = runtime->GetLanguageContext(panda_file::SourceLang::PANDA_ASSEMBLY);
131     auto *class_linker = runtime->GetClassLinker();
132     auto cls = class_linker->GetExtension(ctx)->GetClass(ctx.GetOutOfMemoryErrorClassDescriptor());
133     auto oom_obj = ObjectHeader::Create(cls);
134     if (oom_obj == nullptr) {
135         LOG(FATAL, RUNTIME) << "Cannot preallocate OOM Error object";
136         return;
137     }
138     oom_obj_ref_ = global_object_storage->Add(oom_obj, panda::mem::Reference::ObjectType::GLOBAL);
139 }
140 
InitializeFinish()141 bool PandaCoreVM::InitializeFinish()
142 {
143     // Preinitialize StackOverflowException so we don't need to do this when stack overflow occurred
144     auto runtime = Runtime::GetCurrent();
145     auto *class_linker = runtime->GetClassLinker();
146     LanguageContext ctx = runtime->GetLanguageContext(panda_file::SourceLang::PANDA_ASSEMBLY);
147     auto *extension = class_linker->GetExtension(ctx);
148     class_linker->GetClass(ctx.GetStackOverflowErrorClassDescriptor(), true, extension->GetBootContext());
149 
150     return true;
151 }
152 
UninitializeThreads()153 void PandaCoreVM::UninitializeThreads()
154 {
155     // Wait until all threads finish the work
156     thread_manager_->WaitForDeregistration();
157     main_thread_->Destroy();
158 }
159 
PreStartup()160 void PandaCoreVM::PreStartup()
161 {
162     mm_->PreStartup();
163 }
164 
PreZygoteFork()165 void PandaCoreVM::PreZygoteFork()
166 {
167     mm_->PreZygoteFork();
168     compiler_->PreZygoteFork();
169 }
170 
PostZygoteFork()171 void PandaCoreVM::PostZygoteFork()
172 {
173     compiler_->PostZygoteFork();
174     mm_->PostZygoteFork();
175 }
176 
InitializeGC()177 void PandaCoreVM::InitializeGC()
178 {
179     mm_->InitializeGC(this);
180 }
181 
StartGC()182 void PandaCoreVM::StartGC()
183 {
184     mm_->StartGC();
185 }
186 
StopGC()187 void PandaCoreVM::StopGC()
188 {
189     mm_->StopGC();
190 }
191 
HandleReferences(const GCTask & task,const mem::GC::ReferenceClearPredicateT & pred)192 void PandaCoreVM::HandleReferences(const GCTask &task, const mem::GC::ReferenceClearPredicateT &pred)
193 {
194     LOG(DEBUG, REF_PROC) << "Start processing cleared references";
195     mem::GC *gc = mm_->GetGC();
196     gc->ProcessReferences(gc->GetGCPhase(), task, pred);
197 }
198 
199 // TODO(alovkov): call ReferenceQueue.add method with cleared references
HandleEnqueueReferences()200 void PandaCoreVM::HandleEnqueueReferences()
201 {
202     LOG(DEBUG, REF_PROC) << "Start HandleEnqueueReferences";
203     mm_->GetGC()->EnqueueReferences();
204     LOG(DEBUG, REF_PROC) << "Finish HandleEnqueueReferences";
205 }
206 
HandleGCFinished()207 void PandaCoreVM::HandleGCFinished() {}
208 
CheckEntrypointSignature(Method * entrypoint)209 bool PandaCoreVM::CheckEntrypointSignature(Method *entrypoint)
210 {
211     if (entrypoint->GetNumArgs() == 0) {
212         return true;
213     }
214 
215     if (entrypoint->GetNumArgs() > 1) {
216         return false;
217     }
218 
219     auto *pf = entrypoint->GetPandaFile();
220     panda_file::MethodDataAccessor mda(*pf, entrypoint->GetFileId());
221     panda_file::ProtoDataAccessor pda(*pf, mda.GetProtoId());
222 
223     if (pda.GetArgType(0).GetId() != panda_file::Type::TypeId::REFERENCE) {
224         return false;
225     }
226 
227     auto type_id = pda.GetReferenceType(0);
228     auto string_data = pf->GetStringData(type_id);
229     const char class_name[] = "[Lpanda/String;";  // NOLINT(modernize-avoid-c-arrays)
230 
231     return utf::IsEqual({string_data.data, string_data.utf16_length},
232                         {utf::CStringAsMutf8(class_name), sizeof(class_name) - 1});
233 }
234 
CreateArgumentsArray(const std::vector<std::string> & args,const LanguageContext & ctx,ClassLinker * class_linker,PandaVM * vm)235 static coretypes::Array *CreateArgumentsArray(const std::vector<std::string> &args, const LanguageContext &ctx,
236                                               ClassLinker *class_linker, PandaVM *vm)
237 {
238     const char class_name[] = "[Lpanda/String;";  // NOLINT(modernize-avoid-c-arrays)
239     auto *array_klass = class_linker->GetExtension(ctx)->GetClass(utf::CStringAsMutf8(class_name));
240     if (array_klass == nullptr) {
241         LOG(FATAL, RUNTIME) << "Class " << class_name << " not found";
242     }
243 
244     auto thread = MTManagedThread::GetCurrent();
245     [[maybe_unused]] HandleScope<ObjectHeader *> scope(thread);
246     auto *array = coretypes::Array::Create(array_klass, args.size());
247     VMHandle<coretypes::Array> array_handle(thread, array);
248 
249     for (size_t i = 0; i < args.size(); i++) {
250         auto *str = coretypes::String::CreateFromMUtf8(utf::CStringAsMutf8(args[i].data()), args[i].length(), ctx, vm);
251         array_handle.GetPtr()->Set(i, str);
252     }
253 
254     return array_handle.GetPtr();
255 }
256 
InvokeEntrypointImpl(Method * entrypoint,const std::vector<std::string> & args)257 Expected<int, Runtime::Error> PandaCoreVM::InvokeEntrypointImpl(Method *entrypoint,
258                                                                 const std::vector<std::string> &args)
259 {
260     Runtime *runtime = Runtime::GetCurrent();
261     MTManagedThread *thread = MTManagedThread::GetCurrent();
262     LanguageContext ctx = runtime->GetLanguageContext(*entrypoint);
263     ASSERT(ctx.GetLanguage() == panda_file::SourceLang::PANDA_ASSEMBLY);
264 
265     ScopedManagedCodeThread sj(thread);
266     ClassLinker *class_linker = runtime->GetClassLinker();
267     if (!class_linker->InitializeClass(thread, entrypoint->GetClass())) {
268         LOG(ERROR, RUNTIME) << "Cannot initialize class '" << entrypoint->GetClass()->GetName() << "'";
269         return Unexpected(Runtime::Error::CLASS_NOT_INITIALIZED);
270     }
271 
272     ObjectHeader *object_header = nullptr;
273     if (entrypoint->GetNumArgs() == 1) {
274         coretypes::Array *arg_array = CreateArgumentsArray(args, ctx, runtime_->GetClassLinker(), thread->GetVM());
275         object_header = arg_array;
276     }
277 
278     [[maybe_unused]] HandleScope<ObjectHeader *> scope(thread);
279     VMHandle<ObjectHeader> args_handle(thread, object_header);
280     Value arg_val(args_handle.GetPtr());
281     Value v = entrypoint->Invoke(thread, &arg_val);
282 
283     return v.GetAs<int>();
284 }
285 
GetOOMErrorObject()286 ObjectHeader *PandaCoreVM::GetOOMErrorObject()
287 {
288     auto global_object_storage = GetGlobalObjectStorage();
289     auto obj = global_object_storage->Get(oom_obj_ref_);
290     ASSERT(obj != nullptr);
291     return obj;
292 }
293 
HandleUncaughtException()294 void PandaCoreVM::HandleUncaughtException()
295 {
296     ManagedThread *thread = ManagedThread::GetCurrent();
297     LOG(ERROR, RUNTIME) << "Unhandled exception: " << thread->GetException()->ClassAddr<Class>()->GetName();
298     // _exit guarantees a safe completion in case of multi-threading as static destructors aren't called
299     _exit(1);
300 }
301 
VisitVmRoots(const GCRootVisitor & visitor)302 void PandaCoreVM::VisitVmRoots(const GCRootVisitor &visitor)
303 {
304     // Visit PT roots
305     GetThreadManager()->EnumerateThreads([visitor](ManagedThread *thread) {
306         ASSERT(MTManagedThread::ThreadIsMTManagedThread(thread));
307         auto mt_thread = MTManagedThread::CastFromThread(thread);
308         auto pt_storage = mt_thread->GetPtReferenceStorage();
309         pt_storage->VisitObjects(visitor, mem::RootType::ROOT_PT_LOCAL);
310         return true;
311     });
312 }
313 
UpdateVmRefs()314 void PandaCoreVM::UpdateVmRefs()
315 {
316     LOG(DEBUG, GC) << "=== PTRoots Update moved. BEGIN ===";
317     GetThreadManager()->EnumerateThreads([](ManagedThread *thread) {
318         ASSERT(MTManagedThread::ThreadIsMTManagedThread(thread));
319         auto mt_thread = MTManagedThread::CastFromThread(thread);
320         auto pt_storage = mt_thread->GetPtReferenceStorage();
321         pt_storage->UpdateMovedRefs();
322         return true;
323     });
324     LOG(DEBUG, GC) << "=== PTRoots Update moved. END ===";
325 }
326 
327 }  // namespace panda::core
328