1// Copyright 2016 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/codegen/external-reference-table.h"
6
7#include "src/builtins/accessors.h"
8#include "src/codegen/external-reference.h"
9#include "src/execution/isolate.h"
10#include "src/ic/stub-cache.h"
11#include "src/logging/counters.h"
12
13#if defined(DEBUG) && defined(V8_OS_LINUX) && !defined(V8_OS_ANDROID)
14#define SYMBOLIZE_FUNCTION
15#include <execinfo.h>
16
17#include <vector>
18
19#include "src/base/platform/wrappers.h"
20#endif  // DEBUG && V8_OS_LINUX && !V8_OS_ANDROID
21
22namespace v8 {
23namespace internal {
24
25#define ADD_EXT_REF_NAME(name, desc) desc,
26#define ADD_BUILTIN_NAME(Name, ...) "Builtin_" #Name,
27#define ADD_RUNTIME_FUNCTION(name, ...) "Runtime::" #name,
28#define ADD_ISOLATE_ADDR(Name, name) "Isolate::" #name "_address",
29#define ADD_ACCESSOR_INFO_NAME(_, __, AccessorName, ...) \
30  "Accessors::" #AccessorName "Getter",
31#define ADD_ACCESSOR_SETTER_NAME(name) "Accessors::" #name,
32#define ADD_STATS_COUNTER_NAME(name, ...) "StatsCounter::" #name,
33// static
34// clang-format off
35const char* const
36    ExternalReferenceTable::ref_name_[ExternalReferenceTable::kSize] = {
37        // === Isolate independent ===
38        // Special references:
39        "nullptr",
40        // External references (without isolate):
41        EXTERNAL_REFERENCE_LIST(ADD_EXT_REF_NAME)
42        // Builtins:
43        BUILTIN_LIST_C(ADD_BUILTIN_NAME)
44        // Runtime functions:
45        FOR_EACH_INTRINSIC(ADD_RUNTIME_FUNCTION)
46        // Accessors:
47        ACCESSOR_INFO_LIST_GENERATOR(ADD_ACCESSOR_INFO_NAME, /* not used */)
48        ACCESSOR_SETTER_LIST(ADD_ACCESSOR_SETTER_NAME)
49
50        // === Isolate dependent ===
51        // External references (with isolate):
52        EXTERNAL_REFERENCE_LIST_WITH_ISOLATE(ADD_EXT_REF_NAME)
53        // Isolate addresses:
54        FOR_EACH_ISOLATE_ADDRESS_NAME(ADD_ISOLATE_ADDR)
55        // Stub cache:
56        "Load StubCache::primary_->key",
57        "Load StubCache::primary_->value",
58        "Load StubCache::primary_->map",
59        "Load StubCache::secondary_->key",
60        "Load StubCache::secondary_->value",
61        "Load StubCache::secondary_->map",
62        "Store StubCache::primary_->key",
63        "Store StubCache::primary_->value",
64        "Store StubCache::primary_->map",
65        "Store StubCache::secondary_->key",
66        "Store StubCache::secondary_->value",
67        "Store StubCache::secondary_->map",
68        // Native code counters:
69        STATS_COUNTER_NATIVE_CODE_LIST(ADD_STATS_COUNTER_NAME)
70};
71// clang-format on
72#undef ADD_EXT_REF_NAME
73#undef ADD_BUILTIN_NAME
74#undef ADD_RUNTIME_FUNCTION
75#undef ADD_ISOLATE_ADDR
76#undef ADD_ACCESSOR_INFO_NAME
77#undef ADD_ACCESSOR_SETTER_NAME
78#undef ADD_STATS_COUNTER_NAME
79
80namespace {
81static Address ref_addr_isolate_independent_
82    [ExternalReferenceTable::kSizeIsolateIndependent] = {0};
83}  // namespace
84
85// Forward declarations for C++ builtins.
86#define FORWARD_DECLARE(Name) \
87  Address Builtin_##Name(int argc, Address* args, Isolate* isolate);
88BUILTIN_LIST_C(FORWARD_DECLARE)
89#undef FORWARD_DECLARE
90
91void ExternalReferenceTable::Init(Isolate* isolate) {
92  int index = 0;
93
94  CopyIsolateIndependentReferences(&index);
95
96  AddIsolateDependentReferences(isolate, &index);
97  AddIsolateAddresses(isolate, &index);
98  AddStubCache(isolate, &index);
99  AddNativeCodeStatsCounters(isolate, &index);
100  is_initialized_ = static_cast<uint32_t>(true);
101
102  CHECK_EQ(kSize, index);
103}
104
105const char* ExternalReferenceTable::ResolveSymbol(void* address) {
106#ifdef SYMBOLIZE_FUNCTION
107  char** names = backtrace_symbols(&address, 1);
108  const char* name = names[0];
109  // The array of names is malloc'ed. However, each name string is static
110  // and do not need to be freed.
111  base::Free(names);
112  return name;
113#else
114  return "<unresolved>";
115#endif  // SYMBOLIZE_FUNCTION
116}
117
118void ExternalReferenceTable::InitializeOncePerProcess() {
119  int index = 0;
120
121  // kNullAddress is preserved through serialization/deserialization.
122  AddIsolateIndependent(kNullAddress, &index);
123  AddIsolateIndependentReferences(&index);
124  AddBuiltins(&index);
125  AddRuntimeFunctions(&index);
126  AddAccessors(&index);
127
128  CHECK_EQ(kSizeIsolateIndependent, index);
129}
130
131const char* ExternalReferenceTable::NameOfIsolateIndependentAddress(
132    Address address) {
133  for (int i = 0; i < kSizeIsolateIndependent; i++) {
134    if (ref_addr_isolate_independent_[i] == address) {
135      return ref_name_[i];
136    }
137  }
138  return "<unknown>";
139}
140
141void ExternalReferenceTable::Add(Address address, int* index) {
142  ref_addr_[(*index)++] = address;
143}
144
145void ExternalReferenceTable::AddIsolateIndependent(Address address,
146                                                   int* index) {
147  ref_addr_isolate_independent_[(*index)++] = address;
148}
149
150void ExternalReferenceTable::AddIsolateIndependentReferences(int* index) {
151  CHECK_EQ(kSpecialReferenceCount, *index);
152
153#define ADD_EXTERNAL_REFERENCE(name, desc) \
154  AddIsolateIndependent(ExternalReference::name().address(), index);
155  EXTERNAL_REFERENCE_LIST(ADD_EXTERNAL_REFERENCE)
156#undef ADD_EXTERNAL_REFERENCE
157
158  CHECK_EQ(kSpecialReferenceCount + kExternalReferenceCountIsolateIndependent,
159           *index);
160}
161
162void ExternalReferenceTable::AddIsolateDependentReferences(Isolate* isolate,
163                                                           int* index) {
164  CHECK_EQ(kSizeIsolateIndependent, *index);
165
166#define ADD_EXTERNAL_REFERENCE(name, desc) \
167  Add(ExternalReference::name(isolate).address(), index);
168  EXTERNAL_REFERENCE_LIST_WITH_ISOLATE(ADD_EXTERNAL_REFERENCE)
169#undef ADD_EXTERNAL_REFERENCE
170
171  CHECK_EQ(kSizeIsolateIndependent + kExternalReferenceCountIsolateDependent,
172           *index);
173}
174
175void ExternalReferenceTable::AddBuiltins(int* index) {
176  CHECK_EQ(kSpecialReferenceCount + kExternalReferenceCountIsolateIndependent,
177           *index);
178
179  static const Address c_builtins[] = {
180#define DEF_ENTRY(Name, ...) FUNCTION_ADDR(&Builtin_##Name),
181      BUILTIN_LIST_C(DEF_ENTRY)
182#undef DEF_ENTRY
183  };
184  for (Address addr : c_builtins) {
185    AddIsolateIndependent(ExternalReference::Create(addr).address(), index);
186  }
187
188  CHECK_EQ(kSpecialReferenceCount + kExternalReferenceCountIsolateIndependent +
189               kBuiltinsReferenceCount,
190           *index);
191}
192
193void ExternalReferenceTable::AddRuntimeFunctions(int* index) {
194  CHECK_EQ(kSpecialReferenceCount + kExternalReferenceCountIsolateIndependent +
195               kBuiltinsReferenceCount,
196           *index);
197
198  static constexpr Runtime::FunctionId runtime_functions[] = {
199#define RUNTIME_ENTRY(name, ...) Runtime::k##name,
200      FOR_EACH_INTRINSIC(RUNTIME_ENTRY)
201#undef RUNTIME_ENTRY
202  };
203
204  for (Runtime::FunctionId fId : runtime_functions) {
205    AddIsolateIndependent(ExternalReference::Create(fId).address(), index);
206  }
207
208  CHECK_EQ(kSpecialReferenceCount + kExternalReferenceCountIsolateIndependent +
209               kBuiltinsReferenceCount + kRuntimeReferenceCount,
210           *index);
211}
212
213void ExternalReferenceTable::CopyIsolateIndependentReferences(int* index) {
214  CHECK_EQ(0, *index);
215
216  std::copy(ref_addr_isolate_independent_,
217            ref_addr_isolate_independent_ + kSizeIsolateIndependent, ref_addr_);
218  *index += kSizeIsolateIndependent;
219}
220
221void ExternalReferenceTable::AddIsolateAddresses(Isolate* isolate, int* index) {
222  CHECK_EQ(kSizeIsolateIndependent + kExternalReferenceCountIsolateDependent,
223           *index);
224
225  for (int i = 0; i < IsolateAddressId::kIsolateAddressCount; ++i) {
226    Add(isolate->get_address_from_id(static_cast<IsolateAddressId>(i)), index);
227  }
228
229  CHECK_EQ(kSizeIsolateIndependent + kExternalReferenceCountIsolateDependent +
230               kIsolateAddressReferenceCount,
231           *index);
232}
233
234void ExternalReferenceTable::AddAccessors(int* index) {
235  CHECK_EQ(kSpecialReferenceCount + kExternalReferenceCountIsolateIndependent +
236               kBuiltinsReferenceCount + kRuntimeReferenceCount,
237           *index);
238
239  static const Address accessors[] = {
240  // Getters:
241#define ACCESSOR_INFO_DECLARATION(_, __, AccessorName, ...) \
242  FUNCTION_ADDR(&Accessors::AccessorName##Getter),
243      ACCESSOR_INFO_LIST_GENERATOR(ACCESSOR_INFO_DECLARATION, /* not used */)
244#undef ACCESSOR_INFO_DECLARATION
245  // Setters:
246#define ACCESSOR_SETTER_DECLARATION(name) FUNCTION_ADDR(&Accessors::name),
247          ACCESSOR_SETTER_LIST(ACCESSOR_SETTER_DECLARATION)
248#undef ACCESSOR_SETTER_DECLARATION
249  };
250
251  for (Address addr : accessors) {
252    AddIsolateIndependent(addr, index);
253  }
254
255  CHECK_EQ(kSpecialReferenceCount + kExternalReferenceCountIsolateIndependent +
256               kBuiltinsReferenceCount + kRuntimeReferenceCount +
257               kAccessorReferenceCount,
258           *index);
259}
260
261void ExternalReferenceTable::AddStubCache(Isolate* isolate, int* index) {
262  CHECK_EQ(kSizeIsolateIndependent + kExternalReferenceCountIsolateDependent +
263               kIsolateAddressReferenceCount,
264           *index);
265
266  StubCache* load_stub_cache = isolate->load_stub_cache();
267
268  // Stub cache tables
269  Add(load_stub_cache->key_reference(StubCache::kPrimary).address(), index);
270  Add(load_stub_cache->value_reference(StubCache::kPrimary).address(), index);
271  Add(load_stub_cache->map_reference(StubCache::kPrimary).address(), index);
272  Add(load_stub_cache->key_reference(StubCache::kSecondary).address(), index);
273  Add(load_stub_cache->value_reference(StubCache::kSecondary).address(), index);
274  Add(load_stub_cache->map_reference(StubCache::kSecondary).address(), index);
275
276  StubCache* store_stub_cache = isolate->store_stub_cache();
277
278  // Stub cache tables
279  Add(store_stub_cache->key_reference(StubCache::kPrimary).address(), index);
280  Add(store_stub_cache->value_reference(StubCache::kPrimary).address(), index);
281  Add(store_stub_cache->map_reference(StubCache::kPrimary).address(), index);
282  Add(store_stub_cache->key_reference(StubCache::kSecondary).address(), index);
283  Add(store_stub_cache->value_reference(StubCache::kSecondary).address(),
284      index);
285  Add(store_stub_cache->map_reference(StubCache::kSecondary).address(), index);
286
287  CHECK_EQ(kSizeIsolateIndependent + kExternalReferenceCountIsolateDependent +
288               kIsolateAddressReferenceCount + kStubCacheReferenceCount,
289           *index);
290}
291
292Address ExternalReferenceTable::GetStatsCounterAddress(StatsCounter* counter) {
293  if (!counter->Enabled()) {
294    return reinterpret_cast<Address>(&dummy_stats_counter_);
295  }
296  std::atomic<int>* address = counter->GetInternalPointer();
297  STATIC_ASSERT(sizeof(address) == sizeof(Address));
298  return reinterpret_cast<Address>(address);
299}
300
301void ExternalReferenceTable::AddNativeCodeStatsCounters(Isolate* isolate,
302                                                        int* index) {
303  CHECK_EQ(kSizeIsolateIndependent + kExternalReferenceCountIsolateDependent +
304               kIsolateAddressReferenceCount + kStubCacheReferenceCount,
305           *index);
306
307  Counters* counters = isolate->counters();
308
309#define SC(name, caption) Add(GetStatsCounterAddress(counters->name()), index);
310  STATS_COUNTER_NATIVE_CODE_LIST(SC)
311#undef SC
312
313  CHECK_EQ(kSizeIsolateIndependent + kExternalReferenceCountIsolateDependent +
314               kIsolateAddressReferenceCount + kStubCacheReferenceCount +
315               kStatsCountersReferenceCount,
316           *index);
317  CHECK_EQ(kSize, *index);
318}
319
320}  // namespace internal
321}  // namespace v8
322
323#undef SYMBOLIZE_FUNCTION
324