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/heap/heap-inl.h" |
8 | #include "src/isolate.h" |
9 | #include "src/objects/oddball-inl.h" |
10 | #include "src/roots-inl.h" |
11 | |
12 | namespace v8 { |
13 | namespace internal { |
14 | |
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 | |
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 | uint32_t* maybe_key = map_.Find(object); |
50 | if (maybe_key == nullptr) { |
51 | DCHECK(object->IsHeapObject()); |
52 | uint32_t index = map_.size(); |
53 | map_.Set(object, index); |
54 | return index; |
55 | } else { |
56 | return *maybe_key; |
57 | } |
58 | } |
59 | |
60 | void BuiltinsConstantsTableBuilder::PatchSelfReference( |
61 | Handle<Object> self_reference, Handle<Code> code_object) { |
62 | #ifdef DEBUG |
63 | // Roots must not be inserted into the constants table as they are already |
64 | // accessibly from the root list. |
65 | RootIndex root_list_index; |
66 | DCHECK(!isolate_->roots_table().IsRootHandle(code_object, &root_list_index)); |
67 | |
68 | // Not yet finalized. |
69 | DCHECK_EQ(ReadOnlyRoots(isolate_).empty_fixed_array(), |
70 | isolate_->heap()->builtins_constants_table()); |
71 | |
72 | DCHECK(isolate_->IsGeneratingEmbeddedBuiltins()); |
73 | |
74 | DCHECK(self_reference->IsOddball()); |
75 | DCHECK(Oddball::cast(*self_reference)->kind() == |
76 | Oddball::kSelfReferenceMarker); |
77 | #endif |
78 | |
79 | uint32_t key; |
80 | if (map_.Delete(self_reference, &key)) { |
81 | DCHECK(code_object->IsCode()); |
82 | map_.Set(code_object, key); |
83 | } |
84 | } |
85 | |
86 | void BuiltinsConstantsTableBuilder::Finalize() { |
87 | HandleScope handle_scope(isolate_); |
88 | |
89 | DCHECK_EQ(ReadOnlyRoots(isolate_).empty_fixed_array(), |
90 | isolate_->heap()->builtins_constants_table()); |
91 | DCHECK(isolate_->IsGeneratingEmbeddedBuiltins()); |
92 | |
93 | // An empty map means there's nothing to do. |
94 | if (map_.size() == 0) return; |
95 | |
96 | Handle<FixedArray> table = |
97 | isolate_->factory()->NewFixedArray(map_.size(), AllocationType::kOld); |
98 | |
99 | Builtins* builtins = isolate_->builtins(); |
100 | ConstantsMap::IteratableScope it_scope(&map_); |
101 | for (auto it = it_scope.begin(); it != it_scope.end(); ++it) { |
102 | uint32_t index = *it.entry(); |
103 | Object value = it.key(); |
104 | if (value->IsCode() && Code::cast(value)->kind() == Code::BUILTIN) { |
105 | // Replace placeholder code objects with the real builtin. |
106 | // See also: SetupIsolateDelegate::PopulateWithPlaceholders. |
107 | // TODO(jgruber): Deduplicate placeholders and their corresponding |
108 | // builtin. |
109 | value = builtins->builtin(Code::cast(value)->builtin_index()); |
110 | } |
111 | DCHECK(value->IsHeapObject()); |
112 | table->set(index, value); |
113 | } |
114 | |
115 | #ifdef DEBUG |
116 | for (int i = 0; i < map_.size(); i++) { |
117 | DCHECK(table->get(i)->IsHeapObject()); |
118 | DCHECK_NE(ReadOnlyRoots(isolate_).undefined_value(), table->get(i)); |
119 | DCHECK_NE(ReadOnlyRoots(isolate_).self_reference_marker(), table->get(i)); |
120 | } |
121 | #endif |
122 | |
123 | isolate_->heap()->SetBuiltinsConstantsTable(*table); |
124 | } |
125 | |
126 | } // namespace internal |
127 | } // namespace v8 |
128 | |