Merge
This commit is contained in:
commit
381021aebf
src
hotspot/share
c1
ci
gc
jfr/support
jfrAllocationTracer.cppjfrAllocationTracer.hppjfrObjectAllocationSample.cppjfrObjectAllocationSample.hpp
jvmci
memory
oops
prims
runtime
java.base/share/classes/java
java.compiler/share/classes/javax
annotation/processing
lang/model
test
hotspot
jdk/java
lang/reflect/records
util/concurrent/CompletableFuture
langtools/jdk/javadoc/doclet/testHtmlTableTags
@ -539,6 +539,20 @@ JRT_ENTRY_NO_ASYNC(static address, exception_handler_for_pc_helper(JavaThread* t
|
||||
}
|
||||
#endif
|
||||
|
||||
// debugging support
|
||||
// tracing
|
||||
if (log_is_enabled(Info, exceptions)) {
|
||||
ResourceMark rm;
|
||||
stringStream tempst;
|
||||
assert(nm->method() != NULL, "Unexpected NULL method()");
|
||||
tempst.print("C1 compiled method <%s>\n"
|
||||
" at PC" INTPTR_FORMAT " for thread " INTPTR_FORMAT,
|
||||
nm->method()->print_value_string(), p2i(pc), p2i(thread));
|
||||
Exceptions::log_exception(exception, tempst.as_string());
|
||||
}
|
||||
// for AbortVMOnException flag
|
||||
Exceptions::debug_check_abort(exception);
|
||||
|
||||
// Check the stack guard pages and reenable them if necessary and there is
|
||||
// enough space on the stack to do so. Use fast exceptions only if the guard
|
||||
// pages are enabled.
|
||||
@ -585,20 +599,6 @@ JRT_ENTRY_NO_ASYNC(static address, exception_handler_for_pc_helper(JavaThread* t
|
||||
// New exception handling mechanism can support inlined methods
|
||||
// with exception handlers since the mappings are from PC to PC
|
||||
|
||||
// debugging support
|
||||
// tracing
|
||||
if (log_is_enabled(Info, exceptions)) {
|
||||
ResourceMark rm;
|
||||
stringStream tempst;
|
||||
assert(nm->method() != NULL, "Unexpected NULL method()");
|
||||
tempst.print("compiled method <%s>\n"
|
||||
" at PC" INTPTR_FORMAT " for thread " INTPTR_FORMAT,
|
||||
nm->method()->print_value_string(), p2i(pc), p2i(thread));
|
||||
Exceptions::log_exception(exception, tempst.as_string());
|
||||
}
|
||||
// for AbortVMOnException flag
|
||||
Exceptions::debug_check_abort(exception);
|
||||
|
||||
// Clear out the exception oop and pc since looking up an
|
||||
// exception handler can cause class loading, which might throw an
|
||||
// exception and those fields are expected to be clear during
|
||||
|
@ -47,6 +47,7 @@ ciMethodData::ciMethodData(MethodData* md)
|
||||
_saw_free_extra_data(false),
|
||||
// Initialize the escape information (to "don't know.");
|
||||
_eflags(0), _arg_local(0), _arg_stack(0), _arg_returned(0),
|
||||
_creation_mileage(0),
|
||||
_current_mileage(0),
|
||||
_invocation_counter(0),
|
||||
_backedge_counter(0),
|
||||
@ -242,6 +243,7 @@ void ciMethodData::load_data() {
|
||||
load_remaining_extra_data();
|
||||
|
||||
// Note: Extra data are all BitData, and do not need translation.
|
||||
_creation_mileage = mdo->creation_mileage();
|
||||
_current_mileage = MethodData::mileage_of(mdo->method());
|
||||
_invocation_counter = mdo->invocation_count();
|
||||
_backedge_counter = mdo->backedge_count();
|
||||
|
@ -395,6 +395,8 @@ private:
|
||||
intx _arg_stack; // bit set of stack-allocatable arguments
|
||||
intx _arg_returned; // bit set of returned arguments
|
||||
|
||||
int _creation_mileage; // method mileage at MDO creation
|
||||
|
||||
// Maturity of the oop when the snapshot is taken.
|
||||
int _current_mileage;
|
||||
|
||||
@ -475,7 +477,7 @@ public:
|
||||
bool is_empty() { return _state == empty_state; }
|
||||
bool is_mature() { return _state == mature_state; }
|
||||
|
||||
int creation_mileage() { return _orig.creation_mileage(); }
|
||||
int creation_mileage() { return _creation_mileage; }
|
||||
int current_mileage() { return _current_mileage; }
|
||||
|
||||
int invocation_count() { return _invocation_counter; }
|
||||
|
@ -472,6 +472,7 @@ bool G1HeapVerifier::should_verify(G1VerifyType type) {
|
||||
|
||||
void G1HeapVerifier::verify(VerifyOption vo) {
|
||||
assert_at_safepoint_on_vm_thread();
|
||||
assert(Heap_lock->is_locked(), "heap must be locked");
|
||||
|
||||
log_debug(gc, verify)("Roots");
|
||||
VerifyRootsClosure rootsCl(vo);
|
||||
|
@ -24,7 +24,6 @@
|
||||
|
||||
#include "precompiled.hpp"
|
||||
#include "gc/shared/allocTracer.hpp"
|
||||
#include "gc/shared/threadLocalAllocBuffer.inline.hpp"
|
||||
#include "jfr/jfrEvents.hpp"
|
||||
#include "utilities/globalDefinitions.hpp"
|
||||
#include "utilities/macros.hpp"
|
||||
@ -32,91 +31,18 @@
|
||||
#include "jfr/support/jfrAllocationTracer.hpp"
|
||||
#endif
|
||||
|
||||
static THREAD_LOCAL int64_t _last_allocated_bytes = 0;
|
||||
|
||||
inline void send_allocation_sample(const Klass* klass, int64_t allocated_bytes) {
|
||||
assert(allocated_bytes > 0, "invariant");
|
||||
EventObjectAllocationSample event;
|
||||
if (event.should_commit()) {
|
||||
const size_t weight = allocated_bytes - _last_allocated_bytes;
|
||||
assert(weight > 0, "invariant");
|
||||
event.set_objectClass(klass);
|
||||
event.set_weight(weight);
|
||||
event.commit();
|
||||
_last_allocated_bytes = allocated_bytes;
|
||||
}
|
||||
}
|
||||
|
||||
inline bool send_allocation_sample_with_result(const Klass* klass, int64_t allocated_bytes) {
|
||||
assert(allocated_bytes > 0, "invariant");
|
||||
EventObjectAllocationSample event;
|
||||
if (event.should_commit()) {
|
||||
const size_t weight = allocated_bytes - _last_allocated_bytes;
|
||||
assert(weight > 0, "invariant");
|
||||
event.set_objectClass(klass);
|
||||
event.set_weight(weight);
|
||||
event.commit();
|
||||
_last_allocated_bytes = allocated_bytes;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
inline intptr_t estimate_tlab_size_bytes(Thread* thread) {
|
||||
assert(thread != NULL, "invariant");
|
||||
const size_t desired_tlab_size_bytes = thread->tlab().desired_size() * HeapWordSize;
|
||||
const size_t alignment_reserve_bytes = thread->tlab().alignment_reserve_in_bytes();
|
||||
assert(desired_tlab_size_bytes > alignment_reserve_bytes, "invariant");
|
||||
return static_cast<intptr_t>(desired_tlab_size_bytes - alignment_reserve_bytes);
|
||||
}
|
||||
|
||||
inline int64_t load_allocated_bytes(Thread* thread) {
|
||||
const int64_t allocated_bytes = thread->allocated_bytes();
|
||||
if (allocated_bytes < _last_allocated_bytes) {
|
||||
// A hw thread can detach and reattach to the VM, and when it does,
|
||||
// it gets a new JavaThread representation. The thread local variable
|
||||
// tracking _last_allocated_bytes is mapped to the existing hw thread,
|
||||
// so it needs to be reset.
|
||||
_last_allocated_bytes = 0;
|
||||
}
|
||||
return allocated_bytes == _last_allocated_bytes ? 0 : allocated_bytes;
|
||||
}
|
||||
|
||||
// To avoid large objects from being undersampled compared to the regular TLAB samples,
|
||||
// the data amount is normalized as if it was a TLAB, giving a number of TLAB sampling attempts to the large object.
|
||||
static void normalize_as_tlab_and_send_allocation_samples(Klass* klass, intptr_t obj_alloc_size_bytes, Thread* thread) {
|
||||
const int64_t allocated_bytes = load_allocated_bytes(thread);
|
||||
assert(allocated_bytes > 0, "invariant"); // obj_alloc_size_bytes is already attributed to allocated_bytes at this point.
|
||||
if (!UseTLAB) {
|
||||
send_allocation_sample(klass, allocated_bytes);
|
||||
return;
|
||||
}
|
||||
const intptr_t tlab_size_bytes = estimate_tlab_size_bytes(thread);
|
||||
if (allocated_bytes - _last_allocated_bytes < tlab_size_bytes) {
|
||||
return;
|
||||
}
|
||||
assert(obj_alloc_size_bytes > 0, "invariant");
|
||||
do {
|
||||
if (send_allocation_sample_with_result(klass, allocated_bytes)) {
|
||||
return;
|
||||
}
|
||||
obj_alloc_size_bytes -= tlab_size_bytes;
|
||||
} while (obj_alloc_size_bytes > 0);
|
||||
}
|
||||
|
||||
void AllocTracer::send_allocation_outside_tlab(Klass* klass, HeapWord* obj, size_t alloc_size, Thread* thread) {
|
||||
JFR_ONLY(JfrAllocationTracer tracer(obj, alloc_size, thread);)
|
||||
JFR_ONLY(JfrAllocationTracer tracer(klass, obj, alloc_size, true, thread);)
|
||||
EventObjectAllocationOutsideTLAB event;
|
||||
if (event.should_commit()) {
|
||||
event.set_objectClass(klass);
|
||||
event.set_allocationSize(alloc_size);
|
||||
event.commit();
|
||||
}
|
||||
normalize_as_tlab_and_send_allocation_samples(klass, static_cast<intptr_t>(alloc_size), thread);
|
||||
}
|
||||
|
||||
void AllocTracer::send_allocation_in_new_tlab(Klass* klass, HeapWord* obj, size_t tlab_size, size_t alloc_size, Thread* thread) {
|
||||
JFR_ONLY(JfrAllocationTracer tracer(obj, alloc_size, thread);)
|
||||
JFR_ONLY(JfrAllocationTracer tracer(klass, obj, alloc_size, false, thread);)
|
||||
EventObjectAllocationInNewTLAB event;
|
||||
if (event.should_commit()) {
|
||||
event.set_objectClass(klass);
|
||||
@ -124,11 +50,6 @@ void AllocTracer::send_allocation_in_new_tlab(Klass* klass, HeapWord* obj, size_
|
||||
event.set_tlabSize(tlab_size);
|
||||
event.commit();
|
||||
}
|
||||
const int64_t allocated_bytes = load_allocated_bytes(thread);
|
||||
if (allocated_bytes == 0) {
|
||||
return;
|
||||
}
|
||||
send_allocation_sample(klass, allocated_bytes);
|
||||
}
|
||||
|
||||
void AllocTracer::send_allocation_requiring_gc_event(size_t size, uint gcId) {
|
||||
|
@ -46,6 +46,20 @@
|
||||
#include "gc/g1/g1Policy.hpp"
|
||||
#endif // INCLUDE_G1GC
|
||||
|
||||
bool VM_GC_Sync_Operation::doit_prologue() {
|
||||
Heap_lock->lock();
|
||||
return true;
|
||||
}
|
||||
|
||||
void VM_GC_Sync_Operation::doit_epilogue() {
|
||||
Heap_lock->unlock();
|
||||
}
|
||||
|
||||
void VM_Verify::doit() {
|
||||
Universe::heap()->prepare_for_verify();
|
||||
Universe::verify();
|
||||
}
|
||||
|
||||
VM_GC_Operation::~VM_GC_Operation() {
|
||||
CollectedHeap* ch = Universe::heap();
|
||||
ch->soft_ref_policy()->set_all_soft_refs_clear(false);
|
||||
@ -94,8 +108,7 @@ bool VM_GC_Operation::doit_prologue() {
|
||||
proper_unit_for_byte_size(NewSize)));
|
||||
}
|
||||
|
||||
// If the GC count has changed someone beat us to the collection
|
||||
Heap_lock->lock();
|
||||
VM_GC_Sync_Operation::doit_prologue();
|
||||
|
||||
// Check invocations
|
||||
if (skip_operation()) {
|
||||
@ -116,7 +129,7 @@ void VM_GC_Operation::doit_epilogue() {
|
||||
if (Universe::has_reference_pending_list()) {
|
||||
Heap_lock->notify_all();
|
||||
}
|
||||
Heap_lock->unlock();
|
||||
VM_GC_Sync_Operation::doit_epilogue();
|
||||
}
|
||||
|
||||
bool VM_GC_HeapInspection::skip_operation() const {
|
||||
|
@ -39,17 +39,27 @@
|
||||
// a set of operations (VM_Operation) related to GC.
|
||||
//
|
||||
// VM_Operation
|
||||
// VM_GC_Sync_Operation
|
||||
// VM_GC_Operation
|
||||
// VM_GC_HeapInspection
|
||||
// VM_GenCollectFull
|
||||
// VM_GenCollectFullConcurrent
|
||||
// VM_ParallelGCSystemGC
|
||||
// VM_CollectForAllocation
|
||||
// VM_GenCollectForAllocation
|
||||
// VM_ParallelGCFailedAllocation
|
||||
// VM_GC_HeapInspection
|
||||
// VM_PopulateDynamicDumpSharedSpace
|
||||
// VM_GenCollectFull
|
||||
// VM_GenCollectFullConcurrent
|
||||
// VM_ParallelGCSystemGC
|
||||
// VM_CollectForAllocation
|
||||
// VM_GenCollectForAllocation
|
||||
// VM_ParallelGCFailedAllocation
|
||||
// VM_Verify
|
||||
// VM_PopulateDumpSharedSpace
|
||||
//
|
||||
// VM_GC_Sync_Operation
|
||||
// - implements only synchronization with other VM operations of the
|
||||
// same kind using the Heap_lock, not actually doing a GC.
|
||||
//
|
||||
// VM_GC_Operation
|
||||
// - implements methods common to all classes in the hierarchy:
|
||||
// prevents multiple gc requests and manages lock on heap;
|
||||
// - implements methods common to all operations that perform garbage collections,
|
||||
// checking that the VM is in a state to do GC and preventing multiple GC
|
||||
// requests.
|
||||
//
|
||||
// VM_GC_HeapInspection
|
||||
// - prints class histogram on SIGBREAK if PrintClassHistogram
|
||||
@ -68,11 +78,37 @@
|
||||
// - these operations preform full collection of heaps of
|
||||
// different kind
|
||||
//
|
||||
// VM_Verify
|
||||
// - verifies the heap
|
||||
//
|
||||
// VM_PopulateDynamicDumpSharedSpace
|
||||
// - populates the CDS archive area with the information from the archive file.
|
||||
//
|
||||
// VM_PopulateDumpSharedSpace
|
||||
// - creates the CDS archive
|
||||
//
|
||||
|
||||
class VM_GC_Operation: public VM_Operation {
|
||||
class VM_GC_Sync_Operation : public VM_Operation {
|
||||
public:
|
||||
|
||||
VM_GC_Sync_Operation() : VM_Operation() { }
|
||||
|
||||
// Acquires the Heap_lock.
|
||||
virtual bool doit_prologue();
|
||||
// Releases the Heap_lock.
|
||||
virtual void doit_epilogue();
|
||||
};
|
||||
|
||||
class VM_Verify : public VM_GC_Sync_Operation {
|
||||
public:
|
||||
VMOp_Type type() const { return VMOp_Verify; }
|
||||
void doit();
|
||||
};
|
||||
|
||||
class VM_GC_Operation: public VM_GC_Sync_Operation {
|
||||
protected:
|
||||
uint _gc_count_before; // gc count before acquiring PLL
|
||||
uint _full_gc_count_before; // full gc count before acquiring PLL
|
||||
uint _gc_count_before; // gc count before acquiring the Heap_lock
|
||||
uint _full_gc_count_before; // full gc count before acquiring the Heap_lock
|
||||
bool _full; // whether a "full" collection
|
||||
bool _prologue_succeeded; // whether doit_prologue succeeded
|
||||
GCCause::Cause _gc_cause; // the putative cause for this gc op
|
||||
@ -84,7 +120,7 @@ class VM_GC_Operation: public VM_Operation {
|
||||
VM_GC_Operation(uint gc_count_before,
|
||||
GCCause::Cause _cause,
|
||||
uint full_gc_count_before = 0,
|
||||
bool full = false) {
|
||||
bool full = false) : VM_GC_Sync_Operation() {
|
||||
_full = full;
|
||||
_prologue_succeeded = false;
|
||||
_gc_count_before = gc_count_before;
|
||||
@ -106,9 +142,10 @@ class VM_GC_Operation: public VM_Operation {
|
||||
}
|
||||
~VM_GC_Operation();
|
||||
|
||||
// Acquire the reference synchronization lock
|
||||
// Acquire the Heap_lock and determine if this VM operation should be executed
|
||||
// (i.e. not skipped). Return this result, and also store it in _prologue_succeeded.
|
||||
virtual bool doit_prologue();
|
||||
// Do notifyAll (if needed) and release held lock
|
||||
// Notify the Heap_lock if needed and release it.
|
||||
virtual void doit_epilogue();
|
||||
|
||||
virtual bool allow_nested_vm_operations() const { return true; }
|
||||
|
@ -24,6 +24,7 @@
|
||||
#include "precompiled.hpp"
|
||||
#include "gc/shared/gcId.hpp"
|
||||
#include "gc/shared/gcLocker.hpp"
|
||||
#include "gc/shared/gcVMOperations.hpp"
|
||||
#include "gc/shared/isGCActiveMark.hpp"
|
||||
#include "gc/z/zBreakpoint.hpp"
|
||||
#include "gc/z/zCollectedHeap.hpp"
|
||||
|
@ -25,10 +25,12 @@
|
||||
#include "precompiled.hpp"
|
||||
#include "jfr/leakprofiler/leakProfiler.hpp"
|
||||
#include "jfr/support/jfrAllocationTracer.hpp"
|
||||
#include "jfr/support/jfrObjectAllocationSample.hpp"
|
||||
#include "jfr/support/jfrThreadLocal.hpp"
|
||||
#include "runtime/thread.hpp"
|
||||
|
||||
JfrAllocationTracer::JfrAllocationTracer(HeapWord* obj, size_t alloc_size, Thread* thread) : _tl(NULL) {
|
||||
JfrAllocationTracer::JfrAllocationTracer(const Klass* klass, HeapWord* obj, size_t alloc_size, bool outside_tlab, Thread* thread) : _tl(NULL) {
|
||||
JfrObjectAllocationSample::send_event(klass, alloc_size, outside_tlab, thread);
|
||||
if (LeakProfiler::is_running()) {
|
||||
_tl = thread->jfr_thread_local();
|
||||
LeakProfiler::sample(obj, alloc_size, thread->as_Java_thread());
|
||||
|
@ -27,13 +27,15 @@
|
||||
|
||||
#include "memory/allocation.hpp"
|
||||
|
||||
class Klass;
|
||||
class JfrThreadLocal;
|
||||
class Thread;
|
||||
|
||||
class JfrAllocationTracer : public StackObj {
|
||||
private:
|
||||
JfrThreadLocal* _tl;
|
||||
public:
|
||||
JfrAllocationTracer(HeapWord* obj, size_t alloc_size, Thread* thread);
|
||||
JfrAllocationTracer(const Klass* klass, HeapWord* obj, size_t alloc_size, bool outside_tlab, Thread* thread);
|
||||
~JfrAllocationTracer();
|
||||
};
|
||||
|
||||
|
113
src/hotspot/share/jfr/support/jfrObjectAllocationSample.cpp
Normal file
113
src/hotspot/share/jfr/support/jfrObjectAllocationSample.cpp
Normal file
@ -0,0 +1,113 @@
|
||||
/*
|
||||
* Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "precompiled.hpp"
|
||||
#include "gc/shared/threadLocalAllocBuffer.inline.hpp"
|
||||
#include "jfr/jfrEvents.hpp"
|
||||
#include "jfr/support/jfrObjectAllocationSample.hpp"
|
||||
#include "utilities/globalDefinitions.hpp"
|
||||
|
||||
static THREAD_LOCAL int64_t _last_allocated_bytes = 0;
|
||||
|
||||
inline void send_allocation_sample(const Klass* klass, int64_t allocated_bytes) {
|
||||
assert(allocated_bytes > 0, "invariant");
|
||||
EventObjectAllocationSample event;
|
||||
if (event.should_commit()) {
|
||||
const size_t weight = allocated_bytes - _last_allocated_bytes;
|
||||
assert(weight > 0, "invariant");
|
||||
event.set_objectClass(klass);
|
||||
event.set_weight(weight);
|
||||
event.commit();
|
||||
_last_allocated_bytes = allocated_bytes;
|
||||
}
|
||||
}
|
||||
|
||||
inline bool send_allocation_sample_with_result(const Klass* klass, int64_t allocated_bytes) {
|
||||
assert(allocated_bytes > 0, "invariant");
|
||||
EventObjectAllocationSample event;
|
||||
if (event.should_commit()) {
|
||||
const size_t weight = allocated_bytes - _last_allocated_bytes;
|
||||
assert(weight > 0, "invariant");
|
||||
event.set_objectClass(klass);
|
||||
event.set_weight(weight);
|
||||
event.commit();
|
||||
_last_allocated_bytes = allocated_bytes;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
inline intptr_t estimate_tlab_size_bytes(Thread* thread) {
|
||||
const size_t desired_tlab_size_bytes = thread->tlab().desired_size() * HeapWordSize;
|
||||
const size_t alignment_reserve_bytes = thread->tlab().alignment_reserve_in_bytes();
|
||||
assert(desired_tlab_size_bytes > alignment_reserve_bytes, "invariant");
|
||||
return static_cast<intptr_t>(desired_tlab_size_bytes - alignment_reserve_bytes);
|
||||
}
|
||||
|
||||
inline int64_t load_allocated_bytes(Thread* thread) {
|
||||
assert(thread != NULL, "invariant");
|
||||
const int64_t allocated_bytes = thread->allocated_bytes();
|
||||
if (allocated_bytes < _last_allocated_bytes) {
|
||||
// A hw thread can detach and reattach to the VM, and when it does,
|
||||
// it gets a new JavaThread representation. The thread local variable
|
||||
// tracking _last_allocated_bytes is mapped to the existing hw thread,
|
||||
// so it needs to be reset.
|
||||
_last_allocated_bytes = 0;
|
||||
}
|
||||
return allocated_bytes == _last_allocated_bytes ? 0 : allocated_bytes;
|
||||
}
|
||||
|
||||
// To avoid large objects from being undersampled compared to the regular TLAB samples,
|
||||
// the data amount is normalized as if it was a TLAB, giving a number of TLAB sampling attempts to the large object.
|
||||
static void normalize_as_tlab_and_send_allocation_samples(const Klass* klass, intptr_t obj_alloc_size_bytes, Thread* thread) {
|
||||
const int64_t allocated_bytes = load_allocated_bytes(thread);
|
||||
assert(allocated_bytes > 0, "invariant"); // obj_alloc_size_bytes is already attributed to allocated_bytes at this point.
|
||||
if (!UseTLAB) {
|
||||
send_allocation_sample(klass, allocated_bytes);
|
||||
return;
|
||||
}
|
||||
const intptr_t tlab_size_bytes = estimate_tlab_size_bytes(thread);
|
||||
if (allocated_bytes - _last_allocated_bytes < tlab_size_bytes) {
|
||||
return;
|
||||
}
|
||||
assert(obj_alloc_size_bytes > 0, "invariant");
|
||||
do {
|
||||
if (send_allocation_sample_with_result(klass, allocated_bytes)) {
|
||||
return;
|
||||
}
|
||||
obj_alloc_size_bytes -= tlab_size_bytes;
|
||||
} while (obj_alloc_size_bytes > 0);
|
||||
}
|
||||
|
||||
void JfrObjectAllocationSample::send_event(const Klass* klass, size_t alloc_size, bool outside_tlab, Thread* thread) {
|
||||
if (outside_tlab) {
|
||||
normalize_as_tlab_and_send_allocation_samples(klass, static_cast<intptr_t>(alloc_size), thread);
|
||||
return;
|
||||
}
|
||||
const int64_t allocated_bytes = load_allocated_bytes(thread);
|
||||
if (allocated_bytes == 0) {
|
||||
return;
|
||||
}
|
||||
send_allocation_sample(klass, allocated_bytes);
|
||||
}
|
38
src/hotspot/share/jfr/support/jfrObjectAllocationSample.hpp
Normal file
38
src/hotspot/share/jfr/support/jfrObjectAllocationSample.hpp
Normal file
@ -0,0 +1,38 @@
|
||||
/*
|
||||
* Copyright (c) 2020, 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_JFR_SUPPORT_JFROBJECTALLOCATIONSAMPLE_HPP
|
||||
#define SHARE_JFR_SUPPORT_JFROBJECTALLOCATIONSAMPLE_HPP
|
||||
|
||||
#include "memory/allocation.hpp"
|
||||
|
||||
class Klass;
|
||||
class Thread;
|
||||
|
||||
class JfrObjectAllocationSample : AllStatic {
|
||||
friend class JfrAllocationTracer;
|
||||
static void send_event(const Klass* klass, size_t alloc_size, bool outside_tlab, Thread* thread);
|
||||
};
|
||||
|
||||
#endif // SHARE_JFR_SUPPORT_JFROBJECTALLOCATIONSAMPLE_HPP
|
@ -267,6 +267,20 @@ JRT_ENTRY_NO_ASYNC(static address, exception_handler_for_pc_helper(JavaThread* t
|
||||
}
|
||||
#endif
|
||||
|
||||
// debugging support
|
||||
// tracing
|
||||
if (log_is_enabled(Info, exceptions)) {
|
||||
ResourceMark rm;
|
||||
stringStream tempst;
|
||||
assert(cm->method() != NULL, "Unexpected null method()");
|
||||
tempst.print("JVMCI compiled method <%s>\n"
|
||||
" at PC" INTPTR_FORMAT " for thread " INTPTR_FORMAT,
|
||||
cm->method()->print_value_string(), p2i(pc), p2i(thread));
|
||||
Exceptions::log_exception(exception, tempst.as_string());
|
||||
}
|
||||
// for AbortVMOnException flag
|
||||
Exceptions::debug_check_abort(exception);
|
||||
|
||||
// Check the stack guard pages and reenable them if necessary and there is
|
||||
// enough space on the stack to do so. Use fast exceptions only if the guard
|
||||
// pages are enabled.
|
||||
@ -313,20 +327,6 @@ JRT_ENTRY_NO_ASYNC(static address, exception_handler_for_pc_helper(JavaThread* t
|
||||
// New exception handling mechanism can support inlined methods
|
||||
// with exception handlers since the mappings are from PC to PC
|
||||
|
||||
// debugging support
|
||||
// tracing
|
||||
if (log_is_enabled(Info, exceptions)) {
|
||||
ResourceMark rm;
|
||||
stringStream tempst;
|
||||
assert(cm->method() != NULL, "Unexpected null method()");
|
||||
tempst.print("compiled method <%s>\n"
|
||||
" at PC" INTPTR_FORMAT " for thread " INTPTR_FORMAT,
|
||||
cm->method()->print_value_string(), p2i(pc), p2i(thread));
|
||||
Exceptions::log_exception(exception, tempst.as_string());
|
||||
}
|
||||
// for AbortVMOnException flag
|
||||
NOT_PRODUCT(Exceptions::debug_check_abort(exception));
|
||||
|
||||
// Clear out the exception oop and pc since looking up an
|
||||
// exception handler can cause class loading, which might throw an
|
||||
// exception and those fields are expected to be clear during
|
||||
|
@ -27,6 +27,7 @@
|
||||
#include "classfile/classLoaderData.inline.hpp"
|
||||
#include "classfile/symbolTable.hpp"
|
||||
#include "classfile/systemDictionaryShared.hpp"
|
||||
#include "gc/shared/gcVMOperations.hpp"
|
||||
#include "logging/log.hpp"
|
||||
#include "memory/archiveBuilder.hpp"
|
||||
#include "memory/archiveUtils.inline.hpp"
|
||||
@ -541,10 +542,10 @@ void DynamicArchiveBuilder::write_archive(char* serialized_data) {
|
||||
log_info(cds, dynamic)("%d klasses; %d symbols", num_klasses, num_symbols);
|
||||
}
|
||||
|
||||
class VM_PopulateDynamicDumpSharedSpace: public VM_Operation {
|
||||
class VM_PopulateDynamicDumpSharedSpace: public VM_GC_Sync_Operation {
|
||||
DynamicArchiveBuilder* _builder;
|
||||
public:
|
||||
VM_PopulateDynamicDumpSharedSpace(DynamicArchiveBuilder* builder) : _builder(builder) {}
|
||||
VM_PopulateDynamicDumpSharedSpace(DynamicArchiveBuilder* builder) : VM_GC_Sync_Operation(), _builder(builder) {}
|
||||
VMOp_Type type() const { return VMOp_PopulateDumpSharedSpace; }
|
||||
void doit() {
|
||||
ResourceMark rm;
|
||||
|
@ -33,6 +33,7 @@
|
||||
#include "classfile/systemDictionaryShared.hpp"
|
||||
#include "classfile/vmSymbols.hpp"
|
||||
#include "gc/shared/gcLocker.hpp"
|
||||
#include "gc/shared/gcVMOperations.hpp"
|
||||
#include "logging/log.hpp"
|
||||
#include "logging/logMessage.hpp"
|
||||
#include "logging/logStream.hpp"
|
||||
@ -655,8 +656,10 @@ static void verify_the_heap(Klass* k, const char* which) {
|
||||
ResourceMark rm;
|
||||
log_info(cds, heap)("Verify heap %s initializing static field(s) in %s",
|
||||
which, k->external_name());
|
||||
|
||||
VM_Verify verify_op;
|
||||
VMThread::execute(&verify_op);
|
||||
|
||||
if (!FLAG_IS_DEFAULT(VerifyArchivedFields)) {
|
||||
// If VerifyArchivedFields has a non-default value (e.g., specified on the command-line), do
|
||||
// more expensive checks.
|
||||
|
@ -37,6 +37,7 @@
|
||||
#include "classfile/systemDictionaryShared.hpp"
|
||||
#include "classfile/vmSymbols.hpp"
|
||||
#include "code/codeCache.hpp"
|
||||
#include "gc/shared/gcVMOperations.hpp"
|
||||
#include "interpreter/abstractInterpreter.hpp"
|
||||
#include "interpreter/bytecodeStream.hpp"
|
||||
#include "interpreter/bytecodes.hpp"
|
||||
@ -577,7 +578,7 @@ void MetaspaceShared::rewrite_nofast_bytecodes_and_calculate_fingerprints(Thread
|
||||
}
|
||||
}
|
||||
|
||||
class VM_PopulateDumpSharedSpace: public VM_Operation {
|
||||
class VM_PopulateDumpSharedSpace : public VM_GC_Operation {
|
||||
private:
|
||||
GrowableArray<MemRegion> *_closed_archive_heap_regions;
|
||||
GrowableArray<MemRegion> *_open_archive_heap_regions;
|
||||
@ -602,6 +603,12 @@ private:
|
||||
|
||||
public:
|
||||
|
||||
VM_PopulateDumpSharedSpace() : VM_GC_Operation(0, /* total collections, ignored */
|
||||
GCCause::_archive_time_gc)
|
||||
{ }
|
||||
|
||||
bool skip_operation() const { return false; }
|
||||
|
||||
VMOp_Type type() const { return VMOp_PopulateDumpSharedSpace; }
|
||||
void doit(); // outline because gdb sucks
|
||||
bool allow_nested_vm_operations() const { return true; }
|
||||
@ -1085,8 +1092,6 @@ void MetaspaceShared::preload_and_dump(TRAPS) {
|
||||
#endif
|
||||
|
||||
VM_PopulateDumpSharedSpace op;
|
||||
MutexLocker ml(THREAD, HeapShared::is_heap_object_archiving_allowed() ?
|
||||
Heap_lock : NULL); // needed by HeapShared::run_gc()
|
||||
VMThread::execute(&op);
|
||||
}
|
||||
}
|
||||
|
@ -739,6 +739,12 @@ void InstanceKlass::deallocate_contents(ClassLoaderData* loader_data) {
|
||||
}
|
||||
}
|
||||
|
||||
bool InstanceKlass::is_record() const {
|
||||
return _record_components != NULL &&
|
||||
is_final() &&
|
||||
java_super() == SystemDictionary::Record_klass();
|
||||
}
|
||||
|
||||
bool InstanceKlass::is_sealed() const {
|
||||
return _permitted_subclasses != NULL &&
|
||||
_permitted_subclasses != Universe::the_empty_short_array();
|
||||
|
@ -473,7 +473,7 @@ class InstanceKlass: public Klass {
|
||||
void set_record_components(Array<RecordComponent*>* record_components) {
|
||||
_record_components = record_components;
|
||||
}
|
||||
bool is_record() const { return _record_components != NULL; }
|
||||
bool is_record() const;
|
||||
|
||||
// permitted subclasses
|
||||
Array<u2>* permitted_subclasses() const { return _permitted_subclasses; }
|
||||
|
@ -1207,7 +1207,7 @@ void MethodData::post_initialize(BytecodeStream* stream) {
|
||||
MethodData::MethodData(const methodHandle& method)
|
||||
: _method(method()),
|
||||
_extra_data_lock(Mutex::leaf, "MDO extra data lock"),
|
||||
_compiler_counters(method()),
|
||||
_compiler_counters(),
|
||||
_parameters_type_data_di(parameters_uninitialized) {
|
||||
initialize();
|
||||
}
|
||||
@ -1218,6 +1218,7 @@ void MethodData::initialize() {
|
||||
ResourceMark rm(thread);
|
||||
|
||||
init();
|
||||
set_creation_mileage(mileage_of(method()));
|
||||
|
||||
// Go through the bytecodes and allocate and initialize the
|
||||
// corresponding data cells.
|
||||
@ -1282,6 +1283,7 @@ void MethodData::initialize() {
|
||||
}
|
||||
|
||||
void MethodData::init() {
|
||||
_compiler_counters = CompilerCounters(); // reset compiler counters
|
||||
_invocation_counter.init();
|
||||
_backedge_counter.init();
|
||||
_invocation_counter_start = 0;
|
||||
|
@ -1974,7 +1974,6 @@ public:
|
||||
friend class VMStructs;
|
||||
friend class JVMCIVMStructs;
|
||||
|
||||
int _creation_mileage; // method mileage at MDO creation
|
||||
uint _nof_decompiles; // count of all nmethod removals
|
||||
uint _nof_overflow_recompiles; // recompile count, excluding recomp. bits
|
||||
uint _nof_overflow_traps; // trap count, excluding _trap_hist
|
||||
@ -1983,16 +1982,12 @@ public:
|
||||
u1 _array[JVMCI_ONLY(2 *) MethodData::_trap_hist_limit];
|
||||
} _trap_hist;
|
||||
|
||||
CompilerCounters(int current_mileage) : _creation_mileage(current_mileage), _nof_decompiles(0), _nof_overflow_recompiles(0), _nof_overflow_traps(0) {
|
||||
public:
|
||||
CompilerCounters() : _nof_decompiles(0), _nof_overflow_recompiles(0), _nof_overflow_traps(0) {
|
||||
static_assert(sizeof(_trap_hist) % HeapWordSize == 0, "align");
|
||||
uint size_in_words = sizeof(_trap_hist) / HeapWordSize;
|
||||
Copy::zero_to_words((HeapWord*) &_trap_hist, size_in_words);
|
||||
}
|
||||
public:
|
||||
CompilerCounters(Method* m) : CompilerCounters(MethodData::mileage_of(m)) {}
|
||||
CompilerCounters() : CompilerCounters(0) {} // for ciMethodData
|
||||
|
||||
int creation_mileage() const { return _creation_mileage; }
|
||||
|
||||
// Return (uint)-1 for overflow.
|
||||
uint trap_count(int reason) const {
|
||||
@ -2044,6 +2039,8 @@ private:
|
||||
intx _arg_stack; // bit set of stack-allocatable arguments
|
||||
intx _arg_returned; // bit set of returned arguments
|
||||
|
||||
int _creation_mileage; // method mileage at MDO creation
|
||||
|
||||
// How many invocations has this MDO seen?
|
||||
// These counters are used to determine the exact age of MDO.
|
||||
// We need those because in tiered a method can be concurrently
|
||||
@ -2188,7 +2185,8 @@ public:
|
||||
int size_in_bytes() const { return _size; }
|
||||
int size() const { return align_metadata_size(align_up(_size, BytesPerWord)/BytesPerWord); }
|
||||
|
||||
int creation_mileage() const { return _compiler_counters.creation_mileage(); }
|
||||
int creation_mileage() const { return _creation_mileage; }
|
||||
void set_creation_mileage(int x) { _creation_mileage = x; }
|
||||
|
||||
int invocation_count() {
|
||||
if (invocation_counter()->carry()) {
|
||||
|
@ -1851,6 +1851,9 @@ JVM_ENTRY(jobjectArray, JVM_GetClassDeclaredFields(JNIEnv *env, jclass ofClass,
|
||||
}
|
||||
JVM_END
|
||||
|
||||
|
||||
// A class is a record if and only if it is final and a direct subclass of
|
||||
// java.lang.Record and has a Record attribute; otherwise, it is not a record.
|
||||
JVM_ENTRY(jboolean, JVM_IsRecord(JNIEnv *env, jclass cls))
|
||||
{
|
||||
JVMWrapper("JVM_IsRecord");
|
||||
@ -1864,6 +1867,11 @@ JVM_ENTRY(jboolean, JVM_IsRecord(JNIEnv *env, jclass cls))
|
||||
}
|
||||
JVM_END
|
||||
|
||||
// Returns an array containing the components of the Record attribute,
|
||||
// or NULL if the attribute is not present.
|
||||
//
|
||||
// Note that this function returns the components of the Record attribute
|
||||
// even if the class is not a record.
|
||||
JVM_ENTRY(jobjectArray, JVM_GetRecordComponents(JNIEnv* env, jclass ofClass))
|
||||
{
|
||||
JVMWrapper("JVM_GetRecordComponents");
|
||||
@ -1871,31 +1879,26 @@ JVM_ENTRY(jobjectArray, JVM_GetRecordComponents(JNIEnv* env, jclass ofClass))
|
||||
assert(c->is_instance_klass(), "must be");
|
||||
InstanceKlass* ik = InstanceKlass::cast(c);
|
||||
|
||||
if (ik->is_record()) {
|
||||
Array<RecordComponent*>* components = ik->record_components();
|
||||
assert(components != NULL, "components should not be NULL");
|
||||
{
|
||||
JvmtiVMObjectAllocEventCollector oam;
|
||||
constantPoolHandle cp(THREAD, ik->constants());
|
||||
int length = components->length();
|
||||
assert(length >= 0, "unexpected record_components length");
|
||||
objArrayOop record_components =
|
||||
oopFactory::new_objArray(SystemDictionary::RecordComponent_klass(), length, CHECK_NULL);
|
||||
objArrayHandle components_h (THREAD, record_components);
|
||||
Array<RecordComponent*>* components = ik->record_components();
|
||||
if (components != NULL) {
|
||||
JvmtiVMObjectAllocEventCollector oam;
|
||||
constantPoolHandle cp(THREAD, ik->constants());
|
||||
int length = components->length();
|
||||
assert(length >= 0, "unexpected record_components length");
|
||||
objArrayOop record_components =
|
||||
oopFactory::new_objArray(SystemDictionary::RecordComponent_klass(), length, CHECK_NULL);
|
||||
objArrayHandle components_h (THREAD, record_components);
|
||||
|
||||
for (int x = 0; x < length; x++) {
|
||||
RecordComponent* component = components->at(x);
|
||||
assert(component != NULL, "unexpected NULL record component");
|
||||
oop component_oop = java_lang_reflect_RecordComponent::create(ik, component, CHECK_NULL);
|
||||
components_h->obj_at_put(x, component_oop);
|
||||
}
|
||||
return (jobjectArray)JNIHandles::make_local(THREAD, components_h());
|
||||
for (int x = 0; x < length; x++) {
|
||||
RecordComponent* component = components->at(x);
|
||||
assert(component != NULL, "unexpected NULL record component");
|
||||
oop component_oop = java_lang_reflect_RecordComponent::create(ik, component, CHECK_NULL);
|
||||
components_h->obj_at_put(x, component_oop);
|
||||
}
|
||||
return (jobjectArray)JNIHandles::make_local(THREAD, components_h());
|
||||
}
|
||||
|
||||
// Return empty array if ofClass is not a record.
|
||||
objArrayOop result = oopFactory::new_objArray(SystemDictionary::RecordComponent_klass(), 0, CHECK_NULL);
|
||||
return (jobjectArray)JNIHandles::make_local(THREAD, result);
|
||||
return NULL;
|
||||
}
|
||||
JVM_END
|
||||
|
||||
|
@ -1731,6 +1731,18 @@ address Deoptimization::deoptimize_for_missing_exception_handler(CompiledMethod*
|
||||
frame runtime_frame = thread->last_frame();
|
||||
frame caller_frame = runtime_frame.sender(®_map);
|
||||
assert(caller_frame.cb()->as_compiled_method_or_null() == cm, "expect top frame compiled method");
|
||||
vframe* vf = vframe::new_vframe(&caller_frame, ®_map, thread);
|
||||
compiledVFrame* cvf = compiledVFrame::cast(vf);
|
||||
ScopeDesc* imm_scope = cvf->scope();
|
||||
MethodData* imm_mdo = get_method_data(thread, methodHandle(thread, imm_scope->method()), true);
|
||||
if (imm_mdo != NULL) {
|
||||
ProfileData* pdata = imm_mdo->allocate_bci_to_data(imm_scope->bci(), NULL);
|
||||
if (pdata != NULL && pdata->is_BitData()) {
|
||||
BitData* bit_data = (BitData*) pdata;
|
||||
bit_data->set_exception_seen();
|
||||
}
|
||||
}
|
||||
|
||||
Deoptimization::deoptimize(thread, caller_frame, Deoptimization::Reason_not_compiled_exception_handler);
|
||||
|
||||
MethodData* trap_mdo = get_method_data(thread, methodHandle(thread, cm->method()), true);
|
||||
|
@ -599,6 +599,28 @@ void SharedRuntime::throw_and_post_jvmti_exception(JavaThread *thread, Handle h_
|
||||
address bcp = method()->bcp_from(vfst.bci());
|
||||
JvmtiExport::post_exception_throw(thread, method(), bcp, h_exception());
|
||||
}
|
||||
|
||||
#if INCLUDE_JVMCI
|
||||
if (EnableJVMCI && UseJVMCICompiler) {
|
||||
vframeStream vfst(thread, true);
|
||||
methodHandle method = methodHandle(thread, vfst.method());
|
||||
int bci = vfst.bci();
|
||||
MethodData* trap_mdo = method->method_data();
|
||||
if (trap_mdo != NULL) {
|
||||
// Set exception_seen if the exceptional bytecode is an invoke
|
||||
Bytecode_invoke call = Bytecode_invoke_check(method, bci);
|
||||
if (call.is_valid()) {
|
||||
ResourceMark rm(thread);
|
||||
ProfileData* pdata = trap_mdo->allocate_bci_to_data(bci, NULL);
|
||||
if (pdata != NULL && pdata->is_BitData()) {
|
||||
BitData* bit_data = (BitData*) pdata;
|
||||
bit_data->set_exception_seen();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
Exceptions::_throw(thread, __FILE__, __LINE__, h_exception);
|
||||
}
|
||||
|
||||
|
@ -39,6 +39,7 @@
|
||||
#include "gc/shared/barrierSet.hpp"
|
||||
#include "gc/shared/gcId.hpp"
|
||||
#include "gc/shared/gcLocker.inline.hpp"
|
||||
#include "gc/shared/gcVMOperations.hpp"
|
||||
#include "gc/shared/oopStorage.hpp"
|
||||
#include "gc/shared/oopStorageSet.hpp"
|
||||
#include "gc/shared/workgroup.hpp"
|
||||
|
@ -156,11 +156,6 @@ void VM_ZombieAll::doit() {
|
||||
|
||||
#endif // !PRODUCT
|
||||
|
||||
void VM_Verify::doit() {
|
||||
Universe::heap()->prepare_for_verify();
|
||||
Universe::verify();
|
||||
}
|
||||
|
||||
bool VM_PrintThreads::doit_prologue() {
|
||||
// Get Heap_lock if concurrent locks will be dumped
|
||||
if (_print_concurrent_locks) {
|
||||
|
@ -277,13 +277,6 @@ class VM_ZombieAll: public VM_Operation {
|
||||
};
|
||||
#endif // PRODUCT
|
||||
|
||||
class VM_Verify: public VM_Operation {
|
||||
public:
|
||||
VMOp_Type type() const { return VMOp_Verify; }
|
||||
void doit();
|
||||
};
|
||||
|
||||
|
||||
class VM_PrintThreads: public VM_Operation {
|
||||
private:
|
||||
outputStream* _out;
|
||||
|
@ -2383,11 +2383,7 @@ public final class Class<T> implements java.io.Serializable,
|
||||
if (!isRecord()) {
|
||||
return null;
|
||||
}
|
||||
RecordComponent[] recordComponents = getRecordComponents0();
|
||||
if (recordComponents == null) {
|
||||
return new RecordComponent[0];
|
||||
}
|
||||
return recordComponents;
|
||||
return getRecordComponents0();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -3577,9 +3573,17 @@ public final class Class<T> implements java.io.Serializable,
|
||||
private native Field[] getDeclaredFields0(boolean publicOnly);
|
||||
private native Method[] getDeclaredMethods0(boolean publicOnly);
|
||||
private native Constructor<T>[] getDeclaredConstructors0(boolean publicOnly);
|
||||
private native Class<?>[] getDeclaredClasses0();
|
||||
private native Class<?>[] getDeclaredClasses0();
|
||||
|
||||
/*
|
||||
* Returns an array containing the components of the Record attribute,
|
||||
* or null if the attribute is not present.
|
||||
*
|
||||
* Note that this method returns non-null array on a class with
|
||||
* the Record attribute even if this class is not a record.
|
||||
*/
|
||||
private native RecordComponent[] getRecordComponents0();
|
||||
private native boolean isRecord0();
|
||||
private native boolean isRecord0();
|
||||
|
||||
/**
|
||||
* Helper method to get the method name from arguments.
|
||||
@ -3706,6 +3710,8 @@ public final class Class<T> implements java.io.Serializable,
|
||||
* @since 16
|
||||
*/
|
||||
public boolean isRecord() {
|
||||
// this superclass and final modifier check is not strictly necessary
|
||||
// they are intrinsified and serve as a fast-path check
|
||||
return getSuperclass() == java.lang.Record.class &&
|
||||
(this.getModifiers() & Modifier.FINAL) != 0 &&
|
||||
isRecord0();
|
||||
|
@ -111,15 +111,14 @@ public abstract class Record {
|
||||
* <li> If the component is of a reference type, the component is
|
||||
* considered equal if and only if {@link
|
||||
* java.util.Objects#equals(Object,Object)
|
||||
* Objects.equals(this.c(), r.c()} would return {@code true}.
|
||||
* Objects.equals(this.c, r.c} would return {@code true}.
|
||||
*
|
||||
* <li> If the component is of a primitive type, using the
|
||||
* corresponding primitive wrapper class {@code PW} (the
|
||||
* corresponding wrapper class for {@code int} is {@code
|
||||
* java.lang.Integer}, and so on), the component is considered
|
||||
* equal if and only if {@code
|
||||
* PW.valueOf(this.c()).equals(PW.valueOf(r.c()))} would return
|
||||
* {@code true}.
|
||||
* PW.compare(this.c, r.c)} would return {@code 0}.
|
||||
*
|
||||
* </ul>
|
||||
*
|
||||
|
@ -1871,6 +1871,8 @@ public class CompletableFuture<T> implements Future<T>, CompletionStage<T> {
|
||||
* interrupted.
|
||||
*/
|
||||
private Object waitingGet(boolean interruptible) {
|
||||
if (interruptible && Thread.interrupted())
|
||||
return null;
|
||||
Signaller q = null;
|
||||
boolean queued = false;
|
||||
Object r;
|
||||
@ -1882,25 +1884,25 @@ public class CompletableFuture<T> implements Future<T>, CompletionStage<T> {
|
||||
}
|
||||
else if (!queued)
|
||||
queued = tryPushStack(q);
|
||||
else if (interruptible && q.interrupted) {
|
||||
q.thread = null;
|
||||
cleanStack();
|
||||
return null;
|
||||
}
|
||||
else {
|
||||
try {
|
||||
ForkJoinPool.managedBlock(q);
|
||||
} catch (InterruptedException ie) { // currently cannot happen
|
||||
q.interrupted = true;
|
||||
}
|
||||
if (q.interrupted && interruptible)
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (q != null && queued) {
|
||||
if (q != null) {
|
||||
q.thread = null;
|
||||
if (!interruptible && q.interrupted)
|
||||
if (q.interrupted)
|
||||
Thread.currentThread().interrupt();
|
||||
if (r == null)
|
||||
cleanStack();
|
||||
}
|
||||
if (r != null || (r = result) != null)
|
||||
postComplete();
|
||||
postComplete();
|
||||
return r;
|
||||
}
|
||||
|
||||
|
@ -109,7 +109,7 @@ public interface RoundEnvironment {
|
||||
* annotation types, or an empty set if there are none
|
||||
* @throws IllegalArgumentException if the any elements of the
|
||||
* argument set do not represent an annotation type
|
||||
* @jls 9.6.3 Repeatable Annotation Types
|
||||
* @jls 9.6.3 Repeatable Annotation Interfaces
|
||||
* @since 9
|
||||
*/
|
||||
default Set<? extends Element> getElementsAnnotatedWithAny(TypeElement... annotations){
|
||||
@ -191,7 +191,7 @@ public interface RoundEnvironment {
|
||||
* annotation types, or an empty set if there are none
|
||||
* @throws IllegalArgumentException if the any elements of the
|
||||
* argument set do not represent an annotation type
|
||||
* @jls 9.6.3 Repeatable Annotation Types
|
||||
* @jls 9.6.3 Repeatable Annotation Interfaces
|
||||
*
|
||||
* @see javax.lang.model.AnnotatedConstruct#getAnnotation(Class)
|
||||
* @see javax.lang.model.AnnotatedConstruct#getAnnotationsByType(Class)
|
||||
|
@ -129,10 +129,10 @@ import javax.lang.model.type.*;
|
||||
* </ul>
|
||||
*
|
||||
* @since 1.8
|
||||
* @jls 9.6 Annotation Types
|
||||
* @jls 9.6 Annotation Interfaces
|
||||
* @jls 9.6.4.3 {@code @Inherited}
|
||||
* @jls 9.7.4 Where Annotations May Appear
|
||||
* @jls 9.7.5 Multiple Annotations of the Same Type
|
||||
* @jls 9.7.5 Multiple Annotations of the Same Interface
|
||||
*/
|
||||
public interface AnnotatedConstruct {
|
||||
/**
|
||||
@ -184,7 +184,7 @@ public interface AnnotatedConstruct {
|
||||
* @see IncompleteAnnotationException
|
||||
* @see MirroredTypeException
|
||||
* @see MirroredTypesException
|
||||
* @jls 9.6.1 Annotation Type Elements
|
||||
* @jls 9.6.1 Annotation Interface Elements
|
||||
*/
|
||||
<A extends Annotation> A getAnnotation(Class<A> annotationType);
|
||||
|
||||
@ -244,8 +244,8 @@ public interface AnnotatedConstruct {
|
||||
* @see IncompleteAnnotationException
|
||||
* @see MirroredTypeException
|
||||
* @see MirroredTypesException
|
||||
* @jls 9.6 Annotation Types
|
||||
* @jls 9.6.1 Annotation Type Elements
|
||||
* @jls 9.6 Annotation Interfaces
|
||||
* @jls 9.6.1 Annotation Interface Elements
|
||||
*/
|
||||
<A extends Annotation> A[] getAnnotationsByType(Class<A> annotationType);
|
||||
}
|
||||
|
@ -229,7 +229,7 @@ public interface Element extends javax.lang.model.AnnotatedConstruct {
|
||||
* @see ModuleElement#getEnclosedElements
|
||||
* @see Elements#getAllMembers
|
||||
* @jls 8.8.9 Default Constructor
|
||||
* @jls 8.9 Enum Types
|
||||
* @jls 8.9 Enum Classes
|
||||
* @revised 9
|
||||
*/
|
||||
List<? extends Element> getEnclosedElements();
|
||||
|
@ -91,7 +91,7 @@ public enum NestingKind {
|
||||
/**
|
||||
* A class or interface that is a named member of another class or
|
||||
* interface.
|
||||
* @jls 8.5 Member Type Declarations
|
||||
* @jls 8.5 Member Class and Interface Declarations
|
||||
*/
|
||||
MEMBER,
|
||||
|
||||
|
@ -116,7 +116,7 @@
|
||||
* @jls 8.1 Class Declarations
|
||||
* @jls 8.3 Field Declarations
|
||||
* @jls 8.4 Method Declarations
|
||||
* @jls 8.5 Member Type Declarations
|
||||
* @jls 8.5 Member Class and Interface Declarations
|
||||
* @jls 8.8 Constructor Declarations
|
||||
* @jls 9.1 Interface Declarations
|
||||
* @since 1.6
|
||||
|
@ -354,7 +354,7 @@ public interface Elements {
|
||||
* @param c the construct the annotation mirror modifies
|
||||
* @param a the annotation mirror being examined
|
||||
* @jls 9.6.3 Repeatable Annotation Types
|
||||
* @jls 9.7.5 Multiple Annotations of the Same Type
|
||||
* @jls 9.7.5 Multiple Annotations of the Same Interface
|
||||
* @since 9
|
||||
*/
|
||||
default Origin getOrigin(AnnotatedConstruct c,
|
||||
@ -428,7 +428,7 @@ public interface Elements {
|
||||
* @jls 8.8.9 Default Constructor
|
||||
* @jls 8.9.3 Enum Members
|
||||
* @jls 9.6.3 Repeatable Annotation Types
|
||||
* @jls 9.7.5 Multiple Annotations of the Same Type
|
||||
* @jls 9.7.5 Multiple Annotations of the Same Interface
|
||||
*/
|
||||
MANDATED,
|
||||
|
||||
|
@ -233,15 +233,15 @@ void JfrGTestAdaptiveSampling::test(JfrGTestAdaptiveSampling::incoming inc, size
|
||||
assertDistributionProperties(100, population, sample, population_size, sample_size, output);
|
||||
}
|
||||
|
||||
TEST_VM_F(JfrGTestAdaptiveSampling, uniform_rate) {
|
||||
TEST_VM_F(JfrGTestAdaptiveSampling, DISABLED_uniform_rate) {
|
||||
test(&JfrGTestAdaptiveSampling::incoming_uniform, expected_sample_points_per_window, 0.05, "random uniform, all samples");
|
||||
}
|
||||
|
||||
TEST_VM_F(JfrGTestAdaptiveSampling, low_rate) {
|
||||
TEST_VM_F(JfrGTestAdaptiveSampling, DISABLED_low_rate) {
|
||||
test(&JfrGTestAdaptiveSampling::incoming_low_rate, min_population_per_window, 0.05, "low rate");
|
||||
}
|
||||
|
||||
TEST_VM_F(JfrGTestAdaptiveSampling, high_rate) {
|
||||
TEST_VM_F(JfrGTestAdaptiveSampling, DISABLED_high_rate) {
|
||||
test(&JfrGTestAdaptiveSampling::incoming_high_rate, expected_sample_points_per_window, 0.02, "high rate");
|
||||
}
|
||||
|
||||
@ -259,23 +259,23 @@ TEST_VM_F(JfrGTestAdaptiveSampling, high_rate) {
|
||||
// - late end of the second -> each second will have sampled the window set point + accumulated debt for the first 9 windows (i.e. it will have sampled all)
|
||||
//
|
||||
|
||||
TEST_VM_F(JfrGTestAdaptiveSampling, early_burst) {
|
||||
TEST_VM_F(JfrGTestAdaptiveSampling, DISABLED_early_burst) {
|
||||
test(&JfrGTestAdaptiveSampling::incoming_early_burst, expected_sample_points_per_window, 0.9, "early burst");
|
||||
}
|
||||
|
||||
TEST_VM_F(JfrGTestAdaptiveSampling, mid_burst) {
|
||||
TEST_VM_F(JfrGTestAdaptiveSampling, DISABLED_mid_burst) {
|
||||
test(&JfrGTestAdaptiveSampling::incoming_mid_burst, expected_sample_points_per_window, 0.5, "mid burst");
|
||||
}
|
||||
|
||||
TEST_VM_F(JfrGTestAdaptiveSampling, late_burst) {
|
||||
TEST_VM_F(JfrGTestAdaptiveSampling, DISABLED_late_burst) {
|
||||
test(&JfrGTestAdaptiveSampling::incoming_late_burst, expected_sample_points_per_window, 0.0, "late burst");
|
||||
}
|
||||
|
||||
// These are randomized burst tests
|
||||
TEST_VM_F(JfrGTestAdaptiveSampling, bursty_rate_10_percent) {
|
||||
TEST_VM_F(JfrGTestAdaptiveSampling, DISABLED_bursty_rate_10_percent) {
|
||||
test(&JfrGTestAdaptiveSampling::incoming_bursty_10_percent, expected_sample_points_per_window, 0.96, "bursty 10%");
|
||||
}
|
||||
|
||||
TEST_VM_F(JfrGTestAdaptiveSampling, bursty_rate_90_percent) {
|
||||
TEST_VM_F(JfrGTestAdaptiveSampling, DISABLED_bursty_rate_90_percent) {
|
||||
test(&JfrGTestAdaptiveSampling::incoming_bursty_10_percent, expected_sample_points_per_window, 0.96, "bursty 90%");
|
||||
}
|
||||
|
@ -28,3 +28,26 @@
|
||||
#############################################################################
|
||||
|
||||
vmTestbase/nsk/jvmti/SetFieldAccessWatch/setfldw001/TestDescription.java 8205957 generic-all
|
||||
|
||||
compiler/blackhole/BlackholeDiagnosticUnlockTest.java 8258101 generic-all
|
||||
compiler/blackhole/BlackholeInstanceReturnTest.java#c1 8258101 generic-all
|
||||
compiler/blackhole/BlackholeInstanceReturnTest.java#c1-no-coops 8258101 generic-all
|
||||
compiler/blackhole/BlackholeInstanceReturnTest.java#c2 8258101 generic-all
|
||||
compiler/blackhole/BlackholeInstanceReturnTest.java#c2-no-coops 8258101 generic-all
|
||||
compiler/blackhole/BlackholeInstanceTest.java#c1 8258101 generic-all
|
||||
compiler/blackhole/BlackholeInstanceTest.java#c1-no-coops 8258101 generic-all
|
||||
compiler/blackhole/BlackholeInstanceTest.java#c2 8258101 generic-all
|
||||
compiler/blackhole/BlackholeInstanceTest.java#c2-no-coops 8258101 generic-all
|
||||
compiler/blackhole/BlackholeNonVoidWarningTest.java 8258101 generic-all
|
||||
compiler/blackhole/BlackholeNullCheckTest.java#c1 8258101 generic-all
|
||||
compiler/blackhole/BlackholeNullCheckTest.java#c1-no-coops 8258101 generic-all
|
||||
compiler/blackhole/BlackholeNullCheckTest.java#c2 8258101 generic-all
|
||||
compiler/blackhole/BlackholeNullCheckTest.java#c2-no-coops 8258101 generic-all
|
||||
compiler/blackhole/BlackholeStaticReturnTest.java#c1 8258101 generic-all
|
||||
compiler/blackhole/BlackholeStaticReturnTest.java#c1-no-coops 8258101 generic-all
|
||||
compiler/blackhole/BlackholeStaticReturnTest.java#c2 8258101 generic-all
|
||||
compiler/blackhole/BlackholeStaticReturnTest.java#c2-no-coops 8258101 generic-all
|
||||
compiler/blackhole/BlackholeStaticTest.java#c1 8258101 generic-all
|
||||
compiler/blackhole/BlackholeStaticTest.java#c1-no-coops 8258101 generic-all
|
||||
compiler/blackhole/BlackholeStaticTest.java#c2 8258101 generic-all
|
||||
compiler/blackhole/BlackholeStaticTest.java#c2-no-coops 8258101 generic-all
|
||||
|
@ -44,8 +44,6 @@ compiler/ciReplay/TestSAServer.java 8029528 generic-all
|
||||
compiler/codecache/jmx/PoolsIndependenceTest.java 8167015 generic-all
|
||||
compiler/compilercontrol/jcmd/ClearDirectivesFileStackTest.java 8225370 generic-all
|
||||
compiler/jvmci/compilerToVM/GetFlagValueTest.java 8204459 generic-all
|
||||
compiler/jvmci/compilerToVM/IsMatureVsReprofileTest.java 8257919 generic-all
|
||||
compiler/jvmci/compilerToVM/ReprofileTest.java 8257919 generic-all
|
||||
compiler/tiered/LevelTransitionTest.java 8067651 generic-all
|
||||
|
||||
compiler/cpuflags/TestAESIntrinsicsOnSupportedConfig.java 8190680 generic-all
|
||||
|
@ -0,0 +1,132 @@
|
||||
/*
|
||||
* Copyright (c) 2020, 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 8257598
|
||||
* @summary check that Record::equals uses the fields and not the accessors for the comparison
|
||||
* @run testng CheckEqualityIsBasedOnFields
|
||||
*/
|
||||
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
import org.testng.annotations.DataProvider;
|
||||
import org.testng.annotations.Test;
|
||||
|
||||
import static org.testng.Assert.*;
|
||||
|
||||
public class CheckEqualityIsBasedOnFields {
|
||||
public record R01(boolean x) {
|
||||
public boolean x() {
|
||||
return x ? x : !x;
|
||||
}
|
||||
}
|
||||
|
||||
public record R02(byte x) {
|
||||
public byte x() {
|
||||
return (x >= 50) ? (byte)(x - 50) : x;
|
||||
}
|
||||
}
|
||||
|
||||
public record R03(short x) {
|
||||
public short x() {
|
||||
return (x >= 50) ? (short)(x - 50) : x;
|
||||
}
|
||||
}
|
||||
|
||||
public record R04(char x) {
|
||||
public char x() {
|
||||
return (x >= 50) ? (char)(x - 50) : x;
|
||||
}
|
||||
}
|
||||
|
||||
public record R05(int x) {
|
||||
public int x() {
|
||||
return (x >= 50) ? (x - 50) : x;
|
||||
}
|
||||
}
|
||||
|
||||
public record R06(long x) {
|
||||
public long x() {
|
||||
return (x >= 50) ? (long)(x - 50) : x;
|
||||
}
|
||||
}
|
||||
|
||||
public record R07(float x) {
|
||||
public float x() {
|
||||
return (x >= 50) ? (float)(x - 50) : x;
|
||||
}
|
||||
}
|
||||
public record R08(double x) {
|
||||
public double x() {
|
||||
return (x >= 50) ? (double)(x - 50) : x;
|
||||
}
|
||||
}
|
||||
|
||||
public record R09(String x) {
|
||||
public String x() {
|
||||
return (x.length() > 1) ? x.substring(0, 1) : x;
|
||||
}
|
||||
}
|
||||
|
||||
@DataProvider(name = "recordData")
|
||||
public Object[][] recordTypeAndExpectedValue() {
|
||||
return new Object[][] {
|
||||
new Object[] { R01.class, boolean.class, new Object[]{true, false} },
|
||||
new Object[] { R02.class, byte.class, new Object[]{(byte)0, (byte)1, (byte)2, (byte)3, (byte)4, (byte)5,
|
||||
(byte)50, (byte)51, (byte)52, (byte)53, (byte)54, (byte)55} },
|
||||
new Object[] { R03.class, short.class, new Object[]{(short)0, (short)1, (short)2, (short)3, (short)4, (short)5,
|
||||
(short)50, (short)51, (short)52, (short)53, (short)54, (short)55} },
|
||||
new Object[] { R04.class, char.class, new Object[]{(char)0, (char)1, (char)2, (char)3, (char)4, (char)5,
|
||||
(char)50, (char)51, (char)52, (char)53, (char)54, (char)55} },
|
||||
new Object[] { R05.class, int.class, new Object[]{0, 1, 2, 3, 4, 5, 50, 51, 52, 53, 54, 55} },
|
||||
new Object[] { R06.class, long.class, new Object[]{0L, 1L, 2L, 3L, 4L, 5L, 50L, 51L, 52L, 53L, 54L, 55L} },
|
||||
new Object[] { R07.class, float.class, new Object[]{(float)0, (float)1, (float)2, (float)3, (float)4, (float)5,
|
||||
(float)50, (float)51, (float)52, (float)53, (float)54, (float)55} },
|
||||
new Object[] { R08.class, double.class, new Object[]{(double)0, (double)1, (double)2, (double)3, (double)4, (double)5,
|
||||
(double)50, (double)51, (double)52, (double)53, (double)54, (double)55} },
|
||||
new Object[] { R09.class, String.class, new Object[]{"1", "2", "3", "4", "5",
|
||||
"1_", "2_", "3_", "4_", "5_"} },
|
||||
};
|
||||
}
|
||||
|
||||
@Test(dataProvider = "recordData")
|
||||
public void testEqualsDoesntUseAccessors(Class<?> clazz, Class<?> componentClass, Object[] expectedXValues) throws Exception {
|
||||
Constructor<?> ctor;
|
||||
Method getter, equalsMethod;
|
||||
ctor = clazz.getConstructor(componentClass);
|
||||
equalsMethod = clazz.getMethod("equals", Object.class);
|
||||
getter = clazz.getMethod("x");
|
||||
for (int i = 0; i < expectedXValues.length / 2; i++) {
|
||||
Object rec1 = ctor.newInstance(expectedXValues[i]);
|
||||
Object rec2 = ctor.newInstance(expectedXValues[i + expectedXValues.length / 2]);
|
||||
System.out.println(rec1.toString());
|
||||
System.out.println(rec2.toString());
|
||||
assertFalse((boolean) equalsMethod.invoke(rec1, rec2));
|
||||
assertNotEquals(expectedXValues[i], expectedXValues[i + expectedXValues.length / 2]);
|
||||
assertEquals(getter.invoke(rec1), getter.invoke(rec2));
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,73 @@
|
||||
/*
|
||||
* Copyright (c) 2020, 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.
|
||||
*/
|
||||
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.ForkJoinPool;
|
||||
import java.util.concurrent.ThreadLocalRandom;
|
||||
import static java.util.concurrent.TimeUnit.DAYS;
|
||||
|
||||
/*
|
||||
* @test
|
||||
* @bug 8254350
|
||||
* @run main LostInterrupt
|
||||
* @summary CompletableFuture.get may swallow interrupt status
|
||||
* @key randomness
|
||||
*/
|
||||
|
||||
// TODO: Rewrite as a CompletableFuture tck test ?
|
||||
|
||||
/**
|
||||
* Submits a task that completes immediately, then invokes CompletableFuture.get
|
||||
* with the interrupt status set. CompletableFuture.get should either complete
|
||||
* immediately with the interrupt status set, or else throw InterruptedException
|
||||
* with the interrupt status cleared.
|
||||
*/
|
||||
public class LostInterrupt {
|
||||
static final int ITERATIONS = 10_000;
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
ThreadLocalRandom rnd = ThreadLocalRandom.current();
|
||||
ForkJoinPool executor = new ForkJoinPool(1);
|
||||
try {
|
||||
for (int i = 0; i < ITERATIONS; i++) {
|
||||
CompletableFuture<String> future = new CompletableFuture<>();
|
||||
boolean timed = rnd.nextBoolean();
|
||||
executor.execute(() -> future.complete("foo"));
|
||||
|
||||
Thread.currentThread().interrupt();
|
||||
try {
|
||||
String result = timed ? future.get(1, DAYS) : future.get();
|
||||
|
||||
if (!Thread.interrupted())
|
||||
throw new AssertionError("lost interrupt, run=" + i);
|
||||
} catch (InterruptedException expected) {
|
||||
if (Thread.interrupted())
|
||||
throw new AssertionError(
|
||||
"interrupt status not cleared, run=" + i);
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
executor.shutdown();
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,90 @@
|
||||
/*
|
||||
* Copyright (c) 2020, 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.
|
||||
*/
|
||||
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
import java.util.concurrent.ThreadLocalRandom;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
|
||||
/*
|
||||
* @test
|
||||
* @bug 8254350
|
||||
* @run main SwallowedInterruptedException
|
||||
* @key randomness
|
||||
*/
|
||||
|
||||
public class SwallowedInterruptedException {
|
||||
static final int ITERATIONS = 100;
|
||||
|
||||
public static void main(String[] args) throws Throwable {
|
||||
for (int i = 1; i <= ITERATIONS; i++) {
|
||||
System.out.format("Iteration %d%n", i);
|
||||
|
||||
CompletableFuture<Void> future = new CompletableFuture<>();
|
||||
CountDownLatch running = new CountDownLatch(1);
|
||||
AtomicReference<String> failed = new AtomicReference<>();
|
||||
|
||||
Thread thread = new Thread(() -> {
|
||||
// signal main thread that child is running
|
||||
running.countDown();
|
||||
|
||||
// invoke Future.get, it complete with the interrupt status set or
|
||||
// else throw InterruptedException with the interrupt status not set.
|
||||
try {
|
||||
future.get();
|
||||
|
||||
// interrupt status should be set
|
||||
if (!Thread.currentThread().isInterrupted()) {
|
||||
failed.set("Future.get completed with interrupt status not set");
|
||||
}
|
||||
} catch (InterruptedException ex) {
|
||||
// interrupt status should be cleared
|
||||
if (Thread.currentThread().isInterrupted()) {
|
||||
failed.set("InterruptedException with interrupt status set");
|
||||
}
|
||||
} catch (Throwable ex) {
|
||||
failed.set("Unexpected exception " + ex);
|
||||
}
|
||||
});
|
||||
thread.setDaemon(true);
|
||||
thread.start();
|
||||
|
||||
// wait for thread to run
|
||||
running.await();
|
||||
|
||||
// interrupt thread and set result after an optional (random) delay
|
||||
thread.interrupt();
|
||||
long sleepMillis = ThreadLocalRandom.current().nextLong(10);
|
||||
if (sleepMillis > 0)
|
||||
Thread.sleep(sleepMillis);
|
||||
future.complete(null);
|
||||
|
||||
// wait for thread to terminate and check for failure
|
||||
thread.join();
|
||||
String failedReason = failed.get();
|
||||
if (failedReason != null) {
|
||||
throw new RuntimeException("Test failed: " + failedReason);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -51,6 +51,7 @@ public class TestHtmlTableTags extends JavadocTester {
|
||||
javadoc("-d", "out",
|
||||
"-sourcepath", testSrc,
|
||||
"-use",
|
||||
"--no-platform-links",
|
||||
"pkg1", "pkg2");
|
||||
checkExit(Exit.OK);
|
||||
|
||||
@ -66,6 +67,7 @@ public class TestHtmlTableTags extends JavadocTester {
|
||||
"-nocomment",
|
||||
"-sourcepath", testSrc,
|
||||
"-use",
|
||||
"--no-platform-links",
|
||||
"pkg1", "pkg2");
|
||||
checkExit(Exit.OK);
|
||||
|
||||
@ -683,12 +685,8 @@ public class TestHtmlTableTags extends JavadocTester {
|
||||
// Constant values
|
||||
checkOutput("constant-values.html", true,
|
||||
"""
|
||||
<div class="col-first even-row-color"><code id="pkg1.C1.CONSTANT1">public s\
|
||||
tatic final <a href="https://download.java.net/java/early_access/jdk17\
|
||||
/docs/api/java.base/java/lang/String.html" title="class or interface in java.lan\
|
||||
g" class="external-link">String</a></code></div>
|
||||
<div class="col-second even-row-color"><code><a href="pkg1/C1.html#CONSTANT1">CO\
|
||||
NSTANT1</a></code></div>
|
||||
<div class="col-first even-row-color"><code id="pkg1.C1.CONSTANT1">public static final java.lang.String</code></div>
|
||||
<div class="col-second even-row-color"><code><a href="pkg1/C1.html#CONSTANT1">CONSTANT1</a></code></div>
|
||||
<div class="col-last even-row-color"><code>"C1"</code></div>
|
||||
</div>""");
|
||||
|
||||
@ -814,12 +812,8 @@ public class TestHtmlTableTags extends JavadocTester {
|
||||
// Constant values
|
||||
checkOutput("constant-values.html", true,
|
||||
"""
|
||||
<div class="col-first even-row-color"><code id="pkg1.C1.CONSTANT1">public s\
|
||||
tatic final <a href="https://download.java.net/java/early_access/jdk17\
|
||||
/docs/api/java.base/java/lang/String.html" title="class or interface in java.lan\
|
||||
g" class="external-link">String</a></code></div>
|
||||
<div class="col-second even-row-color"><code><a href="pkg1/C1.html#CONSTANT1">CO\
|
||||
NSTANT1</a></code></div>
|
||||
<div class="col-first even-row-color"><code id="pkg1.C1.CONSTANT1">public static final java.lang.String</code></div>
|
||||
<div class="col-second even-row-color"><code><a href="pkg1/C1.html#CONSTANT1">CONSTANT1</a></code></div>
|
||||
<div class="col-last even-row-color"><code>"C1"</code></div>
|
||||
</div>""");
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user