* Copyright (c) Huawei Technologies Co., Ltd. 2020-2020. All rights reserved.
* Description: add ref tracker.
* Create: 2020/11/20
*/
#include "tracker.h"
#include "ecma-globals.h"
#include "ecma-helpers.h"
#include "ext-utils.h"
#include "heapdump.h"
#include "vm.h"
#if defined(JERRY_REF_TRACKER)
#define BUFFER_SIZE 65536
#define LogTracker(...) do { fprintf(gLogTrackerFile, __VA_ARGS__); } while (0)
bool gNativeManip = false;
bool gRefTrackerEnabled = false;
static Storage gStorages[2];
static FILE* gLogTrackerFile = NULL;
bool GetRefTrackerEnabled(void)
{
return gRefTrackerEnabled;
}
void SetRefTrackerEnabled(bool flag)
{
gRefTrackerEnabled = flag;
}
void LogTrackerInit(const char* filepath)
{
gLogTrackerFile = fopen(filepath, "w+");
}
void LogTrackerClose(void)
{
fclose(gLogTrackerFile);
}
void RefInfoResetFn(IStorageItem* item)
{
RefInfoItem* ref_item = (RefInfoItem*)item;
JerryExtFree(ref_item->stacktrace);
JerryExtFree(ref_item);
}
void InitTracker(void)
{
StorageInit(&gStorages[kObjectRefInfo], BUFFER_SIZE);
StorageInit(&gStorages[kStringRefInfo], BUFFER_SIZE);
}
void StorageInit(Storage* storage, size_t size)
{
storage->size = size;
storage->data = JerryExtAllocStorageData(size);
}
void StoragePut(Storage* storage, size_t key, size_t value)
{
if (storage->data[key] == 0) {
storage->data[key] = value;
return;
}
IStorageItem* item = (IStorageItem*)storage->data[key];
storage->data[key] = value;
IStorageItem* new_item = (IStorageItem*)value;
new_item->next = item;
}
size_t StorageGet(Storage* storage, size_t key)
{
return storage->data[key];
}
void StorageReset(Storage* storage, size_t key, void(*reset_fn)(IStorageItem*))
{
if (storage->data[key] == 0) {
return;
}
IStorageItem* item = (IStorageItem*)storage->data[key];
storage->data[key] = 0;
while (item != NULL) {
IStorageItem* next = item->next;
reset_fn(item);
item = next;
}
}
char* GetStacktraceString(ecma_string_t* stack)
{
if (stack == NULL) {
return NULL;
}
ECMA_STRING_TO_UTF8_STRING(stack, data, data_size);
char* dst = JerryExtAllocStr(data_size + 1);
memcpy(dst, data, data_size);
dst[data_size] = '\0';
return dst;
}
RefInfoItem* CreateRefInfoItem(RefInfoItemFlags flags, char* stack_str)
{
RefInfoItem* item = JerryExtAlloc(sizeof(RefInfoItem));
item->next = NULL;
item->stacktrace = stack_str;
item->flags = flags;
return item;
}
void ReportObjRefManip(ecma_object_t* obj, RefInfoItemFlags flags)
{
if (!gRefTrackerEnabled) {
return;
}
if (gNativeManip) {
flags &= kRefNative;
}
if (flags & (kRefMark | kRefUnmark)) {
return;
}
const char* native_str = " native";
const char* init_str = " init";
const char* inc_str = " increment";
const char* dec_str = " decrement";
uint32_t refcnt = obj->type_flags_refs >> REF_CNT_SHIFT;
LogTracker("Object %p%s%s%s%s: refcount = %u\n", (void*)obj,
(flags & kRefNative) ? native_str : "",
(flags & kRefInit) ? init_str : "",
(flags & kRefRef) ? inc_str : "",
(flags & kRefDeref) ? dec_str : "",
refcnt);
LogTracker("\n");
}
void ReportObjDelete(ecma_object_t* obj)
{
if (!gRefTrackerEnabled) {
return;
}
LogTracker("Object %p deleted\n", (void*)obj);
LogTracker("\n");
}
void DumpTracker(void)
{
Storage* storage = &gStorages[kObjectRefInfo];
for (int i = 0; i < (int)storage->size; ++i) {
if (storage->data[i] != 0) {
RefInfoItem* item = (RefInfoItem*)storage->data[i];
printf("--== %p ==--:\n", (void*)ECMA_OBJECT_FROM_STORAGE_KEY(i));
while (item != NULL) {
printf("flags = %d\nStacktrace:\n%s\n", item->flags, item->stacktrace);
item = item->next;
}
}
}
}
#endif