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