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 :
21 : namespace v8 {
22 : namespace internal {
23 : namespace compiler {
24 :
25 : // A helper class to simplify the process of reducing a single binop node with a
26 : // JSOperator. This class manages the rewriting of context, control, and effect
27 : // dependencies during lowering of a binop and contains numerous helper
28 : // functions for matching the types of inputs to an operation.
29 : class JSBinopReduction final {
30 : public:
31 : JSBinopReduction(JSTypedLowering* lowering, Node* node)
32 549584 : : lowering_(lowering), node_(node) {}
33 :
34 109888 : bool GetCompareNumberOperationHint(NumberOperationHint* hint) {
35 : DCHECK_EQ(1, node_->op()->EffectOutputCount());
36 109888 : switch (CompareOperationHintOf(node_->op())) {
37 : case CompareOperationHint::kSignedSmall:
38 8383 : *hint = NumberOperationHint::kSignedSmall;
39 : return true;
40 : case CompareOperationHint::kNumber:
41 8527 : *hint = NumberOperationHint::kNumber;
42 : return true;
43 : case CompareOperationHint::kNumberOrOddball:
44 0 : *hint = NumberOperationHint::kNumberOrOddball;
45 : return true;
46 : case CompareOperationHint::kAny:
47 : case CompareOperationHint::kNone:
48 : case CompareOperationHint::kString:
49 : case CompareOperationHint::kSymbol:
50 : case CompareOperationHint::kReceiver:
51 : case CompareOperationHint::kInternalizedString:
52 : break;
53 : }
54 : return false;
55 : }
56 :
57 149020 : bool IsInternalizedStringCompareOperation() {
58 : DCHECK_EQ(1, node_->op()->EffectOutputCount());
59 149020 : return (CompareOperationHintOf(node_->op()) ==
60 153024 : CompareOperationHint::kInternalizedString) &&
61 153024 : BothInputsMaybe(Type::InternalizedString());
62 : }
63 :
64 95386 : bool IsReceiverCompareOperation() {
65 : DCHECK_EQ(1, node_->op()->EffectOutputCount());
66 95386 : return (CompareOperationHintOf(node_->op()) ==
67 96179 : CompareOperationHint::kReceiver) &&
68 96179 : BothInputsMaybe(Type::Receiver());
69 : }
70 :
71 113977 : bool IsStringCompareOperation() {
72 : DCHECK_EQ(1, node_->op()->EffectOutputCount());
73 113977 : return (CompareOperationHintOf(node_->op()) ==
74 117119 : CompareOperationHint::kString) &&
75 117119 : BothInputsMaybe(Type::String());
76 : }
77 :
78 91513 : bool IsSymbolCompareOperation() {
79 : DCHECK_EQ(1, node_->op()->EffectOutputCount());
80 91513 : return (CompareOperationHintOf(node_->op()) ==
81 91513 : CompareOperationHint::kSymbol) &&
82 91513 : BothInputsMaybe(Type::Symbol());
83 : }
84 :
85 : // Check if a string addition will definitely result in creating a ConsString,
86 : // i.e. if the combined length of the resulting string exceeds the ConsString
87 : // minimum length.
88 49577 : bool ShouldCreateConsString() {
89 : DCHECK_EQ(IrOpcode::kJSAdd, node_->opcode());
90 : DCHECK(OneInputIs(Type::String()));
91 80891 : if (BothInputsAre(Type::String()) ||
92 31314 : BinaryOperationHintOf(node_->op()) == BinaryOperationHint::kString) {
93 20279 : HeapObjectBinopMatcher m(node_);
94 35716 : if (m.right().HasValue() && m.right().Value()->IsString()) {
95 : Handle<String> right_string = Handle<String>::cast(m.right().Value());
96 15437 : if (right_string->length() >= ConsString::kMinLength) return true;
97 : }
98 19895 : if (m.left().HasValue() && m.left().Value()->IsString()) {
99 : Handle<String> left_string = Handle<String>::cast(m.left().Value());
100 1651 : if (left_string->length() >= ConsString::kMinLength) {
101 : // The invariant for ConsString requires the left hand side to be
102 : // a sequential or external string if the right hand side is the
103 : // empty string. Since we don't know anything about the right hand
104 : // side here, we must ensure that the left hand side satisfy the
105 : // constraints independent of the right hand side.
106 448 : return left_string->IsSeqString() || left_string->IsExternalString();
107 : }
108 : }
109 : }
110 : return false;
111 : }
112 :
113 : // Inserts a CheckReceiver for the left input.
114 4758 : void CheckLeftInputToReceiver() {
115 : Node* left_input = graph()->NewNode(simplified()->CheckReceiver(), left(),
116 793 : effect(), control());
117 793 : node_->ReplaceInput(0, left_input);
118 : update_effect(left_input);
119 793 : }
120 :
121 : // Checks that both inputs are Receiver, and if we don't know
122 : // statically that one side is already a Receiver, insert a
123 : // CheckReceiver node.
124 826 : void CheckInputsToReceiver() {
125 113 : if (!left_type()->Is(Type::Receiver())) {
126 113 : CheckLeftInputToReceiver();
127 : }
128 113 : if (!right_type()->Is(Type::Receiver())) {
129 : Node* right_input = graph()->NewNode(simplified()->CheckReceiver(),
130 100 : right(), effect(), control());
131 100 : node_->ReplaceInput(1, right_input);
132 : update_effect(right_input);
133 : }
134 113 : }
135 :
136 : // Checks that both inputs are Symbol, and if we don't know
137 : // statically that one side is already a Symbol, insert a
138 : // CheckSymbol node.
139 0 : void CheckInputsToSymbol() {
140 0 : if (!left_type()->Is(Type::Symbol())) {
141 : Node* left_input = graph()->NewNode(simplified()->CheckSymbol(), left(),
142 0 : effect(), control());
143 0 : node_->ReplaceInput(0, left_input);
144 : update_effect(left_input);
145 : }
146 0 : if (!right_type()->Is(Type::Symbol())) {
147 : Node* right_input = graph()->NewNode(simplified()->CheckSymbol(), right(),
148 0 : effect(), control());
149 0 : node_->ReplaceInput(1, right_input);
150 : update_effect(right_input);
151 : }
152 0 : }
153 :
154 : // Checks that both inputs are String, and if we don't know
155 : // statically that one side is already a String, insert a
156 : // CheckString node.
157 27314 : void CheckInputsToString() {
158 3142 : if (!left_type()->Is(Type::String())) {
159 : Node* left_input = graph()->NewNode(simplified()->CheckString(), left(),
160 3110 : effect(), control());
161 3110 : node_->ReplaceInput(0, left_input);
162 : update_effect(left_input);
163 : }
164 3142 : if (!right_type()->Is(Type::String())) {
165 : Node* right_input = graph()->NewNode(simplified()->CheckString(), right(),
166 395 : effect(), control());
167 395 : node_->ReplaceInput(1, right_input);
168 : update_effect(right_input);
169 : }
170 3142 : }
171 :
172 : // Checks that both inputs are InternalizedString, and if we don't know
173 : // statically that one side is already an InternalizedString, insert a
174 : // CheckInternalizedString node.
175 32902 : void CheckInputsToInternalizedString() {
176 4004 : if (!left_type()->Is(Type::UniqueName())) {
177 : Node* left_input = graph()->NewNode(
178 4004 : simplified()->CheckInternalizedString(), left(), effect(), control());
179 4004 : node_->ReplaceInput(0, left_input);
180 : update_effect(left_input);
181 : }
182 4004 : if (!right_type()->Is(Type::UniqueName())) {
183 : Node* right_input =
184 : graph()->NewNode(simplified()->CheckInternalizedString(), right(),
185 145 : effect(), control());
186 145 : node_->ReplaceInput(1, right_input);
187 : update_effect(right_input);
188 : }
189 4004 : }
190 :
191 290456 : void ConvertInputsToNumber() {
192 : DCHECK(left_type()->Is(Type::PlainPrimitive()));
193 : DCHECK(right_type()->Is(Type::PlainPrimitive()));
194 145228 : node_->ReplaceInput(0, ConvertPlainPrimitiveToNumber(left()));
195 145228 : node_->ReplaceInput(1, ConvertPlainPrimitiveToNumber(right()));
196 145228 : }
197 :
198 22702 : void ConvertInputsToUI32(Signedness left_signedness,
199 45404 : Signedness right_signedness) {
200 22702 : node_->ReplaceInput(0, ConvertToUI32(left(), left_signedness));
201 22702 : node_->ReplaceInput(1, ConvertToUI32(right(), right_signedness));
202 22702 : }
203 :
204 17876 : void SwapInputs() {
205 : Node* l = left();
206 : Node* r = right();
207 8938 : node_->ReplaceInput(0, r);
208 8938 : node_->ReplaceInput(1, l);
209 8938 : }
210 :
211 : // Remove all effect and control inputs and outputs to this node and change
212 : // to the pure operator {op}.
213 225414 : Reduction ChangeToPureOperator(const Operator* op, Type* type = Type::Any()) {
214 : DCHECK_EQ(0, op->EffectInputCount());
215 : DCHECK_EQ(false, OperatorProperties::HasContextInput(op));
216 : DCHECK_EQ(0, op->ControlInputCount());
217 : DCHECK_EQ(2, op->ValueInputCount());
218 :
219 : // Remove the effects from the node, and update its effect/control usages.
220 450828 : if (node_->op()->EffectInputCount() > 0) {
221 225414 : lowering_->RelaxEffectsAndControls(node_);
222 : }
223 : // Remove the inputs corresponding to context, effect, and control.
224 225414 : NodeProperties::RemoveNonValueInputs(node_);
225 : // Finally, update the operator to the new one.
226 225414 : NodeProperties::ChangeOp(node_, op);
227 :
228 : // TODO(jarin): Replace the explicit typing hack with a call to some method
229 : // that encapsulates changing the operator and re-typing.
230 225414 : Type* node_type = NodeProperties::GetType(node_);
231 225414 : NodeProperties::SetType(node_, Type::Intersect(node_type, type, zone()));
232 :
233 225414 : return lowering_->Changed(node_);
234 : }
235 :
236 16910 : Reduction ChangeToSpeculativeOperator(const Operator* op, Type* upper_bound) {
237 : DCHECK_EQ(1, op->EffectInputCount());
238 : DCHECK_EQ(1, op->EffectOutputCount());
239 : DCHECK_EQ(false, OperatorProperties::HasContextInput(op));
240 : DCHECK_EQ(1, op->ControlInputCount());
241 : DCHECK_EQ(0, op->ControlOutputCount());
242 : DCHECK_EQ(0, OperatorProperties::GetFrameStateInputCount(op));
243 : DCHECK_EQ(2, op->ValueInputCount());
244 :
245 : DCHECK_EQ(1, node_->op()->EffectInputCount());
246 : DCHECK_EQ(1, node_->op()->EffectOutputCount());
247 : DCHECK_EQ(1, node_->op()->ControlInputCount());
248 : DCHECK_EQ(2, node_->op()->ValueInputCount());
249 :
250 : // Reconnect the control output to bypass the IfSuccess node and
251 : // possibly disconnect from the IfException node.
252 33820 : lowering_->RelaxControls(node_);
253 :
254 : // Remove the frame state and the context.
255 33820 : if (OperatorProperties::HasFrameStateInput(node_->op())) {
256 0 : node_->RemoveInput(NodeProperties::FirstFrameStateIndex(node_));
257 : }
258 33820 : node_->RemoveInput(NodeProperties::FirstContextIndex(node_));
259 :
260 16910 : NodeProperties::ChangeOp(node_, op);
261 :
262 : // Update the type to number.
263 16910 : Type* node_type = NodeProperties::GetType(node_);
264 : NodeProperties::SetType(node_,
265 16910 : Type::Intersect(node_type, upper_bound, zone()));
266 :
267 16910 : return lowering_->Changed(node_);
268 : }
269 :
270 106714 : const Operator* NumberOp() {
271 106714 : switch (node_->opcode()) {
272 : case IrOpcode::kJSAdd:
273 0 : return simplified()->NumberAdd();
274 : case IrOpcode::kJSSubtract:
275 20049 : return simplified()->NumberSubtract();
276 : case IrOpcode::kJSMultiply:
277 4401 : return simplified()->NumberMultiply();
278 : case IrOpcode::kJSDivide:
279 3494 : return simplified()->NumberDivide();
280 : case IrOpcode::kJSModulus:
281 2711 : return simplified()->NumberModulus();
282 : case IrOpcode::kJSBitwiseAnd:
283 3701 : return simplified()->NumberBitwiseAnd();
284 : case IrOpcode::kJSBitwiseOr:
285 5179 : return simplified()->NumberBitwiseOr();
286 : case IrOpcode::kJSBitwiseXor:
287 3098 : return simplified()->NumberBitwiseXor();
288 : case IrOpcode::kJSShiftLeft:
289 3485 : return simplified()->NumberShiftLeft();
290 : case IrOpcode::kJSShiftRight:
291 3784 : return simplified()->NumberShiftRight();
292 : case IrOpcode::kJSShiftRightLogical:
293 3455 : return simplified()->NumberShiftRightLogical();
294 : default:
295 : break;
296 : }
297 0 : UNREACHABLE();
298 : }
299 :
300 67316 : const Operator* NumberOpFromSpeculativeNumberOp() {
301 67316 : switch (node_->opcode()) {
302 : case IrOpcode::kSpeculativeNumberEqual:
303 11390 : return simplified()->NumberEqual();
304 : case IrOpcode::kSpeculativeNumberLessThan:
305 9422 : return simplified()->NumberLessThan();
306 : case IrOpcode::kSpeculativeNumberLessThanOrEqual:
307 354 : return simplified()->NumberLessThanOrEqual();
308 : case IrOpcode::kSpeculativeNumberAdd:
309 0 : return simplified()->NumberAdd();
310 : case IrOpcode::kSpeculativeNumberSubtract:
311 1264 : return simplified()->NumberSubtract();
312 : case IrOpcode::kSpeculativeNumberMultiply:
313 7376 : return simplified()->NumberMultiply();
314 : case IrOpcode::kSpeculativeNumberDivide:
315 3440 : return simplified()->NumberDivide();
316 : case IrOpcode::kSpeculativeNumberModulus:
317 412 : return simplified()->NumberModulus();
318 : default:
319 : break;
320 : }
321 0 : UNREACHABLE();
322 : }
323 :
324 3398588 : bool LeftInputIs(Type* t) { return left_type()->Is(t); }
325 :
326 1348132 : bool RightInputIs(Type* t) { return right_type()->Is(t); }
327 :
328 225025 : bool OneInputIs(Type* t) { return LeftInputIs(t) || RightInputIs(t); }
329 :
330 1372562 : bool BothInputsAre(Type* t) { return LeftInputIs(t) && RightInputIs(t); }
331 :
332 15878 : bool BothInputsMaybe(Type* t) {
333 15878 : return left_type()->Maybe(t) && right_type()->Maybe(t);
334 : }
335 :
336 341545 : bool OneInputCannotBe(Type* t) {
337 341545 : return !left_type()->Maybe(t) || !right_type()->Maybe(t);
338 : }
339 :
340 214522 : bool NeitherInputCanBe(Type* t) {
341 214522 : return !left_type()->Maybe(t) && !right_type()->Maybe(t);
342 : }
343 :
344 8547 : Node* effect() { return NodeProperties::GetEffectInput(node_); }
345 8547 : Node* control() { return NodeProperties::GetControlInput(node_); }
346 : Node* context() { return NodeProperties::GetContextInput(node_); }
347 352834 : Node* left() { return NodeProperties::GetValueInput(node_, 0); }
348 371969 : Node* right() { return NodeProperties::GetValueInput(node_, 1); }
349 : Type* left_type() { return NodeProperties::GetType(node_->InputAt(0)); }
350 : Type* right_type() { return NodeProperties::GetType(node_->InputAt(1)); }
351 : Type* type() { return NodeProperties::GetType(node_); }
352 :
353 : SimplifiedOperatorBuilder* simplified() { return lowering_->simplified(); }
354 : Graph* graph() const { return lowering_->graph(); }
355 : JSGraph* jsgraph() { return lowering_->jsgraph(); }
356 : JSOperatorBuilder* javascript() { return lowering_->javascript(); }
357 : CommonOperatorBuilder* common() { return jsgraph()->common(); }
358 484648 : Zone* zone() const { return graph()->zone(); }
359 :
360 : private:
361 : JSTypedLowering* lowering_; // The containing lowering instance.
362 : Node* node_; // The original node.
363 :
364 307256 : Node* ConvertPlainPrimitiveToNumber(Node* node) {
365 : DCHECK(NodeProperties::GetType(node)->Is(Type::PlainPrimitive()));
366 : // Avoid inserting too many eager ToNumber() operations.
367 290456 : Reduction const reduction = lowering_->ReduceJSToNumberInput(node);
368 290456 : if (reduction.Changed()) return reduction.replacement();
369 8400 : if (NodeProperties::GetType(node)->Is(Type::Number())) {
370 : return node;
371 : }
372 16800 : return graph()->NewNode(simplified()->PlainPrimitiveToNumber(), node);
373 : }
374 :
375 92930 : Node* ConvertToUI32(Node* node, Signedness signedness) {
376 : // Avoid introducing too many eager NumberToXXnt32() operations.
377 : Type* type = NodeProperties::GetType(node);
378 45404 : if (signedness == kSigned) {
379 31225 : if (!type->Is(Type::Signed32())) {
380 14799 : node = graph()->NewNode(simplified()->NumberToInt32(), node);
381 : }
382 : } else {
383 : DCHECK_EQ(kUnsigned, signedness);
384 14179 : if (!type->Is(Type::Unsigned32())) {
385 8964 : node = graph()->NewNode(simplified()->NumberToUint32(), node);
386 : }
387 : }
388 45404 : return node;
389 : }
390 :
391 : void update_effect(Node* effect) {
392 8547 : NodeProperties::ReplaceEffectInput(node_, effect);
393 : }
394 : };
395 :
396 :
397 : // TODO(turbofan): js-typed-lowering improvements possible
398 : // - immediately put in type bounds for all new nodes
399 : // - relax effects from generic but not-side-effecting operations
400 :
401 462956 : JSTypedLowering::JSTypedLowering(Editor* editor,
402 : JSGraph* jsgraph, Zone* zone)
403 : : AdvancedReducer(editor),
404 : jsgraph_(jsgraph),
405 : empty_string_type_(
406 462956 : Type::HeapConstant(factory()->empty_string(), graph()->zone())),
407 : pointer_comparable_type_(
408 : Type::Union(Type::Oddball(),
409 : Type::Union(Type::SymbolOrReceiver(), empty_string_type_,
410 : graph()->zone()),
411 462957 : graph()->zone())),
412 1388870 : type_cache_(TypeCache::Get()) {}
413 :
414 105108 : Reduction JSTypedLowering::ReduceSpeculativeNumberAdd(Node* node) {
415 : JSBinopReduction r(this, node);
416 52554 : NumberOperationHint hint = NumberOperationHintOf(node->op());
417 105108 : if ((hint == NumberOperationHint::kNumber ||
418 52554 : hint == NumberOperationHint::kNumberOrOddball) &&
419 104091 : r.BothInputsAre(Type::PlainPrimitive()) &&
420 51537 : r.NeitherInputCanBe(Type::StringOrReceiver())) {
421 : // SpeculativeNumberAdd(x:-string, y:-string) =>
422 : // NumberAdd(ToNumber(x), ToNumber(y))
423 51522 : r.ConvertInputsToNumber();
424 51522 : return r.ChangeToPureOperator(simplified()->NumberAdd(), Type::Number());
425 : }
426 : return NoChange();
427 : }
428 :
429 233217 : Reduction JSTypedLowering::ReduceJSAdd(Node* node) {
430 : JSBinopReduction r(this, node);
431 90137 : if (r.BothInputsAre(Type::Number())) {
432 : // JSAdd(x:number, y:number) => NumberAdd(x, y)
433 16211 : r.ConvertInputsToNumber();
434 16211 : return r.ChangeToPureOperator(simplified()->NumberAdd(), Type::Number());
435 : }
436 100175 : if (r.BothInputsAre(Type::PlainPrimitive()) &&
437 26249 : r.NeitherInputCanBe(Type::StringOrReceiver())) {
438 : // JSAdd(x:-string, y:-string) => NumberAdd(ToNumber(x), ToNumber(y))
439 21 : r.ConvertInputsToNumber();
440 21 : return r.ChangeToPureOperator(simplified()->NumberAdd(), Type::Number());
441 : }
442 73905 : if (r.OneInputIs(Type::String())) {
443 : // We know that (at least) one input is already a String,
444 : // so try to strength-reduce the non-String input.
445 51179 : if (r.LeftInputIs(Type::String())) {
446 82092 : Reduction const reduction = ReduceJSToStringInput(r.right());
447 41046 : if (reduction.Changed()) {
448 19749 : NodeProperties::ReplaceValueInput(node, reduction.replacement(), 1);
449 : }
450 10133 : } else if (r.RightInputIs(Type::String())) {
451 20266 : Reduction const reduction = ReduceJSToStringInput(r.left());
452 10133 : if (reduction.Changed()) {
453 116 : NodeProperties::ReplaceValueInput(node, reduction.replacement(), 0);
454 : }
455 : }
456 : // We might be able to constant-fold the String concatenation now.
457 51179 : if (r.BothInputsAre(Type::String())) {
458 19865 : HeapObjectBinopMatcher m(node);
459 19865 : if (m.IsFoldable()) {
460 : Handle<String> left = Handle<String>::cast(m.left().Value());
461 : Handle<String> right = Handle<String>::cast(m.right().Value());
462 1602 : if (left->length() + right->length() > String::kMaxLength) {
463 : // No point in trying to optimize this, as it will just throw.
464 : return NoChange();
465 : }
466 : Node* value = jsgraph()->HeapConstant(
467 3204 : factory()->NewConsString(left, right).ToHandleChecked());
468 1684 : ReplaceWithValue(node, value);
469 : return Replace(value);
470 : }
471 : }
472 : // We might know for sure that we're creating a ConsString here.
473 49577 : if (r.ShouldCreateConsString()) {
474 2363 : return ReduceCreateConsString(node);
475 : }
476 : // Eliminate useless concatenation of empty string.
477 47214 : if (BinaryOperationHintOf(node->op()) == BinaryOperationHint::kString) {
478 3345 : Node* effect = NodeProperties::GetEffectInput(node);
479 3345 : Node* control = NodeProperties::GetControlInput(node);
480 3345 : if (r.LeftInputIs(empty_string_type_)) {
481 : Node* value = effect = graph()->NewNode(simplified()->CheckString(),
482 86 : r.right(), effect, control);
483 : ReplaceWithValue(node, value, effect, control);
484 : return Replace(value);
485 3302 : } else if (r.RightInputIs(empty_string_type_)) {
486 : Node* value = effect = graph()->NewNode(simplified()->CheckString(),
487 78 : r.left(), effect, control);
488 : ReplaceWithValue(node, value, effect, control);
489 : return Replace(value);
490 : }
491 : }
492 : StringAddFlags flags = STRING_ADD_CHECK_NONE;
493 47132 : if (!r.LeftInputIs(Type::String())) {
494 : flags = STRING_ADD_CONVERT_LEFT;
495 37254 : } else if (!r.RightInputIs(Type::String())) {
496 : flags = STRING_ADD_CONVERT_RIGHT;
497 : }
498 47132 : Operator::Properties properties = node->op()->properties();
499 47132 : if (r.NeitherInputCanBe(Type::Receiver())) {
500 : // Both sides are already strings, so we know that the
501 : // string addition will not cause any observable side
502 : // effects; it can still throw obviously.
503 17563 : properties = Operator::kNoWrite | Operator::kNoDeopt;
504 : }
505 : // JSAdd(x:string, y) => CallStub[StringAdd](x, y)
506 : // JSAdd(x, y:string) => CallStub[StringAdd](x, y)
507 : Callable const callable =
508 47132 : CodeFactory::StringAdd(isolate(), flags, NOT_TENURED);
509 : CallDescriptor const* const desc = Linkage::GetStubCallDescriptor(
510 : isolate(), graph()->zone(), callable.descriptor(), 0,
511 141396 : CallDescriptor::kNeedsFrameState, properties);
512 : DCHECK_EQ(1, OperatorProperties::GetFrameStateInputCount(node->op()));
513 : node->InsertInput(graph()->zone(), 0,
514 94264 : jsgraph()->HeapConstant(callable.code()));
515 47132 : NodeProperties::ChangeOp(node, common()->Call(desc));
516 : return Changed(node);
517 : }
518 : return NoChange();
519 : }
520 :
521 56427 : Reduction JSTypedLowering::ReduceNumberBinop(Node* node) {
522 : JSBinopReduction r(this, node);
523 56427 : if (r.BothInputsAre(Type::PlainPrimitive())) {
524 30655 : r.ConvertInputsToNumber();
525 30655 : return r.ChangeToPureOperator(r.NumberOp(), Type::Number());
526 : }
527 : return NoChange();
528 : }
529 :
530 84548 : Reduction JSTypedLowering::ReduceSpeculativeNumberBinop(Node* node) {
531 : JSBinopReduction r(this, node);
532 42274 : NumberOperationHint hint = NumberOperationHintOf(node->op());
533 84548 : if ((hint == NumberOperationHint::kNumber ||
534 63141 : hint == NumberOperationHint::kNumberOrOddball) &&
535 20867 : r.BothInputsAre(Type::NumberOrUndefinedOrNullOrBoolean())) {
536 12492 : r.ConvertInputsToNumber();
537 : return r.ChangeToPureOperator(r.NumberOpFromSpeculativeNumberOp(),
538 12492 : Type::Number());
539 : }
540 : return NoChange();
541 : }
542 :
543 23797 : Reduction JSTypedLowering::ReduceInt32Binop(Node* node) {
544 : JSBinopReduction r(this, node);
545 23797 : if (r.BothInputsAre(Type::PlainPrimitive())) {
546 11978 : r.ConvertInputsToNumber();
547 11978 : r.ConvertInputsToUI32(kSigned, kSigned);
548 11978 : return r.ChangeToPureOperator(r.NumberOp(), Type::Signed32());
549 : }
550 : return NoChange();
551 : }
552 :
553 12376 : Reduction JSTypedLowering::ReduceUI32Shift(Node* node, Signedness signedness) {
554 : JSBinopReduction r(this, node);
555 12376 : if (r.BothInputsAre(Type::PlainPrimitive())) {
556 10724 : r.ConvertInputsToNumber();
557 10724 : r.ConvertInputsToUI32(signedness, kUnsigned);
558 : return r.ChangeToPureOperator(r.NumberOp(), signedness == kUnsigned
559 : ? Type::Unsigned32()
560 10724 : : Type::Signed32());
561 : }
562 : return NoChange();
563 : }
564 :
565 7089 : Reduction JSTypedLowering::ReduceCreateConsString(Node* node) {
566 2363 : Node* first = NodeProperties::GetValueInput(node, 0);
567 2363 : Node* second = NodeProperties::GetValueInput(node, 1);
568 2363 : Node* context = NodeProperties::GetContextInput(node);
569 2363 : Node* frame_state = NodeProperties::GetFrameStateInput(node);
570 2363 : Node* effect = NodeProperties::GetEffectInput(node);
571 2363 : Node* control = NodeProperties::GetControlInput(node);
572 :
573 : // Make sure {first} is actually a String.
574 : Type* first_type = NodeProperties::GetType(first);
575 2363 : if (!first_type->Is(Type::String())) {
576 : first = effect =
577 345 : graph()->NewNode(simplified()->CheckString(), first, effect, control);
578 : first_type = NodeProperties::GetType(first);
579 : }
580 :
581 : // Make sure {second} is actually a String.
582 : Type* second_type = NodeProperties::GetType(second);
583 2363 : if (!second_type->Is(Type::String())) {
584 : second = effect =
585 303 : graph()->NewNode(simplified()->CheckString(), second, effect, control);
586 : second_type = NodeProperties::GetType(second);
587 : }
588 :
589 : // Determine the {first} length.
590 2363 : Node* first_length = BuildGetStringLength(first, &effect, control);
591 2363 : Node* second_length = BuildGetStringLength(second, &effect, control);
592 :
593 : // Compute the resulting length.
594 : Node* length =
595 2363 : graph()->NewNode(simplified()->NumberAdd(), first_length, second_length);
596 :
597 2363 : if (isolate()->IsStringLengthOverflowIntact()) {
598 : // We can just deoptimize if the {length} is out-of-bounds. Besides
599 : // generating a shorter code sequence than the version below, this
600 : // has the additional benefit of not holding on to the lazy {frame_state}
601 : // and thus potentially reduces the number of live ranges and allows for
602 : // more truncations.
603 : length = effect = graph()->NewNode(simplified()->CheckBounds(), length,
604 : jsgraph()->Constant(String::kMaxLength),
605 6924 : effect, control);
606 : } else {
607 : // Check if we would overflow the allowed maximum string length.
608 : Node* check =
609 : graph()->NewNode(simplified()->NumberLessThanOrEqual(), length,
610 110 : jsgraph()->Constant(String::kMaxLength));
611 : Node* branch =
612 55 : graph()->NewNode(common()->Branch(BranchHint::kTrue), check, control);
613 55 : Node* if_false = graph()->NewNode(common()->IfFalse(), branch);
614 55 : Node* efalse = effect;
615 : {
616 : // Throw a RangeError in case of overflow.
617 : Node* vfalse = efalse = if_false = graph()->NewNode(
618 : javascript()->CallRuntime(Runtime::kThrowInvalidStringLength),
619 55 : context, frame_state, efalse, if_false);
620 :
621 : // Update potential {IfException} uses of {node} to point to the
622 : // %ThrowInvalidStringLength runtime call node instead.
623 55 : Node* on_exception = nullptr;
624 55 : if (NodeProperties::IsExceptionalCall(node, &on_exception)) {
625 25 : NodeProperties::ReplaceControlInput(on_exception, vfalse);
626 25 : NodeProperties::ReplaceEffectInput(on_exception, efalse);
627 25 : if_false = graph()->NewNode(common()->IfSuccess(), vfalse);
628 2443 : Revisit(on_exception);
629 : }
630 :
631 : // The above %ThrowInvalidStringLength runtime call is an unconditional
632 : // throw, making it impossible to return a successful completion in this
633 : // case. We simply connect the successful completion to the graph end.
634 55 : if_false = graph()->NewNode(common()->Throw(), efalse, if_false);
635 : // TODO(bmeurer): This should be on the AdvancedReducer somehow.
636 55 : NodeProperties::MergeControlToEnd(graph(), common(), if_false);
637 55 : Revisit(graph()->end());
638 : }
639 55 : control = graph()->NewNode(common()->IfTrue(), branch);
640 : }
641 :
642 : // Figure out the map for the resulting ConsString.
643 : // TODO(turbofan): We currently just use the cons_string_map here for
644 : // the sake of simplicity; we could also try to be smarter here and
645 : // use the one_byte_cons_string_map instead when the resulting ConsString
646 : // contains only one byte characters.
647 2363 : Node* value_map = jsgraph()->HeapConstant(factory()->cons_string_map());
648 :
649 : // Allocate the resulting ConsString.
650 2363 : AllocationBuilder a(jsgraph(), effect, control);
651 2363 : a.Allocate(ConsString::kSize, NOT_TENURED, Type::OtherString());
652 2363 : a.Store(AccessBuilder::ForMap(), value_map);
653 : a.Store(AccessBuilder::ForNameHashField(),
654 2363 : jsgraph()->Constant(Name::kEmptyHashField));
655 2363 : a.Store(AccessBuilder::ForStringLength(), length);
656 2363 : a.Store(AccessBuilder::ForConsStringFirst(), first);
657 2363 : a.Store(AccessBuilder::ForConsStringSecond(), second);
658 :
659 : // Morph the {node} into a {FinishRegion}.
660 : ReplaceWithValue(node, node, node, control);
661 2363 : a.FinishAndChange(node);
662 2363 : return Changed(node);
663 : }
664 :
665 4726 : Node* JSTypedLowering::BuildGetStringLength(Node* value, Node** effect,
666 2363 : Node* control) {
667 : HeapObjectMatcher m(value);
668 : Node* length =
669 2363 : (m.HasValue() && m.Value()->IsString())
670 : ? jsgraph()->Constant(Handle<String>::cast(m.Value())->length())
671 : : (*effect) = graph()->NewNode(
672 : simplified()->LoadField(AccessBuilder::ForStringLength()),
673 11815 : value, *effect, control);
674 4726 : return length;
675 : }
676 :
677 67587 : Reduction JSTypedLowering::ReduceSpeculativeNumberComparison(Node* node) {
678 : JSBinopReduction r(this, node);
679 114236 : if (r.BothInputsAre(Type::Signed32()) ||
680 46649 : r.BothInputsAre(Type::Unsigned32())) {
681 21166 : return r.ChangeToPureOperator(r.NumberOpFromSpeculativeNumberOp());
682 : }
683 : return NoChange();
684 : }
685 :
686 55380 : Reduction JSTypedLowering::ReduceJSComparison(Node* node) {
687 : JSBinopReduction r(this, node);
688 37351 : if (r.BothInputsAre(Type::String())) {
689 : // If both inputs are definitely strings, perform a string comparison.
690 : const Operator* stringOp;
691 1058 : switch (node->opcode()) {
692 : case IrOpcode::kJSLessThan:
693 478 : stringOp = simplified()->StringLessThan();
694 478 : break;
695 : case IrOpcode::kJSGreaterThan:
696 199 : stringOp = simplified()->StringLessThan();
697 199 : r.SwapInputs(); // a > b => b < a
698 199 : break;
699 : case IrOpcode::kJSLessThanOrEqual:
700 190 : stringOp = simplified()->StringLessThanOrEqual();
701 190 : break;
702 : case IrOpcode::kJSGreaterThanOrEqual:
703 191 : stringOp = simplified()->StringLessThanOrEqual();
704 191 : r.SwapInputs(); // a >= b => b <= a
705 191 : break;
706 : default:
707 : return NoChange();
708 : }
709 1058 : r.ChangeToPureOperator(stringOp);
710 : return Changed(node);
711 : }
712 :
713 : const Operator* less_than;
714 : const Operator* less_than_or_equal;
715 67467 : if (r.BothInputsAre(Type::Signed32()) ||
716 31174 : r.BothInputsAre(Type::Unsigned32())) {
717 5284 : less_than = simplified()->NumberLessThan();
718 5284 : less_than_or_equal = simplified()->NumberLessThanOrEqual();
719 59977 : } else if (r.OneInputCannotBe(Type::StringOrReceiver()) &&
720 28968 : r.BothInputsAre(Type::PlainPrimitive())) {
721 11625 : r.ConvertInputsToNumber();
722 11625 : less_than = simplified()->NumberLessThan();
723 11625 : less_than_or_equal = simplified()->NumberLessThanOrEqual();
724 19384 : } else if (r.IsStringCompareOperation()) {
725 62 : r.CheckInputsToString();
726 62 : less_than = simplified()->StringLessThan();
727 62 : less_than_or_equal = simplified()->StringLessThanOrEqual();
728 : } else {
729 : return NoChange();
730 : }
731 : const Operator* comparison;
732 16971 : switch (node->opcode()) {
733 : case IrOpcode::kJSLessThan:
734 : comparison = less_than;
735 : break;
736 : case IrOpcode::kJSGreaterThan:
737 : comparison = less_than;
738 6709 : r.SwapInputs(); // a > b => b < a
739 6709 : break;
740 : case IrOpcode::kJSLessThanOrEqual:
741 : comparison = less_than_or_equal;
742 1968 : break;
743 : case IrOpcode::kJSGreaterThanOrEqual:
744 : comparison = less_than_or_equal;
745 1839 : r.SwapInputs(); // a >= b => b <= a
746 1839 : break;
747 : default:
748 : return NoChange();
749 : }
750 16971 : return r.ChangeToPureOperator(comparison);
751 : }
752 :
753 13709 : Reduction JSTypedLowering::ReduceJSEqual(Node* node) {
754 : JSBinopReduction r(this, node);
755 :
756 13709 : if (r.BothInputsAre(Type::UniqueName())) {
757 925 : return r.ChangeToPureOperator(simplified()->ReferenceEqual());
758 : }
759 12784 : if (r.IsInternalizedStringCompareOperation()) {
760 101 : r.CheckInputsToInternalizedString();
761 101 : return r.ChangeToPureOperator(simplified()->ReferenceEqual());
762 : }
763 12683 : if (r.BothInputsAre(Type::String())) {
764 241 : return r.ChangeToPureOperator(simplified()->StringEqual());
765 : }
766 12442 : if (r.BothInputsAre(Type::Boolean())) {
767 38 : return r.ChangeToPureOperator(simplified()->ReferenceEqual());
768 : }
769 12404 : if (r.BothInputsAre(Type::Receiver())) {
770 25 : return r.ChangeToPureOperator(simplified()->ReferenceEqual());
771 : }
772 12379 : if (r.OneInputIs(Type::Undetectable())) {
773 : RelaxEffectsAndControls(node);
774 51 : node->RemoveInput(r.LeftInputIs(Type::Undetectable()) ? 0 : 1);
775 51 : node->TrimInputCount(1);
776 51 : NodeProperties::ChangeOp(node, simplified()->ObjectIsUndetectable());
777 : return Changed(node);
778 : }
779 :
780 20942 : if (r.BothInputsAre(Type::Signed32()) ||
781 8614 : r.BothInputsAre(Type::Unsigned32())) {
782 3766 : return r.ChangeToPureOperator(simplified()->NumberEqual());
783 8562 : } else if (r.BothInputsAre(Type::Number())) {
784 832 : return r.ChangeToPureOperator(simplified()->NumberEqual());
785 7730 : } else if (r.IsReceiverCompareOperation()) {
786 113 : r.CheckInputsToReceiver();
787 113 : return r.ChangeToPureOperator(simplified()->ReferenceEqual());
788 7617 : } else if (r.IsStringCompareOperation()) {
789 24 : r.CheckInputsToString();
790 24 : return r.ChangeToPureOperator(simplified()->StringEqual());
791 7593 : } else if (r.IsSymbolCompareOperation()) {
792 0 : r.CheckInputsToSymbol();
793 0 : return r.ChangeToPureOperator(simplified()->ReferenceEqual());
794 : }
795 : return NoChange();
796 : }
797 :
798 154848 : Reduction JSTypedLowering::ReduceJSStrictEqual(Node* node) {
799 : JSBinopReduction r(this, node);
800 306744 : if (r.left() == r.right()) {
801 : // x === x is always true if x != NaN
802 : Node* replacement = graph()->NewNode(
803 : simplified()->BooleanNot(),
804 13545 : graph()->NewNode(simplified()->ObjectIsNaN(), r.left()));
805 5991 : ReplaceWithValue(node, replacement);
806 : return Replace(replacement);
807 : }
808 148857 : if (r.OneInputCannotBe(Type::NumberOrString())) {
809 : // For values with canonical representation (i.e. neither String, nor
810 : // Number) an empty type intersection means the values cannot be strictly
811 : // equal.
812 10512 : if (!r.left_type()->Maybe(r.right_type())) {
813 1476 : Node* replacement = jsgraph()->FalseConstant();
814 : ReplaceWithValue(node, replacement);
815 : return Replace(replacement);
816 : }
817 : }
818 :
819 147381 : if (r.BothInputsAre(Type::Unique())) {
820 8640 : return r.ChangeToPureOperator(simplified()->ReferenceEqual());
821 : }
822 138741 : if (r.OneInputIs(pointer_comparable_type_)) {
823 2505 : return r.ChangeToPureOperator(simplified()->ReferenceEqual());
824 : }
825 136236 : if (r.IsInternalizedStringCompareOperation()) {
826 3903 : r.CheckInputsToInternalizedString();
827 3903 : return r.ChangeToPureOperator(simplified()->ReferenceEqual());
828 : }
829 132333 : if (r.BothInputsAre(Type::String())) {
830 2360 : return r.ChangeToPureOperator(simplified()->StringEqual());
831 : }
832 :
833 : NumberOperationHint hint;
834 240266 : if (r.BothInputsAre(Type::Signed32()) ||
835 110293 : r.BothInputsAre(Type::Unsigned32())) {
836 20085 : return r.ChangeToPureOperator(simplified()->NumberEqual());
837 109888 : } else if (r.GetCompareNumberOperationHint(&hint)) {
838 : return r.ChangeToSpeculativeOperator(
839 33820 : simplified()->SpeculativeNumberEqual(hint), Type::Boolean());
840 92978 : } else if (r.BothInputsAre(Type::Number())) {
841 5322 : return r.ChangeToPureOperator(simplified()->NumberEqual());
842 87656 : } else if (r.IsReceiverCompareOperation()) {
843 : // For strict equality, it's enough to know that one input is a Receiver,
844 : // as a strict equality comparison with a Receiver can only yield true if
845 : // both sides refer to the same Receiver than.
846 680 : r.CheckLeftInputToReceiver();
847 680 : return r.ChangeToPureOperator(simplified()->ReferenceEqual());
848 86976 : } else if (r.IsStringCompareOperation()) {
849 3056 : r.CheckInputsToString();
850 3056 : return r.ChangeToPureOperator(simplified()->StringEqual());
851 83920 : } else if (r.IsSymbolCompareOperation()) {
852 0 : r.CheckInputsToSymbol();
853 0 : return r.ChangeToPureOperator(simplified()->ReferenceEqual());
854 : }
855 : return NoChange();
856 : }
857 :
858 175 : Reduction JSTypedLowering::ReduceJSToInteger(Node* node) {
859 175 : Node* const input = NodeProperties::GetValueInput(node, 0);
860 : Type* const input_type = NodeProperties::GetType(input);
861 350 : if (input_type->Is(type_cache_.kIntegerOrMinusZero)) {
862 : // JSToInteger(x:integer) => x
863 0 : ReplaceWithValue(node, input);
864 : return Replace(input);
865 : }
866 : return NoChange();
867 : }
868 :
869 1086 : Reduction JSTypedLowering::ReduceJSToName(Node* node) {
870 1086 : Node* const input = NodeProperties::GetValueInput(node, 0);
871 : Type* const input_type = NodeProperties::GetType(input);
872 1086 : if (input_type->Is(Type::Name())) {
873 : // JSToName(x:name) => x
874 167 : ReplaceWithValue(node, input);
875 : return Replace(input);
876 : }
877 : return NoChange();
878 : }
879 :
880 894 : Reduction JSTypedLowering::ReduceJSToLength(Node* node) {
881 867 : Node* input = NodeProperties::GetValueInput(node, 0);
882 : Type* input_type = NodeProperties::GetType(input);
883 1734 : if (input_type->Is(type_cache_.kIntegerOrMinusZero)) {
884 27 : if (input_type->Max() <= 0.0) {
885 2 : input = jsgraph()->ZeroConstant();
886 25 : } else if (input_type->Min() >= kMaxSafeInteger) {
887 2 : input = jsgraph()->Constant(kMaxSafeInteger);
888 : } else {
889 23 : if (input_type->Min() <= 0.0) {
890 : input = graph()->NewNode(simplified()->NumberMax(),
891 46 : jsgraph()->ZeroConstant(), input);
892 : }
893 23 : if (input_type->Max() > kMaxSafeInteger) {
894 : input = graph()->NewNode(simplified()->NumberMin(),
895 0 : jsgraph()->Constant(kMaxSafeInteger), input);
896 : }
897 : }
898 27 : ReplaceWithValue(node, input);
899 : return Replace(input);
900 : }
901 : return NoChange();
902 : }
903 :
904 306382 : Reduction JSTypedLowering::ReduceJSToNumberInput(Node* input) {
905 : // Try constant-folding of JSToNumber with constant inputs.
906 : Type* input_type = NodeProperties::GetType(input);
907 302005 : if (input_type->Is(Type::String())) {
908 : HeapObjectMatcher m(input);
909 3546 : if (m.HasValue() && m.Value()->IsString()) {
910 : Handle<Object> input_value = m.Value();
911 : return Replace(jsgraph()->Constant(
912 2424 : String::ToNumber(Handle<String>::cast(input_value))));
913 : }
914 : }
915 300793 : if (input_type->IsHeapConstant()) {
916 : Handle<Object> input_value = input_type->AsHeapConstant()->Value();
917 1199 : if (input_value->IsOddball()) {
918 : return Replace(jsgraph()->Constant(
919 2394 : Oddball::ToNumber(Handle<Oddball>::cast(input_value))));
920 : }
921 : }
922 299596 : if (input_type->Is(Type::Number())) {
923 : // JSToNumber(x:number) => x
924 : return Changed(input);
925 : }
926 19134 : if (input_type->Is(Type::Undefined())) {
927 : // JSToNumber(undefined) => #NaN
928 984 : return Replace(jsgraph()->NaNConstant());
929 : }
930 18150 : if (input_type->Is(Type::Null())) {
931 : // JSToNumber(null) => #0
932 984 : return Replace(jsgraph()->ZeroConstant());
933 : }
934 : return NoChange();
935 : }
936 :
937 11549 : Reduction JSTypedLowering::ReduceJSToNumber(Node* node) {
938 : // Try to reduce the input first.
939 : Node* const input = node->InputAt(0);
940 11549 : Reduction reduction = ReduceJSToNumberInput(input);
941 11549 : if (reduction.Changed()) {
942 2783 : ReplaceWithValue(node, reduction.replacement());
943 2783 : return reduction;
944 : }
945 : Type* const input_type = NodeProperties::GetType(input);
946 8766 : if (input_type->Is(Type::PlainPrimitive())) {
947 : RelaxEffectsAndControls(node);
948 186 : node->TrimInputCount(1);
949 186 : NodeProperties::ChangeOp(node, simplified()->PlainPrimitiveToNumber());
950 : return Changed(node);
951 : }
952 : return NoChange();
953 : }
954 :
955 55896 : Reduction JSTypedLowering::ReduceJSToStringInput(Node* input) {
956 55021 : if (input->opcode() == IrOpcode::kJSToString) {
957 : // Recursively try to reduce the input first.
958 976 : Reduction result = ReduceJSToString(input);
959 976 : if (result.Changed()) return result;
960 : return Changed(input); // JSToString(JSToString(x)) => JSToString(x)
961 : }
962 : Type* input_type = NodeProperties::GetType(input);
963 54045 : if (input_type->Is(Type::String())) {
964 : return Changed(input); // JSToString(x:string) => x
965 : }
966 36107 : if (input_type->Is(Type::Boolean())) {
967 : return Replace(graph()->NewNode(
968 : common()->Select(MachineRepresentation::kTagged), input,
969 : jsgraph()->HeapConstant(factory()->true_string()),
970 276 : jsgraph()->HeapConstant(factory()->false_string())));
971 : }
972 36038 : if (input_type->Is(Type::Undefined())) {
973 79 : return Replace(jsgraph()->HeapConstant(factory()->undefined_string()));
974 : }
975 35959 : if (input_type->Is(Type::Null())) {
976 25 : return Replace(jsgraph()->HeapConstant(factory()->null_string()));
977 : }
978 35934 : if (input_type->Is(Type::NaN())) {
979 82 : return Replace(jsgraph()->HeapConstant(factory()->NaN_string()));
980 : }
981 37816 : if (input_type->Is(Type::OrderedNumber()) &&
982 1964 : input_type->Min() == input_type->Max()) {
983 : // Note that we can use Type::OrderedNumber(), since
984 : // both 0 and -0 map to the String "0" in JavaScript.
985 : return Replace(jsgraph()->HeapConstant(
986 3500 : factory()->NumberToString(factory()->NewNumber(input_type->Min()))));
987 : }
988 : // TODO(turbofan): js-typed-lowering of ToString(x:number)
989 : return NoChange();
990 : }
991 :
992 3842 : Reduction JSTypedLowering::ReduceJSToString(Node* node) {
993 : DCHECK_EQ(IrOpcode::kJSToString, node->opcode());
994 : // Try to reduce the input first.
995 : Node* const input = node->InputAt(0);
996 3842 : Reduction reduction = ReduceJSToStringInput(input);
997 3842 : if (reduction.Changed()) {
998 179 : ReplaceWithValue(node, reduction.replacement());
999 179 : return reduction;
1000 : }
1001 : return NoChange();
1002 : }
1003 :
1004 7634 : Reduction JSTypedLowering::ReduceJSToObject(Node* node) {
1005 : DCHECK_EQ(IrOpcode::kJSToObject, node->opcode());
1006 3096 : Node* receiver = NodeProperties::GetValueInput(node, 0);
1007 : Type* receiver_type = NodeProperties::GetType(receiver);
1008 3096 : Node* context = NodeProperties::GetContextInput(node);
1009 3096 : Node* frame_state = NodeProperties::GetFrameStateInput(node);
1010 3096 : Node* effect = NodeProperties::GetEffectInput(node);
1011 3096 : Node* control = NodeProperties::GetControlInput(node);
1012 3096 : if (receiver_type->Is(Type::Receiver())) {
1013 3168 : ReplaceWithValue(node, receiver, effect, control);
1014 : return Replace(receiver);
1015 : }
1016 :
1017 : // Check whether {receiver} is a spec object.
1018 2269 : Node* check = graph()->NewNode(simplified()->ObjectIsReceiver(), receiver);
1019 : Node* branch =
1020 2269 : graph()->NewNode(common()->Branch(BranchHint::kTrue), check, control);
1021 :
1022 2269 : Node* if_true = graph()->NewNode(common()->IfTrue(), branch);
1023 : Node* etrue = effect;
1024 : Node* rtrue = receiver;
1025 :
1026 2269 : Node* if_false = graph()->NewNode(common()->IfFalse(), branch);
1027 : Node* efalse = effect;
1028 : Node* rfalse;
1029 : {
1030 : // Convert {receiver} using the ToObjectStub.
1031 2269 : Callable callable = Builtins::CallableFor(isolate(), Builtins::kToObject);
1032 : CallDescriptor const* const desc = Linkage::GetStubCallDescriptor(
1033 : isolate(), graph()->zone(), callable.descriptor(), 0,
1034 6807 : CallDescriptor::kNeedsFrameState, node->op()->properties());
1035 : rfalse = efalse = if_false = graph()->NewNode(
1036 : common()->Call(desc), jsgraph()->HeapConstant(callable.code()),
1037 6807 : receiver, context, frame_state, efalse, if_false);
1038 : }
1039 :
1040 : // Update potential {IfException} uses of {node} to point to the above
1041 : // ToObject stub call node instead. Note that the stub can only throw on
1042 : // receivers that can be null or undefined.
1043 2269 : Node* on_exception = nullptr;
1044 4458 : if (receiver_type->Maybe(Type::NullOrUndefined()) &&
1045 2189 : NodeProperties::IsExceptionalCall(node, &on_exception)) {
1046 72 : NodeProperties::ReplaceControlInput(on_exception, if_false);
1047 72 : NodeProperties::ReplaceEffectInput(on_exception, efalse);
1048 72 : if_false = graph()->NewNode(common()->IfSuccess(), if_false);
1049 72 : Revisit(on_exception);
1050 : }
1051 :
1052 2269 : control = graph()->NewNode(common()->Merge(2), if_true, if_false);
1053 2269 : effect = graph()->NewNode(common()->EffectPhi(2), etrue, efalse, control);
1054 :
1055 : // Morph the {node} into an appropriate Phi.
1056 : ReplaceWithValue(node, node, effect, control);
1057 2269 : node->ReplaceInput(0, rtrue);
1058 2269 : node->ReplaceInput(1, rfalse);
1059 2269 : node->ReplaceInput(2, control);
1060 2269 : node->TrimInputCount(3);
1061 : NodeProperties::ChangeOp(node,
1062 2269 : common()->Phi(MachineRepresentation::kTagged, 2));
1063 : return Changed(node);
1064 : }
1065 :
1066 931326 : Reduction JSTypedLowering::ReduceJSLoadNamed(Node* node) {
1067 : DCHECK_EQ(IrOpcode::kJSLoadNamed, node->opcode());
1068 465663 : Node* receiver = NodeProperties::GetValueInput(node, 0);
1069 : Type* receiver_type = NodeProperties::GetType(receiver);
1070 465663 : Node* effect = NodeProperties::GetEffectInput(node);
1071 465663 : Node* control = NodeProperties::GetControlInput(node);
1072 465663 : Handle<Name> name = NamedAccessOf(node->op()).name();
1073 : // Optimize "length" property of strings.
1074 493995 : if (name.is_identical_to(factory()->length_string()) &&
1075 : receiver_type->Is(Type::String())) {
1076 : Node* value = effect = graph()->NewNode(
1077 : simplified()->LoadField(AccessBuilder::ForStringLength()), receiver,
1078 795 : effect, control);
1079 265 : ReplaceWithValue(node, value, effect);
1080 : return Replace(value);
1081 : }
1082 : return NoChange();
1083 : }
1084 :
1085 10124 : Reduction JSTypedLowering::ReduceJSHasInPrototypeChain(Node* node) {
1086 : DCHECK_EQ(IrOpcode::kJSHasInPrototypeChain, node->opcode());
1087 1288 : Node* value = NodeProperties::GetValueInput(node, 0);
1088 : Type* value_type = NodeProperties::GetType(value);
1089 1288 : Node* prototype = NodeProperties::GetValueInput(node, 1);
1090 1288 : Node* context = NodeProperties::GetContextInput(node);
1091 1288 : Node* frame_state = NodeProperties::GetFrameStateInput(node);
1092 1288 : Node* effect = NodeProperties::GetEffectInput(node);
1093 1288 : Node* control = NodeProperties::GetControlInput(node);
1094 :
1095 : // If {value} cannot be a receiver, then it cannot have {prototype} in
1096 : // it's prototype chain (all Primitive values have a null prototype).
1097 1288 : if (value_type->Is(Type::Primitive())) {
1098 30 : Node* value = jsgraph()->FalseConstant();
1099 1352 : ReplaceWithValue(node, value, effect, control);
1100 : return Replace(value);
1101 : }
1102 :
1103 1258 : Node* check0 = graph()->NewNode(simplified()->ObjectIsSmi(), value);
1104 : Node* branch0 =
1105 1258 : graph()->NewNode(common()->Branch(BranchHint::kFalse), check0, control);
1106 :
1107 1258 : Node* if_true0 = graph()->NewNode(common()->IfTrue(), branch0);
1108 : Node* etrue0 = effect;
1109 1258 : Node* vtrue0 = jsgraph()->FalseConstant();
1110 :
1111 1258 : control = graph()->NewNode(common()->IfFalse(), branch0);
1112 :
1113 : // Loop through the {value}s prototype chain looking for the {prototype}.
1114 1258 : Node* loop = control = graph()->NewNode(common()->Loop(2), control, control);
1115 : Node* eloop = effect =
1116 1258 : graph()->NewNode(common()->EffectPhi(2), effect, effect, loop);
1117 : Node* vloop = value = graph()->NewNode(
1118 1258 : common()->Phi(MachineRepresentation::kTagged, 2), value, value, loop);
1119 : NodeProperties::SetType(vloop, Type::NonInternal());
1120 :
1121 : // Load the {value} map and instance type.
1122 : Node* value_map = effect = graph()->NewNode(
1123 3774 : simplified()->LoadField(AccessBuilder::ForMap()), value, effect, control);
1124 : Node* value_instance_type = effect = graph()->NewNode(
1125 : simplified()->LoadField(AccessBuilder::ForMapInstanceType()), value_map,
1126 3774 : effect, control);
1127 :
1128 : // Check if the {value} is a special receiver, because for special
1129 : // receivers, i.e. proxies or API values that need access checks,
1130 : // we have to use the %HasInPrototypeChain runtime function instead.
1131 : Node* check1 = graph()->NewNode(
1132 : simplified()->NumberLessThanOrEqual(), value_instance_type,
1133 2516 : jsgraph()->Constant(LAST_SPECIAL_RECEIVER_TYPE));
1134 : Node* branch1 =
1135 1258 : graph()->NewNode(common()->Branch(BranchHint::kFalse), check1, control);
1136 :
1137 1258 : control = graph()->NewNode(common()->IfFalse(), branch1);
1138 :
1139 1258 : Node* if_true1 = graph()->NewNode(common()->IfTrue(), branch1);
1140 : Node* etrue1 = effect;
1141 : Node* vtrue1;
1142 :
1143 : // Check if the {value} is not a receiver at all.
1144 : Node* check10 =
1145 : graph()->NewNode(simplified()->NumberLessThan(), value_instance_type,
1146 2516 : jsgraph()->Constant(FIRST_JS_RECEIVER_TYPE));
1147 : Node* branch10 =
1148 1258 : graph()->NewNode(common()->Branch(BranchHint::kTrue), check10, if_true1);
1149 :
1150 : // A primitive value cannot match the {prototype} we're looking for.
1151 1258 : if_true1 = graph()->NewNode(common()->IfTrue(), branch10);
1152 1258 : vtrue1 = jsgraph()->FalseConstant();
1153 :
1154 1258 : Node* if_false1 = graph()->NewNode(common()->IfFalse(), branch10);
1155 : Node* efalse1 = etrue1;
1156 : Node* vfalse1;
1157 : {
1158 : // Slow path, need to call the %HasInPrototypeChain runtime function.
1159 : vfalse1 = efalse1 = if_false1 = graph()->NewNode(
1160 : javascript()->CallRuntime(Runtime::kHasInPrototypeChain), value,
1161 1258 : prototype, context, frame_state, efalse1, if_false1);
1162 :
1163 : // Replace any potential {IfException} uses of {node} to catch
1164 : // exceptions from this %HasInPrototypeChain runtime call instead.
1165 1258 : Node* on_exception = nullptr;
1166 1258 : if (NodeProperties::IsExceptionalCall(node, &on_exception)) {
1167 64 : NodeProperties::ReplaceControlInput(on_exception, vfalse1);
1168 64 : NodeProperties::ReplaceEffectInput(on_exception, efalse1);
1169 64 : if_false1 = graph()->NewNode(common()->IfSuccess(), vfalse1);
1170 64 : Revisit(on_exception);
1171 : }
1172 : }
1173 :
1174 : // Load the {value} prototype.
1175 : Node* value_prototype = effect = graph()->NewNode(
1176 : simplified()->LoadField(AccessBuilder::ForMapPrototype()), value_map,
1177 3774 : effect, control);
1178 :
1179 : // Check if we reached the end of {value}s prototype chain.
1180 : Node* check2 = graph()->NewNode(simplified()->ReferenceEqual(),
1181 2516 : value_prototype, jsgraph()->NullConstant());
1182 1258 : Node* branch2 = graph()->NewNode(common()->Branch(), check2, control);
1183 :
1184 1258 : Node* if_true2 = graph()->NewNode(common()->IfTrue(), branch2);
1185 : Node* etrue2 = effect;
1186 1258 : Node* vtrue2 = jsgraph()->FalseConstant();
1187 :
1188 1258 : control = graph()->NewNode(common()->IfFalse(), branch2);
1189 :
1190 : // Check if we reached the {prototype}.
1191 : Node* check3 = graph()->NewNode(simplified()->ReferenceEqual(),
1192 1258 : value_prototype, prototype);
1193 1258 : Node* branch3 = graph()->NewNode(common()->Branch(), check3, control);
1194 :
1195 1258 : Node* if_true3 = graph()->NewNode(common()->IfTrue(), branch3);
1196 : Node* etrue3 = effect;
1197 1258 : Node* vtrue3 = jsgraph()->TrueConstant();
1198 :
1199 1258 : control = graph()->NewNode(common()->IfFalse(), branch3);
1200 :
1201 : // Close the loop.
1202 1258 : vloop->ReplaceInput(1, value_prototype);
1203 1258 : eloop->ReplaceInput(1, effect);
1204 1258 : loop->ReplaceInput(1, control);
1205 :
1206 : control = graph()->NewNode(common()->Merge(5), if_true0, if_true1, if_true2,
1207 1258 : if_true3, if_false1);
1208 : effect = graph()->NewNode(common()->EffectPhi(5), etrue0, etrue1, etrue2,
1209 1258 : etrue3, efalse1, control);
1210 :
1211 : // Morph the {node} into an appropriate Phi.
1212 : ReplaceWithValue(node, node, effect, control);
1213 1258 : node->ReplaceInput(0, vtrue0);
1214 1258 : node->ReplaceInput(1, vtrue1);
1215 1258 : node->ReplaceInput(2, vtrue2);
1216 1258 : node->ReplaceInput(3, vtrue3);
1217 1258 : node->ReplaceInput(4, vfalse1);
1218 1258 : node->ReplaceInput(5, control);
1219 1258 : node->TrimInputCount(6);
1220 : NodeProperties::ChangeOp(node,
1221 1258 : common()->Phi(MachineRepresentation::kTagged, 5));
1222 : return Changed(node);
1223 : }
1224 :
1225 99 : Reduction JSTypedLowering::ReduceJSOrdinaryHasInstance(Node* node) {
1226 : DCHECK_EQ(IrOpcode::kJSOrdinaryHasInstance, node->opcode());
1227 75 : Node* constructor = NodeProperties::GetValueInput(node, 0);
1228 : Type* constructor_type = NodeProperties::GetType(constructor);
1229 75 : Node* object = NodeProperties::GetValueInput(node, 1);
1230 : Type* object_type = NodeProperties::GetType(object);
1231 :
1232 : // Check if the {constructor} cannot be callable.
1233 : // See ES6 section 7.3.19 OrdinaryHasInstance ( C, O ) step 1.
1234 75 : if (!constructor_type->Maybe(Type::Callable())) {
1235 8 : Node* value = jsgraph()->FalseConstant();
1236 24 : ReplaceWithValue(node, value);
1237 : return Replace(value);
1238 : }
1239 :
1240 : // If the {constructor} cannot be a JSBoundFunction and then {object}
1241 : // cannot be a JSReceiver, then this can be constant-folded to false.
1242 : // See ES6 section 7.3.19 OrdinaryHasInstance ( C, O ) step 2 and 3.
1243 83 : if (!object_type->Maybe(Type::Receiver()) &&
1244 16 : !constructor_type->Maybe(Type::BoundFunction())) {
1245 16 : Node* value = jsgraph()->FalseConstant();
1246 : ReplaceWithValue(node, value);
1247 : return Replace(value);
1248 : }
1249 :
1250 : return NoChange();
1251 : }
1252 :
1253 1374800 : Reduction JSTypedLowering::ReduceJSLoadContext(Node* node) {
1254 : DCHECK_EQ(IrOpcode::kJSLoadContext, node->opcode());
1255 2063945 : ContextAccess const& access = ContextAccessOf(node->op());
1256 687400 : Node* effect = NodeProperties::GetEffectInput(node);
1257 687400 : Node* context = NodeProperties::GetContextInput(node);
1258 687400 : Node* control = graph()->start();
1259 1378290 : for (size_t i = 0; i < access.depth(); ++i) {
1260 : context = effect = graph()->NewNode(
1261 : simplified()->LoadField(
1262 : AccessBuilder::ForContextSlot(Context::PREVIOUS_INDEX)),
1263 5235 : context, effect, control);
1264 : }
1265 687400 : node->ReplaceInput(0, context);
1266 687400 : node->ReplaceInput(1, effect);
1267 687400 : node->AppendInput(jsgraph()->zone(), control);
1268 : NodeProperties::ChangeOp(
1269 : node,
1270 1374800 : simplified()->LoadField(AccessBuilder::ForContextSlot(access.index())));
1271 687400 : return Changed(node);
1272 : }
1273 :
1274 345503 : Reduction JSTypedLowering::ReduceJSStoreContext(Node* node) {
1275 : DCHECK_EQ(IrOpcode::kJSStoreContext, node->opcode());
1276 1036557 : ContextAccess const& access = ContextAccessOf(node->op());
1277 345503 : Node* effect = NodeProperties::GetEffectInput(node);
1278 345503 : Node* context = NodeProperties::GetContextInput(node);
1279 345503 : Node* control = graph()->start();
1280 345503 : Node* value = NodeProperties::GetValueInput(node, 0);
1281 691102 : for (size_t i = 0; i < access.depth(); ++i) {
1282 : context = effect = graph()->NewNode(
1283 : simplified()->LoadField(
1284 : AccessBuilder::ForContextSlot(Context::PREVIOUS_INDEX)),
1285 144 : context, effect, control);
1286 : }
1287 345503 : node->ReplaceInput(0, context);
1288 345503 : node->ReplaceInput(1, value);
1289 345503 : node->ReplaceInput(2, effect);
1290 : NodeProperties::ChangeOp(
1291 : node,
1292 691006 : simplified()->StoreField(AccessBuilder::ForContextSlot(access.index())));
1293 345503 : return Changed(node);
1294 : }
1295 :
1296 7307 : Node* JSTypedLowering::BuildGetModuleCell(Node* node) {
1297 : DCHECK(node->opcode() == IrOpcode::kJSLoadModule ||
1298 : node->opcode() == IrOpcode::kJSStoreModule);
1299 7163 : Node* effect = NodeProperties::GetEffectInput(node);
1300 7163 : Node* control = NodeProperties::GetControlInput(node);
1301 :
1302 7163 : int32_t cell_index = OpParameter<int32_t>(node);
1303 7163 : Node* module = NodeProperties::GetValueInput(node, 0);
1304 : Type* module_type = NodeProperties::GetType(module);
1305 :
1306 7163 : if (module_type->IsHeapConstant()) {
1307 : Handle<Module> module_constant =
1308 : Handle<Module>::cast(module_type->AsHeapConstant()->Value());
1309 144 : Handle<Cell> cell_constant(module_constant->GetCell(cell_index), isolate());
1310 144 : return jsgraph()->HeapConstant(cell_constant);
1311 : }
1312 :
1313 : FieldAccess field_access;
1314 : int index;
1315 7019 : if (ModuleDescriptor::GetCellIndexKind(cell_index) ==
1316 : ModuleDescriptor::kExport) {
1317 6932 : field_access = AccessBuilder::ForModuleRegularExports();
1318 6932 : index = cell_index - 1;
1319 : } else {
1320 : DCHECK_EQ(ModuleDescriptor::GetCellIndexKind(cell_index),
1321 : ModuleDescriptor::kImport);
1322 87 : field_access = AccessBuilder::ForModuleRegularImports();
1323 87 : index = -cell_index - 1;
1324 : }
1325 : Node* array = effect = graph()->NewNode(simplified()->LoadField(field_access),
1326 7019 : module, effect, control);
1327 : return graph()->NewNode(
1328 7019 : simplified()->LoadField(AccessBuilder::ForFixedArraySlot(index)), array,
1329 21057 : effect, control);
1330 : }
1331 :
1332 280 : Reduction JSTypedLowering::ReduceJSLoadModule(Node* node) {
1333 : DCHECK_EQ(IrOpcode::kJSLoadModule, node->opcode());
1334 280 : Node* effect = NodeProperties::GetEffectInput(node);
1335 280 : Node* control = NodeProperties::GetControlInput(node);
1336 :
1337 280 : Node* cell = BuildGetModuleCell(node);
1338 560 : if (cell->op()->EffectOutputCount() > 0) effect = cell;
1339 : Node* value = effect =
1340 : graph()->NewNode(simplified()->LoadField(AccessBuilder::ForCellValue()),
1341 840 : cell, effect, control);
1342 :
1343 280 : ReplaceWithValue(node, value, effect, control);
1344 280 : return Changed(value);
1345 : }
1346 :
1347 6883 : Reduction JSTypedLowering::ReduceJSStoreModule(Node* node) {
1348 : DCHECK_EQ(IrOpcode::kJSStoreModule, node->opcode());
1349 6883 : Node* effect = NodeProperties::GetEffectInput(node);
1350 6883 : Node* control = NodeProperties::GetControlInput(node);
1351 6883 : Node* value = NodeProperties::GetValueInput(node, 1);
1352 : DCHECK_EQ(ModuleDescriptor::GetCellIndexKind(OpParameter<int32_t>(node)),
1353 : ModuleDescriptor::kExport);
1354 :
1355 6883 : Node* cell = BuildGetModuleCell(node);
1356 13766 : if (cell->op()->EffectOutputCount() > 0) effect = cell;
1357 : effect =
1358 : graph()->NewNode(simplified()->StoreField(AccessBuilder::ForCellValue()),
1359 20649 : cell, value, effect, control);
1360 :
1361 6883 : ReplaceWithValue(node, effect, effect, control);
1362 6883 : return Changed(value);
1363 : }
1364 :
1365 177848 : Reduction JSTypedLowering::ReduceJSConvertReceiver(Node* node) {
1366 : DCHECK_EQ(IrOpcode::kJSConvertReceiver, node->opcode());
1367 128052 : ConvertReceiverMode mode = ConvertReceiverModeOf(node->op());
1368 128052 : Node* receiver = NodeProperties::GetValueInput(node, 0);
1369 : Type* receiver_type = NodeProperties::GetType(receiver);
1370 128052 : Node* context = NodeProperties::GetContextInput(node);
1371 : Type* context_type = NodeProperties::GetType(context);
1372 128052 : Node* effect = NodeProperties::GetEffectInput(node);
1373 128052 : Node* control = NodeProperties::GetControlInput(node);
1374 :
1375 : // Check if {receiver} is known to be a receiver.
1376 128052 : if (receiver_type->Is(Type::Receiver())) {
1377 128052 : ReplaceWithValue(node, receiver, effect, control);
1378 : return Replace(receiver);
1379 : }
1380 :
1381 : // If the {receiver} is known to be null or undefined, we can just replace it
1382 : // with the global proxy unconditionally.
1383 128025 : if (receiver_type->Is(Type::NullOrUndefined()) ||
1384 : mode == ConvertReceiverMode::kNullOrUndefined) {
1385 127095 : if (context_type->IsHeapConstant()) {
1386 : Handle<JSObject> global_proxy(
1387 : Handle<Context>::cast(context_type->AsHeapConstant()->Value())
1388 : ->global_proxy(),
1389 47867 : isolate());
1390 47867 : receiver = jsgraph()->Constant(global_proxy);
1391 : } else {
1392 : Node* native_context = effect = graph()->NewNode(
1393 : javascript()->LoadContext(0, Context::NATIVE_CONTEXT_INDEX, true),
1394 79228 : context, effect);
1395 : receiver = effect = graph()->NewNode(
1396 : javascript()->LoadContext(0, Context::GLOBAL_PROXY_INDEX, true),
1397 79228 : native_context, effect);
1398 : }
1399 : ReplaceWithValue(node, receiver, effect, control);
1400 : return Replace(receiver);
1401 : }
1402 :
1403 : // If {receiver} cannot be null or undefined we can skip a few checks.
1404 930 : if (!receiver_type->Maybe(Type::NullOrUndefined()) ||
1405 : mode == ConvertReceiverMode::kNotNullOrUndefined) {
1406 907 : Node* check = graph()->NewNode(simplified()->ObjectIsReceiver(), receiver);
1407 : Node* branch =
1408 907 : graph()->NewNode(common()->Branch(BranchHint::kTrue), check, control);
1409 :
1410 907 : Node* if_true = graph()->NewNode(common()->IfTrue(), branch);
1411 : Node* etrue = effect;
1412 : Node* rtrue = receiver;
1413 :
1414 907 : Node* if_false = graph()->NewNode(common()->IfFalse(), branch);
1415 : Node* efalse = effect;
1416 : Node* rfalse;
1417 : {
1418 : // Convert {receiver} using the ToObjectStub. The call does not require a
1419 : // frame-state in this case, because neither null nor undefined is passed.
1420 907 : Callable callable = Builtins::CallableFor(isolate(), Builtins::kToObject);
1421 : CallDescriptor const* const desc = Linkage::GetStubCallDescriptor(
1422 : isolate(), graph()->zone(), callable.descriptor(), 0,
1423 2721 : CallDescriptor::kNoFlags, node->op()->properties());
1424 : rfalse = efalse = graph()->NewNode(
1425 : common()->Call(desc), jsgraph()->HeapConstant(callable.code()),
1426 2721 : receiver, context, efalse);
1427 : }
1428 :
1429 907 : control = graph()->NewNode(common()->Merge(2), if_true, if_false);
1430 907 : effect = graph()->NewNode(common()->EffectPhi(2), etrue, efalse, control);
1431 :
1432 : // Morph the {node} into an appropriate Phi.
1433 : ReplaceWithValue(node, node, effect, control);
1434 907 : node->ReplaceInput(0, rtrue);
1435 907 : node->ReplaceInput(1, rfalse);
1436 907 : node->ReplaceInput(2, control);
1437 907 : node->TrimInputCount(3);
1438 : NodeProperties::ChangeOp(node,
1439 907 : common()->Phi(MachineRepresentation::kTagged, 2));
1440 : return Changed(node);
1441 : }
1442 :
1443 : // Check if {receiver} is already a JSReceiver.
1444 23 : Node* check0 = graph()->NewNode(simplified()->ObjectIsReceiver(), receiver);
1445 : Node* branch0 =
1446 23 : graph()->NewNode(common()->Branch(BranchHint::kTrue), check0, control);
1447 23 : Node* if_true0 = graph()->NewNode(common()->IfTrue(), branch0);
1448 23 : Node* if_false0 = graph()->NewNode(common()->IfFalse(), branch0);
1449 :
1450 : // Check {receiver} for undefined.
1451 : Node* check1 = graph()->NewNode(simplified()->ReferenceEqual(), receiver,
1452 46 : jsgraph()->UndefinedConstant());
1453 : Node* branch1 =
1454 23 : graph()->NewNode(common()->Branch(BranchHint::kFalse), check1, if_false0);
1455 23 : Node* if_true1 = graph()->NewNode(common()->IfTrue(), branch1);
1456 23 : Node* if_false1 = graph()->NewNode(common()->IfFalse(), branch1);
1457 :
1458 : // Check {receiver} for null.
1459 : Node* check2 = graph()->NewNode(simplified()->ReferenceEqual(), receiver,
1460 46 : jsgraph()->NullConstant());
1461 : Node* branch2 =
1462 23 : graph()->NewNode(common()->Branch(BranchHint::kFalse), check2, if_false1);
1463 23 : Node* if_true2 = graph()->NewNode(common()->IfTrue(), branch2);
1464 23 : Node* if_false2 = graph()->NewNode(common()->IfFalse(), branch2);
1465 :
1466 : // We just use {receiver} directly.
1467 : Node* if_noop = if_true0;
1468 : Node* enoop = effect;
1469 : Node* rnoop = receiver;
1470 :
1471 : // Convert {receiver} using ToObject.
1472 : Node* if_convert = if_false2;
1473 : Node* econvert = effect;
1474 : Node* rconvert;
1475 : {
1476 : // Convert {receiver} using the ToObjectStub. The call does not require a
1477 : // frame-state in this case, because neither null nor undefined is passed.
1478 23 : Callable callable = Builtins::CallableFor(isolate(), Builtins::kToObject);
1479 : CallDescriptor const* const desc = Linkage::GetStubCallDescriptor(
1480 : isolate(), graph()->zone(), callable.descriptor(), 0,
1481 69 : CallDescriptor::kNoFlags, node->op()->properties());
1482 : rconvert = econvert = graph()->NewNode(
1483 : common()->Call(desc), jsgraph()->HeapConstant(callable.code()),
1484 69 : receiver, context, econvert);
1485 : }
1486 :
1487 : // Replace {receiver} with global proxy of {context}.
1488 23 : Node* if_global = graph()->NewNode(common()->Merge(2), if_true1, if_true2);
1489 : Node* eglobal = effect;
1490 : Node* rglobal;
1491 : {
1492 23 : if (context_type->IsHeapConstant()) {
1493 : Handle<JSObject> global_proxy(
1494 : Handle<Context>::cast(context_type->AsHeapConstant()->Value())
1495 : ->global_proxy(),
1496 23 : isolate());
1497 23 : rglobal = jsgraph()->Constant(global_proxy);
1498 : } else {
1499 : Node* native_context = eglobal = graph()->NewNode(
1500 : javascript()->LoadContext(0, Context::NATIVE_CONTEXT_INDEX, true),
1501 0 : context, eglobal);
1502 : rglobal = eglobal = graph()->NewNode(
1503 : javascript()->LoadContext(0, Context::GLOBAL_PROXY_INDEX, true),
1504 0 : native_context, eglobal);
1505 : }
1506 : }
1507 :
1508 : control =
1509 23 : graph()->NewNode(common()->Merge(3), if_noop, if_convert, if_global);
1510 : effect = graph()->NewNode(common()->EffectPhi(3), enoop, econvert, eglobal,
1511 23 : control);
1512 : // Morph the {node} into an appropriate Phi.
1513 : ReplaceWithValue(node, node, effect, control);
1514 23 : node->ReplaceInput(0, rnoop);
1515 23 : node->ReplaceInput(1, rconvert);
1516 23 : node->ReplaceInput(2, rglobal);
1517 23 : node->ReplaceInput(3, control);
1518 23 : node->TrimInputCount(4);
1519 : NodeProperties::ChangeOp(node,
1520 23 : common()->Phi(MachineRepresentation::kTagged, 3));
1521 : return Changed(node);
1522 : }
1523 :
1524 : namespace {
1525 :
1526 23520 : void ReduceBuiltin(Isolate* isolate, JSGraph* jsgraph, Node* node,
1527 : int builtin_index, int arity, CallDescriptor::Flags flags) {
1528 : // Patch {node} to a direct CEntryStub call.
1529 : //
1530 : // ----------- A r g u m e n t s -----------
1531 : // -- 0: CEntryStub
1532 : // --- Stack args ---
1533 : // -- 1: receiver
1534 : // -- [2, 2 + n[: the n actual arguments passed to the builtin
1535 : // -- 2 + n: argc, including the receiver and implicit args (Smi)
1536 : // -- 2 + n + 1: target
1537 : // -- 2 + n + 2: new_target
1538 : // --- Register args ---
1539 : // -- 2 + n + 3: the C entry point
1540 : // -- 2 + n + 4: argc (Int32)
1541 : // -----------------------------------
1542 :
1543 : // The logic contained here is mirrored in Builtins::Generate_Adaptor.
1544 : // Keep these in sync.
1545 :
1546 7840 : const bool is_construct = (node->opcode() == IrOpcode::kJSConstruct);
1547 :
1548 : DCHECK(Builtins::HasCppImplementation(builtin_index));
1549 : DCHECK_EQ(0, flags & CallDescriptor::kSupportsTailCalls);
1550 :
1551 7840 : Node* target = NodeProperties::GetValueInput(node, 0);
1552 : Node* new_target = is_construct
1553 2558 : ? NodeProperties::GetValueInput(node, arity + 1)
1554 10398 : : jsgraph->UndefinedConstant();
1555 :
1556 : // API and CPP builtins are implemented in C++, and we can inline both.
1557 : // CPP builtins create a builtin exit frame, API builtins don't.
1558 7840 : const bool has_builtin_exit_frame = Builtins::IsCpp(builtin_index);
1559 :
1560 : Node* stub = jsgraph->CEntryStubConstant(1, kDontSaveFPRegs, kArgvOnStack,
1561 7840 : has_builtin_exit_frame);
1562 7840 : node->ReplaceInput(0, stub);
1563 :
1564 : Zone* zone = jsgraph->zone();
1565 7840 : if (is_construct) {
1566 : // Unify representations between construct and call nodes.
1567 : // Remove new target and add receiver as a stack parameter.
1568 2558 : Node* receiver = jsgraph->UndefinedConstant();
1569 2558 : node->RemoveInput(arity + 1);
1570 2558 : node->InsertInput(zone, 1, receiver);
1571 : }
1572 :
1573 7840 : const int argc = arity + BuiltinArguments::kNumExtraArgsWithReceiver;
1574 7840 : Node* argc_node = jsgraph->Constant(argc);
1575 :
1576 : static const int kStubAndReceiver = 2;
1577 7840 : int cursor = arity + kStubAndReceiver;
1578 7840 : node->InsertInput(zone, cursor++, jsgraph->PaddingConstant());
1579 7840 : node->InsertInput(zone, cursor++, argc_node);
1580 7840 : node->InsertInput(zone, cursor++, target);
1581 7840 : node->InsertInput(zone, cursor++, new_target);
1582 :
1583 7840 : Address entry = Builtins::CppEntryOf(builtin_index);
1584 7840 : ExternalReference entry_ref(ExternalReference(entry, isolate));
1585 7840 : Node* entry_node = jsgraph->ExternalConstant(entry_ref);
1586 :
1587 7840 : node->InsertInput(zone, cursor++, entry_node);
1588 7840 : node->InsertInput(zone, cursor++, argc_node);
1589 :
1590 : static const int kReturnCount = 1;
1591 7840 : const char* debug_name = Builtins::name(builtin_index);
1592 7840 : Operator::Properties properties = node->op()->properties();
1593 : CallDescriptor* desc = Linkage::GetCEntryStubCallDescriptor(
1594 7840 : zone, kReturnCount, argc, debug_name, properties, flags);
1595 :
1596 7840 : NodeProperties::ChangeOp(node, jsgraph->common()->Call(desc));
1597 7840 : }
1598 :
1599 : bool NeedsArgumentAdaptorFrame(Handle<SharedFunctionInfo> shared, int arity) {
1600 : static const int sentinel = SharedFunctionInfo::kDontAdaptArgumentsSentinel;
1601 : const int num_decl_parms = shared->internal_formal_parameter_count();
1602 196588 : return (num_decl_parms != arity && num_decl_parms != sentinel);
1603 : }
1604 :
1605 : } // namespace
1606 :
1607 2181 : Reduction JSTypedLowering::ReduceJSConstructForwardVarargs(Node* node) {
1608 : DCHECK_EQ(IrOpcode::kJSConstructForwardVarargs, node->opcode());
1609 : ConstructForwardVarargsParameters p =
1610 453 : ConstructForwardVarargsParametersOf(node->op());
1611 : DCHECK_LE(2u, p.arity());
1612 453 : int const arity = static_cast<int>(p.arity() - 2);
1613 453 : int const start_index = static_cast<int>(p.start_index());
1614 453 : Node* target = NodeProperties::GetValueInput(node, 0);
1615 : Type* target_type = NodeProperties::GetType(target);
1616 453 : Node* new_target = NodeProperties::GetValueInput(node, arity + 1);
1617 :
1618 : // Check if {target} is a JSFunction.
1619 453 : if (target_type->Is(Type::Function())) {
1620 : // Patch {node} to an indirect call via ConstructFunctionForwardVarargs.
1621 432 : Callable callable = CodeFactory::ConstructFunctionForwardVarargs(isolate());
1622 432 : node->RemoveInput(arity + 1);
1623 : node->InsertInput(graph()->zone(), 0,
1624 864 : jsgraph()->HeapConstant(callable.code()));
1625 432 : node->InsertInput(graph()->zone(), 2, new_target);
1626 864 : node->InsertInput(graph()->zone(), 3, jsgraph()->Constant(arity));
1627 864 : node->InsertInput(graph()->zone(), 4, jsgraph()->Constant(start_index));
1628 864 : node->InsertInput(graph()->zone(), 5, jsgraph()->UndefinedConstant());
1629 : NodeProperties::ChangeOp(
1630 : node, common()->Call(Linkage::GetStubCallDescriptor(
1631 : isolate(), graph()->zone(), callable.descriptor(), arity + 1,
1632 1296 : CallDescriptor::kNeedsFrameState)));
1633 : return Changed(node);
1634 : }
1635 :
1636 : return NoChange();
1637 : }
1638 :
1639 90129 : Reduction JSTypedLowering::ReduceJSConstruct(Node* node) {
1640 : DCHECK_EQ(IrOpcode::kJSConstruct, node->opcode());
1641 28064 : ConstructParameters const& p = ConstructParametersOf(node->op());
1642 : DCHECK_LE(2u, p.arity());
1643 28064 : int const arity = static_cast<int>(p.arity() - 2);
1644 28064 : Node* target = NodeProperties::GetValueInput(node, 0);
1645 : Type* target_type = NodeProperties::GetType(target);
1646 28064 : Node* new_target = NodeProperties::GetValueInput(node, arity + 1);
1647 28064 : Node* effect = NodeProperties::GetEffectInput(node);
1648 28064 : Node* control = NodeProperties::GetControlInput(node);
1649 :
1650 : // Check if {target} is a known JSFunction.
1651 46260 : if (target_type->IsHeapConstant() &&
1652 : target_type->AsHeapConstant()->Value()->IsJSFunction()) {
1653 : Handle<JSFunction> function =
1654 : Handle<JSFunction>::cast(target_type->AsHeapConstant()->Value());
1655 : Handle<SharedFunctionInfo> shared(function->shared(), isolate());
1656 : const int builtin_index = shared->construct_stub()->builtin_index();
1657 : const bool is_builtin = (builtin_index != -1);
1658 :
1659 : CallDescriptor::Flags flags = CallDescriptor::kNeedsFrameState;
1660 :
1661 19422 : if (is_builtin && Builtins::HasCppImplementation(builtin_index) &&
1662 : !NeedsArgumentAdaptorFrame(shared, arity)) {
1663 : // Patch {node} to a direct CEntryStub call.
1664 :
1665 : // Load the context from the {target}.
1666 : Node* context = effect = graph()->NewNode(
1667 : simplified()->LoadField(AccessBuilder::ForJSFunctionContext()),
1668 7674 : target, effect, control);
1669 2558 : NodeProperties::ReplaceContextInput(node, context);
1670 :
1671 : // Update the effect dependency for the {node}.
1672 2558 : NodeProperties::ReplaceEffectInput(node, effect);
1673 :
1674 2558 : ReduceBuiltin(isolate(), jsgraph(), node, builtin_index, arity, flags);
1675 : } else {
1676 : // Patch {node} to an indirect call via the {function}s construct stub.
1677 : Callable callable(handle(shared->construct_stub(), isolate()),
1678 28612 : ConstructStubDescriptor(isolate()));
1679 14306 : node->RemoveInput(arity + 1);
1680 : node->InsertInput(graph()->zone(), 0,
1681 28612 : jsgraph()->HeapConstant(callable.code()));
1682 14306 : node->InsertInput(graph()->zone(), 2, new_target);
1683 28612 : node->InsertInput(graph()->zone(), 3, jsgraph()->Constant(arity));
1684 28612 : node->InsertInput(graph()->zone(), 4, jsgraph()->UndefinedConstant());
1685 28612 : node->InsertInput(graph()->zone(), 5, jsgraph()->UndefinedConstant());
1686 : NodeProperties::ChangeOp(
1687 : node, common()->Call(Linkage::GetStubCallDescriptor(
1688 : isolate(), graph()->zone(), callable.descriptor(),
1689 42918 : 1 + arity, flags)));
1690 : }
1691 : return Changed(node);
1692 : }
1693 :
1694 : // Check if {target} is a JSFunction.
1695 11200 : if (target_type->Is(Type::Function())) {
1696 : // Patch {node} to an indirect call via the ConstructFunction builtin.
1697 761 : Callable callable = CodeFactory::ConstructFunction(isolate());
1698 761 : node->RemoveInput(arity + 1);
1699 : node->InsertInput(graph()->zone(), 0,
1700 1522 : jsgraph()->HeapConstant(callable.code()));
1701 761 : node->InsertInput(graph()->zone(), 2, new_target);
1702 1522 : node->InsertInput(graph()->zone(), 3, jsgraph()->Constant(arity));
1703 1522 : node->InsertInput(graph()->zone(), 4, jsgraph()->UndefinedConstant());
1704 : NodeProperties::ChangeOp(
1705 : node, common()->Call(Linkage::GetStubCallDescriptor(
1706 : isolate(), graph()->zone(), callable.descriptor(), 1 + arity,
1707 2283 : CallDescriptor::kNeedsFrameState)));
1708 : return Changed(node);
1709 : }
1710 :
1711 : return NoChange();
1712 : }
1713 :
1714 1338 : Reduction JSTypedLowering::ReduceJSCallForwardVarargs(Node* node) {
1715 : DCHECK_EQ(IrOpcode::kJSCallForwardVarargs, node->opcode());
1716 384 : CallForwardVarargsParameters p = CallForwardVarargsParametersOf(node->op());
1717 : DCHECK_LE(2u, p.arity());
1718 384 : int const arity = static_cast<int>(p.arity() - 2);
1719 384 : int const start_index = static_cast<int>(p.start_index());
1720 384 : Node* target = NodeProperties::GetValueInput(node, 0);
1721 : Type* target_type = NodeProperties::GetType(target);
1722 :
1723 : // Check if {target} is a JSFunction.
1724 384 : if (target_type->Is(Type::Function())) {
1725 : // Compute flags for the call.
1726 : CallDescriptor::Flags flags = CallDescriptor::kNeedsFrameState;
1727 : // Patch {node} to an indirect call via CallFunctionForwardVarargs.
1728 318 : Callable callable = CodeFactory::CallFunctionForwardVarargs(isolate());
1729 : node->InsertInput(graph()->zone(), 0,
1730 636 : jsgraph()->HeapConstant(callable.code()));
1731 636 : node->InsertInput(graph()->zone(), 2, jsgraph()->Constant(arity));
1732 636 : node->InsertInput(graph()->zone(), 3, jsgraph()->Constant(start_index));
1733 : NodeProperties::ChangeOp(
1734 : node, common()->Call(Linkage::GetStubCallDescriptor(
1735 : isolate(), graph()->zone(), callable.descriptor(), arity + 1,
1736 1272 : flags)));
1737 : return Changed(node);
1738 : }
1739 :
1740 : return NoChange();
1741 : }
1742 :
1743 1039195 : Reduction JSTypedLowering::ReduceJSCall(Node* node) {
1744 : DCHECK_EQ(IrOpcode::kJSCall, node->opcode());
1745 733450 : CallParameters const& p = CallParametersOf(node->op());
1746 480809 : int const arity = static_cast<int>(p.arity() - 2);
1747 : ConvertReceiverMode convert_mode = p.convert_mode();
1748 480809 : Node* target = NodeProperties::GetValueInput(node, 0);
1749 : Type* target_type = NodeProperties::GetType(target);
1750 480809 : Node* receiver = NodeProperties::GetValueInput(node, 1);
1751 : Type* receiver_type = NodeProperties::GetType(receiver);
1752 480809 : Node* effect = NodeProperties::GetEffectInput(node);
1753 480811 : Node* control = NodeProperties::GetControlInput(node);
1754 :
1755 : // Try to infer receiver {convert_mode} from {receiver} type.
1756 480810 : if (receiver_type->Is(Type::NullOrUndefined())) {
1757 : convert_mode = ConvertReceiverMode::kNullOrUndefined;
1758 157166 : } else if (!receiver_type->Maybe(Type::NullOrUndefined())) {
1759 : convert_mode = ConvertReceiverMode::kNotNullOrUndefined;
1760 : }
1761 :
1762 : // Check if {target} is a known JSFunction.
1763 674888 : if (target_type->IsHeapConstant() &&
1764 : target_type->AsHeapConstant()->Value()->IsJSFunction()) {
1765 : Handle<JSFunction> function =
1766 : Handle<JSFunction>::cast(target_type->AsHeapConstant()->Value());
1767 : Handle<SharedFunctionInfo> shared(function->shared(), isolate());
1768 : const int builtin_index = shared->code()->builtin_index();
1769 : const bool is_builtin = (builtin_index != -1);
1770 :
1771 : // Class constructors are callable, but [[Call]] will raise an exception.
1772 : // See ES6 section 9.2.1 [[Call]] ( thisArgument, argumentsList ).
1773 194030 : if (IsClassConstructor(shared->kind())) return NoChange();
1774 :
1775 : // Load the context from the {target}.
1776 : Node* context = effect = graph()->NewNode(
1777 : simplified()->LoadField(AccessBuilder::ForJSFunctionContext()), target,
1778 582090 : effect, control);
1779 194030 : NodeProperties::ReplaceContextInput(node, context);
1780 :
1781 : // Check if we need to convert the {receiver}.
1782 353302 : if (is_sloppy(shared->language_mode()) && !shared->native() &&
1783 : !receiver_type->Is(Type::Receiver())) {
1784 : receiver = effect =
1785 : graph()->NewNode(javascript()->ConvertReceiver(convert_mode),
1786 79511 : receiver, context, effect, control);
1787 79511 : NodeProperties::ReplaceValueInput(node, receiver, 1);
1788 : }
1789 :
1790 : // Update the effect dependency for the {node}.
1791 194030 : NodeProperties::ReplaceEffectInput(node, effect);
1792 :
1793 : // Compute flags for the call.
1794 : CallDescriptor::Flags flags = CallDescriptor::kNeedsFrameState;
1795 194030 : Node* new_target = jsgraph()->UndefinedConstant();
1796 194030 : Node* argument_count = jsgraph()->Constant(arity);
1797 194030 : if (NeedsArgumentAdaptorFrame(shared, arity)) {
1798 : // Patch {node} to an indirect call via the ArgumentsAdaptorTrampoline.
1799 48383 : Callable callable = CodeFactory::ArgumentAdaptor(isolate());
1800 : node->InsertInput(graph()->zone(), 0,
1801 96766 : jsgraph()->HeapConstant(callable.code()));
1802 48383 : node->InsertInput(graph()->zone(), 2, new_target);
1803 48383 : node->InsertInput(graph()->zone(), 3, argument_count);
1804 : node->InsertInput(
1805 : graph()->zone(), 4,
1806 96766 : jsgraph()->Constant(shared->internal_formal_parameter_count()));
1807 : NodeProperties::ChangeOp(
1808 : node, common()->Call(Linkage::GetStubCallDescriptor(
1809 : isolate(), graph()->zone(), callable.descriptor(),
1810 193532 : 1 + arity, flags)));
1811 145647 : } else if (is_builtin && Builtins::HasCppImplementation(builtin_index)) {
1812 : // Patch {node} to a direct CEntryStub call.
1813 5282 : ReduceBuiltin(isolate(), jsgraph(), node, builtin_index, arity, flags);
1814 : } else {
1815 : // Patch {node} to a direct call.
1816 280730 : node->InsertInput(graph()->zone(), arity + 2, new_target);
1817 280730 : node->InsertInput(graph()->zone(), arity + 3, argument_count);
1818 : NodeProperties::ChangeOp(node,
1819 : common()->Call(Linkage::GetJSCallDescriptor(
1820 421095 : graph()->zone(), false, 1 + arity, flags)));
1821 : }
1822 : return Changed(node);
1823 : }
1824 :
1825 : // Check if {target} is a JSFunction.
1826 286780 : if (target_type->Is(Type::Function())) {
1827 : // Compute flags for the call.
1828 : CallDescriptor::Flags flags = CallDescriptor::kNeedsFrameState;
1829 : // Patch {node} to an indirect call via the CallFunction builtin.
1830 34139 : Callable callable = CodeFactory::CallFunction(isolate(), convert_mode);
1831 : node->InsertInput(graph()->zone(), 0,
1832 68280 : jsgraph()->HeapConstant(callable.code()));
1833 68276 : node->InsertInput(graph()->zone(), 2, jsgraph()->Constant(arity));
1834 : NodeProperties::ChangeOp(
1835 : node, common()->Call(Linkage::GetStubCallDescriptor(
1836 : isolate(), graph()->zone(), callable.descriptor(), 1 + arity,
1837 136559 : flags)));
1838 : return Changed(node);
1839 : }
1840 :
1841 : // Maybe we did at least learn something about the {receiver}.
1842 252641 : if (p.convert_mode() != convert_mode) {
1843 : NodeProperties::ChangeOp(
1844 929 : node, javascript()->Call(p.arity(), p.frequency(), p.feedback(),
1845 929 : convert_mode));
1846 : return Changed(node);
1847 : }
1848 :
1849 : return NoChange();
1850 : }
1851 :
1852 2186 : Reduction JSTypedLowering::ReduceJSForInNext(Node* node) {
1853 : DCHECK_EQ(IrOpcode::kJSForInNext, node->opcode());
1854 1691 : ForInMode const mode = ForInModeOf(node->op());
1855 1691 : Node* receiver = NodeProperties::GetValueInput(node, 0);
1856 1691 : Node* cache_array = NodeProperties::GetValueInput(node, 1);
1857 1691 : Node* cache_type = NodeProperties::GetValueInput(node, 2);
1858 1691 : Node* index = NodeProperties::GetValueInput(node, 3);
1859 1691 : Node* context = NodeProperties::GetContextInput(node);
1860 1691 : Node* frame_state = NodeProperties::GetFrameStateInput(node);
1861 1691 : Node* effect = NodeProperties::GetEffectInput(node);
1862 1691 : Node* control = NodeProperties::GetControlInput(node);
1863 :
1864 : // Load the map of the {receiver}.
1865 : Node* receiver_map = effect =
1866 : graph()->NewNode(simplified()->LoadField(AccessBuilder::ForMap()),
1867 5073 : receiver, effect, control);
1868 :
1869 1691 : switch (mode) {
1870 : case ForInMode::kUseEnumCacheKeys:
1871 : case ForInMode::kUseEnumCacheKeysAndIndices: {
1872 : // Ensure that the expected map still matches that of the {receiver}.
1873 : Node* check = graph()->NewNode(simplified()->ReferenceEqual(),
1874 1196 : receiver_map, cache_type);
1875 : effect =
1876 : graph()->NewNode(simplified()->CheckIf(DeoptimizeReason::kNoReason),
1877 1196 : check, effect, control);
1878 :
1879 : // Since the change to LoadElement() below is effectful, we connect
1880 : // node to all effect uses.
1881 1745 : ReplaceWithValue(node, node, node, control);
1882 :
1883 : // Morph the {node} into a LoadElement.
1884 1196 : node->ReplaceInput(0, cache_array);
1885 1196 : node->ReplaceInput(1, index);
1886 1196 : node->ReplaceInput(2, effect);
1887 1196 : node->ReplaceInput(3, control);
1888 1196 : node->TrimInputCount(4);
1889 : NodeProperties::ChangeOp(
1890 : node,
1891 2392 : simplified()->LoadElement(AccessBuilder::ForFixedArrayElement()));
1892 : NodeProperties::SetType(node, Type::InternalizedString());
1893 : break;
1894 : }
1895 : case ForInMode::kGeneric: {
1896 : // Load the next {key} from the {cache_array}.
1897 : Node* key = effect = graph()->NewNode(
1898 : simplified()->LoadElement(AccessBuilder::ForFixedArrayElement()),
1899 1485 : cache_array, index, effect, control);
1900 :
1901 : // Check if the expected map still matches that of the {receiver}.
1902 : Node* check = graph()->NewNode(simplified()->ReferenceEqual(),
1903 495 : receiver_map, cache_type);
1904 : Node* branch =
1905 495 : graph()->NewNode(common()->Branch(BranchHint::kTrue), check, control);
1906 :
1907 495 : Node* if_true = graph()->NewNode(common()->IfTrue(), branch);
1908 : Node* etrue;
1909 : Node* vtrue;
1910 : {
1911 : // Don't need filtering since expected map still matches that of the
1912 : // {receiver}.
1913 : etrue = effect;
1914 : vtrue = key;
1915 : }
1916 :
1917 495 : Node* if_false = graph()->NewNode(common()->IfFalse(), branch);
1918 : Node* efalse;
1919 : Node* vfalse;
1920 : {
1921 : // Filter the {key} to check if it's still a valid property of the
1922 : // {receiver} (does the ToName conversion implicitly).
1923 : Callable const callable =
1924 495 : Builtins::CallableFor(isolate(), Builtins::kForInFilter);
1925 : CallDescriptor const* const desc = Linkage::GetStubCallDescriptor(
1926 : isolate(), graph()->zone(), callable.descriptor(), 0,
1927 1485 : CallDescriptor::kNeedsFrameState);
1928 : vfalse = efalse = if_false = graph()->NewNode(
1929 : common()->Call(desc), jsgraph()->HeapConstant(callable.code()), key,
1930 1485 : receiver, context, frame_state, effect, if_false);
1931 :
1932 : // Update potential {IfException} uses of {node} to point to the above
1933 : // ForInFilter stub call node instead.
1934 495 : Node* if_exception = nullptr;
1935 495 : if (NodeProperties::IsExceptionalCall(node, &if_exception)) {
1936 54 : if_false = graph()->NewNode(common()->IfSuccess(), vfalse);
1937 54 : NodeProperties::ReplaceControlInput(if_exception, vfalse);
1938 54 : NodeProperties::ReplaceEffectInput(if_exception, efalse);
1939 54 : Revisit(if_exception);
1940 : }
1941 : }
1942 :
1943 495 : control = graph()->NewNode(common()->Merge(2), if_true, if_false);
1944 495 : effect = graph()->NewNode(common()->EffectPhi(2), etrue, efalse, control);
1945 : ReplaceWithValue(node, node, effect, control);
1946 :
1947 : // Morph the {node} into a Phi.
1948 495 : node->ReplaceInput(0, vtrue);
1949 495 : node->ReplaceInput(1, vfalse);
1950 495 : node->ReplaceInput(2, control);
1951 495 : node->TrimInputCount(3);
1952 : NodeProperties::ChangeOp(
1953 495 : node, common()->Phi(MachineRepresentation::kTagged, 2));
1954 : }
1955 : }
1956 :
1957 1691 : return Changed(node);
1958 : }
1959 :
1960 3014 : Reduction JSTypedLowering::ReduceJSForInPrepare(Node* node) {
1961 : DCHECK_EQ(IrOpcode::kJSForInPrepare, node->opcode());
1962 1507 : ForInMode const mode = ForInModeOf(node->op());
1963 1507 : Node* enumerator = NodeProperties::GetValueInput(node, 0);
1964 1507 : Node* effect = NodeProperties::GetEffectInput(node);
1965 1507 : Node* control = NodeProperties::GetControlInput(node);
1966 : Node* cache_type = enumerator;
1967 : Node* cache_array = nullptr;
1968 : Node* cache_length = nullptr;
1969 :
1970 1507 : switch (mode) {
1971 : case ForInMode::kUseEnumCacheKeys:
1972 : case ForInMode::kUseEnumCacheKeysAndIndices: {
1973 : // Check that the {enumerator} is a Map.
1974 : effect = graph()->NewNode(
1975 : simplified()->CheckMaps(CheckMapsFlag::kNone,
1976 : ZoneHandleSet<Map>(factory()->meta_map())),
1977 2336 : enumerator, effect, control);
1978 :
1979 : // Load the enum cache from the {enumerator} map.
1980 : Node* descriptor_array = effect = graph()->NewNode(
1981 : simplified()->LoadField(AccessBuilder::ForMapDescriptors()),
1982 3504 : enumerator, effect, control);
1983 : Node* enum_cache = effect = graph()->NewNode(
1984 : simplified()->LoadField(AccessBuilder::ForDescriptorArrayEnumCache()),
1985 3504 : descriptor_array, effect, control);
1986 : cache_array = effect = graph()->NewNode(
1987 : simplified()->LoadField(AccessBuilder::ForEnumCacheKeys()),
1988 3504 : enum_cache, effect, control);
1989 :
1990 : // Load the enum length of the {enumerator} map.
1991 : Node* bit_field3 = effect = graph()->NewNode(
1992 : simplified()->LoadField(AccessBuilder::ForMapBitField3()), enumerator,
1993 3504 : effect, control);
1994 : STATIC_ASSERT(Map::EnumLengthBits::kShift == 0);
1995 : cache_length =
1996 : graph()->NewNode(simplified()->NumberBitwiseAnd(), bit_field3,
1997 2336 : jsgraph()->Constant(Map::EnumLengthBits::kMask));
1998 1168 : break;
1999 : }
2000 : case ForInMode::kGeneric: {
2001 : // Check if the {enumerator} is a Map or a FixedArray.
2002 : Node* check = effect = graph()->NewNode(
2003 : simplified()->CompareMaps(ZoneHandleSet<Map>(factory()->meta_map())),
2004 678 : enumerator, effect, control);
2005 : Node* branch =
2006 339 : graph()->NewNode(common()->Branch(BranchHint::kTrue), check, control);
2007 :
2008 339 : Node* if_true = graph()->NewNode(common()->IfTrue(), branch);
2009 : Node* etrue = effect;
2010 : Node* cache_array_true;
2011 : Node* cache_length_true;
2012 : {
2013 : // Load the enum cache from the {enumerator} map.
2014 : Node* descriptor_array = etrue = graph()->NewNode(
2015 : simplified()->LoadField(AccessBuilder::ForMapDescriptors()),
2016 1017 : enumerator, etrue, if_true);
2017 : Node* enum_cache = etrue =
2018 : graph()->NewNode(simplified()->LoadField(
2019 : AccessBuilder::ForDescriptorArrayEnumCache()),
2020 1017 : descriptor_array, etrue, if_true);
2021 : cache_array_true = etrue = graph()->NewNode(
2022 : simplified()->LoadField(AccessBuilder::ForEnumCacheKeys()),
2023 1017 : enum_cache, etrue, if_true);
2024 :
2025 : // Load the enum length of the {enumerator} map.
2026 : Node* bit_field3 = etrue = graph()->NewNode(
2027 : simplified()->LoadField(AccessBuilder::ForMapBitField3()),
2028 1017 : enumerator, etrue, if_true);
2029 : STATIC_ASSERT(Map::EnumLengthBits::kShift == 0);
2030 : cache_length_true =
2031 : graph()->NewNode(simplified()->NumberBitwiseAnd(), bit_field3,
2032 678 : jsgraph()->Constant(Map::EnumLengthBits::kMask));
2033 : }
2034 :
2035 339 : Node* if_false = graph()->NewNode(common()->IfFalse(), branch);
2036 : Node* efalse = effect;
2037 : Node* cache_array_false;
2038 : Node* cache_length_false;
2039 : {
2040 : // The {enumerator} is the FixedArray with the keys to iterate.
2041 : cache_array_false = enumerator;
2042 : cache_length_false = efalse = graph()->NewNode(
2043 : simplified()->LoadField(AccessBuilder::ForFixedArrayLength()),
2044 1017 : cache_array_false, efalse, if_false);
2045 : }
2046 :
2047 : // Rewrite the uses of the {node}.
2048 339 : control = graph()->NewNode(common()->Merge(2), if_true, if_false);
2049 339 : effect = graph()->NewNode(common()->EffectPhi(2), etrue, efalse, control);
2050 : cache_array =
2051 : graph()->NewNode(common()->Phi(MachineRepresentation::kTagged, 2),
2052 339 : cache_array_true, cache_array_false, control);
2053 : cache_length =
2054 : graph()->NewNode(common()->Phi(MachineRepresentation::kTagged, 2),
2055 339 : cache_length_true, cache_length_false, control);
2056 339 : break;
2057 : }
2058 : }
2059 :
2060 : // Update the uses of {node}.
2061 25619 : for (Edge edge : node->use_edges()) {
2062 4521 : Node* const user = edge.from();
2063 12056 : if (NodeProperties::IsEffectEdge(edge)) {
2064 1507 : edge.UpdateTo(effect);
2065 12056 : Revisit(user);
2066 10549 : } else if (NodeProperties::IsControlEdge(edge)) {
2067 6028 : edge.UpdateTo(control);
2068 : Revisit(user);
2069 : } else {
2070 : DCHECK(NodeProperties::IsValueEdge(edge));
2071 4521 : switch (ProjectionIndexOf(user->op())) {
2072 : case 0:
2073 : Replace(user, cache_type);
2074 : break;
2075 : case 1:
2076 : Replace(user, cache_array);
2077 : break;
2078 : case 2:
2079 : Replace(user, cache_length);
2080 : break;
2081 : default:
2082 0 : UNREACHABLE();
2083 : }
2084 : }
2085 : }
2086 1507 : node->Kill();
2087 1507 : return Replace(effect);
2088 : }
2089 :
2090 52586 : Reduction JSTypedLowering::ReduceJSLoadMessage(Node* node) {
2091 : DCHECK_EQ(IrOpcode::kJSLoadMessage, node->opcode());
2092 : ExternalReference const ref =
2093 26293 : ExternalReference::address_of_pending_message_obj(isolate());
2094 26293 : node->ReplaceInput(0, jsgraph()->ExternalConstant(ref));
2095 : NodeProperties::ChangeOp(
2096 52586 : node, simplified()->LoadField(AccessBuilder::ForExternalTaggedValue()));
2097 26293 : return Changed(node);
2098 : }
2099 :
2100 52586 : Reduction JSTypedLowering::ReduceJSStoreMessage(Node* node) {
2101 : DCHECK_EQ(IrOpcode::kJSStoreMessage, node->opcode());
2102 : ExternalReference const ref =
2103 26293 : ExternalReference::address_of_pending_message_obj(isolate());
2104 26293 : Node* value = NodeProperties::GetValueInput(node, 0);
2105 26293 : node->ReplaceInput(0, jsgraph()->ExternalConstant(ref));
2106 26293 : node->ReplaceInput(1, value);
2107 : NodeProperties::ChangeOp(
2108 52586 : node, simplified()->StoreField(AccessBuilder::ForExternalTaggedValue()));
2109 26293 : return Changed(node);
2110 : }
2111 :
2112 4946 : Reduction JSTypedLowering::ReduceJSGeneratorStore(Node* node) {
2113 : DCHECK_EQ(IrOpcode::kJSGeneratorStore, node->opcode());
2114 4946 : Node* generator = NodeProperties::GetValueInput(node, 0);
2115 4946 : Node* continuation = NodeProperties::GetValueInput(node, 1);
2116 4946 : Node* offset = NodeProperties::GetValueInput(node, 2);
2117 4946 : Node* context = NodeProperties::GetContextInput(node);
2118 4946 : Node* effect = NodeProperties::GetEffectInput(node);
2119 4946 : Node* control = NodeProperties::GetControlInput(node);
2120 4946 : int register_count = OpParameter<int>(node);
2121 :
2122 4946 : FieldAccess array_field = AccessBuilder::ForJSGeneratorObjectRegisterFile();
2123 4946 : FieldAccess context_field = AccessBuilder::ForJSGeneratorObjectContext();
2124 : FieldAccess continuation_field =
2125 4946 : AccessBuilder::ForJSGeneratorObjectContinuation();
2126 : FieldAccess input_or_debug_pos_field =
2127 4946 : AccessBuilder::ForJSGeneratorObjectInputOrDebugPos();
2128 :
2129 : Node* array = effect = graph()->NewNode(simplified()->LoadField(array_field),
2130 4946 : generator, effect, control);
2131 :
2132 40163 : for (int i = 0; i < register_count; ++i) {
2133 35217 : Node* value = NodeProperties::GetValueInput(node, 3 + i);
2134 : effect = graph()->NewNode(
2135 35217 : simplified()->StoreField(AccessBuilder::ForFixedArraySlot(i)), array,
2136 105651 : value, effect, control);
2137 : }
2138 :
2139 : effect = graph()->NewNode(simplified()->StoreField(context_field), generator,
2140 4946 : context, effect, control);
2141 : effect = graph()->NewNode(simplified()->StoreField(continuation_field),
2142 4946 : generator, continuation, effect, control);
2143 : effect = graph()->NewNode(simplified()->StoreField(input_or_debug_pos_field),
2144 4946 : generator, offset, effect, control);
2145 :
2146 4946 : ReplaceWithValue(node, effect, effect, control);
2147 4946 : return Changed(effect);
2148 : }
2149 :
2150 3046 : Reduction JSTypedLowering::ReduceJSGeneratorRestoreContinuation(Node* node) {
2151 : DCHECK_EQ(IrOpcode::kJSGeneratorRestoreContinuation, node->opcode());
2152 1523 : Node* generator = NodeProperties::GetValueInput(node, 0);
2153 1523 : Node* effect = NodeProperties::GetEffectInput(node);
2154 1523 : Node* control = NodeProperties::GetControlInput(node);
2155 :
2156 : FieldAccess continuation_field =
2157 1523 : AccessBuilder::ForJSGeneratorObjectContinuation();
2158 :
2159 : Node* continuation = effect = graph()->NewNode(
2160 1523 : simplified()->LoadField(continuation_field), generator, effect, control);
2161 1523 : Node* executing = jsgraph()->Constant(JSGeneratorObject::kGeneratorExecuting);
2162 : effect = graph()->NewNode(simplified()->StoreField(continuation_field),
2163 1523 : generator, executing, effect, control);
2164 :
2165 1523 : ReplaceWithValue(node, continuation, effect, control);
2166 1523 : return Changed(continuation);
2167 : }
2168 :
2169 71530 : Reduction JSTypedLowering::ReduceJSGeneratorRestoreRegister(Node* node) {
2170 : DCHECK_EQ(IrOpcode::kJSGeneratorRestoreRegister, node->opcode());
2171 35765 : Node* generator = NodeProperties::GetValueInput(node, 0);
2172 35765 : Node* effect = NodeProperties::GetEffectInput(node);
2173 35765 : Node* control = NodeProperties::GetControlInput(node);
2174 35765 : int index = OpParameter<int>(node);
2175 :
2176 35765 : FieldAccess array_field = AccessBuilder::ForJSGeneratorObjectRegisterFile();
2177 35765 : FieldAccess element_field = AccessBuilder::ForFixedArraySlot(index);
2178 :
2179 : Node* array = effect = graph()->NewNode(simplified()->LoadField(array_field),
2180 35765 : generator, effect, control);
2181 : Node* element = effect = graph()->NewNode(
2182 35765 : simplified()->LoadField(element_field), array, effect, control);
2183 35765 : Node* stale = jsgraph()->StaleRegisterConstant();
2184 : effect = graph()->NewNode(simplified()->StoreField(element_field), array,
2185 35765 : stale, effect, control);
2186 :
2187 35765 : ReplaceWithValue(node, element, effect, control);
2188 35765 : return Changed(element);
2189 : }
2190 :
2191 30003479 : Reduction JSTypedLowering::Reduce(Node* node) {
2192 30003479 : switch (node->opcode()) {
2193 : case IrOpcode::kJSEqual:
2194 13709 : return ReduceJSEqual(node);
2195 : case IrOpcode::kJSStrictEqual:
2196 153372 : return ReduceJSStrictEqual(node);
2197 : case IrOpcode::kJSLessThan: // fall through
2198 : case IrOpcode::kJSGreaterThan: // fall through
2199 : case IrOpcode::kJSLessThanOrEqual: // fall through
2200 : case IrOpcode::kJSGreaterThanOrEqual:
2201 37351 : return ReduceJSComparison(node);
2202 : case IrOpcode::kJSBitwiseOr:
2203 : case IrOpcode::kJSBitwiseXor:
2204 : case IrOpcode::kJSBitwiseAnd:
2205 23797 : return ReduceInt32Binop(node);
2206 : case IrOpcode::kJSShiftLeft:
2207 : case IrOpcode::kJSShiftRight:
2208 8257 : return ReduceUI32Shift(node, kSigned);
2209 : case IrOpcode::kJSShiftRightLogical:
2210 4119 : return ReduceUI32Shift(node, kUnsigned);
2211 : case IrOpcode::kJSAdd:
2212 90137 : return ReduceJSAdd(node);
2213 : case IrOpcode::kJSSubtract:
2214 : case IrOpcode::kJSMultiply:
2215 : case IrOpcode::kJSDivide:
2216 : case IrOpcode::kJSModulus:
2217 56427 : return ReduceNumberBinop(node);
2218 : case IrOpcode::kJSHasInPrototypeChain:
2219 1288 : return ReduceJSHasInPrototypeChain(node);
2220 : case IrOpcode::kJSOrdinaryHasInstance:
2221 75 : return ReduceJSOrdinaryHasInstance(node);
2222 : case IrOpcode::kJSToInteger:
2223 175 : return ReduceJSToInteger(node);
2224 : case IrOpcode::kJSToLength:
2225 867 : return ReduceJSToLength(node);
2226 : case IrOpcode::kJSToName:
2227 1086 : return ReduceJSToName(node);
2228 : case IrOpcode::kJSToNumber:
2229 11549 : return ReduceJSToNumber(node);
2230 : case IrOpcode::kJSToString:
2231 2866 : return ReduceJSToString(node);
2232 : case IrOpcode::kJSToObject:
2233 3096 : return ReduceJSToObject(node);
2234 : case IrOpcode::kJSLoadNamed:
2235 465663 : return ReduceJSLoadNamed(node);
2236 : case IrOpcode::kJSLoadContext:
2237 687400 : return ReduceJSLoadContext(node);
2238 : case IrOpcode::kJSStoreContext:
2239 345503 : return ReduceJSStoreContext(node);
2240 : case IrOpcode::kJSLoadModule:
2241 280 : return ReduceJSLoadModule(node);
2242 : case IrOpcode::kJSStoreModule:
2243 6883 : return ReduceJSStoreModule(node);
2244 : case IrOpcode::kJSConvertReceiver:
2245 128052 : return ReduceJSConvertReceiver(node);
2246 : case IrOpcode::kJSConstructForwardVarargs:
2247 453 : return ReduceJSConstructForwardVarargs(node);
2248 : case IrOpcode::kJSConstruct:
2249 28064 : return ReduceJSConstruct(node);
2250 : case IrOpcode::kJSCallForwardVarargs:
2251 384 : return ReduceJSCallForwardVarargs(node);
2252 : case IrOpcode::kJSCall:
2253 480810 : return ReduceJSCall(node);
2254 : case IrOpcode::kJSForInPrepare:
2255 1507 : return ReduceJSForInPrepare(node);
2256 : case IrOpcode::kJSForInNext:
2257 1691 : return ReduceJSForInNext(node);
2258 : case IrOpcode::kJSLoadMessage:
2259 26293 : return ReduceJSLoadMessage(node);
2260 : case IrOpcode::kJSStoreMessage:
2261 26293 : return ReduceJSStoreMessage(node);
2262 : case IrOpcode::kJSGeneratorStore:
2263 4946 : return ReduceJSGeneratorStore(node);
2264 : case IrOpcode::kJSGeneratorRestoreContinuation:
2265 1523 : return ReduceJSGeneratorRestoreContinuation(node);
2266 : case IrOpcode::kJSGeneratorRestoreRegister:
2267 35765 : return ReduceJSGeneratorRestoreRegister(node);
2268 : // TODO(mstarzinger): Simplified operations hiding in JS-level reducer not
2269 : // fooling anyone. Consider moving this into a separate reducer.
2270 : case IrOpcode::kSpeculativeNumberAdd:
2271 52554 : return ReduceSpeculativeNumberAdd(node);
2272 : case IrOpcode::kSpeculativeNumberSubtract:
2273 : case IrOpcode::kSpeculativeNumberMultiply:
2274 : case IrOpcode::kSpeculativeNumberDivide:
2275 : case IrOpcode::kSpeculativeNumberModulus:
2276 42274 : return ReduceSpeculativeNumberBinop(node);
2277 : case IrOpcode::kSpeculativeNumberEqual:
2278 : case IrOpcode::kSpeculativeNumberLessThan:
2279 : case IrOpcode::kSpeculativeNumberLessThanOrEqual:
2280 67587 : return ReduceSpeculativeNumberComparison(node);
2281 : default:
2282 : break;
2283 : }
2284 : return NoChange();
2285 : }
2286 :
2287 :
2288 473209 : Factory* JSTypedLowering::factory() const { return jsgraph()->factory(); }
2289 :
2290 :
2291 3917885 : Graph* JSTypedLowering::graph() const { return jsgraph()->graph(); }
2292 :
2293 :
2294 634354 : Isolate* JSTypedLowering::isolate() const { return jsgraph()->isolate(); }
2295 :
2296 :
2297 240209 : JSOperatorBuilder* JSTypedLowering::javascript() const {
2298 240209 : return jsgraph()->javascript();
2299 : }
2300 :
2301 :
2302 341205 : CommonOperatorBuilder* JSTypedLowering::common() const {
2303 341205 : return jsgraph()->common();
2304 : }
2305 :
2306 1814812 : SimplifiedOperatorBuilder* JSTypedLowering::simplified() const {
2307 1816319 : return jsgraph()->simplified();
2308 : }
2309 :
2310 : } // namespace compiler
2311 : } // namespace internal
2312 : } // namespace v8
|