1 // Copyright 2006-2008 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 "arguments.h" 32 #include "macro-assembler.h" 33 #include "zone-inl.h" 34 35 namespace v8 { 36 namespace internal { 37 38 39 // The stub cache is used for megamorphic calls and property accesses. 40 // It maps (map, name, type)->Code* 41 42 // The design of the table uses the inline cache stubs used for 43 // mono-morphic calls. The beauty of this, we do not have to 44 // invalidate the cache whenever a prototype map is changed. The stub 45 // validates the map chain as in the mono-morphic case. 46 47 class StubCache; 48 49 class SCTableReference { 50 public: address()51 Address address() const { return address_; } 52 53 private: SCTableReference(Address address)54 explicit SCTableReference(Address address) : address_(address) {} 55 56 Address address_; 57 58 friend class StubCache; 59 }; 60 61 62 class StubCache { 63 public: 64 struct Entry { 65 String* key; 66 Code* value; 67 }; 68 69 void Initialize(bool create_heap_objects); 70 71 72 // Computes the right stub matching. Inserts the result in the 73 // cache before returning. This might compile a stub if needed. 74 MUST_USE_RESULT MaybeObject* ComputeLoadNonexistent( 75 String* name, 76 JSObject* receiver); 77 78 MUST_USE_RESULT MaybeObject* ComputeLoadField(String* name, 79 JSObject* receiver, 80 JSObject* holder, 81 int field_index); 82 83 MUST_USE_RESULT MaybeObject* ComputeLoadCallback( 84 String* name, 85 JSObject* receiver, 86 JSObject* holder, 87 AccessorInfo* callback); 88 89 MUST_USE_RESULT MaybeObject* ComputeLoadConstant(String* name, 90 JSObject* receiver, 91 JSObject* holder, 92 Object* value); 93 94 MUST_USE_RESULT MaybeObject* ComputeLoadInterceptor( 95 String* name, 96 JSObject* receiver, 97 JSObject* holder); 98 99 MUST_USE_RESULT MaybeObject* ComputeLoadNormal(); 100 101 102 MUST_USE_RESULT MaybeObject* ComputeLoadGlobal( 103 String* name, 104 JSObject* receiver, 105 GlobalObject* holder, 106 JSGlobalPropertyCell* cell, 107 bool is_dont_delete); 108 109 110 // --- 111 112 MUST_USE_RESULT MaybeObject* ComputeKeyedLoadField(String* name, 113 JSObject* receiver, 114 JSObject* holder, 115 int field_index); 116 117 MUST_USE_RESULT MaybeObject* ComputeKeyedLoadCallback( 118 String* name, 119 JSObject* receiver, 120 JSObject* holder, 121 AccessorInfo* callback); 122 123 MUST_USE_RESULT MaybeObject* ComputeKeyedLoadConstant( 124 String* name, 125 JSObject* receiver, 126 JSObject* holder, 127 Object* value); 128 129 MUST_USE_RESULT MaybeObject* ComputeKeyedLoadInterceptor( 130 String* name, 131 JSObject* receiver, 132 JSObject* holder); 133 134 MUST_USE_RESULT MaybeObject* ComputeKeyedLoadArrayLength( 135 String* name, 136 JSArray* receiver); 137 138 MUST_USE_RESULT MaybeObject* ComputeKeyedLoadStringLength( 139 String* name, 140 String* receiver); 141 142 MUST_USE_RESULT MaybeObject* ComputeKeyedLoadFunctionPrototype( 143 String* name, 144 JSFunction* receiver); 145 146 MUST_USE_RESULT MaybeObject* ComputeKeyedLoadSpecialized( 147 JSObject* receiver); 148 149 // --- 150 151 MUST_USE_RESULT MaybeObject* ComputeStoreField( 152 String* name, 153 JSObject* receiver, 154 int field_index, 155 Map* transition, 156 StrictModeFlag strict_mode); 157 158 MUST_USE_RESULT MaybeObject* ComputeStoreNormal( 159 StrictModeFlag strict_mode); 160 161 MUST_USE_RESULT MaybeObject* ComputeStoreGlobal( 162 String* name, 163 GlobalObject* receiver, 164 JSGlobalPropertyCell* cell, 165 StrictModeFlag strict_mode); 166 167 MUST_USE_RESULT MaybeObject* ComputeStoreCallback( 168 String* name, 169 JSObject* receiver, 170 AccessorInfo* callback, 171 StrictModeFlag strict_mode); 172 173 MUST_USE_RESULT MaybeObject* ComputeStoreInterceptor( 174 String* name, 175 JSObject* receiver, 176 StrictModeFlag strict_mode); 177 178 // --- 179 180 MUST_USE_RESULT MaybeObject* ComputeKeyedStoreField( 181 String* name, 182 JSObject* receiver, 183 int field_index, 184 Map* transition, 185 StrictModeFlag strict_mode); 186 187 MUST_USE_RESULT MaybeObject* ComputeKeyedStoreSpecialized( 188 JSObject* receiver, 189 StrictModeFlag strict_mode); 190 191 192 MUST_USE_RESULT MaybeObject* ComputeKeyedLoadOrStoreExternalArray( 193 JSObject* receiver, 194 bool is_store, 195 StrictModeFlag strict_mode); 196 197 // --- 198 199 MUST_USE_RESULT MaybeObject* ComputeCallField(int argc, 200 InLoopFlag in_loop, 201 Code::Kind, 202 String* name, 203 Object* object, 204 JSObject* holder, 205 int index); 206 207 MUST_USE_RESULT MaybeObject* ComputeCallConstant( 208 int argc, 209 InLoopFlag in_loop, 210 Code::Kind, 211 Code::ExtraICState extra_ic_state, 212 String* name, 213 Object* object, 214 JSObject* holder, 215 JSFunction* function); 216 217 MUST_USE_RESULT MaybeObject* ComputeCallNormal(int argc, 218 InLoopFlag in_loop, 219 Code::Kind, 220 String* name, 221 JSObject* receiver); 222 223 MUST_USE_RESULT MaybeObject* ComputeCallInterceptor(int argc, 224 Code::Kind, 225 String* name, 226 Object* object, 227 JSObject* holder); 228 229 MUST_USE_RESULT MaybeObject* ComputeCallGlobal( 230 int argc, 231 InLoopFlag in_loop, 232 Code::Kind, 233 String* name, 234 JSObject* receiver, 235 GlobalObject* holder, 236 JSGlobalPropertyCell* cell, 237 JSFunction* function); 238 239 // --- 240 241 MUST_USE_RESULT MaybeObject* ComputeCallInitialize(int argc, 242 InLoopFlag in_loop, 243 Code::Kind kind); 244 245 Handle<Code> ComputeCallInitialize(int argc, InLoopFlag in_loop); 246 247 Handle<Code> ComputeKeyedCallInitialize(int argc, InLoopFlag in_loop); 248 249 MUST_USE_RESULT MaybeObject* ComputeCallPreMonomorphic( 250 int argc, 251 InLoopFlag in_loop, 252 Code::Kind kind); 253 254 MUST_USE_RESULT MaybeObject* ComputeCallNormal(int argc, 255 InLoopFlag in_loop, 256 Code::Kind kind); 257 258 MUST_USE_RESULT MaybeObject* ComputeCallMegamorphic(int argc, 259 InLoopFlag in_loop, 260 Code::Kind kind); 261 262 MUST_USE_RESULT MaybeObject* ComputeCallMiss(int argc, Code::Kind kind); 263 264 // Finds the Code object stored in the Heap::non_monomorphic_cache(). 265 MUST_USE_RESULT Code* FindCallInitialize(int argc, 266 InLoopFlag in_loop, 267 Code::Kind kind); 268 269 #ifdef ENABLE_DEBUGGER_SUPPORT 270 MUST_USE_RESULT MaybeObject* ComputeCallDebugBreak(int argc, Code::Kind kind); 271 272 MUST_USE_RESULT MaybeObject* ComputeCallDebugPrepareStepIn(int argc, 273 Code::Kind kind); 274 #endif 275 276 // Update cache for entry hash(name, map). 277 Code* Set(String* name, Map* map, Code* code); 278 279 // Clear the lookup table (@ mark compact collection). 280 void Clear(); 281 282 // Collect all maps that match the name and flags. 283 void CollectMatchingMaps(ZoneMapList* types, 284 String* name, 285 Code::Flags flags); 286 287 // Generate code for probing the stub cache table. 288 // Arguments extra and extra2 may be used to pass additional scratch 289 // registers. Set to no_reg if not needed. 290 void GenerateProbe(MacroAssembler* masm, 291 Code::Flags flags, 292 Register receiver, 293 Register name, 294 Register scratch, 295 Register extra, 296 Register extra2 = no_reg); 297 298 enum Table { 299 kPrimary, 300 kSecondary 301 }; 302 303 key_reference(StubCache::Table table)304 SCTableReference key_reference(StubCache::Table table) { 305 return SCTableReference( 306 reinterpret_cast<Address>(&first_entry(table)->key)); 307 } 308 309 value_reference(StubCache::Table table)310 SCTableReference value_reference(StubCache::Table table) { 311 return SCTableReference( 312 reinterpret_cast<Address>(&first_entry(table)->value)); 313 } 314 315 first_entry(StubCache::Table table)316 StubCache::Entry* first_entry(StubCache::Table table) { 317 switch (table) { 318 case StubCache::kPrimary: return StubCache::primary_; 319 case StubCache::kSecondary: return StubCache::secondary_; 320 } 321 UNREACHABLE(); 322 return NULL; 323 } 324 isolate()325 Isolate* isolate() { return isolate_; } heap()326 Heap* heap() { return isolate()->heap(); } 327 328 private: 329 explicit StubCache(Isolate* isolate); 330 331 friend class Isolate; 332 friend class SCTableReference; 333 static const int kPrimaryTableSize = 2048; 334 static const int kSecondaryTableSize = 512; 335 Entry primary_[kPrimaryTableSize]; 336 Entry secondary_[kSecondaryTableSize]; 337 338 // Computes the hashed offsets for primary and secondary caches. PrimaryOffset(String * name,Code::Flags flags,Map * map)339 RLYSTC int PrimaryOffset(String* name, Code::Flags flags, Map* map) { 340 // This works well because the heap object tag size and the hash 341 // shift are equal. Shifting down the length field to get the 342 // hash code would effectively throw away two bits of the hash 343 // code. 344 ASSERT(kHeapObjectTagSize == String::kHashShift); 345 // Compute the hash of the name (use entire hash field). 346 ASSERT(name->HasHashCode()); 347 uint32_t field = name->hash_field(); 348 // Using only the low bits in 64-bit mode is unlikely to increase the 349 // risk of collision even if the heap is spread over an area larger than 350 // 4Gb (and not at all if it isn't). 351 uint32_t map_low32bits = 352 static_cast<uint32_t>(reinterpret_cast<uintptr_t>(map)); 353 // We always set the in_loop bit to zero when generating the lookup code 354 // so do it here too so the hash codes match. 355 uint32_t iflags = 356 (static_cast<uint32_t>(flags) & ~Code::kFlagsNotUsedInLookup); 357 // Base the offset on a simple combination of name, flags, and map. 358 uint32_t key = (map_low32bits + field) ^ iflags; 359 return key & ((kPrimaryTableSize - 1) << kHeapObjectTagSize); 360 } 361 SecondaryOffset(String * name,Code::Flags flags,int seed)362 RLYSTC int SecondaryOffset(String* name, Code::Flags flags, int seed) { 363 // Use the seed from the primary cache in the secondary cache. 364 uint32_t string_low32bits = 365 static_cast<uint32_t>(reinterpret_cast<uintptr_t>(name)); 366 // We always set the in_loop bit to zero when generating the lookup code 367 // so do it here too so the hash codes match. 368 uint32_t iflags = 369 (static_cast<uint32_t>(flags) & ~Code::kFlagsICInLoopMask); 370 uint32_t key = seed - string_low32bits + iflags; 371 return key & ((kSecondaryTableSize - 1) << kHeapObjectTagSize); 372 } 373 374 // Compute the entry for a given offset in exactly the same way as 375 // we do in generated code. We generate an hash code that already 376 // ends in String::kHashShift 0s. Then we shift it so it is a multiple 377 // of sizeof(Entry). This makes it easier to avoid making mistakes 378 // in the hashed offset computations. entry(Entry * table,int offset)379 RLYSTC Entry* entry(Entry* table, int offset) { 380 const int shift_amount = kPointerSizeLog2 + 1 - String::kHashShift; 381 return reinterpret_cast<Entry*>( 382 reinterpret_cast<Address>(table) + (offset << shift_amount)); 383 } 384 385 Isolate* isolate_; 386 387 DISALLOW_COPY_AND_ASSIGN(StubCache); 388 }; 389 390 391 // ------------------------------------------------------------------------ 392 393 394 // Support functions for IC stubs for callbacks. 395 DECLARE_RUNTIME_FUNCTION(MaybeObject*, LoadCallbackProperty); 396 DECLARE_RUNTIME_FUNCTION(MaybeObject*, StoreCallbackProperty); 397 398 399 // Support functions for IC stubs for interceptors. 400 DECLARE_RUNTIME_FUNCTION(MaybeObject*, LoadPropertyWithInterceptorOnly); 401 DECLARE_RUNTIME_FUNCTION(MaybeObject*, LoadPropertyWithInterceptorForLoad); 402 DECLARE_RUNTIME_FUNCTION(MaybeObject*, LoadPropertyWithInterceptorForCall); 403 DECLARE_RUNTIME_FUNCTION(MaybeObject*, StoreInterceptorProperty); 404 DECLARE_RUNTIME_FUNCTION(MaybeObject*, CallInterceptorProperty); 405 DECLARE_RUNTIME_FUNCTION(MaybeObject*, KeyedLoadPropertyWithInterceptor); 406 407 408 // The stub compiler compiles stubs for the stub cache. 409 class StubCompiler BASE_EMBEDDED { 410 public: StubCompiler()411 StubCompiler() 412 : scope_(), masm_(Isolate::Current(), NULL, 256), failure_(NULL) { } 413 414 MUST_USE_RESULT MaybeObject* CompileCallInitialize(Code::Flags flags); 415 MUST_USE_RESULT MaybeObject* CompileCallPreMonomorphic(Code::Flags flags); 416 MUST_USE_RESULT MaybeObject* CompileCallNormal(Code::Flags flags); 417 MUST_USE_RESULT MaybeObject* CompileCallMegamorphic(Code::Flags flags); 418 MUST_USE_RESULT MaybeObject* CompileCallMiss(Code::Flags flags); 419 #ifdef ENABLE_DEBUGGER_SUPPORT 420 MUST_USE_RESULT MaybeObject* CompileCallDebugBreak(Code::Flags flags); 421 MUST_USE_RESULT MaybeObject* CompileCallDebugPrepareStepIn(Code::Flags flags); 422 #endif 423 424 // Static functions for generating parts of stubs. 425 static void GenerateLoadGlobalFunctionPrototype(MacroAssembler* masm, 426 int index, 427 Register prototype); 428 429 // Generates prototype loading code that uses the objects from the 430 // context we were in when this function was called. If the context 431 // has changed, a jump to miss is performed. This ties the generated 432 // code to a particular context and so must not be used in cases 433 // where the generated code is not allowed to have references to 434 // objects from a context. 435 static void GenerateDirectLoadGlobalFunctionPrototype(MacroAssembler* masm, 436 int index, 437 Register prototype, 438 Label* miss); 439 440 static void GenerateFastPropertyLoad(MacroAssembler* masm, 441 Register dst, Register src, 442 JSObject* holder, int index); 443 444 static void GenerateLoadArrayLength(MacroAssembler* masm, 445 Register receiver, 446 Register scratch, 447 Label* miss_label); 448 449 static void GenerateLoadStringLength(MacroAssembler* masm, 450 Register receiver, 451 Register scratch1, 452 Register scratch2, 453 Label* miss_label, 454 bool support_wrappers); 455 456 static void GenerateLoadFunctionPrototype(MacroAssembler* masm, 457 Register receiver, 458 Register scratch1, 459 Register scratch2, 460 Label* miss_label); 461 462 static void GenerateStoreField(MacroAssembler* masm, 463 JSObject* object, 464 int index, 465 Map* transition, 466 Register receiver_reg, 467 Register name_reg, 468 Register scratch, 469 Label* miss_label); 470 471 static void GenerateLoadMiss(MacroAssembler* masm, Code::Kind kind); 472 473 // Generates code that verifies that the property holder has not changed 474 // (checking maps of objects in the prototype chain for fast and global 475 // objects or doing negative lookup for slow objects, ensures that the 476 // property cells for global objects are still empty) and checks that the map 477 // of the holder has not changed. If necessary the function also generates 478 // code for security check in case of global object holders. Helps to make 479 // sure that the current IC is still valid. 480 // 481 // The scratch and holder registers are always clobbered, but the object 482 // register is only clobbered if it the same as the holder register. The 483 // function returns a register containing the holder - either object_reg or 484 // holder_reg. 485 // The function can optionally (when save_at_depth != 486 // kInvalidProtoDepth) save the object at the given depth by moving 487 // it to [esp + kPointerSize]. 488 CheckPrototypes(JSObject * object,Register object_reg,JSObject * holder,Register holder_reg,Register scratch1,Register scratch2,String * name,Label * miss)489 Register CheckPrototypes(JSObject* object, 490 Register object_reg, 491 JSObject* holder, 492 Register holder_reg, 493 Register scratch1, 494 Register scratch2, 495 String* name, 496 Label* miss) { 497 return CheckPrototypes(object, object_reg, holder, holder_reg, scratch1, 498 scratch2, name, kInvalidProtoDepth, miss); 499 } 500 501 Register CheckPrototypes(JSObject* object, 502 Register object_reg, 503 JSObject* holder, 504 Register holder_reg, 505 Register scratch1, 506 Register scratch2, 507 String* name, 508 int save_at_depth, 509 Label* miss); 510 511 protected: 512 MaybeObject* GetCodeWithFlags(Code::Flags flags, const char* name); 513 MaybeObject* GetCodeWithFlags(Code::Flags flags, String* name); 514 masm()515 MacroAssembler* masm() { return &masm_; } set_failure(Failure * failure)516 void set_failure(Failure* failure) { failure_ = failure; } 517 518 void GenerateLoadField(JSObject* object, 519 JSObject* holder, 520 Register receiver, 521 Register scratch1, 522 Register scratch2, 523 Register scratch3, 524 int index, 525 String* name, 526 Label* miss); 527 528 MaybeObject* GenerateLoadCallback(JSObject* object, 529 JSObject* holder, 530 Register receiver, 531 Register name_reg, 532 Register scratch1, 533 Register scratch2, 534 Register scratch3, 535 AccessorInfo* callback, 536 String* name, 537 Label* miss); 538 539 void GenerateLoadConstant(JSObject* object, 540 JSObject* holder, 541 Register receiver, 542 Register scratch1, 543 Register scratch2, 544 Register scratch3, 545 Object* value, 546 String* name, 547 Label* miss); 548 549 void GenerateLoadInterceptor(JSObject* object, 550 JSObject* holder, 551 LookupResult* lookup, 552 Register receiver, 553 Register name_reg, 554 Register scratch1, 555 Register scratch2, 556 Register scratch3, 557 String* name, 558 Label* miss); 559 560 static void LookupPostInterceptor(JSObject* holder, 561 String* name, 562 LookupResult* lookup); 563 isolate()564 Isolate* isolate() { return scope_.isolate(); } heap()565 Heap* heap() { return isolate()->heap(); } factory()566 Factory* factory() { return isolate()->factory(); } 567 568 private: 569 HandleScope scope_; 570 MacroAssembler masm_; 571 Failure* failure_; 572 }; 573 574 575 class LoadStubCompiler: public StubCompiler { 576 public: 577 MUST_USE_RESULT MaybeObject* CompileLoadNonexistent(String* name, 578 JSObject* object, 579 JSObject* last); 580 581 MUST_USE_RESULT MaybeObject* CompileLoadField(JSObject* object, 582 JSObject* holder, 583 int index, 584 String* name); 585 586 MUST_USE_RESULT MaybeObject* CompileLoadCallback(String* name, 587 JSObject* object, 588 JSObject* holder, 589 AccessorInfo* callback); 590 591 MUST_USE_RESULT MaybeObject* CompileLoadConstant(JSObject* object, 592 JSObject* holder, 593 Object* value, 594 String* name); 595 596 MUST_USE_RESULT MaybeObject* CompileLoadInterceptor(JSObject* object, 597 JSObject* holder, 598 String* name); 599 600 MUST_USE_RESULT MaybeObject* CompileLoadGlobal(JSObject* object, 601 GlobalObject* holder, 602 JSGlobalPropertyCell* cell, 603 String* name, 604 bool is_dont_delete); 605 606 private: 607 MUST_USE_RESULT MaybeObject* GetCode(PropertyType type, String* name); 608 }; 609 610 611 class KeyedLoadStubCompiler: public StubCompiler { 612 public: 613 MUST_USE_RESULT MaybeObject* CompileLoadField(String* name, 614 JSObject* object, 615 JSObject* holder, 616 int index); 617 618 MUST_USE_RESULT MaybeObject* CompileLoadCallback(String* name, 619 JSObject* object, 620 JSObject* holder, 621 AccessorInfo* callback); 622 623 MUST_USE_RESULT MaybeObject* CompileLoadConstant(String* name, 624 JSObject* object, 625 JSObject* holder, 626 Object* value); 627 628 MUST_USE_RESULT MaybeObject* CompileLoadInterceptor(JSObject* object, 629 JSObject* holder, 630 String* name); 631 632 MUST_USE_RESULT MaybeObject* CompileLoadArrayLength(String* name); 633 MUST_USE_RESULT MaybeObject* CompileLoadStringLength(String* name); 634 MUST_USE_RESULT MaybeObject* CompileLoadFunctionPrototype(String* name); 635 636 MUST_USE_RESULT MaybeObject* CompileLoadSpecialized(JSObject* receiver); 637 638 private: 639 MaybeObject* GetCode(PropertyType type, String* name); 640 }; 641 642 643 class StoreStubCompiler: public StubCompiler { 644 public: StoreStubCompiler(StrictModeFlag strict_mode)645 explicit StoreStubCompiler(StrictModeFlag strict_mode) 646 : strict_mode_(strict_mode) { } 647 648 MUST_USE_RESULT MaybeObject* CompileStoreField(JSObject* object, 649 int index, 650 Map* transition, 651 String* name); 652 653 MUST_USE_RESULT MaybeObject* CompileStoreCallback(JSObject* object, 654 AccessorInfo* callbacks, 655 String* name); 656 MUST_USE_RESULT MaybeObject* CompileStoreInterceptor(JSObject* object, 657 String* name); 658 MUST_USE_RESULT MaybeObject* CompileStoreGlobal(GlobalObject* object, 659 JSGlobalPropertyCell* holder, 660 String* name); 661 662 663 private: 664 MaybeObject* GetCode(PropertyType type, String* name); 665 666 StrictModeFlag strict_mode_; 667 }; 668 669 670 class KeyedStoreStubCompiler: public StubCompiler { 671 public: KeyedStoreStubCompiler(StrictModeFlag strict_mode)672 explicit KeyedStoreStubCompiler(StrictModeFlag strict_mode) 673 : strict_mode_(strict_mode) { } 674 675 MUST_USE_RESULT MaybeObject* CompileStoreField(JSObject* object, 676 int index, 677 Map* transition, 678 String* name); 679 680 MUST_USE_RESULT MaybeObject* CompileStoreSpecialized(JSObject* receiver); 681 682 private: 683 MaybeObject* GetCode(PropertyType type, String* name); 684 685 StrictModeFlag strict_mode_; 686 }; 687 688 689 // Subset of FUNCTIONS_WITH_ID_LIST with custom constant/global call 690 // IC stubs. 691 #define CUSTOM_CALL_IC_GENERATORS(V) \ 692 V(ArrayPush) \ 693 V(ArrayPop) \ 694 V(StringCharCodeAt) \ 695 V(StringCharAt) \ 696 V(StringFromCharCode) \ 697 V(MathFloor) \ 698 V(MathAbs) 699 700 701 class CallOptimization; 702 703 class CallStubCompiler: public StubCompiler { 704 public: 705 CallStubCompiler(int argc, 706 InLoopFlag in_loop, 707 Code::Kind kind, 708 Code::ExtraICState extra_ic_state, 709 InlineCacheHolderFlag cache_holder); 710 711 MUST_USE_RESULT MaybeObject* CompileCallField(JSObject* object, 712 JSObject* holder, 713 int index, 714 String* name); 715 MUST_USE_RESULT MaybeObject* CompileCallConstant(Object* object, 716 JSObject* holder, 717 JSFunction* function, 718 String* name, 719 CheckType check); 720 MUST_USE_RESULT MaybeObject* CompileCallInterceptor(JSObject* object, 721 JSObject* holder, 722 String* name); 723 MUST_USE_RESULT MaybeObject* CompileCallGlobal(JSObject* object, 724 GlobalObject* holder, 725 JSGlobalPropertyCell* cell, 726 JSFunction* function, 727 String* name); 728 729 static bool HasCustomCallGenerator(JSFunction* function); 730 731 private: 732 // Compiles a custom call constant/global IC. For constant calls 733 // cell is NULL. Returns undefined if there is no custom call code 734 // for the given function or it can't be generated. 735 MUST_USE_RESULT MaybeObject* CompileCustomCall(Object* object, 736 JSObject* holder, 737 JSGlobalPropertyCell* cell, 738 JSFunction* function, 739 String* name); 740 741 #define DECLARE_CALL_GENERATOR(name) \ 742 MUST_USE_RESULT MaybeObject* Compile##name##Call(Object* object, \ 743 JSObject* holder, \ 744 JSGlobalPropertyCell* cell, \ 745 JSFunction* function, \ 746 String* fname); 747 CUSTOM_CALL_IC_GENERATORS(DECLARE_CALL_GENERATOR) 748 #undef DECLARE_CALL_GENERATOR 749 750 MUST_USE_RESULT MaybeObject* CompileFastApiCall( 751 const CallOptimization& optimization, 752 Object* object, 753 JSObject* holder, 754 JSGlobalPropertyCell* cell, 755 JSFunction* function, 756 String* name); 757 758 const ParameterCount arguments_; 759 const InLoopFlag in_loop_; 760 const Code::Kind kind_; 761 const Code::ExtraICState extra_ic_state_; 762 const InlineCacheHolderFlag cache_holder_; 763 arguments()764 const ParameterCount& arguments() { return arguments_; } 765 766 MUST_USE_RESULT MaybeObject* GetCode(PropertyType type, String* name); 767 768 // Convenience function. Calls GetCode above passing 769 // CONSTANT_FUNCTION type and the name of the given function. 770 MUST_USE_RESULT MaybeObject* GetCode(JSFunction* function); 771 772 void GenerateNameCheck(String* name, Label* miss); 773 774 void GenerateGlobalReceiverCheck(JSObject* object, 775 JSObject* holder, 776 String* name, 777 Label* miss); 778 779 // Generates code to load the function from the cell checking that 780 // it still contains the same function. 781 void GenerateLoadFunctionFromCell(JSGlobalPropertyCell* cell, 782 JSFunction* function, 783 Label* miss); 784 785 // Generates a jump to CallIC miss stub. Returns Failure if the jump cannot 786 // be generated. 787 MUST_USE_RESULT MaybeObject* GenerateMissBranch(); 788 }; 789 790 791 class ConstructStubCompiler: public StubCompiler { 792 public: ConstructStubCompiler()793 explicit ConstructStubCompiler() {} 794 795 MUST_USE_RESULT MaybeObject* CompileConstructStub(JSFunction* function); 796 797 private: 798 MaybeObject* GetCode(); 799 }; 800 801 802 // Holds information about possible function call optimizations. 803 class CallOptimization BASE_EMBEDDED { 804 public: 805 explicit CallOptimization(LookupResult* lookup); 806 807 explicit CallOptimization(JSFunction* function); 808 is_constant_call()809 bool is_constant_call() const { 810 return constant_function_ != NULL; 811 } 812 constant_function()813 JSFunction* constant_function() const { 814 ASSERT(constant_function_ != NULL); 815 return constant_function_; 816 } 817 is_simple_api_call()818 bool is_simple_api_call() const { 819 return is_simple_api_call_; 820 } 821 expected_receiver_type()822 FunctionTemplateInfo* expected_receiver_type() const { 823 ASSERT(is_simple_api_call_); 824 return expected_receiver_type_; 825 } 826 api_call_info()827 CallHandlerInfo* api_call_info() const { 828 ASSERT(is_simple_api_call_); 829 return api_call_info_; 830 } 831 832 // Returns the depth of the object having the expected type in the 833 // prototype chain between the two arguments. 834 int GetPrototypeDepthOfExpectedType(JSObject* object, 835 JSObject* holder) const; 836 837 private: 838 void Initialize(JSFunction* function); 839 840 // Determines whether the given function can be called using the 841 // fast api call builtin. 842 void AnalyzePossibleApiFunction(JSFunction* function); 843 844 JSFunction* constant_function_; 845 bool is_simple_api_call_; 846 FunctionTemplateInfo* expected_receiver_type_; 847 CallHandlerInfo* api_call_info_; 848 }; 849 850 class ExternalArrayStubCompiler: public StubCompiler { 851 public: ExternalArrayStubCompiler()852 explicit ExternalArrayStubCompiler() {} 853 854 MUST_USE_RESULT MaybeObject* CompileKeyedLoadStub( 855 JSObject* receiver, ExternalArrayType array_type, Code::Flags flags); 856 857 MUST_USE_RESULT MaybeObject* CompileKeyedStoreStub( 858 JSObject* receiver, ExternalArrayType array_type, Code::Flags flags); 859 860 private: 861 MaybeObject* GetCode(Code::Flags flags); 862 }; 863 864 } } // namespace v8::internal 865 866 #endif // V8_STUB_CACHE_H_ 867