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/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 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), 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), field.IsFinal(),
147 false);
148 }
149 } else {
150 do {
151 for (const auto &field : cls->GetInstanceFields()) {
152 handler(utf::Mutf8AsCString(field.GetName().data), GetFieldValueStatic(object, field), field.IsFinal(),
153 false);
154 }
155 cls = cls->GetBase();
156 } while (cls != nullptr);
157 }
158 }
159
EnumerateGlobals(const PropertyHandler & handler)160 void PtStaticDefaultExtension::EnumerateGlobals(const PropertyHandler &handler)
161 {
162 auto classLinkerExtension = Runtime::GetCurrent()->GetClassLinker()->GetExtension(lang_);
163 ASSERT(classLinkerExtension != nullptr);
164 classLinkerExtension->EnumerateClasses([&handler](auto cls) {
165 if (cls->IsInitialized() && cls->GetNumStaticFields() > 0) {
166 handler(cls->GetName(), TypedValue::Reference(cls->GetManagedObject()), false, false);
167 }
168 return true;
169 });
170 }
171
GetClassName(const ObjectHeader * object)172 std::string PtDynamicDefaultExtension::GetClassName(const ObjectHeader *object)
173 {
174 if (object->ClassAddr<HClass>()->IsString()) {
175 return "String object";
176 }
177 return "Dynamic object";
178 }
179
GetAsString(const ObjectHeader * object)180 std::optional<std::string> PtDynamicDefaultExtension::GetAsString([[maybe_unused]] const ObjectHeader *object)
181 {
182 return {};
183 }
184
GetLengthIfArray(const ObjectHeader * object)185 std::optional<size_t> PtDynamicDefaultExtension::GetLengthIfArray(const ObjectHeader *object)
186 {
187 if (!object->ClassAddr<HClass>()->IsArray()) {
188 return {};
189 }
190 auto length = coretypes::Array::Cast(const_cast<ObjectHeader *>(object))->GetLength();
191 return length;
192 }
193
EnumerateProperties(const ObjectHeader * object,const PropertyHandler & handler)194 void PtDynamicDefaultExtension::EnumerateProperties(const ObjectHeader *object, const PropertyHandler &handler)
195 {
196 auto *cls = object->ClassAddr<HClass>();
197 ASSERT(cls != nullptr);
198 if (cls->IsNativePointer() || cls->IsString()) {
199 return;
200 }
201
202 if (cls->IsArray()) {
203 auto &array = *coretypes::Array::Cast(const_cast<ObjectHeader *>(object));
204 ArraySizeT arrayLength = array.GetLength();
205 for (coretypes::ArraySizeT i = 0; i < arrayLength; i++) {
206 TaggedValue arrayElement(array.Get<TaggedType, false, true>(i));
207 handler(std::to_string(i), TypedValue::Tagged(arrayElement), false, false);
208 }
209 } else if (cls->IsHClass()) {
210 auto dataOffset = sizeof(ObjectHeader) + sizeof(HClass);
211 auto objBodySize = cls->GetObjectSize() - dataOffset;
212 ASSERT(objBodySize % TaggedValue::TaggedTypeSize() == 0);
213 auto numOfFields = objBodySize / TaggedValue::TaggedTypeSize();
214 for (size_t i = 0; i < numOfFields; i++) {
215 auto fieldOffset = dataOffset + i * TaggedValue::TaggedTypeSize();
216 auto taggedValue = ObjectAccessor::GetDynValue<TaggedValue>(object, fieldOffset);
217 handler(std::to_string(i), TypedValue::Tagged(taggedValue), false, false);
218 }
219 } else {
220 uint32_t objBodySize = cls->GetObjectSize() - ObjectHeader::ObjectHeaderSize();
221 ASSERT(objBodySize % TaggedValue::TaggedTypeSize() == 0);
222 uint32_t numOfFields = objBodySize / TaggedValue::TaggedTypeSize();
223 size_t dataOffset = ObjectHeader::ObjectHeaderSize();
224 for (uint32_t i = 0; i < numOfFields; i++) {
225 size_t fieldOffset = dataOffset + i * TaggedValue::TaggedTypeSize();
226 if (cls->IsNativeField(fieldOffset)) {
227 continue;
228 }
229 auto taggedValue = ObjectAccessor::GetDynValue<TaggedValue>(object, fieldOffset);
230 handler(std::to_string(i), TypedValue::Tagged(taggedValue), false, false);
231 }
232 }
233 }
234 } // namespace ark::tooling
235