# HG changeset patch # User herrick # Date 1553689678 14400 # Node ID 0be43184f52a96d66fd153ef0b2b9371fd9452b7 # Parent 90fa9a0959596dc7872169892af2d17574971b95# Parent 828c4889adfc8fdd9403fec83d01e1fc96e9a592 Merge diff -r 90fa9a095959 -r 0be43184f52a make/hotspot/lib/JvmFeatures.gmk --- 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) diff -r 90fa9a095959 -r 0be43184f52a src/hotspot/cpu/x86/vm_version_x86.cpp --- 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); } diff -r 90fa9a095959 -r 0be43184f52a src/hotspot/os_cpu/linux_s390/thread_linux_s390.cpp --- 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*/]; diff -r 90fa9a095959 -r 0be43184f52a src/hotspot/share/gc/shared/concurrentGCThread.cpp --- 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(); diff -r 90fa9a095959 -r 0be43184f52a src/hotspot/share/gc/z/zNMethodTableEntry.hpp --- 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; diff -r 90fa9a095959 -r 0be43184f52a src/hotspot/share/opto/graphKit.cpp --- 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)); diff -r 90fa9a095959 -r 0be43184f52a src/hotspot/share/opto/library_call.cpp --- 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???"); diff -r 90fa9a095959 -r 0be43184f52a src/hotspot/share/runtime/init.cpp --- 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(); } diff -r 90fa9a095959 -r 0be43184f52a src/hotspot/share/runtime/init.hpp --- 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 diff -r 90fa9a095959 -r 0be43184f52a src/hotspot/share/runtime/mutexLocker.cpp --- 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); diff -r 90fa9a095959 -r 0be43184f52a src/hotspot/share/runtime/mutexLocker.hpp --- 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 diff -r 90fa9a095959 -r 0be43184f52a src/hotspot/share/runtime/synchronizer.cpp --- 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: diff -r 90fa9a095959 -r 0be43184f52a src/hotspot/share/runtime/synchronizer.hpp --- 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; diff -r 90fa9a095959 -r 0be43184f52a src/hotspot/share/runtime/thread.cpp --- 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 diff -r 90fa9a095959 -r 0be43184f52a src/hotspot/share/services/memBaseline.cpp --- 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; diff -r 90fa9a095959 -r 0be43184f52a src/hotspot/share/services/memReporter.cpp --- 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(")"); } diff -r 90fa9a095959 -r 0be43184f52a src/hotspot/share/services/memTracker.cpp --- 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 diff -r 90fa9a095959 -r 0be43184f52a src/hotspot/share/services/memTracker.hpp --- 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 diff -r 90fa9a095959 -r 0be43184f52a src/hotspot/share/services/threadStackTracker.cpp --- /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* 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(); + 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 _sites; + { + ThreadCritical tc; + assert(_simple_thread_stacks != NULL, "Must be initialized"); + LinkedListIterator 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 site_itr(_sites.head()); + const MallocSite* s = site_itr.next(); + while (s != NULL) { + walker->do_malloc_site(s); + s = site_itr.next(); + } + } + return true; +} diff -r 90fa9a095959 -r 0be43184f52a src/hotspot/share/services/threadStackTracker.hpp --- /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 { +public: + SimpleThreadStackSite(address base, size_t size, const NativeCallStack& stack) : + AllocationSite(stack, mtThreadStack) { + data()->set_size(size); + data()->set_base(base); + } + + SimpleThreadStackSite(address base, size_t size) : + AllocationSite(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* _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 diff -r 90fa9a095959 -r 0be43184f52a src/hotspot/share/services/virtualMemoryTracker.cpp --- 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* VirtualMemoryTracker::_reserved_regions; diff -r 90fa9a095959 -r 0be43184f52a src/java.base/share/classes/java/lang/invoke/MethodHandles.java --- 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 * refuses access * @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 * refuses access * @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. *

* 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. + *

+ * 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. + *

+ * 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. - *

