1 /**
2 * Copyright (c) 2022-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 "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 ark::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,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 auto &value = property.GetValue();
107 if (auto valueId = value.GetObjectId()) {
108 value.GeneratePreview(GetProperties(*valueId));
109 }
110 }
111 }
112
113 return properties;
114 }
115
CreateObject(coretypes::TaggedValue value)116 RemoteObject ObjectRepository::CreateObject(coretypes::TaggedValue value)
117 {
118 if (value.IsHeapObject()) {
119 return CreateObject(value.GetHeapObject());
120 }
121 if (value.IsUndefined() || value.IsHole()) {
122 return RemoteObject::Undefined();
123 }
124 if (value.IsNull()) {
125 return RemoteObject::Null();
126 }
127 if (value.IsBoolean()) {
128 return RemoteObject::Boolean(value.IsTrue());
129 }
130 if (value.IsInt()) {
131 return RemoteObject::Number(value.GetInt());
132 }
133 if (value.IsDouble()) {
134 return RemoteObject::Number(value.GetDouble());
135 }
136 UNREACHABLE();
137 }
138
CreateObject(ObjectHeader * object)139 RemoteObject ObjectRepository::CreateObject(ObjectHeader *object)
140 {
141 ASSERT(ManagedThread::GetCurrent()->GetMutatorLock()->HasLock());
142
143 if (object == nullptr) {
144 return RemoteObject::Null();
145 }
146
147 if (auto str = extension_->GetAsString(object)) {
148 return RemoteObject::String(*str);
149 }
150
151 RemoteObjectId id;
152
153 // SUPPRESS_CSA_NEXTLINE(alpha.core.WasteObjHeader)
154 auto it = std::find_if(objects_.begin(), objects_.end(), [object](auto &p) { return p.second.GetPtr() == object; });
155 if (it == objects_.end()) {
156 id = counter_++;
157
158 objects_.emplace(std::piecewise_construct, std::forward_as_tuple(id),
159 std::forward_as_tuple(ManagedThread::GetCurrent(), object));
160 } else {
161 id = it->first;
162 }
163
164 // SUPPRESS_CSA_NEXTLINE(alpha.core.WasteObjHeader)
165 if (auto arrayLen = extension_->GetLengthIfArray(object)) {
166 // SUPPRESS_CSA_NEXTLINE(alpha.core.WasteObjHeader)
167 return RemoteObject::Array(extension_->GetClassName(object), *arrayLen, id);
168 }
169
170 // SUPPRESS_CSA_NEXTLINE(alpha.core.WasteObjHeader)
171 return RemoteObject::Object(extension_->GetClassName(object), id);
172 }
173
GetProperties(RemoteObjectId id)174 std::vector<PropertyDescriptor> ObjectRepository::GetProperties(RemoteObjectId id)
175 {
176 ASSERT(ManagedThread::GetCurrent()->GetMutatorLock()->HasLock());
177
178 auto fIt = frames_.find(id);
179 if (fIt != frames_.end()) {
180 ASSERT(objects_.find(id) == objects_.end());
181 return fIt->second;
182 }
183
184 std::vector<PropertyDescriptor> properties;
185 auto propertyHandler = [this, &properties](auto &name, auto value, auto isArrayElement, auto isFinal,
186 auto isAccessor) {
187 auto property = isAccessor ? PropertyDescriptor::Accessor(name, CreateObject(value))
188 : PropertyDescriptor(name, CreateObject(value), isArrayElement);
189 if (!isAccessor && isFinal) {
190 property.SetWritable(false);
191 }
192 properties.emplace_back(std::move(property));
193 };
194
195 if (id == GLOBAL_OBJECT_ID) {
196 ASSERT(objects_.find(id) == objects_.end());
197 extension_->EnumerateGlobals(propertyHandler);
198 } else {
199 auto oIt = objects_.find(id);
200 if (oIt == objects_.end()) {
201 LOG(INFO, DEBUGGER) << "Unknown object ID " << id;
202 return {};
203 }
204
205 extension_->EnumerateProperties(oIt->second.GetPtr(), propertyHandler);
206 }
207
208 return properties;
209 }
210 } // namespace ark::tooling::inspector
211