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 358517 : : lowering_(lowering), node_(node) {}
35 :
36 115917 : bool GetCompareNumberOperationHint(NumberOperationHint* hint) {
37 : DCHECK_EQ(1, node_->op()->EffectOutputCount());
38 115917 : switch (CompareOperationHintOf(node_->op())) {
39 : case CompareOperationHint::kSignedSmall:
40 6275 : *hint = NumberOperationHint::kSignedSmall;
41 : return true;
42 : case CompareOperationHint::kNumber:
43 8726 : *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 140005 : bool IsInternalizedStringCompareOperation() {
62 : DCHECK_EQ(1, node_->op()->EffectOutputCount());
63 140005 : return (CompareOperationHintOf(node_->op()) ==
64 143809 : CompareOperationHint::kInternalizedString) &&
65 143809 : BothInputsMaybe(Type::InternalizedString());
66 : }
67 :
68 102569 : bool IsReceiverCompareOperation() {
69 : DCHECK_EQ(1, node_->op()->EffectOutputCount());
70 102569 : return (CompareOperationHintOf(node_->op()) ==
71 103361 : CompareOperationHint::kReceiver) &&
72 103361 : BothInputsMaybe(Type::Receiver());
73 : }
74 :
75 101777 : bool IsReceiverOrNullOrUndefinedCompareOperation() {
76 : DCHECK_EQ(1, node_->op()->EffectOutputCount());
77 101777 : return (CompareOperationHintOf(node_->op()) ==
78 101828 : CompareOperationHint::kReceiverOrNullOrUndefined) &&
79 101828 : BothInputsMaybe(Type::ReceiverOrNullOrUndefined());
80 : }
81 :
82 126856 : bool IsStringCompareOperation() {
83 : DCHECK_EQ(1, node_->op()->EffectOutputCount());
84 126856 : return (CompareOperationHintOf(node_->op()) ==
85 134005 : CompareOperationHint::kString) &&
86 134005 : BothInputsMaybe(Type::String());
87 : }
88 :
89 94844 : bool IsSymbolCompareOperation() {
90 : DCHECK_EQ(1, node_->op()->EffectOutputCount());
91 94844 : return (CompareOperationHintOf(node_->op()) ==
92 94868 : CompareOperationHint::kSymbol) &&
93 94868 : BothInputsMaybe(Type::Symbol());
94 : }
95 :
96 : // Inserts a CheckReceiver for the left input.
97 792 : void CheckLeftInputToReceiver() {
98 792 : Node* left_input = graph()->NewNode(simplified()->CheckReceiver(), left(),
99 : effect(), control());
100 792 : node_->ReplaceInput(0, left_input);
101 : update_effect(left_input);
102 792 : }
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 96 : void CheckInputsToReceiver() {
117 192 : if (!left_type().Is(Type::Receiver())) {
118 96 : CheckLeftInputToReceiver();
119 : }
120 192 : 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 96 : }
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 1872 : void CheckInputsToNonEmptyOneByteString() {
171 3744 : if (!left_type().Is(Type::NonEmptyOneByteString())) {
172 : Node* left_input =
173 981 : graph()->NewNode(simplified()->CheckNonEmptyOneByteString(), left(),
174 : effect(), control());
175 981 : node_->ReplaceInput(0, left_input);
176 : update_effect(left_input);
177 : }
178 3744 : if (!right_type().Is(Type::NonEmptyOneByteString())) {
179 : Node* right_input =
180 564 : graph()->NewNode(simplified()->CheckNonEmptyOneByteString(), right(),
181 : effect(), control());
182 564 : node_->ReplaceInput(1, right_input);
183 : update_effect(right_input);
184 : }
185 1872 : }
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 130 : void CheckInputsToNonEmptyTwoByteString() {
191 260 : if (!left_type().Is(Type::NonEmptyTwoByteString())) {
192 : Node* left_input =
193 94 : graph()->NewNode(simplified()->CheckNonEmptyTwoByteString(), left(),
194 : effect(), control());
195 94 : node_->ReplaceInput(0, left_input);
196 : update_effect(left_input);
197 : }
198 260 : if (!right_type().Is(Type::NonEmptyTwoByteString())) {
199 : Node* right_input =
200 122 : graph()->NewNode(simplified()->CheckNonEmptyTwoByteString(), right(),
201 : effect(), control());
202 122 : node_->ReplaceInput(1, right_input);
203 : update_effect(right_input);
204 : }
205 130 : }
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 0 : void CheckInputsToNonEmptyString() {
211 0 : if (!left_type().Is(Type::NonEmptyString())) {
212 0 : Node* left_input = graph()->NewNode(simplified()->CheckNonEmptyString(),
213 : left(), effect(), control());
214 0 : node_->ReplaceInput(0, left_input);
215 : update_effect(left_input);
216 : }
217 0 : 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 0 : }
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 10900 : void CheckInputsToString() {
229 21800 : if (!left_type().Is(Type::String())) {
230 : Node* left_input =
231 15448 : graph()->NewNode(simplified()->CheckString(VectorSlotPair()), left(),
232 : effect(), control());
233 7724 : node_->ReplaceInput(0, left_input);
234 : update_effect(left_input);
235 : }
236 21800 : if (!right_type().Is(Type::String())) {
237 : Node* right_input =
238 4218 : graph()->NewNode(simplified()->CheckString(VectorSlotPair()), right(),
239 : effect(), control());
240 2109 : node_->ReplaceInput(1, right_input);
241 : update_effect(right_input);
242 : }
243 10900 : }
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 3524 : void CheckInputsToInternalizedString() {
249 7048 : if (!left_type().Is(Type::UniqueName())) {
250 3524 : Node* left_input = graph()->NewNode(
251 : simplified()->CheckInternalizedString(), left(), effect(), control());
252 3524 : node_->ReplaceInput(0, left_input);
253 : update_effect(left_input);
254 : }
255 7048 : if (!right_type().Is(Type::UniqueName())) {
256 : Node* right_input =
257 69 : graph()->NewNode(simplified()->CheckInternalizedString(), right(),
258 : effect(), control());
259 69 : node_->ReplaceInput(1, right_input);
260 : update_effect(right_input);
261 : }
262 3524 : }
263 :
264 46504 : void ConvertInputsToNumber() {
265 : DCHECK(left_type().Is(Type::PlainPrimitive()));
266 : DCHECK(right_type().Is(Type::PlainPrimitive()));
267 46504 : node_->ReplaceInput(0, ConvertPlainPrimitiveToNumber(left()));
268 46504 : node_->ReplaceInput(1, ConvertPlainPrimitiveToNumber(right()));
269 46504 : }
270 :
271 17467 : void ConvertInputsToUI32(Signedness left_signedness,
272 : Signedness right_signedness) {
273 17467 : node_->ReplaceInput(0, ConvertToUI32(left(), left_signedness));
274 17467 : node_->ReplaceInput(1, ConvertToUI32(right(), right_signedness));
275 17467 : }
276 :
277 3228 : void SwapInputs() {
278 : Node* l = left();
279 : Node* r = right();
280 3228 : node_->ReplaceInput(0, r);
281 3228 : node_->ReplaceInput(1, l);
282 3228 : }
283 :
284 : // Remove all effect and control inputs and outputs to this node and change
285 : // to the pure operator {op}.
286 104239 : 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 208478 : if (node_->op()->EffectInputCount() > 0) {
294 104239 : lowering_->RelaxEffectsAndControls(node_);
295 : }
296 : // Remove the inputs corresponding to context, effect, and control.
297 104239 : NodeProperties::RemoveNonValueInputs(node_);
298 : // Finally, update the operator to the new one.
299 104239 : 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 104239 : Type node_type = NodeProperties::GetType(node_);
304 104239 : NodeProperties::SetType(node_, Type::Intersect(node_type, type, zone()));
305 :
306 104239 : return lowering_->Changed(node_);
307 : }
308 :
309 15001 : 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 15001 : lowering_->RelaxControls(node_);
326 :
327 : // Remove the frame state and the context.
328 15001 : if (OperatorProperties::HasFrameStateInput(node_->op())) {
329 0 : node_->RemoveInput(NodeProperties::FirstFrameStateIndex(node_));
330 : }
331 30002 : node_->RemoveInput(NodeProperties::FirstContextIndex(node_));
332 :
333 15001 : NodeProperties::ChangeOp(node_, op);
334 :
335 : // Update the type to number.
336 15001 : Type node_type = NodeProperties::GetType(node_);
337 15001 : NodeProperties::SetType(node_,
338 : Type::Intersect(node_type, upper_bound, zone()));
339 :
340 15001 : return lowering_->Changed(node_);
341 : }
342 :
343 39741 : const Operator* NumberOp() {
344 39741 : switch (node_->opcode()) {
345 : case IrOpcode::kJSAdd:
346 11579 : return simplified()->NumberAdd();
347 : case IrOpcode::kJSSubtract:
348 2957 : return simplified()->NumberSubtract();
349 : case IrOpcode::kJSMultiply:
350 2716 : return simplified()->NumberMultiply();
351 : case IrOpcode::kJSDivide:
352 2782 : return simplified()->NumberDivide();
353 : case IrOpcode::kJSModulus:
354 2207 : return simplified()->NumberModulus();
355 : case IrOpcode::kJSExponentiate:
356 33 : return simplified()->NumberPow();
357 : case IrOpcode::kJSBitwiseAnd:
358 2646 : return simplified()->NumberBitwiseAnd();
359 : case IrOpcode::kJSBitwiseOr:
360 2892 : return simplified()->NumberBitwiseOr();
361 : case IrOpcode::kJSBitwiseXor:
362 2754 : return simplified()->NumberBitwiseXor();
363 : case IrOpcode::kJSShiftLeft:
364 3073 : return simplified()->NumberShiftLeft();
365 : case IrOpcode::kJSShiftRight:
366 3042 : return simplified()->NumberShiftRight();
367 : case IrOpcode::kJSShiftRightLogical:
368 3060 : return simplified()->NumberShiftRightLogical();
369 : default:
370 : break;
371 : }
372 0 : UNREACHABLE();
373 : }
374 :
375 4524108 : bool LeftInputIs(Type t) { return left_type().Is(t); }
376 :
377 1491186 : bool RightInputIs(Type t) { return right_type().Is(t); }
378 :
379 191259 : bool OneInputIs(Type t) { return LeftInputIs(t) || RightInputIs(t); }
380 :
381 1186573 : bool BothInputsAre(Type t) { return LeftInputIs(t) && RightInputIs(t); }
382 :
383 11820 : bool BothInputsMaybe(Type t) {
384 23640 : return left_type().Maybe(t) && right_type().Maybe(t);
385 : }
386 :
387 171454 : bool OneInputCannotBe(Type t) {
388 324733 : return !left_type().Maybe(t) || !right_type().Maybe(t);
389 : }
390 :
391 48373 : bool NeitherInputCanBe(Type t) {
392 68403 : return !left_type().Maybe(t) && !right_type().Maybe(t);
393 : }
394 :
395 16190 : Node* effect() { return NodeProperties::GetEffectInput(node_); }
396 16190 : Node* control() { return NodeProperties::GetControlInput(node_); }
397 : Node* context() { return NodeProperties::GetContextInput(node_); }
398 285482 : Node* left() { return NodeProperties::GetValueInput(node_, 0); }
399 306151 : 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 93008 : Node* ConvertPlainPrimitiveToNumber(Node* node) {
417 : DCHECK(NodeProperties::GetType(node).Is(Type::PlainPrimitive()));
418 : // Avoid inserting too many eager ToNumber() operations.
419 93008 : Reduction const reduction = lowering_->ReduceJSToNumberInput(node);
420 93008 : 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 34934 : Node* ConvertToUI32(Node* node, Signedness signedness) {
428 : // Avoid introducing too many eager NumberToXXnt32() operations.
429 34934 : Type type = NodeProperties::GetType(node);
430 34934 : if (signedness == kSigned) {
431 22699 : if (!type.Is(Type::Signed32())) {
432 12162 : node = graph()->NewNode(simplified()->NumberToInt32(), node);
433 : }
434 : } else {
435 : DCHECK_EQ(kUnsigned, signedness);
436 12235 : if (!type.Is(Type::Unsigned32())) {
437 8153 : node = graph()->NewNode(simplified()->NumberToUint32(), node);
438 : }
439 : }
440 34934 : return node;
441 : }
442 :
443 : void update_effect(Node* effect) {
444 16168 : 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 480064 : 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 480064 : graph()->zone())),
463 960130 : 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 2167 : Reduction JSTypedLowering::ReduceJSDecrement(Node* node) {
481 2167 : Node* input = NodeProperties::GetValueInput(node, 0);
482 2167 : Type input_type = NodeProperties::GetType(input);
483 2167 : 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 18981 : Reduction JSTypedLowering::ReduceJSIncrement(Node* node) {
496 18981 : Node* input = NodeProperties::GetValueInput(node, 0);
497 18981 : Type input_type = NodeProperties::GetType(input);
498 18981 : if (input_type.Is(Type::PlainPrimitive())) {
499 : // JSIncrement(x) => NumberAdd(ToNumber(x), 1)
500 11579 : node->InsertInput(graph()->zone(), 1, jsgraph()->OneConstant());
501 : BinaryOperationHint hint = BinaryOperationHint::kAny; // Dummy.
502 11579 : NodeProperties::ChangeOp(node, javascript()->Add(hint));
503 : JSBinopReduction r(this, node);
504 11579 : r.ConvertInputsToNumber();
505 : DCHECK_EQ(simplified()->NumberAdd(), r.NumberOp());
506 11579 : return r.ChangeToPureOperator(r.NumberOp(), Type::Number());
507 : }
508 : return NoChange();
509 : }
510 :
511 4043 : Reduction JSTypedLowering::ReduceJSNegate(Node* node) {
512 4043 : Node* input = NodeProperties::GetValueInput(node, 0);
513 4043 : Type input_type = NodeProperties::GetType(input);
514 4043 : 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 87237 : Reduction JSTypedLowering::ReduceJSAdd(Node* node) {
526 : JSBinopReduction r(this, node);
527 87237 : if (r.BothInputsAre(Type::Number())) {
528 : // JSAdd(x:number, y:number) => NumberAdd(x, y)
529 13223 : return r.ChangeToPureOperator(simplified()->NumberAdd(), Type::Number());
530 : }
531 96065 : if (r.BothInputsAre(Type::PlainPrimitive()) &&
532 22051 : 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 73997 : if (r.LeftInputIs(Type::String())) {
540 : // JSAdd(x:string, y) => JSAdd(x, JSToString(y))
541 42969 : Reduction const reduction = ReduceJSToStringInput(r.right());
542 42969 : if (reduction.Changed()) {
543 21766 : NodeProperties::ReplaceValueInput(node, reduction.replacement(), 1);
544 : }
545 31028 : } else if (r.RightInputIs(Type::String())) {
546 : // JSAdd(x, y:string) => JSAdd(JSToString(x), y)
547 7690 : Reduction const reduction = ReduceJSToStringInput(r.left());
548 7690 : if (reduction.Changed()) {
549 183 : NodeProperties::ReplaceValueInput(node, reduction.replacement(), 0);
550 : }
551 : }
552 :
553 : // Always bake in String feedback into the graph.
554 73997 : BinaryOperationHint const hint = BinaryOperationHintOf(node->op());
555 73997 : if (hint == BinaryOperationHint::kConsOneByteString) {
556 1872 : r.CheckInputsToNonEmptyOneByteString();
557 72125 : } else if (hint == BinaryOperationHint::kConsTwoByteString) {
558 130 : r.CheckInputsToNonEmptyTwoByteString();
559 71995 : } else if (hint == BinaryOperationHint::kConsString) {
560 0 : r.CheckInputsToNonEmptyString();
561 71995 : } else if (hint == BinaryOperationHint::kString) {
562 3755 : 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 73997 : if (r.BothInputsAre(Type::Primitive())) {
572 29839 : if (r.LeftInputIs(Type::EmptyString())) {
573 : // JSAdd("", x:primitive) => JSToString(x)
574 160 : NodeProperties::ReplaceValueInputs(node, r.right());
575 160 : NodeProperties::ChangeOp(node, javascript()->ToString());
576 160 : NodeProperties::SetType(
577 : node, Type::Intersect(r.type(), Type::String(), graph()->zone()));
578 160 : Reduction const reduction = ReduceJSToString(node);
579 160 : return reduction.Changed() ? reduction : Changed(node);
580 29679 : } else if (r.RightInputIs(Type::EmptyString())) {
581 : // JSAdd(x:primitive, "") => JSToString(x)
582 105 : NodeProperties::ReplaceValueInputs(node, r.left());
583 105 : NodeProperties::ChangeOp(node, javascript()->ToString());
584 105 : NodeProperties::SetType(
585 : node, Type::Intersect(r.type(), Type::String(), graph()->zone()));
586 105 : Reduction const reduction = ReduceJSToString(node);
587 105 : return reduction.Changed() ? reduction : Changed(node);
588 : }
589 : }
590 :
591 : // Lower to string addition if both inputs are known to be strings.
592 73732 : if (r.BothInputsAre(Type::String())) {
593 24388 : Node* context = NodeProperties::GetContextInput(node);
594 24388 : Node* frame_state = NodeProperties::GetFrameStateInput(node);
595 24388 : Node* effect = NodeProperties::GetEffectInput(node);
596 24388 : Node* control = NodeProperties::GetControlInput(node);
597 :
598 : // Compute the resulting length.
599 : Node* left_length =
600 24388 : graph()->NewNode(simplified()->StringLength(), r.left());
601 : Node* right_length =
602 24388 : graph()->NewNode(simplified()->StringLength(), r.right());
603 : Node* length =
604 24388 : graph()->NewNode(simplified()->NumberAdd(), left_length, right_length);
605 :
606 : CellRef string_length_protector(broker(),
607 : factory()->string_length_protector());
608 24388 : 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 48364 : 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 206 : graph()->NewNode(simplified()->NumberLessThanOrEqual(), length,
621 : jsgraph()->Constant(String::kMaxLength));
622 : Node* branch =
623 206 : graph()->NewNode(common()->Branch(BranchHint::kTrue), check, control);
624 206 : Node* if_false = graph()->NewNode(common()->IfFalse(), branch);
625 : Node* efalse = effect;
626 : {
627 : // Throw a RangeError in case of overflow.
628 206 : 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 206 : Node* on_exception = nullptr;
635 206 : if (NodeProperties::IsExceptionalCall(node, &on_exception)) {
636 29 : NodeProperties::ReplaceControlInput(on_exception, vfalse);
637 29 : NodeProperties::ReplaceEffectInput(on_exception, efalse);
638 29 : if_false = graph()->NewNode(common()->IfSuccess(), vfalse);
639 29 : 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 206 : if_false = graph()->NewNode(common()->Throw(), efalse, if_false);
646 : // TODO(bmeurer): This should be on the AdvancedReducer somehow.
647 206 : NodeProperties::MergeControlToEnd(graph(), common(), if_false);
648 : Revisit(graph()->end());
649 : }
650 206 : control = graph()->NewNode(common()->IfTrue(), branch);
651 : length = effect =
652 206 : graph()->NewNode(common()->TypeGuard(type_cache_->kStringLengthType),
653 : length, effect, control);
654 : }
655 :
656 48776 : if (hint == BinaryOperationHint::kConsString ||
657 46904 : hint == BinaryOperationHint::kConsOneByteString ||
658 : hint == BinaryOperationHint::kConsTwoByteString) {
659 1930 : Node* check = graph()->NewNode(
660 : simplified()->NumberLessThan(),
661 : jsgraph()->Constant(ConsString::kMinLength - 1), length);
662 3860 : effect = graph()->NewNode(
663 : simplified()->CheckIf(DeoptimizeReason::kWrongLength), check, effect,
664 : control);
665 1930 : length = effect = graph()->NewNode(
666 1930 : common()->TypeGuard(type_cache_->kConsStringLengthType), length,
667 : effect, control);
668 : }
669 :
670 24388 : 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 49344 : if (r.OneInputIs(Type::String())) {
682 : StringAddFlags flags = STRING_ADD_CHECK_NONE;
683 26322 : if (!r.LeftInputIs(Type::String())) {
684 : flags = STRING_ADD_CONVERT_LEFT;
685 19781 : } else if (!r.RightInputIs(Type::String())) {
686 : flags = STRING_ADD_CONVERT_RIGHT;
687 : }
688 26322 : Operator::Properties properties = node->op()->properties();
689 26322 : 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 176 : 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 26322 : Callable const callable = CodeFactory::StringAdd(isolate(), flags);
699 26322 : auto call_descriptor = Linkage::GetStubCallDescriptor(
700 26322 : graph()->zone(), callable.descriptor(),
701 : callable.descriptor().GetStackParameterCount(),
702 26322 : CallDescriptor::kNeedsFrameState, properties);
703 : DCHECK_EQ(1, OperatorProperties::GetFrameStateInputCount(node->op()));
704 52644 : node->InsertInput(graph()->zone(), 0,
705 26322 : jsgraph()->HeapConstant(callable.code()));
706 26322 : NodeProperties::ChangeOp(node, common()->Call(call_descriptor));
707 : return Changed(node);
708 : }
709 : return NoChange();
710 : }
711 :
712 32820 : Reduction JSTypedLowering::ReduceNumberBinop(Node* node) {
713 : JSBinopReduction r(this, node);
714 32820 : if (r.BothInputsAre(Type::PlainPrimitive())) {
715 10153 : r.ConvertInputsToNumber();
716 10153 : return r.ChangeToPureOperator(r.NumberOp(), Type::Number());
717 : }
718 : return NoChange();
719 : }
720 :
721 23143 : Reduction JSTypedLowering::ReduceInt32Binop(Node* node) {
722 : JSBinopReduction r(this, node);
723 23143 : if (r.BothInputsAre(Type::PlainPrimitive())) {
724 8258 : r.ConvertInputsToNumber();
725 8258 : r.ConvertInputsToUI32(kSigned, kSigned);
726 8258 : return r.ChangeToPureOperator(r.NumberOp(), Type::Signed32());
727 : }
728 : return NoChange();
729 : }
730 :
731 11724 : Reduction JSTypedLowering::ReduceUI32Shift(Node* node, Signedness signedness) {
732 : JSBinopReduction r(this, node);
733 11724 : if (r.BothInputsAre(Type::PlainPrimitive())) {
734 9175 : r.ConvertInputsToNumber();
735 9175 : r.ConvertInputsToUI32(signedness, kUnsigned);
736 : return r.ChangeToPureOperator(r.NumberOp(), signedness == kUnsigned
737 : ? Type::Unsigned32()
738 9175 : : Type::Signed32());
739 : }
740 : return NoChange();
741 : }
742 :
743 34082 : Reduction JSTypedLowering::ReduceJSComparison(Node* node) {
744 : JSBinopReduction r(this, node);
745 34082 : 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 65226 : if (r.BothInputsAre(Type::Signed32()) ||
773 32017 : r.BothInputsAre(Type::Unsigned32())) {
774 1334 : less_than = simplified()->NumberLessThan();
775 1334 : less_than_or_equal = simplified()->NumberLessThanOrEqual();
776 61701 : } else if (r.OneInputCannotBe(Type::StringOrReceiver()) &&
777 29826 : r.BothInputsAre(Type::PlainPrimitive())) {
778 6746 : r.ConvertInputsToNumber();
779 6746 : less_than = simplified()->NumberLessThan();
780 6746 : less_than_or_equal = simplified()->NumberLessThanOrEqual();
781 25129 : } else if (r.IsStringCompareOperation()) {
782 262 : r.CheckInputsToString();
783 262 : less_than = simplified()->StringLessThan();
784 262 : less_than_or_equal = simplified()->StringLessThanOrEqual();
785 : } else {
786 : return NoChange();
787 : }
788 : const Operator* comparison;
789 8342 : 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 1382 : break;
800 : case IrOpcode::kJSGreaterThanOrEqual:
801 : comparison = less_than_or_equal;
802 1341 : r.SwapInputs(); // a >= b => b <= a
803 1341 : break;
804 : default:
805 : return NoChange();
806 : }
807 8342 : return r.ChangeToPureOperator(comparison);
808 : }
809 :
810 13314 : Reduction JSTypedLowering::ReduceJSEqual(Node* node) {
811 : JSBinopReduction r(this, node);
812 :
813 13314 : if (r.BothInputsAre(Type::UniqueName())) {
814 893 : return r.ChangeToPureOperator(simplified()->ReferenceEqual());
815 : }
816 12421 : if (r.IsInternalizedStringCompareOperation()) {
817 59 : r.CheckInputsToInternalizedString();
818 59 : return r.ChangeToPureOperator(simplified()->ReferenceEqual());
819 : }
820 12362 : if (r.BothInputsAre(Type::String())) {
821 78 : return r.ChangeToPureOperator(simplified()->StringEqual());
822 : }
823 12284 : if (r.BothInputsAre(Type::Boolean())) {
824 38 : return r.ChangeToPureOperator(simplified()->ReferenceEqual());
825 : }
826 12246 : if (r.BothInputsAre(Type::Receiver())) {
827 21 : return r.ChangeToPureOperator(simplified()->ReferenceEqual());
828 : }
829 12225 : if (r.OneInputIs(Type::Undetectable())) {
830 : RelaxEffectsAndControls(node);
831 46 : node->RemoveInput(r.LeftInputIs(Type::Undetectable()) ? 0 : 1);
832 46 : node->TrimInputCount(1);
833 46 : NodeProperties::ChangeOp(node, simplified()->ObjectIsUndetectable());
834 : return Changed(node);
835 : }
836 :
837 21201 : if (r.BothInputsAre(Type::Signed32()) ||
838 9022 : r.BothInputsAre(Type::Unsigned32())) {
839 3203 : return r.ChangeToPureOperator(simplified()->NumberEqual());
840 8976 : } else if (r.BothInputsAre(Type::Number())) {
841 585 : return r.ChangeToPureOperator(simplified()->NumberEqual());
842 8391 : } else if (r.IsReceiverCompareOperation()) {
843 96 : r.CheckInputsToReceiver();
844 96 : return r.ChangeToPureOperator(simplified()->ReferenceEqual());
845 8295 : } 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 8257 : } else if (r.IsStringCompareOperation()) {
886 27 : r.CheckInputsToString();
887 27 : return r.ChangeToPureOperator(simplified()->StringEqual());
888 8230 : } else if (r.IsSymbolCompareOperation()) {
889 16 : r.CheckInputsToSymbol();
890 16 : return r.ChangeToPureOperator(simplified()->ReferenceEqual());
891 : }
892 : return NoChange();
893 : }
894 :
895 144042 : Reduction JSTypedLowering::ReduceJSStrictEqual(Node* node) {
896 : JSBinopReduction r(this, node);
897 144042 : if (r.left() == r.right()) {
898 : // x === x is always true if x != NaN
899 8926 : Node* replacement = graph()->NewNode(
900 : simplified()->BooleanNot(),
901 : graph()->NewNode(simplified()->ObjectIsNaN(), r.left()));
902 : ReplaceWithValue(node, replacement);
903 : return Replace(replacement);
904 : }
905 139579 : 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 5857 : if (!r.left_type().Maybe(r.right_type())) {
910 961 : Node* replacement = jsgraph()->FalseConstant();
911 : ReplaceWithValue(node, replacement);
912 : return Replace(replacement);
913 : }
914 : }
915 :
916 138618 : if (r.BothInputsAre(Type::Unique())) {
917 8966 : return r.ChangeToPureOperator(simplified()->ReferenceEqual());
918 : }
919 129652 : if (r.OneInputIs(pointer_comparable_type_)) {
920 2068 : return r.ChangeToPureOperator(simplified()->ReferenceEqual());
921 : }
922 127584 : if (r.IsInternalizedStringCompareOperation()) {
923 3465 : r.CheckInputsToInternalizedString();
924 3465 : return r.ChangeToPureOperator(simplified()->ReferenceEqual());
925 : }
926 124119 : if (r.BothInputsAre(Type::String())) {
927 3508 : return r.ChangeToPureOperator(simplified()->StringEqual());
928 : }
929 :
930 : NumberOperationHint hint;
931 236736 : if (r.BothInputsAre(Type::Signed32()) ||
932 116125 : r.BothInputsAre(Type::Unsigned32())) {
933 4694 : return r.ChangeToPureOperator(simplified()->NumberEqual());
934 115917 : } else if (r.GetCompareNumberOperationHint(&hint)) {
935 : return r.ChangeToSpeculativeOperator(
936 15001 : simplified()->SpeculativeNumberEqual(hint), Type::Boolean());
937 100916 : } else if (r.BothInputsAre(Type::Number())) {
938 6738 : return r.ChangeToPureOperator(simplified()->NumberEqual());
939 94178 : } 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 696 : r.CheckLeftInputToReceiver();
944 696 : return r.ChangeToPureOperator(simplified()->ReferenceEqual());
945 93482 : } 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 93470 : } else if (r.IsStringCompareOperation()) {
953 6856 : r.CheckInputsToString();
954 6856 : return r.ChangeToPureOperator(simplified()->StringEqual());
955 86614 : } 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 1141 : Reduction JSTypedLowering::ReduceJSToName(Node* node) {
966 1141 : Node* const input = NodeProperties::GetValueInput(node, 0);
967 1141 : Type const input_type = NodeProperties::GetType(input);
968 1141 : 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 105028 : Reduction JSTypedLowering::ReduceJSToNumberInput(Node* input) {
1001 : // Try constant-folding of JSToNumber with constant inputs.
1002 105028 : Type input_type = NodeProperties::GetType(input);
1003 :
1004 105028 : if (input_type.Is(Type::String())) {
1005 : HeapObjectMatcher m(input);
1006 2825 : if (m.HasValue() && m.Ref(broker()).IsString()) {
1007 841 : StringRef input_value = m.Ref(broker()).AsString();
1008 : double number;
1009 841 : ASSIGN_RETURN_NO_CHANGE_IF_DATA_MISSING(number, input_value.ToNumber());
1010 841 : return Replace(jsgraph()->Constant(number));
1011 : }
1012 : }
1013 104187 : 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 103381 : if (input_type.Is(Type::Number())) {
1021 : // JSToNumber(x:number) => x
1022 : return Changed(input);
1023 : }
1024 13006 : if (input_type.Is(Type::Undefined())) {
1025 : // JSToNumber(undefined) => #NaN
1026 820 : return Replace(jsgraph()->NaNConstant());
1027 : }
1028 12186 : if (input_type.Is(Type::Null())) {
1029 : // JSToNumber(null) => #0
1030 820 : return Replace(jsgraph()->ZeroConstant());
1031 : }
1032 : return NoChange();
1033 : }
1034 :
1035 12020 : Reduction JSTypedLowering::ReduceJSToNumber(Node* node) {
1036 : // Try to reduce the input first.
1037 : Node* const input = node->InputAt(0);
1038 12020 : Reduction reduction = ReduceJSToNumberInput(input);
1039 12020 : if (reduction.Changed()) {
1040 : ReplaceWithValue(node, reduction.replacement());
1041 2494 : return reduction;
1042 : }
1043 9526 : Type const input_type = NodeProperties::GetType(input);
1044 9526 : if (input_type.Is(Type::PlainPrimitive())) {
1045 : RelaxEffectsAndControls(node);
1046 355 : node->TrimInputCount(1);
1047 : // For a PlainPrimitive, ToNumeric is the same as ToNumber.
1048 355 : Type node_type = NodeProperties::GetType(node);
1049 355 : NodeProperties::SetType(
1050 : node, Type::Intersect(node_type, Type::Number(), graph()->zone()));
1051 355 : NodeProperties::ChangeOp(node, simplified()->PlainPrimitiveToNumber());
1052 : return Changed(node);
1053 : }
1054 : return NoChange();
1055 : }
1056 :
1057 4503 : Reduction JSTypedLowering::ReduceJSToNumeric(Node* node) {
1058 4503 : Node* const input = NodeProperties::GetValueInput(node, 0);
1059 4503 : Type const input_type = NodeProperties::GetType(input);
1060 4503 : if (input_type.Is(Type::NonBigIntPrimitive())) {
1061 : // ToNumeric(x:primitive\bigint) => ToNumber(x)
1062 2219 : NodeProperties::ChangeOp(node, javascript()->ToNumber());
1063 2219 : Reduction const reduction = ReduceJSToNumber(node);
1064 2219 : return reduction.Changed() ? reduction : Changed(node);
1065 : }
1066 : return NoChange();
1067 : }
1068 :
1069 54597 : Reduction JSTypedLowering::ReduceJSToStringInput(Node* input) {
1070 54597 : if (input->opcode() == IrOpcode::kJSToString) {
1071 : // Recursively try to reduce the input first.
1072 1494 : Reduction result = ReduceJSToString(input);
1073 1494 : if (result.Changed()) return result;
1074 : return Changed(input); // JSToString(JSToString(x)) => JSToString(x)
1075 : }
1076 53103 : Type input_type = NodeProperties::GetType(input);
1077 53103 : if (input_type.Is(Type::String())) {
1078 : return Changed(input); // JSToString(x:string) => x
1079 : }
1080 33596 : if (input_type.Is(Type::Boolean())) {
1081 : return Replace(graph()->NewNode(
1082 : common()->Select(MachineRepresentation::kTagged), input,
1083 : jsgraph()->HeapConstant(factory()->true_string()),
1084 228 : jsgraph()->HeapConstant(factory()->false_string())));
1085 : }
1086 33520 : if (input_type.Is(Type::Undefined())) {
1087 69 : return Replace(jsgraph()->HeapConstant(factory()->undefined_string()));
1088 : }
1089 33451 : if (input_type.Is(Type::Null())) {
1090 14 : return Replace(jsgraph()->HeapConstant(factory()->null_string()));
1091 : }
1092 33437 : if (input_type.Is(Type::NaN())) {
1093 2 : return Replace(jsgraph()->HeapConstant(factory()->NaN_string()));
1094 : }
1095 33435 : if (input_type.Is(Type::Number())) {
1096 1147 : return Replace(graph()->NewNode(simplified()->NumberToString(), input));
1097 : }
1098 : return NoChange();
1099 : }
1100 :
1101 3938 : 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 3938 : Reduction reduction = ReduceJSToStringInput(input);
1106 3938 : if (reduction.Changed()) {
1107 : ReplaceWithValue(node, reduction.replacement());
1108 360 : return reduction;
1109 : }
1110 : return NoChange();
1111 : }
1112 :
1113 1916 : Reduction JSTypedLowering::ReduceJSToObject(Node* node) {
1114 : DCHECK_EQ(IrOpcode::kJSToObject, node->opcode());
1115 1916 : Node* receiver = NodeProperties::GetValueInput(node, 0);
1116 1916 : Type receiver_type = NodeProperties::GetType(receiver);
1117 1916 : Node* context = NodeProperties::GetContextInput(node);
1118 1916 : Node* frame_state = NodeProperties::GetFrameStateInput(node);
1119 1916 : Node* effect = NodeProperties::GetEffectInput(node);
1120 1916 : Node* control = NodeProperties::GetControlInput(node);
1121 1916 : 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 1471 : Node* check = graph()->NewNode(simplified()->ObjectIsReceiver(), receiver);
1128 : Node* branch =
1129 1471 : graph()->NewNode(common()->Branch(BranchHint::kTrue), check, control);
1130 :
1131 1471 : Node* if_true = graph()->NewNode(common()->IfTrue(), branch);
1132 : Node* etrue = effect;
1133 : Node* rtrue = receiver;
1134 :
1135 1471 : Node* if_false = graph()->NewNode(common()->IfFalse(), branch);
1136 : Node* efalse = effect;
1137 : Node* rfalse;
1138 : {
1139 : // Convert {receiver} using the ToObjectStub.
1140 1471 : Callable callable = Builtins::CallableFor(isolate(), Builtins::kToObject);
1141 1471 : auto call_descriptor = Linkage::GetStubCallDescriptor(
1142 1471 : graph()->zone(), callable.descriptor(),
1143 : callable.descriptor().GetStackParameterCount(),
1144 1471 : CallDescriptor::kNeedsFrameState, node->op()->properties());
1145 : rfalse = efalse = if_false =
1146 2942 : 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 1471 : Node* on_exception = nullptr;
1155 2864 : if (receiver_type.Maybe(Type::NullOrUndefined()) &&
1156 1393 : NodeProperties::IsExceptionalCall(node, &on_exception)) {
1157 202 : NodeProperties::ReplaceControlInput(on_exception, if_false);
1158 202 : NodeProperties::ReplaceEffectInput(on_exception, efalse);
1159 202 : if_false = graph()->NewNode(common()->IfSuccess(), if_false);
1160 202 : Revisit(on_exception);
1161 : }
1162 :
1163 1471 : control = graph()->NewNode(common()->Merge(2), if_true, if_false);
1164 1471 : 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 1471 : node->ReplaceInput(0, rtrue);
1169 1471 : node->ReplaceInput(1, rfalse);
1170 1471 : node->ReplaceInput(2, control);
1171 1471 : node->TrimInputCount(3);
1172 1471 : NodeProperties::ChangeOp(node,
1173 1471 : common()->Phi(MachineRepresentation::kTagged, 2));
1174 : return Changed(node);
1175 : }
1176 :
1177 419802 : Reduction JSTypedLowering::ReduceJSLoadNamed(Node* node) {
1178 : DCHECK_EQ(IrOpcode::kJSLoadNamed, node->opcode());
1179 419802 : Node* receiver = NodeProperties::GetValueInput(node, 0);
1180 419802 : Type receiver_type = NodeProperties::GetType(receiver);
1181 419802 : NameRef name(broker(), NamedAccessOf(node->op()).name());
1182 : NameRef length_str(broker(), factory()->length_string());
1183 : // Optimize "length" property of strings.
1184 453665 : 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 763 : Reduction JSTypedLowering::ReduceJSHasInPrototypeChain(Node* node) {
1193 : DCHECK_EQ(IrOpcode::kJSHasInPrototypeChain, node->opcode());
1194 763 : Node* value = NodeProperties::GetValueInput(node, 0);
1195 763 : Type value_type = NodeProperties::GetType(value);
1196 763 : Node* prototype = NodeProperties::GetValueInput(node, 1);
1197 763 : Node* context = NodeProperties::GetContextInput(node);
1198 763 : Node* frame_state = NodeProperties::GetFrameStateInput(node);
1199 763 : Node* effect = NodeProperties::GetEffectInput(node);
1200 763 : 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 763 : if (value_type.Is(Type::Primitive())) {
1205 150 : Node* value = jsgraph()->FalseConstant();
1206 : ReplaceWithValue(node, value, effect, control);
1207 : return Replace(value);
1208 : }
1209 :
1210 613 : Node* check0 = graph()->NewNode(simplified()->ObjectIsSmi(), value);
1211 : Node* branch0 =
1212 613 : graph()->NewNode(common()->Branch(BranchHint::kFalse), check0, control);
1213 :
1214 613 : Node* if_true0 = graph()->NewNode(common()->IfTrue(), branch0);
1215 : Node* etrue0 = effect;
1216 613 : Node* vtrue0 = jsgraph()->FalseConstant();
1217 :
1218 613 : control = graph()->NewNode(common()->IfFalse(), branch0);
1219 :
1220 : // Loop through the {value}s prototype chain looking for the {prototype}.
1221 613 : Node* loop = control = graph()->NewNode(common()->Loop(2), control, control);
1222 : Node* eloop = effect =
1223 613 : graph()->NewNode(common()->EffectPhi(2), effect, effect, loop);
1224 613 : Node* terminate = graph()->NewNode(common()->Terminate(), eloop, loop);
1225 613 : NodeProperties::MergeControlToEnd(graph(), common(), terminate);
1226 613 : 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 613 : Node* value_map = effect = graph()->NewNode(
1232 1226 : simplified()->LoadField(AccessBuilder::ForMap()), value, effect, control);
1233 613 : Node* value_instance_type = effect = graph()->NewNode(
1234 1226 : 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 613 : Node* check1 = graph()->NewNode(
1241 : simplified()->NumberLessThanOrEqual(), value_instance_type,
1242 : jsgraph()->Constant(LAST_SPECIAL_RECEIVER_TYPE));
1243 : Node* branch1 =
1244 613 : graph()->NewNode(common()->Branch(BranchHint::kFalse), check1, control);
1245 :
1246 613 : control = graph()->NewNode(common()->IfFalse(), branch1);
1247 :
1248 613 : 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 613 : graph()->NewNode(simplified()->NumberLessThan(), value_instance_type,
1255 : jsgraph()->Constant(FIRST_JS_RECEIVER_TYPE));
1256 : Node* branch10 =
1257 613 : graph()->NewNode(common()->Branch(BranchHint::kTrue), check10, if_true1);
1258 :
1259 : // A primitive value cannot match the {prototype} we're looking for.
1260 613 : if_true1 = graph()->NewNode(common()->IfTrue(), branch10);
1261 613 : vtrue1 = jsgraph()->FalseConstant();
1262 :
1263 613 : 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 613 : 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 613 : Node* on_exception = nullptr;
1275 613 : if (NodeProperties::IsExceptionalCall(node, &on_exception)) {
1276 31 : NodeProperties::ReplaceControlInput(on_exception, vfalse1);
1277 31 : NodeProperties::ReplaceEffectInput(on_exception, efalse1);
1278 31 : if_false1 = graph()->NewNode(common()->IfSuccess(), vfalse1);
1279 31 : Revisit(on_exception);
1280 : }
1281 : }
1282 :
1283 : // Load the {value} prototype.
1284 613 : Node* value_prototype = effect = graph()->NewNode(
1285 1226 : simplified()->LoadField(AccessBuilder::ForMapPrototype()), value_map,
1286 : effect, control);
1287 :
1288 : // Check if we reached the end of {value}s prototype chain.
1289 613 : Node* check2 = graph()->NewNode(simplified()->ReferenceEqual(),
1290 : value_prototype, jsgraph()->NullConstant());
1291 613 : Node* branch2 = graph()->NewNode(common()->Branch(), check2, control);
1292 :
1293 613 : Node* if_true2 = graph()->NewNode(common()->IfTrue(), branch2);
1294 : Node* etrue2 = effect;
1295 613 : Node* vtrue2 = jsgraph()->FalseConstant();
1296 :
1297 613 : control = graph()->NewNode(common()->IfFalse(), branch2);
1298 :
1299 : // Check if we reached the {prototype}.
1300 613 : Node* check3 = graph()->NewNode(simplified()->ReferenceEqual(),
1301 : value_prototype, prototype);
1302 613 : Node* branch3 = graph()->NewNode(common()->Branch(), check3, control);
1303 :
1304 613 : Node* if_true3 = graph()->NewNode(common()->IfTrue(), branch3);
1305 : Node* etrue3 = effect;
1306 613 : Node* vtrue3 = jsgraph()->TrueConstant();
1307 :
1308 613 : control = graph()->NewNode(common()->IfFalse(), branch3);
1309 :
1310 : // Close the loop.
1311 613 : vloop->ReplaceInput(1, value_prototype);
1312 613 : eloop->ReplaceInput(1, effect);
1313 613 : loop->ReplaceInput(1, control);
1314 :
1315 613 : control = graph()->NewNode(common()->Merge(5), if_true0, if_true1, if_true2,
1316 : if_true3, if_false1);
1317 613 : 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 613 : node->ReplaceInput(0, vtrue0);
1323 613 : node->ReplaceInput(1, vtrue1);
1324 613 : node->ReplaceInput(2, vtrue2);
1325 613 : node->ReplaceInput(3, vtrue3);
1326 613 : node->ReplaceInput(4, vfalse1);
1327 613 : node->ReplaceInput(5, control);
1328 613 : node->TrimInputCount(6);
1329 613 : NodeProperties::ChangeOp(node,
1330 613 : common()->Phi(MachineRepresentation::kTagged, 5));
1331 : return Changed(node);
1332 : }
1333 :
1334 157 : Reduction JSTypedLowering::ReduceJSOrdinaryHasInstance(Node* node) {
1335 : DCHECK_EQ(IrOpcode::kJSOrdinaryHasInstance, node->opcode());
1336 157 : Node* constructor = NodeProperties::GetValueInput(node, 0);
1337 157 : Type constructor_type = NodeProperties::GetType(constructor);
1338 157 : Node* object = NodeProperties::GetValueInput(node, 1);
1339 157 : 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 157 : 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 171 : 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 299061 : Reduction JSTypedLowering::ReduceJSLoadContext(Node* node) {
1363 : DCHECK_EQ(IrOpcode::kJSLoadContext, node->opcode());
1364 299061 : ContextAccess const& access = ContextAccessOf(node->op());
1365 299061 : Node* effect = NodeProperties::GetEffectInput(node);
1366 299061 : Node* context = NodeProperties::GetContextInput(node);
1367 : Node* control = graph()->start();
1368 313967 : for (size_t i = 0; i < access.depth(); ++i) {
1369 7453 : context = effect = graph()->NewNode(
1370 : simplified()->LoadField(
1371 14906 : AccessBuilder::ForContextSlot(Context::PREVIOUS_INDEX)),
1372 : context, effect, control);
1373 : }
1374 299061 : node->ReplaceInput(0, context);
1375 299061 : node->ReplaceInput(1, effect);
1376 299061 : node->AppendInput(jsgraph()->zone(), control);
1377 299061 : NodeProperties::ChangeOp(
1378 : node,
1379 598122 : simplified()->LoadField(AccessBuilder::ForContextSlot(access.index())));
1380 299061 : return Changed(node);
1381 : }
1382 :
1383 442842 : Reduction JSTypedLowering::ReduceJSStoreContext(Node* node) {
1384 : DCHECK_EQ(IrOpcode::kJSStoreContext, node->opcode());
1385 442842 : ContextAccess const& access = ContextAccessOf(node->op());
1386 442842 : Node* effect = NodeProperties::GetEffectInput(node);
1387 442842 : Node* context = NodeProperties::GetContextInput(node);
1388 : Node* control = graph()->start();
1389 442842 : Node* value = NodeProperties::GetValueInput(node, 0);
1390 443256 : for (size_t i = 0; i < access.depth(); ++i) {
1391 207 : context = effect = graph()->NewNode(
1392 : simplified()->LoadField(
1393 414 : AccessBuilder::ForContextSlot(Context::PREVIOUS_INDEX)),
1394 : context, effect, control);
1395 : }
1396 442842 : node->ReplaceInput(0, context);
1397 442842 : node->ReplaceInput(1, value);
1398 442842 : node->ReplaceInput(2, effect);
1399 442842 : NodeProperties::ChangeOp(
1400 : node,
1401 885684 : simplified()->StoreField(AccessBuilder::ForContextSlot(access.index())));
1402 442842 : return Changed(node);
1403 : }
1404 :
1405 7258 : Node* JSTypedLowering::BuildGetModuleCell(Node* node) {
1406 : DCHECK(node->opcode() == IrOpcode::kJSLoadModule ||
1407 : node->opcode() == IrOpcode::kJSStoreModule);
1408 7258 : Node* effect = NodeProperties::GetEffectInput(node);
1409 7258 : Node* control = NodeProperties::GetControlInput(node);
1410 :
1411 7258 : int32_t cell_index = OpParameter<int32_t>(node->op());
1412 7258 : Node* module = NodeProperties::GetValueInput(node, 0);
1413 7258 : Type module_type = NodeProperties::GetType(module);
1414 :
1415 7258 : 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 7120 : if (ModuleDescriptor::GetCellIndexKind(cell_index) ==
1424 : ModuleDescriptor::kExport) {
1425 7017 : field_access = AccessBuilder::ForModuleRegularExports();
1426 7017 : 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 7120 : Node* array = effect = graph()->NewNode(simplified()->LoadField(field_access),
1434 : module, effect, control);
1435 7120 : return graph()->NewNode(
1436 14240 : 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 6964 : Reduction JSTypedLowering::ReduceJSStoreModule(Node* node) {
1456 : DCHECK_EQ(IrOpcode::kJSStoreModule, node->opcode());
1457 6964 : Node* effect = NodeProperties::GetEffectInput(node);
1458 6964 : Node* control = NodeProperties::GetControlInput(node);
1459 6964 : Node* value = NodeProperties::GetValueInput(node, 1);
1460 : DCHECK_EQ(
1461 : ModuleDescriptor::GetCellIndexKind(OpParameter<int32_t>(node->op())),
1462 : ModuleDescriptor::kExport);
1463 :
1464 6964 : Node* cell = BuildGetModuleCell(node);
1465 6964 : if (cell->op()->EffectOutputCount() > 0) effect = cell;
1466 : effect =
1467 13928 : graph()->NewNode(simplified()->StoreField(AccessBuilder::ForCellValue()),
1468 : cell, value, effect, control);
1469 :
1470 : ReplaceWithValue(node, effect, effect, control);
1471 6964 : return Changed(value);
1472 : }
1473 :
1474 : namespace {
1475 :
1476 1773 : 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 1773 : Node* target = NodeProperties::GetValueInput(node, 0);
1501 : Node* new_target = is_construct
1502 0 : ? NodeProperties::GetValueInput(node, arity + 1)
1503 1773 : : 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 1773 : const bool has_builtin_exit_frame = Builtins::IsCpp(builtin_index);
1508 :
1509 1773 : Node* stub = jsgraph->CEntryStubConstant(1, kDontSaveFPRegs, kArgvOnStack,
1510 1773 : has_builtin_exit_frame);
1511 1773 : node->ReplaceInput(0, stub);
1512 :
1513 : Zone* zone = jsgraph->zone();
1514 1773 : 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 1773 : const int argc = arity + BuiltinArguments::kNumExtraArgsWithReceiver;
1523 1773 : Node* argc_node = jsgraph->Constant(argc);
1524 :
1525 : static const int kStubAndReceiver = 2;
1526 1773 : int cursor = arity + kStubAndReceiver;
1527 1773 : node->InsertInput(zone, cursor++, jsgraph->PaddingConstant());
1528 1773 : node->InsertInput(zone, cursor++, argc_node);
1529 1773 : node->InsertInput(zone, cursor++, target);
1530 1773 : node->InsertInput(zone, cursor++, new_target);
1531 :
1532 1773 : Address entry = Builtins::CppEntryOf(builtin_index);
1533 1773 : ExternalReference entry_ref = ExternalReference::Create(entry);
1534 1773 : Node* entry_node = jsgraph->ExternalConstant(entry_ref);
1535 :
1536 1773 : node->InsertInput(zone, cursor++, entry_node);
1537 1773 : node->InsertInput(zone, cursor++, argc_node);
1538 :
1539 : static const int kReturnCount = 1;
1540 1773 : const char* debug_name = Builtins::name(builtin_index);
1541 1773 : Operator::Properties properties = node->op()->properties();
1542 : auto call_descriptor = Linkage::GetCEntryStubCallDescriptor(
1543 1773 : zone, kReturnCount, argc, debug_name, properties, flags);
1544 :
1545 1773 : NodeProperties::ChangeOp(node, jsgraph->common()->Call(call_descriptor));
1546 1773 : }
1547 :
1548 : bool NeedsArgumentAdaptorFrame(SharedFunctionInfoRef shared, int arity) {
1549 : static const int sentinel = SharedFunctionInfo::kDontAdaptArgumentsSentinel;
1550 26236 : const int num_decl_parms = shared.internal_formal_parameter_count();
1551 26236 : return (num_decl_parms != arity && num_decl_parms != sentinel);
1552 : }
1553 :
1554 : } // namespace
1555 :
1556 461 : Reduction JSTypedLowering::ReduceJSConstructForwardVarargs(Node* node) {
1557 : DCHECK_EQ(IrOpcode::kJSConstructForwardVarargs, node->opcode());
1558 : ConstructForwardVarargsParameters p =
1559 461 : ConstructForwardVarargsParametersOf(node->op());
1560 : DCHECK_LE(2u, p.arity());
1561 461 : int const arity = static_cast<int>(p.arity() - 2);
1562 461 : int const start_index = static_cast<int>(p.start_index());
1563 461 : Node* target = NodeProperties::GetValueInput(node, 0);
1564 461 : Type target_type = NodeProperties::GetType(target);
1565 461 : Node* new_target = NodeProperties::GetValueInput(node, arity + 1);
1566 :
1567 : // Check if {target} is a JSFunction.
1568 884 : if (target_type.IsHeapConstant() &&
1569 423 : target_type.AsHeapConstant()->Ref().IsJSFunction()) {
1570 : // Only optimize [[Construct]] here if {function} is a Constructor.
1571 422 : JSFunctionRef function = target_type.AsHeapConstant()->Ref().AsJSFunction();
1572 422 : if (!function.map().is_constructor()) return NoChange();
1573 : // Patch {node} to an indirect call via ConstructFunctionForwardVarargs.
1574 422 : Callable callable = CodeFactory::ConstructFunctionForwardVarargs(isolate());
1575 422 : node->RemoveInput(arity + 1);
1576 844 : node->InsertInput(graph()->zone(), 0,
1577 422 : jsgraph()->HeapConstant(callable.code()));
1578 422 : node->InsertInput(graph()->zone(), 2, new_target);
1579 422 : node->InsertInput(graph()->zone(), 3, jsgraph()->Constant(arity));
1580 422 : node->InsertInput(graph()->zone(), 4, jsgraph()->Constant(start_index));
1581 422 : node->InsertInput(graph()->zone(), 5, jsgraph()->UndefinedConstant());
1582 422 : NodeProperties::ChangeOp(
1583 844 : node, common()->Call(Linkage::GetStubCallDescriptor(
1584 422 : graph()->zone(), callable.descriptor(), arity + 1,
1585 422 : CallDescriptor::kNeedsFrameState)));
1586 : return Changed(node);
1587 : }
1588 :
1589 : return NoChange();
1590 : }
1591 :
1592 34357 : Reduction JSTypedLowering::ReduceJSConstruct(Node* node) {
1593 : DCHECK_EQ(IrOpcode::kJSConstruct, node->opcode());
1594 34357 : ConstructParameters const& p = ConstructParametersOf(node->op());
1595 : DCHECK_LE(2u, p.arity());
1596 34357 : int const arity = static_cast<int>(p.arity() - 2);
1597 34357 : Node* target = NodeProperties::GetValueInput(node, 0);
1598 34358 : Type target_type = NodeProperties::GetType(target);
1599 34358 : Node* new_target = NodeProperties::GetValueInput(node, arity + 1);
1600 :
1601 : // Check if {target} is a known JSFunction.
1602 37429 : if (target_type.IsHeapConstant() &&
1603 3072 : target_type.AsHeapConstant()->Ref().IsJSFunction()) {
1604 2316 : JSFunctionRef function = target_type.AsHeapConstant()->Ref().AsJSFunction();
1605 2316 : SharedFunctionInfoRef shared = function.shared();
1606 :
1607 : // Only optimize [[Construct]] here if {function} is a Constructor.
1608 2316 : 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 2315 : 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 4630 : : BUILTIN_CODE(isolate(), JSConstructStubGeneric));
1619 :
1620 2315 : node->RemoveInput(arity + 1);
1621 2315 : node->InsertInput(graph()->zone(), 0, jsgraph()->Constant(code));
1622 2315 : node->InsertInput(graph()->zone(), 2, new_target);
1623 2315 : node->InsertInput(graph()->zone(), 3, jsgraph()->Constant(arity));
1624 2315 : node->InsertInput(graph()->zone(), 4, jsgraph()->UndefinedConstant());
1625 2315 : node->InsertInput(graph()->zone(), 5, jsgraph()->UndefinedConstant());
1626 2315 : NodeProperties::ChangeOp(
1627 : node,
1628 4630 : common()->Call(Linkage::GetStubCallDescriptor(
1629 2315 : graph()->zone(), ConstructStubDescriptor{}, 1 + arity, flags)));
1630 :
1631 : return Changed(node);
1632 : }
1633 :
1634 : return NoChange();
1635 : }
1636 :
1637 370 : Reduction JSTypedLowering::ReduceJSCallForwardVarargs(Node* node) {
1638 : DCHECK_EQ(IrOpcode::kJSCallForwardVarargs, node->opcode());
1639 370 : CallForwardVarargsParameters p = CallForwardVarargsParametersOf(node->op());
1640 : DCHECK_LE(2u, p.arity());
1641 370 : int const arity = static_cast<int>(p.arity() - 2);
1642 370 : int const start_index = static_cast<int>(p.start_index());
1643 370 : Node* target = NodeProperties::GetValueInput(node, 0);
1644 370 : Type target_type = NodeProperties::GetType(target);
1645 :
1646 : // Check if {target} is a JSFunction.
1647 370 : 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 494917 : Reduction JSTypedLowering::ReduceJSCall(Node* node) {
1666 : DCHECK_EQ(IrOpcode::kJSCall, node->opcode());
1667 494917 : CallParameters const& p = CallParametersOf(node->op());
1668 494920 : int arity = static_cast<int>(p.arity() - 2);
1669 : ConvertReceiverMode convert_mode = p.convert_mode();
1670 494920 : Node* target = NodeProperties::GetValueInput(node, 0);
1671 494920 : Type target_type = NodeProperties::GetType(target);
1672 494920 : Node* receiver = NodeProperties::GetValueInput(node, 1);
1673 494920 : Type receiver_type = NodeProperties::GetType(receiver);
1674 494920 : Node* effect = NodeProperties::GetEffectInput(node);
1675 494922 : Node* control = NodeProperties::GetControlInput(node);
1676 :
1677 : // Try to infer receiver {convert_mode} from {receiver} type.
1678 494916 : if (receiver_type.Is(Type::NullOrUndefined())) {
1679 : convert_mode = ConvertReceiverMode::kNullOrUndefined;
1680 158815 : } else if (!receiver_type.Maybe(Type::NullOrUndefined())) {
1681 : convert_mode = ConvertReceiverMode::kNotNullOrUndefined;
1682 : }
1683 :
1684 : // Check if {target} is a known JSFunction.
1685 521263 : if (target_type.IsHeapConstant() &&
1686 26346 : target_type.AsHeapConstant()->Ref().IsJSFunction()) {
1687 26255 : JSFunctionRef function = target_type.AsHeapConstant()->Ref().AsJSFunction();
1688 26255 : SharedFunctionInfoRef shared = function.shared();
1689 :
1690 26255 : 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 52474 : 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 70021 : if (is_sloppy(shared.language_mode()) && !shared.native() &&
1702 : !receiver_type.Is(Type::Receiver())) {
1703 17496 : if (!function.native_context().equals(broker()->native_context())) {
1704 : return NoChange();
1705 : }
1706 : Node* global_proxy =
1707 17496 : jsgraph()->Constant(function.native_context().global_proxy_object());
1708 : receiver = effect =
1709 17496 : graph()->NewNode(simplified()->ConvertReceiver(convert_mode),
1710 : receiver, global_proxy, effect, control);
1711 17496 : NodeProperties::ReplaceValueInput(node, receiver, 1);
1712 : }
1713 :
1714 : // Load the context from the {target}.
1715 26236 : Node* context = effect = graph()->NewNode(
1716 52472 : simplified()->LoadField(AccessBuilder::ForJSFunctionContext()), target,
1717 : effect, control);
1718 26236 : NodeProperties::ReplaceContextInput(node, context);
1719 :
1720 : // Update the effect dependency for the {node}.
1721 26236 : NodeProperties::ReplaceEffectInput(node, effect);
1722 :
1723 : // Compute flags for the call.
1724 : CallDescriptor::Flags flags = CallDescriptor::kNeedsFrameState;
1725 26236 : Node* new_target = jsgraph()->UndefinedConstant();
1726 :
1727 26236 : 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 3741 : 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 50 : int expected_argument_count = shared.internal_formal_parameter_count();
1741 148 : for (; arity > expected_argument_count; --arity) {
1742 49 : node->RemoveInput(arity + 1);
1743 : }
1744 52 : for (; arity < expected_argument_count; ++arity) {
1745 1 : node->InsertInput(graph()->zone(), arity + 2,
1746 1 : jsgraph()->UndefinedConstant());
1747 : }
1748 :
1749 : // Patch {node} to a direct call.
1750 50 : node->InsertInput(graph()->zone(), arity + 2, new_target);
1751 50 : node->InsertInput(graph()->zone(), arity + 3,
1752 50 : jsgraph()->Constant(arity));
1753 50 : NodeProperties::ChangeOp(node,
1754 50 : common()->Call(Linkage::GetJSCallDescriptor(
1755 : graph()->zone(), false, 1 + arity,
1756 50 : flags | CallDescriptor::kCanUseRoots)));
1757 : } else {
1758 : // Patch {node} to an indirect call via the ArgumentsAdaptorTrampoline.
1759 3691 : Callable callable = CodeFactory::ArgumentAdaptor(isolate());
1760 7382 : node->InsertInput(graph()->zone(), 0,
1761 3691 : jsgraph()->HeapConstant(callable.code()));
1762 3691 : node->InsertInput(graph()->zone(), 2, new_target);
1763 3691 : node->InsertInput(graph()->zone(), 3, jsgraph()->Constant(arity));
1764 3691 : node->InsertInput(
1765 : graph()->zone(), 4,
1766 7382 : jsgraph()->Constant(shared.internal_formal_parameter_count()));
1767 3691 : NodeProperties::ChangeOp(
1768 : node,
1769 11073 : common()->Call(Linkage::GetStubCallDescriptor(
1770 7382 : graph()->zone(), callable.descriptor(), 1 + arity, flags)));
1771 : }
1772 29938 : } else if (shared.HasBuiltinId() &&
1773 7443 : Builtins::HasCppImplementation(shared.builtin_id())) {
1774 : // Patch {node} to a direct CEntry call.
1775 1773 : ReduceBuiltin(jsgraph(), node, shared.builtin_id(), arity, flags);
1776 26392 : } else if (shared.HasBuiltinId() &&
1777 5670 : Builtins::KindOf(shared.builtin_id()) == Builtins::TFJ) {
1778 : // Patch {node} to a direct code object call.
1779 : Callable callable = Builtins::CallableFor(
1780 5670 : isolate(), static_cast<Builtins::Name>(shared.builtin_id()));
1781 : CallDescriptor::Flags flags = CallDescriptor::kNeedsFrameState;
1782 :
1783 : const CallInterfaceDescriptor& descriptor = callable.descriptor();
1784 11340 : auto call_descriptor = Linkage::GetStubCallDescriptor(
1785 5670 : graph()->zone(), descriptor, 1 + arity, flags);
1786 5670 : Node* stub_code = jsgraph()->HeapConstant(callable.code());
1787 5670 : node->InsertInput(graph()->zone(), 0, stub_code); // Code object.
1788 5670 : node->InsertInput(graph()->zone(), 2, new_target);
1789 5670 : node->InsertInput(graph()->zone(), 3, jsgraph()->Constant(arity));
1790 5670 : NodeProperties::ChangeOp(node, common()->Call(call_descriptor));
1791 : } else {
1792 : // Patch {node} to a direct call.
1793 15052 : node->InsertInput(graph()->zone(), arity + 2, new_target);
1794 15052 : node->InsertInput(graph()->zone(), arity + 3, jsgraph()->Constant(arity));
1795 15052 : NodeProperties::ChangeOp(node,
1796 15052 : common()->Call(Linkage::GetJSCallDescriptor(
1797 : graph()->zone(), false, 1 + arity,
1798 15052 : flags | CallDescriptor::kCanUseRoots)));
1799 : }
1800 : return Changed(node);
1801 : }
1802 :
1803 : // Check if {target} is a JSFunction.
1804 468662 : 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 21624 : Callable callable = CodeFactory::CallFunction(isolate(), convert_mode);
1809 43255 : node->InsertInput(graph()->zone(), 0,
1810 21626 : jsgraph()->HeapConstant(callable.code()));
1811 21628 : node->InsertInput(graph()->zone(), 2, jsgraph()->Constant(arity));
1812 21624 : NodeProperties::ChangeOp(
1813 64879 : node, common()->Call(Linkage::GetStubCallDescriptor(
1814 43252 : 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 447038 : if (p.convert_mode() != convert_mode) {
1820 137257 : NodeProperties::ChangeOp(
1821 : node, javascript()->Call(p.arity(), p.frequency(), p.feedback(),
1822 137257 : convert_mode, p.speculation_mode()));
1823 : return Changed(node);
1824 : }
1825 :
1826 : return NoChange();
1827 : }
1828 :
1829 1543 : Reduction JSTypedLowering::ReduceJSForInNext(Node* node) {
1830 : DCHECK_EQ(IrOpcode::kJSForInNext, node->opcode());
1831 1543 : ForInMode const mode = ForInModeOf(node->op());
1832 1543 : Node* receiver = NodeProperties::GetValueInput(node, 0);
1833 1543 : Node* cache_array = NodeProperties::GetValueInput(node, 1);
1834 1543 : Node* cache_type = NodeProperties::GetValueInput(node, 2);
1835 1543 : Node* index = NodeProperties::GetValueInput(node, 3);
1836 1543 : Node* context = NodeProperties::GetContextInput(node);
1837 1543 : Node* frame_state = NodeProperties::GetFrameStateInput(node);
1838 1543 : Node* effect = NodeProperties::GetEffectInput(node);
1839 1543 : Node* control = NodeProperties::GetControlInput(node);
1840 :
1841 : // Load the map of the {receiver}.
1842 : Node* receiver_map = effect =
1843 3086 : graph()->NewNode(simplified()->LoadField(AccessBuilder::ForMap()),
1844 : receiver, effect, control);
1845 :
1846 1543 : switch (mode) {
1847 : case ForInMode::kUseEnumCacheKeys:
1848 : case ForInMode::kUseEnumCacheKeysAndIndices: {
1849 : // Ensure that the expected map still matches that of the {receiver}.
1850 977 : Node* check = graph()->NewNode(simplified()->ReferenceEqual(),
1851 : receiver_map, cache_type);
1852 : effect =
1853 1954 : 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 977 : node->ReplaceInput(0, cache_array);
1862 977 : node->ReplaceInput(1, index);
1863 977 : node->ReplaceInput(2, effect);
1864 977 : node->ReplaceInput(3, control);
1865 977 : node->TrimInputCount(4);
1866 977 : NodeProperties::ChangeOp(
1867 : node,
1868 1954 : 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 566 : Node* key = effect = graph()->NewNode(
1875 1132 : simplified()->LoadElement(AccessBuilder::ForFixedArrayElement()),
1876 : cache_array, index, effect, control);
1877 :
1878 : // Check if the expected map still matches that of the {receiver}.
1879 566 : Node* check = graph()->NewNode(simplified()->ReferenceEqual(),
1880 : receiver_map, cache_type);
1881 : Node* branch =
1882 566 : graph()->NewNode(common()->Branch(BranchHint::kTrue), check, control);
1883 :
1884 566 : 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 566 : 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 566 : Builtins::CallableFor(isolate(), Builtins::kForInFilter);
1902 566 : auto call_descriptor = Linkage::GetStubCallDescriptor(
1903 566 : graph()->zone(), callable.descriptor(),
1904 : callable.descriptor().GetStackParameterCount(),
1905 566 : CallDescriptor::kNeedsFrameState);
1906 : vfalse = efalse = if_false =
1907 1132 : 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 566 : Node* if_exception = nullptr;
1914 566 : if (NodeProperties::IsExceptionalCall(node, &if_exception)) {
1915 157 : if_false = graph()->NewNode(common()->IfSuccess(), vfalse);
1916 157 : NodeProperties::ReplaceControlInput(if_exception, vfalse);
1917 157 : NodeProperties::ReplaceEffectInput(if_exception, efalse);
1918 157 : Revisit(if_exception);
1919 : }
1920 : }
1921 :
1922 566 : control = graph()->NewNode(common()->Merge(2), if_true, if_false);
1923 566 : effect = graph()->NewNode(common()->EffectPhi(2), etrue, efalse, control);
1924 : ReplaceWithValue(node, node, effect, control);
1925 :
1926 : // Morph the {node} into a Phi.
1927 566 : node->ReplaceInput(0, vtrue);
1928 566 : node->ReplaceInput(1, vfalse);
1929 566 : node->ReplaceInput(2, control);
1930 566 : node->TrimInputCount(3);
1931 566 : NodeProperties::ChangeOp(
1932 566 : node, common()->Phi(MachineRepresentation::kTagged, 2));
1933 : }
1934 : }
1935 :
1936 1543 : return Changed(node);
1937 : }
1938 :
1939 1361 : Reduction JSTypedLowering::ReduceJSForInPrepare(Node* node) {
1940 : DCHECK_EQ(IrOpcode::kJSForInPrepare, node->opcode());
1941 1361 : ForInMode const mode = ForInModeOf(node->op());
1942 1361 : Node* enumerator = NodeProperties::GetValueInput(node, 0);
1943 1361 : Node* effect = NodeProperties::GetEffectInput(node);
1944 1361 : Node* control = NodeProperties::GetControlInput(node);
1945 : Node* cache_type = enumerator;
1946 : Node* cache_array = nullptr;
1947 : Node* cache_length = nullptr;
1948 :
1949 1361 : switch (mode) {
1950 : case ForInMode::kUseEnumCacheKeys:
1951 : case ForInMode::kUseEnumCacheKeysAndIndices: {
1952 : // Check that the {enumerator} is a Map.
1953 2823 : 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 941 : Node* descriptor_array = effect = graph()->NewNode(
1960 1882 : simplified()->LoadField(AccessBuilder::ForMapDescriptors()),
1961 : enumerator, effect, control);
1962 941 : Node* enum_cache = effect = graph()->NewNode(
1963 1882 : simplified()->LoadField(AccessBuilder::ForDescriptorArrayEnumCache()),
1964 : descriptor_array, effect, control);
1965 941 : cache_array = effect = graph()->NewNode(
1966 1882 : simplified()->LoadField(AccessBuilder::ForEnumCacheKeys()),
1967 : enum_cache, effect, control);
1968 :
1969 : // Load the enum length of the {enumerator} map.
1970 941 : Node* bit_field3 = effect = graph()->NewNode(
1971 1882 : simplified()->LoadField(AccessBuilder::ForMapBitField3()), enumerator,
1972 : effect, control);
1973 : STATIC_ASSERT(Map::EnumLengthBits::kShift == 0);
1974 : cache_length =
1975 941 : graph()->NewNode(simplified()->NumberBitwiseAnd(), bit_field3,
1976 : jsgraph()->Constant(Map::EnumLengthBits::kMask));
1977 941 : 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 23137 : for (Edge edge : node->use_edges()) {
2041 : Node* const user = edge.from();
2042 10888 : if (NodeProperties::IsEffectEdge(edge)) {
2043 1361 : edge.UpdateTo(effect);
2044 : Revisit(user);
2045 9527 : } else if (NodeProperties::IsControlEdge(edge)) {
2046 5444 : edge.UpdateTo(control);
2047 : Revisit(user);
2048 : } else {
2049 : DCHECK(NodeProperties::IsValueEdge(edge));
2050 4083 : 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 1361 : node->Kill();
2066 1361 : return Replace(effect);
2067 : }
2068 :
2069 28611 : Reduction JSTypedLowering::ReduceJSLoadMessage(Node* node) {
2070 : DCHECK_EQ(IrOpcode::kJSLoadMessage, node->opcode());
2071 : ExternalReference const ref =
2072 28611 : ExternalReference::address_of_pending_message_obj(isolate());
2073 28611 : node->ReplaceInput(0, jsgraph()->ExternalConstant(ref));
2074 28611 : NodeProperties::ChangeOp(node, simplified()->LoadMessage());
2075 28611 : return Changed(node);
2076 : }
2077 :
2078 28613 : Reduction JSTypedLowering::ReduceJSStoreMessage(Node* node) {
2079 : DCHECK_EQ(IrOpcode::kJSStoreMessage, node->opcode());
2080 : ExternalReference const ref =
2081 28613 : ExternalReference::address_of_pending_message_obj(isolate());
2082 28613 : Node* value = NodeProperties::GetValueInput(node, 0);
2083 28613 : node->ReplaceInput(0, jsgraph()->ExternalConstant(ref));
2084 28613 : node->ReplaceInput(1, value);
2085 28613 : NodeProperties::ChangeOp(node, simplified()->StoreMessage());
2086 28613 : return Changed(node);
2087 : }
2088 :
2089 6979 : Reduction JSTypedLowering::ReduceJSGeneratorStore(Node* node) {
2090 : DCHECK_EQ(IrOpcode::kJSGeneratorStore, node->opcode());
2091 6979 : Node* generator = NodeProperties::GetValueInput(node, 0);
2092 6979 : Node* continuation = NodeProperties::GetValueInput(node, 1);
2093 6979 : Node* offset = NodeProperties::GetValueInput(node, 2);
2094 6979 : Node* context = NodeProperties::GetContextInput(node);
2095 6979 : Node* effect = NodeProperties::GetEffectInput(node);
2096 6979 : Node* control = NodeProperties::GetControlInput(node);
2097 6979 : int value_count = GeneratorStoreValueCountOf(node->op());
2098 :
2099 : FieldAccess array_field =
2100 6979 : AccessBuilder::ForJSGeneratorObjectParametersAndRegisters();
2101 6979 : FieldAccess context_field = AccessBuilder::ForJSGeneratorObjectContext();
2102 : FieldAccess continuation_field =
2103 6979 : AccessBuilder::ForJSGeneratorObjectContinuation();
2104 : FieldAccess input_or_debug_pos_field =
2105 6979 : AccessBuilder::ForJSGeneratorObjectInputOrDebugPos();
2106 :
2107 6979 : Node* array = effect = graph()->NewNode(simplified()->LoadField(array_field),
2108 : generator, effect, control);
2109 :
2110 58293 : for (int i = 0; i < value_count; ++i) {
2111 25657 : Node* value = NodeProperties::GetValueInput(node, 3 + i);
2112 25657 : if (value != jsgraph()->OptimizedOutConstant()) {
2113 17053 : effect = graph()->NewNode(
2114 34106 : simplified()->StoreField(AccessBuilder::ForFixedArraySlot(i)), array,
2115 : value, effect, control);
2116 : }
2117 : }
2118 :
2119 6979 : effect = graph()->NewNode(simplified()->StoreField(context_field), generator,
2120 : context, effect, control);
2121 6979 : effect = graph()->NewNode(simplified()->StoreField(continuation_field),
2122 : generator, continuation, effect, control);
2123 6979 : effect = graph()->NewNode(simplified()->StoreField(input_or_debug_pos_field),
2124 : generator, offset, effect, control);
2125 :
2126 : ReplaceWithValue(node, effect, effect, control);
2127 6979 : return Changed(effect);
2128 : }
2129 :
2130 2031 : Reduction JSTypedLowering::ReduceJSGeneratorRestoreContinuation(Node* node) {
2131 : DCHECK_EQ(IrOpcode::kJSGeneratorRestoreContinuation, node->opcode());
2132 2031 : Node* generator = NodeProperties::GetValueInput(node, 0);
2133 2031 : Node* effect = NodeProperties::GetEffectInput(node);
2134 2031 : Node* control = NodeProperties::GetControlInput(node);
2135 :
2136 : FieldAccess continuation_field =
2137 2031 : AccessBuilder::ForJSGeneratorObjectContinuation();
2138 :
2139 2031 : Node* continuation = effect = graph()->NewNode(
2140 : simplified()->LoadField(continuation_field), generator, effect, control);
2141 2031 : Node* executing = jsgraph()->Constant(JSGeneratorObject::kGeneratorExecuting);
2142 2031 : effect = graph()->NewNode(simplified()->StoreField(continuation_field),
2143 : generator, executing, effect, control);
2144 :
2145 : ReplaceWithValue(node, continuation, effect, control);
2146 2031 : return Changed(continuation);
2147 : }
2148 :
2149 2031 : Reduction JSTypedLowering::ReduceJSGeneratorRestoreContext(Node* node) {
2150 : DCHECK_EQ(IrOpcode::kJSGeneratorRestoreContext, node->opcode());
2151 :
2152 : const Operator* new_op =
2153 2031 : simplified()->LoadField(AccessBuilder::ForJSGeneratorObjectContext());
2154 :
2155 : // Mutate the node in-place.
2156 : DCHECK(OperatorProperties::HasContextInput(node->op()));
2157 : DCHECK(!OperatorProperties::HasContextInput(new_op));
2158 2031 : node->RemoveInput(NodeProperties::FirstContextIndex(node));
2159 :
2160 2031 : NodeProperties::ChangeOp(node, new_op);
2161 2031 : return Changed(node);
2162 : }
2163 :
2164 15979 : Reduction JSTypedLowering::ReduceJSGeneratorRestoreRegister(Node* node) {
2165 : DCHECK_EQ(IrOpcode::kJSGeneratorRestoreRegister, node->opcode());
2166 15979 : Node* generator = NodeProperties::GetValueInput(node, 0);
2167 15979 : Node* effect = NodeProperties::GetEffectInput(node);
2168 15979 : Node* control = NodeProperties::GetControlInput(node);
2169 15979 : int index = RestoreRegisterIndexOf(node->op());
2170 :
2171 : FieldAccess array_field =
2172 15979 : AccessBuilder::ForJSGeneratorObjectParametersAndRegisters();
2173 15979 : FieldAccess element_field = AccessBuilder::ForFixedArraySlot(index);
2174 :
2175 15979 : Node* array = effect = graph()->NewNode(simplified()->LoadField(array_field),
2176 : generator, effect, control);
2177 15979 : Node* element = effect = graph()->NewNode(
2178 : simplified()->LoadField(element_field), array, effect, control);
2179 15979 : Node* stale = jsgraph()->StaleRegisterConstant();
2180 15979 : effect = graph()->NewNode(simplified()->StoreField(element_field), array,
2181 : stale, effect, control);
2182 :
2183 : ReplaceWithValue(node, element, effect, control);
2184 15979 : return Changed(element);
2185 : }
2186 :
2187 6820 : Reduction JSTypedLowering::ReduceJSGeneratorRestoreInputOrDebugPos(Node* node) {
2188 : DCHECK_EQ(IrOpcode::kJSGeneratorRestoreInputOrDebugPos, node->opcode());
2189 :
2190 : FieldAccess input_or_debug_pos_field =
2191 6820 : AccessBuilder::ForJSGeneratorObjectInputOrDebugPos();
2192 6820 : 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 6820 : node->RemoveInput(NodeProperties::FirstContextIndex(node));
2198 :
2199 6820 : NodeProperties::ChangeOp(node, new_op);
2200 6820 : return Changed(node);
2201 : }
2202 :
2203 63 : Reduction JSTypedLowering::ReduceObjectIsArray(Node* node) {
2204 63 : Node* value = NodeProperties::GetValueInput(node, 0);
2205 63 : Type value_type = NodeProperties::GetType(value);
2206 63 : Node* context = NodeProperties::GetContextInput(node);
2207 63 : Node* frame_state = NodeProperties::GetFrameStateInput(node);
2208 63 : Node* effect = NodeProperties::GetEffectInput(node);
2209 63 : Node* control = NodeProperties::GetControlInput(node);
2210 :
2211 : // Constant-fold based on {value} type.
2212 63 : if (value_type.Is(Type::Array())) {
2213 15 : Node* value = jsgraph()->TrueConstant();
2214 : ReplaceWithValue(node, value);
2215 : return Replace(value);
2216 48 : } 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 40 : Node* check = graph()->NewNode(simplified()->ObjectIsSmi(), value);
2229 : control =
2230 40 : graph()->NewNode(common()->Branch(BranchHint::kFalse), check, control);
2231 :
2232 : // The {value} is a Smi.
2233 80 : controls[count] = graph()->NewNode(common()->IfTrue(), control);
2234 40 : effects[count] = effect;
2235 40 : values[count] = jsgraph()->FalseConstant();
2236 : count++;
2237 :
2238 40 : control = graph()->NewNode(common()->IfFalse(), control);
2239 :
2240 : // Load the {value}s instance type.
2241 40 : Node* value_map = effect = graph()->NewNode(
2242 80 : simplified()->LoadField(AccessBuilder::ForMap()), value, effect, control);
2243 40 : Node* value_instance_type = effect = graph()->NewNode(
2244 80 : simplified()->LoadField(AccessBuilder::ForMapInstanceType()), value_map,
2245 : effect, control);
2246 :
2247 : // Check if the {value} is a JSArray.
2248 40 : check = graph()->NewNode(simplified()->NumberEqual(), value_instance_type,
2249 : jsgraph()->Constant(JS_ARRAY_TYPE));
2250 40 : control = graph()->NewNode(common()->Branch(), check, control);
2251 :
2252 : // The {value} is a JSArray.
2253 80 : controls[count] = graph()->NewNode(common()->IfTrue(), control);
2254 40 : effects[count] = effect;
2255 40 : values[count] = jsgraph()->TrueConstant();
2256 : count++;
2257 :
2258 40 : control = graph()->NewNode(common()->IfFalse(), control);
2259 :
2260 : // Check if the {value} is a JSProxy.
2261 40 : check = graph()->NewNode(simplified()->NumberEqual(), value_instance_type,
2262 : jsgraph()->Constant(JS_PROXY_TYPE));
2263 : control =
2264 40 : graph()->NewNode(common()->Branch(BranchHint::kFalse), check, control);
2265 :
2266 : // The {value} is neither a JSArray nor a JSProxy.
2267 80 : controls[count] = graph()->NewNode(common()->IfFalse(), control);
2268 40 : effects[count] = effect;
2269 40 : values[count] = jsgraph()->FalseConstant();
2270 : count++;
2271 :
2272 40 : control = graph()->NewNode(common()->IfTrue(), control);
2273 :
2274 : // Let the %ArrayIsArray runtime function deal with the JSProxy {value}.
2275 : value = effect = control =
2276 40 : 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 40 : Node* on_exception = nullptr;
2283 40 : 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 40 : controls[count] = control;
2292 40 : effects[count] = effect;
2293 40 : values[count] = value;
2294 : count++;
2295 :
2296 40 : control = graph()->NewNode(common()->Merge(count), count, controls);
2297 40 : effects[count] = control;
2298 40 : values[count] = control;
2299 40 : effect = graph()->NewNode(common()->EffectPhi(count), count + 1, effects);
2300 40 : value = graph()->NewNode(common()->Phi(MachineRepresentation::kTagged, count),
2301 40 : count + 1, values);
2302 : ReplaceWithValue(node, value, effect, control);
2303 : return Replace(value);
2304 : }
2305 :
2306 214 : Reduction JSTypedLowering::ReduceJSParseInt(Node* node) {
2307 214 : Node* value = NodeProperties::GetValueInput(node, 0);
2308 214 : Type value_type = NodeProperties::GetType(value);
2309 214 : Node* radix = NodeProperties::GetValueInput(node, 1);
2310 214 : 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 681 : 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 998 : Reduction JSTypedLowering::ReduceJSResolvePromise(Node* node) {
2326 : DCHECK_EQ(IrOpcode::kJSResolvePromise, node->opcode());
2327 998 : Node* resolution = NodeProperties::GetValueInput(node, 1);
2328 998 : 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 998 : if (resolution_type.Is(Type::Primitive())) {
2333 : // JSResolvePromise(p,v:primitive) -> JSFulfillPromise(p,v)
2334 715 : node->RemoveInput(3); // frame state
2335 715 : NodeProperties::ChangeOp(node, javascript()->FulfillPromise());
2336 : return Changed(node);
2337 : }
2338 : return NoChange();
2339 : }
2340 :
2341 33790953 : Reduction JSTypedLowering::Reduce(Node* node) {
2342 : DisallowHeapAccess no_heap_access;
2343 :
2344 33790953 : switch (node->opcode()) {
2345 : case IrOpcode::kJSEqual:
2346 13314 : return ReduceJSEqual(node);
2347 : case IrOpcode::kJSStrictEqual:
2348 144042 : 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 34082 : return ReduceJSComparison(node);
2354 : case IrOpcode::kJSBitwiseOr:
2355 : case IrOpcode::kJSBitwiseXor:
2356 : case IrOpcode::kJSBitwiseAnd:
2357 23143 : return ReduceInt32Binop(node);
2358 : case IrOpcode::kJSShiftLeft:
2359 : case IrOpcode::kJSShiftRight:
2360 8019 : return ReduceUI32Shift(node, kSigned);
2361 : case IrOpcode::kJSShiftRightLogical:
2362 3705 : return ReduceUI32Shift(node, kUnsigned);
2363 : case IrOpcode::kJSAdd:
2364 87237 : return ReduceJSAdd(node);
2365 : case IrOpcode::kJSSubtract:
2366 : case IrOpcode::kJSMultiply:
2367 : case IrOpcode::kJSDivide:
2368 : case IrOpcode::kJSModulus:
2369 : case IrOpcode::kJSExponentiate:
2370 32820 : return ReduceNumberBinop(node);
2371 : case IrOpcode::kJSBitwiseNot:
2372 164 : return ReduceJSBitwiseNot(node);
2373 : case IrOpcode::kJSDecrement:
2374 2167 : return ReduceJSDecrement(node);
2375 : case IrOpcode::kJSIncrement:
2376 18981 : return ReduceJSIncrement(node);
2377 : case IrOpcode::kJSNegate:
2378 4043 : return ReduceJSNegate(node);
2379 : case IrOpcode::kJSHasInPrototypeChain:
2380 763 : return ReduceJSHasInPrototypeChain(node);
2381 : case IrOpcode::kJSOrdinaryHasInstance:
2382 157 : return ReduceJSOrdinaryHasInstance(node);
2383 : case IrOpcode::kJSToLength:
2384 36 : return ReduceJSToLength(node);
2385 : case IrOpcode::kJSToName:
2386 1141 : return ReduceJSToName(node);
2387 : case IrOpcode::kJSToNumber:
2388 : case IrOpcode::kJSToNumberConvertBigInt:
2389 9801 : return ReduceJSToNumber(node);
2390 : case IrOpcode::kJSToNumeric:
2391 4503 : return ReduceJSToNumeric(node);
2392 : case IrOpcode::kJSToString:
2393 2179 : return ReduceJSToString(node);
2394 : case IrOpcode::kJSToObject:
2395 1916 : return ReduceJSToObject(node);
2396 : case IrOpcode::kJSLoadNamed:
2397 419802 : return ReduceJSLoadNamed(node);
2398 : case IrOpcode::kJSLoadContext:
2399 299061 : return ReduceJSLoadContext(node);
2400 : case IrOpcode::kJSStoreContext:
2401 442842 : return ReduceJSStoreContext(node);
2402 : case IrOpcode::kJSLoadModule:
2403 294 : return ReduceJSLoadModule(node);
2404 : case IrOpcode::kJSStoreModule:
2405 6964 : return ReduceJSStoreModule(node);
2406 : case IrOpcode::kJSConstructForwardVarargs:
2407 461 : return ReduceJSConstructForwardVarargs(node);
2408 : case IrOpcode::kJSConstruct:
2409 34357 : return ReduceJSConstruct(node);
2410 : case IrOpcode::kJSCallForwardVarargs:
2411 370 : return ReduceJSCallForwardVarargs(node);
2412 : case IrOpcode::kJSCall:
2413 494917 : return ReduceJSCall(node);
2414 : case IrOpcode::kJSForInPrepare:
2415 1361 : return ReduceJSForInPrepare(node);
2416 : case IrOpcode::kJSForInNext:
2417 1543 : return ReduceJSForInNext(node);
2418 : case IrOpcode::kJSLoadMessage:
2419 28611 : return ReduceJSLoadMessage(node);
2420 : case IrOpcode::kJSStoreMessage:
2421 28613 : return ReduceJSStoreMessage(node);
2422 : case IrOpcode::kJSGeneratorStore:
2423 6979 : return ReduceJSGeneratorStore(node);
2424 : case IrOpcode::kJSGeneratorRestoreContinuation:
2425 2031 : return ReduceJSGeneratorRestoreContinuation(node);
2426 : case IrOpcode::kJSGeneratorRestoreContext:
2427 2031 : return ReduceJSGeneratorRestoreContext(node);
2428 : case IrOpcode::kJSGeneratorRestoreRegister:
2429 15979 : return ReduceJSGeneratorRestoreRegister(node);
2430 : case IrOpcode::kJSGeneratorRestoreInputOrDebugPos:
2431 6820 : return ReduceJSGeneratorRestoreInputOrDebugPos(node);
2432 : case IrOpcode::kJSObjectIsArray:
2433 63 : return ReduceObjectIsArray(node);
2434 : case IrOpcode::kJSParseInt:
2435 214 : return ReduceJSParseInt(node);
2436 : case IrOpcode::kJSResolvePromise:
2437 998 : 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 120216 : } // namespace v8
|