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_STATE_H_
6 #define V8_IC_STATE_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 class ICUtility : public AllStatic {
18  public:
19   // Clear the inline cache to initial state.
20   static void Clear(Isolate* isolate, Address address,
21                     ConstantPoolArray* constant_pool);
22 };
23 
24 
25 class CallICState FINAL BASE_EMBEDDED {
26  public:
27   explicit CallICState(ExtraICState extra_ic_state);
28 
29   enum CallType { METHOD, FUNCTION };
30 
CallICState(int argc,CallType call_type)31   CallICState(int argc, CallType call_type)
32       : argc_(argc), call_type_(call_type) {}
33 
34   ExtraICState GetExtraICState() const;
35 
36   static void GenerateAheadOfTime(Isolate*,
37                                   void (*Generate)(Isolate*,
38                                                    const CallICState&));
39 
arg_count()40   int arg_count() const { return argc_; }
call_type()41   CallType call_type() const { return call_type_; }
42 
CallAsMethod()43   bool CallAsMethod() const { return call_type_ == METHOD; }
44 
45  private:
46   class ArgcBits : public BitField<int, 0, Code::kArgumentsBits> {};
47   class CallTypeBits : public BitField<CallType, Code::kArgumentsBits, 1> {};
48 
49   const int argc_;
50   const CallType call_type_;
51 };
52 
53 
54 OStream& operator<<(OStream& os, const CallICState& s);
55 
56 
57 // Mode to overwrite BinaryExpression values.
58 enum OverwriteMode { NO_OVERWRITE, OVERWRITE_LEFT, OVERWRITE_RIGHT };
59 
60 class BinaryOpICState FINAL BASE_EMBEDDED {
61  public:
62   BinaryOpICState(Isolate* isolate, ExtraICState extra_ic_state);
63 
BinaryOpICState(Isolate * isolate,Token::Value op,OverwriteMode mode)64   BinaryOpICState(Isolate* isolate, Token::Value op, OverwriteMode mode)
65       : op_(op),
66         mode_(mode),
67         left_kind_(NONE),
68         right_kind_(NONE),
69         result_kind_(NONE),
70         isolate_(isolate) {
71     DCHECK_LE(FIRST_TOKEN, op);
72     DCHECK_LE(op, LAST_TOKEN);
73   }
74 
GetICState()75   InlineCacheState GetICState() const {
76     if (Max(left_kind_, right_kind_) == NONE) {
77       return ::v8::internal::UNINITIALIZED;
78     }
79     if (Max(left_kind_, right_kind_) == GENERIC) {
80       return ::v8::internal::MEGAMORPHIC;
81     }
82     if (Min(left_kind_, right_kind_) == GENERIC) {
83       return ::v8::internal::GENERIC;
84     }
85     return ::v8::internal::MONOMORPHIC;
86   }
87 
88   ExtraICState GetExtraICState() const;
89 
90   static void GenerateAheadOfTime(Isolate*,
91                                   void (*Generate)(Isolate*,
92                                                    const BinaryOpICState&));
93 
CanReuseDoubleBox()94   bool CanReuseDoubleBox() const {
95     return (result_kind_ > SMI && result_kind_ <= NUMBER) &&
96            ((mode_ == OVERWRITE_LEFT && left_kind_ > SMI &&
97              left_kind_ <= NUMBER) ||
98             (mode_ == OVERWRITE_RIGHT && right_kind_ > SMI &&
99              right_kind_ <= NUMBER));
100   }
101 
102   // Returns true if the IC _could_ create allocation mementos.
CouldCreateAllocationMementos()103   bool CouldCreateAllocationMementos() const {
104     if (left_kind_ == STRING || right_kind_ == STRING) {
105       DCHECK_EQ(Token::ADD, op_);
106       return true;
107     }
108     return false;
109   }
110 
111   // Returns true if the IC _should_ create allocation mementos.
ShouldCreateAllocationMementos()112   bool ShouldCreateAllocationMementos() const {
113     return FLAG_allocation_site_pretenuring && CouldCreateAllocationMementos();
114   }
115 
HasSideEffects()116   bool HasSideEffects() const {
117     return Max(left_kind_, right_kind_) == GENERIC;
118   }
119 
120   // Returns true if the IC should enable the inline smi code (i.e. if either
121   // parameter may be a smi).
UseInlinedSmiCode()122   bool UseInlinedSmiCode() const {
123     return KindMaybeSmi(left_kind_) || KindMaybeSmi(right_kind_);
124   }
125 
126   static const int FIRST_TOKEN = Token::BIT_OR;
127   static const int LAST_TOKEN = Token::MOD;
128 
op()129   Token::Value op() const { return op_; }
mode()130   OverwriteMode mode() const { return mode_; }
fixed_right_arg()131   Maybe<int> fixed_right_arg() const { return fixed_right_arg_; }
132 
GetLeftType(Zone * zone)133   Type* GetLeftType(Zone* zone) const { return KindToType(left_kind_, zone); }
GetRightType(Zone * zone)134   Type* GetRightType(Zone* zone) const { return KindToType(right_kind_, zone); }
135   Type* GetResultType(Zone* zone) const;
136 
137   void Update(Handle<Object> left, Handle<Object> right, Handle<Object> result);
138 
isolate()139   Isolate* isolate() const { return isolate_; }
140 
141  private:
142   friend OStream& operator<<(OStream& os, const BinaryOpICState& s);
143 
144   enum Kind { NONE, SMI, INT32, NUMBER, STRING, GENERIC };
145 
146   Kind UpdateKind(Handle<Object> object, Kind kind) const;
147 
148   static const char* KindToString(Kind kind);
149   static Type* KindToType(Kind kind, Zone* zone);
KindMaybeSmi(Kind kind)150   static bool KindMaybeSmi(Kind kind) {
151     return (kind >= SMI && kind <= NUMBER) || kind == GENERIC;
152   }
153 
154   // We truncate the last bit of the token.
155   STATIC_ASSERT(LAST_TOKEN - FIRST_TOKEN < (1 << 4));
156   class OpField : public BitField<int, 0, 4> {};
157   class OverwriteModeField : public BitField<OverwriteMode, 4, 2> {};
158   class ResultKindField : public BitField<Kind, 6, 3> {};
159   class LeftKindField : public BitField<Kind, 9, 3> {};
160   // When fixed right arg is set, we don't need to store the right kind.
161   // Thus the two fields can overlap.
162   class HasFixedRightArgField : public BitField<bool, 12, 1> {};
163   class FixedRightArgValueField : public BitField<int, 13, 4> {};
164   class RightKindField : public BitField<Kind, 13, 3> {};
165 
166   Token::Value op_;
167   OverwriteMode mode_;
168   Kind left_kind_;
169   Kind right_kind_;
170   Kind result_kind_;
171   Maybe<int> fixed_right_arg_;
172   Isolate* isolate_;
173 };
174 
175 
176 OStream& operator<<(OStream& os, const BinaryOpICState& s);
177 
178 
179 class CompareICState {
180  public:
181   // The type/state lattice is defined by the following inequations:
182   //   UNINITIALIZED < ...
183   //   ... < GENERIC
184   //   SMI < NUMBER
185   //   INTERNALIZED_STRING < STRING
186   //   KNOWN_OBJECT < OBJECT
187   enum State {
188     UNINITIALIZED,
189     SMI,
190     NUMBER,
191     STRING,
192     INTERNALIZED_STRING,
193     UNIQUE_NAME,   // Symbol or InternalizedString
194     OBJECT,        // JSObject
195     KNOWN_OBJECT,  // JSObject with specific map (faster check)
196     GENERIC
197   };
198 
199   static Type* StateToType(Zone* zone, State state,
200                            Handle<Map> map = Handle<Map>());
201 
202   static State NewInputState(State old_state, Handle<Object> value);
203 
204   static const char* GetStateName(CompareICState::State state);
205 
206   static State TargetState(State old_state, State old_left, State old_right,
207                            Token::Value op, bool has_inlined_smi_code,
208                            Handle<Object> x, Handle<Object> y);
209 };
210 
211 
212 class LoadICState FINAL BASE_EMBEDDED {
213  public:
LoadICState(ExtraICState extra_ic_state)214   explicit LoadICState(ExtraICState extra_ic_state) : state_(extra_ic_state) {}
215 
LoadICState(ContextualMode mode)216   explicit LoadICState(ContextualMode mode)
217       : state_(ContextualModeBits::encode(mode)) {}
218 
GetExtraICState()219   ExtraICState GetExtraICState() const { return state_; }
220 
contextual_mode()221   ContextualMode contextual_mode() const {
222     return ContextualModeBits::decode(state_);
223   }
224 
GetContextualMode(ExtraICState state)225   static ContextualMode GetContextualMode(ExtraICState state) {
226     return LoadICState(state).contextual_mode();
227   }
228 
229  private:
230   class ContextualModeBits : public BitField<ContextualMode, 0, 1> {};
231   STATIC_ASSERT(static_cast<int>(NOT_CONTEXTUAL) == 0);
232 
233   const ExtraICState state_;
234 };
235 }
236 }
237 
238 #endif  // V8_IC_STATE_H_
239