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