1 // Copyright 2015 the V8 project authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "src/profiler/strings-storage.h"
6
7 #include <memory>
8
9 #include "src/utils/allocation.h"
10 #include "src/objects/objects-inl.h"
11
12 namespace v8 {
13 namespace internal {
14
StringsMatch(void * key1,void * key2)15 bool StringsStorage::StringsMatch(void* key1, void* key2) {
16 return strcmp(reinterpret_cast<char*>(key1), reinterpret_cast<char*>(key2)) ==
17 0;
18 }
19
StringsStorage()20 StringsStorage::StringsStorage() : names_(StringsMatch) {}
21
~StringsStorage()22 StringsStorage::~StringsStorage() {
23 for (base::HashMap::Entry* p = names_.Start(); p != nullptr;
24 p = names_.Next(p)) {
25 DeleteArray(reinterpret_cast<const char*>(p->key));
26 }
27 }
28
GetCopy(const char * src)29 const char* StringsStorage::GetCopy(const char* src) {
30 int len = static_cast<int>(strlen(src));
31 base::HashMap::Entry* entry = GetEntry(src, len);
32 if (entry->value == nullptr) {
33 Vector<char> dst = Vector<char>::New(len + 1);
34 StrNCpy(dst, src, len);
35 dst[len] = '\0';
36 entry->key = dst.begin();
37 }
38 entry->value =
39 reinterpret_cast<void*>(reinterpret_cast<size_t>(entry->value) + 1);
40 return reinterpret_cast<const char*>(entry->key);
41 }
42
GetFormatted(const char * format,...)43 const char* StringsStorage::GetFormatted(const char* format, ...) {
44 va_list args;
45 va_start(args, format);
46 const char* result = GetVFormatted(format, args);
47 va_end(args);
48 return result;
49 }
50
AddOrDisposeString(char * str,int len)51 const char* StringsStorage::AddOrDisposeString(char* str, int len) {
52 base::HashMap::Entry* entry = GetEntry(str, len);
53 if (entry->value == nullptr) {
54 // New entry added.
55 entry->key = str;
56 } else {
57 DeleteArray(str);
58 }
59 entry->value =
60 reinterpret_cast<void*>(reinterpret_cast<size_t>(entry->value) + 1);
61 return reinterpret_cast<const char*>(entry->key);
62 }
63
GetVFormatted(const char * format,va_list args)64 const char* StringsStorage::GetVFormatted(const char* format, va_list args) {
65 Vector<char> str = Vector<char>::New(1024);
66 int len = VSNPrintF(str, format, args);
67 if (len == -1) {
68 DeleteArray(str.begin());
69 return GetCopy(format);
70 }
71 return AddOrDisposeString(str.begin(), len);
72 }
73
GetName(Name name)74 const char* StringsStorage::GetName(Name name) {
75 if (name.IsString()) {
76 String str = String::cast(name);
77 int length = Min(FLAG_heap_snapshot_string_limit, str.length());
78 int actual_length = 0;
79 std::unique_ptr<char[]> data = str.ToCString(
80 DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL, 0, length, &actual_length);
81 return AddOrDisposeString(data.release(), actual_length);
82 } else if (name.IsSymbol()) {
83 return "<symbol>";
84 }
85 return "";
86 }
87
GetName(int index)88 const char* StringsStorage::GetName(int index) {
89 return GetFormatted("%d", index);
90 }
91
GetConsName(const char * prefix,Name name)92 const char* StringsStorage::GetConsName(const char* prefix, Name name) {
93 if (name.IsString()) {
94 String str = String::cast(name);
95 int length = Min(FLAG_heap_snapshot_string_limit, str.length());
96 int actual_length = 0;
97 std::unique_ptr<char[]> data = str.ToCString(
98 DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL, 0, length, &actual_length);
99
100 int cons_length = actual_length + static_cast<int>(strlen(prefix)) + 1;
101 char* cons_result = NewArray<char>(cons_length);
102 snprintf(cons_result, cons_length, "%s%s", prefix, data.get());
103
104 return AddOrDisposeString(cons_result, cons_length);
105 } else if (name.IsSymbol()) {
106 return "<symbol>";
107 }
108 return "";
109 }
110
Release(const char * str)111 bool StringsStorage::Release(const char* str) {
112 int len = static_cast<int>(strlen(str));
113 uint32_t hash = StringHasher::HashSequentialString(str, len, kZeroHashSeed);
114 base::HashMap::Entry* entry = names_.Lookup(const_cast<char*>(str), hash);
115 DCHECK(entry);
116 if (!entry) {
117 return false;
118 }
119
120 DCHECK(entry->value);
121 entry->value =
122 reinterpret_cast<void*>(reinterpret_cast<size_t>(entry->value) - 1);
123
124 if (entry->value == 0) {
125 names_.Remove(const_cast<char*>(str), hash);
126 DeleteArray(str);
127 }
128 return true;
129 }
130
GetStringCountForTesting() const131 size_t StringsStorage::GetStringCountForTesting() const {
132 return names_.occupancy();
133 }
134
GetEntry(const char * str,int len)135 base::HashMap::Entry* StringsStorage::GetEntry(const char* str, int len) {
136 uint32_t hash = StringHasher::HashSequentialString(str, len, kZeroHashSeed);
137 return names_.LookupOrInsert(const_cast<char*>(str), hash);
138 }
139
140 } // namespace internal
141 } // namespace v8
142