This commit is contained in:
J. Duke 2017-07-05 20:06:08 +02:00
commit e5670aea37
251 changed files with 4750 additions and 2055 deletions

View File

@ -279,3 +279,4 @@ e4ba01b726e263953ae129be37c94de6ed145b1d jdk9-b33
087b23f35631e68e950496a36fce8ccca612966a jdk9-b34
c173ba994245380fb11ef077d1e59823386840eb jdk9-b35
201d4e235d597a25a2d3ee1404394789ba386119 jdk9-b36
723a67b0c442391447b1d8aad8b249d06d1032e8 jdk9-b37

View File

@ -136,8 +136,8 @@ AC_DEFUN_ONCE([FLAGS_SETUP_INIT_FLAGS],
SYSROOT_CFLAGS="-isysroot \"$SYSROOT\" -iframework\"$SYSROOT/System/Library/Frameworks\""
SYSROOT_LDFLAGS=$SYSROOT_CFLAGS
elif test "x$TOOLCHAIN_TYPE" = xgcc; then
SYSROOT_CFLAGS="--sysroot=\"$SYSROOT\""
SYSROOT_LDFLAGS="--sysroot=\"$SYSROOT\""
SYSROOT_CFLAGS="--sysroot=$SYSROOT"
SYSROOT_LDFLAGS="--sysroot=$SYSROOT"
elif test "x$TOOLCHAIN_TYPE" = xclang; then
SYSROOT_CFLAGS="-isysroot \"$SYSROOT\""
SYSROOT_LDFLAGS="-isysroot \"$SYSROOT\""

View File

@ -4328,7 +4328,7 @@ TOOLCHAIN_DESCRIPTION_xlc="IBM XL C/C++"
#CUSTOM_AUTOCONF_INCLUDE
# Do not change or remove the following line, it is needed for consistency checks:
DATE_WHEN_GENERATED=1413533532
DATE_WHEN_GENERATED=1414663067
###############################################################################
#
@ -41681,8 +41681,8 @@ $as_echo "$tool_specified" >&6; }
SYSROOT_CFLAGS="-isysroot \"$SYSROOT\" -iframework\"$SYSROOT/System/Library/Frameworks\""
SYSROOT_LDFLAGS=$SYSROOT_CFLAGS
elif test "x$TOOLCHAIN_TYPE" = xgcc; then
SYSROOT_CFLAGS="--sysroot=\"$SYSROOT\""
SYSROOT_LDFLAGS="--sysroot=\"$SYSROOT\""
SYSROOT_CFLAGS="--sysroot=$SYSROOT"
SYSROOT_LDFLAGS="--sysroot=$SYSROOT"
elif test "x$TOOLCHAIN_TYPE" = xclang; then
SYSROOT_CFLAGS="-isysroot \"$SYSROOT\""
SYSROOT_LDFLAGS="-isysroot \"$SYSROOT\""
@ -44037,17 +44037,6 @@ fi
-R$OPENWIN_HOME/lib$OPENJDK_TARGET_CPU_ISADIR"
fi
#
# Weird Sol10 something check...TODO change to try compile
#
if test "x${OPENJDK_TARGET_OS}" = xsolaris; then
if test "`uname -r`" = "5.10"; then
if test "`${EGREP} -c XLinearGradient ${OPENWIN_HOME}/share/include/X11/extensions/Xrender.h`" = "0"; then
X_CFLAGS="${X_CFLAGS} -DSOLARIS10_NO_XRENDER_STRUCTS"
fi
fi
fi
ac_ext=c
ac_cpp='$CPP $CPPFLAGS'
ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
@ -44055,7 +44044,7 @@ ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $
ac_compiler_gnu=$ac_cv_c_compiler_gnu
OLD_CFLAGS="$CFLAGS"
CFLAGS="$CFLAGS $X_CFLAGS"
CFLAGS="$CFLAGS $SYSROOT_CFLAGS $X_CFLAGS"
# Need to include Xlib.h and Xutil.h to avoid "present but cannot be compiled" warnings on Solaris 10
for ac_header in X11/extensions/shape.h X11/extensions/Xrender.h X11/extensions/XTest.h X11/Intrinsic.h
@ -44079,6 +44068,31 @@ fi
done
# If XLinearGradient isn't available in Xrender.h, signal that it needs to be
# defined in libawt_xawt.
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking if XlinearGradient is defined in Xrender.h" >&5
$as_echo_n "checking if XlinearGradient is defined in Xrender.h... " >&6; }
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
#include <X11/extensions/Xrender.h>
int
main ()
{
XLinearGradient x;
;
return 0;
}
_ACEOF
if ac_fn_c_try_compile "$LINENO"; then :
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
$as_echo "yes" >&6; }
else
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
$as_echo "no" >&6; }
X_CFLAGS="$X_CFLAGS -DSOLARIS10_NO_XRENDER_STRUCTS"
fi
rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
CFLAGS="$OLD_CFLAGS"
ac_ext=cpp
ac_cpp='$CXXCPP $CPPFLAGS'

View File

