• 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/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