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 |