# HG changeset patch # User never # Date 1305744306 25200 # Node ID 1be2f0c40a3443dc844a8763f705cbc4b3b2ee1d # Parent b79e8b4ecd76b15fd70cbada7c81a193373d0119# Parent 3f3325361b86c958d227cad5d53cf4c13cb1baa5 Merge diff -r 3f3325361b86 -r 1be2f0c40a34 agent/src/share/classes/sun/jvm/hotspot/CommandProcessor.java --- a/agent/src/share/classes/sun/jvm/hotspot/CommandProcessor.java Wed May 18 10:12:31 2011 -0400 +++ b/agent/src/share/classes/sun/jvm/hotspot/CommandProcessor.java Wed May 18 11:45:06 2011 -0700 @@ -1028,7 +1028,12 @@ if (AddressOps.equal(val, value)) { if (!printed) { printed = true; - blob.printOn(out); + try { + blob.printOn(out); + } catch (Exception e) { + out.println("Exception printing blob at " + base); + e.printStackTrace(); + } } out.println("found at " + base + "\n"); } diff -r 3f3325361b86 -r 1be2f0c40a34 agent/src/share/classes/sun/jvm/hotspot/code/AdapterBlob.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/agent/src/share/classes/sun/jvm/hotspot/code/AdapterBlob.java Wed May 18 11:45:06 2011 -0700 @@ -0,0 +1,58 @@ +/* + * 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. + * + */ + +package sun.jvm.hotspot.code; + +import java.util.*; +import sun.jvm.hotspot.debugger.*; +import sun.jvm.hotspot.runtime.*; +import sun.jvm.hotspot.types.*; + +public class AdapterBlob extends CodeBlob { + static { + VM.registerVMInitializedObserver(new Observer() { + public void update(Observable o, Object data) { + initialize(VM.getVM().getTypeDataBase()); + } + }); + } + + private static void initialize(TypeDataBase db) { + // Type type = db.lookupType("AdapterBlob"); + + // // FIXME: add any needed fields + } + + public AdapterBlob(Address addr) { + super(addr); + } + + public boolean isAdapterBlob() { + return true; + } + + public String getName() { + return "AdapterBlob: " + super.getName(); + } +} diff -r 3f3325361b86 -r 1be2f0c40a34 agent/src/share/classes/sun/jvm/hotspot/code/CodeBlob.java --- a/agent/src/share/classes/sun/jvm/hotspot/code/CodeBlob.java Wed May 18 10:12:31 2011 -0400 +++ b/agent/src/share/classes/sun/jvm/hotspot/code/CodeBlob.java Wed May 18 11:45:06 2011 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 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 @@ -93,6 +93,8 @@ public boolean isUncommonTrapStub() { return false; } public boolean isExceptionStub() { return false; } public boolean isSafepointStub() { return false; } + public boolean isRicochetBlob() { return false; } + public boolean isAdapterBlob() { return false; } // Fine grain nmethod support: isNmethod() == isJavaMethod() || isNativeMethod() || isOSRMethod() public boolean isJavaMethod() { return false; } diff -r 3f3325361b86 -r 1be2f0c40a34 agent/src/share/classes/sun/jvm/hotspot/code/CodeCache.java --- a/agent/src/share/classes/sun/jvm/hotspot/code/CodeCache.java Wed May 18 10:12:31 2011 -0400 +++ b/agent/src/share/classes/sun/jvm/hotspot/code/CodeCache.java Wed May 18 11:45:06 2011 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2005, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 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 @@ -57,6 +57,8 @@ virtualConstructor.addMapping("BufferBlob", BufferBlob.class); virtualConstructor.addMapping("nmethod", NMethod.class); virtualConstructor.addMapping("RuntimeStub", RuntimeStub.class); + virtualConstructor.addMapping("RicochetBlob", RicochetBlob.class); + virtualConstructor.addMapping("AdapterBlob", AdapterBlob.class); virtualConstructor.addMapping("SafepointBlob", SafepointBlob.class); virtualConstructor.addMapping("DeoptimizationBlob", DeoptimizationBlob.class); if (VM.getVM().isServerCompiler()) { diff -r 3f3325361b86 -r 1be2f0c40a34 agent/src/share/classes/sun/jvm/hotspot/code/RicochetBlob.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/agent/src/share/classes/sun/jvm/hotspot/code/RicochetBlob.java Wed May 18 11:45:06 2011 -0700 @@ -0,0 +1,56 @@ +/* + * 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. + * + */ + +package sun.jvm.hotspot.code; + +import java.util.*; +import sun.jvm.hotspot.debugger.*; +import sun.jvm.hotspot.runtime.*; +import sun.jvm.hotspot.types.*; + +/** RicochetBlob (currently only used by Compiler 2) */ + +public class RicochetBlob extends SingletonBlob { + static { + VM.registerVMInitializedObserver(new Observer() { + public void update(Observable o, Object data) { + initialize(VM.getVM().getTypeDataBase()); + } + }); + } + + private static void initialize(TypeDataBase db) { + // Type type = db.lookupType("RicochetBlob"); + + // FIXME: add any needed fields + } + + public RicochetBlob(Address addr) { + super(addr); + } + + public boolean isRicochetBlob() { + return true; + } +} diff -r 3f3325361b86 -r 1be2f0c40a34 src/cpu/x86/vm/methodHandles_x86.cpp --- a/src/cpu/x86/vm/methodHandles_x86.cpp Wed May 18 10:12:31 2011 -0400 +++ b/src/cpu/x86/vm/methodHandles_x86.cpp Wed May 18 11:45:06 2011 -0700 @@ -389,7 +389,7 @@ } } -#ifndef PRODUCT +#ifdef ASSERT void MethodHandles::RicochetFrame::verify_offsets() { // Check compatibility of this struct with the more generally used offsets of class frame: int ebp_off = sender_link_offset_in_bytes(); // offset from struct base to local rbp value diff -r 3f3325361b86 -r 1be2f0c40a34 src/share/vm/ci/ciMethodHandle.cpp --- a/src/share/vm/ci/ciMethodHandle.cpp Wed May 18 10:12:31 2011 -0400 +++ b/src/share/vm/ci/ciMethodHandle.cpp Wed May 18 11:45:06 2011 -0700 @@ -43,7 +43,7 @@ methodHandle callee(_callee->get_methodOop()); // We catch all exceptions here that could happen in the method // handle compiler and stop the VM. - MethodHandleCompiler mhc(h, callee, _profile->count(), is_invokedynamic, THREAD); + MethodHandleCompiler mhc(h, callee->name(), callee->signature(), _profile->count(), is_invokedynamic, THREAD); if (!HAS_PENDING_EXCEPTION) { methodHandle m = mhc.compile(THREAD); if (!HAS_PENDING_EXCEPTION) { diff -r 3f3325361b86 -r 1be2f0c40a34 src/share/vm/interpreter/bytecodeTracer.cpp --- a/src/share/vm/interpreter/bytecodeTracer.cpp Wed May 18 10:12:31 2011 -0400 +++ b/src/share/vm/interpreter/bytecodeTracer.cpp Wed May 18 11:45:06 2011 -0700 @@ -203,11 +203,14 @@ if (value == NULL) { st->print_cr(" NULL"); } else if (java_lang_String::is_instance(value)) { - EXCEPTION_MARK; - Handle h_value (THREAD, value); - Symbol* sym = java_lang_String::as_symbol(h_value, CATCH); - print_symbol(sym, st); - sym->decrement_refcount(); + char buf[40]; + int len = java_lang_String::utf8_length(value); + java_lang_String::as_utf8_string(value, buf, sizeof(buf)); + if (len >= (int)sizeof(buf)) { + st->print_cr(" %s...[%d]", buf, len); + } else { + st->print_cr(" %s", buf); + } } else { st->print_cr(" " PTR_FORMAT, (intptr_t) value); } diff -r 3f3325361b86 -r 1be2f0c40a34 src/share/vm/opto/idealGraphPrinter.cpp --- a/src/share/vm/opto/idealGraphPrinter.cpp Wed May 18 10:12:31 2011 -0400 +++ b/src/share/vm/opto/idealGraphPrinter.cpp Wed May 18 11:45:06 2011 -0700 @@ -615,6 +615,7 @@ } } +#ifdef ASSERT if (node->debug_orig() != NULL) { stringStream dorigStream; Node* dorig = node->debug_orig(); @@ -629,6 +630,7 @@ } print_prop("debug_orig", dorigStream.as_string()); } +#endif if (_chaitin && _chaitin != (PhaseChaitin *)0xdeadbeef) { buffer[0] = 0; diff -r 3f3325361b86 -r 1be2f0c40a34 src/share/vm/opto/loopTransform.cpp --- a/src/share/vm/opto/loopTransform.cpp Wed May 18 10:12:31 2011 -0400 +++ b/src/share/vm/opto/loopTransform.cpp Wed May 18 11:45:06 2011 -0700 @@ -1453,6 +1453,23 @@ return _phase->dom_lca_internal(ctrl, backedge) == ctrl; } +//------------------------------adjust_limit----------------------------------- +// Helper function for add_constraint(). +Node* PhaseIdealLoop::adjust_limit(int stride_con, Node * scale, Node *offset, Node *rc_limit, Node *loop_limit, Node *pre_ctrl) { + // Compute "I :: (limit-offset)/scale" + Node *con = new (C, 3) SubINode(rc_limit, offset); + register_new_node(con, pre_ctrl); + Node *X = new (C, 3) DivINode(0, con, scale); + register_new_node(X, pre_ctrl); + + // Adjust loop limit + loop_limit = (stride_con > 0) + ? (Node*)(new (C, 3) MinINode(loop_limit, X)) + : (Node*)(new (C, 3) MaxINode(loop_limit, X)); + register_new_node(loop_limit, pre_ctrl); + return loop_limit; +} + //------------------------------add_constraint--------------------------------- // Constrain the main loop iterations so the conditions: // low_limit <= scale_con * I + offset < upper_limit @@ -1469,7 +1486,11 @@ // pre-loop must check for underflow and the post-loop for overflow. // Negative stride*scale reverses this; pre-loop checks for overflow and // post-loop for underflow. - if (stride_con*scale_con > 0) { + + Node *scale = _igvn.intcon(scale_con); + set_ctrl(scale, C->root()); + + if ((stride_con^scale_con) >= 0) { // Use XOR to avoid overflow // The overflow limit: scale*I+offset < upper_limit // For main-loop compute // ( if (scale > 0) /* and stride > 0 */ @@ -1478,23 +1499,10 @@ // I > (upper_limit-offset)/scale // ) // - // (upper_limit-offset) may overflow when offset < 0. + // (upper_limit-offset) may overflow or underflow. // But it is fine since main loop will either have // less iterations or will be skipped in such case. - Node *con = new (C, 3) SubINode(upper_limit, offset); - register_new_node(con, pre_ctrl); - Node *scale = _igvn.intcon(scale_con); - set_ctrl(scale, C->root()); - Node *X = new (C, 3) DivINode(0, con, scale); - register_new_node(X, pre_ctrl); - - // Adjust main-loop last iteration - Node *loop_limit = *main_limit; - loop_limit = (stride_con > 0) // scale > 0 - ? (Node*)(new (C, 3) MinINode(loop_limit, X)) - : (Node*)(new (C, 3) MaxINode(loop_limit, X)); - register_new_node(loop_limit, pre_ctrl); - *main_limit = loop_limit; + *main_limit = adjust_limit(stride_con, scale, offset, upper_limit, *main_limit, pre_ctrl); // The underflow limit: low_limit <= scale*I+offset. // For pre-loop compute @@ -1509,76 +1517,33 @@ if (low_limit->get_int() == -max_jint) { if (!RangeLimitCheck) return; // We need this guard when scale*pre_limit+offset >= limit - // due to underflow so we need execute pre-loop until - // scale*I+offset >= min_int. But (low_limit-offset) will - // underflow when offset > 0 and X will be > original_limit. - // To avoid it we replace offset = offset > 0 ? 0 : offset - // and add min(pre_limit, original_limit). + // due to underflow. So we need execute pre-loop until + // scale*I+offset >= min_int. But (min_int-offset) will + // underflow when offset > 0 and X will be > original_limit + // when stride > 0. To avoid it we replace positive offset with 0. + // + // Also (min_int+1 == -max_int) is used instead of min_int here + // to avoid problem with scale == -1 (min_int/(-1) == min_int). Node* shift = _igvn.intcon(31); set_ctrl(shift, C->root()); - Node *neg_off = new (C, 3) RShiftINode(offset, shift); - register_new_node(neg_off, pre_ctrl); - offset = new (C, 3) AndINode(offset, neg_off); + Node* sign = new (C, 3) RShiftINode(offset, shift); + register_new_node(sign, pre_ctrl); + offset = new (C, 3) AndINode(offset, sign); register_new_node(offset, pre_ctrl); } else { assert(low_limit->get_int() == 0, "wrong low limit for range check"); // The only problem we have here when offset == min_int - // since (0-min_int) == min_int. It may be fine for scale > 0 - // but for scale < 0 X will be < original_limit. + // since (0-min_int) == min_int. It may be fine for stride > 0 + // but for stride < 0 X will be < original_limit. To avoid it + // max(pre_limit, original_limit) is used in do_range_check(). } - con = new (C, 3) SubINode(low_limit, offset); - register_new_node(con, pre_ctrl); - scale = _igvn.intcon(scale_con); - set_ctrl(scale, C->root()); - X = new (C, 3) DivINode(0, con, scale); - register_new_node(X, pre_ctrl); - - // Adjust pre-loop last iteration - loop_limit = *pre_limit; - loop_limit = (stride_con > 0) // scale > 0 - ? (Node*)(new (C, 3) MaxINode(loop_limit, X)) - : (Node*)(new (C, 3) MinINode(loop_limit, X)); - register_new_node( loop_limit, pre_ctrl ); - *pre_limit = loop_limit; + // Pass (-stride) to indicate pre_loop_cond = NOT(main_loop_cond); + *pre_limit = adjust_limit((-stride_con), scale, offset, low_limit, *pre_limit, pre_ctrl); } else { // stride_con*scale_con < 0 // For negative stride*scale pre-loop checks for overflow and // post-loop for underflow. // - // The underflow limit: low_limit <= scale*I+offset. - // For main-loop compute - // scale*I+offset+1 > low_limit - // ( if (scale < 0) /* and stride > 0 */ - // I < (low_limit-(offset+1))/scale - // else /* scale < 0 and stride < 0 */ - // I > (low_limit-(offset+1))/scale - // ) - - if (low_limit->get_int() == -max_jint) { - if (!RangeLimitCheck) return; - } else { - assert(low_limit->get_int() == 0, "wrong low limit for range check"); - } - - Node *one = _igvn.intcon(1); - set_ctrl(one, C->root()); - Node *plus_one = new (C, 3) AddINode(offset, one); - register_new_node( plus_one, pre_ctrl ); - Node *con = new (C, 3) SubINode(low_limit, plus_one); - register_new_node(con, pre_ctrl); - Node *scale = _igvn.intcon(scale_con); - set_ctrl(scale, C->root()); - Node *X = new (C, 3) DivINode(0, con, scale); - register_new_node(X, pre_ctrl); - - // Adjust main-loop last iteration - Node *loop_limit = *main_limit; - loop_limit = (stride_con > 0) // scale < 0 - ? (Node*)(new (C, 3) MinINode(loop_limit, X)) - : (Node*)(new (C, 3) MaxINode(loop_limit, X)); - register_new_node(loop_limit, pre_ctrl); - *main_limit = loop_limit; - // The overflow limit: scale*I+offset < upper_limit // For pre-loop compute // NOT(scale*I+offset < upper_limit) @@ -1586,26 +1551,55 @@ // scale*I+offset+1 > upper_limit // ( if (scale < 0) /* and stride > 0 */ // I < (upper_limit-(offset+1))/scale - // else /* scale < 0 and stride < 0 */ + // else /* scale > 0 and stride < 0 */ // I > (upper_limit-(offset+1))/scale // ) - plus_one = new (C, 3) AddINode(offset, one); + // + // (upper_limit-offset-1) may underflow or overflow. + // To avoid it min(pre_limit, original_limit) is used + // in do_range_check() for stride > 0 and max() for < 0. + Node *one = _igvn.intcon(1); + set_ctrl(one, C->root()); + + Node *plus_one = new (C, 3) AddINode(offset, one); register_new_node( plus_one, pre_ctrl ); - con = new (C, 3) SubINode(upper_limit, plus_one); - register_new_node(con, pre_ctrl); - scale = _igvn.intcon(scale_con); - set_ctrl(scale, C->root()); - X = new (C, 3) DivINode(0, con, scale); - register_new_node(X, pre_ctrl); + // Pass (-stride) to indicate pre_loop_cond = NOT(main_loop_cond); + *pre_limit = adjust_limit((-stride_con), scale, plus_one, upper_limit, *pre_limit, pre_ctrl); - // Adjust pre-loop last iteration - loop_limit = *pre_limit; - loop_limit = (stride_con > 0) // scale < 0 - ? (Node*)(new (C, 3) MaxINode(loop_limit, X)) - : (Node*)(new (C, 3) MinINode(loop_limit, X)); - register_new_node( loop_limit, pre_ctrl ); - *pre_limit = loop_limit; + if (low_limit->get_int() == -max_jint) { + if (!RangeLimitCheck) return; + // We need this guard when scale*main_limit+offset >= limit + // due to underflow. So we need execute main-loop while + // scale*I+offset+1 > min_int. But (min_int-offset-1) will + // underflow when (offset+1) > 0 and X will be < main_limit + // when scale < 0 (and stride > 0). To avoid it we replace + // positive (offset+1) with 0. + // + // Also (min_int+1 == -max_int) is used instead of min_int here + // to avoid problem with scale == -1 (min_int/(-1) == min_int). + Node* shift = _igvn.intcon(31); + set_ctrl(shift, C->root()); + Node* sign = new (C, 3) RShiftINode(plus_one, shift); + register_new_node(sign, pre_ctrl); + plus_one = new (C, 3) AndINode(plus_one, sign); + register_new_node(plus_one, pre_ctrl); + } else { + assert(low_limit->get_int() == 0, "wrong low limit for range check"); + // The only problem we have here when offset == max_int + // since (max_int+1) == min_int and (0-min_int) == min_int. + // But it is fine since main loop will either have + // less iterations or will be skipped in such case. + } + // The underflow limit: low_limit <= scale*I+offset. + // For main-loop compute + // scale*I+offset+1 > low_limit + // ( if (scale < 0) /* and stride > 0 */ + // I < (low_limit-(offset+1))/scale + // else /* scale > 0 and stride < 0 */ + // I > (low_limit-(offset+1))/scale + // ) + *main_limit = adjust_limit(stride_con, scale, plus_one, low_limit, *main_limit, pre_ctrl); } } @@ -1869,13 +1863,8 @@ // The underflow and overflow limits: 0 <= scale*I+offset < limit add_constraint( stride_con, scale_con, offset, zero, limit, pre_ctrl, &pre_limit, &main_limit ); if (!conditional_rc) { - conditional_rc = !loop->dominates_backedge(iff); - // It is also needed if offset->_lo == min_int since - // (0-min_int) == min_int. It may be fine for stride > 0 - // but for stride < 0 pre_limit will be < original_limit. - const TypeInt* offset_t = _igvn.type(offset)->is_int(); - conditional_rc |= RangeLimitCheck && (offset_t->_lo == min_jint) && - (scale_con<0) && (stride_con<0); + // (0-offset)/scale could be outside of loop iterations range. + conditional_rc = !loop->dominates_backedge(iff) || RangeLimitCheck; } } else { #ifndef PRODUCT @@ -1905,16 +1894,14 @@ // Fall into LT case case BoolTest::lt: // The underflow and overflow limits: MIN_INT <= scale*I+offset < limit + // Note: (MIN_INT+1 == -MAX_INT) is used instead of MIN_INT here + // to avoid problem with scale == -1: MIN_INT/(-1) == MIN_INT. add_constraint( stride_con, scale_con, offset, mini, limit, pre_ctrl, &pre_limit, &main_limit ); if (!conditional_rc) { - conditional_rc = !loop->dominates_backedge(iff); - // It is also needed if scale*pre_limit+offset >= limit - // due to underflow so we need execute pre-loop until - // scale*I+offset >= min_int. But (low_limit-offset) will - // underflow when offset > 0 and X will be > original_limit. - const TypeInt* offset_t = _igvn.type(offset)->is_int(); - conditional_rc |= RangeLimitCheck && (offset_t->_hi > 0) && - (scale_con>0) && (stride_con>0); + // ((MIN_INT+1)-offset)/scale could be outside of loop iterations range. + // Note: negative offset is replaced with 0 but (MIN_INT+1)/scale could + // still be outside of loop range. + conditional_rc = !loop->dominates_backedge(iff) || RangeLimitCheck; } break; default: diff -r 3f3325361b86 -r 1be2f0c40a34 src/share/vm/opto/loopnode.hpp --- a/src/share/vm/opto/loopnode.hpp Wed May 18 10:12:31 2011 -0400 +++ b/src/share/vm/opto/loopnode.hpp Wed May 18 11:45:06 2011 -0700 @@ -932,6 +932,8 @@ // the pre-loop or the post-loop until the condition holds true in the main // loop. Scale_con, offset and limit are all loop invariant. void add_constraint( int stride_con, int scale_con, Node *offset, Node *low_limit, Node *upper_limit, Node *pre_ctrl, Node **pre_limit, Node **main_limit ); + // Helper function for add_constraint(). + Node* adjust_limit( int stride_con, Node * scale, Node *offset, Node *rc_limit, Node *loop_limit, Node *pre_ctrl ); // Partially peel loop up through last_peel node. bool partial_peel( IdealLoopTree *loop, Node_List &old_new ); diff -r 3f3325361b86 -r 1be2f0c40a34 src/share/vm/prims/methodHandleWalk.cpp --- a/src/share/vm/prims/methodHandleWalk.cpp Wed May 18 10:12:31 2011 -0400 +++ b/src/share/vm/prims/methodHandleWalk.cpp Wed May 18 11:45:06 2011 -0700 @@ -265,7 +265,7 @@ assert(dest == arg_state->_type, ""); ArgToken arg = arg_state->_arg; ArgToken new_arg = make_conversion(T_OBJECT, dest_klass, Bytecodes::_checkcast, arg, CHECK_(empty)); - assert(arg.token_type() >= tt_symbolic || arg.index() == new_arg.index(), "should be the same index"); + assert(!arg.has_index() || arg.index() == new_arg.index(), "should be the same index"); debug_only(dest_klass = (klassOop)badOop); break; } @@ -423,6 +423,7 @@ arglist[1+i] = arg; if (!retain_original_args) change_argument(arg_type, slot, T_VOID, ArgToken(tt_void)); + i++; } arglist[1+argc] = ArgToken(); // sentinel oop invoker = java_lang_invoke_MethodTypeForm::vmlayout( @@ -442,8 +443,10 @@ ret = make_conversion(T_OBJECT, rklass, Bytecodes::_checkcast, ret, CHECK_(empty)); } } - int ret_slot = arg_slot + (retain_original_args ? coll_slots : 0); - change_argument(T_VOID, ret_slot, rtype, ret); + if (rtype != T_VOID) { + int ret_slot = arg_slot + (retain_original_args ? coll_slots : 0); + change_argument(T_VOID, ret_slot, rtype, ret); + } break; } @@ -487,7 +490,7 @@ arglist[1] = length_arg; // length to check arglist[2] = ArgToken(); // sentinel make_invoke(NULL, vmIntrinsics::_checkSpreadArgument, - Bytecodes::_invokestatic, false, 3, &arglist[0], CHECK_(empty)); + Bytecodes::_invokestatic, false, 2, &arglist[0], CHECK_(empty)); // Spread out the array elements. Bytecodes::Code aload_op = Bytecodes::_nop; @@ -689,9 +692,8 @@ // ----------------------------------------------------------------------------- // MethodHandleCompiler -MethodHandleCompiler::MethodHandleCompiler(Handle root, methodHandle callee, int invoke_count, bool is_invokedynamic, TRAPS) +MethodHandleCompiler::MethodHandleCompiler(Handle root, Symbol* name, Symbol* signature, int invoke_count, bool is_invokedynamic, TRAPS) : MethodHandleWalker(root, is_invokedynamic, THREAD), - _callee(callee), _invoke_count(invoke_count), _thread(THREAD), _bytecode(THREAD, 50), @@ -705,8 +707,8 @@ (void) _constants.append(NULL); // Set name and signature index. - _name_index = cpool_symbol_put(_callee->name()); - _signature_index = cpool_symbol_put(_callee->signature()); + _name_index = cpool_symbol_put(name); + _signature_index = cpool_symbol_put(signature); // Get return type klass. Handle first_mtype(THREAD, chain().method_type_oop()); @@ -714,7 +716,8 @@ _rtype = java_lang_Class::as_BasicType(java_lang_invoke_MethodType::rtype(first_mtype()), &_rklass); if (_rtype == T_ARRAY) _rtype = T_OBJECT; - int params = _callee->size_of_parameters(); // Incoming arguments plus receiver. + ArgumentSizeComputer args(signature); + int params = args.size() + 1; // Incoming arguments plus receiver. _num_params = for_invokedynamic() ? params - 1 : params; // XXX Check if callee is static? } @@ -732,7 +735,7 @@ } -void MethodHandleCompiler::emit_bc(Bytecodes::Code op, int index) { +void MethodHandleCompiler::emit_bc(Bytecodes::Code op, int index, int args_size) { Bytecodes::check(op); // Are we legal? switch (op) { @@ -808,6 +811,14 @@ case Bytecodes::_d2i: case Bytecodes::_d2l: case Bytecodes::_d2f: + case Bytecodes::_iaload: + case Bytecodes::_laload: + case Bytecodes::_faload: + case Bytecodes::_daload: + case Bytecodes::_aaload: + case Bytecodes::_baload: + case Bytecodes::_caload: + case Bytecodes::_saload: case Bytecodes::_ireturn: case Bytecodes::_lreturn: case Bytecodes::_freturn: @@ -821,9 +832,14 @@ // bi case Bytecodes::_ldc: assert(Bytecodes::format_bits(op, false) == (Bytecodes::_fmt_b|Bytecodes::_fmt_has_k), "wrong bytecode format"); - assert((char) index == index, "index does not fit in 8-bit"); - _bytecode.push(op); - _bytecode.push(index); + if (index == (index & 0xff)) { + _bytecode.push(op); + _bytecode.push(index); + } else { + _bytecode.push(Bytecodes::_ldc_w); + _bytecode.push(index >> 8); + _bytecode.push(index); + } break; case Bytecodes::_iload: @@ -837,9 +853,16 @@ case Bytecodes::_dstore: case Bytecodes::_astore: assert(Bytecodes::format_bits(op, false) == Bytecodes::_fmt_bi, "wrong bytecode format"); - assert((char) index == index, "index does not fit in 8-bit"); - _bytecode.push(op); - _bytecode.push(index); + if (index == (index & 0xff)) { + _bytecode.push(op); + _bytecode.push(index); + } else { + // doesn't fit in a u2 + _bytecode.push(Bytecodes::_wide); + _bytecode.push(op); + _bytecode.push(index >> 8); + _bytecode.push(index); + } break; // bkk @@ -847,7 +870,7 @@ case Bytecodes::_ldc2_w: case Bytecodes::_checkcast: assert(Bytecodes::format_bits(op, false) == Bytecodes::_fmt_bkk, "wrong bytecode format"); - assert((short) index == index, "index does not fit in 16-bit"); + assert((unsigned short) index == index, "index does not fit in 16-bit"); _bytecode.push(op); _bytecode.push(index >> 8); _bytecode.push(index); @@ -858,12 +881,23 @@ case Bytecodes::_invokespecial: case Bytecodes::_invokevirtual: assert(Bytecodes::format_bits(op, false) == Bytecodes::_fmt_bJJ, "wrong bytecode format"); - assert((short) index == index, "index does not fit in 16-bit"); + assert((unsigned short) index == index, "index does not fit in 16-bit"); _bytecode.push(op); _bytecode.push(index >> 8); _bytecode.push(index); break; + case Bytecodes::_invokeinterface: + assert(Bytecodes::format_bits(op, false) == Bytecodes::_fmt_bJJ, "wrong bytecode format"); + assert((unsigned short) index == index, "index does not fit in 16-bit"); + assert(args_size > 0, "valid args_size"); + _bytecode.push(op); + _bytecode.push(index >> 8); + _bytecode.push(index); + _bytecode.push(args_size); + _bytecode.push(0); + break; + default: ShouldNotReachHere(); } @@ -982,7 +1016,8 @@ const ArgToken& src, TRAPS) { BasicType srctype = src.basic_type(); - int index = src.index(); + TokenType tt = src.token_type(); + int index = -1; switch (op) { case Bytecodes::_i2l: @@ -1003,18 +1038,31 @@ case Bytecodes::_d2i: case Bytecodes::_d2l: case Bytecodes::_d2f: - emit_load(srctype, index); + if (tt == tt_constant) { + emit_load_constant(src); + } else { + emit_load(srctype, src.index()); + } stack_pop(srctype); // pop the src type emit_bc(op); stack_push(type); // push the dest value - if (srctype != type) + if (tt != tt_constant) + index = src.index(); + if (srctype != type || index == -1) index = new_local_index(type); emit_store(type, index); break; case Bytecodes::_checkcast: - emit_load(srctype, index); + if (tt == tt_constant) { + emit_load_constant(src); + } else { + emit_load(srctype, src.index()); + index = src.index(); + } emit_bc(op, cpool_klass_put(tk)); + if (index == -1) + index = new_local_index(type); emit_store(srctype, index); break; @@ -1057,6 +1105,11 @@ Symbol* name = m->name(); Symbol* signature = m->signature(); + // Count the number of arguments, not the size + ArgumentCount asc(signature); + assert(argc == asc.size() + ((op == Bytecodes::_invokestatic || op == Bytecodes::_invokedynamic) ? 0 : 1), + "argc mismatch"); + if (tailcall) { // Actually, in order to make these methods more recognizable, // let's put them in holder class MethodHandle. That way stack @@ -1105,9 +1158,13 @@ case Bytecodes::_invokevirtual: emit_bc(op, methodref_index); break; - case Bytecodes::_invokeinterface: - Unimplemented(); + + case Bytecodes::_invokeinterface: { + ArgumentSizeComputer asc(signature); + emit_bc(op, methodref_index, asc.size() + 1); break; + } + default: ShouldNotReachHere(); } @@ -1116,6 +1173,7 @@ // Otherwise, make a recursive call to some helper routine. BasicType rbt = m->result_type(); if (rbt == T_ARRAY) rbt = T_OBJECT; + stack_push(rbt); // The return value is already pushed onto the stack. ArgToken ret; if (tailcall) { if (rbt != _rtype) { @@ -1170,7 +1228,6 @@ ret = ArgToken(); // Dummy return value. } else { - stack_push(rbt); // The return value is already pushed onto the stack. int index = new_local_index(rbt); switch (rbt) { case T_BOOLEAN: case T_BYTE: case T_CHAR: case T_SHORT: @@ -1195,8 +1252,32 @@ const MethodHandleWalker::ArgToken& base, const MethodHandleWalker::ArgToken& offset, TRAPS) { - Unimplemented(); - return ArgToken(); + switch (base.token_type()) { + case tt_parameter: + case tt_temporary: + emit_load(base.basic_type(), base.index()); + break; + case tt_constant: + emit_load_constant(base); + break; + default: + ShouldNotReachHere(); + } + switch (offset.token_type()) { + case tt_parameter: + case tt_temporary: + emit_load(offset.basic_type(), offset.index()); + break; + case tt_constant: + emit_load_constant(offset); + break; + default: + ShouldNotReachHere(); + } + emit_bc(op); + int index = new_local_index(type); + emit_store(type, index); + return ArgToken(tt_temporary, type, index); } @@ -1371,12 +1452,10 @@ return s; } ArgToken token(const char* str) { - jvalue string_con; - string_con.j = (intptr_t) str; - return ArgToken(tt_symbolic, T_LONG, string_con); + return ArgToken(str); } const char* string(ArgToken token) { - return (const char*) (intptr_t) token.get_jlong(); + return token.str(); } void start_params() { _param_state <<= 1; diff -r 3f3325361b86 -r 1be2f0c40a34 src/share/vm/prims/methodHandleWalk.hpp --- a/src/share/vm/prims/methodHandleWalk.hpp Wed May 18 10:12:31 2011 -0400 +++ b/src/share/vm/prims/methodHandleWalk.hpp Wed May 18 11:45:06 2011 -0700 @@ -126,26 +126,34 @@ Handle _handle; public: - ArgToken(TokenType tt = tt_illegal) : _tt(tt) {} - ArgToken(TokenType tt, BasicType bt, jvalue value) : _tt(tt), _bt(bt), _value(value) {} + ArgToken(TokenType tt = tt_illegal) : _tt(tt) { + assert(tt == tt_illegal || tt == tt_void, "invalid token type"); + } ArgToken(TokenType tt, BasicType bt, int index) : _tt(tt), _bt(bt) { + assert(_tt == tt_parameter || _tt == tt_temporary, "must have index"); _value.i = index; } - ArgToken(TokenType tt, BasicType bt, Handle value) : _tt(tt), _bt(bt) { - _handle = value; + ArgToken(BasicType bt, jvalue value) : _tt(tt_constant), _bt(bt), _value(value) {} + ArgToken(BasicType bt, Handle value) : _tt(tt_constant), _bt(bt), _handle(value) {} + + + ArgToken(const char* str) : _tt(tt_symbolic), _bt(T_LONG) { + _value.j = (intptr_t)str; } TokenType token_type() const { return _tt; } BasicType basic_type() const { return _bt; } - int index() const { return _value.i; } - Handle object() const { return _handle; } + bool has_index() const { return _tt == tt_parameter || _tt == tt_temporary; } + int index() const { assert(has_index(), "must have index");; return _value.i; } + Handle object() const { assert(_tt == tt_constant, "value type"); return _handle; } + const char* str() const { assert(_tt == tt_symbolic, "string type"); return (const char*)_value.j; } - jint get_jint() const { return _value.i; } - jlong get_jlong() const { return _value.j; } - jfloat get_jfloat() const { return _value.f; } - jdouble get_jdouble() const { return _value.d; } + jint get_jint() const { assert(_tt == tt_constant, "value types"); return _value.i; } + jlong get_jlong() const { assert(_tt == tt_constant, "value types"); return _value.j; } + jfloat get_jfloat() const { assert(_tt == tt_constant, "value types"); return _value.f; } + jdouble get_jdouble() const { assert(_tt == tt_constant, "value types"); return _value.d; } }; // Abstract interpretation state: @@ -256,7 +264,6 @@ // The IR happens to be JVM bytecodes. class MethodHandleCompiler : public MethodHandleWalker { private: - methodHandle _callee; int _invoke_count; // count the original call site has been executed KlassHandle _rklass; // Return type for casting. BasicType _rtype; @@ -404,7 +411,7 @@ return cpool_oop_reference_put(JVM_CONSTANT_NameAndType, name_index, signature_index); } - void emit_bc(Bytecodes::Code op, int index = 0); + void emit_bc(Bytecodes::Code op, int index = 0, int args_size = -1); void emit_load(BasicType bt, int index); void emit_store(BasicType bt, int index); void emit_load_constant(ArgToken arg); @@ -414,10 +421,10 @@ } virtual ArgToken make_oop_constant(oop con, TRAPS) { Handle h(THREAD, con); - return ArgToken(tt_constant, T_OBJECT, h); + return ArgToken(T_OBJECT, h); } virtual ArgToken make_prim_constant(BasicType type, jvalue* con, TRAPS) { - return ArgToken(tt_constant, type, *con); + return ArgToken(type, *con); } virtual ArgToken make_conversion(BasicType type, klassOop tk, Bytecodes::Code op, const ArgToken& src, TRAPS); @@ -431,7 +438,7 @@ methodHandle get_method_oop(TRAPS) const; public: - MethodHandleCompiler(Handle root, methodHandle callee, int invoke_count, bool for_invokedynamic, TRAPS); + MethodHandleCompiler(Handle root, Symbol* name, Symbol* signature, int invoke_count, bool for_invokedynamic, TRAPS); // Compile the given MH chain into bytecode. methodHandle compile(TRAPS); diff -r 3f3325361b86 -r 1be2f0c40a34 src/share/vm/prims/methodHandles.cpp --- a/src/share/vm/prims/methodHandles.cpp Wed May 18 10:12:31 2011 -0400 +++ b/src/share/vm/prims/methodHandles.cpp Wed May 18 11:45:06 2011 -0700 @@ -25,9 +25,11 @@ #include "precompiled.hpp" #include "classfile/symbolTable.hpp" #include "interpreter/interpreter.hpp" +#include "interpreter/oopMapCache.hpp" #include "memory/allocation.inline.hpp" #include "memory/oopFactory.hpp" #include "prims/methodHandles.hpp" +#include "prims/methodHandleWalk.hpp" #include "runtime/javaCalls.hpp" #include "runtime/reflection.hpp" #include "runtime/signature.hpp" @@ -2599,6 +2601,50 @@ } } +#ifdef ASSERT + +extern "C" +void print_method_handle(oop mh); + +static void stress_method_handle_walk_impl(Handle mh, TRAPS) { + if (StressMethodHandleWalk) { + // Exercise the MethodHandleWalk code in various ways and validate + // the resulting method oop. Some of these produce output so they + // are guarded under Verbose. + ResourceMark rm; + HandleMark hm; + if (Verbose) { + print_method_handle(mh()); + } + TempNewSymbol name = SymbolTable::new_symbol("invoke", CHECK); + Handle mt = java_lang_invoke_MethodHandle::type(mh()); + TempNewSymbol signature = java_lang_invoke_MethodType::as_signature(mt(), true, CHECK); + MethodHandleCompiler mhc(mh, name, signature, 10000, false, CHECK); + methodHandle m = mhc.compile(CHECK); + if (Verbose) { + m->print_codes(); + } + InterpreterOopMap mask; + OopMapCache::compute_one_oop_map(m, m->code_size() - 1, &mask); + } +} + +static void stress_method_handle_walk(Handle mh, TRAPS) { + stress_method_handle_walk_impl(mh, THREAD); + if (HAS_PENDING_EXCEPTION) { + oop ex = PENDING_EXCEPTION; + CLEAR_PENDING_EXCEPTION; + tty->print("StressMethodHandleWalk: "); + java_lang_Throwable::print(ex, tty); + tty->cr(); + } +} +#else + +static void stress_method_handle_walk(Handle mh, TRAPS) {} + +#endif + // // Here are the native methods on sun.invoke.MethodHandleImpl. // They are the private interface between this JVM and the HotSpot-specific @@ -2666,6 +2712,7 @@ } MethodHandles::init_DirectMethodHandle(mh, m, (do_dispatch != JNI_FALSE), CHECK); + stress_method_handle_walk(mh, CHECK); } JVM_END @@ -2694,11 +2741,11 @@ receiver_limit, decode_flags, CHECK); - return; + } else { + // Build a BMH on top of a DMH or another BMH: + MethodHandles::init_BoundMethodHandle(mh, target, argnum, CHECK); } - - // Build a BMH on top of a DMH or another BMH: - MethodHandles::init_BoundMethodHandle(mh, target, argnum, CHECK); + stress_method_handle_walk(mh, CHECK); } JVM_END @@ -2716,6 +2763,7 @@ assert(java_lang_invoke_MethodHandle::vmentry(mh()) == NULL, "must be safely null"); MethodHandles::init_AdapterMethodHandle(mh, target, argnum, CHECK); + stress_method_handle_walk(mh, CHECK); } JVM_END @@ -2922,6 +2970,20 @@ } JVM_END +JVM_ENTRY(jobject, MH_invoke_UOE(JNIEnv *env, jobject igmh, jobjectArray igargs)) { + TempNewSymbol UOE_name = SymbolTable::new_symbol("java/lang/UnsupportedOperationException", CHECK_NULL); + THROW_MSG_NULL(UOE_name, "MethodHandle.invoke cannot be invoked reflectively"); + return NULL; +} +JVM_END + +JVM_ENTRY(jobject, MH_invokeExact_UOE(JNIEnv *env, jobject igmh, jobjectArray igargs)) { + TempNewSymbol UOE_name = SymbolTable::new_symbol("java/lang/UnsupportedOperationException", CHECK_NULL); + THROW_MSG_NULL(UOE_name, "MethodHandle.invokeExact cannot be invoked reflectively"); + return NULL; +} +JVM_END + /// JVM_RegisterMethodHandleMethods @@ -2960,6 +3022,12 @@ {CC"getMembers", CC"("CLS""STRG""STRG"I"CLS"I["MEM")I", FN_PTR(MHN_getMembers)} }; +static JNINativeMethod invoke_methods[] = { + // void init(MemberName self, AccessibleObject ref) + {CC"invoke", CC"(["OBJ")"OBJ, FN_PTR(MH_invoke_UOE)}, + {CC"invokeExact", CC"(["OBJ")"OBJ, FN_PTR(MH_invokeExact_UOE)} +}; + // This one function is exported, used by NativeLookup. JVM_ENTRY(void, JVM_RegisterMethodHandleMethods(JNIEnv *env, jclass MHN_class)) { @@ -2976,6 +3044,12 @@ ThreadToNativeFromVM ttnfv(thread); int status = env->RegisterNatives(MHN_class, methods, sizeof(methods)/sizeof(JNINativeMethod)); + if (!env->ExceptionOccurred()) { + const char* L_MH_name = (JLINV "MethodHandle"); + const char* MH_name = L_MH_name+1; + jclass MH_class = env->FindClass(MH_name); + status = env->RegisterNatives(MH_class, invoke_methods, sizeof(invoke_methods)/sizeof(JNINativeMethod)); + } if (env->ExceptionOccurred()) { MethodHandles::set_enabled(false); warning("JSR 292 method handle code is mismatched to this JVM. Disabling support."); diff -r 3f3325361b86 -r 1be2f0c40a34 src/share/vm/prims/methodHandles.hpp --- a/src/share/vm/prims/methodHandles.hpp Wed May 18 10:12:31 2011 -0400 +++ b/src/share/vm/prims/methodHandles.hpp Wed May 18 11:45:06 2011 -0700 @@ -721,12 +721,10 @@ //# include "methodHandles_zero.hpp" #endif #ifdef TARGET_ARCH_arm -#define TARGET_ARCH_NYI_6939861 1 //FIXME -//# include "methodHandles_arm.hpp" +# include "methodHandles_arm.hpp" #endif #ifdef TARGET_ARCH_ppc -#define TARGET_ARCH_NYI_6939861 1 //FIXME -//# include "methodHandles_ppc.hpp" +# include "methodHandles_ppc.hpp" #endif #ifdef TARGET_ARCH_NYI_6939861 diff -r 3f3325361b86 -r 1be2f0c40a34 src/share/vm/runtime/globals.hpp --- a/src/share/vm/runtime/globals.hpp Wed May 18 10:12:31 2011 -0400 +++ b/src/share/vm/runtime/globals.hpp Wed May 18 11:45:06 2011 -0700 @@ -2909,6 +2909,12 @@ product(intx, NmethodSweepCheckInterval, 5, \ "Compilers wake up every n seconds to possibly sweep nmethods") \ \ + notproduct(bool, LogSweeper, false, \ + "Keep a ring buffer of sweeper activity") \ + \ + notproduct(intx, SweeperLogEntries, 1024, \ + "Number of records in the ring buffer of sweeper activity") \ + \ notproduct(intx, MemProfilingInterval, 500, \ "Time between each invocation of the MemProfiler") \ \ @@ -3718,6 +3724,9 @@ diagnostic(bool, OptimizeMethodHandles, true, \ "when constructing method handles, try to improve them") \ \ + develop(bool, StressMethodHandleWalk, false, \ + "Process all method handles with MethodHandleWalk") \ + \ diagnostic(bool, UseRicochetFrames, true, \ "use ricochet stack frames for method handle combination, " \ "if the platform supports them") \ diff -r 3f3325361b86 -r 1be2f0c40a34 src/share/vm/runtime/sweeper.cpp --- a/src/share/vm/runtime/sweeper.cpp Wed May 18 10:12:31 2011 -0400 +++ b/src/share/vm/runtime/sweeper.cpp Wed May 18 11:45:06 2011 -0700 @@ -37,6 +37,94 @@ #include "utilities/events.hpp" #include "utilities/xmlstream.hpp" +#ifdef ASSERT + +#define SWEEP(nm) record_sweep(nm, __LINE__) +// Sweeper logging code +class SweeperRecord { + public: + int traversal; + int invocation; + int compile_id; + long traversal_mark; + int state; + const char* kind; + address vep; + address uep; + int line; + + void print() { + tty->print_cr("traversal = %d invocation = %d compile_id = %d %s uep = " PTR_FORMAT " vep = " + PTR_FORMAT " state = %d traversal_mark %d line = %d", + traversal, + invocation, + compile_id, + kind == NULL ? "" : kind, + uep, + vep, + state, + traversal_mark, + line); + } +}; + +static int _sweep_index = 0; +static SweeperRecord* _records = NULL; + +void NMethodSweeper::report_events(int id, address entry) { + if (_records != NULL) { + for (int i = _sweep_index; i < SweeperLogEntries; i++) { + if (_records[i].uep == entry || + _records[i].vep == entry || + _records[i].compile_id == id) { + _records[i].print(); + } + } + for (int i = 0; i < _sweep_index; i++) { + if (_records[i].uep == entry || + _records[i].vep == entry || + _records[i].compile_id == id) { + _records[i].print(); + } + } + } +} + +void NMethodSweeper::report_events() { + if (_records != NULL) { + for (int i = _sweep_index; i < SweeperLogEntries; i++) { + // skip empty records + if (_records[i].vep == NULL) continue; + _records[i].print(); + } + for (int i = 0; i < _sweep_index; i++) { + // skip empty records + if (_records[i].vep == NULL) continue; + _records[i].print(); + } + } +} + +void NMethodSweeper::record_sweep(nmethod* nm, int line) { + if (_records != NULL) { + _records[_sweep_index].traversal = _traversals; + _records[_sweep_index].traversal_mark = nm->_stack_traversal_mark; + _records[_sweep_index].invocation = _invocations; + _records[_sweep_index].compile_id = nm->compile_id(); + _records[_sweep_index].kind = nm->compile_kind(); + _records[_sweep_index].state = nm->_state; + _records[_sweep_index].vep = nm->verified_entry_point(); + _records[_sweep_index].uep = nm->entry_point(); + _records[_sweep_index].line = line; + + _sweep_index = (_sweep_index + 1) % SweeperLogEntries; + } +} +#else +#define SWEEP(nm) +#endif + + long NMethodSweeper::_traversals = 0; // No. of stack traversals performed nmethod* NMethodSweeper::_current = NULL; // Current nmethod int NMethodSweeper::_seen = 0 ; // No. of nmethods we have currently processed in current pass of CodeCache @@ -137,6 +225,13 @@ if (old != 0) { return; } +#ifdef ASSERT + if (LogSweeper && _records == NULL) { + // Create the ring buffer for the logging code + _records = NEW_C_HEAP_ARRAY(SweeperRecord, SweeperLogEntries); + memset(_records, 0, sizeof(SweeperRecord) * SweeperLogEntries); + } +#endif if (_invocations > 0) { sweep_code_cache(); _invocations--; @@ -213,10 +308,29 @@ } } +class NMethodMarker: public StackObj { + private: + CompilerThread* _thread; + public: + NMethodMarker(nmethod* nm) { + _thread = CompilerThread::current(); + _thread->set_scanned_nmethod(nm); + } + ~NMethodMarker() { + _thread->set_scanned_nmethod(NULL); + } +}; + void NMethodSweeper::process_nmethod(nmethod *nm) { assert(!CodeCache_lock->owned_by_self(), "just checking"); + // Make sure this nmethod doesn't get unloaded during the scan, + // since the locks acquired below might safepoint. + NMethodMarker nmm(nm); + + SWEEP(nm); + // Skip methods that are currently referenced by the VM if (nm->is_locked_by_vm()) { // But still remember to clean-up inline caches for alive nmethods @@ -224,8 +338,10 @@ // Clean-up all inline caches that points to zombie/non-reentrant methods MutexLocker cl(CompiledIC_lock); nm->cleanup_inline_caches(); + SWEEP(nm); } else { _locked_seen++; + SWEEP(nm); } return; } @@ -247,6 +363,7 @@ } nm->mark_for_reclamation(); _rescan = true; + SWEEP(nm); } } else if (nm->is_not_entrant()) { // If there is no current activations of this method on the @@ -257,6 +374,7 @@ } nm->make_zombie(); _rescan = true; + SWEEP(nm); } else { // Still alive, clean up its inline caches MutexLocker cl(CompiledIC_lock); @@ -265,6 +383,7 @@ // request a rescan. If this method stays on the stack for a // long time we don't want to keep rescanning the code cache. _not_entrant_seen_on_stack++; + SWEEP(nm); } } else if (nm->is_unloaded()) { // Unloaded code, just make it a zombie @@ -273,10 +392,12 @@ if (nm->is_osr_method()) { // No inline caches will ever point to osr methods, so we can just remove it MutexLockerEx mu(CodeCache_lock, Mutex::_no_safepoint_check_flag); + SWEEP(nm); nm->flush(); } else { nm->make_zombie(); _rescan = true; + SWEEP(nm); } } else { assert(nm->is_alive(), "should be alive"); @@ -293,6 +414,7 @@ // Clean-up all inline caches that points to zombie/non-reentrant methods MutexLocker cl(CompiledIC_lock); nm->cleanup_inline_caches(); + SWEEP(nm); } } diff -r 3f3325361b86 -r 1be2f0c40a34 src/share/vm/runtime/sweeper.hpp --- a/src/share/vm/runtime/sweeper.hpp Wed May 18 10:12:31 2011 -0400 +++ b/src/share/vm/runtime/sweeper.hpp Wed May 18 11:45:06 2011 -0700 @@ -57,6 +57,13 @@ public: static long traversal_count() { return _traversals; } +#ifdef ASSERT + // Keep track of sweeper activity in the ring buffer + static void record_sweep(nmethod* nm, int line); + static void report_events(int id, address entry); + static void report_events(); +#endif + static void scan_stacks(); // Invoked at the end of each safepoint static void sweep_code_cache(); // Concurrent part of sweep job static void possibly_sweep(); // Compiler threads call this to sweep diff -r 3f3325361b86 -r 1be2f0c40a34 src/share/vm/runtime/thread.cpp --- a/src/share/vm/runtime/thread.cpp Wed May 18 10:12:31 2011 -0400 +++ b/src/share/vm/runtime/thread.cpp Wed May 18 11:45:06 2011 -0700 @@ -2861,6 +2861,7 @@ } +#ifdef ASSERT // Print or validate the layout of stack frames void JavaThread::print_frame_layout(int depth, bool validate_only) { ResourceMark rm; @@ -2878,7 +2879,7 @@ values.print(); } } - +#endif void JavaThread::trace_stack_from(vframe* start_vf) { ResourceMark rm; @@ -2942,12 +2943,22 @@ _queue = queue; _counters = counters; _buffer_blob = NULL; + _scanned_nmethod = NULL; #ifndef PRODUCT _ideal_graph_printer = NULL; #endif } +void CompilerThread::oops_do(OopClosure* f, CodeBlobClosure* cf) { + JavaThread::oops_do(f, cf); + if (_scanned_nmethod != NULL && cf != NULL) { + // Safepoints can occur when the sweeper is scanning an nmethod so + // process it here to make sure it isn't unloaded in the middle of + // a scan. + cf->do_code_blob(_scanned_nmethod); + } +} // ======= Threads ======== diff -r 3f3325361b86 -r 1be2f0c40a34 src/share/vm/runtime/thread.hpp --- a/src/share/vm/runtime/thread.hpp Wed May 18 10:12:31 2011 -0400 +++ b/src/share/vm/runtime/thread.hpp Wed May 18 11:45:06 2011 -0700 @@ -439,7 +439,7 @@ // GC support // Apply "f->do_oop" to all root oops in "this". // Apply "cf->do_code_blob" (if !NULL) to all code blobs active in frames - void oops_do(OopClosure* f, CodeBlobClosure* cf); + virtual void oops_do(OopClosure* f, CodeBlobClosure* cf); // Handles the parallel case for the method below. private: @@ -1381,7 +1381,7 @@ void trace_frames() PRODUCT_RETURN; // Print an annotated view of the stack frames - void print_frame_layout(int depth = 0, bool validate_only = false) PRODUCT_RETURN; + void print_frame_layout(int depth = 0, bool validate_only = false) NOT_DEBUG_RETURN; void validate_frame_layout() { print_frame_layout(0, true); } @@ -1698,6 +1698,8 @@ CompileQueue* _queue; BufferBlob* _buffer_blob; + nmethod* _scanned_nmethod; // nmethod being scanned by the sweeper + public: static CompilerThread* current(); @@ -1726,6 +1728,11 @@ _log = log; } + // GC support + // Apply "f->do_oop" to all root oops in "this". + // Apply "cf->do_code_blob" (if !NULL) to all code blobs active in frames + void oops_do(OopClosure* f, CodeBlobClosure* cf); + #ifndef PRODUCT private: IdealGraphPrinter *_ideal_graph_printer; @@ -1737,6 +1744,12 @@ // Get/set the thread's current task CompileTask* task() { return _task; } void set_task(CompileTask* task) { _task = task; } + + // Track the nmethod currently being scanned by the sweeper + void set_scanned_nmethod(nmethod* nm) { + assert(_scanned_nmethod == NULL || nm == NULL, "should reset to NULL before writing a new value"); + _scanned_nmethod = nm; + } }; inline CompilerThread* CompilerThread::current() { diff -r 3f3325361b86 -r 1be2f0c40a34 src/share/vm/runtime/vmStructs.cpp --- a/src/share/vm/runtime/vmStructs.cpp Wed May 18 10:12:31 2011 -0400 +++ b/src/share/vm/runtime/vmStructs.cpp Wed May 18 11:45:06 2011 -0700 @@ -783,6 +783,7 @@ nonstatic_field(nmethod, _osr_link, nmethod*) \ nonstatic_field(nmethod, _scavenge_root_link, nmethod*) \ nonstatic_field(nmethod, _scavenge_root_state, jbyte) \ + nonstatic_field(nmethod, _state, unsigned char) \ nonstatic_field(nmethod, _exception_offset, int) \ nonstatic_field(nmethod, _deoptimize_offset, int) \ nonstatic_field(nmethod, _orig_pc_offset, int) \ @@ -800,6 +801,8 @@ nonstatic_field(nmethod, _osr_entry_point, address) \ nonstatic_field(nmethod, _lock_count, jint) \ nonstatic_field(nmethod, _stack_traversal_mark, long) \ + nonstatic_field(nmethod, _compile_id, int) \ + nonstatic_field(nmethod, _marked_for_deoptimization, bool) \ \ /********************************/ \ /* JavaCalls (NOTE: incomplete) */ \ @@ -1310,11 +1313,13 @@ \ declare_toplevel_type(CodeBlob) \ declare_type(BufferBlob, CodeBlob) \ - declare_type(nmethod, CodeBlob) \ + declare_type(AdapterBlob, BufferBlob) \ + declare_type(nmethod, CodeBlob) \ declare_type(RuntimeStub, CodeBlob) \ declare_type(SingletonBlob, CodeBlob) \ declare_type(SafepointBlob, SingletonBlob) \ declare_type(DeoptimizationBlob, SingletonBlob) \ + declare_type(RicochetBlob, SingletonBlob) \ declare_c2_type(ExceptionBlob, SingletonBlob) \ declare_c2_type(UncommonTrapBlob, CodeBlob) \ \ diff -r 3f3325361b86 -r 1be2f0c40a34 test/compiler/5091921/Test6890943.sh --- a/test/compiler/5091921/Test6890943.sh Wed May 18 10:12:31 2011 -0400 +++ b/test/compiler/5091921/Test6890943.sh Wed May 18 11:45:06 2011 -0700 @@ -52,7 +52,7 @@ ${TESTJAVA}/bin/javac -d . Test6890943.java -${TESTJAVA}/bin/java ${TESTVMOPTS} Test6890943 < input6890943.txt > test.out 2>&1 +${TESTJAVA}/bin/java -XX:-PrintVMOptions ${TESTVMOPTS} Test6890943 < input6890943.txt > test.out 2>&1 diff output6890943.txt test.out diff -r 3f3325361b86 -r 1be2f0c40a34 test/compiler/5091921/Test7005594.java --- a/test/compiler/5091921/Test7005594.java Wed May 18 10:12:31 2011 -0400 +++ b/test/compiler/5091921/Test7005594.java Wed May 18 11:45:06 2011 -0700 @@ -27,7 +27,7 @@ * @bug 7005594 * @summary Array overflow not handled correctly with loop optimzations * - * @run main/othervm -Xms2048m -Xcomp -XX:CompileOnly=Test7005594.test Test7005594 + * @run shell Test7005594.sh */ public class Test7005594 { diff -r 3f3325361b86 -r 1be2f0c40a34 test/compiler/5091921/Test7005594.sh --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/compiler/5091921/Test7005594.sh Wed May 18 11:45:06 2011 -0700 @@ -0,0 +1,80 @@ +#!/bin/sh +# +# 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. +# +# + +if [ "${TESTSRC}" = "" ] +then + echo "TESTSRC not set. Test cannot execute. Failed." + exit 1 +fi +echo "TESTSRC=${TESTSRC}" +if [ "${TESTJAVA}" = "" ] +then + echo "TESTJAVA not set. Test cannot execute. Failed." + exit 1 +fi +echo "TESTJAVA=${TESTJAVA}" +if [ "${TESTCLASSES}" = "" ] +then + echo "TESTCLASSES not set. Test cannot execute. Failed." + exit 1 +fi +echo "TESTCLASSES=${TESTCLASSES}" +echo "CLASSPATH=${CLASSPATH}" + +set -x + +cp ${TESTSRC}/Test7005594.java . +cp ${TESTSRC}/Test7005594.sh . + +${TESTJAVA}/bin/javac -d . Test7005594.java + +${TESTJAVA}/bin/java ${TESTVMOPTS} -Xms1600m -Xcomp -XX:CompileOnly=Test7005594.test Test7005594 > test.out 2>&1 + +result=$? + +cat test.out + +if [ $result -eq 95 ] +then + echo "Passed" + exit 0 +fi + +if [ $result -eq 97 ] +then + echo "Failed" + exit 1 +fi + +# The test should pass when no enough space for object heap +grep "Could not reserve enough space for object heap" test.out +if [ $? = 0 ] +then + echo "Passed" + exit 0 +else + echo "Failed" + exit 1 +fi