1425bb815Sopenharmony_ci/* 2425bb815Sopenharmony_ci * Copyright (c) Huawei Technologies Co., Ltd. 2020-2020. All rights reserved. 3425bb815Sopenharmony_ci * Description: improve heap dump. 4425bb815Sopenharmony_ci * Create: 2020/11/20 5425bb815Sopenharmony_ci */ 6425bb815Sopenharmony_ci 7425bb815Sopenharmony_ci#include "heapdump.h" 8425bb815Sopenharmony_ci 9425bb815Sopenharmony_ci#include "ecma-builtins.h" 10425bb815Sopenharmony_ci#include "ecma-conversion.h" 11425bb815Sopenharmony_ci#include "ecma-gc.h" 12425bb815Sopenharmony_ci#include "ecma-globals.h" 13425bb815Sopenharmony_ci#include "ecma-helpers.h" 14425bb815Sopenharmony_ci#include "ecma-property-hashmap.h" 15425bb815Sopenharmony_ci#include "ecma-array-object.h" 16425bb815Sopenharmony_ci 17425bb815Sopenharmony_ci#include <stdio.h> 18425bb815Sopenharmony_ci 19425bb815Sopenharmony_cibool gHeapdumpTracing = false; 20425bb815Sopenharmony_ciFILE* gLogHeapdumpFile = NULL; 21425bb815Sopenharmony_cibool GetHeapdumpTracing(void) 22425bb815Sopenharmony_ci{ 23425bb815Sopenharmony_ci return gHeapdumpTracing; 24425bb815Sopenharmony_ci} 25425bb815Sopenharmony_ci 26425bb815Sopenharmony_civoid SetHeapdumpTraring(bool flag) 27425bb815Sopenharmony_ci{ 28425bb815Sopenharmony_ci gHeapdumpTracing = flag; 29425bb815Sopenharmony_ci} 30425bb815Sopenharmony_ci 31425bb815Sopenharmony_ciFILE* GetHeapdumpFile(void) 32425bb815Sopenharmony_ci{ 33425bb815Sopenharmony_ci return gLogHeapdumpFile; 34425bb815Sopenharmony_ci} 35425bb815Sopenharmony_ci 36425bb815Sopenharmony_civoid LogHeapdumpInit(const char* filepath) 37425bb815Sopenharmony_ci{ 38425bb815Sopenharmony_ci gLogHeapdumpFile = fopen(filepath, "w+"); 39425bb815Sopenharmony_ci} 40425bb815Sopenharmony_ci 41425bb815Sopenharmony_civoid LogHeapdumpClose(void) 42425bb815Sopenharmony_ci{ 43425bb815Sopenharmony_ci fclose(gLogHeapdumpFile); 44425bb815Sopenharmony_ci} 45425bb815Sopenharmony_ci 46425bb815Sopenharmony_cistatic void StartList(void) 47425bb815Sopenharmony_ci{ 48425bb815Sopenharmony_ci LogHeapdump("[\n"); 49425bb815Sopenharmony_ci} 50425bb815Sopenharmony_ci 51425bb815Sopenharmony_cistatic void EndList(void) 52425bb815Sopenharmony_ci{ 53425bb815Sopenharmony_ci LogHeapdump("]\n"); 54425bb815Sopenharmony_ci} 55425bb815Sopenharmony_ci 56425bb815Sopenharmony_cistatic void Start(void) 57425bb815Sopenharmony_ci{ 58425bb815Sopenharmony_ci LogHeapdump("{\n"); 59425bb815Sopenharmony_ci} 60425bb815Sopenharmony_ci 61425bb815Sopenharmony_cistatic void End(void) 62425bb815Sopenharmony_ci{ 63425bb815Sopenharmony_ci LogHeapdump("}\n"); 64425bb815Sopenharmony_ci} 65425bb815Sopenharmony_ci 66425bb815Sopenharmony_cistatic void Next(void) 67425bb815Sopenharmony_ci{ 68425bb815Sopenharmony_ci LogHeapdump(",\n"); 69425bb815Sopenharmony_ci} 70425bb815Sopenharmony_ci 71425bb815Sopenharmony_cistatic void LogStr(const char* str) 72425bb815Sopenharmony_ci{ 73425bb815Sopenharmony_ci LogHeapdump("\"%s\"\n", str); 74425bb815Sopenharmony_ci} 75425bb815Sopenharmony_ci 76425bb815Sopenharmony_cistatic void LogAddr(void* addr) 77425bb815Sopenharmony_ci{ 78425bb815Sopenharmony_ci LogHeapdump("\"%p\"\n", addr); 79425bb815Sopenharmony_ci} 80425bb815Sopenharmony_ci 81425bb815Sopenharmony_cistatic void LogUint(unsigned int val) 82425bb815Sopenharmony_ci{ 83425bb815Sopenharmony_ci LogHeapdump("%u\n", val); 84425bb815Sopenharmony_ci} 85425bb815Sopenharmony_ci 86425bb815Sopenharmony_cistatic void LogStrObj(const ecma_string_t* obj) 87425bb815Sopenharmony_ci{ 88425bb815Sopenharmony_ci ECMA_STRING_TO_UTF8_STRING(obj, str, str_size); 89425bb815Sopenharmony_ci LogHeapdump("\""); 90425bb815Sopenharmony_ci for (int ii = 0; ii < (int)str_size; ++ii) { 91425bb815Sopenharmony_ci LogHeapdump("%c", str[ii]); 92425bb815Sopenharmony_ci } 93425bb815Sopenharmony_ci LogHeapdump("\"\n"); 94425bb815Sopenharmony_ci} 95425bb815Sopenharmony_ci 96425bb815Sopenharmony_cistatic void Key(const char* key) 97425bb815Sopenharmony_ci{ 98425bb815Sopenharmony_ci LogHeapdump("\"%s\"", key); 99425bb815Sopenharmony_ci LogHeapdump(":\n"); 100425bb815Sopenharmony_ci} 101425bb815Sopenharmony_ci 102425bb815Sopenharmony_cistatic void KeyUint(unsigned int key) 103425bb815Sopenharmony_ci{ 104425bb815Sopenharmony_ci LogHeapdump("\"%u\"", key); 105425bb815Sopenharmony_ci LogHeapdump(":\n"); 106425bb815Sopenharmony_ci} 107425bb815Sopenharmony_ci 108425bb815Sopenharmony_cistatic void Type(const char* type) 109425bb815Sopenharmony_ci{ 110425bb815Sopenharmony_ci Key("type"); 111425bb815Sopenharmony_ci LogHeapdump("\"%s\"", type); 112425bb815Sopenharmony_ci Next(); 113425bb815Sopenharmony_ci} 114425bb815Sopenharmony_ci 115425bb815Sopenharmony_cistatic void Addr(void* addr) 116425bb815Sopenharmony_ci{ 117425bb815Sopenharmony_ci Key("addr"); 118425bb815Sopenharmony_ci LogHeapdump("\"%p\"", addr); 119425bb815Sopenharmony_ci Next(); 120425bb815Sopenharmony_ci} 121425bb815Sopenharmony_ci 122425bb815Sopenharmony_civoid DumpInfoLexEnv(const ecma_object_t* object) 123425bb815Sopenharmony_ci{ 124425bb815Sopenharmony_ci Key("outer"); 125425bb815Sopenharmony_ci jmem_cpointer_t outer_lex_env_cp = object->u2.outer_reference_cp; 126425bb815Sopenharmony_ci if (outer_lex_env_cp != JMEM_CP_NULL) { 127425bb815Sopenharmony_ci LogAddr(ECMA_GET_NON_NULL_POINTER(ecma_object_t, outer_lex_env_cp)); 128425bb815Sopenharmony_ci } else { 129425bb815Sopenharmony_ci LogAddr(NULL); 130425bb815Sopenharmony_ci } 131425bb815Sopenharmony_ci Next(); 132425bb815Sopenharmony_ci 133425bb815Sopenharmony_ci Key("subtype"); 134425bb815Sopenharmony_ci if (ecma_get_lex_env_type(object) != ECMA_LEXICAL_ENVIRONMENT_DECLARATIVE) { 135425bb815Sopenharmony_ci LogStr("binding"); 136425bb815Sopenharmony_ci Next(); 137425bb815Sopenharmony_ci 138425bb815Sopenharmony_ci Key("binding"); 139425bb815Sopenharmony_ci ecma_object_t *binding_object_p = ecma_get_lex_env_binding_object(object); 140425bb815Sopenharmony_ci LogAddr(binding_object_p); 141425bb815Sopenharmony_ci } else { 142425bb815Sopenharmony_ci LogStr("declarative"); 143425bb815Sopenharmony_ci } 144425bb815Sopenharmony_ci} 145425bb815Sopenharmony_ci 146425bb815Sopenharmony_civoid DumpInfoFunction(const ecma_object_t* object) 147425bb815Sopenharmony_ci{ 148425bb815Sopenharmony_ci Key("is_builtin"); 149425bb815Sopenharmony_ci ecma_extended_object_t* ext_obj = (ecma_extended_object_t*)object; 150425bb815Sopenharmony_ci if (ecma_get_object_is_builtin (object)) { 151425bb815Sopenharmony_ci LogStr("true"); 152425bb815Sopenharmony_ci Next(); 153425bb815Sopenharmony_ci 154425bb815Sopenharmony_ci Key("is_routine"); 155425bb815Sopenharmony_ci if (ecma_builtin_function_is_routine ((ecma_object_t*)object)) { 156425bb815Sopenharmony_ci LogStr("true"); 157425bb815Sopenharmony_ci } else { 158425bb815Sopenharmony_ci LogStr("true"); 159425bb815Sopenharmony_ci } 160425bb815Sopenharmony_ci Next(); 161425bb815Sopenharmony_ci 162425bb815Sopenharmony_ci Key("id"); 163425bb815Sopenharmony_ci LogUint(ext_obj->u.built_in.id); 164425bb815Sopenharmony_ci Next(); 165425bb815Sopenharmony_ci Key("routine_id"); 166425bb815Sopenharmony_ci LogUint(ext_obj->u.built_in.routine_id); 167425bb815Sopenharmony_ci } else { 168425bb815Sopenharmony_ci LogStr("false"); 169425bb815Sopenharmony_ci Next(); 170425bb815Sopenharmony_ci 171425bb815Sopenharmony_ci Key("scope"); 172425bb815Sopenharmony_ci LogAddr(ECMA_GET_INTERNAL_VALUE_POINTER(ecma_object_t, ext_obj->u.function.scope_cp)); 173425bb815Sopenharmony_ci } 174425bb815Sopenharmony_ci} 175425bb815Sopenharmony_ci 176425bb815Sopenharmony_civoid DumpPropertyPair(ecma_property_pair_t* pair) 177425bb815Sopenharmony_ci{ 178425bb815Sopenharmony_ci ecma_property_header_t* header = (ecma_property_header_t*)pair; 179425bb815Sopenharmony_ci for (int i = 0; i < ECMA_PROPERTY_PAIR_ITEM_COUNT; i++) { 180425bb815Sopenharmony_ci Start(); 181425bb815Sopenharmony_ci 182425bb815Sopenharmony_ci switch (ECMA_PROPERTY_GET_TYPE(header->types[i])) { 183425bb815Sopenharmony_ci case ECMA_PROPERTY_TYPE_NAMEDDATA: { 184425bb815Sopenharmony_ci Type("data"); 185425bb815Sopenharmony_ci 186425bb815Sopenharmony_ci Key("key"); 187425bb815Sopenharmony_ci ecma_string_t* key_str = ecma_string_from_property_name(header->types[i], 188425bb815Sopenharmony_ci pair->names_cp[i]); 189425bb815Sopenharmony_ci LogStrObj(key_str); 190425bb815Sopenharmony_ci ecma_deref_ecma_string(key_str); 191425bb815Sopenharmony_ci Next(); 192425bb815Sopenharmony_ci 193425bb815Sopenharmony_ci Key("value"); 194425bb815Sopenharmony_ci ecma_value_t value = pair->values[i].value; 195425bb815Sopenharmony_ci if (ecma_is_value_object(value)) { 196425bb815Sopenharmony_ci ecma_object_t* value_obj = ecma_get_object_from_value(value); 197425bb815Sopenharmony_ci LogAddr(value_obj); 198425bb815Sopenharmony_ci } else { 199425bb815Sopenharmony_ci ecma_string_t* value_str = ecma_op_to_string(value); 200425bb815Sopenharmony_ci LogStrObj(value_str); 201425bb815Sopenharmony_ci } 202425bb815Sopenharmony_ci break; 203425bb815Sopenharmony_ci } 204425bb815Sopenharmony_ci case ECMA_PROPERTY_TYPE_NAMEDACCESSOR: { 205425bb815Sopenharmony_ci Type("accessor"); 206425bb815Sopenharmony_ci 207425bb815Sopenharmony_ci ecma_property_value_t* accessor_objs_p = pair->values + i; 208425bb815Sopenharmony_ci ecma_getter_setter_pointers_t* get_set_pair_p = 209425bb815Sopenharmony_ci ecma_get_named_accessor_property(accessor_objs_p); 210425bb815Sopenharmony_ci 211425bb815Sopenharmony_ci Key("getter"); 212425bb815Sopenharmony_ci if (get_set_pair_p->getter_cp != JMEM_CP_NULL) { 213425bb815Sopenharmony_ci LogAddr(ECMA_GET_NON_NULL_POINTER(ecma_object_t, get_set_pair_p->getter_cp)); 214425bb815Sopenharmony_ci } else { 215425bb815Sopenharmony_ci LogAddr(NULL); 216425bb815Sopenharmony_ci } 217425bb815Sopenharmony_ci Next(); 218425bb815Sopenharmony_ci 219425bb815Sopenharmony_ci Key("setter"); 220425bb815Sopenharmony_ci if (get_set_pair_p->setter_cp != JMEM_CP_NULL) { 221425bb815Sopenharmony_ci LogAddr(ECMA_GET_NON_NULL_POINTER(ecma_object_t, get_set_pair_p->setter_cp)); 222425bb815Sopenharmony_ci } else { 223425bb815Sopenharmony_ci LogAddr(NULL); 224425bb815Sopenharmony_ci } 225425bb815Sopenharmony_ci break; 226425bb815Sopenharmony_ci } 227425bb815Sopenharmony_ci case ECMA_PROPERTY_TYPE_INTERNAL: { 228425bb815Sopenharmony_ci Type("internal"); 229425bb815Sopenharmony_ci Key("TODO"); 230425bb815Sopenharmony_ci LogStr("Not implemented yet"); 231425bb815Sopenharmony_ci break; 232425bb815Sopenharmony_ci } 233425bb815Sopenharmony_ci default: { 234425bb815Sopenharmony_ci break; 235425bb815Sopenharmony_ci } 236425bb815Sopenharmony_ci } 237425bb815Sopenharmony_ci End(); 238425bb815Sopenharmony_ci if (i + 1 < ECMA_PROPERTY_PAIR_ITEM_COUNT) { 239425bb815Sopenharmony_ci Next(); 240425bb815Sopenharmony_ci } 241425bb815Sopenharmony_ci } 242425bb815Sopenharmony_ci} 243425bb815Sopenharmony_ci 244425bb815Sopenharmony_civoid DumpInfoObject(ecma_object_t* object, heapdump_object_flags_t flags) 245425bb815Sopenharmony_ci{ 246425bb815Sopenharmony_ci Start(); 247425bb815Sopenharmony_ci Addr(object); 248425bb815Sopenharmony_ci if (flags & HEAPDUMP_OBJECT_ROOT) { 249425bb815Sopenharmony_ci Key("Root"); 250425bb815Sopenharmony_ci LogStr("true"); 251425bb815Sopenharmony_ci Next(); 252425bb815Sopenharmony_ci } 253425bb815Sopenharmony_ci 254425bb815Sopenharmony_ci if (flags & HEAPDUMP_OBJECT_GLOBAL) { 255425bb815Sopenharmony_ci Key("Global"); 256425bb815Sopenharmony_ci LogStr("true"); 257425bb815Sopenharmony_ci Next(); 258425bb815Sopenharmony_ci } 259425bb815Sopenharmony_ci 260425bb815Sopenharmony_ci Key("RefCount"); 261425bb815Sopenharmony_ci LogUint(object->type_flags_refs >> REF_CNT_SHIFT); 262425bb815Sopenharmony_ci Next(); 263425bb815Sopenharmony_ci 264425bb815Sopenharmony_ci if (ecma_is_lexical_environment(object)) { 265425bb815Sopenharmony_ci Type("LexEnv"); 266425bb815Sopenharmony_ci DumpInfoLexEnv(object); 267425bb815Sopenharmony_ci goto finish; 268425bb815Sopenharmony_ci } else { 269425bb815Sopenharmony_ci Key("__proto__"); 270425bb815Sopenharmony_ci jmem_cpointer_t proto_cp = object->u2.prototype_cp; 271425bb815Sopenharmony_ci if (proto_cp != JMEM_CP_NULL) { 272425bb815Sopenharmony_ci LogAddr(ECMA_GET_NON_NULL_POINTER (ecma_object_t, proto_cp)); 273425bb815Sopenharmony_ci } else { 274425bb815Sopenharmony_ci LogAddr(NULL); 275425bb815Sopenharmony_ci } 276425bb815Sopenharmony_ci Next(); 277425bb815Sopenharmony_ci switch (ecma_get_object_type(object)) { 278425bb815Sopenharmony_ci case ECMA_OBJECT_TYPE_EXTERNAL_FUNCTION: { 279425bb815Sopenharmony_ci Type("ExternalFunction"); 280425bb815Sopenharmony_ci break; 281425bb815Sopenharmony_ci } 282425bb815Sopenharmony_ci case ECMA_OBJECT_TYPE_BOUND_FUNCTION: { 283425bb815Sopenharmony_ci Type("BoundFunction"); 284425bb815Sopenharmony_ci break; 285425bb815Sopenharmony_ci } 286425bb815Sopenharmony_ci case ECMA_OBJECT_TYPE_FUNCTION: { 287425bb815Sopenharmony_ci Type("Function"); 288425bb815Sopenharmony_ci DumpInfoFunction(object); 289425bb815Sopenharmony_ci Next(); 290425bb815Sopenharmony_ci break; 291425bb815Sopenharmony_ci } 292425bb815Sopenharmony_ci case ECMA_OBJECT_TYPE_PSEUDO_ARRAY: { 293425bb815Sopenharmony_ci Type("PseudoArray"); 294425bb815Sopenharmony_ci ecma_extended_object_t* ext_object = (ecma_extended_object_t*)object; 295425bb815Sopenharmony_ci if (ext_object->u.pseudo_array.type == ECMA_PSEUDO_ARRAY_ARGUMENTS) { 296425bb815Sopenharmony_ci Key("subtype"); 297425bb815Sopenharmony_ci LogStr("arguments"); 298425bb815Sopenharmony_ci Next(); 299425bb815Sopenharmony_ci ecma_object_t* lex_env = ECMA_GET_INTERNAL_VALUE_POINTER (ecma_object_t, 300425bb815Sopenharmony_ci ext_object->u.pseudo_array.u2.lex_env_cp); 301425bb815Sopenharmony_ci Key("lex_env"); 302425bb815Sopenharmony_ci LogAddr(lex_env); 303425bb815Sopenharmony_ci } else { 304425bb815Sopenharmony_ci Key("subtype"); 305425bb815Sopenharmony_ci LogStr("!!! Unknown"); 306425bb815Sopenharmony_ci } 307425bb815Sopenharmony_ci goto finish; 308425bb815Sopenharmony_ci } 309425bb815Sopenharmony_ci case ECMA_OBJECT_TYPE_ARRAY: { 310425bb815Sopenharmony_ci Type("Array"); 311425bb815Sopenharmony_ci ecma_extended_object_t* ext_object = (ecma_extended_object_t*)object; 312425bb815Sopenharmony_ci 313425bb815Sopenharmony_ci if (ecma_op_object_is_fast_array(object)) { 314425bb815Sopenharmony_ci Key("subtype"); 315425bb815Sopenharmony_ci LogStr("fast"); 316425bb815Sopenharmony_ci Next(); 317425bb815Sopenharmony_ci 318425bb815Sopenharmony_ci Key("data"); 319425bb815Sopenharmony_ci Start(); 320425bb815Sopenharmony_ci if (object->u1.property_list_cp != JMEM_CP_NULL) { 321425bb815Sopenharmony_ci ecma_value_t *values = 322425bb815Sopenharmony_ci ECMA_GET_NON_NULL_POINTER (ecma_value_t, object->u1.property_list_cp); 323425bb815Sopenharmony_ci bool skip_comma = true; 324425bb815Sopenharmony_ci for (uint32_t i = 0; i < ext_object->u.array.length; i++) { 325425bb815Sopenharmony_ci if (ecma_is_value_array_hole(values[i])) { 326425bb815Sopenharmony_ci continue; 327425bb815Sopenharmony_ci } 328425bb815Sopenharmony_ci if (skip_comma) { 329425bb815Sopenharmony_ci skip_comma = false; 330425bb815Sopenharmony_ci } else { 331425bb815Sopenharmony_ci Next(); 332425bb815Sopenharmony_ci } 333425bb815Sopenharmony_ci KeyUint(i); 334425bb815Sopenharmony_ci if (ecma_is_value_object(values[i])) { 335425bb815Sopenharmony_ci ecma_object_t* value_obj = ecma_get_object_from_value(values[i]); 336425bb815Sopenharmony_ci LogAddr(value_obj); 337425bb815Sopenharmony_ci } else { 338425bb815Sopenharmony_ci ecma_string_t* value_str = ecma_op_to_string(values[i]); 339425bb815Sopenharmony_ci LogStrObj(value_str); 340425bb815Sopenharmony_ci } 341425bb815Sopenharmony_ci } 342425bb815Sopenharmony_ci } 343425bb815Sopenharmony_ci End(); 344425bb815Sopenharmony_ci goto finish; 345425bb815Sopenharmony_ci } else { 346425bb815Sopenharmony_ci Key("subtype"); 347425bb815Sopenharmony_ci LogStr("sparse"); 348425bb815Sopenharmony_ci Next(); 349425bb815Sopenharmony_ci } 350425bb815Sopenharmony_ci break; 351425bb815Sopenharmony_ci } 352425bb815Sopenharmony_ci default: { 353425bb815Sopenharmony_ci Type("Object"); 354425bb815Sopenharmony_ci break; 355425bb815Sopenharmony_ci } 356425bb815Sopenharmony_ci } 357425bb815Sopenharmony_ci } 358425bb815Sopenharmony_ci 359425bb815Sopenharmony_ci jmem_cpointer_t prop_iter_cp = object->u1.property_list_cp; 360425bb815Sopenharmony_ci 361425bb815Sopenharmony_ci#if ENABLED (JERRY_PROPRETY_HASHMAP) 362425bb815Sopenharmony_ci if (prop_iter_cp != JMEM_CP_NULL) { 363425bb815Sopenharmony_ci ecma_property_header_t* prop_iter_p = 364425bb815Sopenharmony_ci ECMA_GET_NON_NULL_POINTER(ecma_property_header_t, prop_iter_cp); 365425bb815Sopenharmony_ci if (prop_iter_p->types[0] == ECMA_PROPERTY_TYPE_HASHMAP) { 366425bb815Sopenharmony_ci prop_iter_cp = prop_iter_p->next_property_cp; 367425bb815Sopenharmony_ci } 368425bb815Sopenharmony_ci } 369425bb815Sopenharmony_ci#endif 370425bb815Sopenharmony_ci 371425bb815Sopenharmony_ci Key("properties"); 372425bb815Sopenharmony_ci StartList(); 373425bb815Sopenharmony_ci while (prop_iter_cp != JMEM_CP_NULL) { 374425bb815Sopenharmony_ci ecma_property_header_t* prop_iter_p = 375425bb815Sopenharmony_ci ECMA_GET_NON_NULL_POINTER(ecma_property_header_t, prop_iter_cp); 376425bb815Sopenharmony_ci DumpPropertyPair((ecma_property_pair_t *) prop_iter_p); 377425bb815Sopenharmony_ci 378425bb815Sopenharmony_ci prop_iter_cp = prop_iter_p->next_property_cp; 379425bb815Sopenharmony_ci if (prop_iter_cp != JMEM_CP_NULL) { 380425bb815Sopenharmony_ci Next(); 381425bb815Sopenharmony_ci } 382425bb815Sopenharmony_ci } 383425bb815Sopenharmony_ci EndList(); 384425bb815Sopenharmony_ci 385425bb815Sopenharmony_ci finish: 386425bb815Sopenharmony_ci End(); 387425bb815Sopenharmony_ci Next(); 388425bb815Sopenharmony_ci} 389