• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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/base/optional.h"
9 #include "src/codegen/code-stub-assembler.h"
10 #include "src/compiler/code-assembler.h"
11 
12 namespace v8 {
13 namespace internal {
14 
15 namespace compiler {
16 class CodeAssemblerState;
17 }  // namespace compiler
18 
19 class ExitPoint;
20 
21 class V8_EXPORT_PRIVATE AccessorAssembler : public CodeStubAssembler {
22  public:
23   using Node = compiler::Node;
24 
AccessorAssembler(compiler::CodeAssemblerState * state)25   explicit AccessorAssembler(compiler::CodeAssemblerState* state)
26       : CodeStubAssembler(state) {}
27 
28   void GenerateLoadIC();
29   void GenerateLoadIC_Megamorphic();
30   void GenerateLoadIC_Noninlined();
31   void GenerateLoadIC_NoFeedback();
32   void GenerateLoadGlobalIC_NoFeedback();
33   void GenerateLoadICTrampoline();
34   void GenerateLoadICTrampoline_Megamorphic();
35   void GenerateLoadSuperIC();
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   void GenerateKeyedHasIC();
48   void GenerateKeyedHasIC_Megamorphic();
49   void GenerateKeyedHasIC_PolymorphicName();
50 
51   void GenerateLoadGlobalIC(TypeofMode typeof_mode);
52   void GenerateLoadGlobalICTrampoline(TypeofMode typeof_mode);
53 
54   void GenerateKeyedStoreIC();
55   void GenerateKeyedStoreICTrampoline();
56 
57   void GenerateStoreInArrayLiteralIC();
58 
59   void TryProbeStubCache(StubCache* stub_cache,
60                          TNode<Object> lookup_start_object, TNode<Name> name,
61                          Label* if_handler, TVariable<MaybeObject>* var_handler,
62                          Label* if_miss);
63 
StubCachePrimaryOffsetForTesting(TNode<Name> name,TNode<Map> map)64   TNode<IntPtrT> StubCachePrimaryOffsetForTesting(TNode<Name> name,
65                                                   TNode<Map> map) {
66     return StubCachePrimaryOffset(name, map);
67   }
StubCacheSecondaryOffsetForTesting(TNode<Name> name,TNode<IntPtrT> seed)68   TNode<IntPtrT> StubCacheSecondaryOffsetForTesting(TNode<Name> name,
69                                                     TNode<IntPtrT> seed) {
70     return StubCacheSecondaryOffset(name, seed);
71   }
72 
73   struct LoadICParameters {
74     LoadICParameters(
75         TNode<Context> context, TNode<Object> receiver, TNode<Object> name,
76         TNode<TaggedIndex> slot, TNode<HeapObject> vector,
77         base::Optional<TNode<Object>> lookup_start_object = base::nullopt)
context_LoadICParameters78         : context_(context),
79           receiver_(receiver),
80           name_(name),
81           slot_(slot),
82           vector_(vector),
83           lookup_start_object_(lookup_start_object ? lookup_start_object.value()
84                                                    : receiver) {}
85 
LoadICParametersLoadICParameters86     LoadICParameters(const LoadICParameters* p, TNode<Object> unique_name)
87         : context_(p->context_),
88           receiver_(p->receiver_),
89           name_(unique_name),
90           slot_(p->slot_),
91           vector_(p->vector_),
92           lookup_start_object_(p->lookup_start_object_) {}
93 
contextLoadICParameters94     TNode<Context> context() const { return context_; }
receiverLoadICParameters95     TNode<Object> receiver() const { return receiver_; }
nameLoadICParameters96     TNode<Object> name() const { return name_; }
slotLoadICParameters97     TNode<TaggedIndex> slot() const { return slot_; }
vectorLoadICParameters98     TNode<HeapObject> vector() const { return vector_; }
lookup_start_objectLoadICParameters99     TNode<Object> lookup_start_object() const {
100       return lookup_start_object_.value();
101     }
102 
103     // Usable in cases where the receiver and the lookup start object are
104     // expected to be the same, i.e., when "receiver != lookup_start_object"
105     // case is not supported or not expected by the surrounding code.
receiver_and_lookup_start_objectLoadICParameters106     TNode<Object> receiver_and_lookup_start_object() const {
107       DCHECK_EQ(receiver_, lookup_start_object_);
108       return receiver_;
109     }
110 
111    private:
112     TNode<Context> context_;
113     TNode<Object> receiver_;
114     TNode<Object> name_;
115     TNode<TaggedIndex> slot_;
116     TNode<HeapObject> vector_;
117     base::Optional<TNode<Object>> lookup_start_object_;
118   };
119 
120   struct LazyLoadICParameters {
121     LazyLoadICParameters(
122         LazyNode<Context> context, TNode<Object> receiver,
123         LazyNode<Object> name, LazyNode<TaggedIndex> slot,
124         TNode<HeapObject> vector,
125         base::Optional<TNode<Object>> lookup_start_object = base::nullopt)
context_LazyLoadICParameters126         : context_(context),
127           receiver_(receiver),
128           name_(name),
129           slot_(slot),
130           vector_(vector),
131           lookup_start_object_(lookup_start_object ? lookup_start_object.value()
132                                                    : receiver) {}
133 
LazyLoadICParametersLazyLoadICParameters134     explicit LazyLoadICParameters(const LoadICParameters* p)
135         : receiver_(p->receiver()),
136           vector_(p->vector()),
137           lookup_start_object_(p->lookup_start_object()) {
138       slot_ = [=] { return p->slot(); };
139       context_ = [=] { return p->context(); };
140       name_ = [=] { return p->name(); };
141     }
142 
contextLazyLoadICParameters143     TNode<Context> context() const { return context_(); }
receiverLazyLoadICParameters144     TNode<Object> receiver() const { return receiver_; }
nameLazyLoadICParameters145     TNode<Object> name() const { return name_(); }
slotLazyLoadICParameters146     TNode<TaggedIndex> slot() const { return slot_(); }
vectorLazyLoadICParameters147     TNode<HeapObject> vector() const { return vector_; }
lookup_start_objectLazyLoadICParameters148     TNode<Object> lookup_start_object() const { return lookup_start_object_; }
149 
150     // Usable in cases where the receiver and the lookup start object are
151     // expected to be the same, i.e., when "receiver != lookup_start_object"
152     // case is not supported or not expected by the surrounding code.
receiver_and_lookup_start_objectLazyLoadICParameters153     TNode<Object> receiver_and_lookup_start_object() const {
154       DCHECK_EQ(receiver_, lookup_start_object_);
155       return receiver_;
156     }
157 
158    private:
159     LazyNode<Context> context_;
160     TNode<Object> receiver_;
161     LazyNode<Object> name_;
162     LazyNode<TaggedIndex> slot_;
163     TNode<HeapObject> vector_;
164     TNode<Object> lookup_start_object_;
165   };
166 
167   void LoadGlobalIC(TNode<HeapObject> maybe_feedback_vector,
168                     const LazyNode<TaggedIndex>& lazy_slot,
169                     const LazyNode<Context>& lazy_context,
170                     const LazyNode<Name>& lazy_name, TypeofMode typeof_mode,
171                     ExitPoint* exit_point);
172 
173   // Specialized LoadIC for inlined bytecode handler, hand-tuned to omit frame
174   // construction on common paths.
175   void LoadIC_BytecodeHandler(const LazyLoadICParameters* p,
176                               ExitPoint* exit_point);
177 
178   // Loads dataX field from the DataHandler object.
179   TNode<MaybeObject> LoadHandlerDataField(TNode<DataHandler> handler,
180                                           int data_index);
181 
182  protected:
183   struct StoreICParameters {
StoreICParametersStoreICParameters184     StoreICParameters(TNode<Context> context,
185                       base::Optional<TNode<Object>> receiver,
186                       TNode<Object> name, TNode<Object> value,
187                       TNode<TaggedIndex> slot, TNode<HeapObject> vector)
188         : context_(context),
189           receiver_(receiver),
190           name_(name),
191           value_(value),
192           slot_(slot),
193           vector_(vector) {}
194 
contextStoreICParameters195     TNode<Context> context() const { return context_; }
receiverStoreICParameters196     TNode<Object> receiver() const { return receiver_.value(); }
nameStoreICParameters197     TNode<Object> name() const { return name_; }
valueStoreICParameters198     TNode<Object> value() const { return value_; }
slotStoreICParameters199     TNode<TaggedIndex> slot() const { return slot_; }
vectorStoreICParameters200     TNode<HeapObject> vector() const { return vector_; }
201 
lookup_start_objectStoreICParameters202     TNode<Object> lookup_start_object() const { return receiver(); }
203 
receiver_is_nullStoreICParameters204     bool receiver_is_null() const { return !receiver_.has_value(); }
205 
206    private:
207     TNode<Context> context_;
208     base::Optional<TNode<Object>> receiver_;
209     TNode<Object> name_;
210     TNode<Object> value_;
211     TNode<TaggedIndex> slot_;
212     TNode<HeapObject> vector_;
213   };
214 
215   enum class LoadAccessMode { kLoad, kHas };
216   enum class ICMode { kNonGlobalIC, kGlobalIC };
217   enum ElementSupport { kOnlyProperties, kSupportElements };
218   void HandleStoreICHandlerCase(
219       const StoreICParameters* p, TNode<MaybeObject> handler, Label* miss,
220       ICMode ic_mode, ElementSupport support_elements = kOnlyProperties);
221   enum StoreTransitionMapFlags {
222     kCheckPrototypeValidity = 1 << 0,
223     kValidateTransitionHandler = 1 << 1,
224     kStoreTransitionMapFlagsMask =
225         kCheckPrototypeValidity | kValidateTransitionHandler,
226   };
227   void HandleStoreICTransitionMapHandlerCase(const StoreICParameters* p,
228                                              TNode<Map> transition_map,
229                                              Label* miss,
230                                              StoreTransitionMapFlags flags);
231 
232   void JumpIfDataProperty(TNode<Uint32T> details, Label* writable,
233                           Label* readonly);
234 
235   void InvalidateValidityCellIfPrototype(
236       TNode<Map> map, base::Optional<TNode<Uint32T>> bitfield3 = base::nullopt);
237 
238   void OverwriteExistingFastDataProperty(TNode<HeapObject> object,
239                                          TNode<Map> object_map,
240                                          TNode<DescriptorArray> descriptors,
241                                          TNode<IntPtrT> descriptor_name_index,
242                                          TNode<Uint32T> details,
243                                          TNode<Object> value, Label* slow,
244                                          bool do_transitioning_store);
245 
246   void CheckFieldType(TNode<DescriptorArray> descriptors,
247                       TNode<IntPtrT> name_index, TNode<Word32T> representation,
248                       TNode<Object> value, Label* bailout);
249 
250  private:
251   // Stub generation entry points.
252 
253   // LoadIC contains the full LoadIC logic, while LoadIC_Noninlined contains
254   // logic not inlined into Ignition bytecode handlers.
255   void LoadIC(const LoadICParameters* p);
256 
257   // Can be used in the receiver != lookup_start_object case.
258   void LoadIC_Noninlined(const LoadICParameters* p,
259                          TNode<Map> lookup_start_object_map,
260                          TNode<HeapObject> feedback,
261                          TVariable<MaybeObject>* var_handler, Label* if_handler,
262                          Label* miss, ExitPoint* exit_point);
263 
264   void LoadSuperIC(const LoadICParameters* p);
265 
266   TNode<Object> LoadDescriptorValue(TNode<Map> map,
267                                     TNode<IntPtrT> descriptor_entry);
268   TNode<MaybeObject> LoadDescriptorValueOrFieldType(
269       TNode<Map> map, TNode<IntPtrT> descriptor_entry);
270 
271   void LoadIC_NoFeedback(const LoadICParameters* p, TNode<Smi> smi_typeof_mode);
272   void LoadSuperIC_NoFeedback(const LoadICParameters* p);
273   void LoadGlobalIC_NoFeedback(TNode<Context> context, TNode<Object> name,
274                                TNode<Smi> smi_typeof_mode);
275 
276   void KeyedLoadIC(const LoadICParameters* p, LoadAccessMode access_mode);
277   void KeyedLoadICGeneric(const LoadICParameters* p);
278   void KeyedLoadICPolymorphicName(const LoadICParameters* p,
279                                   LoadAccessMode access_mode);
280   void StoreIC(const StoreICParameters* p);
281   void StoreGlobalIC(const StoreICParameters* p);
282   void StoreGlobalIC_PropertyCellCase(TNode<PropertyCell> property_cell,
283                                       TNode<Object> value,
284                                       ExitPoint* exit_point, Label* miss);
285   void KeyedStoreIC(const StoreICParameters* p);
286   void StoreInArrayLiteralIC(const StoreICParameters* p);
287 
288   // IC dispatcher behavior.
289 
290   // Checks monomorphic case. Returns {feedback} entry of the vector.
291   TNode<MaybeObject> TryMonomorphicCase(TNode<TaggedIndex> slot,
292                                         TNode<FeedbackVector> vector,
293                                         TNode<Map> lookup_start_object_map,
294                                         Label* if_handler,
295                                         TVariable<MaybeObject>* var_handler,
296                                         Label* if_miss);
297   void HandlePolymorphicCase(TNode<Map> lookup_start_object_map,
298                              TNode<WeakFixedArray> feedback, Label* if_handler,
299                              TVariable<MaybeObject>* var_handler,
300                              Label* if_miss);
301 
302   // LoadIC implementation.
303   void HandleLoadICHandlerCase(
304       const LazyLoadICParameters* p, TNode<Object> handler, Label* miss,
305       ExitPoint* exit_point, ICMode ic_mode = ICMode::kNonGlobalIC,
306       OnNonExistent on_nonexistent = OnNonExistent::kReturnUndefined,
307       ElementSupport support_elements = kOnlyProperties,
308       LoadAccessMode access_mode = LoadAccessMode::kLoad);
309 
310   void HandleLoadICSmiHandlerCase(const LazyLoadICParameters* p,
311                                   TNode<Object> holder, TNode<Smi> smi_handler,
312                                   TNode<Object> handler, Label* miss,
313                                   ExitPoint* exit_point, ICMode ic_mode,
314                                   OnNonExistent on_nonexistent,
315                                   ElementSupport support_elements,
316                                   LoadAccessMode access_mode);
317 
318   void HandleLoadICProtoHandler(const LazyLoadICParameters* p,
319                                 TNode<DataHandler> handler,
320                                 TVariable<Object>* var_holder,
321                                 TVariable<Object>* var_smi_handler,
322                                 Label* if_smi_handler, Label* miss,
323                                 ExitPoint* exit_point, ICMode ic_mode,
324                                 LoadAccessMode access_mode);
325 
326   void HandleLoadCallbackProperty(const LazyLoadICParameters* p,
327                                   TNode<JSObject> holder,
328                                   TNode<WordT> handler_word,
329                                   ExitPoint* exit_point);
330 
331   void HandleLoadAccessor(const LazyLoadICParameters* p,
332                           TNode<CallHandlerInfo> call_handler_info,
333                           TNode<WordT> handler_word, TNode<DataHandler> handler,
334                           TNode<IntPtrT> handler_kind, ExitPoint* exit_point);
335 
336   void HandleLoadField(TNode<JSObject> holder, TNode<WordT> handler_word,
337                        TVariable<Float64T>* var_double_value,
338                        Label* rebox_double, Label* miss, ExitPoint* exit_point);
339 
340   void EmitAccessCheck(TNode<Context> expected_native_context,
341                        TNode<Context> context, TNode<Object> receiver,
342                        Label* can_access, Label* miss);
343 
344   void HandleLoadICSmiHandlerLoadNamedCase(
345       const LazyLoadICParameters* p, TNode<Object> holder,
346       TNode<IntPtrT> handler_kind, TNode<WordT> handler_word,
347       Label* rebox_double, TVariable<Float64T>* var_double_value,
348       TNode<Object> handler, Label* miss, ExitPoint* exit_point, ICMode ic_mode,
349       OnNonExistent on_nonexistent, ElementSupport support_elements);
350 
351   void HandleLoadICSmiHandlerHasNamedCase(const LazyLoadICParameters* p,
352                                           TNode<Object> holder,
353                                           TNode<IntPtrT> handler_kind,
354                                           Label* miss, ExitPoint* exit_point,
355                                           ICMode ic_mode);
356 
357   // LoadGlobalIC implementation.
358 
359   void LoadGlobalIC_TryPropertyCellCase(TNode<FeedbackVector> vector,
360                                         TNode<TaggedIndex> slot,
361                                         const LazyNode<Context>& lazy_context,
362                                         ExitPoint* exit_point,
363                                         Label* try_handler, Label* miss);
364 
365   void LoadGlobalIC_TryHandlerCase(TNode<FeedbackVector> vector,
366                                    TNode<TaggedIndex> slot,
367                                    const LazyNode<Context>& lazy_context,
368                                    const LazyNode<Name>& lazy_name,
369                                    TypeofMode typeof_mode,
370                                    ExitPoint* exit_point, Label* miss);
371 
372   // This is a copy of ScriptContextTable::Lookup. They should be kept in sync.
373   void ScriptContextTableLookup(TNode<Name> name,
374                                 TNode<NativeContext> native_context,
375                                 Label* found_hole, Label* not_found);
376 
377   // StoreIC implementation.
378 
379   void HandleStoreICProtoHandler(const StoreICParameters* p,
380                                  TNode<StoreHandler> handler, Label* miss,
381                                  ICMode ic_mode,
382                                  ElementSupport support_elements);
383   void HandleStoreICSmiHandlerCase(TNode<Word32T> handler_word,
384                                    TNode<JSObject> holder, TNode<Object> value,
385                                    Label* miss);
386   void HandleStoreFieldAndReturn(TNode<Word32T> handler_word,
387                                  TNode<JSObject> holder, TNode<Object> value,
388                                  base::Optional<TNode<Float64T>> double_value,
389                                  Representation representation, Label* miss);
390 
391   void CheckPrototypeValidityCell(TNode<Object> maybe_validity_cell,
392                                   Label* miss);
393   void HandleStoreICNativeDataProperty(const StoreICParameters* p,
394                                        TNode<HeapObject> holder,
395                                        TNode<Word32T> handler_word);
396 
397   void HandleStoreToProxy(const StoreICParameters* p, TNode<JSProxy> proxy,
398                           Label* miss, ElementSupport support_elements);
399 
400   void HandleStoreAccessor(const StoreICParameters* p, TNode<HeapObject> holder,
401                            TNode<Word32T> handler_word);
402 
403   // KeyedLoadIC_Generic implementation.
404 
405   void GenericElementLoad(TNode<HeapObject> lookup_start_object,
406                           TNode<Map> lookup_start_object_map,
407                           TNode<Int32T> lookup_start_object_instance_type,
408                           TNode<IntPtrT> index, Label* slow);
409 
410   enum UseStubCache { kUseStubCache, kDontUseStubCache };
411   void GenericPropertyLoad(TNode<HeapObject> lookup_start_object,
412                            TNode<Map> lookup_start_object_map,
413                            TNode<Int32T> lookup_start_object_instance_type,
414                            const LoadICParameters* p, Label* slow,
415                            UseStubCache use_stub_cache = kUseStubCache);
416 
417   // Low-level helpers.
418 
419   using OnCodeHandler = std::function<void(TNode<Code> code_handler)>;
420   using OnFoundOnLookupStartObject = std::function<void(
421       TNode<NameDictionary> properties, TNode<IntPtrT> name_index)>;
422 
423   template <typename ICHandler, typename ICParameters>
424   TNode<Object> HandleProtoHandler(
425       const ICParameters* p, TNode<DataHandler> handler,
426       const OnCodeHandler& on_code_handler,
427       const OnFoundOnLookupStartObject& on_found_on_lookup_start_object,
428       Label* miss, ICMode ic_mode);
429 
430   void CheckHeapObjectTypeMatchesDescriptor(TNode<Word32T> handler_word,
431                                             TNode<JSObject> holder,
432                                             TNode<Object> value,
433                                             Label* bailout);
434   // Double fields store double values in a mutable box, where stores are
435   // writes into this box rather than HeapNumber assignment.
436   void CheckDescriptorConsidersNumbersMutable(TNode<Word32T> handler_word,
437                                               TNode<JSObject> holder,
438                                               Label* bailout);
439 
440   // Extends properties backing store by JSObject::kFieldsAdded elements,
441   // returns updated properties backing store.
442   TNode<PropertyArray> ExtendPropertiesBackingStore(TNode<HeapObject> object,
443                                                     TNode<IntPtrT> index);
444 
445   void EmitFastElementsBoundsCheck(TNode<JSObject> object,
446                                    TNode<FixedArrayBase> elements,
447                                    TNode<IntPtrT> intptr_index,
448                                    TNode<BoolT> is_jsarray_condition,
449                                    Label* miss);
450   void EmitElementLoad(TNode<HeapObject> object, TNode<Word32T> elements_kind,
451                        TNode<IntPtrT> key, TNode<BoolT> is_jsarray_condition,
452                        Label* if_hole, Label* rebox_double,
453                        TVariable<Float64T>* var_double_value,
454                        Label* unimplemented_elements_kind, Label* out_of_bounds,
455                        Label* miss, ExitPoint* exit_point,
456                        LoadAccessMode access_mode = LoadAccessMode::kLoad);
457   TNode<BoolT> IsPropertyDetailsConst(TNode<Uint32T> details);
458 
459   // Stub cache access helpers.
460 
461   // This enum is used here as a replacement for StubCache::Table to avoid
462   // including stub cache header.
463   enum StubCacheTable : int;
464 
465   TNode<IntPtrT> StubCachePrimaryOffset(TNode<Name> name, TNode<Map> map);
466   TNode<IntPtrT> StubCacheSecondaryOffset(TNode<Name> name,
467                                           TNode<IntPtrT> seed);
468 
469   void TryProbeStubCacheTable(StubCache* stub_cache, StubCacheTable table_id,
470                               TNode<IntPtrT> entry_offset, TNode<Object> name,
471                               TNode<Map> map, Label* if_handler,
472                               TVariable<MaybeObject>* var_handler,
473                               Label* if_miss);
474 
475   void BranchIfPrototypesHaveNoElements(TNode<Map> receiver_map,
476                                         Label* definitely_no_elements,
477                                         Label* possibly_elements);
478 };
479 
480 // Abstraction over direct and indirect exit points. Direct exits correspond to
481 // tailcalls and Return, while indirect exits store the result in a variable
482 // and then jump to an exit label.
483 class ExitPoint {
484  private:
485   using CodeAssemblerLabel = compiler::CodeAssemblerLabel;
486 
487  public:
488   using IndirectReturnHandler = std::function<void(TNode<Object> result)>;
489 
ExitPoint(CodeStubAssembler * assembler)490   explicit ExitPoint(CodeStubAssembler* assembler)
491       : ExitPoint(assembler, nullptr) {}
492 
ExitPoint(CodeStubAssembler * assembler,const IndirectReturnHandler & indirect_return_handler)493   ExitPoint(CodeStubAssembler* assembler,
494             const IndirectReturnHandler& indirect_return_handler)
495       : asm_(assembler), indirect_return_handler_(indirect_return_handler) {}
496 
ExitPoint(CodeStubAssembler * assembler,CodeAssemblerLabel * out,compiler::CodeAssembler::TVariable<Object> * var_result)497   ExitPoint(CodeStubAssembler* assembler, CodeAssemblerLabel* out,
498             compiler::CodeAssembler::TVariable<Object>* var_result)
499       : ExitPoint(assembler, [=](TNode<Object> result) {
500           *var_result = result;
501           assembler->Goto(out);
502         }) {
503     DCHECK_EQ(out != nullptr, var_result != nullptr);
504   }
505 
506   template <class... TArgs>
ReturnCallRuntime(Runtime::FunctionId function,TNode<Context> context,TArgs...args)507   void ReturnCallRuntime(Runtime::FunctionId function, TNode<Context> context,
508                          TArgs... args) {
509     if (IsDirect()) {
510       asm_->TailCallRuntime(function, context, args...);
511     } else {
512       indirect_return_handler_(asm_->CallRuntime(function, context, args...));
513     }
514   }
515 
516   template <class... TArgs>
ReturnCallStub(Callable const & callable,TNode<Context> context,TArgs...args)517   void ReturnCallStub(Callable const& callable, TNode<Context> context,
518                       TArgs... args) {
519     if (IsDirect()) {
520       asm_->TailCallStub(callable, context, args...);
521     } else {
522       indirect_return_handler_(asm_->CallStub(callable, context, args...));
523     }
524   }
525 
526   template <class... TArgs>
ReturnCallStub(const CallInterfaceDescriptor & descriptor,TNode<Code> target,TNode<Context> context,TArgs...args)527   void ReturnCallStub(const CallInterfaceDescriptor& descriptor,
528                       TNode<Code> target, TNode<Context> context,
529                       TArgs... args) {
530     if (IsDirect()) {
531       asm_->TailCallStub(descriptor, target, context, args...);
532     } else {
533       indirect_return_handler_(
534           asm_->CallStub(descriptor, target, context, args...));
535     }
536   }
537 
Return(const TNode<Object> result)538   void Return(const TNode<Object> result) {
539     if (IsDirect()) {
540       asm_->Return(result);
541     } else {
542       indirect_return_handler_(result);
543     }
544   }
545 
IsDirect()546   bool IsDirect() const { return !indirect_return_handler_; }
547 
548  private:
549   CodeStubAssembler* const asm_;
550   IndirectReturnHandler indirect_return_handler_;
551 };
552 
553 }  // namespace internal
554 }  // namespace v8
555 
556 #endif  // V8_IC_ACCESSOR_ASSEMBLER_H_
557