blob: 11ae3a9709b1099632fca8cf59af06ba903f73fe [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 Murdoch4a90d5f2016-03-22 12:00:34 +0000536 if (r.OneInputIs(Type::NullOrUndefined())) {
537 Callable const callable = CodeFactory::CompareNilIC(isolate(), kNullValue);
538 CallDescriptor const* const desc = Linkage::GetStubCallDescriptor(
539 isolate(), graph()->zone(), callable.descriptor(), 0,
540 CallDescriptor::kNeedsFrameState, node->op()->properties());
541 node->RemoveInput(r.LeftInputIs(Type::NullOrUndefined()) ? 0 : 1);
542 node->InsertInput(graph()->zone(), 0,
543 jsgraph()->HeapConstant(callable.code()));
544 NodeProperties::ChangeOp(node, common()->Call(desc));
545 if (invert) {
546 // Insert an boolean not to invert the value.
547 Node* value = graph()->NewNode(simplified()->BooleanNot(), node);
548 node->ReplaceUses(value);
549 // Note: ReplaceUses() smashes all uses, so smash it back here.
550 value->ReplaceInput(0, node);
551 return Replace(value);
552 }
553 return Changed(node);
554 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000555 return NoChange();
556}
557
558
559Reduction JSTypedLowering::ReduceJSStrictEqual(Node* node, bool invert) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000560 if (flags() & kDisableBinaryOpReduction) return NoChange();
561
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000562 JSBinopReduction r(this, node);
563 if (r.left() == r.right()) {
564 // x === x is always true if x != NaN
565 if (!r.left_type()->Maybe(Type::NaN())) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000566 Node* replacement = jsgraph()->BooleanConstant(!invert);
567 ReplaceWithValue(node, replacement);
568 return Replace(replacement);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000569 }
570 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400571 if (r.OneInputCannotBe(Type::NumberOrString())) {
572 // For values with canonical representation (i.e. not string nor number) an
573 // empty type intersection means the values cannot be strictly equal.
574 if (!r.left_type()->Maybe(r.right_type())) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000575 Node* replacement = jsgraph()->BooleanConstant(invert);
576 ReplaceWithValue(node, replacement);
577 return Replace(replacement);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000578 }
579 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000580 if (r.OneInputIs(the_hole_type_)) {
581 return r.ChangeToPureOperator(simplified()->ReferenceEqual(the_hole_type_),
582 invert);
583 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000584 if (r.OneInputIs(Type::Undefined())) {
585 return r.ChangeToPureOperator(
586 simplified()->ReferenceEqual(Type::Undefined()), invert);
587 }
588 if (r.OneInputIs(Type::Null())) {
589 return r.ChangeToPureOperator(simplified()->ReferenceEqual(Type::Null()),
590 invert);
591 }
592 if (r.OneInputIs(Type::Boolean())) {
593 return r.ChangeToPureOperator(simplified()->ReferenceEqual(Type::Boolean()),
594 invert);
595 }
596 if (r.OneInputIs(Type::Object())) {
597 return r.ChangeToPureOperator(simplified()->ReferenceEqual(Type::Object()),
598 invert);
599 }
600 if (r.OneInputIs(Type::Receiver())) {
601 return r.ChangeToPureOperator(
602 simplified()->ReferenceEqual(Type::Receiver()), invert);
603 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000604 if (r.BothInputsAre(Type::Unique())) {
605 return r.ChangeToPureOperator(simplified()->ReferenceEqual(Type::Unique()),
606 invert);
607 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000608 if (r.BothInputsAre(Type::String())) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000609 return r.ChangeToStringComparisonOperator(simplified()->StringEqual(),
610 invert);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000611 }
612 if (r.BothInputsAre(Type::Number())) {
613 return r.ChangeToPureOperator(simplified()->NumberEqual(), invert);
614 }
615 // TODO(turbofan): js-typed-lowering of StrictEqual(mixed types)
616 return NoChange();
617}
618
619
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000620Reduction JSTypedLowering::ReduceJSToBoolean(Node* node) {
621 Node* const input = node->InputAt(0);
622 Type* const input_type = NodeProperties::GetType(input);
623 Node* const effect = NodeProperties::GetEffectInput(node);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400624 if (input_type->Is(Type::Boolean())) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000625 // JSToBoolean(x:boolean) => x
626 ReplaceWithValue(node, input, effect);
627 return Replace(input);
628 } else if (input_type->Is(Type::OrderedNumber())) {
629 // JSToBoolean(x:ordered-number) => BooleanNot(NumberEqual(x,#0))
630 RelaxEffectsAndControls(node);
631 node->ReplaceInput(0, graph()->NewNode(simplified()->NumberEqual(), input,
632 jsgraph()->ZeroConstant()));
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400633 node->TrimInputCount(1);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000634 NodeProperties::ChangeOp(node, simplified()->BooleanNot());
635 return Changed(node);
636 } else if (input_type->Is(Type::String())) {
637 // JSToBoolean(x:string) => NumberLessThan(#0,x.length)
638 FieldAccess const access = AccessBuilder::ForStringLength();
639 Node* length = graph()->NewNode(simplified()->LoadField(access), input,
640 effect, graph()->start());
641 ReplaceWithValue(node, node, length);
642 node->ReplaceInput(0, jsgraph()->ZeroConstant());
643 node->ReplaceInput(1, length);
644 node->TrimInputCount(2);
645 NodeProperties::ChangeOp(node, simplified()->NumberLessThan());
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400646 return Changed(node);
647 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000648 return NoChange();
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400649}
650
651
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000652Reduction JSTypedLowering::ReduceJSToNumberInput(Node* input) {
653 if (input->opcode() == IrOpcode::kJSToNumber) {
654 // Recursively try to reduce the input first.
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400655 Reduction result = ReduceJSToNumber(input);
656 if (result.Changed()) return result;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000657 return Changed(input); // JSToNumber(JSToNumber(x)) => JSToNumber(x)
658 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000659 // Check for ToNumber truncation of signaling NaN to undefined mapping.
660 if (input->opcode() == IrOpcode::kSelect) {
661 Node* check = NodeProperties::GetValueInput(input, 0);
662 Node* vtrue = NodeProperties::GetValueInput(input, 1);
663 Type* vtrue_type = NodeProperties::GetType(vtrue);
664 Node* vfalse = NodeProperties::GetValueInput(input, 2);
665 Type* vfalse_type = NodeProperties::GetType(vfalse);
666 if (vtrue_type->Is(Type::Undefined()) && vfalse_type->Is(Type::Number())) {
667 if (check->opcode() == IrOpcode::kNumberIsHoleNaN &&
668 check->InputAt(0) == vfalse) {
669 // JSToNumber(Select(NumberIsHoleNaN(x), y:undefined, x:number)) => x
670 return Replace(vfalse);
671 }
672 }
673 }
Ben Murdoch097c5b22016-05-18 11:27:45 +0100674 // Try constant-folding of JSToNumber with constant inputs.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000675 Type* input_type = NodeProperties::GetType(input);
Ben Murdoch097c5b22016-05-18 11:27:45 +0100676 if (input_type->IsConstant()) {
677 Handle<Object> input_value = input_type->AsConstant()->Value();
678 if (input_value->IsString()) {
679 return Replace(jsgraph()->Constant(
680 String::ToNumber(Handle<String>::cast(input_value))));
681 } else if (input_value->IsOddball()) {
682 return Replace(jsgraph()->Constant(
683 Oddball::ToNumber(Handle<Oddball>::cast(input_value))));
684 }
685 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000686 if (input_type->Is(Type::Number())) {
687 // JSToNumber(x:number) => x
688 return Changed(input);
689 }
690 if (input_type->Is(Type::Undefined())) {
691 // JSToNumber(undefined) => #NaN
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400692 return Replace(jsgraph()->NaNConstant());
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000693 }
694 if (input_type->Is(Type::Null())) {
695 // JSToNumber(null) => #0
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400696 return Replace(jsgraph()->ZeroConstant());
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000697 }
698 if (input_type->Is(Type::Boolean())) {
699 // JSToNumber(x:boolean) => BooleanToNumber(x)
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400700 return Replace(graph()->NewNode(simplified()->BooleanToNumber(), input));
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000701 }
702 // TODO(turbofan): js-typed-lowering of ToNumber(x:string)
703 return NoChange();
704}
705
706
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400707Reduction JSTypedLowering::ReduceJSToNumber(Node* node) {
708 // Try to reduce the input first.
709 Node* const input = node->InputAt(0);
710 Reduction reduction = ReduceJSToNumberInput(input);
711 if (reduction.Changed()) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000712 ReplaceWithValue(node, reduction.replacement());
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400713 return reduction;
714 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000715 Type* const input_type = NodeProperties::GetType(input);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400716 if (input_type->Is(Type::PlainPrimitive())) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000717 if (NodeProperties::GetContextInput(node) !=
718 jsgraph()->NoContextConstant() ||
719 NodeProperties::GetEffectInput(node) != graph()->start() ||
720 NodeProperties::GetControlInput(node) != graph()->start()) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400721 // JSToNumber(x:plain-primitive,context,effect,control)
722 // => JSToNumber(x,no-context,start,start)
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000723 RelaxEffectsAndControls(node);
724 NodeProperties::ReplaceContextInput(node, jsgraph()->NoContextConstant());
725 NodeProperties::ReplaceControlInput(node, graph()->start());
726 NodeProperties::ReplaceEffectInput(node, graph()->start());
727 DCHECK_EQ(1, OperatorProperties::GetFrameStateInputCount(node->op()));
728 NodeProperties::ReplaceFrameStateInput(node, 0,
729 jsgraph()->EmptyFrameState());
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400730 return Changed(node);
731 }
732 }
733 return NoChange();
734}
735
736
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000737Reduction JSTypedLowering::ReduceJSToStringInput(Node* input) {
738 if (input->opcode() == IrOpcode::kJSToString) {
739 // Recursively try to reduce the input first.
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400740 Reduction result = ReduceJSToString(input);
741 if (result.Changed()) return result;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000742 return Changed(input); // JSToString(JSToString(x)) => JSToString(x)
743 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000744 Type* input_type = NodeProperties::GetType(input);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000745 if (input_type->Is(Type::String())) {
746 return Changed(input); // JSToString(x:string) => x
747 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000748 if (input_type->Is(Type::Boolean())) {
749 return Replace(graph()->NewNode(
750 common()->Select(MachineRepresentation::kTagged), input,
751 jsgraph()->HeapConstant(factory()->true_string()),
752 jsgraph()->HeapConstant(factory()->false_string())));
753 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000754 if (input_type->Is(Type::Undefined())) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400755 return Replace(jsgraph()->HeapConstant(factory()->undefined_string()));
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000756 }
757 if (input_type->Is(Type::Null())) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400758 return Replace(jsgraph()->HeapConstant(factory()->null_string()));
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000759 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000760 // TODO(turbofan): js-typed-lowering of ToString(x:number)
761 return NoChange();
762}
763
764
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400765Reduction JSTypedLowering::ReduceJSToString(Node* node) {
766 // Try to reduce the input first.
767 Node* const input = node->InputAt(0);
768 Reduction reduction = ReduceJSToStringInput(input);
769 if (reduction.Changed()) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000770 ReplaceWithValue(node, reduction.replacement());
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400771 return reduction;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000772 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000773 return NoChange();
774}
775
776
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000777Reduction JSTypedLowering::ReduceJSToObject(Node* node) {
778 DCHECK_EQ(IrOpcode::kJSToObject, node->opcode());
779 Node* receiver = NodeProperties::GetValueInput(node, 0);
780 Type* receiver_type = NodeProperties::GetType(receiver);
781 Node* context = NodeProperties::GetContextInput(node);
782 Node* frame_state = NodeProperties::GetFrameStateInput(node, 0);
783 Node* effect = NodeProperties::GetEffectInput(node);
784 Node* control = NodeProperties::GetControlInput(node);
785 if (!receiver_type->Is(Type::Receiver())) {
786 // TODO(bmeurer/mstarzinger): Add support for lowering inside try blocks.
787 if (receiver_type->Maybe(Type::NullOrUndefined()) &&
788 NodeProperties::IsExceptionalCall(node)) {
789 // ToObject throws for null or undefined inputs.
790 return NoChange();
791 }
792
793 // Check whether {receiver} is a Smi.
794 Node* check0 = graph()->NewNode(simplified()->ObjectIsSmi(), receiver);
795 Node* branch0 =
796 graph()->NewNode(common()->Branch(BranchHint::kFalse), check0, control);
797 Node* if_true0 = graph()->NewNode(common()->IfTrue(), branch0);
798 Node* etrue0 = effect;
799
800 Node* if_false0 = graph()->NewNode(common()->IfFalse(), branch0);
801 Node* efalse0 = effect;
802
803 // Determine the instance type of {receiver}.
804 Node* receiver_map = efalse0 =
805 graph()->NewNode(simplified()->LoadField(AccessBuilder::ForMap()),
806 receiver, efalse0, if_false0);
807 Node* receiver_instance_type = efalse0 = graph()->NewNode(
808 simplified()->LoadField(AccessBuilder::ForMapInstanceType()),
809 receiver_map, efalse0, if_false0);
810
811 // Check whether {receiver} is a spec object.
812 STATIC_ASSERT(LAST_JS_RECEIVER_TYPE == LAST_TYPE);
813 Node* check1 =
814 graph()->NewNode(machine()->Uint32LessThanOrEqual(),
815 jsgraph()->Uint32Constant(FIRST_JS_RECEIVER_TYPE),
816 receiver_instance_type);
817 Node* branch1 = graph()->NewNode(common()->Branch(BranchHint::kTrue),
818 check1, if_false0);
819 Node* if_true1 = graph()->NewNode(common()->IfTrue(), branch1);
820 Node* etrue1 = efalse0;
821
822 Node* if_false1 = graph()->NewNode(common()->IfFalse(), branch1);
823 Node* efalse1 = efalse0;
824
825 // Convert {receiver} using the ToObjectStub.
826 Node* if_convert =
827 graph()->NewNode(common()->Merge(2), if_true0, if_false1);
828 Node* econvert =
829 graph()->NewNode(common()->EffectPhi(2), etrue0, efalse1, if_convert);
830 Node* rconvert;
831 {
832 Callable callable = CodeFactory::ToObject(isolate());
833 CallDescriptor const* const desc = Linkage::GetStubCallDescriptor(
834 isolate(), graph()->zone(), callable.descriptor(), 0,
835 CallDescriptor::kNeedsFrameState, node->op()->properties());
836 rconvert = econvert = graph()->NewNode(
837 common()->Call(desc), jsgraph()->HeapConstant(callable.code()),
838 receiver, context, frame_state, econvert, if_convert);
839 }
840
841 // The {receiver} is already a spec object.
842 Node* if_done = if_true1;
843 Node* edone = etrue1;
844 Node* rdone = receiver;
845
846 control = graph()->NewNode(common()->Merge(2), if_convert, if_done);
847 effect = graph()->NewNode(common()->EffectPhi(2), econvert, edone, control);
848 receiver =
849 graph()->NewNode(common()->Phi(MachineRepresentation::kTagged, 2),
850 rconvert, rdone, control);
851 }
852 ReplaceWithValue(node, receiver, effect, control);
853 return Changed(receiver);
854}
855
856
857Reduction JSTypedLowering::ReduceJSLoadNamed(Node* node) {
858 DCHECK_EQ(IrOpcode::kJSLoadNamed, node->opcode());
859 Node* receiver = NodeProperties::GetValueInput(node, 0);
860 Type* receiver_type = NodeProperties::GetType(receiver);
861 Node* effect = NodeProperties::GetEffectInput(node);
862 Node* control = NodeProperties::GetControlInput(node);
863 Handle<Name> name = NamedAccessOf(node->op()).name();
864 // Optimize "length" property of strings.
865 if (name.is_identical_to(factory()->length_string()) &&
866 receiver_type->Is(Type::String())) {
867 Node* value = effect = graph()->NewNode(
868 simplified()->LoadField(AccessBuilder::ForStringLength()), receiver,
869 effect, control);
870 ReplaceWithValue(node, value, effect);
871 return Replace(value);
872 }
873 // Optimize "prototype" property of functions.
874 if (name.is_identical_to(factory()->prototype_string()) &&
875 receiver_type->IsConstant() &&
876 receiver_type->AsConstant()->Value()->IsJSFunction()) {
877 // TODO(turbofan): This lowering might not kick in if we ever lower
878 // the C++ accessor for "prototype" in an earlier optimization pass.
879 Handle<JSFunction> function =
880 Handle<JSFunction>::cast(receiver_type->AsConstant()->Value());
881 if (function->has_initial_map()) {
882 // We need to add a code dependency on the initial map of the {function}
883 // in order to be notified about changes to the "prototype" of {function},
884 // so it doesn't make sense to continue unless deoptimization is enabled.
885 if (!(flags() & kDeoptimizationEnabled)) return NoChange();
886 Handle<Map> initial_map(function->initial_map(), isolate());
887 dependencies()->AssumeInitialMapCantChange(initial_map);
888 Node* value =
889 jsgraph()->Constant(handle(initial_map->prototype(), isolate()));
890 ReplaceWithValue(node, value);
891 return Replace(value);
892 }
893 }
894 return NoChange();
895}
896
897
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000898Reduction JSTypedLowering::ReduceJSLoadProperty(Node* node) {
899 Node* key = NodeProperties::GetValueInput(node, 1);
900 Node* base = NodeProperties::GetValueInput(node, 0);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000901 Type* key_type = NodeProperties::GetType(key);
902 HeapObjectMatcher mbase(base);
903 if (mbase.HasValue() && mbase.Value()->IsJSTypedArray()) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400904 Handle<JSTypedArray> const array =
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000905 Handle<JSTypedArray>::cast(mbase.Value());
906 if (!array->GetBuffer()->was_neutered()) {
907 array->GetBuffer()->set_is_neuterable(false);
908 BufferAccess const access(array->type());
909 size_t const k =
910 ElementSizeLog2Of(access.machine_type().representation());
911 double const byte_length = array->byte_length()->Number();
912 CHECK_LT(k, arraysize(shifted_int32_ranges_));
913 if (key_type->Is(shifted_int32_ranges_[k]) && byte_length <= kMaxInt) {
914 // JSLoadProperty(typed-array, int32)
915 Handle<FixedTypedArrayBase> elements =
916 Handle<FixedTypedArrayBase>::cast(handle(array->elements()));
917 Node* buffer = jsgraph()->PointerConstant(elements->external_pointer());
918 Node* length = jsgraph()->Constant(byte_length);
919 Node* effect = NodeProperties::GetEffectInput(node);
920 Node* control = NodeProperties::GetControlInput(node);
921 // Check if we can avoid the bounds check.
922 if (key_type->Min() >= 0 && key_type->Max() < array->length_value()) {
923 Node* load = graph()->NewNode(
924 simplified()->LoadElement(
925 AccessBuilder::ForTypedArrayElement(array->type(), true)),
926 buffer, key, effect, control);
927 ReplaceWithValue(node, load, load);
928 return Replace(load);
929 }
930 // Compute byte offset.
931 Node* offset = Word32Shl(key, static_cast<int>(k));
932 Node* load = graph()->NewNode(simplified()->LoadBuffer(access), buffer,
933 offset, length, effect, control);
934 ReplaceWithValue(node, load, load);
935 return Replace(load);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400936 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000937 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000938 }
939 return NoChange();
940}
941
942
943Reduction JSTypedLowering::ReduceJSStoreProperty(Node* node) {
944 Node* key = NodeProperties::GetValueInput(node, 1);
945 Node* base = NodeProperties::GetValueInput(node, 0);
946 Node* value = NodeProperties::GetValueInput(node, 2);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000947 Type* key_type = NodeProperties::GetType(key);
948 Type* value_type = NodeProperties::GetType(value);
949 HeapObjectMatcher mbase(base);
950 if (mbase.HasValue() && mbase.Value()->IsJSTypedArray()) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400951 Handle<JSTypedArray> const array =
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000952 Handle<JSTypedArray>::cast(mbase.Value());
953 if (!array->GetBuffer()->was_neutered()) {
954 array->GetBuffer()->set_is_neuterable(false);
955 BufferAccess const access(array->type());
956 size_t const k =
957 ElementSizeLog2Of(access.machine_type().representation());
958 double const byte_length = array->byte_length()->Number();
959 CHECK_LT(k, arraysize(shifted_int32_ranges_));
960 if (access.external_array_type() != kExternalUint8ClampedArray &&
961 key_type->Is(shifted_int32_ranges_[k]) && byte_length <= kMaxInt) {
962 // JSLoadProperty(typed-array, int32)
963 Handle<FixedTypedArrayBase> elements =
964 Handle<FixedTypedArrayBase>::cast(handle(array->elements()));
965 Node* buffer = jsgraph()->PointerConstant(elements->external_pointer());
966 Node* length = jsgraph()->Constant(byte_length);
967 Node* context = NodeProperties::GetContextInput(node);
968 Node* effect = NodeProperties::GetEffectInput(node);
969 Node* control = NodeProperties::GetControlInput(node);
970 // Convert to a number first.
971 if (!value_type->Is(Type::Number())) {
972 Reduction number_reduction = ReduceJSToNumberInput(value);
973 if (number_reduction.Changed()) {
974 value = number_reduction.replacement();
975 } else {
976 Node* frame_state_for_to_number =
977 NodeProperties::GetFrameStateInput(node, 1);
978 value = effect =
979 graph()->NewNode(javascript()->ToNumber(), value, context,
980 frame_state_for_to_number, effect, control);
981 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400982 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000983 // Check if we can avoid the bounds check.
984 if (key_type->Min() >= 0 && key_type->Max() < array->length_value()) {
985 RelaxControls(node);
986 node->ReplaceInput(0, buffer);
987 DCHECK_EQ(key, node->InputAt(1));
988 node->ReplaceInput(2, value);
989 node->ReplaceInput(3, effect);
990 node->ReplaceInput(4, control);
991 node->TrimInputCount(5);
992 NodeProperties::ChangeOp(
993 node,
994 simplified()->StoreElement(
995 AccessBuilder::ForTypedArrayElement(array->type(), true)));
996 return Changed(node);
997 }
998 // Compute byte offset.
999 Node* offset = Word32Shl(key, static_cast<int>(k));
1000 // Turn into a StoreBuffer operation.
1001 RelaxControls(node);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001002 node->ReplaceInput(0, buffer);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001003 node->ReplaceInput(1, offset);
1004 node->ReplaceInput(2, length);
1005 node->ReplaceInput(3, value);
1006 node->ReplaceInput(4, effect);
1007 node->ReplaceInput(5, control);
1008 node->TrimInputCount(6);
1009 NodeProperties::ChangeOp(node, simplified()->StoreBuffer(access));
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001010 return Changed(node);
1011 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001012 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001013 }
1014 return NoChange();
1015}
1016
1017
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001018Reduction JSTypedLowering::ReduceJSInstanceOf(Node* node) {
1019 DCHECK_EQ(IrOpcode::kJSInstanceOf, node->opcode());
1020 Node* const context = NodeProperties::GetContextInput(node);
1021 Node* const frame_state = NodeProperties::GetFrameStateInput(node, 0);
1022
1023 // If deoptimization is disabled, we cannot optimize.
1024 if (!(flags() & kDeoptimizationEnabled) ||
1025 (flags() & kDisableBinaryOpReduction)) {
1026 return NoChange();
1027 }
1028
1029 // If we are in a try block, don't optimize since the runtime call
1030 // in the proxy case can throw.
1031 if (NodeProperties::IsExceptionalCall(node)) return NoChange();
1032
1033 JSBinopReduction r(this, node);
1034 Node* effect = r.effect();
1035 Node* control = r.control();
1036
1037 if (!r.right_type()->IsConstant() ||
1038 !r.right_type()->AsConstant()->Value()->IsJSFunction()) {
1039 return NoChange();
1040 }
1041
1042 Handle<JSFunction> function =
1043 Handle<JSFunction>::cast(r.right_type()->AsConstant()->Value());
1044 Handle<SharedFunctionInfo> shared(function->shared(), isolate());
1045
1046 if (!function->IsConstructor() ||
1047 function->map()->has_non_instance_prototype()) {
1048 return NoChange();
1049 }
1050
1051 JSFunction::EnsureHasInitialMap(function);
1052 DCHECK(function->has_initial_map());
1053 Handle<Map> initial_map(function->initial_map(), isolate());
1054 this->dependencies()->AssumeInitialMapCantChange(initial_map);
1055 Node* prototype =
1056 jsgraph()->Constant(handle(initial_map->prototype(), isolate()));
1057
1058 Node* if_is_smi = nullptr;
1059 Node* e_is_smi = nullptr;
1060 // If the left hand side is an object, no smi check is needed.
1061 if (r.left_type()->Maybe(Type::TaggedSigned())) {
1062 Node* is_smi = graph()->NewNode(simplified()->ObjectIsSmi(), r.left());
1063 Node* branch_is_smi =
1064 graph()->NewNode(common()->Branch(BranchHint::kFalse), is_smi, control);
1065 if_is_smi = graph()->NewNode(common()->IfTrue(), branch_is_smi);
1066 e_is_smi = effect;
1067 control = graph()->NewNode(common()->IfFalse(), branch_is_smi);
1068 }
1069
1070 Node* object_map = effect =
1071 graph()->NewNode(simplified()->LoadField(AccessBuilder::ForMap()),
1072 r.left(), effect, control);
1073
1074 // Loop through the {object}s prototype chain looking for the {prototype}.
1075 Node* loop = control = graph()->NewNode(common()->Loop(2), control, control);
1076
1077 Node* loop_effect = effect =
1078 graph()->NewNode(common()->EffectPhi(2), effect, effect, loop);
1079
1080 Node* loop_object_map =
1081 graph()->NewNode(common()->Phi(MachineRepresentation::kTagged, 2),
1082 object_map, r.left(), loop);
1083
1084 // Check if the lhs needs access checks.
1085 Node* map_bit_field = effect =
1086 graph()->NewNode(simplified()->LoadField(AccessBuilder::ForMapBitField()),
1087 loop_object_map, loop_effect, control);
1088 int is_access_check_needed_bit = 1 << Map::kIsAccessCheckNeeded;
1089 Node* is_access_check_needed_num =
1090 graph()->NewNode(simplified()->NumberBitwiseAnd(), map_bit_field,
1091 jsgraph()->Uint32Constant(is_access_check_needed_bit));
1092 Node* is_access_check_needed =
1093 graph()->NewNode(machine()->Word32Equal(), is_access_check_needed_num,
1094 jsgraph()->Uint32Constant(is_access_check_needed_bit));
1095
1096 Node* branch_is_access_check_needed = graph()->NewNode(
1097 common()->Branch(BranchHint::kFalse), is_access_check_needed, control);
1098 Node* if_is_access_check_needed =
1099 graph()->NewNode(common()->IfTrue(), branch_is_access_check_needed);
1100 Node* e_is_access_check_needed = effect;
1101
1102 control =
1103 graph()->NewNode(common()->IfFalse(), branch_is_access_check_needed);
1104
1105 // Check if the lhs is a proxy.
1106 Node* map_instance_type = effect = graph()->NewNode(
1107 simplified()->LoadField(AccessBuilder::ForMapInstanceType()),
1108 loop_object_map, loop_effect, control);
1109 Node* is_proxy = graph()->NewNode(machine()->Word32Equal(), map_instance_type,
1110 jsgraph()->Uint32Constant(JS_PROXY_TYPE));
1111 Node* branch_is_proxy =
1112 graph()->NewNode(common()->Branch(BranchHint::kFalse), is_proxy, control);
1113 Node* if_is_proxy = graph()->NewNode(common()->IfTrue(), branch_is_proxy);
1114 Node* e_is_proxy = effect;
1115
1116
1117 Node* runtime_has_in_proto_chain = control = graph()->NewNode(
1118 common()->Merge(2), if_is_access_check_needed, if_is_proxy);
1119 effect = graph()->NewNode(common()->EffectPhi(2), e_is_access_check_needed,
1120 e_is_proxy, control);
1121
1122 // If we need an access check or the object is a Proxy, make a runtime call
1123 // to finish the lowering.
1124 Node* bool_result_runtime_has_in_proto_chain_case = graph()->NewNode(
Ben Murdoch097c5b22016-05-18 11:27:45 +01001125 javascript()->CallRuntime(Runtime::kHasInPrototypeChain), r.left(),
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001126 prototype, context, frame_state, effect, control);
1127
1128 control = graph()->NewNode(common()->IfFalse(), branch_is_proxy);
1129
1130 Node* object_prototype = effect = graph()->NewNode(
1131 simplified()->LoadField(AccessBuilder::ForMapPrototype()),
1132 loop_object_map, loop_effect, control);
1133
1134 // Check if object prototype is equal to function prototype.
1135 Node* eq_proto =
1136 graph()->NewNode(simplified()->ReferenceEqual(r.right_type()),
1137 object_prototype, prototype);
1138 Node* branch_eq_proto =
1139 graph()->NewNode(common()->Branch(BranchHint::kFalse), eq_proto, control);
1140 Node* if_eq_proto = graph()->NewNode(common()->IfTrue(), branch_eq_proto);
1141 Node* e_eq_proto = effect;
1142
1143 control = graph()->NewNode(common()->IfFalse(), branch_eq_proto);
1144
1145 // If not, check if object prototype is the null prototype.
1146 Node* null_proto =
1147 graph()->NewNode(simplified()->ReferenceEqual(r.right_type()),
1148 object_prototype, jsgraph()->NullConstant());
1149 Node* branch_null_proto = graph()->NewNode(
1150 common()->Branch(BranchHint::kFalse), null_proto, control);
1151 Node* if_null_proto = graph()->NewNode(common()->IfTrue(), branch_null_proto);
1152 Node* e_null_proto = effect;
1153
1154 control = graph()->NewNode(common()->IfFalse(), branch_null_proto);
1155 Node* load_object_map = effect =
1156 graph()->NewNode(simplified()->LoadField(AccessBuilder::ForMap()),
1157 object_prototype, effect, control);
1158 // Close the loop.
1159 loop_effect->ReplaceInput(1, effect);
1160 loop_object_map->ReplaceInput(1, load_object_map);
1161 loop->ReplaceInput(1, control);
1162
1163 control = graph()->NewNode(common()->Merge(3), runtime_has_in_proto_chain,
1164 if_eq_proto, if_null_proto);
1165 effect = graph()->NewNode(common()->EffectPhi(3),
1166 bool_result_runtime_has_in_proto_chain_case,
1167 e_eq_proto, e_null_proto, control);
1168
1169 Node* result = graph()->NewNode(
1170 common()->Phi(MachineRepresentation::kTagged, 3),
1171 bool_result_runtime_has_in_proto_chain_case, jsgraph()->TrueConstant(),
1172 jsgraph()->FalseConstant(), control);
1173
1174 if (if_is_smi != nullptr) {
1175 DCHECK_NOT_NULL(e_is_smi);
1176 control = graph()->NewNode(common()->Merge(2), if_is_smi, control);
1177 effect =
1178 graph()->NewNode(common()->EffectPhi(2), e_is_smi, effect, control);
1179 result = graph()->NewNode(common()->Phi(MachineRepresentation::kTagged, 2),
1180 jsgraph()->FalseConstant(), result, control);
1181 }
1182
1183 ReplaceWithValue(node, result, effect, control);
1184 return Changed(result);
1185}
1186
1187
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001188Reduction JSTypedLowering::ReduceJSLoadContext(Node* node) {
1189 DCHECK_EQ(IrOpcode::kJSLoadContext, node->opcode());
1190 ContextAccess const& access = ContextAccessOf(node->op());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001191 Node* effect = NodeProperties::GetEffectInput(node);
1192 Node* control = graph()->start();
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001193 for (size_t i = 0; i < access.depth(); ++i) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001194 Node* previous = effect = graph()->NewNode(
1195 simplified()->LoadField(
1196 AccessBuilder::ForContextSlot(Context::PREVIOUS_INDEX)),
1197 NodeProperties::GetValueInput(node, 0), effect, control);
1198 node->ReplaceInput(0, previous);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001199 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001200 node->ReplaceInput(1, effect);
1201 node->ReplaceInput(2, control);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001202 NodeProperties::ChangeOp(
1203 node,
1204 simplified()->LoadField(AccessBuilder::ForContextSlot(access.index())));
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001205 return Changed(node);
1206}
1207
1208
1209Reduction JSTypedLowering::ReduceJSStoreContext(Node* node) {
1210 DCHECK_EQ(IrOpcode::kJSStoreContext, node->opcode());
1211 ContextAccess const& access = ContextAccessOf(node->op());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001212 Node* effect = NodeProperties::GetEffectInput(node);
1213 Node* control = graph()->start();
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001214 for (size_t i = 0; i < access.depth(); ++i) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001215 Node* previous = effect = graph()->NewNode(
1216 simplified()->LoadField(
1217 AccessBuilder::ForContextSlot(Context::PREVIOUS_INDEX)),
1218 NodeProperties::GetValueInput(node, 0), effect, control);
1219 node->ReplaceInput(0, previous);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001220 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001221 node->RemoveInput(2);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001222 node->ReplaceInput(2, effect);
1223 NodeProperties::ChangeOp(
1224 node,
1225 simplified()->StoreField(AccessBuilder::ForContextSlot(access.index())));
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001226 return Changed(node);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001227}
1228
1229
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001230Reduction JSTypedLowering::ReduceJSConvertReceiver(Node* node) {
1231 DCHECK_EQ(IrOpcode::kJSConvertReceiver, node->opcode());
1232 ConvertReceiverMode mode = ConvertReceiverModeOf(node->op());
1233 Node* receiver = NodeProperties::GetValueInput(node, 0);
1234 Type* receiver_type = NodeProperties::GetType(receiver);
1235 Node* context = NodeProperties::GetContextInput(node);
1236 Type* context_type = NodeProperties::GetType(context);
1237 Node* frame_state = NodeProperties::GetFrameStateInput(node, 0);
1238 Node* effect = NodeProperties::GetEffectInput(node);
1239 Node* control = NodeProperties::GetControlInput(node);
1240 if (!receiver_type->Is(Type::Receiver())) {
1241 if (receiver_type->Is(Type::NullOrUndefined()) ||
1242 mode == ConvertReceiverMode::kNullOrUndefined) {
1243 if (context_type->IsConstant()) {
1244 Handle<JSObject> global_proxy(
1245 Handle<Context>::cast(context_type->AsConstant()->Value())
1246 ->global_proxy(),
1247 isolate());
1248 receiver = jsgraph()->Constant(global_proxy);
1249 } else {
1250 Node* native_context = effect = graph()->NewNode(
1251 javascript()->LoadContext(0, Context::NATIVE_CONTEXT_INDEX, true),
1252 context, context, effect);
1253 receiver = effect = graph()->NewNode(
1254 javascript()->LoadContext(0, Context::GLOBAL_PROXY_INDEX, true),
1255 native_context, native_context, effect);
1256 }
1257 } else if (!receiver_type->Maybe(Type::NullOrUndefined()) ||
1258 mode == ConvertReceiverMode::kNotNullOrUndefined) {
1259 receiver = effect =
1260 graph()->NewNode(javascript()->ToObject(), receiver, context,
1261 frame_state, effect, control);
1262 } else {
1263 // Check {receiver} for undefined.
1264 Node* check0 =
1265 graph()->NewNode(simplified()->ReferenceEqual(receiver_type),
1266 receiver, jsgraph()->UndefinedConstant());
1267 Node* branch0 = graph()->NewNode(common()->Branch(BranchHint::kFalse),
1268 check0, control);
1269 Node* if_true0 = graph()->NewNode(common()->IfTrue(), branch0);
1270 Node* if_false0 = graph()->NewNode(common()->IfFalse(), branch0);
1271
1272 // Check {receiver} for null.
1273 Node* check1 =
1274 graph()->NewNode(simplified()->ReferenceEqual(receiver_type),
1275 receiver, jsgraph()->NullConstant());
1276 Node* branch1 = graph()->NewNode(common()->Branch(BranchHint::kFalse),
1277 check1, if_false0);
1278 Node* if_true1 = graph()->NewNode(common()->IfTrue(), branch1);
1279 Node* if_false1 = graph()->NewNode(common()->IfFalse(), branch1);
1280
1281 // Convert {receiver} using ToObject.
1282 Node* if_convert = if_false1;
1283 Node* econvert = effect;
1284 Node* rconvert;
1285 {
1286 rconvert = econvert =
1287 graph()->NewNode(javascript()->ToObject(), receiver, context,
1288 frame_state, econvert, if_convert);
1289 }
1290
1291 // Replace {receiver} with global proxy of {context}.
1292 Node* if_global =
1293 graph()->NewNode(common()->Merge(2), if_true0, if_true1);
1294 Node* eglobal = effect;
1295 Node* rglobal;
1296 {
1297 if (context_type->IsConstant()) {
1298 Handle<JSObject> global_proxy(
1299 Handle<Context>::cast(context_type->AsConstant()->Value())
1300 ->global_proxy(),
1301 isolate());
1302 rglobal = jsgraph()->Constant(global_proxy);
1303 } else {
1304 Node* native_context = eglobal = graph()->NewNode(
1305 javascript()->LoadContext(0, Context::NATIVE_CONTEXT_INDEX, true),
1306 context, context, eglobal);
1307 rglobal = eglobal = graph()->NewNode(
1308 javascript()->LoadContext(0, Context::GLOBAL_PROXY_INDEX, true),
1309 native_context, native_context, eglobal);
1310 }
1311 }
1312
1313 control = graph()->NewNode(common()->Merge(2), if_convert, if_global);
1314 effect =
1315 graph()->NewNode(common()->EffectPhi(2), econvert, eglobal, control);
1316 receiver =
1317 graph()->NewNode(common()->Phi(MachineRepresentation::kTagged, 2),
1318 rconvert, rglobal, control);
1319 }
1320 }
1321 ReplaceWithValue(node, receiver, effect, control);
1322 return Changed(receiver);
1323}
1324
1325
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001326Reduction JSTypedLowering::ReduceJSCallConstruct(Node* node) {
1327 DCHECK_EQ(IrOpcode::kJSCallConstruct, node->opcode());
1328 CallConstructParameters const& p = CallConstructParametersOf(node->op());
1329 DCHECK_LE(2u, p.arity());
1330 int const arity = static_cast<int>(p.arity() - 2);
1331 Node* target = NodeProperties::GetValueInput(node, 0);
1332 Type* target_type = NodeProperties::GetType(target);
1333 Node* new_target = NodeProperties::GetValueInput(node, arity + 1);
1334
1335 // Check if {target} is a known JSFunction.
1336 if (target_type->IsConstant() &&
1337 target_type->AsConstant()->Value()->IsJSFunction()) {
1338 Handle<JSFunction> function =
1339 Handle<JSFunction>::cast(target_type->AsConstant()->Value());
1340 Handle<SharedFunctionInfo> shared(function->shared(), isolate());
1341
1342 // Remove the eager bailout frame state.
1343 NodeProperties::RemoveFrameStateInput(node, 1);
1344
1345 // Patch {node} to an indirect call via the {function}s construct stub.
1346 Callable callable(handle(shared->construct_stub(), isolate()),
1347 ConstructStubDescriptor(isolate()));
1348 node->RemoveInput(arity + 1);
1349 node->InsertInput(graph()->zone(), 0,
1350 jsgraph()->HeapConstant(callable.code()));
1351 node->InsertInput(graph()->zone(), 2, new_target);
1352 node->InsertInput(graph()->zone(), 3, jsgraph()->Int32Constant(arity));
1353 node->InsertInput(graph()->zone(), 4, jsgraph()->UndefinedConstant());
1354 node->InsertInput(graph()->zone(), 5, jsgraph()->UndefinedConstant());
1355 NodeProperties::ChangeOp(
1356 node, common()->Call(Linkage::GetStubCallDescriptor(
1357 isolate(), graph()->zone(), callable.descriptor(), 1 + arity,
1358 CallDescriptor::kNeedsFrameState)));
1359 return Changed(node);
1360 }
1361
1362 // Check if {target} is a JSFunction.
1363 if (target_type->Is(Type::Function())) {
1364 // Remove the eager bailout frame state.
1365 NodeProperties::RemoveFrameStateInput(node, 1);
1366
1367 // Patch {node} to an indirect call via the ConstructFunction builtin.
1368 Callable callable = CodeFactory::ConstructFunction(isolate());
1369 node->RemoveInput(arity + 1);
1370 node->InsertInput(graph()->zone(), 0,
1371 jsgraph()->HeapConstant(callable.code()));
1372 node->InsertInput(graph()->zone(), 2, new_target);
1373 node->InsertInput(graph()->zone(), 3, jsgraph()->Int32Constant(arity));
1374 node->InsertInput(graph()->zone(), 4, jsgraph()->UndefinedConstant());
1375 NodeProperties::ChangeOp(
1376 node, common()->Call(Linkage::GetStubCallDescriptor(
1377 isolate(), graph()->zone(), callable.descriptor(), 1 + arity,
1378 CallDescriptor::kNeedsFrameState)));
1379 return Changed(node);
1380 }
1381
1382 return NoChange();
1383}
1384
1385
1386Reduction JSTypedLowering::ReduceJSCallFunction(Node* node) {
1387 DCHECK_EQ(IrOpcode::kJSCallFunction, node->opcode());
1388 CallFunctionParameters const& p = CallFunctionParametersOf(node->op());
1389 int const arity = static_cast<int>(p.arity() - 2);
1390 ConvertReceiverMode convert_mode = p.convert_mode();
1391 Node* target = NodeProperties::GetValueInput(node, 0);
1392 Type* target_type = NodeProperties::GetType(target);
1393 Node* receiver = NodeProperties::GetValueInput(node, 1);
1394 Type* receiver_type = NodeProperties::GetType(receiver);
1395 Node* frame_state = NodeProperties::GetFrameStateInput(node, 1);
1396 Node* effect = NodeProperties::GetEffectInput(node);
1397 Node* control = NodeProperties::GetControlInput(node);
1398
1399 // Try to infer receiver {convert_mode} from {receiver} type.
1400 if (receiver_type->Is(Type::NullOrUndefined())) {
1401 convert_mode = ConvertReceiverMode::kNullOrUndefined;
1402 } else if (!receiver_type->Maybe(Type::NullOrUndefined())) {
1403 convert_mode = ConvertReceiverMode::kNotNullOrUndefined;
1404 }
1405
1406 // Check if {target} is a known JSFunction.
1407 if (target_type->IsConstant() &&
1408 target_type->AsConstant()->Value()->IsJSFunction()) {
1409 Handle<JSFunction> function =
1410 Handle<JSFunction>::cast(target_type->AsConstant()->Value());
1411 Handle<SharedFunctionInfo> shared(function->shared(), isolate());
1412
1413 // Class constructors are callable, but [[Call]] will raise an exception.
1414 // See ES6 section 9.2.1 [[Call]] ( thisArgument, argumentsList ).
1415 if (IsClassConstructor(shared->kind())) return NoChange();
1416
1417 // Load the context from the {target}.
1418 Node* context = effect = graph()->NewNode(
1419 simplified()->LoadField(AccessBuilder::ForJSFunctionContext()), target,
1420 effect, control);
1421 NodeProperties::ReplaceContextInput(node, context);
1422
1423 // Check if we need to convert the {receiver}.
1424 if (is_sloppy(shared->language_mode()) && !shared->native() &&
1425 !receiver_type->Is(Type::Receiver())) {
1426 receiver = effect =
1427 graph()->NewNode(javascript()->ConvertReceiver(convert_mode),
1428 receiver, context, frame_state, effect, control);
1429 NodeProperties::ReplaceValueInput(node, receiver, 1);
1430 }
1431
1432 // Update the effect dependency for the {node}.
1433 NodeProperties::ReplaceEffectInput(node, effect);
1434
1435 // Remove the eager bailout frame state.
1436 NodeProperties::RemoveFrameStateInput(node, 1);
1437
1438 // Compute flags for the call.
1439 CallDescriptor::Flags flags = CallDescriptor::kNeedsFrameState;
1440 if (p.tail_call_mode() == TailCallMode::kAllow) {
1441 flags |= CallDescriptor::kSupportsTailCalls;
1442 }
1443
1444 Node* new_target = jsgraph()->UndefinedConstant();
1445 Node* argument_count = jsgraph()->Int32Constant(arity);
1446 if (shared->internal_formal_parameter_count() == arity ||
1447 shared->internal_formal_parameter_count() ==
1448 SharedFunctionInfo::kDontAdaptArgumentsSentinel) {
1449 // Patch {node} to a direct call.
1450 node->InsertInput(graph()->zone(), arity + 2, new_target);
1451 node->InsertInput(graph()->zone(), arity + 3, argument_count);
1452 NodeProperties::ChangeOp(node,
1453 common()->Call(Linkage::GetJSCallDescriptor(
1454 graph()->zone(), false, 1 + arity, flags)));
1455 } else {
1456 // Patch {node} to an indirect call via the ArgumentsAdaptorTrampoline.
1457 Callable callable = CodeFactory::ArgumentAdaptor(isolate());
1458 node->InsertInput(graph()->zone(), 0,
1459 jsgraph()->HeapConstant(callable.code()));
1460 node->InsertInput(graph()->zone(), 2, new_target);
1461 node->InsertInput(graph()->zone(), 3, argument_count);
1462 node->InsertInput(
1463 graph()->zone(), 4,
1464 jsgraph()->Int32Constant(shared->internal_formal_parameter_count()));
1465 NodeProperties::ChangeOp(
1466 node, common()->Call(Linkage::GetStubCallDescriptor(
1467 isolate(), graph()->zone(), callable.descriptor(),
1468 1 + arity, flags)));
1469 }
1470 return Changed(node);
1471 }
1472
1473 // Check if {target} is a JSFunction.
1474 if (target_type->Is(Type::Function())) {
1475 // Remove the eager bailout frame state.
1476 NodeProperties::RemoveFrameStateInput(node, 1);
1477
1478 // Compute flags for the call.
1479 CallDescriptor::Flags flags = CallDescriptor::kNeedsFrameState;
1480 if (p.tail_call_mode() == TailCallMode::kAllow) {
1481 flags |= CallDescriptor::kSupportsTailCalls;
1482 }
1483
1484 // Patch {node} to an indirect call via the CallFunction builtin.
1485 Callable callable = CodeFactory::CallFunction(isolate(), convert_mode);
1486 node->InsertInput(graph()->zone(), 0,
1487 jsgraph()->HeapConstant(callable.code()));
1488 node->InsertInput(graph()->zone(), 2, jsgraph()->Int32Constant(arity));
1489 NodeProperties::ChangeOp(
1490 node, common()->Call(Linkage::GetStubCallDescriptor(
1491 isolate(), graph()->zone(), callable.descriptor(), 1 + arity,
1492 flags)));
1493 return Changed(node);
1494 }
1495
1496 // Maybe we did at least learn something about the {receiver}.
1497 if (p.convert_mode() != convert_mode) {
1498 NodeProperties::ChangeOp(
Ben Murdoch097c5b22016-05-18 11:27:45 +01001499 node, javascript()->CallFunction(p.arity(), p.feedback(), convert_mode,
1500 p.tail_call_mode()));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001501 return Changed(node);
1502 }
1503
1504 return NoChange();
1505}
1506
1507
1508Reduction JSTypedLowering::ReduceJSForInDone(Node* node) {
1509 DCHECK_EQ(IrOpcode::kJSForInDone, node->opcode());
1510 node->TrimInputCount(2);
1511 NodeProperties::ChangeOp(node, machine()->Word32Equal());
1512 return Changed(node);
1513}
1514
1515
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001516Reduction JSTypedLowering::ReduceJSForInNext(Node* node) {
1517 DCHECK_EQ(IrOpcode::kJSForInNext, node->opcode());
1518 Node* receiver = NodeProperties::GetValueInput(node, 0);
1519 Node* cache_array = NodeProperties::GetValueInput(node, 1);
1520 Node* cache_type = NodeProperties::GetValueInput(node, 2);
1521 Node* index = NodeProperties::GetValueInput(node, 3);
1522 Node* context = NodeProperties::GetContextInput(node);
1523 Node* frame_state = NodeProperties::GetFrameStateInput(node, 0);
1524 Node* effect = NodeProperties::GetEffectInput(node);
1525 Node* control = NodeProperties::GetControlInput(node);
1526
1527 // Load the next {key} from the {cache_array}.
1528 Node* key = effect = graph()->NewNode(
1529 simplified()->LoadElement(AccessBuilder::ForFixedArrayElement()),
1530 cache_array, index, effect, control);
1531
1532 // Load the map of the {receiver}.
1533 Node* receiver_map = effect =
1534 graph()->NewNode(simplified()->LoadField(AccessBuilder::ForMap()),
1535 receiver, effect, control);
1536
1537 // Check if the expected map still matches that of the {receiver}.
1538 Node* check0 = graph()->NewNode(simplified()->ReferenceEqual(Type::Any()),
1539 receiver_map, cache_type);
1540 Node* branch0 =
1541 graph()->NewNode(common()->Branch(BranchHint::kTrue), check0, control);
1542
1543 Node* if_true0 = graph()->NewNode(common()->IfTrue(), branch0);
1544 Node* etrue0;
1545 Node* vtrue0;
1546 {
1547 // Don't need filtering since expected map still matches that of the
1548 // {receiver}.
1549 etrue0 = effect;
1550 vtrue0 = key;
1551 }
1552
1553 Node* if_false0 = graph()->NewNode(common()->IfFalse(), branch0);
1554 Node* efalse0;
1555 Node* vfalse0;
1556 {
Ben Murdoch097c5b22016-05-18 11:27:45 +01001557 // Filter the {key} to check if it's still a valid property of the
1558 // {receiver} (does the ToName conversion implicitly).
1559 vfalse0 = efalse0 = graph()->NewNode(
1560 javascript()->CallRuntime(Runtime::kForInFilter), receiver, key,
1561 context, frame_state, effect, if_false0);
1562 if_false0 = graph()->NewNode(common()->IfSuccess(), vfalse0);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001563 }
1564
1565 control = graph()->NewNode(common()->Merge(2), if_true0, if_false0);
1566 effect = graph()->NewNode(common()->EffectPhi(2), etrue0, efalse0, control);
1567 ReplaceWithValue(node, node, effect, control);
1568 node->ReplaceInput(0, vtrue0);
1569 node->ReplaceInput(1, vfalse0);
1570 node->ReplaceInput(2, control);
1571 node->TrimInputCount(3);
1572 NodeProperties::ChangeOp(node,
1573 common()->Phi(MachineRepresentation::kTagged, 2));
1574 return Changed(node);
1575}
1576
1577
1578Reduction JSTypedLowering::ReduceJSForInStep(Node* node) {
1579 DCHECK_EQ(IrOpcode::kJSForInStep, node->opcode());
1580 node->ReplaceInput(1, jsgraph()->Int32Constant(1));
1581 NodeProperties::ChangeOp(node, machine()->Int32Add());
1582 return Changed(node);
1583}
1584
1585
1586Reduction JSTypedLowering::ReduceSelect(Node* node) {
1587 DCHECK_EQ(IrOpcode::kSelect, node->opcode());
1588 Node* const condition = NodeProperties::GetValueInput(node, 0);
1589 Type* const condition_type = NodeProperties::GetType(condition);
1590 Node* const vtrue = NodeProperties::GetValueInput(node, 1);
1591 Type* const vtrue_type = NodeProperties::GetType(vtrue);
1592 Node* const vfalse = NodeProperties::GetValueInput(node, 2);
1593 Type* const vfalse_type = NodeProperties::GetType(vfalse);
1594 if (condition_type->Is(true_type_)) {
1595 // Select(condition:true, vtrue, vfalse) => vtrue
1596 return Replace(vtrue);
1597 }
1598 if (condition_type->Is(false_type_)) {
1599 // Select(condition:false, vtrue, vfalse) => vfalse
1600 return Replace(vfalse);
1601 }
1602 if (vtrue_type->Is(true_type_) && vfalse_type->Is(false_type_)) {
1603 // Select(condition, vtrue:true, vfalse:false) => condition
1604 return Replace(condition);
1605 }
1606 if (vtrue_type->Is(false_type_) && vfalse_type->Is(true_type_)) {
1607 // Select(condition, vtrue:false, vfalse:true) => BooleanNot(condition)
1608 node->TrimInputCount(1);
1609 NodeProperties::ChangeOp(node, simplified()->BooleanNot());
1610 return Changed(node);
1611 }
1612 return NoChange();
1613}
1614
1615
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001616Reduction JSTypedLowering::Reduce(Node* node) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001617 // Check if the output type is a singleton. In that case we already know the
1618 // result value and can simply replace the node if it's eliminable.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001619 if (!NodeProperties::IsConstant(node) && NodeProperties::IsTyped(node) &&
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001620 node->op()->HasProperty(Operator::kEliminatable)) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001621 Type* upper = NodeProperties::GetType(node);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001622 if (upper->IsConstant()) {
1623 Node* replacement = jsgraph()->Constant(upper->AsConstant()->Value());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001624 ReplaceWithValue(node, replacement);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001625 return Changed(replacement);
1626 } else if (upper->Is(Type::MinusZero())) {
1627 Node* replacement = jsgraph()->Constant(factory()->minus_zero_value());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001628 ReplaceWithValue(node, replacement);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001629 return Changed(replacement);
1630 } else if (upper->Is(Type::NaN())) {
1631 Node* replacement = jsgraph()->NaNConstant();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001632 ReplaceWithValue(node, replacement);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001633 return Changed(replacement);
1634 } else if (upper->Is(Type::Null())) {
1635 Node* replacement = jsgraph()->NullConstant();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001636 ReplaceWithValue(node, replacement);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001637 return Changed(replacement);
1638 } else if (upper->Is(Type::PlainNumber()) && upper->Min() == upper->Max()) {
1639 Node* replacement = jsgraph()->Constant(upper->Min());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001640 ReplaceWithValue(node, replacement);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001641 return Changed(replacement);
1642 } else if (upper->Is(Type::Undefined())) {
1643 Node* replacement = jsgraph()->UndefinedConstant();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001644 ReplaceWithValue(node, replacement);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001645 return Changed(replacement);
1646 }
1647 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001648 switch (node->opcode()) {
1649 case IrOpcode::kJSEqual:
1650 return ReduceJSEqual(node, false);
1651 case IrOpcode::kJSNotEqual:
1652 return ReduceJSEqual(node, true);
1653 case IrOpcode::kJSStrictEqual:
1654 return ReduceJSStrictEqual(node, false);
1655 case IrOpcode::kJSStrictNotEqual:
1656 return ReduceJSStrictEqual(node, true);
1657 case IrOpcode::kJSLessThan: // fall through
1658 case IrOpcode::kJSGreaterThan: // fall through
1659 case IrOpcode::kJSLessThanOrEqual: // fall through
1660 case IrOpcode::kJSGreaterThanOrEqual:
1661 return ReduceJSComparison(node);
1662 case IrOpcode::kJSBitwiseOr:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001663 return ReduceInt32Binop(node, simplified()->NumberBitwiseOr());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001664 case IrOpcode::kJSBitwiseXor:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001665 return ReduceInt32Binop(node, simplified()->NumberBitwiseXor());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001666 case IrOpcode::kJSBitwiseAnd:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001667 return ReduceInt32Binop(node, simplified()->NumberBitwiseAnd());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001668 case IrOpcode::kJSShiftLeft:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001669 return ReduceUI32Shift(node, kSigned, simplified()->NumberShiftLeft());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001670 case IrOpcode::kJSShiftRight:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001671 return ReduceUI32Shift(node, kSigned, simplified()->NumberShiftRight());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001672 case IrOpcode::kJSShiftRightLogical:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001673 return ReduceUI32Shift(node, kUnsigned,
1674 simplified()->NumberShiftRightLogical());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001675 case IrOpcode::kJSAdd:
1676 return ReduceJSAdd(node);
1677 case IrOpcode::kJSSubtract:
1678 return ReduceNumberBinop(node, simplified()->NumberSubtract());
1679 case IrOpcode::kJSMultiply:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001680 return ReduceNumberBinop(node, simplified()->NumberMultiply());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001681 case IrOpcode::kJSDivide:
1682 return ReduceNumberBinop(node, simplified()->NumberDivide());
1683 case IrOpcode::kJSModulus:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001684 return ReduceJSModulus(node);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001685 case IrOpcode::kJSToBoolean:
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001686 return ReduceJSToBoolean(node);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001687 case IrOpcode::kJSToNumber:
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001688 return ReduceJSToNumber(node);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001689 case IrOpcode::kJSToString:
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001690 return ReduceJSToString(node);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001691 case IrOpcode::kJSToObject:
1692 return ReduceJSToObject(node);
1693 case IrOpcode::kJSLoadNamed:
1694 return ReduceJSLoadNamed(node);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001695 case IrOpcode::kJSLoadProperty:
1696 return ReduceJSLoadProperty(node);
1697 case IrOpcode::kJSStoreProperty:
1698 return ReduceJSStoreProperty(node);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001699 case IrOpcode::kJSInstanceOf:
1700 return ReduceJSInstanceOf(node);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001701 case IrOpcode::kJSLoadContext:
1702 return ReduceJSLoadContext(node);
1703 case IrOpcode::kJSStoreContext:
1704 return ReduceJSStoreContext(node);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001705 case IrOpcode::kJSConvertReceiver:
1706 return ReduceJSConvertReceiver(node);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001707 case IrOpcode::kJSCallConstruct:
1708 return ReduceJSCallConstruct(node);
1709 case IrOpcode::kJSCallFunction:
1710 return ReduceJSCallFunction(node);
1711 case IrOpcode::kJSForInDone:
1712 return ReduceJSForInDone(node);
1713 case IrOpcode::kJSForInNext:
1714 return ReduceJSForInNext(node);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001715 case IrOpcode::kJSForInStep:
1716 return ReduceJSForInStep(node);
1717 case IrOpcode::kSelect:
1718 return ReduceSelect(node);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001719 default:
1720 break;
1721 }
1722 return NoChange();
1723}
1724
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001725
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001726Node* JSTypedLowering::Word32Shl(Node* const lhs, int32_t const rhs) {
1727 if (rhs == 0) return lhs;
1728 return graph()->NewNode(machine()->Word32Shl(), lhs,
1729 jsgraph()->Int32Constant(rhs));
1730}
1731
1732
1733Factory* JSTypedLowering::factory() const { return jsgraph()->factory(); }
1734
1735
1736Graph* JSTypedLowering::graph() const { return jsgraph()->graph(); }
1737
1738
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001739Isolate* JSTypedLowering::isolate() const { return jsgraph()->isolate(); }
1740
1741
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001742JSOperatorBuilder* JSTypedLowering::javascript() const {
1743 return jsgraph()->javascript();
1744}
1745
1746
1747CommonOperatorBuilder* JSTypedLowering::common() const {
1748 return jsgraph()->common();
1749}
1750
1751
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001752SimplifiedOperatorBuilder* JSTypedLowering::simplified() const {
1753 return jsgraph()->simplified();
1754}
1755
1756
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001757MachineOperatorBuilder* JSTypedLowering::machine() const {
1758 return jsgraph()->machine();
1759}
1760
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001761
1762CompilationDependencies* JSTypedLowering::dependencies() const {
1763 return dependencies_;
1764}
1765
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001766} // namespace compiler
1767} // namespace internal
1768} // namespace v8