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