• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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/base/strings.h"
10 #include "src/objects/objects-inl.h"
11 #include "src/utils/allocation.h"
12 
13 namespace v8 {
14 namespace internal {
15 
StringsMatch(void * key1,void * key2)16 bool StringsStorage::StringsMatch(void* key1, void* key2) {
17   return strcmp(reinterpret_cast<char*>(key1), reinterpret_cast<char*>(key2)) ==
18          0;
19 }
20 
StringsStorage()21 StringsStorage::StringsStorage() : names_(StringsMatch) {}
22 
~StringsStorage()23 StringsStorage::~StringsStorage() {
24   for (base::HashMap::Entry* p = names_.Start(); p != nullptr;
25        p = names_.Next(p)) {
26     DeleteArray(reinterpret_cast<const char*>(p->key));
27   }
28 }
29 
GetCopy(const char * src)30 const char* StringsStorage::GetCopy(const char* src) {
31   base::MutexGuard guard(&mutex_);
32   int len = static_cast<int>(strlen(src));
33   base::HashMap::Entry* entry = GetEntry(src, len);
34   if (entry->value == nullptr) {
35     base::Vector<char> dst = base::Vector<char>::New(len + 1);
36     base::StrNCpy(dst, src, len);
37     dst[len] = '\0';
38     entry->key = dst.begin();
39     string_size_ += len;
40   }
41   entry->value =
42       reinterpret_cast<void*>(reinterpret_cast<size_t>(entry->value) + 1);
43   return reinterpret_cast<const char*>(entry->key);
44 }
45 
GetFormatted(const char * format,...)46 const char* StringsStorage::GetFormatted(const char* format, ...) {
47   va_list args;
48   va_start(args, format);
49   const char* result = GetVFormatted(format, args);
50   va_end(args);
51   return result;
52 }
53 
AddOrDisposeString(char * str,int len)54 const char* StringsStorage::AddOrDisposeString(char* str, int len) {
55   base::MutexGuard guard(&mutex_);
56   base::HashMap::Entry* entry = GetEntry(str, len);
57   if (entry->value == nullptr) {
58     // New entry added.
59     entry->key = str;
60     string_size_ += len;
61   } else {
62     DeleteArray(str);
63   }
64   entry->value =
65       reinterpret_cast<void*>(reinterpret_cast<size_t>(entry->value) + 1);
66   return reinterpret_cast<const char*>(entry->key);
67 }
68 
GetVFormatted(const char * format,va_list args)69 const char* StringsStorage::GetVFormatted(const char* format, va_list args) {
70   base::Vector<char> str = base::Vector<char>::New(1024);
71   int len = base::VSNPrintF(str, format, args);
72   if (len == -1) {
73     DeleteArray(str.begin());
74     return GetCopy(format);
75   }
76   return AddOrDisposeString(str.begin(), len);
77 }
78 
GetSymbol(Symbol sym)79 const char* StringsStorage::GetSymbol(Symbol sym) {
80   if (!sym.description().IsString()) {
81     return "<symbol>";
82   }
83   String description = String::cast(sym.description());
84   int length = std::min(FLAG_heap_snapshot_string_limit, description.length());
85   auto data = description.ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL, 0,
86                                     length, &length);
87   if (sym.is_private_name()) {
88     return AddOrDisposeString(data.release(), length);
89   }
90   auto str_length = 8 + length + 1 + 1;
91   auto str_result = NewArray<char>(str_length);
92   snprintf(str_result, str_length, "<symbol %s>", data.get());
93   return AddOrDisposeString(str_result, str_length - 1);
94 }
95 
GetName(Name name)96 const char* StringsStorage::GetName(Name name) {
97   if (name.IsString()) {
98     String str = String::cast(name);
99     int length = std::min(FLAG_heap_snapshot_string_limit, str.length());
100     int actual_length = 0;
101     std::unique_ptr<char[]> data = str.ToCString(
102         DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL, 0, length, &actual_length);
103     return AddOrDisposeString(data.release(), actual_length);
104   } else if (name.IsSymbol()) {
105     return GetSymbol(Symbol::cast(name));
106   }
107   return "";
108 }
109 
GetName(int index)110 const char* StringsStorage::GetName(int index) {
111   return GetFormatted("%d", index);
112 }
113 
GetConsName(const char * prefix,Name name)114 const char* StringsStorage::GetConsName(const char* prefix, Name name) {
115   if (name.IsString()) {
116     String str = String::cast(name);
117     int length = std::min(FLAG_heap_snapshot_string_limit, str.length());
118     int actual_length = 0;
119     std::unique_ptr<char[]> data = str.ToCString(
120         DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL, 0, length, &actual_length);
121 
122     int cons_length = actual_length + static_cast<int>(strlen(prefix)) + 1;
123     char* cons_result = NewArray<char>(cons_length);
124     snprintf(cons_result, cons_length, "%s%s", prefix, data.get());
125 
126     return AddOrDisposeString(cons_result, cons_length - 1);
127   } else if (name.IsSymbol()) {
128     return GetSymbol(Symbol::cast(name));
129   }
130   return "";
131 }
132 
133 namespace {
134 
ComputeStringHash(const char * str,int len)135 inline uint32_t ComputeStringHash(const char* str, int len) {
136   uint32_t raw_hash_field =
137       StringHasher::HashSequentialString(str, len, kZeroHashSeed);
138   return Name::HashBits::decode(raw_hash_field);
139 }
140 
141 }  // namespace
142 
Release(const char * str)143 bool StringsStorage::Release(const char* str) {
144   base::MutexGuard guard(&mutex_);
145   int len = static_cast<int>(strlen(str));
146   uint32_t hash = ComputeStringHash(str, len);
147   base::HashMap::Entry* entry = names_.Lookup(const_cast<char*>(str), hash);
148 
149   // If an entry wasn't found or the address of the found entry doesn't match
150   // the one passed in, this string wasn't managed by this StringsStorage
151   // instance (i.e. a constant). Ignore this.
152   if (!entry || entry->key != str) {
153     return false;
154   }
155 
156   DCHECK(entry->value);
157   entry->value =
158       reinterpret_cast<void*>(reinterpret_cast<size_t>(entry->value) - 1);
159 
160   if (entry->value == 0) {
161     string_size_ -= len;
162     names_.Remove(const_cast<char*>(str), hash);
163     DeleteArray(str);
164   }
165   return true;
166 }
167 
GetStringCountForTesting() const168 size_t StringsStorage::GetStringCountForTesting() const {
169   return names_.occupancy();
170 }
171 
GetStringSize()172 size_t StringsStorage::GetStringSize() {
173   base::MutexGuard guard(&mutex_);
174   return string_size_;
175 }
176 
GetEntry(const char * str,int len)177 base::HashMap::Entry* StringsStorage::GetEntry(const char* str, int len) {
178   uint32_t hash = ComputeStringHash(str, len);
179   return names_.LookupOrInsert(const_cast<char*>(str), hash);
180 }
181 
182 }  // namespace internal
183 }  // namespace v8
184