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