1 /**
2 * Copyright (c) 2021-2024 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 "libpandabase/utils/expected.h"
17 #include "runtime/compiler.h"
18 #include "runtime/core/core_vm.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/lock_config_helper.h"
25 #include "runtime/mem/refstorage/global_object_storage.h"
26 #include "runtime/single_thread_manager.h"
27
28 namespace ark::core {
29
30 // Create MemoryManager by RuntimeOptions
CreateMM(const LanguageContext & ctx,mem::InternalAllocatorPtr internalAllocator,const RuntimeOptions & options)31 static mem::MemoryManager *CreateMM(const LanguageContext &ctx, mem::InternalAllocatorPtr internalAllocator,
32 const RuntimeOptions &options)
33 {
34 mem::MemoryManager::HeapOptions heapOptions {
35 nullptr, // is_object_finalizeble_func
36 nullptr, // register_finalize_reference_func
37 options.GetMaxGlobalRefSize(), // max_global_ref_size
38 options.IsGlobalReferenceSizeCheckEnabled(), // is_global_reference_size_check_enabled
39 MT_MODE_MULTI, // multithreading mode
40 options.IsUseTlabForAllocations(), // is_use_tlab_for_allocations
41 options.IsStartAsZygote(), // is_start_as_zygote
42 };
43
44 mem::GCTriggerConfig gcTriggerConfig(options, panda_file::SourceLang::PANDA_ASSEMBLY);
45
46 mem::GCSettings gcSettings(options, panda_file::SourceLang::PANDA_ASSEMBLY);
47
48 mem::GCType gcType = Runtime::GetGCType(options, panda_file::SourceLang::PANDA_ASSEMBLY);
49
50 return mem::MemoryManager::Create(ctx, internalAllocator, gcType, gcSettings, gcTriggerConfig, heapOptions);
51 }
52
53 /* static */
Create(Runtime * runtime,const RuntimeOptions & options)54 Expected<PandaCoreVM *, PandaString> PandaCoreVM::Create(Runtime *runtime, const RuntimeOptions &options)
55 {
56 LanguageContext ctx = Runtime::GetCurrent()->GetLanguageContext(panda_file::SourceLang::PANDA_ASSEMBLY);
57 mem::MemoryManager *mm = CreateMM(ctx, runtime->GetInternalAllocator(), options);
58 if (mm == nullptr) {
59 return Unexpected(PandaString("Cannot create MemoryManager"));
60 }
61
62 auto allocator = mm->GetHeapManager()->GetInternalAllocator();
63 PandaCoreVM *coreVm = allocator->New<PandaCoreVM>(runtime, options, mm);
64 if (coreVm == nullptr) {
65 return Unexpected(PandaString("Cannot create PandaCoreVM"));
66 }
67
68 coreVm->InitializeGC();
69
70 // Create Main Thread
71 coreVm->mainThread_ = MTManagedThread::Create(runtime, coreVm);
72 coreVm->mainThread_->InitBuffers();
73 ASSERT(coreVm->mainThread_ == ManagedThread::GetCurrent());
74 coreVm->mainThread_->InitForStackOverflowCheck(ManagedThread::STACK_OVERFLOW_RESERVED_SIZE,
75 ManagedThread::STACK_OVERFLOW_PROTECTED_SIZE);
76
77 coreVm->threadManager_->SetMainThread(coreVm->mainThread_);
78
79 return coreVm;
80 }
81
PandaCoreVM(Runtime * runtime,const RuntimeOptions & options,mem::MemoryManager * mm)82 PandaCoreVM::PandaCoreVM(Runtime *runtime, const RuntimeOptions &options, mem::MemoryManager *mm)
83 : runtime_(runtime), mm_(mm)
84 {
85 mem::HeapManager *heapManager = mm_->GetHeapManager();
86 mem::InternalAllocatorPtr allocator = heapManager->GetInternalAllocator();
87 runtimeIface_ = allocator->New<PandaRuntimeInterface>();
88 compiler_ = allocator->New<Compiler>(heapManager->GetCodeAllocator(), allocator, options,
89 heapManager->GetMemStats(), runtimeIface_);
90 stringTable_ = allocator->New<StringTable>();
91 monitorPool_ = allocator->New<MonitorPool>(allocator);
92 referenceProcessor_ = allocator->New<mem::EmptyReferenceProcessor>();
93 threadManager_ = allocator->New<MTThreadManager>(allocator);
94 rendezvous_ = allocator->New<Rendezvous>(this);
95 }
96
~PandaCoreVM()97 PandaCoreVM::~PandaCoreVM()
98 {
99 delete mainThread_;
100
101 mem::InternalAllocatorPtr allocator = mm_->GetHeapManager()->GetInternalAllocator();
102 allocator->Delete(rendezvous_);
103 allocator->Delete(runtimeIface_);
104 allocator->Delete(threadManager_);
105 allocator->Delete(referenceProcessor_);
106 allocator->Delete(monitorPool_);
107 allocator->Delete(stringTable_);
108 allocator->Delete(compiler_);
109 mm_->Finalize();
110 mem::MemoryManager::Destroy(mm_);
111 }
112
Initialize()113 bool PandaCoreVM::Initialize()
114 {
115 if (!intrinsics::Initialize(ark::panda_file::SourceLang::PANDA_ASSEMBLY)) {
116 LOG(ERROR, RUNTIME) << "Failed to initialize Core intrinsics";
117 return false;
118 }
119
120 auto runtime = Runtime::GetCurrent();
121 if (runtime->GetOptions().ShouldLoadBootPandaFiles()) {
122 PreAllocOOMErrorObject();
123 }
124
125 return true;
126 }
127
PreAllocOOMErrorObject()128 void PandaCoreVM::PreAllocOOMErrorObject()
129 {
130 auto globalObjectStorage = GetGlobalObjectStorage();
131 auto runtime = Runtime::GetCurrent();
132 LanguageContext ctx = runtime->GetLanguageContext(panda_file::SourceLang::PANDA_ASSEMBLY);
133 auto *classLinker = runtime->GetClassLinker();
134 auto cls = classLinker->GetExtension(ctx)->GetClass(ctx.GetOutOfMemoryErrorClassDescriptor());
135 auto oomObj = ObjectHeader::Create(cls);
136 if (oomObj == nullptr) {
137 LOG(FATAL, RUNTIME) << "Cannot preallocate OOM Error object";
138 return;
139 }
140 oomObjRef_ = globalObjectStorage->Add(oomObj, ark::mem::Reference::ObjectType::GLOBAL);
141 }
142
InitializeFinish()143 bool PandaCoreVM::InitializeFinish()
144 {
145 // Preinitialize StackOverflowException so we don't need to do this when stack overflow occurred
146 auto runtime = Runtime::GetCurrent();
147 auto *classLinker = runtime->GetClassLinker();
148 LanguageContext ctx = runtime->GetLanguageContext(panda_file::SourceLang::PANDA_ASSEMBLY);
149 auto *extension = classLinker->GetExtension(ctx);
150 classLinker->GetClass(ctx.GetStackOverflowErrorClassDescriptor(), true, extension->GetBootContext());
151
152 return true;
153 }
154
UninitializeThreads()155 void PandaCoreVM::UninitializeThreads()
156 {
157 // Wait until all threads finish the work
158 threadManager_->WaitForDeregistration();
159 mainThread_->Destroy();
160 }
161
PreStartup()162 void PandaCoreVM::PreStartup()
163 {
164 mm_->PreStartup();
165 }
166
PreZygoteFork()167 void PandaCoreVM::PreZygoteFork()
168 {
169 mm_->PreZygoteFork();
170 compiler_->PreZygoteFork();
171 }
172
PostZygoteFork()173 void PandaCoreVM::PostZygoteFork()
174 {
175 compiler_->PostZygoteFork();
176 mm_->PostZygoteFork();
177 }
178
InitializeGC()179 void PandaCoreVM::InitializeGC()
180 {
181 mm_->InitializeGC(this);
182 }
183
StartGC()184 void PandaCoreVM::StartGC()
185 {
186 mm_->StartGC();
187 }
188
StopGC()189 void PandaCoreVM::StopGC()
190 {
191 mm_->StopGC();
192 }
193
HandleReferences(const GCTask & task,const mem::GC::ReferenceClearPredicateT & pred)194 void PandaCoreVM::HandleReferences(const GCTask &task, const mem::GC::ReferenceClearPredicateT &pred)
195 {
196 LOG(DEBUG, REF_PROC) << "Start processing cleared references";
197 mem::GC *gc = mm_->GetGC();
198 gc->ProcessReferences(gc->GetGCPhase(), task, pred);
199 }
200
201 // NOTE(alovkov): call ReferenceQueue.add method with cleared references
HandleEnqueueReferences()202 void PandaCoreVM::HandleEnqueueReferences()
203 {
204 LOG(DEBUG, REF_PROC) << "Start HandleEnqueueReferences";
205 mm_->GetGC()->EnqueueReferences();
206 LOG(DEBUG, REF_PROC) << "Finish HandleEnqueueReferences";
207 }
208
HandleGCFinished()209 void PandaCoreVM::HandleGCFinished() {}
210
CheckEntrypointSignature(Method * entrypoint)211 bool PandaCoreVM::CheckEntrypointSignature(Method *entrypoint)
212 {
213 if (entrypoint->GetNumArgs() == 0) {
214 return true;
215 }
216
217 if (entrypoint->GetNumArgs() > 1) {
218 return false;
219 }
220
221 auto *pf = entrypoint->GetPandaFile();
222 panda_file::MethodDataAccessor mda(*pf, entrypoint->GetFileId());
223 panda_file::ProtoDataAccessor pda(*pf, mda.GetProtoId());
224
225 if (pda.GetArgType(0).GetId() != panda_file::Type::TypeId::REFERENCE) {
226 return false;
227 }
228
229 auto typeId = pda.GetReferenceType(0);
230 auto stringData = pf->GetStringData(typeId);
231 const char className[] = "[Lpanda/String;"; // NOLINT(modernize-avoid-c-arrays)
232
233 return utf::IsEqual({stringData.data, stringData.utf16Length},
234 {utf::CStringAsMutf8(className), sizeof(className) - 1});
235 }
236
CreateArgumentsArray(const std::vector<std::string> & args,const LanguageContext & ctx,ClassLinker * classLinker,PandaVM * vm)237 static coretypes::Array *CreateArgumentsArray(const std::vector<std::string> &args, const LanguageContext &ctx,
238 ClassLinker *classLinker, PandaVM *vm)
239 {
240 const char className[] = "[Lpanda/String;"; // NOLINT(modernize-avoid-c-arrays)
241 auto *arrayKlass = classLinker->GetExtension(ctx)->GetClass(utf::CStringAsMutf8(className));
242 if (arrayKlass == nullptr) {
243 LOG(FATAL, RUNTIME) << "Class " << className << " not found";
244 }
245
246 auto thread = MTManagedThread::GetCurrent();
247 [[maybe_unused]] HandleScope<ObjectHeader *> scope(thread);
248 auto *array = coretypes::Array::Create(arrayKlass, args.size());
249 VMHandle<coretypes::Array> arrayHandle(thread, array);
250
251 for (size_t i = 0; i < args.size(); i++) {
252 auto *str = coretypes::String::CreateFromMUtf8(utf::CStringAsMutf8(args[i].data()), args[i].length(), ctx, vm);
253 arrayHandle.GetPtr()->Set(i, str);
254 }
255
256 return arrayHandle.GetPtr();
257 }
258
InvokeEntrypointImpl(Method * entrypoint,const std::vector<std::string> & args)259 Expected<int, Runtime::Error> PandaCoreVM::InvokeEntrypointImpl(Method *entrypoint,
260 const std::vector<std::string> &args)
261 {
262 Runtime *runtime = Runtime::GetCurrent();
263 MTManagedThread *thread = MTManagedThread::GetCurrent();
264 LanguageContext ctx = runtime->GetLanguageContext(*entrypoint);
265 ASSERT(ctx.GetLanguage() == panda_file::SourceLang::PANDA_ASSEMBLY);
266
267 ScopedManagedCodeThread sj(thread);
268 ClassLinker *classLinker = runtime->GetClassLinker();
269 if (!classLinker->InitializeClass(thread, entrypoint->GetClass())) {
270 LOG(ERROR, RUNTIME) << "Cannot initialize class '" << entrypoint->GetClass()->GetName() << "'";
271 return Unexpected(Runtime::Error::CLASS_NOT_INITIALIZED);
272 }
273
274 ObjectHeader *objectHeader = nullptr;
275 if (entrypoint->GetNumArgs() == 1) {
276 coretypes::Array *argArray = CreateArgumentsArray(args, ctx, runtime_->GetClassLinker(), thread->GetVM());
277 objectHeader = argArray;
278 }
279
280 [[maybe_unused]] HandleScope<ObjectHeader *> scope(thread);
281 VMHandle<ObjectHeader> argsHandle(thread, objectHeader);
282 Value argVal(argsHandle.GetPtr());
283 Value v = entrypoint->Invoke(thread, &argVal);
284
285 return v.GetAs<int>();
286 }
287
GetOOMErrorObject()288 ObjectHeader *PandaCoreVM::GetOOMErrorObject()
289 {
290 auto globalObjectStorage = GetGlobalObjectStorage();
291 auto obj = globalObjectStorage->Get(oomObjRef_);
292 ASSERT(obj != nullptr);
293 return obj;
294 }
295
HandleUncaughtException()296 void PandaCoreVM::HandleUncaughtException()
297 {
298 ManagedThread *thread = ManagedThread::GetCurrent();
299 LOG(ERROR, RUNTIME) << "Unhandled exception: " << thread->GetException()->ClassAddr<Class>()->GetName();
300 // _exit guarantees a safe completion in case of multi-threading as static destructors aren't called
301 _exit(1);
302 }
303
VisitVmRoots(const GCRootVisitor & visitor)304 void PandaCoreVM::VisitVmRoots(const GCRootVisitor &visitor)
305 {
306 PandaVM::VisitVmRoots(visitor);
307 // Visit PT roots
308 GetThreadManager()->EnumerateThreads([visitor](ManagedThread *thread) {
309 ASSERT(MTManagedThread::ThreadIsMTManagedThread(thread));
310 auto mtThread = MTManagedThread::CastFromThread(thread);
311 auto ptStorage = mtThread->GetPtReferenceStorage();
312 ptStorage->VisitObjects(visitor, mem::RootType::ROOT_PT_LOCAL);
313 return true;
314 });
315 }
316
UpdateVmRefs()317 void PandaCoreVM::UpdateVmRefs()
318 {
319 PandaVM::UpdateVmRefs();
320 LOG(DEBUG, GC) << "=== PTRoots Update moved. BEGIN ===";
321 GetThreadManager()->EnumerateThreads([](ManagedThread *thread) {
322 ASSERT(MTManagedThread::ThreadIsMTManagedThread(thread));
323 auto mtThread = MTManagedThread::CastFromThread(thread);
324 auto ptStorage = mtThread->GetPtReferenceStorage();
325 ptStorage->UpdateMovedRefs();
326 return true;
327 });
328 LOG(DEBUG, GC) << "=== PTRoots Update moved. END ===";
329 }
330
331 } // namespace ark::core
332