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, Address constant_pool);
21};
22
23
24class CallICState final BASE_EMBEDDED {
25 public:
26  explicit CallICState(ExtraICState extra_ic_state)
27      : bit_field_(extra_ic_state) {}
28  CallICState(int argc, ConvertReceiverMode convert_mode,
29              TailCallMode tail_call_mode)
30      : bit_field_(ArgcBits::encode(argc) |
31                   ConvertModeBits::encode(convert_mode) |
32                   TailCallModeBits::encode(tail_call_mode)) {}
33
34  ExtraICState GetExtraICState() const { return bit_field_; }
35
36  static void GenerateAheadOfTime(Isolate*,
37                                  void (*Generate)(Isolate*,
38                                                   const CallICState&));
39
40  int argc() const { return ArgcBits::decode(bit_field_); }
41  ConvertReceiverMode convert_mode() const {
42    return ConvertModeBits::decode(bit_field_);
43  }
44  TailCallMode tail_call_mode() const {
45    return TailCallModeBits::decode(bit_field_);
46  }
47
48 private:
49  typedef BitField<int, 0, Code::kArgumentsBits> ArgcBits;
50  typedef BitField<ConvertReceiverMode, ArgcBits::kNext, 2> ConvertModeBits;
51  typedef BitField<TailCallMode, ConvertModeBits::kNext, 1> TailCallModeBits;
52
53  int const bit_field_;
54};
55
56
57std::ostream& operator<<(std::ostream& os, const CallICState& s);
58
59
60class BinaryOpICState final BASE_EMBEDDED {
61 public:
62  BinaryOpICState(Isolate* isolate, ExtraICState extra_ic_state);
63  BinaryOpICState(Isolate* isolate, Token::Value op)
64      : op_(op),
65        left_kind_(NONE),
66        right_kind_(NONE),
67        result_kind_(NONE),
68        fixed_right_arg_(Nothing<int>()),
69        isolate_(isolate) {
70    DCHECK_LE(FIRST_TOKEN, op);
71    DCHECK_LE(op, LAST_TOKEN);
72  }
73
74  InlineCacheState GetICState() const {
75    if (Max(left_kind_, right_kind_) == NONE) {
76      return ::v8::internal::UNINITIALIZED;
77    }
78    if (Max(left_kind_, right_kind_) == GENERIC) {
79      return ::v8::internal::MEGAMORPHIC;
80    }
81    if (Min(left_kind_, right_kind_) == GENERIC) {
82      return ::v8::internal::GENERIC;
83    }
84    return ::v8::internal::MONOMORPHIC;
85  }
86
87  ExtraICState GetExtraICState() const;
88
89  static void GenerateAheadOfTime(Isolate*,
90                                  void (*Generate)(Isolate*,
91                                                   const BinaryOpICState&));
92
93  // Returns true if the IC _could_ create allocation mementos.
94  bool CouldCreateAllocationMementos() const {
95    if (left_kind_ == STRING || right_kind_ == STRING) {
96      DCHECK_EQ(Token::ADD, op_);
97      return true;
98    }
99    return false;
100  }
101
102  // Returns true if the IC _should_ create allocation mementos.
103  bool ShouldCreateAllocationMementos() const {
104    return FLAG_allocation_site_pretenuring && CouldCreateAllocationMementos();
105  }
106
107  bool HasSideEffects() const {
108    return Max(left_kind_, right_kind_) == GENERIC;
109  }
110
111  // Returns true if the IC should enable the inline smi code (i.e. if either
112  // parameter may be a smi).
113  bool UseInlinedSmiCode() const {
114    return KindMaybeSmi(left_kind_) || KindMaybeSmi(right_kind_);
115  }
116
117  static const int FIRST_TOKEN = Token::BIT_OR;
118  static const int LAST_TOKEN = Token::MOD;
119
120  Token::Value op() const { return op_; }
121  Maybe<int> fixed_right_arg() const { return fixed_right_arg_; }
122
123  Type* GetLeftType() const { return KindToType(left_kind_); }
124  Type* GetRightType() const { return KindToType(right_kind_); }
125  Type* GetResultType() const;
126
127  void Update(Handle<Object> left, Handle<Object> right, Handle<Object> result);
128
129  Isolate* isolate() const { return isolate_; }
130
131 private:
132  friend std::ostream& operator<<(std::ostream& os, const BinaryOpICState& s);
133
134  enum Kind { NONE, SMI, INT32, NUMBER, STRING, GENERIC };
135
136  Kind UpdateKind(Handle<Object> object, Kind kind) const;
137
138  static const char* KindToString(Kind kind);
139  static Type* KindToType(Kind kind);
140  static bool KindMaybeSmi(Kind kind) {
141    return (kind >= SMI && kind <= NUMBER) || kind == GENERIC;
142  }
143
144  // We truncate the last bit of the token.
145  STATIC_ASSERT(LAST_TOKEN - FIRST_TOKEN < (1 << 4));
146  class OpField : public BitField<int, 0, 4> {};
147  class ResultKindField : public BitField<Kind, 4, 3> {};
148  class LeftKindField : public BitField<Kind, 7, 3> {};
149  // When fixed right arg is set, we don't need to store the right kind.
150  // Thus the two fields can overlap.
151  class HasFixedRightArgField : public BitField<bool, 10, 1> {};
152  class FixedRightArgValueField : public BitField<int, 11, 4> {};
153  class RightKindField : public BitField<Kind, 11, 3> {};
154
155  Token::Value op_;
156  Kind left_kind_;
157  Kind right_kind_;
158  Kind result_kind_;
159  Maybe<int> fixed_right_arg_;
160  Isolate* isolate_;
161};
162
163
164std::ostream& operator<<(std::ostream& os, const BinaryOpICState& s);
165
166
167class CompareICState {
168 public:
169  // The type/state lattice is defined by the following inequations:
170  //   UNINITIALIZED < ...
171  //   ... < GENERIC
172  //   SMI < NUMBER
173  //   INTERNALIZED_STRING < STRING
174  //   INTERNALIZED_STRING < UNIQUE_NAME
175  //   KNOWN_RECEIVER < RECEIVER
176  enum State {
177    UNINITIALIZED,
178    BOOLEAN,
179    SMI,
180    NUMBER,
181    STRING,
182    INTERNALIZED_STRING,
183    UNIQUE_NAME,     // Symbol or InternalizedString
184    RECEIVER,        // JSReceiver
185    KNOWN_RECEIVER,  // JSReceiver with specific map (faster check)
186    GENERIC
187  };
188
189  static Type* StateToType(Zone* zone, State state,
190                           Handle<Map> map = Handle<Map>());
191
192  static State NewInputState(State old_state, Handle<Object> value);
193
194  static const char* GetStateName(CompareICState::State state);
195
196  static State TargetState(Isolate* isolate, State old_state, State old_left,
197                           State old_right, Token::Value op,
198                           bool has_inlined_smi_code, Handle<Object> x,
199                           Handle<Object> y);
200};
201
202class LoadGlobalICState final BASE_EMBEDDED {
203 private:
204  class TypeofModeBits : public BitField<TypeofMode, 0, 1> {};
205  STATIC_ASSERT(static_cast<int>(INSIDE_TYPEOF) == 0);
206  const ExtraICState state_;
207
208 public:
209  static const uint32_t kNextBitFieldOffset = TypeofModeBits::kNext;
210
211  explicit LoadGlobalICState(ExtraICState extra_ic_state)
212      : state_(extra_ic_state) {}
213
214  explicit LoadGlobalICState(TypeofMode typeof_mode)
215      : state_(TypeofModeBits::encode(typeof_mode)) {}
216
217  ExtraICState GetExtraICState() const { return state_; }
218
219  TypeofMode typeof_mode() const { return TypeofModeBits::decode(state_); }
220
221  static TypeofMode GetTypeofMode(ExtraICState state) {
222    return LoadGlobalICState(state).typeof_mode();
223  }
224};
225
226
227class StoreICState final BASE_EMBEDDED {
228 public:
229  explicit StoreICState(ExtraICState extra_ic_state) : state_(extra_ic_state) {}
230
231  explicit StoreICState(LanguageMode mode)
232      : state_(LanguageModeState::encode(mode)) {}
233
234  ExtraICState GetExtraICState() const { return state_; }
235
236  LanguageMode language_mode() const {
237    return LanguageModeState::decode(state_);
238  }
239
240  static LanguageMode GetLanguageMode(ExtraICState state) {
241    return StoreICState(state).language_mode();
242  }
243
244  class LanguageModeState : public BitField<LanguageMode, 1, 2> {};
245  STATIC_ASSERT(i::LANGUAGE_END == 3);
246
247  // For convenience, a statically declared encoding of strict mode extra
248  // IC state.
249  static const ExtraICState kStrictModeState = STRICT
250                                               << LanguageModeState::kShift;
251
252 private:
253  const ExtraICState state_;
254};
255
256}  // namespace internal
257}  // namespace v8
258
259#endif  // V8_IC_STATE_H_
260