• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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