Fri, 15 Jul 2011 15:35:50 -0700
6990212: JSR 292 JVMTI MethodEnter hook is not called for JSR 292 bootstrap and target methods
Summary: check for single stepping when dispatching invokes from method handles
Reviewed-by: coleenp, twisti, kvn, dsamersoff
1.1 --- a/src/cpu/sparc/vm/methodHandles_sparc.cpp Thu Jul 14 15:39:40 2011 -0700 1.2 +++ b/src/cpu/sparc/vm/methodHandles_sparc.cpp Fri Jul 15 15:35:50 2011 -0700 1.3 @@ -524,6 +524,30 @@ 1.4 } 1.5 #endif // ASSERT 1.6 1.7 + 1.8 +void MethodHandles::jump_from_method_handle(MacroAssembler* _masm, Register method, Register target, Register temp) { 1.9 + assert(method == G5_method, "interpreter calling convention"); 1.10 + __ verify_oop(method); 1.11 + __ ld_ptr(G5_method, in_bytes(methodOopDesc::from_interpreted_offset()), target); 1.12 + if (JvmtiExport::can_post_interpreter_events()) { 1.13 + // JVMTI events, such as single-stepping, are implemented partly by avoiding running 1.14 + // compiled code in threads for which the event is enabled. Check here for 1.15 + // interp_only_mode if these events CAN be enabled. 1.16 + __ verify_thread(); 1.17 + Label skip_compiled_code; 1.18 + 1.19 + const Address interp_only(G2_thread, JavaThread::interp_only_mode_offset()); 1.20 + __ ld(interp_only, temp); 1.21 + __ tst(temp); 1.22 + __ br(Assembler::notZero, true, Assembler::pn, skip_compiled_code); 1.23 + __ delayed()->ld_ptr(G5_method, in_bytes(methodOopDesc::interpreter_entry_offset()), target); 1.24 + __ bind(skip_compiled_code); 1.25 + } 1.26 + __ jmp(target, 0); 1.27 + __ delayed()->nop(); 1.28 +} 1.29 + 1.30 + 1.31 // Code generation 1.32 address MethodHandles::generate_method_handle_interpreter_entry(MacroAssembler* _masm) { 1.33 // I5_savedSP/O5_savedSP: sender SP (must preserve) 1.34 @@ -1105,9 +1129,6 @@ 1.35 guarantee(java_lang_invoke_MethodHandle::vmentry_offset_in_bytes() != 0, "must have offsets"); 1.36 1.37 // Some handy addresses: 1.38 - Address G5_method_fie( G5_method, in_bytes(methodOopDesc::from_interpreted_offset())); 1.39 - Address G5_method_fce( G5_method, in_bytes(methodOopDesc::from_compiled_offset())); 1.40 - 1.41 Address G3_mh_vmtarget( G3_method_handle, java_lang_invoke_MethodHandle::vmtarget_offset_in_bytes()); 1.42 1.43 Address G3_dmh_vmindex( G3_method_handle, java_lang_invoke_DirectMethodHandle::vmindex_offset_in_bytes()); 1.44 @@ -1136,24 +1157,23 @@ 1.45 case _raise_exception: 1.46 { 1.47 // Not a real MH entry, but rather shared code for raising an 1.48 - // exception. Since we use the compiled entry, arguments are 1.49 - // expected in compiler argument registers. 1.50 + // exception. For sharing purposes the arguments are passed into registers 1.51 + // and then placed in the intepreter calling convention here. 1.52 assert(raise_exception_method(), "must be set"); 1.53 assert(raise_exception_method()->from_compiled_entry(), "method must be linked"); 1.54 1.55 - __ mov(O5_savedSP, SP); // Cut the stack back to where the caller started. 1.56 - 1.57 - Label L_no_method; 1.58 - // FIXME: fill in _raise_exception_method with a suitable java.lang.invoke method 1.59 __ set(AddressLiteral((address) &_raise_exception_method), G5_method); 1.60 __ ld_ptr(Address(G5_method, 0), G5_method); 1.61 1.62 const int jobject_oop_offset = 0; 1.63 __ ld_ptr(Address(G5_method, jobject_oop_offset), G5_method); 1.64 1.65 - __ verify_oop(G5_method); 1.66 - __ jump_indirect_to(G5_method_fce, O3_scratch); // jump to compiled entry 1.67 - __ delayed()->nop(); 1.68 + adjust_SP_and_Gargs_down_by_slots(_masm, 3, noreg, noreg); 1.69 + 1.70 + __ st_ptr(O0_code, __ argument_address(constant(2), noreg, 0)); 1.71 + __ st_ptr(O1_actual, __ argument_address(constant(1), noreg, 0)); 1.72 + __ st_ptr(O2_required, __ argument_address(constant(0), noreg, 0)); 1.73 + jump_from_method_handle(_masm, G5_method, O1_scratch, O2_scratch); 1.74 } 1.75 break; 1.76 1.77 @@ -1161,7 +1181,6 @@ 1.78 case _invokespecial_mh: 1.79 { 1.80 __ load_heap_oop(G3_mh_vmtarget, G5_method); // target is a methodOop 1.81 - __ verify_oop(G5_method); 1.82 // Same as TemplateTable::invokestatic or invokespecial, 1.83 // minus the CP setup and profiling: 1.84 if (ek == _invokespecial_mh) { 1.85 @@ -1171,8 +1190,7 @@ 1.86 __ null_check(G3_method_handle); 1.87 __ verify_oop(G3_method_handle); 1.88 } 1.89 - __ jump_indirect_to(G5_method_fie, O1_scratch); 1.90 - __ delayed()->nop(); 1.91 + jump_from_method_handle(_masm, G5_method, O1_scratch, O2_scratch); 1.92 } 1.93 break; 1.94 1.95 @@ -1204,9 +1222,7 @@ 1.96 Address vtable_entry_addr(O0_klass, base + vtableEntry::method_offset_in_bytes()); 1.97 __ ld_ptr(vtable_entry_addr, G5_method); 1.98 1.99 - __ verify_oop(G5_method); 1.100 - __ jump_indirect_to(G5_method_fie, O1_scratch); 1.101 - __ delayed()->nop(); 1.102 + jump_from_method_handle(_masm, G5_method, O1_scratch, O2_scratch); 1.103 } 1.104 break; 1.105 1.106 @@ -1237,9 +1253,7 @@ 1.107 O3_scratch, 1.108 no_such_interface); 1.109 1.110 - __ verify_oop(G5_method); 1.111 - __ jump_indirect_to(G5_method_fie, O1_scratch); 1.112 - __ delayed()->nop(); 1.113 + jump_from_method_handle(_masm, G5_method, O1_scratch, O2_scratch); 1.114 1.115 __ bind(no_such_interface); 1.116 // Throw an exception. 1.117 @@ -1283,9 +1297,7 @@ 1.118 1.119 if (direct_to_method) { 1.120 __ load_heap_oop(G3_mh_vmtarget, G5_method); // target is a methodOop 1.121 - __ verify_oop(G5_method); 1.122 - __ jump_indirect_to(G5_method_fie, O1_scratch); 1.123 - __ delayed()->nop(); 1.124 + jump_from_method_handle(_masm, G5_method, O1_scratch, O2_scratch); 1.125 } else { 1.126 __ load_heap_oop(G3_mh_vmtarget, G3_method_handle); // target is a methodOop 1.127 __ verify_oop(G3_method_handle);
2.1 --- a/src/cpu/sparc/vm/methodHandles_sparc.hpp Thu Jul 14 15:39:40 2011 -0700 2.2 +++ b/src/cpu/sparc/vm/methodHandles_sparc.hpp Fri Jul 15 15:35:50 2011 -0700 2.3 @@ -221,4 +221,8 @@ 2.4 "reference is a MH"); 2.5 } 2.6 2.7 + // Similar to InterpreterMacroAssembler::jump_from_interpreted. 2.8 + // Takes care of special dispatch from single stepping too. 2.9 + static void jump_from_method_handle(MacroAssembler* _masm, Register method, Register temp, Register temp2); 2.10 + 2.11 static void trace_method_handle(MacroAssembler* _masm, const char* adaptername) PRODUCT_RETURN;
3.1 --- a/src/cpu/x86/vm/interp_masm_x86_32.cpp Thu Jul 14 15:39:40 2011 -0700 3.2 +++ b/src/cpu/x86/vm/interp_masm_x86_32.cpp Fri Jul 15 15:35:50 2011 -0700 3.3 @@ -403,9 +403,9 @@ 3.4 // interp_only_mode if these events CAN be enabled. 3.5 get_thread(temp); 3.6 // interp_only is an int, on little endian it is sufficient to test the byte only 3.7 - // Is a cmpl faster (ce 3.8 + // Is a cmpl faster? 3.9 cmpb(Address(temp, JavaThread::interp_only_mode_offset()), 0); 3.10 - jcc(Assembler::zero, run_compiled_code); 3.11 + jccb(Assembler::zero, run_compiled_code); 3.12 jmp(Address(method, methodOopDesc::interpreter_entry_offset())); 3.13 bind(run_compiled_code); 3.14 }
4.1 --- a/src/cpu/x86/vm/interp_masm_x86_64.cpp Thu Jul 14 15:39:40 2011 -0700 4.2 +++ b/src/cpu/x86/vm/interp_masm_x86_64.cpp Fri Jul 15 15:35:50 2011 -0700 4.3 @@ -402,7 +402,7 @@ 4.4 // interp_only is an int, on little endian it is sufficient to test the byte only 4.5 // Is a cmpl faster? 4.6 cmpb(Address(r15_thread, JavaThread::interp_only_mode_offset()), 0); 4.7 - jcc(Assembler::zero, run_compiled_code); 4.8 + jccb(Assembler::zero, run_compiled_code); 4.9 jmp(Address(method, methodOopDesc::interpreter_entry_offset())); 4.10 bind(run_compiled_code); 4.11 }
5.1 --- a/src/cpu/x86/vm/methodHandles_x86.cpp Thu Jul 14 15:39:40 2011 -0700 5.2 +++ b/src/cpu/x86/vm/methodHandles_x86.cpp Fri Jul 15 15:35:50 2011 -0700 5.3 @@ -546,6 +546,28 @@ 5.4 } 5.5 #endif //ASSERT 5.6 5.7 +void MethodHandles::jump_from_method_handle(MacroAssembler* _masm, Register method, Register temp) { 5.8 + if (JvmtiExport::can_post_interpreter_events()) { 5.9 + Label run_compiled_code; 5.10 + // JVMTI events, such as single-stepping, are implemented partly by avoiding running 5.11 + // compiled code in threads for which the event is enabled. Check here for 5.12 + // interp_only_mode if these events CAN be enabled. 5.13 +#ifdef _LP64 5.14 + Register rthread = r15_thread; 5.15 +#else 5.16 + Register rthread = temp; 5.17 + __ get_thread(rthread); 5.18 +#endif 5.19 + // interp_only is an int, on little endian it is sufficient to test the byte only 5.20 + // Is a cmpl faster? 5.21 + __ cmpb(Address(rthread, JavaThread::interp_only_mode_offset()), 0); 5.22 + __ jccb(Assembler::zero, run_compiled_code); 5.23 + __ jmp(Address(method, methodOopDesc::interpreter_entry_offset())); 5.24 + __ bind(run_compiled_code); 5.25 + } 5.26 + __ jmp(Address(method, methodOopDesc::from_interpreted_offset())); 5.27 +} 5.28 + 5.29 // Code generation 5.30 address MethodHandles::generate_method_handle_interpreter_entry(MacroAssembler* _masm) { 5.31 // rbx: methodOop 5.32 @@ -1120,9 +1142,6 @@ 5.33 guarantee(java_lang_invoke_MethodHandle::vmentry_offset_in_bytes() != 0, "must have offsets"); 5.34 5.35 // some handy addresses 5.36 - Address rbx_method_fie( rbx, methodOopDesc::from_interpreted_offset() ); 5.37 - Address rbx_method_fce( rbx, methodOopDesc::from_compiled_offset() ); 5.38 - 5.39 Address rcx_mh_vmtarget( rcx_recv, java_lang_invoke_MethodHandle::vmtarget_offset_in_bytes() ); 5.40 Address rcx_dmh_vmindex( rcx_recv, java_lang_invoke_DirectMethodHandle::vmindex_offset_in_bytes() ); 5.41 5.42 @@ -1163,8 +1182,8 @@ 5.43 assert(raise_exception_method(), "must be set"); 5.44 assert(raise_exception_method()->from_compiled_entry(), "method must be linked"); 5.45 5.46 - const Register rdi_pc = rax; 5.47 - __ pop(rdi_pc); // caller PC 5.48 + const Register rax_pc = rax; 5.49 + __ pop(rax_pc); // caller PC 5.50 __ mov(rsp, saved_last_sp); // cut the stack back to where the caller started 5.51 5.52 Register rbx_method = rbx_temp; 5.53 @@ -1172,11 +1191,15 @@ 5.54 5.55 const int jobject_oop_offset = 0; 5.56 __ movptr(rbx_method, Address(rbx_method, jobject_oop_offset)); // dereference the jobject 5.57 - __ verify_oop(rbx_method); 5.58 5.59 - NOT_LP64(__ push(rarg2_required)); 5.60 - __ push(rdi_pc); // restore caller PC 5.61 - __ jmp(rbx_method_fce); // jump to compiled entry 5.62 + __ movptr(rsi, rsp); 5.63 + __ subptr(rsp, 3 * wordSize); 5.64 + __ push(rax_pc); // restore caller PC 5.65 + 5.66 + __ movptr(__ argument_address(constant(2)), rarg0_code); 5.67 + __ movptr(__ argument_address(constant(1)), rarg1_actual); 5.68 + __ movptr(__ argument_address(constant(0)), rarg2_required); 5.69 + jump_from_method_handle(_masm, rbx_method, rax); 5.70 } 5.71 break; 5.72 5.73 @@ -1195,7 +1218,7 @@ 5.74 __ null_check(rcx_recv); 5.75 __ verify_oop(rcx_recv); 5.76 } 5.77 - __ jmp(rbx_method_fie); 5.78 + jump_from_method_handle(_masm, rbx_method, rax); 5.79 } 5.80 break; 5.81 5.82 @@ -1228,7 +1251,7 @@ 5.83 __ movptr(rbx_method, vtable_entry_addr); 5.84 5.85 __ verify_oop(rbx_method); 5.86 - __ jmp(rbx_method_fie); 5.87 + jump_from_method_handle(_masm, rbx_method, rax); 5.88 } 5.89 break; 5.90 5.91 @@ -1263,7 +1286,7 @@ 5.92 no_such_interface); 5.93 5.94 __ verify_oop(rbx_method); 5.95 - __ jmp(rbx_method_fie); 5.96 + jump_from_method_handle(_masm, rbx_method, rax); 5.97 __ hlt(); 5.98 5.99 __ bind(no_such_interface); 5.100 @@ -1311,7 +1334,7 @@ 5.101 Register rbx_method = rbx_temp; 5.102 __ load_heap_oop(rbx_method, rcx_mh_vmtarget); 5.103 __ verify_oop(rbx_method); 5.104 - __ jmp(rbx_method_fie); 5.105 + jump_from_method_handle(_masm, rbx_method, rax); 5.106 } else { 5.107 __ load_heap_oop(rcx_recv, rcx_mh_vmtarget); 5.108 __ verify_oop(rcx_recv);
6.1 --- a/src/cpu/x86/vm/methodHandles_x86.hpp Thu Jul 14 15:39:40 2011 -0700 6.2 +++ b/src/cpu/x86/vm/methodHandles_x86.hpp Fri Jul 15 15:35:50 2011 -0700 6.3 @@ -291,6 +291,10 @@ 6.4 "reference is a MH"); 6.5 } 6.6 6.7 + // Similar to InterpreterMacroAssembler::jump_from_interpreted. 6.8 + // Takes care of special dispatch from single stepping too. 6.9 + static void jump_from_method_handle(MacroAssembler* _masm, Register method, Register temp); 6.10 + 6.11 static void trace_method_handle(MacroAssembler* _masm, const char* adaptername) PRODUCT_RETURN; 6.12 6.13 static Register saved_last_sp_register() {
7.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 7.2 +++ b/test/compiler/6990212/Test6990212.java Fri Jul 15 15:35:50 2011 -0700 7.3 @@ -0,0 +1,56 @@ 7.4 +/* 7.5 + * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. 7.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 7.7 + * 7.8 + * This code is free software; you can redistribute it and/or modify it 7.9 + * under the terms of the GNU General Public License version 2 only, as 7.10 + * published by the Free Software Foundation. 7.11 + * 7.12 + * This code is distributed in the hope that it will be useful, but WITHOUT 7.13 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 7.14 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 7.15 + * version 2 for more details (a copy is included in the LICENSE file that 7.16 + * accompanied this code). 7.17 + * 7.18 + * You should have received a copy of the GNU General Public License version 7.19 + * 2 along with this work; if not, write to the Free Software Foundation, 7.20 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 7.21 + * 7.22 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 7.23 + * or visit www.oracle.com if you need additional information or have any 7.24 + * questions. 7.25 + * 7.26 + */ 7.27 + 7.28 +/** 7.29 + * @test 7.30 + * @bug 6990212 7.31 + * @summary JSR 292 JVMTI MethodEnter hook is not called for JSR 292 bootstrap and target methods 7.32 + * 7.33 + * @run main Test6990212 7.34 + */ 7.35 + 7.36 +import java.lang.invoke.*; 7.37 + 7.38 +interface intf { 7.39 + public Object target(); 7.40 +} 7.41 + 7.42 +public class Test6990212 implements intf { 7.43 + public Object target() { 7.44 + return null; 7.45 + } 7.46 + 7.47 + public static void main(String[] args) throws Throwable { 7.48 + // Build an interface invoke and then invoke it on something 7.49 + // that doesn't implement the interface to test the 7.50 + // raiseException path. 7.51 + MethodHandle target = MethodHandles.lookup().findVirtual(intf.class, "target", MethodType.methodType(Object.class)); 7.52 + try { 7.53 + target.invoke(new Object()); 7.54 + } catch (ClassCastException cce) { 7.55 + // everything is ok 7.56 + System.out.println("got expected ClassCastException"); 7.57 + } 7.58 + } 7.59 +}