| 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/access-builder.h" | 5 #include "src/compiler/access-builder.h" |
| 6 #include "src/compiler/graph-inl.h" | 6 #include "src/compiler/graph-inl.h" |
| 7 #include "src/compiler/js-graph.h" | 7 #include "src/compiler/js-graph.h" |
| 8 #include "src/compiler/js-typed-lowering.h" | 8 #include "src/compiler/js-typed-lowering.h" |
| 9 #include "src/compiler/node-aux-data-inl.h" | 9 #include "src/compiler/node-aux-data-inl.h" |
| 10 #include "src/compiler/node-matchers.h" | 10 #include "src/compiler/node-matchers.h" |
| (...skipping 519 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 530 | 530 |
| 531 | 531 |
| 532 Reduction JSTypedLowering::ReduceJSToNumberInput(Node* input) { | 532 Reduction JSTypedLowering::ReduceJSToNumberInput(Node* input) { |
| 533 if (input->opcode() == IrOpcode::kJSToNumber) { | 533 if (input->opcode() == IrOpcode::kJSToNumber) { |
| 534 // Recursively try to reduce the input first. | 534 // Recursively try to reduce the input first. |
| 535 Reduction result = ReduceJSToNumber(input); | 535 Reduction result = ReduceJSToNumber(input); |
| 536 if (result.Changed()) return result; | 536 if (result.Changed()) return result; |
| 537 return Changed(input); // JSToNumber(JSToNumber(x)) => JSToNumber(x) | 537 return Changed(input); // JSToNumber(JSToNumber(x)) => JSToNumber(x) |
| 538 } | 538 } |
| 539 // Check if we have a cached conversion. | 539 // Check if we have a cached conversion. |
| 540 Node* conversion = FindConversion<IrOpcode::kPlainPrimitiveToNumber>(input); | 540 Node* conversion = FindConversion<IrOpcode::kJSToNumber>(input); |
| 541 if (conversion) return Replace(conversion); | 541 if (conversion) return Replace(conversion); |
| 542 Type* input_type = NodeProperties::GetBounds(input).upper; | 542 Type* input_type = NodeProperties::GetBounds(input).upper; |
| 543 if (input_type->Is(Type::Number())) { | 543 if (input_type->Is(Type::Number())) { |
| 544 // JSToNumber(x:number) => x | 544 // JSToNumber(x:number) => x |
| 545 return Changed(input); | 545 return Changed(input); |
| 546 } | 546 } |
| 547 if (input_type->Is(Type::Undefined())) { | 547 if (input_type->Is(Type::Undefined())) { |
| 548 // JSToNumber(undefined) => #NaN | 548 // JSToNumber(undefined) => #NaN |
| 549 return Replace(jsgraph()->NaNConstant()); | 549 return Replace(jsgraph()->NaNConstant()); |
| 550 } | 550 } |
| (...skipping 13 matching lines...) Expand all Loading... |
| 564 Reduction JSTypedLowering::ReduceJSToNumber(Node* node) { | 564 Reduction JSTypedLowering::ReduceJSToNumber(Node* node) { |
| 565 // Try to reduce the input first. | 565 // Try to reduce the input first. |
| 566 Node* const input = node->InputAt(0); | 566 Node* const input = node->InputAt(0); |
| 567 Reduction reduction = ReduceJSToNumberInput(input); | 567 Reduction reduction = ReduceJSToNumberInput(input); |
| 568 if (reduction.Changed()) { | 568 if (reduction.Changed()) { |
| 569 NodeProperties::ReplaceWithValue(node, reduction.replacement()); | 569 NodeProperties::ReplaceWithValue(node, reduction.replacement()); |
| 570 return reduction; | 570 return reduction; |
| 571 } | 571 } |
| 572 Type* const input_type = NodeProperties::GetBounds(input).upper; | 572 Type* const input_type = NodeProperties::GetBounds(input).upper; |
| 573 if (input_type->Is(Type::PlainPrimitive())) { | 573 if (input_type->Is(Type::PlainPrimitive())) { |
| 574 RelaxEffects(node); | |
| 575 if (input->opcode() == IrOpcode::kPhi) { | 574 if (input->opcode() == IrOpcode::kPhi) { |
| 576 // JSToNumber(phi(x1,...,xn,control):plain-primitive,context) | 575 // JSToNumber(phi(x1,...,xn,control):plain-primitive,context) |
| 577 // => phi(PlainPrimitiveToNumber(x1), | 576 // => phi(JSToNumber(x1,no-context), |
| 578 // ..., | 577 // ..., |
| 579 // PlainPrimitiveToNumber(xn), | 578 // JSToNumber(xn,no-context),control) |
| 580 // control) | |
| 581 int const input_count = input->InputCount() - 1; | 579 int const input_count = input->InputCount() - 1; |
| 582 Node* const control = input->InputAt(input_count); | 580 Node* const control = input->InputAt(input_count); |
| 583 DCHECK_LE(0, input_count); | 581 DCHECK_LE(0, input_count); |
| 584 DCHECK(NodeProperties::IsControl(control)); | 582 DCHECK(NodeProperties::IsControl(control)); |
| 585 DCHECK(NodeProperties::GetBounds(node).upper->Is(Type::Number())); | 583 DCHECK(NodeProperties::GetBounds(node).upper->Is(Type::Number())); |
| 586 DCHECK(!NodeProperties::GetBounds(input).upper->Is(Type::Number())); | 584 DCHECK(!NodeProperties::GetBounds(input).upper->Is(Type::Number())); |
| 585 RelaxEffects(node); |
| 587 node->set_op(common()->Phi(kMachAnyTagged, input_count)); | 586 node->set_op(common()->Phi(kMachAnyTagged, input_count)); |
| 588 for (int i = 0; i < input_count; ++i) { | 587 for (int i = 0; i < input_count; ++i) { |
| 589 // We must be very careful not to introduce cycles when pushing | 588 // We must be very careful not to introduce cycles when pushing |
| 590 // operations into phis. It is safe for {value}, since it appears | 589 // operations into phis. It is safe for {value}, since it appears |
| 591 // as input to the phi that we are replacing, but it's not safe | 590 // as input to the phi that we are replacing, but it's not safe |
| 592 // to simply reuse the context of the {node}. However, ToNumber() | 591 // to simply reuse the context of the {node}. However, ToNumber() |
| 593 // does not require a context anyways, so it's safe to discard it | 592 // does not require a context anyways, so it's safe to discard it |
| 594 // here and pass the dummy context. | 593 // here and pass the dummy context. |
| 595 Node* const value = ConvertToNumber(input->InputAt(i)); | 594 Node* const value = ConvertToNumber(input->InputAt(i)); |
| 596 if (i < node->InputCount()) { | 595 if (i < node->InputCount()) { |
| 597 node->ReplaceInput(i, value); | 596 node->ReplaceInput(i, value); |
| 598 } else { | 597 } else { |
| 599 node->AppendInput(graph()->zone(), value); | 598 node->AppendInput(graph()->zone(), value); |
| 600 } | 599 } |
| 601 } | 600 } |
| 602 if (input_count < node->InputCount()) { | 601 if (input_count < node->InputCount()) { |
| 603 node->ReplaceInput(input_count, control); | 602 node->ReplaceInput(input_count, control); |
| 604 } else { | 603 } else { |
| 605 node->AppendInput(graph()->zone(), control); | 604 node->AppendInput(graph()->zone(), control); |
| 606 } | 605 } |
| 607 node->TrimInputCount(input_count + 1); | 606 node->TrimInputCount(input_count + 1); |
| 608 return Changed(node); | 607 return Changed(node); |
| 609 } | 608 } |
| 610 if (input->opcode() == IrOpcode::kSelect) { | 609 if (input->opcode() == IrOpcode::kSelect) { |
| 611 // JSToNumber(select(c,x1,x2):plain-primitive,context) | 610 // JSToNumber(select(c,x1,x2):plain-primitive,context) |
| 612 // => select(c,PlainPrimitiveToNumber(x1),PlainPrimitiveToNumber(x2)) | 611 // => select(c,JSToNumber(x1,no-context),JSToNumber(x2,no-context)) |
| 613 int const input_count = input->InputCount(); | 612 int const input_count = input->InputCount(); |
| 614 BranchHint const input_hint = SelectParametersOf(input->op()).hint(); | 613 BranchHint const input_hint = SelectParametersOf(input->op()).hint(); |
| 615 DCHECK_EQ(3, input_count); | 614 DCHECK_EQ(3, input_count); |
| 616 DCHECK(NodeProperties::GetBounds(node).upper->Is(Type::Number())); | 615 DCHECK(NodeProperties::GetBounds(node).upper->Is(Type::Number())); |
| 617 DCHECK(!NodeProperties::GetBounds(input).upper->Is(Type::Number())); | 616 DCHECK(!NodeProperties::GetBounds(input).upper->Is(Type::Number())); |
| 617 RelaxEffects(node); |
| 618 node->set_op(common()->Select(kMachAnyTagged, input_hint)); | 618 node->set_op(common()->Select(kMachAnyTagged, input_hint)); |
| 619 node->ReplaceInput(0, input->InputAt(0)); | 619 node->ReplaceInput(0, input->InputAt(0)); |
| 620 for (int i = 1; i < input_count; ++i) { | 620 for (int i = 1; i < input_count; ++i) { |
| 621 // We must be very careful not to introduce cycles when pushing | 621 // We must be very careful not to introduce cycles when pushing |
| 622 // operations into selects. It is safe for {value}, since it appears | 622 // operations into selects. It is safe for {value}, since it appears |
| 623 // as input to the select that we are replacing, but it's not safe | 623 // as input to the select that we are replacing, but it's not safe |
| 624 // to simply reuse the context of the {node}. However, ToNumber() | 624 // to simply reuse the context of the {node}. However, ToNumber() |
| 625 // does not require a context anyways, so it's safe to discard it | 625 // does not require a context anyways, so it's safe to discard it |
| 626 // here and pass the dummy context. | 626 // here and pass the dummy context. |
| 627 Node* const value = ConvertToNumber(input->InputAt(i)); | 627 Node* const value = ConvertToNumber(input->InputAt(i)); |
| 628 node->ReplaceInput(i, value); | 628 node->ReplaceInput(i, value); |
| 629 } | 629 } |
| 630 node->TrimInputCount(input_count); | 630 node->TrimInputCount(input_count); |
| 631 return Changed(node); | 631 return Changed(node); |
| 632 } | 632 } |
| 633 // JSToNumber(x:plain-primitive,context) => PlainPrimitiveToNumber(x) | |
| 634 node->set_op(simplified()->PlainPrimitiveToNumber()); | |
| 635 node->TrimInputCount(1); | |
| 636 // Remember this conversion. | 633 // Remember this conversion. |
| 637 InsertConversion(node); | 634 InsertConversion(node); |
| 638 return Changed(node); | 635 if (NodeProperties::GetContextInput(node) != |
| 636 jsgraph()->NoContextConstant() || |
| 637 NodeProperties::GetEffectInput(node) != graph()->start() || |
| 638 NodeProperties::GetControlInput(node) != graph()->start()) { |
| 639 // JSToNumber(x:plain-primitive,context,effect,control) |
| 640 // => JSToNumber(x,no-context,start,start) |
| 641 RelaxEffects(node); |
| 642 NodeProperties::ReplaceContextInput(node, jsgraph()->NoContextConstant()); |
| 643 NodeProperties::ReplaceControlInput(node, graph()->start()); |
| 644 NodeProperties::ReplaceEffectInput(node, graph()->start()); |
| 645 if (OperatorProperties::HasFrameStateInput(node->op())) { |
| 646 NodeProperties::ReplaceFrameStateInput(node, |
| 647 jsgraph()->EmptyFrameState()); |
| 648 } |
| 649 return Changed(node); |
| 650 } |
| 639 } | 651 } |
| 640 return NoChange(); | 652 return NoChange(); |
| 641 } | 653 } |
| 642 | 654 |
| 643 | 655 |
| 644 Reduction JSTypedLowering::ReduceJSToStringInput(Node* input) { | 656 Reduction JSTypedLowering::ReduceJSToStringInput(Node* input) { |
| 645 if (input->opcode() == IrOpcode::kJSToString) { | 657 if (input->opcode() == IrOpcode::kJSToString) { |
| 646 // Recursively try to reduce the input first. | 658 // Recursively try to reduce the input first. |
| 647 Reduction result = ReduceJSToString(input); | 659 Reduction result = ReduceJSToString(input); |
| 648 if (result.Changed()) return result; | 660 if (result.Changed()) return result; |
| (...skipping 284 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 933 } | 945 } |
| 934 return NoChange(); | 946 return NoChange(); |
| 935 } | 947 } |
| 936 | 948 |
| 937 | 949 |
| 938 Node* JSTypedLowering::ConvertToNumber(Node* input) { | 950 Node* JSTypedLowering::ConvertToNumber(Node* input) { |
| 939 DCHECK(NodeProperties::GetBounds(input).upper->Is(Type::PlainPrimitive())); | 951 DCHECK(NodeProperties::GetBounds(input).upper->Is(Type::PlainPrimitive())); |
| 940 // Avoid inserting too many eager ToNumber() operations. | 952 // Avoid inserting too many eager ToNumber() operations. |
| 941 Reduction const reduction = ReduceJSToNumberInput(input); | 953 Reduction const reduction = ReduceJSToNumberInput(input); |
| 942 if (reduction.Changed()) return reduction.replacement(); | 954 if (reduction.Changed()) return reduction.replacement(); |
| 955 // TODO(jarin) Use PlainPrimitiveToNumber once we have it. |
| 943 Node* const conversion = | 956 Node* const conversion = |
| 944 graph()->NewNode(simplified()->PlainPrimitiveToNumber(), input); | 957 FLAG_turbo_deoptimization |
| 958 ? graph()->NewNode(javascript()->ToNumber(), input, |
| 959 jsgraph()->NoContextConstant(), |
| 960 jsgraph()->EmptyFrameState(), graph()->start(), |
| 961 graph()->start()) |
| 962 : graph()->NewNode(javascript()->ToNumber(), input, |
| 963 jsgraph()->NoContextConstant(), graph()->start(), |
| 964 graph()->start()); |
| 945 InsertConversion(conversion); | 965 InsertConversion(conversion); |
| 946 return conversion; | 966 return conversion; |
| 947 } | 967 } |
| 948 | 968 |
| 949 | 969 |
| 950 template <IrOpcode::Value kOpcode> | 970 template <IrOpcode::Value kOpcode> |
| 951 Node* JSTypedLowering::FindConversion(Node* input) { | 971 Node* JSTypedLowering::FindConversion(Node* input) { |
| 952 size_t const input_id = input->id(); | 972 size_t const input_id = input->id(); |
| 953 if (input_id < conversions_.size()) { | 973 if (input_id < conversions_.size()) { |
| 954 Node* const conversion = conversions_[input_id]; | 974 Node* const conversion = conversions_[input_id]; |
| 955 if (conversion && conversion->opcode() == kOpcode) { | 975 if (conversion && conversion->opcode() == kOpcode) { |
| 956 return conversion; | 976 return conversion; |
| 957 } | 977 } |
| 958 } | 978 } |
| 959 return nullptr; | 979 return nullptr; |
| 960 } | 980 } |
| 961 | 981 |
| 962 | 982 |
| 963 void JSTypedLowering::InsertConversion(Node* conversion) { | 983 void JSTypedLowering::InsertConversion(Node* conversion) { |
| 964 DCHECK(conversion->opcode() == IrOpcode::kPlainPrimitiveToNumber); | 984 DCHECK(conversion->opcode() == IrOpcode::kJSToNumber); |
| 965 size_t const input_id = conversion->InputAt(0)->id(); | 985 size_t const input_id = conversion->InputAt(0)->id(); |
| 966 if (input_id >= conversions_.size()) { | 986 if (input_id >= conversions_.size()) { |
| 967 conversions_.resize(2 * input_id + 1); | 987 conversions_.resize(2 * input_id + 1); |
| 968 } | 988 } |
| 969 conversions_[input_id] = conversion; | 989 conversions_[input_id] = conversion; |
| 970 } | 990 } |
| 971 | 991 |
| 972 | 992 |
| 973 Node* JSTypedLowering::Word32Shl(Node* const lhs, int32_t const rhs) { | 993 Node* JSTypedLowering::Word32Shl(Node* const lhs, int32_t const rhs) { |
| 974 if (rhs == 0) return lhs; | 994 if (rhs == 0) return lhs; |
| (...skipping 18 matching lines...) Expand all Loading... |
| 993 } | 1013 } |
| 994 | 1014 |
| 995 | 1015 |
| 996 MachineOperatorBuilder* JSTypedLowering::machine() const { | 1016 MachineOperatorBuilder* JSTypedLowering::machine() const { |
| 997 return jsgraph()->machine(); | 1017 return jsgraph()->machine(); |
| 998 } | 1018 } |
| 999 | 1019 |
| 1000 } // namespace compiler | 1020 } // namespace compiler |
| 1001 } // namespace internal | 1021 } // namespace internal |
| 1002 } // namespace v8 | 1022 } // namespace v8 |
| OLD | NEW |