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 | #ifndef V8_CONSTANT_POOL_H_ |
6 | #define V8_CONSTANT_POOL_H_ |
7 | |
8 | #include <map> |
9 | |
10 | #include "src/double.h" |
11 | #include "src/globals.h" |
12 | #include "src/label.h" |
13 | #include "src/reloc-info.h" |
14 | |
15 | namespace v8 { |
16 | namespace internal { |
17 | |
18 | // ----------------------------------------------------------------------------- |
19 | // Constant pool support |
20 | |
21 | class ConstantPoolEntry { |
22 | public: |
23 | ConstantPoolEntry() = default; |
24 | ConstantPoolEntry(int position, intptr_t value, bool sharing_ok, |
25 | RelocInfo::Mode rmode = RelocInfo::NONE) |
26 | : position_(position), |
27 | merged_index_(sharing_ok ? SHARING_ALLOWED : SHARING_PROHIBITED), |
28 | value_(value), |
29 | rmode_(rmode) {} |
30 | ConstantPoolEntry(int position, Double value, |
31 | RelocInfo::Mode rmode = RelocInfo::NONE) |
32 | : position_(position), |
33 | merged_index_(SHARING_ALLOWED), |
34 | value64_(value.AsUint64()), |
35 | rmode_(rmode) {} |
36 | |
37 | int position() const { return position_; } |
38 | bool sharing_ok() const { return merged_index_ != SHARING_PROHIBITED; } |
39 | bool is_merged() const { return merged_index_ >= 0; } |
40 | int merged_index() const { |
41 | DCHECK(is_merged()); |
42 | return merged_index_; |
43 | } |
44 | void set_merged_index(int index) { |
45 | DCHECK(sharing_ok()); |
46 | merged_index_ = index; |
47 | DCHECK(is_merged()); |
48 | } |
49 | int offset() const { |
50 | DCHECK_GE(merged_index_, 0); |
51 | return merged_index_; |
52 | } |
53 | void set_offset(int offset) { |
54 | DCHECK_GE(offset, 0); |
55 | merged_index_ = offset; |
56 | } |
57 | intptr_t value() const { return value_; } |
58 | uint64_t value64() const { return value64_; } |
59 | RelocInfo::Mode rmode() const { return rmode_; } |
60 | |
61 | enum Type { INTPTR, DOUBLE, NUMBER_OF_TYPES }; |
62 | |
63 | static int size(Type type) { |
64 | return (type == INTPTR) ? kSystemPointerSize : kDoubleSize; |
65 | } |
66 | |
67 | enum Access { REGULAR, OVERFLOWED }; |
68 | |
69 | private: |
70 | int position_; |
71 | int merged_index_; |
72 | union { |
73 | intptr_t value_; |
74 | uint64_t value64_; |
75 | }; |
76 | // TODO(leszeks): The way we use this, it could probably be packed into |
77 | // merged_index_ if size is a concern. |
78 | RelocInfo::Mode rmode_; |
79 | enum { SHARING_PROHIBITED = -2, SHARING_ALLOWED = -1 }; |
80 | }; |
81 | |
82 | #if defined(V8_TARGET_ARCH_PPC) |
83 | |
84 | // ----------------------------------------------------------------------------- |
85 | // Embedded constant pool support |
86 | |
87 | class ConstantPoolBuilder { |
88 | public: |
89 | ConstantPoolBuilder(int ptr_reach_bits, int double_reach_bits); |
90 | |
91 | #ifdef DEBUG |
92 | ~ConstantPoolBuilder() { |
93 | // Unused labels to prevent DCHECK failures. |
94 | emitted_label_.Unuse(); |
95 | emitted_label_.UnuseNear(); |
96 | } |
97 | #endif |
98 | |
99 | // Add pointer-sized constant to the embedded constant pool |
100 | ConstantPoolEntry::Access AddEntry(int position, intptr_t value, |
101 | bool sharing_ok) { |
102 | ConstantPoolEntry entry(position, value, sharing_ok); |
103 | return AddEntry(entry, ConstantPoolEntry::INTPTR); |
104 | } |
105 | |
106 | // Add double constant to the embedded constant pool |
107 | ConstantPoolEntry::Access AddEntry(int position, Double value) { |
108 | ConstantPoolEntry entry(position, value); |
109 | return AddEntry(entry, ConstantPoolEntry::DOUBLE); |
110 | } |
111 | |
112 | // Add double constant to the embedded constant pool |
113 | ConstantPoolEntry::Access AddEntry(int position, double value) { |
114 | return AddEntry(position, Double(value)); |
115 | } |
116 | |
117 | // Previews the access type required for the next new entry to be added. |
118 | ConstantPoolEntry::Access NextAccess(ConstantPoolEntry::Type type) const; |
119 | |
120 | bool IsEmpty() { |
121 | return info_[ConstantPoolEntry::INTPTR].entries.empty() && |
122 | info_[ConstantPoolEntry::INTPTR].shared_entries.empty() && |
123 | info_[ConstantPoolEntry::DOUBLE].entries.empty() && |
124 | info_[ConstantPoolEntry::DOUBLE].shared_entries.empty(); |
125 | } |
126 | |
127 | // Emit the constant pool. Invoke only after all entries have been |
128 | // added and all instructions have been emitted. |
129 | // Returns position of the emitted pool (zero implies no constant pool). |
130 | int Emit(Assembler* assm); |
131 | |
132 | // Returns the label associated with the start of the constant pool. |
133 | // Linking to this label in the function prologue may provide an |
134 | // efficient means of constant pool pointer register initialization |
135 | // on some architectures. |
136 | inline Label* EmittedPosition() { return &emitted_label_; } |
137 | |
138 | private: |
139 | ConstantPoolEntry::Access AddEntry(ConstantPoolEntry& entry, |
140 | ConstantPoolEntry::Type type); |
141 | void EmitSharedEntries(Assembler* assm, ConstantPoolEntry::Type type); |
142 | void EmitGroup(Assembler* assm, ConstantPoolEntry::Access access, |
143 | ConstantPoolEntry::Type type); |
144 | |
145 | struct PerTypeEntryInfo { |
146 | PerTypeEntryInfo() : regular_count(0), overflow_start(-1) {} |
147 | bool overflow() const { |
148 | return (overflow_start >= 0 && |
149 | overflow_start < static_cast<int>(entries.size())); |
150 | } |
151 | int regular_reach_bits; |
152 | int regular_count; |
153 | int overflow_start; |
154 | std::vector<ConstantPoolEntry> entries; |
155 | std::vector<ConstantPoolEntry> shared_entries; |
156 | }; |
157 | |
158 | Label emitted_label_; // Records pc_offset of emitted pool |
159 | PerTypeEntryInfo info_[ConstantPoolEntry::NUMBER_OF_TYPES]; |
160 | }; |
161 | |
162 | #endif // defined(V8_TARGET_ARCH_PPC) |
163 | |
164 | } // namespace internal |
165 | } // namespace v8 |
166 | |
167 | #endif // V8_CONSTANT_POOL_H_ |
168 | |