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 19bool gHeapdumpTracing = false; 20FILE* gLogHeapdumpFile = NULL; 21bool GetHeapdumpTracing(void) 22{ 23 return gHeapdumpTracing; 24} 25 26void SetHeapdumpTraring(bool flag) 27{ 28 gHeapdumpTracing = flag; 29} 30 31FILE* GetHeapdumpFile(void) 32{ 33 return gLogHeapdumpFile; 34} 35 36void LogHeapdumpInit(const char* filepath) 37{ 38 gLogHeapdumpFile = fopen(filepath, "w+"); 39} 40 41void LogHeapdumpClose(void) 42{ 43 fclose(gLogHeapdumpFile); 44} 45 46static void StartList(void) 47{ 48 LogHeapdump("[\n"); 49} 50 51static void EndList(void) 52{ 53 LogHeapdump("]\n"); 54} 55 56static void Start(void) 57{ 58 LogHeapdump("{\n"); 59} 60 61static void End(void) 62{ 63 LogHeapdump("}\n"); 64} 65 66static void Next(void) 67{ 68 LogHeapdump(",\n"); 69} 70 71static void LogStr(const char* str) 72{ 73 LogHeapdump("\"%s\"\n", str); 74} 75 76static void LogAddr(void* addr) 77{ 78 LogHeapdump("\"%p\"\n", addr); 79} 80 81static void LogUint(unsigned int val) 82{ 83 LogHeapdump("%u\n", val); 84} 85 86static 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 96static void Key(const char* key) 97{ 98 LogHeapdump("\"%s\"", key); 99 LogHeapdump(":\n"); 100} 101 102static void KeyUint(unsigned int key) 103{ 104 LogHeapdump("\"%u\"", key); 105 LogHeapdump(":\n"); 106} 107 108static void Type(const char* type) 109{ 110 Key("type"); 111 LogHeapdump("\"%s\"", type); 112 Next(); 113} 114 115static void Addr(void* addr) 116{ 117 Key("addr"); 118 LogHeapdump("\"%p\"", addr); 119 Next(); 120} 121 122void 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 146void 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 176void 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 244void 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