Line data Source code
1 : // Copyright 2016 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_SRC_IC_ACCESSOR_ASSEMBLER_H_
6 : #define V8_SRC_IC_ACCESSOR_ASSEMBLER_H_
7 :
8 : #include "src/code-stub-assembler.h"
9 :
10 : namespace v8 {
11 : namespace internal {
12 :
13 : namespace compiler {
14 : class CodeAssemblerState;
15 : }
16 :
17 : class ExitPoint;
18 :
19 : class AccessorAssembler : public CodeStubAssembler {
20 : public:
21 : typedef compiler::Node Node;
22 :
23 : explicit AccessorAssembler(compiler::CodeAssemblerState* state)
24 1720 : : CodeStubAssembler(state) {}
25 :
26 : void GenerateLoadIC();
27 : void GenerateLoadIC_Noninlined();
28 : void GenerateLoadIC_Uninitialized();
29 : void GenerateLoadField();
30 : void GenerateLoadICTrampoline();
31 : void GenerateKeyedLoadIC();
32 : void GenerateKeyedLoadICTrampoline();
33 : void GenerateKeyedLoadIC_Megamorphic();
34 : void GenerateStoreIC(LanguageMode language_mode);
35 : void GenerateStoreICTrampoline(LanguageMode language_mode);
36 :
37 : void GenerateLoadICProtoArray(bool throw_reference_error_if_nonexistent);
38 :
39 : void GenerateLoadGlobalIC(TypeofMode typeof_mode);
40 : void GenerateLoadGlobalICTrampoline(TypeofMode typeof_mode);
41 :
42 : void GenerateKeyedStoreIC(LanguageMode language_mode);
43 : void GenerateKeyedStoreICTrampoline(LanguageMode language_mode);
44 :
45 : void TryProbeStubCache(StubCache* stub_cache, Node* receiver, Node* name,
46 : Label* if_handler, Variable* var_handler,
47 : Label* if_miss);
48 :
49 : Node* StubCachePrimaryOffsetForTesting(Node* name, Node* map) {
50 : return StubCachePrimaryOffset(name, map);
51 : }
52 : Node* StubCacheSecondaryOffsetForTesting(Node* name, Node* map) {
53 : return StubCacheSecondaryOffset(name, map);
54 : }
55 :
56 : struct LoadICParameters {
57 : LoadICParameters(Node* context, Node* receiver, Node* name, Node* slot,
58 : Node* vector)
59 : : context(context),
60 : receiver(receiver),
61 : name(name),
62 : slot(slot),
63 1892 : vector(vector) {}
64 :
65 : Node* context;
66 : Node* receiver;
67 : Node* name;
68 : Node* slot;
69 : Node* vector;
70 : };
71 :
72 : void LoadGlobalIC_TryPropertyCellCase(
73 : Node* vector, Node* slot, ExitPoint* exit_point, Label* try_handler,
74 : Label* miss, ParameterMode slot_mode = SMI_PARAMETERS);
75 : void LoadGlobalIC_TryHandlerCase(const LoadICParameters* p,
76 : TypeofMode typeof_mode,
77 : ExitPoint* exit_point, Label* miss);
78 : void LoadGlobalIC_MissCase(const LoadICParameters* p, ExitPoint* exit_point);
79 :
80 : // Specialized LoadIC for inlined bytecode handler, hand-tuned to omit frame
81 : // construction on common paths.
82 : void LoadIC_BytecodeHandler(const LoadICParameters* p, ExitPoint* exit_point);
83 :
84 : protected:
85 : struct StoreICParameters : public LoadICParameters {
86 : StoreICParameters(Node* context, Node* receiver, Node* name, Node* value,
87 : Node* slot, Node* vector)
88 : : LoadICParameters(context, receiver, name, slot, vector),
89 344 : value(value) {}
90 : Node* value;
91 : };
92 :
93 : enum ElementSupport { kOnlyProperties, kSupportElements };
94 : void HandleStoreICHandlerCase(
95 : const StoreICParameters* p, Node* handler, Label* miss,
96 : ElementSupport support_elements = kOnlyProperties);
97 : void JumpIfDataProperty(Node* details, Label* writable, Label* readonly);
98 :
99 : private:
100 : // Stub generation entry points.
101 :
102 : // LoadIC contains the full LoadIC logic, while LoadIC_Noninlined contains
103 : // logic not inlined into Ignition bytecode handlers.
104 : void LoadIC(const LoadICParameters* p);
105 : void LoadIC_Noninlined(const LoadICParameters* p, Node* receiver_map,
106 : Node* feedback, Variable* var_handler,
107 : Label* if_handler, Label* miss, ExitPoint* exit_point);
108 :
109 : void LoadIC_Uninitialized(const LoadICParameters* p);
110 : void LoadICProtoArray(const LoadICParameters* p, Node* handler,
111 : bool throw_reference_error_if_nonexistent);
112 : void LoadGlobalIC(const LoadICParameters* p, TypeofMode typeof_mode);
113 : void KeyedLoadIC(const LoadICParameters* p);
114 : void KeyedLoadICGeneric(const LoadICParameters* p);
115 : void StoreIC(const StoreICParameters* p, LanguageMode language_mode);
116 : void KeyedStoreIC(const StoreICParameters* p, LanguageMode language_mode);
117 :
118 : // IC dispatcher behavior.
119 :
120 : // Checks monomorphic case. Returns {feedback} entry of the vector.
121 : Node* TryMonomorphicCase(Node* slot, Node* vector, Node* receiver_map,
122 : Label* if_handler, Variable* var_handler,
123 : Label* if_miss);
124 : void HandlePolymorphicCase(Node* receiver_map, Node* feedback,
125 : Label* if_handler, Variable* var_handler,
126 : Label* if_miss, int min_feedback_capacity);
127 :
128 : // LoadIC implementation.
129 :
130 : void HandleLoadICHandlerCase(
131 : const LoadICParameters* p, Node* handler, Label* miss,
132 : ExitPoint* exit_point, ElementSupport support_elements = kOnlyProperties);
133 :
134 : void HandleLoadICSmiHandlerCase(const LoadICParameters* p, Node* holder,
135 : Node* smi_handler, Label* miss,
136 : ExitPoint* exit_point,
137 : bool throw_reference_error_if_nonexistent,
138 : ElementSupport support_elements);
139 :
140 : void HandleLoadICProtoHandlerCase(const LoadICParameters* p, Node* handler,
141 : Variable* var_holder,
142 : Variable* var_smi_handler,
143 : Label* if_smi_handler, Label* miss,
144 : ExitPoint* exit_point,
145 : bool throw_reference_error_if_nonexistent);
146 :
147 : void HandleLoadField(Node* holder, Node* handler_word,
148 : Variable* var_double_value, Label* rebox_double,
149 : ExitPoint* exit_point);
150 :
151 : Node* EmitLoadICProtoArrayCheck(const LoadICParameters* p, Node* handler,
152 : Node* handler_length, Node* handler_flags,
153 : Label* miss);
154 :
155 : // LoadGlobalIC implementation.
156 :
157 : void HandleLoadGlobalICHandlerCase(const LoadICParameters* p, Node* handler,
158 : Label* miss, ExitPoint* exit_point,
159 : bool throw_reference_error_if_nonexistent);
160 :
161 : // StoreIC implementation.
162 :
163 : void HandleStoreICElementHandlerCase(const StoreICParameters* p,
164 : Node* handler, Label* miss);
165 :
166 : void HandleStoreICProtoHandler(const StoreICParameters* p, Node* handler,
167 : Label* miss, ElementSupport support_elements);
168 : // If |transition| is nullptr then the normal field store is generated or
169 : // transitioning store otherwise.
170 : void HandleStoreICSmiHandlerCase(Node* handler_word, Node* holder,
171 : Node* value, Node* transition, Label* miss);
172 : // If |transition| is nullptr then the normal field store is generated or
173 : // transitioning store otherwise.
174 : void HandleStoreFieldAndReturn(Node* handler_word, Node* holder,
175 : Representation representation, Node* value,
176 : Node* transition, Label* miss);
177 :
178 : // KeyedLoadIC_Generic implementation.
179 :
180 : void GenericElementLoad(Node* receiver, Node* receiver_map,
181 : Node* instance_type, Node* index, Label* slow);
182 :
183 : enum UseStubCache { kUseStubCache, kDontUseStubCache };
184 : void GenericPropertyLoad(Node* receiver, Node* receiver_map,
185 : Node* instance_type, Node* key,
186 : const LoadICParameters* p, Label* slow,
187 : UseStubCache use_stub_cache = kUseStubCache);
188 :
189 : // Low-level helpers.
190 :
191 : Node* PrepareValueForStore(Node* handler_word, Node* holder,
192 : Representation representation, Node* transition,
193 : Node* value, Label* bailout);
194 :
195 : // Extends properties backing store by JSObject::kFieldsAdded elements.
196 : void ExtendPropertiesBackingStore(Node* object, Node* handler_word);
197 :
198 : void StoreNamedField(Node* handler_word, Node* object, bool is_inobject,
199 : Representation representation, Node* value,
200 : bool transition_to_field, Label* bailout);
201 :
202 : void EmitFastElementsBoundsCheck(Node* object, Node* elements,
203 : Node* intptr_index,
204 : Node* is_jsarray_condition, Label* miss);
205 : void EmitElementLoad(Node* object, Node* elements, Node* elements_kind,
206 : Node* key, Node* is_jsarray_condition, Label* if_hole,
207 : Label* rebox_double, Variable* var_double_value,
208 : Label* unimplemented_elements_kind, Label* out_of_bounds,
209 : Label* miss, ExitPoint* exit_point);
210 : void CheckPrototype(Node* prototype_cell, Node* name, Label* miss);
211 : void NameDictionaryNegativeLookup(Node* object, Node* name, Label* miss);
212 :
213 : // Stub cache access helpers.
214 :
215 : // This enum is used here as a replacement for StubCache::Table to avoid
216 : // including stub cache header.
217 : enum StubCacheTable : int;
218 :
219 : Node* StubCachePrimaryOffset(Node* name, Node* map);
220 : Node* StubCacheSecondaryOffset(Node* name, Node* seed);
221 :
222 : void TryProbeStubCacheTable(StubCache* stub_cache, StubCacheTable table_id,
223 : Node* entry_offset, Node* name, Node* map,
224 : Label* if_handler, Variable* var_handler,
225 : Label* if_miss);
226 : };
227 :
228 : // Abstraction over direct and indirect exit points. Direct exits correspond to
229 : // tailcalls and Return, while indirect exits store the result in a variable
230 : // and then jump to an exit label.
231 : class ExitPoint {
232 : private:
233 : typedef compiler::Node Node;
234 : typedef compiler::CodeAssemblerLabel CodeAssemblerLabel;
235 : typedef compiler::CodeAssemblerVariable CodeAssemblerVariable;
236 :
237 : public:
238 : explicit ExitPoint(CodeStubAssembler* assembler)
239 : : ExitPoint(assembler, nullptr, nullptr) {}
240 : ExitPoint(CodeStubAssembler* assembler, CodeAssemblerLabel* out,
241 : CodeAssemblerVariable* var_result)
242 1634 : : out_(out), var_result_(var_result), asm_(assembler) {
243 : DCHECK_EQ(out != nullptr, var_result != nullptr);
244 : }
245 :
246 : template <class... TArgs>
247 3053 : void ReturnCallRuntime(Runtime::FunctionId function, Node* context,
248 3053 : TArgs... args) {
249 3053 : if (IsDirect()) {
250 731 : asm_->TailCallRuntime(function, context, args...);
251 : } else {
252 2322 : IndirectReturn(asm_->CallRuntime(function, context, args...));
253 : }
254 3053 : }
255 :
256 : template <class... TArgs>
257 2580 : void ReturnCallStub(Callable const& callable, Node* context, TArgs... args) {
258 2580 : if (IsDirect()) {
259 774 : asm_->TailCallStub(callable, context, args...);
260 : } else {
261 1806 : IndirectReturn(asm_->CallStub(callable, context, args...));
262 : }
263 2580 : }
264 :
265 : template <class... TArgs>
266 1032 : void ReturnCallStub(const CallInterfaceDescriptor& descriptor, Node* target,
267 1032 : Node* context, TArgs... args) {
268 1032 : if (IsDirect()) {
269 258 : asm_->TailCallStub(descriptor, target, context, args...);
270 : } else {
271 1548 : IndirectReturn(asm_->CallStub(descriptor, target, context, args...));
272 : }
273 1032 : }
274 :
275 14491 : void Return(Node* const result) {
276 14491 : if (IsDirect()) {
277 4558 : asm_->Return(result);
278 : } else {
279 9933 : IndirectReturn(result);
280 : }
281 14491 : }
282 :
283 : bool IsDirect() const { return out_ == nullptr; }
284 :
285 : private:
286 14835 : void IndirectReturn(Node* const result) {
287 14835 : var_result_->Bind(result);
288 14835 : asm_->Goto(out_);
289 14835 : }
290 :
291 : CodeAssemblerLabel* const out_;
292 : CodeAssemblerVariable* const var_result_;
293 : CodeStubAssembler* const asm_;
294 : };
295 :
296 : } // namespace internal
297 : } // namespace v8
298 :
299 : #endif // V8_SRC_IC_ACCESSOR_ASSEMBLER_H_
|