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