--- a/make/hotspot/lib/JvmFeatures.gmk Wed Mar 27 07:45:21 2019 -0400
+++ b/make/hotspot/lib/JvmFeatures.gmk Wed Mar 27 08:27:58 2019 -0400
@@ -1,5 +1,5 @@
#
-# Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2013, 2019, 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
@@ -126,7 +126,7 @@
JVM_CFLAGS_FEATURES += -DINCLUDE_NMT=0
JVM_EXCLUDE_FILES += \
memBaseline.cpp memReporter.cpp mallocTracker.cpp virtualMemoryTracker.cpp nmtCommon.cpp \
- memTracker.cpp nmtDCmd.cpp mallocSiteTable.cpp
+ memTracker.cpp nmtDCmd.cpp mallocSiteTable.cpp threadStackTracker.cpp
endif
ifneq ($(call check-jvm-feature, aot), true)
--- a/src/hotspot/cpu/x86/vm_version_x86.cpp Wed Mar 27 07:45:21 2019 -0400
+++ b/src/hotspot/cpu/x86/vm_version_x86.cpp Wed Mar 27 08:27:58 2019 -0400
@@ -901,11 +901,15 @@
FLAG_SET_DEFAULT(UseSHA256Intrinsics, false);
}
+#ifdef _LP64
+ // These are only supported on 64-bit
if (UseSHA && supports_avx2() && supports_bmi2()) {
if (FLAG_IS_DEFAULT(UseSHA512Intrinsics)) {
FLAG_SET_DEFAULT(UseSHA512Intrinsics, true);
}
- } else if (UseSHA512Intrinsics) {
+ } else
+#endif
+ if (UseSHA512Intrinsics) {
warning("Intrinsics for SHA-384 and SHA-512 crypto hash functions not available on this CPU.");
FLAG_SET_DEFAULT(UseSHA512Intrinsics, false);
}
--- a/src/hotspot/os_cpu/linux_s390/thread_linux_s390.cpp Wed Mar 27 07:45:21 2019 -0400
+++ b/src/hotspot/os_cpu/linux_s390/thread_linux_s390.cpp Wed Mar 27 08:27:58 2019 -0400
@@ -1,6 +1,6 @@
/*
- * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
- * Copyright (c) 2016 SAP SE. All rights reserved.
+ * Copyright (c) 2016, 2019, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2016, 2019 SAP SE. 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
@@ -63,7 +63,7 @@
if (ret_frame.is_interpreted_frame()) {
frame::z_ijava_state* istate = ret_frame.ijava_state_unchecked();
- if (!((Method*)(istate->method))->is_metaspace_object()) {
+ if ((stack_base() >= (address)istate && (address)istate > stack_end()) || !((Method*)(istate->method))->is_metaspace_object()) {
return false;
}
uint64_t reg_bcp = uc->uc_mcontext.gregs[13/*Z_BCP*/];
--- a/src/hotspot/share/gc/shared/concurrentGCThread.cpp Wed Mar 27 07:45:21 2019 -0400
+++ b/src/hotspot/share/gc/shared/concurrentGCThread.cpp Wed Mar 27 08:27:58 2019 -0400
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2001, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2001, 2019, 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
@@ -54,13 +54,6 @@
assert(this == Thread::current(), "just checking");
}
-void ConcurrentGCThread::wait_for_universe_init() {
- MutexLockerEx x(CGC_lock, Mutex::_no_safepoint_check_flag);
- while (!is_init_completed() && !_should_terminate) {
- CGC_lock->wait(Mutex::_no_safepoint_check_flag, 1);
- }
-}
-
void ConcurrentGCThread::terminate() {
assert(_should_terminate, "Should only be called on terminate request.");
// Signal that it is terminated
@@ -74,7 +67,7 @@
void ConcurrentGCThread::run() {
initialize_in_thread();
- wait_for_universe_init();
+ wait_init_completed();
run_service();
--- a/src/hotspot/share/gc/z/zNMethodTableEntry.hpp Wed Mar 27 07:45:21 2019 -0400
+++ b/src/hotspot/share/gc/z/zNMethodTableEntry.hpp Wed Mar 27 08:27:58 2019 -0400
@@ -37,13 +37,11 @@
// |11111111 11111111 11111111 11111111 11111111 11111111 11111111 111111|1|1|
// +---------------------------------------------------------------------+-+-+
// | | |
-// | | |
-// | | |
// | 1-1 Unregistered Flag (1-bits) * |
// | |
// | 0-0 Registered Flag (1-bits) *
// |
-// * 63-3 NMethod Address (61-bits)
+// * 63-2 NMethod Address (62-bits)
//
class nmethod;
--- a/src/hotspot/share/opto/graphKit.cpp Wed Mar 27 07:45:21 2019 -0400
+++ b/src/hotspot/share/opto/graphKit.cpp Wed Mar 27 08:27:58 2019 -0400
@@ -2450,6 +2450,8 @@
Node* parm2, Node* parm3,
Node* parm4, Node* parm5,
Node* parm6, Node* parm7) {
+ assert(call_addr != NULL, "must not call NULL targets");
+
// Slow-path call
bool is_leaf = !(flags & RC_NO_LEAF);
bool has_io = (!is_leaf && !(flags & RC_NO_IO));
--- a/src/hotspot/share/opto/library_call.cpp Wed Mar 27 07:45:21 2019 -0400
+++ b/src/hotspot/share/opto/library_call.cpp Wed Mar 27 08:27:58 2019 -0400
@@ -6353,6 +6353,9 @@
}
if (state == NULL) return false;
+ assert(stubAddr != NULL, "Stub is generated");
+ if (stubAddr == NULL) return false;
+
// Call the stub.
Node* call = make_runtime_call(RC_LEAF|RC_NO_FP, OptoRuntime::sha_implCompress_Type(),
stubAddr, stubName, TypePtr::BOTTOM,
@@ -6425,6 +6428,9 @@
fatal("unknown SHA intrinsic predicate: %d", predicate);
}
if (klass_SHA_name != NULL) {
+ assert(stub_addr != NULL, "Stub is generated");
+ if (stub_addr == NULL) return false;
+
// get DigestBase klass to lookup for SHA klass
const TypeInstPtr* tinst = _gvn.type(digestBase_obj)->isa_instptr();
assert(tinst != NULL, "digestBase_obj is not instance???");
--- a/src/hotspot/share/runtime/init.cpp Wed Mar 27 07:45:21 2019 -0400
+++ b/src/hotspot/share/runtime/init.cpp Wed Mar 27 08:27:58 2019 -0400
@@ -36,6 +36,7 @@
#include "runtime/handles.inline.hpp"
#include "runtime/icache.hpp"
#include "runtime/init.hpp"
+#include "runtime/orderAccess.hpp"
#include "runtime/safepoint.hpp"
#include "runtime/sharedRuntime.hpp"
#include "services/memTracker.hpp"
@@ -186,11 +187,19 @@
static volatile bool _init_completed = false;
bool is_init_completed() {
- return _init_completed;
+ return OrderAccess::load_acquire(&_init_completed);
}
+void wait_init_completed() {
+ MonitorLockerEx ml(InitCompleted_lock, Monitor::_no_safepoint_check_flag);
+ while (!_init_completed) {
+ ml.wait(Monitor::_no_safepoint_check_flag);
+ }
+}
void set_init_completed() {
assert(Universe::is_fully_initialized(), "Should have completed initialization");
- _init_completed = true;
+ MonitorLockerEx ml(InitCompleted_lock, Monitor::_no_safepoint_check_flag);
+ OrderAccess::release_store(&_init_completed, true);
+ ml.notify_all();
}
--- a/src/hotspot/share/runtime/init.hpp Wed Mar 27 07:45:21 2019 -0400
+++ b/src/hotspot/share/runtime/init.hpp Wed Mar 27 08:27:58 2019 -0400
@@ -40,6 +40,7 @@
void exit_globals(); // call destructors before exit
bool is_init_completed(); // returns true when bootstrapping has completed
+void wait_init_completed(); // wait until set_init_completed() has been called
void set_init_completed(); // set basic init to completed
#endif // SHARE_RUNTIME_INIT_HPP
--- a/src/hotspot/share/runtime/mutexLocker.cpp Wed Mar 27 07:45:21 2019 -0400
+++ b/src/hotspot/share/runtime/mutexLocker.cpp Wed Mar 27 08:27:58 2019 -0400
@@ -97,6 +97,7 @@
Mutex* DirectivesStack_lock = NULL;
Mutex* MultiArray_lock = NULL;
Monitor* Terminator_lock = NULL;
+Monitor* InitCompleted_lock = NULL;
Monitor* BeforeExit_lock = NULL;
Monitor* Notify_lock = NULL;
Mutex* ProfilePrint_lock = NULL;
@@ -283,6 +284,7 @@
def(VMOperationRequest_lock , PaddedMonitor, nonleaf, true, Monitor::_safepoint_check_sometimes);
def(RetData_lock , PaddedMutex , nonleaf, false, Monitor::_safepoint_check_always);
def(Terminator_lock , PaddedMonitor, nonleaf, true, Monitor::_safepoint_check_sometimes);
+ def(InitCompleted_lock , PaddedMonitor, leaf, true, Monitor::_safepoint_check_never);
def(VtableStubs_lock , PaddedMutex , nonleaf, true, Monitor::_safepoint_check_never);
def(Notify_lock , PaddedMonitor, nonleaf, true, Monitor::_safepoint_check_always);
def(JNIGlobalAlloc_lock , PaddedMutex , nonleaf, true, Monitor::_safepoint_check_never);
--- a/src/hotspot/share/runtime/mutexLocker.hpp Wed Mar 27 07:45:21 2019 -0400
+++ b/src/hotspot/share/runtime/mutexLocker.hpp Wed Mar 27 08:27:58 2019 -0400
@@ -96,6 +96,7 @@
extern Mutex* DirectivesStack_lock; // a lock held when mutating the dirstack and ref counting directives
extern Mutex* MultiArray_lock; // a lock used to guard allocation of multi-dim arrays
extern Monitor* Terminator_lock; // a lock used to guard termination of the vm
+extern Monitor* InitCompleted_lock; // a lock used to signal threads waiting on init completed
extern Monitor* BeforeExit_lock; // a lock used to guard cleanups and shutdown hooks
extern Monitor* Notify_lock; // a lock used to synchronize the start-up of the vm
extern Mutex* ProfilePrint_lock; // a lock used to serialize the printing of profiles
--- a/src/hotspot/share/runtime/synchronizer.cpp Wed Mar 27 07:45:21 2019 -0400
+++ b/src/hotspot/share/runtime/synchronizer.cpp Wed Mar 27 08:27:58 2019 -0400
@@ -1270,6 +1270,21 @@
}
Thread::muxRelease(&gListLock);
+
+ LogStreamHandle(Debug, monitorinflation) lsh_debug;
+ LogStreamHandle(Info, monitorinflation) lsh_info;
+ LogStream * ls = NULL;
+ if (log_is_enabled(Debug, monitorinflation)) {
+ ls = &lsh_debug;
+ } else if ((tally != 0 || inUseTally != 0) &&
+ log_is_enabled(Info, monitorinflation)) {
+ ls = &lsh_info;
+ }
+ if (ls != NULL) {
+ ls->print_cr("omFlush: jt=" INTPTR_FORMAT ", free_monitor_tally=%d"
+ ", in_use_monitor_tally=%d" ", omFreeProvision=%d",
+ p2i(Self), tally, inUseTally, Self->omFreeProvision);
+ }
}
static void post_monitor_inflate_event(EventJavaMonitorInflate* event,
@@ -1665,24 +1680,18 @@
// than a beginning to end measurement of the phase.
log_info(safepoint, cleanup)("deflating per-thread idle monitors, %3.7f secs, monitors=%d", counters->perThreadTimes, counters->perThreadScavenged);
- LogStreamHandle(Debug, monitorinflation) lsh_debug;
- LogStreamHandle(Info, monitorinflation) lsh_info;
- LogStream * ls = NULL;
- if (log_is_enabled(Debug, monitorinflation)) {
- ls = &lsh_debug;
- } else if (counters->perThreadScavenged != 0 && log_is_enabled(Info, monitorinflation)) {
- ls = &lsh_info;
- }
- if (ls != NULL) {
- ls->print_cr("deflating per-thread idle monitors, %3.7f secs, %d monitors", counters->perThreadTimes, counters->perThreadScavenged);
- }
-
gMonitorFreeCount += counters->nScavenged;
if (log_is_enabled(Debug, monitorinflation)) {
// exit_globals()'s call to audit_and_print_stats() is done
// at the Info level.
ObjectSynchronizer::audit_and_print_stats(false /* on_exit */);
+ } else if (log_is_enabled(Info, monitorinflation)) {
+ Thread::muxAcquire(&gListLock, "finish_deflate_idle_monitors");
+ log_info(monitorinflation)("gMonitorPopulation=%d, gOmInUseCount=%d, "
+ "gMonitorFreeCount=%d", gMonitorPopulation,
+ gOmInUseCount, gMonitorFreeCount);
+ Thread::muxRelease(&gListLock);
}
ForceMonitorScavenge = 0; // Reset
@@ -1708,8 +1717,6 @@
int deflated_count = deflate_monitor_list(thread->omInUseList_addr(), &freeHeadp, &freeTailp);
- timer.stop();
-
Thread::muxAcquire(&gListLock, "deflate_thread_local_monitors");
// Adjust counters
@@ -1718,8 +1725,6 @@
counters->nScavenged += deflated_count;
counters->nInuse += thread->omInUseCount;
counters->perThreadScavenged += deflated_count;
- // For now, we only care about cumulative per-thread deflation time.
- counters->perThreadTimes += timer.seconds();
// Move the scavenged monitors back to the global free list.
if (freeHeadp != NULL) {
@@ -1730,7 +1735,26 @@
freeTailp->FreeNext = gFreeList;
gFreeList = freeHeadp;
}
+
+ timer.stop();
+ // Safepoint logging cares about cumulative perThreadTimes and
+ // we'll capture most of the cost, but not the muxRelease() which
+ // should be cheap.
+ counters->perThreadTimes += timer.seconds();
+
Thread::muxRelease(&gListLock);
+
+ LogStreamHandle(Debug, monitorinflation) lsh_debug;
+ LogStreamHandle(Info, monitorinflation) lsh_info;
+ LogStream * ls = NULL;
+ if (log_is_enabled(Debug, monitorinflation)) {
+ ls = &lsh_debug;
+ } else if (deflated_count != 0 && log_is_enabled(Info, monitorinflation)) {
+ ls = &lsh_info;
+ }
+ if (ls != NULL) {
+ ls->print_cr("jt=" INTPTR_FORMAT ": deflating per-thread idle monitors, %3.7f secs, %d monitors", p2i(thread), timer.seconds(), deflated_count);
+ }
}
// Monitor cleanup on JavaThread::exit
@@ -1839,13 +1863,13 @@
// Check gMonitorPopulation:
if (gMonitorPopulation == chkMonitorPopulation) {
- ls->print_cr("gMonitorPopulation=%d equals chkMonitorPopulation=%d",
- gMonitorPopulation, chkMonitorPopulation);
+ ls->print_cr("gMonitorPopulation=%d equals chkMonitorPopulation=%d",
+ gMonitorPopulation, chkMonitorPopulation);
} else {
- ls->print_cr("ERROR: gMonitorPopulation=%d is not equal to "
- "chkMonitorPopulation=%d", gMonitorPopulation,
- chkMonitorPopulation);
- error_cnt++;
+ ls->print_cr("ERROR: gMonitorPopulation=%d is not equal to "
+ "chkMonitorPopulation=%d", gMonitorPopulation,
+ chkMonitorPopulation);
+ error_cnt++;
}
// Check gOmInUseList and gOmInUseCount:
--- a/src/hotspot/share/runtime/synchronizer.hpp Wed Mar 27 07:45:21 2019 -0400
+++ b/src/hotspot/share/runtime/synchronizer.hpp Wed Mar 27 08:27:58 2019 -0400
@@ -199,11 +199,11 @@
static u_char* get_gvars_stwRandom_addr();
};
-// ObjectLocker enforced balanced locking and can never thrown an
+// ObjectLocker enforces balanced locking and can never throw an
// IllegalMonitorStateException. However, a pending exception may
// have to pass through, and we must also be able to deal with
// asynchronous exceptions. The caller is responsible for checking
-// the threads pending exception if needed.
+// the thread's pending exception if needed.
class ObjectLocker : public StackObj {
private:
Thread* _thread;
--- a/src/hotspot/share/runtime/thread.cpp Wed Mar 27 07:45:21 2019 -0400
+++ b/src/hotspot/share/runtime/thread.cpp Wed Mar 27 08:27:58 2019 -0400
@@ -4449,7 +4449,7 @@
void Threads::remove(JavaThread* p) {
- // Reclaim the objectmonitors from the omInUseList and omFreeList of the moribund thread.
+ // Reclaim the ObjectMonitors from the omInUseList and omFreeList of the moribund thread.
ObjectSynchronizer::omFlush(p);
// Extra scope needed for Thread_lock, so we can check
--- a/src/hotspot/share/services/memBaseline.cpp Wed Mar 27 07:45:21 2019 -0400
+++ b/src/hotspot/share/services/memBaseline.cpp Wed Mar 27 08:27:58 2019 -0400
@@ -156,6 +156,11 @@
return false;
}
+ // Walk simple thread stacks
+ if (!ThreadStackTracker::walk_simple_thread_stack_site(&malloc_walker)) {
+ return false;
+ }
+
_malloc_sites.move(malloc_walker.malloc_sites());
// The malloc sites are collected in size order
_malloc_sites_order = by_size;
--- a/src/hotspot/share/services/memReporter.cpp Wed Mar 27 07:45:21 2019 -0400
+++ b/src/hotspot/share/services/memReporter.cpp Wed Mar 27 08:27:58 2019 -0400
@@ -26,6 +26,7 @@
#include "memory/allocation.hpp"
#include "services/mallocTracker.hpp"
#include "services/memReporter.hpp"
+#include "services/threadStackTracker.hpp"
#include "services/virtualMemoryTracker.hpp"
#include "utilities/globalDefinitions.hpp"
@@ -46,11 +47,13 @@
void MemReporterBase::print_malloc(size_t amount, size_t count, MEMFLAGS flag) const {
const char* scale = current_scale();
outputStream* out = output();
+ const char* alloc_type = (flag == mtThreadStack) ? "" : "malloc=";
+
if (flag != mtNone) {
- out->print("(malloc=" SIZE_FORMAT "%s type=%s",
+ out->print("(%s" SIZE_FORMAT "%s type=%s", alloc_type,
amount_in_current_scale(amount), scale, NMTUtil::flag_to_name(flag));
} else {
- out->print("(malloc=" SIZE_FORMAT "%s",
+ out->print("(%s" SIZE_FORMAT "%s", alloc_type,
amount_in_current_scale(amount), scale);
}
@@ -126,10 +129,17 @@
// Count thread's native stack in "Thread" category
if (flag == mtThread) {
- const VirtualMemory* thread_stack_usage =
- (const VirtualMemory*)_vm_snapshot->by_type(mtThreadStack);
- reserved_amount += thread_stack_usage->reserved();
- committed_amount += thread_stack_usage->committed();
+ if (ThreadStackTracker::track_as_vm()) {
+ const VirtualMemory* thread_stack_usage =
+ (const VirtualMemory*)_vm_snapshot->by_type(mtThreadStack);
+ reserved_amount += thread_stack_usage->reserved();
+ committed_amount += thread_stack_usage->committed();
+ } else {
+ const MallocMemory* thread_stack_usage =
+ (const MallocMemory*)_malloc_snapshot->by_type(mtThreadStack);
+ reserved_amount += thread_stack_usage->malloc_size();
+ committed_amount += thread_stack_usage->malloc_size();
+ }
} else if (flag == mtNMT) {
// Count malloc headers in "NMT" category
reserved_amount += _malloc_snapshot->malloc_overhead()->size();
@@ -150,12 +160,22 @@
out->print_cr("%27s ( instance classes #" SIZE_FORMAT ", array classes #" SIZE_FORMAT ")",
" ", _instance_class_count, _array_class_count);
} else if (flag == mtThread) {
- // report thread count
- out->print_cr("%27s (thread #" SIZE_FORMAT ")", " ", _malloc_snapshot->thread_count());
- const VirtualMemory* thread_stack_usage =
- _vm_snapshot->by_type(mtThreadStack);
- out->print("%27s (stack: ", " ");
- print_total(thread_stack_usage->reserved(), thread_stack_usage->committed());
+ if (ThreadStackTracker::track_as_vm()) {
+ const VirtualMemory* thread_stack_usage =
+ _vm_snapshot->by_type(mtThreadStack);
+ // report thread count
+ out->print_cr("%27s (thread #" SIZE_FORMAT ")", " ", ThreadStackTracker::thread_count());
+ out->print("%27s (stack: ", " ");
+ print_total(thread_stack_usage->reserved(), thread_stack_usage->committed());
+ } else {
+ MallocMemory* thread_stack_memory = _malloc_snapshot->by_type(mtThreadStack);
+ const char* scale = current_scale();
+ // report thread count
+ assert(ThreadStackTracker::thread_count() == 0, "Not used");
+ out->print_cr("%27s (thread #" SIZE_FORMAT ")", " ", thread_stack_memory->malloc_count());
+ out->print("%27s (Stack: " SIZE_FORMAT "%s", " ",
+ amount_in_current_scale(thread_stack_memory->malloc_size()), scale);
+ }
out->print_cr(")");
}
@@ -368,10 +388,11 @@
size_t early_amount, size_t early_count, MEMFLAGS flags) const {
const char* scale = current_scale();
outputStream* out = output();
+ const char* alloc_type = (flags == mtThread) ? "" : "malloc=";
- out->print("malloc=" SIZE_FORMAT "%s", amount_in_current_scale(current_amount), scale);
- // Report type only if it is valid
- if (flags != mtNone) {
+ out->print("%s" SIZE_FORMAT "%s", alloc_type, amount_in_current_scale(current_amount), scale);
+ // Report type only if it is valid and not under "thread" category
+ if (flags != mtNone && flags != mtThread) {
out->print(" type=%s", NMTUtil::flag_to_name(flags));
}
@@ -497,15 +518,25 @@
}
out->print_cr(")");
- // report thread stack
- const VirtualMemory* current_thread_stack =
+ out->print("%27s (stack: ", " ");
+ if (ThreadStackTracker::track_as_vm()) {
+ // report thread stack
+ const VirtualMemory* current_thread_stack =
_current_baseline.virtual_memory(mtThreadStack);
- const VirtualMemory* early_thread_stack =
- _early_baseline.virtual_memory(mtThreadStack);
+ const VirtualMemory* early_thread_stack =
+ _early_baseline.virtual_memory(mtThreadStack);
- out->print("%27s (stack: ", " ");
- print_virtual_memory_diff(current_thread_stack->reserved(), current_thread_stack->committed(),
- early_thread_stack->reserved(), early_thread_stack->committed());
+ print_virtual_memory_diff(current_thread_stack->reserved(), current_thread_stack->committed(),
+ early_thread_stack->reserved(), early_thread_stack->committed());
+ } else {
+ const MallocMemory* current_thread_stack =
+ _current_baseline.malloc_memory(mtThreadStack);
+ const MallocMemory* early_thread_stack =
+ _early_baseline.malloc_memory(mtThreadStack);
+
+ print_malloc_diff(current_thread_stack->malloc_size(), current_thread_stack->malloc_count(),
+ early_thread_stack->malloc_size(), early_thread_stack->malloc_count(), flag);
+ }
out->print_cr(")");
}
--- a/src/hotspot/share/services/memTracker.cpp Wed Mar 27 07:45:21 2019 -0400
+++ b/src/hotspot/share/services/memTracker.cpp Wed Mar 27 08:27:58 2019 -0400
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2012, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2019, 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
@@ -31,6 +31,7 @@
#include "services/memReporter.hpp"
#include "services/mallocTracker.inline.hpp"
#include "services/memTracker.hpp"
+#include "services/threadStackTracker.hpp"
#include "utilities/debug.hpp"
#include "utilities/defaultStream.hpp"
#include "utilities/vmError.hpp"
@@ -92,7 +93,8 @@
void MemTracker::init() {
NMT_TrackingLevel level = tracking_level();
if (level >= NMT_summary) {
- if (!VirtualMemoryTracker::late_initialize(level)) {
+ if (!VirtualMemoryTracker::late_initialize(level) ||
+ !ThreadStackTracker::late_initialize(level)) {
shutdown();
return;
}
@@ -164,6 +166,7 @@
OrderAccess::fence();
VirtualMemoryTracker::transition(current_level, level);
MallocTracker::transition(current_level, level);
+ ThreadStackTracker::transition(current_level, level);
} else {
// Upgrading tracking level is not supported and has never been supported.
// Allocating and deallocating malloc tracking structures is not thread safe and
--- a/src/hotspot/share/services/memTracker.hpp Wed Mar 27 07:45:21 2019 -0400
+++ b/src/hotspot/share/services/memTracker.hpp Wed Mar 27 08:27:58 2019 -0400
@@ -82,6 +82,7 @@
#include "runtime/mutexLocker.hpp"
#include "runtime/threadCritical.hpp"
#include "services/mallocTracker.hpp"
+#include "services/threadStackTracker.hpp"
#include "services/virtualMemoryTracker.hpp"
extern volatile bool NMT_stack_walkable;
@@ -241,31 +242,19 @@
}
}
-#ifdef _AIX
- // See JDK-8202772 - temporarily disable thread stack tracking on AIX.
- static inline void record_thread_stack(void* addr, size_t size) {}
- static inline void release_thread_stack(void* addr, size_t size) {}
-#else
- static inline void record_thread_stack(void* addr, size_t size) {
+ static void record_thread_stack(void* addr, size_t size) {
if (tracking_level() < NMT_summary) return;
if (addr != NULL) {
- // uses thread stack malloc slot for book keeping number of threads
- MallocMemorySummary::record_malloc(0, mtThreadStack);
- record_virtual_memory_reserve(addr, size, CALLER_PC, mtThreadStack);
+ ThreadStackTracker::new_thread_stack((address)addr, size, CALLER_PC);
}
}
static inline void release_thread_stack(void* addr, size_t size) {
if (tracking_level() < NMT_summary) return;
if (addr != NULL) {
- // uses thread stack malloc slot for book keeping number of threads
- MallocMemorySummary::record_free(0, mtThreadStack);
- ThreadCritical tc;
- if (tracking_level() < NMT_summary) return;
- VirtualMemoryTracker::remove_released_region((address)addr, size);
+ ThreadStackTracker::delete_thread_stack((address)addr, size);
}
}
-#endif
// Query lock is used to synchronize the access to tracking data.
// So far, it is only used by JCmd query, but it may be used by
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hotspot/share/services/threadStackTracker.cpp Wed Mar 27 08:27:58 2019 -0400
@@ -0,0 +1,133 @@
+/*
+ * Copyright (c) 2019, Red Hat, Inc. All rights reserved.
+ *
+ * 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 "runtime/atomic.hpp"
+#include "runtime/threadCritical.hpp"
+#include "services/mallocTracker.hpp"
+#include "services/memTracker.hpp"
+#include "services/virtualMemoryTracker.hpp"
+#include "services/threadStackTracker.hpp"
+
+volatile size_t ThreadStackTracker::_thread_count = 0;
+SortedLinkedList<SimpleThreadStackSite, ThreadStackTracker::compare_thread_stack_base>* ThreadStackTracker::_simple_thread_stacks = NULL;
+
+bool ThreadStackTracker::late_initialize(NMT_TrackingLevel level) {
+ if (level == NMT_detail && !track_as_vm()) {
+ _simple_thread_stacks = new (std::nothrow, ResourceObj::C_HEAP, mtNMT)
+ SortedLinkedList<SimpleThreadStackSite, ThreadStackTracker::compare_thread_stack_base>();
+ return (_simple_thread_stacks != NULL);
+ }
+ return true;
+}
+
+bool ThreadStackTracker::transition(NMT_TrackingLevel from, NMT_TrackingLevel to) {
+ assert (from != NMT_minimal, "cannot convert from the lowest tracking level to anything");
+ if (to == NMT_minimal) {
+ assert(from == NMT_summary || from == NMT_detail, "Just check");
+ ThreadCritical tc;
+ if (_simple_thread_stacks != NULL) {
+ delete _simple_thread_stacks;
+ _simple_thread_stacks = NULL;
+ }
+ }
+ return true;
+}
+
+int ThreadStackTracker::compare_thread_stack_base(const SimpleThreadStackSite& s1, const SimpleThreadStackSite& s2) {
+ return s1.base() - s2.base();
+}
+
+void ThreadStackTracker::new_thread_stack(void* base, size_t size, const NativeCallStack& stack) {
+ assert(MemTracker::tracking_level() >= NMT_summary, "Must be");
+ assert(base != NULL, "Should have been filtered");
+ if (track_as_vm()) {
+ ThreadCritical tc;
+ VirtualMemoryTracker::add_reserved_region((address)base, size, stack, mtThreadStack);
+ _thread_count ++;
+ } else {
+ // Use a slot in mallocMemorySummary for thread stack bookkeeping
+ MallocMemorySummary::record_malloc(size, mtThreadStack);
+ if (MemTracker::tracking_level() == NMT_detail) {
+ ThreadCritical tc;
+ assert(_simple_thread_stacks != NULL, "Must be initialized");
+ SimpleThreadStackSite site((address)base, size, stack);
+ _simple_thread_stacks->add(site);
+ }
+ }
+}
+
+void ThreadStackTracker::delete_thread_stack(void* base, size_t size) {
+ assert(MemTracker::tracking_level() >= NMT_summary, "Must be");
+ assert(base != NULL, "Should have been filtered");
+ if(track_as_vm()) {
+ ThreadCritical tc;
+ VirtualMemoryTracker::remove_released_region((address)base, size);
+ _thread_count--;
+ } else {
+ // Use a slot in mallocMemorySummary for thread stack bookkeeping
+ MallocMemorySummary::record_free(size, mtThreadStack);
+ if (MemTracker::tracking_level() == NMT_detail) {
+ ThreadCritical tc;
+ assert(_simple_thread_stacks != NULL, "Must be initialized");
+ SimpleThreadStackSite site((address)base, size);
+ bool removed = _simple_thread_stacks->remove(site);
+ assert(removed, "Must exist");
+ }
+ }
+}
+
+bool ThreadStackTracker::walk_simple_thread_stack_site(MallocSiteWalker* walker) {
+ if (!track_as_vm()) {
+ LinkedListImpl<MallocSite> _sites;
+ {
+ ThreadCritical tc;
+ assert(_simple_thread_stacks != NULL, "Must be initialized");
+ LinkedListIterator<SimpleThreadStackSite> itr(_simple_thread_stacks->head());
+ const SimpleThreadStackSite* ts = itr.next();
+ // Consolidate sites and convert to MallocSites, so we can piggyback into
+ // malloc snapshot
+ while (ts != NULL) {
+ MallocSite site(*ts->call_stack(), mtThreadStack);
+ MallocSite* exist = _sites.find(site);
+ if (exist != NULL) {
+ exist->allocate(ts->size());
+ } else {
+ site.allocate(ts->size());
+ _sites.add(site);
+ }
+ ts = itr.next();
+ }
+ }
+
+ // Piggyback to malloc snapshot
+ LinkedListIterator<MallocSite> site_itr(_sites.head());
+ const MallocSite* s = site_itr.next();
+ while (s != NULL) {
+ walker->do_malloc_site(s);
+ s = site_itr.next();
+ }
+ }
+ return true;
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hotspot/share/services/threadStackTracker.hpp Wed Mar 27 08:27:58 2019 -0400
@@ -0,0 +1,114 @@
+/*
+ * Copyright (c) 2019, Red Hat, Inc. All rights reserved.
+ *
+ * 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_SERVICES_THREADSTACKTRACKER_HPP
+#define SHARE_SERVICES_THREADSTACKTRACKER_HPP
+
+#if INCLUDE_NMT
+
+#include "services/allocationSite.hpp"
+#include "services/mallocSiteTable.hpp"
+#include "services/nmtCommon.hpp"
+#include "utilities/nativeCallStack.hpp"
+#include "utilities/linkedlist.hpp"
+
+class SimpleThreadStackSite;
+
+class SimpleThreadStack {
+ friend class SimpleThreadStackSite;
+private:
+ address _base;
+ size_t _size;
+public:
+ SimpleThreadStack() : _base(NULL), _size(0) { }
+ bool equals(const SimpleThreadStack& s) const {
+ return base() == s.base();
+ }
+
+ size_t size() const { return _size; }
+ address base() const { return _base; }
+private:
+ void set_size(size_t size) { _size = size; }
+ void set_base(address base) { _base = base; }
+};
+
+class SimpleThreadStackSite : public AllocationSite<SimpleThreadStack> {
+public:
+ SimpleThreadStackSite(address base, size_t size, const NativeCallStack& stack) :
+ AllocationSite<SimpleThreadStack>(stack, mtThreadStack) {
+ data()->set_size(size);
+ data()->set_base(base);
+ }
+
+ SimpleThreadStackSite(address base, size_t size) :
+ AllocationSite<SimpleThreadStack>(NativeCallStack::empty_stack(), mtThreadStack) {
+ data()->set_base(base);
+ data()->set_size(size);
+ }
+
+ bool equals(const SimpleThreadStackSite& mts) const {
+ bool eq = base() == mts.base();
+ assert(!eq || size() == mts.size(), "Must match");
+ return eq;
+ }
+
+ size_t size() const { return peek()->size(); }
+ address base() const { return peek()->base(); }
+};
+
+ /*
+ * Most of platforms, that hotspot support, have their thread stacks backed by
+ * virtual memory by default. For these cases, thread stack tracker simply
+ * delegates tracking to virtual memory tracker.
+ * However, there are exceptions, (e.g. AIX), that platforms can provide stacks
+ * that are not page aligned. A hypothetical VM implementation, it can provide
+ * it own stacks. In these case, track_as_vm() should return false and manage
+ * stack tracking by this tracker internally.
+ * During memory snapshot, tracked thread stacks memory data is walked and stored
+ * along with malloc'd data inside baseline. The regions are not scanned and assumed
+ * all committed for now. Can add scanning phase when there is a need.
+ */
+class ThreadStackTracker : AllStatic {
+private:
+ static volatile size_t _thread_count;
+
+ static int compare_thread_stack_base(const SimpleThreadStackSite& s1, const SimpleThreadStackSite& s2);
+ static SortedLinkedList<SimpleThreadStackSite, compare_thread_stack_base>* _simple_thread_stacks;
+public:
+ // Late phase initialization
+ static bool late_initialize(NMT_TrackingLevel level);
+ static bool transition(NMT_TrackingLevel from, NMT_TrackingLevel to);
+
+ static void new_thread_stack(void* base, size_t size, const NativeCallStack& stack);
+ static void delete_thread_stack(void* base, size_t size);
+
+ static bool track_as_vm() { return AIX_ONLY(false) NOT_AIX(true); }
+ static size_t thread_count() { return _thread_count; }
+
+ // Snapshot support. Piggyback thread stack data in malloc slot, NMT always handles
+ // thread stack slot specially since beginning.
+ static bool walk_simple_thread_stack_site(MallocSiteWalker* walker);
+};
+
+#endif // INCLUDE_NMT
+#endif // SHARE_SERVICES_THREADSTACKTRACKER_HPP
--- a/src/hotspot/share/services/virtualMemoryTracker.cpp Wed Mar 27 07:45:21 2019 -0400
+++ b/src/hotspot/share/services/virtualMemoryTracker.cpp Wed Mar 27 08:27:58 2019 -0400
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2019, 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
@@ -29,6 +29,7 @@
#include "runtime/os.hpp"
#include "runtime/threadCritical.hpp"
#include "services/memTracker.hpp"
+#include "services/threadStackTracker.hpp"
#include "services/virtualMemoryTracker.hpp"
size_t VirtualMemorySummary::_snapshot[CALC_OBJ_SIZE_IN_TYPE(VirtualMemorySnapshot, size_t)];
@@ -40,9 +41,12 @@
}
void VirtualMemorySummary::snapshot(VirtualMemorySnapshot* s) {
- // Snapshot current thread stacks
- VirtualMemoryTracker::snapshot_thread_stacks();
- as_snapshot()->copy_to(s);
+ // Only if thread stack is backed by virtual memory
+ if (ThreadStackTracker::track_as_vm()) {
+ // Snapshot current thread stacks
+ VirtualMemoryTracker::snapshot_thread_stacks();
+ as_snapshot()->copy_to(s);
+ }
}
SortedLinkedList<ReservedMemoryRegion, compare_reserved_region_base>* VirtualMemoryTracker::_reserved_regions;
--- a/src/java.base/share/classes/java/lang/invoke/MethodHandles.java Wed Mar 27 07:45:21 2019 -0400
+++ b/src/java.base/share/classes/java/lang/invoke/MethodHandles.java Wed Mar 27 08:27:58 2019 -0400
@@ -422,6 +422,10 @@
* because the desired class member is missing, or because the
* desired class member is not accessible to the lookup class, or
* because the lookup object is not trusted enough to access the member.
+ * In the case of a field setter function on a {@code final} field,
+ * finality enforcement is treated as a kind of access control,
+ * and the lookup will fail, except in special cases of
+ * {@link Lookup#unreflectSetter Lookup.unreflectSetter}.
* In any of these cases, a {@code ReflectiveOperationException} will be
* thrown from the attempted lookup. The exact class will be one of
* the following:
@@ -1438,6 +1442,7 @@
* @return a method handle which can store values into the field
* @throws NoSuchFieldException if the field does not exist
* @throws IllegalAccessException if access checking fails, or if the field is {@code static}
+ * or {@code final}
* @exception SecurityException if a security manager is present and it
* <a href="MethodHandles.Lookup.html#secmgr">refuses access</a>
* @throws NullPointerException if any argument is null
@@ -1561,6 +1566,7 @@
* @return a method handle which can store values into the field
* @throws NoSuchFieldException if the field does not exist
* @throws IllegalAccessException if access checking fails, or if the field is not {@code static}
+ * or is {@code final}
* @exception SecurityException if a security manager is present and it
* <a href="MethodHandles.Lookup.html#secmgr">refuses access</a>
* @throws NullPointerException if any argument is null
@@ -1840,10 +1846,10 @@
* Produces a method handle giving read access to a reflected field.
* The type of the method handle will have a return type of the field's
* value type.
- * If the field is static, the method handle will take no arguments.
+ * If the field is {@code static}, the method handle will take no arguments.
* Otherwise, its single argument will be the instance containing
* the field.
- * If the field's {@code accessible} flag is not set,
+ * If the {@code Field} object's {@code accessible} flag is not set,
* access checking is performed immediately on behalf of the lookup class.
* <p>
* If the field is static, and
@@ -1857,8 +1863,43 @@
public MethodHandle unreflectGetter(Field f) throws IllegalAccessException {
return unreflectField(f, false);
}
+
+ /**
+ * Produces a method handle giving write access to a reflected field.
+ * The type of the method handle will have a void return type.
+ * If the field is {@code static}, the method handle will take a single
+ * argument, of the field's value type, the value to be stored.
+ * Otherwise, the two arguments will be the instance containing
+ * the field, and the value to be stored.
+ * If the {@code Field} object's {@code accessible} flag is not set,
+ * access checking is performed immediately on behalf of the lookup class.
+ * <p>
+ * If the field is {@code final}, write access will not be
+ * allowed and access checking will fail, except under certain
+ * narrow circumstances documented for {@link Field#set Field.set}.
+ * A method handle is returned only if a corresponding call to
+ * the {@code Field} object's {@code set} method could return
+ * normally. In particular, fields which are both {@code static}
+ * and {@code final} may never be set.
+ * <p>
+ * If the field is {@code static}, and
+ * if the returned method handle is invoked, the field's class will
+ * be initialized, if it has not already been initialized.
+ * @param f the reflected field
+ * @return a method handle which can store values into the reflected field
+ * @throws IllegalAccessException if access checking fails,
+ * or if the field is {@code final} and write access
+ * is not enabled on the {@code Field} object
+ * @throws NullPointerException if the argument is null
+ */
+ public MethodHandle unreflectSetter(Field f) throws IllegalAccessException {
+ return unreflectField(f, true);
+ }
+
private MethodHandle unreflectField(Field f, boolean isSetter) throws IllegalAccessException {
MemberName field = new MemberName(f, isSetter);
+ if (isSetter && field.isStatic() && field.isFinal())
+ throw field.makeAccessException("static final field has no write access", this);
assert(isSetter
? MethodHandleNatives.refKindIsSetter(field.getReferenceKind())
: MethodHandleNatives.refKindIsGetter(field.getReferenceKind()));
@@ -1868,28 +1909,6 @@
}
/**
- * Produces a method handle giving write access to a reflected field.
- * The type of the method handle will have a void return type.
- * If the field is static, the method handle will take a single
- * argument, of the field's value type, the value to be stored.
- * Otherwise, the two arguments will be the instance containing
- * the field, and the value to be stored.
- * If the field's {@code accessible} flag is not set,
- * access checking is performed immediately on behalf of the lookup class.
- * <p>
- * If the field is static, and
- * if the returned method handle is invoked, the field's class will
- * be initialized, if it has not already been initialized.
- * @param f the reflected field
- * @return a method handle which can store values into the reflected field
- * @throws IllegalAccessException if access checking fails
- * @throws NullPointerException if the argument is null
- */
- public MethodHandle unreflectSetter(Field f) throws IllegalAccessException {
- return unreflectField(f, true);
- }
-
- /**
* Produces a VarHandle giving access to a reflected field {@code f}
* of type {@code T} declared in a class of type {@code R}.
* The VarHandle's variable type is {@code T}.
--- a/src/java.compiler/share/classes/javax/tools/StandardJavaFileManager.java Wed Mar 27 07:45:21 2019 -0400
+++ b/src/java.compiler/share/classes/javax/tools/StandardJavaFileManager.java Wed Mar 27 08:27:58 2019 -0400
@@ -28,9 +28,11 @@
import java.io.File;
import java.io.IOException;
import java.nio.file.Path;
+import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Iterator;
+import java.util.List;
/**
* File manager based on {@linkplain File java.io.File} and {@linkplain Path java.nio.file.Path}.
@@ -199,11 +201,40 @@
* a directory or if this file manager does not support any of the
* given paths.
*
- * @since 9
+ * @since 13
*/
default Iterable<? extends JavaFileObject> getJavaFileObjectsFromPaths(
+ Collection<? extends Path> paths) {
+ return getJavaFileObjectsFromFiles(asFiles(paths));
+ }
+
+ /**
+ * Returns file objects representing the given paths.
+ *
+ * @implSpec
+ * The default implementation converts each path to a file and calls
+ * {@link #getJavaFileObjectsFromFiles getJavaObjectsFromFiles}.
+ * IllegalArgumentException will be thrown if any of the paths
+ * cannot be converted to a file.
+ *
+ * @param paths a list of paths
+ * @return a list of file objects
+ * @throws IllegalArgumentException if the list of paths includes
+ * a directory or if this file manager does not support any of the
+ * given paths.
+ *
+ * @since 9
+ * @deprecated use {@link #getJavaFileObjectsFromPaths(Collection)} instead,
+ * to prevent the possibility of accidentally calling the method with a
+ * single {@code Path} as such an argument. Although {@code Path} implements
+ * {@code Iterable<Path>}, it would almost never be correct to pass a single
+ * {@code Path} and have it be treated as an {@code Iterable} of its
+ * components.
+ */
+ @Deprecated(since = "13")
+ default Iterable<? extends JavaFileObject> getJavaFileObjectsFromPaths(
Iterable<? extends Path> paths) {
- return getJavaFileObjectsFromFiles(asFiles(paths));
+ return getJavaFileObjectsFromPaths(asCollection(paths));
}
/**
@@ -484,4 +515,13 @@
}
};
}
+
+ private static <T> Collection<T> asCollection(Iterable<T> iterable) {
+ if (iterable instanceof Collection) {
+ return (Collection<T>) iterable;
+ }
+ List<T> result = new ArrayList<>();
+ for (T item : iterable) result.add(item);
+ return result;
+ }
}
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/api/ClientCodeWrapper.java Wed Mar 27 07:45:21 2019 -0400
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/api/ClientCodeWrapper.java Wed Mar 27 08:27:58 2019 -0400
@@ -437,6 +437,18 @@
}
@Override @DefinedBy(Api.COMPILER)
+ public Iterable<? extends JavaFileObject> getJavaFileObjectsFromPaths(Collection<? extends Path> paths) {
+ try {
+ return ((StandardJavaFileManager)clientJavaFileManager).getJavaFileObjectsFromPaths(paths);
+ } catch (ClientCodeException e) {
+ throw e;
+ } catch (RuntimeException | Error e) {
+ throw new ClientCodeException(e);
+ }
+ }
+
+ @Deprecated(since = "13")
+ @Override @DefinedBy(Api.COMPILER)
public Iterable<? extends JavaFileObject> getJavaFileObjectsFromPaths(Iterable<? extends Path> paths) {
try {
return ((StandardJavaFileManager)clientJavaFileManager).getJavaFileObjectsFromPaths(paths);
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/file/CacheFSInfo.java Wed Mar 27 07:45:21 2019 -0400
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/file/CacheFSInfo.java Wed Mar 27 08:27:58 2019 -0400
@@ -26,9 +26,11 @@
package com.sun.tools.javac.file;
import java.io.IOException;
+import java.nio.file.Files;
import java.nio.file.Path;
+import java.nio.file.attribute.BasicFileAttributes;
import java.util.List;
-import java.util.Map;
+import java.util.Optional;
import java.util.concurrent.ConcurrentHashMap;
import com.sun.tools.javac.util.Context;
@@ -44,6 +46,12 @@
*/
public class CacheFSInfo extends FSInfo {
+ protected final ConcurrentHashMap<Path, Path> canonicalPathCache = new ConcurrentHashMap<>();
+ protected final ConcurrentHashMap<Path, Optional<BasicFileAttributes>> attributeCache =
+ new ConcurrentHashMap<>();
+ protected final ConcurrentHashMap<Path, List<Path>> jarClassPathCache =
+ new ConcurrentHashMap<>();
+
/**
* Register a Context.Factory to create a CacheFSInfo.
*/
@@ -56,68 +64,53 @@
}
public void clearCache() {
- cache.clear();
+ canonicalPathCache.clear();
+ attributeCache.clear();
+ jarClassPathCache.clear();
}
@Override
public Path getCanonicalFile(Path file) {
- Entry e = getEntry(file);
- return e.canonicalFile;
+ return canonicalPathCache.computeIfAbsent(file, super::getCanonicalFile);
}
@Override
public boolean exists(Path file) {
- Entry e = getEntry(file);
- return e.exists;
+ return getAttributes(file).isPresent();
}
@Override
public boolean isDirectory(Path file) {
- Entry e = getEntry(file);
- return e.isDirectory;
+ return getAttributes(file).map(BasicFileAttributes::isDirectory).orElse(false);
}
@Override
public boolean isFile(Path file) {
- Entry e = getEntry(file);
- return e.isFile;
+ return getAttributes(file).map(BasicFileAttributes::isRegularFile).orElse(false);
}
@Override
public List<Path> getJarClassPath(Path file) throws IOException {
- // don't bother to lock the cache, because it is thread-safe, and
- // because the worst that can happen would be to create two identical
- // jar class paths together and have one overwrite the other.
- Entry e = getEntry(file);
- if (e.jarClassPath == null)
- e.jarClassPath = super.getJarClassPath(file);
- return e.jarClassPath;
+ synchronized (jarClassPathCache) {
+ List<Path> jarClassPath = jarClassPathCache.get(file);
+ if (jarClassPath == null) {
+ jarClassPath = super.getJarClassPath(file);
+ jarClassPathCache.put(file, jarClassPath);
+ }
+ return jarClassPath;
+ }
}
- private Entry getEntry(Path file) {
- // don't bother to lock the cache, because it is thread-safe, and
- // because the worst that can happen would be to create two identical
- // entries together and have one overwrite the other.
- Entry e = cache.get(file);
- if (e == null) {
- e = new Entry();
- e.canonicalFile = super.getCanonicalFile(file);
- e.exists = super.exists(file);
- e.isDirectory = super.isDirectory(file);
- e.isFile = super.isFile(file);
- cache.put(file, e);
- }
- return e;
+ protected Optional<BasicFileAttributes> getAttributes(Path file) {
+ return attributeCache.computeIfAbsent(file, this::maybeReadAttributes);
}
- // could also be a Map<File,SoftReference<Entry>> ?
- private final Map<Path,Entry> cache = new ConcurrentHashMap<>();
-
- private static class Entry {
- Path canonicalFile;
- boolean exists;
- boolean isFile;
- boolean isDirectory;
- List<Path> jarClassPath;
+ protected Optional<BasicFileAttributes> maybeReadAttributes(Path file) {
+ try {
+ return Optional.of(Files.readAttributes(file, BasicFileAttributes.class));
+ } catch (IOException e) {
+ // Ignore; means file not found
+ return Optional.empty();
+ }
}
}
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/file/JavacFileManager.java Wed Mar 27 07:45:21 2019 -0400
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/file/JavacFileManager.java Wed Mar 27 08:27:58 2019 -0400
@@ -897,7 +897,7 @@
@Override @DefinedBy(Api.COMPILER)
public Iterable<? extends JavaFileObject> getJavaFileObjectsFromPaths(
- Iterable<? extends Path> paths)
+ Collection<? extends Path> paths)
{
ArrayList<PathFileObject> result;
if (paths instanceof Collection<?>)
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/main/DelegatingJavaFileManager.java Wed Mar 27 07:45:21 2019 -0400
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/main/DelegatingJavaFileManager.java Wed Mar 27 08:27:58 2019 -0400
@@ -206,6 +206,13 @@
@Override
public Iterable<? extends JavaFileObject> getJavaFileObjectsFromPaths
+ (Collection<? extends Path> paths) {
+ return baseSJFM.getJavaFileObjectsFromPaths(paths);
+ }
+
+ @Deprecated(since = "13")
+ @Override
+ public Iterable<? extends JavaFileObject> getJavaFileObjectsFromPaths
(Iterable<? extends Path> paths) {
return baseSJFM.getJavaFileObjectsFromPaths(paths);
}
--- a/test/hotspot/jtreg/ProblemList.txt Wed Mar 27 07:45:21 2019 -0400
+++ b/test/hotspot/jtreg/ProblemList.txt Wed Mar 27 08:27:58 2019 -0400
@@ -161,6 +161,8 @@
vmTestbase/nsk/jdi/VirtualMachine/redefineClasses/redefineclasses021/TestDescription.java 8065773 generic-all
vmTestbase/nsk/jdi/VirtualMachine/redefineClasses/redefineclasses023/TestDescription.java 8065773 generic-all
+vmTestbase/nsk/jdb/eval/eval001/eval001.java 8221503 generic-all
+
vmTestbase/metaspace/gc/firstGC_10m/TestDescription.java 8208250 generic-all
vmTestbase/metaspace/gc/firstGC_50m/TestDescription.java 8208250 generic-all
vmTestbase/metaspace/gc/firstGC_99m/TestDescription.java 8208250 generic-all
--- a/test/hotspot/jtreg/runtime/appcds/jvmti/InstrumentationApp.java Wed Mar 27 07:45:21 2019 -0400
+++ b/test/hotspot/jtreg/runtime/appcds/jvmti/InstrumentationApp.java Wed Mar 27 08:27:58 2019 -0400
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2014, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2014, 2019, 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
@@ -28,6 +28,7 @@
import java.net.URL;
import java.net.URLClassLoader;
import java.io.File;
+import java.io.FileWriter;
import java.security.CodeSigner;
import java.security.CodeSource;
import java.security.ProtectionDomain;
@@ -140,8 +141,22 @@
}
static void waitAttach(String flagFile) throws Throwable {
+ // See InstrumentationTest.java for the hand-shake protocol.
if (!flagFile.equals("noattach")) {
File f = new File(flagFile);
+ try (FileWriter fw = new FileWriter(f)) {
+ long pid = ProcessHandle.current().pid();
+ System.out.println("my pid = " + pid);
+ fw.write(Long.toString(pid));
+ fw.write("\n");
+ for (int i=0; i<10; i++) {
+ // Parent process waits until we have written more than 100 bytes, so it won't
+ // read a partial pid
+ fw.write("==========");
+ }
+ fw.close();
+ }
+
long start = System.currentTimeMillis();
while (f.exists()) {
long elapsed = System.currentTimeMillis() - start;
--- a/test/hotspot/jtreg/runtime/appcds/jvmti/InstrumentationTest.java Wed Mar 27 07:45:21 2019 -0400
+++ b/test/hotspot/jtreg/runtime/appcds/jvmti/InstrumentationTest.java Wed Mar 27 08:27:58 2019 -0400
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2014, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2014, 2019, 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
@@ -29,9 +29,6 @@
* @library /test/lib /test/hotspot/jtreg/runtime/appcds /test/hotspot/jtreg/runtime/appcds/test-classes
* @requires vm.cds
* @requires vm.flavor != "minimal"
- * @modules java.base/jdk.internal.misc
- * jdk.jartool/sun.tools.jar
- * java.management
* @build sun.hotspot.WhiteBox
* InstrumentationApp
* InstrumentationClassFileTransformer
@@ -43,10 +40,9 @@
// Note: Util is from /test/hotspot/jtreg/runtime/appcds/test-classes/TestCommon.java
import com.sun.tools.attach.VirtualMachine;
-import com.sun.tools.attach.VirtualMachineDescriptor;
import java.io.File;
-import java.io.FileOutputStream;
-import java.util.List;
+import java.io.FileInputStream;
+import java.util.Scanner;
import jdk.test.lib.Asserts;
import jdk.test.lib.cds.CDSOptions;
import jdk.test.lib.process.OutputAnalyzer;
@@ -179,24 +175,28 @@
return null;
}
- // We use the flagFile to prevent the child process to make progress, until we have
- // attached to it.
+ // Hand-shake protocol with the child process
+ // [1] Parent process (this process) launches child process (InstrumentationApp)
+ // and then waits until child process writes its pid into the flagFile.
+ // [2] Child process process starts up, writes its pid into the flagFile,
+ // and waits for the flagFile to be deleted.
+ // [3] When parent process gets the pid, it attaches to the child process
+ // (if we attempt to attach to a process too early, the SIGQUIT
+ // may cause the child to die) and deletes the flagFile.
+ // [4] Child process resumes execution.
+
File f = new File(flagFile);
- try (FileOutputStream o = new FileOutputStream(f)) {
- o.write(1);
- }
- if (!f.exists()) {
- throw new RuntimeException("Failed to create " + f);
+ f.delete();
+ if (f.exists()) {
+ throw new RuntimeException("Flag file should not exist: " + f);
}
// At this point, the child process is not yet launched. Note that
// TestCommon.exec() and OutputAnalyzer.OutputAnalyzer() both block
// until the child process has finished.
//
- // So, we will launch a AgentAttachThread which will poll the system
- // until the child process is launched, and then do the attachment.
- // The child process is uniquely identified by having flagFile in its
- // command-line -- see AgentAttachThread.getPid().
+ // So, we will launch a AgentAttachThread which will poll the flagFile
+ // until the child process is launched.
AgentAttachThread t = new AgentAttachThread(flagFile, agentJar);
t.start();
return t;
@@ -225,13 +225,17 @@
// reason the child process fails to launch, this test will be terminated
// by JTREG's time-out mechanism.
Thread.sleep(100);
- List<VirtualMachineDescriptor> vmds = VirtualMachine.list();
- for (VirtualMachineDescriptor vmd : vmds) {
- if (vmd.displayName().contains(flagFile) && vmd.displayName().contains("InstrumentationApp")) {
- // We use flagFile (which has the PID of this process) as a unique identifier
- // to ident the child process, which we want to attach to.
- System.out.println("Process found: " + vmd.id() + " " + vmd.displayName());
- return vmd.id();
+ File f = new File(flagFile);
+ if (f.exists() && f.length() > 100) {
+ try (FileInputStream in = new FileInputStream(f)) {
+ Scanner scanner = new Scanner(in);
+ return Long.toString(scanner.nextLong());
+ } catch (Throwable t) {
+ // This may happen on Windows if the child process has not
+ // fully closed the output stream to the flagFile
+ System.out.println("Ignored: " + t);
+ t.printStackTrace(System.out);
+ continue;
}
}
}
@@ -240,6 +244,7 @@
public void run() {
try {
String pid = getPid(flagFile);
+ System.out.println("child pid = " + pid);
VirtualMachine vm = VirtualMachine.attach(pid);
System.out.println(agentJar);
vm.loadAgent(agentJar);
--- a/test/hotspot/jtreg/runtime/containers/docker/Dockerfile-BasicTest Wed Mar 27 07:45:21 2019 -0400
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,8 +0,0 @@
-FROM oraclelinux:7.6
-MAINTAINER mikhailo.seledtsov@oracle.com
-
-COPY /jdk /jdk
-
-ENV JAVA_HOME=/jdk
-
-CMD ["/bin/bash"]
--- a/test/hotspot/jtreg/runtime/containers/docker/Dockerfile-BasicTest-aarch64 Wed Mar 27 07:45:21 2019 -0400
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,8 +0,0 @@
-# Use generic ubuntu Linux on AArch64
-FROM aarch64/ubuntu
-
-COPY /jdk /jdk
-
-ENV JAVA_HOME=/jdk
-
-CMD ["/bin/bash"]
--- a/test/hotspot/jtreg/runtime/containers/docker/Dockerfile-BasicTest-ppc64le Wed Mar 27 07:45:21 2019 -0400
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,10 +0,0 @@
-# test on x86_64 uses Oracle Linux but we do not have this for ppc64le
-# so use some other Linux where OpenJDK works
-# FROM oraclelinux:7.2
-FROM ppc64le/ubuntu
-
-COPY /jdk /jdk
-
-ENV JAVA_HOME=/jdk
-
-CMD ["/bin/bash"]
--- a/test/hotspot/jtreg/runtime/containers/docker/Dockerfile-BasicTest-s390x Wed Mar 27 07:45:21 2019 -0400
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,7 +0,0 @@
-FROM s390x/ubuntu
-
-COPY /jdk /jdk
-
-ENV JAVA_HOME=/jdk
-
-CMD ["/bin/bash"]
--- a/test/hotspot/jtreg/serviceability/sa/TestUniverse.java Wed Mar 27 07:45:21 2019 -0400
+++ b/test/hotspot/jtreg/serviceability/sa/TestUniverse.java Wed Mar 27 08:27:58 2019 -0400
@@ -29,99 +29,107 @@
import java.util.HashMap;
import jdk.test.lib.apps.LingeredApp;
import jtreg.SkippedException;
+import sun.hotspot.gc.GC;
/**
* @test
* @summary Test the 'universe' command of jhsdb clhsdb.
- * @requires vm.hasSAandCanAttach & vm.gc != "Z"
+ * @requires vm.hasSAandCanAttach
* @bug 8190307
* @library /test/lib
* @build jdk.test.lib.apps.*
* @build sun.hotspot.WhiteBox
* @run driver ClassFileInstaller sun.hotspot.WhiteBox sun.hotspot.WhiteBox$WhiteBoxPermission
- * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:. TestUniverse withoutZ
- */
-
-/**
- * @test
- * @summary Test the 'universe' command of jhsdb clhsdb.
- * @requires vm.hasSAandCanAttach & vm.gc == "Z"
- * @bug 8190307
- * @library /test/lib
- * @build jdk.test.lib.apps.*
- * @build sun.hotspot.WhiteBox
- * @run driver ClassFileInstaller sun.hotspot.WhiteBox sun.hotspot.WhiteBox$WhiteBoxPermission
- * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:. TestUniverse withZ
+ * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:. TestUniverse
*/
public class TestUniverse {
- private static void testClhsdbForUniverse(long lingeredAppPid,
- String gc) throws Exception {
-
+ private static void testClhsdbForUniverse(long lingeredAppPid, GC gc) throws Exception {
ClhsdbLauncher launcher = new ClhsdbLauncher();
List<String> cmds = List.of("universe");
Map<String, List<String>> expStrMap = new HashMap<>();
List<String> expStrings = new ArrayList<String>();
expStrings.add("Heap Parameters");
- if (gc.contains("UseZGC")) {
- expStrings.add("ZHeap");
- }
- if (gc.contains("G1GC")) {
+ switch (gc) {
+ case Serial:
+ expStrings.add("Gen 1: old");
+ break;
+
+ case Parallel:
+ expStrings.add("ParallelScavengeHeap");
+ expStrings.add("PSYoungGen");
+ expStrings.add("eden");
+ break;
+
+ case ConcMarkSweep:
+ expStrings.add("Gen 1: concurrent mark-sweep generation");
+ break;
+
+ case G1:
expStrings.add("garbage-first heap");
expStrings.add("region size");
expStrings.add("G1 Young Generation:");
expStrings.add("regions =");
- }
- if (gc.contains("UseConcMarkSweepGC")) {
- expStrings.add("Gen 1: concurrent mark-sweep generation");
- }
- if (gc.contains("UseSerialGC")) {
- expStrings.add("Gen 1: old");
- }
- if (gc.contains("UseParallelGC")) {
- expStrings.add("ParallelScavengeHeap");
- expStrings.add("PSYoungGen");
- expStrings.add("eden");
- }
- if (gc.contains("UseEpsilonGC")) {
+ break;
+
+ case Epsilon:
expStrings.add("Epsilon heap");
expStrings.add("reserved");
expStrings.add("committed");
expStrings.add("used");
+ break;
+
+ case Z:
+ expStrings.add("ZHeap");
+ break;
+
+ case Shenandoah:
+ expStrings.add("Shenandoah Heap");
+ break;
}
+
expStrMap.put("universe", expStrings);
launcher.run(lingeredAppPid, cmds, expStrMap, null);
}
- public static void test(String gc) throws Exception {
+ private static void test(GC gc) throws Exception {
LingeredApp app = null;
try {
- List<String> vmArgs = new ArrayList<String>();
- vmArgs.add("-XX:+UnlockExperimentalVMOptions"); // unlock experimental GCs
- vmArgs.add(gc);
- app = LingeredApp.startApp(vmArgs);
- System.out.println ("Started LingeredApp with the GC option " + gc +
- " and pid " + app.getPid());
+ app = LingeredApp.startApp(List.of("-XX:+UnlockExperimentalVMOptions", "-XX:+Use" + gc + "GC"));
+ System.out.println ("Started LingeredApp with " + gc + "GC and pid " + app.getPid());
testClhsdbForUniverse(app.getPid(), gc);
} finally {
LingeredApp.stopApp(app);
}
}
+ private static boolean isSelectedAndSupported(GC gc) {
+ if (!gc.isSelected()) {
+ // Not selected
+ return false;
+ }
+
+ if (Compiler.isGraalEnabled()) {
+ if (gc == GC.ConcMarkSweep || gc == GC.Epsilon || gc == GC.Z || gc == GC.Shenandoah) {
+ // Not supported
+ System.out.println ("Skipped testing of " + gc + "GC, not supported by Graal");
+ return false;
+ }
+ }
+
+ // Selected and supported
+ return true;
+ }
+
public static void main (String... args) throws Exception {
- System.out.println("Starting TestUniverse test");
+ System.out.println("Starting TestUniverse");
try {
- test("-XX:+UseG1GC");
- test("-XX:+UseParallelGC");
- test("-XX:+UseSerialGC");
- if (!Compiler.isGraalEnabled()) { // Graal does not support all GCs
- test("-XX:+UseConcMarkSweepGC");
- if (args[0].equals("withZ")) {
- test("-XX:+UseZGC");
+ for (GC gc: GC.values()) {
+ if (isSelectedAndSupported(gc)) {
+ test(gc);
}
- test("-XX:+UseEpsilonGC");
}
} catch (SkippedException se) {
throw se;
--- a/test/jdk/java/lang/String/StringRepeat.java Wed Mar 27 07:45:21 2019 -0400
+++ b/test/jdk/java/lang/String/StringRepeat.java Wed Mar 27 08:27:58 2019 -0400
@@ -24,7 +24,7 @@
/*
* @test
* @summary This exercises String#repeat patterns and limits.
- * @run main/othervm -Xmx4G StringRepeat
+ * @run main/othervm -Xmx2g StringRepeat
*/
import java.nio.CharBuffer;
--- a/test/jdk/java/lang/invoke/MethodHandlesGeneralTest.java Wed Mar 27 07:45:21 2019 -0400
+++ b/test/jdk/java/lang/invoke/MethodHandlesGeneralTest.java Wed Mar 27 08:27:58 2019 -0400
@@ -22,6 +22,7 @@
*/
/* @test
+ * @bug 8216558
* @summary unit tests for java.lang.invoke.MethodHandles
* @library /test/lib /java/lang/invoke/common
* @compile MethodHandlesTest.java MethodHandlesGeneralTest.java remote/RemoteExample.java
@@ -664,6 +665,7 @@
boolean testNPE = ((testMode0 & TEST_NPE) != 0);
int testMode = testMode0 & ~(TEST_SETTER | TEST_BOUND | TEST_NPE);
boolean positive = positive0 && !testNPE;
+ boolean isFinal;
boolean isStatic;
Class<?> fclass;
String fname;
@@ -671,12 +673,14 @@
Field f = (fieldRef instanceof Field ? (Field)fieldRef : null);
if (f != null) {
isStatic = Modifier.isStatic(f.getModifiers());
+ isFinal = Modifier.isFinal(f.getModifiers());
fclass = f.getDeclaringClass();
fname = f.getName();
ftype = f.getType();
} else {
Object[] scnt = (Object[]) fieldRef;
isStatic = (Boolean) scnt[0];
+ isFinal = false;
fclass = (Class<?>) scnt[1];
fname = (String) scnt[2];
ftype = (Class<?>) scnt[3];
@@ -720,18 +724,21 @@
? NoSuchFieldException.class
: IllegalAccessException.class,
noAccess);
+ if (((testMode0 & TEST_SETTER) != 0) && (isFinal && isStatic)) return; // Final static field setter test failed as intended.
if (verbosity >= 5) ex.printStackTrace(System.out);
}
if (verbosity >= 3)
- System.out.println("find"+(isStatic?"Static":"")+(isGetter?"Getter":"Setter")+" "+fclass.getName()+"."+fname+"/"+ftype
- +" => "+mh
- +(noAccess == null ? "" : " !! "+noAccess));
+ System.out.println((((testMode0 & TEST_UNREFLECT) != 0)?"unreflect":"find")
+ +(((testMode0 & TEST_FIND_STATIC) != 0)?"Static":"")
+ +(isGetter?"Getter":"Setter")
+ +" "+fclass.getName()+"."+fname+"/"+ftype
+ +" => "+mh
+ +(noAccess == null ? "" : " !! "+noAccess));
if (positive && !testNPE && noAccess != null) throw new RuntimeException(noAccess);
assertEquals(positive0 ? "positive test" : "negative test erroneously passed", positive0, mh != null);
+ assertFalse("Setter methods should throw an exception if passed a final static field.", ((testMode0 & TEST_SETTER) != 0) && (isFinal && isStatic));
if (!positive && !testNPE) return; // negative access test failed as expected
assertEquals((isStatic ? 0 : 1)+(isGetter ? 0 : 1), mh.type().parameterCount());
-
-
assertSame(mh.type(), expType);
//assertNameStringContains(mh, fname); // This does not hold anymore with LFs
HasFields fields = new HasFields();
@@ -778,8 +785,7 @@
}
}
assertEquals(sawValue, expValue);
- if (f != null && f.getDeclaringClass() == HasFields.class
- && !Modifier.isFinal(f.getModifiers())) {
+ if (f != null && f.getDeclaringClass() == HasFields.class && !isFinal) {
Object random = randomArg(ftype);
f.set(fields, random);
expValue = random;
@@ -813,8 +819,8 @@
}
}
}
- if (f != null && f.getDeclaringClass() == HasFields.class) {
- f.set(fields, value); // put it back
+ if ((f != null) && (f.getDeclaringClass() == HasFields.class) && !isFinal) {
+ f.set(fields, value); // put it back if we changed it.
}
if (testNPE) {
if (caughtEx == null || !(caughtEx instanceof NullPointerException))
@@ -862,7 +868,6 @@
public void testSetter(int testMode) throws Throwable {
Lookup lookup = PRIVATE; // FIXME: test more lookups than this one
- startTest("unreflectSetter");
for (Object[] c : HasFields.CASES) {
boolean positive = (c[1] != Error.class);
testSetter(positive, lookup, c[0], c[1], testMode);
--- a/test/jdk/java/lang/invoke/MethodHandlesTest.java Wed Mar 27 07:45:21 2019 -0400
+++ b/test/jdk/java/lang/invoke/MethodHandlesTest.java Wed Mar 27 08:27:58 2019 -0400
@@ -545,14 +545,14 @@
}
public static class HasFields {
- boolean fZ = false;
- byte fB = (byte)'B';
- short fS = (short)'S';
- char fC = 'C';
- int fI = 'I';
- long fJ = 'J';
- float fF = 'F';
- double fD = 'D';
+ boolean iZ = false;
+ byte iB = (byte)'B';
+ short iS = (short)'S';
+ char iC = 'C';
+ int iI = 'I';
+ long iJ = 'J';
+ float iF = 'F';
+ double iD = 'D';
static boolean sZ = true;
static byte sB = 1+(byte)'B';
static short sS = 1+(short)'S';
@@ -561,11 +561,21 @@
static long sJ = 1+'J';
static float sF = 1+'F';
static double sD = 1+'D';
+ final static boolean fsZ = false;
+ final static byte fsB = 2+(byte)'B';
+ final static short fsS = 2+(short)'S';
+ final static char fsC = 2+'C';
+ final static int fsI = 2+'I';
+ final static long fsJ = 2+'J';
+ final static float fsF = 2+'F';
+ final static double fsD = 2+'D';
- Object fL = 'L';
- String fR = "R";
+ Object iL = 'L';
+ String iR = "R";
static Object sL = 'M';
static String sR = "S";
+ final static Object fsL = 'N';
+ final static String fsR = "T";
static final Object[][] CASES;
static {
@@ -579,14 +589,16 @@
};
HasFields fields = new HasFields();
for (Object[] t : types) {
- for (int kind = 0; kind <= 1; kind++) {
+ for (int kind = 0; kind <= 2; kind++) {
boolean isStatic = (kind != 0);
+ boolean isFinal = (kind == 2);
char btc = (Character)t[0];
- String name = (isStatic ? "s" : "f") + btc;
+ String name = (isStatic ? "s" : "i") + btc;
+ if (isFinal) name = "f" + name;
Class<?> type = (Class<?>) t[1];
Object value;
Field field;
- try {
+ try {
field = HasFields.class.getDeclaredField(name);
} catch (NoSuchFieldException | SecurityException ex) {
throw new InternalError("no field HasFields."+name);
@@ -599,11 +611,14 @@
if (type == float.class) {
float v = 'F';
if (isStatic) v++;
+ if (isFinal) v++;
assertTrue(value.equals(v));
}
+ if (isFinal && isStatic) field.setAccessible(true);
assertTrue(name.equals(field.getName()));
assertTrue(type.equals(field.getType()));
assertTrue(isStatic == (Modifier.isStatic(field.getModifiers())));
+ assertTrue(isFinal == (Modifier.isFinal(field.getModifiers())));
cases.add(new Object[]{ field, value });
}
}
--- a/test/jdk/java/lang/invoke/VarHandles/accessibility/TestFieldLookupAccessibility.java Wed Mar 27 07:45:21 2019 -0400
+++ b/test/jdk/java/lang/invoke/VarHandles/accessibility/TestFieldLookupAccessibility.java Wed Mar 27 08:27:58 2019 -0400
@@ -22,7 +22,7 @@
*/
/* @test
- * @bug 8152645
+ * @bug 8152645 8216558
* @summary test field lookup accessibility of MethodHandles and VarHandles
* @compile TestFieldLookupAccessibility.java
* pkg/A.java pkg/B_extends_A.java pkg/C.java
@@ -96,6 +96,12 @@
Object lookup(MethodHandles.Lookup l, Field f) throws Exception {
return l.unreflectGetter(cloneAndSetAccessible(f));
}
+
+ // Setting the accessibility bit of a Field grants access under
+ // all conditions for MethodHandle getters.
+ Set<String> inaccessibleFields(Set<String> inaccessibleFields) {
+ return new HashSet<>();
+ }
},
MH_UNREFLECT_SETTER() {
Object lookup(MethodHandles.Lookup l, Field f) throws Exception {
@@ -103,13 +109,27 @@
}
boolean isAccessible(Field f) {
- return f.isAccessible() || !Modifier.isFinal(f.getModifiers());
+ return f.isAccessible() && !Modifier.isStatic(f.getModifiers()) || !Modifier.isFinal(f.getModifiers());
}
},
MH_UNREFLECT_SETTER_ACCESSIBLE() {
Object lookup(MethodHandles.Lookup l, Field f) throws Exception {
return l.unreflectSetter(cloneAndSetAccessible(f));
}
+
+ boolean isAccessible(Field f) {
+ return !(Modifier.isStatic(f.getModifiers()) && Modifier.isFinal(f.getModifiers()));
+ }
+
+ // Setting the accessibility bit of a Field grants access to non-static
+ // final fields for MethodHandle setters.
+ Set<String> inaccessibleFields(Set<String>inaccessibleFields) {
+ Set<String> result = new HashSet<>();
+ inaccessibleFields.stream()
+ .filter(f -> (f.contains("static") && f.contains("final")))
+ .forEach(result::add);
+ return result;
+ }
},
VH() {
Object lookup(MethodHandles.Lookup l, Field f) throws Exception {
@@ -142,6 +162,10 @@
return true;
}
+ Set<String> inaccessibleFields(Set<String> inaccessibleFields) {
+ return new HashSet<>(inaccessibleFields);
+ }
+
static Field cloneAndSetAccessible(Field f) throws Exception {
// Clone to avoid mutating source field
f = f.getDeclaringClass().getDeclaredField(f.getName());
@@ -180,7 +204,7 @@
@Test(dataProvider = "lookupProvider")
public void test(FieldLookup fl, Class<?> src, MethodHandles.Lookup l, Set<String> inaccessibleFields) {
// Add to the expected failures all inaccessible fields due to accessibility modifiers
- Set<String> expected = new HashSet<>(inaccessibleFields);
+ Set<String> expected = fl.inaccessibleFields(inaccessibleFields);
Map<Field, Throwable> actual = new HashMap<>();
for (Field f : fields(src)) {
@@ -202,12 +226,7 @@
collect(Collectors.toSet());
if (!actualFieldNames.equals(expected)) {
if (actualFieldNames.isEmpty()) {
- // Setting the accessibility bit of a Field grants access under
- // all conditions for MethodHander getters and setters
- if (fl != FieldLookup.MH_UNREFLECT_GETTER_ACCESSIBLE &&
- fl != FieldLookup.MH_UNREFLECT_SETTER_ACCESSIBLE) {
- Assert.assertEquals(actualFieldNames, expected, "No accessibility failures:");
- }
+ Assert.assertEquals(actualFieldNames, expected, "No accessibility failures:");
}
else {
Assert.assertEquals(actualFieldNames, expected, "Accessibility failures differ:");
--- a/test/jdk/java/math/BigInteger/LargeValueExceptions.java Wed Mar 27 07:45:21 2019 -0400
+++ b/test/jdk/java/math/BigInteger/LargeValueExceptions.java Wed Mar 27 08:27:58 2019 -0400
@@ -25,7 +25,7 @@
* @test
* @bug 8200698
* @summary Tests that exceptions are thrown for ops which would overflow
- * @requires os.maxMemory >= 4g
+ * @requires (sun.arch.data.model == "64" & os.maxMemory >= 4g)
* @run testng/othervm -Xmx4g LargeValueExceptions
*/
import java.math.BigInteger;
--- a/test/jdk/java/util/Base64/TestEncodingDecodingLength.java Wed Mar 27 07:45:21 2019 -0400
+++ b/test/jdk/java/util/Base64/TestEncodingDecodingLength.java Wed Mar 27 08:27:58 2019 -0400
@@ -30,7 +30,7 @@
* @bug 8210583 8217969 8218265
* @summary Tests Base64.Encoder.encode and Base64.Decoder.decode
* with the large size of input array/buffer
- * @requires os.maxMemory >= 10g
+ * @requires (sun.arch.data.model == "64" & os.maxMemory >= 10g)
* @run main/othervm -Xms6g -Xmx8g TestEncodingDecodingLength
*
*/
--- a/test/jdk/jdk/internal/platform/docker/Dockerfile-BasicTest Wed Mar 27 07:45:21 2019 -0400
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,8 +0,0 @@
-FROM oraclelinux:7.6
-MAINTAINER mikhailo.seledtsov@oracle.com
-
-COPY /jdk /jdk
-
-ENV JAVA_HOME=/jdk
-
-CMD ["/bin/bash"]
--- a/test/jdk/jdk/internal/platform/docker/Dockerfile-BasicTest-aarch64 Wed Mar 27 07:45:21 2019 -0400
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,8 +0,0 @@
-# Use generic ubuntu Linux on AArch64
-FROM aarch64/ubuntu
-
-COPY /jdk /jdk
-
-ENV JAVA_HOME=/jdk
-
-CMD ["/bin/bash"]
--- a/test/jdk/jdk/internal/platform/docker/Dockerfile-BasicTest-ppc64le Wed Mar 27 07:45:21 2019 -0400
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,10 +0,0 @@
-# test on x86_64 uses Oracle Linux but we do not have this for ppc64le
-# so use some other Linux where OpenJDK works
-# FROM oraclelinux:7.2
-FROM ppc64le/ubuntu
-
-COPY /jdk /jdk
-
-ENV JAVA_HOME=/jdk
-
-CMD ["/bin/bash"]
--- a/test/jdk/jdk/internal/platform/docker/Dockerfile-BasicTest-s390x Wed Mar 27 07:45:21 2019 -0400
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,7 +0,0 @@
-FROM s390x/ubuntu
-
-COPY /jdk /jdk
-
-ENV JAVA_HOME=/jdk
-
-CMD ["/bin/bash"]
--- a/test/langtools/tools/javac/api/file/SJFM_GetFileObjects.java Wed Mar 27 07:45:21 2019 -0400
+++ b/test/langtools/tools/javac/api/file/SJFM_GetFileObjects.java Wed Mar 27 08:27:58 2019 -0400
@@ -23,7 +23,7 @@
/*
* @test
- * @bug 8059977
+ * @bug 8059977 8220687
* @summary StandardJavaFileManager should support java.nio.file.Path.
* Test getFileObject methods.
* @modules java.compiler
@@ -117,6 +117,40 @@
//----------------------------------------------------------------------------------------------
+ @Test
+ void test_getJavaFileObjectsFromPaths_Iterable(StandardJavaFileManager fm) throws IOException {
+ test_getJavaFileObjectsFromPaths_Iterable(fm, getTestFilePaths());
+ test_getJavaFileObjectsFromPaths_Iterable(fm, getTestZipPaths());
+ }
+
+ /**
+ * Tests the {@code getJavaFileObjectsFromPaths(Iterable)} method for a specific file
+ * manager and a series of paths.
+ *
+ * Note: instances of MyStandardJavaFileManager only support
+ * encapsulating paths for files in the default file system.
+ *
+ * @param fm the file manager to be tested
+ * @param paths the paths to be tested
+ * @throws IOException
+ */
+ void test_getJavaFileObjectsFromPaths_Iterable(StandardJavaFileManager fm, List<Path> paths)
+ throws IOException {
+ boolean expectException = !isGetFileObjectsSupported(fm, paths);
+ try {
+ compile(fm.getJavaFileObjectsFromPaths((Iterable<Path>) paths));
+ if (expectException)
+ error("expected exception not thrown: " + IllegalArgumentException.class.getName());
+ } catch (RuntimeException e) {
+ if (expectException && e instanceof IllegalArgumentException)
+ return;
+ error("unexpected exception thrown: " + e);
+ }
+ }
+
+
+ //----------------------------------------------------------------------------------------------
+
/**
* Compiles a set of files.
*
--- a/test/lib/jdk/test/lib/containers/docker/DockerTestUtils.java Wed Mar 27 07:45:21 2019 -0400
+++ b/test/lib/jdk/test/lib/containers/docker/DockerTestUtils.java Wed Mar 27 08:27:58 2019 -0400
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2017, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2017, 2019, 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
@@ -35,7 +35,6 @@
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
-import jdk.test.lib.Platform;
import jdk.test.lib.Utils;
import jdk.test.lib.process.OutputAnalyzer;
import jdk.test.lib.process.ProcessTools;
@@ -126,11 +125,6 @@
if (Files.exists(buildDir)) {
throw new RuntimeException("The docker build directory already exists: " + buildDir);
}
- // check for the existance of a platform specific docker file as well
- String platformSpecificDockerfile = dockerfile + "-" + Platform.getOsArch();
- if (Files.exists(Paths.get(Utils.TEST_SRC, platformSpecificDockerfile))) {
- dockerfile = platformSpecificDockerfile;
- }
Path jdkSrcDir = Paths.get(Utils.TEST_JDK);
Path jdkDstDir = buildDir.resolve("jdk");
@@ -158,8 +152,9 @@
public static void
buildDockerImage(String imageName, Path dockerfile, Path buildDir) throws Exception {
- // Copy docker file to the build dir
- Files.copy(dockerfile, buildDir.resolve("Dockerfile"));
+ generateDockerFile(buildDir.resolve("Dockerfile"),
+ DockerfileConfig.getBaseImageName(),
+ DockerfileConfig.getBaseImageVersion());
// Build the docker
execute("docker", "build", "--no-cache", "--tag", imageName, buildDir.toString())
@@ -250,6 +245,18 @@
}
+ private static void generateDockerFile(Path dockerfile, String baseImage,
+ String baseImageVersion) throws Exception {
+ String template =
+ "FROM %s:%s\n" +
+ "COPY /jdk /jdk\n" +
+ "ENV JAVA_HOME=/jdk\n" +
+ "CMD [\"/bin/bash\"]\n";
+ String dockerFileStr = String.format(template, baseImage, baseImageVersion);
+ Files.writeString(dockerfile, dockerFileStr);
+ }
+
+
private static class CopyFileVisitor extends SimpleFileVisitor<Path> {
private final Path src;
private final Path dst;
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/lib/jdk/test/lib/containers/docker/DockerfileConfig.java Wed Mar 27 08:27:58 2019 -0400
@@ -0,0 +1,75 @@
+/*
+ * Copyright (c) 2019, 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.
+ */
+
+package jdk.test.lib.containers.docker;
+
+import jdk.test.lib.Platform;
+
+// Use the following properties to specify docker base image at test execution time:
+// Image name: jdk.test.docker.image.name
+// Image version: jdk.test.docker.image.version
+// Usage:
+// jtreg -Djdk.test.docker.image.name=<BASE_IMAGE_NAME> -Djdk.test.docker.image.version=<BASE_IMAGE_VERSION> test/hotspot/jtreg/runtime/containers/docker/
+// E.g.:
+// jtreg -Djdk.test.docker.image.name=ubuntu -Djdk.test.docker.image.version=latest test/hotspot/jtreg/runtime/containers/docker/
+// Using make:
+// make test TEST="test/hotspot/jtreg/runtime/containers/docker" JTREG="JAVA_OPTIONS=-Djdk.test.docker.image.name=ubuntu -Djdk.test.docker.image.version=latest"
+// Note: base image version should not be an empty string. Use "latest" to get the latest version.
+
+public class DockerfileConfig {
+ static String getBaseImageName() {
+ String name = System.getProperty("jdk.test.docker.image.name");
+ if (name != null) {
+ System.out.println("DockerfileConfig: using custom image name: " + name);
+ return name;
+ }
+
+ switch (Platform.getOsArch()) {
+ case "aarch64":
+ return "aarch64/ubuntu";
+ case "ppc64le":
+ return "ppc64le/ubuntu";
+ case "s390x":
+ return "s390x/ubuntu";
+ default:
+ return "oraclelinux";
+ }
+ }
+
+ static String getBaseImageVersion() {
+ String version = System.getProperty("jdk.test.docker.image.version");
+ if (version != null) {
+ System.out.println("DockerfileConfig: using custom image version: " + version);
+ return version;
+ }
+
+ switch (Platform.getOsArch()) {
+ case "aarch64":
+ case "ppc64le":
+ case "s390x":
+ return "latest";
+ default:
+ return "7.6";
+ }
+ }
+}