8303805: [REDO] JDK-8302189 and JDK-8302799

Reviewed-by: dholmes, coleenp
This commit is contained in:
Kim Barrett 2023-03-29 23:45:03 +00:00
parent b524a74165
commit b3ff8d1c89
12 changed files with 213 additions and 52 deletions

View File

@ -100,7 +100,7 @@ endif
DISABLED_WARNINGS_xlc := tautological-compare shift-negative-value
DISABLED_WARNINGS_microsoft := 4624 4244 4291 4146 4127
DISABLED_WARNINGS_microsoft := 4624 4244 4291 4146 4127 4722
################################################################################
# Platform specific setup

View File

@ -42,7 +42,6 @@
#include "oops/klass.inline.hpp"
#include "prims/methodHandles.hpp"
#include "runtime/continuation.hpp"
#include "runtime/flags/flagSetting.hpp"
#include "runtime/interfaceSupport.inline.hpp"
#include "runtime/javaThread.hpp"
#include "runtime/jniHandles.hpp"
@ -403,7 +402,7 @@ void MacroAssembler::debug32(int rdi, int rsi, int rbp, int rsp, int rbx, int rd
void MacroAssembler::print_state32(int rdi, int rsi, int rbp, int rsp, int rbx, int rdx, int rcx, int rax, int eip) {
ttyLocker ttyl;
FlagSetting fs(Debugging, true);
DebuggingContext debugging{};
tty->print_cr("eip = 0x%08x", eip);
#ifndef PRODUCT
if ((WizardMode || Verbose) && PrintMiscellaneous) {
@ -832,7 +831,7 @@ void MacroAssembler::debug64(char* msg, int64_t pc, int64_t regs[]) {
void MacroAssembler::print_state64(int64_t pc, int64_t regs[]) {
ttyLocker ttyl;
FlagSetting fs(Debugging, true);
DebuggingContext debugging{};
tty->print_cr("rip = 0x%016lx", (intptr_t)pc);
#ifndef PRODUCT
tty->cr();

View File

@ -628,7 +628,9 @@ HeapWord* ParallelScavengeHeap::block_start(const void* addr) const {
assert(young_gen()->is_in(addr),
"addr should be in allocated part of young gen");
// called from os::print_location by find or VMError
if (Debugging || VMError::is_error_reported()) return nullptr;
if (DebuggingContext::is_enabled() || VMError::is_error_reported()) {
return nullptr;
}
Unimplemented();
} else if (old_gen()->is_in_reserved(addr)) {
assert(old_gen()->is_in(addr),

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2017, 2022, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2017, 2023, 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
@ -209,7 +209,7 @@ namespace AccessInternal {
#ifdef ASSERT
void check_access_thread_state() {
if (VMError::is_error_reported() || Debugging) {
if (VMError::is_error_reported() || DebuggingContext::is_enabled()) {
return;
}

View File

@ -376,6 +376,9 @@ void JavaThread::check_possible_safepoint() {
}
void JavaThread::check_for_valid_safepoint_state() {
// Don't complain if running a debugging command.
if (DebuggingContext::is_enabled()) return;
// Check NoSafepointVerifier, which is implied by locks taken that can be
// shared with the VM thread. This makes sure that no locks with allow_vm_block
// are held.

View File

@ -165,6 +165,7 @@ static int _num_mutex;
#ifdef ASSERT
void assert_locked_or_safepoint(const Mutex* lock) {
if (DebuggingContext::is_enabled()) return;
// check if this thread owns the lock (common case)
assert(lock != nullptr, "Need non-null lock");
if (lock->owned_by_self()) return;
@ -175,6 +176,7 @@ void assert_locked_or_safepoint(const Mutex* lock) {
// a weaker assertion than the above
void assert_locked_or_safepoint_weak(const Mutex* lock) {
if (DebuggingContext::is_enabled()) return;
assert(lock != nullptr, "Need non-null lock");
if (lock->is_locked()) return;
if (SafepointSynchronize::is_at_safepoint()) return;
@ -184,6 +186,7 @@ void assert_locked_or_safepoint_weak(const Mutex* lock) {
// a stronger assertion than the above
void assert_lock_strong(const Mutex* lock) {
if (DebuggingContext::is_enabled()) return;
assert(lock != nullptr, "Need non-null lock");
if (lock->owned_by_self()) return;
fatal("must own lock %s", lock->name());

View File

@ -576,7 +576,7 @@ class os: AllStatic {
// multiple calls to naked_short_sleep. Only for use by non-JavaThreads.
static void naked_sleep(jlong millis);
// Never returns, use with CAUTION
[[noreturn]] static void infinite_sleep();
ATTRIBUTE_NORETURN static void infinite_sleep();
static void naked_yield () ;
static OSReturn set_priority(Thread* thread, ThreadPriority priority);
static OSReturn get_priority(const Thread* const thread, ThreadPriority& priority);
@ -601,26 +601,26 @@ class os: AllStatic {
static int fork_and_exec(const char *cmd);
// Call ::exit() on all platforms
[[noreturn]] static void exit(int num);
ATTRIBUTE_NORETURN static void exit(int num);
// Call ::_exit() on all platforms. Similar semantics to die() except we never
// want a core dump.
[[noreturn]] static void _exit(int num);
ATTRIBUTE_NORETURN static void _exit(int num);
// Terminate the VM, but don't exit the process
static void shutdown();
// Terminate with an error. Default is to generate a core file on platforms
// that support such things. This calls shutdown() and then aborts.
[[noreturn]] static void abort(bool dump_core, void *siginfo, const void *context);
[[noreturn]] static void abort(bool dump_core = true);
ATTRIBUTE_NORETURN static void abort(bool dump_core, void *siginfo, const void *context);
ATTRIBUTE_NORETURN static void abort(bool dump_core = true);
// Die immediately, no exit hook, no abort hook, no cleanup.
// Dump a core file, if possible, for debugging. os::abort() is the
// preferred means to abort the VM on error. os::die() should only
// be called if something has gone badly wrong. CreateCoredumpOnCrash
// is intentionally not honored by this function.
[[noreturn]] static void die();
ATTRIBUTE_NORETURN static void die();
// File i/o operations
static int open(const char *path, int oflag, int mode);

View File

@ -0,0 +1,50 @@
/*
* Copyright (c) 2023, 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_UTILITY_ATTRIBUTENORETURN_HPP
#define SHARE_UTILITY_ATTRIBUTENORETURN_HPP
// Provide a (temporary) macro for the [[noreturn]] attribute.
//
// Unfortunately, some older (though still in use) compilers have bugs when
// using [[noreturn]]. For them we use an empty definition for the attribute.
//
// Note: This can't be placed in globalDefinitions_xxx.hpp because the
// attribute is used in debug.hpp, which can't include globalDefinitions.hpp.
// clang 12 (and possibly prior) crashes during build if we use [[noreturn]]
// for assertion failure reporting functions. The problem seems to be fixed
// in clang 13.
#ifdef __clang__
#if __clang_major__ < 13
#define ATTRIBUTE_NORETURN
#endif
#endif
// All other platforms can use [[noreturn]].
#ifndef ATTRIBUTE_NORETURN
#define ATTRIBUTE_NORETURN [[noreturn]]
#endif
#endif // SHARE_UTILITY_ATTRIBUTENORETURN_HPP

View File

@ -76,8 +76,19 @@ static intx g_asserting_thread = 0;
static void* g_assertion_context = nullptr;
#endif // CAN_SHOW_REGISTERS_ON_ASSERT
// Set to suppress secondary error reporting.
bool Debugging = false;
int DebuggingContext::_enabled = 0; // Initially disabled.
DebuggingContext::DebuggingContext() {
_enabled += 1; // Increase nesting count.
}
DebuggingContext::~DebuggingContext() {
if (is_enabled()) {
_enabled -= 1; // Decrease nesting count.
} else {
fatal("Debugging nesting confusion");
}
}
#ifndef ASSERT
# ifdef _DEBUG
@ -166,7 +177,6 @@ static void print_error_for_unit_test(const char* message, const char* detail_fm
void report_vm_error(const char* file, int line, const char* error_msg, const char* detail_fmt, ...)
{
if (Debugging) return;
va_list detail_args;
va_start(detail_args, detail_fmt);
void* context = nullptr;
@ -188,7 +198,6 @@ void report_vm_status_error(const char* file, int line, const char* error_msg,
}
void report_fatal(VMErrorType error_type, const char* file, int line, const char* detail_fmt, ...) {
if (Debugging) return;
va_list detail_args;
va_start(detail_args, detail_fmt);
void* context = nullptr;
@ -208,7 +217,6 @@ void report_fatal(VMErrorType error_type, const char* file, int line, const char
void report_vm_out_of_memory(const char* file, int line, size_t size,
VMErrorType vm_err_type, const char* detail_fmt, ...) {
if (Debugging) return;
va_list detail_args;
va_start(detail_args, detail_fmt);
@ -278,13 +286,11 @@ void report_java_out_of_memory(const char* message) {
class Command : public StackObj {
private:
ResourceMark rm;
bool debug_save;
ResourceMark _rm;
DebuggingContext _debugging;
public:
static int level;
Command(const char* str) {
debug_save = Debugging;
Debugging = true;
if (level++ > 0) return;
tty->cr();
tty->print_cr("\"Executing %s\"", str);
@ -292,7 +298,6 @@ class Command : public StackObj {
~Command() {
tty->flush();
Debugging = debug_save;
level--;
}
};

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 1997, 2022, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1997, 2023, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -25,6 +25,7 @@
#ifndef SHARE_UTILITIES_DEBUG_HPP
#define SHARE_UTILITIES_DEBUG_HPP
#include "utilities/attributeNoreturn.hpp"
#include "utilities/breakpoint.hpp"
#include "utilities/compilerWarnings.hpp"
#include "utilities/macros.hpp"
@ -46,6 +47,98 @@ bool handle_assert_poison_fault(const void* ucVoid, const void* faulting_address
#define TOUCH_ASSERT_POISON
#endif // CAN_SHOW_REGISTERS_ON_ASSERT
// The DebuggingContext class provides a mechanism for temporarily disabling
// asserts and various consistency checks. Ordinarily that would be a really
// bad idea, but it's essential for some of the debugging commands provided by
// HotSpot. (See the Command class in debug.cpp.) These commands are intended
// to be invoked from the debugger while the program is otherwise stopped.
// The commands may invoke operations while the program is in a state where
// those operations are not normally permitted, with the state checked by an
// assert. We want the debugging commands to bypass those checks.
class DebuggingContext {
static int _enabled; // Nesting counter.
public:
DebuggingContext();
~DebuggingContext();
// Asserts and other code use this to determine whether to bypass checks
// that would otherwise lead to program termination.
static bool is_enabled() { return _enabled > 0; }
};
// VMASSERT_CHECK_PASSED(P) provides the mechanism by which DebuggingContext
// disables asserts. It returns true if P is true or DebuggingContext is
// enabled. Assertion failure is reported if it returns false, terminating
// the program.
//
// The DebuggingContext check being enabled isn't placed inside the report
// function, as that would prevent the report function from being noreturn.
// The report function should be noreturn so there isn't a control path to the
// assertion's continuation that has P being false. Otherwise, the compiler
// might logically split the continuation to include that path explicitly,
// possibly leading to discovering (and warning about) invalid code. For
// example, if P := x != nullptr, and the continuation contains a dereference
// of x, the compiler might warn because there is a control path (!P -> report
// -> continuation) where that dereference is known to be invalid. (Of
// course, if execution actually took that path things would go wrong, but
// that's the risk the DebuggingContext mechanism takes.)
//
// Similarly, the check for enabled DebuggingContext shouldn't follow P.
// Having this macro expand to `P || DebuggingContext::is_enabled()` has the
// same problem of a control path through !P to the assertion's continuation.
//
// But it can't be just `DebuggingContext::is_enabled() || P` either. That
// prevents the compiler from inferring based on P that it is true in the
// continuation. But it also prevents the use of assertions in constexpr
// contexts, since that expression is not constexpr.
//
// We could accomodate constexpr usage with std::is_constant_evaluated() (from
// C++20). Unfortunately, we don't currently support C++20. However, most
// supported compilers have implemented it, and that implementation uses a
// compiler intrinsic that we can use directly without otherwise using C++20.
//
// Note that if we could use std::is_constant_evaluated() then we could just
// use this definition for DebuggingContext::is_enabled:
// static constexpr bool is_enabled() {
// return !std::is_constant_evaluated() && _enabled;
// }
// The idea being that we are definitely not executing for debugging if doing
// constant evaluation in the compiler. We don't do something like that now,
// because we need a fallback when we don't have any mechanism for detecting
// constant evaluation.
#if defined(TARGET_COMPILER_gcc) || defined(TARGET_COMPILER_xlc)
// gcc10 added both __has_builtin and __builtin_is_constant_evaluated.
// clang has had __has_builtin for a long time, so likely also in xlclang++.
// Similarly, clang has had __builtin_is_constant_evaluated for a long time.
#ifdef __has_builtin
#if __has_builtin(__builtin_is_constant_evaluated)
#define VMASSERT_CHECK_PASSED(p) \
((! __builtin_is_constant_evaluated() && DebuggingContext::is_enabled()) || (p))
#endif
#endif
#elif defined(TARGET_COMPILER_visCPP)
// std::is_constant_evaluated() and it's associated intrinsic are available in
// VS 2019 16.5. The minimum supported version of VS 2019 is already past
// that, so we can rely on the intrinsic being available.
#define VMASSERT_CHECK_PASSED(p) \
((! __builtin_is_constant_evaluated() && DebuggingContext::is_enabled()) || (p))
#endif // End dispatch on TARGET_COMPILER_xxx
// If we don't have a way to detect constant evaluation, then fall back to the
// less than ideal form of the check, and hope it works. This succeeds at
// least for gcc. The support needed to use the above definition was added in
// gcc10. The problems arising from analyzing the failed P case don't seem to
// appear until gcc12. An alternative is to not provide DebuggingContext
// support for such a configuration.
#ifndef VMASSERT_CHECK_PASSED
#define VMASSERT_CHECK_PASSED(p) ((p) || DebuggingContext::is_enabled())
#endif
// assertions
#ifndef ASSERT
#define vmassert(p, ...)
@ -56,10 +149,9 @@ bool handle_assert_poison_fault(const void* ucVoid, const void* faulting_address
// compiler can't handle an empty ellipsis in a macro without a warning.
#define vmassert(p, ...) \
do { \
if (!(p)) { \
if (! VMASSERT_CHECK_PASSED(p)) { \
TOUCH_ASSERT_POISON; \
report_vm_error(__FILE__, __LINE__, "assert(" #p ") failed", __VA_ARGS__); \
BREAKPOINT; \
} \
} while (0)
#endif
@ -82,14 +174,13 @@ do { \
// like "Invalid argument", "out of memory" etc
#define vmassert_status(p, status, msg) \
do { \
if (!(p)) { \
if (! VMASSERT_CHECK_PASSED(p)) { \
TOUCH_ASSERT_POISON; \
report_vm_status_error(__FILE__, __LINE__, "assert(" #p ") failed", \
status, msg); \
BREAKPOINT; \
} \
} while (0)
#endif
#endif // ASSERT
// For backward compatibility.
#define assert_status(p, status, msg) vmassert_status(p, status, msg)
@ -97,12 +188,12 @@ do { \
// guarantee is like vmassert except it's always executed -- use it for
// cheap tests that catch errors that would otherwise be hard to find.
// guarantee is also used for Verify options.
// guarantee is not subject to DebuggingContext bypass.
#define guarantee(p, ...) \
do { \
if (!(p)) { \
TOUCH_ASSERT_POISON; \
report_vm_error(__FILE__, __LINE__, "guarantee(" #p ") failed", __VA_ARGS__); \
BREAKPOINT; \
} \
} while (0)
@ -110,35 +201,30 @@ do {
do { \
TOUCH_ASSERT_POISON; \
report_fatal(INTERNAL_ERROR, __FILE__, __LINE__, __VA_ARGS__); \
BREAKPOINT; \
} while (0)
// out of memory
#define vm_exit_out_of_memory(size, vm_err_type, ...) \
do { \
report_vm_out_of_memory(__FILE__, __LINE__, size, vm_err_type, __VA_ARGS__); \
BREAKPOINT; \
} while (0)
#define ShouldNotCallThis() \
do { \
TOUCH_ASSERT_POISON; \
report_should_not_call(__FILE__, __LINE__); \
BREAKPOINT; \
} while (0)
#define ShouldNotReachHere() \
do { \
TOUCH_ASSERT_POISON; \
report_should_not_reach_here(__FILE__, __LINE__); \
BREAKPOINT; \
} while (0)
#define Unimplemented() \
do { \
TOUCH_ASSERT_POISON; \
report_unimplemented(__FILE__, __LINE__); \
BREAKPOINT; \
} while (0)
#define Untested(msg) \
@ -157,25 +243,37 @@ enum VMErrorType {
OOM_JAVA_HEAP_FATAL = 0xe0000004
};
// Set to suppress secondary error reporting.
// Really should have a qualified name or something.
extern bool Debugging;
// error reporting helper functions
ATTRIBUTE_NORETURN
void report_vm_error(const char* file, int line, const char* error_msg);
ATTRIBUTE_NORETURN
ATTRIBUTE_PRINTF(4, 5)
void report_vm_error(const char* file, int line, const char* error_msg,
const char* detail_fmt, ...) ATTRIBUTE_PRINTF(4, 5);
const char* detail_fmt, ...);
ATTRIBUTE_NORETURN
void report_vm_status_error(const char* file, int line, const char* error_msg,
int status, const char* detail);
void report_fatal(VMErrorType error_type, const char* file, int line, const char* detail_fmt, ...) ATTRIBUTE_PRINTF(4, 5);
ATTRIBUTE_NORETURN
ATTRIBUTE_PRINTF(4, 5)
void report_fatal(VMErrorType error_type, const char* file, int line, const char* detail_fmt, ...);
ATTRIBUTE_NORETURN
ATTRIBUTE_PRINTF(5, 6)
void report_vm_out_of_memory(const char* file, int line, size_t size, VMErrorType vm_err_type,
const char* detail_fmt, ...) ATTRIBUTE_PRINTF(5, 6);
void report_should_not_call(const char* file, int line);
void report_should_not_reach_here(const char* file, int line);
void report_unimplemented(const char* file, int line);
const char* detail_fmt, ...);
ATTRIBUTE_NORETURN void report_should_not_call(const char* file, int line);
ATTRIBUTE_NORETURN void report_should_not_reach_here(const char* file, int line);
ATTRIBUTE_NORETURN void report_unimplemented(const char* file, int line);
// NOT ATTRIBUTE_NORETURN
void report_untested(const char* file, int line, const char* message);
void warning(const char* format, ...) ATTRIBUTE_PRINTF(1, 2);
ATTRIBUTE_PRINTF(1, 2)
void warning(const char* format, ...);
#define STATIC_ASSERT(Cond) static_assert((Cond), #Cond)

View File

@ -25,6 +25,7 @@
#ifndef SHARE_UTILITIES_GLOBALDEFINITIONS_HPP
#define SHARE_UTILITIES_GLOBALDEFINITIONS_HPP
#include "utilities/attributeNoreturn.hpp"
#include "utilities/compilerWarnings.hpp"
#include "utilities/debug.hpp"
#include "utilities/macros.hpp"

View File

@ -136,7 +136,7 @@ class VMError : public AllStatic {
static jlong get_step_start_time();
static void clear_step_start_time();
WINDOWS_ONLY([[noreturn]] static void raise_fail_fast(void* exrecord, void* context);)
WINDOWS_ONLY(ATTRIBUTE_NORETURN static void raise_fail_fast(void* exrecord, void* context);)
public:
@ -156,27 +156,27 @@ public:
static void print_vm_info(outputStream* st);
// main error reporting function
[[noreturn]]
ATTRIBUTE_NORETURN
ATTRIBUTE_PRINTF(6, 7)
static void report_and_die(Thread* thread, unsigned int sig, address pc, void* siginfo,
void* context, const char* detail_fmt, ...);
[[noreturn]]
ATTRIBUTE_NORETURN
ATTRIBUTE_PRINTF(3, 0)
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,
const char* filename, int lineno, size_t size);
[[noreturn]]
ATTRIBUTE_NORETURN
static void report_and_die(Thread* thread, unsigned int sig, address pc,
void* siginfo, void* context);
[[noreturn]]
ATTRIBUTE_NORETURN
ATTRIBUTE_PRINTF(6, 0)
static void report_and_die(Thread* thread, void* context, const char* filename, int lineno, const char* message,
const char* detail_fmt, va_list detail_args);
[[noreturn]]
ATTRIBUTE_NORETURN
ATTRIBUTE_PRINTF(6, 0)
static void report_and_die(Thread* thread, const char* filename, int lineno, size_t size,
VMErrorType vm_err_type, const char* detail_fmt,