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/compiler/js-typed-lowering.h"
6
7 #include "src/ast/modules.h"
8 #include "src/builtins/builtins-utils.h"
9 #include "src/code-factory.h"
10 #include "src/compiler/access-builder.h"
11 #include "src/compiler/allocation-builder.h"
12 #include "src/compiler/js-graph.h"
13 #include "src/compiler/linkage.h"
14 #include "src/compiler/node-matchers.h"
15 #include "src/compiler/node-properties.h"
16 #include "src/compiler/operator-properties.h"
17 #include "src/compiler/type-cache.h"
18 #include "src/compiler/types.h"
19 #include "src/objects-inl.h"
20 #include "src/objects/js-generator.h"
21 #include "src/objects/module-inl.h"
22
23 namespace v8 {
24 namespace internal {
25 namespace compiler {
26
27 // A helper class to simplify the process of reducing a single binop node with a
28 // JSOperator. This class manages the rewriting of context, control, and effect
29 // dependencies during lowering of a binop and contains numerous helper
30 // functions for matching the types of inputs to an operation.
31 class JSBinopReduction final {
32 public:
JSBinopReduction(JSTypedLowering * lowering,Node * node)33 JSBinopReduction(JSTypedLowering* lowering, Node* node)
34 : lowering_(lowering), node_(node) {}
35
GetCompareNumberOperationHint(NumberOperationHint * hint)36 bool GetCompareNumberOperationHint(NumberOperationHint* hint) {
37 DCHECK_EQ(1, node_->op()->EffectOutputCount());
38 switch (CompareOperationHintOf(node_->op())) {
39 case CompareOperationHint::kSignedSmall:
40 *hint = NumberOperationHint::kSignedSmall;
41 return true;
42 case CompareOperationHint::kNumber:
43 *hint = NumberOperationHint::kNumber;
44 return true;
45 case CompareOperationHint::kNumberOrOddball:
46 *hint = NumberOperationHint::kNumberOrOddball;
47 return true;
48 case CompareOperationHint::kAny:
49 case CompareOperationHint::kNone:
50 case CompareOperationHint::kString:
51 case CompareOperationHint::kSymbol:
52 case CompareOperationHint::kBigInt:
53 case CompareOperationHint::kReceiver:
54 case CompareOperationHint::kInternalizedString:
55 break;
56 }
57 return false;
58 }
59
IsInternalizedStringCompareOperation()60 bool IsInternalizedStringCompareOperation() {
61 DCHECK_EQ(1, node_->op()->EffectOutputCount());
62 return (CompareOperationHintOf(node_->op()) ==
63 CompareOperationHint::kInternalizedString) &&
64 BothInputsMaybe(Type::InternalizedString());
65 }
66
IsReceiverCompareOperation()67 bool IsReceiverCompareOperation() {
68 DCHECK_EQ(1, node_->op()->EffectOutputCount());
69 return (CompareOperationHintOf(node_->op()) ==
70 CompareOperationHint::kReceiver) &&
71 BothInputsMaybe(Type::Receiver());
72 }
73
IsStringCompareOperation()74 bool IsStringCompareOperation() {
75 DCHECK_EQ(1, node_->op()->EffectOutputCount());
76 return (CompareOperationHintOf(node_->op()) ==
77 CompareOperationHint::kString) &&
78 BothInputsMaybe(Type::String());
79 }
80
IsSymbolCompareOperation()81 bool IsSymbolCompareOperation() {
82 DCHECK_EQ(1, node_->op()->EffectOutputCount());
83 return (CompareOperationHintOf(node_->op()) ==
84 CompareOperationHint::kSymbol) &&
85 BothInputsMaybe(Type::Symbol());
86 }
87
88 // Check if a string addition will definitely result in creating a ConsString,
89 // i.e. if the combined length of the resulting string exceeds the ConsString
90 // minimum length.
ShouldCreateConsString()91 bool ShouldCreateConsString() {
92 DCHECK_EQ(IrOpcode::kJSAdd, node_->opcode());
93 DCHECK(OneInputIs(Type::String()));
94 if (BothInputsAre(Type::String()) ||
95 BinaryOperationHintOf(node_->op()) == BinaryOperationHint::kString) {
96 HeapObjectBinopMatcher m(node_);
97 JSHeapBroker* broker = lowering_->js_heap_broker();
98 if (m.right().HasValue() && m.right().Ref(broker).IsString()) {
99 StringRef right_string = m.right().Ref(broker).AsString();
100 if (right_string.length() >= ConsString::kMinLength) return true;
101 }
102 if (m.left().HasValue() && m.left().Ref(broker).IsString()) {
103 StringRef left_string = m.left().Ref(broker).AsString();
104 if (left_string.length() >= ConsString::kMinLength) {
105 // The invariant for ConsString requires the left hand side to be
106 // a sequential or external string if the right hand side is the
107 // empty string. Since we don't know anything about the right hand
108 // side here, we must ensure that the left hand side satisfy the
109 // constraints independent of the right hand side.
110 return left_string.IsSeqString() || left_string.IsExternalString();
111 }
112 }
113 }
114 return false;
115 }
116
117 // Inserts a CheckReceiver for the left input.
CheckLeftInputToReceiver()118 void CheckLeftInputToReceiver() {
119 Node* left_input = graph()->NewNode(simplified()->CheckReceiver(), left(),
120 effect(), control());
121 node_->ReplaceInput(0, left_input);
122 update_effect(left_input);
123 }
124
125 // Checks that both inputs are Receiver, and if we don't know
126 // statically that one side is already a Receiver, insert a
127 // CheckReceiver node.
CheckInputsToReceiver()128 void CheckInputsToReceiver() {
129 if (!left_type().Is(Type::Receiver())) {
130 CheckLeftInputToReceiver();
131 }
132 if (!right_type().Is(Type::Receiver())) {
133 Node* right_input = graph()->NewNode(simplified()->CheckReceiver(),
134 right(), effect(), control());
135 node_->ReplaceInput(1, right_input);
136 update_effect(right_input);
137 }
138 }
139
140 // Checks that both inputs are Symbol, and if we don't know
141 // statically that one side is already a Symbol, insert a
142 // CheckSymbol node.
CheckInputsToSymbol()143 void CheckInputsToSymbol() {
144 if (!left_type().Is(Type::Symbol())) {
145 Node* left_input = graph()->NewNode(simplified()->CheckSymbol(), left(),
146 effect(), control());
147 node_->ReplaceInput(0, left_input);
148 update_effect(left_input);
149 }
150 if (!right_type().Is(Type::Symbol())) {
151 Node* right_input = graph()->NewNode(simplified()->CheckSymbol(), right(),
152 effect(), control());
153 node_->ReplaceInput(1, right_input);
154 update_effect(right_input);
155 }
156 }
157
158 // Checks that both inputs are String, and if we don't know
159 // statically that one side is already a String, insert a
160 // CheckString node.
CheckInputsToString()161 void CheckInputsToString() {
162 if (!left_type().Is(Type::String())) {
163 Node* left_input =
164 graph()->NewNode(simplified()->CheckString(VectorSlotPair()), left(),
165 effect(), control());
166 node_->ReplaceInput(0, left_input);
167 update_effect(left_input);
168 }
169 if (!right_type().Is(Type::String())) {
170 Node* right_input =
171 graph()->NewNode(simplified()->CheckString(VectorSlotPair()), right(),
172 effect(), control());
173 node_->ReplaceInput(1, right_input);
174 update_effect(right_input);
175 }
176 }
177
178 // Checks that both inputs are InternalizedString, and if we don't know
179 // statically that one side is already an InternalizedString, insert a
180 // CheckInternalizedString node.
CheckInputsToInternalizedString()181 void CheckInputsToInternalizedString() {
182 if (!left_type().Is(Type::UniqueName())) {
183 Node* left_input = graph()->NewNode(
184 simplified()->CheckInternalizedString(), left(), effect(), control());
185 node_->ReplaceInput(0, left_input);
186 update_effect(left_input);
187 }
188 if (!right_type().Is(Type::UniqueName())) {
189 Node* right_input =
190 graph()->NewNode(simplified()->CheckInternalizedString(), right(),
191 effect(), control());
192 node_->ReplaceInput(1, right_input);
193 update_effect(right_input);
194 }
195 }
196
ConvertInputsToNumber()197 void ConvertInputsToNumber() {
198 DCHECK(left_type().Is(Type::PlainPrimitive()));
199 DCHECK(right_type().Is(Type::PlainPrimitive()));
200 node_->ReplaceInput(0, ConvertPlainPrimitiveToNumber(left()));
201 node_->ReplaceInput(1, ConvertPlainPrimitiveToNumber(right()));
202 }
203
ConvertInputsToUI32(Signedness left_signedness,Signedness right_signedness)204 void ConvertInputsToUI32(Signedness left_signedness,
205 Signedness right_signedness) {
206 node_->ReplaceInput(0, ConvertToUI32(left(), left_signedness));
207 node_->ReplaceInput(1, ConvertToUI32(right(), right_signedness));
208 }
209
SwapInputs()210 void SwapInputs() {
211 Node* l = left();
212 Node* r = right();
213 node_->ReplaceInput(0, r);
214 node_->ReplaceInput(1, l);
215 }
216
217 // Remove all effect and control inputs and outputs to this node and change
218 // to the pure operator {op}.
ChangeToPureOperator(const Operator * op,Type type=Type::Any ())219 Reduction ChangeToPureOperator(const Operator* op, Type type = Type::Any()) {
220 DCHECK_EQ(0, op->EffectInputCount());
221 DCHECK_EQ(false, OperatorProperties::HasContextInput(op));
222 DCHECK_EQ(0, op->ControlInputCount());
223 DCHECK_EQ(2, op->ValueInputCount());
224
225 // Remove the effects from the node, and update its effect/control usages.
226 if (node_->op()->EffectInputCount() > 0) {
227 lowering_->RelaxEffectsAndControls(node_);
228 }
229 // Remove the inputs corresponding to context, effect, and control.
230 NodeProperties::RemoveNonValueInputs(node_);
231 // Finally, update the operator to the new one.
232 NodeProperties::ChangeOp(node_, op);
233
234 // TODO(jarin): Replace the explicit typing hack with a call to some method
235 // that encapsulates changing the operator and re-typing.
236 Type node_type = NodeProperties::GetType(node_);
237 NodeProperties::SetType(node_, Type::Intersect(node_type, type, zone()));
238
239 return lowering_->Changed(node_);
240 }
241
ChangeToSpeculativeOperator(const Operator * op,Type upper_bound)242 Reduction ChangeToSpeculativeOperator(const Operator* op, Type upper_bound) {
243 DCHECK_EQ(1, op->EffectInputCount());
244 DCHECK_EQ(1, op->EffectOutputCount());
245 DCHECK_EQ(false, OperatorProperties::HasContextInput(op));
246 DCHECK_EQ(1, op->ControlInputCount());
247 DCHECK_EQ(0, op->ControlOutputCount());
248 DCHECK_EQ(0, OperatorProperties::GetFrameStateInputCount(op));
249 DCHECK_EQ(2, op->ValueInputCount());
250
251 DCHECK_EQ(1, node_->op()->EffectInputCount());
252 DCHECK_EQ(1, node_->op()->EffectOutputCount());
253 DCHECK_EQ(1, node_->op()->ControlInputCount());
254 DCHECK_EQ(2, node_->op()->ValueInputCount());
255
256 // Reconnect the control output to bypass the IfSuccess node and
257 // possibly disconnect from the IfException node.
258 lowering_->RelaxControls(node_);
259
260 // Remove the frame state and the context.
261 if (OperatorProperties::HasFrameStateInput(node_->op())) {
262 node_->RemoveInput(NodeProperties::FirstFrameStateIndex(node_));
263 }
264 node_->RemoveInput(NodeProperties::FirstContextIndex(node_));
265
266 NodeProperties::ChangeOp(node_, op);
267
268 // Update the type to number.
269 Type node_type = NodeProperties::GetType(node_);
270 NodeProperties::SetType(node_,
271 Type::Intersect(node_type, upper_bound, zone()));
272
273 return lowering_->Changed(node_);
274 }
275
NumberOp()276 const Operator* NumberOp() {
277 switch (node_->opcode()) {
278 case IrOpcode::kJSAdd:
279 return simplified()->NumberAdd();
280 case IrOpcode::kJSSubtract:
281 return simplified()->NumberSubtract();
282 case IrOpcode::kJSMultiply:
283 return simplified()->NumberMultiply();
284 case IrOpcode::kJSDivide:
285 return simplified()->NumberDivide();
286 case IrOpcode::kJSModulus:
287 return simplified()->NumberModulus();
288 case IrOpcode::kJSExponentiate:
289 return simplified()->NumberPow();
290 case IrOpcode::kJSBitwiseAnd:
291 return simplified()->NumberBitwiseAnd();
292 case IrOpcode::kJSBitwiseOr:
293 return simplified()->NumberBitwiseOr();
294 case IrOpcode::kJSBitwiseXor:
295 return simplified()->NumberBitwiseXor();
296 case IrOpcode::kJSShiftLeft:
297 return simplified()->NumberShiftLeft();
298 case IrOpcode::kJSShiftRight:
299 return simplified()->NumberShiftRight();
300 case IrOpcode::kJSShiftRightLogical:
301 return simplified()->NumberShiftRightLogical();
302 default:
303 break;
304 }
305 UNREACHABLE();
306 }
307
NumberOpFromSpeculativeNumberOp()308 const Operator* NumberOpFromSpeculativeNumberOp() {
309 switch (node_->opcode()) {
310 case IrOpcode::kSpeculativeNumberEqual:
311 return simplified()->NumberEqual();
312 case IrOpcode::kSpeculativeNumberLessThan:
313 return simplified()->NumberLessThan();
314 case IrOpcode::kSpeculativeNumberLessThanOrEqual:
315 return simplified()->NumberLessThanOrEqual();
316 case IrOpcode::kSpeculativeNumberAdd:
317 // Handled by ReduceSpeculativeNumberAdd.
318 UNREACHABLE();
319 case IrOpcode::kSpeculativeNumberSubtract:
320 return simplified()->NumberSubtract();
321 case IrOpcode::kSpeculativeNumberMultiply:
322 return simplified()->NumberMultiply();
323 case IrOpcode::kSpeculativeNumberDivide:
324 return simplified()->NumberDivide();
325 case IrOpcode::kSpeculativeNumberModulus:
326 return simplified()->NumberModulus();
327 default:
328 break;
329 }
330 UNREACHABLE();
331 }
332
LeftInputIs(Type t)333 bool LeftInputIs(Type t) { return left_type().Is(t); }
334
RightInputIs(Type t)335 bool RightInputIs(Type t) { return right_type().Is(t); }
336
OneInputIs(Type t)337 bool OneInputIs(Type t) { return LeftInputIs(t) || RightInputIs(t); }
338
BothInputsAre(Type t)339 bool BothInputsAre(Type t) { return LeftInputIs(t) && RightInputIs(t); }
340
BothInputsMaybe(Type t)341 bool BothInputsMaybe(Type t) {
342 return left_type().Maybe(t) && right_type().Maybe(t);
343 }
344
OneInputCannotBe(Type t)345 bool OneInputCannotBe(Type t) {
346 return !left_type().Maybe(t) || !right_type().Maybe(t);
347 }
348
NeitherInputCanBe(Type t)349 bool NeitherInputCanBe(Type t) {
350 return !left_type().Maybe(t) && !right_type().Maybe(t);
351 }
352
effect()353 Node* effect() { return NodeProperties::GetEffectInput(node_); }
control()354 Node* control() { return NodeProperties::GetControlInput(node_); }
context()355 Node* context() { return NodeProperties::GetContextInput(node_); }
left()356 Node* left() { return NodeProperties::GetValueInput(node_, 0); }
right()357 Node* right() { return NodeProperties::GetValueInput(node_, 1); }
left_type()358 Type left_type() { return NodeProperties::GetType(node_->InputAt(0)); }
right_type()359 Type right_type() { return NodeProperties::GetType(node_->InputAt(1)); }
type()360 Type type() { return NodeProperties::GetType(node_); }
361
simplified()362 SimplifiedOperatorBuilder* simplified() { return lowering_->simplified(); }
graph() const363 Graph* graph() const { return lowering_->graph(); }
jsgraph()364 JSGraph* jsgraph() { return lowering_->jsgraph(); }
isolate()365 Isolate* isolate() { return jsgraph()->isolate(); }
javascript()366 JSOperatorBuilder* javascript() { return lowering_->javascript(); }
common()367 CommonOperatorBuilder* common() { return jsgraph()->common(); }
zone() const368 Zone* zone() const { return graph()->zone(); }
369
370 private:
371 JSTypedLowering* lowering_; // The containing lowering instance.
372 Node* node_; // The original node.
373
ConvertPlainPrimitiveToNumber(Node * node)374 Node* ConvertPlainPrimitiveToNumber(Node* node) {
375 DCHECK(NodeProperties::GetType(node).Is(Type::PlainPrimitive()));
376 // Avoid inserting too many eager ToNumber() operations.
377 Reduction const reduction = lowering_->ReduceJSToNumberOrNumericInput(node);
378 if (reduction.Changed()) return reduction.replacement();
379 if (NodeProperties::GetType(node).Is(Type::Number())) {
380 return node;
381 }
382 return graph()->NewNode(simplified()->PlainPrimitiveToNumber(), node);
383 }
384
ConvertToUI32(Node * node,Signedness signedness)385 Node* ConvertToUI32(Node* node, Signedness signedness) {
386 // Avoid introducing too many eager NumberToXXnt32() operations.
387 Type type = NodeProperties::GetType(node);
388 if (signedness == kSigned) {
389 if (!type.Is(Type::Signed32())) {
390 node = graph()->NewNode(simplified()->NumberToInt32(), node);
391 }
392 } else {
393 DCHECK_EQ(kUnsigned, signedness);
394 if (!type.Is(Type::Unsigned32())) {
395 node = graph()->NewNode(simplified()->NumberToUint32(), node);
396 }
397 }
398 return node;
399 }
400
update_effect(Node * effect)401 void update_effect(Node* effect) {
402 NodeProperties::ReplaceEffectInput(node_, effect);
403 }
404 };
405
406
407 // TODO(turbofan): js-typed-lowering improvements possible
408 // - immediately put in type bounds for all new nodes
409 // - relax effects from generic but not-side-effecting operations
410
JSTypedLowering(Editor * editor,JSGraph * jsgraph,JSHeapBroker * js_heap_broker,Zone * zone)411 JSTypedLowering::JSTypedLowering(Editor* editor, JSGraph* jsgraph,
412 JSHeapBroker* js_heap_broker, Zone* zone)
413 : AdvancedReducer(editor),
414 jsgraph_(jsgraph),
415 js_heap_broker_(js_heap_broker),
416 empty_string_type_(Type::HeapConstant(
417 js_heap_broker, factory()->empty_string(), graph()->zone())),
418 pointer_comparable_type_(
419 Type::Union(Type::Oddball(),
420 Type::Union(Type::SymbolOrReceiver(), empty_string_type_,
421 graph()->zone()),
422 graph()->zone())),
423 type_cache_(TypeCache::Get()) {}
424
ReduceSpeculativeNumberAdd(Node * node)425 Reduction JSTypedLowering::ReduceSpeculativeNumberAdd(Node* node) {
426 JSBinopReduction r(this, node);
427 NumberOperationHint hint = NumberOperationHintOf(node->op());
428 if ((hint == NumberOperationHint::kNumber ||
429 hint == NumberOperationHint::kNumberOrOddball) &&
430 r.BothInputsAre(Type::PlainPrimitive()) &&
431 r.NeitherInputCanBe(Type::StringOrReceiver())) {
432 // SpeculativeNumberAdd(x:-string, y:-string) =>
433 // NumberAdd(ToNumber(x), ToNumber(y))
434 r.ConvertInputsToNumber();
435 return r.ChangeToPureOperator(simplified()->NumberAdd(), Type::Number());
436 }
437 return NoChange();
438 }
439
ReduceJSBitwiseNot(Node * node)440 Reduction JSTypedLowering::ReduceJSBitwiseNot(Node* node) {
441 Node* input = NodeProperties::GetValueInput(node, 0);
442 Type input_type = NodeProperties::GetType(input);
443 if (input_type.Is(Type::PlainPrimitive())) {
444 // JSBitwiseNot(x) => NumberBitwiseXor(ToInt32(x), -1)
445 node->InsertInput(graph()->zone(), 1, jsgraph()->SmiConstant(-1));
446 NodeProperties::ChangeOp(node, javascript()->BitwiseXor());
447 JSBinopReduction r(this, node);
448 r.ConvertInputsToNumber();
449 r.ConvertInputsToUI32(kSigned, kSigned);
450 return r.ChangeToPureOperator(r.NumberOp(), Type::Signed32());
451 }
452 return NoChange();
453 }
454
ReduceJSDecrement(Node * node)455 Reduction JSTypedLowering::ReduceJSDecrement(Node* node) {
456 Node* input = NodeProperties::GetValueInput(node, 0);
457 Type input_type = NodeProperties::GetType(input);
458 if (input_type.Is(Type::PlainPrimitive())) {
459 // JSDecrement(x) => NumberSubtract(ToNumber(x), 1)
460 node->InsertInput(graph()->zone(), 1, jsgraph()->OneConstant());
461 NodeProperties::ChangeOp(node, javascript()->Subtract());
462 JSBinopReduction r(this, node);
463 r.ConvertInputsToNumber();
464 DCHECK_EQ(simplified()->NumberSubtract(), r.NumberOp());
465 return r.ChangeToPureOperator(r.NumberOp(), Type::Number());
466 }
467 return NoChange();
468 }
469
ReduceJSIncrement(Node * node)470 Reduction JSTypedLowering::ReduceJSIncrement(Node* node) {
471 Node* input = NodeProperties::GetValueInput(node, 0);
472 Type input_type = NodeProperties::GetType(input);
473 if (input_type.Is(Type::PlainPrimitive())) {
474 // JSIncrement(x) => NumberAdd(ToNumber(x), 1)
475 node->InsertInput(graph()->zone(), 1, jsgraph()->OneConstant());
476 BinaryOperationHint hint = BinaryOperationHint::kAny; // Dummy.
477 NodeProperties::ChangeOp(node, javascript()->Add(hint));
478 JSBinopReduction r(this, node);
479 r.ConvertInputsToNumber();
480 DCHECK_EQ(simplified()->NumberAdd(), r.NumberOp());
481 return r.ChangeToPureOperator(r.NumberOp(), Type::Number());
482 }
483 return NoChange();
484 }
485
ReduceJSNegate(Node * node)486 Reduction JSTypedLowering::ReduceJSNegate(Node* node) {
487 Node* input = NodeProperties::GetValueInput(node, 0);
488 Type input_type = NodeProperties::GetType(input);
489 if (input_type.Is(Type::PlainPrimitive())) {
490 // JSNegate(x) => NumberMultiply(ToNumber(x), -1)
491 node->InsertInput(graph()->zone(), 1, jsgraph()->SmiConstant(-1));
492 NodeProperties::ChangeOp(node, javascript()->Multiply());
493 JSBinopReduction r(this, node);
494 r.ConvertInputsToNumber();
495 return r.ChangeToPureOperator(r.NumberOp(), Type::Number());
496 }
497 return NoChange();
498 }
499
ReduceJSAdd(Node * node)500 Reduction JSTypedLowering::ReduceJSAdd(Node* node) {
501 JSBinopReduction r(this, node);
502 if (r.BothInputsAre(Type::Number())) {
503 // JSAdd(x:number, y:number) => NumberAdd(x, y)
504 return r.ChangeToPureOperator(simplified()->NumberAdd(), Type::Number());
505 }
506 if (r.BothInputsAre(Type::PlainPrimitive()) &&
507 r.NeitherInputCanBe(Type::StringOrReceiver())) {
508 // JSAdd(x:-string, y:-string) => NumberAdd(ToNumber(x), ToNumber(y))
509 r.ConvertInputsToNumber();
510 return r.ChangeToPureOperator(simplified()->NumberAdd(), Type::Number());
511 }
512 if (BinaryOperationHintOf(node->op()) == BinaryOperationHint::kString) {
513 // Always bake in String feedback into the graph.
514 // TODO(bmeurer): Consider adding a SpeculativeStringAdd operator,
515 // and use that in JSTypeHintLowering instead of looking at the
516 // binary operation feedback here.
517 r.CheckInputsToString();
518 }
519 if (r.OneInputIs(Type::String())) {
520 // We know that (at least) one input is already a String,
521 // so try to strength-reduce the non-String input.
522 if (r.LeftInputIs(Type::String())) {
523 Reduction const reduction = ReduceJSToStringInput(r.right());
524 if (reduction.Changed()) {
525 NodeProperties::ReplaceValueInput(node, reduction.replacement(), 1);
526 }
527 } else if (r.RightInputIs(Type::String())) {
528 Reduction const reduction = ReduceJSToStringInput(r.left());
529 if (reduction.Changed()) {
530 NodeProperties::ReplaceValueInput(node, reduction.replacement(), 0);
531 }
532 }
533 // We might be able to constant-fold the String concatenation now.
534 if (r.BothInputsAre(Type::String())) {
535 HeapObjectBinopMatcher m(node);
536 if (m.IsFoldable()) {
537 StringRef left = m.left().Ref(js_heap_broker()).AsString();
538 StringRef right = m.right().Ref(js_heap_broker()).AsString();
539 if (left.length() + right.length() > String::kMaxLength) {
540 // No point in trying to optimize this, as it will just throw.
541 return NoChange();
542 }
543 // TODO(mslekova): get rid of these allows by doing either one of:
544 // 1. remove the optimization and check if it ruins the performance
545 // 2. leave a placeholder and do the actual allocations once back on the
546 // MT
547 AllowHandleDereference allow_handle_dereference;
548 AllowHandleAllocation allow_handle_allocation;
549 AllowHeapAllocation allow_heap_allocation;
550 ObjectRef cons(
551 js_heap_broker(),
552 factory()
553 ->NewConsString(left.object<String>(), right.object<String>())
554 .ToHandleChecked());
555 Node* value = jsgraph()->Constant(cons);
556 ReplaceWithValue(node, value);
557 return Replace(value);
558 }
559 }
560 // We might know for sure that we're creating a ConsString here.
561 if (r.ShouldCreateConsString()) {
562 return ReduceCreateConsString(node);
563 }
564 // Eliminate useless concatenation of empty string.
565 if (r.BothInputsAre(Type::String())) {
566 Node* effect = NodeProperties::GetEffectInput(node);
567 Node* control = NodeProperties::GetControlInput(node);
568 if (r.LeftInputIs(empty_string_type_)) {
569 Node* value = effect =
570 graph()->NewNode(simplified()->CheckString(VectorSlotPair()),
571 r.right(), effect, control);
572 ReplaceWithValue(node, value, effect, control);
573 return Replace(value);
574 } else if (r.RightInputIs(empty_string_type_)) {
575 Node* value = effect =
576 graph()->NewNode(simplified()->CheckString(VectorSlotPair()),
577 r.left(), effect, control);
578 ReplaceWithValue(node, value, effect, control);
579 return Replace(value);
580 }
581 }
582 StringAddFlags flags = STRING_ADD_CHECK_NONE;
583 if (!r.LeftInputIs(Type::String())) {
584 flags = STRING_ADD_CONVERT_LEFT;
585 } else if (!r.RightInputIs(Type::String())) {
586 flags = STRING_ADD_CONVERT_RIGHT;
587 }
588 Operator::Properties properties = node->op()->properties();
589 if (r.NeitherInputCanBe(Type::Receiver())) {
590 // Both sides are already strings, so we know that the
591 // string addition will not cause any observable side
592 // effects; it can still throw obviously.
593 properties = Operator::kNoWrite | Operator::kNoDeopt;
594 }
595 // JSAdd(x:string, y) => CallStub[StringAdd](x, y)
596 // JSAdd(x, y:string) => CallStub[StringAdd](x, y)
597 Callable const callable =
598 CodeFactory::StringAdd(isolate(), flags, NOT_TENURED);
599 auto call_descriptor = Linkage::GetStubCallDescriptor(
600 graph()->zone(), callable.descriptor(), 0,
601 CallDescriptor::kNeedsFrameState, properties);
602 DCHECK_EQ(1, OperatorProperties::GetFrameStateInputCount(node->op()));
603 node->InsertInput(graph()->zone(), 0,
604 jsgraph()->HeapConstant(callable.code()));
605 NodeProperties::ChangeOp(node, common()->Call(call_descriptor));
606 return Changed(node);
607 }
608 // We never get here when we had String feedback.
609 DCHECK_NE(BinaryOperationHint::kString, BinaryOperationHintOf(node->op()));
610 return NoChange();
611 }
612
ReduceNumberBinop(Node * node)613 Reduction JSTypedLowering::ReduceNumberBinop(Node* node) {
614 JSBinopReduction r(this, node);
615 if (r.BothInputsAre(Type::PlainPrimitive())) {
616 r.ConvertInputsToNumber();
617 return r.ChangeToPureOperator(r.NumberOp(), Type::Number());
618 }
619 return NoChange();
620 }
621
ReduceSpeculativeNumberBinop(Node * node)622 Reduction JSTypedLowering::ReduceSpeculativeNumberBinop(Node* node) {
623 JSBinopReduction r(this, node);
624 NumberOperationHint hint = NumberOperationHintOf(node->op());
625 if ((hint == NumberOperationHint::kNumber ||
626 hint == NumberOperationHint::kNumberOrOddball) &&
627 r.BothInputsAre(Type::NumberOrUndefinedOrNullOrBoolean())) {
628 // We intentionally do this only in the Number and NumberOrOddball hint case
629 // because simplified lowering of these speculative ops may do some clever
630 // reductions in the other cases.
631 r.ConvertInputsToNumber();
632 return r.ChangeToPureOperator(r.NumberOpFromSpeculativeNumberOp(),
633 Type::Number());
634 }
635 return NoChange();
636 }
637
ReduceInt32Binop(Node * node)638 Reduction JSTypedLowering::ReduceInt32Binop(Node* node) {
639 JSBinopReduction r(this, node);
640 if (r.BothInputsAre(Type::PlainPrimitive())) {
641 r.ConvertInputsToNumber();
642 r.ConvertInputsToUI32(kSigned, kSigned);
643 return r.ChangeToPureOperator(r.NumberOp(), Type::Signed32());
644 }
645 return NoChange();
646 }
647
ReduceUI32Shift(Node * node,Signedness signedness)648 Reduction JSTypedLowering::ReduceUI32Shift(Node* node, Signedness signedness) {
649 JSBinopReduction r(this, node);
650 if (r.BothInputsAre(Type::PlainPrimitive())) {
651 r.ConvertInputsToNumber();
652 r.ConvertInputsToUI32(signedness, kUnsigned);
653 return r.ChangeToPureOperator(r.NumberOp(), signedness == kUnsigned
654 ? Type::Unsigned32()
655 : Type::Signed32());
656 }
657 return NoChange();
658 }
659
ReduceCreateConsString(Node * node)660 Reduction JSTypedLowering::ReduceCreateConsString(Node* node) {
661 Node* first = NodeProperties::GetValueInput(node, 0);
662 Node* second = NodeProperties::GetValueInput(node, 1);
663 Node* context = NodeProperties::GetContextInput(node);
664 Node* frame_state = NodeProperties::GetFrameStateInput(node);
665 Node* effect = NodeProperties::GetEffectInput(node);
666 Node* control = NodeProperties::GetControlInput(node);
667
668 // Make sure {first} is actually a String.
669 Type first_type = NodeProperties::GetType(first);
670 if (!first_type.Is(Type::String())) {
671 first = effect = graph()->NewNode(
672 simplified()->CheckString(VectorSlotPair()), first, effect, control);
673 first_type = NodeProperties::GetType(first);
674 }
675
676 // Make sure {second} is actually a String.
677 Type second_type = NodeProperties::GetType(second);
678 if (!second_type.Is(Type::String())) {
679 second = effect = graph()->NewNode(
680 simplified()->CheckString(VectorSlotPair()), second, effect, control);
681 second_type = NodeProperties::GetType(second);
682 }
683
684 // Determine the {first} length.
685 Node* first_length = BuildGetStringLength(first);
686 Node* second_length = BuildGetStringLength(second);
687
688 // Compute the resulting length.
689 Node* length =
690 graph()->NewNode(simplified()->NumberAdd(), first_length, second_length);
691
692 if (isolate()->IsStringLengthOverflowIntact()) {
693 // We can just deoptimize if the {length} is out-of-bounds. Besides
694 // generating a shorter code sequence than the version below, this
695 // has the additional benefit of not holding on to the lazy {frame_state}
696 // and thus potentially reduces the number of live ranges and allows for
697 // more truncations.
698 length = effect = graph()->NewNode(
699 simplified()->CheckBounds(VectorSlotPair()), length,
700 jsgraph()->Constant(String::kMaxLength), effect, control);
701 } else {
702 // Check if we would overflow the allowed maximum string length.
703 Node* check =
704 graph()->NewNode(simplified()->NumberLessThanOrEqual(), length,
705 jsgraph()->Constant(String::kMaxLength));
706 Node* branch =
707 graph()->NewNode(common()->Branch(BranchHint::kTrue), check, control);
708 Node* if_false = graph()->NewNode(common()->IfFalse(), branch);
709 Node* efalse = effect;
710 {
711 // Throw a RangeError in case of overflow.
712 Node* vfalse = efalse = if_false = graph()->NewNode(
713 javascript()->CallRuntime(Runtime::kThrowInvalidStringLength),
714 context, frame_state, efalse, if_false);
715
716 // Update potential {IfException} uses of {node} to point to the
717 // %ThrowInvalidStringLength runtime call node instead.
718 Node* on_exception = nullptr;
719 if (NodeProperties::IsExceptionalCall(node, &on_exception)) {
720 NodeProperties::ReplaceControlInput(on_exception, vfalse);
721 NodeProperties::ReplaceEffectInput(on_exception, efalse);
722 if_false = graph()->NewNode(common()->IfSuccess(), vfalse);
723 Revisit(on_exception);
724 }
725
726 // The above %ThrowInvalidStringLength runtime call is an unconditional
727 // throw, making it impossible to return a successful completion in this
728 // case. We simply connect the successful completion to the graph end.
729 if_false = graph()->NewNode(common()->Throw(), efalse, if_false);
730 // TODO(bmeurer): This should be on the AdvancedReducer somehow.
731 NodeProperties::MergeControlToEnd(graph(), common(), if_false);
732 Revisit(graph()->end());
733 }
734 control = graph()->NewNode(common()->IfTrue(), branch);
735 length = effect =
736 graph()->NewNode(common()->TypeGuard(type_cache_.kStringLengthType),
737 length, effect, control);
738 }
739
740 Node* value =
741 graph()->NewNode(simplified()->NewConsString(), length, first, second);
742 ReplaceWithValue(node, value, effect, control);
743 return Replace(value);
744 }
745
BuildGetStringLength(Node * value)746 Node* JSTypedLowering::BuildGetStringLength(Node* value) {
747 // TODO(bmeurer): Get rid of this hack and instead have a way to
748 // express the string length in the types.
749 HeapObjectMatcher m(value);
750 if (!m.HasValue() || !m.Ref(js_heap_broker()).IsString()) {
751 return graph()->NewNode(simplified()->StringLength(), value);
752 }
753
754 return jsgraph()->Constant(m.Ref(js_heap_broker()).AsString().length());
755 }
756
ReduceSpeculativeNumberComparison(Node * node)757 Reduction JSTypedLowering::ReduceSpeculativeNumberComparison(Node* node) {
758 JSBinopReduction r(this, node);
759 if (r.BothInputsAre(Type::Signed32()) ||
760 r.BothInputsAre(Type::Unsigned32())) {
761 return r.ChangeToPureOperator(r.NumberOpFromSpeculativeNumberOp());
762 }
763 return NoChange();
764 }
765
ReduceJSComparison(Node * node)766 Reduction JSTypedLowering::ReduceJSComparison(Node* node) {
767 JSBinopReduction r(this, node);
768 if (r.BothInputsAre(Type::String())) {
769 // If both inputs are definitely strings, perform a string comparison.
770 const Operator* stringOp;
771 switch (node->opcode()) {
772 case IrOpcode::kJSLessThan:
773 stringOp = simplified()->StringLessThan();
774 break;
775 case IrOpcode::kJSGreaterThan:
776 stringOp = simplified()->StringLessThan();
777 r.SwapInputs(); // a > b => b < a
778 break;
779 case IrOpcode::kJSLessThanOrEqual:
780 stringOp = simplified()->StringLessThanOrEqual();
781 break;
782 case IrOpcode::kJSGreaterThanOrEqual:
783 stringOp = simplified()->StringLessThanOrEqual();
784 r.SwapInputs(); // a >= b => b <= a
785 break;
786 default:
787 return NoChange();
788 }
789 r.ChangeToPureOperator(stringOp);
790 return Changed(node);
791 }
792
793 const Operator* less_than;
794 const Operator* less_than_or_equal;
795 if (r.BothInputsAre(Type::Signed32()) ||
796 r.BothInputsAre(Type::Unsigned32())) {
797 less_than = simplified()->NumberLessThan();
798 less_than_or_equal = simplified()->NumberLessThanOrEqual();
799 } else if (r.OneInputCannotBe(Type::StringOrReceiver()) &&
800 r.BothInputsAre(Type::PlainPrimitive())) {
801 r.ConvertInputsToNumber();
802 less_than = simplified()->NumberLessThan();
803 less_than_or_equal = simplified()->NumberLessThanOrEqual();
804 } else if (r.IsStringCompareOperation()) {
805 r.CheckInputsToString();
806 less_than = simplified()->StringLessThan();
807 less_than_or_equal = simplified()->StringLessThanOrEqual();
808 } else {
809 return NoChange();
810 }
811 const Operator* comparison;
812 switch (node->opcode()) {
813 case IrOpcode::kJSLessThan:
814 comparison = less_than;
815 break;
816 case IrOpcode::kJSGreaterThan:
817 comparison = less_than;
818 r.SwapInputs(); // a > b => b < a
819 break;
820 case IrOpcode::kJSLessThanOrEqual:
821 comparison = less_than_or_equal;
822 break;
823 case IrOpcode::kJSGreaterThanOrEqual:
824 comparison = less_than_or_equal;
825 r.SwapInputs(); // a >= b => b <= a
826 break;
827 default:
828 return NoChange();
829 }
830 return r.ChangeToPureOperator(comparison);
831 }
832
ReduceJSEqual(Node * node)833 Reduction JSTypedLowering::ReduceJSEqual(Node* node) {
834 JSBinopReduction r(this, node);
835
836 if (r.BothInputsAre(Type::UniqueName())) {
837 return r.ChangeToPureOperator(simplified()->ReferenceEqual());
838 }
839 if (r.IsInternalizedStringCompareOperation()) {
840 r.CheckInputsToInternalizedString();
841 return r.ChangeToPureOperator(simplified()->ReferenceEqual());
842 }
843 if (r.BothInputsAre(Type::String())) {
844 return r.ChangeToPureOperator(simplified()->StringEqual());
845 }
846 if (r.BothInputsAre(Type::Boolean())) {
847 return r.ChangeToPureOperator(simplified()->ReferenceEqual());
848 }
849 if (r.BothInputsAre(Type::Receiver())) {
850 return r.ChangeToPureOperator(simplified()->ReferenceEqual());
851 }
852 if (r.OneInputIs(Type::Undetectable())) {
853 RelaxEffectsAndControls(node);
854 node->RemoveInput(r.LeftInputIs(Type::Undetectable()) ? 0 : 1);
855 node->TrimInputCount(1);
856 NodeProperties::ChangeOp(node, simplified()->ObjectIsUndetectable());
857 return Changed(node);
858 }
859
860 if (r.BothInputsAre(Type::Signed32()) ||
861 r.BothInputsAre(Type::Unsigned32())) {
862 return r.ChangeToPureOperator(simplified()->NumberEqual());
863 } else if (r.BothInputsAre(Type::Number())) {
864 return r.ChangeToPureOperator(simplified()->NumberEqual());
865 } else if (r.IsReceiverCompareOperation()) {
866 r.CheckInputsToReceiver();
867 return r.ChangeToPureOperator(simplified()->ReferenceEqual());
868 } else if (r.IsStringCompareOperation()) {
869 r.CheckInputsToString();
870 return r.ChangeToPureOperator(simplified()->StringEqual());
871 } else if (r.IsSymbolCompareOperation()) {
872 r.CheckInputsToSymbol();
873 return r.ChangeToPureOperator(simplified()->ReferenceEqual());
874 }
875 return NoChange();
876 }
877
ReduceJSStrictEqual(Node * node)878 Reduction JSTypedLowering::ReduceJSStrictEqual(Node* node) {
879 JSBinopReduction r(this, node);
880 if (r.left() == r.right()) {
881 // x === x is always true if x != NaN
882 Node* replacement = graph()->NewNode(
883 simplified()->BooleanNot(),
884 graph()->NewNode(simplified()->ObjectIsNaN(), r.left()));
885 ReplaceWithValue(node, replacement);
886 return Replace(replacement);
887 }
888 if (r.OneInputCannotBe(Type::NumericOrString())) {
889 // For values with canonical representation (i.e. neither String nor
890 // Numeric) an empty type intersection means the values cannot be strictly
891 // equal.
892 if (!r.left_type().Maybe(r.right_type())) {
893 Node* replacement = jsgraph()->FalseConstant();
894 ReplaceWithValue(node, replacement);
895 return Replace(replacement);
896 }
897 }
898
899 if (r.BothInputsAre(Type::Unique())) {
900 return r.ChangeToPureOperator(simplified()->ReferenceEqual());
901 }
902 if (r.OneInputIs(pointer_comparable_type_)) {
903 return r.ChangeToPureOperator(simplified()->ReferenceEqual());
904 }
905 if (r.IsInternalizedStringCompareOperation()) {
906 r.CheckInputsToInternalizedString();
907 return r.ChangeToPureOperator(simplified()->ReferenceEqual());
908 }
909 if (r.BothInputsAre(Type::String())) {
910 return r.ChangeToPureOperator(simplified()->StringEqual());
911 }
912
913 NumberOperationHint hint;
914 if (r.BothInputsAre(Type::Signed32()) ||
915 r.BothInputsAre(Type::Unsigned32())) {
916 return r.ChangeToPureOperator(simplified()->NumberEqual());
917 } else if (r.GetCompareNumberOperationHint(&hint)) {
918 return r.ChangeToSpeculativeOperator(
919 simplified()->SpeculativeNumberEqual(hint), Type::Boolean());
920 } else if (r.BothInputsAre(Type::Number())) {
921 return r.ChangeToPureOperator(simplified()->NumberEqual());
922 } else if (r.IsReceiverCompareOperation()) {
923 // For strict equality, it's enough to know that one input is a Receiver,
924 // as a strict equality comparison with a Receiver can only yield true if
925 // both sides refer to the same Receiver than.
926 r.CheckLeftInputToReceiver();
927 return r.ChangeToPureOperator(simplified()->ReferenceEqual());
928 } else if (r.IsStringCompareOperation()) {
929 r.CheckInputsToString();
930 return r.ChangeToPureOperator(simplified()->StringEqual());
931 } else if (r.IsSymbolCompareOperation()) {
932 r.CheckInputsToSymbol();
933 return r.ChangeToPureOperator(simplified()->ReferenceEqual());
934 }
935 return NoChange();
936 }
937
ReduceJSToInteger(Node * node)938 Reduction JSTypedLowering::ReduceJSToInteger(Node* node) {
939 Node* const input = NodeProperties::GetValueInput(node, 0);
940 Type const input_type = NodeProperties::GetType(input);
941 if (input_type.Is(type_cache_.kIntegerOrMinusZero)) {
942 // JSToInteger(x:integer) => x
943 ReplaceWithValue(node, input);
944 return Replace(input);
945 }
946 return NoChange();
947 }
948
ReduceJSToName(Node * node)949 Reduction JSTypedLowering::ReduceJSToName(Node* node) {
950 Node* const input = NodeProperties::GetValueInput(node, 0);
951 Type const input_type = NodeProperties::GetType(input);
952 if (input_type.Is(Type::Name())) {
953 // JSToName(x:name) => x
954 ReplaceWithValue(node, input);
955 return Replace(input);
956 }
957 return NoChange();
958 }
959
ReduceJSToLength(Node * node)960 Reduction JSTypedLowering::ReduceJSToLength(Node* node) {
961 Node* input = NodeProperties::GetValueInput(node, 0);
962 Type input_type = NodeProperties::GetType(input);
963 if (input_type.Is(type_cache_.kIntegerOrMinusZero)) {
964 if (input_type.IsNone() || input_type.Max() <= 0.0) {
965 input = jsgraph()->ZeroConstant();
966 } else if (input_type.Min() >= kMaxSafeInteger) {
967 input = jsgraph()->Constant(kMaxSafeInteger);
968 } else {
969 if (input_type.Min() <= 0.0) {
970 input = graph()->NewNode(simplified()->NumberMax(),
971 jsgraph()->ZeroConstant(), input);
972 }
973 if (input_type.Max() > kMaxSafeInteger) {
974 input = graph()->NewNode(simplified()->NumberMin(),
975 jsgraph()->Constant(kMaxSafeInteger), input);
976 }
977 }
978 ReplaceWithValue(node, input);
979 return Replace(input);
980 }
981 return NoChange();
982 }
983
ReduceJSToNumberOrNumericInput(Node * input)984 Reduction JSTypedLowering::ReduceJSToNumberOrNumericInput(Node* input) {
985 // Try constant-folding of JSToNumber/JSToNumeric with constant inputs. Here
986 // we only cover cases where ToNumber and ToNumeric coincide.
987 Type input_type = NodeProperties::GetType(input);
988
989 if (input_type.Is(Type::String())) {
990 HeapObjectMatcher m(input);
991 if (m.HasValue() && m.Ref(js_heap_broker()).IsString()) {
992 StringRef input_value = m.Ref(js_heap_broker()).AsString();
993 double number;
994 ASSIGN_RETURN_NO_CHANGE_IF_DATA_MISSING(number, input_value.ToNumber());
995 return Replace(jsgraph()->Constant(number));
996 }
997 }
998 if (input_type.IsHeapConstant()) {
999 ObjectRef input_value = input_type.AsHeapConstant()->Ref();
1000 if (input_value.oddball_type() != OddballType::kNone) {
1001 return Replace(jsgraph()->Constant(input_value.OddballToNumber()));
1002 }
1003 }
1004 if (input_type.Is(Type::Number())) {
1005 // JSToNumber(x:number) => x
1006 return Changed(input);
1007 }
1008 if (input_type.Is(Type::Undefined())) {
1009 // JSToNumber(undefined) => #NaN
1010 return Replace(jsgraph()->NaNConstant());
1011 }
1012 if (input_type.Is(Type::Null())) {
1013 // JSToNumber(null) => #0
1014 return Replace(jsgraph()->ZeroConstant());
1015 }
1016 return NoChange();
1017 }
1018
ReduceJSToNumberOrNumeric(Node * node)1019 Reduction JSTypedLowering::ReduceJSToNumberOrNumeric(Node* node) {
1020 // Try to reduce the input first.
1021 Node* const input = node->InputAt(0);
1022 Reduction reduction = ReduceJSToNumberOrNumericInput(input);
1023 if (reduction.Changed()) {
1024 ReplaceWithValue(node, reduction.replacement());
1025 return reduction;
1026 }
1027 Type const input_type = NodeProperties::GetType(input);
1028 if (input_type.Is(Type::PlainPrimitive())) {
1029 RelaxEffectsAndControls(node);
1030 node->TrimInputCount(1);
1031 // For a PlainPrimitive, ToNumeric is the same as ToNumber.
1032 Type node_type = NodeProperties::GetType(node);
1033 NodeProperties::SetType(
1034 node, Type::Intersect(node_type, Type::Number(), graph()->zone()));
1035 NodeProperties::ChangeOp(node, simplified()->PlainPrimitiveToNumber());
1036 return Changed(node);
1037 }
1038 // TODO(neis): Reduce ToNumeric to ToNumber if input can't be BigInt?
1039 return NoChange();
1040 }
1041
ReduceJSToStringInput(Node * input)1042 Reduction JSTypedLowering::ReduceJSToStringInput(Node* input) {
1043 if (input->opcode() == IrOpcode::kJSToString) {
1044 // Recursively try to reduce the input first.
1045 Reduction result = ReduceJSToString(input);
1046 if (result.Changed()) return result;
1047 return Changed(input); // JSToString(JSToString(x)) => JSToString(x)
1048 }
1049 Type input_type = NodeProperties::GetType(input);
1050 if (input_type.Is(Type::String())) {
1051 return Changed(input); // JSToString(x:string) => x
1052 }
1053 if (input_type.Is(Type::Boolean())) {
1054 return Replace(graph()->NewNode(
1055 common()->Select(MachineRepresentation::kTagged), input,
1056 jsgraph()->HeapConstant(factory()->true_string()),
1057 jsgraph()->HeapConstant(factory()->false_string())));
1058 }
1059 if (input_type.Is(Type::Undefined())) {
1060 return Replace(jsgraph()->HeapConstant(factory()->undefined_string()));
1061 }
1062 if (input_type.Is(Type::Null())) {
1063 return Replace(jsgraph()->HeapConstant(factory()->null_string()));
1064 }
1065 if (input_type.Is(Type::NaN())) {
1066 return Replace(jsgraph()->HeapConstant(factory()->NaN_string()));
1067 }
1068 if (input_type.Is(Type::OrderedNumber()) &&
1069 input_type.Min() == input_type.Max()) {
1070 // TODO(mslekova): get rid of these allows by doing either one of:
1071 // 1. remove the optimization and check if it ruins the performance
1072 // 2. allocate all the ToString's from numbers before the compilation
1073 // 3. leave a placeholder and do the actual allocations once back on the MT
1074 AllowHandleDereference allow_handle_dereference;
1075 AllowHandleAllocation allow_handle_allocation;
1076 AllowHeapAllocation allow_heap_allocation;
1077 // Note that we can use Type::OrderedNumber(), since
1078 // both 0 and -0 map to the String "0" in JavaScript.
1079 return Replace(jsgraph()->HeapConstant(
1080 factory()->NumberToString(factory()->NewNumber(input_type.Min()))));
1081 }
1082 if (input_type.Is(Type::Number())) {
1083 return Replace(graph()->NewNode(simplified()->NumberToString(), input));
1084 }
1085 return NoChange();
1086 }
1087
ReduceJSToString(Node * node)1088 Reduction JSTypedLowering::ReduceJSToString(Node* node) {
1089 DCHECK_EQ(IrOpcode::kJSToString, node->opcode());
1090 // Try to reduce the input first.
1091 Node* const input = node->InputAt(0);
1092 Reduction reduction = ReduceJSToStringInput(input);
1093 if (reduction.Changed()) {
1094 ReplaceWithValue(node, reduction.replacement());
1095 return reduction;
1096 }
1097 return NoChange();
1098 }
1099
ReduceJSToObject(Node * node)1100 Reduction JSTypedLowering::ReduceJSToObject(Node* node) {
1101 DCHECK_EQ(IrOpcode::kJSToObject, node->opcode());
1102 Node* receiver = NodeProperties::GetValueInput(node, 0);
1103 Type receiver_type = NodeProperties::GetType(receiver);
1104 Node* context = NodeProperties::GetContextInput(node);
1105 Node* frame_state = NodeProperties::GetFrameStateInput(node);
1106 Node* effect = NodeProperties::GetEffectInput(node);
1107 Node* control = NodeProperties::GetControlInput(node);
1108 if (receiver_type.Is(Type::Receiver())) {
1109 ReplaceWithValue(node, receiver, effect, control);
1110 return Replace(receiver);
1111 }
1112
1113 // Check whether {receiver} is a spec object.
1114 Node* check = graph()->NewNode(simplified()->ObjectIsReceiver(), receiver);
1115 Node* branch =
1116 graph()->NewNode(common()->Branch(BranchHint::kTrue), check, control);
1117
1118 Node* if_true = graph()->NewNode(common()->IfTrue(), branch);
1119 Node* etrue = effect;
1120 Node* rtrue = receiver;
1121
1122 Node* if_false = graph()->NewNode(common()->IfFalse(), branch);
1123 Node* efalse = effect;
1124 Node* rfalse;
1125 {
1126 // Convert {receiver} using the ToObjectStub.
1127 Callable callable = Builtins::CallableFor(isolate(), Builtins::kToObject);
1128 auto call_descriptor = Linkage::GetStubCallDescriptor(
1129 graph()->zone(), callable.descriptor(), 0,
1130 CallDescriptor::kNeedsFrameState, node->op()->properties());
1131 rfalse = efalse = if_false =
1132 graph()->NewNode(common()->Call(call_descriptor),
1133 jsgraph()->HeapConstant(callable.code()), receiver,
1134 context, frame_state, efalse, if_false);
1135 }
1136
1137 // Update potential {IfException} uses of {node} to point to the above
1138 // ToObject stub call node instead. Note that the stub can only throw on
1139 // receivers that can be null or undefined.
1140 Node* on_exception = nullptr;
1141 if (receiver_type.Maybe(Type::NullOrUndefined()) &&
1142 NodeProperties::IsExceptionalCall(node, &on_exception)) {
1143 NodeProperties::ReplaceControlInput(on_exception, if_false);
1144 NodeProperties::ReplaceEffectInput(on_exception, efalse);
1145 if_false = graph()->NewNode(common()->IfSuccess(), if_false);
1146 Revisit(on_exception);
1147 }
1148
1149 control = graph()->NewNode(common()->Merge(2), if_true, if_false);
1150 effect = graph()->NewNode(common()->EffectPhi(2), etrue, efalse, control);
1151
1152 // Morph the {node} into an appropriate Phi.
1153 ReplaceWithValue(node, node, effect, control);
1154 node->ReplaceInput(0, rtrue);
1155 node->ReplaceInput(1, rfalse);
1156 node->ReplaceInput(2, control);
1157 node->TrimInputCount(3);
1158 NodeProperties::ChangeOp(node,
1159 common()->Phi(MachineRepresentation::kTagged, 2));
1160 return Changed(node);
1161 }
1162
ReduceJSLoadNamed(Node * node)1163 Reduction JSTypedLowering::ReduceJSLoadNamed(Node* node) {
1164 DCHECK_EQ(IrOpcode::kJSLoadNamed, node->opcode());
1165 Node* receiver = NodeProperties::GetValueInput(node, 0);
1166 Type receiver_type = NodeProperties::GetType(receiver);
1167 NameRef name(js_heap_broker(), NamedAccessOf(node->op()).name());
1168 NameRef length_str(js_heap_broker(), factory()->length_string());
1169 // Optimize "length" property of strings.
1170 if (name.equals(length_str) && receiver_type.Is(Type::String())) {
1171 Node* value = graph()->NewNode(simplified()->StringLength(), receiver);
1172 ReplaceWithValue(node, value);
1173 return Replace(value);
1174 }
1175 return NoChange();
1176 }
1177
ReduceJSHasInPrototypeChain(Node * node)1178 Reduction JSTypedLowering::ReduceJSHasInPrototypeChain(Node* node) {
1179 DCHECK_EQ(IrOpcode::kJSHasInPrototypeChain, node->opcode());
1180 Node* value = NodeProperties::GetValueInput(node, 0);
1181 Type value_type = NodeProperties::GetType(value);
1182 Node* prototype = NodeProperties::GetValueInput(node, 1);
1183 Node* context = NodeProperties::GetContextInput(node);
1184 Node* frame_state = NodeProperties::GetFrameStateInput(node);
1185 Node* effect = NodeProperties::GetEffectInput(node);
1186 Node* control = NodeProperties::GetControlInput(node);
1187
1188 // If {value} cannot be a receiver, then it cannot have {prototype} in
1189 // it's prototype chain (all Primitive values have a null prototype).
1190 if (value_type.Is(Type::Primitive())) {
1191 Node* value = jsgraph()->FalseConstant();
1192 ReplaceWithValue(node, value, effect, control);
1193 return Replace(value);
1194 }
1195
1196 Node* check0 = graph()->NewNode(simplified()->ObjectIsSmi(), value);
1197 Node* branch0 =
1198 graph()->NewNode(common()->Branch(BranchHint::kFalse), check0, control);
1199
1200 Node* if_true0 = graph()->NewNode(common()->IfTrue(), branch0);
1201 Node* etrue0 = effect;
1202 Node* vtrue0 = jsgraph()->FalseConstant();
1203
1204 control = graph()->NewNode(common()->IfFalse(), branch0);
1205
1206 // Loop through the {value}s prototype chain looking for the {prototype}.
1207 Node* loop = control = graph()->NewNode(common()->Loop(2), control, control);
1208 Node* eloop = effect =
1209 graph()->NewNode(common()->EffectPhi(2), effect, effect, loop);
1210 Node* terminate = graph()->NewNode(common()->Terminate(), eloop, loop);
1211 NodeProperties::MergeControlToEnd(graph(), common(), terminate);
1212 Node* vloop = value = graph()->NewNode(
1213 common()->Phi(MachineRepresentation::kTagged, 2), value, value, loop);
1214 NodeProperties::SetType(vloop, Type::NonInternal());
1215
1216 // Load the {value} map and instance type.
1217 Node* value_map = effect = graph()->NewNode(
1218 simplified()->LoadField(AccessBuilder::ForMap()), value, effect, control);
1219 Node* value_instance_type = effect = graph()->NewNode(
1220 simplified()->LoadField(AccessBuilder::ForMapInstanceType()), value_map,
1221 effect, control);
1222
1223 // Check if the {value} is a special receiver, because for special
1224 // receivers, i.e. proxies or API values that need access checks,
1225 // we have to use the %HasInPrototypeChain runtime function instead.
1226 Node* check1 = graph()->NewNode(
1227 simplified()->NumberLessThanOrEqual(), value_instance_type,
1228 jsgraph()->Constant(LAST_SPECIAL_RECEIVER_TYPE));
1229 Node* branch1 =
1230 graph()->NewNode(common()->Branch(BranchHint::kFalse), check1, control);
1231
1232 control = graph()->NewNode(common()->IfFalse(), branch1);
1233
1234 Node* if_true1 = graph()->NewNode(common()->IfTrue(), branch1);
1235 Node* etrue1 = effect;
1236 Node* vtrue1;
1237
1238 // Check if the {value} is not a receiver at all.
1239 Node* check10 =
1240 graph()->NewNode(simplified()->NumberLessThan(), value_instance_type,
1241 jsgraph()->Constant(FIRST_JS_RECEIVER_TYPE));
1242 Node* branch10 =
1243 graph()->NewNode(common()->Branch(BranchHint::kTrue), check10, if_true1);
1244
1245 // A primitive value cannot match the {prototype} we're looking for.
1246 if_true1 = graph()->NewNode(common()->IfTrue(), branch10);
1247 vtrue1 = jsgraph()->FalseConstant();
1248
1249 Node* if_false1 = graph()->NewNode(common()->IfFalse(), branch10);
1250 Node* efalse1 = etrue1;
1251 Node* vfalse1;
1252 {
1253 // Slow path, need to call the %HasInPrototypeChain runtime function.
1254 vfalse1 = efalse1 = if_false1 = graph()->NewNode(
1255 javascript()->CallRuntime(Runtime::kHasInPrototypeChain), value,
1256 prototype, context, frame_state, efalse1, if_false1);
1257
1258 // Replace any potential {IfException} uses of {node} to catch
1259 // exceptions from this %HasInPrototypeChain runtime call instead.
1260 Node* on_exception = nullptr;
1261 if (NodeProperties::IsExceptionalCall(node, &on_exception)) {
1262 NodeProperties::ReplaceControlInput(on_exception, vfalse1);
1263 NodeProperties::ReplaceEffectInput(on_exception, efalse1);
1264 if_false1 = graph()->NewNode(common()->IfSuccess(), vfalse1);
1265 Revisit(on_exception);
1266 }
1267 }
1268
1269 // Load the {value} prototype.
1270 Node* value_prototype = effect = graph()->NewNode(
1271 simplified()->LoadField(AccessBuilder::ForMapPrototype()), value_map,
1272 effect, control);
1273
1274 // Check if we reached the end of {value}s prototype chain.
1275 Node* check2 = graph()->NewNode(simplified()->ReferenceEqual(),
1276 value_prototype, jsgraph()->NullConstant());
1277 Node* branch2 = graph()->NewNode(common()->Branch(), check2, control);
1278
1279 Node* if_true2 = graph()->NewNode(common()->IfTrue(), branch2);
1280 Node* etrue2 = effect;
1281 Node* vtrue2 = jsgraph()->FalseConstant();
1282
1283 control = graph()->NewNode(common()->IfFalse(), branch2);
1284
1285 // Check if we reached the {prototype}.
1286 Node* check3 = graph()->NewNode(simplified()->ReferenceEqual(),
1287 value_prototype, prototype);
1288 Node* branch3 = graph()->NewNode(common()->Branch(), check3, control);
1289
1290 Node* if_true3 = graph()->NewNode(common()->IfTrue(), branch3);
1291 Node* etrue3 = effect;
1292 Node* vtrue3 = jsgraph()->TrueConstant();
1293
1294 control = graph()->NewNode(common()->IfFalse(), branch3);
1295
1296 // Close the loop.
1297 vloop->ReplaceInput(1, value_prototype);
1298 eloop->ReplaceInput(1, effect);
1299 loop->ReplaceInput(1, control);
1300
1301 control = graph()->NewNode(common()->Merge(5), if_true0, if_true1, if_true2,
1302 if_true3, if_false1);
1303 effect = graph()->NewNode(common()->EffectPhi(5), etrue0, etrue1, etrue2,
1304 etrue3, efalse1, control);
1305
1306 // Morph the {node} into an appropriate Phi.
1307 ReplaceWithValue(node, node, effect, control);
1308 node->ReplaceInput(0, vtrue0);
1309 node->ReplaceInput(1, vtrue1);
1310 node->ReplaceInput(2, vtrue2);
1311 node->ReplaceInput(3, vtrue3);
1312 node->ReplaceInput(4, vfalse1);
1313 node->ReplaceInput(5, control);
1314 node->TrimInputCount(6);
1315 NodeProperties::ChangeOp(node,
1316 common()->Phi(MachineRepresentation::kTagged, 5));
1317 return Changed(node);
1318 }
1319
ReduceJSOrdinaryHasInstance(Node * node)1320 Reduction JSTypedLowering::ReduceJSOrdinaryHasInstance(Node* node) {
1321 DCHECK_EQ(IrOpcode::kJSOrdinaryHasInstance, node->opcode());
1322 Node* constructor = NodeProperties::GetValueInput(node, 0);
1323 Type constructor_type = NodeProperties::GetType(constructor);
1324 Node* object = NodeProperties::GetValueInput(node, 1);
1325 Type object_type = NodeProperties::GetType(object);
1326
1327 // Check if the {constructor} cannot be callable.
1328 // See ES6 section 7.3.19 OrdinaryHasInstance ( C, O ) step 1.
1329 if (!constructor_type.Maybe(Type::Callable())) {
1330 Node* value = jsgraph()->FalseConstant();
1331 ReplaceWithValue(node, value);
1332 return Replace(value);
1333 }
1334
1335 // If the {constructor} cannot be a JSBoundFunction and then {object}
1336 // cannot be a JSReceiver, then this can be constant-folded to false.
1337 // See ES6 section 7.3.19 OrdinaryHasInstance ( C, O ) step 2 and 3.
1338 if (!object_type.Maybe(Type::Receiver()) &&
1339 !constructor_type.Maybe(Type::BoundFunction())) {
1340 Node* value = jsgraph()->FalseConstant();
1341 ReplaceWithValue(node, value);
1342 return Replace(value);
1343 }
1344
1345 return NoChange();
1346 }
1347
ReduceJSLoadContext(Node * node)1348 Reduction JSTypedLowering::ReduceJSLoadContext(Node* node) {
1349 DCHECK_EQ(IrOpcode::kJSLoadContext, node->opcode());
1350 ContextAccess const& access = ContextAccessOf(node->op());
1351 Node* effect = NodeProperties::GetEffectInput(node);
1352 Node* context = NodeProperties::GetContextInput(node);
1353 Node* control = graph()->start();
1354 for (size_t i = 0; i < access.depth(); ++i) {
1355 context = effect = graph()->NewNode(
1356 simplified()->LoadField(
1357 AccessBuilder::ForContextSlot(Context::PREVIOUS_INDEX)),
1358 context, effect, control);
1359 }
1360 node->ReplaceInput(0, context);
1361 node->ReplaceInput(1, effect);
1362 node->AppendInput(jsgraph()->zone(), control);
1363 NodeProperties::ChangeOp(
1364 node,
1365 simplified()->LoadField(AccessBuilder::ForContextSlot(access.index())));
1366 return Changed(node);
1367 }
1368
ReduceJSStoreContext(Node * node)1369 Reduction JSTypedLowering::ReduceJSStoreContext(Node* node) {
1370 DCHECK_EQ(IrOpcode::kJSStoreContext, node->opcode());
1371 ContextAccess const& access = ContextAccessOf(node->op());
1372 Node* effect = NodeProperties::GetEffectInput(node);
1373 Node* context = NodeProperties::GetContextInput(node);
1374 Node* control = graph()->start();
1375 Node* value = NodeProperties::GetValueInput(node, 0);
1376 for (size_t i = 0; i < access.depth(); ++i) {
1377 context = effect = graph()->NewNode(
1378 simplified()->LoadField(
1379 AccessBuilder::ForContextSlot(Context::PREVIOUS_INDEX)),
1380 context, effect, control);
1381 }
1382 node->ReplaceInput(0, context);
1383 node->ReplaceInput(1, value);
1384 node->ReplaceInput(2, effect);
1385 NodeProperties::ChangeOp(
1386 node,
1387 simplified()->StoreField(AccessBuilder::ForContextSlot(access.index())));
1388 return Changed(node);
1389 }
1390
BuildGetModuleCell(Node * node)1391 Node* JSTypedLowering::BuildGetModuleCell(Node* node) {
1392 DCHECK(node->opcode() == IrOpcode::kJSLoadModule ||
1393 node->opcode() == IrOpcode::kJSStoreModule);
1394 Node* effect = NodeProperties::GetEffectInput(node);
1395 Node* control = NodeProperties::GetControlInput(node);
1396
1397 int32_t cell_index = OpParameter<int32_t>(node->op());
1398 Node* module = NodeProperties::GetValueInput(node, 0);
1399 Type module_type = NodeProperties::GetType(module);
1400
1401 if (module_type.IsHeapConstant()) {
1402 ModuleRef module_constant = module_type.AsHeapConstant()->Ref().AsModule();
1403 CellRef cell_constant = module_constant.GetCell(cell_index);
1404 return jsgraph()->Constant(cell_constant);
1405 }
1406
1407 FieldAccess field_access;
1408 int index;
1409 if (ModuleDescriptor::GetCellIndexKind(cell_index) ==
1410 ModuleDescriptor::kExport) {
1411 field_access = AccessBuilder::ForModuleRegularExports();
1412 index = cell_index - 1;
1413 } else {
1414 DCHECK_EQ(ModuleDescriptor::GetCellIndexKind(cell_index),
1415 ModuleDescriptor::kImport);
1416 field_access = AccessBuilder::ForModuleRegularImports();
1417 index = -cell_index - 1;
1418 }
1419 Node* array = effect = graph()->NewNode(simplified()->LoadField(field_access),
1420 module, effect, control);
1421 return graph()->NewNode(
1422 simplified()->LoadField(AccessBuilder::ForFixedArraySlot(index)), array,
1423 effect, control);
1424 }
1425
ReduceJSLoadModule(Node * node)1426 Reduction JSTypedLowering::ReduceJSLoadModule(Node* node) {
1427 DCHECK_EQ(IrOpcode::kJSLoadModule, node->opcode());
1428 Node* effect = NodeProperties::GetEffectInput(node);
1429 Node* control = NodeProperties::GetControlInput(node);
1430
1431 Node* cell = BuildGetModuleCell(node);
1432 if (cell->op()->EffectOutputCount() > 0) effect = cell;
1433 Node* value = effect =
1434 graph()->NewNode(simplified()->LoadField(AccessBuilder::ForCellValue()),
1435 cell, effect, control);
1436
1437 ReplaceWithValue(node, value, effect, control);
1438 return Changed(value);
1439 }
1440
ReduceJSStoreModule(Node * node)1441 Reduction JSTypedLowering::ReduceJSStoreModule(Node* node) {
1442 DCHECK_EQ(IrOpcode::kJSStoreModule, node->opcode());
1443 Node* effect = NodeProperties::GetEffectInput(node);
1444 Node* control = NodeProperties::GetControlInput(node);
1445 Node* value = NodeProperties::GetValueInput(node, 1);
1446 DCHECK_EQ(
1447 ModuleDescriptor::GetCellIndexKind(OpParameter<int32_t>(node->op())),
1448 ModuleDescriptor::kExport);
1449
1450 Node* cell = BuildGetModuleCell(node);
1451 if (cell->op()->EffectOutputCount() > 0) effect = cell;
1452 effect =
1453 graph()->NewNode(simplified()->StoreField(AccessBuilder::ForCellValue()),
1454 cell, value, effect, control);
1455
1456 ReplaceWithValue(node, effect, effect, control);
1457 return Changed(value);
1458 }
1459
1460 namespace {
1461
ReduceBuiltin(JSGraph * jsgraph,Node * node,int builtin_index,int arity,CallDescriptor::Flags flags)1462 void ReduceBuiltin(JSGraph* jsgraph, Node* node, int builtin_index, int arity,
1463 CallDescriptor::Flags flags) {
1464 // Patch {node} to a direct CEntry call.
1465 //
1466 // ----------- A r g u m e n t s -----------
1467 // -- 0: CEntry
1468 // --- Stack args ---
1469 // -- 1: receiver
1470 // -- [2, 2 + n[: the n actual arguments passed to the builtin
1471 // -- 2 + n: argc, including the receiver and implicit args (Smi)
1472 // -- 2 + n + 1: target
1473 // -- 2 + n + 2: new_target
1474 // --- Register args ---
1475 // -- 2 + n + 3: the C entry point
1476 // -- 2 + n + 4: argc (Int32)
1477 // -----------------------------------
1478
1479 // The logic contained here is mirrored in Builtins::Generate_Adaptor.
1480 // Keep these in sync.
1481
1482 const bool is_construct = (node->opcode() == IrOpcode::kJSConstruct);
1483
1484 DCHECK(Builtins::HasCppImplementation(builtin_index));
1485
1486 Node* target = NodeProperties::GetValueInput(node, 0);
1487 Node* new_target = is_construct
1488 ? NodeProperties::GetValueInput(node, arity + 1)
1489 : jsgraph->UndefinedConstant();
1490
1491 // API and CPP builtins are implemented in C++, and we can inline both.
1492 // CPP builtins create a builtin exit frame, API builtins don't.
1493 const bool has_builtin_exit_frame = Builtins::IsCpp(builtin_index);
1494
1495 Node* stub = jsgraph->CEntryStubConstant(1, kDontSaveFPRegs, kArgvOnStack,
1496 has_builtin_exit_frame);
1497 node->ReplaceInput(0, stub);
1498
1499 Zone* zone = jsgraph->zone();
1500 if (is_construct) {
1501 // Unify representations between construct and call nodes.
1502 // Remove new target and add receiver as a stack parameter.
1503 Node* receiver = jsgraph->UndefinedConstant();
1504 node->RemoveInput(arity + 1);
1505 node->InsertInput(zone, 1, receiver);
1506 }
1507
1508 const int argc = arity + BuiltinArguments::kNumExtraArgsWithReceiver;
1509 Node* argc_node = jsgraph->Constant(argc);
1510
1511 static const int kStubAndReceiver = 2;
1512 int cursor = arity + kStubAndReceiver;
1513 node->InsertInput(zone, cursor++, jsgraph->PaddingConstant());
1514 node->InsertInput(zone, cursor++, argc_node);
1515 node->InsertInput(zone, cursor++, target);
1516 node->InsertInput(zone, cursor++, new_target);
1517
1518 Address entry = Builtins::CppEntryOf(builtin_index);
1519 ExternalReference entry_ref = ExternalReference::Create(entry);
1520 Node* entry_node = jsgraph->ExternalConstant(entry_ref);
1521
1522 node->InsertInput(zone, cursor++, entry_node);
1523 node->InsertInput(zone, cursor++, argc_node);
1524
1525 static const int kReturnCount = 1;
1526 const char* debug_name = Builtins::name(builtin_index);
1527 Operator::Properties properties = node->op()->properties();
1528 auto call_descriptor = Linkage::GetCEntryStubCallDescriptor(
1529 zone, kReturnCount, argc, debug_name, properties, flags);
1530
1531 NodeProperties::ChangeOp(node, jsgraph->common()->Call(call_descriptor));
1532 }
1533
NeedsArgumentAdaptorFrame(SharedFunctionInfoRef shared,int arity)1534 bool NeedsArgumentAdaptorFrame(SharedFunctionInfoRef shared, int arity) {
1535 static const int sentinel = SharedFunctionInfo::kDontAdaptArgumentsSentinel;
1536 const int num_decl_parms = shared.internal_formal_parameter_count();
1537 return (num_decl_parms != arity && num_decl_parms != sentinel);
1538 }
1539
1540 } // namespace
1541
ReduceJSConstructForwardVarargs(Node * node)1542 Reduction JSTypedLowering::ReduceJSConstructForwardVarargs(Node* node) {
1543 DCHECK_EQ(IrOpcode::kJSConstructForwardVarargs, node->opcode());
1544 ConstructForwardVarargsParameters p =
1545 ConstructForwardVarargsParametersOf(node->op());
1546 DCHECK_LE(2u, p.arity());
1547 int const arity = static_cast<int>(p.arity() - 2);
1548 int const start_index = static_cast<int>(p.start_index());
1549 Node* target = NodeProperties::GetValueInput(node, 0);
1550 Type target_type = NodeProperties::GetType(target);
1551 Node* new_target = NodeProperties::GetValueInput(node, arity + 1);
1552
1553 // Check if {target} is a JSFunction.
1554 if (target_type.IsHeapConstant() &&
1555 target_type.AsHeapConstant()->Ref().IsJSFunction()) {
1556 // Only optimize [[Construct]] here if {function} is a Constructor.
1557 JSFunctionRef function = target_type.AsHeapConstant()->Ref().AsJSFunction();
1558 if (!function.IsConstructor()) return NoChange();
1559 // Patch {node} to an indirect call via ConstructFunctionForwardVarargs.
1560 Callable callable = CodeFactory::ConstructFunctionForwardVarargs(isolate());
1561 node->RemoveInput(arity + 1);
1562 node->InsertInput(graph()->zone(), 0,
1563 jsgraph()->HeapConstant(callable.code()));
1564 node->InsertInput(graph()->zone(), 2, new_target);
1565 node->InsertInput(graph()->zone(), 3, jsgraph()->Constant(arity));
1566 node->InsertInput(graph()->zone(), 4, jsgraph()->Constant(start_index));
1567 node->InsertInput(graph()->zone(), 5, jsgraph()->UndefinedConstant());
1568 NodeProperties::ChangeOp(
1569 node, common()->Call(Linkage::GetStubCallDescriptor(
1570 graph()->zone(), callable.descriptor(), arity + 1,
1571 CallDescriptor::kNeedsFrameState)));
1572 return Changed(node);
1573 }
1574
1575 return NoChange();
1576 }
1577
ReduceJSConstruct(Node * node)1578 Reduction JSTypedLowering::ReduceJSConstruct(Node* node) {
1579 DCHECK_EQ(IrOpcode::kJSConstruct, node->opcode());
1580 ConstructParameters const& p = ConstructParametersOf(node->op());
1581 DCHECK_LE(2u, p.arity());
1582 int const arity = static_cast<int>(p.arity() - 2);
1583 Node* target = NodeProperties::GetValueInput(node, 0);
1584 Type target_type = NodeProperties::GetType(target);
1585 Node* new_target = NodeProperties::GetValueInput(node, arity + 1);
1586
1587 // Check if {target} is a known JSFunction.
1588 if (target_type.IsHeapConstant() &&
1589 target_type.AsHeapConstant()->Ref().IsJSFunction()) {
1590 JSFunctionRef function = target_type.AsHeapConstant()->Ref().AsJSFunction();
1591 SharedFunctionInfoRef shared = function.shared();
1592
1593 // Only optimize [[Construct]] here if {function} is a Constructor.
1594 if (!function.IsConstructor()) return NoChange();
1595
1596 CallDescriptor::Flags flags = CallDescriptor::kNeedsFrameState;
1597
1598 // Patch {node} to an indirect call via the {function}s construct stub.
1599 bool use_builtin_construct_stub = shared.construct_as_builtin();
1600
1601 CodeRef code(js_heap_broker(),
1602 use_builtin_construct_stub
1603 ? BUILTIN_CODE(isolate(), JSBuiltinsConstructStub)
1604 : BUILTIN_CODE(isolate(), JSConstructStubGeneric));
1605
1606 node->RemoveInput(arity + 1);
1607 node->InsertInput(graph()->zone(), 0, jsgraph()->Constant(code));
1608 node->InsertInput(graph()->zone(), 2, new_target);
1609 node->InsertInput(graph()->zone(), 3, jsgraph()->Constant(arity));
1610 node->InsertInput(graph()->zone(), 4, jsgraph()->UndefinedConstant());
1611 node->InsertInput(graph()->zone(), 5, jsgraph()->UndefinedConstant());
1612 NodeProperties::ChangeOp(
1613 node,
1614 common()->Call(Linkage::GetStubCallDescriptor(
1615 graph()->zone(), ConstructStubDescriptor{}, 1 + arity, flags)));
1616
1617 return Changed(node);
1618 }
1619
1620 return NoChange();
1621 }
1622
ReduceJSCallForwardVarargs(Node * node)1623 Reduction JSTypedLowering::ReduceJSCallForwardVarargs(Node* node) {
1624 DCHECK_EQ(IrOpcode::kJSCallForwardVarargs, node->opcode());
1625 CallForwardVarargsParameters p = CallForwardVarargsParametersOf(node->op());
1626 DCHECK_LE(2u, p.arity());
1627 int const arity = static_cast<int>(p.arity() - 2);
1628 int const start_index = static_cast<int>(p.start_index());
1629 Node* target = NodeProperties::GetValueInput(node, 0);
1630 Type target_type = NodeProperties::GetType(target);
1631
1632 // Check if {target} is a JSFunction.
1633 if (target_type.Is(Type::Function())) {
1634 // Compute flags for the call.
1635 CallDescriptor::Flags flags = CallDescriptor::kNeedsFrameState;
1636 // Patch {node} to an indirect call via CallFunctionForwardVarargs.
1637 Callable callable = CodeFactory::CallFunctionForwardVarargs(isolate());
1638 node->InsertInput(graph()->zone(), 0,
1639 jsgraph()->HeapConstant(callable.code()));
1640 node->InsertInput(graph()->zone(), 2, jsgraph()->Constant(arity));
1641 node->InsertInput(graph()->zone(), 3, jsgraph()->Constant(start_index));
1642 NodeProperties::ChangeOp(
1643 node, common()->Call(Linkage::GetStubCallDescriptor(
1644 graph()->zone(), callable.descriptor(), arity + 1, flags)));
1645 return Changed(node);
1646 }
1647
1648 return NoChange();
1649 }
1650
ReduceJSCall(Node * node)1651 Reduction JSTypedLowering::ReduceJSCall(Node* node) {
1652 DCHECK_EQ(IrOpcode::kJSCall, node->opcode());
1653 CallParameters const& p = CallParametersOf(node->op());
1654 int const arity = static_cast<int>(p.arity() - 2);
1655 ConvertReceiverMode convert_mode = p.convert_mode();
1656 Node* target = NodeProperties::GetValueInput(node, 0);
1657 Type target_type = NodeProperties::GetType(target);
1658 Node* receiver = NodeProperties::GetValueInput(node, 1);
1659 Type receiver_type = NodeProperties::GetType(receiver);
1660 Node* effect = NodeProperties::GetEffectInput(node);
1661 Node* control = NodeProperties::GetControlInput(node);
1662
1663 // Try to infer receiver {convert_mode} from {receiver} type.
1664 if (receiver_type.Is(Type::NullOrUndefined())) {
1665 convert_mode = ConvertReceiverMode::kNullOrUndefined;
1666 } else if (!receiver_type.Maybe(Type::NullOrUndefined())) {
1667 convert_mode = ConvertReceiverMode::kNotNullOrUndefined;
1668 }
1669
1670 // Check if {target} is a known JSFunction.
1671 if (target_type.IsHeapConstant() &&
1672 target_type.AsHeapConstant()->Ref().IsJSFunction()) {
1673 JSFunctionRef function = target_type.AsHeapConstant()->Ref().AsJSFunction();
1674 SharedFunctionInfoRef shared = function.shared();
1675
1676 if (shared.HasBreakInfo()) {
1677 // Do not inline the call if we need to check whether to break at entry.
1678 return NoChange();
1679 }
1680
1681 // Class constructors are callable, but [[Call]] will raise an exception.
1682 // See ES6 section 9.2.1 [[Call]] ( thisArgument, argumentsList ).
1683 if (IsClassConstructor(shared.kind())) return NoChange();
1684
1685 // Load the context from the {target}.
1686 Node* context = effect = graph()->NewNode(
1687 simplified()->LoadField(AccessBuilder::ForJSFunctionContext()), target,
1688 effect, control);
1689 NodeProperties::ReplaceContextInput(node, context);
1690
1691 // Check if we need to convert the {receiver}.
1692 if (is_sloppy(shared.language_mode()) && !shared.native() &&
1693 !receiver_type.Is(Type::Receiver())) {
1694 Node* global_proxy = jsgraph()->Constant(function.global_proxy());
1695 receiver = effect =
1696 graph()->NewNode(simplified()->ConvertReceiver(convert_mode),
1697 receiver, global_proxy, effect, control);
1698 NodeProperties::ReplaceValueInput(node, receiver, 1);
1699 }
1700
1701 // Update the effect dependency for the {node}.
1702 NodeProperties::ReplaceEffectInput(node, effect);
1703
1704 // Compute flags for the call.
1705 CallDescriptor::Flags flags = CallDescriptor::kNeedsFrameState;
1706 Node* new_target = jsgraph()->UndefinedConstant();
1707 Node* argument_count = jsgraph()->Constant(arity);
1708
1709 if (NeedsArgumentAdaptorFrame(shared, arity)) {
1710 // Patch {node} to an indirect call via the ArgumentsAdaptorTrampoline.
1711 Callable callable = CodeFactory::ArgumentAdaptor(isolate());
1712 node->InsertInput(graph()->zone(), 0,
1713 jsgraph()->HeapConstant(callable.code()));
1714 node->InsertInput(graph()->zone(), 2, new_target);
1715 node->InsertInput(graph()->zone(), 3, argument_count);
1716 node->InsertInput(
1717 graph()->zone(), 4,
1718 jsgraph()->Constant(shared.internal_formal_parameter_count()));
1719 NodeProperties::ChangeOp(
1720 node, common()->Call(Linkage::GetStubCallDescriptor(
1721 graph()->zone(), callable.descriptor(), 1 + arity, flags)));
1722 } else if (shared.HasBuiltinId() &&
1723 Builtins::HasCppImplementation(shared.builtin_id())) {
1724 // Patch {node} to a direct CEntry call.
1725 ReduceBuiltin(jsgraph(), node, shared.builtin_id(), arity, flags);
1726 } else if (shared.HasBuiltinId() &&
1727 Builtins::KindOf(shared.builtin_id()) == Builtins::TFJ) {
1728 // Patch {node} to a direct code object call.
1729 Callable callable = Builtins::CallableFor(
1730 isolate(), static_cast<Builtins::Name>(shared.builtin_id()));
1731 CallDescriptor::Flags flags = CallDescriptor::kNeedsFrameState;
1732
1733 const CallInterfaceDescriptor& descriptor = callable.descriptor();
1734 auto call_descriptor = Linkage::GetStubCallDescriptor(
1735 graph()->zone(), descriptor, 1 + arity, flags);
1736 Node* stub_code = jsgraph()->HeapConstant(callable.code());
1737 node->InsertInput(graph()->zone(), 0, stub_code); // Code object.
1738 node->InsertInput(graph()->zone(), 2, new_target);
1739 node->InsertInput(graph()->zone(), 3, argument_count);
1740 NodeProperties::ChangeOp(node, common()->Call(call_descriptor));
1741 } else {
1742 // Patch {node} to a direct call.
1743 node->InsertInput(graph()->zone(), arity + 2, new_target);
1744 node->InsertInput(graph()->zone(), arity + 3, argument_count);
1745 NodeProperties::ChangeOp(node,
1746 common()->Call(Linkage::GetJSCallDescriptor(
1747 graph()->zone(), false, 1 + arity, flags)));
1748 }
1749 return Changed(node);
1750 }
1751
1752 // Check if {target} is a JSFunction.
1753 if (target_type.Is(Type::Function())) {
1754 // Compute flags for the call.
1755 CallDescriptor::Flags flags = CallDescriptor::kNeedsFrameState;
1756 // Patch {node} to an indirect call via the CallFunction builtin.
1757 Callable callable = CodeFactory::CallFunction(isolate(), convert_mode);
1758 node->InsertInput(graph()->zone(), 0,
1759 jsgraph()->HeapConstant(callable.code()));
1760 node->InsertInput(graph()->zone(), 2, jsgraph()->Constant(arity));
1761 NodeProperties::ChangeOp(
1762 node, common()->Call(Linkage::GetStubCallDescriptor(
1763 graph()->zone(), callable.descriptor(), 1 + arity, flags)));
1764 return Changed(node);
1765 }
1766
1767 // Maybe we did at least learn something about the {receiver}.
1768 if (p.convert_mode() != convert_mode) {
1769 NodeProperties::ChangeOp(
1770 node, javascript()->Call(p.arity(), p.frequency(), p.feedback(),
1771 convert_mode, p.speculation_mode()));
1772 return Changed(node);
1773 }
1774
1775 return NoChange();
1776 }
1777
ReduceJSForInNext(Node * node)1778 Reduction JSTypedLowering::ReduceJSForInNext(Node* node) {
1779 DCHECK_EQ(IrOpcode::kJSForInNext, node->opcode());
1780 ForInMode const mode = ForInModeOf(node->op());
1781 Node* receiver = NodeProperties::GetValueInput(node, 0);
1782 Node* cache_array = NodeProperties::GetValueInput(node, 1);
1783 Node* cache_type = NodeProperties::GetValueInput(node, 2);
1784 Node* index = NodeProperties::GetValueInput(node, 3);
1785 Node* context = NodeProperties::GetContextInput(node);
1786 Node* frame_state = NodeProperties::GetFrameStateInput(node);
1787 Node* effect = NodeProperties::GetEffectInput(node);
1788 Node* control = NodeProperties::GetControlInput(node);
1789
1790 // Load the map of the {receiver}.
1791 Node* receiver_map = effect =
1792 graph()->NewNode(simplified()->LoadField(AccessBuilder::ForMap()),
1793 receiver, effect, control);
1794
1795 switch (mode) {
1796 case ForInMode::kUseEnumCacheKeys:
1797 case ForInMode::kUseEnumCacheKeysAndIndices: {
1798 // Ensure that the expected map still matches that of the {receiver}.
1799 Node* check = graph()->NewNode(simplified()->ReferenceEqual(),
1800 receiver_map, cache_type);
1801 effect =
1802 graph()->NewNode(simplified()->CheckIf(DeoptimizeReason::kWrongMap),
1803 check, effect, control);
1804
1805 // Since the change to LoadElement() below is effectful, we connect
1806 // node to all effect uses.
1807 ReplaceWithValue(node, node, node, control);
1808
1809 // Morph the {node} into a LoadElement.
1810 node->ReplaceInput(0, cache_array);
1811 node->ReplaceInput(1, index);
1812 node->ReplaceInput(2, effect);
1813 node->ReplaceInput(3, control);
1814 node->TrimInputCount(4);
1815 NodeProperties::ChangeOp(
1816 node,
1817 simplified()->LoadElement(AccessBuilder::ForFixedArrayElement()));
1818 NodeProperties::SetType(node, Type::InternalizedString());
1819 break;
1820 }
1821 case ForInMode::kGeneric: {
1822 // Load the next {key} from the {cache_array}.
1823 Node* key = effect = graph()->NewNode(
1824 simplified()->LoadElement(AccessBuilder::ForFixedArrayElement()),
1825 cache_array, index, effect, control);
1826
1827 // Check if the expected map still matches that of the {receiver}.
1828 Node* check = graph()->NewNode(simplified()->ReferenceEqual(),
1829 receiver_map, cache_type);
1830 Node* branch =
1831 graph()->NewNode(common()->Branch(BranchHint::kTrue), check, control);
1832
1833 Node* if_true = graph()->NewNode(common()->IfTrue(), branch);
1834 Node* etrue;
1835 Node* vtrue;
1836 {
1837 // Don't need filtering since expected map still matches that of the
1838 // {receiver}.
1839 etrue = effect;
1840 vtrue = key;
1841 }
1842
1843 Node* if_false = graph()->NewNode(common()->IfFalse(), branch);
1844 Node* efalse;
1845 Node* vfalse;
1846 {
1847 // Filter the {key} to check if it's still a valid property of the
1848 // {receiver} (does the ToName conversion implicitly).
1849 Callable const callable =
1850 Builtins::CallableFor(isolate(), Builtins::kForInFilter);
1851 auto call_descriptor = Linkage::GetStubCallDescriptor(
1852 graph()->zone(), callable.descriptor(), 0,
1853 CallDescriptor::kNeedsFrameState);
1854 vfalse = efalse = if_false =
1855 graph()->NewNode(common()->Call(call_descriptor),
1856 jsgraph()->HeapConstant(callable.code()), key,
1857 receiver, context, frame_state, effect, if_false);
1858
1859 // Update potential {IfException} uses of {node} to point to the above
1860 // ForInFilter stub call node instead.
1861 Node* if_exception = nullptr;
1862 if (NodeProperties::IsExceptionalCall(node, &if_exception)) {
1863 if_false = graph()->NewNode(common()->IfSuccess(), vfalse);
1864 NodeProperties::ReplaceControlInput(if_exception, vfalse);
1865 NodeProperties::ReplaceEffectInput(if_exception, efalse);
1866 Revisit(if_exception);
1867 }
1868 }
1869
1870 control = graph()->NewNode(common()->Merge(2), if_true, if_false);
1871 effect = graph()->NewNode(common()->EffectPhi(2), etrue, efalse, control);
1872 ReplaceWithValue(node, node, effect, control);
1873
1874 // Morph the {node} into a Phi.
1875 node->ReplaceInput(0, vtrue);
1876 node->ReplaceInput(1, vfalse);
1877 node->ReplaceInput(2, control);
1878 node->TrimInputCount(3);
1879 NodeProperties::ChangeOp(
1880 node, common()->Phi(MachineRepresentation::kTagged, 2));
1881 }
1882 }
1883
1884 return Changed(node);
1885 }
1886
ReduceJSForInPrepare(Node * node)1887 Reduction JSTypedLowering::ReduceJSForInPrepare(Node* node) {
1888 DCHECK_EQ(IrOpcode::kJSForInPrepare, node->opcode());
1889 ForInMode const mode = ForInModeOf(node->op());
1890 Node* enumerator = NodeProperties::GetValueInput(node, 0);
1891 Node* effect = NodeProperties::GetEffectInput(node);
1892 Node* control = NodeProperties::GetControlInput(node);
1893 Node* cache_type = enumerator;
1894 Node* cache_array = nullptr;
1895 Node* cache_length = nullptr;
1896
1897 switch (mode) {
1898 case ForInMode::kUseEnumCacheKeys:
1899 case ForInMode::kUseEnumCacheKeysAndIndices: {
1900 // Check that the {enumerator} is a Map.
1901 effect = graph()->NewNode(
1902 simplified()->CheckMaps(CheckMapsFlag::kNone,
1903 ZoneHandleSet<Map>(factory()->meta_map())),
1904 enumerator, effect, control);
1905
1906 // Load the enum cache from the {enumerator} map.
1907 Node* descriptor_array = effect = graph()->NewNode(
1908 simplified()->LoadField(AccessBuilder::ForMapDescriptors()),
1909 enumerator, effect, control);
1910 Node* enum_cache = effect = graph()->NewNode(
1911 simplified()->LoadField(AccessBuilder::ForDescriptorArrayEnumCache()),
1912 descriptor_array, effect, control);
1913 cache_array = effect = graph()->NewNode(
1914 simplified()->LoadField(AccessBuilder::ForEnumCacheKeys()),
1915 enum_cache, effect, control);
1916
1917 // Load the enum length of the {enumerator} map.
1918 Node* bit_field3 = effect = graph()->NewNode(
1919 simplified()->LoadField(AccessBuilder::ForMapBitField3()), enumerator,
1920 effect, control);
1921 STATIC_ASSERT(Map::EnumLengthBits::kShift == 0);
1922 cache_length =
1923 graph()->NewNode(simplified()->NumberBitwiseAnd(), bit_field3,
1924 jsgraph()->Constant(Map::EnumLengthBits::kMask));
1925 break;
1926 }
1927 case ForInMode::kGeneric: {
1928 // Check if the {enumerator} is a Map or a FixedArray.
1929 Node* check = effect = graph()->NewNode(
1930 simplified()->CompareMaps(ZoneHandleSet<Map>(factory()->meta_map())),
1931 enumerator, effect, control);
1932 Node* branch =
1933 graph()->NewNode(common()->Branch(BranchHint::kTrue), check, control);
1934
1935 Node* if_true = graph()->NewNode(common()->IfTrue(), branch);
1936 Node* etrue = effect;
1937 Node* cache_array_true;
1938 Node* cache_length_true;
1939 {
1940 // Load the enum cache from the {enumerator} map.
1941 Node* descriptor_array = etrue = graph()->NewNode(
1942 simplified()->LoadField(AccessBuilder::ForMapDescriptors()),
1943 enumerator, etrue, if_true);
1944 Node* enum_cache = etrue =
1945 graph()->NewNode(simplified()->LoadField(
1946 AccessBuilder::ForDescriptorArrayEnumCache()),
1947 descriptor_array, etrue, if_true);
1948 cache_array_true = etrue = graph()->NewNode(
1949 simplified()->LoadField(AccessBuilder::ForEnumCacheKeys()),
1950 enum_cache, etrue, if_true);
1951
1952 // Load the enum length of the {enumerator} map.
1953 Node* bit_field3 = etrue = graph()->NewNode(
1954 simplified()->LoadField(AccessBuilder::ForMapBitField3()),
1955 enumerator, etrue, if_true);
1956 STATIC_ASSERT(Map::EnumLengthBits::kShift == 0);
1957 cache_length_true =
1958 graph()->NewNode(simplified()->NumberBitwiseAnd(), bit_field3,
1959 jsgraph()->Constant(Map::EnumLengthBits::kMask));
1960 }
1961
1962 Node* if_false = graph()->NewNode(common()->IfFalse(), branch);
1963 Node* efalse = effect;
1964 Node* cache_array_false;
1965 Node* cache_length_false;
1966 {
1967 // The {enumerator} is the FixedArray with the keys to iterate.
1968 cache_array_false = enumerator;
1969 cache_length_false = efalse = graph()->NewNode(
1970 simplified()->LoadField(AccessBuilder::ForFixedArrayLength()),
1971 cache_array_false, efalse, if_false);
1972 }
1973
1974 // Rewrite the uses of the {node}.
1975 control = graph()->NewNode(common()->Merge(2), if_true, if_false);
1976 effect = graph()->NewNode(common()->EffectPhi(2), etrue, efalse, control);
1977 cache_array =
1978 graph()->NewNode(common()->Phi(MachineRepresentation::kTagged, 2),
1979 cache_array_true, cache_array_false, control);
1980 cache_length =
1981 graph()->NewNode(common()->Phi(MachineRepresentation::kTagged, 2),
1982 cache_length_true, cache_length_false, control);
1983 break;
1984 }
1985 }
1986
1987 // Update the uses of {node}.
1988 for (Edge edge : node->use_edges()) {
1989 Node* const user = edge.from();
1990 if (NodeProperties::IsEffectEdge(edge)) {
1991 edge.UpdateTo(effect);
1992 Revisit(user);
1993 } else if (NodeProperties::IsControlEdge(edge)) {
1994 edge.UpdateTo(control);
1995 Revisit(user);
1996 } else {
1997 DCHECK(NodeProperties::IsValueEdge(edge));
1998 switch (ProjectionIndexOf(user->op())) {
1999 case 0:
2000 Replace(user, cache_type);
2001 break;
2002 case 1:
2003 Replace(user, cache_array);
2004 break;
2005 case 2:
2006 Replace(user, cache_length);
2007 break;
2008 default:
2009 UNREACHABLE();
2010 }
2011 }
2012 }
2013 node->Kill();
2014 return Replace(effect);
2015 }
2016
ReduceJSLoadMessage(Node * node)2017 Reduction JSTypedLowering::ReduceJSLoadMessage(Node* node) {
2018 DCHECK_EQ(IrOpcode::kJSLoadMessage, node->opcode());
2019 ExternalReference const ref =
2020 ExternalReference::address_of_pending_message_obj(isolate());
2021 node->ReplaceInput(0, jsgraph()->ExternalConstant(ref));
2022 NodeProperties::ChangeOp(
2023 node, simplified()->LoadField(AccessBuilder::ForExternalTaggedValue()));
2024 return Changed(node);
2025 }
2026
ReduceJSStoreMessage(Node * node)2027 Reduction JSTypedLowering::ReduceJSStoreMessage(Node* node) {
2028 DCHECK_EQ(IrOpcode::kJSStoreMessage, node->opcode());
2029 ExternalReference const ref =
2030 ExternalReference::address_of_pending_message_obj(isolate());
2031 Node* value = NodeProperties::GetValueInput(node, 0);
2032 node->ReplaceInput(0, jsgraph()->ExternalConstant(ref));
2033 node->ReplaceInput(1, value);
2034 NodeProperties::ChangeOp(
2035 node, simplified()->StoreField(AccessBuilder::ForExternalTaggedValue()));
2036 return Changed(node);
2037 }
2038
ReduceJSGeneratorStore(Node * node)2039 Reduction JSTypedLowering::ReduceJSGeneratorStore(Node* node) {
2040 DCHECK_EQ(IrOpcode::kJSGeneratorStore, node->opcode());
2041 Node* generator = NodeProperties::GetValueInput(node, 0);
2042 Node* continuation = NodeProperties::GetValueInput(node, 1);
2043 Node* offset = NodeProperties::GetValueInput(node, 2);
2044 Node* context = NodeProperties::GetContextInput(node);
2045 Node* effect = NodeProperties::GetEffectInput(node);
2046 Node* control = NodeProperties::GetControlInput(node);
2047 int value_count = GeneratorStoreValueCountOf(node->op());
2048
2049 FieldAccess array_field =
2050 AccessBuilder::ForJSGeneratorObjectParametersAndRegisters();
2051 FieldAccess context_field = AccessBuilder::ForJSGeneratorObjectContext();
2052 FieldAccess continuation_field =
2053 AccessBuilder::ForJSGeneratorObjectContinuation();
2054 FieldAccess input_or_debug_pos_field =
2055 AccessBuilder::ForJSGeneratorObjectInputOrDebugPos();
2056
2057 Node* array = effect = graph()->NewNode(simplified()->LoadField(array_field),
2058 generator, effect, control);
2059
2060 for (int i = 0; i < value_count; ++i) {
2061 Node* value = NodeProperties::GetValueInput(node, 3 + i);
2062 if (value != jsgraph()->OptimizedOutConstant()) {
2063 effect = graph()->NewNode(
2064 simplified()->StoreField(AccessBuilder::ForFixedArraySlot(i)), array,
2065 value, effect, control);
2066 }
2067 }
2068
2069 effect = graph()->NewNode(simplified()->StoreField(context_field), generator,
2070 context, effect, control);
2071 effect = graph()->NewNode(simplified()->StoreField(continuation_field),
2072 generator, continuation, effect, control);
2073 effect = graph()->NewNode(simplified()->StoreField(input_or_debug_pos_field),
2074 generator, offset, effect, control);
2075
2076 ReplaceWithValue(node, effect, effect, control);
2077 return Changed(effect);
2078 }
2079
ReduceJSGeneratorRestoreContinuation(Node * node)2080 Reduction JSTypedLowering::ReduceJSGeneratorRestoreContinuation(Node* node) {
2081 DCHECK_EQ(IrOpcode::kJSGeneratorRestoreContinuation, node->opcode());
2082 Node* generator = NodeProperties::GetValueInput(node, 0);
2083 Node* effect = NodeProperties::GetEffectInput(node);
2084 Node* control = NodeProperties::GetControlInput(node);
2085
2086 FieldAccess continuation_field =
2087 AccessBuilder::ForJSGeneratorObjectContinuation();
2088
2089 Node* continuation = effect = graph()->NewNode(
2090 simplified()->LoadField(continuation_field), generator, effect, control);
2091 Node* executing = jsgraph()->Constant(JSGeneratorObject::kGeneratorExecuting);
2092 effect = graph()->NewNode(simplified()->StoreField(continuation_field),
2093 generator, executing, effect, control);
2094
2095 ReplaceWithValue(node, continuation, effect, control);
2096 return Changed(continuation);
2097 }
2098
ReduceJSGeneratorRestoreContext(Node * node)2099 Reduction JSTypedLowering::ReduceJSGeneratorRestoreContext(Node* node) {
2100 DCHECK_EQ(IrOpcode::kJSGeneratorRestoreContext, node->opcode());
2101
2102 const Operator* new_op =
2103 simplified()->LoadField(AccessBuilder::ForJSGeneratorObjectContext());
2104
2105 // Mutate the node in-place.
2106 DCHECK(OperatorProperties::HasContextInput(node->op()));
2107 DCHECK(!OperatorProperties::HasContextInput(new_op));
2108 node->RemoveInput(NodeProperties::FirstContextIndex(node));
2109
2110 NodeProperties::ChangeOp(node, new_op);
2111 return Changed(node);
2112 }
2113
ReduceJSGeneratorRestoreRegister(Node * node)2114 Reduction JSTypedLowering::ReduceJSGeneratorRestoreRegister(Node* node) {
2115 DCHECK_EQ(IrOpcode::kJSGeneratorRestoreRegister, node->opcode());
2116 Node* generator = NodeProperties::GetValueInput(node, 0);
2117 Node* effect = NodeProperties::GetEffectInput(node);
2118 Node* control = NodeProperties::GetControlInput(node);
2119 int index = RestoreRegisterIndexOf(node->op());
2120
2121 FieldAccess array_field =
2122 AccessBuilder::ForJSGeneratorObjectParametersAndRegisters();
2123 FieldAccess element_field = AccessBuilder::ForFixedArraySlot(index);
2124
2125 Node* array = effect = graph()->NewNode(simplified()->LoadField(array_field),
2126 generator, effect, control);
2127 Node* element = effect = graph()->NewNode(
2128 simplified()->LoadField(element_field), array, effect, control);
2129 Node* stale = jsgraph()->StaleRegisterConstant();
2130 effect = graph()->NewNode(simplified()->StoreField(element_field), array,
2131 stale, effect, control);
2132
2133 ReplaceWithValue(node, element, effect, control);
2134 return Changed(element);
2135 }
2136
ReduceJSGeneratorRestoreInputOrDebugPos(Node * node)2137 Reduction JSTypedLowering::ReduceJSGeneratorRestoreInputOrDebugPos(Node* node) {
2138 DCHECK_EQ(IrOpcode::kJSGeneratorRestoreInputOrDebugPos, node->opcode());
2139
2140 FieldAccess input_or_debug_pos_field =
2141 AccessBuilder::ForJSGeneratorObjectInputOrDebugPos();
2142 const Operator* new_op = simplified()->LoadField(input_or_debug_pos_field);
2143
2144 // Mutate the node in-place.
2145 DCHECK(OperatorProperties::HasContextInput(node->op()));
2146 DCHECK(!OperatorProperties::HasContextInput(new_op));
2147 node->RemoveInput(NodeProperties::FirstContextIndex(node));
2148
2149 NodeProperties::ChangeOp(node, new_op);
2150 return Changed(node);
2151 }
2152
ReduceObjectIsArray(Node * node)2153 Reduction JSTypedLowering::ReduceObjectIsArray(Node* node) {
2154 Node* value = NodeProperties::GetValueInput(node, 0);
2155 Type value_type = NodeProperties::GetType(value);
2156 Node* context = NodeProperties::GetContextInput(node);
2157 Node* frame_state = NodeProperties::GetFrameStateInput(node);
2158 Node* effect = NodeProperties::GetEffectInput(node);
2159 Node* control = NodeProperties::GetControlInput(node);
2160
2161 // Constant-fold based on {value} type.
2162 if (value_type.Is(Type::Array())) {
2163 Node* value = jsgraph()->TrueConstant();
2164 ReplaceWithValue(node, value);
2165 return Replace(value);
2166 } else if (!value_type.Maybe(Type::ArrayOrProxy())) {
2167 Node* value = jsgraph()->FalseConstant();
2168 ReplaceWithValue(node, value);
2169 return Replace(value);
2170 }
2171
2172 int count = 0;
2173 Node* values[5];
2174 Node* effects[5];
2175 Node* controls[4];
2176
2177 // Check if the {value} is a Smi.
2178 Node* check = graph()->NewNode(simplified()->ObjectIsSmi(), value);
2179 control =
2180 graph()->NewNode(common()->Branch(BranchHint::kFalse), check, control);
2181
2182 // The {value} is a Smi.
2183 controls[count] = graph()->NewNode(common()->IfTrue(), control);
2184 effects[count] = effect;
2185 values[count] = jsgraph()->FalseConstant();
2186 count++;
2187
2188 control = graph()->NewNode(common()->IfFalse(), control);
2189
2190 // Load the {value}s instance type.
2191 Node* value_map = effect = graph()->NewNode(
2192 simplified()->LoadField(AccessBuilder::ForMap()), value, effect, control);
2193 Node* value_instance_type = effect = graph()->NewNode(
2194 simplified()->LoadField(AccessBuilder::ForMapInstanceType()), value_map,
2195 effect, control);
2196
2197 // Check if the {value} is a JSArray.
2198 check = graph()->NewNode(simplified()->NumberEqual(), value_instance_type,
2199 jsgraph()->Constant(JS_ARRAY_TYPE));
2200 control = graph()->NewNode(common()->Branch(), check, control);
2201
2202 // The {value} is a JSArray.
2203 controls[count] = graph()->NewNode(common()->IfTrue(), control);
2204 effects[count] = effect;
2205 values[count] = jsgraph()->TrueConstant();
2206 count++;
2207
2208 control = graph()->NewNode(common()->IfFalse(), control);
2209
2210 // Check if the {value} is a JSProxy.
2211 check = graph()->NewNode(simplified()->NumberEqual(), value_instance_type,
2212 jsgraph()->Constant(JS_PROXY_TYPE));
2213 control =
2214 graph()->NewNode(common()->Branch(BranchHint::kFalse), check, control);
2215
2216 // The {value} is neither a JSArray nor a JSProxy.
2217 controls[count] = graph()->NewNode(common()->IfFalse(), control);
2218 effects[count] = effect;
2219 values[count] = jsgraph()->FalseConstant();
2220 count++;
2221
2222 control = graph()->NewNode(common()->IfTrue(), control);
2223
2224 // Let the %ArrayIsArray runtime function deal with the JSProxy {value}.
2225 value = effect = control =
2226 graph()->NewNode(javascript()->CallRuntime(Runtime::kArrayIsArray), value,
2227 context, frame_state, effect, control);
2228 NodeProperties::SetType(value, Type::Boolean());
2229
2230 // Update potential {IfException} uses of {node} to point to the above
2231 // %ArrayIsArray runtime call node instead.
2232 Node* on_exception = nullptr;
2233 if (NodeProperties::IsExceptionalCall(node, &on_exception)) {
2234 NodeProperties::ReplaceControlInput(on_exception, control);
2235 NodeProperties::ReplaceEffectInput(on_exception, effect);
2236 control = graph()->NewNode(common()->IfSuccess(), control);
2237 Revisit(on_exception);
2238 }
2239
2240 // The {value} is neither a JSArray nor a JSProxy.
2241 controls[count] = control;
2242 effects[count] = effect;
2243 values[count] = value;
2244 count++;
2245
2246 control = graph()->NewNode(common()->Merge(count), count, controls);
2247 effects[count] = control;
2248 values[count] = control;
2249 effect = graph()->NewNode(common()->EffectPhi(count), count + 1, effects);
2250 value = graph()->NewNode(common()->Phi(MachineRepresentation::kTagged, count),
2251 count + 1, values);
2252 ReplaceWithValue(node, value, effect, control);
2253 return Replace(value);
2254 }
2255
ReduceJSParseInt(Node * node)2256 Reduction JSTypedLowering::ReduceJSParseInt(Node* node) {
2257 Node* value = NodeProperties::GetValueInput(node, 0);
2258 Type value_type = NodeProperties::GetType(value);
2259 Node* radix = NodeProperties::GetValueInput(node, 1);
2260 Type radix_type = NodeProperties::GetType(radix);
2261 // We need kTenOrUndefined and kZeroOrUndefined because
2262 // the type representing {0,10} would become the range 1-10.
2263 if (value_type.Is(type_cache_.kSafeInteger) &&
2264 (radix_type.Is(type_cache_.kTenOrUndefined) ||
2265 radix_type.Is(type_cache_.kZeroOrUndefined))) {
2266 // Number.parseInt(a:safe-integer) -> a
2267 // Number.parseInt(a:safe-integer,b:#0\/undefined) -> a
2268 // Number.parseInt(a:safe-integer,b:#10\/undefined) -> a
2269 ReplaceWithValue(node, value);
2270 return Replace(value);
2271 }
2272 return NoChange();
2273 }
2274
Reduce(Node * node)2275 Reduction JSTypedLowering::Reduce(Node* node) {
2276 DisallowHeapAccess no_heap_access;
2277
2278 switch (node->opcode()) {
2279 case IrOpcode::kJSEqual:
2280 return ReduceJSEqual(node);
2281 case IrOpcode::kJSStrictEqual:
2282 return ReduceJSStrictEqual(node);
2283 case IrOpcode::kJSLessThan: // fall through
2284 case IrOpcode::kJSGreaterThan: // fall through
2285 case IrOpcode::kJSLessThanOrEqual: // fall through
2286 case IrOpcode::kJSGreaterThanOrEqual:
2287 return ReduceJSComparison(node);
2288 case IrOpcode::kJSBitwiseOr:
2289 case IrOpcode::kJSBitwiseXor:
2290 case IrOpcode::kJSBitwiseAnd:
2291 return ReduceInt32Binop(node);
2292 case IrOpcode::kJSShiftLeft:
2293 case IrOpcode::kJSShiftRight:
2294 return ReduceUI32Shift(node, kSigned);
2295 case IrOpcode::kJSShiftRightLogical:
2296 return ReduceUI32Shift(node, kUnsigned);
2297 case IrOpcode::kJSAdd:
2298 return ReduceJSAdd(node);
2299 case IrOpcode::kJSSubtract:
2300 case IrOpcode::kJSMultiply:
2301 case IrOpcode::kJSDivide:
2302 case IrOpcode::kJSModulus:
2303 case IrOpcode::kJSExponentiate:
2304 return ReduceNumberBinop(node);
2305 case IrOpcode::kJSBitwiseNot:
2306 return ReduceJSBitwiseNot(node);
2307 case IrOpcode::kJSDecrement:
2308 return ReduceJSDecrement(node);
2309 case IrOpcode::kJSIncrement:
2310 return ReduceJSIncrement(node);
2311 case IrOpcode::kJSNegate:
2312 return ReduceJSNegate(node);
2313 case IrOpcode::kJSHasInPrototypeChain:
2314 return ReduceJSHasInPrototypeChain(node);
2315 case IrOpcode::kJSOrdinaryHasInstance:
2316 return ReduceJSOrdinaryHasInstance(node);
2317 case IrOpcode::kJSToInteger:
2318 return ReduceJSToInteger(node);
2319 case IrOpcode::kJSToLength:
2320 return ReduceJSToLength(node);
2321 case IrOpcode::kJSToName:
2322 return ReduceJSToName(node);
2323 case IrOpcode::kJSToNumber:
2324 case IrOpcode::kJSToNumberConvertBigInt:
2325 case IrOpcode::kJSToNumeric:
2326 return ReduceJSToNumberOrNumeric(node);
2327 case IrOpcode::kJSToString:
2328 return ReduceJSToString(node);
2329 case IrOpcode::kJSToObject:
2330 return ReduceJSToObject(node);
2331 case IrOpcode::kJSLoadNamed:
2332 return ReduceJSLoadNamed(node);
2333 case IrOpcode::kJSLoadContext:
2334 return ReduceJSLoadContext(node);
2335 case IrOpcode::kJSStoreContext:
2336 return ReduceJSStoreContext(node);
2337 case IrOpcode::kJSLoadModule:
2338 return ReduceJSLoadModule(node);
2339 case IrOpcode::kJSStoreModule:
2340 return ReduceJSStoreModule(node);
2341 case IrOpcode::kJSConstructForwardVarargs:
2342 return ReduceJSConstructForwardVarargs(node);
2343 case IrOpcode::kJSConstruct:
2344 return ReduceJSConstruct(node);
2345 case IrOpcode::kJSCallForwardVarargs:
2346 return ReduceJSCallForwardVarargs(node);
2347 case IrOpcode::kJSCall:
2348 return ReduceJSCall(node);
2349 case IrOpcode::kJSForInPrepare:
2350 return ReduceJSForInPrepare(node);
2351 case IrOpcode::kJSForInNext:
2352 return ReduceJSForInNext(node);
2353 case IrOpcode::kJSLoadMessage:
2354 return ReduceJSLoadMessage(node);
2355 case IrOpcode::kJSStoreMessage:
2356 return ReduceJSStoreMessage(node);
2357 case IrOpcode::kJSGeneratorStore:
2358 return ReduceJSGeneratorStore(node);
2359 case IrOpcode::kJSGeneratorRestoreContinuation:
2360 return ReduceJSGeneratorRestoreContinuation(node);
2361 case IrOpcode::kJSGeneratorRestoreContext:
2362 return ReduceJSGeneratorRestoreContext(node);
2363 case IrOpcode::kJSGeneratorRestoreRegister:
2364 return ReduceJSGeneratorRestoreRegister(node);
2365 case IrOpcode::kJSGeneratorRestoreInputOrDebugPos:
2366 return ReduceJSGeneratorRestoreInputOrDebugPos(node);
2367 // TODO(mstarzinger): Simplified operations hiding in JS-level reducer not
2368 // fooling anyone. Consider moving this into a separate reducer.
2369 case IrOpcode::kSpeculativeNumberAdd:
2370 return ReduceSpeculativeNumberAdd(node);
2371 case IrOpcode::kSpeculativeNumberSubtract:
2372 case IrOpcode::kSpeculativeNumberMultiply:
2373 case IrOpcode::kSpeculativeNumberDivide:
2374 case IrOpcode::kSpeculativeNumberModulus:
2375 return ReduceSpeculativeNumberBinop(node);
2376 case IrOpcode::kSpeculativeNumberEqual:
2377 case IrOpcode::kSpeculativeNumberLessThan:
2378 case IrOpcode::kSpeculativeNumberLessThanOrEqual:
2379 return ReduceSpeculativeNumberComparison(node);
2380 case IrOpcode::kJSObjectIsArray:
2381 return ReduceObjectIsArray(node);
2382 case IrOpcode::kJSParseInt:
2383 return ReduceJSParseInt(node);
2384 default:
2385 break;
2386 }
2387 return NoChange();
2388 }
2389
2390
factory() const2391 Factory* JSTypedLowering::factory() const { return jsgraph()->factory(); }
2392
2393
graph() const2394 Graph* JSTypedLowering::graph() const { return jsgraph()->graph(); }
2395
2396
isolate() const2397 Isolate* JSTypedLowering::isolate() const { return jsgraph()->isolate(); }
2398
2399
javascript() const2400 JSOperatorBuilder* JSTypedLowering::javascript() const {
2401 return jsgraph()->javascript();
2402 }
2403
2404
common() const2405 CommonOperatorBuilder* JSTypedLowering::common() const {
2406 return jsgraph()->common();
2407 }
2408
simplified() const2409 SimplifiedOperatorBuilder* JSTypedLowering::simplified() const {
2410 return jsgraph()->simplified();
2411 }
2412
2413 } // namespace compiler
2414 } // namespace internal
2415 } // namespace v8
2416