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_IC_H_ 29 #define V8_IC_H_ 30 31 #include "macro-assembler.h" 32 #include "type-info.h" 33 34 namespace v8 { 35 namespace internal { 36 37 38 // IC_UTIL_LIST defines all utility functions called from generated 39 // inline caching code. The argument for the macro, ICU, is the function name. 40 #define IC_UTIL_LIST(ICU) \ 41 ICU(LoadIC_Miss) \ 42 ICU(KeyedLoadIC_Miss) \ 43 ICU(CallIC_Miss) \ 44 ICU(KeyedCallIC_Miss) \ 45 ICU(StoreIC_Miss) \ 46 ICU(StoreIC_ArrayLength) \ 47 ICU(StoreIC_Slow) \ 48 ICU(SharedStoreIC_ExtendStorage) \ 49 ICU(KeyedStoreIC_Miss) \ 50 ICU(KeyedStoreIC_Slow) \ 51 /* Utilities for IC stubs. */ \ 52 ICU(StoreCallbackProperty) \ 53 ICU(LoadPropertyWithInterceptorOnly) \ 54 ICU(LoadPropertyWithInterceptorForLoad) \ 55 ICU(LoadPropertyWithInterceptorForCall) \ 56 ICU(KeyedLoadPropertyWithInterceptor) \ 57 ICU(StoreInterceptorProperty) \ 58 ICU(CompareIC_Miss) \ 59 ICU(BinaryOpIC_Miss) \ 60 ICU(CompareNilIC_Miss) \ 61 ICU(Unreachable) \ 62 ICU(ToBooleanIC_Miss) 63 // 64 // IC is the base class for LoadIC, StoreIC, CallIC, KeyedLoadIC, 65 // and KeyedStoreIC. 66 // 67 class IC { 68 public: 69 // The ids for utility called from the generated code. 70 enum UtilityId { 71 #define CONST_NAME(name) k##name, 72 IC_UTIL_LIST(CONST_NAME) 73 #undef CONST_NAME 74 kUtilityCount 75 }; 76 77 // Looks up the address of the named utility. 78 static Address AddressFromUtilityId(UtilityId id); 79 80 // Alias the inline cache state type to make the IC code more readable. 81 typedef InlineCacheState State; 82 83 // The IC code is either invoked with no extra frames on the stack 84 // or with a single extra frame for supporting calls. 85 enum FrameDepth { 86 NO_EXTRA_FRAME = 0, 87 EXTRA_CALL_FRAME = 1 88 }; 89 90 // Construct the IC structure with the given number of extra 91 // JavaScript frames on the stack. 92 IC(FrameDepth depth, Isolate* isolate); 93 virtual ~IC() {} 94 95 State state() const { return state_; } 96 inline Address address() const; 97 98 // Compute the current IC state based on the target stub, receiver and name. 99 void UpdateState(Handle<Object> receiver, Handle<Object> name); 100 void MarkMonomorphicPrototypeFailure() { 101 state_ = MONOMORPHIC_PROTOTYPE_FAILURE; 102 } 103 104 // Clear the inline cache to initial state. 105 static void Clear(Isolate* isolate, Address address); 106 107 // Computes the reloc info for this IC. This is a fairly expensive 108 // operation as it has to search through the heap to find the code 109 // object that contains this IC site. 110 RelocInfo::Mode ComputeMode(); 111 112 // Returns if this IC is for contextual (no explicit receiver) 113 // access to properties. 114 bool IsUndeclaredGlobal(Handle<Object> receiver) { 115 if (receiver->IsGlobalObject()) { 116 return SlowIsUndeclaredGlobal(); 117 } else { 118 ASSERT(!SlowIsUndeclaredGlobal()); 119 return false; 120 } 121 } 122 123 bool SlowIsUndeclaredGlobal() { 124 return ComputeMode() == RelocInfo::CODE_TARGET_CONTEXT; 125 } 126 127 #ifdef DEBUG 128 bool IsLoadStub() { 129 return target()->is_load_stub() || target()->is_keyed_load_stub(); 130 } 131 132 bool IsStoreStub() { 133 return target()->is_store_stub() || target()->is_keyed_store_stub(); 134 } 135 136 bool IsCallStub() { 137 return target()->is_call_stub() || target()->is_keyed_call_stub(); 138 } 139 #endif 140 141 // Determines which map must be used for keeping the code stub. 142 // These methods should not be called with undefined or null. 143 static inline InlineCacheHolderFlag GetCodeCacheForObject(Object* object); 144 // TODO(verwaest): This currently returns a HeapObject rather than JSObject* 145 // since loading the IC for loading the length from strings are stored on 146 // the string map directly, rather than on the JSObject-typed prototype. 147 static inline HeapObject* GetCodeCacheHolder(Isolate* isolate, 148 Object* object, 149 InlineCacheHolderFlag holder); 150 151 static inline InlineCacheHolderFlag GetCodeCacheFlag(Type* type); 152 static inline Handle<Map> GetCodeCacheHolder(InlineCacheHolderFlag flag, 153 Type* type, 154 Isolate* isolate); 155 156 static bool IsCleared(Code* code) { 157 InlineCacheState state = code->ic_state(); 158 return state == UNINITIALIZED || state == PREMONOMORPHIC; 159 } 160 161 // Utility functions to convert maps to types and back. There are two special 162 // cases: 163 // - The heap_number_map is used as a marker which includes heap numbers as 164 // well as smis. 165 // - The oddball map is only used for booleans. 166 static Handle<Map> TypeToMap(Type* type, Isolate* isolate); 167 static Type* MapToType(Handle<Map> type); 168 static Handle<Type> CurrentTypeOf(Handle<Object> object, Isolate* isolate); 169 170 protected: 171 // Get the call-site target; used for determining the state. 172 Handle<Code> target() const { return target_; } 173 174 Address fp() const { return fp_; } 175 Address pc() const { return *pc_address_; } 176 Isolate* isolate() const { return isolate_; } 177 178 #ifdef ENABLE_DEBUGGER_SUPPORT 179 // Computes the address in the original code when the code running is 180 // containing break points (calls to DebugBreakXXX builtins). 181 Address OriginalCodeAddress() const; 182 #endif 183 184 // Set the call-site target. 185 void set_target(Code* code) { 186 SetTargetAtAddress(address(), code); 187 target_set_ = true; 188 } 189 190 bool is_target_set() { return target_set_; } 191 192 #ifdef DEBUG 193 char TransitionMarkFromState(IC::State state); 194 195 void TraceIC(const char* type, Handle<Object> name); 196 #endif 197 198 Failure* TypeError(const char* type, 199 Handle<Object> object, 200 Handle<Object> key); 201 Failure* ReferenceError(const char* type, Handle<String> name); 202 203 // Access the target code for the given IC address. 204 static inline Code* GetTargetAtAddress(Address address); 205 static inline void SetTargetAtAddress(Address address, Code* target); 206 static void PostPatching(Address address, Code* target, Code* old_target); 207 208 // Compute the handler either by compiling or by retrieving a cached version. 209 Handle<Code> ComputeHandler(LookupResult* lookup, 210 Handle<Object> object, 211 Handle<String> name, 212 Handle<Object> value = Handle<Code>::null()); 213 virtual Handle<Code> CompileHandler(LookupResult* lookup, 214 Handle<Object> object, 215 Handle<String> name, 216 Handle<Object> value, 217 InlineCacheHolderFlag cache_holder) { 218 UNREACHABLE(); 219 return Handle<Code>::null(); 220 } 221 222 void UpdateMonomorphicIC(Handle<Type> type, 223 Handle<Code> handler, 224 Handle<String> name); 225 226 bool UpdatePolymorphicIC(Handle<Type> type, 227 Handle<String> name, 228 Handle<Code> code); 229 230 virtual void UpdateMegamorphicCache(Type* type, Name* name, Code* code); 231 232 void CopyICToMegamorphicCache(Handle<String> name); 233 bool IsTransitionOfMonomorphicTarget(Type* type); 234 void PatchCache(Handle<Type> type, 235 Handle<String> name, 236 Handle<Code> code); 237 virtual Code::Kind kind() const { 238 UNREACHABLE(); 239 return Code::STUB; 240 } 241 virtual Handle<Code> slow_stub() const { 242 UNREACHABLE(); 243 return Handle<Code>::null(); 244 } 245 virtual Handle<Code> megamorphic_stub() { 246 UNREACHABLE(); 247 return Handle<Code>::null(); 248 } 249 virtual Handle<Code> generic_stub() const { 250 UNREACHABLE(); 251 return Handle<Code>::null(); 252 } 253 254 bool TryRemoveInvalidPrototypeDependentStub(Handle<Object> receiver, 255 Handle<String> name); 256 void TryRemoveInvalidHandlers(Handle<Map> map, Handle<String> name); 257 258 virtual ExtraICState extra_ic_state() { return kNoExtraICState; } 259 260 private: 261 Code* raw_target() const { return GetTargetAtAddress(address()); } 262 263 // Frame pointer for the frame that uses (calls) the IC. 264 Address fp_; 265 266 // All access to the program counter of an IC structure is indirect 267 // to make the code GC safe. This feature is crucial since 268 // GetProperty and SetProperty are called and they in turn might 269 // invoke the garbage collector. 270 Address* pc_address_; 271 272 Isolate* isolate_; 273 274 // The original code target that missed. 275 Handle<Code> target_; 276 State state_; 277 bool target_set_; 278 279 DISALLOW_IMPLICIT_CONSTRUCTORS(IC); 280 }; 281 282 283 // An IC_Utility encapsulates IC::UtilityId. It exists mainly because you 284 // cannot make forward declarations to an enum. 285 class IC_Utility { 286 public: 287 explicit IC_Utility(IC::UtilityId id) 288 : address_(IC::AddressFromUtilityId(id)), id_(id) {} 289 290 Address address() const { return address_; } 291 292 IC::UtilityId id() const { return id_; } 293 private: 294 Address address_; 295 IC::UtilityId id_; 296 }; 297 298 299 class CallICBase: public IC { 300 public: 301 // ExtraICState bits 302 class Contextual: public BitField<ContextualMode, 0, 1> {}; 303 class StringStubState: public BitField<StringStubFeedback, 1, 1> {}; 304 static ExtraICState ComputeExtraICState(ContextualMode mode, 305 StringStubFeedback feedback) { 306 return Contextual::encode(mode) | StringStubState::encode(feedback); 307 } 308 309 // Returns a JSFunction or a Failure. 310 MUST_USE_RESULT MaybeObject* LoadFunction(Handle<Object> object, 311 Handle<String> name); 312 313 protected: 314 CallICBase(Code::Kind kind, Isolate* isolate) 315 : IC(EXTRA_CALL_FRAME, isolate), kind_(kind) {} 316 317 // Compute a monomorphic stub if possible, otherwise return a null handle. 318 Handle<Code> ComputeMonomorphicStub(LookupResult* lookup, 319 Handle<Object> object, 320 Handle<String> name); 321 322 // Update the inline cache and the global stub cache based on the lookup 323 // result. 324 void UpdateCaches(LookupResult* lookup, 325 Handle<Object> object, 326 Handle<String> name); 327 328 // Returns a JSFunction if the object can be called as a function, and 329 // patches the stack to be ready for the call. Otherwise, it returns the 330 // undefined value. 331 Handle<Object> TryCallAsFunction(Handle<Object> object); 332 333 void ReceiverToObjectIfRequired(Handle<Object> callee, Handle<Object> object); 334 335 static void Clear(Address address, Code* target); 336 337 // Platform-specific code generation functions used by both call and 338 // keyed call. 339 static void GenerateMiss(MacroAssembler* masm, 340 int argc, 341 IC::UtilityId id, 342 ExtraICState extra_state); 343 344 static void GenerateNormal(MacroAssembler* masm, int argc); 345 346 static void GenerateMonomorphicCacheProbe(MacroAssembler* masm, 347 int argc, 348 Code::Kind kind, 349 ExtraICState extra_state); 350 351 virtual Handle<Code> megamorphic_stub(); 352 virtual Handle<Code> pre_monomorphic_stub(); 353 354 Code::Kind kind_; 355 356 friend class IC; 357 }; 358 359 360 class CallIC: public CallICBase { 361 public: 362 explicit CallIC(Isolate* isolate) 363 : CallICBase(Code::CALL_IC, isolate), 364 extra_ic_state_(target()->extra_ic_state()) { 365 ASSERT(target()->is_call_stub()); 366 } 367 368 // Code generator routines. 369 static void GenerateInitialize(MacroAssembler* masm, 370 int argc, 371 ExtraICState extra_state) { 372 GenerateMiss(masm, argc, extra_state); 373 } 374 375 static void GenerateMiss(MacroAssembler* masm, 376 int argc, 377 ExtraICState extra_state) { 378 CallICBase::GenerateMiss(masm, argc, IC::kCallIC_Miss, extra_state); 379 } 380 381 static void GenerateMegamorphic(MacroAssembler* masm, 382 int argc, 383 ExtraICState extra_ic_state); 384 385 static void GenerateNormal(MacroAssembler* masm, int argc) { 386 CallICBase::GenerateNormal(masm, argc); 387 GenerateMiss(masm, argc, kNoExtraICState); 388 } 389 bool TryUpdateExtraICState(LookupResult* lookup, Handle<Object> object); 390 391 protected: 392 virtual ExtraICState extra_ic_state() { return extra_ic_state_; } 393 394 private: 395 ExtraICState extra_ic_state_; 396 }; 397 398 399 class KeyedCallIC: public CallICBase { 400 public: 401 explicit KeyedCallIC(Isolate* isolate) 402 : CallICBase(Code::KEYED_CALL_IC, isolate) { 403 ASSERT(target()->is_keyed_call_stub()); 404 } 405 406 MUST_USE_RESULT MaybeObject* LoadFunction(Handle<Object> object, 407 Handle<Object> key); 408 409 // Code generator routines. 410 static void GenerateInitialize(MacroAssembler* masm, int argc) { 411 GenerateMiss(masm, argc); 412 } 413 414 static void GenerateMiss(MacroAssembler* masm, int argc) { 415 CallICBase::GenerateMiss(masm, argc, IC::kKeyedCallIC_Miss, 416 kNoExtraICState); 417 } 418 419 static void GenerateMegamorphic(MacroAssembler* masm, int argc); 420 static void GenerateNormal(MacroAssembler* masm, int argc); 421 static void GenerateNonStrictArguments(MacroAssembler* masm, int argc); 422 }; 423 424 425 class LoadIC: public IC { 426 public: 427 explicit LoadIC(FrameDepth depth, Isolate* isolate) : IC(depth, isolate) { 428 ASSERT(IsLoadStub()); 429 } 430 431 // Code generator routines. 432 static void GenerateInitialize(MacroAssembler* masm) { GenerateMiss(masm); } 433 static void GeneratePreMonomorphic(MacroAssembler* masm) { 434 GenerateMiss(masm); 435 } 436 static void GenerateMiss(MacroAssembler* masm); 437 static void GenerateMegamorphic(MacroAssembler* masm); 438 static void GenerateNormal(MacroAssembler* masm); 439 static void GenerateRuntimeGetProperty(MacroAssembler* masm); 440 441 MUST_USE_RESULT MaybeObject* Load(Handle<Object> object, 442 Handle<String> name); 443 444 protected: 445 virtual Code::Kind kind() const { return Code::LOAD_IC; } 446 447 virtual Handle<Code> slow_stub() const { 448 return isolate()->builtins()->LoadIC_Slow(); 449 } 450 451 virtual Handle<Code> megamorphic_stub() { 452 return isolate()->builtins()->LoadIC_Megamorphic(); 453 } 454 455 // Update the inline cache and the global stub cache based on the 456 // lookup result. 457 void UpdateCaches(LookupResult* lookup, 458 Handle<Object> object, 459 Handle<String> name); 460 461 virtual Handle<Code> CompileHandler(LookupResult* lookup, 462 Handle<Object> object, 463 Handle<String> name, 464 Handle<Object> unused, 465 InlineCacheHolderFlag cache_holder); 466 467 private: 468 // Stub accessors. 469 static Handle<Code> initialize_stub(Isolate* isolate) { 470 return isolate->builtins()->LoadIC_Initialize(); 471 } 472 473 static Handle<Code> pre_monomorphic_stub(Isolate* isolate) { 474 return isolate->builtins()->LoadIC_PreMonomorphic(); 475 } 476 477 virtual Handle<Code> pre_monomorphic_stub() { 478 return pre_monomorphic_stub(isolate()); 479 } 480 481 Handle<Code> SimpleFieldLoad(int offset, 482 bool inobject = true, 483 Representation representation = 484 Representation::Tagged()); 485 486 static void Clear(Isolate* isolate, Address address, Code* target); 487 488 friend class IC; 489 }; 490 491 492 class KeyedLoadIC: public LoadIC { 493 public: 494 explicit KeyedLoadIC(FrameDepth depth, Isolate* isolate) 495 : LoadIC(depth, isolate) { 496 ASSERT(target()->is_keyed_load_stub()); 497 } 498 499 MUST_USE_RESULT MaybeObject* Load(Handle<Object> object, 500 Handle<Object> key); 501 502 // Code generator routines. 503 static void GenerateMiss(MacroAssembler* masm); 504 static void GenerateRuntimeGetProperty(MacroAssembler* masm); 505 static void GenerateInitialize(MacroAssembler* masm) { GenerateMiss(masm); } 506 static void GeneratePreMonomorphic(MacroAssembler* masm) { 507 GenerateMiss(masm); 508 } 509 static void GenerateGeneric(MacroAssembler* masm); 510 static void GenerateString(MacroAssembler* masm); 511 static void GenerateIndexedInterceptor(MacroAssembler* masm); 512 static void GenerateNonStrictArguments(MacroAssembler* masm); 513 514 // Bit mask to be tested against bit field for the cases when 515 // generic stub should go into slow case. 516 // Access check is necessary explicitly since generic stub does not perform 517 // map checks. 518 static const int kSlowCaseBitFieldMask = 519 (1 << Map::kIsAccessCheckNeeded) | (1 << Map::kHasIndexedInterceptor); 520 521 protected: 522 virtual Code::Kind kind() const { return Code::KEYED_LOAD_IC; } 523 524 Handle<Code> LoadElementStub(Handle<JSObject> receiver); 525 526 virtual Handle<Code> megamorphic_stub() { 527 return isolate()->builtins()->KeyedLoadIC_Generic(); 528 } 529 virtual Handle<Code> generic_stub() const { 530 return isolate()->builtins()->KeyedLoadIC_Generic(); 531 } 532 virtual Handle<Code> slow_stub() const { 533 return isolate()->builtins()->KeyedLoadIC_Slow(); 534 } 535 536 virtual void UpdateMegamorphicCache(Type* type, Name* name, Code* code) { } 537 538 private: 539 // Stub accessors. 540 static Handle<Code> initialize_stub(Isolate* isolate) { 541 return isolate->builtins()->KeyedLoadIC_Initialize(); 542 } 543 static Handle<Code> pre_monomorphic_stub(Isolate* isolate) { 544 return isolate->builtins()->KeyedLoadIC_PreMonomorphic(); 545 } 546 virtual Handle<Code> pre_monomorphic_stub() { 547 return pre_monomorphic_stub(isolate()); 548 } 549 Handle<Code> indexed_interceptor_stub() { 550 return isolate()->builtins()->KeyedLoadIC_IndexedInterceptor(); 551 } 552 Handle<Code> non_strict_arguments_stub() { 553 return isolate()->builtins()->KeyedLoadIC_NonStrictArguments(); 554 } 555 Handle<Code> string_stub() { 556 return isolate()->builtins()->KeyedLoadIC_String(); 557 } 558 559 static void Clear(Isolate* isolate, Address address, Code* target); 560 561 friend class IC; 562 }; 563 564 565 class StoreIC: public IC { 566 public: 567 // ExtraICState bits 568 class StrictModeState: public BitField<StrictModeFlag, 0, 1> {}; 569 static ExtraICState ComputeExtraICState(StrictModeFlag flag) { 570 return StrictModeState::encode(flag); 571 } 572 573 static StrictModeFlag GetStrictMode(ExtraICState state) { 574 return StrictModeState::decode(state); 575 } 576 577 // For convenience, a statically declared encoding of strict mode extra 578 // IC state. 579 static const ExtraICState kStrictModeState = 580 1 << StrictModeState::kShift; 581 582 StoreIC(FrameDepth depth, Isolate* isolate) 583 : IC(depth, isolate), 584 strict_mode_(GetStrictMode(target()->extra_ic_state())) { 585 ASSERT(IsStoreStub()); 586 } 587 588 StrictModeFlag strict_mode() const { return strict_mode_; } 589 590 // Code generators for stub routines. Only called once at startup. 591 static void GenerateSlow(MacroAssembler* masm); 592 static void GenerateInitialize(MacroAssembler* masm) { GenerateMiss(masm); } 593 static void GeneratePreMonomorphic(MacroAssembler* masm) { 594 GenerateMiss(masm); 595 } 596 static void GenerateMiss(MacroAssembler* masm); 597 static void GenerateMegamorphic(MacroAssembler* masm, 598 ExtraICState extra_ic_state); 599 static void GenerateNormal(MacroAssembler* masm); 600 static void GenerateRuntimeSetProperty(MacroAssembler* masm, 601 StrictModeFlag strict_mode); 602 603 MUST_USE_RESULT MaybeObject* Store( 604 Handle<Object> object, 605 Handle<String> name, 606 Handle<Object> value, 607 JSReceiver::StoreFromKeyed store_mode = 608 JSReceiver::CERTAINLY_NOT_STORE_FROM_KEYED); 609 610 protected: 611 virtual Code::Kind kind() const { return Code::STORE_IC; } 612 virtual Handle<Code> megamorphic_stub() { 613 if (strict_mode() == kStrictMode) { 614 return isolate()->builtins()->StoreIC_Megamorphic_Strict(); 615 } else { 616 return isolate()->builtins()->StoreIC_Megamorphic(); 617 } 618 } 619 // Stub accessors. 620 virtual Handle<Code> generic_stub() const { 621 if (strict_mode() == kStrictMode) { 622 return isolate()->builtins()->StoreIC_Generic_Strict(); 623 } else { 624 return isolate()->builtins()->StoreIC_Generic(); 625 } 626 } 627 628 virtual Handle<Code> slow_stub() const { 629 return isolate()->builtins()->StoreIC_Slow(); 630 } 631 632 virtual Handle<Code> pre_monomorphic_stub() { 633 return pre_monomorphic_stub(isolate(), strict_mode()); 634 } 635 636 static Handle<Code> pre_monomorphic_stub(Isolate* isolate, 637 StrictModeFlag strict_mode) { 638 if (strict_mode == kStrictMode) { 639 return isolate->builtins()->StoreIC_PreMonomorphic_Strict(); 640 } else { 641 return isolate->builtins()->StoreIC_PreMonomorphic(); 642 } 643 } 644 645 // Update the inline cache and the global stub cache based on the 646 // lookup result. 647 void UpdateCaches(LookupResult* lookup, 648 Handle<JSObject> receiver, 649 Handle<String> name, 650 Handle<Object> value); 651 virtual Handle<Code> CompileHandler(LookupResult* lookup, 652 Handle<Object> object, 653 Handle<String> name, 654 Handle<Object> value, 655 InlineCacheHolderFlag cache_holder); 656 657 virtual ExtraICState extra_ic_state() { 658 return ComputeExtraICState(strict_mode()); 659 } 660 661 private: 662 void set_target(Code* code) { 663 // Strict mode must be preserved across IC patching. 664 ASSERT(GetStrictMode(code->extra_ic_state()) == 665 GetStrictMode(target()->extra_ic_state())); 666 IC::set_target(code); 667 } 668 669 static Handle<Code> initialize_stub(Isolate* isolate, 670 StrictModeFlag strict_mode) { 671 if (strict_mode == kStrictMode) { 672 return isolate->builtins()->StoreIC_Initialize_Strict(); 673 } else { 674 return isolate->builtins()->StoreIC_Initialize(); 675 } 676 } 677 678 static void Clear(Isolate* isolate, Address address, Code* target); 679 680 StrictModeFlag strict_mode_; 681 682 friend class IC; 683 }; 684 685 686 enum KeyedStoreCheckMap { 687 kDontCheckMap, 688 kCheckMap 689 }; 690 691 692 enum KeyedStoreIncrementLength { 693 kDontIncrementLength, 694 kIncrementLength 695 }; 696 697 698 class KeyedStoreIC: public StoreIC { 699 public: 700 // ExtraICState bits (building on IC) 701 // ExtraICState bits 702 class ExtraICStateKeyedAccessStoreMode: 703 public BitField<KeyedAccessStoreMode, 1, 4> {}; // NOLINT 704 705 static ExtraICState ComputeExtraICState(StrictModeFlag flag, 706 KeyedAccessStoreMode mode) { 707 return StrictModeState::encode(flag) | 708 ExtraICStateKeyedAccessStoreMode::encode(mode); 709 } 710 711 static KeyedAccessStoreMode GetKeyedAccessStoreMode( 712 ExtraICState extra_state) { 713 return ExtraICStateKeyedAccessStoreMode::decode(extra_state); 714 } 715 716 KeyedStoreIC(FrameDepth depth, Isolate* isolate) 717 : StoreIC(depth, isolate) { 718 ASSERT(target()->is_keyed_store_stub()); 719 } 720 721 MUST_USE_RESULT MaybeObject* Store(Handle<Object> object, 722 Handle<Object> name, 723 Handle<Object> value); 724 725 // Code generators for stub routines. Only called once at startup. 726 static void GenerateInitialize(MacroAssembler* masm) { GenerateMiss(masm); } 727 static void GeneratePreMonomorphic(MacroAssembler* masm) { 728 GenerateMiss(masm); 729 } 730 static void GenerateMiss(MacroAssembler* masm); 731 static void GenerateSlow(MacroAssembler* masm); 732 static void GenerateRuntimeSetProperty(MacroAssembler* masm, 733 StrictModeFlag strict_mode); 734 static void GenerateGeneric(MacroAssembler* masm, StrictModeFlag strict_mode); 735 static void GenerateNonStrictArguments(MacroAssembler* masm); 736 737 protected: 738 virtual Code::Kind kind() const { return Code::KEYED_STORE_IC; } 739 740 virtual void UpdateMegamorphicCache(Type* type, Name* name, Code* code) { } 741 742 virtual ExtraICState extra_ic_state() { 743 return ComputeExtraICState(strict_mode(), STANDARD_STORE); 744 } 745 746 virtual Handle<Code> pre_monomorphic_stub() { 747 return pre_monomorphic_stub(isolate(), strict_mode()); 748 } 749 static Handle<Code> pre_monomorphic_stub(Isolate* isolate, 750 StrictModeFlag strict_mode) { 751 if (strict_mode == kStrictMode) { 752 return isolate->builtins()->KeyedStoreIC_PreMonomorphic_Strict(); 753 } else { 754 return isolate->builtins()->KeyedStoreIC_PreMonomorphic(); 755 } 756 } 757 virtual Handle<Code> slow_stub() const { 758 return isolate()->builtins()->KeyedStoreIC_Slow(); 759 } 760 virtual Handle<Code> megamorphic_stub() { 761 if (strict_mode() == kStrictMode) { 762 return isolate()->builtins()->KeyedStoreIC_Generic_Strict(); 763 } else { 764 return isolate()->builtins()->KeyedStoreIC_Generic(); 765 } 766 } 767 768 Handle<Code> StoreElementStub(Handle<JSObject> receiver, 769 KeyedAccessStoreMode store_mode); 770 771 private: 772 void set_target(Code* code) { 773 // Strict mode must be preserved across IC patching. 774 ASSERT(GetStrictMode(code->extra_ic_state()) == strict_mode()); 775 IC::set_target(code); 776 } 777 778 // Stub accessors. 779 static Handle<Code> initialize_stub(Isolate* isolate, 780 StrictModeFlag strict_mode) { 781 if (strict_mode == kStrictMode) { 782 return isolate->builtins()->KeyedStoreIC_Initialize_Strict(); 783 } else { 784 return isolate->builtins()->KeyedStoreIC_Initialize(); 785 } 786 } 787 788 virtual Handle<Code> generic_stub() const { 789 if (strict_mode() == kStrictMode) { 790 return isolate()->builtins()->KeyedStoreIC_Generic_Strict(); 791 } else { 792 return isolate()->builtins()->KeyedStoreIC_Generic(); 793 } 794 } 795 796 Handle<Code> non_strict_arguments_stub() { 797 return isolate()->builtins()->KeyedStoreIC_NonStrictArguments(); 798 } 799 800 static void Clear(Isolate* isolate, Address address, Code* target); 801 802 KeyedAccessStoreMode GetStoreMode(Handle<JSObject> receiver, 803 Handle<Object> key, 804 Handle<Object> value); 805 806 Handle<Map> ComputeTransitionedMap(Handle<JSObject> receiver, 807 KeyedAccessStoreMode store_mode); 808 809 friend class IC; 810 }; 811 812 813 // Mode to overwrite BinaryExpression values. 814 enum OverwriteMode { NO_OVERWRITE, OVERWRITE_LEFT, OVERWRITE_RIGHT }; 815 816 // Type Recording BinaryOpIC, that records the types of the inputs and outputs. 817 class BinaryOpIC: public IC { 818 public: 819 class State V8_FINAL BASE_EMBEDDED { 820 public: 821 explicit State(ExtraICState extra_ic_state); 822 823 State(Token::Value op, OverwriteMode mode) 824 : op_(op), mode_(mode), left_kind_(NONE), right_kind_(NONE), 825 result_kind_(NONE) { 826 ASSERT_LE(FIRST_TOKEN, op); 827 ASSERT_LE(op, LAST_TOKEN); 828 } 829 830 InlineCacheState GetICState() const { 831 if (Max(left_kind_, right_kind_) == NONE) { 832 return ::v8::internal::UNINITIALIZED; 833 } 834 if (Max(left_kind_, right_kind_) == GENERIC) { 835 return ::v8::internal::MEGAMORPHIC; 836 } 837 if (Min(left_kind_, right_kind_) == GENERIC) { 838 return ::v8::internal::GENERIC; 839 } 840 return ::v8::internal::MONOMORPHIC; 841 } 842 843 ExtraICState GetExtraICState() const; 844 845 static void GenerateAheadOfTime( 846 Isolate*, void (*Generate)(Isolate*, const State&)); 847 848 bool CanReuseDoubleBox() const { 849 return (result_kind_ > SMI && result_kind_ <= NUMBER) && 850 ((mode_ == OVERWRITE_LEFT && 851 left_kind_ > SMI && left_kind_ <= NUMBER) || 852 (mode_ == OVERWRITE_RIGHT && 853 right_kind_ > SMI && right_kind_ <= NUMBER)); 854 } 855 856 bool HasSideEffects() const { 857 return Max(left_kind_, right_kind_) == GENERIC; 858 } 859 860 bool UseInlinedSmiCode() const { 861 return KindMaybeSmi(left_kind_) || KindMaybeSmi(right_kind_); 862 } 863 864 static const int FIRST_TOKEN = Token::BIT_OR; 865 static const int LAST_TOKEN = Token::MOD; 866 867 Token::Value op() const { return op_; } 868 OverwriteMode mode() const { return mode_; } 869 Maybe<int> fixed_right_arg() const { return fixed_right_arg_; } 870 871 Handle<Type> GetLeftType(Isolate* isolate) const { 872 return KindToType(left_kind_, isolate); 873 } 874 Handle<Type> GetRightType(Isolate* isolate) const { 875 return KindToType(right_kind_, isolate); 876 } 877 Handle<Type> GetResultType(Isolate* isolate) const; 878 879 void Print(StringStream* stream) const; 880 881 void Update(Handle<Object> left, 882 Handle<Object> right, 883 Handle<Object> result); 884 885 private: 886 enum Kind { NONE, SMI, INT32, NUMBER, STRING, GENERIC }; 887 888 Kind UpdateKind(Handle<Object> object, Kind kind) const; 889 890 static const char* KindToString(Kind kind); 891 static Handle<Type> KindToType(Kind kind, Isolate* isolate); 892 static bool KindMaybeSmi(Kind kind) { 893 return (kind >= SMI && kind <= NUMBER) || kind == GENERIC; 894 } 895 896 // We truncate the last bit of the token. 897 STATIC_ASSERT(LAST_TOKEN - FIRST_TOKEN < (1 << 4)); 898 class OpField: public BitField<int, 0, 4> {}; 899 class OverwriteModeField: public BitField<OverwriteMode, 4, 2> {}; 900 class SSE2Field: public BitField<bool, 6, 1> {}; 901 class ResultKindField: public BitField<Kind, 7, 3> {}; 902 class LeftKindField: public BitField<Kind, 10, 3> {}; 903 // When fixed right arg is set, we don't need to store the right kind. 904 // Thus the two fields can overlap. 905 class HasFixedRightArgField: public BitField<bool, 13, 1> {}; 906 class FixedRightArgValueField: public BitField<int, 14, 4> {}; 907 class RightKindField: public BitField<Kind, 14, 3> {}; 908 909 Token::Value op_; 910 OverwriteMode mode_; 911 Kind left_kind_; 912 Kind right_kind_; 913 Kind result_kind_; 914 Maybe<int> fixed_right_arg_; 915 }; 916 917 explicit BinaryOpIC(Isolate* isolate) : IC(EXTRA_CALL_FRAME, isolate) { } 918 919 static Builtins::JavaScript TokenToJSBuiltin(Token::Value op); 920 921 MUST_USE_RESULT MaybeObject* Transition(Handle<Object> left, 922 Handle<Object> right); 923 }; 924 925 926 class CompareIC: public IC { 927 public: 928 // The type/state lattice is defined by the following inequations: 929 // UNINITIALIZED < ... 930 // ... < GENERIC 931 // SMI < NUMBER 932 // INTERNALIZED_STRING < STRING 933 // KNOWN_OBJECT < OBJECT 934 enum State { 935 UNINITIALIZED, 936 SMI, 937 NUMBER, 938 STRING, 939 INTERNALIZED_STRING, 940 UNIQUE_NAME, // Symbol or InternalizedString 941 OBJECT, // JSObject 942 KNOWN_OBJECT, // JSObject with specific map (faster check) 943 GENERIC 944 }; 945 946 static State NewInputState(State old_state, Handle<Object> value); 947 948 static Handle<Type> StateToType(Isolate* isolate, 949 State state, 950 Handle<Map> map = Handle<Map>()); 951 952 static void StubInfoToType(int stub_minor_key, 953 Handle<Type>* left_type, 954 Handle<Type>* right_type, 955 Handle<Type>* overall_type, 956 Handle<Map> map, 957 Isolate* isolate); 958 959 CompareIC(Isolate* isolate, Token::Value op) 960 : IC(EXTRA_CALL_FRAME, isolate), op_(op) { } 961 962 // Update the inline cache for the given operands. 963 Code* UpdateCaches(Handle<Object> x, Handle<Object> y); 964 965 966 // Factory method for getting an uninitialized compare stub. 967 static Handle<Code> GetUninitialized(Isolate* isolate, Token::Value op); 968 969 // Helper function for computing the condition for a compare operation. 970 static Condition ComputeCondition(Token::Value op); 971 972 static const char* GetStateName(State state); 973 974 private: 975 static bool HasInlinedSmiCode(Address address); 976 977 State TargetState(State old_state, 978 State old_left, 979 State old_right, 980 bool has_inlined_smi_code, 981 Handle<Object> x, 982 Handle<Object> y); 983 984 bool strict() const { return op_ == Token::EQ_STRICT; } 985 Condition GetCondition() const { return ComputeCondition(op_); } 986 987 static Code* GetRawUninitialized(Isolate* isolate, Token::Value op); 988 989 static void Clear(Isolate* isolate, Address address, Code* target); 990 991 Token::Value op_; 992 993 friend class IC; 994 }; 995 996 997 class CompareNilIC: public IC { 998 public: 999 explicit CompareNilIC(Isolate* isolate) : IC(EXTRA_CALL_FRAME, isolate) {} 1000 1001 MUST_USE_RESULT MaybeObject* CompareNil(Handle<Object> object); 1002 1003 static Handle<Code> GetUninitialized(); 1004 1005 static void Clear(Address address, Code* target); 1006 1007 static MUST_USE_RESULT MaybeObject* DoCompareNilSlow(NilValue nil, 1008 Handle<Object> object); 1009 }; 1010 1011 1012 class ToBooleanIC: public IC { 1013 public: 1014 explicit ToBooleanIC(Isolate* isolate) : IC(EXTRA_CALL_FRAME, isolate) { } 1015 1016 MaybeObject* ToBoolean(Handle<Object> object); 1017 }; 1018 1019 1020 // Helper for BinaryOpIC and CompareIC. 1021 enum InlinedSmiCheck { ENABLE_INLINED_SMI_CHECK, DISABLE_INLINED_SMI_CHECK }; 1022 void PatchInlinedSmiCode(Address address, InlinedSmiCheck check); 1023 1024 DECLARE_RUNTIME_FUNCTION(MaybeObject*, KeyedLoadIC_MissFromStubFailure); 1025 DECLARE_RUNTIME_FUNCTION(MaybeObject*, KeyedStoreIC_MissFromStubFailure); 1026 DECLARE_RUNTIME_FUNCTION(MaybeObject*, UnaryOpIC_Miss); 1027 DECLARE_RUNTIME_FUNCTION(MaybeObject*, StoreIC_MissFromStubFailure); 1028 DECLARE_RUNTIME_FUNCTION(MaybeObject*, KeyedCallIC_MissFromStubFailure); 1029 DECLARE_RUNTIME_FUNCTION(MaybeObject*, ElementsTransitionAndStoreIC_Miss); 1030 DECLARE_RUNTIME_FUNCTION(MaybeObject*, BinaryOpIC_Miss); 1031 DECLARE_RUNTIME_FUNCTION(MaybeObject*, CompareNilIC_Miss); 1032 DECLARE_RUNTIME_FUNCTION(MaybeObject*, ToBooleanIC_Miss); 1033 1034 1035 } } // namespace v8::internal 1036 1037 #endif // V8_IC_H_ 1038