From 68ffb0bf12fc8629c9a289af7499a9c8d3295a23 Mon Sep 17 00:00:00 2001 From: Jungwoo Ha Date: Tue, 3 Nov 2015 13:03:04 -0800 Subject: [PATCH 01/20] 8141356: Explicitly stop CMS threads during VM termination GenCollectedHeap::stop() is not implemented which is supposed to stop CMS threads during VM termination. Reviewed-by: jmasa, kbarrett --- hotspot/src/share/vm/gc/shared/genCollectedHeap.cpp | 8 ++++++++ hotspot/src/share/vm/gc/shared/genCollectedHeap.hpp | 3 +++ 2 files changed, 11 insertions(+) diff --git a/hotspot/src/share/vm/gc/shared/genCollectedHeap.cpp b/hotspot/src/share/vm/gc/shared/genCollectedHeap.cpp index 5724808b142..bfa47a3734a 100644 --- a/hotspot/src/share/vm/gc/shared/genCollectedHeap.cpp +++ b/hotspot/src/share/vm/gc/shared/genCollectedHeap.cpp @@ -1319,3 +1319,11 @@ jlong GenCollectedHeap::millis_since_last_gc() { } return retVal; } + +void GenCollectedHeap::stop() { +#if INCLUDE_ALL_GCS + if (UseConcMarkSweepGC) { + ConcurrentMarkSweepThread::stop(); + } +#endif +} diff --git a/hotspot/src/share/vm/gc/shared/genCollectedHeap.hpp b/hotspot/src/share/vm/gc/shared/genCollectedHeap.hpp index 954bc8ad281..11114dd38f0 100644 --- a/hotspot/src/share/vm/gc/shared/genCollectedHeap.hpp +++ b/hotspot/src/share/vm/gc/shared/genCollectedHeap.hpp @@ -499,6 +499,9 @@ private: protected: void gc_prologue(bool full); void gc_epilogue(bool full); + +public: + void stop(); }; #endif // SHARE_VM_GC_SHARED_GENCOLLECTEDHEAP_HPP From 0a4657e8c129da85040c00dd8fb9425ea69a38fe Mon Sep 17 00:00:00 2001 From: Goetz Lindenmaier Date: Thu, 5 Nov 2015 15:05:59 +0100 Subject: [PATCH 02/20] 8141529: Fix handling of _JAVA_SR_SIGNUM Reviewed-by: dholmes, stuefe, dsamersoff --- hotspot/src/os/aix/vm/jsig.c | 42 +++++++++++------------- hotspot/src/os/aix/vm/os_aix.cpp | 31 ++++++++++------- hotspot/src/os/aix/vm/os_aix.hpp | 9 ----- hotspot/src/os/bsd/vm/jsig.c | 12 ++++--- hotspot/src/os/bsd/vm/os_bsd.cpp | 31 ++++++++++------- hotspot/src/os/bsd/vm/os_bsd.hpp | 7 ---- hotspot/src/os/linux/vm/jsig.c | 21 +++++++----- hotspot/src/os/linux/vm/os_linux.cpp | 31 ++++++++++------- hotspot/src/os/linux/vm/os_linux.hpp | 8 ----- hotspot/src/os/solaris/vm/os_solaris.hpp | 3 -- 10 files changed, 97 insertions(+), 98 deletions(-) diff --git a/hotspot/src/os/aix/vm/jsig.c b/hotspot/src/os/aix/vm/jsig.c index ca15dc595ac..d39fbe311eb 100644 --- a/hotspot/src/os/aix/vm/jsig.c +++ b/hotspot/src/os/aix/vm/jsig.c @@ -1,6 +1,6 @@ /* - * Copyright (c) 2001, 2013, Oracle and/or its affiliates. All rights reserved. - * Copyright 2012, 2013 SAP AG. All rights reserved. + * Copyright (c) 2001, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright 2012, 2015 SAP AG. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -36,26 +36,23 @@ #include #include #include +#include #define bool int #define true 1 #define false 0 -// Highest so far on AIX 5.2 is SIGSAK (63) -#define MAXSIGNUM 63 -#define MASK(sig) ((unsigned int)1 << sig) +static struct sigaction sact[NSIG]; /* saved signal handlers */ +static sigset_t jvmsigs; /* Signals used by jvm. */ -static struct sigaction sact[MAXSIGNUM]; /* saved signal handlers */ -static unsigned int jvmsigs = 0; /* signals used by jvm */ - -/* used to synchronize the installation of signal handlers */ +/* Used to synchronize the installation of signal handlers. */ static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; static pthread_cond_t cond = PTHREAD_COND_INITIALIZER; static pthread_t tid = 0; typedef void (*sa_handler_t)(int); typedef void (*sa_sigaction_t)(int, siginfo_t *, void *); -// signal_t is already defined on AIX +// signal_t is already defined on AIX. typedef sa_handler_t (*signal_like_function_t)(int, sa_handler_t); typedef int (*sigaction_t)(int, const struct sigaction *, struct sigaction *); @@ -68,7 +65,7 @@ static bool jvm_signal_installed = false; static void signal_lock() { pthread_mutex_lock(&mutex); /* When the jvm is installing its set of signal handlers, threads - * other than the jvm thread should wait */ + * other than the jvm thread should wait. */ if (jvm_signal_installing) { if (tid != pthread_self()) { pthread_cond_wait(&cond, &mutex); @@ -84,10 +81,10 @@ static sa_handler_t call_os_signal(int sig, sa_handler_t disp, bool is_sigset) { if (os_signal == NULL) { if (!is_sigset) { - // Aix: call functions directly instead of dlsym'ing them + // Aix: call functions directly instead of dlsym'ing them. os_signal = signal; } else { - // Aix: call functions directly instead of dlsym'ing them + // Aix: call functions directly instead of dlsym'ing them. os_signal = sigset; } if (os_signal == NULL) { @@ -112,7 +109,7 @@ static sa_handler_t set_signal(int sig, sa_handler_t disp, bool is_sigset) { signal_lock(); - sigused = (MASK(sig) & jvmsigs) != 0; + sigused = sigismember(&jvmsigs, sig); if (jvm_signal_installed && sigused) { /* jvm has installed its signal handler for this signal. */ /* Save the handler. Don't really install it. */ @@ -129,7 +126,7 @@ static sa_handler_t set_signal(int sig, sa_handler_t disp, bool is_sigset) { save_signal_handler(sig, oldhandler); /* Record the signals used by jvm */ - jvmsigs |= MASK(sig); + sigaddset(&jvmsigs, sig); signal_unlock(); return oldhandler; @@ -149,12 +146,12 @@ sa_handler_t signal(int sig, sa_handler_t disp) { sa_handler_t sigset(int sig, sa_handler_t disp) { return set_signal(sig, disp, true); - } +} static int call_os_sigaction(int sig, const struct sigaction *act, struct sigaction *oact) { if (os_sigaction == NULL) { - // Aix: call functions directly instead of dlsym'ing them + // Aix: call functions directly instead of dlsym'ing them. os_sigaction = sigaction; if (os_sigaction == NULL) { printf("%s\n", dlerror()); @@ -171,7 +168,7 @@ int sigaction(int sig, const struct sigaction *act, struct sigaction *oact) { signal_lock(); - sigused = (MASK(sig) & jvmsigs) != 0; + sigused = sigismember(&jvmsigs, sig); if (jvm_signal_installed && sigused) { /* jvm has installed its signal handler for this signal. */ /* Save the handler. Don't really install it. */ @@ -193,8 +190,8 @@ int sigaction(int sig, const struct sigaction *act, struct sigaction *oact) { *oact = oldAct; } - /* Record the signals used by jvm */ - jvmsigs |= MASK(sig); + /* Record the signals used by jvm. */ + sigaddset(&jvmsigs, sig); signal_unlock(); return res; @@ -208,9 +205,10 @@ int sigaction(int sig, const struct sigaction *act, struct sigaction *oact) { } } -/* The three functions for the jvm to call into */ +/* The three functions for the jvm to call into. */ void JVM_begin_signal_setting() { signal_lock(); + sigemptyset(&jvmsigs); jvm_signal_installing = true; tid = pthread_self(); signal_unlock(); @@ -226,7 +224,7 @@ void JVM_end_signal_setting() { struct sigaction *JVM_get_signal_action(int sig) { /* Does race condition make sense here? */ - if ((MASK(sig) & jvmsigs) != 0) { + if (sigismember(&jvmsigs, sig)) { return &sact[sig]; } return NULL; diff --git a/hotspot/src/os/aix/vm/os_aix.cpp b/hotspot/src/os/aix/vm/os_aix.cpp index 9bc5ab02f06..b45a9d360aa 100644 --- a/hotspot/src/os/aix/vm/os_aix.cpp +++ b/hotspot/src/os/aix/vm/os_aix.cpp @@ -2769,8 +2769,12 @@ static int SR_initialize() { // Get signal number to use for suspend/resume if ((s = ::getenv("_JAVA_SR_SIGNUM")) != 0) { int sig = ::strtol(s, 0, 10); - if (sig > 0 || sig < NSIG) { + if (sig > MAX2(SIGSEGV, SIGBUS) && // See 4355769. + sig < NSIG) { // Must be legal signal and fit into sigflags[]. SR_signum = sig; + } else { + warning("You set _JAVA_SR_SIGNUM=%d. It must be in range [%d, %d]. Using %d instead.", + sig, MAX2(SIGSEGV, SIGBUS)+1, NSIG-1, SR_signum); } } @@ -2966,8 +2970,8 @@ void javaSignalHandler(int sig, siginfo_t* info, void* uc) { bool os::Aix::signal_handlers_are_installed = false; // For signal-chaining -struct sigaction os::Aix::sigact[MAXSIGNUM]; -unsigned int os::Aix::sigs = 0; +struct sigaction sigact[NSIG]; +sigset_t sigs; bool os::Aix::libjsig_is_loaded = false; typedef struct sigaction *(*get_signal_t)(int); get_signal_t os::Aix::get_signal_action = NULL; @@ -3045,29 +3049,31 @@ bool os::Aix::chained_handler(int sig, siginfo_t* siginfo, void* context) { } struct sigaction* os::Aix::get_preinstalled_handler(int sig) { - if ((((unsigned int)1 << sig) & sigs) != 0) { + if (sigismember(&sigs, sig)) { return &sigact[sig]; } return NULL; } void os::Aix::save_preinstalled_handler(int sig, struct sigaction& oldAct) { - assert(sig > 0 && sig < MAXSIGNUM, "vm signal out of expected range"); + assert(sig > 0 && sig < NSIG, "vm signal out of expected range"); sigact[sig] = oldAct; - sigs |= (unsigned int)1 << sig; + sigaddset(&sigs, sig); } // for diagnostic -int os::Aix::sigflags[MAXSIGNUM]; +int sigflags[NSIG]; int os::Aix::get_our_sigflags(int sig) { - assert(sig > 0 && sig < MAXSIGNUM, "vm signal out of expected range"); + assert(sig > 0 && sig < NSIG, "vm signal out of expected range"); return sigflags[sig]; } void os::Aix::set_our_sigflags(int sig, int flags) { - assert(sig > 0 && sig < MAXSIGNUM, "vm signal out of expected range"); - sigflags[sig] = flags; + assert(sig > 0 && sig < NSIG, "vm signal out of expected range"); + if (sig > 0 && sig < NSIG) { + sigflags[sig] = flags; + } } void os::Aix::set_signal_handler(int sig, bool set_installed) { @@ -3107,7 +3113,7 @@ void os::Aix::set_signal_handler(int sig, bool set_installed) { sigAct.sa_flags = SA_SIGINFO|SA_RESTART; } // Save flags, which are set by ours - assert(sig > 0 && sig < MAXSIGNUM, "vm signal out of expected range"); + assert(sig > 0 && sig < NSIG, "vm signal out of expected range"); sigflags[sig] = sigAct.sa_flags; int ret = sigaction(sig, &sigAct, &oldAct); @@ -3140,10 +3146,11 @@ void os::Aix::install_signal_handlers() { assert(UseSignalChaining, "should enable signal-chaining"); } if (libjsig_is_loaded) { - // Tell libjsig jvm is setting signal handlers + // Tell libjsig jvm is setting signal handlers. (*begin_signal_setting)(); } + ::sigemptyset(&sigs); set_signal_handler(SIGSEGV, true); set_signal_handler(SIGPIPE, true); set_signal_handler(SIGBUS, true); diff --git a/hotspot/src/os/aix/vm/os_aix.hpp b/hotspot/src/os/aix/vm/os_aix.hpp index 8e96dd9f6c5..7381da500e2 100644 --- a/hotspot/src/os/aix/vm/os_aix.hpp +++ b/hotspot/src/os/aix/vm/os_aix.hpp @@ -34,15 +34,9 @@ static bool zero_page_read_protected() { return false; } class Aix { friend class os; - // For signal-chaining - // highest so far (AIX 5.2 - 6.1) is SIGSAK (63) -#define MAXSIGNUM 63 // Length of strings included in the libperfstat structures. #define IDENTIFIER_LENGTH 64 - static struct sigaction sigact[MAXSIGNUM]; // saved preinstalled sigactions - static unsigned int sigs; // mask of signals that have - // preinstalled signal handlers static bool libjsig_is_loaded; // libjsig that interposes sigaction(), // __sigaction(), signal() is loaded static struct sigaction *(*get_signal_action)(int); @@ -51,9 +45,6 @@ class Aix { static void check_signal_handler(int sig); - // For signal flags diagnostics - static int sigflags[MAXSIGNUM]; - protected: static julong _physical_memory; diff --git a/hotspot/src/os/bsd/vm/jsig.c b/hotspot/src/os/bsd/vm/jsig.c index 597e57ab75a..d7b1e8be1a7 100644 --- a/hotspot/src/os/bsd/vm/jsig.c +++ b/hotspot/src/os/bsd/vm/jsig.c @@ -36,12 +36,14 @@ #include #include #include +#include -#define MAXSIGNUM 32 -#define MASK(sig) ((unsigned int)1 << sig) - -static struct sigaction sact[MAXSIGNUM]; /* saved signal handlers */ -static unsigned int jvmsigs = 0; /* signals used by jvm */ +#define MASK(sig) ((uint32_t)1 << (sig-1)) // 0 is not a signal. +#if (32 < NSIG-1) +#error "Not all signals can be encoded in jvmsigs. Adapt its type!" +#endif +static struct sigaction sact[NSIG]; /* saved signal handlers */ +static uint32_t jvmsigs = 0; /* signals used by jvm */ static __thread bool reentry = false; /* prevent reentry deadlock (per-thread) */ /* used to synchronize the installation of signal handlers */ diff --git a/hotspot/src/os/bsd/vm/os_bsd.cpp b/hotspot/src/os/bsd/vm/os_bsd.cpp index 70eef822955..a21d2c92a0b 100644 --- a/hotspot/src/os/bsd/vm/os_bsd.cpp +++ b/hotspot/src/os/bsd/vm/os_bsd.cpp @@ -2831,8 +2831,12 @@ static int SR_initialize() { // Get signal number to use for suspend/resume if ((s = ::getenv("_JAVA_SR_SIGNUM")) != 0) { int sig = ::strtol(s, 0, 10); - if (sig > 0 || sig < NSIG) { + if (sig > MAX2(SIGSEGV, SIGBUS) && // See 4355769. + sig < NSIG) { // Must be legal signal and fit into sigflags[]. SR_signum = sig; + } else { + warning("You set _JAVA_SR_SIGNUM=%d. It must be in range [%d, %d]. Using %d instead.", + sig, MAX2(SIGSEGV, SIGBUS)+1, NSIG-1, SR_signum); } } @@ -2985,8 +2989,11 @@ void signalHandler(int sig, siginfo_t* info, void* uc) { bool os::Bsd::signal_handlers_are_installed = false; // For signal-chaining -struct sigaction os::Bsd::sigact[MAXSIGNUM]; -unsigned int os::Bsd::sigs = 0; +struct sigaction sigact[NSIG]; +uint32_t sigs = 0; +#if (32 < NSIG-1) +#error "Not all signals can be encoded in sigs. Adapt its type!" +#endif bool os::Bsd::libjsig_is_loaded = false; typedef struct sigaction *(*get_signal_t)(int); get_signal_t os::Bsd::get_signal_action = NULL; @@ -3064,29 +3071,31 @@ bool os::Bsd::chained_handler(int sig, siginfo_t* siginfo, void* context) { } struct sigaction* os::Bsd::get_preinstalled_handler(int sig) { - if ((((unsigned int)1 << sig) & sigs) != 0) { + if ((((uint32_t)1 << (sig-1)) & sigs) != 0) { return &sigact[sig]; } return NULL; } void os::Bsd::save_preinstalled_handler(int sig, struct sigaction& oldAct) { - assert(sig > 0 && sig < MAXSIGNUM, "vm signal out of expected range"); + assert(sig > 0 && sig < NSIG, "vm signal out of expected range"); sigact[sig] = oldAct; - sigs |= (unsigned int)1 << sig; + sigs |= (uint32_t)1 << (sig-1); } // for diagnostic -int os::Bsd::sigflags[MAXSIGNUM]; +int sigflags[NSIG]; int os::Bsd::get_our_sigflags(int sig) { - assert(sig > 0 && sig < MAXSIGNUM, "vm signal out of expected range"); + assert(sig > 0 && sig < NSIG, "vm signal out of expected range"); return sigflags[sig]; } void os::Bsd::set_our_sigflags(int sig, int flags) { - assert(sig > 0 && sig < MAXSIGNUM, "vm signal out of expected range"); - sigflags[sig] = flags; + assert(sig > 0 && sig < NSIG, "vm signal out of expected range"); + if (sig > 0 && sig < NSIG) { + sigflags[sig] = flags; + } } void os::Bsd::set_signal_handler(int sig, bool set_installed) { @@ -3137,7 +3146,7 @@ void os::Bsd::set_signal_handler(int sig, bool set_installed) { #endif // Save flags, which are set by ours - assert(sig > 0 && sig < MAXSIGNUM, "vm signal out of expected range"); + assert(sig > 0 && sig < NSIG, "vm signal out of expected range"); sigflags[sig] = sigAct.sa_flags; int ret = sigaction(sig, &sigAct, &oldAct); diff --git a/hotspot/src/os/bsd/vm/os_bsd.hpp b/hotspot/src/os/bsd/vm/os_bsd.hpp index 8b48cb78cf0..4c63d532043 100644 --- a/hotspot/src/os/bsd/vm/os_bsd.hpp +++ b/hotspot/src/os/bsd/vm/os_bsd.hpp @@ -40,10 +40,6 @@ class Bsd { friend class os; // For signal-chaining -#define MAXSIGNUM 32 - static struct sigaction sigact[MAXSIGNUM]; // saved preinstalled sigactions - static unsigned int sigs; // mask of signals that have - // preinstalled signal handlers static bool libjsig_is_loaded; // libjsig that interposes sigaction(), // __sigaction(), signal() is loaded static struct sigaction *(*get_signal_action)(int); @@ -52,9 +48,6 @@ class Bsd { static void check_signal_handler(int sig); - // For signal flags diagnostics - static int sigflags[MAXSIGNUM]; - #ifdef __APPLE__ // mach_absolute_time static mach_timebase_info_data_t _timebase_info; diff --git a/hotspot/src/os/linux/vm/jsig.c b/hotspot/src/os/linux/vm/jsig.c index ae2f25b33c4..f4221355ca0 100644 --- a/hotspot/src/os/linux/vm/jsig.c +++ b/hotspot/src/os/linux/vm/jsig.c @@ -35,16 +35,19 @@ #include #include #include +#include #define bool int #define true 1 #define false 0 -#define MAXSIGNUM 32 -#define MASK(sig) ((unsigned int)1 << sig) - -static struct sigaction sact[MAXSIGNUM]; /* saved signal handlers */ -static unsigned int jvmsigs = 0; /* signals used by jvm */ +#define MASK(sig) ((uint64_t)1 << (sig-1)) // 0 is not a signal. +// Check whether all signals fit into jvmsigs. -1 as MASK shifts by -1. +#if (64 < NSIG-1) +#error "Not all signals can be encoded in jvmsigs. Adapt its type!" +#endif +static struct sigaction sact[NSIG]; /* saved signal handlers */ +static uint64_t jvmsigs = 0; /* signals used by jvm */ /* used to synchronize the installation of signal handlers */ static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; @@ -107,7 +110,7 @@ static sa_handler_t set_signal(int sig, sa_handler_t disp, bool is_sigset) { signal_lock(); - sigused = (sig < MAXSIGNUM) && ((MASK(sig) & jvmsigs) != 0); + sigused = (sig < NSIG) && ((MASK(sig) & jvmsigs) != 0); if (jvm_signal_installed && sigused) { /* jvm has installed its signal handler for this signal. */ /* Save the handler. Don't really install it. */ @@ -116,7 +119,7 @@ static sa_handler_t set_signal(int sig, sa_handler_t disp, bool is_sigset) { signal_unlock(); return oldhandler; - } else if (sig < MAXSIGNUM && jvm_signal_installing) { + } else if (sig < NSIG && jvm_signal_installing) { /* jvm is installing its signal handlers. Install the new * handlers and save the old ones. jvm uses sigaction(). * Leave the piece here just in case. */ @@ -165,7 +168,7 @@ int sigaction(int sig, const struct sigaction *act, struct sigaction *oact) { signal_lock(); - sigused = (sig < MAXSIGNUM) && ((MASK(sig) & jvmsigs) != 0); + sigused = (sig < NSIG) && ((MASK(sig) & jvmsigs) != 0); if (jvm_signal_installed && sigused) { /* jvm has installed its signal handler for this signal. */ /* Save the handler. Don't really install it. */ @@ -178,7 +181,7 @@ int sigaction(int sig, const struct sigaction *act, struct sigaction *oact) { signal_unlock(); return 0; - } else if (sig < MAXSIGNUM && jvm_signal_installing) { + } else if (sig < NSIG && jvm_signal_installing) { /* jvm is installing its signal handlers. Install the new * handlers and save the old ones. */ res = call_os_sigaction(sig, act, &oldAct); diff --git a/hotspot/src/os/linux/vm/os_linux.cpp b/hotspot/src/os/linux/vm/os_linux.cpp index 8c5486f5d19..b81aa765dee 100644 --- a/hotspot/src/os/linux/vm/os_linux.cpp +++ b/hotspot/src/os/linux/vm/os_linux.cpp @@ -3989,15 +3989,19 @@ static void SR_handler(int sig, siginfo_t* siginfo, ucontext_t* context) { errno = old_errno; } - static int SR_initialize() { struct sigaction act; char *s; + // Get signal number to use for suspend/resume if ((s = ::getenv("_JAVA_SR_SIGNUM")) != 0) { int sig = ::strtol(s, 0, 10); - if (sig > 0 || sig < _NSIG) { + if (sig > MAX2(SIGSEGV, SIGBUS) && // See 4355769. + sig < NSIG) { // Must be legal signal and fit into sigflags[]. SR_signum = sig; + } else { + warning("You set _JAVA_SR_SIGNUM=%d. It must be in range [%d, %d]. Using %d instead.", + sig, MAX2(SIGSEGV, SIGBUS)+1, NSIG-1, SR_signum); } } @@ -4151,8 +4155,11 @@ void signalHandler(int sig, siginfo_t* info, void* uc) { bool os::Linux::signal_handlers_are_installed = false; // For signal-chaining -struct sigaction os::Linux::sigact[MAXSIGNUM]; -unsigned int os::Linux::sigs = 0; +struct sigaction sigact[NSIG]; +uint64_t sigs = 0; +#if (64 < NSIG-1) +#error "Not all signals can be encoded in sigs. Adapt its type!" +#endif bool os::Linux::libjsig_is_loaded = false; typedef struct sigaction *(*get_signal_t)(int); get_signal_t os::Linux::get_signal_action = NULL; @@ -4230,29 +4237,29 @@ bool os::Linux::chained_handler(int sig, siginfo_t* siginfo, void* context) { } struct sigaction* os::Linux::get_preinstalled_handler(int sig) { - if ((((unsigned int)1 << sig) & sigs) != 0) { + if ((((uint64_t)1 << (sig-1)) & sigs) != 0) { return &sigact[sig]; } return NULL; } void os::Linux::save_preinstalled_handler(int sig, struct sigaction& oldAct) { - assert(sig > 0 && sig < MAXSIGNUM, "vm signal out of expected range"); + assert(sig > 0 && sig < NSIG, "vm signal out of expected range"); sigact[sig] = oldAct; - sigs |= (unsigned int)1 << sig; + sigs |= (uint64_t)1 << (sig-1); } // for diagnostic -int os::Linux::sigflags[MAXSIGNUM]; +int sigflags[NSIG]; int os::Linux::get_our_sigflags(int sig) { - assert(sig > 0 && sig < MAXSIGNUM, "vm signal out of expected range"); + assert(sig > 0 && sig < NSIG, "vm signal out of expected range"); return sigflags[sig]; } void os::Linux::set_our_sigflags(int sig, int flags) { - assert(sig > 0 && sig < MAXSIGNUM, "vm signal out of expected range"); - if (sig > 0 && sig < MAXSIGNUM) { + assert(sig > 0 && sig < NSIG, "vm signal out of expected range"); + if (sig > 0 && sig < NSIG) { sigflags[sig] = flags; } } @@ -4292,7 +4299,7 @@ void os::Linux::set_signal_handler(int sig, bool set_installed) { sigAct.sa_flags = SA_SIGINFO|SA_RESTART; } // Save flags, which are set by ours - assert(sig > 0 && sig < MAXSIGNUM, "vm signal out of expected range"); + assert(sig > 0 && sig < NSIG, "vm signal out of expected range"); sigflags[sig] = sigAct.sa_flags; int ret = sigaction(sig, &sigAct, &oldAct); diff --git a/hotspot/src/os/linux/vm/os_linux.hpp b/hotspot/src/os/linux/vm/os_linux.hpp index b8104e75ebc..cbb649179fb 100644 --- a/hotspot/src/os/linux/vm/os_linux.hpp +++ b/hotspot/src/os/linux/vm/os_linux.hpp @@ -34,11 +34,6 @@ class Linux { friend class os; friend class TestReserveMemorySpecial; - // For signal-chaining -#define MAXSIGNUM 32 - static struct sigaction sigact[MAXSIGNUM]; // saved preinstalled sigactions - static unsigned int sigs; // mask of signals that have - // preinstalled signal handlers static bool libjsig_is_loaded; // libjsig that interposes sigaction(), // __sigaction(), signal() is loaded static struct sigaction *(*get_signal_action)(int); @@ -47,9 +42,6 @@ class Linux { static void check_signal_handler(int sig); - // For signal flags diagnostics - static int sigflags[MAXSIGNUM]; - static int (*_clock_gettime)(clockid_t, struct timespec *); static int (*_pthread_getcpuclockid)(pthread_t, clockid_t *); static int (*_pthread_setname_np)(pthread_t, const char*); diff --git a/hotspot/src/os/solaris/vm/os_solaris.hpp b/hotspot/src/os/solaris/vm/os_solaris.hpp index 0f9b86d9ca8..9f5a450fb9a 100644 --- a/hotspot/src/os/solaris/vm/os_solaris.hpp +++ b/hotspot/src/os/solaris/vm/os_solaris.hpp @@ -113,9 +113,6 @@ class Solaris { static void try_enable_extended_io(); - // For signal-chaining - static unsigned long sigs; // mask of signals that have - // preinstalled signal handlers static struct sigaction *(*get_signal_action)(int); static struct sigaction *get_preinstalled_handler(int); static int (*get_libjsig_version)(); From 6c10034f4bfb70e995db4c16b4e2c5391238ea74 Mon Sep 17 00:00:00 2001 From: Sangheon Kim Date: Thu, 12 Nov 2015 09:52:04 -0800 Subject: [PATCH 03/20] 8134631: G1DummyRegionsPerGC fires assert of assert(words <= filler_array_max_size()) failed: too big for a single object Change filler max value temporarily for G1DummyRegionsPerGC flag. Reviewed-by: tbenson, tschatzl --- hotspot/src/share/vm/gc/g1/g1CollectedHeap.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/hotspot/src/share/vm/gc/g1/g1CollectedHeap.cpp b/hotspot/src/share/vm/gc/g1/g1CollectedHeap.cpp index 5b779becfee..14846eaa4a6 100644 --- a/hotspot/src/share/vm/gc/g1/g1CollectedHeap.cpp +++ b/hotspot/src/share/vm/gc/g1/g1CollectedHeap.cpp @@ -2278,6 +2278,10 @@ void G1CollectedHeap::allocate_dummy_regions() { // And as a result the region we'll allocate will be humongous. guarantee(is_humongous(word_size), "sanity"); + // _filler_array_max_size is set to humongous object threshold + // but temporarily change it to use CollectedHeap::fill_with_object(). + SizeTFlagSetting fs(_filler_array_max_size, word_size); + for (uintx i = 0; i < G1DummyRegionsPerGC; ++i) { // Let's use the existing mechanism for the allocation HeapWord* dummy_obj = humongous_obj_allocate(word_size, From 2a5e95250feda669c876e8fe8d0d1caab86616c0 Mon Sep 17 00:00:00 2001 From: Lana Steuck Date: Thu, 12 Nov 2015 10:39:00 -0800 Subject: [PATCH 04/20] Added tag jdk9-b92 for changeset bb921f8f8007 --- hotspot/.hgtags | 1 + 1 file changed, 1 insertion(+) diff --git a/hotspot/.hgtags b/hotspot/.hgtags index 430d279731b..1a17516ef3d 100644 --- a/hotspot/.hgtags +++ b/hotspot/.hgtags @@ -494,3 +494,4 @@ bc48b669bc6610fac97e16593050c0f559cf6945 jdk9-b88 20dff0211deda8d5877fda0e80b6d165ab93c6c2 jdk9-b89 7fe46dc64bb3a8df554b24cde0153ffb24f39c5e jdk9-b90 3fd5c2ca4c20c183628b6dbeb8df821a961419e3 jdk9-b91 +53cb98d68a1aeb08d29c89d6da748de60c448e37 jdk9-b92 From 4d9dfbeb1d43e3a5951064eda9aec926a846001a Mon Sep 17 00:00:00 2001 From: Thomas Schatzl Date: Fri, 13 Nov 2015 09:12:06 +0100 Subject: [PATCH 05/20] 8138684: G1 decision about taking regions into the collection set is too aggressive Factor in expected waste and uncertainty of our guess in the decision whether to take another region into the collection set. Reviewed-by: mgerdin, jmasa --- hotspot/src/share/vm/gc/g1/g1CollectorPolicy.cpp | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/hotspot/src/share/vm/gc/g1/g1CollectorPolicy.cpp b/hotspot/src/share/vm/gc/g1/g1CollectorPolicy.cpp index ee558818f83..2a5ec5e9366 100644 --- a/hotspot/src/share/vm/gc/g1/g1CollectorPolicy.cpp +++ b/hotspot/src/share/vm/gc/g1/g1CollectorPolicy.cpp @@ -467,8 +467,19 @@ bool G1CollectorPolicy::predict_will_fit(uint young_length, } size_t free_bytes = (base_free_regions - young_length) * HeapRegion::GrainBytes; - if ((2.0 /* magic */ * _predictor.sigma()) * bytes_to_copy > free_bytes) { - // end condition 3: out-of-space (conservatively!) + + // When copying, we will likely need more bytes free than is live in the region. + // Add some safety margin to factor in the confidence of our guess, and the + // natural expected waste. + // (100.0 / G1ConfidencePercent) is a scale factor that expresses the uncertainty + // of the calculation: the lower the confidence, the more headroom. + // (100 + TargetPLABWastePct) represents the increase in expected bytes during + // copying due to anticipated waste in the PLABs. + double safety_factor = (100.0 / G1ConfidencePercent) * (100 + TargetPLABWastePct) / 100.0; + size_t expected_bytes_to_copy = safety_factor * bytes_to_copy; + + if (expected_bytes_to_copy > free_bytes) { + // end condition 3: out-of-space return false; } From 6983acfb5f19b4873ec144ad9a38a27c2b0bb402 Mon Sep 17 00:00:00 2001 From: Stefan Johansson Date: Fri, 13 Nov 2015 09:28:53 +0100 Subject: [PATCH 06/20] 8139424: SIGSEGV, Problematic frame: # V [libjvm.so+0xd0c0cc] void InstanceKlass::oop_oop_iterate_oop_maps_specialized The crash was caused by a faulty eager humongous reclaim. The reason for reclaiming a live object was that the call to cleanupHRRS was done after dirtying cards and clearing the remembered sets for the humongous object. This could lead to one or many cards being missed. Reviewed-by: tbenson, kbarrett, tschatzl --- .../src/share/vm/gc/g1/g1CollectedHeap.cpp | 10 ++ hotspot/src/share/vm/gc/g1/g1RemSet.cpp | 1 - .../TestNoEagerReclaimOfHumongousRegions.java | 91 +++++++++++++++++++ 3 files changed, 101 insertions(+), 1 deletion(-) create mode 100644 hotspot/test/gc/g1/TestNoEagerReclaimOfHumongousRegions.java diff --git a/hotspot/src/share/vm/gc/g1/g1CollectedHeap.cpp b/hotspot/src/share/vm/gc/g1/g1CollectedHeap.cpp index 5b779becfee..153c11a8a56 100644 --- a/hotspot/src/share/vm/gc/g1/g1CollectedHeap.cpp +++ b/hotspot/src/share/vm/gc/g1/g1CollectedHeap.cpp @@ -3561,6 +3561,9 @@ class RegisterHumongousWithInCSetFastTestClosure : public HeapRegionClosure { } } } + assert(hrrs.n_yielded() == r->rem_set()->occupied(), + "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."); @@ -3848,6 +3851,13 @@ G1CollectedHeap::do_collection_pause_at_safepoint(double target_pause_time_ms) { evacuation_info.set_collectionset_regions(g1_policy()->cset_region_length()); + // 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_cset(); assert(check_cset_fast_test(), "Inconsistency in the InCSetState table."); diff --git a/hotspot/src/share/vm/gc/g1/g1RemSet.cpp b/hotspot/src/share/vm/gc/g1/g1RemSet.cpp index 87605532e51..8ea400204c4 100644 --- a/hotspot/src/share/vm/gc/g1/g1RemSet.cpp +++ b/hotspot/src/share/vm/gc/g1/g1RemSet.cpp @@ -307,7 +307,6 @@ size_t G1RemSet::oops_into_collection_set_do(G1ParPushHeapRSClosure* oc, } 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 --git a/hotspot/test/gc/g1/TestNoEagerReclaimOfHumongousRegions.java b/hotspot/test/gc/g1/TestNoEagerReclaimOfHumongousRegions.java new file mode 100644 index 00000000000..7d505d5ae5c --- /dev/null +++ b/hotspot/test/gc/g1/TestNoEagerReclaimOfHumongousRegions.java @@ -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 /test/lib + * @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(); + } +} From 396cd88e2f9ad2302b0ef20e87fe72d2e0c1fe8e Mon Sep 17 00:00:00 2001 From: Marcus Larsson Date: Fri, 13 Nov 2015 09:49:28 +0100 Subject: [PATCH 07/20] 8142482: Improve the support for prefix functions in unified logging Reviewed-by: brutisso, pliden --- hotspot/src/share/vm/logging/logPrefix.hpp | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/hotspot/src/share/vm/logging/logPrefix.hpp b/hotspot/src/share/vm/logging/logPrefix.hpp index 2bdd290c7e0..443f20a0a4d 100644 --- a/hotspot/src/share/vm/logging/logPrefix.hpp +++ b/hotspot/src/share/vm/logging/logPrefix.hpp @@ -27,12 +27,17 @@ #include "gc/shared/gcId.hpp" #include "logging/logTag.hpp" -// Prefixes prepend each log message for a specified tagset with the given prefix. -// A prefix consists of a format string and a value or callback. Prefixes are added -// after the decorations but before the log message. +// Prefixes prepend each log message for a specified tagset with a given prefix. +// These prefixes are written before the log message but after the log decorations. +// +// A prefix is defined as a function that takes a buffer (with some size) as argument. +// This function will be called for each log message, and should write the prefix +// to the given buffer. The function should return how many characters it wrote, +// which should never exceed the given size. // // List of prefixes for specific tags and/or tagsets. -// Syntax: LOG_PREFIX(, , LOG_TAGS()) +// Syntax: LOG_PREFIX(, LOG_TAGS()) +// Where the prefixer function matches the following signature: size_t (*)(char*, size_t) #define LOG_PREFIX_LIST // Currently unused/empty // The empty prefix, used when there's no prefix defined. @@ -44,12 +49,12 @@ struct LogPrefix : public AllStatic { } }; -#define LOG_PREFIX(fmt, fn, ...) \ +#define LOG_PREFIX(fn, ...) \ template <> struct LogPrefix<__VA_ARGS__> { \ static size_t prefix(char* buf, size_t len) { \ - int ret = jio_snprintf(buf, len, fmt, fn); \ - assert(ret >= 0, \ - "Failed to prefix log message using prefix ('%s', '%s'), log buffer too small?", fmt, #fn); \ + DEBUG_ONLY(buf[0] = '\0';) \ + size_t ret = fn(buf, len); \ + assert(ret == strlen(buf), "Length mismatch ret (" SIZE_FORMAT ") != buf length (" SIZE_FORMAT ")", ret, strlen(buf)); \ return ret; \ } \ }; From 57ee6fa3abb6ce2159ac1c85438aa503969e493d Mon Sep 17 00:00:00 2001 From: Coleen Phillimore Date: Fri, 13 Nov 2015 16:50:39 -0500 Subject: [PATCH 08/20] 8027429: Add diagnostic command VM.info to get hs_err print-out Refactored hs_err reporting code so that it can be used for VM.info safely Co-authored-by: David Buck Reviewed-by: dholmes, hseigel --- .../share/vm/services/diagnosticCommand.cpp | 5 + .../share/vm/services/diagnosticCommand.hpp | 17 ++ hotspot/src/share/vm/utilities/vmError.cpp | 198 +++++++++++++++--- hotspot/src/share/vm/utilities/vmError.hpp | 6 +- 4 files changed, 196 insertions(+), 30 deletions(-) diff --git a/hotspot/src/share/vm/services/diagnosticCommand.cpp b/hotspot/src/share/vm/services/diagnosticCommand.cpp index 1d9ddf4de4e..d3ae517d795 100644 --- a/hotspot/src/share/vm/services/diagnosticCommand.cpp +++ b/hotspot/src/share/vm/services/diagnosticCommand.cpp @@ -56,6 +56,7 @@ void DCmdRegistrant::register_dcmds(){ DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl(full_export, true, false)); DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl(full_export, true, false)); DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl(full_export, true, false)); + DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl(full_export, true, false)); DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl(full_export, true, false)); DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl(full_export, true, false)); DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl(full_export, true, false)); @@ -323,6 +324,10 @@ int VMUptimeDCmd::num_arguments() { } } +void VMInfoDCmd::execute(DCmdSource source, TRAPS) { + VMError::print_vm_info(_output); +} + void SystemGCDCmd::execute(DCmdSource source, TRAPS) { if (!DisableExplicitGC) { Universe::heap()->collect(GCCause::_dcmd_gc_run); diff --git a/hotspot/src/share/vm/services/diagnosticCommand.hpp b/hotspot/src/share/vm/services/diagnosticCommand.hpp index d71bff40bd4..3b0505a7347 100644 --- a/hotspot/src/share/vm/services/diagnosticCommand.hpp +++ b/hotspot/src/share/vm/services/diagnosticCommand.hpp @@ -213,6 +213,23 @@ public: virtual void execute(DCmdSource source, TRAPS); }; +class VMInfoDCmd : public DCmd { +public: + VMInfoDCmd(outputStream* output, bool heap) : DCmd(output, heap) { } + static const char* name() { return "VM.info"; } + static const char* description() { + return "Print information about JVM environment and status."; + } + static const char* impact() { return "Low"; } + static const JavaPermission permission() { + JavaPermission p = {"java.lang.management.ManagementPermission", + "monitor", NULL}; + return p; + } + static int num_arguments() { return 0; } + virtual void execute(DCmdSource source, TRAPS); +}; + class SystemGCDCmd : public DCmd { public: SystemGCDCmd(outputStream* output, bool heap) : DCmd(output, heap) { } diff --git a/hotspot/src/share/vm/utilities/vmError.cpp b/hotspot/src/share/vm/utilities/vmError.cpp index 45cc47152f8..6af19370b7c 100644 --- a/hotspot/src/share/vm/utilities/vmError.cpp +++ b/hotspot/src/share/vm/utilities/vmError.cpp @@ -201,7 +201,7 @@ void VMError::print_stack_trace(outputStream* st, JavaThread* jt, #endif // ZERO } -void VMError::print_oom_reasons(outputStream* st) { +static void print_oom_reasons(outputStream* st) { st->print_cr("# Possible reasons:"); st->print_cr("# The system is out of physical RAM or swap space"); st->print_cr("# In 32 bit mode, the process size limit was hit"); @@ -217,7 +217,7 @@ void VMError::print_oom_reasons(outputStream* st) { st->print_cr("# This output file may be truncated or incomplete."); } -const char* VMError::gc_mode() { +static const char* gc_mode() { if (UseG1GC) return "g1 gc"; if (UseParallelGC) return "parallel gc"; if (UseConcMarkSweepGC) return "concurrent mark sweep gc"; @@ -225,6 +225,33 @@ const char* VMError::gc_mode() { return "ERROR in GC mode"; } +static void report_vm_version(outputStream* st, char* buf, int buflen) { + // VM version + st->print_cr("#"); + JDK_Version::current().to_string(buf, buflen); + const char* runtime_name = JDK_Version::runtime_name() != NULL ? + JDK_Version::runtime_name() : ""; + const char* runtime_version = JDK_Version::runtime_version() != NULL ? + JDK_Version::runtime_version() : ""; + st->print_cr("# JRE version: %s (%s) (build %s)", runtime_name, buf, runtime_version); + // This is the long version with some default settings added + st->print_cr("# Java VM: %s (%s, %s%s%s%s%s, %s, %s)", + Abstract_VM_Version::vm_name(), + Abstract_VM_Version::vm_release(), + Abstract_VM_Version::vm_info_string(), + TieredCompilation ? ", tiered" : "", +#if INCLUDE_JVMCI + EnableJVMCI ? ", jvmci" : "", + UseJVMCICompiler ? ", jvmci compiler" : "", +#else + "", "", +#endif + UseCompressedOops ? ", compressed oops" : "", + gc_mode(), + Abstract_VM_Version::vm_platform_string() + ); +} + // This is the main function to report a fatal error. Only one thread can // call this function, so we don't need to worry about MT-safety. But it's // possible that the error handler itself may crash or die on an internal @@ -401,30 +428,7 @@ void VMError::report(outputStream* st, bool _verbose) { STEP(90, "(printing Java version string)") - // VM version - st->print_cr("#"); - JDK_Version::current().to_string(buf, sizeof(buf)); - const char* runtime_name = JDK_Version::runtime_name() != NULL ? - JDK_Version::runtime_name() : ""; - const char* runtime_version = JDK_Version::runtime_version() != NULL ? - JDK_Version::runtime_version() : ""; - st->print_cr("# JRE version: %s (%s) (build %s)", runtime_name, buf, runtime_version); - // This is the long version with some default settings added - st->print_cr("# Java VM: %s (%s, %s%s%s%s%s, %s, %s)", - Abstract_VM_Version::vm_name(), - Abstract_VM_Version::vm_release(), - Abstract_VM_Version::vm_info_string(), - TieredCompilation ? ", tiered" : "", -#if INCLUDE_JVMCI - EnableJVMCI ? ", jvmci" : "", - UseJVMCICompiler ? ", jvmci compiler" : "", -#else - "", "", -#endif - UseCompressedOops ? ", compressed oops" : "", - gc_mode(), - Abstract_VM_Version::vm_platform_string() - ); + report_vm_version(st, buf, sizeof(buf)); STEP(100, "(printing problematic frame)") @@ -715,7 +719,6 @@ void VMError::report(outputStream* st, bool _verbose) { if (_verbose && Universe::is_fully_initialized()) { Universe::heap()->print_on_error(st); st->cr(); - st->print_cr("Polling page: " INTPTR_FORMAT, p2i(os::get_polling_page())); st->cr(); } @@ -826,6 +829,147 @@ void VMError::report(outputStream* st, bool _verbose) { # undef END } +// Report for the vm_info_cmd. This prints out the information above omitting +// crash and thread specific information. If output is added above, it should be added +// here also, if it is safe to call during a running process. +void VMError::print_vm_info(outputStream* st) { + + char buf[O_BUFLEN]; + report_vm_version(st, buf, sizeof(buf)); + + // STEP("(printing summary)") + + st->cr(); + st->print_cr("--------------- S U M M A R Y ------------"); + st->cr(); + + // STEP("(printing VM option summary)") + + // VM options + Arguments::print_summary_on(st); + st->cr(); + + // STEP("(printing summary machine and OS info)") + + os::print_summary_info(st, buf, sizeof(buf)); + + // STEP("(printing date and time)") + + os::print_date_and_time(st, buf, sizeof(buf)); + + // Skip: STEP("(printing thread)") + + // STEP("(printing process)") + + st->cr(); + st->print_cr("--------------- P R O C E S S ---------------"); + st->cr(); + + // STEP("(printing number of OutOfMemoryError and StackOverflow exceptions)") + + if (Exceptions::has_exception_counts()) { + st->print_cr("OutOfMemory and StackOverflow Exception counts:"); + Exceptions::print_exception_counts_on_error(st); + st->cr(); + } + + // STEP("(printing compressed oops mode") + + if (UseCompressedOops) { + Universe::print_compressed_oops_mode(st); + if (UseCompressedClassPointers) { + Metaspace::print_compressed_class_space(st); + } + st->cr(); + } + + // STEP("(printing heap information)") + + if (Universe::is_fully_initialized()) { + Universe::heap()->print_on_error(st); + st->cr(); + st->print_cr("Polling page: " INTPTR_FORMAT, p2i(os::get_polling_page())); + st->cr(); + } + + // STEP("(printing code cache information)") + + if (Universe::is_fully_initialized()) { + // print code cache information before vm abort + CodeCache::print_summary(st); + st->cr(); + } + + // STEP("(printing ring buffers)") + + Events::print_all(st); + st->cr(); + + // STEP("(printing dynamic libraries)") + + // dynamic libraries, or memory map + os::print_dll_info(st); + st->cr(); + + // STEP("(printing VM options)") + + // VM options + Arguments::print_on(st); + st->cr(); + + // STEP("(printing warning if internal testing API used)") + + if (WhiteBox::used()) { + st->print_cr("Unsupported internal testing APIs have been used."); + st->cr(); + } + + // STEP("(printing all environment variables)") + + os::print_environment_variables(st, env_list); + st->cr(); + + // STEP("(printing signal handlers)") + + os::print_signal_handlers(st, buf, sizeof(buf)); + st->cr(); + + // STEP("(Native Memory Tracking)") + + MemTracker::error_report(st); + + // STEP("(printing system)") + + st->cr(); + st->print_cr("--------------- S Y S T E M ---------------"); + st->cr(); + + // STEP("(printing OS information)") + + os::print_os_info(st); + st->cr(); + + // STEP("(printing CPU info)") + + os::print_cpu_info(st, buf, sizeof(buf)); + st->cr(); + + // STEP("(printing memory info)") + + os::print_memory_info(st); + st->cr(); + + // STEP("(printing internal vm info)") + + st->print_cr("vm_info: %s", Abstract_VM_Version::internal_vm_info_string()); + st->cr(); + + // print a defined marker to show that error handling finished correctly. + // STEP("(printing end marker)") + + st->print_cr("END."); +} + volatile intptr_t VMError::first_error_tid = -1; // An error could happen before tty is initialized or after it has been diff --git a/hotspot/src/share/vm/utilities/vmError.hpp b/hotspot/src/share/vm/utilities/vmError.hpp index aa1d89ecea6..e7cce398fd3 100644 --- a/hotspot/src/share/vm/utilities/vmError.hpp +++ b/hotspot/src/share/vm/utilities/vmError.hpp @@ -88,9 +88,6 @@ class VMError : public AllStatic { static void print_stack_trace(outputStream* st, JavaThread* jt, char* buf, int buflen, bool verbose = false); - static const char* gc_mode(); - static void print_oom_reasons(outputStream* st); - static bool should_report_bug(unsigned int id) { return (id != OOM_MALLOC_ERROR) && (id != OOM_MMAP_ERROR); } @@ -110,6 +107,9 @@ public: // Record status of core/minidump static void record_coredump_status(const char* message, bool status); + // support for VM.info diagnostic command + static void print_vm_info(outputStream* st); + // main error reporting function static void report_and_die(int id, const char* message, const char* detail_fmt, va_list detail_args, Thread* thread, address pc, void* siginfo, void* context, From 7badb3edfb46e0cac71acc8a063adaf9244db931 Mon Sep 17 00:00:00 2001 From: Kim Barrett Date: Mon, 16 Nov 2015 14:11:36 -0500 Subject: [PATCH 09/20] 8143013: Remove unused DirtyCardQueue::iterate_closure_all_threads Remove unused function. Reviewed-by: tbenson, tschatzl, mgerdin --- hotspot/src/share/vm/gc/g1/dirtyCardQueue.cpp | 14 -------------- hotspot/src/share/vm/gc/g1/dirtyCardQueue.hpp | 8 -------- 2 files changed, 22 deletions(-) diff --git a/hotspot/src/share/vm/gc/g1/dirtyCardQueue.cpp b/hotspot/src/share/vm/gc/g1/dirtyCardQueue.cpp index 15947fddf76..7eb460394a3 100644 --- a/hotspot/src/share/vm/gc/g1/dirtyCardQueue.cpp +++ b/hotspot/src/share/vm/gc/g1/dirtyCardQueue.cpp @@ -119,20 +119,6 @@ void DirtyCardQueueSet::handle_zero_index_for_thread(JavaThread* t) { t->dirty_card_queue().handle_zero_index(); } -void DirtyCardQueueSet::iterate_closure_all_threads(CardTableEntryClosure* cl, - bool consume, - uint worker_i) { - assert(SafepointSynchronize::is_at_safepoint(), "Must be at safepoint."); - for (JavaThread* t = Threads::first(); t; t = t->next()) { - bool b = t->dirty_card_queue().apply_closure(cl, consume); - guarantee(b, "Should not be interrupted."); - } - bool b = shared_dirty_card_queue()->apply_closure(cl, - consume, - worker_i); - guarantee(b, "Should not be interrupted."); -} - bool DirtyCardQueueSet::mut_process_buffer(void** buf) { // Used to determine if we had already claimed a par_id diff --git a/hotspot/src/share/vm/gc/g1/dirtyCardQueue.hpp b/hotspot/src/share/vm/gc/g1/dirtyCardQueue.hpp index 86fc438b71e..965c83b1d67 100644 --- a/hotspot/src/share/vm/gc/g1/dirtyCardQueue.hpp +++ b/hotspot/src/share/vm/gc/g1/dirtyCardQueue.hpp @@ -112,14 +112,6 @@ public: static void handle_zero_index_for_thread(JavaThread* t); - // Apply the given closure to all entries in all currently-active buffers. - // This should only be applied at a safepoint. (Currently must not be called - // in parallel; this should change in the future.) If "consume" is true, - // processed entries are discarded. - void iterate_closure_all_threads(CardTableEntryClosure* cl, - bool consume = true, - uint worker_i = 0); - // If there exists some completed buffer, pop it, then apply the // specified closure to all its elements, nulling out those elements // processed. If all elements are processed, returns "true". If no From 56745a7f9f97b8aec7182b7c84cadb464f5cd4c3 Mon Sep 17 00:00:00 2001 From: David Holmes Date: Mon, 16 Nov 2015 14:47:21 -0500 Subject: [PATCH 10/20] 8141024: [Solaris] Obsolete UseAltSigs Reviewed-by: dcubed, ddmitriev --- hotspot/src/os/solaris/vm/jvm_solaris.h | 4 ---- hotspot/src/os/solaris/vm/os_solaris.cpp | 19 +++++++------------ hotspot/src/share/vm/runtime/arguments.cpp | 11 ++++------- hotspot/src/share/vm/runtime/globals.hpp | 4 ---- 4 files changed, 11 insertions(+), 27 deletions(-) diff --git a/hotspot/src/os/solaris/vm/jvm_solaris.h b/hotspot/src/os/solaris/vm/jvm_solaris.h index 5e4c41e7680..e961d36035b 100644 --- a/hotspot/src/os/solaris/vm/jvm_solaris.h +++ b/hotspot/src/os/solaris/vm/jvm_solaris.h @@ -91,10 +91,6 @@ #define SHUTDOWN1_SIGNAL SIGHUP /* Shutdown Hooks support. */ #define SHUTDOWN2_SIGNAL SIGINT #define SHUTDOWN3_SIGNAL SIGTERM -/* alternative signals used with -XX:+UseAltSigs (or for backward - compatibility with 1.2, -Xusealtsigs) flag. Chosen to be - unlikely to conflict with applications embedding the vm */ -#define ALT_ASYNC_SIGNAL (SIGRTMIN + SIGRTMAX)/2 /* alternate async signal */ /* With 1.4.1 libjsig added versioning: used in os_solaris.cpp and jsig.c */ #define JSIG_VERSION_1_4_1 0x30140100 diff --git a/hotspot/src/os/solaris/vm/os_solaris.cpp b/hotspot/src/os/solaris/vm/os_solaris.cpp index 36ee014bed3..de90c5ca4f8 100644 --- a/hotspot/src/os/solaris/vm/os_solaris.cpp +++ b/hotspot/src/os/solaris/vm/os_solaris.cpp @@ -997,9 +997,8 @@ bool os::create_thread(Thread* thread, ThreadType thr_type, } // defined for >= Solaris 10. This allows builds on earlier versions -// of Solaris to take advantage of the newly reserved Solaris JVM signals -// With SIGJVM1, SIGJVM2, ASYNC_SIGNAL is SIGJVM2 and -XX:+UseAltSigs does -// nothing since these should have no conflict. Previously INTERRUPT_SIGNAL +// of Solaris to take advantage of the newly reserved Solaris JVM signals. +// With SIGJVM1, SIGJVM2, ASYNC_SIGNAL is SIGJVM2. Previously INTERRUPT_SIGNAL // was SIGJVM1. // #if !defined(SIGJVM1) @@ -1053,13 +1052,9 @@ void os::Solaris::signal_sets_init() { sigaddset(&unblocked_sigs, SIGBUS); sigaddset(&unblocked_sigs, SIGFPE); - if (isJVM1available) { - os::Solaris::set_SIGasync(SIGJVM2); - } else if (UseAltSigs) { - os::Solaris::set_SIGasync(ALT_ASYNC_SIGNAL); - } else { - os::Solaris::set_SIGasync(ASYNC_SIGNAL); - } + // Always true on Solaris 10+ + guarantee(isJVM1available(), "SIGJVM1/2 missing!"); + os::Solaris::set_SIGasync(SIGJVM2); sigaddset(&unblocked_sigs, os::Solaris::SIGasync()); @@ -3922,7 +3917,7 @@ void os::Solaris::set_signal_handler(int sig, bool set_installed, // save the old handler in jvm save_preinstalled_handler(sig, oldAct); } else { - vm_exit_during_initialization("Signal chaining not allowed for VM interrupt signal, try -XX:+UseAltSigs."); + vm_exit_during_initialization("Signal chaining not allowed for VM interrupt signal."); } // libjsig also interposes the sigaction() call below and saves the // old sigaction on it own. @@ -3991,7 +3986,7 @@ void os::run_periodic_checks() { DO_SIGNAL_CHECK(BREAK_SIGNAL); } - // See comments above for using JVM1/JVM2 and UseAltSigs + // See comments above for using JVM1/JVM2 DO_SIGNAL_CHECK(os::Solaris::SIGasync()); } diff --git a/hotspot/src/share/vm/runtime/arguments.cpp b/hotspot/src/share/vm/runtime/arguments.cpp index 0efd30b08f8..ca98eb8e7f0 100644 --- a/hotspot/src/share/vm/runtime/arguments.cpp +++ b/hotspot/src/share/vm/runtime/arguments.cpp @@ -366,6 +366,7 @@ static SpecialFlag const special_jvm_flags[] = { { "StarvationMonitorInterval", JDK_Version::undefined(), JDK_Version::jdk(9), JDK_Version::jdk(10) }, { "PreInflateSpin", JDK_Version::undefined(), JDK_Version::jdk(9), JDK_Version::jdk(10) }, { "JNIDetachReleasesMonitors", JDK_Version::undefined(), JDK_Version::jdk(9), JDK_Version::jdk(10) }, + { "UseAltSigs", JDK_Version::undefined(), JDK_Version::jdk(9), JDK_Version::jdk(10) }, #ifdef TEST_VERIFY_SPECIAL_JVM_FLAGS { "dep > obs", JDK_Version::jdk(9), JDK_Version::jdk(8), JDK_Version::undefined() }, @@ -2949,11 +2950,12 @@ jint Arguments::parse_each_vm_init_arg(const JavaVMInitArgs* args, round_to((int)long_ThreadStackSize, K) / K) != Flag::SUCCESS) { return JNI_EINVAL; } - // -Xoss, -Xsqnopause, -Xoptimize, -Xboundthreads + // -Xoss, -Xsqnopause, -Xoptimize, -Xboundthreads, -Xusealtsigs } else if (match_option(option, "-Xoss", &tail) || match_option(option, "-Xsqnopause") || match_option(option, "-Xoptimize") || - match_option(option, "-Xboundthreads")) { + match_option(option, "-Xboundthreads") || + match_option(option, "-Xusealtsigs")) { // All these options are deprecated in JDK 9 and will be removed in a future release char version[256]; JDK_Version::jdk(9).to_string(version, sizeof(version)); @@ -3036,11 +3038,6 @@ jint Arguments::parse_each_vm_init_arg(const JavaVMInitArgs* args, if (FLAG_SET_CMDLINE(bool, ReduceSignalUsage, true) != Flag::SUCCESS) { return JNI_EINVAL; } - } else if (match_option(option, "-Xusealtsigs")) { - // change default internal VM signals used - lower case for back compat - if (FLAG_SET_CMDLINE(bool, UseAltSigs, true) != Flag::SUCCESS) { - return JNI_EINVAL; - } // -Xprof } else if (match_option(option, "-Xprof")) { #if INCLUDE_FPROF diff --git a/hotspot/src/share/vm/runtime/globals.hpp b/hotspot/src/share/vm/runtime/globals.hpp index 49153c0c62d..fb61f555307 100644 --- a/hotspot/src/share/vm/runtime/globals.hpp +++ b/hotspot/src/share/vm/runtime/globals.hpp @@ -1334,10 +1334,6 @@ public: "Use signal-chaining to invoke signal handlers installed " \ "by the application (Solaris & Linux only)") \ \ - product(bool, UseAltSigs, false, \ - "Use alternate signals instead of SIGUSR1 & SIGUSR2 for VM " \ - "internal signals (Solaris only)") \ - \ product(bool, AllowJNIEnvProxy, false, \ "Allow JNIEnv proxies for jdbx") \ \ From 3904de571b293dca3ce291def23190b95105b97f Mon Sep 17 00:00:00 2001 From: David Holmes Date: Mon, 16 Nov 2015 18:50:55 -0500 Subject: [PATCH 11/20] 8139300: Internal Error (vm/utilities/debug.cpp:399), # Error: ShouldNotReachHere() Reviewed-by: simonis, dcubed --- hotspot/src/share/vm/utilities/debug.cpp | 4 +++- hotspot/test/runtime/ErrorHandling/SecondaryErrorTest.java | 1 - 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/hotspot/src/share/vm/utilities/debug.cpp b/hotspot/src/share/vm/utilities/debug.cpp index fa1c625d334..241aa6f139e 100644 --- a/hotspot/src/share/vm/utilities/debug.cpp +++ b/hotspot/src/share/vm/utilities/debug.cpp @@ -331,7 +331,9 @@ static void crash_with_sigfpe() { volatile int x = 0; volatile int y = 1/x; #ifndef _WIN32 - raise(SIGFPE); + // OSX implements raise(sig) incorrectly so we need to + // explicitly target the current thread + pthread_kill(pthread_self(), SIGFPE); #endif } // end: crash_with_sigfpe diff --git a/hotspot/test/runtime/ErrorHandling/SecondaryErrorTest.java b/hotspot/test/runtime/ErrorHandling/SecondaryErrorTest.java index 9c60d2d0c89..37fac08130c 100644 --- a/hotspot/test/runtime/ErrorHandling/SecondaryErrorTest.java +++ b/hotspot/test/runtime/ErrorHandling/SecondaryErrorTest.java @@ -28,7 +28,6 @@ * @summary Synchronous signals during error reporting may terminate or hang VM process * @library /testlibrary * @author Thomas Stuefe (SAP) - * @requires os.family != "mac" * @modules java.base/sun.misc * java.management */ From 56adbd02ec40ed5109b857383b6b6f0f453e5c08 Mon Sep 17 00:00:00 2001 From: Stefan Johansson Date: Tue, 17 Nov 2015 11:20:27 +0100 Subject: [PATCH 12/20] 8141280: G1ResManAllocator doesn't work with _survivor_is_full/_old_is_full Reviewed-by: jmasa, kbarrett, tschatzl --- hotspot/src/share/vm/gc/g1/g1Allocator.cpp | 42 +++++++++++----------- hotspot/src/share/vm/gc/g1/g1Allocator.hpp | 24 ++++++++----- 2 files changed, 35 insertions(+), 31 deletions(-) diff --git a/hotspot/src/share/vm/gc/g1/g1Allocator.cpp b/hotspot/src/share/vm/gc/g1/g1Allocator.cpp index 9a63b618d8b..8bd8b376c72 100644 --- a/hotspot/src/share/vm/gc/g1/g1Allocator.cpp +++ b/hotspot/src/share/vm/gc/g1/g1Allocator.cpp @@ -33,6 +33,8 @@ G1DefaultAllocator::G1DefaultAllocator(G1CollectedHeap* heap) : G1Allocator(heap), + _survivor_is_full(false), + _old_is_full(false), _retained_old_gc_alloc_region(NULL), _survivor_gc_alloc_region(heap->alloc_buffer_stats(InCSetState::Young)), _old_gc_alloc_region(heap->alloc_buffer_stats(InCSetState::Old)) { @@ -87,7 +89,8 @@ void G1Allocator::reuse_retained_old_region(EvacuationInfo& evacuation_info, void G1DefaultAllocator::init_gc_alloc_regions(EvacuationInfo& evacuation_info) { assert_at_safepoint(true /* should_be_vm_thread */); - G1Allocator::init_gc_alloc_regions(evacuation_info); + _survivor_is_full = false; + _old_is_full = false; _survivor_gc_alloc_region.init(); _old_gc_alloc_region.init(); @@ -118,6 +121,22 @@ void G1DefaultAllocator::abandon_gc_alloc_regions() { _retained_old_gc_alloc_region = NULL; } +bool G1DefaultAllocator::survivor_is_full(AllocationContext_t context) const { + return _survivor_is_full; +} + +bool G1DefaultAllocator::old_is_full(AllocationContext_t context) const { + return _old_is_full; +} + +void G1DefaultAllocator::set_survivor_full(AllocationContext_t context) { + _survivor_is_full = true; +} + +void G1DefaultAllocator::set_old_full(AllocationContext_t context) { + _old_is_full = true; +} + G1PLAB::G1PLAB(size_t gclab_word_size) : PLAB(gclab_word_size), _retired(true) { } @@ -165,22 +184,6 @@ HeapWord* G1Allocator::par_allocate_during_gc(InCSetState dest, } } -bool G1Allocator::survivor_is_full(AllocationContext_t context) const { - return _survivor_is_full; -} - -bool G1Allocator::old_is_full(AllocationContext_t context) const { - return _old_is_full; -} - -void G1Allocator::set_survivor_full(AllocationContext_t context) { - _survivor_is_full = true; -} - -void G1Allocator::set_old_full(AllocationContext_t context) { - _old_is_full = true; -} - HeapWord* G1Allocator::survivor_attempt_allocation(size_t min_word_size, size_t desired_word_size, size_t* actual_word_size, @@ -232,11 +235,6 @@ HeapWord* G1Allocator::old_attempt_allocation(size_t min_word_size, return result; } -void G1Allocator::init_gc_alloc_regions(EvacuationInfo& evacuation_info) { - _survivor_is_full = false; - _old_is_full = false; -} - G1PLABAllocator::G1PLABAllocator(G1Allocator* allocator) : _g1h(G1CollectedHeap::heap()), _allocator(allocator), diff --git a/hotspot/src/share/vm/gc/g1/g1Allocator.hpp b/hotspot/src/share/vm/gc/g1/g1Allocator.hpp index f58b248bd4e..e2db5c8dd0c 100644 --- a/hotspot/src/share/vm/gc/g1/g1Allocator.hpp +++ b/hotspot/src/share/vm/gc/g1/g1Allocator.hpp @@ -38,19 +38,16 @@ class EvacuationInfo; // Also keeps track of retained regions across GCs. class G1Allocator : public CHeapObj { friend class VMStructs; -private: - bool _survivor_is_full; - bool _old_is_full; protected: G1CollectedHeap* _g1h; virtual MutatorAllocRegion* mutator_alloc_region(AllocationContext_t context) = 0; - virtual bool survivor_is_full(AllocationContext_t context) const; - virtual bool old_is_full(AllocationContext_t context) const; + virtual bool survivor_is_full(AllocationContext_t context) const = 0; + virtual bool old_is_full(AllocationContext_t context) const = 0; - virtual void set_survivor_full(AllocationContext_t context); - virtual void set_old_full(AllocationContext_t context); + virtual void set_survivor_full(AllocationContext_t context) = 0; + virtual void set_old_full(AllocationContext_t context) = 0; // Accessors to the allocation regions. virtual SurvivorGCAllocRegion* survivor_gc_alloc_region(AllocationContext_t context) = 0; @@ -67,7 +64,7 @@ protected: size_t* actual_word_size, AllocationContext_t context); public: - G1Allocator(G1CollectedHeap* heap) : _g1h(heap), _survivor_is_full(false), _old_is_full(false) { } + G1Allocator(G1CollectedHeap* heap) : _g1h(heap) { } virtual ~G1Allocator() { } static G1Allocator* create_allocator(G1CollectedHeap* g1h); @@ -79,7 +76,7 @@ public: virtual void init_mutator_alloc_region() = 0; virtual void release_mutator_alloc_region() = 0; - virtual void init_gc_alloc_regions(EvacuationInfo& evacuation_info); + virtual void init_gc_alloc_regions(EvacuationInfo& evacuation_info) = 0; virtual void release_gc_alloc_regions(EvacuationInfo& evacuation_info) = 0; virtual void abandon_gc_alloc_regions() = 0; @@ -119,6 +116,9 @@ public: // and old generation allocation region. // Can retain the (single) old generation allocation region across GCs. class G1DefaultAllocator : public G1Allocator { +private: + bool _survivor_is_full; + bool _old_is_full; protected: // Alloc region used to satisfy mutator allocation requests. MutatorAllocRegion _mutator_alloc_region; @@ -135,6 +135,12 @@ protected: public: G1DefaultAllocator(G1CollectedHeap* heap); + virtual bool survivor_is_full(AllocationContext_t context) const; + virtual bool old_is_full(AllocationContext_t context) const ; + + virtual void set_survivor_full(AllocationContext_t context); + virtual void set_old_full(AllocationContext_t context); + virtual void init_mutator_alloc_region(); virtual void release_mutator_alloc_region(); From e8c5bc2024e510cb1746498c322ce9267967a5e6 Mon Sep 17 00:00:00 2001 From: Kim Barrett Date: Tue, 17 Nov 2015 16:40:52 -0500 Subject: [PATCH 13/20] 8143014: Access PtrQueue member offsets through derived classes Moved accessors to derived classes and updated callers. Reviewed-by: tschatzl, jmasa, twisti --- .../cpu/aarch64/vm/c1_Runtime1_aarch64.cpp | 10 +++--- .../cpu/aarch64/vm/macroAssembler_aarch64.cpp | 14 ++++----- hotspot/src/cpu/ppc/vm/macroAssembler_ppc.cpp | 20 ++++++------ hotspot/src/cpu/ppc/vm/stubGenerator_ppc.cpp | 8 ++--- .../src/cpu/sparc/vm/c1_Runtime1_sparc.cpp | 12 +++---- .../src/cpu/sparc/vm/macroAssembler_sparc.cpp | 24 +++++++------- hotspot/src/cpu/x86/vm/c1_Runtime1_x86.cpp | 8 ++--- hotspot/src/cpu/x86/vm/macroAssembler_x86.cpp | 14 ++++----- .../jdk/vm/ci/hotspot/HotSpotVMConfig.java | 19 +++++++----- hotspot/src/share/vm/c1/c1_LIRGenerator.cpp | 6 ++-- hotspot/src/share/vm/gc/g1/dirtyCardQueue.hpp | 12 +++++++ hotspot/src/share/vm/gc/g1/ptrQueue.hpp | 14 +++++++-- hotspot/src/share/vm/gc/g1/satbMarkQueue.hpp | 17 ++++++++++ hotspot/src/share/vm/gc/g1/vmStructs_g1.hpp | 31 ++++++++++++++++++- hotspot/src/share/vm/opto/compile.cpp | 2 +- hotspot/src/share/vm/opto/escape.cpp | 4 +-- hotspot/src/share/vm/opto/graphKit.cpp | 16 +++++----- hotspot/src/share/vm/opto/macro.cpp | 2 +- hotspot/src/share/vm/runtime/vmStructs.cpp | 12 +++---- 19 files changed, 157 insertions(+), 88 deletions(-) diff --git a/hotspot/src/cpu/aarch64/vm/c1_Runtime1_aarch64.cpp b/hotspot/src/cpu/aarch64/vm/c1_Runtime1_aarch64.cpp index a68da825e62..77498c35972 100644 --- a/hotspot/src/cpu/aarch64/vm/c1_Runtime1_aarch64.cpp +++ b/hotspot/src/cpu/aarch64/vm/c1_Runtime1_aarch64.cpp @@ -1169,12 +1169,12 @@ OopMapSet* Runtime1::generate_code_for(StubID id, StubAssembler* sasm) { const Register tmp = rscratch1; Address in_progress(thread, in_bytes(JavaThread::satb_mark_queue_offset() + - PtrQueue::byte_offset_of_active())); + SATBMarkQueue::byte_offset_of_active())); Address queue_index(thread, in_bytes(JavaThread::satb_mark_queue_offset() + - PtrQueue::byte_offset_of_index())); + SATBMarkQueue::byte_offset_of_index())); Address buffer(thread, in_bytes(JavaThread::satb_mark_queue_offset() + - PtrQueue::byte_offset_of_buf())); + SATBMarkQueue::byte_offset_of_buf())); Label done; Label runtime; @@ -1219,9 +1219,9 @@ OopMapSet* Runtime1::generate_code_for(StubID id, StubAssembler* sasm) { const Register thread = rthread; Address queue_index(thread, in_bytes(JavaThread::dirty_card_queue_offset() + - PtrQueue::byte_offset_of_index())); + DirtyCardQueue::byte_offset_of_index())); Address buffer(thread, in_bytes(JavaThread::dirty_card_queue_offset() + - PtrQueue::byte_offset_of_buf())); + DirtyCardQueue::byte_offset_of_buf())); const Register card_addr = rscratch2; ExternalAddress cardtable((address) ct->byte_map_base); diff --git a/hotspot/src/cpu/aarch64/vm/macroAssembler_aarch64.cpp b/hotspot/src/cpu/aarch64/vm/macroAssembler_aarch64.cpp index a827da7a5be..8a59f261512 100644 --- a/hotspot/src/cpu/aarch64/vm/macroAssembler_aarch64.cpp +++ b/hotspot/src/cpu/aarch64/vm/macroAssembler_aarch64.cpp @@ -3487,18 +3487,18 @@ void MacroAssembler::g1_write_barrier_pre(Register obj, assert_different_registers(obj, pre_val, tmp); Address in_progress(thread, in_bytes(JavaThread::satb_mark_queue_offset() + - PtrQueue::byte_offset_of_active())); + SATBMarkQueue::byte_offset_of_active())); Address index(thread, in_bytes(JavaThread::satb_mark_queue_offset() + - PtrQueue::byte_offset_of_index())); + SATBMarkQueue::byte_offset_of_index())); Address buffer(thread, in_bytes(JavaThread::satb_mark_queue_offset() + - PtrQueue::byte_offset_of_buf())); + SATBMarkQueue::byte_offset_of_buf())); // Is marking active? - if (in_bytes(PtrQueue::byte_width_of_active()) == 4) { + if (in_bytes(SATBMarkQueue::byte_width_of_active()) == 4) { ldrw(tmp, in_progress); } else { - assert(in_bytes(PtrQueue::byte_width_of_active()) == 1, "Assumption"); + assert(in_bytes(SATBMarkQueue::byte_width_of_active()) == 1, "Assumption"); ldrb(tmp, in_progress); } cbzw(tmp, done); @@ -3566,9 +3566,9 @@ void MacroAssembler::g1_write_barrier_post(Register store_addr, assert(thread == rthread, "must be"); Address queue_index(thread, in_bytes(JavaThread::dirty_card_queue_offset() + - PtrQueue::byte_offset_of_index())); + DirtyCardQueue::byte_offset_of_index())); Address buffer(thread, in_bytes(JavaThread::dirty_card_queue_offset() + - PtrQueue::byte_offset_of_buf())); + DirtyCardQueue::byte_offset_of_buf())); BarrierSet* bs = Universe::heap()->barrier_set(); CardTableModRefBS* ct = (CardTableModRefBS*)bs; diff --git a/hotspot/src/cpu/ppc/vm/macroAssembler_ppc.cpp b/hotspot/src/cpu/ppc/vm/macroAssembler_ppc.cpp index 3310f37f57a..38cf28d094a 100644 --- a/hotspot/src/cpu/ppc/vm/macroAssembler_ppc.cpp +++ b/hotspot/src/cpu/ppc/vm/macroAssembler_ppc.cpp @@ -2633,11 +2633,11 @@ void MacroAssembler::g1_write_barrier_pre(Register Robj, RegisterOrConstant offs Label runtime, filtered; // Is marking active? - if (in_bytes(PtrQueue::byte_width_of_active()) == 4) { - lwz(Rtmp1, in_bytes(JavaThread::satb_mark_queue_offset() + PtrQueue::byte_offset_of_active()), R16_thread); + if (in_bytes(SATBMarkQueue::byte_width_of_active()) == 4) { + lwz(Rtmp1, in_bytes(JavaThread::satb_mark_queue_offset() + SATBMarkQueue::byte_offset_of_active()), R16_thread); } else { - guarantee(in_bytes(PtrQueue::byte_width_of_active()) == 1, "Assumption"); - lbz(Rtmp1, in_bytes(JavaThread::satb_mark_queue_offset() + PtrQueue::byte_offset_of_active()), R16_thread); + guarantee(in_bytes(SATBMarkQueue::byte_width_of_active()) == 1, "Assumption"); + lbz(Rtmp1, in_bytes(JavaThread::satb_mark_queue_offset() + SATBMarkQueue::byte_offset_of_active()), R16_thread); } cmpdi(CCR0, Rtmp1, 0); beq(CCR0, filtered); @@ -2672,13 +2672,13 @@ void MacroAssembler::g1_write_barrier_pre(Register Robj, RegisterOrConstant offs // (The index field is typed as size_t.) const Register Rbuffer = Rtmp1, Rindex = Rtmp2; - ld(Rindex, in_bytes(JavaThread::satb_mark_queue_offset() + PtrQueue::byte_offset_of_index()), R16_thread); + ld(Rindex, in_bytes(JavaThread::satb_mark_queue_offset() + SATBMarkQueue::byte_offset_of_index()), R16_thread); cmpdi(CCR0, Rindex, 0); beq(CCR0, runtime); // If index == 0, goto runtime. - ld(Rbuffer, in_bytes(JavaThread::satb_mark_queue_offset() + PtrQueue::byte_offset_of_buf()), R16_thread); + ld(Rbuffer, in_bytes(JavaThread::satb_mark_queue_offset() + SATBMarkQueue::byte_offset_of_buf()), R16_thread); addi(Rindex, Rindex, -wordSize); // Decrement index. - std(Rindex, in_bytes(JavaThread::satb_mark_queue_offset() + PtrQueue::byte_offset_of_index()), R16_thread); + std(Rindex, in_bytes(JavaThread::satb_mark_queue_offset() + SATBMarkQueue::byte_offset_of_index()), R16_thread); // Record the previous value. stdx(Rpre_val, Rbuffer, Rindex); @@ -2757,13 +2757,13 @@ void MacroAssembler::g1_write_barrier_post(Register Rstore_addr, Register Rnew_v const Register Rqueue_index = Rtmp2, Rqueue_buf = Rtmp3; - ld(Rqueue_index, in_bytes(JavaThread::dirty_card_queue_offset() + PtrQueue::byte_offset_of_index()), R16_thread); + ld(Rqueue_index, in_bytes(JavaThread::dirty_card_queue_offset() + DirtyCardQueue::byte_offset_of_index()), R16_thread); cmpdi(CCR0, Rqueue_index, 0); beq(CCR0, runtime); // index == 0 then jump to runtime - ld(Rqueue_buf, in_bytes(JavaThread::dirty_card_queue_offset() + PtrQueue::byte_offset_of_buf()), R16_thread); + ld(Rqueue_buf, in_bytes(JavaThread::dirty_card_queue_offset() + DirtyCardQueue::byte_offset_of_buf()), R16_thread); addi(Rqueue_index, Rqueue_index, -wordSize); // decrement index - std(Rqueue_index, in_bytes(JavaThread::dirty_card_queue_offset() + PtrQueue::byte_offset_of_index()), R16_thread); + std(Rqueue_index, in_bytes(JavaThread::dirty_card_queue_offset() + DirtyCardQueue::byte_offset_of_index()), R16_thread); stdx(Rcard_addr, Rqueue_buf, Rqueue_index); // store card b(filtered); diff --git a/hotspot/src/cpu/ppc/vm/stubGenerator_ppc.cpp b/hotspot/src/cpu/ppc/vm/stubGenerator_ppc.cpp index 1f0d252229d..1dbb5c04f29 100644 --- a/hotspot/src/cpu/ppc/vm/stubGenerator_ppc.cpp +++ b/hotspot/src/cpu/ppc/vm/stubGenerator_ppc.cpp @@ -630,11 +630,11 @@ class StubGenerator: public StubCodeGenerator { Label filtered; // Is marking active? - if (in_bytes(PtrQueue::byte_width_of_active()) == 4) { - __ lwz(Rtmp1, in_bytes(JavaThread::satb_mark_queue_offset() + PtrQueue::byte_offset_of_active()), R16_thread); + if (in_bytes(SATBMarkQueue::byte_width_of_active()) == 4) { + __ lwz(Rtmp1, in_bytes(JavaThread::satb_mark_queue_offset() + SATBMarkQueue::byte_offset_of_active()), R16_thread); } else { - guarantee(in_bytes(PtrQueue::byte_width_of_active()) == 1, "Assumption"); - __ lbz(Rtmp1, in_bytes(JavaThread::satb_mark_queue_offset() + PtrQueue::byte_offset_of_active()), R16_thread); + guarantee(in_bytes(SATBMarkQueue::byte_width_of_active()) == 1, "Assumption"); + __ lbz(Rtmp1, in_bytes(JavaThread::satb_mark_queue_offset() + SATBMarkQueue::byte_offset_of_active()), R16_thread); } __ cmpdi(CCR0, Rtmp1, 0); __ beq(CCR0, filtered); diff --git a/hotspot/src/cpu/sparc/vm/c1_Runtime1_sparc.cpp b/hotspot/src/cpu/sparc/vm/c1_Runtime1_sparc.cpp index 766b00a6bd8..45bfab26f45 100644 --- a/hotspot/src/cpu/sparc/vm/c1_Runtime1_sparc.cpp +++ b/hotspot/src/cpu/sparc/vm/c1_Runtime1_sparc.cpp @@ -857,13 +857,13 @@ OopMapSet* Runtime1::generate_code_for(StubID id, StubAssembler* sasm) { bool with_frame = false; // I don't know if we can do with-frame. int satb_q_index_byte_offset = in_bytes(JavaThread::satb_mark_queue_offset() + - PtrQueue::byte_offset_of_index()); + SATBMarkQueue::byte_offset_of_index()); int satb_q_buf_byte_offset = in_bytes(JavaThread::satb_mark_queue_offset() + - PtrQueue::byte_offset_of_buf()); + SATBMarkQueue::byte_offset_of_buf()); __ bind(restart); - // Load the index into the SATB buffer. PtrQueue::_index is a + // Load the index into the SATB buffer. SATBMarkQueue::_index is a // size_t so ld_ptr is appropriate __ ld_ptr(G2_thread, satb_q_index_byte_offset, tmp); @@ -961,14 +961,14 @@ OopMapSet* Runtime1::generate_code_for(StubID id, StubAssembler* sasm) { int dirty_card_q_index_byte_offset = in_bytes(JavaThread::dirty_card_queue_offset() + - PtrQueue::byte_offset_of_index()); + DirtyCardQueue::byte_offset_of_index()); int dirty_card_q_buf_byte_offset = in_bytes(JavaThread::dirty_card_queue_offset() + - PtrQueue::byte_offset_of_buf()); + DirtyCardQueue::byte_offset_of_buf()); __ bind(restart); - // Get the index into the update buffer. PtrQueue::_index is + // Get the index into the update buffer. DirtyCardQueue::_index is // a size_t so ld_ptr is appropriate here. __ ld_ptr(G2_thread, dirty_card_q_index_byte_offset, tmp3); diff --git a/hotspot/src/cpu/sparc/vm/macroAssembler_sparc.cpp b/hotspot/src/cpu/sparc/vm/macroAssembler_sparc.cpp index a6d5cd68e47..9f5d807b390 100644 --- a/hotspot/src/cpu/sparc/vm/macroAssembler_sparc.cpp +++ b/hotspot/src/cpu/sparc/vm/macroAssembler_sparc.cpp @@ -3632,19 +3632,19 @@ static void generate_satb_log_enqueue(bool with_frame) { int satb_q_index_byte_offset = in_bytes(JavaThread::satb_mark_queue_offset() + - PtrQueue::byte_offset_of_index()); + SATBMarkQueue::byte_offset_of_index()); int satb_q_buf_byte_offset = in_bytes(JavaThread::satb_mark_queue_offset() + - PtrQueue::byte_offset_of_buf()); + SATBMarkQueue::byte_offset_of_buf()); - assert(in_bytes(PtrQueue::byte_width_of_index()) == sizeof(intptr_t) && - in_bytes(PtrQueue::byte_width_of_buf()) == sizeof(intptr_t), + assert(in_bytes(SATBMarkQueue::byte_width_of_index()) == sizeof(intptr_t) && + in_bytes(SATBMarkQueue::byte_width_of_buf()) == sizeof(intptr_t), "check sizes in assembly below"); __ bind(restart); - // Load the index into the SATB buffer. PtrQueue::_index is a size_t + // Load the index into the SATB buffer. SATBMarkQueue::_index is a size_t // so ld_ptr is appropriate. __ ld_ptr(G2_thread, satb_q_index_byte_offset, L0); @@ -3736,17 +3736,17 @@ void MacroAssembler::g1_write_barrier_pre(Register obj, } // Is marking active? - if (in_bytes(PtrQueue::byte_width_of_active()) == 4) { + if (in_bytes(SATBMarkQueue::byte_width_of_active()) == 4) { ld(G2, in_bytes(JavaThread::satb_mark_queue_offset() + - PtrQueue::byte_offset_of_active()), + SATBMarkQueue::byte_offset_of_active()), tmp); } else { - guarantee(in_bytes(PtrQueue::byte_width_of_active()) == 1, + guarantee(in_bytes(SATBMarkQueue::byte_width_of_active()) == 1, "Assumption"); ldsb(G2, in_bytes(JavaThread::satb_mark_queue_offset() + - PtrQueue::byte_offset_of_active()), + SATBMarkQueue::byte_offset_of_active()), tmp); } @@ -3847,13 +3847,13 @@ static void generate_dirty_card_log_enqueue(jbyte* byte_map_base) { int dirty_card_q_index_byte_offset = in_bytes(JavaThread::dirty_card_queue_offset() + - PtrQueue::byte_offset_of_index()); + DirtyCardQueue::byte_offset_of_index()); int dirty_card_q_buf_byte_offset = in_bytes(JavaThread::dirty_card_queue_offset() + - PtrQueue::byte_offset_of_buf()); + DirtyCardQueue::byte_offset_of_buf()); __ bind(restart); - // Load the index into the update buffer. PtrQueue::_index is + // Load the index into the update buffer. DirtyCardQueue::_index is // a size_t so ld_ptr is appropriate here. __ ld_ptr(G2_thread, dirty_card_q_index_byte_offset, L0); diff --git a/hotspot/src/cpu/x86/vm/c1_Runtime1_x86.cpp b/hotspot/src/cpu/x86/vm/c1_Runtime1_x86.cpp index 02c0bed270d..c977465cfc5 100644 --- a/hotspot/src/cpu/x86/vm/c1_Runtime1_x86.cpp +++ b/hotspot/src/cpu/x86/vm/c1_Runtime1_x86.cpp @@ -1622,9 +1622,9 @@ OopMapSet* Runtime1::generate_code_for(StubID id, StubAssembler* sasm) { NOT_LP64(__ get_thread(thread);) Address queue_index(thread, in_bytes(JavaThread::satb_mark_queue_offset() + - PtrQueue::byte_offset_of_index())); + SATBMarkQueue::byte_offset_of_index())); Address buffer(thread, in_bytes(JavaThread::satb_mark_queue_offset() + - PtrQueue::byte_offset_of_buf())); + SATBMarkQueue::byte_offset_of_buf())); Label done; Label runtime; @@ -1698,9 +1698,9 @@ OopMapSet* Runtime1::generate_code_for(StubID id, StubAssembler* sasm) { const Register thread = NOT_LP64(rax) LP64_ONLY(r15_thread); Address queue_index(thread, in_bytes(JavaThread::dirty_card_queue_offset() + - PtrQueue::byte_offset_of_index())); + DirtyCardQueue::byte_offset_of_index())); Address buffer(thread, in_bytes(JavaThread::dirty_card_queue_offset() + - PtrQueue::byte_offset_of_buf())); + DirtyCardQueue::byte_offset_of_buf())); __ push(rax); __ push(rcx); diff --git a/hotspot/src/cpu/x86/vm/macroAssembler_x86.cpp b/hotspot/src/cpu/x86/vm/macroAssembler_x86.cpp index 100ea5962c6..37d117e6b23 100644 --- a/hotspot/src/cpu/x86/vm/macroAssembler_x86.cpp +++ b/hotspot/src/cpu/x86/vm/macroAssembler_x86.cpp @@ -4248,18 +4248,18 @@ void MacroAssembler::g1_write_barrier_pre(Register obj, } Address in_progress(thread, in_bytes(JavaThread::satb_mark_queue_offset() + - PtrQueue::byte_offset_of_active())); + SATBMarkQueue::byte_offset_of_active())); Address index(thread, in_bytes(JavaThread::satb_mark_queue_offset() + - PtrQueue::byte_offset_of_index())); + SATBMarkQueue::byte_offset_of_index())); Address buffer(thread, in_bytes(JavaThread::satb_mark_queue_offset() + - PtrQueue::byte_offset_of_buf())); + SATBMarkQueue::byte_offset_of_buf())); // Is marking active? - if (in_bytes(PtrQueue::byte_width_of_active()) == 4) { + if (in_bytes(SATBMarkQueue::byte_width_of_active()) == 4) { cmpl(in_progress, 0); } else { - assert(in_bytes(PtrQueue::byte_width_of_active()) == 1, "Assumption"); + assert(in_bytes(SATBMarkQueue::byte_width_of_active()) == 1, "Assumption"); cmpb(in_progress, 0); } jcc(Assembler::equal, done); @@ -4346,9 +4346,9 @@ void MacroAssembler::g1_write_barrier_post(Register store_addr, #endif // _LP64 Address queue_index(thread, in_bytes(JavaThread::dirty_card_queue_offset() + - PtrQueue::byte_offset_of_index())); + DirtyCardQueue::byte_offset_of_index())); Address buffer(thread, in_bytes(JavaThread::dirty_card_queue_offset() + - PtrQueue::byte_offset_of_buf())); + DirtyCardQueue::byte_offset_of_buf())); CardTableModRefBS* ct = barrier_set_cast(Universe::heap()->barrier_set()); diff --git a/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotVMConfig.java b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotVMConfig.java index 7b924e25ed9..e6e051131de 100644 --- a/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotVMConfig.java +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotVMConfig.java @@ -1193,9 +1193,12 @@ public class HotSpotVMConfig { @HotSpotVMConstant(name = "frame::interpreter_frame_sender_sp_offset", archs = {"amd64"}) @Stable public int frameInterpreterFrameSenderSpOffset; @HotSpotVMConstant(name = "frame::interpreter_frame_last_sp_offset", archs = {"amd64"}) @Stable public int frameInterpreterFrameLastSpOffset; - @HotSpotVMField(name = "PtrQueue::_active", type = "bool", get = HotSpotVMField.Type.OFFSET) @Stable public int ptrQueueActiveOffset; - @HotSpotVMField(name = "PtrQueue::_buf", type = "void**", get = HotSpotVMField.Type.OFFSET) @Stable public int ptrQueueBufferOffset; - @HotSpotVMField(name = "PtrQueue::_index", type = "size_t", get = HotSpotVMField.Type.OFFSET) @Stable public int ptrQueueIndexOffset; + @HotSpotVMConstant(name = "dirtyCardQueueBufferOffset") @Stable private int dirtyCardQueueBufferOffset; + @HotSpotVMConstant(name = "dirtyCardQueueIndexOffset") @Stable private int dirtyCardQueueIndexOffset; + + @HotSpotVMConstant(name = "satbMarkQueueBufferOffset") @Stable private int satbMarkQueueBufferOffset; + @HotSpotVMConstant(name = "satbMarkQueueIndexOffset") @Stable private int satbMarkQueueIndexOffset; + @HotSpotVMConstant(name = "satbMarkQueueActiveOffset") @Stable private int satbMarkQueueActiveOffset; @HotSpotVMField(name = "OSThread::_interrupted", type = "jint", get = HotSpotVMField.Type.OFFSET) @Stable public int osThreadInterruptedOffset; @@ -1396,23 +1399,23 @@ public class HotSpotVMConfig { // G1 Collector Related Values. public int g1CardQueueIndexOffset() { - return javaThreadDirtyCardQueueOffset + ptrQueueIndexOffset; + return javaThreadDirtyCardQueueOffset + dirtyCardQueueIndexOffset; } public int g1CardQueueBufferOffset() { - return javaThreadDirtyCardQueueOffset + ptrQueueBufferOffset; + return javaThreadDirtyCardQueueOffset + dirtyCardQueueBufferOffset; } public int g1SATBQueueMarkingOffset() { - return javaThreadSatbMarkQueueOffset + ptrQueueActiveOffset; + return javaThreadSatbMarkQueueOffset + satbMarkQueueActiveOffset; } public int g1SATBQueueIndexOffset() { - return javaThreadSatbMarkQueueOffset + ptrQueueIndexOffset; + return javaThreadSatbMarkQueueOffset + satbMarkQueueIndexOffset; } public int g1SATBQueueBufferOffset() { - return javaThreadSatbMarkQueueOffset + ptrQueueBufferOffset; + return javaThreadSatbMarkQueueOffset + satbMarkQueueBufferOffset; } @HotSpotVMField(name = "java_lang_Class::_klass_offset", type = "int", get = HotSpotVMField.Type.VALUE) @Stable public int klassOffset; diff --git a/hotspot/src/share/vm/c1/c1_LIRGenerator.cpp b/hotspot/src/share/vm/c1/c1_LIRGenerator.cpp index a45d221f740..627c48f4a05 100644 --- a/hotspot/src/share/vm/c1/c1_LIRGenerator.cpp +++ b/hotspot/src/share/vm/c1/c1_LIRGenerator.cpp @@ -1464,10 +1464,10 @@ void LIRGenerator::G1SATBCardTableModRef_pre_barrier(LIR_Opr addr_opr, LIR_Opr p bool do_load, bool patch, CodeEmitInfo* info) { // First we test whether marking is in progress. BasicType flag_type; - if (in_bytes(PtrQueue::byte_width_of_active()) == 4) { + if (in_bytes(SATBMarkQueue::byte_width_of_active()) == 4) { flag_type = T_INT; } else { - guarantee(in_bytes(PtrQueue::byte_width_of_active()) == 1, + guarantee(in_bytes(SATBMarkQueue::byte_width_of_active()) == 1, "Assumption"); // Use unsigned type T_BOOLEAN here rather than signed T_BYTE since some platforms, eg. ARM, // need to use unsigned instructions to use the large offset to load the satb_mark_queue. @@ -1477,7 +1477,7 @@ void LIRGenerator::G1SATBCardTableModRef_pre_barrier(LIR_Opr addr_opr, LIR_Opr p LIR_Address* mark_active_flag_addr = new LIR_Address(thrd, in_bytes(JavaThread::satb_mark_queue_offset() + - PtrQueue::byte_offset_of_active()), + SATBMarkQueue::byte_offset_of_active()), flag_type); // Read the marking-in-progress flag. LIR_Opr flag_val = new_register(T_INT); diff --git a/hotspot/src/share/vm/gc/g1/dirtyCardQueue.hpp b/hotspot/src/share/vm/gc/g1/dirtyCardQueue.hpp index 965c83b1d67..f3f9bb18a07 100644 --- a/hotspot/src/share/vm/gc/g1/dirtyCardQueue.hpp +++ b/hotspot/src/share/vm/gc/g1/dirtyCardQueue.hpp @@ -72,6 +72,18 @@ public: void **get_buf() { return _buf;} size_t get_index() { return _index;} void reinitialize() { _buf = 0; _sz = 0; _index = 0;} + + // Compiler support. + static ByteSize byte_offset_of_index() { + return PtrQueue::byte_offset_of_index(); + } + using PtrQueue::byte_width_of_index; + + static ByteSize byte_offset_of_buf() { + return PtrQueue::byte_offset_of_buf(); + } + using PtrQueue::byte_width_of_buf; + }; diff --git a/hotspot/src/share/vm/gc/g1/ptrQueue.hpp b/hotspot/src/share/vm/gc/g1/ptrQueue.hpp index 39f1c931e74..707d591c0c0 100644 --- a/hotspot/src/share/vm/gc/g1/ptrQueue.hpp +++ b/hotspot/src/share/vm/gc/g1/ptrQueue.hpp @@ -140,19 +140,27 @@ public: } // To support compiler. + +protected: + template static ByteSize byte_offset_of_index() { - return byte_offset_of(PtrQueue, _index); + return byte_offset_of(Derived, _index); } + static ByteSize byte_width_of_index() { return in_ByteSize(sizeof(size_t)); } + template static ByteSize byte_offset_of_buf() { - return byte_offset_of(PtrQueue, _buf); + return byte_offset_of(Derived, _buf); } + static ByteSize byte_width_of_buf() { return in_ByteSize(sizeof(void*)); } + template static ByteSize byte_offset_of_active() { - return byte_offset_of(PtrQueue, _active); + return byte_offset_of(Derived, _active); } + static ByteSize byte_width_of_active() { return in_ByteSize(sizeof(bool)); } }; diff --git a/hotspot/src/share/vm/gc/g1/satbMarkQueue.hpp b/hotspot/src/share/vm/gc/g1/satbMarkQueue.hpp index 0ca3b45c2ff..e3591f4f7df 100644 --- a/hotspot/src/share/vm/gc/g1/satbMarkQueue.hpp +++ b/hotspot/src/share/vm/gc/g1/satbMarkQueue.hpp @@ -68,6 +68,23 @@ public: void print(const char* name); static void print(const char* name, void** buf, size_t index, size_t sz); #endif // PRODUCT + + // Compiler support. + static ByteSize byte_offset_of_index() { + return PtrQueue::byte_offset_of_index(); + } + using PtrQueue::byte_width_of_index; + + static ByteSize byte_offset_of_buf() { + return PtrQueue::byte_offset_of_buf(); + } + using PtrQueue::byte_width_of_buf; + + static ByteSize byte_offset_of_active() { + return PtrQueue::byte_offset_of_active(); + } + using PtrQueue::byte_width_of_active; + }; class SATBMarkQueueSet: public PtrQueueSet { diff --git a/hotspot/src/share/vm/gc/g1/vmStructs_g1.hpp b/hotspot/src/share/vm/gc/g1/vmStructs_g1.hpp index 97daf08e66d..1fad2b64637 100644 --- a/hotspot/src/share/vm/gc/g1/vmStructs_g1.hpp +++ b/hotspot/src/share/vm/gc/g1/vmStructs_g1.hpp @@ -28,6 +28,7 @@ #include "gc/g1/g1CollectedHeap.hpp" #include "gc/g1/heapRegion.hpp" #include "gc/g1/heapRegionManager.hpp" +#include "utilities/macros.hpp" #define VM_STRUCTS_G1(nonstatic_field, static_field) \ \ @@ -62,6 +63,34 @@ \ nonstatic_field(HeapRegionSetCount, _length, uint) \ nonstatic_field(HeapRegionSetCount, _capacity, size_t) \ + \ + nonstatic_field(PtrQueue, _active, bool) \ + nonstatic_field(PtrQueue, _buf, void**) \ + nonstatic_field(PtrQueue, _index, size_t) \ + + +#define VM_INT_CONSTANTS_G1(declare_constant, declare_constant_with_value) \ + \ + JVMCI_ONLY( \ + declare_constant_with_value( \ + "dirtyCardQueueBufferOffset", \ + in_bytes(DirtyCardQueue::byte_offset_of_buf())) \ + declare_constant_with_value( \ + "dirtyCardQueueIndexOffset", \ + in_bytes(DirtyCardQueue::byte_offset_of_index())) \ + ) /* JVMCI_ONLY */ \ + \ + JVMCI_ONLY( \ + declare_constant_with_value( \ + "satbMarkQueueBufferOffset", \ + in_bytes(SATBMarkQueue::byte_offset_of_buf())) \ + declare_constant_with_value( \ + "satbMarkQueueIndexOffset", \ + in_bytes(SATBMarkQueue::byte_offset_of_index())) \ + declare_constant_with_value( \ + "satbMarkQueueActiveOffset", \ + in_bytes(SATBMarkQueue::byte_offset_of_active())) \ + ) /* JVMCI_ONLY */ \ #define VM_TYPES_G1(declare_type, declare_toplevel_type) \ @@ -76,10 +105,10 @@ declare_toplevel_type(HeapRegionSetBase) \ declare_toplevel_type(HeapRegionSetCount) \ declare_toplevel_type(G1MonitoringSupport) \ + declare_toplevel_type(PtrQueue) \ \ declare_toplevel_type(G1CollectedHeap*) \ declare_toplevel_type(HeapRegion*) \ declare_toplevel_type(G1MonitoringSupport*) \ - #endif // SHARE_VM_GC_G1_VMSTRUCTS_G1_HPP diff --git a/hotspot/src/share/vm/opto/compile.cpp b/hotspot/src/share/vm/opto/compile.cpp index 032fe0a6f6f..268a54e60e0 100644 --- a/hotspot/src/share/vm/opto/compile.cpp +++ b/hotspot/src/share/vm/opto/compile.cpp @@ -3549,7 +3549,7 @@ void Compile::verify_graph_edges(bool no_dead_code) { void Compile::verify_barriers() { if (UseG1GC) { // Verify G1 pre-barriers - const int marking_offset = in_bytes(JavaThread::satb_mark_queue_offset() + PtrQueue::byte_offset_of_active()); + const int marking_offset = in_bytes(JavaThread::satb_mark_queue_offset() + SATBMarkQueue::byte_offset_of_active()); ResourceArea *area = Thread::current()->resource_area(); Unique_Node_List visited(area); diff --git a/hotspot/src/share/vm/opto/escape.cpp b/hotspot/src/share/vm/opto/escape.cpp index fac8c4d67fe..92ed15ca3da 100644 --- a/hotspot/src/share/vm/opto/escape.cpp +++ b/hotspot/src/share/vm/opto/escape.cpp @@ -539,11 +539,11 @@ void ConnectionGraph::add_node_to_connection_graph(Node *n, Unique_Node_List *de if (tls->Opcode() == Op_ThreadLocal) { int offs = (int)igvn->find_intptr_t_con(adr->in(AddPNode::Offset), Type::OffsetBot); if (offs == in_bytes(JavaThread::satb_mark_queue_offset() + - PtrQueue::byte_offset_of_buf())) { + SATBMarkQueue::byte_offset_of_buf())) { break; // G1 pre barrier previous oop value store. } if (offs == in_bytes(JavaThread::dirty_card_queue_offset() + - PtrQueue::byte_offset_of_buf())) { + DirtyCardQueue::byte_offset_of_buf())) { break; // G1 post barrier card address store. } } diff --git a/hotspot/src/share/vm/opto/graphKit.cpp b/hotspot/src/share/vm/opto/graphKit.cpp index 397e6cb1c81..bcdf343aaf8 100644 --- a/hotspot/src/share/vm/opto/graphKit.cpp +++ b/hotspot/src/share/vm/opto/graphKit.cpp @@ -3986,16 +3986,16 @@ void GraphKit::g1_write_barrier_pre(bool do_load, float likely = PROB_LIKELY(0.999); float unlikely = PROB_UNLIKELY(0.999); - BasicType active_type = in_bytes(PtrQueue::byte_width_of_active()) == 4 ? T_INT : T_BYTE; - assert(in_bytes(PtrQueue::byte_width_of_active()) == 4 || in_bytes(PtrQueue::byte_width_of_active()) == 1, "flag width"); + BasicType active_type = in_bytes(SATBMarkQueue::byte_width_of_active()) == 4 ? T_INT : T_BYTE; + assert(in_bytes(SATBMarkQueue::byte_width_of_active()) == 4 || in_bytes(SATBMarkQueue::byte_width_of_active()) == 1, "flag width"); // Offsets into the thread const int marking_offset = in_bytes(JavaThread::satb_mark_queue_offset() + // 648 - PtrQueue::byte_offset_of_active()); + SATBMarkQueue::byte_offset_of_active()); const int index_offset = in_bytes(JavaThread::satb_mark_queue_offset() + // 656 - PtrQueue::byte_offset_of_index()); + SATBMarkQueue::byte_offset_of_index()); const int buffer_offset = in_bytes(JavaThread::satb_mark_queue_offset() + // 652 - PtrQueue::byte_offset_of_buf()); + SATBMarkQueue::byte_offset_of_buf()); // Now the actual pointers into the thread Node* marking_adr = __ AddP(no_base, tls, __ ConX(marking_offset)); @@ -4008,7 +4008,7 @@ void GraphKit::g1_write_barrier_pre(bool do_load, // if (!marking) __ if_then(marking, BoolTest::ne, zero, unlikely); { BasicType index_bt = TypeX_X->basic_type(); - assert(sizeof(size_t) == type2aelembytes(index_bt), "Loading G1 PtrQueue::_index with wrong size."); + assert(sizeof(size_t) == type2aelembytes(index_bt), "Loading G1 SATBMarkQueue::_index with wrong size."); Node* index = __ load(__ ctrl(), index_adr, TypeX_X, index_bt, Compile::AliasIdxRaw); if (do_load) { @@ -4196,9 +4196,9 @@ void GraphKit::g1_write_barrier_post(Node* oop_store, // Offsets into the thread const int index_offset = in_bytes(JavaThread::dirty_card_queue_offset() + - PtrQueue::byte_offset_of_index()); + DirtyCardQueue::byte_offset_of_index()); const int buffer_offset = in_bytes(JavaThread::dirty_card_queue_offset() + - PtrQueue::byte_offset_of_buf()); + DirtyCardQueue::byte_offset_of_buf()); // Pointers into the thread diff --git a/hotspot/src/share/vm/opto/macro.cpp b/hotspot/src/share/vm/opto/macro.cpp index bd5ceaa9b7a..4551560a6e4 100644 --- a/hotspot/src/share/vm/opto/macro.cpp +++ b/hotspot/src/share/vm/opto/macro.cpp @@ -290,7 +290,7 @@ void PhaseMacroExpand::eliminate_card_mark(Node* p2x) { cmpx->in(1)->is_Load()) { Node* adr = cmpx->in(1)->as_Load()->in(MemNode::Address); const int marking_offset = in_bytes(JavaThread::satb_mark_queue_offset() + - PtrQueue::byte_offset_of_active()); + SATBMarkQueue::byte_offset_of_active()); if (adr->is_AddP() && adr->in(AddPNode::Base) == top() && adr->in(AddPNode::Address)->Opcode() == Op_ThreadLocal && adr->in(AddPNode::Offset) == MakeConX(marking_offset)) { diff --git a/hotspot/src/share/vm/runtime/vmStructs.cpp b/hotspot/src/share/vm/runtime/vmStructs.cpp index 784c8be3eb7..b38fd110b2d 100644 --- a/hotspot/src/share/vm/runtime/vmStructs.cpp +++ b/hotspot/src/share/vm/runtime/vmStructs.cpp @@ -1378,10 +1378,6 @@ typedef CompactHashtable SymbolCompactHashTable; nonstatic_field(vframeArrayElement, _bci, int) \ nonstatic_field(vframeArrayElement, _method, Method*) \ \ - nonstatic_field(PtrQueue, _active, bool) \ - nonstatic_field(PtrQueue, _buf, void**) \ - nonstatic_field(PtrQueue, _index, size_t) \ - \ nonstatic_field(AccessFlags, _flags, jint) \ nonstatic_field(elapsedTimer, _counter, jlong) \ nonstatic_field(elapsedTimer, _active, bool) \ @@ -2273,8 +2269,6 @@ typedef CompactHashtable SymbolCompactHashTable; /* Miscellaneous types */ \ /***************/ \ \ - declare_toplevel_type(PtrQueue) \ - \ /* freelist */ \ declare_toplevel_type(FreeChunk*) \ declare_toplevel_type(AdaptiveFreeList*) \ @@ -3066,6 +3060,9 @@ typedef CompactHashtable SymbolCompactHashTable; #define GENERATE_VM_INT_CONSTANT_ENTRY(name) \ { QUOTE(name), (int32_t) name }, +#define GENERATE_VM_INT_CONSTANT_WITH_VALUE_ENTRY(name, value) \ + { (name), (int32_t)(value) }, + #define GENERATE_PREPROCESSOR_VM_INT_CONSTANT_ENTRY(name, value) \ { name, (int32_t) value }, @@ -3296,6 +3293,9 @@ VMIntConstantEntry VMStructs::localHotSpotVMIntConstants[] = { VM_INT_CONSTANTS_CMS(GENERATE_VM_INT_CONSTANT_ENTRY) VM_INT_CONSTANTS_PARNEW(GENERATE_VM_INT_CONSTANT_ENTRY) + + VM_INT_CONSTANTS_G1(GENERATE_VM_INT_CONSTANT_ENTRY, + GENERATE_VM_INT_CONSTANT_WITH_VALUE_ENTRY) #endif // INCLUDE_ALL_GCS #if INCLUDE_TRACE From 581c251007ffd4a6544e08f45d27671891684c52 Mon Sep 17 00:00:00 2001 From: Yumin Qi Date: Tue, 17 Nov 2015 15:14:29 -0800 Subject: [PATCH 14/20] 8087223: InterfaceMethod CP entry pointing to a class should cause ICCE Check constantTag for class constant data consistency at method resolution Reviewed-by: coleenp, vlivanov --- hotspot/src/share/vm/ci/ciEnv.cpp | 9 +- hotspot/src/share/vm/ci/ciEnv.hpp | 3 +- hotspot/src/share/vm/ci/ciMethod.cpp | 3 +- .../src/share/vm/interpreter/linkResolver.cpp | 21 +- .../src/share/vm/interpreter/linkResolver.hpp | 21 +- .../src/share/vm/jvmci/jvmciCompilerToVM.cpp | 4 +- hotspot/src/share/vm/jvmci/jvmciEnv.cpp | 8 +- hotspot/src/share/vm/jvmci/jvmciEnv.hpp | 3 +- hotspot/src/share/vm/oops/constantPool.cpp | 23 ++ hotspot/src/share/vm/oops/constantPool.hpp | 3 + hotspot/src/share/vm/prims/methodHandles.cpp | 6 +- hotspot/src/share/vm/runtime/javaCalls.cpp | 6 +- hotspot/src/share/vm/runtime/reflection.cpp | 2 +- .../runtime/8087223/BadMethodHandles.java | 250 ++++++++++++++++++ hotspot/test/runtime/8087223/IntfMethod.java | 156 +++++++++++ 15 files changed, 496 insertions(+), 22 deletions(-) create mode 100644 hotspot/test/runtime/8087223/BadMethodHandles.java create mode 100644 hotspot/test/runtime/8087223/IntfMethod.java diff --git a/hotspot/src/share/vm/ci/ciEnv.cpp b/hotspot/src/share/vm/ci/ciEnv.cpp index 9c9d7b300c2..2e096bb303a 100644 --- a/hotspot/src/share/vm/ci/ciEnv.cpp +++ b/hotspot/src/share/vm/ci/ciEnv.cpp @@ -704,13 +704,14 @@ Method* ciEnv::lookup_method(InstanceKlass* accessor, InstanceKlass* holder, Symbol* name, Symbol* sig, - Bytecodes::Code bc) { + Bytecodes::Code bc, + constantTag tag) { EXCEPTION_CONTEXT; KlassHandle h_accessor(THREAD, accessor); KlassHandle h_holder(THREAD, holder); LinkResolver::check_klass_accessability(h_accessor, h_holder, KILL_COMPILE_ON_FATAL_(NULL)); methodHandle dest_method; - LinkInfo link_info(h_holder, name, sig, h_accessor, /*check_access*/true); + LinkInfo link_info(h_holder, name, sig, h_accessor, LinkInfo::needs_access_check, tag); switch (bc) { case Bytecodes::_invokestatic: dest_method = @@ -796,7 +797,9 @@ ciMethod* ciEnv::get_method_by_index_impl(const constantPoolHandle& cpool, if (holder_is_accessible) { // Our declared holder is loaded. InstanceKlass* lookup = declared_holder->get_instanceKlass(); - Method* m = lookup_method(accessor->get_instanceKlass(), lookup, name_sym, sig_sym, bc); + constantTag tag = cpool->tag_ref_at(index); + assert(accessor->get_instanceKlass() == cpool->pool_holder(), "not the pool holder?"); + Method* m = lookup_method(accessor->get_instanceKlass(), lookup, name_sym, sig_sym, bc, tag); if (m != NULL && (bc == Bytecodes::_invokestatic ? m->method_holder()->is_not_initialized() diff --git a/hotspot/src/share/vm/ci/ciEnv.hpp b/hotspot/src/share/vm/ci/ciEnv.hpp index b1a95bd38f6..abffa79e4e5 100644 --- a/hotspot/src/share/vm/ci/ciEnv.hpp +++ b/hotspot/src/share/vm/ci/ciEnv.hpp @@ -158,7 +158,8 @@ private: InstanceKlass* holder, Symbol* name, Symbol* sig, - Bytecodes::Code bc); + Bytecodes::Code bc, + constantTag tag); // Get a ciObject from the object factory. Ensures uniqueness // of ciObjects. diff --git a/hotspot/src/share/vm/ci/ciMethod.cpp b/hotspot/src/share/vm/ci/ciMethod.cpp index 0acf602a4cc..50aa4dc42c1 100644 --- a/hotspot/src/share/vm/ci/ciMethod.cpp +++ b/hotspot/src/share/vm/ci/ciMethod.cpp @@ -786,7 +786,8 @@ ciMethod* ciMethod::resolve_invoke(ciKlass* caller, ciKlass* exact_receiver, boo Symbol* h_name = name()->get_symbol(); Symbol* h_signature = signature()->get_symbol(); - LinkInfo link_info(h_resolved, h_name, h_signature, caller_klass, check_access); + LinkInfo link_info(h_resolved, h_name, h_signature, caller_klass, + check_access ? LinkInfo::needs_access_check : LinkInfo::skip_access_check); methodHandle m; // Only do exact lookup if receiver klass has been linked. Otherwise, // the vtable has not been setup, and the LinkResolver will fail. diff --git a/hotspot/src/share/vm/interpreter/linkResolver.cpp b/hotspot/src/share/vm/interpreter/linkResolver.cpp index 173ec0ec667..42dc138319a 100644 --- a/hotspot/src/share/vm/interpreter/linkResolver.cpp +++ b/hotspot/src/share/vm/interpreter/linkResolver.cpp @@ -245,6 +245,7 @@ LinkInfo::LinkInfo(const constantPoolHandle& pool, int index, TRAPS) { // Get name, signature, and static klass _name = pool->name_ref_at(index); _signature = pool->signature_ref_at(index); + _tag = pool->tag_ref_at(index); _current_klass = KlassHandle(THREAD, pool->pool_holder()); // Coming from the constant pool always checks access @@ -681,6 +682,15 @@ methodHandle LinkResolver::resolve_method(const LinkInfo& link_info, THROW_MSG_NULL(vmSymbols::java_lang_IncompatibleClassChangeError(), buf); } + // check tag at call is method + if (!link_info.tag().is_invalid() && !link_info.tag().is_method()) { + ResourceMark rm(THREAD); + char buf[200]; + jio_snprintf(buf, sizeof(buf), "Resolving to non regular method %s", link_info.method_string()); + THROW_MSG_NULL(vmSymbols::java_lang_IncompatibleClassChangeError(), buf); + } + + // 2. lookup method in resolved klass and its super klasses methodHandle resolved_method = lookup_method_in_klasses(link_info, true, false, CHECK_NULL); @@ -740,6 +750,14 @@ methodHandle LinkResolver::resolve_interface_method(const LinkInfo& link_info, THROW_MSG_NULL(vmSymbols::java_lang_IncompatibleClassChangeError(), buf); } + // check tag at call is an interface method + if (!link_info.tag().is_invalid() && !link_info.tag().is_interface_method()) { + ResourceMark rm(THREAD); + char buf[200]; + jio_snprintf(buf, sizeof(buf), "Resolving to non interface method %s", link_info.method_string()); + THROW_MSG_NULL(vmSymbols::java_lang_IncompatibleClassChangeError(), buf); + } + // lookup method in this interface or its super, java.lang.Object // JDK8: also look for static methods methodHandle resolved_method = lookup_method_in_klasses(link_info, false, true, CHECK_NULL); @@ -917,7 +935,8 @@ void LinkResolver::resolve_static_call(CallInfo& result, resolved_klass->initialize(CHECK); // Use updated LinkInfo (to reresolve with resolved_klass as method_holder?) LinkInfo new_info(resolved_klass, link_info.name(), link_info.signature(), - link_info.current_klass(), link_info.check_access()); + link_info.current_klass(), + link_info.check_access() ? LinkInfo::needs_access_check : LinkInfo::skip_access_check); resolved_method = linktime_resolve_static_method(new_info, CHECK); } diff --git a/hotspot/src/share/vm/interpreter/linkResolver.hpp b/hotspot/src/share/vm/interpreter/linkResolver.hpp index 198eefbe2c0..919496bfa69 100644 --- a/hotspot/src/share/vm/interpreter/linkResolver.hpp +++ b/hotspot/src/share/vm/interpreter/linkResolver.hpp @@ -135,20 +135,35 @@ class LinkInfo : public StackObj { KlassHandle _resolved_klass; // class that the constant pool entry points to KlassHandle _current_klass; // class that owns the constant pool bool _check_access; + constantTag _tag; public: + enum AccessCheck { + needs_access_check, + skip_access_check + }; + LinkInfo(const constantPoolHandle& pool, int index, TRAPS); + // Condensed information from other call sites within the vm. - LinkInfo(KlassHandle resolved_klass, Symbol* name, Symbol* signature, - KlassHandle current_klass, bool check_access = true) : + LinkInfo(KlassHandle resolved_klass, Symbol* name, Symbol* signature, KlassHandle current_klass, + AccessCheck check_access = needs_access_check, + constantTag tag = JVM_CONSTANT_Invalid) : _resolved_klass(resolved_klass), _name(name), _signature(signature), _current_klass(current_klass), - _check_access(check_access) {} + _check_access(check_access == needs_access_check && current_klass.not_null()), _tag(tag) {} + + // Case where we just find the method and don't check access against the current class + LinkInfo(KlassHandle resolved_klass, Symbol*name, Symbol* signature) : + _resolved_klass(resolved_klass), + _name(name), _signature(signature), _current_klass(NULL), + _check_access(false), _tag(JVM_CONSTANT_Invalid) {} // accessors Symbol* name() const { return _name; } Symbol* signature() const { return _signature; } KlassHandle resolved_klass() const { return _resolved_klass; } KlassHandle current_klass() const { return _current_klass; } + constantTag tag() const { return _tag; } bool check_access() const { return _check_access; } char* method_string() const; diff --git a/hotspot/src/share/vm/jvmci/jvmciCompilerToVM.cpp b/hotspot/src/share/vm/jvmci/jvmciCompilerToVM.cpp index c0f773e279b..c4d3dfbb6b2 100644 --- a/hotspot/src/share/vm/jvmci/jvmciCompilerToVM.cpp +++ b/hotspot/src/share/vm/jvmci/jvmciCompilerToVM.cpp @@ -574,7 +574,7 @@ C2V_VMENTRY(jobject, resolveMethod, (JNIEnv *, jobject, jobject receiver_jvmci_t if (holder_klass->is_interface()) { // do link-time resolution to check all access rules. - LinkInfo link_info(holder_klass, method_name, method_signature, caller_klass, true); + LinkInfo link_info(holder_klass, method_name, method_signature, caller_klass); methodHandle resolved_method = LinkResolver::linktime_resolve_interface_method_or_null(link_info); if (resolved_method.is_null() || resolved_method->is_private()) { return NULL; @@ -586,7 +586,7 @@ C2V_VMENTRY(jobject, resolveMethod, (JNIEnv *, jobject, jobject receiver_jvmci_t return JNIHandles::make_local(THREAD, result); } else { // do link-time resolution to check all access rules. - LinkInfo link_info(holder_klass, method_name, method_signature, caller_klass, true); + LinkInfo link_info(holder_klass, method_name, method_signature, caller_klass); methodHandle resolved_method = LinkResolver::linktime_resolve_virtual_method_or_null(link_info); if (resolved_method.is_null()) { return NULL; diff --git a/hotspot/src/share/vm/jvmci/jvmciEnv.cpp b/hotspot/src/share/vm/jvmci/jvmciEnv.cpp index 348a28601be..808d4924ea8 100644 --- a/hotspot/src/share/vm/jvmci/jvmciEnv.cpp +++ b/hotspot/src/share/vm/jvmci/jvmciEnv.cpp @@ -282,11 +282,12 @@ methodHandle JVMCIEnv::lookup_method(instanceKlassHandle& h_accessor, instanceKlassHandle& h_holder, Symbol* name, Symbol* sig, - Bytecodes::Code bc) { + Bytecodes::Code bc, + constantTag tag) { JVMCI_EXCEPTION_CONTEXT; LinkResolver::check_klass_accessability(h_accessor, h_holder, KILL_COMPILE_ON_FATAL_(NULL)); methodHandle dest_method; - LinkInfo link_info(h_holder, name, sig, h_accessor, /*check_access*/true); + LinkInfo link_info(h_holder, name, sig, h_accessor, LinkInfo::needs_access_check, tag); switch (bc) { case Bytecodes::_invokestatic: dest_method = @@ -359,7 +360,8 @@ methodHandle JVMCIEnv::get_method_by_index_impl(const constantPoolHandle& cpool, if (holder_is_accessible) { // Our declared holder is loaded. instanceKlassHandle lookup = get_instance_klass_for_declared_method_holder(holder); - methodHandle m = lookup_method(accessor, lookup, name_sym, sig_sym, bc); + constantTag tag = cpool->tag_ref_at(index); + methodHandle m = lookup_method(accessor, lookup, name_sym, sig_sym, bc, tag); if (!m.is_null() && (bc == Bytecodes::_invokestatic ? InstanceKlass::cast(m->method_holder())->is_not_initialized() diff --git a/hotspot/src/share/vm/jvmci/jvmciEnv.hpp b/hotspot/src/share/vm/jvmci/jvmciEnv.hpp index f0291efde26..4f9cf9271b7 100644 --- a/hotspot/src/share/vm/jvmci/jvmciEnv.hpp +++ b/hotspot/src/share/vm/jvmci/jvmciEnv.hpp @@ -125,7 +125,8 @@ private: instanceKlassHandle& holder, Symbol* name, Symbol* sig, - Bytecodes::Code bc); + Bytecodes::Code bc, + constantTag tag); private: diff --git a/hotspot/src/share/vm/oops/constantPool.cpp b/hotspot/src/share/vm/oops/constantPool.cpp index 006a1e5b5a6..9900c45c816 100644 --- a/hotspot/src/share/vm/oops/constantPool.cpp +++ b/hotspot/src/share/vm/oops/constantPool.cpp @@ -409,6 +409,19 @@ int ConstantPool::impl_name_and_type_ref_index_at(int which, bool uncached) { return extract_high_short_from_int(ref_index); } +constantTag ConstantPool::impl_tag_ref_at(int which, bool uncached) { + int pool_index = which; + if (!uncached && cache() != NULL) { + if (ConstantPool::is_invokedynamic_index(which)) { + // Invokedynamic index is index into resolved_references + pool_index = invokedynamic_cp_cache_entry_at(which)->constant_pool_index(); + } else { + // change byte-ordering and go via cache + pool_index = remap_instruction_operand_from_cache(which); + } + } + return tag_at(pool_index); +} int ConstantPool::impl_klass_ref_index_at(int which, bool uncached) { guarantee(!ConstantPool::is_invokedynamic_index(which), @@ -664,6 +677,7 @@ oop ConstantPool::resolve_constant_at_impl(const constantPoolHandle& this_cp, in int callee_index = this_cp->method_handle_klass_index_at(index); Symbol* name = this_cp->method_handle_name_ref_at(index); Symbol* signature = this_cp->method_handle_signature_ref_at(index); + constantTag m_tag = this_cp->tag_at(this_cp->method_handle_index_at(index)); if (PrintMiscellaneous) tty->print_cr("resolve JVM_CONSTANT_MethodHandle:%d [%d/%d/%d] %s.%s", ref_kind, index, this_cp->method_handle_index_at(index), @@ -672,6 +686,15 @@ oop ConstantPool::resolve_constant_at_impl(const constantPoolHandle& this_cp, in { Klass* k = klass_at_impl(this_cp, callee_index, true, CHECK_NULL); callee = KlassHandle(THREAD, k); } + if ((callee->is_interface() && m_tag.is_method()) || + (!callee->is_interface() && m_tag.is_interface_method())) { + ResourceMark rm(THREAD); + char buf[200]; + jio_snprintf(buf, sizeof(buf), "Inconsistent constant data for %s.%s%s at index %d", + callee->name()->as_C_string(), name->as_C_string(), signature->as_C_string(), index); + THROW_MSG_NULL(vmSymbols::java_lang_IncompatibleClassChangeError(), buf); + } + KlassHandle klass(THREAD, this_cp->pool_holder()); Handle value = SystemDictionary::link_method_handle_constant(klass, ref_kind, callee, name, signature, diff --git a/hotspot/src/share/vm/oops/constantPool.hpp b/hotspot/src/share/vm/oops/constantPool.hpp index 99d77253be9..740e9f77bac 100644 --- a/hotspot/src/share/vm/oops/constantPool.hpp +++ b/hotspot/src/share/vm/oops/constantPool.hpp @@ -664,6 +664,8 @@ class ConstantPool : public Metadata { int remap_instruction_operand_from_cache(int operand); // operand must be biased by CPCACHE_INDEX_TAG + constantTag tag_ref_at(int cp_cache_index) { return impl_tag_ref_at(cp_cache_index, false); } + // Lookup for entries consisting of (name_index, signature_index) int name_ref_index_at(int which_nt); // == low-order jshort of name_and_type_at(which_nt) int signature_ref_index_at(int which_nt); // == high-order jshort of name_and_type_at(which_nt) @@ -784,6 +786,7 @@ class ConstantPool : public Metadata { Symbol* impl_signature_ref_at(int which, bool uncached); int impl_klass_ref_index_at(int which, bool uncached); int impl_name_and_type_ref_index_at(int which, bool uncached); + constantTag impl_tag_ref_at(int which, bool uncached); // Used while constructing constant pool (only by ClassFileParser) jint klass_index_at(int which) { diff --git a/hotspot/src/share/vm/prims/methodHandles.cpp b/hotspot/src/share/vm/prims/methodHandles.cpp index 0f58dde7063..0a72474dfa3 100644 --- a/hotspot/src/share/vm/prims/methodHandles.cpp +++ b/hotspot/src/share/vm/prims/methodHandles.cpp @@ -679,7 +679,7 @@ Handle MethodHandles::resolve_MemberName(Handle mname, KlassHandle caller, TRAPS case IS_METHOD: { CallInfo result; - LinkInfo link_info(defc, name, type, caller, caller.not_null()); + LinkInfo link_info(defc, name, type, caller); { assert(!HAS_PENDING_EXCEPTION, ""); if (ref_kind == JVM_REF_invokeStatic) { @@ -716,7 +716,7 @@ Handle MethodHandles::resolve_MemberName(Handle mname, KlassHandle caller, TRAPS case IS_CONSTRUCTOR: { CallInfo result; - LinkInfo link_info(defc, name, type, caller, caller.not_null()); + LinkInfo link_info(defc, name, type, caller); { assert(!HAS_PENDING_EXCEPTION, ""); if (name == vmSymbols::object_initializer_name()) { @@ -737,7 +737,7 @@ Handle MethodHandles::resolve_MemberName(Handle mname, KlassHandle caller, TRAPS fieldDescriptor result; // find_field initializes fd if found { assert(!HAS_PENDING_EXCEPTION, ""); - LinkInfo link_info(defc, name, type, caller, /*check_access*/false); + LinkInfo link_info(defc, name, type, caller, LinkInfo::skip_access_check); LinkResolver::resolve_field(result, link_info, Bytecodes::_nop, false, THREAD); if (HAS_PENDING_EXCEPTION) { return empty; diff --git a/hotspot/src/share/vm/runtime/javaCalls.cpp b/hotspot/src/share/vm/runtime/javaCalls.cpp index 9acd0200b29..82cbd26b2d4 100644 --- a/hotspot/src/share/vm/runtime/javaCalls.cpp +++ b/hotspot/src/share/vm/runtime/javaCalls.cpp @@ -183,7 +183,7 @@ void JavaCalls::call_virtual(JavaValue* result, KlassHandle spec_klass, Symbol* CallInfo callinfo; Handle receiver = args->receiver(); KlassHandle recvrKlass(THREAD, receiver.is_null() ? (Klass*)NULL : receiver->klass()); - LinkInfo link_info(spec_klass, name, signature, KlassHandle(), /*check_access*/false); + LinkInfo link_info(spec_klass, name, signature); LinkResolver::resolve_virtual_call( callinfo, receiver, recvrKlass, link_info, true, CHECK); methodHandle method = callinfo.selected_method(); @@ -220,7 +220,7 @@ void JavaCalls::call_virtual(JavaValue* result, Handle receiver, KlassHandle spe void JavaCalls::call_special(JavaValue* result, KlassHandle klass, Symbol* name, Symbol* signature, JavaCallArguments* args, TRAPS) { CallInfo callinfo; - LinkInfo link_info(klass, name, signature, KlassHandle(), /*check_access*/false); + LinkInfo link_info(klass, name, signature); LinkResolver::resolve_special_call(callinfo, link_info, CHECK); methodHandle method = callinfo.selected_method(); assert(method.not_null(), "should have thrown exception"); @@ -255,7 +255,7 @@ void JavaCalls::call_special(JavaValue* result, Handle receiver, KlassHandle kla void JavaCalls::call_static(JavaValue* result, KlassHandle klass, Symbol* name, Symbol* signature, JavaCallArguments* args, TRAPS) { CallInfo callinfo; - LinkInfo link_info(klass, name, signature, KlassHandle(), /*check_access*/false); + LinkInfo link_info(klass, name, signature); LinkResolver::resolve_static_call(callinfo, link_info, true, CHECK); methodHandle method = callinfo.selected_method(); assert(method.not_null(), "should have thrown exception"); diff --git a/hotspot/src/share/vm/runtime/reflection.cpp b/hotspot/src/share/vm/runtime/reflection.cpp index 45746d67c7c..d44ce3869fa 100644 --- a/hotspot/src/share/vm/runtime/reflection.cpp +++ b/hotspot/src/share/vm/runtime/reflection.cpp @@ -830,7 +830,7 @@ methodHandle Reflection::resolve_interface_call(instanceKlassHandle klass, const Symbol* signature = method->signature(); Symbol* name = method->name(); LinkResolver::resolve_interface_call(info, receiver, recv_klass, - LinkInfo(klass, name, signature, KlassHandle(), false), + LinkInfo(klass, name, signature), true, CHECK_(methodHandle())); return info.selected_method(); diff --git a/hotspot/test/runtime/8087223/BadMethodHandles.java b/hotspot/test/runtime/8087223/BadMethodHandles.java new file mode 100644 index 00000000000..57defac0fe2 --- /dev/null +++ b/hotspot/test/runtime/8087223/BadMethodHandles.java @@ -0,0 +1,250 @@ +/* + * 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 8087223 + * @summary Adding constantTag to keep method call consistent with it. + * @compile -XDignore.symbol.file BadMethodHandles.java + * @run main/othervm BadMethodHandles + */ + +import jdk.internal.org.objectweb.asm.*; +import java.io.FileOutputStream; +import java.lang.reflect.InvocationTargetException; +import java.lang.invoke.MethodHandle; +import java.lang.invoke.MethodHandles; +import java.lang.invoke.MethodType; +import static jdk.internal.org.objectweb.asm.Opcodes.*; + +public class BadMethodHandles { + + static byte[] dumpBadInterfaceMethodref() { + ClassWriter cw = new ClassWriter(0); + cw.visit(52, ACC_PUBLIC | ACC_SUPER, "BadInterfaceMethodref", null, "java/lang/Object", null); + Handle handle1 = + new Handle(Opcodes.H_INVOKEINTERFACE, "BadInterfaceMethodref", "m", "()V"); + Handle handle2 = + new Handle(Opcodes.H_INVOKEINTERFACE, "BadInterfaceMethodref", "staticM", "()V"); + + { + MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, "", "()V", null, null); + mv.visitCode(); + mv.visitVarInsn(ALOAD, 0); + mv.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "", "()V", false); + mv.visitInsn(RETURN); + mv.visitMaxs(1, 1); + mv.visitEnd(); + } + { + MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, "m", "()V", null, null); + mv.visitCode(); + mv.visitFieldInsn(GETSTATIC, "java/lang/System", "out", "Ljava/io/PrintStream;"); + mv.visitLdcInsn("hello from m"); + mv.visitMethodInsn(INVOKEVIRTUAL, "java/io/PrintStream", "println", "(Ljava/lang/String;)V", false/*intf*/); + mv.visitInsn(RETURN); + mv.visitMaxs(3, 1); + mv.visitEnd(); + } + { + MethodVisitor mv = cw.visitMethod(ACC_PUBLIC | ACC_STATIC, "staticM", "()V", null, null); + mv.visitCode(); + mv.visitFieldInsn(GETSTATIC, "java/lang/System", "out", "Ljava/io/PrintStream;"); + mv.visitLdcInsn("hello from staticM"); + mv.visitMethodInsn(INVOKEVIRTUAL, "java/io/PrintStream", "println", "(Ljava/lang/String;)V", false/*intf*/); + mv.visitInsn(RETURN); + mv.visitMaxs(3, 1); + mv.visitEnd(); + } + + { + MethodVisitor mv = cw.visitMethod(ACC_PUBLIC | ACC_STATIC, "runm", "()V", null, null); + mv.visitCode(); + // REF_invokeStatic + mv.visitLdcInsn(handle1); + mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/invoke/MethodHandle", "invoke", "()V", false); + mv.visitInsn(RETURN); + mv.visitMaxs(1, 1); + mv.visitEnd(); + } + + { + MethodVisitor mv = cw.visitMethod(ACC_PUBLIC | ACC_STATIC, "runStaticM", "()V", null, null); + mv.visitCode(); + // REF_invokeStatic + mv.visitLdcInsn(handle2); + mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/invoke/MethodHandle", "invoke", "()V", false); + mv.visitInsn(RETURN); + mv.visitMaxs(1, 1); + mv.visitEnd(); + } + + cw.visitEnd(); + return cw.toByteArray(); + } + + static byte[] dumpIBad() { + ClassWriter cw = new ClassWriter(0); + cw.visit(52, ACC_PUBLIC | ACC_ABSTRACT | ACC_INTERFACE, "IBad", null, "java/lang/Object", null); + { + MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, "m", "()V", null, null); + mv.visitCode(); + mv.visitFieldInsn(GETSTATIC, "java/lang/System", "out", "Ljava/io/PrintStream;"); + mv.visitLdcInsn("hello from m"); + mv.visitMethodInsn(INVOKEVIRTUAL, "java/io/PrintStream", "println", "(Ljava/lang/String;)V", false/*intf*/); + mv.visitInsn(RETURN); + mv.visitMaxs(3, 1); + mv.visitEnd(); + } + { + MethodVisitor mv = cw.visitMethod(ACC_PUBLIC | ACC_STATIC, "staticM", "()V", null, null); + mv.visitCode(); + mv.visitFieldInsn(GETSTATIC, "java/lang/System", "out", "Ljava/io/PrintStream;"); + mv.visitLdcInsn("hello from staticM"); + mv.visitMethodInsn(INVOKEVIRTUAL, "java/io/PrintStream", "println", "(Ljava/lang/String;)V", false/*intf*/); + mv.visitInsn(RETURN); + mv.visitMaxs(3, 1); + mv.visitEnd(); + } + cw.visitEnd(); + return cw.toByteArray(); + } + + static byte[] dumpBadMethodref() { + ClassWriter cw = new ClassWriter(0); + cw.visit(52, ACC_PUBLIC | ACC_SUPER, "BadMethodref", null, "java/lang/Object", new String[]{"IBad"}); + Handle handle1 = + new Handle(Opcodes.H_INVOKEINTERFACE, "BadMethodref", "m", "()V"); + Handle handle2 = + new Handle(Opcodes.H_INVOKEINTERFACE, "BadMethodref", "staticM", "()V"); + + { + MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, "", "()V", null, null); + mv.visitCode(); + mv.visitVarInsn(ALOAD, 0); + mv.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "", "()V", false); + mv.visitInsn(RETURN); + mv.visitMaxs(1, 1); + mv.visitEnd(); + } + + { + MethodVisitor mv = cw.visitMethod(ACC_PUBLIC | ACC_STATIC, "runm", "()V", null, null); + mv.visitCode(); + // REF_invokeStatic + mv.visitLdcInsn(handle1); + mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/invoke/MethodHandle", "invoke", "()V", false); + mv.visitInsn(RETURN); + mv.visitMaxs(1, 1); + mv.visitEnd(); + } + + { + MethodVisitor mv = cw.visitMethod(ACC_PUBLIC | ACC_STATIC, "runStaticM", "()V", null, null); + mv.visitCode(); + // REF_invokeStatic + mv.visitLdcInsn(handle2); + mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/invoke/MethodHandle", "invoke", "()V", false); + mv.visitInsn(RETURN); + mv.visitMaxs(1, 1); + mv.visitEnd(); + } + + cw.visitEnd(); + return cw.toByteArray(); + } + static class CL extends ClassLoader { + @Override + protected Class findClass(String name) throws ClassNotFoundException { + byte[] classBytes = null; + switch (name) { + case "BadInterfaceMethodref": classBytes = dumpBadInterfaceMethodref(); break; + case "BadMethodref" : classBytes = dumpBadMethodref(); break; + case "IBad" : classBytes = dumpIBad(); break; + default : throw new ClassNotFoundException(name); + } + return defineClass(name, classBytes, 0, classBytes.length); + } + } + + public static void main(String[] args) throws Throwable { + try (FileOutputStream fos = new FileOutputStream("BadInterfaceMethodref.class")) { + fos.write(dumpBadInterfaceMethodref()); + } + try (FileOutputStream fos = new FileOutputStream("IBad.class")) { + fos.write(dumpIBad()); + } + try (FileOutputStream fos = new FileOutputStream("BadMethodref.class")) { + fos.write(dumpBadMethodref()); + } + + Class cls = (new CL()).loadClass("BadInterfaceMethodref"); + String[] methods = {"runm", "runStaticM"}; + System.out.println("Test BadInterfaceMethodref:"); + int success = 0; + for (String name : methods) { + try { + System.out.printf("invoke %s: \n", name); + cls.getMethod(name).invoke(cls.newInstance()); + System.out.println("FAILED (no exception)"); // ICCE should be thrown + } catch (Throwable e) { + if (e instanceof InvocationTargetException && e.getCause() != null && + e.getCause() instanceof IncompatibleClassChangeError) { + System.out.println("PASSED"); + success++; + continue; + } else { + System.out.println("FAILED with exception"); + throw e; + } + } + } + if (success != methods.length) { + throw new Exception("BadInterfaceMethodRef Failed to catch IncompatibleClassChangeError"); + } + System.out.println("Test BadMethodref:"); + cls = (new CL()).loadClass("BadMethodref"); + success = 0; + for (String name : methods) { + try { + System.out.printf("invoke %s: \n", name); + cls.getMethod(name).invoke(cls.newInstance()); + System.out.println("FAILED (no exception)"); // ICCE should be thrown + } catch (Throwable e) { + if (e instanceof InvocationTargetException && e.getCause() != null && + e.getCause() instanceof IncompatibleClassChangeError) { + System.out.println("PASSED"); + success++; + continue; + } else { + System.out.println("FAILED with exception"); + throw e; + } + } + } + if (success != methods.length) { + throw new Exception("BadMethodRef Failed to catch IncompatibleClassChangeError"); + } + + } +} diff --git a/hotspot/test/runtime/8087223/IntfMethod.java b/hotspot/test/runtime/8087223/IntfMethod.java new file mode 100644 index 00000000000..a3a4ee3b8d8 --- /dev/null +++ b/hotspot/test/runtime/8087223/IntfMethod.java @@ -0,0 +1,156 @@ +/* + * 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 8087223 + * @summary Adding constantTag to keep method call consistent with it. + * @compile -XDignore.symbol.file IntfMethod.java + * @run main/othervm IntfMethod + * @run main/othervm -Xint IntfMethod + * @run main/othervm -Xcomp IntfMethod + */ + + +import jdk.internal.org.objectweb.asm.*; +import java.io.FileOutputStream; +import java.lang.reflect.InvocationTargetException; +import static jdk.internal.org.objectweb.asm.Opcodes.*; + +public class IntfMethod { + static byte[] dumpC() { + ClassWriter cw = new ClassWriter(0); + cw.visit(52, ACC_PUBLIC | ACC_SUPER, "C", null, "java/lang/Object", new String[]{"I"}); + { + MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, "", "()V", null, null); + mv.visitCode(); + mv.visitVarInsn(ALOAD, 0); + mv.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "", "()V", false); + mv.visitInsn(RETURN); + mv.visitMaxs(1, 1); + mv.visitEnd(); + } + { + MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, "testSpecialIntf", "()V", null, null); + mv.visitCode(); + mv.visitVarInsn(ALOAD, 0); + mv.visitMethodInsn(INVOKESPECIAL, "I", "f1", "()V", /*itf=*/false); + mv.visitInsn(RETURN); + mv.visitMaxs(1, 1); + mv.visitEnd(); + } + { + MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, "testStaticIntf", "()V", null, null); + mv.visitCode(); + mv.visitMethodInsn(INVOKESTATIC, "I", "f2", "()V", /*itf=*/false); + mv.visitInsn(RETURN); + mv.visitMaxs(1, 1); + mv.visitEnd(); + } + { + MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, "testSpecialClass", "()V", null, null); + mv.visitCode(); + mv.visitVarInsn(ALOAD, 0); + mv.visitMethodInsn(INVOKESPECIAL, "C", "f1", "()V", /*itf=*/true); + mv.visitInsn(RETURN); + mv.visitMaxs(1, 1); + mv.visitEnd(); + } + + { + MethodVisitor mv = cw.visitMethod(ACC_PUBLIC | ACC_STATIC, "f2", "()V", null, null); + mv.visitCode(); + mv.visitInsn(RETURN); + mv.visitMaxs(0, 1); + mv.visitEnd(); + } + { + MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, "testStaticClass", "()V", null, null); + mv.visitCode(); + mv.visitMethodInsn(INVOKESTATIC, "C", "f2", "()V", /*itf=*/true); + mv.visitInsn(RETURN); + mv.visitMaxs(1, 1); + mv.visitEnd(); + } + cw.visitEnd(); + return cw.toByteArray(); + } + + static byte[] dumpI() { + ClassWriter cw = new ClassWriter(0); + cw.visit(52, ACC_PUBLIC | ACC_ABSTRACT | ACC_INTERFACE, "I", null, "java/lang/Object", null); + { + MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, "f1", "()V", null, null); + mv.visitCode(); + mv.visitInsn(RETURN); + mv.visitMaxs(0, 1); + mv.visitEnd(); + } + { + MethodVisitor mv = cw.visitMethod(ACC_PUBLIC | ACC_STATIC, "f2", "()V", null, null); + mv.visitCode(); + mv.visitInsn(RETURN); + mv.visitMaxs(0, 1); + mv.visitEnd(); + } + cw.visitEnd(); + return cw.toByteArray(); + } + + static class CL extends ClassLoader { + @Override + protected Class findClass(String name) throws ClassNotFoundException { + byte[] classFile; + switch (name) { + case "I": classFile = dumpI(); break; + case "C": classFile = dumpC(); break; + default: + throw new ClassNotFoundException(name); + } + return defineClass(name, classFile, 0, classFile.length); + } + } + + public static void main(String[] args) throws Throwable { + Class cls = (new CL()).loadClass("C"); + try (FileOutputStream fos = new FileOutputStream("I.class")) { fos.write(dumpI()); } + try (FileOutputStream fos = new FileOutputStream("C.class")) { fos.write(dumpC()); } + + int success = 0; + for (String name : new String[] { "testSpecialIntf", "testStaticIntf", "testSpecialClass", "testStaticClass"}) { + System.out.printf("%s: ", name); + try { + cls.getMethod(name).invoke(cls.newInstance()); + System.out.println("FAILED"); + } catch (Throwable e) { + if (e instanceof InvocationTargetException && + e.getCause() != null && e.getCause() instanceof IncompatibleClassChangeError) { + System.out.println("PASSED"); + success++; + continue; + } + } + } + if (success != 4) throw new Exception("Failed to catch ICCE"); + } +} From 1777e00ccac09b897c0782ec3e57b35198b48688 Mon Sep 17 00:00:00 2001 From: Gerard Ziemski Date: Wed, 18 Nov 2015 10:46:02 -0600 Subject: [PATCH 15/20] 8141641: Runtime: implement range for ErrorLogTimeout Implement range=(0, jlong_max/1000) Reviewed-by: coleenp, ddmitriev, dholmes --- hotspot/src/share/vm/runtime/commandLineFlagRangeList.cpp | 2 +- hotspot/src/share/vm/runtime/globals.hpp | 3 ++- hotspot/src/share/vm/runtime/thread.cpp | 2 +- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/hotspot/src/share/vm/runtime/commandLineFlagRangeList.cpp b/hotspot/src/share/vm/runtime/commandLineFlagRangeList.cpp index b25f7ccdd28..ef45b27f0c6 100644 --- a/hotspot/src/share/vm/runtime/commandLineFlagRangeList.cpp +++ b/hotspot/src/share/vm/runtime/commandLineFlagRangeList.cpp @@ -279,7 +279,7 @@ void emit_range_double(const char* name, double min, double max) { // Generate func argument to pass into emit_range_xxx functions #define EMIT_RANGE_CHECK(a, b) , a, b -#define INITIAL_RANGES_SIZE 204 +#define INITIAL_RANGES_SIZE 205 GrowableArray* CommandLineFlagRangeList::_ranges = NULL; // Check the ranges of all flags that have them diff --git a/hotspot/src/share/vm/runtime/globals.hpp b/hotspot/src/share/vm/runtime/globals.hpp index fb61f555307..eeb61ea36a6 100644 --- a/hotspot/src/share/vm/runtime/globals.hpp +++ b/hotspot/src/share/vm/runtime/globals.hpp @@ -1031,9 +1031,10 @@ public: product(bool, CreateCoredumpOnCrash, true, \ "Create core/mini dump on VM fatal error") \ \ - product(uintx, ErrorLogTimeout, 2 * 60, \ + product(uint64_t, ErrorLogTimeout, 2 * 60, \ "Timeout, in seconds, to limit the time spent on writing an " \ "error log in case of a crash.") \ + range(0, (uint64_t)max_jlong/1000) \ \ product_pd(bool, UseOSErrorReporting, \ "Let VM fatal error propagate to the OS (ie. WER on Windows)") \ diff --git a/hotspot/src/share/vm/runtime/thread.cpp b/hotspot/src/share/vm/runtime/thread.cpp index de7c4139059..5291b8025fa 100644 --- a/hotspot/src/share/vm/runtime/thread.cpp +++ b/hotspot/src/share/vm/runtime/thread.cpp @@ -1299,7 +1299,7 @@ void WatcherThread::run() { if (!ShowMessageBoxOnError && (OnError == NULL || OnError[0] == '\0') && Arguments::abort_hook() == NULL) { - os::sleep(this, ErrorLogTimeout * 60 * 1000, false); + os::sleep(this, (jlong)ErrorLogTimeout * 1000, false); // in seconds fdStream err(defaultStream::output_fd()); err.print_raw_cr("# [ timer expired, abort... ]"); // skip atexit/vm_exit/vm_abort hooks From 72756888e9da71b64efa5fd3cb4f113553436f8c Mon Sep 17 00:00:00 2001 From: Coleen Phillimore Date: Wed, 18 Nov 2015 11:47:55 -0500 Subject: [PATCH 16/20] 8141570: Fix Zero interpreter build for --disable-precompiled-headers Change to include atomic.inline.hpp and allocation.inline.hpp only in .cpp files and some build fixes from Kim to build on ubuntu without devkits Reviewed-by: kbarrett, sgehwolf, erikj --- hotspot/make/linux/makefiles/zeroshark.make | 16 ++++--- hotspot/src/share/vm/gc/g1/g1AllocRegion.cpp | 1 + hotspot/src/share/vm/gc/g1/g1Allocator.cpp | 1 + .../src/share/vm/gc/g1/g1CollectedHeap.cpp | 1 + hotspot/src/share/vm/gc/g1/g1EvacStats.cpp | 2 + hotspot/src/share/vm/gc/g1/g1EvacStats.hpp | 23 +++------- .../src/share/vm/gc/g1/g1EvacStats.inline.hpp | 45 +++++++++++++++++++ hotspot/src/share/vm/runtime/java.cpp | 1 + 8 files changed, 69 insertions(+), 21 deletions(-) create mode 100644 hotspot/src/share/vm/gc/g1/g1EvacStats.inline.hpp diff --git a/hotspot/make/linux/makefiles/zeroshark.make b/hotspot/make/linux/makefiles/zeroshark.make index 3c10770d42a..240946fee3a 100644 --- a/hotspot/make/linux/makefiles/zeroshark.make +++ b/hotspot/make/linux/makefiles/zeroshark.make @@ -1,5 +1,5 @@ # -# Copyright (c) 2003, 2005, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2003, 2015, Oracle and/or its affiliates. All rights reserved. # Copyright 2007, 2008 Red Hat, Inc. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # @@ -25,8 +25,16 @@ # Setup common to Zero (non-Shark) and Shark versions of VM -# override this from the main file because some version of llvm do not like -Wundef -WARNING_FLAGS = -Wpointer-arith -Wsign-compare -Wunused-function -Wunused-value +# Some versions of llvm do not like -Wundef +ifeq ($(USE_CLANG), true) + WARNING_FLAGS += -Wno-undef +endif +# Suppress some warning flags that are normally turned on for hotspot, +# because some of the zero code has not been updated accordingly. +WARNING_FLAGS += -Wno-return-type \ + -Wno-format-nonliteral -Wno-format-security \ + -Wno-maybe-uninitialized + # The copied fdlibm routines in sharedRuntimeTrig.o must not be optimized OPT_CFLAGS/sharedRuntimeTrig.o = $(OPT_CFLAGS/NOOPT) @@ -42,5 +50,3 @@ endif ifeq ($(ARCH_DATA_MODEL), 64) CFLAGS += -D_LP64=1 endif - -OPT_CFLAGS/compactingPermGenGen.o = -O1 diff --git a/hotspot/src/share/vm/gc/g1/g1AllocRegion.cpp b/hotspot/src/share/vm/gc/g1/g1AllocRegion.cpp index 9a61b0da769..f7a9c8e8414 100644 --- a/hotspot/src/share/vm/gc/g1/g1AllocRegion.cpp +++ b/hotspot/src/share/vm/gc/g1/g1AllocRegion.cpp @@ -24,6 +24,7 @@ #include "precompiled.hpp" #include "gc/g1/g1AllocRegion.inline.hpp" +#include "gc/g1/g1EvacStats.inline.hpp" #include "gc/g1/g1CollectedHeap.inline.hpp" #include "runtime/orderAccess.inline.hpp" diff --git a/hotspot/src/share/vm/gc/g1/g1Allocator.cpp b/hotspot/src/share/vm/gc/g1/g1Allocator.cpp index 8bd8b376c72..665a7b5ed61 100644 --- a/hotspot/src/share/vm/gc/g1/g1Allocator.cpp +++ b/hotspot/src/share/vm/gc/g1/g1Allocator.cpp @@ -25,6 +25,7 @@ #include "precompiled.hpp" #include "gc/g1/g1Allocator.inline.hpp" #include "gc/g1/g1AllocRegion.inline.hpp" +#include "gc/g1/g1EvacStats.inline.hpp" #include "gc/g1/g1CollectedHeap.inline.hpp" #include "gc/g1/g1CollectorPolicy.hpp" #include "gc/g1/g1MarkSweep.hpp" diff --git a/hotspot/src/share/vm/gc/g1/g1CollectedHeap.cpp b/hotspot/src/share/vm/gc/g1/g1CollectedHeap.cpp index cba9a3eaf36..2b63e5dd67e 100644 --- a/hotspot/src/share/vm/gc/g1/g1CollectedHeap.cpp +++ b/hotspot/src/share/vm/gc/g1/g1CollectedHeap.cpp @@ -37,6 +37,7 @@ #include "gc/g1/g1CollectorState.hpp" #include "gc/g1/g1ErgoVerbose.hpp" #include "gc/g1/g1EvacFailure.hpp" +#include "gc/g1/g1EvacStats.inline.hpp" #include "gc/g1/g1GCPhaseTimes.hpp" #include "gc/g1/g1Log.hpp" #include "gc/g1/g1MarkSweep.hpp" diff --git a/hotspot/src/share/vm/gc/g1/g1EvacStats.cpp b/hotspot/src/share/vm/gc/g1/g1EvacStats.cpp index de0e5eda296..8a2317c59bd 100644 --- a/hotspot/src/share/vm/gc/g1/g1EvacStats.cpp +++ b/hotspot/src/share/vm/gc/g1/g1EvacStats.cpp @@ -23,6 +23,7 @@ */ #include "precompiled.hpp" +#include "memory/allocation.inline.hpp" #include "gc/g1/g1EvacStats.hpp" #include "gc/shared/gcId.hpp" #include "trace/tracing.hpp" @@ -114,3 +115,4 @@ void G1EvacStats::adjust_desired_plab_sz() { reset(); } +G1EvacStats::~G1EvacStats() { } diff --git a/hotspot/src/share/vm/gc/g1/g1EvacStats.hpp b/hotspot/src/share/vm/gc/g1/g1EvacStats.hpp index ffc548d16a3..1d0a53f5453 100644 --- a/hotspot/src/share/vm/gc/g1/g1EvacStats.hpp +++ b/hotspot/src/share/vm/gc/g1/g1EvacStats.hpp @@ -22,11 +22,10 @@ * */ -#ifndef SHARE_VM_gc_G1_G1EVACSTATS_HPP -#define SHARE_VM_gc_G1_G1EVACSTATS_HPP +#ifndef SHARE_VM_GC_G1_G1EVACSTATS_HPP +#define SHARE_VM_GC_G1_G1EVACSTATS_HPP #include "gc/shared/plab.hpp" -#include "runtime/atomic.hpp" // Records various memory allocation statistics gathered during evacuation. class G1EvacStats : public PLABStats { @@ -75,19 +74,11 @@ class G1EvacStats : public PLABStats { // Amount of space in heapwords wasted (unused) in the failing regions when an evacuation failure happens. size_t failure_waste() const { return _failure_waste; } - void add_direct_allocated(size_t value) { - Atomic::add_ptr(value, &_direct_allocated); - } + inline void add_direct_allocated(size_t value); + inline void add_region_end_waste(size_t value); + inline void add_failure_used_and_waste(size_t used, size_t waste); - void add_region_end_waste(size_t value) { - Atomic::add_ptr(value, &_region_end_waste); - Atomic::add_ptr(1, &_regions_filled); - } - - void add_failure_used_and_waste(size_t used, size_t waste) { - Atomic::add_ptr(used, &_failure_used); - Atomic::add_ptr(waste, &_failure_waste); - } + ~G1EvacStats(); }; -#endif // SHARE_VM_gc_G1_G1EVACSTATS_HPP +#endif // SHARE_VM_GC_G1_G1EVACSTATS_HPP diff --git a/hotspot/src/share/vm/gc/g1/g1EvacStats.inline.hpp b/hotspot/src/share/vm/gc/g1/g1EvacStats.inline.hpp new file mode 100644 index 00000000000..337d4625707 --- /dev/null +++ b/hotspot/src/share/vm/gc/g1/g1EvacStats.inline.hpp @@ -0,0 +1,45 @@ +/* + * 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. + * + */ + +#ifndef SHARE_VM_GC_G1_G1EVACSTATS_INLINE_HPP +#define SHARE_VM_GC_G1_G1EVACSTATS_INLINE_HPP + +#include "gc/g1/g1EvacStats.hpp" +#include "runtime/atomic.inline.hpp" + +inline void G1EvacStats::add_direct_allocated(size_t value) { + Atomic::add_ptr(value, &_direct_allocated); +} + +inline void G1EvacStats::add_region_end_waste(size_t value) { + Atomic::add_ptr(value, &_region_end_waste); + Atomic::add_ptr(1, &_regions_filled); +} + +inline void G1EvacStats::add_failure_used_and_waste(size_t used, size_t waste) { + Atomic::add_ptr(used, &_failure_used); + Atomic::add_ptr(waste, &_failure_waste); +} + +#endif // SHARE_VM_GC_G1_G1EVACSTATS_INLINE_HPP diff --git a/hotspot/src/share/vm/runtime/java.cpp b/hotspot/src/share/vm/runtime/java.cpp index 35bb7684be8..1ab815c7d52 100644 --- a/hotspot/src/share/vm/runtime/java.cpp +++ b/hotspot/src/share/vm/runtime/java.cpp @@ -49,6 +49,7 @@ #include "runtime/arguments.hpp" #include "runtime/biasedLocking.hpp" #include "runtime/compilationPolicy.hpp" +#include "runtime/deoptimization.hpp" #include "runtime/fprofiler.hpp" #include "runtime/init.hpp" #include "runtime/interfaceSupport.hpp" From d56280ca10db96016c9d5f2431f4bf3c614d137b Mon Sep 17 00:00:00 2001 From: Gerald Thornbrugh Date: Wed, 18 Nov 2015 09:32:52 -0800 Subject: [PATCH 17/20] 8141445: Use of Solaris/SPARC M7 libadimalloc.so can generate unknown signal in hs_err file Add libadimalloc.so SIGSEGV defines and a test to validate the correct message is printed in the hs_err file Reviewed-by: dcubed, dholmes --- hotspot/make/test/JtregNative.gmk | 10 ++ hotspot/src/os/posix/vm/os_posix.cpp | 15 +++ .../SEGVOverflow.java | 39 +++++++ .../Testlibadimalloc.java | 104 ++++++++++++++++++ .../libadimalloc.solaris.sparc/liboverflow.c | 72 ++++++++++++ 5 files changed, 240 insertions(+) create mode 100644 hotspot/test/runtime/libadimalloc.solaris.sparc/SEGVOverflow.java create mode 100644 hotspot/test/runtime/libadimalloc.solaris.sparc/Testlibadimalloc.java create mode 100644 hotspot/test/runtime/libadimalloc.solaris.sparc/liboverflow.c diff --git a/hotspot/make/test/JtregNative.gmk b/hotspot/make/test/JtregNative.gmk index b9d1dfa5894..b158b7eddb2 100644 --- a/hotspot/make/test/JtregNative.gmk +++ b/hotspot/make/test/JtregNative.gmk @@ -48,6 +48,16 @@ BUILD_HOTSPOT_JTREG_NATIVE_SRC := \ $(HOTSPOT_TOPDIR)/test/runtime/SameObject \ # +# Add conditional directories here when needed. +ifeq ($(OPENJDK_TARGET_OS)-$(OPENJDK_TARGET_CPU_ARCH), solaris-sparc) +BUILD_HOTSPOT_JTREG_NATIVE_SRC += \ + $(HOTSPOT_TOPDIR)/test/runtime/libadimalloc.solaris.sparc +endif + +ifeq ($(TOOLCHAIN_TYPE), solstudio) + BUILD_HOTSPOT_JTREG_LIBRARIES_LDFLAGS_liboverflow := -lc +endif + BUILD_HOTSPOT_JTREG_OUTPUT_DIR := $(BUILD_OUTPUT)/support/test/hotspot/jtreg/native BUILD_HOTSPOT_JTREG_IMAGE_DIR := $(TEST_IMAGE_DIR)/hotspot/jtreg diff --git a/hotspot/src/os/posix/vm/os_posix.cpp b/hotspot/src/os/posix/vm/os_posix.cpp index 47ad1217d1e..63fe550518b 100644 --- a/hotspot/src/os/posix/vm/os_posix.cpp +++ b/hotspot/src/os/posix/vm/os_posix.cpp @@ -837,6 +837,21 @@ static bool get_signal_code_description(const siginfo_t* si, enum_sigcode_desc_t #if defined(IA64) && !defined(AIX) { SIGSEGV, SEGV_PSTKOVF, "SEGV_PSTKOVF", "Paragraph stack overflow" }, #endif +#if defined(__sparc) && defined(SOLARIS) +// define Solaris Sparc M7 ADI SEGV signals +#if !defined(SEGV_ACCADI) +#define SEGV_ACCADI 3 +#endif + { SIGSEGV, SEGV_ACCADI, "SEGV_ACCADI", "ADI not enabled for mapped object." }, +#if !defined(SEGV_ACCDERR) +#define SEGV_ACCDERR 4 +#endif + { SIGSEGV, SEGV_ACCDERR, "SEGV_ACCDERR", "ADI disrupting exception." }, +#if !defined(SEGV_ACCPERR) +#define SEGV_ACCPERR 5 +#endif + { SIGSEGV, SEGV_ACCPERR, "SEGV_ACCPERR", "ADI precise exception." }, +#endif // defined(__sparc) && defined(SOLARIS) { SIGBUS, BUS_ADRALN, "BUS_ADRALN", "Invalid address alignment." }, { SIGBUS, BUS_ADRERR, "BUS_ADRERR", "Nonexistent physical address." }, { SIGBUS, BUS_OBJERR, "BUS_OBJERR", "Object-specific hardware error." }, diff --git a/hotspot/test/runtime/libadimalloc.solaris.sparc/SEGVOverflow.java b/hotspot/test/runtime/libadimalloc.solaris.sparc/SEGVOverflow.java new file mode 100644 index 00000000000..da754da73ac --- /dev/null +++ b/hotspot/test/runtime/libadimalloc.solaris.sparc/SEGVOverflow.java @@ -0,0 +1,39 @@ +/* + * 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. + */ +public class SEGVOverflow { + + static { + System.loadLibrary("overflow"); + } + + native static String nativesegv(); + + public static void main(String[] args) { + String str = nativesegv(); + if (str == null) { + System.out.println("FAILED: malloc returned null"); + } else { + System.out.println(str); + } + } +} diff --git a/hotspot/test/runtime/libadimalloc.solaris.sparc/Testlibadimalloc.java b/hotspot/test/runtime/libadimalloc.solaris.sparc/Testlibadimalloc.java new file mode 100644 index 00000000000..e9a8406f0f1 --- /dev/null +++ b/hotspot/test/runtime/libadimalloc.solaris.sparc/Testlibadimalloc.java @@ -0,0 +1,104 @@ +/* + * 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 Testlibadimalloc.java + * @bug 8141445 + * @summary make sure the Solaris Sparc M7 libadimalloc.so library generates SIGSEGV's on buffer overflow + * @requires (os.family == "solaris" & os.arch == "sparcv9") + * @library /testlibrary + * @build jdk.test.lib.* + * @compile SEGVOverflow.java + * @run driver Testlibadimalloc + */ + +import java.io.*; +import java.nio.file.*; +import java.util.*; +import jdk.test.lib.ProcessTools; + +public class Testlibadimalloc { + + // Expected return value when java program cores + static final int EXPECTED_RET_VAL = 6; + + public static void main(String[] args) throws Throwable { + + // See if the libadimalloc.so library exists + Path path = Paths.get("/usr/lib/64/libadimalloc.so"); + + // If the libadimalloc.so file does not exist, pass the test + if (!(Files.isRegularFile(path) || Files.isSymbolicLink(path))) { + System.out.println("Test skipped; libadimalloc.so does not exist"); + return; + } + + // Get the JDK, library and class path properties + String libpath = System.getProperty("java.library.path"); + + // Create a new java process for the SEGVOverflow Java/JNI test + ProcessBuilder builder = ProcessTools.createJavaProcessBuilder( + "-Djava.library.path=" + libpath + ":.", "SEGVOverflow"); + + // Add the LD_PRELOAD_64 value to the environment + Map env = builder.environment(); + env.put("LD_PRELOAD_64", "libadimalloc.so"); + + // Start the process, get the pid and then wait for the test to finish + Process process = builder.start(); + long pid = process.getPid(); + int retval = process.waitFor(); + + // make sure the SEGVOverflow test crashed + boolean found = false; + if (retval == EXPECTED_RET_VAL) { + String filename = "hs_err_pid" + pid + ".log"; + Path filepath = Paths.get(filename); + // check to see if hs_err_file exists + if (Files.isRegularFile(filepath)) { + // see if the crash was due to a SEGV_ACCPERR signal + File hs_err_file = new File(filename); + Scanner scanner = new Scanner(hs_err_file); + while (!found && scanner.hasNextLine()) { + String nextline = scanner.nextLine(); + if (nextline.contains("SEGV_ACCPERR")) { + found = true; + } + } + } else { + System.out.println("Test failed; hs_err_file does not exist: " + + filepath); + } + } else { + System.out.println("Test failed; java test program did not " + + "return expected error: expected = " + + EXPECTED_RET_VAL + ", retval = " + retval); + } + // If SEGV_ACCPERR was not found in the hs_err file fail the test + if (!found) { + System.out.println("FAIL: SEGV_ACCPERR not found"); + throw new RuntimeException("FAIL: SEGV_ACCPERR not found"); + } + } +} diff --git a/hotspot/test/runtime/libadimalloc.solaris.sparc/liboverflow.c b/hotspot/test/runtime/libadimalloc.solaris.sparc/liboverflow.c new file mode 100644 index 00000000000..36b5dae9fb0 --- /dev/null +++ b/hotspot/test/runtime/libadimalloc.solaris.sparc/liboverflow.c @@ -0,0 +1,72 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +#include +#include +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +JNIEXPORT jstring JNICALL Java_SEGVOverflow_nativesegv(JNIEnv *env, jobject obj) { + char *buffer1; + char *buffer2; + char *buffer3; + char ch; + + jstring ret = NULL; + + // sleep for a bit to let the libadimalloc library initialize + sleep(5); + + // allocate three buffers + buffer1 = (char *)malloc(64); + buffer2 = (char *)malloc(64); + buffer3 = (char *)malloc(64); + if ((buffer1 == NULL) || (buffer2 == NULL) || (buffer3 == NULL)) { + // this return will result in a test failure + return ret; + } + + // Read past the end of each buffer multiple times to increase the probability + // that an ADI version mismatch occurs so an ADI fault is triggered. + ch = buffer1[70]; + ch = buffer2[70]; + ch = buffer3[70]; + ch = buffer1[140]; + ch = buffer2[140]; + ch = buffer3[140]; + + // create a failed test return value because this test should have cored + buffer1 = "TEST FAILED, a read past the end of a buffer succeeded."; + ret = (*env)->NewStringUTF(env, buffer1); + + return ret; +} + +#ifdef __cplusplus +} +#endif From 8af1d18e787af1055a7fb2cfd96b5ad15ec0da52 Mon Sep 17 00:00:00 2001 From: Bengt Rutisson Date: Thu, 19 Nov 2015 16:14:45 +0100 Subject: [PATCH 18/20] 8143255: Remove debug logging from SymbolTable::unlink() and SymbolTable::possibly_parallel_unlink() Reviewed-by: coleenp, tschatzl --- .../src/share/vm/classfile/symbolTable.cpp | 19 +++---------------- .../src/share/vm/classfile/symbolTable.hpp | 2 +- 2 files changed, 4 insertions(+), 17 deletions(-) diff --git a/hotspot/src/share/vm/classfile/symbolTable.cpp b/hotspot/src/share/vm/classfile/symbolTable.cpp index eeb23890265..b268e08bdba 100644 --- a/hotspot/src/share/vm/classfile/symbolTable.cpp +++ b/hotspot/src/share/vm/classfile/symbolTable.cpp @@ -97,7 +97,7 @@ int SymbolTable::_symbols_removed = 0; int SymbolTable::_symbols_counted = 0; volatile int SymbolTable::_parallel_claimed_idx = 0; -void SymbolTable::buckets_unlink(int start_idx, int end_idx, int* processed, int* removed, size_t* memory_total) { +void SymbolTable::buckets_unlink(int start_idx, int end_idx, int* processed, int* removed) { for (int i = start_idx; i < end_idx; ++i) { HashtableEntry** p = the_table()->bucket_addr(i); HashtableEntry* entry = the_table()->bucket(i); @@ -110,7 +110,6 @@ void SymbolTable::buckets_unlink(int start_idx, int end_idx, int* processed, int break; } Symbol* s = entry->literal(); - (*memory_total) += s->size(); (*processed)++; assert(s != NULL, "just checking"); // If reference count is zero, remove. @@ -133,15 +132,9 @@ void SymbolTable::buckets_unlink(int start_idx, int end_idx, int* processed, int // This is done late during GC. void SymbolTable::unlink(int* processed, int* removed) { size_t memory_total = 0; - buckets_unlink(0, the_table()->table_size(), processed, removed, &memory_total); + buckets_unlink(0, the_table()->table_size(), processed, removed); _symbols_removed += *removed; _symbols_counted += *processed; - // Exclude printing for normal PrintGCDetails because people parse - // this output. - if (PrintGCDetails && Verbose && WizardMode) { - gclog_or_tty->print(" [Symbols=%d size=" SIZE_FORMAT "K] ", *processed, - (memory_total*HeapWordSize)/1024); - } } void SymbolTable::possibly_parallel_unlink(int* processed, int* removed) { @@ -158,16 +151,10 @@ void SymbolTable::possibly_parallel_unlink(int* processed, int* removed) { } int end_idx = MIN2(limit, start_idx + ClaimChunkSize); - buckets_unlink(start_idx, end_idx, processed, removed, &memory_total); + buckets_unlink(start_idx, end_idx, processed, removed); } Atomic::add(*processed, &_symbols_counted); Atomic::add(*removed, &_symbols_removed); - // Exclude printing for normal PrintGCDetails because people parse - // this output. - if (PrintGCDetails && Verbose && WizardMode) { - gclog_or_tty->print(" [Symbols: scanned=%d removed=%d size=" SIZE_FORMAT "K] ", *processed, *removed, - (memory_total*HeapWordSize)/1024); - } } // Create a new table and using alternate hash code, populate the new table diff --git a/hotspot/src/share/vm/classfile/symbolTable.hpp b/hotspot/src/share/vm/classfile/symbolTable.hpp index 29ee8d2b779..8f310e70e1b 100644 --- a/hotspot/src/share/vm/classfile/symbolTable.hpp +++ b/hotspot/src/share/vm/classfile/symbolTable.hpp @@ -132,7 +132,7 @@ private: static volatile int _parallel_claimed_idx; // Release any dead symbols - static void buckets_unlink(int start_idx, int end_idx, int* processed, int* removed, size_t* memory_total); + static void buckets_unlink(int start_idx, int end_idx, int* processed, int* removed); public: enum { symbol_alloc_batch_size = 8, From 71fe04f939e618827c5da84fddcc40f2a4670afb Mon Sep 17 00:00:00 2001 From: Harold Seigel Date: Thu, 19 Nov 2015 11:54:32 -0500 Subject: [PATCH 19/20] 8143078: Remove JVM_DefineClassWithSourceCond() API Remove the method and remove unneeded argument to jvm_define_class_common() Reviewed-by: dholmes, coleenp --- hotspot/make/share/makefiles/mapfile-vers | 1 - hotspot/src/share/vm/prims/jvm.cpp | 19 ++++--------------- hotspot/src/share/vm/prims/jvm.h | 11 ----------- 3 files changed, 4 insertions(+), 27 deletions(-) diff --git a/hotspot/make/share/makefiles/mapfile-vers b/hotspot/make/share/makefiles/mapfile-vers index 57b5ad37c41..7021e53d444 100644 --- a/hotspot/make/share/makefiles/mapfile-vers +++ b/hotspot/make/share/makefiles/mapfile-vers @@ -31,7 +31,6 @@ JVM_CurrentTimeMillis; JVM_DefineClass; JVM_DefineClassWithSource; - JVM_DefineClassWithSourceCond; JVM_DesiredAssertionStatus; JVM_DoPrivileged; JVM_DumpAllStacks; diff --git a/hotspot/src/share/vm/prims/jvm.cpp b/hotspot/src/share/vm/prims/jvm.cpp index d25485c051e..45db3542ec2 100644 --- a/hotspot/src/share/vm/prims/jvm.cpp +++ b/hotspot/src/share/vm/prims/jvm.cpp @@ -861,11 +861,10 @@ static void is_lock_held_by_thread(Handle loader, PerfCounter* counter, TRAPS) { } // common code for JVM_DefineClass() and JVM_DefineClassWithSource() -// and JVM_DefineClassWithSourceCond() static jclass jvm_define_class_common(JNIEnv *env, const char *name, jobject loader, const jbyte *buf, jsize len, jobject pd, const char *source, - jboolean verify, TRAPS) { + TRAPS) { if (source == NULL) source = "__JVM_DefineClass__"; assert(THREAD->is_Java_thread(), "must be a JavaThread"); @@ -906,8 +905,7 @@ static jclass jvm_define_class_common(JNIEnv *env, const char *name, Handle protection_domain (THREAD, JNIHandles::resolve(pd)); Klass* k = SystemDictionary::resolve_from_stream(class_name, class_loader, protection_domain, &st, - verify != 0, - CHECK_NULL); + true, CHECK_NULL); if (TraceClassResolution && k != NULL) { trace_class_resolution(k); @@ -920,23 +918,14 @@ static jclass jvm_define_class_common(JNIEnv *env, const char *name, JVM_ENTRY(jclass, JVM_DefineClass(JNIEnv *env, const char *name, jobject loader, const jbyte *buf, jsize len, jobject pd)) JVMWrapper2("JVM_DefineClass %s", name); - return jvm_define_class_common(env, name, loader, buf, len, pd, NULL, true, THREAD); + return jvm_define_class_common(env, name, loader, buf, len, pd, NULL, THREAD); JVM_END JVM_ENTRY(jclass, JVM_DefineClassWithSource(JNIEnv *env, const char *name, jobject loader, const jbyte *buf, jsize len, jobject pd, const char *source)) JVMWrapper2("JVM_DefineClassWithSource %s", name); - return jvm_define_class_common(env, name, loader, buf, len, pd, source, true, THREAD); -JVM_END - -JVM_ENTRY(jclass, JVM_DefineClassWithSourceCond(JNIEnv *env, const char *name, - jobject loader, const jbyte *buf, - jsize len, jobject pd, - const char *source, jboolean verify)) - JVMWrapper2("JVM_DefineClassWithSourceCond %s", name); - - return jvm_define_class_common(env, name, loader, buf, len, pd, source, verify, THREAD); + return jvm_define_class_common(env, name, loader, buf, len, pd, source, THREAD); JVM_END JVM_ENTRY(jclass, JVM_FindLoadedClass(JNIEnv *env, jobject loader, jstring name)) diff --git a/hotspot/src/share/vm/prims/jvm.h b/hotspot/src/share/vm/prims/jvm.h index beb5bc8f32a..bc42dbf3edb 100644 --- a/hotspot/src/share/vm/prims/jvm.h +++ b/hotspot/src/share/vm/prims/jvm.h @@ -378,17 +378,6 @@ JVM_DefineClassWithSource(JNIEnv *env, const char *name, jobject loader, const jbyte *buf, jsize len, jobject pd, const char *source); -/* Define a class with a source with conditional verification (added HSX 14) - * -Xverify:all will verify anyway, -Xverify:none will not verify, - * -Xverify:remote (default) will obey this conditional - * i.e. true = should_verify_class - */ -JNIEXPORT jclass JNICALL -JVM_DefineClassWithSourceCond(JNIEnv *env, const char *name, - jobject loader, const jbyte *buf, - jsize len, jobject pd, const char *source, - jboolean verify); - /* * Reflection support functions */ From c02b26ee45b405fd55ba4e15dedc6ed1d7912b14 Mon Sep 17 00:00:00 2001 From: Christian Tornqvist Date: Thu, 19 Nov 2015 10:34:11 -0800 Subject: [PATCH 20/20] 8143324: Backout JDK-8087223 Reviewed-by: coleenp, acorn --- hotspot/src/share/vm/ci/ciEnv.cpp | 9 +- hotspot/src/share/vm/ci/ciEnv.hpp | 3 +- hotspot/src/share/vm/ci/ciMethod.cpp | 3 +- .../src/share/vm/interpreter/linkResolver.cpp | 21 +- .../src/share/vm/interpreter/linkResolver.hpp | 21 +- .../src/share/vm/jvmci/jvmciCompilerToVM.cpp | 4 +- hotspot/src/share/vm/jvmci/jvmciEnv.cpp | 8 +- hotspot/src/share/vm/jvmci/jvmciEnv.hpp | 3 +- hotspot/src/share/vm/oops/constantPool.cpp | 23 -- hotspot/src/share/vm/oops/constantPool.hpp | 3 - hotspot/src/share/vm/prims/methodHandles.cpp | 6 +- hotspot/src/share/vm/runtime/javaCalls.cpp | 6 +- hotspot/src/share/vm/runtime/reflection.cpp | 2 +- .../runtime/8087223/BadMethodHandles.java | 250 ------------------ hotspot/test/runtime/8087223/IntfMethod.java | 156 ----------- 15 files changed, 22 insertions(+), 496 deletions(-) delete mode 100644 hotspot/test/runtime/8087223/BadMethodHandles.java delete mode 100644 hotspot/test/runtime/8087223/IntfMethod.java diff --git a/hotspot/src/share/vm/ci/ciEnv.cpp b/hotspot/src/share/vm/ci/ciEnv.cpp index 2e096bb303a..9c9d7b300c2 100644 --- a/hotspot/src/share/vm/ci/ciEnv.cpp +++ b/hotspot/src/share/vm/ci/ciEnv.cpp @@ -704,14 +704,13 @@ Method* ciEnv::lookup_method(InstanceKlass* accessor, InstanceKlass* holder, Symbol* name, Symbol* sig, - Bytecodes::Code bc, - constantTag tag) { + Bytecodes::Code bc) { EXCEPTION_CONTEXT; KlassHandle h_accessor(THREAD, accessor); KlassHandle h_holder(THREAD, holder); LinkResolver::check_klass_accessability(h_accessor, h_holder, KILL_COMPILE_ON_FATAL_(NULL)); methodHandle dest_method; - LinkInfo link_info(h_holder, name, sig, h_accessor, LinkInfo::needs_access_check, tag); + LinkInfo link_info(h_holder, name, sig, h_accessor, /*check_access*/true); switch (bc) { case Bytecodes::_invokestatic: dest_method = @@ -797,9 +796,7 @@ ciMethod* ciEnv::get_method_by_index_impl(const constantPoolHandle& cpool, if (holder_is_accessible) { // Our declared holder is loaded. InstanceKlass* lookup = declared_holder->get_instanceKlass(); - constantTag tag = cpool->tag_ref_at(index); - assert(accessor->get_instanceKlass() == cpool->pool_holder(), "not the pool holder?"); - Method* m = lookup_method(accessor->get_instanceKlass(), lookup, name_sym, sig_sym, bc, tag); + Method* m = lookup_method(accessor->get_instanceKlass(), lookup, name_sym, sig_sym, bc); if (m != NULL && (bc == Bytecodes::_invokestatic ? m->method_holder()->is_not_initialized() diff --git a/hotspot/src/share/vm/ci/ciEnv.hpp b/hotspot/src/share/vm/ci/ciEnv.hpp index abffa79e4e5..b1a95bd38f6 100644 --- a/hotspot/src/share/vm/ci/ciEnv.hpp +++ b/hotspot/src/share/vm/ci/ciEnv.hpp @@ -158,8 +158,7 @@ private: InstanceKlass* holder, Symbol* name, Symbol* sig, - Bytecodes::Code bc, - constantTag tag); + Bytecodes::Code bc); // Get a ciObject from the object factory. Ensures uniqueness // of ciObjects. diff --git a/hotspot/src/share/vm/ci/ciMethod.cpp b/hotspot/src/share/vm/ci/ciMethod.cpp index 50aa4dc42c1..0acf602a4cc 100644 --- a/hotspot/src/share/vm/ci/ciMethod.cpp +++ b/hotspot/src/share/vm/ci/ciMethod.cpp @@ -786,8 +786,7 @@ ciMethod* ciMethod::resolve_invoke(ciKlass* caller, ciKlass* exact_receiver, boo Symbol* h_name = name()->get_symbol(); Symbol* h_signature = signature()->get_symbol(); - LinkInfo link_info(h_resolved, h_name, h_signature, caller_klass, - check_access ? LinkInfo::needs_access_check : LinkInfo::skip_access_check); + LinkInfo link_info(h_resolved, h_name, h_signature, caller_klass, check_access); methodHandle m; // Only do exact lookup if receiver klass has been linked. Otherwise, // the vtable has not been setup, and the LinkResolver will fail. diff --git a/hotspot/src/share/vm/interpreter/linkResolver.cpp b/hotspot/src/share/vm/interpreter/linkResolver.cpp index 42dc138319a..173ec0ec667 100644 --- a/hotspot/src/share/vm/interpreter/linkResolver.cpp +++ b/hotspot/src/share/vm/interpreter/linkResolver.cpp @@ -245,7 +245,6 @@ LinkInfo::LinkInfo(const constantPoolHandle& pool, int index, TRAPS) { // Get name, signature, and static klass _name = pool->name_ref_at(index); _signature = pool->signature_ref_at(index); - _tag = pool->tag_ref_at(index); _current_klass = KlassHandle(THREAD, pool->pool_holder()); // Coming from the constant pool always checks access @@ -682,15 +681,6 @@ methodHandle LinkResolver::resolve_method(const LinkInfo& link_info, THROW_MSG_NULL(vmSymbols::java_lang_IncompatibleClassChangeError(), buf); } - // check tag at call is method - if (!link_info.tag().is_invalid() && !link_info.tag().is_method()) { - ResourceMark rm(THREAD); - char buf[200]; - jio_snprintf(buf, sizeof(buf), "Resolving to non regular method %s", link_info.method_string()); - THROW_MSG_NULL(vmSymbols::java_lang_IncompatibleClassChangeError(), buf); - } - - // 2. lookup method in resolved klass and its super klasses methodHandle resolved_method = lookup_method_in_klasses(link_info, true, false, CHECK_NULL); @@ -750,14 +740,6 @@ methodHandle LinkResolver::resolve_interface_method(const LinkInfo& link_info, THROW_MSG_NULL(vmSymbols::java_lang_IncompatibleClassChangeError(), buf); } - // check tag at call is an interface method - if (!link_info.tag().is_invalid() && !link_info.tag().is_interface_method()) { - ResourceMark rm(THREAD); - char buf[200]; - jio_snprintf(buf, sizeof(buf), "Resolving to non interface method %s", link_info.method_string()); - THROW_MSG_NULL(vmSymbols::java_lang_IncompatibleClassChangeError(), buf); - } - // lookup method in this interface or its super, java.lang.Object // JDK8: also look for static methods methodHandle resolved_method = lookup_method_in_klasses(link_info, false, true, CHECK_NULL); @@ -935,8 +917,7 @@ void LinkResolver::resolve_static_call(CallInfo& result, resolved_klass->initialize(CHECK); // Use updated LinkInfo (to reresolve with resolved_klass as method_holder?) LinkInfo new_info(resolved_klass, link_info.name(), link_info.signature(), - link_info.current_klass(), - link_info.check_access() ? LinkInfo::needs_access_check : LinkInfo::skip_access_check); + link_info.current_klass(), link_info.check_access()); resolved_method = linktime_resolve_static_method(new_info, CHECK); } diff --git a/hotspot/src/share/vm/interpreter/linkResolver.hpp b/hotspot/src/share/vm/interpreter/linkResolver.hpp index 919496bfa69..198eefbe2c0 100644 --- a/hotspot/src/share/vm/interpreter/linkResolver.hpp +++ b/hotspot/src/share/vm/interpreter/linkResolver.hpp @@ -135,35 +135,20 @@ class LinkInfo : public StackObj { KlassHandle _resolved_klass; // class that the constant pool entry points to KlassHandle _current_klass; // class that owns the constant pool bool _check_access; - constantTag _tag; public: - enum AccessCheck { - needs_access_check, - skip_access_check - }; - LinkInfo(const constantPoolHandle& pool, int index, TRAPS); - // Condensed information from other call sites within the vm. - LinkInfo(KlassHandle resolved_klass, Symbol* name, Symbol* signature, KlassHandle current_klass, - AccessCheck check_access = needs_access_check, - constantTag tag = JVM_CONSTANT_Invalid) : + LinkInfo(KlassHandle resolved_klass, Symbol* name, Symbol* signature, + KlassHandle current_klass, bool check_access = true) : _resolved_klass(resolved_klass), _name(name), _signature(signature), _current_klass(current_klass), - _check_access(check_access == needs_access_check && current_klass.not_null()), _tag(tag) {} - - // Case where we just find the method and don't check access against the current class - LinkInfo(KlassHandle resolved_klass, Symbol*name, Symbol* signature) : - _resolved_klass(resolved_klass), - _name(name), _signature(signature), _current_klass(NULL), - _check_access(false), _tag(JVM_CONSTANT_Invalid) {} + _check_access(check_access) {} // accessors Symbol* name() const { return _name; } Symbol* signature() const { return _signature; } KlassHandle resolved_klass() const { return _resolved_klass; } KlassHandle current_klass() const { return _current_klass; } - constantTag tag() const { return _tag; } bool check_access() const { return _check_access; } char* method_string() const; diff --git a/hotspot/src/share/vm/jvmci/jvmciCompilerToVM.cpp b/hotspot/src/share/vm/jvmci/jvmciCompilerToVM.cpp index c4d3dfbb6b2..c0f773e279b 100644 --- a/hotspot/src/share/vm/jvmci/jvmciCompilerToVM.cpp +++ b/hotspot/src/share/vm/jvmci/jvmciCompilerToVM.cpp @@ -574,7 +574,7 @@ C2V_VMENTRY(jobject, resolveMethod, (JNIEnv *, jobject, jobject receiver_jvmci_t if (holder_klass->is_interface()) { // do link-time resolution to check all access rules. - LinkInfo link_info(holder_klass, method_name, method_signature, caller_klass); + LinkInfo link_info(holder_klass, method_name, method_signature, caller_klass, true); methodHandle resolved_method = LinkResolver::linktime_resolve_interface_method_or_null(link_info); if (resolved_method.is_null() || resolved_method->is_private()) { return NULL; @@ -586,7 +586,7 @@ C2V_VMENTRY(jobject, resolveMethod, (JNIEnv *, jobject, jobject receiver_jvmci_t return JNIHandles::make_local(THREAD, result); } else { // do link-time resolution to check all access rules. - LinkInfo link_info(holder_klass, method_name, method_signature, caller_klass); + LinkInfo link_info(holder_klass, method_name, method_signature, caller_klass, true); methodHandle resolved_method = LinkResolver::linktime_resolve_virtual_method_or_null(link_info); if (resolved_method.is_null()) { return NULL; diff --git a/hotspot/src/share/vm/jvmci/jvmciEnv.cpp b/hotspot/src/share/vm/jvmci/jvmciEnv.cpp index 808d4924ea8..348a28601be 100644 --- a/hotspot/src/share/vm/jvmci/jvmciEnv.cpp +++ b/hotspot/src/share/vm/jvmci/jvmciEnv.cpp @@ -282,12 +282,11 @@ methodHandle JVMCIEnv::lookup_method(instanceKlassHandle& h_accessor, instanceKlassHandle& h_holder, Symbol* name, Symbol* sig, - Bytecodes::Code bc, - constantTag tag) { + Bytecodes::Code bc) { JVMCI_EXCEPTION_CONTEXT; LinkResolver::check_klass_accessability(h_accessor, h_holder, KILL_COMPILE_ON_FATAL_(NULL)); methodHandle dest_method; - LinkInfo link_info(h_holder, name, sig, h_accessor, LinkInfo::needs_access_check, tag); + LinkInfo link_info(h_holder, name, sig, h_accessor, /*check_access*/true); switch (bc) { case Bytecodes::_invokestatic: dest_method = @@ -360,8 +359,7 @@ methodHandle JVMCIEnv::get_method_by_index_impl(const constantPoolHandle& cpool, if (holder_is_accessible) { // Our declared holder is loaded. instanceKlassHandle lookup = get_instance_klass_for_declared_method_holder(holder); - constantTag tag = cpool->tag_ref_at(index); - methodHandle m = lookup_method(accessor, lookup, name_sym, sig_sym, bc, tag); + methodHandle m = lookup_method(accessor, lookup, name_sym, sig_sym, bc); if (!m.is_null() && (bc == Bytecodes::_invokestatic ? InstanceKlass::cast(m->method_holder())->is_not_initialized() diff --git a/hotspot/src/share/vm/jvmci/jvmciEnv.hpp b/hotspot/src/share/vm/jvmci/jvmciEnv.hpp index 4f9cf9271b7..f0291efde26 100644 --- a/hotspot/src/share/vm/jvmci/jvmciEnv.hpp +++ b/hotspot/src/share/vm/jvmci/jvmciEnv.hpp @@ -125,8 +125,7 @@ private: instanceKlassHandle& holder, Symbol* name, Symbol* sig, - Bytecodes::Code bc, - constantTag tag); + Bytecodes::Code bc); private: diff --git a/hotspot/src/share/vm/oops/constantPool.cpp b/hotspot/src/share/vm/oops/constantPool.cpp index 9900c45c816..006a1e5b5a6 100644 --- a/hotspot/src/share/vm/oops/constantPool.cpp +++ b/hotspot/src/share/vm/oops/constantPool.cpp @@ -409,19 +409,6 @@ int ConstantPool::impl_name_and_type_ref_index_at(int which, bool uncached) { return extract_high_short_from_int(ref_index); } -constantTag ConstantPool::impl_tag_ref_at(int which, bool uncached) { - int pool_index = which; - if (!uncached && cache() != NULL) { - if (ConstantPool::is_invokedynamic_index(which)) { - // Invokedynamic index is index into resolved_references - pool_index = invokedynamic_cp_cache_entry_at(which)->constant_pool_index(); - } else { - // change byte-ordering and go via cache - pool_index = remap_instruction_operand_from_cache(which); - } - } - return tag_at(pool_index); -} int ConstantPool::impl_klass_ref_index_at(int which, bool uncached) { guarantee(!ConstantPool::is_invokedynamic_index(which), @@ -677,7 +664,6 @@ oop ConstantPool::resolve_constant_at_impl(const constantPoolHandle& this_cp, in int callee_index = this_cp->method_handle_klass_index_at(index); Symbol* name = this_cp->method_handle_name_ref_at(index); Symbol* signature = this_cp->method_handle_signature_ref_at(index); - constantTag m_tag = this_cp->tag_at(this_cp->method_handle_index_at(index)); if (PrintMiscellaneous) tty->print_cr("resolve JVM_CONSTANT_MethodHandle:%d [%d/%d/%d] %s.%s", ref_kind, index, this_cp->method_handle_index_at(index), @@ -686,15 +672,6 @@ oop ConstantPool::resolve_constant_at_impl(const constantPoolHandle& this_cp, in { Klass* k = klass_at_impl(this_cp, callee_index, true, CHECK_NULL); callee = KlassHandle(THREAD, k); } - if ((callee->is_interface() && m_tag.is_method()) || - (!callee->is_interface() && m_tag.is_interface_method())) { - ResourceMark rm(THREAD); - char buf[200]; - jio_snprintf(buf, sizeof(buf), "Inconsistent constant data for %s.%s%s at index %d", - callee->name()->as_C_string(), name->as_C_string(), signature->as_C_string(), index); - THROW_MSG_NULL(vmSymbols::java_lang_IncompatibleClassChangeError(), buf); - } - KlassHandle klass(THREAD, this_cp->pool_holder()); Handle value = SystemDictionary::link_method_handle_constant(klass, ref_kind, callee, name, signature, diff --git a/hotspot/src/share/vm/oops/constantPool.hpp b/hotspot/src/share/vm/oops/constantPool.hpp index 740e9f77bac..99d77253be9 100644 --- a/hotspot/src/share/vm/oops/constantPool.hpp +++ b/hotspot/src/share/vm/oops/constantPool.hpp @@ -664,8 +664,6 @@ class ConstantPool : public Metadata { int remap_instruction_operand_from_cache(int operand); // operand must be biased by CPCACHE_INDEX_TAG - constantTag tag_ref_at(int cp_cache_index) { return impl_tag_ref_at(cp_cache_index, false); } - // Lookup for entries consisting of (name_index, signature_index) int name_ref_index_at(int which_nt); // == low-order jshort of name_and_type_at(which_nt) int signature_ref_index_at(int which_nt); // == high-order jshort of name_and_type_at(which_nt) @@ -786,7 +784,6 @@ class ConstantPool : public Metadata { Symbol* impl_signature_ref_at(int which, bool uncached); int impl_klass_ref_index_at(int which, bool uncached); int impl_name_and_type_ref_index_at(int which, bool uncached); - constantTag impl_tag_ref_at(int which, bool uncached); // Used while constructing constant pool (only by ClassFileParser) jint klass_index_at(int which) { diff --git a/hotspot/src/share/vm/prims/methodHandles.cpp b/hotspot/src/share/vm/prims/methodHandles.cpp index 0a72474dfa3..0f58dde7063 100644 --- a/hotspot/src/share/vm/prims/methodHandles.cpp +++ b/hotspot/src/share/vm/prims/methodHandles.cpp @@ -679,7 +679,7 @@ Handle MethodHandles::resolve_MemberName(Handle mname, KlassHandle caller, TRAPS case IS_METHOD: { CallInfo result; - LinkInfo link_info(defc, name, type, caller); + LinkInfo link_info(defc, name, type, caller, caller.not_null()); { assert(!HAS_PENDING_EXCEPTION, ""); if (ref_kind == JVM_REF_invokeStatic) { @@ -716,7 +716,7 @@ Handle MethodHandles::resolve_MemberName(Handle mname, KlassHandle caller, TRAPS case IS_CONSTRUCTOR: { CallInfo result; - LinkInfo link_info(defc, name, type, caller); + LinkInfo link_info(defc, name, type, caller, caller.not_null()); { assert(!HAS_PENDING_EXCEPTION, ""); if (name == vmSymbols::object_initializer_name()) { @@ -737,7 +737,7 @@ Handle MethodHandles::resolve_MemberName(Handle mname, KlassHandle caller, TRAPS fieldDescriptor result; // find_field initializes fd if found { assert(!HAS_PENDING_EXCEPTION, ""); - LinkInfo link_info(defc, name, type, caller, LinkInfo::skip_access_check); + LinkInfo link_info(defc, name, type, caller, /*check_access*/false); LinkResolver::resolve_field(result, link_info, Bytecodes::_nop, false, THREAD); if (HAS_PENDING_EXCEPTION) { return empty; diff --git a/hotspot/src/share/vm/runtime/javaCalls.cpp b/hotspot/src/share/vm/runtime/javaCalls.cpp index 82cbd26b2d4..9acd0200b29 100644 --- a/hotspot/src/share/vm/runtime/javaCalls.cpp +++ b/hotspot/src/share/vm/runtime/javaCalls.cpp @@ -183,7 +183,7 @@ void JavaCalls::call_virtual(JavaValue* result, KlassHandle spec_klass, Symbol* CallInfo callinfo; Handle receiver = args->receiver(); KlassHandle recvrKlass(THREAD, receiver.is_null() ? (Klass*)NULL : receiver->klass()); - LinkInfo link_info(spec_klass, name, signature); + LinkInfo link_info(spec_klass, name, signature, KlassHandle(), /*check_access*/false); LinkResolver::resolve_virtual_call( callinfo, receiver, recvrKlass, link_info, true, CHECK); methodHandle method = callinfo.selected_method(); @@ -220,7 +220,7 @@ void JavaCalls::call_virtual(JavaValue* result, Handle receiver, KlassHandle spe void JavaCalls::call_special(JavaValue* result, KlassHandle klass, Symbol* name, Symbol* signature, JavaCallArguments* args, TRAPS) { CallInfo callinfo; - LinkInfo link_info(klass, name, signature); + LinkInfo link_info(klass, name, signature, KlassHandle(), /*check_access*/false); LinkResolver::resolve_special_call(callinfo, link_info, CHECK); methodHandle method = callinfo.selected_method(); assert(method.not_null(), "should have thrown exception"); @@ -255,7 +255,7 @@ void JavaCalls::call_special(JavaValue* result, Handle receiver, KlassHandle kla void JavaCalls::call_static(JavaValue* result, KlassHandle klass, Symbol* name, Symbol* signature, JavaCallArguments* args, TRAPS) { CallInfo callinfo; - LinkInfo link_info(klass, name, signature); + LinkInfo link_info(klass, name, signature, KlassHandle(), /*check_access*/false); LinkResolver::resolve_static_call(callinfo, link_info, true, CHECK); methodHandle method = callinfo.selected_method(); assert(method.not_null(), "should have thrown exception"); diff --git a/hotspot/src/share/vm/runtime/reflection.cpp b/hotspot/src/share/vm/runtime/reflection.cpp index d44ce3869fa..45746d67c7c 100644 --- a/hotspot/src/share/vm/runtime/reflection.cpp +++ b/hotspot/src/share/vm/runtime/reflection.cpp @@ -830,7 +830,7 @@ methodHandle Reflection::resolve_interface_call(instanceKlassHandle klass, const Symbol* signature = method->signature(); Symbol* name = method->name(); LinkResolver::resolve_interface_call(info, receiver, recv_klass, - LinkInfo(klass, name, signature), + LinkInfo(klass, name, signature, KlassHandle(), false), true, CHECK_(methodHandle())); return info.selected_method(); diff --git a/hotspot/test/runtime/8087223/BadMethodHandles.java b/hotspot/test/runtime/8087223/BadMethodHandles.java deleted file mode 100644 index 57defac0fe2..00000000000 --- a/hotspot/test/runtime/8087223/BadMethodHandles.java +++ /dev/null @@ -1,250 +0,0 @@ -/* - * 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 8087223 - * @summary Adding constantTag to keep method call consistent with it. - * @compile -XDignore.symbol.file BadMethodHandles.java - * @run main/othervm BadMethodHandles - */ - -import jdk.internal.org.objectweb.asm.*; -import java.io.FileOutputStream; -import java.lang.reflect.InvocationTargetException; -import java.lang.invoke.MethodHandle; -import java.lang.invoke.MethodHandles; -import java.lang.invoke.MethodType; -import static jdk.internal.org.objectweb.asm.Opcodes.*; - -public class BadMethodHandles { - - static byte[] dumpBadInterfaceMethodref() { - ClassWriter cw = new ClassWriter(0); - cw.visit(52, ACC_PUBLIC | ACC_SUPER, "BadInterfaceMethodref", null, "java/lang/Object", null); - Handle handle1 = - new Handle(Opcodes.H_INVOKEINTERFACE, "BadInterfaceMethodref", "m", "()V"); - Handle handle2 = - new Handle(Opcodes.H_INVOKEINTERFACE, "BadInterfaceMethodref", "staticM", "()V"); - - { - MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, "", "()V", null, null); - mv.visitCode(); - mv.visitVarInsn(ALOAD, 0); - mv.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "", "()V", false); - mv.visitInsn(RETURN); - mv.visitMaxs(1, 1); - mv.visitEnd(); - } - { - MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, "m", "()V", null, null); - mv.visitCode(); - mv.visitFieldInsn(GETSTATIC, "java/lang/System", "out", "Ljava/io/PrintStream;"); - mv.visitLdcInsn("hello from m"); - mv.visitMethodInsn(INVOKEVIRTUAL, "java/io/PrintStream", "println", "(Ljava/lang/String;)V", false/*intf*/); - mv.visitInsn(RETURN); - mv.visitMaxs(3, 1); - mv.visitEnd(); - } - { - MethodVisitor mv = cw.visitMethod(ACC_PUBLIC | ACC_STATIC, "staticM", "()V", null, null); - mv.visitCode(); - mv.visitFieldInsn(GETSTATIC, "java/lang/System", "out", "Ljava/io/PrintStream;"); - mv.visitLdcInsn("hello from staticM"); - mv.visitMethodInsn(INVOKEVIRTUAL, "java/io/PrintStream", "println", "(Ljava/lang/String;)V", false/*intf*/); - mv.visitInsn(RETURN); - mv.visitMaxs(3, 1); - mv.visitEnd(); - } - - { - MethodVisitor mv = cw.visitMethod(ACC_PUBLIC | ACC_STATIC, "runm", "()V", null, null); - mv.visitCode(); - // REF_invokeStatic - mv.visitLdcInsn(handle1); - mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/invoke/MethodHandle", "invoke", "()V", false); - mv.visitInsn(RETURN); - mv.visitMaxs(1, 1); - mv.visitEnd(); - } - - { - MethodVisitor mv = cw.visitMethod(ACC_PUBLIC | ACC_STATIC, "runStaticM", "()V", null, null); - mv.visitCode(); - // REF_invokeStatic - mv.visitLdcInsn(handle2); - mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/invoke/MethodHandle", "invoke", "()V", false); - mv.visitInsn(RETURN); - mv.visitMaxs(1, 1); - mv.visitEnd(); - } - - cw.visitEnd(); - return cw.toByteArray(); - } - - static byte[] dumpIBad() { - ClassWriter cw = new ClassWriter(0); - cw.visit(52, ACC_PUBLIC | ACC_ABSTRACT | ACC_INTERFACE, "IBad", null, "java/lang/Object", null); - { - MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, "m", "()V", null, null); - mv.visitCode(); - mv.visitFieldInsn(GETSTATIC, "java/lang/System", "out", "Ljava/io/PrintStream;"); - mv.visitLdcInsn("hello from m"); - mv.visitMethodInsn(INVOKEVIRTUAL, "java/io/PrintStream", "println", "(Ljava/lang/String;)V", false/*intf*/); - mv.visitInsn(RETURN); - mv.visitMaxs(3, 1); - mv.visitEnd(); - } - { - MethodVisitor mv = cw.visitMethod(ACC_PUBLIC | ACC_STATIC, "staticM", "()V", null, null); - mv.visitCode(); - mv.visitFieldInsn(GETSTATIC, "java/lang/System", "out", "Ljava/io/PrintStream;"); - mv.visitLdcInsn("hello from staticM"); - mv.visitMethodInsn(INVOKEVIRTUAL, "java/io/PrintStream", "println", "(Ljava/lang/String;)V", false/*intf*/); - mv.visitInsn(RETURN); - mv.visitMaxs(3, 1); - mv.visitEnd(); - } - cw.visitEnd(); - return cw.toByteArray(); - } - - static byte[] dumpBadMethodref() { - ClassWriter cw = new ClassWriter(0); - cw.visit(52, ACC_PUBLIC | ACC_SUPER, "BadMethodref", null, "java/lang/Object", new String[]{"IBad"}); - Handle handle1 = - new Handle(Opcodes.H_INVOKEINTERFACE, "BadMethodref", "m", "()V"); - Handle handle2 = - new Handle(Opcodes.H_INVOKEINTERFACE, "BadMethodref", "staticM", "()V"); - - { - MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, "", "()V", null, null); - mv.visitCode(); - mv.visitVarInsn(ALOAD, 0); - mv.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "", "()V", false); - mv.visitInsn(RETURN); - mv.visitMaxs(1, 1); - mv.visitEnd(); - } - - { - MethodVisitor mv = cw.visitMethod(ACC_PUBLIC | ACC_STATIC, "runm", "()V", null, null); - mv.visitCode(); - // REF_invokeStatic - mv.visitLdcInsn(handle1); - mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/invoke/MethodHandle", "invoke", "()V", false); - mv.visitInsn(RETURN); - mv.visitMaxs(1, 1); - mv.visitEnd(); - } - - { - MethodVisitor mv = cw.visitMethod(ACC_PUBLIC | ACC_STATIC, "runStaticM", "()V", null, null); - mv.visitCode(); - // REF_invokeStatic - mv.visitLdcInsn(handle2); - mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/invoke/MethodHandle", "invoke", "()V", false); - mv.visitInsn(RETURN); - mv.visitMaxs(1, 1); - mv.visitEnd(); - } - - cw.visitEnd(); - return cw.toByteArray(); - } - static class CL extends ClassLoader { - @Override - protected Class findClass(String name) throws ClassNotFoundException { - byte[] classBytes = null; - switch (name) { - case "BadInterfaceMethodref": classBytes = dumpBadInterfaceMethodref(); break; - case "BadMethodref" : classBytes = dumpBadMethodref(); break; - case "IBad" : classBytes = dumpIBad(); break; - default : throw new ClassNotFoundException(name); - } - return defineClass(name, classBytes, 0, classBytes.length); - } - } - - public static void main(String[] args) throws Throwable { - try (FileOutputStream fos = new FileOutputStream("BadInterfaceMethodref.class")) { - fos.write(dumpBadInterfaceMethodref()); - } - try (FileOutputStream fos = new FileOutputStream("IBad.class")) { - fos.write(dumpIBad()); - } - try (FileOutputStream fos = new FileOutputStream("BadMethodref.class")) { - fos.write(dumpBadMethodref()); - } - - Class cls = (new CL()).loadClass("BadInterfaceMethodref"); - String[] methods = {"runm", "runStaticM"}; - System.out.println("Test BadInterfaceMethodref:"); - int success = 0; - for (String name : methods) { - try { - System.out.printf("invoke %s: \n", name); - cls.getMethod(name).invoke(cls.newInstance()); - System.out.println("FAILED (no exception)"); // ICCE should be thrown - } catch (Throwable e) { - if (e instanceof InvocationTargetException && e.getCause() != null && - e.getCause() instanceof IncompatibleClassChangeError) { - System.out.println("PASSED"); - success++; - continue; - } else { - System.out.println("FAILED with exception"); - throw e; - } - } - } - if (success != methods.length) { - throw new Exception("BadInterfaceMethodRef Failed to catch IncompatibleClassChangeError"); - } - System.out.println("Test BadMethodref:"); - cls = (new CL()).loadClass("BadMethodref"); - success = 0; - for (String name : methods) { - try { - System.out.printf("invoke %s: \n", name); - cls.getMethod(name).invoke(cls.newInstance()); - System.out.println("FAILED (no exception)"); // ICCE should be thrown - } catch (Throwable e) { - if (e instanceof InvocationTargetException && e.getCause() != null && - e.getCause() instanceof IncompatibleClassChangeError) { - System.out.println("PASSED"); - success++; - continue; - } else { - System.out.println("FAILED with exception"); - throw e; - } - } - } - if (success != methods.length) { - throw new Exception("BadMethodRef Failed to catch IncompatibleClassChangeError"); - } - - } -} diff --git a/hotspot/test/runtime/8087223/IntfMethod.java b/hotspot/test/runtime/8087223/IntfMethod.java deleted file mode 100644 index a3a4ee3b8d8..00000000000 --- a/hotspot/test/runtime/8087223/IntfMethod.java +++ /dev/null @@ -1,156 +0,0 @@ -/* - * 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 8087223 - * @summary Adding constantTag to keep method call consistent with it. - * @compile -XDignore.symbol.file IntfMethod.java - * @run main/othervm IntfMethod - * @run main/othervm -Xint IntfMethod - * @run main/othervm -Xcomp IntfMethod - */ - - -import jdk.internal.org.objectweb.asm.*; -import java.io.FileOutputStream; -import java.lang.reflect.InvocationTargetException; -import static jdk.internal.org.objectweb.asm.Opcodes.*; - -public class IntfMethod { - static byte[] dumpC() { - ClassWriter cw = new ClassWriter(0); - cw.visit(52, ACC_PUBLIC | ACC_SUPER, "C", null, "java/lang/Object", new String[]{"I"}); - { - MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, "", "()V", null, null); - mv.visitCode(); - mv.visitVarInsn(ALOAD, 0); - mv.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "", "()V", false); - mv.visitInsn(RETURN); - mv.visitMaxs(1, 1); - mv.visitEnd(); - } - { - MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, "testSpecialIntf", "()V", null, null); - mv.visitCode(); - mv.visitVarInsn(ALOAD, 0); - mv.visitMethodInsn(INVOKESPECIAL, "I", "f1", "()V", /*itf=*/false); - mv.visitInsn(RETURN); - mv.visitMaxs(1, 1); - mv.visitEnd(); - } - { - MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, "testStaticIntf", "()V", null, null); - mv.visitCode(); - mv.visitMethodInsn(INVOKESTATIC, "I", "f2", "()V", /*itf=*/false); - mv.visitInsn(RETURN); - mv.visitMaxs(1, 1); - mv.visitEnd(); - } - { - MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, "testSpecialClass", "()V", null, null); - mv.visitCode(); - mv.visitVarInsn(ALOAD, 0); - mv.visitMethodInsn(INVOKESPECIAL, "C", "f1", "()V", /*itf=*/true); - mv.visitInsn(RETURN); - mv.visitMaxs(1, 1); - mv.visitEnd(); - } - - { - MethodVisitor mv = cw.visitMethod(ACC_PUBLIC | ACC_STATIC, "f2", "()V", null, null); - mv.visitCode(); - mv.visitInsn(RETURN); - mv.visitMaxs(0, 1); - mv.visitEnd(); - } - { - MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, "testStaticClass", "()V", null, null); - mv.visitCode(); - mv.visitMethodInsn(INVOKESTATIC, "C", "f2", "()V", /*itf=*/true); - mv.visitInsn(RETURN); - mv.visitMaxs(1, 1); - mv.visitEnd(); - } - cw.visitEnd(); - return cw.toByteArray(); - } - - static byte[] dumpI() { - ClassWriter cw = new ClassWriter(0); - cw.visit(52, ACC_PUBLIC | ACC_ABSTRACT | ACC_INTERFACE, "I", null, "java/lang/Object", null); - { - MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, "f1", "()V", null, null); - mv.visitCode(); - mv.visitInsn(RETURN); - mv.visitMaxs(0, 1); - mv.visitEnd(); - } - { - MethodVisitor mv = cw.visitMethod(ACC_PUBLIC | ACC_STATIC, "f2", "()V", null, null); - mv.visitCode(); - mv.visitInsn(RETURN); - mv.visitMaxs(0, 1); - mv.visitEnd(); - } - cw.visitEnd(); - return cw.toByteArray(); - } - - static class CL extends ClassLoader { - @Override - protected Class findClass(String name) throws ClassNotFoundException { - byte[] classFile; - switch (name) { - case "I": classFile = dumpI(); break; - case "C": classFile = dumpC(); break; - default: - throw new ClassNotFoundException(name); - } - return defineClass(name, classFile, 0, classFile.length); - } - } - - public static void main(String[] args) throws Throwable { - Class cls = (new CL()).loadClass("C"); - try (FileOutputStream fos = new FileOutputStream("I.class")) { fos.write(dumpI()); } - try (FileOutputStream fos = new FileOutputStream("C.class")) { fos.write(dumpC()); } - - int success = 0; - for (String name : new String[] { "testSpecialIntf", "testStaticIntf", "testSpecialClass", "testStaticClass"}) { - System.out.printf("%s: ", name); - try { - cls.getMethod(name).invoke(cls.newInstance()); - System.out.println("FAILED"); - } catch (Throwable e) { - if (e instanceof InvocationTargetException && - e.getCause() != null && e.getCause() instanceof IncompatibleClassChangeError) { - System.out.println("PASSED"); - success++; - continue; - } - } - } - if (success != 4) throw new Exception("Failed to catch ICCE"); - } -}