|
41 | 41 | #include "opto/opaquenode.hpp" |
42 | 42 | #include "opto/parse.hpp" |
43 | 43 | #include "opto/runtime.hpp" |
| 44 | +#include "opto/subtypenode.hpp" |
44 | 45 | #include "runtime/deoptimization.hpp" |
45 | 46 | #include "runtime/sharedRuntime.hpp" |
46 | 47 |
|
@@ -1719,38 +1720,108 @@ static Node* extract_obj_from_klass_load(PhaseGVN* gvn, Node* n) { |
1719 | 1720 | return obj; |
1720 | 1721 | } |
1721 | 1722 |
|
| 1723 | +// Matches exact and inexact type check IR shapes during parsing. |
| 1724 | +// On successful match, returns type checked object node and its type after successful check |
| 1725 | +// as out parameters. |
| 1726 | +static bool match_type_check(PhaseGVN& gvn, |
| 1727 | + BoolTest::mask btest, |
| 1728 | + Node* con, const Type* tcon, |
| 1729 | + Node* val, const Type* tval, |
| 1730 | + Node** obj, const TypeOopPtr** cast_type) { // out-parameters |
| 1731 | + // Look for opportunities to sharpen the type of a node whose klass is compared with a constant klass. |
| 1732 | + // The constant klass being tested against can come from many bytecode instructions (implicitly or explicitly), |
| 1733 | + // and also from profile data used by speculative casts. |
| 1734 | + if (btest == BoolTest::eq && tcon->isa_klassptr()) { |
| 1735 | + // Found: |
| 1736 | + // Bool(CmpP(LoadKlass(obj._klass), ConP(Foo.klass)), [eq]) |
| 1737 | + // or the narrowOop equivalent. |
| 1738 | + (*obj) = extract_obj_from_klass_load(&gvn, val); |
| 1739 | + (*cast_type) = tcon->isa_klassptr()->as_instance_type(); |
| 1740 | + return true; // found |
| 1741 | + } |
| 1742 | + |
| 1743 | + // Match an instanceof check. |
| 1744 | + // During parsing its IR shape is not canonicalized yet. |
| 1745 | + // |
| 1746 | + // obj superklass |
| 1747 | + // | | |
| 1748 | + // SubTypeCheck |
| 1749 | + // | |
| 1750 | + // Bool [eq] / [ne] |
| 1751 | + // | |
| 1752 | + // If |
| 1753 | + // / \ |
| 1754 | + // T F |
| 1755 | + // \ / |
| 1756 | + // Region |
| 1757 | + // \ ConI ConI |
| 1758 | + // \ | / |
| 1759 | + // val -> Phi ConI <- con |
| 1760 | + // \ / |
| 1761 | + // CmpI |
| 1762 | + // | |
| 1763 | + // Bool [btest] |
| 1764 | + // | |
| 1765 | + // |
| 1766 | + if (tval->isa_int() && val->is_Phi() && val->in(0)->as_Region()->is_diamond()) { |
| 1767 | + RegionNode* diamond = val->in(0)->as_Region(); |
| 1768 | + IfNode* if1 = diamond->in(1)->in(0)->as_If(); |
| 1769 | + BoolNode* b1 = if1->in(1)->isa_Bool(); |
| 1770 | + if (b1 != nullptr && b1->in(1)->isa_SubTypeCheck()) { |
| 1771 | + assert(b1->_test._test == BoolTest::eq || |
| 1772 | + b1->_test._test == BoolTest::ne, "%d", b1->_test._test); |
| 1773 | + |
| 1774 | + ProjNode* success_proj = if1->proj_out(b1->_test._test == BoolTest::eq ? 1 : 0); |
| 1775 | + int idx = diamond->find_edge(success_proj); |
| 1776 | + assert(idx == 1 || idx == 2, ""); |
| 1777 | + Node* vcon = val->in(idx); |
| 1778 | + |
| 1779 | + assert(val->find_edge(con) > 0, ""); |
| 1780 | + if ((btest == BoolTest::eq && vcon == con) || (btest == BoolTest::ne && vcon != con)) { |
| 1781 | + SubTypeCheckNode* sub = b1->in(1)->as_SubTypeCheck(); |
| 1782 | + Node* obj_or_subklass = sub->in(SubTypeCheckNode::ObjOrSubKlass); |
| 1783 | + Node* superklass = sub->in(SubTypeCheckNode::SuperKlass); |
| 1784 | + |
| 1785 | + if (gvn.type(obj_or_subklass)->isa_oopptr()) { |
| 1786 | + const TypeKlassPtr* klass_ptr_type = gvn.type(superklass)->is_klassptr(); |
| 1787 | + const TypeKlassPtr* improved_klass_ptr_type = klass_ptr_type->try_improve(); |
| 1788 | + |
| 1789 | + (*obj) = obj_or_subklass; |
| 1790 | + (*cast_type) = improved_klass_ptr_type->cast_to_exactness(false)->as_instance_type(); |
| 1791 | + return true; // found |
| 1792 | + } |
| 1793 | + } |
| 1794 | + } |
| 1795 | + } |
| 1796 | + return false; // not found |
| 1797 | +} |
| 1798 | + |
1722 | 1799 | void Parse::sharpen_type_after_if(BoolTest::mask btest, |
1723 | 1800 | Node* con, const Type* tcon, |
1724 | 1801 | Node* val, const Type* tval) { |
1725 | | - // Look for opportunities to sharpen the type of a node |
1726 | | - // whose klass is compared with a constant klass. |
1727 | | - if (btest == BoolTest::eq && tcon->isa_klassptr()) { |
1728 | | - Node* obj = extract_obj_from_klass_load(&_gvn, val); |
1729 | | - const TypeOopPtr* con_type = tcon->isa_klassptr()->as_instance_type(); |
1730 | | - if (obj != nullptr && (con_type->isa_instptr() || con_type->isa_aryptr())) { |
1731 | | - // Found: |
1732 | | - // Bool(CmpP(LoadKlass(obj._klass), ConP(Foo.klass)), [eq]) |
1733 | | - // or the narrowOop equivalent. |
1734 | | - const Type* obj_type = _gvn.type(obj); |
1735 | | - const TypeOopPtr* tboth = obj_type->join_speculative(con_type)->isa_oopptr(); |
1736 | | - if (tboth != nullptr && tboth->klass_is_exact() && tboth != obj_type && |
1737 | | - tboth->higher_equal(obj_type)) { |
1738 | | - // obj has to be of the exact type Foo if the CmpP succeeds. |
1739 | | - int obj_in_map = map()->find_edge(obj); |
1740 | | - JVMState* jvms = this->jvms(); |
1741 | | - if (obj_in_map >= 0 && |
1742 | | - (jvms->is_loc(obj_in_map) || jvms->is_stk(obj_in_map))) { |
1743 | | - TypeNode* ccast = new CheckCastPPNode(control(), obj, tboth); |
1744 | | - const Type* tcc = ccast->as_Type()->type(); |
1745 | | - assert(tcc != obj_type && tcc->higher_equal(obj_type), "must improve"); |
1746 | | - // Delay transform() call to allow recovery of pre-cast value |
1747 | | - // at the control merge. |
1748 | | - _gvn.set_type_bottom(ccast); |
1749 | | - record_for_igvn(ccast); |
1750 | | - // Here's the payoff. |
1751 | | - replace_in_map(obj, ccast); |
1752 | | - } |
1753 | | - } |
| 1802 | + Node* obj = nullptr; |
| 1803 | + const TypeOopPtr* cast_type = nullptr; |
| 1804 | + // Insert a cast node with a narrowed type after a successful type check. |
| 1805 | + if (match_type_check(_gvn, btest, con, tcon, val, tval, |
| 1806 | + &obj, &cast_type)) { |
| 1807 | + assert(obj != nullptr && cast_type != nullptr, "missing type check info"); |
| 1808 | + const Type* obj_type = _gvn.type(obj); |
| 1809 | + const TypeOopPtr* tboth = obj_type->join_speculative(cast_type)->isa_oopptr(); |
| 1810 | + if (tboth != nullptr && tboth != obj_type && tboth->higher_equal(obj_type)) { |
| 1811 | + int obj_in_map = map()->find_edge(obj); |
| 1812 | + JVMState* jvms = this->jvms(); |
| 1813 | + if (obj_in_map >= 0 && |
| 1814 | + (jvms->is_loc(obj_in_map) || jvms->is_stk(obj_in_map))) { |
| 1815 | + TypeNode* ccast = new CheckCastPPNode(control(), obj, tboth); |
| 1816 | + const Type* tcc = ccast->as_Type()->type(); |
| 1817 | + assert(tcc != obj_type && tcc->higher_equal(obj_type), "must improve"); |
| 1818 | + // Delay transform() call to allow recovery of pre-cast value |
| 1819 | + // at the control merge. |
| 1820 | + _gvn.set_type_bottom(ccast); |
| 1821 | + record_for_igvn(ccast); |
| 1822 | + // Here's the payoff. |
| 1823 | + replace_in_map(obj, ccast); |
| 1824 | + } |
1754 | 1825 | } |
1755 | 1826 | } |
1756 | 1827 |
|
|
0 commit comments