1 /*
2 * Copyright (c) Huawei Technologies Co., Ltd. 2020-2020. All rights reserved.
3 * Description: improve heap dump.
4 * Create: 2020/11/20
5 */
6
7 #include "heapdump.h"
8
9 #include "ecma-builtins.h"
10 #include "ecma-conversion.h"
11 #include "ecma-gc.h"
12 #include "ecma-globals.h"
13 #include "ecma-helpers.h"
14 #include "ecma-property-hashmap.h"
15 #include "ecma-array-object.h"
16
17 #include <stdio.h>
18
19 bool gHeapdumpTracing = false;
20 FILE* gLogHeapdumpFile = NULL;
GetHeapdumpTracing(void)21 bool GetHeapdumpTracing(void)
22 {
23 return gHeapdumpTracing;
24 }
25
SetHeapdumpTraring(bool flag)26 void SetHeapdumpTraring(bool flag)
27 {
28 gHeapdumpTracing = flag;
29 }
30
GetHeapdumpFile(void)31 FILE* GetHeapdumpFile(void)
32 {
33 return gLogHeapdumpFile;
34 }
35
LogHeapdumpInit(const char * filepath)36 void LogHeapdumpInit(const char* filepath)
37 {
38 gLogHeapdumpFile = fopen(filepath, "w+");
39 }
40
LogHeapdumpClose(void)41 void LogHeapdumpClose(void)
42 {
43 fclose(gLogHeapdumpFile);
44 }
45
StartList(void)46 static void StartList(void)
47 {
48 LogHeapdump("[\n");
49 }
50
EndList(void)51 static void EndList(void)
52 {
53 LogHeapdump("]\n");
54 }
55
Start(void)56 static void Start(void)
57 {
58 LogHeapdump("{\n");
59 }
60
End(void)61 static void End(void)
62 {
63 LogHeapdump("}\n");
64 }
65
Next(void)66 static void Next(void)
67 {
68 LogHeapdump(",\n");
69 }
70
LogStr(const char * str)71 static void LogStr(const char* str)
72 {
73 LogHeapdump("\"%s\"\n", str);
74 }
75
LogAddr(void * addr)76 static void LogAddr(void* addr)
77 {
78 LogHeapdump("\"%p\"\n", addr);
79 }
80
LogUint(unsigned int val)81 static void LogUint(unsigned int val)
82 {
83 LogHeapdump("%u\n", val);
84 }
85
LogStrObj(const ecma_string_t * obj)86 static void LogStrObj(const ecma_string_t* obj)
87 {
88 ECMA_STRING_TO_UTF8_STRING(obj, str, str_size);
89 LogHeapdump("\"");
90 for (int ii = 0; ii < (int)str_size; ++ii) {
91 LogHeapdump("%c", str[ii]);
92 }
93 LogHeapdump("\"\n");
94 }
95
Key(const char * key)96 static void Key(const char* key)
97 {
98 LogHeapdump("\"%s\"", key);
99 LogHeapdump(":\n");
100 }
101
KeyUint(unsigned int key)102 static void KeyUint(unsigned int key)
103 {
104 LogHeapdump("\"%u\"", key);
105 LogHeapdump(":\n");
106 }
107
Type(const char * type)108 static void Type(const char* type)
109 {
110 Key("type");
111 LogHeapdump("\"%s\"", type);
112 Next();
113 }
114
Addr(void * addr)115 static void Addr(void* addr)
116 {
117 Key("addr");
118 LogHeapdump("\"%p\"", addr);
119 Next();
120 }
121
DumpInfoLexEnv(const ecma_object_t * object)122 void DumpInfoLexEnv(const ecma_object_t* object)
123 {
124 Key("outer");
125 jmem_cpointer_t outer_lex_env_cp = object->u2.outer_reference_cp;
126 if (outer_lex_env_cp != JMEM_CP_NULL) {
127 LogAddr(ECMA_GET_NON_NULL_POINTER(ecma_object_t, outer_lex_env_cp));
128 } else {
129 LogAddr(NULL);
130 }
131 Next();
132
133 Key("subtype");
134 if (ecma_get_lex_env_type(object) != ECMA_LEXICAL_ENVIRONMENT_DECLARATIVE) {
135 LogStr("binding");
136 Next();
137
138 Key("binding");
139 ecma_object_t *binding_object_p = ecma_get_lex_env_binding_object(object);
140 LogAddr(binding_object_p);
141 } else {
142 LogStr("declarative");
143 }
144 }
145
DumpInfoFunction(const ecma_object_t * object)146 void DumpInfoFunction(const ecma_object_t* object)
147 {
148 Key("is_builtin");
149 ecma_extended_object_t* ext_obj = (ecma_extended_object_t*)object;
150 if (ecma_get_object_is_builtin (object)) {
151 LogStr("true");
152 Next();
153
154 Key("is_routine");
155 if (ecma_builtin_function_is_routine ((ecma_object_t*)object)) {
156 LogStr("true");
157 } else {
158 LogStr("true");
159 }
160 Next();
161
162 Key("id");
163 LogUint(ext_obj->u.built_in.id);
164 Next();
165 Key("routine_id");
166 LogUint(ext_obj->u.built_in.routine_id);
167 } else {
168 LogStr("false");
169 Next();
170
171 Key("scope");
172 LogAddr(ECMA_GET_INTERNAL_VALUE_POINTER(ecma_object_t, ext_obj->u.function.scope_cp));
173 }
174 }
175
DumpPropertyPair(ecma_property_pair_t * pair)176 void DumpPropertyPair(ecma_property_pair_t* pair)
177 {
178 ecma_property_header_t* header = (ecma_property_header_t*)pair;
179 for (int i = 0; i < ECMA_PROPERTY_PAIR_ITEM_COUNT; i++) {
180 Start();
181
182 switch (ECMA_PROPERTY_GET_TYPE(header->types[i])) {
183 case ECMA_PROPERTY_TYPE_NAMEDDATA: {
184 Type("data");
185
186 Key("key");
187 ecma_string_t* key_str = ecma_string_from_property_name(header->types[i],
188 pair->names_cp[i]);
189 LogStrObj(key_str);
190 ecma_deref_ecma_string(key_str);
191 Next();
192
193 Key("value");
194 ecma_value_t value = pair->values[i].value;
195 if (ecma_is_value_object(value)) {
196 ecma_object_t* value_obj = ecma_get_object_from_value(value);
197 LogAddr(value_obj);
198 } else {
199 ecma_string_t* value_str = ecma_op_to_string(value);
200 LogStrObj(value_str);
201 }
202 break;
203 }
204 case ECMA_PROPERTY_TYPE_NAMEDACCESSOR: {
205 Type("accessor");
206
207 ecma_property_value_t* accessor_objs_p = pair->values + i;
208 ecma_getter_setter_pointers_t* get_set_pair_p =
209 ecma_get_named_accessor_property(accessor_objs_p);
210
211 Key("getter");
212 if (get_set_pair_p->getter_cp != JMEM_CP_NULL) {
213 LogAddr(ECMA_GET_NON_NULL_POINTER(ecma_object_t, get_set_pair_p->getter_cp));
214 } else {
215 LogAddr(NULL);
216 }
217 Next();
218
219 Key("setter");
220 if (get_set_pair_p->setter_cp != JMEM_CP_NULL) {
221 LogAddr(ECMA_GET_NON_NULL_POINTER(ecma_object_t, get_set_pair_p->setter_cp));
222 } else {
223 LogAddr(NULL);
224 }
225 break;
226 }
227 case ECMA_PROPERTY_TYPE_INTERNAL: {
228 Type("internal");
229 Key("TODO");
230 LogStr("Not implemented yet");
231 break;
232 }
233 default: {
234 break;
235 }
236 }
237 End();
238 if (i + 1 < ECMA_PROPERTY_PAIR_ITEM_COUNT) {
239 Next();
240 }
241 }
242 }
243
DumpInfoObject(ecma_object_t * object,heapdump_object_flags_t flags)244 void DumpInfoObject(ecma_object_t* object, heapdump_object_flags_t flags)
245 {
246 Start();
247 Addr(object);
248 if (flags & HEAPDUMP_OBJECT_ROOT) {
249 Key("Root");
250 LogStr("true");
251 Next();
252 }
253
254 if (flags & HEAPDUMP_OBJECT_GLOBAL) {
255 Key("Global");
256 LogStr("true");
257 Next();
258 }
259
260 Key("RefCount");
261 LogUint(object->type_flags_refs >> REF_CNT_SHIFT);
262 Next();
263
264 if (ecma_is_lexical_environment(object)) {
265 Type("LexEnv");
266 DumpInfoLexEnv(object);
267 goto finish;
268 } else {
269 Key("__proto__");
270 jmem_cpointer_t proto_cp = object->u2.prototype_cp;
271 if (proto_cp != JMEM_CP_NULL) {
272 LogAddr(ECMA_GET_NON_NULL_POINTER (ecma_object_t, proto_cp));
273 } else {
274 LogAddr(NULL);
275 }
276 Next();
277 switch (ecma_get_object_type(object)) {
278 case ECMA_OBJECT_TYPE_EXTERNAL_FUNCTION: {
279 Type("ExternalFunction");
280 break;
281 }
282 case ECMA_OBJECT_TYPE_BOUND_FUNCTION: {
283 Type("BoundFunction");
284 break;
285 }
286 case ECMA_OBJECT_TYPE_FUNCTION: {
287 Type("Function");
288 DumpInfoFunction(object);
289 Next();
290 break;
291 }
292 case ECMA_OBJECT_TYPE_PSEUDO_ARRAY: {
293 Type("PseudoArray");
294 ecma_extended_object_t* ext_object = (ecma_extended_object_t*)object;
295 if (ext_object->u.pseudo_array.type == ECMA_PSEUDO_ARRAY_ARGUMENTS) {
296 Key("subtype");
297 LogStr("arguments");
298 Next();
299 ecma_object_t* lex_env = ECMA_GET_INTERNAL_VALUE_POINTER (ecma_object_t,
300 ext_object->u.pseudo_array.u2.lex_env_cp);
301 Key("lex_env");
302 LogAddr(lex_env);
303 } else {
304 Key("subtype");
305 LogStr("!!! Unknown");
306 }
307 goto finish;
308 }
309 case ECMA_OBJECT_TYPE_ARRAY: {
310 Type("Array");
311 ecma_extended_object_t* ext_object = (ecma_extended_object_t*)object;
312
313 if (ecma_op_object_is_fast_array(object)) {
314 Key("subtype");
315 LogStr("fast");
316 Next();
317
318 Key("data");
319 Start();
320 if (object->u1.property_list_cp != JMEM_CP_NULL) {
321 ecma_value_t *values =
322 ECMA_GET_NON_NULL_POINTER (ecma_value_t, object->u1.property_list_cp);
323 bool skip_comma = true;
324 for (uint32_t i = 0; i < ext_object->u.array.length; i++) {
325 if (ecma_is_value_array_hole(values[i])) {
326 continue;
327 }
328 if (skip_comma) {
329 skip_comma = false;
330 } else {
331 Next();
332 }
333 KeyUint(i);
334 if (ecma_is_value_object(values[i])) {
335 ecma_object_t* value_obj = ecma_get_object_from_value(values[i]);
336 LogAddr(value_obj);
337 } else {
338 ecma_string_t* value_str = ecma_op_to_string(values[i]);
339 LogStrObj(value_str);
340 }
341 }
342 }
343 End();
344 goto finish;
345 } else {
346 Key("subtype");
347 LogStr("sparse");
348 Next();
349 }
350 break;
351 }
352 default: {
353 Type("Object");
354 break;
355 }
356 }
357 }
358
359 jmem_cpointer_t prop_iter_cp = object->u1.property_list_cp;
360
361 #if ENABLED (JERRY_PROPRETY_HASHMAP)
362 if (prop_iter_cp != JMEM_CP_NULL) {
363 ecma_property_header_t* prop_iter_p =
364 ECMA_GET_NON_NULL_POINTER(ecma_property_header_t, prop_iter_cp);
365 if (prop_iter_p->types[0] == ECMA_PROPERTY_TYPE_HASHMAP) {
366 prop_iter_cp = prop_iter_p->next_property_cp;
367 }
368 }
369 #endif
370
371 Key("properties");
372 StartList();
373 while (prop_iter_cp != JMEM_CP_NULL) {
374 ecma_property_header_t* prop_iter_p =
375 ECMA_GET_NON_NULL_POINTER(ecma_property_header_t, prop_iter_cp);
376 DumpPropertyPair((ecma_property_pair_t *) prop_iter_p);
377
378 prop_iter_cp = prop_iter_p->next_property_cp;
379 if (prop_iter_cp != JMEM_CP_NULL) {
380 Next();
381 }
382 }
383 EndList();
384
385 finish:
386 End();
387 Next();
388 }
389