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
20bool gNativeManip = false;
21// This variable shall be used only in "streaming" mode.
22bool gRefTrackerEnabled = false;
23static Storage gStorages[2];
24static FILE* gLogTrackerFile = NULL;
25
26bool GetRefTrackerEnabled(void)
27{
28  return gRefTrackerEnabled;
29}
30
31void SetRefTrackerEnabled(bool flag)
32{
33  gRefTrackerEnabled = flag;
34}
35
36void LogTrackerInit(const char* filepath)
37{
38  gLogTrackerFile = fopen(filepath, "w+");
39}
40
41void LogTrackerClose(void)
42{
43  fclose(gLogTrackerFile);
44}
45
46void RefInfoResetFn(IStorageItem* item)
47{
48  RefInfoItem* ref_item = (RefInfoItem*)item;
49  JerryExtFree(ref_item->stacktrace);
50  JerryExtFree(ref_item);
51}
52
53void InitTracker(void)
54{
55  StorageInit(&gStorages[kObjectRefInfo], BUFFER_SIZE);
56  StorageInit(&gStorages[kStringRefInfo], BUFFER_SIZE);
57}
58
59void StorageInit(Storage* storage, size_t size)
60{
61  storage->size = size;
62  storage->data = JerryExtAllocStorageData(size);
63}
64
65void 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
79size_t StorageGet(Storage* storage, size_t key)
80{
81  return storage->data[key];
82}
83
84void 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
100char* 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
113RefInfoItem* 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
122void 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
153void 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
163void 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