1 // Copyright 2012 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_STUB_CACHE_H_ 6 #define V8_STUB_CACHE_H_ 7 8 #include "src/allocation.h" 9 #include "src/arguments.h" 10 #include "src/code-stubs.h" 11 #include "src/ic-inl.h" 12 #include "src/macro-assembler.h" 13 #include "src/objects.h" 14 #include "src/zone-inl.h" 15 16 namespace v8 { 17 namespace internal { 18 19 20 // The stub cache is used for megamorphic calls and property accesses. 21 // It maps (map, name, type)->Code* 22 23 // The design of the table uses the inline cache stubs used for 24 // mono-morphic calls. The beauty of this, we do not have to 25 // invalidate the cache whenever a prototype map is changed. The stub 26 // validates the map chain as in the mono-morphic case. 27 28 29 class CallOptimization; 30 class SmallMapList; 31 class StubCache; 32 33 34 class SCTableReference { 35 public: 36 Address address() const { return address_; } 37 38 private: 39 explicit SCTableReference(Address address) : address_(address) {} 40 41 Address address_; 42 43 friend class StubCache; 44 }; 45 46 47 class StubCache { 48 public: 49 struct Entry { 50 Name* key; 51 Code* value; 52 Map* map; 53 }; 54 55 void Initialize(); 56 57 Handle<JSObject> StubHolder(Handle<JSObject> receiver, 58 Handle<JSObject> holder); 59 60 Handle<Code> FindIC(Handle<Name> name, 61 Handle<Map> stub_holder_map, 62 Code::Kind kind, 63 ExtraICState extra_state = kNoExtraICState, 64 InlineCacheHolderFlag cache_holder = OWN_MAP); 65 66 Handle<Code> FindHandler(Handle<Name> name, 67 Handle<Map> map, 68 Code::Kind kind, 69 InlineCacheHolderFlag cache_holder, 70 Code::StubType type); 71 72 Handle<Code> ComputeMonomorphicIC(Code::Kind kind, 73 Handle<Name> name, 74 Handle<HeapType> type, 75 Handle<Code> handler, 76 ExtraICState extra_ic_state); 77 78 Handle<Code> ComputeLoadNonexistent(Handle<Name> name, Handle<HeapType> type); 79 80 Handle<Code> ComputeKeyedLoadElement(Handle<Map> receiver_map); 81 82 Handle<Code> ComputeKeyedStoreElement(Handle<Map> receiver_map, 83 StrictMode strict_mode, 84 KeyedAccessStoreMode store_mode); 85 86 // --- 87 88 Handle<Code> ComputeLoad(InlineCacheState ic_state, ExtraICState extra_state); 89 Handle<Code> ComputeStore(InlineCacheState ic_state, 90 ExtraICState extra_state); 91 92 // --- 93 94 Handle<Code> ComputeCompareNil(Handle<Map> receiver_map, 95 CompareNilICStub* stub); 96 97 // --- 98 99 Handle<Code> ComputeLoadElementPolymorphic(MapHandleList* receiver_maps); 100 Handle<Code> ComputeStoreElementPolymorphic(MapHandleList* receiver_maps, 101 KeyedAccessStoreMode store_mode, 102 StrictMode strict_mode); 103 104 Handle<Code> ComputePolymorphicIC(Code::Kind kind, 105 TypeHandleList* types, 106 CodeHandleList* handlers, 107 int number_of_valid_maps, 108 Handle<Name> name, 109 ExtraICState extra_ic_state); 110 111 // Finds the Code object stored in the Heap::non_monomorphic_cache(). 112 Code* FindPreMonomorphicIC(Code::Kind kind, ExtraICState extra_ic_state); 113 114 // Update cache for entry hash(name, map). 115 Code* Set(Name* name, Map* map, Code* code); 116 117 // Clear the lookup table (@ mark compact collection). 118 void Clear(); 119 120 // Collect all maps that match the name and flags. 121 void CollectMatchingMaps(SmallMapList* types, 122 Handle<Name> name, 123 Code::Flags flags, 124 Handle<Context> native_context, 125 Zone* zone); 126 127 // Generate code for probing the stub cache table. 128 // Arguments extra, extra2 and extra3 may be used to pass additional scratch 129 // registers. Set to no_reg if not needed. 130 void GenerateProbe(MacroAssembler* masm, 131 Code::Flags flags, 132 Register receiver, 133 Register name, 134 Register scratch, 135 Register extra, 136 Register extra2 = no_reg, 137 Register extra3 = no_reg); 138 139 enum Table { 140 kPrimary, 141 kSecondary 142 }; 143 144 145 SCTableReference key_reference(StubCache::Table table) { 146 return SCTableReference( 147 reinterpret_cast<Address>(&first_entry(table)->key)); 148 } 149 150 151 SCTableReference map_reference(StubCache::Table table) { 152 return SCTableReference( 153 reinterpret_cast<Address>(&first_entry(table)->map)); 154 } 155 156 157 SCTableReference value_reference(StubCache::Table table) { 158 return SCTableReference( 159 reinterpret_cast<Address>(&first_entry(table)->value)); 160 } 161 162 163 StubCache::Entry* first_entry(StubCache::Table table) { 164 switch (table) { 165 case StubCache::kPrimary: return StubCache::primary_; 166 case StubCache::kSecondary: return StubCache::secondary_; 167 } 168 UNREACHABLE(); 169 return NULL; 170 } 171 172 Isolate* isolate() { return isolate_; } 173 Heap* heap() { return isolate()->heap(); } 174 Factory* factory() { return isolate()->factory(); } 175 176 // These constants describe the structure of the interceptor arguments on the 177 // stack. The arguments are pushed by the (platform-specific) 178 // PushInterceptorArguments and read by LoadPropertyWithInterceptorOnly and 179 // LoadWithInterceptor. 180 static const int kInterceptorArgsNameIndex = 0; 181 static const int kInterceptorArgsInfoIndex = 1; 182 static const int kInterceptorArgsThisIndex = 2; 183 static const int kInterceptorArgsHolderIndex = 3; 184 static const int kInterceptorArgsLength = 4; 185 186 private: 187 explicit StubCache(Isolate* isolate); 188 189 // The stub cache has a primary and secondary level. The two levels have 190 // different hashing algorithms in order to avoid simultaneous collisions 191 // in both caches. Unlike a probing strategy (quadratic or otherwise) the 192 // update strategy on updates is fairly clear and simple: Any existing entry 193 // in the primary cache is moved to the secondary cache, and secondary cache 194 // entries are overwritten. 195 196 // Hash algorithm for the primary table. This algorithm is replicated in 197 // assembler for every architecture. Returns an index into the table that 198 // is scaled by 1 << kHeapObjectTagSize. 199 static int PrimaryOffset(Name* name, Code::Flags flags, Map* map) { 200 // This works well because the heap object tag size and the hash 201 // shift are equal. Shifting down the length field to get the 202 // hash code would effectively throw away two bits of the hash 203 // code. 204 STATIC_ASSERT(kHeapObjectTagSize == Name::kHashShift); 205 // Compute the hash of the name (use entire hash field). 206 ASSERT(name->HasHashCode()); 207 uint32_t field = name->hash_field(); 208 // Using only the low bits in 64-bit mode is unlikely to increase the 209 // risk of collision even if the heap is spread over an area larger than 210 // 4Gb (and not at all if it isn't). 211 uint32_t map_low32bits = 212 static_cast<uint32_t>(reinterpret_cast<uintptr_t>(map)); 213 // We always set the in_loop bit to zero when generating the lookup code 214 // so do it here too so the hash codes match. 215 uint32_t iflags = 216 (static_cast<uint32_t>(flags) & ~Code::kFlagsNotUsedInLookup); 217 // Base the offset on a simple combination of name, flags, and map. 218 uint32_t key = (map_low32bits + field) ^ iflags; 219 return key & ((kPrimaryTableSize - 1) << kHeapObjectTagSize); 220 } 221 222 // Hash algorithm for the secondary table. This algorithm is replicated in 223 // assembler for every architecture. Returns an index into the table that 224 // is scaled by 1 << kHeapObjectTagSize. 225 static int SecondaryOffset(Name* name, Code::Flags flags, int seed) { 226 // Use the seed from the primary cache in the secondary cache. 227 uint32_t name_low32bits = 228 static_cast<uint32_t>(reinterpret_cast<uintptr_t>(name)); 229 // We always set the in_loop bit to zero when generating the lookup code 230 // so do it here too so the hash codes match. 231 uint32_t iflags = 232 (static_cast<uint32_t>(flags) & ~Code::kFlagsNotUsedInLookup); 233 uint32_t key = (seed - name_low32bits) + iflags; 234 return key & ((kSecondaryTableSize - 1) << kHeapObjectTagSize); 235 } 236 237 // Compute the entry for a given offset in exactly the same way as 238 // we do in generated code. We generate an hash code that already 239 // ends in Name::kHashShift 0s. Then we multiply it so it is a multiple 240 // of sizeof(Entry). This makes it easier to avoid making mistakes 241 // in the hashed offset computations. 242 static Entry* entry(Entry* table, int offset) { 243 const int multiplier = sizeof(*table) >> Name::kHashShift; 244 return reinterpret_cast<Entry*>( 245 reinterpret_cast<Address>(table) + offset * multiplier); 246 } 247 248 static const int kPrimaryTableBits = 11; 249 static const int kPrimaryTableSize = (1 << kPrimaryTableBits); 250 static const int kSecondaryTableBits = 9; 251 static const int kSecondaryTableSize = (1 << kSecondaryTableBits); 252 253 Entry primary_[kPrimaryTableSize]; 254 Entry secondary_[kSecondaryTableSize]; 255 Isolate* isolate_; 256 257 friend class Isolate; 258 friend class SCTableReference; 259 260 DISALLOW_COPY_AND_ASSIGN(StubCache); 261 }; 262 263 264 // ------------------------------------------------------------------------ 265 266 267 // Support functions for IC stubs for callbacks. 268 DECLARE_RUNTIME_FUNCTION(StoreCallbackProperty); 269 270 271 // Support functions for IC stubs for interceptors. 272 DECLARE_RUNTIME_FUNCTION(LoadPropertyWithInterceptorOnly); 273 DECLARE_RUNTIME_FUNCTION(LoadPropertyWithInterceptor); 274 DECLARE_RUNTIME_FUNCTION(StoreInterceptorProperty); 275 DECLARE_RUNTIME_FUNCTION(KeyedLoadPropertyWithInterceptor); 276 277 278 enum PrototypeCheckType { CHECK_ALL_MAPS, SKIP_RECEIVER }; 279 enum IcCheckType { ELEMENT, PROPERTY }; 280 281 282 // The stub compilers compile stubs for the stub cache. 283 class StubCompiler BASE_EMBEDDED { 284 public: 285 explicit StubCompiler(Isolate* isolate, 286 ExtraICState extra_ic_state = kNoExtraICState) 287 : isolate_(isolate), extra_ic_state_(extra_ic_state), 288 masm_(isolate, NULL, 256) { } 289 290 Handle<Code> CompileLoadInitialize(Code::Flags flags); 291 Handle<Code> CompileLoadPreMonomorphic(Code::Flags flags); 292 Handle<Code> CompileLoadMegamorphic(Code::Flags flags); 293 294 Handle<Code> CompileStoreInitialize(Code::Flags flags); 295 Handle<Code> CompileStorePreMonomorphic(Code::Flags flags); 296 Handle<Code> CompileStoreGeneric(Code::Flags flags); 297 Handle<Code> CompileStoreMegamorphic(Code::Flags flags); 298 299 // Static functions for generating parts of stubs. 300 static void GenerateLoadGlobalFunctionPrototype(MacroAssembler* masm, 301 int index, 302 Register prototype); 303 304 // Helper function used to check that the dictionary doesn't contain 305 // the property. This function may return false negatives, so miss_label 306 // must always call a backup property check that is complete. 307 // This function is safe to call if the receiver has fast properties. 308 // Name must be unique and receiver must be a heap object. 309 static void GenerateDictionaryNegativeLookup(MacroAssembler* masm, 310 Label* miss_label, 311 Register receiver, 312 Handle<Name> name, 313 Register r0, 314 Register r1); 315 316 // Generates prototype loading code that uses the objects from the 317 // context we were in when this function was called. If the context 318 // has changed, a jump to miss is performed. This ties the generated 319 // code to a particular context and so must not be used in cases 320 // where the generated code is not allowed to have references to 321 // objects from a context. 322 static void GenerateDirectLoadGlobalFunctionPrototype(MacroAssembler* masm, 323 int index, 324 Register prototype, 325 Label* miss); 326 327 static void GenerateFastPropertyLoad(MacroAssembler* masm, 328 Register dst, 329 Register src, 330 bool inobject, 331 int index, 332 Representation representation); 333 334 static void GenerateLoadArrayLength(MacroAssembler* masm, 335 Register receiver, 336 Register scratch, 337 Label* miss_label); 338 339 static void GenerateLoadFunctionPrototype(MacroAssembler* masm, 340 Register receiver, 341 Register scratch1, 342 Register scratch2, 343 Label* miss_label); 344 345 // Generate code to check that a global property cell is empty. Create 346 // the property cell at compilation time if no cell exists for the 347 // property. 348 static void GenerateCheckPropertyCell(MacroAssembler* masm, 349 Handle<JSGlobalObject> global, 350 Handle<Name> name, 351 Register scratch, 352 Label* miss); 353 354 static void TailCallBuiltin(MacroAssembler* masm, Builtins::Name name); 355 356 // Generates code that verifies that the property holder has not changed 357 // (checking maps of objects in the prototype chain for fast and global 358 // objects or doing negative lookup for slow objects, ensures that the 359 // property cells for global objects are still empty) and checks that the map 360 // of the holder has not changed. If necessary the function also generates 361 // code for security check in case of global object holders. Helps to make 362 // sure that the current IC is still valid. 363 // 364 // The scratch and holder registers are always clobbered, but the object 365 // register is only clobbered if it the same as the holder register. The 366 // function returns a register containing the holder - either object_reg or 367 // holder_reg. 368 Register CheckPrototypes(Handle<HeapType> type, 369 Register object_reg, 370 Handle<JSObject> holder, 371 Register holder_reg, 372 Register scratch1, 373 Register scratch2, 374 Handle<Name> name, 375 Label* miss, 376 PrototypeCheckType check = CHECK_ALL_MAPS); 377 378 static void GenerateFastApiCall(MacroAssembler* masm, 379 const CallOptimization& optimization, 380 Handle<Map> receiver_map, 381 Register receiver, 382 Register scratch, 383 bool is_store, 384 int argc, 385 Register* values); 386 387 protected: 388 Handle<Code> GetCodeWithFlags(Code::Flags flags, const char* name); 389 Handle<Code> GetCodeWithFlags(Code::Flags flags, Handle<Name> name); 390 391 ExtraICState extra_state() { return extra_ic_state_; } 392 393 MacroAssembler* masm() { return &masm_; } 394 395 static void LookupPostInterceptor(Handle<JSObject> holder, 396 Handle<Name> name, 397 LookupResult* lookup); 398 399 Isolate* isolate() { return isolate_; } 400 Heap* heap() { return isolate()->heap(); } 401 Factory* factory() { return isolate()->factory(); } 402 403 static void GenerateTailCall(MacroAssembler* masm, Handle<Code> code); 404 405 private: 406 Isolate* isolate_; 407 const ExtraICState extra_ic_state_; 408 MacroAssembler masm_; 409 }; 410 411 412 enum FrontendCheckType { PERFORM_INITIAL_CHECKS, SKIP_INITIAL_CHECKS }; 413 414 415 class BaseLoadStoreStubCompiler: public StubCompiler { 416 public: 417 BaseLoadStoreStubCompiler(Isolate* isolate, 418 Code::Kind kind, 419 ExtraICState extra_ic_state = kNoExtraICState, 420 InlineCacheHolderFlag cache_holder = OWN_MAP) 421 : StubCompiler(isolate, extra_ic_state), 422 kind_(kind), 423 cache_holder_(cache_holder) { 424 InitializeRegisters(); 425 } 426 virtual ~BaseLoadStoreStubCompiler() { } 427 428 Handle<Code> CompileMonomorphicIC(Handle<HeapType> type, 429 Handle<Code> handler, 430 Handle<Name> name); 431 432 Handle<Code> CompilePolymorphicIC(TypeHandleList* types, 433 CodeHandleList* handlers, 434 Handle<Name> name, 435 Code::StubType type, 436 IcCheckType check); 437 438 static Builtins::Name MissBuiltin(Code::Kind kind) { 439 switch (kind) { 440 case Code::LOAD_IC: return Builtins::kLoadIC_Miss; 441 case Code::STORE_IC: return Builtins::kStoreIC_Miss; 442 case Code::KEYED_LOAD_IC: return Builtins::kKeyedLoadIC_Miss; 443 case Code::KEYED_STORE_IC: return Builtins::kKeyedStoreIC_Miss; 444 default: UNREACHABLE(); 445 } 446 return Builtins::kLoadIC_Miss; 447 } 448 449 protected: 450 virtual Register HandlerFrontendHeader(Handle<HeapType> type, 451 Register object_reg, 452 Handle<JSObject> holder, 453 Handle<Name> name, 454 Label* miss) = 0; 455 456 virtual void HandlerFrontendFooter(Handle<Name> name, Label* miss) = 0; 457 458 Register HandlerFrontend(Handle<HeapType> type, 459 Register object_reg, 460 Handle<JSObject> holder, 461 Handle<Name> name); 462 463 Handle<Code> GetCode(Code::Kind kind, 464 Code::StubType type, 465 Handle<Name> name); 466 467 Handle<Code> GetICCode(Code::Kind kind, 468 Code::StubType type, 469 Handle<Name> name, 470 InlineCacheState state = MONOMORPHIC); 471 Code::Kind kind() { return kind_; } 472 473 Logger::LogEventsAndTags log_kind(Handle<Code> code) { 474 if (!code->is_inline_cache_stub()) return Logger::STUB_TAG; 475 if (kind_ == Code::LOAD_IC) { 476 return code->ic_state() == MONOMORPHIC 477 ? Logger::LOAD_IC_TAG : Logger::LOAD_POLYMORPHIC_IC_TAG; 478 } else if (kind_ == Code::KEYED_LOAD_IC) { 479 return code->ic_state() == MONOMORPHIC 480 ? Logger::KEYED_LOAD_IC_TAG : Logger::KEYED_LOAD_POLYMORPHIC_IC_TAG; 481 } else if (kind_ == Code::STORE_IC) { 482 return code->ic_state() == MONOMORPHIC 483 ? Logger::STORE_IC_TAG : Logger::STORE_POLYMORPHIC_IC_TAG; 484 } else { 485 return code->ic_state() == MONOMORPHIC 486 ? Logger::KEYED_STORE_IC_TAG : Logger::KEYED_STORE_POLYMORPHIC_IC_TAG; 487 } 488 } 489 void JitEvent(Handle<Name> name, Handle<Code> code); 490 491 Register receiver() { return registers_[0]; } 492 Register name() { return registers_[1]; } 493 Register scratch1() { return registers_[2]; } 494 Register scratch2() { return registers_[3]; } 495 Register scratch3() { return registers_[4]; } 496 497 void InitializeRegisters(); 498 499 bool IncludesNumberType(TypeHandleList* types); 500 501 Code::Kind kind_; 502 InlineCacheHolderFlag cache_holder_; 503 Register* registers_; 504 }; 505 506 507 class LoadStubCompiler: public BaseLoadStoreStubCompiler { 508 public: 509 LoadStubCompiler(Isolate* isolate, 510 ExtraICState extra_ic_state = kNoExtraICState, 511 InlineCacheHolderFlag cache_holder = OWN_MAP, 512 Code::Kind kind = Code::LOAD_IC) 513 : BaseLoadStoreStubCompiler(isolate, kind, extra_ic_state, 514 cache_holder) { } 515 virtual ~LoadStubCompiler() { } 516 517 Handle<Code> CompileLoadField(Handle<HeapType> type, 518 Handle<JSObject> holder, 519 Handle<Name> name, 520 FieldIndex index, 521 Representation representation); 522 523 Handle<Code> CompileLoadCallback(Handle<HeapType> type, 524 Handle<JSObject> holder, 525 Handle<Name> name, 526 Handle<ExecutableAccessorInfo> callback); 527 528 Handle<Code> CompileLoadCallback(Handle<HeapType> type, 529 Handle<JSObject> holder, 530 Handle<Name> name, 531 const CallOptimization& call_optimization); 532 533 Handle<Code> CompileLoadConstant(Handle<HeapType> type, 534 Handle<JSObject> holder, 535 Handle<Name> name, 536 Handle<Object> value); 537 538 Handle<Code> CompileLoadInterceptor(Handle<HeapType> type, 539 Handle<JSObject> holder, 540 Handle<Name> name); 541 542 Handle<Code> CompileLoadViaGetter(Handle<HeapType> type, 543 Handle<JSObject> holder, 544 Handle<Name> name, 545 Handle<JSFunction> getter); 546 547 static void GenerateLoadViaGetter(MacroAssembler* masm, 548 Handle<HeapType> type, 549 Register receiver, 550 Handle<JSFunction> getter); 551 552 static void GenerateLoadViaGetterForDeopt(MacroAssembler* masm) { 553 GenerateLoadViaGetter( 554 masm, Handle<HeapType>::null(), no_reg, Handle<JSFunction>()); 555 } 556 557 Handle<Code> CompileLoadNonexistent(Handle<HeapType> type, 558 Handle<JSObject> last, 559 Handle<Name> name); 560 561 Handle<Code> CompileLoadGlobal(Handle<HeapType> type, 562 Handle<GlobalObject> holder, 563 Handle<PropertyCell> cell, 564 Handle<Name> name, 565 bool is_dont_delete); 566 567 protected: 568 ContextualMode contextual_mode() { 569 return LoadIC::GetContextualMode(extra_state()); 570 } 571 572 virtual Register HandlerFrontendHeader(Handle<HeapType> type, 573 Register object_reg, 574 Handle<JSObject> holder, 575 Handle<Name> name, 576 Label* miss); 577 578 virtual void HandlerFrontendFooter(Handle<Name> name, Label* miss); 579 580 Register CallbackHandlerFrontend(Handle<HeapType> type, 581 Register object_reg, 582 Handle<JSObject> holder, 583 Handle<Name> name, 584 Handle<Object> callback); 585 void NonexistentHandlerFrontend(Handle<HeapType> type, 586 Handle<JSObject> last, 587 Handle<Name> name); 588 589 void GenerateLoadField(Register reg, 590 Handle<JSObject> holder, 591 FieldIndex field, 592 Representation representation); 593 void GenerateLoadConstant(Handle<Object> value); 594 void GenerateLoadCallback(Register reg, 595 Handle<ExecutableAccessorInfo> callback); 596 void GenerateLoadCallback(const CallOptimization& call_optimization, 597 Handle<Map> receiver_map); 598 void GenerateLoadInterceptor(Register holder_reg, 599 Handle<Object> object, 600 Handle<JSObject> holder, 601 LookupResult* lookup, 602 Handle<Name> name); 603 void GenerateLoadPostInterceptor(Register reg, 604 Handle<JSObject> interceptor_holder, 605 Handle<Name> name, 606 LookupResult* lookup); 607 608 private: 609 static Register* registers(); 610 Register scratch4() { return registers_[5]; } 611 friend class BaseLoadStoreStubCompiler; 612 }; 613 614 615 class KeyedLoadStubCompiler: public LoadStubCompiler { 616 public: 617 KeyedLoadStubCompiler(Isolate* isolate, 618 ExtraICState extra_ic_state = kNoExtraICState, 619 InlineCacheHolderFlag cache_holder = OWN_MAP) 620 : LoadStubCompiler(isolate, extra_ic_state, cache_holder, 621 Code::KEYED_LOAD_IC) { } 622 623 Handle<Code> CompileLoadElement(Handle<Map> receiver_map); 624 625 void CompileElementHandlers(MapHandleList* receiver_maps, 626 CodeHandleList* handlers); 627 628 static void GenerateLoadDictionaryElement(MacroAssembler* masm); 629 630 private: 631 static Register* registers(); 632 friend class BaseLoadStoreStubCompiler; 633 }; 634 635 636 class StoreStubCompiler: public BaseLoadStoreStubCompiler { 637 public: 638 StoreStubCompiler(Isolate* isolate, 639 ExtraICState extra_ic_state, 640 Code::Kind kind = Code::STORE_IC) 641 : BaseLoadStoreStubCompiler(isolate, kind, extra_ic_state) {} 642 643 virtual ~StoreStubCompiler() { } 644 645 Handle<Code> CompileStoreTransition(Handle<JSObject> object, 646 LookupResult* lookup, 647 Handle<Map> transition, 648 Handle<Name> name); 649 650 Handle<Code> CompileStoreField(Handle<JSObject> object, 651 LookupResult* lookup, 652 Handle<Name> name); 653 654 Handle<Code> CompileStoreArrayLength(Handle<JSObject> object, 655 LookupResult* lookup, 656 Handle<Name> name); 657 658 void GenerateStoreArrayLength(); 659 660 void GenerateNegativeHolderLookup(MacroAssembler* masm, 661 Handle<JSObject> holder, 662 Register holder_reg, 663 Handle<Name> name, 664 Label* miss); 665 666 void GenerateStoreTransition(MacroAssembler* masm, 667 Handle<JSObject> object, 668 LookupResult* lookup, 669 Handle<Map> transition, 670 Handle<Name> name, 671 Register receiver_reg, 672 Register name_reg, 673 Register value_reg, 674 Register scratch1, 675 Register scratch2, 676 Register scratch3, 677 Label* miss_label, 678 Label* slow); 679 680 void GenerateStoreField(MacroAssembler* masm, 681 Handle<JSObject> object, 682 LookupResult* lookup, 683 Register receiver_reg, 684 Register name_reg, 685 Register value_reg, 686 Register scratch1, 687 Register scratch2, 688 Label* miss_label); 689 690 Handle<Code> CompileStoreCallback(Handle<JSObject> object, 691 Handle<JSObject> holder, 692 Handle<Name> name, 693 Handle<ExecutableAccessorInfo> callback); 694 695 Handle<Code> CompileStoreCallback(Handle<JSObject> object, 696 Handle<JSObject> holder, 697 Handle<Name> name, 698 const CallOptimization& call_optimization); 699 700 static void GenerateStoreViaSetter(MacroAssembler* masm, 701 Handle<HeapType> type, 702 Register receiver, 703 Handle<JSFunction> setter); 704 705 static void GenerateStoreViaSetterForDeopt(MacroAssembler* masm) { 706 GenerateStoreViaSetter( 707 masm, Handle<HeapType>::null(), no_reg, Handle<JSFunction>()); 708 } 709 710 Handle<Code> CompileStoreViaSetter(Handle<JSObject> object, 711 Handle<JSObject> holder, 712 Handle<Name> name, 713 Handle<JSFunction> setter); 714 715 Handle<Code> CompileStoreInterceptor(Handle<JSObject> object, 716 Handle<Name> name); 717 718 static Builtins::Name SlowBuiltin(Code::Kind kind) { 719 switch (kind) { 720 case Code::STORE_IC: return Builtins::kStoreIC_Slow; 721 case Code::KEYED_STORE_IC: return Builtins::kKeyedStoreIC_Slow; 722 default: UNREACHABLE(); 723 } 724 return Builtins::kStoreIC_Slow; 725 } 726 727 protected: 728 virtual Register HandlerFrontendHeader(Handle<HeapType> type, 729 Register object_reg, 730 Handle<JSObject> holder, 731 Handle<Name> name, 732 Label* miss); 733 734 virtual void HandlerFrontendFooter(Handle<Name> name, Label* miss); 735 void GenerateRestoreName(MacroAssembler* masm, 736 Label* label, 737 Handle<Name> name); 738 739 private: 740 static Register* registers(); 741 static Register value(); 742 friend class BaseLoadStoreStubCompiler; 743 }; 744 745 746 class KeyedStoreStubCompiler: public StoreStubCompiler { 747 public: 748 KeyedStoreStubCompiler(Isolate* isolate, 749 ExtraICState extra_ic_state) 750 : StoreStubCompiler(isolate, extra_ic_state, Code::KEYED_STORE_IC) {} 751 752 Handle<Code> CompileStoreElement(Handle<Map> receiver_map); 753 754 Handle<Code> CompileStorePolymorphic(MapHandleList* receiver_maps, 755 CodeHandleList* handler_stubs, 756 MapHandleList* transitioned_maps); 757 758 Handle<Code> CompileStoreElementPolymorphic(MapHandleList* receiver_maps); 759 760 static void GenerateStoreDictionaryElement(MacroAssembler* masm); 761 762 private: 763 static Register* registers(); 764 765 KeyedAccessStoreMode store_mode() { 766 return KeyedStoreIC::GetKeyedAccessStoreMode(extra_state()); 767 } 768 769 Register transition_map() { return scratch1(); } 770 771 friend class BaseLoadStoreStubCompiler; 772 }; 773 774 775 // Holds information about possible function call optimizations. 776 class CallOptimization BASE_EMBEDDED { 777 public: 778 explicit CallOptimization(LookupResult* lookup); 779 780 explicit CallOptimization(Handle<JSFunction> function); 781 782 bool is_constant_call() const { 783 return !constant_function_.is_null(); 784 } 785 786 Handle<JSFunction> constant_function() const { 787 ASSERT(is_constant_call()); 788 return constant_function_; 789 } 790 791 bool is_simple_api_call() const { 792 return is_simple_api_call_; 793 } 794 795 Handle<FunctionTemplateInfo> expected_receiver_type() const { 796 ASSERT(is_simple_api_call()); 797 return expected_receiver_type_; 798 } 799 800 Handle<CallHandlerInfo> api_call_info() const { 801 ASSERT(is_simple_api_call()); 802 return api_call_info_; 803 } 804 805 enum HolderLookup { 806 kHolderNotFound, 807 kHolderIsReceiver, 808 kHolderFound 809 }; 810 Handle<JSObject> LookupHolderOfExpectedType( 811 Handle<Map> receiver_map, 812 HolderLookup* holder_lookup) const; 813 814 // Check if the api holder is between the receiver and the holder. 815 bool IsCompatibleReceiver(Handle<Object> receiver, 816 Handle<JSObject> holder) const; 817 818 private: 819 void Initialize(Handle<JSFunction> function); 820 821 // Determines whether the given function can be called using the 822 // fast api call builtin. 823 void AnalyzePossibleApiFunction(Handle<JSFunction> function); 824 825 Handle<JSFunction> constant_function_; 826 bool is_simple_api_call_; 827 Handle<FunctionTemplateInfo> expected_receiver_type_; 828 Handle<CallHandlerInfo> api_call_info_; 829 }; 830 831 832 } } // namespace v8::internal 833 834 #endif // V8_STUB_CACHE_H_ 835