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