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_IC_ACCESSOR_ASSEMBLER_H_
6 : #define V8_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 2520 : class AccessorAssembler : public CodeStubAssembler {
20 : public:
21 : using Node = compiler::Node;
22 : template <class T>
23 : using TNode = compiler::TNode<T>;
24 : template <class T>
25 : using SloppyTNode = compiler::SloppyTNode<T>;
26 :
27 2520 : explicit AccessorAssembler(compiler::CodeAssemblerState* state)
28 2532 : : CodeStubAssembler(state) {}
29 :
30 : void GenerateLoadIC();
31 : void GenerateLoadIC_Megamorphic();
32 : void GenerateLoadIC_Noninlined();
33 : void GenerateLoadIC_Uninitialized();
34 : void GenerateLoadICTrampoline();
35 : void GenerateLoadICTrampoline_Megamorphic();
36 : void GenerateKeyedLoadIC();
37 : void GenerateKeyedLoadIC_Megamorphic();
38 : void GenerateKeyedLoadIC_PolymorphicName();
39 : void GenerateKeyedLoadICTrampoline();
40 : void GenerateKeyedLoadICTrampoline_Megamorphic();
41 : void GenerateStoreIC();
42 : void GenerateStoreICTrampoline();
43 : void GenerateStoreGlobalIC();
44 : void GenerateStoreGlobalICTrampoline();
45 : void GenerateCloneObjectIC();
46 : void GenerateCloneObjectIC_Slow();
47 :
48 : void GenerateLoadGlobalIC(TypeofMode typeof_mode);
49 : void GenerateLoadGlobalICTrampoline(TypeofMode typeof_mode);
50 :
51 : void GenerateKeyedStoreIC();
52 : void GenerateKeyedStoreICTrampoline();
53 :
54 : void GenerateStoreInArrayLiteralIC();
55 :
56 : void TryProbeStubCache(StubCache* stub_cache, Node* receiver, Node* name,
57 : Label* if_handler, TVariable<MaybeObject>* var_handler,
58 : Label* if_miss);
59 :
60 : Node* StubCachePrimaryOffsetForTesting(Node* name, Node* map) {
61 8 : return StubCachePrimaryOffset(name, map);
62 : }
63 : Node* StubCacheSecondaryOffsetForTesting(Node* name, Node* map) {
64 4 : return StubCacheSecondaryOffset(name, map);
65 : }
66 :
67 : struct LoadICParameters {
68 1848 : LoadICParameters(Node* context, Node* receiver, Node* name, Node* slot,
69 : Node* vector, Node* holder = nullptr)
70 : : context(context),
71 : receiver(receiver),
72 : name(name),
73 : slot(slot),
74 : vector(vector),
75 1848 : holder(holder ? holder : receiver) {}
76 :
77 : Node* context;
78 : Node* receiver;
79 : Node* name;
80 : Node* slot;
81 : Node* vector;
82 : Node* holder;
83 : };
84 :
85 : void LoadGlobalIC(TNode<FeedbackVector> vector, Node* slot,
86 : const LazyNode<Context>& lazy_context,
87 : const LazyNode<Name>& lazy_name, TypeofMode typeof_mode,
88 : ExitPoint* exit_point,
89 : ParameterMode slot_mode = SMI_PARAMETERS);
90 :
91 : // Specialized LoadIC for inlined bytecode handler, hand-tuned to omit frame
92 : // construction on common paths.
93 : void LoadIC_BytecodeHandler(const LoadICParameters* p, ExitPoint* exit_point);
94 :
95 : // Loads dataX field from the DataHandler object.
96 : TNode<MaybeObject> LoadHandlerDataField(SloppyTNode<DataHandler> handler,
97 : int data_index);
98 :
99 : protected:
100 : struct StoreICParameters : public LoadICParameters {
101 504 : StoreICParameters(Node* context, Node* receiver, Node* name,
102 : SloppyTNode<Object> value, Node* slot, Node* vector)
103 : : LoadICParameters(context, receiver, name, slot, vector),
104 504 : value(value) {}
105 : SloppyTNode<Object> value;
106 : };
107 :
108 : enum class ICMode { kNonGlobalIC, kGlobalIC };
109 : enum ElementSupport { kOnlyProperties, kSupportElements };
110 : void HandleStoreICHandlerCase(
111 : const StoreICParameters* p, TNode<MaybeObject> handler, Label* miss,
112 : ICMode ic_mode, ElementSupport support_elements = kOnlyProperties);
113 : enum StoreTransitionMapFlags {
114 : kCheckPrototypeValidity = 1 << 0,
115 : kValidateTransitionHandler = 1 << 1,
116 : kStoreTransitionMapFlagsMask =
117 : kCheckPrototypeValidity | kValidateTransitionHandler,
118 : };
119 : void HandleStoreICTransitionMapHandlerCase(const StoreICParameters* p,
120 : TNode<Map> transition_map,
121 : Label* miss,
122 : StoreTransitionMapFlags flags);
123 :
124 : void JumpIfDataProperty(Node* details, Label* writable, Label* readonly);
125 :
126 : void InvalidateValidityCellIfPrototype(Node* map, Node* bitfield2 = nullptr);
127 :
128 : void OverwriteExistingFastDataProperty(Node* object, Node* object_map,
129 : Node* descriptors,
130 : Node* descriptor_name_index,
131 : Node* details, Node* value,
132 : Label* slow,
133 : bool do_transitioning_store);
134 :
135 : void CheckFieldType(TNode<DescriptorArray> descriptors, Node* name_index,
136 : Node* representation, Node* value, Label* bailout);
137 :
138 : private:
139 : // Stub generation entry points.
140 :
141 : // LoadIC contains the full LoadIC logic, while LoadIC_Noninlined contains
142 : // logic not inlined into Ignition bytecode handlers.
143 : void LoadIC(const LoadICParameters* p);
144 : void LoadIC_Noninlined(const LoadICParameters* p, Node* receiver_map,
145 : TNode<HeapObject> feedback,
146 : TVariable<MaybeObject>* var_handler, Label* if_handler,
147 : Label* miss, ExitPoint* exit_point);
148 :
149 : TNode<Object> LoadDescriptorValue(TNode<Map> map,
150 : TNode<IntPtrT> descriptor_entry);
151 : TNode<MaybeObject> LoadDescriptorValueOrFieldType(
152 : TNode<Map> map, TNode<IntPtrT> descriptor_entry);
153 :
154 : void LoadIC_Uninitialized(const LoadICParameters* p);
155 :
156 : void KeyedLoadIC(const LoadICParameters* p);
157 : void KeyedLoadICGeneric(const LoadICParameters* p);
158 : void KeyedLoadICPolymorphicName(const LoadICParameters* p);
159 : void StoreIC(const StoreICParameters* p);
160 : void StoreGlobalIC(const StoreICParameters* p);
161 : void StoreGlobalIC_PropertyCellCase(Node* property_cell, Node* value,
162 : ExitPoint* exit_point, Label* miss);
163 : void KeyedStoreIC(const StoreICParameters* p);
164 : void StoreInArrayLiteralIC(const StoreICParameters* p);
165 :
166 : // IC dispatcher behavior.
167 :
168 : // Checks monomorphic case. Returns {feedback} entry of the vector.
169 : TNode<MaybeObject> TryMonomorphicCase(Node* slot, Node* vector,
170 : Node* receiver_map, Label* if_handler,
171 : TVariable<MaybeObject>* var_handler,
172 : Label* if_miss);
173 : void HandlePolymorphicCase(Node* receiver_map, TNode<WeakFixedArray> feedback,
174 : Label* if_handler,
175 : TVariable<MaybeObject>* var_handler,
176 : Label* if_miss);
177 :
178 : // LoadIC implementation.
179 : void HandleLoadICHandlerCase(
180 : const LoadICParameters* p, TNode<Object> handler, Label* miss,
181 : ExitPoint* exit_point, ICMode ic_mode = ICMode::kNonGlobalIC,
182 : OnNonExistent on_nonexistent = OnNonExistent::kReturnUndefined,
183 : ElementSupport support_elements = kOnlyProperties);
184 :
185 : void HandleLoadICSmiHandlerCase(const LoadICParameters* p, Node* holder,
186 : SloppyTNode<Smi> smi_handler,
187 : SloppyTNode<Object> handler, Label* miss,
188 : ExitPoint* exit_point,
189 : OnNonExistent on_nonexistent,
190 : ElementSupport support_elements);
191 :
192 : void HandleLoadICProtoHandler(const LoadICParameters* p, Node* handler,
193 : Variable* var_holder, Variable* var_smi_handler,
194 : Label* if_smi_handler, Label* miss,
195 : ExitPoint* exit_point, ICMode ic_mode);
196 :
197 : void HandleLoadCallbackProperty(const LoadICParameters* p,
198 : TNode<JSObject> holder,
199 : TNode<WordT> handler_word,
200 : ExitPoint* exit_point);
201 :
202 : void HandleLoadAccessor(const LoadICParameters* p,
203 : TNode<CallHandlerInfo> call_handler_info,
204 : TNode<WordT> handler_word, TNode<DataHandler> handler,
205 : TNode<IntPtrT> handler_kind, ExitPoint* exit_point);
206 :
207 : void HandleLoadField(Node* holder, Node* handler_word,
208 : Variable* var_double_value, Label* rebox_double,
209 : ExitPoint* exit_point);
210 :
211 : void EmitAccessCheck(Node* expected_native_context, Node* context,
212 : Node* receiver, Label* can_access, Label* miss);
213 :
214 : // LoadGlobalIC implementation.
215 :
216 : void LoadGlobalIC_TryPropertyCellCase(
217 : TNode<FeedbackVector> vector, Node* slot,
218 : const LazyNode<Context>& lazy_context, ExitPoint* exit_point,
219 : Label* try_handler, Label* miss,
220 : ParameterMode slot_mode = SMI_PARAMETERS);
221 :
222 : void LoadGlobalIC_TryHandlerCase(TNode<FeedbackVector> vector, Node* slot,
223 : const LazyNode<Context>& lazy_context,
224 : const LazyNode<Name>& lazy_name,
225 : TypeofMode typeof_mode,
226 : ExitPoint* exit_point, Label* miss,
227 : ParameterMode slot_mode);
228 :
229 : // StoreIC implementation.
230 :
231 : void HandleStoreICProtoHandler(const StoreICParameters* p,
232 : TNode<StoreHandler> handler, Label* miss,
233 : ICMode ic_mode,
234 : ElementSupport support_elements);
235 : void HandleStoreICSmiHandlerCase(Node* handler_word, Node* holder,
236 : Node* value, Label* miss);
237 : void HandleStoreFieldAndReturn(Node* handler_word, Node* holder,
238 : Representation representation, Node* value,
239 : Label* miss);
240 :
241 : void CheckPrototypeValidityCell(Node* maybe_validity_cell, Label* miss);
242 : void HandleStoreICNativeDataProperty(const StoreICParameters* p, Node* holder,
243 : Node* handler_word);
244 :
245 : void HandleStoreToProxy(const StoreICParameters* p, Node* proxy, Label* miss,
246 : ElementSupport support_elements);
247 :
248 : void HandleStoreAccessor(const StoreICParameters* p, Node* holder,
249 : Node* handler_word);
250 :
251 : // KeyedLoadIC_Generic implementation.
252 :
253 : void GenericElementLoad(Node* receiver, Node* receiver_map,
254 : SloppyTNode<Int32T> instance_type, Node* index,
255 : Label* slow);
256 :
257 : enum UseStubCache { kUseStubCache, kDontUseStubCache };
258 : void GenericPropertyLoad(Node* receiver, Node* receiver_map,
259 : SloppyTNode<Int32T> instance_type,
260 : const LoadICParameters* p, Label* slow,
261 : UseStubCache use_stub_cache = kUseStubCache);
262 :
263 : // Low-level helpers.
264 :
265 : typedef std::function<void(Node* code_handler)> OnCodeHandler;
266 : typedef std::function<void(Node* properties, Node* name_index)>
267 : OnFoundOnReceiver;
268 :
269 : template <typename ICHandler, typename ICParameters>
270 : Node* HandleProtoHandler(const ICParameters* p, Node* handler,
271 : const OnCodeHandler& on_code_handler,
272 : const OnFoundOnReceiver& on_found_on_receiver,
273 : Label* miss, ICMode ic_mode);
274 :
275 : Node* PrepareValueForStore(Node* handler_word, Node* holder,
276 : Representation representation, Node* value,
277 : Label* bailout);
278 :
279 : // Extends properties backing store by JSObject::kFieldsAdded elements,
280 : // returns updated properties backing store.
281 : Node* ExtendPropertiesBackingStore(Node* object, Node* index);
282 :
283 : void StoreNamedField(Node* handler_word, Node* object, bool is_inobject,
284 : Representation representation, Node* value,
285 : Label* bailout);
286 :
287 : void EmitFastElementsBoundsCheck(Node* object, Node* elements,
288 : Node* intptr_index,
289 : Node* is_jsarray_condition, Label* miss);
290 : void EmitElementLoad(Node* object, Node* elements, Node* elements_kind,
291 : SloppyTNode<IntPtrT> key, Node* is_jsarray_condition,
292 : Label* if_hole, Label* rebox_double,
293 : Variable* var_double_value,
294 : Label* unimplemented_elements_kind, Label* out_of_bounds,
295 : Label* miss, ExitPoint* exit_point);
296 : void NameDictionaryNegativeLookup(Node* object, SloppyTNode<Name> name,
297 : Label* miss);
298 : TNode<BoolT> IsPropertyDetailsConst(Node* details);
299 :
300 : // Stub cache access helpers.
301 :
302 : // This enum is used here as a replacement for StubCache::Table to avoid
303 : // including stub cache header.
304 : enum StubCacheTable : int;
305 :
306 : Node* StubCachePrimaryOffset(Node* name, Node* map);
307 : Node* StubCacheSecondaryOffset(Node* name, Node* seed);
308 :
309 : void TryProbeStubCacheTable(StubCache* stub_cache, StubCacheTable table_id,
310 : Node* entry_offset, Node* name, Node* map,
311 : Label* if_handler,
312 : TVariable<MaybeObject>* var_handler,
313 : Label* if_miss);
314 : };
315 :
316 : // Abstraction over direct and indirect exit points. Direct exits correspond to
317 : // tailcalls and Return, while indirect exits store the result in a variable
318 : // and then jump to an exit label.
319 2128 : class ExitPoint {
320 : private:
321 : typedef compiler::Node Node;
322 : typedef compiler::CodeAssemblerLabel CodeAssemblerLabel;
323 : typedef compiler::CodeAssemblerVariable CodeAssemblerVariable;
324 :
325 : public:
326 : typedef std::function<void(Node* result)> IndirectReturnHandler;
327 :
328 1232 : explicit ExitPoint(CodeStubAssembler* assembler)
329 1232 : : ExitPoint(assembler, nullptr) {}
330 :
331 2128 : ExitPoint(CodeStubAssembler* assembler,
332 : const IndirectReturnHandler& indirect_return_handler)
333 2128 : : asm_(assembler), indirect_return_handler_(indirect_return_handler) {}
334 :
335 168 : ExitPoint(CodeStubAssembler* assembler, CodeAssemblerLabel* out,
336 : CodeAssemblerVariable* var_result)
337 3360 : : ExitPoint(assembler, [=](Node* result) {
338 3360 : var_result->Bind(result);
339 3360 : assembler->Goto(out);
340 3528 : }) {
341 : DCHECK_EQ(out != nullptr, var_result != nullptr);
342 168 : }
343 :
344 : template <class... TArgs>
345 7784 : void ReturnCallRuntime(Runtime::FunctionId function, Node* context,
346 : TArgs... args) {
347 7784 : if (IsDirect()) {
348 2464 : asm_->TailCallRuntime(function, context, args...);
349 : } else {
350 5320 : indirect_return_handler_(asm_->CallRuntime(function, context, args...));
351 : }
352 7784 : }
353 :
354 : template <class... TArgs>
355 2856 : void ReturnCallStub(Callable const& callable, Node* context, TArgs... args) {
356 2856 : if (IsDirect()) {
357 1176 : asm_->TailCallStub(callable, context, args...);
358 : } else {
359 1680 : indirect_return_handler_(asm_->CallStub(callable, context, args...));
360 : }
361 2856 : }
362 :
363 : template <class... TArgs>
364 1456 : void ReturnCallStub(const CallInterfaceDescriptor& descriptor, Node* target,
365 : Node* context, TArgs... args) {
366 1456 : if (IsDirect()) {
367 448 : asm_->TailCallStub(descriptor, target, context, args...);
368 : } else {
369 1008 : indirect_return_handler_(
370 : asm_->CallStub(descriptor, target, context, args...));
371 : }
372 1456 : }
373 :
374 18256 : void Return(Node* const result) {
375 18256 : if (IsDirect()) {
376 8400 : asm_->Return(result);
377 : } else {
378 9856 : indirect_return_handler_(result);
379 : }
380 18256 : }
381 :
382 30352 : bool IsDirect() const { return !indirect_return_handler_; }
383 :
384 : private:
385 : CodeStubAssembler* const asm_;
386 : IndirectReturnHandler indirect_return_handler_;
387 : };
388 :
389 : } // namespace internal
390 : } // namespace v8
391 :
392 : #endif // V8_IC_ACCESSOR_ASSEMBLER_H_
|