summaryrefslogtreecommitdiff
path: root/deps/v8/src/ic/ic-state.h
blob: b529b8c54de77d0f765dd4efd6d917e581144535 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
// Copyright 2012 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef V8_IC_STATE_H_
#define V8_IC_STATE_H_

#include "src/macro-assembler.h"

namespace v8 {
namespace internal {


const int kMaxKeyedPolymorphism = 4;


class ICUtility : public AllStatic {
 public:
  // Clear the inline cache to initial state.
  static void Clear(Isolate* isolate, Address address, Address constant_pool);
};


class CallICState final BASE_EMBEDDED {
 public:
  explicit CallICState(ExtraICState extra_ic_state);

  enum CallType { METHOD, FUNCTION };

  CallICState(int argc, CallType call_type)
      : argc_(argc), call_type_(call_type) {}

  ExtraICState GetExtraICState() const;

  static void GenerateAheadOfTime(Isolate*,
                                  void (*Generate)(Isolate*,
                                                   const CallICState&));

  int arg_count() const { return argc_; }
  CallType call_type() const { return call_type_; }

  bool CallAsMethod() const { return call_type_ == METHOD; }

 private:
  class ArgcBits : public BitField<int, 0, Code::kArgumentsBits> {};
  class CallTypeBits : public BitField<CallType, Code::kArgumentsBits, 1> {};

  const int argc_;
  const CallType call_type_;
};


std::ostream& operator<<(std::ostream& os, const CallICState& s);


class BinaryOpICState final BASE_EMBEDDED {
 public:
  BinaryOpICState(Isolate* isolate, ExtraICState extra_ic_state);
  BinaryOpICState(Isolate* isolate, Token::Value op, Strength strength)
      : op_(op),
        strong_(is_strong(strength)),
        left_kind_(NONE),
        right_kind_(NONE),
        result_kind_(NONE),
        fixed_right_arg_(Nothing<int>()),
        isolate_(isolate) {
    DCHECK_LE(FIRST_TOKEN, op);
    DCHECK_LE(op, LAST_TOKEN);
  }

  InlineCacheState GetICState() const {
    if (Max(left_kind_, right_kind_) == NONE) {
      return ::v8::internal::UNINITIALIZED;
    }
    if (Max(left_kind_, right_kind_) == GENERIC) {
      return ::v8::internal::MEGAMORPHIC;
    }
    if (Min(left_kind_, right_kind_) == GENERIC) {
      return ::v8::internal::GENERIC;
    }
    return ::v8::internal::MONOMORPHIC;
  }

  ExtraICState GetExtraICState() const;

  static void GenerateAheadOfTime(Isolate*,
                                  void (*Generate)(Isolate*,
                                                   const BinaryOpICState&));

  // Returns true if the IC _could_ create allocation mementos.
  bool CouldCreateAllocationMementos() const {
    if (left_kind_ == STRING || right_kind_ == STRING) {
      DCHECK_EQ(Token::ADD, op_);
      return true;
    }
    return false;
  }

  // Returns true if the IC _should_ create allocation mementos.
  bool ShouldCreateAllocationMementos() const {
    return FLAG_allocation_site_pretenuring && CouldCreateAllocationMementos();
  }

  bool HasSideEffects() const {
    return Max(left_kind_, right_kind_) == GENERIC;
  }

  Strength strength() const {
    return strong_ ? Strength::STRONG : Strength::WEAK;
  }

  // Returns true if the IC should enable the inline smi code (i.e. if either
  // parameter may be a smi).
  bool UseInlinedSmiCode() const {
    return KindMaybeSmi(left_kind_) || KindMaybeSmi(right_kind_);
  }

  static const int FIRST_TOKEN = Token::BIT_OR;
  static const int LAST_TOKEN = Token::MOD;

  Token::Value op() const { return op_; }
  Maybe<int> fixed_right_arg() const { return fixed_right_arg_; }

  Type* GetLeftType(Zone* zone) const { return KindToType(left_kind_, zone); }
  Type* GetRightType(Zone* zone) const { return KindToType(right_kind_, zone); }
  Type* GetResultType(Zone* zone) const;

  void Update(Handle<Object> left, Handle<Object> right, Handle<Object> result);

  Isolate* isolate() const { return isolate_; }

 private:
  friend std::ostream& operator<<(std::ostream& os, const BinaryOpICState& s);

  enum Kind { NONE, SMI, INT32, NUMBER, STRING, GENERIC };

  Kind UpdateKind(Handle<Object> object, Kind kind) const;

