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/compilation-dependencies.h"
11 : #include "src/compiler/access-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 864134 : : lowering_(lowering), node_(node) {}
33 :
34 150734 : bool GetCompareNumberOperationHint(NumberOperationHint* hint) {
35 301468 : if (lowering_->flags() & JSTypedLowering::kDeoptimizationEnabled) {
36 : DCHECK_EQ(1, node_->op()->EffectOutputCount());
37 150734 : switch (CompareOperationHintOf(node_->op())) {
38 : case CompareOperationHint::kSignedSmall:
39 8960 : *hint = NumberOperationHint::kSignedSmall;
40 8960 : return true;
41 : case CompareOperationHint::kNumber:
42 7101 : *hint = NumberOperationHint::kNumber;
43 7101 : return true;
44 : case CompareOperationHint::kNumberOrOddball:
45 0 : *hint = NumberOperationHint::kNumberOrOddball;
46 0 : return true;
47 : case CompareOperationHint::kAny:
48 : case CompareOperationHint::kNone:
49 : case CompareOperationHint::kString:
50 : case CompareOperationHint::kReceiver:
51 : case CompareOperationHint::kInternalizedString:
52 : break;
53 : }
54 : }
55 : return false;
56 : }
57 :
58 232785 : bool IsInternalizedStringCompareOperation() {
59 465570 : if (lowering_->flags() & JSTypedLowering::kDeoptimizationEnabled) {
60 : DCHECK_EQ(1, node_->op()->EffectOutputCount());
61 230321 : return (CompareOperationHintOf(node_->op()) ==
62 234577 : CompareOperationHint::kInternalizedString) &&
63 234577 : BothInputsMaybe(Type::InternalizedString());
64 : }
65 : return false;
66 : }
67 :
68 135953 : bool IsReceiverCompareOperation() {
69 271906 : if (lowering_->flags() & JSTypedLowering::kDeoptimizationEnabled) {
70 : DCHECK_EQ(1, node_->op()->EffectOutputCount());
71 135938 : return (CompareOperationHintOf(node_->op()) ==
72 136325 : CompareOperationHint::kReceiver) &&
73 136325 : BothInputsMaybe(Type::Receiver());
74 : }
75 : return false;
76 : }
77 :
78 157869 : bool IsStringCompareOperation() {
79 315738 : if (lowering_->flags() & JSTypedLowering::kDeoptimizationEnabled) {
80 : DCHECK_EQ(1, node_->op()->EffectOutputCount());
81 157839 : return (CompareOperationHintOf(node_->op()) ==
82 158401 : CompareOperationHint::kString) &&
83 158401 : BothInputsMaybe(Type::String());
84 : }
85 : return false;
86 : }
87 :
88 : // Check if a string addition will definitely result in creating a ConsString,
89 : // i.e. if the combined length of the resulting string exceeds the ConsString
90 : // minimum length.
91 74259 : bool ShouldCreateConsString() {
92 : DCHECK_EQ(IrOpcode::kJSAdd, node_->opcode());
93 : DCHECK(OneInputIs(Type::String()));
94 194013 : if (BothInputsAre(Type::String()) ||
95 90990 : ((lowering_->flags() & JSTypedLowering::kDeoptimizationEnabled) &&
96 45495 : BinaryOperationHintOf(node_->op()) == BinaryOperationHint::kString)) {
97 31773 : HeapObjectBinopMatcher m(node_);
98 56497 : if (m.right().HasValue() && m.right().Value()->IsString()) {
99 : Handle<String> right_string = Handle<String>::cast(m.right().Value());
100 24724 : if (right_string->length() >= ConsString::kMinLength) return true;
101 : }
102 30282 : if (m.left().HasValue() && m.left().Value()->IsString()) {
103 : Handle<String> left_string = Handle<String>::cast(m.left().Value());
104 1601 : if (left_string->length() >= ConsString::kMinLength) {
105 : // The invariant for ConsString requires the left hand side to be
106 : // a sequential or external string if the right hand side is the
107 : // empty string. Since we don't know anything about the right hand
108 : // side here, we must ensure that the left hand side satisfy the
109 : // constraints independent of the right hand side.
110 353 : return left_string->IsSeqString() || left_string->IsExternalString();
111 : }
112 : }
113 : }
114 : return false;
115 : }
116 :
117 : // Inserts a CheckReceiver for the left input.
118 1662 : void CheckLeftInputToReceiver() {
119 : Node* left_input = graph()->NewNode(simplified()->CheckReceiver(), left(),
120 277 : effect(), control());
121 277 : node_->ReplaceInput(0, left_input);
122 : update_effect(left_input);
123 277 : }
124 :
125 : // Checks that both inputs are Receiver, and if we don't know
126 : // statically that one side is already a Receiver, insert a
127 : // CheckReceiver node.
128 1584 : void CheckInputsToReceiver() {
129 204 : if (!left_type()->Is(Type::Receiver())) {
130 94 : CheckLeftInputToReceiver();
131 : }
132 204 : if (!right_type()->Is(Type::Receiver())) {
133 : Node* right_input = graph()->NewNode(simplified()->CheckReceiver(),
134 196 : right(), effect(), control());
135 196 : node_->ReplaceInput(1, right_input);
136 : update_effect(right_input);
137 : }
138 204 : }
139 :
140 : // Checks that both inputs are String, and if we don't know
141 : // statically that one side is already a String, insert a
142 : // CheckString node.
143 4868 : void CheckInputsToString() {
144 562 : if (!left_type()->Is(Type::String())) {
145 : Node* left_input = graph()->NewNode(simplified()->CheckString(), left(),
146 562 : effect(), control());
147 562 : node_->ReplaceInput(0, left_input);
148 : update_effect(left_input);
149 : }
150 562 : if (!right_type()->Is(Type::String())) {
151 : Node* right_input = graph()->NewNode(simplified()->CheckString(), right(),
152 62 : effect(), control());
153 62 : node_->ReplaceInput(1, right_input);
154 : update_effect(right_input);
155 : }
156 562 : }
157 :
158 : // Checks that both inputs are InternalizedString, and if we don't know
159 : // statically that one side is already an InternalizedString, insert a
160 : // CheckInternalizedString node.
161 34900 : void CheckInputsToInternalizedString() {
162 4256 : if (!left_type()->Is(Type::UniqueName())) {
163 : Node* left_input = graph()->NewNode(
164 4256 : simplified()->CheckInternalizedString(), left(), effect(), control());
165 4256 : node_->ReplaceInput(0, left_input);
166 : update_effect(left_input);
167 : }
168 4256 : if (!right_type()->Is(Type::UniqueName())) {
169 : Node* right_input =
170 : graph()->NewNode(simplified()->CheckInternalizedString(), right(),
171 142 : effect(), control());
172 142 : node_->ReplaceInput(1, right_input);
173 : update_effect(right_input);
174 : }
175 4256 : }
176 :
177 1091903 : void ConvertInputsToNumber() {
178 : // To convert the inputs to numbers, we have to provide frame states
179 : // for lazy bailouts in the ToNumber conversions.
180 : // We use a little hack here: we take the frame state before the binary
181 : // operation and use it to construct the frame states for the conversion
182 : // so that after the deoptimization, the binary operation IC gets
183 : // already converted values from full code. This way we are sure that we
184 : // will not re-do any of the side effects.
185 :
186 217842 : Node* left_input = nullptr;
187 217842 : Node* right_input = nullptr;
188 : bool left_is_primitive = left_type()->Is(Type::PlainPrimitive());
189 : bool right_is_primitive = right_type()->Is(Type::PlainPrimitive());
190 217842 : bool handles_exception = NodeProperties::IsExceptionalCall(node_);
191 :
192 217842 : if (!left_is_primitive && !right_is_primitive && handles_exception) {
193 0 : ConvertBothInputsToNumber(&left_input, &right_input);
194 : } else {
195 : left_input = left_is_primitive
196 : ? ConvertPlainPrimitiveToNumber(left())
197 : : ConvertSingleInputToNumber(
198 435684 : left(), CreateFrameStateForLeftInput());
199 : right_input =
200 : right_is_primitive
201 : ? ConvertPlainPrimitiveToNumber(right())
202 : : ConvertSingleInputToNumber(
203 435684 : right(), CreateFrameStateForRightInput(left_input));
204 : }
205 :
206 217842 : node_->ReplaceInput(0, left_input);
207 217842 : node_->ReplaceInput(1, right_input);
208 217842 : }
209 :
210 69195 : void ConvertInputsToUI32(Signedness left_signedness,
211 138390 : Signedness right_signedness) {
212 69195 : node_->ReplaceInput(0, ConvertToUI32(left(), left_signedness));
213 69195 : node_->ReplaceInput(1, ConvertToUI32(right(), right_signedness));
214 69195 : }
215 :
216 11680 : void SwapInputs() {
217 : Node* l = left();
218 : Node* r = right();
219 5840 : node_->ReplaceInput(0, r);
220 5840 : node_->ReplaceInput(1, l);
221 5840 : }
222 :
223 : // Remove all effect and control inputs and outputs to this node and change
224 : // to the pure operator {op}.
225 333773 : Reduction ChangeToPureOperator(const Operator* op, Type* type = Type::Any()) {
226 : DCHECK_EQ(0, op->EffectInputCount());
227 : DCHECK_EQ(false, OperatorProperties::HasContextInput(op));
228 : DCHECK_EQ(0, op->ControlInputCount());
229 : DCHECK_EQ(2, op->ValueInputCount());
230 :
231 : // Remove the effects from the node, and update its effect/control usages.
232 667546 : if (node_->op()->EffectInputCount() > 0) {
233 333773 : lowering_->RelaxEffectsAndControls(node_);
234 : }
235 : // Remove the inputs corresponding to context, effect, and control.
236 333773 : NodeProperties::RemoveNonValueInputs(node_);
237 : // Finally, update the operator to the new one.
238 333773 : NodeProperties::ChangeOp(node_, op);
239 :
240 : // TODO(jarin): Replace the explicit typing hack with a call to some method
241 : // that encapsulates changing the operator and re-typing.
242 333773 : Type* node_type = NodeProperties::GetType(node_);
243 333773 : NodeProperties::SetType(node_, Type::Intersect(node_type, type, zone()));
244 :
245 333773 : return lowering_->Changed(node_);
246 : }
247 :
248 16061 : Reduction ChangeToSpeculativeOperator(const Operator* op, Type* upper_bound) {
249 : DCHECK_EQ(1, op->EffectInputCount());
250 : DCHECK_EQ(1, op->EffectOutputCount());
251 : DCHECK_EQ(false, OperatorProperties::HasContextInput(op));
252 : DCHECK_EQ(1, op->ControlInputCount());
253 : DCHECK_EQ(0, op->ControlOutputCount());
254 : DCHECK_EQ(0, OperatorProperties::GetFrameStateInputCount(op));
255 : DCHECK_EQ(2, op->ValueInputCount());
256 :
257 : DCHECK_EQ(1, node_->op()->EffectInputCount());
258 : DCHECK_EQ(1, node_->op()->EffectOutputCount());
259 : DCHECK_EQ(1, node_->op()->ControlInputCount());
260 : DCHECK_EQ(2, node_->op()->ValueInputCount());
261 :
262 : // Reconnect the control output to bypass the IfSuccess node and
263 : // possibly disconnect from the IfException node.
264 32122 : lowering_->RelaxControls(node_);
265 :
266 : // Remove the frame state and the context.
267 32122 : if (OperatorProperties::HasFrameStateInput(node_->op())) {
268 0 : node_->RemoveInput(NodeProperties::FirstFrameStateIndex(node_));
269 : }
270 32122 : node_->RemoveInput(NodeProperties::FirstContextIndex(node_));
271 :
272 16061 : NodeProperties::ChangeOp(node_, op);
273 :
274 : // Update the type to number.
275 16061 : Type* node_type = NodeProperties::GetType(node_);
276 : NodeProperties::SetType(node_,
277 16061 : Type::Intersect(node_type, upper_bound, zone()));
278 :
279 16061 : return lowering_->Changed(node_);
280 : }
281 :
282 230698 : const Operator* NumberOp() {
283 230698 : switch (node_->opcode()) {
284 : case IrOpcode::kJSAdd:
285 0 : return simplified()->NumberAdd();
286 : case IrOpcode::kJSSubtract:
287 22714 : return simplified()->NumberSubtract();
288 : case IrOpcode::kJSMultiply:
289 11806 : return simplified()->NumberMultiply();
290 : case IrOpcode::kJSDivide:
291 8164 : return simplified()->NumberDivide();
292 : case IrOpcode::kJSModulus:
293 3470 : return simplified()->NumberModulus();
294 : case IrOpcode::kJSBitwiseAnd:
295 6055 : return simplified()->NumberBitwiseAnd();
296 : case IrOpcode::kJSBitwiseOr:
297 28044 : return simplified()->NumberBitwiseOr();
298 : case IrOpcode::kJSBitwiseXor:
299 6393 : return simplified()->NumberBitwiseXor();
300 : case IrOpcode::kJSShiftLeft:
301 6543 : return simplified()->NumberShiftLeft();
302 : case IrOpcode::kJSShiftRight:
303 13643 : return simplified()->NumberShiftRight();
304 : case IrOpcode::kJSShiftRightLogical:
305 8517 : return simplified()->NumberShiftRightLogical();
306 : default:
307 : break;
308 : }
309 0 : UNREACHABLE();
310 : return nullptr;
311 : }
312 :
313 55730 : const Operator* NumberOpFromSpeculativeNumberOp() {
314 55730 : switch (node_->opcode()) {
315 : case IrOpcode::kSpeculativeNumberEqual:
316 1511 : return simplified()->NumberEqual();
317 : case IrOpcode::kSpeculativeNumberLessThan:
318 7066 : return simplified()->NumberLessThan();
319 : case IrOpcode::kSpeculativeNumberLessThanOrEqual:
320 288 : return simplified()->NumberLessThanOrEqual();
321 : case IrOpcode::kSpeculativeNumberAdd:
322 0 : return simplified()->NumberAdd();
323 : case IrOpcode::kSpeculativeNumberSubtract:
324 1114 : return simplified()->NumberSubtract();
325 : case IrOpcode::kSpeculativeNumberMultiply:
326 8617 : return simplified()->NumberMultiply();
327 : case IrOpcode::kSpeculativeNumberDivide:
328 8884 : return simplified()->NumberDivide();
329 : case IrOpcode::kSpeculativeNumberModulus:
330 385 : return simplified()->NumberModulus();
331 : default:
332 : break;
333 : }
334 0 : UNREACHABLE();
335 : return nullptr;
336 : }
337 :
338 4456640 : bool LeftInputIs(Type* t) { return left_type()->Is(t); }
339 :
340 1762474 : bool RightInputIs(Type* t) { return right_type()->Is(t); }
341 :
342 331006 : bool OneInputIs(Type* t) { return LeftInputIs(t) || RightInputIs(t); }
343 :
344 1826375 : bool BothInputsAre(Type* t) { return LeftInputIs(t) && RightInputIs(t); }
345 :
346 10410 : bool BothInputsMaybe(Type* t) {
347 10410 : return left_type()->Maybe(t) && right_type()->Maybe(t);
348 : }
349 :
350 509563 : bool OneInputCannotBe(Type* t) {
351 509563 : return !left_type()->Maybe(t) || !right_type()->Maybe(t);
352 : }
353 :
354 267609 : bool NeitherInputCanBe(Type* t) {
355 267609 : return !left_type()->Maybe(t) && !right_type()->Maybe(t);
356 : }
357 :
358 8188 : Node* effect() { return NodeProperties::GetEffectInput(node_); }
359 8188 : Node* control() { return NodeProperties::GetControlInput(node_); }
360 2693 : Node* context() { return NodeProperties::GetContextInput(node_); }
361 547736 : Node* left() { return NodeProperties::GetValueInput(node_, 0); }
362 534608 : Node* right() { return NodeProperties::GetValueInput(node_, 1); }
363 : Type* left_type() { return NodeProperties::GetType(node_->InputAt(0)); }
364 : Type* right_type() { return NodeProperties::GetType(node_->InputAt(1)); }
365 : Type* type() { return NodeProperties::GetType(node_); }
366 :
367 : SimplifiedOperatorBuilder* simplified() { return lowering_->simplified(); }
368 : Graph* graph() const { return lowering_->graph(); }
369 0 : JSGraph* jsgraph() { return lowering_->jsgraph(); }
370 : JSOperatorBuilder* javascript() { return lowering_->javascript(); }
371 0 : CommonOperatorBuilder* common() { return jsgraph()->common(); }
372 699668 : Zone* zone() const { return graph()->zone(); }
373 :
374 : private:
375 : JSTypedLowering* lowering_; // The containing lowering instance.
376 : Node* node_; // The original node.
377 :
378 : Node* CreateFrameStateForLeftInput() {
379 : // Deoptimization is disabled => return dummy frame state instead.
380 2558 : Node* dummy_state = NodeProperties::GetFrameStateInput(node_);
381 : DCHECK(OpParameter<FrameStateInfo>(dummy_state).bailout_id().IsNone());
382 : return dummy_state;
383 : }
384 :
385 : Node* CreateFrameStateForRightInput(Node* converted_left) {
386 : // Deoptimization is disabled => return dummy frame state instead.
387 135 : Node* dummy_state = NodeProperties::GetFrameStateInput(node_);
388 : DCHECK(OpParameter<FrameStateInfo>(dummy_state).bailout_id().IsNone());
389 : return dummy_state;
390 : }
391 :
392 465493 : Node* ConvertPlainPrimitiveToNumber(Node* node) {
393 : DCHECK(NodeProperties::GetType(node)->Is(Type::PlainPrimitive()));
394 : // Avoid inserting too many eager ToNumber() operations.
395 432991 : Reduction const reduction = lowering_->ReduceJSToNumberInput(node);
396 432991 : if (reduction.Changed()) return reduction.replacement();
397 16251 : if (NodeProperties::GetType(node)->Is(Type::Number())) {
398 : return node;
399 : }
400 32502 : return graph()->NewNode(simplified()->PlainPrimitiveToNumber(), node);
401 : }
402 :
403 16158 : Node* ConvertSingleInputToNumber(Node* node, Node* frame_state) {
404 : DCHECK(!NodeProperties::GetType(node)->Is(Type::PlainPrimitive()));
405 : Node* const n = graph()->NewNode(javascript()->ToNumber(), node, context(),
406 2693 : frame_state, effect(), control());
407 2693 : NodeProperties::ReplaceControlInput(node_, n);
408 : update_effect(n);
409 2693 : return n;
410 : }
411 :
412 0 : void ConvertBothInputsToNumber(Node** left_result, Node** right_result) {
413 : Node* projections[2];
414 :
415 : // Find {IfSuccess} and {IfException} continuations of the operation.
416 0 : NodeProperties::CollectControlProjections(node_, projections, 2);
417 0 : Node* if_exception = projections[1];
418 0 : Node* if_success = projections[0];
419 :
420 : // Insert two ToNumber() operations that both potentially throw.
421 : Node* left_state = CreateFrameStateForLeftInput();
422 : Node* left_conv =
423 : graph()->NewNode(javascript()->ToNumber(), left(), context(),
424 0 : left_state, effect(), control());
425 0 : Node* left_success = graph()->NewNode(common()->IfSuccess(), left_conv);
426 : Node* right_state = CreateFrameStateForRightInput(left_conv);
427 : Node* right_conv =
428 : graph()->NewNode(javascript()->ToNumber(), right(), context(),
429 0 : right_state, left_conv, left_success);
430 : Node* left_exception =
431 0 : graph()->NewNode(common()->IfException(), left_conv, left_conv);
432 : Node* right_exception =
433 0 : graph()->NewNode(common()->IfException(), right_conv, right_conv);
434 0 : NodeProperties::ReplaceControlInput(if_success, right_conv);
435 : update_effect(right_conv);
436 :
437 : // Wire conversions to existing {IfException} continuation.
438 : Node* exception_merge = if_exception;
439 : Node* exception_value =
440 : graph()->NewNode(common()->Phi(MachineRepresentation::kTagged, 2),
441 0 : left_exception, right_exception, exception_merge);
442 : Node* exception_effect =
443 : graph()->NewNode(common()->EffectPhi(2), left_exception,
444 0 : right_exception, exception_merge);
445 0 : for (Edge edge : exception_merge->use_edges()) {
446 0 : if (NodeProperties::IsEffectEdge(edge)) edge.UpdateTo(exception_effect);
447 0 : if (NodeProperties::IsValueEdge(edge)) edge.UpdateTo(exception_value);
448 : }
449 : NodeProperties::RemoveType(exception_merge);
450 0 : exception_merge->ReplaceInput(0, left_exception);
451 0 : exception_merge->ReplaceInput(1, right_exception);
452 0 : NodeProperties::ChangeOp(exception_merge, common()->Merge(2));
453 :
454 0 : *left_result = left_conv;
455 0 : *right_result = right_conv;
456 0 : }
457 :
458 248100 : Node* ConvertToUI32(Node* node, Signedness signedness) {
459 : // Avoid introducing too many eager NumberToXXnt32() operations.
460 : Type* type = NodeProperties::GetType(node);
461 138390 : if (signedness == kSigned) {
462 101170 : if (!type->Is(Type::Signed32())) {
463 41180 : node = graph()->NewNode(simplified()->NumberToInt32(), node);
464 : }
465 : } else {
466 : DCHECK_EQ(kUnsigned, signedness);
467 37220 : if (!type->Is(Type::Unsigned32())) {
468 13675 : node = graph()->NewNode(simplified()->NumberToUint32(), node);
469 : }
470 : }
471 138390 : return node;
472 : }
473 :
474 : void update_effect(Node* effect) {
475 8188 : NodeProperties::ReplaceEffectInput(node_, effect);
476 : }
477 : };
478 :
479 :
480 : // TODO(turbofan): js-typed-lowering improvements possible
481 : // - immediately put in type bounds for all new nodes
482 : // - relax effects from generic but not-side-effecting operations
483 :
484 418317 : JSTypedLowering::JSTypedLowering(Editor* editor,
485 : CompilationDependencies* dependencies,
486 : Flags flags, JSGraph* jsgraph, Zone* zone)
487 : : AdvancedReducer(editor),
488 : dependencies_(dependencies),
489 : flags_(flags),
490 : jsgraph_(jsgraph),
491 : pointer_comparable_type_(Type::Union(
492 : Type::Oddball(),
493 : Type::Union(
494 : Type::SymbolOrReceiver(),
495 : Type::HeapConstant(factory()->empty_string(), graph()->zone()),
496 : graph()->zone()),
497 836634 : graph()->zone())),
498 836634 : type_cache_(TypeCache::Get()) {
499 2091585 : for (size_t k = 0; k < arraysize(shifted_int32_ranges_); ++k) {
500 1673268 : double min = kMinInt / (1 << k);
501 1673268 : double max = kMaxInt / (1 << k);
502 3346536 : shifted_int32_ranges_[k] = Type::Range(min, max, graph()->zone());
503 : }
504 418317 : }
505 :
506 311816 : Reduction JSTypedLowering::ReduceSpeculativeNumberAdd(Node* node) {
507 : JSBinopReduction r(this, node);
508 155908 : NumberOperationHint hint = NumberOperationHintOf(node->op());
509 207885 : if (hint == NumberOperationHint::kNumberOrOddball &&
510 207207 : r.BothInputsAre(Type::PlainPrimitive()) &&
511 51299 : r.NeitherInputCanBe(Type::StringOrReceiver())) {
512 : // SpeculativeNumberAdd(x:-string, y:-string) =>
513 : // NumberAdd(ToNumber(x), ToNumber(y))
514 51299 : r.ConvertInputsToNumber();
515 51299 : return r.ChangeToPureOperator(simplified()->NumberAdd(), Type::Number());
516 : }
517 : return NoChange();
518 : }
519 :
520 262449 : Reduction JSTypedLowering::ReduceJSAdd(Node* node) {
521 : JSBinopReduction r(this, node);
522 120613 : if (r.BothInputsAre(Type::Number())) {
523 : // JSAdd(x:number, y:number) => NumberAdd(x, y)
524 23312 : r.ConvertInputsToNumber();
525 23312 : return r.ChangeToPureOperator(simplified()->NumberAdd(), Type::Number());
526 : }
527 254814 : if ((r.BothInputsAre(Type::PlainPrimitive()) ||
528 134763 : !(flags() & kDeoptimizationEnabled)) &&
529 37462 : r.NeitherInputCanBe(Type::StringOrReceiver())) {
530 : // JSAdd(x:-string, y:-string) => NumberAdd(ToNumber(x), ToNumber(y))
531 168 : r.ConvertInputsToNumber();
532 168 : return r.ChangeToPureOperator(simplified()->NumberAdd(), Type::Number());
533 : }
534 97133 : if (r.OneInputIs(Type::String())) {
535 74259 : if (r.ShouldCreateConsString()) {
536 3341 : return ReduceCreateConsString(node);
537 : }
538 : StringAddFlags flags = STRING_ADD_CHECK_NONE;
539 70918 : if (!r.LeftInputIs(Type::String())) {
540 : flags = STRING_ADD_CONVERT_LEFT;
541 55837 : } else if (!r.RightInputIs(Type::String())) {
542 : flags = STRING_ADD_CONVERT_RIGHT;
543 : }
544 70918 : Operator::Properties properties = node->op()->properties();
545 70918 : if (r.NeitherInputCanBe(Type::Receiver())) {
546 : // Both sides are already strings, so we know that the
547 : // string addition will not cause any observable side
548 : // effects; it can still throw obviously.
549 28075 : properties = Operator::kNoWrite | Operator::kNoDeopt;
550 : }
551 : // JSAdd(x:string, y) => CallStub[StringAdd](x, y)
552 : // JSAdd(x, y:string) => CallStub[StringAdd](x, y)
553 : Callable const callable =
554 70918 : CodeFactory::StringAdd(isolate(), flags, NOT_TENURED);
555 : CallDescriptor const* const desc = Linkage::GetStubCallDescriptor(
556 : isolate(), graph()->zone(), callable.descriptor(), 0,
557 212754 : CallDescriptor::kNeedsFrameState, properties);
558 : DCHECK_EQ(1, OperatorProperties::GetFrameStateInputCount(node->op()));
559 : node->InsertInput(graph()->zone(), 0,
560 141836 : jsgraph()->HeapConstant(callable.code()));
561 70918 : NodeProperties::ChangeOp(node, common()->Call(desc));
562 : return Changed(node);
563 : }
564 : return NoChange();
565 : }
566 :
567 88140 : Reduction JSTypedLowering::ReduceNumberBinop(Node* node) {
568 : JSBinopReduction r(this, node);
569 130281 : if (r.BothInputsAre(Type::PlainPrimitive()) ||
570 : !(flags() & kDeoptimizationEnabled)) {
571 46154 : r.ConvertInputsToNumber();
572 46154 : return r.ChangeToPureOperator(r.NumberOp(), Type::Number());
573 : }
574 : return NoChange();
575 : }
576 :
577 144718 : Reduction JSTypedLowering::ReduceSpeculativeNumberBinop(Node* node) {
578 : JSBinopReduction r(this, node);
579 72359 : NumberOperationHint hint = NumberOperationHintOf(node->op());
580 110258 : if (hint == NumberOperationHint::kNumberOrOddball &&
581 37899 : r.BothInputsAre(Type::NumberOrOddball())) {
582 19000 : r.ConvertInputsToNumber();
583 : return r.ChangeToPureOperator(r.NumberOpFromSpeculativeNumberOp(),
584 19000 : Type::Number());
585 : }
586 : return NoChange();
587 : }
588 :
589 44899 : Reduction JSTypedLowering::ReduceInt32Binop(Node* node) {
590 : JSBinopReduction r(this, node);
591 51621 : if (r.BothInputsAre(Type::PlainPrimitive()) ||
592 : !(flags() & kDeoptimizationEnabled)) {
593 40492 : r.ConvertInputsToNumber();
594 40492 : r.ConvertInputsToUI32(kSigned, kSigned);
595 40492 : return r.ChangeToPureOperator(r.NumberOp(), Type::Signed32());
596 : }
597 : return NoChange();
598 : }
599 :
600 30543 : Reduction JSTypedLowering::ReduceUI32Shift(Node* node, Signedness signedness) {
601 : JSBinopReduction r(this, node);
602 32459 : if (r.BothInputsAre(Type::PlainPrimitive()) ||
603 : !(flags() & kDeoptimizationEnabled)) {
604 28703 : r.ConvertInputsToNumber();
605 28703 : r.ConvertInputsToUI32(signedness, kUnsigned);
606 : return r.ChangeToPureOperator(r.NumberOp(), signedness == kUnsigned
607 : ? Type::Unsigned32()
608 28703 : : Type::Signed32());
609 : }
610 : return NoChange();
611 : }
612 :
613 16776 : Reduction JSTypedLowering::ReduceCreateConsString(Node* node) {
614 3341 : Node* first = NodeProperties::GetValueInput(node, 0);
615 3341 : Node* second = NodeProperties::GetValueInput(node, 1);
616 3341 : Node* context = NodeProperties::GetContextInput(node);
617 3341 : Node* frame_state = NodeProperties::GetFrameStateInput(node);
618 3341 : Node* effect = NodeProperties::GetEffectInput(node);
619 3341 : Node* control = NodeProperties::GetControlInput(node);
620 :
621 : // Make sure {first} is actually a String.
622 : Type* first_type = NodeProperties::GetType(first);
623 3341 : if (!first_type->Is(Type::String())) {
624 : first = effect =
625 73 : graph()->NewNode(simplified()->CheckString(), first, effect, control);
626 : first_type = NodeProperties::GetType(first);
627 : }
628 :
629 : // Make sure {second} is actually a String.
630 : Type* second_type = NodeProperties::GetType(second);
631 3341 : if (!second_type->Is(Type::String())) {
632 : second = effect =
633 87 : graph()->NewNode(simplified()->CheckString(), second, effect, control);
634 : second_type = NodeProperties::GetType(second);
635 : }
636 :
637 : // Determine the {first} length.
638 3341 : HeapObjectBinopMatcher m(node);
639 : Node* first_length =
640 3661 : (m.left().HasValue() && m.left().Value()->IsString())
641 : ? jsgraph()->Constant(
642 : Handle<String>::cast(m.left().Value())->length())
643 : : effect = graph()->NewNode(
644 : simplified()->LoadField(AccessBuilder::ForStringLength()),
645 10023 : first, effect, control);
646 :
647 : // Determine the {second} length.
648 : Node* second_length =
649 6433 : (m.right().HasValue() && m.right().Value()->IsString())
650 : ? jsgraph()->Constant(
651 : Handle<String>::cast(m.right().Value())->length())
652 : : effect = graph()->NewNode(
653 : simplified()->LoadField(AccessBuilder::ForStringLength()),
654 10023 : second, effect, control);
655 :
656 : // Compute the resulting length.
657 : Node* length =
658 3341 : graph()->NewNode(simplified()->NumberAdd(), first_length, second_length);
659 :
660 : // Check if we would overflow the allowed maximum string length.
661 : Node* check = graph()->NewNode(simplified()->NumberLessThanOrEqual(), length,
662 6682 : jsgraph()->Constant(String::kMaxLength));
663 3341 : if (isolate()->IsStringLengthOverflowIntact()) {
664 : // Add a code dependency on the string length overflow protector.
665 : dependencies()->AssumePropertyCell(factory()->string_length_protector());
666 :
667 : // We can just deoptimize if the {check} fails. Besides generating a
668 : // shorter code sequence than the version below, this has the additional
669 : // benefit of not holding on to the lazy {frame_state} and thus potentially
670 : // reduces the number of live ranges and allows for more truncations.
671 3297 : effect = graph()->NewNode(simplified()->CheckIf(), check, effect, control);
672 : } else {
673 : Node* branch =
674 44 : graph()->NewNode(common()->Branch(BranchHint::kTrue), check, control);
675 44 : Node* if_false = graph()->NewNode(common()->IfFalse(), branch);
676 : Node* efalse = effect;
677 : {
678 : // Throw a RangeError in case of overflow.
679 : Node* vfalse = efalse = if_false = graph()->NewNode(
680 : javascript()->CallRuntime(Runtime::kThrowInvalidStringLength),
681 44 : context, frame_state, efalse, if_false);
682 :
683 : // Update potential {IfException} uses of {node} to point to the
684 : // %ThrowInvalidStringLength runtime call node instead.
685 44 : Node* on_exception = nullptr;
686 44 : if (NodeProperties::IsExceptionalCall(node, &on_exception)) {
687 18 : NodeProperties::ReplaceControlInput(on_exception, vfalse);
688 18 : NodeProperties::ReplaceEffectInput(on_exception, efalse);
689 18 : if_false = graph()->NewNode(common()->IfSuccess(), vfalse);
690 3403 : Revisit(on_exception);
691 : }
692 :
693 : // The above %ThrowInvalidStringLength runtime call is an unconditional
694 : // throw, making it impossible to return a successful completion in this
695 : // case. We simply connect the successful completion to the graph end.
696 44 : if_false = graph()->NewNode(common()->Throw(), efalse, if_false);
697 : // TODO(bmeurer): This should be on the AdvancedReducer somehow.
698 44 : NodeProperties::MergeControlToEnd(graph(), common(), if_false);
699 44 : Revisit(graph()->end());
700 : }
701 44 : control = graph()->NewNode(common()->IfTrue(), branch);
702 : }
703 :
704 : // Figure out the map for the resulting ConsString.
705 : // TODO(turbofan): We currently just use the cons_string_map here for
706 : // the sake of simplicity; we could also try to be smarter here and
707 : // use the one_byte_cons_string_map instead when the resulting ConsString
708 : // contains only one byte characters.
709 3341 : Node* value_map = jsgraph()->HeapConstant(factory()->cons_string_map());
710 :
711 : // Allocate the resulting ConsString.
712 : effect = graph()->NewNode(
713 3341 : common()->BeginRegion(RegionObservability::kNotObservable), effect);
714 : Node* value = effect =
715 : graph()->NewNode(simplified()->Allocate(Type::OtherString(), NOT_TENURED),
716 6682 : jsgraph()->Constant(ConsString::kSize), effect, control);
717 : effect = graph()->NewNode(simplified()->StoreField(AccessBuilder::ForMap()),
718 10023 : value, value_map, effect, control);
719 : effect = graph()->NewNode(
720 : simplified()->StoreField(AccessBuilder::ForNameHashField()), value,
721 10023 : jsgraph()->Constant(Name::kEmptyHashField), effect, control);
722 : effect = graph()->NewNode(
723 : simplified()->StoreField(AccessBuilder::ForStringLength()), value, length,
724 10023 : effect, control);
725 : effect = graph()->NewNode(
726 : simplified()->StoreField(AccessBuilder::ForConsStringFirst()), value,
727 10023 : first, effect, control);
728 : effect = graph()->NewNode(
729 : simplified()->StoreField(AccessBuilder::ForConsStringSecond()), value,
730 10023 : second, effect, control);
731 :
732 : // Morph the {node} into a {FinishRegion}.
733 : ReplaceWithValue(node, node, node, control);
734 3341 : node->ReplaceInput(0, value);
735 3341 : node->ReplaceInput(1, effect);
736 3341 : node->TrimInputCount(2);
737 3341 : NodeProperties::ChangeOp(node, common()->FinishRegion());
738 3341 : return Changed(node);
739 : }
740 :
741 53880 : Reduction JSTypedLowering::ReduceSpeculativeNumberComparison(Node* node) {
742 : JSBinopReduction r(this, node);
743 99081 : if (r.BothInputsAre(Type::Signed32()) ||
744 45201 : r.BothInputsAre(Type::Unsigned32())) {
745 8865 : return r.ChangeToPureOperator(r.NumberOpFromSpeculativeNumberOp());
746 : }
747 : return Changed(node);
748 : }
749 :
750 54225 : Reduction JSTypedLowering::ReduceJSComparison(Node* node) {
751 : JSBinopReduction r(this, node);
752 38228 : if (r.BothInputsAre(Type::String())) {
753 : // If both inputs are definitely strings, perform a string comparison.
754 : const Operator* stringOp;
755 647 : switch (node->opcode()) {
756 : case IrOpcode::kJSLessThan:
757 424 : stringOp = simplified()->StringLessThan();
758 424 : break;
759 : case IrOpcode::kJSGreaterThan:
760 80 : stringOp = simplified()->StringLessThan();
761 80 : r.SwapInputs(); // a > b => b < a
762 80 : break;
763 : case IrOpcode::kJSLessThanOrEqual:
764 71 : stringOp = simplified()->StringLessThanOrEqual();
765 71 : break;
766 : case IrOpcode::kJSGreaterThanOrEqual:
767 72 : stringOp = simplified()->StringLessThanOrEqual();
768 72 : r.SwapInputs(); // a >= b => b <= a
769 72 : break;
770 : default:
771 : return NoChange();
772 : }
773 647 : r.ChangeToPureOperator(stringOp);
774 : return Changed(node);
775 : }
776 :
777 : const Operator* less_than;
778 : const Operator* less_than_or_equal;
779 69314 : if (r.BothInputsAre(Type::Signed32()) ||
780 31733 : r.BothInputsAre(Type::Unsigned32())) {
781 6564 : less_than = simplified()->NumberLessThan();
782 6564 : less_than_or_equal = simplified()->NumberLessThanOrEqual();
783 90467 : } else if (r.OneInputCannotBe(Type::StringOrReceiver()) &&
784 48222 : (r.BothInputsAre(Type::PlainPrimitive()) ||
785 : !(flags() & kDeoptimizationEnabled))) {
786 8714 : r.ConvertInputsToNumber();
787 8714 : less_than = simplified()->NumberLessThan();
788 8714 : less_than_or_equal = simplified()->NumberLessThanOrEqual();
789 22303 : } else if (r.IsStringCompareOperation()) {
790 72 : r.CheckInputsToString();
791 72 : less_than = simplified()->StringLessThan();
792 72 : less_than_or_equal = simplified()->StringLessThanOrEqual();
793 : } else {
794 : return NoChange();
795 : }
796 : const Operator* comparison;
797 15350 : switch (node->opcode()) {
798 : case IrOpcode::kJSLessThan:
799 : comparison = less_than;
800 : break;
801 : case IrOpcode::kJSGreaterThan:
802 : comparison = less_than;
803 3572 : r.SwapInputs(); // a > b => b < a
804 3572 : break;
805 : case IrOpcode::kJSLessThanOrEqual:
806 : comparison = less_than_or_equal;
807 2079 : break;
808 : case IrOpcode::kJSGreaterThanOrEqual:
809 : comparison = less_than_or_equal;
810 2116 : r.SwapInputs(); // a >= b => b <= a
811 2116 : break;
812 : default:
813 : return NoChange();
814 : }
815 15350 : return r.ChangeToPureOperator(comparison);
816 : }
817 :
818 43738 : Reduction JSTypedLowering::ReduceJSTypeOf(Node* node) {
819 : Node* const input = node->InputAt(0);
820 : Type* type = NodeProperties::GetType(input);
821 : Factory* const f = factory();
822 31284 : if (type->Is(Type::Boolean())) {
823 2903 : return Replace(jsgraph()->Constant(f->boolean_string()));
824 28381 : } else if (type->Is(Type::Number())) {
825 8168 : return Replace(jsgraph()->Constant(f->number_string()));
826 20213 : } else if (type->Is(Type::String())) {
827 851 : return Replace(jsgraph()->Constant(f->string_string()));
828 19362 : } else if (type->Is(Type::Symbol())) {
829 0 : return Replace(jsgraph()->Constant(f->symbol_string()));
830 19362 : } else if (type->Is(Type::OtherUndetectableOrUndefined())) {
831 363 : return Replace(jsgraph()->Constant(f->undefined_string()));
832 18999 : } else if (type->Is(Type::NonCallableOrNull())) {
833 142 : return Replace(jsgraph()->Constant(f->object_string()));
834 18857 : } else if (type->Is(Type::Function())) {
835 27 : return Replace(jsgraph()->Constant(f->function_string()));
836 18830 : } else if (type->IsHeapConstant()) {
837 : return Replace(jsgraph()->Constant(
838 0 : Object::TypeOf(isolate(), type->AsHeapConstant()->Value())));
839 : }
840 :
841 : return NoChange();
842 : }
843 :
844 18233 : Reduction JSTypedLowering::ReduceJSEqual(Node* node) {
845 : JSBinopReduction r(this, node);
846 :
847 18233 : if (r.BothInputsAre(Type::UniqueName())) {
848 1459 : return r.ChangeToPureOperator(simplified()->ReferenceEqual());
849 : }
850 16774 : if (r.IsInternalizedStringCompareOperation()) {
851 103 : r.CheckInputsToInternalizedString();
852 103 : return r.ChangeToPureOperator(simplified()->ReferenceEqual());
853 : }
854 16671 : if (r.BothInputsAre(Type::String())) {
855 306 : return r.ChangeToPureOperator(simplified()->StringEqual());
856 : }
857 16365 : if (r.BothInputsAre(Type::Boolean())) {
858 39 : return r.ChangeToPureOperator(simplified()->ReferenceEqual());
859 : }
860 16326 : if (r.BothInputsAre(Type::Receiver())) {
861 20 : return r.ChangeToPureOperator(simplified()->ReferenceEqual());
862 : }
863 16306 : if (r.OneInputIs(Type::Undetectable())) {
864 : RelaxEffectsAndControls(node);
865 21 : node->RemoveInput(r.LeftInputIs(Type::Undetectable()) ? 0 : 1);
866 21 : node->TrimInputCount(1);
867 21 : NodeProperties::ChangeOp(node, simplified()->ObjectIsUndetectable());
868 : return Changed(node);
869 : }
870 :
871 26924 : if (r.BothInputsAre(Type::Signed32()) ||
872 10639 : r.BothInputsAre(Type::Unsigned32())) {
873 5704 : return r.ChangeToPureOperator(simplified()->NumberEqual());
874 10581 : } else if (r.BothInputsAre(Type::Number())) {
875 951 : return r.ChangeToPureOperator(simplified()->NumberEqual());
876 9630 : } else if (r.IsReceiverCompareOperation()) {
877 204 : r.CheckInputsToReceiver();
878 204 : return r.ChangeToPureOperator(simplified()->ReferenceEqual());
879 9426 : } else if (r.IsStringCompareOperation()) {
880 20 : r.CheckInputsToString();
881 20 : return r.ChangeToPureOperator(simplified()->StringEqual());
882 : }
883 : return NoChange();
884 : }
885 :
886 241521 : Reduction JSTypedLowering::ReduceJSStrictEqual(Node* node) {
887 : JSBinopReduction r(this, node);
888 482662 : if (r.left() == r.right()) {
889 : // x === x is always true if x != NaN
890 : Node* replacement = graph()->NewNode(
891 : simplified()->BooleanNot(),
892 25299 : graph()->NewNode(simplified()->ObjectIsNaN(), r.left()));
893 8623 : ReplaceWithValue(node, replacement);
894 : return Replace(replacement);
895 : }
896 232898 : if (r.OneInputCannotBe(Type::NumberOrString())) {
897 : // For values with canonical representation (i.e. neither String, nor
898 : // Number) an empty type intersection means the values cannot be strictly
899 : // equal.
900 4554 : if (!r.left_type()->Maybe(r.right_type())) {
901 190 : Node* replacement = jsgraph()->FalseConstant();
902 : ReplaceWithValue(node, replacement);
903 : return Replace(replacement);
904 : }
905 : }
906 :
907 232708 : if (r.BothInputsAre(Type::Unique())) {
908 15141 : return r.ChangeToPureOperator(simplified()->ReferenceEqual());
909 : }
910 217567 : if (r.OneInputIs(pointer_comparable_type_)) {
911 1556 : return r.ChangeToPureOperator(simplified()->ReferenceEqual());
912 : }
913 216011 : if (r.IsInternalizedStringCompareOperation()) {
914 4153 : r.CheckInputsToInternalizedString();
915 4153 : return r.ChangeToPureOperator(simplified()->ReferenceEqual());
916 : }
917 211858 : if (r.BothInputsAre(Type::String())) {
918 1398 : return r.ChangeToPureOperator(simplified()->StringEqual());
919 : }
920 :
921 : NumberOperationHint hint;
922 361349 : if (r.BothInputsAre(Type::Signed32()) ||
923 150889 : r.BothInputsAre(Type::Unsigned32())) {
924 59726 : return r.ChangeToPureOperator(simplified()->NumberEqual());
925 150734 : } else if (r.GetCompareNumberOperationHint(&hint)) {
926 : return r.ChangeToSpeculativeOperator(
927 32122 : simplified()->SpeculativeNumberEqual(hint), Type::Boolean());
928 134673 : } else if (r.BothInputsAre(Type::Number())) {
929 8350 : return r.ChangeToPureOperator(simplified()->NumberEqual());
930 126323 : } else if (r.IsReceiverCompareOperation()) {
931 : // For strict equality, it's enough to know that one input is a Receiver,
932 : // as a strict equality comparison with a Receiver can only yield true if
933 : // both sides refer to the same Receiver than.
934 183 : r.CheckLeftInputToReceiver();
935 183 : return r.ChangeToPureOperator(simplified()->ReferenceEqual());
936 126140 : } else if (r.IsStringCompareOperation()) {
937 470 : r.CheckInputsToString();
938 470 : return r.ChangeToPureOperator(simplified()->StringEqual());
939 : }
940 : return NoChange();
941 : }
942 :
943 113502 : Reduction JSTypedLowering::ReduceJSToBoolean(Node* node) {
944 : Node* const input = node->InputAt(0);
945 : Type* const input_type = NodeProperties::GetType(input);
946 112618 : if (input_type->Is(Type::Boolean())) {
947 : // JSToBoolean(x:boolean) => x
948 : return Replace(input);
949 74391 : } else if (input_type->Is(Type::OrderedNumber())) {
950 : // JSToBoolean(x:ordered-number) => BooleanNot(NumberEqual(x,#0))
951 : node->ReplaceInput(0, graph()->NewNode(simplified()->NumberEqual(), input,
952 2610 : jsgraph()->ZeroConstant()));
953 870 : node->TrimInputCount(1);
954 870 : NodeProperties::ChangeOp(node, simplified()->BooleanNot());
955 : return Changed(node);
956 73521 : } else if (input_type->Is(Type::Number())) {
957 : // JSToBoolean(x:number) => NumberToBoolean(x)
958 253 : node->TrimInputCount(1);
959 253 : NodeProperties::ChangeOp(node, simplified()->NumberToBoolean());
960 : return Changed(node);
961 73268 : } else if (input_type->Is(Type::DetectableReceiverOrNull())) {
962 : // JSToBoolean(x:detectable receiver \/ null)
963 : // => BooleanNot(ReferenceEqual(x,#null))
964 : node->ReplaceInput(0, graph()->NewNode(simplified()->ReferenceEqual(),
965 21 : input, jsgraph()->NullConstant()));
966 7 : node->TrimInputCount(1);
967 7 : NodeProperties::ChangeOp(node, simplified()->BooleanNot());
968 : return Changed(node);
969 73261 : } else if (input_type->Is(Type::ReceiverOrNullOrUndefined())) {
970 : // JSToBoolean(x:receiver \/ null \/ undefined)
971 : // => BooleanNot(ObjectIsUndetectable(x))
972 : node->ReplaceInput(
973 124 : 0, graph()->NewNode(simplified()->ObjectIsUndetectable(), input));
974 62 : node->TrimInputCount(1);
975 62 : NodeProperties::ChangeOp(node, simplified()->BooleanNot());
976 : return Changed(node);
977 73199 : } else if (input_type->Is(Type::String())) {
978 : // JSToBoolean(x:string) => BooleanNot(ReferenceEqual(x,""))
979 : node->ReplaceInput(0,
980 : graph()->NewNode(simplified()->ReferenceEqual(), input,
981 21 : jsgraph()->EmptyStringConstant()));
982 7 : node->TrimInputCount(1);
983 7 : NodeProperties::ChangeOp(node, simplified()->BooleanNot());
984 : return Changed(node);
985 : }
986 : return NoChange();
987 : }
988 :
989 271 : Reduction JSTypedLowering::ReduceJSToInteger(Node* node) {
990 271 : Node* const input = NodeProperties::GetValueInput(node, 0);
991 : Type* const input_type = NodeProperties::GetType(input);
992 542 : if (input_type->Is(type_cache_.kIntegerOrMinusZero)) {
993 : // JSToInteger(x:integer) => x
994 0 : ReplaceWithValue(node, input);
995 : return Replace(input);
996 : }
997 : return NoChange();
998 : }
999 :
1000 1531 : Reduction JSTypedLowering::ReduceJSToName(Node* node) {
1001 1531 : Node* const input = NodeProperties::GetValueInput(node, 0);
1002 : Type* const input_type = NodeProperties::GetType(input);
1003 1531 : if (input_type->Is(Type::Name())) {
1004 : // JSToName(x:name) => x
1005 167 : ReplaceWithValue(node, input);
1006 : return Replace(input);
1007 : }
1008 : return NoChange();
1009 : }
1010 :
1011 281 : Reduction JSTypedLowering::ReduceJSToLength(Node* node) {
1012 257 : Node* input = NodeProperties::GetValueInput(node, 0);
1013 : Type* input_type = NodeProperties::GetType(input);
1014 514 : if (input_type->Is(type_cache_.kIntegerOrMinusZero)) {
1015 24 : if (input_type->Max() <= 0.0) {
1016 4 : input = jsgraph()->ZeroConstant();
1017 20 : } else if (input_type->Min() >= kMaxSafeInteger) {
1018 4 : input = jsgraph()->Constant(kMaxSafeInteger);
1019 : } else {
1020 16 : if (input_type->Min() <= 0.0) {
1021 : input = graph()->NewNode(simplified()->NumberMax(),
1022 32 : jsgraph()->ZeroConstant(), input);
1023 : }
1024 16 : if (input_type->Max() > kMaxSafeInteger) {
1025 : input = graph()->NewNode(simplified()->NumberMin(),
1026 0 : jsgraph()->Constant(kMaxSafeInteger), input);
1027 : }
1028 : }
1029 24 : ReplaceWithValue(node, input);
1030 : return Replace(input);
1031 : }
1032 : return NoChange();
1033 : }
1034 :
1035 444868 : Reduction JSTypedLowering::ReduceJSToNumberInput(Node* input) {
1036 : // Try constant-folding of JSToNumber with constant inputs.
1037 : Type* input_type = NodeProperties::GetType(input);
1038 440160 : if (input_type->Is(Type::String())) {
1039 : HeapObjectMatcher m(input);
1040 2807 : if (m.HasValue() && m.Value()->IsString()) {
1041 : Handle<Object> input_value = m.Value();
1042 : return Replace(jsgraph()->Constant(
1043 1360 : String::ToNumber(Handle<String>::cast(input_value))));
1044 : }
1045 : }
1046 439480 : if (input_type->IsHeapConstant()) {
1047 : Handle<Object> input_value = input_type->AsHeapConstant()->Value();
1048 1732 : if (input_value->IsOddball()) {
1049 : return Replace(jsgraph()->Constant(
1050 3464 : Oddball::ToNumber(Handle<Oddball>::cast(input_value))));
1051 : }
1052 : }
1053 437748 : if (input_type->Is(Type::Number())) {
1054 : // JSToNumber(x:number) => x
1055 : return Changed(input);
1056 : }
1057 23984 : if (input_type->Is(Type::Undefined())) {
1058 : // JSToNumber(undefined) => #NaN
1059 1148 : return Replace(jsgraph()->NaNConstant());
1060 : }
1061 22836 : if (input_type->Is(Type::Null())) {
1062 : // JSToNumber(null) => #0
1063 1148 : return Replace(jsgraph()->ZeroConstant());
1064 : }
1065 : return NoChange();
1066 : }
1067 :
1068 6497 : Reduction JSTypedLowering::ReduceJSToNumber(Node* node) {
1069 : // Try to reduce the input first.
1070 : Node* const input = node->InputAt(0);
1071 6497 : Reduction reduction = ReduceJSToNumberInput(input);
1072 6497 : if (reduction.Changed()) {
1073 1684 : ReplaceWithValue(node, reduction.replacement());
1074 1684 : return reduction;
1075 : }
1076 : Type* const input_type = NodeProperties::GetType(input);
1077 4813 : if (input_type->Is(Type::PlainPrimitive())) {
1078 : RelaxEffectsAndControls(node);
1079 64 : node->TrimInputCount(1);
1080 64 : NodeProperties::ChangeOp(node, simplified()->PlainPrimitiveToNumber());
1081 : return Changed(node);
1082 : }
1083 : return NoChange();
1084 : }
1085 :
1086 2380 : Reduction JSTypedLowering::ReduceJSToStringInput(Node* input) {
1087 2380 : if (input->opcode() == IrOpcode::kJSToString) {
1088 : // Recursively try to reduce the input first.
1089 0 : Reduction result = ReduceJSToString(input);
1090 0 : if (result.Changed()) return result;
1091 : return Changed(input); // JSToString(JSToString(x)) => JSToString(x)
1092 : }
1093 : Type* input_type = NodeProperties::GetType(input);
1094 2380 : if (input_type->Is(Type::String())) {
1095 : return Changed(input); // JSToString(x:string) => x
1096 : }
1097 2340 : if (input_type->Is(Type::Boolean())) {
1098 : return Replace(graph()->NewNode(
1099 : common()->Select(MachineRepresentation::kTagged), input,
1100 : jsgraph()->HeapConstant(factory()->true_string()),
1101 56 : jsgraph()->HeapConstant(factory()->false_string())));
1102 : }
1103 2326 : if (input_type->Is(Type::Undefined())) {
1104 16 : return Replace(jsgraph()->HeapConstant(factory()->undefined_string()));
1105 : }
1106 2310 : if (input_type->Is(Type::Null())) {
1107 16 : return Replace(jsgraph()->HeapConstant(factory()->null_string()));
1108 : }
1109 : // TODO(turbofan): js-typed-lowering of ToString(x:number)
1110 : return NoChange();
1111 : }
1112 :
1113 2380 : Reduction JSTypedLowering::ReduceJSToString(Node* node) {
1114 : // Try to reduce the input first.
1115 : Node* const input = node->InputAt(0);
1116 2380 : Reduction reduction = ReduceJSToStringInput(input);
1117 2380 : if (reduction.Changed()) {
1118 86 : ReplaceWithValue(node, reduction.replacement());
1119 86 : return reduction;
1120 : }
1121 : return NoChange();
1122 : }
1123 :
1124 5109 : Reduction JSTypedLowering::ReduceJSToObject(Node* node) {
1125 : DCHECK_EQ(IrOpcode::kJSToObject, node->opcode());
1126 2433 : Node* receiver = NodeProperties::GetValueInput(node, 0);
1127 : Type* receiver_type = NodeProperties::GetType(receiver);
1128 2433 : Node* context = NodeProperties::GetContextInput(node);
1129 2433 : Node* frame_state = NodeProperties::GetFrameStateInput(node);
1130 2433 : Node* effect = NodeProperties::GetEffectInput(node);
1131 2433 : Node* control = NodeProperties::GetControlInput(node);
1132 2433 : if (receiver_type->Is(Type::Receiver())) {
1133 2392 : ReplaceWithValue(node, receiver, effect, control);
1134 : return Replace(receiver);
1135 : }
1136 :
1137 : // TODO(bmeurer/mstarzinger): Add support for lowering inside try blocks.
1138 2719 : if (receiver_type->Maybe(Type::NullOrUndefined()) &&
1139 1340 : NodeProperties::IsExceptionalCall(node)) {
1140 : // ToObject throws for null or undefined inputs.
1141 : return NoChange();
1142 : }
1143 :
1144 : // Check whether {receiver} is a spec object.
1145 1338 : Node* check = graph()->NewNode(simplified()->ObjectIsReceiver(), receiver);
1146 : Node* branch =
1147 1338 : graph()->NewNode(common()->Branch(BranchHint::kTrue), check, control);
1148 :
1149 1338 : Node* if_true = graph()->NewNode(common()->IfTrue(), branch);
1150 : Node* etrue = effect;
1151 : Node* rtrue = receiver;
1152 :
1153 1338 : Node* if_false = graph()->NewNode(common()->IfFalse(), branch);
1154 : Node* efalse = effect;
1155 : Node* rfalse;
1156 : {
1157 : // Convert {receiver} using the ToObjectStub.
1158 1338 : Callable callable = CodeFactory::ToObject(isolate());
1159 : CallDescriptor const* const desc = Linkage::GetStubCallDescriptor(
1160 : isolate(), graph()->zone(), callable.descriptor(), 0,
1161 4014 : CallDescriptor::kNeedsFrameState, node->op()->properties());
1162 : rfalse = efalse = if_false = graph()->NewNode(
1163 : common()->Call(desc), jsgraph()->HeapConstant(callable.code()),
1164 4014 : receiver, context, frame_state, efalse, if_false);
1165 : }
1166 :
1167 1338 : control = graph()->NewNode(common()->Merge(2), if_true, if_false);
1168 1338 : effect = graph()->NewNode(common()->EffectPhi(2), etrue, efalse, control);
1169 :
1170 : // Morph the {node} into an appropriate Phi.
1171 : ReplaceWithValue(node, node, effect, control);
1172 1338 : node->ReplaceInput(0, rtrue);
1173 1338 : node->ReplaceInput(1, rfalse);
1174 1338 : node->ReplaceInput(2, control);
1175 1338 : node->TrimInputCount(3);
1176 : NodeProperties::ChangeOp(node,
1177 1338 : common()->Phi(MachineRepresentation::kTagged, 2));
1178 : return Changed(node);
1179 : }
1180 :
1181 701918 : Reduction JSTypedLowering::ReduceJSLoadNamed(Node* node) {
1182 : DCHECK_EQ(IrOpcode::kJSLoadNamed, node->opcode());
1183 350959 : Node* receiver = NodeProperties::GetValueInput(node, 0);
1184 : Type* receiver_type = NodeProperties::GetType(receiver);
1185 350959 : Node* effect = NodeProperties::GetEffectInput(node);
1186 350959 : Node* control = NodeProperties::GetControlInput(node);
1187 350959 : Handle<Name> name = NamedAccessOf(node->op()).name();
1188 : // Optimize "length" property of strings.
1189 382018 : if (name.is_identical_to(factory()->length_string()) &&
1190 : receiver_type->Is(Type::String())) {
1191 : Node* value = effect = graph()->NewNode(
1192 : simplified()->LoadField(AccessBuilder::ForStringLength()), receiver,
1193 489 : effect, control);
1194 163 : ReplaceWithValue(node, value, effect);
1195 : return Replace(value);
1196 : }
1197 : return NoChange();
1198 : }
1199 :
1200 78274 : Reduction JSTypedLowering::ReduceJSLoadProperty(Node* node) {
1201 59116 : Node* key = NodeProperties::GetValueInput(node, 1);
1202 59116 : Node* base = NodeProperties::GetValueInput(node, 0);
1203 : Type* key_type = NodeProperties::GetType(key);
1204 : HeapObjectMatcher mbase(base);
1205 69660 : if (mbase.HasValue() && mbase.Value()->IsJSTypedArray()) {
1206 : Handle<JSTypedArray> const array =
1207 : Handle<JSTypedArray>::cast(mbase.Value());
1208 14314 : if (!array->GetBuffer()->was_neutered()) {
1209 14314 : array->GetBuffer()->set_is_neuterable(false);
1210 7157 : BufferAccess const access(array->type());
1211 : size_t const k =
1212 7157 : ElementSizeLog2Of(access.machine_type().representation());
1213 : double const byte_length = array->byte_length()->Number();
1214 7157 : CHECK_LT(k, arraysize(shifted_int32_ranges_));
1215 14314 : if (key_type->Is(shifted_int32_ranges_[k]) && byte_length <= kMaxInt) {
1216 : // JSLoadProperty(typed-array, int32)
1217 : Handle<FixedTypedArrayBase> elements =
1218 : Handle<FixedTypedArrayBase>::cast(handle(array->elements()));
1219 : Node* buffer = jsgraph()->PointerConstant(elements->external_pointer());
1220 7018 : Node* length = jsgraph()->Constant(byte_length);
1221 7018 : Node* effect = NodeProperties::GetEffectInput(node);
1222 7018 : Node* control = NodeProperties::GetControlInput(node);
1223 : // Check if we can avoid the bounds check.
1224 8307 : if (key_type->Min() >= 0 && key_type->Max() < array->length_value()) {
1225 : Node* load = graph()->NewNode(
1226 : simplified()->LoadElement(
1227 1213 : AccessBuilder::ForTypedArrayElement(array->type(), true)),
1228 3639 : buffer, key, effect, control);
1229 7018 : ReplaceWithValue(node, load, load);
1230 : return Replace(load);
1231 : }
1232 : // Compute byte offset.
1233 : Node* offset =
1234 : (k == 0) ? key : graph()->NewNode(
1235 : simplified()->NumberShiftLeft(), key,
1236 16049 : jsgraph()->Constant(static_cast<double>(k)));
1237 : Node* load = graph()->NewNode(simplified()->LoadBuffer(access), buffer,
1238 5805 : offset, length, effect, control);
1239 : ReplaceWithValue(node, load, load);
1240 : return Replace(load);
1241 : }
1242 : }
1243 : }
1244 : return NoChange();
1245 : }
1246 :
1247 47096 : Reduction JSTypedLowering::ReduceJSStoreProperty(Node* node) {
1248 33863 : Node* key = NodeProperties::GetValueInput(node, 1);
1249 33863 : Node* base = NodeProperties::GetValueInput(node, 0);
1250 33863 : Node* value = NodeProperties::GetValueInput(node, 2);
1251 : Type* key_type = NodeProperties::GetType(key);
1252 : Type* value_type = NodeProperties::GetType(value);
1253 :
1254 33863 : if (!value_type->Is(Type::PlainPrimitive())) return NoChange();
1255 :
1256 : HeapObjectMatcher mbase(base);
1257 18167 : if (mbase.HasValue() && mbase.Value()->IsJSTypedArray()) {
1258 : Handle<JSTypedArray> const array =
1259 : Handle<JSTypedArray>::cast(mbase.Value());
1260 10416 : if (!array->GetBuffer()->was_neutered()) {
1261 10416 : array->GetBuffer()->set_is_neuterable(false);
1262 5208 : BufferAccess const access(array->type());
1263 : size_t const k =
1264 5208 : ElementSizeLog2Of(access.machine_type().representation());
1265 : double const byte_length = array->byte_length()->Number();
1266 5208 : CHECK_LT(k, arraysize(shifted_int32_ranges_));
1267 10302 : if (access.external_array_type() != kExternalUint8ClampedArray &&
1268 10046 : key_type->Is(shifted_int32_ranges_[k]) && byte_length <= kMaxInt) {
1269 : // JSLoadProperty(typed-array, int32)
1270 : Handle<FixedTypedArrayBase> elements =
1271 : Handle<FixedTypedArrayBase>::cast(handle(array->elements()));
1272 : Node* buffer = jsgraph()->PointerConstant(elements->external_pointer());
1273 4838 : Node* length = jsgraph()->Constant(byte_length);
1274 4838 : Node* effect = NodeProperties::GetEffectInput(node);
1275 4838 : Node* control = NodeProperties::GetControlInput(node);
1276 : // Convert to a number first.
1277 4838 : if (!value_type->Is(Type::Number())) {
1278 672 : Reduction number_reduction = ReduceJSToNumberInput(value);
1279 672 : if (number_reduction.Changed()) {
1280 : value = number_reduction.replacement();
1281 : } else {
1282 : value =
1283 624 : graph()->NewNode(simplified()->PlainPrimitiveToNumber(), value);
1284 : }
1285 : }
1286 : // Check if we can avoid the bounds check.
1287 5735 : if (key_type->Min() >= 0 && key_type->Max() < array->length_value()) {
1288 : RelaxControls(node);
1289 844 : node->ReplaceInput(0, buffer);
1290 : DCHECK_EQ(key, node->InputAt(1));
1291 844 : node->ReplaceInput(2, value);
1292 844 : node->ReplaceInput(3, effect);
1293 844 : node->ReplaceInput(4, control);
1294 844 : node->TrimInputCount(5);
1295 : NodeProperties::ChangeOp(
1296 : node,
1297 : simplified()->StoreElement(
1298 1688 : AccessBuilder::ForTypedArrayElement(array->type(), true)));
1299 : return Changed(node);
1300 : }
1301 : // Compute byte offset.
1302 : Node* offset =
1303 : (k == 0) ? key : graph()->NewNode(
1304 : simplified()->NumberShiftLeft(), key,
1305 11108 : jsgraph()->Constant(static_cast<double>(k)));
1306 : // Turn into a StoreBuffer operation.
1307 : RelaxControls(node);
1308 3994 : node->ReplaceInput(0, buffer);
1309 3994 : node->ReplaceInput(1, offset);
1310 3994 : node->ReplaceInput(2, length);
1311 3994 : node->ReplaceInput(3, value);
1312 3994 : node->ReplaceInput(4, effect);
1313 3994 : node->ReplaceInput(5, control);
1314 3994 : node->TrimInputCount(6);
1315 3994 : NodeProperties::ChangeOp(node, simplified()->StoreBuffer(access));
1316 : return Changed(node);
1317 : }
1318 : }
1319 : }
1320 : return NoChange();
1321 : }
1322 :
1323 88 : Reduction JSTypedLowering::ReduceJSOrdinaryHasInstance(Node* node) {
1324 : DCHECK_EQ(IrOpcode::kJSOrdinaryHasInstance, node->opcode());
1325 64 : Node* constructor = NodeProperties::GetValueInput(node, 0);
1326 : Type* constructor_type = NodeProperties::GetType(constructor);
1327 64 : Node* object = NodeProperties::GetValueInput(node, 1);
1328 : Type* object_type = NodeProperties::GetType(object);
1329 :
1330 : // Check if the {constructor} cannot be callable.
1331 : // See ES6 section 7.3.19 OrdinaryHasInstance ( C, O ) step 1.
1332 64 : if (!constructor_type->Maybe(Type::Callable())) {
1333 8 : Node* value = jsgraph()->FalseConstant();
1334 24 : ReplaceWithValue(node, value);
1335 : return Replace(value);
1336 : }
1337 :
1338 : // If the {constructor} cannot be a JSBoundFunction and then {object}
1339 : // cannot be a JSReceiver, then this can be constant-folded to false.
1340 : // See ES6 section 7.3.19 OrdinaryHasInstance ( C, O ) step 2 and 3.
1341 72 : if (!object_type->Maybe(Type::Receiver()) &&
1342 16 : !constructor_type->Maybe(Type::BoundFunction())) {
1343 16 : Node* value = jsgraph()->FalseConstant();
1344 : ReplaceWithValue(node, value);
1345 : return Replace(value);
1346 : }
1347 :
1348 : return NoChange();
1349 : }
1350 :
1351 1184630 : Reduction JSTypedLowering::ReduceJSLoadContext(Node* node) {
1352 : DCHECK_EQ(IrOpcode::kJSLoadContext, node->opcode());
1353 1779262 : ContextAccess const& access = ContextAccessOf(node->op());
1354 592315 : Node* effect = NodeProperties::GetEffectInput(node);
1355 592315 : Node* context = NodeProperties::GetContextInput(node);
1356 592315 : Node* control = graph()->start();
1357 1189264 : for (size_t i = 0; i < access.depth(); ++i) {
1358 : context = effect = graph()->NewNode(
1359 : simplified()->LoadField(
1360 : AccessBuilder::ForContextSlot(Context::PREVIOUS_INDEX)),
1361 6951 : context, effect, control);
1362 : }
1363 592315 : node->ReplaceInput(0, context);
1364 592315 : node->ReplaceInput(1, effect);
1365 592315 : node->AppendInput(jsgraph()->zone(), control);
1366 : NodeProperties::ChangeOp(
1367 : node,
1368 1184630 : simplified()->LoadField(AccessBuilder::ForContextSlot(access.index())));
1369 592315 : return Changed(node);
1370 : }
1371 :
1372 156349 : Reduction JSTypedLowering::ReduceJSStoreContext(Node* node) {
1373 : DCHECK_EQ(IrOpcode::kJSStoreContext, node->opcode());
1374 469099 : ContextAccess const& access = ContextAccessOf(node->op());
1375 156349 : Node* effect = NodeProperties::GetEffectInput(node);
1376 156349 : Node* context = NodeProperties::GetContextInput(node);
1377 156349 : Node* control = graph()->start();
1378 156349 : Node* value = NodeProperties::GetValueInput(node, 0);
1379 312802 : for (size_t i = 0; i < access.depth(); ++i) {
1380 : context = effect = graph()->NewNode(
1381 : simplified()->LoadField(
1382 : AccessBuilder::ForContextSlot(Context::PREVIOUS_INDEX)),
1383 156 : context, effect, control);
1384 : }
1385 156349 : node->ReplaceInput(0, context);
1386 156349 : node->ReplaceInput(1, value);
1387 156349 : node->ReplaceInput(2, effect);
1388 : NodeProperties::ChangeOp(
1389 : node,
1390 312698 : simplified()->StoreField(AccessBuilder::ForContextSlot(access.index())));
1391 156349 : return Changed(node);
1392 : }
1393 :
1394 406 : Reduction JSTypedLowering::ReduceJSLoadModule(Node* node) {
1395 : DCHECK_EQ(IrOpcode::kJSLoadModule, node->opcode());
1396 406 : Node* effect = NodeProperties::GetEffectInput(node);
1397 406 : Node* control = NodeProperties::GetControlInput(node);
1398 :
1399 406 : int32_t cell_index = OpParameter<int32_t>(node);
1400 406 : Node* module = NodeProperties::GetValueInput(node, 0);
1401 :
1402 : Node* array;
1403 : int index;
1404 406 : if (ModuleDescriptor::GetCellIndexKind(cell_index) ==
1405 : ModuleDescriptor::kExport) {
1406 : array = effect = graph()->NewNode(
1407 : simplified()->LoadField(AccessBuilder::ForModuleRegularExports()),
1408 702 : module, effect, control);
1409 234 : index = cell_index - 1;
1410 : } else {
1411 : DCHECK_EQ(ModuleDescriptor::GetCellIndexKind(cell_index),
1412 : ModuleDescriptor::kImport);
1413 : array = effect = graph()->NewNode(
1414 : simplified()->LoadField(AccessBuilder::ForModuleRegularImports()),
1415 516 : module, effect, control);
1416 172 : index = -cell_index - 1;
1417 : }
1418 :
1419 : Node* cell = effect = graph()->NewNode(
1420 : simplified()->LoadField(AccessBuilder::ForFixedArraySlot(index)), array,
1421 1218 : effect, control);
1422 :
1423 : Node* value = effect =
1424 : graph()->NewNode(simplified()->LoadField(AccessBuilder::ForCellValue()),
1425 1218 : cell, effect, control);
1426 :
1427 406 : ReplaceWithValue(node, value, effect, control);
1428 406 : return Changed(value);
1429 : }
1430 :
1431 486 : Reduction JSTypedLowering::ReduceJSStoreModule(Node* node) {
1432 : DCHECK_EQ(IrOpcode::kJSStoreModule, node->opcode());
1433 486 : Node* effect = NodeProperties::GetEffectInput(node);
1434 486 : Node* control = NodeProperties::GetControlInput(node);
1435 :
1436 486 : int32_t cell_index = OpParameter<int32_t>(node);
1437 486 : Node* module = NodeProperties::GetValueInput(node, 0);
1438 486 : Node* value = NodeProperties::GetValueInput(node, 1);
1439 :
1440 : Node* array;
1441 : int index;
1442 486 : if (ModuleDescriptor::GetCellIndexKind(cell_index) ==
1443 : ModuleDescriptor::kExport) {
1444 : array = effect = graph()->NewNode(
1445 : simplified()->LoadField(AccessBuilder::ForModuleRegularExports()),
1446 1458 : module, effect, control);
1447 486 : index = cell_index - 1;
1448 : } else {
1449 : DCHECK_EQ(ModuleDescriptor::GetCellIndexKind(cell_index),
1450 : ModuleDescriptor::kImport);
1451 : array = effect = graph()->NewNode(
1452 : simplified()->LoadField(AccessBuilder::ForModuleRegularImports()),
1453 0 : module, effect, control);
1454 0 : index = -cell_index - 1;
1455 : }
1456 :
1457 : Node* cell = effect = graph()->NewNode(
1458 : simplified()->LoadField(AccessBuilder::ForFixedArraySlot(index)), array,
1459 1458 : effect, control);
1460 :
1461 : effect =
1462 : graph()->NewNode(simplified()->StoreField(AccessBuilder::ForCellValue()),
1463 1458 : cell, value, effect, control);
1464 :
1465 486 : ReplaceWithValue(node, effect, effect, control);
1466 486 : return Changed(value);
1467 : }
1468 :
1469 151993 : Reduction JSTypedLowering::ReduceJSConvertReceiver(Node* node) {
1470 : DCHECK_EQ(IrOpcode::kJSConvertReceiver, node->opcode());
1471 119027 : ConvertReceiverMode mode = ConvertReceiverModeOf(node->op());
1472 119027 : Node* receiver = NodeProperties::GetValueInput(node, 0);
1473 : Type* receiver_type = NodeProperties::GetType(receiver);
1474 119027 : Node* context = NodeProperties::GetContextInput(node);
1475 : Type* context_type = NodeProperties::GetType(context);
1476 119027 : Node* effect = NodeProperties::GetEffectInput(node);
1477 119027 : Node* control = NodeProperties::GetControlInput(node);
1478 :
1479 : // Check if {receiver} is known to be a receiver.
1480 119027 : if (receiver_type->Is(Type::Receiver())) {
1481 119027 : ReplaceWithValue(node, receiver, effect, control);
1482 : return Replace(receiver);
1483 : }
1484 :
1485 : // If the {receiver} is known to be null or undefined, we can just replace it
1486 : // with the global proxy unconditionally.
1487 119009 : if (receiver_type->Is(Type::NullOrUndefined()) ||
1488 : mode == ConvertReceiverMode::kNullOrUndefined) {
1489 117276 : if (context_type->IsHeapConstant()) {
1490 : Handle<JSObject> global_proxy(
1491 : Handle<Context>::cast(context_type->AsHeapConstant()->Value())
1492 : ->global_proxy(),
1493 29377 : isolate());
1494 29377 : receiver = jsgraph()->Constant(global_proxy);
1495 : } else {
1496 : Node* native_context = effect = graph()->NewNode(
1497 : javascript()->LoadContext(0, Context::NATIVE_CONTEXT_INDEX, true),
1498 87899 : context, effect);
1499 : receiver = effect = graph()->NewNode(
1500 : javascript()->LoadContext(0, Context::GLOBAL_PROXY_INDEX, true),
1501 87899 : native_context, effect);
1502 : }
1503 : ReplaceWithValue(node, receiver, effect, control);
1504 : return Replace(receiver);
1505 : }
1506 :
1507 : // If {receiver} cannot be null or undefined we can skip a few checks.
1508 1733 : if (!receiver_type->Maybe(Type::NullOrUndefined()) ||
1509 : mode == ConvertReceiverMode::kNotNullOrUndefined) {
1510 1684 : Node* check = graph()->NewNode(simplified()->ObjectIsReceiver(), receiver);
1511 : Node* branch =
1512 1684 : graph()->NewNode(common()->Branch(BranchHint::kTrue), check, control);
1513 :
1514 1684 : Node* if_true = graph()->NewNode(common()->IfTrue(), branch);
1515 : Node* etrue = effect;
1516 : Node* rtrue = receiver;
1517 :
1518 1684 : Node* if_false = graph()->NewNode(common()->IfFalse(), branch);
1519 : Node* efalse = effect;
1520 : Node* rfalse;
1521 : {
1522 : // Convert {receiver} using the ToObjectStub. The call does not require a
1523 : // frame-state in this case, because neither null nor undefined is passed.
1524 1684 : Callable callable = CodeFactory::ToObject(isolate());
1525 : CallDescriptor const* const desc = Linkage::GetStubCallDescriptor(
1526 : isolate(), graph()->zone(), callable.descriptor(), 0,
1527 5052 : CallDescriptor::kNoFlags, node->op()->properties());
1528 : rfalse = efalse = graph()->NewNode(
1529 : common()->Call(desc), jsgraph()->HeapConstant(callable.code()),
1530 5052 : receiver, context, efalse);
1531 : }
1532 :
1533 1684 : control = graph()->NewNode(common()->Merge(2), if_true, if_false);
1534 1684 : effect = graph()->NewNode(common()->EffectPhi(2), etrue, efalse, control);
1535 :
1536 : // Morph the {node} into an appropriate Phi.
1537 : ReplaceWithValue(node, node, effect, control);
1538 1684 : node->ReplaceInput(0, rtrue);
1539 1684 : node->ReplaceInput(1, rfalse);
1540 1684 : node->ReplaceInput(2, control);
1541 1684 : node->TrimInputCount(3);
1542 : NodeProperties::ChangeOp(node,
1543 1684 : common()->Phi(MachineRepresentation::kTagged, 2));
1544 : return Changed(node);
1545 : }
1546 :
1547 : // Check if {receiver} is already a JSReceiver.
1548 49 : Node* check0 = graph()->NewNode(simplified()->ObjectIsReceiver(), receiver);
1549 : Node* branch0 =
1550 49 : graph()->NewNode(common()->Branch(BranchHint::kTrue), check0, control);
1551 49 : Node* if_true0 = graph()->NewNode(common()->IfTrue(), branch0);
1552 49 : Node* if_false0 = graph()->NewNode(common()->IfFalse(), branch0);
1553 :
1554 : // Check {receiver} for undefined.
1555 : Node* check1 = graph()->NewNode(simplified()->ReferenceEqual(), receiver,
1556 98 : jsgraph()->UndefinedConstant());
1557 : Node* branch1 =
1558 49 : graph()->NewNode(common()->Branch(BranchHint::kFalse), check1, if_false0);
1559 49 : Node* if_true1 = graph()->NewNode(common()->IfTrue(), branch1);
1560 49 : Node* if_false1 = graph()->NewNode(common()->IfFalse(), branch1);
1561 :
1562 : // Check {receiver} for null.
1563 : Node* check2 = graph()->NewNode(simplified()->ReferenceEqual(), receiver,
1564 98 : jsgraph()->NullConstant());
1565 : Node* branch2 =
1566 49 : graph()->NewNode(common()->Branch(BranchHint::kFalse), check2, if_false1);
1567 49 : Node* if_true2 = graph()->NewNode(common()->IfTrue(), branch2);
1568 49 : Node* if_false2 = graph()->NewNode(common()->IfFalse(), branch2);
1569 :
1570 : // We just use {receiver} directly.
1571 : Node* if_noop = if_true0;
1572 : Node* enoop = effect;
1573 : Node* rnoop = receiver;
1574 :
1575 : // Convert {receiver} using ToObject.
1576 : Node* if_convert = if_false2;
1577 : Node* econvert = effect;
1578 : Node* rconvert;
1579 : {
1580 : // Convert {receiver} using the ToObjectStub. The call does not require a
1581 : // frame-state in this case, because neither null nor undefined is passed.
1582 49 : Callable callable = CodeFactory::ToObject(isolate());
1583 : CallDescriptor const* const desc = Linkage::GetStubCallDescriptor(
1584 : isolate(), graph()->zone(), callable.descriptor(), 0,
1585 147 : CallDescriptor::kNoFlags, node->op()->properties());
1586 : rconvert = econvert = graph()->NewNode(
1587 : common()->Call(desc), jsgraph()->HeapConstant(callable.code()),
1588 147 : receiver, context, econvert);
1589 : }
1590 :
1591 : // Replace {receiver} with global proxy of {context}.
1592 49 : Node* if_global = graph()->NewNode(common()->Merge(2), if_true1, if_true2);
1593 : Node* eglobal = effect;
1594 : Node* rglobal;
1595 : {
1596 49 : if (context_type->IsHeapConstant()) {
1597 : Handle<JSObject> global_proxy(
1598 : Handle<Context>::cast(context_type->AsHeapConstant()->Value())
1599 : ->global_proxy(),
1600 25 : isolate());
1601 25 : rglobal = jsgraph()->Constant(global_proxy);
1602 : } else {
1603 : Node* native_context = eglobal = graph()->NewNode(
1604 : javascript()->LoadContext(0, Context::NATIVE_CONTEXT_INDEX, true),
1605 24 : context, eglobal);
1606 : rglobal = eglobal = graph()->NewNode(
1607 : javascript()->LoadContext(0, Context::GLOBAL_PROXY_INDEX, true),
1608 24 : native_context, eglobal);
1609 : }
1610 : }
1611 :
1612 : control =
1613 49 : graph()->NewNode(common()->Merge(3), if_noop, if_convert, if_global);
1614 : effect = graph()->NewNode(common()->EffectPhi(3), enoop, econvert, eglobal,
1615 49 : control);
1616 : // Morph the {node} into an appropriate Phi.
1617 : ReplaceWithValue(node, node, effect, control);
1618 49 : node->ReplaceInput(0, rnoop);
1619 49 : node->ReplaceInput(1, rconvert);
1620 49 : node->ReplaceInput(2, rglobal);
1621 49 : node->ReplaceInput(3, control);
1622 49 : node->TrimInputCount(4);
1623 : NodeProperties::ChangeOp(node,
1624 49 : common()->Phi(MachineRepresentation::kTagged, 3));
1625 : return Changed(node);
1626 : }
1627 :
1628 : namespace {
1629 :
1630 35292 : void ReduceBuiltin(Isolate* isolate, JSGraph* jsgraph, Node* node,
1631 : int builtin_index, int arity, CallDescriptor::Flags flags) {
1632 : // Patch {node} to a direct CEntryStub call.
1633 : //
1634 : // ----------- A r g u m e n t s -----------
1635 : // -- 0: CEntryStub
1636 : // --- Stack args ---
1637 : // -- 1: receiver
1638 : // -- [2, 2 + n[: the n actual arguments passed to the builtin
1639 : // -- 2 + n: argc, including the receiver and implicit args (Smi)
1640 : // -- 2 + n + 1: target
1641 : // -- 2 + n + 2: new_target
1642 : // --- Register args ---
1643 : // -- 2 + n + 3: the C entry point
1644 : // -- 2 + n + 4: argc (Int32)
1645 : // -----------------------------------
1646 :
1647 : // The logic contained here is mirrored in Builtins::Generate_Adaptor.
1648 : // Keep these in sync.
1649 :
1650 11764 : const bool is_construct = (node->opcode() == IrOpcode::kJSConstruct);
1651 :
1652 : DCHECK(Builtins::HasCppImplementation(builtin_index));
1653 : DCHECK_EQ(0, flags & CallDescriptor::kSupportsTailCalls);
1654 :
1655 11764 : Node* target = NodeProperties::GetValueInput(node, 0);
1656 : Node* new_target = is_construct
1657 2758 : ? NodeProperties::GetValueInput(node, arity + 1)
1658 14522 : : jsgraph->UndefinedConstant();
1659 :
1660 : // API and CPP builtins are implemented in C++, and we can inline both.
1661 : // CPP builtins create a builtin exit frame, API builtins don't.
1662 11764 : const bool has_builtin_exit_frame = Builtins::IsCpp(builtin_index);
1663 :
1664 : Node* stub = jsgraph->CEntryStubConstant(1, kDontSaveFPRegs, kArgvOnStack,
1665 11764 : has_builtin_exit_frame);
1666 11764 : node->ReplaceInput(0, stub);
1667 :
1668 : Zone* zone = jsgraph->zone();
1669 11764 : if (is_construct) {
1670 : // Unify representations between construct and call nodes.
1671 : // Remove new target and add receiver as a stack parameter.
1672 2758 : Node* receiver = jsgraph->UndefinedConstant();
1673 2758 : node->RemoveInput(arity + 1);
1674 2758 : node->InsertInput(zone, 1, receiver);
1675 : }
1676 :
1677 11764 : const int argc = arity + BuiltinArguments::kNumExtraArgsWithReceiver;
1678 11764 : Node* argc_node = jsgraph->Constant(argc);
1679 :
1680 : static const int kStubAndReceiver = 2;
1681 11764 : int cursor = arity + kStubAndReceiver;
1682 11764 : node->InsertInput(zone, cursor++, argc_node);
1683 11764 : node->InsertInput(zone, cursor++, target);
1684 11764 : node->InsertInput(zone, cursor++, new_target);
1685 :
1686 11764 : Address entry = Builtins::CppEntryOf(builtin_index);
1687 11764 : ExternalReference entry_ref(ExternalReference(entry, isolate));
1688 11764 : Node* entry_node = jsgraph->ExternalConstant(entry_ref);
1689 :
1690 11764 : node->InsertInput(zone, cursor++, entry_node);
1691 11764 : node->InsertInput(zone, cursor++, argc_node);
1692 :
1693 : static const int kReturnCount = 1;
1694 11764 : const char* debug_name = Builtins::name(builtin_index);
1695 11764 : Operator::Properties properties = node->op()->properties();
1696 : CallDescriptor* desc = Linkage::GetCEntryStubCallDescriptor(
1697 11764 : zone, kReturnCount, argc, debug_name, properties, flags);
1698 :
1699 11764 : NodeProperties::ChangeOp(node, jsgraph->common()->Call(desc));
1700 11764 : }
1701 :
1702 : bool NeedsArgumentAdaptorFrame(Handle<SharedFunctionInfo> shared, int arity) {
1703 : static const int sentinel = SharedFunctionInfo::kDontAdaptArgumentsSentinel;
1704 : const int num_decl_parms = shared->internal_formal_parameter_count();
1705 173520 : return (num_decl_parms != arity && num_decl_parms != sentinel);
1706 : }
1707 :
1708 : } // namespace
1709 :
1710 107843 : Reduction JSTypedLowering::ReduceJSConstruct(Node* node) {
1711 : DCHECK_EQ(IrOpcode::kJSConstruct, node->opcode());
1712 28689 : ConstructParameters const& p = ConstructParametersOf(node->op());
1713 : DCHECK_LE(2u, p.arity());
1714 28689 : int const arity = static_cast<int>(p.arity() - 2);
1715 28689 : Node* target = NodeProperties::GetValueInput(node, 0);
1716 : Type* target_type = NodeProperties::GetType(target);
1717 28689 : Node* new_target = NodeProperties::GetValueInput(node, arity + 1);
1718 28689 : Node* effect = NodeProperties::GetEffectInput(node);
1719 28689 : Node* control = NodeProperties::GetControlInput(node);
1720 :
1721 : // Check if {target} is a known JSFunction.
1722 50066 : if (target_type->IsHeapConstant() &&
1723 : target_type->AsHeapConstant()->Value()->IsJSFunction()) {
1724 : Handle<JSFunction> function =
1725 : Handle<JSFunction>::cast(target_type->AsHeapConstant()->Value());
1726 : Handle<SharedFunctionInfo> shared(function->shared(), isolate());
1727 : const int builtin_index = shared->construct_stub()->builtin_index();
1728 : const bool is_builtin = (builtin_index != -1);
1729 :
1730 : CallDescriptor::Flags flags = CallDescriptor::kNeedsFrameState;
1731 :
1732 24123 : if (is_builtin && Builtins::HasCppImplementation(builtin_index) &&
1733 : !NeedsArgumentAdaptorFrame(shared, arity)) {
1734 : // Patch {node} to a direct CEntryStub call.
1735 :
1736 : // Load the context from the {target}.
1737 : Node* context = effect = graph()->NewNode(
1738 : simplified()->LoadField(AccessBuilder::ForJSFunctionContext()),
1739 8274 : target, effect, control);
1740 2758 : NodeProperties::ReplaceContextInput(node, context);
1741 :
1742 : // Update the effect dependency for the {node}.
1743 2758 : NodeProperties::ReplaceEffectInput(node, effect);
1744 :
1745 2758 : ReduceBuiltin(isolate(), jsgraph(), node, builtin_index, arity, flags);
1746 : } else {
1747 : // Patch {node} to an indirect call via the {function}s construct stub.
1748 : Callable callable(handle(shared->construct_stub(), isolate()),
1749 37214 : ConstructStubDescriptor(isolate()));
1750 18607 : node->RemoveInput(arity + 1);
1751 : node->InsertInput(graph()->zone(), 0,
1752 37214 : jsgraph()->HeapConstant(callable.code()));
1753 18607 : node->InsertInput(graph()->zone(), 2, new_target);
1754 37214 : node->InsertInput(graph()->zone(), 3, jsgraph()->Constant(arity));
1755 37214 : node->InsertInput(graph()->zone(), 4, jsgraph()->UndefinedConstant());
1756 37214 : node->InsertInput(graph()->zone(), 5, jsgraph()->UndefinedConstant());
1757 : NodeProperties::ChangeOp(
1758 : node, common()->Call(Linkage::GetStubCallDescriptor(
1759 : isolate(), graph()->zone(), callable.descriptor(),
1760 55821 : 1 + arity, flags)));
1761 : }
1762 : return Changed(node);
1763 : }
1764 :
1765 : // Check if {target} is a JSFunction.
1766 7324 : if (target_type->Is(Type::Function())) {
1767 : // Patch {node} to an indirect call via the ConstructFunction builtin.
1768 656 : Callable callable = CodeFactory::ConstructFunction(isolate());
1769 656 : node->RemoveInput(arity + 1);
1770 : node->InsertInput(graph()->zone(), 0,
1771 1312 : jsgraph()->HeapConstant(callable.code()));
1772 656 : node->InsertInput(graph()->zone(), 2, new_target);
1773 1312 : node->InsertInput(graph()->zone(), 3, jsgraph()->Constant(arity));
1774 1312 : node->InsertInput(graph()->zone(), 4, jsgraph()->UndefinedConstant());
1775 : NodeProperties::ChangeOp(
1776 : node, common()->Call(Linkage::GetStubCallDescriptor(
1777 : isolate(), graph()->zone(), callable.descriptor(), 1 + arity,
1778 1968 : CallDescriptor::kNeedsFrameState)));
1779 : return Changed(node);
1780 : }
1781 :
1782 : return NoChange();
1783 : }
1784 :
1785 611 : Reduction JSTypedLowering::ReduceJSCallForwardVarargs(Node* node) {
1786 : DCHECK_EQ(IrOpcode::kJSCallForwardVarargs, node->opcode());
1787 215 : CallForwardVarargsParameters p = CallForwardVarargsParametersOf(node->op());
1788 215 : Node* target = NodeProperties::GetValueInput(node, 0);
1789 : Type* target_type = NodeProperties::GetType(target);
1790 :
1791 : // Check if {target} is a JSFunction.
1792 215 : if (target_type->Is(Type::Function())) {
1793 : // Compute flags for the call.
1794 : CallDescriptor::Flags flags = CallDescriptor::kNeedsFrameState;
1795 198 : if (p.tail_call_mode() == TailCallMode::kAllow) {
1796 : flags |= CallDescriptor::kSupportsTailCalls;
1797 : }
1798 :
1799 : // Patch {node} to an indirect call via CallFunctionForwardVarargs.
1800 198 : Callable callable = CodeFactory::CallFunctionForwardVarargs(isolate());
1801 : node->InsertInput(graph()->zone(), 0,
1802 396 : jsgraph()->HeapConstant(callable.code()));
1803 396 : node->InsertInput(graph()->zone(), 2, jsgraph()->Constant(p.start_index()));
1804 : NodeProperties::ChangeOp(
1805 : node,
1806 : common()->Call(Linkage::GetStubCallDescriptor(
1807 594 : isolate(), graph()->zone(), callable.descriptor(), 1, flags)));
1808 : return Changed(node);
1809 : }
1810 :
1811 : return NoChange();
1812 : }
1813 :
1814 644717 : Reduction JSTypedLowering::ReduceJSCall(Node* node) {
1815 : DCHECK_EQ(IrOpcode::kJSCall, node->opcode());
1816 378656 : CallParameters const& p = CallParametersOf(node->op());
1817 188937 : int const arity = static_cast<int>(p.arity() - 2);
1818 : ConvertReceiverMode convert_mode = p.convert_mode();
1819 188937 : Node* target = NodeProperties::GetValueInput(node, 0);
1820 : Type* target_type = NodeProperties::GetType(target);
1821 188937 : Node* receiver = NodeProperties::GetValueInput(node, 1);
1822 : Type* receiver_type = NodeProperties::GetType(receiver);
1823 188937 : Node* effect = NodeProperties::GetEffectInput(node);
1824 188937 : Node* control = NodeProperties::GetControlInput(node);
1825 :
1826 : // Try to infer receiver {convert_mode} from {receiver} type.
1827 188937 : if (receiver_type->Is(Type::NullOrUndefined())) {
1828 : convert_mode = ConvertReceiverMode::kNullOrUndefined;
1829 49343 : } else if (!receiver_type->Maybe(Type::NullOrUndefined())) {
1830 : convert_mode = ConvertReceiverMode::kNotNullOrUndefined;
1831 : }
1832 :
1833 : // Check if {target} is a known JSFunction.
1834 359824 : if (target_type->IsHeapConstant() &&
1835 : target_type->AsHeapConstant()->Value()->IsJSFunction()) {
1836 : Handle<JSFunction> function =
1837 : Handle<JSFunction>::cast(target_type->AsHeapConstant()->Value());
1838 : Handle<SharedFunctionInfo> shared(function->shared(), isolate());
1839 : const int builtin_index = shared->code()->builtin_index();
1840 : const bool is_builtin = (builtin_index != -1);
1841 :
1842 : // Class constructors are callable, but [[Call]] will raise an exception.
1843 : // See ES6 section 9.2.1 [[Call]] ( thisArgument, argumentsList ).
1844 170776 : if (IsClassConstructor(shared->kind())) return NoChange();
1845 :
1846 : // Load the context from the {target}.
1847 : Node* context = effect = graph()->NewNode(
1848 : simplified()->LoadField(AccessBuilder::ForJSFunctionContext()), target,
1849 512286 : effect, control);
1850 170762 : NodeProperties::ReplaceContextInput(node, context);
1851 :
1852 : // Check if we need to convert the {receiver}.
1853 405965 : if (is_sloppy(shared->language_mode()) && !shared->native() &&
1854 : !receiver_type->Is(Type::Receiver())) {
1855 : receiver = effect =
1856 : graph()->NewNode(javascript()->ConvertReceiver(convert_mode),
1857 89197 : receiver, context, effect, control);
1858 89197 : NodeProperties::ReplaceValueInput(node, receiver, 1);
1859 : }
1860 :
1861 : // Update the effect dependency for the {node}.
1862 170762 : NodeProperties::ReplaceEffectInput(node, effect);
1863 :
1864 : // Compute flags for the call.
1865 : CallDescriptor::Flags flags = CallDescriptor::kNeedsFrameState;
1866 170762 : if (p.tail_call_mode() == TailCallMode::kAllow) {
1867 : flags |= CallDescriptor::kSupportsTailCalls;
1868 : }
1869 :
1870 170762 : Node* new_target = jsgraph()->UndefinedConstant();
1871 170762 : Node* argument_count = jsgraph()->Constant(arity);
1872 170762 : if (NeedsArgumentAdaptorFrame(shared, arity)) {
1873 : // Patch {node} to an indirect call via the ArgumentsAdaptorTrampoline.
1874 51548 : Callable callable = CodeFactory::ArgumentAdaptor(isolate());
1875 : node->InsertInput(graph()->zone(), 0,
1876 103096 : jsgraph()->HeapConstant(callable.code()));
1877 51548 : node->InsertInput(graph()->zone(), 2, new_target);
1878 51548 : node->InsertInput(graph()->zone(), 3, argument_count);
1879 : node->InsertInput(
1880 : graph()->zone(), 4,
1881 103096 : jsgraph()->Constant(shared->internal_formal_parameter_count()));
1882 : NodeProperties::ChangeOp(
1883 : node, common()->Call(Linkage::GetStubCallDescriptor(
1884 : isolate(), graph()->zone(), callable.descriptor(),
1885 206192 : 1 + arity, flags)));
1886 128233 : } else if (is_builtin && Builtins::HasCppImplementation(builtin_index) &&
1887 : ((flags & CallDescriptor::kSupportsTailCalls) == 0)) {
1888 : // Patch {node} to a direct CEntryStub call.
1889 9006 : ReduceBuiltin(isolate(), jsgraph(), node, builtin_index, arity, flags);
1890 : } else {
1891 : // Patch {node} to a direct call.
1892 220416 : node->InsertInput(graph()->zone(), arity + 2, new_target);
1893 220416 : node->InsertInput(graph()->zone(), arity + 3, argument_count);
1894 : NodeProperties::ChangeOp(node,
1895 : common()->Call(Linkage::GetJSCallDescriptor(
1896 330624 : graph()->zone(), false, 1 + arity, flags)));
1897 : }
1898 : return Changed(node);
1899 : }
1900 :
1901 : // Check if {target} is a JSFunction.
1902 18161 : if (target_type->Is(Type::Function())) {
1903 : // Compute flags for the call.
1904 : CallDescriptor::Flags flags = CallDescriptor::kNeedsFrameState;
1905 1077 : if (p.tail_call_mode() == TailCallMode::kAllow) {
1906 : flags |= CallDescriptor::kSupportsTailCalls;
1907 : }
1908 :
1909 : // Patch {node} to an indirect call via the CallFunction builtin.
1910 1077 : Callable callable = CodeFactory::CallFunction(isolate(), convert_mode);
1911 : node->InsertInput(graph()->zone(), 0,
1912 2154 : jsgraph()->HeapConstant(callable.code()));
1913 2154 : node->InsertInput(graph()->zone(), 2, jsgraph()->Constant(arity));
1914 : NodeProperties::ChangeOp(
1915 : node, common()->Call(Linkage::GetStubCallDescriptor(
1916 : isolate(), graph()->zone(), callable.descriptor(), 1 + arity,
1917 4308 : flags)));
1918 : return Changed(node);
1919 : }
1920 :
1921 : // Maybe we did at least learn something about the {receiver}.
1922 17084 : if (p.convert_mode() != convert_mode) {
1923 : NodeProperties::ChangeOp(
1924 : node,
1925 796 : javascript()->Call(p.arity(), p.frequency(), p.feedback(), convert_mode,
1926 796 : p.tail_call_mode()));
1927 : return Changed(node);
1928 : }
1929 :
1930 : return NoChange();
1931 : }
1932 :
1933 :
1934 2944 : Reduction JSTypedLowering::ReduceJSForInNext(Node* node) {
1935 : DCHECK_EQ(IrOpcode::kJSForInNext, node->opcode());
1936 1472 : Node* receiver = NodeProperties::GetValueInput(node, 0);
1937 1472 : Node* cache_array = NodeProperties::GetValueInput(node, 1);
1938 1472 : Node* cache_type = NodeProperties::GetValueInput(node, 2);
1939 1472 : Node* index = NodeProperties::GetValueInput(node, 3);
1940 1472 : Node* context = NodeProperties::GetContextInput(node);
1941 1472 : Node* frame_state = NodeProperties::GetFrameStateInput(node);
1942 1472 : Node* effect = NodeProperties::GetEffectInput(node);
1943 1472 : Node* control = NodeProperties::GetControlInput(node);
1944 :
1945 : // We know that the {index} is in Unsigned32 range here, otherwise executing
1946 : // the JSForInNext wouldn't be valid. Unfortunately due to OSR and generators
1947 : // this is not always reflected in the types, hence we might need to rename
1948 : // the {index} here.
1949 1472 : if (!NodeProperties::GetType(index)->Is(Type::Unsigned32())) {
1950 : index = graph()->NewNode(common()->TypeGuard(Type::Unsigned32()), index,
1951 209 : control);
1952 : }
1953 :
1954 : // Load the next {key} from the {cache_array}.
1955 : Node* key = effect = graph()->NewNode(
1956 : simplified()->LoadElement(AccessBuilder::ForFixedArrayElement()),
1957 4416 : cache_array, index, effect, control);
1958 :
1959 : // Load the map of the {receiver}.
1960 : Node* receiver_map = effect =
1961 : graph()->NewNode(simplified()->LoadField(AccessBuilder::ForMap()),
1962 4416 : receiver, effect, control);
1963 :
1964 : // Check if the expected map still matches that of the {receiver}.
1965 : Node* check0 = graph()->NewNode(simplified()->ReferenceEqual(), receiver_map,
1966 1472 : cache_type);
1967 : Node* branch0 =
1968 1472 : graph()->NewNode(common()->Branch(BranchHint::kTrue), check0, control);
1969 :
1970 1472 : Node* if_true0 = graph()->NewNode(common()->IfTrue(), branch0);
1971 : Node* etrue0;
1972 : Node* vtrue0;
1973 : {
1974 : // Don't need filtering since expected map still matches that of the
1975 : // {receiver}.
1976 : etrue0 = effect;
1977 : vtrue0 = key;
1978 : }
1979 :
1980 1472 : Node* if_false0 = graph()->NewNode(common()->IfFalse(), branch0);
1981 : Node* efalse0;
1982 : Node* vfalse0;
1983 : {
1984 : // Filter the {key} to check if it's still a valid property of the
1985 : // {receiver} (does the ToName conversion implicitly).
1986 1472 : Callable const callable = CodeFactory::ForInFilter(isolate());
1987 : CallDescriptor const* const desc = Linkage::GetStubCallDescriptor(
1988 : isolate(), graph()->zone(), callable.descriptor(), 0,
1989 4416 : CallDescriptor::kNeedsFrameState);
1990 : vfalse0 = efalse0 = if_false0 = graph()->NewNode(
1991 : common()->Call(desc), jsgraph()->HeapConstant(callable.code()), key,
1992 4416 : receiver, context, frame_state, effect, if_false0);
1993 :
1994 : // Update potential {IfException} uses of {node} to point to the ahove
1995 : // ForInFilter stub call node instead.
1996 1472 : Node* if_exception = nullptr;
1997 1472 : if (NodeProperties::IsExceptionalCall(node, &if_exception)) {
1998 59 : if_false0 = graph()->NewNode(common()->IfSuccess(), vfalse0);
1999 59 : NodeProperties::ReplaceControlInput(if_exception, vfalse0);
2000 59 : NodeProperties::ReplaceEffectInput(if_exception, efalse0);
2001 1531 : Revisit(if_exception);
2002 : }
2003 : }
2004 :
2005 1472 : control = graph()->NewNode(common()->Merge(2), if_true0, if_false0);
2006 1472 : effect = graph()->NewNode(common()->EffectPhi(2), etrue0, efalse0, control);
2007 : ReplaceWithValue(node, node, effect, control);
2008 :
2009 : // Morph the {node} into a Phi.
2010 1472 : node->ReplaceInput(0, vtrue0);
2011 1472 : node->ReplaceInput(1, vfalse0);
2012 1472 : node->ReplaceInput(2, control);
2013 1472 : node->TrimInputCount(3);
2014 : NodeProperties::ChangeOp(node,
2015 1472 : common()->Phi(MachineRepresentation::kTagged, 2));
2016 1472 : return Changed(node);
2017 : }
2018 :
2019 78952 : Reduction JSTypedLowering::ReduceJSLoadMessage(Node* node) {
2020 : DCHECK_EQ(IrOpcode::kJSLoadMessage, node->opcode());
2021 : ExternalReference const ref =
2022 39476 : ExternalReference::address_of_pending_message_obj(isolate());
2023 39476 : node->ReplaceInput(0, jsgraph()->ExternalConstant(ref));
2024 : NodeProperties::ChangeOp(
2025 78952 : node, simplified()->LoadField(AccessBuilder::ForExternalTaggedValue()));
2026 39476 : return Changed(node);
2027 : }
2028 :
2029 78952 : Reduction JSTypedLowering::ReduceJSStoreMessage(Node* node) {
2030 : DCHECK_EQ(IrOpcode::kJSStoreMessage, node->opcode());
2031 : ExternalReference const ref =
2032 39476 : ExternalReference::address_of_pending_message_obj(isolate());
2033 39476 : Node* value = NodeProperties::GetValueInput(node, 0);
2034 39476 : node->ReplaceInput(0, jsgraph()->ExternalConstant(ref));
2035 39476 : node->ReplaceInput(1, value);
2036 : NodeProperties::ChangeOp(
2037 78952 : node, simplified()->StoreField(AccessBuilder::ForExternalTaggedValue()));
2038 39476 : return Changed(node);
2039 : }
2040 :
2041 12858 : Reduction JSTypedLowering::ReduceJSGeneratorStore(Node* node) {
2042 : DCHECK_EQ(IrOpcode::kJSGeneratorStore, node->opcode());
2043 6429 : Node* generator = NodeProperties::GetValueInput(node, 0);
2044 6429 : Node* continuation = NodeProperties::GetValueInput(node, 1);
2045 6429 : Node* offset = NodeProperties::GetValueInput(node, 2);
2046 6429 : Node* context = NodeProperties::GetContextInput(node);
2047 6429 : Node* effect = NodeProperties::GetEffectInput(node);
2048 6429 : Node* control = NodeProperties::GetControlInput(node);
2049 108447 : const GeneratorStoreParameters& p = GeneratorStoreParametersOf(node->op());
2050 :
2051 6429 : FieldAccess array_field = AccessBuilder::ForJSGeneratorObjectRegisterFile();
2052 6429 : FieldAccess context_field = AccessBuilder::ForJSGeneratorObjectContext();
2053 : FieldAccess continuation_field =
2054 6429 : AccessBuilder::ForJSGeneratorObjectContinuation();
2055 : FieldAccess input_or_debug_pos_field =
2056 : p.suspend_flags() == SuspendFlags::kAsyncGeneratorAwait
2057 : ? AccessBuilder::ForJSAsyncGeneratorObjectAwaitInputOrDebugPos()
2058 6429 : : AccessBuilder::ForJSGeneratorObjectInputOrDebugPos();
2059 :
2060 : Node* array = effect = graph()->NewNode(simplified()->LoadField(array_field),
2061 6429 : generator, effect, control);
2062 :
2063 191178 : for (int i = 0; i < p.register_count(); ++i) {
2064 89160 : Node* value = NodeProperties::GetValueInput(node, 3 + i);
2065 : effect = graph()->NewNode(
2066 : simplified()->StoreField(AccessBuilder::ForFixedArraySlot(i)), array,
2067 267480 : value, effect, control);
2068 : }
2069 :
2070 : effect = graph()->NewNode(simplified()->StoreField(context_field), generator,
2071 6429 : context, effect, control);
2072 : effect = graph()->NewNode(simplified()->StoreField(continuation_field),
2073 6429 : generator, continuation, effect, control);
2074 : effect = graph()->NewNode(simplified()->StoreField(input_or_debug_pos_field),
2075 6429 : generator, offset, effect, control);
2076 :
2077 6429 : ReplaceWithValue(node, effect, effect, control);
2078 6429 : return Changed(effect);
2079 : }
2080 :
2081 4446 : Reduction JSTypedLowering::ReduceJSGeneratorRestoreContinuation(Node* node) {
2082 : DCHECK_EQ(IrOpcode::kJSGeneratorRestoreContinuation, node->opcode());
2083 2223 : Node* generator = NodeProperties::GetValueInput(node, 0);
2084 2223 : Node* effect = NodeProperties::GetEffectInput(node);
2085 2223 : Node* control = NodeProperties::GetControlInput(node);
2086 :
2087 : FieldAccess continuation_field =
2088 2223 : AccessBuilder::ForJSGeneratorObjectContinuation();
2089 :
2090 : Node* continuation = effect = graph()->NewNode(
2091 2223 : simplified()->LoadField(continuation_field), generator, effect, control);
2092 2223 : Node* executing = jsgraph()->Constant(JSGeneratorObject::kGeneratorExecuting);
2093 : effect = graph()->NewNode(simplified()->StoreField(continuation_field),
2094 2223 : generator, executing, effect, control);
2095 :
2096 2223 : ReplaceWithValue(node, continuation, effect, control);
2097 2223 : return Changed(continuation);
2098 : }
2099 :
2100 60138 : Reduction JSTypedLowering::ReduceJSGeneratorRestoreRegister(Node* node) {
2101 : DCHECK_EQ(IrOpcode::kJSGeneratorRestoreRegister, node->opcode());
2102 30069 : Node* generator = NodeProperties::GetValueInput(node, 0);
2103 30069 : Node* effect = NodeProperties::GetEffectInput(node);
2104 30069 : Node* control = NodeProperties::GetControlInput(node);
2105 30069 : int index = OpParameter<int>(node);
2106 :
2107 30069 : FieldAccess array_field = AccessBuilder::ForJSGeneratorObjectRegisterFile();
2108 30069 : FieldAccess element_field = AccessBuilder::ForFixedArraySlot(index);
2109 :
2110 : Node* array = effect = graph()->NewNode(simplified()->LoadField(array_field),
2111 30069 : generator, effect, control);
2112 : Node* element = effect = graph()->NewNode(
2113 30069 : simplified()->LoadField(element_field), array, effect, control);
2114 30069 : Node* stale = jsgraph()->StaleRegisterConstant();
2115 : effect = graph()->NewNode(simplified()->StoreField(element_field), array,
2116 30069 : stale, effect, control);
2117 :
2118 30069 : ReplaceWithValue(node, element, effect, control);
2119 30069 : return Changed(element);
2120 : }
2121 :
2122 30175065 : Reduction JSTypedLowering::Reduce(Node* node) {
2123 30175065 : switch (node->opcode()) {
2124 : case IrOpcode::kJSEqual:
2125 18233 : return ReduceJSEqual(node);
2126 : case IrOpcode::kJSStrictEqual:
2127 241331 : return ReduceJSStrictEqual(node);
2128 : case IrOpcode::kJSLessThan: // fall through
2129 : case IrOpcode::kJSGreaterThan: // fall through
2130 : case IrOpcode::kJSLessThanOrEqual: // fall through
2131 : case IrOpcode::kJSGreaterThanOrEqual:
2132 38228 : return ReduceJSComparison(node);
2133 : case IrOpcode::kJSBitwiseOr:
2134 : case IrOpcode::kJSBitwiseXor:
2135 : case IrOpcode::kJSBitwiseAnd:
2136 44899 : return ReduceInt32Binop(node);
2137 : case IrOpcode::kJSShiftLeft:
2138 : case IrOpcode::kJSShiftRight:
2139 21706 : return ReduceUI32Shift(node, kSigned);
2140 : case IrOpcode::kJSShiftRightLogical:
2141 8837 : return ReduceUI32Shift(node, kUnsigned);
2142 : case IrOpcode::kJSAdd:
2143 120613 : return ReduceJSAdd(node);
2144 : case IrOpcode::kJSSubtract:
2145 : case IrOpcode::kJSMultiply:
2146 : case IrOpcode::kJSDivide:
2147 : case IrOpcode::kJSModulus:
2148 88140 : return ReduceNumberBinop(node);
2149 : case IrOpcode::kJSOrdinaryHasInstance:
2150 64 : return ReduceJSOrdinaryHasInstance(node);
2151 : case IrOpcode::kJSToBoolean:
2152 112618 : return ReduceJSToBoolean(node);
2153 : case IrOpcode::kJSToInteger:
2154 271 : return ReduceJSToInteger(node);
2155 : case IrOpcode::kJSToLength:
2156 257 : return ReduceJSToLength(node);
2157 : case IrOpcode::kJSToName:
2158 1531 : return ReduceJSToName(node);
2159 : case IrOpcode::kJSToNumber:
2160 6497 : return ReduceJSToNumber(node);
2161 : case IrOpcode::kJSToString:
2162 2380 : return ReduceJSToString(node);
2163 : case IrOpcode::kJSToObject:
2164 2433 : return ReduceJSToObject(node);
2165 : case IrOpcode::kJSTypeOf:
2166 31284 : return ReduceJSTypeOf(node);
2167 : case IrOpcode::kJSLoadNamed:
2168 350959 : return ReduceJSLoadNamed(node);
2169 : case IrOpcode::kJSLoadProperty:
2170 59116 : return ReduceJSLoadProperty(node);
2171 : case IrOpcode::kJSStoreProperty:
2172 33863 : return ReduceJSStoreProperty(node);
2173 : case IrOpcode::kJSLoadContext:
2174 592315 : return ReduceJSLoadContext(node);
2175 : case IrOpcode::kJSStoreContext:
2176 156349 : return ReduceJSStoreContext(node);
2177 : case IrOpcode::kJSLoadModule:
2178 406 : return ReduceJSLoadModule(node);
2179 : case IrOpcode::kJSStoreModule:
2180 486 : return ReduceJSStoreModule(node);
2181 : case IrOpcode::kJSConvertReceiver:
2182 119027 : return ReduceJSConvertReceiver(node);
2183 : case IrOpcode::kJSConstruct:
2184 28689 : return ReduceJSConstruct(node);
2185 : case IrOpcode::kJSCallForwardVarargs:
2186 215 : return ReduceJSCallForwardVarargs(node);
2187 : case IrOpcode::kJSCall:
2188 188937 : return ReduceJSCall(node);
2189 : case IrOpcode::kJSForInNext:
2190 1472 : return ReduceJSForInNext(node);
2191 : case IrOpcode::kJSLoadMessage:
2192 39476 : return ReduceJSLoadMessage(node);
2193 : case IrOpcode::kJSStoreMessage:
2194 39476 : return ReduceJSStoreMessage(node);
2195 : case IrOpcode::kJSGeneratorStore:
2196 6429 : return ReduceJSGeneratorStore(node);
2197 : case IrOpcode::kJSGeneratorRestoreContinuation:
2198 2223 : return ReduceJSGeneratorRestoreContinuation(node);
2199 : case IrOpcode::kJSGeneratorRestoreRegister:
2200 30069 : return ReduceJSGeneratorRestoreRegister(node);
2201 : // TODO(mstarzinger): Simplified operations hiding in JS-level reducer not
2202 : // fooling anyone. Consider moving this into a separate reducer.
2203 : case IrOpcode::kSpeculativeNumberAdd:
2204 155908 : return ReduceSpeculativeNumberAdd(node);
2205 : case IrOpcode::kSpeculativeNumberSubtract:
2206 : case IrOpcode::kSpeculativeNumberMultiply:
2207 : case IrOpcode::kSpeculativeNumberDivide:
2208 : case IrOpcode::kSpeculativeNumberModulus:
2209 72359 : return ReduceSpeculativeNumberBinop(node);
2210 : case IrOpcode::kSpeculativeNumberEqual:
2211 : case IrOpcode::kSpeculativeNumberLessThan:
2212 : case IrOpcode::kSpeculativeNumberLessThanOrEqual:
2213 53880 : return ReduceSpeculativeNumberComparison(node);
2214 : default:
2215 : break;
2216 : }
2217 : return NoChange();
2218 : }
2219 :
2220 :
2221 385644 : Factory* JSTypedLowering::factory() const { return jsgraph()->factory(); }
2222 :
2223 :
2224 4882906 : Graph* JSTypedLowering::graph() const { return jsgraph()->graph(); }
2225 :
2226 :
2227 629301 : Isolate* JSTypedLowering::isolate() const { return jsgraph()->isolate(); }
2228 :
2229 :
2230 268576 : JSOperatorBuilder* JSTypedLowering::javascript() const {
2231 268576 : return jsgraph()->javascript();
2232 : }
2233 :
2234 :
2235 292514 : CommonOperatorBuilder* JSTypedLowering::common() const {
2236 292558 : return jsgraph()->common();
2237 : }
2238 :
2239 1738969 : SimplifiedOperatorBuilder* JSTypedLowering::simplified() const {
2240 1738969 : return jsgraph()->simplified();
2241 : }
2242 :
2243 :
2244 0 : CompilationDependencies* JSTypedLowering::dependencies() const {
2245 3297 : return dependencies_;
2246 : }
2247 :
2248 : } // namespace compiler
2249 : } // namespace internal
2250 : } // namespace v8
|