1 /*
2 * Copyright (c) Huawei Technologies Co., Ltd. 2020-2020. All rights reserved.
3 * Description: add ref tracker.
4 * Create: 2020/11/20
5 */
6
7 #include "tracker.h"
8
9 #include "ecma-globals.h"
10 #include "ecma-helpers.h"
11 #include "ext-utils.h"
12 #include "heapdump.h"
13 #include "vm.h"
14
15 #if defined(JERRY_REF_TRACKER)
16
17 #define BUFFER_SIZE 65536
18 #define LogTracker(...) do { fprintf(gLogTrackerFile, __VA_ARGS__); } while (0)
19
20 bool gNativeManip = false;
21 // This variable shall be used only in "streaming" mode.
22 bool gRefTrackerEnabled = false;
23 static Storage gStorages[2];
24 static FILE* gLogTrackerFile = NULL;
25
GetRefTrackerEnabled(void)26 bool GetRefTrackerEnabled(void)
27 {
28 return gRefTrackerEnabled;
29 }
30
SetRefTrackerEnabled(bool flag)31 void SetRefTrackerEnabled(bool flag)
32 {
33 gRefTrackerEnabled = flag;
34 }
35
LogTrackerInit(const char * filepath)36 void LogTrackerInit(const char* filepath)
37 {
38 gLogTrackerFile = fopen(filepath, "w+");
39 }
40
LogTrackerClose(void)41 void LogTrackerClose(void)
42 {
43 fclose(gLogTrackerFile);
44 }
45
RefInfoResetFn(IStorageItem * item)46 void RefInfoResetFn(IStorageItem* item)
47 {
48 RefInfoItem* ref_item = (RefInfoItem*)item;
49 JerryExtFree(ref_item->stacktrace);
50 JerryExtFree(ref_item);
51 }
52
InitTracker(void)53 void InitTracker(void)
54 {
55 StorageInit(&gStorages[kObjectRefInfo], BUFFER_SIZE);
56 StorageInit(&gStorages[kStringRefInfo], BUFFER_SIZE);
57 }
58
StorageInit(Storage * storage,size_t size)59 void StorageInit(Storage* storage, size_t size)
60 {
61 storage->size = size;
62 storage->data = JerryExtAllocStorageData(size);
63 }
64
StoragePut(Storage * storage,size_t key,size_t value)65 void StoragePut(Storage* storage, size_t key, size_t value)
66 {
67 if (storage->data[key] == 0) {
68 storage->data[key] = value;
69 return;
70 }
71
72 IStorageItem* item = (IStorageItem*)storage->data[key];
73 storage->data[key] = value;
74
75 IStorageItem* new_item = (IStorageItem*)value;
76 new_item->next = item;
77 }
78
StorageGet(Storage * storage,size_t key)79 size_t StorageGet(Storage* storage, size_t key)
80 {
81 return storage->data[key];
82 }
83
StorageReset(Storage * storage,size_t key,void (* reset_fn)(IStorageItem *))84 void StorageReset(Storage* storage, size_t key, void(*reset_fn)(IStorageItem*))
85 {
86 if (storage->data[key] == 0) {
87 // Nothing to reset.
88 return;
89 }
90
91 IStorageItem* item = (IStorageItem*)storage->data[key];
92 storage->data[key] = 0;
93 while (item != NULL) {
94 IStorageItem* next = item->next;
95 reset_fn(item);
96 item = next;
97 }
98 }
99
GetStacktraceString(ecma_string_t * stack)100 char* GetStacktraceString(ecma_string_t* stack)
101 {
102 if (stack == NULL) {
103 return NULL;
104 }
105 // Copy string to jsheap-independent storage.
106 ECMA_STRING_TO_UTF8_STRING(stack, data, data_size);
107 char* dst = JerryExtAllocStr(data_size + 1);
108 memcpy(dst, data, data_size);
109 dst[data_size] = '\0';
110 return dst;
111 }
112
CreateRefInfoItem(RefInfoItemFlags flags,char * stack_str)113 RefInfoItem* CreateRefInfoItem(RefInfoItemFlags flags, char* stack_str)
114 {
115 RefInfoItem* item = JerryExtAlloc(sizeof(RefInfoItem));
116 item->next = NULL;
117 item->stacktrace = stack_str;
118 item->flags = flags;
119 return item;
120 }
121
ReportObjRefManip(ecma_object_t * obj,RefInfoItemFlags flags)122 void ReportObjRefManip(ecma_object_t* obj, RefInfoItemFlags flags)
123 {
124 if (!gRefTrackerEnabled) {
125 return;
126 }
127
128 if (gNativeManip) {
129 flags &= kRefNative;
130 }
131
132 // XXX: For now don't do anything regarding within-gc ops.
133 if (flags & (kRefMark | kRefUnmark)) {
134 return;
135 }
136
137 const char* native_str = " native";
138 const char* init_str = " init";
139 const char* inc_str = " increment";
140 const char* dec_str = " decrement";
141
142 uint32_t refcnt = obj->type_flags_refs >> REF_CNT_SHIFT;
143
144 LogTracker("Object %p%s%s%s%s: refcount = %u\n", (void*)obj,
145 (flags & kRefNative) ? native_str : "",
146 (flags & kRefInit) ? init_str : "",
147 (flags & kRefRef) ? inc_str : "",
148 (flags & kRefDeref) ? dec_str : "",
149 refcnt);
150 LogTracker("\n");
151 }
152
ReportObjDelete(ecma_object_t * obj)153 void ReportObjDelete(ecma_object_t* obj)
154 {
155 if (!gRefTrackerEnabled) {
156 return;
157 }
158
159 LogTracker("Object %p deleted\n", (void*)obj);
160 LogTracker("\n");
161 }
162
DumpTracker(void)163 void DumpTracker(void)
164 {
165 Storage* storage = &gStorages[kObjectRefInfo];
166 for (int i = 0; i < (int)storage->size; ++i) {
167 if (storage->data[i] != 0) {
168 RefInfoItem* item = (RefInfoItem*)storage->data[i];
169 printf("--== %p ==--:\n", (void*)ECMA_OBJECT_FROM_STORAGE_KEY(i));
170 while (item != NULL) {
171 printf("flags = %d\nStacktrace:\n%s\n", item->flags, item->stacktrace);
172 item = item->next;
173 }
174 }
175 }
176 }
177
178 #endif
179