# HG changeset patch # User trims # Date 1308894202 25200 # Node ID b3a485ccfe866d2b195ab5abbaa036ec28bcf81f # Parent 5bb91b0db2c9b5ec73b411bae46b1e1de0e2d94f# Parent 393e144bb99b960fc6da95a0e37a203cbd712002 Merge diff -r 5bb91b0db2c9 -r b3a485ccfe86 .hgtags --- a/.hgtags Wed Jun 22 12:40:50 2011 -0700 +++ b/.hgtags Thu Jun 23 22:43:22 2011 -0700 @@ -179,3 +179,4 @@ 82a81d5c5700a69333e12532bf0c4d33e885c7fc jdk7-b145 82a81d5c5700a69333e12532bf0c4d33e885c7fc hs21-b15 38fa55e5e79232d48f1bb8cf27d88bc094c9375a jdk7-b146 +38fa55e5e79232d48f1bb8cf27d88bc094c9375a hs21-b16 diff -r 5bb91b0db2c9 -r b3a485ccfe86 src/cpu/x86/vm/assembler_x86.cpp --- a/src/cpu/x86/vm/assembler_x86.cpp Wed Jun 22 12:40:50 2011 -0700 +++ b/src/cpu/x86/vm/assembler_x86.cpp Thu Jun 23 22:43:22 2011 -0700 @@ -3804,6 +3804,14 @@ emit_arith(0x03, 0xC0, dst, src); } +void Assembler::andq(Address dst, int32_t imm32) { + InstructionMark im(this); + prefixq(dst); + emit_byte(0x81); + emit_operand(rsp, dst, 4); + emit_long(imm32); +} + void Assembler::andq(Register dst, int32_t imm32) { (void) prefixq_and_encode(dst->encoding()); emit_arith(0x81, 0xE0, dst, imm32); diff -r 5bb91b0db2c9 -r b3a485ccfe86 src/cpu/x86/vm/assembler_x86.hpp --- a/src/cpu/x86/vm/assembler_x86.hpp Wed Jun 22 12:40:50 2011 -0700 +++ b/src/cpu/x86/vm/assembler_x86.hpp Thu Jun 23 22:43:22 2011 -0700 @@ -779,6 +779,7 @@ void andl(Register dst, Address src); void andl(Register dst, Register src); + void andq(Address dst, int32_t imm32); void andq(Register dst, int32_t imm32); void andq(Register dst, Address src); void andq(Register dst, Register src); diff -r 5bb91b0db2c9 -r b3a485ccfe86 src/cpu/x86/vm/x86_64.ad --- a/src/cpu/x86/vm/x86_64.ad Wed Jun 22 12:40:50 2011 -0700 +++ b/src/cpu/x86/vm/x86_64.ad Thu Jun 23 22:43:22 2011 -0700 @@ -830,6 +830,17 @@ } } +// This could be in MacroAssembler but it's fairly C2 specific +void emit_cmpfp_fixup(MacroAssembler& _masm) { + Label exit; + __ jccb(Assembler::noParity, exit); + __ pushf(); + __ andq(Address(rsp, 0), 0xffffff2b); + __ popf(); + __ bind(exit); + __ nop(); // (target for branch to avoid branch to branch) +} + //============================================================================= const bool Matcher::constant_table_absolute_addressing = true; @@ -2173,27 +2184,9 @@ emit_rm(cbuf, 0x3, $dst$$reg & 7, $src$$reg & 7); %} - enc_class cmpfp_fixup() - %{ - // jnp,s exit - emit_opcode(cbuf, 0x7B); - emit_d8(cbuf, 0x0A); - - // pushfq - emit_opcode(cbuf, 0x9C); - - // andq $0xffffff2b, (%rsp) - emit_opcode(cbuf, Assembler::REX_W); - emit_opcode(cbuf, 0x81); - emit_opcode(cbuf, 0x24); - emit_opcode(cbuf, 0x24); - emit_d32(cbuf, 0xffffff2b); - - // popfq - emit_opcode(cbuf, 0x9D); - - // nop (target for branch to avoid branch to branch) - emit_opcode(cbuf, 0x90); + enc_class cmpfp_fixup() %{ + MacroAssembler _masm(&cbuf); + emit_cmpfp_fixup(_masm); %} enc_class cmpfp3(rRegI dst) @@ -10253,14 +10246,8 @@ "popfq\n" "exit: nop\t# avoid branch to branch" %} ins_encode %{ - Label L_exit; __ ucomiss($src$$XMMRegister, $constantaddress($con)); - __ jcc(Assembler::noParity, L_exit); - __ pushf(); - __ andq(rsp, 0xffffff2b); - __ popf(); - __ bind(L_exit); - __ nop(); + emit_cmpfp_fixup(_masm); %} ins_pipe(pipe_slow); %} @@ -10341,14 +10328,8 @@ "popfq\n" "exit: nop\t# avoid branch to branch" %} ins_encode %{ - Label L_exit; __ ucomisd($src$$XMMRegister, $constantaddress($con)); - __ jcc(Assembler::noParity, L_exit); - __ pushf(); - __ andq(rsp, 0xffffff2b); - __ popf(); - __ bind(L_exit); - __ nop(); + emit_cmpfp_fixup(_masm); %} ins_pipe(pipe_slow); %} diff -r 5bb91b0db2c9 -r b3a485ccfe86 src/share/vm/code/nmethod.cpp --- a/src/share/vm/code/nmethod.cpp Wed Jun 22 12:40:50 2011 -0700 +++ b/src/share/vm/code/nmethod.cpp Thu Jun 23 22:43:22 2011 -0700 @@ -1832,7 +1832,9 @@ if (!method()->is_native()) { SimpleScopeDesc ssd(this, fr.pc()); Bytecode_invoke call(ssd.method(), ssd.bci()); - bool has_receiver = call.has_receiver(); + // compiled invokedynamic call sites have an implicit receiver at + // resolution time, so make sure it gets GC'ed. + bool has_receiver = !call.is_invokestatic(); Symbol* signature = call.signature(); fr.oops_compiled_arguments_do(signature, has_receiver, reg_map, f); } diff -r 5bb91b0db2c9 -r b3a485ccfe86 src/share/vm/opto/bytecodeInfo.cpp --- a/src/share/vm/opto/bytecodeInfo.cpp Wed Jun 22 12:40:50 2011 -0700 +++ b/src/share/vm/opto/bytecodeInfo.cpp Thu Jun 23 22:43:22 2011 -0700 @@ -35,14 +35,16 @@ //============================================================================= //------------------------------InlineTree------------------------------------- -InlineTree::InlineTree( Compile* c, - const InlineTree *caller_tree, ciMethod* callee, - JVMState* caller_jvms, int caller_bci, - float site_invoke_ratio, int site_depth_adjust) -: C(c), _caller_jvms(caller_jvms), - _caller_tree((InlineTree*)caller_tree), - _method(callee), _site_invoke_ratio(site_invoke_ratio), - _site_depth_adjust(site_depth_adjust), +InlineTree::InlineTree(Compile* c, + const InlineTree *caller_tree, ciMethod* callee, + JVMState* caller_jvms, int caller_bci, + float site_invoke_ratio, int max_inline_level) : + C(c), + _caller_jvms(caller_jvms), + _caller_tree((InlineTree*) caller_tree), + _method(callee), + _site_invoke_ratio(site_invoke_ratio), + _max_inline_level(max_inline_level), _count_inline_bcs(method()->code_size()) { NOT_PRODUCT(_count_inlines = 0;) @@ -66,10 +68,13 @@ } InlineTree::InlineTree(Compile* c, ciMethod* callee_method, JVMState* caller_jvms, - float site_invoke_ratio, int site_depth_adjust) -: C(c), _caller_jvms(caller_jvms), _caller_tree(NULL), - _method(callee_method), _site_invoke_ratio(site_invoke_ratio), - _site_depth_adjust(site_depth_adjust), + float site_invoke_ratio, int max_inline_level) : + C(c), + _caller_jvms(caller_jvms), + _caller_tree(NULL), + _method(callee_method), + _site_invoke_ratio(site_invoke_ratio), + _max_inline_level(max_inline_level), _count_inline_bcs(method()->code_size()) { NOT_PRODUCT(_count_inlines = 0;) @@ -94,7 +99,7 @@ if(callee_method->should_inline()) { *wci_result = *(WarmCallInfo::always_hot()); if (PrintInlining && Verbose) { - CompileTask::print_inline_indent(inline_depth()); + CompileTask::print_inline_indent(inline_level()); tty->print_cr("Inlined method is hot: "); } return NULL; @@ -109,7 +114,7 @@ size < InlineThrowMaxSize ) { wci_result->set_profit(wci_result->profit() * 100); if (PrintInlining && Verbose) { - CompileTask::print_inline_indent(inline_depth()); + CompileTask::print_inline_indent(inline_level()); tty->print_cr("Inlined method with many throws (throws=%d):", callee_method->interpreter_throwout_count()); } return NULL; @@ -149,9 +154,9 @@ max_inline_size = C->freq_inline_size(); if (size <= max_inline_size && TraceFrequencyInlining) { - CompileTask::print_inline_indent(inline_depth()); + CompileTask::print_inline_indent(inline_level()); tty->print_cr("Inlined frequent method (freq=%d count=%d):", freq, call_site_count); - CompileTask::print_inline_indent(inline_depth()); + CompileTask::print_inline_indent(inline_level()); callee_method->print(); tty->cr(); } @@ -322,7 +327,7 @@ if (!C->do_inlining() && InlineAccessors) { return "not an accessor"; } - if( inline_depth() > MaxInlineLevel ) { + if (inline_level() > _max_inline_level) { return "inlining too deep"; } @@ -392,7 +397,7 @@ //------------------------------print_inlining--------------------------------- // Really, the failure_msg can be a success message also. void InlineTree::print_inlining(ciMethod* callee_method, int caller_bci, const char* failure_msg) const { - CompileTask::print_inlining(callee_method, inline_depth(), caller_bci, failure_msg ? failure_msg : "inline"); + CompileTask::print_inlining(callee_method, inline_level(), caller_bci, failure_msg ? failure_msg : "inline"); if (callee_method == NULL) tty->print(" callee not monotonic or profiled"); if (Verbose && callee_method) { const InlineTree *top = this; @@ -500,25 +505,25 @@ if (old_ilt != NULL) { return old_ilt; } - int new_depth_adjust = 0; + int max_inline_level_adjust = 0; if (caller_jvms->method() != NULL) { if (caller_jvms->method()->is_method_handle_adapter()) - new_depth_adjust -= 1; // don't count actions in MH or indy adapter frames + max_inline_level_adjust += 1; // don't count actions in MH or indy adapter frames else if (callee_method->is_method_handle_invoke()) { - new_depth_adjust -= 1; // don't count method handle calls from java.lang.invoke implem + max_inline_level_adjust += 1; // don't count method handle calls from java.lang.invoke implem } - if (new_depth_adjust != 0 && PrintInlining) { - CompileTask::print_inline_indent(inline_depth()); + if (max_inline_level_adjust != 0 && PrintInlining && (Verbose || WizardMode)) { + CompileTask::print_inline_indent(inline_level()); tty->print_cr(" \\-> discounting inline depth"); } - if (new_depth_adjust != 0 && C->log()) { + if (max_inline_level_adjust != 0 && C->log()) { int id1 = C->log()->identify(caller_jvms->method()); int id2 = C->log()->identify(callee_method); - C->log()->elem("inline_depth_discount caller='%d' callee='%d'", id1, id2); + C->log()->elem("inline_level_discount caller='%d' callee='%d'", id1, id2); } } - InlineTree *ilt = new InlineTree(C, this, callee_method, caller_jvms, caller_bci, recur_frequency, _site_depth_adjust + new_depth_adjust); - _subtrees.append( ilt ); + InlineTree* ilt = new InlineTree(C, this, callee_method, caller_jvms, caller_bci, recur_frequency, _max_inline_level + max_inline_level_adjust); + _subtrees.append(ilt); NOT_PRODUCT( _count_inlines += 1; ) @@ -543,7 +548,7 @@ Compile* C = Compile::current(); // Root of inline tree - InlineTree *ilt = new InlineTree(C, NULL, C->method(), NULL, -1, 1.0F, 0); + InlineTree* ilt = new InlineTree(C, NULL, C->method(), NULL, -1, 1.0F, MaxInlineLevel); return ilt; } diff -r 5bb91b0db2c9 -r b3a485ccfe86 src/share/vm/opto/doCall.cpp --- a/src/share/vm/opto/doCall.cpp Wed Jun 22 12:40:50 2011 -0700 +++ b/src/share/vm/opto/doCall.cpp Thu Jun 23 22:43:22 2011 -0700 @@ -183,7 +183,7 @@ // TO DO: When UseOldInlining is removed, copy the ILT code elsewhere. float site_invoke_ratio = prof_factor; // Note: ilt is for the root of this parse, not the present call site. - ilt = new InlineTree(this, jvms->method(), jvms->caller(), site_invoke_ratio, 0); + ilt = new InlineTree(this, jvms->method(), jvms->caller(), site_invoke_ratio, MaxInlineLevel); } WarmCallInfo scratch_ci; if (!UseOldInlining) diff -r 5bb91b0db2c9 -r b3a485ccfe86 src/share/vm/opto/loopTransform.cpp --- a/src/share/vm/opto/loopTransform.cpp Wed Jun 22 12:40:50 2011 -0700 +++ b/src/share/vm/opto/loopTransform.cpp Thu Jun 23 22:43:22 2011 -0700 @@ -83,7 +83,7 @@ #ifdef ASSERT BoolTest::mask bt = cl->loopexit()->test_trip(); assert(bt == BoolTest::lt || bt == BoolTest::gt || - (bt == BoolTest::ne && !LoopLimitCheck), "canonical test is expected"); + bt == BoolTest::ne, "canonical test is expected"); #endif Node* init_n = cl->init_trip(); @@ -1070,9 +1070,11 @@ // direction: // positive stride use < // negative stride use > + // + // not-equal test is kept for post loop to handle case + // when init > limit when stride > 0 (and reverse). if (pre_end->in(CountedLoopEndNode::TestValue)->as_Bool()->_test._test == BoolTest::ne) { - assert(!LoopLimitCheck, "only canonical tests (lt or gt) are expected"); BoolTest::mask new_test = (main_end->stride_con() > 0) ? BoolTest::lt : BoolTest::gt; // Modify pre loop end condition diff -r 5bb91b0db2c9 -r b3a485ccfe86 src/share/vm/opto/loopnode.cpp --- a/src/share/vm/opto/loopnode.cpp Wed Jun 22 12:40:50 2011 -0700 +++ b/src/share/vm/opto/loopnode.cpp Thu Jun 23 22:43:22 2011 -0700 @@ -453,7 +453,12 @@ // Now we need to canonicalize loop condition. if (bt == BoolTest::ne) { assert(stride_con == 1 || stride_con == -1, "simple increment only"); - bt = (stride_con > 0) ? BoolTest::lt : BoolTest::gt; + // 'ne' can be replaced with 'lt' only when init < limit. + if (stride_con > 0 && init_t->_hi < limit_t->_lo) + bt = BoolTest::lt; + // 'ne' can be replaced with 'gt' only when init > limit. + if (stride_con < 0 && init_t->_lo > limit_t->_hi) + bt = BoolTest::gt; } if (incl_limit) { diff -r 5bb91b0db2c9 -r b3a485ccfe86 src/share/vm/opto/parse.hpp --- a/src/share/vm/opto/parse.hpp Wed Jun 22 12:40:50 2011 -0700 +++ b/src/share/vm/opto/parse.hpp Thu Jun 23 22:43:22 2011 -0700 @@ -50,7 +50,7 @@ // Always between 0.0 and 1.0. Represents the percentage of the method's // total execution time used at this call site. const float _site_invoke_ratio; - const int _site_depth_adjust; + const int _max_inline_level; // the maximum inline level for this sub-tree (may be adjusted) float compute_callee_frequency( int caller_bci ) const; GrowableArray _subtrees; @@ -63,7 +63,7 @@ JVMState* caller_jvms, int caller_bci, float site_invoke_ratio, - int site_depth_adjust); + int max_inline_level); InlineTree *build_inline_tree_for_callee(ciMethod* callee_method, JVMState* caller_jvms, int caller_bci); @@ -74,7 +74,7 @@ InlineTree *caller_tree() const { return _caller_tree; } InlineTree* callee_at(int bci, ciMethod* m) const; - int inline_depth() const { return stack_depth() + _site_depth_adjust; } + int inline_level() const { return stack_depth(); } int stack_depth() const { return _caller_jvms ? _caller_jvms->depth() : 0; } public: @@ -82,7 +82,7 @@ static InlineTree* find_subtree_from_root(InlineTree* root, JVMState* jvms, ciMethod* callee, bool create_if_not_found = false); // For temporary (stack-allocated, stateless) ilts: - InlineTree(Compile* c, ciMethod* callee_method, JVMState* caller_jvms, float site_invoke_ratio, int site_depth_adjust); + InlineTree(Compile* c, ciMethod* callee_method, JVMState* caller_jvms, float site_invoke_ratio, int max_inline_level); // InlineTree enum enum InlineStyle { diff -r 5bb91b0db2c9 -r b3a485ccfe86 test/compiler/7052494/Test7052494.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/compiler/7052494/Test7052494.java Thu Jun 23 22:43:22 2011 -0700 @@ -0,0 +1,162 @@ +/* + * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +/** + * @test + * @bug 7052494 + * @summary Eclipse test fails on JDK 7 b142 + * + * @run main/othervm -Xbatch Test7052494 + */ + + +public class Test7052494 { + + static int test1(int i, int limit) { + int result = 0; + while (i++ != 0) { + if (result >= limit) + break; + result = i*2; + } + return result; + } + + static int test2(int i, int limit) { + int result = 0; + while (i-- != 0) { + if (result <= limit) + break; + result = i*2; + } + return result; + } + + static void test3(int i, int limit, int arr[]) { + while (i++ != 0) { + if (arr[i-1] >= limit) + break; + arr[i] = i*2; + } + } + + static void test4(int i, int limit, int arr[]) { + while (i-- != 0) { + if (arr[arr.length + i + 1] <= limit) + break; + arr[arr.length + i] = i*2; + } + } + + // Empty loop rolls through MAXINT if i > 0 + static int test5(int i) { + int result = 0; + while (i++ != 0) { + result = i*2; + } + return result; + } + + // Empty loop rolls through MININT if i < 0 + static int test6(int i) { + int result = 0; + while (i-- != 0) { + result = i*2; + } + return result; + } + + public static void main(String [] args) { + boolean failed = false; + int[] arr = new int[8]; + int[] ar3 = { 0, 0, 4, 6, 8, 10, 0, 0 }; + int[] ar4 = { 0, 0, 0, -10, -8, -6, -4, 0 }; + for (int i = 0; i < 11000; i++) { + int k = test1(1, 10); + if (k != 10) { + System.out.println("FAILED: " + k + " != 10"); + failed = true; + break; + } + } + for (int i = 0; i < 11000; i++) { + int k = test2(-1, -10); + if (k != -10) { + System.out.println("FAILED: " + k + " != -10"); + failed = true; + break; + } + } + for (int i = 0; i < 11000; i++) { + java.util.Arrays.fill(arr, 0); + test3(1, 10, arr); + if (!java.util.Arrays.equals(arr,ar3)) { + System.out.println("FAILED: arr = { " + arr[0] + ", " + + arr[1] + ", " + + arr[2] + ", " + + arr[3] + ", " + + arr[4] + ", " + + arr[5] + ", " + + arr[6] + ", " + + arr[7] + " }"); + failed = true; + break; + } + } + for (int i = 0; i < 11000; i++) { + java.util.Arrays.fill(arr, 0); + test4(-1, -10, arr); + if (!java.util.Arrays.equals(arr,ar4)) { + System.out.println("FAILED: arr = { " + arr[0] + ", " + + arr[1] + ", " + + arr[2] + ", " + + arr[3] + ", " + + arr[4] + ", " + + arr[5] + ", " + + arr[6] + ", " + + arr[7] + " }"); + failed = true; + break; + } + } + for (int i = 0; i < 11000; i++) { + int k = test5(1); + if (k != 0) { + System.out.println("FAILED: " + k + " != 0"); + failed = true; + break; + } + } + for (int i = 0; i < 11000; i++) { + int k = test6(-1); + if (k != 0) { + System.out.println("FAILED: " + k + " != 0"); + failed = true; + break; + } + } + if (failed) + System.exit(97); + } +}