V8 Project
ic-state.cc
Go to the documentation of this file.
1 // Copyright 2014 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 #include "src/v8.h"
6 
7 #include "src/ic/ic.h"
8 #include "src/ic/ic-state.h"
9 
10 namespace v8 {
11 namespace internal {
12 
13 void ICUtility::Clear(Isolate* isolate, Address address,
14  ConstantPoolArray* constant_pool) {
15  IC::Clear(isolate, address, constant_pool);
16 }
17 
18 
19 CallICState::CallICState(ExtraICState extra_ic_state)
20  : argc_(ArgcBits::decode(extra_ic_state)),
21  call_type_(CallTypeBits::decode(extra_ic_state)) {}
22 
23 
24 ExtraICState CallICState::GetExtraICState() const {
25  ExtraICState extra_ic_state =
26  ArgcBits::encode(argc_) | CallTypeBits::encode(call_type_);
27  return extra_ic_state;
28 }
29 
30 
31 OStream& operator<<(OStream& os, const CallICState& s) {
32  return os << "(args(" << s.arg_count() << "), "
33  << (s.call_type() == CallICState::METHOD ? "METHOD" : "FUNCTION")
34  << ", ";
35 }
36 
37 
38 BinaryOpICState::BinaryOpICState(Isolate* isolate, ExtraICState extra_ic_state)
39  : isolate_(isolate) {
40  op_ =
41  static_cast<Token::Value>(FIRST_TOKEN + OpField::decode(extra_ic_state));
42  mode_ = OverwriteModeField::decode(extra_ic_state);
43  fixed_right_arg_ =
44  Maybe<int>(HasFixedRightArgField::decode(extra_ic_state),
45  1 << FixedRightArgValueField::decode(extra_ic_state));
46  left_kind_ = LeftKindField::decode(extra_ic_state);
47  if (fixed_right_arg_.has_value) {
48  right_kind_ = Smi::IsValid(fixed_right_arg_.value) ? SMI : INT32;
49  } else {
50  right_kind_ = RightKindField::decode(extra_ic_state);
51  }
52  result_kind_ = ResultKindField::decode(extra_ic_state);
53  DCHECK_LE(FIRST_TOKEN, op_);
54  DCHECK_LE(op_, LAST_TOKEN);
55 }
56 
57 
58 ExtraICState BinaryOpICState::GetExtraICState() const {
59  ExtraICState extra_ic_state =
60  OpField::encode(op_ - FIRST_TOKEN) | OverwriteModeField::encode(mode_) |
61  LeftKindField::encode(left_kind_) |
62  ResultKindField::encode(result_kind_) |
63  HasFixedRightArgField::encode(fixed_right_arg_.has_value);
64  if (fixed_right_arg_.has_value) {
65  extra_ic_state = FixedRightArgValueField::update(
66  extra_ic_state, WhichPowerOf2(fixed_right_arg_.value));
67  } else {
68  extra_ic_state = RightKindField::update(extra_ic_state, right_kind_);
69  }
70  return extra_ic_state;
71 }
72 
73 
74 // static
75 void BinaryOpICState::GenerateAheadOfTime(
76  Isolate* isolate, void (*Generate)(Isolate*, const BinaryOpICState&)) {
77 // TODO(olivf) We should investigate why adding stubs to the snapshot is so
78 // expensive at runtime. When solved we should be able to add most binops to
79 // the snapshot instead of hand-picking them.
80 // Generated list of commonly used stubs
81 #define GENERATE(op, left_kind, right_kind, result_kind, mode) \
82  do { \
83  BinaryOpICState state(isolate, op, mode); \
84  state.left_kind_ = left_kind; \
85  state.fixed_right_arg_.has_value = false; \
86  state.right_kind_ = right_kind; \
87  state.result_kind_ = result_kind; \
88  Generate(isolate, state); \
89  } while (false)
90  GENERATE(Token::ADD, INT32, INT32, INT32, NO_OVERWRITE);
91  GENERATE(Token::ADD, INT32, INT32, INT32, OVERWRITE_LEFT);
92  GENERATE(Token::ADD, INT32, INT32, NUMBER, NO_OVERWRITE);
93  GENERATE(Token::ADD, INT32, INT32, NUMBER, OVERWRITE_LEFT);
94  GENERATE(Token::ADD, INT32, NUMBER, NUMBER, NO_OVERWRITE);
95  GENERATE(Token::ADD, INT32, NUMBER, NUMBER, OVERWRITE_LEFT);
96  GENERATE(Token::ADD, INT32, NUMBER, NUMBER, OVERWRITE_RIGHT);
97  GENERATE(Token::ADD, INT32, SMI, INT32, NO_OVERWRITE);
98  GENERATE(Token::ADD, INT32, SMI, INT32, OVERWRITE_LEFT);
99  GENERATE(Token::ADD, INT32, SMI, INT32, OVERWRITE_RIGHT);
100  GENERATE(Token::ADD, NUMBER, INT32, NUMBER, NO_OVERWRITE);
101  GENERATE(Token::ADD, NUMBER, INT32, NUMBER, OVERWRITE_LEFT);
102  GENERATE(Token::ADD, NUMBER, INT32, NUMBER, OVERWRITE_RIGHT);
103  GENERATE(Token::ADD, NUMBER, NUMBER, NUMBER, NO_OVERWRITE);
104  GENERATE(Token::ADD, NUMBER, NUMBER, NUMBER, OVERWRITE_LEFT);
105  GENERATE(Token::ADD, NUMBER, NUMBER, NUMBER, OVERWRITE_RIGHT);
106  GENERATE(Token::ADD, NUMBER, SMI, NUMBER, NO_OVERWRITE);
107  GENERATE(Token::ADD, NUMBER, SMI, NUMBER, OVERWRITE_LEFT);
108  GENERATE(Token::ADD, NUMBER, SMI, NUMBER, OVERWRITE_RIGHT);
109  GENERATE(Token::ADD, SMI, INT32, INT32, NO_OVERWRITE);
110  GENERATE(Token::ADD, SMI, INT32, INT32, OVERWRITE_LEFT);
111  GENERATE(Token::ADD, SMI, INT32, NUMBER, NO_OVERWRITE);
112  GENERATE(Token::ADD, SMI, NUMBER, NUMBER, NO_OVERWRITE);
113  GENERATE(Token::ADD, SMI, NUMBER, NUMBER, OVERWRITE_LEFT);
114  GENERATE(Token::ADD, SMI, NUMBER, NUMBER, OVERWRITE_RIGHT);
115  GENERATE(Token::ADD, SMI, SMI, INT32, OVERWRITE_LEFT);
116  GENERATE(Token::ADD, SMI, SMI, SMI, OVERWRITE_RIGHT);
117  GENERATE(Token::BIT_AND, INT32, INT32, INT32, NO_OVERWRITE);
118  GENERATE(Token::BIT_AND, INT32, INT32, INT32, OVERWRITE_LEFT);
119  GENERATE(Token::BIT_AND, INT32, INT32, INT32, OVERWRITE_RIGHT);
120  GENERATE(Token::BIT_AND, INT32, INT32, SMI, NO_OVERWRITE);
121  GENERATE(Token::BIT_AND, INT32, INT32, SMI, OVERWRITE_RIGHT);
122  GENERATE(Token::BIT_AND, INT32, SMI, INT32, NO_OVERWRITE);
123  GENERATE(Token::BIT_AND, INT32, SMI, INT32, OVERWRITE_RIGHT);
124  GENERATE(Token::BIT_AND, INT32, SMI, SMI, NO_OVERWRITE);
125  GENERATE(Token::BIT_AND, INT32, SMI, SMI, OVERWRITE_LEFT);
126  GENERATE(Token::BIT_AND, INT32, SMI, SMI, OVERWRITE_RIGHT);
127  GENERATE(Token::BIT_AND, NUMBER, INT32, INT32, OVERWRITE_RIGHT);
128  GENERATE(Token::BIT_AND, NUMBER, SMI, SMI, NO_OVERWRITE);
129  GENERATE(Token::BIT_AND, NUMBER, SMI, SMI, OVERWRITE_RIGHT);
130  GENERATE(Token::BIT_AND, SMI, INT32, INT32, NO_OVERWRITE);
131  GENERATE(Token::BIT_AND, SMI, INT32, SMI, OVERWRITE_RIGHT);
132  GENERATE(Token::BIT_AND, SMI, NUMBER, SMI, OVERWRITE_RIGHT);
133  GENERATE(Token::BIT_AND, SMI, SMI, SMI, NO_OVERWRITE);
134  GENERATE(Token::BIT_AND, SMI, SMI, SMI, OVERWRITE_LEFT);
135  GENERATE(Token::BIT_AND, SMI, SMI, SMI, OVERWRITE_RIGHT);
136  GENERATE(Token::BIT_OR, INT32, INT32, INT32, OVERWRITE_LEFT);
137  GENERATE(Token::BIT_OR, INT32, INT32, INT32, OVERWRITE_RIGHT);
138  GENERATE(Token::BIT_OR, INT32, INT32, SMI, OVERWRITE_LEFT);
139  GENERATE(Token::BIT_OR, INT32, SMI, INT32, NO_OVERWRITE);
140  GENERATE(Token::BIT_OR, INT32, SMI, INT32, OVERWRITE_LEFT);
141  GENERATE(Token::BIT_OR, INT32, SMI, INT32, OVERWRITE_RIGHT);
142  GENERATE(Token::BIT_OR, INT32, SMI, SMI, NO_OVERWRITE);
143  GENERATE(Token::BIT_OR, INT32, SMI, SMI, OVERWRITE_RIGHT);
144  GENERATE(Token::BIT_OR, NUMBER, SMI, INT32, NO_OVERWRITE);
145  GENERATE(Token::BIT_OR, NUMBER, SMI, INT32, OVERWRITE_LEFT);
146  GENERATE(Token::BIT_OR, NUMBER, SMI, INT32, OVERWRITE_RIGHT);
147  GENERATE(Token::BIT_OR, NUMBER, SMI, SMI, NO_OVERWRITE);
148  GENERATE(Token::BIT_OR, NUMBER, SMI, SMI, OVERWRITE_LEFT);
149  GENERATE(Token::BIT_OR, SMI, INT32, INT32, OVERWRITE_LEFT);
150  GENERATE(Token::BIT_OR, SMI, INT32, INT32, OVERWRITE_RIGHT);
151  GENERATE(Token::BIT_OR, SMI, INT32, SMI, OVERWRITE_RIGHT);
152  GENERATE(Token::BIT_OR, SMI, SMI, SMI, OVERWRITE_LEFT);
153  GENERATE(Token::BIT_OR, SMI, SMI, SMI, OVERWRITE_RIGHT);
154  GENERATE(Token::BIT_XOR, INT32, INT32, INT32, NO_OVERWRITE);
155  GENERATE(Token::BIT_XOR, INT32, INT32, INT32, OVERWRITE_LEFT);
156  GENERATE(Token::BIT_XOR, INT32, INT32, INT32, OVERWRITE_RIGHT);
157  GENERATE(Token::BIT_XOR, INT32, INT32, SMI, NO_OVERWRITE);
158  GENERATE(Token::BIT_XOR, INT32, INT32, SMI, OVERWRITE_LEFT);
159  GENERATE(Token::BIT_XOR, INT32, NUMBER, SMI, NO_OVERWRITE);
160  GENERATE(Token::BIT_XOR, INT32, SMI, INT32, NO_OVERWRITE);
161  GENERATE(Token::BIT_XOR, INT32, SMI, INT32, OVERWRITE_LEFT);
162  GENERATE(Token::BIT_XOR, INT32, SMI, INT32, OVERWRITE_RIGHT);
163  GENERATE(Token::BIT_XOR, NUMBER, INT32, INT32, NO_OVERWRITE);
164  GENERATE(Token::BIT_XOR, NUMBER, SMI, INT32, NO_OVERWRITE);
165  GENERATE(Token::BIT_XOR, NUMBER, SMI, SMI, NO_OVERWRITE);
166  GENERATE(Token::BIT_XOR, SMI, INT32, INT32, NO_OVERWRITE);
167  GENERATE(Token::BIT_XOR, SMI, INT32, INT32, OVERWRITE_LEFT);
168  GENERATE(Token::BIT_XOR, SMI, INT32, SMI, OVERWRITE_LEFT);
169  GENERATE(Token::BIT_XOR, SMI, SMI, SMI, NO_OVERWRITE);
170  GENERATE(Token::BIT_XOR, SMI, SMI, SMI, OVERWRITE_LEFT);
171  GENERATE(Token::BIT_XOR, SMI, SMI, SMI, OVERWRITE_RIGHT);
172  GENERATE(Token::DIV, INT32, INT32, INT32, NO_OVERWRITE);
173  GENERATE(Token::DIV, INT32, INT32, NUMBER, NO_OVERWRITE);
174  GENERATE(Token::DIV, INT32, NUMBER, NUMBER, NO_OVERWRITE);
175  GENERATE(Token::DIV, INT32, NUMBER, NUMBER, OVERWRITE_LEFT);
176  GENERATE(Token::DIV, INT32, SMI, INT32, NO_OVERWRITE);
177  GENERATE(Token::DIV, INT32, SMI, NUMBER, NO_OVERWRITE);
178  GENERATE(Token::DIV, NUMBER, INT32, NUMBER, NO_OVERWRITE);
179  GENERATE(Token::DIV, NUMBER, INT32, NUMBER, OVERWRITE_LEFT);
180  GENERATE(Token::DIV, NUMBER, NUMBER, NUMBER, NO_OVERWRITE);
181  GENERATE(Token::DIV, NUMBER, NUMBER, NUMBER, OVERWRITE_LEFT);
182  GENERATE(Token::DIV, NUMBER, NUMBER, NUMBER, OVERWRITE_RIGHT);
183  GENERATE(Token::DIV, NUMBER, SMI, NUMBER, NO_OVERWRITE);
184  GENERATE(Token::DIV, NUMBER, SMI, NUMBER, OVERWRITE_LEFT);
185  GENERATE(Token::DIV, SMI, INT32, INT32, NO_OVERWRITE);
186  GENERATE(Token::DIV, SMI, INT32, NUMBER, NO_OVERWRITE);
187  GENERATE(Token::DIV, SMI, INT32, NUMBER, OVERWRITE_LEFT);
188  GENERATE(Token::DIV, SMI, NUMBER, NUMBER, NO_OVERWRITE);
189  GENERATE(Token::DIV, SMI, NUMBER, NUMBER, OVERWRITE_LEFT);
190  GENERATE(Token::DIV, SMI, NUMBER, NUMBER, OVERWRITE_RIGHT);
191  GENERATE(Token::DIV, SMI, SMI, NUMBER, NO_OVERWRITE);
192  GENERATE(Token::DIV, SMI, SMI, NUMBER, OVERWRITE_LEFT);
193  GENERATE(Token::DIV, SMI, SMI, NUMBER, OVERWRITE_RIGHT);
194  GENERATE(Token::DIV, SMI, SMI, SMI, NO_OVERWRITE);
195  GENERATE(Token::DIV, SMI, SMI, SMI, OVERWRITE_LEFT);
196  GENERATE(Token::DIV, SMI, SMI, SMI, OVERWRITE_RIGHT);
197  GENERATE(Token::MOD, NUMBER, SMI, NUMBER, OVERWRITE_LEFT);
198  GENERATE(Token::MOD, SMI, SMI, SMI, NO_OVERWRITE);
199  GENERATE(Token::MOD, SMI, SMI, SMI, OVERWRITE_LEFT);
200  GENERATE(Token::MUL, INT32, INT32, INT32, NO_OVERWRITE);
201  GENERATE(Token::MUL, INT32, INT32, NUMBER, NO_OVERWRITE);
202  GENERATE(Token::MUL, INT32, NUMBER, NUMBER, NO_OVERWRITE);
203  GENERATE(Token::MUL, INT32, NUMBER, NUMBER, OVERWRITE_LEFT);
204  GENERATE(Token::MUL, INT32, SMI, INT32, NO_OVERWRITE);
205  GENERATE(Token::MUL, INT32, SMI, INT32, OVERWRITE_LEFT);
206  GENERATE(Token::MUL, INT32, SMI, NUMBER, NO_OVERWRITE);
207  GENERATE(Token::MUL, NUMBER, INT32, NUMBER, NO_OVERWRITE);
208  GENERATE(Token::MUL, NUMBER, INT32, NUMBER, OVERWRITE_LEFT);
209  GENERATE(Token::MUL, NUMBER, INT32, NUMBER, OVERWRITE_RIGHT);
210  GENERATE(Token::MUL, NUMBER, NUMBER, NUMBER, NO_OVERWRITE);
211  GENERATE(Token::MUL, NUMBER, NUMBER, NUMBER, OVERWRITE_LEFT);
212  GENERATE(Token::MUL, NUMBER, SMI, NUMBER, NO_OVERWRITE);
213  GENERATE(Token::MUL, NUMBER, SMI, NUMBER, OVERWRITE_LEFT);
214  GENERATE(Token::MUL, NUMBER, SMI, NUMBER, OVERWRITE_RIGHT);
215  GENERATE(Token::MUL, SMI, INT32, INT32, NO_OVERWRITE);
216  GENERATE(Token::MUL, SMI, INT32, INT32, OVERWRITE_LEFT);
217  GENERATE(Token::MUL, SMI, INT32, NUMBER, NO_OVERWRITE);
218  GENERATE(Token::MUL, SMI, NUMBER, NUMBER, NO_OVERWRITE);
219  GENERATE(Token::MUL, SMI, NUMBER, NUMBER, OVERWRITE_LEFT);
220  GENERATE(Token::MUL, SMI, NUMBER, NUMBER, OVERWRITE_RIGHT);
221  GENERATE(Token::MUL, SMI, SMI, INT32, NO_OVERWRITE);
222  GENERATE(Token::MUL, SMI, SMI, NUMBER, NO_OVERWRITE);
223  GENERATE(Token::MUL, SMI, SMI, NUMBER, OVERWRITE_LEFT);
224  GENERATE(Token::MUL, SMI, SMI, SMI, NO_OVERWRITE);
225  GENERATE(Token::MUL, SMI, SMI, SMI, OVERWRITE_LEFT);
226  GENERATE(Token::MUL, SMI, SMI, SMI, OVERWRITE_RIGHT);
227  GENERATE(Token::SAR, INT32, SMI, INT32, OVERWRITE_RIGHT);
228  GENERATE(Token::SAR, INT32, SMI, SMI, NO_OVERWRITE);
229  GENERATE(Token::SAR, INT32, SMI, SMI, OVERWRITE_RIGHT);
230  GENERATE(Token::SAR, NUMBER, SMI, SMI, NO_OVERWRITE);
231  GENERATE(Token::SAR, NUMBER, SMI, SMI, OVERWRITE_RIGHT);
232  GENERATE(Token::SAR, SMI, SMI, SMI, OVERWRITE_LEFT);
233  GENERATE(Token::SAR, SMI, SMI, SMI, OVERWRITE_RIGHT);
234  GENERATE(Token::SHL, INT32, SMI, INT32, NO_OVERWRITE);
235  GENERATE(Token::SHL, INT32, SMI, INT32, OVERWRITE_RIGHT);
236  GENERATE(Token::SHL, INT32, SMI, SMI, NO_OVERWRITE);
237  GENERATE(Token::SHL, INT32, SMI, SMI, OVERWRITE_RIGHT);
238  GENERATE(Token::SHL, NUMBER, SMI, SMI, OVERWRITE_RIGHT);
239  GENERATE(Token::SHL, SMI, SMI, INT32, NO_OVERWRITE);
240  GENERATE(Token::SHL, SMI, SMI, INT32, OVERWRITE_LEFT);
241  GENERATE(Token::SHL, SMI, SMI, INT32, OVERWRITE_RIGHT);
242  GENERATE(Token::SHL, SMI, SMI, SMI, NO_OVERWRITE);
243  GENERATE(Token::SHL, SMI, SMI, SMI, OVERWRITE_LEFT);
244  GENERATE(Token::SHL, SMI, SMI, SMI, OVERWRITE_RIGHT);
245  GENERATE(Token::SHR, INT32, SMI, SMI, NO_OVERWRITE);
246  GENERATE(Token::SHR, INT32, SMI, SMI, OVERWRITE_LEFT);
247  GENERATE(Token::SHR, INT32, SMI, SMI, OVERWRITE_RIGHT);
248  GENERATE(Token::SHR, NUMBER, SMI, SMI, NO_OVERWRITE);
249  GENERATE(Token::SHR, NUMBER, SMI, SMI, OVERWRITE_LEFT);
250  GENERATE(Token::SHR, NUMBER, SMI, INT32, OVERWRITE_RIGHT);
251  GENERATE(Token::SHR, SMI, SMI, SMI, NO_OVERWRITE);
252  GENERATE(Token::SHR, SMI, SMI, SMI, OVERWRITE_LEFT);
253  GENERATE(Token::SHR, SMI, SMI, SMI, OVERWRITE_RIGHT);
254  GENERATE(Token::SUB, INT32, INT32, INT32, NO_OVERWRITE);
255  GENERATE(Token::SUB, INT32, INT32, INT32, OVERWRITE_LEFT);
256  GENERATE(Token::SUB, INT32, NUMBER, NUMBER, NO_OVERWRITE);
257  GENERATE(Token::SUB, INT32, NUMBER, NUMBER, OVERWRITE_RIGHT);
258  GENERATE(Token::SUB, INT32, SMI, INT32, OVERWRITE_LEFT);
259  GENERATE(Token::SUB, INT32, SMI, INT32, OVERWRITE_RIGHT);
260  GENERATE(Token::SUB, NUMBER, INT32, NUMBER, NO_OVERWRITE);
261  GENERATE(Token::SUB, NUMBER, INT32, NUMBER, OVERWRITE_LEFT);
262  GENERATE(Token::SUB, NUMBER, NUMBER, NUMBER, NO_OVERWRITE);
263  GENERATE(Token::SUB, NUMBER, NUMBER, NUMBER, OVERWRITE_LEFT);
264  GENERATE(Token::SUB, NUMBER, NUMBER, NUMBER, OVERWRITE_RIGHT);
265  GENERATE(Token::SUB, NUMBER, SMI, NUMBER, NO_OVERWRITE);
266  GENERATE(Token::SUB, NUMBER, SMI, NUMBER, OVERWRITE_LEFT);
267  GENERATE(Token::SUB, NUMBER, SMI, NUMBER, OVERWRITE_RIGHT);
268  GENERATE(Token::SUB, SMI, INT32, INT32, NO_OVERWRITE);
269  GENERATE(Token::SUB, SMI, NUMBER, NUMBER, NO_OVERWRITE);
270  GENERATE(Token::SUB, SMI, NUMBER, NUMBER, OVERWRITE_LEFT);
271  GENERATE(Token::SUB, SMI, NUMBER, NUMBER, OVERWRITE_RIGHT);
272  GENERATE(Token::SUB, SMI, SMI, SMI, NO_OVERWRITE);
273  GENERATE(Token::SUB, SMI, SMI, SMI, OVERWRITE_LEFT);
274  GENERATE(Token::SUB, SMI, SMI, SMI, OVERWRITE_RIGHT);
275 #undef GENERATE
276 #define GENERATE(op, left_kind, fixed_right_arg_value, result_kind, mode) \
277  do { \
278  BinaryOpICState state(isolate, op, mode); \
279  state.left_kind_ = left_kind; \
280  state.fixed_right_arg_.has_value = true; \
281  state.fixed_right_arg_.value = fixed_right_arg_value; \
282  state.right_kind_ = SMI; \
283  state.result_kind_ = result_kind; \
284  Generate(isolate, state); \
285  } while (false)
286  GENERATE(Token::MOD, SMI, 2, SMI, NO_OVERWRITE);
287  GENERATE(Token::MOD, SMI, 4, SMI, NO_OVERWRITE);
288  GENERATE(Token::MOD, SMI, 4, SMI, OVERWRITE_LEFT);
289  GENERATE(Token::MOD, SMI, 8, SMI, NO_OVERWRITE);
290  GENERATE(Token::MOD, SMI, 16, SMI, OVERWRITE_LEFT);
291  GENERATE(Token::MOD, SMI, 32, SMI, NO_OVERWRITE);
292  GENERATE(Token::MOD, SMI, 2048, SMI, NO_OVERWRITE);
293 #undef GENERATE
294 }
295 
296 
297 Type* BinaryOpICState::GetResultType(Zone* zone) const {
298  Kind result_kind = result_kind_;
299  if (HasSideEffects()) {
300  result_kind = NONE;
301  } else if (result_kind == GENERIC && op_ == Token::ADD) {
302  return Type::Union(Type::Number(zone), Type::String(zone), zone);
303  } else if (result_kind == NUMBER && op_ == Token::SHR) {
304  return Type::Unsigned32(zone);
305  }
306  DCHECK_NE(GENERIC, result_kind);
307  return KindToType(result_kind, zone);
308 }
309 
310 
311 OStream& operator<<(OStream& os, const BinaryOpICState& s) {
312  os << "(" << Token::Name(s.op_);
313  if (s.mode_ == OVERWRITE_LEFT)
314  os << "_ReuseLeft";
315  else if (s.mode_ == OVERWRITE_RIGHT)
316  os << "_ReuseRight";
317  if (s.CouldCreateAllocationMementos()) os << "_CreateAllocationMementos";
318  os << ":" << BinaryOpICState::KindToString(s.left_kind_) << "*";
319  if (s.fixed_right_arg_.has_value) {
320  os << s.fixed_right_arg_.value;
321  } else {
322  os << BinaryOpICState::KindToString(s.right_kind_);
323  }
324  return os << "->" << BinaryOpICState::KindToString(s.result_kind_) << ")";
325 }
326 
327 
328 void BinaryOpICState::Update(Handle<Object> left, Handle<Object> right,
329  Handle<Object> result) {
330  ExtraICState old_extra_ic_state = GetExtraICState();
331 
332  left_kind_ = UpdateKind(left, left_kind_);
333  right_kind_ = UpdateKind(right, right_kind_);
334 
335  int32_t fixed_right_arg_value = 0;
336  bool has_fixed_right_arg =
337  op_ == Token::MOD && right->ToInt32(&fixed_right_arg_value) &&
338  fixed_right_arg_value > 0 &&
339  base::bits::IsPowerOfTwo32(fixed_right_arg_value) &&
340  FixedRightArgValueField::is_valid(WhichPowerOf2(fixed_right_arg_value)) &&
341  (left_kind_ == SMI || left_kind_ == INT32) &&
342  (result_kind_ == NONE || !fixed_right_arg_.has_value);
343  fixed_right_arg_ = Maybe<int32_t>(has_fixed_right_arg, fixed_right_arg_value);
344 
345  result_kind_ = UpdateKind(result, result_kind_);
346 
347  if (!Token::IsTruncatingBinaryOp(op_)) {
348  Kind input_kind = Max(left_kind_, right_kind_);
349  if (result_kind_ < input_kind && input_kind <= NUMBER) {
350  result_kind_ = input_kind;
351  }
352  }
353 
354  // We don't want to distinguish INT32 and NUMBER for string add (because
355  // NumberToString can't make use of this anyway).
356  if (left_kind_ == STRING && right_kind_ == INT32) {
357  DCHECK_EQ(STRING, result_kind_);
358  DCHECK_EQ(Token::ADD, op_);
359  right_kind_ = NUMBER;
360  } else if (right_kind_ == STRING && left_kind_ == INT32) {
361  DCHECK_EQ(STRING, result_kind_);
362  DCHECK_EQ(Token::ADD, op_);
363  left_kind_ = NUMBER;
364  }
365 
366  // Reset overwrite mode unless we can actually make use of it, or may be able
367  // to make use of it at some point in the future.
368  if ((mode_ == OVERWRITE_LEFT && left_kind_ > NUMBER) ||
369  (mode_ == OVERWRITE_RIGHT && right_kind_ > NUMBER) ||
370  result_kind_ > NUMBER) {
371  mode_ = NO_OVERWRITE;
372  }
373 
374  if (old_extra_ic_state == GetExtraICState()) {
375  // Tagged operations can lead to non-truncating HChanges
376  if (left->IsUndefined() || left->IsBoolean()) {
377  left_kind_ = GENERIC;
378  } else {
379  DCHECK(right->IsUndefined() || right->IsBoolean());
380  right_kind_ = GENERIC;
381  }
382  }
383 }
384 
385 
386 BinaryOpICState::Kind BinaryOpICState::UpdateKind(Handle<Object> object,
387  Kind kind) const {
388  Kind new_kind = GENERIC;
389  bool is_truncating = Token::IsTruncatingBinaryOp(op());
390  if (object->IsBoolean() && is_truncating) {
391  // Booleans will be automatically truncated by HChange.
392  new_kind = INT32;
393  } else if (object->IsUndefined()) {
394  // Undefined will be automatically truncated by HChange.
395  new_kind = is_truncating ? INT32 : NUMBER;
396  } else if (object->IsSmi()) {
397  new_kind = SMI;
398  } else if (object->IsHeapNumber()) {
399  double value = Handle<HeapNumber>::cast(object)->value();
400  new_kind = IsInt32Double(value) ? INT32 : NUMBER;
401  } else if (object->IsString() && op() == Token::ADD) {
402  new_kind = STRING;
403  }
404  if (new_kind == INT32 && SmiValuesAre32Bits()) {
405  new_kind = NUMBER;
406  }
407  if (kind != NONE && ((new_kind <= NUMBER && kind > NUMBER) ||
408  (new_kind > NUMBER && kind <= NUMBER))) {
409  new_kind = GENERIC;
410  }
411  return Max(kind, new_kind);
412 }
413 
414 
415 // static
416 const char* BinaryOpICState::KindToString(Kind kind) {
417  switch (kind) {
418  case NONE:
419  return "None";
420  case SMI:
421  return "Smi";
422  case INT32:
423  return "Int32";
424  case NUMBER:
425  return "Number";
426  case STRING:
427  return "String";
428  case GENERIC:
429  return "Generic";
430  }
431  UNREACHABLE();
432  return NULL;
433 }
434 
435 
436 // static
437 Type* BinaryOpICState::KindToType(Kind kind, Zone* zone) {
438  switch (kind) {
439  case NONE:
440  return Type::None(zone);
441  case SMI:
442  return Type::SignedSmall(zone);
443  case INT32:
444  return Type::Signed32(zone);
445  case NUMBER:
446  return Type::Number(zone);
447  case STRING:
448  return Type::String(zone);
449  case GENERIC:
450  return Type::Any(zone);
451  }
452  UNREACHABLE();
453  return NULL;
454 }
455 
456 
457 const char* CompareICState::GetStateName(State state) {
458  switch (state) {
459  case UNINITIALIZED:
460  return "UNINITIALIZED";
461  case SMI:
462  return "SMI";
463  case NUMBER:
464  return "NUMBER";
465  case INTERNALIZED_STRING:
466  return "INTERNALIZED_STRING";
467  case STRING:
468  return "STRING";
469  case UNIQUE_NAME:
470  return "UNIQUE_NAME";
471  case OBJECT:
472  return "OBJECT";
473  case KNOWN_OBJECT:
474  return "KNOWN_OBJECT";
475  case GENERIC:
476  return "GENERIC";
477  }
478  UNREACHABLE();
479  return NULL;
480 }
481 
482 
483 Type* CompareICState::StateToType(Zone* zone, State state, Handle<Map> map) {
484  switch (state) {
485  case UNINITIALIZED:
486  return Type::None(zone);
487  case SMI:
488  return Type::SignedSmall(zone);
489  case NUMBER:
490  return Type::Number(zone);
491  case STRING:
492  return Type::String(zone);
493  case INTERNALIZED_STRING:
494  return Type::InternalizedString(zone);
495  case UNIQUE_NAME:
496  return Type::UniqueName(zone);
497  case OBJECT:
498  return Type::Receiver(zone);
499  case KNOWN_OBJECT:
500  return map.is_null() ? Type::Receiver(zone) : Type::Class(map, zone);
501  case GENERIC:
502  return Type::Any(zone);
503  }
504  UNREACHABLE();
505  return NULL;
506 }
507 
508 
509 CompareICState::State CompareICState::NewInputState(State old_state,
510  Handle<Object> value) {
511  switch (old_state) {
512  case UNINITIALIZED:
513  if (value->IsSmi()) return SMI;
514  if (value->IsHeapNumber()) return NUMBER;
515  if (value->IsInternalizedString()) return INTERNALIZED_STRING;
516  if (value->IsString()) return STRING;
517  if (value->IsSymbol()) return UNIQUE_NAME;
518  if (value->IsJSObject()) return OBJECT;
519  break;
520  case SMI:
521  if (value->IsSmi()) return SMI;
522  if (value->IsHeapNumber()) return NUMBER;
523  break;
524  case NUMBER:
525  if (value->IsNumber()) return NUMBER;
526  break;
527  case INTERNALIZED_STRING:
528  if (value->IsInternalizedString()) return INTERNALIZED_STRING;
529  if (value->IsString()) return STRING;
530  if (value->IsSymbol()) return UNIQUE_NAME;
531  break;
532  case STRING:
533  if (value->IsString()) return STRING;
534  break;
535  case UNIQUE_NAME:
536  if (value->IsUniqueName()) return UNIQUE_NAME;
537  break;
538  case OBJECT:
539  if (value->IsJSObject()) return OBJECT;
540  break;
541  case GENERIC:
542  break;
543  case KNOWN_OBJECT:
544  UNREACHABLE();
545  break;
546  }
547  return GENERIC;
548 }
549 
550 
551 // static
552 CompareICState::State CompareICState::TargetState(
553  State old_state, State old_left, State old_right, Token::Value op,
554  bool has_inlined_smi_code, Handle<Object> x, Handle<Object> y) {
555  switch (old_state) {
556  case UNINITIALIZED:
557  if (x->IsSmi() && y->IsSmi()) return SMI;
558  if (x->IsNumber() && y->IsNumber()) return NUMBER;
559  if (Token::IsOrderedRelationalCompareOp(op)) {
560  // Ordered comparisons treat undefined as NaN, so the
561  // NUMBER stub will do the right thing.
562  if ((x->IsNumber() && y->IsUndefined()) ||
563  (y->IsNumber() && x->IsUndefined())) {
564  return NUMBER;
565  }
566  }
567  if (x->IsInternalizedString() && y->IsInternalizedString()) {
568  // We compare internalized strings as plain ones if we need to determine
569  // the order in a non-equality compare.
570  return Token::IsEqualityOp(op) ? INTERNALIZED_STRING : STRING;
571  }
572  if (x->IsString() && y->IsString()) return STRING;
573  if (!Token::IsEqualityOp(op)) return GENERIC;
574  if (x->IsUniqueName() && y->IsUniqueName()) return UNIQUE_NAME;
575  if (x->IsJSObject() && y->IsJSObject()) {
576  if (Handle<JSObject>::cast(x)->map() ==
578  return KNOWN_OBJECT;
579  } else {
580  return OBJECT;
581  }
582  }
583  return GENERIC;
584  case SMI:
585  return x->IsNumber() && y->IsNumber() ? NUMBER : GENERIC;
586  case INTERNALIZED_STRING:
587  DCHECK(Token::IsEqualityOp(op));
588  if (x->IsString() && y->IsString()) return STRING;
589  if (x->IsUniqueName() && y->IsUniqueName()) return UNIQUE_NAME;
590  return GENERIC;
591  case NUMBER:
592  // If the failure was due to one side changing from smi to heap number,
593  // then keep the state (if other changed at the same time, we will get
594  // a second miss and then go to generic).
595  if (old_left == SMI && x->IsHeapNumber()) return NUMBER;
596  if (old_right == SMI && y->IsHeapNumber()) return NUMBER;
597  return GENERIC;
598  case KNOWN_OBJECT:
599  DCHECK(Token::IsEqualityOp(op));
600  if (x->IsJSObject() && y->IsJSObject()) {
601  return OBJECT;
602  }
603  return GENERIC;
604  case STRING:
605  case UNIQUE_NAME:
606  case OBJECT:
607  case GENERIC:
608  return GENERIC;
609  }
610  UNREACHABLE();
611  return GENERIC; // Make the compiler happy.
612 }
613 }
614 } // namespace v8::internal
Isolate represents an isolated instance of the V8 engine.
Definition: v8.h:4356
static void Clear(Isolate *isolate, Address address, ConstantPoolArray *constant_pool)
Definition: ic-state.cc:13
static void Clear(Isolate *isolate, Address address, ConstantPoolArray *constant_pool)
Definition: ic.cc:478
static bool IsValid(intptr_t value)
Definition: objects-inl.h:1334
enable harmony numeric enable harmony object literal extensions Optimize object Array DOM strings and string trace pretenuring decisions of HAllocate instructions Enables optimizations which favor memory size over execution speed maximum source size in bytes considered for a single inlining maximum cumulative number of AST nodes considered for inlining trace the tracking of allocation sites deoptimize every n garbage collections perform array bounds checks elimination analyze liveness of environment slots and zap dead values flushes the cache of optimized code for closures on every GC allow uint32 values on optimize frames if they are used only in safe operations track concurrent recompilation artificial compilation delay in ms do not emit check maps for constant values that have a leaf map
enable harmony numeric enable harmony object literal extensions Optimize object Array DOM strings and string trace pretenuring decisions of HAllocate instructions Enables optimizations which favor memory size over execution speed maximum source size in bytes considered for a single inlining maximum cumulative number of AST nodes considered for inlining trace the tracking of allocation sites deoptimize every n garbage collections perform array bounds checks elimination analyze liveness of environment slots and zap dead values flushes the cache of optimized code for closures on every GC allow uint32 values on optimize frames if they are used only in safe operations track concurrent recompilation artificial compilation delay in ms do not emit check maps for constant values that have a leaf deoptimize the optimized code if the layout of the maps changes enable context specialization in TurboFan execution budget before interrupt is triggered max percentage of megamorphic generic ICs to allow optimization enable use of SAHF instruction if enable use of VFP3 instructions if available enable use of NEON instructions if enable use of SDIV and UDIV instructions if enable use of MLS instructions if enable loading bit constant by means of movw movt instruction enable unaligned accesses for enable use of d16 d31 registers on ARM this requires VFP3 force all emitted branches to be in long enable alignment of csp to bytes on platforms which prefer the register to always be NULL
#define INTERNALIZED_STRING(name, value)
#define GENERATE(op, left_kind, right_kind, result_kind, mode)
#define UNREACHABLE()
Definition: logging.h:30
#define DCHECK_LE(v1, v2)
Definition: logging.h:210
#define DCHECK_NE(v1, v2)
Definition: logging.h:207
#define DCHECK(condition)
Definition: logging.h:205
#define DCHECK_EQ(v1, v2)
Definition: logging.h:206
int int32_t
Definition: unicode.cc:24
bool IsPowerOfTwo32(uint32_t value)
Definition: bits.h:77
static LifetimePosition Max(LifetimePosition a, LifetimePosition b)
int WhichPowerOf2(uint32_t x)
Definition: utils.h:37
TypeImpl< ZoneTypeConfig > Type
static bool IsInt32Double(double value)
Definition: conversions.h:169
int ExtraICState
Definition: objects.h:305
OStream & operator<<(OStream &os, const BinaryOpICState &s)
Definition: ic-state.cc:311
@ NO_OVERWRITE
Definition: ic-state.h:58
@ OVERWRITE_RIGHT
Definition: ic-state.h:58
@ OVERWRITE_LEFT
Definition: ic-state.h:58
OStream & operator<<(OStream &os, const BasicBlockProfiler &p)
byte * Address
Definition: globals.h:101
static bool SmiValuesAre32Bits()
Definition: v8.h:5808
@ UNINITIALIZED
Definition: globals.h:446
Debugger support for the V8 JavaScript engine.
Definition: accessors.cc:20
@ None
Definition: v8.h:2211
@ NONE
@ STRING