blob: fcfe1345a1b5b91449a0e459c2a25ea51fcb74c5 [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 Murdoch61f157c2016-09-16 13:49:30 +010030 BinaryOperationHints::Hint GetNumberBinaryOperationFeedback() {
31 if (!(lowering_->flags() & JSTypedLowering::kDeoptimizationEnabled) ||
32 !(lowering_->flags() & JSTypedLowering::kTypeFeedbackEnabled)) {
33 return BinaryOperationHints::kAny;
34 }
35 DCHECK_NE(0, node_->op()->ControlOutputCount());
36 DCHECK_EQ(1, node_->op()->EffectOutputCount());
37 DCHECK_EQ(2, OperatorProperties::GetFrameStateInputCount(node_->op()));
38 BinaryOperationHints hints = BinaryOperationHintsOf(node_->op());
39 BinaryOperationHints::Hint combined = hints.combined();
40 if (combined == BinaryOperationHints::kSignedSmall ||
41 combined == BinaryOperationHints::kSigned32 ||
42 combined == BinaryOperationHints::kNumberOrUndefined) {
43 return combined;
44 }
45 return BinaryOperationHints::kAny;
46 }
47
48 CompareOperationHints::Hint GetNumberCompareOperationFeedback() {
49 if (!(lowering_->flags() & JSTypedLowering::kDeoptimizationEnabled) ||
50 !(lowering_->flags() & JSTypedLowering::kTypeFeedbackEnabled)) {
51 return CompareOperationHints::kAny;
52 }
53 DCHECK_NE(0, node_->op()->ControlOutputCount());
54 DCHECK_EQ(1, node_->op()->EffectOutputCount());
55 DCHECK_EQ(2, OperatorProperties::GetFrameStateInputCount(node_->op()));
56 CompareOperationHints hints = CompareOperationHintsOf(node_->op());
57 CompareOperationHints::Hint combined = hints.combined();
58 if (combined == CompareOperationHints::kSignedSmall ||
59 combined == CompareOperationHints::kNumber) {
60 return combined;
61 }
62 return CompareOperationHints::kAny;
63 }
64
65 void ConvertInputsToNumber(Node* frame_state) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000066 // To convert the inputs to numbers, we have to provide frame states
67 // for lazy bailouts in the ToNumber conversions.
68 // We use a little hack here: we take the frame state before the binary
69 // operation and use it to construct the frame states for the conversion
70 // so that after the deoptimization, the binary operation IC gets
71 // already converted values from full code. This way we are sure that we
72 // will not re-do any of the side effects.
73
74 Node* left_input = nullptr;
75 Node* right_input = nullptr;
76 bool left_is_primitive = left_type()->Is(Type::PlainPrimitive());
77 bool right_is_primitive = right_type()->Is(Type::PlainPrimitive());
78 bool handles_exception = NodeProperties::IsExceptionalCall(node_);
79
80 if (!left_is_primitive && !right_is_primitive && handles_exception) {
81 ConvertBothInputsToNumber(&left_input, &right_input, frame_state);
82 } else {
83 left_input = left_is_primitive
Ben Murdoch61f157c2016-09-16 13:49:30 +010084 ? ConvertPlainPrimitiveToNumber(left())
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000085 : ConvertSingleInputToNumber(
86 left(), CreateFrameStateForLeftInput(frame_state));
87 right_input = right_is_primitive
Ben Murdoch61f157c2016-09-16 13:49:30 +010088 ? ConvertPlainPrimitiveToNumber(right())
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000089 : ConvertSingleInputToNumber(
90 right(), CreateFrameStateForRightInput(
91 frame_state, left_input));
92 }
93
94 node_->ReplaceInput(0, left_input);
95 node_->ReplaceInput(1, right_input);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000096 }
97
Emily Bernierd0a1eb72015-03-24 16:35:39 -040098 void ConvertInputsToUI32(Signedness left_signedness,
99 Signedness right_signedness) {
100 node_->ReplaceInput(0, ConvertToUI32(left(), left_signedness));
101 node_->ReplaceInput(1, ConvertToUI32(right(), right_signedness));
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000102 }
103
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000104 void SwapInputs() {
105 Node* l = left();
106 Node* r = right();
107 node_->ReplaceInput(0, r);
108 node_->ReplaceInput(1, l);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000109 }
110
111 // Remove all effect and control inputs and outputs to this node and change
112 // to the pure operator {op}, possibly inserting a boolean inversion.
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400113 Reduction ChangeToPureOperator(const Operator* op, bool invert = false,
114 Type* type = Type::Any()) {
115 DCHECK_EQ(0, op->EffectInputCount());
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000116 DCHECK_EQ(false, OperatorProperties::HasContextInput(op));
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400117 DCHECK_EQ(0, op->ControlInputCount());
118 DCHECK_EQ(2, op->ValueInputCount());
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000119
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000120 // Remove the effects from the node, and update its effect/control usages.
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400121 if (node_->op()->EffectInputCount() > 0) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000122 lowering_->RelaxEffectsAndControls(node_);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000123 }
124 // Remove the inputs corresponding to context, effect, and control.
125 NodeProperties::RemoveNonValueInputs(node_);
126 // Finally, update the operator to the new one.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000127 NodeProperties::ChangeOp(node_, op);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000128
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400129 // TODO(jarin): Replace the explicit typing hack with a call to some method
130 // that encapsulates changing the operator and re-typing.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000131 Type* node_type = NodeProperties::GetType(node_);
132 NodeProperties::SetType(node_, Type::Intersect(node_type, type, zone()));
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400133
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000134 if (invert) {
135 // Insert an boolean not to invert the value.
136 Node* value = graph()->NewNode(simplified()->BooleanNot(), node_);
137 node_->ReplaceUses(value);
138 // Note: ReplaceUses() smashes all uses, so smash it back here.
139 value->ReplaceInput(0, node_);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400140 return lowering_->Replace(value);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000141 }
142 return lowering_->Changed(node_);
143 }
144
Ben Murdoch61f157c2016-09-16 13:49:30 +0100145 Reduction ChangeToSpeculativeOperator(const Operator* op, Type* upper_bound) {
146 DCHECK_EQ(1, op->EffectInputCount());
147 DCHECK_EQ(1, op->EffectOutputCount());
148 DCHECK_EQ(false, OperatorProperties::HasContextInput(op));
149 DCHECK_EQ(1, op->ControlInputCount());
150 DCHECK_EQ(0, op->ControlOutputCount());
151 DCHECK_EQ(0, OperatorProperties::GetFrameStateInputCount(op));
152 DCHECK_EQ(2, op->ValueInputCount());
153
154 DCHECK_EQ(1, node_->op()->EffectInputCount());
155 DCHECK_EQ(1, node_->op()->EffectOutputCount());
156 DCHECK_EQ(1, node_->op()->ControlInputCount());
157 DCHECK_LT(1, node_->op()->ControlOutputCount());
158 DCHECK_EQ(2, OperatorProperties::GetFrameStateInputCount(node_->op()));
159 DCHECK_EQ(2, node_->op()->ValueInputCount());
160
161 // Reconnect the control output to bypass the IfSuccess node and
162 // possibly disconnect from the IfException node.
163 for (Edge edge : node_->use_edges()) {
164 Node* const user = edge.from();
165 DCHECK(!user->IsDead());
166 if (NodeProperties::IsControlEdge(edge)) {
167 if (user->opcode() == IrOpcode::kIfSuccess) {
168 user->ReplaceUses(NodeProperties::GetControlInput(node_));
169 user->Kill();
170 } else {
171 DCHECK_EQ(user->opcode(), IrOpcode::kIfException);
172 edge.UpdateTo(jsgraph()->Dead());
173 }
174 }
175 }
176
177 // Remove both bailout frame states and the context.
178 node_->RemoveInput(NodeProperties::FirstFrameStateIndex(node_) + 1);
179 node_->RemoveInput(NodeProperties::FirstFrameStateIndex(node_));
180 node_->RemoveInput(NodeProperties::FirstContextIndex(node_));
181
182 NodeProperties::ChangeOp(node_, op);
183
184 // Update the type to number.
185 Type* node_type = NodeProperties::GetType(node_);
186 NodeProperties::SetType(node_,
187 Type::Intersect(node_type, upper_bound, zone()));
188
189 return lowering_->Changed(node_);
190 }
191
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400192 Reduction ChangeToPureOperator(const Operator* op, Type* type) {
193 return ChangeToPureOperator(op, false, type);
194 }
195
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000196 bool LeftInputIs(Type* t) { return left_type()->Is(t); }
197
198 bool RightInputIs(Type* t) { return right_type()->Is(t); }
199
200 bool OneInputIs(Type* t) { return LeftInputIs(t) || RightInputIs(t); }
201
202 bool BothInputsAre(Type* t) { return LeftInputIs(t) && RightInputIs(t); }
203
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000204 bool OneInputCannotBe(Type* t) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000205 return !left_type()->Maybe(t) || !right_type()->Maybe(t);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000206 }
207
208 bool NeitherInputCanBe(Type* t) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000209 return !left_type()->Maybe(t) && !right_type()->Maybe(t);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000210 }
211
212 Node* effect() { return NodeProperties::GetEffectInput(node_); }
213 Node* control() { return NodeProperties::GetControlInput(node_); }
214 Node* context() { return NodeProperties::GetContextInput(node_); }
215 Node* left() { return NodeProperties::GetValueInput(node_, 0); }
216 Node* right() { return NodeProperties::GetValueInput(node_, 1); }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000217 Type* left_type() { return NodeProperties::GetType(node_->InputAt(0)); }
218 Type* right_type() { return NodeProperties::GetType(node_->InputAt(1)); }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000219
220 SimplifiedOperatorBuilder* simplified() { return lowering_->simplified(); }
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400221 Graph* graph() const { return lowering_->graph(); }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000222 JSGraph* jsgraph() { return lowering_->jsgraph(); }
223 JSOperatorBuilder* javascript() { return lowering_->javascript(); }
224 MachineOperatorBuilder* machine() { return lowering_->machine(); }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000225 CommonOperatorBuilder* common() { return jsgraph()->common(); }
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400226 Zone* zone() const { return graph()->zone(); }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000227
228 private:
229 JSTypedLowering* lowering_; // The containing lowering instance.
230 Node* node_; // The original node.
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000231
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000232 Node* CreateFrameStateForLeftInput(Node* frame_state) {
233 FrameStateInfo state_info = OpParameter<FrameStateInfo>(frame_state);
234
235 if (state_info.bailout_id() == BailoutId::None()) {
236 // Dummy frame state => just leave it as is.
237 return frame_state;
238 }
239
240 // If the frame state is already the right one, just return it.
241 if (state_info.state_combine().kind() == OutputFrameStateCombine::kPokeAt &&
242 state_info.state_combine().GetOffsetToPokeAt() == 1) {
243 return frame_state;
244 }
245
246 // Here, we smash the result of the conversion into the slot just below
247 // the stack top. This is the slot that full code uses to store the
248 // left operand.
249 const Operator* op = jsgraph()->common()->FrameState(
250 state_info.bailout_id(), OutputFrameStateCombine::PokeAt(1),
251 state_info.function_info());
252
253 return graph()->NewNode(op,
254 frame_state->InputAt(kFrameStateParametersInput),
255 frame_state->InputAt(kFrameStateLocalsInput),
256 frame_state->InputAt(kFrameStateStackInput),
257 frame_state->InputAt(kFrameStateContextInput),
258 frame_state->InputAt(kFrameStateFunctionInput),
259 frame_state->InputAt(kFrameStateOuterStateInput));
260 }
261
262 Node* CreateFrameStateForRightInput(Node* frame_state, Node* converted_left) {
263 FrameStateInfo state_info = OpParameter<FrameStateInfo>(frame_state);
264
265 if (state_info.bailout_id() == BailoutId::None()) {
266 // Dummy frame state => just leave it as is.
267 return frame_state;
268 }
269
270 // Create a frame state that stores the result of the operation to the
271 // top of the stack (i.e., the slot used for the right operand).
272 const Operator* op = jsgraph()->common()->FrameState(
273 state_info.bailout_id(), OutputFrameStateCombine::PokeAt(0),
274 state_info.function_info());
275
276 // Change the left operand {converted_left} on the expression stack.
277 Node* stack = frame_state->InputAt(2);
278 DCHECK_EQ(stack->opcode(), IrOpcode::kStateValues);
279 DCHECK_GE(stack->InputCount(), 2);
280
281 // TODO(jarin) Allocate in a local zone or a reusable buffer.
282 NodeVector new_values(stack->InputCount(), zone());
283 for (int i = 0; i < stack->InputCount(); i++) {
284 if (i == stack->InputCount() - 2) {
285 new_values[i] = converted_left;
286 } else {
287 new_values[i] = stack->InputAt(i);
288 }
289 }
290 Node* new_stack =
291 graph()->NewNode(stack->op(), stack->InputCount(), &new_values.front());
292
293 return graph()->NewNode(
294 op, frame_state->InputAt(kFrameStateParametersInput),
295 frame_state->InputAt(kFrameStateLocalsInput), new_stack,
296 frame_state->InputAt(kFrameStateContextInput),
297 frame_state->InputAt(kFrameStateFunctionInput),
298 frame_state->InputAt(kFrameStateOuterStateInput));
299 }
300
Ben Murdoch61f157c2016-09-16 13:49:30 +0100301 Node* ConvertPlainPrimitiveToNumber(Node* node) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000302 DCHECK(NodeProperties::GetType(node)->Is(Type::PlainPrimitive()));
303 // Avoid inserting too many eager ToNumber() operations.
304 Reduction const reduction = lowering_->ReduceJSToNumberInput(node);
305 if (reduction.Changed()) return reduction.replacement();
Ben Murdoch61f157c2016-09-16 13:49:30 +0100306 if (NodeProperties::GetType(node)->Is(Type::Number())) {
Ben Murdochc5610432016-08-08 18:44:38 +0100307 return node;
308 }
Ben Murdoch61f157c2016-09-16 13:49:30 +0100309 return graph()->NewNode(simplified()->PlainPrimitiveToNumber(), node);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000310 }
311
312 Node* ConvertSingleInputToNumber(Node* node, Node* frame_state) {
313 DCHECK(!NodeProperties::GetType(node)->Is(Type::PlainPrimitive()));
314 Node* const n = graph()->NewNode(javascript()->ToNumber(), node, context(),
315 frame_state, effect(), control());
Ben Murdochc5610432016-08-08 18:44:38 +0100316 Node* const if_success = graph()->NewNode(common()->IfSuccess(), n);
317 NodeProperties::ReplaceControlInput(node_, if_success);
318 NodeProperties::ReplaceUses(node_, node_, node_, node_, n);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000319 update_effect(n);
320 return n;
321 }
322
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000323 void ConvertBothInputsToNumber(Node** left_result, Node** right_result,
324 Node* frame_state) {
325 Node* projections[2];
326
327 // Find {IfSuccess} and {IfException} continuations of the operation.
328 NodeProperties::CollectControlProjections(node_, projections, 2);
329 IfExceptionHint hint = OpParameter<IfExceptionHint>(projections[1]);
330 Node* if_exception = projections[1];
331 Node* if_success = projections[0];
332
333 // Insert two ToNumber() operations that both potentially throw.
334 Node* left_state = CreateFrameStateForLeftInput(frame_state);
335 Node* left_conv =
336 graph()->NewNode(javascript()->ToNumber(), left(), context(),
337 left_state, effect(), control());
338 Node* left_success = graph()->NewNode(common()->IfSuccess(), left_conv);
339 Node* right_state = CreateFrameStateForRightInput(frame_state, left_conv);
340 Node* right_conv =
341 graph()->NewNode(javascript()->ToNumber(), right(), context(),
342 right_state, left_conv, left_success);
343 Node* left_exception =
344 graph()->NewNode(common()->IfException(hint), left_conv, left_conv);
345 Node* right_exception =
346 graph()->NewNode(common()->IfException(hint), right_conv, right_conv);
347 NodeProperties::ReplaceControlInput(if_success, right_conv);
348 update_effect(right_conv);
349
350 // Wire conversions to existing {IfException} continuation.
351 Node* exception_merge = if_exception;
352 Node* exception_value =
353 graph()->NewNode(common()->Phi(MachineRepresentation::kTagged, 2),
354 left_exception, right_exception, exception_merge);
355 Node* exception_effect =
356 graph()->NewNode(common()->EffectPhi(2), left_exception,
357 right_exception, exception_merge);
358 for (Edge edge : exception_merge->use_edges()) {
359 if (NodeProperties::IsEffectEdge(edge)) edge.UpdateTo(exception_effect);
360 if (NodeProperties::IsValueEdge(edge)) edge.UpdateTo(exception_value);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400361 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000362 NodeProperties::RemoveType(exception_merge);
363 exception_merge->ReplaceInput(0, left_exception);
364 exception_merge->ReplaceInput(1, right_exception);
365 NodeProperties::ChangeOp(exception_merge, common()->Merge(2));
366
367 *left_result = left_conv;
368 *right_result = right_conv;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000369 }
370
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400371 Node* ConvertToUI32(Node* node, Signedness signedness) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000372 // Avoid introducing too many eager NumberToXXnt32() operations.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000373 Type* type = NodeProperties::GetType(node);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400374 if (signedness == kSigned) {
375 if (!type->Is(Type::Signed32())) {
376 node = graph()->NewNode(simplified()->NumberToInt32(), node);
377 }
378 } else {
379 DCHECK_EQ(kUnsigned, signedness);
380 if (!type->Is(Type::Unsigned32())) {
381 node = graph()->NewNode(simplified()->NumberToUint32(), node);
382 }
383 }
384 return node;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000385 }
386
387 void update_effect(Node* effect) {
388 NodeProperties::ReplaceEffectInput(node_, effect);
389 }
390};
391
392
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000393// TODO(turbofan): js-typed-lowering improvements possible
394// - immediately put in type bounds for all new nodes
395// - relax effects from generic but not-side-effecting operations
396
397
398JSTypedLowering::JSTypedLowering(Editor* editor,
399 CompilationDependencies* dependencies,
400 Flags flags, JSGraph* jsgraph, Zone* zone)
401 : AdvancedReducer(editor),
402 dependencies_(dependencies),
403 flags_(flags),
404 jsgraph_(jsgraph),
405 true_type_(Type::Constant(factory()->true_value(), graph()->zone())),
406 false_type_(Type::Constant(factory()->false_value(), graph()->zone())),
407 the_hole_type_(
408 Type::Constant(factory()->the_hole_value(), graph()->zone())),
409 type_cache_(TypeCache::Get()) {
410 for (size_t k = 0; k < arraysize(shifted_int32_ranges_); ++k) {
411 double min = kMinInt / (1 << k);
412 double max = kMaxInt / (1 << k);
413 shifted_int32_ranges_[k] = Type::Range(min, max, graph()->zone());
414 }
415}
416
417
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000418Reduction JSTypedLowering::ReduceJSAdd(Node* node) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000419 if (flags() & kDisableBinaryOpReduction) return NoChange();
420
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000421 JSBinopReduction r(this, node);
Ben Murdoch61f157c2016-09-16 13:49:30 +0100422
423 BinaryOperationHints::Hint feedback = r.GetNumberBinaryOperationFeedback();
424 if (feedback == BinaryOperationHints::kNumberOrUndefined &&
425 r.BothInputsAre(Type::PlainPrimitive()) &&
426 r.NeitherInputCanBe(Type::StringOrReceiver())) {
427 // JSAdd(x:-string, y:-string) => NumberAdd(ToNumber(x), ToNumber(y))
428 Node* frame_state = NodeProperties::GetFrameStateInput(node, 1);
429 r.ConvertInputsToNumber(frame_state);
430 return r.ChangeToPureOperator(simplified()->NumberAdd(), Type::Number());
431 }
432 if (feedback != BinaryOperationHints::kAny) {
433 // Lower to the optimistic number binop.
434 return r.ChangeToSpeculativeOperator(
435 simplified()->SpeculativeNumberAdd(feedback), Type::Number());
436 }
437 if (r.BothInputsAre(Type::Number())) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000438 // JSAdd(x:number, y:number) => NumberAdd(x, y)
Ben Murdoch61f157c2016-09-16 13:49:30 +0100439 Node* frame_state = NodeProperties::GetFrameStateInput(node, 1);
440 r.ConvertInputsToNumber(frame_state);
441 return r.ChangeToPureOperator(simplified()->NumberAdd(), Type::Number());
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000442 }
Ben Murdoch097c5b22016-05-18 11:27:45 +0100443 if (r.NeitherInputCanBe(Type::StringOrReceiver())) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000444 // JSAdd(x:-string, y:-string) => NumberAdd(ToNumber(x), ToNumber(y))
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000445 Node* frame_state = NodeProperties::GetFrameStateInput(node, 1);
Ben Murdoch61f157c2016-09-16 13:49:30 +0100446 r.ConvertInputsToNumber(frame_state);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400447 return r.ChangeToPureOperator(simplified()->NumberAdd(), Type::Number());
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000448 }
Ben Murdochc5610432016-08-08 18:44:38 +0100449 if (r.OneInputIs(Type::String())) {
450 StringAddFlags flags = STRING_ADD_CHECK_NONE;
451 if (!r.LeftInputIs(Type::String())) {
452 flags = STRING_ADD_CONVERT_LEFT;
453 } else if (!r.RightInputIs(Type::String())) {
454 flags = STRING_ADD_CONVERT_RIGHT;
455 }
456 // JSAdd(x:string, y) => CallStub[StringAdd](x, y)
457 // JSAdd(x, y:string) => CallStub[StringAdd](x, y)
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000458 Callable const callable =
Ben Murdochc5610432016-08-08 18:44:38 +0100459 CodeFactory::StringAdd(isolate(), flags, NOT_TENURED);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000460 CallDescriptor const* const desc = Linkage::GetStubCallDescriptor(
461 isolate(), graph()->zone(), callable.descriptor(), 0,
462 CallDescriptor::kNeedsFrameState, node->op()->properties());
463 DCHECK_EQ(2, OperatorProperties::GetFrameStateInputCount(node->op()));
464 node->RemoveInput(NodeProperties::FirstFrameStateIndex(node) + 1);
465 node->InsertInput(graph()->zone(), 0,
466 jsgraph()->HeapConstant(callable.code()));
467 NodeProperties::ChangeOp(node, common()->Call(desc));
468 return Changed(node);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400469 }
470 return NoChange();
471}
472
473
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000474Reduction JSTypedLowering::ReduceJSModulus(Node* node) {
475 if (flags() & kDisableBinaryOpReduction) return NoChange();
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400476 JSBinopReduction r(this, node);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000477 if (r.BothInputsAre(Type::Number())) {
478 // JSModulus(x:number, x:number) => NumberModulus(x, y)
479 return r.ChangeToPureOperator(simplified()->NumberModulus(),
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400480 Type::Number());
481 }
Ben Murdoch61f157c2016-09-16 13:49:30 +0100482 BinaryOperationHints::Hint feedback = r.GetNumberBinaryOperationFeedback();
483 if (feedback != BinaryOperationHints::kAny) {
484 return r.ChangeToSpeculativeOperator(
485 simplified()->SpeculativeNumberModulus(feedback), Type::Number());
486 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400487 return NoChange();
488}
489
Ben Murdoch61f157c2016-09-16 13:49:30 +0100490Reduction JSTypedLowering::ReduceJSSubtract(Node* node) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000491 if (flags() & kDisableBinaryOpReduction) return NoChange();
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000492 JSBinopReduction r(this, node);
Ben Murdoch61f157c2016-09-16 13:49:30 +0100493 BinaryOperationHints::Hint feedback = r.GetNumberBinaryOperationFeedback();
494 if (feedback == BinaryOperationHints::kNumberOrUndefined &&
495 r.BothInputsAre(Type::PlainPrimitive())) {
496 // JSSubtract(x:plain-primitive, y:plain-primitive)
497 // => NumberSubtract(ToNumber(x), ToNumber(y))
498 Node* frame_state = NodeProperties::GetFrameStateInput(node, 1);
499 r.ConvertInputsToNumber(frame_state);
500 return r.ChangeToPureOperator(simplified()->NumberSubtract(),
501 Type::Number());
502 }
503 if (feedback != BinaryOperationHints::kAny) {
504 // Lower to the optimistic number binop.
505 return r.ChangeToSpeculativeOperator(
506 simplified()->SpeculativeNumberSubtract(feedback), Type::Number());
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400507 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000508 Node* frame_state = NodeProperties::GetFrameStateInput(node, 1);
Ben Murdoch61f157c2016-09-16 13:49:30 +0100509 r.ConvertInputsToNumber(frame_state);
510 return r.ChangeToPureOperator(simplified()->NumberSubtract(), Type::Number());
511}
512
513Reduction JSTypedLowering::ReduceJSMultiply(Node* node) {
514 if (flags() & kDisableBinaryOpReduction) return NoChange();
515 JSBinopReduction r(this, node);
516
517 BinaryOperationHints::Hint feedback = r.GetNumberBinaryOperationFeedback();
518 if (feedback != BinaryOperationHints::kAny) {
519 return r.ChangeToSpeculativeOperator(
520 simplified()->SpeculativeNumberMultiply(feedback), Type::Number());
521 }
522
523 Node* frame_state = NodeProperties::GetFrameStateInput(node, 1);
524 r.ConvertInputsToNumber(frame_state);
525 return r.ChangeToPureOperator(simplified()->NumberMultiply(), Type::Number());
526}
527
528Reduction JSTypedLowering::ReduceJSDivide(Node* node) {
529 if (flags() & kDisableBinaryOpReduction) return NoChange();
530 JSBinopReduction r(this, node);
531 BinaryOperationHints::Hint feedback = r.GetNumberBinaryOperationFeedback();
532 if (feedback != BinaryOperationHints::kAny) {
533 return r.ChangeToSpeculativeOperator(
534 simplified()->SpeculativeNumberDivide(feedback), Type::Number());
535 }
536 Node* frame_state = NodeProperties::GetFrameStateInput(node, 1);
537 r.ConvertInputsToNumber(frame_state);
538 return r.ChangeToPureOperator(simplified()->NumberDivide(), Type::Number());
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000539}
540
541
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400542Reduction JSTypedLowering::ReduceInt32Binop(Node* node, const Operator* intOp) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000543 if (flags() & kDisableBinaryOpReduction) return NoChange();
544
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000545 JSBinopReduction r(this, node);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000546 Node* frame_state = NodeProperties::GetFrameStateInput(node, 1);
Ben Murdoch61f157c2016-09-16 13:49:30 +0100547 r.ConvertInputsToNumber(frame_state);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000548 r.ConvertInputsToUI32(kSigned, kSigned);
549 return r.ChangeToPureOperator(intOp, Type::Integral32());
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000550}
551
552
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400553Reduction JSTypedLowering::ReduceUI32Shift(Node* node,
554 Signedness left_signedness,
555 const Operator* shift_op) {
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);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000559 Node* frame_state = NodeProperties::GetFrameStateInput(node, 1);
Ben Murdoch61f157c2016-09-16 13:49:30 +0100560 r.ConvertInputsToNumber(frame_state);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000561 r.ConvertInputsToUI32(left_signedness, kUnsigned);
562 return r.ChangeToPureOperator(shift_op);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000563}
564
565
566Reduction JSTypedLowering::ReduceJSComparison(Node* node) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000567 if (flags() & kDisableBinaryOpReduction) return NoChange();
568
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000569 JSBinopReduction r(this, node);
570 if (r.BothInputsAre(Type::String())) {
571 // If both inputs are definitely strings, perform a string comparison.
572 const Operator* stringOp;
573 switch (node->opcode()) {
574 case IrOpcode::kJSLessThan:
575 stringOp = simplified()->StringLessThan();
576 break;
577 case IrOpcode::kJSGreaterThan:
578 stringOp = simplified()->StringLessThan();
579 r.SwapInputs(); // a > b => b < a
580 break;
581 case IrOpcode::kJSLessThanOrEqual:
582 stringOp = simplified()->StringLessThanOrEqual();
583 break;
584 case IrOpcode::kJSGreaterThanOrEqual:
585 stringOp = simplified()->StringLessThanOrEqual();
586 r.SwapInputs(); // a >= b => b <= a
587 break;
588 default:
589 return NoChange();
590 }
Ben Murdochc5610432016-08-08 18:44:38 +0100591 r.ChangeToPureOperator(stringOp);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000592 return Changed(node);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000593 }
Ben Murdoch61f157c2016-09-16 13:49:30 +0100594
595 CompareOperationHints::Hint hint = r.GetNumberCompareOperationFeedback();
596 if (hint != CompareOperationHints::kAny ||
597 r.OneInputCannotBe(Type::StringOrReceiver())) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000598 const Operator* less_than;
599 const Operator* less_than_or_equal;
600 if (r.BothInputsAre(Type::Unsigned32())) {
601 less_than = machine()->Uint32LessThan();
602 less_than_or_equal = machine()->Uint32LessThanOrEqual();
603 } else if (r.BothInputsAre(Type::Signed32())) {
604 less_than = machine()->Int32LessThan();
605 less_than_or_equal = machine()->Int32LessThanOrEqual();
Ben Murdoch61f157c2016-09-16 13:49:30 +0100606 } else if (hint != CompareOperationHints::kAny) {
607 less_than = simplified()->SpeculativeNumberLessThan(hint);
608 less_than_or_equal = simplified()->SpeculativeNumberLessThanOrEqual(hint);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000609 } else {
610 // TODO(turbofan): mixed signed/unsigned int32 comparisons.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000611 Node* frame_state = NodeProperties::GetFrameStateInput(node, 1);
Ben Murdoch61f157c2016-09-16 13:49:30 +0100612 r.ConvertInputsToNumber(frame_state);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000613 less_than = simplified()->NumberLessThan();
614 less_than_or_equal = simplified()->NumberLessThanOrEqual();
615 }
616 const Operator* comparison;
617 switch (node->opcode()) {
618 case IrOpcode::kJSLessThan:
619 comparison = less_than;
620 break;
621 case IrOpcode::kJSGreaterThan:
622 comparison = less_than;
623 r.SwapInputs(); // a > b => b < a
624 break;
625 case IrOpcode::kJSLessThanOrEqual:
626 comparison = less_than_or_equal;
627 break;
628 case IrOpcode::kJSGreaterThanOrEqual:
629 comparison = less_than_or_equal;
630 r.SwapInputs(); // a >= b => b <= a
631 break;
632 default:
633 return NoChange();
634 }
Ben Murdoch61f157c2016-09-16 13:49:30 +0100635 if (comparison->EffectInputCount() > 0) {
636 return r.ChangeToSpeculativeOperator(comparison, Type::Boolean());
637 } else {
638 return r.ChangeToPureOperator(comparison);
639 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000640 }
641 // TODO(turbofan): relax/remove effects of this operator in other cases.
642 return NoChange(); // Keep a generic comparison.
643}
644
Ben Murdochc5610432016-08-08 18:44:38 +0100645Reduction JSTypedLowering::ReduceJSEqualTypeOf(Node* node, bool invert) {
646 HeapObjectBinopMatcher m(node);
647 if (m.left().IsJSTypeOf() && m.right().HasValue() &&
648 m.right().Value()->IsString()) {
649 Node* replacement;
650 Node* input = m.left().InputAt(0);
651 Handle<String> value = Handle<String>::cast(m.right().Value());
652 if (String::Equals(value, factory()->boolean_string())) {
653 replacement = graph()->NewNode(
654 common()->Select(MachineRepresentation::kTagged),
655 graph()->NewNode(simplified()->ReferenceEqual(Type::Any()), input,
656 jsgraph()->TrueConstant()),
657 jsgraph()->TrueConstant(),
658 graph()->NewNode(simplified()->ReferenceEqual(Type::Any()), input,
659 jsgraph()->FalseConstant()));
660 } else if (String::Equals(value, factory()->function_string())) {
661 replacement = graph()->NewNode(simplified()->ObjectIsCallable(), input);
662 } else if (String::Equals(value, factory()->number_string())) {
663 replacement = graph()->NewNode(simplified()->ObjectIsNumber(), input);
664 } else if (String::Equals(value, factory()->string_string())) {
665 replacement = graph()->NewNode(simplified()->ObjectIsString(), input);
666 } else if (String::Equals(value, factory()->undefined_string())) {
667 replacement = graph()->NewNode(
668 common()->Select(MachineRepresentation::kTagged),
669 graph()->NewNode(simplified()->ReferenceEqual(Type::Any()), input,
670 jsgraph()->NullConstant()),
671 jsgraph()->FalseConstant(),
672 graph()->NewNode(simplified()->ObjectIsUndetectable(), input));
673 } else {
674 return NoChange();
675 }
676 if (invert) {
677 replacement = graph()->NewNode(simplified()->BooleanNot(), replacement);
678 }
679 return Replace(replacement);
680 }
681 return NoChange();
682}
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000683
684Reduction JSTypedLowering::ReduceJSEqual(Node* node, bool invert) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000685 if (flags() & kDisableBinaryOpReduction) return NoChange();
686
Ben Murdochc5610432016-08-08 18:44:38 +0100687 Reduction const reduction = ReduceJSEqualTypeOf(node, invert);
688 if (reduction.Changed()) {
689 ReplaceWithValue(node, reduction.replacement());
690 return reduction;
691 }
692
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000693 JSBinopReduction r(this, node);
694
695 if (r.BothInputsAre(Type::Number())) {
696 return r.ChangeToPureOperator(simplified()->NumberEqual(), invert);
697 }
698 if (r.BothInputsAre(Type::String())) {
Ben Murdochc5610432016-08-08 18:44:38 +0100699 return r.ChangeToPureOperator(simplified()->StringEqual(), invert);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000700 }
701 if (r.BothInputsAre(Type::Boolean())) {
702 return r.ChangeToPureOperator(simplified()->ReferenceEqual(Type::Boolean()),
703 invert);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000704 }
705 if (r.BothInputsAre(Type::Receiver())) {
706 return r.ChangeToPureOperator(
707 simplified()->ReferenceEqual(Type::Receiver()), invert);
708 }
Ben Murdochda12d292016-06-02 14:46:10 +0100709 if (r.OneInputIs(Type::Undetectable())) {
710 RelaxEffectsAndControls(node);
711 node->RemoveInput(r.LeftInputIs(Type::Undetectable()) ? 0 : 1);
712 node->TrimInputCount(1);
713 NodeProperties::ChangeOp(node, simplified()->ObjectIsUndetectable());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000714 if (invert) {
715 // Insert an boolean not to invert the value.
716 Node* value = graph()->NewNode(simplified()->BooleanNot(), node);
717 node->ReplaceUses(value);
718 // Note: ReplaceUses() smashes all uses, so smash it back here.
719 value->ReplaceInput(0, node);
720 return Replace(value);
721 }
722 return Changed(node);
723 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000724 return NoChange();
725}
726
727
728Reduction JSTypedLowering::ReduceJSStrictEqual(Node* node, bool invert) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000729 if (flags() & kDisableBinaryOpReduction) return NoChange();
730
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000731 JSBinopReduction r(this, node);
732 if (r.left() == r.right()) {
733 // x === x is always true if x != NaN
734 if (!r.left_type()->Maybe(Type::NaN())) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000735 Node* replacement = jsgraph()->BooleanConstant(!invert);
736 ReplaceWithValue(node, replacement);
737 return Replace(replacement);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000738 }
739 }
Ben Murdoch61f157c2016-09-16 13:49:30 +0100740 if (r.OneInputCannotBe(Type::NumberOrSimdOrString())) {
741 // For values with canonical representation (i.e. neither String, nor
742 // Simd128Value nor Number) an empty type intersection means the values
743 // cannot be strictly equal.
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400744 if (!r.left_type()->Maybe(r.right_type())) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000745 Node* replacement = jsgraph()->BooleanConstant(invert);
746 ReplaceWithValue(node, replacement);
747 return Replace(replacement);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000748 }
749 }
Ben Murdochc5610432016-08-08 18:44:38 +0100750 Reduction const reduction = ReduceJSEqualTypeOf(node, invert);
751 if (reduction.Changed()) {
752 return reduction;
753 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000754 if (r.OneInputIs(the_hole_type_)) {
755 return r.ChangeToPureOperator(simplified()->ReferenceEqual(the_hole_type_),
756 invert);
757 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000758 if (r.OneInputIs(Type::Undefined())) {
759 return r.ChangeToPureOperator(
760 simplified()->ReferenceEqual(Type::Undefined()), invert);
761 }
762 if (r.OneInputIs(Type::Null())) {
763 return r.ChangeToPureOperator(simplified()->ReferenceEqual(Type::Null()),
764 invert);
765 }
766 if (r.OneInputIs(Type::Boolean())) {
767 return r.ChangeToPureOperator(simplified()->ReferenceEqual(Type::Boolean()),
768 invert);
769 }
770 if (r.OneInputIs(Type::Object())) {
771 return r.ChangeToPureOperator(simplified()->ReferenceEqual(Type::Object()),
772 invert);
773 }
774 if (r.OneInputIs(Type::Receiver())) {
775 return r.ChangeToPureOperator(
776 simplified()->ReferenceEqual(Type::Receiver()), invert);
777 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000778 if (r.BothInputsAre(Type::Unique())) {
779 return r.ChangeToPureOperator(simplified()->ReferenceEqual(Type::Unique()),
780 invert);
781 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000782 if (r.BothInputsAre(Type::String())) {
Ben Murdochc5610432016-08-08 18:44:38 +0100783 return r.ChangeToPureOperator(simplified()->StringEqual(), invert);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000784 }
Ben Murdoch61f157c2016-09-16 13:49:30 +0100785 if (r.BothInputsAre(Type::Number())) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000786 return r.ChangeToPureOperator(simplified()->NumberEqual(), invert);
787 }
788 // TODO(turbofan): js-typed-lowering of StrictEqual(mixed types)
789 return NoChange();
790}
791
792
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000793Reduction JSTypedLowering::ReduceJSToBoolean(Node* node) {
794 Node* const input = node->InputAt(0);
795 Type* const input_type = NodeProperties::GetType(input);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400796 if (input_type->Is(Type::Boolean())) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000797 // JSToBoolean(x:boolean) => x
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000798 return Replace(input);
799 } else if (input_type->Is(Type::OrderedNumber())) {
800 // JSToBoolean(x:ordered-number) => BooleanNot(NumberEqual(x,#0))
801 RelaxEffectsAndControls(node);
802 node->ReplaceInput(0, graph()->NewNode(simplified()->NumberEqual(), input,
803 jsgraph()->ZeroConstant()));
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400804 node->TrimInputCount(1);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000805 NodeProperties::ChangeOp(node, simplified()->BooleanNot());
806 return Changed(node);
807 } else if (input_type->Is(Type::String())) {
808 // JSToBoolean(x:string) => NumberLessThan(#0,x.length)
809 FieldAccess const access = AccessBuilder::ForStringLength();
810 Node* length = graph()->NewNode(simplified()->LoadField(access), input,
Ben Murdochc5610432016-08-08 18:44:38 +0100811 graph()->start(), graph()->start());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000812 ReplaceWithValue(node, node, length);
813 node->ReplaceInput(0, jsgraph()->ZeroConstant());
814 node->ReplaceInput(1, length);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000815 NodeProperties::ChangeOp(node, simplified()->NumberLessThan());
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400816 return Changed(node);
817 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000818 return NoChange();
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400819}
820
Ben Murdochda12d292016-06-02 14:46:10 +0100821Reduction JSTypedLowering::ReduceJSToInteger(Node* node) {
822 Node* const input = NodeProperties::GetValueInput(node, 0);
823 Type* const input_type = NodeProperties::GetType(input);
824 if (input_type->Is(type_cache_.kIntegerOrMinusZero)) {
825 // JSToInteger(x:integer) => x
826 ReplaceWithValue(node, input);
827 return Replace(input);
828 }
829 return NoChange();
830}
831
832Reduction JSTypedLowering::ReduceJSToLength(Node* node) {
833 Node* input = NodeProperties::GetValueInput(node, 0);
834 Type* input_type = NodeProperties::GetType(input);
835 if (input_type->Is(type_cache_.kIntegerOrMinusZero)) {
836 if (input_type->Max() <= 0.0) {
837 input = jsgraph()->ZeroConstant();
838 } else if (input_type->Min() >= kMaxSafeInteger) {
839 input = jsgraph()->Constant(kMaxSafeInteger);
840 } else {
841 if (input_type->Min() <= 0.0) {
842 input = graph()->NewNode(
843 common()->Select(MachineRepresentation::kTagged),
844 graph()->NewNode(simplified()->NumberLessThanOrEqual(), input,
845 jsgraph()->ZeroConstant()),
846 jsgraph()->ZeroConstant(), input);
847 input_type = Type::Range(0.0, input_type->Max(), graph()->zone());
848 NodeProperties::SetType(input, input_type);
849 }
850 if (input_type->Max() > kMaxSafeInteger) {
851 input = graph()->NewNode(
852 common()->Select(MachineRepresentation::kTagged),
853 graph()->NewNode(simplified()->NumberLessThanOrEqual(),
854 jsgraph()->Constant(kMaxSafeInteger), input),
855 jsgraph()->Constant(kMaxSafeInteger), input);
856 input_type =
857 Type::Range(input_type->Min(), kMaxSafeInteger, graph()->zone());
858 NodeProperties::SetType(input, input_type);
859 }
860 }
861 ReplaceWithValue(node, input);
862 return Replace(input);
863 }
864 return NoChange();
865}
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400866
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000867Reduction JSTypedLowering::ReduceJSToNumberInput(Node* input) {
Ben Murdoch097c5b22016-05-18 11:27:45 +0100868 // Try constant-folding of JSToNumber with constant inputs.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000869 Type* input_type = NodeProperties::GetType(input);
Ben Murdoch097c5b22016-05-18 11:27:45 +0100870 if (input_type->IsConstant()) {
871 Handle<Object> input_value = input_type->AsConstant()->Value();
872 if (input_value->IsString()) {
873 return Replace(jsgraph()->Constant(
874 String::ToNumber(Handle<String>::cast(input_value))));
875 } else if (input_value->IsOddball()) {
876 return Replace(jsgraph()->Constant(
877 Oddball::ToNumber(Handle<Oddball>::cast(input_value))));
878 }
879 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000880 if (input_type->Is(Type::Number())) {
881 // JSToNumber(x:number) => x
882 return Changed(input);
883 }
884 if (input_type->Is(Type::Undefined())) {
885 // JSToNumber(undefined) => #NaN
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400886 return Replace(jsgraph()->NaNConstant());
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000887 }
888 if (input_type->Is(Type::Null())) {
889 // JSToNumber(null) => #0
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400890 return Replace(jsgraph()->ZeroConstant());
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000891 }
892 if (input_type->Is(Type::Boolean())) {
893 // JSToNumber(x:boolean) => BooleanToNumber(x)
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400894 return Replace(graph()->NewNode(simplified()->BooleanToNumber(), input));
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000895 }
Ben Murdochda12d292016-06-02 14:46:10 +0100896 if (input_type->Is(Type::String())) {
897 // JSToNumber(x:string) => StringToNumber(x)
898 return Replace(graph()->NewNode(simplified()->StringToNumber(), input));
899 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000900 return NoChange();
901}
902
903
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400904Reduction JSTypedLowering::ReduceJSToNumber(Node* node) {
905 // Try to reduce the input first.
906 Node* const input = node->InputAt(0);
907 Reduction reduction = ReduceJSToNumberInput(input);
908 if (reduction.Changed()) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000909 ReplaceWithValue(node, reduction.replacement());
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400910 return reduction;
911 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000912 Type* const input_type = NodeProperties::GetType(input);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400913 if (input_type->Is(Type::PlainPrimitive())) {
Ben Murdoch61f157c2016-09-16 13:49:30 +0100914 RelaxEffectsAndControls(node);
915 node->TrimInputCount(1);
916 NodeProperties::ChangeOp(node, simplified()->PlainPrimitiveToNumber());
917 return Changed(node);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400918 }
919 return NoChange();
920}
921
922
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000923Reduction JSTypedLowering::ReduceJSToStringInput(Node* input) {
924 if (input->opcode() == IrOpcode::kJSToString) {
925 // Recursively try to reduce the input first.
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400926 Reduction result = ReduceJSToString(input);
927 if (result.Changed()) return result;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000928 return Changed(input); // JSToString(JSToString(x)) => JSToString(x)
929 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000930 Type* input_type = NodeProperties::GetType(input);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000931 if (input_type->Is(Type::String())) {
932 return Changed(input); // JSToString(x:string) => x
933 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000934 if (input_type->Is(Type::Boolean())) {
935 return Replace(graph()->NewNode(
936 common()->Select(MachineRepresentation::kTagged), input,
937 jsgraph()->HeapConstant(factory()->true_string()),
938 jsgraph()->HeapConstant(factory()->false_string())));
939 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000940 if (input_type->Is(Type::Undefined())) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400941 return Replace(jsgraph()->HeapConstant(factory()->undefined_string()));
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000942 }
943 if (input_type->Is(Type::Null())) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400944 return Replace(jsgraph()->HeapConstant(factory()->null_string()));
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000945 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000946 // TODO(turbofan): js-typed-lowering of ToString(x:number)
947 return NoChange();
948}
949
950
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400951Reduction JSTypedLowering::ReduceJSToString(Node* node) {
952 // Try to reduce the input first.
953 Node* const input = node->InputAt(0);
954 Reduction reduction = ReduceJSToStringInput(input);
955 if (reduction.Changed()) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000956 ReplaceWithValue(node, reduction.replacement());
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400957 return reduction;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000958 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000959 return NoChange();
960}
961
962
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000963Reduction JSTypedLowering::ReduceJSToObject(Node* node) {
964 DCHECK_EQ(IrOpcode::kJSToObject, node->opcode());
965 Node* receiver = NodeProperties::GetValueInput(node, 0);
966 Type* receiver_type = NodeProperties::GetType(receiver);
967 Node* context = NodeProperties::GetContextInput(node);
968 Node* frame_state = NodeProperties::GetFrameStateInput(node, 0);
969 Node* effect = NodeProperties::GetEffectInput(node);
970 Node* control = NodeProperties::GetControlInput(node);
971 if (!receiver_type->Is(Type::Receiver())) {
972 // TODO(bmeurer/mstarzinger): Add support for lowering inside try blocks.
973 if (receiver_type->Maybe(Type::NullOrUndefined()) &&
974 NodeProperties::IsExceptionalCall(node)) {
975 // ToObject throws for null or undefined inputs.
976 return NoChange();
977 }
978
979 // Check whether {receiver} is a Smi.
980 Node* check0 = graph()->NewNode(simplified()->ObjectIsSmi(), receiver);
981 Node* branch0 =
982 graph()->NewNode(common()->Branch(BranchHint::kFalse), check0, control);
983 Node* if_true0 = graph()->NewNode(common()->IfTrue(), branch0);
984 Node* etrue0 = effect;
985
986 Node* if_false0 = graph()->NewNode(common()->IfFalse(), branch0);
987 Node* efalse0 = effect;
988
989 // Determine the instance type of {receiver}.
990 Node* receiver_map = efalse0 =
991 graph()->NewNode(simplified()->LoadField(AccessBuilder::ForMap()),
992 receiver, efalse0, if_false0);
993 Node* receiver_instance_type = efalse0 = graph()->NewNode(
994 simplified()->LoadField(AccessBuilder::ForMapInstanceType()),
995 receiver_map, efalse0, if_false0);
996
997 // Check whether {receiver} is a spec object.
998 STATIC_ASSERT(LAST_JS_RECEIVER_TYPE == LAST_TYPE);
999 Node* check1 =
1000 graph()->NewNode(machine()->Uint32LessThanOrEqual(),
1001 jsgraph()->Uint32Constant(FIRST_JS_RECEIVER_TYPE),
1002 receiver_instance_type);
1003 Node* branch1 = graph()->NewNode(common()->Branch(BranchHint::kTrue),
1004 check1, if_false0);
1005 Node* if_true1 = graph()->NewNode(common()->IfTrue(), branch1);
1006 Node* etrue1 = efalse0;
1007
1008 Node* if_false1 = graph()->NewNode(common()->IfFalse(), branch1);
1009 Node* efalse1 = efalse0;
1010
1011 // Convert {receiver} using the ToObjectStub.
1012 Node* if_convert =
1013 graph()->NewNode(common()->Merge(2), if_true0, if_false1);
1014 Node* econvert =
1015 graph()->NewNode(common()->EffectPhi(2), etrue0, efalse1, if_convert);
1016 Node* rconvert;
1017 {
1018 Callable callable = CodeFactory::ToObject(isolate());
1019 CallDescriptor const* const desc = Linkage::GetStubCallDescriptor(
1020 isolate(), graph()->zone(), callable.descriptor(), 0,
1021 CallDescriptor::kNeedsFrameState, node->op()->properties());
1022 rconvert = econvert = graph()->NewNode(
1023 common()->Call(desc), jsgraph()->HeapConstant(callable.code()),
1024 receiver, context, frame_state, econvert, if_convert);
1025 }
1026
1027 // The {receiver} is already a spec object.
1028 Node* if_done = if_true1;
1029 Node* edone = etrue1;
1030 Node* rdone = receiver;
1031
1032 control = graph()->NewNode(common()->Merge(2), if_convert, if_done);
1033 effect = graph()->NewNode(common()->EffectPhi(2), econvert, edone, control);
1034 receiver =
1035 graph()->NewNode(common()->Phi(MachineRepresentation::kTagged, 2),
1036 rconvert, rdone, control);
1037 }
1038 ReplaceWithValue(node, receiver, effect, control);
1039 return Changed(receiver);
1040}
1041
1042
1043Reduction JSTypedLowering::ReduceJSLoadNamed(Node* node) {
1044 DCHECK_EQ(IrOpcode::kJSLoadNamed, node->opcode());
1045 Node* receiver = NodeProperties::GetValueInput(node, 0);
1046 Type* receiver_type = NodeProperties::GetType(receiver);
1047 Node* effect = NodeProperties::GetEffectInput(node);
1048 Node* control = NodeProperties::GetControlInput(node);
1049 Handle<Name> name = NamedAccessOf(node->op()).name();
1050 // Optimize "length" property of strings.
1051 if (name.is_identical_to(factory()->length_string()) &&
1052 receiver_type->Is(Type::String())) {
1053 Node* value = effect = graph()->NewNode(
1054 simplified()->LoadField(AccessBuilder::ForStringLength()), receiver,
1055 effect, control);
1056 ReplaceWithValue(node, value, effect);
1057 return Replace(value);
1058 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001059 return NoChange();
1060}
1061
1062
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001063Reduction JSTypedLowering::ReduceJSLoadProperty(Node* node) {
1064 Node* key = NodeProperties::GetValueInput(node, 1);
1065 Node* base = NodeProperties::GetValueInput(node, 0);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001066 Type* key_type = NodeProperties::GetType(key);
1067 HeapObjectMatcher mbase(base);
1068 if (mbase.HasValue() && mbase.Value()->IsJSTypedArray()) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001069 Handle<JSTypedArray> const array =
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001070 Handle<JSTypedArray>::cast(mbase.Value());
1071 if (!array->GetBuffer()->was_neutered()) {
1072 array->GetBuffer()->set_is_neuterable(false);
1073 BufferAccess const access(array->type());
1074 size_t const k =
1075 ElementSizeLog2Of(access.machine_type().representation());
1076 double const byte_length = array->byte_length()->Number();
1077 CHECK_LT(k, arraysize(shifted_int32_ranges_));
1078 if (key_type->Is(shifted_int32_ranges_[k]) && byte_length <= kMaxInt) {
1079 // JSLoadProperty(typed-array, int32)
1080 Handle<FixedTypedArrayBase> elements =
1081 Handle<FixedTypedArrayBase>::cast(handle(array->elements()));
1082 Node* buffer = jsgraph()->PointerConstant(elements->external_pointer());
1083 Node* length = jsgraph()->Constant(byte_length);
1084 Node* effect = NodeProperties::GetEffectInput(node);
1085 Node* control = NodeProperties::GetControlInput(node);
1086 // Check if we can avoid the bounds check.
1087 if (key_type->Min() >= 0 && key_type->Max() < array->length_value()) {
1088 Node* load = graph()->NewNode(
1089 simplified()->LoadElement(
1090 AccessBuilder::ForTypedArrayElement(array->type(), true)),
1091 buffer, key, effect, control);
1092 ReplaceWithValue(node, load, load);
1093 return Replace(load);
1094 }
1095 // Compute byte offset.
1096 Node* offset = Word32Shl(key, static_cast<int>(k));
1097 Node* load = graph()->NewNode(simplified()->LoadBuffer(access), buffer,
1098 offset, length, effect, control);
1099 ReplaceWithValue(node, load, load);
1100 return Replace(load);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001101 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001102 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001103 }
1104 return NoChange();
1105}
1106
1107
1108Reduction JSTypedLowering::ReduceJSStoreProperty(Node* node) {
1109 Node* key = NodeProperties::GetValueInput(node, 1);
1110 Node* base = NodeProperties::GetValueInput(node, 0);
1111 Node* value = NodeProperties::GetValueInput(node, 2);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001112 Type* key_type = NodeProperties::GetType(key);
1113 Type* value_type = NodeProperties::GetType(value);
1114 HeapObjectMatcher mbase(base);
1115 if (mbase.HasValue() && mbase.Value()->IsJSTypedArray()) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001116 Handle<JSTypedArray> const array =
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001117 Handle<JSTypedArray>::cast(mbase.Value());
1118 if (!array->GetBuffer()->was_neutered()) {
1119 array->GetBuffer()->set_is_neuterable(false);
1120 BufferAccess const access(array->type());
1121 size_t const k =
1122 ElementSizeLog2Of(access.machine_type().representation());
1123 double const byte_length = array->byte_length()->Number();
1124 CHECK_LT(k, arraysize(shifted_int32_ranges_));
1125 if (access.external_array_type() != kExternalUint8ClampedArray &&
1126 key_type->Is(shifted_int32_ranges_[k]) && byte_length <= kMaxInt) {
1127 // JSLoadProperty(typed-array, int32)
1128 Handle<FixedTypedArrayBase> elements =
1129 Handle<FixedTypedArrayBase>::cast(handle(array->elements()));
1130 Node* buffer = jsgraph()->PointerConstant(elements->external_pointer());
1131 Node* length = jsgraph()->Constant(byte_length);
1132 Node* context = NodeProperties::GetContextInput(node);
1133 Node* effect = NodeProperties::GetEffectInput(node);
1134 Node* control = NodeProperties::GetControlInput(node);
1135 // Convert to a number first.
Ben Murdoch61f157c2016-09-16 13:49:30 +01001136 if (!value_type->Is(Type::Number())) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001137 Reduction number_reduction = ReduceJSToNumberInput(value);
1138 if (number_reduction.Changed()) {
1139 value = number_reduction.replacement();
1140 } else {
1141 Node* frame_state_for_to_number =
Ben Murdoch61f157c2016-09-16 13:49:30 +01001142 NodeProperties::FindFrameStateBefore(node);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001143 value = effect =
1144 graph()->NewNode(javascript()->ToNumber(), value, context,
1145 frame_state_for_to_number, effect, control);
1146 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001147 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001148 // Check if we can avoid the bounds check.
1149 if (key_type->Min() >= 0 && key_type->Max() < array->length_value()) {
1150 RelaxControls(node);
1151 node->ReplaceInput(0, buffer);
1152 DCHECK_EQ(key, node->InputAt(1));
1153 node->ReplaceInput(2, value);
1154 node->ReplaceInput(3, effect);
1155 node->ReplaceInput(4, control);
1156 node->TrimInputCount(5);
1157 NodeProperties::ChangeOp(
1158 node,
1159 simplified()->StoreElement(
1160 AccessBuilder::ForTypedArrayElement(array->type(), true)));
1161 return Changed(node);
1162 }
1163 // Compute byte offset.
1164 Node* offset = Word32Shl(key, static_cast<int>(k));
1165 // Turn into a StoreBuffer operation.
1166 RelaxControls(node);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001167 node->ReplaceInput(0, buffer);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001168 node->ReplaceInput(1, offset);
1169 node->ReplaceInput(2, length);
1170 node->ReplaceInput(3, value);
1171 node->ReplaceInput(4, effect);
1172 node->ReplaceInput(5, control);
1173 node->TrimInputCount(6);
1174 NodeProperties::ChangeOp(node, simplified()->StoreBuffer(access));
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001175 return Changed(node);
1176 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001177 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001178 }
1179 return NoChange();
1180}
1181
1182
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001183Reduction JSTypedLowering::ReduceJSInstanceOf(Node* node) {
1184 DCHECK_EQ(IrOpcode::kJSInstanceOf, node->opcode());
1185 Node* const context = NodeProperties::GetContextInput(node);
1186 Node* const frame_state = NodeProperties::GetFrameStateInput(node, 0);
1187
1188 // If deoptimization is disabled, we cannot optimize.
Ben Murdochc5610432016-08-08 18:44:38 +01001189 if (!(flags() & kDeoptimizationEnabled)) return NoChange();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001190
1191 // If we are in a try block, don't optimize since the runtime call
1192 // in the proxy case can throw.
1193 if (NodeProperties::IsExceptionalCall(node)) return NoChange();
1194
1195 JSBinopReduction r(this, node);
1196 Node* effect = r.effect();
1197 Node* control = r.control();
1198
1199 if (!r.right_type()->IsConstant() ||
1200 !r.right_type()->AsConstant()->Value()->IsJSFunction()) {
1201 return NoChange();
1202 }
1203
1204 Handle<JSFunction> function =
1205 Handle<JSFunction>::cast(r.right_type()->AsConstant()->Value());
1206 Handle<SharedFunctionInfo> shared(function->shared(), isolate());
1207
Ben Murdochc5610432016-08-08 18:44:38 +01001208 // Make sure the prototype of {function} is the %FunctionPrototype%, and it
1209 // already has a meaningful initial map (i.e. we constructed at least one
1210 // instance using the constructor {function}).
1211 if (function->map()->prototype() != function->native_context()->closure() ||
1212 function->map()->has_non_instance_prototype() ||
1213 !function->has_initial_map()) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001214 return NoChange();
1215 }
1216
Ben Murdochc5610432016-08-08 18:44:38 +01001217 // We can only use the fast case if @@hasInstance was not used so far.
1218 if (!isolate()->IsHasInstanceLookupChainIntact()) return NoChange();
1219 dependencies()->AssumePropertyCell(factory()->has_instance_protector());
1220
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001221 Handle<Map> initial_map(function->initial_map(), isolate());
Ben Murdochc5610432016-08-08 18:44:38 +01001222 dependencies()->AssumeInitialMapCantChange(initial_map);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001223 Node* prototype =
1224 jsgraph()->Constant(handle(initial_map->prototype(), isolate()));
1225
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001226 // If the left hand side is an object, no smi check is needed.
Ben Murdoch61f157c2016-09-16 13:49:30 +01001227 Node* is_smi = graph()->NewNode(simplified()->ObjectIsSmi(), r.left());
1228 Node* branch_is_smi =
1229 graph()->NewNode(common()->Branch(BranchHint::kFalse), is_smi, control);
1230 Node* if_is_smi = graph()->NewNode(common()->IfTrue(), branch_is_smi);
1231 Node* e_is_smi = effect;
1232 control = graph()->NewNode(common()->IfFalse(), branch_is_smi);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001233
1234 Node* object_map = effect =
1235 graph()->NewNode(simplified()->LoadField(AccessBuilder::ForMap()),
1236 r.left(), effect, control);
1237
1238 // Loop through the {object}s prototype chain looking for the {prototype}.
1239 Node* loop = control = graph()->NewNode(common()->Loop(2), control, control);
1240
1241 Node* loop_effect = effect =
1242 graph()->NewNode(common()->EffectPhi(2), effect, effect, loop);
1243
1244 Node* loop_object_map =
1245 graph()->NewNode(common()->Phi(MachineRepresentation::kTagged, 2),
1246 object_map, r.left(), loop);
1247
1248 // Check if the lhs needs access checks.
1249 Node* map_bit_field = effect =
1250 graph()->NewNode(simplified()->LoadField(AccessBuilder::ForMapBitField()),
1251 loop_object_map, loop_effect, control);
1252 int is_access_check_needed_bit = 1 << Map::kIsAccessCheckNeeded;
1253 Node* is_access_check_needed_num =
1254 graph()->NewNode(simplified()->NumberBitwiseAnd(), map_bit_field,
1255 jsgraph()->Uint32Constant(is_access_check_needed_bit));
1256 Node* is_access_check_needed =
1257 graph()->NewNode(machine()->Word32Equal(), is_access_check_needed_num,
1258 jsgraph()->Uint32Constant(is_access_check_needed_bit));
1259
1260 Node* branch_is_access_check_needed = graph()->NewNode(
1261 common()->Branch(BranchHint::kFalse), is_access_check_needed, control);
1262 Node* if_is_access_check_needed =
1263 graph()->NewNode(common()->IfTrue(), branch_is_access_check_needed);
1264 Node* e_is_access_check_needed = effect;
1265
1266 control =
1267 graph()->NewNode(common()->IfFalse(), branch_is_access_check_needed);
1268
1269 // Check if the lhs is a proxy.
1270 Node* map_instance_type = effect = graph()->NewNode(
1271 simplified()->LoadField(AccessBuilder::ForMapInstanceType()),
1272 loop_object_map, loop_effect, control);
1273 Node* is_proxy = graph()->NewNode(machine()->Word32Equal(), map_instance_type,
1274 jsgraph()->Uint32Constant(JS_PROXY_TYPE));
1275 Node* branch_is_proxy =
1276 graph()->NewNode(common()->Branch(BranchHint::kFalse), is_proxy, control);
1277 Node* if_is_proxy = graph()->NewNode(common()->IfTrue(), branch_is_proxy);
1278 Node* e_is_proxy = effect;
1279
1280
1281 Node* runtime_has_in_proto_chain = control = graph()->NewNode(
1282 common()->Merge(2), if_is_access_check_needed, if_is_proxy);
1283 effect = graph()->NewNode(common()->EffectPhi(2), e_is_access_check_needed,
1284 e_is_proxy, control);
1285
1286 // If we need an access check or the object is a Proxy, make a runtime call
1287 // to finish the lowering.
1288 Node* bool_result_runtime_has_in_proto_chain_case = graph()->NewNode(
Ben Murdoch097c5b22016-05-18 11:27:45 +01001289 javascript()->CallRuntime(Runtime::kHasInPrototypeChain), r.left(),
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001290 prototype, context, frame_state, effect, control);
1291
1292 control = graph()->NewNode(common()->IfFalse(), branch_is_proxy);
1293
1294 Node* object_prototype = effect = graph()->NewNode(
1295 simplified()->LoadField(AccessBuilder::ForMapPrototype()),
1296 loop_object_map, loop_effect, control);
1297
Ben Murdoch61f157c2016-09-16 13:49:30 +01001298 // If not, check if object prototype is the null prototype.
1299 Node* null_proto =
1300 graph()->NewNode(simplified()->ReferenceEqual(r.right_type()),
1301 object_prototype, jsgraph()->NullConstant());
1302 Node* branch_null_proto = graph()->NewNode(
1303 common()->Branch(BranchHint::kFalse), null_proto, control);
1304 Node* if_null_proto = graph()->NewNode(common()->IfTrue(), branch_null_proto);
1305 Node* e_null_proto = effect;
1306
1307 control = graph()->NewNode(common()->IfFalse(), branch_null_proto);
1308
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001309 // Check if object prototype is equal to function prototype.
1310 Node* eq_proto =
1311 graph()->NewNode(simplified()->ReferenceEqual(r.right_type()),
1312 object_prototype, prototype);
1313 Node* branch_eq_proto =
1314 graph()->NewNode(common()->Branch(BranchHint::kFalse), eq_proto, control);
1315 Node* if_eq_proto = graph()->NewNode(common()->IfTrue(), branch_eq_proto);
1316 Node* e_eq_proto = effect;
1317
1318 control = graph()->NewNode(common()->IfFalse(), branch_eq_proto);
1319
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001320 Node* load_object_map = effect =
1321 graph()->NewNode(simplified()->LoadField(AccessBuilder::ForMap()),
1322 object_prototype, effect, control);
1323 // Close the loop.
1324 loop_effect->ReplaceInput(1, effect);
1325 loop_object_map->ReplaceInput(1, load_object_map);
1326 loop->ReplaceInput(1, control);
1327
1328 control = graph()->NewNode(common()->Merge(3), runtime_has_in_proto_chain,
1329 if_eq_proto, if_null_proto);
1330 effect = graph()->NewNode(common()->EffectPhi(3),
1331 bool_result_runtime_has_in_proto_chain_case,
1332 e_eq_proto, e_null_proto, control);
1333
1334 Node* result = graph()->NewNode(
1335 common()->Phi(MachineRepresentation::kTagged, 3),
1336 bool_result_runtime_has_in_proto_chain_case, jsgraph()->TrueConstant(),
1337 jsgraph()->FalseConstant(), control);
1338
Ben Murdoch61f157c2016-09-16 13:49:30 +01001339 DCHECK_NOT_NULL(e_is_smi);
1340 control = graph()->NewNode(common()->Merge(2), if_is_smi, control);
1341 effect =
1342 graph()->NewNode(common()->EffectPhi(2), e_is_smi, effect, control);
1343 result = graph()->NewNode(common()->Phi(MachineRepresentation::kTagged, 2),
1344 jsgraph()->FalseConstant(), result, control);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001345
1346 ReplaceWithValue(node, result, effect, control);
1347 return Changed(result);
1348}
1349
1350
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001351Reduction JSTypedLowering::ReduceJSLoadContext(Node* node) {
1352 DCHECK_EQ(IrOpcode::kJSLoadContext, node->opcode());
1353 ContextAccess const& access = ContextAccessOf(node->op());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001354 Node* effect = NodeProperties::GetEffectInput(node);
1355 Node* control = graph()->start();
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001356 for (size_t i = 0; i < access.depth(); ++i) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001357 Node* previous = effect = graph()->NewNode(
1358 simplified()->LoadField(
1359 AccessBuilder::ForContextSlot(Context::PREVIOUS_INDEX)),
1360 NodeProperties::GetValueInput(node, 0), effect, control);
1361 node->ReplaceInput(0, previous);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001362 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001363 node->ReplaceInput(1, effect);
1364 node->ReplaceInput(2, control);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001365 NodeProperties::ChangeOp(
1366 node,
1367 simplified()->LoadField(AccessBuilder::ForContextSlot(access.index())));
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001368 return Changed(node);
1369}
1370
1371
1372Reduction JSTypedLowering::ReduceJSStoreContext(Node* node) {
1373 DCHECK_EQ(IrOpcode::kJSStoreContext, node->opcode());
1374 ContextAccess const& access = ContextAccessOf(node->op());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001375 Node* effect = NodeProperties::GetEffectInput(node);
1376 Node* control = graph()->start();
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001377 for (size_t i = 0; i < access.depth(); ++i) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001378 Node* previous = effect = graph()->NewNode(
1379 simplified()->LoadField(
1380 AccessBuilder::ForContextSlot(Context::PREVIOUS_INDEX)),
1381 NodeProperties::GetValueInput(node, 0), effect, control);
1382 node->ReplaceInput(0, previous);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001383 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001384 node->RemoveInput(2);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001385 node->ReplaceInput(2, effect);
1386 NodeProperties::ChangeOp(
1387 node,
1388 simplified()->StoreField(AccessBuilder::ForContextSlot(access.index())));
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001389 return Changed(node);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001390}
1391
1392
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001393Reduction JSTypedLowering::ReduceJSConvertReceiver(Node* node) {
1394 DCHECK_EQ(IrOpcode::kJSConvertReceiver, node->opcode());
1395 ConvertReceiverMode mode = ConvertReceiverModeOf(node->op());
1396 Node* receiver = NodeProperties::GetValueInput(node, 0);
1397 Type* receiver_type = NodeProperties::GetType(receiver);
1398 Node* context = NodeProperties::GetContextInput(node);
1399 Type* context_type = NodeProperties::GetType(context);
1400 Node* frame_state = NodeProperties::GetFrameStateInput(node, 0);
1401 Node* effect = NodeProperties::GetEffectInput(node);
1402 Node* control = NodeProperties::GetControlInput(node);
1403 if (!receiver_type->Is(Type::Receiver())) {
1404 if (receiver_type->Is(Type::NullOrUndefined()) ||
1405 mode == ConvertReceiverMode::kNullOrUndefined) {
1406 if (context_type->IsConstant()) {
1407 Handle<JSObject> global_proxy(
1408 Handle<Context>::cast(context_type->AsConstant()->Value())
1409 ->global_proxy(),
1410 isolate());
1411 receiver = jsgraph()->Constant(global_proxy);
1412 } else {
1413 Node* native_context = effect = graph()->NewNode(
1414 javascript()->LoadContext(0, Context::NATIVE_CONTEXT_INDEX, true),
1415 context, context, effect);
1416 receiver = effect = graph()->NewNode(
1417 javascript()->LoadContext(0, Context::GLOBAL_PROXY_INDEX, true),
1418 native_context, native_context, effect);
1419 }
1420 } else if (!receiver_type->Maybe(Type::NullOrUndefined()) ||
1421 mode == ConvertReceiverMode::kNotNullOrUndefined) {
1422 receiver = effect =
1423 graph()->NewNode(javascript()->ToObject(), receiver, context,
1424 frame_state, effect, control);
1425 } else {
1426 // Check {receiver} for undefined.
1427 Node* check0 =
1428 graph()->NewNode(simplified()->ReferenceEqual(receiver_type),
1429 receiver, jsgraph()->UndefinedConstant());
1430 Node* branch0 = graph()->NewNode(common()->Branch(BranchHint::kFalse),
1431 check0, control);
1432 Node* if_true0 = graph()->NewNode(common()->IfTrue(), branch0);
1433 Node* if_false0 = graph()->NewNode(common()->IfFalse(), branch0);
1434
1435 // Check {receiver} for null.
1436 Node* check1 =
1437 graph()->NewNode(simplified()->ReferenceEqual(receiver_type),
1438 receiver, jsgraph()->NullConstant());
1439 Node* branch1 = graph()->NewNode(common()->Branch(BranchHint::kFalse),
1440 check1, if_false0);
1441 Node* if_true1 = graph()->NewNode(common()->IfTrue(), branch1);
1442 Node* if_false1 = graph()->NewNode(common()->IfFalse(), branch1);
1443
1444 // Convert {receiver} using ToObject.
1445 Node* if_convert = if_false1;
1446 Node* econvert = effect;
1447 Node* rconvert;
1448 {
1449 rconvert = econvert =
1450 graph()->NewNode(javascript()->ToObject(), receiver, context,
1451 frame_state, econvert, if_convert);
1452 }
1453
1454 // Replace {receiver} with global proxy of {context}.
1455 Node* if_global =
1456 graph()->NewNode(common()->Merge(2), if_true0, if_true1);
1457 Node* eglobal = effect;
1458 Node* rglobal;
1459 {
1460 if (context_type->IsConstant()) {
1461 Handle<JSObject> global_proxy(
1462 Handle<Context>::cast(context_type->AsConstant()->Value())
1463 ->global_proxy(),
1464 isolate());
1465 rglobal = jsgraph()->Constant(global_proxy);
1466 } else {
1467 Node* native_context = eglobal = graph()->NewNode(
1468 javascript()->LoadContext(0, Context::NATIVE_CONTEXT_INDEX, true),
1469 context, context, eglobal);
1470 rglobal = eglobal = graph()->NewNode(
1471 javascript()->LoadContext(0, Context::GLOBAL_PROXY_INDEX, true),
1472 native_context, native_context, eglobal);
1473 }
1474 }
1475
1476 control = graph()->NewNode(common()->Merge(2), if_convert, if_global);
1477 effect =
1478 graph()->NewNode(common()->EffectPhi(2), econvert, eglobal, control);
1479 receiver =
1480 graph()->NewNode(common()->Phi(MachineRepresentation::kTagged, 2),
1481 rconvert, rglobal, control);
1482 }
1483 }
1484 ReplaceWithValue(node, receiver, effect, control);
1485 return Changed(receiver);
1486}
1487
1488
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001489Reduction JSTypedLowering::ReduceJSCallConstruct(Node* node) {
1490 DCHECK_EQ(IrOpcode::kJSCallConstruct, node->opcode());
1491 CallConstructParameters const& p = CallConstructParametersOf(node->op());
1492 DCHECK_LE(2u, p.arity());
1493 int const arity = static_cast<int>(p.arity() - 2);
1494 Node* target = NodeProperties::GetValueInput(node, 0);
1495 Type* target_type = NodeProperties::GetType(target);
1496 Node* new_target = NodeProperties::GetValueInput(node, arity + 1);
1497
1498 // Check if {target} is a known JSFunction.
1499 if (target_type->IsConstant() &&
1500 target_type->AsConstant()->Value()->IsJSFunction()) {
1501 Handle<JSFunction> function =
1502 Handle<JSFunction>::cast(target_type->AsConstant()->Value());
1503 Handle<SharedFunctionInfo> shared(function->shared(), isolate());
1504
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001505 // Patch {node} to an indirect call via the {function}s construct stub.
1506 Callable callable(handle(shared->construct_stub(), isolate()),
1507 ConstructStubDescriptor(isolate()));
1508 node->RemoveInput(arity + 1);
1509 node->InsertInput(graph()->zone(), 0,
1510 jsgraph()->HeapConstant(callable.code()));
1511 node->InsertInput(graph()->zone(), 2, new_target);
1512 node->InsertInput(graph()->zone(), 3, jsgraph()->Int32Constant(arity));
1513 node->InsertInput(graph()->zone(), 4, jsgraph()->UndefinedConstant());
1514 node->InsertInput(graph()->zone(), 5, jsgraph()->UndefinedConstant());
1515 NodeProperties::ChangeOp(
1516 node, common()->Call(Linkage::GetStubCallDescriptor(
1517 isolate(), graph()->zone(), callable.descriptor(), 1 + arity,
1518 CallDescriptor::kNeedsFrameState)));
1519 return Changed(node);
1520 }
1521
1522 // Check if {target} is a JSFunction.
1523 if (target_type->Is(Type::Function())) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001524 // Patch {node} to an indirect call via the ConstructFunction builtin.
1525 Callable callable = CodeFactory::ConstructFunction(isolate());
1526 node->RemoveInput(arity + 1);
1527 node->InsertInput(graph()->zone(), 0,
1528 jsgraph()->HeapConstant(callable.code()));
1529 node->InsertInput(graph()->zone(), 2, new_target);
1530 node->InsertInput(graph()->zone(), 3, jsgraph()->Int32Constant(arity));
1531 node->InsertInput(graph()->zone(), 4, jsgraph()->UndefinedConstant());
1532 NodeProperties::ChangeOp(
1533 node, common()->Call(Linkage::GetStubCallDescriptor(
1534 isolate(), graph()->zone(), callable.descriptor(), 1 + arity,
1535 CallDescriptor::kNeedsFrameState)));
1536 return Changed(node);
1537 }
1538
1539 return NoChange();
1540}
1541
1542
1543Reduction JSTypedLowering::ReduceJSCallFunction(Node* node) {
1544 DCHECK_EQ(IrOpcode::kJSCallFunction, node->opcode());
1545 CallFunctionParameters const& p = CallFunctionParametersOf(node->op());
1546 int const arity = static_cast<int>(p.arity() - 2);
1547 ConvertReceiverMode convert_mode = p.convert_mode();
1548 Node* target = NodeProperties::GetValueInput(node, 0);
1549 Type* target_type = NodeProperties::GetType(target);
1550 Node* receiver = NodeProperties::GetValueInput(node, 1);
1551 Type* receiver_type = NodeProperties::GetType(receiver);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001552 Node* effect = NodeProperties::GetEffectInput(node);
1553 Node* control = NodeProperties::GetControlInput(node);
Ben Murdoch61f157c2016-09-16 13:49:30 +01001554 Node* frame_state = NodeProperties::FindFrameStateBefore(node);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001555
1556 // Try to infer receiver {convert_mode} from {receiver} type.
1557 if (receiver_type->Is(Type::NullOrUndefined())) {
1558 convert_mode = ConvertReceiverMode::kNullOrUndefined;
1559 } else if (!receiver_type->Maybe(Type::NullOrUndefined())) {
1560 convert_mode = ConvertReceiverMode::kNotNullOrUndefined;
1561 }
1562
1563 // Check if {target} is a known JSFunction.
1564 if (target_type->IsConstant() &&
1565 target_type->AsConstant()->Value()->IsJSFunction()) {
1566 Handle<JSFunction> function =
1567 Handle<JSFunction>::cast(target_type->AsConstant()->Value());
1568 Handle<SharedFunctionInfo> shared(function->shared(), isolate());
1569
1570 // Class constructors are callable, but [[Call]] will raise an exception.
1571 // See ES6 section 9.2.1 [[Call]] ( thisArgument, argumentsList ).
1572 if (IsClassConstructor(shared->kind())) return NoChange();
1573
1574 // Load the context from the {target}.
1575 Node* context = effect = graph()->NewNode(
1576 simplified()->LoadField(AccessBuilder::ForJSFunctionContext()), target,
1577 effect, control);
1578 NodeProperties::ReplaceContextInput(node, context);
1579
1580 // Check if we need to convert the {receiver}.
1581 if (is_sloppy(shared->language_mode()) && !shared->native() &&
1582 !receiver_type->Is(Type::Receiver())) {
1583 receiver = effect =
1584 graph()->NewNode(javascript()->ConvertReceiver(convert_mode),
1585 receiver, context, frame_state, effect, control);
1586 NodeProperties::ReplaceValueInput(node, receiver, 1);
1587 }
1588
1589 // Update the effect dependency for the {node}.
1590 NodeProperties::ReplaceEffectInput(node, effect);
1591
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001592 // Compute flags for the call.
1593 CallDescriptor::Flags flags = CallDescriptor::kNeedsFrameState;
1594 if (p.tail_call_mode() == TailCallMode::kAllow) {
1595 flags |= CallDescriptor::kSupportsTailCalls;
1596 }
1597
1598 Node* new_target = jsgraph()->UndefinedConstant();
1599 Node* argument_count = jsgraph()->Int32Constant(arity);
1600 if (shared->internal_formal_parameter_count() == arity ||
1601 shared->internal_formal_parameter_count() ==
1602 SharedFunctionInfo::kDontAdaptArgumentsSentinel) {
1603 // Patch {node} to a direct call.
1604 node->InsertInput(graph()->zone(), arity + 2, new_target);
1605 node->InsertInput(graph()->zone(), arity + 3, argument_count);
1606 NodeProperties::ChangeOp(node,
1607 common()->Call(Linkage::GetJSCallDescriptor(
1608 graph()->zone(), false, 1 + arity, flags)));
1609 } else {
1610 // Patch {node} to an indirect call via the ArgumentsAdaptorTrampoline.
1611 Callable callable = CodeFactory::ArgumentAdaptor(isolate());
1612 node->InsertInput(graph()->zone(), 0,
1613 jsgraph()->HeapConstant(callable.code()));
1614 node->InsertInput(graph()->zone(), 2, new_target);
1615 node->InsertInput(graph()->zone(), 3, argument_count);
1616 node->InsertInput(
1617 graph()->zone(), 4,
1618 jsgraph()->Int32Constant(shared->internal_formal_parameter_count()));
1619 NodeProperties::ChangeOp(
1620 node, common()->Call(Linkage::GetStubCallDescriptor(
1621 isolate(), graph()->zone(), callable.descriptor(),
1622 1 + arity, flags)));
1623 }
1624 return Changed(node);
1625 }
1626
1627 // Check if {target} is a JSFunction.
1628 if (target_type->Is(Type::Function())) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001629 // Compute flags for the call.
1630 CallDescriptor::Flags flags = CallDescriptor::kNeedsFrameState;
1631 if (p.tail_call_mode() == TailCallMode::kAllow) {
1632 flags |= CallDescriptor::kSupportsTailCalls;
1633 }
1634
1635 // Patch {node} to an indirect call via the CallFunction builtin.
1636 Callable callable = CodeFactory::CallFunction(isolate(), convert_mode);
1637 node->InsertInput(graph()->zone(), 0,
1638 jsgraph()->HeapConstant(callable.code()));
1639 node->InsertInput(graph()->zone(), 2, jsgraph()->Int32Constant(arity));
1640 NodeProperties::ChangeOp(
1641 node, common()->Call(Linkage::GetStubCallDescriptor(
1642 isolate(), graph()->zone(), callable.descriptor(), 1 + arity,
1643 flags)));
1644 return Changed(node);
1645 }
1646
1647 // Maybe we did at least learn something about the {receiver}.
1648 if (p.convert_mode() != convert_mode) {
1649 NodeProperties::ChangeOp(
Ben Murdoch097c5b22016-05-18 11:27:45 +01001650 node, javascript()->CallFunction(p.arity(), p.feedback(), convert_mode,
1651 p.tail_call_mode()));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001652 return Changed(node);
1653 }
1654
1655 return NoChange();
1656}
1657
1658
1659Reduction JSTypedLowering::ReduceJSForInDone(Node* node) {
1660 DCHECK_EQ(IrOpcode::kJSForInDone, node->opcode());
1661 node->TrimInputCount(2);
1662 NodeProperties::ChangeOp(node, machine()->Word32Equal());
1663 return Changed(node);
1664}
1665
1666
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001667Reduction JSTypedLowering::ReduceJSForInNext(Node* node) {
1668 DCHECK_EQ(IrOpcode::kJSForInNext, node->opcode());
1669 Node* receiver = NodeProperties::GetValueInput(node, 0);
1670 Node* cache_array = NodeProperties::GetValueInput(node, 1);
1671 Node* cache_type = NodeProperties::GetValueInput(node, 2);
1672 Node* index = NodeProperties::GetValueInput(node, 3);
1673 Node* context = NodeProperties::GetContextInput(node);
1674 Node* frame_state = NodeProperties::GetFrameStateInput(node, 0);
1675 Node* effect = NodeProperties::GetEffectInput(node);
1676 Node* control = NodeProperties::GetControlInput(node);
1677
1678 // Load the next {key} from the {cache_array}.
1679 Node* key = effect = graph()->NewNode(
1680 simplified()->LoadElement(AccessBuilder::ForFixedArrayElement()),
1681 cache_array, index, effect, control);
1682
1683 // Load the map of the {receiver}.
1684 Node* receiver_map = effect =
1685 graph()->NewNode(simplified()->LoadField(AccessBuilder::ForMap()),
1686 receiver, effect, control);
1687
1688 // Check if the expected map still matches that of the {receiver}.
1689 Node* check0 = graph()->NewNode(simplified()->ReferenceEqual(Type::Any()),
1690 receiver_map, cache_type);
1691 Node* branch0 =
1692 graph()->NewNode(common()->Branch(BranchHint::kTrue), check0, control);
1693
1694 Node* if_true0 = graph()->NewNode(common()->IfTrue(), branch0);
1695 Node* etrue0;
1696 Node* vtrue0;
1697 {
1698 // Don't need filtering since expected map still matches that of the
1699 // {receiver}.
1700 etrue0 = effect;
1701 vtrue0 = key;
1702 }
1703
1704 Node* if_false0 = graph()->NewNode(common()->IfFalse(), branch0);
1705 Node* efalse0;
1706 Node* vfalse0;
1707 {
Ben Murdoch097c5b22016-05-18 11:27:45 +01001708 // Filter the {key} to check if it's still a valid property of the
1709 // {receiver} (does the ToName conversion implicitly).
1710 vfalse0 = efalse0 = graph()->NewNode(
1711 javascript()->CallRuntime(Runtime::kForInFilter), receiver, key,
1712 context, frame_state, effect, if_false0);
1713 if_false0 = graph()->NewNode(common()->IfSuccess(), vfalse0);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001714 }
1715
1716 control = graph()->NewNode(common()->Merge(2), if_true0, if_false0);
1717 effect = graph()->NewNode(common()->EffectPhi(2), etrue0, efalse0, control);
1718 ReplaceWithValue(node, node, effect, control);
1719 node->ReplaceInput(0, vtrue0);
1720 node->ReplaceInput(1, vfalse0);
1721 node->ReplaceInput(2, control);
1722 node->TrimInputCount(3);
1723 NodeProperties::ChangeOp(node,
1724 common()->Phi(MachineRepresentation::kTagged, 2));
1725 return Changed(node);
1726}
1727
1728
1729Reduction JSTypedLowering::ReduceJSForInStep(Node* node) {
1730 DCHECK_EQ(IrOpcode::kJSForInStep, node->opcode());
1731 node->ReplaceInput(1, jsgraph()->Int32Constant(1));
1732 NodeProperties::ChangeOp(node, machine()->Int32Add());
1733 return Changed(node);
1734}
1735
Ben Murdoch61f157c2016-09-16 13:49:30 +01001736Reduction JSTypedLowering::ReduceJSGeneratorStore(Node* node) {
1737 DCHECK_EQ(IrOpcode::kJSGeneratorStore, node->opcode());
1738 Node* generator = NodeProperties::GetValueInput(node, 0);
1739 Node* continuation = NodeProperties::GetValueInput(node, 1);
1740 Node* offset = NodeProperties::GetValueInput(node, 2);
1741 Node* context = NodeProperties::GetContextInput(node);
1742 Node* effect = NodeProperties::GetEffectInput(node);
1743 Node* control = NodeProperties::GetControlInput(node);
1744 int register_count = OpParameter<int>(node);
1745
1746 FieldAccess array_field = AccessBuilder::ForJSGeneratorObjectOperandStack();
1747 FieldAccess context_field = AccessBuilder::ForJSGeneratorObjectContext();
1748 FieldAccess continuation_field =
1749 AccessBuilder::ForJSGeneratorObjectContinuation();
1750 FieldAccess input_or_debug_pos_field =
1751 AccessBuilder::ForJSGeneratorObjectInputOrDebugPos();
1752
1753 Node* array = effect = graph()->NewNode(simplified()->LoadField(array_field),
1754 generator, effect, control);
1755
1756 for (int i = 0; i < register_count; ++i) {
1757 Node* value = NodeProperties::GetValueInput(node, 3 + i);
1758 effect = graph()->NewNode(
1759 simplified()->StoreField(AccessBuilder::ForFixedArraySlot(i)), array,
1760 value, effect, control);
1761 }
1762
1763 effect = graph()->NewNode(simplified()->StoreField(context_field), generator,
1764 context, effect, control);
1765 effect = graph()->NewNode(simplified()->StoreField(continuation_field),
1766 generator, continuation, effect, control);
1767 effect = graph()->NewNode(simplified()->StoreField(input_or_debug_pos_field),
1768 generator, offset, effect, control);
1769
1770 ReplaceWithValue(node, effect, effect, control);
1771 return Changed(effect);
1772}
1773
1774Reduction JSTypedLowering::ReduceJSGeneratorRestoreContinuation(Node* node) {
1775 DCHECK_EQ(IrOpcode::kJSGeneratorRestoreContinuation, node->opcode());
1776 Node* generator = NodeProperties::GetValueInput(node, 0);
1777 Node* effect = NodeProperties::GetEffectInput(node);
1778 Node* control = NodeProperties::GetControlInput(node);
1779
1780 FieldAccess continuation_field =
1781 AccessBuilder::ForJSGeneratorObjectContinuation();
1782
1783 Node* continuation = effect = graph()->NewNode(
1784 simplified()->LoadField(continuation_field), generator, effect, control);
1785 Node* executing = jsgraph()->Constant(JSGeneratorObject::kGeneratorExecuting);
1786 effect = graph()->NewNode(simplified()->StoreField(continuation_field),
1787 generator, executing, effect, control);
1788
1789 ReplaceWithValue(node, continuation, effect, control);
1790 return Changed(continuation);
1791}
1792
1793Reduction JSTypedLowering::ReduceJSGeneratorRestoreRegister(Node* node) {
1794 DCHECK_EQ(IrOpcode::kJSGeneratorRestoreRegister, node->opcode());
1795 Node* generator = NodeProperties::GetValueInput(node, 0);
1796 Node* effect = NodeProperties::GetEffectInput(node);
1797 Node* control = NodeProperties::GetControlInput(node);
1798 int index = OpParameter<int>(node);
1799
1800 FieldAccess array_field = AccessBuilder::ForJSGeneratorObjectOperandStack();
1801 FieldAccess element_field = AccessBuilder::ForFixedArraySlot(index);
1802
1803 Node* array = effect = graph()->NewNode(simplified()->LoadField(array_field),
1804 generator, effect, control);
1805 Node* element = effect = graph()->NewNode(
1806 simplified()->LoadField(element_field), array, effect, control);
1807 Node* stale = jsgraph()->StaleRegisterConstant();
1808 effect = graph()->NewNode(simplified()->StoreField(element_field), array,
1809 stale, effect, control);
1810
1811 ReplaceWithValue(node, element, effect, control);
1812 return Changed(element);
1813}
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001814
1815Reduction JSTypedLowering::ReduceSelect(Node* node) {
1816 DCHECK_EQ(IrOpcode::kSelect, node->opcode());
1817 Node* const condition = NodeProperties::GetValueInput(node, 0);
1818 Type* const condition_type = NodeProperties::GetType(condition);
1819 Node* const vtrue = NodeProperties::GetValueInput(node, 1);
1820 Type* const vtrue_type = NodeProperties::GetType(vtrue);
1821 Node* const vfalse = NodeProperties::GetValueInput(node, 2);
1822 Type* const vfalse_type = NodeProperties::GetType(vfalse);
1823 if (condition_type->Is(true_type_)) {
1824 // Select(condition:true, vtrue, vfalse) => vtrue
1825 return Replace(vtrue);
1826 }
1827 if (condition_type->Is(false_type_)) {
1828 // Select(condition:false, vtrue, vfalse) => vfalse
1829 return Replace(vfalse);
1830 }
1831 if (vtrue_type->Is(true_type_) && vfalse_type->Is(false_type_)) {
1832 // Select(condition, vtrue:true, vfalse:false) => condition
1833 return Replace(condition);
1834 }
1835 if (vtrue_type->Is(false_type_) && vfalse_type->Is(true_type_)) {
1836 // Select(condition, vtrue:false, vfalse:true) => BooleanNot(condition)
1837 node->TrimInputCount(1);
1838 NodeProperties::ChangeOp(node, simplified()->BooleanNot());
1839 return Changed(node);
1840 }
1841 return NoChange();
1842}
1843
1844
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001845Reduction JSTypedLowering::Reduce(Node* node) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001846 // Check if the output type is a singleton. In that case we already know the
1847 // result value and can simply replace the node if it's eliminable.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001848 if (!NodeProperties::IsConstant(node) && NodeProperties::IsTyped(node) &&
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001849 node->op()->HasProperty(Operator::kEliminatable)) {
Ben Murdoch61f157c2016-09-16 13:49:30 +01001850 // We can only constant-fold nodes here, that are known to not cause any
1851 // side-effect, may it be a JavaScript observable side-effect or a possible
1852 // eager deoptimization exit (i.e. {node} has an operator that doesn't have
1853 // the Operator::kNoDeopt property).
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001854 Type* upper = NodeProperties::GetType(node);
Ben Murdoch61f157c2016-09-16 13:49:30 +01001855 if (upper->IsInhabited()) {
1856 if (upper->IsConstant()) {
1857 Node* replacement = jsgraph()->Constant(upper->AsConstant()->Value());
1858 ReplaceWithValue(node, replacement);
1859 return Changed(replacement);
1860 } else if (upper->Is(Type::MinusZero())) {
1861 Node* replacement = jsgraph()->Constant(factory()->minus_zero_value());
1862 ReplaceWithValue(node, replacement);
1863 return Changed(replacement);
1864 } else if (upper->Is(Type::NaN())) {
1865 Node* replacement = jsgraph()->NaNConstant();
1866 ReplaceWithValue(node, replacement);
1867 return Changed(replacement);
1868 } else if (upper->Is(Type::Null())) {
1869 Node* replacement = jsgraph()->NullConstant();
1870 ReplaceWithValue(node, replacement);
1871 return Changed(replacement);
1872 } else if (upper->Is(Type::PlainNumber()) &&
1873 upper->Min() == upper->Max()) {
1874 Node* replacement = jsgraph()->Constant(upper->Min());
1875 ReplaceWithValue(node, replacement);
1876 return Changed(replacement);
1877 } else if (upper->Is(Type::Undefined())) {
1878 Node* replacement = jsgraph()->UndefinedConstant();
1879 ReplaceWithValue(node, replacement);
1880 return Changed(replacement);
1881 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001882 }
1883 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001884 switch (node->opcode()) {
1885 case IrOpcode::kJSEqual:
1886 return ReduceJSEqual(node, false);
1887 case IrOpcode::kJSNotEqual:
1888 return ReduceJSEqual(node, true);
1889 case IrOpcode::kJSStrictEqual:
1890 return ReduceJSStrictEqual(node, false);
1891 case IrOpcode::kJSStrictNotEqual:
1892 return ReduceJSStrictEqual(node, true);
1893 case IrOpcode::kJSLessThan: // fall through
1894 case IrOpcode::kJSGreaterThan: // fall through
1895 case IrOpcode::kJSLessThanOrEqual: // fall through
1896 case IrOpcode::kJSGreaterThanOrEqual:
1897 return ReduceJSComparison(node);
1898 case IrOpcode::kJSBitwiseOr:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001899 return ReduceInt32Binop(node, simplified()->NumberBitwiseOr());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001900 case IrOpcode::kJSBitwiseXor:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001901 return ReduceInt32Binop(node, simplified()->NumberBitwiseXor());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001902 case IrOpcode::kJSBitwiseAnd:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001903 return ReduceInt32Binop(node, simplified()->NumberBitwiseAnd());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001904 case IrOpcode::kJSShiftLeft:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001905 return ReduceUI32Shift(node, kSigned, simplified()->NumberShiftLeft());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001906 case IrOpcode::kJSShiftRight:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001907 return ReduceUI32Shift(node, kSigned, simplified()->NumberShiftRight());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001908 case IrOpcode::kJSShiftRightLogical:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001909 return ReduceUI32Shift(node, kUnsigned,
1910 simplified()->NumberShiftRightLogical());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001911 case IrOpcode::kJSAdd:
1912 return ReduceJSAdd(node);
1913 case IrOpcode::kJSSubtract:
Ben Murdoch61f157c2016-09-16 13:49:30 +01001914 return ReduceJSSubtract(node);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001915 case IrOpcode::kJSMultiply:
Ben Murdoch61f157c2016-09-16 13:49:30 +01001916 return ReduceJSMultiply(node);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001917 case IrOpcode::kJSDivide:
Ben Murdoch61f157c2016-09-16 13:49:30 +01001918 return ReduceJSDivide(node);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001919 case IrOpcode::kJSModulus:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001920 return ReduceJSModulus(node);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001921 case IrOpcode::kJSToBoolean:
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001922 return ReduceJSToBoolean(node);
Ben Murdochda12d292016-06-02 14:46:10 +01001923 case IrOpcode::kJSToInteger:
1924 return ReduceJSToInteger(node);
1925 case IrOpcode::kJSToLength:
1926 return ReduceJSToLength(node);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001927 case IrOpcode::kJSToNumber:
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001928 return ReduceJSToNumber(node);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001929 case IrOpcode::kJSToString:
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001930 return ReduceJSToString(node);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001931 case IrOpcode::kJSToObject:
1932 return ReduceJSToObject(node);
1933 case IrOpcode::kJSLoadNamed:
1934 return ReduceJSLoadNamed(node);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001935 case IrOpcode::kJSLoadProperty:
1936 return ReduceJSLoadProperty(node);
1937 case IrOpcode::kJSStoreProperty:
1938 return ReduceJSStoreProperty(node);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001939 case IrOpcode::kJSInstanceOf:
1940 return ReduceJSInstanceOf(node);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001941 case IrOpcode::kJSLoadContext:
1942 return ReduceJSLoadContext(node);
1943 case IrOpcode::kJSStoreContext:
1944 return ReduceJSStoreContext(node);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001945 case IrOpcode::kJSConvertReceiver:
1946 return ReduceJSConvertReceiver(node);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001947 case IrOpcode::kJSCallConstruct:
1948 return ReduceJSCallConstruct(node);
1949 case IrOpcode::kJSCallFunction:
1950 return ReduceJSCallFunction(node);
1951 case IrOpcode::kJSForInDone:
1952 return ReduceJSForInDone(node);
1953 case IrOpcode::kJSForInNext:
1954 return ReduceJSForInNext(node);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001955 case IrOpcode::kJSForInStep:
1956 return ReduceJSForInStep(node);
Ben Murdoch61f157c2016-09-16 13:49:30 +01001957 case IrOpcode::kJSGeneratorStore:
1958 return ReduceJSGeneratorStore(node);
1959 case IrOpcode::kJSGeneratorRestoreContinuation:
1960 return ReduceJSGeneratorRestoreContinuation(node);
1961 case IrOpcode::kJSGeneratorRestoreRegister:
1962 return ReduceJSGeneratorRestoreRegister(node);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001963 case IrOpcode::kSelect:
1964 return ReduceSelect(node);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001965 default:
1966 break;
1967 }
1968 return NoChange();
1969}
1970
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001971
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001972Node* JSTypedLowering::Word32Shl(Node* const lhs, int32_t const rhs) {
1973 if (rhs == 0) return lhs;
1974 return graph()->NewNode(machine()->Word32Shl(), lhs,
1975 jsgraph()->Int32Constant(rhs));
1976}
1977
Ben Murdoch61f157c2016-09-16 13:49:30 +01001978Node* JSTypedLowering::EmptyFrameState() {
1979 return graph()->NewNode(
1980 common()->FrameState(BailoutId::None(), OutputFrameStateCombine::Ignore(),
1981 nullptr),
1982 jsgraph()->EmptyStateValues(), jsgraph()->EmptyStateValues(),
1983 jsgraph()->EmptyStateValues(), jsgraph()->NoContextConstant(),
1984 jsgraph()->UndefinedConstant(), graph()->start());
1985}
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001986
1987Factory* JSTypedLowering::factory() const { return jsgraph()->factory(); }
1988
1989
1990Graph* JSTypedLowering::graph() const { return jsgraph()->graph(); }
1991
1992
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001993Isolate* JSTypedLowering::isolate() const { return jsgraph()->isolate(); }
1994
1995
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001996JSOperatorBuilder* JSTypedLowering::javascript() const {
1997 return jsgraph()->javascript();
1998}
1999
2000
2001CommonOperatorBuilder* JSTypedLowering::common() const {
2002 return jsgraph()->common();
2003}
2004
2005
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002006SimplifiedOperatorBuilder* JSTypedLowering::simplified() const {
2007 return jsgraph()->simplified();
2008}
2009
2010
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002011MachineOperatorBuilder* JSTypedLowering::machine() const {
2012 return jsgraph()->machine();
2013}
2014
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002015
2016CompilationDependencies* JSTypedLowering::dependencies() const {
2017 return dependencies_;
2018}
2019
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002020} // namespace compiler
2021} // namespace internal
2022} // namespace v8