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 <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 panda {
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 = panda::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 =
81 panda::Runtime::GetCurrent()->ResolveString(this, *frame->GetMethod(), stringId.AsFileId());
82 frame->GetAccAsVReg().SetReference(str);
83 }
84
OpenPandaFile(std::string_view location)85 std::unique_ptr<const panda_file::File> PandaVM::OpenPandaFile(std::string_view location)
86 {
87 return panda_file::OpenPandaFile(location);
88 }
89
GetNonMovableString(const panda_file::File & pf,panda_file::File::EntityId id) const90 coretypes::String *PandaVM::GetNonMovableString(const panda_file::File &pf, panda_file::File::EntityId id) const
91 {
92 auto cachedString = GetStringTable()->GetInternalStringFast(pf, id);
93 if (cachedString == nullptr) {
94 return nullptr;
95 }
96
97 if (!GetHeapManager()->IsObjectInNonMovableSpace(cachedString)) {
98 return nullptr;
99 }
100
101 return cachedString;
102 }
103
ShouldEnableDebug()104 bool PandaVM::ShouldEnableDebug()
105 {
106 return !Runtime::GetOptions().GetDebuggerLibraryPath().empty() || Runtime::GetOptions().IsDebuggerEnable();
107 }
108
109 // Intrusive GC test API
MarkObject(ObjectHeader * obj)110 void PandaVM::MarkObject(ObjectHeader *obj)
111 {
112 os::memory::LockHolder lock(markQueueLock_);
113 markQueue_.push_back(obj);
114 }
115
IterateOverMarkQueue(const std::function<void (ObjectHeader *)> & visitor)116 void PandaVM::IterateOverMarkQueue(const std::function<void(ObjectHeader *)> &visitor)
117 {
118 os::memory::LockHolder lock(markQueueLock_);
119 for (ObjectHeader *obj : markQueue_) {
120 visitor(obj);
121 }
122 }
123
ClearMarkQueue()124 void PandaVM::ClearMarkQueue()
125 {
126 os::memory::LockHolder lock(markQueueLock_);
127 markQueue_.clear();
128 }
129
CreateDebuggerAgent()130 LoadableAgentHandle PandaVM::CreateDebuggerAgent()
131 {
132 if (!Runtime::GetOptions().GetDebuggerLibraryPath().empty()) {
133 return DefaultDebuggerAgent::LoadInstance();
134 }
135
136 return {};
137 }
138
GetClassesFootprint() const139 PandaString PandaVM::GetClassesFootprint() const
140 {
141 ASSERT(GetLanguageContext().GetLanguageType() == LangTypeT::LANG_TYPE_STATIC);
142 PandaVector<Class *> classes;
143 auto classLinker = Runtime::GetCurrent()->GetClassLinker();
144 classLinker->EnumerateClasses([&classes](Class *cls) {
145 classes.push_back(cls);
146 return true;
147 });
148
149 PandaVector<uint64_t> footprintOfClasses(classes.size(), 0U);
150 GetHeapManager()->CountInstances(classes, true, footprintOfClasses.data());
151
152 PandaMultiMap<uint64_t, Class *> footprintToClass;
153 for (size_t index = 0; index < classes.size(); ++index) {
154 footprintToClass.insert({footprintOfClasses[index], classes[index]});
155 }
156
157 PandaStringStream statistic;
158 PandaMultiMap<uint64_t, Class *>::reverse_iterator rit;
159 for (rit = footprintToClass.rbegin(); rit != footprintToClass.rend(); ++rit) {
160 if (rit->first == 0U) {
161 break;
162 }
163 auto clazz = rit->second;
164 statistic << "class: " << clazz->GetName() << ", footprint - " << rit->first << std::endl;
165 }
166 return statistic.str();
167 }
168
169 } // namespace panda
170