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