- * 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}. diff -r 90fa9a095959 -r 0be43184f52a src/java.compiler/share/classes/javax/tools/StandardJavaFileManager.java --- 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 getJavaFileObjectsFromPaths( + Collection 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}, 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 getJavaFileObjectsFromPaths( Iterable paths) { - return getJavaFileObjectsFromFiles(asFiles(paths)); + return getJavaFileObjectsFromPaths(asCollection(paths)); } /** @@ -484,4 +515,13 @@ } }; } + + private static Collection asCollection(Iterable iterable) { + if (iterable instanceof Collection) { + return (Collection) iterable; + } + List result = new ArrayList<>(); + for (T item : iterable) result.add(item); + return result; + } } diff -r 90fa9a095959 -r 0be43184f52a src/jdk.compiler/share/classes/com/sun/tools/javac/api/ClientCodeWrapper.java --- 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 getJavaFileObjectsFromPaths(Collection 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 getJavaFileObjectsFromPaths(Iterable paths) { try { return ((StandardJavaFileManager)clientJavaFileManager).getJavaFileObjectsFromPaths(paths); diff -r 90fa9a095959 -r 0be43184f52a src/jdk.compiler/share/classes/com/sun/tools/javac/file/CacheFSInfo.java --- 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 canonicalPathCache = new ConcurrentHashMap<>(); + protected final ConcurrentHashMap> attributeCache = + new ConcurrentHashMap<>(); + protected final ConcurrentHashMap> 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 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 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 getAttributes(Path file) { + return attributeCache.computeIfAbsent(file, this::maybeReadAttributes); } - // could also be a Map> ? - private final Map cache = new ConcurrentHashMap<>(); - - private static class Entry { - Path canonicalFile; - boolean exists; - boolean isFile; - boolean isDirectory; - List jarClassPath; + protected Optional maybeReadAttributes(Path file) { + try { + return Optional.of(Files.readAttributes(file, BasicFileAttributes.class)); + } catch (IOException e) { + // Ignore; means file not found + return Optional.empty(); + } } } diff -r 90fa9a095959 -r 0be43184f52a src/jdk.compiler/share/classes/com/sun/tools/javac/file/JavacFileManager.java --- 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 getJavaFileObjectsFromPaths( - Iterable paths) + Collection paths) { ArrayList result; if (paths instanceof Collection) diff -r 90fa9a095959 -r 0be43184f52a src/jdk.compiler/share/classes/com/sun/tools/javac/main/DelegatingJavaFileManager.java --- 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 getJavaFileObjectsFromPaths + (Collection paths) { + return baseSJFM.getJavaFileObjectsFromPaths(paths); + } + + @Deprecated(since = "13") + @Override + public Iterable getJavaFileObjectsFromPaths (Iterable paths) { return baseSJFM.getJavaFileObjectsFromPaths(paths); } diff -r 90fa9a095959 -r 0be43184f52a test/hotspot/jtreg/ProblemList.txt --- 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 diff -r 90fa9a095959 -r 0be43184f52a test/hotspot/jtreg/runtime/appcds/jvmti/InstrumentationApp.java --- 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; diff -r 90fa9a095959 -r 0be43184f52a test/hotspot/jtreg/runtime/appcds/jvmti/InstrumentationTest.java --- 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 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); diff -r 90fa9a095959 -r 0be43184f52a test/hotspot/jtreg/runtime/containers/docker/Dockerfile-BasicTest --- 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"] diff -r 90fa9a095959 -r 0be43184f52a test/hotspot/jtreg/runtime/containers/docker/Dockerfile-BasicTest-aarch64 --- 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"] diff -r 90fa9a095959 -r 0be43184f52a test/hotspot/jtreg/runtime/containers/docker/Dockerfile-BasicTest-ppc64le --- 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"] diff -r 90fa9a095959 -r 0be43184f52a test/hotspot/jtreg/runtime/containers/docker/Dockerfile-BasicTest-s390x --- 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"] diff -r 90fa9a095959 -r 0be43184f52a test/hotspot/jtreg/serviceability/sa/TestUniverse.java --- 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 cmds = List.of("universe"); Map> expStrMap = new HashMap<>(); List expStrings = new ArrayList(); 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 vmArgs = new ArrayList(); - 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; diff -r 90fa9a095959 -r 0be43184f52a test/jdk/java/lang/String/StringRepeat.java --- 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; diff -r 90fa9a095959 -r 0be43184f52a test/jdk/java/lang/invoke/MethodHandlesGeneralTest.java --- 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); diff -r 90fa9a095959 -r 0be43184f52a test/jdk/java/lang/invoke/MethodHandlesTest.java --- 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 }); } } diff -r 90fa9a095959 -r 0be43184f52a test/jdk/java/lang/invoke/VarHandles/accessibility/TestFieldLookupAccessibility.java --- 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 inaccessibleFields(Set 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 inaccessibleFields(SetinaccessibleFields) { + Set 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 inaccessibleFields(Set 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 inaccessibleFields) { // Add to the expected failures all inaccessible fields due to accessibility modifiers - Set expected = new HashSet<>(inaccessibleFields); + Set expected = fl.inaccessibleFields(inaccessibleFields); Map 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:"); diff -r 90fa9a095959 -r 0be43184f52a test/jdk/java/math/BigInteger/LargeValueExceptions.java --- 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; diff -r 90fa9a095959 -r 0be43184f52a test/jdk/java/util/Base64/TestEncodingDecodingLength.java --- 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 * */ diff -r 90fa9a095959 -r 0be43184f52a test/jdk/jdk/internal/platform/docker/Dockerfile-BasicTest --- 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"] diff -r 90fa9a095959 -r 0be43184f52a test/jdk/jdk/internal/platform/docker/Dockerfile-BasicTest-aarch64 --- 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"] diff -r 90fa9a095959 -r 0be43184f52a test/jdk/jdk/internal/platform/docker/Dockerfile-BasicTest-ppc64le --- 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"] diff -r 90fa9a095959 -r 0be43184f52a test/jdk/jdk/internal/platform/docker/Dockerfile-BasicTest-s390x --- 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"] diff -r 90fa9a095959 -r 0be43184f52a test/langtools/tools/javac/api/file/SJFM_GetFileObjects.java --- 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 paths) + throws IOException { + boolean expectException = !isGetFileObjectsSupported(fm, paths); + try { + compile(fm.getJavaFileObjectsFromPaths((Iterable) 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. * diff -r 90fa9a095959 -r 0be43184f52a test/lib/jdk/test/lib/containers/docker/DockerTestUtils.java --- 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 { private final Path src; private final Path dst; diff -r 90fa9a095959 -r 0be43184f52a test/lib/jdk/test/lib/containers/docker/DockerfileConfig.java --- /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= -Djdk.test.docker.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"; + } + } +}