V8 Project
js-typed-lowering.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 
11 #include "src/types.h"
12 
13 namespace v8 {
14 namespace internal {
15 namespace compiler {
16 
17 // TODO(turbofan): js-typed-lowering improvements possible
18 // - immediately put in type bounds for all new nodes
19 // - relax effects from generic but not-side-effecting operations
20 // - relax effects for ToNumber(mixed)
21 
22 
23 // Relax the effects of {node} by immediately replacing effect uses of {node}
24 // with the effect input to {node}.
25 // TODO(turbofan): replace the effect input to {node} with {graph->start()}.
26 // TODO(titzer): move into a GraphEditor?
27 static void RelaxEffects(Node* node) {
29 }
30 
31 
32 JSTypedLowering::~JSTypedLowering() {}
33 
34 
35 Reduction JSTypedLowering::ReplaceEagerly(Node* old, Node* node) {
36  NodeProperties::ReplaceWithValue(old, node, node);
37  return Changed(node);
38 }
39 
40 
41 // A helper class to simplify the process of reducing a single binop node with a
42 // JSOperator. This class manages the rewriting of context, control, and effect
43 // dependencies during lowering of a binop and contains numerous helper
44 // functions for matching the types of inputs to an operation.
46  public:
47  JSBinopReduction(JSTypedLowering* lowering, Node* node)
48  : lowering_(lowering),
49  node_(node),
50  left_type_(NodeProperties::GetBounds(node->InputAt(0)).upper),
51  right_type_(NodeProperties::GetBounds(node->InputAt(1)).upper) {}
52 
54  node_->ReplaceInput(0, ConvertToNumber(left()));
55  node_->ReplaceInput(1, ConvertToNumber(right()));
56  }
57 
58  void ConvertInputsToInt32(bool left_signed, bool right_signed) {
59  node_->ReplaceInput(0, ConvertToI32(left_signed, left()));
60  node_->ReplaceInput(1, ConvertToI32(right_signed, right()));
61  }
62 
64  node_->ReplaceInput(0, ConvertToString(left()));
65  node_->ReplaceInput(1, ConvertToString(right()));
66  }
67 
68  // Convert inputs for bitwise shift operation (ES5 spec 11.7).
69  void ConvertInputsForShift(bool left_signed) {
70  node_->ReplaceInput(0, ConvertToI32(left_signed, left()));
71  Node* rnum = ConvertToI32(false, right());
72  node_->ReplaceInput(1, graph()->NewNode(machine()->Word32And(), rnum,
73  jsgraph()->Int32Constant(0x1F)));
74  }
75 
76  void SwapInputs() {
77  Node* l = left();
78  Node* r = right();
79  node_->ReplaceInput(0, r);
80  node_->ReplaceInput(1, l);
81  std::swap(left_type_, right_type_);
82  }
83 
84  // Remove all effect and control inputs and outputs to this node and change
85  // to the pure operator {op}, possibly inserting a boolean inversion.
86  Reduction ChangeToPureOperator(const Operator* op, bool invert = false) {
91 
92  // Remove the effects from the node, if any, and update its effect usages.
95  }
96  // Remove the inputs corresponding to context, effect, and control.
98  // Finally, update the operator to the new one.
99  node_->set_op(op);
100 
101  if (invert) {
102  // Insert an boolean not to invert the value.
103  Node* value = graph()->NewNode(simplified()->BooleanNot(), node_);
104  node_->ReplaceUses(value);
105  // Note: ReplaceUses() smashes all uses, so smash it back here.
106  value->ReplaceInput(0, node_);
107  return lowering_->ReplaceWith(value);
108  }
109  return lowering_->Changed(node_);
110  }
111 
112  bool OneInputIs(Type* t) { return left_type_->Is(t) || right_type_->Is(t); }
113 
114  bool BothInputsAre(Type* t) {
115  return left_type_->Is(t) && right_type_->Is(t);
116  }
117 
119  return !left_type_->Maybe(t) || !right_type_->Maybe(t);
120  }
121 
123  return !left_type_->Maybe(t) && !right_type_->Maybe(t);
124  }
125 
129  Node* left() { return NodeProperties::GetValueInput(node_, 0); }
130  Node* right() { return NodeProperties::GetValueInput(node_, 1); }
131  Type* left_type() { return left_type_; }
132  Type* right_type() { return right_type_; }
133 
134  SimplifiedOperatorBuilder* simplified() { return lowering_->simplified(); }
135  Graph* graph() { return lowering_->graph(); }
136  JSGraph* jsgraph() { return lowering_->jsgraph(); }
137  JSOperatorBuilder* javascript() { return lowering_->javascript(); }
138  MachineOperatorBuilder* machine() { return lowering_->machine(); }
139 
140  private:
141  JSTypedLowering* lowering_; // The containing lowering instance.
142  Node* node_; // The original node.
143  Type* left_type_; // Cache of the left input's type.
144  Type* right_type_; // Cache of the right input's type.
145 
146  Node* ConvertToString(Node* node) {
147  // Avoid introducing too many eager ToString() operations.
148  Reduction reduced = lowering_->ReduceJSToStringInput(node);
149  if (reduced.Changed()) return reduced.replacement();
150  Node* n = graph()->NewNode(javascript()->ToString(), node, context(),
151  effect(), control());
152  update_effect(n);
153  return n;
154  }
155 
156  Node* ConvertToNumber(Node* node) {
157  // Avoid introducing too many eager ToNumber() operations.
158  Reduction reduced = lowering_->ReduceJSToNumberInput(node);
159  if (reduced.Changed()) return reduced.replacement();
160  Node* n = graph()->NewNode(javascript()->ToNumber(), node, context(),
161  effect(), control());
162  update_effect(n);
163  return n;
164  }
165 
166  // Try narrowing a double or number operation to an Int32 operation.
167  bool TryNarrowingToI32(Type* type, Node* node) {
168  switch (node->opcode()) {
169  case IrOpcode::kFloat64Add:
170  case IrOpcode::kNumberAdd: {
171  JSBinopReduction r(lowering_, node);
172  if (r.BothInputsAre(Type::Integral32())) {
173  node->set_op(lowering_->machine()->Int32Add());
174  // TODO(titzer): narrow bounds instead of overwriting.
175  NodeProperties::SetBounds(node, Bounds(type));
176  return true;
177  }
178  }
179  case IrOpcode::kFloat64Sub:
180  case IrOpcode::kNumberSubtract: {
181  JSBinopReduction r(lowering_, node);
182  if (r.BothInputsAre(Type::Integral32())) {
183  node->set_op(lowering_->machine()->Int32Sub());
184  // TODO(titzer): narrow bounds instead of overwriting.
185  NodeProperties::SetBounds(node, Bounds(type));
186  return true;
187  }
188  }
189  default:
190  return false;
191  }
192  }
193 
194  Node* ConvertToI32(bool is_signed, Node* node) {
195  Type* type = is_signed ? Type::Signed32() : Type::Unsigned32();
196  if (node->OwnedBy(node_)) {
197  // If this node {node_} has the only edge to {node}, then try narrowing
198  // its operation to an Int32 add or subtract.
199  if (TryNarrowingToI32(type, node)) return node;
200  } else {
201  // Otherwise, {node} has multiple uses. Leave it as is and let the
202  // further lowering passes deal with it, which use a full backwards
203  // fixpoint.
204  }
205 
206  // Avoid introducing too many eager NumberToXXnt32() operations.
207  node = ConvertToNumber(node);
208  Type* input_type = NodeProperties::GetBounds(node).upper;
209 
210  if (input_type->Is(type)) return node; // already in the value range.
211 
212  const Operator* op = is_signed ? simplified()->NumberToInt32()
213  : simplified()->NumberToUint32();
214  Node* n = graph()->NewNode(op, node);
215  return n;
216  }
217 
218  void update_effect(Node* effect) {
220  }
221 };
222 
223 
224 Reduction JSTypedLowering::ReduceJSAdd(Node* node) {
225  JSBinopReduction r(this, node);
226  if (r.BothInputsAre(Type::Number())) {
227  // JSAdd(x:number, y:number) => NumberAdd(x, y)
228  return r.ChangeToPureOperator(simplified()->NumberAdd());
229  }
230  Type* maybe_string = Type::Union(Type::String(), Type::Receiver(), zone());
231  if (r.NeitherInputCanBe(maybe_string)) {
232  // JSAdd(x:-string, y:-string) => NumberAdd(ToNumber(x), ToNumber(y))
233  r.ConvertInputsToNumber();
234  return r.ChangeToPureOperator(simplified()->NumberAdd());
235  }
236 #if 0
237  // TODO(turbofan): Lowering of StringAdd is disabled for now because:
238  // a) The inserted ToString operation screws up valueOf vs. toString order.
239  // b) Deoptimization at ToString doesn't have corresponding bailout id.
240  // c) Our current StringAddStub is actually non-pure and requires context.
241  if (r.OneInputIs(Type::String())) {
242  // JSAdd(x:string, y:string) => StringAdd(x, y)
243  // JSAdd(x:string, y) => StringAdd(x, ToString(y))
244  // JSAdd(x, y:string) => StringAdd(ToString(x), y)
245  r.ConvertInputsToString();
246  return r.ChangeToPureOperator(simplified()->StringAdd());
247  }
248 #endif
249  return NoChange();
250 }
251 
252 
253 Reduction JSTypedLowering::ReduceNumberBinop(Node* node,
254  const Operator* numberOp) {
255  JSBinopReduction r(this, node);
256  if (r.OneInputIs(Type::Primitive())) {
257  // If at least one input is a primitive, then insert appropriate conversions
258  // to number and reduce this operator to the given numeric one.
259  // TODO(turbofan): make this heuristic configurable for code size.
260  r.ConvertInputsToNumber();
261  return r.ChangeToPureOperator(numberOp);
262  }
263  // TODO(turbofan): relax/remove the effects of this operator in other cases.
264  return NoChange();
265 }
266 
267 
268 Reduction JSTypedLowering::ReduceI32Binop(Node* node, bool left_signed,
269  bool right_signed,
270  const Operator* intOp) {
271  JSBinopReduction r(this, node);
272  // TODO(titzer): some Smi bitwise operations don't really require going
273  // all the way to int32, which can save tagging/untagging for some operations
274  // on some platforms.
275  // TODO(turbofan): make this heuristic configurable for code size.
276  r.ConvertInputsToInt32(left_signed, right_signed);
277  return r.ChangeToPureOperator(intOp);
278 }
279 
280 
281 Reduction JSTypedLowering::ReduceI32Shift(Node* node, bool left_signed,
282  const Operator* shift_op) {
283  JSBinopReduction r(this, node);
284  r.ConvertInputsForShift(left_signed);
285  return r.ChangeToPureOperator(shift_op);
286 }
287 
288 
289 Reduction JSTypedLowering::ReduceJSComparison(Node* node) {
290  JSBinopReduction r(this, node);
291  if (r.BothInputsAre(Type::String())) {
292  // If both inputs are definitely strings, perform a string comparison.
293  const Operator* stringOp;
294  switch (node->opcode()) {
295  case IrOpcode::kJSLessThan:
296  stringOp = simplified()->StringLessThan();
297  break;
298  case IrOpcode::kJSGreaterThan:
299  stringOp = simplified()->StringLessThan();
300  r.SwapInputs(); // a > b => b < a
301  break;
302  case IrOpcode::kJSLessThanOrEqual:
303  stringOp = simplified()->StringLessThanOrEqual();
304  break;
305  case IrOpcode::kJSGreaterThanOrEqual:
306  stringOp = simplified()->StringLessThanOrEqual();
307  r.SwapInputs(); // a >= b => b <= a
308  break;
309  default:
310  return NoChange();
311  }
312  return r.ChangeToPureOperator(stringOp);
313  }
314  Type* maybe_string = Type::Union(Type::String(), Type::Receiver(), zone());
315  if (r.OneInputCannotBe(maybe_string)) {
316  // If one input cannot be a string, then emit a number comparison.
317  const Operator* less_than;
318  const Operator* less_than_or_equal;
319  if (r.BothInputsAre(Type::Unsigned32())) {
320  less_than = machine()->Uint32LessThan();
321  less_than_or_equal = machine()->Uint32LessThanOrEqual();
322  } else if (r.BothInputsAre(Type::Signed32())) {
323  less_than = machine()->Int32LessThan();
324  less_than_or_equal = machine()->Int32LessThanOrEqual();
325  } else {
326  // TODO(turbofan): mixed signed/unsigned int32 comparisons.
327  r.ConvertInputsToNumber();
328  less_than = simplified()->NumberLessThan();
329  less_than_or_equal = simplified()->NumberLessThanOrEqual();
330  }
331  const Operator* comparison;
332  switch (node->opcode()) {
333  case IrOpcode::kJSLessThan:
334  comparison = less_than;
335  break;
336  case IrOpcode::kJSGreaterThan:
337  comparison = less_than;
338  r.SwapInputs(); // a > b => b < a
339  break;
340  case IrOpcode::kJSLessThanOrEqual:
341  comparison = less_than_or_equal;
342  break;
343  case IrOpcode::kJSGreaterThanOrEqual:
344  comparison = less_than_or_equal;
345  r.SwapInputs(); // a >= b => b <= a
346  break;
347  default:
348  return NoChange();
349  }
350  return r.ChangeToPureOperator(comparison);
351  }
352  // TODO(turbofan): relax/remove effects of this operator in other cases.
353  return NoChange(); // Keep a generic comparison.
354 }
355 
356 
357 Reduction JSTypedLowering::ReduceJSEqual(Node* node, bool invert) {
358  JSBinopReduction r(this, node);
359 
360  if (r.BothInputsAre(Type::Number())) {
361  return r.ChangeToPureOperator(simplified()->NumberEqual(), invert);
362  }
363  if (r.BothInputsAre(Type::String())) {
364  return r.ChangeToPureOperator(simplified()->StringEqual(), invert);
365  }
366  if (r.BothInputsAre(Type::Receiver())) {
367  return r.ChangeToPureOperator(
368  simplified()->ReferenceEqual(Type::Receiver()), invert);
369  }
370  // TODO(turbofan): js-typed-lowering of Equal(undefined)
371  // TODO(turbofan): js-typed-lowering of Equal(null)
372  // TODO(turbofan): js-typed-lowering of Equal(boolean)
373  return NoChange();
374 }
375 
376 
377 Reduction JSTypedLowering::ReduceJSStrictEqual(Node* node, bool invert) {
378  JSBinopReduction r(this, node);
379  if (r.left() == r.right()) {
380  // x === x is always true if x != NaN
381  if (!r.left_type()->Maybe(Type::NaN())) {
382  return ReplaceEagerly(node, invert ? jsgraph()->FalseConstant()
383  : jsgraph()->TrueConstant());
384  }
385  }
386  if (!r.left_type()->Maybe(r.right_type())) {
387  // Type intersection is empty; === is always false unless both
388  // inputs could be strings (one internalized and one not).
389  if (r.OneInputCannotBe(Type::String())) {
390  return ReplaceEagerly(node, invert ? jsgraph()->TrueConstant()
391  : jsgraph()->FalseConstant());
392  }
393  }
394  if (r.OneInputIs(Type::Undefined())) {
395  return r.ChangeToPureOperator(
396  simplified()->ReferenceEqual(Type::Undefined()), invert);
397  }
398  if (r.OneInputIs(Type::Null())) {
399  return r.ChangeToPureOperator(simplified()->ReferenceEqual(Type::Null()),
400  invert);
401  }
402  if (r.OneInputIs(Type::Boolean())) {
403  return r.ChangeToPureOperator(simplified()->ReferenceEqual(Type::Boolean()),
404  invert);
405  }
406  if (r.OneInputIs(Type::Object())) {
407  return r.ChangeToPureOperator(simplified()->ReferenceEqual(Type::Object()),
408  invert);
409  }
410  if (r.OneInputIs(Type::Receiver())) {
411  return r.ChangeToPureOperator(
412  simplified()->ReferenceEqual(Type::Receiver()), invert);
413  }
414  if (r.BothInputsAre(Type::String())) {
415  return r.ChangeToPureOperator(simplified()->StringEqual(), invert);
416  }
417  if (r.BothInputsAre(Type::Number())) {
418  return r.ChangeToPureOperator(simplified()->NumberEqual(), invert);
419  }
420  // TODO(turbofan): js-typed-lowering of StrictEqual(mixed types)
421  return NoChange();
422 }
423 
424 
425 Reduction JSTypedLowering::ReduceJSToNumberInput(Node* input) {
426  if (input->opcode() == IrOpcode::kJSToNumber) {
427  // Recursively try to reduce the input first.
428  Reduction result = ReduceJSToNumberInput(input->InputAt(0));
429  if (result.Changed()) {
430  RelaxEffects(input);
431  return result;
432  }
433  return Changed(input); // JSToNumber(JSToNumber(x)) => JSToNumber(x)
434  }
435  Type* input_type = NodeProperties::GetBounds(input).upper;
436  if (input_type->Is(Type::Number())) {
437  // JSToNumber(x:number) => x
438  return Changed(input);
439  }
440  if (input_type->Is(Type::Undefined())) {
441  // JSToNumber(undefined) => #NaN
442  return ReplaceWith(jsgraph()->NaNConstant());
443  }
444  if (input_type->Is(Type::Null())) {
445  // JSToNumber(null) => #0
446  return ReplaceWith(jsgraph()->ZeroConstant());
447  }
448  if (input_type->Is(Type::Boolean())) {
449  // JSToNumber(x:boolean) => BooleanToNumber(x)
450  return ReplaceWith(
451  graph()->NewNode(simplified()->BooleanToNumber(), input));
452  }
453  // TODO(turbofan): js-typed-lowering of ToNumber(x:string)
454  return NoChange();
455 }
456 
457 
458 Reduction JSTypedLowering::ReduceJSToStringInput(Node* input) {
459  if (input->opcode() == IrOpcode::kJSToString) {
460  // Recursively try to reduce the input first.
461  Reduction result = ReduceJSToStringInput(input->InputAt(0));
462  if (result.Changed()) {
463  RelaxEffects(input);
464  return result;
465  }
466  return Changed(input); // JSToString(JSToString(x)) => JSToString(x)
467  }
468  Type* input_type = NodeProperties::GetBounds(input).upper;
469  if (input_type->Is(Type::String())) {
470  return Changed(input); // JSToString(x:string) => x
471  }
472  if (input_type->Is(Type::Undefined())) {
473  return ReplaceWith(jsgraph()->HeapConstant(
474  graph()->zone()->isolate()->factory()->undefined_string()));
475  }
476  if (input_type->Is(Type::Null())) {
477  return ReplaceWith(jsgraph()->HeapConstant(
478  graph()->zone()->isolate()->factory()->null_string()));
479  }
480  // TODO(turbofan): js-typed-lowering of ToString(x:boolean)
481  // TODO(turbofan): js-typed-lowering of ToString(x:number)
482  return NoChange();
483 }
484 
485 
486 Reduction JSTypedLowering::ReduceJSToBooleanInput(Node* input) {
487  if (input->opcode() == IrOpcode::kJSToBoolean) {
488  // Recursively try to reduce the input first.
489  Reduction result = ReduceJSToBooleanInput(input->InputAt(0));
490  if (result.Changed()) {
491  RelaxEffects(input);
492  return result;
493  }
494  return Changed(input); // JSToBoolean(JSToBoolean(x)) => JSToBoolean(x)
495  }
496  Type* input_type = NodeProperties::GetBounds(input).upper;
497  if (input_type->Is(Type::Boolean())) {
498  return Changed(input); // JSToBoolean(x:boolean) => x
499  }
500  if (input_type->Is(Type::Undefined())) {
501  // JSToBoolean(undefined) => #false
502  return ReplaceWith(jsgraph()->FalseConstant());
503  }
504  if (input_type->Is(Type::Null())) {
505  // JSToBoolean(null) => #false
506  return ReplaceWith(jsgraph()->FalseConstant());
507  }
508  if (input_type->Is(Type::DetectableReceiver())) {
509  // JSToBoolean(x:detectable) => #true
510  return ReplaceWith(jsgraph()->TrueConstant());
511  }
512  if (input_type->Is(Type::Undetectable())) {
513  // JSToBoolean(x:undetectable) => #false
514  return ReplaceWith(jsgraph()->FalseConstant());
515  }
516  if (input_type->Is(Type::OrderedNumber())) {
517  // JSToBoolean(x:ordered-number) => BooleanNot(NumberEqual(x, #0))
518  Node* cmp = graph()->NewNode(simplified()->NumberEqual(), input,
519  jsgraph()->ZeroConstant());
520  Node* inv = graph()->NewNode(simplified()->BooleanNot(), cmp);
521  return ReplaceWith(inv);
522  }
523  // TODO(turbofan): js-typed-lowering of ToBoolean(string)
524  return NoChange();
525 }
526 
527 
528 Reduction JSTypedLowering::ReduceJSLoadProperty(Node* node) {
529  Node* key = NodeProperties::GetValueInput(node, 1);
530  Node* base = NodeProperties::GetValueInput(node, 0);
531  Type* key_type = NodeProperties::GetBounds(key).upper;
532  Type* base_type = NodeProperties::GetBounds(base).upper;
533  // TODO(mstarzinger): This lowering is not correct if:
534  // a) The typed array turns external (i.e. MaterializeArrayBuffer)
535  // b) The typed array or it's buffer is neutered.
536  // c) The index is out of bounds.
537  if (base_type->IsConstant() && key_type->Is(Type::Integral32()) &&
538  base_type->AsConstant()->Value()->IsJSTypedArray()) {
539  // JSLoadProperty(typed-array, int32)
540  JSTypedArray* array = JSTypedArray::cast(*base_type->AsConstant()->Value());
541  ElementsKind elements_kind = array->map()->elements_kind();
542  ExternalArrayType type = array->type();
543  uint32_t length;
544  CHECK(array->length()->ToUint32(&length));
545  ElementAccess element_access;
546  Node* elements = graph()->NewNode(
547  simplified()->LoadField(AccessBuilder::ForJSObjectElements()), base,
549  if (IsExternalArrayElementsKind(elements_kind)) {
550  elements = graph()->NewNode(
551  simplified()->LoadField(AccessBuilder::ForExternalArrayPointer()),
552  elements, NodeProperties::GetEffectInput(node));
553  element_access = AccessBuilder::ForTypedArrayElement(type, true);
554  } else {
555  DCHECK(IsFixedTypedArrayElementsKind(elements_kind));
556  element_access = AccessBuilder::ForTypedArrayElement(type, false);
557  }
558  Node* value =
559  graph()->NewNode(simplified()->LoadElement(element_access), elements,
560  key, jsgraph()->Uint32Constant(length),
562  return ReplaceEagerly(node, value);
563  }
564  return NoChange();
565 }
566 
567 
568 Reduction JSTypedLowering::ReduceJSStoreProperty(Node* node) {
569  Node* key = NodeProperties::GetValueInput(node, 1);
570  Node* base = NodeProperties::GetValueInput(node, 0);
571  Node* value = NodeProperties::GetValueInput(node, 2);
572  Type* key_type = NodeProperties::GetBounds(key).upper;
573  Type* base_type = NodeProperties::GetBounds(base).upper;
574  // TODO(mstarzinger): This lowering is not correct if:
575  // a) The typed array turns external (i.e. MaterializeArrayBuffer)
576  // b) The typed array or its buffer is neutered.
577  if (key_type->Is(Type::Integral32()) && base_type->IsConstant() &&
578  base_type->AsConstant()->Value()->IsJSTypedArray()) {
579  // JSStoreProperty(typed-array, int32, value)
580  JSTypedArray* array = JSTypedArray::cast(*base_type->AsConstant()->Value());
581  ElementsKind elements_kind = array->map()->elements_kind();
582  ExternalArrayType type = array->type();
583  uint32_t length;
584  CHECK(array->length()->ToUint32(&length));
585  ElementAccess element_access;
586  Node* elements = graph()->NewNode(
587  simplified()->LoadField(AccessBuilder::ForJSObjectElements()), base,
589  if (IsExternalArrayElementsKind(elements_kind)) {
590  elements = graph()->NewNode(
591  simplified()->LoadField(AccessBuilder::ForExternalArrayPointer()),
592  elements, NodeProperties::GetEffectInput(node));
593  element_access = AccessBuilder::ForTypedArrayElement(type, true);
594  } else {
595  DCHECK(IsFixedTypedArrayElementsKind(elements_kind));
596  element_access = AccessBuilder::ForTypedArrayElement(type, false);
597  }
598 
599  Node* check = graph()->NewNode(machine()->Uint32LessThan(), key,
600  jsgraph()->Uint32Constant(length));
601  Node* branch = graph()->NewNode(common()->Branch(), check,
603 
604  Node* if_true = graph()->NewNode(common()->IfTrue(), branch);
605 
606  Node* store =
607  graph()->NewNode(simplified()->StoreElement(element_access), elements,
608  key, jsgraph()->Uint32Constant(length), value,
609  NodeProperties::GetEffectInput(node), if_true);
610 
611  Node* if_false = graph()->NewNode(common()->IfFalse(), branch);
612 
613  Node* merge = graph()->NewNode(common()->Merge(2), if_true, if_false);
614  Node* phi = graph()->NewNode(common()->EffectPhi(2), store,
615  NodeProperties::GetEffectInput(node), merge);
616 
617  return ReplaceWith(phi);
618  }
619  return NoChange();
620 }
621 
622 
623 static Reduction ReplaceWithReduction(Node* node, Reduction reduction) {
624  if (reduction.Changed()) {
625  NodeProperties::ReplaceWithValue(node, reduction.replacement());
626  return reduction;
627  }
628  return Reducer::NoChange();
629 }
630 
631 
632 Reduction JSTypedLowering::Reduce(Node* node) {
633  switch (node->opcode()) {
634  case IrOpcode::kJSEqual:
635  return ReduceJSEqual(node, false);
636  case IrOpcode::kJSNotEqual:
637  return ReduceJSEqual(node, true);
638  case IrOpcode::kJSStrictEqual:
639  return ReduceJSStrictEqual(node, false);
640  case IrOpcode::kJSStrictNotEqual:
641  return ReduceJSStrictEqual(node, true);
642  case IrOpcode::kJSLessThan: // fall through
643  case IrOpcode::kJSGreaterThan: // fall through
644  case IrOpcode::kJSLessThanOrEqual: // fall through
645  case IrOpcode::kJSGreaterThanOrEqual:
646  return ReduceJSComparison(node);
647  case IrOpcode::kJSBitwiseOr:
648  return ReduceI32Binop(node, true, true, machine()->Word32Or());
649  case IrOpcode::kJSBitwiseXor:
650  return ReduceI32Binop(node, true, true, machine()->Word32Xor());
651  case IrOpcode::kJSBitwiseAnd:
652  return ReduceI32Binop(node, true, true, machine()->Word32And());
653  case IrOpcode::kJSShiftLeft:
654  return ReduceI32Shift(node, true, machine()->Word32Shl());
655  case IrOpcode::kJSShiftRight:
656  return ReduceI32Shift(node, true, machine()->Word32Sar());
657  case IrOpcode::kJSShiftRightLogical:
658  return ReduceI32Shift(node, false, machine()->Word32Shr());
659  case IrOpcode::kJSAdd:
660  return ReduceJSAdd(node);
661  case IrOpcode::kJSSubtract:
662  return ReduceNumberBinop(node, simplified()->NumberSubtract());
663  case IrOpcode::kJSMultiply:
664  return ReduceNumberBinop(node, simplified()->NumberMultiply());
665  case IrOpcode::kJSDivide:
666  return ReduceNumberBinop(node, simplified()->NumberDivide());
667  case IrOpcode::kJSModulus:
668  return ReduceNumberBinop(node, simplified()->NumberModulus());
669  case IrOpcode::kJSUnaryNot: {
670  Reduction result = ReduceJSToBooleanInput(node->InputAt(0));
671  Node* value;
672  if (result.Changed()) {
673  // JSUnaryNot(x:boolean) => BooleanNot(x)
674  value =
675  graph()->NewNode(simplified()->BooleanNot(), result.replacement());
677  return Changed(value);
678  } else {
679  // JSUnaryNot(x) => BooleanNot(JSToBoolean(x))
680  value = graph()->NewNode(simplified()->BooleanNot(), node);
681  node->set_op(javascript()->ToBoolean());
682  NodeProperties::ReplaceWithValue(node, value, node);
683  // Note: ReplaceUses() smashes all uses, so smash it back here.
684  value->ReplaceInput(0, node);
685  return Changed(node);
686  }
687  }
688  case IrOpcode::kJSToBoolean:
689  return ReplaceWithReduction(node,
690  ReduceJSToBooleanInput(node->InputAt(0)));
691  case IrOpcode::kJSToNumber:
692  return ReplaceWithReduction(node,
693  ReduceJSToNumberInput(node->InputAt(0)));
694  case IrOpcode::kJSToString:
695  return ReplaceWithReduction(node,
696  ReduceJSToStringInput(node->InputAt(0)));
697  case IrOpcode::kJSLoadProperty:
698  return ReduceJSLoadProperty(node);
699  case IrOpcode::kJSStoreProperty:
700  return ReduceJSStoreProperty(node);
701  case IrOpcode::kJSCallFunction:
702  return JSBuiltinReducer(jsgraph()).Reduce(node);
703  default:
704  break;
705  }
706  return NoChange();
707 }
708 
709 } // namespace compiler
710 } // namespace internal
711 } // namespace v8
bool Is(TypeImpl *that)
Definition: types.h:390
static TypeHandle Union(TypeHandle type1, TypeHandle type2, Region *reg)
Definition: types.cc:737
bool Maybe(TypeImpl *that)
Definition: types.cc:504
Node * NewNode(const Operator *op, int input_count, Node **inputs)
Definition: graph.cc:24
SimplifiedOperatorBuilder * simplified()
Reduction ChangeToPureOperator(const Operator *op, bool invert=false)
Node * ConvertToI32(bool is_signed, Node *node)
JSBinopReduction(JSTypedLowering *lowering, Node *node)
void ConvertInputsToInt32(bool left_signed, bool right_signed)
bool TryNarrowingToI32(Type *type, Node *node)
static void ReplaceWithValue(Node *node, Node *value, Node *effect=NULL)
static void ReplaceEffectInput(Node *node, Node *effect, int index=0)
static Node * GetContextInput(Node *node)
static Node * GetValueInput(Node *node, int index)
static void SetBounds(Node *node, Bounds bounds)
static Node * GetEffectInput(Node *node, int index=0)
static Node * GetControlInput(Node *node, int index=0)
static int GetEffectInputCount(const Operator *op)
static int GetValueInputCount(const Operator *op)
static bool HasContextInput(const Operator *op)
static int GetControlInputCount(const Operator *op)
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 CHECK(condition)
Definition: logging.h:36
#define DCHECK(condition)
Definition: logging.h:205
#define DCHECK_EQ(v1, v2)
Definition: logging.h:206
static Reduction ReplaceWithReduction(Node *node, Reduction reduction)
static void RelaxEffects(Node *node)
bool IsExternalArrayElementsKind(ElementsKind kind)
Definition: elements-kind.h:95
TypeImpl< ZoneTypeConfig > Type
int ToNumber(Register reg)
kSerializedDataOffset Object
Definition: objects-inl.h:5322
BoundsImpl< ZoneTypeConfig > Bounds
Definition: types.h:1047
bool IsFixedTypedArrayElementsKind(ElementsKind kind)
Debugger support for the V8 JavaScript engine.
Definition: accessors.cc:20
ExternalArrayType
Definition: v8.h:2217
Handle< Primitive > Null(Isolate *isolate)
Definition: v8.h:6845
Handle< Primitive > Undefined(Isolate *isolate)
Definition: v8.h:6836