Merge
This commit is contained in:
commit
8a47e1f795
@ -49,7 +49,7 @@
|
||||
#include "sun_jvm_hotspot_debugger_sparc_SPARCThreadContext.h"
|
||||
#endif
|
||||
|
||||
#ifdef ppc64
|
||||
#if defined(ppc64) || defined(ppc64le)
|
||||
#include "sun_jvm_hotspot_debugger_ppc64_PPC64ThreadContext.h"
|
||||
#endif
|
||||
|
||||
@ -223,9 +223,12 @@ JNIEXPORT void JNICALL Java_sun_jvm_hotspot_debugger_linux_LinuxDebuggerLocal_at
|
||||
verifyBitness(env, (char *) &buf);
|
||||
CHECK_EXCEPTION;
|
||||
|
||||
char err_buf[200];
|
||||
struct ps_prochandle* ph;
|
||||
if ( (ph = Pgrab(jpid)) == NULL) {
|
||||
THROW_NEW_DEBUGGER_EXCEPTION("Can't attach to the process");
|
||||
if ( (ph = Pgrab(jpid, err_buf, sizeof(err_buf))) == NULL) {
|
||||
char msg[230];
|
||||
snprintf(msg, sizeof(msg), "Can't attach to the process: %s", err_buf);
|
||||
THROW_NEW_DEBUGGER_EXCEPTION(msg);
|
||||
}
|
||||
(*env)->SetLongField(env, this_obj, p_ps_prochandle_ID, (jlong)(intptr_t)ph);
|
||||
fillThreadsAndLoadObjects(env, this_obj, ph);
|
||||
@ -349,7 +352,7 @@ JNIEXPORT jbyteArray JNICALL Java_sun_jvm_hotspot_debugger_linux_LinuxDebuggerLo
|
||||
return (err == PS_OK)? array : 0;
|
||||
}
|
||||
|
||||
#if defined(i386) || defined(amd64) || defined(sparc) || defined(sparcv9) | defined(ppc64) || defined(aarch64)
|
||||
#if defined(i386) || defined(amd64) || defined(sparc) || defined(sparcv9) | defined(ppc64) || defined(ppc64le) || defined(aarch64)
|
||||
JNIEXPORT jlongArray JNICALL Java_sun_jvm_hotspot_debugger_linux_LinuxDebuggerLocal_getThreadIntegerRegisterSet0
|
||||
(JNIEnv *env, jobject this_obj, jint lwp_id) {
|
||||
|
||||
@ -377,7 +380,7 @@ JNIEXPORT jlongArray JNICALL Java_sun_jvm_hotspot_debugger_linux_LinuxDebuggerLo
|
||||
#if defined(sparc) || defined(sparcv9)
|
||||
#define NPRGREG sun_jvm_hotspot_debugger_sparc_SPARCThreadContext_NPRGREG
|
||||
#endif
|
||||
#ifdef ppc64
|
||||
#if defined(ppc64) || defined(ppc64le)
|
||||
#define NPRGREG sun_jvm_hotspot_debugger_ppc64_PPC64ThreadContext_NPRGREG
|
||||
#endif
|
||||
|
||||
@ -486,7 +489,7 @@ JNIEXPORT jlongArray JNICALL Java_sun_jvm_hotspot_debugger_linux_LinuxDebuggerLo
|
||||
}
|
||||
#endif /* aarch64 */
|
||||
|
||||
#ifdef ppc64
|
||||
#if defined(ppc64) || defined(ppc64le)
|
||||
#define REG_INDEX(reg) sun_jvm_hotspot_debugger_ppc64_PPC64ThreadContext_##reg
|
||||
|
||||
regs[REG_INDEX(LR)] = gregs.link;
|
||||
|
@ -68,7 +68,8 @@ combination of ptrace and /proc calls.
|
||||
*************************************************************************************/
|
||||
|
||||
|
||||
#if defined(sparc) || defined(sparcv9) || defined(ppc64)
|
||||
#if defined(sparc) || defined(sparcv9) || defined(ppc64) || defined(ppc64le)
|
||||
#include <asm/ptrace.h>
|
||||
#define user_regs_struct pt_regs
|
||||
#endif
|
||||
#if defined(aarch64)
|
||||
@ -86,7 +87,7 @@ typedef int bool;
|
||||
struct ps_prochandle;
|
||||
|
||||
// attach to a process
|
||||
struct ps_prochandle* Pgrab(pid_t pid);
|
||||
struct ps_prochandle* Pgrab(pid_t pid, char* err_buf, size_t err_buf_len);
|
||||
|
||||
// attach to a core dump
|
||||
struct ps_prochandle* Pgrab_core(const char* execfile, const char* corefile);
|
||||
|
@ -215,9 +215,12 @@ static bool ptrace_waitpid(pid_t pid) {
|
||||
}
|
||||
|
||||
// attach to a process/thread specified by "pid"
|
||||
static bool ptrace_attach(pid_t pid) {
|
||||
static bool ptrace_attach(pid_t pid, char* err_buf, size_t err_buf_len) {
|
||||
if (ptrace(PTRACE_ATTACH, pid, NULL, NULL) < 0) {
|
||||
print_debug("ptrace(PTRACE_ATTACH, ..) failed for %d\n", pid);
|
||||
char buf[200];
|
||||
char* msg = strerror_r(errno, buf, sizeof(buf));
|
||||
snprintf(err_buf, err_buf_len, "ptrace(PTRACE_ATTACH, ..) failed for %d: %s", pid, msg);
|
||||
print_debug("%s\n", err_buf);
|
||||
return false;
|
||||
} else {
|
||||
return ptrace_waitpid(pid);
|
||||
@ -370,16 +373,17 @@ static ps_prochandle_ops process_ops = {
|
||||
};
|
||||
|
||||
// attach to the process. One and only one exposed stuff
|
||||
struct ps_prochandle* Pgrab(pid_t pid) {
|
||||
struct ps_prochandle* Pgrab(pid_t pid, char* err_buf, size_t err_buf_len) {
|
||||
struct ps_prochandle* ph = NULL;
|
||||
thread_info* thr = NULL;
|
||||
|
||||
if ( (ph = (struct ps_prochandle*) calloc(1, sizeof(struct ps_prochandle))) == NULL) {
|
||||
print_debug("can't allocate memory for ps_prochandle\n");
|
||||
snprintf(err_buf, err_buf_len, "can't allocate memory for ps_prochandle");
|
||||
print_debug("%s\n", err_buf);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (ptrace_attach(pid) != true) {
|
||||
if (ptrace_attach(pid, err_buf, err_buf_len) != true) {
|
||||
free(ph);
|
||||
return NULL;
|
||||
}
|
||||
@ -402,7 +406,7 @@ struct ps_prochandle* Pgrab(pid_t pid) {
|
||||
thr = ph->threads;
|
||||
while (thr) {
|
||||
// don't attach to the main thread again
|
||||
if (ph->pid != thr->lwp_id && ptrace_attach(thr->lwp_id) != true) {
|
||||
if (ph->pid != thr->lwp_id && ptrace_attach(thr->lwp_id, err_buf, err_buf_len) != true) {
|
||||
// even if one attach fails, we get return NULL
|
||||
Prelease(ph);
|
||||
return NULL;
|
||||
|
@ -125,10 +125,14 @@ public class HSDB implements ObjectHistogramPanel.Listener, SAListener {
|
||||
}
|
||||
}
|
||||
|
||||
// close this tool without calling System.exit
|
||||
protected void closeUI() {
|
||||
workerThread.shutdown();
|
||||
frame.dispose();
|
||||
private class CloseUI extends WindowAdapter {
|
||||
|
||||
@Override
|
||||
public void windowClosing(WindowEvent e) {
|
||||
workerThread.shutdown();
|
||||
frame.dispose();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public void run() {
|
||||
@ -144,7 +148,8 @@ public class HSDB implements ObjectHistogramPanel.Listener, SAListener {
|
||||
|
||||
frame = new JFrame("HSDB - HotSpot Debugger");
|
||||
frame.setSize(800, 600);
|
||||
frame.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
|
||||
frame.setDefaultCloseOperation(WindowConstants.DO_NOTHING_ON_CLOSE);
|
||||
frame.addWindowListener(new CloseUI());
|
||||
|
||||
JMenuBar menuBar = new JMenuBar();
|
||||
|
||||
@ -207,7 +212,8 @@ public class HSDB implements ObjectHistogramPanel.Listener, SAListener {
|
||||
item = createMenuItem("Exit",
|
||||
new ActionListener() {
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
closeUI();
|
||||
workerThread.shutdown();
|
||||
frame.dispose();
|
||||
}
|
||||
});
|
||||
item.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_X, ActionEvent.ALT_MASK));
|
||||
|
@ -37,7 +37,7 @@ public class SAGetopt {
|
||||
private boolean _optreset; // special handling of first call
|
||||
|
||||
public SAGetopt(String[] args) {
|
||||
_argv = args;
|
||||
_argv = args.clone();
|
||||
_optind = 0;
|
||||
_optopt = 1;
|
||||
_optarg = null;
|
||||
|
@ -41,7 +41,8 @@ import sun.jvm.hotspot.types.TypeDataBase;
|
||||
|
||||
public class HeapRegionSetBase extends VMObject {
|
||||
|
||||
static private long countField;
|
||||
// uint _length
|
||||
static private CIntegerField lengthField;
|
||||
|
||||
static {
|
||||
VM.registerVMInitializedObserver(new Observer() {
|
||||
@ -54,13 +55,11 @@ public class HeapRegionSetBase extends VMObject {
|
||||
static private synchronized void initialize(TypeDataBase db) {
|
||||
Type type = db.lookupType("HeapRegionSetBase");
|
||||
|
||||
countField = type.getField("_count").getOffset();
|
||||
lengthField = type.getCIntegerField("_length");
|
||||
}
|
||||
|
||||
|
||||
public HeapRegionSetCount count() {
|
||||
Address countFieldAddr = addr.addOffsetTo(countField);
|
||||
return (HeapRegionSetCount) VMObjectFactory.newObject(HeapRegionSetCount.class, countFieldAddr);
|
||||
public long length() {
|
||||
return lengthField.getValue(addr);
|
||||
}
|
||||
|
||||
public HeapRegionSetBase(Address addr) {
|
||||
|
@ -1,73 +0,0 @@
|
||||
/*
|
||||
* 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
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*
|
||||
*/
|
||||
|
||||
package sun.jvm.hotspot.gc.g1;
|
||||
|
||||
import java.util.Iterator;
|
||||
import java.util.Observable;
|
||||
import java.util.Observer;
|
||||
|
||||
import sun.jvm.hotspot.debugger.Address;
|
||||
import sun.jvm.hotspot.runtime.VM;
|
||||
import sun.jvm.hotspot.runtime.VMObject;
|
||||
import sun.jvm.hotspot.runtime.VMObjectFactory;
|
||||
import sun.jvm.hotspot.types.AddressField;
|
||||
import sun.jvm.hotspot.types.CIntegerField;
|
||||
import sun.jvm.hotspot.types.Type;
|
||||
import sun.jvm.hotspot.types.TypeDataBase;
|
||||
|
||||
// Mirror class for HeapRegionSetCount. Represents a group of regions.
|
||||
|
||||
public class HeapRegionSetCount extends VMObject {
|
||||
|
||||
static private CIntegerField lengthField;
|
||||
static private CIntegerField capacityField;
|
||||
|
||||
static {
|
||||
VM.registerVMInitializedObserver(new Observer() {
|
||||
public void update(Observable o, Object data) {
|
||||
initialize(VM.getVM().getTypeDataBase());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
static private synchronized void initialize(TypeDataBase db) {
|
||||
Type type = db.lookupType("HeapRegionSetCount");
|
||||
|
||||
lengthField = type.getCIntegerField("_length");
|
||||
capacityField = type.getCIntegerField("_capacity");
|
||||
}
|
||||
|
||||
public long length() {
|
||||
return lengthField.getValue(addr);
|
||||
}
|
||||
|
||||
public long capacity() {
|
||||
return capacityField.getValue(addr);
|
||||
}
|
||||
|
||||
public HeapRegionSetCount(Address addr) {
|
||||
super(addr);
|
||||
}
|
||||
}
|
@ -229,17 +229,17 @@ public class VM {
|
||||
|
||||
public String getValue() {
|
||||
if (isBool()) {
|
||||
return new Boolean(getBool()).toString();
|
||||
return Boolean.toString(getBool());
|
||||
} else if (isInt()) {
|
||||
return new Long(getInt()).toString();
|
||||
return Long.toString(getInt());
|
||||
} else if (isUInt()) {
|
||||
return new Long(getUInt()).toString();
|
||||
return Long.toString(getUInt());
|
||||
} else if (isIntx()) {
|
||||
return new Long(getIntx()).toString();
|
||||
return Long.toString(getIntx());
|
||||
} else if (isUIntx()) {
|
||||
return new Long(getUIntx()).toString();
|
||||
return Long.toString(getUIntx());
|
||||
} else if (isSizet()) {
|
||||
return new Long(getSizet()).toString();
|
||||
return Long.toString(getSizet());
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
|
@ -112,8 +112,7 @@ public class HeapSummary extends Tool {
|
||||
long survivorRegionNum = g1mm.survivorRegionNum();
|
||||
HeapRegionSetBase oldSet = g1h.oldSet();
|
||||
HeapRegionSetBase humongousSet = g1h.humongousSet();
|
||||
long oldRegionNum = oldSet.count().length()
|
||||
+ humongousSet.count().capacity() / HeapRegion.grainBytes();
|
||||
long oldRegionNum = oldSet.length() + humongousSet.length();
|
||||
printG1Space("G1 Heap:", g1h.n_regions(),
|
||||
g1h.used(), g1h.capacity());
|
||||
System.out.println("G1 Young Generation:");
|
||||
|
@ -1921,6 +1921,15 @@ public class HTMLGenerator implements /* imports */ ClassConstants {
|
||||
buf.link(genPCHref(addressToLong(pc)), pc.toString());
|
||||
}
|
||||
|
||||
if (!method.isStatic() && !method.isNative()) {
|
||||
OopHandle oopHandle = vf.getLocals().oopHandleAt(0);
|
||||
|
||||
if (oopHandle != null) {
|
||||
buf.append(", oop = ");
|
||||
buf.append(oopHandle.toString());
|
||||
}
|
||||
}
|
||||
|
||||
if (vf.isCompiledFrame()) {
|
||||
buf.append(" (Compiled");
|
||||
}
|
||||
|
@ -54,7 +54,7 @@ public class PlatformInfo {
|
||||
|
||||
public static boolean knownCPU(String cpu) {
|
||||
final String[] KNOWN =
|
||||
new String[] {"i386", "x86", "x86_64", "amd64", "sparc", "sparcv9", "ppc64", "aarch64"};
|
||||
new String[] {"i386", "x86", "x86_64", "amd64", "sparc", "sparcv9", "ppc64", "ppc64le", "aarch64"};
|
||||
|
||||
for(String s : KNOWN) {
|
||||
if(s.equals(cpu))
|
||||
@ -98,6 +98,9 @@ public class PlatformInfo {
|
||||
if (cpu.equals("x86_64"))
|
||||
return "amd64";
|
||||
|
||||
if (cpu.equals("ppc64le"))
|
||||
return "ppc64";
|
||||
|
||||
return cpu;
|
||||
|
||||
}
|
||||
|
@ -277,7 +277,7 @@ ifneq ($(OSNAME),windows)
|
||||
|
||||
# Use uname output for SRCARCH, but deal with platform differences. If ARCH
|
||||
# is not explicitly listed below, it is treated as x86.
|
||||
SRCARCH ?= $(ARCH/$(filter sparc sparc64 ia64 amd64 x86_64 ppc ppc64 aarch64 zero,$(ARCH)))
|
||||
SRCARCH ?= $(ARCH/$(filter sparc sparc64 ia64 amd64 x86_64 ppc ppc64 ppc64le aarch64 zero,$(ARCH)))
|
||||
ARCH/ = x86
|
||||
ARCH/sparc = sparc
|
||||
ARCH/sparc64= sparc
|
||||
@ -285,6 +285,7 @@ ifneq ($(OSNAME),windows)
|
||||
ARCH/amd64 = x86
|
||||
ARCH/x86_64 = x86
|
||||
ARCH/ppc64 = ppc
|
||||
ARCH/ppc64le= ppc
|
||||
ARCH/ppc = ppc
|
||||
ARCH/aarch64= aarch64
|
||||
ARCH/zero = zero
|
||||
@ -309,8 +310,13 @@ ifneq ($(OSNAME),windows)
|
||||
endif
|
||||
endif
|
||||
|
||||
# LIBARCH is 1:1 mapping from BUILDARCH
|
||||
LIBARCH ?= $(LIBARCH/$(BUILDARCH))
|
||||
# LIBARCH is 1:1 mapping from BUILDARCH, except for ARCH=ppc64le
|
||||
ifeq ($(ARCH),ppc64le)
|
||||
LIBARCH ?= ppc64le
|
||||
else
|
||||
LIBARCH ?= $(LIBARCH/$(BUILDARCH))
|
||||
endif
|
||||
|
||||
LIBARCH/i486 = i386
|
||||
LIBARCH/amd64 = amd64
|
||||
LIBARCH/sparc = sparc
|
||||
|
@ -58,14 +58,17 @@ define_pd_global(intx, InlineFrequencyCount, 100);
|
||||
#define DEFAULT_STACK_YELLOW_PAGES (2)
|
||||
#define DEFAULT_STACK_RED_PAGES (1)
|
||||
#define DEFAULT_STACK_SHADOW_PAGES (4 DEBUG_ONLY(+5))
|
||||
#define DEFAULT_STACK_RESERVED_PAGES (0)
|
||||
|
||||
#define MIN_STACK_YELLOW_PAGES 1
|
||||
#define MIN_STACK_RED_PAGES 1
|
||||
#define MIN_STACK_SHADOW_PAGES 1
|
||||
#define MIN_STACK_RESERVED_PAGES (0)
|
||||
|
||||
define_pd_global(intx, StackYellowPages, DEFAULT_STACK_YELLOW_PAGES);
|
||||
define_pd_global(intx, StackRedPages, DEFAULT_STACK_RED_PAGES);
|
||||
define_pd_global(intx, StackShadowPages, DEFAULT_STACK_SHADOW_PAGES);
|
||||
define_pd_global(intx, StackReservedPages, DEFAULT_STACK_RESERVED_PAGES);
|
||||
|
||||
define_pd_global(bool, RewriteBytecodes, true);
|
||||
define_pd_global(bool, RewriteFrequentPairs, true);
|
||||
|
@ -36,4 +36,9 @@ const int StackAlignmentInBytes = 16;
|
||||
// The PPC CPUs are NOT multiple-copy-atomic.
|
||||
#define CPU_NOT_MULTIPLE_COPY_ATOMIC
|
||||
|
||||
#if defined(COMPILER2) && defined(AIX)
|
||||
// Include Transactional Memory lock eliding optimization
|
||||
#define INCLUDE_RTM_OPT 1
|
||||
#endif
|
||||
|
||||
#endif // CPU_PPC_VM_GLOBALDEFINITIONS_PPC_HPP
|
||||
|
@ -44,14 +44,17 @@ define_pd_global(bool, UncommonNullCast, true); // Uncommon-trap NULLs pas
|
||||
#define DEFAULT_STACK_YELLOW_PAGES (6)
|
||||
#define DEFAULT_STACK_RED_PAGES (1)
|
||||
#define DEFAULT_STACK_SHADOW_PAGES (6 DEBUG_ONLY(+2))
|
||||
#define DEFAULT_STACK_RESERVED_PAGES (0)
|
||||
|
||||
#define MIN_STACK_YELLOW_PAGES (1)
|
||||
#define MIN_STACK_RED_PAGES DEFAULT_STACK_RED_PAGES
|
||||
#define MIN_STACK_SHADOW_PAGES (1)
|
||||
#define MIN_STACK_RESERVED_PAGES (0)
|
||||
|
||||
define_pd_global(intx, StackYellowPages, DEFAULT_STACK_YELLOW_PAGES);
|
||||
define_pd_global(intx, StackRedPages, DEFAULT_STACK_RED_PAGES);
|
||||
define_pd_global(intx, StackShadowPages, DEFAULT_STACK_SHADOW_PAGES);
|
||||
define_pd_global(intx, StackReservedPages, DEFAULT_STACK_RESERVED_PAGES);
|
||||
|
||||
// Use large code-entry alignment.
|
||||
define_pd_global(intx, CodeEntryAlignment, 128);
|
||||
|
@ -50,12 +50,29 @@
|
||||
// to be 'vtbl_list_size' instances of the vtable in order to
|
||||
// differentiate between the 'vtable_list_size' original Klass objects.
|
||||
|
||||
#define __ masm->
|
||||
|
||||
void MetaspaceShared::generate_vtable_methods(void** vtbl_list,
|
||||
void** vtable,
|
||||
char** md_top,
|
||||
char* md_end,
|
||||
char** mc_top,
|
||||
char* mc_end) {
|
||||
Unimplemented();
|
||||
intptr_t vtable_bytes = (num_virtuals * vtbl_list_size) * sizeof(void*);
|
||||
*(intptr_t *)(*md_top) = vtable_bytes;
|
||||
*md_top += sizeof(intptr_t);
|
||||
void** dummy_vtable = (void**)*md_top;
|
||||
*vtable = dummy_vtable;
|
||||
*md_top += vtable_bytes;
|
||||
|
||||
// Get ready to generate dummy methods.
|
||||
|
||||
CodeBuffer cb((unsigned char*)*mc_top, mc_end - *mc_top);
|
||||
MacroAssembler* masm = new MacroAssembler(&cb);
|
||||
|
||||
// There are more general problems with CDS on ppc, so I can not
|
||||
// really test this. But having this instead of Unimplementd() allows
|
||||
// us to pass TestOptionsWithRanges.java.
|
||||
__ unimplemented();
|
||||
}
|
||||
|
||||
|
@ -210,12 +210,27 @@ void VM_Version::initialize() {
|
||||
}
|
||||
|
||||
// Adjust RTM (Restricted Transactional Memory) flags.
|
||||
if (!has_tcheck() && UseRTMLocking) {
|
||||
if (UseRTMLocking) {
|
||||
// If CPU or OS are too old:
|
||||
// Can't continue because UseRTMLocking affects UseBiasedLocking flag
|
||||
// setting during arguments processing. See use_biased_locking().
|
||||
// VM_Version_init() is executed after UseBiasedLocking is used
|
||||
// in Thread::allocate().
|
||||
vm_exit_during_initialization("RTM instructions are not available on this CPU");
|
||||
if (!has_tcheck()) {
|
||||
vm_exit_during_initialization("RTM instructions are not available on this CPU");
|
||||
}
|
||||
bool os_too_old = true;
|
||||
#ifdef AIX
|
||||
if (os::Aix::os_version() >= 0x0701031e) { // at least AIX 7.1.3.30
|
||||
os_too_old = false;
|
||||
}
|
||||
#endif
|
||||
#ifdef linux
|
||||
// TODO: check kernel version (we currently have too old versions only)
|
||||
#endif
|
||||
if (os_too_old) {
|
||||
vm_exit_during_initialization("RTM is not supported on this OS version.");
|
||||
}
|
||||
}
|
||||
|
||||
if (UseRTMLocking) {
|
||||
|
@ -1453,6 +1453,9 @@ void LIR_Assembler::reg2mem(LIR_Opr from_reg, LIR_Opr dest, BasicType type,
|
||||
|
||||
|
||||
void LIR_Assembler::return_op(LIR_Opr result) {
|
||||
if (StackReservedPages > 0 && compilation()->has_reserved_stack_access()) {
|
||||
__ reserved_stack_check();
|
||||
}
|
||||
// the poll may need a register so just pick one that isn't the return register
|
||||
#if defined(TIERED) && !defined(_LP64)
|
||||
if (result->type_field() == LIR_OprDesc::long_type) {
|
||||
|
@ -632,7 +632,7 @@ bool frame::is_interpreted_frame_valid(JavaThread* thread) const {
|
||||
|
||||
// stack frames shouldn't be much larger than max_stack elements
|
||||
|
||||
if (fp() - sp() > 1024 + m->max_stack()*Interpreter::stackElementSize) {
|
||||
if (fp() - unextended_sp() > 1024 + m->max_stack()*Interpreter::stackElementSize) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -54,4 +54,8 @@ const int StackAlignmentInBytes = (2*wordSize);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if defined(SOLARIS)
|
||||
#define SUPPORT_RESERVED_STACK_AREA
|
||||
#endif
|
||||
|
||||
#endif // CPU_SPARC_VM_GLOBALDEFINITIONS_SPARC_HPP
|
||||
|
@ -54,6 +54,7 @@ define_pd_global(intx, InlineSmallCode, 1500);
|
||||
|
||||
#define DEFAULT_STACK_YELLOW_PAGES (2)
|
||||
#define DEFAULT_STACK_RED_PAGES (1)
|
||||
#define DEFAULT_STACK_RESERVED_PAGES (SOLARIS_ONLY(1) NOT_SOLARIS(0))
|
||||
|
||||
#ifdef _LP64
|
||||
// Stack slots are 2X larger in LP64 than in the 32 bit VM.
|
||||
@ -69,10 +70,12 @@ define_pd_global(intx, VMThreadStackSize, 512);
|
||||
#define MIN_STACK_YELLOW_PAGES DEFAULT_STACK_YELLOW_PAGES
|
||||
#define MIN_STACK_RED_PAGES DEFAULT_STACK_RED_PAGES
|
||||
#define MIN_STACK_SHADOW_PAGES DEFAULT_STACK_SHADOW_PAGES
|
||||
#define MIN_STACK_RESERVED_PAGES (0)
|
||||
|
||||
define_pd_global(intx, StackYellowPages, DEFAULT_STACK_YELLOW_PAGES);
|
||||
define_pd_global(intx, StackRedPages, DEFAULT_STACK_RED_PAGES);
|
||||
define_pd_global(intx, StackShadowPages, DEFAULT_STACK_SHADOW_PAGES);
|
||||
define_pd_global(intx, StackReservedPages, DEFAULT_STACK_RESERVED_PAGES);
|
||||
|
||||
define_pd_global(bool, RewriteBytecodes, true);
|
||||
define_pd_global(bool, RewriteFrequentPairs, true);
|
||||
|
@ -1140,6 +1140,19 @@ void InterpreterMacroAssembler::remove_activation(TosState state,
|
||||
// save result (push state before jvmti call and pop it afterwards) and notify jvmti
|
||||
notify_method_exit(false, state, NotifyJVMTI);
|
||||
|
||||
if (StackReservedPages > 0) {
|
||||
// testing if Stack Reserved Area needs to be re-enabled
|
||||
Label no_reserved_zone_enabling;
|
||||
ld_ptr(G2_thread, JavaThread::reserved_stack_activation_offset(), G3_scratch);
|
||||
cmp_and_brx_short(SP, G3_scratch, Assembler::lessUnsigned, Assembler::pt, no_reserved_zone_enabling);
|
||||
|
||||
call_VM_leaf(noreg, CAST_FROM_FN_PTR(address, SharedRuntime::enable_stack_reserved_zone), G2_thread);
|
||||
call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::throw_delayed_StackOverflowError), G2_thread);
|
||||
should_not_reach_here();
|
||||
|
||||
bind(no_reserved_zone_enabling);
|
||||
}
|
||||
|
||||
interp_verify_oop(Otos_i, state, __FILE__, __LINE__);
|
||||
verify_thread();
|
||||
|
||||
|
@ -3601,6 +3601,24 @@ void MacroAssembler::bang_stack_size(Register Rsize, Register Rtsp,
|
||||
}
|
||||
}
|
||||
|
||||
void MacroAssembler::reserved_stack_check() {
|
||||
// testing if reserved zone needs to be enabled
|
||||
Label no_reserved_zone_enabling;
|
||||
|
||||
ld_ptr(G2_thread, JavaThread::reserved_stack_activation_offset(), G4_scratch);
|
||||
cmp_and_brx_short(SP, G4_scratch, Assembler::lessUnsigned, Assembler::pt, no_reserved_zone_enabling);
|
||||
|
||||
call_VM_leaf(L0, CAST_FROM_FN_PTR(address, SharedRuntime::enable_stack_reserved_zone), G2_thread);
|
||||
|
||||
AddressLiteral stub(StubRoutines::throw_delayed_StackOverflowError_entry());
|
||||
jump_to(stub, G4_scratch);
|
||||
delayed()->restore();
|
||||
|
||||
should_not_reach_here();
|
||||
|
||||
bind(no_reserved_zone_enabling);
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////
|
||||
#if INCLUDE_ALL_GCS
|
||||
|
||||
|
@ -1422,6 +1422,9 @@ public:
|
||||
// stack overflow + shadow pages. Clobbers tsp and scratch registers.
|
||||
void bang_stack_size(Register Rsize, Register Rtsp, Register Rscratch);
|
||||
|
||||
// Check for reserved stack access in method being exited (for JIT)
|
||||
void reserved_stack_check();
|
||||
|
||||
virtual RegisterOrConstant delayed_value_impl(intptr_t* delayed_value_addr, Register tmp, int offset);
|
||||
|
||||
void verify_tlab();
|
||||
|
@ -1294,6 +1294,10 @@ void MachEpilogNode::emit(CodeBuffer &cbuf, PhaseRegAlloc *ra_) const {
|
||||
|
||||
__ verify_thread();
|
||||
|
||||
if (StackReservedPages > 0 && C->has_reserved_stack_access()) {
|
||||
__ reserved_stack_check();
|
||||
}
|
||||
|
||||
// If this does safepoint polling, then do it here
|
||||
if(do_polling() && ra_->C->is_method_compilation()) {
|
||||
AddressLiteral polling_page(os::get_polling_page());
|
||||
|
@ -5355,7 +5355,12 @@ class StubGenerator: public StubCodeGenerator {
|
||||
#endif // COMPILER2 !=> _LP64
|
||||
|
||||
// Build this early so it's available for the interpreter.
|
||||
StubRoutines::_throw_StackOverflowError_entry = generate_throw_exception("StackOverflowError throw_exception", CAST_FROM_FN_PTR(address, SharedRuntime::throw_StackOverflowError));
|
||||
StubRoutines::_throw_StackOverflowError_entry =
|
||||
generate_throw_exception("StackOverflowError throw_exception",
|
||||
CAST_FROM_FN_PTR(address, SharedRuntime::throw_StackOverflowError));
|
||||
StubRoutines::_throw_delayed_StackOverflowError_entry =
|
||||
generate_throw_exception("delayed StackOverflowError throw_exception",
|
||||
CAST_FROM_FN_PTR(address, SharedRuntime::throw_delayed_StackOverflowError));
|
||||
|
||||
if (UseCRC32Intrinsics) {
|
||||
// set table address before stub generation which use it
|
||||
|
@ -35,7 +35,10 @@ const char* VM_Version::_features_str = "";
|
||||
unsigned int VM_Version::_L2_data_cache_line_size = 0;
|
||||
|
||||
void VM_Version::initialize() {
|
||||
_features = determine_features();
|
||||
|
||||
assert(_features != VM_Version::unknown_m, "System pre-initialization is not complete.");
|
||||
guarantee(VM_Version::has_v9(), "only SPARC v9 is supported");
|
||||
|
||||
PrefetchCopyIntervalInBytes = prefetch_copy_interval_in_bytes();
|
||||
PrefetchScanIntervalInBytes = prefetch_scan_interval_in_bytes();
|
||||
PrefetchFieldsAhead = prefetch_fields_ahead();
|
||||
@ -60,8 +63,6 @@ void VM_Version::initialize() {
|
||||
FLAG_SET_DEFAULT(AllocatePrefetchStyle, 1);
|
||||
}
|
||||
|
||||
guarantee(VM_Version::has_v9(), "only SPARC v9 is supported");
|
||||
|
||||
UseSSE = 0; // Only on x86 and x64
|
||||
|
||||
_supports_cx8 = has_v9();
|
||||
|
@ -127,6 +127,8 @@ public:
|
||||
// Initialization
|
||||
static void initialize();
|
||||
|
||||
static void init_before_ergo() { _features = determine_features(); }
|
||||
|
||||
// Instruction support
|
||||
static bool has_v8() { return (_features & v8_instructions_m) != 0; }
|
||||
static bool has_v9() { return (_features & v9_instructions_m) != 0; }
|
||||
|
@ -518,6 +518,10 @@ void LIR_Assembler::return_op(LIR_Opr result) {
|
||||
// Pop the stack before the safepoint code
|
||||
__ remove_frame(initial_frame_size_in_bytes());
|
||||
|
||||
if (StackReservedPages > 0 && compilation()->has_reserved_stack_access()) {
|
||||
__ reserved_stack_check();
|
||||
}
|
||||
|
||||
bool result_is_oop = result->is_valid() ? result->is_oop() : false;
|
||||
|
||||
// Note: we do not need to round double result; float result has the right precision
|
||||
|
@ -57,4 +57,8 @@ const int StackAlignmentInBytes = 16;
|
||||
#define INCLUDE_RTM_OPT 1
|
||||
#endif
|
||||
|
||||
#if defined(LINUX) || defined(SOLARIS) || defined(__APPLE__)
|
||||
#define SUPPORT_RESERVED_STACK_AREA
|
||||
#endif
|
||||
|
||||
#endif // CPU_X86_VM_GLOBALDEFINITIONS_X86_HPP
|
||||
|
@ -57,9 +57,11 @@ define_pd_global(intx, InlineSmallCode, 1000);
|
||||
|
||||
#define DEFAULT_STACK_YELLOW_PAGES (NOT_WINDOWS(2) WINDOWS_ONLY(3))
|
||||
#define DEFAULT_STACK_RED_PAGES (1)
|
||||
#define DEFAULT_STACK_RESERVED_PAGES (NOT_WINDOWS(1) WINDOWS_ONLY(0))
|
||||
|
||||
#define MIN_STACK_YELLOW_PAGES DEFAULT_STACK_YELLOW_PAGES
|
||||
#define MIN_STACK_RED_PAGES DEFAULT_STACK_RED_PAGES
|
||||
#define MIN_STACK_RESERVED_PAGES (0)
|
||||
|
||||
#ifdef AMD64
|
||||
// Very large C++ stack frames using solaris-amd64 optimized builds
|
||||
@ -76,6 +78,7 @@ define_pd_global(intx, InlineSmallCode, 1000);
|
||||
define_pd_global(intx, StackYellowPages, DEFAULT_STACK_YELLOW_PAGES);
|
||||
define_pd_global(intx, StackRedPages, DEFAULT_STACK_RED_PAGES);
|
||||
define_pd_global(intx, StackShadowPages, DEFAULT_STACK_SHADOW_PAGES);
|
||||
define_pd_global(intx, StackReservedPages, DEFAULT_STACK_RESERVED_PAGES);
|
||||
|
||||
define_pd_global(bool, RewriteBytecodes, true);
|
||||
define_pd_global(bool, RewriteFrequentPairs, true);
|
||||
|
@ -1023,6 +1023,25 @@ void InterpreterMacroAssembler::remove_activation(
|
||||
// get sender sp
|
||||
movptr(rbx,
|
||||
Address(rbp, frame::interpreter_frame_sender_sp_offset * wordSize));
|
||||
if (StackReservedPages > 0) {
|
||||
// testing if reserved zone needs to be re-enabled
|
||||
Register rthread = LP64_ONLY(r15_thread) NOT_LP64(rcx);
|
||||
Label no_reserved_zone_enabling;
|
||||
|
||||
NOT_LP64(get_thread(rthread);)
|
||||
|
||||
cmpptr(rbx, Address(rthread, JavaThread::reserved_stack_activation_offset()));
|
||||
jcc(Assembler::lessEqual, no_reserved_zone_enabling);
|
||||
|
||||
call_VM_leaf(
|
||||
CAST_FROM_FN_PTR(address, SharedRuntime::enable_stack_reserved_zone), rthread);
|
||||
push(rthread);
|
||||
call_VM(noreg, CAST_FROM_FN_PTR(address,
|
||||
InterpreterRuntime::throw_delayed_StackOverflowError));
|
||||
should_not_reach_here();
|
||||
|
||||
bind(no_reserved_zone_enabling);
|
||||
}
|
||||
leave(); // remove frame anchor
|
||||
pop(ret_addr); // get return address
|
||||
mov(rsp, rbx); // set sp to sender sp
|
||||
|
@ -1067,6 +1067,22 @@ void MacroAssembler::bang_stack_size(Register size, Register tmp) {
|
||||
}
|
||||
}
|
||||
|
||||
void MacroAssembler::reserved_stack_check() {
|
||||
// testing if reserved zone needs to be enabled
|
||||
Label no_reserved_zone_enabling;
|
||||
Register thread = NOT_LP64(rsi) LP64_ONLY(r15_thread);
|
||||
NOT_LP64(get_thread(rsi);)
|
||||
|
||||
cmpptr(rsp, Address(thread, JavaThread::reserved_stack_activation_offset()));
|
||||
jcc(Assembler::below, no_reserved_zone_enabling);
|
||||
|
||||
call_VM_leaf(CAST_FROM_FN_PTR(address, SharedRuntime::enable_stack_reserved_zone), thread);
|
||||
jump(RuntimeAddress(StubRoutines::throw_delayed_StackOverflowError_entry()));
|
||||
should_not_reach_here();
|
||||
|
||||
bind(no_reserved_zone_enabling);
|
||||
}
|
||||
|
||||
int MacroAssembler::biased_locking_enter(Register lock_reg,
|
||||
Register obj_reg,
|
||||
Register swap_reg,
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 1997, 2013, 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
|
||||
@ -641,6 +641,9 @@ class MacroAssembler: public Assembler {
|
||||
// stack overflow + shadow pages. Also, clobbers tmp
|
||||
void bang_stack_size(Register size, Register tmp);
|
||||
|
||||
// Check for reserved stack access in method being exited (for JIT)
|
||||
void reserved_stack_check();
|
||||
|
||||
virtual RegisterOrConstant delayed_value_impl(intptr_t* delayed_value_addr,
|
||||
Register tmp,
|
||||
int offset);
|
||||
|
@ -3290,7 +3290,10 @@ class StubGenerator: public StubCodeGenerator {
|
||||
CAST_FROM_FN_PTR(address, SharedRuntime::d2l));
|
||||
|
||||
// Build this early so it's available for the interpreter
|
||||
StubRoutines::_throw_StackOverflowError_entry = generate_throw_exception("StackOverflowError throw_exception", CAST_FROM_FN_PTR(address, SharedRuntime::throw_StackOverflowError));
|
||||
StubRoutines::_throw_StackOverflowError_entry = generate_throw_exception("StackOverflowError throw_exception",
|
||||
CAST_FROM_FN_PTR(address, SharedRuntime::throw_StackOverflowError));
|
||||
StubRoutines::_throw_delayed_StackOverflowError_entry = generate_throw_exception("delayed StackOverflowError throw_exception",
|
||||
CAST_FROM_FN_PTR(address, SharedRuntime::throw_delayed_StackOverflowError));
|
||||
|
||||
if (UseCRC32Intrinsics) {
|
||||
// set table address before stub generation which use it
|
||||
|
@ -4410,6 +4410,11 @@ class StubGenerator: public StubCodeGenerator {
|
||||
CAST_FROM_FN_PTR(address,
|
||||
SharedRuntime::
|
||||
throw_StackOverflowError));
|
||||
StubRoutines::_throw_delayed_StackOverflowError_entry =
|
||||
generate_throw_exception("delayed StackOverflowError throw_exception",
|
||||
CAST_FROM_FN_PTR(address,
|
||||
SharedRuntime::
|
||||
throw_delayed_StackOverflowError));
|
||||
if (UseCRC32Intrinsics) {
|
||||
// set table address before stub generation which use it
|
||||
StubRoutines::_crc_table_adr = (address)StubRoutines::x86::_crc_table;
|
||||
|
@ -541,8 +541,8 @@ void InterpreterGenerator::generate_stack_overflow_check(void) {
|
||||
__ subptr(rax, stack_size);
|
||||
|
||||
// Use the maximum number of pages we might bang.
|
||||
const int max_pages = StackShadowPages > (StackRedPages+StackYellowPages) ? StackShadowPages :
|
||||
(StackRedPages+StackYellowPages);
|
||||
const int max_pages = StackShadowPages > (StackRedPages+StackYellowPages+StackReservedPages) ? StackShadowPages :
|
||||
(StackRedPages+StackYellowPages+StackReservedPages);
|
||||
|
||||
// add in the red and yellow zone sizes
|
||||
__ addptr(rax, max_pages * page_size);
|
||||
|
@ -670,17 +670,16 @@ void MachEpilogNode::format( PhaseRegAlloc *ra_, outputStream* st ) const {
|
||||
|
||||
void MachEpilogNode::emit(CodeBuffer &cbuf, PhaseRegAlloc *ra_) const {
|
||||
Compile *C = ra_->C;
|
||||
MacroAssembler _masm(&cbuf);
|
||||
|
||||
if (C->max_vector_size() > 16) {
|
||||
// Clear upper bits of YMM registers when current compiled code uses
|
||||
// wide vectors to avoid AVX <-> SSE transition penalty during call.
|
||||
MacroAssembler masm(&cbuf);
|
||||
masm.vzeroupper();
|
||||
_masm.vzeroupper();
|
||||
}
|
||||
// If method set FPU control word, restore to standard control word
|
||||
if (C->in_24_bit_fp_mode()) {
|
||||
MacroAssembler masm(&cbuf);
|
||||
masm.fldcw(ExternalAddress(StubRoutines::addr_fpu_cntrl_wrd_std()));
|
||||
_masm.fldcw(ExternalAddress(StubRoutines::addr_fpu_cntrl_wrd_std()));
|
||||
}
|
||||
|
||||
int framesize = C->frame_size_in_bytes();
|
||||
@ -702,6 +701,10 @@ void MachEpilogNode::emit(CodeBuffer &cbuf, PhaseRegAlloc *ra_) const {
|
||||
|
||||
emit_opcode(cbuf, 0x58 | EBP_enc);
|
||||
|
||||
if (StackReservedPages > 0 && C->has_reserved_stack_access()) {
|
||||
__ reserved_stack_check();
|
||||
}
|
||||
|
||||
if (do_polling() && C->is_method_compilation()) {
|
||||
cbuf.relocate(cbuf.insts_end(), relocInfo::poll_return_type, 0);
|
||||
emit_opcode(cbuf,0x85);
|
||||
@ -729,6 +732,7 @@ uint MachEpilogNode::size(PhaseRegAlloc *ra_) const {
|
||||
} else {
|
||||
size += framesize ? 3 : 0;
|
||||
}
|
||||
size += 64; // added to support ReservedStackAccess
|
||||
return size;
|
||||
}
|
||||
|
||||
|
@ -953,10 +953,11 @@ void MachEpilogNode::format(PhaseRegAlloc* ra_, outputStream* st) const
|
||||
void MachEpilogNode::emit(CodeBuffer& cbuf, PhaseRegAlloc* ra_) const
|
||||
{
|
||||
Compile* C = ra_->C;
|
||||
MacroAssembler _masm(&cbuf);
|
||||
|
||||
if (C->max_vector_size() > 16) {
|
||||
// Clear upper bits of YMM registers when current compiled code uses
|
||||
// wide vectors to avoid AVX <-> SSE transition penalty during call.
|
||||
MacroAssembler _masm(&cbuf);
|
||||
__ vzeroupper();
|
||||
}
|
||||
|
||||
@ -984,6 +985,10 @@ void MachEpilogNode::emit(CodeBuffer& cbuf, PhaseRegAlloc* ra_) const
|
||||
// popq rbp
|
||||
emit_opcode(cbuf, 0x58 | RBP_enc);
|
||||
|
||||
if (StackReservedPages > 0 && C->has_reserved_stack_access()) {
|
||||
__ reserved_stack_check();
|
||||
}
|
||||
|
||||
if (do_polling() && C->is_method_compilation()) {
|
||||
MacroAssembler _masm(&cbuf);
|
||||
AddressLiteral polling_page(os::get_polling_page(), relocInfo::poll_return_type);
|
||||
|
@ -48,14 +48,17 @@ define_pd_global(intx, InlineSmallCode, 1000 );
|
||||
#define DEFAULT_STACK_YELLOW_PAGES (2)
|
||||
#define DEFAULT_STACK_RED_PAGES (1)
|
||||
#define DEFAULT_STACK_SHADOW_PAGES (5 LP64_ONLY(+1) DEBUG_ONLY(+3))
|
||||
#define DEFAULT_STACK_RESERVED_PAGES (0)
|
||||
|
||||
#define MIN_STACK_YELLOW_PAGES DEFAULT_STACK_YELLOW_PAGES
|
||||
#define MIN_STACK_RED_PAGES DEFAULT_STACK_RED_PAGES
|
||||
#define MIN_STACK_SHADOW_PAGES DEFAULT_STACK_SHADOW_PAGES
|
||||
#define MIN_STACK_RESERVED_PAGES (0)
|
||||
|
||||
define_pd_global(intx, StackYellowPages, DEFAULT_STACK_YELLOW_PAGES);
|
||||
define_pd_global(intx, StackRedPages, DEFAULT_STACK_RED_PAGES);
|
||||
define_pd_global(intx, StackShadowPages, DEFAULT_STACK_SHADOW_PAGES);
|
||||
define_pd_global(intx, StackReservedPages, DEFAULT_STACK_RESERVED_PAGES);
|
||||
|
||||
define_pd_global(bool, RewriteBytecodes, true);
|
||||
define_pd_global(bool, RewriteFrequentPairs, true);
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2011, 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
|
||||
@ -170,7 +170,7 @@ final class HotSpotResolvedJavaMethodImpl extends HotSpotMethod implements HotSp
|
||||
* @return flags of this method
|
||||
*/
|
||||
private int getFlags() {
|
||||
return UNSAFE.getByte(metaspaceMethod + config().methodFlagsOffset);
|
||||
return UNSAFE.getShort(metaspaceMethod + config().methodFlagsOffset);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1244,7 +1244,7 @@ public class HotSpotVMConfig {
|
||||
@HotSpotVMField(name = "Method::_access_flags", type = "AccessFlags", get = HotSpotVMField.Type.OFFSET) @Stable public int methodAccessFlagsOffset;
|
||||
@HotSpotVMField(name = "Method::_constMethod", type = "ConstMethod*", get = HotSpotVMField.Type.OFFSET) @Stable public int methodConstMethodOffset;
|
||||
@HotSpotVMField(name = "Method::_intrinsic_id", type = "u2", get = HotSpotVMField.Type.OFFSET) @Stable public int methodIntrinsicIdOffset;
|
||||
@HotSpotVMField(name = "Method::_flags", type = "u1", get = HotSpotVMField.Type.OFFSET) @Stable public int methodFlagsOffset;
|
||||
@HotSpotVMField(name = "Method::_flags", type = "u2", get = HotSpotVMField.Type.OFFSET) @Stable public int methodFlagsOffset;
|
||||
@HotSpotVMField(name = "Method::_vtable_index", type = "int", get = HotSpotVMField.Type.OFFSET) @Stable public int methodVtableIndexOffset;
|
||||
|
||||
@HotSpotVMConstant(name = "Method::_jfr_towrite") @Stable public int methodFlagsJfrTowrite;
|
||||
|
118
hotspot/src/os/aix/vm/libodm_aix.cpp
Normal file
118
hotspot/src/os/aix/vm/libodm_aix.cpp
Normal file
@ -0,0 +1,118 @@
|
||||
/*
|
||||
* Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright 2015, 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
|
||||
* 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 "libodm_aix.hpp"
|
||||
#include "misc_aix.hpp"
|
||||
#include <stdlib.h>
|
||||
#include <dlfcn.h>
|
||||
#include <string.h>
|
||||
#include "runtime/arguments.hpp"
|
||||
|
||||
|
||||
dynamicOdm::dynamicOdm() {
|
||||
const char *libodmname = "/usr/lib/libodm.a(shr_64.o)";
|
||||
_libhandle = dlopen(libodmname, RTLD_MEMBER | RTLD_NOW);
|
||||
if (!_libhandle) {
|
||||
trcVerbose("Couldn't open %s", libodmname);
|
||||
return;
|
||||
}
|
||||
_odm_initialize = (fun_odm_initialize )dlsym(_libhandle, "odm_initialize" );
|
||||
_odm_set_path = (fun_odm_set_path )dlsym(_libhandle, "odm_set_path" );
|
||||
_odm_mount_class = (fun_odm_mount_class)dlsym(_libhandle, "odm_mount_class");
|
||||
_odm_get_obj = (fun_odm_get_obj )dlsym(_libhandle, "odm_get_obj" );
|
||||
_odm_terminate = (fun_odm_terminate )dlsym(_libhandle, "odm_terminate" );
|
||||
if (!_odm_initialize || !_odm_set_path || !_odm_mount_class || !_odm_get_obj || !_odm_terminate) {
|
||||
trcVerbose("Couldn't find all required odm symbols from %s", libodmname);
|
||||
dlclose(_libhandle);
|
||||
_libhandle = NULL;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
dynamicOdm::~dynamicOdm() {
|
||||
if (_libhandle) { dlclose(_libhandle); }
|
||||
}
|
||||
|
||||
|
||||
void odmWrapper::clean_data() { if (_data) { free(_data); _data = NULL; } }
|
||||
|
||||
|
||||
int odmWrapper::class_offset(char *field, bool is_aix_5)
|
||||
{
|
||||
assert(has_class(), "initialization");
|
||||
for (int i = 0; i < odm_class()->nelem; i++) {
|
||||
if (strcmp(odm_class()->elem[i].elemname, field) == 0) {
|
||||
int offset = odm_class()->elem[i].offset;
|
||||
if (is_aix_5) { offset += LINK_VAL_OFFSET; }
|
||||
return offset;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
void odmWrapper::determine_os_kernel_version(uint32_t* p_ver) {
|
||||
int major_aix_version = ((*p_ver) >> 24) & 0xFF,
|
||||
minor_aix_version = ((*p_ver) >> 16) & 0xFF;
|
||||
assert(*p_ver, "must be initialized");
|
||||
|
||||
odmWrapper odm("product", "/usr/lib/objrepos"); // could also use "lpp"
|
||||
if (!odm.has_class()) {
|
||||
trcVerbose("try_determine_os_kernel_version: odm init problem");
|
||||
return;
|
||||
}
|
||||
int voff, roff, moff, foff;
|
||||
bool is_aix_5 = (major_aix_version == 5);
|
||||
voff = odm.class_offset("ver", is_aix_5);
|
||||
roff = odm.class_offset("rel", is_aix_5);
|
||||
moff = odm.class_offset("mod", is_aix_5);
|
||||
foff = odm.class_offset("fix", is_aix_5);
|
||||
if (voff == -1 || roff == -1 || moff == -1 || foff == -1) {
|
||||
trcVerbose("try_determine_os_kernel_version: could not get offsets");
|
||||
return;
|
||||
}
|
||||
if (!odm.retrieve_obj("name='bos.mp64'")) {
|
||||
trcVerbose("try_determine_os_kernel_version: odm_get_obj failed");
|
||||
return;
|
||||
}
|
||||
int version, release, modification, fix_level;
|
||||
do {
|
||||
version = odm.read_short(voff);
|
||||
release = odm.read_short(roff);
|
||||
modification = odm.read_short(moff);
|
||||
fix_level = odm.read_short(foff);
|
||||
trcVerbose("odm found version: %d.%d.%d.%d", version, release, modification, fix_level);
|
||||
if (version >> 8 != 0 || release >> 8 != 0 || modification >> 8 != 0 || fix_level >> 8 != 0) {
|
||||
trcVerbose("8 bit numbers expected");
|
||||
return;
|
||||
}
|
||||
} while (odm.retrieve_obj());
|
||||
|
||||
if (version != major_aix_version || release != minor_aix_version) {
|
||||
trcVerbose("version determined by odm does not match uname");
|
||||
return;
|
||||
}
|
||||
*p_ver = version << 24 | release << 16 | modification << 8 | fix_level;
|
||||
}
|
106
hotspot/src/os/aix/vm/libodm_aix.hpp
Normal file
106
hotspot/src/os/aix/vm/libodm_aix.hpp
Normal file
@ -0,0 +1,106 @@
|
||||
/*
|
||||
* Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright 2015, 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
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
// Encapsulates the libodm library and provides more convenient interfaces.
|
||||
|
||||
#ifndef OS_AIX_VM_LIBODM_AIX_HPP
|
||||
#define OS_AIX_VM_LIBODM_AIX_HPP
|
||||
|
||||
#include <odmi.h>
|
||||
|
||||
|
||||
// The purpose of this code is to dynamically load the libodm library
|
||||
// instead of statically linking against it. The library is AIX-specific.
|
||||
// It only exists on AIX, not on PASE. In order to share binaries
|
||||
// between AIX and PASE, we can't directly link against it.
|
||||
|
||||
typedef int (*fun_odm_initialize )(void);
|
||||
typedef char* (*fun_odm_set_path )(char*);
|
||||
typedef CLASS_SYMBOL (*fun_odm_mount_class)(char*);
|
||||
typedef void* (*fun_odm_get_obj )(CLASS_SYMBOL, char*, void*, int);
|
||||
typedef int (*fun_odm_terminate )(void);
|
||||
|
||||
class dynamicOdm {
|
||||
void *_libhandle;
|
||||
protected:
|
||||
fun_odm_initialize _odm_initialize;
|
||||
fun_odm_set_path _odm_set_path;
|
||||
fun_odm_mount_class _odm_mount_class;
|
||||
fun_odm_get_obj _odm_get_obj;
|
||||
fun_odm_terminate _odm_terminate;
|
||||
public:
|
||||
dynamicOdm();
|
||||
~dynamicOdm();
|
||||
bool odm_loaded() {return _libhandle != NULL; }
|
||||
};
|
||||
|
||||
|
||||
// We provide a more convenient interface for odm access and
|
||||
// especially to determine the exact AIX kernel version.
|
||||
|
||||
class odmWrapper : private dynamicOdm {
|
||||
CLASS_SYMBOL _odm_class;
|
||||
char *_data;
|
||||
bool _initialized;
|
||||
void clean_data();
|
||||
|
||||
public:
|
||||
// Make sure everything gets initialized and cleaned up properly.
|
||||
explicit odmWrapper(char* odm_class_name, char* odm_path = NULL) : _odm_class((CLASS_SYMBOL)-1),
|
||||
_data(NULL), _initialized(false) {
|
||||
if (!odm_loaded()) { return; }
|
||||
_initialized = ((*_odm_initialize)() != -1);
|
||||
if (_initialized) {
|
||||
if (odm_path) { (*_odm_set_path)(odm_path); }
|
||||
_odm_class = (*_odm_mount_class)(odm_class_name);
|
||||
}
|
||||
}
|
||||
~odmWrapper() {
|
||||
if (_initialized) { (*_odm_terminate)(); clean_data(); }
|
||||
}
|
||||
|
||||
CLASS_SYMBOL odm_class() { return _odm_class; }
|
||||
bool has_class() { return odm_class() != (CLASS_SYMBOL)-1; }
|
||||
int class_offset(char *field, bool is_aix_5);
|
||||
char* data() { return _data; }
|
||||
|
||||
char* retrieve_obj(char* name = NULL) {
|
||||
clean_data();
|
||||
char *cnp = (char*)(void*)(*_odm_get_obj)(odm_class(), name, NULL, (name == NULL) ? ODM_NEXT : ODM_FIRST);
|
||||
if (cnp != (char*)-1) { _data = cnp; }
|
||||
return data();
|
||||
}
|
||||
|
||||
int read_short(int offs) {
|
||||
short *addr = (short*)(data() + offs);
|
||||
return *addr;
|
||||
}
|
||||
|
||||
// Determine the exact AIX kernel version as 4 byte value.
|
||||
// The high order 2 bytes must be initialized already. They can be determined by uname.
|
||||
static void determine_os_kernel_version(uint32_t* p_ver);
|
||||
};
|
||||
|
||||
#endif // OS_AIX_VM_LIBODM_AIX_HPP
|
@ -38,6 +38,7 @@
|
||||
#include "jvm_aix.h"
|
||||
#include "libo4.hpp"
|
||||
#include "libperfstat_aix.hpp"
|
||||
#include "libodm_aix.hpp"
|
||||
#include "loadlib_aix.hpp"
|
||||
#include "memory/allocation.inline.hpp"
|
||||
#include "memory/filemap.hpp"
|
||||
@ -197,9 +198,13 @@ int os::Aix::_page_size = -1;
|
||||
// -1 = uninitialized, 0 if AIX, 1 if OS/400 pase
|
||||
int os::Aix::_on_pase = -1;
|
||||
|
||||
// -1 = uninitialized, otherwise os version in the form 0xMMmm - MM:major, mm:minor
|
||||
// E.g. 0x0601 for AIX 6.1 or 0x0504 for OS/400 V5R4
|
||||
int os::Aix::_os_version = -1;
|
||||
// 0 = uninitialized, otherwise 32 bit number:
|
||||
// 0xVVRRTTSS
|
||||
// VV - major version
|
||||
// RR - minor version
|
||||
// TT - tech level, if known, 0 otherwise
|
||||
// SS - service pack, if known, 0 otherwise
|
||||
uint32_t os::Aix::_os_version = 0;
|
||||
|
||||
int os::Aix::_stack_page_size = -1;
|
||||
|
||||
@ -358,7 +363,7 @@ static char cpu_arch[] = "ppc64";
|
||||
|
||||
// Wrap the function "vmgetinfo" which is not available on older OS releases.
|
||||
static int checked_vmgetinfo(void *out, int command, int arg) {
|
||||
if (os::Aix::on_pase() && os::Aix::os_version() < 0x0601) {
|
||||
if (os::Aix::on_pase() && os::Aix::os_version_short() < 0x0601) {
|
||||
guarantee(false, "cannot call vmgetinfo on AS/400 older than V6R1");
|
||||
}
|
||||
return ::vmgetinfo(out, command, arg);
|
||||
@ -367,7 +372,7 @@ static int checked_vmgetinfo(void *out, int command, int arg) {
|
||||
// Given an address, returns the size of the page backing that address.
|
||||
size_t os::Aix::query_pagesize(void* addr) {
|
||||
|
||||
if (os::Aix::on_pase() && os::Aix::os_version() < 0x0601) {
|
||||
if (os::Aix::on_pase() && os::Aix::os_version_short() < 0x0601) {
|
||||
// AS/400 older than V6R1: no vmgetinfo here, default to 4K
|
||||
return SIZE_4K;
|
||||
}
|
||||
@ -1211,7 +1216,7 @@ void os::shutdown() {
|
||||
// Note: os::abort() might be called very early during initialization, or
|
||||
// called from signal handler. Before adding something to os::abort(), make
|
||||
// sure it is async-safe and can handle partially initialized VM.
|
||||
void os::abort(bool dump_core, void* siginfo, void* context) {
|
||||
void os::abort(bool dump_core, void* siginfo, const void* context) {
|
||||
os::shutdown();
|
||||
if (dump_core) {
|
||||
#ifndef PRODUCT
|
||||
@ -1491,6 +1496,10 @@ void os::print_os_info(outputStream* st) {
|
||||
st->print(name.machine);
|
||||
st->cr();
|
||||
|
||||
uint32_t ver = os::Aix::os_version();
|
||||
st->print_cr("AIX kernel version %u.%u.%u.%u",
|
||||
(ver >> 24) & 0xFF, (ver >> 16) & 0xFF, (ver >> 8) & 0xFF, ver & 0xFF);
|
||||
|
||||
// rlimit
|
||||
st->print("rlimit:");
|
||||
struct rlimit rlim;
|
||||
@ -3806,7 +3815,7 @@ void PcFetcher::do_task(const os::SuspendedThreadTaskContext& context) {
|
||||
Thread* thread = context.thread();
|
||||
OSThread* osthread = thread->osthread();
|
||||
if (osthread->ucontext() != NULL) {
|
||||
_epc = os::Aix::ucontext_get_pc((ucontext_t *) context.ucontext());
|
||||
_epc = os::Aix::ucontext_get_pc((const ucontext_t *) context.ucontext());
|
||||
} else {
|
||||
// NULL context is unexpected, double-check this is the VMThread.
|
||||
guarantee(thread->is_VM_thread(), "can only be called for VMThread");
|
||||
@ -4255,7 +4264,7 @@ bool os::Aix::is_primordial_thread() {
|
||||
// one of Aix::on_pase(), Aix::os_version() static
|
||||
void os::Aix::initialize_os_info() {
|
||||
|
||||
assert(_on_pase == -1 && _os_version == -1, "already called.");
|
||||
assert(_on_pase == -1 && _os_version == 0, "already called.");
|
||||
|
||||
struct utsname uts;
|
||||
memset(&uts, 0, sizeof(uts));
|
||||
@ -4271,28 +4280,34 @@ void os::Aix::initialize_os_info() {
|
||||
assert(major > 0, "invalid OS version");
|
||||
const int minor = atoi(uts.release);
|
||||
assert(minor > 0, "invalid OS release");
|
||||
_os_version = (major << 8) | minor;
|
||||
_os_version = (major << 24) | (minor << 16);
|
||||
char ver_str[20] = {0};
|
||||
char *name_str = "unknown OS";
|
||||
if (strcmp(uts.sysname, "OS400") == 0) {
|
||||
// We run on AS/400 PASE. We do not support versions older than V5R4M0.
|
||||
_on_pase = 1;
|
||||
if (_os_version < 0x0504) {
|
||||
if (os_version_short() < 0x0504) {
|
||||
trcVerbose("OS/400 releases older than V5R4M0 not supported.");
|
||||
assert(false, "OS/400 release too old.");
|
||||
} else {
|
||||
trcVerbose("We run on OS/400 (pase) V%dR%d", major, minor);
|
||||
}
|
||||
name_str = "OS/400 (pase)";
|
||||
jio_snprintf(ver_str, sizeof(ver_str), "%u.%u", major, minor);
|
||||
} else if (strcmp(uts.sysname, "AIX") == 0) {
|
||||
// We run on AIX. We do not support versions older than AIX 5.3.
|
||||
_on_pase = 0;
|
||||
if (_os_version < 0x0503) {
|
||||
// Determine detailed AIX version: Version, Release, Modification, Fix Level.
|
||||
odmWrapper::determine_os_kernel_version(&_os_version);
|
||||
if (os_version_short() < 0x0503) {
|
||||
trcVerbose("AIX release older than AIX 5.3 not supported.");
|
||||
assert(false, "AIX release too old.");
|
||||
} else {
|
||||
trcVerbose("We run on AIX %d.%d", major, minor);
|
||||
}
|
||||
name_str = "AIX";
|
||||
jio_snprintf(ver_str, sizeof(ver_str), "%u.%u.%u.%u",
|
||||
major, minor, (_os_version >> 8) & 0xFF, _os_version & 0xFF);
|
||||
} else {
|
||||
assert(false, "unknown OS");
|
||||
assert(false, name_str);
|
||||
}
|
||||
trcVerbose("We run on %s %s", name_str, ver_str);
|
||||
}
|
||||
|
||||
guarantee(_on_pase != -1 && _os_version, "Could not determine AIX/OS400 release");
|
||||
@ -4357,7 +4372,7 @@ void os::Aix::scan_environment() {
|
||||
|
||||
p = ::getenv("LDR_CNTRL");
|
||||
trcVerbose("LDR_CNTRL=%s.", p ? p : "<unset>");
|
||||
if (os::Aix::on_pase() && os::Aix::os_version() == 0x0701) {
|
||||
if (os::Aix::on_pase() && os::Aix::os_version_short() == 0x0701) {
|
||||
if (p && ::strstr(p, "TEXTPSIZE")) {
|
||||
trcVerbose("*** WARNING - LDR_CNTRL contains TEXTPSIZE. "
|
||||
"you may experience hangs or crashes on OS/400 V7R1.");
|
||||
@ -5016,7 +5031,7 @@ void TestReserveMemorySpecial_test() {
|
||||
}
|
||||
#endif
|
||||
|
||||
bool os::start_debugging(char *buf, int buflen) {
|
||||
bool os::start_debugging(char *buf, int buflen) {
|
||||
int len = (int)strlen(buf);
|
||||
char *p = &buf[len];
|
||||
|
||||
|
@ -55,15 +55,12 @@ class Aix {
|
||||
// -1 = uninitialized, 0 = AIX, 1 = OS/400 (PASE)
|
||||
static int _on_pase;
|
||||
|
||||
// -1 = uninitialized, otherwise 16 bit number:
|
||||
// 0 = uninitialized, otherwise 16 bit number:
|
||||
// lower 8 bit - minor version
|
||||
// higher 8 bit - major version
|
||||
// For AIX, e.g. 0x0601 for AIX 6.1
|
||||
// for OS/400 e.g. 0x0504 for OS/400 V5R4
|
||||
static int _os_version;
|
||||
|
||||
// 4 Byte kernel version: Version, Release, Tech Level, Service Pack.
|
||||
static unsigned int _os_kernel_version;
|
||||
static uint32_t _os_version;
|
||||
|
||||
// -1 = uninitialized,
|
||||
// 0 - SPEC1170 not requested (XPG_SUS_ENV is OFF or not set)
|
||||
@ -126,8 +123,8 @@ class Aix {
|
||||
static int vm_default_page_size(void ) { return 8*K; }
|
||||
|
||||
static address ucontext_get_pc(const ucontext_t* uc);
|
||||
static intptr_t* ucontext_get_sp(ucontext_t* uc);
|
||||
static intptr_t* ucontext_get_fp(ucontext_t* uc);
|
||||
static intptr_t* ucontext_get_sp(const ucontext_t* uc);
|
||||
static intptr_t* ucontext_get_fp(const ucontext_t* uc);
|
||||
// Set PC into context. Needed for continuation after signal.
|
||||
static void ucontext_set_pc(ucontext_t* uc, address pc);
|
||||
|
||||
@ -175,32 +172,31 @@ class Aix {
|
||||
return _on_pase ? false : true;
|
||||
}
|
||||
|
||||
// -1 = uninitialized, otherwise 16 bit number:
|
||||
// Get 4 byte AIX kernel version number:
|
||||
// highest 2 bytes: Version, Release
|
||||
// if available: lowest 2 bytes: Tech Level, Service Pack.
|
||||
static uint32_t os_version() {
|
||||
assert(_os_version != 0, "not initialized");
|
||||
return _os_version;
|
||||
}
|
||||
|
||||
// 0 = uninitialized, otherwise 16 bit number:
|
||||
// lower 8 bit - minor version
|
||||
// higher 8 bit - major version
|
||||
// For AIX, e.g. 0x0601 for AIX 6.1
|
||||
// for OS/400 e.g. 0x0504 for OS/400 V5R4
|
||||
static int os_version () {
|
||||
assert(_os_version != -1, "not initialized");
|
||||
return _os_version;
|
||||
}
|
||||
|
||||
// Get 4 byte AIX kernel version number:
|
||||
// highest 2 bytes: Version, Release
|
||||
// if available: lowest 2 bytes: Tech Level, Service Pack.
|
||||
static unsigned int os_kernel_version() {
|
||||
if (_os_kernel_version) return _os_kernel_version;
|
||||
return os_version() << 16;
|
||||
static int os_version_short() {
|
||||
return os_version() >> 16;
|
||||
}
|
||||
|
||||
// Convenience method: returns true if running on PASE V5R4 or older.
|
||||
static bool on_pase_V5R4_or_older() {
|
||||
return on_pase() && os_version() <= 0x0504;
|
||||
return on_pase() && os_version_short() <= 0x0504;
|
||||
}
|
||||
|
||||
// Convenience method: returns true if running on AIX 5.3 or older.
|
||||
static bool on_aix_53_or_older() {
|
||||
return on_aix() && os_version() <= 0x0503;
|
||||
return on_aix() && os_version_short() <= 0x0503;
|
||||
}
|
||||
|
||||
// Returns true if we run in SPEC1170 compliant mode (XPG_SUS_ENV=ON).
|
||||
|
@ -1077,7 +1077,7 @@ void os::shutdown() {
|
||||
// Note: os::abort() might be called very early during initialization, or
|
||||
// called from signal handler. Before adding something to os::abort(), make
|
||||
// sure it is async-safe and can handle partially initialized VM.
|
||||
void os::abort(bool dump_core, void* siginfo, void* context) {
|
||||
void os::abort(bool dump_core, void* siginfo, const void* context) {
|
||||
os::shutdown();
|
||||
if (dump_core) {
|
||||
#ifndef PRODUCT
|
||||
@ -3497,7 +3497,7 @@ jint os::init_2(void) {
|
||||
// Add in 2*BytesPerWord times page size to account for VM stack during
|
||||
// class initialization depending on 32 or 64 bit VM.
|
||||
os::Bsd::min_stack_allowed = MAX2(os::Bsd::min_stack_allowed,
|
||||
(size_t)(StackYellowPages+StackRedPages+StackShadowPages+
|
||||
(size_t)(StackReservedPages+StackYellowPages+StackRedPages+StackShadowPages+
|
||||
2*BytesPerWord COMPILER2_PRESENT(+1)) * Bsd::page_size());
|
||||
|
||||
size_t threadStackSizeInBytes = ThreadStackSize * K;
|
||||
@ -3643,7 +3643,7 @@ void PcFetcher::do_task(const os::SuspendedThreadTaskContext& context) {
|
||||
Thread* thread = context.thread();
|
||||
OSThread* osthread = thread->osthread();
|
||||
if (osthread->ucontext() != NULL) {
|
||||
_epc = os::Bsd::ucontext_get_pc((ucontext_t *) context.ucontext());
|
||||
_epc = os::Bsd::ucontext_get_pc((const ucontext_t *) context.ucontext());
|
||||
} else {
|
||||
// NULL context is unexpected, double-check this is the VMThread
|
||||
guarantee(thread->is_VM_thread(), "can only be called for VMThread");
|
||||
|
@ -86,19 +86,21 @@ class Bsd {
|
||||
static int page_size(void) { return _page_size; }
|
||||
static void set_page_size(int val) { _page_size = val; }
|
||||
|
||||
static address ucontext_get_pc(ucontext_t* uc);
|
||||
static address ucontext_get_pc(const 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);
|
||||
static intptr_t* ucontext_get_sp(const ucontext_t* uc);
|
||||
static intptr_t* ucontext_get_fp(const ucontext_t* uc);
|
||||
|
||||
// For Analyzer Forte AsyncGetCallTrace profiling support:
|
||||
//
|
||||
// This interface should be declared in os_bsd_i486.hpp, but
|
||||
// that file provides extensions to the os class and not the
|
||||
// Bsd class.
|
||||
static ExtendedPC fetch_frame_from_ucontext(Thread* thread, ucontext_t* uc,
|
||||
static ExtendedPC fetch_frame_from_ucontext(Thread* thread, const ucontext_t* uc,
|
||||
intptr_t** ret_sp, intptr_t** ret_fp);
|
||||
|
||||
static bool get_frame_at_stack_banging_point(JavaThread* thread, ucontext_t* uc, frame* fr);
|
||||
|
||||
// This boolean allows users to forward their own non-matching signals
|
||||
// to JVM_handle_bsd_signal, harmlessly.
|
||||
static bool signal_handlers_are_installed;
|
||||
|
@ -1341,7 +1341,7 @@ void os::shutdown() {
|
||||
// Note: os::abort() might be called very early during initialization, or
|
||||
// called from signal handler. Before adding something to os::abort(), make
|
||||
// sure it is async-safe and can handle partially initialized VM.
|
||||
void os::abort(bool dump_core, void* siginfo, void* context) {
|
||||
void os::abort(bool dump_core, void* siginfo, const void* context) {
|
||||
os::shutdown();
|
||||
if (dump_core) {
|
||||
#ifndef PRODUCT
|
||||
@ -1733,7 +1733,7 @@ void * os::dll_load(const char *filename, char *ebuf, int ebuflen) {
|
||||
#if defined(VM_LITTLE_ENDIAN)
|
||||
{EM_PPC64, EM_PPC64, ELFCLASS64, ELFDATA2LSB, (char*)"Power PC 64"},
|
||||
#else
|
||||
{EM_PPC64, EM_PPC64, ELFCLASS64, ELFDATA2MSB, (char*)"Power PC 64"},
|
||||
{EM_PPC64, EM_PPC64, ELFCLASS64, ELFDATA2MSB, (char*)"Power PC 64 LE"},
|
||||
#endif
|
||||
{EM_ARM, EM_ARM, ELFCLASS32, ELFDATA2LSB, (char*)"ARM"},
|
||||
{EM_S390, EM_S390, ELFCLASSNONE, ELFDATA2MSB, (char*)"IBM System/390"},
|
||||
@ -1861,8 +1861,8 @@ void * os::Linux::dll_load_in_vmthread(const char *filename, char *ebuf,
|
||||
JavaThread *jt = Threads::first();
|
||||
|
||||
while (jt) {
|
||||
if (!jt->stack_guard_zone_unused() && // Stack not yet fully initialized
|
||||
jt->stack_yellow_zone_enabled()) { // No pending stack overflow exceptions
|
||||
if (!jt->stack_guard_zone_unused() && // Stack not yet fully initialized
|
||||
jt->stack_guards_enabled()) { // No pending stack overflow exceptions
|
||||
if (!os::guard_memory((char *) jt->stack_red_zone_base() - jt->stack_red_zone_size(),
|
||||
jt->stack_yellow_zone_size() + jt->stack_red_zone_size())) {
|
||||
warning("Attempt to reguard stack yellow zone failed.");
|
||||
@ -2177,6 +2177,8 @@ void os::pd_print_cpu_info(outputStream* st, char* buf, size_t buflen) {
|
||||
const char* search_string = "model name";
|
||||
#elif defined(SPARC)
|
||||
const char* search_string = "cpu";
|
||||
#elif defined(PPC64)
|
||||
const char* search_string = "cpu";
|
||||
#else
|
||||
const char* search_string = "Processor";
|
||||
#endif
|
||||
@ -4603,6 +4605,11 @@ void os::init(void) {
|
||||
if (vm_page_size() > (int)Linux::vm_default_page_size()) {
|
||||
StackYellowPages = 1;
|
||||
StackRedPages = 1;
|
||||
#if defined(IA32) || defined(IA64)
|
||||
StackReservedPages = 1;
|
||||
#else
|
||||
StackReservedPages = 0;
|
||||
#endif
|
||||
StackShadowPages = round_to((StackShadowPages*Linux::vm_default_page_size()), vm_page_size()) / vm_page_size();
|
||||
}
|
||||
|
||||
@ -4664,7 +4671,7 @@ jint os::init_2(void) {
|
||||
// Add in 2*BytesPerWord times page size to account for VM stack during
|
||||
// class initialization depending on 32 or 64 bit VM.
|
||||
os::Linux::min_stack_allowed = MAX2(os::Linux::min_stack_allowed,
|
||||
(size_t)(StackYellowPages+StackRedPages+StackShadowPages) * Linux::page_size() +
|
||||
(size_t)(StackReservedPages+StackYellowPages+StackRedPages+StackShadowPages) * Linux::page_size() +
|
||||
(2*BytesPerWord COMPILER2_PRESENT(+1)) * Linux::vm_default_page_size());
|
||||
|
||||
size_t threadStackSizeInBytes = ThreadStackSize * K;
|
||||
@ -4846,7 +4853,7 @@ void PcFetcher::do_task(const os::SuspendedThreadTaskContext& context) {
|
||||
Thread* thread = context.thread();
|
||||
OSThread* osthread = thread->osthread();
|
||||
if (osthread->ucontext() != NULL) {
|
||||
_epc = os::Linux::ucontext_get_pc((ucontext_t *) context.ucontext());
|
||||
_epc = os::Linux::ucontext_get_pc((const ucontext_t *) context.ucontext());
|
||||
} else {
|
||||
// NULL context is unexpected, double-check this is the VMThread
|
||||
guarantee(thread->is_VM_thread(), "can only be called for VMThread");
|
||||
|
@ -123,19 +123,21 @@ class Linux {
|
||||
|
||||
static int vm_default_page_size(void) { return _vm_default_page_size; }
|
||||
|
||||
static address ucontext_get_pc(ucontext_t* uc);
|
||||
static address ucontext_get_pc(const 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);
|
||||
static intptr_t* ucontext_get_sp(const ucontext_t* uc);
|
||||
static intptr_t* ucontext_get_fp(const ucontext_t* uc);
|
||||
|
||||
// For Analyzer Forte AsyncGetCallTrace profiling support:
|
||||
//
|
||||
// This interface should be declared in os_linux_i486.hpp, but
|
||||
// that file provides extensions to the os class and not the
|
||||
// Linux class.
|
||||
static ExtendedPC fetch_frame_from_ucontext(Thread* thread, ucontext_t* uc,
|
||||
static ExtendedPC fetch_frame_from_ucontext(Thread* thread, const ucontext_t* uc,
|
||||
intptr_t** ret_sp, intptr_t** ret_fp);
|
||||
|
||||
static bool get_frame_at_stack_banging_point(JavaThread* thread, ucontext_t* uc, frame* fr);
|
||||
|
||||
// This boolean allows users to forward their own non-matching signals
|
||||
// to JVM_handle_linux_signal, harmlessly.
|
||||
static bool signal_handlers_are_installed;
|
||||
|
@ -736,12 +736,12 @@ bool os::Posix::is_valid_signal(int sig) {
|
||||
}
|
||||
|
||||
// Returns:
|
||||
// "invalid (<num>)" for an invalid signal number
|
||||
// NULL for an invalid signal number
|
||||
// "SIG<num>" for a valid but unknown signal number
|
||||
// signal name otherwise.
|
||||
const char* os::exception_name(int sig, char* buf, size_t size) {
|
||||
if (!os::Posix::is_valid_signal(sig)) {
|
||||
jio_snprintf(buf, size, "invalid (%d)", sig);
|
||||
return NULL;
|
||||
}
|
||||
const char* const name = os::Posix::get_signal_name(sig, buf, size);
|
||||
if (strcmp(name, "UNKNOWN") == 0) {
|
||||
@ -1031,7 +1031,7 @@ int os::Posix::unblock_thread_signal_mask(const sigset_t *set) {
|
||||
return pthread_sigmask(SIG_UNBLOCK, set, NULL);
|
||||
}
|
||||
|
||||
address os::Posix::ucontext_get_pc(ucontext_t* ctx) {
|
||||
address os::Posix::ucontext_get_pc(const ucontext_t* ctx) {
|
||||
#ifdef TARGET_OS_FAMILY_linux
|
||||
return Linux::ucontext_get_pc(ctx);
|
||||
#elif defined(TARGET_OS_FAMILY_solaris)
|
||||
|
@ -76,7 +76,7 @@ public:
|
||||
// A POSIX conform, platform-independend siginfo print routine.
|
||||
static void print_siginfo_brief(outputStream* os, const siginfo_t* si);
|
||||
|
||||
static address ucontext_get_pc(ucontext_t* ctx);
|
||||
static address ucontext_get_pc(const ucontext_t* ctx);
|
||||
// Set PC into context. Needed for continuation after signal.
|
||||
static void ucontext_set_pc(ucontext_t* ctx, address pc);
|
||||
};
|
||||
|
@ -1380,7 +1380,7 @@ void os::shutdown() {
|
||||
// Note: os::abort() might be called very early during initialization, or
|
||||
// called from signal handler. Before adding something to os::abort(), make
|
||||
// sure it is async-safe and can handle partially initialized VM.
|
||||
void os::abort(bool dump_core, void* siginfo, void* context) {
|
||||
void os::abort(bool dump_core, void* siginfo, const void* context) {
|
||||
os::shutdown();
|
||||
if (dump_core) {
|
||||
#ifndef PRODUCT
|
||||
@ -3736,7 +3736,7 @@ void PcFetcher::do_task(const os::SuspendedThreadTaskContext& context) {
|
||||
Thread* thread = context.thread();
|
||||
OSThread* osthread = thread->osthread();
|
||||
if (osthread->ucontext() != NULL) {
|
||||
_epc = os::Solaris::ucontext_get_pc((ucontext_t *) context.ucontext());
|
||||
_epc = os::Solaris::ucontext_get_pc((const ucontext_t *) context.ucontext());
|
||||
} else {
|
||||
// NULL context is unexpected, double-check this is the VMThread
|
||||
guarantee(thread->is_VM_thread(), "can only be called for VMThread");
|
||||
@ -4382,6 +4382,7 @@ void os::init(void) {
|
||||
if (vm_page_size() > 8*K) {
|
||||
StackYellowPages = 1;
|
||||
StackRedPages = 1;
|
||||
StackReservedPages = 1;
|
||||
StackShadowPages = round_to((StackShadowPages*8*K), vm_page_size()) / vm_page_size();
|
||||
}
|
||||
}
|
||||
@ -4438,7 +4439,7 @@ jint os::init_2(void) {
|
||||
// Add in 2*BytesPerWord times page size to account for VM stack during
|
||||
// class initialization depending on 32 or 64 bit VM.
|
||||
os::Solaris::min_stack_allowed = MAX2(os::Solaris::min_stack_allowed,
|
||||
(size_t)(StackYellowPages+StackRedPages+StackShadowPages+
|
||||
(size_t)(StackReservedPages+StackYellowPages+StackRedPages+StackShadowPages+
|
||||
2*BytesPerWord COMPILER2_PRESENT(+1)) * page_size);
|
||||
|
||||
size_t threadStackSizeInBytes = ThreadStackSize * K;
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved.
|
||||
* 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
|
||||
@ -130,15 +130,15 @@ class Solaris {
|
||||
static address handler_start, handler_end; // start and end pc of thr_sighndlrinfo
|
||||
|
||||
static bool valid_stack_address(Thread* thread, address sp);
|
||||
static bool valid_ucontext(Thread* thread, ucontext_t* valid, ucontext_t* suspect);
|
||||
static ucontext_t* get_valid_uc_in_signal_handler(Thread* thread,
|
||||
ucontext_t* uc);
|
||||
static bool valid_ucontext(Thread* thread, const ucontext_t* valid, const ucontext_t* suspect);
|
||||
static const ucontext_t* get_valid_uc_in_signal_handler(Thread* thread,
|
||||
const ucontext_t* uc);
|
||||
|
||||
static ExtendedPC ucontext_get_ExtendedPC(ucontext_t* uc);
|
||||
static intptr_t* ucontext_get_sp(ucontext_t* uc);
|
||||
static ExtendedPC ucontext_get_ExtendedPC(const ucontext_t* uc);
|
||||
static intptr_t* ucontext_get_sp(const ucontext_t* uc);
|
||||
// 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 intptr_t* ucontext_get_fp(const ucontext_t* uc);
|
||||
static address ucontext_get_pc(const ucontext_t* uc);
|
||||
static void ucontext_set_pc(ucontext_t* uc, address pc);
|
||||
|
||||
// For Analyzer Forte AsyncGetCallTrace profiling support:
|
||||
@ -147,9 +147,11 @@ class Solaris {
|
||||
// We should have different declarations of this interface in
|
||||
// os_solaris_i486.hpp and os_solaris_sparc.hpp, but that file
|
||||
// provides extensions to the os class and not the Solaris class.
|
||||
static ExtendedPC fetch_frame_from_ucontext(Thread* thread, ucontext_t* uc,
|
||||
static ExtendedPC fetch_frame_from_ucontext(Thread* thread, const ucontext_t* uc,
|
||||
intptr_t** ret_sp, intptr_t** ret_fp);
|
||||
|
||||
static bool get_frame_at_stack_banging_point(JavaThread* thread, ucontext_t* uc, frame* fr);
|
||||
|
||||
static void hotspot_sigmask(Thread* thread);
|
||||
|
||||
// SR_handler
|
||||
|
@ -1028,7 +1028,7 @@ void os::check_dump_limit(char* buffer, size_t buffsz) {
|
||||
VMError::record_coredump_status(buffer, status);
|
||||
}
|
||||
|
||||
void os::abort(bool dump_core, void* siginfo, void* context) {
|
||||
void os::abort(bool dump_core, void* siginfo, const void* context) {
|
||||
HINSTANCE dbghelp;
|
||||
EXCEPTION_POINTERS ep;
|
||||
MINIDUMP_EXCEPTION_INFORMATION mei;
|
||||
@ -2374,6 +2374,39 @@ static inline void report_error(Thread* t, DWORD exception_code,
|
||||
// somewhere where we can find it in the minidump.
|
||||
}
|
||||
|
||||
bool os::win32::get_frame_at_stack_banging_point(JavaThread* thread,
|
||||
struct _EXCEPTION_POINTERS* exceptionInfo, address pc, frame* fr) {
|
||||
PEXCEPTION_RECORD exceptionRecord = exceptionInfo->ExceptionRecord;
|
||||
address addr = (address) exceptionRecord->ExceptionInformation[1];
|
||||
if (Interpreter::contains(pc)) {
|
||||
*fr = os::fetch_frame_from_context((void*)exceptionInfo->ContextRecord);
|
||||
if (!fr->is_first_java_frame()) {
|
||||
assert(fr->safe_for_sender(thread), "Safety check");
|
||||
*fr = fr->java_sender();
|
||||
}
|
||||
} else {
|
||||
// more complex code with compiled code
|
||||
assert(!Interpreter::contains(pc), "Interpreted methods should have been handled above");
|
||||
CodeBlob* cb = CodeCache::find_blob(pc);
|
||||
if (cb == NULL || !cb->is_nmethod() || cb->is_frame_complete_at(pc)) {
|
||||
// Not sure where the pc points to, fallback to default
|
||||
// stack overflow handling
|
||||
return false;
|
||||
} else {
|
||||
*fr = os::fetch_frame_from_context((void*)exceptionInfo->ContextRecord);
|
||||
// in compiled code, the stack banging is performed just after the return pc
|
||||
// has been pushed on the stack
|
||||
*fr = frame(fr->sp() + 1, fr->fp(), (address)*(fr->sp()));
|
||||
if (!fr->is_java_frame()) {
|
||||
assert(fr->safe_for_sender(thread), "Safety check");
|
||||
*fr = fr->java_sender();
|
||||
}
|
||||
}
|
||||
}
|
||||
assert(fr->is_java_frame(), "Safety check");
|
||||
return true;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
LONG WINAPI topLevelExceptionFilter(struct _EXCEPTION_POINTERS* exceptionInfo) {
|
||||
if (InterceptOSException) return EXCEPTION_CONTINUE_SEARCH;
|
||||
@ -2550,7 +2583,16 @@ LONG WINAPI topLevelExceptionFilter(struct _EXCEPTION_POINTERS* exceptionInfo) {
|
||||
SharedRuntime::continuation_for_implicit_exception(thread, pc, SharedRuntime::STACK_OVERFLOW));
|
||||
}
|
||||
#endif
|
||||
if (thread->stack_yellow_zone_enabled()) {
|
||||
if (thread->stack_guards_enabled()) {
|
||||
if (_thread_in_Java) {
|
||||
frame fr;
|
||||
PEXCEPTION_RECORD exceptionRecord = exceptionInfo->ExceptionRecord;
|
||||
address addr = (address) exceptionRecord->ExceptionInformation[1];
|
||||
if (os::win32::get_frame_at_stack_banging_point(thread, exceptionInfo, pc, &fr)) {
|
||||
assert(fr.is_java_frame(), "Must be a Java frame");
|
||||
SharedRuntime::look_for_reserved_stack_annotated_method(thread, fr);
|
||||
}
|
||||
}
|
||||
// Yellow zone violation. The o/s has unprotected the first yellow
|
||||
// zone page for us. Note: must call disable_stack_yellow_zone to
|
||||
// update the enabled status, even if the zone contains only one page.
|
||||
@ -5529,8 +5571,6 @@ bool os::start_debugging(char *buf, int buflen) {
|
||||
return yes;
|
||||
}
|
||||
|
||||
#ifndef JDK6_OR_EARLIER
|
||||
|
||||
void os::Kernel32Dll::initialize() {
|
||||
initializeCommon();
|
||||
}
|
||||
@ -5705,261 +5745,6 @@ char* os::build_agent_function_name(const char *sym_name, const char *lib_name,
|
||||
return agent_entry_name;
|
||||
}
|
||||
|
||||
#else
|
||||
// Kernel32 API
|
||||
typedef BOOL (WINAPI* SwitchToThread_Fn)(void);
|
||||
typedef HANDLE (WINAPI* CreateToolhelp32Snapshot_Fn)(DWORD, DWORD);
|
||||
typedef BOOL (WINAPI* Module32First_Fn)(HANDLE, LPMODULEENTRY32);
|
||||
typedef BOOL (WINAPI* Module32Next_Fn)(HANDLE, LPMODULEENTRY32);
|
||||
typedef void (WINAPI* GetNativeSystemInfo_Fn)(LPSYSTEM_INFO);
|
||||
|
||||
SwitchToThread_Fn os::Kernel32Dll::_SwitchToThread = NULL;
|
||||
CreateToolhelp32Snapshot_Fn os::Kernel32Dll::_CreateToolhelp32Snapshot = NULL;
|
||||
Module32First_Fn os::Kernel32Dll::_Module32First = NULL;
|
||||
Module32Next_Fn os::Kernel32Dll::_Module32Next = NULL;
|
||||
GetNativeSystemInfo_Fn os::Kernel32Dll::_GetNativeSystemInfo = NULL;
|
||||
|
||||
void os::Kernel32Dll::initialize() {
|
||||
if (!initialized) {
|
||||
HMODULE handle = ::GetModuleHandle("Kernel32.dll");
|
||||
assert(handle != NULL, "Just check");
|
||||
|
||||
_SwitchToThread = (SwitchToThread_Fn)::GetProcAddress(handle, "SwitchToThread");
|
||||
_CreateToolhelp32Snapshot = (CreateToolhelp32Snapshot_Fn)
|
||||
::GetProcAddress(handle, "CreateToolhelp32Snapshot");
|
||||
_Module32First = (Module32First_Fn)::GetProcAddress(handle, "Module32First");
|
||||
_Module32Next = (Module32Next_Fn)::GetProcAddress(handle, "Module32Next");
|
||||
_GetNativeSystemInfo = (GetNativeSystemInfo_Fn)::GetProcAddress(handle, "GetNativeSystemInfo");
|
||||
initializeCommon(); // resolve the functions that always need resolving
|
||||
|
||||
initialized = TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
BOOL os::Kernel32Dll::SwitchToThread() {
|
||||
assert(initialized && _SwitchToThread != NULL,
|
||||
"SwitchToThreadAvailable() not yet called");
|
||||
return _SwitchToThread();
|
||||
}
|
||||
|
||||
|
||||
BOOL os::Kernel32Dll::SwitchToThreadAvailable() {
|
||||
if (!initialized) {
|
||||
initialize();
|
||||
}
|
||||
return _SwitchToThread != NULL;
|
||||
}
|
||||
|
||||
// Help tools
|
||||
BOOL os::Kernel32Dll::HelpToolsAvailable() {
|
||||
if (!initialized) {
|
||||
initialize();
|
||||
}
|
||||
return _CreateToolhelp32Snapshot != NULL &&
|
||||
_Module32First != NULL &&
|
||||
_Module32Next != NULL;
|
||||
}
|
||||
|
||||
HANDLE os::Kernel32Dll::CreateToolhelp32Snapshot(DWORD dwFlags,
|
||||
DWORD th32ProcessId) {
|
||||
assert(initialized && _CreateToolhelp32Snapshot != NULL,
|
||||
"HelpToolsAvailable() not yet called");
|
||||
|
||||
return _CreateToolhelp32Snapshot(dwFlags, th32ProcessId);
|
||||
}
|
||||
|
||||
BOOL os::Kernel32Dll::Module32First(HANDLE hSnapshot,LPMODULEENTRY32 lpme) {
|
||||
assert(initialized && _Module32First != NULL,
|
||||
"HelpToolsAvailable() not yet called");
|
||||
|
||||
return _Module32First(hSnapshot, lpme);
|
||||
}
|
||||
|
||||
inline BOOL os::Kernel32Dll::Module32Next(HANDLE hSnapshot,
|
||||
LPMODULEENTRY32 lpme) {
|
||||
assert(initialized && _Module32Next != NULL,
|
||||
"HelpToolsAvailable() not yet called");
|
||||
|
||||
return _Module32Next(hSnapshot, lpme);
|
||||
}
|
||||
|
||||
|
||||
BOOL os::Kernel32Dll::GetNativeSystemInfoAvailable() {
|
||||
if (!initialized) {
|
||||
initialize();
|
||||
}
|
||||
return _GetNativeSystemInfo != NULL;
|
||||
}
|
||||
|
||||
void os::Kernel32Dll::GetNativeSystemInfo(LPSYSTEM_INFO lpSystemInfo) {
|
||||
assert(initialized && _GetNativeSystemInfo != NULL,
|
||||
"GetNativeSystemInfoAvailable() not yet called");
|
||||
|
||||
_GetNativeSystemInfo(lpSystemInfo);
|
||||
}
|
||||
|
||||
// PSAPI API
|
||||
|
||||
|
||||
typedef BOOL (WINAPI *EnumProcessModules_Fn)(HANDLE, HMODULE *, DWORD, LPDWORD);
|
||||
typedef BOOL (WINAPI *GetModuleFileNameEx_Fn)(HANDLE, HMODULE, LPTSTR, DWORD);
|
||||
typedef BOOL (WINAPI *GetModuleInformation_Fn)(HANDLE, HMODULE, LPMODULEINFO, DWORD);
|
||||
|
||||
EnumProcessModules_Fn os::PSApiDll::_EnumProcessModules = NULL;
|
||||
GetModuleFileNameEx_Fn os::PSApiDll::_GetModuleFileNameEx = NULL;
|
||||
GetModuleInformation_Fn os::PSApiDll::_GetModuleInformation = NULL;
|
||||
BOOL os::PSApiDll::initialized = FALSE;
|
||||
|
||||
void os::PSApiDll::initialize() {
|
||||
if (!initialized) {
|
||||
HMODULE handle = os::win32::load_Windows_dll("PSAPI.DLL", NULL, 0);
|
||||
if (handle != NULL) {
|
||||
_EnumProcessModules = (EnumProcessModules_Fn)::GetProcAddress(handle,
|
||||
"EnumProcessModules");
|
||||
_GetModuleFileNameEx = (GetModuleFileNameEx_Fn)::GetProcAddress(handle,
|
||||
"GetModuleFileNameExA");
|
||||
_GetModuleInformation = (GetModuleInformation_Fn)::GetProcAddress(handle,
|
||||
"GetModuleInformation");
|
||||
}
|
||||
initialized = TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
BOOL os::PSApiDll::EnumProcessModules(HANDLE hProcess, HMODULE *lpModule,
|
||||
DWORD cb, LPDWORD lpcbNeeded) {
|
||||
assert(initialized && _EnumProcessModules != NULL,
|
||||
"PSApiAvailable() not yet called");
|
||||
return _EnumProcessModules(hProcess, lpModule, cb, lpcbNeeded);
|
||||
}
|
||||
|
||||
DWORD os::PSApiDll::GetModuleFileNameEx(HANDLE hProcess, HMODULE hModule,
|
||||
LPTSTR lpFilename, DWORD nSize) {
|
||||
assert(initialized && _GetModuleFileNameEx != NULL,
|
||||
"PSApiAvailable() not yet called");
|
||||
return _GetModuleFileNameEx(hProcess, hModule, lpFilename, nSize);
|
||||
}
|
||||
|
||||
BOOL os::PSApiDll::GetModuleInformation(HANDLE hProcess, HMODULE hModule,
|
||||
LPMODULEINFO lpmodinfo, DWORD cb) {
|
||||
assert(initialized && _GetModuleInformation != NULL,
|
||||
"PSApiAvailable() not yet called");
|
||||
return _GetModuleInformation(hProcess, hModule, lpmodinfo, cb);
|
||||
}
|
||||
|
||||
BOOL os::PSApiDll::PSApiAvailable() {
|
||||
if (!initialized) {
|
||||
initialize();
|
||||
}
|
||||
return _EnumProcessModules != NULL &&
|
||||
_GetModuleFileNameEx != NULL &&
|
||||
_GetModuleInformation != NULL;
|
||||
}
|
||||
|
||||
|
||||
// WinSock2 API
|
||||
typedef int (PASCAL FAR* WSAStartup_Fn)(WORD, LPWSADATA);
|
||||
typedef struct hostent *(PASCAL FAR *gethostbyname_Fn)(...);
|
||||
|
||||
WSAStartup_Fn os::WinSock2Dll::_WSAStartup = NULL;
|
||||
gethostbyname_Fn os::WinSock2Dll::_gethostbyname = NULL;
|
||||
BOOL os::WinSock2Dll::initialized = FALSE;
|
||||
|
||||
void os::WinSock2Dll::initialize() {
|
||||
if (!initialized) {
|
||||
HMODULE handle = os::win32::load_Windows_dll("ws2_32.dll", NULL, 0);
|
||||
if (handle != NULL) {
|
||||
_WSAStartup = (WSAStartup_Fn)::GetProcAddress(handle, "WSAStartup");
|
||||
_gethostbyname = (gethostbyname_Fn)::GetProcAddress(handle, "gethostbyname");
|
||||
}
|
||||
initialized = TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
BOOL os::WinSock2Dll::WSAStartup(WORD wVersionRequested, LPWSADATA lpWSAData) {
|
||||
assert(initialized && _WSAStartup != NULL,
|
||||
"WinSock2Available() not yet called");
|
||||
return _WSAStartup(wVersionRequested, lpWSAData);
|
||||
}
|
||||
|
||||
struct hostent* os::WinSock2Dll::gethostbyname(const char *name) {
|
||||
assert(initialized && _gethostbyname != NULL,
|
||||
"WinSock2Available() not yet called");
|
||||
return _gethostbyname(name);
|
||||
}
|
||||
|
||||
BOOL os::WinSock2Dll::WinSock2Available() {
|
||||
if (!initialized) {
|
||||
initialize();
|
||||
}
|
||||
return _WSAStartup != NULL &&
|
||||
_gethostbyname != NULL;
|
||||
}
|
||||
|
||||
typedef BOOL (WINAPI *AdjustTokenPrivileges_Fn)(HANDLE, BOOL, PTOKEN_PRIVILEGES, DWORD, PTOKEN_PRIVILEGES, PDWORD);
|
||||
typedef BOOL (WINAPI *OpenProcessToken_Fn)(HANDLE, DWORD, PHANDLE);
|
||||
typedef BOOL (WINAPI *LookupPrivilegeValue_Fn)(LPCTSTR, LPCTSTR, PLUID);
|
||||
|
||||
AdjustTokenPrivileges_Fn os::Advapi32Dll::_AdjustTokenPrivileges = NULL;
|
||||
OpenProcessToken_Fn os::Advapi32Dll::_OpenProcessToken = NULL;
|
||||
LookupPrivilegeValue_Fn os::Advapi32Dll::_LookupPrivilegeValue = NULL;
|
||||
BOOL os::Advapi32Dll::initialized = FALSE;
|
||||
|
||||
void os::Advapi32Dll::initialize() {
|
||||
if (!initialized) {
|
||||
HMODULE handle = os::win32::load_Windows_dll("advapi32.dll", NULL, 0);
|
||||
if (handle != NULL) {
|
||||
_AdjustTokenPrivileges = (AdjustTokenPrivileges_Fn)::GetProcAddress(handle,
|
||||
"AdjustTokenPrivileges");
|
||||
_OpenProcessToken = (OpenProcessToken_Fn)::GetProcAddress(handle,
|
||||
"OpenProcessToken");
|
||||
_LookupPrivilegeValue = (LookupPrivilegeValue_Fn)::GetProcAddress(handle,
|
||||
"LookupPrivilegeValueA");
|
||||
}
|
||||
initialized = TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
BOOL os::Advapi32Dll::AdjustTokenPrivileges(HANDLE TokenHandle,
|
||||
BOOL DisableAllPrivileges,
|
||||
PTOKEN_PRIVILEGES NewState,
|
||||
DWORD BufferLength,
|
||||
PTOKEN_PRIVILEGES PreviousState,
|
||||
PDWORD ReturnLength) {
|
||||
assert(initialized && _AdjustTokenPrivileges != NULL,
|
||||
"AdvapiAvailable() not yet called");
|
||||
return _AdjustTokenPrivileges(TokenHandle, DisableAllPrivileges, NewState,
|
||||
BufferLength, PreviousState, ReturnLength);
|
||||
}
|
||||
|
||||
BOOL os::Advapi32Dll::OpenProcessToken(HANDLE ProcessHandle,
|
||||
DWORD DesiredAccess,
|
||||
PHANDLE TokenHandle) {
|
||||
assert(initialized && _OpenProcessToken != NULL,
|
||||
"AdvapiAvailable() not yet called");
|
||||
return _OpenProcessToken(ProcessHandle, DesiredAccess, TokenHandle);
|
||||
}
|
||||
|
||||
BOOL os::Advapi32Dll::LookupPrivilegeValue(LPCTSTR lpSystemName,
|
||||
LPCTSTR lpName, PLUID lpLuid) {
|
||||
assert(initialized && _LookupPrivilegeValue != NULL,
|
||||
"AdvapiAvailable() not yet called");
|
||||
return _LookupPrivilegeValue(lpSystemName, lpName, lpLuid);
|
||||
}
|
||||
|
||||
BOOL os::Advapi32Dll::AdvapiAvailable() {
|
||||
if (!initialized) {
|
||||
initialize();
|
||||
}
|
||||
return _AdjustTokenPrivileges != NULL &&
|
||||
_OpenProcessToken != NULL &&
|
||||
_LookupPrivilegeValue != NULL;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#ifndef PRODUCT
|
||||
|
||||
// test the code path in reserve_memory_special() that tries to allocate memory in a single
|
||||
@ -5976,7 +5761,7 @@ BOOL os::Advapi32Dll::AdvapiAvailable() {
|
||||
void TestReserveMemorySpecial_test() {
|
||||
if (!UseLargePages) {
|
||||
if (VerboseInternalVMTests) {
|
||||
gclog_or_tty->print("Skipping test because large pages are disabled");
|
||||
tty->print("Skipping test because large pages are disabled");
|
||||
}
|
||||
return;
|
||||
}
|
||||
@ -5992,7 +5777,7 @@ void TestReserveMemorySpecial_test() {
|
||||
char* result = os::reserve_memory_special(large_allocation_size, os::large_page_size(), NULL, false);
|
||||
if (result == NULL) {
|
||||
if (VerboseInternalVMTests) {
|
||||
gclog_or_tty->print("Failed to allocate control block with size " SIZE_FORMAT ". Skipping remainder of test.",
|
||||
tty->print("Failed to allocate control block with size " SIZE_FORMAT ". Skipping remainder of test.",
|
||||
large_allocation_size);
|
||||
}
|
||||
} else {
|
||||
@ -6005,7 +5790,7 @@ void TestReserveMemorySpecial_test() {
|
||||
char* actual_location = os::reserve_memory_special(expected_allocation_size, os::large_page_size(), expected_location, false);
|
||||
if (actual_location == NULL) {
|
||||
if (VerboseInternalVMTests) {
|
||||
gclog_or_tty->print("Failed to allocate any memory at " PTR_FORMAT " size " SIZE_FORMAT ". Skipping remainder of test.",
|
||||
tty->print("Failed to allocate any memory at " PTR_FORMAT " size " SIZE_FORMAT ". Skipping remainder of test.",
|
||||
expected_location, large_allocation_size);
|
||||
}
|
||||
} else {
|
||||
|
@ -110,6 +110,10 @@ class win32 {
|
||||
// Default stack size for the current process.
|
||||
static size_t default_stack_size() { return _default_stack_size; }
|
||||
|
||||
static bool get_frame_at_stack_banging_point(JavaThread* thread,
|
||||
struct _EXCEPTION_POINTERS* exceptionInfo,
|
||||
address pc, frame* fr);
|
||||
|
||||
#ifndef _WIN64
|
||||
// A wrapper to install a structured exception handler for fast JNI accesors.
|
||||
static address fast_jni_accessor_wrapper(BasicType);
|
||||
@ -183,26 +187,11 @@ class PlatformParker : public CHeapObj<mtInternal> {
|
||||
|
||||
} ;
|
||||
|
||||
// JDK7 requires VS2010
|
||||
#if _MSC_VER < 1600
|
||||
#define JDK6_OR_EARLIER 1
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
class WinSock2Dll: AllStatic {
|
||||
public:
|
||||
static BOOL WSAStartup(WORD, LPWSADATA);
|
||||
static struct hostent* gethostbyname(const char *name);
|
||||
static BOOL WinSock2Available();
|
||||
#ifdef JDK6_OR_EARLIER
|
||||
private:
|
||||
static int (PASCAL FAR* _WSAStartup)(WORD, LPWSADATA);
|
||||
static struct hostent *(PASCAL FAR *_gethostbyname)(...);
|
||||
static BOOL initialized;
|
||||
|
||||
static void initialize();
|
||||
#endif
|
||||
};
|
||||
|
||||
class Kernel32Dll: AllStatic {
|
||||
@ -244,16 +233,6 @@ private:
|
||||
|
||||
static void initialize();
|
||||
static void initializeCommon();
|
||||
|
||||
#ifdef JDK6_OR_EARLIER
|
||||
private:
|
||||
static BOOL (WINAPI *_SwitchToThread)(void);
|
||||
static HANDLE (WINAPI* _CreateToolhelp32Snapshot)(DWORD,DWORD);
|
||||
static BOOL (WINAPI* _Module32First)(HANDLE,LPMODULEENTRY32);
|
||||
static BOOL (WINAPI* _Module32Next)(HANDLE,LPMODULEENTRY32);
|
||||
static void (WINAPI *_GetNativeSystemInfo)(LPSYSTEM_INFO);
|
||||
#endif
|
||||
|
||||
};
|
||||
|
||||
class Advapi32Dll: AllStatic {
|
||||
@ -263,16 +242,6 @@ public:
|
||||
static BOOL LookupPrivilegeValue(LPCTSTR, LPCTSTR, PLUID);
|
||||
|
||||
static BOOL AdvapiAvailable();
|
||||
|
||||
#ifdef JDK6_OR_EARLIER
|
||||
private:
|
||||
static BOOL (WINAPI *_AdjustTokenPrivileges)(HANDLE, BOOL, PTOKEN_PRIVILEGES, DWORD, PTOKEN_PRIVILEGES, PDWORD);
|
||||
static BOOL (WINAPI *_OpenProcessToken)(HANDLE, DWORD, PHANDLE);
|
||||
static BOOL (WINAPI *_LookupPrivilegeValue)(LPCTSTR, LPCTSTR, PLUID);
|
||||
static BOOL initialized;
|
||||
|
||||
static void initialize();
|
||||
#endif
|
||||
};
|
||||
|
||||
class PSApiDll: AllStatic {
|
||||
@ -282,16 +251,6 @@ public:
|
||||
static BOOL GetModuleInformation(HANDLE, HMODULE, LPMODULEINFO, DWORD);
|
||||
|
||||
static BOOL PSApiAvailable();
|
||||
|
||||
#ifdef JDK6_OR_EARLIER
|
||||
private:
|
||||
static BOOL (WINAPI *_EnumProcessModules)(HANDLE, HMODULE *, DWORD, LPDWORD);
|
||||
static BOOL (WINAPI *_GetModuleFileNameEx)(HANDLE, HMODULE, LPTSTR, DWORD);;
|
||||
static BOOL (WINAPI *_GetModuleInformation)(HANDLE, HMODULE, LPMODULEINFO, DWORD);
|
||||
static BOOL initialized;
|
||||
|
||||
static void initialize();
|
||||
#endif
|
||||
};
|
||||
|
||||
#endif // OS_WINDOWS_VM_OS_WINDOWS_HPP
|
||||
|
162
hotspot/src/os/windows/vm/sharedRuntimeRem.cpp
Normal file
162
hotspot/src/os/windows/vm/sharedRuntimeRem.cpp
Normal file
@ -0,0 +1,162 @@
|
||||
/*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "precompiled.hpp"
|
||||
|
||||
#ifdef _WIN64
|
||||
// These are copied defines from fdlibm.h, this allows us to keep the code
|
||||
// the same as in the JDK, for easier maintenance.
|
||||
|
||||
#define __HI(x) *(1+(int*)&x)
|
||||
#define __LO(x) *(int*)&x
|
||||
|
||||
// This code is a copy of __ieee754_fmod() from the JDK's libfdlibm and is
|
||||
// used as a workaround for issues with the Windows x64 CRT implementation
|
||||
// of fmod. Microsoft has acknowledged that this is an issue in Visual Studio
|
||||
// 2012 and forward, but has not provided a time frame for a fix other than that
|
||||
// it'll not be fixed in Visual Studio 2013 or 2015.
|
||||
|
||||
static const double one = 1.0, Zero[] = { 0.0, -0.0, };
|
||||
|
||||
double SharedRuntime::fmod_winx64(double x, double y)
|
||||
{
|
||||
int n, hx, hy, hz, ix, iy, sx, i;
|
||||
unsigned lx, ly, lz;
|
||||
|
||||
hx = __HI(x); /* high word of x */
|
||||
lx = __LO(x); /* low word of x */
|
||||
hy = __HI(y); /* high word of y */
|
||||
ly = __LO(y); /* low word of y */
|
||||
sx = hx & 0x80000000; /* sign of x */
|
||||
hx ^= sx; /* |x| */
|
||||
hy &= 0x7fffffff; /* |y| */
|
||||
|
||||
#pragma warning( disable : 4146 )
|
||||
/* purge off exception values */
|
||||
if ((hy | ly) == 0 || (hx >= 0x7ff00000) || /* y=0,or x not finite */
|
||||
((hy | ((ly | -ly) >> 31))>0x7ff00000)) /* or y is NaN */
|
||||
#pragma warning( default : 4146 )
|
||||
return (x*y) / (x*y);
|
||||
if (hx <= hy) {
|
||||
if ((hx<hy) || (lx<ly)) return x; /* |x|<|y| return x */
|
||||
if (lx == ly)
|
||||
return Zero[(unsigned)sx >> 31]; /* |x|=|y| return x*0*/
|
||||
}
|
||||
|
||||
/* determine ix = ilogb(x) */
|
||||
if (hx<0x00100000) { /* subnormal x */
|
||||
if (hx == 0) {
|
||||
for (ix = -1043, i = lx; i>0; i <<= 1) ix -= 1;
|
||||
}
|
||||
else {
|
||||
for (ix = -1022, i = (hx << 11); i>0; i <<= 1) ix -= 1;
|
||||
}
|
||||
}
|
||||
else ix = (hx >> 20) - 1023;
|
||||
|
||||
/* determine iy = ilogb(y) */
|
||||
if (hy<0x00100000) { /* subnormal y */
|
||||
if (hy == 0) {
|
||||
for (iy = -1043, i = ly; i>0; i <<= 1) iy -= 1;
|
||||
}
|
||||
else {
|
||||
for (iy = -1022, i = (hy << 11); i>0; i <<= 1) iy -= 1;
|
||||
}
|
||||
}
|
||||
else iy = (hy >> 20) - 1023;
|
||||
|
||||
/* set up {hx,lx}, {hy,ly} and align y to x */
|
||||
if (ix >= -1022)
|
||||
hx = 0x00100000 | (0x000fffff & hx);
|
||||
else { /* subnormal x, shift x to normal */
|
||||
n = -1022 - ix;
|
||||
if (n <= 31) {
|
||||
hx = (hx << n) | (lx >> (32 - n));
|
||||
lx <<= n;
|
||||
}
|
||||
else {
|
||||
hx = lx << (n - 32);
|
||||
lx = 0;
|
||||
}
|
||||
}
|
||||
if (iy >= -1022)
|
||||
hy = 0x00100000 | (0x000fffff & hy);
|
||||
else { /* subnormal y, shift y to normal */
|
||||
n = -1022 - iy;
|
||||
if (n <= 31) {
|
||||
hy = (hy << n) | (ly >> (32 - n));
|
||||
ly <<= n;
|
||||
}
|
||||
else {
|
||||
hy = ly << (n - 32);
|
||||
ly = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* fix point fmod */
|
||||
n = ix - iy;
|
||||
while (n--) {
|
||||
hz = hx - hy; lz = lx - ly; if (lx<ly) hz -= 1;
|
||||
if (hz<0){ hx = hx + hx + (lx >> 31); lx = lx + lx; }
|
||||
else {
|
||||
if ((hz | lz) == 0) /* return sign(x)*0 */
|
||||
return Zero[(unsigned)sx >> 31];
|
||||
hx = hz + hz + (lz >> 31); lx = lz + lz;
|
||||
}
|
||||
}
|
||||
hz = hx - hy; lz = lx - ly; if (lx<ly) hz -= 1;
|
||||
if (hz >= 0) { hx = hz; lx = lz; }
|
||||
|
||||
/* convert back to floating value and restore the sign */
|
||||
if ((hx | lx) == 0) /* return sign(x)*0 */
|
||||
return Zero[(unsigned)sx >> 31];
|
||||
while (hx<0x00100000) { /* normalize x */
|
||||
hx = hx + hx + (lx >> 31); lx = lx + lx;
|
||||
iy -= 1;
|
||||
}
|
||||
if (iy >= -1022) { /* normalize output */
|
||||
hx = ((hx - 0x00100000) | ((iy + 1023) << 20));
|
||||
__HI(x) = hx | sx;
|
||||
__LO(x) = lx;
|
||||
}
|
||||
else { /* subnormal output */
|
||||
n = -1022 - iy;
|
||||
if (n <= 20) {
|
||||
lx = (lx >> n) | ((unsigned)hx << (32 - n));
|
||||
hx >>= n;
|
||||
}
|
||||
else if (n <= 31) {
|
||||
lx = (hx << (32 - n)) | (lx >> n); hx = sx;
|
||||
}
|
||||
else {
|
||||
lx = hx >> (n - 32); hx = sx;
|
||||
}
|
||||
__HI(x) = hx | sx;
|
||||
__LO(x) = lx;
|
||||
x *= one; /* create necessary signal */
|
||||
}
|
||||
return x; /* exact output */
|
||||
}
|
||||
|
||||
#endif
|
@ -291,6 +291,71 @@ inline void* Atomic::xchg_ptr(void* exchange_value, volatile void* dest) {
|
||||
return (void*)xchg_ptr((intptr_t)exchange_value, (volatile intptr_t*)dest);
|
||||
}
|
||||
|
||||
#define VM_HAS_SPECIALIZED_CMPXCHG_BYTE
|
||||
inline jbyte Atomic::cmpxchg(jbyte exchange_value, volatile jbyte* dest, jbyte compare_value) {
|
||||
|
||||
// Note that cmpxchg guarantees a two-way memory barrier across
|
||||
// the cmpxchg, so it's really a a 'fence_cmpxchg_acquire'
|
||||
// (see atomic.hpp).
|
||||
|
||||
// Using 32 bit internally.
|
||||
volatile int *dest_base = (volatile int*)((uintptr_t)dest & ~3);
|
||||
|
||||
#ifdef VM_LITTLE_ENDIAN
|
||||
const unsigned int shift_amount = ((uintptr_t)dest & 3) * 8;
|
||||
#else
|
||||
const unsigned int shift_amount = ((~(uintptr_t)dest) & 3) * 8;
|
||||
#endif
|
||||
const unsigned int masked_compare_val = ((unsigned int)(unsigned char)compare_value),
|
||||
masked_exchange_val = ((unsigned int)(unsigned char)exchange_value),
|
||||
xor_value = (masked_compare_val ^ masked_exchange_val) << shift_amount;
|
||||
|
||||
unsigned int old_value, value32;
|
||||
|
||||
__asm__ __volatile__ (
|
||||
/* fence */
|
||||
strasm_sync
|
||||
/* simple guard */
|
||||
" lbz %[old_value], 0(%[dest]) \n"
|
||||
" cmpw %[masked_compare_val], %[old_value] \n"
|
||||
" bne- 2f \n"
|
||||
/* atomic loop */
|
||||
"1: \n"
|
||||
" lwarx %[value32], 0, %[dest_base] \n"
|
||||
/* extract byte and compare */
|
||||
" srd %[old_value], %[value32], %[shift_amount] \n"
|
||||
" clrldi %[old_value], %[old_value], 56 \n"
|
||||
" cmpw %[masked_compare_val], %[old_value] \n"
|
||||
" bne- 2f \n"
|
||||
/* replace byte and try to store */
|
||||
" xor %[value32], %[xor_value], %[value32] \n"
|
||||
" stwcx. %[value32], 0, %[dest_base] \n"
|
||||
" bne- 1b \n"
|
||||
/* acquire */
|
||||
strasm_sync
|
||||
/* exit */
|
||||
"2: \n"
|
||||
/* out */
|
||||
: [old_value] "=&r" (old_value),
|
||||
[value32] "=&r" (value32),
|
||||
"=m" (*dest),
|
||||
"=m" (*dest_base)
|
||||
/* in */
|
||||
: [dest] "b" (dest),
|
||||
[dest_base] "b" (dest_base),
|
||||
[shift_amount] "r" (shift_amount),
|
||||
[masked_compare_val] "r" (masked_compare_val),
|
||||
[xor_value] "r" (xor_value),
|
||||
"m" (*dest),
|
||||
"m" (*dest_base)
|
||||
/* clobber */
|
||||
: "cc",
|
||||
"memory"
|
||||
);
|
||||
|
||||
return (jbyte)(unsigned char)old_value;
|
||||
}
|
||||
|
||||
inline jint Atomic::cmpxchg(jint exchange_value, volatile jint* dest, jint compare_value) {
|
||||
|
||||
// Note that cmpxchg guarantees a two-way memory barrier across
|
||||
|
@ -98,12 +98,12 @@ address os::Aix::ucontext_get_pc(const ucontext_t * uc) {
|
||||
return (address)uc->uc_mcontext.jmp_context.iar;
|
||||
}
|
||||
|
||||
intptr_t* os::Aix::ucontext_get_sp(ucontext_t * uc) {
|
||||
intptr_t* os::Aix::ucontext_get_sp(const ucontext_t * uc) {
|
||||
// gpr1 holds the stack pointer on aix
|
||||
return (intptr_t*)uc->uc_mcontext.jmp_context.gpr[1/*REG_SP*/];
|
||||
}
|
||||
|
||||
intptr_t* os::Aix::ucontext_get_fp(ucontext_t * uc) {
|
||||
intptr_t* os::Aix::ucontext_get_fp(const ucontext_t * uc) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@ -111,11 +111,11 @@ void os::Aix::ucontext_set_pc(ucontext_t* uc, address new_pc) {
|
||||
uc->uc_mcontext.jmp_context.iar = (uint64_t) new_pc;
|
||||
}
|
||||
|
||||
ExtendedPC os::fetch_frame_from_context(void* ucVoid,
|
||||
ExtendedPC os::fetch_frame_from_context(const void* ucVoid,
|
||||
intptr_t** ret_sp, intptr_t** ret_fp) {
|
||||
|
||||
ExtendedPC epc;
|
||||
ucontext_t* uc = (ucontext_t*)ucVoid;
|
||||
const ucontext_t* uc = (const ucontext_t*)ucVoid;
|
||||
|
||||
if (uc != NULL) {
|
||||
epc = ExtendedPC(os::Aix::ucontext_get_pc(uc));
|
||||
@ -131,7 +131,7 @@ ExtendedPC os::fetch_frame_from_context(void* ucVoid,
|
||||
return epc;
|
||||
}
|
||||
|
||||
frame os::fetch_frame_from_context(void* ucVoid) {
|
||||
frame os::fetch_frame_from_context(const void* ucVoid) {
|
||||
intptr_t* sp;
|
||||
intptr_t* fp;
|
||||
ExtendedPC epc = fetch_frame_from_context(ucVoid, &sp, &fp);
|
||||
@ -507,10 +507,10 @@ size_t os::Aix::default_guard_size(os::ThreadType thr_type) {
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// helper functions for fatal error handler
|
||||
|
||||
void os::print_context(outputStream *st, void *context) {
|
||||
void os::print_context(outputStream *st, const void *context) {
|
||||
if (context == NULL) return;
|
||||
|
||||
ucontext_t* uc = (ucontext_t*)context;
|
||||
const ucontext_t* uc = (const ucontext_t*)context;
|
||||
|
||||
st->print_cr("Registers:");
|
||||
st->print("pc =" INTPTR_FORMAT " ", uc->uc_mcontext.jmp_context.iar);
|
||||
@ -544,9 +544,23 @@ void os::print_context(outputStream *st, void *context) {
|
||||
st->cr();
|
||||
}
|
||||
|
||||
void os::print_register_info(outputStream *st, void *context) {
|
||||
void os::print_register_info(outputStream *st, const void *context) {
|
||||
if (context == NULL) return;
|
||||
st->print("Not ported - print_register_info\n");
|
||||
|
||||
ucontext_t *uc = (ucontext_t*)context;
|
||||
|
||||
st->print_cr("Register to memory mapping:");
|
||||
st->cr();
|
||||
|
||||
st->print("pc ="); print_location(st, (intptr_t)uc->uc_mcontext.jmp_context.iar);
|
||||
st->print("lr ="); print_location(st, (intptr_t)uc->uc_mcontext.jmp_context.lr);
|
||||
st->print("sp ="); print_location(st, (intptr_t)os::Aix::ucontext_get_sp(uc));
|
||||
for (int i = 0; i < 32; i++) {
|
||||
st->print("r%-2d=", i);
|
||||
print_location(st, (intptr_t)uc->uc_mcontext.jmp_context.gpr[i]);
|
||||
}
|
||||
|
||||
st->cr();
|
||||
}
|
||||
|
||||
extern "C" {
|
||||
@ -565,3 +579,4 @@ int os::extra_bang_size_in_bytes() {
|
||||
// PPC does not require the additional stack bang.
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -304,7 +304,7 @@ void os::initialize_thread(Thread* thr) {
|
||||
// Nothing to do.
|
||||
}
|
||||
|
||||
address os::Bsd::ucontext_get_pc(ucontext_t * uc) {
|
||||
address os::Bsd::ucontext_get_pc(const ucontext_t * uc) {
|
||||
return (address)uc->context_pc;
|
||||
}
|
||||
|
||||
@ -312,11 +312,11 @@ 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) {
|
||||
intptr_t* os::Bsd::ucontext_get_sp(const ucontext_t * uc) {
|
||||
return (intptr_t*)uc->context_sp;
|
||||
}
|
||||
|
||||
intptr_t* os::Bsd::ucontext_get_fp(ucontext_t * uc) {
|
||||
intptr_t* os::Bsd::ucontext_get_fp(const ucontext_t * uc) {
|
||||
return (intptr_t*)uc->context_fp;
|
||||
}
|
||||
|
||||
@ -325,8 +325,9 @@ intptr_t* os::Bsd::ucontext_get_fp(ucontext_t * uc) {
|
||||
// os::Solaris::fetch_frame_from_ucontext() tries to skip nested signal
|
||||
// frames. Currently we don't do that on Bsd, so it's the same as
|
||||
// os::fetch_frame_from_context().
|
||||
// This method is also used for stack overflow signal handling.
|
||||
ExtendedPC os::Bsd::fetch_frame_from_ucontext(Thread* thread,
|
||||
ucontext_t* uc, intptr_t** ret_sp, intptr_t** ret_fp) {
|
||||
const ucontext_t* uc, intptr_t** ret_sp, intptr_t** ret_fp) {
|
||||
|
||||
assert(thread != NULL, "just checking");
|
||||
assert(ret_sp != NULL, "just checking");
|
||||
@ -335,11 +336,11 @@ ExtendedPC os::Bsd::fetch_frame_from_ucontext(Thread* thread,
|
||||
return os::fetch_frame_from_context(uc, ret_sp, ret_fp);
|
||||
}
|
||||
|
||||
ExtendedPC os::fetch_frame_from_context(void* ucVoid,
|
||||
ExtendedPC os::fetch_frame_from_context(const void* ucVoid,
|
||||
intptr_t** ret_sp, intptr_t** ret_fp) {
|
||||
|
||||
ExtendedPC epc;
|
||||
ucontext_t* uc = (ucontext_t*)ucVoid;
|
||||
const ucontext_t* uc = (const ucontext_t*)ucVoid;
|
||||
|
||||
if (uc != NULL) {
|
||||
epc = ExtendedPC(os::Bsd::ucontext_get_pc(uc));
|
||||
@ -355,13 +356,55 @@ ExtendedPC os::fetch_frame_from_context(void* ucVoid,
|
||||
return epc;
|
||||
}
|
||||
|
||||
frame os::fetch_frame_from_context(void* ucVoid) {
|
||||
frame os::fetch_frame_from_context(const void* ucVoid) {
|
||||
intptr_t* sp;
|
||||
intptr_t* fp;
|
||||
ExtendedPC epc = fetch_frame_from_context(ucVoid, &sp, &fp);
|
||||
return frame(sp, fp, epc.pc());
|
||||
}
|
||||
|
||||
frame os::fetch_frame_from_ucontext(Thread* thread, void* ucVoid) {
|
||||
intptr_t* sp;
|
||||
intptr_t* fp;
|
||||
ExtendedPC epc = os::Bsd::fetch_frame_from_ucontext(thread, (ucontext_t*)ucVoid, &sp, &fp);
|
||||
return frame(sp, fp, epc.pc());
|
||||
}
|
||||
|
||||
bool os::Bsd::get_frame_at_stack_banging_point(JavaThread* thread, ucontext_t* uc, frame* fr) {
|
||||
address pc = (address) os::Bsd::ucontext_get_pc(uc);
|
||||
if (Interpreter::contains(pc)) {
|
||||
// interpreter performs stack banging after the fixed frame header has
|
||||
// been generated while the compilers perform it before. To maintain
|
||||
// semantic consistency between interpreted and compiled frames, the
|
||||
// method returns the Java sender of the current frame.
|
||||
*fr = os::fetch_frame_from_ucontext(thread, uc);
|
||||
if (!fr->is_first_java_frame()) {
|
||||
assert(fr->safe_for_sender(thread), "Safety check");
|
||||
*fr = fr->java_sender();
|
||||
}
|
||||
} else {
|
||||
// more complex code with compiled code
|
||||
assert(!Interpreter::contains(pc), "Interpreted methods should have been handled above");
|
||||
CodeBlob* cb = CodeCache::find_blob(pc);
|
||||
if (cb == NULL || !cb->is_nmethod() || cb->is_frame_complete_at(pc)) {
|
||||
// Not sure where the pc points to, fallback to default
|
||||
// stack overflow handling
|
||||
return false;
|
||||
} else {
|
||||
*fr = os::fetch_frame_from_ucontext(thread, uc);
|
||||
// in compiled code, the stack banging is performed just after the return pc
|
||||
// has been pushed on the stack
|
||||
*fr = frame(fr->sp() + 1, fr->fp(), (address)*(fr->sp()));
|
||||
if (!fr->is_java_frame()) {
|
||||
assert(fr->safe_for_sender(thread), "Safety check");
|
||||
*fr = fr->java_sender();
|
||||
}
|
||||
}
|
||||
}
|
||||
assert(fr->is_java_frame(), "Safety check");
|
||||
return true;
|
||||
}
|
||||
|
||||
// By default, gcc always save frame pointer (%ebp/%rbp) on stack. It may get
|
||||
// turned off by -fomit-frame-pointer,
|
||||
frame os::get_sender_for_C_frame(frame* fr) {
|
||||
@ -479,13 +522,31 @@ JVM_handle_bsd_signal(int sig,
|
||||
addr >= thread->stack_base() - thread->stack_size()) {
|
||||
// stack overflow
|
||||
if (thread->in_stack_yellow_zone(addr)) {
|
||||
thread->disable_stack_yellow_zone();
|
||||
if (thread->thread_state() == _thread_in_Java) {
|
||||
if (thread->in_stack_reserved_zone(addr)) {
|
||||
frame fr;
|
||||
if (os::Bsd::get_frame_at_stack_banging_point(thread, uc, &fr)) {
|
||||
assert(fr.is_java_frame(), "Must be a Java frame");
|
||||
frame activation = SharedRuntime::look_for_reserved_stack_annotated_method(thread, fr);
|
||||
if (activation.sp() != NULL) {
|
||||
thread->disable_stack_reserved_zone();
|
||||
if (activation.is_interpreted_frame()) {
|
||||
thread->set_reserved_stack_activation((address)(
|
||||
activation.fp() + frame::interpreter_frame_initial_sp_offset));
|
||||
} else {
|
||||
thread->set_reserved_stack_activation((address)activation.unextended_sp());
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
// Throw a stack overflow exception. Guard pages will be reenabled
|
||||
// while unwinding the stack.
|
||||
thread->disable_stack_yellow_zone();
|
||||
stub = SharedRuntime::continuation_for_implicit_exception(thread, pc, SharedRuntime::STACK_OVERFLOW);
|
||||
} else {
|
||||
// Thread was in the vm or native code. Return and try to finish.
|
||||
thread->disable_stack_yellow_zone();
|
||||
return 1;
|
||||
}
|
||||
} else if (thread->in_stack_red_zone(addr)) {
|
||||
@ -910,10 +971,10 @@ size_t os::current_stack_size() {
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// helper functions for fatal error handler
|
||||
|
||||
void os::print_context(outputStream *st, void *context) {
|
||||
void os::print_context(outputStream *st, const void *context) {
|
||||
if (context == NULL) return;
|
||||
|
||||
ucontext_t *uc = (ucontext_t*)context;
|
||||
const ucontext_t *uc = (const ucontext_t*)context;
|
||||
st->print_cr("Registers:");
|
||||
#ifdef AMD64
|
||||
st->print( "RAX=" INTPTR_FORMAT, uc->context_rax);
|
||||
@ -971,10 +1032,10 @@ void os::print_context(outputStream *st, void *context) {
|
||||
print_hex_dump(st, pc - 32, pc + 32, sizeof(char));
|
||||
}
|
||||
|
||||
void os::print_register_info(outputStream *st, void *context) {
|
||||
void os::print_register_info(outputStream *st, const void *context) {
|
||||
if (context == NULL) return;
|
||||
|
||||
ucontext_t *uc = (ucontext_t*)context;
|
||||
const ucontext_t *uc = (const ucontext_t*)context;
|
||||
|
||||
st->print_cr("Register to memory mapping:");
|
||||
st->cr();
|
||||
|
@ -106,7 +106,7 @@ void os::initialize_thread(Thread* thr) {
|
||||
// Nothing to do.
|
||||
}
|
||||
|
||||
address os::Bsd::ucontext_get_pc(ucontext_t* uc) {
|
||||
address os::Bsd::ucontext_get_pc(const ucontext_t* uc) {
|
||||
ShouldNotCallThis();
|
||||
return NULL;
|
||||
}
|
||||
@ -115,14 +115,14 @@ void os::Bsd::ucontext_set_pc(ucontext_t * uc, address pc) {
|
||||
ShouldNotCallThis();
|
||||
}
|
||||
|
||||
ExtendedPC os::fetch_frame_from_context(void* ucVoid,
|
||||
ExtendedPC os::fetch_frame_from_context(const void* ucVoid,
|
||||
intptr_t** ret_sp,
|
||||
intptr_t** ret_fp) {
|
||||
ShouldNotCallThis();
|
||||
return ExtendedPC();
|
||||
}
|
||||
|
||||
frame os::fetch_frame_from_context(void* ucVoid) {
|
||||
frame os::fetch_frame_from_context(const void* ucVoid) {
|
||||
ShouldNotCallThis();
|
||||
return frame();
|
||||
}
|
||||
@ -374,11 +374,11 @@ size_t os::current_stack_size() {
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// helper functions for fatal error handler
|
||||
|
||||
void os::print_context(outputStream* st, void* context) {
|
||||
void os::print_context(outputStream* st, const void* context) {
|
||||
ShouldNotCallThis();
|
||||
}
|
||||
|
||||
void os::print_register_info(outputStream *st, void *context) {
|
||||
void os::print_register_info(outputStream *st, const void *context) {
|
||||
ShouldNotCallThis();
|
||||
}
|
||||
|
||||
|
@ -109,7 +109,7 @@ char* os::non_memory_address_word() {
|
||||
void os::initialize_thread(Thread *thr) {
|
||||
}
|
||||
|
||||
address os::Linux::ucontext_get_pc(ucontext_t * uc) {
|
||||
address os::Linux::ucontext_get_pc(const ucontext_t * uc) {
|
||||
#ifdef BUILTIN_SIM
|
||||
return (address)uc->uc_mcontext.gregs[REG_PC];
|
||||
#else
|
||||
@ -125,7 +125,7 @@ void os::Linux::ucontext_set_pc(ucontext_t * uc, address pc) {
|
||||
#endif
|
||||
}
|
||||
|
||||
intptr_t* os::Linux::ucontext_get_sp(ucontext_t * uc) {
|
||||
intptr_t* os::Linux::ucontext_get_sp(const ucontext_t * uc) {
|
||||
#ifdef BUILTIN_SIM
|
||||
return (intptr_t*)uc->uc_mcontext.gregs[REG_SP];
|
||||
#else
|
||||
@ -133,7 +133,7 @@ intptr_t* os::Linux::ucontext_get_sp(ucontext_t * uc) {
|
||||
#endif
|
||||
}
|
||||
|
||||
intptr_t* os::Linux::ucontext_get_fp(ucontext_t * uc) {
|
||||
intptr_t* os::Linux::ucontext_get_fp(const ucontext_t * uc) {
|
||||
#ifdef BUILTIN_SIM
|
||||
return (intptr_t*)uc->uc_mcontext.gregs[REG_FP];
|
||||
#else
|
||||
@ -147,7 +147,7 @@ intptr_t* os::Linux::ucontext_get_fp(ucontext_t * uc) {
|
||||
// frames. Currently we don't do that on Linux, so it's the same as
|
||||
// os::fetch_frame_from_context().
|
||||
ExtendedPC os::Linux::fetch_frame_from_ucontext(Thread* thread,
|
||||
ucontext_t* uc, intptr_t** ret_sp, intptr_t** ret_fp) {
|
||||
const ucontext_t* uc, intptr_t** ret_sp, intptr_t** ret_fp) {
|
||||
|
||||
assert(thread != NULL, "just checking");
|
||||
assert(ret_sp != NULL, "just checking");
|
||||
@ -156,11 +156,11 @@ ExtendedPC os::Linux::fetch_frame_from_ucontext(Thread* thread,
|
||||
return os::fetch_frame_from_context(uc, ret_sp, ret_fp);
|
||||
}
|
||||
|
||||
ExtendedPC os::fetch_frame_from_context(void* ucVoid,
|
||||
ExtendedPC os::fetch_frame_from_context(const void* ucVoid,
|
||||
intptr_t** ret_sp, intptr_t** ret_fp) {
|
||||
|
||||
ExtendedPC epc;
|
||||
ucontext_t* uc = (ucontext_t*)ucVoid;
|
||||
const ucontext_t* uc = (const ucontext_t*)ucVoid;
|
||||
|
||||
if (uc != NULL) {
|
||||
epc = ExtendedPC(os::Linux::ucontext_get_pc(uc));
|
||||
@ -176,7 +176,7 @@ ExtendedPC os::fetch_frame_from_context(void* ucVoid,
|
||||
return epc;
|
||||
}
|
||||
|
||||
frame os::fetch_frame_from_context(void* ucVoid) {
|
||||
frame os::fetch_frame_from_context(const void* ucVoid) {
|
||||
intptr_t* sp;
|
||||
intptr_t* fp;
|
||||
ExtendedPC epc = fetch_frame_from_context(ucVoid, &sp, &fp);
|
||||
@ -591,10 +591,10 @@ size_t os::current_stack_size() {
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// helper functions for fatal error handler
|
||||
|
||||
void os::print_context(outputStream *st, void *context) {
|
||||
void os::print_context(outputStream *st, const void *context) {
|
||||
if (context == NULL) return;
|
||||
|
||||
ucontext_t *uc = (ucontext_t*)context;
|
||||
const ucontext_t *uc = (const ucontext_t*)context;
|
||||
st->print_cr("Registers:");
|
||||
#ifdef BUILTIN_SIM
|
||||
st->print( "RAX=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_RAX]);
|
||||
@ -643,10 +643,10 @@ void os::print_context(outputStream *st, void *context) {
|
||||
print_hex_dump(st, pc - 32, pc + 32, sizeof(char));
|
||||
}
|
||||
|
||||
void os::print_register_info(outputStream *st, void *context) {
|
||||
void os::print_register_info(outputStream *st, const void *context) {
|
||||
if (context == NULL) return;
|
||||
|
||||
ucontext_t *uc = (ucontext_t*)context;
|
||||
const ucontext_t *uc = (const ucontext_t*)context;
|
||||
|
||||
st->print_cr("Register to memory mapping:");
|
||||
st->cr();
|
||||
|
@ -291,6 +291,71 @@ inline void* Atomic::xchg_ptr(void* exchange_value, volatile void* dest) {
|
||||
return (void*)xchg_ptr((intptr_t)exchange_value, (volatile intptr_t*)dest);
|
||||
}
|
||||
|
||||
#define VM_HAS_SPECIALIZED_CMPXCHG_BYTE
|
||||
inline jbyte Atomic::cmpxchg(jbyte exchange_value, volatile jbyte* dest, jbyte compare_value) {
|
||||
|
||||
// Note that cmpxchg guarantees a two-way memory barrier across
|
||||
// the cmpxchg, so it's really a a 'fence_cmpxchg_acquire'
|
||||
// (see atomic.hpp).
|
||||
|
||||
// Using 32 bit internally.
|
||||
volatile int *dest_base = (volatile int*)((uintptr_t)dest & ~3);
|
||||
|
||||
#ifdef VM_LITTLE_ENDIAN
|
||||
const unsigned int shift_amount = ((uintptr_t)dest & 3) * 8;
|
||||
#else
|
||||
const unsigned int shift_amount = ((~(uintptr_t)dest) & 3) * 8;
|
||||
#endif
|
||||
const unsigned int masked_compare_val = ((unsigned int)(unsigned char)compare_value),
|
||||
masked_exchange_val = ((unsigned int)(unsigned char)exchange_value),
|
||||
xor_value = (masked_compare_val ^ masked_exchange_val) << shift_amount;
|
||||
|
||||
unsigned int old_value, value32;
|
||||
|
||||
__asm__ __volatile__ (
|
||||
/* fence */
|
||||
strasm_sync
|
||||
/* simple guard */
|
||||
" lbz %[old_value], 0(%[dest]) \n"
|
||||
" cmpw %[masked_compare_val], %[old_value] \n"
|
||||
" bne- 2f \n"
|
||||
/* atomic loop */
|
||||
"1: \n"
|
||||
" lwarx %[value32], 0, %[dest_base] \n"
|
||||
/* extract byte and compare */
|
||||
" srd %[old_value], %[value32], %[shift_amount] \n"
|
||||
" clrldi %[old_value], %[old_value], 56 \n"
|
||||
" cmpw %[masked_compare_val], %[old_value] \n"
|
||||
" bne- 2f \n"
|
||||
/* replace byte and try to store */
|
||||
" xor %[value32], %[xor_value], %[value32] \n"
|
||||
" stwcx. %[value32], 0, %[dest_base] \n"
|
||||
" bne- 1b \n"
|
||||
/* acquire */
|
||||
strasm_sync
|
||||
/* exit */
|
||||
"2: \n"
|
||||
/* out */
|
||||
: [old_value] "=&r" (old_value),
|
||||
[value32] "=&r" (value32),
|
||||
"=m" (*dest),
|
||||
"=m" (*dest_base)
|
||||
/* in */
|
||||
: [dest] "b" (dest),
|
||||
[dest_base] "b" (dest_base),
|
||||
[shift_amount] "r" (shift_amount),
|
||||
[masked_compare_val] "r" (masked_compare_val),
|
||||
[xor_value] "r" (xor_value),
|
||||
"m" (*dest),
|
||||
"m" (*dest_base)
|
||||
/* clobber */
|
||||
: "cc",
|
||||
"memory"
|
||||
);
|
||||
|
||||
return (jbyte)(unsigned char)old_value;
|
||||
}
|
||||
|
||||
inline jint Atomic::cmpxchg(jint exchange_value, volatile jint* dest, jint compare_value) {
|
||||
|
||||
// Note that cmpxchg guarantees a two-way memory barrier across
|
||||
|
@ -99,7 +99,7 @@ void os::initialize_thread(Thread *thread) { }
|
||||
// Frame information (pc, sp, fp) retrieved via ucontext
|
||||
// always looks like a C-frame according to the frame
|
||||
// conventions in frame_ppc64.hpp.
|
||||
address os::Linux::ucontext_get_pc(ucontext_t * uc) {
|
||||
address os::Linux::ucontext_get_pc(const ucontext_t * uc) {
|
||||
// On powerpc64, ucontext_t is not selfcontained but contains
|
||||
// a pointer to an optional substructure (mcontext_t.regs) containing the volatile
|
||||
// registers - NIP, among others.
|
||||
@ -122,19 +122,19 @@ void os::Linux::ucontext_set_pc(ucontext_t * uc, address pc) {
|
||||
uc->uc_mcontext.regs->nip = (unsigned long)pc;
|
||||
}
|
||||
|
||||
intptr_t* os::Linux::ucontext_get_sp(ucontext_t * uc) {
|
||||
intptr_t* os::Linux::ucontext_get_sp(const ucontext_t * uc) {
|
||||
return (intptr_t*)uc->uc_mcontext.regs->gpr[1/*REG_SP*/];
|
||||
}
|
||||
|
||||
intptr_t* os::Linux::ucontext_get_fp(ucontext_t * uc) {
|
||||
intptr_t* os::Linux::ucontext_get_fp(const ucontext_t * uc) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ExtendedPC os::fetch_frame_from_context(void* ucVoid,
|
||||
ExtendedPC os::fetch_frame_from_context(const void* ucVoid,
|
||||
intptr_t** ret_sp, intptr_t** ret_fp) {
|
||||
|
||||
ExtendedPC epc;
|
||||
ucontext_t* uc = (ucontext_t*)ucVoid;
|
||||
const ucontext_t* uc = (const ucontext_t*)ucVoid;
|
||||
|
||||
if (uc != NULL) {
|
||||
epc = ExtendedPC(os::Linux::ucontext_get_pc(uc));
|
||||
@ -150,7 +150,7 @@ ExtendedPC os::fetch_frame_from_context(void* ucVoid,
|
||||
return epc;
|
||||
}
|
||||
|
||||
frame os::fetch_frame_from_context(void* ucVoid) {
|
||||
frame os::fetch_frame_from_context(const void* ucVoid) {
|
||||
intptr_t* sp;
|
||||
intptr_t* fp;
|
||||
ExtendedPC epc = fetch_frame_from_context(ucVoid, &sp, &fp);
|
||||
@ -564,10 +564,10 @@ size_t os::current_stack_size() {
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// helper functions for fatal error handler
|
||||
|
||||
void os::print_context(outputStream *st, void *context) {
|
||||
void os::print_context(outputStream *st, const void *context) {
|
||||
if (context == NULL) return;
|
||||
|
||||
ucontext_t* uc = (ucontext_t*)context;
|
||||
const ucontext_t* uc = (const ucontext_t*)context;
|
||||
|
||||
st->print_cr("Registers:");
|
||||
st->print("pc =" INTPTR_FORMAT " ", uc->uc_mcontext.regs->nip);
|
||||
@ -595,10 +595,10 @@ void os::print_context(outputStream *st, void *context) {
|
||||
st->cr();
|
||||
}
|
||||
|
||||
void os::print_register_info(outputStream *st, void *context) {
|
||||
void os::print_register_info(outputStream *st, const void *context) {
|
||||
if (context == NULL) return;
|
||||
|
||||
ucontext_t *uc = (ucontext_t*)context;
|
||||
const ucontext_t *uc = (const ucontext_t*)context;
|
||||
|
||||
st->print_cr("Register to memory mapping:");
|
||||
st->cr();
|
||||
|
@ -92,7 +92,7 @@ enum {
|
||||
// signal frames. Currently we don't do that on Linux, so it's the
|
||||
// same as os::fetch_frame_from_context().
|
||||
ExtendedPC os::Linux::fetch_frame_from_ucontext(Thread* thread,
|
||||
ucontext_t* uc,
|
||||
const ucontext_t* uc,
|
||||
intptr_t** ret_sp,
|
||||
intptr_t** ret_fp) {
|
||||
assert(thread != NULL, "just checking");
|
||||
@ -102,10 +102,10 @@ ExtendedPC os::Linux::fetch_frame_from_ucontext(Thread* thread,
|
||||
return os::fetch_frame_from_context(uc, ret_sp, ret_fp);
|
||||
}
|
||||
|
||||
ExtendedPC os::fetch_frame_from_context(void* ucVoid,
|
||||
ExtendedPC os::fetch_frame_from_context(const void* ucVoid,
|
||||
intptr_t** ret_sp,
|
||||
intptr_t** ret_fp) {
|
||||
ucontext_t* uc = (ucontext_t*) ucVoid;
|
||||
const ucontext_t* uc = (const ucontext_t*) ucVoid;
|
||||
ExtendedPC epc;
|
||||
|
||||
if (uc != NULL) {
|
||||
@ -130,7 +130,7 @@ ExtendedPC os::fetch_frame_from_context(void* ucVoid,
|
||||
return epc;
|
||||
}
|
||||
|
||||
frame os::fetch_frame_from_context(void* ucVoid) {
|
||||
frame os::fetch_frame_from_context(const void* ucVoid) {
|
||||
intptr_t* sp;
|
||||
ExtendedPC epc = fetch_frame_from_context(ucVoid, &sp, NULL);
|
||||
return frame(sp, frame::unpatchable, epc.pc());
|
||||
@ -213,10 +213,10 @@ char* os::non_memory_address_word() {
|
||||
|
||||
void os::initialize_thread(Thread* thr) {}
|
||||
|
||||
void os::print_context(outputStream *st, void *context) {
|
||||
void os::print_context(outputStream *st, const void *context) {
|
||||
if (context == NULL) return;
|
||||
|
||||
ucontext_t* uc = (ucontext_t*)context;
|
||||
const ucontext_t* uc = (const ucontext_t*)context;
|
||||
sigcontext* sc = (sigcontext*)context;
|
||||
st->print_cr("Registers:");
|
||||
|
||||
@ -291,11 +291,11 @@ void os::print_context(outputStream *st, void *context) {
|
||||
}
|
||||
|
||||
|
||||
void os::print_register_info(outputStream *st, void *context) {
|
||||
void os::print_register_info(outputStream *st, const void *context) {
|
||||
if (context == NULL) return;
|
||||
|
||||
ucontext_t *uc = (ucontext_t*)context;
|
||||
sigcontext* sc = (sigcontext*)context;
|
||||
const ucontext_t *uc = (const ucontext_t*)context;
|
||||
const sigcontext* sc = (const sigcontext*)context;
|
||||
intptr_t *sp = (intptr_t *)os::Linux::ucontext_get_sp(uc);
|
||||
|
||||
st->print_cr("Register to memory mapping:");
|
||||
@ -343,7 +343,7 @@ void os::print_register_info(outputStream *st, void *context) {
|
||||
}
|
||||
|
||||
|
||||
address os::Linux::ucontext_get_pc(ucontext_t* uc) {
|
||||
address os::Linux::ucontext_get_pc(const ucontext_t* uc) {
|
||||
return (address) SIG_PC((sigcontext*)uc);
|
||||
}
|
||||
|
||||
@ -353,13 +353,13 @@ void os::Linux::ucontext_set_pc(ucontext_t* uc, address pc) {
|
||||
SIG_NPC(ctx) = (intptr_t)(pc+4);
|
||||
}
|
||||
|
||||
intptr_t* os::Linux::ucontext_get_sp(ucontext_t *uc) {
|
||||
intptr_t* os::Linux::ucontext_get_sp(const ucontext_t *uc) {
|
||||
return (intptr_t*)
|
||||
((intptr_t)SIG_REGS((sigcontext*)uc).u_regs[CON_O6] + STACK_BIAS);
|
||||
}
|
||||
|
||||
// not used on Sparc
|
||||
intptr_t* os::Linux::ucontext_get_fp(ucontext_t *uc) {
|
||||
intptr_t* os::Linux::ucontext_get_fp(const ucontext_t *uc) {
|
||||
ShouldNotReachHere();
|
||||
return NULL;
|
||||
}
|
||||
@ -684,7 +684,7 @@ JVM_handle_linux_signal(int sig,
|
||||
}
|
||||
|
||||
if (pc == NULL && uc != NULL) {
|
||||
pc = os::Linux::ucontext_get_pc((ucontext_t*)uc);
|
||||
pc = os::Linux::ucontext_get_pc((const ucontext_t*)uc);
|
||||
}
|
||||
|
||||
// unmask current signal
|
||||
|
@ -117,7 +117,7 @@ void os::initialize_thread(Thread* thr) {
|
||||
// Nothing to do.
|
||||
}
|
||||
|
||||
address os::Linux::ucontext_get_pc(ucontext_t * uc) {
|
||||
address os::Linux::ucontext_get_pc(const ucontext_t * uc) {
|
||||
return (address)uc->uc_mcontext.gregs[REG_PC];
|
||||
}
|
||||
|
||||
@ -125,11 +125,11 @@ 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) {
|
||||
intptr_t* os::Linux::ucontext_get_sp(const ucontext_t * uc) {
|
||||
return (intptr_t*)uc->uc_mcontext.gregs[REG_SP];
|
||||
}
|
||||
|
||||
intptr_t* os::Linux::ucontext_get_fp(ucontext_t * uc) {
|
||||
intptr_t* os::Linux::ucontext_get_fp(const ucontext_t * uc) {
|
||||
return (intptr_t*)uc->uc_mcontext.gregs[REG_FP];
|
||||
}
|
||||
|
||||
@ -138,8 +138,9 @@ intptr_t* os::Linux::ucontext_get_fp(ucontext_t * uc) {
|
||||
// os::Solaris::fetch_frame_from_ucontext() tries to skip nested signal
|
||||
// frames. Currently we don't do that on Linux, so it's the same as
|
||||
// os::fetch_frame_from_context().
|
||||
// This method is also used for stack overflow signal handling.
|
||||
ExtendedPC os::Linux::fetch_frame_from_ucontext(Thread* thread,
|
||||
ucontext_t* uc, intptr_t** ret_sp, intptr_t** ret_fp) {
|
||||
const ucontext_t* uc, intptr_t** ret_sp, intptr_t** ret_fp) {
|
||||
|
||||
assert(thread != NULL, "just checking");
|
||||
assert(ret_sp != NULL, "just checking");
|
||||
@ -148,11 +149,11 @@ ExtendedPC os::Linux::fetch_frame_from_ucontext(Thread* thread,
|
||||
return os::fetch_frame_from_context(uc, ret_sp, ret_fp);
|
||||
}
|
||||
|
||||
ExtendedPC os::fetch_frame_from_context(void* ucVoid,
|
||||
ExtendedPC os::fetch_frame_from_context(const void* ucVoid,
|
||||
intptr_t** ret_sp, intptr_t** ret_fp) {
|
||||
|
||||
ExtendedPC epc;
|
||||
ucontext_t* uc = (ucontext_t*)ucVoid;
|
||||
const ucontext_t* uc = (const ucontext_t*)ucVoid;
|
||||
|
||||
if (uc != NULL) {
|
||||
epc = ExtendedPC(os::Linux::ucontext_get_pc(uc));
|
||||
@ -168,13 +169,57 @@ ExtendedPC os::fetch_frame_from_context(void* ucVoid,
|
||||
return epc;
|
||||
}
|
||||
|
||||
frame os::fetch_frame_from_context(void* ucVoid) {
|
||||
frame os::fetch_frame_from_context(const void* ucVoid) {
|
||||
intptr_t* sp;
|
||||
intptr_t* fp;
|
||||
ExtendedPC epc = fetch_frame_from_context(ucVoid, &sp, &fp);
|
||||
return frame(sp, fp, epc.pc());
|
||||
}
|
||||
|
||||
frame os::fetch_frame_from_ucontext(Thread* thread, void* ucVoid) {
|
||||
intptr_t* sp;
|
||||
intptr_t* fp;
|
||||
ExtendedPC epc = os::Linux::fetch_frame_from_ucontext(thread, (ucontext_t*)ucVoid, &sp, &fp);
|
||||
return frame(sp, fp, epc.pc());
|
||||
}
|
||||
|
||||
bool os::Linux::get_frame_at_stack_banging_point(JavaThread* thread, ucontext_t* uc, frame* fr) {
|
||||
address pc = (address) os::Linux::ucontext_get_pc(uc);
|
||||
if (Interpreter::contains(pc)) {
|
||||
// interpreter performs stack banging after the fixed frame header has
|
||||
// been generated while the compilers perform it before. To maintain
|
||||
// semantic consistency between interpreted and compiled frames, the
|
||||
// method returns the Java sender of the current frame.
|
||||
*fr = os::fetch_frame_from_ucontext(thread, uc);
|
||||
if (!fr->is_first_java_frame()) {
|
||||
assert(fr->safe_for_sender(thread), "Safety check");
|
||||
*fr = fr->java_sender();
|
||||
}
|
||||
} else {
|
||||
// more complex code with compiled code
|
||||
assert(!Interpreter::contains(pc), "Interpreted methods should have been handled above");
|
||||
CodeBlob* cb = CodeCache::find_blob(pc);
|
||||
if (cb == NULL || !cb->is_nmethod() || cb->is_frame_complete_at(pc)) {
|
||||
// Not sure where the pc points to, fallback to default
|
||||
// stack overflow handling
|
||||
return false;
|
||||
} else {
|
||||
// in compiled code, the stack banging is performed just after the return pc
|
||||
// has been pushed on the stack
|
||||
intptr_t* fp = os::Linux::ucontext_get_fp(uc);
|
||||
intptr_t* sp = os::Linux::ucontext_get_sp(uc);
|
||||
*fr = frame(sp + 1, fp, (address)*sp);
|
||||
if (!fr->is_java_frame()) {
|
||||
assert(fr->safe_for_sender(thread), "Safety check");
|
||||
assert(!fr->is_first_frame(), "Safety check");
|
||||
*fr = fr->java_sender();
|
||||
}
|
||||
}
|
||||
}
|
||||
assert(fr->is_java_frame(), "Safety check");
|
||||
return true;
|
||||
}
|
||||
|
||||
// By default, gcc always save frame pointer (%ebp/%rbp) on stack. It may get
|
||||
// turned off by -fomit-frame-pointer,
|
||||
frame os::get_sender_for_C_frame(frame* fr) {
|
||||
@ -305,13 +350,32 @@ JVM_handle_linux_signal(int sig,
|
||||
addr >= thread->stack_base() - thread->stack_size()) {
|
||||
// stack overflow
|
||||
if (thread->in_stack_yellow_zone(addr)) {
|
||||
thread->disable_stack_yellow_zone();
|
||||
if (thread->thread_state() == _thread_in_Java) {
|
||||
if (thread->in_stack_reserved_zone(addr)) {
|
||||
frame fr;
|
||||
if (os::Linux::get_frame_at_stack_banging_point(thread, uc, &fr)) {
|
||||
assert(fr.is_java_frame(), "Must be a Java frame");
|
||||
frame activation =
|
||||
SharedRuntime::look_for_reserved_stack_annotated_method(thread, fr);
|
||||
if (activation.sp() != NULL) {
|
||||
thread->disable_stack_reserved_zone();
|
||||
if (activation.is_interpreted_frame()) {
|
||||
thread->set_reserved_stack_activation((address)(
|
||||
activation.fp() + frame::interpreter_frame_initial_sp_offset));
|
||||
} else {
|
||||
thread->set_reserved_stack_activation((address)activation.unextended_sp());
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
// Throw a stack overflow exception. Guard pages will be reenabled
|
||||
// while unwinding the stack.
|
||||
thread->disable_stack_yellow_zone();
|
||||
stub = SharedRuntime::continuation_for_implicit_exception(thread, pc, SharedRuntime::STACK_OVERFLOW);
|
||||
} else {
|
||||
// Thread was in the vm or native code. Return and try to finish.
|
||||
thread->disable_stack_yellow_zone();
|
||||
return 1;
|
||||
}
|
||||
} else if (thread->in_stack_red_zone(addr)) {
|
||||
@ -720,10 +784,10 @@ size_t os::current_stack_size() {
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// helper functions for fatal error handler
|
||||
|
||||
void os::print_context(outputStream *st, void *context) {
|
||||
void os::print_context(outputStream *st, const void *context) {
|
||||
if (context == NULL) return;
|
||||
|
||||
ucontext_t *uc = (ucontext_t*)context;
|
||||
const ucontext_t *uc = (const ucontext_t*)context;
|
||||
st->print_cr("Registers:");
|
||||
#ifdef AMD64
|
||||
st->print( "RAX=" INTPTR_FORMAT, (intptr_t)uc->uc_mcontext.gregs[REG_RAX]);
|
||||
@ -783,10 +847,10 @@ void os::print_context(outputStream *st, void *context) {
|
||||
print_hex_dump(st, pc - 32, pc + 32, sizeof(char));
|
||||
}
|
||||
|
||||
void os::print_register_info(outputStream *st, void *context) {
|
||||
void os::print_register_info(outputStream *st, const void *context) {
|
||||
if (context == NULL) return;
|
||||
|
||||
ucontext_t *uc = (ucontext_t*)context;
|
||||
const ucontext_t *uc = (const ucontext_t*)context;
|
||||
|
||||
st->print_cr("Register to memory mapping:");
|
||||
st->cr();
|
||||
@ -868,7 +932,7 @@ void os::workaround_expand_exec_shield_cs_limit() {
|
||||
* we don't have much control or understanding of the address space, just let it slide.
|
||||
*/
|
||||
char* hint = (char*) (Linux::initial_thread_stack_bottom() -
|
||||
((StackYellowPages + StackRedPages + 1) * page_size));
|
||||
((StackReservedPages + StackYellowPages + StackRedPages + 1) * page_size));
|
||||
char* codebuf = os::attempt_reserve_memory_at(page_size, hint);
|
||||
if ( (codebuf == NULL) || (!os::commit_memory(codebuf, page_size, true)) ) {
|
||||
return; // No matter, we tried, best effort.
|
||||
|
@ -100,7 +100,7 @@ void os::initialize_thread(Thread * thr){
|
||||
// Nothing to do.
|
||||
}
|
||||
|
||||
address os::Linux::ucontext_get_pc(ucontext_t* uc) {
|
||||
address os::Linux::ucontext_get_pc(const ucontext_t* uc) {
|
||||
ShouldNotCallThis();
|
||||
}
|
||||
|
||||
@ -108,13 +108,13 @@ void os::Linux::ucontext_set_pc(ucontext_t * uc, address pc) {
|
||||
ShouldNotCallThis();
|
||||
}
|
||||
|
||||
ExtendedPC os::fetch_frame_from_context(void* ucVoid,
|
||||
ExtendedPC os::fetch_frame_from_context(const void* ucVoid,
|
||||
intptr_t** ret_sp,
|
||||
intptr_t** ret_fp) {
|
||||
ShouldNotCallThis();
|
||||
}
|
||||
|
||||
frame os::fetch_frame_from_context(void* ucVoid) {
|
||||
frame os::fetch_frame_from_context(const void* ucVoid) {
|
||||
ShouldNotCallThis();
|
||||
}
|
||||
|
||||
@ -406,11 +406,11 @@ size_t os::current_stack_size() {
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// helper functions for fatal error handler
|
||||
|
||||
void os::print_context(outputStream* st, void* context) {
|
||||
void os::print_context(outputStream* st, const void* context) {
|
||||
ShouldNotCallThis();
|
||||
}
|
||||
|
||||
void os::print_register_info(outputStream *st, void *context) {
|
||||
void os::print_register_info(outputStream *st, const void *context) {
|
||||
ShouldNotCallThis();
|
||||
}
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 1999, 2015, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 1999, 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
|
||||
@ -121,7 +121,7 @@ char* os::non_memory_address_word() {
|
||||
// There are issues with libthread giving out uc_links for different threads
|
||||
// on the same uc_link chain and bad or circular links.
|
||||
//
|
||||
bool os::Solaris::valid_ucontext(Thread* thread, ucontext_t* valid, ucontext_t* suspect) {
|
||||
bool os::Solaris::valid_ucontext(Thread* thread, const ucontext_t* valid, const ucontext_t* suspect) {
|
||||
if (valid >= suspect ||
|
||||
valid->uc_stack.ss_flags != suspect->uc_stack.ss_flags ||
|
||||
valid->uc_stack.ss_sp != suspect->uc_stack.ss_sp ||
|
||||
@ -148,10 +148,10 @@ bool os::Solaris::valid_ucontext(Thread* thread, ucontext_t* valid, ucontext_t*
|
||||
// We will only follow one level of uc_link since there are libthread
|
||||
// issues with ucontext linking and it is better to be safe and just
|
||||
// let caller retry later.
|
||||
ucontext_t* os::Solaris::get_valid_uc_in_signal_handler(Thread *thread,
|
||||
ucontext_t *uc) {
|
||||
const ucontext_t* os::Solaris::get_valid_uc_in_signal_handler(Thread *thread,
|
||||
const ucontext_t *uc) {
|
||||
|
||||
ucontext_t *retuc = NULL;
|
||||
const ucontext_t *retuc = NULL;
|
||||
|
||||
// Sometimes the topmost register windows are not properly flushed.
|
||||
// i.e., if the kernel would have needed to take a page fault
|
||||
@ -179,7 +179,7 @@ ucontext_t* os::Solaris::get_valid_uc_in_signal_handler(Thread *thread,
|
||||
}
|
||||
|
||||
// Assumes ucontext is valid
|
||||
ExtendedPC os::Solaris::ucontext_get_ExtendedPC(ucontext_t *uc) {
|
||||
ExtendedPC os::Solaris::ucontext_get_ExtendedPC(const ucontext_t *uc) {
|
||||
address pc = (address)uc->uc_mcontext.gregs[REG_PC];
|
||||
// set npc to zero to avoid using it for safepoint, good for profiling only
|
||||
return ExtendedPC(pc);
|
||||
@ -191,17 +191,17 @@ void os::Solaris::ucontext_set_pc(ucontext_t* uc, address pc) {
|
||||
}
|
||||
|
||||
// Assumes ucontext is valid
|
||||
intptr_t* os::Solaris::ucontext_get_sp(ucontext_t *uc) {
|
||||
intptr_t* os::Solaris::ucontext_get_sp(const ucontext_t *uc) {
|
||||
return (intptr_t*)((intptr_t)uc->uc_mcontext.gregs[REG_SP] + STACK_BIAS);
|
||||
}
|
||||
|
||||
// Solaris X86 only
|
||||
intptr_t* os::Solaris::ucontext_get_fp(ucontext_t *uc) {
|
||||
intptr_t* os::Solaris::ucontext_get_fp(const ucontext_t *uc) {
|
||||
ShouldNotReachHere();
|
||||
return NULL;
|
||||
}
|
||||
|
||||
address os::Solaris::ucontext_get_pc(ucontext_t *uc) {
|
||||
address os::Solaris::ucontext_get_pc(const ucontext_t *uc) {
|
||||
return (address) uc->uc_mcontext.gregs[REG_PC];
|
||||
}
|
||||
|
||||
@ -213,25 +213,26 @@ address os::Solaris::ucontext_get_pc(ucontext_t *uc) {
|
||||
//
|
||||
// The difference between this and os::fetch_frame_from_context() is that
|
||||
// here we try to skip nested signal frames.
|
||||
// This method is also used for stack overflow signal handling.
|
||||
ExtendedPC os::Solaris::fetch_frame_from_ucontext(Thread* thread,
|
||||
ucontext_t* uc, intptr_t** ret_sp, intptr_t** ret_fp) {
|
||||
const ucontext_t* uc, intptr_t** ret_sp, intptr_t** ret_fp) {
|
||||
|
||||
assert(thread != NULL, "just checking");
|
||||
assert(ret_sp != NULL, "just checking");
|
||||
assert(ret_fp == NULL, "just checking");
|
||||
|
||||
ucontext_t *luc = os::Solaris::get_valid_uc_in_signal_handler(thread, uc);
|
||||
const ucontext_t *luc = os::Solaris::get_valid_uc_in_signal_handler(thread, uc);
|
||||
|
||||
return os::fetch_frame_from_context(luc, ret_sp, ret_fp);
|
||||
}
|
||||
|
||||
|
||||
// ret_fp parameter is only used by Solaris X86.
|
||||
ExtendedPC os::fetch_frame_from_context(void* ucVoid,
|
||||
ExtendedPC os::fetch_frame_from_context(const void* ucVoid,
|
||||
intptr_t** ret_sp, intptr_t** ret_fp) {
|
||||
|
||||
ExtendedPC epc;
|
||||
ucontext_t *uc = (ucontext_t*)ucVoid;
|
||||
const ucontext_t *uc = (const ucontext_t*)ucVoid;
|
||||
|
||||
if (uc != NULL) {
|
||||
epc = os::Solaris::ucontext_get_ExtendedPC(uc);
|
||||
@ -245,13 +246,48 @@ ExtendedPC os::fetch_frame_from_context(void* ucVoid,
|
||||
return epc;
|
||||
}
|
||||
|
||||
frame os::fetch_frame_from_context(void* ucVoid) {
|
||||
frame os::fetch_frame_from_context(const void* ucVoid) {
|
||||
intptr_t* sp;
|
||||
intptr_t* fp;
|
||||
ExtendedPC epc = fetch_frame_from_context(ucVoid, &sp, &fp);
|
||||
return frame(sp, frame::unpatchable, epc.pc());
|
||||
}
|
||||
|
||||
frame os::fetch_frame_from_ucontext(Thread* thread, void* ucVoid) {
|
||||
intptr_t* sp;
|
||||
ExtendedPC epc = os::Solaris::fetch_frame_from_ucontext(thread, (ucontext_t*)ucVoid, &sp, NULL);
|
||||
return frame(sp, frame::unpatchable, epc.pc());
|
||||
}
|
||||
|
||||
bool os::Solaris::get_frame_at_stack_banging_point(JavaThread* thread, ucontext_t* uc, frame* fr) {
|
||||
address pc = (address) os::Solaris::ucontext_get_pc(uc);
|
||||
if (Interpreter::contains(pc)) {
|
||||
*fr = os::fetch_frame_from_ucontext(thread, uc);
|
||||
if (!fr->is_first_java_frame()) {
|
||||
assert(fr->safe_for_sender(thread), "Safety check");
|
||||
*fr = fr->java_sender();
|
||||
}
|
||||
} else {
|
||||
// more complex code with compiled code
|
||||
assert(!Interpreter::contains(pc), "Interpreted methods should have been handled above");
|
||||
CodeBlob* cb = CodeCache::find_blob(pc);
|
||||
if (cb == NULL || !cb->is_nmethod() || cb->is_frame_complete_at(pc)) {
|
||||
// Not sure where the pc points to, fallback to default
|
||||
// stack overflow handling
|
||||
return false;
|
||||
} else {
|
||||
*fr = os::fetch_frame_from_ucontext(thread, uc);
|
||||
*fr = frame(fr->sender_sp(), frame::unpatchable, fr->sender_pc());
|
||||
if (!fr->is_java_frame()) {
|
||||
assert(fr->safe_for_sender(thread), "Safety check");
|
||||
*fr = fr->java_sender();
|
||||
}
|
||||
}
|
||||
}
|
||||
assert(fr->is_java_frame(), "Safety check");
|
||||
return true;
|
||||
}
|
||||
|
||||
frame os::get_sender_for_C_frame(frame* fr) {
|
||||
return frame(fr->sender_sp(), frame::unpatchable, fr->sender_pc());
|
||||
}
|
||||
@ -367,17 +403,32 @@ JVM_handle_solaris_signal(int sig, siginfo_t* info, void* ucVoid,
|
||||
if (sig == SIGSEGV && info->si_code == SEGV_ACCERR) {
|
||||
address addr = (address) info->si_addr;
|
||||
if (thread->in_stack_yellow_zone(addr)) {
|
||||
thread->disable_stack_yellow_zone();
|
||||
// Sometimes the register windows are not properly flushed.
|
||||
if(uc->uc_mcontext.gwins != NULL) {
|
||||
::handle_unflushed_register_windows(uc->uc_mcontext.gwins);
|
||||
}
|
||||
if (thread->thread_state() == _thread_in_Java) {
|
||||
if (thread->in_stack_reserved_zone(addr)) {
|
||||
frame fr;
|
||||
if (os::Solaris::get_frame_at_stack_banging_point(thread, uc, &fr)) {
|
||||
assert(fr.is_java_frame(), "Must be a Java frame");
|
||||
frame activation = SharedRuntime::look_for_reserved_stack_annotated_method(thread, fr);
|
||||
if (activation.sp() != NULL) {
|
||||
thread->disable_stack_reserved_zone();
|
||||
RegisterMap map(thread);
|
||||
int frame_size = activation.frame_size(&map);
|
||||
thread->set_reserved_stack_activation((address)(((address)activation.sp()) - STACK_BIAS));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
// Throw a stack overflow exception. Guard pages will be reenabled
|
||||
// while unwinding the stack.
|
||||
thread->disable_stack_yellow_zone();
|
||||
stub = SharedRuntime::continuation_for_implicit_exception(thread, pc, SharedRuntime::STACK_OVERFLOW);
|
||||
} else {
|
||||
// Thread was in the vm or native code. Return and try to finish.
|
||||
thread->disable_stack_yellow_zone();
|
||||
return true;
|
||||
}
|
||||
} else if (thread->in_stack_red_zone(addr)) {
|
||||
@ -554,10 +605,10 @@ JVM_handle_solaris_signal(int sig, siginfo_t* info, void* ucVoid,
|
||||
return false;
|
||||
}
|
||||
|
||||
void os::print_context(outputStream *st, void *context) {
|
||||
void os::print_context(outputStream *st, const void *context) {
|
||||
if (context == NULL) return;
|
||||
|
||||
ucontext_t *uc = (ucontext_t*)context;
|
||||
const ucontext_t *uc = (const ucontext_t*)context;
|
||||
st->print_cr("Registers:");
|
||||
|
||||
st->print_cr(" G1=" INTPTR_FORMAT " G2=" INTPTR_FORMAT
|
||||
@ -631,10 +682,10 @@ void os::print_context(outputStream *st, void *context) {
|
||||
print_hex_dump(st, pc - 32, pc + 32, sizeof(char));
|
||||
}
|
||||
|
||||
void os::print_register_info(outputStream *st, void *context) {
|
||||
void os::print_register_info(outputStream *st, const void *context) {
|
||||
if (context == NULL) return;
|
||||
|
||||
ucontext_t *uc = (ucontext_t*)context;
|
||||
const ucontext_t *uc = (const ucontext_t*)context;
|
||||
intptr_t *sp = (intptr_t *)os::Solaris::ucontext_get_sp(uc);
|
||||
|
||||
st->print_cr("Register to memory mapping:");
|
||||
|
@ -121,7 +121,7 @@ char* os::non_memory_address_word() {
|
||||
// There are issues with libthread giving out uc_links for different threads
|
||||
// on the same uc_link chain and bad or circular links.
|
||||
//
|
||||
bool os::Solaris::valid_ucontext(Thread* thread, ucontext_t* valid, ucontext_t* suspect) {
|
||||
bool os::Solaris::valid_ucontext(Thread* thread, const ucontext_t* valid, const ucontext_t* suspect) {
|
||||
if (valid >= suspect ||
|
||||
valid->uc_stack.ss_flags != suspect->uc_stack.ss_flags ||
|
||||
valid->uc_stack.ss_sp != suspect->uc_stack.ss_sp ||
|
||||
@ -146,10 +146,10 @@ bool os::Solaris::valid_ucontext(Thread* thread, ucontext_t* valid, ucontext_t*
|
||||
// We will only follow one level of uc_link since there are libthread
|
||||
// issues with ucontext linking and it is better to be safe and just
|
||||
// let caller retry later.
|
||||
ucontext_t* os::Solaris::get_valid_uc_in_signal_handler(Thread *thread,
|
||||
ucontext_t *uc) {
|
||||
const ucontext_t* os::Solaris::get_valid_uc_in_signal_handler(Thread *thread,
|
||||
const ucontext_t *uc) {
|
||||
|
||||
ucontext_t *retuc = NULL;
|
||||
const ucontext_t *retuc = NULL;
|
||||
|
||||
if (uc != NULL) {
|
||||
if (uc->uc_link == NULL) {
|
||||
@ -171,7 +171,7 @@ ucontext_t* os::Solaris::get_valid_uc_in_signal_handler(Thread *thread,
|
||||
}
|
||||
|
||||
// Assumes ucontext is valid
|
||||
ExtendedPC os::Solaris::ucontext_get_ExtendedPC(ucontext_t *uc) {
|
||||
ExtendedPC os::Solaris::ucontext_get_ExtendedPC(const ucontext_t *uc) {
|
||||
return ExtendedPC((address)uc->uc_mcontext.gregs[REG_PC]);
|
||||
}
|
||||
|
||||
@ -180,16 +180,16 @@ void os::Solaris::ucontext_set_pc(ucontext_t* uc, address pc) {
|
||||
}
|
||||
|
||||
// Assumes ucontext is valid
|
||||
intptr_t* os::Solaris::ucontext_get_sp(ucontext_t *uc) {
|
||||
intptr_t* os::Solaris::ucontext_get_sp(const ucontext_t *uc) {
|
||||
return (intptr_t*)uc->uc_mcontext.gregs[REG_SP];
|
||||
}
|
||||
|
||||
// Assumes ucontext is valid
|
||||
intptr_t* os::Solaris::ucontext_get_fp(ucontext_t *uc) {
|
||||
intptr_t* os::Solaris::ucontext_get_fp(const ucontext_t *uc) {
|
||||
return (intptr_t*)uc->uc_mcontext.gregs[REG_FP];
|
||||
}
|
||||
|
||||
address os::Solaris::ucontext_get_pc(ucontext_t *uc) {
|
||||
address os::Solaris::ucontext_get_pc(const ucontext_t *uc) {
|
||||
return (address) uc->uc_mcontext.gregs[REG_PC];
|
||||
}
|
||||
|
||||
@ -198,22 +198,23 @@ address os::Solaris::ucontext_get_pc(ucontext_t *uc) {
|
||||
//
|
||||
// The difference between this and os::fetch_frame_from_context() is that
|
||||
// here we try to skip nested signal frames.
|
||||
// This method is also used for stack overflow signal handling.
|
||||
ExtendedPC os::Solaris::fetch_frame_from_ucontext(Thread* thread,
|
||||
ucontext_t* uc, intptr_t** ret_sp, intptr_t** ret_fp) {
|
||||
const ucontext_t* uc, intptr_t** ret_sp, intptr_t** ret_fp) {
|
||||
|
||||
assert(thread != NULL, "just checking");
|
||||
assert(ret_sp != NULL, "just checking");
|
||||
assert(ret_fp != NULL, "just checking");
|
||||
|
||||
ucontext_t *luc = os::Solaris::get_valid_uc_in_signal_handler(thread, uc);
|
||||
const ucontext_t *luc = os::Solaris::get_valid_uc_in_signal_handler(thread, uc);
|
||||
return os::fetch_frame_from_context(luc, ret_sp, ret_fp);
|
||||
}
|
||||
|
||||
ExtendedPC os::fetch_frame_from_context(void* ucVoid,
|
||||
ExtendedPC os::fetch_frame_from_context(const void* ucVoid,
|
||||
intptr_t** ret_sp, intptr_t** ret_fp) {
|
||||
|
||||
ExtendedPC epc;
|
||||
ucontext_t *uc = (ucontext_t*)ucVoid;
|
||||
const ucontext_t *uc = (const ucontext_t*)ucVoid;
|
||||
|
||||
if (uc != NULL) {
|
||||
epc = os::Solaris::ucontext_get_ExtendedPC(uc);
|
||||
@ -229,13 +230,56 @@ ExtendedPC os::fetch_frame_from_context(void* ucVoid,
|
||||
return epc;
|
||||
}
|
||||
|
||||
frame os::fetch_frame_from_context(void* ucVoid) {
|
||||
frame os::fetch_frame_from_context(const void* ucVoid) {
|
||||
intptr_t* sp;
|
||||
intptr_t* fp;
|
||||
ExtendedPC epc = fetch_frame_from_context(ucVoid, &sp, &fp);
|
||||
return frame(sp, fp, epc.pc());
|
||||
}
|
||||
|
||||
frame os::fetch_frame_from_ucontext(Thread* thread, void* ucVoid) {
|
||||
intptr_t* sp;
|
||||
intptr_t* fp;
|
||||
ExtendedPC epc = os::Solaris::fetch_frame_from_ucontext(thread, (ucontext_t*)ucVoid, &sp, &fp);
|
||||
return frame(sp, fp, epc.pc());
|
||||
}
|
||||
|
||||
bool os::Solaris::get_frame_at_stack_banging_point(JavaThread* thread, ucontext_t* uc, frame* fr) {
|
||||
address pc = (address) os::Solaris::ucontext_get_pc(uc);
|
||||
if (Interpreter::contains(pc)) {
|
||||
// interpreter performs stack banging after the fixed frame header has
|
||||
// been generated while the compilers perform it before. To maintain
|
||||
// semantic consistency between interpreted and compiled frames, the
|
||||
// method returns the Java sender of the current frame.
|
||||
*fr = os::fetch_frame_from_ucontext(thread, uc);
|
||||
if (!fr->is_first_java_frame()) {
|
||||
assert(fr->safe_for_sender(thread), "Safety check");
|
||||
*fr = fr->java_sender();
|
||||
}
|
||||
} else {
|
||||
// more complex code with compiled code
|
||||
assert(!Interpreter::contains(pc), "Interpreted methods should have been handled above");
|
||||
CodeBlob* cb = CodeCache::find_blob(pc);
|
||||
if (cb == NULL || !cb->is_nmethod() || cb->is_frame_complete_at(pc)) {
|
||||
// Not sure where the pc points to, fallback to default
|
||||
// stack overflow handling
|
||||
return false;
|
||||
} else {
|
||||
// in compiled code, the stack banging is performed just after the return pc
|
||||
// has been pushed on the stack
|
||||
intptr_t* fp = os::Solaris::ucontext_get_fp(uc);
|
||||
intptr_t* sp = os::Solaris::ucontext_get_sp(uc);
|
||||
*fr = frame(sp + 1, fp, (address)*sp);
|
||||
if (!fr->is_java_frame()) {
|
||||
assert(fr->safe_for_sender(thread), "Safety check");
|
||||
*fr = fr->java_sender();
|
||||
}
|
||||
}
|
||||
}
|
||||
assert(fr->is_java_frame(), "Safety check");
|
||||
return true;
|
||||
}
|
||||
|
||||
frame os::get_sender_for_C_frame(frame* fr) {
|
||||
return frame(fr->sender_sp(), fr->link(), fr->sender_pc());
|
||||
}
|
||||
@ -422,13 +466,31 @@ JVM_handle_solaris_signal(int sig, siginfo_t* info, void* ucVoid,
|
||||
if (sig == SIGSEGV && info->si_code == SEGV_ACCERR) {
|
||||
address addr = (address) info->si_addr;
|
||||
if (thread->in_stack_yellow_zone(addr)) {
|
||||
thread->disable_stack_yellow_zone();
|
||||
if (thread->thread_state() == _thread_in_Java) {
|
||||
if (thread->in_stack_reserved_zone(addr)) {
|
||||
frame fr;
|
||||
if (os::Solaris::get_frame_at_stack_banging_point(thread, uc, &fr)) {
|
||||
assert(fr.is_java_frame(), "Must be Java frame");
|
||||
frame activation = SharedRuntime::look_for_reserved_stack_annotated_method(thread, fr);
|
||||
if (activation.sp() != NULL) {
|
||||
thread->disable_stack_reserved_zone();
|
||||
if (activation.is_interpreted_frame()) {
|
||||
thread->set_reserved_stack_activation((address)(
|
||||
activation.fp() + frame::interpreter_frame_initial_sp_offset));
|
||||
} else {
|
||||
thread->set_reserved_stack_activation((address)activation.unextended_sp());
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
// Throw a stack overflow exception. Guard pages will be reenabled
|
||||
// while unwinding the stack.
|
||||
thread->disable_stack_yellow_zone();
|
||||
stub = SharedRuntime::continuation_for_implicit_exception(thread, pc, SharedRuntime::STACK_OVERFLOW);
|
||||
} else {
|
||||
// Thread was in the vm or native code. Return and try to finish.
|
||||
thread->disable_stack_yellow_zone();
|
||||
return true;
|
||||
}
|
||||
} else if (thread->in_stack_red_zone(addr)) {
|
||||
@ -712,10 +774,10 @@ JVM_handle_solaris_signal(int sig, siginfo_t* info, void* ucVoid,
|
||||
return false;
|
||||
}
|
||||
|
||||
void os::print_context(outputStream *st, void *context) {
|
||||
void os::print_context(outputStream *st, const void *context) {
|
||||
if (context == NULL) return;
|
||||
|
||||
ucontext_t *uc = (ucontext_t*)context;
|
||||
const ucontext_t *uc = (const ucontext_t*)context;
|
||||
st->print_cr("Registers:");
|
||||
#ifdef AMD64
|
||||
st->print( "RAX=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_RAX]);
|
||||
@ -771,10 +833,10 @@ void os::print_context(outputStream *st, void *context) {
|
||||
print_hex_dump(st, pc - 32, pc + 32, sizeof(char));
|
||||
}
|
||||
|
||||
void os::print_register_info(outputStream *st, void *context) {
|
||||
void os::print_register_info(outputStream *st, const void *context) {
|
||||
if (context == NULL) return;
|
||||
|
||||
ucontext_t *uc = (ucontext_t*)context;
|
||||
const ucontext_t *uc = (const ucontext_t*)context;
|
||||
|
||||
st->print_cr("Register to memory mapping:");
|
||||
st->cr();
|
||||
|
@ -359,7 +359,7 @@ cmpxchg_long_func_t* os::atomic_cmpxchg_long_func = os::atomic_cmpxchg_long_boot
|
||||
* while (...) {... fr = os::get_sender_for_C_frame(&fr); }
|
||||
* loop in vmError.cpp. We need to roll our own loop.
|
||||
*/
|
||||
bool os::platform_print_native_stack(outputStream* st, void* context,
|
||||
bool os::platform_print_native_stack(outputStream* st, const void* context,
|
||||
char *buf, int buf_size)
|
||||
{
|
||||
CONTEXT ctx;
|
||||
@ -435,7 +435,7 @@ bool os::platform_print_native_stack(outputStream* st, void* context,
|
||||
}
|
||||
#endif // AMD64
|
||||
|
||||
ExtendedPC os::fetch_frame_from_context(void* ucVoid,
|
||||
ExtendedPC os::fetch_frame_from_context(const void* ucVoid,
|
||||
intptr_t** ret_sp, intptr_t** ret_fp) {
|
||||
|
||||
ExtendedPC epc;
|
||||
@ -455,7 +455,7 @@ ExtendedPC os::fetch_frame_from_context(void* ucVoid,
|
||||
return epc;
|
||||
}
|
||||
|
||||
frame os::fetch_frame_from_context(void* ucVoid) {
|
||||
frame os::fetch_frame_from_context(const void* ucVoid) {
|
||||
intptr_t* sp;
|
||||
intptr_t* fp;
|
||||
ExtendedPC epc = fetch_frame_from_context(ucVoid, &sp, &fp);
|
||||
@ -527,10 +527,10 @@ frame os::current_frame() {
|
||||
}
|
||||
}
|
||||
|
||||
void os::print_context(outputStream *st, void *context) {
|
||||
void os::print_context(outputStream *st, const void *context) {
|
||||
if (context == NULL) return;
|
||||
|
||||
CONTEXT* uc = (CONTEXT*)context;
|
||||
const CONTEXT* uc = (const CONTEXT*)context;
|
||||
|
||||
st->print_cr("Registers:");
|
||||
#ifdef AMD64
|
||||
@ -588,10 +588,10 @@ void os::print_context(outputStream *st, void *context) {
|
||||
}
|
||||
|
||||
|
||||
void os::print_register_info(outputStream *st, void *context) {
|
||||
void os::print_register_info(outputStream *st, const void *context) {
|
||||
if (context == NULL) return;
|
||||
|
||||
CONTEXT* uc = (CONTEXT*)context;
|
||||
const CONTEXT* uc = (const CONTEXT*)context;
|
||||
|
||||
st->print_cr("Register to memory mapping:");
|
||||
st->cr();
|
||||
|
@ -66,7 +66,7 @@
|
||||
|
||||
#ifdef AMD64
|
||||
#define PLATFORM_PRINT_NATIVE_STACK 1
|
||||
static bool platform_print_native_stack(outputStream* st, void* context,
|
||||
static bool platform_print_native_stack(outputStream* st, const void* context,
|
||||
char *buf, int buf_size);
|
||||
#endif
|
||||
|
||||
|
@ -70,12 +70,12 @@ CONFIGURE_ARGS= --host=$(MINGW) --target=$(MINGW)
|
||||
else #linux
|
||||
CPU = $(shell uname -m)
|
||||
ARCH1=$(CPU:x86_64=amd64)
|
||||
ARCH2=$(ARCH1:i686=i386)
|
||||
ARCH=$(ARCH2:ppc64le=ppc64)
|
||||
ARCH=$(ARCH1:i686=i386)
|
||||
ifdef LP64
|
||||
CFLAGS/sparcv9 += -m64
|
||||
CFLAGS/amd64 += -m64
|
||||
CFLAGS/ppc64 += -m64
|
||||
CFLAGS/ppc64le += -m64 -DABI_ELFv2
|
||||
else
|
||||
ARCH=$(ARCH1:amd64=i386)
|
||||
CFLAGS/i386 += -m32
|
||||
|
@ -66,7 +66,7 @@ int main(int ac, char** av) {
|
||||
printf("...And now for something completely different:\n");
|
||||
void *start = (void*) &main;
|
||||
void *end = (void*) &end_of_file;
|
||||
#if defined(__ia64) || defined(__powerpc__)
|
||||
#if defined(__ia64) || (defined(__powerpc__) && !defined(ABI_ELFv2))
|
||||
/* On IA64 and PPC function pointers are pointers to function descriptors */
|
||||
start = *((void**)start);
|
||||
end = *((void**)end);
|
||||
|
@ -461,7 +461,7 @@ static const char* native_arch_name() {
|
||||
#ifdef LIBARCH_sparcv9
|
||||
res = "sparc:v9b";
|
||||
#endif
|
||||
#ifdef LIBARCH_ppc64
|
||||
#if defined(LIBARCH_ppc64) || defined(LIBARCH_ppc64le)
|
||||
res = "powerpc:common64";
|
||||
#endif
|
||||
#ifdef LIBARCH_aarch64
|
||||
|
@ -8,7 +8,6 @@
|
||||
prepend in front of bootstrap class path
|
||||
-Xnoclassgc disable class garbage collection
|
||||
-Xlog:<opts> control JVM logging, use -Xlog:help for details
|
||||
-Xloggc:<file> log GC status to a file with time stamps
|
||||
-Xbatch disable background compilation
|
||||
-Xms<size> set initial Java heap size
|
||||
-Xmx<size> set maximum Java heap size
|
||||
|
@ -551,6 +551,7 @@ Compilation::Compilation(AbstractCompiler* compiler, ciEnv* env, ciMethod* metho
|
||||
, _would_profile(false)
|
||||
, _has_unsafe_access(false)
|
||||
, _has_method_handle_invokes(false)
|
||||
, _has_reserved_stack_access(method->has_reserved_stack_access())
|
||||
, _bailout_msg(NULL)
|
||||
, _exception_info_list(NULL)
|
||||
, _allocator(NULL)
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 1999, 2015, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 1999, 2013, 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
|
||||
@ -81,6 +81,7 @@ class Compilation: public StackObj {
|
||||
bool _has_unsafe_access;
|
||||
bool _would_profile;
|
||||
bool _has_method_handle_invokes; // True if this method has MethodHandle invokes.
|
||||
bool _has_reserved_stack_access;
|
||||
const char* _bailout_msg;
|
||||
ExceptionInfoList* _exception_info_list;
|
||||
ExceptionHandlerTable _exception_handler_table;
|
||||
@ -171,6 +172,9 @@ class Compilation: public StackObj {
|
||||
bool has_method_handle_invokes() const { return _has_method_handle_invokes; }
|
||||
void set_has_method_handle_invokes(bool z) { _has_method_handle_invokes = z; }
|
||||
|
||||
bool has_reserved_stack_access() const { return _has_reserved_stack_access; }
|
||||
void set_has_reserved_stack_access(bool z) { _has_reserved_stack_access = z; }
|
||||
|
||||
DebugInformationRecorder* debug_info_recorder() const; // = _env->debug_info();
|
||||
Dependencies* dependency_recorder() const; // = _env->dependencies()
|
||||
ImplicitExceptionTable* implicit_exception_table() { return &_implicit_exception_table; }
|
||||
|
@ -3322,7 +3322,13 @@ bool GraphBuilder::try_inline(ciMethod* callee, bool holder_known, Bytecodes::Co
|
||||
|
||||
// method handle invokes
|
||||
if (callee->is_method_handle_intrinsic()) {
|
||||
return try_method_handle_inline(callee);
|
||||
if (try_method_handle_inline(callee)) {
|
||||
if (callee->has_reserved_stack_access()) {
|
||||
compilation()->set_has_reserved_stack_access(true);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// handle intrinsics
|
||||
@ -3330,6 +3336,9 @@ bool GraphBuilder::try_inline(ciMethod* callee, bool holder_known, Bytecodes::Co
|
||||
(CheckIntrinsics ? callee->intrinsic_candidate() : true)) {
|
||||
if (try_inline_intrinsics(callee)) {
|
||||
print_inlining(callee, "intrinsic");
|
||||
if (callee->has_reserved_stack_access()) {
|
||||
compilation()->set_has_reserved_stack_access(true);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
// try normal inlining
|
||||
@ -3346,8 +3355,12 @@ bool GraphBuilder::try_inline(ciMethod* callee, bool holder_known, Bytecodes::Co
|
||||
if (bc == Bytecodes::_illegal) {
|
||||
bc = code();
|
||||
}
|
||||
if (try_inline_full(callee, holder_known, bc, receiver))
|
||||
if (try_inline_full(callee, holder_known, bc, receiver)) {
|
||||
if (callee->has_reserved_stack_access()) {
|
||||
compilation()->set_has_reserved_stack_access(true);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// Entire compilation could fail during try_inline_full call.
|
||||
// In that case printing inlining decision info is useless.
|
||||
|
@ -502,7 +502,7 @@ JRT_ENTRY_NO_ASYNC(static address, exception_handler_for_pc_helper(JavaThread* t
|
||||
// Check the stack guard pages and reenable them if necessary and there is
|
||||
// enough space on the stack to do so. Use fast exceptions only if the guard
|
||||
// pages are enabled.
|
||||
bool guard_pages_enabled = thread->stack_yellow_zone_enabled();
|
||||
bool guard_pages_enabled = thread->stack_guards_enabled();
|
||||
if (!guard_pages_enabled) guard_pages_enabled = thread->reguard_stack();
|
||||
|
||||
if (JvmtiExport::can_post_on_exceptions()) {
|
||||
|
@ -91,6 +91,7 @@ ciMethod::ciMethod(methodHandle h_m, ciInstanceKlass* holder) :
|
||||
_balanced_monitors = !_uses_monitors || h_m()->access_flags().is_monitor_matching();
|
||||
_is_c1_compilable = !h_m()->is_not_c1_compilable();
|
||||
_is_c2_compilable = !h_m()->is_not_c2_compilable();
|
||||
_has_reserved_stack_access = h_m()->has_reserved_stack_access();
|
||||
// Lazy fields, filled in on demand. Require allocation.
|
||||
_code = NULL;
|
||||
_exception_handlers = NULL;
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 1999, 2013, 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
|
||||
@ -81,6 +81,7 @@ class ciMethod : public ciMetadata {
|
||||
bool _is_c1_compilable;
|
||||
bool _is_c2_compilable;
|
||||
bool _can_be_statically_bound;
|
||||
bool _has_reserved_stack_access;
|
||||
|
||||
// Lazy fields, filled in on demand
|
||||
address _code;
|
||||
@ -316,6 +317,7 @@ class ciMethod : public ciMetadata {
|
||||
bool is_accessor () const;
|
||||
bool is_initializer () const;
|
||||
bool can_be_statically_bound() const { return _can_be_statically_bound; }
|
||||
bool has_reserved_stack_access() const { return _has_reserved_stack_access; }
|
||||
bool is_boxing_method() const;
|
||||
bool is_unboxing_method() const;
|
||||
|
||||
|
@ -946,6 +946,7 @@ public:
|
||||
_method_HotSpotIntrinsicCandidate,
|
||||
_jdk_internal_vm_annotation_Contended,
|
||||
_field_Stable,
|
||||
_jdk_internal_vm_annotation_ReservedStackAccess,
|
||||
_annotation_LIMIT
|
||||
};
|
||||
const Location _location;
|
||||
@ -2016,6 +2017,11 @@ AnnotationCollector::annotation_index(const ClassLoaderData* loader_data,
|
||||
}
|
||||
return _jdk_internal_vm_annotation_Contended;
|
||||
}
|
||||
case vmSymbols::VM_SYMBOL_ENUM_NAME(jdk_internal_vm_annotation_ReservedStackAccess_signature): {
|
||||
if (_location != _in_method) break; // only allow for methods
|
||||
if (RestrictReservedStack && !privileged) break; // honor privileges
|
||||
return _jdk_internal_vm_annotation_ReservedStackAccess;
|
||||
}
|
||||
default: {
|
||||
break;
|
||||
}
|
||||
@ -2051,6 +2057,8 @@ void MethodAnnotationCollector::apply_to(methodHandle m) {
|
||||
m->set_hidden(true);
|
||||
if (has_annotation(_method_HotSpotIntrinsicCandidate) && !m->is_synthetic())
|
||||
m->set_intrinsic_candidate(true);
|
||||
if (has_annotation(_jdk_internal_vm_annotation_ReservedStackAccess))
|
||||
m->set_has_reserved_stack_access(true);
|
||||
}
|
||||
|
||||
void ClassFileParser::ClassAnnotationCollector::apply_to(InstanceKlass* ik) {
|
||||
|
@ -212,6 +212,7 @@
|
||||
template(java_util_concurrent_atomic_AtomicLongFieldUpdater_LockedUpdater, "java/util/concurrent/atomic/AtomicLongFieldUpdater$LockedUpdater") \
|
||||
template(java_util_concurrent_atomic_AtomicReferenceFieldUpdater_Impl, "java/util/concurrent/atomic/AtomicReferenceFieldUpdater$AtomicReferenceFieldUpdaterImpl") \
|
||||
template(jdk_internal_vm_annotation_Contended_signature, "Ljdk/internal/vm/annotation/Contended;") \
|
||||
template(jdk_internal_vm_annotation_ReservedStackAccess_signature, "Ljdk/internal/vm/annotation/ReservedStackAccess;") \
|
||||
\
|
||||
/* class symbols needed by intrinsics */ \
|
||||
VM_INTRINSICS_DO(VM_INTRINSIC_IGNORE, template, VM_SYMBOL_IGNORE, VM_SYMBOL_IGNORE, VM_ALIAS_IGNORE) \
|
||||
|
@ -26,6 +26,7 @@
|
||||
#define SHARE_VM_GC_CMS_ALLOCATIONSTATS_HPP
|
||||
|
||||
#include "gc/shared/gcUtil.hpp"
|
||||
#include "logging/log.hpp"
|
||||
#include "memory/allocation.hpp"
|
||||
#include "utilities/globalDefinitions.hpp"
|
||||
#include "utilities/macros.hpp"
|
||||
@ -119,11 +120,9 @@ class AllocationStats VALUE_OBJ_CLASS_SPEC {
|
||||
ssize_t old_desired = _desired;
|
||||
float delta_ise = (CMSExtrapolateSweep ? intra_sweep_estimate : 0.0);
|
||||
_desired = (ssize_t)(new_rate * (inter_sweep_estimate + delta_ise));
|
||||
if (PrintFLSStatistics > 1) {
|
||||
gclog_or_tty->print_cr("demand: " SSIZE_FORMAT ", old_rate: %f, current_rate: %f, "
|
||||
"new_rate: %f, old_desired: " SSIZE_FORMAT ", new_desired: " SSIZE_FORMAT,
|
||||
demand, old_rate, rate, new_rate, old_desired, _desired);
|
||||
}
|
||||
log_trace(gc, freelist)("demand: " SSIZE_FORMAT ", old_rate: %f, current_rate: %f, "
|
||||
"new_rate: %f, old_desired: " SSIZE_FORMAT ", new_desired: " SSIZE_FORMAT,
|
||||
demand, old_rate, rate, new_rate, old_desired, _desired);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -400,17 +400,16 @@ void CompactibleFreeListSpace::print_on(outputStream* st) const {
|
||||
|
||||
void CompactibleFreeListSpace::print_indexed_free_lists(outputStream* st)
|
||||
const {
|
||||
reportIndexedFreeListStatistics();
|
||||
gclog_or_tty->print_cr("Layout of Indexed Freelists");
|
||||
gclog_or_tty->print_cr("---------------------------");
|
||||
reportIndexedFreeListStatistics(st);
|
||||
st->print_cr("Layout of Indexed Freelists");
|
||||
st->print_cr("---------------------------");
|
||||
AdaptiveFreeList<FreeChunk>::print_labels_on(st, "size");
|
||||
for (size_t i = IndexSetStart; i < IndexSetSize; i += IndexSetStride) {
|
||||
_indexedFreeList[i].print_on(gclog_or_tty);
|
||||
for (FreeChunk* fc = _indexedFreeList[i].head(); fc != NULL;
|
||||
fc = fc->next()) {
|
||||
gclog_or_tty->print_cr("\t[" PTR_FORMAT "," PTR_FORMAT ") %s",
|
||||
p2i(fc), p2i((HeapWord*)fc + i),
|
||||
fc->cantCoalesce() ? "\t CC" : "");
|
||||
_indexedFreeList[i].print_on(st);
|
||||
for (FreeChunk* fc = _indexedFreeList[i].head(); fc != NULL; fc = fc->next()) {
|
||||
st->print_cr("\t[" PTR_FORMAT "," PTR_FORMAT ") %s",
|
||||
p2i(fc), p2i((HeapWord*)fc + i),
|
||||
fc->cantCoalesce() ? "\t CC" : "");
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -422,7 +421,7 @@ const {
|
||||
|
||||
void CompactibleFreeListSpace::print_dictionary_free_lists(outputStream* st)
|
||||
const {
|
||||
_dictionary->report_statistics();
|
||||
_dictionary->report_statistics(st);
|
||||
st->print_cr("Layout of Freelists in Tree");
|
||||
st->print_cr("---------------------------");
|
||||
_dictionary->print_free_lists(st);
|
||||
@ -472,54 +471,58 @@ size_t BlkPrintingClosure::do_blk(HeapWord* addr) {
|
||||
return sz;
|
||||
}
|
||||
|
||||
void CompactibleFreeListSpace::dump_at_safepoint_with_locks(CMSCollector* c,
|
||||
outputStream* st) {
|
||||
st->print_cr("\n=========================");
|
||||
void CompactibleFreeListSpace::dump_at_safepoint_with_locks(CMSCollector* c, outputStream* st) {
|
||||
st->print_cr("=========================");
|
||||
st->print_cr("Block layout in CMS Heap:");
|
||||
st->print_cr("=========================");
|
||||
BlkPrintingClosure bpcl(c, this, c->markBitMap(), st);
|
||||
blk_iterate(&bpcl);
|
||||
|
||||
st->print_cr("\n=======================================");
|
||||
st->print_cr("=======================================");
|
||||
st->print_cr("Order & Layout of Promotion Info Blocks");
|
||||
st->print_cr("=======================================");
|
||||
print_promo_info_blocks(st);
|
||||
|
||||
st->print_cr("\n===========================");
|
||||
st->print_cr("===========================");
|
||||
st->print_cr("Order of Indexed Free Lists");
|
||||
st->print_cr("=========================");
|
||||
print_indexed_free_lists(st);
|
||||
|
||||
st->print_cr("\n=================================");
|
||||
st->print_cr("=================================");
|
||||
st->print_cr("Order of Free Lists in Dictionary");
|
||||
st->print_cr("=================================");
|
||||
print_dictionary_free_lists(st);
|
||||
}
|
||||
|
||||
|
||||
void CompactibleFreeListSpace::reportFreeListStatistics() const {
|
||||
void CompactibleFreeListSpace::reportFreeListStatistics(const char* title) const {
|
||||
assert_lock_strong(&_freelistLock);
|
||||
assert(PrintFLSStatistics != 0, "Reporting error");
|
||||
_dictionary->report_statistics();
|
||||
if (PrintFLSStatistics > 1) {
|
||||
reportIndexedFreeListStatistics();
|
||||
LogHandle(gc, freelist, stats) log;
|
||||
if (!log.is_debug()) {
|
||||
return;
|
||||
}
|
||||
log.debug("%s", title);
|
||||
_dictionary->report_statistics(log.debug_stream());
|
||||
if (log.is_trace()) {
|
||||
ResourceMark rm;
|
||||
reportIndexedFreeListStatistics(log.trace_stream());
|
||||
size_t total_size = totalSizeInIndexedFreeLists() +
|
||||
_dictionary->total_chunk_size(DEBUG_ONLY(freelistLock()));
|
||||
gclog_or_tty->print(" free=" SIZE_FORMAT " frag=%1.4f\n", total_size, flsFrag());
|
||||
log.trace(" free=" SIZE_FORMAT " frag=%1.4f", total_size, flsFrag());
|
||||
}
|
||||
}
|
||||
|
||||
void CompactibleFreeListSpace::reportIndexedFreeListStatistics() const {
|
||||
void CompactibleFreeListSpace::reportIndexedFreeListStatistics(outputStream* st) const {
|
||||
assert_lock_strong(&_freelistLock);
|
||||
gclog_or_tty->print("Statistics for IndexedFreeLists:\n"
|
||||
"--------------------------------\n");
|
||||
st->print_cr("Statistics for IndexedFreeLists:");
|
||||
st->print_cr("--------------------------------");
|
||||
size_t total_size = totalSizeInIndexedFreeLists();
|
||||
size_t free_blocks = numFreeBlocksInIndexedFreeLists();
|
||||
gclog_or_tty->print("Total Free Space: " SIZE_FORMAT "\n", total_size);
|
||||
gclog_or_tty->print("Max Chunk Size: " SIZE_FORMAT "\n", maxChunkSizeInIndexedFreeLists());
|
||||
gclog_or_tty->print("Number of Blocks: " SIZE_FORMAT "\n", free_blocks);
|
||||
size_t free_blocks = numFreeBlocksInIndexedFreeLists();
|
||||
st->print_cr("Total Free Space: " SIZE_FORMAT, total_size);
|
||||
st->print_cr("Max Chunk Size: " SIZE_FORMAT, maxChunkSizeInIndexedFreeLists());
|
||||
st->print_cr("Number of Blocks: " SIZE_FORMAT, free_blocks);
|
||||
if (free_blocks != 0) {
|
||||
gclog_or_tty->print("Av. Block Size: " SIZE_FORMAT "\n", total_size/free_blocks);
|
||||
st->print_cr("Av. Block Size: " SIZE_FORMAT, total_size/free_blocks);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1824,10 +1827,7 @@ CompactibleFreeListSpace::sweep_completed() {
|
||||
void
|
||||
CompactibleFreeListSpace::gc_prologue() {
|
||||
assert_locked();
|
||||
if (PrintFLSStatistics != 0) {
|
||||
gclog_or_tty->print("Before GC:\n");
|
||||
reportFreeListStatistics();
|
||||
}
|
||||
reportFreeListStatistics("Before GC:");
|
||||
refillLinearAllocBlocksIfNeeded();
|
||||
}
|
||||
|
||||
@ -1837,11 +1837,7 @@ CompactibleFreeListSpace::gc_epilogue() {
|
||||
assert(_promoInfo.noPromotions(), "_promoInfo inconsistency");
|
||||
_promoInfo.stopTrackingPromotions();
|
||||
repairLinearAllocationBlocks();
|
||||
// Print Space's stats
|
||||
if (PrintFLSStatistics != 0) {
|
||||
gclog_or_tty->print("After GC:\n");
|
||||
reportFreeListStatistics();
|
||||
}
|
||||
reportFreeListStatistics("After GC:");
|
||||
}
|
||||
|
||||
// Iteration support, mostly delegated from a CMS generation
|
||||
@ -2014,9 +2010,7 @@ void CompactibleFreeListSpace::beginSweepFLCensus(
|
||||
size_t i;
|
||||
for (i = IndexSetStart; i < IndexSetSize; i += IndexSetStride) {
|
||||
AdaptiveFreeList<FreeChunk>* fl = &_indexedFreeList[i];
|
||||
if (PrintFLSStatistics > 1) {
|
||||
gclog_or_tty->print("size[" SIZE_FORMAT "] : ", i);
|
||||
}
|
||||
log_trace(gc, freelist)("size[" SIZE_FORMAT "] : ", i);
|
||||
fl->compute_desired(inter_sweep_current, inter_sweep_estimate, intra_sweep_estimate);
|
||||
fl->set_coal_desired((ssize_t)((double)fl->desired() * CMSSmallCoalSurplusPercent));
|
||||
fl->set_before_sweep(fl->count());
|
||||
@ -2065,16 +2059,10 @@ void CompactibleFreeListSpace::clearFLCensus() {
|
||||
}
|
||||
|
||||
void CompactibleFreeListSpace::endSweepFLCensus(size_t sweep_count) {
|
||||
if (PrintFLSStatistics > 0) {
|
||||
HeapWord* largestAddr = (HeapWord*) dictionary()->find_largest_dict();
|
||||
gclog_or_tty->print_cr("CMS: Large block " PTR_FORMAT,
|
||||
p2i(largestAddr));
|
||||
}
|
||||
log_debug(gc, freelist)("CMS: Large block " PTR_FORMAT, p2i(dictionary()->find_largest_dict()));
|
||||
setFLSurplus();
|
||||
setFLHints();
|
||||
if (PrintGC && PrintFLSCensus > 0) {
|
||||
printFLCensus(sweep_count);
|
||||
}
|
||||
printFLCensus(sweep_count);
|
||||
clearFLCensus();
|
||||
assert_locked();
|
||||
_dictionary->end_sweep_dict_census(CMSLargeSplitSurplusPercent);
|
||||
@ -2213,14 +2201,15 @@ class VerifyAllBlksClosure: public BlkClosure {
|
||||
}
|
||||
}
|
||||
if (res == 0) {
|
||||
gclog_or_tty->print_cr("Livelock: no rank reduction!");
|
||||
gclog_or_tty->print_cr(
|
||||
" Current: addr = " PTR_FORMAT ", size = " SIZE_FORMAT ", obj = %s, live = %s \n"
|
||||
" Previous: addr = " PTR_FORMAT ", size = " SIZE_FORMAT ", obj = %s, live = %s \n",
|
||||
LogHandle(gc, verify) log;
|
||||
log.info("Livelock: no rank reduction!");
|
||||
log.info(" Current: addr = " PTR_FORMAT ", size = " SIZE_FORMAT ", obj = %s, live = %s \n"
|
||||
" Previous: addr = " PTR_FORMAT ", size = " SIZE_FORMAT ", obj = %s, live = %s \n",
|
||||
p2i(addr), res, was_obj ?"true":"false", was_live ?"true":"false",
|
||||
p2i(_last_addr), _last_size, _last_was_obj?"true":"false", _last_was_live?"true":"false");
|
||||
_sp->print_on(gclog_or_tty);
|
||||
guarantee(false, "Seppuku!");
|
||||
ResourceMark rm;
|
||||
_sp->print_on(log.info_stream());
|
||||
guarantee(false, "Verification failed.");
|
||||
}
|
||||
_last_addr = addr;
|
||||
_last_size = res;
|
||||
@ -2386,17 +2375,23 @@ void CompactibleFreeListSpace::check_free_list_consistency() const {
|
||||
|
||||
void CompactibleFreeListSpace::printFLCensus(size_t sweep_count) const {
|
||||
assert_lock_strong(&_freelistLock);
|
||||
LogHandle(gc, freelist, census) log;
|
||||
if (!log.is_debug()) {
|
||||
return;
|
||||
}
|
||||
AdaptiveFreeList<FreeChunk> total;
|
||||
gclog_or_tty->print("end sweep# " SIZE_FORMAT "\n", sweep_count);
|
||||
AdaptiveFreeList<FreeChunk>::print_labels_on(gclog_or_tty, "size");
|
||||
log.debug("end sweep# " SIZE_FORMAT, sweep_count);
|
||||
ResourceMark rm;
|
||||
outputStream* out = log.debug_stream();
|
||||
AdaptiveFreeList<FreeChunk>::print_labels_on(out, "size");
|
||||
size_t total_free = 0;
|
||||
for (size_t i = IndexSetStart; i < IndexSetSize; i += IndexSetStride) {
|
||||
const AdaptiveFreeList<FreeChunk> *fl = &_indexedFreeList[i];
|
||||
total_free += fl->count() * fl->size();
|
||||
if (i % (40*IndexSetStride) == 0) {
|
||||
AdaptiveFreeList<FreeChunk>::print_labels_on(gclog_or_tty, "size");
|
||||
AdaptiveFreeList<FreeChunk>::print_labels_on(out, "size");
|
||||
}
|
||||
fl->print_on(gclog_or_tty);
|
||||
fl->print_on(out);
|
||||
total.set_bfr_surp( total.bfr_surp() + fl->bfr_surp() );
|
||||
total.set_surplus( total.surplus() + fl->surplus() );
|
||||
total.set_desired( total.desired() + fl->desired() );
|
||||
@ -2408,14 +2403,13 @@ void CompactibleFreeListSpace::printFLCensus(size_t sweep_count) const {
|
||||
total.set_split_births(total.split_births() + fl->split_births());
|
||||
total.set_split_deaths(total.split_deaths() + fl->split_deaths());
|
||||
}
|
||||
total.print_on(gclog_or_tty, "TOTAL");
|
||||
gclog_or_tty->print_cr("Total free in indexed lists "
|
||||
SIZE_FORMAT " words", total_free);
|
||||
gclog_or_tty->print("growth: %8.5f deficit: %8.5f\n",
|
||||
(double)(total.split_births()+total.coal_births()-total.split_deaths()-total.coal_deaths())/
|
||||
(total.prev_sweep() != 0 ? (double)total.prev_sweep() : 1.0),
|
||||
(double)(total.desired() - total.count())/(total.desired() != 0 ? (double)total.desired() : 1.0));
|
||||
_dictionary->print_dict_census();
|
||||
total.print_on(out, "TOTAL");
|
||||
log.debug("Total free in indexed lists " SIZE_FORMAT " words", total_free);
|
||||
log.debug("growth: %8.5f deficit: %8.5f",
|
||||
(double)(total.split_births()+total.coal_births()-total.split_deaths()-total.coal_deaths())/
|
||||
(total.prev_sweep() != 0 ? (double)total.prev_sweep() : 1.0),
|
||||
(double)(total.desired() - total.count())/(total.desired() != 0 ? (double)total.desired() : 1.0));
|
||||
_dictionary->print_dict_census(out);
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
@ -2544,10 +2538,7 @@ void CFLS_LAB::compute_desired_plab_size() {
|
||||
// Reset counters for next round
|
||||
_global_num_workers[i] = 0;
|
||||
_global_num_blocks[i] = 0;
|
||||
if (PrintOldPLAB) {
|
||||
gclog_or_tty->print_cr("[" SIZE_FORMAT "]: " SIZE_FORMAT,
|
||||
i, (size_t)_blocks_to_claim[i].average());
|
||||
}
|
||||
log_trace(gc, plab)("[" SIZE_FORMAT "]: " SIZE_FORMAT, i, (size_t)_blocks_to_claim[i].average());
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -2584,10 +2575,8 @@ void CFLS_LAB::retire(int tid) {
|
||||
_indexedFreeList[i].set_size(i);
|
||||
}
|
||||
}
|
||||
if (PrintOldPLAB) {
|
||||
gclog_or_tty->print_cr("%d[" SIZE_FORMAT "]: " SIZE_FORMAT "/" SIZE_FORMAT "/" SIZE_FORMAT,
|
||||
tid, i, num_retire, _num_blocks[i], (size_t)_blocks_to_claim[i].average());
|
||||
}
|
||||
log_trace(gc, plab)("%d[" SIZE_FORMAT "]: " SIZE_FORMAT "/" SIZE_FORMAT "/" SIZE_FORMAT,
|
||||
tid, i, num_retire, _num_blocks[i], (size_t)_blocks_to_claim[i].average());
|
||||
// Reset stats for next round
|
||||
_num_blocks[i] = 0;
|
||||
}
|
||||
|
@ -29,6 +29,7 @@
|
||||
#include "gc/cms/promotionInfo.hpp"
|
||||
#include "gc/shared/blockOffsetTable.hpp"
|
||||
#include "gc/shared/space.hpp"
|
||||
#include "logging/log.hpp"
|
||||
#include "memory/binaryTreeDictionary.hpp"
|
||||
#include "memory/freeList.hpp"
|
||||
|
||||
@ -275,8 +276,8 @@ class CompactibleFreeListSpace: public CompactibleSpace {
|
||||
void verify_objects_initialized() const;
|
||||
|
||||
// Statistics reporting helper functions
|
||||
void reportFreeListStatistics() const;
|
||||
void reportIndexedFreeListStatistics() const;
|
||||
void reportFreeListStatistics(const char* title) const;
|
||||
void reportIndexedFreeListStatistics(outputStream* st) const;
|
||||
size_t maxChunkSizeInIndexedFreeLists() const;
|
||||
size_t numFreeBlocksInIndexedFreeLists() const;
|
||||
// Accessor
|
||||
@ -450,11 +451,9 @@ class CompactibleFreeListSpace: public CompactibleSpace {
|
||||
void save_sweep_limit() {
|
||||
_sweep_limit = BlockOffsetArrayUseUnallocatedBlock ?
|
||||
unallocated_block() : end();
|
||||
if (CMSTraceSweeper) {
|
||||
gclog_or_tty->print_cr(">>>>> Saving sweep limit " PTR_FORMAT
|
||||
" for space [" PTR_FORMAT "," PTR_FORMAT ") <<<<<<",
|
||||
p2i(_sweep_limit), p2i(bottom()), p2i(end()));
|
||||
}
|
||||
log_develop_trace(gc, sweep)(">>>>> Saving sweep limit " PTR_FORMAT
|
||||
" for space [" PTR_FORMAT "," PTR_FORMAT ") <<<<<<",
|
||||
p2i(_sweep_limit), p2i(bottom()), p2i(end()));
|
||||
}
|
||||
NOT_PRODUCT(
|
||||
void clear_sweep_limit() { _sweep_limit = NULL; }
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -35,6 +35,7 @@
|
||||
#include "gc/shared/generationCounters.hpp"
|
||||
#include "gc/shared/space.hpp"
|
||||
#include "gc/shared/taskqueue.hpp"
|
||||
#include "logging/log.hpp"
|
||||
#include "memory/freeBlockDictionary.hpp"
|
||||
#include "memory/iterator.hpp"
|
||||
#include "memory/virtualspace.hpp"
|
||||
@ -308,9 +309,8 @@ class ChunkArray: public CHeapObj<mtGC> {
|
||||
|
||||
void reset() {
|
||||
_index = 0;
|
||||
if (_overflows > 0 && PrintCMSStatistics > 1) {
|
||||
warning("CMS: ChunkArray[" SIZE_FORMAT "] overflowed " SIZE_FORMAT " times",
|
||||
_capacity, _overflows);
|
||||
if (_overflows > 0) {
|
||||
log_trace(gc)("CMS: ChunkArray[" SIZE_FORMAT "] overflowed " SIZE_FORMAT " times", _capacity, _overflows);
|
||||
}
|
||||
_overflows = 0;
|
||||
}
|
||||
@ -451,7 +451,7 @@ class CMSStats VALUE_OBJ_CLASS_SPEC {
|
||||
|
||||
// Debugging.
|
||||
void print_on(outputStream* st) const PRODUCT_RETURN;
|
||||
void print() const { print_on(gclog_or_tty); }
|
||||
void print() const { print_on(tty); }
|
||||
};
|
||||
|
||||
// A closure related to weak references processing which
|
||||
@ -935,7 +935,7 @@ class CMSCollector: public CHeapObj<mtGC> {
|
||||
void startTimer() { assert(!_timer.is_active(), "Error"); _timer.start(); }
|
||||
void stopTimer() { assert( _timer.is_active(), "Error"); _timer.stop(); }
|
||||
void resetTimer() { assert(!_timer.is_active(), "Error"); _timer.reset(); }
|
||||
double timerValue() { assert(!_timer.is_active(), "Error"); return _timer.seconds(); }
|
||||
jlong timerTicks() { assert(!_timer.is_active(), "Error"); return _timer.ticks(); }
|
||||
|
||||
int yields() { return _numYields; }
|
||||
void resetYields() { _numYields = 0; }
|
||||
@ -961,7 +961,7 @@ class CMSCollector: public CHeapObj<mtGC> {
|
||||
|
||||
// Debugging
|
||||
void verify();
|
||||
bool verify_after_remark(bool silent = VerifySilently);
|
||||
bool verify_after_remark();
|
||||
void verify_ok_to_terminate() const PRODUCT_RETURN;
|
||||
void verify_work_stacks_empty() const PRODUCT_RETURN;
|
||||
void verify_overflow_empty() const PRODUCT_RETURN;
|
||||
@ -1234,7 +1234,6 @@ class ConcurrentMarkSweepGeneration: public CardGeneration {
|
||||
const char* name() const;
|
||||
virtual const char* short_name() const { return "CMS"; }
|
||||
void print() const;
|
||||
void printOccupancy(const char* s);
|
||||
|
||||
// Resize the generation after a compacting GC. The
|
||||
// generation can be treated as a contiguous space
|
||||
|
@ -34,7 +34,7 @@
|
||||
#include "gc/shared/gcHeapSummary.hpp"
|
||||
#include "gc/shared/gcTimer.hpp"
|
||||
#include "gc/shared/gcTrace.hpp"
|
||||
#include "gc/shared/gcTraceTime.hpp"
|
||||
#include "gc/shared/gcTraceTime.inline.hpp"
|
||||
#include "gc/shared/genCollectedHeap.hpp"
|
||||
#include "gc/shared/genOopClosures.inline.hpp"
|
||||
#include "gc/shared/generation.hpp"
|
||||
@ -45,6 +45,7 @@
|
||||
#include "gc/shared/strongRootsScope.hpp"
|
||||
#include "gc/shared/taskqueue.inline.hpp"
|
||||
#include "gc/shared/workgroup.hpp"
|
||||
#include "logging/log.hpp"
|
||||
#include "memory/resourceArea.hpp"
|
||||
#include "oops/objArrayOop.hpp"
|
||||
#include "oops/oop.inline.hpp"
|
||||
@ -270,9 +271,9 @@ void ParScanThreadState::undo_alloc_in_to_space(HeapWord* obj, size_t word_sz) {
|
||||
}
|
||||
|
||||
void ParScanThreadState::print_promotion_failure_size() {
|
||||
if (_promotion_failed_info.has_failed() && PrintPromotionFailure) {
|
||||
gclog_or_tty->print(" (%d: promotion failure size = " SIZE_FORMAT ") ",
|
||||
_thread_num, _promotion_failed_info.first_size());
|
||||
if (_promotion_failed_info.has_failed()) {
|
||||
log_trace(gc, promotion)(" (%d: promotion failure size = " SIZE_FORMAT ") ",
|
||||
_thread_num, _promotion_failed_info.first_size());
|
||||
}
|
||||
}
|
||||
|
||||
@ -298,11 +299,11 @@ public:
|
||||
|
||||
#if TASKQUEUE_STATS
|
||||
static void
|
||||
print_termination_stats_hdr(outputStream* const st = gclog_or_tty);
|
||||
void print_termination_stats(outputStream* const st = gclog_or_tty);
|
||||
print_termination_stats_hdr(outputStream* const st);
|
||||
void print_termination_stats();
|
||||
static void
|
||||
print_taskqueue_stats_hdr(outputStream* const st = gclog_or_tty);
|
||||
void print_taskqueue_stats(outputStream* const st = gclog_or_tty);
|
||||
print_taskqueue_stats_hdr(outputStream* const st);
|
||||
void print_taskqueue_stats();
|
||||
void reset_stats();
|
||||
#endif // TASKQUEUE_STATS
|
||||
|
||||
@ -383,7 +384,15 @@ void ParScanThreadStateSet::print_termination_stats_hdr(outputStream* const st)
|
||||
st->print_raw_cr("--- --------- --------- ------ --------- ------ --------");
|
||||
}
|
||||
|
||||
void ParScanThreadStateSet::print_termination_stats(outputStream* const st) {
|
||||
void ParScanThreadStateSet::print_termination_stats() {
|
||||
LogHandle(gc, task, stats) log;
|
||||
if (!log.is_debug()) {
|
||||
return;
|
||||
}
|
||||
|
||||
ResourceMark rm;
|
||||
outputStream* st = log.debug_stream();
|
||||
|
||||
print_termination_stats_hdr(st);
|
||||
|
||||
for (int i = 0; i < length(); ++i) {
|
||||
@ -404,7 +413,13 @@ void ParScanThreadStateSet::print_taskqueue_stats_hdr(outputStream* const st) {
|
||||
st->print_raw("--- "); TaskQueueStats::print_header(2, st); st->cr();
|
||||
}
|
||||
|
||||
void ParScanThreadStateSet::print_taskqueue_stats(outputStream* const st) {
|
||||
void ParScanThreadStateSet::print_taskqueue_stats() {
|
||||
if (!develop_log_is_enabled(Trace, gc, task, stats)) {
|
||||
return;
|
||||
}
|
||||
LogHandle(gc, task, stats) log;
|
||||
ResourceMark rm;
|
||||
outputStream* st = log.trace_stream();
|
||||
print_taskqueue_stats_hdr(st);
|
||||
|
||||
TaskQueueStats totals;
|
||||
@ -823,9 +838,7 @@ void ParNewGeneration::handle_promotion_failed(GenCollectedHeap* gch, ParScanThr
|
||||
_promo_failure_scan_stack.clear(true); // Clear cached segments.
|
||||
|
||||
remove_forwarding_pointers();
|
||||
if (PrintGCDetails) {
|
||||
gclog_or_tty->print(" (promotion failed)");
|
||||
}
|
||||
log_info(gc, promotion)("Promotion failed");
|
||||
// All the spaces are in play for mark-sweep.
|
||||
swap_spaces(); // Make life simpler for CMS || rescan; see 6483690.
|
||||
from()->set_next_compaction_space(to());
|
||||
@ -882,9 +895,7 @@ void ParNewGeneration::collect(bool full,
|
||||
size_policy->minor_collection_begin();
|
||||
}
|
||||
|
||||
GCTraceTime t1(GCCauseString("GC", gch->gc_cause()), PrintGC && !PrintGCDetails, true, NULL);
|
||||
// Capture heap used before collection (for printing).
|
||||
size_t gch_prev_used = gch->used();
|
||||
GCTraceTime(Trace, gc) t1("ParNew", NULL, gch->gc_cause());
|
||||
|
||||
age_table()->clear();
|
||||
to()->clear(SpaceDecorator::Mangle);
|
||||
@ -990,12 +1001,8 @@ void ParNewGeneration::collect(bool full,
|
||||
plab_stats()->adjust_desired_plab_sz();
|
||||
}
|
||||
|
||||
if (PrintGC && !PrintGCDetails) {
|
||||
gch->print_heap_change(gch_prev_used);
|
||||
}
|
||||
|
||||
TASKQUEUE_STATS_ONLY(if (PrintTerminationStats) thread_state_set.print_termination_stats());
|
||||
TASKQUEUE_STATS_ONLY(if (PrintTaskqueue) thread_state_set.print_taskqueue_stats());
|
||||
TASKQUEUE_STATS_ONLY(thread_state_set.print_termination_stats());
|
||||
TASKQUEUE_STATS_ONLY(thread_state_set.print_taskqueue_stats());
|
||||
|
||||
if (UseAdaptiveSizePolicy) {
|
||||
size_policy->minor_collection_end(gch->gc_cause());
|
||||
@ -1150,11 +1157,9 @@ oop ParNewGeneration::copy_to_survivor_space(ParScanThreadState* par_scan_state,
|
||||
|
||||
// This code must come after the CAS test, or it will print incorrect
|
||||
// information.
|
||||
if (TraceScavenge) {
|
||||
gclog_or_tty->print_cr("{%s %s " PTR_FORMAT " -> " PTR_FORMAT " (%d)}",
|
||||
is_in_reserved(new_obj) ? "copying" : "tenuring",
|
||||
new_obj->klass()->internal_name(), p2i(old), p2i(new_obj), new_obj->size());
|
||||
}
|
||||
log_develop_trace(gc, scavenge)("{%s %s " PTR_FORMAT " -> " PTR_FORMAT " (%d)}",
|
||||
is_in_reserved(new_obj) ? "copying" : "tenuring",
|
||||
new_obj->klass()->internal_name(), p2i(old), p2i(new_obj), new_obj->size());
|
||||
|
||||
if (forward_ptr == NULL) {
|
||||
oop obj_to_push = new_obj;
|
||||
@ -1176,9 +1181,7 @@ oop ParNewGeneration::copy_to_survivor_space(ParScanThreadState* par_scan_state,
|
||||
)
|
||||
if (simulate_overflow || !par_scan_state->work_queue()->push(obj_to_push)) {
|
||||
// Add stats for overflow pushes.
|
||||
if (Verbose && PrintGCDetails) {
|
||||
gclog_or_tty->print("queue overflow!\n");
|
||||
}
|
||||
log_develop_trace(gc)("Queue Overflow");
|
||||
push_on_overflow_list(old, par_scan_state);
|
||||
TASKQUEUE_STATS_ONLY(par_scan_state->taskqueue_stats().record_overflow(0));
|
||||
}
|
||||
|
@ -30,6 +30,7 @@
|
||||
#include "gc/shared/cardTableRS.hpp"
|
||||
#include "gc/shared/genCollectedHeap.hpp"
|
||||
#include "gc/shared/genOopClosures.inline.hpp"
|
||||
#include "logging/log.hpp"
|
||||
|
||||
template <class T> inline void ParScanWeakRefClosure::do_oop_work(T* p) {
|
||||
assert (!oopDesc::is_null(*p), "null weak reference?");
|
||||
@ -108,11 +109,9 @@ inline void ParScanClosure::do_oop_work(T* p,
|
||||
if (m->is_marked()) { // Contains forwarding pointer.
|
||||
new_obj = ParNewGeneration::real_forwardee(obj);
|
||||
oopDesc::encode_store_heap_oop_not_null(p, new_obj);
|
||||
if (TraceScavenge) {
|
||||
gclog_or_tty->print_cr("{%s %s ( " PTR_FORMAT " ) " PTR_FORMAT " -> " PTR_FORMAT " (%d)}",
|
||||
"forwarded ",
|
||||
new_obj->klass()->internal_name(), p2i(p), p2i((void *)obj), p2i((void *)new_obj), new_obj->size());
|
||||
}
|
||||
log_develop_trace(gc, scavenge)("{%s %s ( " PTR_FORMAT " ) " PTR_FORMAT " -> " PTR_FORMAT " (%d)}",
|
||||
"forwarded ",
|
||||
new_obj->klass()->internal_name(), p2i(p), p2i((void *)obj), p2i((void *)new_obj), new_obj->size());
|
||||
} else {
|
||||
size_t obj_sz = obj->size_given_klass(objK);
|
||||
new_obj = _g->copy_to_survivor_space(_par_scan_state, obj, obj_sz, m);
|
||||
|
@ -132,7 +132,7 @@ class SpoolBlock: public FreeChunk {
|
||||
}
|
||||
|
||||
void print_on(outputStream* st) const;
|
||||
void print() const { print_on(gclog_or_tty); }
|
||||
void print() const { print_on(tty); }
|
||||
};
|
||||
|
||||
class PromotionInfo VALUE_OBJ_CLASS_SPEC {
|
||||
|
@ -28,7 +28,7 @@
|
||||
#include "gc/cms/vmCMSOperations.hpp"
|
||||
#include "gc/shared/gcLocker.inline.hpp"
|
||||
#include "gc/shared/gcTimer.hpp"
|
||||
#include "gc/shared/gcTraceTime.hpp"
|
||||
#include "gc/shared/gcTraceTime.inline.hpp"
|
||||
#include "gc/shared/isGCActiveMark.hpp"
|
||||
#include "runtime/interfaceSupport.hpp"
|
||||
#include "runtime/os.hpp"
|
||||
@ -58,7 +58,7 @@ void VM_CMS_Operation::release_and_notify_pending_list_lock() {
|
||||
void VM_CMS_Operation::verify_before_gc() {
|
||||
if (VerifyBeforeGC &&
|
||||
GenCollectedHeap::heap()->total_collections() >= VerifyGCStartAt) {
|
||||
GCTraceTime tm("Verify Before", false, false, _collector->_gc_timer_cm);
|
||||
GCTraceTime(Info, gc, verify) tm("Verify Before", _collector->_gc_timer_cm);
|
||||
HandleMark hm;
|
||||
FreelistLocker x(_collector);
|
||||
MutexLockerEx y(_collector->bitMapLock(), Mutex::_no_safepoint_check_flag);
|
||||
@ -70,7 +70,7 @@ void VM_CMS_Operation::verify_before_gc() {
|
||||
void VM_CMS_Operation::verify_after_gc() {
|
||||
if (VerifyAfterGC &&
|
||||
GenCollectedHeap::heap()->total_collections() >= VerifyGCStartAt) {
|
||||
GCTraceTime tm("Verify After", false, false, _collector->_gc_timer_cm);
|
||||
GCTraceTime(Info, gc, verify) tm("Verify After", _collector->_gc_timer_cm);
|
||||
HandleMark hm;
|
||||
FreelistLocker x(_collector);
|
||||
MutexLockerEx y(_collector->bitMapLock(), Mutex::_no_safepoint_check_flag);
|
||||
|
@ -26,7 +26,6 @@
|
||||
#include "gc/g1/collectionSetChooser.hpp"
|
||||
#include "gc/g1/g1CollectedHeap.inline.hpp"
|
||||
#include "gc/g1/g1CollectorPolicy.hpp"
|
||||
#include "gc/g1/g1ErgoVerbose.hpp"
|
||||
#include "gc/shared/space.inline.hpp"
|
||||
#include "runtime/atomic.inline.hpp"
|
||||
|
||||
@ -136,8 +135,8 @@ void CollectionSetChooser::sort_regions() {
|
||||
assert(regions_at(i) != NULL, "Should be true by sorting!");
|
||||
}
|
||||
#endif // ASSERT
|
||||
if (G1PrintRegionLivenessInfo) {
|
||||
G1PrintRegionLivenessInfoClosure cl(gclog_or_tty, "Post-Sorting");
|
||||
if (log_is_enabled(Trace, gc, liveness)) {
|
||||
G1PrintRegionLivenessInfoClosure cl("Post-Sorting");
|
||||
for (uint i = 0; i < _end; ++i) {
|
||||
HeapRegion* r = regions_at(i);
|
||||
cl.doHeapRegion(r);
|
||||
|
@ -28,6 +28,7 @@
|
||||
#include "gc/g1/g1CollectedHeap.inline.hpp"
|
||||
#include "gc/g1/g1CollectorPolicy.hpp"
|
||||
#include "gc/g1/suspendibleThreadSet.hpp"
|
||||
#include "logging/log.hpp"
|
||||
#include "memory/resourceArea.hpp"
|
||||
#include "runtime/handles.inline.hpp"
|
||||
#include "runtime/mutexLocker.hpp"
|
||||
@ -88,11 +89,8 @@ bool ConcurrentG1RefineThread::is_active() {
|
||||
void ConcurrentG1RefineThread::activate() {
|
||||
MutexLockerEx x(_monitor, Mutex::_no_safepoint_check_flag);
|
||||
if (!is_primary()) {
|
||||
if (G1TraceConcRefinement) {
|
||||
DirtyCardQueueSet& dcqs = JavaThread::dirty_card_queue_set();
|
||||
gclog_or_tty->print_cr("G1-Refine-activated worker %d, on threshold %d, current %d",
|
||||
_worker_id, _threshold, (int)dcqs.completed_buffers_num());
|
||||
}
|
||||
log_debug(gc, refine)("G1-Refine-activated worker %d, on threshold %d, current %d",
|
||||
_worker_id, _threshold, JavaThread::dirty_card_queue_set().completed_buffers_num());
|
||||
set_active(true);
|
||||
} else {
|
||||
DirtyCardQueueSet& dcqs = JavaThread::dirty_card_queue_set();
|
||||
@ -104,11 +102,8 @@ void ConcurrentG1RefineThread::activate() {
|
||||
void ConcurrentG1RefineThread::deactivate() {
|
||||
MutexLockerEx x(_monitor, Mutex::_no_safepoint_check_flag);
|
||||
if (!is_primary()) {
|
||||
if (G1TraceConcRefinement) {
|
||||
DirtyCardQueueSet& dcqs = JavaThread::dirty_card_queue_set();
|
||||
gclog_or_tty->print_cr("G1-Refine-deactivated worker %d, off threshold %d, current %d",
|
||||
_worker_id, _deactivation_threshold, (int)dcqs.completed_buffers_num());
|
||||
}
|
||||
log_debug(gc, refine)("G1-Refine-deactivated worker %d, off threshold %d, current %d",
|
||||
_worker_id, _deactivation_threshold, JavaThread::dirty_card_queue_set().completed_buffers_num());
|
||||
set_active(false);
|
||||
} else {
|
||||
DirtyCardQueueSet& dcqs = JavaThread::dirty_card_queue_set();
|
||||
@ -174,9 +169,7 @@ void ConcurrentG1RefineThread::run_service() {
|
||||
}
|
||||
}
|
||||
|
||||
if (G1TraceConcRefinement) {
|
||||
gclog_or_tty->print_cr("G1-Refine-stop");
|
||||
}
|
||||
log_debug(gc, refine)("G1-Refine-stop");
|
||||
}
|
||||
|
||||
void ConcurrentG1RefineThread::stop() {
|
||||
@ -199,4 +192,4 @@ void ConcurrentG1RefineThread::stop() {
|
||||
void ConcurrentG1RefineThread::stop_service() {
|
||||
MutexLockerEx x(_monitor, Mutex::_no_safepoint_check_flag);
|
||||
_monitor->notify();
|
||||
}
|
||||
}
|
||||
|
@ -31,8 +31,6 @@
|
||||
#include "gc/g1/g1CollectedHeap.inline.hpp"
|
||||
#include "gc/g1/g1CollectorPolicy.hpp"
|
||||
#include "gc/g1/g1CollectorState.hpp"
|
||||
#include "gc/g1/g1ErgoVerbose.hpp"
|
||||
#include "gc/g1/g1Log.hpp"
|
||||
#include "gc/g1/g1OopClosures.inline.hpp"
|
||||
#include "gc/g1/g1RemSet.hpp"
|
||||
#include "gc/g1/g1StringDedup.hpp"
|
||||
@ -44,12 +42,13 @@
|
||||
#include "gc/shared/gcId.hpp"
|
||||
#include "gc/shared/gcTimer.hpp"
|
||||
#include "gc/shared/gcTrace.hpp"
|
||||
#include "gc/shared/gcTraceTime.hpp"
|
||||
#include "gc/shared/gcTraceTime.inline.hpp"
|
||||
#include "gc/shared/genOopClosures.inline.hpp"
|
||||
#include "gc/shared/referencePolicy.hpp"
|
||||
#include "gc/shared/strongRootsScope.hpp"
|
||||
#include "gc/shared/taskqueue.inline.hpp"
|
||||
#include "gc/shared/vmGCOperations.hpp"
|
||||
#include "logging/log.hpp"
|
||||
#include "memory/allocation.hpp"
|
||||
#include "memory/resourceArea.hpp"
|
||||
#include "oops/oop.inline.hpp"
|
||||
@ -232,9 +231,7 @@ void CMMarkStack::expand() {
|
||||
// Clear expansion flag
|
||||
_should_expand = false;
|
||||
if (_capacity == (jint) MarkStackSizeMax) {
|
||||
if (PrintGCDetails && Verbose) {
|
||||
gclog_or_tty->print_cr(" (benign) Can't expand marking stack capacity, at max size limit");
|
||||
}
|
||||
log_trace(gc)("(benign) Can't expand marking stack capacity, at max size limit");
|
||||
return;
|
||||
}
|
||||
// Double capacity if possible
|
||||
@ -254,12 +251,9 @@ void CMMarkStack::expand() {
|
||||
_index = 0;
|
||||
_capacity = new_capacity;
|
||||
} else {
|
||||
if (PrintGCDetails && Verbose) {
|
||||
// Failed to double capacity, continue;
|
||||
gclog_or_tty->print(" (benign) Failed to expand marking stack capacity from "
|
||||
SIZE_FORMAT "K to " SIZE_FORMAT "K",
|
||||
_capacity / K, new_capacity / K);
|
||||
}
|
||||
// Failed to double capacity, continue;
|
||||
log_trace(gc)("(benign) Failed to expand marking stack capacity from " SIZE_FORMAT "K to " SIZE_FORMAT "K",
|
||||
_capacity / K, new_capacity / K);
|
||||
}
|
||||
}
|
||||
|
||||
@ -848,10 +842,7 @@ void ConcurrentMark::enter_first_sync_barrier(uint worker_id) {
|
||||
// marking.
|
||||
reset_marking_state(true /* clear_overflow */);
|
||||
|
||||
if (G1Log::fine()) {
|
||||
gclog_or_tty->gclog_stamp();
|
||||
gclog_or_tty->print_cr("[GC concurrent-mark-reset-for-overflow]");
|
||||
}
|
||||
log_info(gc)("Concurrent Mark reset for overflow");
|
||||
}
|
||||
}
|
||||
|
||||
@ -987,8 +978,6 @@ public:
|
||||
};
|
||||
|
||||
void ConcurrentMark::scanRootRegions() {
|
||||
double scan_start = os::elapsedTime();
|
||||
|
||||
// Start of concurrent marking.
|
||||
ClassLoaderDataGraph::clear_claimed_marks();
|
||||
|
||||
@ -996,10 +985,7 @@ void ConcurrentMark::scanRootRegions() {
|
||||
// at least one root region to scan. So, if it's false, we
|
||||
// should not attempt to do any further work.
|
||||
if (root_regions()->scan_in_progress()) {
|
||||
if (G1Log::fine()) {
|
||||
gclog_or_tty->gclog_stamp();
|
||||
gclog_or_tty->print_cr("[GC concurrent-root-region-scan-start]");
|
||||
}
|
||||
GCTraceConcTime(Info, gc) tt("Concurrent Root Region Scan");
|
||||
|
||||
_parallel_marking_threads = calc_parallel_marking_threads();
|
||||
assert(parallel_marking_threads() <= max_parallel_marking_threads(),
|
||||
@ -1010,11 +996,6 @@ void ConcurrentMark::scanRootRegions() {
|
||||
_parallel_workers->set_active_workers(active_workers);
|
||||
_parallel_workers->run_task(&task);
|
||||
|
||||
if (G1Log::fine()) {
|
||||
gclog_or_tty->gclog_stamp();
|
||||
gclog_or_tty->print_cr("[GC concurrent-root-region-scan-end, %1.7lf secs]", os::elapsedTime() - scan_start);
|
||||
}
|
||||
|
||||
// It's possible that has_aborted() is true here without actually
|
||||
// aborting the survivor scan earlier. This is OK as it's
|
||||
// mainly used for sanity checking.
|
||||
@ -1049,22 +1030,6 @@ void ConcurrentMark::markFromRoots() {
|
||||
print_stats();
|
||||
}
|
||||
|
||||
// Helper class to get rid of some boilerplate code.
|
||||
class G1CMTraceTime : public StackObj {
|
||||
GCTraceTimeImpl _gc_trace_time;
|
||||
static bool doit_and_prepend(bool doit) {
|
||||
if (doit) {
|
||||
gclog_or_tty->put(' ');
|
||||
}
|
||||
return doit;
|
||||
}
|
||||
|
||||
public:
|
||||
G1CMTraceTime(const char* title, bool doit)
|
||||
: _gc_trace_time(title, doit_and_prepend(doit), false, G1CollectedHeap::heap()->gc_timer_cm()) {
|
||||
}
|
||||
};
|
||||
|
||||
void ConcurrentMark::checkpointRootsFinal(bool clear_all_soft_refs) {
|
||||
// world is stopped at this checkpoint
|
||||
assert(SafepointSynchronize::is_at_safepoint(),
|
||||
@ -1083,8 +1048,7 @@ void ConcurrentMark::checkpointRootsFinal(bool clear_all_soft_refs) {
|
||||
if (VerifyDuringGC) {
|
||||
HandleMark hm; // handle scope
|
||||
g1h->prepare_for_verify();
|
||||
Universe::verify(VerifyOption_G1UsePrevMarking,
|
||||
" VerifyDuringGC:(before)");
|
||||
Universe::verify(VerifyOption_G1UsePrevMarking, "During GC (before)");
|
||||
}
|
||||
g1h->check_bitmaps("Remark Start");
|
||||
|
||||
@ -1102,16 +1066,13 @@ void ConcurrentMark::checkpointRootsFinal(bool clear_all_soft_refs) {
|
||||
if (has_overflown()) {
|
||||
// Oops. We overflowed. Restart concurrent marking.
|
||||
_restart_for_overflow = true;
|
||||
if (G1TraceMarkStackOverflow) {
|
||||
gclog_or_tty->print_cr("\nRemark led to restart for overflow.");
|
||||
}
|
||||
log_develop_trace(gc)("Remark led to restart for overflow.");
|
||||
|
||||
// Verify the heap w.r.t. the previous marking bitmap.
|
||||
if (VerifyDuringGC) {
|
||||
HandleMark hm; // handle scope
|
||||
g1h->prepare_for_verify();
|
||||
Universe::verify(VerifyOption_G1UsePrevMarking,
|
||||
" VerifyDuringGC:(overflow)");
|
||||
Universe::verify(VerifyOption_G1UsePrevMarking, "During GC (overflow)");
|
||||
}
|
||||
|
||||
// Clear the marking state because we will be restarting
|
||||
@ -1119,7 +1080,7 @@ void ConcurrentMark::checkpointRootsFinal(bool clear_all_soft_refs) {
|
||||
reset_marking_state();
|
||||
} else {
|
||||
{
|
||||
G1CMTraceTime trace("GC aggregate-data", G1Log::finer());
|
||||
GCTraceTime(Debug, gc) trace("GC Aggregate Data", g1h->gc_timer_cm());
|
||||
|
||||
// Aggregate the per-task counting data that we have accumulated
|
||||
// while marking.
|
||||
@ -1136,8 +1097,7 @@ void ConcurrentMark::checkpointRootsFinal(bool clear_all_soft_refs) {
|
||||
if (VerifyDuringGC) {
|
||||
HandleMark hm; // handle scope
|
||||
g1h->prepare_for_verify();
|
||||
Universe::verify(VerifyOption_G1UseNextMarking,
|
||||
" VerifyDuringGC:(after)");
|
||||
Universe::verify(VerifyOption_G1UseNextMarking, "During GC (after)");
|
||||
}
|
||||
g1h->check_bitmaps("Remark End");
|
||||
assert(!restart_for_overflow(), "sanity");
|
||||
@ -1523,8 +1483,8 @@ class G1NoteEndOfConcMarkClosure : public HeapRegionClosure {
|
||||
G1CollectedHeap* _g1;
|
||||
size_t _freed_bytes;
|
||||
FreeRegionList* _local_cleanup_list;
|
||||
HeapRegionSetCount _old_regions_removed;
|
||||
HeapRegionSetCount _humongous_regions_removed;
|
||||
uint _old_regions_removed;
|
||||
uint _humongous_regions_removed;
|
||||
HRRSCleanupTask* _hrrs_cleanup_task;
|
||||
|
||||
public:
|
||||
@ -1534,13 +1494,13 @@ public:
|
||||
_g1(g1),
|
||||
_freed_bytes(0),
|
||||
_local_cleanup_list(local_cleanup_list),
|
||||
_old_regions_removed(),
|
||||
_humongous_regions_removed(),
|
||||
_old_regions_removed(0),
|
||||
_humongous_regions_removed(0),
|
||||
_hrrs_cleanup_task(hrrs_cleanup_task) { }
|
||||
|
||||
size_t freed_bytes() { return _freed_bytes; }
|
||||
const HeapRegionSetCount& old_regions_removed() { return _old_regions_removed; }
|
||||
const HeapRegionSetCount& humongous_regions_removed() { return _humongous_regions_removed; }
|
||||
const uint old_regions_removed() { return _old_regions_removed; }
|
||||
const uint humongous_regions_removed() { return _humongous_regions_removed; }
|
||||
|
||||
bool doHeapRegion(HeapRegion *hr) {
|
||||
if (hr->is_archive()) {
|
||||
@ -1555,10 +1515,10 @@ public:
|
||||
_freed_bytes += hr->used();
|
||||
hr->set_containing_set(NULL);
|
||||
if (hr->is_humongous()) {
|
||||
_humongous_regions_removed.increment(1u, hr->capacity());
|
||||
_humongous_regions_removed++;
|
||||
_g1->free_humongous_region(hr, _local_cleanup_list, true);
|
||||
} else {
|
||||
_old_regions_removed.increment(1u, hr->capacity());
|
||||
_old_regions_removed++;
|
||||
_g1->free_region(hr, _local_cleanup_list, true);
|
||||
}
|
||||
} else {
|
||||
@ -1656,8 +1616,7 @@ void ConcurrentMark::cleanup() {
|
||||
if (VerifyDuringGC) {
|
||||
HandleMark hm; // handle scope
|
||||
g1h->prepare_for_verify();
|
||||
Universe::verify(VerifyOption_G1UsePrevMarking,
|
||||
" VerifyDuringGC:(before)");
|
||||
Universe::verify(VerifyOption_G1UsePrevMarking, "During GC (before)");
|
||||
}
|
||||
g1h->check_bitmaps("Cleanup Start");
|
||||
|
||||
@ -1699,8 +1658,8 @@ void ConcurrentMark::cleanup() {
|
||||
double this_final_counting_time = (count_end - start);
|
||||
_total_counting_time += this_final_counting_time;
|
||||
|
||||
if (G1PrintRegionLivenessInfo) {
|
||||
G1PrintRegionLivenessInfoClosure cl(gclog_or_tty, "Post-Marking");
|
||||
if (log_is_enabled(Trace, gc, liveness)) {
|
||||
G1PrintRegionLivenessInfoClosure cl("Post-Marking");
|
||||
_g1h->heap_region_iterate(&cl);
|
||||
}
|
||||
|
||||
@ -1743,10 +1702,6 @@ void ConcurrentMark::cleanup() {
|
||||
double end = os::elapsedTime();
|
||||
_cleanup_times.add((end - start) * 1000.0);
|
||||
|
||||
if (G1Log::fine()) {
|
||||
g1h->g1_policy()->print_heap_transition(start_used_bytes);
|
||||
}
|
||||
|
||||
// Clean up will have freed any regions completely full of garbage.
|
||||
// Update the soft reference policy with the new heap occupancy.
|
||||
Universe::update_heap_info_at_gc();
|
||||
@ -1754,8 +1709,7 @@ void ConcurrentMark::cleanup() {
|
||||
if (VerifyDuringGC) {
|
||||
HandleMark hm; // handle scope
|
||||
g1h->prepare_for_verify();
|
||||
Universe::verify(VerifyOption_G1UsePrevMarking,
|
||||
" VerifyDuringGC:(after)");
|
||||
Universe::verify(VerifyOption_G1UsePrevMarking, "During GC (after)");
|
||||
}
|
||||
|
||||
g1h->check_bitmaps("Cleanup End");
|
||||
@ -1788,11 +1742,9 @@ void ConcurrentMark::completeCleanup() {
|
||||
_cleanup_list.verify_optional();
|
||||
FreeRegionList tmp_free_list("Tmp Free List");
|
||||
|
||||
if (G1ConcRegionFreeingVerbose) {
|
||||
gclog_or_tty->print_cr("G1ConcRegionFreeing [complete cleanup] : "
|
||||
"cleanup list has %u entries",
|
||||
_cleanup_list.length());
|
||||
}
|
||||
log_develop_trace(gc, freelist)("G1ConcRegionFreeing [complete cleanup] : "
|
||||
"cleanup list has %u entries",
|
||||
_cleanup_list.length());
|
||||
|
||||
// No one else should be accessing the _cleanup_list at this point,
|
||||
// so it is not necessary to take any locks
|
||||
@ -1810,13 +1762,11 @@ void ConcurrentMark::completeCleanup() {
|
||||
// region from the _cleanup_list).
|
||||
if ((tmp_free_list.length() % G1SecondaryFreeListAppendLength == 0) ||
|
||||
_cleanup_list.is_empty()) {
|
||||
if (G1ConcRegionFreeingVerbose) {
|
||||
gclog_or_tty->print_cr("G1ConcRegionFreeing [complete cleanup] : "
|
||||
"appending %u entries to the secondary_free_list, "
|
||||
"cleanup list still has %u entries",
|
||||
tmp_free_list.length(),
|
||||
_cleanup_list.length());
|
||||
}
|
||||
log_develop_trace(gc, freelist)("G1ConcRegionFreeing [complete cleanup] : "
|
||||
"appending %u entries to the secondary_free_list, "
|
||||
"cleanup list still has %u entries",
|
||||
tmp_free_list.length(),
|
||||
_cleanup_list.length());
|
||||
|
||||
{
|
||||
MutexLockerEx x(SecondaryFreeList_lock, Mutex::_no_safepoint_check_flag);
|
||||
@ -2073,7 +2023,7 @@ void ConcurrentMark::weakRefsWork(bool clear_all_soft_refs) {
|
||||
// Inner scope to exclude the cleaning of the string and symbol
|
||||
// tables from the displayed time.
|
||||
{
|
||||
G1CMTraceTime t("GC ref-proc", G1Log::finer());
|
||||
GCTraceTime(Debug, gc) trace("GC Ref Proc", g1h->gc_timer_cm());
|
||||
|
||||
ReferenceProcessor* rp = g1h->ref_processor_cm();
|
||||
|
||||
@ -2163,24 +2113,24 @@ void ConcurrentMark::weakRefsWork(bool clear_all_soft_refs) {
|
||||
|
||||
// Unload Klasses, String, Symbols, Code Cache, etc.
|
||||
{
|
||||
G1CMTraceTime trace("Unloading", G1Log::finer());
|
||||
GCTraceTime(Debug, gc) trace("Unloading", g1h->gc_timer_cm());
|
||||
|
||||
if (ClassUnloadingWithConcurrentMark) {
|
||||
bool purged_classes;
|
||||
|
||||
{
|
||||
G1CMTraceTime trace("System Dictionary Unloading", G1Log::finest());
|
||||
GCTraceTime(Trace, gc) trace("System Dictionary Unloading", g1h->gc_timer_cm());
|
||||
purged_classes = SystemDictionary::do_unloading(&g1_is_alive, false /* Defer klass cleaning */);
|
||||
}
|
||||
|
||||
{
|
||||
G1CMTraceTime trace("Parallel Unloading", G1Log::finest());
|
||||
GCTraceTime(Trace, gc) trace("Parallel Unloading", g1h->gc_timer_cm());
|
||||
weakRefsWorkParallelPart(&g1_is_alive, purged_classes);
|
||||
}
|
||||
}
|
||||
|
||||
if (G1StringDedup::is_enabled()) {
|
||||
G1CMTraceTime trace("String Deduplication Unlink", G1Log::finest());
|
||||
GCTraceTime(Trace, gc) trace("String Deduplication Unlink", g1h->gc_timer_cm());
|
||||
G1StringDedup::unlink(&g1_is_alive);
|
||||
}
|
||||
}
|
||||
@ -2301,7 +2251,7 @@ void ConcurrentMark::checkpointRootsFinalWork() {
|
||||
HandleMark hm;
|
||||
G1CollectedHeap* g1h = G1CollectedHeap::heap();
|
||||
|
||||
G1CMTraceTime trace("Finalize Marking", G1Log::finer());
|
||||
GCTraceTime(Debug, gc) trace("Finalize Marking", g1h->gc_timer_cm());
|
||||
|
||||
g1h->ensure_parsability(false);
|
||||
|
||||
@ -2614,12 +2564,13 @@ void ConcurrentMark::clear_all_count_data() {
|
||||
}
|
||||
|
||||
void ConcurrentMark::print_stats() {
|
||||
if (G1MarkingVerboseLevel > 0) {
|
||||
gclog_or_tty->print_cr("---------------------------------------------------------------------");
|
||||
for (size_t i = 0; i < _active_tasks; ++i) {
|
||||
_tasks[i]->print_stats();
|
||||
gclog_or_tty->print_cr("---------------------------------------------------------------------");
|
||||
}
|
||||
if (!log_is_enabled(Debug, gc, stats)) {
|
||||
return;
|
||||
}
|
||||
log_debug(gc, stats)("---------------------------------------------------------------------");
|
||||
for (size_t i = 0; i < _active_tasks; ++i) {
|
||||
_tasks[i]->print_stats();
|
||||
log_debug(gc, stats)("---------------------------------------------------------------------");
|
||||
}
|
||||
}
|
||||
|
||||
@ -2663,16 +2614,21 @@ void ConcurrentMark::abort() {
|
||||
|
||||
static void print_ms_time_info(const char* prefix, const char* name,
|
||||
NumberSeq& ns) {
|
||||
gclog_or_tty->print_cr("%s%5d %12s: total time = %8.2f s (avg = %8.2f ms).",
|
||||
log_trace(gc, marking)("%s%5d %12s: total time = %8.2f s (avg = %8.2f ms).",
|
||||
prefix, ns.num(), name, ns.sum()/1000.0, ns.avg());
|
||||
if (ns.num() > 0) {
|
||||
gclog_or_tty->print_cr("%s [std. dev = %8.2f ms, max = %8.2f ms]",
|
||||
log_trace(gc, marking)("%s [std. dev = %8.2f ms, max = %8.2f ms]",
|
||||
prefix, ns.sd(), ns.maximum());
|
||||
}
|
||||
}
|
||||
|
||||
void ConcurrentMark::print_summary_info() {
|
||||
gclog_or_tty->print_cr(" Concurrent marking:");
|
||||
LogHandle(gc, marking) log;
|
||||
if (!log.is_trace()) {
|
||||
return;
|
||||
}
|
||||
|
||||
log.trace(" Concurrent marking:");
|
||||
print_ms_time_info(" ", "init marks", _init_times);
|
||||
print_ms_time_info(" ", "remarks", _remark_times);
|
||||
{
|
||||
@ -2681,25 +2637,16 @@ void ConcurrentMark::print_summary_info() {
|
||||
|
||||
}
|
||||
print_ms_time_info(" ", "cleanups", _cleanup_times);
|
||||
gclog_or_tty->print_cr(" Final counting total time = %8.2f s (avg = %8.2f ms).",
|
||||
_total_counting_time,
|
||||
(_cleanup_times.num() > 0 ? _total_counting_time * 1000.0 /
|
||||
(double)_cleanup_times.num()
|
||||
: 0.0));
|
||||
log.trace(" Final counting total time = %8.2f s (avg = %8.2f ms).",
|
||||
_total_counting_time, (_cleanup_times.num() > 0 ? _total_counting_time * 1000.0 / (double)_cleanup_times.num() : 0.0));
|
||||
if (G1ScrubRemSets) {
|
||||
gclog_or_tty->print_cr(" RS scrub total time = %8.2f s (avg = %8.2f ms).",
|
||||
_total_rs_scrub_time,
|
||||
(_cleanup_times.num() > 0 ? _total_rs_scrub_time * 1000.0 /
|
||||
(double)_cleanup_times.num()
|
||||
: 0.0));
|
||||
log.trace(" RS scrub total time = %8.2f s (avg = %8.2f ms).",
|
||||
_total_rs_scrub_time, (_cleanup_times.num() > 0 ? _total_rs_scrub_time * 1000.0 / (double)_cleanup_times.num() : 0.0));
|
||||
}
|
||||
gclog_or_tty->print_cr(" Total stop_world time = %8.2f s.",
|
||||
(_init_times.sum() + _remark_times.sum() +
|
||||
_cleanup_times.sum())/1000.0);
|
||||
gclog_or_tty->print_cr(" Total concurrent time = %8.2f s "
|
||||
"(%8.2f s marking).",
|
||||
cmThread()->vtime_accum(),
|
||||
cmThread()->vtime_mark_accum());
|
||||
log.trace(" Total stop_world time = %8.2f s.",
|
||||
(_init_times.sum() + _remark_times.sum() + _cleanup_times.sum())/1000.0);
|
||||
log.trace(" Total concurrent time = %8.2f s (%8.2f s marking).",
|
||||
cmThread()->vtime_accum(), cmThread()->vtime_mark_accum());
|
||||
}
|
||||
|
||||
void ConcurrentMark::print_worker_threads_on(outputStream* st) const {
|
||||
@ -3079,15 +3026,15 @@ void CMTask::drain_satb_buffers() {
|
||||
}
|
||||
|
||||
void CMTask::print_stats() {
|
||||
gclog_or_tty->print_cr("Marking Stats, task = %u, calls = %d",
|
||||
_worker_id, _calls);
|
||||
gclog_or_tty->print_cr(" Elapsed time = %1.2lfms, Termination time = %1.2lfms",
|
||||
_elapsed_time_ms, _termination_time_ms);
|
||||
gclog_or_tty->print_cr(" Step Times (cum): num = %d, avg = %1.2lfms, sd = %1.2lfms",
|
||||
_step_times_ms.num(), _step_times_ms.avg(),
|
||||
_step_times_ms.sd());
|
||||
gclog_or_tty->print_cr(" max = %1.2lfms, total = %1.2lfms",
|
||||
_step_times_ms.maximum(), _step_times_ms.sum());
|
||||
log_debug(gc, stats)("Marking Stats, task = %u, calls = %d",
|
||||
_worker_id, _calls);
|
||||
log_debug(gc, stats)(" Elapsed time = %1.2lfms, Termination time = %1.2lfms",
|
||||
_elapsed_time_ms, _termination_time_ms);
|
||||
log_debug(gc, stats)(" Step Times (cum): num = %d, avg = %1.2lfms, sd = %1.2lfms",
|
||||
_step_times_ms.num(), _step_times_ms.avg(),
|
||||
_step_times_ms.sd());
|
||||
log_debug(gc, stats)(" max = %1.2lfms, total = %1.2lfms",
|
||||
_step_times_ms.maximum(), _step_times_ms.sum());
|
||||
}
|
||||
|
||||
bool ConcurrentMark::try_stealing(uint worker_id, int* hash_seed, oop& obj) {
|
||||
@ -3587,9 +3534,8 @@ CMTask::CMTask(uint worker_id,
|
||||
#define G1PPRL_SUM_MB_PERC_FORMAT(tag) G1PPRL_SUM_MB_FORMAT(tag) " / %1.2f %%"
|
||||
|
||||
G1PrintRegionLivenessInfoClosure::
|
||||
G1PrintRegionLivenessInfoClosure(outputStream* out, const char* phase_name)
|
||||
: _out(out),
|
||||
_total_used_bytes(0), _total_capacity_bytes(0),
|
||||
G1PrintRegionLivenessInfoClosure(const char* phase_name)
|
||||
: _total_used_bytes(0), _total_capacity_bytes(0),
|
||||
_total_prev_live_bytes(0), _total_next_live_bytes(0),
|
||||
_hum_used_bytes(0), _hum_capacity_bytes(0),
|
||||
_hum_prev_live_bytes(0), _hum_next_live_bytes(0),
|
||||
@ -3599,38 +3545,37 @@ G1PrintRegionLivenessInfoClosure(outputStream* out, const char* phase_name)
|
||||
double now = os::elapsedTime();
|
||||
|
||||
// Print the header of the output.
|
||||
_out->cr();
|
||||
_out->print_cr(G1PPRL_LINE_PREFIX" PHASE %s @ %1.3f", phase_name, now);
|
||||
_out->print_cr(G1PPRL_LINE_PREFIX" HEAP"
|
||||
G1PPRL_SUM_ADDR_FORMAT("reserved")
|
||||
G1PPRL_SUM_BYTE_FORMAT("region-size"),
|
||||
p2i(g1_reserved.start()), p2i(g1_reserved.end()),
|
||||
HeapRegion::GrainBytes);
|
||||
_out->print_cr(G1PPRL_LINE_PREFIX);
|
||||
_out->print_cr(G1PPRL_LINE_PREFIX
|
||||
G1PPRL_TYPE_H_FORMAT
|
||||
G1PPRL_ADDR_BASE_H_FORMAT
|
||||
G1PPRL_BYTE_H_FORMAT
|
||||
G1PPRL_BYTE_H_FORMAT
|
||||
G1PPRL_BYTE_H_FORMAT
|
||||
G1PPRL_DOUBLE_H_FORMAT
|
||||
G1PPRL_BYTE_H_FORMAT
|
||||
G1PPRL_BYTE_H_FORMAT,
|
||||
"type", "address-range",
|
||||
"used", "prev-live", "next-live", "gc-eff",
|
||||
"remset", "code-roots");
|
||||
_out->print_cr(G1PPRL_LINE_PREFIX
|
||||
G1PPRL_TYPE_H_FORMAT
|
||||
G1PPRL_ADDR_BASE_H_FORMAT
|
||||
G1PPRL_BYTE_H_FORMAT
|
||||
G1PPRL_BYTE_H_FORMAT
|
||||
G1PPRL_BYTE_H_FORMAT
|
||||
G1PPRL_DOUBLE_H_FORMAT
|
||||
G1PPRL_BYTE_H_FORMAT
|
||||
G1PPRL_BYTE_H_FORMAT,
|
||||
"", "",
|
||||
"(bytes)", "(bytes)", "(bytes)", "(bytes/ms)",
|
||||
"(bytes)", "(bytes)");
|
||||
log_trace(gc, liveness)(G1PPRL_LINE_PREFIX" PHASE %s @ %1.3f", phase_name, now);
|
||||
log_trace(gc, liveness)(G1PPRL_LINE_PREFIX" HEAP"
|
||||
G1PPRL_SUM_ADDR_FORMAT("reserved")
|
||||
G1PPRL_SUM_BYTE_FORMAT("region-size"),
|
||||
p2i(g1_reserved.start()), p2i(g1_reserved.end()),
|
||||
HeapRegion::GrainBytes);
|
||||
log_trace(gc, liveness)(G1PPRL_LINE_PREFIX);
|
||||
log_trace(gc, liveness)(G1PPRL_LINE_PREFIX
|
||||
G1PPRL_TYPE_H_FORMAT
|
||||
G1PPRL_ADDR_BASE_H_FORMAT
|
||||
G1PPRL_BYTE_H_FORMAT
|
||||
G1PPRL_BYTE_H_FORMAT
|
||||
G1PPRL_BYTE_H_FORMAT
|
||||
G1PPRL_DOUBLE_H_FORMAT
|
||||
G1PPRL_BYTE_H_FORMAT
|
||||
G1PPRL_BYTE_H_FORMAT,
|
||||
"type", "address-range",
|
||||
"used", "prev-live", "next-live", "gc-eff",
|
||||
"remset", "code-roots");
|
||||
log_trace(gc, liveness)(G1PPRL_LINE_PREFIX
|
||||
G1PPRL_TYPE_H_FORMAT
|
||||
G1PPRL_ADDR_BASE_H_FORMAT
|
||||
G1PPRL_BYTE_H_FORMAT
|
||||
G1PPRL_BYTE_H_FORMAT
|
||||
G1PPRL_BYTE_H_FORMAT
|
||||
G1PPRL_DOUBLE_H_FORMAT
|
||||
G1PPRL_BYTE_H_FORMAT
|
||||
G1PPRL_BYTE_H_FORMAT,
|
||||
"", "",
|
||||
"(bytes)", "(bytes)", "(bytes)", "(bytes/ms)",
|
||||
"(bytes)", "(bytes)");
|
||||
}
|
||||
|
||||
// It takes as a parameter a reference to one of the _hum_* fields, it
|
||||
@ -3701,18 +3646,18 @@ bool G1PrintRegionLivenessInfoClosure::doHeapRegion(HeapRegion* r) {
|
||||
_total_strong_code_roots_bytes += strong_code_roots_bytes;
|
||||
|
||||
// Print a line for this particular region.
|
||||
_out->print_cr(G1PPRL_LINE_PREFIX
|
||||
G1PPRL_TYPE_FORMAT
|
||||
G1PPRL_ADDR_BASE_FORMAT
|
||||
G1PPRL_BYTE_FORMAT
|
||||
G1PPRL_BYTE_FORMAT
|
||||
G1PPRL_BYTE_FORMAT
|
||||
G1PPRL_DOUBLE_FORMAT
|
||||
G1PPRL_BYTE_FORMAT
|
||||
G1PPRL_BYTE_FORMAT,
|
||||
type, p2i(bottom), p2i(end),
|
||||
used_bytes, prev_live_bytes, next_live_bytes, gc_eff,
|
||||
remset_bytes, strong_code_roots_bytes);
|
||||
log_trace(gc, liveness)(G1PPRL_LINE_PREFIX
|
||||
G1PPRL_TYPE_FORMAT
|
||||
G1PPRL_ADDR_BASE_FORMAT
|
||||
G1PPRL_BYTE_FORMAT
|
||||
G1PPRL_BYTE_FORMAT
|
||||
G1PPRL_BYTE_FORMAT
|
||||
G1PPRL_DOUBLE_FORMAT
|
||||
G1PPRL_BYTE_FORMAT
|
||||
G1PPRL_BYTE_FORMAT,
|
||||
type, p2i(bottom), p2i(end),
|
||||
used_bytes, prev_live_bytes, next_live_bytes, gc_eff,
|
||||
remset_bytes, strong_code_roots_bytes);
|
||||
|
||||
return false;
|
||||
}
|
||||
@ -3721,23 +3666,22 @@ G1PrintRegionLivenessInfoClosure::~G1PrintRegionLivenessInfoClosure() {
|
||||
// add static memory usages to remembered set sizes
|
||||
_total_remset_bytes += HeapRegionRemSet::fl_mem_size() + HeapRegionRemSet::static_mem_size();
|
||||
// Print the footer of the output.
|
||||
_out->print_cr(G1PPRL_LINE_PREFIX);
|
||||
_out->print_cr(G1PPRL_LINE_PREFIX
|
||||
" SUMMARY"
|
||||
G1PPRL_SUM_MB_FORMAT("capacity")
|
||||
G1PPRL_SUM_MB_PERC_FORMAT("used")
|
||||
G1PPRL_SUM_MB_PERC_FORMAT("prev-live")
|
||||
G1PPRL_SUM_MB_PERC_FORMAT("next-live")
|
||||
G1PPRL_SUM_MB_FORMAT("remset")
|
||||
G1PPRL_SUM_MB_FORMAT("code-roots"),
|
||||
bytes_to_mb(_total_capacity_bytes),
|
||||
bytes_to_mb(_total_used_bytes),
|
||||
perc(_total_used_bytes, _total_capacity_bytes),
|
||||
bytes_to_mb(_total_prev_live_bytes),
|
||||
perc(_total_prev_live_bytes, _total_capacity_bytes),
|
||||
bytes_to_mb(_total_next_live_bytes),
|
||||
perc(_total_next_live_bytes, _total_capacity_bytes),
|
||||
bytes_to_mb(_total_remset_bytes),
|
||||
bytes_to_mb(_total_strong_code_roots_bytes));
|
||||
_out->cr();
|
||||
log_trace(gc, liveness)(G1PPRL_LINE_PREFIX);
|
||||
log_trace(gc, liveness)(G1PPRL_LINE_PREFIX
|
||||
" SUMMARY"
|
||||
G1PPRL_SUM_MB_FORMAT("capacity")
|
||||
G1PPRL_SUM_MB_PERC_FORMAT("used")
|
||||
G1PPRL_SUM_MB_PERC_FORMAT("prev-live")
|
||||
G1PPRL_SUM_MB_PERC_FORMAT("next-live")
|
||||
G1PPRL_SUM_MB_FORMAT("remset")
|
||||
G1PPRL_SUM_MB_FORMAT("code-roots"),
|
||||
bytes_to_mb(_total_capacity_bytes),
|
||||
bytes_to_mb(_total_used_bytes),
|
||||
perc(_total_used_bytes, _total_capacity_bytes),
|
||||
bytes_to_mb(_total_prev_live_bytes),
|
||||
perc(_total_prev_live_bytes, _total_capacity_bytes),
|
||||
bytes_to_mb(_total_next_live_bytes),
|
||||
perc(_total_next_live_bytes, _total_capacity_bytes),
|
||||
bytes_to_mb(_total_remset_bytes),
|
||||
bytes_to_mb(_total_strong_code_roots_bytes));
|
||||
}
|
||||
|
@ -978,8 +978,6 @@ public:
|
||||
// after we sort the old regions at the end of the cleanup operation.
|
||||
class G1PrintRegionLivenessInfoClosure: public HeapRegionClosure {
|
||||
private:
|
||||
outputStream* _out;
|
||||
|
||||
// Accumulators for these values.
|
||||
size_t _total_used_bytes;
|
||||
size_t _total_capacity_bytes;
|
||||
@ -1024,7 +1022,7 @@ private:
|
||||
public:
|
||||
// The header and footer are printed in the constructor and
|
||||
// destructor respectively.
|
||||
G1PrintRegionLivenessInfoClosure(outputStream* out, const char* phase_name);
|
||||
G1PrintRegionLivenessInfoClosure(const char* phase_name);
|
||||
virtual bool doHeapRegion(HeapRegion* r);
|
||||
~G1PrintRegionLivenessInfoClosure();
|
||||
};
|
||||
|
@ -26,12 +26,13 @@
|
||||
#include "gc/g1/concurrentMarkThread.inline.hpp"
|
||||
#include "gc/g1/g1CollectedHeap.inline.hpp"
|
||||
#include "gc/g1/g1CollectorPolicy.hpp"
|
||||
#include "gc/g1/g1Log.hpp"
|
||||
#include "gc/g1/g1MMUTracker.hpp"
|
||||
#include "gc/g1/suspendibleThreadSet.hpp"
|
||||
#include "gc/g1/vm_operations_g1.hpp"
|
||||
#include "gc/shared/gcId.hpp"
|
||||
#include "gc/shared/gcTrace.hpp"
|
||||
#include "gc/shared/gcTraceTime.inline.hpp"
|
||||
#include "logging/log.hpp"
|
||||
#include "memory/resourceArea.hpp"
|
||||
#include "runtime/vmThread.hpp"
|
||||
|
||||
@ -78,20 +79,6 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
// We want to avoid that the logging from the concurrent thread is mixed
|
||||
// with the logging from a STW GC. So, if necessary join the STS to ensure
|
||||
// that the logging is done either before or after the STW logging.
|
||||
void ConcurrentMarkThread::cm_log(bool doit, bool join_sts, const char* fmt, ...) {
|
||||
if (doit) {
|
||||
SuspendibleThreadSetJoiner sts_joiner(join_sts);
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
gclog_or_tty->gclog_stamp();
|
||||
gclog_or_tty->vprint_cr(fmt, args);
|
||||
va_end(args);
|
||||
}
|
||||
}
|
||||
|
||||
// Marking pauses can be scheduled flexibly, so we might delay marking to meet MMU.
|
||||
void ConcurrentMarkThread::delay_to_keep_mmu(G1CollectorPolicy* g1_policy, bool remark) {
|
||||
if (g1_policy->adaptive_young_list_length()) {
|
||||
@ -143,8 +130,11 @@ void ConcurrentMarkThread::run_service() {
|
||||
_cm->scanRootRegions();
|
||||
}
|
||||
|
||||
double mark_start_sec = os::elapsedTime();
|
||||
cm_log(G1Log::fine(), true, "[GC concurrent-mark-start]");
|
||||
// It would be nice to use the GCTraceConcTime class here but
|
||||
// the "end" logging is inside the loop and not at the end of
|
||||
// a scope. Mimicking the same log output as GCTraceConcTime instead.
|
||||
jlong mark_start = os::elapsed_counter();
|
||||
log_info(gc)("Concurrent Mark (%.3fs)", TimeHelper::counter_to_seconds(mark_start));
|
||||
|
||||
int iter = 0;
|
||||
do {
|
||||
@ -154,20 +144,22 @@ void ConcurrentMarkThread::run_service() {
|
||||
}
|
||||
|
||||
double mark_end_time = os::elapsedVTime();
|
||||
double mark_end_sec = os::elapsedTime();
|
||||
jlong mark_end = os::elapsed_counter();
|
||||
_vtime_mark_accum += (mark_end_time - cycle_start);
|
||||
if (!cm()->has_aborted()) {
|
||||
delay_to_keep_mmu(g1_policy, true /* remark */);
|
||||
|
||||
cm_log(G1Log::fine(), true, "[GC concurrent-mark-end, %1.7lf secs]", mark_end_sec - mark_start_sec);
|
||||
log_info(gc)("Concurrent Mark (%.3fs, %.3fs) %.3fms",
|
||||
TimeHelper::counter_to_seconds(mark_start),
|
||||
TimeHelper::counter_to_seconds(mark_end),
|
||||
TimeHelper::counter_to_millis(mark_end - mark_start));
|
||||
|
||||
CMCheckpointRootsFinalClosure final_cl(_cm);
|
||||
VM_CGC_Operation op(&final_cl, "GC remark", true /* needs_pll */);
|
||||
VM_CGC_Operation op(&final_cl, "Pause Remark", true /* needs_pll */);
|
||||
VMThread::execute(&op);
|
||||
}
|
||||
if (cm()->restart_for_overflow()) {
|
||||
cm_log(G1TraceMarkStackOverflow, true, "Restarting conc marking because of MS overflow in remark (restart #%d).", iter);
|
||||
cm_log(G1Log::fine(), true, "[GC concurrent-mark-restart-for-overflow]");
|
||||
log_debug(gc)("Restarting conc marking because of MS overflow in remark (restart #%d).", iter);
|
||||
log_info(gc)("Concurrent Mark restart for overflow");
|
||||
}
|
||||
} while (cm()->restart_for_overflow());
|
||||
|
||||
@ -181,7 +173,7 @@ void ConcurrentMarkThread::run_service() {
|
||||
delay_to_keep_mmu(g1_policy, false /* cleanup */);
|
||||
|
||||
CMCleanUp cl_cl(_cm);
|
||||
VM_CGC_Operation op(&cl_cl, "GC cleanup", false /* needs_pll */);
|
||||
VM_CGC_Operation op(&cl_cl, "Pause Cleanup", false /* needs_pll */);
|
||||
VMThread::execute(&op);
|
||||
} else {
|
||||
// We don't want to update the marking status if a GC pause
|
||||
@ -201,8 +193,7 @@ void ConcurrentMarkThread::run_service() {
|
||||
// place, it would wait for us to process the regions
|
||||
// reclaimed by cleanup.
|
||||
|
||||
double cleanup_start_sec = os::elapsedTime();
|
||||
cm_log(G1Log::fine(), false, "[GC concurrent-cleanup-start]");
|
||||
GCTraceConcTime(Info, gc) tt("Concurrent Cleanup");
|
||||
|
||||
// Now do the concurrent cleanup operation.
|
||||
_cm->completeCleanup();
|
||||
@ -217,9 +208,6 @@ void ConcurrentMarkThread::run_service() {
|
||||
// while it's trying to join the STS, which is conditional on
|
||||
// the GC workers finishing.
|
||||
g1h->reset_free_regions_coming();
|
||||
|
||||
double cleanup_end_sec = os::elapsedTime();
|
||||
cm_log(G1Log::fine(), true, "[GC concurrent-cleanup-end, %1.7lf secs]", cleanup_end_sec - cleanup_start_sec);
|
||||
}
|
||||
guarantee(cm()->cleanup_list_is_empty(),
|
||||
"at this point there should be no regions on the cleanup list");
|
||||
@ -253,7 +241,7 @@ void ConcurrentMarkThread::run_service() {
|
||||
if (!cm()->has_aborted()) {
|
||||
g1_policy->record_concurrent_mark_cleanup_completed();
|
||||
} else {
|
||||
cm_log(G1Log::fine(), false, "[GC concurrent-mark-abort]");
|
||||
log_info(gc)("Concurrent Mark abort");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -40,7 +40,6 @@ class ConcurrentMarkThread: public ConcurrentGCThread {
|
||||
double _vtime_accum; // Accumulated virtual time.
|
||||
|
||||
double _vtime_mark_accum;
|
||||
void cm_log(bool doit, bool join_sts, const char* fmt, ...) ATTRIBUTE_PRINTF(4, 5);
|
||||
|
||||
public:
|
||||
virtual void run();
|
||||
|
@ -112,7 +112,7 @@ void DirtyCardQueueSet::initialize(CardTableEntryClosure* cl,
|
||||
fl_owner);
|
||||
set_buffer_size(G1UpdateBufferSize);
|
||||
_shared_dirty_card_queue.set_lock(lock);
|
||||
_free_ids = new FreeIdSet((int) num_par_ids(), _cbl_mon);
|
||||
_free_ids = new FreeIdSet(num_par_ids(), _cbl_mon);
|
||||
}
|
||||
|
||||
void DirtyCardQueueSet::handle_zero_index_for_thread(JavaThread* t) {
|
||||
|
@ -353,7 +353,7 @@ bool G1ArchiveAllocator::alloc_new_region() {
|
||||
assert(hr->is_empty(), "expected empty region (index %u)", hr->hrm_index());
|
||||
hr->set_archive();
|
||||
_g1h->old_set_add(hr);
|
||||
_g1h->hr_printer()->alloc(hr, G1HRPrinter::Archive);
|
||||
_g1h->hr_printer()->alloc(hr);
|
||||
_allocated_regions.append(hr);
|
||||
_allocation_region = hr;
|
||||
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user