1 /*
2 * Copyright (c) 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 "ecmascript/dfx/hprof/rawheap_translate/metadata_parse.h"
17
18 namespace rawheap_translate {
Parse(const cJSON * object)19 bool MetaParser::Parse(const cJSON *object)
20 {
21 if (!ParseVersion(object) || !ParseTypeEnums(object) || !ParseTypeList(object) ||
22 !ParseTypeLayoutAndDesc(object)) {
23 return false;
24 }
25
26 GenerateMetaData();
27 SetBitField("HCLASS", "BitField", bitField_.objectTypeField);
28 SetBitField("JS_NATIVE_POINTER", "BindingSize", bitField_.nativePointerBindingSizeField);
29 SetBitField("TAGGED_ARRAY", "Length", bitField_.taggedArrayLengthField);
30 SetBitField("TAGGED_ARRAY", "Data", bitField_.taggedArrayDataField);
31 return true;
32 }
33
GetJSTypeFromHClass(Node * hclass)34 JSType MetaParser::GetJSTypeFromHClass(Node *hclass)
35 {
36 JSType type = static_cast<JSType>(ByteToU32(hclass->data + bitField_.objectTypeField.offset));
37 if (type < orderedMeta_.size()) {
38 // lower 8-bits of 32-bit value means JSType
39 return type;
40 }
41 LOG_ERROR_ << "js type error, " << (int)type;
42 return 0;
43 }
44
GetJSTypeFromTypeName(const std::string & name)45 JSType MetaParser::GetJSTypeFromTypeName(const std::string &name)
46 {
47 MetaData *meta = GetMetaData(name);
48 if (meta == nullptr) {
49 return 0; // 0: INVALID type
50 }
51 return meta->type;
52 }
53
GetNodeType(JSType type)54 NodeType MetaParser::GetNodeType(JSType type)
55 {
56 MetaData *meta = GetMetaData(type);
57 if (meta == nullptr) {
58 return DEFAULT_NODETYPE;
59 }
60 return meta->nodeType;
61 }
62
GetNativateSize(Node * node,JSType type)63 uint32_t MetaParser::GetNativateSize(Node *node, JSType type)
64 {
65 if (!IsNativePointer(type)) {
66 return 0;
67 }
68 return ByteToU32(node->data + bitField_.nativePointerBindingSizeField.offset);
69 }
70
GetTypeName(JSType type)71 std::string MetaParser::GetTypeName(JSType type)
72 {
73 MetaData *meta = GetMetaData(type);
74 if (meta != nullptr) {
75 return meta->name;
76 }
77 return "UNKNOWN_TYPE";
78 }
79
GetMetaData(const std::string & name)80 MetaData* MetaParser::GetMetaData(const std::string &name)
81 {
82 auto meta = meta_.find(name);
83 if (meta != meta_.end()) {
84 return meta->second;
85 }
86 return nullptr;
87 }
88
GetMetaData(const JSType type)89 MetaData *MetaParser::GetMetaData(const JSType type)
90 {
91 if (type < orderedMeta_.size()) {
92 return orderedMeta_[type];
93 }
94 return nullptr;
95 }
96
IsNativePointer(JSType type)97 bool MetaParser::IsNativePointer(JSType type)
98 {
99 return type == GetJSTypeFromTypeName("JS_NATIVE_POINTER");
100 }
101
IsString(JSType type)102 bool MetaParser::IsString(JSType type)
103 {
104 return typeRange_.stringFirst <= type && type <= typeRange_.stringLast;
105 }
106
IsDictionaryMode(JSType type)107 bool MetaParser::IsDictionaryMode(JSType type)
108 {
109 return type == GetJSTypeFromTypeName("TAGGED_DICTIONARY");
110 }
111
IsJSObject(JSType type)112 bool MetaParser::IsJSObject(JSType type)
113 {
114 return typeRange_.objectFirst <= type && type <= typeRange_.objectLast;
115 }
116
IsGlobalEnv(JSType type)117 bool MetaParser::IsGlobalEnv(JSType type)
118 {
119 return type == GetJSTypeFromTypeName("GLOBAL_ENV");
120 }
121
IsArray(JSType type)122 bool MetaParser::IsArray(JSType type)
123 {
124 MetaData *meta = GetMetaData(type);
125 if (meta != nullptr && meta->IsArray()) {
126 return true;
127 }
128 return false;
129 }
130
ParseTypeEnums(const cJSON * json)131 bool MetaParser::ParseTypeEnums(const cJSON *json)
132 {
133 cJSON *typeEnums = cJSON_GetObjectItem(json, "type_enum");
134 JSType type = 0;
135 auto visitor = [&type, this] (const cJSON *item) {
136 if (item->type == cJSON_Number) {
137 MetaData *meta = FindOrCreateMetaData(item->string);
138 // valuedouble: The item's number, if type==cJSON_Number
139 meta->nodeType = static_cast<NodeType>(item->valuedouble);
140 meta->type = type++;
141 orderedMeta_.push_back(meta);
142 }
143 };
144 IterateJSONArray(typeEnums, visitor);
145 LOG_INFO_ << "total JSType count " << orderedMeta_.size();
146 return true;
147 }
148
ParseTypeList(const cJSON * json)149 bool MetaParser::ParseTypeList(const cJSON *json)
150 {
151 cJSON *metadatas {nullptr};
152 if (!GetArray(json, "type_list", &metadatas)) {
153 LOG_ERROR_ << "get type list item failed!";
154 return false;
155 }
156
157 auto metaVisitor = [this](const cJSON *item) {
158 std::string name;
159 GetString(item, "name", name);
160 MetaData *meta = FindOrCreateMetaData(name);
161 GetString(item, "visit_type", meta->visitType);
162 GetUInt32(item, "end_offset", meta->endOffset);
163
164 cJSON *parents {nullptr};
165 cJSON *offsets {nullptr};
166 if (GetArray(item, "parents", &parents) && GetArray(item, "offsets", &offsets)) {
167 ParseParents(parents, meta);
168 ParseOffsets(offsets, meta);
169 }
170 };
171
172 IterateJSONArray(metadatas, metaVisitor);
173 LOG_INFO_ << "total metadata count " << meta_.size();
174 return true;
175 }
176
ParseTypeLayoutAndDesc(const cJSON * json)177 bool MetaParser::ParseTypeLayoutAndDesc(const cJSON *json)
178 {
179 cJSON *object = cJSON_GetObjectItem(json, "type_layout");
180 cJSON *dictLayout = cJSON_GetObjectItem(object, "Dictionary_layout");
181 GetUInt32(dictLayout, "key_index", dictionaryLayout_.keyIndex);
182 GetUInt32(dictLayout, "value_index", dictionaryLayout_.valueIndex);
183 GetUInt32(dictLayout, "detail_index", dictionaryLayout_.detailIndex);
184 GetUInt32(dictLayout, "entry_size", dictionaryLayout_.entrySize);
185 GetUInt32(dictLayout, "header_size", dictionaryLayout_.headerSize);
186
187 cJSON *typeRange = cJSON_GetObjectItem(object, "Type_range");
188 std::string name;
189 GetString(typeRange, "string_first", name);
190 typeRange_.stringFirst = GetJSTypeFromTypeName(name);
191 GetString(typeRange, "string_last", name);
192 typeRange_.stringLast = GetJSTypeFromTypeName(name);
193 GetString(typeRange, "js_object_first", name);
194 typeRange_.objectFirst = GetJSTypeFromTypeName(name);
195 GetString(typeRange, "js_object_last", name);
196 typeRange_.objectLast = GetJSTypeFromTypeName(name);
197 return true;
198 }
199
ParseVersion(const cJSON * json)200 bool MetaParser::ParseVersion(const cJSON *json)
201 {
202 std::string versionId;
203 if (!GetString(json, "version", versionId)) {
204 LOG_ERROR_ << "version not found!";
205 return false;
206 }
207
208 if (!version_.Parse(versionId)) {
209 return false;
210 }
211
212 LOG_INFO_ << "current meta version is " << version_.ToString();
213 return true;
214 }
215
ParseParents(const cJSON * array,MetaData * meta)216 void MetaParser::ParseParents(const cJSON *array, MetaData *meta)
217 {
218 if (cJSON_GetArraySize(array) <= 0) {
219 return;
220 }
221 cJSON *item = cJSON_GetArrayItem(array, 0);
222 if (item->type == cJSON_String) {
223 meta->parent = FindOrCreateMetaData(item->valuestring);
224 }
225 }
226
ParseOffsets(const cJSON * array,MetaData * meta)227 void MetaParser::ParseOffsets(const cJSON *array, MetaData *meta)
228 {
229 auto visitor = [&meta](const cJSON *item) {
230 Field field;
231 GetString(item, "name", field.name);
232 GetUInt32(item, "offset", field.offset);
233 GetUInt32(item, "size", field.size);
234 meta->fields.push_back(field);
235 };
236 IterateJSONArray(array, visitor);
237 }
238
SetBitField(const std::string & metaName,const std::string & fieldName,Field & field)239 void MetaParser::SetBitField(const std::string &metaName, const std::string &fieldName, Field &field)
240 {
241 MetaData *meta = GetMetaData(metaName);
242 if (meta == nullptr) {
243 return;
244 }
245
246 for (const auto &field_ : meta->fields) {
247 if (field_.name == fieldName) {
248 field = field_;
249 break;
250 }
251 }
252
253 LOG_INFO_ << "set " << fieldName << " offset " << field.offset;
254 }
255
FillMetaData(MetaData * parent,MetaData * meta)256 void MetaParser::FillMetaData(MetaData *parent, MetaData *meta)
257 {
258 if (parent->parent != nullptr) {
259 FillMetaData(parent->parent, meta);
260 }
261
262 for (const auto &field : parent->fields) {
263 meta->fields.push_back({field.name, field.offset + meta->endOffset, field.size});
264 }
265
266 meta->endOffset += parent->endOffset;
267
268 if (parent->IsArray()) {
269 meta->visitType = parent->visitType;
270 }
271 }
272
GenerateMetaData()273 void MetaParser::GenerateMetaData()
274 {
275 std::unordered_map<std::string, MetaData *> newMeta {};
276 for (auto &it : meta_) {
277 MetaData *meta = new MetaData();
278 newMeta.emplace(it.first, meta);
279 FillMetaData(it.second, meta);
280 }
281
282 for (auto &it : meta_) {
283 MetaData *meta = newMeta[it.first];
284 it.second->fields.swap(meta->fields);
285 it.second->visitType = meta->visitType;
286 it.second->endOffset = meta->endOffset;
287 delete meta;
288 }
289
290 newMeta.clear();
291 }
292
FindOrCreateMetaData(const std::string & name)293 MetaData *MetaParser::FindOrCreateMetaData(const std::string &name)
294 {
295 MetaData *meta = GetMetaData(name);
296 if (meta == nullptr) {
297 meta = new MetaData();
298 meta->name = name;
299 meta_[name] = meta;
300 }
301 return meta;
302 }
303
IterateJSONArray(const cJSON * array,const std::function<void (const cJSON *)> & visitor)304 void MetaParser::IterateJSONArray(const cJSON *array, const std::function<void(const cJSON *)> &visitor)
305 {
306 int size = cJSON_GetArraySize(array);
307 for (int i = 0; i < size; i++) {
308 cJSON *item = cJSON_GetArrayItem(array, i);
309 visitor(item);
310 }
311 }
312
GetArray(const cJSON * json,const char * key,cJSON ** value)313 bool MetaParser::GetArray(const cJSON *json, const char *key, cJSON **value)
314 {
315 cJSON *array = cJSON_GetObjectItem(json, key);
316 if (array == nullptr || cJSON_IsArray(array) == 0) {
317 return false;
318 }
319 *value = array;
320 return true;
321 }
322
GetString(const cJSON * json,const char * key,std::string & value)323 bool MetaParser::GetString(const cJSON *json, const char *key, std::string &value)
324 {
325 cJSON *item = cJSON_GetObjectItem(json, key);
326 if (item == nullptr) {
327 return false;
328 }
329 return GetString(item, value);
330 }
331
GetString(const cJSON * json,std::string & value)332 bool MetaParser::GetString(const cJSON *json, std::string &value)
333 {
334 if (cJSON_IsString(json) == 0) {
335 return false;
336 }
337 value = json->valuestring;
338 return true;
339 }
340
GetUInt32(const cJSON * json,const char * key,uint32_t & value)341 bool MetaParser::GetUInt32(const cJSON *json, const char *key, uint32_t &value)
342 {
343 cJSON *item = cJSON_GetObjectItem(json, key);
344 if (item == nullptr) {
345 return false;
346 }
347 return GetUInt32(item, value);
348 }
349
GetUInt32(const cJSON * json,uint32_t & value)350 bool MetaParser::GetUInt32(const cJSON *json, uint32_t &value)
351 {
352 if (cJSON_IsNumber(json) == 0) {
353 return false;
354 }
355 if (json->valuedouble < 0 || json->valuedouble > static_cast<double>(UINT32_MAX)) {
356 return false;
357 }
358 value = static_cast<uint32_t>(json->valuedouble);
359 return true;
360 }
361 } // namespace rawheap_translate