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
12 namespace v8 {
13 namespace internal {
14
BuiltinsConstantsTableBuilder(Isolate* isolate)15 BuiltinsConstantsTableBuilder::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
AddObject(Handle<Object> object)27 uint32_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
57 namespace {
CheckPreconditionsForPatching(Isolate* isolate, Handle<Object> replacement_object)58 void 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
PatchSelfReference( Handle<Object> self_reference, Handle<Code> code_object)75 void 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
PatchBasicBlockCountersReference( Handle<ByteArray> counters)89 void 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
Finalize()100 void 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