# HG changeset patch # User trims # Date 1307157218 25200 # Node ID 82a81d5c5700a69333e12532bf0c4d33e885c7fc # Parent 63d3fb17903465d77bd503d9bf6f18f05b30bfc8# Parent e5ae807761b8c08f31582a4f1057addd97e03e4b Merge diff -r 63d3fb179034 -r 82a81d5c5700 .hgtags --- a/.hgtags Thu Jun 02 13:37:40 2011 -0700 +++ b/.hgtags Fri Jun 03 20:13:38 2011 -0700 @@ -175,3 +175,4 @@ c149193c768b8b7233da4c3a3fdc0756b975848e hs21-b13 c149193c768b8b7233da4c3a3fdc0756b975848e jdk7-b143 fe189d4a44e9e8f0c7d78fcbd1c63701745752ca jdk7-b144 +62f39d40ebf176306a916812729df586f9d10f43 hs21-b14 diff -r 63d3fb179034 -r 82a81d5c5700 src/cpu/x86/vm/c1_LIRAssembler_x86.cpp --- a/src/cpu/x86/vm/c1_LIRAssembler_x86.cpp Thu Jun 02 13:37:40 2011 -0700 +++ b/src/cpu/x86/vm/c1_LIRAssembler_x86.cpp Fri Jun 03 20:13:38 2011 -0700 @@ -3113,7 +3113,6 @@ // reload the register args properly if we go slow path. Yuck // These are proper for the calling convention - store_parameter(length, 2); store_parameter(dst_pos, 1); store_parameter(dst, 0); @@ -3351,12 +3350,15 @@ __ jcc(Assembler::notEqual, *stub->entry()); } + // Spill because stubs can use any register they like and it's + // easier to restore just those that we care about. + store_parameter(dst, 0); + store_parameter(dst_pos, 1); + store_parameter(length, 2); + store_parameter(src_pos, 3); + store_parameter(src, 4); + #ifndef _LP64 - // save caller save registers - store_parameter(rax, 2); - store_parameter(rcx, 1); - store_parameter(rdx, 0); - __ movptr(tmp, dst_klass_addr); __ movptr(tmp, Address(tmp, objArrayKlass::element_klass_offset_in_bytes() + sizeof(oopDesc))); __ push(tmp); @@ -3372,17 +3374,6 @@ #else __ movl2ptr(length, length); //higher 32bits must be null - // save caller save registers: copy them to callee save registers - __ mov(rbx, rdx); - __ mov(r13, r8); - __ mov(r14, r9); -#ifndef _WIN64 - store_parameter(rsi, 1); - store_parameter(rcx, 0); - // on WIN64 other incoming parameters are in rdi and rsi saved - // across the call -#endif - __ lea(c_rarg0, Address(src, src_pos, scale, arrayOopDesc::base_offset_in_bytes(basic_type))); assert_different_registers(c_rarg0, dst, dst_pos, length); __ lea(c_rarg1, Address(dst, dst_pos, scale, arrayOopDesc::base_offset_in_bytes(basic_type))); @@ -3432,25 +3423,13 @@ __ xorl(tmp, -1); -#ifndef _LP64 - // restore caller save registers - assert_different_registers(tmp, rdx, rcx, rax); // result of stub will be lost - __ movptr(rdx, Address(rsp, 0*BytesPerWord)); - __ movptr(rcx, Address(rsp, 1*BytesPerWord)); - __ movptr(rax, Address(rsp, 2*BytesPerWord)); -#else - // restore caller save registers - __ mov(rdx, rbx); - __ mov(r8, r13); - __ mov(r9, r14); -#ifndef _WIN64 - assert_different_registers(tmp, rdx, r8, r9, rcx, rsi); // result of stub will be lost - __ movptr(rcx, Address(rsp, 0*BytesPerWord)); - __ movptr(rsi, Address(rsp, 1*BytesPerWord)); -#else - assert_different_registers(tmp, rdx, r8, r9); // result of stub will be lost -#endif -#endif + // Restore previously spilled arguments + __ movptr (dst, Address(rsp, 0*BytesPerWord)); + __ movptr (dst_pos, Address(rsp, 1*BytesPerWord)); + __ movptr (length, Address(rsp, 2*BytesPerWord)); + __ movptr (src_pos, Address(rsp, 3*BytesPerWord)); + __ movptr (src, Address(rsp, 4*BytesPerWord)); + __ subl(length, tmp); __ addl(src_pos, tmp); diff -r 63d3fb179034 -r 82a81d5c5700 src/cpu/x86/vm/x86_64.ad --- a/src/cpu/x86/vm/x86_64.ad Thu Jun 02 13:37:40 2011 -0700 +++ b/src/cpu/x86/vm/x86_64.ad Fri Jun 03 20:13:38 2011 -0700 @@ -3179,50 +3179,6 @@ emit_rm(cbuf, 0x3, 0x0, dstenc); %} - enc_class enc_cmpLTP(no_rcx_RegI p, no_rcx_RegI q, no_rcx_RegI y, - rcx_RegI tmp) - %{ - // cadd_cmpLT - - int tmpReg = $tmp$$reg; - - int penc = $p$$reg; - int qenc = $q$$reg; - int yenc = $y$$reg; - - // subl $p,$q - if (penc < 8) { - if (qenc >= 8) { - emit_opcode(cbuf, Assembler::REX_B); - } - } else { - if (qenc < 8) { - emit_opcode(cbuf, Assembler::REX_R); - } else { - emit_opcode(cbuf, Assembler::REX_RB); - } - } - emit_opcode(cbuf, 0x2B); - emit_rm(cbuf, 0x3, penc & 7, qenc & 7); - - // sbbl $tmp, $tmp - emit_opcode(cbuf, 0x1B); - emit_rm(cbuf, 0x3, tmpReg, tmpReg); - - // andl $tmp, $y - if (yenc >= 8) { - emit_opcode(cbuf, Assembler::REX_B); - } - emit_opcode(cbuf, 0x23); - emit_rm(cbuf, 0x3, tmpReg, yenc & 7); - - // addl $p,$tmp - if (penc >= 8) { - emit_opcode(cbuf, Assembler::REX_R); - } - emit_opcode(cbuf, 0x03); - emit_rm(cbuf, 0x3, penc & 7, tmpReg); - %} // Compare the lonogs and set -1, 0, or 1 into dst enc_class cmpl3_flag(rRegL src1, rRegL src2, rRegI dst) @@ -10206,9 +10162,7 @@ %} -instruct cadd_cmpLTMask(rRegI p, rRegI q, rRegI y, - rRegI tmp, - rFlagsReg cr) +instruct cadd_cmpLTMask(rRegI p, rRegI q, rRegI y, rRegI tmp, rFlagsReg cr) %{ match(Set p (AddI (AndI (CmpLTMask p q) y) (SubI p q))); effect(TEMP tmp, KILL cr); @@ -10218,25 +10172,19 @@ "sbbl $tmp, $tmp\n\t" "andl $tmp, $y\n\t" "addl $p, $tmp" %} - ins_encode(enc_cmpLTP(p, q, y, tmp)); + ins_encode %{ + Register Rp = $p$$Register; + Register Rq = $q$$Register; + Register Ry = $y$$Register; + Register Rt = $tmp$$Register; + __ subl(Rp, Rq); + __ sbbl(Rt, Rt); + __ andl(Rt, Ry); + __ addl(Rp, Rt); + %} ins_pipe(pipe_cmplt); %} -/* If I enable this, I encourage spilling in the inner loop of compress. -instruct cadd_cmpLTMask_mem( rRegI p, rRegI q, memory y, rRegI tmp, rFlagsReg cr ) -%{ - match(Set p (AddI (AndI (CmpLTMask p q) (LoadI y)) (SubI p q))); - effect( TEMP tmp, KILL cr ); - ins_cost(400); - - format %{ "SUB $p,$q\n\t" - "SBB RCX,RCX\n\t" - "AND RCX,$y\n\t" - "ADD $p,RCX" %} - ins_encode( enc_cmpLTP_mem(p,q,y,tmp) ); -%} -*/ - //---------- FP Instructions------------------------------------------------ instruct cmpF_cc_reg(rFlagsRegU cr, regF src1, regF src2) diff -r 63d3fb179034 -r 82a81d5c5700 src/share/vm/classfile/systemDictionary.hpp --- a/src/share/vm/classfile/systemDictionary.hpp Thu Jun 02 13:37:40 2011 -0700 +++ b/src/share/vm/classfile/systemDictionary.hpp Fri Jun 03 20:13:38 2011 -0700 @@ -152,6 +152,7 @@ template(DirectMethodHandle_klass, java_lang_invoke_DirectMethodHandle, Pre_JSR292) \ template(MethodType_klass, java_lang_invoke_MethodType, Pre_JSR292) \ template(MethodTypeForm_klass, java_lang_invoke_MethodTypeForm, Pre_JSR292) \ + template(BootstrapMethodError_klass, java_lang_BootstrapMethodError, Pre_JSR292) \ template(WrongMethodTypeException_klass, java_lang_invoke_WrongMethodTypeException, Pre_JSR292) \ template(CallSite_klass, java_lang_invoke_CallSite, Pre_JSR292) \ /* Note: MethodHandle must be first, and CallSite last in group */ \ diff -r 63d3fb179034 -r 82a81d5c5700 src/share/vm/classfile/vmSymbols.hpp --- a/src/share/vm/classfile/vmSymbols.hpp Thu Jun 02 13:37:40 2011 -0700 +++ b/src/share/vm/classfile/vmSymbols.hpp Fri Jun 03 20:13:38 2011 -0700 @@ -148,6 +148,7 @@ template(java_lang_InstantiationException, "java/lang/InstantiationException") \ template(java_lang_InstantiationError, "java/lang/InstantiationError") \ template(java_lang_InterruptedException, "java/lang/InterruptedException") \ + template(java_lang_BootstrapMethodError, "java/lang/BootstrapMethodError") \ template(java_lang_LinkageError, "java/lang/LinkageError") \ template(java_lang_NegativeArraySizeException, "java/lang/NegativeArraySizeException") \ template(java_lang_NoSuchFieldException, "java/lang/NoSuchFieldException") \ diff -r 63d3fb179034 -r 82a81d5c5700 src/share/vm/interpreter/linkResolver.cpp --- a/src/share/vm/interpreter/linkResolver.cpp Thu Jun 02 13:37:40 2011 -0700 +++ b/src/share/vm/interpreter/linkResolver.cpp Fri Jun 03 20:13:38 2011 -0700 @@ -1117,7 +1117,24 @@ // The extra MH receiver will be inserted into the stack on every call. methodHandle resolved_method; KlassHandle current_klass(THREAD, pool->pool_holder()); - lookup_implicit_method(resolved_method, resolved_klass, method_name, method_signature, current_klass, CHECK); + lookup_implicit_method(resolved_method, resolved_klass, method_name, method_signature, current_klass, THREAD); + if (HAS_PENDING_EXCEPTION) { + if (PENDING_EXCEPTION->is_a(SystemDictionary::BootstrapMethodError_klass())) { + // throw these guys, since they are already wrapped + return; + } + if (!PENDING_EXCEPTION->is_a(SystemDictionary::LinkageError_klass())) { + // intercept only LinkageErrors which might have failed to wrap + return; + } + // See the "Linking Exceptions" section for the invokedynamic instruction in the JVMS. + Handle ex(THREAD, PENDING_EXCEPTION); + CLEAR_PENDING_EXCEPTION; + oop bsme = Klass::cast(SystemDictionary::BootstrapMethodError_klass())->java_mirror(); + MethodHandles::raise_exception(Bytecodes::_athrow, ex(), bsme, CHECK); + // java code should not return, but if it does throw out anyway + THROW(vmSymbols::java_lang_InternalError()); + } if (resolved_method.is_null()) { THROW(vmSymbols::java_lang_InternalError()); } diff -r 63d3fb179034 -r 82a81d5c5700 src/share/vm/oops/methodOop.cpp --- a/src/share/vm/oops/methodOop.cpp Thu Jun 02 13:37:40 2011 -0700 +++ b/src/share/vm/oops/methodOop.cpp Fri Jun 03 20:13:38 2011 -0700 @@ -720,7 +720,7 @@ // called from the vtable. We need adapters on such methods that get loaded // later. Ditto for mega-morphic itable calls. If this proves to be a // problem we'll make these lazily later. - if (UseCompiler) (void) make_adapters(h_method, CHECK); + (void) make_adapters(h_method, CHECK); // ONLY USE the h_method now as make_adapter may have blocked diff -r 63d3fb179034 -r 82a81d5c5700 src/share/vm/opto/library_call.cpp --- a/src/share/vm/opto/library_call.cpp Thu Jun 02 13:37:40 2011 -0700 +++ b/src/share/vm/opto/library_call.cpp Fri Jun 03 20:13:38 2011 -0700 @@ -5225,15 +5225,16 @@ // Look at the alignment of the starting offsets. int abase = arrayOopDesc::base_offset_in_bytes(basic_elem_type); - const intptr_t BIG_NEG = -128; - assert(BIG_NEG + 2*abase < 0, "neg enough"); - - intptr_t src_off = abase + ((intptr_t) find_int_con(src_offset, -1) << scale); - intptr_t dest_off = abase + ((intptr_t) find_int_con(dest_offset, -1) << scale); - if (src_off < 0 || dest_off < 0) + + intptr_t src_off_con = (intptr_t) find_int_con(src_offset, -1); + intptr_t dest_off_con = (intptr_t) find_int_con(dest_offset, -1); + if (src_off_con < 0 || dest_off_con < 0) // At present, we can only understand constants. return false; + intptr_t src_off = abase + (src_off_con << scale); + intptr_t dest_off = abase + (dest_off_con << scale); + if (((src_off | dest_off) & (BytesPerLong-1)) != 0) { // Non-aligned; too bad. // One more chance: Pick off an initial 32-bit word. diff -r 63d3fb179034 -r 82a81d5c5700 src/share/vm/opto/subnode.cpp --- a/src/share/vm/opto/subnode.cpp Thu Jun 02 13:37:40 2011 -0700 +++ b/src/share/vm/opto/subnode.cpp Fri Jun 03 20:13:38 2011 -0700 @@ -1101,6 +1101,7 @@ if( cmp2_type == TypeInt::ZERO && cmp1_op == Op_XorI && j_xor->in(1) != j_xor && // An xor of itself is dead + phase->type( j_xor->in(1) ) == TypeInt::BOOL && phase->type( j_xor->in(2) ) == TypeInt::ONE && (_test._test == BoolTest::eq || _test._test == BoolTest::ne) ) { diff -r 63d3fb179034 -r 82a81d5c5700 src/share/vm/prims/methodHandleWalk.cpp --- a/src/share/vm/prims/methodHandleWalk.cpp Thu Jun 02 13:37:40 2011 -0700 +++ b/src/share/vm/prims/methodHandleWalk.cpp Fri Jun 03 20:13:38 2011 -0700 @@ -141,6 +141,12 @@ void MethodHandleChain::lose(const char* msg, TRAPS) { _lose_message = msg; +#ifdef ASSERT + if (Verbose) { + tty->print_cr(INTPTR_FORMAT " lose: %s", _method_handle(), msg); + print(); + } +#endif if (!THREAD->is_Java_thread() || ((JavaThread*)THREAD)->thread_state() != _thread_in_vm) { // throw a preallocated exception THROW_OOP(Universe::virtual_machine_error_instance()); @@ -149,6 +155,145 @@ } +#ifdef ASSERT +static const char* adapter_ops[] = { + "retype_only" , + "retype_raw" , + "check_cast" , + "prim_to_prim" , + "ref_to_prim" , + "prim_to_ref" , + "swap_args" , + "rot_args" , + "dup_args" , + "drop_args" , + "collect_args" , + "spread_args" , + "fold_args" +}; + +static const char* adapter_op_to_string(int op) { + if (op >= 0 && op < (int)ARRAY_SIZE(adapter_ops)) + return adapter_ops[op]; + return "unknown_op"; +} + + +void MethodHandleChain::print(Handle mh) { + EXCEPTION_MARK; + MethodHandleChain mhc(mh, THREAD); + if (HAS_PENDING_EXCEPTION) { + oop ex = THREAD->pending_exception(); + CLEAR_PENDING_EXCEPTION; + ex->print(); + return; + } + mhc.print(); +} + + +void MethodHandleChain::print() { + EXCEPTION_MARK; + print_impl(THREAD); + if (HAS_PENDING_EXCEPTION) { + oop ex = THREAD->pending_exception(); + CLEAR_PENDING_EXCEPTION; + ex->print(); + } +} + +void MethodHandleChain::print_impl(TRAPS) { + ResourceMark rm; + + MethodHandleChain chain(_root, CHECK); + for (;;) { + tty->print(INTPTR_FORMAT ": ", chain.method_handle()()); + if (chain.is_bound()) { + tty->print("bound: arg_type %s arg_slot %d", + type2name(chain.bound_arg_type()), + chain.bound_arg_slot()); + oop o = chain.bound_arg_oop(); + if (o != NULL) { + if (o->is_instance()) { + tty->print(" instance %s", o->klass()->klass_part()->internal_name()); + } else { + o->print(); + } + } + } else if (chain.is_adapter()) { + tty->print("adapter: arg_slot %d conversion op %s", + chain.adapter_arg_slot(), + adapter_op_to_string(chain.adapter_conversion_op())); + switch (chain.adapter_conversion_op()) { + case java_lang_invoke_AdapterMethodHandle::OP_RETYPE_ONLY: + case java_lang_invoke_AdapterMethodHandle::OP_RETYPE_RAW: + case java_lang_invoke_AdapterMethodHandle::OP_CHECK_CAST: + case java_lang_invoke_AdapterMethodHandle::OP_PRIM_TO_PRIM: + case java_lang_invoke_AdapterMethodHandle::OP_REF_TO_PRIM: + case java_lang_invoke_AdapterMethodHandle::OP_PRIM_TO_REF: + break; + + case java_lang_invoke_AdapterMethodHandle::OP_SWAP_ARGS: + case java_lang_invoke_AdapterMethodHandle::OP_ROT_ARGS: { + int dest_arg_slot = chain.adapter_conversion_vminfo(); + tty->print(" dest_arg_slot %d type %s", dest_arg_slot, type2name(chain.adapter_conversion_src_type())); + break; + } + + case java_lang_invoke_AdapterMethodHandle::OP_DUP_ARGS: + case java_lang_invoke_AdapterMethodHandle::OP_DROP_ARGS: { + int dup_slots = chain.adapter_conversion_stack_pushes(); + tty->print(" pushes %d", dup_slots); + break; + } + + case java_lang_invoke_AdapterMethodHandle::OP_FOLD_ARGS: + case java_lang_invoke_AdapterMethodHandle::OP_COLLECT_ARGS: { + int coll_slots = chain.MethodHandle_vmslots(); + tty->print(" coll_slots %d", coll_slots); + break; + } + + case java_lang_invoke_AdapterMethodHandle::OP_SPREAD_ARGS: { + // Check the required length. + int spread_slots = 1 + chain.adapter_conversion_stack_pushes(); + tty->print(" spread_slots %d", spread_slots); + break; + } + + default: + tty->print_cr("bad adapter conversion"); + break; + } + } else { + // DMH + tty->print("direct: "); + chain.last_method_oop()->print_short_name(tty); + } + + tty->print(" ("); + objArrayOop ptypes = java_lang_invoke_MethodType::ptypes(chain.method_type_oop()); + for (int i = ptypes->length() - 1; i >= 0; i--) { + BasicType t = java_lang_Class::as_BasicType(ptypes->obj_at(i)); + if (t == T_ARRAY) t = T_OBJECT; + tty->print("%c", type2char(t)); + if (t == T_LONG || t == T_DOUBLE) tty->print("_"); + } + tty->print(")"); + BasicType rtype = java_lang_Class::as_BasicType(java_lang_invoke_MethodType::rtype(chain.method_type_oop())); + if (rtype == T_ARRAY) rtype = T_OBJECT; + tty->print("%c", type2char(rtype)); + tty->cr(); + if (!chain.is_last()) { + chain.next(CHECK); + } else { + break; + } + } +} +#endif + + // ----------------------------------------------------------------------------- // MethodHandleWalker @@ -205,10 +350,16 @@ if (chain().is_adapter()) { int conv_op = chain().adapter_conversion_op(); int arg_slot = chain().adapter_arg_slot(); - SlotState* arg_state = slot_state(arg_slot); - if (arg_state == NULL - && conv_op > java_lang_invoke_AdapterMethodHandle::OP_RETYPE_RAW) { - lose("bad argument index", CHECK_(empty)); + + // Check that the arg_slot is valid. In most cases it must be + // within range of the current arguments but there are some + // exceptions. Those are sanity checked in their implemention + // below. + if ((arg_slot < 0 || arg_slot >= _outgoing.length()) && + conv_op > java_lang_invoke_AdapterMethodHandle::OP_RETYPE_RAW && + conv_op != java_lang_invoke_AdapterMethodHandle::OP_COLLECT_ARGS && + conv_op != java_lang_invoke_AdapterMethodHandle::OP_FOLD_ARGS) { + lose(err_msg("bad argument index %d", arg_slot), CHECK_(empty)); } bool retain_original_args = false; // used by fold/collect logic @@ -237,8 +388,7 @@ // Argument types. for (int i = 0, slot = _outgoing.length() - 1; slot >= 0; slot--) { - SlotState* arg_state = slot_state(slot); - if (arg_state->_type == T_VOID) continue; + if (arg_type(slot) == T_VOID) continue; klassOop src_klass = NULL; klassOop dst_klass = NULL; @@ -262,8 +412,8 @@ klassOop dest_klass = NULL; BasicType dest = java_lang_Class::as_BasicType(chain().adapter_arg_oop(), &dest_klass); assert(dest == T_OBJECT, ""); - assert(dest == arg_state->_type, ""); - ArgToken arg = arg_state->_arg; + ArgToken arg = _outgoing.at(arg_slot); + assert(dest == arg.basic_type(), ""); ArgToken new_arg = make_conversion(T_OBJECT, dest_klass, Bytecodes::_checkcast, arg, CHECK_(empty)); assert(!arg.has_index() || arg.index() == new_arg.index(), "should be the same index"); debug_only(dest_klass = (klassOop)badOop); @@ -274,8 +424,8 @@ // i2l, etc., on the Nth outgoing argument in place BasicType src = chain().adapter_conversion_src_type(), dest = chain().adapter_conversion_dest_type(); + ArgToken arg = _outgoing.at(arg_slot); Bytecodes::Code bc = conversion_code(src, dest); - ArgToken arg = arg_state->_arg; if (bc == Bytecodes::_nop) { break; } else if (bc != Bytecodes::_illegal) { @@ -289,7 +439,7 @@ } } if (bc == Bytecodes::_illegal) { - lose("bad primitive conversion", CHECK_(empty)); + lose(err_msg("bad primitive conversion for %s -> %s", type2name(src), type2name(dest)), CHECK_(empty)); } change_argument(src, arg_slot, dest, arg); break; @@ -298,7 +448,7 @@ case java_lang_invoke_AdapterMethodHandle::OP_REF_TO_PRIM: { // checkcast to wrapper type & call intValue, etc. BasicType dest = chain().adapter_conversion_dest_type(); - ArgToken arg = arg_state->_arg; + ArgToken arg = _outgoing.at(arg_slot); arg = make_conversion(T_OBJECT, SystemDictionary::box_klass(dest), Bytecodes::_checkcast, arg, CHECK_(empty)); vmIntrinsics::ID unboxer = vmIntrinsics::for_unboxing(dest); @@ -316,11 +466,11 @@ case java_lang_invoke_AdapterMethodHandle::OP_PRIM_TO_REF: { // call wrapper type.valueOf BasicType src = chain().adapter_conversion_src_type(); - ArgToken arg = arg_state->_arg; vmIntrinsics::ID boxer = vmIntrinsics::for_boxing(src); if (boxer == vmIntrinsics::_none) { lose("no boxing method", CHECK_(empty)); } + ArgToken arg = _outgoing.at(arg_slot); ArgToken arglist[2]; arglist[0] = arg; // outgoing value arglist[1] = ArgToken(); // sentinel @@ -331,40 +481,45 @@ case java_lang_invoke_AdapterMethodHandle::OP_SWAP_ARGS: { int dest_arg_slot = chain().adapter_conversion_vminfo(); - if (!slot_has_argument(dest_arg_slot)) { + if (!has_argument(dest_arg_slot)) { lose("bad swap index", CHECK_(empty)); } // a simple swap between two arguments - SlotState* dest_arg_state = slot_state(dest_arg_slot); - SlotState temp = (*dest_arg_state); - (*dest_arg_state) = (*arg_state); - (*arg_state) = temp; + if (arg_slot > dest_arg_slot) { + int tmp = arg_slot; + arg_slot = dest_arg_slot; + dest_arg_slot = tmp; + } + ArgToken a1 = _outgoing.at(arg_slot); + ArgToken a2 = _outgoing.at(dest_arg_slot); + change_argument(a2.basic_type(), dest_arg_slot, a1); + change_argument(a1.basic_type(), arg_slot, a2); break; } case java_lang_invoke_AdapterMethodHandle::OP_ROT_ARGS: { int dest_arg_slot = chain().adapter_conversion_vminfo(); - if (!slot_has_argument(dest_arg_slot) || arg_slot == dest_arg_slot) { + if (!has_argument(dest_arg_slot) || arg_slot == dest_arg_slot) { lose("bad rotate index", CHECK_(empty)); } - SlotState* dest_arg_state = slot_state(dest_arg_slot); // Rotate the source argument (plus following N slots) into the // position occupied by the dest argument (plus following N slots). - int rotate_count = type2size[dest_arg_state->_type]; + int rotate_count = type2size[chain().adapter_conversion_src_type()]; // (no other rotate counts are currently supported) if (arg_slot < dest_arg_slot) { for (int i = 0; i < rotate_count; i++) { - SlotState temp = _outgoing.at(arg_slot); + ArgToken temp = _outgoing.at(arg_slot); _outgoing.remove_at(arg_slot); _outgoing.insert_before(dest_arg_slot + rotate_count - 1, temp); } } else { // arg_slot > dest_arg_slot for (int i = 0; i < rotate_count; i++) { - SlotState temp = _outgoing.at(arg_slot + rotate_count - 1); + ArgToken temp = _outgoing.at(arg_slot + rotate_count - 1); _outgoing.remove_at(arg_slot + rotate_count - 1); _outgoing.insert_before(dest_arg_slot, temp); } } + assert(_outgoing_argc == argument_count_slow(), "empty slots under control"); break; } @@ -374,11 +529,11 @@ lose("bad dup count", CHECK_(empty)); } for (int i = 0; i < dup_slots; i++) { - SlotState* dup = slot_state(arg_slot + 2*i); - if (dup == NULL) break; // safety net - if (dup->_type != T_VOID) _outgoing_argc += 1; - _outgoing.insert_before(i, (*dup)); + ArgToken dup = _outgoing.at(arg_slot + 2*i); + if (dup.basic_type() != T_VOID) _outgoing_argc += 1; + _outgoing.insert_before(i, dup); } + assert(_outgoing_argc == argument_count_slow(), "empty slots under control"); break; } @@ -388,11 +543,11 @@ lose("bad drop count", CHECK_(empty)); } for (int i = 0; i < drop_slots; i++) { - SlotState* drop = slot_state(arg_slot); - if (drop == NULL) break; // safety net - if (drop->_type != T_VOID) _outgoing_argc -= 1; + ArgToken drop = _outgoing.at(arg_slot); + if (drop.basic_type() != T_VOID) _outgoing_argc -= 1; _outgoing.remove_at(arg_slot); } + assert(_outgoing_argc == argument_count_slow(), "empty slots under control"); break; } @@ -415,10 +570,10 @@ lose("bad fold/collect arg slot", CHECK_(empty)); } for (int i = 0, slot = arg_slot + coll_slots - 1; slot >= arg_slot; slot--) { - SlotState* arg_state = slot_state(slot); - BasicType arg_type = arg_state->_type; + ArgToken arg_state = _outgoing.at(slot); + BasicType arg_type = arg_state.basic_type(); if (arg_type == T_VOID) continue; - ArgToken arg = _outgoing.at(slot)._arg; + ArgToken arg = _outgoing.at(slot); if (i >= argc) { lose("bad fold/collect arg", CHECK_(empty)); } arglist[1+i] = arg; if (!retain_original_args) @@ -466,8 +621,9 @@ debug_only(element_klass_oop = (klassOop)badOop); // Fetch the argument, which we will cast to the required array type. - assert(arg_state->_type == T_OBJECT, ""); - ArgToken array_arg = arg_state->_arg; + ArgToken arg = _outgoing.at(arg_slot); + assert(arg.basic_type() == T_OBJECT, ""); + ArgToken array_arg = arg; array_arg = make_conversion(T_OBJECT, array_klass(), Bytecodes::_checkcast, array_arg, CHECK_(empty)); change_argument(T_OBJECT, arg_slot, T_VOID, ArgToken(tt_void)); @@ -534,10 +690,10 @@ } else { jvalue arg_value; BasicType bt = java_lang_boxing_object::get_value(arg_oop, &arg_value); - if (bt == arg_type) { + if (bt == arg_type || (bt == T_INT && is_subword_type(arg_type))) { arg = make_prim_constant(arg_type, &arg_value, CHECK_(empty)); } else { - lose("bad bound value", CHECK_(empty)); + lose(err_msg("bad bound value: arg_type %s boxing %s", type2name(arg_type), type2name(bt)), CHECK_(empty)); } } DEBUG_ONLY(arg_oop = badOop); @@ -557,9 +713,9 @@ ArgToken* arglist = NEW_RESOURCE_ARRAY(ArgToken, _outgoing.length() + 1); int ap = 0; for (int i = _outgoing.length() - 1; i >= 0; i--) { - SlotState* arg_state = slot_state(i); - if (arg_state->_type == T_VOID) continue; - arglist[ap++] = _outgoing.at(i)._arg; + ArgToken arg_state = _outgoing.at(i); + if (arg_state.basic_type() == T_VOID) continue; + arglist[ap++] = _outgoing.at(i); } assert(ap == _outgoing_argc, ""); arglist[ap] = ArgToken(); // add a sentinel, for the sake of asserts @@ -579,7 +735,7 @@ _outgoing_argc = nptypes; int argp = nptypes - 1; if (argp >= 0) { - _outgoing.at_grow(argp, make_state(T_VOID, ArgToken(tt_void))); // presize + _outgoing.at_grow(argp, ArgToken(tt_void)); // presize } for (int i = 0; i < nptypes; i++) { klassOop arg_type_klass = NULL; @@ -587,10 +743,10 @@ int index = new_local_index(arg_type); ArgToken arg = make_parameter(arg_type, arg_type_klass, index, CHECK); DEBUG_ONLY(arg_type_klass = (klassOop) NULL); - _outgoing.at_put(argp, make_state(arg_type, arg)); + _outgoing.at_put(argp, arg); if (type2size[arg_type] == 2) { // add the extra slot, so we can model the JVM stack - _outgoing.insert_before(argp+1, make_state(T_VOID, ArgToken(tt_void))); + _outgoing.insert_before(argp+1, ArgToken(tt_void)); } --argp; } @@ -599,38 +755,61 @@ BasicType ret_type = java_lang_Class::as_BasicType(java_lang_invoke_MethodType::rtype(mtype()), &ret_type_klass); ArgToken ret = make_parameter(ret_type, ret_type_klass, -1, CHECK); // ignore ret; client can catch it if needed + + assert(_outgoing_argc == argument_count_slow(), "empty slots under control"); + + verify_args_and_signature(CHECK); } +#ifdef ASSERT +void MethodHandleWalker::verify_args_and_signature(TRAPS) { + int index = _outgoing.length() - 1; + objArrayOop ptypes = java_lang_invoke_MethodType::ptypes(chain().method_type_oop()); + for (int i = 0, limit = ptypes->length(); i < limit; i++) { + BasicType t = java_lang_Class::as_BasicType(ptypes->obj_at(i)); + if (t == T_ARRAY) t = T_OBJECT; + if (t == T_LONG || t == T_DOUBLE) { + assert(T_VOID == _outgoing.at(index).basic_type(), "types must match"); + index--; + } + assert(t == _outgoing.at(index).basic_type(), "types must match"); + index--; + } +} +#endif + + // ----------------------------------------------------------------------------- // MethodHandleWalker::change_argument // // This is messy because some kinds of arguments are paired with // companion slots containing an empty value. -void MethodHandleWalker::change_argument(BasicType old_type, int slot, BasicType new_type, - const ArgToken& new_arg) { +void MethodHandleWalker::change_argument(BasicType old_type, int slot, const ArgToken& new_arg) { + BasicType new_type = new_arg.basic_type(); int old_size = type2size[old_type]; int new_size = type2size[new_type]; if (old_size == new_size) { // simple case first - _outgoing.at_put(slot, make_state(new_type, new_arg)); + _outgoing.at_put(slot, new_arg); } else if (old_size > new_size) { for (int i = old_size - 1; i >= new_size; i--) { - assert((i != 0) == (_outgoing.at(slot + i)._type == T_VOID), ""); + assert((i != 0) == (_outgoing.at(slot + i).basic_type() == T_VOID), ""); _outgoing.remove_at(slot + i); } if (new_size > 0) - _outgoing.at_put(slot, make_state(new_type, new_arg)); + _outgoing.at_put(slot, new_arg); else _outgoing_argc -= 1; // deleted a real argument } else { for (int i = old_size; i < new_size; i++) { - _outgoing.insert_before(slot + i, make_state(T_VOID, ArgToken(tt_void))); + _outgoing.insert_before(slot + i, ArgToken(tt_void)); } - _outgoing.at_put(slot, make_state(new_type, new_arg)); + _outgoing.at_put(slot, new_arg); if (old_size == 0) _outgoing_argc += 1; // inserted a real argument } + assert(_outgoing_argc == argument_count_slow(), "empty slots under control"); } @@ -638,8 +817,15 @@ int MethodHandleWalker::argument_count_slow() { int args_seen = 0; for (int i = _outgoing.length() - 1; i >= 0; i--) { - if (_outgoing.at(i)._type != T_VOID) { + if (_outgoing.at(i).basic_type() != T_VOID) { ++args_seen; + if (_outgoing.at(i).basic_type() == T_LONG || + _outgoing.at(i).basic_type() == T_DOUBLE) { + assert(_outgoing.at(i + 1).basic_type() == T_VOID, "should only follow two word"); + } + } else { + assert(_outgoing.at(i - 1).basic_type() == T_LONG || + _outgoing.at(i - 1).basic_type() == T_DOUBLE, "should only follow two word"); } } return args_seen; @@ -663,7 +849,7 @@ ArgToken arglist[2]; if (!for_return) { // argument type conversion - ArgToken arg = _outgoing.at(slot)._arg; + ArgToken arg = _outgoing.at(slot); assert(arg.token_type() >= tt_symbolic || src == arg.basic_type(), "sanity"); arglist[0] = arg; // outgoing 'this' arglist[1] = ArgToken(); // sentinel @@ -683,7 +869,7 @@ // ref-to-prim: discard ref, push zero lose("requested ref-to-prim conversion not expected", CHECK); } else { - lose("requested raw conversion not allowed", CHECK); + lose(err_msg("requested raw conversion not allowed: %s -> %s", type2name(src), type2name(dst)), CHECK); } } } @@ -963,6 +1149,7 @@ void MethodHandleCompiler::emit_load_constant(ArgToken arg) { BasicType bt = arg.basic_type(); + if (is_subword_type(bt)) bt = T_INT; switch (bt) { case T_INT: { jint value = arg.get_jint(); @@ -1066,11 +1253,15 @@ emit_store(srctype, index); break; + case Bytecodes::_nop: + // nothing to do + return src; + default: if (op == Bytecodes::_illegal) - lose("no such primitive conversion", THREAD); + lose(err_msg("no such primitive conversion: %s -> %s", type2name(src.basic_type()), type2name(type)), THREAD); else - lose("bad primitive conversion op", THREAD); + lose(err_msg("bad primitive conversion op: %s", Bytecodes::name(op)), THREAD); return make_prim_constant(type, &zero_jvalue, THREAD); } @@ -1300,7 +1491,7 @@ // for (int i = 1, imax = _constants.length(); i < imax; i++) { // ConstantValue* con = _constants.at(i); -// if (con != NULL && con->is_primitive() && con->_type == bt) { +// if (con != NULL && con->is_primitive() && con.basic_type() == bt) { // bool match = false; // switch (type2size[bt]) { // case 1: if (pcon->_value.i == con->i) match = true; break; @@ -1452,8 +1643,8 @@ _strbuf.reset(); return s; } - ArgToken token(const char* str) { - return ArgToken(str); + ArgToken token(const char* str, BasicType type) { + return ArgToken(str, type); } const char* string(ArgToken token) { return token.str(); @@ -1475,12 +1666,12 @@ } ArgToken maybe_make_temp(const char* statement_op, BasicType type, const char* temp_name) { const char* value = strbuf(); - if (!_verbose) return token(value); + if (!_verbose) return token(value, type); // make an explicit binding for each separate value _strbuf.print("%s%d", temp_name, ++_temp_num); const char* temp = strbuf(); _out->print("\n %s %s %s = %s;", statement_op, type2name(type), temp, value); - return token(temp); + return token(temp, type); } public: @@ -1496,7 +1687,7 @@ virtual ArgToken make_parameter(BasicType type, klassOop tk, int argnum, TRAPS) { if (argnum < 0) { end_params(); - return token("return"); + return token("return", type); } if ((_param_state & 1) == 0) { _param_state |= 1; @@ -1511,7 +1702,7 @@ const char* arg = strbuf(); put_type_name(type, tk, _out); _out->print(" %s", arg); - return token(arg); + return token(arg, type); } virtual ArgToken make_oop_constant(oop con, TRAPS) { if (con == NULL) @@ -1598,7 +1789,7 @@ out->print("\n"); } static void print(Handle root, bool verbose = Verbose, outputStream* out = tty) { - EXCEPTION_MARK; + Thread* THREAD = Thread::current(); ResourceMark rm; MethodHandlePrinter printer(root, verbose, out, THREAD); if (!HAS_PENDING_EXCEPTION) diff -r 63d3fb179034 -r 82a81d5c5700 src/share/vm/prims/methodHandleWalk.hpp --- a/src/share/vm/prims/methodHandleWalk.hpp Thu Jun 02 13:37:40 2011 -0700 +++ b/src/share/vm/prims/methodHandleWalk.hpp Fri Jun 03 20:13:38 2011 -0700 @@ -56,6 +56,10 @@ int BoundMethodHandle_vmargslot() { return java_lang_invoke_BoundMethodHandle::vmargslot(method_handle_oop()); } int AdapterMethodHandle_conversion() { return java_lang_invoke_AdapterMethodHandle::conversion(method_handle_oop()); } +#ifdef ASSERT + void print_impl(TRAPS); +#endif + public: MethodHandleChain(Handle root, TRAPS) : _root(root) @@ -99,6 +103,14 @@ void lose(const char* msg, TRAPS); const char* lose_message() { return _lose_message; } + +#ifdef ASSERT + // Print a symbolic description of a method handle chain, including + // the signature for each method. The signatures are printed in + // slot order to make it easier to understand. + void print(); + static void print(Handle mh); +#endif }; @@ -126,7 +138,7 @@ Handle _handle; public: - ArgToken(TokenType tt = tt_illegal) : _tt(tt) { + ArgToken(TokenType tt = tt_illegal) : _tt(tt), _bt(tt == tt_void ? T_VOID : T_ILLEGAL) { assert(tt == tt_illegal || tt == tt_void, "invalid token type"); } @@ -135,11 +147,11 @@ _value.i = index; } - 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(BasicType bt, jvalue value) : _tt(tt_constant), _bt(bt), _value(value) { assert(_bt != T_OBJECT, "wrong constructor"); } + ArgToken(Handle handle) : _tt(tt_constant), _bt(T_OBJECT), _handle(handle) {} - ArgToken(const char* str) : _tt(tt_symbolic), _bt(T_LONG) { + ArgToken(const char* str, BasicType type) : _tt(tt_symbolic), _bt(type) { _value.j = (intptr_t)str; } @@ -147,26 +159,14 @@ BasicType basic_type() const { return _bt; } 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 { 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; } - }; + Handle object() const { assert(_bt == T_OBJECT, "wrong accessor"); assert(_tt == tt_constant, "value type"); return _handle; } + const char* str() const { assert(_tt == tt_symbolic, "string type"); return (const char*)(intptr_t)_value.j; } - // Abstract interpretation state: - struct SlotState { - BasicType _type; - ArgToken _arg; - SlotState() : _type(), _arg() {} + jint get_jint() const { assert(_bt == T_INT || is_subword_type(_bt), "wrong accessor"); assert(_tt == tt_constant, "value types"); return _value.i; } + jlong get_jlong() const { assert(_bt == T_LONG, "wrong accessor"); assert(_tt == tt_constant, "value types"); return _value.j; } + jfloat get_jfloat() const { assert(_bt == T_FLOAT, "wrong accessor"); assert(_tt == tt_constant, "value types"); return _value.f; } + jdouble get_jdouble() const { assert(_bt == T_DOUBLE, "wrong accessor"); assert(_tt == tt_constant, "value types"); return _value.d; } }; - static SlotState make_state(BasicType type, ArgToken arg) { - SlotState ss; - ss._type = type; ss._arg = arg; - return ss; - } private: MethodHandleChain _chain; @@ -177,33 +177,29 @@ // TOS is always _outgoing.at(0), so simple pushes and pops shift the whole _outgoing array. // If there is a receiver in the current argument list, it is at _outgoing.at(_outgoing.length()-1). // If a value at _outgoing.at(n) is T_LONG or T_DOUBLE, the value at _outgoing.at(n+1) is T_VOID. - GrowableArray _outgoing; // current outgoing parameter slots + GrowableArray _outgoing; // current outgoing parameter slots int _outgoing_argc; // # non-empty outgoing slots // Replace a value of type old_type at slot (and maybe slot+1) with the new value. // If old_type != T_VOID, remove the old argument at that point. // If new_type != T_VOID, insert the new argument at that point. // Insert or delete a second empty slot as needed. - void change_argument(BasicType old_type, int slot, BasicType new_type, const ArgToken& new_arg); + void change_argument(BasicType old_type, int slot, const ArgToken& new_arg); + void change_argument(BasicType old_type, int slot, BasicType type, const ArgToken& new_arg) { + assert(type == new_arg.basic_type(), "must agree"); + change_argument(old_type, slot, new_arg); + } // Raw retype conversions for OP_RAW_RETYPE. void retype_raw_conversion(BasicType src, BasicType dst, bool for_return, int slot, TRAPS); void retype_raw_argument_type(BasicType src, BasicType dst, int slot, TRAPS) { retype_raw_conversion(src, dst, false, slot, CHECK); } void retype_raw_return_type( BasicType src, BasicType dst, TRAPS) { retype_raw_conversion(src, dst, true, -1, CHECK); } - SlotState* slot_state(int slot) { - if (slot < 0 || slot >= _outgoing.length()) - return NULL; - return _outgoing.adr_at(slot); + BasicType arg_type(int slot) { + return _outgoing.at(slot).basic_type(); } - BasicType slot_type(int slot) { - SlotState* ss = slot_state(slot); - if (ss == NULL) - return T_ILLEGAL; - return ss->_type; - } - bool slot_has_argument(int slot) { - return slot_type(slot) < T_VOID; + bool has_argument(int slot) { + return arg_type(slot) < T_VOID; } #ifdef ASSERT @@ -215,6 +211,8 @@ void walk_incoming_state(TRAPS); + void verify_args_and_signature(TRAPS) NOT_DEBUG_RETURN; + public: MethodHandleWalker(Handle root, bool for_invokedynamic, TRAPS) : _chain(root, THREAD), @@ -421,7 +419,7 @@ } virtual ArgToken make_oop_constant(oop con, TRAPS) { Handle h(THREAD, con); - return ArgToken(T_OBJECT, h); + return ArgToken(h); } virtual ArgToken make_prim_constant(BasicType type, jvalue* con, TRAPS) { return ArgToken(type, *con); diff -r 63d3fb179034 -r 82a81d5c5700 src/share/vm/prims/methodHandles.cpp --- a/src/share/vm/prims/methodHandles.cpp Thu Jun 02 13:37:40 2011 -0700 +++ b/src/share/vm/prims/methodHandles.cpp Fri Jun 03 20:13:38 2011 -0700 @@ -1305,6 +1305,7 @@ // Verify that argslot points at the given argnum. int check_slot = argument_slot(java_lang_invoke_MethodHandle::type(mh()), argnum); if (argslot != check_slot || argslot < 0) { + ResourceMark rm; const char* fmt = "for argnum of %d, vmargslot is %d, should be %d"; size_t msglen = strlen(fmt) + 3*11 + 1; char* msg = NEW_RESOURCE_ARRAY(char, msglen); @@ -1829,6 +1830,7 @@ bool direct_to_method = false; if (OptimizeMethodHandles && target->klass() == SystemDictionary::DirectMethodHandle_klass() && + (argnum != 0 || java_lang_invoke_BoundMethodHandle::argument(mh()) != NULL) && (argnum == 0 || java_lang_invoke_DirectMethodHandle::vmindex(target()) < 0)) { KlassHandle receiver_limit; int decode_flags = 0; methodHandle m = decode_method(target(), receiver_limit, decode_flags); @@ -1980,7 +1982,6 @@ err = "adapter requires src/dest conversion subfields for swap"; break; } int swap_size = type2size[src]; - int slot_limit = java_lang_invoke_MethodHandle::vmslots(target()); int src_slot = argslot; int dest_slot = vminfo; bool rotate_up = (src_slot > dest_slot); // upward rotation @@ -2333,7 +2334,6 @@ case _adapter_rot_args: { int swap_slots = type2size[src]; - int slot_limit = java_lang_invoke_AdapterMethodHandle::vmslots(mh()); int src_slot = argslot; int dest_slot = vminfo; int rotate = (ek_orig == _adapter_swap_args) ? 0 : (src_slot > dest_slot) ? 1 : -1; @@ -2661,14 +2661,14 @@ ResourceMark rm; // for error messages // This is the guy we are initializing: - if (mh_jh == NULL) { THROW(vmSymbols::java_lang_InternalError()); } + if (mh_jh == NULL) { THROW_MSG(vmSymbols::java_lang_InternalError(), "self is null"); } Handle mh(THREAD, JNIHandles::resolve_non_null(mh_jh)); // Early returns out of this method leave the DMH in an unfinished state. assert(java_lang_invoke_MethodHandle::vmentry(mh()) == NULL, "must be safely null"); // which method are we really talking about? - if (target_jh == NULL) { THROW(vmSymbols::java_lang_InternalError()); } + if (target_jh == NULL) { THROW_MSG(vmSymbols::java_lang_InternalError(), "target is null"); } Handle target(THREAD, JNIHandles::resolve_non_null(target_jh)); if (java_lang_invoke_MemberName::is_instance(target()) && java_lang_invoke_MemberName::vmindex(target()) == VM_INDEX_UNINITIALIZED) { @@ -2722,13 +2722,13 @@ ResourceMark rm; // for error messages // This is the guy we are initializing: - if (mh_jh == NULL) { THROW(vmSymbols::java_lang_InternalError()); } + if (mh_jh == NULL) { THROW_MSG(vmSymbols::java_lang_InternalError(), "self is null"); } Handle mh(THREAD, JNIHandles::resolve_non_null(mh_jh)); // Early returns out of this method leave the BMH in an unfinished state. assert(java_lang_invoke_MethodHandle::vmentry(mh()) == NULL, "must be safely null"); - if (target_jh == NULL) { THROW(vmSymbols::java_lang_InternalError()); } + if (target_jh == NULL) { THROW_MSG(vmSymbols::java_lang_InternalError(), "target is null"); } Handle target(THREAD, JNIHandles::resolve_non_null(target_jh)); if (!java_lang_invoke_MethodHandle::is_instance(target())) { @@ -2753,9 +2753,8 @@ JVM_ENTRY(void, MHN_init_AMH(JNIEnv *env, jobject igcls, jobject mh_jh, jobject target_jh, int argnum)) { // This is the guy we are initializing: - if (mh_jh == NULL || target_jh == NULL) { - THROW(vmSymbols::java_lang_InternalError()); - } + if (mh_jh == NULL) { THROW_MSG(vmSymbols::java_lang_InternalError(), "self is null"); } + if (target_jh == NULL) { THROW_MSG(vmSymbols::java_lang_InternalError(), "target is null"); } Handle mh(THREAD, JNIHandles::resolve_non_null(mh_jh)); Handle target(THREAD, JNIHandles::resolve_non_null(target_jh)); @@ -2890,7 +2889,8 @@ // void init(MemberName self, AccessibleObject ref) JVM_ENTRY(void, MHN_init_Mem(JNIEnv *env, jobject igcls, jobject mname_jh, jobject target_jh)) { - if (mname_jh == NULL || target_jh == NULL) { THROW(vmSymbols::java_lang_InternalError()); } + if (mname_jh == NULL) { THROW_MSG(vmSymbols::java_lang_InternalError(), "mname is null"); } + if (target_jh == NULL) { THROW_MSG(vmSymbols::java_lang_InternalError(), "target is null"); } Handle mname(THREAD, JNIHandles::resolve_non_null(mname_jh)); oop target_oop = JNIHandles::resolve_non_null(target_jh); MethodHandles::init_MemberName(mname(), target_oop); @@ -2899,7 +2899,7 @@ // void expand(MemberName self) JVM_ENTRY(void, MHN_expand_Mem(JNIEnv *env, jobject igcls, jobject mname_jh)) { - if (mname_jh == NULL) { THROW(vmSymbols::java_lang_InternalError()); } + if (mname_jh == NULL) { THROW_MSG(vmSymbols::java_lang_InternalError(), "mname is null"); } Handle mname(THREAD, JNIHandles::resolve_non_null(mname_jh)); MethodHandles::expand_MemberName(mname, 0, CHECK); } @@ -2907,7 +2907,7 @@ // void resolve(MemberName self, Class caller) JVM_ENTRY(void, MHN_resolve_Mem(JNIEnv *env, jobject igcls, jobject mname_jh, jclass caller_jh)) { - if (mname_jh == NULL) { THROW(vmSymbols::java_lang_InternalError()); } + if (mname_jh == NULL) { THROW_MSG(vmSymbols::java_lang_InternalError(), "mname is null"); } Handle mname(THREAD, JNIHandles::resolve_non_null(mname_jh)); // The trusted Java code that calls this method should already have performed @@ -2970,6 +2970,45 @@ } JVM_END +methodOop MethodHandles::resolve_raise_exception_method(TRAPS) { + if (_raise_exception_method != NULL) { + // no need to do it twice + return raise_exception_method(); + } + // LinkResolver::resolve_invokedynamic can reach this point + // because an invokedynamic has failed very early (7049415) + KlassHandle MHN_klass = SystemDictionaryHandles::MethodHandleNatives_klass(); + if (MHN_klass.not_null()) { + TempNewSymbol raiseException_name = SymbolTable::new_symbol("raiseException", CHECK_NULL); + TempNewSymbol raiseException_sig = SymbolTable::new_symbol("(ILjava/lang/Object;Ljava/lang/Object;)V", CHECK_NULL); + methodOop raiseException_method = instanceKlass::cast(MHN_klass->as_klassOop()) + ->find_method(raiseException_name, raiseException_sig); + if (raiseException_method != NULL && raiseException_method->is_static()) { + return raiseException_method; + } + } + // not found; let the caller deal with it + return NULL; +} +void MethodHandles::raise_exception(int code, oop actual, oop required, TRAPS) { + methodOop raiseException_method = resolve_raise_exception_method(CHECK); + if (raiseException_method != NULL && + instanceKlass::cast(raiseException_method->method_holder())->is_not_initialized()) { + instanceKlass::cast(raiseException_method->method_holder())->initialize(CHECK); + // it had better be resolved by now, or maybe JSR 292 failed to load + raiseException_method = raise_exception_method(); + } + if (raiseException_method == NULL) { + THROW_MSG(vmSymbols::java_lang_InternalError(), "no raiseException method"); + } + JavaCallArguments args; + args.push_int(code); + args.push_oop(actual); + args.push_oop(required); + JavaValue result(T_VOID); + JavaCalls::call(&result, raiseException_method, &args, CHECK); +} + 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"); @@ -3059,19 +3098,11 @@ } if (enable_MH) { - KlassHandle MHN_klass = SystemDictionaryHandles::MethodHandleNatives_klass(); - if (MHN_klass.not_null()) { - TempNewSymbol raiseException_name = SymbolTable::new_symbol("raiseException", CHECK); - TempNewSymbol raiseException_sig = SymbolTable::new_symbol("(ILjava/lang/Object;Ljava/lang/Object;)V", CHECK); - methodOop raiseException_method = instanceKlass::cast(MHN_klass->as_klassOop()) - ->find_method(raiseException_name, raiseException_sig); - if (raiseException_method != NULL && raiseException_method->is_static()) { - MethodHandles::set_raise_exception_method(raiseException_method); - } else { - warning("JSR 292 method handle code is mismatched to this JVM. Disabling support."); - enable_MH = false; - } + methodOop raiseException_method = MethodHandles::resolve_raise_exception_method(CHECK); + if (raiseException_method != NULL) { + MethodHandles::set_raise_exception_method(raiseException_method); } else { + warning("JSR 292 method handle code is mismatched to this JVM. Disabling support."); enable_MH = false; } } diff -r 63d3fb179034 -r 82a81d5c5700 src/share/vm/prims/methodHandles.hpp --- a/src/share/vm/prims/methodHandles.hpp Thu Jun 02 13:37:40 2011 -0700 +++ b/src/share/vm/prims/methodHandles.hpp Fri Jun 03 20:13:38 2011 -0700 @@ -439,6 +439,9 @@ assert(_raise_exception_method == NULL, ""); _raise_exception_method = JNIHandles::make_global(Handle(rem)); } + static methodOop resolve_raise_exception_method(TRAPS); + // call raise_exception_method from C code: + static void raise_exception(int code, oop actual, oop required, TRAPS); static jint adapter_conversion(int conv_op, BasicType src, BasicType dest, int stack_move = 0, int vminfo = 0) { diff -r 63d3fb179034 -r 82a81d5c5700 src/share/vm/runtime/globals.hpp --- a/src/share/vm/runtime/globals.hpp Thu Jun 02 13:37:40 2011 -0700 +++ b/src/share/vm/runtime/globals.hpp Fri Jun 03 20:13:38 2011 -0700 @@ -3734,7 +3734,7 @@ experimental(bool, TrustFinalNonStaticFields, false, \ "trust final non-static declarations for constant folding") \ \ - experimental(bool, AllowInvokeGeneric, true, \ + experimental(bool, AllowInvokeGeneric, false, \ "accept MethodHandle.invoke and MethodHandle.invokeGeneric " \ "as equivalent methods") \ \ diff -r 63d3fb179034 -r 82a81d5c5700 test/compiler/6956668/Test6956668.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/compiler/6956668/Test6956668.java Fri Jun 03 20:13:38 2011 -0700 @@ -0,0 +1,69 @@ +/* + * 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 6956668 + * @summary misbehavior of XOR operator (^) with int + * + * @run main/othervm -Xbatch Test6956668 + */ + + +public class Test6956668 { + + public static int bitTest() { + int result = 0; + + int testValue = 73; + int bitCount = Integer.bitCount(testValue); + + if (testValue != 0) { + int gap = Long.numberOfTrailingZeros(testValue); + testValue >>>= gap; + + while (testValue != 0) { + result++; + + if ((testValue ^= 0x1) != 0) { + gap = Long.numberOfTrailingZeros(testValue); + testValue >>>= gap; + } + } + } + + if (bitCount != result) { + System.out.println("ERROR: " + bitCount + " != " + result); + System.exit(97); + } + + return (result); + } + + public static void main(String[] args) { + for (int i = 0; i < 100000; i++) { + int ct = bitTest(); + } + } +} diff -r 63d3fb179034 -r 82a81d5c5700 test/compiler/7047069/Test7047069.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/compiler/7047069/Test7047069.java Fri Jun 03 20:13:38 2011 -0700 @@ -0,0 +1,200 @@ +/* + * 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 7047069 + * @summary Array can dynamically change size when assigned to an object field + * + * @run main/othervm -Xbatch Test7047069 + */ + +import java.util.*; +import java.awt.geom.*; + +public class Test7047069 { + static boolean verbose; + + static final int GROW_SIZE = 24; // Multiple of cubic & quad curve size + + float squareflat; // Square of the flatness parameter + // for testing against squared lengths + + int limit; // Maximum number of recursion levels + + float hold[] = new float[14]; // The cache of interpolated coords + // Note that this must be long enough + // to store a full cubic segment and + // a relative cubic segment to avoid + // aliasing when copying the coords + // of a curve to the end of the array. + // This is also serendipitously equal + // to the size of a full quad segment + // and 2 relative quad segments. + + int holdEnd; // The index of the last curve segment + // being held for interpolation + + int holdIndex; // The index of the curve segment + // that was last interpolated. This + // is the curve segment ready to be + // returned in the next call to + // currentSegment(). + + int levels[]; // The recursion level at which + // each curve being held in storage + // was generated. + + int levelIndex; // The index of the entry in the + // levels array of the curve segment + // at the holdIndex + + public static void subdivide(float src[], int srcoff, + float left[], int leftoff, + float right[], int rightoff) + { + float x1 = src[srcoff + 0]; + float y1 = src[srcoff + 1]; + float ctrlx = src[srcoff + 2]; + float ctrly = src[srcoff + 3]; + float x2 = src[srcoff + 4]; + float y2 = src[srcoff + 5]; + if (left != null) { + left[leftoff + 0] = x1; + left[leftoff + 1] = y1; + } + if (right != null) { + right[rightoff + 4] = x2; + right[rightoff + 5] = y2; + } + x1 = (x1 + ctrlx) / 2f; + y1 = (y1 + ctrly) / 2f; + x2 = (x2 + ctrlx) / 2f; + y2 = (y2 + ctrly) / 2f; + ctrlx = (x1 + x2) / 2f; + ctrly = (y1 + y2) / 2f; + if (left != null) { + left[leftoff + 2] = x1; + left[leftoff + 3] = y1; + left[leftoff + 4] = ctrlx; + left[leftoff + 5] = ctrly; + } + if (right != null) { + right[rightoff + 0] = ctrlx; + right[rightoff + 1] = ctrly; + right[rightoff + 2] = x2; + right[rightoff + 3] = y2; + } + } + + public static double getFlatnessSq(float coords[], int offset) { + return Line2D.ptSegDistSq(coords[offset + 0], coords[offset + 1], + coords[offset + 4], coords[offset + 5], + coords[offset + 2], coords[offset + 3]); + } + + public Test7047069() { + this.squareflat = .0001f * .0001f; + holdIndex = hold.length - 6; + holdEnd = hold.length - 2; + hold[holdIndex + 0] = (float) (Math.random() * 100); + hold[holdIndex + 1] = (float) (Math.random() * 100); + hold[holdIndex + 2] = (float) (Math.random() * 100); + hold[holdIndex + 3] = (float) (Math.random() * 100); + hold[holdIndex + 4] = (float) (Math.random() * 100); + hold[holdIndex + 5] = (float) (Math.random() * 100); + levelIndex = 0; + this.limit = 10; + this.levels = new int[limit + 1]; + } + + /* + * Ensures that the hold array can hold up to (want) more values. + * It is currently holding (hold.length - holdIndex) values. + */ + void ensureHoldCapacity(int want) { + if (holdIndex - want < 0) { + int have = hold.length - holdIndex; + int newsize = hold.length + GROW_SIZE; + float newhold[] = new float[newsize]; + System.arraycopy(hold, holdIndex, + newhold, holdIndex + GROW_SIZE, + have); + if (verbose) System.err.println("old hold = "+hold+"["+hold.length+"]"); + if (verbose) System.err.println("replacement hold = "+newhold+"["+newhold.length+"]"); + hold = newhold; + if (verbose) System.err.println("new hold = "+hold+"["+hold.length+"]"); + if (verbose) System.err.println("replacement hold still = "+newhold+"["+newhold.length+"]"); + holdIndex += GROW_SIZE; + holdEnd += GROW_SIZE; + } + } + + private boolean next() { + if (holdIndex >= holdEnd) { + return false; + } + + int level = levels[levelIndex]; + while (level < limit) { + if (getFlatnessSq(hold, holdIndex) < squareflat) { + break; + } + + ensureHoldCapacity(4); + subdivide(hold, holdIndex, + hold, holdIndex - 4, + hold, holdIndex); + holdIndex -= 4; + + // Now that we have subdivided, we have constructed + // two curves of one depth lower than the original + // curve. One of those curves is in the place of + // the former curve and one of them is in the next + // set of held coordinate slots. We now set both + // curves level values to the next higher level. + level++; + levels[levelIndex] = level; + levelIndex++; + levels[levelIndex] = level; + } + + // This curve segment is flat enough, or it is too deep + // in recursion levels to try to flatten any more. The + // two coordinates at holdIndex+4 and holdIndex+5 now + // contain the endpoint of the curve which can be the + // endpoint of an approximating line segment. + holdIndex += 4; + levelIndex--; + return true; + } + + public static void main(String argv[]) { + verbose = (argv.length > 0); + for (int i = 0; i < 100000; i++) { + Test7047069 st = new Test7047069(); + while (st.next()) {} + } + } +} diff -r 63d3fb179034 -r 82a81d5c5700 test/compiler/7048332/Test7048332.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/compiler/7048332/Test7048332.java Fri Jun 03 20:13:38 2011 -0700 @@ -0,0 +1,60 @@ +/* + * 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 7048332 + * @summary Cadd_cmpLTMask doesn't handle 64-bit tmp register properly + * + * @run main/othervm -Xbatch Test7048332 + */ + + +public class Test7048332 { + + static int capacity = 2; + static int first = 1; + static int last = 2; + + static int test(int i1, int i2, int i3, int i4, int i5, int i6) { + final int result; + if (last >= first) { + result = last - first; + } else { + result = last - first + capacity; + } + return result; + } + + public static void main(String [] args) { + for (int i = 0; i < 11000; i++) { + last = (i & 1) << 1; // 0 or 2 + int k = test(1, 2, 3, 4, 5, 6); + if (k != 1) { + System.out.println("FAILED: " + k + " != 1"); + System.exit(97); + } + } + } +}