1425bb815Sopenharmony_ci/*
2425bb815Sopenharmony_ci * Copyright (c) Huawei Technologies Co., Ltd. 2020-2020. All rights reserved.
3425bb815Sopenharmony_ci * Description: add ref tracker.
4425bb815Sopenharmony_ci * Create: 2020/11/20
5425bb815Sopenharmony_ci */
6425bb815Sopenharmony_ci
7425bb815Sopenharmony_ci#include "tracker.h"
8425bb815Sopenharmony_ci
9425bb815Sopenharmony_ci#include "ecma-globals.h"
10425bb815Sopenharmony_ci#include "ecma-helpers.h"
11425bb815Sopenharmony_ci#include "ext-utils.h"
12425bb815Sopenharmony_ci#include "heapdump.h"
13425bb815Sopenharmony_ci#include "vm.h"
14425bb815Sopenharmony_ci
15425bb815Sopenharmony_ci#if defined(JERRY_REF_TRACKER)
16425bb815Sopenharmony_ci
17425bb815Sopenharmony_ci#define BUFFER_SIZE 65536
18425bb815Sopenharmony_ci#define LogTracker(...) do { fprintf(gLogTrackerFile, __VA_ARGS__); } while (0)
19425bb815Sopenharmony_ci
20425bb815Sopenharmony_cibool gNativeManip = false;
21425bb815Sopenharmony_ci// This variable shall be used only in "streaming" mode.
22425bb815Sopenharmony_cibool gRefTrackerEnabled = false;
23425bb815Sopenharmony_cistatic Storage gStorages[2];
24425bb815Sopenharmony_cistatic FILE* gLogTrackerFile = NULL;
25425bb815Sopenharmony_ci
26425bb815Sopenharmony_cibool GetRefTrackerEnabled(void)
27425bb815Sopenharmony_ci{
28425bb815Sopenharmony_ci  return gRefTrackerEnabled;
29425bb815Sopenharmony_ci}
30425bb815Sopenharmony_ci
31425bb815Sopenharmony_civoid SetRefTrackerEnabled(bool flag)
32425bb815Sopenharmony_ci{
33425bb815Sopenharmony_ci  gRefTrackerEnabled = flag;
34425bb815Sopenharmony_ci}
35425bb815Sopenharmony_ci
36425bb815Sopenharmony_civoid LogTrackerInit(const char* filepath)
37425bb815Sopenharmony_ci{
38425bb815Sopenharmony_ci  gLogTrackerFile = fopen(filepath, "w+");
39425bb815Sopenharmony_ci}
40425bb815Sopenharmony_ci
41425bb815Sopenharmony_civoid LogTrackerClose(void)
42425bb815Sopenharmony_ci{
43425bb815Sopenharmony_ci  fclose(gLogTrackerFile);
44425bb815Sopenharmony_ci}
45425bb815Sopenharmony_ci
46425bb815Sopenharmony_civoid RefInfoResetFn(IStorageItem* item)
47425bb815Sopenharmony_ci{
48425bb815Sopenharmony_ci  RefInfoItem* ref_item = (RefInfoItem*)item;
49425bb815Sopenharmony_ci  JerryExtFree(ref_item->stacktrace);
50425bb815Sopenharmony_ci  JerryExtFree(ref_item);
51425bb815Sopenharmony_ci}
52425bb815Sopenharmony_ci
53425bb815Sopenharmony_civoid InitTracker(void)
54425bb815Sopenharmony_ci{
55425bb815Sopenharmony_ci  StorageInit(&gStorages[kObjectRefInfo], BUFFER_SIZE);
56425bb815Sopenharmony_ci  StorageInit(&gStorages[kStringRefInfo], BUFFER_SIZE);
57425bb815Sopenharmony_ci}
58425bb815Sopenharmony_ci
59425bb815Sopenharmony_civoid StorageInit(Storage* storage, size_t size)
60425bb815Sopenharmony_ci{
61425bb815Sopenharmony_ci  storage->size = size;
62425bb815Sopenharmony_ci  storage->data = JerryExtAllocStorageData(size);
63425bb815Sopenharmony_ci}
64425bb815Sopenharmony_ci
65425bb815Sopenharmony_civoid StoragePut(Storage* storage, size_t key, size_t value)
66425bb815Sopenharmony_ci{
67425bb815Sopenharmony_ci  if (storage->data[key] == 0) {
68425bb815Sopenharmony_ci    storage->data[key] = value;
69425bb815Sopenharmony_ci    return;
70425bb815Sopenharmony_ci  }
71425bb815Sopenharmony_ci
72425bb815Sopenharmony_ci  IStorageItem* item = (IStorageItem*)storage->data[key];
73425bb815Sopenharmony_ci  storage->data[key] = value;
74425bb815Sopenharmony_ci
75425bb815Sopenharmony_ci  IStorageItem* new_item = (IStorageItem*)value;
76425bb815Sopenharmony_ci  new_item->next = item;
77425bb815Sopenharmony_ci}
78425bb815Sopenharmony_ci
79425bb815Sopenharmony_cisize_t StorageGet(Storage* storage, size_t key)
80425bb815Sopenharmony_ci{
81425bb815Sopenharmony_ci  return storage->data[key];
82425bb815Sopenharmony_ci}
83425bb815Sopenharmony_ci
84425bb815Sopenharmony_civoid StorageReset(Storage* storage, size_t key, void(*reset_fn)(IStorageItem*))
85425bb815Sopenharmony_ci{
86425bb815Sopenharmony_ci  if (storage->data[key] == 0) {
87425bb815Sopenharmony_ci    // Nothing to reset.
88425bb815Sopenharmony_ci    return;
89425bb815Sopenharmony_ci  }
90425bb815Sopenharmony_ci
91425bb815Sopenharmony_ci  IStorageItem* item = (IStorageItem*)storage->data[key];
92425bb815Sopenharmony_ci  storage->data[key] = 0;
93425bb815Sopenharmony_ci  while (item != NULL) {
94425bb815Sopenharmony_ci    IStorageItem* next = item->next;
95425bb815Sopenharmony_ci    reset_fn(item);
96425bb815Sopenharmony_ci    item = next;
97425bb815Sopenharmony_ci  }
98425bb815Sopenharmony_ci}
99425bb815Sopenharmony_ci
100425bb815Sopenharmony_cichar* GetStacktraceString(ecma_string_t* stack)
101425bb815Sopenharmony_ci{
102425bb815Sopenharmony_ci  if (stack == NULL) {
103425bb815Sopenharmony_ci    return NULL;
104425bb815Sopenharmony_ci  }
105425bb815Sopenharmony_ci  // Copy string to jsheap-independent storage.
106425bb815Sopenharmony_ci  ECMA_STRING_TO_UTF8_STRING(stack, data, data_size);
107425bb815Sopenharmony_ci  char* dst = JerryExtAllocStr(data_size + 1);
108425bb815Sopenharmony_ci  memcpy(dst, data, data_size);
109425bb815Sopenharmony_ci  dst[data_size] = '\0';
110425bb815Sopenharmony_ci  return dst;
111425bb815Sopenharmony_ci}
112425bb815Sopenharmony_ci
113425bb815Sopenharmony_ciRefInfoItem* CreateRefInfoItem(RefInfoItemFlags flags, char* stack_str)
114425bb815Sopenharmony_ci{
115425bb815Sopenharmony_ci  RefInfoItem* item = JerryExtAlloc(sizeof(RefInfoItem));
116425bb815Sopenharmony_ci  item->next = NULL;
117425bb815Sopenharmony_ci  item->stacktrace = stack_str;
118425bb815Sopenharmony_ci  item->flags = flags;
119425bb815Sopenharmony_ci  return item;
120425bb815Sopenharmony_ci}
121425bb815Sopenharmony_ci
122425bb815Sopenharmony_civoid ReportObjRefManip(ecma_object_t* obj, RefInfoItemFlags flags)
123425bb815Sopenharmony_ci{
124425bb815Sopenharmony_ci  if (!gRefTrackerEnabled) {
125425bb815Sopenharmony_ci    return;
126425bb815Sopenharmony_ci  }
127425bb815Sopenharmony_ci
128425bb815Sopenharmony_ci  if (gNativeManip) {
129425bb815Sopenharmony_ci    flags &= kRefNative;
130425bb815Sopenharmony_ci  }
131425bb815Sopenharmony_ci
132425bb815Sopenharmony_ci  // XXX: For now don't do anything regarding within-gc ops.
133425bb815Sopenharmony_ci  if (flags & (kRefMark | kRefUnmark)) {
134425bb815Sopenharmony_ci    return;
135425bb815Sopenharmony_ci  }
136425bb815Sopenharmony_ci
137425bb815Sopenharmony_ci  const char* native_str = "    native";
138425bb815Sopenharmony_ci  const char* init_str   = "      init";
139425bb815Sopenharmony_ci  const char* inc_str    = " increment";
140425bb815Sopenharmony_ci  const char* dec_str    = " decrement";
141425bb815Sopenharmony_ci
142425bb815Sopenharmony_ci  uint32_t refcnt = obj->type_flags_refs >> REF_CNT_SHIFT;
143425bb815Sopenharmony_ci
144425bb815Sopenharmony_ci  LogTracker("Object %p%s%s%s%s: refcount = %u\n", (void*)obj,
145425bb815Sopenharmony_ci      (flags & kRefNative) ? native_str : "",
146425bb815Sopenharmony_ci      (flags & kRefInit) ? init_str : "",
147425bb815Sopenharmony_ci      (flags & kRefRef) ? inc_str : "",
148425bb815Sopenharmony_ci      (flags & kRefDeref) ? dec_str : "",
149425bb815Sopenharmony_ci      refcnt);
150425bb815Sopenharmony_ci  LogTracker("\n");
151425bb815Sopenharmony_ci}
152425bb815Sopenharmony_ci
153425bb815Sopenharmony_civoid ReportObjDelete(ecma_object_t* obj)
154425bb815Sopenharmony_ci{
155425bb815Sopenharmony_ci  if (!gRefTrackerEnabled) {
156425bb815Sopenharmony_ci    return;
157425bb815Sopenharmony_ci  }
158425bb815Sopenharmony_ci
159425bb815Sopenharmony_ci  LogTracker("Object %p deleted\n", (void*)obj);
160425bb815Sopenharmony_ci  LogTracker("\n");
161425bb815Sopenharmony_ci}
162425bb815Sopenharmony_ci
163425bb815Sopenharmony_civoid DumpTracker(void)
164425bb815Sopenharmony_ci{
165425bb815Sopenharmony_ci  Storage* storage = &gStorages[kObjectRefInfo];
166425bb815Sopenharmony_ci  for (int i = 0; i < (int)storage->size; ++i) {
167425bb815Sopenharmony_ci    if (storage->data[i] != 0) {
168425bb815Sopenharmony_ci      RefInfoItem* item = (RefInfoItem*)storage->data[i];
169425bb815Sopenharmony_ci      printf("--== %p ==--:\n", (void*)ECMA_OBJECT_FROM_STORAGE_KEY(i));
170425bb815Sopenharmony_ci      while (item != NULL) {
171425bb815Sopenharmony_ci        printf("flags = %d\nStacktrace:\n%s\n", item->flags, item->stacktrace);
172425bb815Sopenharmony_ci        item = item->next;
173425bb815Sopenharmony_ci      }
174425bb815Sopenharmony_ci    }
175425bb815Sopenharmony_ci  }
176425bb815Sopenharmony_ci}
177425bb815Sopenharmony_ci
178425bb815Sopenharmony_ci#endif
179