# HG changeset patch # User amurillo # Date 1427136281 25200 # Node ID 889895365eb9670726b1bfaebeedc048223eb54f # Parent 8c1cc431f38817091c002a8a8ac60e3ca69874fd# Parent 6952cbf4b762bebbaef5c97e259e2890972cd935 Merge diff -r 8c1cc431f388 -r 889895365eb9 hotspot/agent/src/share/classes/sun/jvm/hotspot/runtime/ppc64/PPC64Frame.java --- a/hotspot/agent/src/share/classes/sun/jvm/hotspot/runtime/ppc64/PPC64Frame.java Fri Mar 20 17:39:29 2015 +0000 +++ b/hotspot/agent/src/share/classes/sun/jvm/hotspot/runtime/ppc64/PPC64Frame.java Mon Mar 23 11:44:41 2015 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2015, 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 @@ -63,10 +63,6 @@ // Entry frames private static int ENTRY_FRAME_CALL_WRAPPER_OFFSET; - // Native frames - private static int NATIVE_FRAME_INITIAL_PARAM_OFFSET; - - static { VM.registerVMInitializedObserver(new Observer() { public void update(Observable o, Object data) { @@ -76,10 +72,8 @@ } private static synchronized void initialize(TypeDataBase db) { - int abi_minframe_size = db.lookupIntConstant("frame::abi_minframe_size").intValue(); int entry_frame_locals_size = db.lookupIntConstant("frame::entry_frame_locals_size").intValue(); int wordLength = (int) VM.getVM().getAddressSize(); - NATIVE_FRAME_INITIAL_PARAM_OFFSET = -abi_minframe_size/wordLength; ENTRY_FRAME_CALL_WRAPPER_OFFSET = -entry_frame_locals_size/wordLength; } @@ -389,13 +383,6 @@ // Return address: public Address getSenderPC() { return getSenderSP().getAddressAt(2 * VM.getVM().getAddressSize()); } - // return address of param, zero origin index. - // MPJ note: Appears to be unused. - public Address getNativeParamAddr(int idx) { - return null; - // return addressOfStackSlot(NATIVE_FRAME_INITIAL_PARAM_OFFSET + idx); - } - public Address getSenderSP() { return getFP(); } public Address addressOfInterpreterFrameLocals() { return addressOfStackSlot(INTERPRETER_FRAME_LOCALS_OFFSET); diff -r 8c1cc431f388 -r 889895365eb9 hotspot/agent/src/share/classes/sun/jvm/hotspot/runtime/x86/X86Frame.java --- a/hotspot/agent/src/share/classes/sun/jvm/hotspot/runtime/x86/X86Frame.java Fri Mar 20 17:39:29 2015 +0000 +++ b/hotspot/agent/src/share/classes/sun/jvm/hotspot/runtime/x86/X86Frame.java Mon Mar 23 11:44:41 2015 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2015, 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 @@ -63,9 +63,6 @@ // Entry frames private static int ENTRY_FRAME_CALL_WRAPPER_OFFSET; - // Native frames - private static final int NATIVE_FRAME_INITIAL_PARAM_OFFSET = 2; - private static VMReg rbp; static { @@ -423,20 +420,12 @@ return addressOfStackSlot(LINK_OFFSET).getAddressAt(0); } - // FIXME: not implementable yet - //inline void frame::set_link(intptr_t* addr) { *(intptr_t **)addr_at(link_offset) = addr; } - public Address getUnextendedSP() { return raw_unextendedSP; } // Return address: public Address getSenderPCAddr() { return addressOfStackSlot(RETURN_ADDR_OFFSET); } public Address getSenderPC() { return getSenderPCAddr().getAddressAt(0); } - // return address of param, zero origin index. - public Address getNativeParamAddr(int idx) { - return addressOfStackSlot(NATIVE_FRAME_INITIAL_PARAM_OFFSET + idx); - } - public Address getSenderSP() { return addressOfStackSlot(SENDER_SP_OFFSET); } public Address addressOfInterpreterFrameLocals() { diff -r 8c1cc431f388 -r 889895365eb9 hotspot/make/linux/Makefile --- a/hotspot/make/linux/Makefile Fri Mar 20 17:39:29 2015 +0000 +++ b/hotspot/make/linux/Makefile Mon Mar 23 11:44:41 2015 -0700 @@ -1,5 +1,5 @@ # -# Copyright (c) 1999, 2014, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 1999, 2015, 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 @@ -233,7 +233,7 @@ # Solaris 2.5.1, 2.6). # Disable this check by setting DISABLE_HOTSPOT_OS_VERSION_CHECK=ok. -SUPPORTED_OS_VERSION = 2.4% 2.5% 2.6% 3% +SUPPORTED_OS_VERSION = 2.4% 2.5% 2.6% 3% 4% OS_VERSION := $(shell uname -r) EMPTY_IF_NOT_SUPPORTED = $(filter $(SUPPORTED_OS_VERSION),$(OS_VERSION)) diff -r 8c1cc431f388 -r 889895365eb9 hotspot/make/linux/makefiles/gcc.make --- a/hotspot/make/linux/makefiles/gcc.make Fri Mar 20 17:39:29 2015 +0000 +++ b/hotspot/make/linux/makefiles/gcc.make Mon Mar 23 11:44:41 2015 -0700 @@ -214,6 +214,11 @@ # conversions which might affect the values. Only enable it in earlier versions. ifeq "$(shell expr \( $(CC_VER_MAJOR) \> 4 \) \| \( \( $(CC_VER_MAJOR) = 4 \) \& \( $(CC_VER_MINOR) \>= 3 \) \))" "0" WARNING_FLAGS += -Wconversion + endif + ifeq "$(shell expr \( $(CC_VER_MAJOR) \> 4 \) \| \( \( $(CC_VER_MAJOR) = 4 \) \& \( $(CC_VER_MINOR) \>= 8 \) \))" "1" + # This flag is only known since GCC 4.3. Gcc 4.8 contains a fix so that with templates no + # warnings are issued: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=11856 + WARNING_FLAGS += -Wtype-limits endif endif diff -r 8c1cc431f388 -r 889895365eb9 hotspot/make/windows/makefiles/projectcreator.make --- a/hotspot/make/windows/makefiles/projectcreator.make Fri Mar 20 17:39:29 2015 +0000 +++ b/hotspot/make/windows/makefiles/projectcreator.make Mon Mar 23 11:44:41 2015 -0700 @@ -69,6 +69,7 @@ -ignorePath ppc \ -ignorePath zero \ -ignorePath aix \ + -ignorePath aarch64 \ -hidePath .hg diff -r 8c1cc431f388 -r 889895365eb9 hotspot/src/cpu/aarch64/vm/aarch64.ad --- a/hotspot/src/cpu/aarch64/vm/aarch64.ad Fri Mar 20 17:39:29 2015 +0000 +++ b/hotspot/src/cpu/aarch64/vm/aarch64.ad Mon Mar 23 11:44:41 2015 -0700 @@ -3735,12 +3735,12 @@ interface(CONST_INTER); %} -// constant 'double +0.0'. +// Double Immediate: +0.0d operand immD0() %{ - predicate((n->getd() == 0) && - (fpclassify(n->getd()) == FP_ZERO) && (signbit(n->getd()) == 0)); + predicate(jlong_cast(n->getd()) == 0); match(ConD); + op_cost(0); format %{ %} interface(CONST_INTER); @@ -3765,12 +3765,12 @@ interface(CONST_INTER); %} -// constant 'float +0.0'. +// Float Immediate: +0.0f. operand immF0() %{ - predicate((n->getf() == 0) && - (fpclassify(n->getf()) == FP_ZERO) && (signbit(n->getf()) == 0)); + predicate(jint_cast(n->getf()) == 0); match(ConF); + op_cost(0); format %{ %} interface(CONST_INTER); diff -r 8c1cc431f388 -r 889895365eb9 hotspot/src/cpu/aarch64/vm/frame_aarch64.hpp --- a/hotspot/src/cpu/aarch64/vm/frame_aarch64.hpp Fri Mar 20 17:39:29 2015 +0000 +++ b/hotspot/src/cpu/aarch64/vm/frame_aarch64.hpp Mon Mar 23 11:44:41 2015 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2014, Red Hat Inc. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -136,12 +136,7 @@ entry_frame_call_wrapper_offset = -8, // we don't need a save area - arg_reg_save_area_bytes = 0, - - // TODO - check that this is still correct - // Native frames - - native_frame_initial_param_offset = 2 + arg_reg_save_area_bytes = 0 }; @@ -195,9 +190,6 @@ inline address* sender_pc_addr() const; - // return address of param, zero origin index. - inline address* native_param_addr(int idx) const; - // expression stack tos if we are nested in a java call intptr_t* interpreter_frame_last_sp() const; diff -r 8c1cc431f388 -r 889895365eb9 hotspot/src/cpu/aarch64/vm/frame_aarch64.inline.hpp --- a/hotspot/src/cpu/aarch64/vm/frame_aarch64.inline.hpp Fri Mar 20 17:39:29 2015 +0000 +++ b/hotspot/src/cpu/aarch64/vm/frame_aarch64.inline.hpp Mon Mar 23 11:44:41 2015 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2014, Red Hat Inc. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -166,7 +166,6 @@ inline intptr_t* frame::link() const { return (intptr_t*) *(intptr_t **)addr_at(link_offset); } -inline void frame::set_link(intptr_t* addr) { *(intptr_t **)addr_at(link_offset) = addr; } inline intptr_t* frame::unextended_sp() const { return _unextended_sp; } @@ -176,9 +175,6 @@ inline address* frame::sender_pc_addr() const { return (address*) addr_at( return_addr_offset); } inline address frame::sender_pc() const { return *sender_pc_addr(); } -// return address of param, zero origin index. -inline address* frame::native_param_addr(int idx) const { return (address*) addr_at( native_frame_initial_param_offset+idx); } - #ifdef CC_INTERP inline interpreterState frame::get_interpreterState() const { diff -r 8c1cc431f388 -r 889895365eb9 hotspot/src/cpu/ppc/vm/ppc.ad --- a/hotspot/src/cpu/ppc/vm/ppc.ad Fri Mar 20 17:39:29 2015 +0000 +++ b/hotspot/src/cpu/ppc/vm/ppc.ad Mon Mar 23 11:44:41 2015 -0700 @@ -4416,11 +4416,11 @@ interface(CONST_INTER); %} -// constant 'float +0.0'. +// Float Immediate: +0.0f. operand immF_0() %{ - predicate((n->getf() == 0) && - (fpclassify(n->getf()) == FP_ZERO) && (signbit(n->getf()) == 0)); + predicate(jint_cast(n->getf()) == 0); match(ConF); + op_cost(0); format %{ %} interface(CONST_INTER); diff -r 8c1cc431f388 -r 889895365eb9 hotspot/src/cpu/sparc/vm/frame_sparc.inline.hpp --- a/hotspot/src/cpu/sparc/vm/frame_sparc.inline.hpp Fri Mar 20 17:39:29 2015 +0000 +++ b/hotspot/src/cpu/sparc/vm/frame_sparc.inline.hpp Mon Mar 23 11:44:41 2015 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2015, 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 @@ -69,8 +69,6 @@ inline intptr_t* frame::link() const { return (intptr_t *)(fp()[FP->sp_offset_in_saved_window()] + STACK_BIAS); } -inline void frame::set_link(intptr_t* addr) { assert(link()==addr, "frame nesting is controlled by hardware"); } - inline intptr_t* frame::unextended_sp() const { return sp() + _sp_adjustment_by_callee; } // return address: diff -r 8c1cc431f388 -r 889895365eb9 hotspot/src/cpu/sparc/vm/sparc.ad --- a/hotspot/src/cpu/sparc/vm/sparc.ad Fri Mar 20 17:39:29 2015 +0000 +++ b/hotspot/src/cpu/sparc/vm/sparc.ad Mon Mar 23 11:44:41 2015 -0700 @@ -3758,13 +3758,9 @@ interface(CONST_INTER); %} +// Double Immediate: +0.0d operand immD0() %{ -#ifdef _LP64 - // on 64-bit architectures this comparision is faster predicate(jlong_cast(n->getd()) == 0); -#else - predicate((n->getd() == 0) && (fpclass(n->getd()) == FP_PZERO)); -#endif match(ConD); op_cost(0); @@ -3781,9 +3777,9 @@ interface(CONST_INTER); %} -// Float Immediate: 0 +// Float Immediate: +0.0f operand immF0() %{ - predicate((n->getf() == 0) && (fpclass(n->getf()) == FP_PZERO)); + predicate(jint_cast(n->getf()) == 0); match(ConF); op_cost(0); diff -r 8c1cc431f388 -r 889895365eb9 hotspot/src/cpu/x86/vm/frame_x86.hpp --- a/hotspot/src/cpu/x86/vm/frame_x86.hpp Fri Mar 20 17:39:29 2015 +0000 +++ b/hotspot/src/cpu/x86/vm/frame_x86.hpp Mon Mar 23 11:44:41 2015 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2015, 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 @@ -128,21 +128,16 @@ entry_frame_after_call_words = 28, entry_frame_call_wrapper_offset = 2, - arg_reg_save_area_bytes = 32, // Register argument save area + arg_reg_save_area_bytes = 32 // Register argument save area #else entry_frame_after_call_words = 13, entry_frame_call_wrapper_offset = -6, - arg_reg_save_area_bytes = 0, + arg_reg_save_area_bytes = 0 #endif // _WIN64 #else - entry_frame_call_wrapper_offset = 2, + entry_frame_call_wrapper_offset = 2 #endif // AMD64 - - // Native frames - - native_frame_initial_param_offset = 2 - }; intptr_t ptr_at(int offset) const { @@ -195,9 +190,6 @@ inline address* sender_pc_addr() const; - // return address of param, zero origin index. - inline address* native_param_addr(int idx) const; - // expression stack tos if we are nested in a java call intptr_t* interpreter_frame_last_sp() const; diff -r 8c1cc431f388 -r 889895365eb9 hotspot/src/cpu/x86/vm/frame_x86.inline.hpp --- a/hotspot/src/cpu/x86/vm/frame_x86.inline.hpp Fri Mar 20 17:39:29 2015 +0000 +++ b/hotspot/src/cpu/x86/vm/frame_x86.inline.hpp Mon Mar 23 11:44:41 2015 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2015, 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 @@ -139,8 +139,6 @@ inline intptr_t* frame::link() const { return (intptr_t*) *(intptr_t **)addr_at(link_offset); } -inline void frame::set_link(intptr_t* addr) { *(intptr_t **)addr_at(link_offset) = addr; } - inline intptr_t* frame::unextended_sp() const { return _unextended_sp; } @@ -149,9 +147,6 @@ inline address* frame::sender_pc_addr() const { return (address*) addr_at( return_addr_offset); } inline address frame::sender_pc() const { return *sender_pc_addr(); } -// return address of param, zero origin index. -inline address* frame::native_param_addr(int idx) const { return (address*) addr_at( native_frame_initial_param_offset+idx); } - #ifdef CC_INTERP inline interpreterState frame::get_interpreterState() const { diff -r 8c1cc431f388 -r 889895365eb9 hotspot/src/cpu/x86/vm/interp_masm_x86.cpp --- a/hotspot/src/cpu/x86/vm/interp_masm_x86.cpp Fri Mar 20 17:39:29 2015 +0000 +++ b/hotspot/src/cpu/x86/vm/interp_masm_x86.cpp Mon Mar 23 11:44:41 2015 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2015, 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 @@ -25,7 +25,20 @@ #include "precompiled.hpp" #include "interp_masm_x86.hpp" #include "interpreter/interpreter.hpp" +#include "interpreter/interpreterRuntime.hpp" +#include "oops/arrayOop.hpp" +#include "oops/markOop.hpp" #include "oops/methodData.hpp" +#include "oops/method.hpp" +#include "prims/jvmtiExport.hpp" +#include "prims/jvmtiRedefineClassesTrace.hpp" +#include "prims/jvmtiThreadState.hpp" +#include "runtime/basicLock.hpp" +#include "runtime/biasedLocking.hpp" +#include "runtime/sharedRuntime.hpp" +#include "runtime/thread.inline.hpp" + +// Implementation of InterpreterMacroAssembler #ifndef CC_INTERP void InterpreterMacroAssembler::profile_obj_type(Register obj, const Address& mdo_addr) { @@ -227,3 +240,1637 @@ } } #endif + +#ifdef CC_INTERP +void InterpreterMacroAssembler::get_method(Register reg) { + movptr(reg, Address(rbp, -(sizeof(BytecodeInterpreter) + 2 * wordSize))); + movptr(reg, Address(reg, byte_offset_of(BytecodeInterpreter, _method))); +} +#endif // CC_INTERP + +#ifndef CC_INTERP +void InterpreterMacroAssembler::call_VM_leaf_base(address entry_point, + int number_of_arguments) { + // interpreter specific + // + // Note: No need to save/restore bcp & locals registers + // since these are callee saved registers and no blocking/ + // GC can happen in leaf calls. + // Further Note: DO NOT save/restore bcp/locals. If a caller has + // already saved them so that it can use rsi/rdi as temporaries + // then a save/restore here will DESTROY the copy the caller + // saved! There used to be a save_bcp() that only happened in + // the ASSERT path (no restore_bcp). Which caused bizarre failures + // when jvm built with ASSERTs. +#ifdef ASSERT + { + Label L; + cmpptr(Address(rbp, frame::interpreter_frame_last_sp_offset * wordSize), (int32_t)NULL_WORD); + jcc(Assembler::equal, L); + stop("InterpreterMacroAssembler::call_VM_leaf_base:" + " last_sp != NULL"); + bind(L); + } +#endif + // super call + MacroAssembler::call_VM_leaf_base(entry_point, number_of_arguments); + // interpreter specific + // LP64: Used to ASSERT that r13/r14 were equal to frame's bcp/locals + // but since they may not have been saved (and we don't want to + // save them here (see note above) the assert is invalid. +} + +void InterpreterMacroAssembler::call_VM_base(Register oop_result, + Register java_thread, + Register last_java_sp, + address entry_point, + int number_of_arguments, + bool check_exceptions) { + // interpreter specific + // + // Note: Could avoid restoring locals ptr (callee saved) - however doesn't + // really make a difference for these runtime calls, since they are + // slow anyway. Btw., bcp must be saved/restored since it may change + // due to GC. + NOT_LP64(assert(java_thread == noreg , "not expecting a precomputed java thread");) + save_bcp(); +#ifdef ASSERT + { + Label L; + cmpptr(Address(rbp, frame::interpreter_frame_last_sp_offset * wordSize), (int32_t)NULL_WORD); + jcc(Assembler::equal, L); + stop("InterpreterMacroAssembler::call_VM_leaf_base:" + " last_sp != NULL"); + bind(L); + } +#endif /* ASSERT */ + // super call + MacroAssembler::call_VM_base(oop_result, noreg, last_java_sp, + entry_point, number_of_arguments, + check_exceptions); + // interpreter specific + restore_bcp(); + restore_locals(); +} + +void InterpreterMacroAssembler::check_and_handle_popframe(Register java_thread) { + if (JvmtiExport::can_pop_frame()) { + Label L; + // Initiate popframe handling only if it is not already being + // processed. If the flag has the popframe_processing bit set, it + // means that this code is called *during* popframe handling - we + // don't want to reenter. + // This method is only called just after the call into the vm in + // call_VM_base, so the arg registers are available. + Register pop_cond = NOT_LP64(java_thread) // Not clear if any other register is available on 32 bit + LP64_ONLY(c_rarg0); + movl(pop_cond, Address(java_thread, JavaThread::popframe_condition_offset())); + testl(pop_cond, JavaThread::popframe_pending_bit); + jcc(Assembler::zero, L); + testl(pop_cond, JavaThread::popframe_processing_bit); + jcc(Assembler::notZero, L); + // Call Interpreter::remove_activation_preserving_args_entry() to get the + // address of the same-named entrypoint in the generated interpreter code. + call_VM_leaf(CAST_FROM_FN_PTR(address, Interpreter::remove_activation_preserving_args_entry)); + jmp(rax); + bind(L); + NOT_LP64(get_thread(java_thread);) + } +} + +void InterpreterMacroAssembler::load_earlyret_value(TosState state) { + Register thread = LP64_ONLY(r15_thread) NOT_LP64(rcx); + NOT_LP64(get_thread(thread);) + movptr(rcx, Address(thread, JavaThread::jvmti_thread_state_offset())); + const Address tos_addr(rcx, JvmtiThreadState::earlyret_tos_offset()); + const Address oop_addr(rcx, JvmtiThreadState::earlyret_oop_offset()); + const Address val_addr(rcx, JvmtiThreadState::earlyret_value_offset()); +#ifdef _LP64 + switch (state) { + case atos: movptr(rax, oop_addr); + movptr(oop_addr, (int32_t)NULL_WORD); + verify_oop(rax, state); break; + case ltos: movptr(rax, val_addr); break; + case btos: // fall through + case ctos: // fall through + case stos: // fall through + case itos: movl(rax, val_addr); break; + case ftos: movflt(xmm0, val_addr); break; + case dtos: movdbl(xmm0, val_addr); break; + case vtos: /* nothing to do */ break; + default : ShouldNotReachHere(); + } + // Clean up tos value in the thread object + movl(tos_addr, (int) ilgl); + movl(val_addr, (int32_t) NULL_WORD); +#else + const Address val_addr1(rcx, JvmtiThreadState::earlyret_value_offset() + + in_ByteSize(wordSize)); + switch (state) { + case atos: movptr(rax, oop_addr); + movptr(oop_addr, NULL_WORD); + verify_oop(rax, state); break; + case ltos: + movl(rdx, val_addr1); // fall through + case btos: // fall through + case ctos: // fall through + case stos: // fall through + case itos: movl(rax, val_addr); break; + case ftos: fld_s(val_addr); break; + case dtos: fld_d(val_addr); break; + case vtos: /* nothing to do */ break; + default : ShouldNotReachHere(); + } +#endif // _LP64 + // Clean up tos value in the thread object + movl(tos_addr, (int32_t) ilgl); + movptr(val_addr, NULL_WORD); + NOT_LP64(movptr(val_addr1, NULL_WORD);) +} + + +void InterpreterMacroAssembler::check_and_handle_earlyret(Register java_thread) { + if (JvmtiExport::can_force_early_return()) { + Label L; + Register tmp = LP64_ONLY(c_rarg0) NOT_LP64(java_thread); + Register rthread = LP64_ONLY(r15_thread) NOT_LP64(java_thread); + + movptr(tmp, Address(rthread, JavaThread::jvmti_thread_state_offset())); + testptr(tmp, tmp); + jcc(Assembler::zero, L); // if (thread->jvmti_thread_state() == NULL) exit; + + // Initiate earlyret handling only if it is not already being processed. + // If the flag has the earlyret_processing bit set, it means that this code + // is called *during* earlyret handling - we don't want to reenter. + movl(tmp, Address(tmp, JvmtiThreadState::earlyret_state_offset())); + cmpl(tmp, JvmtiThreadState::earlyret_pending); + jcc(Assembler::notEqual, L); + + // Call Interpreter::remove_activation_early_entry() to get the address of the + // same-named entrypoint in the generated interpreter code. + NOT_LP64(get_thread(java_thread);) + movptr(tmp, Address(rthread, JavaThread::jvmti_thread_state_offset())); +#ifdef _LP64 + movl(tmp, Address(tmp, JvmtiThreadState::earlyret_tos_offset())); + call_VM_leaf(CAST_FROM_FN_PTR(address, Interpreter::remove_activation_early_entry), tmp); +#else + pushl(Address(tmp, JvmtiThreadState::earlyret_tos_offset())); + call_VM_leaf(CAST_FROM_FN_PTR(address, Interpreter::remove_activation_early_entry), 1); +#endif // _LP64 + jmp(rax); + bind(L); + NOT_LP64(get_thread(java_thread);) + } +} + +void InterpreterMacroAssembler::get_unsigned_2_byte_index_at_bcp(Register reg, int bcp_offset) { + assert(bcp_offset >= 0, "bcp is still pointing to start of bytecode"); + load_unsigned_short(reg, Address(_bcp_register, bcp_offset)); + bswapl(reg); + shrl(reg, 16); +} + +void InterpreterMacroAssembler::get_cache_index_at_bcp(Register index, + int bcp_offset, + size_t index_size) { + assert(bcp_offset > 0, "bcp is still pointing to start of bytecode"); + if (index_size == sizeof(u2)) { + load_unsigned_short(index, Address(_bcp_register, bcp_offset)); + } else if (index_size == sizeof(u4)) { + movl(index, Address(_bcp_register, bcp_offset)); + // Check if the secondary index definition is still ~x, otherwise + // we have to change the following assembler code to calculate the + // plain index. + assert(ConstantPool::decode_invokedynamic_index(~123) == 123, "else change next line"); + notl(index); // convert to plain index + } else if (index_size == sizeof(u1)) { + load_unsigned_byte(index, Address(_bcp_register, bcp_offset)); + } else { + ShouldNotReachHere(); + } +} + +void InterpreterMacroAssembler::get_cache_and_index_at_bcp(Register cache, + Register index, + int bcp_offset, + size_t index_size) { + assert_different_registers(cache, index); + get_cache_index_at_bcp(index, bcp_offset, index_size); + movptr(cache, Address(rbp, frame::interpreter_frame_cache_offset * wordSize)); + assert(sizeof(ConstantPoolCacheEntry) == 4 * wordSize, "adjust code below"); + // convert from field index to ConstantPoolCacheEntry index + assert(exact_log2(in_words(ConstantPoolCacheEntry::size())) == 2, "else change next line"); + shll(index, 2); +} + +void InterpreterMacroAssembler::get_cache_and_index_and_bytecode_at_bcp(Register cache, + Register index, + Register bytecode, + int byte_no, + int bcp_offset, + size_t index_size) { + get_cache_and_index_at_bcp(cache, index, bcp_offset, index_size); + // We use a 32-bit load here since the layout of 64-bit words on + // little-endian machines allow us that. + movl(bytecode, Address(cache, index, Address::times_ptr, ConstantPoolCache::base_offset() + ConstantPoolCacheEntry::indices_offset())); + const int shift_count = (1 + byte_no) * BitsPerByte; + assert((byte_no == TemplateTable::f1_byte && shift_count == ConstantPoolCacheEntry::bytecode_1_shift) || + (byte_no == TemplateTable::f2_byte && shift_count == ConstantPoolCacheEntry::bytecode_2_shift), + "correct shift count"); + shrl(bytecode, shift_count); + assert(ConstantPoolCacheEntry::bytecode_1_mask == ConstantPoolCacheEntry::bytecode_2_mask, "common mask"); + andl(bytecode, ConstantPoolCacheEntry::bytecode_1_mask); +} + +void InterpreterMacroAssembler::get_cache_entry_pointer_at_bcp(Register cache, + Register tmp, + int bcp_offset, + size_t index_size) { + assert(cache != tmp, "must use different register"); + get_cache_index_at_bcp(tmp, bcp_offset, index_size); + assert(sizeof(ConstantPoolCacheEntry) == 4 * wordSize, "adjust code below"); + // convert from field index to ConstantPoolCacheEntry index + // and from word offset to byte offset + assert(exact_log2(in_bytes(ConstantPoolCacheEntry::size_in_bytes())) == 2 + LogBytesPerWord, "else change next line"); + shll(tmp, 2 + LogBytesPerWord); + movptr(cache, Address(rbp, frame::interpreter_frame_cache_offset * wordSize)); + // skip past the header + addptr(cache, in_bytes(ConstantPoolCache::base_offset())); + addptr(cache, tmp); // construct pointer to cache entry +} + +// Load object from cpool->resolved_references(index) +void InterpreterMacroAssembler::load_resolved_reference_at_index( + Register result, Register index) { + assert_different_registers(result, index); + // convert from field index to resolved_references() index and from + // word index to byte offset. Since this is a java object, it can be compressed + Register tmp = index; // reuse + shll(tmp, LogBytesPerHeapOop); + + get_constant_pool(result); + // load pointer for resolved_references[] objArray + movptr(result, Address(result, ConstantPool::resolved_references_offset_in_bytes())); + // JNIHandles::resolve(obj); + movptr(result, Address(result, 0)); + // Add in the index + addptr(result, tmp); + load_heap_oop(result, Address(result, arrayOopDesc::base_offset_in_bytes(T_OBJECT))); +} + + +// Generate a subtype check: branch to ok_is_subtype if sub_klass is a +// subtype of super_klass. +// +// Args: +// rax: superklass +// Rsub_klass: subklass +// +// Kills: +// rcx, rdi +void InterpreterMacroAssembler::gen_subtype_check(Register Rsub_klass, + Label& ok_is_subtype) { + assert(Rsub_klass != rax, "rax holds superklass"); + LP64_ONLY(assert(Rsub_klass != r14, "r14 holds locals");) + LP64_ONLY(assert(Rsub_klass != r13, "r13 holds bcp");) + assert(Rsub_klass != rcx, "rcx holds 2ndary super array length"); + assert(Rsub_klass != rdi, "rdi holds 2ndary super array scan ptr"); + + // Profile the not-null value's klass. + profile_typecheck(rcx, Rsub_klass, rdi); // blows rcx, reloads rdi + + // Do the check. + check_klass_subtype(Rsub_klass, rax, rcx, ok_is_subtype); // blows rcx + + // Profile the failure of the check. + profile_typecheck_failed(rcx); // blows rcx +} + + +#ifndef _LP64 +void InterpreterMacroAssembler::f2ieee() { + if (IEEEPrecision) { + fstp_s(Address(rsp, 0)); + fld_s(Address(rsp, 0)); + } +} + + +void InterpreterMacroAssembler::d2ieee() { + if (IEEEPrecision) { + fstp_d(Address(rsp, 0)); + fld_d(Address(rsp, 0)); + } +} +#endif // _LP64 + +// Java Expression Stack + +void InterpreterMacroAssembler::pop_ptr(Register r) { + pop(r); +} + +void InterpreterMacroAssembler::push_ptr(Register r) { + push(r); +} + +void InterpreterMacroAssembler::push_i(Register r) { + push(r); +} + +#ifdef _LP64 +void InterpreterMacroAssembler::pop_i(Register r) { + // XXX can't use pop currently, upper half non clean + movl(r, Address(rsp, 0)); + addptr(rsp, wordSize); +} + +void InterpreterMacroAssembler::pop_l(Register r) { + movq(r, Address(rsp, 0)); + addptr(rsp, 2 * Interpreter::stackElementSize); +} + +void InterpreterMacroAssembler::pop_f(XMMRegister r) { + movflt(r, Address(rsp, 0)); + addptr(rsp, wordSize); +} + +void InterpreterMacroAssembler::pop_d(XMMRegister r) { + movdbl(r, Address(rsp, 0)); + addptr(rsp, 2 * Interpreter::stackElementSize); +} + +void InterpreterMacroAssembler::push_l(Register r) { + subptr(rsp, 2 * wordSize); + movq(Address(rsp, 0), r); +} + +void InterpreterMacroAssembler::push_f(XMMRegister r) { + subptr(rsp, wordSize); + movflt(Address(rsp, 0), r); +} + +void InterpreterMacroAssembler::push_d(XMMRegister r) { + subptr(rsp, 2 * wordSize); + movdbl(Address(rsp, 0), r); +} + +void InterpreterMacroAssembler::pop(TosState state) { + switch (state) { + case atos: pop_ptr(); break; + case btos: + case ctos: + case stos: + case itos: pop_i(); break; + case ltos: pop_l(); break; + case ftos: pop_f(); break; + case dtos: pop_d(); break; + case vtos: /* nothing to do */ break; + default: ShouldNotReachHere(); + } + verify_oop(rax, state); +} + +void InterpreterMacroAssembler::push(TosState state) { + verify_oop(rax, state); + switch (state) { + case atos: push_ptr(); break; + case btos: + case ctos: + case stos: + case itos: push_i(); break; + case ltos: push_l(); break; + case ftos: push_f(); break; + case dtos: push_d(); break; + case vtos: /* nothing to do */ break; + default : ShouldNotReachHere(); + } +} +#else +void InterpreterMacroAssembler::pop_i(Register r) { + pop(r); +} + +void InterpreterMacroAssembler::pop_l(Register lo, Register hi) { + pop(lo); + pop(hi); +} + +void InterpreterMacroAssembler::pop_f() { + fld_s(Address(rsp, 0)); + addptr(rsp, 1 * wordSize); +} + +void InterpreterMacroAssembler::pop_d() { + fld_d(Address(rsp, 0)); + addptr(rsp, 2 * wordSize); +} + + +void InterpreterMacroAssembler::pop(TosState state) { + switch (state) { + case atos: pop_ptr(rax); break; + case btos: // fall through + case ctos: // fall through + case stos: // fall through + case itos: pop_i(rax); break; + case ltos: pop_l(rax, rdx); break; + case ftos: pop_f(); break; + case dtos: pop_d(); break; + case vtos: /* nothing to do */ break; + default : ShouldNotReachHere(); + } + verify_oop(rax, state); +} + + +void InterpreterMacroAssembler::push_l(Register lo, Register hi) { + push(hi); + push(lo); +} + +void InterpreterMacroAssembler::push_f() { + // Do not schedule for no AGI! Never write beyond rsp! + subptr(rsp, 1 * wordSize); + fstp_s(Address(rsp, 0)); +} + +void InterpreterMacroAssembler::push_d(Register r) { + // Do not schedule for no AGI! Never write beyond rsp! + subptr(rsp, 2 * wordSize); + fstp_d(Address(rsp, 0)); +} + + +void InterpreterMacroAssembler::push(TosState state) { + verify_oop(rax, state); + switch (state) { + case atos: push_ptr(rax); break; + case btos: // fall through + case ctos: // fall through + case stos: // fall through + case itos: push_i(rax); break; + case ltos: push_l(rax, rdx); break; + case ftos: push_f(); break; + case dtos: push_d(rax); break; + case vtos: /* nothing to do */ break; + default : ShouldNotReachHere(); + } +} +#endif // _LP64 + + +// Helpers for swap and dup +void InterpreterMacroAssembler::load_ptr(int n, Register val) { + movptr(val, Address(rsp, Interpreter::expr_offset_in_bytes(n))); +} + +void InterpreterMacroAssembler::store_ptr(int n, Register val) { + movptr(Address(rsp, Interpreter::expr_offset_in_bytes(n)), val); +} + + +void InterpreterMacroAssembler::prepare_to_jump_from_interpreted() { + // set sender sp + lea(_bcp_register, Address(rsp, wordSize)); + // record last_sp + movptr(Address(rbp, frame::interpreter_frame_last_sp_offset * wordSize), _bcp_register); +} + + +// Jump to from_interpreted entry of a call unless single stepping is possible +// in this thread in which case we must call the i2i entry +void InterpreterMacroAssembler::jump_from_interpreted(Register method, Register temp) { + prepare_to_jump_from_interpreted(); + + if (JvmtiExport::can_post_interpreter_events()) { + Label run_compiled_code; + // JVMTI events, such as single-stepping, are implemented partly by avoiding running + // compiled code in threads for which the event is enabled. Check here for + // interp_only_mode if these events CAN be enabled. + // interp_only is an int, on little endian it is sufficient to test the byte only + // Is a cmpl faster? + LP64_ONLY(temp = r15_thread;) + NOT_LP64(get_thread(temp);) + cmpb(Address(temp, JavaThread::interp_only_mode_offset()), 0); + jccb(Assembler::zero, run_compiled_code); + jmp(Address(method, Method::interpreter_entry_offset())); + bind(run_compiled_code); + } + + jmp(Address(method, Method::from_interpreted_offset())); +} + +// The following two routines provide a hook so that an implementation +// can schedule the dispatch in two parts. x86 does not do this. +void InterpreterMacroAssembler::dispatch_prolog(TosState state, int step) { + // Nothing x86 specific to be done here +} + +void InterpreterMacroAssembler::dispatch_epilog(TosState state, int step) { + dispatch_next(state, step); +} + +void InterpreterMacroAssembler::dispatch_base(TosState state, + address* table, + bool verifyoop) { + verify_FPU(1, state); + if (VerifyActivationFrameSize) { + Label L; + mov(rcx, rbp); + subptr(rcx, rsp); + int32_t min_frame_size = + (frame::link_offset - frame::interpreter_frame_initial_sp_offset) * + wordSize; + cmpptr(rcx, (int32_t)min_frame_size); + jcc(Assembler::greaterEqual, L); + stop("broken stack frame"); + bind(L); + } + if (verifyoop) { + verify_oop(rax, state); + } +#ifdef _LP64 + lea(rscratch1, ExternalAddress((address)table)); + jmp(Address(rscratch1, rbx, Address::times_8)); +#else + Address index(noreg, rbx, Address::times_ptr); + ExternalAddress tbl((address)table); + ArrayAddress dispatch(tbl, index); + jump(dispatch); +#endif // _LP64 +} + +void InterpreterMacroAssembler::dispatch_only(TosState state) { + dispatch_base(state, Interpreter::dispatch_table(state)); +} + +void InterpreterMacroAssembler::dispatch_only_normal(TosState state) { + dispatch_base(state, Interpreter::normal_table(state)); +} + +void InterpreterMacroAssembler::dispatch_only_noverify(TosState state) { + dispatch_base(state, Interpreter::normal_table(state), false); +} + + +void InterpreterMacroAssembler::dispatch_next(TosState state, int step) { + // load next bytecode (load before advancing _bcp_register to prevent AGI) + load_unsigned_byte(rbx, Address(_bcp_register, step)); + // advance _bcp_register + increment(_bcp_register, step); + dispatch_base(state, Interpreter::dispatch_table(state)); +} + +void InterpreterMacroAssembler::dispatch_via(TosState state, address* table) { + // load current bytecode + load_unsigned_byte(rbx, Address(_bcp_register, 0)); + dispatch_base(state, table); +} + +// remove activation +// +// Unlock the receiver if this is a synchronized method. +// Unlock any Java monitors from syncronized blocks. +// Remove the activation from the stack. +// +// If there are locked Java monitors +// If throw_monitor_exception +// throws IllegalMonitorStateException +// Else if install_monitor_exception +// installs IllegalMonitorStateException +// Else +// no error processing +void InterpreterMacroAssembler::remove_activation( + TosState state, + Register ret_addr, + bool throw_monitor_exception, + bool install_monitor_exception, + bool notify_jvmdi) { + // Note: Registers rdx xmm0 may be in use for the + // result check if synchronized method + Label unlocked, unlock, no_unlock; + + const Register rthread = LP64_ONLY(r15_thread) NOT_LP64(rcx); + const Register robj = LP64_ONLY(c_rarg1) NOT_LP64(rdx); + const Register rmon = LP64_ONLY(c_rarg1) NOT_LP64(rcx); + // monitor pointers need different register + // because rdx may have the result in it + NOT_LP64(get_thread(rcx);) + + // get the value of _do_not_unlock_if_synchronized into rdx + const Address do_not_unlock_if_synchronized(rthread, + in_bytes(JavaThread::do_not_unlock_if_synchronized_offset())); + movbool(rbx, do_not_unlock_if_synchronized); + movbool(do_not_unlock_if_synchronized, false); // reset the flag + + // get method access flags + movptr(rcx, Address(rbp, frame::interpreter_frame_method_offset * wordSize)); + movl(rcx, Address(rcx, Method::access_flags_offset())); + testl(rcx, JVM_ACC_SYNCHRONIZED); + jcc(Assembler::zero, unlocked); + + // Don't unlock anything if the _do_not_unlock_if_synchronized flag + // is set. + testbool(rbx); + jcc(Assembler::notZero, no_unlock); + + // unlock monitor + push(state); // save result + + // BasicObjectLock will be first in list, since this is a + // synchronized method. However, need to check that the object has + // not been unlocked by an explicit monitorexit bytecode. + const Address monitor(rbp, frame::interpreter_frame_initial_sp_offset * + wordSize - (int) sizeof(BasicObjectLock)); + // We use c_rarg1/rdx so that if we go slow path it will be the correct + // register for unlock_object to pass to VM directly + lea(robj, monitor); // address of first monitor + + movptr(rax, Address(robj, BasicObjectLock::obj_offset_in_bytes())); + testptr(rax, rax); + jcc(Assembler::notZero, unlock); + + pop(state); + if (throw_monitor_exception) { + // Entry already unlocked, need to throw exception + NOT_LP64(empty_FPU_stack();) // remove possible return value from FPU-stack, otherwise stack could overflow + call_VM(noreg, CAST_FROM_FN_PTR(address, + InterpreterRuntime::throw_illegal_monitor_state_exception)); + should_not_reach_here(); + } else { + // Monitor already unlocked during a stack unroll. If requested, + // install an illegal_monitor_state_exception. Continue with + // stack unrolling. + if (install_monitor_exception) { + NOT_LP64(empty_FPU_stack();) + call_VM(noreg, CAST_FROM_FN_PTR(address, + InterpreterRuntime::new_illegal_monitor_state_exception)); + } + jmp(unlocked); + } + + bind(unlock); + unlock_object(robj); + pop(state); + + // Check that for block-structured locking (i.e., that all locked + // objects has been unlocked) + bind(unlocked); + + // rax, rdx: Might contain return value + + // Check that all monitors are unlocked + { + Label loop, exception, entry, restart; + const int entry_size = frame::interpreter_frame_monitor_size() * wordSize; + const Address monitor_block_top( + rbp, frame::interpreter_frame_monitor_block_top_offset * wordSize); + const Address monitor_block_bot( + rbp, frame::interpreter_frame_initial_sp_offset * wordSize); + + bind(restart); + // We use c_rarg1 so that if we go slow path it will be the correct + // register for unlock_object to pass to VM directly + movptr(rmon, monitor_block_top); // points to current entry, starting + // with top-most entry + lea(rbx, monitor_block_bot); // points to word before bottom of + // monitor block + jmp(entry); + + // Entry already locked, need to throw exception + bind(exception); + + if (throw_monitor_exception) { + // Throw exception + NOT_LP64(empty_FPU_stack();) + MacroAssembler::call_VM(noreg, + CAST_FROM_FN_PTR(address, InterpreterRuntime:: + throw_illegal_monitor_state_exception)); + should_not_reach_here(); + } else { + // Stack unrolling. Unlock object and install illegal_monitor_exception. + // Unlock does not block, so don't have to worry about the frame. + // We don't have to preserve c_rarg1 since we are going to throw an exception. + + push(state); + mov(robj, rmon); // nop if robj and rmon are the same + unlock_object(robj); + pop(state); + + if (install_monitor_exception) { + NOT_LP64(empty_FPU_stack();) + call_VM(noreg, CAST_FROM_FN_PTR(address, + InterpreterRuntime:: + new_illegal_monitor_state_exception)); + } + + jmp(restart); + } + + bind(loop); + // check if current entry is used + cmpptr(Address(rmon, BasicObjectLock::obj_offset_in_bytes()), (int32_t) NULL); + jcc(Assembler::notEqual, exception); + + addptr(rmon, entry_size); // otherwise advance to next entry + bind(entry); + cmpptr(rmon, rbx); // check if bottom reached + jcc(Assembler::notEqual, loop); // if not at bottom then check this entry + } + + bind(no_unlock); + + // jvmti support + if (notify_jvmdi) { + notify_method_exit(state, NotifyJVMTI); // preserve TOSCA + } else { + notify_method_exit(state, SkipNotifyJVMTI); // preserve TOSCA + } + + // remove activation + // get sender sp + movptr(rbx, + Address(rbp, frame::interpreter_frame_sender_sp_offset * wordSize)); + leave(); // remove frame anchor + pop(ret_addr); // get return address + mov(rsp, rbx); // set sp to sender sp +#ifndef _LP64 + if (UseSSE) { + // float and double are returned in xmm register in SSE-mode + if (state == ftos && UseSSE >= 1) { + subptr(rsp, wordSize); + fstp_s(Address(rsp, 0)); + movflt(xmm0, Address(rsp, 0)); + addptr(rsp, wordSize); + } else if (state == dtos && UseSSE >= 2) { + subptr(rsp, 2*wordSize); + fstp_d(Address(rsp, 0)); + movdbl(xmm0, Address(rsp, 0)); + addptr(rsp, 2*wordSize); + } + } +#endif // _LP64 +} +#endif // !CC_INTERP + +void InterpreterMacroAssembler::get_method_counters(Register method, + Register mcs, Label& skip) { + Label has_counters; + movptr(mcs, Address(method, Method::method_counters_offset())); + testptr(mcs, mcs); + jcc(Assembler::notZero, has_counters); + call_VM(noreg, CAST_FROM_FN_PTR(address, + InterpreterRuntime::build_method_counters), method); + movptr(mcs, Address(method,Method::method_counters_offset())); + testptr(mcs, mcs); + jcc(Assembler::zero, skip); // No MethodCounters allocated, OutOfMemory + bind(has_counters); +} + + +// Lock object +// +// Args: +// rdx, c_rarg1: BasicObjectLock to be used for locking +// +// Kills: +// rax +// rscratch1 (scratch regs) +void InterpreterMacroAssembler::lock_object(Register lock_reg) { + assert(lock_reg == LP64_ONLY(c_rarg1) NOT_LP64(rdx), + "The argument is only for looks. It must be c_rarg1"); + + if (UseHeavyMonitors) { + call_VM(noreg, + CAST_FROM_FN_PTR(address, InterpreterRuntime::monitorenter), + lock_reg); + } else { + Label done; + + const Register swap_reg = rax; // Must use rax for cmpxchg instruction + const Register obj_reg = LP64_ONLY(c_rarg3) NOT_LP64(rcx); // Will contain the oop + + const int obj_offset = BasicObjectLock::obj_offset_in_bytes(); + const int lock_offset = BasicObjectLock::lock_offset_in_bytes (); + const int mark_offset = lock_offset + + BasicLock::displaced_header_offset_in_bytes(); + + Label slow_case; + + // Load object pointer into obj_reg + movptr(obj_reg, Address(lock_reg, obj_offset)); + + if (UseBiasedLocking) { + biased_locking_enter(lock_reg, obj_reg, swap_reg, rscratch1, false, done, &slow_case); + } + + // Load immediate 1 into swap_reg %rax + movl(swap_reg, (int32_t)1); + + // Load (object->mark() | 1) into swap_reg %rax + orptr(swap_reg, Address(obj_reg, 0)); + + // Save (object->mark() | 1) into BasicLock's displaced header + movptr(Address(lock_reg, mark_offset), swap_reg); + + assert(lock_offset == 0, + "displached header must be first word in BasicObjectLock"); + + if (os::is_MP()) lock(); + cmpxchgptr(lock_reg, Address(obj_reg, 0)); + if (PrintBiasedLockingStatistics) { + cond_inc32(Assembler::zero, + ExternalAddress((address) BiasedLocking::fast_path_entry_count_addr())); + } + jcc(Assembler::zero, done); + + const int zero_bits = LP64_ONLY(7) NOT_LP64(3); + + // Test if the oopMark is an obvious stack pointer, i.e., + // 1) (mark & zero_bits) == 0, and + // 2) rsp <= mark < mark + os::pagesize() + // + // These 3 tests can be done by evaluating the following + // expression: ((mark - rsp) & (zero_bits - os::vm_page_size())), + // assuming both stack pointer and pagesize have their + // least significant bits clear. + // NOTE: the oopMark is in swap_reg %rax as the result of cmpxchg + subptr(swap_reg, rsp); + andptr(swap_reg, zero_bits - os::vm_page_size()); + + // Save the test result, for recursive case, the result is zero + movptr(Address(lock_reg, mark_offset), swap_reg); + + if (PrintBiasedLockingStatistics) { + cond_inc32(Assembler::zero, + ExternalAddress((address) BiasedLocking::fast_path_entry_count_addr())); + } + jcc(Assembler::zero, done); + + bind(slow_case); + + // Call the runtime routine for slow case + call_VM(noreg, + CAST_FROM_FN_PTR(address, InterpreterRuntime::monitorenter), + lock_reg); + + bind(done); + } +} + + +// Unlocks an object. Used in monitorexit bytecode and +// remove_activation. Throws an IllegalMonitorException if object is +// not locked by current thread. +// +// Args: +// rdx, c_rarg1: BasicObjectLock for lock +// +// Kills: +// rax +// c_rarg0, c_rarg1, c_rarg2, c_rarg3, ... (param regs) +// rscratch1, rscratch2 (scratch regs) +// rax, rbx, rcx, rdx +void InterpreterMacroAssembler::unlock_object(Register lock_reg) { + assert(lock_reg == LP64_ONLY(c_rarg1) NOT_LP64(rdx), + "The argument is only for looks. It must be c_rarg1"); + + if (UseHeavyMonitors) { + call_VM(noreg, + CAST_FROM_FN_PTR(address, InterpreterRuntime::monitorexit), + lock_reg); + } else { + Label done; + + const Register swap_reg = rax; // Must use rax for cmpxchg instruction + const Register header_reg = LP64_ONLY(c_rarg2) NOT_LP64(rbx); // Will contain the old oopMark + const Register obj_reg = LP64_ONLY(c_rarg3) NOT_LP64(rcx); // Will contain the oop + + save_bcp(); // Save in case of exception + + // Convert from BasicObjectLock structure to object and BasicLock + // structure Store the BasicLock address into %rax + lea(swap_reg, Address(lock_reg, BasicObjectLock::lock_offset_in_bytes())); + + // Load oop into obj_reg(%c_rarg3) + movptr(obj_reg, Address(lock_reg, BasicObjectLock::obj_offset_in_bytes())); + + // Free entry + movptr(Address(lock_reg, BasicObjectLock::obj_offset_in_bytes()), (int32_t)NULL_WORD); + + if (UseBiasedLocking) { + biased_locking_exit(obj_reg, header_reg, done); + } + + // Load the old header from BasicLock structure + movptr(header_reg, Address(swap_reg, + BasicLock::displaced_header_offset_in_bytes())); + + // Test for recursion + testptr(header_reg, header_reg); + + // zero for recursive case + jcc(Assembler::zero, done); + + // Atomic swap back the old header + if (os::is_MP()) lock(); + cmpxchgptr(header_reg, Address(obj_reg, 0)); + + // zero for recursive case + jcc(Assembler::zero, done); + + // Call the runtime routine for slow case. + movptr(Address(lock_reg, BasicObjectLock::obj_offset_in_bytes()), + obj_reg); // restore obj + call_VM(noreg, + CAST_FROM_FN_PTR(address, InterpreterRuntime::monitorexit), + lock_reg); + + bind(done); + + restore_bcp(); + } +} +#ifndef CC_INTERP +void InterpreterMacroAssembler::test_method_data_pointer(Register mdp, + Label& zero_continue) { + assert(ProfileInterpreter, "must be profiling interpreter"); + movptr(mdp, Address(rbp, frame::interpreter_frame_mdp_offset * wordSize)); + testptr(mdp, mdp); + jcc(Assembler::zero, zero_continue); +} + + +// Set the method data pointer for the current bcp. +void InterpreterMacroAssembler::set_method_data_pointer_for_bcp() { + assert(ProfileInterpreter, "must be profiling interpreter"); + Label set_mdp; + push(rax); + push(rbx); + + get_method(rbx); + // Test MDO to avoid the call if it is NULL. + movptr(rax, Address(rbx, in_bytes(Method::method_data_offset()))); + testptr(rax, rax); + jcc(Assembler::zero, set_mdp); + // rbx: method + // _bcp_register: bcp + call_VM_leaf(CAST_FROM_FN_PTR(address, InterpreterRuntime::bcp_to_di), rbx, _bcp_register); + // rax: mdi + // mdo is guaranteed to be non-zero here, we checked for it before the call. + movptr(rbx, Address(rbx, in_bytes(Method::method_data_offset()))); + addptr(rbx, in_bytes(MethodData::data_offset())); + addptr(rax, rbx); + bind(set_mdp); + movptr(Address(rbp, frame::interpreter_frame_mdp_offset * wordSize), rax); + pop(rbx); + pop(rax); +} + +void InterpreterMacroAssembler::verify_method_data_pointer() { + assert(ProfileInterpreter, "must be profiling interpreter"); +#ifdef ASSERT + Label verify_continue; + push(rax); + push(rbx); + Register arg3_reg = LP64_ONLY(c_rarg3) NOT_LP64(rcx); + Register arg2_reg = LP64_ONLY(c_rarg2) NOT_LP64(rdx); + push(arg3_reg); + push(arg2_reg); + test_method_data_pointer(arg3_reg, verify_continue); // If mdp is zero, continue + get_method(rbx); + + // If the mdp is valid, it will point to a DataLayout header which is + // consistent with the bcp. The converse is highly probable also. + load_unsigned_short(arg2_reg, + Address(arg3_reg, in_bytes(DataLayout::bci_offset()))); + addptr(arg2_reg, Address(rbx, Method::const_offset())); + lea(arg2_reg, Address(arg2_reg, ConstMethod::codes_offset())); + cmpptr(arg2_reg, _bcp_register); + jcc(Assembler::equal, verify_continue); + // rbx: method + // _bcp_register: bcp + // c_rarg3: mdp + call_VM_leaf(CAST_FROM_FN_PTR(address, InterpreterRuntime::verify_mdp), + rbx, _bcp_register, arg3_reg); + bind(verify_continue); + pop(arg2_reg); + pop(arg3_reg); + pop(rbx); + pop(rax); +#endif // ASSERT +} + + +void InterpreterMacroAssembler::set_mdp_data_at(Register mdp_in, + int constant, + Register value) { + assert(ProfileInterpreter, "must be profiling interpreter"); + Address data(mdp_in, constant); + movptr(data, value); +} + + +void InterpreterMacroAssembler::increment_mdp_data_at(Register mdp_in, + int constant, + bool decrement) { + // Counter address + Address data(mdp_in, constant); + + increment_mdp_data_at(data, decrement); +} + +void InterpreterMacroAssembler::increment_mdp_data_at(Address data, + bool decrement) { + assert(ProfileInterpreter, "must be profiling interpreter"); + // %%% this does 64bit counters at best it is wasting space + // at worst it is a rare bug when counters overflow + + if (decrement) { + // Decrement the register. Set condition codes. + addptr(data, (int32_t) -DataLayout::counter_increment); + // If the decrement causes the counter to overflow, stay negative + Label L; + jcc(Assembler::negative, L); + addptr(data, (int32_t) DataLayout::counter_increment); + bind(L); + } else { + assert(DataLayout::counter_increment == 1, + "flow-free idiom only works with 1"); + // Increment the register. Set carry flag. + addptr(data, DataLayout::counter_increment); + // If the increment causes the counter to overflow, pull back by 1. + sbbptr(data, (int32_t)0); + } +} + + +void InterpreterMacroAssembler::increment_mdp_data_at(Register mdp_in, + Register reg, + int constant, + bool decrement) { + Address data(mdp_in, reg, Address::times_1, constant); + + increment_mdp_data_at(data, decrement); +} + +void InterpreterMacroAssembler::set_mdp_flag_at(Register mdp_in, + int flag_byte_constant) { + assert(ProfileInterpreter, "must be profiling interpreter"); + int header_offset = in_bytes(DataLayout::header_offset()); + int header_bits = DataLayout::flag_mask_to_header_mask(flag_byte_constant); + // Set the flag + orl(Address(mdp_in, header_offset), header_bits); +} + + + +void InterpreterMacroAssembler::test_mdp_data_at(Register mdp_in, + int offset, + Register value, + Register test_value_out, + Label& not_equal_continue) { + assert(ProfileInterpreter, "must be profiling interpreter"); + if (test_value_out == noreg) { + cmpptr(value, Address(mdp_in, offset)); + } else { + // Put the test value into a register, so caller can use it: + movptr(test_value_out, Address(mdp_in, offset)); + cmpptr(test_value_out, value); + } + jcc(Assembler::notEqual, not_equal_continue); +} + + +void InterpreterMacroAssembler::update_mdp_by_offset(Register mdp_in, + int offset_of_disp) { + assert(ProfileInterpreter, "must be profiling interpreter"); + Address disp_address(mdp_in, offset_of_disp); + addptr(mdp_in, disp_address); + movptr(Address(rbp, frame::interpreter_frame_mdp_offset * wordSize), mdp_in); +} + + +void InterpreterMacroAssembler::update_mdp_by_offset(Register mdp_in, + Register reg, + int offset_of_disp) { + assert(ProfileInterpreter, "must be profiling interpreter"); + Address disp_address(mdp_in, reg, Address::times_1, offset_of_disp); + addptr(mdp_in, disp_address); + movptr(Address(rbp, frame::interpreter_frame_mdp_offset * wordSize), mdp_in); +} + + +void InterpreterMacroAssembler::update_mdp_by_constant(Register mdp_in, + int constant) { + assert(ProfileInterpreter, "must be profiling interpreter"); + addptr(mdp_in, constant); + movptr(Address(rbp, frame::interpreter_frame_mdp_offset * wordSize), mdp_in); +} + + +void InterpreterMacroAssembler::update_mdp_for_ret(Register return_bci) { + assert(ProfileInterpreter, "must be profiling interpreter"); + push(return_bci); // save/restore across call_VM + call_VM(noreg, + CAST_FROM_FN_PTR(address, InterpreterRuntime::update_mdp_for_ret), + return_bci); + pop(return_bci); +} + + +void InterpreterMacroAssembler::profile_taken_branch(Register mdp, + Register bumped_count) { + if (ProfileInterpreter) { + Label profile_continue; + + // If no method data exists, go to profile_continue. + // Otherwise, assign to mdp + test_method_data_pointer(mdp, profile_continue); + + // We are taking a branch. Increment the taken count. + // We inline increment_mdp_data_at to return bumped_count in a register + //increment_mdp_data_at(mdp, in_bytes(JumpData::taken_offset())); + Address data(mdp, in_bytes(JumpData::taken_offset())); + movptr(bumped_count, data); + assert(DataLayout::counter_increment == 1, + "flow-free idiom only works with 1"); + addptr(bumped_count, DataLayout::counter_increment); + sbbptr(bumped_count, 0); + movptr(data, bumped_count); // Store back out + + // The method data pointer needs to be updated to reflect the new target. + update_mdp_by_offset(mdp, in_bytes(JumpData::displacement_offset())); + bind(profile_continue); + } +} + + +void InterpreterMacroAssembler::profile_not_taken_branch(Register mdp) { + if (ProfileInterpreter) { + Label profile_continue; + + // If no method data exists, go to profile_continue. + test_method_data_pointer(mdp, profile_continue); + + // We are taking a branch. Increment the not taken count. + increment_mdp_data_at(mdp, in_bytes(BranchData::not_taken_offset())); + + // The method data pointer needs to be updated to correspond to + // the next bytecode + update_mdp_by_constant(mdp, in_bytes(BranchData::branch_data_size())); + bind(profile_continue); + } +} + +void InterpreterMacroAssembler::profile_call(Register mdp) { + if (ProfileInterpreter) { + Label profile_continue; + + // If no method data exists, go to profile_continue. + test_method_data_pointer(mdp, profile_continue); + + // We are making a call. Increment the count. + increment_mdp_data_at(mdp, in_bytes(CounterData::count_offset())); + + // The method data pointer needs to be updated to reflect the new target. + update_mdp_by_constant(mdp, in_bytes(CounterData::counter_data_size())); + bind(profile_continue); + } +} + + +void InterpreterMacroAssembler::profile_final_call(Register mdp) { + if (ProfileInterpreter) { + Label profile_continue; + + // If no method data exists, go to profile_continue. + test_method_data_pointer(mdp, profile_continue); + + // We are making a call. Increment the count. + increment_mdp_data_at(mdp, in_bytes(CounterData::count_offset())); + + // The method data pointer needs to be updated to reflect the new target. + update_mdp_by_constant(mdp, + in_bytes(VirtualCallData:: + virtual_call_data_size())); + bind(profile_continue); + } +} + + +void InterpreterMacroAssembler::profile_virtual_call(Register receiver, + Register mdp, + Register reg2, + bool receiver_can_be_null) { + if (ProfileInterpreter) { + Label profile_continue; + + // If no method data exists, go to profile_continue. + test_method_data_pointer(mdp, profile_continue); + + Label skip_receiver_profile; + if (receiver_can_be_null) { + Label not_null; + testptr(receiver, receiver); + jccb(Assembler::notZero, not_null); + // We are making a call. Increment the count for null receiver. + increment_mdp_data_at(mdp, in_bytes(CounterData::count_offset())); + jmp(skip_receiver_profile); + bind(not_null); + } + + // Record the receiver type. + record_klass_in_profile(receiver, mdp, reg2, true); + bind(skip_receiver_profile); + + // The method data pointer needs to be updated to reflect the new target. + update_mdp_by_constant(mdp, + in_bytes(VirtualCallData:: + virtual_call_data_size())); + bind(profile_continue); + } +} + +// This routine creates a state machine for updating the multi-row +// type profile at a virtual call site (or other type-sensitive bytecode). +// The machine visits each row (of receiver/count) until the receiver type +// is found, or until it runs out of rows. At the same time, it remembers +// the location of the first empty row. (An empty row records null for its +// receiver, and can be allocated for a newly-observed receiver type.) +// Because there are two degrees of freedom in the state, a simple linear +// search will not work; it must be a decision tree. Hence this helper +// function is recursive, to generate the required tree structured code. +// It's the interpreter, so we are trading off code space for speed. +// See below for example code. +void InterpreterMacroAssembler::record_klass_in_profile_helper( + Register receiver, Register mdp, + Register reg2, int start_row, + Label& done, bool is_virtual_call) { + if (TypeProfileWidth == 0) { + if (is_virtual_call) { + increment_mdp_data_at(mdp, in_bytes(CounterData::count_offset())); + } + return; + } + + int last_row = VirtualCallData::row_limit() - 1; + assert(start_row <= last_row, "must be work left to do"); + // Test this row for both the receiver and for null. + // Take any of three different outcomes: + // 1. found receiver => increment count and goto done + // 2. found null => keep looking for case 1, maybe allocate this cell + // 3. found something else => keep looking for cases 1 and 2 + // Case 3 is handled by a recursive call. + for (int row = start_row; row <= last_row; row++) { + Label next_test; + bool test_for_null_also = (row == start_row); + + // See if the receiver is receiver[n]. + int recvr_offset = in_bytes(VirtualCallData::receiver_offset(row)); + test_mdp_data_at(mdp, recvr_offset, receiver, + (test_for_null_also ? reg2 : noreg), + next_test); + // (Reg2 now contains the receiver from the CallData.) + + // The receiver is receiver[n]. Increment count[n]. + int count_offset = in_bytes(VirtualCallData::receiver_count_offset(row)); + increment_mdp_data_at(mdp, count_offset); + jmp(done); + bind(next_test); + + if (test_for_null_also) { + Label found_null; + // Failed the equality check on receiver[n]... Test for null. + testptr(reg2, reg2); + if (start_row == last_row) { + // The only thing left to do is handle the null case. + if (is_virtual_call) { + jccb(Assembler::zero, found_null); + // Receiver did not match any saved receiver and there is no empty row for it. + // Increment total counter to indicate polymorphic case. + increment_mdp_data_at(mdp, in_bytes(CounterData::count_offset())); + jmp(done); + bind(found_null); + } else { + jcc(Assembler::notZero, done); + } + break; + } + // Since null is rare, make it be the branch-taken case. + jcc(Assembler::zero, found_null); + + // Put all the "Case 3" tests here. + record_klass_in_profile_helper(receiver, mdp, reg2, start_row + 1, done, is_virtual_call); + + // Found a null. Keep searching for a matching receiver, + // but remember that this is an empty (unused) slot. + bind(found_null); + } + } + + // In the fall-through case, we found no matching receiver, but we + // observed the receiver[start_row] is NULL. + + // Fill in the receiver field and increment the count. + int recvr_offset = in_bytes(VirtualCallData::receiver_offset(start_row)); + set_mdp_data_at(mdp, recvr_offset, receiver); + int count_offset = in_bytes(VirtualCallData::receiver_count_offset(start_row)); + movl(reg2, DataLayout::counter_increment); + set_mdp_data_at(mdp, count_offset, reg2); + if (start_row > 0) { + jmp(done); + } +} + +// Example state machine code for three profile rows: +// // main copy of decision tree, rooted at row[1] +// if (row[0].rec == rec) { row[0].incr(); goto done; } +// if (row[0].rec != NULL) { +// // inner copy of decision tree, rooted at row[1] +// if (row[1].rec == rec) { row[1].incr(); goto done; } +// if (row[1].rec != NULL) { +// // degenerate decision tree, rooted at row[2] +// if (row[2].rec == rec) { row[2].incr(); goto done; } +// if (row[2].rec != NULL) { count.incr(); goto done; } // overflow +// row[2].init(rec); goto done; +// } else { +// // remember row[1] is empty +// if (row[2].rec == rec) { row[2].incr(); goto done; } +// row[1].init(rec); goto done; +// } +// } else { +// // remember row[0] is empty +// if (row[1].rec == rec) { row[1].incr(); goto done; } +// if (row[2].rec == rec) { row[2].incr(); goto done; } +// row[0].init(rec); goto done; +// } +// done: + +void InterpreterMacroAssembler::record_klass_in_profile(Register receiver, + Register mdp, Register reg2, + bool is_virtual_call) { + assert(ProfileInterpreter, "must be profiling"); + Label done; + + record_klass_in_profile_helper(receiver, mdp, reg2, 0, done, is_virtual_call); + + bind (done); +} + +void InterpreterMacroAssembler::profile_ret(Register return_bci, + Register mdp) { + if (ProfileInterpreter) { + Label profile_continue; + uint row; + + // If no method data exists, go to profile_continue. + test_method_data_pointer(mdp, profile_continue); + + // Update the total ret count. + increment_mdp_data_at(mdp, in_bytes(CounterData::count_offset())); + + for (row = 0; row < RetData::row_limit(); row++) { + Label next_test; + + // See if return_bci is equal to bci[n]: + test_mdp_data_at(mdp, + in_bytes(RetData::bci_offset(row)), + return_bci, noreg, + next_test); + + // return_bci is equal to bci[n]. Increment the count. + increment_mdp_data_at(mdp, in_bytes(RetData::bci_count_offset(row))); + + // The method data pointer needs to be updated to reflect the new target. + update_mdp_by_offset(mdp, + in_bytes(RetData::bci_displacement_offset(row))); + jmp(profile_continue); + bind(next_test); + } + + update_mdp_for_ret(return_bci); + + bind(profile_continue); + } +} + + +void InterpreterMacroAssembler::profile_null_seen(Register mdp) { + if (ProfileInterpreter) { + Label profile_continue; + + // If no method data exists, go to profile_continue. + test_method_data_pointer(mdp, profile_continue); + + set_mdp_flag_at(mdp, BitData::null_seen_byte_constant()); + + // The method data pointer needs to be updated. + int mdp_delta = in_bytes(BitData::bit_data_size()); + if (TypeProfileCasts) { + mdp_delta = in_bytes(VirtualCallData::virtual_call_data_size()); + } + update_mdp_by_constant(mdp, mdp_delta); + + bind(profile_continue); + } +} + + +void InterpreterMacroAssembler::profile_typecheck_failed(Register mdp) { + if (ProfileInterpreter && TypeProfileCasts) { + Label profile_continue; + + // If no method data exists, go to profile_continue. + test_method_data_pointer(mdp, profile_continue); + + int count_offset = in_bytes(CounterData::count_offset()); + // Back up the address, since we have already bumped the mdp. + count_offset -= in_bytes(VirtualCallData::virtual_call_data_size()); + + // *Decrement* the counter. We expect to see zero or small negatives. + increment_mdp_data_at(mdp, count_offset, true); + + bind (profile_continue); + } +} + + +void InterpreterMacroAssembler::profile_typecheck(Register mdp, Register klass, Register reg2) { + if (ProfileInterpreter) { + Label profile_continue; + + // If no method data exists, go to profile_continue. + test_method_data_pointer(mdp, profile_continue); + + // The method data pointer needs to be updated. + int mdp_delta = in_bytes(BitData::bit_data_size()); + if (TypeProfileCasts) { + mdp_delta = in_bytes(VirtualCallData::virtual_call_data_size()); + + // Record the object type. + record_klass_in_profile(klass, mdp, reg2, false); + NOT_LP64(assert(reg2 == rdi, "we know how to fix this blown reg");) + NOT_LP64(restore_locals();) // Restore EDI + } + update_mdp_by_constant(mdp, mdp_delta); + + bind(profile_continue); + } +} + + +void InterpreterMacroAssembler::profile_switch_default(Register mdp) { + if (ProfileInterpreter) { + Label profile_continue; + + // If no method data exists, go to profile_continue. + test_method_data_pointer(mdp, profile_continue); + + // Update the default case count + increment_mdp_data_at(mdp, + in_bytes(MultiBranchData::default_count_offset())); + + // The method data pointer needs to be updated. + update_mdp_by_offset(mdp, + in_bytes(MultiBranchData:: + default_displacement_offset())); + + bind(profile_continue); + } +} + + +void InterpreterMacroAssembler::profile_switch_case(Register index, + Register mdp, + Register reg2) { + if (ProfileInterpreter) { + Label profile_continue; + + // If no method data exists, go to profile_continue. + test_method_data_pointer(mdp, profile_continue); + + // Build the base (index * per_case_size_in_bytes()) + + // case_array_offset_in_bytes() + movl(reg2, in_bytes(MultiBranchData::per_case_size())); + imulptr(index, reg2); // XXX l ? + addptr(index, in_bytes(MultiBranchData::case_array_offset())); // XXX l ? + + // Update the case count + increment_mdp_data_at(mdp, + index, + in_bytes(MultiBranchData::relative_count_offset())); + + // The method data pointer needs to be updated. + update_mdp_by_offset(mdp, + index, + in_bytes(MultiBranchData:: + relative_displacement_offset())); + + bind(profile_continue); + } +} + + + +void InterpreterMacroAssembler::verify_oop(Register reg, TosState state) { + if (state == atos) { + MacroAssembler::verify_oop(reg); + } +} + +void InterpreterMacroAssembler::verify_FPU(int stack_depth, TosState state) { +#ifndef _LP64 + if (state == ftos || state == dtos) MacroAssembler::verify_FPU(stack_depth); +#endif +} + +// Jump if ((*counter_addr += increment) & mask) satisfies the condition. +void InterpreterMacroAssembler::increment_mask_and_jump(Address counter_addr, + int increment, Address mask, + Register scratch, bool preloaded, + Condition cond, Label* where) { + if (!preloaded) { + movl(scratch, counter_addr); + } + incrementl(scratch, increment); + movl(counter_addr, scratch); + andl(scratch, mask); + jcc(cond, *where); +} +#endif // CC_INTERP + +void InterpreterMacroAssembler::notify_method_entry() { + // Whenever JVMTI is interp_only_mode, method entry/exit events are sent to + // track stack depth. If it is possible to enter interp_only_mode we add + // the code to check if the event should be sent. + Register rthread = LP64_ONLY(r15_thread) NOT_LP64(rcx); + Register rarg = LP64_ONLY(c_rarg1) NOT_LP64(rbx); + if (JvmtiExport::can_post_interpreter_events()) { + Label L; + NOT_LP64(get_thread(rthread);) + movl(rdx, Address(rthread, JavaThread::interp_only_mode_offset())); + testl(rdx, rdx); + jcc(Assembler::zero, L); + call_VM(noreg, CAST_FROM_FN_PTR(address, + InterpreterRuntime::post_method_entry)); + bind(L); + } + + { + SkipIfEqual skip(this, &DTraceMethodProbes, false); + NOT_LP64(get_thread(rthread);) + get_method(rarg); + call_VM_leaf(CAST_FROM_FN_PTR(address, SharedRuntime::dtrace_method_entry), + rthread, rarg); + } + + // RedefineClasses() tracing support for obsolete method entry + if (RC_TRACE_IN_RANGE(0x00001000, 0x00002000)) { + NOT_LP64(get_thread(rthread);) + get_method(rarg); + call_VM_leaf( + CAST_FROM_FN_PTR(address, SharedRuntime::rc_trace_method_entry), + rthread, rarg); + } +} + + +void InterpreterMacroAssembler::notify_method_exit( + TosState state, NotifyMethodExitMode mode) { + // Whenever JVMTI is interp_only_mode, method entry/exit events are sent to + // track stack depth. If it is possible to enter interp_only_mode we add + // the code to check if the event should be sent. + Register rthread = LP64_ONLY(r15_thread) NOT_LP64(rcx); + Register rarg = LP64_ONLY(c_rarg1) NOT_LP64(rbx); + if (mode == NotifyJVMTI && JvmtiExport::can_post_interpreter_events()) { + Label L; + // Note: frame::interpreter_frame_result has a dependency on how the + // method result is saved across the call to post_method_exit. If this + // is changed then the interpreter_frame_result implementation will + // need to be updated too. + + // For c++ interpreter the result is always stored at a known location in the frame + // template interpreter will leave it on the top of the stack. + NOT_CC_INTERP(push(state);) + NOT_LP64(get_thread(rthread);) + movl(rdx, Address(rthread, JavaThread::interp_only_mode_offset())); + testl(rdx, rdx); + jcc(Assembler::zero, L); + call_VM(noreg, + CAST_FROM_FN_PTR(address, InterpreterRuntime::post_method_exit)); + bind(L); + NOT_CC_INTERP(pop(state)); + } + + { + SkipIfEqual skip(this, &DTraceMethodProbes, false); + NOT_CC_INTERP(push(state)); + NOT_LP64(get_thread(rthread);) + get_method(rarg); + call_VM_leaf(CAST_FROM_FN_PTR(address, SharedRuntime::dtrace_method_exit), + rthread, rarg); + NOT_CC_INTERP(pop(state)); + } +} diff -r 8c1cc431f388 -r 889895365eb9 hotspot/src/cpu/x86/vm/interp_masm_x86.hpp --- a/hotspot/src/cpu/x86/vm/interp_masm_x86.hpp Fri Mar 20 17:39:29 2015 +0000 +++ b/hotspot/src/cpu/x86/vm/interp_masm_x86.hpp Mon Mar 23 11:44:41 2015 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2015, 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 @@ -35,12 +35,254 @@ class InterpreterMacroAssembler: public MacroAssembler { -#ifdef TARGET_ARCH_MODEL_x86_32 -# include "interp_masm_x86_32.hpp" -#endif -#ifdef TARGET_ARCH_MODEL_x86_64 -# include "interp_masm_x86_64.hpp" -#endif +#ifndef CC_INTERP + protected: + // Interpreter specific version of call_VM_base + virtual void call_VM_leaf_base(address entry_point, + int number_of_arguments); + + virtual void call_VM_base(Register oop_result, + Register java_thread, + Register last_java_sp, + address entry_point, + int number_of_arguments, + bool check_exceptions); + + virtual void check_and_handle_popframe(Register java_thread); + virtual void check_and_handle_earlyret(Register java_thread); + + // base routine for all dispatches + void dispatch_base(TosState state, address* table, bool verifyoop = true); +#endif // CC_INTERP + + public: + InterpreterMacroAssembler(CodeBuffer* code) : MacroAssembler(code), + _locals_register(LP64_ONLY(r14) NOT_LP64(rdi)), + _bcp_register(LP64_ONLY(r13) NOT_LP64(rsi)) {} + + void load_earlyret_value(TosState state); + +#ifdef CC_INTERP + void save_bcp() { /* not needed in c++ interpreter and harmless */ } + void restore_bcp() { /* not needed in c++ interpreter and harmless */ } + + // Helpers for runtime call arguments/results + void get_method(Register reg); + +#else + + // Interpreter-specific registers + void save_bcp() { + movptr(Address(rbp, frame::interpreter_frame_bcp_offset * wordSize), _bcp_register); + } + + void restore_bcp() { + movptr(_bcp_register, Address(rbp, frame::interpreter_frame_bcp_offset * wordSize)); + } + + void restore_locals() { + movptr(_locals_register, Address(rbp, frame::interpreter_frame_locals_offset * wordSize)); + } + + // Helpers for runtime call arguments/results + void get_method(Register reg) { + movptr(reg, Address(rbp, frame::interpreter_frame_method_offset * wordSize)); + } + + void get_const(Register reg) { + get_method(reg); + movptr(reg, Address(reg, Method::const_offset())); + } + + void get_constant_pool(Register reg) { + get_const(reg); + movptr(reg, Address(reg, ConstMethod::constants_offset())); + } + + void get_constant_pool_cache(Register reg) { + get_constant_pool(reg); + movptr(reg, Address(reg, ConstantPool::cache_offset_in_bytes())); + } + + void get_cpool_and_tags(Register cpool, Register tags) { + get_constant_pool(cpool); + movptr(tags, Address(cpool, ConstantPool::tags_offset_in_bytes())); + } + + void get_unsigned_2_byte_index_at_bcp(Register reg, int bcp_offset); + void get_cache_and_index_at_bcp(Register cache, + Register index, + int bcp_offset, + size_t index_size = sizeof(u2)); + void get_cache_and_index_and_bytecode_at_bcp(Register cache, + Register index, + Register bytecode, + int byte_no, + int bcp_offset, + size_t index_size = sizeof(u2)); + void get_cache_entry_pointer_at_bcp(Register cache, + Register tmp, + int bcp_offset, + size_t index_size = sizeof(u2)); + void get_cache_index_at_bcp(Register index, + int bcp_offset, + size_t index_size = sizeof(u2)); + + // load cpool->resolved_references(index); + void load_resolved_reference_at_index(Register result, Register index); + + NOT_LP64(void f2ieee();) // truncate ftos to 32bits + NOT_LP64(void d2ieee();) // truncate dtos to 64bits + + // Expression stack + void pop_ptr(Register r = rax); + void pop_i(Register r = rax); + void push_ptr(Register r = rax); + void push_i(Register r = rax); + +#ifdef _LP64 + void pop_l(Register r = rax); + void pop_f(XMMRegister r = xmm0); + void pop_d(XMMRegister r = xmm0); + void push_l(Register r = rax); + void push_f(XMMRegister r = xmm0); + void push_d(XMMRegister r = xmm0); +#else + void pop_l(Register lo = rax, Register hi = rdx); + void pop_f(); + void pop_d(); + + void push_l(Register lo = rax, Register hi = rdx); + void push_d(Register r = rax); + void push_f(); +#endif // _LP64 + + void pop(Register r) { ((MacroAssembler*)this)->pop(r); } + void push(Register r) { ((MacroAssembler*)this)->push(r); } + void push(int32_t imm ) { ((MacroAssembler*)this)->push(imm); } + + void pop(TosState state); // transition vtos -> state + void push(TosState state); // transition state -> vtos + + // These are dummies to prevent surprise implicit conversions to Register + void pop(void* v); // Add unimplemented ambiguous method + void push(void* v); // Add unimplemented ambiguous method + + void empty_expression_stack() { + movptr(rsp, Address(rbp, frame::interpreter_frame_monitor_block_top_offset * wordSize)); + // NULL last_sp until next java call + movptr(Address(rbp, frame::interpreter_frame_last_sp_offset * wordSize), (int32_t)NULL_WORD); + } + + // Helpers for swap and dup + void load_ptr(int n, Register val); + void store_ptr(int n, Register val); + + // Generate a subtype check: branch to ok_is_subtype if sub_klass is + // a subtype of super_klass. + void gen_subtype_check( Register sub_klass, Label &ok_is_subtype ); + + // Dispatching + void dispatch_prolog(TosState state, int step = 0); + void dispatch_epilog(TosState state, int step = 0); + // dispatch via rbx (assume rbx is loaded already) + void dispatch_only(TosState state); + // dispatch normal table via rbx (assume rbx is loaded already) + void dispatch_only_normal(TosState state); + void dispatch_only_noverify(TosState state); + // load rbx from [_bcp_register + step] and dispatch via rbx + void dispatch_next(TosState state, int step = 0); + // load rbx from [_bcp_register] and dispatch via rbx and table + void dispatch_via (TosState state, address* table); + + // jump to an invoked target + void prepare_to_jump_from_interpreted(); + void jump_from_interpreted(Register method, Register temp); + + // Returning from interpreted functions + // + // Removes the current activation (incl. unlocking of monitors) + // and sets up the return address. This code is also used for + // exception unwindwing. In that case, we do not want to throw + // IllegalMonitorStateExceptions, since that might get us into an + // infinite rethrow exception loop. + // Additionally this code is used for popFrame and earlyReturn. + // In popFrame case we want to skip throwing an exception, + // installing an exception, and notifying jvmdi. + // In earlyReturn case we only want to skip throwing an exception + // and installing an exception. + void remove_activation(TosState state, Register ret_addr, + bool throw_monitor_exception = true, + bool install_monitor_exception = true, + bool notify_jvmdi = true); +#endif // CC_INTERP + void get_method_counters(Register method, Register mcs, Label& skip); + + // Object locking + void lock_object (Register lock_reg); + void unlock_object(Register lock_reg); + +#ifndef CC_INTERP + + // Interpreter profiling operations + void set_method_data_pointer_for_bcp(); + void test_method_data_pointer(Register mdp, Label& zero_continue); + void verify_method_data_pointer(); + + void set_mdp_data_at(Register mdp_in, int constant, Register value); + void increment_mdp_data_at(Address data, bool decrement = false); + void increment_mdp_data_at(Register mdp_in, int constant, + bool decrement = false); + void increment_mdp_data_at(Register mdp_in, Register reg, int constant, + bool decrement = false); + void increment_mask_and_jump(Address counter_addr, + int increment, Address mask, + Register scratch, bool preloaded, + Condition cond, Label* where); + void set_mdp_flag_at(Register mdp_in, int flag_constant); + void test_mdp_data_at(Register mdp_in, int offset, Register value, + Register test_value_out, + Label& not_equal_continue); + + void record_klass_in_profile(Register receiver, Register mdp, + Register reg2, bool is_virtual_call); + void record_klass_in_profile_helper(Register receiver, Register mdp, + Register reg2, int start_row, + Label& done, bool is_virtual_call); + + void update_mdp_by_offset(Register mdp_in, int offset_of_offset); + void update_mdp_by_offset(Register mdp_in, Register reg, int offset_of_disp); + void update_mdp_by_constant(Register mdp_in, int constant); + void update_mdp_for_ret(Register return_bci); + + void profile_taken_branch(Register mdp, Register bumped_count); + void profile_not_taken_branch(Register mdp); + void profile_call(Register mdp); + void profile_final_call(Register mdp); + void profile_virtual_call(Register receiver, Register mdp, + Register scratch2, + bool receiver_can_be_null = false); + void profile_ret(Register return_bci, Register mdp); + void profile_null_seen(Register mdp); + void profile_typecheck(Register mdp, Register klass, Register scratch); + void profile_typecheck_failed(Register mdp); + void profile_switch_default(Register mdp); + void profile_switch_case(Register index_in_scratch, Register mdp, + Register scratch2); + + // Debugging + // only if +VerifyOops && state == atos + void verify_oop(Register reg, TosState state = atos); + // only if +VerifyFPU && (state == ftos || state == dtos) + void verify_FPU(int stack_depth, TosState state = ftos); + +#endif // !CC_INTERP + + typedef enum { NotifyJVMTI, SkipNotifyJVMTI } NotifyMethodExitMode; + + // support for jvmti/dtrace + void notify_method_entry(); + void notify_method_exit(TosState state, NotifyMethodExitMode mode); private: diff -r 8c1cc431f388 -r 889895365eb9 hotspot/src/cpu/x86/vm/interp_masm_x86_32.cpp --- a/hotspot/src/cpu/x86/vm/interp_masm_x86_32.cpp Fri Mar 20 17:39:29 2015 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,1444 +0,0 @@ -/* - * Copyright (c) 1997, 2014, 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. - * - */ - -#include "precompiled.hpp" -#include "interp_masm_x86.hpp" -#include "interpreter/interpreter.hpp" -#include "interpreter/interpreterRuntime.hpp" -#include "oops/arrayOop.hpp" -#include "oops/markOop.hpp" -#include "oops/methodData.hpp" -#include "oops/method.hpp" -#include "prims/jvmtiExport.hpp" -#include "prims/jvmtiRedefineClassesTrace.hpp" -#include "prims/jvmtiThreadState.hpp" -#include "runtime/basicLock.hpp" -#include "runtime/biasedLocking.hpp" -#include "runtime/sharedRuntime.hpp" -#include "runtime/thread.inline.hpp" - - -// Implementation of InterpreterMacroAssembler -#ifdef CC_INTERP -void InterpreterMacroAssembler::get_method(Register reg) { - movptr(reg, Address(rbp, -(sizeof(BytecodeInterpreter) + 2 * wordSize))); - movptr(reg, Address(reg, byte_offset_of(BytecodeInterpreter, _method))); -} -#endif // CC_INTERP - - -#ifndef CC_INTERP -void InterpreterMacroAssembler::call_VM_leaf_base( - address entry_point, - int number_of_arguments -) { - // interpreter specific - // - // Note: No need to save/restore bcp & locals (rsi & rdi) pointer - // since these are callee saved registers and no blocking/ - // GC can happen in leaf calls. - // Further Note: DO NOT save/restore bcp/locals. If a caller has - // already saved them so that it can use rsi/rdi as temporaries - // then a save/restore here will DESTROY the copy the caller - // saved! There used to be a save_bcp() that only happened in - // the ASSERT path (no restore_bcp). Which caused bizarre failures - // when jvm built with ASSERTs. -#ifdef ASSERT - { Label L; - cmpptr(Address(rbp, frame::interpreter_frame_last_sp_offset * wordSize), (int32_t)NULL_WORD); - jcc(Assembler::equal, L); - stop("InterpreterMacroAssembler::call_VM_leaf_base: last_sp != NULL"); - bind(L); - } -#endif - // super call - MacroAssembler::call_VM_leaf_base(entry_point, number_of_arguments); - // interpreter specific - - // Used to ASSERT that rsi/rdi were equal to frame's bcp/locals - // but since they may not have been saved (and we don't want to - // save them here (see note above) the assert is invalid. -} - - -void InterpreterMacroAssembler::call_VM_base( - Register oop_result, - Register java_thread, - Register last_java_sp, - address entry_point, - int number_of_arguments, - bool check_exceptions -) { -#ifdef ASSERT - { Label L; - cmpptr(Address(rbp, frame::interpreter_frame_last_sp_offset * wordSize), (int32_t)NULL_WORD); - jcc(Assembler::equal, L); - stop("InterpreterMacroAssembler::call_VM_base: last_sp != NULL"); - bind(L); - } -#endif /* ASSERT */ - // interpreter specific - // - // Note: Could avoid restoring locals ptr (callee saved) - however doesn't - // really make a difference for these runtime calls, since they are - // slow anyway. Btw., bcp must be saved/restored since it may change - // due to GC. - assert(java_thread == noreg , "not expecting a precomputed java thread"); - save_bcp(); - // super call - MacroAssembler::call_VM_base(oop_result, java_thread, last_java_sp, entry_point, number_of_arguments, check_exceptions); - // interpreter specific - restore_bcp(); - restore_locals(); -} - - -void InterpreterMacroAssembler::check_and_handle_popframe(Register java_thread) { - if (JvmtiExport::can_pop_frame()) { - Label L; - // Initiate popframe handling only if it is not already being processed. If the flag - // has the popframe_processing bit set, it means that this code is called *during* popframe - // handling - we don't want to reenter. - Register pop_cond = java_thread; // Not clear if any other register is available... - movl(pop_cond, Address(java_thread, JavaThread::popframe_condition_offset())); - testl(pop_cond, JavaThread::popframe_pending_bit); - jcc(Assembler::zero, L); - testl(pop_cond, JavaThread::popframe_processing_bit); - jcc(Assembler::notZero, L); - // Call Interpreter::remove_activation_preserving_args_entry() to get the - // address of the same-named entrypoint in the generated interpreter code. - call_VM_leaf(CAST_FROM_FN_PTR(address, Interpreter::remove_activation_preserving_args_entry)); - jmp(rax); - bind(L); - get_thread(java_thread); - } -} - - -void InterpreterMacroAssembler::load_earlyret_value(TosState state) { - get_thread(rcx); - movl(rcx, Address(rcx, JavaThread::jvmti_thread_state_offset())); - const Address tos_addr (rcx, JvmtiThreadState::earlyret_tos_offset()); - const Address oop_addr (rcx, JvmtiThreadState::earlyret_oop_offset()); - const Address val_addr (rcx, JvmtiThreadState::earlyret_value_offset()); - const Address val_addr1(rcx, JvmtiThreadState::earlyret_value_offset() - + in_ByteSize(wordSize)); - switch (state) { - case atos: movptr(rax, oop_addr); - movptr(oop_addr, NULL_WORD); - verify_oop(rax, state); break; - case ltos: - movl(rdx, val_addr1); // fall through - case btos: // fall through - case ctos: // fall through - case stos: // fall through - case itos: movl(rax, val_addr); break; - case ftos: fld_s(val_addr); break; - case dtos: fld_d(val_addr); break; - case vtos: /* nothing to do */ break; - default : ShouldNotReachHere(); - } - // Clean up tos value in the thread object - movl(tos_addr, (int32_t) ilgl); - movptr(val_addr, NULL_WORD); - NOT_LP64(movptr(val_addr1, NULL_WORD)); -} - - -void InterpreterMacroAssembler::check_and_handle_earlyret(Register java_thread) { - if (JvmtiExport::can_force_early_return()) { - Label L; - Register tmp = java_thread; - movptr(tmp, Address(tmp, JavaThread::jvmti_thread_state_offset())); - testptr(tmp, tmp); - jcc(Assembler::zero, L); // if (thread->jvmti_thread_state() == NULL) exit; - - // Initiate earlyret handling only if it is not already being processed. - // If the flag has the earlyret_processing bit set, it means that this code - // is called *during* earlyret handling - we don't want to reenter. - movl(tmp, Address(tmp, JvmtiThreadState::earlyret_state_offset())); - cmpl(tmp, JvmtiThreadState::earlyret_pending); - jcc(Assembler::notEqual, L); - - // Call Interpreter::remove_activation_early_entry() to get the address of the - // same-named entrypoint in the generated interpreter code. - get_thread(java_thread); - movptr(tmp, Address(java_thread, JavaThread::jvmti_thread_state_offset())); - pushl(Address(tmp, JvmtiThreadState::earlyret_tos_offset())); - call_VM_leaf(CAST_FROM_FN_PTR(address, Interpreter::remove_activation_early_entry), 1); - jmp(rax); - bind(L); - get_thread(java_thread); - } -} - - -void InterpreterMacroAssembler::get_unsigned_2_byte_index_at_bcp(Register reg, int bcp_offset) { - assert(bcp_offset >= 0, "bcp is still pointing to start of bytecode"); - load_unsigned_short(reg, Address(rsi, bcp_offset)); - bswapl(reg); - shrl(reg, 16); -} - - -void InterpreterMacroAssembler::get_cache_index_at_bcp(Register reg, int bcp_offset, size_t index_size) { - assert(bcp_offset > 0, "bcp is still pointing to start of bytecode"); - if (index_size == sizeof(u2)) { - load_unsigned_short(reg, Address(rsi, bcp_offset)); - } else if (index_size == sizeof(u4)) { - movl(reg, Address(rsi, bcp_offset)); - // Check if the secondary index definition is still ~x, otherwise - // we have to change the following assembler code to calculate the - // plain index. - assert(ConstantPool::decode_invokedynamic_index(~123) == 123, "else change next line"); - notl(reg); // convert to plain index - } else if (index_size == sizeof(u1)) { - load_unsigned_byte(reg, Address(rsi, bcp_offset)); - } else { - ShouldNotReachHere(); - } -} - - -void InterpreterMacroAssembler::get_cache_and_index_at_bcp(Register cache, Register index, - int bcp_offset, size_t index_size) { - assert_different_registers(cache, index); - get_cache_index_at_bcp(index, bcp_offset, index_size); - movptr(cache, Address(rbp, frame::interpreter_frame_cache_offset * wordSize)); - assert(sizeof(ConstantPoolCacheEntry) == 4*wordSize, "adjust code below"); - assert(exact_log2(in_words(ConstantPoolCacheEntry::size())) == 2, "else change next line"); - shlptr(index, 2); // convert from field index to ConstantPoolCacheEntry index -} - - -void InterpreterMacroAssembler::get_cache_and_index_and_bytecode_at_bcp(Register cache, - Register index, - Register bytecode, - int byte_no, - int bcp_offset, - size_t index_size) { - get_cache_and_index_at_bcp(cache, index, bcp_offset, index_size); - movptr(bytecode, Address(cache, index, Address::times_ptr, ConstantPoolCache::base_offset() + ConstantPoolCacheEntry::indices_offset())); - const int shift_count = (1 + byte_no) * BitsPerByte; - assert((byte_no == TemplateTable::f1_byte && shift_count == ConstantPoolCacheEntry::bytecode_1_shift) || - (byte_no == TemplateTable::f2_byte && shift_count == ConstantPoolCacheEntry::bytecode_2_shift), - "correct shift count"); - shrptr(bytecode, shift_count); - assert(ConstantPoolCacheEntry::bytecode_1_mask == ConstantPoolCacheEntry::bytecode_2_mask, "common mask"); - andptr(bytecode, ConstantPoolCacheEntry::bytecode_1_mask); -} - - -void InterpreterMacroAssembler::get_cache_entry_pointer_at_bcp(Register cache, Register tmp, - int bcp_offset, size_t index_size) { - assert(cache != tmp, "must use different register"); - get_cache_index_at_bcp(tmp, bcp_offset, index_size); - assert(sizeof(ConstantPoolCacheEntry) == 4*wordSize, "adjust code below"); - // convert from field index to ConstantPoolCacheEntry index - // and from word offset to byte offset - assert(exact_log2(in_bytes(ConstantPoolCacheEntry::size_in_bytes())) == 2 + LogBytesPerWord, "else change next line"); - shll(tmp, 2 + LogBytesPerWord); - movptr(cache, Address(rbp, frame::interpreter_frame_cache_offset * wordSize)); - // skip past the header - addptr(cache, in_bytes(ConstantPoolCache::base_offset())); - addptr(cache, tmp); // construct pointer to cache entry -} - -// Load object from cpool->resolved_references(index) -void InterpreterMacroAssembler::load_resolved_reference_at_index( - Register result, Register index) { - assert_different_registers(result, index); - // convert from field index to resolved_references() index and from - // word index to byte offset. Since this is a java object, it can be compressed - Register tmp = index; // reuse - shll(tmp, LogBytesPerHeapOop); - - get_constant_pool(result); - // load pointer for resolved_references[] objArray - movptr(result, Address(result, ConstantPool::resolved_references_offset_in_bytes())); - // JNIHandles::resolve(obj); - movptr(result, Address(result, 0)); - // Add in the index - addptr(result, tmp); - load_heap_oop(result, Address(result, arrayOopDesc::base_offset_in_bytes(T_OBJECT))); -} - - // Generate a subtype check: branch to ok_is_subtype if sub_klass is - // a subtype of super_klass. EAX holds the super_klass. Blows ECX. - // Resets EDI to locals. Register sub_klass cannot be any of the above. -void InterpreterMacroAssembler::gen_subtype_check( Register Rsub_klass, Label &ok_is_subtype ) { - assert( Rsub_klass != rax, "rax, holds superklass" ); - assert( Rsub_klass != rcx, "used as a temp" ); - assert( Rsub_klass != rdi, "used as a temp, restored from locals" ); - - // Profile the not-null value's klass. - profile_typecheck(rcx, Rsub_klass, rdi); // blows rcx, reloads rdi - - // Do the check. - check_klass_subtype(Rsub_klass, rax, rcx, ok_is_subtype); // blows rcx - - // Profile the failure of the check. - profile_typecheck_failed(rcx); // blows rcx -} - -void InterpreterMacroAssembler::f2ieee() { - if (IEEEPrecision) { - fstp_s(Address(rsp, 0)); - fld_s(Address(rsp, 0)); - } -} - - -void InterpreterMacroAssembler::d2ieee() { - if (IEEEPrecision) { - fstp_d(Address(rsp, 0)); - fld_d(Address(rsp, 0)); - } -} - -// Java Expression Stack - -void InterpreterMacroAssembler::pop_ptr(Register r) { - pop(r); -} - -void InterpreterMacroAssembler::pop_i(Register r) { - pop(r); -} - -void InterpreterMacroAssembler::pop_l(Register lo, Register hi) { - pop(lo); - pop(hi); -} - -void InterpreterMacroAssembler::pop_f() { - fld_s(Address(rsp, 0)); - addptr(rsp, 1 * wordSize); -} - -void InterpreterMacroAssembler::pop_d() { - fld_d(Address(rsp, 0)); - addptr(rsp, 2 * wordSize); -} - - -void InterpreterMacroAssembler::pop(TosState state) { - switch (state) { - case atos: pop_ptr(rax); break; - case btos: // fall through - case ctos: // fall through - case stos: // fall through - case itos: pop_i(rax); break; - case ltos: pop_l(rax, rdx); break; - case ftos: pop_f(); break; - case dtos: pop_d(); break; - case vtos: /* nothing to do */ break; - default : ShouldNotReachHere(); - } - verify_oop(rax, state); -} - -void InterpreterMacroAssembler::push_ptr(Register r) { - push(r); -} - -void InterpreterMacroAssembler::push_i(Register r) { - push(r); -} - -void InterpreterMacroAssembler::push_l(Register lo, Register hi) { - push(hi); - push(lo); -} - -void InterpreterMacroAssembler::push_f() { - // Do not schedule for no AGI! Never write beyond rsp! - subptr(rsp, 1 * wordSize); - fstp_s(Address(rsp, 0)); -} - -void InterpreterMacroAssembler::push_d(Register r) { - // Do not schedule for no AGI! Never write beyond rsp! - subptr(rsp, 2 * wordSize); - fstp_d(Address(rsp, 0)); -} - - -void InterpreterMacroAssembler::push(TosState state) { - verify_oop(rax, state); - switch (state) { - case atos: push_ptr(rax); break; - case btos: // fall through - case ctos: // fall through - case stos: // fall through - case itos: push_i(rax); break; - case ltos: push_l(rax, rdx); break; - case ftos: push_f(); break; - case dtos: push_d(rax); break; - case vtos: /* nothing to do */ break; - default : ShouldNotReachHere(); - } -} - - -// Helpers for swap and dup -void InterpreterMacroAssembler::load_ptr(int n, Register val) { - movptr(val, Address(rsp, Interpreter::expr_offset_in_bytes(n))); -} - -void InterpreterMacroAssembler::store_ptr(int n, Register val) { - movptr(Address(rsp, Interpreter::expr_offset_in_bytes(n)), val); -} - -void InterpreterMacroAssembler::prepare_to_jump_from_interpreted() { - // set sender sp - lea(rsi, Address(rsp, wordSize)); - // record last_sp - movptr(Address(rbp, frame::interpreter_frame_last_sp_offset * wordSize), rsi); -} - - -// Jump to from_interpreted entry of a call unless single stepping is possible -// in this thread in which case we must call the i2i entry -void InterpreterMacroAssembler::jump_from_interpreted(Register method, Register temp) { - prepare_to_jump_from_interpreted(); - - if (JvmtiExport::can_post_interpreter_events()) { - Label run_compiled_code; - // JVMTI events, such as single-stepping, are implemented partly by avoiding running - // compiled code in threads for which the event is enabled. Check here for - // interp_only_mode if these events CAN be enabled. - get_thread(temp); - // interp_only is an int, on little endian it is sufficient to test the byte only - // Is a cmpl faster? - cmpb(Address(temp, JavaThread::interp_only_mode_offset()), 0); - jccb(Assembler::zero, run_compiled_code); - jmp(Address(method, Method::interpreter_entry_offset())); - bind(run_compiled_code); - } - - jmp(Address(method, Method::from_interpreted_offset())); - -} - - -// The following two routines provide a hook so that an implementation -// can schedule the dispatch in two parts. Intel does not do this. -void InterpreterMacroAssembler::dispatch_prolog(TosState state, int step) { - // Nothing Intel-specific to be done here. -} - -void InterpreterMacroAssembler::dispatch_epilog(TosState state, int step) { - dispatch_next(state, step); -} - -void InterpreterMacroAssembler::dispatch_base(TosState state, address* table, - bool verifyoop) { - verify_FPU(1, state); - if (VerifyActivationFrameSize) { - Label L; - mov(rcx, rbp); - subptr(rcx, rsp); - int min_frame_size = (frame::link_offset - frame::interpreter_frame_initial_sp_offset) * wordSize; - cmpptr(rcx, min_frame_size); - jcc(Assembler::greaterEqual, L); - stop("broken stack frame"); - bind(L); - } - if (verifyoop) verify_oop(rax, state); - Address index(noreg, rbx, Address::times_ptr); - ExternalAddress tbl((address)table); - ArrayAddress dispatch(tbl, index); - jump(dispatch); -} - - -void InterpreterMacroAssembler::dispatch_only(TosState state) { - dispatch_base(state, Interpreter::dispatch_table(state)); -} - - -void InterpreterMacroAssembler::dispatch_only_normal(TosState state) { - dispatch_base(state, Interpreter::normal_table(state)); -} - -void InterpreterMacroAssembler::dispatch_only_noverify(TosState state) { - dispatch_base(state, Interpreter::normal_table(state), false); -} - - -void InterpreterMacroAssembler::dispatch_next(TosState state, int step) { - // load next bytecode (load before advancing rsi to prevent AGI) - load_unsigned_byte(rbx, Address(rsi, step)); - // advance rsi - increment(rsi, step); - dispatch_base(state, Interpreter::dispatch_table(state)); -} - - -void InterpreterMacroAssembler::dispatch_via(TosState state, address* table) { - // load current bytecode - load_unsigned_byte(rbx, Address(rsi, 0)); - dispatch_base(state, table); -} - -// remove activation -// -// Unlock the receiver if this is a synchronized method. -// Unlock any Java monitors from syncronized blocks. -// Remove the activation from the stack. -// -// If there are locked Java monitors -// If throw_monitor_exception -// throws IllegalMonitorStateException -// Else if install_monitor_exception -// installs IllegalMonitorStateException -// Else -// no error processing -void InterpreterMacroAssembler::remove_activation(TosState state, Register ret_addr, - bool throw_monitor_exception, - bool install_monitor_exception, - bool notify_jvmdi) { - // Note: Registers rax, rdx and FPU ST(0) may be in use for the result - // check if synchronized method - Label unlocked, unlock, no_unlock; - - get_thread(rcx); - const Address do_not_unlock_if_synchronized(rcx, - in_bytes(JavaThread::do_not_unlock_if_synchronized_offset())); - - movbool(rbx, do_not_unlock_if_synchronized); - mov(rdi,rbx); - movbool(do_not_unlock_if_synchronized, false); // reset the flag - - movptr(rbx, Address(rbp, frame::interpreter_frame_method_offset * wordSize)); // get method access flags - movl(rcx, Address(rbx, Method::access_flags_offset())); - - testl(rcx, JVM_ACC_SYNCHRONIZED); - jcc(Assembler::zero, unlocked); - - // Don't unlock anything if the _do_not_unlock_if_synchronized flag - // is set. - mov(rcx,rdi); - testbool(rcx); - jcc(Assembler::notZero, no_unlock); - - // unlock monitor - push(state); // save result - - // BasicObjectLock will be first in list, since this is a synchronized method. However, need - // to check that the object has not been unlocked by an explicit monitorexit bytecode. - const Address monitor(rbp, frame::interpreter_frame_initial_sp_offset * wordSize - (int)sizeof(BasicObjectLock)); - lea (rdx, monitor); // address of first monitor - - movptr (rax, Address(rdx, BasicObjectLock::obj_offset_in_bytes())); - testptr(rax, rax); - jcc (Assembler::notZero, unlock); - - pop(state); - if (throw_monitor_exception) { - empty_FPU_stack(); // remove possible return value from FPU-stack, otherwise stack could overflow - - // Entry already unlocked, need to throw exception - call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::throw_illegal_monitor_state_exception)); - should_not_reach_here(); - } else { - // Monitor already unlocked during a stack unroll. - // If requested, install an illegal_monitor_state_exception. - // Continue with stack unrolling. - if (install_monitor_exception) { - empty_FPU_stack(); // remove possible return value from FPU-stack, otherwise stack could overflow - call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::new_illegal_monitor_state_exception)); - } - jmp(unlocked); - } - - bind(unlock); - unlock_object(rdx); - pop(state); - - // Check that for block-structured locking (i.e., that all locked objects has been unlocked) - bind(unlocked); - - // rax, rdx: Might contain return value - - // Check that all monitors are unlocked - { - Label loop, exception, entry, restart; - const int entry_size = frame::interpreter_frame_monitor_size() * wordSize; - const Address monitor_block_top(rbp, frame::interpreter_frame_monitor_block_top_offset * wordSize); - const Address monitor_block_bot(rbp, frame::interpreter_frame_initial_sp_offset * wordSize); - - bind(restart); - movptr(rcx, monitor_block_top); // points to current entry, starting with top-most entry - lea(rbx, monitor_block_bot); // points to word before bottom of monitor block - jmp(entry); - - // Entry already locked, need to throw exception - bind(exception); - - if (throw_monitor_exception) { - empty_FPU_stack(); // remove possible return value from FPU-stack, otherwise stack could overflow - - // Throw exception - call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::throw_illegal_monitor_state_exception)); - should_not_reach_here(); - } else { - // Stack unrolling. Unlock object and install illegal_monitor_exception - // Unlock does not block, so don't have to worry about the frame - - push(state); - mov(rdx, rcx); - unlock_object(rdx); - pop(state); - - if (install_monitor_exception) { - empty_FPU_stack(); // remove possible return value from FPU-stack, otherwise stack could overflow - call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::new_illegal_monitor_state_exception)); - } - - jmp(restart); - } - - bind(loop); - cmpptr(Address(rcx, BasicObjectLock::obj_offset_in_bytes()), (int32_t)NULL_WORD); // check if current entry is used - jcc(Assembler::notEqual, exception); - - addptr(rcx, entry_size); // otherwise advance to next entry - bind(entry); - cmpptr(rcx, rbx); // check if bottom reached - jcc(Assembler::notEqual, loop); // if not at bottom then check this entry - } - - bind(no_unlock); - - // jvmti support - if (notify_jvmdi) { - notify_method_exit(state, NotifyJVMTI); // preserve TOSCA - } else { - notify_method_exit(state, SkipNotifyJVMTI); // preserve TOSCA - } - - // remove activation - movptr(rbx, Address(rbp, frame::interpreter_frame_sender_sp_offset * wordSize)); // get sender sp - leave(); // remove frame anchor - pop(ret_addr); // get return address - mov(rsp, rbx); // set sp to sender sp - if (UseSSE) { - // float and double are returned in xmm register in SSE-mode - if (state == ftos && UseSSE >= 1) { - subptr(rsp, wordSize); - fstp_s(Address(rsp, 0)); - movflt(xmm0, Address(rsp, 0)); - addptr(rsp, wordSize); - } else if (state == dtos && UseSSE >= 2) { - subptr(rsp, 2*wordSize); - fstp_d(Address(rsp, 0)); - movdbl(xmm0, Address(rsp, 0)); - addptr(rsp, 2*wordSize); - } - } -} - -#endif /* !CC_INTERP */ - -void InterpreterMacroAssembler::get_method_counters(Register method, - Register mcs, Label& skip) { - Label has_counters; - movptr(mcs, Address(method, Method::method_counters_offset())); - testptr(mcs, mcs); - jcc(Assembler::notZero, has_counters); - call_VM(noreg, CAST_FROM_FN_PTR(address, - InterpreterRuntime::build_method_counters), method); - movptr(mcs, Address(method,Method::method_counters_offset())); - testptr(mcs, mcs); - jcc(Assembler::zero, skip); // No MethodCounters allocated, OutOfMemory - bind(has_counters); -} - - -// Lock object -// -// Argument: rdx : Points to BasicObjectLock to be used for locking. Must -// be initialized with object to lock -void InterpreterMacroAssembler::lock_object(Register lock_reg) { - assert(lock_reg == rdx, "The argument is only for looks. It must be rdx"); - - if (UseHeavyMonitors) { - call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::monitorenter), lock_reg); - } else { - - Label done; - - const Register swap_reg = rax; // Must use rax, for cmpxchg instruction - const Register obj_reg = rcx; // Will contain the oop - - const int obj_offset = BasicObjectLock::obj_offset_in_bytes(); - const int lock_offset = BasicObjectLock::lock_offset_in_bytes (); - const int mark_offset = lock_offset + BasicLock::displaced_header_offset_in_bytes(); - - Label slow_case; - - // Load object pointer into obj_reg %rcx - movptr(obj_reg, Address(lock_reg, obj_offset)); - - if (UseBiasedLocking) { - // Note: we use noreg for the temporary register since it's hard - // to come up with a free register on all incoming code paths - biased_locking_enter(lock_reg, obj_reg, swap_reg, noreg, false, done, &slow_case); - } - - // Load immediate 1 into swap_reg %rax, - movptr(swap_reg, (int32_t)1); - - // Load (object->mark() | 1) into swap_reg %rax, - orptr(swap_reg, Address(obj_reg, 0)); - - // Save (object->mark() | 1) into BasicLock's displaced header - movptr(Address(lock_reg, mark_offset), swap_reg); - - assert(lock_offset == 0, "displached header must be first word in BasicObjectLock"); - if (os::is_MP()) { - lock(); - } - cmpxchgptr(lock_reg, Address(obj_reg, 0)); - if (PrintBiasedLockingStatistics) { - cond_inc32(Assembler::zero, - ExternalAddress((address) BiasedLocking::fast_path_entry_count_addr())); - } - jcc(Assembler::zero, done); - - // Test if the oopMark is an obvious stack pointer, i.e., - // 1) (mark & 3) == 0, and - // 2) rsp <= mark < mark + os::pagesize() - // - // These 3 tests can be done by evaluating the following - // expression: ((mark - rsp) & (3 - os::vm_page_size())), - // assuming both stack pointer and pagesize have their - // least significant 2 bits clear. - // NOTE: the oopMark is in swap_reg %rax, as the result of cmpxchg - subptr(swap_reg, rsp); - andptr(swap_reg, 3 - os::vm_page_size()); - - // Save the test result, for recursive case, the result is zero - movptr(Address(lock_reg, mark_offset), swap_reg); - - if (PrintBiasedLockingStatistics) { - cond_inc32(Assembler::zero, - ExternalAddress((address) BiasedLocking::fast_path_entry_count_addr())); - } - jcc(Assembler::zero, done); - - bind(slow_case); - - // Call the runtime routine for slow case - call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::monitorenter), lock_reg); - - bind(done); - } -} - - -// Unlocks an object. Used in monitorexit bytecode and remove_activation. -// -// Argument: rdx : Points to BasicObjectLock structure for lock -// Throw an IllegalMonitorException if object is not locked by current thread -// -// Uses: rax, rbx, rcx, rdx -void InterpreterMacroAssembler::unlock_object(Register lock_reg) { - assert(lock_reg == rdx, "The argument is only for looks. It must be rdx"); - - if (UseHeavyMonitors) { - call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::monitorexit), lock_reg); - } else { - Label done; - - const Register swap_reg = rax; // Must use rax, for cmpxchg instruction - const Register header_reg = rbx; // Will contain the old oopMark - const Register obj_reg = rcx; // Will contain the oop - - save_bcp(); // Save in case of exception - - // Convert from BasicObjectLock structure to object and BasicLock structure - // Store the BasicLock address into %rax, - lea(swap_reg, Address(lock_reg, BasicObjectLock::lock_offset_in_bytes())); - - // Load oop into obj_reg(%rcx) - movptr(obj_reg, Address(lock_reg, BasicObjectLock::obj_offset_in_bytes ())); - - // Free entry - movptr(Address(lock_reg, BasicObjectLock::obj_offset_in_bytes()), NULL_WORD); - - if (UseBiasedLocking) { - biased_locking_exit(obj_reg, header_reg, done); - } - - // Load the old header from BasicLock structure - movptr(header_reg, Address(swap_reg, BasicLock::displaced_header_offset_in_bytes())); - - // Test for recursion - testptr(header_reg, header_reg); - - // zero for recursive case - jcc(Assembler::zero, done); - - // Atomic swap back the old header - if (os::is_MP()) lock(); - cmpxchgptr(header_reg, Address(obj_reg, 0)); - - // zero for recursive case - jcc(Assembler::zero, done); - - // Call the runtime routine for slow case. - movptr(Address(lock_reg, BasicObjectLock::obj_offset_in_bytes()), obj_reg); // restore obj - call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::monitorexit), lock_reg); - - bind(done); - - restore_bcp(); - } -} - - -#ifndef CC_INTERP - -// Test ImethodDataPtr. If it is null, continue at the specified label -void InterpreterMacroAssembler::test_method_data_pointer(Register mdp, Label& zero_continue) { - assert(ProfileInterpreter, "must be profiling interpreter"); - movptr(mdp, Address(rbp, frame::interpreter_frame_mdp_offset * wordSize)); - testptr(mdp, mdp); - jcc(Assembler::zero, zero_continue); -} - - -// Set the method data pointer for the current bcp. -void InterpreterMacroAssembler::set_method_data_pointer_for_bcp() { - assert(ProfileInterpreter, "must be profiling interpreter"); - Label set_mdp; - push(rax); - push(rbx); - - get_method(rbx); - // Test MDO to avoid the call if it is NULL. - movptr(rax, Address(rbx, in_bytes(Method::method_data_offset()))); - testptr(rax, rax); - jcc(Assembler::zero, set_mdp); - // rbx,: method - // rsi: bcp - call_VM_leaf(CAST_FROM_FN_PTR(address, InterpreterRuntime::bcp_to_di), rbx, rsi); - // rax,: mdi - // mdo is guaranteed to be non-zero here, we checked for it before the call. - movptr(rbx, Address(rbx, in_bytes(Method::method_data_offset()))); - addptr(rbx, in_bytes(MethodData::data_offset())); - addptr(rax, rbx); - bind(set_mdp); - movptr(Address(rbp, frame::interpreter_frame_mdp_offset * wordSize), rax); - pop(rbx); - pop(rax); -} - -void InterpreterMacroAssembler::verify_method_data_pointer() { - assert(ProfileInterpreter, "must be profiling interpreter"); -#ifdef ASSERT - Label verify_continue; - push(rax); - push(rbx); - push(rcx); - push(rdx); - test_method_data_pointer(rcx, verify_continue); // If mdp is zero, continue - get_method(rbx); - - // If the mdp is valid, it will point to a DataLayout header which is - // consistent with the bcp. The converse is highly probable also. - load_unsigned_short(rdx, Address(rcx, in_bytes(DataLayout::bci_offset()))); - addptr(rdx, Address(rbx, Method::const_offset())); - lea(rdx, Address(rdx, ConstMethod::codes_offset())); - cmpptr(rdx, rsi); - jcc(Assembler::equal, verify_continue); - // rbx,: method - // rsi: bcp - // rcx: mdp - call_VM_leaf(CAST_FROM_FN_PTR(address, InterpreterRuntime::verify_mdp), rbx, rsi, rcx); - bind(verify_continue); - pop(rdx); - pop(rcx); - pop(rbx); - pop(rax); -#endif // ASSERT -} - - -void InterpreterMacroAssembler::set_mdp_data_at(Register mdp_in, int constant, Register value) { - // %%% this seems to be used to store counter data which is surely 32bits - // however 64bit side stores 64 bits which seems wrong - assert(ProfileInterpreter, "must be profiling interpreter"); - Address data(mdp_in, constant); - movptr(data, value); -} - - -void InterpreterMacroAssembler::increment_mdp_data_at(Register mdp_in, - int constant, - bool decrement) { - // Counter address - Address data(mdp_in, constant); - - increment_mdp_data_at(data, decrement); -} - - -void InterpreterMacroAssembler::increment_mdp_data_at(Address data, - bool decrement) { - - assert( DataLayout::counter_increment==1, "flow-free idiom only works with 1" ); - assert(ProfileInterpreter, "must be profiling interpreter"); - - // %%% 64bit treats this as 64 bit which seems unlikely - if (decrement) { - // Decrement the register. Set condition codes. - addl(data, -DataLayout::counter_increment); - // If the decrement causes the counter to overflow, stay negative - Label L; - jcc(Assembler::negative, L); - addl(data, DataLayout::counter_increment); - bind(L); - } else { - assert(DataLayout::counter_increment == 1, - "flow-free idiom only works with 1"); - // Increment the register. Set carry flag. - addl(data, DataLayout::counter_increment); - // If the increment causes the counter to overflow, pull back by 1. - sbbl(data, 0); - } -} - - -void InterpreterMacroAssembler::increment_mdp_data_at(Register mdp_in, - Register reg, - int constant, - bool decrement) { - Address data(mdp_in, reg, Address::times_1, constant); - - increment_mdp_data_at(data, decrement); -} - - -void InterpreterMacroAssembler::set_mdp_flag_at(Register mdp_in, int flag_byte_constant) { - assert(ProfileInterpreter, "must be profiling interpreter"); - int header_offset = in_bytes(DataLayout::header_offset()); - int header_bits = DataLayout::flag_mask_to_header_mask(flag_byte_constant); - // Set the flag - orl(Address(mdp_in, header_offset), header_bits); -} - - - -void InterpreterMacroAssembler::test_mdp_data_at(Register mdp_in, - int offset, - Register value, - Register test_value_out, - Label& not_equal_continue) { - assert(ProfileInterpreter, "must be profiling interpreter"); - if (test_value_out == noreg) { - cmpptr(value, Address(mdp_in, offset)); - } else { - // Put the test value into a register, so caller can use it: - movptr(test_value_out, Address(mdp_in, offset)); - cmpptr(test_value_out, value); - } - jcc(Assembler::notEqual, not_equal_continue); -} - - -void InterpreterMacroAssembler::update_mdp_by_offset(Register mdp_in, int offset_of_disp) { - assert(ProfileInterpreter, "must be profiling interpreter"); - Address disp_address(mdp_in, offset_of_disp); - addptr(mdp_in,disp_address); - movptr(Address(rbp, frame::interpreter_frame_mdp_offset * wordSize), mdp_in); -} - - -void InterpreterMacroAssembler::update_mdp_by_offset(Register mdp_in, Register reg, int offset_of_disp) { - assert(ProfileInterpreter, "must be profiling interpreter"); - Address disp_address(mdp_in, reg, Address::times_1, offset_of_disp); - addptr(mdp_in, disp_address); - movptr(Address(rbp, frame::interpreter_frame_mdp_offset * wordSize), mdp_in); -} - - -void InterpreterMacroAssembler::update_mdp_by_constant(Register mdp_in, int constant) { - assert(ProfileInterpreter, "must be profiling interpreter"); - addptr(mdp_in, constant); - movptr(Address(rbp, frame::interpreter_frame_mdp_offset * wordSize), mdp_in); -} - - -void InterpreterMacroAssembler::update_mdp_for_ret(Register return_bci) { - assert(ProfileInterpreter, "must be profiling interpreter"); - push(return_bci); // save/restore across call_VM - call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::update_mdp_for_ret), return_bci); - pop(return_bci); -} - - -void InterpreterMacroAssembler::profile_taken_branch(Register mdp, Register bumped_count) { - if (ProfileInterpreter) { - Label profile_continue; - - // If no method data exists, go to profile_continue. - // Otherwise, assign to mdp - test_method_data_pointer(mdp, profile_continue); - - // We are taking a branch. Increment the taken count. - // We inline increment_mdp_data_at to return bumped_count in a register - //increment_mdp_data_at(mdp, in_bytes(JumpData::taken_offset())); - Address data(mdp, in_bytes(JumpData::taken_offset())); - - // %%% 64bit treats these cells as 64 bit but they seem to be 32 bit - movl(bumped_count,data); - assert( DataLayout::counter_increment==1, "flow-free idiom only works with 1" ); - addl(bumped_count, DataLayout::counter_increment); - sbbl(bumped_count, 0); - movl(data,bumped_count); // Store back out - - // The method data pointer needs to be updated to reflect the new target. - update_mdp_by_offset(mdp, in_bytes(JumpData::displacement_offset())); - bind (profile_continue); - } -} - - -void InterpreterMacroAssembler::profile_not_taken_branch(Register mdp) { - if (ProfileInterpreter) { - Label profile_continue; - - // If no method data exists, go to profile_continue. - test_method_data_pointer(mdp, profile_continue); - - // We are taking a branch. Increment the not taken count. - increment_mdp_data_at(mdp, in_bytes(BranchData::not_taken_offset())); - - // The method data pointer needs to be updated to correspond to the next bytecode - update_mdp_by_constant(mdp, in_bytes(BranchData::branch_data_size())); - bind (profile_continue); - } -} - -void InterpreterMacroAssembler::profile_call(Register mdp) { - if (ProfileInterpreter) { - Label profile_continue; - - // If no method data exists, go to profile_continue. - test_method_data_pointer(mdp, profile_continue); - - // We are making a call. Increment the count. - increment_mdp_data_at(mdp, in_bytes(CounterData::count_offset())); - - // The method data pointer needs to be updated to reflect the new target. - update_mdp_by_constant(mdp, in_bytes(CounterData::counter_data_size())); - bind (profile_continue); - } -} - - -void InterpreterMacroAssembler::profile_final_call(Register mdp) { - if (ProfileInterpreter) { - Label profile_continue; - - // If no method data exists, go to profile_continue. - test_method_data_pointer(mdp, profile_continue); - - // We are making a call. Increment the count. - increment_mdp_data_at(mdp, in_bytes(CounterData::count_offset())); - - // The method data pointer needs to be updated to reflect the new target. - update_mdp_by_constant(mdp, in_bytes(VirtualCallData::virtual_call_data_size())); - bind (profile_continue); - } -} - - -void InterpreterMacroAssembler::profile_virtual_call(Register receiver, Register mdp, - Register reg2, - bool receiver_can_be_null) { - if (ProfileInterpreter) { - Label profile_continue; - - // If no method data exists, go to profile_continue. - test_method_data_pointer(mdp, profile_continue); - - Label skip_receiver_profile; - if (receiver_can_be_null) { - Label not_null; - testptr(receiver, receiver); - jccb(Assembler::notZero, not_null); - // We are making a call. Increment the count for null receiver. - increment_mdp_data_at(mdp, in_bytes(CounterData::count_offset())); - jmp(skip_receiver_profile); - bind(not_null); - } - - // Record the receiver type. - record_klass_in_profile(receiver, mdp, reg2, true); - bind(skip_receiver_profile); - - // The method data pointer needs to be updated to reflect the new target. - update_mdp_by_constant(mdp, - in_bytes(VirtualCallData:: - virtual_call_data_size())); - bind(profile_continue); - } -} - - -void InterpreterMacroAssembler::record_klass_in_profile_helper( - Register receiver, Register mdp, - Register reg2, int start_row, - Label& done, bool is_virtual_call) { - if (TypeProfileWidth == 0) { - if (is_virtual_call) { - increment_mdp_data_at(mdp, in_bytes(CounterData::count_offset())); - } - return; - } - - int last_row = VirtualCallData::row_limit() - 1; - assert(start_row <= last_row, "must be work left to do"); - // Test this row for both the receiver and for null. - // Take any of three different outcomes: - // 1. found receiver => increment count and goto done - // 2. found null => keep looking for case 1, maybe allocate this cell - // 3. found something else => keep looking for cases 1 and 2 - // Case 3 is handled by a recursive call. - for (int row = start_row; row <= last_row; row++) { - Label next_test; - bool test_for_null_also = (row == start_row); - - // See if the receiver is receiver[n]. - int recvr_offset = in_bytes(VirtualCallData::receiver_offset(row)); - test_mdp_data_at(mdp, recvr_offset, receiver, - (test_for_null_also ? reg2 : noreg), - next_test); - // (Reg2 now contains the receiver from the CallData.) - - // The receiver is receiver[n]. Increment count[n]. - int count_offset = in_bytes(VirtualCallData::receiver_count_offset(row)); - increment_mdp_data_at(mdp, count_offset); - jmp(done); - bind(next_test); - - if (row == start_row) { - Label found_null; - // Failed the equality check on receiver[n]... Test for null. - testptr(reg2, reg2); - if (start_row == last_row) { - // The only thing left to do is handle the null case. - if (is_virtual_call) { - jccb(Assembler::zero, found_null); - // Receiver did not match any saved receiver and there is no empty row for it. - // Increment total counter to indicate polymorphic case. - increment_mdp_data_at(mdp, in_bytes(CounterData::count_offset())); - jmp(done); - bind(found_null); - } else { - jcc(Assembler::notZero, done); - } - break; - } - // Since null is rare, make it be the branch-taken case. - jcc(Assembler::zero, found_null); - - // Put all the "Case 3" tests here. - record_klass_in_profile_helper(receiver, mdp, reg2, start_row + 1, done, is_virtual_call); - - // Found a null. Keep searching for a matching receiver, - // but remember that this is an empty (unused) slot. - bind(found_null); - } - } - - // In the fall-through case, we found no matching receiver, but we - // observed the receiver[start_row] is NULL. - - // Fill in the receiver field and increment the count. - int recvr_offset = in_bytes(VirtualCallData::receiver_offset(start_row)); - set_mdp_data_at(mdp, recvr_offset, receiver); - int count_offset = in_bytes(VirtualCallData::receiver_count_offset(start_row)); - movptr(reg2, (intptr_t)DataLayout::counter_increment); - set_mdp_data_at(mdp, count_offset, reg2); - if (start_row > 0) { - jmp(done); - } -} - -void InterpreterMacroAssembler::record_klass_in_profile(Register receiver, - Register mdp, Register reg2, - bool is_virtual_call) { - assert(ProfileInterpreter, "must be profiling"); - Label done; - - record_klass_in_profile_helper(receiver, mdp, reg2, 0, done, is_virtual_call); - - bind (done); -} - -void InterpreterMacroAssembler::profile_ret(Register return_bci, Register mdp) { - if (ProfileInterpreter) { - Label profile_continue; - uint row; - - // If no method data exists, go to profile_continue. - test_method_data_pointer(mdp, profile_continue); - - // Update the total ret count. - increment_mdp_data_at(mdp, in_bytes(CounterData::count_offset())); - - for (row = 0; row < RetData::row_limit(); row++) { - Label next_test; - - // See if return_bci is equal to bci[n]: - test_mdp_data_at(mdp, in_bytes(RetData::bci_offset(row)), return_bci, - noreg, next_test); - - // return_bci is equal to bci[n]. Increment the count. - increment_mdp_data_at(mdp, in_bytes(RetData::bci_count_offset(row))); - - // The method data pointer needs to be updated to reflect the new target. - update_mdp_by_offset(mdp, in_bytes(RetData::bci_displacement_offset(row))); - jmp(profile_continue); - bind(next_test); - } - - update_mdp_for_ret(return_bci); - - bind (profile_continue); - } -} - - -void InterpreterMacroAssembler::profile_null_seen(Register mdp) { - if (ProfileInterpreter) { - Label profile_continue; - - // If no method data exists, go to profile_continue. - test_method_data_pointer(mdp, profile_continue); - - set_mdp_flag_at(mdp, BitData::null_seen_byte_constant()); - - // The method data pointer needs to be updated. - int mdp_delta = in_bytes(BitData::bit_data_size()); - if (TypeProfileCasts) { - mdp_delta = in_bytes(VirtualCallData::virtual_call_data_size()); - } - update_mdp_by_constant(mdp, mdp_delta); - - bind (profile_continue); - } -} - - -void InterpreterMacroAssembler::profile_typecheck_failed(Register mdp) { - if (ProfileInterpreter && TypeProfileCasts) { - Label profile_continue; - - // If no method data exists, go to profile_continue. - test_method_data_pointer(mdp, profile_continue); - - int count_offset = in_bytes(CounterData::count_offset()); - // Back up the address, since we have already bumped the mdp. - count_offset -= in_bytes(VirtualCallData::virtual_call_data_size()); - - // *Decrement* the counter. We expect to see zero or small negatives. - increment_mdp_data_at(mdp, count_offset, true); - - bind (profile_continue); - } -} - - -void InterpreterMacroAssembler::profile_typecheck(Register mdp, Register klass, Register reg2) -{ - if (ProfileInterpreter) { - Label profile_continue; - - // If no method data exists, go to profile_continue. - test_method_data_pointer(mdp, profile_continue); - - // The method data pointer needs to be updated. - int mdp_delta = in_bytes(BitData::bit_data_size()); - if (TypeProfileCasts) { - mdp_delta = in_bytes(VirtualCallData::virtual_call_data_size()); - - // Record the object type. - record_klass_in_profile(klass, mdp, reg2, false); - assert(reg2 == rdi, "we know how to fix this blown reg"); - restore_locals(); // Restore EDI - } - update_mdp_by_constant(mdp, mdp_delta); - - bind(profile_continue); - } -} - - -void InterpreterMacroAssembler::profile_switch_default(Register mdp) { - if (ProfileInterpreter) { - Label profile_continue; - - // If no method data exists, go to profile_continue. - test_method_data_pointer(mdp, profile_continue); - - // Update the default case count - increment_mdp_data_at(mdp, in_bytes(MultiBranchData::default_count_offset())); - - // The method data pointer needs to be updated. - update_mdp_by_offset(mdp, in_bytes(MultiBranchData::default_displacement_offset())); - - bind (profile_continue); - } -} - - -void InterpreterMacroAssembler::profile_switch_case(Register index, Register mdp, Register reg2) { - if (ProfileInterpreter) { - Label profile_continue; - - // If no method data exists, go to profile_continue. - test_method_data_pointer(mdp, profile_continue); - - // Build the base (index * per_case_size_in_bytes()) + case_array_offset_in_bytes() - movptr(reg2, (intptr_t)in_bytes(MultiBranchData::per_case_size())); - // index is positive and so should have correct value if this code were - // used on 64bits - imulptr(index, reg2); - addptr(index, in_bytes(MultiBranchData::case_array_offset())); - - // Update the case count - increment_mdp_data_at(mdp, index, in_bytes(MultiBranchData::relative_count_offset())); - - // The method data pointer needs to be updated. - update_mdp_by_offset(mdp, index, in_bytes(MultiBranchData::relative_displacement_offset())); - - bind (profile_continue); - } -} - -#endif // !CC_INTERP - - - -void InterpreterMacroAssembler::verify_oop(Register reg, TosState state) { - if (state == atos) MacroAssembler::verify_oop(reg); -} - - -#ifndef CC_INTERP -void InterpreterMacroAssembler::verify_FPU(int stack_depth, TosState state) { - if (state == ftos || state == dtos) MacroAssembler::verify_FPU(stack_depth); -} - -// Jump if ((*counter_addr += increment) & mask) satisfies the condition. -void InterpreterMacroAssembler::increment_mask_and_jump(Address counter_addr, - int increment, Address mask, - Register scratch, bool preloaded, - Condition cond, Label* where) { - if (!preloaded) { - movl(scratch, counter_addr); - } - incrementl(scratch, increment); - movl(counter_addr, scratch); - andl(scratch, mask); - jcc(cond, *where); -} -#endif /* CC_INTERP */ - - -void InterpreterMacroAssembler::notify_method_entry() { - // Whenever JVMTI is interp_only_mode, method entry/exit events are sent to - // track stack depth. If it is possible to enter interp_only_mode we add - // the code to check if the event should be sent. - if (JvmtiExport::can_post_interpreter_events()) { - Label L; - get_thread(rcx); - movl(rcx, Address(rcx, JavaThread::interp_only_mode_offset())); - testl(rcx,rcx); - jcc(Assembler::zero, L); - call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::post_method_entry)); - bind(L); - } - - { - SkipIfEqual skip_if(this, &DTraceMethodProbes, 0); - get_thread(rcx); - get_method(rbx); - call_VM_leaf( - CAST_FROM_FN_PTR(address, SharedRuntime::dtrace_method_entry), rcx, rbx); - } - - // RedefineClasses() tracing support for obsolete method entry - if (RC_TRACE_IN_RANGE(0x00001000, 0x00002000)) { - get_thread(rcx); - get_method(rbx); - call_VM_leaf( - CAST_FROM_FN_PTR(address, SharedRuntime::rc_trace_method_entry), - rcx, rbx); - } -} - - -void InterpreterMacroAssembler::notify_method_exit( - TosState state, NotifyMethodExitMode mode) { - // Whenever JVMTI is interp_only_mode, method entry/exit events are sent to - // track stack depth. If it is possible to enter interp_only_mode we add - // the code to check if the event should be sent. - if (mode == NotifyJVMTI && JvmtiExport::can_post_interpreter_events()) { - Label L; - // Note: frame::interpreter_frame_result has a dependency on how the - // method result is saved across the call to post_method_exit. If this - // is changed then the interpreter_frame_result implementation will - // need to be updated too. - - // For c++ interpreter the result is always stored at a known location in the frame - // template interpreter will leave it on the top of the stack. - NOT_CC_INTERP(push(state);) - get_thread(rcx); - movl(rcx, Address(rcx, JavaThread::interp_only_mode_offset())); - testl(rcx,rcx); - jcc(Assembler::zero, L); - call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::post_method_exit)); - bind(L); - NOT_CC_INTERP(pop(state);) - } - - { - SkipIfEqual skip_if(this, &DTraceMethodProbes, 0); - NOT_CC_INTERP(push(state)); - get_thread(rbx); - get_method(rcx); - call_VM_leaf( - CAST_FROM_FN_PTR(address, SharedRuntime::dtrace_method_exit), - rbx, rcx); - NOT_CC_INTERP(pop(state)); - } -} diff -r 8c1cc431f388 -r 889895365eb9 hotspot/src/cpu/x86/vm/interp_masm_x86_32.hpp --- a/hotspot/src/cpu/x86/vm/interp_masm_x86_32.hpp Fri Mar 20 17:39:29 2015 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,223 +0,0 @@ -/* - * Copyright (c) 1997, 2014, 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. - * - */ - -#ifndef CC_INTERP - protected: - // Interpreter specific version of call_VM_base - virtual void call_VM_leaf_base( - address entry_point, - int number_of_arguments - ); - - virtual void call_VM_base( - Register oop_result, - Register java_thread, - Register last_java_sp, - address entry_point, - int number_of_arguments, - bool check_exceptions - ); - - virtual void check_and_handle_popframe(Register java_thread); - virtual void check_and_handle_earlyret(Register java_thread); - - // base routine for all dispatches - void dispatch_base(TosState state, address* table, bool verifyoop = true); -#endif /* CC_INTERP */ - - public: - InterpreterMacroAssembler(CodeBuffer* code) : MacroAssembler(code), _locals_register(rdi), _bcp_register(rsi) {} - - void load_earlyret_value(TosState state); - - // Interpreter-specific registers -#ifdef CC_INTERP - void save_bcp() { /* not needed in c++ interpreter and harmless */ } - void restore_bcp() { /* not needed in c++ interpreter and harmless */ } - - // Helpers for runtime call arguments/results - void get_method(Register reg); - -#else - - void save_bcp() { movptr(Address(rbp, frame::interpreter_frame_bcp_offset * wordSize), rsi); } - void restore_bcp() { movptr(rsi, Address(rbp, frame::interpreter_frame_bcp_offset * wordSize)); } - void restore_locals() { movptr(rdi, Address(rbp, frame::interpreter_frame_locals_offset * wordSize)); } - - // Helpers for runtime call arguments/results - void get_method(Register reg) { movptr(reg, Address(rbp, frame::interpreter_frame_method_offset * wordSize)); } - void get_const(Register reg) { get_method(reg); movptr(reg, Address(reg, Method::const_offset())); } - void get_constant_pool(Register reg) { get_const(reg); movptr(reg, Address(reg, ConstMethod::constants_offset())); } - void get_constant_pool_cache(Register reg) { get_constant_pool(reg); movptr(reg, Address(reg, ConstantPool::cache_offset_in_bytes())); } - void get_cpool_and_tags(Register cpool, Register tags) { get_constant_pool(cpool); movptr(tags, Address(cpool, ConstantPool::tags_offset_in_bytes())); - } - void get_unsigned_2_byte_index_at_bcp(Register reg, int bcp_offset); - void get_cache_and_index_at_bcp(Register cache, Register index, int bcp_offset, size_t index_size = sizeof(u2)); - void get_cache_and_index_and_bytecode_at_bcp(Register cache, Register index, Register bytecode, int byte_no, int bcp_offset, size_t index_size = sizeof(u2)); - void get_cache_entry_pointer_at_bcp(Register cache, Register tmp, int bcp_offset, size_t index_size = sizeof(u2)); - void get_cache_index_at_bcp(Register index, int bcp_offset, size_t index_size = sizeof(u2)); - - // load cpool->resolved_references(index); - void load_resolved_reference_at_index(Register result, Register index); - - // Expression stack - void f2ieee(); // truncate ftos to 32bits - void d2ieee(); // truncate dtos to 64bits - - void pop_ptr(Register r = rax); - void pop_i(Register r = rax); - void pop_l(Register lo = rax, Register hi = rdx); - void pop_f(); - void pop_d(); - - void push_ptr(Register r = rax); - void push_i(Register r = rax); - void push_l(Register lo = rax, Register hi = rdx); - void push_d(Register r = rax); - void push_f(); - - void pop(TosState state); // transition vtos -> state - void push(TosState state); // transition state -> vtos - - void pop(Register r ) { ((MacroAssembler*)this)->pop(r); } - - void push(Register r ) { ((MacroAssembler*)this)->push(r); } - void push(int32_t imm ) { ((MacroAssembler*)this)->push(imm); } - - // These are dummies to prevent surprise implicit conversions to Register - void pop(void* v ); // Add unimplemented ambiguous method - void push(void* v ); // Add unimplemented ambiguous method - - void empty_expression_stack() { - movptr(rsp, Address(rbp, frame::interpreter_frame_monitor_block_top_offset * wordSize)); - // NULL last_sp until next java call - movptr(Address(rbp, frame::interpreter_frame_last_sp_offset * wordSize), NULL_WORD); - } - - // Helpers for swap and dup - void load_ptr(int n, Register val); - void store_ptr(int n, Register val); - - // Generate a subtype check: branch to ok_is_subtype if sub_klass is - // a subtype of super_klass. EAX holds the super_klass. Blows ECX - // and EDI. Register sub_klass cannot be any of the above. - void gen_subtype_check( Register sub_klass, Label &ok_is_subtype ); - - // Dispatching - void dispatch_prolog(TosState state, int step = 0); - void dispatch_epilog(TosState state, int step = 0); - void dispatch_only(TosState state); // dispatch via rbx, (assume rbx, is loaded already) - void dispatch_only_normal(TosState state); // dispatch normal table via rbx, (assume rbx, is loaded already) - void dispatch_only_noverify(TosState state); - void dispatch_next(TosState state, int step = 0); // load rbx, from [esi + step] and dispatch via rbx, - void dispatch_via (TosState state, address* table); // load rbx, from [esi] and dispatch via rbx, and table - - - // jump to an invoked target - void prepare_to_jump_from_interpreted(); - void jump_from_interpreted(Register method, Register temp); - - // Returning from interpreted functions - // - // Removes the current activation (incl. unlocking of monitors) - // and sets up the return address. This code is also used for - // exception unwindwing. In that case, we do not want to throw - // IllegalMonitorStateExceptions, since that might get us into an - // infinite rethrow exception loop. - // Additionally this code is used for popFrame and earlyReturn. - // In popFrame case we want to skip throwing an exception, - // installing an exception, and notifying jvmdi. - // In earlyReturn case we only want to skip throwing an exception - // and installing an exception. - void remove_activation(TosState state, Register ret_addr, - bool throw_monitor_exception = true, - bool install_monitor_exception = true, - bool notify_jvmdi = true); -#endif /* !CC_INTERP */ - void get_method_counters(Register method, Register mcs, Label& skip); - - // Debugging - void verify_oop(Register reg, TosState state = atos); // only if +VerifyOops && state == atos -#ifndef CC_INTERP - void verify_FPU(int stack_depth, TosState state = ftos); // only if +VerifyFPU && (state == ftos || state == dtos) - -#endif /* !CC_INTERP */ - - // Object locking - void lock_object (Register lock_reg); - void unlock_object(Register lock_reg); - -#ifndef CC_INTERP - - // Interpreter profiling operations - void set_method_data_pointer_for_bcp(); - void test_method_data_pointer(Register mdp, Label& zero_continue); - void verify_method_data_pointer(); - - void set_mdp_data_at(Register mdp_in, int constant, Register value); - void increment_mdp_data_at(Address data, bool decrement = false); - void increment_mdp_data_at(Register mdp_in, int constant, - bool decrement = false); - void increment_mdp_data_at(Register mdp_in, Register reg, int constant, - bool decrement = false); - void increment_mask_and_jump(Address counter_addr, - int increment, Address mask, - Register scratch, bool preloaded, - Condition cond, Label* where); - void set_mdp_flag_at(Register mdp_in, int flag_constant); - void test_mdp_data_at(Register mdp_in, int offset, Register value, - Register test_value_out, - Label& not_equal_continue); - - void record_klass_in_profile(Register receiver, Register mdp, - Register reg2, bool is_virtual_call); - void record_klass_in_profile_helper(Register receiver, Register mdp, - Register reg2, int start_row, - Label& done, bool is_virtual_call); - - void update_mdp_by_offset(Register mdp_in, int offset_of_offset); - void update_mdp_by_offset(Register mdp_in, Register reg, int offset_of_disp); - void update_mdp_by_constant(Register mdp_in, int constant); - void update_mdp_for_ret(Register return_bci); - - void profile_taken_branch(Register mdp, Register bumped_count); - void profile_not_taken_branch(Register mdp); - void profile_call(Register mdp); - void profile_final_call(Register mdp); - void profile_virtual_call(Register receiver, Register mdp, Register scratch2, - bool receiver_can_be_null = false); - void profile_ret(Register return_bci, Register mdp); - void profile_null_seen(Register mdp); - void profile_typecheck(Register mdp, Register klass, Register scratch); - void profile_typecheck_failed(Register mdp); - void profile_switch_default(Register mdp); - void profile_switch_case(Register index_in_scratch, Register mdp, Register scratch2); - -#endif /* !CC_INTERP */ - - typedef enum { NotifyJVMTI, SkipNotifyJVMTI } NotifyMethodExitMode; - - // support for jvmti - void notify_method_entry(); - void notify_method_exit(TosState state, NotifyMethodExitMode mode); diff -r 8c1cc431f388 -r 889895365eb9 hotspot/src/cpu/x86/vm/interp_masm_x86_64.cpp --- a/hotspot/src/cpu/x86/vm/interp_masm_x86_64.cpp Fri Mar 20 17:39:29 2015 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,1507 +0,0 @@ -/* - * Copyright (c) 2003, 2014, 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. - * - */ - -#include "precompiled.hpp" -#include "interp_masm_x86.hpp" -#include "interpreter/interpreter.hpp" -#include "interpreter/interpreterRuntime.hpp" -#include "oops/arrayOop.hpp" -#include "oops/markOop.hpp" -#include "oops/methodData.hpp" -#include "oops/method.hpp" -#include "prims/jvmtiExport.hpp" -#include "prims/jvmtiRedefineClassesTrace.hpp" -#include "prims/jvmtiThreadState.hpp" -#include "runtime/basicLock.hpp" -#include "runtime/biasedLocking.hpp" -#include "runtime/sharedRuntime.hpp" -#include "runtime/thread.inline.hpp" - - -// Implementation of InterpreterMacroAssembler - -#ifdef CC_INTERP -void InterpreterMacroAssembler::get_method(Register reg) { - movptr(reg, Address(rbp, -((int)sizeof(BytecodeInterpreter) + 2 * wordSize))); - movptr(reg, Address(reg, byte_offset_of(BytecodeInterpreter, _method))); -} -#endif // CC_INTERP - -#ifndef CC_INTERP - -void InterpreterMacroAssembler::call_VM_leaf_base(address entry_point, - int number_of_arguments) { - // interpreter specific - // - // Note: No need to save/restore bcp & locals (r13 & r14) pointer - // since these are callee saved registers and no blocking/ - // GC can happen in leaf calls. - // Further Note: DO NOT save/restore bcp/locals. If a caller has - // already saved them so that it can use esi/edi as temporaries - // then a save/restore here will DESTROY the copy the caller - // saved! There used to be a save_bcp() that only happened in - // the ASSERT path (no restore_bcp). Which caused bizarre failures - // when jvm built with ASSERTs. -#ifdef ASSERT - { - Label L; - cmpptr(Address(rbp, frame::interpreter_frame_last_sp_offset * wordSize), (int32_t)NULL_WORD); - jcc(Assembler::equal, L); - stop("InterpreterMacroAssembler::call_VM_leaf_base:" - " last_sp != NULL"); - bind(L); - } -#endif - // super call - MacroAssembler::call_VM_leaf_base(entry_point, number_of_arguments); - // interpreter specific - // Used to ASSERT that r13/r14 were equal to frame's bcp/locals - // but since they may not have been saved (and we don't want to - // save thme here (see note above) the assert is invalid. -} - -void InterpreterMacroAssembler::call_VM_base(Register oop_result, - Register java_thread, - Register last_java_sp, - address entry_point, - int number_of_arguments, - bool check_exceptions) { - // interpreter specific - // - // Note: Could avoid restoring locals ptr (callee saved) - however doesn't - // really make a difference for these runtime calls, since they are - // slow anyway. Btw., bcp must be saved/restored since it may change - // due to GC. - // assert(java_thread == noreg , "not expecting a precomputed java thread"); - save_bcp(); -#ifdef ASSERT - { - Label L; - cmpptr(Address(rbp, frame::interpreter_frame_last_sp_offset * wordSize), (int32_t)NULL_WORD); - jcc(Assembler::equal, L); - stop("InterpreterMacroAssembler::call_VM_leaf_base:" - " last_sp != NULL"); - bind(L); - } -#endif /* ASSERT */ - // super call - MacroAssembler::call_VM_base(oop_result, noreg, last_java_sp, - entry_point, number_of_arguments, - check_exceptions); - // interpreter specific - restore_bcp(); - restore_locals(); -} - - -void InterpreterMacroAssembler::check_and_handle_popframe(Register java_thread) { - if (JvmtiExport::can_pop_frame()) { - Label L; - // Initiate popframe handling only if it is not already being - // processed. If the flag has the popframe_processing bit set, it - // means that this code is called *during* popframe handling - we - // don't want to reenter. - // This method is only called just after the call into the vm in - // call_VM_base, so the arg registers are available. - movl(c_rarg0, Address(r15_thread, JavaThread::popframe_condition_offset())); - testl(c_rarg0, JavaThread::popframe_pending_bit); - jcc(Assembler::zero, L); - testl(c_rarg0, JavaThread::popframe_processing_bit); - jcc(Assembler::notZero, L); - // Call Interpreter::remove_activation_preserving_args_entry() to get the - // address of the same-named entrypoint in the generated interpreter code. - call_VM_leaf(CAST_FROM_FN_PTR(address, Interpreter::remove_activation_preserving_args_entry)); - jmp(rax); - bind(L); - } -} - - -void InterpreterMacroAssembler::load_earlyret_value(TosState state) { - movptr(rcx, Address(r15_thread, JavaThread::jvmti_thread_state_offset())); - const Address tos_addr(rcx, JvmtiThreadState::earlyret_tos_offset()); - const Address oop_addr(rcx, JvmtiThreadState::earlyret_oop_offset()); - const Address val_addr(rcx, JvmtiThreadState::earlyret_value_offset()); - switch (state) { - case atos: movptr(rax, oop_addr); - movptr(oop_addr, (int32_t)NULL_WORD); - verify_oop(rax, state); break; - case ltos: movptr(rax, val_addr); break; - case btos: // fall through - case ctos: // fall through - case stos: // fall through - case itos: movl(rax, val_addr); break; - case ftos: movflt(xmm0, val_addr); break; - case dtos: movdbl(xmm0, val_addr); break; - case vtos: /* nothing to do */ break; - default : ShouldNotReachHere(); - } - // Clean up tos value in the thread object - movl(tos_addr, (int) ilgl); - movl(val_addr, (int32_t) NULL_WORD); -} - - -void InterpreterMacroAssembler::check_and_handle_earlyret(Register java_thread) { - if (JvmtiExport::can_force_early_return()) { - Label L; - movptr(c_rarg0, Address(r15_thread, JavaThread::jvmti_thread_state_offset())); - testptr(c_rarg0, c_rarg0); - jcc(Assembler::zero, L); // if (thread->jvmti_thread_state() == NULL) exit; - - // Initiate earlyret handling only if it is not already being processed. - // If the flag has the earlyret_processing bit set, it means that this code - // is called *during* earlyret handling - we don't want to reenter. - movl(c_rarg0, Address(c_rarg0, JvmtiThreadState::earlyret_state_offset())); - cmpl(c_rarg0, JvmtiThreadState::earlyret_pending); - jcc(Assembler::notEqual, L); - - // Call Interpreter::remove_activation_early_entry() to get the address of the - // same-named entrypoint in the generated interpreter code. - movptr(c_rarg0, Address(r15_thread, JavaThread::jvmti_thread_state_offset())); - movl(c_rarg0, Address(c_rarg0, JvmtiThreadState::earlyret_tos_offset())); - call_VM_leaf(CAST_FROM_FN_PTR(address, Interpreter::remove_activation_early_entry), c_rarg0); - jmp(rax); - bind(L); - } -} - - -void InterpreterMacroAssembler::get_unsigned_2_byte_index_at_bcp( - Register reg, - int bcp_offset) { - assert(bcp_offset >= 0, "bcp is still pointing to start of bytecode"); - load_unsigned_short(reg, Address(r13, bcp_offset)); - bswapl(reg); - shrl(reg, 16); -} - - -void InterpreterMacroAssembler::get_cache_index_at_bcp(Register index, - int bcp_offset, - size_t index_size) { - assert(bcp_offset > 0, "bcp is still pointing to start of bytecode"); - if (index_size == sizeof(u2)) { - load_unsigned_short(index, Address(r13, bcp_offset)); - } else if (index_size == sizeof(u4)) { - movl(index, Address(r13, bcp_offset)); - // Check if the secondary index definition is still ~x, otherwise - // we have to change the following assembler code to calculate the - // plain index. - assert(ConstantPool::decode_invokedynamic_index(~123) == 123, "else change next line"); - notl(index); // convert to plain index - } else if (index_size == sizeof(u1)) { - load_unsigned_byte(index, Address(r13, bcp_offset)); - } else { - ShouldNotReachHere(); - } -} - - -void InterpreterMacroAssembler::get_cache_and_index_at_bcp(Register cache, - Register index, - int bcp_offset, - size_t index_size) { - assert_different_registers(cache, index); - get_cache_index_at_bcp(index, bcp_offset, index_size); - movptr(cache, Address(rbp, frame::interpreter_frame_cache_offset * wordSize)); - assert(sizeof(ConstantPoolCacheEntry) == 4 * wordSize, "adjust code below"); - // convert from field index to ConstantPoolCacheEntry index - assert(exact_log2(in_words(ConstantPoolCacheEntry::size())) == 2, "else change next line"); - shll(index, 2); -} - - -void InterpreterMacroAssembler::get_cache_and_index_and_bytecode_at_bcp(Register cache, - Register index, - Register bytecode, - int byte_no, - int bcp_offset, - size_t index_size) { - get_cache_and_index_at_bcp(cache, index, bcp_offset, index_size); - // We use a 32-bit load here since the layout of 64-bit words on - // little-endian machines allow us that. - movl(bytecode, Address(cache, index, Address::times_ptr, ConstantPoolCache::base_offset() + ConstantPoolCacheEntry::indices_offset())); - const int shift_count = (1 + byte_no) * BitsPerByte; - assert((byte_no == TemplateTable::f1_byte && shift_count == ConstantPoolCacheEntry::bytecode_1_shift) || - (byte_no == TemplateTable::f2_byte && shift_count == ConstantPoolCacheEntry::bytecode_2_shift), - "correct shift count"); - shrl(bytecode, shift_count); - assert(ConstantPoolCacheEntry::bytecode_1_mask == ConstantPoolCacheEntry::bytecode_2_mask, "common mask"); - andl(bytecode, ConstantPoolCacheEntry::bytecode_1_mask); -} - - -void InterpreterMacroAssembler::get_cache_entry_pointer_at_bcp(Register cache, - Register tmp, - int bcp_offset, - size_t index_size) { - assert(cache != tmp, "must use different register"); - get_cache_index_at_bcp(tmp, bcp_offset, index_size); - assert(sizeof(ConstantPoolCacheEntry) == 4 * wordSize, "adjust code below"); - // convert from field index to ConstantPoolCacheEntry index - // and from word offset to byte offset - assert(exact_log2(in_bytes(ConstantPoolCacheEntry::size_in_bytes())) == 2 + LogBytesPerWord, "else change next line"); - shll(tmp, 2 + LogBytesPerWord); - movptr(cache, Address(rbp, frame::interpreter_frame_cache_offset * wordSize)); - // skip past the header - addptr(cache, in_bytes(ConstantPoolCache::base_offset())); - addptr(cache, tmp); // construct pointer to cache entry -} - -// Load object from cpool->resolved_references(index) -void InterpreterMacroAssembler::load_resolved_reference_at_index( - Register result, Register index) { - assert_different_registers(result, index); - // convert from field index to resolved_references() index and from - // word index to byte offset. Since this is a java object, it can be compressed - Register tmp = index; // reuse - shll(tmp, LogBytesPerHeapOop); - - get_constant_pool(result); - // load pointer for resolved_references[] objArray - movptr(result, Address(result, ConstantPool::resolved_references_offset_in_bytes())); - // JNIHandles::resolve(obj); - movptr(result, Address(result, 0)); - // Add in the index - addptr(result, tmp); - load_heap_oop(result, Address(result, arrayOopDesc::base_offset_in_bytes(T_OBJECT))); -} - -// Generate a subtype check: branch to ok_is_subtype if sub_klass is a -// subtype of super_klass. -// -// Args: -// rax: superklass -// Rsub_klass: subklass -// -// Kills: -// rcx, rdi -void InterpreterMacroAssembler::gen_subtype_check(Register Rsub_klass, - Label& ok_is_subtype) { - assert(Rsub_klass != rax, "rax holds superklass"); - assert(Rsub_klass != r14, "r14 holds locals"); - assert(Rsub_klass != r13, "r13 holds bcp"); - assert(Rsub_klass != rcx, "rcx holds 2ndary super array length"); - assert(Rsub_klass != rdi, "rdi holds 2ndary super array scan ptr"); - - // Profile the not-null value's klass. - profile_typecheck(rcx, Rsub_klass, rdi); // blows rcx, reloads rdi - - // Do the check. - check_klass_subtype(Rsub_klass, rax, rcx, ok_is_subtype); // blows rcx - - // Profile the failure of the check. - profile_typecheck_failed(rcx); // blows rcx -} - - - -// Java Expression Stack - -void InterpreterMacroAssembler::pop_ptr(Register r) { - pop(r); -} - -void InterpreterMacroAssembler::pop_i(Register r) { - // XXX can't use pop currently, upper half non clean - movl(r, Address(rsp, 0)); - addptr(rsp, wordSize); -} - -void InterpreterMacroAssembler::pop_l(Register r) { - movq(r, Address(rsp, 0)); - addptr(rsp, 2 * Interpreter::stackElementSize); -} - -void InterpreterMacroAssembler::pop_f(XMMRegister r) { - movflt(r, Address(rsp, 0)); - addptr(rsp, wordSize); -} - -void InterpreterMacroAssembler::pop_d(XMMRegister r) { - movdbl(r, Address(rsp, 0)); - addptr(rsp, 2 * Interpreter::stackElementSize); -} - -void InterpreterMacroAssembler::push_ptr(Register r) { - push(r); -} - -void InterpreterMacroAssembler::push_i(Register r) { - push(r); -} - -void InterpreterMacroAssembler::push_l(Register r) { - subptr(rsp, 2 * wordSize); - movq(Address(rsp, 0), r); -} - -void InterpreterMacroAssembler::push_f(XMMRegister r) { - subptr(rsp, wordSize); - movflt(Address(rsp, 0), r); -} - -void InterpreterMacroAssembler::push_d(XMMRegister r) { - subptr(rsp, 2 * wordSize); - movdbl(Address(rsp, 0), r); -} - -void InterpreterMacroAssembler::pop(TosState state) { - switch (state) { - case atos: pop_ptr(); break; - case btos: - case ctos: - case stos: - case itos: pop_i(); break; - case ltos: pop_l(); break; - case ftos: pop_f(); break; - case dtos: pop_d(); break; - case vtos: /* nothing to do */ break; - default: ShouldNotReachHere(); - } - verify_oop(rax, state); -} - -void InterpreterMacroAssembler::push(TosState state) { - verify_oop(rax, state); - switch (state) { - case atos: push_ptr(); break; - case btos: - case ctos: - case stos: - case itos: push_i(); break; - case ltos: push_l(); break; - case ftos: push_f(); break; - case dtos: push_d(); break; - case vtos: /* nothing to do */ break; - default : ShouldNotReachHere(); - } -} - - -// Helpers for swap and dup -void InterpreterMacroAssembler::load_ptr(int n, Register val) { - movptr(val, Address(rsp, Interpreter::expr_offset_in_bytes(n))); -} - -void InterpreterMacroAssembler::store_ptr(int n, Register val) { - movptr(Address(rsp, Interpreter::expr_offset_in_bytes(n)), val); -} - - -void InterpreterMacroAssembler::prepare_to_jump_from_interpreted() { - // set sender sp - lea(r13, Address(rsp, wordSize)); - // record last_sp - movptr(Address(rbp, frame::interpreter_frame_last_sp_offset * wordSize), r13); -} - - -// Jump to from_interpreted entry of a call unless single stepping is possible -// in this thread in which case we must call the i2i entry -void InterpreterMacroAssembler::jump_from_interpreted(Register method, Register temp) { - prepare_to_jump_from_interpreted(); - - if (JvmtiExport::can_post_interpreter_events()) { - Label run_compiled_code; - // JVMTI events, such as single-stepping, are implemented partly by avoiding running - // compiled code in threads for which the event is enabled. Check here for - // interp_only_mode if these events CAN be enabled. - // interp_only is an int, on little endian it is sufficient to test the byte only - // Is a cmpl faster? - cmpb(Address(r15_thread, JavaThread::interp_only_mode_offset()), 0); - jccb(Assembler::zero, run_compiled_code); - jmp(Address(method, Method::interpreter_entry_offset())); - bind(run_compiled_code); - } - - jmp(Address(method, Method::from_interpreted_offset())); - -} - - -// The following two routines provide a hook so that an implementation -// can schedule the dispatch in two parts. amd64 does not do this. -void InterpreterMacroAssembler::dispatch_prolog(TosState state, int step) { - // Nothing amd64 specific to be done here -} - -void InterpreterMacroAssembler::dispatch_epilog(TosState state, int step) { - dispatch_next(state, step); -} - -void InterpreterMacroAssembler::dispatch_base(TosState state, - address* table, - bool verifyoop) { - verify_FPU(1, state); - if (VerifyActivationFrameSize) { - Label L; - mov(rcx, rbp); - subptr(rcx, rsp); - int32_t min_frame_size = - (frame::link_offset - frame::interpreter_frame_initial_sp_offset) * - wordSize; - cmpptr(rcx, (int32_t)min_frame_size); - jcc(Assembler::greaterEqual, L); - stop("broken stack frame"); - bind(L); - } - if (verifyoop) { - verify_oop(rax, state); - } - lea(rscratch1, ExternalAddress((address)table)); - jmp(Address(rscratch1, rbx, Address::times_8)); -} - -void InterpreterMacroAssembler::dispatch_only(TosState state) { - dispatch_base(state, Interpreter::dispatch_table(state)); -} - -void InterpreterMacroAssembler::dispatch_only_normal(TosState state) { - dispatch_base(state, Interpreter::normal_table(state)); -} - -void InterpreterMacroAssembler::dispatch_only_noverify(TosState state) { - dispatch_base(state, Interpreter::normal_table(state), false); -} - - -void InterpreterMacroAssembler::dispatch_next(TosState state, int step) { - // load next bytecode (load before advancing r13 to prevent AGI) - load_unsigned_byte(rbx, Address(r13, step)); - // advance r13 - increment(r13, step); - dispatch_base(state, Interpreter::dispatch_table(state)); -} - -void InterpreterMacroAssembler::dispatch_via(TosState state, address* table) { - // load current bytecode - load_unsigned_byte(rbx, Address(r13, 0)); - dispatch_base(state, table); -} - -// remove activation -// -// Unlock the receiver if this is a synchronized method. -// Unlock any Java monitors from syncronized blocks. -// Remove the activation from the stack. -// -// If there are locked Java monitors -// If throw_monitor_exception -// throws IllegalMonitorStateException -// Else if install_monitor_exception -// installs IllegalMonitorStateException -// Else -// no error processing -void InterpreterMacroAssembler::remove_activation( - TosState state, - Register ret_addr, - bool throw_monitor_exception, - bool install_monitor_exception, - bool notify_jvmdi) { - // Note: Registers rdx xmm0 may be in use for the - // result check if synchronized method - Label unlocked, unlock, no_unlock; - - // get the value of _do_not_unlock_if_synchronized into rdx - const Address do_not_unlock_if_synchronized(r15_thread, - in_bytes(JavaThread::do_not_unlock_if_synchronized_offset())); - movbool(rdx, do_not_unlock_if_synchronized); - movbool(do_not_unlock_if_synchronized, false); // reset the flag - - // get method access flags - movptr(rbx, Address(rbp, frame::interpreter_frame_method_offset * wordSize)); - movl(rcx, Address(rbx, Method::access_flags_offset())); - testl(rcx, JVM_ACC_SYNCHRONIZED); - jcc(Assembler::zero, unlocked); - - // Don't unlock anything if the _do_not_unlock_if_synchronized flag - // is set. - testbool(rdx); - jcc(Assembler::notZero, no_unlock); - - // unlock monitor - push(state); // save result - - // BasicObjectLock will be first in list, since this is a - // synchronized method. However, need to check that the object has - // not been unlocked by an explicit monitorexit bytecode. - const Address monitor(rbp, frame::interpreter_frame_initial_sp_offset * - wordSize - (int) sizeof(BasicObjectLock)); - // We use c_rarg1 so that if we go slow path it will be the correct - // register for unlock_object to pass to VM directly - lea(c_rarg1, monitor); // address of first monitor - - movptr(rax, Address(c_rarg1, BasicObjectLock::obj_offset_in_bytes())); - testptr(rax, rax); - jcc(Assembler::notZero, unlock); - - pop(state); - if (throw_monitor_exception) { - // Entry already unlocked, need to throw exception - call_VM(noreg, CAST_FROM_FN_PTR(address, - InterpreterRuntime::throw_illegal_monitor_state_exception)); - should_not_reach_here(); - } else { - // Monitor already unlocked during a stack unroll. If requested, - // install an illegal_monitor_state_exception. Continue with - // stack unrolling. - if (install_monitor_exception) { - call_VM(noreg, CAST_FROM_FN_PTR(address, - InterpreterRuntime::new_illegal_monitor_state_exception)); - } - jmp(unlocked); - } - - bind(unlock); - unlock_object(c_rarg1); - pop(state); - - // Check that for block-structured locking (i.e., that all locked - // objects has been unlocked) - bind(unlocked); - - // rax: Might contain return value - - // Check that all monitors are unlocked - { - Label loop, exception, entry, restart; - const int entry_size = frame::interpreter_frame_monitor_size() * wordSize; - const Address monitor_block_top( - rbp, frame::interpreter_frame_monitor_block_top_offset * wordSize); - const Address monitor_block_bot( - rbp, frame::interpreter_frame_initial_sp_offset * wordSize); - - bind(restart); - // We use c_rarg1 so that if we go slow path it will be the correct - // register for unlock_object to pass to VM directly - movptr(c_rarg1, monitor_block_top); // points to current entry, starting - // with top-most entry - lea(rbx, monitor_block_bot); // points to word before bottom of - // monitor block - jmp(entry); - - // Entry already locked, need to throw exception - bind(exception); - - if (throw_monitor_exception) { - // Throw exception - MacroAssembler::call_VM(noreg, - CAST_FROM_FN_PTR(address, InterpreterRuntime:: - throw_illegal_monitor_state_exception)); - should_not_reach_here(); - } else { - // Stack unrolling. Unlock object and install illegal_monitor_exception. - // Unlock does not block, so don't have to worry about the frame. - // We don't have to preserve c_rarg1 since we are going to throw an exception. - - push(state); - unlock_object(c_rarg1); - pop(state); - - if (install_monitor_exception) { - call_VM(noreg, CAST_FROM_FN_PTR(address, - InterpreterRuntime:: - new_illegal_monitor_state_exception)); - } - - jmp(restart); - } - - bind(loop); - // check if current entry is used - cmpptr(Address(c_rarg1, BasicObjectLock::obj_offset_in_bytes()), (int32_t) NULL); - jcc(Assembler::notEqual, exception); - - addptr(c_rarg1, entry_size); // otherwise advance to next entry - bind(entry); - cmpptr(c_rarg1, rbx); // check if bottom reached - jcc(Assembler::notEqual, loop); // if not at bottom then check this entry - } - - bind(no_unlock); - - // jvmti support - if (notify_jvmdi) { - notify_method_exit(state, NotifyJVMTI); // preserve TOSCA - } else { - notify_method_exit(state, SkipNotifyJVMTI); // preserve TOSCA - } - - // remove activation - // get sender sp - movptr(rbx, - Address(rbp, frame::interpreter_frame_sender_sp_offset * wordSize)); - leave(); // remove frame anchor - pop(ret_addr); // get return address - mov(rsp, rbx); // set sp to sender sp -} - -#endif // C_INTERP - -void InterpreterMacroAssembler::get_method_counters(Register method, - Register mcs, Label& skip) { - Label has_counters; - movptr(mcs, Address(method, Method::method_counters_offset())); - testptr(mcs, mcs); - jcc(Assembler::notZero, has_counters); - call_VM(noreg, CAST_FROM_FN_PTR(address, - InterpreterRuntime::build_method_counters), method); - movptr(mcs, Address(method,Method::method_counters_offset())); - testptr(mcs, mcs); - jcc(Assembler::zero, skip); // No MethodCounters allocated, OutOfMemory - bind(has_counters); -} - - -// Lock object -// -// Args: -// c_rarg1: BasicObjectLock to be used for locking -// -// Kills: -// rax -// c_rarg0, c_rarg1, c_rarg2, c_rarg3, .. (param regs) -// rscratch1, rscratch2 (scratch regs) -void InterpreterMacroAssembler::lock_object(Register lock_reg) { - assert(lock_reg == c_rarg1, "The argument is only for looks. It must be c_rarg1"); - - if (UseHeavyMonitors) { - call_VM(noreg, - CAST_FROM_FN_PTR(address, InterpreterRuntime::monitorenter), - lock_reg); - } else { - Label done; - - const Register swap_reg = rax; // Must use rax for cmpxchg instruction - const Register obj_reg = c_rarg3; // Will contain the oop - - const int obj_offset = BasicObjectLock::obj_offset_in_bytes(); - const int lock_offset = BasicObjectLock::lock_offset_in_bytes (); - const int mark_offset = lock_offset + - BasicLock::displaced_header_offset_in_bytes(); - - Label slow_case; - - // Load object pointer into obj_reg %c_rarg3 - movptr(obj_reg, Address(lock_reg, obj_offset)); - - if (UseBiasedLocking) { - biased_locking_enter(lock_reg, obj_reg, swap_reg, rscratch1, false, done, &slow_case); - } - - // Load immediate 1 into swap_reg %rax - movl(swap_reg, 1); - - // Load (object->mark() | 1) into swap_reg %rax - orptr(swap_reg, Address(obj_reg, 0)); - - // Save (object->mark() | 1) into BasicLock's displaced header - movptr(Address(lock_reg, mark_offset), swap_reg); - - assert(lock_offset == 0, - "displached header must be first word in BasicObjectLock"); - - if (os::is_MP()) lock(); - cmpxchgptr(lock_reg, Address(obj_reg, 0)); - if (PrintBiasedLockingStatistics) { - cond_inc32(Assembler::zero, - ExternalAddress((address) BiasedLocking::fast_path_entry_count_addr())); - } - jcc(Assembler::zero, done); - - // Test if the oopMark is an obvious stack pointer, i.e., - // 1) (mark & 7) == 0, and - // 2) rsp <= mark < mark + os::pagesize() - // - // These 3 tests can be done by evaluating the following - // expression: ((mark - rsp) & (7 - os::vm_page_size())), - // assuming both stack pointer and pagesize have their - // least significant 3 bits clear. - // NOTE: the oopMark is in swap_reg %rax as the result of cmpxchg - subptr(swap_reg, rsp); - andptr(swap_reg, 7 - os::vm_page_size()); - - // Save the test result, for recursive case, the result is zero - movptr(Address(lock_reg, mark_offset), swap_reg); - - if (PrintBiasedLockingStatistics) { - cond_inc32(Assembler::zero, - ExternalAddress((address) BiasedLocking::fast_path_entry_count_addr())); - } - jcc(Assembler::zero, done); - - bind(slow_case); - - // Call the runtime routine for slow case - call_VM(noreg, - CAST_FROM_FN_PTR(address, InterpreterRuntime::monitorenter), - lock_reg); - - bind(done); - } -} - - -// Unlocks an object. Used in monitorexit bytecode and -// remove_activation. Throws an IllegalMonitorException if object is -// not locked by current thread. -// -// Args: -// c_rarg1: BasicObjectLock for lock -// -// Kills: -// rax -// c_rarg0, c_rarg1, c_rarg2, c_rarg3, ... (param regs) -// rscratch1, rscratch2 (scratch regs) -void InterpreterMacroAssembler::unlock_object(Register lock_reg) { - assert(lock_reg == c_rarg1, "The argument is only for looks. It must be rarg1"); - - if (UseHeavyMonitors) { - call_VM(noreg, - CAST_FROM_FN_PTR(address, InterpreterRuntime::monitorexit), - lock_reg); - } else { - Label done; - - const Register swap_reg = rax; // Must use rax for cmpxchg instruction - const Register header_reg = c_rarg2; // Will contain the old oopMark - const Register obj_reg = c_rarg3; // Will contain the oop - - save_bcp(); // Save in case of exception - - // Convert from BasicObjectLock structure to object and BasicLock - // structure Store the BasicLock address into %rax - lea(swap_reg, Address(lock_reg, BasicObjectLock::lock_offset_in_bytes())); - - // Load oop into obj_reg(%c_rarg3) - movptr(obj_reg, Address(lock_reg, BasicObjectLock::obj_offset_in_bytes())); - - // Free entry - movptr(Address(lock_reg, BasicObjectLock::obj_offset_in_bytes()), (int32_t)NULL_WORD); - - if (UseBiasedLocking) { - biased_locking_exit(obj_reg, header_reg, done); - } - - // Load the old header from BasicLock structure - movptr(header_reg, Address(swap_reg, - BasicLock::displaced_header_offset_in_bytes())); - - // Test for recursion - testptr(header_reg, header_reg); - - // zero for recursive case - jcc(Assembler::zero, done); - - // Atomic swap back the old header - if (os::is_MP()) lock(); - cmpxchgptr(header_reg, Address(obj_reg, 0)); - - // zero for recursive case - jcc(Assembler::zero, done); - - // Call the runtime routine for slow case. - movptr(Address(lock_reg, BasicObjectLock::obj_offset_in_bytes()), - obj_reg); // restore obj - call_VM(noreg, - CAST_FROM_FN_PTR(address, InterpreterRuntime::monitorexit), - lock_reg); - - bind(done); - - restore_bcp(); - } -} - -#ifndef CC_INTERP - -void InterpreterMacroAssembler::test_method_data_pointer(Register mdp, - Label& zero_continue) { - assert(ProfileInterpreter, "must be profiling interpreter"); - movptr(mdp, Address(rbp, frame::interpreter_frame_mdp_offset * wordSize)); - testptr(mdp, mdp); - jcc(Assembler::zero, zero_continue); -} - - -// Set the method data pointer for the current bcp. -void InterpreterMacroAssembler::set_method_data_pointer_for_bcp() { - assert(ProfileInterpreter, "must be profiling interpreter"); - Label set_mdp; - push(rax); - push(rbx); - - get_method(rbx); - // Test MDO to avoid the call if it is NULL. - movptr(rax, Address(rbx, in_bytes(Method::method_data_offset()))); - testptr(rax, rax); - jcc(Assembler::zero, set_mdp); - // rbx: method - // r13: bcp - call_VM_leaf(CAST_FROM_FN_PTR(address, InterpreterRuntime::bcp_to_di), rbx, r13); - // rax: mdi - // mdo is guaranteed to be non-zero here, we checked for it before the call. - movptr(rbx, Address(rbx, in_bytes(Method::method_data_offset()))); - addptr(rbx, in_bytes(MethodData::data_offset())); - addptr(rax, rbx); - bind(set_mdp); - movptr(Address(rbp, frame::interpreter_frame_mdp_offset * wordSize), rax); - pop(rbx); - pop(rax); -} - -void InterpreterMacroAssembler::verify_method_data_pointer() { - assert(ProfileInterpreter, "must be profiling interpreter"); -#ifdef ASSERT - Label verify_continue; - push(rax); - push(rbx); - push(c_rarg3); - push(c_rarg2); - test_method_data_pointer(c_rarg3, verify_continue); // If mdp is zero, continue - get_method(rbx); - - // If the mdp is valid, it will point to a DataLayout header which is - // consistent with the bcp. The converse is highly probable also. - load_unsigned_short(c_rarg2, - Address(c_rarg3, in_bytes(DataLayout::bci_offset()))); - addptr(c_rarg2, Address(rbx, Method::const_offset())); - lea(c_rarg2, Address(c_rarg2, ConstMethod::codes_offset())); - cmpptr(c_rarg2, r13); - jcc(Assembler::equal, verify_continue); - // rbx: method - // r13: bcp - // c_rarg3: mdp - call_VM_leaf(CAST_FROM_FN_PTR(address, InterpreterRuntime::verify_mdp), - rbx, r13, c_rarg3); - bind(verify_continue); - pop(c_rarg2); - pop(c_rarg3); - pop(rbx); - pop(rax); -#endif // ASSERT -} - - -void InterpreterMacroAssembler::set_mdp_data_at(Register mdp_in, - int constant, - Register value) { - assert(ProfileInterpreter, "must be profiling interpreter"); - Address data(mdp_in, constant); - movptr(data, value); -} - - -void InterpreterMacroAssembler::increment_mdp_data_at(Register mdp_in, - int constant, - bool decrement) { - // Counter address - Address data(mdp_in, constant); - - increment_mdp_data_at(data, decrement); -} - -void InterpreterMacroAssembler::increment_mdp_data_at(Address data, - bool decrement) { - assert(ProfileInterpreter, "must be profiling interpreter"); - // %%% this does 64bit counters at best it is wasting space - // at worst it is a rare bug when counters overflow - - if (decrement) { - // Decrement the register. Set condition codes. - addptr(data, (int32_t) -DataLayout::counter_increment); - // If the decrement causes the counter to overflow, stay negative - Label L; - jcc(Assembler::negative, L); - addptr(data, (int32_t) DataLayout::counter_increment); - bind(L); - } else { - assert(DataLayout::counter_increment == 1, - "flow-free idiom only works with 1"); - // Increment the register. Set carry flag. - addptr(data, DataLayout::counter_increment); - // If the increment causes the counter to overflow, pull back by 1. - sbbptr(data, (int32_t)0); - } -} - - -void InterpreterMacroAssembler::increment_mdp_data_at(Register mdp_in, - Register reg, - int constant, - bool decrement) { - Address data(mdp_in, reg, Address::times_1, constant); - - increment_mdp_data_at(data, decrement); -} - -void InterpreterMacroAssembler::set_mdp_flag_at(Register mdp_in, - int flag_byte_constant) { - assert(ProfileInterpreter, "must be profiling interpreter"); - int header_offset = in_bytes(DataLayout::header_offset()); - int header_bits = DataLayout::flag_mask_to_header_mask(flag_byte_constant); - // Set the flag - orl(Address(mdp_in, header_offset), header_bits); -} - - - -void InterpreterMacroAssembler::test_mdp_data_at(Register mdp_in, - int offset, - Register value, - Register test_value_out, - Label& not_equal_continue) { - assert(ProfileInterpreter, "must be profiling interpreter"); - if (test_value_out == noreg) { - cmpptr(value, Address(mdp_in, offset)); - } else { - // Put the test value into a register, so caller can use it: - movptr(test_value_out, Address(mdp_in, offset)); - cmpptr(test_value_out, value); - } - jcc(Assembler::notEqual, not_equal_continue); -} - - -void InterpreterMacroAssembler::update_mdp_by_offset(Register mdp_in, - int offset_of_disp) { - assert(ProfileInterpreter, "must be profiling interpreter"); - Address disp_address(mdp_in, offset_of_disp); - addptr(mdp_in, disp_address); - movptr(Address(rbp, frame::interpreter_frame_mdp_offset * wordSize), mdp_in); -} - - -void InterpreterMacroAssembler::update_mdp_by_offset(Register mdp_in, - Register reg, - int offset_of_disp) { - assert(ProfileInterpreter, "must be profiling interpreter"); - Address disp_address(mdp_in, reg, Address::times_1, offset_of_disp); - addptr(mdp_in, disp_address); - movptr(Address(rbp, frame::interpreter_frame_mdp_offset * wordSize), mdp_in); -} - - -void InterpreterMacroAssembler::update_mdp_by_constant(Register mdp_in, - int constant) { - assert(ProfileInterpreter, "must be profiling interpreter"); - addptr(mdp_in, constant); - movptr(Address(rbp, frame::interpreter_frame_mdp_offset * wordSize), mdp_in); -} - - -void InterpreterMacroAssembler::update_mdp_for_ret(Register return_bci) { - assert(ProfileInterpreter, "must be profiling interpreter"); - push(return_bci); // save/restore across call_VM - call_VM(noreg, - CAST_FROM_FN_PTR(address, InterpreterRuntime::update_mdp_for_ret), - return_bci); - pop(return_bci); -} - - -void InterpreterMacroAssembler::profile_taken_branch(Register mdp, - Register bumped_count) { - if (ProfileInterpreter) { - Label profile_continue; - - // If no method data exists, go to profile_continue. - // Otherwise, assign to mdp - test_method_data_pointer(mdp, profile_continue); - - // We are taking a branch. Increment the taken count. - // We inline increment_mdp_data_at to return bumped_count in a register - //increment_mdp_data_at(mdp, in_bytes(JumpData::taken_offset())); - Address data(mdp, in_bytes(JumpData::taken_offset())); - movptr(bumped_count, data); - assert(DataLayout::counter_increment == 1, - "flow-free idiom only works with 1"); - addptr(bumped_count, DataLayout::counter_increment); - sbbptr(bumped_count, 0); - movptr(data, bumped_count); // Store back out - - // The method data pointer needs to be updated to reflect the new target. - update_mdp_by_offset(mdp, in_bytes(JumpData::displacement_offset())); - bind(profile_continue); - } -} - - -void InterpreterMacroAssembler::profile_not_taken_branch(Register mdp) { - if (ProfileInterpreter) { - Label profile_continue; - - // If no method data exists, go to profile_continue. - test_method_data_pointer(mdp, profile_continue); - - // We are taking a branch. Increment the not taken count. - increment_mdp_data_at(mdp, in_bytes(BranchData::not_taken_offset())); - - // The method data pointer needs to be updated to correspond to - // the next bytecode - update_mdp_by_constant(mdp, in_bytes(BranchData::branch_data_size())); - bind(profile_continue); - } -} - -void InterpreterMacroAssembler::profile_call(Register mdp) { - if (ProfileInterpreter) { - Label profile_continue; - - // If no method data exists, go to profile_continue. - test_method_data_pointer(mdp, profile_continue); - - // We are making a call. Increment the count. - increment_mdp_data_at(mdp, in_bytes(CounterData::count_offset())); - - // The method data pointer needs to be updated to reflect the new target. - update_mdp_by_constant(mdp, in_bytes(CounterData::counter_data_size())); - bind(profile_continue); - } -} - - -void InterpreterMacroAssembler::profile_final_call(Register mdp) { - if (ProfileInterpreter) { - Label profile_continue; - - // If no method data exists, go to profile_continue. - test_method_data_pointer(mdp, profile_continue); - - // We are making a call. Increment the count. - increment_mdp_data_at(mdp, in_bytes(CounterData::count_offset())); - - // The method data pointer needs to be updated to reflect the new target. - update_mdp_by_constant(mdp, - in_bytes(VirtualCallData:: - virtual_call_data_size())); - bind(profile_continue); - } -} - - -void InterpreterMacroAssembler::profile_virtual_call(Register receiver, - Register mdp, - Register reg2, - bool receiver_can_be_null) { - if (ProfileInterpreter) { - Label profile_continue; - - // If no method data exists, go to profile_continue. - test_method_data_pointer(mdp, profile_continue); - - Label skip_receiver_profile; - if (receiver_can_be_null) { - Label not_null; - testptr(receiver, receiver); - jccb(Assembler::notZero, not_null); - // We are making a call. Increment the count for null receiver. - increment_mdp_data_at(mdp, in_bytes(CounterData::count_offset())); - jmp(skip_receiver_profile); - bind(not_null); - } - - // Record the receiver type. - record_klass_in_profile(receiver, mdp, reg2, true); - bind(skip_receiver_profile); - - // The method data pointer needs to be updated to reflect the new target. - update_mdp_by_constant(mdp, - in_bytes(VirtualCallData:: - virtual_call_data_size())); - bind(profile_continue); - } -} - -// This routine creates a state machine for updating the multi-row -// type profile at a virtual call site (or other type-sensitive bytecode). -// The machine visits each row (of receiver/count) until the receiver type -// is found, or until it runs out of rows. At the same time, it remembers -// the location of the first empty row. (An empty row records null for its -// receiver, and can be allocated for a newly-observed receiver type.) -// Because there are two degrees of freedom in the state, a simple linear -// search will not work; it must be a decision tree. Hence this helper -// function is recursive, to generate the required tree structured code. -// It's the interpreter, so we are trading off code space for speed. -// See below for example code. -void InterpreterMacroAssembler::record_klass_in_profile_helper( - Register receiver, Register mdp, - Register reg2, int start_row, - Label& done, bool is_virtual_call) { - if (TypeProfileWidth == 0) { - if (is_virtual_call) { - increment_mdp_data_at(mdp, in_bytes(CounterData::count_offset())); - } - return; - } - - int last_row = VirtualCallData::row_limit() - 1; - assert(start_row <= last_row, "must be work left to do"); - // Test this row for both the receiver and for null. - // Take any of three different outcomes: - // 1. found receiver => increment count and goto done - // 2. found null => keep looking for case 1, maybe allocate this cell - // 3. found something else => keep looking for cases 1 and 2 - // Case 3 is handled by a recursive call. - for (int row = start_row; row <= last_row; row++) { - Label next_test; - bool test_for_null_also = (row == start_row); - - // See if the receiver is receiver[n]. - int recvr_offset = in_bytes(VirtualCallData::receiver_offset(row)); - test_mdp_data_at(mdp, recvr_offset, receiver, - (test_for_null_also ? reg2 : noreg), - next_test); - // (Reg2 now contains the receiver from the CallData.) - - // The receiver is receiver[n]. Increment count[n]. - int count_offset = in_bytes(VirtualCallData::receiver_count_offset(row)); - increment_mdp_data_at(mdp, count_offset); - jmp(done); - bind(next_test); - - if (test_for_null_also) { - Label found_null; - // Failed the equality check on receiver[n]... Test for null. - testptr(reg2, reg2); - if (start_row == last_row) { - // The only thing left to do is handle the null case. - if (is_virtual_call) { - jccb(Assembler::zero, found_null); - // Receiver did not match any saved receiver and there is no empty row for it. - // Increment total counter to indicate polymorphic case. - increment_mdp_data_at(mdp, in_bytes(CounterData::count_offset())); - jmp(done); - bind(found_null); - } else { - jcc(Assembler::notZero, done); - } - break; - } - // Since null is rare, make it be the branch-taken case. - jcc(Assembler::zero, found_null); - - // Put all the "Case 3" tests here. - record_klass_in_profile_helper(receiver, mdp, reg2, start_row + 1, done, is_virtual_call); - - // Found a null. Keep searching for a matching receiver, - // but remember that this is an empty (unused) slot. - bind(found_null); - } - } - - // In the fall-through case, we found no matching receiver, but we - // observed the receiver[start_row] is NULL. - - // Fill in the receiver field and increment the count. - int recvr_offset = in_bytes(VirtualCallData::receiver_offset(start_row)); - set_mdp_data_at(mdp, recvr_offset, receiver); - int count_offset = in_bytes(VirtualCallData::receiver_count_offset(start_row)); - movl(reg2, DataLayout::counter_increment); - set_mdp_data_at(mdp, count_offset, reg2); - if (start_row > 0) { - jmp(done); - } -} - -// Example state machine code for three profile rows: -// // main copy of decision tree, rooted at row[1] -// if (row[0].rec == rec) { row[0].incr(); goto done; } -// if (row[0].rec != NULL) { -// // inner copy of decision tree, rooted at row[1] -// if (row[1].rec == rec) { row[1].incr(); goto done; } -// if (row[1].rec != NULL) { -// // degenerate decision tree, rooted at row[2] -// if (row[2].rec == rec) { row[2].incr(); goto done; } -// if (row[2].rec != NULL) { count.incr(); goto done; } // overflow -// row[2].init(rec); goto done; -// } else { -// // remember row[1] is empty -// if (row[2].rec == rec) { row[2].incr(); goto done; } -// row[1].init(rec); goto done; -// } -// } else { -// // remember row[0] is empty -// if (row[1].rec == rec) { row[1].incr(); goto done; } -// if (row[2].rec == rec) { row[2].incr(); goto done; } -// row[0].init(rec); goto done; -// } -// done: - -void InterpreterMacroAssembler::record_klass_in_profile(Register receiver, - Register mdp, Register reg2, - bool is_virtual_call) { - assert(ProfileInterpreter, "must be profiling"); - Label done; - - record_klass_in_profile_helper(receiver, mdp, reg2, 0, done, is_virtual_call); - - bind (done); -} - -void InterpreterMacroAssembler::profile_ret(Register return_bci, - Register mdp) { - if (ProfileInterpreter) { - Label profile_continue; - uint row; - - // If no method data exists, go to profile_continue. - test_method_data_pointer(mdp, profile_continue); - - // Update the total ret count. - increment_mdp_data_at(mdp, in_bytes(CounterData::count_offset())); - - for (row = 0; row < RetData::row_limit(); row++) { - Label next_test; - - // See if return_bci is equal to bci[n]: - test_mdp_data_at(mdp, - in_bytes(RetData::bci_offset(row)), - return_bci, noreg, - next_test); - - // return_bci is equal to bci[n]. Increment the count. - increment_mdp_data_at(mdp, in_bytes(RetData::bci_count_offset(row))); - - // The method data pointer needs to be updated to reflect the new target. - update_mdp_by_offset(mdp, - in_bytes(RetData::bci_displacement_offset(row))); - jmp(profile_continue); - bind(next_test); - } - - update_mdp_for_ret(return_bci); - - bind(profile_continue); - } -} - - -void InterpreterMacroAssembler::profile_null_seen(Register mdp) { - if (ProfileInterpreter) { - Label profile_continue; - - // If no method data exists, go to profile_continue. - test_method_data_pointer(mdp, profile_continue); - - set_mdp_flag_at(mdp, BitData::null_seen_byte_constant()); - - // The method data pointer needs to be updated. - int mdp_delta = in_bytes(BitData::bit_data_size()); - if (TypeProfileCasts) { - mdp_delta = in_bytes(VirtualCallData::virtual_call_data_size()); - } - update_mdp_by_constant(mdp, mdp_delta); - - bind(profile_continue); - } -} - - -void InterpreterMacroAssembler::profile_typecheck_failed(Register mdp) { - if (ProfileInterpreter && TypeProfileCasts) { - Label profile_continue; - - // If no method data exists, go to profile_continue. - test_method_data_pointer(mdp, profile_continue); - - int count_offset = in_bytes(CounterData::count_offset()); - // Back up the address, since we have already bumped the mdp. - count_offset -= in_bytes(VirtualCallData::virtual_call_data_size()); - - // *Decrement* the counter. We expect to see zero or small negatives. - increment_mdp_data_at(mdp, count_offset, true); - - bind (profile_continue); - } -} - - -void InterpreterMacroAssembler::profile_typecheck(Register mdp, Register klass, Register reg2) { - if (ProfileInterpreter) { - Label profile_continue; - - // If no method data exists, go to profile_continue. - test_method_data_pointer(mdp, profile_continue); - - // The method data pointer needs to be updated. - int mdp_delta = in_bytes(BitData::bit_data_size()); - if (TypeProfileCasts) { - mdp_delta = in_bytes(VirtualCallData::virtual_call_data_size()); - - // Record the object type. - record_klass_in_profile(klass, mdp, reg2, false); - } - update_mdp_by_constant(mdp, mdp_delta); - - bind(profile_continue); - } -} - - -void InterpreterMacroAssembler::profile_switch_default(Register mdp) { - if (ProfileInterpreter) { - Label profile_continue; - - // If no method data exists, go to profile_continue. - test_method_data_pointer(mdp, profile_continue); - - // Update the default case count - increment_mdp_data_at(mdp, - in_bytes(MultiBranchData::default_count_offset())); - - // The method data pointer needs to be updated. - update_mdp_by_offset(mdp, - in_bytes(MultiBranchData:: - default_displacement_offset())); - - bind(profile_continue); - } -} - - -void InterpreterMacroAssembler::profile_switch_case(Register index, - Register mdp, - Register reg2) { - if (ProfileInterpreter) { - Label profile_continue; - - // If no method data exists, go to profile_continue. - test_method_data_pointer(mdp, profile_continue); - - // Build the base (index * per_case_size_in_bytes()) + - // case_array_offset_in_bytes() - movl(reg2, in_bytes(MultiBranchData::per_case_size())); - imulptr(index, reg2); // XXX l ? - addptr(index, in_bytes(MultiBranchData::case_array_offset())); // XXX l ? - - // Update the case count - increment_mdp_data_at(mdp, - index, - in_bytes(MultiBranchData::relative_count_offset())); - - // The method data pointer needs to be updated. - update_mdp_by_offset(mdp, - index, - in_bytes(MultiBranchData:: - relative_displacement_offset())); - - bind(profile_continue); - } -} - - - -void InterpreterMacroAssembler::verify_oop(Register reg, TosState state) { - if (state == atos) { - MacroAssembler::verify_oop(reg); - } -} - -void InterpreterMacroAssembler::verify_FPU(int stack_depth, TosState state) { -} - -// Jump if ((*counter_addr += increment) & mask) satisfies the condition. -void InterpreterMacroAssembler::increment_mask_and_jump(Address counter_addr, - int increment, Address mask, - Register scratch, bool preloaded, - Condition cond, Label* where) { - if (!preloaded) { - movl(scratch, counter_addr); - } - incrementl(scratch, increment); - movl(counter_addr, scratch); - andl(scratch, mask); - jcc(cond, *where); -} -#endif // !CC_INTERP - - -void InterpreterMacroAssembler::notify_method_entry() { - // Whenever JVMTI is interp_only_mode, method entry/exit events are sent to - // track stack depth. If it is possible to enter interp_only_mode we add - // the code to check if the event should be sent. - if (JvmtiExport::can_post_interpreter_events()) { - Label L; - movl(rdx, Address(r15_thread, JavaThread::interp_only_mode_offset())); - testl(rdx, rdx); - jcc(Assembler::zero, L); - call_VM(noreg, CAST_FROM_FN_PTR(address, - InterpreterRuntime::post_method_entry)); - bind(L); - } - - { - SkipIfEqual skip(this, &DTraceMethodProbes, false); - get_method(c_rarg1); - call_VM_leaf(CAST_FROM_FN_PTR(address, SharedRuntime::dtrace_method_entry), - r15_thread, c_rarg1); - } - - // RedefineClasses() tracing support for obsolete method entry - if (RC_TRACE_IN_RANGE(0x00001000, 0x00002000)) { - get_method(c_rarg1); - call_VM_leaf( - CAST_FROM_FN_PTR(address, SharedRuntime::rc_trace_method_entry), - r15_thread, c_rarg1); - } -} - - -void InterpreterMacroAssembler::notify_method_exit( - TosState state, NotifyMethodExitMode mode) { - // Whenever JVMTI is interp_only_mode, method entry/exit events are sent to - // track stack depth. If it is possible to enter interp_only_mode we add - // the code to check if the event should be sent. - if (mode == NotifyJVMTI && JvmtiExport::can_post_interpreter_events()) { - Label L; - // Note: frame::interpreter_frame_result has a dependency on how the - // method result is saved across the call to post_method_exit. If this - // is changed then the interpreter_frame_result implementation will - // need to be updated too. - - // For c++ interpreter the result is always stored at a known location in the frame - // template interpreter will leave it on the top of the stack. - NOT_CC_INTERP(push(state);) - movl(rdx, Address(r15_thread, JavaThread::interp_only_mode_offset())); - testl(rdx, rdx); - jcc(Assembler::zero, L); - call_VM(noreg, - CAST_FROM_FN_PTR(address, InterpreterRuntime::post_method_exit)); - bind(L); - NOT_CC_INTERP(pop(state)); - } - - { - SkipIfEqual skip(this, &DTraceMethodProbes, false); - NOT_CC_INTERP(push(state)); - get_method(c_rarg1); - call_VM_leaf(CAST_FROM_FN_PTR(address, SharedRuntime::dtrace_method_exit), - r15_thread, c_rarg1); - NOT_CC_INTERP(pop(state)); - } -} - diff -r 8c1cc431f388 -r 889895365eb9 hotspot/src/cpu/x86/vm/interp_masm_x86_64.hpp --- a/hotspot/src/cpu/x86/vm/interp_masm_x86_64.hpp Fri Mar 20 17:39:29 2015 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,240 +0,0 @@ -/* - * Copyright (c) 2003, 2014, 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. - * - */ - -#ifndef CC_INTERP - protected: - // Interpreter specific version of call_VM_base - virtual void call_VM_leaf_base(address entry_point, - int number_of_arguments); - - virtual void call_VM_base(Register oop_result, - Register java_thread, - Register last_java_sp, - address entry_point, - int number_of_arguments, - bool check_exceptions); - - virtual void check_and_handle_popframe(Register java_thread); - virtual void check_and_handle_earlyret(Register java_thread); - - // base routine for all dispatches - void dispatch_base(TosState state, address* table, bool verifyoop = true); -#endif // CC_INTERP - - public: - InterpreterMacroAssembler(CodeBuffer* code) : MacroAssembler(code), _locals_register(r14), _bcp_register(r13) {} - - void load_earlyret_value(TosState state); - -#ifdef CC_INTERP - void save_bcp() { /* not needed in c++ interpreter and harmless */ } - void restore_bcp() { /* not needed in c++ interpreter and harmless */ } - - // Helpers for runtime call arguments/results - void get_method(Register reg); - -#else - - // Interpreter-specific registers - void save_bcp() { - movptr(Address(rbp, frame::interpreter_frame_bcp_offset * wordSize), r13); - } - - void restore_bcp() { - movptr(r13, Address(rbp, frame::interpreter_frame_bcp_offset * wordSize)); - } - - void restore_locals() { - movptr(r14, Address(rbp, frame::interpreter_frame_locals_offset * wordSize)); - } - - // Helpers for runtime call arguments/results - void get_method(Register reg) { - movptr(reg, Address(rbp, frame::interpreter_frame_method_offset * wordSize)); - } - - void get_const(Register reg) { - get_method(reg); - movptr(reg, Address(reg, Method::const_offset())); - } - - void get_constant_pool(Register reg) { - get_const(reg); - movptr(reg, Address(reg, ConstMethod::constants_offset())); - } - - void get_constant_pool_cache(Register reg) { - get_constant_pool(reg); - movptr(reg, Address(reg, ConstantPool::cache_offset_in_bytes())); - } - - void get_cpool_and_tags(Register cpool, Register tags) { - get_constant_pool(cpool); - movptr(tags, Address(cpool, ConstantPool::tags_offset_in_bytes())); - } - - void get_unsigned_2_byte_index_at_bcp(Register reg, int bcp_offset); - void get_cache_and_index_at_bcp(Register cache, Register index, int bcp_offset, size_t index_size = sizeof(u2)); - void get_cache_and_index_and_bytecode_at_bcp(Register cache, Register index, Register bytecode, int byte_no, int bcp_offset, size_t index_size = sizeof(u2)); - void get_cache_entry_pointer_at_bcp(Register cache, Register tmp, int bcp_offset, size_t index_size = sizeof(u2)); - void get_cache_index_at_bcp(Register index, int bcp_offset, size_t index_size = sizeof(u2)); - - // load cpool->resolved_references(index); - void load_resolved_reference_at_index(Register result, Register index); - - void pop_ptr(Register r = rax); - void pop_i(Register r = rax); - void pop_l(Register r = rax); - void pop_f(XMMRegister r = xmm0); - void pop_d(XMMRegister r = xmm0); - void push_ptr(Register r = rax); - void push_i(Register r = rax); - void push_l(Register r = rax); - void push_f(XMMRegister r = xmm0); - void push_d(XMMRegister r = xmm0); - - void pop(Register r ) { ((MacroAssembler*)this)->pop(r); } - - void push(Register r ) { ((MacroAssembler*)this)->push(r); } - void push(int32_t imm ) { ((MacroAssembler*)this)->push(imm); } - - void pop(TosState state); // transition vtos -> state - void push(TosState state); // transition state -> vtos - - void empty_expression_stack() { - movptr(rsp, Address(rbp, frame::interpreter_frame_monitor_block_top_offset * wordSize)); - // NULL last_sp until next java call - movptr(Address(rbp, frame::interpreter_frame_last_sp_offset * wordSize), (int32_t)NULL_WORD); - } - - // Helpers for swap and dup - void load_ptr(int n, Register val); - void store_ptr(int n, Register val); - - // Generate a subtype check: branch to ok_is_subtype if sub_klass is - // a subtype of super_klass. - void gen_subtype_check( Register sub_klass, Label &ok_is_subtype ); - - // Dispatching - void dispatch_prolog(TosState state, int step = 0); - void dispatch_epilog(TosState state, int step = 0); - // dispatch via ebx (assume ebx is loaded already) - void dispatch_only(TosState state); - // dispatch normal table via ebx (assume ebx is loaded already) - void dispatch_only_normal(TosState state); - void dispatch_only_noverify(TosState state); - // load ebx from [esi + step] and dispatch via ebx - void dispatch_next(TosState state, int step = 0); - // load ebx from [esi] and dispatch via ebx and table - void dispatch_via (TosState state, address* table); - - // jump to an invoked target - void prepare_to_jump_from_interpreted(); - void jump_from_interpreted(Register method, Register temp); - - - // Returning from interpreted functions - // - // Removes the current activation (incl. unlocking of monitors) - // and sets up the return address. This code is also used for - // exception unwindwing. In that case, we do not want to throw - // IllegalMonitorStateExceptions, since that might get us into an - // infinite rethrow exception loop. - // Additionally this code is used for popFrame and earlyReturn. - // In popFrame case we want to skip throwing an exception, - // installing an exception, and notifying jvmdi. - // In earlyReturn case we only want to skip throwing an exception - // and installing an exception. - void remove_activation(TosState state, Register ret_addr, - bool throw_monitor_exception = true, - bool install_monitor_exception = true, - bool notify_jvmdi = true); -#endif // CC_INTERP - void get_method_counters(Register method, Register mcs, Label& skip); - - // Object locking - void lock_object (Register lock_reg); - void unlock_object(Register lock_reg); - -#ifndef CC_INTERP - - // Interpreter profiling operations - void set_method_data_pointer_for_bcp(); - void test_method_data_pointer(Register mdp, Label& zero_continue); - void verify_method_data_pointer(); - - void set_mdp_data_at(Register mdp_in, int constant, Register value); - void increment_mdp_data_at(Address data, bool decrement = false); - void increment_mdp_data_at(Register mdp_in, int constant, - bool decrement = false); - void increment_mdp_data_at(Register mdp_in, Register reg, int constant, - bool decrement = false); - void increment_mask_and_jump(Address counter_addr, - int increment, Address mask, - Register scratch, bool preloaded, - Condition cond, Label* where); - void set_mdp_flag_at(Register mdp_in, int flag_constant); - void test_mdp_data_at(Register mdp_in, int offset, Register value, - Register test_value_out, - Label& not_equal_continue); - - void record_klass_in_profile(Register receiver, Register mdp, - Register reg2, bool is_virtual_call); - void record_klass_in_profile_helper(Register receiver, Register mdp, - Register reg2, int start_row, - Label& done, bool is_virtual_call); - - void update_mdp_by_offset(Register mdp_in, int offset_of_offset); - void update_mdp_by_offset(Register mdp_in, Register reg, int offset_of_disp); - void update_mdp_by_constant(Register mdp_in, int constant); - void update_mdp_for_ret(Register return_bci); - - void profile_taken_branch(Register mdp, Register bumped_count); - void profile_not_taken_branch(Register mdp); - void profile_call(Register mdp); - void profile_final_call(Register mdp); - void profile_virtual_call(Register receiver, Register mdp, - Register scratch2, - bool receiver_can_be_null = false); - void profile_ret(Register return_bci, Register mdp); - void profile_null_seen(Register mdp); - void profile_typecheck(Register mdp, Register klass, Register scratch); - void profile_typecheck_failed(Register mdp); - void profile_switch_default(Register mdp); - void profile_switch_case(Register index_in_scratch, Register mdp, - Register scratch2); - - // Debugging - // only if +VerifyOops && state == atos - void verify_oop(Register reg, TosState state = atos); - // only if +VerifyFPU && (state == ftos || state == dtos) - void verify_FPU(int stack_depth, TosState state = ftos); - -#endif // !CC_INTERP - - typedef enum { NotifyJVMTI, SkipNotifyJVMTI } NotifyMethodExitMode; - - // support for jvmti/dtrace - void notify_method_entry(); - void notify_method_exit(TosState state, NotifyMethodExitMode mode); diff -r 8c1cc431f388 -r 889895365eb9 hotspot/src/os/aix/vm/vmError_aix.cpp --- a/hotspot/src/os/aix/vm/vmError_aix.cpp Fri Mar 20 17:39:29 2015 +0000 +++ b/hotspot/src/os/aix/vm/vmError_aix.cpp Mon Mar 23 11:44:41 2015 -0700 @@ -109,7 +109,15 @@ } sigthreadmask(SIG_UNBLOCK, &newset, NULL); - VMError err(NULL, sig, NULL, info, ucVoid); + // support safefetch faults in error handling + ucontext_t* const uc = (ucontext_t*) ucVoid; + address const pc = uc ? os::Aix::ucontext_get_pc(uc) : NULL; + if (uc && pc && StubRoutines::is_safefetch_fault(pc)) { + os::Aix::ucontext_set_pc(uc, StubRoutines::continuation_for_safefetch_fault(pc)); + return; + } + + VMError err(NULL, sig, pc, info, ucVoid); err.report_and_die(); } diff -r 8c1cc431f388 -r 889895365eb9 hotspot/src/os/bsd/vm/os_bsd.hpp --- a/hotspot/src/os/bsd/vm/os_bsd.hpp Fri Mar 20 17:39:29 2015 +0000 +++ b/hotspot/src/os/bsd/vm/os_bsd.hpp Mon Mar 23 11:44:41 2015 -0700 @@ -99,6 +99,7 @@ static void set_page_size(int val) { _page_size = val; } static address ucontext_get_pc(ucontext_t* uc); + static void ucontext_set_pc(ucontext_t* uc, address pc); static intptr_t* ucontext_get_sp(ucontext_t* uc); static intptr_t* ucontext_get_fp(ucontext_t* uc); diff -r 8c1cc431f388 -r 889895365eb9 hotspot/src/os/bsd/vm/vmError_bsd.cpp --- a/hotspot/src/os/bsd/vm/vmError_bsd.cpp Fri Mar 20 17:39:29 2015 +0000 +++ b/hotspot/src/os/bsd/vm/vmError_bsd.cpp Mon Mar 23 11:44:41 2015 -0700 @@ -112,7 +112,16 @@ } pthread_sigmask(SIG_UNBLOCK, &newset, NULL); - VMError err(NULL, sig, NULL, info, ucVoid); + // support safefetch faults in error handling + ucontext_t* const uc = (ucontext_t*) ucVoid; + address const pc = uc ? os::Bsd::ucontext_get_pc(uc) : NULL; + + if (uc && pc && StubRoutines::is_safefetch_fault(pc)) { + os::Bsd::ucontext_set_pc(uc, StubRoutines::continuation_for_safefetch_fault(pc)); + return; + } + + VMError err(NULL, sig, pc, info, ucVoid); err.report_and_die(); } diff -r 8c1cc431f388 -r 889895365eb9 hotspot/src/os/linux/vm/os_linux.cpp --- a/hotspot/src/os/linux/vm/os_linux.cpp Fri Mar 20 17:39:29 2015 +0000 +++ b/hotspot/src/os/linux/vm/os_linux.cpp Mon Mar 23 11:44:41 2015 -0700 @@ -3732,14 +3732,14 @@ // Does this overlap the block we wanted? Give back the overlapped // parts and try again. - size_t top_overlap = requested_addr + (bytes + gap) - base[i]; - if (top_overlap >= 0 && top_overlap < bytes) { + ptrdiff_t top_overlap = requested_addr + (bytes + gap) - base[i]; + if (top_overlap >= 0 && (size_t)top_overlap < bytes) { unmap_memory(base[i], top_overlap); base[i] += top_overlap; size[i] = bytes - top_overlap; } else { - size_t bottom_overlap = base[i] + bytes - requested_addr; - if (bottom_overlap >= 0 && bottom_overlap < bytes) { + ptrdiff_t bottom_overlap = base[i] + bytes - requested_addr; + if (bottom_overlap >= 0 && (size_t)bottom_overlap < bytes) { unmap_memory(requested_addr, bottom_overlap); size[i] = bytes - bottom_overlap; } else { @@ -6003,11 +6003,11 @@ } if (strlen(core_pattern) == 0) { - return 0; + return -1; } char *pid_pos = strstr(core_pattern, "%p"); - size_t written; + int written; if (core_pattern[0] == '/') { written = jio_snprintf(buffer, bufferSize, core_pattern); @@ -6016,8 +6016,7 @@ const char* p = get_current_directory(cwd, PATH_MAX); if (p == NULL) { - assert(p != NULL, "failed to get current directory"); - return 0; + return -1; } if (core_pattern[0] == '|') { @@ -6029,8 +6028,11 @@ } } - if ((written >= 0) && (written < bufferSize) - && (pid_pos == NULL) && (core_pattern[0] != '|')) { + if (written < 0) { + return -1; + } + + if (((size_t)written < bufferSize) && (pid_pos == NULL) && (core_pattern[0] != '|')) { int core_uses_pid_file = ::open("/proc/sys/kernel/core_uses_pid", O_RDONLY); if (core_uses_pid_file != -1) { @@ -6038,7 +6040,7 @@ ssize_t ret = ::read(core_uses_pid_file, &core_uses_pid, 1); ::close(core_uses_pid_file); - if (core_uses_pid == '1'){ + if (core_uses_pid == '1') { jio_snprintf(buffer + written, bufferSize - written, ".%d", current_process_id()); } diff -r 8c1cc431f388 -r 889895365eb9 hotspot/src/os/linux/vm/os_linux.hpp --- a/hotspot/src/os/linux/vm/os_linux.hpp Fri Mar 20 17:39:29 2015 +0000 +++ b/hotspot/src/os/linux/vm/os_linux.hpp Mon Mar 23 11:44:41 2015 -0700 @@ -143,6 +143,7 @@ static int vm_default_page_size(void) { return _vm_default_page_size; } static address ucontext_get_pc(ucontext_t* uc); + static void ucontext_set_pc(ucontext_t* uc, address pc); static intptr_t* ucontext_get_sp(ucontext_t* uc); static intptr_t* ucontext_get_fp(ucontext_t* uc); diff -r 8c1cc431f388 -r 889895365eb9 hotspot/src/os/linux/vm/vmError_linux.cpp --- a/hotspot/src/os/linux/vm/vmError_linux.cpp Fri Mar 20 17:39:29 2015 +0000 +++ b/hotspot/src/os/linux/vm/vmError_linux.cpp Mon Mar 23 11:44:41 2015 -0700 @@ -112,7 +112,16 @@ } pthread_sigmask(SIG_UNBLOCK, &newset, NULL); - VMError err(NULL, sig, NULL, info, ucVoid); + // support safefetch faults in error handling + ucontext_t* const uc = (ucontext_t*) ucVoid; + address const pc = uc ? os::Linux::ucontext_get_pc(uc) : NULL; + + if (uc && pc && StubRoutines::is_safefetch_fault(pc)) { + os::Linux::ucontext_set_pc(uc, StubRoutines::continuation_for_safefetch_fault(pc)); + return; + } + + VMError err(NULL, sig, pc, info, ucVoid); err.report_and_die(); } diff -r 8c1cc431f388 -r 889895365eb9 hotspot/src/os/solaris/vm/os_solaris.hpp --- a/hotspot/src/os/solaris/vm/os_solaris.hpp Fri Mar 20 17:39:29 2015 +0000 +++ b/hotspot/src/os/solaris/vm/os_solaris.hpp Mon Mar 23 11:44:41 2015 -0700 @@ -137,6 +137,7 @@ // ucontext_get_fp() is only used by Solaris X86 (see note below) static intptr_t* ucontext_get_fp(ucontext_t* uc); static address ucontext_get_pc(ucontext_t* uc); + static void ucontext_set_pc(ucontext_t* uc, address pc); // For Analyzer Forte AsyncGetCallTrace profiling support: // Parameter ret_fp is only used by Solaris X86. diff -r 8c1cc431f388 -r 889895365eb9 hotspot/src/os/solaris/vm/vmError_solaris.cpp --- a/hotspot/src/os/solaris/vm/vmError_solaris.cpp Fri Mar 20 17:39:29 2015 +0000 +++ b/hotspot/src/os/solaris/vm/vmError_solaris.cpp Mon Mar 23 11:44:41 2015 -0700 @@ -109,7 +109,15 @@ } thr_sigsetmask(SIG_UNBLOCK, &newset, NULL); - VMError err(NULL, sig, NULL, info, ucVoid); + // support safefetch faults in error handling + ucontext_t* const uc = (ucontext_t*) ucVoid; + address const pc = uc ? os::Solaris::ucontext_get_pc(uc) : NULL; + if (uc && pc && StubRoutines::is_safefetch_fault(pc)) { + os::Solaris::ucontext_set_pc(uc, StubRoutines::continuation_for_safefetch_fault(pc)); + return; + } + + VMError err(NULL, sig, pc, info, ucVoid); err.report_and_die(); } diff -r 8c1cc431f388 -r 889895365eb9 hotspot/src/os_cpu/aix_ppc/vm/globals_aix_ppc.hpp --- a/hotspot/src/os_cpu/aix_ppc/vm/globals_aix_ppc.hpp Fri Mar 20 17:39:29 2015 +0000 +++ b/hotspot/src/os_cpu/aix_ppc/vm/globals_aix_ppc.hpp Mon Mar 23 11:44:41 2015 -0700 @@ -1,6 +1,6 @@ /* - * Copyright (c) 2002, 2013, Oracle and/or its affiliates. All rights reserved. - * Copyright 2012, 2013 SAP AG. All rights reserved. + * Copyright (c) 2002, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright 2012, 2015 SAP AG. 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 @@ -48,7 +48,5 @@ // Only used on 64 bit platforms define_pd_global(uintx,HeapBaseMinAddress, 2*G); -// Only used on 64 bit Windows platforms -define_pd_global(bool, UseVectoredExceptions, false); #endif // OS_CPU_AIX_OJDKPPC_VM_GLOBALS_AIX_PPC_HPP diff -r 8c1cc431f388 -r 889895365eb9 hotspot/src/os_cpu/aix_ppc/vm/os_aix_ppc.cpp --- a/hotspot/src/os_cpu/aix_ppc/vm/os_aix_ppc.cpp Fri Mar 20 17:39:29 2015 +0000 +++ b/hotspot/src/os_cpu/aix_ppc/vm/os_aix_ppc.cpp Mon Mar 23 11:44:41 2015 -0700 @@ -397,7 +397,7 @@ // continue at the next instruction after the faulting read. Returning // garbage from this read is ok. thread->set_pending_unsafe_access_error(); - uc->uc_mcontext.jmp_context.iar = ((unsigned long)pc) + 4; + os::Aix::ucontext_set_pc(uc, pc + 4); return 1; } } @@ -420,7 +420,7 @@ // continue at the next instruction after the faulting read. Returning // garbage from this read is ok. thread->set_pending_unsafe_access_error(); - uc->uc_mcontext.jmp_context.iar = ((unsigned long)pc) + 4; + os::Aix::ucontext_set_pc(uc, pc + 4); return 1; } } @@ -445,7 +445,7 @@ if (stub != NULL) { // Save all thread context in case we need to restore it. if (thread != NULL) thread->set_saved_exception_pc(pc); - uc->uc_mcontext.jmp_context.iar = (unsigned long)stub; + os::Aix::ucontext_set_pc(uc, stub); return 1; } diff -r 8c1cc431f388 -r 889895365eb9 hotspot/src/os_cpu/bsd_x86/vm/os_bsd_x86.cpp --- a/hotspot/src/os_cpu/bsd_x86/vm/os_bsd_x86.cpp Fri Mar 20 17:39:29 2015 +0000 +++ b/hotspot/src/os_cpu/bsd_x86/vm/os_bsd_x86.cpp Mon Mar 23 11:44:41 2015 -0700 @@ -309,6 +309,10 @@ return (address)uc->context_pc; } +void os::Bsd::ucontext_set_pc(ucontext_t * uc, address pc) { + uc->context_pc = (intptr_t)pc ; +} + intptr_t* os::Bsd::ucontext_get_sp(ucontext_t * uc) { return (intptr_t*)uc->context_sp; } @@ -463,7 +467,7 @@ pc = (address) os::Bsd::ucontext_get_pc(uc); if (StubRoutines::is_safefetch_fault(pc)) { - uc->context_pc = intptr_t(StubRoutines::continuation_for_safefetch_fault(pc)); + os::Bsd::ucontext_set_pc(uc, StubRoutines::continuation_for_safefetch_fault(pc)); return 1; } @@ -703,7 +707,7 @@ // save all thread context in case we need to restore it if (thread != NULL) thread->set_saved_exception_pc(pc); - uc->context_pc = (intptr_t)stub; + os::Bsd::ucontext_set_pc(uc, stub); return true; } diff -r 8c1cc431f388 -r 889895365eb9 hotspot/src/os_cpu/bsd_zero/vm/os_bsd_zero.cpp --- a/hotspot/src/os_cpu/bsd_zero/vm/os_bsd_zero.cpp Fri Mar 20 17:39:29 2015 +0000 +++ b/hotspot/src/os_cpu/bsd_zero/vm/os_bsd_zero.cpp Mon Mar 23 11:44:41 2015 -0700 @@ -107,6 +107,10 @@ return NULL; } +void os::Bsd::ucontext_set_pc(ucontext_t * uc, address pc) { + ShouldNotCallThis(); +} + ExtendedPC os::fetch_frame_from_context(void* ucVoid, intptr_t** ret_sp, intptr_t** ret_fp) { diff -r 8c1cc431f388 -r 889895365eb9 hotspot/src/os_cpu/linux_ppc/vm/globals_linux_ppc.hpp --- a/hotspot/src/os_cpu/linux_ppc/vm/globals_linux_ppc.hpp Fri Mar 20 17:39:29 2015 +0000 +++ b/hotspot/src/os_cpu/linux_ppc/vm/globals_linux_ppc.hpp Mon Mar 23 11:44:41 2015 -0700 @@ -1,6 +1,6 @@ /* - * Copyright (c) 2002, 2013, Oracle and/or its affiliates. All rights reserved. - * Copyright 2012, 2013 SAP AG. All rights reserved. + * Copyright (c) 2002, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright 2012, 2015 SAP AG. 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 @@ -48,7 +48,5 @@ // Only used on 64 bit platforms define_pd_global(uintx,HeapBaseMinAddress, 2*G); -// Only used on 64 bit Windows platforms -define_pd_global(bool, UseVectoredExceptions, false); #endif // OS_CPU_LINUX_PPC_VM_GLOBALS_LINUX_PPC_HPP diff -r 8c1cc431f388 -r 889895365eb9 hotspot/src/os_cpu/linux_ppc/vm/os_linux_ppc.cpp --- a/hotspot/src/os_cpu/linux_ppc/vm/os_linux_ppc.cpp Fri Mar 20 17:39:29 2015 +0000 +++ b/hotspot/src/os_cpu/linux_ppc/vm/os_linux_ppc.cpp Mon Mar 23 11:44:41 2015 -0700 @@ -113,6 +113,14 @@ return (address)uc->uc_mcontext.regs->nip; } +// modify PC in ucontext. +// Note: Only use this for an ucontext handed down to a signal handler. See comment +// in ucontext_get_pc. +void os::Linux::ucontext_set_pc(ucontext_t * uc, address pc) { + guarantee(uc->uc_mcontext.regs != NULL, "only use ucontext_set_pc in sigaction context"); + uc->uc_mcontext.regs->nip = (unsigned long)pc; +} + intptr_t* os::Linux::ucontext_get_sp(ucontext_t * uc) { return (intptr_t*)uc->uc_mcontext.regs->gpr[1/*REG_SP*/]; } @@ -213,7 +221,7 @@ if (uc) { address const pc = os::Linux::ucontext_get_pc(uc); if (pc && StubRoutines::is_safefetch_fault(pc)) { - uc->uc_mcontext.regs->nip = (unsigned long)StubRoutines::continuation_for_safefetch_fault(pc); + os::Linux::ucontext_set_pc(uc, StubRoutines::continuation_for_safefetch_fault(pc)); return true; } } @@ -360,7 +368,7 @@ // continue at the next instruction after the faulting read. Returning // garbage from this read is ok. thread->set_pending_unsafe_access_error(); - uc->uc_mcontext.regs->nip = ((unsigned long)pc) + 4; + os::Linux::ucontext_set_pc(uc, pc + 4); return true; } } @@ -379,7 +387,7 @@ // continue at the next instruction after the faulting read. Returning // garbage from this read is ok. thread->set_pending_unsafe_access_error(); - uc->uc_mcontext.regs->nip = ((unsigned long)pc) + 4; + os::Linux::ucontext_set_pc(uc, pc + 4); return true; } } @@ -402,7 +410,7 @@ if (stub != NULL) { // Save all thread context in case we need to restore it. if (thread != NULL) thread->set_saved_exception_pc(pc); - uc->uc_mcontext.regs->nip = (unsigned long)stub; + os::Linux::ucontext_set_pc(uc, stub); return true; } diff -r 8c1cc431f388 -r 889895365eb9 hotspot/src/os_cpu/linux_sparc/vm/os_linux_sparc.cpp --- a/hotspot/src/os_cpu/linux_sparc/vm/os_linux_sparc.cpp Fri Mar 20 17:39:29 2015 +0000 +++ b/hotspot/src/os_cpu/linux_sparc/vm/os_linux_sparc.cpp Mon Mar 23 11:44:41 2015 -0700 @@ -85,11 +85,6 @@ CON_O7, }; -static inline void set_cont_address(sigcontext* ctx, address addr) { - SIG_PC(ctx) = (intptr_t)addr; - SIG_NPC(ctx) = (intptr_t)(addr+4); -} - // For Forte Analyzer AsyncGetCallTrace profiling support - thread is // currently interrupted by SIGPROF. // os::Solaris::fetch_frame_from_ucontext() tries to skip nested @@ -351,6 +346,12 @@ return (address) SIG_PC((sigcontext*)uc); } +void os::Linux::ucontext_set_pc(ucontext_t* uc, address pc) { + sigcontext_t* ctx = (sigcontext_t*) uc; + SIG_PC(ctx) = (intptr_t)addr; + SIG_NPC(ctx) = (intptr_t)(addr+4); +} + intptr_t* os::Linux::ucontext_get_sp(ucontext_t *uc) { return (intptr_t*) ((intptr_t)SIG_REGS((sigcontext*)uc).u_regs[CON_O6] + STACK_BIAS); @@ -366,7 +367,7 @@ inline static bool checkPrefetch(sigcontext* uc, address pc) { if (StubRoutines::is_safefetch_fault(pc)) { - set_cont_address(uc, address(StubRoutines::continuation_for_safefetch_fault(pc))); + os::Linux::ucontext_set_pc((ucontext_t*)uc, StubRoutines::continuation_for_safefetch_fault(pc)); return true; } return false; @@ -666,7 +667,7 @@ // save all thread context in case we need to restore it thread->set_saved_exception_pc(pc); thread->set_saved_exception_npc(npc); - set_cont_address(uc, stub); + os::Linux::ucontext_set_pc((ucontext_t*)uc, stub); return true; } } diff -r 8c1cc431f388 -r 889895365eb9 hotspot/src/os_cpu/linux_x86/vm/os_linux_x86.cpp --- a/hotspot/src/os_cpu/linux_x86/vm/os_linux_x86.cpp Fri Mar 20 17:39:29 2015 +0000 +++ b/hotspot/src/os_cpu/linux_x86/vm/os_linux_x86.cpp Mon Mar 23 11:44:41 2015 -0700 @@ -122,6 +122,10 @@ return (address)uc->uc_mcontext.gregs[REG_PC]; } +void os::Linux::ucontext_set_pc(ucontext_t * uc, address pc) { + uc->uc_mcontext.gregs[REG_PC] = (intptr_t)pc; +} + intptr_t* os::Linux::ucontext_get_sp(ucontext_t * uc) { return (intptr_t*)uc->uc_mcontext.gregs[REG_SP]; } @@ -279,7 +283,7 @@ pc = (address) os::Linux::ucontext_get_pc(uc); if (StubRoutines::is_safefetch_fault(pc)) { - uc->uc_mcontext.gregs[REG_PC] = intptr_t(StubRoutines::continuation_for_safefetch_fault(pc)); + os::Linux::ucontext_set_pc(uc, StubRoutines::continuation_for_safefetch_fault(pc)); return 1; } @@ -514,7 +518,7 @@ // save all thread context in case we need to restore it if (thread != NULL) thread->set_saved_exception_pc(pc); - uc->uc_mcontext.gregs[REG_PC] = (greg_t)stub; + os::Linux::ucontext_set_pc(uc, stub); return true; } diff -r 8c1cc431f388 -r 889895365eb9 hotspot/src/os_cpu/linux_zero/vm/os_linux_zero.cpp --- a/hotspot/src/os_cpu/linux_zero/vm/os_linux_zero.cpp Fri Mar 20 17:39:29 2015 +0000 +++ b/hotspot/src/os_cpu/linux_zero/vm/os_linux_zero.cpp Mon Mar 23 11:44:41 2015 -0700 @@ -100,6 +100,10 @@ ShouldNotCallThis(); } +void os::Linux::ucontext_set_pc(ucontext_t * uc, address pc) { + ShouldNotCallThis(); +} + ExtendedPC os::fetch_frame_from_context(void* ucVoid, intptr_t** ret_sp, intptr_t** ret_fp) { diff -r 8c1cc431f388 -r 889895365eb9 hotspot/src/os_cpu/solaris_sparc/vm/os_solaris_sparc.cpp --- a/hotspot/src/os_cpu/solaris_sparc/vm/os_solaris_sparc.cpp Fri Mar 20 17:39:29 2015 +0000 +++ b/hotspot/src/os_cpu/solaris_sparc/vm/os_solaris_sparc.cpp Mon Mar 23 11:44:41 2015 -0700 @@ -184,6 +184,11 @@ return ExtendedPC(pc); } +void os::Solaris::ucontext_set_pc(ucontext_t* uc, address pc) { + uc->uc_mcontext.gregs [REG_PC] = (greg_t) pc; + uc->uc_mcontext.gregs [REG_nPC] = (greg_t) (pc + 4); +} + // Assumes ucontext is valid intptr_t* os::Solaris::ucontext_get_sp(ucontext_t *uc) { return (intptr_t*)((intptr_t)uc->uc_mcontext.gregs[REG_SP] + STACK_BIAS); @@ -355,8 +360,7 @@ // SafeFetch() support if (StubRoutines::is_safefetch_fault(pc)) { - uc->uc_mcontext.gregs[REG_PC] = intptr_t(StubRoutines::continuation_for_safefetch_fault(pc)); - uc->uc_mcontext.gregs[REG_nPC] = uc->uc_mcontext.gregs[REG_PC] + 4; + os::Solaris::ucontext_set_pc(uc, StubRoutines::continuation_for_safefetch_fault(pc)); return 1; } @@ -494,8 +498,7 @@ // simulate a branch to the stub (a "call" in the safepoint stub case) // factor me: setPC - uc->uc_mcontext.gregs[REG_PC ] = (greg_t)stub; - uc->uc_mcontext.gregs[REG_nPC] = (greg_t)(stub + 4); + os::Solaris::ucontext_set_pc(uc, stub); #ifndef PRODUCT if (TraceJumps) thread->record_jump(stub, NULL, __FILE__, __LINE__); diff -r 8c1cc431f388 -r 889895365eb9 hotspot/src/os_cpu/solaris_x86/vm/os_solaris_x86.cpp --- a/hotspot/src/os_cpu/solaris_x86/vm/os_solaris_x86.cpp Fri Mar 20 17:39:29 2015 +0000 +++ b/hotspot/src/os_cpu/solaris_x86/vm/os_solaris_x86.cpp Mon Mar 23 11:44:41 2015 -0700 @@ -174,6 +174,10 @@ return ExtendedPC((address)uc->uc_mcontext.gregs[REG_PC]); } +void os::Solaris::ucontext_set_pc(ucontext_t* uc, address pc) { + uc->uc_mcontext.gregs [REG_PC] = (greg_t) pc; +} + // Assumes ucontext is valid intptr_t* os::Solaris::ucontext_get_sp(ucontext_t *uc) { return (intptr_t*)uc->uc_mcontext.gregs[REG_SP]; @@ -411,7 +415,7 @@ pc = (address) uc->uc_mcontext.gregs[REG_PC]; if (StubRoutines::is_safefetch_fault(pc)) { - uc->uc_mcontext.gregs[REG_PC] = intptr_t(StubRoutines::continuation_for_safefetch_fault(pc)); + os::Solaris::ucontext_set_pc(uc, StubRoutines::continuation_for_safefetch_fault(pc)); return true; } @@ -614,8 +618,7 @@ if (thread != NULL) thread->set_saved_exception_pc(pc); // 12/02/99: On Sparc it appears that the full context is also saved // but as yet, no one looks at or restores that saved context - // factor me: setPC - uc->uc_mcontext.gregs[REG_PC] = (greg_t)stub; + os::Solaris::ucontext_set_pc(uc, stub); return true; } diff -r 8c1cc431f388 -r 889895365eb9 hotspot/src/share/vm/asm/codeBuffer.cpp --- a/hotspot/src/share/vm/asm/codeBuffer.cpp Fri Mar 20 17:39:29 2015 +0000 +++ b/hotspot/src/share/vm/asm/codeBuffer.cpp Mon Mar 23 11:44:41 2015 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2015, 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 @@ -926,9 +926,6 @@ void CodeBuffer::take_over_code_from(CodeBuffer* cb) { // Must already have disposed of the old blob somehow. assert(blob() == NULL, "must be empty"); -#ifdef ASSERT - -#endif // Take the new blob away from cb. set_blob(cb->blob()); // Take over all the section pointers. diff -r 8c1cc431f388 -r 889895365eb9 hotspot/src/share/vm/c1/c1_GraphBuilder.cpp --- a/hotspot/src/share/vm/c1/c1_GraphBuilder.cpp Fri Mar 20 17:39:29 2015 +0000 +++ b/hotspot/src/share/vm/c1/c1_GraphBuilder.cpp Mon Mar 23 11:44:41 2015 -0700 @@ -4306,7 +4306,18 @@ log->inline_fail("reason unknown"); } } - +#if INCLUDE_TRACE + EventCompilerInlining event; + if (event.should_commit()) { + event.set_compileID(compilation()->env()->task()->compile_id()); + event.set_message(msg); + event.set_succeeded(success); + event.set_bci(bci()); + event.set_caller(method()->get_Method()); + event.set_callee(callee->to_trace_struct()); + event.commit(); + } +#endif // INCLUDE_TRACE if (!PrintInlining && !compilation()->method()->has_option("PrintInlining")) { return; } diff -r 8c1cc431f388 -r 889895365eb9 hotspot/src/share/vm/ci/ciMethod.cpp --- a/hotspot/src/share/vm/ci/ciMethod.cpp Fri Mar 20 17:39:29 2015 +0000 +++ b/hotspot/src/share/vm/ci/ciMethod.cpp Mon Mar 23 11:44:41 2015 -0700 @@ -48,6 +48,7 @@ #include "runtime/deoptimization.hpp" #include "utilities/bitMap.inline.hpp" #include "utilities/xmlstream.hpp" +#include "trace/tracing.hpp" #ifdef COMPILER2 #include "ci/bcEscapeAnalyzer.hpp" #include "ci/ciTypeFlow.hpp" @@ -1466,3 +1467,13 @@ st->print(" loaded=false"); } } + +#if INCLUDE_TRACE +TraceStructCiMethod ciMethod::to_trace_struct() const { + TraceStructCiMethod result; + result.set_class(holder()->name()->as_utf8()); + result.set_name(name()->as_utf8()); + result.set_signature(signature()->as_symbol()->as_utf8()); + return result; +} +#endif diff -r 8c1cc431f388 -r 889895365eb9 hotspot/src/share/vm/ci/ciMethod.hpp --- a/hotspot/src/share/vm/ci/ciMethod.hpp Fri Mar 20 17:39:29 2015 +0000 +++ b/hotspot/src/share/vm/ci/ciMethod.hpp Mon Mar 23 11:44:41 2015 -0700 @@ -32,13 +32,14 @@ #include "compiler/methodLiveness.hpp" #include "prims/methodHandles.hpp" #include "utilities/bitMap.hpp" +#include "trace/tracing.hpp" class ciMethodBlocks; class MethodLiveness; class BitMap; class Arena; class BCEscapeAnalyzer; - +class InlineTree; // ciMethod // @@ -52,6 +53,7 @@ friend class ciBytecodeStream; friend class ciMethodHandle; friend class ciReplay; + friend class InlineTree; private: // General method information. @@ -95,12 +97,6 @@ ciMethod(methodHandle h_m, ciInstanceKlass* holder); ciMethod(ciInstanceKlass* holder, ciSymbol* name, ciSymbol* signature, ciInstanceKlass* accessor); - Method* get_Method() const { - Method* m = (Method*)_metadata; - assert(m != NULL, "illegal use of unloaded method"); - return m; - } - oop loader() const { return _holder->loader(); } const char* type_string() { return "ciMethod"; } @@ -158,6 +154,11 @@ } } + Method* get_Method() const { + Method* m = (Method*)_metadata; + assert(m != NULL, "illegal use of unloaded method"); + return m; + } // Method code and related information. address code() { if (_code == NULL) load_code(); return _code; } @@ -339,6 +340,10 @@ // Print the name of this method in various incarnations. void print_name(outputStream* st = tty); void print_short_name(outputStream* st = tty); + +#if INCLUDE_TRACE + TraceStructCiMethod to_trace_struct() const; +#endif }; #endif // SHARE_VM_CI_CIMETHOD_HPP diff -r 8c1cc431f388 -r 889895365eb9 hotspot/src/share/vm/classfile/classLoaderData.cpp --- a/hotspot/src/share/vm/classfile/classLoaderData.cpp Fri Mar 20 17:39:29 2015 +0000 +++ b/hotspot/src/share/vm/classfile/classLoaderData.cpp Mon Mar 23 11:44:41 2015 -0700 @@ -467,6 +467,12 @@ } else { ShouldNotReachHere(); } + } else { + // Metadata is alive. + // If scratch_class is on stack then it shouldn't be on this list! + assert(!m->is_klass() || !((InstanceKlass*)m)->is_scratch_class(), + "scratch classes on this list should be dead"); + // Also should assert that other metadata on the list was found in handles. } } } @@ -737,11 +743,22 @@ // Move class loader data from main list to the unloaded list for unloading // and deallocation later. -bool ClassLoaderDataGraph::do_unloading(BoolObjectClosure* is_alive_closure, bool clean_alive) { +bool ClassLoaderDataGraph::do_unloading(BoolObjectClosure* is_alive_closure, + bool clean_previous_versions) { + ClassLoaderData* data = _head; ClassLoaderData* prev = NULL; bool seen_dead_loader = false; + // Mark metadata seen on the stack only so we can delete unneeded entries. + // Only walk all metadata, including the expensive code cache walk, for Full GC + // and only if class redefinition and if there's previous versions of + // Klasses to delete. + bool walk_all_metadata = clean_previous_versions && + JvmtiExport::has_redefined_a_class() && + InstanceKlass::has_previous_versions(); + MetadataOnStackMark md_on_stack(walk_all_metadata); + // Save previous _unloading pointer for CMS which may add to unloading list before // purging and we don't want to rewalk the previously unloaded class loader data. _saved_unloading = _unloading; @@ -749,6 +766,11 @@ data = _head; while (data != NULL) { if (data->is_alive(is_alive_closure)) { + // clean metaspace + if (walk_all_metadata) { + data->classes_do(InstanceKlass::purge_previous_versions); + } + data->free_deallocate_list(); prev = data; data = data->next(); continue; @@ -770,11 +792,6 @@ _unloading = dead; } - if (clean_alive) { - // Clean previous versions and the deallocate list. - ClassLoaderDataGraph::clean_metaspaces(); - } - if (seen_dead_loader) { post_class_unload_events(); } @@ -782,21 +799,6 @@ return seen_dead_loader; } -void ClassLoaderDataGraph::clean_metaspaces() { - // mark metadata seen on the stack and code cache so we can delete unneeded entries. - bool has_redefined_a_class = JvmtiExport::has_redefined_a_class(); - MetadataOnStackMark md_on_stack(has_redefined_a_class); - - if (has_redefined_a_class) { - for (ClassLoaderData* data = _head; data != NULL; data = data->next()) { - data->classes_do(InstanceKlass::purge_previous_versions); - } - } - - // Should purge the previous version before deallocating. - free_deallocate_lists(); -} - void ClassLoaderDataGraph::purge() { assert(SafepointSynchronize::is_at_safepoint(), "must be at safepoint!"); ClassLoaderData* list = _unloading; @@ -829,12 +831,6 @@ #endif } -void ClassLoaderDataGraph::free_deallocate_lists() { - for (ClassLoaderData* cld = _head; cld != NULL; cld = cld->next()) { - cld->free_deallocate_list(); - } -} - // CDS support // Global metaspaces for writing information to the shared archive. When diff -r 8c1cc431f388 -r 889895365eb9 hotspot/src/share/vm/classfile/classLoaderData.hpp --- a/hotspot/src/share/vm/classfile/classLoaderData.hpp Fri Mar 20 17:39:29 2015 +0000 +++ b/hotspot/src/share/vm/classfile/classLoaderData.hpp Mon Mar 23 11:44:41 2015 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2015, 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 @@ -75,7 +75,6 @@ static ClassLoaderData* add(Handle class_loader, bool anonymous, TRAPS); static void post_class_unload_events(void); - static void clean_metaspaces(); public: static ClassLoaderData* find_or_create(Handle class_loader, TRAPS); static void purge(); @@ -95,7 +94,7 @@ static void methods_do(void f(Method*)); static void loaded_classes_do(KlassClosure* klass_closure); static void classes_unloading_do(void f(Klass* const)); - static bool do_unloading(BoolObjectClosure* is_alive, bool clean_alive); + static bool do_unloading(BoolObjectClosure* is_alive, bool clean_previous_versions); // CMS support. static void remember_new_clds(bool remember) { _saved_head = (remember ? _head : NULL); } @@ -114,8 +113,6 @@ static bool has_metaspace_oom() { return _metaspace_oom; } static void set_metaspace_oom(bool value) { _metaspace_oom = value; } - static void free_deallocate_lists(); - static void dump_on(outputStream * const out) PRODUCT_RETURN; static void dump() { dump_on(tty); } static void verify(); diff -r 8c1cc431f388 -r 889895365eb9 hotspot/src/share/vm/classfile/metadataOnStackMark.cpp --- a/hotspot/src/share/vm/classfile/metadataOnStackMark.cpp Fri Mar 20 17:39:29 2015 +0000 +++ b/hotspot/src/share/vm/classfile/metadataOnStackMark.cpp Mon Mar 23 11:44:41 2015 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2015, 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 @@ -33,26 +33,31 @@ #include "services/threadService.hpp" #include "utilities/chunkedList.hpp" -volatile MetadataOnStackBuffer* MetadataOnStackMark::_used_buffers = NULL; -volatile MetadataOnStackBuffer* MetadataOnStackMark::_free_buffers = NULL; +MetadataOnStackBuffer* MetadataOnStackMark::_used_buffers = NULL; +MetadataOnStackBuffer* MetadataOnStackMark::_free_buffers = NULL; +MetadataOnStackBuffer* MetadataOnStackMark::_current_buffer = NULL; NOT_PRODUCT(bool MetadataOnStackMark::_is_active = false;) // Walk metadata on the stack and mark it so that redefinition doesn't delete -// it. Class unloading also walks the previous versions and might try to -// delete it, so this class is used by class unloading also. -MetadataOnStackMark::MetadataOnStackMark(bool visit_code_cache) { +// it. Class unloading only deletes in-error class files, methods created by +// the relocator and dummy constant pools. None of these appear anywhere except +// in metadata Handles. +MetadataOnStackMark::MetadataOnStackMark(bool redefinition_walk) { assert(SafepointSynchronize::is_at_safepoint(), "sanity check"); assert(_used_buffers == NULL, "sanity check"); + assert(!_is_active, "MetadataOnStackMarks do not nest"); NOT_PRODUCT(_is_active = true;) - Threads::metadata_do(Metadata::mark_on_stack); - if (visit_code_cache) { + Threads::metadata_handles_do(Metadata::mark_on_stack); + + if (redefinition_walk) { + Threads::metadata_do(Metadata::mark_on_stack); CodeCache::alive_nmethods_do(nmethod::mark_on_stack); + CompileBroker::mark_on_stack(); + JvmtiCurrentBreakpoints::metadata_do(Metadata::mark_on_stack); + ThreadService::metadata_do(Metadata::mark_on_stack); } - CompileBroker::mark_on_stack(); - JvmtiCurrentBreakpoints::metadata_do(Metadata::mark_on_stack); - ThreadService::metadata_do(Metadata::mark_on_stack); } MetadataOnStackMark::~MetadataOnStackMark() { @@ -60,10 +65,9 @@ // Unmark everything that was marked. Can't do the same walk because // redefine classes messes up the code cache so the set of methods // might not be the same. + retire_current_buffer(); - retire_buffer_for_thread(Thread::current()); - - MetadataOnStackBuffer* buffer = const_cast(_used_buffers); + MetadataOnStackBuffer* buffer = _used_buffers; while (buffer != NULL) { // Clear on stack state for all metadata. size_t size = buffer->size(); @@ -77,7 +81,7 @@ // Move the buffer to the free list. buffer->clear(); buffer->set_next_used(NULL); - buffer->set_next_free(const_cast(_free_buffers)); + buffer->set_next_free(_free_buffers); _free_buffers = buffer; // Step to next used buffer. @@ -93,35 +97,23 @@ if (buffer == NULL) { return; } - - MetadataOnStackBuffer* old_head; - - do { - old_head = const_cast(_used_buffers); - buffer->set_next_used(old_head); - } while (Atomic::cmpxchg_ptr(buffer, &_used_buffers, old_head) != old_head); -} - -void MetadataOnStackMark::retire_buffer_for_thread(Thread* thread) { - retire_buffer(thread->metadata_on_stack_buffer()); - thread->set_metadata_on_stack_buffer(NULL); + buffer->set_next_used(_used_buffers); + _used_buffers = buffer; } -bool MetadataOnStackMark::has_buffer_for_thread(Thread* thread) { - return thread->metadata_on_stack_buffer() != NULL; +// Current buffer is full or we're ready to walk them, add it to the used list. +void MetadataOnStackMark::retire_current_buffer() { + retire_buffer(_current_buffer); + _current_buffer = NULL; } +// Get buffer off free list. MetadataOnStackBuffer* MetadataOnStackMark::allocate_buffer() { - MetadataOnStackBuffer* allocated; - MetadataOnStackBuffer* new_head; + MetadataOnStackBuffer* allocated = _free_buffers; - do { - allocated = const_cast(_free_buffers); - if (allocated == NULL) { - break; - } - new_head = allocated->next_free(); - } while (Atomic::cmpxchg_ptr(new_head, &_free_buffers, allocated) != allocated); + if (allocated != NULL) { + _free_buffers = allocated->next_free(); + } if (allocated == NULL) { allocated = new MetadataOnStackBuffer(); @@ -133,10 +125,10 @@ } // Record which objects are marked so we can unmark the same objects. -void MetadataOnStackMark::record(Metadata* m, Thread* thread) { +void MetadataOnStackMark::record(Metadata* m) { assert(_is_active, "metadata on stack marking is active"); - MetadataOnStackBuffer* buffer = thread->metadata_on_stack_buffer(); + MetadataOnStackBuffer* buffer = _current_buffer; if (buffer != NULL && buffer->is_full()) { retire_buffer(buffer); @@ -145,7 +137,7 @@ if (buffer == NULL) { buffer = allocate_buffer(); - thread->set_metadata_on_stack_buffer(buffer); + _current_buffer = buffer; } buffer->push(m); diff -r 8c1cc431f388 -r 889895365eb9 hotspot/src/share/vm/classfile/metadataOnStackMark.hpp --- a/hotspot/src/share/vm/classfile/metadataOnStackMark.hpp Fri Mar 20 17:39:29 2015 +0000 +++ b/hotspot/src/share/vm/classfile/metadataOnStackMark.hpp Mon Mar 23 11:44:41 2015 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2015, 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 @@ -36,23 +36,23 @@ // or executing methods, so that it can't be deleted during class redefinition // and class unloading. // This is also used for other things that can be deallocated, like class -// metadata during parsing, relocated methods, and methods in backtraces. +// metadata during parsing if errors occur, relocated methods, and temporary +// constant pools. class MetadataOnStackMark : public StackObj { NOT_PRODUCT(static bool _is_active;) - - static volatile MetadataOnStackBuffer* _used_buffers; - static volatile MetadataOnStackBuffer* _free_buffers; + static MetadataOnStackBuffer* _used_buffers; + static MetadataOnStackBuffer* _free_buffers; + static MetadataOnStackBuffer* _current_buffer; static MetadataOnStackBuffer* allocate_buffer(); static void retire_buffer(MetadataOnStackBuffer* buffer); public: - MetadataOnStackMark(bool visit_code_cache); + MetadataOnStackMark(bool redefinition_walk); ~MetadataOnStackMark(); - static void record(Metadata* m, Thread* thread); - static void retire_buffer_for_thread(Thread* thread); - static bool has_buffer_for_thread(Thread* thread); + static void record(Metadata* m); + static void retire_current_buffer(); }; #endif // SHARE_VM_CLASSFILE_METADATAONSTACKMARK_HPP diff -r 8c1cc431f388 -r 889895365eb9 hotspot/src/share/vm/classfile/systemDictionary.cpp --- a/hotspot/src/share/vm/classfile/systemDictionary.cpp Fri Mar 20 17:39:29 2015 +0000 +++ b/hotspot/src/share/vm/classfile/systemDictionary.cpp Mon Mar 23 11:44:41 2015 -0700 @@ -1368,8 +1368,6 @@ ClassLoaderData* loader_data = k->class_loader_data(); Handle class_loader_h(THREAD, loader_data->class_loader()); - for (uintx it = 0; it < GCExpandToAllocateDelayMillis; it++){} - // for bootstrap and other parallel classloaders don't acquire lock, // use placeholder token // If a parallelCapable class loader calls define_instance_class instead of @@ -1690,9 +1688,11 @@ // Assumes classes in the SystemDictionary are only unloaded at a safepoint // Note: anonymous classes are not in the SD. -bool SystemDictionary::do_unloading(BoolObjectClosure* is_alive, bool clean_alive) { +bool SystemDictionary::do_unloading(BoolObjectClosure* is_alive, + bool clean_previous_versions) { // First, mark for unload all ClassLoaderData referencing a dead class loader. - bool unloading_occurred = ClassLoaderDataGraph::do_unloading(is_alive, clean_alive); + bool unloading_occurred = ClassLoaderDataGraph::do_unloading(is_alive, + clean_previous_versions); if (unloading_occurred) { dictionary()->do_unloading(); constraints()->purge_loader_constraints(); diff -r 8c1cc431f388 -r 889895365eb9 hotspot/src/share/vm/classfile/systemDictionary.hpp --- a/hotspot/src/share/vm/classfile/systemDictionary.hpp Fri Mar 20 17:39:29 2015 +0000 +++ b/hotspot/src/share/vm/classfile/systemDictionary.hpp Mon Mar 23 11:44:41 2015 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2015, 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 @@ -335,7 +335,8 @@ // Unload (that is, break root links to) all unmarked classes and // loaders. Returns "true" iff something was unloaded. - static bool do_unloading(BoolObjectClosure* is_alive, bool clean_alive = true); + static bool do_unloading(BoolObjectClosure* is_alive, + bool clean_previous_versions = true); // Used by DumpSharedSpaces only to remove classes that failed verification static void remove_classes_in_error_state(); diff -r 8c1cc431f388 -r 889895365eb9 hotspot/src/share/vm/code/nmethod.cpp --- a/hotspot/src/share/vm/code/nmethod.cpp Fri Mar 20 17:39:29 2015 +0000 +++ b/hotspot/src/share/vm/code/nmethod.cpp Mon Mar 23 11:44:41 2015 -0700 @@ -1572,17 +1572,12 @@ set_unload_reported(); } -void static clean_ic_if_metadata_is_dead(CompiledIC *ic, BoolObjectClosure *is_alive, bool mark_on_stack) { +void static clean_ic_if_metadata_is_dead(CompiledIC *ic, BoolObjectClosure *is_alive) { if (ic->is_icholder_call()) { // The only exception is compiledICHolder oops which may // yet be marked below. (We check this further below). CompiledICHolder* cichk_oop = ic->cached_icholder(); - if (mark_on_stack) { - Metadata::mark_on_stack(cichk_oop->holder_method()); - Metadata::mark_on_stack(cichk_oop->holder_klass()); - } - if (cichk_oop->holder_method()->method_holder()->is_loader_alive(is_alive) && cichk_oop->holder_klass()->is_loader_alive(is_alive)) { return; @@ -1590,10 +1585,6 @@ } else { Metadata* ic_oop = ic->cached_metadata(); if (ic_oop != NULL) { - if (mark_on_stack) { - Metadata::mark_on_stack(ic_oop); - } - if (ic_oop->is_klass()) { if (((Klass*)ic_oop)->is_loader_alive(is_alive)) { return; @@ -1634,8 +1625,7 @@ // The RedefineClasses() API can cause the class unloading invariant // to no longer be true. See jvmtiExport.hpp for details. // Also, leave a debugging breadcrumb in local flag. - bool a_class_was_redefined = JvmtiExport::has_redefined_a_class(); - if (a_class_was_redefined) { + if (JvmtiExport::has_redefined_a_class()) { // This set of the unloading_occurred flag is done before the // call to post_compiled_method_unload() so that the unloading // of this nmethod is reported. @@ -1654,7 +1644,7 @@ while(iter.next()) { if (iter.type() == relocInfo::virtual_call_type) { CompiledIC *ic = CompiledIC_at(&iter); - clean_ic_if_metadata_is_dead(ic, is_alive, false); + clean_ic_if_metadata_is_dead(ic, is_alive); } } } @@ -1741,33 +1731,6 @@ return false; } -void nmethod::mark_metadata_on_stack_at(RelocIterator* iter_at_metadata) { - assert(iter_at_metadata->type() == relocInfo::metadata_type, "Wrong relocation type"); - - metadata_Relocation* r = iter_at_metadata->metadata_reloc(); - // In this metadata, we must only follow those metadatas directly embedded in - // the code. Other metadatas (oop_index>0) are seen as part of - // the metadata section below. - assert(1 == (r->metadata_is_immediate()) + - (r->metadata_addr() >= metadata_begin() && r->metadata_addr() < metadata_end()), - "metadata must be found in exactly one place"); - if (r->metadata_is_immediate() && r->metadata_value() != NULL) { - Metadata* md = r->metadata_value(); - if (md != _method) Metadata::mark_on_stack(md); - } -} - -void nmethod::mark_metadata_on_stack_non_relocs() { - // Visit the metadata section - for (Metadata** p = metadata_begin(); p < metadata_end(); p++) { - if (*p == Universe::non_oop_word() || *p == NULL) continue; // skip non-oops - Metadata* md = *p; - Metadata::mark_on_stack(md); - } - - // Visit metadata not embedded in the other places. - if (_method != NULL) Metadata::mark_on_stack(_method); -} bool nmethod::do_unloading_parallel(BoolObjectClosure* is_alive, bool unloading_occurred) { ResourceMark rm; @@ -1790,19 +1753,13 @@ // The RedefineClasses() API can cause the class unloading invariant // to no longer be true. See jvmtiExport.hpp for details. // Also, leave a debugging breadcrumb in local flag. - bool a_class_was_redefined = JvmtiExport::has_redefined_a_class(); - if (a_class_was_redefined) { + if (JvmtiExport::has_redefined_a_class()) { // This set of the unloading_occurred flag is done before the // call to post_compiled_method_unload() so that the unloading // of this nmethod is reported. unloading_occurred = true; } - // When class redefinition is used all metadata in the CodeCache has to be recorded, - // so that unused "previous versions" can be purged. Since walking the CodeCache can - // be expensive, the "mark on stack" is piggy-backed on this parallel unloading code. - bool mark_metadata_on_stack = a_class_was_redefined; - // Exception cache clean_exception_cache(is_alive); @@ -1818,7 +1775,7 @@ if (unloading_occurred) { // If class unloading occurred we first iterate over all inline caches and // clear ICs where the cached oop is referring to an unloaded klass or method. - clean_ic_if_metadata_is_dead(CompiledIC_at(&iter), is_alive, mark_metadata_on_stack); + clean_ic_if_metadata_is_dead(CompiledIC_at(&iter), is_alive); } postponed |= clean_if_nmethod_is_unloaded(CompiledIC_at(&iter), is_alive, this); @@ -1839,16 +1796,10 @@ break; case relocInfo::metadata_type: - if (mark_metadata_on_stack) { - mark_metadata_on_stack_at(&iter); - } + break; // nothing to do. } } - if (mark_metadata_on_stack) { - mark_metadata_on_stack_non_relocs(); - } - if (is_unloaded) { return postponed; } diff -r 8c1cc431f388 -r 889895365eb9 hotspot/src/share/vm/code/nmethod.hpp --- a/hotspot/src/share/vm/code/nmethod.hpp Fri Mar 20 17:39:29 2015 +0000 +++ b/hotspot/src/share/vm/code/nmethod.hpp Mon Mar 23 11:44:41 2015 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2015, 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 @@ -593,9 +593,6 @@ bool can_unload(BoolObjectClosure* is_alive, oop* root, bool unloading_occurred); bool unload_if_dead_at(RelocIterator *iter_at_oop, BoolObjectClosure* is_alive, bool unloading_occurred); - void mark_metadata_on_stack_at(RelocIterator* iter_at_metadata); - void mark_metadata_on_stack_non_relocs(); - public: void preserve_callee_argument_oops(frame fr, const RegisterMap *reg_map, OopClosure* f); diff -r 8c1cc431f388 -r 889895365eb9 hotspot/src/share/vm/gc_implementation/g1/concurrentMark.cpp --- a/hotspot/src/share/vm/gc_implementation/g1/concurrentMark.cpp Fri Mar 20 17:39:29 2015 +0000 +++ b/hotspot/src/share/vm/gc_implementation/g1/concurrentMark.cpp Mon Mar 23 11:44:41 2015 -0700 @@ -2170,12 +2170,13 @@ g1h->secondary_free_list_add(&tmp_free_list); SecondaryFreeList_lock->notify_all(); } - +#ifndef PRODUCT if (G1StressConcRegionFreeing) { for (uintx i = 0; i < G1StressConcRegionFreeingDelayMillis; ++i) { os::sleep(Thread::current(), (jlong) 1, false); } } +#endif } } assert(tmp_free_list.is_empty(), "post-condition"); @@ -2532,11 +2533,6 @@ G1CMTraceTime trace("Unloading", G1Log::finer()); if (ClassUnloadingWithConcurrentMark) { - // Cleaning of klasses depends on correct information from MetadataMarkOnStack. The CodeCache::mark_on_stack - // part is too slow to be done serially, so it is handled during the weakRefsWorkParallelPart phase. - // Defer the cleaning until we have complete on_stack data. - MetadataOnStackMark md_on_stack(false /* Don't visit the code cache at this point */); - bool purged_classes; { @@ -2548,11 +2544,6 @@ G1CMTraceTime trace("Parallel Unloading", G1Log::finest()); weakRefsWorkParallelPart(&g1_is_alive, purged_classes); } - - { - G1CMTraceTime trace("Deallocate Metadata", G1Log::finest()); - ClassLoaderDataGraph::free_deallocate_lists(); - } } if (G1StringDedup::is_enabled()) { diff -r 8c1cc431f388 -r 889895365eb9 hotspot/src/share/vm/gc_implementation/g1/concurrentMark.hpp --- a/hotspot/src/share/vm/gc_implementation/g1/concurrentMark.hpp Fri Mar 20 17:39:29 2015 +0000 +++ b/hotspot/src/share/vm/gc_implementation/g1/concurrentMark.hpp Mon Mar 23 11:44:41 2015 -0700 @@ -853,7 +853,7 @@ // Returns the card bitmap for a given task or worker id. BitMap* count_card_bitmap_for(uint worker_id) { - assert(0 <= worker_id && worker_id < _max_worker_id, "oob"); + assert(worker_id < _max_worker_id, "oob"); assert(_count_card_bitmaps != NULL, "uninitialized"); BitMap* task_card_bm = &_count_card_bitmaps[worker_id]; assert(task_card_bm->size() == _card_bm.size(), "size mismatch"); @@ -863,7 +863,7 @@ // Returns the array containing the marked bytes for each region, // for the given worker or task id. size_t* count_marked_bytes_array_for(uint worker_id) { - assert(0 <= worker_id && worker_id < _max_worker_id, "oob"); + assert(worker_id < _max_worker_id, "oob"); assert(_count_marked_bytes != NULL, "uninitialized"); size_t* marked_bytes_array = _count_marked_bytes[worker_id]; assert(marked_bytes_array != NULL, "uninitialized"); diff -r 8c1cc431f388 -r 889895365eb9 hotspot/src/share/vm/gc_implementation/g1/g1CardCounts.hpp --- a/hotspot/src/share/vm/gc_implementation/g1/g1CardCounts.hpp Fri Mar 20 17:39:29 2015 +0000 +++ b/hotspot/src/share/vm/gc_implementation/g1/g1CardCounts.hpp Mon Mar 23 11:44:41 2015 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2015, 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 @@ -84,13 +84,13 @@ "_ct_bot: " PTR_FORMAT, p2i(card_ptr), p2i(_ct_bot))); size_t card_num = pointer_delta(card_ptr, _ct_bot, sizeof(jbyte)); - assert(card_num >= 0 && card_num < _reserved_max_card_num, + assert(card_num < _reserved_max_card_num, err_msg("card pointer out of range: " PTR_FORMAT, p2i(card_ptr))); return card_num; } jbyte* card_num_2_ptr(size_t card_num) { - assert(card_num >= 0 && card_num < _reserved_max_card_num, + assert(card_num < _reserved_max_card_num, err_msg("card num out of range: "SIZE_FORMAT, card_num)); return (jbyte*) (_ct_bot + card_num); } diff -r 8c1cc431f388 -r 889895365eb9 hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp --- a/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp Fri Mar 20 17:39:29 2015 +0000 +++ b/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp Mon Mar 23 11:44:41 2015 -0700 @@ -4909,10 +4909,6 @@ clean_nmethod(claimed_nmethods[i]); } } - - // The nmethod cleaning helps out and does the CodeCache part of MetadataOnStackMark. - // Need to retire the buffers now that this thread has stopped cleaning nmethods. - MetadataOnStackMark::retire_buffer_for_thread(Thread::current()); } void work_second_pass(uint worker_id) { @@ -4965,9 +4961,6 @@ // G1 specific cleanup work that has // been moved here to be done in parallel. ik->clean_dependent_nmethods(); - if (JvmtiExport::has_redefined_a_class()) { - InstanceKlass::purge_previous_versions(ik); - } } void work() { @@ -5002,18 +4995,8 @@ _klass_cleaning_task(is_alive) { } - void pre_work_verification() { - assert(!MetadataOnStackMark::has_buffer_for_thread(Thread::current()), "Should be empty"); - } - - void post_work_verification() { - assert(!MetadataOnStackMark::has_buffer_for_thread(Thread::current()), "Should be empty"); - } - // The parallel work done by all worker threads. void work(uint worker_id) { - pre_work_verification(); - // Do first pass of code cache cleaning. _code_cache_task.work_first_pass(worker_id); @@ -5032,8 +5015,6 @@ // Clean all klasses that were not unloaded. _klass_cleaning_task.work(); - - post_work_verification(); } }; @@ -5425,7 +5406,7 @@ // limit is set using max_num_q() - which was set using ParallelGCThreads. // So this must be true - but assert just in case someone decides to // change the worker ids. - assert(0 <= worker_id && worker_id < limit, "sanity"); + assert(worker_id < limit, "sanity"); assert(!rp->discovery_is_atomic(), "check this code"); // Select discovered lists [i, i+stride, i+2*stride,...,limit) diff -r 8c1cc431f388 -r 889895365eb9 hotspot/src/share/vm/gc_implementation/g1/heapRegion.cpp --- a/hotspot/src/share/vm/gc_implementation/g1/heapRegion.cpp Fri Mar 20 17:39:29 2015 +0000 +++ b/hotspot/src/share/vm/gc_implementation/g1/heapRegion.cpp Mon Mar 23 11:44:41 2015 -0700 @@ -324,9 +324,8 @@ void HeapRegion::note_self_forwarding_removal_end(bool during_initial_mark, bool during_conc_mark, size_t marked_bytes) { - assert(0 <= marked_bytes && marked_bytes <= used(), - err_msg("marked: "SIZE_FORMAT" used: "SIZE_FORMAT, - marked_bytes, used())); + assert(marked_bytes <= used(), + err_msg("marked: "SIZE_FORMAT" used: "SIZE_FORMAT, marked_bytes, used())); _prev_top_at_mark_start = top(); _prev_marked_bytes = marked_bytes; } diff -r 8c1cc431f388 -r 889895365eb9 hotspot/src/share/vm/gc_implementation/g1/heapRegionManager.cpp --- a/hotspot/src/share/vm/gc_implementation/g1/heapRegionManager.cpp Fri Mar 20 17:39:29 2015 +0000 +++ b/hotspot/src/share/vm/gc_implementation/g1/heapRegionManager.cpp Mon Mar 23 11:44:41 2015 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2015, 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 @@ -270,7 +270,7 @@ const uint n_regions = hrclaimer->n_regions(); for (uint count = 0; count < n_regions; count++) { const uint index = (start_index + count) % n_regions; - assert(0 <= index && index < n_regions, "sanity"); + assert(index < n_regions, "sanity"); // Skip over unavailable regions if (!is_available(index)) { continue; diff -r 8c1cc431f388 -r 889895365eb9 hotspot/src/share/vm/gc_implementation/g1/heapRegionRemSet.cpp --- a/hotspot/src/share/vm/gc_implementation/g1/heapRegionRemSet.cpp Fri Mar 20 17:39:29 2015 +0000 +++ b/hotspot/src/share/vm/gc_implementation/g1/heapRegionRemSet.cpp Mon Mar 23 11:44:41 2015 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2015, 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 @@ -541,7 +541,7 @@ PerRegionTable* OtherRegionsTable::find_region_table(size_t ind, HeapRegion* hr) const { - assert(0 <= ind && ind < _max_fine_entries, "Preconditions."); + assert(ind < _max_fine_entries, "Preconditions."); PerRegionTable* prt = _fine_grain_regions[ind]; while (prt != NULL && prt->hr() != hr) { prt = prt->collision_list_next(); diff -r 8c1cc431f388 -r 889895365eb9 hotspot/src/share/vm/gc_implementation/g1/heapRegionSet.cpp --- a/hotspot/src/share/vm/gc_implementation/g1/heapRegionSet.cpp Fri Mar 20 17:39:29 2015 +0000 +++ b/hotspot/src/share/vm/gc_implementation/g1/heapRegionSet.cpp Mon Mar 23 11:44:41 2015 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -57,7 +57,7 @@ check_mt_safety(); guarantee(( is_empty() && length() == 0 && total_capacity_bytes() == 0) || - (!is_empty() && length() >= 0 && total_capacity_bytes() >= 0), + (!is_empty() && length() > 0 && total_capacity_bytes() > 0) , hrs_ext_msg(this, "invariant")); } diff -r 8c1cc431f388 -r 889895365eb9 hotspot/src/share/vm/gc_implementation/g1/ptrQueue.cpp --- a/hotspot/src/share/vm/gc_implementation/g1/ptrQueue.cpp Fri Mar 20 17:39:29 2015 +0000 +++ b/hotspot/src/share/vm/gc_implementation/g1/ptrQueue.cpp Mon Mar 23 11:44:41 2015 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2015, 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 @@ -58,7 +58,7 @@ void PtrQueue::enqueue_known_active(void* ptr) { - assert(0 <= _index && _index <= _sz, "Invariant."); + assert(_index <= _sz, "Invariant."); assert(_index == 0 || _buf != NULL, "invariant"); while (_index == 0) { @@ -68,7 +68,7 @@ assert(_index > 0, "postcondition"); _index -= oopSize; _buf[byte_index_to_index((int)_index)] = ptr; - assert(0 <= _index && _index <= _sz, "Invariant."); + assert(_index <= _sz, "Invariant."); } void PtrQueue::locking_enqueue_completed_buffer(void** buf) { @@ -194,7 +194,6 @@ _buf = qset()->allocate_buffer(); _sz = qset()->buffer_size(); _index = _sz; - assert(0 <= _index && _index <= _sz, "Invariant."); } bool PtrQueueSet::process_or_enqueue_complete_buffer(void** buf) { diff -r 8c1cc431f388 -r 889895365eb9 hotspot/src/share/vm/gc_implementation/parNew/parCardTableModRefBS.cpp --- a/hotspot/src/share/vm/gc_implementation/parNew/parCardTableModRefBS.cpp Fri Mar 20 17:39:29 2015 +0000 +++ b/hotspot/src/share/vm/gc_implementation/parNew/parCardTableModRefBS.cpp Mon Mar 23 11:44:41 2015 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2007, 2015, 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 @@ -195,8 +195,9 @@ // our closures depend on this property and do not protect against // double scans. - uintptr_t cur_chunk_index = addr_to_chunk_index(chunk_mr.start()); - cur_chunk_index = cur_chunk_index - lowest_non_clean_base_chunk_index; + uintptr_t start_chunk_index = addr_to_chunk_index(chunk_mr.start()); + assert(start_chunk_index >= lowest_non_clean_base_chunk_index, "Bounds error."); + uintptr_t cur_chunk_index = start_chunk_index - lowest_non_clean_base_chunk_index; NOISY(tty->print_cr("===========================================================================");) NOISY(tty->print_cr(" process_chunk_boundary: Called with [" PTR_FORMAT "," PTR_FORMAT ")", @@ -242,8 +243,7 @@ if (first_dirty_card != NULL) { NOISY(tty->print_cr(" LNC: Found a dirty card at " PTR_FORMAT " in current chunk", first_dirty_card);) - assert(0 <= cur_chunk_index && cur_chunk_index < lowest_non_clean_chunk_size, - "Bounds error."); + assert(cur_chunk_index < lowest_non_clean_chunk_size, "Bounds error."); assert(lowest_non_clean[cur_chunk_index] == NULL, "Write exactly once : value should be stable hereafter for this round"); lowest_non_clean[cur_chunk_index] = first_dirty_card; diff -r 8c1cc431f388 -r 889895365eb9 hotspot/src/share/vm/gc_implementation/shared/gcUtil.hpp --- a/hotspot/src/share/vm/gc_implementation/shared/gcUtil.hpp Fri Mar 20 17:39:29 2015 +0000 +++ b/hotspot/src/share/vm/gc_implementation/shared/gcUtil.hpp Mon Mar 23 11:44:41 2015 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2015, 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 @@ -103,7 +103,7 @@ static inline float exp_avg(float avg, float sample, unsigned int weight) { - assert(0 <= weight && weight <= 100, "weight must be a percent"); + assert(weight <= 100, "weight must be a percent"); return (100.0F - weight) * avg / 100.0F + weight * sample / 100.0F; } static inline size_t exp_avg(size_t avg, size_t sample, diff -r 8c1cc431f388 -r 889895365eb9 hotspot/src/share/vm/gc_implementation/shared/liveRange.hpp --- a/hotspot/src/share/vm/gc_implementation/shared/liveRange.hpp Fri Mar 20 17:39:29 2015 +0000 +++ b/hotspot/src/share/vm/gc_implementation/shared/liveRange.hpp Mon Mar 23 11:44:41 2015 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2015, 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 @@ -42,7 +42,6 @@ MemRegion::set_end(e); } void set_word_size(size_t ws) { - assert(ws >= 0, "should be a non-zero range"); MemRegion::set_word_size(ws); } diff -r 8c1cc431f388 -r 889895365eb9 hotspot/src/share/vm/gc_implementation/shared/mutableSpace.cpp --- a/hotspot/src/share/vm/gc_implementation/shared/mutableSpace.cpp Fri Mar 20 17:39:29 2015 +0000 +++ b/hotspot/src/share/vm/gc_implementation/shared/mutableSpace.cpp Mon Mar 23 11:44:41 2015 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2015, 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 @@ -36,8 +36,7 @@ PRAGMA_FORMAT_MUTE_WARNINGS_FOR_GCC MutableSpace::MutableSpace(size_t alignment): ImmutableSpace(), _top(NULL), _alignment(alignment) { - assert(MutableSpace::alignment() >= 0 && - MutableSpace::alignment() % os::vm_page_size() == 0, + assert(MutableSpace::alignment() % os::vm_page_size() == 0, "Space should be aligned"); _mangler = new MutableSpaceMangler(this); } diff -r 8c1cc431f388 -r 889895365eb9 hotspot/src/share/vm/memory/allocation.cpp --- a/hotspot/src/share/vm/memory/allocation.cpp Fri Mar 20 17:39:29 2015 +0000 +++ b/hotspot/src/share/vm/memory/allocation.cpp Mon Mar 23 11:44:41 2015 -0700 @@ -562,7 +562,6 @@ // Reallocate storage in Arena. void *Arena::Arealloc(void* old_ptr, size_t old_size, size_t new_size, AllocFailType alloc_failmode) { - assert(new_size >= 0, "bad size"); if (new_size == 0) return NULL; #ifdef ASSERT if (UseMallocOnly) { diff -r 8c1cc431f388 -r 889895365eb9 hotspot/src/share/vm/memory/blockOffsetTable.cpp --- a/hotspot/src/share/vm/memory/blockOffsetTable.cpp Fri Mar 20 17:39:29 2015 +0000 +++ b/hotspot/src/share/vm/memory/blockOffsetTable.cpp Mon Mar 23 11:44:41 2015 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2015, 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 @@ -792,6 +792,5 @@ } size_t BlockOffsetArrayContigSpace::last_active_index() const { - size_t result = _next_offset_index - 1; - return result >= 0 ? result : 0; + return _next_offset_index == 0 ? 0 : _next_offset_index - 1; } diff -r 8c1cc431f388 -r 889895365eb9 hotspot/src/share/vm/memory/heap.cpp --- a/hotspot/src/share/vm/memory/heap.cpp Fri Mar 20 17:39:29 2015 +0000 +++ b/hotspot/src/share/vm/memory/heap.cpp Mon Mar 23 11:44:41 2015 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2015, 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 @@ -52,7 +52,7 @@ void CodeHeap::mark_segmap_as_free(size_t beg, size_t end) { - assert(0 <= beg && beg < _number_of_committed_segments, "interval begin out of bounds"); + assert( beg < _number_of_committed_segments, "interval begin out of bounds"); assert(beg < end && end <= _number_of_committed_segments, "interval end out of bounds"); // setup _segmap pointers for faster indexing address p = (address)_segmap.low() + beg; @@ -63,7 +63,7 @@ void CodeHeap::mark_segmap_as_used(size_t beg, size_t end) { - assert(0 <= beg && beg < _number_of_committed_segments, "interval begin out of bounds"); + assert( beg < _number_of_committed_segments, "interval begin out of bounds"); assert(beg < end && end <= _number_of_committed_segments, "interval end out of bounds"); // setup _segmap pointers for faster indexing address p = (address)_segmap.low() + beg; diff -r 8c1cc431f388 -r 889895365eb9 hotspot/src/share/vm/memory/referenceProcessor.cpp --- a/hotspot/src/share/vm/memory/referenceProcessor.cpp Fri Mar 20 17:39:29 2015 +0000 +++ b/hotspot/src/share/vm/memory/referenceProcessor.cpp Mon Mar 23 11:44:41 2015 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2015, 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 @@ -987,7 +987,7 @@ id = next_id(); } } - assert(0 <= id && id < _max_num_q, "Id is out-of-bounds (call Freud?)"); + assert(id < _max_num_q, "Id is out-of-bounds (call Freud?)"); // Get the discovered queue to which we will add DiscoveredList* list = NULL; @@ -1345,7 +1345,7 @@ } const char* ReferenceProcessor::list_name(uint i) { - assert(i >= 0 && i <= _max_num_q * number_of_subclasses_of_ref(), + assert(i <= _max_num_q * number_of_subclasses_of_ref(), "Out of bounds index"); int j = i / _max_num_q; diff -r 8c1cc431f388 -r 889895365eb9 hotspot/src/share/vm/oops/constantPool.cpp --- a/hotspot/src/share/vm/oops/constantPool.cpp Fri Mar 20 17:39:29 2015 +0000 +++ b/hotspot/src/share/vm/oops/constantPool.cpp Mon Mar 23 11:44:41 2015 -0700 @@ -1790,17 +1790,10 @@ void ConstantPool::set_on_stack(const bool value) { if (value) { - int old_flags = *const_cast(&_flags); - while ((old_flags & _on_stack) == 0) { - int new_flags = old_flags | _on_stack; - int result = Atomic::cmpxchg(new_flags, &_flags, old_flags); - - if (result == old_flags) { - // Succeeded. - MetadataOnStackMark::record(this, Thread::current()); - return; - } - old_flags = result; + // Only record if it's not already set. + if (!on_stack()) { + _flags |= _on_stack; + MetadataOnStackMark::record(this); } } else { // Clearing is done single-threadedly. diff -r 8c1cc431f388 -r 889895365eb9 hotspot/src/share/vm/oops/instanceKlass.cpp --- a/hotspot/src/share/vm/oops/instanceKlass.cpp Fri Mar 20 17:39:29 2015 +0000 +++ b/hotspot/src/share/vm/oops/instanceKlass.cpp Mon Mar 23 11:44:41 2015 -0700 @@ -3492,9 +3492,11 @@ #endif + // RedefineClasses() support for previous versions: - -// Purge previous versions +int InstanceKlass::_previous_version_count = 0; + +// Purge previous versions before adding new previous versions of the class. void InstanceKlass::purge_previous_versions(InstanceKlass* ik) { if (ik->previous_versions() != NULL) { // This klass has previous versions so see what we can cleanup @@ -3524,6 +3526,11 @@ // are executing. Unlink this previous_version. // The previous version InstanceKlass is on the ClassLoaderData deallocate list // so will be deallocated during the next phase of class unloading. + RC_TRACE(0x00000200, ("purge: previous version " INTPTR_FORMAT " is dead", + pv_node)); + // For debugging purposes. + pv_node->set_is_scratch_class(); + pv_node->class_loader_data()->add_to_deallocate_list(pv_node); pv_node = pv_node->previous_versions(); last->link_previous_versions(pv_node); deleted_count++; @@ -3537,7 +3544,7 @@ live_count++; } - // At least one method is live in this previous version so clean its MethodData. + // At least one method is live in this previous version. // Reset dead EMCP methods not to get breakpoints. // All methods are deallocated when all of the methods for this class are no // longer running. @@ -3561,12 +3568,6 @@ ("purge: %s(%s): prev method @%d in version @%d is alive", method->name()->as_C_string(), method->signature()->as_C_string(), j, version)); -#ifdef ASSERT - if (method->method_data() != NULL) { - // Verify MethodData for running methods don't refer to old methods. - method->method_data()->verify_clean_weak_method_links(); - } -#endif // ASSERT } } } @@ -3579,18 +3580,6 @@ ("purge: previous version stats: live=%d, deleted=%d", live_count, deleted_count)); } - -#ifdef ASSERT - // Verify clean MethodData for this class's methods, e.g. they don't refer to - // old methods that are no longer running. - Array* methods = ik->methods(); - int num_methods = methods->length(); - for (int index = 0; index < num_methods; ++index) { - if (methods->at(index)->method_data() != NULL) { - methods->at(index)->method_data()->verify_clean_weak_method_links(); - } - } -#endif // ASSERT } void InstanceKlass::mark_newly_obsolete_methods(Array* old_methods, @@ -3677,6 +3666,11 @@ ConstantPool* cp_ref = scratch_class->constants(); if (!cp_ref->on_stack()) { RC_TRACE(0x00000400, ("add: scratch class not added; no methods are running")); + // For debugging purposes. + scratch_class->set_is_scratch_class(); + scratch_class->class_loader_data()->add_to_deallocate_list(scratch_class()); + // Update count for class unloading. + _previous_version_count--; return; } @@ -3688,8 +3682,8 @@ // if EMCP method (not obsolete) is on the stack, mark as EMCP so that // we can add breakpoints for it. - // We set the method->on_stack bit during safepoints for class redefinition and - // class unloading and use this bit to set the is_running_emcp bit. + // We set the method->on_stack bit during safepoints for class redefinition + // and use this bit to set the is_running_emcp bit. // After the safepoint, the on_stack bit is cleared and the running emcp // method may exit. If so, we would set a breakpoint in a method that // is never reached, but this won't be noticeable to the programmer. @@ -3708,6 +3702,8 @@ assert(scratch_class->previous_versions() == NULL, "shouldn't have a previous version"); scratch_class->link_previous_versions(previous_versions()); link_previous_versions(scratch_class()); + // Update count for class unloading. + _previous_version_count++; } // end add_previous_version() diff -r 8c1cc431f388 -r 889895365eb9 hotspot/src/share/vm/oops/instanceKlass.hpp --- a/hotspot/src/share/vm/oops/instanceKlass.hpp Fri Mar 20 17:39:29 2015 +0000 +++ b/hotspot/src/share/vm/oops/instanceKlass.hpp Mon Mar 23 11:44:41 2015 -0700 @@ -206,7 +206,8 @@ _misc_is_contended = 1 << 4, // marked with contended annotation _misc_has_default_methods = 1 << 5, // class/superclass/implemented interfaces has default methods _misc_declares_default_methods = 1 << 6, // directly declares default methods (any access) - _misc_has_been_redefined = 1 << 7 // class has been redefined + _misc_has_been_redefined = 1 << 7, // class has been redefined + _misc_is_scratch_class = 1 << 8 // class is the redefined scratch class }; u2 _misc_flags; u2 _minor_version; // minor version number of class file @@ -626,11 +627,23 @@ _misc_flags |= _misc_has_been_redefined; } + bool is_scratch_class() const { + return (_misc_flags & _misc_is_scratch_class) != 0; + } + + void set_is_scratch_class() { + _misc_flags |= _misc_is_scratch_class; + } + void init_previous_versions() { _previous_versions = NULL; } + private: + static int _previous_version_count; + public: static void purge_previous_versions(InstanceKlass* ik); + static bool has_previous_versions() { return _previous_version_count > 0; } // JVMTI: Support for caching a class file before it is modified by an agent that can do retransformation void set_cached_class_file(JvmtiCachedClassFileData *data) { diff -r 8c1cc431f388 -r 889895365eb9 hotspot/src/share/vm/oops/method.cpp --- a/hotspot/src/share/vm/oops/method.cpp Fri Mar 20 17:39:29 2015 +0000 +++ b/hotspot/src/share/vm/oops/method.cpp Mon Mar 23 11:44:41 2015 -0700 @@ -1970,9 +1970,10 @@ // on stack means some method referring to it is also on the stack. constants()->set_on_stack(value); - bool succeeded = _access_flags.set_on_stack(value); - if (value && succeeded) { - MetadataOnStackMark::record(this, Thread::current()); + bool already_set = on_stack(); + _access_flags.set_on_stack(value); + if (value && !already_set) { + MetadataOnStackMark::record(this); } } diff -r 8c1cc431f388 -r 889895365eb9 hotspot/src/share/vm/opto/bytecodeInfo.cpp --- a/hotspot/src/share/vm/opto/bytecodeInfo.cpp Fri Mar 20 17:39:29 2015 +0000 +++ b/hotspot/src/share/vm/opto/bytecodeInfo.cpp Mon Mar 23 11:44:41 2015 -0700 @@ -33,6 +33,7 @@ #include "opto/callGenerator.hpp" #include "opto/parse.hpp" #include "runtime/handles.inline.hpp" +#include "utilities/events.hpp" //============================================================================= //------------------------------InlineTree------------------------------------- @@ -490,7 +491,7 @@ //------------------------------print_inlining--------------------------------- void InlineTree::print_inlining(ciMethod* callee_method, int caller_bci, - bool success) const { + ciMethod* caller_method, bool success) const { const char* inline_msg = msg(); assert(inline_msg != NULL, "just checking"); if (C->log() != NULL) { @@ -509,6 +510,18 @@ //tty->print(" bcs: %d+%d invoked: %d", top->count_inline_bcs(), callee_method->code_size(), callee_method->interpreter_invocation_count()); } } +#if INCLUDE_TRACE + EventCompilerInlining event; + if (event.should_commit()) { + event.set_compileID(C->compile_id()); + event.set_message(inline_msg); + event.set_succeeded(success); + event.set_bci(caller_bci); + event.set_caller(caller_method->get_Method()); + event.set_callee(callee_method->to_trace_struct()); + event.commit(); + } +#endif // INCLUDE_TRACE } //------------------------------ok_to_inline----------------------------------- @@ -531,14 +544,14 @@ // Do some initial checks. if (!pass_initial_checks(caller_method, caller_bci, callee_method)) { set_msg("failed initial checks"); - print_inlining(callee_method, caller_bci, false /* !success */); + print_inlining(callee_method, caller_bci, caller_method, false /* !success */); return NULL; } // Do some parse checks. set_msg(check_can_parse(callee_method)); if (msg() != NULL) { - print_inlining(callee_method, caller_bci, false /* !success */); + print_inlining(callee_method, caller_bci, caller_method, false /* !success */); return NULL; } @@ -580,10 +593,11 @@ if (msg() == NULL) { set_msg("inline (hot)"); } - print_inlining(callee_method, caller_bci, true /* success */); + print_inlining(callee_method, caller_bci, caller_method, true /* success */); build_inline_tree_for_callee(callee_method, jvms, caller_bci); - if (InlineWarmCalls && !wci.is_hot()) + if (InlineWarmCalls && !wci.is_hot()) { return new (C) WarmCallInfo(wci); // copy to heap + } return WarmCallInfo::always_hot(); } @@ -591,7 +605,7 @@ if (msg() == NULL) { set_msg("too cold to inline"); } - print_inlining(callee_method, caller_bci, false /* !success */ ); + print_inlining(callee_method, caller_bci, caller_method, false /* !success */ ); return NULL; } diff -r 8c1cc431f388 -r 889895365eb9 hotspot/src/share/vm/opto/chaitin.cpp --- a/hotspot/src/share/vm/opto/chaitin.cpp Fri Mar 20 17:39:29 2015 +0000 +++ b/hotspot/src/share/vm/opto/chaitin.cpp Mon Mar 23 11:44:41 2015 -0700 @@ -602,7 +602,7 @@ // This frame must preserve the required fp alignment _framesize = round_to(_framesize, Matcher::stack_alignment_in_slots()); - assert( _framesize >= 0 && _framesize <= 1000000, "sanity check" ); + assert(_framesize <= 1000000, "sanity check"); #ifndef PRODUCT _total_framesize += _framesize; if ((int)_framesize > _max_framesize) { diff -r 8c1cc431f388 -r 889895365eb9 hotspot/src/share/vm/opto/graphKit.cpp --- a/hotspot/src/share/vm/opto/graphKit.cpp Fri Mar 20 17:39:29 2015 +0000 +++ b/hotspot/src/share/vm/opto/graphKit.cpp Mon Mar 23 11:44:41 2015 -0700 @@ -3027,12 +3027,7 @@ // We may not have profiling here or it may not help us. If we have // a speculative type use it to perform an exact cast. ciKlass* spec_obj_type = obj_type->speculative_type(); - if (spec_obj_type != NULL || - (data != NULL && - // Counter has never been decremented (due to cast failure). - // ...This is a reasonable thing to expect. It is true of - // all casts inserted by javac to implement generic types. - data->as_CounterData()->count() >= 0)) { + if (spec_obj_type != NULL || data != NULL) { cast_obj = maybe_cast_profiled_receiver(not_null_obj, tk->klass(), spec_obj_type, safe_for_replace); if (cast_obj != NULL) { if (failure_control != NULL) // failure is now impossible diff -r 8c1cc431f388 -r 889895365eb9 hotspot/src/share/vm/opto/parse.hpp --- a/hotspot/src/share/vm/opto/parse.hpp Fri Mar 20 17:39:29 2015 +0000 +++ b/hotspot/src/share/vm/opto/parse.hpp Mon Mar 23 11:44:41 2015 -0700 @@ -87,7 +87,7 @@ JVMState* jvms, WarmCallInfo* wci_result); void print_inlining(ciMethod* callee_method, int caller_bci, - bool success) const; + ciMethod* caller_method, bool success) const; InlineTree* caller_tree() const { return _caller_tree; } InlineTree* callee_at(int bci, ciMethod* m) const; diff -r 8c1cc431f388 -r 889895365eb9 hotspot/src/share/vm/prims/jvmtiRedefineClasses.cpp --- a/hotspot/src/share/vm/prims/jvmtiRedefineClasses.cpp Fri Mar 20 17:39:29 2015 +0000 +++ b/hotspot/src/share/vm/prims/jvmtiRedefineClasses.cpp Mon Mar 23 11:44:41 2015 -0700 @@ -142,14 +142,11 @@ for (int i = 0; i < _class_count; i++) { redefine_single_class(_class_defs[i].klass, _scratch_classes[i], thread); - ClassLoaderData* cld = _scratch_classes[i]->class_loader_data(); - // Free the memory for this class at class unloading time. Not before - // because CMS might think this is still live. - cld->add_to_deallocate_list((InstanceKlass*)_scratch_classes[i]); - _scratch_classes[i] = NULL; } // Clean out MethodData pointing to old Method* + // Have to do this after all classes are redefined and all methods that + // are redefined are marked as old. MethodDataCleaner clean_weak_method_links; ClassLoaderDataGraph::classes_do(&clean_weak_method_links); @@ -2902,18 +2899,13 @@ // } assert(stackmap_p + 1 <= stackmap_end, "no room for frame_type"); - // The Linux compiler does not like frame_type to be u1 or u2. It - // issues the following warning for the first if-statement below: - // - // "warning: comparison is always true due to limited range of data type" - // - u4 frame_type = *stackmap_p; + u1 frame_type = *stackmap_p; stackmap_p++; // same_frame { // u1 frame_type = SAME; /* 0-63 */ // } - if (frame_type >= 0 && frame_type <= 63) { + if (frame_type <= 63) { // nothing more to do for same_frame } diff -r 8c1cc431f388 -r 889895365eb9 hotspot/src/share/vm/prims/whitebox.cpp --- a/hotspot/src/share/vm/prims/whitebox.cpp Fri Mar 20 17:39:29 2015 +0000 +++ b/hotspot/src/share/vm/prims/whitebox.cpp Mon Mar 23 11:44:41 2015 -0700 @@ -364,10 +364,6 @@ os::release_memory((char *)(uintptr_t)addr, size); WB_END -WB_ENTRY(jboolean, WB_NMTIsDetailSupported(JNIEnv* env)) - return MemTracker::tracking_level() == NMT_detail; -WB_END - WB_ENTRY(jboolean, WB_NMTChangeTrackingLevel(JNIEnv* env)) // Test that we can downgrade NMT levels but not upgrade them. if (MemTracker::tracking_level() == NMT_off) { @@ -1321,7 +1317,6 @@ {CC"NMTCommitMemory", CC"(JJ)V", (void*)&WB_NMTCommitMemory }, {CC"NMTUncommitMemory", CC"(JJ)V", (void*)&WB_NMTUncommitMemory }, {CC"NMTReleaseMemory", CC"(JJ)V", (void*)&WB_NMTReleaseMemory }, - {CC"NMTIsDetailSupported",CC"()Z", (void*)&WB_NMTIsDetailSupported}, {CC"NMTChangeTrackingLevel", CC"()Z", (void*)&WB_NMTChangeTrackingLevel}, {CC"NMTGetHashSize", CC"()I", (void*)&WB_NMTGetHashSize }, #endif // INCLUDE_NMT diff -r 8c1cc431f388 -r 889895365eb9 hotspot/src/share/vm/runtime/frame.hpp --- a/hotspot/src/share/vm/runtime/frame.hpp Fri Mar 20 17:39:29 2015 +0000 +++ b/hotspot/src/share/vm/runtime/frame.hpp Mon Mar 23 11:44:41 2015 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2015, 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 @@ -194,7 +194,6 @@ public: // Link (i.e., the pointer to the previous frame) intptr_t* link() const; - void set_link(intptr_t* addr); // Return address address sender_pc() const; diff -r 8c1cc431f388 -r 889895365eb9 hotspot/src/share/vm/runtime/globals.hpp --- a/hotspot/src/share/vm/runtime/globals.hpp Fri Mar 20 17:39:29 2015 +0000 +++ b/hotspot/src/share/vm/runtime/globals.hpp Mon Mar 23 11:44:41 2015 -0700 @@ -921,6 +921,9 @@ "If > 0, provokes an error inside VM error handler (a secondary " \ "crash). see test_error_handler() in debug.cpp.") \ \ + notproduct(bool, TestSafeFetchInErrorHandler, false, \ + "If true, tests SafeFetch inside error handler.") \ + \ develop(bool, Verbose, false, \ "Print additional debugging information from other modes") \ \ diff -r 8c1cc431f388 -r 889895365eb9 hotspot/src/share/vm/runtime/stubRoutines.cpp --- a/hotspot/src/share/vm/runtime/stubRoutines.cpp Fri Mar 20 17:39:29 2015 +0000 +++ b/hotspot/src/share/vm/runtime/stubRoutines.cpp Mon Mar 23 11:44:41 2015 -0700 @@ -210,8 +210,36 @@ assert(fbuffer[i] == v && fbuffer2[i] == v2, "shouldn't have copied anything"); } } + +// simple test for SafeFetch32 +static void test_safefetch32() { + int dummy = 17; + int* const p_invalid = (int*) get_segfault_address(); + int* const p_valid = &dummy; + int result_invalid = SafeFetch32(p_invalid, 0xABC); + assert(result_invalid == 0xABC, "SafeFetch32 error"); + int result_valid = SafeFetch32(p_valid, 0xABC); + assert(result_valid == 17, "SafeFetch32 error"); +} + +// simple test for SafeFetchN +static void test_safefetchN() { +#ifdef _LP64 + const intptr_t v1 = UCONST64(0xABCD00000000ABCD); + const intptr_t v2 = UCONST64(0xDEFD00000000DEFD); +#else + const intptr_t v1 = 0xABCDABCD; + const intptr_t v2 = 0xDEFDDEFD; #endif - + intptr_t dummy = v1; + intptr_t* const p_invalid = (intptr_t*) get_segfault_address(); + intptr_t* const p_valid = &dummy; + intptr_t result_invalid = SafeFetchN(p_invalid, v2); + assert(result_invalid == v2, "SafeFetchN error"); + intptr_t result_valid = SafeFetchN(p_valid, v2); + assert(result_valid == v1, "SafeFetchN error"); +} +#endif void StubRoutines::initialize2() { if (_code2 == NULL) { @@ -300,6 +328,13 @@ test_arraycopy_func(CAST_FROM_FN_PTR(address, Copy::aligned_conjoint_words), sizeof(jlong)); test_arraycopy_func(CAST_FROM_FN_PTR(address, Copy::aligned_disjoint_words), sizeof(jlong)); + // test safefetch routines + // Not on Windows 32bit until 8074860 is fixed +#if ! (defined(_WIN32) && defined(_M_IX86)) + test_safefetch32(); + test_safefetchN(); +#endif + #endif } diff -r 8c1cc431f388 -r 889895365eb9 hotspot/src/share/vm/runtime/stubRoutines.hpp --- a/hotspot/src/share/vm/runtime/stubRoutines.hpp Fri Mar 20 17:39:29 2015 +0000 +++ b/hotspot/src/share/vm/runtime/stubRoutines.hpp Mon Mar 23 11:44:41 2015 -0700 @@ -448,4 +448,9 @@ return StubRoutines::SafeFetchN_stub()(adr, errValue); } + +// returns true if SafeFetch32 and SafeFetchN can be used safely (stubroutines are already generated) +inline bool CanUseSafeFetch32() { return StubRoutines::SafeFetch32_stub() ? true : false; } +inline bool CanUseSafeFetchN() { return StubRoutines::SafeFetchN_stub() ? true : false; } + #endif // SHARE_VM_RUNTIME_STUBROUTINES_HPP diff -r 8c1cc431f388 -r 889895365eb9 hotspot/src/share/vm/runtime/thread.cpp --- a/hotspot/src/share/vm/runtime/thread.cpp Fri Mar 20 17:39:29 2015 +0000 +++ b/hotspot/src/share/vm/runtime/thread.cpp Mon Mar 23 11:44:41 2015 -0700 @@ -203,8 +203,6 @@ // This initial value ==> never claimed. _oops_do_parity = 0; - _metadata_on_stack_buffer = NULL; - // the handle mark links itself to last_handle_mark new HandleMark(this); @@ -776,7 +774,8 @@ // no nmethods in a generic thread... } -void Thread::metadata_do(void f(Metadata*)) { +void Thread::metadata_handles_do(void f(Metadata*)) { + // Only walk the Handles in Thread. if (metadata_handles() != NULL) { for (int i = 0; i< metadata_handles()->length(); i++) { f(metadata_handles()->at(i)); @@ -2713,7 +2712,6 @@ } void JavaThread::metadata_do(void f(Metadata*)) { - Thread::metadata_do(f); if (has_last_Java_frame()) { // Traverse the execution stack to call f() on the methods in the stack for (StackFrameStream fst(this); !fst.is_done(); fst.next()) { @@ -4104,6 +4102,21 @@ } } +class ThreadHandlesClosure : public ThreadClosure { + void (*_f)(Metadata*); + public: + ThreadHandlesClosure(void f(Metadata*)) : _f(f) {} + virtual void do_thread(Thread* thread) { + thread->metadata_handles_do(_f); + } +}; + +void Threads::metadata_handles_do(void f(Metadata*)) { + // Only walk the Handles in Thread. + ThreadHandlesClosure handles_closure(f); + threads_do(&handles_closure); +} + void Threads::deoptimized_wrt_marked_nmethods() { ALL_JAVA_THREADS(p) { p->deoptimized_wrt_marked_nmethods(); diff -r 8c1cc431f388 -r 889895365eb9 hotspot/src/share/vm/runtime/thread.hpp --- a/hotspot/src/share/vm/runtime/thread.hpp Fri Mar 20 17:39:29 2015 +0000 +++ b/hotspot/src/share/vm/runtime/thread.hpp Mon Mar 23 11:44:41 2015 -0700 @@ -255,9 +255,6 @@ jlong _allocated_bytes; // Cumulative number of bytes allocated on // the Java heap - // Thread-local buffer used by MetadataOnStackMark. - MetadataOnStackBuffer* _metadata_on_stack_buffer; - TRACE_DATA _trace_data; // Thread-local data for tracing ThreadExt _ext; @@ -478,7 +475,7 @@ void nmethods_do(CodeBlobClosure* cf); // jvmtiRedefineClasses support - void metadata_do(void f(Metadata*)); + void metadata_handles_do(void f(Metadata*)); // Used by fast lock support virtual bool is_lock_owned(address adr) const; @@ -494,9 +491,6 @@ // creation fails due to lack of memory, too many threads etc. bool set_as_starting_thread(); - void set_metadata_on_stack_buffer(MetadataOnStackBuffer* buffer) { _metadata_on_stack_buffer = buffer; } - MetadataOnStackBuffer* metadata_on_stack_buffer() const { return _metadata_on_stack_buffer; } - protected: // OS data associated with the thread OSThread* _osthread; // Platform-specific thread information @@ -1915,6 +1909,7 @@ // RedefineClasses support static void metadata_do(void f(Metadata*)); + static void metadata_handles_do(void f(Metadata*)); #ifdef ASSERT static bool is_vm_complete() { return _vm_complete; } diff -r 8c1cc431f388 -r 889895365eb9 hotspot/src/share/vm/runtime/virtualspace.cpp --- a/hotspot/src/share/vm/runtime/virtualspace.cpp Fri Mar 20 17:39:29 2015 +0000 +++ b/hotspot/src/share/vm/runtime/virtualspace.cpp Mon Mar 23 11:44:41 2015 -0700 @@ -519,12 +519,13 @@ // Calc address range within we try to attach (range of possible start addresses). char *const highest_start = (char *)align_ptr_down(zerobased_max - size, attach_point_alignment); - // SS10 and SS12u1 cannot compile "(char *)UnscaledOopHeapMax - size" on solaris sparc 32-bit: - // "Cannot use int to initialize char*." Introduce aux variable. - char *unscaled_end = (char *)UnscaledOopHeapMax; - unscaled_end -= size; - char *lowest_start = (size < UnscaledOopHeapMax) ? - MAX2(unscaled_end, aligned_heap_base_min_address) : aligned_heap_base_min_address; + // Need to be careful about size being guaranteed to be less + // than UnscaledOopHeapMax due to type constraints. + char *lowest_start = aligned_heap_base_min_address; + uint64_t unscaled_end = UnscaledOopHeapMax - size; + if (unscaled_end < UnscaledOopHeapMax) { // unscaled_end wrapped if size is large + lowest_start = MAX2(lowest_start, (char*)unscaled_end); + } lowest_start = (char *)align_ptr_up(lowest_start, attach_point_alignment); try_reserve_range(highest_start, lowest_start, attach_point_alignment, aligned_heap_base_min_address, zerobased_max, size, alignment, large); diff -r 8c1cc431f388 -r 889895365eb9 hotspot/src/share/vm/runtime/vmStructs.cpp --- a/hotspot/src/share/vm/runtime/vmStructs.cpp Fri Mar 20 17:39:29 2015 +0000 +++ b/hotspot/src/share/vm/runtime/vmStructs.cpp Mon Mar 23 11:44:41 2015 -0700 @@ -2584,7 +2584,6 @@ /**********************/ \ /* frame */ \ /**********************/ \ - NOT_ZERO(PPC64_ONLY(declare_constant(frame::abi_minframe_size))) \ NOT_ZERO(PPC64_ONLY(declare_constant(frame::entry_frame_locals_size))) \ \ NOT_ZERO(X86_ONLY(declare_constant(frame::entry_frame_call_wrapper_offset))) \ diff -r 8c1cc431f388 -r 889895365eb9 hotspot/src/share/vm/services/memTracker.cpp --- a/hotspot/src/share/vm/services/memTracker.cpp Fri Mar 20 17:39:29 2015 +0000 +++ b/hotspot/src/share/vm/services/memTracker.cpp Mon Mar 23 11:44:41 2015 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2015, 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 @@ -53,11 +53,7 @@ if (strcmp(nmt_option, "summary") == 0) { level = NMT_summary; } else if (strcmp(nmt_option, "detail") == 0) { -#if PLATFORM_NATIVE_STACK_WALKING_SUPPORTED level = NMT_detail; -#else - level = NMT_summary; -#endif // PLATFORM_NATIVE_STACK_WALKING_SUPPORTED } else if (strcmp(nmt_option, "off") != 0) { // The option value is invalid _is_nmt_env_valid = false; @@ -95,17 +91,9 @@ bool MemTracker::check_launcher_nmt_support(const char* value) { if (strcmp(value, "=detail") == 0) { -#if !PLATFORM_NATIVE_STACK_WALKING_SUPPORTED - jio_fprintf(defaultStream::error_stream(), - "NMT detail is not supported on this platform. Using NMT summary instead.\n"); - if (MemTracker::tracking_level() != NMT_summary) { - return false; - } -#else if (MemTracker::tracking_level() != NMT_detail) { return false; } -#endif } else if (strcmp(value, "=summary") == 0) { if (MemTracker::tracking_level() != NMT_summary) { return false; diff -r 8c1cc431f388 -r 889895365eb9 hotspot/src/share/vm/trace/trace.xml --- a/hotspot/src/share/vm/trace/trace.xml Fri Mar 20 17:39:29 2015 +0000 +++ b/hotspot/src/share/vm/trace/trace.xml Mon Mar 23 11:44:41 2015 -0700 @@ -400,6 +400,22 @@ + + + + + + + + + + + + + + + = 0, "just checking"); } @@ -45,7 +44,6 @@ } void BitMap::resize(idx_t size_in_bits, bool in_resource_area) { - assert(size_in_bits >= 0, "just checking"); idx_t old_size_in_words = size_in_words(); bm_word_t* old_map = map(); diff -r 8c1cc431f388 -r 889895365eb9 hotspot/src/share/vm/utilities/globalDefinitions.hpp --- a/hotspot/src/share/vm/utilities/globalDefinitions.hpp Fri Mar 20 17:39:29 2015 +0000 +++ b/hotspot/src/share/vm/utilities/globalDefinitions.hpp Mon Mar 23 11:44:41 2015 -0700 @@ -446,15 +446,6 @@ # include "globalDefinitions_aarch64.hpp" #endif -/* - * If a platform does not support native stack walking - * the platform specific globalDefinitions (above) - * can set PLATFORM_NATIVE_STACK_WALKING_SUPPORTED to 0 - */ -#ifndef PLATFORM_NATIVE_STACK_WALKING_SUPPORTED -#define PLATFORM_NATIVE_STACK_WALKING_SUPPORTED 1 -#endif - // To assure the IRIW property on processors that are not multiple copy // atomic, sync instructions must be issued between volatile reads to // assure their ordering, instead of after volatile stores. diff -r 8c1cc431f388 -r 889895365eb9 hotspot/src/share/vm/utilities/globalDefinitions_gcc.hpp --- a/hotspot/src/share/vm/utilities/globalDefinitions_gcc.hpp Fri Mar 20 17:39:29 2015 +0000 +++ b/hotspot/src/share/vm/utilities/globalDefinitions_gcc.hpp Mon Mar 23 11:44:41 2015 -0700 @@ -44,14 +44,6 @@ #endif // SOLARIS #include -#ifndef FP_PZERO -// Linux doesn't have positive/negative zero -#define FP_PZERO FP_ZERO -#endif -#if (!defined fpclass) && ((!defined SPARC) || (!defined SOLARIS)) -#define fpclass fpclassify -#endif - #include #include #include diff -r 8c1cc431f388 -r 889895365eb9 hotspot/src/share/vm/utilities/globalDefinitions_sparcWorks.hpp --- a/hotspot/src/share/vm/utilities/globalDefinitions_sparcWorks.hpp Fri Mar 20 17:39:29 2015 +0000 +++ b/hotspot/src/share/vm/utilities/globalDefinitions_sparcWorks.hpp Mon Mar 23 11:44:41 2015 -0700 @@ -48,15 +48,6 @@ # include #endif # include -#ifdef LINUX -#ifndef FP_PZERO - // Linux doesn't have positive/negative zero - #define FP_PZERO FP_ZERO -#endif -#ifndef fpclass - #define fpclass fpclassify -#endif -#endif # include # include # include diff -r 8c1cc431f388 -r 889895365eb9 hotspot/src/share/vm/utilities/globalDefinitions_xlc.hpp --- a/hotspot/src/share/vm/utilities/globalDefinitions_xlc.hpp Fri Mar 20 17:39:29 2015 +0000 +++ b/hotspot/src/share/vm/utilities/globalDefinitions_xlc.hpp Mon Mar 23 11:44:41 2015 -0700 @@ -41,14 +41,6 @@ #include #include -#ifndef FP_PZERO -// Linux doesn't have positive/negative zero -#define FP_PZERO FP_ZERO -#endif -#if (!defined fpclass) -#define fpclass fpclassify -#endif - #include #include #include diff -r 8c1cc431f388 -r 889895365eb9 hotspot/src/share/vm/utilities/nativeCallStack.cpp --- a/hotspot/src/share/vm/utilities/nativeCallStack.cpp Fri Mar 20 17:39:29 2015 +0000 +++ b/hotspot/src/share/vm/utilities/nativeCallStack.cpp Mon Mar 23 11:44:41 2015 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2015, 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 @@ -32,10 +32,6 @@ NativeCallStack::NativeCallStack(int toSkip, bool fillStack) : _hash_value(0) { -#if !PLATFORM_NATIVE_STACK_WALKING_SUPPORTED - fillStack = false; -#endif - if (fillStack) { os::get_native_stack(_stack, NMT_TrackingStackDepth, toSkip); } else { @@ -95,11 +91,7 @@ int offset; if (is_empty()) { for (int index = 0; index < indent; index ++) out->print(" "); -#if PLATFORM_NATIVE_STACK_WALKING_SUPPORTED out->print("[BOOTSTRAP]"); -#else - out->print("[No stack]"); -#endif } else { for (int frame = 0; frame < NMT_TrackingStackDepth; frame ++) { pc = get_frame(frame); diff -r 8c1cc431f388 -r 889895365eb9 hotspot/src/share/vm/utilities/vmError.cpp --- a/hotspot/src/share/vm/utilities/vmError.cpp Fri Mar 20 17:39:29 2015 +0000 +++ b/hotspot/src/share/vm/utilities/vmError.cpp Mon Mar 23 11:44:41 2015 -0700 @@ -358,18 +358,38 @@ // test secondary error handling. Test it twice, to test that resetting // error handler after a secondary crash works. - STEP(13, "(test secondary crash 1)") + STEP(11, "(test secondary crash 1)") + if (_verbose && TestCrashInErrorHandler != 0) { + st->print_cr("Will crash now (TestCrashInErrorHandler=%d)...", + TestCrashInErrorHandler); + controlled_crash(TestCrashInErrorHandler); + } + + STEP(12, "(test secondary crash 2)") if (_verbose && TestCrashInErrorHandler != 0) { st->print_cr("Will crash now (TestCrashInErrorHandler=%d)...", TestCrashInErrorHandler); controlled_crash(TestCrashInErrorHandler); } - STEP(14, "(test secondary crash 2)") - if (_verbose && TestCrashInErrorHandler != 0) { - st->print_cr("Will crash now (TestCrashInErrorHandler=%d)...", - TestCrashInErrorHandler); - controlled_crash(TestCrashInErrorHandler); + STEP(13, "(test safefetch in error handler)") + // test whether it is safe to use SafeFetch32 in Crash Handler. Test twice + // to test that resetting the signal handler works correctly. + if (_verbose && TestSafeFetchInErrorHandler) { + st->print_cr("Will test SafeFetch..."); + if (CanUseSafeFetch32()) { + int* const invalid_pointer = (int*) get_segfault_address(); + const int x = 0x76543210; + int i1 = SafeFetch32(invalid_pointer, x); + int i2 = SafeFetch32(invalid_pointer, x); + if (i1 == x && i2 == x) { + st->print_cr("SafeFetch OK."); // Correctly deflected and returned default pattern + } else { + st->print_cr("??"); + } + } else { + st->print_cr("not possible; skipped."); + } } #endif // PRODUCT diff -r 8c1cc431f388 -r 889895365eb9 hotspot/src/share/vm/utilities/workgroup.cpp --- a/hotspot/src/share/vm/utilities/workgroup.cpp Fri Mar 20 17:39:29 2015 +0000 +++ b/hotspot/src/share/vm/utilities/workgroup.cpp Mon Mar 23 11:44:41 2015 -0700 @@ -124,7 +124,7 @@ // Array index bounds checking. GangWorker* result = NULL; assert(gang_workers() != NULL, "No workers for indexing"); - assert(((i >= 0) && (i < total_workers())), "Worker index out of bounds"); + assert(i < total_workers(), "Worker index out of bounds"); result = _gang_workers[i]; assert(result != NULL, "Indexing to null worker"); return result; @@ -463,7 +463,7 @@ } bool SubTasksDone::is_task_claimed(uint t) { - assert(0 <= t && t < _n_tasks, "bad task id."); + assert(t < _n_tasks, "bad task id."); uint old = _tasks[t]; if (old == 0) { old = Atomic::cmpxchg(1, &_tasks[t], 0); diff -r 8c1cc431f388 -r 889895365eb9 hotspot/src/share/vm/utilities/yieldingWorkgroup.cpp --- a/hotspot/src/share/vm/utilities/yieldingWorkgroup.cpp Fri Mar 20 17:39:29 2015 +0000 +++ b/hotspot/src/share/vm/utilities/yieldingWorkgroup.cpp Mon Mar 23 11:44:41 2015 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2015, 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 @@ -120,7 +120,6 @@ _sequence_number++; uint requested_size = new_task->requested_size(); - assert(requested_size >= 0, "Should be non-negative"); if (requested_size != 0) { _active_workers = MIN2(requested_size, total_workers()); } else { diff -r 8c1cc431f388 -r 889895365eb9 hotspot/test/compiler/loopopts/ConstFPVectorization.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/test/compiler/loopopts/ConstFPVectorization.java Mon Mar 23 11:44:41 2015 -0700 @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2015, 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 8074869 + * @summary C2 code generator can replace -0.0f with +0.0f on Linux + * @run main ConstFPVectorization 8 + * @author volker.simonis@gmail.com + * + */ + +public class ConstFPVectorization { + + static float[] f = new float[16]; + static double[] d = new double[16]; + + static void floatLoop(int count) { + for (int i = 0; i < count; i++) { + f[i] = -0.0f; + } + } + + static void doubleLoop(int count) { + for (int i = 0; i < count; i++) { + d[i] = -0.0d; + } + } + + public static void main(String args[]) { + for (int i = 0; i < 10_000; i++) { + floatLoop(Integer.parseInt(args[0])); + doubleLoop(Integer.parseInt(args[0])); + } + for (int i = 0; i < Integer.parseInt(args[0]); i++) { + if (Float.floatToRawIntBits(f[i]) != Float.floatToRawIntBits(-0.0f)) + throw new Error("Float error at index " + i); + if (Double.doubleToRawLongBits(d[i]) != Double.doubleToRawLongBits(-0.0d)) + throw new Error("Double error at index " + i); + } + } +} diff -r 8c1cc431f388 -r 889895365eb9 hotspot/test/runtime/ErrorHandling/SafeFetchInErrorHandlingTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/test/runtime/ErrorHandling/SafeFetchInErrorHandlingTest.java Mon Mar 23 11:44:41 2015 -0700 @@ -0,0 +1,92 @@ +import java.io.BufferedReader; +import java.io.File; +import java.io.FileInputStream; +import java.io.InputStreamReader; +import java.util.regex.Pattern; + +import com.oracle.java.testlibrary.OutputAnalyzer; +import com.oracle.java.testlibrary.Platform; +import com.oracle.java.testlibrary.ProcessTools; + +/* + * @test + * @bug 8074552 + * @summary SafeFetch32 and SafeFetchN do not work in error handling + * @library /testlibrary + * @author Thomas Stuefe (SAP) + */ + +public class SafeFetchInErrorHandlingTest { + + + public static void main(String[] args) throws Exception { + + if (!Platform.isDebugBuild()) { + return; + } + + ProcessBuilder pb = ProcessTools.createJavaProcessBuilder( + "-XX:+UnlockDiagnosticVMOptions", + "-Xmx100M", + "-XX:ErrorHandlerTest=14", + "-XX:+TestSafeFetchInErrorHandler", + "-version"); + + OutputAnalyzer output_detail = new OutputAnalyzer(pb.start()); + + // we should have crashed with a SIGSEGV + output_detail.shouldMatch("# A fatal error has been detected by the Java Runtime Environment:.*"); + output_detail.shouldMatch("# +(?:SIGSEGV|EXCEPTION_ACCESS_VIOLATION).*"); + + // extract hs-err file + String hs_err_file = output_detail.firstMatch("# *(\\S*hs_err_pid\\d+\\.log)", 1); + if (hs_err_file == null) { + throw new RuntimeException("Did not find hs-err file in output.\n"); + } + + File f = new File(hs_err_file); + if (!f.exists()) { + throw new RuntimeException("hs-err file missing at " + + f.getAbsolutePath() + ".\n"); + } + + System.out.println("Found hs_err file. Scanning..."); + + FileInputStream fis = new FileInputStream(f); + BufferedReader br = new BufferedReader(new InputStreamReader(fis)); + String line = null; + + Pattern [] pattern = new Pattern[] { + Pattern.compile("Will test SafeFetch..."), + Pattern.compile("SafeFetch OK."), + }; + int currentPattern = 0; + + String lastLine = null; + while ((line = br.readLine()) != null) { + if (currentPattern < pattern.length) { + if (pattern[currentPattern].matcher(line).matches()) { + System.out.println("Found: " + line + "."); + currentPattern ++; + } + } + lastLine = line; + } + br.close(); + + if (currentPattern < pattern.length) { + throw new RuntimeException("hs-err file incomplete (first missing pattern: " + currentPattern + ")"); + } + + if (!lastLine.equals("END.")) { + throw new RuntimeException("hs-err file incomplete (missing END marker.)"); + } else { + System.out.println("End marker found."); + } + + System.out.println("OK."); + + } + +} + diff -r 8c1cc431f388 -r 889895365eb9 hotspot/test/runtime/NMT/ChangeTrackingLevel.java --- a/hotspot/test/runtime/NMT/ChangeTrackingLevel.java Fri Mar 20 17:39:29 2015 +0000 +++ b/hotspot/test/runtime/NMT/ChangeTrackingLevel.java Mon Mar 23 11:44:41 2015 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2015, 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 @@ -27,7 +27,6 @@ * @summary Test that you can decrease NMT tracking level but not increase it. * @key nmt * @library /testlibrary /../../test/lib - * @ignore 8067167 * @build ChangeTrackingLevel * @run main ClassFileInstaller sun.hotspot.WhiteBox * sun.hotspot.WhiteBox$WhiteBoxPermission diff -r 8c1cc431f388 -r 889895365eb9 hotspot/test/runtime/NMT/PrintNMTStatistics.java --- a/hotspot/test/runtime/NMT/PrintNMTStatistics.java Fri Mar 20 17:39:29 2015 +0000 +++ b/hotspot/test/runtime/NMT/PrintNMTStatistics.java Mon Mar 23 11:44:41 2015 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2015, 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 @@ -27,7 +27,6 @@ * @bug 8005936 8058606 * @summary Verify PrintNMTStatistics on normal JVM exit for detail and summary tracking level * @library /testlibrary - * @ignore 8067167 */ import com.oracle.java.testlibrary.*; diff -r 8c1cc431f388 -r 889895365eb9 hotspot/test/runtime/NMT/ThreadedVirtualAllocTestType.java --- a/hotspot/test/runtime/NMT/ThreadedVirtualAllocTestType.java Fri Mar 20 17:39:29 2015 +0000 +++ b/hotspot/test/runtime/NMT/ThreadedVirtualAllocTestType.java Mon Mar 23 11:44:41 2015 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2015, 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 @@ -46,13 +46,6 @@ String pid = Integer.toString(ProcessTools.getProcessId()); ProcessBuilder pb = new ProcessBuilder(); - boolean has_nmt_detail = wb.NMTIsDetailSupported(); - if (has_nmt_detail) { - System.out.println("NMT detail support detected."); - } else { - System.out.println("NMT detail support not detected."); - } - Thread reserveThread = new Thread() { public void run() { addr = wb.NMTReserveMemory(reserveSize); @@ -64,9 +57,7 @@ pb.command(new String[] { JDKToolFinder.getJDKTool("jcmd"), pid, "VM.native_memory", "detail"}); output = new OutputAnalyzer(pb.start()); output.shouldContain("Test (reserved=512KB, committed=0KB)"); - if (has_nmt_detail) { - output.shouldMatch("\\[0x[0]*" + Long.toHexString(addr) + " - 0x[0]*" + Long.toHexString(addr + reserveSize) + "\\] reserved 512KB for Test"); - } + output.shouldMatch("\\[0x[0]*" + Long.toHexString(addr) + " - 0x[0]*" + Long.toHexString(addr + reserveSize) + "\\] reserved 512KB for Test"); Thread commitThread = new Thread() { public void run() { @@ -78,9 +69,7 @@ output = new OutputAnalyzer(pb.start()); output.shouldContain("Test (reserved=512KB, committed=128KB)"); - if (has_nmt_detail) { - output.shouldMatch("\\[0x[0]*" + Long.toHexString(addr) + " - 0x[0]*" + Long.toHexString(addr + commitSize) + "\\] committed 128KB"); - } + output.shouldMatch("\\[0x[0]*" + Long.toHexString(addr) + " - 0x[0]*" + Long.toHexString(addr + commitSize) + "\\] committed 128KB"); Thread uncommitThread = new Thread() { public void run() { @@ -107,4 +96,4 @@ output.shouldNotContain("\\[0x[0]*" + Long.toHexString(addr) + " - 0x[0]*" + Long.toHexString(addr + reserveSize) + "\\] reserved"); } - } +} diff -r 8c1cc431f388 -r 889895365eb9 hotspot/test/runtime/NMT/VirtualAllocCommitUncommitRecommit.java --- a/hotspot/test/runtime/NMT/VirtualAllocCommitUncommitRecommit.java Fri Mar 20 17:39:29 2015 +0000 +++ b/hotspot/test/runtime/NMT/VirtualAllocCommitUncommitRecommit.java Mon Mar 23 11:44:41 2015 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2015, 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 @@ -49,13 +49,6 @@ String pid = Integer.toString(ProcessTools.getProcessId()); ProcessBuilder pb = new ProcessBuilder(); - boolean has_nmt_detail = wb.NMTIsDetailSupported(); - if (has_nmt_detail) { - System.out.println("NMT detail support detected."); - } else { - System.out.println("NMT detail support not detected."); - } - // reserve addr = wb.NMTReserveMemory(reserveSize); pb.command(new String[] { JDKToolFinder.getJDKTool("jcmd"), pid, @@ -63,11 +56,9 @@ output = new OutputAnalyzer(pb.start()); output.shouldContain("Test (reserved=4096KB, committed=0KB)"); - if (has_nmt_detail) { - output.shouldMatch("\\[0x[0]*" + Long.toHexString(addr) + " - 0x[0]*" - + Long.toHexString(addr + reserveSize) - + "\\] reserved 4096KB for Test"); - } + output.shouldMatch("\\[0x[0]*" + Long.toHexString(addr) + " - 0x[0]*" + + Long.toHexString(addr + reserveSize) + + "\\] reserved 4096KB for Test"); long addrA = addr; long addrB = addr + commitSize; @@ -85,11 +76,9 @@ output = new OutputAnalyzer(pb.start()); output.shouldContain("Test (reserved=4096KB, committed=512KB)"); - if (has_nmt_detail) { - output.shouldMatch("\\[0x[0]*" + Long.toHexString(addr) + " - 0x[0]*" - + Long.toHexString(addr + reserveSize) - + "\\] reserved 4096KB for Test"); - } + output.shouldMatch("\\[0x[0]*" + Long.toHexString(addr) + " - 0x[0]*" + + Long.toHexString(addr + reserveSize) + + "\\] reserved 4096KB for Test"); // uncommit BC wb.NMTUncommitMemory(addrB, commitSize); wb.NMTUncommitMemory(addrC, commitSize); @@ -97,11 +86,9 @@ output = new OutputAnalyzer(pb.start()); output.shouldContain("Test (reserved=4096KB, committed=256KB)"); - if (has_nmt_detail) { - output.shouldMatch("\\[0x[0]*" + Long.toHexString(addr) + " - 0x[0]*" - + Long.toHexString(addr + reserveSize) - + "\\] reserved 4096KB for Test"); - } + output.shouldMatch("\\[0x[0]*" + Long.toHexString(addr) + " - 0x[0]*" + + Long.toHexString(addr + reserveSize) + + "\\] reserved 4096KB for Test"); // commit EF wb.NMTCommitMemory(addrE, commitSize); @@ -109,22 +96,18 @@ output = new OutputAnalyzer(pb.start()); output.shouldContain("Test (reserved=4096KB, committed=512KB)"); - if (has_nmt_detail) { - output.shouldMatch("\\[0x[0]*" + Long.toHexString(addr) + " - 0x[0]*" - + Long.toHexString(addr + reserveSize) - + "\\] reserved 4096KB for Test"); - } + output.shouldMatch("\\[0x[0]*" + Long.toHexString(addr) + " - 0x[0]*" + + Long.toHexString(addr + reserveSize) + + "\\] reserved 4096KB for Test"); // uncommit A wb.NMTUncommitMemory(addrA, commitSize); output = new OutputAnalyzer(pb.start()); output.shouldContain("Test (reserved=4096KB, committed=384KB)"); - if (has_nmt_detail) { - output.shouldMatch("\\[0x[0]*" + Long.toHexString(addr) + " - 0x[0]*" - + Long.toHexString(addr + reserveSize) - + "\\] reserved 4096KB for Test"); - } + output.shouldMatch("\\[0x[0]*" + Long.toHexString(addr) + " - 0x[0]*" + + Long.toHexString(addr + reserveSize) + + "\\] reserved 4096KB for Test"); // commit ABC wb.NMTCommitMemory(addrA, commitSize); @@ -133,11 +116,9 @@ output = new OutputAnalyzer(pb.start()); output.shouldContain("Test (reserved=4096KB, committed=768KB)"); - if (has_nmt_detail) { - output.shouldMatch("\\[0x[0]*" + Long.toHexString(addr) + " - 0x[0]*" - + Long.toHexString(addr + reserveSize) - + "\\] reserved 4096KB for Test"); - } + output.shouldMatch("\\[0x[0]*" + Long.toHexString(addr) + " - 0x[0]*" + + Long.toHexString(addr + reserveSize) + + "\\] reserved 4096KB for Test"); // uncommit ABCDEF wb.NMTUncommitMemory(addrA, commitSize); @@ -149,11 +130,9 @@ output = new OutputAnalyzer(pb.start()); output.shouldContain("Test (reserved=4096KB, committed=0KB)"); - if (has_nmt_detail) { - output.shouldMatch("\\[0x[0]*" + Long.toHexString(addr) + " - 0x[0]*" - + Long.toHexString(addr + reserveSize) - + "\\] reserved 4096KB for Test"); - } + output.shouldMatch("\\[0x[0]*" + Long.toHexString(addr) + " - 0x[0]*" + + Long.toHexString(addr + reserveSize) + + "\\] reserved 4096KB for Test"); // release wb.NMTReleaseMemory(addr, reserveSize); diff -r 8c1cc431f388 -r 889895365eb9 hotspot/test/runtime/NMT/VirtualAllocTestType.java --- a/hotspot/test/runtime/NMT/VirtualAllocTestType.java Fri Mar 20 17:39:29 2015 +0000 +++ b/hotspot/test/runtime/NMT/VirtualAllocTestType.java Mon Mar 23 11:44:41 2015 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2015, 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 @@ -47,30 +47,19 @@ String pid = Integer.toString(ProcessTools.getProcessId()); ProcessBuilder pb = new ProcessBuilder(); - boolean has_nmt_detail = wb.NMTIsDetailSupported(); - if (has_nmt_detail) { - System.out.println("NMT detail support detected."); - } else { - System.out.println("NMT detail support not detected."); - } - addr = wb.NMTReserveMemory(reserveSize); pb.command(new String[] { JDKToolFinder.getJDKTool("jcmd"), pid, "VM.native_memory", "detail"}); output = new OutputAnalyzer(pb.start()); output.shouldContain("Test (reserved=256KB, committed=0KB)"); - if (has_nmt_detail) { - output.shouldMatch("\\[0x[0]*" + Long.toHexString(addr) + " - 0x[0]*" + Long.toHexString(addr + reserveSize) + "\\] reserved 256KB for Test"); - } + output.shouldMatch("\\[0x[0]*" + Long.toHexString(addr) + " - 0x[0]*" + Long.toHexString(addr + reserveSize) + "\\] reserved 256KB for Test"); wb.NMTCommitMemory(addr, commitSize); output = new OutputAnalyzer(pb.start()); output.shouldContain("Test (reserved=256KB, committed=128KB)"); - if (has_nmt_detail) { - output.shouldMatch("\\[0x[0]*" + Long.toHexString(addr) + " - 0x[0]*" + Long.toHexString(addr + commitSize) + "\\] committed 128KB"); - } + output.shouldMatch("\\[0x[0]*" + Long.toHexString(addr) + " - 0x[0]*" + Long.toHexString(addr + commitSize) + "\\] committed 128KB"); wb.NMTUncommitMemory(addr, commitSize); @@ -85,4 +74,4 @@ output.shouldNotContain("Test (reserved="); output.shouldNotMatch("\\[0x[0]*" + Long.toHexString(addr) + " - 0x[0]*" + Long.toHexString(addr + reserveSize) + "\\] reserved"); } - } +}