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