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 <cstdlib>
17 
18 #include "mem/lock_config_helper.h"
19 #include "runtime/default_debugger_agent.h"
20 #include "runtime/include/runtime.h"
21 #include "runtime/include/runtime_options.h"
22 #include "runtime/include/runtime_notification.h"
23 #include "runtime/include/panda_vm.h"
24 #include "runtime/include/thread_scopes.h"
25 #include "runtime/mem/gc/reference-processor/reference_processor.h"
26 
27 #include "libpandafile/file.h"
28 
29 namespace ark {
30 /* static */
Create(Runtime *runtime, const RuntimeOptions &options, std::string_view runtimeType)31 PandaVM *PandaVM::Create(Runtime *runtime, const RuntimeOptions &options, std::string_view runtimeType)
32 {
33     LanguageContext ctx = runtime->GetLanguageContext(std::string(runtimeType));
34     return ctx.CreateVM(runtime, options);
35 }
36 
VisitVmRoots(const GCRootVisitor &visitor)37 void PandaVM::VisitVmRoots(const GCRootVisitor &visitor)
38 {
39     os::memory::LockHolder lock(markQueueLock_);
40     for (ObjectHeader *obj : markQueue_) {
41         visitor(mem::GCRoot(mem::RootType::ROOT_VM, obj));
42     }
43 }
44 
UpdateVmRefs()45 void PandaVM::UpdateVmRefs()
46 {
47     os::memory::LockHolder lock(markQueueLock_);
48     // NOLINTNEXTLINE(modernize-loop-convert)
49     for (auto it = markQueue_.begin(); it != markQueue_.end(); ++it) {
50         if ((*it)->IsForwarded()) {
51             *it = ark::mem::GetForwardAddress(*it);
52         }
53     }
54 }
55 
InvokeEntrypoint(Method *entrypoint, const std::vector<std::string> &args)56 Expected<int, Runtime::Error> PandaVM::InvokeEntrypoint(Method *entrypoint, const std::vector<std::string> &args)
57 {
58     if (!CheckEntrypointSignature(entrypoint)) {
59         LOG(ERROR, RUNTIME) << "Method '" << entrypoint << "' has invalid signature";
60         return Unexpected(Runtime::Error::INVALID_ENTRY_POINT);
61     }
62     Expected<int, Runtime::Error> ret = InvokeEntrypointImpl(entrypoint, args);
63     ManagedThread *thread = ManagedThread::GetCurrent();
64     ASSERT(thread != nullptr);
65     bool hasException = false;
66     {
67         ScopedManagedCodeThread s(thread);
68         hasException = thread->HasPendingException();
69     }
70     if (hasException) {
71         HandleUncaughtException();
72         ret = EXIT_FAILURE;
73     }
74 
75     return ret;
76 }
77 
HandleLdaStr(Frame *frame, BytecodeId stringId)78 void PandaVM::HandleLdaStr(Frame *frame, BytecodeId stringId)
79 {
80     coretypes::String *str = ark::Runtime::GetCurrent()->ResolveString(this, *frame->GetMethod(), stringId.AsFileId());
81     frame->GetAccAsVReg().SetReference(str);
82 }
83 
OpenPandaFile(std::string_view location)84 std::unique_ptr<const panda_file::File> PandaVM::OpenPandaFile(std::string_view location)
85 {
86     return panda_file::OpenPandaFile(location);
87 }
88 
GetNonMovableString(const panda_file::File &pf, panda_file::File::EntityId id) const89 coretypes::String *PandaVM::GetNonMovableString(const panda_file::File &pf, panda_file::File::EntityId id) const
90 {
91     auto cachedString = GetStringTable()->GetInternalStringFast(pf, id);
92     if (cachedString == nullptr) {
93         return nullptr;
94     }
95 
96     if (!GetHeapManager()->IsObjectInNonMovableSpace(cachedString)) {
97         return nullptr;
98     }
99 
100     return cachedString;
101 }
102 
ShouldEnableDebug()103 bool PandaVM::ShouldEnableDebug()
104 {
105     return !Runtime::GetOptions().GetDebuggerLibraryPath().empty() || Runtime::GetOptions().IsDebuggerEnable();
106 }
107 
108 // Intrusive GC test API
MarkObject(ObjectHeader *obj)109 void PandaVM::MarkObject(ObjectHeader *obj)
110 {
111     os::memory::LockHolder lock(markQueueLock_);
112     markQueue_.push_back(obj);
113 }
114 
IterateOverMarkQueue(const std::function<void(ObjectHeader *)> &visitor)115 void PandaVM::IterateOverMarkQueue(const std::function<void(ObjectHeader *)> &visitor)
116 {
117     os::memory::LockHolder lock(markQueueLock_);
118     for (ObjectHeader *obj : markQueue_) {
119         visitor(obj);
120     }
121 }
122 
ClearMarkQueue()123 void PandaVM::ClearMarkQueue()
124 {
125     os::memory::LockHolder lock(markQueueLock_);
126     markQueue_.clear();
127 }
128 
CreateDebuggerAgent()129 LoadableAgentHandle PandaVM::CreateDebuggerAgent()
130 {
131     if (!Runtime::GetOptions().GetDebuggerLibraryPath().empty()) {
132         return DefaultDebuggerAgent::LoadInstance();
133     }
134 
135     return {};
136 }
137 
GetClassesFootprint() const138 PandaString PandaVM::GetClassesFootprint() const
139 {
140     ASSERT(GetLanguageContext().GetLanguageType() == LangTypeT::LANG_TYPE_STATIC);
141     PandaVector<Class *> classes;
142     auto classLinker = Runtime::GetCurrent()->GetClassLinker();
143     classLinker->EnumerateClasses([&classes](Class *cls) {
144         classes.push_back(cls);
145         return true;
146     });
147 
148     PandaVector<uint64_t> footprintOfClasses(classes.size(), 0U);
149     GetHeapManager()->CountInstances(classes, true, footprintOfClasses.data());
150 
151     PandaMultiMap<uint64_t, Class *> footprintToClass;
152     for (size_t index = 0; index < classes.size(); ++index) {
153         footprintToClass.insert({footprintOfClasses[index], classes[index]});
154     }
155 
156     PandaStringStream statistic;
157     PandaMultiMap<uint64_t, Class *>::reverse_iterator rit;
158     for (rit = footprintToClass.rbegin(); rit != footprintToClass.rend(); ++rit) {
159         if (rit->first == 0U) {
160             break;
161         }
162         auto clazz = rit->second;
163         statistic << "class: " << clazz->GetName() << ", footprint - " << rit->first << std::endl;
164     }
165     return statistic.str();
166 }
167 
ProcessReferenceFinalizers()168 void PandaVM::ProcessReferenceFinalizers()
169 {
170     GetReferenceProcessor()->ProcessFinalizers();
171 }
172 
173 }  // namespace ark
174