# HG changeset patch # User asaha # Date 1454742625 28800 # Node ID aa6d8e03b258059ae6b1cc6a71589e16fb149144 # Parent 737b321e6f0ec1471157d6d346299e3b17c3a5a3# Parent 4cd449d966359d057e0b94c01f3eb5880a68bf43 Merge diff -r 737b321e6f0e -r aa6d8e03b258 .hgtags --- a/.hgtags Wed Jan 27 15:01:46 2016 +0100 +++ b/.hgtags Fri Feb 05 23:10:25 2016 -0800 @@ -803,8 +803,26 @@ dc2fdd4e0b8105268b8231040f761f27ab4523f2 jdk8u72-b14 d6670c5d49ba381405ec9f69a78ccc5b8b0c8473 jdk8u72-b15 da43260704c28b9f19cb652090ae65c258220fd6 jdk8u72-b31 +26b99cd20661a1fa05939d1856a9389311e01c4f jdk8u73-b00 +931c31db01ae873525a1b2c306b01129eb431960 jdk8u73-b01 +67566d815a66d958c1f817d65f1621ba1d2e5f33 jdk8u73-b02 +451dda77f6c29bd3260e87f847a9eadae122a759 jdk8u74-b00 +c1031a924f2c910fad078838b88a2f0146f2de98 jdk8u74-b01 +ca9cae9aa9e989bbe6713c91d55c913edeaecce4 jdk8u74-b02 +a5b78b56841e97ce00463874f1b7f63c54d84934 jdk8u74-b31 +da43260704c28b9f19cb652090ae65c258220fd6 jdk8u72-b31 c0242ea4bde19d72be5149feda112a39e8c89b0a jdk8u75-b00 ca3b8c8e390ab0540b0cc2e5def869b38e460d86 jdk8u75-b01 9aef5b5e0a68f20059cfa9e2806b4ff0e11a3d31 jdk8u75-b02 2df9fe896819362b9075a670b78106b249e50d6d jdk8u75-b03 +32b682649973231b54740c09b10889660f6ebde5 jdk8u75-b04 +1f43bd4fab06d2ca5d1964611df14d8506d6b36e jdk8u75-b05 +916712f178c39d0acbc590f38802133fc86a7346 jdk8u75-b06 +d7b01fb81aa8a5437cb03bc36afe15cf0e55fb89 jdk8u76-b00 +c1679cc87ba045219169cabb6b9b378c2b5cc578 jdk8u76-b01 +218483967e52b419d885d34af4488a81c5133804 jdk8u76-b02 +2a2720daacaa8d9a3ba9435cfaaf9751241d2062 jdk8u76-b03 +16f7b676725aadafb79ea105b22df112e2593a78 jdk8u76-b04 +35bfaf7f9021b5c1e86effbeac075753a82e9a0c jdk8u76-b05 +6449ee3bf707225372709ac830524c00984c601f jdk8u76-b06 b374548dcb4834eb8731a06b52faddd0f10bd45d jdk8u81-b00 diff -r 737b321e6f0e -r aa6d8e03b258 agent/src/os/linux/LinuxDebuggerLocal.c --- a/agent/src/os/linux/LinuxDebuggerLocal.c Wed Jan 27 15:01:46 2016 +0100 +++ b/agent/src/os/linux/LinuxDebuggerLocal.c Fri Feb 05 23:10:25 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); diff -r 737b321e6f0e -r aa6d8e03b258 agent/src/os/linux/libproc.h --- a/agent/src/os/linux/libproc.h Wed Jan 27 15:01:46 2016 +0100 +++ b/agent/src/os/linux/libproc.h Fri Feb 05 23:10:25 2016 -0800 @@ -69,6 +69,7 @@ #if defined(sparc) || defined(sparcv9) || defined(ppc64) +#include #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); diff -r 737b321e6f0e -r aa6d8e03b258 agent/src/os/linux/ps_proc.c --- a/agent/src/os/linux/ps_proc.c Wed Jan 27 15:01:46 2016 +0100 +++ b/agent/src/os/linux/ps_proc.c Fri Feb 05 23:10:25 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; diff -r 737b321e6f0e -r aa6d8e03b258 agent/src/share/classes/sun/jvm/hotspot/CommandProcessor.java --- a/agent/src/share/classes/sun/jvm/hotspot/CommandProcessor.java Wed Jan 27 15:01:46 2016 +0100 +++ b/agent/src/share/classes/sun/jvm/hotspot/CommandProcessor.java Fri Feb 05 23:10:25 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..."); } } } diff -r 737b321e6f0e -r aa6d8e03b258 agent/src/share/classes/sun/jvm/hotspot/runtime/JavaThread.java --- a/agent/src/share/classes/sun/jvm/hotspot/runtime/JavaThread.java Wed Jan 27 15:01:46 2016 +0100 +++ b/agent/src/share/classes/sun/jvm/hotspot/runtime/JavaThread.java Fri Feb 05 23:10:25 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()); diff -r 737b321e6f0e -r aa6d8e03b258 make/defs.make --- a/make/defs.make Wed Jan 27 15:01:46 2016 +0100 +++ b/make/defs.make Fri Feb 05 23:10:25 2016 -0800 @@ -1,5 +1,5 @@ # -# Copyright (c) 2006, 2015, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2006, 2016, 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 @@ -285,7 +285,7 @@ # Use uname output for SRCARCH, but deal with platform differences. If ARCH # is not explicitly listed below, it is treated as x86. - SRCARCH ?= $(ARCH/$(filter sparc sparc64 ia64 amd64 x86_64 ppc64 zero,$(ARCH))) + SRCARCH ?= $(ARCH/$(filter sparc sparc64 ia64 amd64 x86_64 ppc ppc64 zero,$(ARCH))) ARCH/ = x86 ARCH/sparc = sparc ARCH/sparc64= sparc @@ -293,6 +293,7 @@ ARCH/amd64 = x86 ARCH/x86_64 = x86 ARCH/ppc64 = ppc + ARCH/ppc = ppc ARCH/zero = zero # BUILDARCH is usually the same as SRCARCH, except for sparcv9 diff -r 737b321e6f0e -r aa6d8e03b258 make/linux/Makefile --- a/make/linux/Makefile Wed Jan 27 15:01:46 2016 +0100 +++ b/make/linux/Makefile Fri Feb 05 23:10:25 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 diff -r 737b321e6f0e -r aa6d8e03b258 make/linux/makefiles/defs.make --- a/make/linux/makefiles/defs.make Wed Jan 27 15:01:46 2016 +0100 +++ b/make/linux/makefiles/defs.make Fri Feb 05 23:10:25 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. diff -r 737b321e6f0e -r aa6d8e03b258 src/cpu/ppc/vm/interpreter_ppc.cpp --- a/src/cpu/ppc/vm/interpreter_ppc.cpp Wed Jan 27 15:01:46 2016 +0100 +++ b/src/cpu/ppc/vm/interpreter_ppc.cpp Fri Feb 05 23:10:25 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" diff -r 737b321e6f0e -r aa6d8e03b258 src/cpu/ppc/vm/macroAssembler_ppc.cpp --- a/src/cpu/ppc/vm/macroAssembler_ppc.cpp Wed Jan 27 15:01:46 2016 +0100 +++ b/src/cpu/ppc/vm/macroAssembler_ppc.cpp Fri Feb 05 23:10:25 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) { diff -r 737b321e6f0e -r aa6d8e03b258 src/cpu/ppc/vm/sharedRuntime_ppc.cpp --- a/src/cpu/ppc/vm/sharedRuntime_ppc.cpp Wed Jan 27 15:01:46 2016 +0100 +++ b/src/cpu/ppc/vm/sharedRuntime_ppc.cpp Fri Feb 05 23:10:25 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); diff -r 737b321e6f0e -r aa6d8e03b258 src/cpu/sparc/vm/frame_sparc.cpp --- a/src/cpu/sparc/vm/frame_sparc.cpp Wed Jan 27 15:01:46 2016 +0100 +++ b/src/cpu/sparc/vm/frame_sparc.cpp Fri Feb 05 23:10:25 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 diff -r 737b321e6f0e -r aa6d8e03b258 src/cpu/x86/vm/macroAssembler_x86.cpp --- a/src/cpu/x86/vm/macroAssembler_x86.cpp Wed Jan 27 15:01:46 2016 +0100 +++ b/src/cpu/x86/vm/macroAssembler_x86.cpp Fri Feb 05 23:10:25 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); + } } } diff -r 737b321e6f0e -r aa6d8e03b258 src/cpu/x86/vm/x86_32.ad --- a/src/cpu/x86/vm/x86_32.ad Wed Jan 27 15:01:46 2016 +0100 +++ b/src/cpu/x86/vm/x86_32.ad Fri Feb 05 23:10:25 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); + } } } diff -r 737b321e6f0e -r aa6d8e03b258 src/cpu/x86/vm/x86_64.ad --- a/src/cpu/x86/vm/x86_64.ad Wed Jan 27 15:01:46 2016 +0100 +++ b/src/cpu/x86/vm/x86_64.ad Fri Feb 05 23:10:25 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); + } } } diff -r 737b321e6f0e -r aa6d8e03b258 src/cpu/zero/vm/frame_zero.cpp --- a/src/cpu/zero/vm/frame_zero.cpp Wed Jan 27 15:01:46 2016 +0100 +++ b/src/cpu/zero/vm/frame_zero.cpp Fri Feb 05 23:10:25 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); } } diff -r 737b321e6f0e -r aa6d8e03b258 src/os/aix/vm/perfMemory_aix.cpp --- a/src/os/aix/vm/perfMemory_aix.cpp Wed Jan 27 15:01:46 2016 +0100 +++ b/src/os/aix/vm/perfMemory_aix.cpp Fri Feb 05 23:10:25 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. * @@ -201,6 +201,7 @@ // the backing store files. Returns true if the directory is considered // a secure location. Returns false if the statbuf is a symbolic link or // if an error occurred. +// static bool is_statbuf_secure(struct stat *statp) { if (S_ISLNK(statp->st_mode) || !S_ISDIR(statp->st_mode)) { // The path represents a link or some non-directory file type, @@ -209,15 +210,18 @@ return false; } // We have an existing directory, check if the permissions are safe. + // if ((statp->st_mode & (S_IWGRP|S_IWOTH)) != 0) { // The directory is open for writing and could be subjected // to a symlink or a hard link attack. Declare it insecure. + // return false; } - // See if the uid of the directory matches the effective uid of the process. - // - if (statp->st_uid != geteuid()) { + // If user is not root then see if the uid of the directory matches the effective uid of the process. + uid_t euid = geteuid(); + if ((euid != 0) && (statp->st_uid != euid)) { // The directory was not created by this user, declare it insecure. + // return false; } return true; @@ -228,6 +232,7 @@ // the backing store files. Returns true if the directory exists // and is considered a secure location. Returns false if the path // is a symbolic link or if an error occurred. +// static bool is_directory_secure(const char* path) { struct stat statbuf; int result = 0; @@ -454,13 +459,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; diff -r 737b321e6f0e -r aa6d8e03b258 src/os/bsd/dtrace/hotspot.d --- a/src/os/bsd/dtrace/hotspot.d Wed Jan 27 15:01:46 2016 +0100 +++ b/src/os/bsd/dtrace/hotspot.d Fri Feb 05 23:10:25 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); diff -r 737b321e6f0e -r aa6d8e03b258 src/os/bsd/vm/perfMemory_bsd.cpp --- a/src/os/bsd/vm/perfMemory_bsd.cpp Wed Jan 27 15:01:46 2016 +0100 +++ b/src/os/bsd/vm/perfMemory_bsd.cpp Fri Feb 05 23:10:25 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 @@ -217,9 +217,9 @@ // return false; } - // See if the uid of the directory matches the effective uid of the process. - // - if (statp->st_uid != geteuid()) { + // If user is not root then see if the uid of the directory matches the effective uid of the process. + uid_t euid = geteuid(); + if ((euid != 0) && (statp->st_uid != euid)) { // The directory was not created by this user, declare it insecure. // return false; @@ -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. diff -r 737b321e6f0e -r aa6d8e03b258 src/os/linux/vm/perfMemory_linux.cpp --- a/src/os/linux/vm/perfMemory_linux.cpp Wed Jan 27 15:01:46 2016 +0100 +++ b/src/os/linux/vm/perfMemory_linux.cpp Fri Feb 05 23:10:25 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. diff -r 737b321e6f0e -r aa6d8e03b258 src/os/solaris/vm/os_solaris.cpp --- a/src/os/solaris/vm/os_solaris.cpp Wed Jan 27 15:01:46 2016 +0100 +++ b/src/os/solaris/vm/os_solaris.cpp Fri Feb 05 23:10:25 2016 -0800 @@ -2041,7 +2041,9 @@ st->print(", physical " UINT64_FORMAT "k", os::physical_memory()>>10); st->print("(" UINT64_FORMAT "k free)", os::available_memory() >> 10); st->cr(); - (void) check_addr0(st); + if (VMError::fatal_error_in_progress()) { + (void) check_addr0(st); + } } void os::print_siginfo(outputStream* st, void* siginfo) { diff -r 737b321e6f0e -r aa6d8e03b258 src/os/solaris/vm/perfMemory_solaris.cpp --- a/src/os/solaris/vm/perfMemory_solaris.cpp Wed Jan 27 15:01:46 2016 +0100 +++ b/src/os/solaris/vm/perfMemory_solaris.cpp Fri Feb 05 23:10:25 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. diff -r 737b321e6f0e -r aa6d8e03b258 src/os_cpu/linux_zero/vm/os_linux_zero.cpp --- a/src/os_cpu/linux_zero/vm/os_linux_zero.cpp Wed Jan 27 15:01:46 2016 +0100 +++ b/src/os_cpu/linux_zero/vm/os_linux_zero.cpp Fri Feb 05 23:10:25 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) { diff -r 737b321e6f0e -r aa6d8e03b258 src/share/vm/c1/c1_ValueType.cpp --- a/src/share/vm/c1/c1_ValueType.cpp Wed Jan 27 15:01:46 2016 +0100 +++ b/src/share/vm/c1/c1_ValueType.cpp Fri Feb 05 23:10:25 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; diff -r 737b321e6f0e -r aa6d8e03b258 src/share/vm/ci/ciField.cpp --- a/src/share/vm/ci/ciField.cpp Wed Jan 27 15:01:46 2016 +0100 +++ b/src/share/vm/ci/ciField.cpp Fri Feb 05 23:10:25 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; } diff -r 737b321e6f0e -r aa6d8e03b258 src/share/vm/classfile/classLoader.cpp --- a/src/share/vm/classfile/classLoader.cpp Wed Jan 27 15:01:46 2016 +0100 +++ b/src/share/vm/classfile/classLoader.cpp Fri Feb 05 23:10:25 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) { diff -r 737b321e6f0e -r aa6d8e03b258 src/share/vm/classfile/classLoader.hpp --- a/src/share/vm/classfile/classLoader.hpp Wed Jan 27 15:01:46 2016 +0100 +++ b/src/share/vm/classfile/classLoader.hpp Fri Feb 05 23:10:25 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(); diff -r 737b321e6f0e -r aa6d8e03b258 src/share/vm/classfile/sharedPathsMiscInfo.cpp --- a/src/share/vm/classfile/sharedPathsMiscInfo.cpp Wed Jan 27 15:01:46 2016 +0100 +++ b/src/share/vm/classfile/sharedPathsMiscInfo.cpp Fri Feb 05 23:10:25 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; } diff -r 737b321e6f0e -r aa6d8e03b258 src/share/vm/classfile/sharedPathsMiscInfo.hpp --- a/src/share/vm/classfile/sharedPathsMiscInfo.hpp Wed Jan 27 15:01:46 2016 +0100 +++ b/src/share/vm/classfile/sharedPathsMiscInfo.hpp Fri Feb 05 23:10:25 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); diff -r 737b321e6f0e -r aa6d8e03b258 src/share/vm/classfile/vmSymbols.hpp --- a/src/share/vm/classfile/vmSymbols.hpp Wed Jan 27 15:01:46 2016 +0100 +++ b/src/share/vm/classfile/vmSymbols.hpp Fri Feb 05 23:10:25 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 */ \ diff -r 737b321e6f0e -r aa6d8e03b258 src/share/vm/code/nmethod.cpp --- a/src/share/vm/code/nmethod.cpp Wed Jan 27 15:01:46 2016 +0100 +++ b/src/share/vm/code/nmethod.cpp Fri Feb 05 23:10:25 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); } } } diff -r 737b321e6f0e -r aa6d8e03b258 src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp --- a/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp Wed Jan 27 15:01:46 2016 +0100 +++ b/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp Fri Feb 05 23:10:25 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; } } @@ -3766,6 +3767,9 @@ _dcq.enqueue(card_ptr); } } + assert(hrrs.n_yielded() == r->rem_set()->occupied(), + err_msg("Remembered set hash maps out of sync, cur: " SIZE_FORMAT " entries, next: " SIZE_FORMAT " entries", + hrrs.n_yielded(), r->rem_set()->occupied())); r->rem_set()->clear_locked(); } assert(r->rem_set()->is_empty(), "At this point any humongous candidate remembered set must be empty."); @@ -4088,6 +4092,13 @@ g1_policy()->finalize_cset(target_pause_time_ms, evacuation_info); + // Make sure the remembered sets are up to date. This needs to be + // done before register_humongous_regions_with_cset(), because the + // remembered sets are used there to choose eager reclaim candidates. + // If the remembered sets are not up to date we might miss some + // entries that need to be handled. + g1_rem_set()->cleanupHRRS(); + register_humongous_regions_with_in_cset_fast_test(); assert(check_cset_fast_test(), "Inconsistency in the InCSetState table."); @@ -5045,12 +5056,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); } diff -r 737b321e6f0e -r aa6d8e03b258 src/share/vm/gc_implementation/g1/g1RemSet.cpp --- a/src/share/vm/gc_implementation/g1/g1RemSet.cpp Wed Jan 27 15:01:46 2016 +0100 +++ b/src/share/vm/gc_implementation/g1/g1RemSet.cpp Fri Feb 05 23:10:25 2016 -0800 @@ -335,7 +335,6 @@ } void G1RemSet::prepare_for_oops_into_collection_set_do() { - cleanupHRRS(); _g1->set_refine_cte_cl_concurrency(false); DirtyCardQueueSet& dcqs = JavaThread::dirty_card_queue_set(); dcqs.concatenate_logs(); diff -r 737b321e6f0e -r aa6d8e03b258 src/share/vm/gc_implementation/g1/heapRegionRemSet.cpp --- a/src/share/vm/gc_implementation/g1/heapRegionRemSet.cpp Wed Jan 27 15:01:46 2016 +0100 +++ b/src/share/vm/gc_implementation/g1/heapRegionRemSet.cpp Fri Feb 05 23:10:25 2016 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2016, 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 @@ -119,7 +119,9 @@ public: - HeapRegion* hr() const { return _hr; } + HeapRegion* hr() const { + return (HeapRegion*) OrderAccess::load_ptr_acquire(&_hr); + } jint occupied() const { // Overkill, but if we ever need it... @@ -132,10 +134,12 @@ set_next(NULL); set_prev(NULL); } - _hr = hr; _collision_list_next = NULL; _occupied = 0; _bm.clear(); + // Make sure that the bitmap clearing above has been finished before publishing + // this PRT to concurrent threads. + OrderAccess::release_store_ptr(&_hr, hr); } void add_reference(OopOrNarrowOopStar from) { @@ -441,7 +445,7 @@ if (G1TraceHeapRegionRememberedSet) { gclog_or_tty->print_cr(" from-card cache hit."); } - assert(contains_reference(from), "We just added it!"); + assert(contains_reference(from), err_msg("We just found " PTR_FORMAT " in the FromCardCache", from)); return; } @@ -454,7 +458,7 @@ if (G1TraceHeapRegionRememberedSet) { gclog_or_tty->print_cr(" coarse map hit."); } - assert(contains_reference(from), "We just added it!"); + assert(contains_reference(from), err_msg("We just found " PTR_FORMAT " in the Coarse table", from)); return; } @@ -488,7 +492,7 @@ if (G1TraceHeapRegionRememberedSet) { gclog_or_tty->print_cr(" added card to sparse table."); } - assert(contains_reference_locked(from), "We just added it!"); + assert(contains_reference_locked(from), err_msg("We just added " PTR_FORMAT " to the Sparse table", from)); return; } else { if (G1TraceHeapRegionRememberedSet) { @@ -547,7 +551,7 @@ hr()->bottom(), from); } } - assert(contains_reference(from), "We just added it!"); + assert(contains_reference(from), err_msg("We just added " PTR_FORMAT " to the PRT", from)); } PerRegionTable* diff -r 737b321e6f0e -r aa6d8e03b258 src/share/vm/gc_implementation/g1/vm_operations_g1.cpp --- a/src/share/vm/gc_implementation/g1/vm_operations_g1.cpp Wed Jan 27 15:01:46 2016 +0100 +++ b/src/share/vm/gc_implementation/g1/vm_operations_g1.cpp Fri Feb 05 23:10:25 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. diff -r 737b321e6f0e -r aa6d8e03b258 src/share/vm/gc_implementation/parallelScavenge/psParallelCompact.hpp --- a/src/share/vm/gc_implementation/parallelScavenge/psParallelCompact.hpp Wed Jan 27 15:01:46 2016 +0100 +++ b/src/share/vm/gc_implementation/parallelScavenge/psParallelCompact.hpp Fri Feb 05 23:10:25 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)); diff -r 737b321e6f0e -r aa6d8e03b258 src/share/vm/gc_interface/gcCause.cpp --- a/src/share/vm/gc_interface/gcCause.cpp Wed Jan 27 15:01:46 2016 +0100 +++ b/src/share/vm/gc_interface/gcCause.cpp Fri Feb 05 23:10:25 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"; diff -r 737b321e6f0e -r aa6d8e03b258 src/share/vm/gc_interface/gcCause.hpp --- a/src/share/vm/gc_interface/gcCause.hpp Wed Jan 27 15:01:46 2016 +0100 +++ b/src/share/vm/gc_interface/gcCause.hpp Fri Feb 05 23:10:25 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, diff -r 737b321e6f0e -r aa6d8e03b258 src/share/vm/memory/universe.cpp --- a/src/share/vm/memory/universe.cpp Wed Jan 27 15:01:46 2016 +0100 +++ b/src/share/vm/memory/universe.cpp Fri Feb 05 23:10:25 2016 -0800 @@ -114,6 +114,7 @@ LatestMethodCache* Universe::_finalizer_register_cache = NULL; LatestMethodCache* Universe::_loader_addClass_cache = NULL; LatestMethodCache* Universe::_pd_implies_cache = NULL; +LatestMethodCache* Universe::_throw_illegal_access_error_cache = NULL; oop Universe::_out_of_memory_error_java_heap = NULL; oop Universe::_out_of_memory_error_metaspace = NULL; oop Universe::_out_of_memory_error_class_metaspace = NULL; @@ -129,7 +130,6 @@ oop Universe::_vm_exception = NULL; oop Universe::_allocation_context_notification_obj = NULL; -Method* Universe::_throw_illegal_access_error = NULL; Array* Universe::_the_empty_int_array = NULL; Array* Universe::_the_empty_short_array = NULL; Array* Universe::_the_empty_klass_array = NULL; @@ -235,6 +235,7 @@ _finalizer_register_cache->serialize(f); _loader_addClass_cache->serialize(f); _pd_implies_cache->serialize(f); + _throw_illegal_access_error_cache->serialize(f); } void Universe::check_alignment(uintx size, uintx alignment, const char* name) { @@ -663,6 +664,7 @@ Universe::_finalizer_register_cache = new LatestMethodCache(); Universe::_loader_addClass_cache = new LatestMethodCache(); Universe::_pd_implies_cache = new LatestMethodCache(); + Universe::_throw_illegal_access_error_cache = new LatestMethodCache(); if (UseSharedSpaces) { // Read the data structures supporting the shared spaces (shared @@ -847,12 +849,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 +858,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 +872,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 +900,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 +987,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(); @@ -1134,7 +1137,8 @@ tty->print_cr("Unable to link/verify Unsafe.throwIllegalAccessError method"); return false; // initialization failed (cannot throw exception yet) } - Universe::_throw_illegal_access_error = m; + Universe::_throw_illegal_access_error_cache->init( + SystemDictionary::misc_Unsafe_klass(), m); // Setup method for registering loaded classes in class loader vector InstanceKlass::cast(SystemDictionary::ClassLoader_klass())->link_class(CHECK_false); @@ -1160,7 +1164,7 @@ return false; // initialization failed } Universe::_pd_implies_cache->init( - SystemDictionary::ProtectionDomain_klass(), m);; + SystemDictionary::ProtectionDomain_klass(), m); } // The folowing is initializing converter functions for serialization in diff -r 737b321e6f0e -r aa6d8e03b258 src/share/vm/memory/universe.hpp --- a/src/share/vm/memory/universe.hpp Wed Jan 27 15:01:46 2016 +0100 +++ b/src/share/vm/memory/universe.hpp Fri Feb 05 23:10:25 2016 -0800 @@ -148,8 +148,7 @@ static LatestMethodCache* _finalizer_register_cache; // static method for registering finalizable objects static LatestMethodCache* _loader_addClass_cache; // method for registering loaded classes in class loader vector static LatestMethodCache* _pd_implies_cache; // method for checking protection domain attributes - - static Method* _throw_illegal_access_error; + static LatestMethodCache* _throw_illegal_access_error_cache; // Unsafe.throwIllegalAccessError() method // preallocated error objects (no backtrace) static oop _out_of_memory_error_java_heap; @@ -305,6 +304,7 @@ static Method* loader_addClass_method() { return _loader_addClass_cache->get_method(); } static Method* protection_domain_implies_method() { return _pd_implies_cache->get_method(); } + static Method* throw_illegal_access_error() { return _throw_illegal_access_error_cache->get_method(); } static oop null_ptr_exception_instance() { return _null_ptr_exception_instance; } static oop arithmetic_exception_instance() { return _arithmetic_exception_instance; } @@ -314,8 +314,6 @@ static inline oop allocation_context_notification_obj(); static inline void set_allocation_context_notification_obj(oop obj); - static Method* throw_illegal_access_error() { return _throw_illegal_access_error; } - static Array* the_empty_int_array() { return _the_empty_int_array; } static Array* the_empty_short_array() { return _the_empty_short_array; } static Array* the_empty_method_array() { return _the_empty_method_array; } @@ -376,6 +374,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; diff -r 737b321e6f0e -r aa6d8e03b258 src/share/vm/oops/instanceKlass.cpp --- a/src/share/vm/oops/instanceKlass.cpp Wed Jan 27 15:01:46 2016 +0100 +++ b/src/share/vm/oops/instanceKlass.cpp Fri Feb 05 23:10:25 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()) { diff -r 737b321e6f0e -r aa6d8e03b258 src/share/vm/oops/instanceKlass.hpp --- a/src/share/vm/oops/instanceKlass.hpp Wed Jan 27 15:01:46 2016 +0100 +++ b/src/share/vm/oops/instanceKlass.hpp Fri Feb 05 23:10:25 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(); diff -r 737b321e6f0e -r aa6d8e03b258 src/share/vm/oops/klass.cpp --- a/src/share/vm/oops/klass.cpp Wed Jan 27 15:01:46 2016 +0100 +++ b/src/share/vm/oops/klass.cpp Fri Feb 05 23:10:25 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); } } } diff -r 737b321e6f0e -r aa6d8e03b258 src/share/vm/opto/c2_globals.hpp --- a/src/share/vm/opto/c2_globals.hpp Wed Jan 27 15:01:46 2016 +0100 +++ b/src/share/vm/opto/c2_globals.hpp Fri Feb 05 23:10:25 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) diff -r 737b321e6f0e -r aa6d8e03b258 src/share/vm/opto/compile.cpp --- a/src/share/vm/opto/compile.cpp Wed Jan 27 15:01:46 2016 +0100 +++ b/src/share/vm/opto/compile.cpp Fri Feb 05 23:10:25 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()) { diff -r 737b321e6f0e -r aa6d8e03b258 src/share/vm/opto/loopTransform.cpp --- a/src/share/vm/opto/loopTransform.cpp Wed Jan 27 15:01:46 2016 +0100 +++ b/src/share/vm/opto/loopTransform.cpp Fri Feb 05 23:10:25 2016 -0800 @@ -1739,6 +1739,12 @@ } return true; } + if (is_scaled_iv(exp->in(2), iv, p_scale)) { + if (p_offset != NULL) { + *p_offset = exp->in(1); + } + return true; + } if (exp->in(2)->is_Con()) { Node* offset2 = NULL; if (depth < 2 && diff -r 737b321e6f0e -r aa6d8e03b258 src/share/vm/opto/loopnode.cpp --- a/src/share/vm/opto/loopnode.cpp Wed Jan 27 15:01:46 2016 +0100 +++ b/src/share/vm/opto/loopnode.cpp Fri Feb 05 23:10:25 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(); } @@ -2303,6 +2328,11 @@ #endif if (skip_loop_opts) { + // restore major progress flag + for (int i = 0; i < old_progress; i++) { + C->set_major_progress(); + } + // Cleanup any modified bits _igvn.optimize(); diff -r 737b321e6f0e -r aa6d8e03b258 src/share/vm/opto/loopnode.hpp --- a/src/share/vm/opto/loopnode.hpp Wed Jan 27 15:01:46 2016 +0100 +++ b/src/share/vm/opto/loopnode.hpp Fri Feb 05 23:10:25 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 ); diff -r 737b321e6f0e -r aa6d8e03b258 src/share/vm/opto/node.cpp --- a/src/share/vm/opto/node.cpp Wed Jan 27 15:01:46 2016 +0100 +++ b/src/share/vm/opto/node.cpp Fri Feb 05 23:10:25 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 ) { diff -r 737b321e6f0e -r aa6d8e03b258 src/share/vm/opto/node.hpp --- a/src/share/vm/opto/node.hpp Wed Jan 27 15:01:46 2016 +0100 +++ b/src/share/vm/opto/node.hpp Fri Feb 05 23:10:25 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------------------------------- diff -r 737b321e6f0e -r aa6d8e03b258 src/share/vm/opto/phase.cpp --- a/src/share/vm/opto/phase.cpp Wed Jan 27 15:01:46 2016 +0100 +++ b/src/share/vm/opto/phase.cpp Fri Feb 05 23:10:25 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(); diff -r 737b321e6f0e -r aa6d8e03b258 src/share/vm/opto/phase.hpp --- a/src/share/vm/opto/phase.hpp Wed Jan 27 15:01:46 2016 +0100 +++ b/src/share/vm/opto/phase.hpp Fri Feb 05 23:10:25 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; diff -r 737b321e6f0e -r aa6d8e03b258 src/share/vm/opto/phaseX.cpp --- a/src/share/vm/opto/phaseX.cpp Wed Jan 27 15:01:46 2016 +0100 +++ b/src/share/vm/opto/phaseX.cpp Fri Feb 05 23:10:25 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--------------------------------- diff -r 737b321e6f0e -r aa6d8e03b258 src/share/vm/opto/phaseX.hpp --- a/src/share/vm/opto/phaseX.hpp Wed Jan 27 15:01:46 2016 +0100 +++ b/src/share/vm/opto/phaseX.hpp Fri Feb 05 23:10:25 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. diff -r 737b321e6f0e -r aa6d8e03b258 src/share/vm/prims/jni.cpp --- a/src/share/vm/prims/jni.cpp Wed Jan 27 15:01:46 2016 +0100 +++ b/src/share/vm/prims/jni.cpp Fri Feb 05 23:10:25 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()); @@ -3139,7 +3139,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), diff -r 737b321e6f0e -r aa6d8e03b258 src/share/vm/prims/jvmtiRedefineClasses.cpp --- a/src/share/vm/prims/jvmtiRedefineClasses.cpp Wed Jan 27 15:01:46 2016 +0100 +++ b/src/share/vm/prims/jvmtiRedefineClasses.cpp Fri Feb 05 23:10:25 2016 -0800 @@ -3378,7 +3378,9 @@ // not yet in the vtable, because the vtable setup is in progress. // This must be done after we adjust the default_methods and // default_vtable_indices for methods already in the vtable. + // If redefining Unsafe, walk all the vtables looking for entries. if (ik->vtable_length() > 0 && (_the_class_oop->is_interface() + || _the_class_oop == SystemDictionary::misc_Unsafe_klass() || ik->is_subtype_of(_the_class_oop))) { // ik->vtable() creates a wrapper object; rm cleans it up ResourceMark rm(_thread); @@ -3393,7 +3395,9 @@ // interface, then we have to call adjust_method_entries() for // every InstanceKlass that has an itable since there isn't a // subclass relationship between an interface and an InstanceKlass. + // If redefining Unsafe, walk all the itables looking for entries. if (ik->itable_length() > 0 && (_the_class_oop->is_interface() + || _the_class_oop == SystemDictionary::misc_Unsafe_klass() || ik->is_subclass_of(_the_class_oop))) { // ik->itable() creates a wrapper object; rm cleans it up ResourceMark rm(_thread); diff -r 737b321e6f0e -r aa6d8e03b258 src/share/vm/prims/whitebox.cpp --- a/src/share/vm/prims/whitebox.cpp Wed Jan 27 15:01:46 2016 +0100 +++ b/src/share/vm/prims/whitebox.cpp Fri Feb 05 23:10:25 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 diff -r 737b321e6f0e -r aa6d8e03b258 src/share/vm/runtime/arguments.cpp --- a/src/share/vm/runtime/arguments.cpp Wed Jan 27 15:01:46 2016 +0100 +++ b/src/share/vm/runtime/arguments.cpp Fri Feb 05 23:10:25 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()); } } diff -r 737b321e6f0e -r aa6d8e03b258 src/share/vm/runtime/globals.hpp --- a/src/share/vm/runtime/globals.hpp Wed Jan 27 15:01:46 2016 +0100 +++ b/src/share/vm/runtime/globals.hpp Fri Feb 05 23:10:25 2016 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2016, 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 @@ -1279,6 +1279,13 @@ "Decay time (in milliseconds) to re-enable bulk rebiasing of a " \ "type after previous bulk rebias") \ \ + product(bool, ExitOnOutOfMemoryError, false, \ + "JVM exits on the first occurrence of an out-of-memory error") \ + \ + product(bool, CrashOnOutOfMemoryError, false, \ + "JVM aborts, producing an error log and core/mini dump, on the " \ + "first occurrence of an out-of-memory error") \ + \ /* tracing */ \ \ notproduct(bool, TraceRuntimeCalls, false, \ diff -r 737b321e6f0e -r aa6d8e03b258 src/share/vm/runtime/safepoint.cpp --- a/src/share/vm/runtime/safepoint.cpp Wed Jan 27 15:01:46 2016 +0100 +++ b/src/share/vm/runtime/safepoint.cpp Fri Feb 05 23:10:25 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; i1print("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); } diff -r 737b321e6f0e -r aa6d8e03b258 src/share/vm/runtime/synchronizer.cpp --- a/src/share/vm/runtime/synchronizer.cpp Wed Jan 27 15:01:46 2016 +0100 +++ b/src/share/vm/runtime/synchronizer.cpp Fri Feb 05 23:10:25 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) \ { \ diff -r 737b321e6f0e -r aa6d8e03b258 src/share/vm/runtime/thread.cpp --- a/src/share/vm/runtime/thread.cpp Wed Jan 27 15:01:46 2016 +0100 +++ b/src/share/vm/runtime/thread.cpp Fri Feb 05 23:10:25 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) \ { \ diff -r 737b321e6f0e -r aa6d8e03b258 src/share/vm/utilities/debug.cpp --- a/src/share/vm/utilities/debug.cpp Wed Jan 27 15:01:46 2016 +0100 +++ b/src/share/vm/utilities/debug.cpp Fri Feb 05 23:10:25 2016 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2016, 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 @@ -302,6 +302,16 @@ VMError err(message); err.report_java_out_of_memory(); } + + if (CrashOnOutOfMemoryError) { + tty->print_cr("Aborting due to java.lang.OutOfMemoryError: %s", message); + fatal(err_msg("OutOfMemory encountered: %s", message)); + } + + if (ExitOnOutOfMemoryError) { + tty->print_cr("Terminating due to java.lang.OutOfMemoryError: %s", message); + exit(3); + } } } diff -r 737b321e6f0e -r aa6d8e03b258 src/share/vm/utilities/vmError.cpp --- a/src/share/vm/utilities/vmError.cpp Wed Jan 27 15:01:46 2016 +0100 +++ b/src/share/vm/utilities/vmError.cpp Fri Feb 05 23:10:25 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)") diff -r 737b321e6f0e -r aa6d8e03b258 test/TEST.groups --- a/test/TEST.groups Wed Jan 27 15:01:46 2016 +0100 +++ b/test/TEST.groups Fri Feb 05 23:10:25 2016 -0800 @@ -96,7 +96,8 @@ runtime/Thread/TestThreadDumpMonitorContention.java \ runtime/XCheckJniJsig/XCheckJSig.java \ serviceability/attach/AttachWithStalePidFile.java \ - serviceability/sa/jmap-hprof/JMapHProfLargeHeapTest.java + serviceability/sa/jmap-hprof/JMapHProfLargeHeapTest.java \ + testlibrary_tests/ # JRE adds further tests to compact3 @@ -251,7 +252,6 @@ serviceability/ \ compiler/ \ testlibrary/ \ - testlibrary_tests/ \ sanity/ \ runtime/ \ gc/ \ diff -r 737b321e6f0e -r aa6d8e03b258 test/compiler/loopopts/UseCountedLoopSafepoints.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/compiler/loopopts/UseCountedLoopSafepoints.java Fri Feb 05 23:10:25 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); + } + } +} diff -r 737b321e6f0e -r aa6d8e03b258 test/gc/whitebox/TestConcMarkCycleWB.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/gc/whitebox/TestConcMarkCycleWB.java Fri Feb 05 23:10:25 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()); + } +} diff -r 737b321e6f0e -r aa6d8e03b258 test/gc_implementation/g1/TestNoEagerReclaimOfHumongousRegions.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/gc_implementation/g1/TestNoEagerReclaimOfHumongousRegions.java Fri Feb 05 23:10:25 2016 -0800 @@ -0,0 +1,91 @@ +/* + * 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 TestNoEagerReclaimOfHumongousRegions + * @bug 8139424 + * @summary Test to check that a live humongous object is not eagerly reclaimed. This is a regression test for + * 8139424 and the test will crash if an eager reclaim occur. The test is not 100% deterministic and + * might pass even if there are problems in the code, but it will never crash unless there is a problem. + * @requires vm.gc=="G1" | vm.gc=="null" + * @key gc + * @library /testlibrary /testlibrary/whitebox + * @modules java.base/sun.misc + * @build TestNoEagerReclaimOfHumongousRegions + * @run main ClassFileInstaller sun.hotspot.WhiteBox + * sun.hotspot.WhiteBox$WhiteBoxPermission + * @run main/othervm -Xbootclasspath/a:. -XX:+PrintGC -XX:+UseG1GC -XX:MaxTenuringThreshold=0 -XX:G1RSetSparseRegionEntries=32 -XX:G1HeapRegionSize=1m -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -XX:+UnlockExperimentalVMOptions -XX:+G1TraceEagerReclaimHumongousObjects TestNoEagerReclaimOfHumongousRegions + */ + +import java.util.LinkedList; + +import sun.hotspot.WhiteBox; + +public class TestNoEagerReclaimOfHumongousRegions { + // Helper class to keep reference to humongous byte[]. + static class LargeRef { + private byte[] _ref; + + LargeRef(byte[] ref) { + _ref = ref; + } + + byte[] ref() { return _ref; } + } + + static LargeRef humongous_reference_holder; + + public static void main(String[] args) throws InterruptedException{ + WhiteBox wb = WhiteBox.getWhiteBox(); + LinkedList garbageAndRefList = new LinkedList(); + // Creating a 1M large byte array. Since the test specifies the heap + // region size to be 1m this will be a humongous object. We then + // store a pointer to the array in the static object to keep it live + // during the whole test. + humongous_reference_holder = new LargeRef(new byte[1 * 1024 * 1024]); + + // Create some garbage and a reference to the humongous object each round. + for (int i = 0; i < 32; i++) { + garbageAndRefList.add(new byte[400*1000]); + garbageAndRefList.add(new LargeRef(humongous_reference_holder.ref())); + + // Promote to old, goal is to get rem-set entries for the humongous + // object from different regions. The test specifies MaxTenuringThreshold=0, + // this will make sure we get objects promoted to old at once. + wb.youngGC(); + } + // Clear the garbage and reference list. + garbageAndRefList.clear(); + + // Run a concurrent mark cycle to mark all references but the static one as dead. + wb.g1StartConcMarkCycle(); + while (wb.g1InConcurrentMark()) { + Thread.sleep(100); + } + + // Run a young collection to make sure humongous object still can't be eagerly reclaimed. + wb.youngGC(); + // Will crash/assert if humongous object has been reclaimed. + wb.fullGC(); + } +} diff -r 737b321e6f0e -r aa6d8e03b258 test/runtime/ErrorHandling/TestCrashOnOutOfMemoryError.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/runtime/ErrorHandling/TestCrashOnOutOfMemoryError.java Fri Feb 05 23:10:25 2016 -0800 @@ -0,0 +1,106 @@ +/* + * Copyright (c) 2015, 2016, 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 TestCrashOnOutOfMemoryError + * @summary Test using -XX:+CrashOnOutOfMemoryError + * @library /testlibrary + * @build jdk.test.lib.* + * @run driver TestCrashOnOutOfMemoryError + * @bug 8138745 + */ + +import com.oracle.java.testlibrary.OutputAnalyzer; +import com.oracle.java.testlibrary.ProcessTools; +import java.io.BufferedReader; +import java.io.File; +import java.io.FileInputStream; +import java.io.InputStreamReader; +import java.io.IOException; + +public class TestCrashOnOutOfMemoryError { + + public static void main(String[] args) throws Exception { + if (args.length == 1) { + // This should guarantee to throw: + // java.lang.OutOfMemoryError: Requested array size exceeds VM limit + try { + Object[] oa = new Object[Integer.MAX_VALUE]; + throw new Error("OOME not triggered"); + } catch (OutOfMemoryError err) { + throw new Error("OOME didn't abort JVM!"); + } + } + // else this is the main test + ProcessBuilder pb = ProcessTools.createJavaProcessBuilder("-XX:+CrashOnOutOfMemoryError", + "-Xmx64m", TestCrashOnOutOfMemoryError.class.getName(),"throwOOME"); + OutputAnalyzer output = new OutputAnalyzer(pb.start()); + int exitValue = output.getExitValue(); + if (0 == exitValue) { + //expecting a non zero value + throw new Error("Expected to get non zero exit value"); + } + + /* Output should look something like this. The actual text will depend on the OS and its core dump processing. + Aborting due to java.lang.OutOfMemoryError: Requested array size exceeds VM limit + # To suppress the following error report, specify this argument + # after -XX: or in .hotspotrc: SuppressErrorAt=/debug.cpp:303 + # + # A fatal error has been detected by the Java Runtime Environment: + # + # Internal Error (/home/cheleswer/Desktop/jdk9/dev/hotspot/src/share/vm/utilities/debug.cpp:303), pid=6212, tid=6213 + # fatal error: OutOfMemory encountered: Requested array size exceeds VM limit + # + # JRE version: OpenJDK Runtime Environment (9.0) (build 1.9.0-internal-debug-cheleswer_2015_10_20_14_32-b00) + # Java VM: OpenJDK 64-Bit Server VM (1.9.0-internal-debug-cheleswer_2015_10_20_14_32-b00, mixed mode, tiered, compressed oops, serial gc, linux-amd64) + # Core dump will be written. Default location: Core dumps may be processed with "/usr/share/apport/apport %p %s %c %P" (or dumping to + /home/cheleswer/Desktop/core.6212) + # + # An error report file with more information is saved as: + # /home/cheleswer/Desktop/hs_err_pid6212.log + # + # If you would like to submit a bug report, please visit: + # http://bugreport.java.com/bugreport/crash.jsp + # + Current thread is 6213 + Dumping core ... + Aborted (core dumped) + */ + output.shouldContain("Aborting due to java.lang.OutOfMemoryError: Requested array size exceeds VM limit"); + // extract hs-err file + String hs_err_file = output.firstMatch("# *(\\S*hs_err_pid\\d+\\.log)", 1); + if (hs_err_file == null) { + throw new Error("Did not find hs-err file in output.\n"); + } + + /* + * Check if hs_err files exist or not + */ + File f = new File(hs_err_file); + if (!f.exists()) { + throw new Error("hs-err file missing at "+ f.getAbsolutePath() + ".\n"); + } + + System.out.println("PASSED"); + } +} diff -r 737b321e6f0e -r aa6d8e03b258 test/runtime/ErrorHandling/TestExitOnOutOfMemoryError.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/runtime/ErrorHandling/TestExitOnOutOfMemoryError.java Fri Feb 05 23:10:25 2016 -0800 @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2015, 2016, 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 TestExitOnOutOfMemoryError + * @summary Test using -XX:ExitOnOutOfMemoryError + * @library /testlibrary + * @build jdk.test.lib.* + * @run driver TestExitOnOutOfMemoryError + * @bug 8138745 + */ + +import com.oracle.java.testlibrary.ProcessTools; +import com.oracle.java.testlibrary.OutputAnalyzer; + +public class TestExitOnOutOfMemoryError { + + public static void main(String[] args) throws Exception { + if (args.length == 1) { + // This should guarantee to throw: + // java.lang.OutOfMemoryError: Requested array size exceeds VM limit + try { + Object[] oa = new Object[Integer.MAX_VALUE]; + throw new Error("OOME not triggered"); + } catch (OutOfMemoryError err) { + throw new Error("OOME didn't terminate JVM!"); + } + } + + // else this is the main test + ProcessBuilder pb = ProcessTools.createJavaProcessBuilder("-XX:+ExitOnOutOfMemoryError", + "-Xmx64m", TestExitOnOutOfMemoryError.class.getName(), "throwOOME"); + OutputAnalyzer output = new OutputAnalyzer(pb.start()); + + /* + * Actual output should look like this: + * Terminating due to java.lang.OutOfMemoryError: Requested array size exceeds VM limit + */ + output.shouldHaveExitValue(3); + output.shouldContain("Terminating due to java.lang.OutOfMemoryError: Requested array size exceeds VM limit"); + System.out.println("PASSED"); + } +} diff -r 737b321e6f0e -r aa6d8e03b258 test/runtime/NMT/JcmdWithNMTDisabled.java --- a/test/runtime/NMT/JcmdWithNMTDisabled.java Wed Jan 27 15:01:46 2016 +0100 +++ b/test/runtime/NMT/JcmdWithNMTDisabled.java Fri Feb 05 23:10:25 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()); diff -r 737b321e6f0e -r aa6d8e03b258 test/testlibrary/com/oracle/java/testlibrary/OutputAnalyzer.java --- a/test/testlibrary/com/oracle/java/testlibrary/OutputAnalyzer.java Wed Jan 27 15:01:46 2016 +0100 +++ b/test/testlibrary/com/oracle/java/testlibrary/OutputAnalyzer.java Fri Feb 05 23:10:25 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; } diff -r 737b321e6f0e -r aa6d8e03b258 test/testlibrary/whitebox/sun/hotspot/WhiteBox.java --- a/test/testlibrary/whitebox/sun/hotspot/WhiteBox.java Wed Jan 27 15:01:46 2016 +0100 +++ b/test/testlibrary/whitebox/sun/hotspot/WhiteBox.java Fri Feb 05 23:10:25 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();