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(KeyedLoadIC_MissForceGeneric) \ 44 ICU(CallIC_Miss) \ 45 ICU(KeyedCallIC_Miss) \ 46 ICU(StoreIC_Miss) \ 47 ICU(StoreIC_ArrayLength) \ 48 ICU(SharedStoreIC_ExtendStorage) \ 49 ICU(KeyedStoreIC_Miss) \ 50 ICU(KeyedStoreIC_MissForceGeneric) \ 51 ICU(KeyedStoreIC_Slow) \ 52 /* Utilities for IC stubs. */ \ 53 ICU(LoadCallbackProperty) \ 54 ICU(StoreCallbackProperty) \ 55 ICU(LoadPropertyWithInterceptorOnly) \ 56 ICU(LoadPropertyWithInterceptorForLoad) \ 57 ICU(LoadPropertyWithInterceptorForCall) \ 58 ICU(KeyedLoadPropertyWithInterceptor) \ 59 ICU(StoreInterceptorProperty) \ 60 ICU(UnaryOp_Patch) \ 61 ICU(BinaryOp_Patch) \ 62 ICU(CompareIC_Miss) \ 63 ICU(ToBoolean_Patch) 64 // 65 // IC is the base class for LoadIC, StoreIC, CallIC, KeyedLoadIC, 66 // and KeyedStoreIC. 67 // 68 class IC { 69 public: 70 // The ids for utility called from the generated code. 71 enum UtilityId { 72 #define CONST_NAME(name) k##name, 73 IC_UTIL_LIST(CONST_NAME) 74 #undef CONST_NAME 75 kUtilityCount 76 }; 77 78 // Looks up the address of the named utility. 79 static Address AddressFromUtilityId(UtilityId id); 80 81 // Alias the inline cache state type to make the IC code more readable. 82 typedef InlineCacheState State; 83 84 // The IC code is either invoked with no extra frames on the stack 85 // or with a single extra frame for supporting calls. 86 enum FrameDepth { 87 NO_EXTRA_FRAME = 0, 88 EXTRA_CALL_FRAME = 1 89 }; 90 91 // Construct the IC structure with the given number of extra 92 // JavaScript frames on the stack. 93 IC(FrameDepth depth, Isolate* isolate); 94 virtual ~IC() {} 95 96 // Get the call-site target; used for determining the state. 97 Code* target() const { return GetTargetAtAddress(address()); } 98 inline Address address() const; 99 100 virtual bool IsGeneric() const { return false; } 101 102 // Compute the current IC state based on the target stub, receiver and name. 103 static State StateFrom(Code* target, Object* receiver, Object* name); 104 105 // Clear the inline cache to initial state. 106 static void Clear(Address address); 107 108 // Computes the reloc info for this IC. This is a fairly expensive 109 // operation as it has to search through the heap to find the code 110 // object that contains this IC site. 111 RelocInfo::Mode ComputeMode(); 112 113 // Returns if this IC is for contextual (no explicit receiver) 114 // access to properties. 115 bool IsContextual(Handle<Object> receiver) { 116 if (receiver->IsGlobalObject()) { 117 return SlowIsContextual(); 118 } else { 119 ASSERT(!SlowIsContextual()); 120 return false; 121 } 122 } 123 124 bool SlowIsContextual() { 125 return ComputeMode() == RelocInfo::CODE_TARGET_CONTEXT; 126 } 127 128 // Determines which map must be used for keeping the code stub. 129 // These methods should not be called with undefined or null. 130 static inline InlineCacheHolderFlag GetCodeCacheForObject(Object* object, 131 JSObject* holder); 132 static inline InlineCacheHolderFlag GetCodeCacheForObject(JSObject* object, 133 JSObject* holder); 134 static inline JSObject* GetCodeCacheHolder(Object* object, 135 InlineCacheHolderFlag holder); 136 137 protected: 138 Address fp() const { return fp_; } 139 Address pc() const { return *pc_address_; } 140 Isolate* isolate() const { return isolate_; } 141 142 #ifdef ENABLE_DEBUGGER_SUPPORT 143 // Computes the address in the original code when the code running is 144 // containing break points (calls to DebugBreakXXX builtins). 145 Address OriginalCodeAddress() const; 146 #endif 147 148 // Set the call-site target. 149 void set_target(Code* code) { SetTargetAtAddress(address(), code); } 150 151 #ifdef DEBUG 152 char TransitionMarkFromState(IC::State state); 153 154 void TraceIC(const char* type, 155 Handle<Object> name, 156 State old_state, 157 Code* new_target); 158 #endif 159 160 Failure* TypeError(const char* type, 161 Handle<Object> object, 162 Handle<Object> key); 163 Failure* ReferenceError(const char* type, Handle<String> name); 164 165 // Access the target code for the given IC address. 166 static inline Code* GetTargetAtAddress(Address address); 167 static inline void SetTargetAtAddress(Address address, Code* target); 168 static void PostPatching(Address address, Code* target, Code* old_target); 169 170 private: 171 // Frame pointer for the frame that uses (calls) the IC. 172 Address fp_; 173 174 // All access to the program counter of an IC structure is indirect 175 // to make the code GC safe. This feature is crucial since 176 // GetProperty and SetProperty are called and they in turn might 177 // invoke the garbage collector. 178 Address* pc_address_; 179 180 Isolate* isolate_; 181 182 DISALLOW_IMPLICIT_CONSTRUCTORS(IC); 183 }; 184 185 186 // An IC_Utility encapsulates IC::UtilityId. It exists mainly because you 187 // cannot make forward declarations to an enum. 188 class IC_Utility { 189 public: 190 explicit IC_Utility(IC::UtilityId id) 191 : address_(IC::AddressFromUtilityId(id)), id_(id) {} 192 193 Address address() const { return address_; } 194 195 IC::UtilityId id() const { return id_; } 196 private: 197 Address address_; 198 IC::UtilityId id_; 199 }; 200 201 202 class CallICBase: public IC { 203 public: 204 class Contextual: public BitField<bool, 0, 1> {}; 205 class StringStubState: public BitField<StringStubFeedback, 1, 1> {}; 206 207 // Returns a JSFunction or a Failure. 208 MUST_USE_RESULT MaybeObject* LoadFunction(State state, 209 Code::ExtraICState extra_ic_state, 210 Handle<Object> object, 211 Handle<String> name); 212 213 protected: 214 CallICBase(Code::Kind kind, Isolate* isolate) 215 : IC(EXTRA_CALL_FRAME, isolate), kind_(kind) {} 216 217 bool TryUpdateExtraICState(LookupResult* lookup, 218 Handle<Object> object, 219 Code::ExtraICState* extra_ic_state); 220 221 // Compute a monomorphic stub if possible, otherwise return a null handle. 222 Handle<Code> ComputeMonomorphicStub(LookupResult* lookup, 223 State state, 224 Code::ExtraICState extra_state, 225 Handle<Object> object, 226 Handle<String> name); 227 228 // Update the inline cache and the global stub cache based on the lookup 229 // result. 230 void UpdateCaches(LookupResult* lookup, 231 State state, 232 Code::ExtraICState extra_ic_state, 233 Handle<Object> object, 234 Handle<String> name); 235 236 // Returns a JSFunction if the object can be called as a function, and 237 // patches the stack to be ready for the call. Otherwise, it returns the 238 // undefined value. 239 Handle<Object> TryCallAsFunction(Handle<Object> object); 240 241 void ReceiverToObjectIfRequired(Handle<Object> callee, Handle<Object> object); 242 243 static void Clear(Address address, Code* target); 244 245 // Platform-specific code generation functions used by both call and 246 // keyed call. 247 static void GenerateMiss(MacroAssembler* masm, 248 int argc, 249 IC::UtilityId id, 250 Code::ExtraICState extra_state); 251 252 static void GenerateNormal(MacroAssembler* masm, int argc); 253 254 static void GenerateMonomorphicCacheProbe(MacroAssembler* masm, 255 int argc, 256 Code::Kind kind, 257 Code::ExtraICState extra_state); 258 259 Code::Kind kind_; 260 261 friend class IC; 262 }; 263 264 265 class CallIC: public CallICBase { 266 public: 267 explicit CallIC(Isolate* isolate) : CallICBase(Code::CALL_IC, isolate) { 268 ASSERT(target()->is_call_stub()); 269 } 270 271 // Code generator routines. 272 static void GenerateInitialize(MacroAssembler* masm, 273 int argc, 274 Code::ExtraICState extra_state) { 275 GenerateMiss(masm, argc, extra_state); 276 } 277 278 static void GenerateMiss(MacroAssembler* masm, 279 int argc, 280 Code::ExtraICState extra_state) { 281 CallICBase::GenerateMiss(masm, argc, IC::kCallIC_Miss, extra_state); 282 } 283 284 static void GenerateMegamorphic(MacroAssembler* masm, 285 int argc, 286 Code::ExtraICState extra_ic_state); 287 288 static void GenerateNormal(MacroAssembler* masm, int argc) { 289 CallICBase::GenerateNormal(masm, argc); 290 GenerateMiss(masm, argc, Code::kNoExtraICState); 291 } 292 }; 293 294 295 class KeyedCallIC: public CallICBase { 296 public: 297 explicit KeyedCallIC(Isolate* isolate) 298 : CallICBase(Code::KEYED_CALL_IC, isolate) { 299 ASSERT(target()->is_keyed_call_stub()); 300 } 301 302 MUST_USE_RESULT MaybeObject* LoadFunction(State state, 303 Handle<Object> object, 304 Handle<Object> key); 305 306 // Code generator routines. 307 static void GenerateInitialize(MacroAssembler* masm, int argc) { 308 GenerateMiss(masm, argc); 309 } 310 311 static void GenerateMiss(MacroAssembler* masm, int argc) { 312 CallICBase::GenerateMiss(masm, argc, IC::kKeyedCallIC_Miss, 313 Code::kNoExtraICState); 314 } 315 316 static void GenerateMegamorphic(MacroAssembler* masm, int argc); 317 static void GenerateNormal(MacroAssembler* masm, int argc); 318 static void GenerateNonStrictArguments(MacroAssembler* masm, int argc); 319 }; 320 321 322 class LoadIC: public IC { 323 public: 324 explicit LoadIC(Isolate* isolate) : IC(NO_EXTRA_FRAME, isolate) { 325 ASSERT(target()->is_load_stub()); 326 } 327 328 MUST_USE_RESULT MaybeObject* Load(State state, 329 Handle<Object> object, 330 Handle<String> name); 331 332 // Code generator routines. 333 static void GenerateInitialize(MacroAssembler* masm) { GenerateMiss(masm); } 334 static void GeneratePreMonomorphic(MacroAssembler* masm) { 335 GenerateMiss(masm); 336 } 337 static void GenerateMiss(MacroAssembler* masm); 338 static void GenerateMegamorphic(MacroAssembler* masm); 339 static void GenerateNormal(MacroAssembler* masm); 340 341 // Specialized code generator routines. 342 static void GenerateArrayLength(MacroAssembler* masm); 343 static void GenerateStringLength(MacroAssembler* masm, 344 bool support_wrappers); 345 static void GenerateFunctionPrototype(MacroAssembler* masm); 346 347 private: 348 // Update the inline cache and the global stub cache based on the 349 // lookup result. 350 void UpdateCaches(LookupResult* lookup, 351 State state, 352 Handle<Object> object, 353 Handle<String> name); 354 355 // Stub accessors. 356 Handle<Code> megamorphic_stub() { 357 return isolate()->builtins()->LoadIC_Megamorphic(); 358 } 359 static Code* initialize_stub() { 360 return Isolate::Current()->builtins()->builtin( 361 Builtins::kLoadIC_Initialize); 362 } 363 Handle<Code> pre_monomorphic_stub() { 364 return isolate()->builtins()->LoadIC_PreMonomorphic(); 365 } 366 367 static void Clear(Address address, Code* target); 368 369 friend class IC; 370 }; 371 372 373 class KeyedIC: public IC { 374 public: 375 enum StubKind { 376 LOAD, 377 STORE_NO_TRANSITION, 378 STORE_TRANSITION_SMI_TO_OBJECT, 379 STORE_TRANSITION_SMI_TO_DOUBLE, 380 STORE_TRANSITION_DOUBLE_TO_OBJECT, 381 STORE_AND_GROW_NO_TRANSITION, 382 STORE_AND_GROW_TRANSITION_SMI_TO_OBJECT, 383 STORE_AND_GROW_TRANSITION_SMI_TO_DOUBLE, 384 STORE_AND_GROW_TRANSITION_DOUBLE_TO_OBJECT 385 }; 386 387 static const int kGrowICDelta = STORE_AND_GROW_NO_TRANSITION - 388 STORE_NO_TRANSITION; 389 STATIC_ASSERT(kGrowICDelta == 390 STORE_AND_GROW_TRANSITION_SMI_TO_OBJECT - 391 STORE_TRANSITION_SMI_TO_OBJECT); 392 STATIC_ASSERT(kGrowICDelta == 393 STORE_AND_GROW_TRANSITION_SMI_TO_DOUBLE - 394 STORE_TRANSITION_SMI_TO_DOUBLE); 395 STATIC_ASSERT(kGrowICDelta == 396 STORE_AND_GROW_TRANSITION_DOUBLE_TO_OBJECT - 397 STORE_TRANSITION_DOUBLE_TO_OBJECT); 398 399 explicit KeyedIC(Isolate* isolate) : IC(NO_EXTRA_FRAME, isolate) {} 400 virtual ~KeyedIC() {} 401 402 static inline KeyedAccessGrowMode GetGrowModeFromStubKind( 403 StubKind stub_kind) { 404 return (stub_kind >= STORE_AND_GROW_NO_TRANSITION) 405 ? ALLOW_JSARRAY_GROWTH 406 : DO_NOT_ALLOW_JSARRAY_GROWTH; 407 } 408 409 static inline StubKind GetGrowStubKind(StubKind stub_kind) { 410 ASSERT(stub_kind != LOAD); 411 if (stub_kind < STORE_AND_GROW_NO_TRANSITION) { 412 stub_kind = static_cast<StubKind>(static_cast<int>(stub_kind) + 413 kGrowICDelta); 414 } 415 return stub_kind; 416 } 417 418 virtual Handle<Code> GetElementStubWithoutMapCheck( 419 bool is_js_array, 420 ElementsKind elements_kind, 421 KeyedAccessGrowMode grow_mode) = 0; 422 423 protected: 424 virtual Handle<Code> string_stub() { 425 return Handle<Code>::null(); 426 } 427 428 virtual Code::Kind kind() const = 0; 429 430 Handle<Code> ComputeStub(Handle<JSObject> receiver, 431 StubKind stub_kind, 432 StrictModeFlag strict_mode, 433 Handle<Code> default_stub); 434 435 virtual Handle<Code> ComputePolymorphicStub( 436 MapHandleList* receiver_maps, 437 StrictModeFlag strict_mode, 438 KeyedAccessGrowMode grow_mode) = 0; 439 440 Handle<Code> ComputeMonomorphicStubWithoutMapCheck( 441 Handle<Map> receiver_map, 442 StrictModeFlag strict_mode, 443 KeyedAccessGrowMode grow_mode); 444 445 private: 446 void GetReceiverMapsForStub(Handle<Code> stub, MapHandleList* result); 447 448 Handle<Code> ComputeMonomorphicStub(Handle<JSObject> receiver, 449 StubKind stub_kind, 450 StrictModeFlag strict_mode, 451 Handle<Code> default_stub); 452 453 Handle<Map> ComputeTransitionedMap(Handle<JSObject> receiver, 454 StubKind stub_kind); 455 456 static bool IsTransitionStubKind(StubKind stub_kind) { 457 return stub_kind > STORE_NO_TRANSITION && 458 stub_kind != STORE_AND_GROW_NO_TRANSITION; 459 } 460 461 static bool IsGrowStubKind(StubKind stub_kind) { 462 return stub_kind >= STORE_AND_GROW_NO_TRANSITION; 463 } 464 }; 465 466 467 class KeyedLoadIC: public KeyedIC { 468 public: 469 explicit KeyedLoadIC(Isolate* isolate) : KeyedIC(isolate) { 470 ASSERT(target()->is_keyed_load_stub()); 471 } 472 473 MUST_USE_RESULT MaybeObject* Load(State state, 474 Handle<Object> object, 475 Handle<Object> key, 476 bool force_generic_stub); 477 478 // Code generator routines. 479 static void GenerateMiss(MacroAssembler* masm, bool force_generic); 480 static void GenerateRuntimeGetProperty(MacroAssembler* masm); 481 static void GenerateInitialize(MacroAssembler* masm) { 482 GenerateMiss(masm, false); 483 } 484 static void GeneratePreMonomorphic(MacroAssembler* masm) { 485 GenerateMiss(masm, false); 486 } 487 static void GenerateGeneric(MacroAssembler* masm); 488 static void GenerateString(MacroAssembler* masm); 489 static void GenerateIndexedInterceptor(MacroAssembler* masm); 490 static void GenerateNonStrictArguments(MacroAssembler* masm); 491 492 // Bit mask to be tested against bit field for the cases when 493 // generic stub should go into slow case. 494 // Access check is necessary explicitly since generic stub does not perform 495 // map checks. 496 static const int kSlowCaseBitFieldMask = 497 (1 << Map::kIsAccessCheckNeeded) | (1 << Map::kHasIndexedInterceptor); 498 499 virtual Handle<Code> GetElementStubWithoutMapCheck( 500 bool is_js_array, 501 ElementsKind elements_kind, 502 KeyedAccessGrowMode grow_mode); 503 504 virtual bool IsGeneric() const { 505 return target() == *generic_stub(); 506 } 507 508 protected: 509 virtual Code::Kind kind() const { return Code::KEYED_LOAD_IC; } 510 511 virtual Handle<Code> ComputePolymorphicStub(MapHandleList* receiver_maps, 512 StrictModeFlag strict_mode, 513 KeyedAccessGrowMode grow_mode); 514 515 virtual Handle<Code> string_stub() { 516 return isolate()->builtins()->KeyedLoadIC_String(); 517 } 518 519 private: 520 // Update the inline cache. 521 void UpdateCaches(LookupResult* lookup, 522 State state, 523 Handle<Object> object, 524 Handle<String> name); 525 526 // Stub accessors. 527 static Code* initialize_stub() { 528 return Isolate::Current()->builtins()->builtin( 529 Builtins::kKeyedLoadIC_Initialize); 530 } 531 Handle<Code> megamorphic_stub() { 532 return isolate()->builtins()->KeyedLoadIC_Generic(); 533 } 534 Handle<Code> generic_stub() const { 535 return isolate()->builtins()->KeyedLoadIC_Generic(); 536 } 537 Handle<Code> pre_monomorphic_stub() { 538 return isolate()->builtins()->KeyedLoadIC_PreMonomorphic(); 539 } 540 Handle<Code> indexed_interceptor_stub() { 541 return isolate()->builtins()->KeyedLoadIC_IndexedInterceptor(); 542 } 543 Handle<Code> non_strict_arguments_stub() { 544 return isolate()->builtins()->KeyedLoadIC_NonStrictArguments(); 545 } 546 547 static void Clear(Address address, Code* target); 548 549 friend class IC; 550 }; 551 552 553 class StoreIC: public IC { 554 public: 555 explicit StoreIC(Isolate* isolate) : IC(NO_EXTRA_FRAME, isolate) { 556 ASSERT(target()->is_store_stub()); 557 } 558 559 MUST_USE_RESULT MaybeObject* Store(State state, 560 StrictModeFlag strict_mode, 561 Handle<Object> object, 562 Handle<String> name, 563 Handle<Object> value); 564 565 // Code generators for stub routines. Only called once at startup. 566 static void GenerateInitialize(MacroAssembler* masm) { GenerateMiss(masm); } 567 static void GenerateMiss(MacroAssembler* masm); 568 static void GenerateMegamorphic(MacroAssembler* masm, 569 StrictModeFlag strict_mode); 570 static void GenerateArrayLength(MacroAssembler* masm); 571 static void GenerateNormal(MacroAssembler* masm); 572 static void GenerateGlobalProxy(MacroAssembler* masm, 573 StrictModeFlag strict_mode); 574 575 private: 576 // Update the inline cache and the global stub cache based on the 577 // lookup result. 578 void UpdateCaches(LookupResult* lookup, 579 State state, 580 StrictModeFlag strict_mode, 581 Handle<JSObject> receiver, 582 Handle<String> name, 583 Handle<Object> value); 584 585 void set_target(Code* code) { 586 // Strict mode must be preserved across IC patching. 587 ASSERT(Code::GetStrictMode(code->extra_ic_state()) == 588 Code::GetStrictMode(target()->extra_ic_state())); 589 IC::set_target(code); 590 } 591 592 // Stub accessors. 593 Code* megamorphic_stub() { 594 return isolate()->builtins()->builtin( 595 Builtins::kStoreIC_Megamorphic); 596 } 597 Code* megamorphic_stub_strict() { 598 return isolate()->builtins()->builtin( 599 Builtins::kStoreIC_Megamorphic_Strict); 600 } 601 static Code* initialize_stub() { 602 return Isolate::Current()->builtins()->builtin( 603 Builtins::kStoreIC_Initialize); 604 } 605 static Code* initialize_stub_strict() { 606 return Isolate::Current()->builtins()->builtin( 607 Builtins::kStoreIC_Initialize_Strict); 608 } 609 Handle<Code> global_proxy_stub() { 610 return isolate()->builtins()->StoreIC_GlobalProxy(); 611 } 612 Handle<Code> global_proxy_stub_strict() { 613 return isolate()->builtins()->StoreIC_GlobalProxy_Strict(); 614 } 615 616 static void Clear(Address address, Code* target); 617 618 friend class IC; 619 }; 620 621 622 class KeyedStoreIC: public KeyedIC { 623 public: 624 explicit KeyedStoreIC(Isolate* isolate) : KeyedIC(isolate) { 625 ASSERT(target()->is_keyed_store_stub()); 626 } 627 628 MUST_USE_RESULT MaybeObject* Store(State state, 629 StrictModeFlag strict_mode, 630 Handle<Object> object, 631 Handle<Object> name, 632 Handle<Object> value, 633 bool force_generic); 634 635 // Code generators for stub routines. Only called once at startup. 636 static void GenerateInitialize(MacroAssembler* masm) { 637 GenerateMiss(masm, false); 638 } 639 static void GenerateMiss(MacroAssembler* masm, bool force_generic); 640 static void GenerateSlow(MacroAssembler* masm); 641 static void GenerateRuntimeSetProperty(MacroAssembler* masm, 642 StrictModeFlag strict_mode); 643 static void GenerateGeneric(MacroAssembler* masm, StrictModeFlag strict_mode); 644 static void GenerateNonStrictArguments(MacroAssembler* masm); 645 static void GenerateTransitionElementsSmiToDouble(MacroAssembler* masm); 646 static void GenerateTransitionElementsDoubleToObject(MacroAssembler* masm); 647 648 virtual Handle<Code> GetElementStubWithoutMapCheck( 649 bool is_js_array, 650 ElementsKind elements_kind, 651 KeyedAccessGrowMode grow_mode); 652 653 virtual bool IsGeneric() const { 654 return target() == *generic_stub() || 655 target() == *generic_stub_strict(); 656 } 657 658 protected: 659 virtual Code::Kind kind() const { return Code::KEYED_STORE_IC; } 660 661 virtual Handle<Code> ComputePolymorphicStub(MapHandleList* receiver_maps, 662 StrictModeFlag strict_mode, 663 KeyedAccessGrowMode grow_mode); 664 665 private: 666 // Update the inline cache. 667 void UpdateCaches(LookupResult* lookup, 668 State state, 669 StrictModeFlag strict_mode, 670 Handle<JSObject> receiver, 671 Handle<String> name, 672 Handle<Object> value); 673 674 void set_target(Code* code) { 675 // Strict mode must be preserved across IC patching. 676 ASSERT(Code::GetStrictMode(code->extra_ic_state()) == 677 Code::GetStrictMode(target()->extra_ic_state())); 678 IC::set_target(code); 679 } 680 681 // Stub accessors. 682 static Code* initialize_stub() { 683 return Isolate::Current()->builtins()->builtin( 684 Builtins::kKeyedStoreIC_Initialize); 685 } 686 static Code* initialize_stub_strict() { 687 return Isolate::Current()->builtins()->builtin( 688 Builtins::kKeyedStoreIC_Initialize_Strict); 689 } 690 Handle<Code> megamorphic_stub() { 691 return isolate()->builtins()->KeyedStoreIC_Generic(); 692 } 693 Handle<Code> megamorphic_stub_strict() { 694 return isolate()->builtins()->KeyedStoreIC_Generic_Strict(); 695 } 696 Handle<Code> generic_stub() const { 697 return isolate()->builtins()->KeyedStoreIC_Generic(); 698 } 699 Handle<Code> generic_stub_strict() const { 700 return isolate()->builtins()->KeyedStoreIC_Generic_Strict(); 701 } 702 Handle<Code> non_strict_arguments_stub() { 703 return isolate()->builtins()->KeyedStoreIC_NonStrictArguments(); 704 } 705 706 static void Clear(Address address, Code* target); 707 708 StubKind GetStubKind(Handle<JSObject> receiver, 709 Handle<Object> key, 710 Handle<Object> value); 711 712 friend class IC; 713 }; 714 715 716 class UnaryOpIC: public IC { 717 public: 718 // sorted: increasingly more unspecific (ignoring UNINITIALIZED) 719 // TODO(svenpanne) Using enums+switch is an antipattern, use a class instead. 720 enum TypeInfo { 721 UNINITIALIZED, 722 SMI, 723 HEAP_NUMBER, 724 GENERIC 725 }; 726 727 explicit UnaryOpIC(Isolate* isolate) : IC(NO_EXTRA_FRAME, isolate) { } 728 729 void patch(Code* code); 730 731 static const char* GetName(TypeInfo type_info); 732 733 static State ToState(TypeInfo type_info); 734 735 static TypeInfo GetTypeInfo(Handle<Object> operand); 736 737 static TypeInfo ComputeNewType(TypeInfo type, TypeInfo previous); 738 }; 739 740 741 // Type Recording BinaryOpIC, that records the types of the inputs and outputs. 742 class BinaryOpIC: public IC { 743 public: 744 enum TypeInfo { 745 UNINITIALIZED, 746 SMI, 747 INT32, 748 HEAP_NUMBER, 749 ODDBALL, 750 BOTH_STRING, // Only used for addition operation. 751 STRING, // Only used for addition operation. At least one string operand. 752 GENERIC 753 }; 754 755 explicit BinaryOpIC(Isolate* isolate) : IC(NO_EXTRA_FRAME, isolate) { } 756 757 void patch(Code* code); 758 759 static const char* GetName(TypeInfo type_info); 760 761 static State ToState(TypeInfo type_info); 762 763 static TypeInfo GetTypeInfo(Handle<Object> left, Handle<Object> right); 764 765 static TypeInfo JoinTypes(TypeInfo x, TypeInfo y); 766 }; 767 768 769 class CompareIC: public IC { 770 public: 771 enum State { 772 UNINITIALIZED, 773 SMIS, 774 HEAP_NUMBERS, 775 SYMBOLS, 776 STRINGS, 777 OBJECTS, 778 KNOWN_OBJECTS, 779 GENERIC 780 }; 781 782 CompareIC(Isolate* isolate, Token::Value op) 783 : IC(EXTRA_CALL_FRAME, isolate), op_(op) { } 784 785 // Update the inline cache for the given operands. 786 void UpdateCaches(Handle<Object> x, Handle<Object> y); 787 788 // Factory method for getting an uninitialized compare stub. 789 static Handle<Code> GetUninitialized(Token::Value op); 790 791 // Helper function for computing the condition for a compare operation. 792 static Condition ComputeCondition(Token::Value op); 793 794 // Helper function for determining the state of a compare IC. 795 static State ComputeState(Code* target); 796 797 static const char* GetStateName(State state); 798 799 private: 800 State TargetState(State state, bool has_inlined_smi_code, 801 Handle<Object> x, Handle<Object> y); 802 803 bool strict() const { return op_ == Token::EQ_STRICT; } 804 Condition GetCondition() const { return ComputeCondition(op_); } 805 State GetState() { return ComputeState(target()); } 806 807 Token::Value op_; 808 }; 809 810 811 class ToBooleanIC: public IC { 812 public: 813 explicit ToBooleanIC(Isolate* isolate) : IC(NO_EXTRA_FRAME, isolate) { } 814 815 void patch(Code* code); 816 }; 817 818 819 // Helper for BinaryOpIC and CompareIC. 820 void PatchInlinedSmiCode(Address address); 821 822 } } // namespace v8::internal 823 824 #endif // V8_IC_H_ 825