@ -139,20 +139,9 @@ AC_DEFUN_ONCE([LIB_SETUP_X11],
-R$OPENWIN_HOME/lib$OPENJDK_TARGET_CPU_ISADIR"
fi
#
# Weird Sol10 something check...TODO change to try compile
#
if test "x${OPENJDK_TARGET_OS}" = xsolaris; then
if test "`uname -r`" = "5.10"; then
if test "`${EGREP} -c XLinearGradient ${OPENWIN_HOME}/share/include/X11/extensions/Xrender.h`" = "0"; then
X_CFLAGS="${X_CFLAGS} -DSOLARIS10_NO_XRENDER_STRUCTS"
fi
fi
fi
AC_LANG_PUSH(C)
OLD_CFLAGS="$CFLAGS"
CFLAGS="$CFLAGS $X_CFLAGS"
CFLAGS="$CFLAGS $SYSROOT_CFLAGS $X_CFLAGS"
# Need to include Xlib.h and Xutil.h to avoid "present but cannot be compiled" warnings on Solaris 10
AC_CHECK_HEADERS([X11/extensions/shape.h X11/extensions/Xrender.h X11/extensions/XTest.h X11/Intrinsic.h],
@ -164,6 +153,16 @@ AC_DEFUN_ONCE([LIB_SETUP_X11],
]
)
# If XLinearGradient isn't available in Xrender.h, signal that it needs to be
# defined in libawt_xawt.
AC_MSG_CHECKING([if XlinearGradient is defined in Xrender.h])
AC_COMPILE_IFELSE(
[AC_LANG_PROGRAM([[#include <X11/extensions/Xrender.h>]],
[[XLinearGradient x;]])],
[AC_MSG_RESULT([yes])],
[AC_MSG_RESULT([no])
X_CFLAGS="$X_CFLAGS -DSOLARIS10_NO_XRENDER_STRUCTS"])
CFLAGS="$OLD_CFLAGS"
AC_LANG_POP(C)

View File

@ -279,3 +279,4 @@ cfdac5887952c2dd73c73a1d8d9aa880d0539bbf jdk9-b33
24a0bad5910f775bb4002d1dacf8b3af87c63cd8 jdk9-b34
9bc2dbd3dfb8c9fa88e00056b8b93a81ee6d306e jdk9-b35
ffd90c81d4ef9d94d880fc852e2fc482ecd9b374 jdk9-b36
7e9add74ad50841fb39dae75db56374aefa1de4c jdk9-b37

View File

@ -439,3 +439,4 @@ af46576a8d7cb4003028b8ee8bf408cfe227315b jdk9-b32
821164b0131a47ca065697c7d27d8f215e608c8d jdk9-b34
438cb613151c4bd290bb732697517cba1cafcb04 jdk9-b35
464ab653fbb17eb518d8ef60f8df301de7ef00d0 jdk9-b36
b1c2dd843f247a1db19e1e85eb62ca405f72dc26 jdk9-b37

View File

@ -734,7 +734,7 @@ bool ClassLoaderDataGraph::contains_loader_data(ClassLoaderData* loader_data) {
// Move class loader data from main list to the unloaded list for unloading
// and deallocation later.
bool ClassLoaderDataGraph::do_unloading(BoolObjectClosure* is_alive_closure) {
bool ClassLoaderDataGraph::do_unloading(BoolObjectClosure* is_alive_closure, bool clean_alive) {
ClassLoaderData* data = _head;
ClassLoaderData* prev = NULL;
bool seen_dead_loader = false;
@ -743,27 +743,9 @@ bool ClassLoaderDataGraph::do_unloading(BoolObjectClosure* is_alive_closure) {
// purging and we don't want to rewalk the previously unloaded class loader data.
_saved_unloading = _unloading;
// mark metadata seen on the stack and code cache so we can delete
// unneeded entries.
bool has_redefined_a_class = JvmtiExport::has_redefined_a_class();
MetadataOnStackMark md_on_stack(has_redefined_a_class);
if (has_redefined_a_class) {
// purge_previous_versions also cleans weak method links. Because
// one method's MDO can reference another method from another
// class loader, we need to first clean weak method links for all
// class loaders here. Below, we can then free redefined methods
// for all class loaders.
while (data != NULL) {
if (data->is_alive(is_alive_closure)) {
data->classes_do(InstanceKlass::purge_previous_versions);
}
data = data->next();
}
}
data = _head;
while (data != NULL) {
if (data->is_alive(is_alive_closure)) {
data->free_deallocate_list();
prev = data;
data = data->next();
continue;
@ -785,6 +767,11 @@ bool ClassLoaderDataGraph::do_unloading(BoolObjectClosure* is_alive_closure) {
_unloading = dead;
}
if (clean_alive) {
// Clean previous versions and the deallocate list.
ClassLoaderDataGraph::clean_metaspaces();
}
if (seen_dead_loader) {
post_class_unload_events();
}
@ -792,6 +779,26 @@ bool ClassLoaderDataGraph::do_unloading(BoolObjectClosure* is_alive_closure) {
return seen_dead_loader;
}
void ClassLoaderDataGraph::clean_metaspaces() {
// mark metadata seen on the stack and code cache so we can delete unneeded entries.
bool has_redefined_a_class = JvmtiExport::has_redefined_a_class();
MetadataOnStackMark md_on_stack(has_redefined_a_class);
if (has_redefined_a_class) {
// purge_previous_versions also cleans weak method links. Because
// one method's MDO can reference another method from another
// class loader, we need to first clean weak method links for all
// class loaders here. Below, we can then free redefined methods
// for all class loaders.
for (ClassLoaderData* data = _head; data != NULL; data = data->next()) {
data->classes_do(InstanceKlass::purge_previous_versions);
}
}
// Need to purge the previous version before deallocating.
free_deallocate_lists();
}
void ClassLoaderDataGraph::purge() {
assert(SafepointSynchronize::is_at_safepoint(), "must be at safepoint!");
ClassLoaderData* list = _unloading;
@ -819,6 +826,14 @@ void ClassLoaderDataGraph::post_class_unload_events(void) {
#endif
}
void ClassLoaderDataGraph::free_deallocate_lists() {
for (ClassLoaderData* cld = _head; cld != NULL; cld = cld->next()) {
// We need to keep this data until InstanceKlass::purge_previous_version has been
// called on all alive classes. See the comment in ClassLoaderDataGraph::clean_metaspaces.
cld->free_deallocate_list();
}
}
// CDS support
// Global metaspaces for writing information to the shared archive. When

View File

@ -71,6 +71,7 @@ class ClassLoaderDataGraph : public AllStatic {
static ClassLoaderData* add(Handle class_loader, bool anonymous, TRAPS);
static void post_class_unload_events(void);
static void clean_metaspaces();
public:
static ClassLoaderData* find_or_create(Handle class_loader, TRAPS);
static void purge();
@ -90,7 +91,7 @@ class ClassLoaderDataGraph : public AllStatic {
static void methods_do(void f(Method*));
static void loaded_classes_do(KlassClosure* klass_closure);
static void classes_unloading_do(void f(Klass* const));
static bool do_unloading(BoolObjectClosure* is_alive);
static bool do_unloading(BoolObjectClosure* is_alive, bool clean_alive);
// CMS support.
static void remember_new_clds(bool remember) { _saved_head = (remember ? _head : NULL); }
@ -106,6 +107,8 @@ class ClassLoaderDataGraph : public AllStatic {
}
}
static void free_deallocate_lists();
static void dump_on(outputStream * const out) PRODUCT_RETURN;
static void dump() { dump_on(tty); }
static void verify();

View File

@ -31,25 +31,23 @@
#include "runtime/synchronizer.hpp"
#include "runtime/thread.hpp"
#include "services/threadService.hpp"
#include "utilities/growableArray.hpp"
#include "utilities/chunkedList.hpp"
volatile MetadataOnStackBuffer* MetadataOnStackMark::_used_buffers = NULL;
volatile MetadataOnStackBuffer* MetadataOnStackMark::_free_buffers = NULL;
// Keep track of marked on-stack metadata so it can be cleared.
GrowableArray<Metadata*>* _marked_objects = NULL;
NOT_PRODUCT(bool MetadataOnStackMark::_is_active = false;)
// Walk metadata on the stack and mark it so that redefinition doesn't delete
// it. Class unloading also walks the previous versions and might try to
// delete it, so this class is used by class unloading also.
MetadataOnStackMark::MetadataOnStackMark(bool has_redefined_a_class) {
MetadataOnStackMark::MetadataOnStackMark(bool visit_code_cache) {
assert(SafepointSynchronize::is_at_safepoint(), "sanity check");
assert(_used_buffers == NULL, "sanity check");
NOT_PRODUCT(_is_active = true;)
if (_marked_objects == NULL) {
_marked_objects = new (ResourceObj::C_HEAP, mtClass) GrowableArray<Metadata*>(1000, true);
}
Threads::metadata_do(Metadata::mark_on_stack);
if (has_redefined_a_class) {
if (visit_code_cache) {
CodeCache::alive_nmethods_do(nmethod::mark_on_stack);
}
CompileBroker::mark_on_stack();
@ -62,15 +60,93 @@ MetadataOnStackMark::~MetadataOnStackMark() {
// Unmark everything that was marked. Can't do the same walk because
// redefine classes messes up the code cache so the set of methods
// might not be the same.
for (int i = 0; i< _marked_objects->length(); i++) {
_marked_objects->at(i)->set_on_stack(false);
retire_buffer_for_thread(Thread::current());
MetadataOnStackBuffer* buffer = const_cast<MetadataOnStackBuffer* >(_used_buffers);
while (buffer != NULL) {
// Clear on stack state for all metadata.
size_t size = buffer->size();
for (size_t i = 0; i < size; i++) {
Metadata* md = buffer->at(i);
md->set_on_stack(false);
}
MetadataOnStackBuffer* next = buffer->next_used();
// Move the buffer to the free list.
buffer->clear();
buffer->set_next_used(NULL);
buffer->set_next_free(const_cast<MetadataOnStackBuffer*>(_free_buffers));
_free_buffers = buffer;
// Step to next used buffer.
buffer = next;
}
_marked_objects->clear(); // reuse growable array for next time.
_used_buffers = NULL;
NOT_PRODUCT(_is_active = false;)
}
// Record which objects are marked so we can unmark the same objects.
void MetadataOnStackMark::record(Metadata* m) {
assert(_is_active, "metadata on stack marking is active");
_marked_objects->push(m);
void MetadataOnStackMark::retire_buffer(MetadataOnStackBuffer* buffer) {
if (buffer == NULL) {
return;
}
MetadataOnStackBuffer* old_head;
do {
old_head = const_cast<MetadataOnStackBuffer*>(_used_buffers);
buffer->set_next_used(old_head);
} while (Atomic::cmpxchg_ptr(buffer, &_used_buffers, old_head) != old_head);
}
void MetadataOnStackMark::retire_buffer_for_thread(Thread* thread) {
retire_buffer(thread->metadata_on_stack_buffer());
thread->set_metadata_on_stack_buffer(NULL);
}
bool MetadataOnStackMark::has_buffer_for_thread(Thread* thread) {
return thread->metadata_on_stack_buffer() != NULL;
}
MetadataOnStackBuffer* MetadataOnStackMark::allocate_buffer() {
MetadataOnStackBuffer* allocated;
MetadataOnStackBuffer* new_head;
do {
allocated = const_cast<MetadataOnStackBuffer*>(_free_buffers);
if (allocated == NULL) {
break;
}
new_head = allocated->next_free();
} while (Atomic::cmpxchg_ptr(new_head, &_free_buffers, allocated) != allocated);
if (allocated == NULL) {
allocated = new MetadataOnStackBuffer();
}
assert(!allocated->is_full(), err_msg("Should not be full: " PTR_FORMAT, p2i(allocated)));
return allocated;
}
// Record which objects are marked so we can unmark the same objects.
void MetadataOnStackMark::record(Metadata* m, Thread* thread) {
assert(_is_active, "metadata on stack marking is active");
MetadataOnStackBuffer* buffer = thread->metadata_on_stack_buffer();
if (buffer != NULL && buffer->is_full()) {
retire_buffer(buffer);
buffer = NULL;
}
if (buffer == NULL) {
buffer = allocate_buffer();
thread->set_metadata_on_stack_buffer(buffer);
}
buffer->push(m);
}

View File

@ -26,9 +26,12 @@
#define SHARE_VM_CLASSFILE_METADATAONSTACKMARK_HPP
#include "memory/allocation.hpp"
#include "utilities/chunkedList.hpp"
class Metadata;
typedef ChunkedList<Metadata*, mtInternal> MetadataOnStackBuffer;
// Helper class to mark and unmark metadata used on the stack as either handles
// or executing methods, so that it can't be deleted during class redefinition
// and class unloading.
@ -36,10 +39,20 @@ class Metadata;
// metadata during parsing, relocated methods, and methods in backtraces.
class MetadataOnStackMark : public StackObj {
NOT_PRODUCT(static bool _is_active;)
static volatile MetadataOnStackBuffer* _used_buffers;
static volatile MetadataOnStackBuffer* _free_buffers;
static MetadataOnStackBuffer* allocate_buffer();
static void retire_buffer(MetadataOnStackBuffer* buffer);
public:
MetadataOnStackMark(bool has_redefined_a_class);
~MetadataOnStackMark();
static void record(Metadata* m);
MetadataOnStackMark(bool visit_code_cache);
~MetadataOnStackMark();
static void record(Metadata* m, Thread* thread);
static void retire_buffer_for_thread(Thread* thread);
static bool has_buffer_for_thread(Thread* thread);
};
#endif // SHARE_VM_CLASSFILE_METADATAONSTACKMARK_HPP

View File

@ -1690,9 +1690,9 @@ public:
// Assumes classes in the SystemDictionary are only unloaded at a safepoint
// Note: anonymous classes are not in the SD.
bool SystemDictionary::do_unloading(BoolObjectClosure* is_alive) {
bool SystemDictionary::do_unloading(BoolObjectClosure* is_alive, bool clean_alive) {
// First, mark for unload all ClassLoaderData referencing a dead class loader.
bool unloading_occurred = ClassLoaderDataGraph::do_unloading(is_alive);
bool unloading_occurred = ClassLoaderDataGraph::do_unloading(is_alive, clean_alive);
if (unloading_occurred) {
dictionary()->do_unloading();
constraints()->purge_loader_constraints();

View File

@ -334,7 +334,7 @@ public:
// Unload (that is, break root links to) all unmarked classes and
// loaders. Returns "true" iff something was unloaded.
static bool do_unloading(BoolObjectClosure* is_alive);
static bool do_unloading(BoolObjectClosure* is_alive, bool clean_alive = true);
// Used by DumpSharedSpaces only to remove classes that failed verification
static void remove_classes_in_error_state();

View File

@ -1700,11 +1700,17 @@ void nmethod::post_compiled_method_unload() {
set_unload_reported();
}
void static clean_ic_if_metadata_is_dead(CompiledIC *ic, BoolObjectClosure *is_alive) {
void static clean_ic_if_metadata_is_dead(CompiledIC *ic, BoolObjectClosure *is_alive, bool mark_on_stack) {
if (ic->is_icholder_call()) {
// The only exception is compiledICHolder oops which may
// yet be marked below. (We check this further below).
CompiledICHolder* cichk_oop = ic->cached_icholder();
if (mark_on_stack) {
Metadata::mark_on_stack(cichk_oop->holder_method());
Metadata::mark_on_stack(cichk_oop->holder_klass());
}
if (cichk_oop->holder_method()->method_holder()->is_loader_alive(is_alive) &&
cichk_oop->holder_klass()->is_loader_alive(is_alive)) {
return;
@ -1712,6 +1718,10 @@ void static clean_ic_if_metadata_is_dead(CompiledIC *ic, BoolObjectClosure *is_a
} else {
Metadata* ic_oop = ic->cached_metadata();
if (ic_oop != NULL) {
if (mark_on_stack) {
Metadata::mark_on_stack(ic_oop);
}
if (ic_oop->is_klass()) {
if (((Klass*)ic_oop)->is_loader_alive(is_alive)) {
return;
@ -1772,7 +1782,7 @@ void nmethod::do_unloading(BoolObjectClosure* is_alive, bool unloading_occurred)
while(iter.next()) {
if (iter.type() == relocInfo::virtual_call_type) {
CompiledIC *ic = CompiledIC_at(&iter);
clean_ic_if_metadata_is_dead(ic, is_alive);
clean_ic_if_metadata_is_dead(ic, is_alive, false);
}
}
}
@ -1840,6 +1850,53 @@ static bool clean_if_nmethod_is_unloaded(CompiledStaticCall *csc, BoolObjectClos
return clean_if_nmethod_is_unloaded(csc, csc->destination(), is_alive, from);
}
bool nmethod::unload_if_dead_at(RelocIterator* iter_at_oop, BoolObjectClosure *is_alive, bool unloading_occurred) {
assert(iter_at_oop->type() == relocInfo::oop_type, "Wrong relocation type");
oop_Relocation* r = iter_at_oop->oop_reloc();
// Traverse those oops directly embedded in the code.
// Other oops (oop_index>0) are seen as part of scopes_oops.
assert(1 == (r->oop_is_immediate()) +
(r->oop_addr() >= oops_begin() && r->oop_addr() < oops_end()),
"oop must be found in exactly one place");
if (r->oop_is_immediate() && r->oop_value() != NULL) {
// Unload this nmethod if the oop is dead.
if (can_unload(is_alive, r->oop_addr(), unloading_occurred)) {
return true;;
}
}
return false;
}
void nmethod::mark_metadata_on_stack_at(RelocIterator* iter_at_metadata) {
assert(iter_at_metadata->type() == relocInfo::metadata_type, "Wrong relocation type");
metadata_Relocation* r = iter_at_metadata->metadata_reloc();
// In this metadata, we must only follow those metadatas directly embedded in
// the code. Other metadatas (oop_index>0) are seen as part of
// the metadata section below.
assert(1 == (r->metadata_is_immediate()) +
(r->metadata_addr() >= metadata_begin() && r->metadata_addr() < metadata_end()),
"metadata must be found in exactly one place");
if (r->metadata_is_immediate() && r->metadata_value() != NULL) {
Metadata* md = r->metadata_value();
if (md != _method) Metadata::mark_on_stack(md);
}
}
void nmethod::mark_metadata_on_stack_non_relocs() {
// Visit the metadata section
for (Metadata** p = metadata_begin(); p < metadata_end(); p++) {
if (*p == Universe::non_oop_word() || *p == NULL) continue; // skip non-oops
Metadata* md = *p;
Metadata::mark_on_stack(md);
}
// Visit metadata not embedded in the other places.
if (_method != NULL) Metadata::mark_on_stack(_method);
}
bool nmethod::do_unloading_parallel(BoolObjectClosure* is_alive, bool unloading_occurred) {
ResourceMark rm;
@ -1869,6 +1926,11 @@ bool nmethod::do_unloading_parallel(BoolObjectClosure* is_alive, bool unloading_
unloading_occurred = true;
}
// When class redefinition is used all metadata in the CodeCache has to be recorded,
// so that unused "previous versions" can be purged. Since walking the CodeCache can
// be expensive, the "mark on stack" is piggy-backed on this parallel unloading code.
bool mark_metadata_on_stack = a_class_was_redefined;
// Exception cache
clean_exception_cache(is_alive);
@ -1884,7 +1946,7 @@ bool nmethod::do_unloading_parallel(BoolObjectClosure* is_alive, bool unloading_
if (unloading_occurred) {
// If class unloading occurred we first iterate over all inline caches and
// clear ICs where the cached oop is referring to an unloaded klass or method.
clean_ic_if_metadata_is_dead(CompiledIC_at(&iter), is_alive);
clean_ic_if_metadata_is_dead(CompiledIC_at(&iter), is_alive, mark_metadata_on_stack);
}
postponed |= clean_if_nmethod_is_unloaded(CompiledIC_at(&iter), is_alive, this);
@ -1900,24 +1962,21 @@ bool nmethod::do_unloading_parallel(BoolObjectClosure* is_alive, bool unloading_
case relocInfo::oop_type:
if (!is_unloaded) {
// Unload check
oop_Relocation* r = iter.oop_reloc();
// Traverse those oops directly embedded in the code.
// Other oops (oop_index>0) are seen as part of scopes_oops.
assert(1 == (r->oop_is_immediate()) +
(r->oop_addr() >= oops_begin() && r->oop_addr() < oops_end()),
"oop must be found in exactly one place");
if (r->oop_is_immediate() && r->oop_value() != NULL) {
if (can_unload(is_alive, r->oop_addr(), unloading_occurred)) {
is_unloaded = true;
}
}
is_unloaded = unload_if_dead_at(&iter, is_alive, unloading_occurred);
}
break;
case relocInfo::metadata_type:
if (mark_metadata_on_stack) {
mark_metadata_on_stack_at(&iter);
}
}
}
if (mark_metadata_on_stack) {
mark_metadata_on_stack_non_relocs();
}
if (is_unloaded) {
return postponed;
}
@ -2065,7 +2124,7 @@ void nmethod::metadata_do(void f(Metadata*)) {
while (iter.next()) {
if (iter.type() == relocInfo::metadata_type ) {
metadata_Relocation* r = iter.metadata_reloc();
// In this lmetadata, we must only follow those metadatas directly embedded in
// In this metadata, we must only follow those metadatas directly embedded in
// the code. Other metadatas (oop_index>0) are seen as part of
// the metadata section below.
assert(1 == (r->metadata_is_immediate()) +
@ -2099,7 +2158,7 @@ void nmethod::metadata_do(void f(Metadata*)) {
f(md);
}
// Call function Method*, not embedded in these other places.
// Visit metadata not embedded in the other places.
if (_method != NULL) f(_method);
}

View File

@ -615,9 +615,16 @@ public:
// The parallel versions are used by G1.
bool do_unloading_parallel(BoolObjectClosure* is_alive, bool unloading_occurred);
void do_unloading_parallel_postponed(BoolObjectClosure* is_alive, bool unloading_occurred);
private:
// Unload a nmethod if the *root object is dead.
bool can_unload(BoolObjectClosure* is_alive, oop* root, bool unloading_occurred);
bool unload_if_dead_at(RelocIterator *iter_at_oop, BoolObjectClosure* is_alive, bool unloading_occurred);
void mark_metadata_on_stack_at(RelocIterator* iter_at_metadata);
void mark_metadata_on_stack_non_relocs();
public:
void preserve_callee_argument_oops(frame fr, const RegisterMap *reg_map,
OopClosure* f);
void oops_do(OopClosure* f) { oops_do(f, false); }

View File

@ -64,23 +64,6 @@ void AdaptiveFreeList<Chunk>::reset(size_t hint) {
set_hint(hint);
}
#ifndef PRODUCT
template <class Chunk>
void AdaptiveFreeList<Chunk>::assert_proper_lock_protection_work() const {
assert(protecting_lock() != NULL, "Don't call this directly");
assert(ParallelGCThreads > 0, "Don't call this directly");
Thread* thr = Thread::current();
if (thr->is_VM_thread() || thr->is_ConcurrentGC_thread()) {
// assert that we are holding the freelist lock
} else if (thr->is_GC_task_thread()) {
assert(protecting_lock()->owned_by_self(), "FreeList RACE DETECTED");
} else if (thr->is_Java_thread()) {
assert(!SafepointSynchronize::is_at_safepoint(), "Should not be executing");
} else {
ShouldNotReachHere(); // unaccounted thread type?
}
}
#endif
template <class Chunk>
void AdaptiveFreeList<Chunk>::init_statistics(bool split_birth) {
_allocation_stats.initialize(split_birth);

View File

@ -81,8 +81,6 @@ class AdaptiveFreeList : public FreeList<Chunk> {
// Reset the head, tail, hint, and count of a free list.
void reset(size_t hint);
void assert_proper_lock_protection_work() const PRODUCT_RETURN;
void print_on(outputStream* st, const char* c = NULL) const;
size_t hint() const {

View File

@ -149,18 +149,15 @@ CompactibleFreeListSpace::CompactibleFreeListSpace(BlockOffsetSharedArray* bs,
check_free_list_consistency();
// Initialize locks for parallel case.
if (CollectedHeap::use_parallel_gc_threads()) {
for (size_t i = IndexSetStart; i < IndexSetSize; i += IndexSetStride) {
_indexedFreeListParLocks[i] = new Mutex(Mutex::leaf - 1, // == ExpandHeap_lock - 1
"a freelist par lock",
true);
DEBUG_ONLY(
_indexedFreeList[i].set_protecting_lock(_indexedFreeListParLocks[i]);
)
}
_dictionary->set_par_lock(&_parDictionaryAllocLock);
for (size_t i = IndexSetStart; i < IndexSetSize; i += IndexSetStride) {
_indexedFreeListParLocks[i] = new Mutex(Mutex::leaf - 1, // == ExpandHeap_lock - 1
"a freelist par lock",
true);
DEBUG_ONLY(
_indexedFreeList[i].set_protecting_lock(_indexedFreeListParLocks[i]);
)
}
_dictionary->set_par_lock(&_parDictionaryAllocLock);
}
// Like CompactibleSpace forward() but always calls cross_threshold() to
@ -622,17 +619,11 @@ void CompactibleFreeListSpace::set_end(HeapWord* value) {
// Mark the boundary of the new block in BOT
_bt.mark_block(prevEnd, value);
// put it all in the linAB
if (ParallelGCThreads == 0) {
_smallLinearAllocBlock._ptr = prevEnd;
_smallLinearAllocBlock._word_size = newFcSize;
repairLinearAllocBlock(&_smallLinearAllocBlock);
} else { // ParallelGCThreads > 0
MutexLockerEx x(parDictionaryAllocLock(),
Mutex::_no_safepoint_check_flag);
_smallLinearAllocBlock._ptr = prevEnd;
_smallLinearAllocBlock._word_size = newFcSize;
repairLinearAllocBlock(&_smallLinearAllocBlock);
}
MutexLockerEx x(parDictionaryAllocLock(),
Mutex::_no_safepoint_check_flag);
_smallLinearAllocBlock._ptr = prevEnd;
_smallLinearAllocBlock._word_size = newFcSize;
repairLinearAllocBlock(&_smallLinearAllocBlock);
// Births of chunks put into a LinAB are not recorded. Births
// of chunks as they are allocated out of a LinAB are.
} else {
@ -1740,10 +1731,7 @@ CompactibleFreeListSpace::addChunkToFreeListsAtEndRecordingStats(
assert(chunk != NULL && is_in_reserved(chunk), "Not in this space!");
// One of the parallel gc task threads may be here
// whilst others are allocating.
Mutex* lock = NULL;
if (ParallelGCThreads != 0) {
lock = &_parDictionaryAllocLock;
}
Mutex* lock = &_parDictionaryAllocLock;
FreeChunk* ec;
{
MutexLockerEx x(lock, Mutex::_no_safepoint_check_flag);
@ -1760,7 +1748,7 @@ CompactibleFreeListSpace::addChunkToFreeListsAtEndRecordingStats(
}
ec->set_size(size);
debug_only(ec->mangleFreed(size));
if (size < SmallForDictionary && ParallelGCThreads != 0) {
if (size < SmallForDictionary) {
lock = _indexedFreeListParLocks[size];
}
MutexLockerEx x(lock, Mutex::_no_safepoint_check_flag);

View File

@ -887,10 +887,8 @@ void ConcurrentMarkSweepGeneration::reset_after_compaction() {
// along with all the other pointers into the heap but
// compaction is expected to be a rare event with
// a heap using cms so don't do it without seeing the need.
if (CollectedHeap::use_parallel_gc_threads()) {
for (uint i = 0; i < ParallelGCThreads; i++) {
_par_gc_thread_states[i]->promo.reset();
}
for (uint i = 0; i < ParallelGCThreads; i++) {
_par_gc_thread_states[i]->promo.reset();
}
}
@ -2804,10 +2802,8 @@ void ConcurrentMarkSweepGeneration::gc_epilogue(bool full) {
collector()->gc_epilogue(full);
// Also reset promotion tracking in par gc thread states.
if (CollectedHeap::use_parallel_gc_threads()) {
for (uint i = 0; i < ParallelGCThreads; i++) {
_par_gc_thread_states[i]->promo.stopTrackingPromotions(i);
}
for (uint i = 0; i < ParallelGCThreads; i++) {
_par_gc_thread_states[i]->promo.stopTrackingPromotions(i);
}
}

View File

@ -23,6 +23,7 @@
*/
#include "precompiled.hpp"
#include "classfile/metadataOnStackMark.hpp"
#include "classfile/symbolTable.hpp"
#include "code/codeCache.hpp"
#include "gc_implementation/g1/concurrentMark.inline.hpp"
@ -611,74 +612,64 @@ ConcurrentMark::ConcurrentMark(G1CollectedHeap* g1h, G1RegionToSpaceMapper* prev
ConcGCThreads, ParallelGCThreads);
return;
}
if (ParallelGCThreads == 0) {
// if we are not running with any parallel GC threads we will not
// spawn any marking threads either
_parallel_marking_threads = 0;
_max_parallel_marking_threads = 0;
_sleep_factor = 0.0;
_marking_task_overhead = 1.0;
if (!FLAG_IS_DEFAULT(ConcGCThreads) && ConcGCThreads > 0) {
// Note: ConcGCThreads has precedence over G1MarkingOverheadPercent
// if both are set
_sleep_factor = 0.0;
_marking_task_overhead = 1.0;
} else if (G1MarkingOverheadPercent > 0) {
// We will calculate the number of parallel marking threads based
// on a target overhead with respect to the soft real-time goal
double marking_overhead = (double) G1MarkingOverheadPercent / 100.0;
double overall_cm_overhead =
(double) MaxGCPauseMillis * marking_overhead /
(double) GCPauseIntervalMillis;
double cpu_ratio = 1.0 / (double) os::processor_count();
double marking_thread_num = ceil(overall_cm_overhead / cpu_ratio);
double marking_task_overhead =
overall_cm_overhead / marking_thread_num *
(double) os::processor_count();
double sleep_factor =
(1.0 - marking_task_overhead) / marking_task_overhead;
FLAG_SET_ERGO(uintx, ConcGCThreads, (uint) marking_thread_num);
_sleep_factor = sleep_factor;
_marking_task_overhead = marking_task_overhead;
} else {
if (!FLAG_IS_DEFAULT(ConcGCThreads) && ConcGCThreads > 0) {
// Note: ConcGCThreads has precedence over G1MarkingOverheadPercent
// if both are set
_sleep_factor = 0.0;
_marking_task_overhead = 1.0;
} else if (G1MarkingOverheadPercent > 0) {
// We will calculate the number of parallel marking threads based
// on a target overhead with respect to the soft real-time goal
double marking_overhead = (double) G1MarkingOverheadPercent / 100.0;
double overall_cm_overhead =
(double) MaxGCPauseMillis * marking_overhead /
(double) GCPauseIntervalMillis;
double cpu_ratio = 1.0 / (double) os::processor_count();
double marking_thread_num = ceil(overall_cm_overhead / cpu_ratio);
double marking_task_overhead =
overall_cm_overhead / marking_thread_num *
(double) os::processor_count();
double sleep_factor =
(1.0 - marking_task_overhead) / marking_task_overhead;
// Calculate the number of parallel marking threads by scaling
// the number of parallel GC threads.
uint marking_thread_num = scale_parallel_threads((uint) ParallelGCThreads);
FLAG_SET_ERGO(uintx, ConcGCThreads, marking_thread_num);
_sleep_factor = 0.0;
_marking_task_overhead = 1.0;
}
FLAG_SET_ERGO(uintx, ConcGCThreads, (uint) marking_thread_num);
_sleep_factor = sleep_factor;
_marking_task_overhead = marking_task_overhead;
} else {
// Calculate the number of parallel marking threads by scaling
// the number of parallel GC threads.
uint marking_thread_num = scale_parallel_threads((uint) ParallelGCThreads);
FLAG_SET_ERGO(uintx, ConcGCThreads, marking_thread_num);
_sleep_factor = 0.0;
_marking_task_overhead = 1.0;
}
assert(ConcGCThreads > 0, "Should have been set");
_parallel_marking_threads = (uint) ConcGCThreads;
_max_parallel_marking_threads = _parallel_marking_threads;
assert(ConcGCThreads > 0, "Should have been set");
_parallel_marking_threads = (uint) ConcGCThreads;
_max_parallel_marking_threads = _parallel_marking_threads;
if (parallel_marking_threads() > 1) {
_cleanup_task_overhead = 1.0;
} else {
_cleanup_task_overhead = marking_task_overhead();
}
_cleanup_sleep_factor =
(1.0 - cleanup_task_overhead()) / cleanup_task_overhead();
if (parallel_marking_threads() > 1) {
_cleanup_task_overhead = 1.0;
} else {
_cleanup_task_overhead = marking_task_overhead();
}
_cleanup_sleep_factor =
(1.0 - cleanup_task_overhead()) / cleanup_task_overhead();
#if 0
gclog_or_tty->print_cr("Marking Threads %d", parallel_marking_threads());
gclog_or_tty->print_cr("CM Marking Task Overhead %1.4lf", marking_task_overhead());
gclog_or_tty->print_cr("CM Sleep Factor %1.4lf", sleep_factor());
gclog_or_tty->print_cr("CL Marking Task Overhead %1.4lf", cleanup_task_overhead());
gclog_or_tty->print_cr("CL Sleep Factor %1.4lf", cleanup_sleep_factor());
gclog_or_tty->print_cr("Marking Threads %d", parallel_marking_threads());
gclog_or_tty->print_cr("CM Marking Task Overhead %1.4lf", marking_task_overhead());
gclog_or_tty->print_cr("CM Sleep Factor %1.4lf", sleep_factor());
gclog_or_tty->print_cr("CL Marking Task Overhead %1.4lf", cleanup_task_overhead());
gclog_or_tty->print_cr("CL Sleep Factor %1.4lf", cleanup_sleep_factor());
#endif
guarantee(parallel_marking_threads() > 0, "peace of mind");
_parallel_workers = new FlexibleWorkGang("G1 Parallel Marking Threads",
_max_parallel_marking_threads, false, true);
if (_parallel_workers == NULL) {
vm_exit_during_initialization("Failed necessary allocation.");
} else {
_parallel_workers->initialize_workers();
}
_parallel_workers = new FlexibleWorkGang("G1 Parallel Marking Threads",
_max_parallel_marking_threads, false, true);
if (_parallel_workers == NULL) {
vm_exit_during_initialization("Failed necessary allocation.");
} else {
_parallel_workers->initialize_workers();
}
if (FLAG_IS_DEFAULT(MarkStackSize)) {
@ -1166,29 +1157,23 @@ public:
// Calculates the number of active workers for a concurrent
// phase.
uint ConcurrentMark::calc_parallel_marking_threads() {
if (G1CollectedHeap::use_parallel_gc_threads()) {
uint n_conc_workers = 0;
if (!UseDynamicNumberOfGCThreads ||
(!FLAG_IS_DEFAULT(ConcGCThreads) &&
!ForceDynamicNumberOfGCThreads)) {
n_conc_workers = max_parallel_marking_threads();
} else {
n_conc_workers =
AdaptiveSizePolicy::calc_default_active_workers(
max_parallel_marking_threads(),
1, /* Minimum workers */
parallel_marking_threads(),
Threads::number_of_non_daemon_threads());
// Don't scale down "n_conc_workers" by scale_parallel_threads() because
// that scaling has already gone into "_max_parallel_marking_threads".
}
assert(n_conc_workers > 0, "Always need at least 1");
return n_conc_workers;
uint n_conc_workers = 0;
if (!UseDynamicNumberOfGCThreads ||
(!FLAG_IS_DEFAULT(ConcGCThreads) &&
!ForceDynamicNumberOfGCThreads)) {
n_conc_workers = max_parallel_marking_threads();
} else {
n_conc_workers =
AdaptiveSizePolicy::calc_default_active_workers(
max_parallel_marking_threads(),
1, /* Minimum workers */
parallel_marking_threads(),
Threads::number_of_non_daemon_threads());
// Don't scale down "n_conc_workers" by scale_parallel_threads() because
// that scaling has already gone into "_max_parallel_marking_threads".
}
// If we are not running with any parallel GC threads we will not
// have spawned any marking threads either. Hence the number of
// concurrent workers should be 0.
return 0;
assert(n_conc_workers > 0, "Always need at least 1");
return n_conc_workers;
}
void ConcurrentMark::scanRootRegion(HeapRegion* hr, uint worker_id) {
@ -1243,12 +1228,8 @@ void ConcurrentMark::scanRootRegions() {
uint active_workers = MAX2(1U, parallel_marking_threads());
CMRootRegionScanTask task(this);
if (use_parallel_marking_threads()) {
_parallel_workers->set_active_workers((int) active_workers);
_parallel_workers->run_task(&task);
} else {
task.work(0);
}
_parallel_workers->set_active_workers(active_workers);
_parallel_workers->run_task(&task);
// It's possible that has_aborted() is true here without actually
// aborting the survivor scan earlier. This is OK as it's
@ -1279,15 +1260,11 @@ void ConcurrentMark::markFromRoots() {
set_concurrency_and_phase(active_workers, true /* concurrent */);
CMConcurrentMarkingTask markingTask(this, cmThread());
if (use_parallel_marking_threads()) {
_parallel_workers->set_active_workers((int)active_workers);
// Don't set _n_par_threads because it affects MT in process_roots()
// and the decisions on that MT processing is made elsewhere.
assert(_parallel_workers->active_workers() > 0, "Should have been set");
_parallel_workers->run_task(&markingTask);
} else {
markingTask.work(0);
}
_parallel_workers->set_active_workers(active_workers);
// Don't set _n_par_threads because it affects MT in process_roots()
// and the decisions on that MT processing is made elsewhere.
assert(_parallel_workers->active_workers() > 0, "Should have been set");
_parallel_workers->run_task(&markingTask);
print_stats();
}
@ -1714,11 +1691,7 @@ public:
_expected_card_bm,
_verbose);
if (G1CollectedHeap::use_parallel_gc_threads()) {
_g1h->heap_region_par_iterate(&verify_cl, worker_id, &_hrclaimer);
} else {
_g1h->heap_region_iterate(&verify_cl);
}
_g1h->heap_region_par_iterate(&verify_cl, worker_id, &_hrclaimer);
Atomic::add(verify_cl.failures(), &_failures);
}
@ -1821,11 +1794,7 @@ public:
_actual_region_bm,
_actual_card_bm);
if (G1CollectedHeap::use_parallel_gc_threads()) {
_g1h->heap_region_par_iterate(&final_update_cl, worker_id, &_hrclaimer);
} else {
_g1h->heap_region_iterate(&final_update_cl);
}
_g1h->heap_region_par_iterate(&final_update_cl, worker_id, &_hrclaimer);
}
};
@ -1922,11 +1891,7 @@ public:
HRRSCleanupTask hrrs_cleanup_task;
G1NoteEndOfConcMarkClosure g1_note_end(_g1h, &local_cleanup_list,
&hrrs_cleanup_task);
if (G1CollectedHeap::use_parallel_gc_threads()) {
_g1h->heap_region_par_iterate(&g1_note_end, worker_id, &_hrclaimer);
} else {
_g1h->heap_region_iterate(&g1_note_end);
}
_g1h->heap_region_par_iterate(&g1_note_end, worker_id, &_hrclaimer);
assert(g1_note_end.complete(), "Shouldn't have yielded!");
// Now update the lists
@ -1977,11 +1942,7 @@ public:
}
void work(uint worker_id) {
if (G1CollectedHeap::use_parallel_gc_threads()) {
_g1rs->scrub_par(_region_bm, _card_bm, worker_id, &_hrclaimer);
} else {
_g1rs->scrub(_region_bm, _card_bm);
}
_g1rs->scrub(_region_bm, _card_bm, worker_id, &_hrclaimer);
}
};
@ -2020,18 +1981,13 @@ void ConcurrentMark::cleanup() {
// Do counting once more with the world stopped for good measure.
G1ParFinalCountTask g1_par_count_task(g1h, &_region_bm, &_card_bm);
if (G1CollectedHeap::use_parallel_gc_threads()) {
g1h->set_par_threads();
n_workers = g1h->n_par_threads();
assert(g1h->n_par_threads() == n_workers,
"Should not have been reset");
g1h->workers()->run_task(&g1_par_count_task);
// Done with the parallel phase so reset to 0.
g1h->set_par_threads(0);
} else {
n_workers = 1;
g1_par_count_task.work(0);
}
g1h->set_par_threads();
n_workers = g1h->n_par_threads();
assert(g1h->n_par_threads() == n_workers,
"Should not have been reset");
g1h->workers()->run_task(&g1_par_count_task);
// Done with the parallel phase so reset to 0.
g1h->set_par_threads(0);
if (VerifyDuringGC) {
// Verify that the counting data accumulated during marking matches
@ -2047,14 +2003,10 @@ void ConcurrentMark::cleanup() {
&expected_region_bm,
&expected_card_bm);
if (G1CollectedHeap::use_parallel_gc_threads()) {
g1h->set_par_threads((int)n_workers);
g1h->workers()->run_task(&g1_par_verify_task);
// Done with the parallel phase so reset to 0.
g1h->set_par_threads(0);
} else {
g1_par_verify_task.work(0);
}
g1h->set_par_threads((int)n_workers);
g1h->workers()->run_task(&g1_par_verify_task);
// Done with the parallel phase so reset to 0.
g1h->set_par_threads(0);
guarantee(g1_par_verify_task.failures() == 0, "Unexpected accounting failures");
}
@ -2078,13 +2030,9 @@ void ConcurrentMark::cleanup() {
// Note end of marking in all heap regions.
G1ParNoteEndTask g1_par_note_end_task(g1h, &_cleanup_list, n_workers);
if (G1CollectedHeap::use_parallel_gc_threads()) {
g1h->set_par_threads((int)n_workers);
g1h->workers()->run_task(&g1_par_note_end_task);
g1h->set_par_threads(0);
} else {
g1_par_note_end_task.work(0);
}
g1h->set_par_threads((int)n_workers);
g1h->workers()->run_task(&g1_par_note_end_task);
g1h->set_par_threads(0);
g1h->check_gc_time_stamps();
if (!cleanup_list_is_empty()) {
@ -2099,13 +2047,9 @@ void ConcurrentMark::cleanup() {
if (G1ScrubRemSets) {
double rs_scrub_start = os::elapsedTime();
G1ParScrubRemSetTask g1_par_scrub_rs_task(g1h, &_region_bm, &_card_bm, n_workers);
if (G1CollectedHeap::use_parallel_gc_threads()) {
g1h->set_par_threads((int)n_workers);
g1h->workers()->run_task(&g1_par_scrub_rs_task);
g1h->set_par_threads(0);
} else {
g1_par_scrub_rs_task.work(0);
}
g1h->set_par_threads((int)n_workers);
g1h->workers()->run_task(&g1_par_scrub_rs_task);
g1h->set_par_threads(0);
double rs_scrub_end = os::elapsedTime();
double this_rs_scrub_time = (rs_scrub_end - rs_scrub_start);
@ -2502,7 +2446,7 @@ void ConcurrentMark::weakRefsWork(bool clear_all_soft_refs) {
// is not multi-threaded we use the current (VMThread) thread,
// otherwise we use the work gang from the G1CollectedHeap and
// we utilize all the worker threads we can.
bool processing_is_mt = rp->processing_is_mt() && g1h->workers() != NULL;
bool processing_is_mt = rp->processing_is_mt();
uint active_workers = (processing_is_mt ? g1h->workers()->active_workers() : 1U);
active_workers = MAX2(MIN2(active_workers, _max_worker_id), 1U);
@ -2564,17 +2508,27 @@ void ConcurrentMark::weakRefsWork(bool clear_all_soft_refs) {
G1CMTraceTime trace("Unloading", G1Log::finer());
if (ClassUnloadingWithConcurrentMark) {
// Cleaning of klasses depends on correct information from MetadataMarkOnStack. The CodeCache::mark_on_stack
// part is too slow to be done serially, so it is handled during the weakRefsWorkParallelPart phase.
// Defer the cleaning until we have complete on_stack data.
MetadataOnStackMark md_on_stack(false /* Don't visit the code cache at this point */);
bool purged_classes;
{
G1CMTraceTime trace("System Dictionary Unloading", G1Log::finest());
purged_classes = SystemDictionary::do_unloading(&g1_is_alive);
purged_classes = SystemDictionary::do_unloading(&g1_is_alive, false /* Defer klass cleaning */);
}
{
G1CMTraceTime trace("Parallel Unloading", G1Log::finest());
weakRefsWorkParallelPart(&g1_is_alive, purged_classes);
}
{
G1CMTraceTime trace("Deallocate Metadata", G1Log::finest());
ClassLoaderDataGraph::free_deallocate_lists();
}
}
if (G1StringDedup::is_enabled()) {
@ -2611,16 +2565,15 @@ class G1RemarkThreadsClosure : public ThreadClosure {
G1CMOopClosure _cm_cl;
MarkingCodeBlobClosure _code_cl;
int _thread_parity;
bool _is_par;
public:
G1RemarkThreadsClosure(G1CollectedHeap* g1h, CMTask* task, bool is_par) :
G1RemarkThreadsClosure(G1CollectedHeap* g1h, CMTask* task) :
_cm_obj(task), _cm_cl(g1h, g1h->concurrent_mark(), task), _code_cl(&_cm_cl, !CodeBlobToOopClosure::FixRelocations),
_thread_parity(SharedHeap::heap()->strong_roots_parity()), _is_par(is_par) {}
_thread_parity(SharedHeap::heap()->strong_roots_parity()) {}
void do_thread(Thread* thread) {
if (thread->is_Java_thread()) {
if (thread->claim_oops_do(_is_par, _thread_parity)) {
if (thread->claim_oops_do(true, _thread_parity)) {
JavaThread* jt = (JavaThread*)thread;
// In theory it should not be neccessary to explicitly walk the nmethods to find roots for concurrent marking
@ -2634,7 +2587,7 @@ class G1RemarkThreadsClosure : public ThreadClosure {
jt->satb_mark_queue().apply_closure_and_empty(&_cm_obj);
}
} else if (thread->is_VM_thread()) {
if (thread->claim_oops_do(_is_par, _thread_parity)) {
if (thread->claim_oops_do(true, _thread_parity)) {
JavaThread::satb_mark_queue_set().shared_satb_queue()->apply_closure_and_empty(&_cm_obj);
}
}
@ -2644,7 +2597,6 @@ class G1RemarkThreadsClosure : public ThreadClosure {
class CMRemarkTask: public AbstractGangTask {
private:
ConcurrentMark* _cm;
bool _is_serial;
public:
void work(uint worker_id) {
// Since all available tasks are actually started, we should
@ -2656,14 +2608,14 @@ public:
ResourceMark rm;
HandleMark hm;
G1RemarkThreadsClosure threads_f(G1CollectedHeap::heap(), task, !_is_serial);
G1RemarkThreadsClosure threads_f(G1CollectedHeap::heap(), task);
Threads::threads_do(&threads_f);
}
do {
task->do_marking_step(1000000000.0 /* something very large */,
true /* do_termination */,
_is_serial);
false /* is_serial */);
} while (task->has_aborted() && !_cm->has_overflown());
// If we overflow, then we do not want to restart. We instead
// want to abort remark and do concurrent marking again.
@ -2671,8 +2623,8 @@ public:
}
}
CMRemarkTask(ConcurrentMark* cm, int active_workers, bool is_serial) :
AbstractGangTask("Par Remark"), _cm(cm), _is_serial(is_serial) {
CMRemarkTask(ConcurrentMark* cm, int active_workers) :
AbstractGangTask("Par Remark"), _cm(cm) {
_cm->terminator()->reset_for_reuse(active_workers);
}
};
@ -2686,43 +2638,28 @@ void ConcurrentMark::checkpointRootsFinalWork() {
g1h->ensure_parsability(false);
if (G1CollectedHeap::use_parallel_gc_threads()) {
G1CollectedHeap::StrongRootsScope srs(g1h);
// this is remark, so we'll use up all active threads
uint active_workers = g1h->workers()->active_workers();
if (active_workers == 0) {
assert(active_workers > 0, "Should have been set earlier");
active_workers = (uint) ParallelGCThreads;
g1h->workers()->set_active_workers(active_workers);
}
set_concurrency_and_phase(active_workers, false /* concurrent */);
// Leave _parallel_marking_threads at it's
// value originally calculated in the ConcurrentMark
// constructor and pass values of the active workers
// through the gang in the task.
CMRemarkTask remarkTask(this, active_workers, false /* is_serial */);
// We will start all available threads, even if we decide that the
// active_workers will be fewer. The extra ones will just bail out
// immediately.
g1h->set_par_threads(active_workers);
g1h->workers()->run_task(&remarkTask);
g1h->set_par_threads(0);
} else {
G1CollectedHeap::StrongRootsScope srs(g1h);
uint active_workers = 1;
set_concurrency_and_phase(active_workers, false /* concurrent */);
// Note - if there's no work gang then the VMThread will be
// the thread to execute the remark - serially. We have
// to pass true for the is_serial parameter so that
// CMTask::do_marking_step() doesn't enter the sync
// barriers in the event of an overflow. Doing so will
// cause an assert that the current thread is not a
// concurrent GC thread.
CMRemarkTask remarkTask(this, active_workers, true /* is_serial*/);
remarkTask.work(0);
G1CollectedHeap::StrongRootsScope srs(g1h);
// this is remark, so we'll use up all active threads
uint active_workers = g1h->workers()->active_workers();
if (active_workers == 0) {
assert(active_workers > 0, "Should have been set earlier");
active_workers = (uint) ParallelGCThreads;
g1h->workers()->set_active_workers(active_workers);
}
set_concurrency_and_phase(active_workers, false /* concurrent */);
// Leave _parallel_marking_threads at it's
// value originally calculated in the ConcurrentMark
// constructor and pass values of the active workers
// through the gang in the task.
CMRemarkTask remarkTask(this, active_workers);
// We will start all available threads, even if we decide that the
// active_workers will be fewer. The extra ones will just bail out
// immediately.
g1h->set_par_threads(active_workers);
g1h->workers()->run_task(&remarkTask);
g1h->set_par_threads(0);
SATBMarkQueueSet& satb_mq_set = JavaThread::satb_mark_queue_set();
guarantee(has_overflown() ||
satb_mq_set.completed_buffers_num() == 0,
@ -3268,30 +3205,20 @@ public:
void work(uint worker_id) {
AggregateCountDataHRClosure cl(_g1h, _cm_card_bm, _max_worker_id);
if (G1CollectedHeap::use_parallel_gc_threads()) {
_g1h->heap_region_par_iterate(&cl, worker_id, &_hrclaimer);
} else {
_g1h->heap_region_iterate(&cl);
}
_g1h->heap_region_par_iterate(&cl, worker_id, &_hrclaimer);
}
};
void ConcurrentMark::aggregate_count_data() {
int n_workers = (G1CollectedHeap::use_parallel_gc_threads() ?
_g1h->workers()->active_workers() :
1);
int n_workers = _g1h->workers()->active_workers();
G1AggregateCountDataTask g1_par_agg_task(_g1h, this, &_card_bm,
_max_worker_id, n_workers);
if (G1CollectedHeap::use_parallel_gc_threads()) {
_g1h->set_par_threads(n_workers);
_g1h->workers()->run_task(&g1_par_agg_task);
_g1h->set_par_threads(0);
} else {
g1_par_agg_task.work(0);
}
_g1h->set_par_threads(n_workers);
_g1h->workers()->run_task(&g1_par_agg_task);
_g1h->set_par_threads(0);
_g1h->allocation_context_stats().update_at_remark();
}
@ -3419,9 +3346,7 @@ void ConcurrentMark::print_summary_info() {
}
void ConcurrentMark::print_worker_threads_on(outputStream* st) const {
if (use_parallel_marking_threads()) {
_parallel_workers->print_worker_threads_on(st);
}
_parallel_workers->print_worker_threads_on(st);
}
void ConcurrentMark::print_on_error(outputStream* st) const {
@ -3942,32 +3867,17 @@ void CMTask::drain_satb_buffers() {
CMObjectClosure oc(this);
SATBMarkQueueSet& satb_mq_set = JavaThread::satb_mark_queue_set();
if (G1CollectedHeap::use_parallel_gc_threads()) {
satb_mq_set.set_par_closure(_worker_id, &oc);
} else {
satb_mq_set.set_closure(&oc);
}
satb_mq_set.set_closure(_worker_id, &oc);
// This keeps claiming and applying the closure to completed buffers
// until we run out of buffers or we need to abort.
if (G1CollectedHeap::use_parallel_gc_threads()) {
while (!has_aborted() &&
satb_mq_set.par_apply_closure_to_completed_buffer(_worker_id)) {
if (_cm->verbose_medium()) {
gclog_or_tty->print_cr("[%u] processed an SATB buffer", _worker_id);
}
statsOnly( ++_satb_buffers_processed );
regular_clock_call();
}
} else {
while (!has_aborted() &&
satb_mq_set.apply_closure_to_completed_buffer()) {
if (_cm->verbose_medium()) {
gclog_or_tty->print_cr("[%u] processed an SATB buffer", _worker_id);
}
statsOnly( ++_satb_buffers_processed );
regular_clock_call();
while (!has_aborted() &&
satb_mq_set.apply_closure_to_completed_buffer(_worker_id)) {
if (_cm->verbose_medium()) {
gclog_or_tty->print_cr("[%u] processed an SATB buffer", _worker_id);
}
statsOnly( ++_satb_buffers_processed );
regular_clock_call();
}
_draining_satb_buffers = false;
@ -3976,11 +3886,7 @@ void CMTask::drain_satb_buffers() {
concurrent() ||
satb_mq_set.completed_buffers_num() == 0, "invariant");
if (G1CollectedHeap::use_parallel_gc_threads()) {
satb_mq_set.set_par_closure(_worker_id, NULL);
} else {
satb_mq_set.set_closure(NULL);
}
satb_mq_set.set_closure(_worker_id, NULL);
// again, this was a potentially expensive operation, decrease the
// limits to get the regular clock call early

View File

@ -519,15 +519,6 @@ protected:
double cleanup_sleep_factor() { return _cleanup_sleep_factor; }
double cleanup_task_overhead() { return _cleanup_task_overhead;}
bool use_parallel_marking_threads() const {
assert(parallel_marking_threads() <=
max_parallel_marking_threads(), "sanity");
assert((_parallel_workers == NULL && parallel_marking_threads() == 0) ||
parallel_marking_threads() > 0,
"parallel workers not set up correctly");
return _parallel_workers != NULL;
}
HeapWord* finger() { return _finger; }
bool concurrent() { return _concurrent; }
uint active_tasks() { return _active_tasks; }

View File

@ -28,6 +28,7 @@
#endif
#include "precompiled.hpp"
#include "classfile/metadataOnStackMark.hpp"
#include "classfile/stringTable.hpp"
#include "code/codeCache.hpp"
#include "code/icBuffer.hpp"
@ -1438,36 +1439,31 @@ bool G1CollectedHeap::do_collection(bool explicit_gc,
}
// Rebuild remembered sets of all regions.
if (G1CollectedHeap::use_parallel_gc_threads()) {
uint n_workers =
AdaptiveSizePolicy::calc_active_workers(workers()->total_workers(),
workers()->active_workers(),
Threads::number_of_non_daemon_threads());
assert(UseDynamicNumberOfGCThreads ||
n_workers == workers()->total_workers(),
"If not dynamic should be using all the workers");
workers()->set_active_workers(n_workers);
// Set parallel threads in the heap (_n_par_threads) only
// before a parallel phase and always reset it to 0 after
// the phase so that the number of parallel threads does
// no get carried forward to a serial phase where there
// may be code that is "possibly_parallel".
set_par_threads(n_workers);
uint n_workers =
AdaptiveSizePolicy::calc_active_workers(workers()->total_workers(),
workers()->active_workers(),
Threads::number_of_non_daemon_threads());
assert(UseDynamicNumberOfGCThreads ||
n_workers == workers()->total_workers(),
"If not dynamic should be using all the workers");
workers()->set_active_workers(n_workers);
// Set parallel threads in the heap (_n_par_threads) only
// before a parallel phase and always reset it to 0 after
// the phase so that the number of parallel threads does
// no get carried forward to a serial phase where there
// may be code that is "possibly_parallel".
set_par_threads(n_workers);
ParRebuildRSTask rebuild_rs_task(this);
assert(UseDynamicNumberOfGCThreads ||
workers()->active_workers() == workers()->total_workers(),
"Unless dynamic should use total workers");
// Use the most recent number of active workers
assert(workers()->active_workers() > 0,
"Active workers not properly set");
set_par_threads(workers()->active_workers());
workers()->run_task(&rebuild_rs_task);
set_par_threads(0);
} else {
RebuildRSOutOfRegionClosure rebuild_rs(this);
heap_region_iterate(&rebuild_rs);
}
ParRebuildRSTask rebuild_rs_task(this);
assert(UseDynamicNumberOfGCThreads ||
workers()->active_workers() == workers()->total_workers(),
"Unless dynamic should use total workers");
// Use the most recent number of active workers
assert(workers()->active_workers() > 0,
"Active workers not properly set");
set_par_threads(workers()->active_workers());
workers()->run_task(&rebuild_rs_task);
set_par_threads(0);
// Rebuild the strong code root lists for each region
rebuild_strong_code_roots();
@ -2482,6 +2478,7 @@ void G1CollectedHeap::collect(GCCause::Cause cause) {
unsigned int gc_count_before;
unsigned int old_marking_count_before;
unsigned int full_gc_count_before;
bool retry_gc;
do {
@ -2492,6 +2489,7 @@ void G1CollectedHeap::collect(GCCause::Cause cause) {
// Read the GC count while holding the Heap_lock
gc_count_before = total_collections();
full_gc_count_before = total_full_collections();
old_marking_count_before = _old_marking_cycles_started;
}
@ -2536,7 +2534,7 @@ void G1CollectedHeap::collect(GCCause::Cause cause) {
VMThread::execute(&op);
} else {
// Schedule a Full GC.
VM_G1CollectFull op(gc_count_before, old_marking_count_before, cause);
VM_G1CollectFull op(gc_count_before, full_gc_count_before, cause);
VMThread::execute(&op);
}
}
@ -2678,27 +2676,25 @@ HeapRegion* G1CollectedHeap::start_cset_region_for_worker(uint worker_i) {
// Then thread t will start at region floor ((t * n) / p)
result = g1_policy()->collection_set();
if (G1CollectedHeap::use_parallel_gc_threads()) {
uint cs_size = g1_policy()->cset_region_length();
uint active_workers = workers()->active_workers();
assert(UseDynamicNumberOfGCThreads ||
active_workers == workers()->total_workers(),
"Unless dynamic should use total workers");
uint cs_size = g1_policy()->cset_region_length();
uint active_workers = workers()->active_workers();
assert(UseDynamicNumberOfGCThreads ||
active_workers == workers()->total_workers(),
"Unless dynamic should use total workers");
uint end_ind = (cs_size * worker_i) / active_workers;
uint start_ind = 0;
uint end_ind = (cs_size * worker_i) / active_workers;
uint start_ind = 0;
if (worker_i > 0 &&
_worker_cset_start_region_time_stamp[worker_i - 1] == gc_time_stamp) {
// Previous workers starting region is valid
// so let's iterate from there
start_ind = (cs_size * (worker_i - 1)) / active_workers;
result = _worker_cset_start_region[worker_i - 1];
}
if (worker_i > 0 &&
_worker_cset_start_region_time_stamp[worker_i - 1] == gc_time_stamp) {
// Previous workers starting region is valid
// so let's iterate from there
start_ind = (cs_size * (worker_i - 1)) / active_workers;
result = _worker_cset_start_region[worker_i - 1];
}
for (uint i = start_ind; i < end_ind; i++) {
result = result->next_in_collection_set();
}
for (uint i = start_ind; i < end_ind; i++) {
result = result->next_in_collection_set();
}
// Note: the calculated starting heap region may be NULL
@ -3373,9 +3369,7 @@ void G1CollectedHeap::print_on_error(outputStream* st) const {
}
void G1CollectedHeap::print_gc_threads_on(outputStream* st) const {
if (G1CollectedHeap::use_parallel_gc_threads()) {
workers()->print_worker_threads_on(st);
}
workers()->print_worker_threads_on(st);
_cmThread->print_on(st);
st->cr();
_cm->print_worker_threads_on(st);
@ -3386,9 +3380,7 @@ void G1CollectedHeap::print_gc_threads_on(outputStream* st) const {
}
void G1CollectedHeap::gc_threads_do(ThreadClosure* tc) const {
if (G1CollectedHeap::use_parallel_gc_threads()) {
workers()->threads_do(tc);
}
workers()->threads_do(tc);
tc->do_thread(_cmThread);
_cg1r->threads_do(tc);
if (G1StringDedup::is_enabled()) {
@ -3683,7 +3675,7 @@ void G1CollectedHeap::print_taskqueue_stats(outputStream* const st) const {
print_taskqueue_stats_hdr(st);
TaskQueueStats totals;
const int n = workers() != NULL ? workers()->total_workers() : 1;
const int n = workers()->total_workers();
for (int i = 0; i < n; ++i) {
st->print("%3d ", i); task_queue(i)->stats.print(st); st->cr();
totals += task_queue(i)->stats;
@ -3694,7 +3686,7 @@ void G1CollectedHeap::print_taskqueue_stats(outputStream* const st) const {
}
void G1CollectedHeap::reset_taskqueue_stats() {
const int n = workers() != NULL ? workers()->total_workers() : 1;
const int n = workers()->total_workers();
for (int i = 0; i < n; ++i) {
task_queue(i)->stats.reset();
}
@ -3792,8 +3784,7 @@ G1CollectedHeap::do_collection_pause_at_safepoint(double target_pause_time_ms) {
TraceCPUTime tcpu(G1Log::finer(), true, gclog_or_tty);
int active_workers = (G1CollectedHeap::use_parallel_gc_threads() ?
workers()->active_workers() : 1);
int active_workers = workers()->active_workers();
double pause_start_sec = os::elapsedTime();
g1_policy()->phase_times()->note_gc_start(active_workers);
log_gc_header();
@ -4787,12 +4778,10 @@ private:
int _symbols_processed;
int _symbols_removed;
bool _do_in_parallel;
public:
G1StringSymbolTableUnlinkTask(BoolObjectClosure* is_alive, bool process_strings, bool process_symbols) :
AbstractGangTask("String/Symbol Unlinking"),
_is_alive(is_alive),
_do_in_parallel(G1CollectedHeap::use_parallel_gc_threads()),
_process_strings(process_strings), _strings_processed(0), _strings_removed(0),
_process_symbols(process_symbols), _symbols_processed(0), _symbols_removed(0) {
@ -4807,10 +4796,10 @@ public:
}
~G1StringSymbolTableUnlinkTask() {
guarantee(!_process_strings || !_do_in_parallel || StringTable::parallel_claimed_index() >= _initial_string_table_size,
guarantee(!_process_strings || StringTable::parallel_claimed_index() >= _initial_string_table_size,
err_msg("claim value %d after unlink less than initial string table size %d",
StringTable::parallel_claimed_index(), _initial_string_table_size));
guarantee(!_process_symbols || !_do_in_parallel || SymbolTable::parallel_claimed_index() >= _initial_symbol_table_size,
guarantee(!_process_symbols || SymbolTable::parallel_claimed_index() >= _initial_symbol_table_size,
err_msg("claim value %d after unlink less than initial symbol table size %d",
SymbolTable::parallel_claimed_index(), _initial_symbol_table_size));
@ -4824,28 +4813,19 @@ public:
}
void work(uint worker_id) {
if (_do_in_parallel) {
int strings_processed = 0;
int strings_removed = 0;
int symbols_processed = 0;
int symbols_removed = 0;
if (_process_strings) {
StringTable::possibly_parallel_unlink(_is_alive, &strings_processed, &strings_removed);
Atomic::add(strings_processed, &_strings_processed);
Atomic::add(strings_removed, &_strings_removed);
}
if (_process_symbols) {
SymbolTable::possibly_parallel_unlink(&symbols_processed, &symbols_removed);
Atomic::add(symbols_processed, &_symbols_processed);
Atomic::add(symbols_removed, &_symbols_removed);
}
} else {
if (_process_strings) {
StringTable::unlink(_is_alive, &_strings_processed, &_strings_removed);
}
if (_process_symbols) {
SymbolTable::unlink(&_symbols_processed, &_symbols_removed);
}
int strings_processed = 0;
int strings_removed = 0;
int symbols_processed = 0;
int symbols_removed = 0;
if (_process_strings) {
StringTable::possibly_parallel_unlink(_is_alive, &strings_processed, &strings_removed);
Atomic::add(strings_processed, &_strings_processed);
Atomic::add(strings_removed, &_strings_removed);
}
if (_process_symbols) {
SymbolTable::possibly_parallel_unlink(&symbols_processed, &symbols_removed);
Atomic::add(symbols_processed, &_symbols_processed);
Atomic::add(symbols_removed, &_symbols_removed);
}
}
@ -5013,6 +4993,10 @@ private:
clean_nmethod(claimed_nmethods[i]);
}
}
// The nmethod cleaning helps out and does the CodeCache part of MetadataOnStackMark.
// Need to retire the buffers now that this thread has stopped cleaning nmethods.
MetadataOnStackMark::retire_buffer_for_thread(Thread::current());
}
void work_second_pass(uint worker_id) {
@ -5065,6 +5049,9 @@ public:
// G1 specific cleanup work that has
// been moved here to be done in parallel.
ik->clean_dependent_nmethods();
if (JvmtiExport::has_redefined_a_class()) {
InstanceKlass::purge_previous_versions(ik);
}
}
void work() {
@ -5099,8 +5086,18 @@ public:
_klass_cleaning_task(is_alive) {
}
void pre_work_verification() {
assert(!MetadataOnStackMark::has_buffer_for_thread(Thread::current()), "Should be empty");
}
void post_work_verification() {
assert(!MetadataOnStackMark::has_buffer_for_thread(Thread::current()), "Should be empty");
}
// The parallel work done by all worker threads.
void work(uint worker_id) {
pre_work_verification();
// Do first pass of code cache cleaning.
_code_cache_task.work_first_pass(worker_id);
@ -5119,6 +5116,8 @@ public:
// Clean all klasses that were not unloaded.
_klass_cleaning_task.work();
post_work_verification();
}
};
@ -5127,33 +5126,23 @@ void G1CollectedHeap::parallel_cleaning(BoolObjectClosure* is_alive,
bool process_strings,
bool process_symbols,
bool class_unloading_occurred) {
uint n_workers = (G1CollectedHeap::use_parallel_gc_threads() ?
workers()->active_workers() : 1);
uint n_workers = workers()->active_workers();
G1ParallelCleaningTask g1_unlink_task(is_alive, process_strings, process_symbols,
n_workers, class_unloading_occurred);
if (G1CollectedHeap::use_parallel_gc_threads()) {
set_par_threads(n_workers);
workers()->run_task(&g1_unlink_task);
set_par_threads(0);
} else {
g1_unlink_task.work(0);
}
set_par_threads(n_workers);
workers()->run_task(&g1_unlink_task);
set_par_threads(0);
}
void G1CollectedHeap::unlink_string_and_symbol_table(BoolObjectClosure* is_alive,
bool process_strings, bool process_symbols) {
{
uint n_workers = (G1CollectedHeap::use_parallel_gc_threads() ?
_g1h->workers()->active_workers() : 1);
uint n_workers = _g1h->workers()->active_workers();
G1StringSymbolTableUnlinkTask g1_unlink_task(is_alive, process_strings, process_symbols);
if (G1CollectedHeap::use_parallel_gc_threads()) {
set_par_threads(n_workers);
workers()->run_task(&g1_unlink_task);
set_par_threads(0);
} else {
g1_unlink_task.work(0);
}
set_par_threads(n_workers);
workers()->run_task(&g1_unlink_task);
set_par_threads(0);
}
if (G1StringDedup::is_enabled()) {
@ -5171,11 +5160,7 @@ class G1RedirtyLoggedCardsTask : public AbstractGangTask {
double start_time = os::elapsedTime();
RedirtyLoggedCardTableEntryClosure cl;
if (G1CollectedHeap::heap()->use_parallel_gc_threads()) {
_queue->par_apply_closure_to_all_completed_buffers(&cl);
} else {
_queue->apply_closure_to_all_completed_buffers(&cl);
}
_queue->par_apply_closure_to_all_completed_buffers(&cl);
G1GCPhaseTimes* timer = G1CollectedHeap::heap()->g1_policy()->phase_times();
timer->record_redirty_logged_cards_time_ms(worker_id, (os::elapsedTime() - start_time) * 1000.0);
@ -5186,18 +5171,13 @@ class G1RedirtyLoggedCardsTask : public AbstractGangTask {
void G1CollectedHeap::redirty_logged_cards() {
double redirty_logged_cards_start = os::elapsedTime();
uint n_workers = (G1CollectedHeap::use_parallel_gc_threads() ?
_g1h->workers()->active_workers() : 1);
uint n_workers = _g1h->workers()->active_workers();
G1RedirtyLoggedCardsTask redirty_task(&dirty_card_queue_set());
dirty_card_queue_set().reset_for_par_iteration();
if (use_parallel_gc_threads()) {
set_par_threads(n_workers);
workers()->run_task(&redirty_task);
set_par_threads(0);
} else {
redirty_task.work(0);
}
set_par_threads(n_workers);
workers()->run_task(&redirty_task);
set_par_threads(0);
DirtyCardQueueSet& dcq = JavaThread::dirty_card_queue_set();
dcq.merge_bufferlists(&dirty_card_queue_set());
@ -5587,20 +5567,14 @@ void G1CollectedHeap::process_discovered_references(uint no_of_gc_workers) {
// referents points to another object which is also referenced by an
// object discovered by the STW ref processor.
assert(!G1CollectedHeap::use_parallel_gc_threads() ||
no_of_gc_workers == workers()->active_workers(),
"Need to reset active GC workers");
assert(no_of_gc_workers == workers()->active_workers(), "Need to reset active GC workers");
set_par_threads(no_of_gc_workers);
G1ParPreserveCMReferentsTask keep_cm_referents(this,
no_of_gc_workers,
_task_queues);
if (G1CollectedHeap::use_parallel_gc_threads()) {
workers()->run_task(&keep_cm_referents);
} else {
keep_cm_referents.work(0);
}
workers()->run_task(&keep_cm_referents);
set_par_threads(0);
@ -5727,21 +5701,15 @@ void G1CollectedHeap::evacuate_collection_set(EvacuationInfo& evacuation_info) {
hot_card_cache->set_use_cache(false);
uint n_workers;
if (G1CollectedHeap::use_parallel_gc_threads()) {
n_workers =
AdaptiveSizePolicy::calc_active_workers(workers()->total_workers(),
workers()->active_workers(),
Threads::number_of_non_daemon_threads());
assert(UseDynamicNumberOfGCThreads ||
n_workers == workers()->total_workers(),
"If not dynamic should be using all the workers");
workers()->set_active_workers(n_workers);
set_par_threads(n_workers);
} else {
assert(n_par_threads() == 0,
"Should be the original non-parallel value");
n_workers = 1;
}
n_workers =
AdaptiveSizePolicy::calc_active_workers(workers()->total_workers(),
workers()->active_workers(),
Threads::number_of_non_daemon_threads());
assert(UseDynamicNumberOfGCThreads ||
n_workers == workers()->total_workers(),
"If not dynamic should be using all the workers");
workers()->set_active_workers(n_workers);
set_par_threads(n_workers);
G1ParTask g1_par_task(this, _task_queues);
@ -5760,18 +5728,13 @@ void G1CollectedHeap::evacuate_collection_set(EvacuationInfo& evacuation_info) {
ClassLoaderDataGraph::clear_claimed_marks();
}
if (G1CollectedHeap::use_parallel_gc_threads()) {
// The individual threads will set their evac-failure closures.
if (PrintTerminationStats) G1ParScanThreadState::print_termination_stats_hdr();
// These tasks use ShareHeap::_process_strong_tasks
assert(UseDynamicNumberOfGCThreads ||
workers()->active_workers() == workers()->total_workers(),
"If not dynamic should be using all the workers");
workers()->run_task(&g1_par_task);
} else {
g1_par_task.set_for_termination(n_workers);
g1_par_task.work(0);
}
// The individual threads will set their evac-failure closures.
if (PrintTerminationStats) G1ParScanThreadState::print_termination_stats_hdr();
// These tasks use ShareHeap::_process_strong_tasks
assert(UseDynamicNumberOfGCThreads ||
workers()->active_workers() == workers()->total_workers(),
"If not dynamic should be using all the workers");
workers()->run_task(&g1_par_task);
end_par_time_sec = os::elapsedTime();
// Closing the inner scope will execute the destructor
@ -6077,22 +6040,9 @@ void G1CollectedHeap::cleanUpCardTable() {
// Iterate over the dirty cards region list.
G1ParCleanupCTTask cleanup_task(ct_bs, this);
if (G1CollectedHeap::use_parallel_gc_threads()) {
set_par_threads();
workers()->run_task(&cleanup_task);
set_par_threads(0);
} else {
while (_dirty_cards_region_list) {
HeapRegion* r = _dirty_cards_region_list;
cleanup_task.clear_cards(r);
_dirty_cards_region_list = r->get_next_dirty_cards_region();
if (_dirty_cards_region_list == r) {
// The last region.
_dirty_cards_region_list = NULL;
}
r->set_next_dirty_cards_region(NULL);
}
}
set_par_threads();
workers()->run_task(&cleanup_task);
set_par_threads(0);
#ifndef PRODUCT
if (G1VerifyCTCleanup || VerifyAfterGC) {
G1VerifyCardTableCleanup cleanup_verifier(this, ct_bs);
@ -6632,7 +6582,6 @@ void G1CollectedHeap::retire_mutator_alloc_region(HeapRegion* alloc_region,
void G1CollectedHeap::set_par_threads() {
// Don't change the number of workers. Use the value previously set
// in the workgroup.
assert(G1CollectedHeap::use_parallel_gc_threads(), "shouldn't be here otherwise");
uint n_workers = workers()->active_workers();
assert(UseDynamicNumberOfGCThreads ||
n_workers == workers()->total_workers(),

View File

@ -84,8 +84,7 @@ static double non_young_other_cost_per_region_ms_defaults[] = {
};
G1CollectorPolicy::G1CollectorPolicy() :
_parallel_gc_threads(G1CollectedHeap::use_parallel_gc_threads()
? ParallelGCThreads : 1),
_parallel_gc_threads(ParallelGCThreads),
_recent_gc_times_ms(new TruncatedSeq(NumPrevPausesForHeuristics)),
_stop_world_start(0.0),
@ -1544,32 +1543,6 @@ G1CollectorPolicy::decide_on_conc_mark_initiation() {
}
}
class KnownGarbageClosure: public HeapRegionClosure {
G1CollectedHeap* _g1h;
CollectionSetChooser* _hrSorted;
public:
KnownGarbageClosure(CollectionSetChooser* hrSorted) :
_g1h(G1CollectedHeap::heap()), _hrSorted(hrSorted) { }
bool doHeapRegion(HeapRegion* r) {
// We only include humongous regions in collection
// sets when concurrent mark shows that their contained object is
// unreachable.
// Do we have any marking information for this region?
if (r->is_marked()) {
// We will skip any region that's currently used as an old GC
// alloc region (we should not consider those for collection
// before we fill them up).
if (_hrSorted->should_add(r) && !_g1h->is_old_gc_alloc_region(r)) {
_hrSorted->add_region(r);
}
}
return false;
}
};
class ParKnownGarbageHRClosure: public HeapRegionClosure {
G1CollectedHeap* _g1h;
CSetChooserParUpdater _cset_updater;
@ -1617,34 +1590,29 @@ G1CollectorPolicy::record_concurrent_mark_cleanup_end(int no_of_gc_threads) {
_collectionSetChooser->clear();
uint region_num = _g1->num_regions();
if (G1CollectedHeap::use_parallel_gc_threads()) {
const uint OverpartitionFactor = 4;
uint WorkUnit;
// The use of MinChunkSize = 8 in the original code
// causes some assertion failures when the total number of
// region is less than 8. The code here tries to fix that.
// Should the original code also be fixed?
if (no_of_gc_threads > 0) {
const uint MinWorkUnit = MAX2(region_num / no_of_gc_threads, 1U);
WorkUnit = MAX2(region_num / (no_of_gc_threads * OverpartitionFactor),
MinWorkUnit);
} else {
assert(no_of_gc_threads > 0,
"The active gc workers should be greater than 0");
// In a product build do something reasonable to avoid a crash.
const uint MinWorkUnit = MAX2(region_num / (uint) ParallelGCThreads, 1U);
WorkUnit =
MAX2(region_num / (uint) (ParallelGCThreads * OverpartitionFactor),
MinWorkUnit);
}
_collectionSetChooser->prepare_for_par_region_addition(_g1->num_regions(),
WorkUnit);
ParKnownGarbageTask parKnownGarbageTask(_collectionSetChooser, WorkUnit, (uint) no_of_gc_threads);
_g1->workers()->run_task(&parKnownGarbageTask);
const uint OverpartitionFactor = 4;
uint WorkUnit;
// The use of MinChunkSize = 8 in the original code
// causes some assertion failures when the total number of
// region is less than 8. The code here tries to fix that.
// Should the original code also be fixed?
if (no_of_gc_threads > 0) {
const uint MinWorkUnit = MAX2(region_num / no_of_gc_threads, 1U);
WorkUnit = MAX2(region_num / (no_of_gc_threads * OverpartitionFactor),
MinWorkUnit);
} else {
KnownGarbageClosure knownGarbagecl(_collectionSetChooser);
_g1->heap_region_iterate(&knownGarbagecl);
assert(no_of_gc_threads > 0,
"The active gc workers should be greater than 0");
// In a product build do something reasonable to avoid a crash.
const uint MinWorkUnit = MAX2(region_num / (uint) ParallelGCThreads, 1U);
WorkUnit =
MAX2(region_num / (uint) (ParallelGCThreads * OverpartitionFactor),
MinWorkUnit);
}
_collectionSetChooser->prepare_for_par_region_addition(_g1->num_regions(),
WorkUnit);
ParKnownGarbageTask parKnownGarbageTask(_collectionSetChooser, WorkUnit, (uint) no_of_gc_threads);
_g1->workers()->run_task(&parKnownGarbageTask);
_collectionSetChooser->sort_regions();

View File

@ -292,36 +292,25 @@ void G1GCPhaseTimes::print(double pause_time_sec) {
if (_root_region_scan_wait_time_ms > 0.0) {
print_stats(1, "Root Region Scan Waiting", _root_region_scan_wait_time_ms);
}
if (G1CollectedHeap::use_parallel_gc_threads()) {
print_stats(1, "Parallel Time", _cur_collection_par_time_ms, _active_gc_threads);
_last_gc_worker_start_times_ms.print(2, "GC Worker Start (ms)");
_last_ext_root_scan_times_ms.print(2, "Ext Root Scanning (ms)");
if (_last_satb_filtering_times_ms.sum() > 0.0) {
_last_satb_filtering_times_ms.print(2, "SATB Filtering (ms)");
}
_last_update_rs_times_ms.print(2, "Update RS (ms)");
_last_update_rs_processed_buffers.print(3, "Processed Buffers");
_last_scan_rs_times_ms.print(2, "Scan RS (ms)");
_last_strong_code_root_scan_times_ms.print(2, "Code Root Scanning (ms)");
_last_obj_copy_times_ms.print(2, "Object Copy (ms)");
_last_termination_times_ms.print(2, "Termination (ms)");
if (G1Log::finest()) {
_last_termination_attempts.print(3, "Termination Attempts");
}
_last_gc_worker_other_times_ms.print(2, "GC Worker Other (ms)");
_last_gc_worker_times_ms.print(2, "GC Worker Total (ms)");
_last_gc_worker_end_times_ms.print(2, "GC Worker End (ms)");
} else {
_last_ext_root_scan_times_ms.print(1, "Ext Root Scanning (ms)");
if (_last_satb_filtering_times_ms.sum() > 0.0) {
_last_satb_filtering_times_ms.print(1, "SATB Filtering (ms)");
}
_last_update_rs_times_ms.print(1, "Update RS (ms)");
_last_update_rs_processed_buffers.print(2, "Processed Buffers");
_last_scan_rs_times_ms.print(1, "Scan RS (ms)");
_last_strong_code_root_scan_times_ms.print(1, "Code Root Scanning (ms)");
_last_obj_copy_times_ms.print(1, "Object Copy (ms)");
print_stats(1, "Parallel Time", _cur_collection_par_time_ms, _active_gc_threads);
_last_gc_worker_start_times_ms.print(2, "GC Worker Start (ms)");
_last_ext_root_scan_times_ms.print(2, "Ext Root Scanning (ms)");
if (_last_satb_filtering_times_ms.sum() > 0.0) {
_last_satb_filtering_times_ms.print(2, "SATB Filtering (ms)");
}
_last_update_rs_times_ms.print(2, "Update RS (ms)");
_last_update_rs_processed_buffers.print(3, "Processed Buffers");
_last_scan_rs_times_ms.print(2, "Scan RS (ms)");
_last_strong_code_root_scan_times_ms.print(2, "Code Root Scanning (ms)");
_last_obj_copy_times_ms.print(2, "Object Copy (ms)");
_last_termination_times_ms.print(2, "Termination (ms)");
if (G1Log::finest()) {
_last_termination_attempts.print(3, "Termination Attempts");
}
_last_gc_worker_other_times_ms.print(2, "GC Worker Other (ms)");
_last_gc_worker_times_ms.print(2, "GC Worker Total (ms)");
_last_gc_worker_end_times_ms.print(2, "GC Worker End (ms)");
print_stats(1, "Code Root Fixup", _cur_collection_code_root_fixup_time_ms);
print_stats(1, "Code Root Purge", _cur_strong_code_root_purge_time_ms);
if (G1StringDedup::is_enabled()) {

View File

@ -43,7 +43,7 @@ void G1HotCardCache::initialize(G1RegionToSpaceMapper* card_counts_storage) {
_hot_cache_idx = 0;
// For refining the cards in the hot cache in parallel
_hot_cache_par_chunk_size = (ParallelGCThreads > 0 ? ClaimChunkSize : _hot_cache_size);
_hot_cache_par_chunk_size = ClaimChunkSize;
_hot_cache_par_claimed_idx = 0;
_card_counts.initialize(card_counts_storage);
@ -119,7 +119,7 @@ void G1HotCardCache::drain(uint worker_i,
// RSet updating while within an evacuation pause.
// In this case worker_i should be the id of a GC worker thread
assert(SafepointSynchronize::is_at_safepoint(), "Should be at a safepoint");
assert(worker_i < (ParallelGCThreads == 0 ? 1 : ParallelGCThreads),
assert(worker_i < ParallelGCThreads,
err_msg("incorrect worker id: %u", worker_i));
into_cset_dcq->enqueue(card_ptr);

View File

@ -80,7 +80,6 @@ G1RemSet::G1RemSet(G1CollectedHeap* g1, CardTableModRefBS* ct_bs)
_prev_period_summary()
{
_seq_task = new SubTasksDone(NumSeqTasks);
guarantee(n_workers() > 0, "There should be some workers");
_cset_rs_update_cl = NEW_C_HEAP_ARRAY(OopsInHeapRegionClosure*, n_workers(), mtGC);
for (uint i = 0; i < n_workers(); i++) {
_cset_rs_update_cl[i] = NULL;
@ -282,7 +281,7 @@ public:
// is during RSet updating within an evacuation pause.
// In this case worker_i should be the id of a GC worker thread.
assert(SafepointSynchronize::is_at_safepoint(), "not during an evacuation pause");
assert(worker_i < (ParallelGCThreads == 0 ? 1 : ParallelGCThreads), "should be a GC worker");
assert(worker_i < ParallelGCThreads, "should be a GC worker");
if (_g1rs->refine_card(card_ptr, worker_i, true)) {
// 'card_ptr' contains references that point into the collection
@ -343,8 +342,6 @@ void G1RemSet::oops_into_collection_set_do(OopsInHeapRegionClosure* oc,
// DirtyCardQueueSet that is used to manage RSet updates
DirtyCardQueue into_cset_dcq(&_g1->into_cset_dirty_card_queue_set());
assert((ParallelGCThreads > 0) || worker_i == 0, "invariant");
updateRS(&into_cset_dcq, worker_i);
scanRS(oc, code_root_cl, worker_i);
@ -420,12 +417,7 @@ public:
}
};
void G1RemSet::scrub(BitMap* region_bm, BitMap* card_bm) {
ScrubRSClosure scrub_cl(region_bm, card_bm);
_g1->heap_region_iterate(&scrub_cl);
}
void G1RemSet::scrub_par(BitMap* region_bm, BitMap* card_bm, uint worker_num, HeapRegionClaimer *hrclaimer) {
void G1RemSet::scrub(BitMap* region_bm, BitMap* card_bm, uint worker_num, HeapRegionClaimer *hrclaimer) {
ScrubRSClosure scrub_cl(region_bm, card_bm);
_g1->heap_region_par_iterate(&scrub_cl, worker_num, hrclaimer);
}

View File

@ -124,14 +124,10 @@ public:
// Requires "region_bm" and "card_bm" to be bitmaps with 1 bit per region
// or card, respectively, such that a region or card with a corresponding
// 0 bit contains no part of any live object. Eliminates any remembered
// set entries that correspond to dead heap ranges.
void scrub(BitMap* region_bm, BitMap* card_bm);
// Like the above, but assumes is called in parallel: "worker_num" is the
// parallel thread id of the current thread, and "hrclaimer" is the shared
// HeapRegionClaimer that should be used to claim heap regions.
void scrub_par(BitMap* region_bm, BitMap* card_bm,
uint worker_num, HeapRegionClaimer* hrclaimer);
// set entries that correspond to dead heap ranges. "worker_num" is the
// parallel thread id of the current thread, and "hrclaimer" is the
// HeapRegionClaimer that should be used.
void scrub(BitMap* region_bm, BitMap* card_bm, uint worker_num, HeapRegionClaimer* hrclaimer);
// Refine the card corresponding to "card_ptr".
// If check_for_refs_into_cset is true, a true result is returned

View File

@ -31,11 +31,7 @@
#include "oops/oop.inline.hpp"
inline uint G1RemSet::n_workers() {
if (_g1->workers() != NULL) {
return _g1->workers()->total_workers();
} else {
return 1;
}
return _g1->workers()->total_workers();
}
template <class T>

View File

@ -154,14 +154,10 @@ void G1StringDedup::unlink_or_oops_do(BoolObjectClosure* is_alive, OopClosure* k
double fixup_start = os::elapsedTime();
G1StringDedupUnlinkOrOopsDoTask task(is_alive, keep_alive, allow_resize_and_rehash);
if (G1CollectedHeap::use_parallel_gc_threads()) {
G1CollectedHeap* g1h = G1CollectedHeap::heap();
g1h->set_par_threads();
g1h->workers()->run_task(&task);
g1h->set_par_threads(0);
} else {
task.work(0);
}
G1CollectedHeap* g1h = G1CollectedHeap::heap();
g1h->set_par_threads();
g1h->workers()->run_task(&task);
g1h->set_par_threads(0);
double fixup_time_ms = (os::elapsedTime() - fixup_start) * 1000.0;
g1p->phase_times()->record_string_dedup_fixup_time(fixup_time_ms);

View File

@ -202,7 +202,7 @@ void ObjPtrQueue::verify_oops_in_buffer() {
#endif // _MSC_VER
SATBMarkQueueSet::SATBMarkQueueSet() :
PtrQueueSet(), _closure(NULL), _par_closures(NULL),
PtrQueueSet(), _closures(NULL),
_shared_satb_queue(this, true /*perm*/) { }
void SATBMarkQueueSet::initialize(Monitor* cbl_mon, Mutex* fl_lock,
@ -210,9 +210,7 @@ void SATBMarkQueueSet::initialize(Monitor* cbl_mon, Mutex* fl_lock,
Mutex* lock) {
PtrQueueSet::initialize(cbl_mon, fl_lock, process_completed_threshold, -1);
_shared_satb_queue.set_lock(lock);
if (ParallelGCThreads > 0) {
_par_closures = NEW_C_HEAP_ARRAY(ObjectClosure*, ParallelGCThreads, mtGC);
}
_closures = NEW_C_HEAP_ARRAY(ObjectClosure*, ParallelGCThreads, mtGC);
}
void SATBMarkQueueSet::handle_zero_index_for_thread(JavaThread* t) {
@ -276,17 +274,13 @@ void SATBMarkQueueSet::filter_thread_buffers() {
shared_satb_queue()->filter();
}
void SATBMarkQueueSet::set_closure(ObjectClosure* closure) {
_closure = closure;
void SATBMarkQueueSet::set_closure(uint worker, ObjectClosure* closure) {
assert(_closures != NULL, "Precondition");
assert(worker < ParallelGCThreads, "Worker index must be in range [0...ParallelGCThreads)");
_closures[worker] = closure;
}
void SATBMarkQueueSet::set_par_closure(int i, ObjectClosure* par_closure) {
assert(ParallelGCThreads > 0 && _par_closures != NULL, "Precondition");
_par_closures[i] = par_closure;
}
bool SATBMarkQueueSet::apply_closure_to_completed_buffer_work(bool par,
uint worker) {
bool SATBMarkQueueSet::apply_closure_to_completed_buffer(uint worker) {
BufferNode* nd = NULL;
{
MutexLockerEx x(_cbl_mon, Mutex::_no_safepoint_check_flag);
@ -298,7 +292,7 @@ bool SATBMarkQueueSet::apply_closure_to_completed_buffer_work(bool par,
if (_n_completed_buffers == 0) _process_completed = false;
}
}
ObjectClosure* cl = (par ? _par_closures[worker] : _closure);
ObjectClosure* cl = _closures[worker];
if (nd != NULL) {
void **buf = BufferNode::make_buffer_from_node(nd);
ObjPtrQueue::apply_closure_to_buffer(cl, buf, 0, _sz);

View File

@ -78,16 +78,10 @@ public:
};
class SATBMarkQueueSet: public PtrQueueSet {
ObjectClosure* _closure;
ObjectClosure** _par_closures; // One per ParGCThread.
ObjectClosure** _closures; // One per ParGCThread.
ObjPtrQueue _shared_satb_queue;
// Utility function to support sequential and parallel versions. If
// "par" is true, then "worker" is the par thread id; if "false", worker
// is ignored.
bool apply_closure_to_completed_buffer_work(bool par, uint worker);
#ifdef ASSERT
void dump_active_states(bool expected_active);
void verify_active_states(bool expected_active);
@ -111,26 +105,16 @@ public:
// Filter all the currently-active SATB buffers.
void filter_thread_buffers();
// Register "blk" as "the closure" for all queues. Only one such closure
// is allowed. The "apply_closure_to_completed_buffer" method will apply
// this closure to a completed buffer, and "iterate_closure_all_threads"
// Register closure for the given worker thread. The "apply_closure_to_completed_buffer"
// method will apply this closure to a completed buffer, and "iterate_closure_all_threads"
// applies it to partially-filled buffers (the latter should only be done
// with the world stopped).
void set_closure(ObjectClosure* closure);
// Set the parallel closures: pointer is an array of pointers to
// closures, one for each parallel GC thread.
void set_par_closure(int i, ObjectClosure* closure);
void set_closure(uint worker, ObjectClosure* closure);
// If there exists some completed buffer, pop it, then apply the
// registered closure to all its elements, and return true. If no
// completed buffers exist, return false.
bool apply_closure_to_completed_buffer() {
return apply_closure_to_completed_buffer_work(false, 0);
}
// Parallel version of the above.
bool par_apply_closure_to_completed_buffer(uint worker) {
return apply_closure_to_completed_buffer_work(true, worker);
}
bool apply_closure_to_completed_buffer(uint worker);
// Apply the given closure on enqueued and currently-active buffers
// respectively. Both methods are read-only, i.e., they do not

View File

@ -60,7 +60,7 @@ public:
VM_G1CollectFull(unsigned int gc_count_before,
unsigned int full_gc_count_before,
GCCause::Cause cause)
: VM_GC_Operation(gc_count_before, cause, full_gc_count_before) { }
: VM_GC_Operation(gc_count_before, cause, full_gc_count_before, true) { }
virtual VMOp_Type type() const { return VMOp_G1CollectFull; }
virtual void doit();
virtual const char* name() const {

View File

@ -479,7 +479,7 @@ void ParScanThreadStateSet::flush()
_next_gen.par_oop_since_save_marks_iterate_done(i);
}
if (UseConcMarkSweepGC && ParallelGCThreads > 0) {
if (UseConcMarkSweepGC) {
// We need to call this even when ResizeOldPLAB is disabled
// so as to avoid breaking some asserts. While we may be able
// to avoid this by reorganizing the code a bit, I am loathe

View File

@ -47,11 +47,6 @@ void GenerationSizer::initialize_flags() {
// Do basic sizing work
GenCollectorPolicy::initialize_flags();
assert(UseSerialGC ||
!FLAG_IS_DEFAULT(ParallelGCThreads) ||
(ParallelGCThreads > 0),
"ParallelGCThreads should be set before flag initialization");
// The survivor ratio's are calculated "raw", unlike the
// default gc, which adds 2 to the ratio value. We need to
// make sure the values are valid before using them.

View File

@ -43,12 +43,10 @@ template <class Chunk> void FreeBlockDictionary<Chunk>::set_par_lock(Mutex* lock
template <class Chunk> void FreeBlockDictionary<Chunk>::verify_par_locked() const {
#ifdef ASSERT
if (ParallelGCThreads > 0) {
Thread* my_thread = Thread::current();
if (my_thread->is_GC_task_thread()) {
assert(par_lock() != NULL, "Should be using locking?");
assert_lock_strong(par_lock());
}
Thread* my_thread = Thread::current();
if (my_thread->is_GC_task_thread()) {
assert(par_lock() != NULL, "Should be using locking?");
assert_lock_strong(par_lock());
}
#endif // ASSERT
}

View File

@ -287,11 +287,14 @@ bool FreeList<Chunk>::verify_chunk_in_free_list(Chunk* fc) const {
return false;
}
#ifndef PRODUCT
#ifdef ASSERT
template <class Chunk>
void FreeList<Chunk>::assert_proper_lock_protection_work() const {
assert(protecting_lock() != NULL, "Don't call this directly");
assert(ParallelGCThreads > 0, "Don't call this directly");
// Nothing to do if the list has no assigned protecting lock
if (protecting_lock() == NULL) {
return;
}
Thread* thr = Thread::current();
if (thr->is_VM_thread() || thr->is_ConcurrentGC_thread()) {
// assert that we are holding the freelist lock

View File

@ -56,15 +56,12 @@ class FreeList VALUE_OBJ_CLASS_SPEC {
#ifdef ASSERT
Mutex* _protecting_lock;
void assert_proper_lock_protection_work() const;
#endif
// Asserts false if the protecting lock (if any) is not held.
void assert_proper_lock_protection_work() const PRODUCT_RETURN;
void assert_proper_lock_protection() const {
#ifdef ASSERT
if (_protecting_lock != NULL)
assert_proper_lock_protection_work();
#endif
DEBUG_ONLY(assert_proper_lock_protection_work());
}
void increment_count() {

View File

@ -68,11 +68,9 @@ SharedHeap::SharedHeap(CollectorPolicy* policy_) :
vm_exit_during_initialization("Failed necessary allocation.");
}
_sh = this; // ch is static, should be set only once.
if ((UseParNewGC ||
(UseConcMarkSweepGC && (CMSParallelInitialMarkEnabled ||
CMSParallelRemarkEnabled)) ||
UseG1GC) &&
ParallelGCThreads > 0) {
if (UseParNewGC ||
UseG1GC ||
(UseConcMarkSweepGC && (CMSParallelInitialMarkEnabled || CMSParallelRemarkEnabled) && use_parallel_gc_threads())) {
_workers = new FlexibleWorkGang("Parallel GC Threads", ParallelGCThreads,
/* are_GC_task_threads */true,
/* are_ConcurrentGC_threads */false);

View File

@ -1779,11 +1779,22 @@ int ConstantPool::copy_cpool_bytes(int cpool_size,
void ConstantPool::set_on_stack(const bool value) {
if (value) {
_flags |= _on_stack;
int old_flags = *const_cast<volatile int *>(&_flags);
while ((old_flags & _on_stack) == 0) {
int new_flags = old_flags | _on_stack;
int result = Atomic::cmpxchg(new_flags, &_flags, old_flags);
if (result == old_flags) {
// Succeeded.
MetadataOnStackMark::record(this, Thread::current());
return;
}
old_flags = result;
}
} else {
// Clearing is done single-threadedly.
_flags &= ~_on_stack;
}
if (value) MetadataOnStackMark::record(this);
}
// JSR 292 support for patching constant pool oops after the class is linked and

View File

@ -1862,9 +1862,12 @@ Method* Method::checked_resolve_jmethod_id(jmethodID mid) {
void Method::set_on_stack(const bool value) {
// Set both the method itself and its constant pool. The constant pool
// on stack means some method referring to it is also on the stack.
_access_flags.set_on_stack(value);
constants()->set_on_stack(value);
if (value) MetadataOnStackMark::record(this);
bool succeeded = _access_flags.set_on_stack(value);
if (value && succeeded) {
MetadataOnStackMark::record(this, Thread::current());
}
}
// Called when the class loader is unloaded to make all methods weak.

View File

@ -3861,6 +3861,7 @@ void TestKlass_test();
void TestBitMap_test();
void TestAsUtf8();
void Test_linked_list();
void TestChunkedList_test();
#if INCLUDE_ALL_GCS
void TestOldFreeSpaceCalculation_test();
void TestG1BiasedArray_test();
@ -3894,6 +3895,7 @@ void execute_internal_vm_tests() {
run_unit_test(TestAsUtf8());
run_unit_test(ObjectMonitor::sanity_checks());
run_unit_test(Test_linked_list());
run_unit_test(TestChunkedList_test());
#if INCLUDE_VM_STRUCTS
run_unit_test(VMStructs::test());
#endif

View File

@ -3782,27 +3782,33 @@ jint Arguments::parse(const JavaVMInitArgs* args) {
bool settings_file_specified = false;
bool needs_hotspotrc_warning = false;
ArgumentsExt::process_options(args);
const char* flags_file;
int index;
for (index = 0; index < args->nOptions; index++) {
const JavaVMOption *option = args->options + index;
if (ArgumentsExt::process_options(option)) {
continue;
}
if (match_option(option, "-XX:Flags=", &tail)) {
flags_file = tail;
settings_file_specified = true;
continue;
}
if (match_option(option, "-XX:+PrintVMOptions", &tail)) {
PrintVMOptions = true;
continue;
}
if (match_option(option, "-XX:-PrintVMOptions", &tail)) {
PrintVMOptions = false;
continue;
}
if (match_option(option, "-XX:+IgnoreUnrecognizedVMOptions", &tail)) {
IgnoreUnrecognizedVMOptions = true;
continue;
}
if (match_option(option, "-XX:-IgnoreUnrecognizedVMOptions", &tail)) {
IgnoreUnrecognizedVMOptions = false;
continue;
}
if (match_option(option, "-XX:+PrintFlagsInitial", &tail)) {
CommandLineFlags::printFlags(tty, false);
@ -3824,6 +3830,7 @@ jint Arguments::parse(const JavaVMInitArgs* args) {
} else {
vm_exit_during_initialization("Syntax error, expecting -XX:NativeMemoryTracking=[off|summary|detail]", NULL);
}
continue;
}
#endif

View File

@ -34,7 +34,10 @@ public:
static inline bool check_gc_consistency_user();
static inline bool check_gc_consistency_ergo();
static inline bool check_vm_args_consistency();
static void process_options(const JavaVMInitArgs* args) {}
// The argument processing extension. Returns true if there is
// no additional parsing needed in Arguments::parse() for the option.
// Otherwise returns false.
static inline bool process_options(const JavaVMOption *option) { return false; }
};
void ArgumentsExt::select_gc_ergonomically() {

View File

@ -201,6 +201,8 @@ Thread::Thread() {
// This initial value ==> never claimed.
_oops_do_parity = 0;
_metadata_on_stack_buffer = NULL;
// the handle mark links itself to last_handle_mark
new HandleMark(this);

View File

@ -42,11 +42,10 @@
#include "runtime/threadLocalStorage.hpp"
#include "runtime/thread_ext.hpp"
#include "runtime/unhandledOops.hpp"
#include "utilities/macros.hpp"
#include "trace/traceBackend.hpp"
#include "trace/traceMacros.hpp"
#include "utilities/exceptions.hpp"
#include "utilities/macros.hpp"
#include "utilities/top.hpp"
#if INCLUDE_ALL_GCS
#include "gc_implementation/g1/dirtyCardQueue.hpp"
@ -83,6 +82,10 @@ class GCTaskQueue;
class ThreadClosure;
class IdealGraphPrinter;
class Metadata;
template <class T, MEMFLAGS F> class ChunkedList;
typedef ChunkedList<Metadata*, mtInternal> MetadataOnStackBuffer;
DEBUG_ONLY(class ResourceMark;)
class WorkerThread;
@ -255,6 +258,9 @@ class Thread: public ThreadShadow {
jlong _allocated_bytes; // Cumulative number of bytes allocated on
// the Java heap
// Thread-local buffer used by MetadataOnStackMark.
MetadataOnStackBuffer* _metadata_on_stack_buffer;
TRACE_DATA _trace_data; // Thread-local data for tracing
ThreadExt _ext;
@ -490,7 +496,10 @@ class Thread: public ThreadShadow {
// creation fails due to lack of memory, too many threads etc.
bool set_as_starting_thread();
protected:
void set_metadata_on_stack_buffer(MetadataOnStackBuffer* buffer) { _metadata_on_stack_buffer = buffer; }
MetadataOnStackBuffer* metadata_on_stack_buffer() const { return _metadata_on_stack_buffer; }
protected:
// OS data associated with the thread
OSThread* _osthread; // Platform-specific thread information

View File

@ -47,6 +47,21 @@ void AccessFlags::atomic_clear_bits(jint bits) {
} while(f != old_flags);
}
// Returns true iff this thread succeeded setting the bit.
bool AccessFlags::atomic_set_one_bit(jint bit) {
// Atomically update the flags with the bit given
jint old_flags, new_flags, f;
bool is_setting_bit = false;
do {
old_flags = _flags;
new_flags = old_flags | bit;
is_setting_bit = old_flags != new_flags;
f = Atomic::cmpxchg(new_flags, &_flags, old_flags);
} while(f != old_flags);
return is_setting_bit;
}
#if !defined(PRODUCT) || INCLUDE_JVMTI
void AccessFlags::print_on(outputStream* st) const {

View File

@ -172,6 +172,7 @@ class AccessFlags VALUE_OBJ_CLASS_SPEC {
// Atomic update of flags
void atomic_set_bits(jint bits);
bool atomic_set_one_bit(jint bit);
void atomic_clear_bits(jint bits);
private:
@ -233,12 +234,13 @@ class AccessFlags VALUE_OBJ_CLASS_SPEC {
atomic_set_bits(JVM_ACC_FIELD_HAS_GENERIC_SIGNATURE);
}
void set_on_stack(const bool value)
bool set_on_stack(const bool value)
{
if (value) {
atomic_set_bits(JVM_ACC_ON_STACK);
return atomic_set_one_bit(JVM_ACC_ON_STACK);
} else {
atomic_clear_bits(JVM_ACC_ON_STACK);
return true; // Ignored
}
}
// Conversion

View File

@ -0,0 +1,109 @@
/*
* Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*
*/
#include "precompiled.hpp"
#include "utilities/chunkedList.hpp"
#include "utilities/debug.hpp"
/////////////// Unit tests ///////////////
#ifndef PRODUCT
template <typename T>
class TestChunkedList {
typedef ChunkedList<T, mtOther> ChunkedListT;
public:
static void testEmpty() {
ChunkedListT buffer;
assert(buffer.size() == 0, "assert");
}
static void testFull() {
ChunkedListT buffer;
for (uintptr_t i = 0; i < ChunkedListT::BufferSize; i++) {
buffer.push((T)i);
}
assert(buffer.size() == ChunkedListT::BufferSize, "assert");
assert(buffer.is_full(), "assert");
}
static void testSize() {
ChunkedListT buffer;
for (uintptr_t i = 0; i < ChunkedListT::BufferSize; i++) {
assert(buffer.size() == i, "assert");
buffer.push((T)i);
assert(buffer.size() == i + 1, "assert");
}
}
static void testClear() {
ChunkedListT buffer;
buffer.clear();
assert(buffer.size() == 0, "assert");
for (uintptr_t i = 0; i < ChunkedListT::BufferSize / 2; i++) {
buffer.push((T)i);
}
buffer.clear();
assert(buffer.size() == 0, "assert");
for (uintptr_t i = 0; i < ChunkedListT::BufferSize; i++) {
buffer.push((T)i);
}
buffer.clear();
assert(buffer.size() == 0, "assert");
}
static void testAt() {
ChunkedListT buffer;
for (uintptr_t i = 0; i < ChunkedListT::BufferSize; i++) {
buffer.push((T)i);
assert(buffer.at(i) == (T)i, "assert");
}
for (uintptr_t i = 0; i < ChunkedListT::BufferSize; i++) {
assert(buffer.at(i) == (T)i, "assert");
}
}
static void test() {
testEmpty();
testFull();
testSize();
testClear();
testAt();
}
};
class Metadata;
void TestChunkedList_test() {
TestChunkedList<Metadata*>::test();
TestChunkedList<size_t>::test();
}
#endif

View File

@ -0,0 +1,81 @@
/*
* Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*
*/
#ifndef SHARE_VM_UTILITIES_CHUNKED_LIST_HPP
#define SHARE_VM_UTILITIES_CHUNKED_LIST_HPP
#include "memory/allocation.hpp"
#include "utilities/debug.hpp"
template <class T, MEMFLAGS F> class ChunkedList : public CHeapObj<F> {
template <class U> friend class TestChunkedList;
static const size_t BufferSize = 64;
T _values[BufferSize];
T* _top;
ChunkedList<T, F>* _next_used;
ChunkedList<T, F>* _next_free;
T const * end() const {
return &_values[BufferSize];
}
public:
ChunkedList<T, F>() : _top(_values), _next_used(NULL), _next_free(NULL) {}
bool is_full() const {
return _top == end();
}
void clear() {
_top = _values;
// Don't clear the next pointers since that would interfere
// with other threads trying to iterate through the lists.
}
void push(T m) {
assert(!is_full(), "Buffer is full");
*_top = m;
_top++;
}
void set_next_used(ChunkedList<T, F>* buffer) { _next_used = buffer; }
void set_next_free(ChunkedList<T, F>* buffer) { _next_free = buffer; }
ChunkedList<T, F>* next_used() const { return _next_used; }
ChunkedList<T, F>* next_free() const { return _next_free; }
size_t size() const {
return pointer_delta(_top, _values, sizeof(T));
}
T at(size_t i) {
assert(i < size(), err_msg("IOOBE i: " SIZE_FORMAT " size(): " SIZE_FORMAT, i, size()));
return _values[i];
}
};
#endif // SHARE_VM_UTILITIES_CHUNKED_LIST_HPP

View File

@ -0,0 +1,56 @@
/*
* Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* @test
* @bug 8060256
* @summary Test various command line options
* @library /testlibrary
* @run main TestVMOptions
*/
import com.oracle.java.testlibrary.*;
import java.io.File;
public class TestVMOptions {
public static void main(String[] args) throws Exception {
ProcessBuilder pb = ProcessTools.createJavaProcessBuilder(
"-XX:bogus",
"-XX:+IgnoreUnrecognizedVMOptions",
"-XX:+PrintFlagsInitial");
OutputAnalyzer output = new OutputAnalyzer(pb.start());
output.shouldContain("bool PrintGCDetails");
pb = ProcessTools.createJavaProcessBuilder(
"-XX:-PrintVMOptions", "-version");
output = new OutputAnalyzer(pb.start());
output.shouldContain("java version");
File dir = new File(System.getProperty("test.src", "."));
File file = new File(dir, "flagfile.txt");
String s = file.getAbsolutePath();
pb = ProcessTools.createJavaProcessBuilder("-XX:Flags="+s);
output = new OutputAnalyzer(pb.start());
output.shouldContain("VM option '-IgnoreUnrecognizedVMOptions'");
}
}

View File

@ -0,0 +1 @@
+PrintVMOptions -IgnoreUnrecognizedVMOptions

View File

@ -279,3 +279,4 @@ b940ca3d2c7e8a279ca850706b89c2ad3a841e82 jdk9-b32
6b343b9b7a7008f5f699a2d99881163cab7a2986 jdk9-b34
b9370464572fc663a38956047aa612d6e7854c3d jdk9-b35
61b4c9acaa58e482db6601ec5dc4fc3d2d8dbb55 jdk9-b36
48e4ec70cc1c8651e4a0324d91f193c4edd83af9 jdk9-b37

View File

@ -529,6 +529,16 @@ public class UTF8Reader
invalidByte(4, 4, b2);
}
// check if output buffer is large enough to hold 2 surrogate chars
if (out + 1 >= ch.length) {
fBuffer[0] = (byte)b0;
fBuffer[1] = (byte)b1;
fBuffer[2] = (byte)b2;
fBuffer[3] = (byte)b3;
fOffset = 4;
return out - offset;
}
// decode bytes into surrogate characters
int uuuuu = ((b0 << 2) & 0x001C) | ((b1 >> 4) & 0x0003);
if (uuuuu > 0x10) {

View File

@ -282,3 +282,4 @@ e58d3ea638c3824f01547596b2a98aa5f77c4a5c jdk9-b30
28ea43d925f1e5250976097a2977dd3e66e11f0b jdk9-b34
afe0c89e2edbdfb1a7ceff3d9b3ff46c4186202f jdk9-b35
84803c3be7f79d29c7dc40749d7743675f64107a jdk9-b36
90de6ecbff46386a3f9d6f7ca876e7aa6381f50a jdk9-b37

View File

@ -279,3 +279,4 @@ f0870554049807d3392bd7976ab114f7f2b7bafa jdk9-b27
21568031434d7a9dbb0cc6516cc3183d349c2253 jdk9-b34
e549291a0227031310fa91c574891f892d27f959 jdk9-b35
cdcf2e599e42935c2d1d19a24bb19e808aeb43b5 jdk9-b36
27c3345d6dce39a22c262f30bb1f0e0b00c3709e jdk9-b37

View File

@ -48,22 +48,6 @@ $(INCLUDE_DST_OS_DIR)/%.h: \
################################################################################
CALENDARS_SRC := $(JDK_TOPDIR)/src/java.base/share/conf
$(LIB_DST_DIR)/calendars.properties: $(CALENDARS_SRC)/calendars.properties
$(call install-file)
BASE_CONF_FILES += $(LIB_DST_DIR)/calendars.properties
$(LIB_DST_DIR)/hijrah-config-umalqura.properties: $(CALENDARS_SRC)/hijrah-config-umalqura.properties
$(MKDIR) -p $(@D)
$(RM) $@
$(CP) $< $@
BASE_CONF_FILES += $(LIB_DST_DIR)/hijrah-config-umalqura.properties
################################################################################
ifneq ($(findstring $(OPENJDK_TARGET_OS), windows aix),)
TZMAPPINGS_SRC := $(JDK_TOPDIR)/src/java.base/$(OPENJDK_TARGET_OS)/conf

View File

@ -67,8 +67,11 @@ ifneq ($(FREETYPE_BUNDLE_LIB_PATH), )
FREETYPE_TARGET_LIB := $(JDK_OUTPUTDIR)/lib$(OPENJDK_TARGET_CPU_LIBDIR)/$(call SHARED_LIBRARY,freetype).6
endif
# We can't use $(install-file) in this rule because it preserves symbolic links and
# libfreetype.so is usually a symbolic link to something like libfreetype.so.6 on Unix.
$(FREETYPE_TARGET_LIB): $(FREETYPE_BUNDLE_LIB_PATH)/$(call SHARED_LIBRARY,freetype)
$(install-file)
$(MKDIR) -p $(@D)
$(CP) $< $@
ifeq ($(OPENJDK_BUILD_OS), windows)
$(CHMOD) +rx $@
endif

View File

@ -21,4 +21,4 @@
# or visit www.oracle.com if you need additional information or have any
# questions.
#
tzdata2014g
tzdata2014i

View File

@ -133,23 +133,13 @@ Zone Africa/Algiers 0:12:12 - LMT 1891 Mar 15 0:01
# See Africa/Lagos.
# Botswana
# From Paul Eggert (2013-02-21):
# Milne says they were regulated by the Cape Town Signal in 1899;
# assume they switched to 2:00 when Cape Town did.
# Zone NAME GMTOFF RULES FORMAT [UNTIL]
Zone Africa/Gaborone 1:43:40 - LMT 1885
1:30 - SAST 1903 Mar
2:00 - CAT 1943 Sep 19 2:00
2:00 1:00 CAST 1944 Mar 19 2:00
2:00 - CAT
# See Africa/Maputo.
# Burkina Faso
# See Africa/Abidjan.
# Burundi
# Zone NAME GMTOFF RULES FORMAT [UNTIL]
Zone Africa/Bujumbura 1:57:28 - LMT 1890
2:00 - CAT
# See Africa/Maputo.
# Cameroon
# See Africa/Lagos.
@ -184,10 +174,7 @@ Zone Indian/Comoro 2:53:04 - LMT 1911 Jul # Moroni, Gran Comoro
3:00 - EAT
# Democratic Republic of the Congo
# Zone NAME GMTOFF RULES FORMAT [UNTIL]
Zone Africa/Lubumbashi 1:49:52 - LMT 1897 Nov 9
2:00 - CAT
# The above is for the eastern part; see Africa/Lagos for the western part.
# See Africa/Lagos for the western part and Africa/Maputo for the eastern.
# Republic of the Congo
# See Africa/Lagos.
@ -339,7 +326,7 @@ Rule Egypt 2007 only - Sep Thu>=1 24:00 0 -
# Egypt is to change back to Daylight system on May 15
# http://english.ahram.org.eg/NewsContent/1/64/100735/Egypt/Politics-/Egypts-government-to-reapply-daylight-saving-time-.aspx
# From Gunther Vermier (2015-05-13):
# From Gunther Vermier (2014-05-13):
# our Egypt office confirms that the change will be at 15 May "midnight" (24:00)
# From Imed Chihi (2014-06-04):
@ -489,11 +476,7 @@ Zone Africa/Nairobi 2:27:16 - LMT 1928 Jul
3:00 - EAT
# Lesotho
# Zone NAME GMTOFF RULES FORMAT [UNTIL]
Zone Africa/Maseru 1:50:00 - LMT 1903 Mar
2:00 - SAST 1943 Sep 19 2:00
2:00 1:00 SAST 1944 Mar 19 2:00
2:00 - SAST
# See Africa/Johannesburg.
# Liberia
# From Paul Eggert (2006-03-22):
@ -575,9 +558,7 @@ Zone Indian/Antananarivo 3:10:04 - LMT 1911 Jul
3:00 - EAT
# Malawi
# Zone NAME GMTOFF RULES FORMAT [UNTIL]
Zone Africa/Blantyre 2:20:00 - LMT 1903 Mar
2:00 - CAT
# See Africa/Maputo.
# Mali
# Mauritania
@ -987,6 +968,13 @@ Zone Africa/El_Aaiun -0:52:48 - LMT 1934 Jan # El Aaiún
# Zone NAME GMTOFF RULES FORMAT [UNTIL]
Zone Africa/Maputo 2:10:20 - LMT 1903 Mar
2:00 - CAT
Link Africa/Maputo Africa/Blantyre # Malawi
Link Africa/Maputo Africa/Bujumbura # Burundi
Link Africa/Maputo Africa/Gaborone # Botswana
Link Africa/Maputo Africa/Harare # Zimbabwe
Link Africa/Maputo Africa/Kigali # Rwanda
Link Africa/Maputo Africa/Lubumbashi # E Dem. Rep. of Congo
Link Africa/Maputo Africa/Lusaka # Zambia
# Namibia
# The 1994-04-03 transition is from Shanks & Pottenger.
@ -1054,9 +1042,7 @@ Zone Indian/Reunion 3:41:52 - LMT 1911 Jun # Saint-Denis
# Tromelin - inhabited until at least 1958
# Rwanda
# Zone NAME GMTOFF RULES FORMAT [UNTIL]
Zone Africa/Kigali 2:00:16 - LMT 1935 Jun
2:00 - CAT
# See Africa/Maputo.
# St Helena
# See Africa/Abidjan.
@ -1100,6 +1086,9 @@ Rule SA 1943 1944 - Mar Sun>=15 2:00 0 -
Zone Africa/Johannesburg 1:52:00 - LMT 1892 Feb 8
1:30 - SAST 1903 Mar
2:00 SA SAST
Link Africa/Johannesburg Africa/Maseru # Lesotho
Link Africa/Johannesburg Africa/Mbabane # Swaziland
#
# Marion and Prince Edward Is
# scientific station since 1947
# no information
@ -1127,9 +1116,7 @@ Zone Africa/Khartoum 2:10:08 - LMT 1931
Link Africa/Khartoum Africa/Juba
# Swaziland
# Zone NAME GMTOFF RULES FORMAT [UNTIL]
Zone Africa/Mbabane 2:04:24 - LMT 1903 Mar
2:00 - SAST
# See Africa/Johannesburg.
# Tanzania
# Zone NAME GMTOFF RULES FORMAT [UNTIL]
@ -1250,11 +1237,5 @@ Zone Africa/Kampala 2:09:40 - LMT 1928 Jul
3:00 - EAT
# Zambia
# Zone NAME GMTOFF RULES FORMAT [UNTIL]
Zone Africa/Lusaka 1:53:08 - LMT 1903 Mar
2:00 - CAT
# Zimbabwe
# Zone NAME GMTOFF RULES FORMAT [UNTIL]
Zone Africa/Harare 2:04:12 - LMT 1903 Mar
2:00 - CAT
# See Africa/Maputo.

View File

@ -70,10 +70,11 @@
# 3:30 IRST IRDT Iran
# 4:00 GST Gulf*
# 5:30 IST India
# 7:00 ICT Indochina*
# 7:00 ICT Indochina, most times and locations*
# 7:00 WIB west Indonesia (Waktu Indonesia Barat)
# 8:00 WITA central Indonesia (Waktu Indonesia Tengah)
# 8:00 CST China
# 8:00 IDT Indochina, 1943-45, 1947-55, 1960-75 (some locations)*
# 8:00 JWST Western Standard Time (Japan, 1896/1937)*
# 9:00 JCST Central Standard Time (Japan, 1896/1937)
# 9:00 WIT east Indonesia (Waktu Indonesia Timur)
@ -294,12 +295,8 @@ Zone Asia/Rangoon 6:24:40 - LMT 1880 # or Yangon
6:30 - MMT # Myanmar Time
# Cambodia
# Zone NAME GMTOFF RULES FORMAT [UNTIL]
Zone Asia/Phnom_Penh 6:59:40 - LMT 1906 Jun 9
7:06:20 - SMT 1911 Mar 11 0:01 # Saigon MT?
7:00 - ICT 1912 May
8:00 - ICT 1931 May
7:00 - ICT
# See Asia/Bangkok.
# China
@ -916,6 +913,10 @@ Zone Asia/Kolkata 5:53:28 - LMT 1880 # Kolkata
# Indonesia
#
# From Paul Eggert (2014-09-06):
# The 1876 Report of the Secretary of the [US] Navy, p 306 says that Batavia
# civil time was 7:07:12.5; round to even for Jakarta.
#
# From Gwillim Law (2001-05-28), overriding Shanks & Pottenger:
# http://www.sumatera-inc.com/go_to_invest/about_indonesia.asp#standtime
# says that Indonesia's time zones changed on 1988-01-01. Looking at some
@ -1733,12 +1734,8 @@ Zone Asia/Kuwait 3:11:56 - LMT 1950
3:00 - AST
# Laos
# Zone NAME GMTOFF RULES FORMAT [UNTIL]
Zone Asia/Vientiane 6:50:24 - LMT 1906 Jun 9 # or Viangchan
7:06:20 - SMT 1911 Mar 11 0:01 # Saigon MT?
7:00 - ICT 1912 May
8:00 - ICT 1931 May
7:00 - ICT
# See Asia/Bangkok.
# Lebanon
# Rule NAME FROM TO TYPE IN ON AT SAVE LETTER/S
@ -2751,6 +2748,8 @@ Zone Asia/Dushanbe 4:35:12 - LMT 1924 May 2
Zone Asia/Bangkok 6:42:04 - LMT 1880
6:42:04 - BMT 1920 Apr # Bangkok Mean Time
7:00 - ICT
Link Asia/Bangkok Asia/Phnom_Penh # Cambodia
Link Asia/Bangkok Asia/Vientiane # Laos
# Turkmenistan
# From Shanks & Pottenger.
@ -2788,22 +2787,65 @@ Zone Asia/Tashkent 4:37:11 - LMT 1924 May 2
# Vietnam
# From Paul Eggert (2013-02-21):
# From Paul Eggert (2014-10-04):
# Milne gives 7:16:56 for the meridian of Saigon in 1899, as being
# used in Lower Laos, Cambodia, and Annam. But this is quite a ways
# from Saigon's location. For now, ignore this and stick with Shanks
# and Pottenger.
# and Pottenger for LMT before 1906.
# From Arthur David Olson (2008-03-18):
# The English-language name of Vietnam's most populous city is "Ho Chi Minh
# City"; use Ho_Chi_Minh below to avoid a name of more than 14 characters.
# From Shanks & Pottenger:
# From Paul Eggert (2014-10-21) after a heads-up from Trần Ngọc Quân:
# Trần Tiến Bình's authoritative book "Lịch Việt Nam: thế kỷ XX-XXI (1901-2100)"
# (Nhà xuất bản Văn Hoá - Thông Tin, Hanoi, 2005), pp 49-50,
# is quoted verbatim in:
# http://www.thoigian.com.vn/?mPage=P80D01
# is translated by Brian Inglis in:
# http://mm.icann.org/pipermail/tz/2014-October/021654.html
# and is the basis for the information below.
#
# The 1906 transition was effective July 1 and standardized Indochina to
# Phù Liễn Observatory, legally 104 deg. 17'17" east of Paris.
# It's unclear whether this meant legal Paris Mean Time (00:09:21) or
# the Paris Meridian (2 deg. 20'14.03" E); the former yields 07:06:30.1333...
# and the latter 07:06:29.333... so either way it rounds to 07:06:30,
# which is used below even though the modern-day Phù Liễn Observatory
# is closer to 07:06:31. Abbreviate Phù Liễn Mean Time as PLMT.
#
# The following transitions occurred in Indochina in general (before 1954)
# and in South Vietnam in particular (after 1954):
# To 07:00 on 1911-05-01.
# To 08:00 on 1942-12-31 at 23:00.
# To 09:00 in 1945-03-14 at 23:00.
# To 07:00 on 1945-09-02 in Vietnam.
# To 08:00 on 1947-04-01 in French-controlled Indochina.
# To 07:00 on 1955-07-01 in South Vietnam.
# To 08:00 on 1959-12-31 at 23:00 in South Vietnam.
# To 07:00 on 1975-06-13 in South Vietnam.
#
# Trần cites the following sources; it's unclear which supplied the info above.
#
# Hoàng Xuân Hãn: "Lịch và lịch Việt Nam". Tập san Khoa học Xã hội,
# No. 9, Paris, February 1982.
#
# Lê Thành Lân: "Lịch và niên biểu lịch sử hai mươi thế kỷ (0001-2010)",
# NXB Thống kê, Hanoi, 2000.
#
# Lê Thành Lân: "Lịch hai thế kỷ (1802-2010) và các lịch vĩnh cửu",
# NXB Thuận Hoá, Huế, 1995.
# Zone NAME GMTOFF RULES FORMAT [UNTIL]
Zone Asia/Ho_Chi_Minh 7:06:40 - LMT 1906 Jun 9
7:06:20 - SMT 1911 Mar 11 0:01 # Saigon MT?
7:00 - ICT 1912 May
8:00 - ICT 1931 May
Zone Asia/Ho_Chi_Minh 7:06:40 - LMT 1906 Jul 1
7:06:30 - PLMT 1911 May 1
7:00 - ICT 1942 Dec 31 23:00
8:00 - IDT 1945 Mar 14 23:00
9:00 - JST 1945 Sep 2
7:00 - ICT 1947 Apr 1
8:00 - IDT 1955 Jul 1
7:00 - ICT 1959 Dec 31 23:00
8:00 - IDT 1975 Jun 13
7:00 - ICT
# Yemen

View File

@ -354,20 +354,27 @@ Zone Indian/Cocos 6:27:40 - LMT 1900
# Fiji will end DST on 2014-01-19 02:00:
# http://www.fiji.gov.fj/Media-Center/Press-Releases/DAYLIGHT-SAVINGS-TO-END-THIS-MONTH-%281%29.aspx
# From Paul Eggert (2014-01-10):
# For now, guess that Fiji springs forward the Sunday before the fourth
# Monday in October, and springs back the penultimate Sunday in January.
# This is ad hoc, but matches recent practice.
# From Ken Rylander (2014-10-20):
# DST will start Nov. 2 this year.
# http://www.fiji.gov.fj/Media-Center/Press-Releases/DAYLIGHT-SAVING-STARTS-ON-SUNDAY,-NOVEMBER-2ND.aspx
# From Paul Eggert (2014-10-20):
# For now, guess DST from 02:00 the first Sunday in November to
# 03:00 the first Sunday on or after January 18. Although ad hoc, it
# matches this year's plan and seems more likely to match future
# practice than guessing no DST.
# Rule NAME FROM TO TYPE IN ON AT SAVE LETTER/S
Rule Fiji 1998 1999 - Nov Sun>=1 2:00 1:00 S
Rule Fiji 1999 2000 - Feb lastSun 3:00 0 -
Rule Fiji 2009 only - Nov 29 2:00 1:00 S
Rule Fiji 2010 only - Mar lastSun 3:00 0 -
Rule Fiji 2010 max - Oct Sun>=21 2:00 1:00 S
Rule Fiji 2010 2013 - Oct Sun>=21 2:00 1:00 S
Rule Fiji 2011 only - Mar Sun>=1 3:00 0 -
Rule Fiji 2012 2013 - Jan Sun>=18 3:00 0 -
Rule Fiji 2014 max - Jan Sun>=18 2:00 0 -
Rule Fiji 2014 only - Jan Sun>=18 2:00 0 -
Rule Fiji 2014 max - Nov Sun>=1 2:00 1:00 S
Rule Fiji 2015 max - Jan Sun>=18 3:00 0 -
# Zone NAME GMTOFF RULES FORMAT [UNTIL]
Zone Pacific/Fiji 11:55:44 - LMT 1915 Oct 26 # Suva
12:00 Fiji FJ%sT # Fiji Time
@ -542,6 +549,30 @@ Zone Pacific/Palau 8:57:56 - LMT 1901 # Koror
Zone Pacific/Port_Moresby 9:48:40 - LMT 1880
9:48:32 - PMMT 1895 # Port Moresby Mean Time
10:00 - PGT # Papua New Guinea Time
#
# From Paul Eggert (2014-10-13):
# Base the Bougainville entry on the Arawa-Kieta region, which appears to have
# the most people even though it was devastated in the Bougainville Civil War.
#
# Although Shanks gives 1942-03-15 / 1943-11-01 for JST, these dates
# are apparently rough guesswork from the starts of military campaigns.
# The World War II entries below are instead based on Arawa-Kieta.
# The Japanese occupied Kieta in July 1942,
# according to the Pacific War Online Encyclopedia
# http://pwencycl.kgbudge.com/B/o/Bougainville.htm
# and seem to have controlled it until their 1945-08-21 surrender.
#
# The Autonomous Region of Bougainville plans to switch from UTC+10 to UTC+11
# on 2014-12-28 at 02:00. They call UTC+11 "Bougainville Standard Time";
# abbreviate this as BST. See:
# http://www.bougainville24.com/bougainville-issues/bougainville-gets-own-timezone/
#
Zone Pacific/Bougainville 10:22:16 - LMT 1880
9:48:32 - PMMT 1895
10:00 - PGT 1942 Jul
9:00 - JST 1945 Aug 21
10:00 - PGT 2014 Dec 28 2:00
11:00 - BST
# Pitcairn
# Zone NAME GMTOFF RULES FORMAT [UNTIL]
@ -826,6 +857,7 @@ Zone Pacific/Wallis 12:15:20 - LMT 1901
# 10:00 AEST AEDT Eastern Australia
# 10:00 ChST Chamorro
# 10:30 LHST LHDT Lord Howe*
# 11:00 BST Bougainville*
# 11:30 NZMT NZST New Zealand through 1945
# 12:00 NZST NZDT New Zealand 1946-present
# 12:15 CHAST Chatham through 1945*

View File

@ -91,10 +91,11 @@
# 0:00 WET WEST WEMT Western Europe
# 0:19:32.13 AMT NST Amsterdam, Netherlands Summer (1835-1937)*
# 0:20 NET NEST Netherlands (1937-1940)*
# 1:00 BST British Standard (1968-1971)
# 1:00 CET CEST CEMT Central Europe
# 1:00:14 SET Swedish (1879-1899)*
# 2:00 EET EEST Eastern Europe
# 3:00 FET Further-eastern Europe*
# 3:00 FET Further-eastern Europe (2011-2014)*
# 3:00 MSK MSD MSM* Moscow
# From Peter Ilieve (1994-12-04),
@ -746,6 +747,13 @@ Zone Europe/Vienna 1:05:21 - LMT 1893 Apr
# http://www.belta.by/ru/all_news/society/V-Belarusi-otmenjaetsja-perexod-na-sezonnoe-vremja_i_572952.html
# http://naviny.by/rubrics/society/2011/09/16/ic_articles_116_175144/
# http://news.tut.by/society/250578.html
#
# From Alexander Bokovoy (2014-10-09):
# Belarussian government decided against changing to winter time....
# http://eng.belta.by/all_news/society/Belarus-decides-against-adjusting-time-in-Russias-wake_i_76335.html
# From Paul Eggert (2014-10-08):
# Hence Belarus can share time zone abbreviations with Moscow again.
#
# Zone NAME GMTOFF RULES FORMAT [UNTIL]
Zone Europe/Minsk 1:50:16 - LMT 1880
1:50 - MMT 1924 May 2 # Minsk Mean Time
@ -758,7 +766,8 @@ Zone Europe/Minsk 1:50:16 - LMT 1880
2:00 - EET 1992 Mar 29 0:00s
2:00 1:00 EEST 1992 Sep 27 0:00s
2:00 Russia EE%sT 2011 Mar 27 2:00s
3:00 - FET
3:00 - FET 2014 Oct 26 1:00s
3:00 - MSK
# Belgium
#
@ -2524,7 +2533,7 @@ Zone Asia/Novosibirsk 5:31:40 - LMT 1919 Dec 14 6:00
# The Kemerovo region will remain at UTC+7 through the 2014-10-26 change, thus
# realigning itself with KRAT.
Zone Asia/Novokuznetsk 5:48:48 - NMT 1920 Jan 6
Zone Asia/Novokuznetsk 5:48:48 - LMT 1924 May 1
6:00 - KRAT 1930 Jun 21 # Krasnoyarsk Time
7:00 Russia KRA%sT 1991 Mar 31 2:00s
6:00 Russia KRA%sT 1992 Jan 19 2:00s

View File

@ -300,6 +300,12 @@ Zone PST8PDT -8:00 US P%sT
# time zone, but we do go by the Eastern time zone because so many people work
# in Columbus."
# From Paul Eggert (2014-09-06):
# Monthly Notices of the Royal Astronomical Society 44, 4 (1884-02-08), 208
# says that New York City Hall time was 3 minutes 58.4 seconds fast of
# Eastern time (i.e., -4:56:01.6) just before the 1883 switch. Round to the
# nearest second.
# Rule NAME FROM TO TYPE IN ON AT SAVE LETTER
Rule NYC 1920 only - Mar lastSun 2:00 1:00 D
Rule NYC 1920 only - Oct lastSun 2:00 0 S
@ -1118,17 +1124,16 @@ Zone America/Menominee -5:50:27 - LMT 1885 Sep 18 12:00
# An amendment to the Interpretation Act was registered on February 19/2007....
# http://action.attavik.ca/home/justice-gn/attach/2007/gaz02part2.pdf
# From Paul Eggert (2006-04-25):
# From Paul Eggert (2014-10-18):
# H. David Matthews and Mary Vincent's map
# "It's about TIME", _Canadian Geographic_ (September-October 1998)
# http://www.canadiangeographic.ca/Magazine/SO98/geomap.asp
# http://www.canadiangeographic.ca/Magazine/SO98/alacarte.asp
# contains detailed boundaries for regions observing nonstandard
# time and daylight saving time arrangements in Canada circa 1998.
#
# INMS, the Institute for National Measurement Standards in Ottawa, has
# information about standard and daylight saving time zones in Canada.
# http://inms-ienm.nrc-cnrc.gc.ca/en/time_services/daylight_saving_e.php
# (updated periodically).
# National Research Council Canada maintains info about time zones and DST.
# http://www.nrc-cnrc.gc.ca/eng/services/time/time_zones.html
# http://www.nrc-cnrc.gc.ca/eng/services/time/faq/index.html#Q5
# Its unofficial information is often taken from Matthews and Vincent.
# From Paul Eggert (2006-06-27):
@ -1993,10 +1998,7 @@ Zone America/Creston -7:46:04 - LMT 1884
# [Also see <http://www.nunatsiaq.com/nunavut/nvt10309_06.html> (2001-03-09).]
# From Gwillim Law (2005-05-21):
# According to maps at
# http://inms-ienm.nrc-cnrc.gc.ca/images/time_services/TZ01SWE.jpg
# http://inms-ienm.nrc-cnrc.gc.ca/images/time_services/TZ01SSE.jpg
# (both dated 2003), and
# According to ...
# http://www.canadiangeographic.ca/Magazine/SO98/geomap.asp
# (from a 1998 Canadian Geographic article), the de facto and de jure time
# for Southampton Island (at the north end of Hudson Bay) is UTC-5 all year
@ -2005,9 +2007,11 @@ Zone America/Creston -7:46:04 - LMT 1884
# predates the creation of Nunavut, it probably goes back many years....
# The Inuktitut name of Coral Harbour is Sallit, but it's rarely used.
#
# From Paul Eggert (2005-07-26):
# From Paul Eggert (2014-10-17):
# For lack of better information, assume that Southampton Island observed
# daylight saving only during wartime.
# daylight saving only during wartime. Gwillim Law's email also
# mentioned maps now maintained by National Research Council Canada;
# see above for an up-to-date link.
# From Chris Walton (2007-03-01):
# ... the community of Resolute (located on Cornwallis Island in
@ -3008,10 +3012,21 @@ Zone America/Tegucigalpa -5:48:52 - LMT 1921 Apr
# Shanks & Pottenger give -5:07:12, but Milne records -5:07:10.41 from an
# unspecified official document, and says "This time is used throughout the
# island". Go with Milne. Round to the nearest second as required by zic.
#
# Shanks & Pottenger give April 28 for the 1974 spring-forward transition, but
# Lance Neita writes that Prime Minister Michael Manley decreed it January 5.
# Assume Neita meant Jan 6 02:00, the same as the US. Neita also writes that
# Manley's supporters associated this act with Manley's nickname "Joshua"
# (recall that in the Bible the sun stood still at Joshua's request),
# and with the Rod of Correction which Manley said he had received from
# Haile Selassie, Emperor of Ethiopia. See:
# Neita L. The politician in all of us. Jamaica Observer 2014-09-20
# http://www.jamaicaobserver.com/columns/The-politician-in-all-of-us_17573647
#
# Zone NAME GMTOFF RULES FORMAT [UNTIL]
Zone America/Jamaica -5:07:11 - LMT 1890 # Kingston
-5:07:11 - KMT 1912 Feb # Kingston Mean Time
-5:00 - EST 1974 Apr 28 2:00
-5:00 - EST 1974
-5:00 US E%sT 1984
-5:00 - EST

View File

@ -330,7 +330,8 @@ PE -1203-07703 America/Lima
PF -1732-14934 Pacific/Tahiti Society Islands
PF -0900-13930 Pacific/Marquesas Marquesas Islands
PF -2308-13457 Pacific/Gambier Gambier Islands
PG -0930+14710 Pacific/Port_Moresby
PG -0930+14710 Pacific/Port_Moresby most locations
PG -0613+15534 Pacific/Bougainville Bougainville
PH +1435+12100 Asia/Manila
PK +2452+06703 Asia/Karachi
PL +5215+02100 Europe/Warsaw

View File

@ -75,6 +75,7 @@ SUNWprivate_1.1 {
Java_java_io_FileDescriptor_initIDs;
Java_java_io_FileDescriptor_sync;
Java_java_io_FileDescriptor_getAppend;
Java_java_io_FileInputStream_available;
Java_java_io_FileInputStream_close0;
Java_java_io_FileInputStream_initIDs;

View File

@ -54,14 +54,12 @@ PROFILE_1_JRE_LIB_FILES := \
$(OPENJDK_TARGET_CPU_LEGACY_LIB)/server/$(LIBRARY_PREFIX)jvm$(SHARED_LIBRARY_SUFFIX) \
$(OPENJDK_TARGET_CPU_LEGACY_LIB)/server/$(LIBRARY_PREFIX)jvm.diz \
$(OPENJDK_TARGET_CPU_LEGACY_LIB)/server/Xusage.txt \
calendars.properties \
classlist \
ext/localedata.jar \
ext/meta-index \
ext/sunec.jar \
ext/sunjce_provider.jar \
ext/sunpkcs11.jar \
hijrah-config-umalqura.properties \
jce.jar \
jsse.jar \
logging.properties \

View File

@ -1588,7 +1588,7 @@ public class File
/**
* A convenience method to set the owner's read permission for this abstract
* pathname. On some platforms it may be possible to start the Java virtual
* machine with special privileges that allow it to read files that that are
* machine with special privileges that allow it to read files that are
* marked as unreadable.
*
* <p>An invocation of this method of the form <tt>file.setReadable(arg)</tt>

View File

@ -26,6 +26,8 @@
package java.io;
import java.nio.channels.FileChannel;
import sun.misc.SharedSecrets;
import sun.misc.JavaIOFileDescriptorAccess;
import sun.nio.ch.FileChannelImpl;
@ -52,16 +54,17 @@ import sun.nio.ch.FileChannelImpl;
public
class FileOutputStream extends OutputStream
{
/**
* Access to FileDescriptor internals.
*/
private static final JavaIOFileDescriptorAccess fdAccess =
SharedSecrets.getJavaIOFileDescriptorAccess();
/**
* The system dependent file descriptor.
*/
private final FileDescriptor fd;
/**
* True if the file is opened for append.
*/
private final boolean append;
/**
* The associated channel, initialized lazily.
*/
@ -207,7 +210,6 @@ class FileOutputStream extends OutputStream
}
this.fd = new FileDescriptor();
fd.attach(this);
this.append = append;
this.path = name;
open(name, append);
@ -245,7 +247,6 @@ class FileOutputStream extends OutputStream
security.checkWrite(fdObj);
}
this.fd = fdObj;
this.append = false;
this.path = null;
fd.attach(this);
@ -287,7 +288,7 @@ class FileOutputStream extends OutputStream
* @exception IOException if an I/O error occurs.
*/
public void write(int b) throws IOException {
write(b, append);
write(b, fdAccess.getAppend(fd));
}
/**
@ -310,7 +311,7 @@ class FileOutputStream extends OutputStream
* @exception IOException if an I/O error occurs.
*/
public void write(byte b[]) throws IOException {
writeBytes(b, 0, b.length, append);
writeBytes(b, 0, b.length, fdAccess.getAppend(fd));
}
/**
@ -323,7 +324,7 @@ class FileOutputStream extends OutputStream
* @exception IOException if an I/O error occurs.
*/
public void write(byte b[], int off, int len) throws IOException {
writeBytes(b, off, len, append);
writeBytes(b, off, len, fdAccess.getAppend(fd));
}
/**
@ -395,7 +396,7 @@ class FileOutputStream extends OutputStream
public FileChannel getChannel() {
synchronized (this) {
if (channel == null) {
channel = FileChannelImpl.open(fd, path, false, true, append, this);
channel = FileChannelImpl.open(fd, path, false, true, this);
}
return channel;
}

View File

@ -44,6 +44,10 @@ abstract class DelegatingMethodHandle extends MethodHandle {
super(type, chooseDelegatingForm(target));
}
protected DelegatingMethodHandle(MethodType type, LambdaForm form) {
super(type, form);
}
/** Define this to extract the delegated target which supplies the invocation behavior. */
abstract protected MethodHandle getTarget();
@ -88,14 +92,31 @@ abstract class DelegatingMethodHandle extends MethodHandle {
return makeReinvokerForm(target, MethodTypeForm.LF_DELEGATE, DelegatingMethodHandle.class, NF_getTarget);
}
/** Create a LF which simply reinvokes a target of the given basic type. */
static LambdaForm makeReinvokerForm(MethodHandle target,
int whichCache,
Object constraint,
NamedFunction getTargetFn) {
String debugString;
switch(whichCache) {
case MethodTypeForm.LF_REBIND: debugString = "BMH.reinvoke"; break;
case MethodTypeForm.LF_DELEGATE: debugString = "MH.delegate"; break;
default: debugString = "MH.reinvoke"; break;
}
// No pre-action needed.
return makeReinvokerForm(target, whichCache, constraint, debugString, true, getTargetFn, null);
}
/** Create a LF which simply reinvokes a target of the given basic type. */
static LambdaForm makeReinvokerForm(MethodHandle target,
int whichCache,
Object constraint,
String debugString,
boolean forceInline,
NamedFunction getTargetFn,
NamedFunction preActionFn) {
MethodType mtype = target.type().basicType();
boolean customized = (whichCache < 0 ||
mtype.parameterSlotCount() > MethodType.MAX_MH_INVOKER_ARITY);
boolean hasPreAction = (preActionFn != null);
LambdaForm form;
if (!customized) {
form = mtype.form().cachedLambdaForm(whichCache);
@ -105,12 +126,16 @@ abstract class DelegatingMethodHandle extends MethodHandle {
final int ARG_BASE = 1;
final int ARG_LIMIT = ARG_BASE + mtype.parameterCount();
int nameCursor = ARG_LIMIT;
final int PRE_ACTION = hasPreAction ? nameCursor++ : -1;
final int NEXT_MH = customized ? -1 : nameCursor++;
final int REINVOKE = nameCursor++;
LambdaForm.Name[] names = LambdaForm.arguments(nameCursor - ARG_LIMIT, mtype.invokerType());
assert(names.length == nameCursor);
names[THIS_DMH] = names[THIS_DMH].withConstraint(constraint);
Object[] targetArgs;
if (hasPreAction) {
names[PRE_ACTION] = new LambdaForm.Name(preActionFn, names[THIS_DMH]);
}
if (customized) {
targetArgs = Arrays.copyOfRange(names, ARG_BASE, ARG_LIMIT, Object[].class);
names[REINVOKE] = new LambdaForm.Name(target, targetArgs); // the invoker is the target itself
@ -120,20 +145,14 @@ abstract class DelegatingMethodHandle extends MethodHandle {
targetArgs[0] = names[NEXT_MH]; // overwrite this MH with next MH
names[REINVOKE] = new LambdaForm.Name(mtype, targetArgs);
}
String debugString;
switch(whichCache) {
case MethodTypeForm.LF_REBIND: debugString = "BMH.reinvoke"; break;
case MethodTypeForm.LF_DELEGATE: debugString = "MH.delegate"; break;
default: debugString = "MH.reinvoke"; break;
}
form = new LambdaForm(debugString, ARG_LIMIT, names);
form = new LambdaForm(debugString, ARG_LIMIT, names, forceInline);
if (!customized) {
form = mtype.form().setCachedLambdaForm(whichCache, form);
}
return form;
}
private static final NamedFunction NF_getTarget;
static final NamedFunction NF_getTarget;
static {
try {
NF_getTarget = new NamedFunction(DelegatingMethodHandle.class

View File

@ -628,8 +628,13 @@ class InvokerBytecodeGenerator {
// Mark this method as a compiled LambdaForm
mv.visitAnnotation("Ljava/lang/invoke/LambdaForm$Compiled;", true);
// Force inlining of this invoker method.
mv.visitAnnotation("Ljava/lang/invoke/ForceInline;", true);
if (lambdaForm.forceInline) {
// Force inlining of this invoker method.
mv.visitAnnotation("Ljava/lang/invoke/ForceInline;", true);
} else {
mv.visitAnnotation("Ljava/lang/invoke/DontInline;", true);
}
// iterate over the form's names, generating bytecode instructions for each
// start iterating at the first name following the arguments

View File

@ -119,6 +119,7 @@ import static java.lang.invoke.MethodHandleNatives.Constants.*;
class LambdaForm {
final int arity;
final int result;
final boolean forceInline;
@Stable final Name[] names;
final String debugName;
MemberName vmentry; // low-level behavior, or null if not yet prepared
@ -243,11 +244,16 @@ class LambdaForm {
LambdaForm(String debugName,
int arity, Name[] names, int result) {
this(debugName, arity, names, result, true);
}
LambdaForm(String debugName,
int arity, Name[] names, int result, boolean forceInline) {
assert(namesOK(arity, names));
this.arity = arity;
this.result = fixResult(result, names);
this.names = names.clone();
this.debugName = fixDebugName(debugName);
this.forceInline = forceInline;
int maxOutArity = normalize();
if (maxOutArity > MethodType.MAX_MH_INVOKER_ARITY) {
// Cannot use LF interpreter on very high arity expressions.
@ -255,17 +261,23 @@ class LambdaForm {
compileToBytecode();
}
}
LambdaForm(String debugName,
int arity, Name[] names) {
this(debugName,
arity, names, LAST_RESULT);
this(debugName, arity, names, LAST_RESULT, true);
}
LambdaForm(String debugName,
int arity, Name[] names, boolean forceInline) {
this(debugName, arity, names, LAST_RESULT, forceInline);
}
LambdaForm(String debugName,
Name[] formals, Name[] temps, Name result) {
this(debugName,
formals.length, buildNames(formals, temps, result), LAST_RESULT);
formals.length, buildNames(formals, temps, result), LAST_RESULT, true);
}
LambdaForm(String debugName,
Name[] formals, Name[] temps, Name result, boolean forceInline) {
this(debugName,
formals.length, buildNames(formals, temps, result), LAST_RESULT, forceInline);
}
private static Name[] buildNames(Name[] formals, Name[] temps, Name result) {
@ -279,6 +291,10 @@ class LambdaForm {
}
private LambdaForm(String sig) {
this(sig, true);
}
private LambdaForm(String sig, boolean forceInline) {
// Make a blank lambda form, which returns a constant zero or null.
// It is used as a template for managing the invocation of similar forms that are non-empty.
// Called only from getPreparedForm.
@ -287,6 +303,7 @@ class LambdaForm {
this.result = (signatureReturn(sig) == V_TYPE ? -1 : arity);
this.names = buildEmptyNames(arity, sig);
this.debugName = "LF.zero";
this.forceInline = forceInline;
assert(nameRefsAreLegal());
assert(isEmpty());
assert(sig.equals(basicTypeSignature())) : sig + " != " + basicTypeSignature();

View File

@ -1438,10 +1438,9 @@ assertEquals("[three, thee, tee]", asListFix.invoke((Object)argv).toString());
/*non-public*/
void updateForm(LambdaForm newForm) {
if (form == newForm) return;
assert(this instanceof DirectMethodHandle && this.internalMemberName().isStatic());
// ISSUE: Should we have a memory fence here?
newForm.prepare(); // as in MethodHandle.<init>
UNSAFE.putObject(this, FORM_OFFSET, newForm);
this.form.prepare(); // as in MethodHandle.<init>
UNSAFE.fullFence();
}
private static final long FORM_OFFSET;

View File

@ -30,6 +30,7 @@ import java.security.PrivilegedAction;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.function.Function;
import sun.invoke.empty.Empty;
import sun.invoke.util.ValueConversions;
@ -713,10 +714,11 @@ import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP;
LambdaForm form = makeGuardWithTestForm(basicType);
BoundMethodHandle.SpeciesData data = BoundMethodHandle.speciesData_LLL();
BoundMethodHandle mh;
try {
mh = (BoundMethodHandle)
data.constructor().invokeBasic(type, form,
(Object) test, (Object) target, (Object) fallback);
(Object) test, (Object) profile(target), (Object) profile(fallback));
} catch (Throwable ex) {
throw uncaughtException(ex);
}
@ -724,6 +726,129 @@ import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP;
return mh;
}
static
MethodHandle profile(MethodHandle target) {
if (DONT_INLINE_THRESHOLD >= 0) {
return makeBlockInlningWrapper(target);
} else {
return target;
}
}
/**
* Block inlining during JIT-compilation of a target method handle if it hasn't been invoked enough times.
* Corresponding LambdaForm has @DontInline when compiled into bytecode.
*/
static
MethodHandle makeBlockInlningWrapper(MethodHandle target) {
LambdaForm lform = PRODUCE_BLOCK_INLINING_FORM.apply(target);
return new CountingWrapper(target, lform,
PRODUCE_BLOCK_INLINING_FORM, PRODUCE_REINVOKER_FORM,
DONT_INLINE_THRESHOLD);
}
/** Constructs reinvoker lambda form which block inlining during JIT-compilation for a particular method handle */
private static final Function<MethodHandle, LambdaForm> PRODUCE_BLOCK_INLINING_FORM = new Function<MethodHandle, LambdaForm>() {
@Override
public LambdaForm apply(MethodHandle target) {
return DelegatingMethodHandle.makeReinvokerForm(target,
MethodTypeForm.LF_DELEGATE_BLOCK_INLINING, CountingWrapper.class, "reinvoker.dontInline", false,
DelegatingMethodHandle.NF_getTarget, CountingWrapper.NF_maybeStopCounting);
}
};
/** Constructs simple reinvoker lambda form for a particular method handle */
private static final Function<MethodHandle, LambdaForm> PRODUCE_REINVOKER_FORM = new Function<MethodHandle, LambdaForm>() {
@Override
public LambdaForm apply(MethodHandle target) {
return DelegatingMethodHandle.makeReinvokerForm(target,
MethodTypeForm.LF_DELEGATE, DelegatingMethodHandle.class, DelegatingMethodHandle.NF_getTarget);
}
};
/**
* Counting method handle. It has 2 states: counting and non-counting.
* It is in counting state for the first n invocations and then transitions to non-counting state.
* Behavior in counting and non-counting states is determined by lambda forms produced by
* countingFormProducer & nonCountingFormProducer respectively.
*/
static class CountingWrapper extends DelegatingMethodHandle {
private final MethodHandle target;
private int count;
private Function<MethodHandle, LambdaForm> countingFormProducer;
private Function<MethodHandle, LambdaForm> nonCountingFormProducer;
private volatile boolean isCounting;
private CountingWrapper(MethodHandle target, LambdaForm lform,
Function<MethodHandle, LambdaForm> countingFromProducer,
Function<MethodHandle, LambdaForm> nonCountingFormProducer,
int count) {
super(target.type(), lform);
this.target = target;
this.count = count;
this.countingFormProducer = countingFromProducer;
this.nonCountingFormProducer = nonCountingFormProducer;
this.isCounting = (count > 0);
}
@Hidden
@Override
protected MethodHandle getTarget() {
return target;
}
@Override
public MethodHandle asTypeUncached(MethodType newType) {
MethodHandle newTarget = target.asType(newType);
MethodHandle wrapper;
if (isCounting) {
LambdaForm lform;
lform = countingFormProducer.apply(target);
wrapper = new CountingWrapper(newTarget, lform, countingFormProducer, nonCountingFormProducer, DONT_INLINE_THRESHOLD);
} else {
wrapper = newTarget; // no need for a counting wrapper anymore
}
return (asTypeCache = wrapper);
}
boolean countDown() {
if (count <= 0) {
// Try to limit number of updates. MethodHandle.updateForm() doesn't guarantee LF update visibility.
if (isCounting) {
isCounting = false;
return true;
} else {
return false;
}
} else {
--count;
return false;
}
}
@Hidden
static void maybeStopCounting(Object o1) {
CountingWrapper wrapper = (CountingWrapper) o1;
if (wrapper.countDown()) {
// Reached invocation threshold. Replace counting behavior with a non-counting one.
LambdaForm lform = wrapper.nonCountingFormProducer.apply(wrapper.target);
lform.compileToBytecode(); // speed up warmup by avoiding LF interpretation again after transition
wrapper.updateForm(lform);
}
}
static final NamedFunction NF_maybeStopCounting;
static {
Class<?> THIS_CLASS = CountingWrapper.class;
try {
NF_maybeStopCounting = new NamedFunction(THIS_CLASS.getDeclaredMethod("maybeStopCounting", Object.class));
} catch (ReflectiveOperationException ex) {
throw newInternalError(ex);
}
}
}
static
LambdaForm makeGuardWithTestForm(MethodType basicType) {
LambdaForm lform = basicType.form().cachedLambdaForm(MethodTypeForm.LF_GWT);

View File

@ -47,10 +47,11 @@ import sun.misc.Unsafe;
static final boolean TRACE_METHOD_LINKAGE;
static final boolean USE_LAMBDA_FORM_EDITOR;
static final int COMPILE_THRESHOLD;
static final int DONT_INLINE_THRESHOLD;
static final int PROFILE_LEVEL;
static {
final Object[] values = { false, false, false, false, false, null, null };
final Object[] values = new Object[8];
AccessController.doPrivileged(new PrivilegedAction<Void>() {
public Void run() {
values[0] = Boolean.getBoolean("java.lang.invoke.MethodHandle.DEBUG_NAMES");
@ -59,7 +60,8 @@ import sun.misc.Unsafe;
values[3] = Boolean.getBoolean("java.lang.invoke.MethodHandle.TRACE_METHOD_LINKAGE");
values[4] = Boolean.getBoolean("java.lang.invoke.MethodHandle.USE_LF_EDITOR");
values[5] = Integer.getInteger("java.lang.invoke.MethodHandle.COMPILE_THRESHOLD", 30);
values[6] = Integer.getInteger("java.lang.invoke.MethodHandle.PROFILE_LEVEL", 0);
values[6] = Integer.getInteger("java.lang.invoke.MethodHandle.DONT_INLINE_THRESHOLD", 30);
values[7] = Integer.getInteger("java.lang.invoke.MethodHandle.PROFILE_LEVEL", 0);
return null;
}
});
@ -69,7 +71,8 @@ import sun.misc.Unsafe;
TRACE_METHOD_LINKAGE = (Boolean) values[3];
USE_LAMBDA_FORM_EDITOR = (Boolean) values[4];
COMPILE_THRESHOLD = (Integer) values[5];
PROFILE_LEVEL = (Integer) values[6];
DONT_INLINE_THRESHOLD = (Integer) values[6];
PROFILE_LEVEL = (Integer) values[7];
}
/** Tell if any of the debugging switches are turned on.

View File

@ -63,24 +63,25 @@ final class MethodTypeForm {
final @Stable LambdaForm[] lambdaForms;
// Indexes into lambdaForms:
static final int
LF_INVVIRTUAL = 0, // DMH invokeVirtual
LF_INVSTATIC = 1,
LF_INVSPECIAL = 2,
LF_NEWINVSPECIAL = 3,
LF_INVINTERFACE = 4,
LF_INVSTATIC_INIT = 5, // DMH invokeStatic with <clinit> barrier
LF_INTERPRET = 6, // LF interpreter
LF_REBIND = 7, // BoundMethodHandle
LF_DELEGATE = 8, // DelegatingMethodHandle
LF_EX_LINKER = 9, // invokeExact_MT (for invokehandle)
LF_EX_INVOKER = 10, // MHs.invokeExact
LF_GEN_LINKER = 11, // generic invoke_MT (for invokehandle)
LF_GEN_INVOKER = 12, // generic MHs.invoke
LF_CS_LINKER = 13, // linkToCallSite_CS
LF_MH_LINKER = 14, // linkToCallSite_MH
LF_GWC = 15, // guardWithCatch (catchException)
LF_GWT = 16, // guardWithTest
LF_LIMIT = 17;
LF_INVVIRTUAL = 0, // DMH invokeVirtual
LF_INVSTATIC = 1,
LF_INVSPECIAL = 2,
LF_NEWINVSPECIAL = 3,
LF_INVINTERFACE = 4,
LF_INVSTATIC_INIT = 5, // DMH invokeStatic with <clinit> barrier
LF_INTERPRET = 6, // LF interpreter
LF_REBIND = 7, // BoundMethodHandle
LF_DELEGATE = 8, // DelegatingMethodHandle
LF_DELEGATE_BLOCK_INLINING = 9, // Counting DelegatingMethodHandle w/ @DontInline
LF_EX_LINKER = 10, // invokeExact_MT (for invokehandle)
LF_EX_INVOKER = 11, // MHs.invokeExact
LF_GEN_LINKER = 12, // generic invoke_MT (for invokehandle)
LF_GEN_INVOKER = 13, // generic MHs.invoke
LF_CS_LINKER = 14, // linkToCallSite_CS
LF_MH_LINKER = 15, // linkToCallSite_MH
LF_GWC = 16, // guardWithCatch (catchException)
LF_GWT = 17, // guardWithTest
LF_LIMIT = 18;
/** Return the type corresponding uniquely (1-1) to this MT-form.
* It might have any primitive returns or arguments, but will have no references except Object.

View File

@ -239,7 +239,7 @@ public abstract class Buffer {
* @throws IllegalArgumentException
* If the preconditions on <tt>newPosition</tt> do not hold
*/
public final Buffer position(int newPosition) {
public Buffer position(int newPosition) {
if ((newPosition > limit) || (newPosition < 0))
throw new IllegalArgumentException();
position = newPosition;
@ -270,7 +270,7 @@ public abstract class Buffer {
* @throws IllegalArgumentException
* If the preconditions on <tt>newLimit</tt> do not hold
*/
public final Buffer limit(int newLimit) {
public Buffer limit(int newLimit) {
if ((newLimit > capacity) || (newLimit < 0))
throw new IllegalArgumentException();
limit = newLimit;
@ -284,7 +284,7 @@ public abstract class Buffer {
*
* @return This buffer
*/
public final Buffer mark() {
public Buffer mark() {
mark = position;
return this;
}
@ -300,7 +300,7 @@ public abstract class Buffer {
* @throws InvalidMarkException
* If the mark has not been set
*/
public final Buffer reset() {
public Buffer reset() {
int m = mark;
if (m < 0)
throw new InvalidMarkException();
@ -325,7 +325,7 @@ public abstract class Buffer {
*
* @return This buffer
*/
public final Buffer clear() {
public Buffer clear() {
position = 0;
limit = capacity;
mark = -1;
@ -353,7 +353,7 @@ public abstract class Buffer {
*
* @return This buffer
*/
public final Buffer flip() {
public Buffer flip() {
limit = position;
position = 0;
mark = -1;
@ -375,7 +375,7 @@ public abstract class Buffer {
*
* @return This buffer
*/
public final Buffer rewind() {
public Buffer rewind() {
position = 0;
mark = -1;
return this;

View File

@ -208,4 +208,76 @@ public abstract class MappedByteBuffer
private native boolean isLoaded0(long address, long length, int pageCount);
private native void load0(long address, long length);
private native void force0(FileDescriptor fd, long address, long length);
// -- Covariant return type overrides
/**
* {@inheritDoc}
* @since 1.9
*/
@Override
public final MappedByteBuffer position(int newPosition) {
super.position(newPosition);
return this;
}
/**
* {@inheritDoc}
* @since 1.9
*/
@Override
public final MappedByteBuffer limit(int newLimit) {
super.limit(newLimit);
return this;
}
/**
* {@inheritDoc}
* @since 1.9
*/
@Override
public final MappedByteBuffer mark() {
super.mark();
return this;
}
/**
* {@inheritDoc}
* @since 1.9
*/
@Override
public final MappedByteBuffer reset() {
super.reset();
return this;
}
/**
* {@inheritDoc}
* @since 1.9
*/
@Override
public final MappedByteBuffer clear() {
super.clear();
return this;
}
/**
* {@inheritDoc}
* @since 1.9
*/
@Override
public final MappedByteBuffer flip() {
super.flip();
return this;
}
/**
* {@inheritDoc}
* @since 1.9
*/
@Override
public final MappedByteBuffer rewind() {
super.rewind();
return this;
}
}

View File

@ -1025,6 +1025,106 @@ public abstract class $Type$Buffer
return offset;
}
// -- Covariant return type overrides
/**
* {@inheritDoc}
* @since 1.9
*/
@Override
public
#if[!byte]
final
#end[!byte]
$Type$Buffer position(int newPosition) {
super.position(newPosition);
return this;
}
/**
* {@inheritDoc}
* @since 1.9
*/
@Override
public
#if[!byte]
final
#end[!byte]
$Type$Buffer limit(int newLimit) {
super.limit(newLimit);
return this;
}
/**
* {@inheritDoc}
* @since 1.9
*/
@Override
public
#if[!byte]
final
#end[!byte]
$Type$Buffer mark() {
super.mark();
return this;
}
/**
* {@inheritDoc}
* @since 1.9
*/
@Override
public
#if[!byte]
final
#end[!byte]
$Type$Buffer reset() {
super.reset();
return this;
}
/**
* {@inheritDoc}
* @since 1.9
*/
@Override
public
#if[!byte]
final
#end[!byte]
$Type$Buffer clear() {
super.clear();
return this;
}
/**
* {@inheritDoc}
* @since 1.9
*/
@Override
public
#if[!byte]
final
#end[!byte]
$Type$Buffer flip() {
super.flip();
return this;
}
/**
* {@inheritDoc}
* @since 1.9
*/
@Override
public
#if[!byte]
final
#end[!byte]
$Type$Buffer rewind() {
super.rewind();
return this;
}
/**
* Compacts this buffer&nbsp;&nbsp;<i>(optional operation)</i>.
*

View File

@ -208,7 +208,7 @@ public abstract class FileStore {
* @param attribute
* the attribute to read
* @return the attribute value; {@code null} may be a valid for some
* @return the attribute value; {@code null} may be valid for some
* attributes
*
* @throws UnsupportedOperationException

View File

@ -51,7 +51,7 @@
* <p> An attribute view provides a read-only or updatable view of the non-opaque
* values, or <em>metadata</em>, associated with objects in a file system.
* The {@link java.nio.file.attribute.FileAttributeView} interface is
* extended by several other interfaces that views to specific sets of file
* extended by several other interfaces that provide views to specific sets of file
* attributes. {@code FileAttributeViews} are selected by invoking the {@link
* java.nio.file.Files#getFileAttributeView} method with a
* <em>type-token</em> to identify the required view. Views can also be identified

View File

@ -61,13 +61,14 @@ import static java.time.temporal.ChronoField.EPOCH_DAY;
import java.io.File;
import java.io.FileInputStream;
import java.io.FilePermission;
import java.io.IOException;
import java.io.InputStream;
import java.io.InvalidObjectException;
import java.io.ObjectInputStream;
import java.io.Serializable;
import java.security.AccessController;
import java.security.PrivilegedActionException;
import java.security.PrivilegedAction;
import java.time.Clock;
import java.time.DateTimeException;
import java.time.Instant;
@ -145,29 +146,8 @@ import sun.util.logging.PlatformLogger;
* property resource that defines the {@code ID}, the {@code calendar type},
* the start of the calendar, the alignment with the
* ISO calendar, and the length of each month for a range of years.
* The variants are identified in the {@code calendars.properties} file.
* The new properties are prefixed with {@code "calendars.hijrah."}:
* <table cellpadding="2" border="0" summary="Configuration of Hijrah Calendar Variants">
* <thead>
* <tr class="tableSubHeadingColor">
* <th class="colFirst" align="left">Property Name</th>
* <th class="colFirst" align="left">Property value</th>
* <th class="colLast" align="left">Description </th>
* </tr>
* </thead>
* <tbody>
* <tr class="altColor">
* <td>calendars.hijrah.{ID}</td>
* <td>The property resource defining the {@code {ID}} variant</td>
* <td>The property resource is located with the {@code calendars.properties} file</td>
* </tr>
* <tr class="rowColor">
* <td>calendars.hijrah.{ID}.type</td>
* <td>The calendar type</td>
* <td>LDML defines the calendar type names</td>
* </tr>
* </tbody>
* </table>
* The variants are loaded by HijrahChronology as a resource from
* hijrah-config-&lt;calendar type&gt;.properties.
* <p>
* The Hijrah property resource is a set of properties that describe the calendar.
* The syntax is defined by {@code java.util.Properties#load(Reader)}.
@ -279,91 +259,41 @@ public final class HijrahChronology extends AbstractChronology implements Serial
* Computed by {@link #createEpochMonths}.
*/
private transient int maxYearLength;
/**
* A reference to the properties stored in
* ${java.home}/lib/calendars.properties
*/
private final transient static Properties calendarProperties;
/**
* Prefix of property names for Hijrah calendar variants.
* Prefix of resource names for Hijrah calendar variants.
*/
private static final String PROP_PREFIX = "calendar.hijrah.";
/**
* Suffix of property names containing the calendar type of a variant.
*/
private static final String PROP_TYPE_SUFFIX = ".type";
private static final String RESOURCE_PREFIX = "hijrah-config-";
/**
* Static initialization of the predefined calendars found in the
* lib/calendars.properties file.
* Suffix of resource names for Hijrah calendar variants.
*/
private static final String RESOURCE_SUFFIX = ".properties";
/**
* Static initialization of the built-in calendars.
* The data is not loaded until it is used.
*/
static {
try {
calendarProperties = sun.util.calendar.BaseCalendar.getCalendarProperties();
} catch (IOException ioe) {
throw new InternalError("Can't initialize lib/calendars.properties", ioe);
}
try {
INSTANCE = new HijrahChronology("Hijrah-umalqura");
// Register it by its aliases
AbstractChronology.registerChrono(INSTANCE, "Hijrah");
AbstractChronology.registerChrono(INSTANCE, "islamic");
} catch (DateTimeException ex) {
// Absence of Hijrah calendar is fatal to initializing this class.
PlatformLogger logger = PlatformLogger.getLogger("java.time.chrono");
logger.severe("Unable to initialize Hijrah calendar: Hijrah-umalqura", ex);
throw new RuntimeException("Unable to initialize Hijrah-umalqura calendar", ex.getCause());
}
registerVariants();
INSTANCE = new HijrahChronology("Hijrah-umalqura", "islamic-umalqura");
// Register it by its aliases
AbstractChronology.registerChrono(INSTANCE, "Hijrah");
AbstractChronology.registerChrono(INSTANCE, "islamic");
}
/**
* For each Hijrah variant listed, create the HijrahChronology and register it.
* Exceptions during initialization are logged but otherwise ignored.
*/
private static void registerVariants() {
for (String name : calendarProperties.stringPropertyNames()) {
if (name.startsWith(PROP_PREFIX)) {
String id = name.substring(PROP_PREFIX.length());
if (id.indexOf('.') >= 0) {
continue; // no name or not a simple name of a calendar
}
if (id.equals(INSTANCE.getId())) {
continue; // do not duplicate the default
}
try {
// Create and register the variant
HijrahChronology chrono = new HijrahChronology(id);
AbstractChronology.registerChrono(chrono);
} catch (DateTimeException ex) {
// Log error and continue
PlatformLogger logger = PlatformLogger.getLogger("java.time.chrono");
logger.severe("Unable to initialize Hijrah calendar: " + id, ex);
}
}
}
}
/**
* Create a HijrahChronology for the named variant.
* The resource and calendar type are retrieved from properties
* in the {@code calendars.properties}.
* The property names are {@code "calendar.hijrah." + id}
* and {@code "calendar.hijrah." + id + ".type"}
* Create a HijrahChronology for the named variant and type.
*
* @param id the id of the calendar
* @throws DateTimeException if the calendar type is missing from the properties file.
* @throws IllegalArgumentException if the id is empty
* @param calType the typeId of the calendar
* @throws IllegalArgumentException if the id or typeId is empty
*/
private HijrahChronology(String id) throws DateTimeException {
private HijrahChronology(String id, String calType) {
if (id.isEmpty()) {
throw new IllegalArgumentException("calendar id is empty");
}
String propName = PROP_PREFIX + id + PROP_TYPE_SUFFIX;
String calType = calendarProperties.getProperty(propName);
if (calType == null || calType.isEmpty()) {
throw new DateTimeException("calendarType is missing or empty for: " + propName);
if (calType.isEmpty()) {
throw new IllegalArgumentException("calendar typeId is empty");
}
this.typeId = id;
this.calendarType = calType;
@ -866,30 +796,26 @@ public final class HijrahChronology extends AbstractChronology implements Serial
/**
* Return the configuration properties from the resource.
* <p>
* The default location of the variant configuration resource is:
* The location of the variant configuration resource is:
* <pre>
* "$java.home/lib/" + resource-name
* "/java/time/chrono/hijrah-config-" + calendarType + ".properties"
* </pre>
*
* @param resource the name of the calendar property resource
* @param calendarType the calendarType of the calendar variant
* @return a Properties containing the properties read from the resource.
* @throws Exception if access to the property resource fails
*/
private static Properties readConfigProperties(final String resource) throws Exception {
try {
return AccessController
.doPrivileged((java.security.PrivilegedExceptionAction<Properties>)
() -> {
String libDir = System.getProperty("java.home") + File.separator + "lib";
File file = new File(libDir, resource);
Properties props = new Properties();
try (InputStream is = new FileInputStream(file)) {
props.load(is);
}
return props;
});
} catch (PrivilegedActionException pax) {
throw pax.getException();
private Properties readConfigProperties(final String calendarType) throws Exception {
String resourceName = RESOURCE_PREFIX + calendarType + RESOURCE_SUFFIX;
PrivilegedAction<InputStream> getResourceAction = () -> HijrahChronology.class.getResourceAsStream(resourceName);
FilePermission perm = new FilePermission("<<ALL FILES>>", "read");
try (InputStream is = AccessController.doPrivileged(getResourceAction, null, perm)) {
if (is == null) {
throw new RuntimeException("Hijrah calendar resource not found: /java/time/chrono/" + resourceName);
}
Properties props = new Properties();
props.load(is);
return props;
}
}
@ -906,9 +832,7 @@ public final class HijrahChronology extends AbstractChronology implements Serial
*/
private void loadCalendarData() {
try {
String resourceName = calendarProperties.getProperty(PROP_PREFIX + typeId);
Objects.requireNonNull(resourceName, "Resource missing for calendar: " + PROP_PREFIX + typeId);
Properties props = readConfigProperties(resourceName);
Properties props = readConfigProperties(calendarType);
Map<Integer, int[]> years = new HashMap<>();
int minYear = Integer.MAX_VALUE;
@ -937,7 +861,7 @@ public final class HijrahChronology extends AbstractChronology implements Serial
default:
try {
// Everything else is either a year or invalid
int year = Integer.valueOf(key);
int year = Integer.parseInt(key);
int[] months = parseMonths((String) entry.getValue());
years.put(year, months);
maxYear = Math.max(maxYear, year);
@ -1045,7 +969,7 @@ public final class HijrahChronology extends AbstractChronology implements Serial
}
for (int i = 0; i < 12; i++) {
try {
months[i] = Integer.valueOf(numbers[i]);
months[i] = Integer.parseInt(numbers[i]);
} catch (NumberFormatException nfe) {
throw new IllegalArgumentException("bad key: " + numbers[i]);
}
@ -1067,9 +991,9 @@ public final class HijrahChronology extends AbstractChronology implements Serial
throw new IllegalArgumentException("date must be yyyy-MM-dd");
}
int[] ymd = new int[3];
ymd[0] = Integer.valueOf(string.substring(0, 4));
ymd[1] = Integer.valueOf(string.substring(5, 7));
ymd[2] = Integer.valueOf(string.substring(8, 10));
ymd[0] = Integer.parseInt(string, 0, 4, 10);
ymd[1] = Integer.parseInt(string, 5, 7, 10);
ymd[2] = Integer.parseInt(string, 8, 10, 10);
return ymd;
} catch (NumberFormatException ex) {
throw new IllegalArgumentException("date must be yyyy-MM-dd", ex);

View File

@ -518,7 +518,7 @@ public interface Collection<E> extends Iterable<E> {
* <p>The default implementation should be overridden by subclasses that
* can return a more efficient spliterator. In order to
* preserve expected laziness behavior for the {@link #stream()} and
* {@link #parallelStream()}} methods, spliterators should either have the
* {@link #parallelStream()} methods, spliterators should either have the
* characteristic of {@code IMMUTABLE} or {@code CONCURRENT}, or be
* <em><a href="Spliterator.html#binding">late-binding</a></em>.
* If none of these is practical, the overriding class should describe the

View File

@ -97,8 +97,7 @@ class JapaneseImperialCalendar extends Calendar {
*
* This implementation uses
* sun.util.calendar.LocalGregorianCalendar to perform most of the
* calendar calculations. LocalGregorianCalendar is configurable
* and reads <JRE_HOME>/lib/calendars.properties at the start-up.
* calendar calculations.
*/
/**

View File

@ -33,6 +33,8 @@ import java.io.FileDescriptor;
public interface JavaIOFileDescriptorAccess {
public void set(FileDescriptor obj, int fd);
public int get(FileDescriptor fd);
public void setAppend(FileDescriptor obj, boolean append);
public boolean getAppend(FileDescriptor obj);
// Only valid on Windows
public void setHandle(FileDescriptor obj, long handle);

View File

@ -44,6 +44,8 @@ import java.util.ArrayList;
import java.util.List;
import sun.misc.Cleaner;
import sun.misc.JavaIOFileDescriptorAccess;
import sun.misc.SharedSecrets;
import sun.security.action.GetPropertyAction;
public class FileChannelImpl
@ -52,6 +54,10 @@ public class FileChannelImpl
// Memory allocation size for mapping buffers
private static final long allocationGranularity;
// Access to FileDispatcher internals
private static final JavaIOFileDescriptorAccess fdAccess =
SharedSecrets.getJavaIOFileDescriptorAccess();
// Used to make native read and write calls
private final FileDispatcher nd;
@ -61,7 +67,6 @@ public class FileChannelImpl
// File access mode (immutable)
private final boolean writable;
private final boolean readable;
private final boolean append;
// Required to prevent finalization of creating stream (immutable)
private final Object parent;
@ -77,31 +82,23 @@ public class FileChannelImpl
private final Object positionLock = new Object();
private FileChannelImpl(FileDescriptor fd, String path, boolean readable,
boolean writable, boolean append, Object parent)
boolean writable, Object parent)
{
this.fd = fd;
this.readable = readable;
this.writable = writable;
this.append = append;
this.parent = parent;
this.path = path;
this.nd = new FileDispatcherImpl(append);
this.nd = new FileDispatcherImpl();
}
// Used by FileInputStream.getChannel() and RandomAccessFile.getChannel()
// Used by FileInputStream.getChannel(), FileOutputStream.getChannel
// and RandomAccessFile.getChannel()
public static FileChannel open(FileDescriptor fd, String path,
boolean readable, boolean writable,
Object parent)
{
return new FileChannelImpl(fd, path, readable, writable, false, parent);
}
// Used by FileOutputStream.getChannel
public static FileChannel open(FileDescriptor fd, String path,
boolean readable, boolean writable,
boolean append, Object parent)
{
return new FileChannelImpl(fd, path, readable, writable, append, parent);
return new FileChannelImpl(fd, path, readable, writable, parent);
}
private void ensureOpen() throws IOException {
@ -109,7 +106,6 @@ public class FileChannelImpl
throw new ClosedChannelException();
}
// -- Standard channel operations --
protected void implCloseChannel() throws IOException {
@ -258,6 +254,7 @@ public class FileChannelImpl
ti = threads.add();
if (!isOpen())
return 0;
boolean append = fdAccess.getAppend(fd);
do {
// in append-mode then position is advanced to end before writing
p = (append) ? nd.size(fd) : position0(fd, -1);
@ -284,7 +281,7 @@ public class FileChannelImpl
if (!isOpen())
return null;
do {
p = position0(fd, newPosition);
p = position0(fd, newPosition);
} while ((p == IOStatus.INTERRUPTED) && isOpen());
return this;
} finally {

View File

@ -247,7 +247,7 @@ class ServerSocketChannelImpl
return null;
thread = NativeThread.current();
for (;;) {
n = accept0(this.fd, newfd, isaa);
n = accept(this.fd, newfd, isaa);
if ((n == IOStatus.INTERRUPTED) && isOpen())
continue;
break;
@ -410,6 +410,18 @@ class ServerSocketChannelImpl
return sb.toString();
}
/**
* Accept a connection on a socket.
*
* @implNote Wrap native call to allow instrumentation.
*/
private int accept(FileDescriptor ssfd, FileDescriptor newfd,
InetSocketAddress[] isaa)
throws IOException
{
return accept0(ssfd, newfd, isaa);
}
// -- Native methods --
// Accepts a new connection, setting the given file descriptor to refer to

View File

@ -560,7 +560,7 @@ final class CipherBox {
+ newLen);
hd.encodeBuffer(
(ByteBuffer)bb.duplicate().position(pos), System.out);
bb.duplicate().position(pos), System.out);
} catch (IOException e) { }
}
@ -790,7 +790,7 @@ final class CipherBox {
// The padding data should be filled with the padding length value.
int[] results = checkPadding(
(ByteBuffer)bb.duplicate().position(offset + newLen),
bb.duplicate().position(offset + newLen),
(byte)(padLen & 0xFF));
if (protocolVersion.v >= ProtocolVersion.TLS10.v) {
if (results[0] != 0) { // padding data has invalid bytes

View File

@ -349,8 +349,7 @@ final class EngineInputRecord extends InputRecord {
/*
* Copy data out of buffer, it's ready to go.
*/
ByteBuffer netBB = (ByteBuffer)
(ByteBuffer.allocate(len).put(buf, 0, len).flip());
ByteBuffer netBB = ByteBuffer.allocate(len).put(buf, 0, len).flip();
engine.writer.putOutboundDataSync(netBB);
}

View File

@ -113,9 +113,7 @@ final class EngineOutputRecord extends OutputRecord {
/*
* Copy data out of buffer, it's ready to go.
*/
ByteBuffer netBB = (ByteBuffer)
ByteBuffer.allocate(len).put(buf, off, len).flip();
ByteBuffer netBB = ByteBuffer.allocate(len).put(buf, off, len).flip();
writer.putOutboundData(netBB);
}

View File

@ -177,44 +177,6 @@ public abstract class CalendarSystem {
return (cs == null) ? cal : cs;
}
/**
* Returns a {@link Properties} loaded from lib/calendars.properties.
*
* @return a {@link Properties} loaded from lib/calendars.properties
* @throws IOException if an error occurred when reading from the input stream
* @throws IllegalArgumentException if the input stream contains any malformed
* Unicode escape sequences
*/
public static Properties getCalendarProperties() throws IOException {
Properties calendarProps = null;
try {
String homeDir = AccessController.doPrivileged(
new sun.security.action.GetPropertyAction("java.home"));
final String fname = homeDir + File.separator + "lib" + File.separator
+ "calendars.properties";
calendarProps = AccessController.doPrivileged(new PrivilegedExceptionAction<Properties>() {
@Override
public Properties run() throws IOException {
Properties props = new Properties();
try (FileInputStream fis = new FileInputStream(fname)) {
props.load(fis);
}
return props;
}
});
} catch (PrivilegedActionException e) {
Throwable cause = e.getCause();
if (cause instanceof IOException) {
throw (IOException) cause;
} else if (cause instanceof IllegalArgumentException) {
throw (IllegalArgumentException) cause;
}
// Should not happen
throw new InternalError(cause);
}
return calendarProps;
}
//////////////////////////////// Calendar API //////////////////////////////////
/**

View File

@ -829,7 +829,7 @@ public final class TimeZoneNames extends TimeZoneNamesBundle {
{"Europe/Madrid", CET},
{"Europe/Malta", CET},
{"Europe/Mariehamn", EET},
{"Europe/Minsk", FET},
{"Europe/Minsk", MSK},
{"Europe/Monaco", CET},
{"Europe/Moscow", MSK},
{"Europe/Nicosia", EET},
@ -917,6 +917,9 @@ public final class TimeZoneNames extends TimeZoneNamesBundle {
{"PRT", AST},
{"Pacific/Apia", WST_SAMOA},
{"Pacific/Auckland", NZST},
{"Pacific/Bougainville", new String[] {"Bougainville Standard Time", "BST",
"Bougainville Daylight Time", "BST",
"Bougainville Time", "BT"}},
{"Pacific/Chatham", CHAST},
{"Pacific/Chuuk", CHUT},
{"Pacific/Easter", EASTER},

View File

@ -1,29 +0,0 @@
# Copyright (c) 2005, 2014, 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. Oracle designates this
# particular file as subject to the "Classpath" exception as provided
# by Oracle in the LICENSE file that accompanied this code.
#
# 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.
#
#
# Hijrah calendars
#
calendar.hijrah.Hijrah-umalqura: hijrah-config-umalqura.properties
calendar.hijrah.Hijrah-umalqura.type: islamic-umalqura

View File

@ -28,6 +28,7 @@
extern jfieldID IO_fd_fdID;
extern jfieldID IO_handle_fdID;
extern jfieldID IO_append_fdID;
#ifdef _ALLBSD_SOURCE
#include <fcntl.h>

View File

@ -51,16 +51,22 @@ public final class FileDescriptor {
private List<Closeable> otherParents;
private boolean closed;
/**
* true, if file is opened for appending.
*/
private boolean append;
/**
* Constructs an (invalid) FileDescriptor
* object.
*/
public /**/ FileDescriptor() {
public FileDescriptor() {
fd = -1;
}
private /* */ FileDescriptor(int fd) {
private FileDescriptor(int fd) {
this.fd = fd;
this.append = getAppend(fd);
}
/**
@ -149,6 +155,14 @@ public final class FileDescriptor {
return obj.fd;
}
public void setAppend(FileDescriptor obj, boolean append) {
obj.append = append;
}
public boolean getAppend(FileDescriptor obj) {
return obj.append;
}
public void setHandle(FileDescriptor obj, long handle) {
throw new UnsupportedOperationException();
}
@ -160,6 +174,11 @@ public final class FileDescriptor {
);
}
/**
* Returns true, if the file was opened for appending.
*/
private static native boolean getAppend(int fd);
/*
* Package private methods to track referents.
* If multiple streams point to the same FileDescriptor, we cycle

View File

@ -35,10 +35,6 @@ class FileDispatcherImpl extends FileDispatcher
init();
}
FileDispatcherImpl(boolean append) {
/* append is ignored */
}
FileDispatcherImpl() {
}

View File

@ -141,7 +141,7 @@ class UnixAsynchronousServerSocketChannelImpl
Throwable exc = null;
try {
begin();
int n = accept0(this.fd, newfd, isaa);
int n = accept(this.fd, newfd, isaa);
// spurious wakeup, is this possible?
if (n == IOStatus.UNAVAILABLE) {
@ -277,7 +277,7 @@ class UnixAsynchronousServerSocketChannelImpl
try {
begin();
int n = accept0(this.fd, newfd, isaa);
int n = accept(this.fd, newfd, isaa);
if (n == IOStatus.UNAVAILABLE) {
// need calling context when there is security manager as
@ -332,6 +332,18 @@ class UnixAsynchronousServerSocketChannelImpl
}
}
/**
* Accept a connection on a socket.
*
* @implNote Wrap native call to allow instrumentation.
*/
private int accept(FileDescriptor ssfd, FileDescriptor newfd,
InetSocketAddress[] isaa)
throws IOException
{
return accept0(ssfd, newfd, isaa);
}
// -- Native methods --
private static native void initIDs();

View File

@ -134,7 +134,7 @@ class UnixChannelFactory {
throw new IllegalArgumentException("APPEND + TRUNCATE_EXISTING not allowed");
FileDescriptor fdObj = open(dfd, path, pathForPermissionCheck, flags, mode);
return FileChannelImpl.open(fdObj, path.toString(), flags.read, flags.write, flags.append, null);
return FileChannelImpl.open(fdObj, path.toString(), flags.read, flags.write, null);
}
/**
@ -288,6 +288,7 @@ class UnixChannelFactory {
// create java.io.FileDescriptor
FileDescriptor fdObj = new FileDescriptor();
fdAccess.set(fdObj, fd);
fdAccess.setAppend(fdObj, flags.append);
return fdObj;
}
}

View File

@ -23,6 +23,9 @@
* questions.
*/
#include <unistd.h>
#include <fcntl.h>
#include "jvm.h"
#include "io_util_md.h"
@ -35,6 +38,9 @@
/* field id for jint 'fd' in java.io.FileDescriptor */
jfieldID IO_fd_fdID;
/* field id for jboolean 'append' in java.io.FileDescriptor */
jfieldID IO_append_fdID;
/**************************************************************
* static methods to store field ID's in initializers
*/
@ -42,6 +48,7 @@ jfieldID IO_fd_fdID;
JNIEXPORT void JNICALL
Java_java_io_FileDescriptor_initIDs(JNIEnv *env, jclass fdClass) {
IO_fd_fdID = (*env)->GetFieldID(env, fdClass, "fd", "I");
IO_append_fdID = (*env)->GetFieldID(env, fdClass, "append", "Z");
}
/**************************************************************
@ -55,3 +62,9 @@ Java_java_io_FileDescriptor_sync(JNIEnv *env, jobject this) {
JNU_ThrowByName(env, "java/io/SyncFailedException", "sync failed");
}
}
JNIEXPORT jboolean JNICALL
Java_java_io_FileDescriptor_getAppend(JNIEnv *env, jclass fdClass, jint fd) {
int flags = fcntl(fd, F_GETFL);
return ((flags & O_APPEND) == 0) ? JNI_FALSE : JNI_TRUE;
}

View File

@ -107,7 +107,15 @@ fileOpen(JNIEnv *env, jobject this, jstring path, jfieldID fid, int flags)
#endif
fd = handleOpen(ps, flags, 0666);
if (fd != -1) {
jobject fdobj;
jboolean append;
SET_FD(this, fd, fid);
fdobj = (*env)->GetObjectField(env, this, fid);
if (fdobj != NULL) {
append = (flags & O_APPEND) == 0 ? JNI_FALSE : JNI_TRUE;
(*env)->SetBooleanField(env, fdobj, IO_append_fdID, append);
}
} else {
throwFileNotFoundException(env, path);
}

View File

@ -50,6 +50,11 @@ public final class FileDescriptor {
private List<Closeable> otherParents;
private boolean closed;
/**
* true, if file is opened for appending.
*/
private boolean append;
/**
* Constructs an (invalid) FileDescriptor
* object.
@ -75,6 +80,14 @@ public final class FileDescriptor {
return obj.fd;
}
public void setAppend(FileDescriptor obj, boolean append) {
obj.append = append;
}
public boolean getAppend(FileDescriptor obj) {
return obj.append;
}
public void setHandle(FileDescriptor obj, long handle) {
obj.handle = handle;
}

Some files were not shown because too many files have changed in this diff Show More