• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /**
2  * Copyright (c) 2021-2025 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 [[noreturn]] void PandaCoreVM::HandleUncaughtException()
297 {
298     ManagedThread *thread = ManagedThread::GetCurrent();
299     ASSERT(thread != nullptr);
300     LOG(ERROR, RUNTIME) << "Unhandled exception: " << thread->GetException()->ClassAddr<Class>()->GetName();
301     // _exit guarantees a safe completion in case of multi-threading as static destructors aren't called
302     _exit(1);
303 }
304 
VisitVmRoots(const GCRootVisitor & visitor)305 void PandaCoreVM::VisitVmRoots(const GCRootVisitor &visitor)
306 {
307     PandaVM::VisitVmRoots(visitor);
308     // Visit PT roots
309     GetThreadManager()->EnumerateThreads([visitor](ManagedThread *thread) {
310         ASSERT(MTManagedThread::ThreadIsMTManagedThread(thread));
311         auto mtThread = MTManagedThread::CastFromThread(thread);
312         auto ptStorage = mtThread->GetPtReferenceStorage();
313         ptStorage->VisitObjects(visitor, mem::RootType::ROOT_PT_LOCAL);
314         return true;
315     });
316 }
317 
UpdateVmRefs(const GCRootUpdater & gcRootUpdater)318 void PandaCoreVM::UpdateVmRefs(const GCRootUpdater &gcRootUpdater)
319 {
320     PandaVM::UpdateVmRefs(gcRootUpdater);
321     LOG(DEBUG, GC) << "=== PTRoots Update moved. BEGIN ===";
322     GetThreadManager()->EnumerateThreads([&gcRootUpdater](ManagedThread *thread) {
323         ASSERT(MTManagedThread::ThreadIsMTManagedThread(thread));
324         auto mtThread = MTManagedThread::CastFromThread(thread);
325         auto ptStorage = mtThread->GetPtReferenceStorage();
326         ptStorage->UpdateMovedRefs(gcRootUpdater);
327         return true;
328     });
329     LOG(DEBUG, GC) << "=== PTRoots Update moved. END ===";
330 }
331 
332 }  // namespace ark::core
333