1// Copyright 2018 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/builtins/constants-table-builder.h"
6
7#include "src/execution/isolate.h"
8#include "src/heap/heap-inl.h"
9#include "src/objects/oddball-inl.h"
10#include "src/roots/roots-inl.h"
11
12namespace v8 {
13namespace internal {
14
15BuiltinsConstantsTableBuilder::BuiltinsConstantsTableBuilder(Isolate* isolate)
16    : isolate_(isolate), map_(isolate->heap()) {
17  // Ensure this is only called once per Isolate.
18  DCHECK_EQ(ReadOnlyRoots(isolate_).empty_fixed_array(),
19            isolate_->heap()->builtins_constants_table());
20
21  // And that the initial value of the builtins constants table can be treated
22  // as a constant, which means that codegen will load it using the root
23  // register.
24  DCHECK(RootsTable::IsImmortalImmovable(RootIndex::kEmptyFixedArray));
25}
26
27uint32_t BuiltinsConstantsTableBuilder::AddObject(Handle<Object> object) {
28#ifdef DEBUG
29  // Roots must not be inserted into the constants table as they are already
30  // accessibly from the root list.
31  RootIndex root_list_index;
32  DCHECK(!isolate_->roots_table().IsRootHandle(object, &root_list_index));
33
34  // Not yet finalized.
35  DCHECK_EQ(ReadOnlyRoots(isolate_).empty_fixed_array(),
36            isolate_->heap()->builtins_constants_table());
37
38  // Must be on the main thread.
39  DCHECK_EQ(ThreadId::Current(), isolate_->thread_id());
40
41  // Must be generating embedded builtin code.
42  DCHECK(isolate_->IsGeneratingEmbeddedBuiltins());
43
44  // All code objects should be loaded through the root register or use
45  // pc-relative addressing.
46  DCHECK(!object->IsCode());
47#endif
48
49  auto find_result = map_.FindOrInsert(object);
50  if (!find_result.already_exists) {
51    DCHECK(object->IsHeapObject());
52    *find_result.entry = map_.size() - 1;
53  }
54  return *find_result.entry;
55}
56
57namespace {
58void CheckPreconditionsForPatching(Isolate* isolate,
59                                   Handle<Object> replacement_object) {
60  // Roots must not be inserted into the constants table as they are already
61  // accessible from the root list.
62  RootIndex root_list_index;
63  DCHECK(!isolate->roots_table().IsRootHandle(replacement_object,
64                                              &root_list_index));
65  USE(root_list_index);
66
67  // Not yet finalized.
68  DCHECK_EQ(ReadOnlyRoots(isolate).empty_fixed_array(),
69            isolate->heap()->builtins_constants_table());
70
71  DCHECK(isolate->IsGeneratingEmbeddedBuiltins());
72}
73}  // namespace
74
75void BuiltinsConstantsTableBuilder::PatchSelfReference(
76    Handle<Object> self_reference, Handle<Code> code_object) {
77  CheckPreconditionsForPatching(isolate_, code_object);
78  DCHECK(self_reference->IsOddball());
79  DCHECK(Oddball::cast(*self_reference).kind() ==
80         Oddball::kSelfReferenceMarker);
81
82  uint32_t key;
83  if (map_.Delete(self_reference, &key)) {
84    DCHECK(code_object->IsCode());
85    map_.Insert(code_object, key);
86  }
87}
88
89void BuiltinsConstantsTableBuilder::PatchBasicBlockCountersReference(
90    Handle<ByteArray> counters) {
91  CheckPreconditionsForPatching(isolate_, counters);
92
93  uint32_t key;
94  if (map_.Delete(ReadOnlyRoots(isolate_).basic_block_counters_marker(),
95                  &key)) {
96    map_.Insert(counters, key);
97  }
98}
99
100void BuiltinsConstantsTableBuilder::Finalize() {
101  HandleScope handle_scope(isolate_);
102
103  DCHECK_EQ(ReadOnlyRoots(isolate_).empty_fixed_array(),
104            isolate_->heap()->builtins_constants_table());
105  DCHECK(isolate_->IsGeneratingEmbeddedBuiltins());
106
107  // An empty map means there's nothing to do.
108  if (map_.size() == 0) return;
109
110  Handle<FixedArray> table =
111      isolate_->factory()->NewFixedArray(map_.size(), AllocationType::kOld);
112
113  Builtins* builtins = isolate_->builtins();
114  ConstantsMap::IteratableScope it_scope(&map_);
115  for (auto it = it_scope.begin(); it != it_scope.end(); ++it) {
116    uint32_t index = *it.entry();
117    Object value = it.key();
118    if (value.IsCode() && Code::cast(value).kind() == CodeKind::BUILTIN) {
119      // Replace placeholder code objects with the real builtin.
120      // See also: SetupIsolateDelegate::PopulateWithPlaceholders.
121      // TODO(jgruber): Deduplicate placeholders and their corresponding
122      // builtin.
123      value = builtins->code(Code::cast(value).builtin_id());
124    }
125    DCHECK(value.IsHeapObject());
126    table->set(index, value);
127  }
128
129#ifdef DEBUG
130  for (int i = 0; i < map_.size(); i++) {
131    DCHECK(table->get(i).IsHeapObject());
132    DCHECK_NE(ReadOnlyRoots(isolate_).undefined_value(), table->get(i));
133    DCHECK_NE(ReadOnlyRoots(isolate_).self_reference_marker(), table->get(i));
134    DCHECK_NE(ReadOnlyRoots(isolate_).basic_block_counters_marker(),
135              table->get(i));
136  }
137#endif
138
139  isolate_->heap()->SetBuiltinsConstantsTable(*table);
140}
141
142}  // namespace internal
143}  // namespace v8
144