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 345004 : : lowering_(lowering), node_(node) {}
35 :
36 116448 : bool GetCompareNumberOperationHint(NumberOperationHint* hint) {
37 : DCHECK_EQ(1, node_->op()->EffectOutputCount());
38 116448 : switch (CompareOperationHintOf(node_->op())) {
39 : case CompareOperationHint::kSignedSmall:
40 6706 : *hint = NumberOperationHint::kSignedSmall;
41 : return true;
42 : case CompareOperationHint::kNumber:
43 8331 : *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 140777 : bool IsInternalizedStringCompareOperation() {
62 : DCHECK_EQ(1, node_->op()->EffectOutputCount());
63 140777 : return (CompareOperationHintOf(node_->op()) ==
64 144577 : CompareOperationHint::kInternalizedString) &&
65 144577 : BothInputsMaybe(Type::InternalizedString());
66 : }
67 :
68 103141 : bool IsReceiverCompareOperation() {
69 : DCHECK_EQ(1, node_->op()->EffectOutputCount());
70 103141 : return (CompareOperationHintOf(node_->op()) ==
71 103929 : CompareOperationHint::kReceiver) &&
72 103929 : BothInputsMaybe(Type::Receiver());
73 : }
74 :
75 102353 : bool IsReceiverOrNullOrUndefinedCompareOperation() {
76 : DCHECK_EQ(1, node_->op()->EffectOutputCount());
77 102353 : return (CompareOperationHintOf(node_->op()) ==
78 102404 : CompareOperationHint::kReceiverOrNullOrUndefined) &&
79 102404 : BothInputsMaybe(Type::ReceiverOrNullOrUndefined());
80 : }
81 :
82 127925 : bool IsStringCompareOperation() {
83 : DCHECK_EQ(1, node_->op()->EffectOutputCount());
84 127925 : return (CompareOperationHintOf(node_->op()) ==
85 135071 : CompareOperationHint::kString) &&
86 135071 : BothInputsMaybe(Type::String());
87 : }
88 :
89 95397 : bool IsSymbolCompareOperation() {
90 : DCHECK_EQ(1, node_->op()->EffectOutputCount());
91 95397 : return (CompareOperationHintOf(node_->op()) ==
92 95421 : CompareOperationHint::kSymbol) &&
93 95421 : BothInputsMaybe(Type::Symbol());
94 : }
95 :
96 : // Inserts a CheckReceiver for the left input.
97 788 : void CheckLeftInputToReceiver() {
98 788 : Node* left_input = graph()->NewNode(simplified()->CheckReceiver(), left(),
99 : effect(), control());
100 788 : node_->ReplaceInput(0, left_input);
101 : update_effect(left_input);
102 788 : }
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 1814 : void CheckInputsToNonEmptyOneByteString() {
171 3628 : if (!left_type().Is(Type::NonEmptyOneByteString())) {
172 : Node* left_input =
173 998 : graph()->NewNode(simplified()->CheckNonEmptyOneByteString(), left(),
174 : effect(), control());
175 998 : node_->ReplaceInput(0, left_input);
176 : update_effect(left_input);
177 : }
178 3628 : if (!right_type().Is(Type::NonEmptyOneByteString())) {
179 : Node* right_input =
180 522 : graph()->NewNode(simplified()->CheckNonEmptyOneByteString(), right(),
181 : effect(), control());
182 522 : node_->ReplaceInput(1, right_input);
183 : update_effect(right_input);
184 : }
185 1814 : }
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 136 : void CheckInputsToNonEmptyTwoByteString() {
191 272 : if (!left_type().Is(Type::NonEmptyTwoByteString())) {
192 : Node* left_input =
193 98 : graph()->NewNode(simplified()->CheckNonEmptyTwoByteString(), left(),
194 : effect(), control());
195 98 : node_->ReplaceInput(0, left_input);
196 : update_effect(left_input);
197 : }
198 272 : if (!right_type().Is(Type::NonEmptyTwoByteString())) {
199 : Node* right_input =
200 128 : graph()->NewNode(simplified()->CheckNonEmptyTwoByteString(), right(),
201 : effect(), control());
202 128 : node_->ReplaceInput(1, right_input);
203 : update_effect(right_input);
204 : }
205 136 : }
206 :
207 : // Checks that both inputs are NonEmptyString, and if we don't know
208 : // statically that one side is already a NonEmptyString, insert a
209 : // CheckNonEmptyString node.
210 18 : void CheckInputsToNonEmptyString() {
211 36 : if (!left_type().Is(Type::NonEmptyString())) {
212 18 : Node* left_input = graph()->NewNode(simplified()->CheckNonEmptyString(),
213 : left(), effect(), control());
214 18 : node_->ReplaceInput(0, left_input);
215 : update_effect(left_input);
216 : }
217 36 : if (!right_type().Is(Type::NonEmptyString())) {
218 0 : Node* right_input = graph()->NewNode(simplified()->CheckNonEmptyString(),
219 : right(), effect(), control());
220 0 : node_->ReplaceInput(1, right_input);
221 : update_effect(right_input);
222 : }
223 18 : }
224 :
225 : // Checks that both inputs are String, and if we don't know
226 : // statically that one side is already a String, insert a
227 : // CheckString node.
228 10810 : void CheckInputsToString() {
229 21620 : if (!left_type().Is(Type::String())) {
230 : Node* left_input =
231 15382 : graph()->NewNode(simplified()->CheckString(VectorSlotPair()), left(),
232 : effect(), control());
233 7691 : node_->ReplaceInput(0, left_input);
234 : update_effect(left_input);
235 : }
236 21620 : if (!right_type().Is(Type::String())) {
237 : Node* right_input =
238 4108 : graph()->NewNode(simplified()->CheckString(VectorSlotPair()), right(),
239 : effect(), control());
240 2054 : node_->ReplaceInput(1, right_input);
241 : update_effect(right_input);
242 : }
243 10810 : }
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 3520 : void CheckInputsToInternalizedString() {
249 7040 : if (!left_type().Is(Type::UniqueName())) {
250 3520 : Node* left_input = graph()->NewNode(
251 : simplified()->CheckInternalizedString(), left(), effect(), control());
252 3520 : node_->ReplaceInput(0, left_input);
253 : update_effect(left_input);
254 : }
255 7040 : if (!right_type().Is(Type::UniqueName())) {
256 : Node* right_input =
257 50 : graph()->NewNode(simplified()->CheckInternalizedString(), right(),
258 : effect(), control());
259 50 : node_->ReplaceInput(1, right_input);
260 : update_effect(right_input);
261 : }
262 3520 : }
263 :
264 33835 : void ConvertInputsToNumber() {
265 : DCHECK(left_type().Is(Type::PlainPrimitive()));
266 : DCHECK(right_type().Is(Type::PlainPrimitive()));
267 33835 : node_->ReplaceInput(0, ConvertPlainPrimitiveToNumber(left()));
268 33835 : node_->ReplaceInput(1, ConvertPlainPrimitiveToNumber(right()));
269 33835 : }
270 :
271 9827 : void ConvertInputsToUI32(Signedness left_signedness,
272 : Signedness right_signedness) {
273 9827 : node_->ReplaceInput(0, ConvertToUI32(left(), left_signedness));
274 9827 : node_->ReplaceInput(1, ConvertToUI32(right(), right_signedness));
275 9827 : }
276 :
277 3215 : void SwapInputs() {
278 : Node* l = left();
279 : Node* r = right();
280 3215 : node_->ReplaceInput(0, r);
281 3215 : node_->ReplaceInput(1, l);
282 3215 : }
283 :
284 : // Remove all effect and control inputs and outputs to this node and change
285 : // to the pure operator {op}.
286 90459 : 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 180918 : if (node_->op()->EffectInputCount() > 0) {
294 90459 : lowering_->RelaxEffectsAndControls(node_);
295 : }
296 : // Remove the inputs corresponding to context, effect, and control.
297 90459 : NodeProperties::RemoveNonValueInputs(node_);
298 : // Finally, update the operator to the new one.
299 90459 : 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 90459 : Type node_type = NodeProperties::GetType(node_);
304 90459 : NodeProperties::SetType(node_, Type::Intersect(node_type, type, zone()));
305 :
306 90459 : return lowering_->Changed(node_);
307 : }
308 :
309 15037 : 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 15037 : lowering_->RelaxControls(node_);
326 :
327 : // Remove the frame state and the context.
328 15037 : if (OperatorProperties::HasFrameStateInput(node_->op())) {
329 0 : node_->RemoveInput(NodeProperties::FirstFrameStateIndex(node_));
330 : }
331 30074 : node_->RemoveInput(NodeProperties::FirstContextIndex(node_));
332 :
333 15037 : NodeProperties::ChangeOp(node_, op);
334 :
335 : // Update the type to number.
336 15037 : Type node_type = NodeProperties::GetType(node_);
337 15037 : NodeProperties::SetType(node_,
338 : Type::Intersect(node_type, upper_bound, zone()));
339 :
340 15037 : return lowering_->Changed(node_);
341 : }
342 :
343 27094 : const Operator* NumberOp() {
344 27094 : switch (node_->opcode()) {
345 : case IrOpcode::kJSAdd:
346 11661 : return simplified()->NumberAdd();
347 : case IrOpcode::kJSSubtract:
348 1761 : return simplified()->NumberSubtract();
349 : case IrOpcode::kJSMultiply:
350 1486 : return simplified()->NumberMultiply();
351 : case IrOpcode::kJSDivide:
352 1504 : return simplified()->NumberDivide();
353 : case IrOpcode::kJSModulus:
354 822 : return simplified()->NumberModulus();
355 : case IrOpcode::kJSExponentiate:
356 33 : return simplified()->NumberPow();
357 : case IrOpcode::kJSBitwiseAnd:
358 1421 : return simplified()->NumberBitwiseAnd();
359 : case IrOpcode::kJSBitwiseOr:
360 1638 : return simplified()->NumberBitwiseOr();
361 : case IrOpcode::kJSBitwiseXor:
362 1433 : return simplified()->NumberBitwiseXor();
363 : case IrOpcode::kJSShiftLeft:
364 1821 : return simplified()->NumberShiftLeft();
365 : case IrOpcode::kJSShiftRight:
366 1750 : return simplified()->NumberShiftRight();
367 : case IrOpcode::kJSShiftRightLogical:
368 1764 : return simplified()->NumberShiftRightLogical();
369 : default:
370 : break;
371 : }
372 0 : UNREACHABLE();
373 : }
374 :
375 4506624 : bool LeftInputIs(Type t) { return left_type().Is(t); }
376 :
377 1457034 : bool RightInputIs(Type t) { return right_type().Is(t); }
378 :
379 192487 : bool OneInputIs(Type t) { return LeftInputIs(t) || RightInputIs(t); }
380 :
381 1178760 : bool BothInputsAre(Type t) { return LeftInputIs(t) && RightInputIs(t); }
382 :
383 11809 : bool BothInputsMaybe(Type t) {
384 23618 : return left_type().Maybe(t) && right_type().Maybe(t);
385 : }
386 :
387 172575 : bool OneInputCannotBe(Type t) {
388 326860 : return !left_type().Maybe(t) || !right_type().Maybe(t);
389 : }
390 :
391 48782 : bool NeitherInputCanBe(Type t) {
392 69195 : return !left_type().Maybe(t) && !right_type().Maybe(t);
393 : }
394 :
395 16078 : Node* effect() { return NodeProperties::GetEffectInput(node_); }
396 16078 : Node* control() { return NodeProperties::GetControlInput(node_); }
397 : Node* context() { return NodeProperties::GetContextInput(node_); }
398 265788 : Node* left() { return NodeProperties::GetValueInput(node_, 0); }
399 286588 : 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 67670 : Node* ConvertPlainPrimitiveToNumber(Node* node) {
417 : DCHECK(NodeProperties::GetType(node).Is(Type::PlainPrimitive()));
418 : // Avoid inserting too many eager ToNumber() operations.
419 67670 : Reduction const reduction = lowering_->ReduceJSToNumberInput(node);
420 67670 : if (reduction.Changed()) return reduction.replacement();
421 3680 : if (NodeProperties::GetType(node).Is(Type::Number())) {
422 : return node;
423 : }
424 3680 : return graph()->NewNode(simplified()->PlainPrimitiveToNumber(), node);
425 : }
426 :
427 19654 : Node* ConvertToUI32(Node* node, Signedness signedness) {
428 : // Avoid introducing too many eager NumberToXXnt32() operations.
429 19654 : Type type = NodeProperties::GetType(node);
430 19654 : if (signedness == kSigned) {
431 12555 : if (!type.Is(Type::Signed32())) {
432 6535 : node = graph()->NewNode(simplified()->NumberToInt32(), node);
433 : }
434 : } else {
435 : DCHECK_EQ(kUnsigned, signedness);
436 7099 : if (!type.Is(Type::Unsigned32())) {
437 3829 : node = graph()->NewNode(simplified()->NumberToUint32(), node);
438 : }
439 : }
440 19654 : return node;
441 : }
442 :
443 : void update_effect(Node* effect) {
444 16056 : 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 480406 : 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 480406 : graph()->zone())),
463 960813 : 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 2173 : Reduction JSTypedLowering::ReduceJSDecrement(Node* node) {
481 2173 : Node* input = NodeProperties::GetValueInput(node, 0);
482 2173 : Type input_type = NodeProperties::GetType(input);
483 2173 : 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 19160 : Reduction JSTypedLowering::ReduceJSIncrement(Node* node) {
496 19160 : Node* input = NodeProperties::GetValueInput(node, 0);
497 19160 : Type input_type = NodeProperties::GetType(input);
498 19160 : if (input_type.Is(Type::PlainPrimitive())) {
499 : // JSIncrement(x) => NumberAdd(ToNumber(x), 1)
500 11661 : node->InsertInput(graph()->zone(), 1, jsgraph()->OneConstant());
501 : BinaryOperationHint hint = BinaryOperationHint::kAny; // Dummy.
502 11661 : NodeProperties::ChangeOp(node, javascript()->Add(hint));
503 : JSBinopReduction r(this, node);
504 11661 : r.ConvertInputsToNumber();
505 : DCHECK_EQ(simplified()->NumberAdd(), r.NumberOp());
506 11661 : return r.ChangeToPureOperator(r.NumberOp(), Type::Number());
507 : }
508 : return NoChange();
509 : }
510 :
511 4035 : Reduction JSTypedLowering::ReduceJSNegate(Node* node) {
512 4035 : Node* input = NodeProperties::GetValueInput(node, 0);
513 4035 : Type input_type = NodeProperties::GetType(input);
514 4035 : if (input_type.Is(Type::PlainPrimitive())) {
515 : // JSNegate(x) => NumberMultiply(ToNumber(x), -1)
516 235 : node->InsertInput(graph()->zone(), 1, jsgraph()->SmiConstant(-1));
517 235 : NodeProperties::ChangeOp(node, javascript()->Multiply());
518 : JSBinopReduction r(this, node);
519 235 : r.ConvertInputsToNumber();
520 235 : return r.ChangeToPureOperator(r.NumberOp(), Type::Number());
521 : }
522 : return NoChange();
523 : }
524 :
525 86368 : Reduction JSTypedLowering::ReduceJSAdd(Node* node) {
526 : JSBinopReduction r(this, node);
527 86368 : if (r.BothInputsAre(Type::Number())) {
528 : // JSAdd(x:number, y:number) => NumberAdd(x, y)
529 11939 : return r.ChangeToPureOperator(simplified()->NumberAdd(), Type::Number());
530 : }
531 96495 : if (r.BothInputsAre(Type::PlainPrimitive()) &&
532 22066 : 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 74412 : if (r.LeftInputIs(Type::String())) {
540 : // JSAdd(x:string, y) => JSAdd(x, JSToString(y))
541 43281 : Reduction const reduction = ReduceJSToStringInput(r.right());
542 43281 : if (reduction.Changed()) {
543 21779 : NodeProperties::ReplaceValueInput(node, reduction.replacement(), 1);
544 : }
545 31131 : } else if (r.RightInputIs(Type::String())) {
546 : // JSAdd(x, y:string) => JSAdd(JSToString(x), y)
547 7752 : Reduction const reduction = ReduceJSToStringInput(r.left());
548 7752 : if (reduction.Changed()) {
549 183 : NodeProperties::ReplaceValueInput(node, reduction.replacement(), 0);
550 : }
551 : }
552 :
553 : // Always bake in String feedback into the graph.
554 74412 : BinaryOperationHint const hint = BinaryOperationHintOf(node->op());
555 74412 : if (hint == BinaryOperationHint::kConsOneByteString) {
556 1814 : r.CheckInputsToNonEmptyOneByteString();
557 72598 : } else if (hint == BinaryOperationHint::kConsTwoByteString) {
558 136 : r.CheckInputsToNonEmptyTwoByteString();
559 72462 : } else if (hint == BinaryOperationHint::kConsString) {
560 18 : r.CheckInputsToNonEmptyString();
561 72444 : } else if (hint == BinaryOperationHint::kString) {
562 3668 : 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 74412 : if (r.BothInputsAre(Type::Primitive())) {
572 29785 : if (r.LeftInputIs(Type::EmptyString())) {
573 : // JSAdd("", x:primitive) => JSToString(x)
574 161 : NodeProperties::ReplaceValueInputs(node, r.right());
575 161 : NodeProperties::ChangeOp(node, javascript()->ToString());
576 161 : NodeProperties::SetType(
577 : node, Type::Intersect(r.type(), Type::String(), graph()->zone()));
578 161 : Reduction const reduction = ReduceJSToString(node);
579 161 : return reduction.Changed() ? reduction : Changed(node);
580 29624 : } else if (r.RightInputIs(Type::EmptyString())) {
581 : // JSAdd(x:primitive, "") => JSToString(x)
582 109 : NodeProperties::ReplaceValueInputs(node, r.left());
583 109 : NodeProperties::ChangeOp(node, javascript()->ToString());
584 109 : NodeProperties::SetType(
585 : node, Type::Intersect(r.type(), Type::String(), graph()->zone()));
586 109 : Reduction const reduction = ReduceJSToString(node);
587 109 : return reduction.Changed() ? reduction : Changed(node);
588 : }
589 : }
590 :
591 : // Lower to string addition if both inputs are known to be strings.
592 74142 : if (r.BothInputsAre(Type::String())) {
593 24337 : Node* context = NodeProperties::GetContextInput(node);
594 24337 : Node* frame_state = NodeProperties::GetFrameStateInput(node);
595 24337 : Node* effect = NodeProperties::GetEffectInput(node);
596 24337 : Node* control = NodeProperties::GetControlInput(node);
597 :
598 : // Compute the resulting length.
599 : Node* left_length =
600 24337 : graph()->NewNode(simplified()->StringLength(), r.left());
601 : Node* right_length =
602 24337 : graph()->NewNode(simplified()->StringLength(), r.right());
603 : Node* length =
604 24337 : graph()->NewNode(simplified()->NumberAdd(), left_length, right_length);
605 :
606 : CellRef string_length_protector(broker(),
607 : factory()->string_length_protector());
608 24337 : 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 48286 : length = effect = graph()->NewNode(
615 : simplified()->CheckBounds(VectorSlotPair()), length,
616 : jsgraph()->Constant(String::kMaxLength + 1), effect, control);
617 : } else {
618 : // Check if we would overflow the allowed maximum string length.
619 : Node* check =
620 194 : graph()->NewNode(simplified()->NumberLessThanOrEqual(), length,
621 : jsgraph()->Constant(String::kMaxLength));
622 : Node* branch =
623 194 : graph()->NewNode(common()->Branch(BranchHint::kTrue), check, control);
624 194 : Node* if_false = graph()->NewNode(common()->IfFalse(), branch);
625 : Node* efalse = effect;
626 : {
627 : // Throw a RangeError in case of overflow.
628 194 : Node* vfalse = efalse = if_false = graph()->NewNode(
629 : javascript()->CallRuntime(Runtime::kThrowInvalidStringLength),
630 : context, frame_state, efalse, if_false);
631 :
632 : // Update potential {IfException} uses of {node} to point to the
633 : // %ThrowInvalidStringLength runtime call node instead.
634 194 : Node* on_exception = nullptr;
635 194 : if (NodeProperties::IsExceptionalCall(node, &on_exception)) {
636 28 : NodeProperties::ReplaceControlInput(on_exception, vfalse);
637 28 : NodeProperties::ReplaceEffectInput(on_exception, efalse);
638 28 : if_false = graph()->NewNode(common()->IfSuccess(), vfalse);
639 28 : Revisit(on_exception);
640 : }
641 :
642 : // The above %ThrowInvalidStringLength runtime call is an unconditional
643 : // throw, making it impossible to return a successful completion in this
644 : // case. We simply connect the successful completion to the graph end.
645 194 : if_false = graph()->NewNode(common()->Throw(), efalse, if_false);
646 : // TODO(bmeurer): This should be on the AdvancedReducer somehow.
647 194 : NodeProperties::MergeControlToEnd(graph(), common(), if_false);
648 : Revisit(graph()->end());
649 : }
650 194 : control = graph()->NewNode(common()->IfTrue(), branch);
651 : length = effect =
652 194 : graph()->NewNode(common()->TypeGuard(type_cache_->kStringLengthType),
653 : length, effect, control);
654 : }
655 :
656 48674 : if (hint == BinaryOperationHint::kConsString ||
657 46842 : hint == BinaryOperationHint::kConsOneByteString ||
658 : hint == BinaryOperationHint::kConsTwoByteString) {
659 1892 : Node* check = graph()->NewNode(
660 : simplified()->NumberLessThan(),
661 : jsgraph()->Constant(ConsString::kMinLength - 1), length);
662 3784 : effect = graph()->NewNode(
663 : simplified()->CheckIf(DeoptimizeReason::kWrongLength), check, effect,
664 : control);
665 1892 : length = effect = graph()->NewNode(
666 1892 : common()->TypeGuard(type_cache_->kConsStringLengthType), length,
667 : effect, control);
668 : }
669 :
670 24337 : 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 49805 : if (r.OneInputIs(Type::String())) {
682 : StringAddFlags flags = STRING_ADD_CHECK_NONE;
683 26716 : if (!r.LeftInputIs(Type::String())) {
684 : flags = STRING_ADD_CONVERT_LEFT;
685 20163 : } else if (!r.RightInputIs(Type::String())) {
686 : flags = STRING_ADD_CONVERT_RIGHT;
687 : }
688 26716 : Operator::Properties properties = node->op()->properties();
689 26716 : if (r.NeitherInputCanBe(Type::Receiver())) {
690 : // Both sides are already strings, so we know that the
691 : // string addition will not cause any observable side
692 : // effects; it can still throw obviously.
693 177 : properties = Operator::kNoWrite | Operator::kNoDeopt;
694 : }
695 :
696 : // JSAdd(x:string, y) => CallStub[StringAdd](x, y)
697 : // JSAdd(x, y:string) => CallStub[StringAdd](x, y)
698 26716 : Callable const callable = CodeFactory::StringAdd(isolate(), flags);
699 26716 : auto call_descriptor = Linkage::GetStubCallDescriptor(
700 26716 : graph()->zone(), callable.descriptor(),
701 : callable.descriptor().GetStackParameterCount(),
702 26716 : CallDescriptor::kNeedsFrameState, properties);
703 : DCHECK_EQ(1, OperatorProperties::GetFrameStateInputCount(node->op()));
704 53432 : node->InsertInput(graph()->zone(), 0,
705 26716 : jsgraph()->HeapConstant(callable.code()));
706 26716 : NodeProperties::ChangeOp(node, common()->Call(call_descriptor));
707 : return Changed(node);
708 : }
709 : return NoChange();
710 : }
711 :
712 26279 : Reduction JSTypedLowering::ReduceNumberBinop(Node* node) {
713 : JSBinopReduction r(this, node);
714 26279 : if (r.BothInputsAre(Type::PlainPrimitive())) {
715 5064 : r.ConvertInputsToNumber();
716 5064 : return r.ChangeToPureOperator(r.NumberOp(), Type::Number());
717 : }
718 : return NoChange();
719 : }
720 :
721 19453 : Reduction JSTypedLowering::ReduceInt32Binop(Node* node) {
722 : JSBinopReduction r(this, node);
723 19453 : if (r.BothInputsAre(Type::PlainPrimitive())) {
724 4458 : r.ConvertInputsToNumber();
725 4458 : r.ConvertInputsToUI32(kSigned, kSigned);
726 4458 : return r.ChangeToPureOperator(r.NumberOp(), Type::Signed32());
727 : }
728 : return NoChange();
729 : }
730 :
731 7960 : Reduction JSTypedLowering::ReduceUI32Shift(Node* node, Signedness signedness) {
732 : JSBinopReduction r(this, node);
733 7960 : if (r.BothInputsAre(Type::PlainPrimitive())) {
734 5335 : r.ConvertInputsToNumber();
735 5335 : r.ConvertInputsToUI32(signedness, kUnsigned);
736 : return r.ChangeToPureOperator(r.NumberOp(), signedness == kUnsigned
737 : ? Type::Unsigned32()
738 5335 : : Type::Signed32());
739 : }
740 : return NoChange();
741 : }
742 :
743 34553 : Reduction JSTypedLowering::ReduceJSComparison(Node* node) {
744 : JSBinopReduction r(this, node);
745 34553 : 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 66168 : if (r.BothInputsAre(Type::Signed32()) ||
773 32488 : r.BothInputsAre(Type::Unsigned32())) {
774 1334 : less_than = simplified()->NumberLessThan();
775 1334 : less_than_or_equal = simplified()->NumberLessThanOrEqual();
776 62649 : } else if (r.OneInputCannotBe(Type::StringOrReceiver()) &&
777 30303 : r.BothInputsAre(Type::PlainPrimitive())) {
778 6724 : r.ConvertInputsToNumber();
779 6724 : less_than = simplified()->NumberLessThan();
780 6724 : less_than_or_equal = simplified()->NumberLessThanOrEqual();
781 25622 : } else if (r.IsStringCompareOperation()) {
782 236 : r.CheckInputsToString();
783 236 : less_than = simplified()->StringLessThan();
784 236 : less_than_or_equal = simplified()->StringLessThanOrEqual();
785 : } else {
786 : return NoChange();
787 : }
788 : const Operator* comparison;
789 8294 : switch (node->opcode()) {
790 : case IrOpcode::kJSLessThan:
791 : comparison = less_than;
792 : break;
793 : case IrOpcode::kJSGreaterThan:
794 : comparison = less_than;
795 1458 : r.SwapInputs(); // a > b => b < a
796 1458 : break;
797 : case IrOpcode::kJSLessThanOrEqual:
798 : comparison = less_than_or_equal;
799 1369 : break;
800 : case IrOpcode::kJSGreaterThanOrEqual:
801 : comparison = less_than_or_equal;
802 1328 : r.SwapInputs(); // a >= b => b <= a
803 1328 : break;
804 : default:
805 : return NoChange();
806 : }
807 8294 : return r.ChangeToPureOperator(comparison);
808 : }
809 :
810 13454 : Reduction JSTypedLowering::ReduceJSEqual(Node* node) {
811 : JSBinopReduction r(this, node);
812 :
813 13454 : if (r.BothInputsAre(Type::UniqueName())) {
814 900 : return r.ChangeToPureOperator(simplified()->ReferenceEqual());
815 : }
816 12554 : if (r.IsInternalizedStringCompareOperation()) {
817 49 : r.CheckInputsToInternalizedString();
818 49 : return r.ChangeToPureOperator(simplified()->ReferenceEqual());
819 : }
820 12505 : if (r.BothInputsAre(Type::String())) {
821 78 : return r.ChangeToPureOperator(simplified()->StringEqual());
822 : }
823 12427 : if (r.BothInputsAre(Type::Boolean())) {
824 38 : return r.ChangeToPureOperator(simplified()->ReferenceEqual());
825 : }
826 12389 : if (r.BothInputsAre(Type::Receiver())) {
827 21 : return r.ChangeToPureOperator(simplified()->ReferenceEqual());
828 : }
829 12368 : if (r.OneInputIs(Type::Undetectable())) {
830 : RelaxEffectsAndControls(node);
831 49 : node->RemoveInput(r.LeftInputIs(Type::Undetectable()) ? 0 : 1);
832 49 : node->TrimInputCount(1);
833 49 : NodeProperties::ChangeOp(node, simplified()->ObjectIsUndetectable());
834 : return Changed(node);
835 : }
836 :
837 21463 : if (r.BothInputsAre(Type::Signed32()) ||
838 9144 : r.BothInputsAre(Type::Unsigned32())) {
839 3221 : return r.ChangeToPureOperator(simplified()->NumberEqual());
840 9098 : } else if (r.BothInputsAre(Type::Number())) {
841 585 : return r.ChangeToPureOperator(simplified()->NumberEqual());
842 8513 : } else if (r.IsReceiverCompareOperation()) {
843 96 : r.CheckInputsToReceiver();
844 96 : return r.ChangeToPureOperator(simplified()->ReferenceEqual());
845 8417 : } 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 8379 : } else if (r.IsStringCompareOperation()) {
886 36 : r.CheckInputsToString();
887 36 : return r.ChangeToPureOperator(simplified()->StringEqual());
888 8343 : } else if (r.IsSymbolCompareOperation()) {
889 16 : r.CheckInputsToSymbol();
890 16 : return r.ChangeToPureOperator(simplified()->ReferenceEqual());
891 : }
892 : return NoChange();
893 : }
894 :
895 144700 : Reduction JSTypedLowering::ReduceJSStrictEqual(Node* node) {
896 : JSBinopReduction r(this, node);
897 144700 : if (r.left() == r.right()) {
898 : // x === x is always true if x != NaN
899 8942 : Node* replacement = graph()->NewNode(
900 : simplified()->BooleanNot(),
901 : graph()->NewNode(simplified()->ObjectIsNaN(), r.left()));
902 : ReplaceWithValue(node, replacement);
903 : return Replace(replacement);
904 : }
905 140229 : 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 5859 : if (!r.left_type().Maybe(r.right_type())) {
910 960 : Node* replacement = jsgraph()->FalseConstant();
911 : ReplaceWithValue(node, replacement);
912 : return Replace(replacement);
913 : }
914 : }
915 :
916 139269 : if (r.BothInputsAre(Type::Unique())) {
917 8993 : return r.ChangeToPureOperator(simplified()->ReferenceEqual());
918 : }
919 130276 : if (r.OneInputIs(pointer_comparable_type_)) {
920 2053 : return r.ChangeToPureOperator(simplified()->ReferenceEqual());
921 : }
922 128223 : if (r.IsInternalizedStringCompareOperation()) {
923 3471 : r.CheckInputsToInternalizedString();
924 3471 : return r.ChangeToPureOperator(simplified()->ReferenceEqual());
925 : }
926 124752 : if (r.BothInputsAre(Type::String())) {
927 3485 : return r.ChangeToPureOperator(simplified()->StringEqual());
928 : }
929 :
930 : NumberOperationHint hint;
931 237925 : if (r.BothInputsAre(Type::Signed32()) ||
932 116658 : r.BothInputsAre(Type::Unsigned32())) {
933 4819 : return r.ChangeToPureOperator(simplified()->NumberEqual());
934 116448 : } else if (r.GetCompareNumberOperationHint(&hint)) {
935 : return r.ChangeToSpeculativeOperator(
936 15037 : simplified()->SpeculativeNumberEqual(hint), Type::Boolean());
937 101411 : } else if (r.BothInputsAre(Type::Number())) {
938 6783 : return r.ChangeToPureOperator(simplified()->NumberEqual());
939 94628 : } 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 692 : r.CheckLeftInputToReceiver();
944 692 : return r.ChangeToPureOperator(simplified()->ReferenceEqual());
945 93936 : } 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 93924 : } else if (r.IsStringCompareOperation()) {
953 6870 : r.CheckInputsToString();
954 6870 : return r.ChangeToPureOperator(simplified()->StringEqual());
955 87054 : } 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 1148 : Reduction JSTypedLowering::ReduceJSToName(Node* node) {
966 1148 : Node* const input = NodeProperties::GetValueInput(node, 0);
967 1148 : Type const input_type = NodeProperties::GetType(input);
968 1148 : 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 79695 : Reduction JSTypedLowering::ReduceJSToNumberInput(Node* input) {
1001 : // Try constant-folding of JSToNumber with constant inputs.
1002 79695 : Type input_type = NodeProperties::GetType(input);
1003 :
1004 79695 : if (input_type.Is(Type::String())) {
1005 : HeapObjectMatcher m(input);
1006 2828 : 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 78854 : 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 78048 : if (input_type.Is(Type::Number())) {
1021 : // JSToNumber(x:number) => x
1022 : return Changed(input);
1023 : }
1024 13011 : if (input_type.Is(Type::Undefined())) {
1025 : // JSToNumber(undefined) => #NaN
1026 820 : return Replace(jsgraph()->NaNConstant());
1027 : }
1028 12191 : if (input_type.Is(Type::Null())) {
1029 : // JSToNumber(null) => #0
1030 820 : return Replace(jsgraph()->ZeroConstant());
1031 : }
1032 : return NoChange();
1033 : }
1034 :
1035 12025 : Reduction JSTypedLowering::ReduceJSToNumber(Node* node) {
1036 : // Try to reduce the input first.
1037 : Node* const input = node->InputAt(0);
1038 12025 : Reduction reduction = ReduceJSToNumberInput(input);
1039 12025 : if (reduction.Changed()) {
1040 : ReplaceWithValue(node, reduction.replacement());
1041 2494 : return reduction;
1042 : }
1043 9531 : Type const input_type = NodeProperties::GetType(input);
1044 9531 : if (input_type.Is(Type::PlainPrimitive())) {
1045 : RelaxEffectsAndControls(node);
1046 358 : node->TrimInputCount(1);
1047 : // For a PlainPrimitive, ToNumeric is the same as ToNumber.
1048 358 : Type node_type = NodeProperties::GetType(node);
1049 358 : NodeProperties::SetType(
1050 : node, Type::Intersect(node_type, Type::Number(), graph()->zone()));
1051 358 : NodeProperties::ChangeOp(node, simplified()->PlainPrimitiveToNumber());
1052 : return Changed(node);
1053 : }
1054 : return NoChange();
1055 : }
1056 :
1057 4568 : Reduction JSTypedLowering::ReduceJSToNumeric(Node* node) {
1058 4568 : Node* const input = NodeProperties::GetValueInput(node, 0);
1059 4568 : Type const input_type = NodeProperties::GetType(input);
1060 4568 : 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 54955 : Reduction JSTypedLowering::ReduceJSToStringInput(Node* input) {
1070 54955 : if (input->opcode() == IrOpcode::kJSToString) {
1071 : // Recursively try to reduce the input first.
1072 1486 : Reduction result = ReduceJSToString(input);
1073 1486 : if (result.Changed()) return result;
1074 : return Changed(input); // JSToString(JSToString(x)) => JSToString(x)
1075 : }
1076 53469 : Type input_type = NodeProperties::GetType(input);
1077 53469 : if (input_type.Is(Type::String())) {
1078 : return Changed(input); // JSToString(x:string) => x
1079 : }
1080 33930 : if (input_type.Is(Type::Boolean())) {
1081 : return Replace(graph()->NewNode(
1082 : common()->Select(MachineRepresentation::kTagged), input,
1083 : jsgraph()->HeapConstant(factory()->true_string()),
1084 222 : jsgraph()->HeapConstant(factory()->false_string())));
1085 : }
1086 33856 : if (input_type.Is(Type::Undefined())) {
1087 69 : return Replace(jsgraph()->HeapConstant(factory()->undefined_string()));
1088 : }
1089 33787 : if (input_type.Is(Type::Null())) {
1090 14 : return Replace(jsgraph()->HeapConstant(factory()->null_string()));
1091 : }
1092 33773 : if (input_type.Is(Type::NaN())) {
1093 2 : return Replace(jsgraph()->HeapConstant(factory()->NaN_string()));
1094 : }
1095 33771 : if (input_type.Is(Type::Number())) {
1096 1141 : return Replace(graph()->NewNode(simplified()->NumberToString(), input));
1097 : }
1098 : return NoChange();
1099 : }
1100 :
1101 3922 : 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 3922 : Reduction reduction = ReduceJSToStringInput(input);
1106 3922 : if (reduction.Changed()) {
1107 : ReplaceWithValue(node, reduction.replacement());
1108 363 : return reduction;
1109 : }
1110 : return NoChange();
1111 : }
1112 :
1113 1935 : Reduction JSTypedLowering::ReduceJSToObject(Node* node) {
1114 : DCHECK_EQ(IrOpcode::kJSToObject, node->opcode());
1115 1935 : Node* receiver = NodeProperties::GetValueInput(node, 0);
1116 1935 : Type receiver_type = NodeProperties::GetType(receiver);
1117 1935 : Node* context = NodeProperties::GetContextInput(node);
1118 1935 : Node* frame_state = NodeProperties::GetFrameStateInput(node);
1119 1935 : Node* effect = NodeProperties::GetEffectInput(node);
1120 1935 : Node* control = NodeProperties::GetControlInput(node);
1121 1935 : 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 1479 : Node* check = graph()->NewNode(simplified()->ObjectIsReceiver(), receiver);
1128 : Node* branch =
1129 1479 : graph()->NewNode(common()->Branch(BranchHint::kTrue), check, control);
1130 :
1131 1479 : Node* if_true = graph()->NewNode(common()->IfTrue(), branch);
1132 : Node* etrue = effect;
1133 : Node* rtrue = receiver;
1134 :
1135 1479 : Node* if_false = graph()->NewNode(common()->IfFalse(), branch);
1136 : Node* efalse = effect;
1137 : Node* rfalse;
1138 : {
1139 : // Convert {receiver} using the ToObjectStub.
1140 1479 : Callable callable = Builtins::CallableFor(isolate(), Builtins::kToObject);
1141 1479 : auto call_descriptor = Linkage::GetStubCallDescriptor(
1142 1479 : graph()->zone(), callable.descriptor(),
1143 : callable.descriptor().GetStackParameterCount(),
1144 1479 : CallDescriptor::kNeedsFrameState, node->op()->properties());
1145 : rfalse = efalse = if_false =
1146 2958 : 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 1479 : Node* on_exception = nullptr;
1155 2875 : if (receiver_type.Maybe(Type::NullOrUndefined()) &&
1156 1396 : NodeProperties::IsExceptionalCall(node, &on_exception)) {
1157 207 : NodeProperties::ReplaceControlInput(on_exception, if_false);
1158 207 : NodeProperties::ReplaceEffectInput(on_exception, efalse);
1159 207 : if_false = graph()->NewNode(common()->IfSuccess(), if_false);
1160 207 : Revisit(on_exception);
1161 : }
1162 :
1163 1479 : control = graph()->NewNode(common()->Merge(2), if_true, if_false);
1164 1479 : 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 1479 : node->ReplaceInput(0, rtrue);
1169 1479 : node->ReplaceInput(1, rfalse);
1170 1479 : node->ReplaceInput(2, control);
1171 1479 : node->TrimInputCount(3);
1172 1479 : NodeProperties::ChangeOp(node,
1173 1479 : common()->Phi(MachineRepresentation::kTagged, 2));
1174 : return Changed(node);
1175 : }
1176 :
1177 423882 : Reduction JSTypedLowering::ReduceJSLoadNamed(Node* node) {
1178 : DCHECK_EQ(IrOpcode::kJSLoadNamed, node->opcode());
1179 423882 : Node* receiver = NodeProperties::GetValueInput(node, 0);
1180 423882 : Type receiver_type = NodeProperties::GetType(receiver);
1181 423882 : NameRef name(broker(), NamedAccessOf(node->op()).name());
1182 : NameRef length_str(broker(), factory()->length_string());
1183 : // Optimize "length" property of strings.
1184 458771 : 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 833 : Reduction JSTypedLowering::ReduceJSHasInPrototypeChain(Node* node) {
1193 : DCHECK_EQ(IrOpcode::kJSHasInPrototypeChain, node->opcode());
1194 833 : Node* value = NodeProperties::GetValueInput(node, 0);
1195 833 : Type value_type = NodeProperties::GetType(value);
1196 833 : Node* prototype = NodeProperties::GetValueInput(node, 1);
1197 833 : Node* context = NodeProperties::GetContextInput(node);
1198 833 : Node* frame_state = NodeProperties::GetFrameStateInput(node);
1199 833 : Node* effect = NodeProperties::GetEffectInput(node);
1200 833 : 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 833 : if (value_type.Is(Type::Primitive())) {
1205 159 : Node* value = jsgraph()->FalseConstant();
1206 : ReplaceWithValue(node, value, effect, control);
1207 : return Replace(value);
1208 : }
1209 :
1210 674 : Node* check0 = graph()->NewNode(simplified()->ObjectIsSmi(), value);
1211 : Node* branch0 =
1212 674 : graph()->NewNode(common()->Branch(BranchHint::kFalse), check0, control);
1213 :
1214 674 : Node* if_true0 = graph()->NewNode(common()->IfTrue(), branch0);
1215 : Node* etrue0 = effect;
1216 674 : Node* vtrue0 = jsgraph()->FalseConstant();
1217 :
1218 674 : control = graph()->NewNode(common()->IfFalse(), branch0);
1219 :
1220 : // Loop through the {value}s prototype chain looking for the {prototype}.
1221 674 : Node* loop = control = graph()->NewNode(common()->Loop(2), control, control);
1222 : Node* eloop = effect =
1223 674 : graph()->NewNode(common()->EffectPhi(2), effect, effect, loop);
1224 674 : Node* terminate = graph()->NewNode(common()->Terminate(), eloop, loop);
1225 674 : NodeProperties::MergeControlToEnd(graph(), common(), terminate);
1226 674 : 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 674 : Node* value_map = effect = graph()->NewNode(
1232 1348 : simplified()->LoadField(AccessBuilder::ForMap()), value, effect, control);
1233 674 : Node* value_instance_type = effect = graph()->NewNode(
1234 1348 : 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 674 : Node* check1 = graph()->NewNode(
1241 : simplified()->NumberLessThanOrEqual(), value_instance_type,
1242 : jsgraph()->Constant(LAST_SPECIAL_RECEIVER_TYPE));
1243 : Node* branch1 =
1244 674 : graph()->NewNode(common()->Branch(BranchHint::kFalse), check1, control);
1245 :
1246 674 : control = graph()->NewNode(common()->IfFalse(), branch1);
1247 :
1248 674 : 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 674 : graph()->NewNode(simplified()->NumberLessThan(), value_instance_type,
1255 : jsgraph()->Constant(FIRST_JS_RECEIVER_TYPE));
1256 : Node* branch10 =
1257 674 : graph()->NewNode(common()->Branch(BranchHint::kTrue), check10, if_true1);
1258 :
1259 : // A primitive value cannot match the {prototype} we're looking for.
1260 674 : if_true1 = graph()->NewNode(common()->IfTrue(), branch10);
1261 674 : vtrue1 = jsgraph()->FalseConstant();
1262 :
1263 674 : 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 674 : 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 674 : Node* on_exception = nullptr;
1275 674 : if (NodeProperties::IsExceptionalCall(node, &on_exception)) {
1276 28 : NodeProperties::ReplaceControlInput(on_exception, vfalse1);
1277 28 : NodeProperties::ReplaceEffectInput(on_exception, efalse1);
1278 28 : if_false1 = graph()->NewNode(common()->IfSuccess(), vfalse1);
1279 28 : Revisit(on_exception);
1280 : }
1281 : }
1282 :
1283 : // Load the {value} prototype.
1284 674 : Node* value_prototype = effect = graph()->NewNode(
1285 1348 : simplified()->LoadField(AccessBuilder::ForMapPrototype()), value_map,
1286 : effect, control);
1287 :
1288 : // Check if we reached the end of {value}s prototype chain.
1289 674 : Node* check2 = graph()->NewNode(simplified()->ReferenceEqual(),
1290 : value_prototype, jsgraph()->NullConstant());
1291 674 : Node* branch2 = graph()->NewNode(common()->Branch(), check2, control);
1292 :
1293 674 : Node* if_true2 = graph()->NewNode(common()->IfTrue(), branch2);
1294 : Node* etrue2 = effect;
1295 674 : Node* vtrue2 = jsgraph()->FalseConstant();
1296 :
1297 674 : control = graph()->NewNode(common()->IfFalse(), branch2);
1298 :
1299 : // Check if we reached the {prototype}.
1300 674 : Node* check3 = graph()->NewNode(simplified()->ReferenceEqual(),
1301 : value_prototype, prototype);
1302 674 : Node* branch3 = graph()->NewNode(common()->Branch(), check3, control);
1303 :
1304 674 : Node* if_true3 = graph()->NewNode(common()->IfTrue(), branch3);
1305 : Node* etrue3 = effect;
1306 674 : Node* vtrue3 = jsgraph()->TrueConstant();
1307 :
1308 674 : control = graph()->NewNode(common()->IfFalse(), branch3);
1309 :
1310 : // Close the loop.
1311 674 : vloop->ReplaceInput(1, value_prototype);
1312 674 : eloop->ReplaceInput(1, effect);
1313 674 : loop->ReplaceInput(1, control);
1314 :
1315 674 : control = graph()->NewNode(common()->Merge(5), if_true0, if_true1, if_true2,
1316 : if_true3, if_false1);
1317 674 : 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 674 : node->ReplaceInput(0, vtrue0);
1323 674 : node->ReplaceInput(1, vtrue1);
1324 674 : node->ReplaceInput(2, vtrue2);
1325 674 : node->ReplaceInput(3, vtrue3);
1326 674 : node->ReplaceInput(4, vfalse1);
1327 674 : node->ReplaceInput(5, control);
1328 674 : node->TrimInputCount(6);
1329 674 : NodeProperties::ChangeOp(node,
1330 674 : common()->Phi(MachineRepresentation::kTagged, 5));
1331 : return Changed(node);
1332 : }
1333 :
1334 110 : Reduction JSTypedLowering::ReduceJSOrdinaryHasInstance(Node* node) {
1335 : DCHECK_EQ(IrOpcode::kJSOrdinaryHasInstance, node->opcode());
1336 110 : Node* constructor = NodeProperties::GetValueInput(node, 0);
1337 110 : Type constructor_type = NodeProperties::GetType(constructor);
1338 110 : Node* object = NodeProperties::GetValueInput(node, 1);
1339 110 : 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 110 : 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 124 : 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 302264 : Reduction JSTypedLowering::ReduceJSLoadContext(Node* node) {
1363 : DCHECK_EQ(IrOpcode::kJSLoadContext, node->opcode());
1364 302264 : ContextAccess const& access = ContextAccessOf(node->op());
1365 302264 : Node* effect = NodeProperties::GetEffectInput(node);
1366 302264 : Node* context = NodeProperties::GetContextInput(node);
1367 : Node* control = graph()->start();
1368 317844 : for (size_t i = 0; i < access.depth(); ++i) {
1369 7790 : context = effect = graph()->NewNode(
1370 : simplified()->LoadField(
1371 15580 : AccessBuilder::ForContextSlot(Context::PREVIOUS_INDEX)),
1372 : context, effect, control);
1373 : }
1374 302264 : node->ReplaceInput(0, context);
1375 302264 : node->ReplaceInput(1, effect);
1376 302264 : node->AppendInput(jsgraph()->zone(), control);
1377 302264 : NodeProperties::ChangeOp(
1378 : node,
1379 604528 : simplified()->LoadField(AccessBuilder::ForContextSlot(access.index())));
1380 302264 : return Changed(node);
1381 : }
1382 :
1383 450771 : Reduction JSTypedLowering::ReduceJSStoreContext(Node* node) {
1384 : DCHECK_EQ(IrOpcode::kJSStoreContext, node->opcode());
1385 450771 : ContextAccess const& access = ContextAccessOf(node->op());
1386 450771 : Node* effect = NodeProperties::GetEffectInput(node);
1387 450771 : Node* context = NodeProperties::GetContextInput(node);
1388 : Node* control = graph()->start();
1389 450771 : Node* value = NodeProperties::GetValueInput(node, 0);
1390 451187 : for (size_t i = 0; i < access.depth(); ++i) {
1391 208 : context = effect = graph()->NewNode(
1392 : simplified()->LoadField(
1393 416 : AccessBuilder::ForContextSlot(Context::PREVIOUS_INDEX)),
1394 : context, effect, control);
1395 : }
1396 450771 : node->ReplaceInput(0, context);
1397 450771 : node->ReplaceInput(1, value);
1398 450771 : node->ReplaceInput(2, effect);
1399 450771 : NodeProperties::ChangeOp(
1400 : node,
1401 901542 : simplified()->StoreField(AccessBuilder::ForContextSlot(access.index())));
1402 450771 : return Changed(node);
1403 : }
1404 :
1405 7242 : Node* JSTypedLowering::BuildGetModuleCell(Node* node) {
1406 : DCHECK(node->opcode() == IrOpcode::kJSLoadModule ||
1407 : node->opcode() == IrOpcode::kJSStoreModule);
1408 7242 : Node* effect = NodeProperties::GetEffectInput(node);
1409 7242 : Node* control = NodeProperties::GetControlInput(node);
1410 :
1411 7242 : int32_t cell_index = OpParameter<int32_t>(node->op());
1412 7242 : Node* module = NodeProperties::GetValueInput(node, 0);
1413 7242 : Type module_type = NodeProperties::GetType(module);
1414 :
1415 7242 : if (module_type.IsHeapConstant()) {
1416 138 : ModuleRef module_constant = module_type.AsHeapConstant()->Ref().AsModule();
1417 138 : CellRef cell_constant = module_constant.GetCell(cell_index);
1418 138 : return jsgraph()->Constant(cell_constant);
1419 : }
1420 :
1421 : FieldAccess field_access;
1422 : int index;
1423 7104 : if (ModuleDescriptor::GetCellIndexKind(cell_index) ==
1424 : ModuleDescriptor::kExport) {
1425 7001 : field_access = AccessBuilder::ForModuleRegularExports();
1426 7001 : index = cell_index - 1;
1427 : } else {
1428 : DCHECK_EQ(ModuleDescriptor::GetCellIndexKind(cell_index),
1429 : ModuleDescriptor::kImport);
1430 103 : field_access = AccessBuilder::ForModuleRegularImports();
1431 103 : index = -cell_index - 1;
1432 : }
1433 7104 : Node* array = effect = graph()->NewNode(simplified()->LoadField(field_access),
1434 : module, effect, control);
1435 7104 : return graph()->NewNode(
1436 14208 : simplified()->LoadField(AccessBuilder::ForFixedArraySlot(index)), array,
1437 : effect, control);
1438 : }
1439 :
1440 294 : Reduction JSTypedLowering::ReduceJSLoadModule(Node* node) {
1441 : DCHECK_EQ(IrOpcode::kJSLoadModule, node->opcode());
1442 294 : Node* effect = NodeProperties::GetEffectInput(node);
1443 294 : Node* control = NodeProperties::GetControlInput(node);
1444 :
1445 294 : Node* cell = BuildGetModuleCell(node);
1446 294 : if (cell->op()->EffectOutputCount() > 0) effect = cell;
1447 : Node* value = effect =
1448 588 : graph()->NewNode(simplified()->LoadField(AccessBuilder::ForCellValue()),
1449 : cell, effect, control);
1450 :
1451 : ReplaceWithValue(node, value, effect, control);
1452 294 : return Changed(value);
1453 : }
1454 :
1455 6948 : Reduction JSTypedLowering::ReduceJSStoreModule(Node* node) {
1456 : DCHECK_EQ(IrOpcode::kJSStoreModule, node->opcode());
1457 6948 : Node* effect = NodeProperties::GetEffectInput(node);
1458 6948 : Node* control = NodeProperties::GetControlInput(node);
1459 6948 : Node* value = NodeProperties::GetValueInput(node, 1);
1460 : DCHECK_EQ(
1461 : ModuleDescriptor::GetCellIndexKind(OpParameter<int32_t>(node->op())),
1462 : ModuleDescriptor::kExport);
1463 :
1464 6948 : Node* cell = BuildGetModuleCell(node);
1465 6948 : if (cell->op()->EffectOutputCount() > 0) effect = cell;
1466 : effect =
1467 13896 : graph()->NewNode(simplified()->StoreField(AccessBuilder::ForCellValue()),
1468 : cell, value, effect, control);
1469 :
1470 : ReplaceWithValue(node, effect, effect, control);
1471 6948 : return Changed(value);
1472 : }
1473 :
1474 : namespace {
1475 :
1476 2739 : 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 2739 : Node* target = NodeProperties::GetValueInput(node, 0);
1501 : Node* new_target = is_construct
1502 0 : ? NodeProperties::GetValueInput(node, arity + 1)
1503 2739 : : 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 2739 : const bool has_builtin_exit_frame = Builtins::IsCpp(builtin_index);
1508 :
1509 2739 : Node* stub = jsgraph->CEntryStubConstant(1, kDontSaveFPRegs, kArgvOnStack,
1510 2739 : has_builtin_exit_frame);
1511 2739 : node->ReplaceInput(0, stub);
1512 :
1513 : Zone* zone = jsgraph->zone();
1514 2739 : 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 2739 : const int argc = arity + BuiltinArguments::kNumExtraArgsWithReceiver;
1523 2739 : Node* argc_node = jsgraph->Constant(argc);
1524 :
1525 : static const int kStubAndReceiver = 2;
1526 2739 : int cursor = arity + kStubAndReceiver;
1527 2739 : node->InsertInput(zone, cursor++, jsgraph->PaddingConstant());
1528 2739 : node->InsertInput(zone, cursor++, argc_node);
1529 2739 : node->InsertInput(zone, cursor++, target);
1530 2739 : node->InsertInput(zone, cursor++, new_target);
1531 :
1532 2739 : Address entry = Builtins::CppEntryOf(builtin_index);
1533 2739 : ExternalReference entry_ref = ExternalReference::Create(entry);
1534 2739 : Node* entry_node = jsgraph->ExternalConstant(entry_ref);
1535 :
1536 2739 : node->InsertInput(zone, cursor++, entry_node);
1537 2739 : node->InsertInput(zone, cursor++, argc_node);
1538 :
1539 : static const int kReturnCount = 1;
1540 2739 : const char* debug_name = Builtins::name(builtin_index);
1541 2739 : Operator::Properties properties = node->op()->properties();
1542 : auto call_descriptor = Linkage::GetCEntryStubCallDescriptor(
1543 2739 : zone, kReturnCount, argc, debug_name, properties, flags);
1544 :
1545 2739 : NodeProperties::ChangeOp(node, jsgraph->common()->Call(call_descriptor));
1546 2739 : }
1547 :
1548 : bool NeedsArgumentAdaptorFrame(SharedFunctionInfoRef shared, int arity) {
1549 : static const int sentinel = SharedFunctionInfo::kDontAdaptArgumentsSentinel;
1550 28070 : const int num_decl_parms = shared.internal_formal_parameter_count();
1551 28070 : return (num_decl_parms != arity && num_decl_parms != sentinel);
1552 : }
1553 :
1554 : } // namespace
1555 :
1556 469 : Reduction JSTypedLowering::ReduceJSConstructForwardVarargs(Node* node) {
1557 : DCHECK_EQ(IrOpcode::kJSConstructForwardVarargs, node->opcode());
1558 : ConstructForwardVarargsParameters p =
1559 469 : ConstructForwardVarargsParametersOf(node->op());
1560 : DCHECK_LE(2u, p.arity());
1561 469 : int const arity = static_cast<int>(p.arity() - 2);
1562 469 : int const start_index = static_cast<int>(p.start_index());
1563 469 : Node* target = NodeProperties::GetValueInput(node, 0);
1564 469 : Type target_type = NodeProperties::GetType(target);
1565 469 : Node* new_target = NodeProperties::GetValueInput(node, arity + 1);
1566 :
1567 : // Check if {target} is a JSFunction.
1568 899 : if (target_type.IsHeapConstant() &&
1569 430 : target_type.AsHeapConstant()->Ref().IsJSFunction()) {
1570 : // Only optimize [[Construct]] here if {function} is a Constructor.
1571 429 : JSFunctionRef function = target_type.AsHeapConstant()->Ref().AsJSFunction();
1572 429 : if (!function.map().is_constructor()) return NoChange();
1573 : // Patch {node} to an indirect call via ConstructFunctionForwardVarargs.
1574 429 : Callable callable = CodeFactory::ConstructFunctionForwardVarargs(isolate());
1575 429 : node->RemoveInput(arity + 1);
1576 858 : node->InsertInput(graph()->zone(), 0,
1577 429 : jsgraph()->HeapConstant(callable.code()));
1578 429 : node->InsertInput(graph()->zone(), 2, new_target);
1579 429 : node->InsertInput(graph()->zone(), 3, jsgraph()->Constant(arity));
1580 429 : node->InsertInput(graph()->zone(), 4, jsgraph()->Constant(start_index));
1581 429 : node->InsertInput(graph()->zone(), 5, jsgraph()->UndefinedConstant());
1582 429 : NodeProperties::ChangeOp(
1583 858 : node, common()->Call(Linkage::GetStubCallDescriptor(
1584 429 : graph()->zone(), callable.descriptor(), arity + 1,
1585 429 : CallDescriptor::kNeedsFrameState)));
1586 : return Changed(node);
1587 : }
1588 :
1589 : return NoChange();
1590 : }
1591 :
1592 35545 : Reduction JSTypedLowering::ReduceJSConstruct(Node* node) {
1593 : DCHECK_EQ(IrOpcode::kJSConstruct, node->opcode());
1594 35545 : ConstructParameters const& p = ConstructParametersOf(node->op());
1595 : DCHECK_LE(2u, p.arity());
1596 35545 : int const arity = static_cast<int>(p.arity() - 2);
1597 35545 : Node* target = NodeProperties::GetValueInput(node, 0);
1598 35545 : Type target_type = NodeProperties::GetType(target);
1599 35545 : Node* new_target = NodeProperties::GetValueInput(node, arity + 1);
1600 :
1601 : // Check if {target} is a known JSFunction.
1602 39402 : if (target_type.IsHeapConstant() &&
1603 3857 : target_type.AsHeapConstant()->Ref().IsJSFunction()) {
1604 3101 : JSFunctionRef function = target_type.AsHeapConstant()->Ref().AsJSFunction();
1605 3101 : SharedFunctionInfoRef shared = function.shared();
1606 :
1607 : // Only optimize [[Construct]] here if {function} is a Constructor.
1608 3101 : 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 3100 : 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 6200 : : BUILTIN_CODE(isolate(), JSConstructStubGeneric));
1619 :
1620 3100 : node->RemoveInput(arity + 1);
1621 3100 : node->InsertInput(graph()->zone(), 0, jsgraph()->Constant(code));
1622 3100 : node->InsertInput(graph()->zone(), 2, new_target);
1623 3100 : node->InsertInput(graph()->zone(), 3, jsgraph()->Constant(arity));
1624 3100 : node->InsertInput(graph()->zone(), 4, jsgraph()->UndefinedConstant());
1625 3100 : node->InsertInput(graph()->zone(), 5, jsgraph()->UndefinedConstant());
1626 3100 : NodeProperties::ChangeOp(
1627 : node,
1628 6200 : common()->Call(Linkage::GetStubCallDescriptor(
1629 3100 : graph()->zone(), ConstructStubDescriptor{}, 1 + arity, flags)));
1630 :
1631 : return Changed(node);
1632 : }
1633 :
1634 : return NoChange();
1635 : }
1636 :
1637 374 : Reduction JSTypedLowering::ReduceJSCallForwardVarargs(Node* node) {
1638 : DCHECK_EQ(IrOpcode::kJSCallForwardVarargs, node->opcode());
1639 374 : CallForwardVarargsParameters p = CallForwardVarargsParametersOf(node->op());
1640 : DCHECK_LE(2u, p.arity());
1641 374 : int const arity = static_cast<int>(p.arity() - 2);
1642 374 : int const start_index = static_cast<int>(p.start_index());
1643 374 : Node* target = NodeProperties::GetValueInput(node, 0);
1644 374 : Type target_type = NodeProperties::GetType(target);
1645 :
1646 : // Check if {target} is a JSFunction.
1647 374 : 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 299 : Callable callable = CodeFactory::CallFunctionForwardVarargs(isolate());
1652 598 : node->InsertInput(graph()->zone(), 0,
1653 299 : jsgraph()->HeapConstant(callable.code()));
1654 299 : node->InsertInput(graph()->zone(), 2, jsgraph()->Constant(arity));
1655 299 : node->InsertInput(graph()->zone(), 3, jsgraph()->Constant(start_index));
1656 299 : NodeProperties::ChangeOp(
1657 897 : node, common()->Call(Linkage::GetStubCallDescriptor(
1658 598 : graph()->zone(), callable.descriptor(), arity + 1, flags)));
1659 : return Changed(node);
1660 : }
1661 :
1662 : return NoChange();
1663 : }
1664 :
1665 489464 : Reduction JSTypedLowering::ReduceJSCall(Node* node) {
1666 : DCHECK_EQ(IrOpcode::kJSCall, node->opcode());
1667 489464 : CallParameters const& p = CallParametersOf(node->op());
1668 489465 : int arity = static_cast<int>(p.arity() - 2);
1669 : ConvertReceiverMode convert_mode = p.convert_mode();
1670 489465 : Node* target = NodeProperties::GetValueInput(node, 0);
1671 489465 : Type target_type = NodeProperties::GetType(target);
1672 489465 : Node* receiver = NodeProperties::GetValueInput(node, 1);
1673 489465 : Type receiver_type = NodeProperties::GetType(receiver);
1674 489465 : Node* effect = NodeProperties::GetEffectInput(node);
1675 489464 : Node* control = NodeProperties::GetControlInput(node);
1676 :
1677 : // Try to infer receiver {convert_mode} from {receiver} type.
1678 489464 : if (receiver_type.Is(Type::NullOrUndefined())) {
1679 : convert_mode = ConvertReceiverMode::kNullOrUndefined;
1680 159557 : } else if (!receiver_type.Maybe(Type::NullOrUndefined())) {
1681 : convert_mode = ConvertReceiverMode::kNotNullOrUndefined;
1682 : }
1683 :
1684 : // Check if {target} is a known JSFunction.
1685 517780 : if (target_type.IsHeapConstant() &&
1686 28316 : target_type.AsHeapConstant()->Ref().IsJSFunction()) {
1687 28089 : JSFunctionRef function = target_type.AsHeapConstant()->Ref().AsJSFunction();
1688 28089 : SharedFunctionInfoRef shared = function.shared();
1689 :
1690 28089 : 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 56142 : 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 73566 : if (is_sloppy(shared.language_mode()) && !shared.native() &&
1702 : !receiver_type.Is(Type::Receiver())) {
1703 17374 : if (!function.native_context().equals(broker()->native_context())) {
1704 : return NoChange();
1705 : }
1706 : Node* global_proxy =
1707 17374 : jsgraph()->Constant(function.native_context().global_proxy_object());
1708 : receiver = effect =
1709 17374 : graph()->NewNode(simplified()->ConvertReceiver(convert_mode),
1710 : receiver, global_proxy, effect, control);
1711 17374 : NodeProperties::ReplaceValueInput(node, receiver, 1);
1712 : }
1713 :
1714 : // Load the context from the {target}.
1715 28070 : Node* context = effect = graph()->NewNode(
1716 56140 : simplified()->LoadField(AccessBuilder::ForJSFunctionContext()), target,
1717 : effect, control);
1718 28070 : NodeProperties::ReplaceContextInput(node, context);
1719 :
1720 : // Update the effect dependency for the {node}.
1721 28070 : NodeProperties::ReplaceEffectInput(node, effect);
1722 :
1723 : // Compute flags for the call.
1724 : CallDescriptor::Flags flags = CallDescriptor::kNeedsFrameState;
1725 28070 : Node* new_target = jsgraph()->UndefinedConstant();
1726 :
1727 28070 : 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 4073 : 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 52 : int expected_argument_count = shared.internal_formal_parameter_count();
1741 150 : for (; arity > expected_argument_count; --arity) {
1742 49 : node->RemoveInput(arity + 1);
1743 : }
1744 58 : for (; arity < expected_argument_count; ++arity) {
1745 3 : node->InsertInput(graph()->zone(), arity + 2,
1746 3 : jsgraph()->UndefinedConstant());
1747 : }
1748 :
1749 : // Patch {node} to a direct call.
1750 52 : node->InsertInput(graph()->zone(), arity + 2, new_target);
1751 52 : node->InsertInput(graph()->zone(), arity + 3,
1752 52 : jsgraph()->Constant(arity));
1753 52 : NodeProperties::ChangeOp(node,
1754 52 : common()->Call(Linkage::GetJSCallDescriptor(
1755 : graph()->zone(), false, 1 + arity,
1756 52 : flags | CallDescriptor::kCanUseRoots)));
1757 : } else {
1758 : // Patch {node} to an indirect call via the ArgumentsAdaptorTrampoline.
1759 4021 : Callable callable = CodeFactory::ArgumentAdaptor(isolate());
1760 8042 : node->InsertInput(graph()->zone(), 0,
1761 4021 : jsgraph()->HeapConstant(callable.code()));
1762 4021 : node->InsertInput(graph()->zone(), 2, new_target);
1763 4021 : node->InsertInput(graph()->zone(), 3, jsgraph()->Constant(arity));
1764 4021 : node->InsertInput(
1765 : graph()->zone(), 4,
1766 8042 : jsgraph()->Constant(shared.internal_formal_parameter_count()));
1767 4021 : NodeProperties::ChangeOp(
1768 : node,
1769 12063 : common()->Call(Linkage::GetStubCallDescriptor(
1770 8042 : graph()->zone(), callable.descriptor(), 1 + arity, flags)));
1771 : }
1772 33061 : } else if (shared.HasBuiltinId() &&
1773 9064 : Builtins::HasCppImplementation(shared.builtin_id())) {
1774 : // Patch {node} to a direct CEntry call.
1775 2739 : ReduceBuiltin(jsgraph(), node, shared.builtin_id(), arity, flags);
1776 27583 : } else if (shared.HasBuiltinId() &&
1777 6325 : Builtins::KindOf(shared.builtin_id()) == Builtins::TFJ) {
1778 : // Patch {node} to a direct code object call.
1779 : Callable callable = Builtins::CallableFor(
1780 6325 : isolate(), static_cast<Builtins::Name>(shared.builtin_id()));
1781 : CallDescriptor::Flags flags = CallDescriptor::kNeedsFrameState;
1782 :
1783 : const CallInterfaceDescriptor& descriptor = callable.descriptor();
1784 12650 : auto call_descriptor = Linkage::GetStubCallDescriptor(
1785 6325 : graph()->zone(), descriptor, 1 + arity, flags);
1786 6325 : Node* stub_code = jsgraph()->HeapConstant(callable.code());
1787 6325 : node->InsertInput(graph()->zone(), 0, stub_code); // Code object.
1788 6325 : node->InsertInput(graph()->zone(), 2, new_target);
1789 6325 : node->InsertInput(graph()->zone(), 3, jsgraph()->Constant(arity));
1790 6325 : NodeProperties::ChangeOp(node, common()->Call(call_descriptor));
1791 : } else {
1792 : // Patch {node} to a direct call.
1793 14933 : node->InsertInput(graph()->zone(), arity + 2, new_target);
1794 14933 : node->InsertInput(graph()->zone(), arity + 3, jsgraph()->Constant(arity));
1795 14933 : NodeProperties::ChangeOp(node,
1796 14933 : common()->Call(Linkage::GetJSCallDescriptor(
1797 : graph()->zone(), false, 1 + arity,
1798 14933 : flags | CallDescriptor::kCanUseRoots)));
1799 : }
1800 : return Changed(node);
1801 : }
1802 :
1803 : // Check if {target} is a JSFunction.
1804 461375 : 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 22847 : Callable callable = CodeFactory::CallFunction(isolate(), convert_mode);
1809 45696 : node->InsertInput(graph()->zone(), 0,
1810 22848 : jsgraph()->HeapConstant(callable.code()));
1811 22848 : node->InsertInput(graph()->zone(), 2, jsgraph()->Constant(arity));
1812 22847 : NodeProperties::ChangeOp(
1813 68542 : node, common()->Call(Linkage::GetStubCallDescriptor(
1814 45693 : 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 438528 : if (p.convert_mode() != convert_mode) {
1820 133568 : NodeProperties::ChangeOp(
1821 : node, javascript()->Call(p.arity(), p.frequency(), p.feedback(),
1822 133568 : convert_mode, p.speculation_mode()));
1823 : return Changed(node);
1824 : }
1825 :
1826 : return NoChange();
1827 : }
1828 :
1829 1548 : Reduction JSTypedLowering::ReduceJSForInNext(Node* node) {
1830 : DCHECK_EQ(IrOpcode::kJSForInNext, node->opcode());
1831 1548 : ForInMode const mode = ForInModeOf(node->op());
1832 1548 : Node* receiver = NodeProperties::GetValueInput(node, 0);
1833 1548 : Node* cache_array = NodeProperties::GetValueInput(node, 1);
1834 1548 : Node* cache_type = NodeProperties::GetValueInput(node, 2);
1835 1548 : Node* index = NodeProperties::GetValueInput(node, 3);
1836 1548 : Node* context = NodeProperties::GetContextInput(node);
1837 1548 : Node* frame_state = NodeProperties::GetFrameStateInput(node);
1838 1548 : Node* effect = NodeProperties::GetEffectInput(node);
1839 1548 : Node* control = NodeProperties::GetControlInput(node);
1840 :
1841 : // Load the map of the {receiver}.
1842 : Node* receiver_map = effect =
1843 3096 : graph()->NewNode(simplified()->LoadField(AccessBuilder::ForMap()),
1844 : receiver, effect, control);
1845 :
1846 1548 : switch (mode) {
1847 : case ForInMode::kUseEnumCacheKeys:
1848 : case ForInMode::kUseEnumCacheKeysAndIndices: {
1849 : // Ensure that the expected map still matches that of the {receiver}.
1850 983 : Node* check = graph()->NewNode(simplified()->ReferenceEqual(),
1851 : receiver_map, cache_type);
1852 : effect =
1853 1966 : 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 983 : node->ReplaceInput(0, cache_array);
1862 983 : node->ReplaceInput(1, index);
1863 983 : node->ReplaceInput(2, effect);
1864 983 : node->ReplaceInput(3, control);
1865 983 : node->TrimInputCount(4);
1866 983 : NodeProperties::ChangeOp(
1867 : node,
1868 1966 : 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 565 : Node* key = effect = graph()->NewNode(
1875 1130 : simplified()->LoadElement(AccessBuilder::ForFixedArrayElement()),
1876 : cache_array, index, effect, control);
1877 :
1878 : // Check if the expected map still matches that of the {receiver}.
1879 565 : Node* check = graph()->NewNode(simplified()->ReferenceEqual(),
1880 : receiver_map, cache_type);
1881 : Node* branch =
1882 565 : graph()->NewNode(common()->Branch(BranchHint::kTrue), check, control);
1883 :
1884 565 : 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 565 : 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 565 : Builtins::CallableFor(isolate(), Builtins::kForInFilter);
1902 565 : auto call_descriptor = Linkage::GetStubCallDescriptor(
1903 565 : graph()->zone(), callable.descriptor(),
1904 : callable.descriptor().GetStackParameterCount(),
1905 565 : CallDescriptor::kNeedsFrameState);
1906 : vfalse = efalse = if_false =
1907 1130 : 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 565 : Node* if_exception = nullptr;
1914 565 : if (NodeProperties::IsExceptionalCall(node, &if_exception)) {
1915 162 : if_false = graph()->NewNode(common()->IfSuccess(), vfalse);
1916 162 : NodeProperties::ReplaceControlInput(if_exception, vfalse);
1917 162 : NodeProperties::ReplaceEffectInput(if_exception, efalse);
1918 162 : Revisit(if_exception);
1919 : }
1920 : }
1921 :
1922 565 : control = graph()->NewNode(common()->Merge(2), if_true, if_false);
1923 565 : effect = graph()->NewNode(common()->EffectPhi(2), etrue, efalse, control);
1924 : ReplaceWithValue(node, node, effect, control);
1925 :
1926 : // Morph the {node} into a Phi.
1927 565 : node->ReplaceInput(0, vtrue);
1928 565 : node->ReplaceInput(1, vfalse);
1929 565 : node->ReplaceInput(2, control);
1930 565 : node->TrimInputCount(3);
1931 565 : NodeProperties::ChangeOp(
1932 565 : node, common()->Phi(MachineRepresentation::kTagged, 2));
1933 : }
1934 : }
1935 :
1936 1548 : return Changed(node);
1937 : }
1938 :
1939 1371 : Reduction JSTypedLowering::ReduceJSForInPrepare(Node* node) {
1940 : DCHECK_EQ(IrOpcode::kJSForInPrepare, node->opcode());
1941 1371 : ForInMode const mode = ForInModeOf(node->op());
1942 1371 : Node* enumerator = NodeProperties::GetValueInput(node, 0);
1943 1371 : Node* effect = NodeProperties::GetEffectInput(node);
1944 1371 : Node* control = NodeProperties::GetControlInput(node);
1945 : Node* cache_type = enumerator;
1946 : Node* cache_array = nullptr;
1947 : Node* cache_length = nullptr;
1948 :
1949 1371 : switch (mode) {
1950 : case ForInMode::kUseEnumCacheKeys:
1951 : case ForInMode::kUseEnumCacheKeysAndIndices: {
1952 : // Check that the {enumerator} is a Map.
1953 2844 : 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 948 : Node* descriptor_array = effect = graph()->NewNode(
1960 1896 : simplified()->LoadField(AccessBuilder::ForMapDescriptors()),
1961 : enumerator, effect, control);
1962 948 : Node* enum_cache = effect = graph()->NewNode(
1963 1896 : simplified()->LoadField(AccessBuilder::ForDescriptorArrayEnumCache()),
1964 : descriptor_array, effect, control);
1965 948 : cache_array = effect = graph()->NewNode(
1966 1896 : simplified()->LoadField(AccessBuilder::ForEnumCacheKeys()),
1967 : enum_cache, effect, control);
1968 :
1969 : // Load the enum length of the {enumerator} map.
1970 948 : Node* bit_field3 = effect = graph()->NewNode(
1971 1896 : simplified()->LoadField(AccessBuilder::ForMapBitField3()), enumerator,
1972 : effect, control);
1973 : STATIC_ASSERT(Map::EnumLengthBits::kShift == 0);
1974 : cache_length =
1975 948 : graph()->NewNode(simplified()->NumberBitwiseAnd(), bit_field3,
1976 : jsgraph()->Constant(Map::EnumLengthBits::kMask));
1977 948 : break;
1978 : }
1979 : case ForInMode::kGeneric: {
1980 : // Check if the {enumerator} is a Map or a FixedArray.
1981 846 : Node* check = effect = graph()->NewNode(
1982 : simplified()->CompareMaps(ZoneHandleSet<Map>(factory()->meta_map())),
1983 : enumerator, effect, control);
1984 : Node* branch =
1985 423 : graph()->NewNode(common()->Branch(BranchHint::kTrue), check, control);
1986 :
1987 423 : 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 423 : Node* descriptor_array = etrue = graph()->NewNode(
1994 846 : simplified()->LoadField(AccessBuilder::ForMapDescriptors()),
1995 : enumerator, etrue, if_true);
1996 : Node* enum_cache = etrue =
1997 423 : graph()->NewNode(simplified()->LoadField(
1998 846 : AccessBuilder::ForDescriptorArrayEnumCache()),
1999 : descriptor_array, etrue, if_true);
2000 423 : cache_array_true = etrue = graph()->NewNode(
2001 846 : simplified()->LoadField(AccessBuilder::ForEnumCacheKeys()),
2002 : enum_cache, etrue, if_true);
2003 :
2004 : // Load the enum length of the {enumerator} map.
2005 423 : Node* bit_field3 = etrue = graph()->NewNode(
2006 846 : simplified()->LoadField(AccessBuilder::ForMapBitField3()),
2007 : enumerator, etrue, if_true);
2008 : STATIC_ASSERT(Map::EnumLengthBits::kShift == 0);
2009 : cache_length_true =
2010 423 : graph()->NewNode(simplified()->NumberBitwiseAnd(), bit_field3,
2011 : jsgraph()->Constant(Map::EnumLengthBits::kMask));
2012 : }
2013 :
2014 423 : 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 423 : cache_length_false = efalse = graph()->NewNode(
2022 846 : simplified()->LoadField(AccessBuilder::ForFixedArrayLength()),
2023 : cache_array_false, efalse, if_false);
2024 : }
2025 :
2026 : // Rewrite the uses of the {node}.
2027 423 : control = graph()->NewNode(common()->Merge(2), if_true, if_false);
2028 423 : effect = graph()->NewNode(common()->EffectPhi(2), etrue, efalse, control);
2029 : cache_array =
2030 423 : graph()->NewNode(common()->Phi(MachineRepresentation::kTagged, 2),
2031 : cache_array_true, cache_array_false, control);
2032 : cache_length =
2033 423 : graph()->NewNode(common()->Phi(MachineRepresentation::kTagged, 2),
2034 : cache_length_true, cache_length_false, control);
2035 423 : break;
2036 : }
2037 : }
2038 :
2039 : // Update the uses of {node}.
2040 23307 : for (Edge edge : node->use_edges()) {
2041 : Node* const user = edge.from();
2042 10968 : if (NodeProperties::IsEffectEdge(edge)) {
2043 1371 : edge.UpdateTo(effect);
2044 : Revisit(user);
2045 9597 : } else if (NodeProperties::IsControlEdge(edge)) {
2046 5484 : edge.UpdateTo(control);
2047 : Revisit(user);
2048 : } else {
2049 : DCHECK(NodeProperties::IsValueEdge(edge));
2050 4113 : 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 1371 : node->Kill();
2066 1371 : return Replace(effect);
2067 : }
2068 :
2069 29935 : Reduction JSTypedLowering::ReduceJSLoadMessage(Node* node) {
2070 : DCHECK_EQ(IrOpcode::kJSLoadMessage, node->opcode());
2071 : ExternalReference const ref =
2072 29935 : ExternalReference::address_of_pending_message_obj(isolate());
2073 29935 : node->ReplaceInput(0, jsgraph()->ExternalConstant(ref));
2074 29935 : NodeProperties::ChangeOp(node, simplified()->LoadMessage());
2075 29935 : return Changed(node);
2076 : }
2077 :
2078 29937 : Reduction JSTypedLowering::ReduceJSStoreMessage(Node* node) {
2079 : DCHECK_EQ(IrOpcode::kJSStoreMessage, node->opcode());
2080 : ExternalReference const ref =
2081 29937 : ExternalReference::address_of_pending_message_obj(isolate());
2082 29937 : Node* value = NodeProperties::GetValueInput(node, 0);
2083 29937 : node->ReplaceInput(0, jsgraph()->ExternalConstant(ref));
2084 29937 : node->ReplaceInput(1, value);
2085 29937 : NodeProperties::ChangeOp(node, simplified()->StoreMessage());
2086 29937 : return Changed(node);
2087 : }
2088 :
2089 6150 : Reduction JSTypedLowering::ReduceJSGeneratorStore(Node* node) {
2090 : DCHECK_EQ(IrOpcode::kJSGeneratorStore, node->opcode());
2091 6150 : Node* generator = NodeProperties::GetValueInput(node, 0);
2092 6150 : Node* continuation = NodeProperties::GetValueInput(node, 1);
2093 6150 : Node* offset = NodeProperties::GetValueInput(node, 2);
2094 6150 : Node* context = NodeProperties::GetContextInput(node);
2095 6150 : Node* effect = NodeProperties::GetEffectInput(node);
2096 6150 : Node* control = NodeProperties::GetControlInput(node);
2097 6150 : int value_count = GeneratorStoreValueCountOf(node->op());
2098 :
2099 : FieldAccess array_field =
2100 6150 : AccessBuilder::ForJSGeneratorObjectParametersAndRegisters();
2101 6150 : FieldAccess context_field = AccessBuilder::ForJSGeneratorObjectContext();
2102 : FieldAccess continuation_field =
2103 6150 : AccessBuilder::ForJSGeneratorObjectContinuation();
2104 : FieldAccess input_or_debug_pos_field =
2105 6150 : AccessBuilder::ForJSGeneratorObjectInputOrDebugPos();
2106 :
2107 6150 : Node* array = effect = graph()->NewNode(simplified()->LoadField(array_field),
2108 : generator, effect, control);
2109 :
2110 55906 : for (int i = 0; i < value_count; ++i) {
2111 24878 : Node* value = NodeProperties::GetValueInput(node, 3 + i);
2112 24878 : if (value != jsgraph()->OptimizedOutConstant()) {
2113 16312 : effect = graph()->NewNode(
2114 32624 : simplified()->StoreField(AccessBuilder::ForFixedArraySlot(i)), array,
2115 : value, effect, control);
2116 : }
2117 : }
2118 :
2119 6150 : effect = graph()->NewNode(simplified()->StoreField(context_field), generator,
2120 : context, effect, control);
2121 6150 : effect = graph()->NewNode(simplified()->StoreField(continuation_field),
2122 : generator, continuation, effect, control);
2123 6150 : effect = graph()->NewNode(simplified()->StoreField(input_or_debug_pos_field),
2124 : generator, offset, effect, control);
2125 :
2126 : ReplaceWithValue(node, effect, effect, control);
2127 6150 : return Changed(effect);
2128 : }
2129 :
2130 2004 : Reduction JSTypedLowering::ReduceJSGeneratorRestoreContinuation(Node* node) {
2131 : DCHECK_EQ(IrOpcode::kJSGeneratorRestoreContinuation, node->opcode());
2132 2004 : Node* generator = NodeProperties::GetValueInput(node, 0);
2133 2004 : Node* effect = NodeProperties::GetEffectInput(node);
2134 2004 : Node* control = NodeProperties::GetControlInput(node);
2135 :
2136 : FieldAccess continuation_field =
2137 2004 : AccessBuilder::ForJSGeneratorObjectContinuation();
2138 :
2139 2004 : Node* continuation = effect = graph()->NewNode(
2140 : simplified()->LoadField(continuation_field), generator, effect, control);
2141 2004 : Node* executing = jsgraph()->Constant(JSGeneratorObject::kGeneratorExecuting);
2142 2004 : effect = graph()->NewNode(simplified()->StoreField(continuation_field),
2143 : generator, executing, effect, control);
2144 :
2145 : ReplaceWithValue(node, continuation, effect, control);
2146 2004 : return Changed(continuation);
2147 : }
2148 :
2149 2004 : Reduction JSTypedLowering::ReduceJSGeneratorRestoreContext(Node* node) {
2150 : DCHECK_EQ(IrOpcode::kJSGeneratorRestoreContext, node->opcode());
2151 :
2152 : const Operator* new_op =
2153 2004 : simplified()->LoadField(AccessBuilder::ForJSGeneratorObjectContext());
2154 :
2155 : // Mutate the node in-place.
2156 : DCHECK(OperatorProperties::HasContextInput(node->op()));
2157 : DCHECK(!OperatorProperties::HasContextInput(new_op));
2158 2004 : node->RemoveInput(NodeProperties::FirstContextIndex(node));
2159 :
2160 2004 : NodeProperties::ChangeOp(node, new_op);
2161 2004 : return Changed(node);
2162 : }
2163 :
2164 15314 : Reduction JSTypedLowering::ReduceJSGeneratorRestoreRegister(Node* node) {
2165 : DCHECK_EQ(IrOpcode::kJSGeneratorRestoreRegister, node->opcode());
2166 15314 : Node* generator = NodeProperties::GetValueInput(node, 0);
2167 15314 : Node* effect = NodeProperties::GetEffectInput(node);
2168 15314 : Node* control = NodeProperties::GetControlInput(node);
2169 15314 : int index = RestoreRegisterIndexOf(node->op());
2170 :
2171 : FieldAccess array_field =
2172 15314 : AccessBuilder::ForJSGeneratorObjectParametersAndRegisters();
2173 15314 : FieldAccess element_field = AccessBuilder::ForFixedArraySlot(index);
2174 :
2175 15314 : Node* array = effect = graph()->NewNode(simplified()->LoadField(array_field),
2176 : generator, effect, control);
2177 15314 : Node* element = effect = graph()->NewNode(
2178 : simplified()->LoadField(element_field), array, effect, control);
2179 15314 : Node* stale = jsgraph()->StaleRegisterConstant();
2180 15314 : effect = graph()->NewNode(simplified()->StoreField(element_field), array,
2181 : stale, effect, control);
2182 :
2183 : ReplaceWithValue(node, element, effect, control);
2184 15314 : return Changed(element);
2185 : }
2186 :
2187 6025 : Reduction JSTypedLowering::ReduceJSGeneratorRestoreInputOrDebugPos(Node* node) {
2188 : DCHECK_EQ(IrOpcode::kJSGeneratorRestoreInputOrDebugPos, node->opcode());
2189 :
2190 : FieldAccess input_or_debug_pos_field =
2191 6025 : AccessBuilder::ForJSGeneratorObjectInputOrDebugPos();
2192 6025 : 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 6025 : node->RemoveInput(NodeProperties::FirstContextIndex(node));
2198 :
2199 6025 : NodeProperties::ChangeOp(node, new_op);
2200 6025 : return Changed(node);
2201 : }
2202 :
2203 87 : Reduction JSTypedLowering::ReduceObjectIsArray(Node* node) {
2204 87 : Node* value = NodeProperties::GetValueInput(node, 0);
2205 87 : Type value_type = NodeProperties::GetType(value);
2206 87 : Node* context = NodeProperties::GetContextInput(node);
2207 87 : Node* frame_state = NodeProperties::GetFrameStateInput(node);
2208 87 : Node* effect = NodeProperties::GetEffectInput(node);
2209 87 : Node* control = NodeProperties::GetControlInput(node);
2210 :
2211 : // Constant-fold based on {value} type.
2212 87 : if (value_type.Is(Type::Array())) {
2213 15 : Node* value = jsgraph()->TrueConstant();
2214 : ReplaceWithValue(node, value);
2215 : return Replace(value);
2216 72 : } else if (!value_type.Maybe(Type::ArrayOrProxy())) {
2217 8 : Node* value = jsgraph()->FalseConstant();
2218 : ReplaceWithValue(node, value);
2219 : return Replace(value);
2220 : }
2221 :
2222 : int count = 0;
2223 : Node* values[5];
2224 : Node* effects[5];
2225 : Node* controls[4];
2226 :
2227 : // Check if the {value} is a Smi.
2228 64 : Node* check = graph()->NewNode(simplified()->ObjectIsSmi(), value);
2229 : control =
2230 64 : graph()->NewNode(common()->Branch(BranchHint::kFalse), check, control);
2231 :
2232 : // The {value} is a Smi.
2233 128 : controls[count] = graph()->NewNode(common()->IfTrue(), control);
2234 64 : effects[count] = effect;
2235 64 : values[count] = jsgraph()->FalseConstant();
2236 : count++;
2237 :
2238 64 : control = graph()->NewNode(common()->IfFalse(), control);
2239 :
2240 : // Load the {value}s instance type.
2241 64 : Node* value_map = effect = graph()->NewNode(
2242 128 : simplified()->LoadField(AccessBuilder::ForMap()), value, effect, control);
2243 64 : Node* value_instance_type = effect = graph()->NewNode(
2244 128 : simplified()->LoadField(AccessBuilder::ForMapInstanceType()), value_map,
2245 : effect, control);
2246 :
2247 : // Check if the {value} is a JSArray.
2248 64 : check = graph()->NewNode(simplified()->NumberEqual(), value_instance_type,
2249 : jsgraph()->Constant(JS_ARRAY_TYPE));
2250 64 : control = graph()->NewNode(common()->Branch(), check, control);
2251 :
2252 : // The {value} is a JSArray.
2253 128 : controls[count] = graph()->NewNode(common()->IfTrue(), control);
2254 64 : effects[count] = effect;
2255 64 : values[count] = jsgraph()->TrueConstant();
2256 : count++;
2257 :
2258 64 : control = graph()->NewNode(common()->IfFalse(), control);
2259 :
2260 : // Check if the {value} is a JSProxy.
2261 64 : check = graph()->NewNode(simplified()->NumberEqual(), value_instance_type,
2262 : jsgraph()->Constant(JS_PROXY_TYPE));
2263 : control =
2264 64 : graph()->NewNode(common()->Branch(BranchHint::kFalse), check, control);
2265 :
2266 : // The {value} is neither a JSArray nor a JSProxy.
2267 128 : controls[count] = graph()->NewNode(common()->IfFalse(), control);
2268 64 : effects[count] = effect;
2269 64 : values[count] = jsgraph()->FalseConstant();
2270 : count++;
2271 :
2272 64 : control = graph()->NewNode(common()->IfTrue(), control);
2273 :
2274 : // Let the %ArrayIsArray runtime function deal with the JSProxy {value}.
2275 : value = effect = control =
2276 64 : graph()->NewNode(javascript()->CallRuntime(Runtime::kArrayIsArray), value,
2277 : context, frame_state, effect, control);
2278 : NodeProperties::SetType(value, Type::Boolean());
2279 :
2280 : // Update potential {IfException} uses of {node} to point to the above
2281 : // %ArrayIsArray runtime call node instead.
2282 64 : Node* on_exception = nullptr;
2283 64 : if (NodeProperties::IsExceptionalCall(node, &on_exception)) {
2284 8 : NodeProperties::ReplaceControlInput(on_exception, control);
2285 8 : NodeProperties::ReplaceEffectInput(on_exception, effect);
2286 8 : control = graph()->NewNode(common()->IfSuccess(), control);
2287 8 : Revisit(on_exception);
2288 : }
2289 :
2290 : // The {value} is neither a JSArray nor a JSProxy.
2291 64 : controls[count] = control;
2292 64 : effects[count] = effect;
2293 64 : values[count] = value;
2294 : count++;
2295 :
2296 64 : control = graph()->NewNode(common()->Merge(count), count, controls);
2297 64 : effects[count] = control;
2298 64 : values[count] = control;
2299 64 : effect = graph()->NewNode(common()->EffectPhi(count), count + 1, effects);
2300 64 : value = graph()->NewNode(common()->Phi(MachineRepresentation::kTagged, count),
2301 64 : count + 1, values);
2302 : ReplaceWithValue(node, value, effect, control);
2303 : return Replace(value);
2304 : }
2305 :
2306 193 : Reduction JSTypedLowering::ReduceJSParseInt(Node* node) {
2307 193 : Node* value = NodeProperties::GetValueInput(node, 0);
2308 193 : Type value_type = NodeProperties::GetType(value);
2309 193 : Node* radix = NodeProperties::GetValueInput(node, 1);
2310 193 : 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 618 : if (value_type.Is(type_cache_->kSafeInteger) &&
2314 54 : (radix_type.Is(type_cache_->kTenOrUndefined) ||
2315 15 : radix_type.Is(type_cache_->kZeroOrUndefined))) {
2316 : // Number.parseInt(a:safe-integer) -> a
2317 : // Number.parseInt(a:safe-integer,b:#0\/undefined) -> a
2318 : // Number.parseInt(a:safe-integer,b:#10\/undefined) -> a
2319 : ReplaceWithValue(node, value);
2320 : return Replace(value);
2321 : }
2322 : return NoChange();
2323 : }
2324 :
2325 1004 : Reduction JSTypedLowering::ReduceJSResolvePromise(Node* node) {
2326 : DCHECK_EQ(IrOpcode::kJSResolvePromise, node->opcode());
2327 1004 : Node* resolution = NodeProperties::GetValueInput(node, 1);
2328 1004 : Type resolution_type = NodeProperties::GetType(resolution);
2329 : // We can strength-reduce JSResolvePromise to JSFulfillPromise
2330 : // if the {resolution} is known to be a primitive, as in that
2331 : // case we don't perform the implicit chaining (via "then").
2332 1004 : if (resolution_type.Is(Type::Primitive())) {
2333 : // JSResolvePromise(p,v:primitive) -> JSFulfillPromise(p,v)
2334 721 : node->RemoveInput(3); // frame state
2335 721 : NodeProperties::ChangeOp(node, javascript()->FulfillPromise());
2336 : return Changed(node);
2337 : }
2338 : return NoChange();
2339 : }
2340 :
2341 32515730 : Reduction JSTypedLowering::Reduce(Node* node) {
2342 : DisallowHeapAccess no_heap_access;
2343 :
2344 32515730 : switch (node->opcode()) {
2345 : case IrOpcode::kJSEqual:
2346 13454 : return ReduceJSEqual(node);
2347 : case IrOpcode::kJSStrictEqual:
2348 144700 : 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 34553 : return ReduceJSComparison(node);
2354 : case IrOpcode::kJSBitwiseOr:
2355 : case IrOpcode::kJSBitwiseXor:
2356 : case IrOpcode::kJSBitwiseAnd:
2357 19453 : return ReduceInt32Binop(node);
2358 : case IrOpcode::kJSShiftLeft:
2359 : case IrOpcode::kJSShiftRight:
2360 5537 : return ReduceUI32Shift(node, kSigned);
2361 : case IrOpcode::kJSShiftRightLogical:
2362 2423 : return ReduceUI32Shift(node, kUnsigned);
2363 : case IrOpcode::kJSAdd:
2364 86368 : return ReduceJSAdd(node);
2365 : case IrOpcode::kJSSubtract:
2366 : case IrOpcode::kJSMultiply:
2367 : case IrOpcode::kJSDivide:
2368 : case IrOpcode::kJSModulus:
2369 : case IrOpcode::kJSExponentiate:
2370 26279 : return ReduceNumberBinop(node);
2371 : case IrOpcode::kJSBitwiseNot:
2372 164 : return ReduceJSBitwiseNot(node);
2373 : case IrOpcode::kJSDecrement:
2374 2173 : return ReduceJSDecrement(node);
2375 : case IrOpcode::kJSIncrement:
2376 19160 : return ReduceJSIncrement(node);
2377 : case IrOpcode::kJSNegate:
2378 4035 : return ReduceJSNegate(node);
2379 : case IrOpcode::kJSHasInPrototypeChain:
2380 833 : return ReduceJSHasInPrototypeChain(node);
2381 : case IrOpcode::kJSOrdinaryHasInstance:
2382 110 : return ReduceJSOrdinaryHasInstance(node);
2383 : case IrOpcode::kJSToLength:
2384 36 : return ReduceJSToLength(node);
2385 : case IrOpcode::kJSToName:
2386 1148 : return ReduceJSToName(node);
2387 : case IrOpcode::kJSToNumber:
2388 : case IrOpcode::kJSToNumberConvertBigInt:
2389 9806 : return ReduceJSToNumber(node);
2390 : case IrOpcode::kJSToNumeric:
2391 4568 : return ReduceJSToNumeric(node);
2392 : case IrOpcode::kJSToString:
2393 2166 : return ReduceJSToString(node);
2394 : case IrOpcode::kJSToObject:
2395 1935 : return ReduceJSToObject(node);
2396 : case IrOpcode::kJSLoadNamed:
2397 423882 : return ReduceJSLoadNamed(node);
2398 : case IrOpcode::kJSLoadContext:
2399 302264 : return ReduceJSLoadContext(node);
2400 : case IrOpcode::kJSStoreContext:
2401 450771 : return ReduceJSStoreContext(node);
2402 : case IrOpcode::kJSLoadModule:
2403 294 : return ReduceJSLoadModule(node);
2404 : case IrOpcode::kJSStoreModule:
2405 6948 : return ReduceJSStoreModule(node);
2406 : case IrOpcode::kJSConstructForwardVarargs:
2407 469 : return ReduceJSConstructForwardVarargs(node);
2408 : case IrOpcode::kJSConstruct:
2409 35545 : return ReduceJSConstruct(node);
2410 : case IrOpcode::kJSCallForwardVarargs:
2411 374 : return ReduceJSCallForwardVarargs(node);
2412 : case IrOpcode::kJSCall:
2413 489463 : return ReduceJSCall(node);
2414 : case IrOpcode::kJSForInPrepare:
2415 1371 : return ReduceJSForInPrepare(node);
2416 : case IrOpcode::kJSForInNext:
2417 1548 : return ReduceJSForInNext(node);
2418 : case IrOpcode::kJSLoadMessage:
2419 29935 : return ReduceJSLoadMessage(node);
2420 : case IrOpcode::kJSStoreMessage:
2421 29937 : return ReduceJSStoreMessage(node);
2422 : case IrOpcode::kJSGeneratorStore:
2423 6150 : return ReduceJSGeneratorStore(node);
2424 : case IrOpcode::kJSGeneratorRestoreContinuation:
2425 2004 : return ReduceJSGeneratorRestoreContinuation(node);
2426 : case IrOpcode::kJSGeneratorRestoreContext:
2427 2004 : return ReduceJSGeneratorRestoreContext(node);
2428 : case IrOpcode::kJSGeneratorRestoreRegister:
2429 15314 : return ReduceJSGeneratorRestoreRegister(node);
2430 : case IrOpcode::kJSGeneratorRestoreInputOrDebugPos:
2431 6025 : return ReduceJSGeneratorRestoreInputOrDebugPos(node);
2432 : case IrOpcode::kJSObjectIsArray:
2433 87 : return ReduceObjectIsArray(node);
2434 : case IrOpcode::kJSParseInt:
2435 193 : return ReduceJSParseInt(node);
2436 : case IrOpcode::kJSResolvePromise:
2437 1004 : return ReduceJSResolvePromise(node);
2438 : default:
2439 : break;
2440 : }
2441 : return NoChange();
2442 : }
2443 :
2444 :
2445 0 : Factory* JSTypedLowering::factory() const { return jsgraph()->factory(); }
2446 :
2447 :
2448 0 : Graph* JSTypedLowering::graph() const { return jsgraph()->graph(); }
2449 :
2450 :
2451 0 : Isolate* JSTypedLowering::isolate() const { return jsgraph()->isolate(); }
2452 :
2453 :
2454 0 : JSOperatorBuilder* JSTypedLowering::javascript() const {
2455 0 : return jsgraph()->javascript();
2456 : }
2457 :
2458 :
2459 0 : CommonOperatorBuilder* JSTypedLowering::common() const {
2460 0 : return jsgraph()->common();
2461 : }
2462 :
2463 0 : SimplifiedOperatorBuilder* JSTypedLowering::simplified() const {
2464 0 : return jsgraph()->simplified();
2465 : }
2466 :
2467 : } // namespace compiler
2468 : } // namespace internal
2469 122004 : } // namespace v8
|