blob: 809953367e95512557863ee8877da2c509ab43f1 [file] [log] [blame]
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001// 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
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00005#include "src/code-factory.h"
6#include "src/compilation-dependencies.h"
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007#include "src/compiler/access-builder.h"
Emily Bernierd0a1eb72015-03-24 16:35:39 -04008#include "src/compiler/js-graph.h"
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009#include "src/compiler/js-typed-lowering.h"
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000010#include "src/compiler/linkage.h"
Emily Bernierd0a1eb72015-03-24 16:35:39 -040011#include "src/compiler/node-matchers.h"
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000012#include "src/compiler/node-properties.h"
13#include "src/compiler/operator-properties.h"
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000014#include "src/type-cache.h"
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015#include "src/types.h"
16
17namespace v8 {
18namespace internal {
19namespace compiler {
20
Ben Murdochb8a8cc12014-11-26 15:28:44 +000021// A helper class to simplify the process of reducing a single binop node with a
22// JSOperator. This class manages the rewriting of context, control, and effect
23// dependencies during lowering of a binop and contains numerous helper
24// functions for matching the types of inputs to an operation.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000025class JSBinopReduction final {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000026 public:
27 JSBinopReduction(JSTypedLowering* lowering, Node* node)
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000028 : lowering_(lowering), node_(node) {}
Ben Murdochb8a8cc12014-11-26 15:28:44 +000029
Ben Murdochc5610432016-08-08 18:44:38 +010030 void ConvertInputsToNumberOrUndefined(Node* frame_state) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000031 // To convert the inputs to numbers, we have to provide frame states
32 // for lazy bailouts in the ToNumber conversions.
33 // We use a little hack here: we take the frame state before the binary
34 // operation and use it to construct the frame states for the conversion
35 // so that after the deoptimization, the binary operation IC gets
36 // already converted values from full code. This way we are sure that we
37 // will not re-do any of the side effects.
38
39 Node* left_input = nullptr;
40 Node* right_input = nullptr;
41 bool left_is_primitive = left_type()->Is(Type::PlainPrimitive());
42 bool right_is_primitive = right_type()->Is(Type::PlainPrimitive());
43 bool handles_exception = NodeProperties::IsExceptionalCall(node_);
44
45 if (!left_is_primitive && !right_is_primitive && handles_exception) {
46 ConvertBothInputsToNumber(&left_input, &right_input, frame_state);
47 } else {
48 left_input = left_is_primitive
Ben Murdochc5610432016-08-08 18:44:38 +010049 ? ConvertPlainPrimitiveToNumberOrUndefined(left())
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000050 : ConvertSingleInputToNumber(
51 left(), CreateFrameStateForLeftInput(frame_state));
52 right_input = right_is_primitive
Ben Murdochc5610432016-08-08 18:44:38 +010053 ? ConvertPlainPrimitiveToNumberOrUndefined(right())
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000054 : ConvertSingleInputToNumber(
55 right(), CreateFrameStateForRightInput(
56 frame_state, left_input));
57 }
58
59 node_->ReplaceInput(0, left_input);
60 node_->ReplaceInput(1, right_input);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000061 }
62
Emily Bernierd0a1eb72015-03-24 16:35:39 -040063 void ConvertInputsToUI32(Signedness left_signedness,
64 Signedness right_signedness) {
65 node_->ReplaceInput(0, ConvertToUI32(left(), left_signedness));
66 node_->ReplaceInput(1, ConvertToUI32(right(), right_signedness));
Ben Murdochb8a8cc12014-11-26 15:28:44 +000067 }
68
Ben Murdochb8a8cc12014-11-26 15:28:44 +000069 void SwapInputs() {
70 Node* l = left();
71 Node* r = right();
72 node_->ReplaceInput(0, r);
73 node_->ReplaceInput(1, l);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000074 }
75
76 // Remove all effect and control inputs and outputs to this node and change
77 // to the pure operator {op}, possibly inserting a boolean inversion.
Emily Bernierd0a1eb72015-03-24 16:35:39 -040078 Reduction ChangeToPureOperator(const Operator* op, bool invert = false,
79 Type* type = Type::Any()) {
80 DCHECK_EQ(0, op->EffectInputCount());
Ben Murdochb8a8cc12014-11-26 15:28:44 +000081 DCHECK_EQ(false, OperatorProperties::HasContextInput(op));
Emily Bernierd0a1eb72015-03-24 16:35:39 -040082 DCHECK_EQ(0, op->ControlInputCount());
83 DCHECK_EQ(2, op->ValueInputCount());
Ben Murdochb8a8cc12014-11-26 15:28:44 +000084
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000085 // Remove the effects from the node, and update its effect/control usages.
Emily Bernierd0a1eb72015-03-24 16:35:39 -040086 if (node_->op()->EffectInputCount() > 0) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000087 lowering_->RelaxEffectsAndControls(node_);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000088 }
89 // Remove the inputs corresponding to context, effect, and control.
90 NodeProperties::RemoveNonValueInputs(node_);
91 // Finally, update the operator to the new one.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000092 NodeProperties::ChangeOp(node_, op);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000093
Emily Bernierd0a1eb72015-03-24 16:35:39 -040094 // TODO(jarin): Replace the explicit typing hack with a call to some method
95 // that encapsulates changing the operator and re-typing.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000096 Type* node_type = NodeProperties::GetType(node_);
97 NodeProperties::SetType(node_, Type::Intersect(node_type, type, zone()));
Emily Bernierd0a1eb72015-03-24 16:35:39 -040098
Ben Murdochb8a8cc12014-11-26 15:28:44 +000099 if (invert) {
100 // Insert an boolean not to invert the value.
101 Node* value = graph()->NewNode(simplified()->BooleanNot(), node_);
102 node_->ReplaceUses(value);
103 // Note: ReplaceUses() smashes all uses, so smash it back here.
104 value->ReplaceInput(0, node_);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400105 return lowering_->Replace(value);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000106 }
107 return lowering_->Changed(node_);
108 }
109
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400110 Reduction ChangeToPureOperator(const Operator* op, Type* type) {
111 return ChangeToPureOperator(op, false, type);
112 }
113
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000114 bool LeftInputIs(Type* t) { return left_type()->Is(t); }
115
116 bool RightInputIs(Type* t) { return right_type()->Is(t); }
117
118 bool OneInputIs(Type* t) { return LeftInputIs(t) || RightInputIs(t); }
119
120 bool BothInputsAre(Type* t) { return LeftInputIs(t) && RightInputIs(t); }
121
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000122 bool OneInputCannotBe(Type* t) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000123 return !left_type()->Maybe(t) || !right_type()->Maybe(t);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000124 }
125
126 bool NeitherInputCanBe(Type* t) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000127 return !left_type()->Maybe(t) && !right_type()->Maybe(t);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000128 }
129
130 Node* effect() { return NodeProperties::GetEffectInput(node_); }
131 Node* control() { return NodeProperties::GetControlInput(node_); }
132 Node* context() { return NodeProperties::GetContextInput(node_); }
133 Node* left() { return NodeProperties::GetValueInput(node_, 0); }
134 Node* right() { return NodeProperties::GetValueInput(node_, 1); }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000135 Type* left_type() { return NodeProperties::GetType(node_->InputAt(0)); }
136 Type* right_type() { return NodeProperties::GetType(node_->InputAt(1)); }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000137
138 SimplifiedOperatorBuilder* simplified() { return lowering_->simplified(); }
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400139 Graph* graph() const { return lowering_->graph(); }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000140 JSGraph* jsgraph() { return lowering_->jsgraph(); }
141 JSOperatorBuilder* javascript() { return lowering_->javascript(); }
142 MachineOperatorBuilder* machine() { return lowering_->machine(); }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000143 CommonOperatorBuilder* common() { return jsgraph()->common(); }
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400144 Zone* zone() const { return graph()->zone(); }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000145
146 private:
147 JSTypedLowering* lowering_; // The containing lowering instance.
148 Node* node_; // The original node.
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000149
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000150 Node* CreateFrameStateForLeftInput(Node* frame_state) {
151 FrameStateInfo state_info = OpParameter<FrameStateInfo>(frame_state);
152
153 if (state_info.bailout_id() == BailoutId::None()) {
154 // Dummy frame state => just leave it as is.
155 return frame_state;
156 }
157
158 // If the frame state is already the right one, just return it.
159 if (state_info.state_combine().kind() == OutputFrameStateCombine::kPokeAt &&
160 state_info.state_combine().GetOffsetToPokeAt() == 1) {
161 return frame_state;
162 }
163
164 // Here, we smash the result of the conversion into the slot just below
165 // the stack top. This is the slot that full code uses to store the
166 // left operand.
167 const Operator* op = jsgraph()->common()->FrameState(
168 state_info.bailout_id(), OutputFrameStateCombine::PokeAt(1),
169 state_info.function_info());
170
171 return graph()->NewNode(op,
172 frame_state->InputAt(kFrameStateParametersInput),
173 frame_state->InputAt(kFrameStateLocalsInput),
174 frame_state->InputAt(kFrameStateStackInput),
175 frame_state->InputAt(kFrameStateContextInput),
176 frame_state->InputAt(kFrameStateFunctionInput),
177 frame_state->InputAt(kFrameStateOuterStateInput));
178 }
179
180 Node* CreateFrameStateForRightInput(Node* frame_state, Node* converted_left) {
181 FrameStateInfo state_info = OpParameter<FrameStateInfo>(frame_state);
182
183 if (state_info.bailout_id() == BailoutId::None()) {
184 // Dummy frame state => just leave it as is.
185 return frame_state;
186 }
187
188 // Create a frame state that stores the result of the operation to the
189 // top of the stack (i.e., the slot used for the right operand).
190 const Operator* op = jsgraph()->common()->FrameState(
191 state_info.bailout_id(), OutputFrameStateCombine::PokeAt(0),
192 state_info.function_info());
193
194 // Change the left operand {converted_left} on the expression stack.
195 Node* stack = frame_state->InputAt(2);
196 DCHECK_EQ(stack->opcode(), IrOpcode::kStateValues);
197 DCHECK_GE(stack->InputCount(), 2);
198
199 // TODO(jarin) Allocate in a local zone or a reusable buffer.
200 NodeVector new_values(stack->InputCount(), zone());
201 for (int i = 0; i < stack->InputCount(); i++) {
202 if (i == stack->InputCount() - 2) {
203 new_values[i] = converted_left;
204 } else {
205 new_values[i] = stack->InputAt(i);
206 }
207 }
208 Node* new_stack =
209 graph()->NewNode(stack->op(), stack->InputCount(), &new_values.front());
210
211 return graph()->NewNode(
212 op, frame_state->InputAt(kFrameStateParametersInput),
213 frame_state->InputAt(kFrameStateLocalsInput), new_stack,
214 frame_state->InputAt(kFrameStateContextInput),
215 frame_state->InputAt(kFrameStateFunctionInput),
216 frame_state->InputAt(kFrameStateOuterStateInput));
217 }
218
Ben Murdochc5610432016-08-08 18:44:38 +0100219 Node* ConvertPlainPrimitiveToNumberOrUndefined(Node* node) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000220 DCHECK(NodeProperties::GetType(node)->Is(Type::PlainPrimitive()));
221 // Avoid inserting too many eager ToNumber() operations.
222 Reduction const reduction = lowering_->ReduceJSToNumberInput(node);
223 if (reduction.Changed()) return reduction.replacement();
Ben Murdochc5610432016-08-08 18:44:38 +0100224 if (NodeProperties::GetType(node)->Is(Type::NumberOrUndefined())) {
225 return node;
226 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000227 return graph()->NewNode(
228 javascript()->ToNumber(), node, jsgraph()->NoContextConstant(),
229 jsgraph()->EmptyFrameState(), graph()->start(), graph()->start());
230 }
231
232 Node* ConvertSingleInputToNumber(Node* node, Node* frame_state) {
233 DCHECK(!NodeProperties::GetType(node)->Is(Type::PlainPrimitive()));
234 Node* const n = graph()->NewNode(javascript()->ToNumber(), node, context(),
235 frame_state, effect(), control());
Ben Murdochc5610432016-08-08 18:44:38 +0100236 Node* const if_success = graph()->NewNode(common()->IfSuccess(), n);
237 NodeProperties::ReplaceControlInput(node_, if_success);
238 NodeProperties::ReplaceUses(node_, node_, node_, node_, n);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000239 update_effect(n);
240 return n;
241 }
242
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000243 void ConvertBothInputsToNumber(Node** left_result, Node** right_result,
244 Node* frame_state) {
245 Node* projections[2];
246
247 // Find {IfSuccess} and {IfException} continuations of the operation.
248 NodeProperties::CollectControlProjections(node_, projections, 2);
249 IfExceptionHint hint = OpParameter<IfExceptionHint>(projections[1]);
250 Node* if_exception = projections[1];
251 Node* if_success = projections[0];
252
253 // Insert two ToNumber() operations that both potentially throw.
254 Node* left_state = CreateFrameStateForLeftInput(frame_state);
255 Node* left_conv =
256 graph()->NewNode(javascript()->ToNumber(), left(), context(),
257 left_state, effect(), control());
258 Node* left_success = graph()->NewNode(common()->IfSuccess(), left_conv);
259 Node* right_state = CreateFrameStateForRightInput(frame_state, left_conv);
260 Node* right_conv =
261 graph()->NewNode(javascript()->ToNumber(), right(), context(),
262 right_state, left_conv, left_success);
263 Node* left_exception =
264 graph()->NewNode(common()->IfException(hint), left_conv, left_conv);
265 Node* right_exception =
266 graph()->NewNode(common()->IfException(hint), right_conv, right_conv);
267 NodeProperties::ReplaceControlInput(if_success, right_conv);
268 update_effect(right_conv);
269
270 // Wire conversions to existing {IfException} continuation.
271 Node* exception_merge = if_exception;
272 Node* exception_value =
273 graph()->NewNode(common()->Phi(MachineRepresentation::kTagged, 2),
274 left_exception, right_exception, exception_merge);
275 Node* exception_effect =
276 graph()->NewNode(common()->EffectPhi(2), left_exception,
277 right_exception, exception_merge);
278 for (Edge edge : exception_merge->use_edges()) {
279 if (NodeProperties::IsEffectEdge(edge)) edge.UpdateTo(exception_effect);
280 if (NodeProperties::IsValueEdge(edge)) edge.UpdateTo(exception_value);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400281 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000282 NodeProperties::RemoveType(exception_merge);
283 exception_merge->ReplaceInput(0, left_exception);
284 exception_merge->ReplaceInput(1, right_exception);
285 NodeProperties::ChangeOp(exception_merge, common()->Merge(2));
286
287 *left_result = left_conv;
288 *right_result = right_conv;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000289 }
290
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400291 Node* ConvertToUI32(Node* node, Signedness signedness) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000292 // Avoid introducing too many eager NumberToXXnt32() operations.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000293 Type* type = NodeProperties::GetType(node);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400294 if (signedness == kSigned) {
295 if (!type->Is(Type::Signed32())) {
296 node = graph()->NewNode(simplified()->NumberToInt32(), node);
297 }
298 } else {
299 DCHECK_EQ(kUnsigned, signedness);
300 if (!type->Is(Type::Unsigned32())) {
301 node = graph()->NewNode(simplified()->NumberToUint32(), node);
302 }
303 }
304 return node;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000305 }
306
307 void update_effect(Node* effect) {
308 NodeProperties::ReplaceEffectInput(node_, effect);
309 }
310};
311
312
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000313// TODO(turbofan): js-typed-lowering improvements possible
314// - immediately put in type bounds for all new nodes
315// - relax effects from generic but not-side-effecting operations
316
317
318JSTypedLowering::JSTypedLowering(Editor* editor,
319 CompilationDependencies* dependencies,
320 Flags flags, JSGraph* jsgraph, Zone* zone)
321 : AdvancedReducer(editor),
322 dependencies_(dependencies),
323 flags_(flags),
324 jsgraph_(jsgraph),
325 true_type_(Type::Constant(factory()->true_value(), graph()->zone())),
326 false_type_(Type::Constant(factory()->false_value(), graph()->zone())),
327 the_hole_type_(
328 Type::Constant(factory()->the_hole_value(), graph()->zone())),
329 type_cache_(TypeCache::Get()) {
330 for (size_t k = 0; k < arraysize(shifted_int32_ranges_); ++k) {
331 double min = kMinInt / (1 << k);
332 double max = kMaxInt / (1 << k);
333 shifted_int32_ranges_[k] = Type::Range(min, max, graph()->zone());
334 }
335}
336
337
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000338Reduction JSTypedLowering::ReduceJSAdd(Node* node) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000339 if (flags() & kDisableBinaryOpReduction) return NoChange();
340
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000341 JSBinopReduction r(this, node);
Ben Murdochc5610432016-08-08 18:44:38 +0100342 if (r.BothInputsAre(Type::NumberOrUndefined())) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000343 // JSAdd(x:number, y:number) => NumberAdd(x, y)
Ben Murdochc5610432016-08-08 18:44:38 +0100344 return ReduceNumberBinop(node, simplified()->NumberAdd());
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000345 }
Ben Murdoch097c5b22016-05-18 11:27:45 +0100346 if (r.NeitherInputCanBe(Type::StringOrReceiver())) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000347 // JSAdd(x:-string, y:-string) => NumberAdd(ToNumber(x), ToNumber(y))
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000348 Node* frame_state = NodeProperties::GetFrameStateInput(node, 1);
Ben Murdochc5610432016-08-08 18:44:38 +0100349 r.ConvertInputsToNumberOrUndefined(frame_state);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400350 return r.ChangeToPureOperator(simplified()->NumberAdd(), Type::Number());
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000351 }
Ben Murdochc5610432016-08-08 18:44:38 +0100352 if (r.OneInputIs(Type::String())) {
353 StringAddFlags flags = STRING_ADD_CHECK_NONE;
354 if (!r.LeftInputIs(Type::String())) {
355 flags = STRING_ADD_CONVERT_LEFT;
356 } else if (!r.RightInputIs(Type::String())) {
357 flags = STRING_ADD_CONVERT_RIGHT;
358 }
359 // JSAdd(x:string, y) => CallStub[StringAdd](x, y)
360 // JSAdd(x, y:string) => CallStub[StringAdd](x, y)
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000361 Callable const callable =
Ben Murdochc5610432016-08-08 18:44:38 +0100362 CodeFactory::StringAdd(isolate(), flags, NOT_TENURED);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000363 CallDescriptor const* const desc = Linkage::GetStubCallDescriptor(
364 isolate(), graph()->zone(), callable.descriptor(), 0,
365 CallDescriptor::kNeedsFrameState, node->op()->properties());
366 DCHECK_EQ(2, OperatorProperties::GetFrameStateInputCount(node->op()));
367 node->RemoveInput(NodeProperties::FirstFrameStateIndex(node) + 1);
368 node->InsertInput(graph()->zone(), 0,
369 jsgraph()->HeapConstant(callable.code()));
370 NodeProperties::ChangeOp(node, common()->Call(desc));
371 return Changed(node);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400372 }
373 return NoChange();
374}
375
376
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000377Reduction JSTypedLowering::ReduceJSModulus(Node* node) {
378 if (flags() & kDisableBinaryOpReduction) return NoChange();
379
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400380 JSBinopReduction r(this, node);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000381 if (r.BothInputsAre(Type::Number())) {
382 // JSModulus(x:number, x:number) => NumberModulus(x, y)
383 return r.ChangeToPureOperator(simplified()->NumberModulus(),
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400384 Type::Number());
385 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400386 return NoChange();
387}
388
389
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000390Reduction JSTypedLowering::ReduceNumberBinop(Node* node,
391 const Operator* numberOp) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000392 if (flags() & kDisableBinaryOpReduction) return NoChange();
393
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000394 JSBinopReduction r(this, node);
Ben Murdoch097c5b22016-05-18 11:27:45 +0100395 if (numberOp == simplified()->NumberModulus()) {
Ben Murdochc5610432016-08-08 18:44:38 +0100396 if (r.BothInputsAre(Type::NumberOrUndefined())) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000397 return r.ChangeToPureOperator(numberOp, Type::Number());
398 }
399 return NoChange();
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400400 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000401 Node* frame_state = NodeProperties::GetFrameStateInput(node, 1);
Ben Murdochc5610432016-08-08 18:44:38 +0100402 r.ConvertInputsToNumberOrUndefined(frame_state);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000403 return r.ChangeToPureOperator(numberOp, Type::Number());
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000404}
405
406
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400407Reduction JSTypedLowering::ReduceInt32Binop(Node* node, const Operator* intOp) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000408 if (flags() & kDisableBinaryOpReduction) return NoChange();
409
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000410 JSBinopReduction r(this, node);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000411 Node* frame_state = NodeProperties::GetFrameStateInput(node, 1);
Ben Murdochc5610432016-08-08 18:44:38 +0100412 r.ConvertInputsToNumberOrUndefined(frame_state);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000413 r.ConvertInputsToUI32(kSigned, kSigned);
414 return r.ChangeToPureOperator(intOp, Type::Integral32());
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000415}
416
417
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400418Reduction JSTypedLowering::ReduceUI32Shift(Node* node,
419 Signedness left_signedness,
420 const Operator* shift_op) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000421 if (flags() & kDisableBinaryOpReduction) return NoChange();
422
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000423 JSBinopReduction r(this, node);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000424 Node* frame_state = NodeProperties::GetFrameStateInput(node, 1);
Ben Murdochc5610432016-08-08 18:44:38 +0100425 r.ConvertInputsToNumberOrUndefined(frame_state);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000426 r.ConvertInputsToUI32(left_signedness, kUnsigned);
427 return r.ChangeToPureOperator(shift_op);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000428}
429
430
431Reduction JSTypedLowering::ReduceJSComparison(Node* node) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000432 if (flags() & kDisableBinaryOpReduction) return NoChange();
433
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000434 JSBinopReduction r(this, node);
435 if (r.BothInputsAre(Type::String())) {
436 // If both inputs are definitely strings, perform a string comparison.
437 const Operator* stringOp;
438 switch (node->opcode()) {
439 case IrOpcode::kJSLessThan:
440 stringOp = simplified()->StringLessThan();
441 break;
442 case IrOpcode::kJSGreaterThan:
443 stringOp = simplified()->StringLessThan();
444 r.SwapInputs(); // a > b => b < a
445 break;
446 case IrOpcode::kJSLessThanOrEqual:
447 stringOp = simplified()->StringLessThanOrEqual();
448 break;
449 case IrOpcode::kJSGreaterThanOrEqual:
450 stringOp = simplified()->StringLessThanOrEqual();
451 r.SwapInputs(); // a >= b => b <= a
452 break;
453 default:
454 return NoChange();
455 }
Ben Murdochc5610432016-08-08 18:44:38 +0100456 r.ChangeToPureOperator(stringOp);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000457 return Changed(node);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000458 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000459 if (r.OneInputCannotBe(Type::StringOrReceiver())) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000460 const Operator* less_than;
461 const Operator* less_than_or_equal;
462 if (r.BothInputsAre(Type::Unsigned32())) {
463 less_than = machine()->Uint32LessThan();
464 less_than_or_equal = machine()->Uint32LessThanOrEqual();
465 } else if (r.BothInputsAre(Type::Signed32())) {
466 less_than = machine()->Int32LessThan();
467 less_than_or_equal = machine()->Int32LessThanOrEqual();
468 } else {
469 // TODO(turbofan): mixed signed/unsigned int32 comparisons.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000470 Node* frame_state = NodeProperties::GetFrameStateInput(node, 1);
Ben Murdochc5610432016-08-08 18:44:38 +0100471 r.ConvertInputsToNumberOrUndefined(frame_state);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000472 less_than = simplified()->NumberLessThan();
473 less_than_or_equal = simplified()->NumberLessThanOrEqual();
474 }
475 const Operator* comparison;
476 switch (node->opcode()) {
477 case IrOpcode::kJSLessThan:
478 comparison = less_than;
479 break;
480 case IrOpcode::kJSGreaterThan:
481 comparison = less_than;
482 r.SwapInputs(); // a > b => b < a
483 break;
484 case IrOpcode::kJSLessThanOrEqual:
485 comparison = less_than_or_equal;
486 break;
487 case IrOpcode::kJSGreaterThanOrEqual:
488 comparison = less_than_or_equal;
489 r.SwapInputs(); // a >= b => b <= a
490 break;
491 default:
492 return NoChange();
493 }
494 return r.ChangeToPureOperator(comparison);
495 }
496 // TODO(turbofan): relax/remove effects of this operator in other cases.
497 return NoChange(); // Keep a generic comparison.
498}
499
Ben Murdochc5610432016-08-08 18:44:38 +0100500Reduction JSTypedLowering::ReduceJSEqualTypeOf(Node* node, bool invert) {
501 HeapObjectBinopMatcher m(node);
502 if (m.left().IsJSTypeOf() && m.right().HasValue() &&
503 m.right().Value()->IsString()) {
504 Node* replacement;
505 Node* input = m.left().InputAt(0);
506 Handle<String> value = Handle<String>::cast(m.right().Value());
507 if (String::Equals(value, factory()->boolean_string())) {
508 replacement = graph()->NewNode(
509 common()->Select(MachineRepresentation::kTagged),
510 graph()->NewNode(simplified()->ReferenceEqual(Type::Any()), input,
511 jsgraph()->TrueConstant()),
512 jsgraph()->TrueConstant(),
513 graph()->NewNode(simplified()->ReferenceEqual(Type::Any()), input,
514 jsgraph()->FalseConstant()));
515 } else if (String::Equals(value, factory()->function_string())) {
516 replacement = graph()->NewNode(simplified()->ObjectIsCallable(), input);
517 } else if (String::Equals(value, factory()->number_string())) {
518 replacement = graph()->NewNode(simplified()->ObjectIsNumber(), input);
519 } else if (String::Equals(value, factory()->string_string())) {
520 replacement = graph()->NewNode(simplified()->ObjectIsString(), input);
521 } else if (String::Equals(value, factory()->undefined_string())) {
522 replacement = graph()->NewNode(
523 common()->Select(MachineRepresentation::kTagged),
524 graph()->NewNode(simplified()->ReferenceEqual(Type::Any()), input,
525 jsgraph()->NullConstant()),
526 jsgraph()->FalseConstant(),
527 graph()->NewNode(simplified()->ObjectIsUndetectable(), input));
528 } else {
529 return NoChange();
530 }
531 if (invert) {
532 replacement = graph()->NewNode(simplified()->BooleanNot(), replacement);
533 }
534 return Replace(replacement);
535 }
536 return NoChange();
537}
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000538
539Reduction JSTypedLowering::ReduceJSEqual(Node* node, bool invert) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000540 if (flags() & kDisableBinaryOpReduction) return NoChange();
541
Ben Murdochc5610432016-08-08 18:44:38 +0100542 Reduction const reduction = ReduceJSEqualTypeOf(node, invert);
543 if (reduction.Changed()) {
544 ReplaceWithValue(node, reduction.replacement());
545 return reduction;
546 }
547
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000548 JSBinopReduction r(this, node);
549
550 if (r.BothInputsAre(Type::Number())) {
551 return r.ChangeToPureOperator(simplified()->NumberEqual(), invert);
552 }
553 if (r.BothInputsAre(Type::String())) {
Ben Murdochc5610432016-08-08 18:44:38 +0100554 return r.ChangeToPureOperator(simplified()->StringEqual(), invert);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000555 }
556 if (r.BothInputsAre(Type::Boolean())) {
557 return r.ChangeToPureOperator(simplified()->ReferenceEqual(Type::Boolean()),
558 invert);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000559 }
560 if (r.BothInputsAre(Type::Receiver())) {
561 return r.ChangeToPureOperator(
562 simplified()->ReferenceEqual(Type::Receiver()), invert);
563 }
Ben Murdochda12d292016-06-02 14:46:10 +0100564 if (r.OneInputIs(Type::Undetectable())) {
565 RelaxEffectsAndControls(node);
566 node->RemoveInput(r.LeftInputIs(Type::Undetectable()) ? 0 : 1);
567 node->TrimInputCount(1);
568 NodeProperties::ChangeOp(node, simplified()->ObjectIsUndetectable());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000569 if (invert) {
570 // Insert an boolean not to invert the value.
571 Node* value = graph()->NewNode(simplified()->BooleanNot(), node);
572 node->ReplaceUses(value);
573 // Note: ReplaceUses() smashes all uses, so smash it back here.
574 value->ReplaceInput(0, node);
575 return Replace(value);
576 }
577 return Changed(node);
578 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000579 return NoChange();
580}
581
582
583Reduction JSTypedLowering::ReduceJSStrictEqual(Node* node, bool invert) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000584 if (flags() & kDisableBinaryOpReduction) return NoChange();
585
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000586 JSBinopReduction r(this, node);
587 if (r.left() == r.right()) {
588 // x === x is always true if x != NaN
589 if (!r.left_type()->Maybe(Type::NaN())) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000590 Node* replacement = jsgraph()->BooleanConstant(!invert);
591 ReplaceWithValue(node, replacement);
592 return Replace(replacement);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000593 }
594 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400595 if (r.OneInputCannotBe(Type::NumberOrString())) {
596 // For values with canonical representation (i.e. not string nor number) an
597 // empty type intersection means the values cannot be strictly equal.
598 if (!r.left_type()->Maybe(r.right_type())) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000599 Node* replacement = jsgraph()->BooleanConstant(invert);
600 ReplaceWithValue(node, replacement);
601 return Replace(replacement);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000602 }
603 }
Ben Murdochc5610432016-08-08 18:44:38 +0100604 Reduction const reduction = ReduceJSEqualTypeOf(node, invert);
605 if (reduction.Changed()) {
606 return reduction;
607 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000608 if (r.OneInputIs(the_hole_type_)) {
609 return r.ChangeToPureOperator(simplified()->ReferenceEqual(the_hole_type_),
610 invert);
611 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000612 if (r.OneInputIs(Type::Undefined())) {
613 return r.ChangeToPureOperator(
614 simplified()->ReferenceEqual(Type::Undefined()), invert);
615 }
616 if (r.OneInputIs(Type::Null())) {
617 return r.ChangeToPureOperator(simplified()->ReferenceEqual(Type::Null()),
618 invert);
619 }
620 if (r.OneInputIs(Type::Boolean())) {
621 return r.ChangeToPureOperator(simplified()->ReferenceEqual(Type::Boolean()),
622 invert);
623 }
624 if (r.OneInputIs(Type::Object())) {
625 return r.ChangeToPureOperator(simplified()->ReferenceEqual(Type::Object()),
626 invert);
627 }
628 if (r.OneInputIs(Type::Receiver())) {
629 return r.ChangeToPureOperator(
630 simplified()->ReferenceEqual(Type::Receiver()), invert);
631 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000632 if (r.BothInputsAre(Type::Unique())) {
633 return r.ChangeToPureOperator(simplified()->ReferenceEqual(Type::Unique()),
634 invert);
635 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000636 if (r.BothInputsAre(Type::String())) {
Ben Murdochc5610432016-08-08 18:44:38 +0100637 return r.ChangeToPureOperator(simplified()->StringEqual(), invert);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000638 }
Ben Murdochc5610432016-08-08 18:44:38 +0100639 if (r.BothInputsAre(Type::NumberOrUndefined())) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000640 return r.ChangeToPureOperator(simplified()->NumberEqual(), invert);
641 }
642 // TODO(turbofan): js-typed-lowering of StrictEqual(mixed types)
643 return NoChange();
644}
645
646
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000647Reduction JSTypedLowering::ReduceJSToBoolean(Node* node) {
648 Node* const input = node->InputAt(0);
649 Type* const input_type = NodeProperties::GetType(input);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400650 if (input_type->Is(Type::Boolean())) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000651 // JSToBoolean(x:boolean) => x
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000652 return Replace(input);
653 } else if (input_type->Is(Type::OrderedNumber())) {
654 // JSToBoolean(x:ordered-number) => BooleanNot(NumberEqual(x,#0))
655 RelaxEffectsAndControls(node);
656 node->ReplaceInput(0, graph()->NewNode(simplified()->NumberEqual(), input,
657 jsgraph()->ZeroConstant()));
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400658 node->TrimInputCount(1);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000659 NodeProperties::ChangeOp(node, simplified()->BooleanNot());
660 return Changed(node);
661 } else if (input_type->Is(Type::String())) {
662 // JSToBoolean(x:string) => NumberLessThan(#0,x.length)
663 FieldAccess const access = AccessBuilder::ForStringLength();
664 Node* length = graph()->NewNode(simplified()->LoadField(access), input,
Ben Murdochc5610432016-08-08 18:44:38 +0100665 graph()->start(), graph()->start());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000666 ReplaceWithValue(node, node, length);
667 node->ReplaceInput(0, jsgraph()->ZeroConstant());
668 node->ReplaceInput(1, length);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000669 NodeProperties::ChangeOp(node, simplified()->NumberLessThan());
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400670 return Changed(node);
671 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000672 return NoChange();
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400673}
674
Ben Murdochda12d292016-06-02 14:46:10 +0100675Reduction JSTypedLowering::ReduceJSToInteger(Node* node) {
676 Node* const input = NodeProperties::GetValueInput(node, 0);
677 Type* const input_type = NodeProperties::GetType(input);
678 if (input_type->Is(type_cache_.kIntegerOrMinusZero)) {
679 // JSToInteger(x:integer) => x
680 ReplaceWithValue(node, input);
681 return Replace(input);
682 }
683 return NoChange();
684}
685
686Reduction JSTypedLowering::ReduceJSToLength(Node* node) {
687 Node* input = NodeProperties::GetValueInput(node, 0);
688 Type* input_type = NodeProperties::GetType(input);
689 if (input_type->Is(type_cache_.kIntegerOrMinusZero)) {
690 if (input_type->Max() <= 0.0) {
691 input = jsgraph()->ZeroConstant();
692 } else if (input_type->Min() >= kMaxSafeInteger) {
693 input = jsgraph()->Constant(kMaxSafeInteger);
694 } else {
695 if (input_type->Min() <= 0.0) {
696 input = graph()->NewNode(
697 common()->Select(MachineRepresentation::kTagged),
698 graph()->NewNode(simplified()->NumberLessThanOrEqual(), input,
699 jsgraph()->ZeroConstant()),
700 jsgraph()->ZeroConstant(), input);
701 input_type = Type::Range(0.0, input_type->Max(), graph()->zone());
702 NodeProperties::SetType(input, input_type);
703 }
704 if (input_type->Max() > kMaxSafeInteger) {
705 input = graph()->NewNode(
706 common()->Select(MachineRepresentation::kTagged),
707 graph()->NewNode(simplified()->NumberLessThanOrEqual(),
708 jsgraph()->Constant(kMaxSafeInteger), input),
709 jsgraph()->Constant(kMaxSafeInteger), input);
710 input_type =
711 Type::Range(input_type->Min(), kMaxSafeInteger, graph()->zone());
712 NodeProperties::SetType(input, input_type);
713 }
714 }
715 ReplaceWithValue(node, input);
716 return Replace(input);
717 }
718 return NoChange();
719}
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400720
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000721Reduction JSTypedLowering::ReduceJSToNumberInput(Node* input) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000722 // Check for ToNumber truncation of signaling NaN to undefined mapping.
723 if (input->opcode() == IrOpcode::kSelect) {
724 Node* check = NodeProperties::GetValueInput(input, 0);
725 Node* vtrue = NodeProperties::GetValueInput(input, 1);
726 Type* vtrue_type = NodeProperties::GetType(vtrue);
727 Node* vfalse = NodeProperties::GetValueInput(input, 2);
728 Type* vfalse_type = NodeProperties::GetType(vfalse);
729 if (vtrue_type->Is(Type::Undefined()) && vfalse_type->Is(Type::Number())) {
730 if (check->opcode() == IrOpcode::kNumberIsHoleNaN &&
731 check->InputAt(0) == vfalse) {
732 // JSToNumber(Select(NumberIsHoleNaN(x), y:undefined, x:number)) => x
733 return Replace(vfalse);
734 }
735 }
736 }
Ben Murdoch097c5b22016-05-18 11:27:45 +0100737 // Try constant-folding of JSToNumber with constant inputs.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000738 Type* input_type = NodeProperties::GetType(input);
Ben Murdoch097c5b22016-05-18 11:27:45 +0100739 if (input_type->IsConstant()) {
740 Handle<Object> input_value = input_type->AsConstant()->Value();
741 if (input_value->IsString()) {
742 return Replace(jsgraph()->Constant(
743 String::ToNumber(Handle<String>::cast(input_value))));
744 } else if (input_value->IsOddball()) {
745 return Replace(jsgraph()->Constant(
746 Oddball::ToNumber(Handle<Oddball>::cast(input_value))));
747 }
748 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000749 if (input_type->Is(Type::Number())) {
750 // JSToNumber(x:number) => x
751 return Changed(input);
752 }
753 if (input_type->Is(Type::Undefined())) {
754 // JSToNumber(undefined) => #NaN
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400755 return Replace(jsgraph()->NaNConstant());
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000756 }
757 if (input_type->Is(Type::Null())) {
758 // JSToNumber(null) => #0
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400759 return Replace(jsgraph()->ZeroConstant());
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000760 }
761 if (input_type->Is(Type::Boolean())) {
762 // JSToNumber(x:boolean) => BooleanToNumber(x)
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400763 return Replace(graph()->NewNode(simplified()->BooleanToNumber(), input));
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000764 }
Ben Murdochda12d292016-06-02 14:46:10 +0100765 if (input_type->Is(Type::String())) {
766 // JSToNumber(x:string) => StringToNumber(x)
767 return Replace(graph()->NewNode(simplified()->StringToNumber(), input));
768 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000769 return NoChange();
770}
771
772
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400773Reduction JSTypedLowering::ReduceJSToNumber(Node* node) {
774 // Try to reduce the input first.
775 Node* const input = node->InputAt(0);
776 Reduction reduction = ReduceJSToNumberInput(input);
777 if (reduction.Changed()) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000778 ReplaceWithValue(node, reduction.replacement());
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400779 return reduction;
780 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000781 Type* const input_type = NodeProperties::GetType(input);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400782 if (input_type->Is(Type::PlainPrimitive())) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000783 if (NodeProperties::GetContextInput(node) !=
784 jsgraph()->NoContextConstant() ||
785 NodeProperties::GetEffectInput(node) != graph()->start() ||
786 NodeProperties::GetControlInput(node) != graph()->start()) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400787 // JSToNumber(x:plain-primitive,context,effect,control)
788 // => JSToNumber(x,no-context,start,start)
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000789 RelaxEffectsAndControls(node);
790 NodeProperties::ReplaceContextInput(node, jsgraph()->NoContextConstant());
791 NodeProperties::ReplaceControlInput(node, graph()->start());
792 NodeProperties::ReplaceEffectInput(node, graph()->start());
793 DCHECK_EQ(1, OperatorProperties::GetFrameStateInputCount(node->op()));
794 NodeProperties::ReplaceFrameStateInput(node, 0,
795 jsgraph()->EmptyFrameState());
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400796 return Changed(node);
797 }
798 }
799 return NoChange();
800}
801
802
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000803Reduction JSTypedLowering::ReduceJSToStringInput(Node* input) {
804 if (input->opcode() == IrOpcode::kJSToString) {
805 // Recursively try to reduce the input first.
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400806 Reduction result = ReduceJSToString(input);
807 if (result.Changed()) return result;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000808 return Changed(input); // JSToString(JSToString(x)) => JSToString(x)
809 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000810 Type* input_type = NodeProperties::GetType(input);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000811 if (input_type->Is(Type::String())) {
812 return Changed(input); // JSToString(x:string) => x
813 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000814 if (input_type->Is(Type::Boolean())) {
815 return Replace(graph()->NewNode(
816 common()->Select(MachineRepresentation::kTagged), input,
817 jsgraph()->HeapConstant(factory()->true_string()),
818 jsgraph()->HeapConstant(factory()->false_string())));
819 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000820 if (input_type->Is(Type::Undefined())) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400821 return Replace(jsgraph()->HeapConstant(factory()->undefined_string()));
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000822 }
823 if (input_type->Is(Type::Null())) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400824 return Replace(jsgraph()->HeapConstant(factory()->null_string()));
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000825 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000826 // TODO(turbofan): js-typed-lowering of ToString(x:number)
827 return NoChange();
828}
829
830
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400831Reduction JSTypedLowering::ReduceJSToString(Node* node) {
832 // Try to reduce the input first.
833 Node* const input = node->InputAt(0);
834 Reduction reduction = ReduceJSToStringInput(input);
835 if (reduction.Changed()) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000836 ReplaceWithValue(node, reduction.replacement());
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400837 return reduction;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000838 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000839 return NoChange();
840}
841
842
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000843Reduction JSTypedLowering::ReduceJSToObject(Node* node) {
844 DCHECK_EQ(IrOpcode::kJSToObject, node->opcode());
845 Node* receiver = NodeProperties::GetValueInput(node, 0);
846 Type* receiver_type = NodeProperties::GetType(receiver);
847 Node* context = NodeProperties::GetContextInput(node);
848 Node* frame_state = NodeProperties::GetFrameStateInput(node, 0);
849 Node* effect = NodeProperties::GetEffectInput(node);
850 Node* control = NodeProperties::GetControlInput(node);
851 if (!receiver_type->Is(Type::Receiver())) {
852 // TODO(bmeurer/mstarzinger): Add support for lowering inside try blocks.
853 if (receiver_type->Maybe(Type::NullOrUndefined()) &&
854 NodeProperties::IsExceptionalCall(node)) {
855 // ToObject throws for null or undefined inputs.
856 return NoChange();
857 }
858
859 // Check whether {receiver} is a Smi.
860 Node* check0 = graph()->NewNode(simplified()->ObjectIsSmi(), receiver);
861 Node* branch0 =
862 graph()->NewNode(common()->Branch(BranchHint::kFalse), check0, control);
863 Node* if_true0 = graph()->NewNode(common()->IfTrue(), branch0);
864 Node* etrue0 = effect;
865
866 Node* if_false0 = graph()->NewNode(common()->IfFalse(), branch0);
867 Node* efalse0 = effect;
868
869 // Determine the instance type of {receiver}.
870 Node* receiver_map = efalse0 =
871 graph()->NewNode(simplified()->LoadField(AccessBuilder::ForMap()),
872 receiver, efalse0, if_false0);
873 Node* receiver_instance_type = efalse0 = graph()->NewNode(
874 simplified()->LoadField(AccessBuilder::ForMapInstanceType()),
875 receiver_map, efalse0, if_false0);
876
877 // Check whether {receiver} is a spec object.
878 STATIC_ASSERT(LAST_JS_RECEIVER_TYPE == LAST_TYPE);
879 Node* check1 =
880 graph()->NewNode(machine()->Uint32LessThanOrEqual(),
881 jsgraph()->Uint32Constant(FIRST_JS_RECEIVER_TYPE),
882 receiver_instance_type);
883 Node* branch1 = graph()->NewNode(common()->Branch(BranchHint::kTrue),
884 check1, if_false0);
885 Node* if_true1 = graph()->NewNode(common()->IfTrue(), branch1);
886 Node* etrue1 = efalse0;
887
888 Node* if_false1 = graph()->NewNode(common()->IfFalse(), branch1);
889 Node* efalse1 = efalse0;
890
891 // Convert {receiver} using the ToObjectStub.
892 Node* if_convert =
893 graph()->NewNode(common()->Merge(2), if_true0, if_false1);
894 Node* econvert =
895 graph()->NewNode(common()->EffectPhi(2), etrue0, efalse1, if_convert);
896 Node* rconvert;
897 {
898 Callable callable = CodeFactory::ToObject(isolate());
899 CallDescriptor const* const desc = Linkage::GetStubCallDescriptor(
900 isolate(), graph()->zone(), callable.descriptor(), 0,
901 CallDescriptor::kNeedsFrameState, node->op()->properties());
902 rconvert = econvert = graph()->NewNode(
903 common()->Call(desc), jsgraph()->HeapConstant(callable.code()),
904 receiver, context, frame_state, econvert, if_convert);
905 }
906
907 // The {receiver} is already a spec object.
908 Node* if_done = if_true1;
909 Node* edone = etrue1;
910 Node* rdone = receiver;
911
912 control = graph()->NewNode(common()->Merge(2), if_convert, if_done);
913 effect = graph()->NewNode(common()->EffectPhi(2), econvert, edone, control);
914 receiver =
915 graph()->NewNode(common()->Phi(MachineRepresentation::kTagged, 2),
916 rconvert, rdone, control);
917 }
918 ReplaceWithValue(node, receiver, effect, control);
919 return Changed(receiver);
920}
921
922
923Reduction JSTypedLowering::ReduceJSLoadNamed(Node* node) {
924 DCHECK_EQ(IrOpcode::kJSLoadNamed, node->opcode());
925 Node* receiver = NodeProperties::GetValueInput(node, 0);
926 Type* receiver_type = NodeProperties::GetType(receiver);
927 Node* effect = NodeProperties::GetEffectInput(node);
928 Node* control = NodeProperties::GetControlInput(node);
929 Handle<Name> name = NamedAccessOf(node->op()).name();
930 // Optimize "length" property of strings.
931 if (name.is_identical_to(factory()->length_string()) &&
932 receiver_type->Is(Type::String())) {
933 Node* value = effect = graph()->NewNode(
934 simplified()->LoadField(AccessBuilder::ForStringLength()), receiver,
935 effect, control);
936 ReplaceWithValue(node, value, effect);
937 return Replace(value);
938 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000939 return NoChange();
940}
941
942
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000943Reduction JSTypedLowering::ReduceJSLoadProperty(Node* node) {
944 Node* key = NodeProperties::GetValueInput(node, 1);
945 Node* base = NodeProperties::GetValueInput(node, 0);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000946 Type* key_type = NodeProperties::GetType(key);
947 HeapObjectMatcher mbase(base);
948 if (mbase.HasValue() && mbase.Value()->IsJSTypedArray()) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400949 Handle<JSTypedArray> const array =
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000950 Handle<JSTypedArray>::cast(mbase.Value());
951 if (!array->GetBuffer()->was_neutered()) {
952 array->GetBuffer()->set_is_neuterable(false);
953 BufferAccess const access(array->type());
954 size_t const k =
955 ElementSizeLog2Of(access.machine_type().representation());
956 double const byte_length = array->byte_length()->Number();
957 CHECK_LT(k, arraysize(shifted_int32_ranges_));
958 if (key_type->Is(shifted_int32_ranges_[k]) && byte_length <= kMaxInt) {
959 // JSLoadProperty(typed-array, int32)
960 Handle<FixedTypedArrayBase> elements =
961 Handle<FixedTypedArrayBase>::cast(handle(array->elements()));
962 Node* buffer = jsgraph()->PointerConstant(elements->external_pointer());
963 Node* length = jsgraph()->Constant(byte_length);
964 Node* effect = NodeProperties::GetEffectInput(node);
965 Node* control = NodeProperties::GetControlInput(node);
966 // Check if we can avoid the bounds check.
967 if (key_type->Min() >= 0 && key_type->Max() < array->length_value()) {
968 Node* load = graph()->NewNode(
969 simplified()->LoadElement(
970 AccessBuilder::ForTypedArrayElement(array->type(), true)),
971 buffer, key, effect, control);
972 ReplaceWithValue(node, load, load);
973 return Replace(load);
974 }
975 // Compute byte offset.
976 Node* offset = Word32Shl(key, static_cast<int>(k));
977 Node* load = graph()->NewNode(simplified()->LoadBuffer(access), buffer,
978 offset, length, effect, control);
979 ReplaceWithValue(node, load, load);
980 return Replace(load);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400981 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000982 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000983 }
984 return NoChange();
985}
986
987
988Reduction JSTypedLowering::ReduceJSStoreProperty(Node* node) {
989 Node* key = NodeProperties::GetValueInput(node, 1);
990 Node* base = NodeProperties::GetValueInput(node, 0);
991 Node* value = NodeProperties::GetValueInput(node, 2);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000992 Type* key_type = NodeProperties::GetType(key);
993 Type* value_type = NodeProperties::GetType(value);
994 HeapObjectMatcher mbase(base);
995 if (mbase.HasValue() && mbase.Value()->IsJSTypedArray()) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400996 Handle<JSTypedArray> const array =
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000997 Handle<JSTypedArray>::cast(mbase.Value());
998 if (!array->GetBuffer()->was_neutered()) {
999 array->GetBuffer()->set_is_neuterable(false);
1000 BufferAccess const access(array->type());
1001 size_t const k =
1002 ElementSizeLog2Of(access.machine_type().representation());
1003 double const byte_length = array->byte_length()->Number();
1004 CHECK_LT(k, arraysize(shifted_int32_ranges_));
1005 if (access.external_array_type() != kExternalUint8ClampedArray &&
1006 key_type->Is(shifted_int32_ranges_[k]) && byte_length <= kMaxInt) {
1007 // JSLoadProperty(typed-array, int32)
1008 Handle<FixedTypedArrayBase> elements =
1009 Handle<FixedTypedArrayBase>::cast(handle(array->elements()));
1010 Node* buffer = jsgraph()->PointerConstant(elements->external_pointer());
1011 Node* length = jsgraph()->Constant(byte_length);
1012 Node* context = NodeProperties::GetContextInput(node);
1013 Node* effect = NodeProperties::GetEffectInput(node);
1014 Node* control = NodeProperties::GetControlInput(node);
1015 // Convert to a number first.
Ben Murdochc5610432016-08-08 18:44:38 +01001016 if (!value_type->Is(Type::NumberOrUndefined())) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001017 Reduction number_reduction = ReduceJSToNumberInput(value);
1018 if (number_reduction.Changed()) {
1019 value = number_reduction.replacement();
1020 } else {
1021 Node* frame_state_for_to_number =
1022 NodeProperties::GetFrameStateInput(node, 1);
1023 value = effect =
1024 graph()->NewNode(javascript()->ToNumber(), value, context,
1025 frame_state_for_to_number, effect, control);
1026 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001027 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001028 // Check if we can avoid the bounds check.
1029 if (key_type->Min() >= 0 && key_type->Max() < array->length_value()) {
1030 RelaxControls(node);
1031 node->ReplaceInput(0, buffer);
1032 DCHECK_EQ(key, node->InputAt(1));
1033 node->ReplaceInput(2, value);
1034 node->ReplaceInput(3, effect);
1035 node->ReplaceInput(4, control);
1036 node->TrimInputCount(5);
1037 NodeProperties::ChangeOp(
1038 node,
1039 simplified()->StoreElement(
1040 AccessBuilder::ForTypedArrayElement(array->type(), true)));
1041 return Changed(node);
1042 }
1043 // Compute byte offset.
1044 Node* offset = Word32Shl(key, static_cast<int>(k));
1045 // Turn into a StoreBuffer operation.
1046 RelaxControls(node);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001047 node->ReplaceInput(0, buffer);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001048 node->ReplaceInput(1, offset);
1049 node->ReplaceInput(2, length);
1050 node->ReplaceInput(3, value);
1051 node->ReplaceInput(4, effect);
1052 node->ReplaceInput(5, control);
1053 node->TrimInputCount(6);
1054 NodeProperties::ChangeOp(node, simplified()->StoreBuffer(access));
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001055 return Changed(node);
1056 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001057 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001058 }
1059 return NoChange();
1060}
1061
1062
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001063Reduction JSTypedLowering::ReduceJSInstanceOf(Node* node) {
1064 DCHECK_EQ(IrOpcode::kJSInstanceOf, node->opcode());
1065 Node* const context = NodeProperties::GetContextInput(node);
1066 Node* const frame_state = NodeProperties::GetFrameStateInput(node, 0);
1067
1068 // If deoptimization is disabled, we cannot optimize.
Ben Murdochc5610432016-08-08 18:44:38 +01001069 if (!(flags() & kDeoptimizationEnabled)) return NoChange();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001070
1071 // If we are in a try block, don't optimize since the runtime call
1072 // in the proxy case can throw.
1073 if (NodeProperties::IsExceptionalCall(node)) return NoChange();
1074
1075 JSBinopReduction r(this, node);
1076 Node* effect = r.effect();
1077 Node* control = r.control();
1078
1079 if (!r.right_type()->IsConstant() ||
1080 !r.right_type()->AsConstant()->Value()->IsJSFunction()) {
1081 return NoChange();
1082 }
1083
1084 Handle<JSFunction> function =
1085 Handle<JSFunction>::cast(r.right_type()->AsConstant()->Value());
1086 Handle<SharedFunctionInfo> shared(function->shared(), isolate());
1087
Ben Murdochc5610432016-08-08 18:44:38 +01001088 // Make sure the prototype of {function} is the %FunctionPrototype%, and it
1089 // already has a meaningful initial map (i.e. we constructed at least one
1090 // instance using the constructor {function}).
1091 if (function->map()->prototype() != function->native_context()->closure() ||
1092 function->map()->has_non_instance_prototype() ||
1093 !function->has_initial_map()) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001094 return NoChange();
1095 }
1096
Ben Murdochc5610432016-08-08 18:44:38 +01001097 // We can only use the fast case if @@hasInstance was not used so far.
1098 if (!isolate()->IsHasInstanceLookupChainIntact()) return NoChange();
1099 dependencies()->AssumePropertyCell(factory()->has_instance_protector());
1100
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001101 Handle<Map> initial_map(function->initial_map(), isolate());
Ben Murdochc5610432016-08-08 18:44:38 +01001102 dependencies()->AssumeInitialMapCantChange(initial_map);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001103 Node* prototype =
1104 jsgraph()->Constant(handle(initial_map->prototype(), isolate()));
1105
1106 Node* if_is_smi = nullptr;
1107 Node* e_is_smi = nullptr;
1108 // If the left hand side is an object, no smi check is needed.
1109 if (r.left_type()->Maybe(Type::TaggedSigned())) {
1110 Node* is_smi = graph()->NewNode(simplified()->ObjectIsSmi(), r.left());
1111 Node* branch_is_smi =
1112 graph()->NewNode(common()->Branch(BranchHint::kFalse), is_smi, control);
1113 if_is_smi = graph()->NewNode(common()->IfTrue(), branch_is_smi);
1114 e_is_smi = effect;
1115 control = graph()->NewNode(common()->IfFalse(), branch_is_smi);
1116 }
1117
1118 Node* object_map = effect =
1119 graph()->NewNode(simplified()->LoadField(AccessBuilder::ForMap()),
1120 r.left(), effect, control);
1121
1122 // Loop through the {object}s prototype chain looking for the {prototype}.
1123 Node* loop = control = graph()->NewNode(common()->Loop(2), control, control);
1124
1125 Node* loop_effect = effect =
1126 graph()->NewNode(common()->EffectPhi(2), effect, effect, loop);
1127
1128 Node* loop_object_map =
1129 graph()->NewNode(common()->Phi(MachineRepresentation::kTagged, 2),
1130 object_map, r.left(), loop);
1131
1132 // Check if the lhs needs access checks.
1133 Node* map_bit_field = effect =
1134 graph()->NewNode(simplified()->LoadField(AccessBuilder::ForMapBitField()),
1135 loop_object_map, loop_effect, control);
1136 int is_access_check_needed_bit = 1 << Map::kIsAccessCheckNeeded;
1137 Node* is_access_check_needed_num =
1138 graph()->NewNode(simplified()->NumberBitwiseAnd(), map_bit_field,
1139 jsgraph()->Uint32Constant(is_access_check_needed_bit));
1140 Node* is_access_check_needed =
1141 graph()->NewNode(machine()->Word32Equal(), is_access_check_needed_num,
1142 jsgraph()->Uint32Constant(is_access_check_needed_bit));
1143
1144 Node* branch_is_access_check_needed = graph()->NewNode(
1145 common()->Branch(BranchHint::kFalse), is_access_check_needed, control);
1146 Node* if_is_access_check_needed =
1147 graph()->NewNode(common()->IfTrue(), branch_is_access_check_needed);
1148 Node* e_is_access_check_needed = effect;
1149
1150 control =
1151 graph()->NewNode(common()->IfFalse(), branch_is_access_check_needed);
1152
1153 // Check if the lhs is a proxy.
1154 Node* map_instance_type = effect = graph()->NewNode(
1155 simplified()->LoadField(AccessBuilder::ForMapInstanceType()),
1156 loop_object_map, loop_effect, control);
1157 Node* is_proxy = graph()->NewNode(machine()->Word32Equal(), map_instance_type,
1158 jsgraph()->Uint32Constant(JS_PROXY_TYPE));
1159 Node* branch_is_proxy =
1160 graph()->NewNode(common()->Branch(BranchHint::kFalse), is_proxy, control);
1161 Node* if_is_proxy = graph()->NewNode(common()->IfTrue(), branch_is_proxy);
1162 Node* e_is_proxy = effect;
1163
1164
1165 Node* runtime_has_in_proto_chain = control = graph()->NewNode(
1166 common()->Merge(2), if_is_access_check_needed, if_is_proxy);
1167 effect = graph()->NewNode(common()->EffectPhi(2), e_is_access_check_needed,
1168 e_is_proxy, control);
1169
1170 // If we need an access check or the object is a Proxy, make a runtime call
1171 // to finish the lowering.
1172 Node* bool_result_runtime_has_in_proto_chain_case = graph()->NewNode(
Ben Murdoch097c5b22016-05-18 11:27:45 +01001173 javascript()->CallRuntime(Runtime::kHasInPrototypeChain), r.left(),
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001174 prototype, context, frame_state, effect, control);
1175
1176 control = graph()->NewNode(common()->IfFalse(), branch_is_proxy);
1177
1178 Node* object_prototype = effect = graph()->NewNode(
1179 simplified()->LoadField(AccessBuilder::ForMapPrototype()),
1180 loop_object_map, loop_effect, control);
1181
1182 // Check if object prototype is equal to function prototype.
1183 Node* eq_proto =
1184 graph()->NewNode(simplified()->ReferenceEqual(r.right_type()),
1185 object_prototype, prototype);
1186 Node* branch_eq_proto =
1187 graph()->NewNode(common()->Branch(BranchHint::kFalse), eq_proto, control);
1188 Node* if_eq_proto = graph()->NewNode(common()->IfTrue(), branch_eq_proto);
1189 Node* e_eq_proto = effect;
1190
1191 control = graph()->NewNode(common()->IfFalse(), branch_eq_proto);
1192
1193 // If not, check if object prototype is the null prototype.
1194 Node* null_proto =
1195 graph()->NewNode(simplified()->ReferenceEqual(r.right_type()),
1196 object_prototype, jsgraph()->NullConstant());
1197 Node* branch_null_proto = graph()->NewNode(
1198 common()->Branch(BranchHint::kFalse), null_proto, control);
1199 Node* if_null_proto = graph()->NewNode(common()->IfTrue(), branch_null_proto);
1200 Node* e_null_proto = effect;
1201
1202 control = graph()->NewNode(common()->IfFalse(), branch_null_proto);
1203 Node* load_object_map = effect =
1204 graph()->NewNode(simplified()->LoadField(AccessBuilder::ForMap()),
1205 object_prototype, effect, control);
1206 // Close the loop.
1207 loop_effect->ReplaceInput(1, effect);
1208 loop_object_map->ReplaceInput(1, load_object_map);
1209 loop->ReplaceInput(1, control);
1210
1211 control = graph()->NewNode(common()->Merge(3), runtime_has_in_proto_chain,
1212 if_eq_proto, if_null_proto);
1213 effect = graph()->NewNode(common()->EffectPhi(3),
1214 bool_result_runtime_has_in_proto_chain_case,
1215 e_eq_proto, e_null_proto, control);
1216
1217 Node* result = graph()->NewNode(
1218 common()->Phi(MachineRepresentation::kTagged, 3),
1219 bool_result_runtime_has_in_proto_chain_case, jsgraph()->TrueConstant(),
1220 jsgraph()->FalseConstant(), control);
1221
1222 if (if_is_smi != nullptr) {
1223 DCHECK_NOT_NULL(e_is_smi);
1224 control = graph()->NewNode(common()->Merge(2), if_is_smi, control);
1225 effect =
1226 graph()->NewNode(common()->EffectPhi(2), e_is_smi, effect, control);
1227 result = graph()->NewNode(common()->Phi(MachineRepresentation::kTagged, 2),
1228 jsgraph()->FalseConstant(), result, control);
1229 }
1230
1231 ReplaceWithValue(node, result, effect, control);
1232 return Changed(result);
1233}
1234
1235
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001236Reduction JSTypedLowering::ReduceJSLoadContext(Node* node) {
1237 DCHECK_EQ(IrOpcode::kJSLoadContext, node->opcode());
1238 ContextAccess const& access = ContextAccessOf(node->op());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001239 Node* effect = NodeProperties::GetEffectInput(node);
1240 Node* control = graph()->start();
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001241 for (size_t i = 0; i < access.depth(); ++i) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001242 Node* previous = effect = graph()->NewNode(
1243 simplified()->LoadField(
1244 AccessBuilder::ForContextSlot(Context::PREVIOUS_INDEX)),
1245 NodeProperties::GetValueInput(node, 0), effect, control);
1246 node->ReplaceInput(0, previous);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001247 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001248 node->ReplaceInput(1, effect);
1249 node->ReplaceInput(2, control);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001250 NodeProperties::ChangeOp(
1251 node,
1252 simplified()->LoadField(AccessBuilder::ForContextSlot(access.index())));
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001253 return Changed(node);
1254}
1255
1256
1257Reduction JSTypedLowering::ReduceJSStoreContext(Node* node) {
1258 DCHECK_EQ(IrOpcode::kJSStoreContext, node->opcode());
1259 ContextAccess const& access = ContextAccessOf(node->op());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001260 Node* effect = NodeProperties::GetEffectInput(node);
1261 Node* control = graph()->start();
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001262 for (size_t i = 0; i < access.depth(); ++i) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001263 Node* previous = effect = graph()->NewNode(
1264 simplified()->LoadField(
1265 AccessBuilder::ForContextSlot(Context::PREVIOUS_INDEX)),
1266 NodeProperties::GetValueInput(node, 0), effect, control);
1267 node->ReplaceInput(0, previous);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001268 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001269 node->RemoveInput(2);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001270 node->ReplaceInput(2, effect);
1271 NodeProperties::ChangeOp(
1272 node,
1273 simplified()->StoreField(AccessBuilder::ForContextSlot(access.index())));
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001274 return Changed(node);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001275}
1276
1277
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001278Reduction JSTypedLowering::ReduceJSConvertReceiver(Node* node) {
1279 DCHECK_EQ(IrOpcode::kJSConvertReceiver, node->opcode());
1280 ConvertReceiverMode mode = ConvertReceiverModeOf(node->op());
1281 Node* receiver = NodeProperties::GetValueInput(node, 0);
1282 Type* receiver_type = NodeProperties::GetType(receiver);
1283 Node* context = NodeProperties::GetContextInput(node);
1284 Type* context_type = NodeProperties::GetType(context);
1285 Node* frame_state = NodeProperties::GetFrameStateInput(node, 0);
1286 Node* effect = NodeProperties::GetEffectInput(node);
1287 Node* control = NodeProperties::GetControlInput(node);
1288 if (!receiver_type->Is(Type::Receiver())) {
1289 if (receiver_type->Is(Type::NullOrUndefined()) ||
1290 mode == ConvertReceiverMode::kNullOrUndefined) {
1291 if (context_type->IsConstant()) {
1292 Handle<JSObject> global_proxy(
1293 Handle<Context>::cast(context_type->AsConstant()->Value())
1294 ->global_proxy(),
1295 isolate());
1296 receiver = jsgraph()->Constant(global_proxy);
1297 } else {
1298 Node* native_context = effect = graph()->NewNode(
1299 javascript()->LoadContext(0, Context::NATIVE_CONTEXT_INDEX, true),
1300 context, context, effect);
1301 receiver = effect = graph()->NewNode(
1302 javascript()->LoadContext(0, Context::GLOBAL_PROXY_INDEX, true),
1303 native_context, native_context, effect);
1304 }
1305 } else if (!receiver_type->Maybe(Type::NullOrUndefined()) ||
1306 mode == ConvertReceiverMode::kNotNullOrUndefined) {
1307 receiver = effect =
1308 graph()->NewNode(javascript()->ToObject(), receiver, context,
1309 frame_state, effect, control);
1310 } else {
1311 // Check {receiver} for undefined.
1312 Node* check0 =
1313 graph()->NewNode(simplified()->ReferenceEqual(receiver_type),
1314 receiver, jsgraph()->UndefinedConstant());
1315 Node* branch0 = graph()->NewNode(common()->Branch(BranchHint::kFalse),
1316 check0, control);
1317 Node* if_true0 = graph()->NewNode(common()->IfTrue(), branch0);
1318 Node* if_false0 = graph()->NewNode(common()->IfFalse(), branch0);
1319
1320 // Check {receiver} for null.
1321 Node* check1 =
1322 graph()->NewNode(simplified()->ReferenceEqual(receiver_type),
1323 receiver, jsgraph()->NullConstant());
1324 Node* branch1 = graph()->NewNode(common()->Branch(BranchHint::kFalse),
1325 check1, if_false0);
1326 Node* if_true1 = graph()->NewNode(common()->IfTrue(), branch1);
1327 Node* if_false1 = graph()->NewNode(common()->IfFalse(), branch1);
1328
1329 // Convert {receiver} using ToObject.
1330 Node* if_convert = if_false1;
1331 Node* econvert = effect;
1332 Node* rconvert;
1333 {
1334 rconvert = econvert =
1335 graph()->NewNode(javascript()->ToObject(), receiver, context,
1336 frame_state, econvert, if_convert);
1337 }
1338
1339 // Replace {receiver} with global proxy of {context}.
1340 Node* if_global =
1341 graph()->NewNode(common()->Merge(2), if_true0, if_true1);
1342 Node* eglobal = effect;
1343 Node* rglobal;
1344 {
1345 if (context_type->IsConstant()) {
1346 Handle<JSObject> global_proxy(
1347 Handle<Context>::cast(context_type->AsConstant()->Value())
1348 ->global_proxy(),
1349 isolate());
1350 rglobal = jsgraph()->Constant(global_proxy);
1351 } else {
1352 Node* native_context = eglobal = graph()->NewNode(
1353 javascript()->LoadContext(0, Context::NATIVE_CONTEXT_INDEX, true),
1354 context, context, eglobal);
1355 rglobal = eglobal = graph()->NewNode(
1356 javascript()->LoadContext(0, Context::GLOBAL_PROXY_INDEX, true),
1357 native_context, native_context, eglobal);
1358 }
1359 }
1360
1361 control = graph()->NewNode(common()->Merge(2), if_convert, if_global);
1362 effect =
1363 graph()->NewNode(common()->EffectPhi(2), econvert, eglobal, control);
1364 receiver =
1365 graph()->NewNode(common()->Phi(MachineRepresentation::kTagged, 2),
1366 rconvert, rglobal, control);
1367 }
1368 }
1369 ReplaceWithValue(node, receiver, effect, control);
1370 return Changed(receiver);
1371}
1372
1373
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001374Reduction JSTypedLowering::ReduceJSCallConstruct(Node* node) {
1375 DCHECK_EQ(IrOpcode::kJSCallConstruct, node->opcode());
1376 CallConstructParameters const& p = CallConstructParametersOf(node->op());
1377 DCHECK_LE(2u, p.arity());
1378 int const arity = static_cast<int>(p.arity() - 2);
1379 Node* target = NodeProperties::GetValueInput(node, 0);
1380 Type* target_type = NodeProperties::GetType(target);
1381 Node* new_target = NodeProperties::GetValueInput(node, arity + 1);
1382
1383 // Check if {target} is a known JSFunction.
1384 if (target_type->IsConstant() &&
1385 target_type->AsConstant()->Value()->IsJSFunction()) {
1386 Handle<JSFunction> function =
1387 Handle<JSFunction>::cast(target_type->AsConstant()->Value());
1388 Handle<SharedFunctionInfo> shared(function->shared(), isolate());
1389
1390 // Remove the eager bailout frame state.
1391 NodeProperties::RemoveFrameStateInput(node, 1);
1392
1393 // Patch {node} to an indirect call via the {function}s construct stub.
1394 Callable callable(handle(shared->construct_stub(), isolate()),
1395 ConstructStubDescriptor(isolate()));
1396 node->RemoveInput(arity + 1);
1397 node->InsertInput(graph()->zone(), 0,
1398 jsgraph()->HeapConstant(callable.code()));
1399 node->InsertInput(graph()->zone(), 2, new_target);
1400 node->InsertInput(graph()->zone(), 3, jsgraph()->Int32Constant(arity));
1401 node->InsertInput(graph()->zone(), 4, jsgraph()->UndefinedConstant());
1402 node->InsertInput(graph()->zone(), 5, jsgraph()->UndefinedConstant());
1403 NodeProperties::ChangeOp(
1404 node, common()->Call(Linkage::GetStubCallDescriptor(
1405 isolate(), graph()->zone(), callable.descriptor(), 1 + arity,
1406 CallDescriptor::kNeedsFrameState)));
1407 return Changed(node);
1408 }
1409
1410 // Check if {target} is a JSFunction.
1411 if (target_type->Is(Type::Function())) {
1412 // Remove the eager bailout frame state.
1413 NodeProperties::RemoveFrameStateInput(node, 1);
1414
1415 // Patch {node} to an indirect call via the ConstructFunction builtin.
1416 Callable callable = CodeFactory::ConstructFunction(isolate());
1417 node->RemoveInput(arity + 1);
1418 node->InsertInput(graph()->zone(), 0,
1419 jsgraph()->HeapConstant(callable.code()));
1420 node->InsertInput(graph()->zone(), 2, new_target);
1421 node->InsertInput(graph()->zone(), 3, jsgraph()->Int32Constant(arity));
1422 node->InsertInput(graph()->zone(), 4, jsgraph()->UndefinedConstant());
1423 NodeProperties::ChangeOp(
1424 node, common()->Call(Linkage::GetStubCallDescriptor(
1425 isolate(), graph()->zone(), callable.descriptor(), 1 + arity,
1426 CallDescriptor::kNeedsFrameState)));
1427 return Changed(node);
1428 }
1429
1430 return NoChange();
1431}
1432
1433
1434Reduction JSTypedLowering::ReduceJSCallFunction(Node* node) {
1435 DCHECK_EQ(IrOpcode::kJSCallFunction, node->opcode());
1436 CallFunctionParameters const& p = CallFunctionParametersOf(node->op());
1437 int const arity = static_cast<int>(p.arity() - 2);
1438 ConvertReceiverMode convert_mode = p.convert_mode();
1439 Node* target = NodeProperties::GetValueInput(node, 0);
1440 Type* target_type = NodeProperties::GetType(target);
1441 Node* receiver = NodeProperties::GetValueInput(node, 1);
1442 Type* receiver_type = NodeProperties::GetType(receiver);
1443 Node* frame_state = NodeProperties::GetFrameStateInput(node, 1);
1444 Node* effect = NodeProperties::GetEffectInput(node);
1445 Node* control = NodeProperties::GetControlInput(node);
1446
1447 // Try to infer receiver {convert_mode} from {receiver} type.
1448 if (receiver_type->Is(Type::NullOrUndefined())) {
1449 convert_mode = ConvertReceiverMode::kNullOrUndefined;
1450 } else if (!receiver_type->Maybe(Type::NullOrUndefined())) {
1451 convert_mode = ConvertReceiverMode::kNotNullOrUndefined;
1452 }
1453
1454 // Check if {target} is a known JSFunction.
1455 if (target_type->IsConstant() &&
1456 target_type->AsConstant()->Value()->IsJSFunction()) {
1457 Handle<JSFunction> function =
1458 Handle<JSFunction>::cast(target_type->AsConstant()->Value());
1459 Handle<SharedFunctionInfo> shared(function->shared(), isolate());
1460
1461 // Class constructors are callable, but [[Call]] will raise an exception.
1462 // See ES6 section 9.2.1 [[Call]] ( thisArgument, argumentsList ).
1463 if (IsClassConstructor(shared->kind())) return NoChange();
1464
1465 // Load the context from the {target}.
1466 Node* context = effect = graph()->NewNode(
1467 simplified()->LoadField(AccessBuilder::ForJSFunctionContext()), target,
1468 effect, control);
1469 NodeProperties::ReplaceContextInput(node, context);
1470
1471 // Check if we need to convert the {receiver}.
1472 if (is_sloppy(shared->language_mode()) && !shared->native() &&
1473 !receiver_type->Is(Type::Receiver())) {
1474 receiver = effect =
1475 graph()->NewNode(javascript()->ConvertReceiver(convert_mode),
1476 receiver, context, frame_state, effect, control);
1477 NodeProperties::ReplaceValueInput(node, receiver, 1);
1478 }
1479
1480 // Update the effect dependency for the {node}.
1481 NodeProperties::ReplaceEffectInput(node, effect);
1482
1483 // Remove the eager bailout frame state.
1484 NodeProperties::RemoveFrameStateInput(node, 1);
1485
1486 // Compute flags for the call.
1487 CallDescriptor::Flags flags = CallDescriptor::kNeedsFrameState;
1488 if (p.tail_call_mode() == TailCallMode::kAllow) {
1489 flags |= CallDescriptor::kSupportsTailCalls;
1490 }
1491
1492 Node* new_target = jsgraph()->UndefinedConstant();
1493 Node* argument_count = jsgraph()->Int32Constant(arity);
1494 if (shared->internal_formal_parameter_count() == arity ||
1495 shared->internal_formal_parameter_count() ==
1496 SharedFunctionInfo::kDontAdaptArgumentsSentinel) {
1497 // Patch {node} to a direct call.
1498 node->InsertInput(graph()->zone(), arity + 2, new_target);
1499 node->InsertInput(graph()->zone(), arity + 3, argument_count);
1500 NodeProperties::ChangeOp(node,
1501 common()->Call(Linkage::GetJSCallDescriptor(
1502 graph()->zone(), false, 1 + arity, flags)));
1503 } else {
1504 // Patch {node} to an indirect call via the ArgumentsAdaptorTrampoline.
1505 Callable callable = CodeFactory::ArgumentAdaptor(isolate());
1506 node->InsertInput(graph()->zone(), 0,
1507 jsgraph()->HeapConstant(callable.code()));
1508 node->InsertInput(graph()->zone(), 2, new_target);
1509 node->InsertInput(graph()->zone(), 3, argument_count);
1510 node->InsertInput(
1511 graph()->zone(), 4,
1512 jsgraph()->Int32Constant(shared->internal_formal_parameter_count()));
1513 NodeProperties::ChangeOp(
1514 node, common()->Call(Linkage::GetStubCallDescriptor(
1515 isolate(), graph()->zone(), callable.descriptor(),
1516 1 + arity, flags)));
1517 }
1518 return Changed(node);
1519 }
1520
1521 // Check if {target} is a JSFunction.
1522 if (target_type->Is(Type::Function())) {
1523 // Remove the eager bailout frame state.
1524 NodeProperties::RemoveFrameStateInput(node, 1);
1525
1526 // Compute flags for the call.
1527 CallDescriptor::Flags flags = CallDescriptor::kNeedsFrameState;
1528 if (p.tail_call_mode() == TailCallMode::kAllow) {
1529 flags |= CallDescriptor::kSupportsTailCalls;
1530 }
1531
1532 // Patch {node} to an indirect call via the CallFunction builtin.
1533 Callable callable = CodeFactory::CallFunction(isolate(), convert_mode);
1534 node->InsertInput(graph()->zone(), 0,
1535 jsgraph()->HeapConstant(callable.code()));
1536 node->InsertInput(graph()->zone(), 2, jsgraph()->Int32Constant(arity));
1537 NodeProperties::ChangeOp(
1538 node, common()->Call(Linkage::GetStubCallDescriptor(
1539 isolate(), graph()->zone(), callable.descriptor(), 1 + arity,
1540 flags)));
1541 return Changed(node);
1542 }
1543
1544 // Maybe we did at least learn something about the {receiver}.
1545 if (p.convert_mode() != convert_mode) {
1546 NodeProperties::ChangeOp(
Ben Murdoch097c5b22016-05-18 11:27:45 +01001547 node, javascript()->CallFunction(p.arity(), p.feedback(), convert_mode,
1548 p.tail_call_mode()));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001549 return Changed(node);
1550 }
1551
1552 return NoChange();
1553}
1554
1555
1556Reduction JSTypedLowering::ReduceJSForInDone(Node* node) {
1557 DCHECK_EQ(IrOpcode::kJSForInDone, node->opcode());
1558 node->TrimInputCount(2);
1559 NodeProperties::ChangeOp(node, machine()->Word32Equal());
1560 return Changed(node);
1561}
1562
1563
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001564Reduction JSTypedLowering::ReduceJSForInNext(Node* node) {
1565 DCHECK_EQ(IrOpcode::kJSForInNext, node->opcode());
1566 Node* receiver = NodeProperties::GetValueInput(node, 0);
1567 Node* cache_array = NodeProperties::GetValueInput(node, 1);
1568 Node* cache_type = NodeProperties::GetValueInput(node, 2);
1569 Node* index = NodeProperties::GetValueInput(node, 3);
1570 Node* context = NodeProperties::GetContextInput(node);
1571 Node* frame_state = NodeProperties::GetFrameStateInput(node, 0);
1572 Node* effect = NodeProperties::GetEffectInput(node);
1573 Node* control = NodeProperties::GetControlInput(node);
1574
1575 // Load the next {key} from the {cache_array}.
1576 Node* key = effect = graph()->NewNode(
1577 simplified()->LoadElement(AccessBuilder::ForFixedArrayElement()),
1578 cache_array, index, effect, control);
1579
1580 // Load the map of the {receiver}.
1581 Node* receiver_map = effect =
1582 graph()->NewNode(simplified()->LoadField(AccessBuilder::ForMap()),
1583 receiver, effect, control);
1584
1585 // Check if the expected map still matches that of the {receiver}.
1586 Node* check0 = graph()->NewNode(simplified()->ReferenceEqual(Type::Any()),
1587 receiver_map, cache_type);
1588 Node* branch0 =
1589 graph()->NewNode(common()->Branch(BranchHint::kTrue), check0, control);
1590
1591 Node* if_true0 = graph()->NewNode(common()->IfTrue(), branch0);
1592 Node* etrue0;
1593 Node* vtrue0;
1594 {
1595 // Don't need filtering since expected map still matches that of the
1596 // {receiver}.
1597 etrue0 = effect;
1598 vtrue0 = key;
1599 }
1600
1601 Node* if_false0 = graph()->NewNode(common()->IfFalse(), branch0);
1602 Node* efalse0;
1603 Node* vfalse0;
1604 {
Ben Murdoch097c5b22016-05-18 11:27:45 +01001605 // Filter the {key} to check if it's still a valid property of the
1606 // {receiver} (does the ToName conversion implicitly).
1607 vfalse0 = efalse0 = graph()->NewNode(
1608 javascript()->CallRuntime(Runtime::kForInFilter), receiver, key,
1609 context, frame_state, effect, if_false0);
1610 if_false0 = graph()->NewNode(common()->IfSuccess(), vfalse0);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001611 }
1612
1613 control = graph()->NewNode(common()->Merge(2), if_true0, if_false0);
1614 effect = graph()->NewNode(common()->EffectPhi(2), etrue0, efalse0, control);
1615 ReplaceWithValue(node, node, effect, control);
1616 node->ReplaceInput(0, vtrue0);
1617 node->ReplaceInput(1, vfalse0);
1618 node->ReplaceInput(2, control);
1619 node->TrimInputCount(3);
1620 NodeProperties::ChangeOp(node,
1621 common()->Phi(MachineRepresentation::kTagged, 2));
1622 return Changed(node);
1623}
1624
1625
1626Reduction JSTypedLowering::ReduceJSForInStep(Node* node) {
1627 DCHECK_EQ(IrOpcode::kJSForInStep, node->opcode());
1628 node->ReplaceInput(1, jsgraph()->Int32Constant(1));
1629 NodeProperties::ChangeOp(node, machine()->Int32Add());
1630 return Changed(node);
1631}
1632
1633
1634Reduction JSTypedLowering::ReduceSelect(Node* node) {
1635 DCHECK_EQ(IrOpcode::kSelect, node->opcode());
1636 Node* const condition = NodeProperties::GetValueInput(node, 0);
1637 Type* const condition_type = NodeProperties::GetType(condition);
1638 Node* const vtrue = NodeProperties::GetValueInput(node, 1);
1639 Type* const vtrue_type = NodeProperties::GetType(vtrue);
1640 Node* const vfalse = NodeProperties::GetValueInput(node, 2);
1641 Type* const vfalse_type = NodeProperties::GetType(vfalse);
1642 if (condition_type->Is(true_type_)) {
1643 // Select(condition:true, vtrue, vfalse) => vtrue
1644 return Replace(vtrue);
1645 }
1646 if (condition_type->Is(false_type_)) {
1647 // Select(condition:false, vtrue, vfalse) => vfalse
1648 return Replace(vfalse);
1649 }
1650 if (vtrue_type->Is(true_type_) && vfalse_type->Is(false_type_)) {
1651 // Select(condition, vtrue:true, vfalse:false) => condition
1652 return Replace(condition);
1653 }
1654 if (vtrue_type->Is(false_type_) && vfalse_type->Is(true_type_)) {
1655 // Select(condition, vtrue:false, vfalse:true) => BooleanNot(condition)
1656 node->TrimInputCount(1);
1657 NodeProperties::ChangeOp(node, simplified()->BooleanNot());
1658 return Changed(node);
1659 }
1660 return NoChange();
1661}
1662
1663
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001664Reduction JSTypedLowering::Reduce(Node* node) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001665 // Check if the output type is a singleton. In that case we already know the
1666 // result value and can simply replace the node if it's eliminable.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001667 if (!NodeProperties::IsConstant(node) && NodeProperties::IsTyped(node) &&
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001668 node->op()->HasProperty(Operator::kEliminatable)) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001669 Type* upper = NodeProperties::GetType(node);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001670 if (upper->IsConstant()) {
1671 Node* replacement = jsgraph()->Constant(upper->AsConstant()->Value());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001672 ReplaceWithValue(node, replacement);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001673 return Changed(replacement);
1674 } else if (upper->Is(Type::MinusZero())) {
1675 Node* replacement = jsgraph()->Constant(factory()->minus_zero_value());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001676 ReplaceWithValue(node, replacement);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001677 return Changed(replacement);
1678 } else if (upper->Is(Type::NaN())) {
1679 Node* replacement = jsgraph()->NaNConstant();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001680 ReplaceWithValue(node, replacement);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001681 return Changed(replacement);
1682 } else if (upper->Is(Type::Null())) {
1683 Node* replacement = jsgraph()->NullConstant();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001684 ReplaceWithValue(node, replacement);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001685 return Changed(replacement);
1686 } else if (upper->Is(Type::PlainNumber()) && upper->Min() == upper->Max()) {
1687 Node* replacement = jsgraph()->Constant(upper->Min());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001688 ReplaceWithValue(node, replacement);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001689 return Changed(replacement);
1690 } else if (upper->Is(Type::Undefined())) {
1691 Node* replacement = jsgraph()->UndefinedConstant();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001692 ReplaceWithValue(node, replacement);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001693 return Changed(replacement);
1694 }
1695 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001696 switch (node->opcode()) {
1697 case IrOpcode::kJSEqual:
1698 return ReduceJSEqual(node, false);
1699 case IrOpcode::kJSNotEqual:
1700 return ReduceJSEqual(node, true);
1701 case IrOpcode::kJSStrictEqual:
1702 return ReduceJSStrictEqual(node, false);
1703 case IrOpcode::kJSStrictNotEqual:
1704 return ReduceJSStrictEqual(node, true);
1705 case IrOpcode::kJSLessThan: // fall through
1706 case IrOpcode::kJSGreaterThan: // fall through
1707 case IrOpcode::kJSLessThanOrEqual: // fall through
1708 case IrOpcode::kJSGreaterThanOrEqual:
1709 return ReduceJSComparison(node);
1710 case IrOpcode::kJSBitwiseOr:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001711 return ReduceInt32Binop(node, simplified()->NumberBitwiseOr());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001712 case IrOpcode::kJSBitwiseXor:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001713 return ReduceInt32Binop(node, simplified()->NumberBitwiseXor());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001714 case IrOpcode::kJSBitwiseAnd:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001715 return ReduceInt32Binop(node, simplified()->NumberBitwiseAnd());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001716 case IrOpcode::kJSShiftLeft:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001717 return ReduceUI32Shift(node, kSigned, simplified()->NumberShiftLeft());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001718 case IrOpcode::kJSShiftRight:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001719 return ReduceUI32Shift(node, kSigned, simplified()->NumberShiftRight());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001720 case IrOpcode::kJSShiftRightLogical:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001721 return ReduceUI32Shift(node, kUnsigned,
1722 simplified()->NumberShiftRightLogical());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001723 case IrOpcode::kJSAdd:
1724 return ReduceJSAdd(node);
1725 case IrOpcode::kJSSubtract:
1726 return ReduceNumberBinop(node, simplified()->NumberSubtract());
1727 case IrOpcode::kJSMultiply:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001728 return ReduceNumberBinop(node, simplified()->NumberMultiply());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001729 case IrOpcode::kJSDivide:
1730 return ReduceNumberBinop(node, simplified()->NumberDivide());
1731 case IrOpcode::kJSModulus:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001732 return ReduceJSModulus(node);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001733 case IrOpcode::kJSToBoolean:
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001734 return ReduceJSToBoolean(node);
Ben Murdochda12d292016-06-02 14:46:10 +01001735 case IrOpcode::kJSToInteger:
1736 return ReduceJSToInteger(node);
1737 case IrOpcode::kJSToLength:
1738 return ReduceJSToLength(node);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001739 case IrOpcode::kJSToNumber:
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001740 return ReduceJSToNumber(node);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001741 case IrOpcode::kJSToString:
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001742 return ReduceJSToString(node);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001743 case IrOpcode::kJSToObject:
1744 return ReduceJSToObject(node);
1745 case IrOpcode::kJSLoadNamed:
1746 return ReduceJSLoadNamed(node);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001747 case IrOpcode::kJSLoadProperty:
1748 return ReduceJSLoadProperty(node);
1749 case IrOpcode::kJSStoreProperty:
1750 return ReduceJSStoreProperty(node);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001751 case IrOpcode::kJSInstanceOf:
1752 return ReduceJSInstanceOf(node);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001753 case IrOpcode::kJSLoadContext:
1754 return ReduceJSLoadContext(node);
1755 case IrOpcode::kJSStoreContext:
1756 return ReduceJSStoreContext(node);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001757 case IrOpcode::kJSConvertReceiver:
1758 return ReduceJSConvertReceiver(node);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001759 case IrOpcode::kJSCallConstruct:
1760 return ReduceJSCallConstruct(node);
1761 case IrOpcode::kJSCallFunction:
1762 return ReduceJSCallFunction(node);
1763 case IrOpcode::kJSForInDone:
1764 return ReduceJSForInDone(node);
1765 case IrOpcode::kJSForInNext:
1766 return ReduceJSForInNext(node);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001767 case IrOpcode::kJSForInStep:
1768 return ReduceJSForInStep(node);
1769 case IrOpcode::kSelect:
1770 return ReduceSelect(node);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001771 default:
1772 break;
1773 }
1774 return NoChange();
1775}
1776
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001777
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001778Node* JSTypedLowering::Word32Shl(Node* const lhs, int32_t const rhs) {
1779 if (rhs == 0) return lhs;
1780 return graph()->NewNode(machine()->Word32Shl(), lhs,
1781 jsgraph()->Int32Constant(rhs));
1782}
1783
1784
1785Factory* JSTypedLowering::factory() const { return jsgraph()->factory(); }
1786
1787
1788Graph* JSTypedLowering::graph() const { return jsgraph()->graph(); }
1789
1790
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001791Isolate* JSTypedLowering::isolate() const { return jsgraph()->isolate(); }
1792
1793
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001794JSOperatorBuilder* JSTypedLowering::javascript() const {
1795 return jsgraph()->javascript();
1796}
1797
1798
1799CommonOperatorBuilder* JSTypedLowering::common() const {
1800 return jsgraph()->common();
1801}
1802
1803
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001804SimplifiedOperatorBuilder* JSTypedLowering::simplified() const {
1805 return jsgraph()->simplified();
1806}
1807
1808
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001809MachineOperatorBuilder* JSTypedLowering::machine() const {
1810 return jsgraph()->machine();
1811}
1812
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001813
1814CompilationDependencies* JSTypedLowering::dependencies() const {
1815 return dependencies_;
1816}
1817
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001818} // namespace compiler
1819} // namespace internal
1820} // namespace v8