1 // Copyright 2014 the V8 project authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "src/code-factory.h"
6 #include "src/compilation-dependencies.h"
7 #include "src/compiler/access-builder.h"
8 #include "src/compiler/js-graph.h"
9 #include "src/compiler/js-typed-lowering.h"
10 #include "src/compiler/linkage.h"
11 #include "src/compiler/node-matchers.h"
12 #include "src/compiler/node-properties.h"
13 #include "src/compiler/operator-properties.h"
14 #include "src/type-cache.h"
15 #include "src/types.h"
16
17 namespace v8 {
18 namespace internal {
19 namespace compiler {
20
21 // 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.
25 class JSBinopReduction final {
26 public:
JSBinopReduction(JSTypedLowering * lowering,Node * node)27 JSBinopReduction(JSTypedLowering* lowering, Node* node)
28 : lowering_(lowering), node_(node) {}
29
GetNumberBinaryOperationFeedback()30 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
GetNumberCompareOperationFeedback()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
ConvertInputsToNumber(Node * frame_state)65 void ConvertInputsToNumber(Node* frame_state) {
66 // 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
84 ? ConvertPlainPrimitiveToNumber(left())
85 : ConvertSingleInputToNumber(
86 left(), CreateFrameStateForLeftInput(frame_state));
87 right_input = right_is_primitive
88 ? ConvertPlainPrimitiveToNumber(right())
89 : ConvertSingleInputToNumber(
90 right(), CreateFrameStateForRightInput(
91 frame_state, left_input));
92 }
93
94 node_->ReplaceInput(0, left_input);
95 node_->ReplaceInput(1, right_input);
96 }
97
ConvertInputsToUI32(Signedness left_signedness,Signedness right_signedness)98 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));
102 }
103
SwapInputs()104 void SwapInputs() {
105 Node* l = left();
106 Node* r = right();
107 node_->ReplaceInput(0, r);
108 node_->ReplaceInput(1, l);
109 }
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.
ChangeToPureOperator(const Operator * op,bool invert=false,Type * type=Type::Any ())113 Reduction ChangeToPureOperator(const Operator* op, bool invert = false,
114 Type* type = Type::Any()) {
115 DCHECK_EQ(0, op->EffectInputCount());
116 DCHECK_EQ(false, OperatorProperties::HasContextInput(op));
117 DCHECK_EQ(0, op->ControlInputCount());
118 DCHECK_EQ(2, op->ValueInputCount());
119
120 // Remove the effects from the node, and update its effect/control usages.
121 if (node_->op()->EffectInputCount() > 0) {
122 lowering_->RelaxEffectsAndControls(node_);
123 }
124 // Remove the inputs corresponding to context, effect, and control.
125 NodeProperties::RemoveNonValueInputs(node_);
126 // Finally, update the operator to the new one.
127 NodeProperties::ChangeOp(node_, op);
128
129 // TODO(jarin): Replace the explicit typing hack with a call to some method
130 // that encapsulates changing the operator and re-typing.
131 Type* node_type = NodeProperties::GetType(node_);
132 NodeProperties::SetType(node_, Type::Intersect(node_type, type, zone()));
133
134 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_);
140 return lowering_->Replace(value);
141 }
142 return lowering_->Changed(node_);
143 }
144
ChangeToSpeculativeOperator(const Operator * op,Type * upper_bound)145 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
ChangeToPureOperator(const Operator * op,Type * type)192 Reduction ChangeToPureOperator(const Operator* op, Type* type) {
193 return ChangeToPureOperator(op, false, type);
194 }
195
LeftInputIs(Type * t)196 bool LeftInputIs(Type* t) { return left_type()->Is(t); }
197
RightInputIs(Type * t)198 bool RightInputIs(Type* t) { return right_type()->Is(t); }
199
OneInputIs(Type * t)200 bool OneInputIs(Type* t) { return LeftInputIs(t) || RightInputIs(t); }
201
BothInputsAre(Type * t)202 bool BothInputsAre(Type* t) { return LeftInputIs(t) && RightInputIs(t); }
203
OneInputCannotBe(Type * t)204 bool OneInputCannotBe(Type* t) {
205 return !left_type()->Maybe(t) || !right_type()->Maybe(t);
206 }
207
NeitherInputCanBe(Type * t)208 bool NeitherInputCanBe(Type* t) {
209 return !left_type()->Maybe(t) && !right_type()->Maybe(t);
210 }
211
effect()212 Node* effect() { return NodeProperties::GetEffectInput(node_); }
control()213 Node* control() { return NodeProperties::GetControlInput(node_); }
context()214 Node* context() { return NodeProperties::GetContextInput(node_); }
left()215 Node* left() { return NodeProperties::GetValueInput(node_, 0); }
right()216 Node* right() { return NodeProperties::GetValueInput(node_, 1); }
left_type()217 Type* left_type() { return NodeProperties::GetType(node_->InputAt(0)); }
right_type()218 Type* right_type() { return NodeProperties::GetType(node_->InputAt(1)); }
219
simplified()220 SimplifiedOperatorBuilder* simplified() { return lowering_->simplified(); }
graph() const221 Graph* graph() const { return lowering_->graph(); }
jsgraph()222 JSGraph* jsgraph() { return lowering_->jsgraph(); }
javascript()223 JSOperatorBuilder* javascript() { return lowering_->javascript(); }
machine()224 MachineOperatorBuilder* machine() { return lowering_->machine(); }
common()225 CommonOperatorBuilder* common() { return jsgraph()->common(); }
zone() const226 Zone* zone() const { return graph()->zone(); }
227
228 private:
229 JSTypedLowering* lowering_; // The containing lowering instance.
230 Node* node_; // The original node.
231
CreateFrameStateForLeftInput(Node * frame_state)232 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
CreateFrameStateForRightInput(Node * frame_state,Node * converted_left)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
ConvertPlainPrimitiveToNumber(Node * node)301 Node* ConvertPlainPrimitiveToNumber(Node* node) {
302 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();
306 if (NodeProperties::GetType(node)->Is(Type::Number())) {
307 return node;
308 }
309 return graph()->NewNode(simplified()->PlainPrimitiveToNumber(), node);
310 }
311
ConvertSingleInputToNumber(Node * node,Node * frame_state)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());
316 Node* const if_success = graph()->NewNode(common()->IfSuccess(), n);
317 NodeProperties::ReplaceControlInput(node_, if_success);
318 NodeProperties::ReplaceUses(node_, node_, node_, node_, n);
319 update_effect(n);
320 return n;
321 }
322
ConvertBothInputsToNumber(Node ** left_result,Node ** right_result,Node * frame_state)323 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);
361 }
362 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;
369 }
370
ConvertToUI32(Node * node,Signedness signedness)371 Node* ConvertToUI32(Node* node, Signedness signedness) {
372 // Avoid introducing too many eager NumberToXXnt32() operations.
373 Type* type = NodeProperties::GetType(node);
374 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;
385 }
386
update_effect(Node * effect)387 void update_effect(Node* effect) {
388 NodeProperties::ReplaceEffectInput(node_, effect);
389 }
390 };
391
392
393 // 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
JSTypedLowering(Editor * editor,CompilationDependencies * dependencies,Flags flags,JSGraph * jsgraph,Zone * zone)398 JSTypedLowering::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
ReduceJSAdd(Node * node)418 Reduction JSTypedLowering::ReduceJSAdd(Node* node) {
419 if (flags() & kDisableBinaryOpReduction) return NoChange();
420
421 JSBinopReduction r(this, node);
422
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())) {
438 // JSAdd(x:number, y:number) => NumberAdd(x, y)
439 Node* frame_state = NodeProperties::GetFrameStateInput(node, 1);
440 r.ConvertInputsToNumber(frame_state);
441 return r.ChangeToPureOperator(simplified()->NumberAdd(), Type::Number());
442 }
443 if (r.NeitherInputCanBe(Type::StringOrReceiver())) {
444 // JSAdd(x:-string, y:-string) => NumberAdd(ToNumber(x), ToNumber(y))
445 Node* frame_state = NodeProperties::GetFrameStateInput(node, 1);
446 r.ConvertInputsToNumber(frame_state);
447 return r.ChangeToPureOperator(simplified()->NumberAdd(), Type::Number());
448 }
449 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)
458 Callable const callable =
459 CodeFactory::StringAdd(isolate(), flags, NOT_TENURED);
460 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);
469 }
470 return NoChange();
471 }
472
473
ReduceJSModulus(Node * node)474 Reduction JSTypedLowering::ReduceJSModulus(Node* node) {
475 if (flags() & kDisableBinaryOpReduction) return NoChange();
476 JSBinopReduction r(this, node);
477 if (r.BothInputsAre(Type::Number())) {
478 // JSModulus(x:number, x:number) => NumberModulus(x, y)
479 return r.ChangeToPureOperator(simplified()->NumberModulus(),
480 Type::Number());
481 }
482 BinaryOperationHints::Hint feedback = r.GetNumberBinaryOperationFeedback();
483 if (feedback != BinaryOperationHints::kAny) {
484 return r.ChangeToSpeculativeOperator(
485 simplified()->SpeculativeNumberModulus(feedback), Type::Number());
486 }
487 return NoChange();
488 }
489
ReduceJSSubtract(Node * node)490 Reduction JSTypedLowering::ReduceJSSubtract(Node* node) {
491 if (flags() & kDisableBinaryOpReduction) return NoChange();
492 JSBinopReduction r(this, node);
493 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());
507 }
508 Node* frame_state = NodeProperties::GetFrameStateInput(node, 1);
509 r.ConvertInputsToNumber(frame_state);
510 return r.ChangeToPureOperator(simplified()->NumberSubtract(), Type::Number());
511 }
512
ReduceJSMultiply(Node * node)513 Reduction 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
ReduceJSDivide(Node * node)528 Reduction 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());
539 }
540
541
ReduceInt32Binop(Node * node,const Operator * intOp)542 Reduction JSTypedLowering::ReduceInt32Binop(Node* node, const Operator* intOp) {
543 if (flags() & kDisableBinaryOpReduction) return NoChange();
544
545 JSBinopReduction r(this, node);
546 Node* frame_state = NodeProperties::GetFrameStateInput(node, 1);
547 r.ConvertInputsToNumber(frame_state);
548 r.ConvertInputsToUI32(kSigned, kSigned);
549 return r.ChangeToPureOperator(intOp, Type::Integral32());
550 }
551
552
ReduceUI32Shift(Node * node,Signedness left_signedness,const Operator * shift_op)553 Reduction JSTypedLowering::ReduceUI32Shift(Node* node,
554 Signedness left_signedness,
555 const Operator* shift_op) {
556 if (flags() & kDisableBinaryOpReduction) return NoChange();
557
558 JSBinopReduction r(this, node);
559 Node* frame_state = NodeProperties::GetFrameStateInput(node, 1);
560 r.ConvertInputsToNumber(frame_state);
561 r.ConvertInputsToUI32(left_signedness, kUnsigned);
562 return r.ChangeToPureOperator(shift_op);
563 }
564
565
ReduceJSComparison(Node * node)566 Reduction JSTypedLowering::ReduceJSComparison(Node* node) {
567 if (flags() & kDisableBinaryOpReduction) return NoChange();
568
569 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 }
591 r.ChangeToPureOperator(stringOp);
592 return Changed(node);
593 }
594
595 CompareOperationHints::Hint hint = r.GetNumberCompareOperationFeedback();
596 if (hint != CompareOperationHints::kAny ||
597 r.OneInputCannotBe(Type::StringOrReceiver())) {
598 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();
606 } else if (hint != CompareOperationHints::kAny) {
607 less_than = simplified()->SpeculativeNumberLessThan(hint);
608 less_than_or_equal = simplified()->SpeculativeNumberLessThanOrEqual(hint);
609 } else {
610 // TODO(turbofan): mixed signed/unsigned int32 comparisons.
611 Node* frame_state = NodeProperties::GetFrameStateInput(node, 1);
612 r.ConvertInputsToNumber(frame_state);
613 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 }
635 if (comparison->EffectInputCount() > 0) {
636 return r.ChangeToSpeculativeOperator(comparison, Type::Boolean());
637 } else {
638 return r.ChangeToPureOperator(comparison);
639 }
640 }
641 // TODO(turbofan): relax/remove effects of this operator in other cases.
642 return NoChange(); // Keep a generic comparison.
643 }
644
ReduceJSEqualTypeOf(Node * node,bool invert)645 Reduction 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 }
683
ReduceJSEqual(Node * node,bool invert)684 Reduction JSTypedLowering::ReduceJSEqual(Node* node, bool invert) {
685 if (flags() & kDisableBinaryOpReduction) return NoChange();
686
687 Reduction const reduction = ReduceJSEqualTypeOf(node, invert);
688 if (reduction.Changed()) {
689 ReplaceWithValue(node, reduction.replacement());
690 return reduction;
691 }
692
693 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())) {
699 return r.ChangeToPureOperator(simplified()->StringEqual(), invert);
700 }
701 if (r.BothInputsAre(Type::Boolean())) {
702 return r.ChangeToPureOperator(simplified()->ReferenceEqual(Type::Boolean()),
703 invert);
704 }
705 if (r.BothInputsAre(Type::Receiver())) {
706 return r.ChangeToPureOperator(
707 simplified()->ReferenceEqual(Type::Receiver()), invert);
708 }
709 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());
714 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 }
724 return NoChange();
725 }
726
727
ReduceJSStrictEqual(Node * node,bool invert)728 Reduction JSTypedLowering::ReduceJSStrictEqual(Node* node, bool invert) {
729 if (flags() & kDisableBinaryOpReduction) return NoChange();
730
731 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())) {
735 Node* replacement = jsgraph()->BooleanConstant(!invert);
736 ReplaceWithValue(node, replacement);
737 return Replace(replacement);
738 }
739 }
740 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.
744 if (!r.left_type()->Maybe(r.right_type())) {
745 Node* replacement = jsgraph()->BooleanConstant(invert);
746 ReplaceWithValue(node, replacement);
747 return Replace(replacement);
748 }
749 }
750 Reduction const reduction = ReduceJSEqualTypeOf(node, invert);
751 if (reduction.Changed()) {
752 return reduction;
753 }
754 if (r.OneInputIs(the_hole_type_)) {
755 return r.ChangeToPureOperator(simplified()->ReferenceEqual(the_hole_type_),
756 invert);
757 }
758 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 }
778 if (r.BothInputsAre(Type::Unique())) {
779 return r.ChangeToPureOperator(simplified()->ReferenceEqual(Type::Unique()),
780 invert);
781 }
782 if (r.BothInputsAre(Type::String())) {
783 return r.ChangeToPureOperator(simplified()->StringEqual(), invert);
784 }
785 if (r.BothInputsAre(Type::Number())) {
786 return r.ChangeToPureOperator(simplified()->NumberEqual(), invert);
787 }
788 // TODO(turbofan): js-typed-lowering of StrictEqual(mixed types)
789 return NoChange();
790 }
791
792
ReduceJSToBoolean(Node * node)793 Reduction JSTypedLowering::ReduceJSToBoolean(Node* node) {
794 Node* const input = node->InputAt(0);
795 Type* const input_type = NodeProperties::GetType(input);
796 if (input_type->Is(Type::Boolean())) {
797 // JSToBoolean(x:boolean) => x
798 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()));
804 node->TrimInputCount(1);
805 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,
811 graph()->start(), graph()->start());
812 ReplaceWithValue(node, node, length);
813 node->ReplaceInput(0, jsgraph()->ZeroConstant());
814 node->ReplaceInput(1, length);
815 NodeProperties::ChangeOp(node, simplified()->NumberLessThan());
816 return Changed(node);
817 }
818 return NoChange();
819 }
820
ReduceJSToInteger(Node * node)821 Reduction 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
ReduceJSToLength(Node * node)832 Reduction 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 }
866
ReduceJSToNumberInput(Node * input)867 Reduction JSTypedLowering::ReduceJSToNumberInput(Node* input) {
868 // Try constant-folding of JSToNumber with constant inputs.
869 Type* input_type = NodeProperties::GetType(input);
870 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 }
880 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
886 return Replace(jsgraph()->NaNConstant());
887 }
888 if (input_type->Is(Type::Null())) {
889 // JSToNumber(null) => #0
890 return Replace(jsgraph()->ZeroConstant());
891 }
892 if (input_type->Is(Type::Boolean())) {
893 // JSToNumber(x:boolean) => BooleanToNumber(x)
894 return Replace(graph()->NewNode(simplified()->BooleanToNumber(), input));
895 }
896 if (input_type->Is(Type::String())) {
897 // JSToNumber(x:string) => StringToNumber(x)
898 return Replace(graph()->NewNode(simplified()->StringToNumber(), input));
899 }
900 return NoChange();
901 }
902
903
ReduceJSToNumber(Node * node)904 Reduction 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()) {
909 ReplaceWithValue(node, reduction.replacement());
910 return reduction;
911 }
912 Type* const input_type = NodeProperties::GetType(input);
913 if (input_type->Is(Type::PlainPrimitive())) {
914 RelaxEffectsAndControls(node);
915 node->TrimInputCount(1);
916 NodeProperties::ChangeOp(node, simplified()->PlainPrimitiveToNumber());
917 return Changed(node);
918 }
919 return NoChange();
920 }
921
922
ReduceJSToStringInput(Node * input)923 Reduction JSTypedLowering::ReduceJSToStringInput(Node* input) {
924 if (input->opcode() == IrOpcode::kJSToString) {
925 // Recursively try to reduce the input first.
926 Reduction result = ReduceJSToString(input);
927 if (result.Changed()) return result;
928 return Changed(input); // JSToString(JSToString(x)) => JSToString(x)
929 }
930 Type* input_type = NodeProperties::GetType(input);
931 if (input_type->Is(Type::String())) {
932 return Changed(input); // JSToString(x:string) => x
933 }
934 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 }
940 if (input_type->Is(Type::Undefined())) {
941 return Replace(jsgraph()->HeapConstant(factory()->undefined_string()));
942 }
943 if (input_type->Is(Type::Null())) {
944 return Replace(jsgraph()->HeapConstant(factory()->null_string()));
945 }
946 // TODO(turbofan): js-typed-lowering of ToString(x:number)
947 return NoChange();
948 }
949
950
ReduceJSToString(Node * node)951 Reduction 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()) {
956 ReplaceWithValue(node, reduction.replacement());
957 return reduction;
958 }
959 return NoChange();
960 }
961
962
ReduceJSToObject(Node * node)963 Reduction 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
ReduceJSLoadNamed(Node * node)1043 Reduction 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 }
1059 return NoChange();
1060 }
1061
1062
ReduceJSLoadProperty(Node * node)1063 Reduction JSTypedLowering::ReduceJSLoadProperty(Node* node) {
1064 Node* key = NodeProperties::GetValueInput(node, 1);
1065 Node* base = NodeProperties::GetValueInput(node, 0);
1066 Type* key_type = NodeProperties::GetType(key);
1067 HeapObjectMatcher mbase(base);
1068 if (mbase.HasValue() && mbase.Value()->IsJSTypedArray()) {
1069 Handle<JSTypedArray> const array =
1070 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);
1101 }
1102 }
1103 }
1104 return NoChange();
1105 }
1106
1107
ReduceJSStoreProperty(Node * node)1108 Reduction 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);
1112 Type* key_type = NodeProperties::GetType(key);
1113 Type* value_type = NodeProperties::GetType(value);
1114 HeapObjectMatcher mbase(base);
1115 if (mbase.HasValue() && mbase.Value()->IsJSTypedArray()) {
1116 Handle<JSTypedArray> const array =
1117 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.
1136 if (!value_type->Is(Type::Number())) {
1137 Reduction number_reduction = ReduceJSToNumberInput(value);
1138 if (number_reduction.Changed()) {
1139 value = number_reduction.replacement();
1140 } else {
1141 Node* frame_state_for_to_number =
1142 NodeProperties::FindFrameStateBefore(node);
1143 value = effect =
1144 graph()->NewNode(javascript()->ToNumber(), value, context,
1145 frame_state_for_to_number, effect, control);
1146 }
1147 }
1148 // 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);
1167 node->ReplaceInput(0, buffer);
1168 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));
1175 return Changed(node);
1176 }
1177 }
1178 }
1179 return NoChange();
1180 }
1181
1182
ReduceJSInstanceOf(Node * node)1183 Reduction 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.
1189 if (!(flags() & kDeoptimizationEnabled)) return NoChange();
1190
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
1208 // 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()) {
1214 return NoChange();
1215 }
1216
1217 // 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
1221 Handle<Map> initial_map(function->initial_map(), isolate());
1222 dependencies()->AssumeInitialMapCantChange(initial_map);
1223 Node* prototype =
1224 jsgraph()->Constant(handle(initial_map->prototype(), isolate()));
1225
1226 // If the left hand side is an object, no smi check is needed.
1227 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);
1233
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(
1289 javascript()->CallRuntime(Runtime::kHasInPrototypeChain), r.left(),
1290 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
1298 // 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
1309 // 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
1320 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
1339 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);
1345
1346 ReplaceWithValue(node, result, effect, control);
1347 return Changed(result);
1348 }
1349
1350
ReduceJSLoadContext(Node * node)1351 Reduction JSTypedLowering::ReduceJSLoadContext(Node* node) {
1352 DCHECK_EQ(IrOpcode::kJSLoadContext, node->opcode());
1353 ContextAccess const& access = ContextAccessOf(node->op());
1354 Node* effect = NodeProperties::GetEffectInput(node);
1355 Node* control = graph()->start();
1356 for (size_t i = 0; i < access.depth(); ++i) {
1357 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);
1362 }
1363 node->ReplaceInput(1, effect);
1364 node->ReplaceInput(2, control);
1365 NodeProperties::ChangeOp(
1366 node,
1367 simplified()->LoadField(AccessBuilder::ForContextSlot(access.index())));
1368 return Changed(node);
1369 }
1370
1371
ReduceJSStoreContext(Node * node)1372 Reduction JSTypedLowering::ReduceJSStoreContext(Node* node) {
1373 DCHECK_EQ(IrOpcode::kJSStoreContext, node->opcode());
1374 ContextAccess const& access = ContextAccessOf(node->op());
1375 Node* effect = NodeProperties::GetEffectInput(node);
1376 Node* control = graph()->start();
1377 for (size_t i = 0; i < access.depth(); ++i) {
1378 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);
1383 }
1384 node->RemoveInput(2);
1385 node->ReplaceInput(2, effect);
1386 NodeProperties::ChangeOp(
1387 node,
1388 simplified()->StoreField(AccessBuilder::ForContextSlot(access.index())));
1389 return Changed(node);
1390 }
1391
1392
ReduceJSConvertReceiver(Node * node)1393 Reduction 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
ReduceJSCallConstruct(Node * node)1489 Reduction 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
1505 // 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())) {
1524 // 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
ReduceJSCallFunction(Node * node)1543 Reduction 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);
1552 Node* effect = NodeProperties::GetEffectInput(node);
1553 Node* control = NodeProperties::GetControlInput(node);
1554 Node* frame_state = NodeProperties::FindFrameStateBefore(node);
1555
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
1592 // 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())) {
1629 // 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(
1650 node, javascript()->CallFunction(p.arity(), p.feedback(), convert_mode,
1651 p.tail_call_mode()));
1652 return Changed(node);
1653 }
1654
1655 return NoChange();
1656 }
1657
1658
ReduceJSForInDone(Node * node)1659 Reduction 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
ReduceJSForInNext(Node * node)1667 Reduction 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 {
1708 // 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);
1714 }
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
ReduceJSForInStep(Node * node)1729 Reduction 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
ReduceJSGeneratorStore(Node * node)1736 Reduction 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
ReduceJSGeneratorRestoreContinuation(Node * node)1774 Reduction 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
ReduceJSGeneratorRestoreRegister(Node * node)1793 Reduction 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 }
1814
ReduceSelect(Node * node)1815 Reduction 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
Reduce(Node * node)1845 Reduction JSTypedLowering::Reduce(Node* node) {
1846 // 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.
1848 if (!NodeProperties::IsConstant(node) && NodeProperties::IsTyped(node) &&
1849 node->op()->HasProperty(Operator::kEliminatable)) {
1850 // 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).
1854 Type* upper = NodeProperties::GetType(node);
1855 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 }
1882 }
1883 }
1884 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:
1899 return ReduceInt32Binop(node, simplified()->NumberBitwiseOr());
1900 case IrOpcode::kJSBitwiseXor:
1901 return ReduceInt32Binop(node, simplified()->NumberBitwiseXor());
1902 case IrOpcode::kJSBitwiseAnd:
1903 return ReduceInt32Binop(node, simplified()->NumberBitwiseAnd());
1904 case IrOpcode::kJSShiftLeft:
1905 return ReduceUI32Shift(node, kSigned, simplified()->NumberShiftLeft());
1906 case IrOpcode::kJSShiftRight:
1907 return ReduceUI32Shift(node, kSigned, simplified()->NumberShiftRight());
1908 case IrOpcode::kJSShiftRightLogical:
1909 return ReduceUI32Shift(node, kUnsigned,
1910 simplified()->NumberShiftRightLogical());
1911 case IrOpcode::kJSAdd:
1912 return ReduceJSAdd(node);
1913 case IrOpcode::kJSSubtract:
1914 return ReduceJSSubtract(node);
1915 case IrOpcode::kJSMultiply:
1916 return ReduceJSMultiply(node);
1917 case IrOpcode::kJSDivide:
1918 return ReduceJSDivide(node);
1919 case IrOpcode::kJSModulus:
1920 return ReduceJSModulus(node);
1921 case IrOpcode::kJSToBoolean:
1922 return ReduceJSToBoolean(node);
1923 case IrOpcode::kJSToInteger:
1924 return ReduceJSToInteger(node);
1925 case IrOpcode::kJSToLength:
1926 return ReduceJSToLength(node);
1927 case IrOpcode::kJSToNumber:
1928 return ReduceJSToNumber(node);
1929 case IrOpcode::kJSToString:
1930 return ReduceJSToString(node);
1931 case IrOpcode::kJSToObject:
1932 return ReduceJSToObject(node);
1933 case IrOpcode::kJSLoadNamed:
1934 return ReduceJSLoadNamed(node);
1935 case IrOpcode::kJSLoadProperty:
1936 return ReduceJSLoadProperty(node);
1937 case IrOpcode::kJSStoreProperty:
1938 return ReduceJSStoreProperty(node);
1939 case IrOpcode::kJSInstanceOf:
1940 return ReduceJSInstanceOf(node);
1941 case IrOpcode::kJSLoadContext:
1942 return ReduceJSLoadContext(node);
1943 case IrOpcode::kJSStoreContext:
1944 return ReduceJSStoreContext(node);
1945 case IrOpcode::kJSConvertReceiver:
1946 return ReduceJSConvertReceiver(node);
1947 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);
1955 case IrOpcode::kJSForInStep:
1956 return ReduceJSForInStep(node);
1957 case IrOpcode::kJSGeneratorStore:
1958 return ReduceJSGeneratorStore(node);
1959 case IrOpcode::kJSGeneratorRestoreContinuation:
1960 return ReduceJSGeneratorRestoreContinuation(node);
1961 case IrOpcode::kJSGeneratorRestoreRegister:
1962 return ReduceJSGeneratorRestoreRegister(node);
1963 case IrOpcode::kSelect:
1964 return ReduceSelect(node);
1965 default:
1966 break;
1967 }
1968 return NoChange();
1969 }
1970
1971
Word32Shl(Node * const lhs,int32_t const rhs)1972 Node* 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
EmptyFrameState()1978 Node* 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 }
1986
factory() const1987 Factory* JSTypedLowering::factory() const { return jsgraph()->factory(); }
1988
1989
graph() const1990 Graph* JSTypedLowering::graph() const { return jsgraph()->graph(); }
1991
1992
isolate() const1993 Isolate* JSTypedLowering::isolate() const { return jsgraph()->isolate(); }
1994
1995
javascript() const1996 JSOperatorBuilder* JSTypedLowering::javascript() const {
1997 return jsgraph()->javascript();
1998 }
1999
2000
common() const2001 CommonOperatorBuilder* JSTypedLowering::common() const {
2002 return jsgraph()->common();
2003 }
2004
2005
simplified() const2006 SimplifiedOperatorBuilder* JSTypedLowering::simplified() const {
2007 return jsgraph()->simplified();
2008 }
2009
2010
machine() const2011 MachineOperatorBuilder* JSTypedLowering::machine() const {
2012 return jsgraph()->machine();
2013 }
2014
2015
dependencies() const2016 CompilationDependencies* JSTypedLowering::dependencies() const {
2017 return dependencies_;
2018 }
2019
2020 } // namespace compiler
2021 } // namespace internal
2022 } // namespace v8
2023