Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(9)

Side by Side Diff: src/compiler/js-builtin-reducer.cc

Issue 2180373005: [turbofan] Add support for String.prototype.charCodeAt/charAt. (Closed) Base URL: https://chromium.googlesource.com/v8/v8.git@master
Patch Set: Created 4 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « src/compiler/js-builtin-reducer.h ('k') | src/compiler/js-graph.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
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
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
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
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
OLDNEW
« no previous file with comments | « src/compiler/js-builtin-reducer.h ('k') | src/compiler/js-graph.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698