1 /**
2 * Copyright (c) 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 "runtime/tooling/inspector/object_repository.h"
17
18 #include "runtime/handle_scope-inl.h"
19 #include "runtime/include/tooling/inspector_extension.h"
20
21 namespace panda::tooling::inspector {
ObjectRepository()22 ObjectRepository::ObjectRepository()
23 : extension_(ManagedThread::GetCurrent()->GetLanguageContext().CreateInspectorExtension()),
24 scope_(ManagedThread::GetCurrent())
25 {
26 }
27
CreateGlobalObject()28 RemoteObject ObjectRepository::CreateGlobalObject()
29 {
30 return RemoteObject::Object("[Global]", GLOBAL_OBJECT_ID, "Global object");
31 }
32
CreateFrameObject(const PtFrame & frame,const std::map<std::string,TypedValue> & locals)33 RemoteObject ObjectRepository::CreateFrameObject(const PtFrame &frame, const std::map<std::string, TypedValue> &locals)
34 {
35 ASSERT(ManagedThread::GetCurrent()->GetMutatorLock()->HasLock());
36
37 std::vector<PropertyDescriptor> properties;
38 properties.reserve(locals.size());
39 for (auto &local : locals) {
40 properties.emplace_back(local.first, CreateObject(local.second));
41 }
42
43 auto id = counter_++;
44 frames_.emplace(id, std::move(properties));
45
46 return RemoteObject::Object("", id, "Frame #" + std::to_string(frame.GetFrameId()));
47 }
48
CreateObject(TypedValue value)49 RemoteObject ObjectRepository::CreateObject(TypedValue value)
50 {
51 ASSERT(ManagedThread::GetCurrent()->GetMutatorLock()->HasLock());
52
53 switch (value.GetType()) {
54 case panda_file::Type::TypeId::INVALID:
55 case panda_file::Type::TypeId::VOID:
56 return RemoteObject::Undefined();
57 case panda_file::Type::TypeId::U1:
58 return RemoteObject::Boolean(value.GetAsU1());
59 case panda_file::Type::TypeId::I8:
60 return RemoteObject::Number(value.GetAsI8());
61 case panda_file::Type::TypeId::U8:
62 return RemoteObject::Number(value.GetAsU8());
63 case panda_file::Type::TypeId::I16:
64 return RemoteObject::Number(value.GetAsI16());
65 case panda_file::Type::TypeId::U16:
66 return RemoteObject::Number(value.GetAsU16());
67 case panda_file::Type::TypeId::I32:
68 return RemoteObject::Number(value.GetAsI32());
69 case panda_file::Type::TypeId::U32:
70 return RemoteObject::Number(value.GetAsU32());
71 case panda_file::Type::TypeId::F32:
72 return RemoteObject::Number(value.GetAsF32());
73 case panda_file::Type::TypeId::F64:
74 return RemoteObject::Number(value.GetAsF64());
75 case panda_file::Type::TypeId::I64:
76 return RemoteObject::Number(value.GetAsI64());
77 case panda_file::Type::TypeId::U64:
78 return RemoteObject::Number(value.GetAsU64());
79 case panda_file::Type::TypeId::REFERENCE:
80 return CreateObject(value.GetAsReference());
81 case panda_file::Type::TypeId::TAGGED:
82 return CreateObject(value.GetAsTagged());
83 }
84 UNREACHABLE();
85 }
86
GetProperties(RemoteObjectId id,bool generatePreview)87 std::vector<PropertyDescriptor> ObjectRepository::GetProperties(RemoteObjectId id, bool generatePreview)
88 {
89 ASSERT(ManagedThread::GetCurrent()->GetMutatorLock()->HasLock());
90
91 auto properties = GetProperties(id);
92
93 if (generatePreview) {
94 for (auto &property : properties) {
95 if (property.IsAccessor()) {
96 continue;
97 }
98
99 auto &value = property.GetValue();
100 if (auto valueId = value.GetObjectId()) {
101 value.GeneratePreview(GetProperties(*valueId));
102 }
103 }
104 }
105
106 return properties;
107 }
108
CreateObject(coretypes::TaggedValue value)109 RemoteObject ObjectRepository::CreateObject(coretypes::TaggedValue value)
110 {
111 if (value.IsHeapObject()) {
112 return CreateObject(value.GetHeapObject());
113 }
114 if (value.IsUndefined() || value.IsHole()) {
115 return RemoteObject::Undefined();
116 }
117 if (value.IsNull()) {
118 return RemoteObject::Null();
119 }
120 if (value.IsBoolean()) {
121 return RemoteObject::Boolean(value.IsTrue());
122 }
123 if (value.IsInt()) {
124 return RemoteObject::Number(value.GetInt());
125 }
126 if (value.IsDouble()) {
127 return RemoteObject::Number(value.GetDouble());
128 }
129 UNREACHABLE();
130 }
131
CreateObject(ObjectHeader * object)132 RemoteObject ObjectRepository::CreateObject(ObjectHeader *object)
133 {
134 ASSERT(ManagedThread::GetCurrent()->GetMutatorLock()->HasLock());
135
136 if (object == nullptr) {
137 return RemoteObject::Null();
138 }
139
140 if (auto str = extension_->GetAsString(object)) {
141 return RemoteObject::String(*str);
142 }
143
144 RemoteObjectId id;
145
146 // SUPPRESS_CSA_NEXTLINE(alpha.core.WasteObjHeader)
147 auto it = std::find_if(objects_.begin(), objects_.end(), [object](auto &p) { return p.second.GetPtr() == object; });
148 if (it == objects_.end()) {
149 id = counter_++;
150
151 objects_.emplace(std::piecewise_construct, std::forward_as_tuple(id),
152 std::forward_as_tuple(ManagedThread::GetCurrent(), object));
153 } else {
154 id = it->first;
155 }
156
157 // SUPPRESS_CSA_NEXTLINE(alpha.core.WasteObjHeader)
158 if (auto arrayLen = extension_->GetLengthIfArray(object)) {
159 // SUPPRESS_CSA_NEXTLINE(alpha.core.WasteObjHeader)
160 return RemoteObject::Array(extension_->GetClassName(object), *arrayLen, id);
161 }
162
163 // SUPPRESS_CSA_NEXTLINE(alpha.core.WasteObjHeader)
164 return RemoteObject::Object(extension_->GetClassName(object), id);
165 }
166
GetProperties(RemoteObjectId id)167 std::vector<PropertyDescriptor> ObjectRepository::GetProperties(RemoteObjectId id)
168 {
169 ASSERT(ManagedThread::GetCurrent()->GetMutatorLock()->HasLock());
170
171 auto fIt = frames_.find(id);
172 if (fIt != frames_.end()) {
173 ASSERT(objects_.find(id) == objects_.end());
174 return fIt->second;
175 }
176
177 std::vector<PropertyDescriptor> properties;
178 auto propertyHandler = [this, &properties](auto &name, auto value, auto isArrayElement, auto isFinal,
179 auto isAccessor) {
180 auto property = isAccessor ? PropertyDescriptor::Accessor(name, CreateObject(value))
181 : PropertyDescriptor(name, CreateObject(value), isArrayElement);
182 if (!isAccessor && isFinal) {
183 property.SetWritable(false);
184 }
185 properties.emplace_back(std::move(property));
186 };
187
188 if (id == GLOBAL_OBJECT_ID) {
189 ASSERT(objects_.find(id) == objects_.end());
190 extension_->EnumerateGlobals(propertyHandler);
191 } else {
192 auto oIt = objects_.find(id);
193 if (oIt == objects_.end()) {
194 LOG(INFO, DEBUGGER) << "Unknown object ID " << id;
195 return {};
196 }
197
198 extension_->EnumerateProperties(oIt->second.GetPtr(), propertyHandler);
199 }
200
201 return properties;
202 }
203 } // namespace panda::tooling::inspector
204