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