blob: 7e1a0dc24e7b0c91195e710b98f8b670fd4679da [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 Murdoch4a90d5f2016-03-22 12:00:34 +000030 void ConvertInputsToNumber(Node* frame_state) {
31 // 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
49 ? ConvertPlainPrimitiveToNumber(left())
50 : ConvertSingleInputToNumber(
51 left(), CreateFrameStateForLeftInput(frame_state));
52 right_input = right_is_primitive
53 ? ConvertPlainPrimitiveToNumber(right())
54 : 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
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000110 Reduction ChangeToStringComparisonOperator(const Operator* op,
111 bool invert = false) {
112 if (node_->op()->ControlInputCount() > 0) {
113 lowering_->RelaxControls(node_);
114 }
115 // String comparison operators need effect and control inputs, so copy them
116 // over.
117 Node* effect = NodeProperties::GetEffectInput(node_);
118 Node* control = NodeProperties::GetControlInput(node_);
119 node_->ReplaceInput(2, effect);
120 node_->ReplaceInput(3, control);
121
122 node_->TrimInputCount(4);
123 NodeProperties::ChangeOp(node_, op);
124
125 if (invert) {
126 // Insert a boolean-not to invert the value.
127 Node* value = graph()->NewNode(simplified()->BooleanNot(), node_);
128 node_->ReplaceUses(value);
129 // Note: ReplaceUses() smashes all uses, so smash it back here.
130 value->ReplaceInput(0, node_);
131 return lowering_->Replace(value);
132 }
133 return lowering_->Changed(node_);
134 }
135
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400136 Reduction ChangeToPureOperator(const Operator* op, Type* type) {
137 return ChangeToPureOperator(op, false, type);
138 }
139
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000140 bool LeftInputIs(Type* t) { return left_type()->Is(t); }
141
142 bool RightInputIs(Type* t) { return right_type()->Is(t); }
143
144 bool OneInputIs(Type* t) { return LeftInputIs(t) || RightInputIs(t); }
145
146 bool BothInputsAre(Type* t) { return LeftInputIs(t) && RightInputIs(t); }
147
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000148 bool OneInputCannotBe(Type* t) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000149 return !left_type()->Maybe(t) || !right_type()->Maybe(t);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000150 }
151
152 bool NeitherInputCanBe(Type* t) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000153 return !left_type()->Maybe(t) && !right_type()->Maybe(t);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000154 }
155
156 Node* effect() { return NodeProperties::GetEffectInput(node_); }
157 Node* control() { return NodeProperties::GetControlInput(node_); }
158 Node* context() { return NodeProperties::GetContextInput(node_); }
159 Node* left() { return NodeProperties::GetValueInput(node_, 0); }
160 Node* right() { return NodeProperties::GetValueInput(node_, 1); }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000161 Type* left_type() { return NodeProperties::GetType(node_->InputAt(0)); }
162 Type* right_type() { return NodeProperties::GetType(node_->InputAt(1)); }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000163
164 SimplifiedOperatorBuilder* simplified() { return lowering_->simplified(); }
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400165 Graph* graph() const { return lowering_->graph(); }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000166 JSGraph* jsgraph() { return lowering_->jsgraph(); }
167 JSOperatorBuilder* javascript() { return lowering_->javascript(); }
168 MachineOperatorBuilder* machine() { return lowering_->machine(); }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000169 CommonOperatorBuilder* common() { return jsgraph()->common(); }
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400170 Zone* zone() const { return graph()->zone(); }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000171
172 private:
173 JSTypedLowering* lowering_; // The containing lowering instance.
174 Node* node_; // The original node.
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000175
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000176 Node* CreateFrameStateForLeftInput(Node* frame_state) {
177 FrameStateInfo state_info = OpParameter<FrameStateInfo>(frame_state);
178
179 if (state_info.bailout_id() == BailoutId::None()) {
180 // Dummy frame state => just leave it as is.
181 return frame_state;
182 }
183
184 // If the frame state is already the right one, just return it.
185 if (state_info.state_combine().kind() == OutputFrameStateCombine::kPokeAt &&
186 state_info.state_combine().GetOffsetToPokeAt() == 1) {
187 return frame_state;
188 }
189
190 // Here, we smash the result of the conversion into the slot just below
191 // the stack top. This is the slot that full code uses to store the
192 // left operand.
193 const Operator* op = jsgraph()->common()->FrameState(
194 state_info.bailout_id(), OutputFrameStateCombine::PokeAt(1),
195 state_info.function_info());
196
197 return graph()->NewNode(op,
198 frame_state->InputAt(kFrameStateParametersInput),
199 frame_state->InputAt(kFrameStateLocalsInput),
200 frame_state->InputAt(kFrameStateStackInput),
201 frame_state->InputAt(kFrameStateContextInput),
202 frame_state->InputAt(kFrameStateFunctionInput),
203 frame_state->InputAt(kFrameStateOuterStateInput));
204 }
205
206 Node* CreateFrameStateForRightInput(Node* frame_state, Node* converted_left) {
207 FrameStateInfo state_info = OpParameter<FrameStateInfo>(frame_state);
208
209 if (state_info.bailout_id() == BailoutId::None()) {
210 // Dummy frame state => just leave it as is.
211 return frame_state;
212 }
213
214 // Create a frame state that stores the result of the operation to the
215 // top of the stack (i.e., the slot used for the right operand).
216 const Operator* op = jsgraph()->common()->FrameState(
217 state_info.bailout_id(), OutputFrameStateCombine::PokeAt(0),
218 state_info.function_info());
219
220 // Change the left operand {converted_left} on the expression stack.
221 Node* stack = frame_state->InputAt(2);
222 DCHECK_EQ(stack->opcode(), IrOpcode::kStateValues);
223 DCHECK_GE(stack->InputCount(), 2);
224
225 // TODO(jarin) Allocate in a local zone or a reusable buffer.
226 NodeVector new_values(stack->InputCount(), zone());
227 for (int i = 0; i < stack->InputCount(); i++) {
228 if (i == stack->InputCount() - 2) {
229 new_values[i] = converted_left;
230 } else {
231 new_values[i] = stack->InputAt(i);
232 }
233 }
234 Node* new_stack =
235 graph()->NewNode(stack->op(), stack->InputCount(), &new_values.front());
236
237 return graph()->NewNode(
238 op, frame_state->InputAt(kFrameStateParametersInput),
239 frame_state->InputAt(kFrameStateLocalsInput), new_stack,
240 frame_state->InputAt(kFrameStateContextInput),
241 frame_state->InputAt(kFrameStateFunctionInput),
242 frame_state->InputAt(kFrameStateOuterStateInput));
243 }
244
245 Node* ConvertPlainPrimitiveToNumber(Node* node) {
246 DCHECK(NodeProperties::GetType(node)->Is(Type::PlainPrimitive()));
247 // Avoid inserting too many eager ToNumber() operations.
248 Reduction const reduction = lowering_->ReduceJSToNumberInput(node);
249 if (reduction.Changed()) return reduction.replacement();
250 // TODO(jarin) Use PlainPrimitiveToNumber once we have it.
251 return graph()->NewNode(
252 javascript()->ToNumber(), node, jsgraph()->NoContextConstant(),
253 jsgraph()->EmptyFrameState(), graph()->start(), graph()->start());
254 }
255
256 Node* ConvertSingleInputToNumber(Node* node, Node* frame_state) {
257 DCHECK(!NodeProperties::GetType(node)->Is(Type::PlainPrimitive()));
258 Node* const n = graph()->NewNode(javascript()->ToNumber(), node, context(),
259 frame_state, effect(), control());
260 NodeProperties::ReplaceUses(node_, node_, node_, n, n);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000261 update_effect(n);
262 return n;
263 }
264
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000265 void ConvertBothInputsToNumber(Node** left_result, Node** right_result,
266 Node* frame_state) {
267 Node* projections[2];
268
269 // Find {IfSuccess} and {IfException} continuations of the operation.
270 NodeProperties::CollectControlProjections(node_, projections, 2);
271 IfExceptionHint hint = OpParameter<IfExceptionHint>(projections[1]);
272 Node* if_exception = projections[1];
273 Node* if_success = projections[0];
274
275 // Insert two ToNumber() operations that both potentially throw.
276 Node* left_state = CreateFrameStateForLeftInput(frame_state);
277 Node* left_conv =
278 graph()->NewNode(javascript()->ToNumber(), left(), context(),
279 left_state, effect(), control());
280 Node* left_success = graph()->NewNode(common()->IfSuccess(), left_conv);
281 Node* right_state = CreateFrameStateForRightInput(frame_state, left_conv);
282 Node* right_conv =
283 graph()->NewNode(javascript()->ToNumber(), right(), context(),
284 right_state, left_conv, left_success);
285 Node* left_exception =
286 graph()->NewNode(common()->IfException(hint), left_conv, left_conv);
287 Node* right_exception =
288 graph()->NewNode(common()->IfException(hint), right_conv, right_conv);
289 NodeProperties::ReplaceControlInput(if_success, right_conv);
290 update_effect(right_conv);
291
292 // Wire conversions to existing {IfException} continuation.
293 Node* exception_merge = if_exception;
294 Node* exception_value =
295 graph()->NewNode(common()->Phi(MachineRepresentation::kTagged, 2),
296 left_exception, right_exception, exception_merge);
297 Node* exception_effect =
298 graph()->NewNode(common()->EffectPhi(2), left_exception,
299 right_exception, exception_merge);
300 for (Edge edge : exception_merge->use_edges()) {
301 if (NodeProperties::IsEffectEdge(edge)) edge.UpdateTo(exception_effect);
302 if (NodeProperties::IsValueEdge(edge)) edge.UpdateTo(exception_value);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400303 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000304 NodeProperties::RemoveType(exception_merge);
305 exception_merge->ReplaceInput(0, left_exception);
306 exception_merge->ReplaceInput(1, right_exception);
307 NodeProperties::ChangeOp(exception_merge, common()->Merge(2));
308
309 *left_result = left_conv;
310 *right_result = right_conv;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000311 }
312
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400313 Node* ConvertToUI32(Node* node, Signedness signedness) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000314 // Avoid introducing too many eager NumberToXXnt32() operations.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000315 Type* type = NodeProperties::GetType(node);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400316 if (signedness == kSigned) {
317 if (!type->Is(Type::Signed32())) {
318 node = graph()->NewNode(simplified()->NumberToInt32(), node);
319 }
320 } else {
321 DCHECK_EQ(kUnsigned, signedness);
322 if (!type->Is(Type::Unsigned32())) {
323 node = graph()->NewNode(simplified()->NumberToUint32(), node);
324 }
325 }
326 return node;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000327 }
328
329 void update_effect(Node* effect) {
330 NodeProperties::ReplaceEffectInput(node_, effect);
331 }
332};
333
334
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000335// TODO(turbofan): js-typed-lowering improvements possible
336// - immediately put in type bounds for all new nodes
337// - relax effects from generic but not-side-effecting operations
338
339
340JSTypedLowering::JSTypedLowering(Editor* editor,
341 CompilationDependencies* dependencies,
342 Flags flags, JSGraph* jsgraph, Zone* zone)
343 : AdvancedReducer(editor),
344 dependencies_(dependencies),
345 flags_(flags),
346 jsgraph_(jsgraph),
347 true_type_(Type::Constant(factory()->true_value(), graph()->zone())),
348 false_type_(Type::Constant(factory()->false_value(), graph()->zone())),
349 the_hole_type_(
350 Type::Constant(factory()->the_hole_value(), graph()->zone())),
351 type_cache_(TypeCache::Get()) {
352 for (size_t k = 0; k < arraysize(shifted_int32_ranges_); ++k) {
353 double min = kMinInt / (1 << k);
354 double max = kMaxInt / (1 << k);
355 shifted_int32_ranges_[k] = Type::Range(min, max, graph()->zone());
356 }
357}
358
359
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000360Reduction JSTypedLowering::ReduceJSAdd(Node* node) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000361 if (flags() & kDisableBinaryOpReduction) return NoChange();
362
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000363 JSBinopReduction r(this, node);
364 if (r.BothInputsAre(Type::Number())) {
365 // JSAdd(x:number, y:number) => NumberAdd(x, y)
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400366 return r.ChangeToPureOperator(simplified()->NumberAdd(), Type::Number());
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000367 }
Ben Murdoch097c5b22016-05-18 11:27:45 +0100368 if (r.NeitherInputCanBe(Type::StringOrReceiver())) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000369 // JSAdd(x:-string, y:-string) => NumberAdd(ToNumber(x), ToNumber(y))
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000370 Node* frame_state = NodeProperties::GetFrameStateInput(node, 1);
371 r.ConvertInputsToNumber(frame_state);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400372 return r.ChangeToPureOperator(simplified()->NumberAdd(), Type::Number());
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000373 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000374 if (r.BothInputsAre(Type::String())) {
375 // JSAdd(x:string, y:string) => CallStub[StringAdd](x, y)
376 Callable const callable =
377 CodeFactory::StringAdd(isolate(), STRING_ADD_CHECK_NONE, NOT_TENURED);
378 CallDescriptor const* const desc = Linkage::GetStubCallDescriptor(
379 isolate(), graph()->zone(), callable.descriptor(), 0,
380 CallDescriptor::kNeedsFrameState, node->op()->properties());
381 DCHECK_EQ(2, OperatorProperties::GetFrameStateInputCount(node->op()));
382 node->RemoveInput(NodeProperties::FirstFrameStateIndex(node) + 1);
383 node->InsertInput(graph()->zone(), 0,
384 jsgraph()->HeapConstant(callable.code()));
385 NodeProperties::ChangeOp(node, common()->Call(desc));
386 return Changed(node);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400387 }
388 return NoChange();
389}
390
391
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000392Reduction JSTypedLowering::ReduceJSModulus(Node* node) {
393 if (flags() & kDisableBinaryOpReduction) return NoChange();
394
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400395 JSBinopReduction r(this, node);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000396 if (r.BothInputsAre(Type::Number())) {
397 // JSModulus(x:number, x:number) => NumberModulus(x, y)
398 return r.ChangeToPureOperator(simplified()->NumberModulus(),
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400399 Type::Number());
400 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400401 return NoChange();
402}
403
404
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000405Reduction JSTypedLowering::ReduceNumberBinop(Node* node,
406 const Operator* numberOp) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000407 if (flags() & kDisableBinaryOpReduction) return NoChange();
408
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000409 JSBinopReduction r(this, node);
Ben Murdoch097c5b22016-05-18 11:27:45 +0100410 if (numberOp == simplified()->NumberModulus()) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000411 if (r.BothInputsAre(Type::Number())) {
412 return r.ChangeToPureOperator(numberOp, Type::Number());
413 }
414 return NoChange();
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400415 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000416 Node* frame_state = NodeProperties::GetFrameStateInput(node, 1);
417 r.ConvertInputsToNumber(frame_state);
418 return r.ChangeToPureOperator(numberOp, Type::Number());
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000419}
420
421
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400422Reduction JSTypedLowering::ReduceInt32Binop(Node* node, const Operator* intOp) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000423 if (flags() & kDisableBinaryOpReduction) return NoChange();
424
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000425 JSBinopReduction r(this, node);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000426 Node* frame_state = NodeProperties::GetFrameStateInput(node, 1);
427 r.ConvertInputsToNumber(frame_state);
428 r.ConvertInputsToUI32(kSigned, kSigned);
429 return r.ChangeToPureOperator(intOp, Type::Integral32());
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000430}
431
432
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400433Reduction JSTypedLowering::ReduceUI32Shift(Node* node,
434 Signedness left_signedness,
435 const Operator* shift_op) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000436 if (flags() & kDisableBinaryOpReduction) return NoChange();
437
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000438 JSBinopReduction r(this, node);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000439 Node* frame_state = NodeProperties::GetFrameStateInput(node, 1);
440 r.ConvertInputsToNumber(frame_state);
441 r.ConvertInputsToUI32(left_signedness, kUnsigned);
442 return r.ChangeToPureOperator(shift_op);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000443}
444
445
446Reduction JSTypedLowering::ReduceJSComparison(Node* node) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000447 if (flags() & kDisableBinaryOpReduction) return NoChange();
448
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000449 JSBinopReduction r(this, node);
450 if (r.BothInputsAre(Type::String())) {
451 // If both inputs are definitely strings, perform a string comparison.
452 const Operator* stringOp;
453 switch (node->opcode()) {
454 case IrOpcode::kJSLessThan:
455 stringOp = simplified()->StringLessThan();
456 break;
457 case IrOpcode::kJSGreaterThan:
458 stringOp = simplified()->StringLessThan();
459 r.SwapInputs(); // a > b => b < a
460 break;
461 case IrOpcode::kJSLessThanOrEqual:
462 stringOp = simplified()->StringLessThanOrEqual();
463 break;
464 case IrOpcode::kJSGreaterThanOrEqual:
465 stringOp = simplified()->StringLessThanOrEqual();
466 r.SwapInputs(); // a >= b => b <= a
467 break;
468 default:
469 return NoChange();
470 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000471 r.ChangeToStringComparisonOperator(stringOp);
472 return Changed(node);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000473 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000474 if (r.OneInputCannotBe(Type::StringOrReceiver())) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000475 const Operator* less_than;
476 const Operator* less_than_or_equal;
477 if (r.BothInputsAre(Type::Unsigned32())) {
478 less_than = machine()->Uint32LessThan();
479 less_than_or_equal = machine()->Uint32LessThanOrEqual();
480 } else if (r.BothInputsAre(Type::Signed32())) {
481 less_than = machine()->Int32LessThan();
482 less_than_or_equal = machine()->Int32LessThanOrEqual();
483 } else {
484 // TODO(turbofan): mixed signed/unsigned int32 comparisons.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000485 Node* frame_state = NodeProperties::GetFrameStateInput(node, 1);
486 r.ConvertInputsToNumber(frame_state);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000487 less_than = simplified()->NumberLessThan();
488 less_than_or_equal = simplified()->NumberLessThanOrEqual();
489 }
490 const Operator* comparison;
491 switch (node->opcode()) {
492 case IrOpcode::kJSLessThan:
493 comparison = less_than;
494 break;
495 case IrOpcode::kJSGreaterThan:
496 comparison = less_than;
497 r.SwapInputs(); // a > b => b < a
498 break;
499 case IrOpcode::kJSLessThanOrEqual:
500 comparison = less_than_or_equal;
501 break;
502 case IrOpcode::kJSGreaterThanOrEqual:
503 comparison = less_than_or_equal;
504 r.SwapInputs(); // a >= b => b <= a
505 break;
506 default:
507 return NoChange();
508 }
509 return r.ChangeToPureOperator(comparison);
510 }
511 // TODO(turbofan): relax/remove effects of this operator in other cases.
512 return NoChange(); // Keep a generic comparison.
513}
514
515
516Reduction JSTypedLowering::ReduceJSEqual(Node* node, bool invert) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000517 if (flags() & kDisableBinaryOpReduction) return NoChange();
518
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000519 JSBinopReduction r(this, node);
520
521 if (r.BothInputsAre(Type::Number())) {
522 return r.ChangeToPureOperator(simplified()->NumberEqual(), invert);
523 }
524 if (r.BothInputsAre(Type::String())) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000525 return r.ChangeToStringComparisonOperator(simplified()->StringEqual(),
526 invert);
527 }
528 if (r.BothInputsAre(Type::Boolean())) {
529 return r.ChangeToPureOperator(simplified()->ReferenceEqual(Type::Boolean()),
530 invert);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000531 }
532 if (r.BothInputsAre(Type::Receiver())) {
533 return r.ChangeToPureOperator(
534 simplified()->ReferenceEqual(Type::Receiver()), invert);
535 }
Ben Murdochda12d292016-06-02 14:46:10 +0100536 if (r.OneInputIs(Type::Undetectable())) {
537 RelaxEffectsAndControls(node);
538 node->RemoveInput(r.LeftInputIs(Type::Undetectable()) ? 0 : 1);
539 node->TrimInputCount(1);
540 NodeProperties::ChangeOp(node, simplified()->ObjectIsUndetectable());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000541 if (invert) {
542 // Insert an boolean not to invert the value.
543 Node* value = graph()->NewNode(simplified()->BooleanNot(), node);
544 node->ReplaceUses(value);
545 // Note: ReplaceUses() smashes all uses, so smash it back here.
546 value->ReplaceInput(0, node);
547 return Replace(value);
548 }
549 return Changed(node);
550 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000551 return NoChange();
552}
553
554
555Reduction JSTypedLowering::ReduceJSStrictEqual(Node* node, bool invert) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000556 if (flags() & kDisableBinaryOpReduction) return NoChange();
557
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000558 JSBinopReduction r(this, node);
559 if (r.left() == r.right()) {
560 // x === x is always true if x != NaN
561 if (!r.left_type()->Maybe(Type::NaN())) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000562 Node* replacement = jsgraph()->BooleanConstant(!invert);
563 ReplaceWithValue(node, replacement);
564 return Replace(replacement);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000565 }
566 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400567 if (r.OneInputCannotBe(Type::NumberOrString())) {
568 // For values with canonical representation (i.e. not string nor number) an
569 // empty type intersection means the values cannot be strictly equal.
570 if (!r.left_type()->Maybe(r.right_type())) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000571 Node* replacement = jsgraph()->BooleanConstant(invert);
572 ReplaceWithValue(node, replacement);
573 return Replace(replacement);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000574 }
575 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000576 if (r.OneInputIs(the_hole_type_)) {
577 return r.ChangeToPureOperator(simplified()->ReferenceEqual(the_hole_type_),
578 invert);
579 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000580 if (r.OneInputIs(Type::Undefined())) {
581 return r.ChangeToPureOperator(
582 simplified()->ReferenceEqual(Type::Undefined()), invert);
583 }
584 if (r.OneInputIs(Type::Null())) {
585 return r.ChangeToPureOperator(simplified()->ReferenceEqual(Type::Null()),
586 invert);
587 }
588 if (r.OneInputIs(Type::Boolean())) {
589 return r.ChangeToPureOperator(simplified()->ReferenceEqual(Type::Boolean()),
590 invert);
591 }
592 if (r.OneInputIs(Type::Object())) {
593 return r.ChangeToPureOperator(simplified()->ReferenceEqual(Type::Object()),
594 invert);
595 }
596 if (r.OneInputIs(Type::Receiver())) {
597 return r.ChangeToPureOperator(
598 simplified()->ReferenceEqual(Type::Receiver()), invert);
599 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000600 if (r.BothInputsAre(Type::Unique())) {
601 return r.ChangeToPureOperator(simplified()->ReferenceEqual(Type::Unique()),
602 invert);
603 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000604 if (r.BothInputsAre(Type::String())) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000605 return r.ChangeToStringComparisonOperator(simplified()->StringEqual(),
606 invert);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000607 }
608 if (r.BothInputsAre(Type::Number())) {
609 return r.ChangeToPureOperator(simplified()->NumberEqual(), invert);
610 }
611 // TODO(turbofan): js-typed-lowering of StrictEqual(mixed types)
612 return NoChange();
613}
614
615
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000616Reduction JSTypedLowering::ReduceJSToBoolean(Node* node) {
617 Node* const input = node->InputAt(0);
618 Type* const input_type = NodeProperties::GetType(input);
619 Node* const effect = NodeProperties::GetEffectInput(node);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400620 if (input_type->Is(Type::Boolean())) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000621 // JSToBoolean(x:boolean) => x
622 ReplaceWithValue(node, input, effect);
623 return Replace(input);
624 } else if (input_type->Is(Type::OrderedNumber())) {
625 // JSToBoolean(x:ordered-number) => BooleanNot(NumberEqual(x,#0))
626 RelaxEffectsAndControls(node);
627 node->ReplaceInput(0, graph()->NewNode(simplified()->NumberEqual(), input,
628 jsgraph()->ZeroConstant()));
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400629 node->TrimInputCount(1);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000630 NodeProperties::ChangeOp(node, simplified()->BooleanNot());
631 return Changed(node);
632 } else if (input_type->Is(Type::String())) {
633 // JSToBoolean(x:string) => NumberLessThan(#0,x.length)
634 FieldAccess const access = AccessBuilder::ForStringLength();
635 Node* length = graph()->NewNode(simplified()->LoadField(access), input,
636 effect, graph()->start());
637 ReplaceWithValue(node, node, length);
638 node->ReplaceInput(0, jsgraph()->ZeroConstant());
639 node->ReplaceInput(1, length);
640 node->TrimInputCount(2);
641 NodeProperties::ChangeOp(node, simplified()->NumberLessThan());
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400642 return Changed(node);
643 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000644 return NoChange();
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400645}
646
Ben Murdochda12d292016-06-02 14:46:10 +0100647Reduction JSTypedLowering::ReduceJSToInteger(Node* node) {
648 Node* const input = NodeProperties::GetValueInput(node, 0);
649 Type* const input_type = NodeProperties::GetType(input);
650 if (input_type->Is(type_cache_.kIntegerOrMinusZero)) {
651 // JSToInteger(x:integer) => x
652 ReplaceWithValue(node, input);
653 return Replace(input);
654 }
655 return NoChange();
656}
657
658Reduction JSTypedLowering::ReduceJSToLength(Node* node) {
659 Node* input = NodeProperties::GetValueInput(node, 0);
660 Type* input_type = NodeProperties::GetType(input);
661 if (input_type->Is(type_cache_.kIntegerOrMinusZero)) {
662 if (input_type->Max() <= 0.0) {
663 input = jsgraph()->ZeroConstant();
664 } else if (input_type->Min() >= kMaxSafeInteger) {
665 input = jsgraph()->Constant(kMaxSafeInteger);
666 } else {
667 if (input_type->Min() <= 0.0) {
668 input = graph()->NewNode(
669 common()->Select(MachineRepresentation::kTagged),
670 graph()->NewNode(simplified()->NumberLessThanOrEqual(), input,
671 jsgraph()->ZeroConstant()),
672 jsgraph()->ZeroConstant(), input);
673 input_type = Type::Range(0.0, input_type->Max(), graph()->zone());
674 NodeProperties::SetType(input, input_type);
675 }
676 if (input_type->Max() > kMaxSafeInteger) {
677 input = graph()->NewNode(
678 common()->Select(MachineRepresentation::kTagged),
679 graph()->NewNode(simplified()->NumberLessThanOrEqual(),
680 jsgraph()->Constant(kMaxSafeInteger), input),
681 jsgraph()->Constant(kMaxSafeInteger), input);
682 input_type =
683 Type::Range(input_type->Min(), kMaxSafeInteger, graph()->zone());
684 NodeProperties::SetType(input, input_type);
685 }
686 }
687 ReplaceWithValue(node, input);
688 return Replace(input);
689 }
690 return NoChange();
691}
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400692
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000693Reduction JSTypedLowering::ReduceJSToNumberInput(Node* input) {
694 if (input->opcode() == IrOpcode::kJSToNumber) {
695 // Recursively try to reduce the input first.
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400696 Reduction result = ReduceJSToNumber(input);
697 if (result.Changed()) return result;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000698 return Changed(input); // JSToNumber(JSToNumber(x)) => JSToNumber(x)
699 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000700 // Check for ToNumber truncation of signaling NaN to undefined mapping.
701 if (input->opcode() == IrOpcode::kSelect) {
702 Node* check = NodeProperties::GetValueInput(input, 0);
703 Node* vtrue = NodeProperties::GetValueInput(input, 1);
704 Type* vtrue_type = NodeProperties::GetType(vtrue);
705 Node* vfalse = NodeProperties::GetValueInput(input, 2);
706 Type* vfalse_type = NodeProperties::GetType(vfalse);
707 if (vtrue_type->Is(Type::Undefined()) && vfalse_type->Is(Type::Number())) {
708 if (check->opcode() == IrOpcode::kNumberIsHoleNaN &&
709 check->InputAt(0) == vfalse) {
710 // JSToNumber(Select(NumberIsHoleNaN(x), y:undefined, x:number)) => x
711 return Replace(vfalse);
712 }
713 }
714 }
Ben Murdoch097c5b22016-05-18 11:27:45 +0100715 // Try constant-folding of JSToNumber with constant inputs.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000716 Type* input_type = NodeProperties::GetType(input);
Ben Murdoch097c5b22016-05-18 11:27:45 +0100717 if (input_type->IsConstant()) {
718 Handle<Object> input_value = input_type->AsConstant()->Value();
719 if (input_value->IsString()) {
720 return Replace(jsgraph()->Constant(
721 String::ToNumber(Handle<String>::cast(input_value))));
722 } else if (input_value->IsOddball()) {
723 return Replace(jsgraph()->Constant(
724 Oddball::ToNumber(Handle<Oddball>::cast(input_value))));
725 }
726 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000727 if (input_type->Is(Type::Number())) {
728 // JSToNumber(x:number) => x
729 return Changed(input);
730 }
731 if (input_type->Is(Type::Undefined())) {
732 // JSToNumber(undefined) => #NaN
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400733 return Replace(jsgraph()->NaNConstant());
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000734 }
735 if (input_type->Is(Type::Null())) {
736 // JSToNumber(null) => #0
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400737 return Replace(jsgraph()->ZeroConstant());
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000738 }
739 if (input_type->Is(Type::Boolean())) {
740 // JSToNumber(x:boolean) => BooleanToNumber(x)
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400741 return Replace(graph()->NewNode(simplified()->BooleanToNumber(), input));
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000742 }
Ben Murdochda12d292016-06-02 14:46:10 +0100743 if (input_type->Is(Type::String())) {
744 // JSToNumber(x:string) => StringToNumber(x)
745 return Replace(graph()->NewNode(simplified()->StringToNumber(), input));
746 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000747 return NoChange();
748}
749
750
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400751Reduction JSTypedLowering::ReduceJSToNumber(Node* node) {
752 // Try to reduce the input first.
753 Node* const input = node->InputAt(0);
754 Reduction reduction = ReduceJSToNumberInput(input);
755 if (reduction.Changed()) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000756 ReplaceWithValue(node, reduction.replacement());
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400757 return reduction;
758 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000759 Type* const input_type = NodeProperties::GetType(input);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400760 if (input_type->Is(Type::PlainPrimitive())) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000761 if (NodeProperties::GetContextInput(node) !=
762 jsgraph()->NoContextConstant() ||
763 NodeProperties::GetEffectInput(node) != graph()->start() ||
764 NodeProperties::GetControlInput(node) != graph()->start()) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400765 // JSToNumber(x:plain-primitive,context,effect,control)
766 // => JSToNumber(x,no-context,start,start)
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000767 RelaxEffectsAndControls(node);
768 NodeProperties::ReplaceContextInput(node, jsgraph()->NoContextConstant());
769 NodeProperties::ReplaceControlInput(node, graph()->start());
770 NodeProperties::ReplaceEffectInput(node, graph()->start());
771 DCHECK_EQ(1, OperatorProperties::GetFrameStateInputCount(node->op()));
772 NodeProperties::ReplaceFrameStateInput(node, 0,
773 jsgraph()->EmptyFrameState());
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400774 return Changed(node);
775 }
776 }
777 return NoChange();
778}
779
780
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000781Reduction JSTypedLowering::ReduceJSToStringInput(Node* input) {
782 if (input->opcode() == IrOpcode::kJSToString) {
783 // Recursively try to reduce the input first.
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400784 Reduction result = ReduceJSToString(input);
785 if (result.Changed()) return result;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000786 return Changed(input); // JSToString(JSToString(x)) => JSToString(x)
787 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000788 Type* input_type = NodeProperties::GetType(input);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000789 if (input_type->Is(Type::String())) {
790 return Changed(input); // JSToString(x:string) => x
791 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000792 if (input_type->Is(Type::Boolean())) {
793 return Replace(graph()->NewNode(
794 common()->Select(MachineRepresentation::kTagged), input,
795 jsgraph()->HeapConstant(factory()->true_string()),
796 jsgraph()->HeapConstant(factory()->false_string())));
797 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000798 if (input_type->Is(Type::Undefined())) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400799 return Replace(jsgraph()->HeapConstant(factory()->undefined_string()));
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000800 }
801 if (input_type->Is(Type::Null())) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400802 return Replace(jsgraph()->HeapConstant(factory()->null_string()));
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000803 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000804 // TODO(turbofan): js-typed-lowering of ToString(x:number)
805 return NoChange();
806}
807
808
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400809Reduction JSTypedLowering::ReduceJSToString(Node* node) {
810 // Try to reduce the input first.
811 Node* const input = node->InputAt(0);
812 Reduction reduction = ReduceJSToStringInput(input);
813 if (reduction.Changed()) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000814 ReplaceWithValue(node, reduction.replacement());
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400815 return reduction;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000816 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000817 return NoChange();
818}
819
820
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000821Reduction JSTypedLowering::ReduceJSToObject(Node* node) {
822 DCHECK_EQ(IrOpcode::kJSToObject, node->opcode());
823 Node* receiver = NodeProperties::GetValueInput(node, 0);
824 Type* receiver_type = NodeProperties::GetType(receiver);
825 Node* context = NodeProperties::GetContextInput(node);
826 Node* frame_state = NodeProperties::GetFrameStateInput(node, 0);
827 Node* effect = NodeProperties::GetEffectInput(node);
828 Node* control = NodeProperties::GetControlInput(node);
829 if (!receiver_type->Is(Type::Receiver())) {
830 // TODO(bmeurer/mstarzinger): Add support for lowering inside try blocks.
831 if (receiver_type->Maybe(Type::NullOrUndefined()) &&
832 NodeProperties::IsExceptionalCall(node)) {
833 // ToObject throws for null or undefined inputs.
834 return NoChange();
835 }
836
837 // Check whether {receiver} is a Smi.
838 Node* check0 = graph()->NewNode(simplified()->ObjectIsSmi(), receiver);
839 Node* branch0 =
840 graph()->NewNode(common()->Branch(BranchHint::kFalse), check0, control);
841 Node* if_true0 = graph()->NewNode(common()->IfTrue(), branch0);
842 Node* etrue0 = effect;
843
844 Node* if_false0 = graph()->NewNode(common()->IfFalse(), branch0);
845 Node* efalse0 = effect;
846
847 // Determine the instance type of {receiver}.
848 Node* receiver_map = efalse0 =
849 graph()->NewNode(simplified()->LoadField(AccessBuilder::ForMap()),
850 receiver, efalse0, if_false0);
851 Node* receiver_instance_type = efalse0 = graph()->NewNode(
852 simplified()->LoadField(AccessBuilder::ForMapInstanceType()),
853 receiver_map, efalse0, if_false0);
854
855 // Check whether {receiver} is a spec object.
856 STATIC_ASSERT(LAST_JS_RECEIVER_TYPE == LAST_TYPE);
857 Node* check1 =
858 graph()->NewNode(machine()->Uint32LessThanOrEqual(),
859 jsgraph()->Uint32Constant(FIRST_JS_RECEIVER_TYPE),
860 receiver_instance_type);
861 Node* branch1 = graph()->NewNode(common()->Branch(BranchHint::kTrue),
862 check1, if_false0);
863 Node* if_true1 = graph()->NewNode(common()->IfTrue(), branch1);
864 Node* etrue1 = efalse0;
865
866 Node* if_false1 = graph()->NewNode(common()->IfFalse(), branch1);
867 Node* efalse1 = efalse0;
868
869 // Convert {receiver} using the ToObjectStub.
870 Node* if_convert =
871 graph()->NewNode(common()->Merge(2), if_true0, if_false1);
872 Node* econvert =
873 graph()->NewNode(common()->EffectPhi(2), etrue0, efalse1, if_convert);
874 Node* rconvert;
875 {
876 Callable callable = CodeFactory::ToObject(isolate());
877 CallDescriptor const* const desc = Linkage::GetStubCallDescriptor(
878 isolate(), graph()->zone(), callable.descriptor(), 0,
879 CallDescriptor::kNeedsFrameState, node->op()->properties());
880 rconvert = econvert = graph()->NewNode(
881 common()->Call(desc), jsgraph()->HeapConstant(callable.code()),
882 receiver, context, frame_state, econvert, if_convert);
883 }
884
885 // The {receiver} is already a spec object.
886 Node* if_done = if_true1;
887 Node* edone = etrue1;
888 Node* rdone = receiver;
889
890 control = graph()->NewNode(common()->Merge(2), if_convert, if_done);
891 effect = graph()->NewNode(common()->EffectPhi(2), econvert, edone, control);
892 receiver =
893 graph()->NewNode(common()->Phi(MachineRepresentation::kTagged, 2),
894 rconvert, rdone, control);
895 }
896 ReplaceWithValue(node, receiver, effect, control);
897 return Changed(receiver);
898}
899
900
901Reduction JSTypedLowering::ReduceJSLoadNamed(Node* node) {
902 DCHECK_EQ(IrOpcode::kJSLoadNamed, node->opcode());
903 Node* receiver = NodeProperties::GetValueInput(node, 0);
904 Type* receiver_type = NodeProperties::GetType(receiver);
905 Node* effect = NodeProperties::GetEffectInput(node);
906 Node* control = NodeProperties::GetControlInput(node);
907 Handle<Name> name = NamedAccessOf(node->op()).name();
908 // Optimize "length" property of strings.
909 if (name.is_identical_to(factory()->length_string()) &&
910 receiver_type->Is(Type::String())) {
911 Node* value = effect = graph()->NewNode(
912 simplified()->LoadField(AccessBuilder::ForStringLength()), receiver,
913 effect, control);
914 ReplaceWithValue(node, value, effect);
915 return Replace(value);
916 }
917 // Optimize "prototype" property of functions.
918 if (name.is_identical_to(factory()->prototype_string()) &&
919 receiver_type->IsConstant() &&
920 receiver_type->AsConstant()->Value()->IsJSFunction()) {
921 // TODO(turbofan): This lowering might not kick in if we ever lower
922 // the C++ accessor for "prototype" in an earlier optimization pass.
923 Handle<JSFunction> function =
924 Handle<JSFunction>::cast(receiver_type->AsConstant()->Value());
925 if (function->has_initial_map()) {
926 // We need to add a code dependency on the initial map of the {function}
927 // in order to be notified about changes to the "prototype" of {function},
928 // so it doesn't make sense to continue unless deoptimization is enabled.
929 if (!(flags() & kDeoptimizationEnabled)) return NoChange();
930 Handle<Map> initial_map(function->initial_map(), isolate());
931 dependencies()->AssumeInitialMapCantChange(initial_map);
932 Node* value =
933 jsgraph()->Constant(handle(initial_map->prototype(), isolate()));
934 ReplaceWithValue(node, value);
935 return Replace(value);
936 }
937 }
938 return NoChange();
939}
940
941
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000942Reduction JSTypedLowering::ReduceJSLoadProperty(Node* node) {
943 Node* key = NodeProperties::GetValueInput(node, 1);
944 Node* base = NodeProperties::GetValueInput(node, 0);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000945 Type* key_type = NodeProperties::GetType(key);
946 HeapObjectMatcher mbase(base);
947 if (mbase.HasValue() && mbase.Value()->IsJSTypedArray()) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400948 Handle<JSTypedArray> const array =
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000949 Handle<JSTypedArray>::cast(mbase.Value());
950 if (!array->GetBuffer()->was_neutered()) {
951 array->GetBuffer()->set_is_neuterable(false);
952 BufferAccess const access(array->type());
953 size_t const k =
954 ElementSizeLog2Of(access.machine_type().representation());
955 double const byte_length = array->byte_length()->Number();
956 CHECK_LT(k, arraysize(shifted_int32_ranges_));
957 if (key_type->Is(shifted_int32_ranges_[k]) && byte_length <= kMaxInt) {
958 // JSLoadProperty(typed-array, int32)
959 Handle<FixedTypedArrayBase> elements =
960 Handle<FixedTypedArrayBase>::cast(handle(array->elements()));
961 Node* buffer = jsgraph()->PointerConstant(elements->external_pointer());
962 Node* length = jsgraph()->Constant(byte_length);
963 Node* effect = NodeProperties::GetEffectInput(node);
964 Node* control = NodeProperties::GetControlInput(node);
965 // Check if we can avoid the bounds check.
966 if (key_type->Min() >= 0 && key_type->Max() < array->length_value()) {
967 Node* load = graph()->NewNode(
968 simplified()->LoadElement(
969 AccessBuilder::ForTypedArrayElement(array->type(), true)),
970 buffer, key, effect, control);
971 ReplaceWithValue(node, load, load);
972 return Replace(load);
973 }
974 // Compute byte offset.
975 Node* offset = Word32Shl(key, static_cast<int>(k));
976 Node* load = graph()->NewNode(simplified()->LoadBuffer(access), buffer,
977 offset, length, effect, control);
978 ReplaceWithValue(node, load, load);
979 return Replace(load);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400980 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000981 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000982 }
983 return NoChange();
984}
985
986
987Reduction JSTypedLowering::ReduceJSStoreProperty(Node* node) {
988 Node* key = NodeProperties::GetValueInput(node, 1);
989 Node* base = NodeProperties::GetValueInput(node, 0);
990 Node* value = NodeProperties::GetValueInput(node, 2);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000991 Type* key_type = NodeProperties::GetType(key);
992 Type* value_type = NodeProperties::GetType(value);
993 HeapObjectMatcher mbase(base);
994 if (mbase.HasValue() && mbase.Value()->IsJSTypedArray()) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400995 Handle<JSTypedArray> const array =
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000996 Handle<JSTypedArray>::cast(mbase.Value());
997 if (!array->GetBuffer()->was_neutered()) {
998 array->GetBuffer()->set_is_neuterable(false);
999 BufferAccess const access(array->type());
1000 size_t const k =
1001 ElementSizeLog2Of(access.machine_type().representation());
1002 double const byte_length = array->byte_length()->Number();
1003 CHECK_LT(k, arraysize(shifted_int32_ranges_));
1004 if (access.external_array_type() != kExternalUint8ClampedArray &&
1005 key_type->Is(shifted_int32_ranges_[k]) && byte_length <= kMaxInt) {
1006 // JSLoadProperty(typed-array, int32)
1007 Handle<FixedTypedArrayBase> elements =
1008 Handle<FixedTypedArrayBase>::cast(handle(array->elements()));
1009 Node* buffer = jsgraph()->PointerConstant(elements->external_pointer());
1010 Node* length = jsgraph()->Constant(byte_length);
1011 Node* context = NodeProperties::GetContextInput(node);
1012 Node* effect = NodeProperties::GetEffectInput(node);
1013 Node* control = NodeProperties::GetControlInput(node);
1014 // Convert to a number first.
1015 if (!value_type->Is(Type::Number())) {
1016 Reduction number_reduction = ReduceJSToNumberInput(value);
1017 if (number_reduction.Changed()) {
1018 value = number_reduction.replacement();
1019 } else {
1020 Node* frame_state_for_to_number =
1021 NodeProperties::GetFrameStateInput(node, 1);
1022 value = effect =
1023 graph()->NewNode(javascript()->ToNumber(), value, context,
1024 frame_state_for_to_number, effect, control);
1025 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001026 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001027 // Check if we can avoid the bounds check.
1028 if (key_type->Min() >= 0 && key_type->Max() < array->length_value()) {
1029 RelaxControls(node);
1030 node->ReplaceInput(0, buffer);
1031 DCHECK_EQ(key, node->InputAt(1));
1032 node->ReplaceInput(2, value);
1033 node->ReplaceInput(3, effect);
1034 node->ReplaceInput(4, control);
1035 node->TrimInputCount(5);
1036 NodeProperties::ChangeOp(
1037 node,
1038 simplified()->StoreElement(
1039 AccessBuilder::ForTypedArrayElement(array->type(), true)));
1040 return Changed(node);
1041 }
1042 // Compute byte offset.
1043 Node* offset = Word32Shl(key, static_cast<int>(k));
1044 // Turn into a StoreBuffer operation.
1045 RelaxControls(node);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001046 node->ReplaceInput(0, buffer);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001047 node->ReplaceInput(1, offset);
1048 node->ReplaceInput(2, length);
1049 node->ReplaceInput(3, value);
1050 node->ReplaceInput(4, effect);
1051 node->ReplaceInput(5, control);
1052 node->TrimInputCount(6);
1053 NodeProperties::ChangeOp(node, simplified()->StoreBuffer(access));
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001054 return Changed(node);
1055 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001056 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001057 }
1058 return NoChange();
1059}
1060
1061
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001062Reduction JSTypedLowering::ReduceJSInstanceOf(Node* node) {
1063 DCHECK_EQ(IrOpcode::kJSInstanceOf, node->opcode());
1064 Node* const context = NodeProperties::GetContextInput(node);
1065 Node* const frame_state = NodeProperties::GetFrameStateInput(node, 0);
1066
1067 // If deoptimization is disabled, we cannot optimize.
1068 if (!(flags() & kDeoptimizationEnabled) ||
1069 (flags() & kDisableBinaryOpReduction)) {
1070 return NoChange();
1071 }
1072
1073 // If we are in a try block, don't optimize since the runtime call
1074 // in the proxy case can throw.
1075 if (NodeProperties::IsExceptionalCall(node)) return NoChange();
1076
1077 JSBinopReduction r(this, node);
1078 Node* effect = r.effect();
1079 Node* control = r.control();
1080
1081 if (!r.right_type()->IsConstant() ||
1082 !r.right_type()->AsConstant()->Value()->IsJSFunction()) {
1083 return NoChange();
1084 }
1085
1086 Handle<JSFunction> function =
1087 Handle<JSFunction>::cast(r.right_type()->AsConstant()->Value());
1088 Handle<SharedFunctionInfo> shared(function->shared(), isolate());
1089
1090 if (!function->IsConstructor() ||
1091 function->map()->has_non_instance_prototype()) {
1092 return NoChange();
1093 }
1094
1095 JSFunction::EnsureHasInitialMap(function);
1096 DCHECK(function->has_initial_map());
1097 Handle<Map> initial_map(function->initial_map(), isolate());
1098 this->dependencies()->AssumeInitialMapCantChange(initial_map);
1099 Node* prototype =
1100 jsgraph()->Constant(handle(initial_map->prototype(), isolate()));
1101
1102 Node* if_is_smi = nullptr;
1103 Node* e_is_smi = nullptr;
1104 // If the left hand side is an object, no smi check is needed.
1105 if (r.left_type()->Maybe(Type::TaggedSigned())) {
1106 Node* is_smi = graph()->NewNode(simplified()->ObjectIsSmi(), r.left());
1107 Node* branch_is_smi =
1108 graph()->NewNode(common()->Branch(BranchHint::kFalse), is_smi, control);
1109 if_is_smi = graph()->NewNode(common()->IfTrue(), branch_is_smi);
1110 e_is_smi = effect;
1111 control = graph()->NewNode(common()->IfFalse(), branch_is_smi);
1112 }
1113
1114 Node* object_map = effect =
1115 graph()->NewNode(simplified()->LoadField(AccessBuilder::ForMap()),
1116 r.left(), effect, control);
1117
1118 // Loop through the {object}s prototype chain looking for the {prototype}.
1119 Node* loop = control = graph()->NewNode(common()->Loop(2), control, control);
1120
1121 Node* loop_effect = effect =
1122 graph()->NewNode(common()->EffectPhi(2), effect, effect, loop);
1123
1124 Node* loop_object_map =
1125 graph()->NewNode(common()->Phi(MachineRepresentation::kTagged, 2),
1126 object_map, r.left(), loop);
1127
1128 // Check if the lhs needs access checks.
1129 Node* map_bit_field = effect =
1130 graph()->NewNode(simplified()->LoadField(AccessBuilder::ForMapBitField()),
1131 loop_object_map, loop_effect, control);
1132 int is_access_check_needed_bit = 1 << Map::kIsAccessCheckNeeded;
1133 Node* is_access_check_needed_num =
1134 graph()->NewNode(simplified()->NumberBitwiseAnd(), map_bit_field,
1135 jsgraph()->Uint32Constant(is_access_check_needed_bit));
1136 Node* is_access_check_needed =
1137 graph()->NewNode(machine()->Word32Equal(), is_access_check_needed_num,
1138 jsgraph()->Uint32Constant(is_access_check_needed_bit));
1139
1140 Node* branch_is_access_check_needed = graph()->NewNode(
1141 common()->Branch(BranchHint::kFalse), is_access_check_needed, control);
1142 Node* if_is_access_check_needed =
1143 graph()->NewNode(common()->IfTrue(), branch_is_access_check_needed);
1144 Node* e_is_access_check_needed = effect;
1145
1146 control =
1147 graph()->NewNode(common()->IfFalse(), branch_is_access_check_needed);
1148
1149 // Check if the lhs is a proxy.
1150 Node* map_instance_type = effect = graph()->NewNode(
1151 simplified()->LoadField(AccessBuilder::ForMapInstanceType()),
1152 loop_object_map, loop_effect, control);
1153 Node* is_proxy = graph()->NewNode(machine()->Word32Equal(), map_instance_type,
1154 jsgraph()->Uint32Constant(JS_PROXY_TYPE));
1155 Node* branch_is_proxy =
1156 graph()->NewNode(common()->Branch(BranchHint::kFalse), is_proxy, control);
1157 Node* if_is_proxy = graph()->NewNode(common()->IfTrue(), branch_is_proxy);
1158 Node* e_is_proxy = effect;
1159
1160
1161 Node* runtime_has_in_proto_chain = control = graph()->NewNode(
1162 common()->Merge(2), if_is_access_check_needed, if_is_proxy);
1163 effect = graph()->NewNode(common()->EffectPhi(2), e_is_access_check_needed,
1164 e_is_proxy, control);
1165
1166 // If we need an access check or the object is a Proxy, make a runtime call
1167 // to finish the lowering.
1168 Node* bool_result_runtime_has_in_proto_chain_case = graph()->NewNode(
Ben Murdoch097c5b22016-05-18 11:27:45 +01001169 javascript()->CallRuntime(Runtime::kHasInPrototypeChain), r.left(),
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001170 prototype, context, frame_state, effect, control);
1171
1172 control = graph()->NewNode(common()->IfFalse(), branch_is_proxy);
1173
1174 Node* object_prototype = effect = graph()->NewNode(
1175 simplified()->LoadField(AccessBuilder::ForMapPrototype()),
1176 loop_object_map, loop_effect, control);
1177
1178 // Check if object prototype is equal to function prototype.
1179 Node* eq_proto =
1180 graph()->NewNode(simplified()->ReferenceEqual(r.right_type()),
1181 object_prototype, prototype);
1182 Node* branch_eq_proto =
1183 graph()->NewNode(common()->Branch(BranchHint::kFalse), eq_proto, control);
1184 Node* if_eq_proto = graph()->NewNode(common()->IfTrue(), branch_eq_proto);
1185 Node* e_eq_proto = effect;
1186
1187 control = graph()->NewNode(common()->IfFalse(), branch_eq_proto);
1188
1189 // If not, check if object prototype is the null prototype.
1190 Node* null_proto =
1191 graph()->NewNode(simplified()->ReferenceEqual(r.right_type()),
1192 object_prototype, jsgraph()->NullConstant());
1193 Node* branch_null_proto = graph()->NewNode(
1194 common()->Branch(BranchHint::kFalse), null_proto, control);
1195 Node* if_null_proto = graph()->NewNode(common()->IfTrue(), branch_null_proto);
1196 Node* e_null_proto = effect;
1197
1198 control = graph()->NewNode(common()->IfFalse(), branch_null_proto);
1199 Node* load_object_map = effect =
1200 graph()->NewNode(simplified()->LoadField(AccessBuilder::ForMap()),
1201 object_prototype, effect, control);
1202 // Close the loop.
1203 loop_effect->ReplaceInput(1, effect);
1204 loop_object_map->ReplaceInput(1, load_object_map);
1205 loop->ReplaceInput(1, control);
1206
1207 control = graph()->NewNode(common()->Merge(3), runtime_has_in_proto_chain,
1208 if_eq_proto, if_null_proto);
1209 effect = graph()->NewNode(common()->EffectPhi(3),
1210 bool_result_runtime_has_in_proto_chain_case,
1211 e_eq_proto, e_null_proto, control);
1212
1213 Node* result = graph()->NewNode(
1214 common()->Phi(MachineRepresentation::kTagged, 3),
1215 bool_result_runtime_has_in_proto_chain_case, jsgraph()->TrueConstant(),
1216 jsgraph()->FalseConstant(), control);
1217
1218 if (if_is_smi != nullptr) {
1219 DCHECK_NOT_NULL(e_is_smi);
1220 control = graph()->NewNode(common()->Merge(2), if_is_smi, control);
1221 effect =
1222 graph()->NewNode(common()->EffectPhi(2), e_is_smi, effect, control);
1223 result = graph()->NewNode(common()->Phi(MachineRepresentation::kTagged, 2),
1224 jsgraph()->FalseConstant(), result, control);
1225 }
1226
1227 ReplaceWithValue(node, result, effect, control);
1228 return Changed(result);
1229}
1230
1231
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001232Reduction JSTypedLowering::ReduceJSLoadContext(Node* node) {
1233 DCHECK_EQ(IrOpcode::kJSLoadContext, node->opcode());
1234 ContextAccess const& access = ContextAccessOf(node->op());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001235 Node* effect = NodeProperties::GetEffectInput(node);
1236 Node* control = graph()->start();
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001237 for (size_t i = 0; i < access.depth(); ++i) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001238 Node* previous = effect = graph()->NewNode(
1239 simplified()->LoadField(
1240 AccessBuilder::ForContextSlot(Context::PREVIOUS_INDEX)),
1241 NodeProperties::GetValueInput(node, 0), effect, control);
1242 node->ReplaceInput(0, previous);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001243 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001244 node->ReplaceInput(1, effect);
1245 node->ReplaceInput(2, control);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001246 NodeProperties::ChangeOp(
1247 node,
1248 simplified()->LoadField(AccessBuilder::ForContextSlot(access.index())));
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001249 return Changed(node);
1250}
1251
1252
1253Reduction JSTypedLowering::ReduceJSStoreContext(Node* node) {
1254 DCHECK_EQ(IrOpcode::kJSStoreContext, node->opcode());
1255 ContextAccess const& access = ContextAccessOf(node->op());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001256 Node* effect = NodeProperties::GetEffectInput(node);
1257 Node* control = graph()->start();
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001258 for (size_t i = 0; i < access.depth(); ++i) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001259 Node* previous = effect = graph()->NewNode(
1260 simplified()->LoadField(
1261 AccessBuilder::ForContextSlot(Context::PREVIOUS_INDEX)),
1262 NodeProperties::GetValueInput(node, 0), effect, control);
1263 node->ReplaceInput(0, previous);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001264 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001265 node->RemoveInput(2);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001266 node->ReplaceInput(2, effect);
1267 NodeProperties::ChangeOp(
1268 node,
1269 simplified()->StoreField(AccessBuilder::ForContextSlot(access.index())));
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001270 return Changed(node);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001271}
1272
1273
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001274Reduction JSTypedLowering::ReduceJSConvertReceiver(Node* node) {
1275 DCHECK_EQ(IrOpcode::kJSConvertReceiver, node->opcode());
1276 ConvertReceiverMode mode = ConvertReceiverModeOf(node->op());
1277 Node* receiver = NodeProperties::GetValueInput(node, 0);
1278 Type* receiver_type = NodeProperties::GetType(receiver);
1279 Node* context = NodeProperties::GetContextInput(node);
1280 Type* context_type = NodeProperties::GetType(context);
1281 Node* frame_state = NodeProperties::GetFrameStateInput(node, 0);
1282 Node* effect = NodeProperties::GetEffectInput(node);
1283 Node* control = NodeProperties::GetControlInput(node);
1284 if (!receiver_type->Is(Type::Receiver())) {
1285 if (receiver_type->Is(Type::NullOrUndefined()) ||
1286 mode == ConvertReceiverMode::kNullOrUndefined) {
1287 if (context_type->IsConstant()) {
1288 Handle<JSObject> global_proxy(
1289 Handle<Context>::cast(context_type->AsConstant()->Value())
1290 ->global_proxy(),
1291 isolate());
1292 receiver = jsgraph()->Constant(global_proxy);
1293 } else {
1294 Node* native_context = effect = graph()->NewNode(
1295 javascript()->LoadContext(0, Context::NATIVE_CONTEXT_INDEX, true),
1296 context, context, effect);
1297 receiver = effect = graph()->NewNode(
1298 javascript()->LoadContext(0, Context::GLOBAL_PROXY_INDEX, true),
1299 native_context, native_context, effect);
1300 }
1301 } else if (!receiver_type->Maybe(Type::NullOrUndefined()) ||
1302 mode == ConvertReceiverMode::kNotNullOrUndefined) {
1303 receiver = effect =
1304 graph()->NewNode(javascript()->ToObject(), receiver, context,
1305 frame_state, effect, control);
1306 } else {
1307 // Check {receiver} for undefined.
1308 Node* check0 =
1309 graph()->NewNode(simplified()->ReferenceEqual(receiver_type),
1310 receiver, jsgraph()->UndefinedConstant());
1311 Node* branch0 = graph()->NewNode(common()->Branch(BranchHint::kFalse),
1312 check0, control);
1313 Node* if_true0 = graph()->NewNode(common()->IfTrue(), branch0);
1314 Node* if_false0 = graph()->NewNode(common()->IfFalse(), branch0);
1315
1316 // Check {receiver} for null.
1317 Node* check1 =
1318 graph()->NewNode(simplified()->ReferenceEqual(receiver_type),
1319 receiver, jsgraph()->NullConstant());
1320 Node* branch1 = graph()->NewNode(common()->Branch(BranchHint::kFalse),
1321 check1, if_false0);
1322 Node* if_true1 = graph()->NewNode(common()->IfTrue(), branch1);
1323 Node* if_false1 = graph()->NewNode(common()->IfFalse(), branch1);
1324
1325 // Convert {receiver} using ToObject.
1326 Node* if_convert = if_false1;
1327 Node* econvert = effect;
1328 Node* rconvert;
1329 {
1330 rconvert = econvert =
1331 graph()->NewNode(javascript()->ToObject(), receiver, context,
1332 frame_state, econvert, if_convert);
1333 }
1334
1335 // Replace {receiver} with global proxy of {context}.
1336 Node* if_global =
1337 graph()->NewNode(common()->Merge(2), if_true0, if_true1);
1338 Node* eglobal = effect;
1339 Node* rglobal;
1340 {
1341 if (context_type->IsConstant()) {
1342 Handle<JSObject> global_proxy(
1343 Handle<Context>::cast(context_type->AsConstant()->Value())
1344 ->global_proxy(),
1345 isolate());
1346 rglobal = jsgraph()->Constant(global_proxy);
1347 } else {
1348 Node* native_context = eglobal = graph()->NewNode(
1349 javascript()->LoadContext(0, Context::NATIVE_CONTEXT_INDEX, true),
1350 context, context, eglobal);
1351 rglobal = eglobal = graph()->NewNode(
1352 javascript()->LoadContext(0, Context::GLOBAL_PROXY_INDEX, true),
1353 native_context, native_context, eglobal);
1354 }
1355 }
1356
1357 control = graph()->NewNode(common()->Merge(2), if_convert, if_global);
1358 effect =
1359 graph()->NewNode(common()->EffectPhi(2), econvert, eglobal, control);
1360 receiver =
1361 graph()->NewNode(common()->Phi(MachineRepresentation::kTagged, 2),
1362 rconvert, rglobal, control);
1363 }
1364 }
1365 ReplaceWithValue(node, receiver, effect, control);
1366 return Changed(receiver);
1367}
1368
1369
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001370Reduction JSTypedLowering::ReduceJSCallConstruct(Node* node) {
1371 DCHECK_EQ(IrOpcode::kJSCallConstruct, node->opcode());
1372 CallConstructParameters const& p = CallConstructParametersOf(node->op());
1373 DCHECK_LE(2u, p.arity());
1374 int const arity = static_cast<int>(p.arity() - 2);
1375 Node* target = NodeProperties::GetValueInput(node, 0);
1376 Type* target_type = NodeProperties::GetType(target);
1377 Node* new_target = NodeProperties::GetValueInput(node, arity + 1);
1378
1379 // Check if {target} is a known JSFunction.
1380 if (target_type->IsConstant() &&
1381 target_type->AsConstant()->Value()->IsJSFunction()) {
1382 Handle<JSFunction> function =
1383 Handle<JSFunction>::cast(target_type->AsConstant()->Value());
1384 Handle<SharedFunctionInfo> shared(function->shared(), isolate());
1385
1386 // Remove the eager bailout frame state.
1387 NodeProperties::RemoveFrameStateInput(node, 1);
1388
1389 // Patch {node} to an indirect call via the {function}s construct stub.
1390 Callable callable(handle(shared->construct_stub(), isolate()),
1391 ConstructStubDescriptor(isolate()));
1392 node->RemoveInput(arity + 1);
1393 node->InsertInput(graph()->zone(), 0,
1394 jsgraph()->HeapConstant(callable.code()));
1395 node->InsertInput(graph()->zone(), 2, new_target);
1396 node->InsertInput(graph()->zone(), 3, jsgraph()->Int32Constant(arity));
1397 node->InsertInput(graph()->zone(), 4, jsgraph()->UndefinedConstant());
1398 node->InsertInput(graph()->zone(), 5, jsgraph()->UndefinedConstant());
1399 NodeProperties::ChangeOp(
1400 node, common()->Call(Linkage::GetStubCallDescriptor(
1401 isolate(), graph()->zone(), callable.descriptor(), 1 + arity,
1402 CallDescriptor::kNeedsFrameState)));
1403 return Changed(node);
1404 }
1405
1406 // Check if {target} is a JSFunction.
1407 if (target_type->Is(Type::Function())) {
1408 // Remove the eager bailout frame state.
1409 NodeProperties::RemoveFrameStateInput(node, 1);
1410
1411 // Patch {node} to an indirect call via the ConstructFunction builtin.
1412 Callable callable = CodeFactory::ConstructFunction(isolate());
1413 node->RemoveInput(arity + 1);
1414 node->InsertInput(graph()->zone(), 0,
1415 jsgraph()->HeapConstant(callable.code()));
1416 node->InsertInput(graph()->zone(), 2, new_target);
1417 node->InsertInput(graph()->zone(), 3, jsgraph()->Int32Constant(arity));
1418 node->InsertInput(graph()->zone(), 4, jsgraph()->UndefinedConstant());
1419 NodeProperties::ChangeOp(
1420 node, common()->Call(Linkage::GetStubCallDescriptor(
1421 isolate(), graph()->zone(), callable.descriptor(), 1 + arity,
1422 CallDescriptor::kNeedsFrameState)));
1423 return Changed(node);
1424 }
1425
1426 return NoChange();
1427}
1428
1429
1430Reduction JSTypedLowering::ReduceJSCallFunction(Node* node) {
1431 DCHECK_EQ(IrOpcode::kJSCallFunction, node->opcode());
1432 CallFunctionParameters const& p = CallFunctionParametersOf(node->op());
1433 int const arity = static_cast<int>(p.arity() - 2);
1434 ConvertReceiverMode convert_mode = p.convert_mode();
1435 Node* target = NodeProperties::GetValueInput(node, 0);
1436 Type* target_type = NodeProperties::GetType(target);
1437 Node* receiver = NodeProperties::GetValueInput(node, 1);
1438 Type* receiver_type = NodeProperties::GetType(receiver);
1439 Node* frame_state = NodeProperties::GetFrameStateInput(node, 1);
1440 Node* effect = NodeProperties::GetEffectInput(node);
1441 Node* control = NodeProperties::GetControlInput(node);
1442
1443 // Try to infer receiver {convert_mode} from {receiver} type.
1444 if (receiver_type->Is(Type::NullOrUndefined())) {
1445 convert_mode = ConvertReceiverMode::kNullOrUndefined;
1446 } else if (!receiver_type->Maybe(Type::NullOrUndefined())) {
1447 convert_mode = ConvertReceiverMode::kNotNullOrUndefined;
1448 }
1449
1450 // Check if {target} is a known JSFunction.
1451 if (target_type->IsConstant() &&
1452 target_type->AsConstant()->Value()->IsJSFunction()) {
1453 Handle<JSFunction> function =
1454 Handle<JSFunction>::cast(target_type->AsConstant()->Value());
1455 Handle<SharedFunctionInfo> shared(function->shared(), isolate());
1456
1457 // Class constructors are callable, but [[Call]] will raise an exception.
1458 // See ES6 section 9.2.1 [[Call]] ( thisArgument, argumentsList ).
1459 if (IsClassConstructor(shared->kind())) return NoChange();
1460
1461 // Load the context from the {target}.
1462 Node* context = effect = graph()->NewNode(
1463 simplified()->LoadField(AccessBuilder::ForJSFunctionContext()), target,
1464 effect, control);
1465 NodeProperties::ReplaceContextInput(node, context);
1466
1467 // Check if we need to convert the {receiver}.
1468 if (is_sloppy(shared->language_mode()) && !shared->native() &&
1469 !receiver_type->Is(Type::Receiver())) {
1470 receiver = effect =
1471 graph()->NewNode(javascript()->ConvertReceiver(convert_mode),
1472 receiver, context, frame_state, effect, control);
1473 NodeProperties::ReplaceValueInput(node, receiver, 1);
1474 }
1475
1476 // Update the effect dependency for the {node}.
1477 NodeProperties::ReplaceEffectInput(node, effect);
1478
1479 // Remove the eager bailout frame state.
1480 NodeProperties::RemoveFrameStateInput(node, 1);
1481
1482 // Compute flags for the call.
1483 CallDescriptor::Flags flags = CallDescriptor::kNeedsFrameState;
1484 if (p.tail_call_mode() == TailCallMode::kAllow) {
1485 flags |= CallDescriptor::kSupportsTailCalls;
1486 }
1487
1488 Node* new_target = jsgraph()->UndefinedConstant();
1489 Node* argument_count = jsgraph()->Int32Constant(arity);
1490 if (shared->internal_formal_parameter_count() == arity ||
1491 shared->internal_formal_parameter_count() ==
1492 SharedFunctionInfo::kDontAdaptArgumentsSentinel) {
1493 // Patch {node} to a direct call.
1494 node->InsertInput(graph()->zone(), arity + 2, new_target);
1495 node->InsertInput(graph()->zone(), arity + 3, argument_count);
1496 NodeProperties::ChangeOp(node,
1497 common()->Call(Linkage::GetJSCallDescriptor(
1498 graph()->zone(), false, 1 + arity, flags)));
1499 } else {
1500 // Patch {node} to an indirect call via the ArgumentsAdaptorTrampoline.
1501 Callable callable = CodeFactory::ArgumentAdaptor(isolate());
1502 node->InsertInput(graph()->zone(), 0,
1503 jsgraph()->HeapConstant(callable.code()));
1504 node->InsertInput(graph()->zone(), 2, new_target);
1505 node->InsertInput(graph()->zone(), 3, argument_count);
1506 node->InsertInput(
1507 graph()->zone(), 4,
1508 jsgraph()->Int32Constant(shared->internal_formal_parameter_count()));
1509 NodeProperties::ChangeOp(
1510 node, common()->Call(Linkage::GetStubCallDescriptor(
1511 isolate(), graph()->zone(), callable.descriptor(),
1512 1 + arity, flags)));
1513 }
1514 return Changed(node);
1515 }
1516
1517 // Check if {target} is a JSFunction.
1518 if (target_type->Is(Type::Function())) {
1519 // Remove the eager bailout frame state.
1520 NodeProperties::RemoveFrameStateInput(node, 1);
1521
1522 // Compute flags for the call.
1523 CallDescriptor::Flags flags = CallDescriptor::kNeedsFrameState;
1524 if (p.tail_call_mode() == TailCallMode::kAllow) {
1525 flags |= CallDescriptor::kSupportsTailCalls;
1526 }
1527
1528 // Patch {node} to an indirect call via the CallFunction builtin.
1529 Callable callable = CodeFactory::CallFunction(isolate(), convert_mode);
1530 node->InsertInput(graph()->zone(), 0,
1531 jsgraph()->HeapConstant(callable.code()));
1532 node->InsertInput(graph()->zone(), 2, jsgraph()->Int32Constant(arity));
1533 NodeProperties::ChangeOp(
1534 node, common()->Call(Linkage::GetStubCallDescriptor(
1535 isolate(), graph()->zone(), callable.descriptor(), 1 + arity,
1536 flags)));
1537 return Changed(node);
1538 }
1539
1540 // Maybe we did at least learn something about the {receiver}.
1541 if (p.convert_mode() != convert_mode) {
1542 NodeProperties::ChangeOp(
Ben Murdoch097c5b22016-05-18 11:27:45 +01001543 node, javascript()->CallFunction(p.arity(), p.feedback(), convert_mode,
1544 p.tail_call_mode()));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001545 return Changed(node);
1546 }
1547
1548 return NoChange();
1549}
1550
1551
1552Reduction JSTypedLowering::ReduceJSForInDone(Node* node) {
1553 DCHECK_EQ(IrOpcode::kJSForInDone, node->opcode());
1554 node->TrimInputCount(2);
1555 NodeProperties::ChangeOp(node, machine()->Word32Equal());
1556 return Changed(node);
1557}
1558
1559
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001560Reduction JSTypedLowering::ReduceJSForInNext(Node* node) {
1561 DCHECK_EQ(IrOpcode::kJSForInNext, node->opcode());
1562 Node* receiver = NodeProperties::GetValueInput(node, 0);
1563 Node* cache_array = NodeProperties::GetValueInput(node, 1);
1564 Node* cache_type = NodeProperties::GetValueInput(node, 2);
1565 Node* index = NodeProperties::GetValueInput(node, 3);
1566 Node* context = NodeProperties::GetContextInput(node);
1567 Node* frame_state = NodeProperties::GetFrameStateInput(node, 0);
1568 Node* effect = NodeProperties::GetEffectInput(node);
1569 Node* control = NodeProperties::GetControlInput(node);
1570
1571 // Load the next {key} from the {cache_array}.
1572 Node* key = effect = graph()->NewNode(
1573 simplified()->LoadElement(AccessBuilder::ForFixedArrayElement()),
1574 cache_array, index, effect, control);
1575
1576 // Load the map of the {receiver}.
1577 Node* receiver_map = effect =
1578 graph()->NewNode(simplified()->LoadField(AccessBuilder::ForMap()),
1579 receiver, effect, control);
1580
1581 // Check if the expected map still matches that of the {receiver}.
1582 Node* check0 = graph()->NewNode(simplified()->ReferenceEqual(Type::Any()),
1583 receiver_map, cache_type);
1584 Node* branch0 =
1585 graph()->NewNode(common()->Branch(BranchHint::kTrue), check0, control);
1586
1587 Node* if_true0 = graph()->NewNode(common()->IfTrue(), branch0);
1588 Node* etrue0;
1589 Node* vtrue0;
1590 {
1591 // Don't need filtering since expected map still matches that of the
1592 // {receiver}.
1593 etrue0 = effect;
1594 vtrue0 = key;
1595 }
1596
1597 Node* if_false0 = graph()->NewNode(common()->IfFalse(), branch0);
1598 Node* efalse0;
1599 Node* vfalse0;
1600 {
Ben Murdoch097c5b22016-05-18 11:27:45 +01001601 // Filter the {key} to check if it's still a valid property of the
1602 // {receiver} (does the ToName conversion implicitly).
1603 vfalse0 = efalse0 = graph()->NewNode(
1604 javascript()->CallRuntime(Runtime::kForInFilter), receiver, key,
1605 context, frame_state, effect, if_false0);
1606 if_false0 = graph()->NewNode(common()->IfSuccess(), vfalse0);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001607 }
1608
1609 control = graph()->NewNode(common()->Merge(2), if_true0, if_false0);
1610 effect = graph()->NewNode(common()->EffectPhi(2), etrue0, efalse0, control);
1611 ReplaceWithValue(node, node, effect, control);
1612 node->ReplaceInput(0, vtrue0);
1613 node->ReplaceInput(1, vfalse0);
1614 node->ReplaceInput(2, control);
1615 node->TrimInputCount(3);
1616 NodeProperties::ChangeOp(node,
1617 common()->Phi(MachineRepresentation::kTagged, 2));
1618 return Changed(node);
1619}
1620
1621
1622Reduction JSTypedLowering::ReduceJSForInStep(Node* node) {
1623 DCHECK_EQ(IrOpcode::kJSForInStep, node->opcode());
1624 node->ReplaceInput(1, jsgraph()->Int32Constant(1));
1625 NodeProperties::ChangeOp(node, machine()->Int32Add());
1626 return Changed(node);
1627}
1628
1629
1630Reduction JSTypedLowering::ReduceSelect(Node* node) {
1631 DCHECK_EQ(IrOpcode::kSelect, node->opcode());
1632 Node* const condition = NodeProperties::GetValueInput(node, 0);
1633 Type* const condition_type = NodeProperties::GetType(condition);
1634 Node* const vtrue = NodeProperties::GetValueInput(node, 1);
1635 Type* const vtrue_type = NodeProperties::GetType(vtrue);
1636 Node* const vfalse = NodeProperties::GetValueInput(node, 2);
1637 Type* const vfalse_type = NodeProperties::GetType(vfalse);
1638 if (condition_type->Is(true_type_)) {
1639 // Select(condition:true, vtrue, vfalse) => vtrue
1640 return Replace(vtrue);
1641 }
1642 if (condition_type->Is(false_type_)) {
1643 // Select(condition:false, vtrue, vfalse) => vfalse
1644 return Replace(vfalse);
1645 }
1646 if (vtrue_type->Is(true_type_) && vfalse_type->Is(false_type_)) {
1647 // Select(condition, vtrue:true, vfalse:false) => condition
1648 return Replace(condition);
1649 }
1650 if (vtrue_type->Is(false_type_) && vfalse_type->Is(true_type_)) {
1651 // Select(condition, vtrue:false, vfalse:true) => BooleanNot(condition)
1652 node->TrimInputCount(1);
1653 NodeProperties::ChangeOp(node, simplified()->BooleanNot());
1654 return Changed(node);
1655 }
1656 return NoChange();
1657}
1658
1659
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001660Reduction JSTypedLowering::Reduce(Node* node) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001661 // Check if the output type is a singleton. In that case we already know the
1662 // result value and can simply replace the node if it's eliminable.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001663 if (!NodeProperties::IsConstant(node) && NodeProperties::IsTyped(node) &&
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001664 node->op()->HasProperty(Operator::kEliminatable)) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001665 Type* upper = NodeProperties::GetType(node);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001666 if (upper->IsConstant()) {
1667 Node* replacement = jsgraph()->Constant(upper->AsConstant()->Value());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001668 ReplaceWithValue(node, replacement);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001669 return Changed(replacement);
1670 } else if (upper->Is(Type::MinusZero())) {
1671 Node* replacement = jsgraph()->Constant(factory()->minus_zero_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::NaN())) {
1675 Node* replacement = jsgraph()->NaNConstant();
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::Null())) {
1679 Node* replacement = jsgraph()->NullConstant();
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::PlainNumber()) && upper->Min() == upper->Max()) {
1683 Node* replacement = jsgraph()->Constant(upper->Min());
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::Undefined())) {
1687 Node* replacement = jsgraph()->UndefinedConstant();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001688 ReplaceWithValue(node, replacement);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001689 return Changed(replacement);
1690 }
1691 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001692 switch (node->opcode()) {
1693 case IrOpcode::kJSEqual:
1694 return ReduceJSEqual(node, false);
1695 case IrOpcode::kJSNotEqual:
1696 return ReduceJSEqual(node, true);
1697 case IrOpcode::kJSStrictEqual:
1698 return ReduceJSStrictEqual(node, false);
1699 case IrOpcode::kJSStrictNotEqual:
1700 return ReduceJSStrictEqual(node, true);
1701 case IrOpcode::kJSLessThan: // fall through
1702 case IrOpcode::kJSGreaterThan: // fall through
1703 case IrOpcode::kJSLessThanOrEqual: // fall through
1704 case IrOpcode::kJSGreaterThanOrEqual:
1705 return ReduceJSComparison(node);
1706 case IrOpcode::kJSBitwiseOr:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001707 return ReduceInt32Binop(node, simplified()->NumberBitwiseOr());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001708 case IrOpcode::kJSBitwiseXor:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001709 return ReduceInt32Binop(node, simplified()->NumberBitwiseXor());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001710 case IrOpcode::kJSBitwiseAnd:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001711 return ReduceInt32Binop(node, simplified()->NumberBitwiseAnd());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001712 case IrOpcode::kJSShiftLeft:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001713 return ReduceUI32Shift(node, kSigned, simplified()->NumberShiftLeft());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001714 case IrOpcode::kJSShiftRight:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001715 return ReduceUI32Shift(node, kSigned, simplified()->NumberShiftRight());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001716 case IrOpcode::kJSShiftRightLogical:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001717 return ReduceUI32Shift(node, kUnsigned,
1718 simplified()->NumberShiftRightLogical());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001719 case IrOpcode::kJSAdd:
1720 return ReduceJSAdd(node);
1721 case IrOpcode::kJSSubtract:
1722 return ReduceNumberBinop(node, simplified()->NumberSubtract());
1723 case IrOpcode::kJSMultiply:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001724 return ReduceNumberBinop(node, simplified()->NumberMultiply());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001725 case IrOpcode::kJSDivide:
1726 return ReduceNumberBinop(node, simplified()->NumberDivide());
1727 case IrOpcode::kJSModulus:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001728 return ReduceJSModulus(node);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001729 case IrOpcode::kJSToBoolean:
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001730 return ReduceJSToBoolean(node);
Ben Murdochda12d292016-06-02 14:46:10 +01001731 case IrOpcode::kJSToInteger:
1732 return ReduceJSToInteger(node);
1733 case IrOpcode::kJSToLength:
1734 return ReduceJSToLength(node);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001735 case IrOpcode::kJSToNumber:
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001736 return ReduceJSToNumber(node);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001737 case IrOpcode::kJSToString:
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001738 return ReduceJSToString(node);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001739 case IrOpcode::kJSToObject:
1740 return ReduceJSToObject(node);
1741 case IrOpcode::kJSLoadNamed:
1742 return ReduceJSLoadNamed(node);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001743 case IrOpcode::kJSLoadProperty:
1744 return ReduceJSLoadProperty(node);
1745 case IrOpcode::kJSStoreProperty:
1746 return ReduceJSStoreProperty(node);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001747 case IrOpcode::kJSInstanceOf:
1748 return ReduceJSInstanceOf(node);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001749 case IrOpcode::kJSLoadContext:
1750 return ReduceJSLoadContext(node);
1751 case IrOpcode::kJSStoreContext:
1752 return ReduceJSStoreContext(node);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001753 case IrOpcode::kJSConvertReceiver:
1754 return ReduceJSConvertReceiver(node);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001755 case IrOpcode::kJSCallConstruct:
1756 return ReduceJSCallConstruct(node);
1757 case IrOpcode::kJSCallFunction:
1758 return ReduceJSCallFunction(node);
1759 case IrOpcode::kJSForInDone:
1760 return ReduceJSForInDone(node);
1761 case IrOpcode::kJSForInNext:
1762 return ReduceJSForInNext(node);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001763 case IrOpcode::kJSForInStep:
1764 return ReduceJSForInStep(node);
1765 case IrOpcode::kSelect:
1766 return ReduceSelect(node);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001767 default:
1768 break;
1769 }
1770 return NoChange();
1771}
1772
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001773
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001774Node* JSTypedLowering::Word32Shl(Node* const lhs, int32_t const rhs) {
1775 if (rhs == 0) return lhs;
1776 return graph()->NewNode(machine()->Word32Shl(), lhs,
1777 jsgraph()->Int32Constant(rhs));
1778}
1779
1780
1781Factory* JSTypedLowering::factory() const { return jsgraph()->factory(); }
1782
1783
1784Graph* JSTypedLowering::graph() const { return jsgraph()->graph(); }
1785
1786
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001787Isolate* JSTypedLowering::isolate() const { return jsgraph()->isolate(); }
1788
1789
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001790JSOperatorBuilder* JSTypedLowering::javascript() const {
1791 return jsgraph()->javascript();
1792}
1793
1794
1795CommonOperatorBuilder* JSTypedLowering::common() const {
1796 return jsgraph()->common();
1797}
1798
1799
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001800SimplifiedOperatorBuilder* JSTypedLowering::simplified() const {
1801 return jsgraph()->simplified();
1802}
1803
1804
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001805MachineOperatorBuilder* JSTypedLowering::machine() const {
1806 return jsgraph()->machine();
1807}
1808
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001809
1810CompilationDependencies* JSTypedLowering::dependencies() const {
1811 return dependencies_;
1812}
1813
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001814} // namespace compiler
1815} // namespace internal
1816} // namespace v8