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