OLD | NEW |
1 // Copyright 2014 the V8 project authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "src/compiler/js-builtin-reducer.h" | 5 #include "src/compiler/js-builtin-reducer.h" |
| 6 |
| 7 #include "src/compiler/access-builder.h" |
6 #include "src/compiler/js-graph.h" | 8 #include "src/compiler/js-graph.h" |
7 #include "src/compiler/node-matchers.h" | 9 #include "src/compiler/node-matchers.h" |
8 #include "src/compiler/node-properties.h" | 10 #include "src/compiler/node-properties.h" |
9 #include "src/compiler/simplified-operator.h" | 11 #include "src/compiler/simplified-operator.h" |
10 #include "src/objects-inl.h" | 12 #include "src/objects-inl.h" |
11 #include "src/type-cache.h" | 13 #include "src/type-cache.h" |
12 #include "src/types.h" | 14 #include "src/types.h" |
13 | 15 |
14 namespace v8 { | 16 namespace v8 { |
15 namespace internal { | 17 namespace internal { |
(...skipping 17 matching lines...) Expand all Loading... |
33 } | 35 } |
34 | 36 |
35 // Retrieves the BuiltinFunctionId as described above. | 37 // Retrieves the BuiltinFunctionId as described above. |
36 BuiltinFunctionId GetBuiltinFunctionId() { | 38 BuiltinFunctionId GetBuiltinFunctionId() { |
37 DCHECK_EQ(IrOpcode::kJSCallFunction, node_->opcode()); | 39 DCHECK_EQ(IrOpcode::kJSCallFunction, node_->opcode()); |
38 HeapObjectMatcher m(NodeProperties::GetValueInput(node_, 0)); | 40 HeapObjectMatcher m(NodeProperties::GetValueInput(node_, 0)); |
39 Handle<JSFunction> function = Handle<JSFunction>::cast(m.Value()); | 41 Handle<JSFunction> function = Handle<JSFunction>::cast(m.Value()); |
40 return function->shared()->builtin_function_id(); | 42 return function->shared()->builtin_function_id(); |
41 } | 43 } |
42 | 44 |
| 45 bool ReceiverMatches(Type* type) { |
| 46 return NodeProperties::GetType(receiver())->Is(type); |
| 47 } |
| 48 |
43 // Determines whether the call takes zero inputs. | 49 // Determines whether the call takes zero inputs. |
44 bool InputsMatchZero() { return GetJSCallArity() == 0; } | 50 bool InputsMatchZero() { return GetJSCallArity() == 0; } |
45 | 51 |
46 // Determines whether the call takes one input of the given type. | 52 // Determines whether the call takes one input of the given type. |
47 bool InputsMatchOne(Type* t1) { | 53 bool InputsMatchOne(Type* t1) { |
48 return GetJSCallArity() == 1 && | 54 return GetJSCallArity() == 1 && |
49 NodeProperties::GetType(GetJSCallInput(0))->Is(t1); | 55 NodeProperties::GetType(GetJSCallInput(0))->Is(t1); |
50 } | 56 } |
51 | 57 |
52 // Determines whether the call takes two inputs of the given types. | 58 // Determines whether the call takes two inputs of the given types. |
53 bool InputsMatchTwo(Type* t1, Type* t2) { | 59 bool InputsMatchTwo(Type* t1, Type* t2) { |
54 return GetJSCallArity() == 2 && | 60 return GetJSCallArity() == 2 && |
55 NodeProperties::GetType(GetJSCallInput(0))->Is(t1) && | 61 NodeProperties::GetType(GetJSCallInput(0))->Is(t1) && |
56 NodeProperties::GetType(GetJSCallInput(1))->Is(t2); | 62 NodeProperties::GetType(GetJSCallInput(1))->Is(t2); |
57 } | 63 } |
58 | 64 |
59 // Determines whether the call takes inputs all of the given type. | 65 // Determines whether the call takes inputs all of the given type. |
60 bool InputsMatchAll(Type* t) { | 66 bool InputsMatchAll(Type* t) { |
61 for (int i = 0; i < GetJSCallArity(); i++) { | 67 for (int i = 0; i < GetJSCallArity(); i++) { |
62 if (!NodeProperties::GetType(GetJSCallInput(i))->Is(t)) { | 68 if (!NodeProperties::GetType(GetJSCallInput(i))->Is(t)) { |
63 return false; | 69 return false; |
64 } | 70 } |
65 } | 71 } |
66 return true; | 72 return true; |
67 } | 73 } |
68 | 74 |
| 75 Node* receiver() { return NodeProperties::GetValueInput(node_, 1); } |
69 Node* left() { return GetJSCallInput(0); } | 76 Node* left() { return GetJSCallInput(0); } |
70 Node* right() { return GetJSCallInput(1); } | 77 Node* right() { return GetJSCallInput(1); } |
71 | 78 |
72 int GetJSCallArity() { | 79 int GetJSCallArity() { |
73 DCHECK_EQ(IrOpcode::kJSCallFunction, node_->opcode()); | 80 DCHECK_EQ(IrOpcode::kJSCallFunction, node_->opcode()); |
74 // Skip first (i.e. callee) and second (i.e. receiver) operand. | 81 // Skip first (i.e. callee) and second (i.e. receiver) operand. |
75 return node_->op()->ValueInputCount() - 2; | 82 return node_->op()->ValueInputCount() - 2; |
76 } | 83 } |
77 | 84 |
78 Node* GetJSCallInput(int index) { | 85 Node* GetJSCallInput(int index) { |
(...skipping 448 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
527 JSCallReduction r(node); | 534 JSCallReduction r(node); |
528 if (r.InputsMatchOne(Type::PlainPrimitive())) { | 535 if (r.InputsMatchOne(Type::PlainPrimitive())) { |
529 // String.fromCharCode(a:plain-primitive) -> StringFromCharCode(a) | 536 // String.fromCharCode(a:plain-primitive) -> StringFromCharCode(a) |
530 Node* input = ToNumber(r.GetJSCallInput(0)); | 537 Node* input = ToNumber(r.GetJSCallInput(0)); |
531 Node* value = graph()->NewNode(simplified()->StringFromCharCode(), input); | 538 Node* value = graph()->NewNode(simplified()->StringFromCharCode(), input); |
532 return Replace(value); | 539 return Replace(value); |
533 } | 540 } |
534 return NoChange(); | 541 return NoChange(); |
535 } | 542 } |
536 | 543 |
| 544 namespace { |
| 545 |
| 546 Node* GetStringReceiver(Node* node) { |
| 547 Node* receiver = NodeProperties::GetValueInput(node, 1); |
| 548 Type* receiver_type = NodeProperties::GetType(receiver); |
| 549 Node* effect = NodeProperties::GetEffectInput(node); |
| 550 if (receiver_type->Is(Type::String())) return receiver; |
| 551 // Check if the {node} is dominated by a CheckString renaming for |
| 552 // it's {receiver}, and if so use that renaming as {receiver} for |
| 553 // the lowering below. |
| 554 for (Node* dominator = effect;;) { |
| 555 if (dominator->opcode() == IrOpcode::kCheckString && |
| 556 dominator->InputAt(0) == receiver) { |
| 557 return dominator; |
| 558 } |
| 559 if (dominator->op()->EffectInputCount() != 1) { |
| 560 // Didn't find any appropriate CheckString node. |
| 561 return nullptr; |
| 562 } |
| 563 dominator = NodeProperties::GetEffectInput(dominator); |
| 564 } |
| 565 } |
| 566 |
| 567 } // namespace |
| 568 |
| 569 // ES6 section 21.1.3.1 String.prototype.charAt ( pos ) |
| 570 Reduction JSBuiltinReducer::ReduceStringCharAt(Node* node) { |
| 571 // We need at least target, receiver and index parameters. |
| 572 if (node->op()->ValueInputCount() >= 3) { |
| 573 Node* index = NodeProperties::GetValueInput(node, 2); |
| 574 Type* index_type = NodeProperties::GetType(index); |
| 575 Node* effect = NodeProperties::GetEffectInput(node); |
| 576 Node* control = NodeProperties::GetControlInput(node); |
| 577 |
| 578 if (index_type->Is(Type::Unsigned32())) { |
| 579 if (Node* receiver = GetStringReceiver(node)) { |
| 580 // Determine the {receiver} length. |
| 581 Node* receiver_length = effect = graph()->NewNode( |
| 582 simplified()->LoadField(AccessBuilder::ForStringLength()), receiver, |
| 583 effect, control); |
| 584 |
| 585 // Check if {index} is less than {receiver} length. |
| 586 Node* check = graph()->NewNode(simplified()->NumberLessThan(), index, |
| 587 receiver_length); |
| 588 Node* branch = graph()->NewNode(common()->Branch(BranchHint::kTrue), |
| 589 check, control); |
| 590 |
| 591 Node* if_true = graph()->NewNode(common()->IfTrue(), branch); |
| 592 Node* vtrue; |
| 593 { |
| 594 // Load the character from the {receiver}. |
| 595 vtrue = graph()->NewNode(simplified()->StringCharCodeAt(), receiver, |
| 596 index, if_true); |
| 597 |
| 598 // Return it as single character string. |
| 599 vtrue = graph()->NewNode(simplified()->StringFromCharCode(), vtrue); |
| 600 } |
| 601 |
| 602 // Return the empty string otherwise. |
| 603 Node* if_false = graph()->NewNode(common()->IfFalse(), branch); |
| 604 Node* vfalse = jsgraph()->EmptyStringConstant(); |
| 605 |
| 606 control = graph()->NewNode(common()->Merge(2), if_true, if_false); |
| 607 Node* value = |
| 608 graph()->NewNode(common()->Phi(MachineRepresentation::kTagged, 2), |
| 609 vtrue, vfalse, control); |
| 610 |
| 611 ReplaceWithValue(node, value, effect, control); |
| 612 return Replace(value); |
| 613 } |
| 614 } |
| 615 } |
| 616 |
| 617 return NoChange(); |
| 618 } |
| 619 |
| 620 // ES6 section 21.1.3.2 String.prototype.charCodeAt ( pos ) |
| 621 Reduction JSBuiltinReducer::ReduceStringCharCodeAt(Node* node) { |
| 622 // We need at least target, receiver and index parameters. |
| 623 if (node->op()->ValueInputCount() >= 3) { |
| 624 Node* index = NodeProperties::GetValueInput(node, 2); |
| 625 Type* index_type = NodeProperties::GetType(index); |
| 626 Node* effect = NodeProperties::GetEffectInput(node); |
| 627 Node* control = NodeProperties::GetControlInput(node); |
| 628 |
| 629 if (index_type->Is(Type::Unsigned32())) { |
| 630 if (Node* receiver = GetStringReceiver(node)) { |
| 631 // Determine the {receiver} length. |
| 632 Node* receiver_length = effect = graph()->NewNode( |
| 633 simplified()->LoadField(AccessBuilder::ForStringLength()), receiver, |
| 634 effect, control); |
| 635 |
| 636 // Check if {index} is less than {receiver} length. |
| 637 Node* check = graph()->NewNode(simplified()->NumberLessThan(), index, |
| 638 receiver_length); |
| 639 Node* branch = graph()->NewNode(common()->Branch(BranchHint::kTrue), |
| 640 check, control); |
| 641 |
| 642 // Load the character from the {receiver}. |
| 643 Node* if_true = graph()->NewNode(common()->IfTrue(), branch); |
| 644 Node* vtrue = graph()->NewNode(simplified()->StringCharCodeAt(), |
| 645 receiver, index, if_true); |
| 646 |
| 647 // Return NaN otherwise. |
| 648 Node* if_false = graph()->NewNode(common()->IfFalse(), branch); |
| 649 Node* vfalse = jsgraph()->NaNConstant(); |
| 650 |
| 651 control = graph()->NewNode(common()->Merge(2), if_true, if_false); |
| 652 Node* value = |
| 653 graph()->NewNode(common()->Phi(MachineRepresentation::kTagged, 2), |
| 654 vtrue, vfalse, control); |
| 655 |
| 656 ReplaceWithValue(node, value, effect, control); |
| 657 return Replace(value); |
| 658 } |
| 659 } |
| 660 } |
| 661 |
| 662 return NoChange(); |
| 663 } |
| 664 |
537 Reduction JSBuiltinReducer::Reduce(Node* node) { | 665 Reduction JSBuiltinReducer::Reduce(Node* node) { |
538 Reduction reduction = NoChange(); | 666 Reduction reduction = NoChange(); |
539 JSCallReduction r(node); | 667 JSCallReduction r(node); |
540 | 668 |
541 // Dispatch according to the BuiltinFunctionId if present. | 669 // Dispatch according to the BuiltinFunctionId if present. |
542 if (!r.HasBuiltinFunctionId()) return NoChange(); | 670 if (!r.HasBuiltinFunctionId()) return NoChange(); |
543 switch (r.GetBuiltinFunctionId()) { | 671 switch (r.GetBuiltinFunctionId()) { |
544 case kMathAbs: | 672 case kMathAbs: |
545 reduction = ReduceMathAbs(node); | 673 reduction = ReduceMathAbs(node); |
546 break; | 674 break; |
(...skipping 92 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
639 break; | 767 break; |
640 case kMathTrunc: | 768 case kMathTrunc: |
641 reduction = ReduceMathTrunc(node); | 769 reduction = ReduceMathTrunc(node); |
642 break; | 770 break; |
643 case kNumberParseInt: | 771 case kNumberParseInt: |
644 reduction = ReduceNumberParseInt(node); | 772 reduction = ReduceNumberParseInt(node); |
645 break; | 773 break; |
646 case kStringFromCharCode: | 774 case kStringFromCharCode: |
647 reduction = ReduceStringFromCharCode(node); | 775 reduction = ReduceStringFromCharCode(node); |
648 break; | 776 break; |
| 777 case kStringCharAt: |
| 778 return ReduceStringCharAt(node); |
| 779 case kStringCharCodeAt: |
| 780 return ReduceStringCharCodeAt(node); |
649 default: | 781 default: |
650 break; | 782 break; |
651 } | 783 } |
652 | 784 |
653 // Replace builtin call assuming replacement nodes are pure values that don't | 785 // Replace builtin call assuming replacement nodes are pure values that don't |
654 // produce an effect. Replaces {node} with {reduction} and relaxes effects. | 786 // produce an effect. Replaces {node} with {reduction} and relaxes effects. |
655 if (reduction.Changed()) ReplaceWithValue(node, reduction.replacement()); | 787 if (reduction.Changed()) ReplaceWithValue(node, reduction.replacement()); |
656 | 788 |
657 return reduction; | 789 return reduction; |
658 } | 790 } |
(...skipping 22 matching lines...) Expand all Loading... |
681 } | 813 } |
682 | 814 |
683 | 815 |
684 SimplifiedOperatorBuilder* JSBuiltinReducer::simplified() const { | 816 SimplifiedOperatorBuilder* JSBuiltinReducer::simplified() const { |
685 return jsgraph()->simplified(); | 817 return jsgraph()->simplified(); |
686 } | 818 } |
687 | 819 |
688 } // namespace compiler | 820 } // namespace compiler |
689 } // namespace internal | 821 } // namespace internal |
690 } // namespace v8 | 822 } // namespace v8 |
OLD | NEW |