# HG changeset patch # User kvn # Date 1310061067 25200 # Node ID b16582d6c7dbcc73e47132bd38aebc692b5eaa59 # Parent 4bf3cbef0b3ed29bcf6258c75c6425e61c605a92# Parent 3e23978ea0c3fea3755ef474ea108b80cce3fc26 Merge diff -r 4bf3cbef0b3e -r b16582d6c7db src/cpu/sparc/vm/methodHandles_sparc.cpp --- a/src/cpu/sparc/vm/methodHandles_sparc.cpp Wed Jul 06 08:43:01 2011 -0700 +++ b/src/cpu/sparc/vm/methodHandles_sparc.cpp Thu Jul 07 10:51:07 2011 -0700 @@ -307,11 +307,12 @@ __ stop("damaged ricochet frame: L4 < FP"); __ BIND(L_ok_2); - __ sub(L4_saved_args_base, UNREASONABLE_STACK_MOVE * Interpreter::stackElementSize, O7_temp); - __ cmp(O7_temp, FP_temp); - __ br(Assembler::lessEqualUnsigned, false, Assembler::pt, L_ok_3); - __ delayed()->nop(); - __ stop("damaged ricochet frame: (L4 - UNREASONABLE_STACK_MOVE) > FP"); + // Disable until we decide on it's fate + // __ sub(L4_saved_args_base, UNREASONABLE_STACK_MOVE * Interpreter::stackElementSize, O7_temp); + // __ cmp(O7_temp, FP_temp); + // __ br(Assembler::lessEqualUnsigned, false, Assembler::pt, L_ok_3); + // __ delayed()->nop(); + // __ stop("damaged ricochet frame: (L4 - UNREASONABLE_STACK_MOVE) > FP"); __ BIND(L_ok_3); extract_conversion_dest_type(_masm, L5_conversion, O7_temp); @@ -547,8 +548,9 @@ __ brx(Assembler::notEqual, false, Assembler::pt, invoke_generic_slow_path); __ delayed()->nop(); __ mov(O0_mtype, G5_method_type); // required by throw_WrongMethodType - // mov(G3_method_handle, G3_method_handle); // already in this register - __ jump_to(AddressLiteral(Interpreter::throw_WrongMethodType_entry()), O1_scratch); + __ mov(G3_method_handle, G3_method_handle); // already in this register + // O0 will be filled in with JavaThread in stub + __ jump_to(AddressLiteral(StubRoutines::throw_WrongMethodTypeException_entry()), O3_scratch); __ delayed()->nop(); // here's where control starts out: @@ -1145,23 +1147,13 @@ // FIXME: fill in _raise_exception_method with a suitable java.lang.invoke method __ set(AddressLiteral((address) &_raise_exception_method), G5_method); __ ld_ptr(Address(G5_method, 0), G5_method); - __ tst(G5_method); - __ brx(Assembler::zero, false, Assembler::pn, L_no_method); - __ delayed()->nop(); const int jobject_oop_offset = 0; __ ld_ptr(Address(G5_method, jobject_oop_offset), G5_method); - __ tst(G5_method); - __ brx(Assembler::zero, false, Assembler::pn, L_no_method); - __ delayed()->nop(); __ verify_oop(G5_method); __ jump_indirect_to(G5_method_fce, O3_scratch); // jump to compiled entry __ delayed()->nop(); - - // Do something that is at least causes a valid throw from the interpreter. - __ bind(L_no_method); - __ unimplemented("call throw_WrongMethodType_entry"); } break; diff -r 4bf3cbef0b3e -r b16582d6c7db src/cpu/sparc/vm/stubGenerator_sparc.cpp --- a/src/cpu/sparc/vm/stubGenerator_sparc.cpp Wed Jul 06 08:43:01 2011 -0700 +++ b/src/cpu/sparc/vm/stubGenerator_sparc.cpp Thu Jul 07 10:51:07 2011 -0700 @@ -440,7 +440,8 @@ #undef __ #define __ masm-> - address generate_throw_exception(const char* name, address runtime_entry, bool restore_saved_exception_pc) { + address generate_throw_exception(const char* name, address runtime_entry, bool restore_saved_exception_pc, + Register arg1 = noreg, Register arg2 = noreg) { #ifdef ASSERT int insts_size = VerifyThread ? 1 * K : 600; #else @@ -476,6 +477,13 @@ __ set_last_Java_frame(last_java_sp, G0); if (VerifyThread) __ mov(G2_thread, O0); // about to be smashed; pass early __ save_thread(noreg); + if (arg1 != noreg) { + assert(arg2 != O1, "clobbered"); + __ mov(arg1, O1); + } + if (arg2 != noreg) { + __ mov(arg2, O2); + } // do the call BLOCK_COMMENT("call runtime_entry"); __ call(runtime_entry, relocInfo::runtime_call_type); @@ -3240,6 +3248,14 @@ StubRoutines::_atomic_cmpxchg_long_entry = generate_atomic_cmpxchg_long(); StubRoutines::_atomic_add_ptr_entry = StubRoutines::_atomic_add_entry; #endif // COMPILER2 !=> _LP64 + + // Build this early so it's available for the interpreter. The + // stub expects the required and actual type to already be in O1 + // and O2 respectively. + StubRoutines::_throw_WrongMethodTypeException_entry = + generate_throw_exception("WrongMethodTypeException throw_exception", + CAST_FROM_FN_PTR(address, SharedRuntime::throw_WrongMethodTypeException), + false, G5_method_type, G3_method_handle); } diff -r 4bf3cbef0b3e -r b16582d6c7db src/cpu/sparc/vm/templateInterpreter_sparc.cpp --- a/src/cpu/sparc/vm/templateInterpreter_sparc.cpp Wed Jul 06 08:43:01 2011 -0700 +++ b/src/cpu/sparc/vm/templateInterpreter_sparc.cpp Thu Jul 07 10:51:07 2011 -0700 @@ -128,24 +128,6 @@ } -// Arguments are: required type in G5_method_type, and -// failing object (or NULL) in G3_method_handle. -address TemplateInterpreterGenerator::generate_WrongMethodType_handler() { - address entry = __ pc(); - // expression stack must be empty before entering the VM if an exception - // happened - __ empty_expression_stack(); - // load exception object - __ call_VM(Oexception, - CAST_FROM_FN_PTR(address, - InterpreterRuntime::throw_WrongMethodTypeException), - G5_method_type, // required - G3_method_handle); // actual - __ should_not_reach_here(); - return entry; -} - - address TemplateInterpreterGenerator::generate_ArrayIndexOutOfBounds_handler(const char* name) { address entry = __ pc(); // expression stack must be empty before entering the VM if an exception happened diff -r 4bf3cbef0b3e -r b16582d6c7db src/cpu/sparc/vm/templateTable_sparc.cpp --- a/src/cpu/sparc/vm/templateTable_sparc.cpp Wed Jul 06 08:43:01 2011 -0700 +++ b/src/cpu/sparc/vm/templateTable_sparc.cpp Thu Jul 07 10:51:07 2011 -0700 @@ -266,7 +266,7 @@ void TemplateTable::ldc(bool wide) { transition(vtos, vtos); - Label call_ldc, notInt, notString, notClass, exit; + Label call_ldc, notInt, isString, notString, notClass, exit; if (wide) { __ get_2_byte_integer_at_bcp(1, G3_scratch, O1, InterpreterMacroAssembler::Unsigned); @@ -317,8 +317,11 @@ __ bind(notInt); // __ cmp(O2, JVM_CONSTANT_String); + __ brx(Assembler::equal, true, Assembler::pt, isString); + __ delayed()->cmp(O2, JVM_CONSTANT_Object); __ brx(Assembler::notEqual, true, Assembler::pt, notString); __ delayed()->ldf(FloatRegisterImpl::S, O0, O1, Ftos_f); + __ bind(isString); __ ld_ptr(O0, O1, Otos_i); __ verify_oop(Otos_i); __ push(atos); diff -r 4bf3cbef0b3e -r b16582d6c7db src/cpu/x86/vm/assembler_x86.cpp --- a/src/cpu/x86/vm/assembler_x86.cpp Wed Jul 06 08:43:01 2011 -0700 +++ b/src/cpu/x86/vm/assembler_x86.cpp Thu Jul 07 10:51:07 2011 -0700 @@ -3804,6 +3804,14 @@ emit_arith(0x03, 0xC0, dst, src); } +void Assembler::andq(Address dst, int32_t imm32) { + InstructionMark im(this); + prefixq(dst); + emit_byte(0x81); + emit_operand(rsp, dst, 4); + emit_long(imm32); +} + void Assembler::andq(Register dst, int32_t imm32) { (void) prefixq_and_encode(dst->encoding()); emit_arith(0x81, 0xE0, dst, imm32); diff -r 4bf3cbef0b3e -r b16582d6c7db src/cpu/x86/vm/assembler_x86.hpp --- a/src/cpu/x86/vm/assembler_x86.hpp Wed Jul 06 08:43:01 2011 -0700 +++ b/src/cpu/x86/vm/assembler_x86.hpp Thu Jul 07 10:51:07 2011 -0700 @@ -779,6 +779,7 @@ void andl(Register dst, Address src); void andl(Register dst, Register src); + void andq(Address dst, int32_t imm32); void andq(Register dst, int32_t imm32); void andq(Register dst, Address src); void andq(Register dst, Register src); diff -r 4bf3cbef0b3e -r b16582d6c7db src/cpu/x86/vm/icache_x86.hpp --- a/src/cpu/x86/vm/icache_x86.hpp Wed Jul 06 08:43:01 2011 -0700 +++ b/src/cpu/x86/vm/icache_x86.hpp Thu Jul 07 10:51:07 2011 -0700 @@ -43,8 +43,8 @@ #ifdef AMD64 enum { stub_size = 64, // Size of the icache flush stub in bytes - line_size = 32, // Icache line size in bytes - log2_line_size = 5 // log2(line_size) + line_size = 64, // Icache line size in bytes + log2_line_size = 6 // log2(line_size) }; // Use default implementation diff -r 4bf3cbef0b3e -r b16582d6c7db src/cpu/x86/vm/methodHandles_x86.cpp --- a/src/cpu/x86/vm/methodHandles_x86.cpp Wed Jul 06 08:43:01 2011 -0700 +++ b/src/cpu/x86/vm/methodHandles_x86.cpp Thu Jul 07 10:51:07 2011 -0700 @@ -602,15 +602,8 @@ // error path for invokeExact (only) __ bind(invoke_exact_error_path); - // jump(ExternalAddress(Interpreter::throw_WrongMethodType_entry())); - Register rdx_last_Java_sp = rdx_temp; - __ lea(rdx_last_Java_sp, __ argument_address(constant(0))); - __ super_call_VM(noreg, - rdx_last_Java_sp, - CAST_FROM_FN_PTR(address, - InterpreterRuntime::throw_WrongMethodTypeException), - // pass required type, then failing mh object - rax_mtype, rcx_recv); + // Stub wants expected type in rax and the actual type in rcx + __ jump(ExternalAddress(StubRoutines::throw_WrongMethodTypeException_entry())); // for invokeGeneric (only), apply argument and result conversions on the fly __ bind(invoke_generic_slow_path); @@ -1175,27 +1168,15 @@ __ mov(rsp, saved_last_sp); // cut the stack back to where the caller started Register rbx_method = rbx_temp; - Label L_no_method; - // FIXME: fill in _raise_exception_method with a suitable java.lang.invoke method __ movptr(rbx_method, ExternalAddress((address) &_raise_exception_method)); - __ testptr(rbx_method, rbx_method); - __ jccb(Assembler::zero, L_no_method); const int jobject_oop_offset = 0; __ movptr(rbx_method, Address(rbx_method, jobject_oop_offset)); // dereference the jobject - __ testptr(rbx_method, rbx_method); - __ jccb(Assembler::zero, L_no_method); __ verify_oop(rbx_method); NOT_LP64(__ push(rarg2_required)); __ push(rdi_pc); // restore caller PC __ jmp(rbx_method_fce); // jump to compiled entry - - // Do something that is at least causes a valid throw from the interpreter. - __ bind(L_no_method); - __ push(rarg2_required); - __ push(rarg1_actual); - __ jump(ExternalAddress(Interpreter::throw_WrongMethodType_entry())); } break; diff -r 4bf3cbef0b3e -r b16582d6c7db src/cpu/x86/vm/stubGenerator_x86_32.cpp --- a/src/cpu/x86/vm/stubGenerator_x86_32.cpp Wed Jul 06 08:43:01 2011 -0700 +++ b/src/cpu/x86/vm/stubGenerator_x86_32.cpp Thu Jul 07 10:51:07 2011 -0700 @@ -2151,6 +2151,8 @@ // if they expect all registers to be preserved. enum layout { thread_off, // last_java_sp + arg1_off, + arg2_off, rbp_off, // callee saved register ret_pc, framesize @@ -2185,7 +2187,7 @@ // either at call sites or otherwise assume that stack unwinding will be initiated, // so caller saved registers were assumed volatile in the compiler. address generate_throw_exception(const char* name, address runtime_entry, - bool restore_saved_exception_pc) { + bool restore_saved_exception_pc, Register arg1 = noreg, Register arg2 = noreg) { int insts_size = 256; int locs_size = 32; @@ -2218,6 +2220,13 @@ // push java thread (becomes first argument of C function) __ movptr(Address(rsp, thread_off * wordSize), java_thread); + if (arg1 != noreg) { + __ movptr(Address(rsp, arg1_off * wordSize), arg1); + } + if (arg2 != noreg) { + assert(arg1 != noreg, "missing reg arg"); + __ movptr(Address(rsp, arg2_off * wordSize), arg2); + } // Set up last_Java_sp and last_Java_fp __ set_last_Java_frame(java_thread, rsp, rbp, NULL); @@ -2309,6 +2318,12 @@ CAST_FROM_FN_PTR(address, SharedRuntime::d2i)); StubRoutines::_d2l_wrapper = generate_d2i_wrapper(T_LONG, CAST_FROM_FN_PTR(address, SharedRuntime::d2l)); + + // Build this early so it's available for the interpreter + StubRoutines::_throw_WrongMethodTypeException_entry = + generate_throw_exception("WrongMethodTypeException throw_exception", + CAST_FROM_FN_PTR(address, SharedRuntime::throw_WrongMethodTypeException), + false, rax, rcx); } diff -r 4bf3cbef0b3e -r b16582d6c7db src/cpu/x86/vm/stubGenerator_x86_64.cpp --- a/src/cpu/x86/vm/stubGenerator_x86_64.cpp Wed Jul 06 08:43:01 2011 -0700 +++ b/src/cpu/x86/vm/stubGenerator_x86_64.cpp Thu Jul 07 10:51:07 2011 -0700 @@ -2934,7 +2934,9 @@ // caller saved registers were assumed volatile in the compiler. address generate_throw_exception(const char* name, address runtime_entry, - bool restore_saved_exception_pc) { + bool restore_saved_exception_pc, + Register arg1 = noreg, + Register arg2 = noreg) { // Information about frame layout at time of blocking runtime call. // Note that we only have to preserve callee-saved registers since // the compilers are responsible for supplying a continuation point @@ -2980,6 +2982,13 @@ __ set_last_Java_frame(rsp, rbp, NULL); // Call runtime + if (arg1 != noreg) { + assert(arg2 != c_rarg1, "clobbered"); + __ movptr(c_rarg1, arg1); + } + if (arg2 != noreg) { + __ movptr(c_rarg2, arg2); + } __ movptr(c_rarg0, r15_thread); BLOCK_COMMENT("call runtime_entry"); __ call(RuntimeAddress(runtime_entry)); @@ -3052,6 +3061,14 @@ StubRoutines::x86::_get_previous_fp_entry = generate_get_previous_fp(); StubRoutines::x86::_verify_mxcsr_entry = generate_verify_mxcsr(); + + // Build this early so it's available for the interpreter. Stub + // expects the required and actual types as register arguments in + // j_rarg0 and j_rarg1 respectively. + StubRoutines::_throw_WrongMethodTypeException_entry = + generate_throw_exception("WrongMethodTypeException throw_exception", + CAST_FROM_FN_PTR(address, SharedRuntime::throw_WrongMethodTypeException), + false, rax, rcx); } void generate_all() { diff -r 4bf3cbef0b3e -r b16582d6c7db src/cpu/x86/vm/templateInterpreter_x86_32.cpp --- a/src/cpu/x86/vm/templateInterpreter_x86_32.cpp Wed Jul 06 08:43:01 2011 -0700 +++ b/src/cpu/x86/vm/templateInterpreter_x86_32.cpp Thu Jul 07 10:51:07 2011 -0700 @@ -112,32 +112,6 @@ return entry; } -// Arguments are: required type at TOS+4, failing object (or NULL) at TOS. -address TemplateInterpreterGenerator::generate_WrongMethodType_handler() { - address entry = __ pc(); - - __ pop(rbx); // actual failing object is at TOS - __ pop(rax); // required type is at TOS+4 - - __ verify_oop(rbx); - __ verify_oop(rax); - - // Various method handle types use interpreter registers as temps. - __ restore_bcp(); - __ restore_locals(); - - // Expression stack must be empty before entering the VM for an exception. - __ empty_expression_stack(); - __ empty_FPU_stack(); - __ call_VM(noreg, - CAST_FROM_FN_PTR(address, - InterpreterRuntime::throw_WrongMethodTypeException), - // pass required type, failing object (or NULL) - rax, rbx); - return entry; -} - - address TemplateInterpreterGenerator::generate_exception_handler_common(const char* name, const char* message, bool pass_oop) { assert(!pass_oop || message == NULL, "either oop or message but not both"); address entry = __ pc(); diff -r 4bf3cbef0b3e -r b16582d6c7db src/cpu/x86/vm/templateInterpreter_x86_64.cpp --- a/src/cpu/x86/vm/templateInterpreter_x86_64.cpp Wed Jul 06 08:43:01 2011 -0700 +++ b/src/cpu/x86/vm/templateInterpreter_x86_64.cpp Thu Jul 07 10:51:07 2011 -0700 @@ -120,31 +120,6 @@ return entry; } -// Arguments are: required type at TOS+8, failing object (or NULL) at TOS+4. -address TemplateInterpreterGenerator::generate_WrongMethodType_handler() { - address entry = __ pc(); - - __ pop(c_rarg2); // failing object is at TOS - __ pop(c_rarg1); // required type is at TOS+8 - - __ verify_oop(c_rarg1); - __ verify_oop(c_rarg2); - - // Various method handle types use interpreter registers as temps. - __ restore_bcp(); - __ restore_locals(); - - // Expression stack must be empty before entering the VM for an exception. - __ empty_expression_stack(); - - __ call_VM(noreg, - CAST_FROM_FN_PTR(address, - InterpreterRuntime::throw_WrongMethodTypeException), - // pass required type, failing object (or NULL) - c_rarg1, c_rarg2); - return entry; -} - address TemplateInterpreterGenerator::generate_exception_handler_common( const char* name, const char* message, bool pass_oop) { assert(!pass_oop || message == NULL, "either oop or message but not both"); diff -r 4bf3cbef0b3e -r b16582d6c7db src/cpu/x86/vm/templateTable_x86_32.cpp --- a/src/cpu/x86/vm/templateTable_x86_32.cpp Wed Jul 06 08:43:01 2011 -0700 +++ b/src/cpu/x86/vm/templateTable_x86_32.cpp Thu Jul 07 10:51:07 2011 -0700 @@ -373,15 +373,17 @@ __ jcc(Assembler::equal, L); __ cmpl(rdx, JVM_CONSTANT_String); __ jcc(Assembler::equal, L); + __ cmpl(rdx, JVM_CONSTANT_Object); + __ jcc(Assembler::equal, L); __ stop("unexpected tag type in ldc"); __ bind(L); } #endif Label isOop; // atos and itos - // String is only oop type we will see here - __ cmpl(rdx, JVM_CONSTANT_String); - __ jccb(Assembler::equal, isOop); + // Integer is only non-oop type we will see here + __ cmpl(rdx, JVM_CONSTANT_Integer); + __ jccb(Assembler::notEqual, isOop); __ movl(rax, Address(rcx, rbx, Address::times_ptr, base_offset)); __ push(itos); __ jmp(Done); diff -r 4bf3cbef0b3e -r b16582d6c7db src/cpu/x86/vm/templateTable_x86_64.cpp --- a/src/cpu/x86/vm/templateTable_x86_64.cpp Wed Jul 06 08:43:01 2011 -0700 +++ b/src/cpu/x86/vm/templateTable_x86_64.cpp Thu Jul 07 10:51:07 2011 -0700 @@ -385,6 +385,8 @@ __ jcc(Assembler::equal, L); __ cmpl(rdx, JVM_CONSTANT_String); __ jcc(Assembler::equal, L); + __ cmpl(rdx, JVM_CONSTANT_Object); + __ jcc(Assembler::equal, L); __ stop("unexpected tag type in ldc"); __ bind(L); } diff -r 4bf3cbef0b3e -r b16582d6c7db src/cpu/x86/vm/vm_version_x86.cpp --- a/src/cpu/x86/vm/vm_version_x86.cpp Wed Jul 06 08:43:01 2011 -0700 +++ b/src/cpu/x86/vm/vm_version_x86.cpp Thu Jul 07 10:51:07 2011 -0700 @@ -321,6 +321,20 @@ if (UseSSE < 2) UseSSE = 2; #endif +#ifdef AMD64 + // flush_icache_stub have to be generated first. + // That is why Icache line size is hard coded in ICache class, + // see icache_x86.hpp. It is also the reason why we can't use + // clflush instruction in 32-bit VM since it could be running + // on CPU which does not support it. + // + // The only thing we can do is to verify that flushed + // ICache::line_size has correct value. + guarantee(_cpuid_info.std_cpuid1_edx.bits.clflush != 0, "clflush is not supported"); + // clflush_size is size in quadwords (8 bytes). + guarantee(_cpuid_info.std_cpuid1_ebx.bits.clflush_size == 8, "such clflush size is not supported"); +#endif + // If the OS doesn't support SSE, we can't use this feature even if the HW does if (!os::supports_sse()) _cpuFeatures &= ~(CPU_SSE|CPU_SSE2|CPU_SSE3|CPU_SSSE3|CPU_SSE4A|CPU_SSE4_1|CPU_SSE4_2); diff -r 4bf3cbef0b3e -r b16582d6c7db src/cpu/x86/vm/vm_version_x86.hpp --- a/src/cpu/x86/vm/vm_version_x86.hpp Wed Jul 06 08:43:01 2011 -0700 +++ b/src/cpu/x86/vm/vm_version_x86.hpp Thu Jul 07 10:51:07 2011 -0700 @@ -91,7 +91,9 @@ cmpxchg8 : 1, : 6, cmov : 1, - : 7, + : 3, + clflush : 1, + : 3, mmx : 1, fxsr : 1, sse : 1, diff -r 4bf3cbef0b3e -r b16582d6c7db src/cpu/x86/vm/x86_64.ad --- a/src/cpu/x86/vm/x86_64.ad Wed Jul 06 08:43:01 2011 -0700 +++ b/src/cpu/x86/vm/x86_64.ad Thu Jul 07 10:51:07 2011 -0700 @@ -830,6 +830,17 @@ } } +// This could be in MacroAssembler but it's fairly C2 specific +void emit_cmpfp_fixup(MacroAssembler& _masm) { + Label exit; + __ jccb(Assembler::noParity, exit); + __ pushf(); + __ andq(Address(rsp, 0), 0xffffff2b); + __ popf(); + __ bind(exit); + __ nop(); // (target for branch to avoid branch to branch) +} + //============================================================================= const bool Matcher::constant_table_absolute_addressing = true; @@ -2173,27 +2184,9 @@ emit_rm(cbuf, 0x3, $dst$$reg & 7, $src$$reg & 7); %} - enc_class cmpfp_fixup() - %{ - // jnp,s exit - emit_opcode(cbuf, 0x7B); - emit_d8(cbuf, 0x0A); - - // pushfq - emit_opcode(cbuf, 0x9C); - - // andq $0xffffff2b, (%rsp) - emit_opcode(cbuf, Assembler::REX_W); - emit_opcode(cbuf, 0x81); - emit_opcode(cbuf, 0x24); - emit_opcode(cbuf, 0x24); - emit_d32(cbuf, 0xffffff2b); - - // popfq - emit_opcode(cbuf, 0x9D); - - // nop (target for branch to avoid branch to branch) - emit_opcode(cbuf, 0x90); + enc_class cmpfp_fixup() %{ + MacroAssembler _masm(&cbuf); + emit_cmpfp_fixup(_masm); %} enc_class cmpfp3(rRegI dst) @@ -10253,14 +10246,8 @@ "popfq\n" "exit: nop\t# avoid branch to branch" %} ins_encode %{ - Label L_exit; __ ucomiss($src$$XMMRegister, $constantaddress($con)); - __ jcc(Assembler::noParity, L_exit); - __ pushf(); - __ andq(rsp, 0xffffff2b); - __ popf(); - __ bind(L_exit); - __ nop(); + emit_cmpfp_fixup(_masm); %} ins_pipe(pipe_slow); %} @@ -10341,14 +10328,8 @@ "popfq\n" "exit: nop\t# avoid branch to branch" %} ins_encode %{ - Label L_exit; __ ucomisd($src$$XMMRegister, $constantaddress($con)); - __ jcc(Assembler::noParity, L_exit); - __ pushf(); - __ andq(rsp, 0xffffff2b); - __ popf(); - __ bind(L_exit); - __ nop(); + emit_cmpfp_fixup(_masm); %} ins_pipe(pipe_slow); %} diff -r 4bf3cbef0b3e -r b16582d6c7db src/cpu/zero/vm/cppInterpreter_zero.cpp --- a/src/cpu/zero/vm/cppInterpreter_zero.cpp Wed Jul 06 08:43:01 2011 -0700 +++ b/src/cpu/zero/vm/cppInterpreter_zero.cpp Thu Jul 07 10:51:07 2011 -0700 @@ -657,7 +657,7 @@ if (!is_exact) { if (method->intrinsic_id() == vmIntrinsics::_invokeExact) { CALL_VM_NOCHECK_NOFIX( - InterpreterRuntime::throw_WrongMethodTypeException( + SharedRuntime::throw_WrongMethodTypeException( thread, method_type, mhtype)); // NB all oops trashed! assert(HAS_PENDING_EXCEPTION, "should do"); @@ -673,7 +673,7 @@ oop adapter = java_lang_invoke_MethodTypeForm::genericInvoker(form); if (adapter == NULL) { CALL_VM_NOCHECK_NOFIX( - InterpreterRuntime::throw_WrongMethodTypeException( + SharedRuntime::throw_WrongMethodTypeException( thread, method_type, mhtype)); // NB all oops trashed! assert(HAS_PENDING_EXCEPTION, "should do"); diff -r 4bf3cbef0b3e -r b16582d6c7db src/share/tools/hsdis/README --- a/src/share/tools/hsdis/README Wed Jul 06 08:43:01 2011 -0700 +++ b/src/share/tools/hsdis/README Thu Jul 07 10:51:07 2011 -0700 @@ -75,8 +75,16 @@ * Installing Products are named like build/$OS-$LIBARCH/hsdis-$LIBARCH.so. You can -install them on your LD_LIBRARY_PATH, or inside of your JRE next to -$LIBARCH/libjvm.so. +install them on your LD_LIBRARY_PATH, or inside of your JRE/JDK. The +search path in the JVM is: + +1. /jre/lib///libhsdis-.so +2. /jre/lib///hsdis-.so +3. /jre/lib//hsdis-.so +4. hsdis-.so (using LD_LIBRARY_PATH) + +Note that there's a bug in hotspot versions prior to hs22 that causes +steps 2 and 3 to fail when used with JDK7. Now test: diff -r 4bf3cbef0b3e -r b16582d6c7db src/share/vm/adlc/adlparse.cpp --- a/src/share/vm/adlc/adlparse.cpp Wed Jul 06 08:43:01 2011 -0700 +++ b/src/share/vm/adlc/adlparse.cpp Thu Jul 07 10:51:07 2011 -0700 @@ -2812,6 +2812,13 @@ params->add_entry(param); } + // Check for duplicate ins_encode sections after parsing the block + // so that parsing can continue and find any other errors. + if (inst._insencode != NULL) { + parse_err(SYNERR, "Multiple ins_encode sections defined\n"); + return; + } + // Set encode class of this instruction. inst._insencode = encrule; } @@ -3044,6 +3051,13 @@ next_char(); // move past ';' skipws(); // be friendly to oper_parse() + // Check for duplicate ins_encode sections after parsing the block + // so that parsing can continue and find any other errors. + if (inst._insencode != NULL) { + parse_err(SYNERR, "Multiple ins_encode sections defined\n"); + return; + } + // Debug Stuff if (_AD._adl_debug > 1) fprintf(stderr,"Instruction Encode: %s\n", ec_name); diff -r 4bf3cbef0b3e -r b16582d6c7db src/share/vm/c1/c1_GraphBuilder.cpp --- a/src/share/vm/c1/c1_GraphBuilder.cpp Wed Jul 06 08:43:01 2011 -0700 +++ b/src/share/vm/c1/c1_GraphBuilder.cpp Thu Jul 07 10:51:07 2011 -0700 @@ -33,6 +33,7 @@ #include "compiler/compileBroker.hpp" #include "interpreter/bytecode.hpp" #include "runtime/sharedRuntime.hpp" +#include "runtime/compilationPolicy.hpp" #include "utilities/bitMap.inline.hpp" class BlockListBuilder VALUE_OBJ_CLASS_SPEC { @@ -3395,8 +3396,8 @@ bool GraphBuilder::try_inline_full(ciMethod* callee, bool holder_known) { assert(!callee->is_native(), "callee must not be native"); - if (count_backedges() && callee->has_loops()) { - INLINE_BAILOUT("too complex for tiered"); + if (CompilationPolicy::policy()->should_not_inline(compilation()->env(), callee)) { + INLINE_BAILOUT("inlining prohibited by policy"); } // first perform tests of things it's not possible to inline if (callee->has_exception_handlers() && diff -r 4bf3cbef0b3e -r b16582d6c7db src/share/vm/c1/c1_Optimizer.cpp --- a/src/share/vm/c1/c1_Optimizer.cpp Wed Jul 06 08:43:01 2011 -0700 +++ b/src/share/vm/c1/c1_Optimizer.cpp Thu Jul 07 10:51:07 2011 -0700 @@ -642,7 +642,7 @@ void NullCheckVisitor::do_NewTypeArray (NewTypeArray* x) { nce()->handle_NewArray(x); } void NullCheckVisitor::do_NewObjectArray (NewObjectArray* x) { nce()->handle_NewArray(x); } void NullCheckVisitor::do_NewMultiArray (NewMultiArray* x) { nce()->handle_NewArray(x); } -void NullCheckVisitor::do_CheckCast (CheckCast* x) {} +void NullCheckVisitor::do_CheckCast (CheckCast* x) { nce()->clear_last_explicit_null_check(); } void NullCheckVisitor::do_InstanceOf (InstanceOf* x) {} void NullCheckVisitor::do_MonitorEnter (MonitorEnter* x) { nce()->handle_AccessMonitor(x); } void NullCheckVisitor::do_MonitorExit (MonitorExit* x) { nce()->handle_AccessMonitor(x); } diff -r 4bf3cbef0b3e -r b16582d6c7db src/share/vm/c1/c1_Runtime1.cpp --- a/src/share/vm/c1/c1_Runtime1.cpp Wed Jul 06 08:43:01 2011 -0700 +++ b/src/share/vm/c1/c1_Runtime1.cpp Thu Jul 07 10:51:07 2011 -0700 @@ -383,8 +383,10 @@ } JRT_END -// This is a helper to allow us to safepoint but allow the outer entry -// to be safepoint free if we need to do an osr +// counter_overflow() is called from within C1-compiled methods. The enclosing method is the method +// associated with the top activation record. The inlinee (that is possibly included in the enclosing +// method) method oop is passed as an argument. In order to do that it is embedded in the code as +// a constant. static nmethod* counter_overflow_helper(JavaThread* THREAD, int branch_bci, methodOopDesc* m) { nmethod* osr_nm = NULL; methodHandle method(THREAD, m); @@ -420,7 +422,7 @@ bci = branch_bci + offset; } - osr_nm = CompilationPolicy::policy()->event(enclosing_method, method, branch_bci, bci, level, THREAD); + osr_nm = CompilationPolicy::policy()->event(enclosing_method, method, branch_bci, bci, level, nm, THREAD); return osr_nm; } diff -r 4bf3cbef0b3e -r b16582d6c7db src/share/vm/ci/ciEnv.cpp --- a/src/share/vm/ci/ciEnv.cpp Wed Jul 06 08:43:01 2011 -0700 +++ b/src/share/vm/ci/ciEnv.cpp Thu Jul 07 10:51:07 2011 -0700 @@ -50,6 +50,7 @@ #include "oops/oop.inline.hpp" #include "oops/oop.inline2.hpp" #include "prims/jvmtiExport.hpp" +#include "prims/methodHandleWalk.hpp" #include "runtime/init.hpp" #include "runtime/reflection.hpp" #include "runtime/sharedRuntime.hpp" @@ -371,6 +372,7 @@ // ------------------------------------------------------------------ // ciEnv::get_klass_by_name_impl ciKlass* ciEnv::get_klass_by_name_impl(ciKlass* accessing_klass, + constantPoolHandle cpool, ciSymbol* name, bool require_local) { ASSERT_IN_VM; @@ -386,7 +388,7 @@ sym->utf8_length()-2, KILL_COMPILE_ON_FATAL_(_unloaded_ciinstance_klass)); ciSymbol* strippedname = get_symbol(strippedsym); - return get_klass_by_name_impl(accessing_klass, strippedname, require_local); + return get_klass_by_name_impl(accessing_klass, cpool, strippedname, require_local); } // Check for prior unloaded klass. The SystemDictionary's answers @@ -443,6 +445,7 @@ // Get element ciKlass recursively. ciKlass* elem_klass = get_klass_by_name_impl(accessing_klass, + cpool, get_symbol(elem_sym), require_local); if (elem_klass != NULL && elem_klass->is_loaded()) { @@ -451,6 +454,19 @@ } } + if (found_klass() == NULL && !cpool.is_null() && cpool->has_preresolution()) { + // Look inside the constant pool for pre-resolved class entries. + for (int i = cpool->length() - 1; i >= 1; i--) { + if (cpool->tag_at(i).is_klass()) { + klassOop kls = cpool->resolved_klass_at(i); + if (Klass::cast(kls)->name() == sym) { + found_klass = KlassHandle(THREAD, kls); + break; + } + } + } + } + if (found_klass() != NULL) { // Found it. Build a CI handle. return get_object(found_klass())->as_klass(); @@ -468,6 +484,7 @@ ciSymbol* klass_name, bool require_local) { GUARDED_VM_ENTRY(return get_klass_by_name_impl(accessing_klass, + constantPoolHandle(), klass_name, require_local);) } @@ -508,13 +525,14 @@ if (klass.is_null()) { // Not found in constant pool. Use the name to do the lookup. ciKlass* k = get_klass_by_name_impl(accessor, + cpool, get_symbol(klass_name), false); // Calculate accessibility the hard way. if (!k->is_loaded()) { is_accessible = false; } else if (k->loader() != accessor->loader() && - get_klass_by_name_impl(accessor, k->name(), true) == NULL) { + get_klass_by_name_impl(accessor, cpool, k->name(), true) == NULL) { // Loaded only remotely. Not linked yet. is_accessible = false; } else { @@ -565,7 +583,7 @@ index = cpc_entry->constant_pool_index(); oop obj = cpc_entry->f1(); if (obj != NULL) { - assert(obj->is_instance(), "must be an instance"); + assert(obj->is_instance() || obj->is_array(), "must be a Java reference"); ciObject* ciobj = get_object(obj); return ciConstant(T_OBJECT, ciobj); } @@ -607,7 +625,7 @@ return ciConstant(T_OBJECT, klass->java_mirror()); } else if (tag.is_object()) { oop obj = cpool->object_at(index); - assert(obj->is_instance(), "must be an instance"); + assert(obj->is_instance() || obj->is_array(), "must be a Java reference"); ciObject* ciobj = get_object(obj); return ciConstant(T_OBJECT, ciobj); } else if (tag.is_method_type()) { @@ -729,9 +747,35 @@ Symbol* name_sym = cpool->name_ref_at(index); Symbol* sig_sym = cpool->signature_ref_at(index); + if (cpool->has_preresolution() + || (holder == ciEnv::MethodHandle_klass() && + methodOopDesc::is_method_handle_invoke_name(name_sym))) { + // Short-circuit lookups for JSR 292-related call sites. + // That is, do not rely only on name-based lookups, because they may fail + // if the names are not resolvable in the boot class loader (7056328). + switch (bc) { + case Bytecodes::_invokevirtual: + case Bytecodes::_invokeinterface: + case Bytecodes::_invokespecial: + case Bytecodes::_invokestatic: + { + methodOop m = constantPoolOopDesc::method_at_if_loaded(cpool, index, bc); + if (m != NULL) { + return get_object(m)->as_method(); + } + } + } + } + if (holder_is_accessible) { // Our declared holder is loaded. instanceKlass* lookup = declared_holder->get_instanceKlass(); methodOop m = lookup_method(accessor->get_instanceKlass(), lookup, name_sym, sig_sym, bc); + if (m != NULL && + (bc == Bytecodes::_invokestatic + ? instanceKlass::cast(m->method_holder())->is_not_initialized() + : !instanceKlass::cast(m->method_holder())->is_loaded())) { + m = NULL; + } if (m != NULL) { // We found the method. return get_object(m)->as_method(); @@ -1046,7 +1090,7 @@ // ciEnv::find_system_klass ciKlass* ciEnv::find_system_klass(ciSymbol* klass_name) { VM_ENTRY_MARK; - return get_klass_by_name_impl(NULL, klass_name, false); + return get_klass_by_name_impl(NULL, constantPoolHandle(), klass_name, false); } // ------------------------------------------------------------------ diff -r 4bf3cbef0b3e -r b16582d6c7db src/share/vm/ci/ciEnv.hpp --- a/src/share/vm/ci/ciEnv.hpp Wed Jul 06 08:43:01 2011 -0700 +++ b/src/share/vm/ci/ciEnv.hpp Thu Jul 07 10:51:07 2011 -0700 @@ -137,6 +137,7 @@ // Implementation methods for loading and constant pool access. ciKlass* get_klass_by_name_impl(ciKlass* accessing_klass, + constantPoolHandle cpool, ciSymbol* klass_name, bool require_local); ciKlass* get_klass_by_index_impl(constantPoolHandle cpool, diff -r 4bf3cbef0b3e -r b16582d6c7db src/share/vm/ci/ciField.cpp --- a/src/share/vm/ci/ciField.cpp Wed Jul 06 08:43:01 2011 -0700 +++ b/src/share/vm/ci/ciField.cpp Thu Jul 07 10:51:07 2011 -0700 @@ -287,7 +287,7 @@ } ciType* ciField::compute_type_impl() { - ciKlass* type = CURRENT_ENV->get_klass_by_name_impl(_holder, _signature, false); + ciKlass* type = CURRENT_ENV->get_klass_by_name_impl(_holder, constantPoolHandle(), _signature, false); if (!type->is_primitive_type() && is_shared()) { // We must not cache a pointer to an unshared type, in a shared field. bool type_is_also_shared = false; diff -r 4bf3cbef0b3e -r b16582d6c7db src/share/vm/ci/ciMethod.cpp --- a/src/share/vm/ci/ciMethod.cpp Wed Jul 06 08:43:01 2011 -0700 +++ b/src/share/vm/ci/ciMethod.cpp Thu Jul 07 10:51:07 2011 -0700 @@ -125,7 +125,8 @@ _name = env->get_symbol(h_m()->name()); _holder = env->get_object(h_m()->method_holder())->as_instance_klass(); ciSymbol* sig_symbol = env->get_symbol(h_m()->signature()); - _signature = new (env->arena()) ciSignature(_holder, sig_symbol); + constantPoolHandle cpool = h_m()->constants(); + _signature = new (env->arena()) ciSignature(_holder, cpool, sig_symbol); _method_data = NULL; // Take a snapshot of these values, so they will be commensurate with the MDO. if (ProfileInterpreter || TieredCompilation) { @@ -152,7 +153,7 @@ // These fields are always filled in. _name = name; _holder = holder; - _signature = new (CURRENT_ENV->arena()) ciSignature(_holder, signature); + _signature = new (CURRENT_ENV->arena()) ciSignature(_holder, constantPoolHandle(), signature); _intrinsic_id = vmIntrinsics::_none; _liveness = NULL; _can_be_statically_bound = false; @@ -1009,6 +1010,12 @@ return 0; } +int ciMethod::highest_osr_comp_level() { + check_is_loaded(); + VM_ENTRY_MARK; + return get_methodOop()->highest_osr_comp_level(); +} + // ------------------------------------------------------------------ // ciMethod::instructions_size // diff -r 4bf3cbef0b3e -r b16582d6c7db src/share/vm/ci/ciMethod.hpp --- a/src/share/vm/ci/ciMethod.hpp Wed Jul 06 08:43:01 2011 -0700 +++ b/src/share/vm/ci/ciMethod.hpp Thu Jul 07 10:51:07 2011 -0700 @@ -158,6 +158,7 @@ int interpreter_throwout_count() const { check_is_loaded(); return _interpreter_throwout_count; } int comp_level(); + int highest_osr_comp_level(); Bytecodes::Code java_code_at_bci(int bci) { address bcp = code() + bci; diff -r 4bf3cbef0b3e -r b16582d6c7db src/share/vm/ci/ciMethodHandle.cpp --- a/src/share/vm/ci/ciMethodHandle.cpp Wed Jul 06 08:43:01 2011 -0700 +++ b/src/share/vm/ci/ciMethodHandle.cpp Thu Jul 07 10:51:07 2011 -0700 @@ -41,6 +41,16 @@ VM_ENTRY_MARK; Handle h(get_oop()); methodHandle callee(_callee->get_methodOop()); + assert(callee->is_method_handle_invoke(), ""); + oop mt1 = callee->method_handle_type(); + oop mt2 = java_lang_invoke_MethodHandle::type(h()); + if (!java_lang_invoke_MethodType::equals(mt1, mt2)) { + if (PrintMiscellaneous && (Verbose || WizardMode)) { + tty->print_cr("ciMethodHandle::get_adapter: types not equal"); + mt1->print(); mt2->print(); + } + return NULL; + } // We catch all exceptions here that could happen in the method // handle compiler and stop the VM. MethodHandleCompiler mhc(h, callee->name(), callee->signature(), _profile.count(), is_invokedynamic, THREAD); @@ -53,7 +63,7 @@ if (PrintMiscellaneous && (Verbose || WizardMode)) { tty->print("*** ciMethodHandle::get_adapter => "); PENDING_EXCEPTION->print(); - tty->print("*** get_adapter (%s): ", is_invokedynamic ? "indy" : "mh"); ((ciObject*)this)->print(); //@@ + tty->print("*** get_adapter (%s): ", is_invokedynamic ? "indy" : "mh"); ((ciObject*)this)->print(); } CLEAR_PENDING_EXCEPTION; return NULL; diff -r 4bf3cbef0b3e -r b16582d6c7db src/share/vm/ci/ciObjArrayKlass.cpp --- a/src/share/vm/ci/ciObjArrayKlass.cpp Wed Jul 06 08:43:01 2011 -0700 +++ b/src/share/vm/ci/ciObjArrayKlass.cpp Thu Jul 07 10:51:07 2011 -0700 @@ -93,6 +93,7 @@ // element klass by name. _element_klass = CURRENT_THREAD_ENV->get_klass_by_name_impl( this, + constantPoolHandle(), construct_array_name(base_element_klass()->name(), dimension() - 1), false); diff -r 4bf3cbef0b3e -r b16582d6c7db src/share/vm/ci/ciSignature.cpp --- a/src/share/vm/ci/ciSignature.cpp Wed Jul 06 08:43:01 2011 -0700 +++ b/src/share/vm/ci/ciSignature.cpp Thu Jul 07 10:51:07 2011 -0700 @@ -35,7 +35,7 @@ // ------------------------------------------------------------------ // ciSignature::ciSignature -ciSignature::ciSignature(ciKlass* accessing_klass, ciSymbol* symbol) { +ciSignature::ciSignature(ciKlass* accessing_klass, constantPoolHandle cpool, ciSymbol* symbol) { ASSERT_IN_VM; EXCEPTION_CONTEXT; _accessing_klass = accessing_klass; @@ -64,7 +64,7 @@ CLEAR_PENDING_EXCEPTION; } else { ciSymbol* klass_name = env->get_symbol(name); - type = env->get_klass_by_name_impl(_accessing_klass, klass_name, false); + type = env->get_klass_by_name_impl(_accessing_klass, cpool, klass_name, false); } } _types->append(type); diff -r 4bf3cbef0b3e -r b16582d6c7db src/share/vm/ci/ciSignature.hpp --- a/src/share/vm/ci/ciSignature.hpp Wed Jul 06 08:43:01 2011 -0700 +++ b/src/share/vm/ci/ciSignature.hpp Thu Jul 07 10:51:07 2011 -0700 @@ -44,7 +44,7 @@ friend class ciMethod; - ciSignature(ciKlass* accessing_klass, ciSymbol* signature); + ciSignature(ciKlass* accessing_klass, constantPoolHandle cpool, ciSymbol* signature); void get_all_klasses(); diff -r 4bf3cbef0b3e -r b16582d6c7db src/share/vm/classfile/classFileParser.cpp --- a/src/share/vm/classfile/classFileParser.cpp Wed Jul 06 08:43:01 2011 -0700 +++ b/src/share/vm/classfile/classFileParser.cpp Thu Jul 07 10:51:07 2011 -0700 @@ -3287,9 +3287,9 @@ // Fields allocation: oops fields in super and sub classes are together. if( nonstatic_field_size > 0 && super_klass() != NULL && super_klass->nonstatic_oop_map_size() > 0 ) { - int map_size = super_klass->nonstatic_oop_map_size(); + int map_count = super_klass->nonstatic_oop_map_count(); OopMapBlock* first_map = super_klass->start_of_nonstatic_oop_maps(); - OopMapBlock* last_map = first_map + map_size - 1; + OopMapBlock* last_map = first_map + map_count - 1; int next_offset = last_map->offset() + (last_map->count() * heapOopSize); if (next_offset == next_nonstatic_field_offset) { allocation_style = 0; // allocate oops first diff -r 4bf3cbef0b3e -r b16582d6c7db src/share/vm/classfile/javaClasses.cpp --- a/src/share/vm/classfile/javaClasses.cpp Wed Jul 06 08:43:01 2011 -0700 +++ b/src/share/vm/classfile/javaClasses.cpp Thu Jul 07 10:51:07 2011 -0700 @@ -2547,6 +2547,18 @@ return name; } +bool java_lang_invoke_MethodType::equals(oop mt1, oop mt2) { + if (rtype(mt1) != rtype(mt2)) + return false; + if (ptype_count(mt1) != ptype_count(mt2)) + return false; + for (int i = ptype_count(mt1) - 1; i >= 0; i--) { + if (ptype(mt1, i) != ptype(mt2, i)) + return false; + } + return true; +} + oop java_lang_invoke_MethodType::rtype(oop mt) { assert(is_instance(mt), "must be a MethodType"); return mt->obj_field(_rtype_offset); diff -r 4bf3cbef0b3e -r b16582d6c7db src/share/vm/classfile/javaClasses.hpp --- a/src/share/vm/classfile/javaClasses.hpp Wed Jul 06 08:43:01 2011 -0700 +++ b/src/share/vm/classfile/javaClasses.hpp Thu Jul 07 10:51:07 2011 -0700 @@ -1079,6 +1079,8 @@ return obj != NULL && obj->klass() == SystemDictionary::MethodType_klass(); } + static bool equals(oop mt1, oop mt2); + // Accessors for code generation: static int rtype_offset_in_bytes() { return _rtype_offset; } static int ptypes_offset_in_bytes() { return _ptypes_offset; } diff -r 4bf3cbef0b3e -r b16582d6c7db src/share/vm/classfile/systemDictionary.cpp --- a/src/share/vm/classfile/systemDictionary.cpp Wed Jul 06 08:43:01 2011 -0700 +++ b/src/share/vm/classfile/systemDictionary.cpp Thu Jul 07 10:51:07 2011 -0700 @@ -2367,6 +2367,8 @@ // Link m to his method type, if it is suitably generic. oop mtform = java_lang_invoke_MethodType::form(mt()); if (mtform != NULL && mt() == java_lang_invoke_MethodTypeForm::erasedType(mtform) + // vmlayout must be an invokeExact: + && name_id == vmSymbols::VM_SYMBOL_ENUM_NAME(invokeExact_name) && java_lang_invoke_MethodTypeForm::vmlayout_offset_in_bytes() > 0) { java_lang_invoke_MethodTypeForm::init_vmlayout(mtform, m()); } diff -r 4bf3cbef0b3e -r b16582d6c7db src/share/vm/code/nmethod.cpp --- a/src/share/vm/code/nmethod.cpp Wed Jul 06 08:43:01 2011 -0700 +++ b/src/share/vm/code/nmethod.cpp Thu Jul 07 10:51:07 2011 -0700 @@ -1832,7 +1832,9 @@ if (!method()->is_native()) { SimpleScopeDesc ssd(this, fr.pc()); Bytecode_invoke call(ssd.method(), ssd.bci()); - bool has_receiver = call.has_receiver(); + // compiled invokedynamic call sites have an implicit receiver at + // resolution time, so make sure it gets GC'ed. + bool has_receiver = !call.is_invokestatic(); Symbol* signature = call.signature(); fr.oops_compiled_arguments_do(signature, has_receiver, reg_map, f); } diff -r 4bf3cbef0b3e -r b16582d6c7db src/share/vm/compiler/disassembler.cpp --- a/src/share/vm/compiler/disassembler.cpp Wed Jul 06 08:43:01 2011 -0700 +++ b/src/share/vm/compiler/disassembler.cpp Thu Jul 07 10:51:07 2011 -0700 @@ -78,21 +78,46 @@ char buf[JVM_MAXPATHLEN]; os::jvm_path(buf, sizeof(buf)); int jvm_offset = -1; + int lib_offset = -1; { // Match "jvm[^/]*" in jvm_path. const char* base = buf; const char* p = strrchr(buf, '/'); + if (p != NULL) lib_offset = p - base + 1; p = strstr(p ? p : base, "jvm"); if (p != NULL) jvm_offset = p - base; } + // Find the disassembler shared library. + // Search for several paths derived from libjvm, in this order: + // 1. /jre/lib///libhsdis-.so (for compatibility) + // 2. /jre/lib///hsdis-.so + // 3. /jre/lib//hsdis-.so + // 4. hsdis-.so (using LD_LIBRARY_PATH) if (jvm_offset >= 0) { - // Find the disassembler next to libjvm.so. + // 1. /jre/lib///libhsdis-.so strcpy(&buf[jvm_offset], hsdis_library_name); strcat(&buf[jvm_offset], os::dll_file_extension()); _library = os::dll_load(buf, ebuf, sizeof ebuf); + if (_library == NULL) { + // 2. /jre/lib///hsdis-.so + strcpy(&buf[lib_offset], hsdis_library_name); + strcat(&buf[lib_offset], os::dll_file_extension()); + _library = os::dll_load(buf, ebuf, sizeof ebuf); + } + if (_library == NULL) { + // 3. /jre/lib//hsdis-.so + buf[lib_offset - 1] = '\0'; + const char* p = strrchr(buf, '/'); + if (p != NULL) { + lib_offset = p - buf + 1; + strcpy(&buf[lib_offset], hsdis_library_name); + strcat(&buf[lib_offset], os::dll_file_extension()); + _library = os::dll_load(buf, ebuf, sizeof ebuf); + } + } } if (_library == NULL) { - // Try a free-floating lookup. + // 4. hsdis-.so (using LD_LIBRARY_PATH) strcpy(&buf[0], hsdis_library_name); strcat(&buf[0], os::dll_file_extension()); _library = os::dll_load(buf, ebuf, sizeof ebuf); @@ -249,7 +274,13 @@ return arg; } } else if (match(event, "mach")) { - output()->print_cr("[Disassembling for mach='%s']", arg); + static char buffer[32] = { 0, }; + if (strcmp(buffer, (const char*)arg) != 0 || + strlen((const char*)arg) > sizeof(buffer) - 1) { + // Only print this when the mach changes + strncpy(buffer, (const char*)arg, sizeof(buffer) - 1); + output()->print_cr("[Disassembling for mach='%s']", arg); + } } else if (match(event, "format bytes-per-line")) { _bytes_per_line = (int) (intptr_t) arg; } else { diff -r 4bf3cbef0b3e -r b16582d6c7db src/share/vm/interpreter/interpreterRuntime.cpp --- a/src/share/vm/interpreter/interpreterRuntime.cpp Wed Jul 06 08:43:01 2011 -0700 +++ b/src/share/vm/interpreter/interpreterRuntime.cpp Thu Jul 07 10:51:07 2011 -0700 @@ -362,25 +362,6 @@ THROW_MSG(vmSymbols::java_lang_ClassCastException(), message); IRT_END -// required can be either a MethodType, or a Class (for a single argument) -// actual (if not null) can be either a MethodHandle, or an arbitrary value (for a single argument) -IRT_ENTRY(void, InterpreterRuntime::throw_WrongMethodTypeException(JavaThread* thread, - oopDesc* required, - oopDesc* actual)) { - ResourceMark rm(thread); - char* message = SharedRuntime::generate_wrong_method_type_message(thread, required, actual); - - if (ProfileTraps) { - note_trap(thread, Deoptimization::Reason_constraint, CHECK); - } - - // create exception - THROW_MSG(vmSymbols::java_lang_invoke_WrongMethodTypeException(), message); -} -IRT_END - - - // exception_handler_for_exception(...) returns the continuation address, // the exception oop (via TLS) and sets the bci/bcp for the continuation. // The exception oop is returned to make sure it is preserved over GC (it @@ -863,7 +844,7 @@ const int branch_bci = branch_bcp != NULL ? method->bci_from(branch_bcp) : InvocationEntryBci; const int bci = branch_bcp != NULL ? method->bci_from(fr.interpreter_frame_bcp()) : InvocationEntryBci; - nmethod* osr_nm = CompilationPolicy::policy()->event(method, method, branch_bci, bci, CompLevel_none, thread); + nmethod* osr_nm = CompilationPolicy::policy()->event(method, method, branch_bci, bci, CompLevel_none, NULL, thread); if (osr_nm != NULL) { // We may need to do on-stack replacement which requires that no diff -r 4bf3cbef0b3e -r b16582d6c7db src/share/vm/interpreter/interpreterRuntime.hpp --- a/src/share/vm/interpreter/interpreterRuntime.hpp Wed Jul 06 08:43:01 2011 -0700 +++ b/src/share/vm/interpreter/interpreterRuntime.hpp Thu Jul 07 10:51:07 2011 -0700 @@ -98,7 +98,6 @@ static void throw_StackOverflowError(JavaThread* thread); static void throw_ArrayIndexOutOfBoundsException(JavaThread* thread, char* name, jint index); static void throw_ClassCastException(JavaThread* thread, oopDesc* obj); - static void throw_WrongMethodTypeException(JavaThread* thread, oopDesc* mtype = NULL, oopDesc* mhandle = NULL); static void create_exception(JavaThread* thread, char* name, char* message); static void create_klass_exception(JavaThread* thread, char* name, oopDesc* obj); static address exception_handler_for_exception(JavaThread* thread, oopDesc* exception); diff -r 4bf3cbef0b3e -r b16582d6c7db src/share/vm/interpreter/linkResolver.cpp --- a/src/share/vm/interpreter/linkResolver.cpp Wed Jul 06 08:43:01 2011 -0700 +++ b/src/share/vm/interpreter/linkResolver.cpp Thu Jul 07 10:51:07 2011 -0700 @@ -294,6 +294,16 @@ Symbol* method_signature = pool->signature_ref_at(index); KlassHandle current_klass(THREAD, pool->pool_holder()); + if (pool->has_preresolution() + || (resolved_klass() == SystemDictionary::MethodHandle_klass() && + methodOopDesc::is_method_handle_invoke_name(method_name))) { + methodOop result_oop = constantPoolOopDesc::method_at_if_loaded(pool, index); + if (result_oop != NULL) { + resolved_method = methodHandle(THREAD, result_oop); + return; + } + } + resolve_method(resolved_method, resolved_klass, method_name, method_signature, current_klass, true, CHECK); } diff -r 4bf3cbef0b3e -r b16582d6c7db src/share/vm/interpreter/templateInterpreter.cpp --- a/src/share/vm/interpreter/templateInterpreter.cpp Wed Jul 06 08:43:01 2011 -0700 +++ b/src/share/vm/interpreter/templateInterpreter.cpp Thu Jul 07 10:51:07 2011 -0700 @@ -171,7 +171,6 @@ address TemplateInterpreter::_throw_ArrayStoreException_entry = NULL; address TemplateInterpreter::_throw_ArithmeticException_entry = NULL; address TemplateInterpreter::_throw_ClassCastException_entry = NULL; -address TemplateInterpreter::_throw_WrongMethodType_entry = NULL; address TemplateInterpreter::_throw_NullPointerException_entry = NULL; address TemplateInterpreter::_throw_StackOverflowError_entry = NULL; address TemplateInterpreter::_throw_exception_entry = NULL; @@ -346,7 +345,6 @@ Interpreter::_throw_ArrayStoreException_entry = generate_klass_exception_handler("java/lang/ArrayStoreException" ); Interpreter::_throw_ArithmeticException_entry = generate_exception_handler("java/lang/ArithmeticException" , "/ by zero"); Interpreter::_throw_ClassCastException_entry = generate_ClassCastException_handler(); - Interpreter::_throw_WrongMethodType_entry = generate_WrongMethodType_handler(); Interpreter::_throw_NullPointerException_entry = generate_exception_handler("java/lang/NullPointerException" , NULL ); Interpreter::_throw_StackOverflowError_entry = generate_StackOverflowError_handler(); } diff -r 4bf3cbef0b3e -r b16582d6c7db src/share/vm/interpreter/templateInterpreterGenerator.hpp --- a/src/share/vm/interpreter/templateInterpreterGenerator.hpp Wed Jul 06 08:43:01 2011 -0700 +++ b/src/share/vm/interpreter/templateInterpreterGenerator.hpp Thu Jul 07 10:51:07 2011 -0700 @@ -51,7 +51,6 @@ } address generate_exception_handler_common(const char* name, const char* message, bool pass_oop); address generate_ClassCastException_handler(); - address generate_WrongMethodType_handler(); address generate_ArrayIndexOutOfBounds_handler(const char* name); address generate_continuation_for(TosState state); address generate_return_entry_for(TosState state, int step); diff -r 4bf3cbef0b3e -r b16582d6c7db src/share/vm/oops/constantPoolKlass.cpp --- a/src/share/vm/oops/constantPoolKlass.cpp Wed Jul 06 08:43:01 2011 -0700 +++ b/src/share/vm/oops/constantPoolKlass.cpp Thu Jul 07 10:51:07 2011 -0700 @@ -310,10 +310,14 @@ st->print(" - flags: 0x%x", cp->flags()); if (cp->has_pseudo_string()) st->print(" has_pseudo_string"); if (cp->has_invokedynamic()) st->print(" has_invokedynamic"); + if (cp->has_preresolution()) st->print(" has_preresolution"); st->cr(); } + if (cp->pool_holder() != NULL) { + bool extra = (instanceKlass::cast(cp->pool_holder())->constants() != cp); + st->print_cr(" - holder: " INTPTR_FORMAT "%s", cp->pool_holder(), (extra? " (extra)" : "")); + } st->print_cr(" - cache: " INTPTR_FORMAT, cp->cache()); - for (int index = 1; index < cp->length(); index++) { // Index 0 is unused st->print(" - %3d : ", index); cp->tag_at(index).print_on(st); @@ -414,10 +418,15 @@ st->print("constant pool [%d]", cp->length()); if (cp->has_pseudo_string()) st->print("/pseudo_string"); if (cp->has_invokedynamic()) st->print("/invokedynamic"); + if (cp->has_preresolution()) st->print("/preresolution"); if (cp->operands() != NULL) st->print("/operands[%d]", cp->operands()->length()); cp->print_address_on(st); st->print(" for "); cp->pool_holder()->print_value_on(st); + if (cp->pool_holder() != NULL) { + bool extra = (instanceKlass::cast(cp->pool_holder())->constants() != cp); + if (extra) st->print(" (extra)"); + } if (cp->cache() != NULL) { st->print(" cache=" PTR_FORMAT, cp->cache()); } diff -r 4bf3cbef0b3e -r b16582d6c7db src/share/vm/oops/constantPoolOop.cpp --- a/src/share/vm/oops/constantPoolOop.cpp Wed Jul 06 08:43:01 2011 -0700 +++ b/src/share/vm/oops/constantPoolOop.cpp Thu Jul 07 10:51:07 2011 -0700 @@ -266,6 +266,29 @@ } +methodOop constantPoolOopDesc::method_at_if_loaded(constantPoolHandle cpool, + int which, Bytecodes::Code invoke_code) { + assert(!constantPoolCacheOopDesc::is_secondary_index(which), "no indy instruction here"); + if (cpool->cache() == NULL) return false; // nothing to load yet + int cache_index = which - CPCACHE_INDEX_TAG; + if (!(cache_index >= 0 && cache_index < cpool->cache()->length())) { + if (PrintMiscellaneous && (Verbose||WizardMode)) { + tty->print_cr("bad operand %d for %d in:", which, invoke_code); cpool->print(); + } + return NULL; + } + ConstantPoolCacheEntry* e = cpool->cache()->entry_at(cache_index); + if (invoke_code != Bytecodes::_illegal) + return e->get_method_if_resolved(invoke_code, cpool); + Bytecodes::Code bc; + if ((bc = e->bytecode_1()) != (Bytecodes::Code)0) + return e->get_method_if_resolved(bc, cpool); + if ((bc = e->bytecode_2()) != (Bytecodes::Code)0) + return e->get_method_if_resolved(bc, cpool); + return NULL; +} + + Symbol* constantPoolOopDesc::impl_name_ref_at(int which, bool uncached) { int name_index = name_ref_index_at(impl_name_and_type_ref_index_at(which, uncached)); return symbol_at(name_index); diff -r 4bf3cbef0b3e -r b16582d6c7db src/share/vm/oops/constantPoolOop.hpp --- a/src/share/vm/oops/constantPoolOop.hpp Wed Jul 06 08:43:01 2011 -0700 +++ b/src/share/vm/oops/constantPoolOop.hpp Thu Jul 07 10:51:07 2011 -0700 @@ -103,7 +103,8 @@ enum FlagBit { FB_has_invokedynamic = 1, - FB_has_pseudo_string = 2 + FB_has_pseudo_string = 2, + FB_has_preresolution = 3 }; int flags() const { return _flags; } @@ -179,8 +180,10 @@ bool has_pseudo_string() const { return flag_at(FB_has_pseudo_string); } bool has_invokedynamic() const { return flag_at(FB_has_invokedynamic); } + bool has_preresolution() const { return flag_at(FB_has_preresolution); } void set_pseudo_string() { set_flag_at(FB_has_pseudo_string); } void set_invokedynamic() { set_flag_at(FB_has_invokedynamic); } + void set_preresolution() { set_flag_at(FB_has_preresolution); } // Klass holding pool klassOop pool_holder() const { return _pool_holder; } @@ -663,6 +666,8 @@ friend class SystemDictionary; // Used by compiler to prevent classloading. + static methodOop method_at_if_loaded (constantPoolHandle this_oop, int which, + Bytecodes::Code bc = Bytecodes::_illegal); static klassOop klass_at_if_loaded (constantPoolHandle this_oop, int which); static klassOop klass_ref_at_if_loaded (constantPoolHandle this_oop, int which); // Same as above - but does LinkResolving. diff -r 4bf3cbef0b3e -r b16582d6c7db src/share/vm/oops/cpCacheOop.cpp --- a/src/share/vm/oops/cpCacheOop.cpp Wed Jul 06 08:43:01 2011 -0700 +++ b/src/share/vm/oops/cpCacheOop.cpp Thu Jul 07 10:51:07 2011 -0700 @@ -295,6 +295,50 @@ } +methodOop ConstantPoolCacheEntry::get_method_if_resolved(Bytecodes::Code invoke_code, constantPoolHandle cpool) { + assert(invoke_code > (Bytecodes::Code)0, "bad query"); + if (is_secondary_entry()) { + return cpool->cache()->entry_at(main_entry_index())->get_method_if_resolved(invoke_code, cpool); + } + // Decode the action of set_method and set_interface_call + if (bytecode_1() == invoke_code) { + oop f1 = _f1; + if (f1 != NULL) { + switch (invoke_code) { + case Bytecodes::_invokeinterface: + assert(f1->is_klass(), ""); + return klassItable::method_for_itable_index(klassOop(f1), (int) f2()); + case Bytecodes::_invokestatic: + case Bytecodes::_invokespecial: + assert(f1->is_method(), ""); + return methodOop(f1); + } + } + } + if (bytecode_2() == invoke_code) { + switch (invoke_code) { + case Bytecodes::_invokevirtual: + if (is_vfinal()) { + // invokevirtual + methodOop m = methodOop((intptr_t) f2()); + assert(m->is_method(), ""); + return m; + } else { + int holder_index = cpool->uncached_klass_ref_index_at(constant_pool_index()); + if (cpool->tag_at(holder_index).is_klass()) { + klassOop klass = cpool->resolved_klass_at(holder_index); + if (!Klass::cast(klass)->oop_is_instance()) + klass = SystemDictionary::Object_klass(); + return instanceKlass::cast(klass)->method_at_vtable((int) f2()); + } + } + } + } + return NULL; +} + + + class LocalOopClosure: public OopClosure { private: void (*_f)(oop*); diff -r 4bf3cbef0b3e -r b16582d6c7db src/share/vm/oops/cpCacheOop.hpp --- a/src/share/vm/oops/cpCacheOop.hpp Wed Jul 06 08:43:01 2011 -0700 +++ b/src/share/vm/oops/cpCacheOop.hpp Thu Jul 07 10:51:07 2011 -0700 @@ -194,6 +194,8 @@ methodHandle signature_invoker // determines signature information ); + methodOop get_method_if_resolved(Bytecodes::Code invoke_code, constantPoolHandle cpool); + // For JVM_CONSTANT_InvokeDynamic cache entries: void initialize_bootstrap_method_index_in_cache(int bsm_cache_index); int bootstrap_method_index_in_cache(); diff -r 4bf3cbef0b3e -r b16582d6c7db src/share/vm/oops/methodOop.cpp --- a/src/share/vm/oops/methodOop.cpp Wed Jul 06 08:43:01 2011 -0700 +++ b/src/share/vm/oops/methodOop.cpp Thu Jul 07 10:51:07 2011 -0700 @@ -929,14 +929,40 @@ name->increment_refcount(); signature->increment_refcount(); + // record non-BCP method types in the constant pool + GrowableArray* extra_klasses = NULL; + for (int i = -1, len = java_lang_invoke_MethodType::ptype_count(method_type()); i < len; i++) { + oop ptype = (i == -1 + ? java_lang_invoke_MethodType::rtype(method_type()) + : java_lang_invoke_MethodType::ptype(method_type(), i)); + klassOop klass = check_non_bcp_klass(java_lang_Class::as_klassOop(ptype)); + if (klass != NULL) { + if (extra_klasses == NULL) + extra_klasses = new GrowableArray(len+1); + bool dup = false; + for (int j = 0; j < extra_klasses->length(); j++) { + if (extra_klasses->at(j) == klass) { dup = true; break; } + } + if (!dup) + extra_klasses->append(KlassHandle(THREAD, klass)); + } + } + + int extra_klass_count = (extra_klasses == NULL ? 0 : extra_klasses->length()); + int cp_length = _imcp_limit + extra_klass_count; constantPoolHandle cp; { - constantPoolOop cp_oop = oopFactory::new_constantPool(_imcp_limit, IsSafeConc, CHECK_(empty)); + constantPoolOop cp_oop = oopFactory::new_constantPool(cp_length, IsSafeConc, CHECK_(empty)); cp = constantPoolHandle(THREAD, cp_oop); } cp->symbol_at_put(_imcp_invoke_name, name); cp->symbol_at_put(_imcp_invoke_signature, signature); cp->string_at_put(_imcp_method_type_value, Universe::the_null_string()); + for (int j = 0; j < extra_klass_count; j++) { + KlassHandle klass = extra_klasses->at(j); + cp->klass_at_put(_imcp_limit + j, klass()); + } + cp->set_preresolution(); cp->set_pool_holder(holder()); // set up the fancy stuff: @@ -985,6 +1011,14 @@ return m; } +klassOop methodOopDesc::check_non_bcp_klass(klassOop klass) { + if (klass != NULL && Klass::cast(klass)->class_loader() != NULL) { + if (Klass::cast(klass)->oop_is_objArray()) + klass = objArrayKlass::cast(klass)->bottom_klass(); + return klass; + } + return NULL; +} methodHandle methodOopDesc:: clone_with_new_data(methodHandle m, u_char* new_code, int new_code_length, diff -r 4bf3cbef0b3e -r b16582d6c7db src/share/vm/oops/methodOop.hpp --- a/src/share/vm/oops/methodOop.hpp Wed Jul 06 08:43:01 2011 -0700 +++ b/src/share/vm/oops/methodOop.hpp Thu Jul 07 10:51:07 2011 -0700 @@ -600,6 +600,7 @@ Symbol* signature, //anything at all Handle method_type, TRAPS); + static klassOop check_non_bcp_klass(klassOop klass); // these operate only on invoke methods: oop method_handle_type() const; static jint* method_type_offsets_chain(); // series of pointer-offsets, terminated by -1 diff -r 4bf3cbef0b3e -r b16582d6c7db src/share/vm/opto/bytecodeInfo.cpp --- a/src/share/vm/opto/bytecodeInfo.cpp Wed Jul 06 08:43:01 2011 -0700 +++ b/src/share/vm/opto/bytecodeInfo.cpp Thu Jul 07 10:51:07 2011 -0700 @@ -35,14 +35,16 @@ //============================================================================= //------------------------------InlineTree------------------------------------- -InlineTree::InlineTree( Compile* c, - const InlineTree *caller_tree, ciMethod* callee, - JVMState* caller_jvms, int caller_bci, - float site_invoke_ratio, int site_depth_adjust) -: C(c), _caller_jvms(caller_jvms), - _caller_tree((InlineTree*)caller_tree), - _method(callee), _site_invoke_ratio(site_invoke_ratio), - _site_depth_adjust(site_depth_adjust), +InlineTree::InlineTree(Compile* c, + const InlineTree *caller_tree, ciMethod* callee, + JVMState* caller_jvms, int caller_bci, + float site_invoke_ratio, int max_inline_level) : + C(c), + _caller_jvms(caller_jvms), + _caller_tree((InlineTree*) caller_tree), + _method(callee), + _site_invoke_ratio(site_invoke_ratio), + _max_inline_level(max_inline_level), _count_inline_bcs(method()->code_size()) { NOT_PRODUCT(_count_inlines = 0;) @@ -66,10 +68,13 @@ } InlineTree::InlineTree(Compile* c, ciMethod* callee_method, JVMState* caller_jvms, - float site_invoke_ratio, int site_depth_adjust) -: C(c), _caller_jvms(caller_jvms), _caller_tree(NULL), - _method(callee_method), _site_invoke_ratio(site_invoke_ratio), - _site_depth_adjust(site_depth_adjust), + float site_invoke_ratio, int max_inline_level) : + C(c), + _caller_jvms(caller_jvms), + _caller_tree(NULL), + _method(callee_method), + _site_invoke_ratio(site_invoke_ratio), + _max_inline_level(max_inline_level), _count_inline_bcs(method()->code_size()) { NOT_PRODUCT(_count_inlines = 0;) @@ -94,7 +99,7 @@ if(callee_method->should_inline()) { *wci_result = *(WarmCallInfo::always_hot()); if (PrintInlining && Verbose) { - CompileTask::print_inline_indent(inline_depth()); + CompileTask::print_inline_indent(inline_level()); tty->print_cr("Inlined method is hot: "); } return NULL; @@ -109,7 +114,7 @@ size < InlineThrowMaxSize ) { wci_result->set_profit(wci_result->profit() * 100); if (PrintInlining && Verbose) { - CompileTask::print_inline_indent(inline_depth()); + CompileTask::print_inline_indent(inline_level()); tty->print_cr("Inlined method with many throws (throws=%d):", callee_method->interpreter_throwout_count()); } return NULL; @@ -149,9 +154,9 @@ max_inline_size = C->freq_inline_size(); if (size <= max_inline_size && TraceFrequencyInlining) { - CompileTask::print_inline_indent(inline_depth()); + CompileTask::print_inline_indent(inline_level()); tty->print_cr("Inlined frequent method (freq=%d count=%d):", freq, call_site_count); - CompileTask::print_inline_indent(inline_depth()); + CompileTask::print_inline_indent(inline_level()); callee_method->print(); tty->cr(); } @@ -322,7 +327,7 @@ if (!C->do_inlining() && InlineAccessors) { return "not an accessor"; } - if( inline_depth() > MaxInlineLevel ) { + if (inline_level() > _max_inline_level) { return "inlining too deep"; } @@ -392,7 +397,7 @@ //------------------------------print_inlining--------------------------------- // Really, the failure_msg can be a success message also. void InlineTree::print_inlining(ciMethod* callee_method, int caller_bci, const char* failure_msg) const { - CompileTask::print_inlining(callee_method, inline_depth(), caller_bci, failure_msg ? failure_msg : "inline"); + CompileTask::print_inlining(callee_method, inline_level(), caller_bci, failure_msg ? failure_msg : "inline"); if (callee_method == NULL) tty->print(" callee not monotonic or profiled"); if (Verbose && callee_method) { const InlineTree *top = this; @@ -500,25 +505,25 @@ if (old_ilt != NULL) { return old_ilt; } - int new_depth_adjust = 0; + int max_inline_level_adjust = 0; if (caller_jvms->method() != NULL) { if (caller_jvms->method()->is_method_handle_adapter()) - new_depth_adjust -= 1; // don't count actions in MH or indy adapter frames + max_inline_level_adjust += 1; // don't count actions in MH or indy adapter frames else if (callee_method->is_method_handle_invoke()) { - new_depth_adjust -= 1; // don't count method handle calls from java.lang.invoke implem + max_inline_level_adjust += 1; // don't count method handle calls from java.lang.invoke implem } - if (new_depth_adjust != 0 && PrintInlining) { - CompileTask::print_inline_indent(inline_depth()); + if (max_inline_level_adjust != 0 && PrintInlining && (Verbose || WizardMode)) { + CompileTask::print_inline_indent(inline_level()); tty->print_cr(" \\-> discounting inline depth"); } - if (new_depth_adjust != 0 && C->log()) { + if (max_inline_level_adjust != 0 && C->log()) { int id1 = C->log()->identify(caller_jvms->method()); int id2 = C->log()->identify(callee_method); - C->log()->elem("inline_depth_discount caller='%d' callee='%d'", id1, id2); + C->log()->elem("inline_level_discount caller='%d' callee='%d'", id1, id2); } } - InlineTree *ilt = new InlineTree(C, this, callee_method, caller_jvms, caller_bci, recur_frequency, _site_depth_adjust + new_depth_adjust); - _subtrees.append( ilt ); + InlineTree* ilt = new InlineTree(C, this, callee_method, caller_jvms, caller_bci, recur_frequency, _max_inline_level + max_inline_level_adjust); + _subtrees.append(ilt); NOT_PRODUCT( _count_inlines += 1; ) @@ -543,7 +548,7 @@ Compile* C = Compile::current(); // Root of inline tree - InlineTree *ilt = new InlineTree(C, NULL, C->method(), NULL, -1, 1.0F, 0); + InlineTree* ilt = new InlineTree(C, NULL, C->method(), NULL, -1, 1.0F, MaxInlineLevel); return ilt; } diff -r 4bf3cbef0b3e -r b16582d6c7db src/share/vm/opto/compile.cpp --- a/src/share/vm/opto/compile.cpp Wed Jul 06 08:43:01 2011 -0700 +++ b/src/share/vm/opto/compile.cpp Thu Jul 07 10:51:07 2011 -0700 @@ -1206,11 +1206,7 @@ // Make sure the Bottom and NotNull variants alias the same. // Also, make sure exact and non-exact variants alias the same. if( ptr == TypePtr::NotNull || ta->klass_is_exact() ) { - if (ta->const_oop()) { - tj = ta = TypeAryPtr::make(TypePtr::Constant,ta->const_oop(),ta->ary(),ta->klass(),false,offset); - } else { - tj = ta = TypeAryPtr::make(TypePtr::BotPTR,ta->ary(),ta->klass(),false,offset); - } + tj = ta = TypeAryPtr::make(TypePtr::BotPTR,ta->ary(),ta->klass(),false,offset); } } diff -r 4bf3cbef0b3e -r b16582d6c7db src/share/vm/opto/doCall.cpp --- a/src/share/vm/opto/doCall.cpp Wed Jul 06 08:43:01 2011 -0700 +++ b/src/share/vm/opto/doCall.cpp Thu Jul 07 10:51:07 2011 -0700 @@ -183,7 +183,7 @@ // TO DO: When UseOldInlining is removed, copy the ILT code elsewhere. float site_invoke_ratio = prof_factor; // Note: ilt is for the root of this parse, not the present call site. - ilt = new InlineTree(this, jvms->method(), jvms->caller(), site_invoke_ratio, 0); + ilt = new InlineTree(this, jvms->method(), jvms->caller(), site_invoke_ratio, MaxInlineLevel); } WarmCallInfo scratch_ci; if (!UseOldInlining) diff -r 4bf3cbef0b3e -r b16582d6c7db src/share/vm/opto/loopTransform.cpp --- a/src/share/vm/opto/loopTransform.cpp Wed Jul 06 08:43:01 2011 -0700 +++ b/src/share/vm/opto/loopTransform.cpp Thu Jul 07 10:51:07 2011 -0700 @@ -83,7 +83,7 @@ #ifdef ASSERT BoolTest::mask bt = cl->loopexit()->test_trip(); assert(bt == BoolTest::lt || bt == BoolTest::gt || - (bt == BoolTest::ne && !LoopLimitCheck), "canonical test is expected"); + bt == BoolTest::ne, "canonical test is expected"); #endif Node* init_n = cl->init_trip(); @@ -824,13 +824,23 @@ //------------------------------clone_up_backedge_goo-------------------------- // If Node n lives in the back_ctrl block and cannot float, we clone a private // version of n in preheader_ctrl block and return that, otherwise return n. -Node *PhaseIdealLoop::clone_up_backedge_goo( Node *back_ctrl, Node *preheader_ctrl, Node *n ) { +Node *PhaseIdealLoop::clone_up_backedge_goo( Node *back_ctrl, Node *preheader_ctrl, Node *n, VectorSet &visited, Node_Stack &clones ) { if( get_ctrl(n) != back_ctrl ) return n; + // Only visit once + if (visited.test_set(n->_idx)) { + Node *x = clones.find(n->_idx); + if (x != NULL) + return x; + return n; + } + Node *x = NULL; // If required, a clone of 'n' // Check for 'n' being pinned in the backedge. if( n->in(0) && n->in(0) == back_ctrl ) { + assert(clones.find(n->_idx) == NULL, "dead loop"); x = n->clone(); // Clone a copy of 'n' to preheader + clones.push(x, n->_idx); x->set_req( 0, preheader_ctrl ); // Fix x's control input to preheader } @@ -838,10 +848,13 @@ // If there are no changes we can just return 'n', otherwise // we need to clone a private copy and change it. for( uint i = 1; i < n->req(); i++ ) { - Node *g = clone_up_backedge_goo( back_ctrl, preheader_ctrl, n->in(i) ); + Node *g = clone_up_backedge_goo( back_ctrl, preheader_ctrl, n->in(i), visited, clones ); if( g != n->in(i) ) { - if( !x ) + if( !x ) { + assert(clones.find(n->_idx) == NULL, "dead loop"); x = n->clone(); + clones.push(x, n->_idx); + } x->set_req(i, g); } } @@ -960,6 +973,9 @@ post_head->set_req(LoopNode::EntryControl, zer_taken); set_idom(post_head, zer_taken, dd_main_exit); + Arena *a = Thread::current()->resource_area(); + VectorSet visited(a); + Node_Stack clones(a, main_head->back_control()->outcnt()); // Step A3: Make the fall-in values to the post-loop come from the // fall-out values of the main-loop. for (DUIterator_Fast imax, i = main_head->fast_outs(imax); i < imax; i++) { @@ -968,7 +984,8 @@ Node *post_phi = old_new[main_phi->_idx]; Node *fallmain = clone_up_backedge_goo(main_head->back_control(), post_head->init_control(), - main_phi->in(LoopNode::LoopBackControl)); + main_phi->in(LoopNode::LoopBackControl), + visited, clones); _igvn.hash_delete(post_phi); post_phi->set_req( LoopNode::EntryControl, fallmain ); } @@ -1032,6 +1049,8 @@ main_head->set_req(LoopNode::EntryControl, min_taken); set_idom(main_head, min_taken, dd_main_head); + visited.Clear(); + clones.clear(); // Step B3: Make the fall-in values to the main-loop come from the // fall-out values of the pre-loop. for (DUIterator_Fast i2max, i2 = main_head->fast_outs(i2max); i2 < i2max; i2++) { @@ -1040,7 +1059,8 @@ Node *pre_phi = old_new[main_phi->_idx]; Node *fallpre = clone_up_backedge_goo(pre_head->back_control(), main_head->init_control(), - pre_phi->in(LoopNode::LoopBackControl)); + pre_phi->in(LoopNode::LoopBackControl), + visited, clones); _igvn.hash_delete(main_phi); main_phi->set_req( LoopNode::EntryControl, fallpre ); } @@ -1070,9 +1090,11 @@ // direction: // positive stride use < // negative stride use > + // + // not-equal test is kept for post loop to handle case + // when init > limit when stride > 0 (and reverse). if (pre_end->in(CountedLoopEndNode::TestValue)->as_Bool()->_test._test == BoolTest::ne) { - assert(!LoopLimitCheck, "only canonical tests (lt or gt) are expected"); BoolTest::mask new_test = (main_end->stride_con() > 0) ? BoolTest::lt : BoolTest::gt; // Modify pre loop end condition diff -r 4bf3cbef0b3e -r b16582d6c7db src/share/vm/opto/loopnode.cpp --- a/src/share/vm/opto/loopnode.cpp Wed Jul 06 08:43:01 2011 -0700 +++ b/src/share/vm/opto/loopnode.cpp Thu Jul 07 10:51:07 2011 -0700 @@ -453,7 +453,12 @@ // Now we need to canonicalize loop condition. if (bt == BoolTest::ne) { assert(stride_con == 1 || stride_con == -1, "simple increment only"); - bt = (stride_con > 0) ? BoolTest::lt : BoolTest::gt; + // 'ne' can be replaced with 'lt' only when init < limit. + if (stride_con > 0 && init_t->_hi < limit_t->_lo) + bt = BoolTest::lt; + // 'ne' can be replaced with 'gt' only when init > limit. + if (stride_con < 0 && init_t->_lo > limit_t->_hi) + bt = BoolTest::gt; } if (incl_limit) { diff -r 4bf3cbef0b3e -r b16582d6c7db src/share/vm/opto/loopnode.hpp --- a/src/share/vm/opto/loopnode.hpp Wed Jul 06 08:43:01 2011 -0700 +++ b/src/share/vm/opto/loopnode.hpp Thu Jul 07 10:51:07 2011 -0700 @@ -843,7 +843,7 @@ void insert_pre_post_loops( IdealLoopTree *loop, Node_List &old_new, bool peel_only ); // If Node n lives in the back_ctrl block, we clone a private version of n // in preheader_ctrl block and return that, otherwise return n. - Node *clone_up_backedge_goo( Node *back_ctrl, Node *preheader_ctrl, Node *n ); + Node *clone_up_backedge_goo( Node *back_ctrl, Node *preheader_ctrl, Node *n, VectorSet &visited, Node_Stack &clones ); // Take steps to maximally unroll the loop. Peel any odd iterations, then // unroll to do double iterations. The next round of major loop transforms diff -r 4bf3cbef0b3e -r b16582d6c7db src/share/vm/opto/macro.cpp --- a/src/share/vm/opto/macro.cpp Wed Jul 06 08:43:01 2011 -0700 +++ b/src/share/vm/opto/macro.cpp Thu Jul 07 10:51:07 2011 -0700 @@ -391,13 +391,9 @@ } } // Check if an appropriate new value phi already exists. - Node* new_phi = NULL; - uint size = value_phis->size(); - for (uint i=0; i < size; i++) { - if ( mem->_idx == value_phis->index_at(i) ) { - return value_phis->node_at(i); - } - } + Node* new_phi = value_phis->find(mem->_idx); + if (new_phi != NULL) + return new_phi; if (level <= 0) { return NULL; // Give up: phi tree too deep diff -r 4bf3cbef0b3e -r b16582d6c7db src/share/vm/opto/node.cpp --- a/src/share/vm/opto/node.cpp Wed Jul 06 08:43:01 2011 -0700 +++ b/src/share/vm/opto/node.cpp Thu Jul 07 10:51:07 2011 -0700 @@ -2012,6 +2012,16 @@ _inode_top = _inodes + old_top; // restore _top } +// Node_Stack is used to map nodes. +Node* Node_Stack::find(uint idx) const { + uint sz = size(); + for (uint i=0; i < sz; i++) { + if (idx == index_at(i) ) + return node_at(i); + } + return NULL; +} + //============================================================================= uint TypeNode::size_of() const { return sizeof(*this); } #ifndef PRODUCT diff -r 4bf3cbef0b3e -r b16582d6c7db src/share/vm/opto/node.hpp --- a/src/share/vm/opto/node.hpp Wed Jul 06 08:43:01 2011 -0700 +++ b/src/share/vm/opto/node.hpp Thu Jul 07 10:51:07 2011 -0700 @@ -1463,6 +1463,9 @@ bool is_nonempty() const { return (_inode_top >= _inodes); } bool is_empty() const { return (_inode_top < _inodes); } void clear() { _inode_top = _inodes - 1; } // retain storage + + // Node_Stack is used to map nodes. + Node* find(uint idx) const; }; diff -r 4bf3cbef0b3e -r b16582d6c7db src/share/vm/opto/parse.hpp --- a/src/share/vm/opto/parse.hpp Wed Jul 06 08:43:01 2011 -0700 +++ b/src/share/vm/opto/parse.hpp Thu Jul 07 10:51:07 2011 -0700 @@ -50,7 +50,7 @@ // Always between 0.0 and 1.0. Represents the percentage of the method's // total execution time used at this call site. const float _site_invoke_ratio; - const int _site_depth_adjust; + const int _max_inline_level; // the maximum inline level for this sub-tree (may be adjusted) float compute_callee_frequency( int caller_bci ) const; GrowableArray _subtrees; @@ -63,7 +63,7 @@ JVMState* caller_jvms, int caller_bci, float site_invoke_ratio, - int site_depth_adjust); + int max_inline_level); InlineTree *build_inline_tree_for_callee(ciMethod* callee_method, JVMState* caller_jvms, int caller_bci); @@ -74,7 +74,7 @@ InlineTree *caller_tree() const { return _caller_tree; } InlineTree* callee_at(int bci, ciMethod* m) const; - int inline_depth() const { return stack_depth() + _site_depth_adjust; } + int inline_level() const { return stack_depth(); } int stack_depth() const { return _caller_jvms ? _caller_jvms->depth() : 0; } public: @@ -82,7 +82,7 @@ static InlineTree* find_subtree_from_root(InlineTree* root, JVMState* jvms, ciMethod* callee, bool create_if_not_found = false); // For temporary (stack-allocated, stateless) ilts: - InlineTree(Compile* c, ciMethod* callee_method, JVMState* caller_jvms, float site_invoke_ratio, int site_depth_adjust); + InlineTree(Compile* c, ciMethod* callee_method, JVMState* caller_jvms, float site_invoke_ratio, int max_inline_level); // InlineTree enum enum InlineStyle { diff -r 4bf3cbef0b3e -r b16582d6c7db src/share/vm/prims/methodHandleWalk.cpp --- a/src/share/vm/prims/methodHandleWalk.cpp Wed Jul 06 08:43:01 2011 -0700 +++ b/src/share/vm/prims/methodHandleWalk.cpp Thu Jul 07 10:51:07 2011 -0700 @@ -425,6 +425,8 @@ ArgToken arg = _outgoing.at(arg_slot); assert(dest == arg.basic_type(), ""); arg = make_conversion(T_OBJECT, dest_klass, Bytecodes::_checkcast, arg, CHECK_(empty)); + // replace the object by the result of the cast, to make the compiler happy: + change_argument(T_OBJECT, arg_slot, T_OBJECT, arg); debug_only(dest_klass = (klassOop)badOop); break; } @@ -467,7 +469,7 @@ ArgToken arglist[2]; arglist[0] = arg; // outgoing 'this' arglist[1] = ArgToken(); // sentinel - arg = make_invoke(NULL, unboxer, Bytecodes::_invokevirtual, false, 1, &arglist[0], CHECK_(empty)); + arg = make_invoke(methodHandle(), unboxer, Bytecodes::_invokevirtual, false, 1, &arglist[0], CHECK_(empty)); change_argument(T_OBJECT, arg_slot, dest, arg); break; } @@ -483,7 +485,7 @@ ArgToken arglist[2]; arglist[0] = arg; // outgoing value arglist[1] = ArgToken(); // sentinel - arg = make_invoke(NULL, boxer, Bytecodes::_invokestatic, false, 1, &arglist[0], CHECK_(empty)); + arg = make_invoke(methodHandle(), boxer, Bytecodes::_invokestatic, false, 1, &arglist[0], CHECK_(empty)); change_argument(src, arg_slot, T_OBJECT, arg); break; } @@ -599,8 +601,9 @@ lose("bad vmlayout slot", CHECK_(empty)); } // FIXME: consider inlining the invokee at the bytecode level - ArgToken ret = make_invoke(methodOop(invoker), vmIntrinsics::_none, + ArgToken ret = make_invoke(methodHandle(THREAD, methodOop(invoker)), vmIntrinsics::_invokeGeneric, Bytecodes::_invokevirtual, false, 1+argc, &arglist[0], CHECK_(empty)); + // The iid = _invokeGeneric really means to adjust reference types as needed. DEBUG_ONLY(invoker = NULL); if (rtype == T_OBJECT) { klassOop rklass = java_lang_Class::as_klassOop( java_lang_invoke_MethodType::rtype(recursive_mtype()) ); @@ -657,7 +660,7 @@ arglist[0] = array_arg; // value to check arglist[1] = length_arg; // length to check arglist[2] = ArgToken(); // sentinel - make_invoke(NULL, vmIntrinsics::_checkSpreadArgument, + make_invoke(methodHandle(), vmIntrinsics::_checkSpreadArgument, Bytecodes::_invokestatic, false, 2, &arglist[0], CHECK_(empty)); // Spread out the array elements. @@ -680,7 +683,7 @@ ArgToken offset_arg = make_prim_constant(T_INT, &offset_jvalue, CHECK_(empty)); ArgToken element_arg = make_fetch(element_type, element_klass(), aload_op, array_arg, offset_arg, CHECK_(empty)); change_argument(T_VOID, ap, element_type, element_arg); - ap += type2size[element_type]; + //ap += type2size[element_type]; // don't do this; insert next arg to *right* of previous } break; } @@ -731,7 +734,7 @@ } assert(ap == _outgoing_argc, ""); arglist[ap] = ArgToken(); // add a sentinel, for the sake of asserts - return make_invoke(chain().last_method_oop(), + return make_invoke(chain().last_method(), vmIntrinsics::_none, chain().last_invoke_code(), true, ap, arglist, THREAD); @@ -853,7 +856,6 @@ if (src != dst) { if (MethodHandles::same_basic_type_for_returns(src, dst, /*raw*/ true)) { if (MethodHandles::is_float_fixed_reinterpretation_cast(src, dst)) { - if (for_return) Untested("MHW return raw conversion"); // still untested vmIntrinsics::ID iid = vmIntrinsics::for_raw_conversion(src, dst); if (iid == vmIntrinsics::_none) { lose("no raw conversion method", CHECK); @@ -865,18 +867,24 @@ assert(arg.token_type() >= tt_symbolic || src == arg.basic_type(), "sanity"); arglist[0] = arg; // outgoing 'this' arglist[1] = ArgToken(); // sentinel - arg = make_invoke(NULL, iid, Bytecodes::_invokestatic, false, 1, &arglist[0], CHECK); + arg = make_invoke(methodHandle(), iid, Bytecodes::_invokestatic, false, 1, &arglist[0], CHECK); change_argument(src, slot, dst, arg); } else { // return type conversion - klassOop arg_klass = NULL; - arglist[0] = make_parameter(src, arg_klass, -1, CHECK); // return value - arglist[1] = ArgToken(); // sentinel - (void) make_invoke(NULL, iid, Bytecodes::_invokestatic, false, 1, &arglist[0], CHECK); + if (_return_conv == vmIntrinsics::_none) { + _return_conv = iid; + } else if (_return_conv == vmIntrinsics::for_raw_conversion(dst, src)) { + _return_conv = vmIntrinsics::_none; + } else if (_return_conv != zero_return_conv()) { + lose(err_msg("requested raw return conversion not allowed: %s -> %s (before %s)", type2name(src), type2name(dst), vmIntrinsics::name_at(_return_conv)), CHECK); + } } } else { // Nothing to do. } + } else if (for_return && (!is_subword_type(src) || !is_subword_type(dst))) { + // This can occur in exception-throwing MHs, which have a fictitious return value encoded as Void or Empty. + _return_conv = zero_return_conv(); } else if (src == T_OBJECT && is_java_primitive(dst)) { // ref-to-prim: discard ref, push zero lose("requested ref-to-prim conversion not expected", CHECK); @@ -896,6 +904,7 @@ _thread(THREAD), _bytecode(THREAD, 50), _constants(THREAD, 10), + _non_bcp_klasses(THREAD, 5), _cur_stack(0), _max_stack(0), _rtype(T_ILLEGAL) @@ -908,6 +917,15 @@ _name_index = cpool_symbol_put(name); _signature_index = cpool_symbol_put(signature); + // To make the resulting methods more recognizable by + // stack walkers and compiler heuristics, + // we put them in holder class MethodHandle. + // See klass_is_method_handle_adapter_holder + // and methodOopDesc::is_method_handle_adapter. + _target_klass = SystemDictionaryHandles::MethodHandle_klass(); + + check_non_bcp_klasses(java_lang_invoke_MethodHandle::type(root()), CHECK); + // Get return type klass. Handle first_mtype(THREAD, chain().method_type_oop()); // _rklass is NULL for primitives. @@ -929,6 +947,7 @@ assert(_thread == THREAD, "must be same thread"); methodHandle nullHandle; (void) walk(CHECK_(nullHandle)); + record_non_bcp_klasses(); return get_method_oop(CHECK_(nullHandle)); } @@ -1197,10 +1216,18 @@ } case T_OBJECT: { Handle value = arg.object(); - if (value.is_null()) + if (value.is_null()) { emit_bc(Bytecodes::_aconst_null); - else - emit_bc(Bytecodes::_ldc, cpool_object_put(value)); + break; + } + if (java_lang_Class::is_instance(value())) { + klassOop k = java_lang_Class::as_klassOop(value()); + if (k != NULL) { + emit_bc(Bytecodes::_ldc, cpool_klass_put(k)); + break; + } + } + emit_bc(Bytecodes::_ldc, cpool_object_put(value)); break; } default: @@ -1260,6 +1287,7 @@ index = src.index(); } emit_bc(op, cpool_klass_put(tk)); + check_non_bcp_klass(tk, CHECK_(src)); // Allocate a new local for the type so that we don't hide the // previous type from the verifier. index = new_local_index(type); @@ -1292,15 +1320,15 @@ // Emit bytecodes for the given invoke instruction. MethodHandleWalker::ArgToken -MethodHandleCompiler::make_invoke(methodOop m, vmIntrinsics::ID iid, +MethodHandleCompiler::make_invoke(methodHandle m, vmIntrinsics::ID iid, Bytecodes::Code op, bool tailcall, int argc, MethodHandleWalker::ArgToken* argv, TRAPS) { ArgToken zero; - if (m == NULL) { + if (m.is_null()) { // Get the intrinsic methodOop. - m = vmIntrinsics::method_for(iid); - if (m == NULL) { + m = methodHandle(THREAD, vmIntrinsics::method_for(iid)); + if (m.is_null()) { lose(vmIntrinsics::name_at(iid), CHECK_(zero)); } } @@ -1309,18 +1337,46 @@ Symbol* name = m->name(); Symbol* signature = m->signature(); + if (iid == vmIntrinsics::_invokeGeneric && + argc >= 1 && argv[0].token_type() == tt_constant) { + assert(m->intrinsic_id() == vmIntrinsics::_invokeExact, ""); + Handle receiver = argv[0].object(); + Handle rtype(THREAD, java_lang_invoke_MethodHandle::type(receiver())); + Handle mtype(THREAD, m->method_handle_type()); + if (rtype() != mtype()) { + assert(java_lang_invoke_MethodType::form(rtype()) == + java_lang_invoke_MethodType::form(mtype()), + "must be the same shape"); + // customize m to the exact required rtype + bool has_non_bcp_klass = check_non_bcp_klasses(rtype(), CHECK_(zero)); + TempNewSymbol sig2 = java_lang_invoke_MethodType::as_signature(rtype(), true, CHECK_(zero)); + methodHandle m2; + if (!has_non_bcp_klass) { + methodOop m2_oop = SystemDictionary::find_method_handle_invoke(m->name(), sig2, + KlassHandle(), CHECK_(zero)); + m2 = methodHandle(THREAD, m2_oop); + } + if (m2.is_null()) { + // just build it fresh + m2 = methodOopDesc::make_invoke_method(klass, m->name(), sig2, rtype, CHECK_(zero)); + if (m2.is_null()) + lose(err_msg("no customized invoker %s", sig2->as_utf8()), CHECK_(zero)); + } + m = m2; + signature = m->signature(); + } + } + + check_non_bcp_klass(klass, CHECK_(zero)); + if (m->is_method_handle_invoke()) { + check_non_bcp_klasses(m->method_handle_type(), CHECK_(zero)); + } + // 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 - // walkers and compiler heuristics can recognize them. - _target_klass = SystemDictionary::MethodHandle_klass(); - } - // Inline the method. InvocationCounter* ic = m->invocation_counter(); ic->set_carry_flag(); @@ -1353,7 +1409,7 @@ int signature_index = cpool_symbol_put(signature); int name_and_type_index = cpool_name_and_type_put(name_index, signature_index); int klass_index = cpool_klass_put(klass); - int methodref_index = cpool_methodref_put(klass_index, name_and_type_index); + int methodref_index = cpool_methodref_put(op, klass_index, name_and_type_index, m); // Generate invoke. switch (op) { @@ -1380,6 +1436,20 @@ stack_push(rbt); // The return value is already pushed onto the stack. ArgToken ret; if (tailcall) { + if (return_conv() == zero_return_conv()) { + rbt = T_VOID; // discard value + } else if (return_conv() != vmIntrinsics::_none) { + // return value conversion + int index = new_local_index(rbt); + emit_store(rbt, index); + ArgToken arglist[2]; + arglist[0] = ArgToken(tt_temporary, rbt, index); + arglist[1] = ArgToken(); // sentinel + ret = make_invoke(methodHandle(), return_conv(), Bytecodes::_invokestatic, false, 1, &arglist[0], CHECK_(zero)); + set_return_conv(vmIntrinsics::_none); + rbt = ret.basic_type(); + emit_load(rbt, ret.index()); + } if (rbt != _rtype) { if (rbt == T_VOID) { // push a zero of the right sort @@ -1425,6 +1495,7 @@ case T_OBJECT: if (_rklass.not_null() && _rklass() != SystemDictionary::Object_klass() && !Klass::cast(_rklass())->is_interface()) { emit_bc(Bytecodes::_checkcast, cpool_klass_put(_rklass())); + check_non_bcp_klass(_rklass(), CHECK_(zero)); } emit_bc(Bytecodes::_areturn); break; @@ -1525,6 +1596,52 @@ return index; } +bool MethodHandleCompiler::check_non_bcp_klasses(Handle method_type, TRAPS) { + bool res = false; + for (int i = -1, len = java_lang_invoke_MethodType::ptype_count(method_type()); i < len; i++) { + oop ptype = (i == -1 + ? java_lang_invoke_MethodType::rtype(method_type()) + : java_lang_invoke_MethodType::ptype(method_type(), i)); + res |= check_non_bcp_klass(java_lang_Class::as_klassOop(ptype), CHECK_(false)); + } + return res; +} + +bool MethodHandleCompiler::check_non_bcp_klass(klassOop klass, TRAPS) { + klass = methodOopDesc::check_non_bcp_klass(klass); + if (klass != NULL) { + Symbol* name = Klass::cast(klass)->name(); + for (int i = _non_bcp_klasses.length() - 1; i >= 0; i--) { + klassOop k2 = _non_bcp_klasses.at(i)(); + if (Klass::cast(k2)->name() == name) { + if (k2 != klass) { + lose(err_msg("unsupported klass name alias %s", name->as_utf8()), THREAD); + } + return true; + } + } + _non_bcp_klasses.append(KlassHandle(THREAD, klass)); + return true; + } + return false; +} + +void MethodHandleCompiler::record_non_bcp_klasses() { + // Append extra klasses to constant pool, to guide klass lookup. + for (int k = 0; k < _non_bcp_klasses.length(); k++) { + klassOop non_bcp_klass = _non_bcp_klasses.at(k)(); + bool add_to_cp = true; + for (int j = 1; j < _constants.length(); j++) { + ConstantValue* cv = _constants.at(j); + if (cv != NULL && cv->tag() == JVM_CONSTANT_Class + && cv->klass_oop() == non_bcp_klass) { + add_to_cp = false; + break; + } + } + if (add_to_cp) cpool_klass_put(non_bcp_klass); + } +} constantPoolHandle MethodHandleCompiler::get_constant_pool(TRAPS) const { constantPoolHandle nullHandle; @@ -1544,6 +1661,8 @@ case JVM_CONSTANT_Double: cpool->double_at_put( i, cv->get_jdouble() ); break; case JVM_CONSTANT_Class: cpool->klass_at_put( i, cv->klass_oop() ); break; case JVM_CONSTANT_Methodref: cpool->method_at_put( i, cv->first_index(), cv->second_index()); break; + case JVM_CONSTANT_InterfaceMethodref: + cpool->interface_method_at_put(i, cv->first_index(), cv->second_index()); break; case JVM_CONSTANT_NameAndType: cpool->name_and_type_at_put(i, cv->first_index(), cv->second_index()); break; case JVM_CONSTANT_Object: cpool->object_at_put( i, cv->object_oop() ); break; default: ShouldNotReachHere(); @@ -1558,6 +1677,8 @@ } } + cpool->set_preresolution(); + // Set the constant pool holder to the target method's class. cpool->set_pool_holder(_target_klass()); @@ -1606,6 +1727,33 @@ Rewriter::rewrite(_target_klass(), cpool, methods, CHECK_(empty)); // Use fake class. Rewriter::relocate_and_link(_target_klass(), methods, CHECK_(empty)); // Use fake class. + // Pre-resolve selected CP cache entries, to avoid problems with class loader scoping. + constantPoolCacheHandle cpc(THREAD, cpool->cache()); + for (int i = 0; i < cpc->length(); i++) { + ConstantPoolCacheEntry* e = cpc->entry_at(i); + assert(!e->is_secondary_entry(), "no indy instructions in here, yet"); + int constant_pool_index = e->constant_pool_index(); + ConstantValue* cv = _constants.at(constant_pool_index); + if (!cv->has_linkage()) continue; + methodHandle m = cv->linkage(); + int index; + switch (cv->tag()) { + case JVM_CONSTANT_Methodref: + index = m->vtable_index(); + if (m->is_static()) { + e->set_method(Bytecodes::_invokestatic, m, index); + } else { + e->set_method(Bytecodes::_invokespecial, m, index); + e->set_method(Bytecodes::_invokevirtual, m, index); + } + break; + case JVM_CONSTANT_InterfaceMethodref: + index = klassItable::compute_itable_index(m()); + e->set_interface_call(m, index); + break; + } + } + // Set the invocation counter's count to the invoke count of the // original call site. InvocationCounter* ic = m->invocation_counter(); @@ -1696,6 +1844,9 @@ _param_state(0), _temp_num(0) { + out->print("MethodHandle:"); + java_lang_invoke_MethodType::print_signature(java_lang_invoke_MethodHandle::type(root()), out); + out->print(" : #"); start_params(); } virtual ArgToken make_parameter(BasicType type, klassOop tk, int argnum, TRAPS) { @@ -1759,12 +1910,12 @@ _strbuf.print(")"); return maybe_make_temp("fetch", type, "x"); } - virtual ArgToken make_invoke(methodOop m, vmIntrinsics::ID iid, + virtual ArgToken make_invoke(methodHandle m, vmIntrinsics::ID iid, Bytecodes::Code op, bool tailcall, int argc, ArgToken* argv, TRAPS) { Symbol* name; Symbol* sig; - if (m != NULL) { + if (m.not_null()) { name = m->name(); sig = m->signature(); } else { diff -r 4bf3cbef0b3e -r b16582d6c7db src/share/vm/prims/methodHandleWalk.hpp --- a/src/share/vm/prims/methodHandleWalk.hpp Wed Jul 06 08:43:01 2011 -0700 +++ b/src/share/vm/prims/methodHandleWalk.hpp Thu Jul 07 10:51:07 2011 -0700 @@ -98,6 +98,7 @@ int bound_arg_slot() { assert(is_bound(), ""); return _arg_slot; } oop bound_arg_oop() { assert(is_bound(), ""); return BoundMethodHandle_argument_oop(); } + methodHandle last_method() { assert(is_last(), ""); return _last_method; } methodOop last_method_oop() { assert(is_last(), ""); return _last_method(); } Bytecodes::Code last_invoke_code() { assert(is_last(), ""); return _last_invoke; } @@ -181,6 +182,8 @@ GrowableArray _outgoing; // current outgoing parameter slots int _outgoing_argc; // # non-empty outgoing slots + vmIntrinsics::ID _return_conv; // Return conversion required by raw retypes. + // 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. @@ -219,7 +222,8 @@ : _chain(root, THREAD), _for_invokedynamic(for_invokedynamic), _outgoing(THREAD, 10), - _outgoing_argc(0) + _outgoing_argc(0), + _return_conv(vmIntrinsics::_none) { _local_index = for_invokedynamic ? 0 : 1; } @@ -228,6 +232,10 @@ bool for_invokedynamic() const { return _for_invokedynamic; } + vmIntrinsics::ID return_conv() const { return _return_conv; } + void set_return_conv(vmIntrinsics::ID c) { _return_conv = c; } + static vmIntrinsics::ID zero_return_conv() { return vmIntrinsics::_min; } + int new_local_index(BasicType bt) { //int index = _for_invokedynamic ? _local_index : _local_index - 1; int index = _local_index; @@ -243,9 +251,9 @@ virtual ArgToken make_oop_constant(oop con, TRAPS) = 0; virtual ArgToken make_conversion(BasicType type, klassOop tk, Bytecodes::Code op, const ArgToken& src, TRAPS) = 0; virtual ArgToken make_fetch(BasicType type, klassOop tk, Bytecodes::Code op, const ArgToken& base, const ArgToken& offset, TRAPS) = 0; - virtual ArgToken make_invoke(methodOop m, vmIntrinsics::ID iid, Bytecodes::Code op, bool tailcall, int argc, ArgToken* argv, TRAPS) = 0; + virtual ArgToken make_invoke(methodHandle m, vmIntrinsics::ID iid, Bytecodes::Code op, bool tailcall, int argc, ArgToken* argv, TRAPS) = 0; - // For make_invoke, the methodOop can be NULL if the intrinsic ID + // For make_invoke, the methodHandle can be NULL if the intrinsic ID // is something other than vmIntrinsics::_none. // and in case anyone cares to related the previous actions to the chain: @@ -280,6 +288,7 @@ JavaValue _value; Handle _handle; Symbol* _sym; + methodHandle _method; // pre-linkage public: // Constructor for oop types. @@ -328,11 +337,21 @@ jlong get_jlong() const { return _value.get_jlong(); } jfloat get_jfloat() const { return _value.get_jfloat(); } jdouble get_jdouble() const { return _value.get_jdouble(); } + + void set_linkage(methodHandle method) { + assert(_method.is_null(), ""); + _method = method; + } + bool has_linkage() const { return _method.not_null(); } + methodHandle linkage() const { return _method; } }; // Fake constant pool. GrowableArray _constants; + // Non-BCP classes that appear in associated MethodTypes (require special handling). + GrowableArray _non_bcp_klasses; + // Accumulated compiler state: GrowableArray _bytecode; @@ -368,15 +387,20 @@ return _constants.append(cv); } - int cpool_oop_reference_put(int tag, int first_index, int second_index) { + int cpool_oop_reference_put(int tag, int first_index, int second_index, methodHandle method) { if (first_index == 0 && second_index == 0) return 0; assert(first_index != 0 && second_index != 0, "no zero indexes"); ConstantValue* cv = new ConstantValue(tag, first_index, second_index); + if (method.not_null()) cv->set_linkage(method); return _constants.append(cv); } int cpool_primitive_put(BasicType type, jvalue* con); + bool check_non_bcp_klasses(Handle method_type, TRAPS); + bool check_non_bcp_klass(klassOop klass, TRAPS); + void record_non_bcp_klasses(); + int cpool_int_put(jint value) { jvalue con; con.i = value; return cpool_primitive_put(T_INT, &con); @@ -403,11 +427,12 @@ int cpool_klass_put(klassOop klass) { return cpool_oop_put(JVM_CONSTANT_Class, klass); } - int cpool_methodref_put(int class_index, int name_and_type_index) { - return cpool_oop_reference_put(JVM_CONSTANT_Methodref, class_index, name_and_type_index); + int cpool_methodref_put(Bytecodes::Code op, int class_index, int name_and_type_index, methodHandle method) { + int tag = (op == Bytecodes::_invokeinterface ? JVM_CONSTANT_InterfaceMethodref : JVM_CONSTANT_Methodref); + return cpool_oop_reference_put(tag, class_index, name_and_type_index, method); } int cpool_name_and_type_put(int name_index, int signature_index) { - return cpool_oop_reference_put(JVM_CONSTANT_NameAndType, name_index, signature_index); + return cpool_oop_reference_put(JVM_CONSTANT_NameAndType, name_index, signature_index, methodHandle()); } void emit_bc(Bytecodes::Code op, int index = 0, int args_size = -1); @@ -428,7 +453,7 @@ virtual ArgToken make_conversion(BasicType type, klassOop tk, Bytecodes::Code op, const ArgToken& src, TRAPS); virtual ArgToken make_fetch(BasicType type, klassOop tk, Bytecodes::Code op, const ArgToken& base, const ArgToken& offset, TRAPS); - virtual ArgToken make_invoke(methodOop m, vmIntrinsics::ID iid, Bytecodes::Code op, bool tailcall, int argc, ArgToken* argv, TRAPS); + virtual ArgToken make_invoke(methodHandle m, vmIntrinsics::ID iid, Bytecodes::Code op, bool tailcall, int argc, ArgToken* argv, TRAPS); // Get a real constant pool. constantPoolHandle get_constant_pool(TRAPS) const; diff -r 4bf3cbef0b3e -r b16582d6c7db src/share/vm/prims/methodHandles.cpp --- a/src/share/vm/prims/methodHandles.cpp Wed Jul 06 08:43:01 2011 -0700 +++ b/src/share/vm/prims/methodHandles.cpp Thu Jul 07 10:51:07 2011 -0700 @@ -24,12 +24,14 @@ #include "precompiled.hpp" #include "classfile/symbolTable.hpp" +#include "compiler/compileBroker.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/compilationPolicy.hpp" #include "runtime/javaCalls.hpp" #include "runtime/reflection.hpp" #include "runtime/signature.hpp" @@ -629,6 +631,8 @@ // convert the external string name to an internal symbol TempNewSymbol name = java_lang_String::as_symbol_or_null(name_str()); if (name == NULL) return; // no such name + if (name == vmSymbols::class_initializer_name()) + return; // illegal name Handle polymorphic_method_type; bool polymorphic_signature = false; @@ -765,7 +769,9 @@ m = NULL; // try again with a different class loader... } - if (m != NULL) { + if (m != NULL && + m->is_method_handle_invoke() && + java_lang_invoke_MethodType::equals(polymorphic_method_type(), m->method_handle_type())) { int mods = (m->access_flags().as_short() & JVM_RECOGNIZED_METHOD_MODIFIERS); java_lang_invoke_MemberName::set_vmtarget(mname(), m); java_lang_invoke_MemberName::set_vmindex(mname(), m->vtable_index()); @@ -984,6 +990,48 @@ // This is for debugging and reflection. oop MethodHandles::encode_target(Handle mh, int format, TRAPS) { assert(java_lang_invoke_MethodHandle::is_instance(mh()), "must be a MH"); + if (format == ETF_FORCE_DIRECT_HANDLE || + format == ETF_COMPILE_DIRECT_HANDLE) { + // Internal function for stress testing. + Handle mt = java_lang_invoke_MethodHandle::type(mh()); + int invocation_count = 10000; + TempNewSymbol signature = java_lang_invoke_MethodType::as_signature(mt(), true, CHECK_NULL); + bool omit_receiver_argument = true; + MethodHandleCompiler mhc(mh, vmSymbols::invoke_name(), signature, invocation_count, omit_receiver_argument, CHECK_NULL); + methodHandle m = mhc.compile(CHECK_NULL); + if (StressMethodHandleWalk && Verbose || PrintMiscellaneous) { + tty->print_cr("MethodHandleNatives.getTarget(%s)", + format == ETF_FORCE_DIRECT_HANDLE ? "FORCE_DIRECT" : "COMPILE_DIRECT"); + if (Verbose) { + m->print_codes(); + } + } + if (StressMethodHandleWalk) { + InterpreterOopMap mask; + OopMapCache::compute_one_oop_map(m, m->code_size() - 1, &mask); + } + if ((format == ETF_COMPILE_DIRECT_HANDLE || + CompilationPolicy::must_be_compiled(m)) + && !instanceKlass::cast(m->method_holder())->is_not_initialized() + && CompilationPolicy::can_be_compiled(m)) { + // Force compilation + CompileBroker::compile_method(m, InvocationEntryBci, + CompLevel_initial_compile, + methodHandle(), 0, "MethodHandleNatives.getTarget", + CHECK_NULL); + } + // Now wrap m in a DirectMethodHandle. + instanceKlassHandle dmh_klass(THREAD, SystemDictionary::DirectMethodHandle_klass()); + Handle dmh = dmh_klass->allocate_instance_handle(CHECK_NULL); + JavaValue ignore_result(T_VOID); + Symbol* init_name = vmSymbols::object_initializer_name(); + Symbol* init_sig = vmSymbols::notifyGenericMethodType_signature(); + JavaCalls::call_special(&ignore_result, dmh, + SystemDictionaryHandles::MethodHandle_klass(), init_name, init_sig, + java_lang_invoke_MethodHandle::type(mh()), CHECK_NULL); + MethodHandles::init_DirectMethodHandle(dmh, m, false, CHECK_NULL); + return dmh(); + } if (format == ETF_HANDLE_OR_METHOD_NAME) { oop target = java_lang_invoke_MethodHandle::vmtarget(mh()); if (target == NULL) { @@ -1219,6 +1267,12 @@ klassOop aklass_oop = SystemDictionary::resolve_or_null(name, loader, domain, CHECK); if (aklass_oop != NULL) aklass = KlassHandle(THREAD, aklass_oop); + if (aklass.is_null() && + pklass.not_null() && + loader.is_null() && + pklass->name() == name) + // accept name equivalence here, since that's the best we can do + aklass = pklass; } } else { // for method handle invokers we don't look at the name in the signature @@ -2652,6 +2706,17 @@ } InterpreterOopMap mask; OopMapCache::compute_one_oop_map(m, m->code_size() - 1, &mask); + // compile to object code if -Xcomp or WizardMode + if ((WizardMode || + CompilationPolicy::must_be_compiled(m)) + && !instanceKlass::cast(m->method_holder())->is_not_initialized() + && CompilationPolicy::can_be_compiled(m)) { + // Force compilation + CompileBroker::compile_method(m, InvocationEntryBci, + CompLevel_initial_compile, + methodHandle(), 0, "StressMethodHandleWalk", + CHECK); + } } } @@ -2771,7 +2836,12 @@ // Build a BMH on top of a DMH or another BMH: MethodHandles::init_BoundMethodHandle(mh, target, argnum, CHECK); } - stress_method_handle_walk(mh, CHECK); + + if (StressMethodHandleWalk) { + if (mh->klass() == SystemDictionary::BoundMethodHandle_klass()) + stress_method_handle_walk(mh, CHECK); + // else don't, since the subclass has not yet initialized its own fields + } } JVM_END diff -r 4bf3cbef0b3e -r b16582d6c7db src/share/vm/prims/methodHandles.hpp --- a/src/share/vm/prims/methodHandles.hpp Wed Jul 06 08:43:01 2011 -0700 +++ b/src/share/vm/prims/methodHandles.hpp Thu Jul 07 10:51:07 2011 -0700 @@ -588,6 +588,8 @@ ETF_DIRECT_HANDLE = 1, // ultimate method handle (will be a DMH, may be self) ETF_METHOD_NAME = 2, // ultimate method as MemberName ETF_REFLECT_METHOD = 3, // ultimate method as java.lang.reflect object (sans refClass) + ETF_FORCE_DIRECT_HANDLE = 64, + ETF_COMPILE_DIRECT_HANDLE = 65, // ad hoc constants OP_ROT_ARGS_DOWN_LIMIT_BIAS = -1 diff -r 4bf3cbef0b3e -r b16582d6c7db src/share/vm/runtime/advancedThresholdPolicy.cpp --- a/src/share/vm/runtime/advancedThresholdPolicy.cpp Wed Jul 06 08:43:01 2011 -0700 +++ b/src/share/vm/runtime/advancedThresholdPolicy.cpp Thu Jul 07 10:51:07 2011 -0700 @@ -171,7 +171,7 @@ // If a method has been stale for some time, remove it from the queue. if (is_stale(t, TieredCompileTaskTimeout, method) && !is_old(method)) { if (PrintTieredEvents) { - print_event(KILL, method, method, task->osr_bci(), (CompLevel)task->comp_level()); + print_event(REMOVE_FROM_QUEUE, method, method, task->osr_bci(), (CompLevel)task->comp_level()); } CompileTaskWrapper ctw(task); // Frees the task compile_queue->remove(task); @@ -192,7 +192,7 @@ if (max_task->comp_level() == CompLevel_full_profile && is_method_profiled(max_method)) { max_task->set_comp_level(CompLevel_limited_profile); if (PrintTieredEvents) { - print_event(UPDATE, max_method, max_method, max_task->osr_bci(), (CompLevel)max_task->comp_level()); + print_event(UPDATE_IN_QUEUE, max_method, max_method, max_task->osr_bci(), (CompLevel)max_task->comp_level()); } } @@ -259,6 +259,17 @@ return false; } +// Inlining control: if we're compiling a profiled method with C1 and the callee +// is known to have OSRed in a C2 version, don't inline it. +bool AdvancedThresholdPolicy::should_not_inline(ciEnv* env, ciMethod* callee) { + CompLevel comp_level = (CompLevel)env->comp_level(); + if (comp_level == CompLevel_full_profile || + comp_level == CompLevel_limited_profile) { + return callee->highest_osr_comp_level() == CompLevel_full_optimization; + } + return false; +} + // Create MDO if necessary. void AdvancedThresholdPolicy::create_mdo(methodHandle mh, TRAPS) { if (mh->is_native() || mh->is_abstract() || mh->is_accessor()) return; @@ -378,8 +389,9 @@ } // Determine if a method should be compiled with a normal entry point at a different level. -CompLevel AdvancedThresholdPolicy::call_event(methodOop method, CompLevel cur_level) { - CompLevel osr_level = (CompLevel) method->highest_osr_comp_level(); +CompLevel AdvancedThresholdPolicy::call_event(methodOop method, CompLevel cur_level) { + CompLevel osr_level = MIN2((CompLevel) method->highest_osr_comp_level(), + common(&AdvancedThresholdPolicy::loop_predicate, method, cur_level)); CompLevel next_level = common(&AdvancedThresholdPolicy::call_predicate, method, cur_level); // If OSR method level is greater than the regular method level, the levels should be @@ -400,15 +412,16 @@ // Determine if we should do an OSR compilation of a given method. CompLevel AdvancedThresholdPolicy::loop_event(methodOop method, CompLevel cur_level) { + CompLevel next_level = common(&AdvancedThresholdPolicy::loop_predicate, method, cur_level); if (cur_level == CompLevel_none) { // If there is a live OSR method that means that we deopted to the interpreter // for the transition. - CompLevel osr_level = (CompLevel)method->highest_osr_comp_level(); + CompLevel osr_level = MIN2((CompLevel)method->highest_osr_comp_level(), next_level); if (osr_level > CompLevel_none) { return osr_level; } } - return common(&AdvancedThresholdPolicy::loop_predicate, method, cur_level); + return next_level; } // Update the rate and submit compile @@ -418,10 +431,9 @@ CompileBroker::compile_method(mh, bci, level, mh, hot_count, "tiered", THREAD); } - // Handle the invocation event. void AdvancedThresholdPolicy::method_invocation_event(methodHandle mh, methodHandle imh, - CompLevel level, TRAPS) { + CompLevel level, nmethod* nm, TRAPS) { if (should_create_mdo(mh(), level)) { create_mdo(mh, THREAD); } @@ -436,32 +448,81 @@ // Handle the back branch event. Notice that we can compile the method // with a regular entry from here. void AdvancedThresholdPolicy::method_back_branch_event(methodHandle mh, methodHandle imh, - int bci, CompLevel level, TRAPS) { + int bci, CompLevel level, nmethod* nm, TRAPS) { if (should_create_mdo(mh(), level)) { create_mdo(mh, THREAD); } + // Check if MDO should be created for the inlined method + if (should_create_mdo(imh(), level)) { + create_mdo(imh, THREAD); + } - // If the method is already compiling, quickly bail out. - if (is_compilation_enabled() && !CompileBroker::compilation_is_in_queue(mh, bci)) { - // Use loop event as an opportinity to also check there's been - // enough calls. - CompLevel cur_level = comp_level(mh()); - CompLevel next_level = call_event(mh(), cur_level); - CompLevel next_osr_level = loop_event(mh(), level); + if (is_compilation_enabled()) { + CompLevel next_osr_level = loop_event(imh(), level); + CompLevel max_osr_level = (CompLevel)imh->highest_osr_comp_level(); if (next_osr_level == CompLevel_limited_profile) { next_osr_level = CompLevel_full_profile; // OSRs are supposed to be for very hot methods. } - next_level = MAX2(next_level, - next_osr_level < CompLevel_full_optimization ? next_osr_level : cur_level); - bool is_compiling = false; - if (next_level != cur_level) { - compile(mh, InvocationEntryBci, next_level, THREAD); - is_compiling = true; + + // At the very least compile the OSR version + if (!CompileBroker::compilation_is_in_queue(imh, bci)) { + // Check if there's a method like that already + nmethod* osr_nm = NULL; + if (max_osr_level >= next_osr_level) { + // There is an osr method already with the same + // or greater level, check if it has the bci we need + osr_nm = imh->lookup_osr_nmethod_for(bci, next_osr_level, false); + } + if (osr_nm == NULL) { + compile(imh, bci, next_osr_level, THREAD); + } } - // Do the OSR version - if (!is_compiling && next_osr_level != level) { - compile(mh, bci, next_osr_level, THREAD); + // Use loop event as an opportunity to also check if there's been + // enough calls. + CompLevel cur_level, next_level; + if (mh() != imh()) { // If there is an enclosing method + guarantee(nm != NULL, "Should have nmethod here"); + cur_level = comp_level(mh()); + next_level = call_event(mh(), cur_level); + + if (max_osr_level == CompLevel_full_optimization) { + // The inlinee OSRed to full opt, we need to modify the enclosing method to avoid deopts + bool make_not_entrant = false; + if (nm->is_osr_method()) { + // This is an osr method, just make it not entrant and recompile later if needed + make_not_entrant = true; + } else { + if (next_level != CompLevel_full_optimization) { + // next_level is not full opt, so we need to recompile the + // enclosing method without the inlinee + cur_level = CompLevel_none; + make_not_entrant = true; + } + } + if (make_not_entrant) { + if (PrintTieredEvents) { + int osr_bci = nm->is_osr_method() ? nm->osr_entry_bci() : InvocationEntryBci; + print_event(MAKE_NOT_ENTRANT, mh(), mh(), osr_bci, level); + } + nm->make_not_entrant(); + } + } + if (!CompileBroker::compilation_is_in_queue(mh, InvocationEntryBci)) { + // Fix up next_level if necessary to avoid deopts + if (next_level == CompLevel_limited_profile && max_osr_level == CompLevel_full_profile) { + next_level = CompLevel_full_profile; + } + if (cur_level != next_level) { + compile(mh, InvocationEntryBci, next_level, THREAD); + } + } + } else { + cur_level = comp_level(imh()); + next_level = call_event(imh(), cur_level); + if (!CompileBroker::compilation_is_in_queue(imh, bci) && next_level != cur_level) { + compile(imh, InvocationEntryBci, next_level, THREAD); + } } } } diff -r 4bf3cbef0b3e -r b16582d6c7db src/share/vm/runtime/advancedThresholdPolicy.hpp --- a/src/share/vm/runtime/advancedThresholdPolicy.hpp Wed Jul 06 08:43:01 2011 -0700 +++ b/src/share/vm/runtime/advancedThresholdPolicy.hpp Thu Jul 07 10:51:07 2011 -0700 @@ -211,14 +211,16 @@ virtual void submit_compile(methodHandle mh, int bci, CompLevel level, TRAPS); // event() from SimpleThresholdPolicy would call these. virtual void method_invocation_event(methodHandle method, methodHandle inlinee, - CompLevel level, TRAPS); + CompLevel level, nmethod* nm, TRAPS); virtual void method_back_branch_event(methodHandle method, methodHandle inlinee, - int bci, CompLevel level, TRAPS); + int bci, CompLevel level, nmethod* nm, TRAPS); public: AdvancedThresholdPolicy() : _start_time(0) { } // Select task is called by CompileBroker. We should return a task or NULL. virtual CompileTask* select_task(CompileQueue* compile_queue); virtual void initialize(); + virtual bool should_not_inline(ciEnv* env, ciMethod* callee); + }; #endif // TIERED diff -r 4bf3cbef0b3e -r b16582d6c7db src/share/vm/runtime/compilationPolicy.cpp --- a/src/share/vm/runtime/compilationPolicy.cpp Wed Jul 06 08:43:01 2011 -0700 +++ b/src/share/vm/runtime/compilationPolicy.cpp Thu Jul 07 10:51:07 2011 -0700 @@ -306,7 +306,7 @@ return (current >= initial + target); } -nmethod* NonTieredCompPolicy::event(methodHandle method, methodHandle inlinee, int branch_bci, int bci, CompLevel comp_level, TRAPS) { +nmethod* NonTieredCompPolicy::event(methodHandle method, methodHandle inlinee, int branch_bci, int bci, CompLevel comp_level, nmethod* nm, TRAPS) { assert(comp_level == CompLevel_none, "This should be only called from the interpreter"); NOT_PRODUCT(trace_frequency_counter_overflow(method, branch_bci, bci)); if (JvmtiExport::can_post_interpreter_events()) { diff -r 4bf3cbef0b3e -r b16582d6c7db src/share/vm/runtime/compilationPolicy.hpp --- a/src/share/vm/runtime/compilationPolicy.hpp Wed Jul 06 08:43:01 2011 -0700 +++ b/src/share/vm/runtime/compilationPolicy.hpp Thu Jul 07 10:51:07 2011 -0700 @@ -62,7 +62,7 @@ virtual int compiler_count(CompLevel comp_level) = 0; // main notification entry, return a pointer to an nmethod if the OSR is required, // returns NULL otherwise. - virtual nmethod* event(methodHandle method, methodHandle inlinee, int branch_bci, int bci, CompLevel comp_level, TRAPS) = 0; + virtual nmethod* event(methodHandle method, methodHandle inlinee, int branch_bci, int bci, CompLevel comp_level, nmethod* nm, TRAPS) = 0; // safepoint() is called at the end of the safepoint virtual void do_safepoint_work() = 0; // reprofile request @@ -80,6 +80,7 @@ virtual bool is_mature(methodOop method) = 0; // Do policy initialization virtual void initialize() = 0; + virtual bool should_not_inline(ciEnv* env, ciMethod* method) { return false; } }; // A base class for baseline policies. @@ -101,7 +102,7 @@ virtual bool is_mature(methodOop method); virtual void initialize(); virtual CompileTask* select_task(CompileQueue* compile_queue); - virtual nmethod* event(methodHandle method, methodHandle inlinee, int branch_bci, int bci, CompLevel comp_level, TRAPS); + virtual nmethod* event(methodHandle method, methodHandle inlinee, int branch_bci, int bci, CompLevel comp_level, nmethod* nm, TRAPS); virtual void method_invocation_event(methodHandle m, TRAPS) = 0; virtual void method_back_branch_event(methodHandle m, int bci, TRAPS) = 0; }; diff -r 4bf3cbef0b3e -r b16582d6c7db src/share/vm/runtime/sharedRuntime.cpp --- a/src/share/vm/runtime/sharedRuntime.cpp Wed Jul 06 08:43:01 2011 -0700 +++ b/src/share/vm/runtime/sharedRuntime.cpp Thu Jul 07 10:51:07 2011 -0700 @@ -763,6 +763,13 @@ throw_and_post_jvmti_exception(thread, exception); JRT_END +JRT_ENTRY(void, SharedRuntime::throw_WrongMethodTypeException(JavaThread* thread, oopDesc* required, oopDesc* actual)) + assert(thread == JavaThread::current() && required->is_oop() && actual->is_oop(), "bad args"); + ResourceMark rm; + char* message = SharedRuntime::generate_wrong_method_type_message(thread, required, actual); + throw_and_post_jvmti_exception(thread, vmSymbols::java_lang_invoke_WrongMethodTypeException(), message); +JRT_END + address SharedRuntime::continuation_for_implicit_exception(JavaThread* thread, address pc, SharedRuntime::ImplicitExceptionKind exception_kind) diff -r 4bf3cbef0b3e -r b16582d6c7db src/share/vm/runtime/sharedRuntime.hpp --- a/src/share/vm/runtime/sharedRuntime.hpp Wed Jul 06 08:43:01 2011 -0700 +++ b/src/share/vm/runtime/sharedRuntime.hpp Thu Jul 07 10:51:07 2011 -0700 @@ -185,6 +185,7 @@ static void throw_NullPointerException(JavaThread* thread); static void throw_NullPointerException_at_call(JavaThread* thread); static void throw_StackOverflowError(JavaThread* thread); + static void throw_WrongMethodTypeException(JavaThread* thread, oopDesc* required, oopDesc* actual); static address continuation_for_implicit_exception(JavaThread* thread, address faulting_pc, ImplicitExceptionKind exception_kind); diff -r 4bf3cbef0b3e -r b16582d6c7db src/share/vm/runtime/simpleThresholdPolicy.cpp --- a/src/share/vm/runtime/simpleThresholdPolicy.cpp Wed Jul 06 08:43:01 2011 -0700 +++ b/src/share/vm/runtime/simpleThresholdPolicy.cpp Thu Jul 07 10:51:07 2011 -0700 @@ -50,15 +50,18 @@ case COMPILE: tty->print("compile"); break; - case KILL: - tty->print("kill"); + case REMOVE_FROM_QUEUE: + tty->print("remove-from-queue"); break; - case UPDATE: - tty->print("update"); + case UPDATE_IN_QUEUE: + tty->print("update-in-queue"); break; case REPROFILE: tty->print("reprofile"); break; + case MAKE_NOT_ENTRANT: + tty->print("make-not-entrant"); + break; default: tty->print("unknown"); } @@ -68,7 +71,6 @@ ResourceMark rm; char *method_name = mh->name_and_sig_as_C_string(); tty->print("[%s", method_name); - // We can have an inlinee, although currently we don't generate any notifications for the inlined methods. if (inlinee_event) { char *inlinee_name = imh->name_and_sig_as_C_string(); tty->print(" [%s]] ", inlinee_name); @@ -170,7 +172,7 @@ } nmethod* SimpleThresholdPolicy::event(methodHandle method, methodHandle inlinee, - int branch_bci, int bci, CompLevel comp_level, TRAPS) { + int branch_bci, int bci, CompLevel comp_level, nmethod* nm, TRAPS) { if (comp_level == CompLevel_none && JvmtiExport::can_post_interpreter_events()) { assert(THREAD->is_Java_thread(), "Should be java thread"); @@ -190,12 +192,13 @@ } if (bci == InvocationEntryBci) { - method_invocation_event(method, inlinee, comp_level, THREAD); + method_invocation_event(method, inlinee, comp_level, nm, THREAD); } else { - method_back_branch_event(method, inlinee, bci, comp_level, THREAD); - int highest_level = method->highest_osr_comp_level(); + method_back_branch_event(method, inlinee, bci, comp_level, nm, THREAD); + // method == inlinee if the event originated in the main method + int highest_level = inlinee->highest_osr_comp_level(); if (highest_level > comp_level) { - osr_nm = method->lookup_osr_nmethod_for(bci, highest_level, false); + osr_nm = inlinee->lookup_osr_nmethod_for(bci, highest_level, false); } } return osr_nm; @@ -323,7 +326,8 @@ // Determine if a method should be compiled with a normal entry point at a different level. CompLevel SimpleThresholdPolicy::call_event(methodOop method, CompLevel cur_level) { - CompLevel osr_level = (CompLevel) method->highest_osr_comp_level(); + CompLevel osr_level = MIN2((CompLevel) method->highest_osr_comp_level(), + common(&SimpleThresholdPolicy::loop_predicate, method, cur_level)); CompLevel next_level = common(&SimpleThresholdPolicy::call_predicate, method, cur_level); // If OSR method level is greater than the regular method level, the levels should be @@ -344,21 +348,22 @@ // Determine if we should do an OSR compilation of a given method. CompLevel SimpleThresholdPolicy::loop_event(methodOop method, CompLevel cur_level) { + CompLevel next_level = common(&SimpleThresholdPolicy::loop_predicate, method, cur_level); if (cur_level == CompLevel_none) { // If there is a live OSR method that means that we deopted to the interpreter // for the transition. - CompLevel osr_level = (CompLevel)method->highest_osr_comp_level(); + CompLevel osr_level = MIN2((CompLevel)method->highest_osr_comp_level(), next_level); if (osr_level > CompLevel_none) { return osr_level; } } - return common(&SimpleThresholdPolicy::loop_predicate, method, cur_level); + return next_level; } // Handle the invocation event. void SimpleThresholdPolicy::method_invocation_event(methodHandle mh, methodHandle imh, - CompLevel level, TRAPS) { + CompLevel level, nmethod* nm, TRAPS) { if (is_compilation_enabled() && !CompileBroker::compilation_is_in_queue(mh, InvocationEntryBci)) { CompLevel next_level = call_event(mh(), level); if (next_level != level) { @@ -370,7 +375,7 @@ // Handle the back branch event. Notice that we can compile the method // with a regular entry from here. void SimpleThresholdPolicy::method_back_branch_event(methodHandle mh, methodHandle imh, - int bci, CompLevel level, TRAPS) { + int bci, CompLevel level, nmethod* nm, TRAPS) { // If the method is already compiling, quickly bail out. if (is_compilation_enabled() && !CompileBroker::compilation_is_in_queue(mh, bci)) { // Use loop event as an opportinity to also check there's been diff -r 4bf3cbef0b3e -r b16582d6c7db src/share/vm/runtime/simpleThresholdPolicy.hpp --- a/src/share/vm/runtime/simpleThresholdPolicy.hpp Wed Jul 06 08:43:01 2011 -0700 +++ b/src/share/vm/runtime/simpleThresholdPolicy.hpp Thu Jul 07 10:51:07 2011 -0700 @@ -62,7 +62,7 @@ void set_c1_count(int x) { _c1_count = x; } void set_c2_count(int x) { _c2_count = x; } - enum EventType { CALL, LOOP, COMPILE, KILL, UPDATE, REPROFILE }; + enum EventType { CALL, LOOP, COMPILE, REMOVE_FROM_QUEUE, UPDATE_IN_QUEUE, REPROFILE, MAKE_NOT_ENTRANT }; void print_event(EventType type, methodHandle mh, methodHandle imh, int bci, CompLevel level); // Print policy-specific information if necessary virtual void print_specific(EventType type, methodHandle mh, methodHandle imh, int bci, CompLevel level) { } @@ -88,9 +88,9 @@ return CompLevel_none; } virtual void method_invocation_event(methodHandle method, methodHandle inlinee, - CompLevel level, TRAPS); + CompLevel level, nmethod* nm, TRAPS); virtual void method_back_branch_event(methodHandle method, methodHandle inlinee, - int bci, CompLevel level, TRAPS); + int bci, CompLevel level, nmethod* nm, TRAPS); public: SimpleThresholdPolicy() : _c1_count(0), _c2_count(0) { } virtual int compiler_count(CompLevel comp_level) { @@ -101,17 +101,20 @@ virtual void do_safepoint_work() { } virtual void delay_compilation(methodOop method) { } virtual void disable_compilation(methodOop method) { } - // TODO: we should honour reprofiling requests in the future. Currently reprofiling - // would happen but not to the extent we would ideally like. virtual void reprofile(ScopeDesc* trap_scope, bool is_osr); virtual nmethod* event(methodHandle method, methodHandle inlinee, - int branch_bci, int bci, CompLevel comp_level, TRAPS); + int branch_bci, int bci, CompLevel comp_level, nmethod* nm, TRAPS); // Select task is called by CompileBroker. We should return a task or NULL. virtual CompileTask* select_task(CompileQueue* compile_queue); // Tell the runtime if we think a given method is adequately profiled. virtual bool is_mature(methodOop method); // Initialize: set compiler thread count virtual void initialize(); + virtual bool should_not_inline(ciEnv* env, ciMethod* callee) { + return (env->comp_level() == CompLevel_limited_profile || + env->comp_level() == CompLevel_full_profile) && + callee->has_loops(); + } }; #endif // SHARE_VM_RUNTIME_SIMPLETHRESHOLDPOLICY_HPP diff -r 4bf3cbef0b3e -r b16582d6c7db src/share/vm/runtime/stubRoutines.cpp --- a/src/share/vm/runtime/stubRoutines.cpp Wed Jul 06 08:43:01 2011 -0700 +++ b/src/share/vm/runtime/stubRoutines.cpp Thu Jul 07 10:51:07 2011 -0700 @@ -55,6 +55,7 @@ address StubRoutines::_throw_NullPointerException_entry = NULL; address StubRoutines::_throw_NullPointerException_at_call_entry = NULL; address StubRoutines::_throw_StackOverflowError_entry = NULL; +address StubRoutines::_throw_WrongMethodTypeException_entry = NULL; address StubRoutines::_handler_for_unsafe_access_entry = NULL; jint StubRoutines::_verify_oop_count = 0; address StubRoutines::_verify_oop_subroutine_entry = NULL; diff -r 4bf3cbef0b3e -r b16582d6c7db src/share/vm/runtime/stubRoutines.hpp --- a/src/share/vm/runtime/stubRoutines.hpp Wed Jul 06 08:43:01 2011 -0700 +++ b/src/share/vm/runtime/stubRoutines.hpp Thu Jul 07 10:51:07 2011 -0700 @@ -132,6 +132,7 @@ static address _throw_NullPointerException_entry; static address _throw_NullPointerException_at_call_entry; static address _throw_StackOverflowError_entry; + static address _throw_WrongMethodTypeException_entry; static address _handler_for_unsafe_access_entry; static address _atomic_xchg_entry; @@ -254,6 +255,7 @@ static address throw_NullPointerException_entry() { return _throw_NullPointerException_entry; } static address throw_NullPointerException_at_call_entry(){ return _throw_NullPointerException_at_call_entry; } static address throw_StackOverflowError_entry() { return _throw_StackOverflowError_entry; } + static address throw_WrongMethodTypeException_entry() { return _throw_WrongMethodTypeException_entry; } // Exceptions during unsafe access - should throw Java exception rather // than crash. diff -r 4bf3cbef0b3e -r b16582d6c7db test/compiler/6478991/NullCheckTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/compiler/6478991/NullCheckTest.java Thu Jul 07 10:51:07 2011 -0700 @@ -0,0 +1,72 @@ +/* + * 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 6478991 + * @summary C1 NullCheckEliminator yields incorrect exceptions + * + * @run main/othervm -XX:CompileOnly=NullCheckTest.test,NullCheckTest.inlined -Xcomp NullCheckTest + */ + +public class NullCheckTest { + static class A { + int f; + + public final void inlined(A a) { + // This cast is intended to fail. + B b = ((B) a); + } + } + + static class B extends A { + } + + + private static void test(A a1, A a2) { + // Inlined call must do a null check on a1. + // However, the exlipcit NullCheck instruction is eliminated and + // the null check is folded into the field load below, so the + // exception in the inlined method is thrown before the null check + // and the NullPointerException is not thrown. + a1.inlined(a2); + + int x = a1.f; + } + + public static void main(String[] args) { + // load classes + new B(); + try { + test(null, new A()); + + throw new InternalError("FAILURE: no exception"); + } catch (NullPointerException ex) { + System.out.println("CORRECT: NullPointerException"); + } catch (ClassCastException ex) { + System.out.println("FAILURE: ClassCastException"); + throw ex; + } + } +} diff -r 4bf3cbef0b3e -r b16582d6c7db test/compiler/7044738/Test7044738.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/compiler/7044738/Test7044738.java Thu Jul 07 10:51:07 2011 -0700 @@ -0,0 +1,104 @@ +/* + * 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 7044738 + * @summary Loop unroll optimization causes incorrect result + * + * @run main/othervm -Xbatch Test7044738 + */ + +public class Test7044738 { + + private static final int INITSIZE = 10000; + public int d[] = { 1, 2, 3, 4 }; + public int i, size; + + private static int iter = 5; + + boolean done() { return (--iter > 0); } + + public static void main(String args[]) { + Test7044738 t = new Test7044738(); + t.test(); + } + + int test() { + + while (done()) { + size = INITSIZE; + + for (i = 0; i < size; i++) { + d[0] = d[1]; // 2 + d[1] = d[2]; // 3 + d[2] = d[3]; // 4 + d[3] = d[0]; // 2 + + d[0] = d[1]; // 3 + d[1] = d[2]; // 4 + d[2] = d[3]; // 2 + d[3] = d[0]; // 3 + + d[0] = d[1]; // 4 + d[1] = d[2]; // 2 + d[2] = d[3]; // 3 + d[3] = d[0]; // 4 + + d[0] = d[1]; // 2 + d[1] = d[2]; // 3 + d[2] = d[3]; // 4 + d[3] = d[0]; // 2 + + d[0] = d[1]; // 3 + d[1] = d[2]; // 4 + d[2] = d[3]; // 2 + d[3] = d[0]; // 3 + + d[0] = d[1]; // 4 + d[1] = d[2]; // 2 + d[2] = d[3]; // 3 + d[3] = d[0]; // 4 + + d[0] = d[1]; // 2 + d[1] = d[2]; // 3 + d[2] = d[3]; // 4 + d[3] = d[0]; // 2 + + d[0] = d[1]; // 3 + d[1] = d[2]; // 4 + d[2] = d[3]; // 2 + d[3] = d[0]; // 3 + } + + // try to defeat dead code elimination + if (d[0] == d[1]) { + System.out.println("test failed: iter=" + iter + " i=" + i + " d[] = { " + d[0] + ", " + d[1] + ", " + d[2] + ", " + d[3] + " } "); + System.exit(97); + } + } + return d[3]; + } + +} diff -r 4bf3cbef0b3e -r b16582d6c7db test/compiler/7046096/Test7046096.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/compiler/7046096/Test7046096.java Thu Jul 07 10:51:07 2011 -0700 @@ -0,0 +1,65 @@ +/* + * 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 7046096 + * @summary SEGV IN C2 WITH 6U25 + * + * @run main/othervm -Xbatch -XX:+IgnoreUnrecognizedVMOptions -XX:+OptimizeStringConcat Test7046096 + */ + + +public class Test7046096 { + + static int first = 1; + + String add(String str) { + if (first != 0) { + return str + "789"; + } else { + return "null"; + } + } + + String test(String str) { + for (int i=0; i < first; i++) { + if (i > 1) + return "bad"; + } + return add(str+"456"); + } + + public static void main(String [] args) { + Test7046096 t = new Test7046096(); + for (int i = 0; i < 11000; i++) { + String str = t.test("123"); + if (!str.equals("123456789")) { + System.out.println("FAILED: " + str + " != \"123456789\""); + System.exit(97); + } + } + } +} + diff -r 4bf3cbef0b3e -r b16582d6c7db test/compiler/7052494/Test7052494.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/compiler/7052494/Test7052494.java Thu Jul 07 10:51:07 2011 -0700 @@ -0,0 +1,162 @@ +/* + * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +/** + * @test + * @bug 7052494 + * @summary Eclipse test fails on JDK 7 b142 + * + * @run main/othervm -Xbatch Test7052494 + */ + + +public class Test7052494 { + + static int test1(int i, int limit) { + int result = 0; + while (i++ != 0) { + if (result >= limit) + break; + result = i*2; + } + return result; + } + + static int test2(int i, int limit) { + int result = 0; + while (i-- != 0) { + if (result <= limit) + break; + result = i*2; + } + return result; + } + + static void test3(int i, int limit, int arr[]) { + while (i++ != 0) { + if (arr[i-1] >= limit) + break; + arr[i] = i*2; + } + } + + static void test4(int i, int limit, int arr[]) { + while (i-- != 0) { + if (arr[arr.length + i + 1] <= limit) + break; + arr[arr.length + i] = i*2; + } + } + + // Empty loop rolls through MAXINT if i > 0 + static int test5(int i) { + int result = 0; + while (i++ != 0) { + result = i*2; + } + return result; + } + + // Empty loop rolls through MININT if i < 0 + static int test6(int i) { + int result = 0; + while (i-- != 0) { + result = i*2; + } + return result; + } + + public static void main(String [] args) { + boolean failed = false; + int[] arr = new int[8]; + int[] ar3 = { 0, 0, 4, 6, 8, 10, 0, 0 }; + int[] ar4 = { 0, 0, 0, -10, -8, -6, -4, 0 }; + for (int i = 0; i < 11000; i++) { + int k = test1(1, 10); + if (k != 10) { + System.out.println("FAILED: " + k + " != 10"); + failed = true; + break; + } + } + for (int i = 0; i < 11000; i++) { + int k = test2(-1, -10); + if (k != -10) { + System.out.println("FAILED: " + k + " != -10"); + failed = true; + break; + } + } + for (int i = 0; i < 11000; i++) { + java.util.Arrays.fill(arr, 0); + test3(1, 10, arr); + if (!java.util.Arrays.equals(arr,ar3)) { + System.out.println("FAILED: arr = { " + arr[0] + ", " + + arr[1] + ", " + + arr[2] + ", " + + arr[3] + ", " + + arr[4] + ", " + + arr[5] + ", " + + arr[6] + ", " + + arr[7] + " }"); + failed = true; + break; + } + } + for (int i = 0; i < 11000; i++) { + java.util.Arrays.fill(arr, 0); + test4(-1, -10, arr); + if (!java.util.Arrays.equals(arr,ar4)) { + System.out.println("FAILED: arr = { " + arr[0] + ", " + + arr[1] + ", " + + arr[2] + ", " + + arr[3] + ", " + + arr[4] + ", " + + arr[5] + ", " + + arr[6] + ", " + + arr[7] + " }"); + failed = true; + break; + } + } + for (int i = 0; i < 11000; i++) { + int k = test5(1); + if (k != 0) { + System.out.println("FAILED: " + k + " != 0"); + failed = true; + break; + } + } + for (int i = 0; i < 11000; i++) { + int k = test6(-1); + if (k != 0) { + System.out.println("FAILED: " + k + " != 0"); + failed = true; + break; + } + } + if (failed) + System.exit(97); + } +}