| OLD | NEW |
| 1 // Copyright 2012 the V8 project authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #ifndef V8_IC_H_ | 5 #ifndef V8_IC_H_ |
| 6 #define V8_IC_H_ | 6 #define V8_IC_H_ |
| 7 | 7 |
| 8 #include "src/ic/ic-state.h" |
| 8 #include "src/macro-assembler.h" | 9 #include "src/macro-assembler.h" |
| 9 | 10 |
| 10 namespace v8 { | 11 namespace v8 { |
| 11 namespace internal { | 12 namespace internal { |
| 12 | 13 |
| 13 | 14 |
| 14 const int kMaxKeyedPolymorphism = 4; | |
| 15 | |
| 16 | |
| 17 // IC_UTIL_LIST defines all utility functions called from generated | 15 // IC_UTIL_LIST defines all utility functions called from generated |
| 18 // inline caching code. The argument for the macro, ICU, is the function name. | 16 // inline caching code. The argument for the macro, ICU, is the function name. |
| 19 #define IC_UTIL_LIST(ICU) \ | 17 #define IC_UTIL_LIST(ICU) \ |
| 20 ICU(LoadIC_Miss) \ | 18 ICU(LoadIC_Miss) \ |
| 21 ICU(KeyedLoadIC_Miss) \ | 19 ICU(KeyedLoadIC_Miss) \ |
| 22 ICU(CallIC_Miss) \ | 20 ICU(CallIC_Miss) \ |
| 23 ICU(CallIC_Customization_Miss) \ | 21 ICU(CallIC_Customization_Miss) \ |
| 24 ICU(StoreIC_Miss) \ | 22 ICU(StoreIC_Miss) \ |
| 25 ICU(StoreIC_Slow) \ | 23 ICU(StoreIC_Slow) \ |
| 26 ICU(SharedStoreIC_ExtendStorage) \ | 24 ICU(SharedStoreIC_ExtendStorage) \ |
| (...skipping 183 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 210 void TargetMaps(MapHandleList* list) { | 208 void TargetMaps(MapHandleList* list) { |
| 211 FindTargetMaps(); | 209 FindTargetMaps(); |
| 212 for (int i = 0; i < target_maps_.length(); i++) { | 210 for (int i = 0; i < target_maps_.length(); i++) { |
| 213 list->Add(target_maps_.at(i)); | 211 list->Add(target_maps_.at(i)); |
| 214 } | 212 } |
| 215 } | 213 } |
| 216 | 214 |
| 217 void TargetTypes(TypeHandleList* list) { | 215 void TargetTypes(TypeHandleList* list) { |
| 218 FindTargetMaps(); | 216 FindTargetMaps(); |
| 219 for (int i = 0; i < target_maps_.length(); i++) { | 217 for (int i = 0; i < target_maps_.length(); i++) { |
| 220 list->Add(IC::MapToType<HeapType>(target_maps_.at(i), isolate_)); | 218 list->Add(MapToType<HeapType>(target_maps_.at(i), isolate_)); |
| 221 } | 219 } |
| 222 } | 220 } |
| 223 | 221 |
| 224 Map* FirstTargetMap() { | 222 Map* FirstTargetMap() { |
| 225 FindTargetMaps(); | 223 FindTargetMaps(); |
| 226 return target_maps_.length() > 0 ? *target_maps_.at(0) : NULL; | 224 return target_maps_.length() > 0 ? *target_maps_.at(0) : NULL; |
| 227 } | 225 } |
| 228 | 226 |
| 229 protected: | 227 protected: |
| 230 inline void UpdateTarget(); | 228 inline void UpdateTarget(); |
| (...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 288 IC::UtilityId id() const { return id_; } | 286 IC::UtilityId id() const { return id_; } |
| 289 | 287 |
| 290 private: | 288 private: |
| 291 Address address_; | 289 Address address_; |
| 292 IC::UtilityId id_; | 290 IC::UtilityId id_; |
| 293 }; | 291 }; |
| 294 | 292 |
| 295 | 293 |
| 296 class CallIC : public IC { | 294 class CallIC : public IC { |
| 297 public: | 295 public: |
| 298 enum CallType { METHOD, FUNCTION }; | |
| 299 | |
| 300 class State FINAL BASE_EMBEDDED { | |
| 301 public: | |
| 302 explicit State(ExtraICState extra_ic_state); | |
| 303 | |
| 304 State(int argc, CallType call_type) : argc_(argc), call_type_(call_type) {} | |
| 305 | |
| 306 ExtraICState GetExtraICState() const; | |
| 307 | |
| 308 static void GenerateAheadOfTime(Isolate*, | |
| 309 void (*Generate)(Isolate*, const State&)); | |
| 310 | |
| 311 int arg_count() const { return argc_; } | |
| 312 CallType call_type() const { return call_type_; } | |
| 313 | |
| 314 bool CallAsMethod() const { return call_type_ == METHOD; } | |
| 315 | |
| 316 private: | |
| 317 class ArgcBits : public BitField<int, 0, Code::kArgumentsBits> {}; | |
| 318 class CallTypeBits : public BitField<CallType, Code::kArgumentsBits, 1> {}; | |
| 319 | |
| 320 const int argc_; | |
| 321 const CallType call_type_; | |
| 322 }; | |
| 323 | |
| 324 explicit CallIC(Isolate* isolate) : IC(EXTRA_CALL_FRAME, isolate) {} | 296 explicit CallIC(Isolate* isolate) : IC(EXTRA_CALL_FRAME, isolate) {} |
| 325 | 297 |
| 326 void PatchMegamorphic(Handle<Object> function, Handle<FixedArray> vector, | 298 void PatchMegamorphic(Handle<Object> function, Handle<FixedArray> vector, |
| 327 Handle<Smi> slot); | 299 Handle<Smi> slot); |
| 328 | 300 |
| 329 void HandleMiss(Handle<Object> receiver, Handle<Object> function, | 301 void HandleMiss(Handle<Object> receiver, Handle<Object> function, |
| 330 Handle<FixedArray> vector, Handle<Smi> slot); | 302 Handle<FixedArray> vector, Handle<Smi> slot); |
| 331 | 303 |
| 332 // Returns true if a custom handler was installed. | 304 // Returns true if a custom handler was installed. |
| 333 bool DoCustomHandler(Handle<Object> receiver, Handle<Object> function, | 305 bool DoCustomHandler(Handle<Object> receiver, Handle<Object> function, |
| 334 Handle<FixedArray> vector, Handle<Smi> slot, | 306 Handle<FixedArray> vector, Handle<Smi> slot, |
| 335 const State& state); | 307 const CallICState& state); |
| 336 | 308 |
| 337 // Code generator routines. | 309 // Code generator routines. |
| 338 static Handle<Code> initialize_stub(Isolate* isolate, int argc, | 310 static Handle<Code> initialize_stub(Isolate* isolate, int argc, |
| 339 CallType call_type); | 311 CallICState::CallType call_type); |
| 340 | 312 |
| 341 static void Clear(Isolate* isolate, Address address, Code* target, | 313 static void Clear(Isolate* isolate, Address address, Code* target, |
| 342 ConstantPoolArray* constant_pool); | 314 ConstantPoolArray* constant_pool); |
| 343 | 315 |
| 344 private: | 316 private: |
| 345 inline IC::State FeedbackToState(Handle<FixedArray> vector, | 317 inline IC::State FeedbackToState(Handle<FixedArray> vector, |
| 346 Handle<Smi> slot) const; | 318 Handle<Smi> slot) const; |
| 347 }; | 319 }; |
| 348 | 320 |
| 349 | 321 |
| 350 OStream& operator<<(OStream& os, const CallIC::State& s); | |
| 351 | |
| 352 | |
| 353 class LoadIC : public IC { | 322 class LoadIC : public IC { |
| 354 public: | 323 public: |
| 355 class State FINAL BASE_EMBEDDED { | |
| 356 public: | |
| 357 explicit State(ExtraICState extra_ic_state) : state_(extra_ic_state) {} | |
| 358 | |
| 359 explicit State(ContextualMode mode) | |
| 360 : state_(ContextualModeBits::encode(mode)) {} | |
| 361 | |
| 362 ExtraICState GetExtraICState() const { return state_; } | |
| 363 | |
| 364 ContextualMode contextual_mode() const { | |
| 365 return ContextualModeBits::decode(state_); | |
| 366 } | |
| 367 | |
| 368 private: | |
| 369 class ContextualModeBits : public BitField<ContextualMode, 0, 1> {}; | |
| 370 STATIC_ASSERT(static_cast<int>(NOT_CONTEXTUAL) == 0); | |
| 371 | |
| 372 const ExtraICState state_; | |
| 373 }; | |
| 374 | |
| 375 static ExtraICState ComputeExtraICState(ContextualMode contextual_mode) { | 324 static ExtraICState ComputeExtraICState(ContextualMode contextual_mode) { |
| 376 return State(contextual_mode).GetExtraICState(); | 325 return LoadICState(contextual_mode).GetExtraICState(); |
| 377 } | |
| 378 | |
| 379 static ContextualMode GetContextualMode(ExtraICState state) { | |
| 380 return State(state).contextual_mode(); | |
| 381 } | 326 } |
| 382 | 327 |
| 383 ContextualMode contextual_mode() const { | 328 ContextualMode contextual_mode() const { |
| 384 return GetContextualMode(extra_ic_state()); | 329 return LoadICState::GetContextualMode(extra_ic_state()); |
| 385 } | 330 } |
| 386 | 331 |
| 387 explicit LoadIC(FrameDepth depth, Isolate* isolate) : IC(depth, isolate) { | 332 explicit LoadIC(FrameDepth depth, Isolate* isolate) : IC(depth, isolate) { |
| 388 DCHECK(IsLoadStub()); | 333 DCHECK(IsLoadStub()); |
| 389 } | 334 } |
| 390 | 335 |
| 391 // Returns if this IC is for contextual (no explicit receiver) | 336 // Returns if this IC is for contextual (no explicit receiver) |
| 392 // access to properties. | 337 // access to properties. |
| 393 bool IsUndeclaredGlobal(Handle<Object> receiver) { | 338 bool IsUndeclaredGlobal(Handle<Object> receiver) { |
| 394 if (receiver->IsGlobalObject()) { | 339 if (receiver->IsGlobalObject()) { |
| (...skipping 281 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 676 KeyedAccessStoreMode GetStoreMode(Handle<JSObject> receiver, | 621 KeyedAccessStoreMode GetStoreMode(Handle<JSObject> receiver, |
| 677 Handle<Object> key, Handle<Object> value); | 622 Handle<Object> key, Handle<Object> value); |
| 678 | 623 |
| 679 Handle<Map> ComputeTransitionedMap(Handle<Map> map, | 624 Handle<Map> ComputeTransitionedMap(Handle<Map> map, |
| 680 KeyedAccessStoreMode store_mode); | 625 KeyedAccessStoreMode store_mode); |
| 681 | 626 |
| 682 friend class IC; | 627 friend class IC; |
| 683 }; | 628 }; |
| 684 | 629 |
| 685 | 630 |
| 686 // Mode to overwrite BinaryExpression values. | |
| 687 enum OverwriteMode { NO_OVERWRITE, OVERWRITE_LEFT, OVERWRITE_RIGHT }; | |
| 688 | |
| 689 // Type Recording BinaryOpIC, that records the types of the inputs and outputs. | 631 // Type Recording BinaryOpIC, that records the types of the inputs and outputs. |
| 690 class BinaryOpIC : public IC { | 632 class BinaryOpIC : public IC { |
| 691 public: | 633 public: |
| 692 class State FINAL BASE_EMBEDDED { | |
| 693 public: | |
| 694 State(Isolate* isolate, ExtraICState extra_ic_state); | |
| 695 | |
| 696 State(Isolate* isolate, Token::Value op, OverwriteMode mode) | |
| 697 : op_(op), | |
| 698 mode_(mode), | |
| 699 left_kind_(NONE), | |
| 700 right_kind_(NONE), | |
| 701 result_kind_(NONE), | |
| 702 isolate_(isolate) { | |
| 703 DCHECK_LE(FIRST_TOKEN, op); | |
| 704 DCHECK_LE(op, LAST_TOKEN); | |
| 705 } | |
| 706 | |
| 707 InlineCacheState GetICState() const { | |
| 708 if (Max(left_kind_, right_kind_) == NONE) { | |
| 709 return ::v8::internal::UNINITIALIZED; | |
| 710 } | |
| 711 if (Max(left_kind_, right_kind_) == GENERIC) { | |
| 712 return ::v8::internal::MEGAMORPHIC; | |
| 713 } | |
| 714 if (Min(left_kind_, right_kind_) == GENERIC) { | |
| 715 return ::v8::internal::GENERIC; | |
| 716 } | |
| 717 return ::v8::internal::MONOMORPHIC; | |
| 718 } | |
| 719 | |
| 720 ExtraICState GetExtraICState() const; | |
| 721 | |
| 722 static void GenerateAheadOfTime(Isolate*, | |
| 723 void (*Generate)(Isolate*, const State&)); | |
| 724 | |
| 725 bool CanReuseDoubleBox() const { | |
| 726 return (result_kind_ > SMI && result_kind_ <= NUMBER) && | |
| 727 ((mode_ == OVERWRITE_LEFT && left_kind_ > SMI && | |
| 728 left_kind_ <= NUMBER) || | |
| 729 (mode_ == OVERWRITE_RIGHT && right_kind_ > SMI && | |
| 730 right_kind_ <= NUMBER)); | |
| 731 } | |
| 732 | |
| 733 // Returns true if the IC _could_ create allocation mementos. | |
| 734 bool CouldCreateAllocationMementos() const { | |
| 735 if (left_kind_ == STRING || right_kind_ == STRING) { | |
| 736 DCHECK_EQ(Token::ADD, op_); | |
| 737 return true; | |
| 738 } | |
| 739 return false; | |
| 740 } | |
| 741 | |
| 742 // Returns true if the IC _should_ create allocation mementos. | |
| 743 bool ShouldCreateAllocationMementos() const { | |
| 744 return FLAG_allocation_site_pretenuring && | |
| 745 CouldCreateAllocationMementos(); | |
| 746 } | |
| 747 | |
| 748 bool HasSideEffects() const { | |
| 749 return Max(left_kind_, right_kind_) == GENERIC; | |
| 750 } | |
| 751 | |
| 752 // Returns true if the IC should enable the inline smi code (i.e. if either | |
| 753 // parameter may be a smi). | |
| 754 bool UseInlinedSmiCode() const { | |
| 755 return KindMaybeSmi(left_kind_) || KindMaybeSmi(right_kind_); | |
| 756 } | |
| 757 | |
| 758 static const int FIRST_TOKEN = Token::BIT_OR; | |
| 759 static const int LAST_TOKEN = Token::MOD; | |
| 760 | |
| 761 Token::Value op() const { return op_; } | |
| 762 OverwriteMode mode() const { return mode_; } | |
| 763 Maybe<int> fixed_right_arg() const { return fixed_right_arg_; } | |
| 764 | |
| 765 Type* GetLeftType(Zone* zone) const { return KindToType(left_kind_, zone); } | |
| 766 Type* GetRightType(Zone* zone) const { | |
| 767 return KindToType(right_kind_, zone); | |
| 768 } | |
| 769 Type* GetResultType(Zone* zone) const; | |
| 770 | |
| 771 void Update(Handle<Object> left, Handle<Object> right, | |
| 772 Handle<Object> result); | |
| 773 | |
| 774 Isolate* isolate() const { return isolate_; } | |
| 775 | |
| 776 private: | |
| 777 friend OStream& operator<<(OStream& os, const BinaryOpIC::State& s); | |
| 778 | |
| 779 enum Kind { NONE, SMI, INT32, NUMBER, STRING, GENERIC }; | |
| 780 | |
| 781 Kind UpdateKind(Handle<Object> object, Kind kind) const; | |
| 782 | |
| 783 static const char* KindToString(Kind kind); | |
| 784 static Type* KindToType(Kind kind, Zone* zone); | |
| 785 static bool KindMaybeSmi(Kind kind) { | |
| 786 return (kind >= SMI && kind <= NUMBER) || kind == GENERIC; | |
| 787 } | |
| 788 | |
| 789 // We truncate the last bit of the token. | |
| 790 STATIC_ASSERT(LAST_TOKEN - FIRST_TOKEN < (1 << 4)); | |
| 791 class OpField : public BitField<int, 0, 4> {}; | |
| 792 class OverwriteModeField : public BitField<OverwriteMode, 4, 2> {}; | |
| 793 class ResultKindField : public BitField<Kind, 6, 3> {}; | |
| 794 class LeftKindField : public BitField<Kind, 9, 3> {}; | |
| 795 // When fixed right arg is set, we don't need to store the right kind. | |
| 796 // Thus the two fields can overlap. | |
| 797 class HasFixedRightArgField : public BitField<bool, 12, 1> {}; | |
| 798 class FixedRightArgValueField : public BitField<int, 13, 4> {}; | |
| 799 class RightKindField : public BitField<Kind, 13, 3> {}; | |
| 800 | |
| 801 Token::Value op_; | |
| 802 OverwriteMode mode_; | |
| 803 Kind left_kind_; | |
| 804 Kind right_kind_; | |
| 805 Kind result_kind_; | |
| 806 Maybe<int> fixed_right_arg_; | |
| 807 Isolate* isolate_; | |
| 808 }; | |
| 809 | |
| 810 explicit BinaryOpIC(Isolate* isolate) : IC(EXTRA_CALL_FRAME, isolate) {} | 634 explicit BinaryOpIC(Isolate* isolate) : IC(EXTRA_CALL_FRAME, isolate) {} |
| 811 | 635 |
| 812 static Builtins::JavaScript TokenToJSBuiltin(Token::Value op); | 636 static Builtins::JavaScript TokenToJSBuiltin(Token::Value op); |
| 813 | 637 |
| 814 MaybeHandle<Object> Transition(Handle<AllocationSite> allocation_site, | 638 MaybeHandle<Object> Transition(Handle<AllocationSite> allocation_site, |
| 815 Handle<Object> left, | 639 Handle<Object> left, |
| 816 Handle<Object> right) WARN_UNUSED_RESULT; | 640 Handle<Object> right) WARN_UNUSED_RESULT; |
| 817 }; | 641 }; |
| 818 | 642 |
| 819 | 643 |
| 820 OStream& operator<<(OStream& os, const BinaryOpIC::State& s); | |
| 821 | |
| 822 | |
| 823 class CompareIC : public IC { | 644 class CompareIC : public IC { |
| 824 public: | 645 public: |
| 825 // The type/state lattice is defined by the following inequations: | |
| 826 // UNINITIALIZED < ... | |
| 827 // ... < GENERIC | |
| 828 // SMI < NUMBER | |
| 829 // INTERNALIZED_STRING < STRING | |
| 830 // KNOWN_OBJECT < OBJECT | |
| 831 enum State { | |
| 832 UNINITIALIZED, | |
| 833 SMI, | |
| 834 NUMBER, | |
| 835 STRING, | |
| 836 INTERNALIZED_STRING, | |
| 837 UNIQUE_NAME, // Symbol or InternalizedString | |
| 838 OBJECT, // JSObject | |
| 839 KNOWN_OBJECT, // JSObject with specific map (faster check) | |
| 840 GENERIC | |
| 841 }; | |
| 842 | |
| 843 static State NewInputState(State old_state, Handle<Object> value); | |
| 844 | |
| 845 static Type* StateToType(Zone* zone, State state, | |
| 846 Handle<Map> map = Handle<Map>()); | |
| 847 | |
| 848 CompareIC(Isolate* isolate, Token::Value op) | 646 CompareIC(Isolate* isolate, Token::Value op) |
| 849 : IC(EXTRA_CALL_FRAME, isolate), op_(op) {} | 647 : IC(EXTRA_CALL_FRAME, isolate), op_(op) {} |
| 850 | 648 |
| 851 // Update the inline cache for the given operands. | 649 // Update the inline cache for the given operands. |
| 852 Code* UpdateCaches(Handle<Object> x, Handle<Object> y); | 650 Code* UpdateCaches(Handle<Object> x, Handle<Object> y); |
| 853 | 651 |
| 652 // Helper function for computing the condition for a compare operation. |
| 653 static Condition ComputeCondition(Token::Value op); |
| 854 | 654 |
| 855 // Factory method for getting an uninitialized compare stub. | 655 // Factory method for getting an uninitialized compare stub. |
| 856 static Handle<Code> GetUninitialized(Isolate* isolate, Token::Value op); | 656 static Handle<Code> GetUninitialized(Isolate* isolate, Token::Value op); |
| 857 | 657 |
| 858 // Helper function for computing the condition for a compare operation. | |
| 859 static Condition ComputeCondition(Token::Value op); | |
| 860 | |
| 861 static const char* GetStateName(State state); | |
| 862 | |
| 863 private: | 658 private: |
| 864 static bool HasInlinedSmiCode(Address address); | 659 static bool HasInlinedSmiCode(Address address); |
| 865 | 660 |
| 866 State TargetState(State old_state, State old_left, State old_right, | |
| 867 bool has_inlined_smi_code, Handle<Object> x, | |
| 868 Handle<Object> y); | |
| 869 | |
| 870 bool strict() const { return op_ == Token::EQ_STRICT; } | 661 bool strict() const { return op_ == Token::EQ_STRICT; } |
| 871 Condition GetCondition() const { return ComputeCondition(op_); } | 662 Condition GetCondition() const { return ComputeCondition(op_); } |
| 872 | 663 |
| 873 static Code* GetRawUninitialized(Isolate* isolate, Token::Value op); | 664 static Code* GetRawUninitialized(Isolate* isolate, Token::Value op); |
| 874 | 665 |
| 875 static void Clear(Isolate* isolate, Address address, Code* target, | 666 static void Clear(Isolate* isolate, Address address, Code* target, |
| 876 ConstantPoolArray* constant_pool); | 667 ConstantPoolArray* constant_pool); |
| 877 | 668 |
| 878 Token::Value op_; | 669 Token::Value op_; |
| 879 | 670 |
| (...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 926 | 717 |
| 927 // Support functions for interceptor handlers. | 718 // Support functions for interceptor handlers. |
| 928 DECLARE_RUNTIME_FUNCTION(LoadPropertyWithInterceptorOnly); | 719 DECLARE_RUNTIME_FUNCTION(LoadPropertyWithInterceptorOnly); |
| 929 DECLARE_RUNTIME_FUNCTION(LoadPropertyWithInterceptor); | 720 DECLARE_RUNTIME_FUNCTION(LoadPropertyWithInterceptor); |
| 930 DECLARE_RUNTIME_FUNCTION(LoadElementWithInterceptor); | 721 DECLARE_RUNTIME_FUNCTION(LoadElementWithInterceptor); |
| 931 DECLARE_RUNTIME_FUNCTION(StorePropertyWithInterceptor); | 722 DECLARE_RUNTIME_FUNCTION(StorePropertyWithInterceptor); |
| 932 } | 723 } |
| 933 } // namespace v8::internal | 724 } // namespace v8::internal |
| 934 | 725 |
| 935 #endif // V8_IC_H_ | 726 #endif // V8_IC_H_ |
| OLD | NEW |