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
10namespace v8 {
11namespace internal {
12
13
14const int kMaxKeyedPolymorphism = 4;
15
16
17class 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
25class CallICState FINAL BASE_EMBEDDED {
26 public:
27  explicit CallICState(ExtraICState extra_ic_state);
28
29  enum CallType { METHOD, FUNCTION };
30
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
40  int arg_count() const { return argc_; }
41  CallType call_type() const { return call_type_; }
42
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
54OStream& operator<<(OStream& os, const CallICState& s);
55
56
57// Mode to overwrite BinaryExpression values.
58enum OverwriteMode { NO_OVERWRITE, OVERWRITE_LEFT, OVERWRITE_RIGHT };
59
60class BinaryOpICState FINAL BASE_EMBEDDED {
61 public:
62  BinaryOpICState(Isolate* isolate, ExtraICState extra_ic_state);
63
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
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
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.
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.
112  bool ShouldCreateAllocationMementos() const {
113    return FLAG_allocation_site_pretenuring && CouldCreateAllocationMementos();
114  }
115
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).
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
129  Token::Value op() const { return op_; }
130  OverwriteMode mode() const { return mode_; }
131  Maybe<int> fixed_right_arg() const { return fixed_right_arg_; }
132
133  Type* GetLeftType(Zone* zone) const { return KindToType(left_kind_, 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
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);
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
176OStream& operator<<(OStream& os, const BinaryOpICState& s);
177
178
179class 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
212class LoadICState FINAL BASE_EMBEDDED {
213 public:
214  explicit LoadICState(ExtraICState extra_ic_state) : state_(extra_ic_state) {}
215
216  explicit LoadICState(ContextualMode mode)
217      : state_(ContextualModeBits::encode(mode)) {}
218
219  ExtraICState GetExtraICState() const { return state_; }
220
221  ContextualMode contextual_mode() const {
222    return ContextualModeBits::decode(state_);
223  }
224
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