Mercurial > hg > graal-jvmci-8
changeset 23566:ac9a68124ba9
Merge
author | asaha |
---|---|
date | Tue, 05 Jan 2016 08:40:50 -0800 |
parents | c3091ebd2811 (diff) 451dda77f6c2 (current diff) |
children | 2a2720daacaa |
files | .hgtags |
diffstat | 71 files changed, 853 insertions(+), 852 deletions(-) [+] |
line wrap: on
line diff
--- a/.hgtags Tue Dec 22 12:28:01 2015 -0800 +++ b/.hgtags Tue Jan 05 08:40:50 2016 -0800 @@ -795,3 +795,6 @@ a8e4754b89aecc388623394a20f6d43d4c58f083 jdk8u72-b13 dc2fdd4e0b8105268b8231040f761f27ab4523f2 jdk8u72-b14 d6670c5d49ba381405ec9f69a78ccc5b8b0c8473 jdk8u72-b15 +d7b01fb81aa8a5437cb03bc36afe15cf0e55fb89 jdk8u76-b00 +c1679cc87ba045219169cabb6b9b378c2b5cc578 jdk8u76-b01 +218483967e52b419d885d34af4488a81c5133804 jdk8u76-b02
--- a/agent/src/os/linux/LinuxDebuggerLocal.c Tue Dec 22 12:28:01 2015 -0800 +++ b/agent/src/os/linux/LinuxDebuggerLocal.c Tue Jan 05 08:40:50 2016 -0800 @@ -209,9 +209,12 @@ 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);
--- a/agent/src/os/linux/libproc.h Tue Dec 22 12:28:01 2015 -0800 +++ b/agent/src/os/linux/libproc.h Tue Jan 05 08:40:50 2016 -0800 @@ -69,6 +69,7 @@ #if defined(sparc) || defined(sparcv9) || defined(ppc64) +#include <asm/ptrace.h> #define user_regs_struct pt_regs #endif @@ -82,7 +83,7 @@ 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);
--- a/agent/src/os/linux/ps_proc.c Tue Dec 22 12:28:01 2015 -0800 +++ b/agent/src/os/linux/ps_proc.c Tue Jan 05 08:40:50 2016 -0800 @@ -215,9 +215,12 @@ } // 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); @@ -339,16 +342,17 @@ }; // 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; } @@ -371,7 +375,7 @@ 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;
--- a/agent/src/share/classes/sun/jvm/hotspot/CommandProcessor.java Tue Dec 22 12:28:01 2015 -0800 +++ b/agent/src/share/classes/sun/jvm/hotspot/CommandProcessor.java Tue Jan 05 08:40:50 2016 -0800 @@ -1446,7 +1446,7 @@ if (type.equals("threads")) { Threads threads = VM.getVM().getThreads(); for (JavaThread thread = threads.first(); thread != null; thread = thread.next()) { - Address base = thread.getBaseOfStackPointer(); + Address base = thread.getStackBase(); Address end = thread.getLastJavaSP(); if (end == null) continue; if (end.lessThan(base)) { @@ -1454,11 +1454,13 @@ base = end; end = tmp; } - out.println("Searching " + base + " " + end); + //out.println("Searching " + base + " " + end); while (base != null && base.lessThan(end)) { Address val = base.getAddressAt(0); if (AddressOps.equal(val, value)) { - out.println(base); + ByteArrayOutputStream bos = new ByteArrayOutputStream(); + thread.printThreadIDOn(new PrintStream(bos)); + out.println("found on the stack of thread " + bos.toString() + " at " + base); } base = base.addOffsetTo(stride); } @@ -1601,6 +1603,8 @@ thread.printThreadIDOn(new PrintStream(bos)); if (all || bos.toString().equals(name)) { out.println("Thread " + bos.toString() + " Address " + thread.getAddress()); + thread.printInfoOn(out); + out.println(" "); if (!all) return; } } @@ -1618,6 +1622,8 @@ for (JavaThread thread = threads.first(); thread != null; thread = thread.next()) { thread.printThreadIDOn(out); out.println(" " + thread.getThreadName()); + thread.printInfoOn(out); + out.println("\n..."); } } }
--- a/agent/src/share/classes/sun/jvm/hotspot/runtime/JavaThread.java Tue Dec 22 12:28:01 2015 -0800 +++ b/agent/src/share/classes/sun/jvm/hotspot/runtime/JavaThread.java Tue Jan 05 08:40:50 2016 -0800 @@ -415,7 +415,7 @@ } else { tty.println("No Java frames present"); } - tty.println("Base of Stack: " + getBaseOfStackPointer()); + tty.println("Base of Stack: " + getStackBase()); tty.println("Last_Java_SP: " + getLastJavaSP()); tty.println("Last_Java_FP: " + getLastJavaFP()); tty.println("Last_Java_PC: " + getLastJavaPC());
--- a/make/linux/Makefile Tue Dec 22 12:28:01 2015 -0800 +++ b/make/linux/Makefile Tue Jan 05 08:40:50 2016 -0800 @@ -67,8 +67,12 @@ endif endif # C1 is not ported on ppc64, so we cannot build a tiered VM: -ifeq ($(ARCH),ppc64) - FORCE_TIERED=0 +# Notice: after 8046471 ARCH will be 'ppc' for top-level ppc64 builds but +# 'ppc64' for HotSpot-only ppc64 builds. Need to detect both variants here! +ifneq (,$(findstring $(ARCH), ppc ppc64)) + ifeq ($(ARCH_DATA_MODEL), 64) + FORCE_TIERED=0 + endif endif ifdef LP64
--- a/make/linux/makefiles/defs.make Tue Dec 22 12:28:01 2015 -0800 +++ b/make/linux/makefiles/defs.make Tue Jan 05 08:40:50 2016 -0800 @@ -69,7 +69,7 @@ endif # sparc -ifeq ($(ARCH), sparc64) +ifneq (,$(findstring $(ARCH), sparc)) ifeq ($(ARCH_DATA_MODEL), 64) ARCH_DATA_MODEL = 64 MAKE_ARGS += LP64=1 @@ -83,39 +83,35 @@ HS_ARCH = sparc endif -# amd64/x86_64 -ifneq (,$(findstring $(ARCH), amd64 x86_64)) +# i686/i586 and amd64/x86_64 +ifneq (,$(findstring $(ARCH), amd64 x86_64 i686 i586)) ifeq ($(ARCH_DATA_MODEL), 64) ARCH_DATA_MODEL = 64 MAKE_ARGS += LP64=1 PLATFORM = linux-amd64 VM_PLATFORM = linux_amd64 - HS_ARCH = x86 else ARCH_DATA_MODEL = 32 PLATFORM = linux-i586 VM_PLATFORM = linux_i486 - HS_ARCH = x86 - # We have to reset ARCH to i686 since SRCARCH relies on it - ARCH = i686 endif + HS_ARCH = x86 endif -# i686/i586 ie 32-bit x86 -ifneq (,$(findstring $(ARCH), i686 i586)) - ARCH_DATA_MODEL = 32 - PLATFORM = linux-i586 - VM_PLATFORM = linux_i486 - HS_ARCH = x86 -endif - -# PPC64 -ifeq ($(ARCH), ppc64) - ARCH_DATA_MODEL = 64 - MAKE_ARGS += LP64=1 - PLATFORM = linux-ppc64 - VM_PLATFORM = linux_ppc64 - HS_ARCH = ppc +# PPC +# Notice: after 8046471 ARCH will be 'ppc' for top-level ppc64 builds but +# 'ppc64' for HotSpot-only ppc64 builds. Need to detect both variants here! +ifneq (,$(findstring $(ARCH), ppc ppc64)) + ifeq ($(ARCH_DATA_MODEL), 64) + MAKE_ARGS += LP64=1 + PLATFORM = linux-ppc64 + VM_PLATFORM = linux_ppc64 + else + ARCH_DATA_MODEL = 32 + PLATFORM = linux-ppc + VM_PLATFORM = linux_ppc + endif + HS_ARCH = ppc endif # On 32 bit linux we build server and client, on 64 bit just server.
--- a/src/cpu/ppc/vm/interpreter_ppc.cpp Tue Dec 22 12:28:01 2015 -0800 +++ b/src/cpu/ppc/vm/interpreter_ppc.cpp Tue Jan 05 08:40:50 2016 -0800 @@ -296,8 +296,16 @@ __ bind(do_float); __ lfs(floatSlot, 0, arg_java); #if defined(LINUX) + // Linux uses ELF ABI. Both original ELF and ELFv2 ABIs have float + // in the least significant word of an argument slot. +#if defined(VM_LITTLE_ENDIAN) + __ stfs(floatSlot, 0, arg_c); +#else __ stfs(floatSlot, 4, arg_c); +#endif #elif defined(AIX) + // Although AIX runs on big endian CPU, float is in most significant + // word of an argument slot. __ stfs(floatSlot, 0, arg_c); #else #error "unknown OS"
--- a/src/cpu/ppc/vm/macroAssembler_ppc.cpp Tue Dec 22 12:28:01 2015 -0800 +++ b/src/cpu/ppc/vm/macroAssembler_ppc.cpp Tue Jan 05 08:40:50 2016 -0800 @@ -592,13 +592,6 @@ "can't identify emitted call"); } else { // variant 1: -#if defined(ABI_ELFv2) - nop(); - calculate_address_from_global_toc(R12, dest, true, true, false); - mtctr(R12); - nop(); - nop(); -#else mr(R0, R11); // spill R11 -> R0. // Load the destination address into CTR, @@ -608,7 +601,6 @@ mtctr(R11); mr(R11, R0); // spill R11 <- R0. nop(); -#endif // do the call/jump if (link) {
--- a/src/cpu/ppc/vm/sharedRuntime_ppc.cpp Tue Dec 22 12:28:01 2015 -0800 +++ b/src/cpu/ppc/vm/sharedRuntime_ppc.cpp Tue Jan 05 08:40:50 2016 -0800 @@ -766,6 +766,21 @@ // in farg_reg[j] if argument i is the j-th float argument of this call. // case T_FLOAT: +#if defined(LINUX) + // Linux uses ELF ABI. Both original ELF and ELFv2 ABIs have float + // in the least significant word of an argument slot. +#if defined(VM_LITTLE_ENDIAN) +#define FLOAT_WORD_OFFSET_IN_SLOT 0 +#else +#define FLOAT_WORD_OFFSET_IN_SLOT 1 +#endif +#elif defined(AIX) + // Although AIX runs on big endian CPU, float is in the most + // significant word of an argument slot. +#define FLOAT_WORD_OFFSET_IN_SLOT 0 +#else +#error "unknown OS" +#endif if (freg < Argument::n_float_register_parameters_c) { // Put float in register ... reg = farg_reg[freg]; @@ -779,14 +794,14 @@ if (arg >= Argument::n_regs_not_on_stack_c) { // ... and on the stack. guarantee(regs2 != NULL, "must pass float in register and stack slot"); - VMReg reg2 = VMRegImpl::stack2reg(stk LINUX_ONLY(+1)); + VMReg reg2 = VMRegImpl::stack2reg(stk + FLOAT_WORD_OFFSET_IN_SLOT); regs2[i].set1(reg2); stk += inc_stk_for_intfloat; } } else { // Put float on stack. - reg = VMRegImpl::stack2reg(stk LINUX_ONLY(+1)); + reg = VMRegImpl::stack2reg(stk + FLOAT_WORD_OFFSET_IN_SLOT); stk += inc_stk_for_intfloat; } regs[i].set1(reg);
--- a/src/cpu/sparc/vm/frame_sparc.cpp Tue Dec 22 12:28:01 2015 -0800 +++ b/src/cpu/sparc/vm/frame_sparc.cpp Tue Jan 05 08:40:50 2016 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -447,32 +447,6 @@ } #endif // CC_INTERP - -#ifdef ASSERT -// Debugging aid -static frame nth_sender(int n) { - frame f = JavaThread::current()->last_frame(); - - for(int i = 0; i < n; ++i) - f = f.sender((RegisterMap*)NULL); - - printf("first frame %d\n", f.is_first_frame() ? 1 : 0); - printf("interpreted frame %d\n", f.is_interpreted_frame() ? 1 : 0); - printf("java frame %d\n", f.is_java_frame() ? 1 : 0); - printf("entry frame %d\n", f.is_entry_frame() ? 1 : 0); - printf("native frame %d\n", f.is_native_frame() ? 1 : 0); - if (f.is_compiled_frame()) { - if (f.is_deoptimized_frame()) - printf("deoptimized frame 1\n"); - else - printf("compiled frame 1\n"); - } - - return f; -} -#endif - - frame frame::sender_for_entry_frame(RegisterMap *map) const { assert(map != NULL, "map must be set"); // Java frame called from C; skip all C frames and return top C
--- a/src/cpu/x86/vm/macroAssembler_x86.cpp Tue Dec 22 12:28:01 2015 -0800 +++ b/src/cpu/x86/vm/macroAssembler_x86.cpp Tue Jan 05 08:40:50 2016 -0800 @@ -6143,7 +6143,9 @@ // Save caller's stack pointer into RBP if the frame pointer is preserved. if (PreserveFramePointer) { movptr(rbp, rsp); - addptr(rbp, framesize + wordSize); + if (framesize > 0) { + addptr(rbp, framesize); + } } }
--- a/src/cpu/x86/vm/x86_32.ad Tue Dec 22 12:28:01 2015 -0800 +++ b/src/cpu/x86/vm/x86_32.ad Tue Jan 05 08:40:50 2016 -0800 @@ -566,7 +566,11 @@ st->print("MOV [ESP + #%d], EBP\t# Save EBP",framesize); if (PreserveFramePointer) { st->print("\n\t"); - st->print("MOV EBP, [ESP + #%d]\t# Save the caller's SP into EBP", (framesize + wordSize)); + st->print("MOV EBP, ESP\t# Save the caller's SP into EBP"); + if (framesize > 0) { + st->print("\n\t"); + st->print("ADD EBP, #%d", framesize); + } } }
--- a/src/cpu/x86/vm/x86_64.ad Tue Dec 22 12:28:01 2015 -0800 +++ b/src/cpu/x86/vm/x86_64.ad Tue Jan 05 08:40:50 2016 -0800 @@ -863,7 +863,11 @@ st->print("movq [rsp + #%d], rbp\t# Save rbp",framesize); if (PreserveFramePointer) { st->print("\n\t"); - st->print("movq rbp, [rsp + #%d]\t# Save the caller's SP into rbp", (framesize + wordSize)); + st->print("movq rbp, rsp\t# Save the caller's SP into rbp"); + if (framesize > 0) { + st->print("\n\t"); + st->print("addq rbp, #%d", framesize); + } } }
--- a/src/cpu/zero/vm/frame_zero.cpp Tue Dec 22 12:28:01 2015 -0800 +++ b/src/cpu/zero/vm/frame_zero.cpp Tue Jan 05 08:40:50 2016 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2015, Oracle and/or its affiliates. All rights reserved. * Copyright 2007, 2008, 2009, 2010, 2011 Red Hat, Inc. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -216,7 +216,7 @@ valuebuf[buflen - 1] = '\0'; // Print the result - st->print_cr(" " PTR_FORMAT ": %-21s = %s", addr, fieldbuf, valuebuf); + st->print_cr(" " PTR_FORMAT ": %-21s = %s", p2i(addr), fieldbuf, valuebuf); } }
--- a/src/os/aix/vm/perfMemory_aix.cpp Tue Dec 22 12:28:01 2015 -0800 +++ b/src/os/aix/vm/perfMemory_aix.cpp Tue Jan 05 08:40:50 2016 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2015, Oracle and/or its affiliates. All rights reserved. * Copyright 2012, 2013 SAP AG. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -454,13 +454,27 @@ *saved_cwd_fd = result; } - // Set the current directory to dirname by using the fd of the directory. + // Set the current directory to dirname by using the fd of the directory and + // handle errors, otherwise shared memory files will be created in cwd. result = fchdir(fd); - - return dirp; + if (result == OS_ERR) { + if (PrintMiscellaneous && Verbose) { + warning("could not change to directory %s", dirname); + } + if (*saved_cwd_fd != -1) { + ::close(*saved_cwd_fd); + *saved_cwd_fd = -1; + } + // Close the directory. + os::closedir(dirp); + return NULL; + } else { + return dirp; + } } // Close the directory and restore the current working directory. +// static void close_directory_secure_cwd(DIR* dirp, int saved_cwd_fd) { int result;
--- a/src/os/bsd/dtrace/hotspot.d Tue Dec 22 12:28:01 2015 -0800 +++ b/src/os/bsd/dtrace/hotspot.d Tue Jan 05 08:40:50 2016 -0800 @@ -47,8 +47,8 @@ probe mem__pool__gc__end( char*, uintptr_t, char*, uintptr_t, uintptr_t, uintptr_t, uintptr_t, uintptr_t); - probe thread__probe__start(char*, uintptr_t, uintptr_t, uintptr_t, uintptr_t); - probe thread__probe__stop(char*, uintptr_t, uintptr_t, uintptr_t, uintptr_t); + probe thread__start(char*, uintptr_t, uintptr_t, uintptr_t, uintptr_t); + probe thread__stop(char*, uintptr_t, uintptr_t, uintptr_t, uintptr_t); probe thread__sleep__begin(long long); probe thread__sleep__end(int); probe thread__yield(); @@ -68,7 +68,7 @@ probe monitor__contended__entered(uintptr_t, uintptr_t, char*, uintptr_t); probe monitor__contended__exit(uintptr_t, uintptr_t, char*, uintptr_t); probe monitor__wait(uintptr_t, uintptr_t, char*, uintptr_t, uintptr_t); - probe monitor__probe__waited(uintptr_t, uintptr_t, char*, uintptr_t); + probe monitor__waited(uintptr_t, uintptr_t, char*, uintptr_t); probe monitor__notify(uintptr_t, uintptr_t, char*, uintptr_t); probe monitor__notifyAll(uintptr_t, uintptr_t, char*, uintptr_t);
--- a/src/os/bsd/vm/perfMemory_bsd.cpp Tue Dec 22 12:28:01 2015 -0800 +++ b/src/os/bsd/vm/perfMemory_bsd.cpp Tue Jan 05 08:40:50 2016 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2015, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -375,10 +375,23 @@ *saved_cwd_fd = result; } - // Set the current directory to dirname by using the fd of the directory. + // Set the current directory to dirname by using the fd of the directory and + // handle errors, otherwise shared memory files will be created in cwd. result = fchdir(fd); - - return dirp; + if (result == OS_ERR) { + if (PrintMiscellaneous && Verbose) { + warning("could not change to directory %s", dirname); + } + if (*saved_cwd_fd != -1) { + ::close(*saved_cwd_fd); + *saved_cwd_fd = -1; + } + // Close the directory. + os::closedir(dirp); + return NULL; + } else { + return dirp; + } } // Close the directory and restore the current working directory.
--- a/src/os/linux/vm/perfMemory_linux.cpp Tue Dec 22 12:28:01 2015 -0800 +++ b/src/os/linux/vm/perfMemory_linux.cpp Tue Jan 05 08:40:50 2016 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2015, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -374,10 +374,23 @@ *saved_cwd_fd = result; } - // Set the current directory to dirname by using the fd of the directory. + // Set the current directory to dirname by using the fd of the directory and + // handle errors, otherwise shared memory files will be created in cwd. result = fchdir(fd); - - return dirp; + if (result == OS_ERR) { + if (PrintMiscellaneous && Verbose) { + warning("could not change to directory %s", dirname); + } + if (*saved_cwd_fd != -1) { + ::close(*saved_cwd_fd); + *saved_cwd_fd = -1; + } + // Close the directory. + os::closedir(dirp); + return NULL; + } else { + return dirp; + } } // Close the directory and restore the current working directory.
--- a/src/os/solaris/vm/os_solaris.cpp Tue Dec 22 12:28:01 2015 -0800 +++ b/src/os/solaris/vm/os_solaris.cpp Tue Jan 05 08:40:50 2016 -0800 @@ -178,75 +178,6 @@ static void unpackTime(timespec* absTime, bool isAbsolute, jlong time); -// Thread Local Storage -// This is common to all Solaris platforms so it is defined here, -// in this common file. -// The declarations are in the os_cpu threadLS*.hpp files. -// -// Static member initialization for TLS -Thread* ThreadLocalStorage::_get_thread_cache[ThreadLocalStorage::_pd_cache_size] = {NULL}; - -#ifndef PRODUCT -#define _PCT(n,d) ((100.0*(double)(n))/(double)(d)) - -int ThreadLocalStorage::_tcacheHit = 0; -int ThreadLocalStorage::_tcacheMiss = 0; - -void ThreadLocalStorage::print_statistics() { - int total = _tcacheMiss+_tcacheHit; - tty->print_cr("Thread cache hits %d misses %d total %d percent %f\n", - _tcacheHit, _tcacheMiss, total, _PCT(_tcacheHit, total)); -} -#undef _PCT -#endif // PRODUCT - -Thread* ThreadLocalStorage::get_thread_via_cache_slowly(uintptr_t raw_id, - int index) { - Thread *thread = get_thread_slow(); - if (thread != NULL) { - address sp = os::current_stack_pointer(); - guarantee(thread->_stack_base == NULL || - (sp <= thread->_stack_base && - sp >= thread->_stack_base - thread->_stack_size) || - is_error_reported(), - "sp must be inside of selected thread stack"); - - thread->set_self_raw_id(raw_id); // mark for quick retrieval - _get_thread_cache[ index ] = thread; - } - return thread; -} - - -static const double all_zero[ sizeof(Thread) / sizeof(double) + 1 ] = {0}; -#define NO_CACHED_THREAD ((Thread*)all_zero) - -void ThreadLocalStorage::pd_set_thread(Thread* thread) { - - // Store the new value before updating the cache to prevent a race - // between get_thread_via_cache_slowly() and this store operation. - os::thread_local_storage_at_put(ThreadLocalStorage::thread_index(), thread); - - // Update thread cache with new thread if setting on thread create, - // or NO_CACHED_THREAD (zeroed) thread if resetting thread on exit. - uintptr_t raw = pd_raw_thread_id(); - int ix = pd_cache_index(raw); - _get_thread_cache[ix] = thread == NULL ? NO_CACHED_THREAD : thread; -} - -void ThreadLocalStorage::pd_init() { - for (int i = 0; i < _pd_cache_size; i++) { - _get_thread_cache[i] = NO_CACHED_THREAD; - } -} - -// Invalidate all the caches (happens to be the same as pd_init). -void ThreadLocalStorage::pd_invalidate_all() { pd_init(); } - -#undef NO_CACHED_THREAD - -// END Thread Local Storage - static inline size_t adjust_stack_size(address base, size_t size) { if ((ssize_t)size < 0) { // 4759953: Compensate for ridiculous stack size. @@ -1473,64 +1404,6 @@ return (int)(_initial_pid ? _initial_pid : getpid()); } -int os::allocate_thread_local_storage() { - // %%% in Win32 this allocates a memory segment pointed to by a - // register. Dan Stein can implement a similar feature in - // Solaris. Alternatively, the VM can do the same thing - // explicitly: malloc some storage and keep the pointer in a - // register (which is part of the thread's context) (or keep it - // in TLS). - // %%% In current versions of Solaris, thr_self and TSD can - // be accessed via short sequences of displaced indirections. - // The value of thr_self is available as %g7(36). - // The value of thr_getspecific(k) is stored in %g7(12)(4)(k*4-4), - // assuming that the current thread already has a value bound to k. - // It may be worth experimenting with such access patterns, - // and later having the parameters formally exported from a Solaris - // interface. I think, however, that it will be faster to - // maintain the invariant that %g2 always contains the - // JavaThread in Java code, and have stubs simply - // treat %g2 as a caller-save register, preserving it in a %lN. - thread_key_t tk; - if (thr_keycreate( &tk, NULL ) ) - fatal(err_msg("os::allocate_thread_local_storage: thr_keycreate failed " - "(%s)", strerror(errno))); - return int(tk); -} - -void os::free_thread_local_storage(int index) { - // %%% don't think we need anything here - // if ( pthread_key_delete((pthread_key_t) tk) ) - // fatal("os::free_thread_local_storage: pthread_key_delete failed"); -} - -#define SMALLINT 32 // libthread allocate for tsd_common is a version specific - // small number - point is NO swap space available -void os::thread_local_storage_at_put(int index, void* value) { - // %%% this is used only in threadLocalStorage.cpp - if (thr_setspecific((thread_key_t)index, value)) { - if (errno == ENOMEM) { - vm_exit_out_of_memory(SMALLINT, OOM_MALLOC_ERROR, - "thr_setspecific: out of swap space"); - } else { - fatal(err_msg("os::thread_local_storage_at_put: thr_setspecific failed " - "(%s)", strerror(errno))); - } - } else { - ThreadLocalStorage::set_thread_in_slot ((Thread *) value) ; - } -} - -// This function could be called before TLS is initialized, for example, when -// VM receives an async signal or when VM causes a fatal error during -// initialization. Return NULL if thr_getspecific() fails. -void* os::thread_local_storage_at(int index) { - // %%% this is used only in threadLocalStorage.cpp - void* r = NULL; - return thr_getspecific((thread_key_t)index, &r) != 0 ? NULL : r; -} - - // gethrtime() should be monotonic according to the documentation, // but some virtualized platforms are known to break this guarantee. // getTimeNanos() must be guaranteed not to move backwards, so we
--- a/src/os/solaris/vm/perfMemory_solaris.cpp Tue Dec 22 12:28:01 2015 -0800 +++ b/src/os/solaris/vm/perfMemory_solaris.cpp Tue Jan 05 08:40:50 2016 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2015, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -377,10 +377,23 @@ *saved_cwd_fd = result; } - // Set the current directory to dirname by using the fd of the directory. + // Set the current directory to dirname by using the fd of the directory and + // handle errors, otherwise shared memory files will be created in cwd. result = fchdir(fd); - - return dirp; + if (result == OS_ERR) { + if (PrintMiscellaneous && Verbose) { + warning("could not change to directory %s", dirname); + } + if (*saved_cwd_fd != -1) { + ::close(*saved_cwd_fd); + *saved_cwd_fd = -1; + } + // Close the directory. + os::closedir(dirp); + return NULL; + } else { + return dirp; + } } // Close the directory and restore the current working directory.
--- a/src/os/solaris/vm/thread_solaris.inline.hpp Tue Dec 22 12:28:01 2015 -0800 +++ b/src/os/solaris/vm/thread_solaris.inline.hpp Tue Jan 05 08:40:50 2016 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2015, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -40,19 +40,12 @@ // For SPARC, to avoid excessive register window spill-fill faults, // we aggressively inline these routines. -inline Thread* ThreadLocalStorage::thread() { - // don't use specialized code if +UseMallocOnly -- may confuse Purify et al. - debug_only(if (UseMallocOnly) return get_thread_slow();); +inline void ThreadLocalStorage::set_thread(Thread* thread) { + _thr_current = thread; +} - uintptr_t raw = pd_raw_thread_id(); - int ix = pd_cache_index(raw); - Thread* candidate = ThreadLocalStorage::_get_thread_cache[ix]; - if (candidate->self_raw_id() == raw) { - // hit - return candidate; - } else { - return ThreadLocalStorage::get_thread_via_cache_slowly(raw, ix); - } +inline Thread* ThreadLocalStorage::thread() { + return _thr_current; } #endif // OS_SOLARIS_VM_THREAD_SOLARIS_INLINE_HPP
--- a/src/os_cpu/linux_zero/vm/os_linux_zero.cpp Tue Dec 22 12:28:01 2015 -0800 +++ b/src/os_cpu/linux_zero/vm/os_linux_zero.cpp Tue Jan 05 08:40:50 2016 -0800 @@ -55,8 +55,8 @@ #include "utilities/vmError.hpp" address os::current_stack_pointer() { - address dummy = (address) &dummy; - return dummy; + // return the address of the current function + return (address)__builtin_frame_address(0); } frame os::get_sender_for_C_frame(frame* fr) {
--- a/src/os_cpu/solaris_sparc/vm/threadLS_solaris_sparc.cpp Tue Dec 22 12:28:01 2015 -0800 +++ b/src/os_cpu/solaris_sparc/vm/threadLS_solaris_sparc.cpp Tue Jan 05 08:40:50 2016 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 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 @@ -26,19 +26,26 @@ #include "runtime/thread.inline.hpp" #include "runtime/threadLocalStorage.hpp" -// Provides an entry point we can link against and -// a buffer we can emit code into. The buffer is -// filled by ThreadLocalStorage::generate_code_for_get_thread -// and called from ThreadLocalStorage::thread() +// True thread-local variable +__thread Thread * ThreadLocalStorage::_thr_current = NULL; + +// Implementations needed to support the shared API -#include <sys/systeminfo.h> +void ThreadLocalStorage::pd_invalidate_all() {} // nothing to do -// The portable TLS mechanism (get_thread_via_cache) is enough on SPARC. -// There is no need for hand-assembling a special function. -void ThreadLocalStorage::generate_code_for_get_thread() { +bool ThreadLocalStorage::_initialized = false; + +void ThreadLocalStorage::init() { + _initialized = true; } -void ThreadLocalStorage::set_thread_in_slot (Thread * self) {} +bool ThreadLocalStorage::is_initialized() { + return _initialized; +} + +Thread* ThreadLocalStorage::get_thread_slow() { + return thread(); +} extern "C" Thread* get_thread() { return ThreadLocalStorage::thread();
--- a/src/os_cpu/solaris_sparc/vm/threadLS_solaris_sparc.hpp Tue Dec 22 12:28:01 2015 -0800 +++ b/src/os_cpu/solaris_sparc/vm/threadLS_solaris_sparc.hpp Tue Jan 05 08:40:50 2016 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2015, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,47 +25,15 @@ #ifndef OS_CPU_SOLARIS_SPARC_VM_THREADLS_SOLARIS_SPARC_HPP #define OS_CPU_SOLARIS_SPARC_VM_THREADLS_SOLARIS_SPARC_HPP -public: - // Java Thread - force inlining - static inline Thread* thread() ; +// Solaris specific implementation involves simple, direct use +// of a compiler-based thread-local variable private: - static Thread* _get_thread_cache[]; // index by [(raw_id>>9)^(raw_id>>20) % _pd_cache_size] - static Thread* get_thread_via_cache_slowly(uintptr_t raw_id, int index); + static __thread Thread * _thr_current; - NOT_PRODUCT(static int _tcacheHit;) - NOT_PRODUCT(static int _tcacheMiss;) + static bool _initialized; // needed for shared API public: - - // Print cache hit/miss statistics - static void print_statistics() PRODUCT_RETURN; - - enum Constants { - _pd_cache_size = 256*2 // projected typical # of threads * 2 - }; - - static void set_thread_in_slot (Thread *) ; - - static uintptr_t pd_raw_thread_id() { - return _raw_thread_id(); - } - - static int pd_cache_index(uintptr_t raw_id) { - // Hash function: From email from Dave: - // The hash function deserves an explanation. %g7 points to libthread's - // "thread" structure. On T1 the thread structure is allocated on the - // user's stack (yes, really!) so the ">>20" handles T1 where the JVM's - // stack size is usually >= 1Mb. The ">>9" is for T2 where Roger allocates - // globs of thread blocks contiguously. The "9" has to do with the - // expected size of the T2 thread structure. If these constants are wrong - // the worst thing that'll happen is that the hit rate for heavily threaded - // apps won't be as good as it could be. If you want to burn another - // shift+xor you could mix together _all of the %g7 bits to form the hash, - // but I think that's excessive. Making the change above changed the - // T$ miss rate on SpecJBB (on a 16X system) from about 3% to imperceptible. - uintptr_t ix = (int) (((raw_id >> 9) ^ (raw_id >> 20)) % _pd_cache_size); - return ix; - } + static inline Thread* thread(); #endif // OS_CPU_SOLARIS_SPARC_VM_THREADLS_SOLARIS_SPARC_HPP
--- a/src/os_cpu/solaris_x86/vm/assembler_solaris_x86.cpp Tue Dec 22 12:28:01 2015 -0800 +++ b/src/os_cpu/solaris_x86/vm/assembler_solaris_x86.cpp Tue Jan 05 08:40:50 2016 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2010, 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 @@ -23,11 +23,10 @@ */ #include "precompiled.hpp" -#include "asm/macroAssembler.hpp" #include "asm/macroAssembler.inline.hpp" #include "runtime/os.hpp" #include "runtime/threadLocalStorage.hpp" - +#include "runtime/thread.inline.hpp" void MacroAssembler::int3() { push(rax); @@ -39,98 +38,32 @@ pop(rax); } -#define __ _masm-> -#ifndef _LP64 -static void slow_call_thr_specific(MacroAssembler* _masm, Register thread) { - - // slow call to of thr_getspecific - // int thr_getspecific(thread_key_t key, void **value); - // Consider using pthread_getspecific instead. - -__ push(0); // allocate space for return value - if (thread != rax) __ push(rax); // save rax, if caller still wants it -__ push(rcx); // save caller save -__ push(rdx); // save caller save +// This is simply a call to ThreadLocalStorage::thread() +void MacroAssembler::get_thread(Register thread) { if (thread != rax) { -__ lea(thread, Address(rsp, 3 * sizeof(int))); // address of return value - } else { -__ lea(thread, Address(rsp, 2 * sizeof(int))); // address of return value + push(rax); } -__ push(thread); // and pass the address -__ push(ThreadLocalStorage::thread_index()); // the key -__ call(RuntimeAddress(CAST_FROM_FN_PTR(address, thr_getspecific))); -__ increment(rsp, 2 * wordSize); -__ pop(rdx); -__ pop(rcx); - if (thread != rax) __ pop(rax); -__ pop(thread); - -} -#else -static void slow_call_thr_specific(MacroAssembler* _masm, Register thread) { - // slow call to of thr_getspecific - // int thr_getspecific(thread_key_t key, void **value); - // Consider using pthread_getspecific instead. + push(rdi); + push(rsi); + push(rdx); + push(rcx); + push(r8); + push(r9); + push(r10); + push(r11); + call(RuntimeAddress(CAST_FROM_FN_PTR(address, ThreadLocalStorage::thread))); + + pop(r11); + pop(r10); + pop(r9); + pop(r8); + pop(rcx); + pop(rdx); + pop(rsi); + pop(rdi); if (thread != rax) { -__ push(rax); - } -__ push(0); // space for return value -__ push(rdi); -__ push(rsi); -__ lea(rsi, Address(rsp, 16)); // pass return value address -__ push(rdx); -__ push(rcx); -__ push(r8); -__ push(r9); -__ push(r10); - // XXX -__ mov(r10, rsp); -__ andptr(rsp, -16); -__ push(r10); -__ push(r11); - -__ movl(rdi, ThreadLocalStorage::thread_index()); -__ call(RuntimeAddress(CAST_FROM_FN_PTR(address, thr_getspecific))); - -__ pop(r11); -__ pop(rsp); -__ pop(r10); -__ pop(r9); -__ pop(r8); -__ pop(rcx); -__ pop(rdx); -__ pop(rsi); -__ pop(rdi); -__ pop(thread); // load return value - if (thread != rax) { -__ pop(rax); + movl(thread, rax); + pop(rax); } } -#endif //LP64 - -void MacroAssembler::get_thread(Register thread) { - - int segment = NOT_LP64(Assembler::GS_segment) LP64_ONLY(Assembler::FS_segment); - // Try to emit a Solaris-specific fast TSD/TLS accessor. - ThreadLocalStorage::pd_tlsAccessMode tlsMode = ThreadLocalStorage::pd_getTlsAccessMode (); - if (tlsMode == ThreadLocalStorage::pd_tlsAccessIndirect) { // T1 - // Use thread as a temporary: mov r, gs:[0]; mov r, [r+tlsOffset] - emit_int8 (segment); - // ExternalAddress doesn't work because it can't take NULL - AddressLiteral null(0, relocInfo::none); - movptr (thread, null); - movptr(thread, Address(thread, ThreadLocalStorage::pd_getTlsOffset())) ; - return ; - } else - if (tlsMode == ThreadLocalStorage::pd_tlsAccessDirect) { // T2 - // mov r, gs:[tlsOffset] - emit_int8 (segment); - AddressLiteral tls_off((address)ThreadLocalStorage::pd_getTlsOffset(), relocInfo::none); - movptr (thread, tls_off); - return ; - } - - slow_call_thr_specific(this, thread); - -}
--- a/src/os_cpu/solaris_x86/vm/threadLS_solaris_x86.cpp Tue Dec 22 12:28:01 2015 -0800 +++ b/src/os_cpu/solaris_x86/vm/threadLS_solaris_x86.cpp Tue Jan 05 08:40:50 2016 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 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 @@ -26,167 +26,27 @@ #include "runtime/thread.inline.hpp" #include "runtime/threadLocalStorage.hpp" -#ifdef AMD64 -extern "C" Thread* fs_load(ptrdiff_t tlsOffset); -extern "C" intptr_t fs_thread(); -#else -// From solaris_i486.s -extern "C" Thread* gs_load(ptrdiff_t tlsOffset); -extern "C" intptr_t gs_thread(); -#endif // AMD64 +// True thread-local variable +__thread Thread * ThreadLocalStorage::_thr_current = NULL; + +// Implementations needed to support the shared API -// tlsMode encoding: -// -// pd_tlsAccessUndefined : uninitialized -// pd_tlsAccessSlow : not available -// pd_tlsAccessIndirect : -// old-style indirect access - present in "T1" libthread. -// use thr_slot_sync_allocate() to attempt to allocate a slot. -// pd_tlsAccessDirect : -// new-style direct access - present in late-model "T2" libthread. -// Allocate the offset (slot) via _thr_slot_offset() or by -// defining an IE- or LE-mode TLS/TSD slot in the launcher and then passing -// that offset into libjvm.so. -// See http://sac.eng/Archives/CaseLog/arc/PSARC/2003/159/. -// -// Note that we have a capability gap - some early model T2 forms -// (e.g., unpatched S9) have neither _thr_slot_sync_allocate() nor -// _thr_slot_offset(). In that case we revert to the usual -// thr_getspecific accessor. -// +void ThreadLocalStorage::pd_invalidate_all() {} // nothing to do -static ThreadLocalStorage::pd_tlsAccessMode tlsMode = ThreadLocalStorage::pd_tlsAccessUndefined ; -static ptrdiff_t tlsOffset = 0 ; -static thread_key_t tlsKey ; - -typedef int (*TSSA_Entry) (ptrdiff_t *, int, int) ; -typedef ptrdiff_t (*TSO_Entry) (int) ; +bool ThreadLocalStorage::_initialized = false; -ThreadLocalStorage::pd_tlsAccessMode ThreadLocalStorage::pd_getTlsAccessMode () -{ - guarantee (tlsMode != pd_tlsAccessUndefined, "tlsMode not set") ; - return tlsMode ; -} - -ptrdiff_t ThreadLocalStorage::pd_getTlsOffset () { - guarantee (tlsMode != pd_tlsAccessUndefined, "tlsMode not set") ; - return tlsOffset ; +void ThreadLocalStorage::init() { + _initialized = true; } -// TODO: Consider the following improvements: -// -// 1. Convert from thr_*specific* to pthread_*specific*. -// The pthread_ forms are slightly faster. Also, the -// pthread_ forms have a pthread_key_delete() API which -// would aid in clean JVM shutdown and the eventual goal -// of permitting a JVM to reinstantiate itself withing a process. -// -// 2. See ThreadLocalStorage::init(). We end up allocating -// two TLS keys during VM startup. That's benign, but we could collapse -// down to one key without too much trouble. -// -// 3. MacroAssembler::get_thread() currently emits calls to thr_getspecific(). -// Modify get_thread() to call Thread::current() instead. -// -// 4. Thread::current() currently uses a cache keyed by %gs:[0]. -// (The JVM has PSARC permission to use %g7/%gs:[0] -// as an opaque temporally unique thread identifier). -// For C++ access to a thread's reflexive "self" pointer we -// should consider using one of the following: -// a. a radix tree keyed by %esp - as in EVM. -// This requires two loads (the 2nd dependent on the 1st), but -// is easily inlined and doesn't require a "miss" slow path. -// b. a fast TLS/TSD slot allocated by _thr_slot_offset -// or _thr_slot_sync_allocate. -// -// 5. 'generate_code_for_get_thread' is a misnomer. -// We should change it to something more general like -// pd_ThreadSelf_Init(), for instance. -// - -static void AllocateTLSOffset () -{ - int rslt ; - TSSA_Entry tssa ; - TSO_Entry tso ; - ptrdiff_t off ; - - guarantee (tlsMode == ThreadLocalStorage::pd_tlsAccessUndefined, "tlsMode not set") ; - tlsMode = ThreadLocalStorage::pd_tlsAccessSlow ; - tlsOffset = 0 ; -#ifndef AMD64 - - tssa = (TSSA_Entry) dlsym (RTLD_DEFAULT, "thr_slot_sync_allocate") ; - if (tssa != NULL) { - off = -1 ; - rslt = (*tssa)(&off, NULL, NULL) ; // (off,dtor,darg) - if (off != -1) { - tlsOffset = off ; - tlsMode = ThreadLocalStorage::pd_tlsAccessIndirect ; - return ; - } - } - - rslt = thr_keycreate (&tlsKey, NULL) ; - if (rslt != 0) { - tlsMode = ThreadLocalStorage::pd_tlsAccessSlow ; // revert to slow mode - return ; - } - - tso = (TSO_Entry) dlsym (RTLD_DEFAULT, "_thr_slot_offset") ; - if (tso != NULL) { - off = (*tso)(tlsKey) ; - if (off >= 0) { - tlsOffset = off ; - tlsMode = ThreadLocalStorage::pd_tlsAccessDirect ; - return ; - } - } - - // Failure: Too bad ... we've allocated a TLS slot we don't need and there's - // no provision in the ABI for returning the slot. - // - // If we didn't find a slot then then: - // 1. We might be on liblwp. - // 2. We might be on T2 libthread, but all "fast" slots are already - // consumed - // 3. We might be on T1, and all TSD (thr_slot_sync_allocate) slots are - // consumed. - // 4. We might be on T2 libthread, but it's be re-architected - // so that fast slots are no longer g7-relative. - // - - tlsMode = ThreadLocalStorage::pd_tlsAccessSlow ; - return ; -#endif // AMD64 +bool ThreadLocalStorage::is_initialized() { + return _initialized; } -void ThreadLocalStorage::generate_code_for_get_thread() { - AllocateTLSOffset() ; +Thread* ThreadLocalStorage::get_thread_slow() { + return thread(); } -void ThreadLocalStorage::set_thread_in_slot(Thread *thread) { - guarantee (tlsMode != pd_tlsAccessUndefined, "tlsMode not set") ; - if (tlsMode == pd_tlsAccessIndirect) { -#ifdef AMD64 - intptr_t tbase = fs_thread(); -#else - intptr_t tbase = gs_thread(); -#endif // AMD64 - *((Thread**) (tbase + tlsOffset)) = thread ; - } else - if (tlsMode == pd_tlsAccessDirect) { - thr_setspecific (tlsKey, (void *) thread) ; - // set with thr_setspecific and then readback with gs_load to validate. -#ifdef AMD64 - guarantee (thread == fs_load(tlsOffset), "tls readback failure") ; -#else - guarantee (thread == gs_load(tlsOffset), "tls readback failure") ; -#endif // AMD64 - } -} - - extern "C" Thread* get_thread() { return ThreadLocalStorage::thread(); }
--- a/src/os_cpu/solaris_x86/vm/threadLS_solaris_x86.hpp Tue Dec 22 12:28:01 2015 -0800 +++ b/src/os_cpu/solaris_x86/vm/threadLS_solaris_x86.hpp Tue Jan 05 08:40:50 2016 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2015, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,61 +25,15 @@ #ifndef OS_CPU_SOLARIS_X86_VM_THREADLS_SOLARIS_X86_HPP #define OS_CPU_SOLARIS_X86_VM_THREADLS_SOLARIS_X86_HPP -// Processor dependent parts of ThreadLocalStorage +// Solaris specific implementation involves simple, direct use +// of a compiler-based thread-local variable private: - static Thread* _get_thread_cache[]; // index by [(raw_id>>9)^(raw_id>>20) % _pd_cache_size] - static Thread* get_thread_via_cache_slowly(uintptr_t raw_id, int index); + static __thread Thread * _thr_current; - NOT_PRODUCT(static int _tcacheHit;) - NOT_PRODUCT(static int _tcacheMiss;) + static bool _initialized; // needed for shared API public: - // Cache hit/miss statistics - static void print_statistics() PRODUCT_RETURN; - - enum Constants { -#ifdef AMD64 - _pd_cache_size = 256*2 // projected typical # of threads * 2 -#else - _pd_cache_size = 128*2 // projected typical # of threads * 2 -#endif // AMD64 - }; - - enum pd_tlsAccessMode { - pd_tlsAccessUndefined = -1, - pd_tlsAccessSlow = 0, - pd_tlsAccessIndirect = 1, - pd_tlsAccessDirect = 2 - } ; - - static void set_thread_in_slot (Thread *) ; - - static pd_tlsAccessMode pd_getTlsAccessMode () ; - static ptrdiff_t pd_getTlsOffset () ; - - static uintptr_t pd_raw_thread_id() { -#ifdef _GNU_SOURCE -#ifdef AMD64 - uintptr_t rv; - __asm__ __volatile__ ("movq %%fs:0, %0" : "=r"(rv)); - return rv; -#else - return gs_thread(); -#endif // AMD64 -#else //_GNU_SOURCE - return _raw_thread_id(); -#endif //_GNU_SOURCE - } - - static int pd_cache_index(uintptr_t raw_id) { - // Copied from the sparc version. Dave said it should also work fine - // for solx86. - int ix = (int) (((raw_id >> 9) ^ (raw_id >> 20)) % _pd_cache_size); - return ix; - } - - // Java Thread static inline Thread* thread(); #endif // OS_CPU_SOLARIS_X86_VM_THREADLS_SOLARIS_X86_HPP
--- a/src/share/vm/c1/c1_ValueType.cpp Tue Dec 22 12:28:01 2015 -0800 +++ b/src/share/vm/c1/c1_ValueType.cpp Tue Jan 05 08:40:50 2016 -0800 @@ -153,7 +153,19 @@ case T_FLOAT : return new FloatConstant (value.as_float ()); case T_DOUBLE : return new DoubleConstant(value.as_double()); case T_ARRAY : // fall through (ciConstant doesn't have an array accessor) - case T_OBJECT : return new ObjectConstant(value.as_object()); + case T_OBJECT : { + // TODO: Common the code with GraphBuilder::load_constant? + ciObject* obj = value.as_object(); + if (obj->is_null_object()) + return objectNull; + if (obj->is_loaded()) { + if (obj->is_array()) + return new ArrayConstant(obj->as_array()); + else if (obj->is_instance()) + return new InstanceConstant(obj->as_instance()); + } + return new ObjectConstant(obj); + } } ShouldNotReachHere(); return illegalType;
--- a/src/share/vm/ci/ciField.cpp Tue Dec 22 12:28:01 2015 -0800 +++ b/src/share/vm/ci/ciField.cpp Tue Jan 05 08:40:50 2016 -0800 @@ -187,6 +187,14 @@ // Even if general trusting is disabled, trust system-built closures in these packages. if (holder->is_in_package("java/lang/invoke") || holder->is_in_package("sun/invoke")) return true; + // Trust Atomic*FieldUpdaters: they are very important for performance, and make up one + // more reason not to use Unsafe, if their final fields are trusted. See more in JDK-8140483. + if (holder->name() == ciSymbol::java_util_concurrent_atomic_AtomicIntegerFieldUpdater_Impl() || + holder->name() == ciSymbol::java_util_concurrent_atomic_AtomicLongFieldUpdater_CASUpdater() || + holder->name() == ciSymbol::java_util_concurrent_atomic_AtomicLongFieldUpdater_LockedUpdater() || + holder->name() == ciSymbol::java_util_concurrent_atomic_AtomicReferenceFieldUpdater_Impl()) { + return true; + } return TrustFinalNonStaticFields; }
--- a/src/share/vm/classfile/classLoader.cpp Tue Dec 22 12:28:01 2015 -0800 +++ b/src/share/vm/classfile/classLoader.cpp Tue Jan 05 08:40:50 2016 -0800 @@ -414,30 +414,30 @@ } #endif -void ClassLoader::trace_class_path(const char* msg, const char* name) { +void ClassLoader::trace_class_path(outputStream* out, const char* msg, const char* name) { if (!TraceClassPaths) { return; } if (msg) { - tty->print("%s", msg); + out->print("%s", msg); } if (name) { if (strlen(name) < 256) { - tty->print("%s", name); + out->print("%s", name); } else { // For very long paths, we need to print each character separately, // as print_cr() has a length limit while (name[0] != '\0') { - tty->print("%c", name[0]); + out->print("%c", name[0]); name++; } } } if (msg && msg[0] == '[') { - tty->print_cr("]"); + out->print_cr("]"); } else { - tty->cr(); + out->cr(); } } @@ -583,7 +583,7 @@ // Don't print sys_class_path - this is the bootcp of this current VM process, not necessarily // the same as the bootcp of the shared archive. } else { - trace_class_path("[Bootstrap loader class path=", sys_class_path); + trace_class_path(tty, "[Bootstrap loader class path=", sys_class_path); } #if INCLUDE_CDS if (DumpSharedSpaces) {
--- a/src/share/vm/classfile/classLoader.hpp Tue Dec 22 12:28:01 2015 -0800 +++ b/src/share/vm/classfile/classLoader.hpp Tue Jan 05 08:40:50 2016 -0800 @@ -346,7 +346,7 @@ static void exit_with_path_failure(const char* error, const char* message); #endif - static void trace_class_path(const char* msg, const char* name = NULL); + static void trace_class_path(outputStream* out, const char* msg, const char* name = NULL); // VM monitoring and management support static jlong classloader_time_ms();
--- a/src/share/vm/classfile/sharedPathsMiscInfo.cpp Tue Dec 22 12:28:01 2015 -0800 +++ b/src/share/vm/classfile/sharedPathsMiscInfo.cpp Tue Jan 05 08:40:50 2016 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -67,7 +67,7 @@ } bool SharedPathsMiscInfo::fail(const char* msg, const char* name) { - ClassLoader::trace_class_path(msg, name); + ClassLoader::trace_class_path(tty, msg, name); MetaspaceShared::set_archive_loading_failed(); return false; }
--- a/src/share/vm/classfile/sharedPathsMiscInfo.hpp Tue Dec 22 12:28:01 2015 -0800 +++ b/src/share/vm/classfile/sharedPathsMiscInfo.hpp Tue Jan 05 08:40:50 2016 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -64,7 +64,7 @@ bool read(void* ptr, size_t size); static void trace_class_path(const char* msg, const char* name = NULL) { - ClassLoader::trace_class_path(msg, name); + ClassLoader::trace_class_path(tty, msg, name); } protected: static bool fail(const char* msg, const char* name = NULL);
--- a/src/share/vm/classfile/vmSymbols.hpp Tue Dec 22 12:28:01 2015 -0800 +++ b/src/share/vm/classfile/vmSymbols.hpp Tue Jan 05 08:40:50 2016 -0800 @@ -203,7 +203,11 @@ template(java_lang_StackTraceElement, "java/lang/StackTraceElement") \ \ /* Concurrency support */ \ - template(java_util_concurrent_locks_AbstractOwnableSynchronizer, "java/util/concurrent/locks/AbstractOwnableSynchronizer") \ + template(java_util_concurrent_locks_AbstractOwnableSynchronizer, "java/util/concurrent/locks/AbstractOwnableSynchronizer") \ + template(java_util_concurrent_atomic_AtomicIntegerFieldUpdater_Impl, "java/util/concurrent/atomic/AtomicIntegerFieldUpdater$AtomicIntegerFieldUpdaterImpl") \ + template(java_util_concurrent_atomic_AtomicLongFieldUpdater_CASUpdater, "java/util/concurrent/atomic/AtomicLongFieldUpdater$CASUpdater") \ + 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(sun_misc_Contended_signature, "Lsun/misc/Contended;") \ \ /* class symbols needed by intrinsics */ \
--- a/src/share/vm/code/nmethod.cpp Tue Dec 22 12:28:01 2015 -0800 +++ b/src/share/vm/code/nmethod.cpp Tue Jan 05 08:40:50 2016 -0800 @@ -1619,7 +1619,11 @@ // During GC the is_alive closure is non-NULL, and is used to // determine liveness of dependees that need to be updated. if (is_alive == NULL || klass->is_loader_alive(is_alive)) { - InstanceKlass::cast(klass)->remove_dependent_nmethod(this); + // The GC defers deletion of this entry, since there might be multiple threads + // iterating over the _dependencies graph. Other call paths are single-threaded + // and may delete it immediately. + bool delete_immediately = is_alive == NULL; + InstanceKlass::cast(klass)->remove_dependent_nmethod(this, delete_immediately); } } }
--- a/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp Tue Dec 22 12:28:01 2015 -0800 +++ b/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp Tue Jan 05 08:40:50 2016 -0800 @@ -2331,6 +2331,7 @@ case GCCause::_java_lang_system_gc: return ExplicitGCInvokesConcurrent; case GCCause::_g1_humongous_allocation: return true; case GCCause::_update_allocation_context_stats_inc: return true; + case GCCause::_wb_conc_mark: return true; default: return false; } } @@ -5045,12 +5046,8 @@ public: void clean_klass(InstanceKlass* ik) { - ik->clean_implementors_list(_is_alive); - ik->clean_method_data(_is_alive); - - // G1 specific cleanup work that has - // been moved here to be done in parallel. - ik->clean_dependent_nmethods(); + ik->clean_weak_instanceklass_links(_is_alive); + if (JvmtiExport::has_redefined_a_class()) { InstanceKlass::purge_previous_versions(ik); }
--- a/src/share/vm/gc_implementation/g1/vm_operations_g1.cpp Tue Dec 22 12:28:01 2015 -0800 +++ b/src/share/vm/gc_implementation/g1/vm_operations_g1.cpp Tue Jan 05 08:40:50 2016 -0800 @@ -90,12 +90,8 @@ void VM_G1IncCollectionPause::doit() { G1CollectedHeap* g1h = G1CollectedHeap::heap(); - assert(!_should_initiate_conc_mark || - ((_gc_cause == GCCause::_gc_locker && GCLockerInvokesConcurrent) || - (_gc_cause == GCCause::_java_lang_system_gc && ExplicitGCInvokesConcurrent) || - _gc_cause == GCCause::_g1_humongous_allocation || - _gc_cause == GCCause::_update_allocation_context_stats_inc), - "only a GC locker, a System.gc(), stats update or a hum allocation induced GC should start a cycle"); + assert(!_should_initiate_conc_mark || g1h->should_do_concurrent_full_gc(_gc_cause), + "only a GC locker, a System.gc(), stats update, whitebox, or a hum allocation induced GC should start a cycle"); if (_word_size > 0) { // An allocation has been requested. So, try to do that first.
--- a/src/share/vm/gc_implementation/parallelScavenge/psParallelCompact.hpp Tue Dec 22 12:28:01 2015 -0800 +++ b/src/share/vm/gc_implementation/parallelScavenge/psParallelCompact.hpp Tue Jan 05 08:40:50 2016 -0800 @@ -348,7 +348,7 @@ HeapWord* _partial_obj_addr; region_sz_t _partial_obj_size; region_sz_t volatile _dc_and_los; - bool _blocks_filled; + bool volatile _blocks_filled; #ifdef ASSERT size_t _blocks_filled_count; // Number of block table fills. @@ -499,7 +499,9 @@ inline bool ParallelCompactData::RegionData::blocks_filled() const { - return _blocks_filled; + bool result = _blocks_filled; + OrderAccess::acquire(); + return result; } #ifdef ASSERT @@ -513,6 +515,7 @@ inline void ParallelCompactData::RegionData::set_blocks_filled() { + OrderAccess::release(); _blocks_filled = true; // Debug builds count the number of times the table was filled. DEBUG_ONLY(Atomic::inc_ptr(&_blocks_filled_count));
--- a/src/share/vm/gc_interface/gcCause.cpp Tue Dec 22 12:28:01 2015 -0800 +++ b/src/share/vm/gc_interface/gcCause.cpp Tue Jan 05 08:40:50 2016 -0800 @@ -54,6 +54,9 @@ case _wb_young_gc: return "WhiteBox Initiated Young GC"; + case _wb_conc_mark: + return "WhiteBox Initiated Concurrent Mark"; + case _update_allocation_context_stats_inc: case _update_allocation_context_stats_full: return "Update Allocation Context Stats";
--- a/src/share/vm/gc_interface/gcCause.hpp Tue Dec 22 12:28:01 2015 -0800 +++ b/src/share/vm/gc_interface/gcCause.hpp Tue Jan 05 08:40:50 2016 -0800 @@ -47,6 +47,7 @@ _heap_inspection, _heap_dump, _wb_young_gc, + _wb_conc_mark, _update_allocation_context_stats_inc, _update_allocation_context_stats_full,
--- a/src/share/vm/memory/universe.cpp Tue Dec 22 12:28:01 2015 -0800 +++ b/src/share/vm/memory/universe.cpp Tue Jan 05 08:40:50 2016 -0800 @@ -847,12 +847,6 @@ // See needs_explicit_null_check. // Only set the heap base for compressed oops because it indicates // compressed oops for pstack code. - bool verbose = PrintCompressedOopsMode || (PrintMiscellaneous && Verbose); - if (verbose) { - tty->cr(); - tty->print("heap address: " PTR_FORMAT ", size: " SIZE_FORMAT " MB", - Universe::heap()->base(), Universe::heap()->reserved_region().byte_size()/M); - } if (((uint64_t)Universe::heap()->reserved_region().end() > OopEncodingHeapMax)) { // Can't reserve heap below 32Gb. // keep the Universe::narrow_oop_base() set in Universe::reserve_heap() @@ -862,16 +856,8 @@ // are decoded so that NULL is preserved, so this page will not be accessed. Universe::set_narrow_oop_use_implicit_null_checks(false); #endif - if (verbose) { - tty->print(", %s: "PTR_FORMAT, - narrow_oop_mode_to_string(HeapBasedNarrowOop), - Universe::narrow_oop_base()); - } } else { Universe::set_narrow_oop_base(0); - if (verbose) { - tty->print(", %s", narrow_oop_mode_to_string(ZeroBasedNarrowOop)); - } #ifdef _WIN64 if (!Universe::narrow_oop_use_implicit_null_checks()) { // Don't need guard page for implicit checks in indexed addressing @@ -884,17 +870,14 @@ Universe::set_narrow_oop_shift(LogMinObjAlignmentInBytes); } else { Universe::set_narrow_oop_shift(0); - if (verbose) { - tty->print(", %s", narrow_oop_mode_to_string(UnscaledNarrowOop)); - } } } - if (verbose) { - tty->cr(); - tty->cr(); + Universe::set_narrow_ptrs_base(Universe::narrow_oop_base()); + + if (PrintCompressedOopsMode || (PrintMiscellaneous && Verbose)) { + Universe::print_compressed_oops_mode(); } - Universe::set_narrow_ptrs_base(Universe::narrow_oop_base()); } // Universe::narrow_oop_base() is one page below the heap. assert((intptr_t)Universe::narrow_oop_base() <= (intptr_t)(Universe::heap()->base() - @@ -915,6 +898,24 @@ return JNI_OK; } +void Universe::print_compressed_oops_mode() { + tty->cr(); + tty->print("heap address: " PTR_FORMAT ", size: " SIZE_FORMAT " MB", + Universe::heap()->base(), Universe::heap()->reserved_region().byte_size()/M); + + tty->print(", Compressed Oops mode: %s", narrow_oop_mode_to_string(narrow_oop_mode())); + + if (Universe::narrow_oop_base() != 0) { + tty->print(":" PTR_FORMAT, Universe::narrow_oop_base()); + } + + if (Universe::narrow_oop_shift() != 0) { + tty->print(", Oop shift amount: %d", Universe::narrow_oop_shift()); + } + + tty->cr(); + tty->cr(); +} // Reserve the Java heap, which is now the same for all GCs. ReservedSpace Universe::reserve_heap(size_t heap_size, size_t alignment) { @@ -984,11 +985,11 @@ const char* Universe::narrow_oop_mode_to_string(Universe::NARROW_OOP_MODE mode) { switch (mode) { case UnscaledNarrowOop: - return "32-bits Oops"; + return "32-bit"; case ZeroBasedNarrowOop: - return "zero based Compressed Oops"; + return "Zero based"; case HeapBasedNarrowOop: - return "Compressed Oops with base"; + return "Non-zero based"; } ShouldNotReachHere();
--- a/src/share/vm/memory/universe.hpp Tue Dec 22 12:28:01 2015 -0800 +++ b/src/share/vm/memory/universe.hpp Tue Jan 05 08:40:50 2016 -0800 @@ -376,6 +376,8 @@ static void set_narrow_ptrs_base(address a) { _narrow_ptrs_base = a; } static address narrow_ptrs_base() { return _narrow_ptrs_base; } + static void print_compressed_oops_mode(); + // this is set in vm_version on sparc (and then reset in universe afaict) static void set_narrow_oop_shift(int shift) { _narrow_oop._shift = shift;
--- a/src/share/vm/oops/instanceKlass.cpp Tue Dec 22 12:28:01 2015 -0800 +++ b/src/share/vm/oops/instanceKlass.cpp Tue Jan 05 08:40:50 2016 -0800 @@ -1969,7 +1969,7 @@ // find a corresponding bucket otherwise there's a bug in the // recording of dependecies. // -void InstanceKlass::remove_dependent_nmethod(nmethod* nm) { +void InstanceKlass::remove_dependent_nmethod(nmethod* nm, bool delete_immediately) { assert_locked_or_safepoint(CodeCache_lock); nmethodBucket* b = _dependencies; nmethodBucket* last = NULL; @@ -1978,7 +1978,17 @@ int val = b->decrement(); guarantee(val >= 0, err_msg("Underflow: %d", val)); if (val == 0) { - set_has_unloaded_dependent(true); + if (delete_immediately) { + if (last == NULL) { + _dependencies = b->next(); + } else { + last->set_next(b->next()); + } + delete b; + } else { + // The deletion of this entry is deferred until a later, potentially parallel GC phase. + set_has_unloaded_dependent(true); + } } return; } @@ -2318,6 +2328,13 @@ #endif // INCLUDE_ALL_GCS +void InstanceKlass::clean_weak_instanceklass_links(BoolObjectClosure* is_alive) { + clean_implementors_list(is_alive); + clean_method_data(is_alive); + + clean_dependent_nmethods(); +} + void InstanceKlass::clean_implementors_list(BoolObjectClosure* is_alive) { assert(class_loader_data()->is_alive(is_alive), "this klass should be live"); if (is_interface()) {
--- a/src/share/vm/oops/instanceKlass.hpp Tue Dec 22 12:28:01 2015 -0800 +++ b/src/share/vm/oops/instanceKlass.hpp Tue Jan 05 08:40:50 2016 -0800 @@ -785,7 +785,7 @@ // maintenance of deoptimization dependencies int mark_dependent_nmethods(DepChange& changes); void add_dependent_nmethod(nmethod* nm); - void remove_dependent_nmethod(nmethod* nm); + void remove_dependent_nmethod(nmethod* nm, bool delete_immediately); // On-stack replacement support nmethod* osr_nmethods_head() const { return _osr_nmethods_head; }; @@ -974,6 +974,7 @@ void oop_follow_contents(oop obj); int oop_adjust_pointers(oop obj); + void clean_weak_instanceklass_links(BoolObjectClosure* is_alive); void clean_implementors_list(BoolObjectClosure* is_alive); void clean_method_data(BoolObjectClosure* is_alive); void clean_dependent_nmethods();
--- a/src/share/vm/oops/klass.cpp Tue Dec 22 12:28:01 2015 -0800 +++ b/src/share/vm/oops/klass.cpp Tue Jan 05 08:40:50 2016 -0800 @@ -454,8 +454,7 @@ // Clean the implementors list and method data. if (clean_alive_klasses && current->oop_is_instance()) { InstanceKlass* ik = InstanceKlass::cast(current); - ik->clean_implementors_list(is_alive); - ik->clean_method_data(is_alive); + ik->clean_weak_instanceklass_links(is_alive); } } }
--- a/src/share/vm/opto/c2_globals.hpp Tue Dec 22 12:28:01 2015 -0800 +++ b/src/share/vm/opto/c2_globals.hpp Tue Jan 05 08:40:50 2016 -0800 @@ -205,6 +205,9 @@ notproduct(bool, TraceProfileTripCount, false, \ "Trace profile loop trip count information") \ \ + product(bool, UseCountedLoopSafepoints, false, \ + "Force counted loops to keep a safepoint") \ + \ product(bool, UseLoopPredicate, true, \ "Generate a predicate to select fast/slow loop versions") \ \ @@ -669,6 +672,9 @@ product_pd(bool, TrapBasedRangeChecks, \ "Generate code for range checks that uses a cmp and trap " \ "instruction raising SIGTRAP. Used on PPC64.") \ + \ + develop(bool, RenumberLiveNodes, true, \ + "Renumber live nodes") \ C2_FLAGS(DECLARE_DEVELOPER_FLAG, DECLARE_PD_DEVELOPER_FLAG, DECLARE_PRODUCT_FLAG, DECLARE_PD_PRODUCT_FLAG, DECLARE_DIAGNOSTIC_FLAG, DECLARE_EXPERIMENTAL_FLAG, DECLARE_NOTPRODUCT_FLAG)
--- a/src/share/vm/opto/compile.cpp Tue Dec 22 12:28:01 2015 -0800 +++ b/src/share/vm/opto/compile.cpp Tue Jan 05 08:40:50 2016 -0800 @@ -2093,6 +2093,20 @@ // so keep only the actual candidates for optimizations. cleanup_expensive_nodes(igvn); + if (!failing() && RenumberLiveNodes && live_nodes() + NodeLimitFudgeFactor < unique()) { + NOT_PRODUCT(Compile::TracePhase t2("", &_t_renumberLive, TimeCompiler);) + initial_gvn()->replace_with(&igvn); + for_igvn()->clear(); + Unique_Node_List new_worklist(C->comp_arena()); + { + ResourceMark rm; + PhaseRenumberLive prl = PhaseRenumberLive(initial_gvn(), for_igvn(), &new_worklist); + } + set_for_igvn(&new_worklist); + igvn = PhaseIterGVN(initial_gvn()); + igvn.optimize(); + } + // Perform escape analysis if (_do_escape_analysis && ConnectionGraph::has_candidates(this)) { if (has_loops()) {
--- a/src/share/vm/opto/loopnode.cpp Tue Dec 22 12:28:01 2015 -0800 +++ b/src/share/vm/opto/loopnode.cpp Tue Jan 05 08:40:50 2016 -0800 @@ -685,14 +685,16 @@ } // LoopLimitCheck - // Check for SafePoint on backedge and remove - Node *sfpt = x->in(LoopNode::LoopBackControl); - if (sfpt->Opcode() == Op_SafePoint && is_deleteable_safept(sfpt)) { - lazy_replace( sfpt, iftrue ); - if (loop->_safepts != NULL) { - loop->_safepts->yank(sfpt); + if (!UseCountedLoopSafepoints) { + // Check for SafePoint on backedge and remove + Node *sfpt = x->in(LoopNode::LoopBackControl); + if (sfpt->Opcode() == Op_SafePoint && is_deleteable_safept(sfpt)) { + lazy_replace( sfpt, iftrue ); + if (loop->_safepts != NULL) { + loop->_safepts->yank(sfpt); + } + loop->_tail = iftrue; } - loop->_tail = iftrue; } // Build a canonical trip test. @@ -781,12 +783,14 @@ lazy_replace( x, l ); set_idom(l, init_control, dom_depth(x)); - // Check for immediately preceding SafePoint and remove - Node *sfpt2 = le->in(0); - if (sfpt2->Opcode() == Op_SafePoint && is_deleteable_safept(sfpt2)) { - lazy_replace( sfpt2, sfpt2->in(TypeFunc::Control)); - if (loop->_safepts != NULL) { - loop->_safepts->yank(sfpt2); + if (!UseCountedLoopSafepoints) { + // Check for immediately preceding SafePoint and remove + Node *sfpt2 = le->in(0); + if (sfpt2->Opcode() == Op_SafePoint && is_deleteable_safept(sfpt2)) { + lazy_replace( sfpt2, sfpt2->in(TypeFunc::Control)); + if (loop->_safepts != NULL) { + loop->_safepts->yank(sfpt2); + } } } @@ -1806,6 +1810,37 @@ } } +void IdealLoopTree::remove_safepoints(PhaseIdealLoop* phase, bool keep_one) { + Node* keep = NULL; + if (keep_one) { + // Look for a safepoint on the idom-path. + for (Node* i = tail(); i != _head; i = phase->idom(i)) { + if (i->Opcode() == Op_SafePoint && phase->get_loop(i) == this) { + keep = i; + break; // Found one + } + } + } + + // Don't remove any safepoints if it is requested to keep a single safepoint and + // no safepoint was found on idom-path. It is not safe to remove any safepoint + // in this case since there's no safepoint dominating all paths in the loop body. + bool prune = !keep_one || keep != NULL; + + // Delete other safepoints in this loop. + Node_List* sfpts = _safepts; + if (prune && sfpts != NULL) { + assert(keep == NULL || keep->Opcode() == Op_SafePoint, "not safepoint"); + for (uint i = 0; i < sfpts->size(); i++) { + Node* n = sfpts->at(i); + assert(phase->get_loop(n) == this, ""); + if (n != keep && phase->is_deleteable_safept(n)) { + phase->lazy_replace(n, n->in(TypeFunc::Control)); + } + } + } +} + //------------------------------counted_loop----------------------------------- // Convert to counted loops where possible void IdealLoopTree::counted_loop( PhaseIdealLoop *phase ) { @@ -1817,42 +1852,23 @@ if (_head->is_CountedLoop() || phase->is_counted_loop(_head, this)) { - _has_sfpt = 1; // Indicate we do not need a safepoint here - - // Look for safepoints to remove. - Node_List* sfpts = _safepts; - if (sfpts != NULL) { - for (uint i = 0; i < sfpts->size(); i++) { - Node* n = sfpts->at(i); - assert(phase->get_loop(n) == this, ""); - if (phase->is_deleteable_safept(n)) { - phase->lazy_replace(n, n->in(TypeFunc::Control)); - } - } + + if (!UseCountedLoopSafepoints) { + // Indicate we do not need a safepoint here + _has_sfpt = 1; } + // Remove safepoints + bool keep_one_sfpt = !(_has_call || _has_sfpt); + remove_safepoints(phase, keep_one_sfpt); + // Look for induction variables phase->replace_parallel_iv(this); } else if (_parent != NULL && !_irreducible) { - // Not a counted loop. - // Look for a safepoint on the idom-path. - Node* sfpt = tail(); - for (; sfpt != _head; sfpt = phase->idom(sfpt)) { - if (sfpt->Opcode() == Op_SafePoint && phase->get_loop(sfpt) == this) - break; // Found one - } - // Delete other safepoints in this loop. - Node_List* sfpts = _safepts; - if (sfpts != NULL && sfpt != _head && sfpt->Opcode() == Op_SafePoint) { - for (uint i = 0; i < sfpts->size(); i++) { - Node* n = sfpts->at(i); - assert(phase->get_loop(n) == this, ""); - if (n != sfpt && phase->is_deleteable_safept(n)) { - phase->lazy_replace(n, n->in(TypeFunc::Control)); - } - } - } + // Not a counted loop. Keep one safepoint. + bool keep_one_sfpt = true; + remove_safepoints(phase, keep_one_sfpt); } // Recursively @@ -1906,6 +1922,15 @@ if (cl->is_main_loop()) tty->print(" main"); if (cl->is_post_loop()) tty->print(" post"); } + if (_has_call) tty->print(" has_call"); + if (_has_sfpt) tty->print(" has_sfpt"); + if (_rce_candidate) tty->print(" rce"); + if (_safepts != NULL && _safepts->size() > 0) { + tty->print(" sfpts={"); _safepts->dump_simple(); tty->print(" }"); + } + if (_required_safept != NULL && _required_safept->size() > 0) { + tty->print(" req={"); _required_safept->dump_simple(); tty->print(" }"); + } tty->cr(); }
--- a/src/share/vm/opto/loopnode.hpp Tue Dec 22 12:28:01 2015 -0800 +++ b/src/share/vm/opto/loopnode.hpp Tue Jan 05 08:40:50 2016 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 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 @@ -403,6 +403,9 @@ // encountered. void allpaths_check_safepts(VectorSet &visited, Node_List &stack); + // Remove safepoints from loop. Optionally keeping one. + void remove_safepoints(PhaseIdealLoop* phase, bool keep_one); + // Convert to counted loops where possible void counted_loop( PhaseIdealLoop *phase );
--- a/src/share/vm/opto/node.cpp Tue Dec 22 12:28:01 2015 -0800 +++ b/src/share/vm/opto/node.cpp Tue Jan 05 08:40:50 2016 -0800 @@ -325,6 +325,9 @@ // Create a Node, with a given number of required edges. Node::Node(uint req) : _idx(IDX_INIT(req)) +#ifdef ASSERT + , _parse_idx(_idx) +#endif { assert( req < Compile::current()->max_node_limit() - NodeLimitFudgeFactor, "Input limit exceeded" ); debug_only( verify_construction() ); @@ -344,6 +347,9 @@ //------------------------------Node------------------------------------------- Node::Node(Node *n0) : _idx(IDX_INIT(1)) +#ifdef ASSERT + , _parse_idx(_idx) +#endif { debug_only( verify_construction() ); NOT_PRODUCT(nodes_created++); @@ -356,6 +362,9 @@ //------------------------------Node------------------------------------------- Node::Node(Node *n0, Node *n1) : _idx(IDX_INIT(2)) +#ifdef ASSERT + , _parse_idx(_idx) +#endif { debug_only( verify_construction() ); NOT_PRODUCT(nodes_created++); @@ -370,6 +379,9 @@ //------------------------------Node------------------------------------------- Node::Node(Node *n0, Node *n1, Node *n2) : _idx(IDX_INIT(3)) +#ifdef ASSERT + , _parse_idx(_idx) +#endif { debug_only( verify_construction() ); NOT_PRODUCT(nodes_created++); @@ -386,6 +398,9 @@ //------------------------------Node------------------------------------------- Node::Node(Node *n0, Node *n1, Node *n2, Node *n3) : _idx(IDX_INIT(4)) +#ifdef ASSERT + , _parse_idx(_idx) +#endif { debug_only( verify_construction() ); NOT_PRODUCT(nodes_created++); @@ -404,6 +419,9 @@ //------------------------------Node------------------------------------------- Node::Node(Node *n0, Node *n1, Node *n2, Node *n3, Node *n4) : _idx(IDX_INIT(5)) +#ifdef ASSERT + , _parse_idx(_idx) +#endif { debug_only( verify_construction() ); NOT_PRODUCT(nodes_created++); @@ -425,6 +443,9 @@ Node::Node(Node *n0, Node *n1, Node *n2, Node *n3, Node *n4, Node *n5) : _idx(IDX_INIT(6)) +#ifdef ASSERT + , _parse_idx(_idx) +#endif { debug_only( verify_construction() ); NOT_PRODUCT(nodes_created++); @@ -448,6 +469,9 @@ Node::Node(Node *n0, Node *n1, Node *n2, Node *n3, Node *n4, Node *n5, Node *n6) : _idx(IDX_INIT(7)) +#ifdef ASSERT + , _parse_idx(_idx) +#endif { debug_only( verify_construction() ); NOT_PRODUCT(nodes_created++); @@ -2083,6 +2107,17 @@ #endif } +void Node_List::dump_simple() const { +#ifndef PRODUCT + for( uint i = 0; i < _cnt; i++ ) + if( _nodes[i] ) { + tty->print(" %d", _nodes[i]->_idx); + } else { + tty->print(" NULL"); + } +#endif +} + //============================================================================= //------------------------------remove----------------------------------------- void Unique_Node_List::remove( Node *n ) {
--- a/src/share/vm/opto/node.hpp Tue Dec 22 12:28:01 2015 -0800 +++ b/src/share/vm/opto/node.hpp Tue Jan 05 08:40:50 2016 -0800 @@ -294,10 +294,16 @@ public: // Each Node is assigned a unique small/dense number. This number is used - // to index into auxiliary arrays of data and bitvectors. - // It is declared const to defend against inadvertant assignment, - // since it is used by clients as a naked field. + // to index into auxiliary arrays of data and bit vectors. + // The field _idx is declared constant to defend against inadvertent assignments, + // since it is used by clients as a naked field. However, the field's value can be + // changed using the set_idx() method. + // + // The PhaseRenumberLive phase renumbers nodes based on liveness information. + // Therefore, it updates the value of the _idx field. The parse-time _idx is + // preserved in _parse_idx. const node_idx_t _idx; + DEBUG_ONLY(const node_idx_t _parse_idx;) // Get the (read-only) number of input edges uint req() const { return _cnt; } @@ -1368,6 +1374,7 @@ void clear() { _cnt = 0; Node_Array::clear(); } // retain storage uint size() const { return _cnt; } void dump() const; + void dump_simple() const; }; //------------------------------Unique_Node_List-------------------------------
--- a/src/share/vm/opto/phase.cpp Tue Dec 22 12:28:01 2015 -0800 +++ b/src/share/vm/opto/phase.cpp Tue Jan 05 08:40:50 2016 -0800 @@ -67,6 +67,8 @@ elapsedTimer Phase::_t_iterGVN; elapsedTimer Phase::_t_iterGVN2; elapsedTimer Phase::_t_incrInline; +elapsedTimer Phase::_t_renumberLive; + // Subtimers for _t_registerAllocation elapsedTimer Phase::_t_ctorChaitin; @@ -115,13 +117,14 @@ } tty->print_cr (" iterGVN : %3.3f sec", Phase::_t_iterGVN.seconds()); tty->print_cr (" incrInline : %3.3f sec", Phase::_t_incrInline.seconds()); + tty->print_cr (" renumberLive : %3.3f sec", Phase::_t_renumberLive.seconds()); tty->print_cr (" idealLoop : %3.3f sec", Phase::_t_idealLoop.seconds()); tty->print_cr (" idealLoopVerify: %3.3f sec", Phase::_t_idealLoopVerify.seconds()); tty->print_cr (" ccp : %3.3f sec", Phase::_t_ccp.seconds()); tty->print_cr (" iterGVN2 : %3.3f sec", Phase::_t_iterGVN2.seconds()); tty->print_cr (" macroExpand : %3.3f sec", Phase::_t_macroExpand.seconds()); tty->print_cr (" graphReshape : %3.3f sec", Phase::_t_graphReshaping.seconds()); - double optimizer_subtotal = Phase::_t_iterGVN.seconds() + Phase::_t_iterGVN2.seconds() + + double optimizer_subtotal = Phase::_t_iterGVN.seconds() + Phase::_t_iterGVN2.seconds() + Phase::_t_renumberLive.seconds() + Phase::_t_escapeAnalysis.seconds() + Phase::_t_macroEliminate.seconds() + Phase::_t_idealLoop.seconds() + Phase::_t_ccp.seconds() + Phase::_t_macroExpand.seconds() + Phase::_t_graphReshaping.seconds();
--- a/src/share/vm/opto/phase.hpp Tue Dec 22 12:28:01 2015 -0800 +++ b/src/share/vm/opto/phase.hpp Tue Jan 05 08:40:50 2016 -0800 @@ -40,22 +40,23 @@ class Phase : public StackObj { public: enum PhaseNumber { - Compiler, // Top-level compiler phase - Parser, // Parse bytecodes - Remove_Useless, // Remove useless nodes - Optimistic, // Optimistic analysis phase - GVN, // Pessimistic global value numbering phase - Ins_Select, // Instruction selection phase - CFG, // Build a CFG - BlockLayout, // Linear ordering of blocks - Register_Allocation, // Register allocation, duh - LIVE, // Dragon-book LIVE range problem - StringOpts, // StringBuilder related optimizations - Interference_Graph, // Building the IFG - Coalesce, // Coalescing copies - Ideal_Loop, // Find idealized trip-counted loops - Macro_Expand, // Expand macro nodes - Peephole, // Apply peephole optimizations + Compiler, // Top-level compiler phase + Parser, // Parse bytecodes + Remove_Useless, // Remove useless nodes + Remove_Useless_And_Renumber_Live, // First, remove useless nodes from the graph. Then, renumber live nodes. + Optimistic, // Optimistic analysis phase + GVN, // Pessimistic global value numbering phase + Ins_Select, // Instruction selection phase + CFG, // Build a CFG + BlockLayout, // Linear ordering of blocks + Register_Allocation, // Register allocation, duh + LIVE, // Dragon-book LIVE range problem + StringOpts, // StringBuilder related optimizations + Interference_Graph, // Building the IFG + Coalesce, // Coalescing copies + Ideal_Loop, // Find idealized trip-counted loops + Macro_Expand, // Expand macro nodes + Peephole, // Apply peephole optimizations last_phase }; protected: @@ -102,6 +103,7 @@ static elapsedTimer _t_iterGVN; static elapsedTimer _t_iterGVN2; static elapsedTimer _t_incrInline; + static elapsedTimer _t_renumberLive; // Subtimers for _t_registerAllocation static elapsedTimer _t_ctorChaitin;
--- a/src/share/vm/opto/phaseX.cpp Tue Dec 22 12:28:01 2015 -0800 +++ b/src/share/vm/opto/phaseX.cpp Tue Jan 05 08:40:50 2016 -0800 @@ -398,7 +398,7 @@ //============================================================================= //------------------------------PhaseRemoveUseless----------------------------- // 1) Use a breadthfirst walk to collect useful nodes reachable from root. -PhaseRemoveUseless::PhaseRemoveUseless( PhaseGVN *gvn, Unique_Node_List *worklist ) : Phase(Remove_Useless), +PhaseRemoveUseless::PhaseRemoveUseless(PhaseGVN *gvn, Unique_Node_List *worklist, PhaseNumber phase_num) : Phase(phase_num), _useful(Thread::current()->resource_area()) { // Implementation requires 'UseLoopSafepoints == true' and an edge from root @@ -435,6 +435,82 @@ } } +//============================================================================= +//------------------------------PhaseRenumberLive------------------------------ +// First, remove useless nodes (equivalent to identifying live nodes). +// Then, renumber live nodes. +// +// The set of live nodes is returned by PhaseRemoveUseless in the _useful structure. +// If the number of live nodes is 'x' (where 'x' == _useful.size()), then the +// PhaseRenumberLive updates the node ID of each node (the _idx field) with a unique +// value in the range [0, x). +// +// At the end of the PhaseRenumberLive phase, the compiler's count of unique nodes is +// updated to 'x' and the list of dead nodes is reset (as there are no dead nodes). +// +// The PhaseRenumberLive phase updates two data structures with the new node IDs. +// (1) The worklist is used by the PhaseIterGVN phase to identify nodes that must be +// processed. A new worklist (with the updated node IDs) is returned in 'new_worklist'. +// (2) Type information (the field PhaseGVN::_types) maps type information to each +// node ID. The mapping is updated to use the new node IDs as well. Updated type +// information is returned in PhaseGVN::_types. +// +// The PhaseRenumberLive phase does not preserve the order of elements in the worklist. +// +// Other data structures used by the compiler are not updated. The hash table for value +// numbering (the field PhaseGVN::_table) is not updated because computing the hash +// values is not based on node IDs. The field PhaseGVN::_nodes is not updated either +// because it is empty wherever PhaseRenumberLive is used. +PhaseRenumberLive::PhaseRenumberLive(PhaseGVN* gvn, + Unique_Node_List* worklist, Unique_Node_List* new_worklist, + PhaseNumber phase_num) : + PhaseRemoveUseless(gvn, worklist, Remove_Useless_And_Renumber_Live) { + + assert(RenumberLiveNodes, "RenumberLiveNodes must be set to true for node renumbering to take place"); + assert(C->live_nodes() == _useful.size(), "the number of live nodes must match the number of useful nodes"); + assert(gvn->nodes_size() == 0, "GVN must not contain any nodes at this point"); + + uint old_unique_count = C->unique(); + uint live_node_count = C->live_nodes(); + uint worklist_size = worklist->size(); + + // Storage for the updated type information. + Type_Array new_type_array(C->comp_arena()); + + // Iterate over the set of live nodes. + uint current_idx = 0; // The current new node ID. Incremented after every assignment. + for (uint i = 0; i < _useful.size(); i++) { + Node* n = _useful.at(i); + const Type* type = gvn->type_or_null(n); + new_type_array.map(current_idx, type); + + bool in_worklist = false; + if (worklist->member(n)) { + in_worklist = true; + } + + n->set_idx(current_idx); // Update node ID. + + if (in_worklist) { + new_worklist->push(n); + } + + current_idx++; + } + + assert(worklist_size == new_worklist->size(), "the new worklist must have the same size as the original worklist"); + assert(live_node_count == current_idx, "all live nodes must be processed"); + + // Replace the compiler's type information with the updated type information. + gvn->replace_types(new_type_array); + + // Update the unique node count of the compilation to the number of currently live nodes. + C->set_unique(live_node_count); + + // Set the dead node count to 0 and reset dead node list. + C->reset_dead_node_list(); +} + //============================================================================= //------------------------------PhaseTransform---------------------------------
--- a/src/share/vm/opto/phaseX.hpp Tue Dec 22 12:28:01 2015 -0800 +++ b/src/share/vm/opto/phaseX.hpp Tue Jan 05 08:40:50 2016 -0800 @@ -148,11 +148,21 @@ Unique_Node_List _useful; // Nodes reachable from root // list is allocated from current resource area public: - PhaseRemoveUseless( PhaseGVN *gvn, Unique_Node_List *worklist ); + PhaseRemoveUseless(PhaseGVN *gvn, Unique_Node_List *worklist, PhaseNumber phase_num = Remove_Useless); Unique_Node_List *get_useful() { return &_useful; } }; +//------------------------------PhaseRenumber---------------------------------- +// Phase that first performs a PhaseRemoveUseless, then it renumbers compiler +// structures accordingly. +class PhaseRenumberLive : public PhaseRemoveUseless { +public: + PhaseRenumberLive(PhaseGVN* gvn, + Unique_Node_List* worklist, Unique_Node_List* new_worklist, + PhaseNumber phase_num = Remove_Useless_And_Renumber_Live); +}; + //------------------------------PhaseTransform--------------------------------- // Phases that analyze, then transform. Constructing the Phase object does any @@ -162,7 +172,7 @@ class PhaseTransform : public Phase { protected: Arena* _arena; - Node_Array _nodes; // Map old node indices to new nodes. + Node_List _nodes; // Map old node indices to new nodes. Type_Array _types; // Map old node indices to Types. // ConNode caches: @@ -187,7 +197,13 @@ Arena* arena() { return _arena; } Type_Array& types() { return _types; } + void replace_types(Type_Array new_types) { + _types = new_types; + } // _nodes is used in varying ways by subclasses, which define local accessors + uint nodes_size() { + return _nodes.size(); + } public: // Get a previously recorded type for the node n.
--- a/src/share/vm/prims/jni.cpp Tue Dec 22 12:28:01 2015 -0800 +++ b/src/share/vm/prims/jni.cpp Tue Jan 05 08:40:50 2016 -0800 @@ -1796,34 +1796,34 @@ // the runtime type of subword integral basic types is integer DEFINE_CALLMETHODV(jboolean, Boolean, T_BOOLEAN - , HOTSPOT_JNI_CALLBOOLEANMETHOD_ENTRY(env, obj, (uintptr_t)methodID), - HOTSPOT_JNI_CALLBOOLEANMETHOD_RETURN(_ret_ref)) + , HOTSPOT_JNI_CALLBOOLEANMETHODV_ENTRY(env, obj, (uintptr_t)methodID), + HOTSPOT_JNI_CALLBOOLEANMETHODV_RETURN(_ret_ref)) DEFINE_CALLMETHODV(jbyte, Byte, T_BYTE - , HOTSPOT_JNI_CALLBYTEMETHOD_ENTRY(env, obj, (uintptr_t)methodID), - HOTSPOT_JNI_CALLBYTEMETHOD_RETURN(_ret_ref)) + , HOTSPOT_JNI_CALLBYTEMETHODV_ENTRY(env, obj, (uintptr_t)methodID), + HOTSPOT_JNI_CALLBYTEMETHODV_RETURN(_ret_ref)) DEFINE_CALLMETHODV(jchar, Char, T_CHAR - , HOTSPOT_JNI_CALLCHARMETHOD_ENTRY(env, obj, (uintptr_t)methodID), - HOTSPOT_JNI_CALLCHARMETHOD_RETURN(_ret_ref)) + , HOTSPOT_JNI_CALLCHARMETHODV_ENTRY(env, obj, (uintptr_t)methodID), + HOTSPOT_JNI_CALLCHARMETHODV_RETURN(_ret_ref)) DEFINE_CALLMETHODV(jshort, Short, T_SHORT - , HOTSPOT_JNI_CALLSHORTMETHOD_ENTRY(env, obj, (uintptr_t)methodID), - HOTSPOT_JNI_CALLSHORTMETHOD_RETURN(_ret_ref)) + , HOTSPOT_JNI_CALLSHORTMETHODV_ENTRY(env, obj, (uintptr_t)methodID), + HOTSPOT_JNI_CALLSHORTMETHODV_RETURN(_ret_ref)) DEFINE_CALLMETHODV(jobject, Object, T_OBJECT - , HOTSPOT_JNI_CALLOBJECTMETHOD_ENTRY(env, obj, (uintptr_t)methodID), - HOTSPOT_JNI_CALLOBJECTMETHOD_RETURN(_ret_ref)) + , HOTSPOT_JNI_CALLOBJECTMETHODV_ENTRY(env, obj, (uintptr_t)methodID), + HOTSPOT_JNI_CALLOBJECTMETHODV_RETURN(_ret_ref)) DEFINE_CALLMETHODV(jint, Int, T_INT, - HOTSPOT_JNI_CALLINTMETHOD_ENTRY(env, obj, (uintptr_t)methodID), - HOTSPOT_JNI_CALLINTMETHOD_RETURN(_ret_ref)) + HOTSPOT_JNI_CALLINTMETHODV_ENTRY(env, obj, (uintptr_t)methodID), + HOTSPOT_JNI_CALLINTMETHODV_RETURN(_ret_ref)) DEFINE_CALLMETHODV(jlong, Long, T_LONG - , HOTSPOT_JNI_CALLLONGMETHOD_ENTRY(env, obj, (uintptr_t)methodID), - HOTSPOT_JNI_CALLLONGMETHOD_RETURN(_ret_ref)) + , HOTSPOT_JNI_CALLLONGMETHODV_ENTRY(env, obj, (uintptr_t)methodID), + HOTSPOT_JNI_CALLLONGMETHODV_RETURN(_ret_ref)) // Float and double probes don't return value because dtrace doesn't currently support it DEFINE_CALLMETHODV(jfloat, Float, T_FLOAT - , HOTSPOT_JNI_CALLFLOATMETHOD_ENTRY(env, obj, (uintptr_t)methodID), - HOTSPOT_JNI_CALLFLOATMETHOD_RETURN()) + , HOTSPOT_JNI_CALLFLOATMETHODV_ENTRY(env, obj, (uintptr_t)methodID), + HOTSPOT_JNI_CALLFLOATMETHODV_RETURN()) DEFINE_CALLMETHODV(jdouble, Double, T_DOUBLE - , HOTSPOT_JNI_CALLDOUBLEMETHOD_ENTRY(env, obj, (uintptr_t)methodID), - HOTSPOT_JNI_CALLDOUBLEMETHOD_RETURN()) + , HOTSPOT_JNI_CALLDOUBLEMETHODV_ENTRY(env, obj, (uintptr_t)methodID), + HOTSPOT_JNI_CALLDOUBLEMETHODV_RETURN()) #define DEFINE_CALLMETHODA(ResultType, Result, Tag \ , EntryProbe, ReturnProbe) \ @@ -1848,34 +1848,34 @@ // the runtime type of subword integral basic types is integer DEFINE_CALLMETHODA(jboolean, Boolean, T_BOOLEAN - , HOTSPOT_JNI_CALLBOOLEANMETHOD_ENTRY(env, obj, (uintptr_t)methodID), - HOTSPOT_JNI_CALLBOOLEANMETHOD_RETURN(_ret_ref)) + , HOTSPOT_JNI_CALLBOOLEANMETHODA_ENTRY(env, obj, (uintptr_t)methodID), + HOTSPOT_JNI_CALLBOOLEANMETHODA_RETURN(_ret_ref)) DEFINE_CALLMETHODA(jbyte, Byte, T_BYTE - , HOTSPOT_JNI_CALLBYTEMETHOD_ENTRY(env, obj, (uintptr_t)methodID), - HOTSPOT_JNI_CALLBYTEMETHOD_RETURN(_ret_ref)) + , HOTSPOT_JNI_CALLBYTEMETHODA_ENTRY(env, obj, (uintptr_t)methodID), + HOTSPOT_JNI_CALLBYTEMETHODA_RETURN(_ret_ref)) DEFINE_CALLMETHODA(jchar, Char, T_CHAR - , HOTSPOT_JNI_CALLCHARMETHOD_ENTRY(env, obj, (uintptr_t)methodID), - HOTSPOT_JNI_CALLCHARMETHOD_RETURN(_ret_ref)) + , HOTSPOT_JNI_CALLCHARMETHODA_ENTRY(env, obj, (uintptr_t)methodID), + HOTSPOT_JNI_CALLCHARMETHODA_RETURN(_ret_ref)) DEFINE_CALLMETHODA(jshort, Short, T_SHORT - , HOTSPOT_JNI_CALLSHORTMETHOD_ENTRY(env, obj, (uintptr_t)methodID), - HOTSPOT_JNI_CALLSHORTMETHOD_RETURN(_ret_ref)) + , HOTSPOT_JNI_CALLSHORTMETHODA_ENTRY(env, obj, (uintptr_t)methodID), + HOTSPOT_JNI_CALLSHORTMETHODA_RETURN(_ret_ref)) DEFINE_CALLMETHODA(jobject, Object, T_OBJECT - , HOTSPOT_JNI_CALLOBJECTMETHOD_ENTRY(env, obj, (uintptr_t)methodID), - HOTSPOT_JNI_CALLOBJECTMETHOD_RETURN(_ret_ref)) + , HOTSPOT_JNI_CALLOBJECTMETHODA_ENTRY(env, obj, (uintptr_t)methodID), + HOTSPOT_JNI_CALLOBJECTMETHODA_RETURN(_ret_ref)) DEFINE_CALLMETHODA(jint, Int, T_INT, - HOTSPOT_JNI_CALLINTMETHOD_ENTRY(env, obj, (uintptr_t)methodID), - HOTSPOT_JNI_CALLINTMETHOD_RETURN(_ret_ref)) + HOTSPOT_JNI_CALLINTMETHODA_ENTRY(env, obj, (uintptr_t)methodID), + HOTSPOT_JNI_CALLINTMETHODA_RETURN(_ret_ref)) DEFINE_CALLMETHODA(jlong, Long, T_LONG - , HOTSPOT_JNI_CALLLONGMETHOD_ENTRY(env, obj, (uintptr_t)methodID), - HOTSPOT_JNI_CALLLONGMETHOD_RETURN(_ret_ref)) + , HOTSPOT_JNI_CALLLONGMETHODA_ENTRY(env, obj, (uintptr_t)methodID), + HOTSPOT_JNI_CALLLONGMETHODA_RETURN(_ret_ref)) // Float and double probes don't return value because dtrace doesn't currently support it DEFINE_CALLMETHODA(jfloat, Float, T_FLOAT - , HOTSPOT_JNI_CALLFLOATMETHOD_ENTRY(env, obj, (uintptr_t)methodID), - HOTSPOT_JNI_CALLFLOATMETHOD_RETURN()) + , HOTSPOT_JNI_CALLFLOATMETHODA_ENTRY(env, obj, (uintptr_t)methodID), + HOTSPOT_JNI_CALLFLOATMETHODA_RETURN()) DEFINE_CALLMETHODA(jdouble, Double, T_DOUBLE - , HOTSPOT_JNI_CALLDOUBLEMETHOD_ENTRY(env, obj, (uintptr_t)methodID), - HOTSPOT_JNI_CALLDOUBLEMETHOD_RETURN()) + , HOTSPOT_JNI_CALLDOUBLEMETHODA_ENTRY(env, obj, (uintptr_t)methodID), + HOTSPOT_JNI_CALLDOUBLEMETHODA_RETURN()) DT_VOID_RETURN_MARK_DECL(CallVoidMethod, HOTSPOT_JNI_CALLVOIDMETHOD_RETURN()); DT_VOID_RETURN_MARK_DECL(CallVoidMethodV, HOTSPOT_JNI_CALLVOIDMETHODV_RETURN()); @@ -3137,7 +3137,7 @@ JNI_END DEFINE_SETSTATICFIELD(jboolean, bool, Boolean, 'Z', z - , HOTSPOT_JNI_SETBOOLEANFIELD_ENTRY(env, clazz, (uintptr_t)fieldID, value), + , HOTSPOT_JNI_SETSTATICBOOLEANFIELD_ENTRY(env, clazz, (uintptr_t)fieldID, value), HOTSPOT_JNI_SETBOOLEANFIELD_RETURN()) DEFINE_SETSTATICFIELD(jbyte, byte, Byte, 'B', b , HOTSPOT_JNI_SETSTATICBYTEFIELD_ENTRY(env, clazz, (uintptr_t) fieldID, value),
--- a/src/share/vm/prims/whitebox.cpp Tue Dec 22 12:28:01 2015 -0800 +++ b/src/share/vm/prims/whitebox.cpp Tue Jan 05 08:40:50 2016 -0800 @@ -45,6 +45,7 @@ #if INCLUDE_ALL_GCS #include "gc_implementation/parallelScavenge/parallelScavengeHeap.inline.hpp" #include "gc_implementation/g1/concurrentMark.hpp" +#include "gc_implementation/g1/concurrentMarkThread.hpp" #include "gc_implementation/g1/g1CollectedHeap.inline.hpp" #include "gc_implementation/g1/heapRegionRemSet.hpp" #endif // INCLUDE_ALL_GCS @@ -323,8 +324,16 @@ WB_ENTRY(jboolean, WB_G1InConcurrentMark(JNIEnv* env, jobject o)) G1CollectedHeap* g1 = G1CollectedHeap::heap(); - ConcurrentMark* cm = g1->concurrent_mark(); - return cm->concurrent_marking_in_progress(); + return g1->concurrent_mark()->cmThread()->during_cycle(); +WB_END + +WB_ENTRY(jboolean, WB_G1StartMarkCycle(JNIEnv* env, jobject o)) + G1CollectedHeap* g1h = G1CollectedHeap::heap(); + if (!g1h->concurrent_mark()->cmThread()->during_cycle()) { + g1h->collect(GCCause::_wb_conc_mark); + return true; + } + return false; WB_END WB_ENTRY(jint, WB_G1RegionSize(JNIEnv* env, jobject o)) @@ -1031,6 +1040,7 @@ {CC"g1NumMaxRegions", CC"()J", (void*)&WB_G1NumMaxRegions }, {CC"g1NumFreeRegions", CC"()J", (void*)&WB_G1NumFreeRegions }, {CC"g1RegionSize", CC"()I", (void*)&WB_G1RegionSize }, + {CC"g1StartConcMarkCycle", CC"()Z", (void*)&WB_G1StartMarkCycle }, {CC"g1AuxiliaryMemoryUsage", CC"()Ljava/lang/management/MemoryUsage;", (void*)&WB_G1AuxiliaryMemoryUsage }, #endif // INCLUDE_ALL_GCS
--- a/src/share/vm/runtime/arguments.cpp Tue Dec 22 12:28:01 2015 -0800 +++ b/src/share/vm/runtime/arguments.cpp Tue Jan 05 08:40:50 2016 -0800 @@ -3414,7 +3414,7 @@ } if (!PrintSharedArchiveAndExit) { - ClassLoader::trace_class_path("[classpath: ", _java_class_path->value()); + ClassLoader::trace_class_path(tty, "[classpath: ", _java_class_path->value()); } }
--- a/src/share/vm/runtime/safepoint.cpp Tue Dec 22 12:28:01 2015 -0800 +++ b/src/share/vm/runtime/safepoint.cpp Tue Jan 05 08:40:50 2016 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -739,80 +739,12 @@ // ------------------------------------------------------------------------------------------------------ // Exception handlers -#ifndef PRODUCT - -#ifdef SPARC - -#ifdef _LP64 -#define PTR_PAD "" -#else -#define PTR_PAD " " -#endif - -static void print_ptrs(intptr_t oldptr, intptr_t newptr, bool wasoop) { - bool is_oop = newptr ? (cast_to_oop(newptr))->is_oop() : false; - tty->print_cr(PTR_FORMAT PTR_PAD " %s %c " PTR_FORMAT PTR_PAD " %s %s", - oldptr, wasoop?"oop":" ", oldptr == newptr ? ' ' : '!', - newptr, is_oop?"oop":" ", (wasoop && !is_oop) ? "STALE" : ((wasoop==false&&is_oop==false&&oldptr !=newptr)?"STOMP":" ")); -} - -static void print_longs(jlong oldptr, jlong newptr, bool wasoop) { - bool is_oop = newptr ? (cast_to_oop(newptr))->is_oop() : false; - tty->print_cr(PTR64_FORMAT " %s %c " PTR64_FORMAT " %s %s", - oldptr, wasoop?"oop":" ", oldptr == newptr ? ' ' : '!', - newptr, is_oop?"oop":" ", (wasoop && !is_oop) ? "STALE" : ((wasoop==false&&is_oop==false&&oldptr !=newptr)?"STOMP":" ")); -} - -static void print_me(intptr_t *new_sp, intptr_t *old_sp, bool *was_oops) { -#ifdef _LP64 - tty->print_cr("--------+------address-----+------before-----------+-------after----------+"); - const int incr = 1; // Increment to skip a long, in units of intptr_t -#else - tty->print_cr("--------+--address-+------before-----------+-------after----------+"); - const int incr = 2; // Increment to skip a long, in units of intptr_t -#endif - tty->print_cr("---SP---|"); - for( int i=0; i<16; i++ ) { - tty->print("blob %c%d |"PTR_FORMAT" ","LO"[i>>3],i&7,new_sp); print_ptrs(*old_sp++,*new_sp++,*was_oops++); } - tty->print_cr("--------|"); - for( int i1=0; i1<frame::memory_parameter_word_sp_offset-16; i1++ ) { - tty->print("argv pad|"PTR_FORMAT" ",new_sp); print_ptrs(*old_sp++,*new_sp++,*was_oops++); } - tty->print(" pad|"PTR_FORMAT" ",new_sp); print_ptrs(*old_sp++,*new_sp++,*was_oops++); - tty->print_cr("--------|"); - tty->print(" G1 |"PTR_FORMAT" ",new_sp); print_longs(*(jlong*)old_sp,*(jlong*)new_sp,was_oops[incr-1]); old_sp += incr; new_sp += incr; was_oops += incr; - tty->print(" G3 |"PTR_FORMAT" ",new_sp); print_longs(*(jlong*)old_sp,*(jlong*)new_sp,was_oops[incr-1]); old_sp += incr; new_sp += incr; was_oops += incr; - tty->print(" G4 |"PTR_FORMAT" ",new_sp); print_longs(*(jlong*)old_sp,*(jlong*)new_sp,was_oops[incr-1]); old_sp += incr; new_sp += incr; was_oops += incr; - tty->print(" G5 |"PTR_FORMAT" ",new_sp); print_longs(*(jlong*)old_sp,*(jlong*)new_sp,was_oops[incr-1]); old_sp += incr; new_sp += incr; was_oops += incr; - tty->print_cr(" FSR |"PTR_FORMAT" "PTR64_FORMAT" "PTR64_FORMAT,new_sp,*(jlong*)old_sp,*(jlong*)new_sp); - old_sp += incr; new_sp += incr; was_oops += incr; - // Skip the floats - tty->print_cr("--Float-|"PTR_FORMAT,new_sp); - tty->print_cr("---FP---|"); - old_sp += incr*32; new_sp += incr*32; was_oops += incr*32; - for( int i2=0; i2<16; i2++ ) { - tty->print("call %c%d |"PTR_FORMAT" ","LI"[i2>>3],i2&7,new_sp); print_ptrs(*old_sp++,*new_sp++,*was_oops++); } - tty->cr(); -} -#endif // SPARC -#endif // PRODUCT - void SafepointSynchronize::handle_polling_page_exception(JavaThread *thread) { assert(thread->is_Java_thread(), "polling reference encountered by VM thread"); assert(thread->thread_state() == _thread_in_Java, "should come from Java code"); assert(SafepointSynchronize::is_synchronizing(), "polling encountered outside safepoint synchronization"); - // Uncomment this to get some serious before/after printing of the - // Sparc safepoint-blob frame structure. - /* - intptr_t* sp = thread->last_Java_sp(); - intptr_t stack_copy[150]; - for( int i=0; i<150; i++ ) stack_copy[i] = sp[i]; - bool was_oops[150]; - for( int i=0; i<150; i++ ) - was_oops[i] = stack_copy[i] ? ((oop)stack_copy[i])->is_oop() : false; - */ - if (ShowSafepointMsgs) { tty->print("handle_polling_page_exception: "); } @@ -824,7 +756,6 @@ ThreadSafepointState* state = thread->safepoint_state(); state->handle_polling_page_exception(); - // print_me(sp,stack_copy,was_oops); }
--- a/src/share/vm/runtime/synchronizer.cpp Tue Dec 22 12:28:01 2015 -0800 +++ b/src/share/vm/runtime/synchronizer.cpp Tue Jan 05 08:40:50 2016 -0800 @@ -121,7 +121,7 @@ } \ } -#define HOTSPOT_MONITOR_PROBE_waited HOTSPOT_MONITOR_PROBE_WAITED +#define HOTSPOT_MONITOR_PROBE_waited HOTSPOT_MONITOR_WAITED #define DTRACE_MONITOR_PROBE(probe, monitor, obj, thread) \ { \
--- a/src/share/vm/runtime/thread.cpp Tue Dec 22 12:28:01 2015 -0800 +++ b/src/share/vm/runtime/thread.cpp Tue Jan 05 08:40:50 2016 -0800 @@ -141,8 +141,8 @@ #else /* USDT2 */ -#define HOTSPOT_THREAD_PROBE_start HOTSPOT_THREAD_PROBE_START -#define HOTSPOT_THREAD_PROBE_stop HOTSPOT_THREAD_PROBE_STOP +#define HOTSPOT_THREAD_PROBE_start HOTSPOT_THREAD_START +#define HOTSPOT_THREAD_PROBE_stop HOTSPOT_THREAD_STOP #define DTRACE_THREAD_PROBE(probe, javathread) \ { \
--- a/src/share/vm/runtime/threadLocalStorage.cpp Tue Dec 22 12:28:01 2015 -0800 +++ b/src/share/vm/runtime/threadLocalStorage.cpp Tue Jan 05 08:40:50 2016 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -38,6 +38,11 @@ # include "os_bsd.inline.hpp" #endif +// Solaris no longer has this kind of ThreadLocalStorage implementation. +// This will be removed from all platforms in the near future. + +#ifndef SOLARIS + // static member initialization int ThreadLocalStorage::_thread_index = -1; @@ -65,3 +70,5 @@ bool ThreadLocalStorage::is_initialized() { return (thread_index() != -1); } + +#endif // SOLARIS
--- a/src/share/vm/runtime/threadLocalStorage.hpp Tue Dec 22 12:28:01 2015 -0800 +++ b/src/share/vm/runtime/threadLocalStorage.hpp Tue Jan 05 08:40:50 2016 -0800 @@ -38,10 +38,14 @@ extern "C" uintptr_t _raw_thread_id(); class ThreadLocalStorage : AllStatic { + + // Exported API public: static void set_thread(Thread* thread); static Thread* get_thread_slow(); static void invalidate_all() { pd_invalidate_all(); } + static void init(); + static bool is_initialized(); // Machine dependent stuff #ifdef TARGET_OS_ARCH_linux_x86 @@ -78,17 +82,12 @@ # include "threadLS_bsd_zero.hpp" #endif - +#ifndef SOLARIS public: // Accessor static inline int thread_index() { return _thread_index; } static inline void set_thread_index(int index) { _thread_index = index; } - // Initialization - // Called explicitly from VMThread::activate_system instead of init_globals. - static void init(); - static bool is_initialized(); - private: static int _thread_index; @@ -97,6 +96,9 @@ // Processor dependent parts of set_thread and initialization static void pd_set_thread(Thread* thread); static void pd_init(); + +#endif // SOLARIS + // Invalidate any thread cacheing or optimization schemes. static void pd_invalidate_all();
--- a/src/share/vm/utilities/vmError.cpp Tue Dec 22 12:28:01 2015 -0800 +++ b/src/share/vm/utilities/vmError.cpp Tue Jan 05 08:40:50 2016 -0800 @@ -229,7 +229,7 @@ if (signame) { jio_snprintf(buf, buflen, - "%s (0x%x) at pc=" PTR_FORMAT ", pid=%d, tid=" UINTX_FORMAT, + "%s (0x%x) at pc=" PTR_FORMAT ", pid=%d, tid=" INTPTR_FORMAT, signame, _id, _pc, os::current_process_id(), os::current_thread_id()); } else if (_filename != NULL && _lineno > 0) { @@ -237,7 +237,7 @@ char separator = os::file_separator()[0]; const char *p = strrchr(_filename, separator); int n = jio_snprintf(buf, buflen, - "Internal Error at %s:%d, pid=%d, tid=" UINTX_FORMAT, + "Internal Error at %s:%d, pid=%d, tid=" INTPTR_FORMAT, p ? p + 1 : _filename, _lineno, os::current_process_id(), os::current_thread_id()); if (n >= 0 && n < buflen && _message) { @@ -251,7 +251,7 @@ } } else { jio_snprintf(buf, buflen, - "Internal Error (0x%x), pid=%d, tid=" UINTX_FORMAT, + "Internal Error (0x%x), pid=%d, tid=" INTPTR_FORMAT, _id, os::current_process_id(), os::current_thread_id()); } @@ -438,7 +438,7 @@ // process id, thread id st->print(", pid=%d", os::current_process_id()); - st->print(", tid=" UINTX_FORMAT, os::current_thread_id()); + st->print(", tid=" INTPTR_FORMAT, os::current_thread_id()); st->cr(); STEP(40, "(printing error message)")
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/compiler/loopopts/UseCountedLoopSafepoints.java Tue Jan 05 08:40:50 2016 -0800 @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +/** + * @test + * @bug 6869327 + * @summary Test that C2 flag UseCountedLoopSafepoints ensures a safepoint is kept in a CountedLoop + * @library /testlibrary + * @run main UseCountedLoopSafepoints + */ + +import java.util.concurrent.atomic.AtomicLong; +import com.oracle.java.testlibrary.ProcessTools; +import com.oracle.java.testlibrary.OutputAnalyzer; + +public class UseCountedLoopSafepoints { + private static final AtomicLong _num = new AtomicLong(0); + + // Uses the fact that an EnableBiasedLocking vmop will be started + // after 500ms, while we are still in the loop. If there is a + // safepoint in the counted loop, then we will reach safepoint + // very quickly. Otherwise SafepointTimeout will be hit. + public static void main (String args[]) throws Exception { + if (args.length == 1) { + final int loops = Integer.parseInt(args[0]); + for (int i = 0; i < loops; i++) { + _num.addAndGet(1); + } + } else { + ProcessBuilder pb = ProcessTools.createJavaProcessBuilder( + "-XX:+IgnoreUnrecognizedVMOptions", + "-XX:-TieredCompilation", + "-XX:+UseBiasedLocking", + "-XX:BiasedLockingStartupDelay=500", + "-XX:+SafepointTimeout", + "-XX:SafepointTimeoutDelay=2000", + "-XX:+UseCountedLoopSafepoints", + "UseCountedLoopSafepoints", + "2000000000" + ); + OutputAnalyzer output = new OutputAnalyzer(pb.start()); + output.shouldNotContain("Timeout detected"); + output.shouldHaveExitValue(0); + } + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/gc/whitebox/TestConcMarkCycleWB.java Tue Jan 05 08:40:50 2016 -0800 @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test TestConMarkCycleWB + * @bug 8065579 + * @requires vm.gc=="null" | vm.gc=="G1" + * @library /testlibrary /testlibrary/whitebox + * @build ClassFileInstaller com.oracle.java.testlibrary.* sun.hotspot.WhiteBox TestConcMarkCycleWB + * @run main ClassFileInstaller sun.hotspot.WhiteBox + * sun.hotspot.WhiteBox$WhiteBoxPermission + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -XX:+UseG1GC TestConcMarkCycleWB + * @summary Verifies that ConcurrentMarking-related WB works properly + */ +import static com.oracle.java.testlibrary.Asserts.assertFalse; +import static com.oracle.java.testlibrary.Asserts.assertTrue; +import sun.hotspot.WhiteBox; + +public class TestConcMarkCycleWB { + + public static void main(String[] args) throws Exception { + WhiteBox wb = WhiteBox.getWhiteBox(); + + wb.youngGC(); + assertTrue(wb.g1StartConcMarkCycle()); + while (wb.g1InConcurrentMark()) { + Thread.sleep(5); + } + + wb.fullGC(); + assertTrue(wb.g1StartConcMarkCycle()); + while (wb.g1InConcurrentMark()) { + Thread.sleep(5); + } + assertTrue(wb.g1StartConcMarkCycle()); + } +}
--- a/test/runtime/NMT/JcmdWithNMTDisabled.java Tue Dec 22 12:28:01 2015 -0800 +++ b/test/runtime/NMT/JcmdWithNMTDisabled.java Tue Jan 05 08:40:50 2016 -0800 @@ -26,10 +26,7 @@ * @key nmt jcmd * @summary Verify that jcmd correctly reports that NMT is not enabled * @library /testlibrary - * First run without enabling NMT - * @run main/othervm JcmdWithNMTDisabled - * Then run with explicitly disabling NMT, should not be any difference - * @run main/othervm -XX:NativeMemoryTracking=off JcmdWithNMTDisabled + * @run main JcmdWithNMTDisabled 1 */ import com.oracle.java.testlibrary.*; @@ -39,6 +36,27 @@ static String pid; public static void main(String args[]) throws Exception { + + // This test explicitly needs to be run with the exact command lines below, not passing on + // arguments from the parent VM is a conscious choice to avoid NMT being turned on. + if (args.length > 0) { + ProcessBuilder pb; + OutputAnalyzer output; + String testjdkPath = System.getProperty("test.jdk"); + + // First run without enabling NMT + pb = ProcessTools.createJavaProcessBuilder("-Dtest.jdk=" + testjdkPath, "JcmdWithNMTDisabled"); + output = new OutputAnalyzer(pb.start()); + output.shouldHaveExitValue(0); + + // Then run with explicitly disabling NMT, should not be any difference + pb = ProcessTools.createJavaProcessBuilder("-Dtest.jdk=" + testjdkPath, "-XX:NativeMemoryTracking=off", "JcmdWithNMTDisabled"); + output = new OutputAnalyzer(pb.start()); + output.shouldHaveExitValue(0); + + return; + } + // Grab my own PID pid = Integer.toString(ProcessTools.getProcessId());
--- a/test/testlibrary/com/oracle/java/testlibrary/OutputAnalyzer.java Tue Dec 22 12:28:01 2015 -0800 +++ b/test/testlibrary/com/oracle/java/testlibrary/OutputAnalyzer.java Tue Jan 05 08:40:50 2016 -0800 @@ -74,11 +74,12 @@ * @param expectedString String that buffer should contain * @throws RuntimeException If the string was not found */ - public void shouldContain(String expectedString) { + public OutputAnalyzer shouldContain(String expectedString) { if (!stdout.contains(expectedString) && !stderr.contains(expectedString)) { reportDiagnosticSummary(); throw new RuntimeException("'" + expectedString + "' missing from stdout/stderr \n"); } + return this; } /** @@ -87,11 +88,12 @@ * @param expectedString String that buffer should contain * @throws RuntimeException If the string was not found */ - public void stdoutShouldContain(String expectedString) { + public OutputAnalyzer stdoutShouldContain(String expectedString) { if (!stdout.contains(expectedString)) { reportDiagnosticSummary(); throw new RuntimeException("'" + expectedString + "' missing from stdout \n"); } + return this; } /** @@ -100,11 +102,12 @@ * @param expectedString String that buffer should contain * @throws RuntimeException If the string was not found */ - public void stderrShouldContain(String expectedString) { + public OutputAnalyzer stderrShouldContain(String expectedString) { if (!stderr.contains(expectedString)) { reportDiagnosticSummary(); throw new RuntimeException("'" + expectedString + "' missing from stderr \n"); } + return this; } /** @@ -113,7 +116,7 @@ * @param expectedString String that the buffer should not contain * @throws RuntimeException If the string was found */ - public void shouldNotContain(String notExpectedString) { + public OutputAnalyzer shouldNotContain(String notExpectedString) { if (stdout.contains(notExpectedString)) { reportDiagnosticSummary(); throw new RuntimeException("'" + notExpectedString + "' found in stdout \n"); @@ -122,6 +125,7 @@ reportDiagnosticSummary(); throw new RuntimeException("'" + notExpectedString + "' found in stderr \n"); } + return this; } /** @@ -130,11 +134,12 @@ * @param expectedString String that the buffer should not contain * @throws RuntimeException If the string was found */ - public void stdoutShouldNotContain(String notExpectedString) { + public OutputAnalyzer stdoutShouldNotContain(String notExpectedString) { if (stdout.contains(notExpectedString)) { reportDiagnosticSummary(); throw new RuntimeException("'" + notExpectedString + "' found in stdout \n"); } + return this; } /** @@ -143,11 +148,12 @@ * @param expectedString String that the buffer should not contain * @throws RuntimeException If the string was found */ - public void stderrShouldNotContain(String notExpectedString) { + public OutputAnalyzer stderrShouldNotContain(String notExpectedString) { if (stderr.contains(notExpectedString)) { reportDiagnosticSummary(); throw new RuntimeException("'" + notExpectedString + "' found in stderr \n"); } + return this; } /** @@ -157,7 +163,7 @@ * @param pattern * @throws RuntimeException If the pattern was not found */ - public void shouldMatch(String pattern) { + public OutputAnalyzer shouldMatch(String pattern) { Matcher stdoutMatcher = Pattern.compile(pattern, Pattern.MULTILINE).matcher(stdout); Matcher stderrMatcher = Pattern.compile(pattern, Pattern.MULTILINE).matcher(stderr); if (!stdoutMatcher.find() && !stderrMatcher.find()) { @@ -165,6 +171,7 @@ throw new RuntimeException("'" + pattern + "' missing from stdout/stderr \n"); } + return this; } /** @@ -174,13 +181,14 @@ * @param pattern * @throws RuntimeException If the pattern was not found */ - public void stdoutShouldMatch(String pattern) { + public OutputAnalyzer stdoutShouldMatch(String pattern) { Matcher matcher = Pattern.compile(pattern, Pattern.MULTILINE).matcher(stdout); if (!matcher.find()) { reportDiagnosticSummary(); throw new RuntimeException("'" + pattern + "' missing from stdout \n"); } + return this; } /** @@ -190,13 +198,14 @@ * @param pattern * @throws RuntimeException If the pattern was not found */ - public void stderrShouldMatch(String pattern) { + public OutputAnalyzer stderrShouldMatch(String pattern) { Matcher matcher = Pattern.compile(pattern, Pattern.MULTILINE).matcher(stderr); if (!matcher.find()) { reportDiagnosticSummary(); throw new RuntimeException("'" + pattern + "' missing from stderr \n"); } + return this; } /** @@ -206,7 +215,7 @@ * @param pattern * @throws RuntimeException If the pattern was found */ - public void shouldNotMatch(String pattern) { + public OutputAnalyzer shouldNotMatch(String pattern) { Matcher matcher = Pattern.compile(pattern, Pattern.MULTILINE).matcher(stdout); if (matcher.find()) { reportDiagnosticSummary(); @@ -219,6 +228,7 @@ throw new RuntimeException("'" + pattern + "' found in stderr: '" + matcher.group() + "' \n"); } + return this; } /** @@ -228,13 +238,14 @@ * @param pattern * @throws RuntimeException If the pattern was found */ - public void stdoutShouldNotMatch(String pattern) { + public OutputAnalyzer stdoutShouldNotMatch(String pattern) { Matcher matcher = Pattern.compile(pattern, Pattern.MULTILINE).matcher(stdout); if (matcher.find()) { reportDiagnosticSummary(); throw new RuntimeException("'" + pattern + "' found in stdout \n"); } + return this; } /** @@ -244,13 +255,14 @@ * @param pattern * @throws RuntimeException If the pattern was found */ - public void stderrShouldNotMatch(String pattern) { + public OutputAnalyzer stderrShouldNotMatch(String pattern) { Matcher matcher = Pattern.compile(pattern, Pattern.MULTILINE).matcher(stderr); if (matcher.find()) { reportDiagnosticSummary(); throw new RuntimeException("'" + pattern + "' found in stderr \n"); } + return this; } /** @@ -290,12 +302,13 @@ * @param expectedExitValue Expected exit value from process * @throws RuntimeException If the exit value from the process did not match the expected value */ - public void shouldHaveExitValue(int expectedExitValue) { + public OutputAnalyzer shouldHaveExitValue(int expectedExitValue) { if (getExitValue() != expectedExitValue) { reportDiagnosticSummary(); throw new RuntimeException("Expected to get exit value of [" + expectedExitValue + "]\n"); } + return this; }
--- a/test/testlibrary/whitebox/sun/hotspot/WhiteBox.java Tue Dec 22 12:28:01 2015 -0800 +++ b/test/testlibrary/whitebox/sun/hotspot/WhiteBox.java Tue Jan 05 08:40:50 2016 -0800 @@ -174,12 +174,16 @@ public native long incMetaspaceCapacityUntilGC(long increment); public native long metaspaceCapacityUntilGC(); - // force Young GC + // Force Young GC public native void youngGC(); - // force Full GC + // Force Full GC public native void fullGC(); + // Method tries to start concurrent mark cycle. + // It returns false if CM Thread is always in concurrent cycle. + public native boolean g1StartConcMarkCycle(); + // Tests on ReservedSpace/VirtualSpace classes public native int stressVirtualSpaceResize(long reservedSpaceSize, long magnitude, long iterations); public native void runMemoryUnitTests();