deps: update v8 to 4.3.61.21
[platform/upstream/nodejs.git] / deps / v8 / src / compiler / js-typed-lowering.cc
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/compiler/access-builder.h"
6 #include "src/compiler/js-graph.h"
7 #include "src/compiler/js-typed-lowering.h"
8 #include "src/compiler/node-matchers.h"
9 #include "src/compiler/node-properties.h"
10 #include "src/compiler/operator-properties.h"
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
21
22 // Relax the effects of {node} by immediately replacing effect and control uses
23 // of {node} with the effect and control input to {node}.
24 // TODO(turbofan): replace the effect input to {node} with {graph->start()}.
25 // TODO(titzer): move into a GraphEditor?
26 static void RelaxEffectsAndControls(Node* node) {
27   NodeProperties::ReplaceWithValue(node, node, NULL);
28 }
29
30
31 // Relax the control uses of {node} by immediately replacing them with the
32 // control input to {node}.
33 // TODO(titzer): move into a GraphEditor?
34 static void RelaxControls(Node* node) {
35   NodeProperties::ReplaceWithValue(node, node, node);
36 }
37
38
39 JSTypedLowering::JSTypedLowering(JSGraph* jsgraph, Zone* zone)
40     : jsgraph_(jsgraph), simplified_(graph()->zone()), conversions_(zone) {
41   zero_range_ = Type::Range(0.0, 0.0, graph()->zone());
42   one_range_ = Type::Range(1.0, 1.0, graph()->zone());
43   zero_thirtyone_range_ = Type::Range(0.0, 31.0, graph()->zone());
44   for (size_t k = 0; k < arraysize(shifted_int32_ranges_); ++k) {
45     double min = kMinInt / (1 << k);
46     double max = kMaxInt / (1 << k);
47     shifted_int32_ranges_[k] = Type::Range(min, max, graph()->zone());
48   }
49 }
50
51
52 Reduction JSTypedLowering::ReplaceEagerly(Node* old, Node* node) {
53   NodeProperties::ReplaceWithValue(old, node, node);
54   return Changed(node);
55 }
56
57
58 // A helper class to simplify the process of reducing a single binop node with a
59 // JSOperator. This class manages the rewriting of context, control, and effect
60 // dependencies during lowering of a binop and contains numerous helper
61 // functions for matching the types of inputs to an operation.
62 class JSBinopReduction FINAL {
63  public:
64   JSBinopReduction(JSTypedLowering* lowering, Node* node)
65       : lowering_(lowering), node_(node) {}
66
67   void ConvertPrimitiveInputsToNumber() {
68     node_->ReplaceInput(0, ConvertPrimitiveToNumber(left()));
69     node_->ReplaceInput(1, ConvertPrimitiveToNumber(right()));
70   }
71
72   void ConvertInputsToNumber(Node* frame_state) {
73     // To convert the inputs to numbers, we have to provide frame states
74     // for lazy bailouts in the ToNumber conversions.
75     // We use a little hack here: we take the frame state before the binary
76     // operation and use it to construct the frame states for the conversion
77     // so that after the deoptimization, the binary operation IC gets
78     // already converted values from full code. This way we are sure that we
79     // will not re-do any of the side effects.
80
81     Node* left_input =
82         left_type()->Is(Type::PlainPrimitive())
83             ? ConvertPrimitiveToNumber(left())
84             : ConvertToNumber(left(),
85                               CreateFrameStateForLeftInput(frame_state));
86
87     Node* right_input =
88         right_type()->Is(Type::PlainPrimitive())
89             ? ConvertPrimitiveToNumber(right())
90             : ConvertToNumber(right(), CreateFrameStateForRightInput(
91                                            frame_state, left_input));
92
93     node_->ReplaceInput(0, left_input);
94     node_->ReplaceInput(1, right_input);
95   }
96
97   void ConvertInputsToUI32(Signedness left_signedness,
98                            Signedness right_signedness) {
99     node_->ReplaceInput(0, ConvertToUI32(left(), left_signedness));
100     node_->ReplaceInput(1, ConvertToUI32(right(), right_signedness));
101   }
102
103   void ConvertInputsToString() {
104     node_->ReplaceInput(0, ConvertToString(left()));
105     node_->ReplaceInput(1, ConvertToString(right()));
106   }
107
108   // Convert inputs for bitwise shift operation (ES5 spec 11.7).
109   void ConvertInputsForShift(Signedness left_signedness) {
110     node_->ReplaceInput(
111         0, ConvertToUI32(ConvertPrimitiveToNumber(left()), left_signedness));
112     Node* rnum = ConvertToUI32(ConvertPrimitiveToNumber(right()), kUnsigned);
113     Type* rnum_type = NodeProperties::GetBounds(rnum).upper;
114     if (!rnum_type->Is(lowering_->zero_thirtyone_range_)) {
115       rnum = graph()->NewNode(machine()->Word32And(), rnum,
116                               jsgraph()->Int32Constant(0x1F));
117     }
118     node_->ReplaceInput(1, rnum);
119   }
120
121   void SwapInputs() {
122     Node* l = left();
123     Node* r = right();
124     node_->ReplaceInput(0, r);
125     node_->ReplaceInput(1, l);
126   }
127
128   // Remove all effect and control inputs and outputs to this node and change
129   // to the pure operator {op}, possibly inserting a boolean inversion.
130   Reduction ChangeToPureOperator(const Operator* op, bool invert = false,
131                                  Type* type = Type::Any()) {
132     DCHECK_EQ(0, op->EffectInputCount());
133     DCHECK_EQ(false, OperatorProperties::HasContextInput(op));
134     DCHECK_EQ(0, op->ControlInputCount());
135     DCHECK_EQ(2, op->ValueInputCount());
136
137     // Remove the effects from the node, and update its effect/control usages.
138     if (node_->op()->EffectInputCount() > 0) {
139       RelaxEffectsAndControls(node_);
140     }
141     // Remove the inputs corresponding to context, effect, and control.
142     NodeProperties::RemoveNonValueInputs(node_);
143     // Finally, update the operator to the new one.
144     node_->set_op(op);
145
146     // TODO(jarin): Replace the explicit typing hack with a call to some method
147     // that encapsulates changing the operator and re-typing.
148     Bounds const bounds = NodeProperties::GetBounds(node_);
149     NodeProperties::SetBounds(node_, Bounds::NarrowUpper(bounds, type, zone()));
150
151     if (invert) {
152       // Insert an boolean not to invert the value.
153       Node* value = graph()->NewNode(simplified()->BooleanNot(), node_);
154       node_->ReplaceUses(value);
155       // Note: ReplaceUses() smashes all uses, so smash it back here.
156       value->ReplaceInput(0, node_);
157       return lowering_->Replace(value);
158     }
159     return lowering_->Changed(node_);
160   }
161
162   Reduction ChangeToPureOperator(const Operator* op, Type* type) {
163     return ChangeToPureOperator(op, false, type);
164   }
165
166   bool OneInputIs(Type* t) { return left_type()->Is(t) || right_type()->Is(t); }
167
168   bool BothInputsAre(Type* t) {
169     return left_type()->Is(t) && right_type()->Is(t);
170   }
171
172   bool OneInputCannotBe(Type* t) {
173     return !left_type()->Maybe(t) || !right_type()->Maybe(t);
174   }
175
176   bool NeitherInputCanBe(Type* t) {
177     return !left_type()->Maybe(t) && !right_type()->Maybe(t);
178   }
179
180   Node* effect() { return NodeProperties::GetEffectInput(node_); }
181   Node* control() { return NodeProperties::GetControlInput(node_); }
182   Node* context() { return NodeProperties::GetContextInput(node_); }
183   Node* left() { return NodeProperties::GetValueInput(node_, 0); }
184   Node* right() { return NodeProperties::GetValueInput(node_, 1); }
185   Type* left_type() {
186     return NodeProperties::GetBounds(node_->InputAt(0)).upper;
187   }
188   Type* right_type() {
189     return NodeProperties::GetBounds(node_->InputAt(1)).upper;
190   }
191
192   SimplifiedOperatorBuilder* simplified() { return lowering_->simplified(); }
193   Graph* graph() const { return lowering_->graph(); }
194   JSGraph* jsgraph() { return lowering_->jsgraph(); }
195   JSOperatorBuilder* javascript() { return lowering_->javascript(); }
196   MachineOperatorBuilder* machine() { return lowering_->machine(); }
197   Zone* zone() const { return graph()->zone(); }
198
199  private:
200   JSTypedLowering* lowering_;  // The containing lowering instance.
201   Node* node_;                 // The original node.
202
203   Node* ConvertToString(Node* node) {
204     // Avoid introducing too many eager ToString() operations.
205     Reduction reduced = lowering_->ReduceJSToStringInput(node);
206     if (reduced.Changed()) return reduced.replacement();
207     Node* n = graph()->NewNode(javascript()->ToString(), node, context(),
208                                effect(), control());
209     update_effect(n);
210     return n;
211   }
212
213   Node* CreateFrameStateForLeftInput(Node* frame_state) {
214     if (!FLAG_turbo_deoptimization) return nullptr;
215
216     FrameStateCallInfo state_info =
217         OpParameter<FrameStateCallInfo>(frame_state);
218     // If the frame state is already the right one, just return it.
219     if (state_info.state_combine().kind() == OutputFrameStateCombine::kPokeAt &&
220         state_info.state_combine().GetOffsetToPokeAt() == 1) {
221       return frame_state;
222     }
223
224     // Here, we smash the result of the conversion into the slot just below
225     // the stack top. This is the slot that full code uses to store the
226     // left operand.
227     const Operator* op = jsgraph()->common()->FrameState(
228         state_info.type(), state_info.bailout_id(),
229         OutputFrameStateCombine::PokeAt(1));
230
231     return graph()->NewNode(op, frame_state->InputAt(0),
232                             frame_state->InputAt(1), frame_state->InputAt(2),
233                             frame_state->InputAt(3), frame_state->InputAt(4));
234   }
235
236   Node* CreateFrameStateForRightInput(Node* frame_state, Node* converted_left) {
237     if (!FLAG_turbo_deoptimization) return nullptr;
238
239     FrameStateCallInfo state_info =
240         OpParameter<FrameStateCallInfo>(frame_state);
241
242     if (state_info.bailout_id() == BailoutId::None()) {
243       // Dummy frame state => just leave it as is.
244       return frame_state;
245     }
246
247     // Create a frame state that stores the result of the operation to the
248     // top of the stack (i.e., the slot used for the right operand).
249     const Operator* op = jsgraph()->common()->FrameState(
250         state_info.type(), state_info.bailout_id(),
251         OutputFrameStateCombine::PokeAt(0));
252
253     // Change the left operand {converted_left} on the expression stack.
254     Node* stack = frame_state->InputAt(2);
255     DCHECK_EQ(stack->opcode(), IrOpcode::kStateValues);
256     DCHECK_GE(stack->InputCount(), 2);
257
258     // TODO(jarin) Allocate in a local zone or a reusable buffer.
259     NodeVector new_values(stack->InputCount(), zone());
260     for (int i = 0; i < stack->InputCount(); i++) {
261       if (i == stack->InputCount() - 2) {
262         new_values[i] = converted_left;
263       } else {
264         new_values[i] = stack->InputAt(i);
265       }
266     }
267     Node* new_stack =
268         graph()->NewNode(stack->op(), stack->InputCount(), &new_values.front());
269
270     return graph()->NewNode(op, frame_state->InputAt(0),
271                             frame_state->InputAt(1), new_stack,
272                             frame_state->InputAt(3), frame_state->InputAt(4));
273   }
274
275   Node* ConvertPrimitiveToNumber(Node* node) {
276     return lowering_->ConvertPrimitiveToNumber(node);
277   }
278
279   Node* ConvertToNumber(Node* node, Node* frame_state) {
280     if (NodeProperties::GetBounds(node).upper->Is(Type::PlainPrimitive())) {
281       return ConvertPrimitiveToNumber(node);
282     } else if (!FLAG_turbo_deoptimization) {
283       // We cannot use ConvertToPrimitiveNumber here because we need context
284       // for converting general values.
285       Node* const n = graph()->NewNode(javascript()->ToNumber(), node,
286                                        context(), effect(), control());
287       update_effect(n);
288       return n;
289     } else {
290       Node* const n =
291           graph()->NewNode(javascript()->ToNumber(), node, context(),
292                            frame_state, effect(), control());
293       update_effect(n);
294       return n;
295     }
296   }
297
298   Node* ConvertToUI32(Node* node, Signedness signedness) {
299     // Avoid introducing too many eager NumberToXXnt32() operations.
300     Type* type = NodeProperties::GetBounds(node).upper;
301     if (signedness == kSigned) {
302       if (!type->Is(Type::Signed32())) {
303         node = graph()->NewNode(simplified()->NumberToInt32(), node);
304       }
305     } else {
306       DCHECK_EQ(kUnsigned, signedness);
307       if (!type->Is(Type::Unsigned32())) {
308         node = graph()->NewNode(simplified()->NumberToUint32(), node);
309       }
310     }
311     return node;
312   }
313
314   void update_effect(Node* effect) {
315     NodeProperties::ReplaceEffectInput(node_, effect);
316   }
317 };
318
319
320 Reduction JSTypedLowering::ReduceJSAdd(Node* node) {
321   JSBinopReduction r(this, node);
322   if (r.BothInputsAre(Type::Number())) {
323     // JSAdd(x:number, y:number) => NumberAdd(x, y)
324     return r.ChangeToPureOperator(simplified()->NumberAdd(), Type::Number());
325   }
326   if (r.NeitherInputCanBe(Type::StringOrReceiver())) {
327     // JSAdd(x:-string, y:-string) => NumberAdd(ToNumber(x), ToNumber(y))
328     Node* frame_state = FLAG_turbo_deoptimization
329                             ? NodeProperties::GetFrameStateInput(node, 1)
330                             : nullptr;
331     r.ConvertInputsToNumber(frame_state);
332     return r.ChangeToPureOperator(simplified()->NumberAdd(), Type::Number());
333   }
334 #if 0
335   // TODO(turbofan): Lowering of StringAdd is disabled for now because:
336   //   a) The inserted ToString operation screws up valueOf vs. toString order.
337   //   b) Deoptimization at ToString doesn't have corresponding bailout id.
338   //   c) Our current StringAddStub is actually non-pure and requires context.
339   if (r.OneInputIs(Type::String())) {
340     // JSAdd(x:string, y:string) => StringAdd(x, y)
341     // JSAdd(x:string, y) => StringAdd(x, ToString(y))
342     // JSAdd(x, y:string) => StringAdd(ToString(x), y)
343     r.ConvertInputsToString();
344     return r.ChangeToPureOperator(simplified()->StringAdd());
345   }
346 #endif
347   return NoChange();
348 }
349
350
351 Reduction JSTypedLowering::ReduceNumberBinop(Node* node,
352                                              const Operator* numberOp) {
353   JSBinopReduction r(this, node);
354   Node* frame_state = FLAG_turbo_deoptimization
355                           ? NodeProperties::GetFrameStateInput(node, 1)
356                           : nullptr;
357   r.ConvertInputsToNumber(frame_state);
358   return r.ChangeToPureOperator(numberOp, Type::Number());
359 }
360
361
362 Reduction JSTypedLowering::ReduceInt32Binop(Node* node, const Operator* intOp) {
363   JSBinopReduction r(this, node);
364   Node* frame_state = FLAG_turbo_deoptimization
365                           ? NodeProperties::GetFrameStateInput(node, 1)
366                           : nullptr;
367   r.ConvertInputsToNumber(frame_state);
368   r.ConvertInputsToUI32(kSigned, kSigned);
369   return r.ChangeToPureOperator(intOp, Type::Integral32());
370 }
371
372
373 Reduction JSTypedLowering::ReduceUI32Shift(Node* node,
374                                            Signedness left_signedness,
375                                            const Operator* shift_op) {
376   JSBinopReduction r(this, node);
377   if (r.BothInputsAre(Type::Primitive())) {
378     r.ConvertInputsForShift(left_signedness);
379     return r.ChangeToPureOperator(shift_op, Type::Integral32());
380   }
381   return NoChange();
382 }
383
384
385 Reduction JSTypedLowering::ReduceJSComparison(Node* node) {
386   JSBinopReduction r(this, node);
387   if (r.BothInputsAre(Type::String())) {
388     // If both inputs are definitely strings, perform a string comparison.
389     const Operator* stringOp;
390     switch (node->opcode()) {
391       case IrOpcode::kJSLessThan:
392         stringOp = simplified()->StringLessThan();
393         break;
394       case IrOpcode::kJSGreaterThan:
395         stringOp = simplified()->StringLessThan();
396         r.SwapInputs();  // a > b => b < a
397         break;
398       case IrOpcode::kJSLessThanOrEqual:
399         stringOp = simplified()->StringLessThanOrEqual();
400         break;
401       case IrOpcode::kJSGreaterThanOrEqual:
402         stringOp = simplified()->StringLessThanOrEqual();
403         r.SwapInputs();  // a >= b => b <= a
404         break;
405       default:
406         return NoChange();
407     }
408     return r.ChangeToPureOperator(stringOp);
409   }
410 #if 0
411   // TODO(turbofan): General ToNumber disabled for now because:
412   //   a) The inserted ToNumber operation screws up observability of valueOf.
413   //   b) Deoptimization at ToNumber doesn't have corresponding bailout id.
414   Type* maybe_string = Type::Union(Type::String(), Type::Receiver(), zone());
415   if (r.OneInputCannotBe(maybe_string)) {
416     // If one input cannot be a string, then emit a number comparison.
417     ...
418   }
419 #endif
420   if (r.BothInputsAre(Type::PlainPrimitive()) &&
421       r.OneInputCannotBe(Type::StringOrReceiver())) {
422     const Operator* less_than;
423     const Operator* less_than_or_equal;
424     if (r.BothInputsAre(Type::Unsigned32())) {
425       less_than = machine()->Uint32LessThan();
426       less_than_or_equal = machine()->Uint32LessThanOrEqual();
427     } else if (r.BothInputsAre(Type::Signed32())) {
428       less_than = machine()->Int32LessThan();
429       less_than_or_equal = machine()->Int32LessThanOrEqual();
430     } else {
431       // TODO(turbofan): mixed signed/unsigned int32 comparisons.
432       r.ConvertPrimitiveInputsToNumber();
433       less_than = simplified()->NumberLessThan();
434       less_than_or_equal = simplified()->NumberLessThanOrEqual();
435     }
436     const Operator* comparison;
437     switch (node->opcode()) {
438       case IrOpcode::kJSLessThan:
439         comparison = less_than;
440         break;
441       case IrOpcode::kJSGreaterThan:
442         comparison = less_than;
443         r.SwapInputs();  // a > b => b < a
444         break;
445       case IrOpcode::kJSLessThanOrEqual:
446         comparison = less_than_or_equal;
447         break;
448       case IrOpcode::kJSGreaterThanOrEqual:
449         comparison = less_than_or_equal;
450         r.SwapInputs();  // a >= b => b <= a
451         break;
452       default:
453         return NoChange();
454     }
455     return r.ChangeToPureOperator(comparison);
456   }
457   // TODO(turbofan): relax/remove effects of this operator in other cases.
458   return NoChange();  // Keep a generic comparison.
459 }
460
461
462 Reduction JSTypedLowering::ReduceJSEqual(Node* node, bool invert) {
463   JSBinopReduction r(this, node);
464
465   if (r.BothInputsAre(Type::Number())) {
466     return r.ChangeToPureOperator(simplified()->NumberEqual(), invert);
467   }
468   if (r.BothInputsAre(Type::String())) {
469     return r.ChangeToPureOperator(simplified()->StringEqual(), invert);
470   }
471   if (r.BothInputsAre(Type::Receiver())) {
472     return r.ChangeToPureOperator(
473         simplified()->ReferenceEqual(Type::Receiver()), invert);
474   }
475   // TODO(turbofan): js-typed-lowering of Equal(undefined)
476   // TODO(turbofan): js-typed-lowering of Equal(null)
477   // TODO(turbofan): js-typed-lowering of Equal(boolean)
478   return NoChange();
479 }
480
481
482 Reduction JSTypedLowering::ReduceJSStrictEqual(Node* node, bool invert) {
483   JSBinopReduction r(this, node);
484   if (r.left() == r.right()) {
485     // x === x is always true if x != NaN
486     if (!r.left_type()->Maybe(Type::NaN())) {
487       return ReplaceEagerly(node, jsgraph()->BooleanConstant(!invert));
488     }
489   }
490   if (r.OneInputCannotBe(Type::NumberOrString())) {
491     // For values with canonical representation (i.e. not string nor number) an
492     // empty type intersection means the values cannot be strictly equal.
493     if (!r.left_type()->Maybe(r.right_type())) {
494       return ReplaceEagerly(node, jsgraph()->BooleanConstant(invert));
495     }
496   }
497   if (r.OneInputIs(Type::Undefined())) {
498     return r.ChangeToPureOperator(
499         simplified()->ReferenceEqual(Type::Undefined()), invert);
500   }
501   if (r.OneInputIs(Type::Null())) {
502     return r.ChangeToPureOperator(simplified()->ReferenceEqual(Type::Null()),
503                                   invert);
504   }
505   if (r.OneInputIs(Type::Boolean())) {
506     return r.ChangeToPureOperator(simplified()->ReferenceEqual(Type::Boolean()),
507                                   invert);
508   }
509   if (r.OneInputIs(Type::Object())) {
510     return r.ChangeToPureOperator(simplified()->ReferenceEqual(Type::Object()),
511                                   invert);
512   }
513   if (r.OneInputIs(Type::Receiver())) {
514     return r.ChangeToPureOperator(
515         simplified()->ReferenceEqual(Type::Receiver()), invert);
516   }
517   if (r.BothInputsAre(Type::String())) {
518     return r.ChangeToPureOperator(simplified()->StringEqual(), invert);
519   }
520   if (r.BothInputsAre(Type::Number())) {
521     return r.ChangeToPureOperator(simplified()->NumberEqual(), invert);
522   }
523   // TODO(turbofan): js-typed-lowering of StrictEqual(mixed types)
524   return NoChange();
525 }
526
527
528 Reduction JSTypedLowering::ReduceJSUnaryNot(Node* node) {
529   Node* const input = node->InputAt(0);
530   Type* const input_type = NodeProperties::GetBounds(input).upper;
531   if (input_type->Is(Type::Boolean())) {
532     // JSUnaryNot(x:boolean) => BooleanNot(x)
533     node->set_op(simplified()->BooleanNot());
534     node->TrimInputCount(1);
535     return Changed(node);
536   } else if (input_type->Is(Type::OrderedNumber())) {
537     // JSUnaryNot(x:number) => NumberEqual(x,#0)
538     node->set_op(simplified()->NumberEqual());
539     node->ReplaceInput(1, jsgraph()->ZeroConstant());
540     node->TrimInputCount(2);
541     return Changed(node);
542   } else if (input_type->Is(Type::String())) {
543     // JSUnaryNot(x:string) => NumberEqual(x.length,#0)
544     FieldAccess const access = AccessBuilder::ForStringLength();
545     // It is safe for the load to be effect-free (i.e. not linked into effect
546     // chain) because we assume String::length to be immutable.
547     Node* length = graph()->NewNode(simplified()->LoadField(access), input,
548                                     graph()->start(), graph()->start());
549     node->set_op(simplified()->NumberEqual());
550     node->ReplaceInput(0, length);
551     node->ReplaceInput(1, jsgraph()->ZeroConstant());
552     node->TrimInputCount(2);
553     NodeProperties::ReplaceWithValue(node, node, length);
554     return Changed(node);
555   }
556   return NoChange();
557 }
558
559
560 Reduction JSTypedLowering::ReduceJSToBoolean(Node* node) {
561   Node* const input = node->InputAt(0);
562   Type* const input_type = NodeProperties::GetBounds(input).upper;
563   if (input_type->Is(Type::Boolean())) {
564     // JSToBoolean(x:boolean) => x
565     return Replace(input);
566   } else if (input_type->Is(Type::OrderedNumber())) {
567     // JSToBoolean(x:ordered-number) => BooleanNot(NumberEqual(x,#0))
568     node->set_op(simplified()->BooleanNot());
569     node->ReplaceInput(0, graph()->NewNode(simplified()->NumberEqual(), input,
570                                            jsgraph()->ZeroConstant()));
571     node->TrimInputCount(1);
572     return Changed(node);
573   } else if (input_type->Is(Type::String())) {
574     // JSToBoolean(x:string) => NumberLessThan(#0,x.length)
575     FieldAccess const access = AccessBuilder::ForStringLength();
576     // It is safe for the load to be effect-free (i.e. not linked into effect
577     // chain) because we assume String::length to be immutable.
578     Node* length = graph()->NewNode(simplified()->LoadField(access), input,
579                                     graph()->start(), graph()->start());
580     node->set_op(simplified()->NumberLessThan());
581     node->ReplaceInput(0, jsgraph()->ZeroConstant());
582     node->ReplaceInput(1, length);
583     node->TrimInputCount(2);
584     return Changed(node);
585   }
586   return NoChange();
587 }
588
589
590 Reduction JSTypedLowering::ReduceJSToNumberInput(Node* input) {
591   if (input->opcode() == IrOpcode::kJSToNumber) {
592     // Recursively try to reduce the input first.
593     Reduction result = ReduceJSToNumber(input);
594     if (result.Changed()) return result;
595     return Changed(input);  // JSToNumber(JSToNumber(x)) => JSToNumber(x)
596   }
597   // Check if we have a cached conversion.
598   Node* conversion = FindConversion<IrOpcode::kJSToNumber>(input);
599   if (conversion) return Replace(conversion);
600   Type* input_type = NodeProperties::GetBounds(input).upper;
601   if (input_type->Is(Type::Number())) {
602     // JSToNumber(x:number) => x
603     return Changed(input);
604   }
605   if (input_type->Is(Type::Undefined())) {
606     // JSToNumber(undefined) => #NaN
607     return Replace(jsgraph()->NaNConstant());
608   }
609   if (input_type->Is(Type::Null())) {
610     // JSToNumber(null) => #0
611     return Replace(jsgraph()->ZeroConstant());
612   }
613   if (input_type->Is(Type::Boolean())) {
614     // JSToNumber(x:boolean) => BooleanToNumber(x)
615     return Replace(graph()->NewNode(simplified()->BooleanToNumber(), input));
616   }
617   // TODO(turbofan): js-typed-lowering of ToNumber(x:string)
618   return NoChange();
619 }
620
621
622 Reduction JSTypedLowering::ReduceJSToNumber(Node* node) {
623   // Try to reduce the input first.
624   Node* const input = node->InputAt(0);
625   Reduction reduction = ReduceJSToNumberInput(input);
626   if (reduction.Changed()) {
627     NodeProperties::ReplaceWithValue(node, reduction.replacement());
628     return reduction;
629   }
630   Type* const input_type = NodeProperties::GetBounds(input).upper;
631   if (input_type->Is(Type::PlainPrimitive())) {
632     if (input->opcode() == IrOpcode::kPhi) {
633       // JSToNumber(phi(x1,...,xn,control):plain-primitive,context)
634       //   => phi(JSToNumber(x1,no-context),
635       //          ...,
636       //          JSToNumber(xn,no-context),control)
637       int const input_count = input->InputCount() - 1;
638       Node* const control = input->InputAt(input_count);
639       DCHECK_LE(0, input_count);
640       DCHECK(NodeProperties::IsControl(control));
641       DCHECK(NodeProperties::GetBounds(node).upper->Is(Type::Number()));
642       DCHECK(!NodeProperties::GetBounds(input).upper->Is(Type::Number()));
643       RelaxEffectsAndControls(node);
644       node->set_op(common()->Phi(kMachAnyTagged, input_count));
645       for (int i = 0; i < input_count; ++i) {
646         // We must be very careful not to introduce cycles when pushing
647         // operations into phis. It is safe for {value}, since it appears
648         // as input to the phi that we are replacing, but it's not safe
649         // to simply reuse the context of the {node}. However, ToNumber()
650         // does not require a context anyways, so it's safe to discard it
651         // here and pass the dummy context.
652         Node* const value = ConvertPrimitiveToNumber(input->InputAt(i));
653         if (i < node->InputCount()) {
654           node->ReplaceInput(i, value);
655         } else {
656           node->AppendInput(graph()->zone(), value);
657         }
658       }
659       if (input_count < node->InputCount()) {
660         node->ReplaceInput(input_count, control);
661       } else {
662         node->AppendInput(graph()->zone(), control);
663       }
664       node->TrimInputCount(input_count + 1);
665       return Changed(node);
666     }
667     if (input->opcode() == IrOpcode::kSelect) {
668       // JSToNumber(select(c,x1,x2):plain-primitive,context)
669       //   => select(c,JSToNumber(x1,no-context),JSToNumber(x2,no-context))
670       int const input_count = input->InputCount();
671       BranchHint const input_hint = SelectParametersOf(input->op()).hint();
672       DCHECK_EQ(3, input_count);
673       DCHECK(NodeProperties::GetBounds(node).upper->Is(Type::Number()));
674       DCHECK(!NodeProperties::GetBounds(input).upper->Is(Type::Number()));
675       RelaxEffectsAndControls(node);
676       node->set_op(common()->Select(kMachAnyTagged, input_hint));
677       node->ReplaceInput(0, input->InputAt(0));
678       for (int i = 1; i < input_count; ++i) {
679         // We must be very careful not to introduce cycles when pushing
680         // operations into selects. It is safe for {value}, since it appears
681         // as input to the select that we are replacing, but it's not safe
682         // to simply reuse the context of the {node}. However, ToNumber()
683         // does not require a context anyways, so it's safe to discard it
684         // here and pass the dummy context.
685         Node* const value = ConvertPrimitiveToNumber(input->InputAt(i));
686         node->ReplaceInput(i, value);
687       }
688       node->TrimInputCount(input_count);
689       return Changed(node);
690     }
691     // Remember this conversion.
692     InsertConversion(node);
693     if (NodeProperties::GetContextInput(node) !=
694             jsgraph()->NoContextConstant() ||
695         NodeProperties::GetEffectInput(node) != graph()->start() ||
696         NodeProperties::GetControlInput(node) != graph()->start()) {
697       // JSToNumber(x:plain-primitive,context,effect,control)
698       //   => JSToNumber(x,no-context,start,start)
699       RelaxEffectsAndControls(node);
700       NodeProperties::ReplaceContextInput(node, jsgraph()->NoContextConstant());
701       NodeProperties::ReplaceControlInput(node, graph()->start());
702       NodeProperties::ReplaceEffectInput(node, graph()->start());
703       if (FLAG_turbo_deoptimization) {
704         DCHECK_EQ(1, OperatorProperties::GetFrameStateInputCount(node->op()));
705         NodeProperties::ReplaceFrameStateInput(node, 0,
706                                                jsgraph()->EmptyFrameState());
707       }
708       return Changed(node);
709     }
710   }
711   return NoChange();
712 }
713
714
715 Reduction JSTypedLowering::ReduceJSToStringInput(Node* input) {
716   if (input->opcode() == IrOpcode::kJSToString) {
717     // Recursively try to reduce the input first.
718     Reduction result = ReduceJSToString(input);
719     if (result.Changed()) return result;
720     return Changed(input);  // JSToString(JSToString(x)) => JSToString(x)
721   }
722   Type* input_type = NodeProperties::GetBounds(input).upper;
723   if (input_type->Is(Type::String())) {
724     return Changed(input);  // JSToString(x:string) => x
725   }
726   if (input_type->Is(Type::Undefined())) {
727     return Replace(jsgraph()->HeapConstant(factory()->undefined_string()));
728   }
729   if (input_type->Is(Type::Null())) {
730     return Replace(jsgraph()->HeapConstant(factory()->null_string()));
731   }
732   // TODO(turbofan): js-typed-lowering of ToString(x:boolean)
733   // TODO(turbofan): js-typed-lowering of ToString(x:number)
734   return NoChange();
735 }
736
737
738 Reduction JSTypedLowering::ReduceJSToString(Node* node) {
739   // Try to reduce the input first.
740   Node* const input = node->InputAt(0);
741   Reduction reduction = ReduceJSToStringInput(input);
742   if (reduction.Changed()) {
743     NodeProperties::ReplaceWithValue(node, reduction.replacement());
744     return reduction;
745   }
746   return NoChange();
747 }
748
749
750 Reduction JSTypedLowering::ReduceJSLoadProperty(Node* node) {
751   Node* key = NodeProperties::GetValueInput(node, 1);
752   Node* base = NodeProperties::GetValueInput(node, 0);
753   Type* key_type = NodeProperties::GetBounds(key).upper;
754   // TODO(mstarzinger): This lowering is not correct if:
755   //   a) The typed array or it's buffer is neutered.
756   HeapObjectMatcher<Object> mbase(base);
757   if (mbase.HasValue() && mbase.Value().handle()->IsJSTypedArray()) {
758     Handle<JSTypedArray> const array =
759         Handle<JSTypedArray>::cast(mbase.Value().handle());
760     array->GetBuffer()->set_is_neuterable(false);
761     BufferAccess const access(array->type());
762     size_t const k = ElementSizeLog2Of(access.machine_type());
763     double const byte_length = array->byte_length()->Number();
764     CHECK_LT(k, arraysize(shifted_int32_ranges_));
765     if (IsExternalArrayElementsKind(array->map()->elements_kind()) &&
766         key_type->Is(shifted_int32_ranges_[k]) && byte_length <= kMaxInt) {
767       // JSLoadProperty(typed-array, int32)
768       Handle<ExternalArray> elements =
769           Handle<ExternalArray>::cast(handle(array->elements()));
770       Node* buffer = jsgraph()->PointerConstant(elements->external_pointer());
771       Node* length = jsgraph()->Constant(byte_length);
772       Node* effect = NodeProperties::GetEffectInput(node);
773       Node* control = NodeProperties::GetControlInput(node);
774       // Check if we can avoid the bounds check.
775       if (key_type->Min() >= 0 && key_type->Max() < array->length()->Number()) {
776         Node* load = graph()->NewNode(
777             simplified()->LoadElement(
778                 AccessBuilder::ForTypedArrayElement(array->type(), true)),
779             buffer, key, effect, control);
780         return ReplaceEagerly(node, load);
781       }
782       // Compute byte offset.
783       Node* offset = Word32Shl(key, static_cast<int>(k));
784       Node* load = graph()->NewNode(simplified()->LoadBuffer(access), buffer,
785                                     offset, length, effect, control);
786       return ReplaceEagerly(node, load);
787     }
788   }
789   return NoChange();
790 }
791
792
793 Reduction JSTypedLowering::ReduceJSStoreProperty(Node* node) {
794   Node* key = NodeProperties::GetValueInput(node, 1);
795   Node* base = NodeProperties::GetValueInput(node, 0);
796   Node* value = NodeProperties::GetValueInput(node, 2);
797   Type* key_type = NodeProperties::GetBounds(key).upper;
798   Type* value_type = NodeProperties::GetBounds(value).upper;
799   // TODO(mstarzinger): This lowering is not correct if:
800   //   a) The typed array or its buffer is neutered.
801   HeapObjectMatcher<Object> mbase(base);
802   if (mbase.HasValue() && mbase.Value().handle()->IsJSTypedArray()) {
803     Handle<JSTypedArray> const array =
804         Handle<JSTypedArray>::cast(mbase.Value().handle());
805     array->GetBuffer()->set_is_neuterable(false);
806     BufferAccess const access(array->type());
807     size_t const k = ElementSizeLog2Of(access.machine_type());
808     double const byte_length = array->byte_length()->Number();
809     CHECK_LT(k, arraysize(shifted_int32_ranges_));
810     if (IsExternalArrayElementsKind(array->map()->elements_kind()) &&
811         access.external_array_type() != kExternalUint8ClampedArray &&
812         key_type->Is(shifted_int32_ranges_[k]) && byte_length <= kMaxInt) {
813       // JSLoadProperty(typed-array, int32)
814       Handle<ExternalArray> elements =
815           Handle<ExternalArray>::cast(handle(array->elements()));
816       Node* buffer = jsgraph()->PointerConstant(elements->external_pointer());
817       Node* length = jsgraph()->Constant(byte_length);
818       Node* context = NodeProperties::GetContextInput(node);
819       Node* effect = NodeProperties::GetEffectInput(node);
820       Node* control = NodeProperties::GetControlInput(node);
821       // Convert to a number first.
822       if (!value_type->Is(Type::Number())) {
823         Reduction number_reduction = ReduceJSToNumberInput(value);
824         if (number_reduction.Changed()) {
825           value = number_reduction.replacement();
826         } else {
827           DCHECK(FLAG_turbo_deoptimization ==
828                  (OperatorProperties::GetFrameStateInputCount(
829                       javascript()->ToNumber()) == 1));
830           if (FLAG_turbo_deoptimization) {
831             Node* frame_state_for_to_number =
832                 NodeProperties::GetFrameStateInput(node, 1);
833             value = effect =
834                 graph()->NewNode(javascript()->ToNumber(), value, context,
835                                  frame_state_for_to_number, effect, control);
836           } else {
837             value = effect = graph()->NewNode(javascript()->ToNumber(), value,
838                                               context, effect, control);
839           }
840         }
841       }
842       // For integer-typed arrays, convert to the integer type.
843       if (TypeOf(access.machine_type()) == kTypeInt32 &&
844           !value_type->Is(Type::Signed32())) {
845         value = graph()->NewNode(simplified()->NumberToInt32(), value);
846       } else if (TypeOf(access.machine_type()) == kTypeUint32 &&
847                  !value_type->Is(Type::Unsigned32())) {
848         value = graph()->NewNode(simplified()->NumberToUint32(), value);
849       }
850       // Check if we can avoid the bounds check.
851       if (key_type->Min() >= 0 && key_type->Max() < array->length()->Number()) {
852         node->set_op(simplified()->StoreElement(
853             AccessBuilder::ForTypedArrayElement(array->type(), true)));
854         node->ReplaceInput(0, buffer);
855         DCHECK_EQ(key, node->InputAt(1));
856         node->ReplaceInput(2, value);
857         node->ReplaceInput(3, effect);
858         node->ReplaceInput(4, control);
859         node->TrimInputCount(5);
860         RelaxControls(node);
861         return Changed(node);
862       }
863       // Compute byte offset.
864       Node* offset = Word32Shl(key, static_cast<int>(k));
865       // Turn into a StoreBuffer operation.
866       node->set_op(simplified()->StoreBuffer(access));
867       node->ReplaceInput(0, buffer);
868       node->ReplaceInput(1, offset);
869       node->ReplaceInput(2, length);
870       node->ReplaceInput(3, value);
871       node->ReplaceInput(4, effect);
872       node->ReplaceInput(5, control);
873       node->TrimInputCount(6);
874       RelaxControls(node);
875       return Changed(node);
876     }
877   }
878   return NoChange();
879 }
880
881
882 Reduction JSTypedLowering::ReduceJSLoadContext(Node* node) {
883   DCHECK_EQ(IrOpcode::kJSLoadContext, node->opcode());
884   ContextAccess const& access = ContextAccessOf(node->op());
885   Node* const effect = NodeProperties::GetEffectInput(node);
886   Node* const control = graph()->start();
887   for (size_t i = 0; i < access.depth(); ++i) {
888     node->ReplaceInput(
889         0, graph()->NewNode(
890                simplified()->LoadField(
891                    AccessBuilder::ForContextSlot(Context::PREVIOUS_INDEX)),
892                NodeProperties::GetValueInput(node, 0), effect, control));
893   }
894   node->set_op(
895       simplified()->LoadField(AccessBuilder::ForContextSlot(access.index())));
896   node->ReplaceInput(1, effect);
897   node->ReplaceInput(2, control);
898   DCHECK_EQ(3, node->InputCount());
899   return Changed(node);
900 }
901
902
903 Reduction JSTypedLowering::ReduceJSStoreContext(Node* node) {
904   DCHECK_EQ(IrOpcode::kJSStoreContext, node->opcode());
905   ContextAccess const& access = ContextAccessOf(node->op());
906   Node* const effect = NodeProperties::GetEffectInput(node);
907   Node* const control = graph()->start();
908   for (size_t i = 0; i < access.depth(); ++i) {
909     node->ReplaceInput(
910         0, graph()->NewNode(
911                simplified()->LoadField(
912                    AccessBuilder::ForContextSlot(Context::PREVIOUS_INDEX)),
913                NodeProperties::GetValueInput(node, 0), effect, control));
914   }
915   node->set_op(
916       simplified()->StoreField(AccessBuilder::ForContextSlot(access.index())));
917   node->RemoveInput(2);
918   DCHECK_EQ(4, node->InputCount());
919   return Changed(node);
920 }
921
922
923 Reduction JSTypedLowering::Reduce(Node* node) {
924   // Check if the output type is a singleton.  In that case we already know the
925   // result value and can simply replace the node if it's eliminable.
926   if (!NodeProperties::IsConstant(node) && NodeProperties::IsTyped(node) &&
927       node->op()->HasProperty(Operator::kEliminatable)) {
928     Type* upper = NodeProperties::GetBounds(node).upper;
929     if (upper->IsConstant()) {
930       Node* replacement = jsgraph()->Constant(upper->AsConstant()->Value());
931       NodeProperties::ReplaceWithValue(node, replacement);
932       return Changed(replacement);
933     } else if (upper->Is(Type::MinusZero())) {
934       Node* replacement = jsgraph()->Constant(factory()->minus_zero_value());
935       NodeProperties::ReplaceWithValue(node, replacement);
936       return Changed(replacement);
937     } else if (upper->Is(Type::NaN())) {
938       Node* replacement = jsgraph()->NaNConstant();
939       NodeProperties::ReplaceWithValue(node, replacement);
940       return Changed(replacement);
941     } else if (upper->Is(Type::Null())) {
942       Node* replacement = jsgraph()->NullConstant();
943       NodeProperties::ReplaceWithValue(node, replacement);
944       return Changed(replacement);
945     } else if (upper->Is(Type::PlainNumber()) && upper->Min() == upper->Max()) {
946       Node* replacement = jsgraph()->Constant(upper->Min());
947       NodeProperties::ReplaceWithValue(node, replacement);
948       return Changed(replacement);
949     } else if (upper->Is(Type::Undefined())) {
950       Node* replacement = jsgraph()->UndefinedConstant();
951       NodeProperties::ReplaceWithValue(node, replacement);
952       return Changed(replacement);
953     }
954   }
955   switch (node->opcode()) {
956     case IrOpcode::kJSEqual:
957       return ReduceJSEqual(node, false);
958     case IrOpcode::kJSNotEqual:
959       return ReduceJSEqual(node, true);
960     case IrOpcode::kJSStrictEqual:
961       return ReduceJSStrictEqual(node, false);
962     case IrOpcode::kJSStrictNotEqual:
963       return ReduceJSStrictEqual(node, true);
964     case IrOpcode::kJSLessThan:         // fall through
965     case IrOpcode::kJSGreaterThan:      // fall through
966     case IrOpcode::kJSLessThanOrEqual:  // fall through
967     case IrOpcode::kJSGreaterThanOrEqual:
968       return ReduceJSComparison(node);
969     case IrOpcode::kJSBitwiseOr:
970       return ReduceInt32Binop(node, machine()->Word32Or());
971     case IrOpcode::kJSBitwiseXor:
972       return ReduceInt32Binop(node, machine()->Word32Xor());
973     case IrOpcode::kJSBitwiseAnd:
974       return ReduceInt32Binop(node, machine()->Word32And());
975     case IrOpcode::kJSShiftLeft:
976       return ReduceUI32Shift(node, kSigned, machine()->Word32Shl());
977     case IrOpcode::kJSShiftRight:
978       return ReduceUI32Shift(node, kSigned, machine()->Word32Sar());
979     case IrOpcode::kJSShiftRightLogical:
980       return ReduceUI32Shift(node, kUnsigned, machine()->Word32Shr());
981     case IrOpcode::kJSAdd:
982       return ReduceJSAdd(node);
983     case IrOpcode::kJSSubtract:
984       return ReduceNumberBinop(node, simplified()->NumberSubtract());
985     case IrOpcode::kJSMultiply:
986       return ReduceNumberBinop(node, simplified()->NumberMultiply());
987     case IrOpcode::kJSDivide:
988       return ReduceNumberBinop(node, simplified()->NumberDivide());
989     case IrOpcode::kJSModulus:
990       return ReduceNumberBinop(node, simplified()->NumberModulus());
991     case IrOpcode::kJSUnaryNot:
992       return ReduceJSUnaryNot(node);
993     case IrOpcode::kJSToBoolean:
994       return ReduceJSToBoolean(node);
995     case IrOpcode::kJSToNumber:
996       return ReduceJSToNumber(node);
997     case IrOpcode::kJSToString:
998       return ReduceJSToString(node);
999     case IrOpcode::kJSLoadProperty:
1000       return ReduceJSLoadProperty(node);
1001     case IrOpcode::kJSStoreProperty:
1002       return ReduceJSStoreProperty(node);
1003     case IrOpcode::kJSLoadContext:
1004       return ReduceJSLoadContext(node);
1005     case IrOpcode::kJSStoreContext:
1006       return ReduceJSStoreContext(node);
1007     default:
1008       break;
1009   }
1010   return NoChange();
1011 }
1012
1013
1014 Node* JSTypedLowering::ConvertPrimitiveToNumber(Node* input) {
1015   DCHECK(NodeProperties::GetBounds(input).upper->Is(Type::PlainPrimitive()));
1016   // Avoid inserting too many eager ToNumber() operations.
1017   Reduction const reduction = ReduceJSToNumberInput(input);
1018   if (reduction.Changed()) return reduction.replacement();
1019   // TODO(jarin) Use PlainPrimitiveToNumber once we have it.
1020   Node* const conversion =
1021       FLAG_turbo_deoptimization
1022           ? graph()->NewNode(javascript()->ToNumber(), input,
1023                              jsgraph()->NoContextConstant(),
1024                              jsgraph()->EmptyFrameState(), graph()->start(),
1025                              graph()->start())
1026           : graph()->NewNode(javascript()->ToNumber(), input,
1027                              jsgraph()->NoContextConstant(), graph()->start(),
1028                              graph()->start());
1029   InsertConversion(conversion);
1030   return conversion;
1031 }
1032
1033
1034 template <IrOpcode::Value kOpcode>
1035 Node* JSTypedLowering::FindConversion(Node* input) {
1036   size_t const input_id = input->id();
1037   if (input_id < conversions_.size()) {
1038     Node* const conversion = conversions_[input_id];
1039     if (conversion && conversion->opcode() == kOpcode) {
1040       return conversion;
1041     }
1042   }
1043   return nullptr;
1044 }
1045
1046
1047 void JSTypedLowering::InsertConversion(Node* conversion) {
1048   DCHECK(conversion->opcode() == IrOpcode::kJSToNumber);
1049   size_t const input_id = conversion->InputAt(0)->id();
1050   if (input_id >= conversions_.size()) {
1051     conversions_.resize(2 * input_id + 1);
1052   }
1053   conversions_[input_id] = conversion;
1054 }
1055
1056
1057 Node* JSTypedLowering::Word32Shl(Node* const lhs, int32_t const rhs) {
1058   if (rhs == 0) return lhs;
1059   return graph()->NewNode(machine()->Word32Shl(), lhs,
1060                           jsgraph()->Int32Constant(rhs));
1061 }
1062
1063
1064 Factory* JSTypedLowering::factory() const { return jsgraph()->factory(); }
1065
1066
1067 Graph* JSTypedLowering::graph() const { return jsgraph()->graph(); }
1068
1069
1070 JSOperatorBuilder* JSTypedLowering::javascript() const {
1071   return jsgraph()->javascript();
1072 }
1073
1074
1075 CommonOperatorBuilder* JSTypedLowering::common() const {
1076   return jsgraph()->common();
1077 }
1078
1079
1080 MachineOperatorBuilder* JSTypedLowering::machine() const {
1081   return jsgraph()->machine();
1082 }
1083
1084 }  // namespace compiler
1085 }  // namespace internal
1086 }  // namespace v8