  static const char* KindToString(Kind kind);
  static Type* KindToType(Kind kind, Zone* zone);
  static bool KindMaybeSmi(Kind kind) {
    return (kind >= SMI && kind <= NUMBER) || kind == GENERIC;
  }

  // We truncate the last bit of the token.
  STATIC_ASSERT(LAST_TOKEN - FIRST_TOKEN < (1 << 4));
  class OpField : public BitField<int, 0, 4> {};
  class ResultKindField : public BitField<Kind, 4, 3> {};
  class LeftKindField : public BitField<Kind, 7, 3> {};
  class StrengthField : public BitField<bool, 10, 1> {};
  // When fixed right arg is set, we don't need to store the right kind.
  // Thus the two fields can overlap.
  class HasFixedRightArgField : public BitField<bool, 11, 1> {};
  class FixedRightArgValueField : public BitField<int, 12, 4> {};
  class RightKindField : public BitField<Kind, 12, 3> {};

  Token::Value op_;
  bool strong_;
  Kind left_kind_;
  Kind right_kind_;
  Kind result_kind_;
  Maybe<int> fixed_right_arg_;
  Isolate* isolate_;
};


std::ostream& operator<<(std::ostream& os, const BinaryOpICState& s);


class CompareICState {
 public:
  // The type/state lattice is defined by the following inequations:
  //   UNINITIALIZED < ...
  //   ... < GENERIC
  //   SMI < NUMBER
  //   INTERNALIZED_STRING < STRING
  //   INTERNALIZED_STRING < UNIQUE_NAME
  //   KNOWN_OBJECT < OBJECT
  enum State {
    UNINITIALIZED,
    BOOLEAN,
    SMI,
    NUMBER,
    STRING,
    INTERNALIZED_STRING,
    UNIQUE_NAME,   // Symbol or InternalizedString
    OBJECT,        // JSObject
    KNOWN_OBJECT,  // JSObject with specific map (faster check)
    GENERIC
  };

  static Type* StateToType(Zone* zone, State state,
                           Handle<Map> map = Handle<Map>());

  static State NewInputState(State old_state, Handle<Object> value);

  static const char* GetStateName(CompareICState::State state);

  static State TargetState(State old_state, State old_left, State old_right,
                           Token::Value op, bool has_inlined_smi_code,
                           Handle<Object> x, Handle<Object> y);
};


class LoadICState final BASE_EMBEDDED {
 private:
  class TypeofModeBits : public BitField<TypeofMode, 0, 1> {};
  class LanguageModeBits
      : public BitField<LanguageMode, TypeofModeBits::kNext, 2> {};
  STATIC_ASSERT(static_cast<int>(INSIDE_TYPEOF) == 0);
  const ExtraICState state_;

 public:
  static const uint32_t kNextBitFieldOffset = LanguageModeBits::kNext;

  static const ExtraICState kStrongModeState = STRONG
                                               << LanguageModeBits::kShift;

  explicit LoadICState(ExtraICState extra_ic_state) : state_(extra_ic_state) {}

  explicit LoadICState(TypeofMode typeof_mode, LanguageMode language_mode)
      : state_(TypeofModeBits::encode(typeof_mode) |
               LanguageModeBits::encode(language_mode)) {}

  ExtraICState GetExtraICState() const { return state_; }

  TypeofMode typeof_mode() const { return TypeofModeBits::decode(state_); }

  LanguageMode language_mode() const {
    return LanguageModeBits::decode(state_);
  }

  static TypeofMode GetTypeofMode(ExtraICState state) {
    return LoadICState(state).typeof_mode();
  }

  static LanguageMode GetLanguageMode(ExtraICState state) {
    return LoadICState(state).language_mode();
  }
};


class StoreICState final BASE_EMBEDDED {
 public:
  explicit StoreICState(ExtraICState extra_ic_state) : state_(extra_ic_state) {}

  explicit StoreICState(LanguageMode mode)
      : state_(LanguageModeState::encode(mode)) {}

  ExtraICState GetExtraICState() const { return state_; }

  LanguageMode language_mode() const {
    return LanguageModeState::decode(state_);
  }

  static LanguageMode GetLanguageMode(ExtraICState state) {
    return StoreICState(state).language_mode();
  }

  class LanguageModeState : public BitField<LanguageMode, 1, 2> {};
  STATIC_ASSERT(i::LANGUAGE_END == 3);

  // For convenience, a statically declared encoding of strict mode extra
  // IC state.
  static const ExtraICState kStrictModeState = STRICT
                                               << LanguageModeState::kShift;

 private:
  const ExtraICState state_;
};
}
}

#endif  // V8_IC_STATE_H_