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