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