1 /**
2 * Copyright (c) 2023-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/include/class.h"
17 #include "runtime/include/coretypes/array-inl.h"
18 #include "runtime/include/coretypes/string-inl.h"
19 #include "runtime/include/object_header.h"
20 #include "runtime/include/hclass.h"
21 #include "runtime/mem/object_helpers-inl.h"
22 #include "runtime/tooling/default_inspector_extension.h"
23
24 namespace ark::tooling {
25
GetArrayElementValueStatic(const coretypes::Array & array,size_t offset,panda_file::Type type)26 static TypedValue GetArrayElementValueStatic(const coretypes::Array &array, size_t offset, panda_file::Type type)
27 {
28 switch (type.GetId()) {
29 case panda_file::Type::TypeId::INVALID:
30 return TypedValue::Invalid();
31 case panda_file::Type::TypeId::VOID:
32 return TypedValue::Void();
33 case panda_file::Type::TypeId::U1:
34 return TypedValue::U1(array.GetPrimitive<uint8_t>(offset) != 0);
35 case panda_file::Type::TypeId::I8:
36 return TypedValue::I8(array.GetPrimitive<int8_t>(offset));
37 case panda_file::Type::TypeId::U8:
38 return TypedValue::U8(array.GetPrimitive<uint8_t>(offset));
39 case panda_file::Type::TypeId::I16:
40 return TypedValue::I16(array.GetPrimitive<int16_t>(offset));
41 case panda_file::Type::TypeId::U16:
42 return TypedValue::U16(array.GetPrimitive<uint16_t>(offset));
43 case panda_file::Type::TypeId::I32:
44 return TypedValue::I32(array.GetPrimitive<int32_t>(offset));
45 case panda_file::Type::TypeId::U32:
46 return TypedValue::U32(array.GetPrimitive<uint32_t>(offset));
47 case panda_file::Type::TypeId::F32:
48 return TypedValue::F32(array.GetPrimitive<float>(offset));
49 case panda_file::Type::TypeId::F64:
50 return TypedValue::F64(array.GetPrimitive<double>(offset));
51 case panda_file::Type::TypeId::I64:
52 return TypedValue::I64(array.GetPrimitive<int64_t>(offset));
53 case panda_file::Type::TypeId::U64:
54 return TypedValue::U64(array.GetPrimitive<uint64_t>(offset));
55 case panda_file::Type::TypeId::REFERENCE:
56 return TypedValue::Reference(array.GetObject(offset));
57 case panda_file::Type::TypeId::TAGGED:
58 default:
59 UNREACHABLE();
60 }
61 UNREACHABLE();
62 }
63
64 template <typename T>
GetFieldValueStatic(T object,const Field & field)65 static TypedValue GetFieldValueStatic(T object, const Field &field)
66 {
67 switch (field.GetType().GetId()) {
68 case panda_file::Type::TypeId::INVALID:
69 return TypedValue::Invalid();
70 case panda_file::Type::TypeId::VOID:
71 return TypedValue::Void();
72 case panda_file::Type::TypeId::U1:
73 return TypedValue::U1(object->template GetFieldPrimitive<uint8_t>(field.GetOffset()) != 0);
74 case panda_file::Type::TypeId::I8:
75 return TypedValue::I8(object->template GetFieldPrimitive<int8_t>(field.GetOffset()));
76 case panda_file::Type::TypeId::U8:
77 return TypedValue::U8(object->template GetFieldPrimitive<uint8_t>(field.GetOffset()));
78 case panda_file::Type::TypeId::I16:
79 return TypedValue::I16(object->template GetFieldPrimitive<int16_t>(field.GetOffset()));
80 case panda_file::Type::TypeId::U16:
81 return TypedValue::U16(object->template GetFieldPrimitive<uint16_t>(field.GetOffset()));
82 case panda_file::Type::TypeId::I32:
83 return TypedValue::I32(object->template GetFieldPrimitive<int32_t>(field.GetOffset()));
84 case panda_file::Type::TypeId::U32:
85 return TypedValue::U32(object->template GetFieldPrimitive<uint32_t>(field.GetOffset()));
86 case panda_file::Type::TypeId::F32:
87 return TypedValue::F32(object->template GetFieldPrimitive<float>(field.GetOffset()));
88 case panda_file::Type::TypeId::F64:
89 return TypedValue::F64(object->template GetFieldPrimitive<double>(field.GetOffset()));
90 case panda_file::Type::TypeId::I64:
91 return TypedValue::I64(object->template GetFieldPrimitive<int64_t>(field.GetOffset()));
92 case panda_file::Type::TypeId::U64:
93 return TypedValue::U64(object->template GetFieldPrimitive<uint64_t>(field.GetOffset()));
94 case panda_file::Type::TypeId::REFERENCE:
95 return TypedValue::Reference(object->GetFieldObject(field.GetOffset()));
96 case panda_file::Type::TypeId::TAGGED:
97 default:
98 UNREACHABLE();
99 }
100 UNREACHABLE();
101 }
102
GetClassName(const ObjectHeader * object)103 std::string StaticDefaultInspectorExtension::GetClassName(const ObjectHeader *object)
104 {
105 return ClassHelper::GetNameUndecorated(object->ClassAddr<Class>()->GetDescriptor());
106 }
107
GetAsString(const ObjectHeader * object)108 std::optional<std::string> StaticDefaultInspectorExtension::GetAsString(const ObjectHeader *object)
109 {
110 if (!object->ClassAddr<Class>()->IsStringClass()) {
111 return {};
112 }
113
114 std::string value;
115
116 auto string = coretypes::String::Cast(const_cast<ObjectHeader *>(object));
117 for (auto index = 0U; index < string->GetLength(); ++index) {
118 value.push_back(string->At(index));
119 }
120 return value;
121 }
122
GetLengthIfArray(const ObjectHeader * object)123 std::optional<size_t> StaticDefaultInspectorExtension::GetLengthIfArray(const ObjectHeader *object)
124 {
125 if (!object->ClassAddr<Class>()->IsArrayClass()) {
126 return {};
127 }
128 return coretypes::Array::Cast(const_cast<ObjectHeader *>(object))->GetLength();
129 }
130
EnumerateProperties(const ObjectHeader * object,const std::function<void (const std::string &,TypedValue,bool,bool,bool)> & handler)131 void StaticDefaultInspectorExtension::EnumerateProperties(
132 const ObjectHeader *object, const std::function<void(const std::string &, TypedValue, bool, bool, bool)> &handler)
133 {
134 auto cls = object->ClassAddr<Class>();
135 ASSERT(cls != nullptr);
136 if (cls->IsArrayClass()) {
137 auto &array = *coretypes::Array::Cast(const_cast<ObjectHeader *>(object));
138 auto type = cls->GetComponentType()->GetType();
139 for (auto index = 0U; index < array.GetLength(); ++index) {
140 auto offset = index * cls->GetComponentSize();
141 handler(std::to_string(index), GetArrayElementValueStatic(array, offset, type), true, false, false);
142 }
143 } else if (cls->IsClassClass()) {
144 auto runtimeCls = ark::Class::FromClassObject(object);
145 for (auto &field : runtimeCls->GetStaticFields()) {
146 handler(utf::Mutf8AsCString(field.GetName().data), GetFieldValueStatic(runtimeCls, field), false,
147 field.IsFinal(), false);
148 }
149 } else {
150 for (const auto &field : cls->GetInstanceFields()) {
151 handler(utf::Mutf8AsCString(field.GetName().data), GetFieldValueStatic(object, field), false,
152 field.IsFinal(), false);
153 }
154 }
155 }
156
EnumerateGlobals(const PropertyHandler & handler)157 void StaticDefaultInspectorExtension::EnumerateGlobals(const PropertyHandler &handler)
158 {
159 auto classLinkerExtension = Runtime::GetCurrent()->GetClassLinker()->GetExtension(lang_);
160 ASSERT(classLinkerExtension != nullptr);
161 classLinkerExtension->EnumerateClasses([&handler](auto cls) {
162 if (cls->IsInitialized() && cls->GetNumStaticFields() > 0) {
163 handler(cls->GetName(), TypedValue::Reference(cls->GetManagedObject()), false, false, false);
164 }
165 return true;
166 });
167 }
168
GetClassName(const ObjectHeader * object)169 std::string DynamicDefaultInspectorExtension::GetClassName(const ObjectHeader *object)
170 {
171 if (object->ClassAddr<HClass>()->IsString()) {
172 return "String object";
173 }
174 return "Dynamic object";
175 }
176
GetAsString(const ObjectHeader * object)177 std::optional<std::string> DynamicDefaultInspectorExtension::GetAsString([[maybe_unused]] const ObjectHeader *object)
178 {
179 return {};
180 }
181
GetLengthIfArray(const ObjectHeader * object)182 std::optional<size_t> DynamicDefaultInspectorExtension::GetLengthIfArray(const ObjectHeader *object)
183 {
184 if (!object->ClassAddr<HClass>()->IsArray()) {
185 return {};
186 }
187 auto length = coretypes::Array::Cast(const_cast<ObjectHeader *>(object))->GetLength();
188 return length;
189 }
190
EnumerateProperties(const ObjectHeader * object,const std::function<void (const std::string &,TypedValue,bool,bool,bool)> & handler)191 void DynamicDefaultInspectorExtension::EnumerateProperties(
192 const ObjectHeader *object, const std::function<void(const std::string &, TypedValue, bool, bool, bool)> &handler)
193 {
194 auto *cls = object->ClassAddr<HClass>();
195 ASSERT(cls != nullptr);
196 if (cls->IsNativePointer() || cls->IsString()) {
197 return;
198 }
199
200 if (cls->IsArray()) {
201 auto &array = *coretypes::Array::Cast(const_cast<ObjectHeader *>(object));
202 ArraySizeT arrayLength = array.GetLength();
203 for (coretypes::ArraySizeT i = 0; i < arrayLength; i++) {
204 TaggedValue arrayElement(array.Get<TaggedType, false, true>(i));
205 handler(std::to_string(i), TypedValue::Tagged(arrayElement), true, false, false);
206 }
207 } else if (cls->IsHClass()) {
208 auto dataOffset = sizeof(ObjectHeader) + sizeof(HClass);
209 auto objBodySize = cls->GetObjectSize() - dataOffset;
210 ASSERT(objBodySize % TaggedValue::TaggedTypeSize() == 0);
211 auto numOfFields = objBodySize / TaggedValue::TaggedTypeSize();
212 for (size_t i = 0; i < numOfFields; i++) {
213 auto fieldOffset = dataOffset + i * TaggedValue::TaggedTypeSize();
214 auto taggedValue = ObjectAccessor::GetDynValue<TaggedValue>(object, fieldOffset);
215 handler(std::to_string(i), TypedValue::Tagged(taggedValue), false, false, false);
216 }
217 } else {
218 uint32_t objBodySize = cls->GetObjectSize() - ObjectHeader::ObjectHeaderSize();
219 ASSERT(objBodySize % TaggedValue::TaggedTypeSize() == 0);
220 uint32_t numOfFields = objBodySize / TaggedValue::TaggedTypeSize();
221 size_t dataOffset = ObjectHeader::ObjectHeaderSize();
222 for (uint32_t i = 0; i < numOfFields; i++) {
223 size_t fieldOffset = dataOffset + i * TaggedValue::TaggedTypeSize();
224 if (cls->IsNativeField(fieldOffset)) {
225 continue;
226 }
227 auto taggedValue = ObjectAccessor::GetDynValue<TaggedValue>(object, fieldOffset);
228 handler(std::to_string(i), TypedValue::Tagged(taggedValue), false, false, false);
229 }
230 }
231 }
232 } // namespace ark::tooling
233