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 52 class CallOptimization; 53 class SmallMapList; 54 class StubCache; 55 56 57 class SCTableReference { 58 public: 59 Address address() const { return address_; } 60 61 private: 62 explicit SCTableReference(Address address) : address_(address) {} 63 64 Address address_; 65 66 friend class StubCache; 67 }; 68 69 70 class StubCache { 71 public: 72 struct Entry { 73 Name* key; 74 Code* value; 75 Map* map; 76 }; 77 78 void Initialize(); 79 80 Handle<JSObject> StubHolder(Handle<JSObject> receiver, 81 Handle<JSObject> holder); 82 83 Handle<Code> FindIC(Handle<Name> name, 84 Handle<Map> stub_holder_map, 85 Code::Kind kind, 86 ExtraICState extra_state = kNoExtraICState, 87 InlineCacheHolderFlag cache_holder = OWN_MAP); 88 89 Handle<Code> FindHandler(Handle<Name> name, 90 Handle<Map> map, 91 Code::Kind kind, 92 InlineCacheHolderFlag cache_holder = OWN_MAP); 93 94 Handle<Code> ComputeMonomorphicIC(Handle<Name> name, 95 Handle<Type> type, 96 Handle<Code> handler, 97 ExtraICState extra_ic_state); 98 99 Handle<Code> ComputeLoadNonexistent(Handle<Name> name, Handle<Type> type); 100 101 Handle<Code> ComputeKeyedLoadElement(Handle<Map> receiver_map); 102 103 Handle<Code> ComputeKeyedStoreElement(Handle<Map> receiver_map, 104 StrictModeFlag strict_mode, 105 KeyedAccessStoreMode store_mode); 106 107 Handle<Code> ComputeCallField(int argc, 108 Code::Kind, 109 ExtraICState extra_state, 110 Handle<Name> name, 111 Handle<Object> object, 112 Handle<JSObject> holder, 113 PropertyIndex index); 114 115 Handle<Code> ComputeCallConstant(int argc, 116 Code::Kind, 117 ExtraICState extra_state, 118 Handle<Name> name, 119 Handle<Object> object, 120 Handle<JSObject> holder, 121 Handle<JSFunction> function); 122 123 Handle<Code> ComputeCallInterceptor(int argc, 124 Code::Kind, 125 ExtraICState extra_state, 126 Handle<Name> name, 127 Handle<Object> object, 128 Handle<JSObject> holder); 129 130 Handle<Code> ComputeCallGlobal(int argc, 131 Code::Kind, 132 ExtraICState extra_state, 133 Handle<Name> name, 134 Handle<JSObject> object, 135 Handle<GlobalObject> holder, 136 Handle<PropertyCell> cell, 137 Handle<JSFunction> function); 138 139 // --- 140 141 Handle<Code> ComputeCallInitialize(int argc, RelocInfo::Mode mode); 142 143 Handle<Code> ComputeKeyedCallInitialize(int argc); 144 145 Handle<Code> ComputeCallPreMonomorphic(int argc, 146 Code::Kind kind, 147 ExtraICState extra_state); 148 149 Handle<Code> ComputeCallNormal(int argc, 150 Code::Kind kind, 151 ExtraICState state); 152 153 Handle<Code> ComputeCallArguments(int argc); 154 155 Handle<Code> ComputeCallMegamorphic(int argc, 156 Code::Kind kind, 157 ExtraICState state); 158 159 Handle<Code> ComputeCallMiss(int argc, 160 Code::Kind kind, 161 ExtraICState state); 162 163 // --- 164 165 Handle<Code> ComputeCompareNil(Handle<Map> receiver_map, 166 CompareNilICStub& stub); 167 168 // --- 169 170 Handle<Code> ComputeLoadElementPolymorphic(MapHandleList* receiver_maps); 171 Handle<Code> ComputeStoreElementPolymorphic(MapHandleList* receiver_maps, 172 KeyedAccessStoreMode store_mode, 173 StrictModeFlag strict_mode); 174 175 Handle<Code> ComputePolymorphicIC(TypeHandleList* types, 176 CodeHandleList* handlers, 177 int number_of_valid_maps, 178 Handle<Name> name, 179 ExtraICState extra_ic_state); 180 181 // Finds the Code object stored in the Heap::non_monomorphic_cache(). 182 Code* FindCallInitialize(int argc, RelocInfo::Mode mode, Code::Kind kind); 183 184 #ifdef ENABLE_DEBUGGER_SUPPORT 185 Handle<Code> ComputeCallDebugBreak(int argc, Code::Kind kind); 186 187 Handle<Code> ComputeCallDebugPrepareStepIn(int argc, Code::Kind kind); 188 #endif 189 190 // Update cache for entry hash(name, map). 191 Code* Set(Name* name, Map* map, Code* code); 192 193 // Clear the lookup table (@ mark compact collection). 194 void Clear(); 195 196 // Collect all maps that match the name and flags. 197 void CollectMatchingMaps(SmallMapList* types, 198 Handle<Name> name, 199 Code::Flags flags, 200 Handle<Context> native_context, 201 Zone* zone); 202 203 // Generate code for probing the stub cache table. 204 // Arguments extra, extra2 and extra3 may be used to pass additional scratch 205 // registers. Set to no_reg if not needed. 206 void GenerateProbe(MacroAssembler* masm, 207 Code::Flags flags, 208 Register receiver, 209 Register name, 210 Register scratch, 211 Register extra, 212 Register extra2 = no_reg, 213 Register extra3 = no_reg); 214 215 enum Table { 216 kPrimary, 217 kSecondary 218 }; 219 220 221 SCTableReference key_reference(StubCache::Table table) { 222 return SCTableReference( 223 reinterpret_cast<Address>(&first_entry(table)->key)); 224 } 225 226 227 SCTableReference map_reference(StubCache::Table table) { 228 return SCTableReference( 229 reinterpret_cast<Address>(&first_entry(table)->map)); 230 } 231 232 233 SCTableReference value_reference(StubCache::Table table) { 234 return SCTableReference( 235 reinterpret_cast<Address>(&first_entry(table)->value)); 236 } 237 238 239 StubCache::Entry* first_entry(StubCache::Table table) { 240 switch (table) { 241 case StubCache::kPrimary: return StubCache::primary_; 242 case StubCache::kSecondary: return StubCache::secondary_; 243 } 244 UNREACHABLE(); 245 return NULL; 246 } 247 248 Isolate* isolate() { return isolate_; } 249 Heap* heap() { return isolate()->heap(); } 250 Factory* factory() { return isolate()->factory(); } 251 252 // These constants describe the structure of the interceptor arguments on the 253 // stack. The arguments are pushed by the (platform-specific) 254 // PushInterceptorArguments and read by LoadPropertyWithInterceptorOnly and 255 // LoadWithInterceptor. 256 static const int kInterceptorArgsNameIndex = 0; 257 static const int kInterceptorArgsInfoIndex = 1; 258 static const int kInterceptorArgsThisIndex = 2; 259 static const int kInterceptorArgsHolderIndex = 3; 260 static const int kInterceptorArgsLength = 4; 261 262 private: 263 explicit StubCache(Isolate* isolate); 264 265 Handle<Code> ComputeCallInitialize(int argc, 266 RelocInfo::Mode mode, 267 Code::Kind kind); 268 269 // The stub cache has a primary and secondary level. The two levels have 270 // different hashing algorithms in order to avoid simultaneous collisions 271 // in both caches. Unlike a probing strategy (quadratic or otherwise) the 272 // update strategy on updates is fairly clear and simple: Any existing entry 273 // in the primary cache is moved to the secondary cache, and secondary cache 274 // entries are overwritten. 275 276 // Hash algorithm for the primary table. This algorithm is replicated in 277 // assembler for every architecture. Returns an index into the table that 278 // is scaled by 1 << kHeapObjectTagSize. 279 static int PrimaryOffset(Name* name, Code::Flags flags, Map* map) { 280 // This works well because the heap object tag size and the hash 281 // shift are equal. Shifting down the length field to get the 282 // hash code would effectively throw away two bits of the hash 283 // code. 284 STATIC_ASSERT(kHeapObjectTagSize == Name::kHashShift); 285 // Compute the hash of the name (use entire hash field). 286 ASSERT(name->HasHashCode()); 287 uint32_t field = name->hash_field(); 288 // Using only the low bits in 64-bit mode is unlikely to increase the 289 // risk of collision even if the heap is spread over an area larger than 290 // 4Gb (and not at all if it isn't). 291 uint32_t map_low32bits = 292 static_cast<uint32_t>(reinterpret_cast<uintptr_t>(map)); 293 // We always set the in_loop bit to zero when generating the lookup code 294 // so do it here too so the hash codes match. 295 uint32_t iflags = 296 (static_cast<uint32_t>(flags) & ~Code::kFlagsNotUsedInLookup); 297 // Base the offset on a simple combination of name, flags, and map. 298 uint32_t key = (map_low32bits + field) ^ iflags; 299 return key & ((kPrimaryTableSize - 1) << kHeapObjectTagSize); 300 } 301 302 // Hash algorithm for the secondary table. This algorithm is replicated in 303 // assembler for every architecture. Returns an index into the table that 304 // is scaled by 1 << kHeapObjectTagSize. 305 static int SecondaryOffset(Name* name, Code::Flags flags, int seed) { 306 // Use the seed from the primary cache in the secondary cache. 307 uint32_t name_low32bits = 308 static_cast<uint32_t>(reinterpret_cast<uintptr_t>(name)); 309 // We always set the in_loop bit to zero when generating the lookup code 310 // so do it here too so the hash codes match. 311 uint32_t iflags = 312 (static_cast<uint32_t>(flags) & ~Code::kFlagsNotUsedInLookup); 313 uint32_t key = (seed - name_low32bits) + iflags; 314 return key & ((kSecondaryTableSize - 1) << kHeapObjectTagSize); 315 } 316 317 // Compute the entry for a given offset in exactly the same way as 318 // we do in generated code. We generate an hash code that already 319 // ends in Name::kHashShift 0s. Then we multiply it so it is a multiple 320 // of sizeof(Entry). This makes it easier to avoid making mistakes 321 // in the hashed offset computations. 322 static Entry* entry(Entry* table, int offset) { 323 const int multiplier = sizeof(*table) >> Name::kHashShift; 324 return reinterpret_cast<Entry*>( 325 reinterpret_cast<Address>(table) + offset * multiplier); 326 } 327 328 static const int kPrimaryTableBits = 11; 329 static const int kPrimaryTableSize = (1 << kPrimaryTableBits); 330 static const int kSecondaryTableBits = 9; 331 static const int kSecondaryTableSize = (1 << kSecondaryTableBits); 332 333 Entry primary_[kPrimaryTableSize]; 334 Entry secondary_[kSecondaryTableSize]; 335 Isolate* isolate_; 336 337 friend class Isolate; 338 friend class SCTableReference; 339 340 DISALLOW_COPY_AND_ASSIGN(StubCache); 341 }; 342 343 344 // ------------------------------------------------------------------------ 345 346 347 // Support functions for IC stubs for callbacks. 348 DECLARE_RUNTIME_FUNCTION(MaybeObject*, StoreCallbackProperty); 349 350 351 // Support functions for IC stubs for interceptors. 352 DECLARE_RUNTIME_FUNCTION(MaybeObject*, LoadPropertyWithInterceptorOnly); 353 DECLARE_RUNTIME_FUNCTION(MaybeObject*, LoadPropertyWithInterceptorForLoad); 354 DECLARE_RUNTIME_FUNCTION(MaybeObject*, LoadPropertyWithInterceptorForCall); 355 DECLARE_RUNTIME_FUNCTION(MaybeObject*, StoreInterceptorProperty); 356 DECLARE_RUNTIME_FUNCTION(MaybeObject*, CallInterceptorProperty); 357 DECLARE_RUNTIME_FUNCTION(MaybeObject*, KeyedLoadPropertyWithInterceptor); 358 359 360 enum PrototypeCheckType { CHECK_ALL_MAPS, SKIP_RECEIVER }; 361 enum IcCheckType { ELEMENT, PROPERTY }; 362 363 364 // The stub compilers compile stubs for the stub cache. 365 class StubCompiler BASE_EMBEDDED { 366 public: 367 explicit StubCompiler(Isolate* isolate, 368 ExtraICState extra_ic_state = kNoExtraICState) 369 : isolate_(isolate), extra_ic_state_(extra_ic_state), 370 masm_(isolate, NULL, 256), failure_(NULL) { } 371 372 // Functions to compile either CallIC or KeyedCallIC. The specific kind 373 // is extracted from the code flags. 374 Handle<Code> CompileCallInitialize(Code::Flags flags); 375 Handle<Code> CompileCallPreMonomorphic(Code::Flags flags); 376 Handle<Code> CompileCallNormal(Code::Flags flags); 377 Handle<Code> CompileCallMegamorphic(Code::Flags flags); 378 Handle<Code> CompileCallArguments(Code::Flags flags); 379 Handle<Code> CompileCallMiss(Code::Flags flags); 380 381 #ifdef ENABLE_DEBUGGER_SUPPORT 382 Handle<Code> CompileCallDebugBreak(Code::Flags flags); 383 Handle<Code> CompileCallDebugPrepareStepIn(Code::Flags flags); 384 #endif 385 386 // Static functions for generating parts of stubs. 387 static void GenerateLoadGlobalFunctionPrototype(MacroAssembler* masm, 388 int index, 389 Register prototype); 390 391 // Helper function used to check that the dictionary doesn't contain 392 // the property. This function may return false negatives, so miss_label 393 // must always call a backup property check that is complete. 394 // This function is safe to call if the receiver has fast properties. 395 // Name must be unique and receiver must be a heap object. 396 static void GenerateDictionaryNegativeLookup(MacroAssembler* masm, 397 Label* miss_label, 398 Register receiver, 399 Handle<Name> name, 400 Register r0, 401 Register r1); 402 403 // Generates prototype loading code that uses the objects from the 404 // context we were in when this function was called. If the context 405 // has changed, a jump to miss is performed. This ties the generated 406 // code to a particular context and so must not be used in cases 407 // where the generated code is not allowed to have references to 408 // objects from a context. 409 static void GenerateDirectLoadGlobalFunctionPrototype(MacroAssembler* masm, 410 int index, 411 Register prototype, 412 Label* miss); 413 414 static void GenerateFastPropertyLoad(MacroAssembler* masm, 415 Register dst, 416 Register src, 417 bool inobject, 418 int index, 419 Representation representation); 420 421 static void GenerateLoadArrayLength(MacroAssembler* masm, 422 Register receiver, 423 Register scratch, 424 Label* miss_label); 425 426 static void GenerateLoadStringLength(MacroAssembler* masm, 427 Register receiver, 428 Register scratch1, 429 Register scratch2, 430 Label* miss_label); 431 432 static void GenerateLoadFunctionPrototype(MacroAssembler* masm, 433 Register receiver, 434 Register scratch1, 435 Register scratch2, 436 Label* miss_label); 437 438 // Generate code to check that a global property cell is empty. Create 439 // the property cell at compilation time if no cell exists for the 440 // property. 441 static void GenerateCheckPropertyCell(MacroAssembler* masm, 442 Handle<JSGlobalObject> global, 443 Handle<Name> name, 444 Register scratch, 445 Label* miss); 446 447 static void TailCallBuiltin(MacroAssembler* masm, Builtins::Name name); 448 449 // Generates code that verifies that the property holder has not changed 450 // (checking maps of objects in the prototype chain for fast and global 451 // objects or doing negative lookup for slow objects, ensures that the 452 // property cells for global objects are still empty) and checks that the map 453 // of the holder has not changed. If necessary the function also generates 454 // code for security check in case of global object holders. Helps to make 455 // sure that the current IC is still valid. 456 // 457 // The scratch and holder registers are always clobbered, but the object 458 // register is only clobbered if it the same as the holder register. The 459 // function returns a register containing the holder - either object_reg or 460 // holder_reg. 461 // The function can optionally (when save_at_depth != 462 // kInvalidProtoDepth) save the object at the given depth by moving 463 // it to [esp + kPointerSize]. 464 Register CheckPrototypes(Handle<Type> type, 465 Register object_reg, 466 Handle<JSObject> holder, 467 Register holder_reg, 468 Register scratch1, 469 Register scratch2, 470 Handle<Name> name, 471 Label* miss, 472 PrototypeCheckType check = CHECK_ALL_MAPS) { 473 return CheckPrototypes(type, object_reg, holder, holder_reg, scratch1, 474 scratch2, name, kInvalidProtoDepth, miss, check); 475 } 476 477 Register CheckPrototypes(Handle<Type> type, 478 Register object_reg, 479 Handle<JSObject> holder, 480 Register holder_reg, 481 Register scratch1, 482 Register scratch2, 483 Handle<Name> name, 484 int save_at_depth, 485 Label* miss, 486 PrototypeCheckType check = CHECK_ALL_MAPS); 487 488 void GenerateBooleanCheck(Register object, Label* miss); 489 490 protected: 491 Handle<Code> GetCodeWithFlags(Code::Flags flags, const char* name); 492 Handle<Code> GetCodeWithFlags(Code::Flags flags, Handle<Name> name); 493 494 ExtraICState extra_state() { return extra_ic_state_; } 495 496 MacroAssembler* masm() { return &masm_; } 497 void set_failure(Failure* failure) { failure_ = failure; } 498 499 static void LookupPostInterceptor(Handle<JSObject> holder, 500 Handle<Name> name, 501 LookupResult* lookup); 502 503 Isolate* isolate() { return isolate_; } 504 Heap* heap() { return isolate()->heap(); } 505 Factory* factory() { return isolate()->factory(); } 506 507 static void GenerateTailCall(MacroAssembler* masm, Handle<Code> code); 508 509 private: 510 Isolate* isolate_; 511 const ExtraICState extra_ic_state_; 512 MacroAssembler masm_; 513 Failure* failure_; 514 }; 515 516 517 enum FrontendCheckType { PERFORM_INITIAL_CHECKS, SKIP_INITIAL_CHECKS }; 518 519 520 class BaseLoadStoreStubCompiler: public StubCompiler { 521 public: 522 BaseLoadStoreStubCompiler(Isolate* isolate, 523 Code::Kind kind, 524 ExtraICState extra_ic_state = kNoExtraICState, 525 InlineCacheHolderFlag cache_holder = OWN_MAP) 526 : StubCompiler(isolate, extra_ic_state), 527 kind_(kind), 528 cache_holder_(cache_holder) { 529 InitializeRegisters(); 530 } 531 virtual ~BaseLoadStoreStubCompiler() { } 532 533 Handle<Code> CompileMonomorphicIC(Handle<Type> type, 534 Handle<Code> handler, 535 Handle<Name> name); 536 537 Handle<Code> CompilePolymorphicIC(TypeHandleList* types, 538 CodeHandleList* handlers, 539 Handle<Name> name, 540 Code::StubType type, 541 IcCheckType check); 542 543 virtual void GenerateNameCheck(Handle<Name> name, 544 Register name_reg, 545 Label* miss) { } 546 547 static Builtins::Name MissBuiltin(Code::Kind kind) { 548 switch (kind) { 549 case Code::LOAD_IC: return Builtins::kLoadIC_Miss; 550 case Code::STORE_IC: return Builtins::kStoreIC_Miss; 551 case Code::KEYED_LOAD_IC: return Builtins::kKeyedLoadIC_Miss; 552 case Code::KEYED_STORE_IC: return Builtins::kKeyedStoreIC_Miss; 553 default: UNREACHABLE(); 554 } 555 return Builtins::kLoadIC_Miss; 556 } 557 558 protected: 559 virtual Register HandlerFrontendHeader(Handle<Type> type, 560 Register object_reg, 561 Handle<JSObject> holder, 562 Handle<Name> name, 563 Label* miss) = 0; 564 565 virtual void HandlerFrontendFooter(Handle<Name> name, Label* miss) = 0; 566 567 Register HandlerFrontend(Handle<Type> type, 568 Register object_reg, 569 Handle<JSObject> holder, 570 Handle<Name> name); 571 572 Handle<Code> GetCode(Code::Kind kind, 573 Code::StubType type, 574 Handle<Name> name); 575 576 Handle<Code> GetICCode(Code::Kind kind, 577 Code::StubType type, 578 Handle<Name> name, 579 InlineCacheState state = MONOMORPHIC); 580 Code::Kind kind() { return kind_; } 581 582 Logger::LogEventsAndTags log_kind(Handle<Code> code) { 583 if (!code->is_inline_cache_stub()) return Logger::STUB_TAG; 584 if (kind_ == Code::LOAD_IC) { 585 return code->ic_state() == MONOMORPHIC 586 ? Logger::LOAD_IC_TAG : Logger::LOAD_POLYMORPHIC_IC_TAG; 587 } else if (kind_ == Code::KEYED_LOAD_IC) { 588 return code->ic_state() == MONOMORPHIC 589 ? Logger::KEYED_LOAD_IC_TAG : Logger::KEYED_LOAD_POLYMORPHIC_IC_TAG; 590 } else if (kind_ == Code::STORE_IC) { 591 return code->ic_state() == MONOMORPHIC 592 ? Logger::STORE_IC_TAG : Logger::STORE_POLYMORPHIC_IC_TAG; 593 } else { 594 return code->ic_state() == MONOMORPHIC 595 ? Logger::KEYED_STORE_IC_TAG : Logger::KEYED_STORE_POLYMORPHIC_IC_TAG; 596 } 597 } 598 void JitEvent(Handle<Name> name, Handle<Code> code); 599 600 virtual Register receiver() = 0; 601 virtual Register name() = 0; 602 virtual Register scratch1() = 0; 603 virtual Register scratch2() = 0; 604 virtual Register scratch3() = 0; 605 606 void InitializeRegisters(); 607 608 bool IncludesNumberType(TypeHandleList* types); 609 610 Code::Kind kind_; 611 InlineCacheHolderFlag cache_holder_; 612 Register* registers_; 613 }; 614 615 616 class LoadStubCompiler: public BaseLoadStoreStubCompiler { 617 public: 618 LoadStubCompiler(Isolate* isolate, 619 ExtraICState extra_ic_state = kNoExtraICState, 620 InlineCacheHolderFlag cache_holder = OWN_MAP, 621 Code::Kind kind = Code::LOAD_IC) 622 : BaseLoadStoreStubCompiler(isolate, kind, extra_ic_state, 623 cache_holder) { } 624 virtual ~LoadStubCompiler() { } 625 626 Handle<Code> CompileLoadField(Handle<Type> type, 627 Handle<JSObject> holder, 628 Handle<Name> name, 629 PropertyIndex index, 630 Representation representation); 631 632 Handle<Code> CompileLoadCallback(Handle<Type> type, 633 Handle<JSObject> holder, 634 Handle<Name> name, 635 Handle<ExecutableAccessorInfo> callback); 636 637 Handle<Code> CompileLoadCallback(Handle<Type> type, 638 Handle<JSObject> holder, 639 Handle<Name> name, 640 const CallOptimization& call_optimization); 641 642 Handle<Code> CompileLoadConstant(Handle<Type> type, 643 Handle<JSObject> holder, 644 Handle<Name> name, 645 Handle<Object> value); 646 647 Handle<Code> CompileLoadInterceptor(Handle<Type> type, 648 Handle<JSObject> holder, 649 Handle<Name> name); 650 651 Handle<Code> CompileLoadViaGetter(Handle<Type> type, 652 Handle<JSObject> holder, 653 Handle<Name> name, 654 Handle<JSFunction> getter); 655 656 static void GenerateLoadViaGetter(MacroAssembler* masm, 657 Register receiver, 658 Handle<JSFunction> getter); 659 660 Handle<Code> CompileLoadNonexistent(Handle<Type> type, 661 Handle<JSObject> last, 662 Handle<Name> name); 663 664 Handle<Code> CompileLoadGlobal(Handle<Type> type, 665 Handle<GlobalObject> holder, 666 Handle<PropertyCell> cell, 667 Handle<Name> name, 668 bool is_dont_delete); 669 670 static Register* registers(); 671 672 protected: 673 virtual Register HandlerFrontendHeader(Handle<Type> type, 674 Register object_reg, 675 Handle<JSObject> holder, 676 Handle<Name> name, 677 Label* miss); 678 679 virtual void HandlerFrontendFooter(Handle<Name> name, Label* miss); 680 681 Register CallbackHandlerFrontend(Handle<Type> type, 682 Register object_reg, 683 Handle<JSObject> holder, 684 Handle<Name> name, 685 Handle<Object> callback); 686 void NonexistentHandlerFrontend(Handle<Type> type, 687 Handle<JSObject> last, 688 Handle<Name> name); 689 690 void GenerateLoadField(Register reg, 691 Handle<JSObject> holder, 692 PropertyIndex field, 693 Representation representation); 694 void GenerateLoadConstant(Handle<Object> value); 695 void GenerateLoadCallback(Register reg, 696 Handle<ExecutableAccessorInfo> callback); 697 void GenerateLoadCallback(const CallOptimization& call_optimization); 698 void GenerateLoadInterceptor(Register holder_reg, 699 Handle<Object> object, 700 Handle<JSObject> holder, 701 LookupResult* lookup, 702 Handle<Name> name); 703 void GenerateLoadPostInterceptor(Register reg, 704 Handle<JSObject> interceptor_holder, 705 Handle<Name> name, 706 LookupResult* lookup); 707 708 virtual Register receiver() { return registers_[0]; } 709 virtual Register name() { return registers_[1]; } 710 virtual Register scratch1() { return registers_[2]; } 711 virtual Register scratch2() { return registers_[3]; } 712 virtual Register scratch3() { return registers_[4]; } 713 Register scratch4() { return registers_[5]; } 714 }; 715 716 717 class KeyedLoadStubCompiler: public LoadStubCompiler { 718 public: 719 KeyedLoadStubCompiler(Isolate* isolate, 720 ExtraICState extra_ic_state = kNoExtraICState, 721 InlineCacheHolderFlag cache_holder = OWN_MAP) 722 : LoadStubCompiler(isolate, extra_ic_state, cache_holder, 723 Code::KEYED_LOAD_IC) { } 724 725 Handle<Code> CompileLoadElement(Handle<Map> receiver_map); 726 727 void CompileElementHandlers(MapHandleList* receiver_maps, 728 CodeHandleList* handlers); 729 730 static void GenerateLoadDictionaryElement(MacroAssembler* masm); 731 732 protected: 733 static Register* registers(); 734 735 private: 736 virtual void GenerateNameCheck(Handle<Name> name, 737 Register name_reg, 738 Label* miss); 739 friend class BaseLoadStoreStubCompiler; 740 }; 741 742 743 class StoreStubCompiler: public BaseLoadStoreStubCompiler { 744 public: 745 StoreStubCompiler(Isolate* isolate, 746 ExtraICState extra_ic_state, 747 Code::Kind kind = Code::STORE_IC) 748 : BaseLoadStoreStubCompiler(isolate, kind, extra_ic_state) {} 749 750 virtual ~StoreStubCompiler() { } 751 752 Handle<Code> CompileStoreTransition(Handle<JSObject> object, 753 LookupResult* lookup, 754 Handle<Map> transition, 755 Handle<Name> name); 756 757 Handle<Code> CompileStoreField(Handle<JSObject> object, 758 LookupResult* lookup, 759 Handle<Name> name); 760 761 void GenerateNegativeHolderLookup(MacroAssembler* masm, 762 Handle<JSObject> holder, 763 Register holder_reg, 764 Handle<Name> name, 765 Label* miss); 766 767 void GenerateStoreTransition(MacroAssembler* masm, 768 Handle<JSObject> object, 769 LookupResult* lookup, 770 Handle<Map> transition, 771 Handle<Name> name, 772 Register receiver_reg, 773 Register name_reg, 774 Register value_reg, 775 Register scratch1, 776 Register scratch2, 777 Register scratch3, 778 Label* miss_label, 779 Label* slow); 780 781 void GenerateStoreField(MacroAssembler* masm, 782 Handle<JSObject> object, 783 LookupResult* lookup, 784 Register receiver_reg, 785 Register name_reg, 786 Register value_reg, 787 Register scratch1, 788 Register scratch2, 789 Label* miss_label); 790 791 Handle<Code> CompileStoreCallback(Handle<JSObject> object, 792 Handle<JSObject> holder, 793 Handle<Name> name, 794 Handle<ExecutableAccessorInfo> callback); 795 796 Handle<Code> CompileStoreCallback(Handle<JSObject> object, 797 Handle<JSObject> holder, 798 Handle<Name> name, 799 const CallOptimization& call_optimization); 800 801 static void GenerateStoreViaSetter(MacroAssembler* masm, 802 Handle<JSFunction> setter); 803 804 Handle<Code> CompileStoreViaSetter(Handle<JSObject> object, 805 Handle<JSObject> holder, 806 Handle<Name> name, 807 Handle<JSFunction> setter); 808 809 Handle<Code> CompileStoreInterceptor(Handle<JSObject> object, 810 Handle<Name> name); 811 812 static Builtins::Name SlowBuiltin(Code::Kind kind) { 813 switch (kind) { 814 case Code::STORE_IC: return Builtins::kStoreIC_Slow; 815 case Code::KEYED_STORE_IC: return Builtins::kKeyedStoreIC_Slow; 816 default: UNREACHABLE(); 817 } 818 return Builtins::kStoreIC_Slow; 819 } 820 821 protected: 822 virtual Register HandlerFrontendHeader(Handle<Type> type, 823 Register object_reg, 824 Handle<JSObject> holder, 825 Handle<Name> name, 826 Label* miss); 827 828 virtual void HandlerFrontendFooter(Handle<Name> name, Label* miss); 829 void GenerateRestoreName(MacroAssembler* masm, 830 Label* label, 831 Handle<Name> name); 832 833 virtual Register receiver() { return registers_[0]; } 834 virtual Register name() { return registers_[1]; } 835 Register value() { return registers_[2]; } 836 virtual Register scratch1() { return registers_[3]; } 837 virtual Register scratch2() { return registers_[4]; } 838 virtual Register scratch3() { return registers_[5]; } 839 840 protected: 841 static Register* registers(); 842 843 private: 844 friend class BaseLoadStoreStubCompiler; 845 }; 846 847 848 class KeyedStoreStubCompiler: public StoreStubCompiler { 849 public: 850 KeyedStoreStubCompiler(Isolate* isolate, 851 ExtraICState extra_ic_state) 852 : StoreStubCompiler(isolate, extra_ic_state, Code::KEYED_STORE_IC) {} 853 854 Handle<Code> CompileStoreElement(Handle<Map> receiver_map); 855 856 Handle<Code> CompileStorePolymorphic(MapHandleList* receiver_maps, 857 CodeHandleList* handler_stubs, 858 MapHandleList* transitioned_maps); 859 860 Handle<Code> CompileStoreElementPolymorphic(MapHandleList* receiver_maps); 861 862 static void GenerateStoreDictionaryElement(MacroAssembler* masm); 863 864 protected: 865 static Register* registers(); 866 867 KeyedAccessStoreMode store_mode() { 868 return KeyedStoreIC::GetKeyedAccessStoreMode(extra_state()); 869 } 870 871 private: 872 Register transition_map() { 873 return registers()[3]; 874 } 875 876 virtual void GenerateNameCheck(Handle<Name> name, 877 Register name_reg, 878 Label* miss); 879 friend class BaseLoadStoreStubCompiler; 880 }; 881 882 883 // Subset of FUNCTIONS_WITH_ID_LIST with custom constant/global call 884 // IC stubs. 885 #define CUSTOM_CALL_IC_GENERATORS(V) \ 886 V(ArrayPush) \ 887 V(ArrayPop) \ 888 V(StringCharCodeAt) \ 889 V(StringCharAt) \ 890 V(StringFromCharCode) \ 891 V(MathFloor) \ 892 V(MathAbs) \ 893 V(ArrayCode) 894 895 896 #define SITE_SPECIFIC_CALL_GENERATORS(V) \ 897 V(ArrayCode) 898 899 900 class CallStubCompiler: public StubCompiler { 901 public: 902 CallStubCompiler(Isolate* isolate, 903 int argc, 904 Code::Kind kind, 905 ExtraICState extra_state, 906 InlineCacheHolderFlag cache_holder = OWN_MAP); 907 908 Handle<Code> CompileCallField(Handle<JSObject> object, 909 Handle<JSObject> holder, 910 PropertyIndex index, 911 Handle<Name> name); 912 913 // Patch the global proxy over the global object if the global object is the 914 // receiver. 915 void PatchGlobalProxy(Handle<Object> object); 916 917 // Returns the register containing the holder of |name|. 918 Register HandlerFrontendHeader(Handle<Object> object, 919 Handle<JSObject> holder, 920 Handle<Name> name, 921 CheckType check, 922 Label* miss); 923 void HandlerFrontendFooter(Label* miss); 924 925 void GenerateJumpFunctionIgnoreReceiver(Handle<JSFunction> function); 926 void GenerateJumpFunction(Handle<Object> object, 927 Handle<JSFunction> function); 928 void GenerateJumpFunction(Handle<Object> object, 929 Register function, 930 Label* miss); 931 // Use to call |actual_closure|, a closure with the same shared function info 932 // as |function|. 933 void GenerateJumpFunction(Handle<Object> object, 934 Register actual_closure, 935 Handle<JSFunction> function); 936 937 Handle<Code> CompileCallConstant(Handle<Object> object, 938 Handle<JSObject> holder, 939 Handle<Name> name, 940 CheckType check, 941 Handle<JSFunction> function); 942 943 Handle<Code> CompileCallInterceptor(Handle<JSObject> object, 944 Handle<JSObject> holder, 945 Handle<Name> name); 946 947 Handle<Code> CompileCallGlobal(Handle<JSObject> object, 948 Handle<GlobalObject> holder, 949 Handle<PropertyCell> cell, 950 Handle<JSFunction> function, 951 Handle<Name> name); 952 953 static bool HasCustomCallGenerator(Handle<JSFunction> function); 954 static bool CanBeCached(Handle<JSFunction> function); 955 956 private: 957 // Compiles a custom call constant/global IC. For constant calls cell is 958 // NULL. Returns an empty handle if there is no custom call code for the 959 // given function. 960 Handle<Code> CompileCustomCall(Handle<Object> object, 961 Handle<JSObject> holder, 962 Handle<Cell> cell, 963 Handle<JSFunction> function, 964 Handle<String> name, 965 Code::StubType type); 966 967 #define DECLARE_CALL_GENERATOR(name) \ 968 Handle<Code> Compile##name##Call(Handle<Object> object, \ 969 Handle<JSObject> holder, \ 970 Handle<Cell> cell, \ 971 Handle<JSFunction> function, \ 972 Handle<String> fname, \ 973 Code::StubType type); 974 CUSTOM_CALL_IC_GENERATORS(DECLARE_CALL_GENERATOR) 975 #undef DECLARE_CALL_GENERATOR 976 977 Handle<Code> CompileFastApiCall(const CallOptimization& optimization, 978 Handle<Object> object, 979 Handle<JSObject> holder, 980 Handle<Cell> cell, 981 Handle<JSFunction> function, 982 Handle<String> name); 983 984 CallKind call_kind(); 985 986 Handle<Code> GetCode(Code::StubType type, Handle<Name> name); 987 Handle<Code> GetCode(Handle<JSFunction> function); 988 989 const ParameterCount& arguments() { return arguments_; } 990 991 void GenerateNameCheck(Handle<Name> name, Label* miss); 992 993 // Generates code to load the function from the cell checking that 994 // it still contains the same function. 995 void GenerateLoadFunctionFromCell(Handle<Cell> cell, 996 Handle<JSFunction> function, 997 Label* miss); 998 999 void GenerateFunctionCheck(Register function, Register scratch, Label* miss); 1000 1001 // Generates a jump to CallIC miss stub. 1002 void GenerateMissBranch(); 1003 1004 const ParameterCount arguments_; 1005 const Code::Kind kind_; 1006 const InlineCacheHolderFlag cache_holder_; 1007 }; 1008 1009 1010 // Holds information about possible function call optimizations. 1011 class CallOptimization BASE_EMBEDDED { 1012 public: 1013 explicit CallOptimization(LookupResult* lookup); 1014 1015 explicit CallOptimization(Handle<JSFunction> function); 1016 1017 bool is_constant_call() const { 1018 return !constant_function_.is_null(); 1019 } 1020 1021 Handle<JSFunction> constant_function() const { 1022 ASSERT(is_constant_call()); 1023 return constant_function_; 1024 } 1025 1026 bool is_simple_api_call() const { 1027 return is_simple_api_call_; 1028 } 1029 1030 Handle<FunctionTemplateInfo> expected_receiver_type() const { 1031 ASSERT(is_simple_api_call()); 1032 return expected_receiver_type_; 1033 } 1034 1035 Handle<CallHandlerInfo> api_call_info() const { 1036 ASSERT(is_simple_api_call()); 1037 return api_call_info_; 1038 } 1039 1040 // Returns the depth of the object having the expected type in the 1041 // prototype chain between the two arguments. 1042 int GetPrototypeDepthOfExpectedType(Handle<JSObject> object, 1043 Handle<JSObject> holder) const; 1044 1045 bool IsCompatibleReceiver(Object* receiver) { 1046 ASSERT(is_simple_api_call()); 1047 if (expected_receiver_type_.is_null()) return true; 1048 return expected_receiver_type_->IsTemplateFor(receiver); 1049 } 1050 1051 private: 1052 void Initialize(Handle<JSFunction> function); 1053 1054 // Determines whether the given function can be called using the 1055 // fast api call builtin. 1056 void AnalyzePossibleApiFunction(Handle<JSFunction> function); 1057 1058 Handle<JSFunction> constant_function_; 1059 bool is_simple_api_call_; 1060 Handle<FunctionTemplateInfo> expected_receiver_type_; 1061 Handle<CallHandlerInfo> api_call_info_; 1062 }; 1063 1064 1065 } } // namespace v8::internal 1066 1067 #endif // V8_STUB_CACHE_H_ 1068