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
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 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
60void 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
86void 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