1 // Copyright 2012 the V8 project authors. All rights reserved. 2 // Redistribution and use in source and binary forms, with or without 3 // modification, are permitted provided that the following conditions are 4 // met: 5 // 6 // * Redistributions of source code must retain the above copyright 7 // notice, this list of conditions and the following disclaimer. 8 // * Redistributions in binary form must reproduce the above 9 // copyright notice, this list of conditions and the following 10 // disclaimer in the documentation and/or other materials provided 11 // with the distribution. 12 // * Neither the name of Google Inc. nor the names of its 13 // contributors may be used to endorse or promote products derived 14 // from this software without specific prior written permission. 15 // 16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 17 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 18 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 19 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 20 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 21 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 22 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 28 #ifndef V8_STUB_CACHE_H_ 29 #define V8_STUB_CACHE_H_ 30 31 #include "allocation.h" 32 #include "arguments.h" 33 #include "code-stubs.h" 34 #include "ic-inl.h" 35 #include "macro-assembler.h" 36 #include "objects.h" 37 #include "zone-inl.h" 38 39 namespace v8 { 40 namespace internal { 41 42 43 // The stub cache is used for megamorphic calls and property accesses. 44 // It maps (map, name, type)->Code* 45 46 // The design of the table uses the inline cache stubs used for 47 // mono-morphic calls. The beauty of this, we do not have to 48 // invalidate the cache whenever a prototype map is changed. The stub 49 // validates the map chain as in the mono-morphic case. 50 51 class SmallMapList; 52 class StubCache; 53 54 55 class SCTableReference { 56 public: 57 Address address() const { return address_; } 58 59 private: 60 explicit SCTableReference(Address address) : address_(address) {} 61 62 Address address_; 63 64 friend class StubCache; 65 }; 66 67 68 class StubCache { 69 public: 70 struct Entry { 71 Name* key; 72 Code* value; 73 Map* map; 74 }; 75 76 void Initialize(); 77 78 Handle<JSObject> StubHolder(Handle<JSObject> receiver, 79 Handle<JSObject> holder); 80 81 Handle<Code> FindIC(Handle<Name> name, 82 Handle<Map> stub_holder_map, 83 Code::Kind kind, 84 Code::StubType type, 85 Code::ExtraICState extra_state = Code::kNoExtraICState); 86 87 Handle<Code> FindIC(Handle<Name> name, 88 Handle<JSObject> stub_holder, 89 Code::Kind kind, 90 Code::StubType type, 91 Code::ExtraICState extra_state = Code::kNoExtraICState); 92 93 Handle<Code> FindLoadHandler(Handle<Name> name, 94 Handle<JSObject> receiver, 95 Handle<JSObject> stub_holder, 96 Code::Kind kind, 97 Code::StubType type); 98 99 Handle<Code> FindStoreHandler(Handle<Name> name, 100 Handle<JSObject> receiver, 101 Code::Kind kind, 102 Code::StubType type, 103 StrictModeFlag strict_mode); 104 105 Handle<Code> ComputeMonomorphicLoadIC(Handle<JSObject> receiver, 106 Handle<Code> handler, 107 Handle<Name> name); 108 109 Handle<Code> ComputeMonomorphicKeyedLoadIC(Handle<JSObject> receiver, 110 Handle<Code> handler, 111 Handle<Name> name); 112 113 Handle<Code> ComputeMonomorphicStoreIC(Handle<JSObject> receiver, 114 Handle<Code> handler, 115 Handle<Name> name, 116 StrictModeFlag strict_mode); 117 118 Handle<Code> ComputeMonomorphicKeyedStoreIC(Handle<JSObject> receiver, 119 Handle<Code> handler, 120 Handle<Name> name, 121 StrictModeFlag strict_mode); 122 123 // Computes the right stub matching. Inserts the result in the 124 // cache before returning. This might compile a stub if needed. 125 Handle<Code> ComputeLoadNonexistent(Handle<Name> name, 126 Handle<JSObject> object); 127 128 Handle<Code> ComputeLoadField(Handle<Name> name, 129 Handle<JSObject> object, 130 Handle<JSObject> holder, 131 PropertyIndex field_index, 132 Representation representation); 133 134 Handle<Code> ComputeLoadCallback(Handle<Name> name, 135 Handle<JSObject> object, 136 Handle<JSObject> holder, 137 Handle<ExecutableAccessorInfo> callback); 138 139 Handle<Code> ComputeLoadViaGetter(Handle<Name> name, 140 Handle<JSObject> object, 141 Handle<JSObject> holder, 142 Handle<JSFunction> getter); 143 144 Handle<Code> ComputeLoadConstant(Handle<Name> name, 145 Handle<JSObject> object, 146 Handle<JSObject> holder, 147 Handle<Object> value); 148 149 Handle<Code> ComputeLoadInterceptor(Handle<Name> name, 150 Handle<JSObject> object, 151 Handle<JSObject> holder); 152 153 Handle<Code> ComputeLoadNormal(Handle<Name> name, 154 Handle<JSObject> object); 155 156 Handle<Code> ComputeLoadGlobal(Handle<Name> name, 157 Handle<JSObject> object, 158 Handle<GlobalObject> holder, 159 Handle<PropertyCell> cell, 160 bool is_dont_delete); 161 162 // --- 163 164 Handle<Code> ComputeKeyedLoadField(Handle<Name> name, 165 Handle<JSObject> object, 166 Handle<JSObject> holder, 167 PropertyIndex field_index, 168 Representation representation); 169 170 Handle<Code> ComputeKeyedLoadCallback( 171 Handle<Name> name, 172 Handle<JSObject> object, 173 Handle<JSObject> holder, 174 Handle<ExecutableAccessorInfo> callback); 175 176 Handle<Code> ComputeKeyedLoadConstant(Handle<Name> name, 177 Handle<JSObject> object, 178 Handle<JSObject> holder, 179 Handle<Object> value); 180 181 Handle<Code> ComputeKeyedLoadInterceptor(Handle<Name> name, 182 Handle<JSObject> object, 183 Handle<JSObject> holder); 184 185 // --- 186 187 Handle<Code> ComputeStoreField(Handle<Name> name, 188 Handle<JSObject> object, 189 LookupResult* lookup, 190 StrictModeFlag strict_mode); 191 192 Handle<Code> ComputeStoreTransition(Handle<Name> name, 193 Handle<JSObject> object, 194 LookupResult* lookup, 195 Handle<Map> transition, 196 StrictModeFlag strict_mode); 197 198 Handle<Code> ComputeStoreNormal(StrictModeFlag strict_mode); 199 200 Handle<Code> ComputeStoreGlobal(Handle<Name> name, 201 Handle<GlobalObject> object, 202 Handle<PropertyCell> cell, 203 Handle<Object> value, 204 StrictModeFlag strict_mode); 205 206 Handle<Code> ComputeStoreCallback(Handle<Name> name, 207 Handle<JSObject> object, 208 Handle<JSObject> holder, 209 Handle<ExecutableAccessorInfo> callback, 210 StrictModeFlag strict_mode); 211 212 Handle<Code> ComputeStoreViaSetter(Handle<Name> name, 213 Handle<JSObject> object, 214 Handle<JSObject> holder, 215 Handle<JSFunction> setter, 216 StrictModeFlag strict_mode); 217 218 Handle<Code> ComputeStoreInterceptor(Handle<Name> name, 219 Handle<JSObject> object, 220 StrictModeFlag strict_mode); 221 222 // --- 223 224 Handle<Code> ComputeKeyedStoreField(Handle<Name> name, 225 Handle<JSObject> object, 226 LookupResult* lookup, 227 StrictModeFlag strict_mode); 228 Handle<Code> ComputeKeyedStoreTransition(Handle<Name> name, 229 Handle<JSObject> object, 230 LookupResult* lookup, 231 Handle<Map> transition, 232 StrictModeFlag strict_mode); 233 234 Handle<Code> ComputeKeyedLoadElement(Handle<Map> receiver_map); 235 236 Handle<Code> ComputeKeyedStoreElement(Handle<Map> receiver_map, 237 StrictModeFlag strict_mode, 238 KeyedAccessStoreMode store_mode); 239 240 // --- 241 242 Handle<Code> ComputeCallField(int argc, 243 Code::Kind, 244 Code::ExtraICState extra_state, 245 Handle<Name> name, 246 Handle<Object> object, 247 Handle<JSObject> holder, 248 PropertyIndex index); 249 250 Handle<Code> ComputeCallConstant(int argc, 251 Code::Kind, 252 Code::ExtraICState extra_state, 253 Handle<Name> name, 254 Handle<Object> object, 255 Handle<JSObject> holder, 256 Handle<JSFunction> function); 257 258 Handle<Code> ComputeCallInterceptor(int argc, 259 Code::Kind, 260 Code::ExtraICState extra_state, 261 Handle<Name> name, 262 Handle<Object> object, 263 Handle<JSObject> holder); 264 265 Handle<Code> ComputeCallGlobal(int argc, 266 Code::Kind, 267 Code::ExtraICState extra_state, 268 Handle<Name> name, 269 Handle<JSObject> object, 270 Handle<GlobalObject> holder, 271 Handle<PropertyCell> cell, 272 Handle<JSFunction> function); 273 274 // --- 275 276 Handle<Code> ComputeCallInitialize(int argc, RelocInfo::Mode mode); 277 278 Handle<Code> ComputeKeyedCallInitialize(int argc); 279 280 Handle<Code> ComputeCallPreMonomorphic(int argc, 281 Code::Kind kind, 282 Code::ExtraICState extra_state); 283 284 Handle<Code> ComputeCallNormal(int argc, 285 Code::Kind kind, 286 Code::ExtraICState state); 287 288 Handle<Code> ComputeCallArguments(int argc); 289 290 Handle<Code> ComputeCallMegamorphic(int argc, 291 Code::Kind kind, 292 Code::ExtraICState state); 293 294 Handle<Code> ComputeCallMiss(int argc, 295 Code::Kind kind, 296 Code::ExtraICState state); 297 298 // --- 299 300 Handle<Code> ComputeCompareNil(Handle<Map> receiver_map, 301 CompareNilICStub& stub); 302 303 // --- 304 305 Handle<Code> ComputeLoadElementPolymorphic(MapHandleList* receiver_maps); 306 Handle<Code> ComputeStoreElementPolymorphic(MapHandleList* receiver_maps, 307 KeyedAccessStoreMode store_mode, 308 StrictModeFlag strict_mode); 309 310 Handle<Code> ComputePolymorphicLoadIC(MapHandleList* receiver_maps, 311 CodeHandleList* handlers, 312 int number_of_valid_maps, 313 Handle<Name> name); 314 315 Handle<Code> ComputePolymorphicStoreIC(MapHandleList* receiver_maps, 316 CodeHandleList* handlers, 317 int number_of_valid_maps, 318 Handle<Name> name, 319 StrictModeFlag strict_mode); 320 321 // Finds the Code object stored in the Heap::non_monomorphic_cache(). 322 Code* FindCallInitialize(int argc, RelocInfo::Mode mode, Code::Kind kind); 323 324 #ifdef ENABLE_DEBUGGER_SUPPORT 325 Handle<Code> ComputeCallDebugBreak(int argc, Code::Kind kind); 326 327 Handle<Code> ComputeCallDebugPrepareStepIn(int argc, Code::Kind kind); 328 #endif 329 330 // Update cache for entry hash(name, map). 331 Code* Set(Name* name, Map* map, Code* code); 332 333 // Clear the lookup table (@ mark compact collection). 334 void Clear(); 335 336 // Collect all maps that match the name and flags. 337 void CollectMatchingMaps(SmallMapList* types, 338 Handle<Name> name, 339 Code::Flags flags, 340 Handle<Context> native_context, 341 Zone* zone); 342 343 // Generate code for probing the stub cache table. 344 // Arguments extra, extra2 and extra3 may be used to pass additional scratch 345 // registers. Set to no_reg if not needed. 346 void GenerateProbe(MacroAssembler* masm, 347 Code::Flags flags, 348 Register receiver, 349 Register name, 350 Register scratch, 351 Register extra, 352 Register extra2 = no_reg, 353 Register extra3 = no_reg); 354 355 enum Table { 356 kPrimary, 357 kSecondary 358 }; 359 360 361 SCTableReference key_reference(StubCache::Table table) { 362 return SCTableReference( 363 reinterpret_cast<Address>(&first_entry(table)->key)); 364 } 365 366 367 SCTableReference map_reference(StubCache::Table table) { 368 return SCTableReference( 369 reinterpret_cast<Address>(&first_entry(table)->map)); 370 } 371 372 373 SCTableReference value_reference(StubCache::Table table) { 374 return SCTableReference( 375 reinterpret_cast<Address>(&first_entry(table)->value)); 376 } 377 378 379 StubCache::Entry* first_entry(StubCache::Table table) { 380 switch (table) { 381 case StubCache::kPrimary: return StubCache::primary_; 382 case StubCache::kSecondary: return StubCache::secondary_; 383 } 384 UNREACHABLE(); 385 return NULL; 386 } 387 388 Isolate* isolate() { return isolate_; } 389 Heap* heap() { return isolate()->heap(); } 390 Factory* factory() { return isolate()->factory(); } 391 392 private: 393 explicit StubCache(Isolate* isolate); 394 395 Handle<Code> ComputeCallInitialize(int argc, 396 RelocInfo::Mode mode, 397 Code::Kind kind); 398 399 // The stub cache has a primary and secondary level. The two levels have 400 // different hashing algorithms in order to avoid simultaneous collisions 401 // in both caches. Unlike a probing strategy (quadratic or otherwise) the 402 // update strategy on updates is fairly clear and simple: Any existing entry 403 // in the primary cache is moved to the secondary cache, and secondary cache 404 // entries are overwritten. 405 406 // Hash algorithm for the primary table. This algorithm is replicated in 407 // assembler for every architecture. Returns an index into the table that 408 // is scaled by 1 << kHeapObjectTagSize. 409 static int PrimaryOffset(Name* name, Code::Flags flags, Map* map) { 410 // This works well because the heap object tag size and the hash 411 // shift are equal. Shifting down the length field to get the 412 // hash code would effectively throw away two bits of the hash 413 // code. 414 STATIC_ASSERT(kHeapObjectTagSize == Name::kHashShift); 415 // Compute the hash of the name (use entire hash field). 416 ASSERT(name->HasHashCode()); 417 uint32_t field = name->hash_field(); 418 // Using only the low bits in 64-bit mode is unlikely to increase the 419 // risk of collision even if the heap is spread over an area larger than 420 // 4Gb (and not at all if it isn't). 421 uint32_t map_low32bits = 422 static_cast<uint32_t>(reinterpret_cast<uintptr_t>(map)); 423 // We always set the in_loop bit to zero when generating the lookup code 424 // so do it here too so the hash codes match. 425 uint32_t iflags = 426 (static_cast<uint32_t>(flags) & ~Code::kFlagsNotUsedInLookup); 427 // Base the offset on a simple combination of name, flags, and map. 428 uint32_t key = (map_low32bits + field) ^ iflags; 429 return key & ((kPrimaryTableSize - 1) << kHeapObjectTagSize); 430 } 431 432 // Hash algorithm for the secondary table. This algorithm is replicated in 433 // assembler for every architecture. Returns an index into the table that 434 // is scaled by 1 << kHeapObjectTagSize. 435 static int SecondaryOffset(Name* name, Code::Flags flags, int seed) { 436 // Use the seed from the primary cache in the secondary cache. 437 uint32_t name_low32bits = 438 static_cast<uint32_t>(reinterpret_cast<uintptr_t>(name)); 439 // We always set the in_loop bit to zero when generating the lookup code 440 // so do it here too so the hash codes match. 441 uint32_t iflags = 442 (static_cast<uint32_t>(flags) & ~Code::kFlagsNotUsedInLookup); 443 uint32_t key = (seed - name_low32bits) + iflags; 444 return key & ((kSecondaryTableSize - 1) << kHeapObjectTagSize); 445 } 446 447 // Compute the entry for a given offset in exactly the same way as 448 // we do in generated code. We generate an hash code that already 449 // ends in Name::kHashShift 0s. Then we multiply it so it is a multiple 450 // of sizeof(Entry). This makes it easier to avoid making mistakes 451 // in the hashed offset computations. 452 static Entry* entry(Entry* table, int offset) { 453 const int multiplier = sizeof(*table) >> Name::kHashShift; 454 return reinterpret_cast<Entry*>( 455 reinterpret_cast<Address>(table) + offset * multiplier); 456 } 457 458 static const int kPrimaryTableBits = 11; 459 static const int kPrimaryTableSize = (1 << kPrimaryTableBits); 460 static const int kSecondaryTableBits = 9; 461 static const int kSecondaryTableSize = (1 << kSecondaryTableBits); 462 463 Entry primary_[kPrimaryTableSize]; 464 Entry secondary_[kSecondaryTableSize]; 465 Isolate* isolate_; 466 467 friend class Isolate; 468 friend class SCTableReference; 469 470 DISALLOW_COPY_AND_ASSIGN(StubCache); 471 }; 472 473 474 // ------------------------------------------------------------------------ 475 476 477 // Support functions for IC stubs for callbacks. 478 DECLARE_RUNTIME_FUNCTION(MaybeObject*, StoreCallbackProperty); 479 480 481 // Support functions for IC stubs for interceptors. 482 DECLARE_RUNTIME_FUNCTION(MaybeObject*, LoadPropertyWithInterceptorOnly); 483 DECLARE_RUNTIME_FUNCTION(MaybeObject*, LoadPropertyWithInterceptorForLoad); 484 DECLARE_RUNTIME_FUNCTION(MaybeObject*, LoadPropertyWithInterceptorForCall); 485 DECLARE_RUNTIME_FUNCTION(MaybeObject*, StoreInterceptorProperty); 486 DECLARE_RUNTIME_FUNCTION(MaybeObject*, CallInterceptorProperty); 487 DECLARE_RUNTIME_FUNCTION(MaybeObject*, KeyedLoadPropertyWithInterceptor); 488 489 490 enum PrototypeCheckType { CHECK_ALL_MAPS, SKIP_RECEIVER }; 491 enum IcCheckType { ELEMENT, PROPERTY }; 492 493 494 // The stub compilers compile stubs for the stub cache. 495 class StubCompiler BASE_EMBEDDED { 496 public: 497 explicit StubCompiler(Isolate* isolate) 498 : isolate_(isolate), masm_(isolate, NULL, 256), failure_(NULL) { } 499 500 // Functions to compile either CallIC or KeyedCallIC. The specific kind 501 // is extracted from the code flags. 502 Handle<Code> CompileCallInitialize(Code::Flags flags); 503 Handle<Code> CompileCallPreMonomorphic(Code::Flags flags); 504 Handle<Code> CompileCallNormal(Code::Flags flags); 505 Handle<Code> CompileCallMegamorphic(Code::Flags flags); 506 Handle<Code> CompileCallArguments(Code::Flags flags); 507 Handle<Code> CompileCallMiss(Code::Flags flags); 508 509 #ifdef ENABLE_DEBUGGER_SUPPORT 510 Handle<Code> CompileCallDebugBreak(Code::Flags flags); 511 Handle<Code> CompileCallDebugPrepareStepIn(Code::Flags flags); 512 #endif 513 514 // Static functions for generating parts of stubs. 515 static void GenerateLoadGlobalFunctionPrototype(MacroAssembler* masm, 516 int index, 517 Register prototype); 518 519 // Generates prototype loading code that uses the objects from the 520 // context we were in when this function was called. If the context 521 // has changed, a jump to miss is performed. This ties the generated 522 // code to a particular context and so must not be used in cases 523 // where the generated code is not allowed to have references to 524 // objects from a context. 525 static void GenerateDirectLoadGlobalFunctionPrototype(MacroAssembler* masm, 526 int index, 527 Register prototype, 528 Label* miss); 529 530 static void GenerateFastPropertyLoad(MacroAssembler* masm, 531 Register dst, 532 Register src, 533 bool inobject, 534 int index, 535 Representation representation); 536 537 static void GenerateLoadArrayLength(MacroAssembler* masm, 538 Register receiver, 539 Register scratch, 540 Label* miss_label); 541 542 static void GenerateLoadStringLength(MacroAssembler* masm, 543 Register receiver, 544 Register scratch1, 545 Register scratch2, 546 Label* miss_label, 547 bool support_wrappers); 548 549 static void GenerateLoadFunctionPrototype(MacroAssembler* masm, 550 Register receiver, 551 Register scratch1, 552 Register scratch2, 553 Label* miss_label); 554 555 static void TailCallBuiltin(MacroAssembler* masm, Builtins::Name name); 556 557 // Generates code that verifies that the property holder has not changed 558 // (checking maps of objects in the prototype chain for fast and global 559 // objects or doing negative lookup for slow objects, ensures that the 560 // property cells for global objects are still empty) and checks that the map 561 // of the holder has not changed. If necessary the function also generates 562 // code for security check in case of global object holders. Helps to make 563 // sure that the current IC is still valid. 564 // 565 // The scratch and holder registers are always clobbered, but the object 566 // register is only clobbered if it the same as the holder register. The 567 // function returns a register containing the holder - either object_reg or 568 // holder_reg. 569 // The function can optionally (when save_at_depth != 570 // kInvalidProtoDepth) save the object at the given depth by moving 571 // it to [esp + kPointerSize]. 572 Register CheckPrototypes(Handle<JSObject> object, 573 Register object_reg, 574 Handle<JSObject> holder, 575 Register holder_reg, 576 Register scratch1, 577 Register scratch2, 578 Handle<Name> name, 579 Label* miss, 580 PrototypeCheckType check = CHECK_ALL_MAPS) { 581 return CheckPrototypes(object, object_reg, holder, holder_reg, scratch1, 582 scratch2, name, kInvalidProtoDepth, miss, check); 583 } 584 585 Register CheckPrototypes(Handle<JSObject> object, 586 Register object_reg, 587 Handle<JSObject> holder, 588 Register holder_reg, 589 Register scratch1, 590 Register scratch2, 591 Handle<Name> name, 592 int save_at_depth, 593 Label* miss, 594 PrototypeCheckType check = CHECK_ALL_MAPS); 595 596 597 protected: 598 Handle<Code> GetCodeWithFlags(Code::Flags flags, const char* name); 599 Handle<Code> GetCodeWithFlags(Code::Flags flags, Handle<Name> name); 600 601 MacroAssembler* masm() { return &masm_; } 602 void set_failure(Failure* failure) { failure_ = failure; } 603 604 static void LookupPostInterceptor(Handle<JSObject> holder, 605 Handle<Name> name, 606 LookupResult* lookup); 607 608 Isolate* isolate() { return isolate_; } 609 Heap* heap() { return isolate()->heap(); } 610 Factory* factory() { return isolate()->factory(); } 611 612 static void GenerateTailCall(MacroAssembler* masm, Handle<Code> code); 613 614 private: 615 Isolate* isolate_; 616 MacroAssembler masm_; 617 Failure* failure_; 618 }; 619 620 621 enum FrontendCheckType { PERFORM_INITIAL_CHECKS, SKIP_INITIAL_CHECKS }; 622 623 624 class BaseLoadStoreStubCompiler: public StubCompiler { 625 public: 626 BaseLoadStoreStubCompiler(Isolate* isolate, Register* registers) 627 : StubCompiler(isolate), registers_(registers) { } 628 virtual ~BaseLoadStoreStubCompiler() { } 629 630 Handle<Code> CompileMonomorphicIC(Handle<Map> receiver_map, 631 Handle<Code> handler, 632 Handle<Name> name); 633 634 Handle<Code> CompilePolymorphicIC(MapHandleList* receiver_maps, 635 CodeHandleList* handlers, 636 Handle<Name> name, 637 Code::StubType type, 638 IcCheckType check); 639 640 virtual void GenerateNameCheck(Handle<Name> name, 641 Register name_reg, 642 Label* miss) { } 643 644 static Builtins::Name MissBuiltin(Code::Kind kind) { 645 switch (kind) { 646 case Code::LOAD_IC: return Builtins::kLoadIC_Miss; 647 case Code::STORE_IC: return Builtins::kStoreIC_Miss; 648 case Code::KEYED_LOAD_IC: return Builtins::kKeyedLoadIC_Miss; 649 case Code::KEYED_STORE_IC: return Builtins::kKeyedStoreIC_Miss; 650 default: UNREACHABLE(); 651 } 652 return Builtins::kLoadIC_Miss; 653 } 654 655 protected: 656 virtual Register HandlerFrontendHeader(Handle<JSObject> object, 657 Register object_reg, 658 Handle<JSObject> holder, 659 Handle<Name> name, 660 Label* miss) = 0; 661 662 virtual void HandlerFrontendFooter(Handle<Name> name, 663 Label* success, 664 Label* miss) = 0; 665 666 Register HandlerFrontend(Handle<JSObject> object, 667 Register object_reg, 668 Handle<JSObject> holder, 669 Handle<Name> name, 670 Label* success); 671 672 Handle<Code> GetICCode(Code::Kind kind, 673 Code::StubType type, 674 Handle<Name> name, 675 InlineCacheState state = MONOMORPHIC); 676 677 virtual Code::ExtraICState extra_state() { return Code::kNoExtraICState; } 678 virtual Logger::LogEventsAndTags log_kind(Handle<Code> code) = 0; 679 virtual void JitEvent(Handle<Name> name, Handle<Code> code) = 0; 680 virtual Code::Kind kind() = 0; 681 virtual Register receiver() = 0; 682 virtual Register name() = 0; 683 virtual Register scratch1() = 0; 684 virtual Register scratch2() = 0; 685 virtual Register scratch3() = 0; 686 687 Register* registers_; 688 }; 689 690 691 class BaseLoadStubCompiler: public BaseLoadStoreStubCompiler { 692 public: 693 BaseLoadStubCompiler(Isolate* isolate, Register* registers) 694 : BaseLoadStoreStubCompiler(isolate, registers) { } 695 virtual ~BaseLoadStubCompiler() { } 696 697 Handle<Code> CompileLoadField(Handle<JSObject> object, 698 Handle<JSObject> holder, 699 Handle<Name> name, 700 PropertyIndex index, 701 Representation representation); 702 703 Handle<Code> CompileLoadCallback(Handle<JSObject> object, 704 Handle<JSObject> holder, 705 Handle<Name> name, 706 Handle<ExecutableAccessorInfo> callback); 707 708 Handle<Code> CompileLoadConstant(Handle<JSObject> object, 709 Handle<JSObject> holder, 710 Handle<Name> name, 711 Handle<Object> value); 712 713 Handle<Code> CompileLoadInterceptor(Handle<JSObject> object, 714 Handle<JSObject> holder, 715 Handle<Name> name); 716 717 protected: 718 virtual Register HandlerFrontendHeader(Handle<JSObject> object, 719 Register object_reg, 720 Handle<JSObject> holder, 721 Handle<Name> name, 722 Label* miss); 723 724 virtual void HandlerFrontendFooter(Handle<Name> name, 725 Label* success, 726 Label* miss); 727 728 Register CallbackHandlerFrontend(Handle<JSObject> object, 729 Register object_reg, 730 Handle<JSObject> holder, 731 Handle<Name> name, 732 Label* success, 733 Handle<ExecutableAccessorInfo> callback); 734 void NonexistentHandlerFrontend(Handle<JSObject> object, 735 Handle<JSObject> last, 736 Handle<Name> name, 737 Label* success, 738 Handle<GlobalObject> global); 739 740 void GenerateLoadField(Register reg, 741 Handle<JSObject> holder, 742 PropertyIndex field, 743 Representation representation); 744 void GenerateLoadConstant(Handle<Object> value); 745 void GenerateLoadCallback(Register reg, 746 Handle<ExecutableAccessorInfo> callback); 747 void GenerateLoadInterceptor(Register holder_reg, 748 Handle<JSObject> object, 749 Handle<JSObject> holder, 750 LookupResult* lookup, 751 Handle<Name> name); 752 void GenerateLoadPostInterceptor(Register reg, 753 Handle<JSObject> interceptor_holder, 754 Handle<Name> name, 755 LookupResult* lookup); 756 757 Handle<Code> GetCode(Code::Kind kind, 758 Code::StubType type, 759 Handle<Name> name); 760 761 virtual Register receiver() { return registers_[0]; } 762 virtual Register name() { return registers_[1]; } 763 virtual Register scratch1() { return registers_[2]; } 764 virtual Register scratch2() { return registers_[3]; } 765 virtual Register scratch3() { return registers_[4]; } 766 Register scratch4() { return registers_[5]; } 767 }; 768 769 770 class LoadStubCompiler: public BaseLoadStubCompiler { 771 public: 772 explicit LoadStubCompiler(Isolate* isolate) 773 : BaseLoadStubCompiler(isolate, registers()) { } 774 775 Handle<Code> CompileLoadNonexistent(Handle<JSObject> object, 776 Handle<JSObject> last, 777 Handle<Name> name, 778 Handle<GlobalObject> global); 779 780 static void GenerateLoadViaGetter(MacroAssembler* masm, 781 Handle<JSFunction> getter); 782 783 Handle<Code> CompileLoadViaGetter(Handle<JSObject> object, 784 Handle<JSObject> holder, 785 Handle<Name> name, 786 Handle<JSFunction> getter); 787 788 Handle<Code> CompileLoadGlobal(Handle<JSObject> object, 789 Handle<GlobalObject> holder, 790 Handle<PropertyCell> cell, 791 Handle<Name> name, 792 bool is_dont_delete); 793 794 private: 795 static Register* registers(); 796 virtual Code::Kind kind() { return Code::LOAD_IC; } 797 virtual Logger::LogEventsAndTags log_kind(Handle<Code> code) { 798 if (!code->is_inline_cache_stub()) return Logger::STUB_TAG; 799 return code->ic_state() == MONOMORPHIC 800 ? Logger::LOAD_IC_TAG : Logger::LOAD_POLYMORPHIC_IC_TAG; 801 } 802 virtual void JitEvent(Handle<Name> name, Handle<Code> code); 803 }; 804 805 806 class KeyedLoadStubCompiler: public BaseLoadStubCompiler { 807 public: 808 explicit KeyedLoadStubCompiler(Isolate* isolate) 809 : BaseLoadStubCompiler(isolate, registers()) { } 810 811 Handle<Code> CompileLoadElement(Handle<Map> receiver_map); 812 813 void CompileElementHandlers(MapHandleList* receiver_maps, 814 CodeHandleList* handlers); 815 816 static void GenerateLoadDictionaryElement(MacroAssembler* masm); 817 818 private: 819 static Register* registers(); 820 virtual Code::Kind kind() { return Code::KEYED_LOAD_IC; } 821 virtual Logger::LogEventsAndTags log_kind(Handle<Code> code) { 822 if (!code->is_inline_cache_stub()) return Logger::STUB_TAG; 823 return code->ic_state() == MONOMORPHIC 824 ? Logger::KEYED_LOAD_IC_TAG : Logger::KEYED_LOAD_POLYMORPHIC_IC_TAG; 825 } 826 virtual void JitEvent(Handle<Name> name, Handle<Code> code); 827 virtual void GenerateNameCheck(Handle<Name> name, 828 Register name_reg, 829 Label* miss); 830 }; 831 832 833 class BaseStoreStubCompiler: public BaseLoadStoreStubCompiler { 834 public: 835 BaseStoreStubCompiler(Isolate* isolate, 836 StrictModeFlag strict_mode, 837 Register* registers) 838 : BaseLoadStoreStubCompiler(isolate, registers), 839 strict_mode_(strict_mode) { } 840 841 virtual ~BaseStoreStubCompiler() { } 842 843 Handle<Code> CompileStoreTransition(Handle<JSObject> object, 844 LookupResult* lookup, 845 Handle<Map> transition, 846 Handle<Name> name); 847 848 Handle<Code> CompileStoreField(Handle<JSObject> object, 849 LookupResult* lookup, 850 Handle<Name> name); 851 852 void GenerateNegativeHolderLookup(MacroAssembler* masm, 853 Handle<JSObject> holder, 854 Register holder_reg, 855 Handle<Name> name, 856 Label* miss); 857 858 void GenerateStoreTransition(MacroAssembler* masm, 859 Handle<JSObject> object, 860 LookupResult* lookup, 861 Handle<Map> transition, 862 Handle<Name> name, 863 Register receiver_reg, 864 Register name_reg, 865 Register value_reg, 866 Register scratch1, 867 Register scratch2, 868 Register scratch3, 869 Label* miss_label, 870 Label* slow); 871 872 void GenerateStoreField(MacroAssembler* masm, 873 Handle<JSObject> object, 874 LookupResult* lookup, 875 Register receiver_reg, 876 Register name_reg, 877 Register value_reg, 878 Register scratch1, 879 Register scratch2, 880 Label* miss_label); 881 882 static Builtins::Name MissBuiltin(Code::Kind kind) { 883 switch (kind) { 884 case Code::LOAD_IC: return Builtins::kLoadIC_Miss; 885 case Code::STORE_IC: return Builtins::kStoreIC_Miss; 886 case Code::KEYED_LOAD_IC: return Builtins::kKeyedLoadIC_Miss; 887 case Code::KEYED_STORE_IC: return Builtins::kKeyedStoreIC_Miss; 888 default: UNREACHABLE(); 889 } 890 return Builtins::kLoadIC_Miss; 891 } 892 static Builtins::Name SlowBuiltin(Code::Kind kind) { 893 switch (kind) { 894 case Code::STORE_IC: return Builtins::kStoreIC_Slow; 895 case Code::KEYED_STORE_IC: return Builtins::kKeyedStoreIC_Slow; 896 default: UNREACHABLE(); 897 } 898 return Builtins::kStoreIC_Slow; 899 } 900 901 protected: 902 virtual Register HandlerFrontendHeader(Handle<JSObject> object, 903 Register object_reg, 904 Handle<JSObject> holder, 905 Handle<Name> name, 906 Label* miss); 907 908 virtual void HandlerFrontendFooter(Handle<Name> name, 909 Label* success, 910 Label* miss); 911 Handle<Code> GetCode(Code::Kind kind, 912 Code::StubType type, 913 Handle<Name> name); 914 915 void GenerateRestoreName(MacroAssembler* masm, 916 Label* label, 917 Handle<Name> name); 918 919 virtual Register receiver() { return registers_[0]; } 920 virtual Register name() { return registers_[1]; } 921 Register value() { return registers_[2]; } 922 virtual Register scratch1() { return registers_[3]; } 923 virtual Register scratch2() { return registers_[4]; } 924 virtual Register scratch3() { return registers_[5]; } 925 StrictModeFlag strict_mode() { return strict_mode_; } 926 virtual Code::ExtraICState extra_state() { return strict_mode_; } 927 928 private: 929 StrictModeFlag strict_mode_; 930 }; 931 932 933 class StoreStubCompiler: public BaseStoreStubCompiler { 934 public: 935 StoreStubCompiler(Isolate* isolate, StrictModeFlag strict_mode) 936 : BaseStoreStubCompiler(isolate, strict_mode, registers()) { } 937 938 939 Handle<Code> CompileStoreCallback(Handle<JSObject> object, 940 Handle<JSObject> holder, 941 Handle<Name> name, 942 Handle<ExecutableAccessorInfo> callback); 943 944 static void GenerateStoreViaSetter(MacroAssembler* masm, 945 Handle<JSFunction> setter); 946 947 Handle<Code> CompileStoreViaSetter(Handle<JSObject> object, 948 Handle<JSObject> holder, 949 Handle<Name> name, 950 Handle<JSFunction> setter); 951 952 Handle<Code> CompileStoreInterceptor(Handle<JSObject> object, 953 Handle<Name> name); 954 955 Handle<Code> CompileStoreGlobal(Handle<GlobalObject> object, 956 Handle<PropertyCell> holder, 957 Handle<Name> name); 958 959 private: 960 static Register* registers(); 961 virtual Code::Kind kind() { return Code::STORE_IC; } 962 virtual Logger::LogEventsAndTags log_kind(Handle<Code> code) { 963 if (!code->is_inline_cache_stub()) return Logger::STUB_TAG; 964 return code->ic_state() == MONOMORPHIC 965 ? Logger::STORE_IC_TAG : Logger::STORE_POLYMORPHIC_IC_TAG; 966 } 967 virtual void JitEvent(Handle<Name> name, Handle<Code> code); 968 }; 969 970 971 class KeyedStoreStubCompiler: public BaseStoreStubCompiler { 972 public: 973 KeyedStoreStubCompiler(Isolate* isolate, 974 StrictModeFlag strict_mode, 975 KeyedAccessStoreMode store_mode) 976 : BaseStoreStubCompiler(isolate, strict_mode, registers()), 977 store_mode_(store_mode) { } 978 979 Handle<Code> CompileStoreElement(Handle<Map> receiver_map); 980 981 Handle<Code> CompileStorePolymorphic(MapHandleList* receiver_maps, 982 CodeHandleList* handler_stubs, 983 MapHandleList* transitioned_maps); 984 985 Handle<Code> CompileStoreElementPolymorphic(MapHandleList* receiver_maps); 986 987 static void GenerateStoreFastElement(MacroAssembler* masm, 988 bool is_js_array, 989 ElementsKind element_kind, 990 KeyedAccessStoreMode store_mode); 991 992 static void GenerateStoreFastDoubleElement(MacroAssembler* masm, 993 bool is_js_array, 994 KeyedAccessStoreMode store_mode); 995 996 static void GenerateStoreExternalArray(MacroAssembler* masm, 997 ElementsKind elements_kind); 998 999 static void GenerateStoreDictionaryElement(MacroAssembler* masm); 1000 1001 protected: 1002 virtual Code::ExtraICState extra_state() { 1003 return Code::ComputeExtraICState(store_mode_, strict_mode()); 1004 } 1005 1006 private: 1007 Register transition_map() { 1008 return registers()[3]; 1009 } 1010 1011 static Register* registers(); 1012 virtual Code::Kind kind() { return Code::KEYED_STORE_IC; } 1013 virtual Logger::LogEventsAndTags log_kind(Handle<Code> code) { 1014 if (!code->is_inline_cache_stub()) return Logger::STUB_TAG; 1015 return code->ic_state() == MONOMORPHIC 1016 ? Logger::KEYED_STORE_IC_TAG : Logger::KEYED_STORE_POLYMORPHIC_IC_TAG; 1017 } 1018 virtual void JitEvent(Handle<Name> name, Handle<Code> code); 1019 virtual void GenerateNameCheck(Handle<Name> name, 1020 Register name_reg, 1021 Label* miss); 1022 KeyedAccessStoreMode store_mode_; 1023 }; 1024 1025 1026 // Subset of FUNCTIONS_WITH_ID_LIST with custom constant/global call 1027 // IC stubs. 1028 #define CUSTOM_CALL_IC_GENERATORS(V) \ 1029 V(ArrayPush) \ 1030 V(ArrayPop) \ 1031 V(StringCharCodeAt) \ 1032 V(StringCharAt) \ 1033 V(StringFromCharCode) \ 1034 V(MathFloor) \ 1035 V(MathAbs) \ 1036 V(ArrayCode) 1037 1038 1039 #define SITE_SPECIFIC_CALL_GENERATORS(V) \ 1040 V(ArrayCode) 1041 1042 1043 class CallOptimization; 1044 1045 class CallStubCompiler: public StubCompiler { 1046 public: 1047 CallStubCompiler(Isolate* isolate, 1048 int argc, 1049 Code::Kind kind, 1050 Code::ExtraICState extra_state, 1051 InlineCacheHolderFlag cache_holder); 1052 1053 Handle<Code> CompileCallField(Handle<JSObject> object, 1054 Handle<JSObject> holder, 1055 PropertyIndex index, 1056 Handle<Name> name); 1057 1058 void CompileHandlerFrontend(Handle<Object> object, 1059 Handle<JSObject> holder, 1060 Handle<Name> name, 1061 CheckType check, 1062 Label* success); 1063 1064 void CompileHandlerBackend(Handle<JSFunction> function); 1065 1066 Handle<Code> CompileCallConstant(Handle<Object> object, 1067 Handle<JSObject> holder, 1068 Handle<Name> name, 1069 CheckType check, 1070 Handle<JSFunction> function); 1071 1072 Handle<Code> CompileCallInterceptor(Handle<JSObject> object, 1073 Handle<JSObject> holder, 1074 Handle<Name> name); 1075 1076 Handle<Code> CompileCallGlobal(Handle<JSObject> object, 1077 Handle<GlobalObject> holder, 1078 Handle<PropertyCell> cell, 1079 Handle<JSFunction> function, 1080 Handle<Name> name); 1081 1082 static bool HasCustomCallGenerator(Handle<JSFunction> function); 1083 static bool CanBeCached(Handle<JSFunction> function); 1084 1085 private: 1086 // Compiles a custom call constant/global IC. For constant calls cell is 1087 // NULL. Returns an empty handle if there is no custom call code for the 1088 // given function. 1089 Handle<Code> CompileCustomCall(Handle<Object> object, 1090 Handle<JSObject> holder, 1091 Handle<Cell> cell, 1092 Handle<JSFunction> function, 1093 Handle<String> name, 1094 Code::StubType type); 1095 1096 #define DECLARE_CALL_GENERATOR(name) \ 1097 Handle<Code> Compile##name##Call(Handle<Object> object, \ 1098 Handle<JSObject> holder, \ 1099 Handle<Cell> cell, \ 1100 Handle<JSFunction> function, \ 1101 Handle<String> fname, \ 1102 Code::StubType type); 1103 CUSTOM_CALL_IC_GENERATORS(DECLARE_CALL_GENERATOR) 1104 #undef DECLARE_CALL_GENERATOR 1105 1106 Handle<Code> CompileFastApiCall(const CallOptimization& optimization, 1107 Handle<Object> object, 1108 Handle<JSObject> holder, 1109 Handle<Cell> cell, 1110 Handle<JSFunction> function, 1111 Handle<String> name); 1112 1113 Handle<Code> GetCode(Code::StubType type, Handle<Name> name); 1114 Handle<Code> GetCode(Handle<JSFunction> function); 1115 1116 const ParameterCount& arguments() { return arguments_; } 1117 1118 void GenerateNameCheck(Handle<Name> name, Label* miss); 1119 1120 void GenerateGlobalReceiverCheck(Handle<JSObject> object, 1121 Handle<JSObject> holder, 1122 Handle<Name> name, 1123 Label* miss); 1124 1125 // Generates code to load the function from the cell checking that 1126 // it still contains the same function. 1127 void GenerateLoadFunctionFromCell(Handle<Cell> cell, 1128 Handle<JSFunction> function, 1129 Label* miss); 1130 1131 // Generates a jump to CallIC miss stub. 1132 void GenerateMissBranch(); 1133 1134 const ParameterCount arguments_; 1135 const Code::Kind kind_; 1136 const Code::ExtraICState extra_state_; 1137 const InlineCacheHolderFlag cache_holder_; 1138 }; 1139 1140 1141 // Holds information about possible function call optimizations. 1142 class CallOptimization BASE_EMBEDDED { 1143 public: 1144 explicit CallOptimization(LookupResult* lookup); 1145 1146 explicit CallOptimization(Handle<JSFunction> function); 1147 1148 bool is_constant_call() const { 1149 return !constant_function_.is_null(); 1150 } 1151 1152 Handle<JSFunction> constant_function() const { 1153 ASSERT(is_constant_call()); 1154 return constant_function_; 1155 } 1156 1157 bool is_simple_api_call() const { 1158 return is_simple_api_call_; 1159 } 1160 1161 Handle<FunctionTemplateInfo> expected_receiver_type() const { 1162 ASSERT(is_simple_api_call()); 1163 return expected_receiver_type_; 1164 } 1165 1166 Handle<CallHandlerInfo> api_call_info() const { 1167 ASSERT(is_simple_api_call()); 1168 return api_call_info_; 1169 } 1170 1171 // Returns the depth of the object having the expected type in the 1172 // prototype chain between the two arguments. 1173 int GetPrototypeDepthOfExpectedType(Handle<JSObject> object, 1174 Handle<JSObject> holder) const; 1175 1176 private: 1177 void Initialize(Handle<JSFunction> function); 1178 1179 // Determines whether the given function can be called using the 1180 // fast api call builtin. 1181 void AnalyzePossibleApiFunction(Handle<JSFunction> function); 1182 1183 Handle<JSFunction> constant_function_; 1184 bool is_simple_api_call_; 1185 Handle<FunctionTemplateInfo> expected_receiver_type_; 1186 Handle<CallHandlerInfo> api_call_info_; 1187 }; 1188 1189 1190 } } // namespace v8::internal 1191 1192 #endif // V8_STUB_CACHE_H_ 1193