--- a/.hgtags-top-repo Wed Sep 08 14:04:18 2010 -0700
+++ b/.hgtags-top-repo Wed Jul 05 17:21:22 2017 +0200
@@ -82,3 +82,4 @@
9f96a4269d7727dad68864eaab795eafce270311 jdk7-b105
43096cccf1cee749c2f4e7714ee71f4e9e0f4d7f jdk7-b106
7d396ad455c3b2f68b0d7094891c5aba7c757a6e jdk7-b107
+140fdef4ddf52244013b6157dc542cd9f677bb6f jdk7-b108
--- a/corba/.hgtags Wed Sep 08 14:04:18 2010 -0700
+++ b/corba/.hgtags Wed Jul 05 17:21:22 2017 +0200
@@ -82,3 +82,4 @@
6f21b030092fb61244cc8a0aedf8058f7c022b81 jdk7-b105
519daea48888196af76a975a3b31258efa860bad jdk7-b106
232adb83eae8375439ccff65b6e205ca0da0510d jdk7-b107
+8d810527b499a67153365db74421a03c12b46f35 jdk7-b108
--- a/corba/make/jprt.properties Wed Sep 08 14:04:18 2010 -0700
+++ b/corba/make/jprt.properties Wed Jul 05 17:21:22 2017 +0200
@@ -1,5 +1,5 @@
#
-# Copyright (c) 2006, 2009, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2006, 2010, 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
@@ -24,29 +24,13 @@
#
# Properties for jprt
-jprt.tools.default.release=jdk1.7.0
-# Specific platform list
-jprt.build.platforms=\
-solaris_sparc_5.10,\
-solaris_sparcv9_5.10,\
-solaris_i586_5.10,\
-solaris_x64_5.10,\
-linux_i586_2.6,\
-linux_x64_2.6,\
-windows_i586_5.0,\
-windows_x64_5.2
+# Use whatever release that the submitted job requests
+jprt.tools.default.release=${jprt.submit.release}
-# The different build flavors we want
+# The different build flavors we want, we override here so we just get these 2
jprt.build.flavors=product,fastdebug
-# Explicitly designate what the 32bit match is for the 64bit build
-jprt.solaris_sparcv9.build.platform.match32=solaris_sparc_5.10
-jprt.solaris_sparcv9_5.10.build.platform.match32=solaris_sparc_5.10
-jprt.solaris_x64.build.platform.match32=solaris_i586_5.10
-jprt.solaris_x64_5.10.build.platform.match32=solaris_i586_5.10
+# Directories to be excluded from the source bundles
+jprt.bundle.exclude.src.dirs=build dist webrev
-# Directories needed to build
-jprt.bundle.src.dirs=make src
-jprt.bundle.exclude.src.dirs=build dist
-
--- a/hotspot/.hgtags Wed Sep 08 14:04:18 2010 -0700
+++ b/hotspot/.hgtags Wed Jul 05 17:21:22 2017 +0200
@@ -115,3 +115,6 @@
cc3fdfeb54b049f18edcf3463e6ab051d0b7b609 hs19-b05
688a538aa65412178286ae2a6b0c00b6711e121b hs19-b06
bf496cbe9b74dda5975a1559da7ecfdd313e509e jdk7-b107
+0000000000000000000000000000000000000000 hs19-b06
+6c43216df13513a0f96532aa06f213066c49e27b hs19-b06
+e44a93947ccbfce712b51725f313163606f15486 jdk7-b108
--- a/hotspot/src/cpu/sparc/vm/vm_version_sparc.cpp Wed Sep 08 14:04:18 2010 -0700
+++ b/hotspot/src/cpu/sparc/vm/vm_version_sparc.cpp Wed Jul 05 17:21:22 2017 +0200
@@ -112,6 +112,11 @@
}
}
+#ifdef COMPILER2
+ // Currently not supported anywhere.
+ FLAG_SET_DEFAULT(UseFPUForSpilling, false);
+#endif
+
char buf[512];
jio_snprintf(buf, sizeof(buf), "%s%s%s%s%s%s%s%s%s%s%s%s",
(has_v8() ? ", has_v8" : ""),
--- a/hotspot/src/cpu/x86/vm/vm_version_x86.cpp Wed Sep 08 14:04:18 2010 -0700
+++ b/hotspot/src/cpu/x86/vm/vm_version_x86.cpp Wed Jul 05 17:21:22 2017 +0200
@@ -482,6 +482,15 @@
}
}
+#ifdef COMPILER2
+ if (UseFPUForSpilling) {
+ if (UseSSE < 2) {
+ // Only supported with SSE2+
+ FLAG_SET_DEFAULT(UseFPUForSpilling, false);
+ }
+ }
+#endif
+
assert(0 <= ReadPrefetchInstr && ReadPrefetchInstr <= 3, "invalid value");
assert(0 <= AllocatePrefetchInstr && AllocatePrefetchInstr <= 3, "invalid value");
@@ -520,6 +529,11 @@
if( supports_sse4_2() && supports_ht() ) { // Nehalem based cpus
AllocatePrefetchDistance = 192;
AllocatePrefetchLines = 4;
+#ifdef COMPILER2
+ if (AggressiveOpts && FLAG_IS_DEFAULT(UseFPUForSpilling)) {
+ FLAG_SET_DEFAULT(UseFPUForSpilling, true);
+ }
+#endif
}
}
assert(AllocatePrefetchDistance % AllocatePrefetchStepSize == 0, "invalid value");
--- a/hotspot/src/cpu/x86/vm/x86_32.ad Wed Sep 08 14:04:18 2010 -0700
+++ b/hotspot/src/cpu/x86/vm/x86_32.ad Wed Jul 05 17:21:22 2017 +0200
@@ -852,6 +852,39 @@
}
}
+static int impl_movgpr2x_helper( CodeBuffer *cbuf, bool do_size, int src_lo, int dst_lo,
+ int src_hi, int dst_hi, int size, outputStream* st ) {
+ // 32-bit
+ if (cbuf) {
+ emit_opcode(*cbuf, 0x66);
+ emit_opcode(*cbuf, 0x0F);
+ emit_opcode(*cbuf, 0x6E);
+ emit_rm(*cbuf, 0x3, Matcher::_regEncode[dst_lo] & 7, Matcher::_regEncode[src_lo] & 7);
+#ifndef PRODUCT
+ } else if (!do_size) {
+ st->print("movdl %s, %s\t# spill", Matcher::regName[dst_lo], Matcher::regName[src_lo]);
+#endif
+ }
+ return 4;
+}
+
+
+static int impl_movx2gpr_helper( CodeBuffer *cbuf, bool do_size, int src_lo, int dst_lo,
+ int src_hi, int dst_hi, int size, outputStream* st ) {
+ // 32-bit
+ if (cbuf) {
+ emit_opcode(*cbuf, 0x66);
+ emit_opcode(*cbuf, 0x0F);
+ emit_opcode(*cbuf, 0x7E);
+ emit_rm(*cbuf, 0x3, Matcher::_regEncode[src_lo] & 7, Matcher::_regEncode[dst_lo] & 7);
+#ifndef PRODUCT
+ } else if (!do_size) {
+ st->print("movdl %s, %s\t# spill", Matcher::regName[dst_lo], Matcher::regName[src_lo]);
+#endif
+ }
+ return 4;
+}
+
static int impl_mov_helper( CodeBuffer *cbuf, bool do_size, int src, int dst, int size, outputStream* st ) {
if( cbuf ) {
emit_opcode(*cbuf, 0x8B );
@@ -947,6 +980,12 @@
if( dst_first_rc == rc_int && src_first_rc == rc_stack )
size = impl_helper(cbuf,do_size,true ,ra_->reg2offset(src_first),dst_first,0x8B,"MOV ",size, st);
+ // Check for integer reg-xmm reg copy
+ if( src_first_rc == rc_int && dst_first_rc == rc_xmm ) {
+ assert( (src_second_rc == rc_bad && dst_second_rc == rc_bad),
+ "no 64 bit integer-float reg moves" );
+ return impl_movgpr2x_helper(cbuf,do_size,src_first,dst_first,src_second, dst_second, size, st);
+ }
// --------------------------------------
// Check for float reg-reg copy
if( src_first_rc == rc_float && dst_first_rc == rc_float ) {
@@ -1018,6 +1057,13 @@
return impl_movx_helper(cbuf,do_size,src_first,dst_first,src_second, dst_second, size, st);
}
+ // Check for xmm reg-integer reg copy
+ if( src_first_rc == rc_xmm && dst_first_rc == rc_int ) {
+ assert( (src_second_rc == rc_bad && dst_second_rc == rc_bad),
+ "no 64 bit float-integer reg moves" );
+ return impl_movx2gpr_helper(cbuf,do_size,src_first,dst_first,src_second, dst_second, size, st);
+ }
+
// Check for xmm store
if( src_first_rc == rc_xmm && dst_first_rc == rc_stack ) {
return impl_x_helper(cbuf,do_size,false,ra_->reg2offset(dst_first),src_first, src_second, size, st);
--- a/hotspot/src/cpu/x86/vm/x86_64.ad Wed Sep 08 14:04:18 2010 -0700
+++ b/hotspot/src/cpu/x86/vm/x86_64.ad Wed Jul 05 17:21:22 2017 +0200
@@ -1607,8 +1607,8 @@
emit_opcode(*cbuf, 0x0F);
emit_opcode(*cbuf, 0x7E);
emit_rm(*cbuf, 0x3,
- Matcher::_regEncode[dst_first] & 7,
- Matcher::_regEncode[src_first] & 7);
+ Matcher::_regEncode[src_first] & 7,
+ Matcher::_regEncode[dst_first] & 7);
#ifndef PRODUCT
} else if (!do_size) {
st->print("movdq %s, %s\t# spill",
@@ -1637,8 +1637,8 @@
emit_opcode(*cbuf, 0x0F);
emit_opcode(*cbuf, 0x7E);
emit_rm(*cbuf, 0x3,
- Matcher::_regEncode[dst_first] & 7,
- Matcher::_regEncode[src_first] & 7);
+ Matcher::_regEncode[src_first] & 7,
+ Matcher::_regEncode[dst_first] & 7);
#ifndef PRODUCT
} else if (!do_size) {
st->print("movdl %s, %s\t# spill",
--- a/hotspot/src/cpu/zero/vm/bytecodeInterpreter_zero.inline.hpp Wed Sep 08 14:04:18 2010 -0700
+++ b/hotspot/src/cpu/zero/vm/bytecodeInterpreter_zero.inline.hpp Wed Jul 05 17:21:22 2017 +0200
@@ -1,6 +1,6 @@
/*
* Copyright (c) 2002, Oracle and/or its affiliates. All rights reserved.
- * Copyright 2007 Red Hat, Inc.
+ * Copyright 2007, 2010 Red Hat, Inc.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -268,7 +268,7 @@
return op1 - op2;
}
-inline jint BytecodeInterpreter::VMintUshr(jint op1, jint op2) {
+inline juint BytecodeInterpreter::VMintUshr(jint op1, jint op2) {
return ((juint) op1) >> (op2 & 0x1F);
}
--- a/hotspot/src/cpu/zero/vm/javaFrameAnchor_zero.hpp Wed Sep 08 14:04:18 2010 -0700
+++ b/hotspot/src/cpu/zero/vm/javaFrameAnchor_zero.hpp Wed Jul 05 17:21:22 2017 +0200
@@ -82,6 +82,10 @@
return _last_Java_fp;
}
+ address last_Java_pc() const {
+ return _last_Java_pc;
+ }
+
static ByteSize last_Java_fp_offset() {
return byte_offset_of(JavaFrameAnchor, _last_Java_fp);
}
--- a/hotspot/src/os_cpu/linux_sparc/vm/orderAccess_linux_sparc.inline.hpp Wed Sep 08 14:04:18 2010 -0700
+++ b/hotspot/src/os_cpu/linux_sparc/vm/orderAccess_linux_sparc.inline.hpp Wed Jul 05 17:21:22 2017 +0200
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2003, 2008, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 2010, 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
@@ -36,8 +36,8 @@
}
inline void OrderAccess::release() {
- jint* dummy = (jint*)&dummy;
- __asm__ volatile("stw %%g0, [%0]" : : "r" (dummy) : "memory");
+ jint* local_dummy = (jint*)&local_dummy;
+ __asm__ volatile("stw %%g0, [%0]" : : "r" (local_dummy) : "memory");
}
inline void OrderAccess::fence() {
--- a/hotspot/src/os_cpu/linux_x86/vm/orderAccess_linux_x86.inline.hpp Wed Sep 08 14:04:18 2010 -0700
+++ b/hotspot/src/os_cpu/linux_x86/vm/orderAccess_linux_x86.inline.hpp Wed Jul 05 17:21:22 2017 +0200
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2003, 2009, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 2010, 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
@@ -30,16 +30,18 @@
inline void OrderAccess::storeload() { fence(); }
inline void OrderAccess::acquire() {
- volatile intptr_t dummy;
+ volatile intptr_t local_dummy;
#ifdef AMD64
- __asm__ volatile ("movq 0(%%rsp), %0" : "=r" (dummy) : : "memory");
+ __asm__ volatile ("movq 0(%%rsp), %0" : "=r" (local_dummy) : : "memory");
#else
- __asm__ volatile ("movl 0(%%esp),%0" : "=r" (dummy) : : "memory");
+ __asm__ volatile ("movl 0(%%esp),%0" : "=r" (local_dummy) : : "memory");
#endif // AMD64
}
inline void OrderAccess::release() {
- dummy = 0;
+ // Avoid hitting the same cache-line from
+ // different threads.
+ volatile jint local_dummy = 0;
}
inline void OrderAccess::fence() {
--- a/hotspot/src/os_cpu/linux_zero/vm/os_linux_zero.cpp Wed Sep 08 14:04:18 2010 -0700
+++ b/hotspot/src/os_cpu/linux_zero/vm/os_linux_zero.cpp Wed Jul 05 17:21:22 2017 +0200
@@ -435,22 +435,22 @@
void _Copy_arrayof_conjoint_bytes(HeapWord* from,
HeapWord* to,
size_t count) {
- ShouldNotCallThis();
+ memmove(to, from, count);
}
void _Copy_arrayof_conjoint_jshorts(HeapWord* from,
HeapWord* to,
size_t count) {
- ShouldNotCallThis();
+ memmove(to, from, count * 2);
}
void _Copy_arrayof_conjoint_jints(HeapWord* from,
HeapWord* to,
size_t count) {
- ShouldNotCallThis();
+ memmove(to, from, count * 4);
}
void _Copy_arrayof_conjoint_jlongs(HeapWord* from,
HeapWord* to,
size_t count) {
- ShouldNotCallThis();
+ memmove(to, from, count * 8);
}
};
--- a/hotspot/src/os_cpu/linux_zero/vm/thread_linux_zero.cpp Wed Sep 08 14:04:18 2010 -0700
+++ b/hotspot/src/os_cpu/linux_zero/vm/thread_linux_zero.cpp Wed Jul 05 17:21:22 2017 +0200
@@ -1,6 +1,6 @@
/*
* Copyright (c) 1997, 2007, Oracle and/or its affiliates. All rights reserved.
- * Copyright 2009 Red Hat, Inc.
+ * Copyright 2009, 2010 Red Hat, Inc.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -23,6 +23,9 @@
*
*/
-// This file is intentionally empty
+#include "incls/_precompiled.incl"
+#include "incls/_thread_linux_zero.cpp.incl"
-void JavaThread::cache_global_variables() { }
+void JavaThread::cache_global_variables() {
+ // nothing to do
+}
--- a/hotspot/src/os_cpu/solaris_sparc/vm/orderAccess_solaris_sparc.inline.hpp Wed Sep 08 14:04:18 2010 -0700
+++ b/hotspot/src/os_cpu/solaris_sparc/vm/orderAccess_solaris_sparc.inline.hpp Wed Jul 05 17:21:22 2017 +0200
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2003, 2009, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 2010, 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
@@ -42,8 +42,8 @@
}
inline void OrderAccess::release() {
- jint* dummy = (jint*)&dummy;
- __asm__ volatile("stw %%g0, [%0]" : : "r" (dummy) : "memory");
+ jint* local_dummy = (jint*)&local_dummy;
+ __asm__ volatile("stw %%g0, [%0]" : : "r" (local_dummy) : "memory");
}
inline void OrderAccess::fence() {
@@ -57,7 +57,9 @@
}
inline void OrderAccess::release() {
- dummy = 0;
+ // Avoid hitting the same cache-line from
+ // different threads.
+ volatile jint local_dummy = 0;
}
inline void OrderAccess::fence() {
--- a/hotspot/src/os_cpu/solaris_x86/vm/orderAccess_solaris_x86.inline.hpp Wed Sep 08 14:04:18 2010 -0700
+++ b/hotspot/src/os_cpu/solaris_x86/vm/orderAccess_solaris_x86.inline.hpp Wed Jul 05 17:21:22 2017 +0200
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2003, 2009, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 2010, 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
@@ -40,7 +40,9 @@
}
inline void OrderAccess::release() {
- dummy = 0;
+ // Avoid hitting the same cache-line from
+ // different threads.
+ volatile jint local_dummy = 0;
}
inline void OrderAccess::fence() {
@@ -53,11 +55,11 @@
extern "C" {
inline void _OrderAccess_acquire() {
- volatile intptr_t dummy;
+ volatile intptr_t local_dummy;
#ifdef AMD64
- __asm__ volatile ("movq 0(%%rsp), %0" : "=r" (dummy) : : "memory");
+ __asm__ volatile ("movq 0(%%rsp), %0" : "=r" (local_dummy) : : "memory");
#else
- __asm__ volatile ("movl 0(%%esp),%0" : "=r" (dummy) : : "memory");
+ __asm__ volatile ("movl 0(%%esp),%0" : "=r" (local_dummy) : : "memory");
#endif // AMD64
}
inline void _OrderAccess_fence() {
--- a/hotspot/src/os_cpu/windows_x86/vm/orderAccess_windows_x86.inline.hpp Wed Sep 08 14:04:18 2010 -0700
+++ b/hotspot/src/os_cpu/windows_x86/vm/orderAccess_windows_x86.inline.hpp Wed Jul 05 17:21:22 2017 +0200
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2003, 2009, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 2010, 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
@@ -41,7 +41,7 @@
inline void OrderAccess::release() {
// A volatile store has release semantics.
- dummy = 0;
+ volatile jint local_dummy = 0;
}
inline void OrderAccess::fence() {
--- a/hotspot/src/share/vm/code/nmethod.cpp Wed Sep 08 14:04:18 2010 -0700
+++ b/hotspot/src/share/vm/code/nmethod.cpp Wed Jul 05 17:21:22 2017 +0200
@@ -433,6 +433,10 @@
_unload_reported = false; // jvmti state
NOT_PRODUCT(_has_debug_info = false);
+#ifdef ASSERT
+ _oops_are_stale = false;
+#endif
+
_oops_do_mark_link = NULL;
_jmethod_id = NULL;
_osr_link = NULL;
@@ -1230,11 +1234,10 @@
bool nmethod::make_not_entrant_or_zombie(unsigned int state) {
assert(state == zombie || state == not_entrant, "must be zombie or not_entrant");
- bool was_alive = false;
-
// Make sure neither the nmethod nor the method is flushed in case of a safepoint in code below.
nmethodLocker nml(this);
methodHandle the_method(method());
+ No_Safepoint_Verifier nsv;
{
// If the method is already zombie there is nothing to do
@@ -1303,13 +1306,27 @@
// state will be flushed later when the transition to zombie
// happens or they get unloaded.
if (state == zombie) {
- // zombie only - if a JVMTI agent has enabled the CompiledMethodUnload event
- // and it hasn't already been reported for this nmethod then report it now.
- // (the event may have been reported earilier if the GC marked it for unloading).
- post_compiled_method_unload();
+ {
+ // Flushing dependecies must be done before any possible
+ // safepoint can sneak in, otherwise the oops used by the
+ // dependency logic could have become stale.
+ MutexLockerEx mu(CodeCache_lock, Mutex::_no_safepoint_check_flag);
+ flush_dependencies(NULL);
+ }
- MutexLockerEx mu(CodeCache_lock, Mutex::_no_safepoint_check_flag);
- flush_dependencies(NULL);
+ {
+ // zombie only - if a JVMTI agent has enabled the CompiledMethodUnload event
+ // and it hasn't already been reported for this nmethod then report it now.
+ // (the event may have been reported earilier if the GC marked it for unloading).
+ Pause_No_Safepoint_Verifier pnsv(&nsv);
+ post_compiled_method_unload();
+ }
+
+#ifdef ASSERT
+ // It's no longer safe to access the oops section since zombie
+ // nmethods aren't scanned for GC.
+ _oops_are_stale = true;
+#endif
} else {
assert(state == not_entrant, "other cases may need to be handled differently");
}
--- a/hotspot/src/share/vm/code/nmethod.hpp Wed Sep 08 14:04:18 2010 -0700
+++ b/hotspot/src/share/vm/code/nmethod.hpp Wed Jul 05 17:21:22 2017 +0200
@@ -177,6 +177,10 @@
// Protected by Patching_lock
unsigned char _state; // {alive, not_entrant, zombie, unloaded)
+#ifdef ASSERT
+ bool _oops_are_stale; // indicates that it's no longer safe to access oops section
+#endif
+
enum { alive = 0,
not_entrant = 1, // uncommon trap has happened but activations may still exist
zombie = 2,
@@ -434,6 +438,7 @@
oop* oop_addr_at(int index) const { // for GC
// relocation indexes are biased by 1 (because 0 is reserved)
assert(index > 0 && index <= oops_size(), "must be a valid non-zero index");
+ assert(!_oops_are_stale, "oops are stale");
return &oops_begin()[index - 1];
}
--- a/hotspot/src/share/vm/compiler/compileBroker.cpp Wed Sep 08 14:04:18 2010 -0700
+++ b/hotspot/src/share/vm/compiler/compileBroker.cpp Wed Jul 05 17:21:22 2017 +0200
@@ -1652,12 +1652,10 @@
void CompileBroker::handle_full_code_cache() {
UseInterpreter = true;
if (UseCompiler || AlwaysCompileLoopMethods ) {
- CompilerThread* thread = CompilerThread::current();
- CompileLog* log = thread->log();
- if (log != NULL) {
- log->begin_elem("code_cache_full");
- log->stamp();
- log->end_elem();
+ if (xtty != NULL) {
+ xtty->begin_elem("code_cache_full");
+ xtty->stamp();
+ xtty->end_elem();
}
warning("CodeCache is full. Compiler has been disabled.");
warning("Try increasing the code cache size using -XX:ReservedCodeCacheSize=");
--- a/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/compactibleFreeListSpace.cpp Wed Sep 08 14:04:18 2010 -0700
+++ b/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/compactibleFreeListSpace.cpp Wed Jul 05 17:21:22 2017 +0200
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2001, 2009, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2001, 2010, 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
@@ -402,6 +402,29 @@
return res;
}
+void LinearAllocBlock::print_on(outputStream* st) const {
+ st->print_cr(" LinearAllocBlock: ptr = " PTR_FORMAT ", word_size = " SIZE_FORMAT
+ ", refillsize = " SIZE_FORMAT ", allocation_size_limit = " SIZE_FORMAT,
+ _ptr, _word_size, _refillSize, _allocation_size_limit);
+}
+
+void CompactibleFreeListSpace::print_on(outputStream* st) const {
+ st->print_cr("COMPACTIBLE FREELIST SPACE");
+ st->print_cr(" Space:");
+ Space::print_on(st);
+
+ st->print_cr("promoInfo:");
+ _promoInfo.print_on(st);
+
+ st->print_cr("_smallLinearAllocBlock");
+ _smallLinearAllocBlock.print_on(st);
+
+ // dump_memory_block(_smallLinearAllocBlock->_ptr, 128);
+
+ st->print_cr(" _fitStrategy = %s, _adaptive_freelists = %s",
+ _fitStrategy?"true":"false", _adaptive_freelists?"true":"false");
+}
+
void CompactibleFreeListSpace::print_indexed_free_lists(outputStream* st)
const {
reportIndexedFreeListStatistics();
@@ -557,13 +580,15 @@
void CompactibleFreeListSpace::set_end(HeapWord* value) {
HeapWord* prevEnd = end();
assert(prevEnd != value, "unnecessary set_end call");
- assert(prevEnd == NULL || value >= unallocated_block(), "New end is below unallocated block");
+ assert(prevEnd == NULL || !BlockOffsetArrayUseUnallocatedBlock || value >= unallocated_block(),
+ "New end is below unallocated block");
_end = value;
if (prevEnd != NULL) {
// Resize the underlying block offset table.
_bt.resize(pointer_delta(value, bottom()));
if (value <= prevEnd) {
- assert(value >= unallocated_block(), "New end is below unallocated block");
+ assert(!BlockOffsetArrayUseUnallocatedBlock || value >= unallocated_block(),
+ "New end is below unallocated block");
} else {
// Now, take this new chunk and add it to the free blocks.
// Note that the BOT has not yet been updated for this block.
@@ -938,7 +963,6 @@
size_t CompactibleFreeListSpace::block_size(const HeapWord* p) const {
NOT_PRODUCT(verify_objects_initialized());
- assert(MemRegion(bottom(), end()).contains(p), "p not in space");
// This must be volatile, or else there is a danger that the compiler
// will compile the code below into a sometimes-infinite loop, by keeping
// the value read the first time in a register.
@@ -957,7 +981,7 @@
// must read from what 'p' points to in each loop.
klassOop k = ((volatile oopDesc*)p)->klass_or_null();
if (k != NULL) {
- assert(k->is_oop(true /* ignore mark word */), "Should really be klass oop.");
+ assert(k->is_oop(true /* ignore mark word */), "Should be klass oop");
oop o = (oop)p;
assert(o->is_parsable(), "Should be parsable");
assert(o->is_oop(true /* ignore mark word */), "Should be an oop.");
@@ -1231,7 +1255,6 @@
// satisfy the request. This is different that
// evm.
// Don't record chunk off a LinAB? smallSplitBirth(size);
-
} else {
// Raid the exact free lists larger than size, even if they are not
// overpopulated.
@@ -1449,6 +1472,7 @@
// Update BOT last so that other (parallel) GC threads see a consistent
// view of the BOT and free blocks.
// Above must occur before BOT is updated below.
+ OrderAccess::storestore();
_bt.split_block(res, blk_size, size); // adjust block offset table
}
return res;
@@ -1477,6 +1501,7 @@
// Update BOT last so that other (parallel) GC threads see a consistent
// view of the BOT and free blocks.
// Above must occur before BOT is updated below.
+ OrderAccess::storestore();
_bt.split_block(res, blk_size, size); // adjust block offset table
_bt.allocated(res, size);
}
@@ -1856,6 +1881,8 @@
ffc->linkPrev(NULL); // Mark as a free block for other (parallel) GC threads.
// Above must occur before BOT is updated below.
// adjust block offset table
+ OrderAccess::storestore();
+ assert(chunk->isFree() && ffc->isFree(), "Error");
_bt.split_block((HeapWord*)chunk, chunk->size(), new_size);
if (rem_size < SmallForDictionary) {
bool is_par = (SharedHeap::heap()->n_par_threads() > 0);
@@ -1911,8 +1938,7 @@
// mark the "end" of the used space at the time of this call;
// note, however, that promoted objects from this point
// on are tracked in the _promoInfo below.
- set_saved_mark_word(BlockOffsetArrayUseUnallocatedBlock ?
- unallocated_block() : end());
+ set_saved_mark_word(unallocated_block());
// inform allocator that promotions should be tracked.
assert(_promoInfo.noPromotions(), "_promoInfo inconsistency");
_promoInfo.startTrackingPromotions();
@@ -2238,8 +2264,7 @@
}
void CompactibleFreeListSpace::print() const {
- tty->print(" CompactibleFreeListSpace");
- Space::print();
+ Space::print_on(tty);
}
void CompactibleFreeListSpace::prepare_for_verify() {
@@ -2253,18 +2278,28 @@
private:
const CompactibleFreeListSpace* _sp;
const MemRegion _span;
+ HeapWord* _last_addr;
+ size_t _last_size;
+ bool _last_was_obj;
+ bool _last_was_live;
public:
VerifyAllBlksClosure(const CompactibleFreeListSpace* sp,
- MemRegion span) : _sp(sp), _span(span) { }
+ MemRegion span) : _sp(sp), _span(span),
+ _last_addr(NULL), _last_size(0),
+ _last_was_obj(false), _last_was_live(false) { }
virtual size_t do_blk(HeapWord* addr) {
size_t res;
+ bool was_obj = false;
+ bool was_live = false;
if (_sp->block_is_obj(addr)) {
+ was_obj = true;
oop p = oop(addr);
guarantee(p->is_oop(), "Should be an oop");
res = _sp->adjustObjectSize(p->size());
if (_sp->obj_is_alive(addr)) {
+ was_live = true;
p->verify();
}
} else {
@@ -2275,7 +2310,20 @@
"Chunk should be on a free list");
}
}
- guarantee(res != 0, "Livelock: no rank reduction!");
+ if (res == 0) {
+ gclog_or_tty->print_cr("Livelock: no rank reduction!");
+ gclog_or_tty->print_cr(
+ " Current: addr = " PTR_FORMAT ", size = " SIZE_FORMAT ", obj = %s, live = %s \n"
+ " Previous: addr = " PTR_FORMAT ", size = " SIZE_FORMAT ", obj = %s, live = %s \n",
+ addr, res, was_obj ?"true":"false", was_live ?"true":"false",
+ _last_addr, _last_size, _last_was_obj?"true":"false", _last_was_live?"true":"false");
+ _sp->print_on(gclog_or_tty);
+ guarantee(false, "Seppuku!");
+ }
+ _last_addr = addr;
+ _last_size = res;
+ _last_was_obj = was_obj;
+ _last_was_live = was_live;
return res;
}
};
@@ -2521,7 +2569,7 @@
HeapWord* CFLS_LAB::alloc(size_t word_sz) {
FreeChunk* res;
- word_sz = _cfls->adjustObjectSize(word_sz);
+ guarantee(word_sz == _cfls->adjustObjectSize(word_sz), "Error");
if (word_sz >= CompactibleFreeListSpace::IndexSetSize) {
// This locking manages sync with other large object allocations.
MutexLockerEx x(_cfls->parDictionaryAllocLock(),
@@ -2667,12 +2715,12 @@
(cur_sz < CompactibleFreeListSpace::IndexSetSize) &&
(CMSSplitIndexedFreeListBlocks || k <= 1);
k++, cur_sz = k * word_sz) {
- FreeList* gfl = &_indexedFreeList[cur_sz];
FreeList fl_for_cur_sz; // Empty.
fl_for_cur_sz.set_size(cur_sz);
{
MutexLockerEx x(_indexedFreeListParLocks[cur_sz],
Mutex::_no_safepoint_check_flag);
+ FreeList* gfl = &_indexedFreeList[cur_sz];
if (gfl->count() != 0) {
// nn is the number of chunks of size cur_sz that
// we'd need to split k-ways each, in order to create
@@ -2685,9 +2733,9 @@
// we increment the split death count by the number of blocks
// we just took from the cur_sz-size blocks list and which
// we will be splitting below.
- ssize_t deaths = _indexedFreeList[cur_sz].splitDeaths() +
+ ssize_t deaths = gfl->splitDeaths() +
fl_for_cur_sz.count();
- _indexedFreeList[cur_sz].set_splitDeaths(deaths);
+ gfl->set_splitDeaths(deaths);
}
}
}
@@ -2703,18 +2751,25 @@
// access the main chunk sees it as a single free block until we
// change it.
size_t fc_size = fc->size();
+ assert(fc->isFree(), "Error");
for (int i = k-1; i >= 0; i--) {
FreeChunk* ffc = (FreeChunk*)((HeapWord*)fc + i * word_sz);
+ assert((i != 0) ||
+ ((fc == ffc) && ffc->isFree() &&
+ (ffc->size() == k*word_sz) && (fc_size == word_sz)),
+ "Counting error");
ffc->setSize(word_sz);
+ ffc->linkPrev(NULL); // Mark as a free block for other (parallel) GC threads.
ffc->linkNext(NULL);
- ffc->linkPrev(NULL); // Mark as a free block for other (parallel) GC threads.
// Above must occur before BOT is updated below.
- // splitting from the right, fc_size == (k - i + 1) * wordsize
- _bt.mark_block((HeapWord*)ffc, word_sz);
+ OrderAccess::storestore();
+ // splitting from the right, fc_size == i * word_sz
+ _bt.mark_block((HeapWord*)ffc, word_sz, true /* reducing */);
fc_size -= word_sz;
- _bt.verify_not_unallocated((HeapWord*)ffc, ffc->size());
+ assert(fc_size == i*word_sz, "Error");
+ _bt.verify_not_unallocated((HeapWord*)ffc, word_sz);
_bt.verify_single_block((HeapWord*)fc, fc_size);
- _bt.verify_single_block((HeapWord*)ffc, ffc->size());
+ _bt.verify_single_block((HeapWord*)ffc, word_sz);
// Push this on "fl".
fl->returnChunkAtHead(ffc);
}
@@ -2744,7 +2799,7 @@
_dictionary->minSize()),
FreeBlockDictionary::atLeast);
if (fc != NULL) {
- _bt.allocated((HeapWord*)fc, fc->size()); // update _unallocated_blk
+ _bt.allocated((HeapWord*)fc, fc->size(), true /* reducing */); // update _unallocated_blk
dictionary()->dictCensusUpdate(fc->size(),
true /*split*/,
false /*birth*/);
@@ -2754,8 +2809,10 @@
}
}
if (fc == NULL) return;
+ // Otherwise, split up that block.
assert((ssize_t)n >= 1, "Control point invariant");
- // Otherwise, split up that block.
+ assert(fc->isFree(), "Error: should be a free block");
+ _bt.verify_single_block((HeapWord*)fc, fc->size());
const size_t nn = fc->size() / word_sz;
n = MIN2(nn, n);
assert((ssize_t)n >= 1, "Control point invariant");
@@ -2773,6 +2830,7 @@
// dictionary and return, leaving "fl" empty.
if (n == 0) {
returnChunkToDictionary(fc);
+ assert(fl->count() == 0, "We never allocated any blocks");
return;
}
@@ -2785,11 +2843,14 @@
size_t prefix_size = n * word_sz;
rem_fc = (FreeChunk*)((HeapWord*)fc + prefix_size);
rem_fc->setSize(rem);
+ rem_fc->linkPrev(NULL); // Mark as a free block for other (parallel) GC threads.
rem_fc->linkNext(NULL);
- rem_fc->linkPrev(NULL); // Mark as a free block for other (parallel) GC threads.
// Above must occur before BOT is updated below.
assert((ssize_t)n > 0 && prefix_size > 0 && rem_fc > fc, "Error");
+ OrderAccess::storestore();
_bt.split_block((HeapWord*)fc, fc->size(), prefix_size);
+ assert(fc->isFree(), "Error");
+ fc->setSize(prefix_size);
if (rem >= IndexSetSize) {
returnChunkToDictionary(rem_fc);
dictionary()->dictCensusUpdate(rem, true /*split*/, true /*birth*/);
@@ -2815,11 +2876,12 @@
for (ssize_t i = n-1; i > 0; i--) {
FreeChunk* ffc = (FreeChunk*)((HeapWord*)fc + i * word_sz);
ffc->setSize(word_sz);
+ ffc->linkPrev(NULL); // Mark as a free block for other (parallel) GC threads.
ffc->linkNext(NULL);
- ffc->linkPrev(NULL); // Mark as a free block for other (parallel) GC threads.
// Above must occur before BOT is updated below.
+ OrderAccess::storestore();
// splitting from the right, fc_size == (n - i + 1) * wordsize
- _bt.mark_block((HeapWord*)ffc, word_sz);
+ _bt.mark_block((HeapWord*)ffc, word_sz, true /* reducing */);
fc_size -= word_sz;
_bt.verify_not_unallocated((HeapWord*)ffc, ffc->size());
_bt.verify_single_block((HeapWord*)ffc, ffc->size());
@@ -2828,9 +2890,11 @@
fl->returnChunkAtHead(ffc);
}
// First chunk
+ assert(fc->isFree() && fc->size() == n*word_sz, "Error: should still be a free block");
+ // The blocks above should show their new sizes before the first block below
fc->setSize(word_sz);
+ fc->linkPrev(NULL); // idempotent wrt free-ness, see assert above
fc->linkNext(NULL);
- fc->linkPrev(NULL);
_bt.verify_not_unallocated((HeapWord*)fc, fc->size());
_bt.verify_single_block((HeapWord*)fc, fc->size());
fl->returnChunkAtHead(fc);
--- a/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/compactibleFreeListSpace.hpp Wed Sep 08 14:04:18 2010 -0700
+++ b/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/compactibleFreeListSpace.hpp Wed Jul 05 17:21:22 2017 +0200
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2001, 2009, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2001, 2010, 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
@@ -48,6 +48,8 @@
size_t _word_size;
size_t _refillSize;
size_t _allocation_size_limit; // largest size that will be allocated
+
+ void print_on(outputStream* st) const;
};
// Concrete subclass of CompactibleSpace that implements
@@ -249,10 +251,14 @@
size_t numFreeBlocksInIndexedFreeLists() const;
// Accessor
HeapWord* unallocated_block() const {
- HeapWord* ub = _bt.unallocated_block();
- assert(ub >= bottom() &&
- ub <= end(), "space invariant");
- return ub;
+ if (BlockOffsetArrayUseUnallocatedBlock) {
+ HeapWord* ub = _bt.unallocated_block();
+ assert(ub >= bottom() &&
+ ub <= end(), "space invariant");
+ return ub;
+ } else {
+ return end();
+ }
}
void freed(HeapWord* start, size_t size) {
_bt.freed(start, size);
@@ -476,6 +482,7 @@
// Debugging support
void print() const;
+ void print_on(outputStream* st) const;
void prepare_for_verify();
void verify(bool allow_dirty) const;
void verifyFreeLists() const PRODUCT_RETURN;
--- a/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepGeneration.cpp Wed Sep 08 14:04:18 2010 -0700
+++ b/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepGeneration.cpp Wed Jul 05 17:21:22 2017 +0200
@@ -1019,7 +1019,7 @@
}
HeapWord* ConcurrentMarkSweepGeneration::have_lock_and_allocate(size_t size,
- bool tlab) {
+ bool tlab /* ignored */) {
assert_lock_strong(freelistLock());
size_t adjustedSize = CompactibleFreeListSpace::adjustObjectSize(size);
HeapWord* res = cmsSpace()->allocate(adjustedSize);
@@ -1032,6 +1032,11 @@
// allowing the object to be blackened (and its references scanned)
// either during a preclean phase or at the final checkpoint.
if (res != NULL) {
+ // We may block here with an uninitialized object with
+ // its mark-bit or P-bits not yet set. Such objects need
+ // to be safely navigable by block_start().
+ assert(oop(res)->klass_or_null() == NULL, "Object should be uninitialized here.");
+ assert(!((FreeChunk*)res)->isFree(), "Error, block will look free but show wrong size");
collector()->direct_allocated(res, adjustedSize);
_direct_allocated_words += adjustedSize;
// allocation counters
@@ -1061,8 +1066,14 @@
// [see comments preceding SweepClosure::do_blk() below for details]
// 1. need to mark the object as live so it isn't collected
// 2. need to mark the 2nd bit to indicate the object may be uninitialized
- // 3. need to mark the end of the object so sweeper can skip over it
- // if it's uninitialized when the sweeper reaches it.
+ // 3. need to mark the end of the object so marking, precleaning or sweeping
+ // can skip over uninitialized or unparsable objects. An allocated
+ // object is considered uninitialized for our purposes as long as
+ // its klass word is NULL. (Unparsable objects are those which are
+ // initialized in the sense just described, but whose sizes can still
+ // not be correctly determined. Note that the class of unparsable objects
+ // can only occur in the perm gen. All old gen objects are parsable
+ // as soon as they are initialized.)
_markBitMap.mark(start); // object is live
_markBitMap.mark(start + 1); // object is potentially uninitialized?
_markBitMap.mark(start + size - 1);
@@ -1088,7 +1099,13 @@
// We don't need to mark the object as uninitialized (as
// in direct_allocated above) because this is being done with the
// world stopped and the object will be initialized by the
- // time the sweeper gets to look at it.
+ // time the marking, precleaning or sweeping get to look at it.
+ // But see the code for copying objects into the CMS generation,
+ // where we need to ensure that concurrent readers of the
+ // block offset table are able to safely navigate a block that
+ // is in flux from being free to being allocated (and in
+ // transition while being copied into) and subsequently
+ // becoming a bona-fide object when the copy/promotion is complete.
assert(SafepointSynchronize::is_at_safepoint(),
"expect promotion only at safepoints");
@@ -1304,6 +1321,48 @@
return collector()->allocation_limit_reached(space, top, word_sz);
}
+// IMPORTANT: Notes on object size recognition in CMS.
+// ---------------------------------------------------
+// A block of storage in the CMS generation is always in
+// one of three states. A free block (FREE), an allocated
+// object (OBJECT) whose size() method reports the correct size,
+// and an intermediate state (TRANSIENT) in which its size cannot
+// be accurately determined.
+// STATE IDENTIFICATION: (32 bit and 64 bit w/o COOPS)
+// -----------------------------------------------------
+// FREE: klass_word & 1 == 1; mark_word holds block size
+//
+// OBJECT: klass_word installed; klass_word != 0 && klass_word & 0 == 0;
+// obj->size() computes correct size
+// [Perm Gen objects needs to be "parsable" before they can be navigated]
+//
+// TRANSIENT: klass_word == 0; size is indeterminate until we become an OBJECT
+//
+// STATE IDENTIFICATION: (64 bit+COOPS)
+// ------------------------------------
+// FREE: mark_word & CMS_FREE_BIT == 1; mark_word & ~CMS_FREE_BIT gives block_size
+//
+// OBJECT: klass_word installed; klass_word != 0;
+// obj->size() computes correct size
+// [Perm Gen comment above continues to hold]
+//
+// TRANSIENT: klass_word == 0; size is indeterminate until we become an OBJECT
+//
+//
+// STATE TRANSITION DIAGRAM
+//
+// mut / parnew mut / parnew
+// FREE --------------------> TRANSIENT ---------------------> OBJECT --|
+// ^ |
+// |------------------------ DEAD <------------------------------------|
+// sweep mut
+//
+// While a block is in TRANSIENT state its size cannot be determined
+// so readers will either need to come back later or stall until
+// the size can be determined. Note that for the case of direct
+// allocation, P-bits, when available, may be used to determine the
+// size of an object that may not yet have been initialized.
+
// Things to support parallel young-gen collection.
oop
ConcurrentMarkSweepGeneration::par_promote(int thread_num,
@@ -1331,33 +1390,39 @@
}
}
assert(promoInfo->has_spooling_space(), "Control point invariant");
- HeapWord* obj_ptr = ps->lab.alloc(word_sz);
+ const size_t alloc_sz = CompactibleFreeListSpace::adjustObjectSize(word_sz);
+ HeapWord* obj_ptr = ps->lab.alloc(alloc_sz);
if (obj_ptr == NULL) {
- obj_ptr = expand_and_par_lab_allocate(ps, word_sz);
+ obj_ptr = expand_and_par_lab_allocate(ps, alloc_sz);
if (obj_ptr == NULL) {
return NULL;
}
}
oop obj = oop(obj_ptr);
+ OrderAccess::storestore();
assert(obj->klass_or_null() == NULL, "Object should be uninitialized here.");
+ assert(!((FreeChunk*)obj_ptr)->isFree(), "Error, block will look free but show wrong size");
+ // IMPORTANT: See note on object initialization for CMS above.
// Otherwise, copy the object. Here we must be careful to insert the
// klass pointer last, since this marks the block as an allocated object.
// Except with compressed oops it's the mark word.
HeapWord* old_ptr = (HeapWord*)old;
+ // Restore the mark word copied above.
+ obj->set_mark(m);
+ assert(obj->klass_or_null() == NULL, "Object should be uninitialized here.");
+ assert(!((FreeChunk*)obj_ptr)->isFree(), "Error, block will look free but show wrong size");
+ OrderAccess::storestore();
+
+ if (UseCompressedOops) {
+ // Copy gap missed by (aligned) header size calculation below
+ obj->set_klass_gap(old->klass_gap());
+ }
if (word_sz > (size_t)oopDesc::header_size()) {
Copy::aligned_disjoint_words(old_ptr + oopDesc::header_size(),
obj_ptr + oopDesc::header_size(),
word_sz - oopDesc::header_size());
}
- if (UseCompressedOops) {
- // Copy gap missed by (aligned) header size calculation above
- obj->set_klass_gap(old->klass_gap());
- }
-
- // Restore the mark word copied above.
- obj->set_mark(m);
-
// Now we can track the promoted object, if necessary. We take care
// to delay the transition from uninitialized to full object
// (i.e., insertion of klass pointer) until after, so that it
@@ -1365,18 +1430,22 @@
if (promoInfo->tracking()) {
promoInfo->track((PromotedObject*)obj, old->klass());
}
+ assert(obj->klass_or_null() == NULL, "Object should be uninitialized here.");
+ assert(!((FreeChunk*)obj_ptr)->isFree(), "Error, block will look free but show wrong size");
+ assert(old->is_oop(), "Will use and dereference old klass ptr below");
// Finally, install the klass pointer (this should be volatile).
+ OrderAccess::storestore();
obj->set_klass(old->klass());
-
- assert(old->is_oop(), "Will dereference klass ptr below");
+ // We should now be able to calculate the right size for this object
+ assert(obj->is_oop() && obj->size() == (int)word_sz, "Error, incorrect size computed for promoted object");
+
collector()->promoted(true, // parallel
obj_ptr, old->is_objArray(), word_sz);
NOT_PRODUCT(
- Atomic::inc(&_numObjectsPromoted);
- Atomic::add((jint)CompactibleFreeListSpace::adjustObjectSize(obj->size()),
- &_numWordsPromoted);
+ Atomic::inc_ptr(&_numObjectsPromoted);
+ Atomic::add_ptr(alloc_sz, &_numWordsPromoted);
)
return obj;
@@ -1965,6 +2034,9 @@
_intra_sweep_estimate.padded_average());
}
+ {
+ TraceCMSMemoryManagerStats();
+ }
GenMarkSweep::invoke_at_safepoint(_cmsGen->level(),
ref_processor(), clear_all_soft_refs);
#ifdef ASSERT
@@ -3415,6 +3487,7 @@
void CMSCollector::checkpointRootsInitial(bool asynch) {
assert(_collectorState == InitialMarking, "Wrong collector state");
check_correct_thread_executing();
+ TraceCMSMemoryManagerStats tms(_collectorState);
ReferenceProcessor* rp = ref_processor();
SpecializationStats::clear();
assert(_restart_addr == NULL, "Control point invariant");
@@ -4748,6 +4821,7 @@
// world is stopped at this checkpoint
assert(SafepointSynchronize::is_at_safepoint(),
"world should be stopped");
+ TraceCMSMemoryManagerStats tms(_collectorState);
verify_work_stacks_empty();
verify_overflow_empty();
@@ -5849,6 +5923,8 @@
verify_work_stacks_empty();
verify_overflow_empty();
increment_sweep_count();
+ TraceCMSMemoryManagerStats tms(_collectorState);
+
_inter_sweep_timer.stop();
_inter_sweep_estimate.sample(_inter_sweep_timer.seconds());
size_policy()->avg_cms_free_at_sweep()->sample(_cmsGen->free());
@@ -7861,14 +7937,20 @@
FreeChunk* fc = (FreeChunk*)addr;
size_t res;
- // check if we are done sweepinrg
- if (addr == _limit) { // we have swept up to the limit, do nothing more
+ // Check if we are done sweeping. Below we check "addr >= _limit" rather
+ // than "addr == _limit" because although _limit was a block boundary when
+ // we started the sweep, it may no longer be one because heap expansion
+ // may have caused us to coalesce the block ending at the address _limit
+ // with a newly expanded chunk (this happens when _limit was set to the
+ // previous _end of the space), so we may have stepped past _limit; see CR 6977970.
+ if (addr >= _limit) { // we have swept up to or past the limit, do nothing more
assert(_limit >= _sp->bottom() && _limit <= _sp->end(),
"sweep _limit out of bounds");
+ assert(addr < _sp->end(), "addr out of bounds");
// help the closure application finish
- return pointer_delta(_sp->end(), _limit);
- }
- assert(addr <= _limit, "sweep invariant");
+ return pointer_delta(_sp->end(), addr);
+ }
+ assert(addr < _limit, "sweep invariant");
// check if we should yield
do_yield_check(addr);
@@ -9121,3 +9203,57 @@
}
return res;
}
+
+TraceCMSMemoryManagerStats::TraceCMSMemoryManagerStats(CMSCollector::CollectorState phase): TraceMemoryManagerStats() {
+
+ switch (phase) {
+ case CMSCollector::InitialMarking:
+ initialize(true /* fullGC */ ,
+ true /* recordGCBeginTime */,
+ true /* recordPreGCUsage */,
+ false /* recordPeakUsage */,
+ false /* recordPostGCusage */,
+ true /* recordAccumulatedGCTime */,
+ false /* recordGCEndTime */,
+ false /* countCollection */ );
+ break;
+
+ case CMSCollector::FinalMarking:
+ initialize(true /* fullGC */ ,
+ false /* recordGCBeginTime */,
+ false /* recordPreGCUsage */,
+ false /* recordPeakUsage */,
+ false /* recordPostGCusage */,
+ true /* recordAccumulatedGCTime */,
+ false /* recordGCEndTime */,
+ false /* countCollection */ );
+ break;
+
+ case CMSCollector::Sweeping:
+ initialize(true /* fullGC */ ,
+ false /* recordGCBeginTime */,
+ false /* recordPreGCUsage */,
+ true /* recordPeakUsage */,
+ true /* recordPostGCusage */,
+ false /* recordAccumulatedGCTime */,
+ true /* recordGCEndTime */,
+ true /* countCollection */ );
+ break;
+
+ default:
+ ShouldNotReachHere();
+ }
+}
+
+// when bailing out of cms in concurrent mode failure
+TraceCMSMemoryManagerStats::TraceCMSMemoryManagerStats(): TraceMemoryManagerStats() {
+ initialize(true /* fullGC */ ,
+ true /* recordGCBeginTime */,
+ true /* recordPreGCUsage */,
+ true /* recordPeakUsage */,
+ true /* recordPostGCusage */,
+ true /* recordAccumulatedGCTime */,
+ true /* recordGCEndTime */,
+ true /* countCollection */ );
+}
+
--- a/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepGeneration.hpp Wed Sep 08 14:04:18 2010 -0700
+++ b/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepGeneration.hpp Wed Jul 05 17:21:22 2017 +0200
@@ -507,6 +507,7 @@
friend class VM_CMS_Operation;
friend class VM_CMS_Initial_Mark;
friend class VM_CMS_Final_Remark;
+ friend class TraceCMSMemoryManagerStats;
private:
jlong _time_of_last_gc;
@@ -1009,10 +1010,10 @@
// Non-product stat counters
NOT_PRODUCT(
- int _numObjectsPromoted;
- int _numWordsPromoted;
- int _numObjectsAllocated;
- int _numWordsAllocated;
+ size_t _numObjectsPromoted;
+ size_t _numWordsPromoted;
+ size_t _numObjectsAllocated;
+ size_t _numWordsAllocated;
)
// Used for sizing decisions
@@ -1858,3 +1859,11 @@
_dead_bit_map(dead_bit_map) {}
size_t do_blk(HeapWord* addr);
};
+
+class TraceCMSMemoryManagerStats : public TraceMemoryManagerStats {
+
+ public:
+ TraceCMSMemoryManagerStats(CMSCollector::CollectorState phase);
+ TraceCMSMemoryManagerStats();
+};
+
--- a/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/freeChunk.hpp Wed Sep 08 14:04:18 2010 -0700
+++ b/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/freeChunk.hpp Wed Jul 05 17:21:22 2017 +0200
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2001, 2008, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2001, 2010, 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
@@ -110,15 +110,21 @@
}
void linkNext(FreeChunk* ptr) { _next = ptr; }
void linkPrev(FreeChunk* ptr) {
- LP64_ONLY(if (UseCompressedOops) _prev = ptr; else)
- _prev = (FreeChunk*)((intptr_t)ptr | 0x1);
+ LP64_ONLY(if (UseCompressedOops) _prev = ptr; else)
+ _prev = (FreeChunk*)((intptr_t)ptr | 0x1);
}
void clearPrev() { _prev = NULL; }
void clearNext() { _next = NULL; }
void markNotFree() {
- LP64_ONLY(if (UseCompressedOops) set_mark(markOopDesc::prototype());)
- // Also set _prev to null
- _prev = NULL;
+ // Set _prev (klass) to null before (if) clearing the mark word below
+ _prev = NULL;
+#ifdef _LP64
+ if (UseCompressedOops) {
+ OrderAccess::storestore();
+ set_mark(markOopDesc::prototype());
+ }
+#endif
+ assert(!isFree(), "Error");
}
// Return the address past the end of this chunk
--- a/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/promotionInfo.cpp Wed Sep 08 14:04:18 2010 -0700
+++ b/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/promotionInfo.cpp Wed Jul 05 17:21:22 2017 +0200
@@ -330,7 +330,7 @@
void PromotionInfo::print_on(outputStream* st) const {
SpoolBlock* curSpool = NULL;
size_t i = 0;
- st->print_cr("start & end indices: [" SIZE_FORMAT ", " SIZE_FORMAT ")",
+ st->print_cr(" start & end indices: [" SIZE_FORMAT ", " SIZE_FORMAT ")",
_firstIndex, _nextIndex);
for (curSpool = _spoolHead; curSpool != _spoolTail && curSpool != NULL;
curSpool = curSpool->nextSpoolBlock) {
@@ -350,7 +350,7 @@
st->print_cr(" free ");
i++;
}
- st->print_cr(SIZE_FORMAT " header spooling blocks", i);
+ st->print_cr(" " SIZE_FORMAT " header spooling blocks", i);
}
void SpoolBlock::print_on(outputStream* st) const {
--- a/hotspot/src/share/vm/gc_implementation/g1/concurrentG1Refine.cpp Wed Sep 08 14:04:18 2010 -0700
+++ b/hotspot/src/share/vm/gc_implementation/g1/concurrentG1Refine.cpp Wed Jul 05 17:21:22 2017 +0200
@@ -339,7 +339,9 @@
return res;
}
-void ConcurrentG1Refine::clean_up_cache(int worker_i, G1RemSet* g1rs) {
+void ConcurrentG1Refine::clean_up_cache(int worker_i,
+ G1RemSet* g1rs,
+ DirtyCardQueue* into_cset_dcq) {
assert(!use_cache(), "cache should be disabled");
int start_idx;
@@ -353,7 +355,19 @@
for (int i = start_idx; i < end_idx; i++) {
jbyte* entry = _hot_cache[i];
if (entry != NULL) {
- g1rs->concurrentRefineOneCard(entry, worker_i);
+ if (g1rs->concurrentRefineOneCard(entry, worker_i, true)) {
+ // 'entry' contains references that point into the current
+ // collection set. We need to record 'entry' in the DCQS
+ // that's used for that purpose.
+ //
+ // The only time we care about recording cards that contain
+ // references that point into the collection set is during
+ // 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(), "not during an evacuation pause");
+ assert(worker_i < (int) DirtyCardQueueSet::num_par_ids(), "incorrect worker id");
+ into_cset_dcq->enqueue(entry);
+ }
}
}
}
--- a/hotspot/src/share/vm/gc_implementation/g1/concurrentG1Refine.hpp Wed Sep 08 14:04:18 2010 -0700
+++ b/hotspot/src/share/vm/gc_implementation/g1/concurrentG1Refine.hpp Wed Jul 05 17:21:22 2017 +0200
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2001, 2009, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2001, 2010, 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
@@ -184,7 +184,7 @@
jbyte* cache_insert(jbyte* card_ptr, bool* defer);
// Process the cached entries.
- void clean_up_cache(int worker_i, G1RemSet* g1rs);
+ void clean_up_cache(int worker_i, G1RemSet* g1rs, DirtyCardQueue* into_cset_dcq);
// Set up for parallel processing of the cards in the hot cache
void clear_hot_cache_claimed_index() {
--- a/hotspot/src/share/vm/gc_implementation/g1/concurrentMark.cpp Wed Sep 08 14:04:18 2010 -0700
+++ b/hotspot/src/share/vm/gc_implementation/g1/concurrentMark.cpp Wed Jul 05 17:21:22 2017 +0200
@@ -2586,9 +2586,6 @@
double end_time = os::elapsedTime();
double elapsed_time_ms = (end_time - start) * 1000.0;
g1h->g1_policy()->record_mark_closure_time(elapsed_time_ms);
- if (PrintGCDetails) {
- gclog_or_tty->print_cr("Mark closure took %5.2f ms.", elapsed_time_ms);
- }
ClearMarksInHRClosure clr(nextMarkBitMap());
g1h->collection_set_iterate(&clr);
--- a/hotspot/src/share/vm/gc_implementation/g1/dirtyCardQueue.cpp Wed Sep 08 14:04:18 2010 -0700
+++ b/hotspot/src/share/vm/gc_implementation/g1/dirtyCardQueue.cpp Wed Jul 05 17:21:22 2017 +0200
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2001, 2009, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2001, 2010, 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
@@ -178,13 +178,14 @@
}
bool DirtyCardQueueSet::
-apply_closure_to_completed_buffer_helper(int worker_i,
+apply_closure_to_completed_buffer_helper(CardTableEntryClosure* cl,
+ int worker_i,
BufferNode* nd) {
if (nd != NULL) {
void **buf = BufferNode::make_buffer_from_node(nd);
size_t index = nd->index();
bool b =
- DirtyCardQueue::apply_closure_to_buffer(_closure, buf,
+ DirtyCardQueue::apply_closure_to_buffer(cl, buf,
index, _sz,
true, worker_i);
if (b) {
@@ -199,15 +200,22 @@
}
}
+bool DirtyCardQueueSet::apply_closure_to_completed_buffer(CardTableEntryClosure* cl,
+ int worker_i,
+ int stop_at,
+ bool during_pause) {
+ assert(!during_pause || stop_at == 0, "Should not leave any completed buffers during a pause");
+ BufferNode* nd = get_completed_buffer(stop_at);
+ bool res = apply_closure_to_completed_buffer_helper(cl, worker_i, nd);
+ if (res) Atomic::inc(&_processed_buffers_rs_thread);
+ return res;
+}
+
bool DirtyCardQueueSet::apply_closure_to_completed_buffer(int worker_i,
int stop_at,
- bool during_pause)
-{
- assert(!during_pause || stop_at == 0, "Should not leave any completed buffers during a pause");
- BufferNode* nd = get_completed_buffer(stop_at);
- bool res = apply_closure_to_completed_buffer_helper(worker_i, nd);
- if (res) Atomic::inc(&_processed_buffers_rs_thread);
- return res;
+ bool during_pause) {
+ return apply_closure_to_completed_buffer(_closure, worker_i,
+ stop_at, during_pause);
}
void DirtyCardQueueSet::apply_closure_to_all_completed_buffers() {
@@ -222,8 +230,8 @@
}
}
-void DirtyCardQueueSet::abandon_logs() {
- assert(SafepointSynchronize::is_at_safepoint(), "Must be at safepoint.");
+// Deallocates any completed log buffers
+void DirtyCardQueueSet::clear() {
BufferNode* buffers_to_delete = NULL;
{
MutexLockerEx x(_cbl_mon, Mutex::_no_safepoint_check_flag);
@@ -242,6 +250,12 @@
buffers_to_delete = nd->next();
deallocate_buffer(BufferNode::make_buffer_from_node(nd));
}
+
+}
+
+void DirtyCardQueueSet::abandon_logs() {
+ assert(SafepointSynchronize::is_at_safepoint(), "Must be at safepoint.");
+ clear();
// Since abandon is done only at safepoints, we can safely manipulate
// these queues.
for (JavaThread* t = Threads::first(); t; t = t->next()) {
--- a/hotspot/src/share/vm/gc_implementation/g1/dirtyCardQueue.hpp Wed Sep 08 14:04:18 2010 -0700
+++ b/hotspot/src/share/vm/gc_implementation/g1/dirtyCardQueue.hpp Wed Jul 05 17:21:22 2017 +0200
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2001, 2009, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2001, 2010, 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
@@ -123,7 +123,21 @@
int stop_at = 0,
bool during_pause = false);
- bool apply_closure_to_completed_buffer_helper(int worker_i,
+ // If there exists some completed buffer, pop it, then apply the
+ // specified closure to all its elements, nulling out those elements
+ // processed. If all elements are processed, returns "true". If no
+ // completed buffers exist, returns false. If a completed buffer exists,
+ // but is only partially completed before a "yield" happens, the
+ // partially completed buffer (with its processed elements set to NULL)
+ // is returned to the completed buffer set, and this call returns false.
+ bool apply_closure_to_completed_buffer(CardTableEntryClosure* cl,
+ int worker_i = 0,
+ int stop_at = 0,
+ bool during_pause = false);
+
+ // Helper routine for the above.
+ bool apply_closure_to_completed_buffer_helper(CardTableEntryClosure* cl,
+ int worker_i,
BufferNode* nd);
BufferNode* get_completed_buffer(int stop_at);
@@ -136,6 +150,9 @@
return &_shared_dirty_card_queue;
}
+ // Deallocate any completed log buffers
+ void clear();
+
// If a full collection is happening, reset partial logs, and ignore
// completed ones: the full collection will make them all irrelevant.
void abandon_logs();
--- a/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp Wed Sep 08 14:04:18 2010 -0700
+++ b/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp Wed Jul 05 17:21:22 2017 +0200
@@ -56,7 +56,12 @@
_sts(sts), _g1rs(g1rs), _cg1r(cg1r), _concurrent(true)
{}
bool do_card_ptr(jbyte* card_ptr, int worker_i) {
- _g1rs->concurrentRefineOneCard(card_ptr, worker_i);
+ bool oops_into_cset = _g1rs->concurrentRefineOneCard(card_ptr, worker_i, false);
+ // This path is executed by the concurrent refine or mutator threads,
+ // concurrently, and so we do not care if card_ptr contains references
+ // that point into the collection set.
+ assert(!oops_into_cset, "should be");
+
if (_concurrent && _sts->should_yield()) {
// Caller will actually yield.
return false;
@@ -1039,29 +1044,56 @@
const size_t capacity_after_gc = capacity();
const size_t free_after_gc = capacity_after_gc - used_after_gc;
+ // This is enforced in arguments.cpp.
+ assert(MinHeapFreeRatio <= MaxHeapFreeRatio,
+ "otherwise the code below doesn't make sense");
+
// We don't have floating point command-line arguments
- const double minimum_free_percentage = (double) MinHeapFreeRatio / 100;
+ const double minimum_free_percentage = (double) MinHeapFreeRatio / 100.0;
const double maximum_used_percentage = 1.0 - minimum_free_percentage;
- const double maximum_free_percentage = (double) MaxHeapFreeRatio / 100;
+ const double maximum_free_percentage = (double) MaxHeapFreeRatio / 100.0;
const double minimum_used_percentage = 1.0 - maximum_free_percentage;
- size_t minimum_desired_capacity = (size_t) (used_after_gc / maximum_used_percentage);
- size_t maximum_desired_capacity = (size_t) (used_after_gc / minimum_used_percentage);
-
- // Don't shrink less than the initial size.
- minimum_desired_capacity =
- MAX2(minimum_desired_capacity,
- collector_policy()->initial_heap_byte_size());
- maximum_desired_capacity =
- MAX2(maximum_desired_capacity,
- collector_policy()->initial_heap_byte_size());
-
- // We are failing here because minimum_desired_capacity is
- assert(used_after_gc <= minimum_desired_capacity, "sanity check");
- assert(minimum_desired_capacity <= maximum_desired_capacity, "sanity check");
+ const size_t min_heap_size = collector_policy()->min_heap_byte_size();
+ const size_t max_heap_size = collector_policy()->max_heap_byte_size();
+
+ // We have to be careful here as these two calculations can overflow
+ // 32-bit size_t's.
+ double used_after_gc_d = (double) used_after_gc;
+ double minimum_desired_capacity_d = used_after_gc_d / maximum_used_percentage;
+ double maximum_desired_capacity_d = used_after_gc_d / minimum_used_percentage;
+
+ // Let's make sure that they are both under the max heap size, which
+ // by default will make them fit into a size_t.
+ double desired_capacity_upper_bound = (double) max_heap_size;
+ minimum_desired_capacity_d = MIN2(minimum_desired_capacity_d,
+ desired_capacity_upper_bound);
+ maximum_desired_capacity_d = MIN2(maximum_desired_capacity_d,
+ desired_capacity_upper_bound);
+
+ // We can now safely turn them into size_t's.
+ size_t minimum_desired_capacity = (size_t) minimum_desired_capacity_d;
+ size_t maximum_desired_capacity = (size_t) maximum_desired_capacity_d;
+
+ // This assert only makes sense here, before we adjust them
+ // with respect to the min and max heap size.
+ assert(minimum_desired_capacity <= maximum_desired_capacity,
+ err_msg("minimum_desired_capacity = "SIZE_FORMAT", "
+ "maximum_desired_capacity = "SIZE_FORMAT,
+ minimum_desired_capacity, maximum_desired_capacity));
+
+ // Should not be greater than the heap max size. No need to adjust
+ // it with respect to the heap min size as it's a lower bound (i.e.,
+ // we'll try to make the capacity larger than it, not smaller).
+ minimum_desired_capacity = MIN2(minimum_desired_capacity, max_heap_size);
+ // Should not be less than the heap min size. No need to adjust it
+ // with respect to the heap max size as it's an upper bound (i.e.,
+ // we'll try to make the capacity smaller than it, not greater).
+ maximum_desired_capacity = MAX2(maximum_desired_capacity, min_heap_size);
if (PrintGC && Verbose) {
- const double free_percentage = ((double)free_after_gc) / capacity();
+ const double free_percentage =
+ (double) free_after_gc / (double) capacity_after_gc;
gclog_or_tty->print_cr("Computing new size after full GC ");
gclog_or_tty->print_cr(" "
" minimum_free_percentage: %6.2f",
@@ -1073,45 +1105,47 @@
" capacity: %6.1fK"
" minimum_desired_capacity: %6.1fK"
" maximum_desired_capacity: %6.1fK",
- capacity() / (double) K,
- minimum_desired_capacity / (double) K,
- maximum_desired_capacity / (double) K);
+ (double) capacity_after_gc / (double) K,
+ (double) minimum_desired_capacity / (double) K,
+ (double) maximum_desired_capacity / (double) K);
gclog_or_tty->print_cr(" "
- " free_after_gc : %6.1fK"
- " used_after_gc : %6.1fK",
- free_after_gc / (double) K,
- used_after_gc / (double) K);
+ " free_after_gc: %6.1fK"
+ " used_after_gc: %6.1fK",
+ (double) free_after_gc / (double) K,
+ (double) used_after_gc / (double) K);
gclog_or_tty->print_cr(" "
" free_percentage: %6.2f",
free_percentage);
}
- if (capacity() < minimum_desired_capacity) {
+ if (capacity_after_gc < minimum_desired_capacity) {
// Don't expand unless it's significant
size_t expand_bytes = minimum_desired_capacity - capacity_after_gc;
expand(expand_bytes);
if (PrintGC && Verbose) {
- gclog_or_tty->print_cr(" expanding:"
+ gclog_or_tty->print_cr(" "
+ " expanding:"
+ " max_heap_size: %6.1fK"
" minimum_desired_capacity: %6.1fK"
" expand_bytes: %6.1fK",
- minimum_desired_capacity / (double) K,
- expand_bytes / (double) K);
+ (double) max_heap_size / (double) K,
+ (double) minimum_desired_capacity / (double) K,
+ (double) expand_bytes / (double) K);
}
// No expansion, now see if we want to shrink
- } else if (capacity() > maximum_desired_capacity) {
+ } else if (capacity_after_gc > maximum_desired_capacity) {
// Capacity too large, compute shrinking size
size_t shrink_bytes = capacity_after_gc - maximum_desired_capacity;
shrink(shrink_bytes);
if (PrintGC && Verbose) {
gclog_or_tty->print_cr(" "
" shrinking:"
- " initSize: %.1fK"
- " maximum_desired_capacity: %.1fK",
- collector_policy()->initial_heap_byte_size() / (double) K,
- maximum_desired_capacity / (double) K);
- gclog_or_tty->print_cr(" "
- " shrink_bytes: %.1fK",
- shrink_bytes / (double) K);
+ " min_heap_size: %6.1fK"
+ " maximum_desired_capacity: %6.1fK"
+ " shrink_bytes: %6.1fK",
+ (double) min_heap_size / (double) K,
+ (double) maximum_desired_capacity / (double) K,
+ (double) shrink_bytes / (double) K);
}
}
}
@@ -1322,6 +1356,7 @@
SharedHeap(policy_),
_g1_policy(policy_),
_dirty_card_queue_set(false),
+ _into_cset_dirty_card_queue_set(false),
_ref_processor(NULL),
_process_strong_tasks(new SubTasksDone(G1H_PS_NumElements)),
_bot_shared(NULL),
@@ -1572,6 +1607,16 @@
Shared_DirtyCardQ_lock,
&JavaThread::dirty_card_queue_set());
}
+
+ // Initialize the card queue set used to hold cards containing
+ // references into the collection set.
+ _into_cset_dirty_card_queue_set.initialize(DirtyCardQ_CBL_mon,
+ DirtyCardQ_FL_lock,
+ -1, // never trigger processing
+ -1, // no limit on length
+ Shared_DirtyCardQ_lock,
+ &JavaThread::dirty_card_queue_set());
+
// In case we're keeping closure specialization stats, initialize those
// counts and that mechanism.
SpecializationStats::clear();
@@ -1603,14 +1648,16 @@
return _g1_committed.byte_size();
}
-void G1CollectedHeap::iterate_dirty_card_closure(bool concurrent,
+void G1CollectedHeap::iterate_dirty_card_closure(CardTableEntryClosure* cl,
+ DirtyCardQueue* into_cset_dcq,
+ bool concurrent,
int worker_i) {
// Clean cards in the hot card cache
- concurrent_g1_refine()->clean_up_cache(worker_i, g1_rem_set());
+ concurrent_g1_refine()->clean_up_cache(worker_i, g1_rem_set(), into_cset_dcq);
DirtyCardQueueSet& dcqs = JavaThread::dirty_card_queue_set();
int n_completed_buffers = 0;
- while (dcqs.apply_closure_to_completed_buffer(worker_i, 0, true)) {
+ while (dcqs.apply_closure_to_completed_buffer(cl, worker_i, 0, true)) {
n_completed_buffers++;
}
g1_policy()->record_update_rs_processed_buffers(worker_i,
@@ -2147,9 +2194,12 @@
}
}
-HeapWord* G1CollectedHeap::allocate_new_tlab(size_t size) {
+HeapWord* G1CollectedHeap::allocate_new_tlab(size_t word_size) {
+ assert(!isHumongous(word_size),
+ err_msg("a TLAB should not be of humongous size, "
+ "word_size = "SIZE_FORMAT, word_size));
bool dummy;
- return G1CollectedHeap::mem_allocate(size, false, true, &dummy);
+ return G1CollectedHeap::mem_allocate(word_size, false, true, &dummy);
}
bool G1CollectedHeap::allocs_are_zero_filled() {
@@ -2692,6 +2742,35 @@
}
};
+#if TASKQUEUE_STATS
+void G1CollectedHeap::print_taskqueue_stats_hdr(outputStream* const st) {
+ st->print_raw_cr("GC Task Stats");
+ st->print_raw("thr "); TaskQueueStats::print_header(1, st); st->cr();
+ st->print_raw("--- "); TaskQueueStats::print_header(2, st); st->cr();
+}
+
+void G1CollectedHeap::print_taskqueue_stats(outputStream* const st) const {
+ print_taskqueue_stats_hdr(st);
+
+ TaskQueueStats totals;
+ const int n = MAX2(workers()->total_workers(), 1);
+ for (int i = 0; i < n; ++i) {
+ st->print("%3d ", i); task_queue(i)->stats.print(st); st->cr();
+ totals += task_queue(i)->stats;
+ }
+ st->print_raw("tot "); totals.print(st); st->cr();
+
+ DEBUG_ONLY(totals.verify());
+}
+
+void G1CollectedHeap::reset_taskqueue_stats() {
+ const int n = MAX2(workers()->total_workers(), 1);
+ for (int i = 0; i < n; ++i) {
+ task_queue(i)->stats.reset();
+ }
+}
+#endif // TASKQUEUE_STATS
+
void
G1CollectedHeap::do_collection_pause_at_safepoint(double target_pause_time_ms) {
if (GC_locker::check_active_before_gc()) {
@@ -2825,93 +2904,57 @@
g1_policy()->print_collection_set(g1_policy()->inc_cset_head(), gclog_or_tty);
#endif // YOUNG_LIST_VERBOSE
- // Now choose the CS. We may abandon a pause if we find no
- // region that will fit in the MMU pause.
- bool abandoned = g1_policy()->choose_collection_set(target_pause_time_ms);
+ g1_policy()->choose_collection_set(target_pause_time_ms);
// Nothing to do if we were unable to choose a collection set.
- if (!abandoned) {
#if G1_REM_SET_LOGGING
- gclog_or_tty->print_cr("\nAfter pause, heap:");
- print();
+ gclog_or_tty->print_cr("\nAfter pause, heap:");
+ print();
#endif
- PrepareForRSScanningClosure prepare_for_rs_scan;
- collection_set_iterate(&prepare_for_rs_scan);
-
- setup_surviving_young_words();
-
- // Set up the gc allocation regions.
- get_gc_alloc_regions();
-
- // Actually do the work...
- evacuate_collection_set();
-
- free_collection_set(g1_policy()->collection_set());
- g1_policy()->clear_collection_set();
-
- cleanup_surviving_young_words();
-
- // Start a new incremental collection set for the next pause.
- g1_policy()->start_incremental_cset_building();
-
- // Clear the _cset_fast_test bitmap in anticipation of adding
- // regions to the incremental collection set for the next
- // evacuation pause.
- clear_cset_fast_test();
-
- if (g1_policy()->in_young_gc_mode()) {
- _young_list->reset_sampled_info();
-
- // Don't check the whole heap at this point as the
- // GC alloc regions from this pause have been tagged
- // as survivors and moved on to the survivor list.
- // Survivor regions will fail the !is_young() check.
- assert(check_young_list_empty(false /* check_heap */),
- "young list should be empty");
+ PrepareForRSScanningClosure prepare_for_rs_scan;
+ collection_set_iterate(&prepare_for_rs_scan);
+
+ setup_surviving_young_words();
+
+ // Set up the gc allocation regions.
+ get_gc_alloc_regions();
+
+ // Actually do the work...
+ evacuate_collection_set();
+
+ free_collection_set(g1_policy()->collection_set());
+ g1_policy()->clear_collection_set();
+
+ cleanup_surviving_young_words();
+
+ // Start a new incremental collection set for the next pause.
+ g1_policy()->start_incremental_cset_building();
+
+ // Clear the _cset_fast_test bitmap in anticipation of adding
+ // regions to the incremental collection set for the next
+ // evacuation pause.
+ clear_cset_fast_test();
+
+ if (g1_policy()->in_young_gc_mode()) {
+ _young_list->reset_sampled_info();
+
+ // Don't check the whole heap at this point as the
+ // GC alloc regions from this pause have been tagged
+ // as survivors and moved on to the survivor list.
+ // Survivor regions will fail the !is_young() check.
+ assert(check_young_list_empty(false /* check_heap */),
+ "young list should be empty");
#if YOUNG_LIST_VERBOSE
- gclog_or_tty->print_cr("Before recording survivors.\nYoung List:");
- _young_list->print();
+ gclog_or_tty->print_cr("Before recording survivors.\nYoung List:");
+ _young_list->print();
#endif // YOUNG_LIST_VERBOSE
- g1_policy()->record_survivor_regions(_young_list->survivor_length(),
+ g1_policy()->record_survivor_regions(_young_list->survivor_length(),
_young_list->first_survivor_region(),
_young_list->last_survivor_region());
- _young_list->reset_auxilary_lists();
- }
- } else {
- // We have abandoned the current collection. This can only happen
- // if we're not doing young or partially young collections, and
- // we didn't find an old region that we're able to collect within
- // the allowed time.
-
- assert(g1_policy()->collection_set() == NULL, "should be");
- assert(_young_list->length() == 0, "because it should be");
-
- // This should be a no-op.
- abandon_collection_set(g1_policy()->inc_cset_head());
-
- g1_policy()->clear_incremental_cset();
- g1_policy()->stop_incremental_cset_building();
-
- // Start a new incremental collection set for the next pause.
- g1_policy()->start_incremental_cset_building();
-
- // Clear the _cset_fast_test bitmap in anticipation of adding
- // regions to the incremental collection set for the next
- // evacuation pause.
- clear_cset_fast_test();
-
- // This looks confusing, because the DPT should really be empty
- // at this point -- since we have not done any collection work,
- // there should not be any derived pointers in the table to update;
- // however, there is some additional state in the DPT which is
- // reset at the end of the (null) "gc" here via the following call.
- // A better approach might be to split off that state resetting work
- // into a separate method that asserts that the DPT is empty and call
- // that here. That is deferred for now.
- COMPILER2_PRESENT(DerivedPointerTable::update_pointers());
+ _young_list->reset_auxilary_lists();
}
if (evacuation_failed()) {
@@ -2945,7 +2988,7 @@
double end_time_sec = os::elapsedTime();
double pause_time_ms = (end_time_sec - start_time_sec) * MILLIUNITS;
g1_policy()->record_pause_time_ms(pause_time_ms);
- g1_policy()->record_collection_pause_end(abandoned);
+ g1_policy()->record_collection_pause_end();
assert(regions_accounted_for(), "Region leakage.");
@@ -2988,6 +3031,9 @@
}
}
+ TASKQUEUE_STATS_ONLY(if (ParallelGCVerbose) print_taskqueue_stats());
+ TASKQUEUE_STATS_ONLY(reset_taskqueue_stats());
+
if (PrintHeapAtGC) {
Universe::print_heap_after_gc();
}
@@ -3346,25 +3392,6 @@
}
};
-class UpdateRSetImmediate : public OopsInHeapRegionClosure {
-private:
- G1CollectedHeap* _g1;
- G1RemSet* _g1_rem_set;
-public:
- UpdateRSetImmediate(G1CollectedHeap* g1) :
- _g1(g1), _g1_rem_set(g1->g1_rem_set()) {}
-
- virtual void do_oop(narrowOop* p) { do_oop_work(p); }
- virtual void do_oop( oop* p) { do_oop_work(p); }
- template <class T> void do_oop_work(T* p) {
- assert(_from->is_in_reserved(p), "paranoia");
- T heap_oop = oopDesc::load_heap_oop(p);
- if (!oopDesc::is_null(heap_oop) && !_from->is_survivor()) {
- _g1_rem_set->par_write_ref(_from, p, 0);
- }
- }
-};
-
class UpdateRSetDeferred : public OopsInHeapRegionClosure {
private:
G1CollectedHeap* _g1;
@@ -3389,8 +3416,6 @@
}
};
-
-
class RemoveSelfPointerClosure: public ObjectClosure {
private:
G1CollectedHeap* _g1;
@@ -3453,7 +3478,7 @@
};
void G1CollectedHeap::remove_self_forwarding_pointers() {
- UpdateRSetImmediate immediate_update(_g1h);
+ UpdateRSetImmediate immediate_update(_g1h->g1_rem_set());
DirtyCardQueue dcq(&_g1h->dirty_card_queue_set());
UpdateRSetDeferred deferred_update(_g1h, &dcq);
OopsInHeapRegionClosure *cl;
@@ -3583,7 +3608,7 @@
if (!r->evacuation_failed()) {
r->set_evacuation_failed(true);
if (G1PrintHeapRegions) {
- gclog_or_tty->print("evacuation failed in heap region "PTR_FORMAT" "
+ gclog_or_tty->print("overflow in heap region "PTR_FORMAT" "
"["PTR_FORMAT","PTR_FORMAT")\n",
r, r->bottom(), r->end());
}
@@ -3617,6 +3642,10 @@
HeapWord* G1CollectedHeap::par_allocate_during_gc(GCAllocPurpose purpose,
size_t word_size) {
+ assert(!isHumongous(word_size),
+ err_msg("we should not be seeing humongous allocation requests "
+ "during GC, word_size = "SIZE_FORMAT, word_size));
+
HeapRegion* alloc_region = _gc_alloc_regions[purpose];
// let the caller handle alloc failure
if (alloc_region == NULL) return NULL;
@@ -3649,6 +3678,10 @@
HeapRegion* alloc_region,
bool par,
size_t word_size) {
+ assert(!isHumongous(word_size),
+ err_msg("we should not be seeing humongous allocation requests "
+ "during GC, word_size = "SIZE_FORMAT, word_size));
+
HeapWord* block = NULL;
// In the parallel case, a previous thread to obtain the lock may have
// already assigned a new gc_alloc_region.
@@ -3754,10 +3787,6 @@
_surviving_alloc_buffer(g1h->desired_plab_sz(GCAllocForSurvived)),
_tenured_alloc_buffer(g1h->desired_plab_sz(GCAllocForTenured)),
_age_table(false),
-#if G1_DETAILED_STATS
- _pushes(0), _pops(0), _steals(0),
- _steal_attempts(0), _overflow_pushes(0),
-#endif
_strong_roots_time(0), _term_time(0),
_alloc_buffer_waste(0), _undo_waste(0)
{
@@ -3777,14 +3806,41 @@
_surviving_young_words = _surviving_young_words_base + PADDING_ELEM_NUM;
memset(_surviving_young_words, 0, real_length * sizeof(size_t));
- _overflowed_refs = new OverflowQueue(10);
-
_alloc_buffers[GCAllocForSurvived] = &_surviving_alloc_buffer;
_alloc_buffers[GCAllocForTenured] = &_tenured_alloc_buffer;
_start = os::elapsedTime();
}
+void
+G1ParScanThreadState::print_termination_stats_hdr(outputStream* const st)
+{
+ st->print_raw_cr("GC Termination Stats");
+ st->print_raw_cr(" elapsed --strong roots-- -------termination-------"
+ " ------waste (KiB)------");
+ st->print_raw_cr("thr ms ms % ms % attempts"
+ " total alloc undo");
+ st->print_raw_cr("--- --------- --------- ------ --------- ------ --------"
+ " ------- ------- -------");
+}
+
+void
+G1ParScanThreadState::print_termination_stats(int i,
+ outputStream* const st) const
+{
+ const double elapsed_ms = elapsed_time() * 1000.0;
+ const double s_roots_ms = strong_roots_time() * 1000.0;
+ const double term_ms = term_time() * 1000.0;
+ st->print_cr("%3d %9.2f %9.2f %6.2f "
+ "%9.2f %6.2f " SIZE_FORMAT_W(8) " "
+ SIZE_FORMAT_W(7) " " SIZE_FORMAT_W(7) " " SIZE_FORMAT_W(7),
+ i, elapsed_ms, s_roots_ms, s_roots_ms * 100 / elapsed_ms,
+ term_ms, term_ms * 100 / elapsed_ms, term_attempts(),
+ (alloc_buffer_waste() + undo_waste()) * HeapWordSize / K,
+ alloc_buffer_waste() * HeapWordSize / K,
+ undo_waste() * HeapWordSize / K);
+}
+
G1ParClosureSuper::G1ParClosureSuper(G1CollectedHeap* g1, G1ParScanThreadState* par_scan_state) :
_g1(g1), _g1_rem(_g1->g1_rem_set()), _cm(_g1->concurrent_mark()),
_par_scan_state(par_scan_state) { }
@@ -3991,12 +4047,9 @@
G1ParScanThreadState* pss = par_scan_state();
while (true) {
pss->trim_queue();
- IF_G1_DETAILED_STATS(pss->note_steal_attempt());
StarTask stolen_task;
if (queues()->steal(pss->queue_num(), pss->hash_seed(), stolen_task)) {
- IF_G1_DETAILED_STATS(pss->note_steal());
-
// slightly paranoid tests; I'm trying to catch potential
// problems before we go into push_on_queue to know where the
// problem is coming from
@@ -4115,35 +4168,9 @@
// Clean up any par-expanded rem sets.
HeapRegionRemSet::par_cleanup();
- MutexLocker x(stats_lock());
if (ParallelGCVerbose) {
- gclog_or_tty->print("Thread %d complete:\n", i);
-#if G1_DETAILED_STATS
- gclog_or_tty->print(" Pushes: %7d Pops: %7d Overflows: %7d Steals %7d (in %d attempts)\n",
- pss.pushes(),
- pss.pops(),
- pss.overflow_pushes(),
- pss.steals(),
- pss.steal_attempts());
-#endif
- double elapsed = pss.elapsed();
- double strong_roots = pss.strong_roots_time();
- double term = pss.term_time();
- gclog_or_tty->print(" Elapsed: %7.2f ms.\n"
- " Strong roots: %7.2f ms (%6.2f%%)\n"
- " Termination: %7.2f ms (%6.2f%%) "
- "(in "SIZE_FORMAT" entries)\n",
- elapsed * 1000.0,
- strong_roots * 1000.0, (strong_roots*100.0/elapsed),
- term * 1000.0, (term*100.0/elapsed),
- pss.term_attempts());
- size_t total_waste = pss.alloc_buffer_waste() + pss.undo_waste();
- gclog_or_tty->print(" Waste: %8dK\n"
- " Alloc Buffer: %8dK\n"
- " Undo: %8dK\n",
- (total_waste * HeapWordSize) / K,
- (pss.alloc_buffer_waste() * HeapWordSize) / K,
- (pss.undo_waste() * HeapWordSize) / K);
+ MutexLocker x(stats_lock());
+ pss.print_termination_stats(i);
}
assert(pss.refs_to_scan() == 0, "Task queue should be empty");
@@ -4260,6 +4287,7 @@
if (ParallelGCThreads > 0) {
// The individual threads will set their evac-failure closures.
StrongRootsScope srs(this);
+ if (ParallelGCVerbose) G1ParScanThreadState::print_termination_stats_hdr();
workers()->run_task(&g1_par_task);
} else {
StrongRootsScope srs(this);
@@ -4293,7 +4321,7 @@
if (evacuation_failed()) {
remove_self_forwarding_pointers();
if (PrintGCDetails) {
- gclog_or_tty->print(" (evacuation failed)");
+ gclog_or_tty->print(" (to-space overflow)");
} else if (PrintGC) {
gclog_or_tty->print("--");
}
--- a/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.hpp Wed Sep 08 14:04:18 2010 -0700
+++ b/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.hpp Wed Jul 05 17:21:22 2017 +0200
@@ -46,17 +46,7 @@
class ConcurrentG1Refine;
class ConcurrentZFThread;
-// If want to accumulate detailed statistics on work queues
-// turn this on.
-#define G1_DETAILED_STATS 0
-
-#if G1_DETAILED_STATS
-# define IF_G1_DETAILED_STATS(code) code
-#else
-# define IF_G1_DETAILED_STATS(code)
-#endif
-
-typedef GenericTaskQueue<StarTask> RefToScanQueue;
+typedef OverflowTaskQueue<StarTask> RefToScanQueue;
typedef GenericTaskQueueSet<RefToScanQueue> RefToScanQueueSet;
typedef int RegionIdx_t; // needs to hold [ 0..max_regions() )
@@ -471,6 +461,12 @@
virtual void shrink(size_t expand_bytes);
void shrink_helper(size_t expand_bytes);
+ #if TASKQUEUE_STATS
+ static void print_taskqueue_stats_hdr(outputStream* const st = gclog_or_tty);
+ void print_taskqueue_stats(outputStream* const st = gclog_or_tty) const;
+ void reset_taskqueue_stats();
+ #endif // TASKQUEUE_STATS
+
// Do an incremental collection: identify a collection set, and evacuate
// its live objects elsewhere.
virtual void do_collection_pause();
@@ -505,6 +501,12 @@
// A function to check the consistency of dirty card logs.
void check_ct_logs_at_safepoint();
+ // A DirtyCardQueueSet that is used to hold cards that contain
+ // references into the current collection set. This is used to
+ // update the remembered sets of the regions in the collection
+ // set in the event of an evacuation failure.
+ DirtyCardQueueSet _into_cset_dirty_card_queue_set;
+
// After a collection pause, make the regions in the CS into free
// regions.
void free_collection_set(HeapRegion* cs_head);
@@ -656,11 +658,18 @@
public:
void set_refine_cte_cl_concurrency(bool concurrent);
- RefToScanQueue *task_queue(int i);
+ RefToScanQueue *task_queue(int i) const;
// A set of cards where updates happened during the GC
DirtyCardQueueSet& dirty_card_queue_set() { return _dirty_card_queue_set; }
+ // A DirtyCardQueueSet that is used to hold cards that contain
+ // references into the current collection set. This is used to
+ // update the remembered sets of the regions in the collection
+ // set in the event of an evacuation failure.
+ DirtyCardQueueSet& into_cset_dirty_card_queue_set()
+ { return _into_cset_dirty_card_queue_set; }
+
// Create a G1CollectedHeap with the specified policy.
// Must call the initialize method afterwards.
// May not return if something goes wrong.
@@ -715,7 +724,9 @@
OrderAccess::fence();
}
- void iterate_dirty_card_closure(bool concurrent, int worker_i);
+ void iterate_dirty_card_closure(CardTableEntryClosure* cl,
+ DirtyCardQueue* into_cset_dcq,
+ bool concurrent, int worker_i);
// The shared block offset table array.
G1BlockOffsetSharedArray* bot_shared() const { return _bot_shared; }
@@ -1021,7 +1032,7 @@
virtual bool supports_tlab_allocation() const;
virtual size_t tlab_capacity(Thread* thr) const;
virtual size_t unsafe_max_tlab_alloc(Thread* thr) const;
- virtual HeapWord* allocate_new_tlab(size_t size);
+ virtual HeapWord* allocate_new_tlab(size_t word_size);
// Can a compiler initialize a new object without store barriers?
// This permission only extends from the creation of a new object
@@ -1564,9 +1575,6 @@
CardTableModRefBS* _ct_bs;
G1RemSet* _g1_rem;
- typedef GrowableArray<StarTask> OverflowQueue;
- OverflowQueue* _overflowed_refs;
-
G1ParGCAllocBuffer _surviving_alloc_buffer;
G1ParGCAllocBuffer _tenured_alloc_buffer;
G1ParGCAllocBuffer* _alloc_buffers[GCAllocPurposeCount];
@@ -1583,10 +1591,6 @@
int _queue_num;
size_t _term_attempts;
-#if G1_DETAILED_STATS
- int _pushes, _pops, _steals, _steal_attempts;
- int _overflow_pushes;
-#endif
double _start;
double _start_strong_roots;
@@ -1600,7 +1604,7 @@
// this points into the array, as we use the first few entries for padding
size_t* _surviving_young_words;
-#define PADDING_ELEM_NUM (64 / sizeof(size_t))
+#define PADDING_ELEM_NUM (DEFAULT_CACHE_LINE_SIZE / sizeof(size_t))
void add_to_alloc_buffer_waste(size_t waste) { _alloc_buffer_waste += waste; }
@@ -1635,15 +1639,14 @@
}
RefToScanQueue* refs() { return _refs; }
- OverflowQueue* overflowed_refs() { return _overflowed_refs; }
ageTable* age_table() { return &_age_table; }
G1ParGCAllocBuffer* alloc_buffer(GCAllocPurpose purpose) {
return _alloc_buffers[purpose];
}
- size_t alloc_buffer_waste() { return _alloc_buffer_waste; }
- size_t undo_waste() { return _undo_waste; }
+ size_t alloc_buffer_waste() const { return _alloc_buffer_waste; }
+ size_t undo_waste() const { return _undo_waste; }
template <class T> void push_on_queue(T* ref) {
assert(ref != NULL, "invariant");
@@ -1656,12 +1659,7 @@
assert(_g1h->obj_in_cs(p), "Should be in CS");
}
#endif
- if (!refs()->push(ref)) {
- overflowed_refs()->push(ref);
- IF_G1_DETAILED_STATS(note_overflow_push());
- } else {
- IF_G1_DETAILED_STATS(note_push());
- }
+ refs()->push(ref);
}
void pop_from_queue(StarTask& ref) {
@@ -1672,7 +1670,6 @@
_g1h->is_in_g1_reserved(ref.is_narrow() ? oopDesc::load_decode_heap_oop((narrowOop*)ref)
: oopDesc::load_decode_heap_oop((oop*)ref)),
"invariant");
- IF_G1_DETAILED_STATS(note_pop());
} else {
StarTask null_task;
ref = null_task;
@@ -1680,7 +1677,8 @@
}
void pop_from_overflow_queue(StarTask& ref) {
- StarTask new_ref = overflowed_refs()->pop();
+ StarTask new_ref;
+ refs()->pop_overflow(new_ref);
assert((oop*)new_ref != NULL, "pop() from a local non-empty stack");
assert(UseCompressedOops || !new_ref.is_narrow(), "Error");
assert(has_partial_array_mask((oop*)new_ref) ||
@@ -1690,8 +1688,8 @@
ref = new_ref;
}
- int refs_to_scan() { return refs()->size(); }
- int overflowed_refs_to_scan() { return overflowed_refs()->length(); }
+ int refs_to_scan() { return refs()->size(); }
+ int overflowed_refs_to_scan() { return refs()->overflow_stack()->length(); }
template <class T> void update_rs(HeapRegion* from, T* p, int tid) {
if (G1DeferredRSUpdate) {
@@ -1760,30 +1758,16 @@
int* hash_seed() { return &_hash_seed; }
int queue_num() { return _queue_num; }
- size_t term_attempts() { return _term_attempts; }
+ size_t term_attempts() const { return _term_attempts; }
void note_term_attempt() { _term_attempts++; }
-#if G1_DETAILED_STATS
- int pushes() { return _pushes; }
- int pops() { return _pops; }
- int steals() { return _steals; }
- int steal_attempts() { return _steal_attempts; }
- int overflow_pushes() { return _overflow_pushes; }
-
- void note_push() { _pushes++; }
- void note_pop() { _pops++; }
- void note_steal() { _steals++; }
- void note_steal_attempt() { _steal_attempts++; }
- void note_overflow_push() { _overflow_pushes++; }
-#endif
-
void start_strong_roots() {
_start_strong_roots = os::elapsedTime();
}
void end_strong_roots() {
_strong_roots_time += (os::elapsedTime() - _start_strong_roots);
}
- double strong_roots_time() { return _strong_roots_time; }
+ double strong_roots_time() const { return _strong_roots_time; }
void start_term_time() {
note_term_attempt();
@@ -1792,12 +1776,17 @@
void end_term_time() {
_term_time += (os::elapsedTime() - _start_term);
}
- double term_time() { return _term_time; }
+ double term_time() const { return _term_time; }
- double elapsed() {
+ double elapsed_time() const {
return os::elapsedTime() - _start;
}
+ static void
+ print_termination_stats_hdr(outputStream* const st = gclog_or_tty);
+ void
+ print_termination_stats(int i, outputStream* const st = gclog_or_tty) const;
+
size_t* surviving_young_words() {
// We add on to hide entry 0 which accumulates surviving words for
// age -1 regions (i.e. non-young ones)
--- a/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.inline.hpp Wed Sep 08 14:04:18 2010 -0700
+++ b/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.inline.hpp Wed Jul 05 17:21:22 2017 +0200
@@ -57,8 +57,9 @@
assert( SafepointSynchronize::is_at_safepoint() ||
Heap_lock->owned_by_self(), "pre-condition of the call" );
- if (_cur_alloc_region != NULL) {
-
+ // All humongous allocation requests should go through the slow path in
+ // attempt_allocation_slow().
+ if (!isHumongous(word_size) && _cur_alloc_region != NULL) {
// If this allocation causes a region to become non empty,
// then we need to update our free_regions count.
@@ -69,23 +70,23 @@
} else {
res = _cur_alloc_region->allocate(word_size);
}
- }
- if (res != NULL) {
- if (!SafepointSynchronize::is_at_safepoint()) {
- assert( Heap_lock->owned_by_self(), "invariant" );
- Heap_lock->unlock();
+
+ if (res != NULL) {
+ if (!SafepointSynchronize::is_at_safepoint()) {
+ assert( Heap_lock->owned_by_self(), "invariant" );
+ Heap_lock->unlock();
+ }
+ return res;
}
- return res;
}
// attempt_allocation_slow will also unlock the heap lock when appropriate.
return attempt_allocation_slow(word_size, permit_collection_pause);
}
-inline RefToScanQueue* G1CollectedHeap::task_queue(int i) {
+inline RefToScanQueue* G1CollectedHeap::task_queue(int i) const {
return _task_queues->queue(i);
}
-
inline bool G1CollectedHeap::isMarkedPrev(oop obj) const {
return _cm->prevMarkBitMap()->isMarked((HeapWord *)obj);
}
--- a/hotspot/src/share/vm/gc_implementation/g1/g1CollectorPolicy.cpp Wed Sep 08 14:04:18 2010 -0700
+++ b/hotspot/src/share/vm/gc_implementation/g1/g1CollectorPolicy.cpp Wed Jul 05 17:21:22 2017 +0200
@@ -88,7 +88,6 @@
_all_mod_union_times_ms(new NumberSeq()),
_summary(new Summary()),
- _abandoned_summary(new AbandonedSummary()),
#ifndef PRODUCT
_cur_clear_ct_time_ms(0.0),
@@ -238,7 +237,6 @@
_par_last_update_rs_processed_buffers = new double[_parallel_gc_threads];
_par_last_scan_rs_times_ms = new double[_parallel_gc_threads];
- _par_last_scan_new_refs_times_ms = new double[_parallel_gc_threads];
_par_last_obj_copy_times_ms = new double[_parallel_gc_threads];
@@ -842,7 +840,6 @@
_par_last_update_rs_times_ms[i] = -1234.0;
_par_last_update_rs_processed_buffers[i] = -1234.0;
_par_last_scan_rs_times_ms[i] = -1234.0;
- _par_last_scan_new_refs_times_ms[i] = -1234.0;
_par_last_obj_copy_times_ms[i] = -1234.0;
_par_last_termination_times_ms[i] = -1234.0;
_par_last_termination_attempts[i] = -1234.0;
@@ -1126,7 +1123,7 @@
// Anything below that is considered to be zero
#define MIN_TIMER_GRANULARITY 0.0000001
-void G1CollectorPolicy::record_collection_pause_end(bool abandoned) {
+void G1CollectorPolicy::record_collection_pause_end() {
double end_time_sec = os::elapsedTime();
double elapsed_ms = _last_pause_time_ms;
bool parallel = ParallelGCThreads > 0;
@@ -1136,7 +1133,7 @@
size_t cur_used_bytes = _g1->used();
assert(cur_used_bytes == _g1->recalculate_used(), "It should!");
bool last_pause_included_initial_mark = false;
- bool update_stats = !abandoned && !_g1->evacuation_failed();
+ bool update_stats = !_g1->evacuation_failed();
#ifndef PRODUCT
if (G1YoungSurvRateVerbose) {
@@ -1275,12 +1272,7 @@
gclog_or_tty->print_cr(" Recording collection pause(%d)", _n_pauses);
}
- PauseSummary* summary;
- if (abandoned) {
- summary = _abandoned_summary;
- } else {
- summary = _summary;
- }
+ PauseSummary* summary = _summary;
double ext_root_scan_time = avg_value(_par_last_ext_root_scan_times_ms);
double mark_stack_scan_time = avg_value(_par_last_mark_stack_scan_times_ms);
@@ -1348,61 +1340,58 @@
double other_time_ms = elapsed_ms;
- if (!abandoned) {
- if (_satb_drain_time_set)
- other_time_ms -= _cur_satb_drain_time_ms;
-
- if (parallel)
- other_time_ms -= _cur_collection_par_time_ms + _cur_clear_ct_time_ms;
- else
- other_time_ms -=
- update_rs_time +
- ext_root_scan_time + mark_stack_scan_time +
- scan_rs_time + obj_copy_time;
+ if (_satb_drain_time_set) {
+ other_time_ms -= _cur_satb_drain_time_ms;
+ }
+
+ if (parallel) {
+ other_time_ms -= _cur_collection_par_time_ms + _cur_clear_ct_time_ms;
+ } else {
+ other_time_ms -=
+ update_rs_time +
+ ext_root_scan_time + mark_stack_scan_time +
+ scan_rs_time + obj_copy_time;
}
if (PrintGCDetails) {
- gclog_or_tty->print_cr("%s%s, %1.8lf secs]",
- abandoned ? " (abandoned)" : "",
+ gclog_or_tty->print_cr("%s, %1.8lf secs]",
(last_pause_included_initial_mark) ? " (initial-mark)" : "",
elapsed_ms / 1000.0);
- if (!abandoned) {
- if (_satb_drain_time_set) {
- print_stats(1, "SATB Drain Time", _cur_satb_drain_time_ms);
- }
- if (_last_satb_drain_processed_buffers >= 0) {
- print_stats(2, "Processed Buffers", _last_satb_drain_processed_buffers);
- }
- if (parallel) {
- print_stats(1, "Parallel Time", _cur_collection_par_time_ms);
- print_par_stats(2, "GC Worker Start Time",
- _par_last_gc_worker_start_times_ms, false);
- print_par_stats(2, "Update RS", _par_last_update_rs_times_ms);
- print_par_sizes(3, "Processed Buffers",
- _par_last_update_rs_processed_buffers, true);
- print_par_stats(2, "Ext Root Scanning",
- _par_last_ext_root_scan_times_ms);
- print_par_stats(2, "Mark Stack Scanning",
- _par_last_mark_stack_scan_times_ms);
- print_par_stats(2, "Scan RS", _par_last_scan_rs_times_ms);
- print_par_stats(2, "Object Copy", _par_last_obj_copy_times_ms);
- print_par_stats(2, "Termination", _par_last_termination_times_ms);
- print_par_sizes(3, "Termination Attempts",
- _par_last_termination_attempts, true);
- print_par_stats(2, "GC Worker End Time",
- _par_last_gc_worker_end_times_ms, false);
- print_stats(2, "Other", parallel_other_time);
- print_stats(1, "Clear CT", _cur_clear_ct_time_ms);
- } else {
- print_stats(1, "Update RS", update_rs_time);
- print_stats(2, "Processed Buffers",
- (int)update_rs_processed_buffers);
- print_stats(1, "Ext Root Scanning", ext_root_scan_time);
- print_stats(1, "Mark Stack Scanning", mark_stack_scan_time);
- print_stats(1, "Scan RS", scan_rs_time);
- print_stats(1, "Object Copying", obj_copy_time);
- }
+ if (_satb_drain_time_set) {
+ print_stats(1, "SATB Drain Time", _cur_satb_drain_time_ms);
+ }
+ if (_last_satb_drain_processed_buffers >= 0) {
+ print_stats(2, "Processed Buffers", _last_satb_drain_processed_buffers);
+ }
+ if (parallel) {
+ print_stats(1, "Parallel Time", _cur_collection_par_time_ms);
+ print_par_stats(2, "GC Worker Start Time",
+ _par_last_gc_worker_start_times_ms, false);
+ print_par_stats(2, "Update RS", _par_last_update_rs_times_ms);
+ print_par_sizes(3, "Processed Buffers",
+ _par_last_update_rs_processed_buffers, true);
+ print_par_stats(2, "Ext Root Scanning",
+ _par_last_ext_root_scan_times_ms);
+ print_par_stats(2, "Mark Stack Scanning",
+ _par_last_mark_stack_scan_times_ms);
+ print_par_stats(2, "Scan RS", _par_last_scan_rs_times_ms);
+ print_par_stats(2, "Object Copy", _par_last_obj_copy_times_ms);
+ print_par_stats(2, "Termination", _par_last_termination_times_ms);
+ print_par_sizes(3, "Termination Attempts",
+ _par_last_termination_attempts, true);
+ print_par_stats(2, "GC Worker End Time",
+ _par_last_gc_worker_end_times_ms, false);
+ print_stats(2, "Other", parallel_other_time);
+ print_stats(1, "Clear CT", _cur_clear_ct_time_ms);
+ } else {
+ print_stats(1, "Update RS", update_rs_time);
+ print_stats(2, "Processed Buffers",
+ (int)update_rs_processed_buffers);
+ print_stats(1, "Ext Root Scanning", ext_root_scan_time);
+ print_stats(1, "Mark Stack Scanning", mark_stack_scan_time);
+ print_stats(1, "Scan RS", scan_rs_time);
+ print_stats(1, "Object Copying", obj_copy_time);
}
#ifndef PRODUCT
print_stats(1, "Cur Clear CC", _cur_clear_cc_time_ms);
@@ -2178,33 +2167,27 @@
print_summary(1, "Other", summary->get_other_seq());
{
NumberSeq calc_other_times_ms;
- if (body_summary != NULL) {
- // not abandoned
- if (parallel) {
- // parallel
- NumberSeq* other_parts[] = {
- body_summary->get_satb_drain_seq(),
- body_summary->get_parallel_seq(),
- body_summary->get_clear_ct_seq()
- };
- calc_other_times_ms = NumberSeq(summary->get_total_seq(),
- 3, other_parts);
- } else {
- // serial
- NumberSeq* other_parts[] = {
- body_summary->get_satb_drain_seq(),
- body_summary->get_update_rs_seq(),
- body_summary->get_ext_root_scan_seq(),
- body_summary->get_mark_stack_scan_seq(),
- body_summary->get_scan_rs_seq(),
- body_summary->get_obj_copy_seq()
- };
- calc_other_times_ms = NumberSeq(summary->get_total_seq(),
- 7, other_parts);
- }
+ if (parallel) {
+ // parallel
+ NumberSeq* other_parts[] = {
+ body_summary->get_satb_drain_seq(),
+ body_summary->get_parallel_seq(),
+ body_summary->get_clear_ct_seq()
+ };
+ calc_other_times_ms = NumberSeq(summary->get_total_seq(),
+ 3, other_parts);
} else {
- // abandoned
- calc_other_times_ms = NumberSeq();
+ // serial
+ NumberSeq* other_parts[] = {
+ body_summary->get_satb_drain_seq(),
+ body_summary->get_update_rs_seq(),
+ body_summary->get_ext_root_scan_seq(),
+ body_summary->get_mark_stack_scan_seq(),
+ body_summary->get_scan_rs_seq(),
+ body_summary->get_obj_copy_seq()
+ };
+ calc_other_times_ms = NumberSeq(summary->get_total_seq(),
+ 7, other_parts);
}
check_other_times(1, summary->get_other_seq(), &calc_other_times_ms);
}
@@ -2215,20 +2198,6 @@
gclog_or_tty->print_cr("");
}
-void
-G1CollectorPolicy::print_abandoned_summary(PauseSummary* summary) const {
- bool printed = false;
- if (summary->get_total_seq()->num() > 0) {
- printed = true;
- print_summary(summary);
- }
- if (!printed) {
- print_indent(0);
- gclog_or_tty->print_cr("none");
- gclog_or_tty->print_cr("");
- }
-}
-
void G1CollectorPolicy::print_tracing_info() const {
if (TraceGen0Time) {
gclog_or_tty->print_cr("ALL PAUSES");
@@ -2242,9 +2211,6 @@
gclog_or_tty->print_cr("EVACUATION PAUSES");
print_summary(_summary);
- gclog_or_tty->print_cr("ABANDONED PAUSES");
- print_abandoned_summary(_abandoned_summary);
-
gclog_or_tty->print_cr("MISC");
print_summary_sd(0, "Stop World", _all_stop_world_times_ms);
print_summary_sd(0, "Yields", _all_yield_times_ms);
@@ -2870,19 +2836,12 @@
}
#endif // !PRODUCT
-bool
+void
G1CollectorPolicy_BestRegionsFirst::choose_collection_set(
double target_pause_time_ms) {
// Set this here - in case we're not doing young collections.
double non_young_start_time_sec = os::elapsedTime();
- // The result that this routine will return. This will be set to
- // false if:
- // * we're doing a young or partially young collection and we
- // have added the youg regions to collection set, or
- // * we add old regions to the collection set.
- bool abandon_collection = true;
-
start_recording_regions();
guarantee(target_pause_time_ms > 0.0,
@@ -2986,10 +2945,6 @@
}
assert(_inc_cset_size == _g1->young_list()->length(), "Invariant");
- if (_inc_cset_size > 0) {
- assert(_collection_set != NULL, "Invariant");
- abandon_collection = false;
- }
double young_end_time_sec = os::elapsedTime();
_recorded_young_cset_choice_time_ms =
@@ -3011,10 +2966,6 @@
NumberSeq seq;
double avg_prediction = 100000000000000000.0; // something very large
- // Save the current size of the collection set to detect
- // if we actually added any old regions.
- size_t n_young_regions = _collection_set_size;
-
do {
hr = _collectionSetChooser->getNextMarkedRegion(time_remaining_ms,
avg_prediction);
@@ -3041,12 +2992,6 @@
if (!adaptive_young_list_length() &&
_collection_set_size < _young_list_fixed_length)
_should_revert_to_full_young_gcs = true;
-
- if (_collection_set_size > n_young_regions) {
- // We actually added old regions to the collection set
- // so we are not abandoning this collection.
- abandon_collection = false;
- }
}
choose_collection_set_end:
@@ -3059,19 +3004,6 @@
double non_young_end_time_sec = os::elapsedTime();
_recorded_non_young_cset_choice_time_ms =
(non_young_end_time_sec - non_young_start_time_sec) * 1000.0;
-
- // Here we are supposed to return whether the pause should be
- // abandoned or not (i.e., whether the collection set is empty or
- // not). However, this introduces a subtle issue when a pause is
- // initiated explicitly with System.gc() and
- // +ExplicitGCInvokesConcurrent (see Comment #2 in CR 6944166), it's
- // supposed to start a marking cycle, and it's abandoned. So, by
- // returning false here we are telling the caller never to consider
- // a pause to be abandoned. We'll actually remove all the code
- // associated with abandoned pauses as part of CR 6963209, but we are
- // just disabling them this way for the moment to avoid increasing
- // further the amount of changes for CR 6944166.
- return false;
}
void G1CollectorPolicy_BestRegionsFirst::record_full_collection_end() {
@@ -3086,7 +3018,7 @@
}
void G1CollectorPolicy_BestRegionsFirst::
-record_collection_pause_end(bool abandoned) {
- G1CollectorPolicy::record_collection_pause_end(abandoned);
+record_collection_pause_end() {
+ G1CollectorPolicy::record_collection_pause_end();
assert(assertMarkedBytesDataOK(), "Marked regions not OK at pause end.");
}
--- a/hotspot/src/share/vm/gc_implementation/g1/g1CollectorPolicy.hpp Wed Sep 08 14:04:18 2010 -0700
+++ b/hotspot/src/share/vm/gc_implementation/g1/g1CollectorPolicy.hpp Wed Jul 05 17:21:22 2017 +0200
@@ -63,8 +63,6 @@
define_num_seq(mark_stack_scan)
define_num_seq(update_rs)
define_num_seq(scan_rs)
- define_num_seq(scan_new_refs) // Only for temp use; added to
- // in parallel case.
define_num_seq(obj_copy)
define_num_seq(termination) // parallel only
define_num_seq(parallel_other) // parallel only
@@ -78,9 +76,6 @@
virtual MainBodySummary* main_body_summary() { return this; }
};
-class AbandonedSummary: public PauseSummary {
-};
-
class G1CollectorPolicy: public CollectorPolicy {
protected:
// The number of pauses during the execution.
@@ -150,7 +145,6 @@
TruncatedSeq* _concurrent_mark_cleanup_times_ms;
Summary* _summary;
- AbandonedSummary* _abandoned_summary;
NumberSeq* _all_pause_times_ms;
NumberSeq* _all_full_gc_times_ms;
@@ -177,7 +171,6 @@
double* _par_last_update_rs_times_ms;
double* _par_last_update_rs_processed_buffers;
double* _par_last_scan_rs_times_ms;
- double* _par_last_scan_new_refs_times_ms;
double* _par_last_obj_copy_times_ms;
double* _par_last_termination_times_ms;
double* _par_last_termination_attempts;
@@ -576,7 +569,6 @@
NumberSeq* calc_other_times_ms) const;
void print_summary (PauseSummary* stats) const;
- void print_abandoned_summary(PauseSummary* summary) const;
void print_summary (int level, const char* str, NumberSeq* seq) const;
void print_summary_sd (int level, const char* str, NumberSeq* seq) const;
@@ -889,7 +881,7 @@
virtual void record_collection_pause_end_CH_strong_roots();
virtual void record_collection_pause_end_G1_strong_roots();
- virtual void record_collection_pause_end(bool abandoned);
+ virtual void record_collection_pause_end();
// Record the fact that a full collection occurred.
virtual void record_full_collection_start();
@@ -933,14 +925,6 @@
_par_last_scan_rs_times_ms[thread] = ms;
}
- void record_scan_new_refs_time(int thread, double ms) {
- _par_last_scan_new_refs_times_ms[thread] = ms;
- }
-
- double get_scan_new_refs_time(int thread) {
- return _par_last_scan_new_refs_times_ms[thread];
- }
-
void reset_obj_copy_time(int thread) {
_par_last_obj_copy_times_ms[thread] = 0.0;
}
@@ -1010,7 +994,7 @@
// Choose a new collection set. Marks the chosen regions as being
// "in_collection_set", and links them together. The head and number of
// the collection set are available via access methods.
- virtual bool choose_collection_set(double target_pause_time_ms) = 0;
+ virtual void choose_collection_set(double target_pause_time_ms) = 0;
// The head of the list (via "next_in_collection_set()") representing the
// current collection set.
@@ -1267,7 +1251,7 @@
// If the estimated is less then desirable, resize if possible.
void expand_if_possible(size_t numRegions);
- virtual bool choose_collection_set(double target_pause_time_ms);
+ virtual void choose_collection_set(double target_pause_time_ms);
virtual void record_collection_pause_start(double start_time_sec,
size_t start_used);
virtual void record_concurrent_mark_cleanup_end(size_t freed_bytes,
@@ -1278,7 +1262,7 @@
G1CollectorPolicy_BestRegionsFirst() {
_collectionSetChooser = new CollectionSetChooser();
}
- void record_collection_pause_end(bool abandoned);
+ void record_collection_pause_end();
bool should_do_collection_pause(size_t word_size);
// This is not needed any more, after the CSet choosing code was
// changed to use the pause prediction work. But let's leave the
--- a/hotspot/src/share/vm/gc_implementation/g1/g1OopClosures.inline.hpp Wed Sep 08 14:04:18 2010 -0700
+++ b/hotspot/src/share/vm/gc_implementation/g1/g1OopClosures.inline.hpp Wed Jul 05 17:21:22 2017 +0200
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2001, 2007, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2001, 2010, 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
@@ -37,7 +37,8 @@
_g1->obj_in_cs(oopDesc::decode_heap_oop_not_null(heap_oop))) {
_oc->do_oop(p);
#if FILTERINTOCSCLOSURE_DOHISTOGRAMCOUNT
- _dcto_cl->incr_count();
+ if (_dcto_cl != NULL)
+ _dcto_cl->incr_count();
#endif
}
}
@@ -113,7 +114,10 @@
if (_g1->in_cset_fast_test(obj)) {
Prefetch::write(obj->mark_addr(), 0);
Prefetch::read(obj->mark_addr(), (HeapWordSize*2));
+
+ // Place on the references queue
_par_scan_state->push_on_queue(p);
}
}
}
+
--- a/hotspot/src/share/vm/gc_implementation/g1/g1RemSet.cpp Wed Sep 08 14:04:18 2010 -0700
+++ b/hotspot/src/share/vm/gc_implementation/g1/g1RemSet.cpp Wed Jul 05 17:21:22 2017 +0200
@@ -122,23 +122,24 @@
HRInto_G1RemSet::HRInto_G1RemSet(G1CollectedHeap* g1, CardTableModRefBS* ct_bs)
: G1RemSet(g1), _ct_bs(ct_bs), _g1p(_g1->g1_policy()),
_cg1r(g1->concurrent_g1_refine()),
- _par_traversal_in_progress(false), _new_refs(NULL),
+ _traversal_in_progress(false),
+ _cset_rs_update_cl(NULL),
_cards_scanned(NULL), _total_cards_scanned(0)
{
_seq_task = new SubTasksDone(NumSeqTasks);
guarantee(n_workers() > 0, "There should be some workers");
- _new_refs = NEW_C_HEAP_ARRAY(GrowableArray<OopOrNarrowOopStar>*, n_workers());
+ _cset_rs_update_cl = NEW_C_HEAP_ARRAY(OopsInHeapRegionClosure*, n_workers());
for (uint i = 0; i < n_workers(); i++) {
- _new_refs[i] = new (ResourceObj::C_HEAP) GrowableArray<OopOrNarrowOopStar>(8192,true);
+ _cset_rs_update_cl[i] = NULL;
}
}
HRInto_G1RemSet::~HRInto_G1RemSet() {
delete _seq_task;
for (uint i = 0; i < n_workers(); i++) {
- delete _new_refs[i];
+ assert(_cset_rs_update_cl[i] == NULL, "it should be");
}
- FREE_C_HEAP_ARRAY(GrowableArray<OopOrNarrowOopStar>*, _new_refs);
+ FREE_C_HEAP_ARRAY(OopsInHeapRegionClosure*, _cset_rs_update_cl);
}
void CountNonCleanMemRegionClosure::do_MemRegion(MemRegion mr) {
@@ -306,12 +307,45 @@
_g1p->record_scan_rs_time(worker_i, scan_rs_time_sec * 1000.0);
}
-void HRInto_G1RemSet::updateRS(int worker_i) {
- ConcurrentG1Refine* cg1r = _g1->concurrent_g1_refine();
+// Closure used for updating RSets and recording references that
+// point into the collection set. Only called during an
+// evacuation pause.
+
+class RefineRecordRefsIntoCSCardTableEntryClosure: public CardTableEntryClosure {
+ G1RemSet* _g1rs;
+ DirtyCardQueue* _into_cset_dcq;
+public:
+ RefineRecordRefsIntoCSCardTableEntryClosure(G1CollectedHeap* g1h,
+ DirtyCardQueue* into_cset_dcq) :
+ _g1rs(g1h->g1_rem_set()), _into_cset_dcq(into_cset_dcq)
+ {}
+ bool do_card_ptr(jbyte* card_ptr, int worker_i) {
+ // The only time we care about recording cards that
+ // contain references that point into the collection set
+ // 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 < (int) DirtyCardQueueSet::num_par_ids(), "should be a GC worker");
+ if (_g1rs->concurrentRefineOneCard(card_ptr, worker_i, true)) {
+ // 'card_ptr' contains references that point into the collection
+ // set. We need to record the card in the DCQS
+ // (G1CollectedHeap::into_cset_dirty_card_queue_set())
+ // that's used for that purpose.
+ //
+ // Enqueue the card
+ _into_cset_dcq->enqueue(card_ptr);
+ }
+ return true;
+ }
+};
+
+void HRInto_G1RemSet::updateRS(DirtyCardQueue* into_cset_dcq, int worker_i) {
double start = os::elapsedTime();
- // Apply the appropriate closure to all remaining log entries.
- _g1->iterate_dirty_card_closure(false, worker_i);
+ // Apply the given closure to all remaining log entries.
+ RefineRecordRefsIntoCSCardTableEntryClosure into_cset_update_rs_cl(_g1, into_cset_dcq);
+ _g1->iterate_dirty_card_closure(&into_cset_update_rs_cl, into_cset_dcq, false, worker_i);
+
// Now there should be no dirty cards.
if (G1RSLogCheckCardTable) {
CountNonCleanMemRegionClosure cl(_g1);
@@ -405,33 +439,6 @@
}
};
-template <class T> void
-HRInto_G1RemSet::scanNewRefsRS_work(OopsInHeapRegionClosure* oc,
- int worker_i) {
- double scan_new_refs_start_sec = os::elapsedTime();
- G1CollectedHeap* g1h = G1CollectedHeap::heap();
- CardTableModRefBS* ct_bs = (CardTableModRefBS*) (g1h->barrier_set());
- for (int i = 0; i < _new_refs[worker_i]->length(); i++) {
- T* p = (T*) _new_refs[worker_i]->at(i);
- oop obj = oopDesc::load_decode_heap_oop(p);
- // *p was in the collection set when p was pushed on "_new_refs", but
- // another thread may have processed this location from an RS, so it
- // might not point into the CS any longer. If so, it's obviously been
- // processed, and we don't need to do anything further.
- if (g1h->obj_in_cs(obj)) {
- HeapRegion* r = g1h->heap_region_containing(p);
-
- DEBUG_ONLY(HeapRegion* to = g1h->heap_region_containing(obj));
- oc->set_region(r);
- // If "p" has already been processed concurrently, this is
- // idempotent.
- oc->do_oop(p);
- }
- }
- double scan_new_refs_time_ms = (os::elapsedTime() - scan_new_refs_start_sec) * 1000.0;
- _g1p->record_scan_new_refs_time(worker_i, scan_new_refs_time_ms);
-}
-
void HRInto_G1RemSet::cleanupHRRS() {
HeapRegionRemSet::cleanup();
}
@@ -457,32 +464,48 @@
count_cl.print_histo();
}
- if (ParallelGCThreads > 0) {
- // The two flags below were introduced temporarily to serialize
- // the updating and scanning of remembered sets. There are some
- // race conditions when these two operations are done in parallel
- // and they are causing failures. When we resolve said race
- // conditions, we'll revert back to parallel remembered set
- // updating and scanning. See CRs 6677707 and 6677708.
- if (G1UseParallelRSetUpdating || (worker_i == 0)) {
- updateRS(worker_i);
- scanNewRefsRS(oc, worker_i);
- } else {
- _g1p->record_update_rs_processed_buffers(worker_i, 0.0);
- _g1p->record_update_rs_time(worker_i, 0.0);
- _g1p->record_scan_new_refs_time(worker_i, 0.0);
- }
- if (G1UseParallelRSetScanning || (worker_i == 0)) {
- scanRS(oc, worker_i);
- } else {
- _g1p->record_scan_rs_time(worker_i, 0.0);
- }
+ // We cache the value of 'oc' closure into the appropriate slot in the
+ // _cset_rs_update_cl for this worker
+ assert(worker_i < (int)n_workers(), "sanity");
+ _cset_rs_update_cl[worker_i] = oc;
+
+ // A DirtyCardQueue that is used to hold cards containing references
+ // that point into the collection set. This DCQ is associated with a
+ // special DirtyCardQueueSet (see g1CollectedHeap.hpp). Under normal
+ // circumstances (i.e. the pause successfully completes), these cards
+ // are just discarded (there's no need to update the RSets of regions
+ // that were in the collection set - after the pause these regions
+ // are wholly 'free' of live objects. In the event of an evacuation
+ // failure the cards/buffers in this queue set are:
+ // * passed to the DirtyCardQueueSet that is used to manage deferred
+ // RSet updates, or
+ // * scanned for references that point into the collection set
+ // and the RSet of the corresponding region in the collection set
+ // is updated immediately.
+ DirtyCardQueue into_cset_dcq(&_g1->into_cset_dirty_card_queue_set());
+
+ assert((ParallelGCThreads > 0) || worker_i == 0, "invariant");
+
+ // The two flags below were introduced temporarily to serialize
+ // the updating and scanning of remembered sets. There are some
+ // race conditions when these two operations are done in parallel
+ // and they are causing failures. When we resolve said race
+ // conditions, we'll revert back to parallel remembered set
+ // updating and scanning. See CRs 6677707 and 6677708.
+ if (G1UseParallelRSetUpdating || (worker_i == 0)) {
+ updateRS(&into_cset_dcq, worker_i);
} else {
- assert(worker_i == 0, "invariant");
- updateRS(0);
- scanNewRefsRS(oc, 0);
- scanRS(oc, 0);
+ _g1p->record_update_rs_processed_buffers(worker_i, 0.0);
+ _g1p->record_update_rs_time(worker_i, 0.0);
}
+ if (G1UseParallelRSetScanning || (worker_i == 0)) {
+ scanRS(oc, worker_i);
+ } else {
+ _g1p->record_scan_rs_time(worker_i, 0.0);
+ }
+
+ // We now clear the cached values of _cset_rs_update_cl for this worker
+ _cset_rs_update_cl[worker_i] = NULL;
}
void HRInto_G1RemSet::
@@ -497,9 +520,9 @@
DirtyCardQueueSet& dcqs = JavaThread::dirty_card_queue_set();
dcqs.concatenate_logs();
- assert(!_par_traversal_in_progress, "Invariant between iterations.");
+ assert(!_traversal_in_progress, "Invariant between iterations.");
+ set_traversal(true);
if (ParallelGCThreads > 0) {
- set_par_traversal(true);
_seq_task->set_par_threads((int)n_workers());
}
guarantee( _cards_scanned == NULL, "invariant" );
@@ -519,49 +542,65 @@
}
};
-class UpdateRSetOopsIntoCSImmediate : public OopClosure {
- G1CollectedHeap* _g1;
-public:
- UpdateRSetOopsIntoCSImmediate(G1CollectedHeap* g1) : _g1(g1) { }
- virtual void do_oop(narrowOop* p) { do_oop_work(p); }
- virtual void do_oop( oop* p) { do_oop_work(p); }
- template <class T> void do_oop_work(T* p) {
- HeapRegion* to = _g1->heap_region_containing(oopDesc::load_decode_heap_oop(p));
- if (to->in_collection_set()) {
- to->rem_set()->add_reference(p, 0);
- }
- }
-};
-
-class UpdateRSetOopsIntoCSDeferred : public OopClosure {
+// This closure, applied to a DirtyCardQueueSet, is used to immediately
+// update the RSets for the regions in the CSet. For each card it iterates
+// through the oops which coincide with that card. It scans the reference
+// fields in each oop; when it finds an oop that points into the collection
+// set, the RSet for the region containing the referenced object is updated.
+// Note: _par_traversal_in_progress in the G1RemSet must be FALSE; otherwise
+// the UpdateRSetImmediate closure will cause cards to be enqueued on to
+// the DCQS that we're iterating over, causing an infinite loop.
+class UpdateRSetCardTableEntryIntoCSetClosure: public CardTableEntryClosure {
G1CollectedHeap* _g1;
CardTableModRefBS* _ct_bs;
- DirtyCardQueue* _dcq;
public:
- UpdateRSetOopsIntoCSDeferred(G1CollectedHeap* g1, DirtyCardQueue* dcq) :
- _g1(g1), _ct_bs((CardTableModRefBS*)_g1->barrier_set()), _dcq(dcq) { }
- virtual void do_oop(narrowOop* p) { do_oop_work(p); }
- virtual void do_oop( oop* p) { do_oop_work(p); }
- template <class T> void do_oop_work(T* p) {
- oop obj = oopDesc::load_decode_heap_oop(p);
- if (_g1->obj_in_cs(obj)) {
- size_t card_index = _ct_bs->index_for(p);
- if (_ct_bs->mark_card_deferred(card_index)) {
- _dcq->enqueue((jbyte*)_ct_bs->byte_for_index(card_index));
- }
- }
+ UpdateRSetCardTableEntryIntoCSetClosure(G1CollectedHeap* g1,
+ CardTableModRefBS* bs):
+ _g1(g1), _ct_bs(bs)
+ { }
+
+ bool do_card_ptr(jbyte* card_ptr, int worker_i) {
+ // Construct the region representing the card.
+ HeapWord* start = _ct_bs->addr_for(card_ptr);
+ // And find the region containing it.
+ HeapRegion* r = _g1->heap_region_containing(start);
+ assert(r != NULL, "unexpected null");
+
+ // Scan oops in the card looking for references into the collection set
+ HeapWord* end = _ct_bs->addr_for(card_ptr + 1);
+ MemRegion scanRegion(start, end);
+
+ UpdateRSetImmediate update_rs_cl(_g1->g1_rem_set());
+ FilterIntoCSClosure update_rs_cset_oop_cl(NULL, _g1, &update_rs_cl);
+ FilterOutOfRegionClosure filter_then_update_rs_cset_oop_cl(r, &update_rs_cset_oop_cl);
+
+ // We can pass false as the "filter_young" parameter here as:
+ // * we should be in a STW pause,
+ // * the DCQS to which this closure is applied is used to hold
+ // references that point into the collection set from the prior
+ // RSet updating,
+ // * the post-write barrier shouldn't be logging updates to young
+ // regions (but there is a situation where this can happen - see
+ // the comment in HRInto_G1RemSet::concurrentRefineOneCard below -
+ // that should not be applicable here), and
+ // * during actual RSet updating, the filtering of cards in young
+ // regions in HeapRegion::oops_on_card_seq_iterate_careful is
+ // employed.
+ // As a result, when this closure is applied to "refs into cset"
+ // DCQS, we shouldn't see any cards in young regions.
+ update_rs_cl.set_region(r);
+ HeapWord* stop_point =
+ r->oops_on_card_seq_iterate_careful(scanRegion,
+ &filter_then_update_rs_cset_oop_cl,
+ false /* filter_young */);
+
+ // Since this is performed in the event of an evacuation failure, we
+ // we shouldn't see a non-null stop point
+ assert(stop_point == NULL, "saw an unallocated region");
+ return true;
}
};
-template <class T> void HRInto_G1RemSet::new_refs_iterate_work(OopClosure* cl) {
- for (size_t i = 0; i < n_workers(); i++) {
- for (int j = 0; j < _new_refs[i]->length(); j++) {
- T* p = (T*) _new_refs[i]->at(j);
- cl->do_oop(p);
- }
- }
-}
-
void HRInto_G1RemSet::cleanup_after_oops_into_collection_set_do() {
guarantee( _cards_scanned != NULL, "invariant" );
_total_cards_scanned = 0;
@@ -580,27 +619,42 @@
// Set all cards back to clean.
_g1->cleanUpCardTable();
- if (ParallelGCThreads > 0) {
- set_par_traversal(false);
- }
+ set_traversal(false);
+
+ DirtyCardQueueSet& into_cset_dcqs = _g1->into_cset_dirty_card_queue_set();
+ int into_cset_n_buffers = into_cset_dcqs.completed_buffers_num();
if (_g1->evacuation_failed()) {
- // Restore remembered sets for the regions pointing into
- // the collection set.
+ // Restore remembered sets for the regions pointing into the collection set.
+
if (G1DeferredRSUpdate) {
- DirtyCardQueue dcq(&_g1->dirty_card_queue_set());
- UpdateRSetOopsIntoCSDeferred deferred_update(_g1, &dcq);
- new_refs_iterate(&deferred_update);
+ // If deferred RS updates are enabled then we just need to transfer
+ // the completed buffers from (a) the DirtyCardQueueSet used to hold
+ // cards that contain references that point into the collection set
+ // to (b) the DCQS used to hold the deferred RS updates
+ _g1->dirty_card_queue_set().merge_bufferlists(&into_cset_dcqs);
} else {
- UpdateRSetOopsIntoCSImmediate immediate_update(_g1);
- new_refs_iterate(&immediate_update);
+
+ CardTableModRefBS* bs = (CardTableModRefBS*)_g1->barrier_set();
+ UpdateRSetCardTableEntryIntoCSetClosure update_rs_cset_immediate(_g1, bs);
+
+ int n_completed_buffers = 0;
+ while (into_cset_dcqs.apply_closure_to_completed_buffer(&update_rs_cset_immediate,
+ 0, 0, true)) {
+ n_completed_buffers++;
+ }
+ assert(n_completed_buffers == into_cset_n_buffers, "missed some buffers");
}
}
- for (uint i = 0; i < n_workers(); i++) {
- _new_refs[i]->clear();
- }
- assert(!_par_traversal_in_progress, "Invariant between iterations.");
+ // Free any completed buffers in the DirtyCardQueueSet used to hold cards
+ // which contain references that point into the collection.
+ _g1->into_cset_dirty_card_queue_set().clear();
+ assert(_g1->into_cset_dirty_card_queue_set().completed_buffers_num() == 0,
+ "all buffers should be freed");
+ _g1->into_cset_dirty_card_queue_set().clear_n_completed_buffers();
+
+ assert(!_traversal_in_progress, "Invariant between iterations.");
}
class UpdateRSObjectClosure: public ObjectClosure {
@@ -652,7 +706,43 @@
static IntHistogram out_of_histo(50, 50);
-void HRInto_G1RemSet::concurrentRefineOneCard_impl(jbyte* card_ptr, int worker_i) {
+class TriggerClosure : public OopClosure {
+ bool _trigger;
+public:
+ TriggerClosure() : _trigger(false) { }
+ bool value() const { return _trigger; }
+ template <class T> void do_oop_nv(T* p) { _trigger = true; }
+ virtual void do_oop(oop* p) { do_oop_nv(p); }
+ virtual void do_oop(narrowOop* p) { do_oop_nv(p); }
+};
+
+class InvokeIfNotTriggeredClosure: public OopClosure {
+ TriggerClosure* _t;
+ OopClosure* _oc;
+public:
+ InvokeIfNotTriggeredClosure(TriggerClosure* t, OopClosure* oc):
+ _t(t), _oc(oc) { }
+ template <class T> void do_oop_nv(T* p) {
+ if (!_t->value()) _oc->do_oop(p);
+ }
+ virtual void do_oop(oop* p) { do_oop_nv(p); }
+ virtual void do_oop(narrowOop* p) { do_oop_nv(p); }
+};
+
+class Mux2Closure : public OopClosure {
+ OopClosure* _c1;
+ OopClosure* _c2;
+public:
+ Mux2Closure(OopClosure *c1, OopClosure *c2) : _c1(c1), _c2(c2) { }
+ template <class T> void do_oop_nv(T* p) {
+ _c1->do_oop(p); _c2->do_oop(p);
+ }
+ virtual void do_oop(oop* p) { do_oop_nv(p); }
+ virtual void do_oop(narrowOop* p) { do_oop_nv(p); }
+};
+
+bool HRInto_G1RemSet::concurrentRefineOneCard_impl(jbyte* card_ptr, int worker_i,
+ bool check_for_refs_into_cset) {
// Construct the region representing the card.
HeapWord* start = _ct_bs->addr_for(card_ptr);
// And find the region containing it.
@@ -669,7 +759,16 @@
UpdateRSOopClosure update_rs_oop_cl(this, worker_i);
update_rs_oop_cl.set_from(r);
- FilterOutOfRegionClosure filter_then_update_rs_oop_cl(r, &update_rs_oop_cl);
+
+ TriggerClosure trigger_cl;
+ FilterIntoCSClosure into_cs_cl(NULL, _g1, &trigger_cl);
+ InvokeIfNotTriggeredClosure invoke_cl(&trigger_cl, &into_cs_cl);
+ Mux2Closure mux(&invoke_cl, &update_rs_oop_cl);
+
+ FilterOutOfRegionClosure filter_then_update_rs_oop_cl(r,
+ (check_for_refs_into_cset ?
+ (OopClosure*)&mux :
+ (OopClosure*)&update_rs_oop_cl));
// Undirty the card.
*card_ptr = CardTableModRefBS::clean_card_val();
@@ -717,11 +816,18 @@
out_of_histo.add_entry(filter_then_update_rs_oop_cl.out_of_region());
_conc_refine_cards++;
}
+
+ return trigger_cl.value();
}
-void HRInto_G1RemSet::concurrentRefineOneCard(jbyte* card_ptr, int worker_i) {
+bool HRInto_G1RemSet::concurrentRefineOneCard(jbyte* card_ptr, int worker_i,
+ bool check_for_refs_into_cset) {
// If the card is no longer dirty, nothing to do.
- if (*card_ptr != CardTableModRefBS::dirty_card_val()) return;
+ if (*card_ptr != CardTableModRefBS::dirty_card_val()) {
+ // No need to return that this card contains refs that point
+ // into the collection set.
+ return false;
+ }
// Construct the region representing the card.
HeapWord* start = _ct_bs->addr_for(card_ptr);
@@ -729,7 +835,9 @@
HeapRegion* r = _g1->heap_region_containing(start);
if (r == NULL) {
guarantee(_g1->is_in_permanent(start), "Or else where?");
- return; // Not in the G1 heap (might be in perm, for example.)
+ // Again no need to return that this card contains refs that
+ // point into the collection set.
+ return false; // Not in the G1 heap (might be in perm, for example.)
}
// Why do we have to check here whether a card is on a young region,
// given that we dirty young regions and, as a result, the
@@ -743,7 +851,7 @@
// and it doesn't happen often, but it can happen. So, the extra
// check below filters out those cards.
if (r->is_young()) {
- return;
+ return false;
}
// While we are processing RSet buffers during the collection, we
// actually don't want to scan any cards on the collection set,
@@ -756,7 +864,7 @@
// however, that if evacuation fails, we have to scan any objects
// that were not moved and create any missing entries.
if (r->in_collection_set()) {
- return;
+ return false;
}
// Should we defer processing the card?
@@ -797,8 +905,14 @@
// cache.
// Immediately process res; no need to process card_ptr.
+
jbyte* res = card_ptr;
bool defer = false;
+
+ // This gets set to true if the card being refined has references
+ // that point into the collection set.
+ bool oops_into_cset = false;
+
if (_cg1r->use_cache()) {
jbyte* res = _cg1r->cache_insert(card_ptr, &defer);
if (res != NULL && (res != card_ptr || defer)) {
@@ -815,14 +929,31 @@
// Process card pointer we get back from the hot card cache. This
// will check whether the region containing the card is young
// _after_ checking that the region has been allocated from.
- concurrentRefineOneCard_impl(res, worker_i);
+ oops_into_cset = concurrentRefineOneCard_impl(res, worker_i,
+ false /* check_for_refs_into_cset */);
+ // The above call to concurrentRefineOneCard_impl is only
+ // performed if the hot card cache is enabled. This cache is
+ // disabled during an evacuation pause - which is the only
+ // time when we need know if the card contains references
+ // that point into the collection set. Also when the hot card
+ // cache is enabled, this code is executed by the concurrent
+ // refine threads - rather than the GC worker threads - and
+ // concurrentRefineOneCard_impl will return false.
+ assert(!oops_into_cset, "should not see true here");
}
}
}
if (!defer) {
- concurrentRefineOneCard_impl(card_ptr, worker_i);
+ oops_into_cset =
+ concurrentRefineOneCard_impl(card_ptr, worker_i, check_for_refs_into_cset);
+ // We should only be detecting that the card contains references
+ // that point into the collection set if the current thread is
+ // a GC worker thread.
+ assert(!oops_into_cset || SafepointSynchronize::is_at_safepoint(),
+ "invalid result at non safepoint");
}
+ return oops_into_cset;
}
class HRRSStatsIter: public HeapRegionClosure {
@@ -920,6 +1051,7 @@
}
}
+
void HRInto_G1RemSet::prepare_for_verify() {
if (G1HRRSFlushLogBuffersOnVerify &&
(VerifyBeforeGC || VerifyAfterGC)
@@ -932,7 +1064,9 @@
}
bool cg1r_use_cache = _cg1r->use_cache();
_cg1r->set_use_cache(false);
- updateRS(0);
+ DirtyCardQueue into_cset_dcq(&_g1->into_cset_dirty_card_queue_set());
+ updateRS(&into_cset_dcq, 0);
+ _g1->into_cset_dirty_card_queue_set().clear();
_cg1r->set_use_cache(cg1r_use_cache);
assert(JavaThread::dirty_card_queue_set().completed_buffers_num() == 0, "All should be consumed");
--- a/hotspot/src/share/vm/gc_implementation/g1/g1RemSet.hpp Wed Sep 08 14:04:18 2010 -0700
+++ b/hotspot/src/share/vm/gc_implementation/g1/g1RemSet.hpp Wed Jul 05 17:21:22 2017 +0200
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2001, 2009, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2001, 2010, 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
@@ -83,7 +83,13 @@
// Refine the card corresponding to "card_ptr". If "sts" is non-NULL,
// join and leave around parts that must be atomic wrt GC. (NULL means
// being done at a safepoint.)
- virtual void concurrentRefineOneCard(jbyte* card_ptr, int worker_i) {}
+ // With some implementations of this routine, when check_for_refs_into_cset
+ // is true, a true result may be returned if the given card contains oops
+ // that have references into the current collection set.
+ virtual bool concurrentRefineOneCard(jbyte* card_ptr, int worker_i,
+ bool check_for_refs_into_cset) {
+ return false;
+ }
// Print any relevant summary info.
virtual void print_summary_info() {}
@@ -142,24 +148,22 @@
size_t* _cards_scanned;
size_t _total_cards_scanned;
- // _par_traversal_in_progress is "true" iff a parallel traversal is in
- // progress. If so, then cards added to remembered sets should also have
- // their references into the collection summarized in "_new_refs".
- bool _par_traversal_in_progress;
- void set_par_traversal(bool b) { _par_traversal_in_progress = b; }
- GrowableArray<OopOrNarrowOopStar>** _new_refs;
- template <class T> void new_refs_iterate_work(OopClosure* cl);
- void new_refs_iterate(OopClosure* cl) {
- if (UseCompressedOops) {
- new_refs_iterate_work<narrowOop>(cl);
- } else {
- new_refs_iterate_work<oop>(cl);
- }
- }
+ // _traversal_in_progress is "true" iff a traversal is in progress.
+
+ bool _traversal_in_progress;
+ void set_traversal(bool b) { _traversal_in_progress = b; }
+
+ // Used for caching the closure that is responsible for scanning
+ // references into the collection set.
+ OopsInHeapRegionClosure** _cset_rs_update_cl;
// The routine that performs the actual work of refining a dirty
// card.
- void concurrentRefineOneCard_impl(jbyte* card_ptr, int worker_i);
+ // If check_for_refs_into_refs is true then a true result is returned
+ // if the card contains oops that have references into the current
+ // collection set.
+ bool concurrentRefineOneCard_impl(jbyte* card_ptr, int worker_i,
+ bool check_for_refs_into_cset);
protected:
template <class T> void write_ref_nv(HeapRegion* from, T* p);
@@ -188,7 +192,7 @@
scanNewRefsRS_work<oop>(oc, worker_i);
}
}
- void updateRS(int worker_i);
+ void updateRS(DirtyCardQueue* into_cset_dcq, int worker_i);
HeapRegion* calculateStartRegion(int i);
HRInto_G1RemSet* as_HRInto_G1RemSet() { return this; }
@@ -219,7 +223,11 @@
void scrub_par(BitMap* region_bm, BitMap* card_bm,
int worker_num, int claim_val);
- virtual void concurrentRefineOneCard(jbyte* card_ptr, int worker_i);
+ // If check_for_refs_into_cset is true then a true result is returned
+ // if the card contains oops that have references into the current
+ // collection set.
+ virtual bool concurrentRefineOneCard(jbyte* card_ptr, int worker_i,
+ bool check_for_refs_into_cset);
virtual void print_summary_info();
virtual void prepare_for_verify();
@@ -265,3 +273,16 @@
// bool idempotent() { return true; }
bool apply_to_weak_ref_discovered_field() { return true; }
};
+
+class UpdateRSetImmediate: public OopsInHeapRegionClosure {
+private:
+ G1RemSet* _g1_rem_set;
+
+ template <class T> void do_oop_work(T* p);
+public:
+ UpdateRSetImmediate(G1RemSet* rs) :
+ _g1_rem_set(rs) {}
+
+ virtual void do_oop(narrowOop* p) { do_oop_work(p); }
+ virtual void do_oop( oop* p) { do_oop_work(p); }
+};
--- a/hotspot/src/share/vm/gc_implementation/g1/g1RemSet.inline.hpp Wed Sep 08 14:04:18 2010 -0700
+++ b/hotspot/src/share/vm/gc_implementation/g1/g1RemSet.inline.hpp Wed Jul 05 17:21:22 2017 +0200
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2001, 2009, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2001, 2010, 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
@@ -56,19 +56,25 @@
assert(Universe::heap()->is_in_reserved(obj), "must be in heap");
}
#endif // ASSERT
- assert(from == NULL || from->is_in_reserved(p),
- "p is not in from");
+
+ assert(from == NULL || from->is_in_reserved(p), "p is not in from");
+
HeapRegion* to = _g1->heap_region_containing(obj);
// The test below could be optimized by applying a bit op to to and from.
if (to != NULL && from != NULL && from != to) {
- // There is a tricky infinite loop if we keep pushing
- // self forwarding pointers onto our _new_refs list.
- // The _par_traversal_in_progress flag is true during the collection pause,
- // false during the evacuation failure handing.
- if (_par_traversal_in_progress &&
+ // The _traversal_in_progress flag is true during the collection pause,
+ // false during the evacuation failure handling. This should avoid a
+ // potential loop if we were to add the card containing 'p' to the DCQS
+ // that's used to regenerate the remembered sets for the collection set,
+ // in the event of an evacuation failure, here. The UpdateRSImmediate
+ // closure will eventally call this routine.
+ if (_traversal_in_progress &&
to->in_collection_set() && !self_forwarded(obj)) {
- _new_refs[tid]->push((void*)p);
- // Deferred updates to the Cset are either discarded (in the normal case),
+
+ assert(_cset_rs_update_cl[tid] != NULL, "should have been set already");
+ _cset_rs_update_cl[tid]->do_oop(p);
+
+ // Deferred updates to the CSet are either discarded (in the normal case),
// or processed (if an evacuation failure occurs) at the end
// of the collection.
// See HRInto_G1RemSet::cleanup_after_oops_into_collection_set_do().
@@ -89,3 +95,12 @@
assert(_from != NULL, "from region must be non-NULL");
_rs->par_write_ref(_from, p, _worker_i);
}
+
+template <class T> inline void UpdateRSetImmediate::do_oop_work(T* p) {
+ assert(_from->is_in_reserved(p), "paranoia");
+ T heap_oop = oopDesc::load_heap_oop(p);
+ if (!oopDesc::is_null(heap_oop) && !_from->is_survivor()) {
+ _g1_rem_set->par_write_ref(_from, p, 0);
+ }
+}
+
--- a/hotspot/src/share/vm/gc_implementation/g1/heapRegion.cpp Wed Sep 08 14:04:18 2010 -0700
+++ b/hotspot/src/share/vm/gc_implementation/g1/heapRegion.cpp Wed Jul 05 17:21:22 2017 +0200
@@ -683,6 +683,8 @@
return NULL;
}
+ assert(!is_young(), "check value of filter_young");
+
// We used to use "block_start_careful" here. But we're actually happy
// to update the BOT while we do this...
HeapWord* cur = block_start(mr.start());
@@ -788,8 +790,18 @@
int objs = 0;
int blocks = 0;
VerifyLiveClosure vl_cl(g1, use_prev_marking);
+ bool is_humongous = isHumongous();
+ size_t object_num = 0;
while (p < top()) {
size_t size = oop(p)->size();
+ if (is_humongous != g1->isHumongous(size)) {
+ gclog_or_tty->print_cr("obj "PTR_FORMAT" is of %shumongous size ("
+ SIZE_FORMAT" words) in a %shumongous region",
+ p, g1->isHumongous(size) ? "" : "non-",
+ size, is_humongous ? "" : "non-");
+ *failures = true;
+ }
+ object_num += 1;
if (blocks == BLOCK_SAMPLE_INTERVAL) {
HeapWord* res = block_start_const(p + (size/2));
if (p != res) {
@@ -855,6 +867,13 @@
}
}
+ if (is_humongous && object_num > 1) {
+ gclog_or_tty->print_cr("region ["PTR_FORMAT","PTR_FORMAT"] is humongous "
+ "but has "SIZE_FORMAT", objects",
+ bottom(), end(), object_num);
+ *failures = true;
+ }
+
if (p != top()) {
gclog_or_tty->print_cr("end of last object "PTR_FORMAT" "
"does not match top "PTR_FORMAT, p, top());
--- a/hotspot/src/share/vm/gc_implementation/g1/sparsePRT.cpp Wed Sep 08 14:04:18 2010 -0700
+++ b/hotspot/src/share/vm/gc_implementation/g1/sparsePRT.cpp Wed Jul 05 17:21:22 2017 +0200
@@ -424,7 +424,7 @@
SparsePRT::SparsePRT(HeapRegion* hr) :
- _expanded(false), _next_expanded(NULL)
+ _hr(hr), _expanded(false), _next_expanded(NULL)
{
_cur = new RSHashTable(InitialCapacity);
_next = _cur;
--- a/hotspot/src/share/vm/gc_implementation/includeDB_gc_concurrentMarkSweep Wed Sep 08 14:04:18 2010 -0700
+++ b/hotspot/src/share/vm/gc_implementation/includeDB_gc_concurrentMarkSweep Wed Jul 05 17:21:22 2017 +0200
@@ -1,5 +1,5 @@
//
-// Copyright (c) 2004, 2009, Oracle and/or its affiliates. All rights reserved.
+// Copyright (c) 2004, 2010, 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
@@ -34,6 +34,8 @@
binaryTreeDictionary.hpp freeBlockDictionary.hpp
binaryTreeDictionary.hpp freeList.hpp
+blockOffsetTable.inline.hpp concurrentMarkSweepGeneration.hpp
+
cmsAdaptiveSizePolicy.cpp cmsAdaptiveSizePolicy.hpp
cmsAdaptiveSizePolicy.cpp defNewGeneration.hpp
cmsAdaptiveSizePolicy.cpp gcStats.hpp
@@ -85,7 +87,7 @@
cmsOopClosures.inline.hpp cmsOopClosures.hpp
cmsOopClosures.inline.hpp concurrentMarkSweepGeneration.hpp
-cmsPermGen.cpp blockOffsetTable.hpp
+cmsPermGen.cpp blockOffsetTable.inline.hpp
cmsPermGen.cpp cSpaceCounters.hpp
cmsPermGen.cpp cmsPermGen.hpp
cmsPermGen.cpp collectedHeap.inline.hpp
@@ -121,6 +123,7 @@
compactibleFreeListSpace.cpp vmThread.hpp
compactibleFreeListSpace.hpp binaryTreeDictionary.hpp
+compactibleFreeListSpace.hpp blockOffsetTable.inline.hpp
compactibleFreeListSpace.hpp freeList.hpp
compactibleFreeListSpace.hpp promotionInfo.hpp
compactibleFreeListSpace.hpp space.hpp
@@ -149,6 +152,7 @@
concurrentMarkSweepGeneration.cpp iterator.hpp
concurrentMarkSweepGeneration.cpp java.hpp
concurrentMarkSweepGeneration.cpp jvmtiExport.hpp
+concurrentMarkSweepGeneration.cpp memoryService.hpp
concurrentMarkSweepGeneration.cpp oop.inline.hpp
concurrentMarkSweepGeneration.cpp parNewGeneration.hpp
concurrentMarkSweepGeneration.cpp referencePolicy.hpp
@@ -165,6 +169,7 @@
concurrentMarkSweepGeneration.hpp gcStats.hpp
concurrentMarkSweepGeneration.hpp generation.hpp
concurrentMarkSweepGeneration.hpp generationCounters.hpp
+concurrentMarkSweepGeneration.hpp memoryService.hpp
concurrentMarkSweepGeneration.hpp mutexLocker.hpp
concurrentMarkSweepGeneration.hpp taskqueue.hpp
concurrentMarkSweepGeneration.hpp virtualspace.hpp
--- a/hotspot/src/share/vm/gc_implementation/includeDB_gc_g1 Wed Sep 08 14:04:18 2010 -0700
+++ b/hotspot/src/share/vm/gc_implementation/includeDB_gc_g1 Wed Jul 05 17:21:22 2017 +0200
@@ -1,5 +1,5 @@
//
-// Copyright (c) 2004, 2009, Oracle and/or its affiliates. All rights reserved.
+// Copyright (c) 2004, 2010, 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
@@ -241,6 +241,7 @@
g1MMUTracker.hpp debug.hpp
g1MMUTracker.hpp allocation.hpp
+
g1RemSet.cpp bufferingOopClosure.hpp
g1RemSet.cpp concurrentG1Refine.hpp
g1RemSet.cpp concurrentG1RefineThread.hpp
--- a/hotspot/src/share/vm/gc_implementation/includeDB_gc_parallelScavenge Wed Sep 08 14:04:18 2010 -0700
+++ b/hotspot/src/share/vm/gc_implementation/includeDB_gc_parallelScavenge Wed Jul 05 17:21:22 2017 +0200
@@ -330,7 +330,6 @@
psPromotionManager.cpp psScavenge.inline.hpp
psPromotionManager.hpp allocation.hpp
-psPromotionManager.hpp prefetchQueue.hpp
psPromotionManager.hpp psPromotionLAB.hpp
psPromotionManager.hpp taskqueue.hpp
--- a/hotspot/src/share/vm/gc_implementation/parNew/parNewGeneration.cpp Wed Sep 08 14:04:18 2010 -0700
+++ b/hotspot/src/share/vm/gc_implementation/parNew/parNewGeneration.cpp Wed Jul 05 17:21:22 2017 +0200
@@ -51,9 +51,14 @@
_is_alive_closure(gen_), _scan_weak_ref_closure(gen_, this),
_keep_alive_closure(&_scan_weak_ref_closure),
_promotion_failure_size(0),
- _pushes(0), _pops(0), _steals(0), _steal_attempts(0), _term_attempts(0),
_strong_roots_time(0.0), _term_time(0.0)
{
+ #if TASKQUEUE_STATS
+ _term_attempts = 0;
+ _overflow_refills = 0;
+ _overflow_refill_objs = 0;
+ #endif // TASKQUEUE_STATS
+
_survivor_chunk_array =
(ChunkArray*) old_gen()->get_data_recorder(thread_num());
_hash_seed = 17; // Might want to take time-based random value.
@@ -100,7 +105,6 @@
// Push remainder.
bool ok = work_queue()->push(old);
assert(ok, "just popped, push must be okay");
- note_push();
} else {
// Restore length so that it can be used if there
// is a promotion failure and forwarding pointers
@@ -126,7 +130,6 @@
while (queue->size() > (juint)max_size) {
oop obj_to_scan;
if (queue->pop_local(obj_to_scan)) {
- note_pop();
if ((HeapWord *)obj_to_scan < young_old_boundary()) {
if (obj_to_scan->is_objArray() &&
obj_to_scan->is_forwarded() &&
@@ -271,20 +274,28 @@
GrowableArray<oop>** overflow_stacks_,
size_t desired_plab_sz,
ParallelTaskTerminator& term);
+
+ ~ParScanThreadStateSet() { TASKQUEUE_STATS_ONLY(reset_stats()); }
+
inline ParScanThreadState& thread_state(int i);
- int pushes() { return _pushes; }
- int pops() { return _pops; }
- int steals() { return _steals; }
+
void reset(bool promotion_failed);
void flush();
+
+ #if TASKQUEUE_STATS
+ static void
+ print_termination_stats_hdr(outputStream* const st = gclog_or_tty);
+ void print_termination_stats(outputStream* const st = gclog_or_tty);
+ static void
+ print_taskqueue_stats_hdr(outputStream* const st = gclog_or_tty);
+ void print_taskqueue_stats(outputStream* const st = gclog_or_tty);
+ void reset_stats();
+ #endif // TASKQUEUE_STATS
+
private:
ParallelTaskTerminator& _term;
ParNewGeneration& _gen;
Generation& _next_gen;
- // staticstics
- int _pushes;
- int _pops;
- int _steals;
};
@@ -294,8 +305,7 @@
GrowableArray<oop>** overflow_stack_set_,
size_t desired_plab_sz, ParallelTaskTerminator& term)
: ResourceArray(sizeof(ParScanThreadState), num_threads),
- _gen(gen), _next_gen(old_gen), _term(term),
- _pushes(0), _pops(0), _steals(0)
+ _gen(gen), _next_gen(old_gen), _term(term)
{
assert(num_threads > 0, "sanity check!");
// Initialize states.
@@ -323,6 +333,82 @@
}
}
+#if TASKQUEUE_STATS
+void
+ParScanThreadState::reset_stats()
+{
+ taskqueue_stats().reset();
+ _term_attempts = 0;
+ _overflow_refills = 0;
+ _overflow_refill_objs = 0;
+}
+
+void ParScanThreadStateSet::reset_stats()
+{
+ for (int i = 0; i < length(); ++i) {
+ thread_state(i).reset_stats();
+ }
+}
+
+void
+ParScanThreadStateSet::print_termination_stats_hdr(outputStream* const st)
+{
+ st->print_raw_cr("GC Termination Stats");
+ st->print_raw_cr(" elapsed --strong roots-- "
+ "-------termination-------");
+ st->print_raw_cr("thr ms ms % "
+ " ms % attempts");
+ st->print_raw_cr("--- --------- --------- ------ "
+ "--------- ------ --------");
+}
+
+void ParScanThreadStateSet::print_termination_stats(outputStream* const st)
+{
+ print_termination_stats_hdr(st);
+
+ for (int i = 0; i < length(); ++i) {
+ const ParScanThreadState & pss = thread_state(i);
+ const double elapsed_ms = pss.elapsed_time() * 1000.0;
+ const double s_roots_ms = pss.strong_roots_time() * 1000.0;
+ const double term_ms = pss.term_time() * 1000.0;
+ st->print_cr("%3d %9.2f %9.2f %6.2f "
+ "%9.2f %6.2f " SIZE_FORMAT_W(8),
+ i, elapsed_ms, s_roots_ms, s_roots_ms * 100 / elapsed_ms,
+ term_ms, term_ms * 100 / elapsed_ms, pss.term_attempts());
+ }
+}
+
+// Print stats related to work queue activity.
+void ParScanThreadStateSet::print_taskqueue_stats_hdr(outputStream* const st)
+{
+ st->print_raw_cr("GC Task Stats");
+ st->print_raw("thr "); TaskQueueStats::print_header(1, st); st->cr();
+ st->print_raw("--- "); TaskQueueStats::print_header(2, st); st->cr();
+}
+
+void ParScanThreadStateSet::print_taskqueue_stats(outputStream* const st)
+{
+ print_taskqueue_stats_hdr(st);
+
+ TaskQueueStats totals;
+ for (int i = 0; i < length(); ++i) {
+ const ParScanThreadState & pss = thread_state(i);
+ const TaskQueueStats & stats = pss.taskqueue_stats();
+ st->print("%3d ", i); stats.print(st); st->cr();
+ totals += stats;
+
+ if (pss.overflow_refills() > 0) {
+ st->print_cr(" " SIZE_FORMAT_W(10) " overflow refills "
+ SIZE_FORMAT_W(10) " overflow objects",
+ pss.overflow_refills(), pss.overflow_refill_objs());
+ }
+ }
+ st->print("tot "); totals.print(st); st->cr();
+
+ DEBUG_ONLY(totals.verify());
+}
+#endif // TASKQUEUE_STATS
+
void ParScanThreadStateSet::flush()
{
// Work in this loop should be kept as lightweight as
@@ -346,42 +432,8 @@
// Inform old gen that we're done.
_next_gen.par_promote_alloc_done(i);
_next_gen.par_oop_since_save_marks_iterate_done(i);
+ }
- // Flush stats related to work queue activity (push/pop/steal)
- // This could conceivably become a bottleneck; if so, we'll put the
- // stat's gathering under the flag.
- if (PAR_STATS_ENABLED) {
- _pushes += par_scan_state.pushes();
- _pops += par_scan_state.pops();
- _steals += par_scan_state.steals();
- if (ParallelGCVerbose) {
- gclog_or_tty->print("Thread %d complete:\n"
- " Pushes: %7d Pops: %7d Steals %7d (in %d attempts)\n",
- i, par_scan_state.pushes(), par_scan_state.pops(),
- par_scan_state.steals(), par_scan_state.steal_attempts());
- if (par_scan_state.overflow_pushes() > 0 ||
- par_scan_state.overflow_refills() > 0) {
- gclog_or_tty->print(" Overflow pushes: %7d "
- "Overflow refills: %7d for %d objs.\n",
- par_scan_state.overflow_pushes(),
- par_scan_state.overflow_refills(),
- par_scan_state.overflow_refill_objs());
- }
-
- double elapsed = par_scan_state.elapsed();
- double strong_roots = par_scan_state.strong_roots_time();
- double term = par_scan_state.term_time();
- gclog_or_tty->print(
- " Elapsed: %7.2f ms.\n"
- " Strong roots: %7.2f ms (%6.2f%%)\n"
- " Termination: %7.2f ms (%6.2f%%) (in %d entries)\n",
- elapsed * 1000.0,
- strong_roots * 1000.0, (strong_roots*100.0/elapsed),
- term * 1000.0, (term*100.0/elapsed),
- par_scan_state.term_attempts());
- }
- }
- }
if (UseConcMarkSweepGC && ParallelGCThreads > 0) {
// We need to call this even when ResizeOldPLAB is disabled
// so as to avoid breaking some asserts. While we may be able
@@ -456,15 +508,12 @@
// We have no local work, attempt to steal from other threads.
// attempt to steal work from promoted.
- par_scan_state()->note_steal_attempt();
if (task_queues()->steal(par_scan_state()->thread_num(),
par_scan_state()->hash_seed(),
obj_to_scan)) {
- par_scan_state()->note_steal();
bool res = work_q->push(obj_to_scan);
assert(res, "Empty queue should have room for a push.");
- par_scan_state()->note_push();
// if successful, goto Start.
continue;
@@ -842,17 +891,6 @@
}
thread_state_set.reset(promotion_failed());
- if (PAR_STATS_ENABLED && ParallelGCVerbose) {
- gclog_or_tty->print("Thread totals:\n"
- " Pushes: %7d Pops: %7d Steals %7d (sum = %7d).\n",
- thread_state_set.pushes(), thread_state_set.pops(),
- thread_state_set.steals(),
- thread_state_set.pops()+thread_state_set.steals());
- }
- assert(thread_state_set.pushes() == thread_state_set.pops()
- + thread_state_set.steals(),
- "Or else the queues are leaky.");
-
// Process (weak) reference objects found during scavenge.
ReferenceProcessor* rp = ref_processor();
IsAliveClosure is_alive(this);
@@ -932,6 +970,11 @@
gch->print_heap_change(gch_prev_used);
}
+ if (PrintGCDetails && ParallelGCVerbose) {
+ TASKQUEUE_STATS_ONLY(thread_state_set.print_termination_stats());
+ TASKQUEUE_STATS_ONLY(thread_state_set.print_taskqueue_stats());
+ }
+
if (UseAdaptiveSizePolicy) {
size_policy->minor_collection_end(gch->gc_cause());
size_policy->avg_survived()->sample(from()->used());
@@ -1104,9 +1147,8 @@
gclog_or_tty->print("queue overflow!\n");
}
push_on_overflow_list(old, par_scan_state);
- par_scan_state->note_overflow_push();
+ TASKQUEUE_STATS_ONLY(par_scan_state->taskqueue_stats().record_overflow(0));
}
- par_scan_state->note_push();
return new_obj;
}
@@ -1227,9 +1269,8 @@
if (simulate_overflow || !par_scan_state->work_queue()->push(obj_to_push)) {
// Add stats for overflow pushes.
push_on_overflow_list(old, par_scan_state);
- par_scan_state->note_overflow_push();
+ TASKQUEUE_STATS_ONLY(par_scan_state->taskqueue_stats().record_overflow(0));
}
- par_scan_state->note_push();
return new_obj;
}
@@ -1466,7 +1507,7 @@
cur = next;
n++;
}
- par_scan_state->note_overflow_refill(n);
+ TASKQUEUE_STATS_ONLY(par_scan_state->note_overflow_refill(n));
#ifndef PRODUCT
assert(_num_par_pushes >= n, "Too many pops?");
Atomic::add_ptr(-(intptr_t)n, &_num_par_pushes);
--- a/hotspot/src/share/vm/gc_implementation/parNew/parNewGeneration.hpp Wed Sep 08 14:04:18 2010 -0700
+++ b/hotspot/src/share/vm/gc_implementation/parNew/parNewGeneration.hpp Wed Jul 05 17:21:22 2017 +0200
@@ -36,9 +36,6 @@
typedef Padded<OopTaskQueue> ObjToScanQueue;
typedef GenericTaskQueueSet<ObjToScanQueue> ObjToScanQueueSet;
-// Enable this to get push/pop/steal stats.
-const int PAR_STATS_ENABLED = 0;
-
class ParKeepAliveClosure: public DefNewGeneration::KeepAliveClosure {
private:
ParScanWeakRefClosure* _par_cl;
@@ -94,8 +91,11 @@
bool _to_space_full;
- int _pushes, _pops, _steals, _steal_attempts, _term_attempts;
- int _overflow_pushes, _overflow_refills, _overflow_refill_objs;
+#if TASKQUEUE_STATS
+ size_t _term_attempts;
+ size_t _overflow_refills;
+ size_t _overflow_refill_objs;
+#endif // TASKQUEUE_STATS
// Stats for promotion failure
size_t _promotion_failure_size;
@@ -181,45 +181,38 @@
}
void print_and_clear_promotion_failure_size();
- int pushes() { return _pushes; }
- int pops() { return _pops; }
- int steals() { return _steals; }
- int steal_attempts() { return _steal_attempts; }
- int term_attempts() { return _term_attempts; }
- int overflow_pushes() { return _overflow_pushes; }
- int overflow_refills() { return _overflow_refills; }
- int overflow_refill_objs() { return _overflow_refill_objs; }
+#if TASKQUEUE_STATS
+ TaskQueueStats & taskqueue_stats() const { return _work_queue->stats; }
+
+ size_t term_attempts() const { return _term_attempts; }
+ size_t overflow_refills() const { return _overflow_refills; }
+ size_t overflow_refill_objs() const { return _overflow_refill_objs; }
- void note_push() { if (PAR_STATS_ENABLED) _pushes++; }
- void note_pop() { if (PAR_STATS_ENABLED) _pops++; }
- void note_steal() { if (PAR_STATS_ENABLED) _steals++; }
- void note_steal_attempt() { if (PAR_STATS_ENABLED) _steal_attempts++; }
- void note_term_attempt() { if (PAR_STATS_ENABLED) _term_attempts++; }
- void note_overflow_push() { if (PAR_STATS_ENABLED) _overflow_pushes++; }
- void note_overflow_refill(int objs) {
- if (PAR_STATS_ENABLED) {
- _overflow_refills++;
- _overflow_refill_objs += objs;
- }
+ void note_term_attempt() { ++_term_attempts; }
+ void note_overflow_refill(size_t objs) {
+ ++_overflow_refills; _overflow_refill_objs += objs;
}
+ void reset_stats();
+#endif // TASKQUEUE_STATS
+
void start_strong_roots() {
_start_strong_roots = os::elapsedTime();
}
void end_strong_roots() {
_strong_roots_time += (os::elapsedTime() - _start_strong_roots);
}
- double strong_roots_time() { return _strong_roots_time; }
+ double strong_roots_time() const { return _strong_roots_time; }
void start_term_time() {
- note_term_attempt();
+ TASKQUEUE_STATS_ONLY(note_term_attempt());
_start_term = os::elapsedTime();
}
void end_term_time() {
_term_time += (os::elapsedTime() - _start_term);
}
- double term_time() { return _term_time; }
+ double term_time() const { return _term_time; }
- double elapsed() {
+ double elapsed_time() const {
return os::elapsedTime() - _start;
}
};
--- a/hotspot/src/share/vm/gc_implementation/parallelScavenge/cardTableExtension.cpp Wed Sep 08 14:04:18 2010 -0700
+++ b/hotspot/src/share/vm/gc_implementation/parallelScavenge/cardTableExtension.cpp Wed Jul 05 17:21:22 2017 +0200
@@ -123,7 +123,6 @@
assert(start_array != NULL && sp != NULL && pm != NULL, "Sanity");
assert(start_array->covered_region().contains(sp->used_region()),
"ObjectStartArray does not cover space");
- bool depth_first = pm->depth_first();
if (sp->not_empty()) {
oop* sp_top = (oop*)space_top;
@@ -201,21 +200,12 @@
*first_nonclean_card++ = clean_card;
}
// scan oops in objects
- // hoisted the if (depth_first) check out of the loop
- if (depth_first){
- do {
- oop(bottom_obj)->push_contents(pm);
- bottom_obj += oop(bottom_obj)->size();
- assert(bottom_obj <= sp_top, "just checking");
- } while (bottom_obj < top);
- pm->drain_stacks_cond_depth();
- } else {
- do {
- oop(bottom_obj)->copy_contents(pm);
- bottom_obj += oop(bottom_obj)->size();
- assert(bottom_obj <= sp_top, "just checking");
- } while (bottom_obj < top);
- }
+ do {
+ oop(bottom_obj)->push_contents(pm);
+ bottom_obj += oop(bottom_obj)->size();
+ assert(bottom_obj <= sp_top, "just checking");
+ } while (bottom_obj < top);
+ pm->drain_stacks_cond_depth();
// remember top oop* scanned
prev_top = top;
}
@@ -230,7 +220,6 @@
uint stripe_number) {
int ssize = 128; // Naked constant! Work unit = 64k.
int dirty_card_count = 0;
- bool depth_first = pm->depth_first();
oop* sp_top = (oop*)space_top;
jbyte* start_card = byte_for(sp->bottom());
@@ -363,43 +352,22 @@
const int interval = PrefetchScanIntervalInBytes;
// scan all objects in the range
if (interval != 0) {
- // hoisted the if (depth_first) check out of the loop
- if (depth_first) {
- while (p < to) {
- Prefetch::write(p, interval);
- oop m = oop(p);
- assert(m->is_oop_or_null(), "check for header");
- m->push_contents(pm);
- p += m->size();
- }
- pm->drain_stacks_cond_depth();
- } else {
- while (p < to) {
- Prefetch::write(p, interval);
- oop m = oop(p);
- assert(m->is_oop_or_null(), "check for header");
- m->copy_contents(pm);
- p += m->size();
- }
+ while (p < to) {
+ Prefetch::write(p, interval);
+ oop m = oop(p);
+ assert(m->is_oop_or_null(), "check for header");
+ m->push_contents(pm);
+ p += m->size();
}
+ pm->drain_stacks_cond_depth();
} else {
- // hoisted the if (depth_first) check out of the loop
- if (depth_first) {
- while (p < to) {
- oop m = oop(p);
- assert(m->is_oop_or_null(), "check for header");
- m->push_contents(pm);
- p += m->size();
- }
- pm->drain_stacks_cond_depth();
- } else {
- while (p < to) {
- oop m = oop(p);
- assert(m->is_oop_or_null(), "check for header");
- m->copy_contents(pm);
- p += m->size();
- }
+ while (p < to) {
+ oop m = oop(p);
+ assert(m->is_oop_or_null(), "check for header");
+ m->push_contents(pm);
+ p += m->size();
}
+ pm->drain_stacks_cond_depth();
}
last_scanned = p;
}
--- a/hotspot/src/share/vm/gc_implementation/parallelScavenge/prefetchQueue.hpp Wed Sep 08 14:04:18 2010 -0700
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,68 +0,0 @@
-/*
- * Copyright (c) 2002, 2008, 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.
- *
- */
-
-//
-// PrefetchQueue is a FIFO queue of variable length (currently 8).
-//
-// We need to examine the performance penalty of variable lengths.
-// We may also want to split this into cpu dependent bits.
-//
-
-const int PREFETCH_QUEUE_SIZE = 8;
-
-class PrefetchQueue : public CHeapObj {
- private:
- void* _prefetch_queue[PREFETCH_QUEUE_SIZE];
- uint _prefetch_index;
-
- public:
- int length() { return PREFETCH_QUEUE_SIZE; }
-
- inline void clear() {
- for(int i=0; i<PREFETCH_QUEUE_SIZE; i++) {
- _prefetch_queue[i] = NULL;
- }
- _prefetch_index = 0;
- }
-
- template <class T> inline void* push_and_pop(T* p) {
- oop o = oopDesc::load_decode_heap_oop_not_null(p);
- Prefetch::write(o->mark_addr(), 0);
- // This prefetch is intended to make sure the size field of array
- // oops is in cache. It assumes the the object layout is
- // mark -> klass -> size, and that mark and klass are heapword
- // sized. If this should change, this prefetch will need updating!
- Prefetch::write(o->mark_addr() + (HeapWordSize*2), 0);
- _prefetch_queue[_prefetch_index++] = p;
- _prefetch_index &= (PREFETCH_QUEUE_SIZE-1);
- return _prefetch_queue[_prefetch_index];
- }
-
- // Stores a NULL pointer in the pop'd location.
- inline void* pop() {
- _prefetch_queue[_prefetch_index++] = NULL;
- _prefetch_index &= (PREFETCH_QUEUE_SIZE-1);
- return _prefetch_queue[_prefetch_index];
- }
-};
--- a/hotspot/src/share/vm/gc_implementation/parallelScavenge/psPromotionManager.cpp Wed Sep 08 14:04:18 2010 -0700
+++ b/hotspot/src/share/vm/gc_implementation/parallelScavenge/psPromotionManager.cpp Wed Jul 05 17:21:22 2017 +0200
@@ -27,7 +27,6 @@
PSPromotionManager** PSPromotionManager::_manager_array = NULL;
OopStarTaskQueueSet* PSPromotionManager::_stack_array_depth = NULL;
-OopTaskQueueSet* PSPromotionManager::_stack_array_breadth = NULL;
PSOldGen* PSPromotionManager::_old_gen = NULL;
MutableSpace* PSPromotionManager::_young_space = NULL;
@@ -42,23 +41,14 @@
_manager_array = NEW_C_HEAP_ARRAY(PSPromotionManager*, ParallelGCThreads+1 );
guarantee(_manager_array != NULL, "Could not initialize promotion manager");
- if (UseDepthFirstScavengeOrder) {
- _stack_array_depth = new OopStarTaskQueueSet(ParallelGCThreads);
- guarantee(_stack_array_depth != NULL, "Count not initialize promotion manager");
- } else {
- _stack_array_breadth = new OopTaskQueueSet(ParallelGCThreads);
- guarantee(_stack_array_breadth != NULL, "Count not initialize promotion manager");
- }
+ _stack_array_depth = new OopStarTaskQueueSet(ParallelGCThreads);
+ guarantee(_stack_array_depth != NULL, "Cound not initialize promotion manager");
// Create and register the PSPromotionManager(s) for the worker threads.
for(uint i=0; i<ParallelGCThreads; i++) {
_manager_array[i] = new PSPromotionManager();
guarantee(_manager_array[i] != NULL, "Could not create PSPromotionManager");
- if (UseDepthFirstScavengeOrder) {
- stack_array_depth()->register_queue(i, _manager_array[i]->claimed_stack_depth());
- } else {
- stack_array_breadth()->register_queue(i, _manager_array[i]->claimed_stack_breadth());
- }
+ stack_array_depth()->register_queue(i, _manager_array[i]->claimed_stack_depth());
}
// The VMThread gets its own PSPromotionManager, which is not available
@@ -93,11 +83,7 @@
TASKQUEUE_STATS_ONLY(if (PrintGCDetails && ParallelGCVerbose) print_stats());
for (uint i = 0; i < ParallelGCThreads + 1; i++) {
PSPromotionManager* manager = manager_array(i);
- if (UseDepthFirstScavengeOrder) {
- assert(manager->claimed_stack_depth()->is_empty(), "should be empty");
- } else {
- assert(manager->claimed_stack_breadth()->is_empty(), "should be empty");
- }
+ assert(manager->claimed_stack_depth()->is_empty(), "should be empty");
manager->flush_labs();
}
}
@@ -105,10 +91,8 @@
#if TASKQUEUE_STATS
void
PSPromotionManager::print_taskqueue_stats(uint i) const {
- const TaskQueueStats& stats = depth_first() ?
- _claimed_stack_depth.stats : _claimed_stack_breadth.stats;
tty->print("%3u ", i);
- stats.print();
+ _claimed_stack_depth.stats.print();
tty->cr();
}
@@ -128,8 +112,7 @@
void
PSPromotionManager::print_stats() {
- const bool df = UseDepthFirstScavengeOrder;
- tty->print_cr("== GC Task Stats (%s-First), GC %3d", df ? "Depth" : "Breadth",
+ tty->print_cr("== GC Tasks Stats, GC %3d",
Universe::heap()->total_collections());
tty->print("thr "); TaskQueueStats::print_header(1); tty->cr();
@@ -147,9 +130,7 @@
void
PSPromotionManager::reset_stats() {
- TaskQueueStats& stats = depth_first() ?
- claimed_stack_depth()->stats : claimed_stack_breadth()->stats;
- stats.reset();
+ claimed_stack_depth()->stats.reset();
_masked_pushes = _masked_steals = 0;
_arrays_chunked = _array_chunks_processed = 0;
}
@@ -158,19 +139,13 @@
PSPromotionManager::PSPromotionManager() {
ParallelScavengeHeap* heap = (ParallelScavengeHeap*)Universe::heap();
assert(heap->kind() == CollectedHeap::ParallelScavengeHeap, "Sanity");
- _depth_first = UseDepthFirstScavengeOrder;
// We set the old lab's start array.
_old_lab.set_start_array(old_gen()->start_array());
uint queue_size;
- if (depth_first()) {
- claimed_stack_depth()->initialize();
- queue_size = claimed_stack_depth()->max_elems();
- } else {
- claimed_stack_breadth()->initialize();
- queue_size = claimed_stack_breadth()->max_elems();
- }
+ claimed_stack_depth()->initialize();
+ queue_size = claimed_stack_depth()->max_elems();
_totally_drain = (ParallelGCThreads == 1) || (GCDrainStackTargetSize == 0);
if (_totally_drain) {
@@ -205,14 +180,11 @@
_old_lab.initialize(MemRegion(lab_base, (size_t)0));
_old_gen_is_full = false;
- _prefetch_queue.clear();
-
TASKQUEUE_STATS_ONLY(reset_stats());
}
void PSPromotionManager::drain_stacks_depth(bool totally_drain) {
- assert(depth_first(), "invariant");
assert(claimed_stack_depth()->overflow_stack() != NULL, "invariant");
totally_drain = totally_drain || _totally_drain;
@@ -250,50 +222,6 @@
assert(tq->overflow_empty(), "Sanity");
}
-void PSPromotionManager::drain_stacks_breadth(bool totally_drain) {
- assert(!depth_first(), "invariant");
- assert(claimed_stack_breadth()->overflow_stack() != NULL, "invariant");
- totally_drain = totally_drain || _totally_drain;
-
-#ifdef ASSERT
- ParallelScavengeHeap* heap = (ParallelScavengeHeap*)Universe::heap();
- assert(heap->kind() == CollectedHeap::ParallelScavengeHeap, "Sanity");
- MutableSpace* to_space = heap->young_gen()->to_space();
- MutableSpace* old_space = heap->old_gen()->object_space();
- MutableSpace* perm_space = heap->perm_gen()->object_space();
-#endif /* ASSERT */
-
- OverflowTaskQueue<oop>* const tq = claimed_stack_breadth();
- do {
- oop obj;
-
- // Drain overflow stack first, so other threads can steal from
- // claimed stack while we work.
- while (tq->pop_overflow(obj)) {
- obj->copy_contents(this);
- }
-
- if (totally_drain) {
- while (tq->pop_local(obj)) {
- obj->copy_contents(this);
- }
- } else {
- while (tq->size() > _target_stack_size && tq->pop_local(obj)) {
- obj->copy_contents(this);
- }
- }
-
- // If we could not find any other work, flush the prefetch queue
- if (tq->is_empty()) {
- flush_prefetch_queue();
- }
- } while (totally_drain && !tq->taskqueue_empty() || !tq->overflow_empty());
-
- assert(!totally_drain || tq->taskqueue_empty(), "Sanity");
- assert(totally_drain || tq->size() <= _target_stack_size, "Sanity");
- assert(tq->overflow_empty(), "Sanity");
-}
-
void PSPromotionManager::flush_labs() {
assert(stacks_empty(), "Attempt to flush lab with live stack");
@@ -319,7 +247,7 @@
// performance.
//
-oop PSPromotionManager::copy_to_survivor_space(oop o, bool depth_first) {
+oop PSPromotionManager::copy_to_survivor_space(oop o) {
assert(PSScavenge::should_scavenge(&o), "Sanity");
oop new_obj = NULL;
@@ -423,24 +351,20 @@
assert(young_space()->contains(new_obj), "Attempt to push non-promoted obj");
}
- if (depth_first) {
- // Do the size comparison first with new_obj_size, which we
- // already have. Hopefully, only a few objects are larger than
- // _min_array_size_for_chunking, and most of them will be arrays.
- // So, the is->objArray() test would be very infrequent.
- if (new_obj_size > _min_array_size_for_chunking &&
- new_obj->is_objArray() &&
- PSChunkLargeArrays) {
- // we'll chunk it
- oop* const masked_o = mask_chunked_array_oop(o);
- push_depth(masked_o);
- TASKQUEUE_STATS_ONLY(++_arrays_chunked; ++_masked_pushes);
- } else {
- // we'll just push its contents
- new_obj->push_contents(this);
- }
+ // Do the size comparison first with new_obj_size, which we
+ // already have. Hopefully, only a few objects are larger than
+ // _min_array_size_for_chunking, and most of them will be arrays.
+ // So, the is->objArray() test would be very infrequent.
+ if (new_obj_size > _min_array_size_for_chunking &&
+ new_obj->is_objArray() &&
+ PSChunkLargeArrays) {
+ // we'll chunk it
+ oop* const masked_o = mask_chunked_array_oop(o);
+ push_depth(masked_o);
+ TASKQUEUE_STATS_ONLY(++_arrays_chunked; ++_masked_pushes);
} else {
- push_breadth(new_obj);
+ // we'll just push its contents
+ new_obj->push_contents(this);
}
} else {
// We lost, someone else "owns" this object
@@ -537,13 +461,7 @@
// We won any races, we "own" this object.
assert(obj == obj->forwardee(), "Sanity");
- if (depth_first()) {
- obj->push_contents(this);
- } else {
- // Don't bother incrementing the age, just push
- // onto the claimed_stack..
- push_breadth(obj);
- }
+ obj->push_contents(this);
// Save the mark if needed
PSScavenge::oop_promotion_failed(obj, obj_mark);
--- a/hotspot/src/share/vm/gc_implementation/parallelScavenge/psPromotionManager.hpp Wed Sep 08 14:04:18 2010 -0700
+++ b/hotspot/src/share/vm/gc_implementation/parallelScavenge/psPromotionManager.hpp Wed Jul 05 17:21:22 2017 +0200
@@ -48,7 +48,6 @@
private:
static PSPromotionManager** _manager_array;
static OopStarTaskQueueSet* _stack_array_depth;
- static OopTaskQueueSet* _stack_array_breadth;
static PSOldGen* _old_gen;
static MutableSpace* _young_space;
@@ -69,12 +68,10 @@
PSOldPromotionLAB _old_lab;
bool _young_gen_is_full;
bool _old_gen_is_full;
- PrefetchQueue _prefetch_queue;
OopStarTaskQueue _claimed_stack_depth;
OverflowTaskQueue<oop> _claimed_stack_breadth;
- bool _depth_first;
bool _totally_drain;
uint _target_stack_size;
@@ -87,7 +84,6 @@
inline static PSPromotionManager* manager_array(int index);
template <class T> inline void claim_or_forward_internal_depth(T* p);
- template <class T> inline void claim_or_forward_internal_breadth(T* p);
// On the task queues we push reference locations as well as
// partially-scanned arrays (in the latter case, we push an oop to
@@ -136,19 +132,11 @@
void process_array_chunk(oop old);
template <class T> void push_depth(T* p) {
- assert(depth_first(), "pre-condition");
claimed_stack_depth()->push(p);
}
- void push_breadth(oop o) {
- assert(!depth_first(), "pre-condition");
- claimed_stack_breadth()->push(o);
- }
-
protected:
static OopStarTaskQueueSet* stack_array_depth() { return _stack_array_depth; }
- static OopTaskQueueSet* stack_array_breadth() { return _stack_array_breadth; }
-
public:
// Static
static void initialize();
@@ -163,19 +151,12 @@
return stack_array_depth()->steal(queue_num, seed, t);
}
- static bool steal_breadth(int queue_num, int* seed, oop& t) {
- return stack_array_breadth()->steal(queue_num, seed, t);
- }
-
PSPromotionManager();
// Accessors
OopStarTaskQueue* claimed_stack_depth() {
return &_claimed_stack_depth;
}
- OverflowTaskQueue<oop>* claimed_stack_breadth() {
- return &_claimed_stack_breadth;
- }
bool young_gen_is_full() { return _young_gen_is_full; }
@@ -183,18 +164,14 @@
void set_old_gen_is_full(bool state) { _old_gen_is_full = state; }
// Promotion methods
- oop copy_to_survivor_space(oop o, bool depth_first);
+ oop copy_to_survivor_space(oop o);
oop oop_promotion_failed(oop obj, markOop obj_mark);
void reset();
void flush_labs();
void drain_stacks(bool totally_drain) {
- if (depth_first()) {
- drain_stacks_depth(totally_drain);
- } else {
- drain_stacks_breadth(totally_drain);
- }
+ drain_stacks_depth(totally_drain);
}
public:
void drain_stacks_cond_depth() {
@@ -203,22 +180,14 @@
}
}
void drain_stacks_depth(bool totally_drain);
- void drain_stacks_breadth(bool totally_drain);
- bool depth_first() const {
- return _depth_first;
- }
bool stacks_empty() {
- return depth_first() ?
- claimed_stack_depth()->is_empty() :
- claimed_stack_breadth()->is_empty();
+ return claimed_stack_depth()->is_empty();
}
inline void process_popped_location_depth(StarTask p);
- inline void flush_prefetch_queue();
template <class T> inline void claim_or_forward_depth(T* p);
- template <class T> inline void claim_or_forward_breadth(T* p);
TASKQUEUE_STATS_ONLY(inline void record_steal(StarTask& p);)
};
--- a/hotspot/src/share/vm/gc_implementation/parallelScavenge/psPromotionManager.inline.hpp Wed Sep 08 14:04:18 2010 -0700
+++ b/hotspot/src/share/vm/gc_implementation/parallelScavenge/psPromotionManager.inline.hpp Wed Jul 05 17:21:22 2017 +0200
@@ -46,32 +46,7 @@
}
template <class T>
-inline void PSPromotionManager::claim_or_forward_internal_breadth(T* p) {
- if (p != NULL) { // XXX: error if p != NULL here
- oop o = oopDesc::load_decode_heap_oop_not_null(p);
- if (o->is_forwarded()) {
- o = o->forwardee();
- } else {
- o = copy_to_survivor_space(o, false);
- }
- // Card mark
- if (PSScavenge::is_obj_in_young((HeapWord*) o)) {
- PSScavenge::card_table()->inline_write_ref_field_gc(p, o);
- }
- oopDesc::encode_store_heap_oop_not_null(p, o);
- }
-}
-
-inline void PSPromotionManager::flush_prefetch_queue() {
- assert(!depth_first(), "invariant");
- for (int i = 0; i < _prefetch_queue.length(); i++) {
- claim_or_forward_internal_breadth((oop*)_prefetch_queue.pop());
- }
-}
-
-template <class T>
inline void PSPromotionManager::claim_or_forward_depth(T* p) {
- assert(depth_first(), "invariant");
assert(PSScavenge::should_scavenge(p, true), "revisiting object?");
assert(Universe::heap()->kind() == CollectedHeap::ParallelScavengeHeap,
"Sanity");
@@ -80,36 +55,6 @@
claim_or_forward_internal_depth(p);
}
-template <class T>
-inline void PSPromotionManager::claim_or_forward_breadth(T* p) {
- assert(!depth_first(), "invariant");
- assert(PSScavenge::should_scavenge(p, true), "revisiting object?");
- assert(Universe::heap()->kind() == CollectedHeap::ParallelScavengeHeap,
- "Sanity");
- assert(Universe::heap()->is_in(p), "pointer outside heap");
-
- if (UsePrefetchQueue) {
- claim_or_forward_internal_breadth((T*)_prefetch_queue.push_and_pop(p));
- } else {
- // This option is used for testing. The use of the prefetch
- // queue can delay the processing of the objects and thus
- // change the order of object scans. For example, remembered
- // set updates are typically the clearing of the remembered
- // set (the cards) followed by updates of the remembered set
- // for young-to-old pointers. In a situation where there
- // is an error in the sequence of clearing and updating
- // (e.g. clear card A, update card A, erroneously clear
- // card A again) the error can be obscured by a delay
- // in the update due to the use of the prefetch queue
- // (e.g., clear card A, erroneously clear card A again,
- // update card A that was pushed into the prefetch queue
- // and thus delayed until after the erronous clear). The
- // length of the delay is random depending on the objects
- // in the queue and the delay can be zero.
- claim_or_forward_internal_breadth(p);
- }
-}
-
inline void PSPromotionManager::process_popped_location_depth(StarTask p) {
if (is_oop_masked(p)) {
assert(PSChunkLargeArrays, "invariant");
--- a/hotspot/src/share/vm/gc_implementation/parallelScavenge/psScavenge.cpp Wed Sep 08 14:04:18 2010 -0700
+++ b/hotspot/src/share/vm/gc_implementation/parallelScavenge/psScavenge.cpp Wed Jul 05 17:21:22 2017 +0200
@@ -157,10 +157,8 @@
q->enqueue(new PSRefProcTaskProxy(task, i));
}
ParallelTaskTerminator terminator(
- ParallelScavengeHeap::gc_task_manager()->workers(),
- UseDepthFirstScavengeOrder ?
- (TaskQueueSetSuper*) PSPromotionManager::stack_array_depth()
- : (TaskQueueSetSuper*) PSPromotionManager::stack_array_breadth());
+ ParallelScavengeHeap::gc_task_manager()->workers(),
+ (TaskQueueSetSuper*) PSPromotionManager::stack_array_depth());
if (task.marks_oops_alive() && ParallelGCThreads > 1) {
for (uint j=0; j<ParallelGCThreads; j++) {
q->enqueue(new StealTask(&terminator));
@@ -375,10 +373,8 @@
q->enqueue(new ScavengeRootsTask(ScavengeRootsTask::code_cache));
ParallelTaskTerminator terminator(
- gc_task_manager()->workers(),
- promotion_manager->depth_first() ?
- (TaskQueueSetSuper*) promotion_manager->stack_array_depth()
- : (TaskQueueSetSuper*) promotion_manager->stack_array_breadth());
+ gc_task_manager()->workers(),
+ (TaskQueueSetSuper*) promotion_manager->stack_array_depth());
if (ParallelGCThreads>1) {
for (uint j=0; j<ParallelGCThreads; j++) {
q->enqueue(new StealTask(&terminator));
--- a/hotspot/src/share/vm/gc_implementation/parallelScavenge/psScavenge.inline.hpp Wed Sep 08 14:04:18 2010 -0700
+++ b/hotspot/src/share/vm/gc_implementation/parallelScavenge/psScavenge.inline.hpp Wed Jul 05 17:21:22 2017 +0200
@@ -65,7 +65,7 @@
oop o = oopDesc::load_decode_heap_oop_not_null(p);
oop new_obj = o->is_forwarded()
? o->forwardee()
- : pm->copy_to_survivor_space(o, pm->depth_first());
+ : pm->copy_to_survivor_space(o);
oopDesc::encode_store_heap_oop_not_null(p, new_obj);
// We cannot mark without test, as some code passes us pointers
--- a/hotspot/src/share/vm/gc_implementation/parallelScavenge/psTasks.cpp Wed Sep 08 14:04:18 2010 -0700
+++ b/hotspot/src/share/vm/gc_implementation/parallelScavenge/psTasks.cpp Wed Jul 05 17:21:22 2017 +0200
@@ -144,29 +144,15 @@
"stacks should be empty at this point");
int random_seed = 17;
- if (pm->depth_first()) {
- while(true) {
- StarTask p;
- if (PSPromotionManager::steal_depth(which, &random_seed, p)) {
- TASKQUEUE_STATS_ONLY(pm->record_steal(p));
- pm->process_popped_location_depth(p);
- pm->drain_stacks_depth(true);
- } else {
- if (terminator()->offer_termination()) {
- break;
- }
- }
- }
- } else {
- while(true) {
- oop obj;
- if (PSPromotionManager::steal_breadth(which, &random_seed, obj)) {
- obj->copy_contents(pm);
- pm->drain_stacks_breadth(true);
- } else {
- if (terminator()->offer_termination()) {
- break;
- }
+ while(true) {
+ StarTask p;
+ if (PSPromotionManager::steal_depth(which, &random_seed, p)) {
+ TASKQUEUE_STATS_ONLY(pm->record_steal(p));
+ pm->process_popped_location_depth(p);
+ pm->drain_stacks_depth(true);
+ } else {
+ if (terminator()->offer_termination()) {
+ break;
}
}
}
--- a/hotspot/src/share/vm/includeDB_core Wed Sep 08 14:04:18 2010 -0700
+++ b/hotspot/src/share/vm/includeDB_core Wed Jul 05 17:21:22 2017 +0200
@@ -225,7 +225,6 @@
arrayOop.cpp symbolOop.hpp
arrayOop.hpp oop.hpp
-arrayOop.hpp universe.hpp
arrayOop.hpp universe.inline.hpp
assembler.cpp assembler.hpp
@@ -236,7 +235,6 @@
assembler.cpp os.hpp
assembler.hpp allocation.hpp
-assembler.hpp allocation.inline.hpp
assembler.hpp debug.hpp
assembler.hpp growableArray.hpp
assembler.hpp oopRecorder.hpp
@@ -330,7 +328,7 @@
blockOffsetTable.cpp iterator.hpp
blockOffsetTable.cpp java.hpp
blockOffsetTable.cpp oop.inline.hpp
-blockOffsetTable.cpp space.hpp
+blockOffsetTable.cpp space.inline.hpp
blockOffsetTable.cpp universe.hpp
blockOffsetTable.hpp globalDefinitions.hpp
@@ -338,6 +336,7 @@
blockOffsetTable.hpp virtualspace.hpp
blockOffsetTable.inline.hpp blockOffsetTable.hpp
+blockOffsetTable.inline.hpp safepoint.hpp
blockOffsetTable.inline.hpp space.hpp
bytecode.cpp bytecode.hpp
@@ -1807,7 +1806,7 @@
generateOopMap.hpp universe.inline.hpp
generation.cpp allocation.inline.hpp
-generation.cpp blockOffsetTable.hpp
+generation.cpp blockOffsetTable.inline.hpp
generation.cpp cardTableRS.hpp
generation.cpp collectedHeap.inline.hpp
generation.cpp copy.hpp
@@ -3436,7 +3435,7 @@
perfMemory_<os_family>.cpp resourceArea.hpp
perfMemory_<os_family>.cpp vmSymbols.hpp
-permGen.cpp blockOffsetTable.hpp
+permGen.cpp blockOffsetTable.inline.hpp
permGen.cpp cSpaceCounters.hpp
permGen.cpp collectedHeap.inline.hpp
permGen.cpp compactPermGen.hpp
@@ -3805,7 +3804,7 @@
sizes.hpp allocation.hpp
sizes.hpp globalDefinitions.hpp
-space.cpp blockOffsetTable.hpp
+space.cpp blockOffsetTable.inline.hpp
space.cpp copy.hpp
space.cpp defNewGeneration.hpp
space.cpp genCollectedHeap.hpp
@@ -3835,7 +3834,6 @@
space.hpp watermark.hpp
space.hpp workgroup.hpp
-space.inline.hpp blockOffsetTable.inline.hpp
space.inline.hpp collectedHeap.hpp
space.inline.hpp safepoint.hpp
space.inline.hpp space.hpp
--- a/hotspot/src/share/vm/interpreter/bytecodeInterpreter.cpp Wed Sep 08 14:04:18 2010 -0700
+++ b/hotspot/src/share/vm/interpreter/bytecodeInterpreter.cpp Wed Jul 05 17:21:22 2017 +0200
@@ -421,7 +421,9 @@
#ifdef ASSERT
if (istate->_msg != initialize) {
assert(abs(istate->_stack_base - istate->_stack_limit) == (istate->_method->max_stack() + 1), "bad stack limit");
- IA32_ONLY(assert(istate->_stack_limit == istate->_thread->last_Java_sp() + 1, "wrong"));
+#ifndef SHARK
+ IA32_ONLY(assert(istate->_stack_limit == istate->_thread->last_Java_sp() + 1, "wrong"));
+#endif // !SHARK
}
// Verify linkages.
interpreterState l = istate;
--- a/hotspot/src/share/vm/memory/allocation.cpp Wed Sep 08 14:04:18 2010 -0700
+++ b/hotspot/src/share/vm/memory/allocation.cpp Wed Jul 05 17:21:22 2017 +0200
@@ -58,7 +58,7 @@
void ResourceObj::operator delete(void* p) {
assert(((ResourceObj *)p)->allocated_on_C_heap(),
"delete only allowed for C_HEAP objects");
- DEBUG_ONLY(((ResourceObj *)p)->_allocation = badHeapOopVal;)
+ DEBUG_ONLY(((ResourceObj *)p)->_allocation = (uintptr_t) badHeapOopVal;)
FreeHeap(p);
}
@@ -104,7 +104,7 @@
ResourceObj::~ResourceObj() {
// allocated_on_C_heap() also checks that encoded (in _allocation) address == this.
if (!allocated_on_C_heap()) { // ResourceObj::delete() zaps _allocation for C_heap.
- _allocation = badHeapOopVal; // zap type
+ _allocation = (uintptr_t) badHeapOopVal; // zap type
}
}
#endif // ASSERT
--- a/hotspot/src/share/vm/memory/blockOffsetTable.cpp Wed Sep 08 14:04:18 2010 -0700
+++ b/hotspot/src/share/vm/memory/blockOffsetTable.cpp Wed Jul 05 17:21:22 2017 +0200
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2000, 2006, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2000, 2010, 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
@@ -103,13 +103,13 @@
//////////////////////////////////////////////////////////////////////
BlockOffsetArray::BlockOffsetArray(BlockOffsetSharedArray* array,
- MemRegion mr, bool init_to_zero) :
+ MemRegion mr, bool init_to_zero_) :
BlockOffsetTable(mr.start(), mr.end()),
- _array(array),
- _init_to_zero(init_to_zero)
+ _array(array)
{
assert(_bottom <= _end, "arguments out of order");
- if (!_init_to_zero) {
+ set_init_to_zero(init_to_zero_);
+ if (!init_to_zero_) {
// initialize cards to point back to mr.start()
set_remainder_to_point_to_start(mr.start() + N_words, mr.end());
_array->set_offset_array(0, 0); // set first card to 0
@@ -121,8 +121,9 @@
// a right-open interval: [start, end)
void
BlockOffsetArray::
-set_remainder_to_point_to_start(HeapWord* start, HeapWord* end) {
+set_remainder_to_point_to_start(HeapWord* start, HeapWord* end, bool reducing) {
+ check_reducing_assertion(reducing);
if (start >= end) {
// The start address is equal to the end address (or to
// the right of the end address) so there are not cards
@@ -167,7 +168,7 @@
size_t end_card = _array->index_for(end-1);
assert(start ==_array->address_for_index(start_card), "Precondition");
assert(end ==_array->address_for_index(end_card)+N_words, "Precondition");
- set_remainder_to_point_to_start_incl(start_card, end_card); // closed interval
+ set_remainder_to_point_to_start_incl(start_card, end_card, reducing); // closed interval
}
@@ -175,7 +176,9 @@
// a closed, inclusive interval: [start_card, end_card], cf set_remainder_to_point_to_start()
// above.
void
-BlockOffsetArray::set_remainder_to_point_to_start_incl(size_t start_card, size_t end_card) {
+BlockOffsetArray::set_remainder_to_point_to_start_incl(size_t start_card, size_t end_card, bool reducing) {
+
+ check_reducing_assertion(reducing);
if (start_card > end_card) {
return;
}
@@ -191,11 +194,11 @@
size_t reach = start_card - 1 + (power_to_cards_back(i+1) - 1);
offset = N_words + i;
if (reach >= end_card) {
- _array->set_offset_array(start_card_for_region, end_card, offset);
+ _array->set_offset_array(start_card_for_region, end_card, offset, reducing);
start_card_for_region = reach + 1;
break;
}
- _array->set_offset_array(start_card_for_region, reach, offset);
+ _array->set_offset_array(start_card_for_region, reach, offset, reducing);
start_card_for_region = reach + 1;
}
assert(start_card_for_region > end_card, "Sanity check");
@@ -211,8 +214,10 @@
return;
}
guarantee(_array->offset_array(start_card) == N_words, "Wrong value in second card");
+ u_char last_entry = N_words;
for (size_t c = start_card + 1; c <= end_card; c++ /* yeah! */) {
u_char entry = _array->offset_array(c);
+ guarantee(entry >= last_entry, "Monotonicity");
if (c - start_card > power_to_cards_back(1)) {
guarantee(entry > N_words, "Should be in logarithmic region");
}
@@ -220,11 +225,13 @@
size_t landing_card = c - backskip;
guarantee(landing_card >= (start_card - 1), "Inv");
if (landing_card >= start_card) {
- guarantee(_array->offset_array(landing_card) <= entry, "monotonicity");
+ guarantee(_array->offset_array(landing_card) <= entry, "Monotonicity");
} else {
- guarantee(landing_card == start_card - 1, "Tautology");
+ guarantee(landing_card == (start_card - 1), "Tautology");
+ // Note that N_words is the maximum offset value
guarantee(_array->offset_array(landing_card) <= N_words, "Offset value");
}
+ last_entry = entry; // remember for monotonicity test
}
}
@@ -243,7 +250,7 @@
void
BlockOffsetArray::do_block_internal(HeapWord* blk_start,
HeapWord* blk_end,
- Action action) {
+ Action action, bool reducing) {
assert(Universe::heap()->is_in_reserved(blk_start),
"reference must be into the heap");
assert(Universe::heap()->is_in_reserved(blk_end-1),
@@ -275,18 +282,18 @@
switch (action) {
case Action_mark: {
if (init_to_zero()) {
- _array->set_offset_array(start_index, boundary, blk_start);
+ _array->set_offset_array(start_index, boundary, blk_start, reducing);
break;
} // Else fall through to the next case
}
case Action_single: {
- _array->set_offset_array(start_index, boundary, blk_start);
+ _array->set_offset_array(start_index, boundary, blk_start, reducing);
// We have finished marking the "offset card". We need to now
// mark the subsequent cards that this blk spans.
if (start_index < end_index) {
HeapWord* rem_st = _array->address_for_index(start_index) + N_words;
HeapWord* rem_end = _array->address_for_index(end_index) + N_words;
- set_remainder_to_point_to_start(rem_st, rem_end);
+ set_remainder_to_point_to_start(rem_st, rem_end, reducing);
}
break;
}
@@ -395,7 +402,7 @@
// Indices for starts of prefix block and suffix block.
size_t pref_index = _array->index_for(pref_addr);
if (_array->address_for_index(pref_index) != pref_addr) {
- // pref_addr deos not begin pref_index
+ // pref_addr does not begin pref_index
pref_index++;
}
@@ -430,18 +437,18 @@
if (num_suff_cards > 0) {
HeapWord* boundary = _array->address_for_index(suff_index);
// Set the offset card for suffix block
- _array->set_offset_array(suff_index, boundary, suff_addr);
+ _array->set_offset_array(suff_index, boundary, suff_addr, true /* reducing */);
// Change any further cards that need changing in the suffix
if (num_pref_cards > 0) {
if (num_pref_cards >= num_suff_cards) {
// Unilaterally fix all of the suffix cards: closed card
// index interval in args below.
- set_remainder_to_point_to_start_incl(suff_index + 1, end_index - 1);
+ set_remainder_to_point_to_start_incl(suff_index + 1, end_index - 1, true /* reducing */);
} else {
// Unilaterally fix the first (num_pref_cards - 1) following
// the "offset card" in the suffix block.
set_remainder_to_point_to_start_incl(suff_index + 1,
- suff_index + num_pref_cards - 1);
+ suff_index + num_pref_cards - 1, true /* reducing */);
// Fix the appropriate cards in the remainder of the
// suffix block -- these are the last num_pref_cards
// cards in each power block of the "new" range plumbed
@@ -461,7 +468,7 @@
// is non-null.
if (left_index <= right_index) {
_array->set_offset_array(left_index, right_index,
- N_words + i - 1);
+ N_words + i - 1, true /* reducing */);
} else {
more = false; // we are done
}
@@ -482,7 +489,7 @@
more = false;
}
assert(left_index <= right_index, "Error");
- _array->set_offset_array(left_index, right_index, N_words + i - 1);
+ _array->set_offset_array(left_index, right_index, N_words + i - 1, true /* reducing */);
i++;
}
}
@@ -501,14 +508,13 @@
// any cards subsequent to the first one.
void
BlockOffsetArrayNonContigSpace::mark_block(HeapWord* blk_start,
- HeapWord* blk_end) {
- do_block_internal(blk_start, blk_end, Action_mark);
+ HeapWord* blk_end, bool reducing) {
+ do_block_internal(blk_start, blk_end, Action_mark, reducing);
}
HeapWord* BlockOffsetArrayNonContigSpace::block_start_unsafe(
const void* addr) const {
assert(_array->offset_array(0) == 0, "objects can't cross covered areas");
-
assert(_bottom <= addr && addr < _end,
"addr must be covered by this Array");
// Must read this exactly once because it can be modified by parallel
@@ -542,9 +548,10 @@
debug_only(HeapWord* last = q); // for debugging
q = n;
n += _sp->block_size(n);
+ assert(n > q, err_msg("Looping at: " INTPTR_FORMAT, n));
}
- assert(q <= addr, "wrong order for current and arg");
- assert(addr <= n, "wrong order for arg and next");
+ assert(q <= addr, err_msg("wrong order for current (" INTPTR_FORMAT ") <= arg (" INTPTR_FORMAT ")", q, addr));
+ assert(addr <= n, err_msg("wrong order for arg (" INTPTR_FORMAT ") <= next (" INTPTR_FORMAT ")", addr, n));
return q;
}
@@ -727,9 +734,8 @@
_next_offset_index = end_index + 1;
// Calculate _next_offset_threshold this way because end_index
// may be the last valid index in the covered region.
- _next_offset_threshold = _array->address_for_index(end_index) +
- N_words;
- assert(_next_offset_threshold >= blk_end, "Incorrent offset threshold");
+ _next_offset_threshold = _array->address_for_index(end_index) + N_words;
+ assert(_next_offset_threshold >= blk_end, "Incorrect offset threshold");
#ifdef ASSERT
// The offset can be 0 if the block starts on a boundary. That
--- a/hotspot/src/share/vm/memory/blockOffsetTable.hpp Wed Sep 08 14:04:18 2010 -0700
+++ b/hotspot/src/share/vm/memory/blockOffsetTable.hpp Wed Jul 05 17:21:22 2017 +0200
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2000, 2009, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2000, 2010, 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
@@ -107,6 +107,8 @@
N_words = 1 << LogN_words
};
+ bool _init_to_zero;
+
// The reserved region covered by the shared array.
MemRegion _reserved;
@@ -125,17 +127,28 @@
assert(index < _vs.committed_size(), "index out of range");
return _offset_array[index];
}
- void set_offset_array(size_t index, u_char offset) {
+ // An assertion-checking helper method for the set_offset_array() methods below.
+ void check_reducing_assertion(bool reducing);
+
+ void set_offset_array(size_t index, u_char offset, bool reducing = false) {
+ check_reducing_assertion(reducing);
assert(index < _vs.committed_size(), "index out of range");
+ assert(!reducing || _offset_array[index] >= offset, "Not reducing");
_offset_array[index] = offset;
}
- void set_offset_array(size_t index, HeapWord* high, HeapWord* low) {
+
+ void set_offset_array(size_t index, HeapWord* high, HeapWord* low, bool reducing = false) {
+ check_reducing_assertion(reducing);
assert(index < _vs.committed_size(), "index out of range");
assert(high >= low, "addresses out of order");
assert(pointer_delta(high, low) <= N_words, "offset too large");
+ assert(!reducing || _offset_array[index] >= (u_char)pointer_delta(high, low),
+ "Not reducing");
_offset_array[index] = (u_char)pointer_delta(high, low);
}
- void set_offset_array(HeapWord* left, HeapWord* right, u_char offset) {
+
+ void set_offset_array(HeapWord* left, HeapWord* right, u_char offset, bool reducing = false) {
+ check_reducing_assertion(reducing);
assert(index_for(right - 1) < _vs.committed_size(),
"right address out of range");
assert(left < right, "Heap addresses out of order");
@@ -150,12 +163,15 @@
size_t i = index_for(left);
const size_t end = i + num_cards;
for (; i < end; i++) {
+ // Elided until CR 6977974 is fixed properly.
+ // assert(!reducing || _offset_array[i] >= offset, "Not reducing");
_offset_array[i] = offset;
}
}
}
- void set_offset_array(size_t left, size_t right, u_char offset) {
+ void set_offset_array(size_t left, size_t right, u_char offset, bool reducing = false) {
+ check_reducing_assertion(reducing);
assert(right < _vs.committed_size(), "right address out of range");
assert(left <= right, "indexes out of order");
size_t num_cards = right - left + 1;
@@ -169,6 +185,8 @@
size_t i = left;
const size_t end = i + num_cards;
for (; i < end; i++) {
+ // Elided until CR 6977974 is fixed properly.
+ // assert(!reducing || _offset_array[i] >= offset, "Not reducing");
_offset_array[i] = offset;
}
}
@@ -212,6 +230,11 @@
void set_bottom(HeapWord* new_bottom);
+ // Whether entries should be initialized to zero. Used currently only for
+ // error checking.
+ void set_init_to_zero(bool val) { _init_to_zero = val; }
+ bool init_to_zero() { return _init_to_zero; }
+
// Updates all the BlockOffsetArray's sharing this shared array to
// reflect the current "top"'s of their spaces.
void update_offset_arrays(); // Not yet implemented!
@@ -285,17 +308,23 @@
// initialized to point backwards to the beginning of the covered region.
bool _init_to_zero;
+ // An assertion-checking helper method for the set_remainder*() methods below.
+ void check_reducing_assertion(bool reducing) { _array->check_reducing_assertion(reducing); }
+
// Sets the entries
// corresponding to the cards starting at "start" and ending at "end"
// to point back to the card before "start": the interval [start, end)
- // is right-open.
- void set_remainder_to_point_to_start(HeapWord* start, HeapWord* end);
+ // is right-open. The last parameter, reducing, indicates whether the
+ // updates to individual entries always reduce the entry from a higher
+ // to a lower value. (For example this would hold true during a temporal
+ // regime during which only block splits were updating the BOT.
+ void set_remainder_to_point_to_start(HeapWord* start, HeapWord* end, bool reducing = false);
// Same as above, except that the args here are a card _index_ interval
// that is closed: [start_index, end_index]
- void set_remainder_to_point_to_start_incl(size_t start, size_t end);
+ void set_remainder_to_point_to_start_incl(size_t start, size_t end, bool reducing = false);
// A helper function for BOT adjustment/verification work
- void do_block_internal(HeapWord* blk_start, HeapWord* blk_end, Action action);
+ void do_block_internal(HeapWord* blk_start, HeapWord* blk_end, Action action, bool reducing = false);
public:
// The space may not have its bottom and top set yet, which is why the
@@ -303,7 +332,7 @@
// elements of the array are initialized to zero. Otherwise, they are
// initialized to point backwards to the beginning.
BlockOffsetArray(BlockOffsetSharedArray* array, MemRegion mr,
- bool init_to_zero);
+ bool init_to_zero_);
// Note: this ought to be part of the constructor, but that would require
// "this" to be passed as a parameter to a member constructor for
@@ -358,6 +387,12 @@
// If true, initialize array slots with no allocated blocks to zero.
// Otherwise, make them point back to the front.
bool init_to_zero() { return _init_to_zero; }
+ // Corresponding setter
+ void set_init_to_zero(bool val) {
+ _init_to_zero = val;
+ assert(_array != NULL, "_array should be non-NULL");
+ _array->set_init_to_zero(val);
+ }
// Debugging
// Return the index of the last entry in the "active" region.
@@ -424,16 +459,16 @@
// of BOT is touched. It is assumed (and verified in the
// non-product VM) that the remaining cards of the block
// are correct.
- void mark_block(HeapWord* blk_start, HeapWord* blk_end);
- void mark_block(HeapWord* blk, size_t size) {
- mark_block(blk, blk + size);
+ void mark_block(HeapWord* blk_start, HeapWord* blk_end, bool reducing = false);
+ void mark_block(HeapWord* blk, size_t size, bool reducing = false) {
+ mark_block(blk, blk + size, reducing);
}
// Adjust _unallocated_block to indicate that a particular
// block has been newly allocated or freed. It is assumed (and
// verified in the non-product VM) that the BOT is correct for
// the given block.
- void allocated(HeapWord* blk_start, HeapWord* blk_end) {
+ void allocated(HeapWord* blk_start, HeapWord* blk_end, bool reducing = false) {
// Verify that the BOT shows [blk, blk + blk_size) to be one block.
verify_single_block(blk_start, blk_end);
if (BlockOffsetArrayUseUnallocatedBlock) {
@@ -441,14 +476,12 @@
}
}
- void allocated(HeapWord* blk, size_t size) {
- allocated(blk, blk + size);
+ void allocated(HeapWord* blk, size_t size, bool reducing = false) {
+ allocated(blk, blk + size, reducing);
}
void freed(HeapWord* blk_start, HeapWord* blk_end);
- void freed(HeapWord* blk, size_t size) {
- freed(blk, blk + size);
- }
+ void freed(HeapWord* blk, size_t size);
HeapWord* block_start_unsafe(const void* addr) const;
@@ -456,7 +489,6 @@
// start of the block that contains the given address.
HeapWord* block_start_careful(const void* addr) const;
-
// Verification & debugging: ensure that the offset table reflects
// the fact that the block [blk_start, blk_end) or [blk, blk + size)
// is a single block of storage. NOTE: can't const this because of
--- a/hotspot/src/share/vm/memory/blockOffsetTable.inline.hpp Wed Sep 08 14:04:18 2010 -0700
+++ b/hotspot/src/share/vm/memory/blockOffsetTable.inline.hpp Wed Jul 05 17:21:22 2017 +0200
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2000, 2002, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2000, 2010, 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
@@ -55,10 +55,22 @@
return result;
}
+inline void BlockOffsetSharedArray::check_reducing_assertion(bool reducing) {
+ assert(reducing || !SafepointSynchronize::is_at_safepoint() || init_to_zero() ||
+ Thread::current()->is_VM_thread() ||
+ Thread::current()->is_ConcurrentGC_thread() ||
+ ((!Thread::current()->is_ConcurrentGC_thread()) &&
+ ParGCRareEvent_lock->owned_by_self()), "Crack");
+}
//////////////////////////////////////////////////////////////////////////
// BlockOffsetArrayNonContigSpace inlines
//////////////////////////////////////////////////////////////////////////
+inline void BlockOffsetArrayNonContigSpace::freed(HeapWord* blk,
+ size_t size) {
+ freed(blk, blk + size);
+}
+
inline void BlockOffsetArrayNonContigSpace::freed(HeapWord* blk_start,
HeapWord* blk_end) {
// Verify that the BOT shows [blk_start, blk_end) to be one block.
--- a/hotspot/src/share/vm/oops/arrayKlassKlass.cpp Wed Sep 08 14:04:18 2010 -0700
+++ b/hotspot/src/share/vm/oops/arrayKlassKlass.cpp Wed Jul 05 17:21:22 2017 +0200
@@ -108,10 +108,6 @@
}
#ifndef SERIALGC
-void arrayKlassKlass::oop_copy_contents(PSPromotionManager* pm, oop obj) {
- assert(obj->blueprint()->oop_is_arrayKlass(),"must be an array klass");
-}
-
void arrayKlassKlass::oop_push_contents(PSPromotionManager* pm, oop obj) {
assert(obj->blueprint()->oop_is_arrayKlass(),"must be an array klass");
}
--- a/hotspot/src/share/vm/oops/compiledICHolderKlass.cpp Wed Sep 08 14:04:18 2010 -0700
+++ b/hotspot/src/share/vm/oops/compiledICHolderKlass.cpp Wed Jul 05 17:21:22 2017 +0200
@@ -120,10 +120,6 @@
}
#ifndef SERIALGC
-void compiledICHolderKlass::oop_copy_contents(PSPromotionManager* pm, oop obj) {
- assert(obj->is_compiledICHolder(), "must be compiledICHolder");
-}
-
void compiledICHolderKlass::oop_push_contents(PSPromotionManager* pm, oop obj) {
assert(obj->is_compiledICHolder(), "must be compiledICHolder");
}
--- a/hotspot/src/share/vm/oops/constMethodKlass.cpp Wed Sep 08 14:04:18 2010 -0700
+++ b/hotspot/src/share/vm/oops/constMethodKlass.cpp Wed Jul 05 17:21:22 2017 +0200
@@ -157,10 +157,6 @@
}
#ifndef SERIALGC
-void constMethodKlass::oop_copy_contents(PSPromotionManager* pm, oop obj) {
- assert(obj->is_constMethod(), "should be constMethod");
-}
-
void constMethodKlass::oop_push_contents(PSPromotionManager* pm, oop obj) {
assert(obj->is_constMethod(), "should be constMethod");
}
--- a/hotspot/src/share/vm/oops/constantPoolKlass.cpp Wed Sep 08 14:04:18 2010 -0700
+++ b/hotspot/src/share/vm/oops/constantPoolKlass.cpp Wed Jul 05 17:21:22 2017 +0200
@@ -268,21 +268,6 @@
return cp->object_size();
}
-void constantPoolKlass::oop_copy_contents(PSPromotionManager* pm, oop obj) {
- assert(obj->is_constantPool(), "should be constant pool");
- constantPoolOop cp = (constantPoolOop) obj;
- if (AnonymousClasses && cp->has_pseudo_string() && cp->tags() != NULL) {
- oop* base = (oop*)cp->base();
- for (int i = 0; i < cp->length(); ++i, ++base) {
- if (cp->tag_at(i).is_string()) {
- if (PSScavenge::should_scavenge(base)) {
- pm->claim_or_forward_breadth(base);
- }
- }
- }
- }
-}
-
void constantPoolKlass::oop_push_contents(PSPromotionManager* pm, oop obj) {
assert(obj->is_constantPool(), "should be constant pool");
constantPoolOop cp = (constantPoolOop) obj;
--- a/hotspot/src/share/vm/oops/cpCacheKlass.cpp Wed Sep 08 14:04:18 2010 -0700
+++ b/hotspot/src/share/vm/oops/cpCacheKlass.cpp Wed Jul 05 17:21:22 2017 +0200
@@ -166,29 +166,6 @@
}
#ifndef SERIALGC
-void constantPoolCacheKlass::oop_copy_contents(PSPromotionManager* pm,
- oop obj) {
- assert(obj->is_constantPoolCache(), "should be constant pool");
- if (EnableInvokeDynamic) {
- constantPoolCacheOop cache = (constantPoolCacheOop)obj;
- // during a scavenge, it is safe to inspect my pool, since it is perm
- constantPoolOop pool = cache->constant_pool();
- assert(pool->is_constantPool(), "should be constant pool");
- if (pool->has_invokedynamic()) {
- for (int i = 0; i < cache->length(); i++) {
- ConstantPoolCacheEntry* e = cache->entry_at(i);
- oop* p = (oop*)&e->_f1;
- if (e->is_secondary_entry()) {
- if (PSScavenge::should_scavenge(p))
- pm->claim_or_forward_breadth(p);
- assert(!(e->is_vfinal() && PSScavenge::should_scavenge((oop*)&e->_f2)),
- "no live oops here");
- }
- }
- }
- }
-}
-
void constantPoolCacheKlass::oop_push_contents(PSPromotionManager* pm,
oop obj) {
assert(obj->is_constantPoolCache(), "should be constant pool");
--- a/hotspot/src/share/vm/oops/instanceKlass.cpp Wed Sep 08 14:04:18 2010 -0700
+++ b/hotspot/src/share/vm/oops/instanceKlass.cpp Wed Jul 05 17:21:22 2017 +0200
@@ -1809,18 +1809,7 @@
}
#ifndef SERIALGC
-void instanceKlass::oop_copy_contents(PSPromotionManager* pm, oop obj) {
- assert(!pm->depth_first(), "invariant");
- InstanceKlass_OOP_MAP_REVERSE_ITERATE( \
- obj, \
- if (PSScavenge::should_scavenge(p)) { \
- pm->claim_or_forward_breadth(p); \
- }, \
- assert_nothing )
-}
-
void instanceKlass::oop_push_contents(PSPromotionManager* pm, oop obj) {
- assert(pm->depth_first(), "invariant");
InstanceKlass_OOP_MAP_REVERSE_ITERATE( \
obj, \
if (PSScavenge::should_scavenge(p)) { \
@@ -1846,18 +1835,7 @@
return size_helper();
}
-void instanceKlass::copy_static_fields(PSPromotionManager* pm) {
- assert(!pm->depth_first(), "invariant");
- InstanceKlass_OOP_ITERATE( \
- start_of_static_fields(), static_oop_field_size(), \
- if (PSScavenge::should_scavenge(p)) { \
- pm->claim_or_forward_breadth(p); \
- }, \
- assert_nothing )
-}
-
void instanceKlass::push_static_fields(PSPromotionManager* pm) {
- assert(pm->depth_first(), "invariant");
InstanceKlass_OOP_ITERATE( \
start_of_static_fields(), static_oop_field_size(), \
if (PSScavenge::should_scavenge(p)) { \
--- a/hotspot/src/share/vm/oops/instanceKlass.hpp Wed Sep 08 14:04:18 2010 -0700
+++ b/hotspot/src/share/vm/oops/instanceKlass.hpp Wed Jul 05 17:21:22 2017 +0200
@@ -711,7 +711,6 @@
#ifndef SERIALGC
// Parallel Scavenge
- void copy_static_fields(PSPromotionManager* pm);
void push_static_fields(PSPromotionManager* pm);
// Parallel Old
--- a/hotspot/src/share/vm/oops/instanceKlassKlass.cpp Wed Sep 08 14:04:18 2010 -0700
+++ b/hotspot/src/share/vm/oops/instanceKlassKlass.cpp Wed Jul 05 17:21:22 2017 +0200
@@ -292,41 +292,7 @@
}
#ifndef SERIALGC
-void instanceKlassKlass::oop_copy_contents(PSPromotionManager* pm, oop obj) {
- assert(!pm->depth_first(), "invariant");
- instanceKlass* ik = instanceKlass::cast(klassOop(obj));
- ik->copy_static_fields(pm);
-
- oop* loader_addr = ik->adr_class_loader();
- if (PSScavenge::should_scavenge(loader_addr)) {
- pm->claim_or_forward_breadth(loader_addr);
- }
-
- oop* pd_addr = ik->adr_protection_domain();
- if (PSScavenge::should_scavenge(pd_addr)) {
- pm->claim_or_forward_breadth(pd_addr);
- }
-
- oop* hk_addr = ik->adr_host_klass();
- if (PSScavenge::should_scavenge(hk_addr)) {
- pm->claim_or_forward_breadth(hk_addr);
- }
-
- oop* sg_addr = ik->adr_signers();
- if (PSScavenge::should_scavenge(sg_addr)) {
- pm->claim_or_forward_breadth(sg_addr);
- }
-
- oop* bsm_addr = ik->adr_bootstrap_method();
- if (PSScavenge::should_scavenge(bsm_addr)) {
- pm->claim_or_forward_breadth(bsm_addr);
- }
-
- klassKlass::oop_copy_contents(pm, obj);
-}
-
void instanceKlassKlass::oop_push_contents(PSPromotionManager* pm, oop obj) {
- assert(pm->depth_first(), "invariant");
instanceKlass* ik = instanceKlass::cast(klassOop(obj));
ik->push_static_fields(pm);
@@ -355,7 +321,7 @@
pm->claim_or_forward_depth(bsm_addr);
}
- klassKlass::oop_copy_contents(pm, obj);
+ klassKlass::oop_push_contents(pm, obj);
}
int instanceKlassKlass::oop_update_pointers(ParCompactionManager* cm, oop obj) {
--- a/hotspot/src/share/vm/oops/instanceRefKlass.cpp Wed Sep 08 14:04:18 2010 -0700
+++ b/hotspot/src/share/vm/oops/instanceRefKlass.cpp Wed Jul 05 17:21:22 2017 +0200
@@ -273,41 +273,8 @@
#ifndef SERIALGC
template <class T>
-void specialized_oop_copy_contents(instanceRefKlass *ref,
- PSPromotionManager* pm, oop obj) {
- assert(!pm->depth_first(), "invariant");
- T* referent_addr = (T*)java_lang_ref_Reference::referent_addr(obj);
- if (PSScavenge::should_scavenge(referent_addr)) {
- ReferenceProcessor* rp = PSScavenge::reference_processor();
- if (rp->discover_reference(obj, ref->reference_type())) {
- // reference already enqueued, referent and next will be traversed later
- ref->instanceKlass::oop_copy_contents(pm, obj);
- return;
- } else {
- // treat referent as normal oop
- pm->claim_or_forward_breadth(referent_addr);
- }
- }
- // treat next as normal oop
- T* next_addr = (T*)java_lang_ref_Reference::next_addr(obj);
- if (PSScavenge::should_scavenge(next_addr)) {
- pm->claim_or_forward_breadth(next_addr);
- }
- ref->instanceKlass::oop_copy_contents(pm, obj);
-}
-
-void instanceRefKlass::oop_copy_contents(PSPromotionManager* pm, oop obj) {
- if (UseCompressedOops) {
- specialized_oop_copy_contents<narrowOop>(this, pm, obj);
- } else {
- specialized_oop_copy_contents<oop>(this, pm, obj);
- }
-}
-
-template <class T>
void specialized_oop_push_contents(instanceRefKlass *ref,
PSPromotionManager* pm, oop obj) {
- assert(pm->depth_first(), "invariant");
T* referent_addr = (T*)java_lang_ref_Reference::referent_addr(obj);
if (PSScavenge::should_scavenge(referent_addr)) {
ReferenceProcessor* rp = PSScavenge::reference_processor();
--- a/hotspot/src/share/vm/oops/klassKlass.cpp Wed Sep 08 14:04:18 2010 -0700
+++ b/hotspot/src/share/vm/oops/klassKlass.cpp Wed Jul 05 17:21:22 2017 +0200
@@ -161,9 +161,6 @@
}
#ifndef SERIALGC
-void klassKlass::oop_copy_contents(PSPromotionManager* pm, oop obj) {
-}
-
void klassKlass::oop_push_contents(PSPromotionManager* pm, oop obj) {
}
--- a/hotspot/src/share/vm/oops/klassPS.hpp Wed Sep 08 14:04:18 2010 -0700
+++ b/hotspot/src/share/vm/oops/klassPS.hpp Wed Jul 05 17:21:22 2017 +0200
@@ -28,7 +28,6 @@
#ifndef SERIALGC
#define PARALLEL_GC_DECLS \
- virtual void oop_copy_contents(PSPromotionManager* pm, oop obj); \
virtual void oop_push_contents(PSPromotionManager* pm, oop obj); \
/* Parallel Old GC support \
\
@@ -43,7 +42,6 @@
// Pure virtual version for klass.hpp
#define PARALLEL_GC_DECLS_PV \
- virtual void oop_copy_contents(PSPromotionManager* pm, oop obj) = 0; \
virtual void oop_push_contents(PSPromotionManager* pm, oop obj) = 0; \
virtual void oop_follow_contents(ParCompactionManager* cm, oop obj) = 0; \
virtual int oop_update_pointers(ParCompactionManager* cm, oop obj) = 0; \
--- a/hotspot/src/share/vm/oops/methodDataKlass.cpp Wed Sep 08 14:04:18 2010 -0700
+++ b/hotspot/src/share/vm/oops/methodDataKlass.cpp Wed Jul 05 17:21:22 2017 +0200
@@ -154,13 +154,6 @@
#ifndef SERIALGC
-void methodDataKlass::oop_copy_contents(PSPromotionManager* pm, oop obj) {
- assert (obj->is_methodData(), "object must be method data");
- methodDataOop m = methodDataOop(obj);
- // This should never point into the young gen.
- assert(!PSScavenge::should_scavenge(m->adr_method()), "Sanity");
-}
-
void methodDataKlass::oop_push_contents(PSPromotionManager* pm, oop obj) {
assert (obj->is_methodData(), "object must be method data");
methodDataOop m = methodDataOop(obj);
--- a/hotspot/src/share/vm/oops/methodKlass.cpp Wed Sep 08 14:04:18 2010 -0700
+++ b/hotspot/src/share/vm/oops/methodKlass.cpp Wed Jul 05 17:21:22 2017 +0200
@@ -184,10 +184,6 @@
}
#ifndef SERIALGC
-void methodKlass::oop_copy_contents(PSPromotionManager* pm, oop obj) {
- assert(obj->is_method(), "should be method");
-}
-
void methodKlass::oop_push_contents(PSPromotionManager* pm, oop obj) {
assert(obj->is_method(), "should be method");
}
--- a/hotspot/src/share/vm/oops/objArrayKlass.cpp Wed Sep 08 14:04:18 2010 -0700
+++ b/hotspot/src/share/vm/oops/objArrayKlass.cpp Wed Jul 05 17:21:22 2017 +0200
@@ -426,18 +426,7 @@
}
#ifndef SERIALGC
-void objArrayKlass::oop_copy_contents(PSPromotionManager* pm, oop obj) {
- assert(!pm->depth_first(), "invariant");
- assert(obj->is_objArray(), "obj must be obj array");
- ObjArrayKlass_OOP_ITERATE( \
- objArrayOop(obj), p, \
- if (PSScavenge::should_scavenge(p)) { \
- pm->claim_or_forward_breadth(p); \
- })
-}
-
void objArrayKlass::oop_push_contents(PSPromotionManager* pm, oop obj) {
- assert(pm->depth_first(), "invariant");
assert(obj->is_objArray(), "obj must be obj array");
ObjArrayKlass_OOP_ITERATE( \
objArrayOop(obj), p, \
--- a/hotspot/src/share/vm/oops/objArrayKlassKlass.cpp Wed Sep 08 14:04:18 2010 -0700
+++ b/hotspot/src/share/vm/oops/objArrayKlassKlass.cpp Wed Jul 05 17:21:22 2017 +0200
@@ -229,10 +229,6 @@
}
#ifndef SERIALGC
-void objArrayKlassKlass::oop_copy_contents(PSPromotionManager* pm, oop obj) {
- assert(obj->blueprint()->oop_is_objArrayKlass(),"must be an obj array klass");
-}
-
void objArrayKlassKlass::oop_push_contents(PSPromotionManager* pm, oop obj) {
assert(obj->blueprint()->oop_is_objArrayKlass(),"must be an obj array klass");
}
--- a/hotspot/src/share/vm/oops/oop.hpp Wed Sep 08 14:04:18 2010 -0700
+++ b/hotspot/src/share/vm/oops/oop.hpp Wed Jul 05 17:21:22 2017 +0200
@@ -306,7 +306,6 @@
#ifndef SERIALGC
// Parallel Scavenge
- void copy_contents(PSPromotionManager* pm);
void push_contents(PSPromotionManager* pm);
// Parallel Old
--- a/hotspot/src/share/vm/oops/oop.psgc.inline.hpp Wed Sep 08 14:04:18 2010 -0700
+++ b/hotspot/src/share/vm/oops/oop.psgc.inline.hpp Wed Jul 05 17:21:22 2017 +0200
@@ -24,15 +24,6 @@
// ParallelScavengeHeap methods
-inline void oopDesc::copy_contents(PSPromotionManager* pm) {
- Klass* klass = blueprint();
- if (!klass->oop_is_typeArray()) {
- // It might contain oops beyond the header, so take the virtual call.
- klass->oop_copy_contents(pm, this);
- }
- // Else skip it. The typeArrayKlass in the header never needs scavenging.
-}
-
inline void oopDesc::push_contents(PSPromotionManager* pm) {
Klass* klass = blueprint();
if (!klass->oop_is_typeArray()) {
--- a/hotspot/src/share/vm/oops/symbolKlass.cpp Wed Sep 08 14:04:18 2010 -0700
+++ b/hotspot/src/share/vm/oops/symbolKlass.cpp Wed Jul 05 17:21:22 2017 +0200
@@ -184,10 +184,6 @@
#ifndef SERIALGC
-void symbolKlass::oop_copy_contents(PSPromotionManager* pm, oop obj) {
- assert(obj->is_symbol(), "should be symbol");
-}
-
void symbolKlass::oop_push_contents(PSPromotionManager* pm, oop obj) {
assert(obj->is_symbol(), "should be symbol");
}
--- a/hotspot/src/share/vm/oops/typeArrayKlass.cpp Wed Sep 08 14:04:18 2010 -0700
+++ b/hotspot/src/share/vm/oops/typeArrayKlass.cpp Wed Jul 05 17:21:22 2017 +0200
@@ -228,10 +228,6 @@
}
#ifndef SERIALGC
-void typeArrayKlass::oop_copy_contents(PSPromotionManager* pm, oop obj) {
- assert(obj->is_typeArray(),"must be a type array");
-}
-
void typeArrayKlass::oop_push_contents(PSPromotionManager* pm, oop obj) {
assert(obj->is_typeArray(),"must be a type array");
}
--- a/hotspot/src/share/vm/opto/c2_globals.hpp Wed Sep 08 14:04:18 2010 -0700
+++ b/hotspot/src/share/vm/opto/c2_globals.hpp Wed Jul 05 17:21:22 2017 +0200
@@ -178,6 +178,9 @@
product(bool, ReduceBulkZeroing, true, \
"When bulk-initializing, try to avoid needless zeroing") \
\
+ product(bool, UseFPUForSpilling, false, \
+ "Spill integer registers to FPU instead of stack when possible") \
+ \
develop_pd(intx, RegisterCostAreaRatio, \
"Spill selection in reg allocator: scale area by (X/64K) before " \
"adding cost") \
--- a/hotspot/src/share/vm/opto/coalesce.cpp Wed Sep 08 14:04:18 2010 -0700
+++ b/hotspot/src/share/vm/opto/coalesce.cpp Wed Jul 05 17:21:22 2017 +0200
@@ -780,6 +780,14 @@
// Number of bits free
uint rm_size = rm.Size();
+ if (UseFPUForSpilling && rm.is_AllStack() ) {
+ // Don't coalesce when frequency difference is large
+ Block *dst_b = _phc._cfg._bbs[dst_copy->_idx];
+ Block *src_def_b = _phc._cfg._bbs[src_def->_idx];
+ if (src_def_b->_freq > 10*dst_b->_freq )
+ return false;
+ }
+
// If we can use any stack slot, then effective size is infinite
if( rm.is_AllStack() ) rm_size += 1000000;
// Incompatible masks, no way to coalesce
--- a/hotspot/src/share/vm/opto/matcher.cpp Wed Sep 08 14:04:18 2010 -0700
+++ b/hotspot/src/share/vm/opto/matcher.cpp Wed Jul 05 17:21:22 2017 +0200
@@ -456,6 +456,23 @@
*idealreg2spillmask[Op_RegP] = *idealreg2regmask[Op_RegP];
idealreg2spillmask[Op_RegP]->OR(C->FIRST_STACK_mask());
+ if (UseFPUForSpilling) {
+ // This mask logic assumes that the spill operations are
+ // symmetric and that the registers involved are the same size.
+ // On sparc for instance we may have to use 64 bit moves will
+ // kill 2 registers when used with F0-F31.
+ idealreg2spillmask[Op_RegI]->OR(*idealreg2regmask[Op_RegF]);
+ idealreg2spillmask[Op_RegF]->OR(*idealreg2regmask[Op_RegI]);
+#ifdef _LP64
+ idealreg2spillmask[Op_RegN]->OR(*idealreg2regmask[Op_RegF]);
+ idealreg2spillmask[Op_RegL]->OR(*idealreg2regmask[Op_RegD]);
+ idealreg2spillmask[Op_RegD]->OR(*idealreg2regmask[Op_RegL]);
+ idealreg2spillmask[Op_RegP]->OR(*idealreg2regmask[Op_RegD]);
+#else
+ idealreg2spillmask[Op_RegP]->OR(*idealreg2regmask[Op_RegF]);
+#endif
+ }
+
// Make up debug masks. Any spill slot plus callee-save registers.
// Caller-save registers are assumed to be trashable by the various
// inline-cache fixup routines.
--- a/hotspot/src/share/vm/opto/reg_split.cpp Wed Sep 08 14:04:18 2010 -0700
+++ b/hotspot/src/share/vm/opto/reg_split.cpp Wed Jul 05 17:21:22 2017 +0200
@@ -975,6 +975,19 @@
insidx++; // Reset iterator to skip USE side split
continue;
}
+
+ if (UseFPUForSpilling && n->is_Call() && !uup && !dup ) {
+ // The use at the call can force the def down so insert
+ // a split before the use to allow the def more freedom.
+ maxlrg = split_USE(def,b,n,inpidx,maxlrg,dup,false, splits,slidx);
+ // If it wasn't split bail
+ if (!maxlrg) {
+ return 0;
+ }
+ insidx++; // Reset iterator to skip USE side split
+ continue;
+ }
+
// Here is the logic chart which describes USE Splitting:
// 0 = false or DOWN, 1 = true or UP
//
--- a/hotspot/src/share/vm/runtime/arguments.cpp Wed Sep 08 14:04:18 2010 -0700
+++ b/hotspot/src/share/vm/runtime/arguments.cpp Wed Jul 05 17:21:22 2017 +0200
@@ -184,6 +184,8 @@
{ "DefaultMaxRAM", JDK_Version::jdk_update(6,18), JDK_Version::jdk(7) },
{ "DefaultInitialRAMFraction",
JDK_Version::jdk_update(6,18), JDK_Version::jdk(7) },
+ { "UseDepthFirstScavengeOrder",
+ JDK_Version::jdk_update(6,22), JDK_Version::jdk(7) },
{ NULL, JDK_Version(0), JDK_Version(0) }
};
@@ -3003,10 +3005,6 @@
CommandLineFlags::printSetFlags();
}
- if (PrintFlagsFinal) {
- CommandLineFlags::printFlags();
- }
-
// Apply CPU specific policy for the BiasedLocking
if (UseBiasedLocking) {
if (!VM_Version::use_biased_locking() &&
--- a/hotspot/src/share/vm/runtime/frame.cpp Wed Sep 08 14:04:18 2010 -0700
+++ b/hotspot/src/share/vm/runtime/frame.cpp Wed Jul 05 17:21:22 2017 +0200
@@ -215,17 +215,15 @@
return !nm->is_at_poll_return(pc());
}
-void frame::deoptimize(JavaThread* thread, bool thread_is_known_safe) {
-// Schedule deoptimization of an nmethod activation with this frame.
-
- // Store the original pc before an patch (or request to self-deopt)
- // in the published location of the frame.
-
+void frame::deoptimize(JavaThread* thread) {
+ // Schedule deoptimization of an nmethod activation with this frame.
assert(_cb != NULL && _cb->is_nmethod(), "must be");
nmethod* nm = (nmethod*)_cb;
// This is a fix for register window patching race
- if (NeedsDeoptSuspend && !thread_is_known_safe) {
+ if (NeedsDeoptSuspend && Thread::current() != thread) {
+ assert(SafepointSynchronize::is_at_safepoint(),
+ "patching other threads for deopt may only occur at a safepoint");
// It is possible especially with DeoptimizeALot/DeoptimizeRandom that
// we could see the frame again and ask for it to be deoptimized since
@@ -248,7 +246,11 @@
// whether to spin or block. It isn't worth it. Just treat it like
// native and be done with it.
//
- JavaThreadState state = thread->thread_state();
+ // Examine the state of the thread at the start of safepoint since
+ // threads that were in native at the start of the safepoint could
+ // come to a halt during the safepoint, changing the current value
+ // of the safepoint_state.
+ JavaThreadState state = thread->safepoint_state()->orig_thread_state();
if (state == _thread_in_native || state == _thread_in_native_trans) {
// Since we are at a safepoint the target thread will stop itself
// before it can return to java as long as we remain at the safepoint.
--- a/hotspot/src/share/vm/runtime/frame.hpp Wed Sep 08 14:04:18 2010 -0700
+++ b/hotspot/src/share/vm/runtime/frame.hpp Wed Jul 05 17:21:22 2017 +0200
@@ -174,7 +174,7 @@
address sender_pc() const;
// Support for deoptimization
- void deoptimize(JavaThread* thread, bool thread_is_known_safe = false);
+ void deoptimize(JavaThread* thread);
// The frame's original SP, before any extension by an interpreted callee;
// used for packing debug info into vframeArray objects and vframeArray lookup.
--- a/hotspot/src/share/vm/runtime/globals.hpp Wed Sep 08 14:04:18 2010 -0700
+++ b/hotspot/src/share/vm/runtime/globals.hpp Wed Jul 05 17:21:22 2017 +0200
@@ -1712,7 +1712,7 @@
develop(bool, VerifyBlockOffsetArray, false, \
"Do (expensive!) block offset array verification") \
\
- product(bool, BlockOffsetArrayUseUnallocatedBlock, trueInDebug, \
+ product(bool, BlockOffsetArrayUseUnallocatedBlock, false, \
"Maintain _unallocated_block in BlockOffsetArray" \
" (currently applicable only to CMS collector)") \
\
@@ -3092,10 +3092,6 @@
\
product(intx, SafepointSpinBeforeYield, 2000, "(Unstable)") \
\
- product(bool, UseDepthFirstScavengeOrder, true, \
- "true: the scavenge order will be depth-first, " \
- "false: the scavenge order will be breadth-first") \
- \
product(bool, PSChunkLargeArrays, true, \
"true: process large arrays in chunks") \
\
--- a/hotspot/src/share/vm/runtime/init.cpp Wed Sep 08 14:04:18 2010 -0700
+++ b/hotspot/src/share/vm/runtime/init.cpp Wed Jul 05 17:21:22 2017 +0200
@@ -128,6 +128,12 @@
Universe::verify(); // make sure we're starting with a clean slate
}
+ // All the flags that get adjusted by VM_Version_init and os::init_2
+ // have been set so dump the flags now.
+ if (PrintFlagsFinal) {
+ CommandLineFlags::printFlags();
+ }
+
return JNI_OK;
}
--- a/hotspot/src/share/vm/runtime/orderAccess.cpp Wed Sep 08 14:04:18 2010 -0700
+++ b/hotspot/src/share/vm/runtime/orderAccess.cpp Wed Jul 05 17:21:22 2017 +0200
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2003, 2009, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -25,8 +25,6 @@
# include "incls/_precompiled.incl"
# include "incls/_orderAccess.cpp.incl"
-volatile intptr_t OrderAccess::dummy = 0;
-
void OrderAccess::StubRoutines_fence() {
// Use a stub if it exists. It may not exist during bootstrap so do
// nothing in that case but assert if no fence code exists after threads have been created
--- a/hotspot/src/share/vm/runtime/orderAccess.hpp Wed Sep 08 14:04:18 2010 -0700
+++ b/hotspot/src/share/vm/runtime/orderAccess.hpp Wed Jul 05 17:21:22 2017 +0200
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2003, 2009, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 2010, 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
@@ -166,6 +166,12 @@
// and release must include a sequence point, usually via a volatile memory
// access. Other ways to guarantee a sequence point are, e.g., use of
// indirect calls and linux's __asm__ volatile.
+// Note: as of 6973570, we have replaced the originally static "dummy" field
+// (see above) by a volatile store to the stack. All of the versions of the
+// compilers that we currently use (SunStudio, gcc and VC++) respect the
+// semantics of volatile here. If you build HotSpot using other
+// compilers, you may need to verify that no compiler reordering occurs
+// across the sequence point respresented by the volatile access.
//
//
// os::is_MP Considered Redundant
@@ -297,10 +303,6 @@
static void release_store_ptr_fence(volatile intptr_t* p, intptr_t v);
static void release_store_ptr_fence(volatile void* p, void* v);
- // In order to force a memory access, implementations may
- // need a volatile externally visible dummy variable.
- static volatile intptr_t dummy;
-
private:
// This is a helper that invokes the StubRoutines::fence_entry()
// routine if it exists, It should only be used by platforms that
--- a/hotspot/src/share/vm/runtime/safepoint.cpp Wed Sep 08 14:04:18 2010 -0700
+++ b/hotspot/src/share/vm/runtime/safepoint.cpp Wed Jul 05 17:21:22 2017 +0200
@@ -782,6 +782,9 @@
JavaThreadState state = _thread->thread_state();
+ // Save the state at the start of safepoint processing.
+ _orig_thread_state = state;
+
// Check for a thread that is suspended. Note that thread resume tries
// to grab the Threads_lock which we own here, so a thread cannot be
// resumed during safepoint synchronization.
--- a/hotspot/src/share/vm/runtime/safepoint.hpp Wed Sep 08 14:04:18 2010 -0700
+++ b/hotspot/src/share/vm/runtime/safepoint.hpp Wed Jul 05 17:21:22 2017 +0200
@@ -185,6 +185,7 @@
JavaThread * _thread;
volatile suspend_type _type;
+ JavaThreadState _orig_thread_state;
public:
@@ -199,6 +200,7 @@
JavaThread* thread() const { return _thread; }
suspend_type type() const { return _type; }
bool is_running() const { return (_type==_running); }
+ JavaThreadState orig_thread_state() const { return _orig_thread_state; }
// Support for safepoint timeout (debugging)
bool has_called_back() const { return _has_called_back; }
--- a/hotspot/src/share/vm/runtime/sharedRuntime.cpp Wed Sep 08 14:04:18 2010 -0700
+++ b/hotspot/src/share/vm/runtime/sharedRuntime.cpp Wed Jul 05 17:21:22 2017 +0200
@@ -2493,15 +2493,13 @@
}
// Must unlock before calling set_code
+
// Install the generated code.
if (nm != NULL) {
method->set_code(method, nm);
nm->post_compiled_method_load_event();
} else {
// CodeCache is full, disable compilation
- // Ought to log this but compile log is only per compile thread
- // and we're some non descript Java thread.
- MutexUnlocker mu(AdapterHandlerLibrary_lock);
CompileBroker::handle_full_code_cache();
}
return nm;
--- a/hotspot/src/share/vm/runtime/thread.cpp Wed Sep 08 14:04:18 2010 -0700
+++ b/hotspot/src/share/vm/runtime/thread.cpp Wed Jul 05 17:21:22 2017 +0200
@@ -2110,8 +2110,7 @@
}
if (f.id() == thread->must_deopt_id()) {
thread->clear_must_deopt_id();
- // Since we know we're safe to deopt the current state is a safe state
- f.deoptimize(thread, true);
+ f.deoptimize(thread);
} else {
fatal("missed deoptimization!");
}
--- a/hotspot/src/share/vm/services/management.cpp Wed Sep 08 14:04:18 2010 -0700
+++ b/hotspot/src/share/vm/services/management.cpp Wed Jul 05 17:21:22 2017 +0200
@@ -1900,16 +1900,15 @@
// Get the GCMemoryManager
GCMemoryManager* mgr = get_gc_memory_manager_from_jobject(obj, CHECK);
- if (mgr->last_gc_stat() == NULL) {
- gc_stat->gc_index = 0;
- return;
- }
// Make a copy of the last GC statistics
// GC may occur while constructing the last GC information
int num_pools = MemoryService::num_memory_pools();
GCStatInfo* stat = new GCStatInfo(num_pools);
- stat->copy_stat(mgr->last_gc_stat());
+ if (mgr->get_last_gc_stat(stat) == 0) {
+ gc_stat->gc_index = 0;
+ return;
+ }
gc_stat->gc_index = stat->gc_index();
gc_stat->start_time = Management::ticks_to_ms(stat->start_time());
--- a/hotspot/src/share/vm/services/memoryManager.cpp Wed Sep 08 14:04:18 2010 -0700
+++ b/hotspot/src/share/vm/services/memoryManager.cpp Wed Jul 05 17:21:22 2017 +0200
@@ -166,17 +166,6 @@
FREE_C_HEAP_ARRAY(MemoryUsage*, _after_gc_usage_array);
}
-void GCStatInfo::copy_stat(GCStatInfo* stat) {
- set_index(stat->gc_index());
- set_start_time(stat->start_time());
- set_end_time(stat->end_time());
- assert(_usage_array_size == stat->usage_array_size(), "Must have same array size");
- for (int i = 0; i < _usage_array_size; i++) {
- set_before_gc_usage(i, stat->before_gc_usage_for_pool(i));
- set_after_gc_usage(i, stat->after_gc_usage_for_pool(i));
- }
-}
-
void GCStatInfo::set_gc_usage(int pool_index, MemoryUsage usage, bool before_gc) {
MemoryUsage* gc_usage_array;
if (before_gc) {
@@ -187,67 +176,129 @@
gc_usage_array[pool_index] = usage;
}
+void GCStatInfo::clear() {
+ _index = 0;
+ _start_time = 0L;
+ _end_time = 0L;
+ size_t len = _usage_array_size * sizeof(MemoryUsage);
+ memset(_before_gc_usage_array, 0, len);
+ memset(_after_gc_usage_array, 0, len);
+}
+
+
GCMemoryManager::GCMemoryManager() : MemoryManager() {
_num_collections = 0;
_last_gc_stat = NULL;
+ _last_gc_lock = new Mutex(Mutex::leaf, "_last_gc_lock", true);
+ _current_gc_stat = NULL;
_num_gc_threads = 1;
}
GCMemoryManager::~GCMemoryManager() {
delete _last_gc_stat;
+ delete _last_gc_lock;
+ delete _current_gc_stat;
}
void GCMemoryManager::initialize_gc_stat_info() {
assert(MemoryService::num_memory_pools() > 0, "should have one or more memory pools");
_last_gc_stat = new GCStatInfo(MemoryService::num_memory_pools());
+ _current_gc_stat = new GCStatInfo(MemoryService::num_memory_pools());
+ // tracking concurrent collections we need two objects: one to update, and one to
+ // hold the publicly available "last (completed) gc" information.
}
-void GCMemoryManager::gc_begin() {
- assert(_last_gc_stat != NULL, "Just checking");
- _accumulated_timer.start();
- _num_collections++;
- _last_gc_stat->set_index(_num_collections);
- _last_gc_stat->set_start_time(Management::timestamp());
+void GCMemoryManager::gc_begin(bool recordGCBeginTime, bool recordPreGCUsage,
+ bool recordAccumulatedGCTime) {
+ assert(_last_gc_stat != NULL && _current_gc_stat != NULL, "Just checking");
+ if (recordAccumulatedGCTime) {
+ _accumulated_timer.start();
+ }
+ // _num_collections now increases in gc_end, to count completed collections
+ if (recordGCBeginTime) {
+ _current_gc_stat->set_index(_num_collections+1);
+ _current_gc_stat->set_start_time(Management::timestamp());
+ }
- // Keep memory usage of all memory pools
- for (int i = 0; i < MemoryService::num_memory_pools(); i++) {
- MemoryPool* pool = MemoryService::get_memory_pool(i);
- MemoryUsage usage = pool->get_memory_usage();
- _last_gc_stat->set_before_gc_usage(i, usage);
- HS_DTRACE_PROBE8(hotspot, mem__pool__gc__begin,
- name(), strlen(name()),
- pool->name(), strlen(pool->name()),
- usage.init_size(), usage.used(),
- usage.committed(), usage.max_size());
+ if (recordPreGCUsage) {
+ // Keep memory usage of all memory pools
+ for (int i = 0; i < MemoryService::num_memory_pools(); i++) {
+ MemoryPool* pool = MemoryService::get_memory_pool(i);
+ MemoryUsage usage = pool->get_memory_usage();
+ _current_gc_stat->set_before_gc_usage(i, usage);
+ HS_DTRACE_PROBE8(hotspot, mem__pool__gc__begin,
+ name(), strlen(name()),
+ pool->name(), strlen(pool->name()),
+ usage.init_size(), usage.used(),
+ usage.committed(), usage.max_size());
+ }
}
}
-void GCMemoryManager::gc_end() {
- _accumulated_timer.stop();
- _last_gc_stat->set_end_time(Management::timestamp());
-
- int i;
- // keep the last gc statistics for all memory pools
- for (i = 0; i < MemoryService::num_memory_pools(); i++) {
- MemoryPool* pool = MemoryService::get_memory_pool(i);
- MemoryUsage usage = pool->get_memory_usage();
-
- HS_DTRACE_PROBE8(hotspot, mem__pool__gc__end,
- name(), strlen(name()),
- pool->name(), strlen(pool->name()),
- usage.init_size(), usage.used(),
- usage.committed(), usage.max_size());
-
- _last_gc_stat->set_after_gc_usage(i, usage);
+// A collector MUST, even if it does not complete for some reason,
+// make a TraceMemoryManagerStats object where countCollection is true,
+// to ensure the current gc stat is placed in _last_gc_stat.
+void GCMemoryManager::gc_end(bool recordPostGCUsage,
+ bool recordAccumulatedGCTime,
+ bool recordGCEndTime, bool countCollection) {
+ if (recordAccumulatedGCTime) {
+ _accumulated_timer.stop();
+ }
+ if (recordGCEndTime) {
+ _current_gc_stat->set_end_time(Management::timestamp());
}
- // Set last collection usage of the memory pools managed by this collector
- for (i = 0; i < num_memory_pools(); i++) {
- MemoryPool* pool = get_memory_pool(i);
- MemoryUsage usage = pool->get_memory_usage();
+ if (recordPostGCUsage) {
+ int i;
+ // keep the last gc statistics for all memory pools
+ for (i = 0; i < MemoryService::num_memory_pools(); i++) {
+ MemoryPool* pool = MemoryService::get_memory_pool(i);
+ MemoryUsage usage = pool->get_memory_usage();
+
+ HS_DTRACE_PROBE8(hotspot, mem__pool__gc__end,
+ name(), strlen(name()),
+ pool->name(), strlen(pool->name()),
+ usage.init_size(), usage.used(),
+ usage.committed(), usage.max_size());
+
+ _current_gc_stat->set_after_gc_usage(i, usage);
+ }
- // Compare with GC usage threshold
- pool->set_last_collection_usage(usage);
- LowMemoryDetector::detect_after_gc_memory(pool);
+ // Set last collection usage of the memory pools managed by this collector
+ for (i = 0; i < num_memory_pools(); i++) {
+ MemoryPool* pool = get_memory_pool(i);
+ MemoryUsage usage = pool->get_memory_usage();
+
+ // Compare with GC usage threshold
+ pool->set_last_collection_usage(usage);
+ LowMemoryDetector::detect_after_gc_memory(pool);
+ }
+ }
+ if (countCollection) {
+ _num_collections++;
+ // alternately update two objects making one public when complete
+ {
+ MutexLockerEx ml(_last_gc_lock, Mutex::_no_safepoint_check_flag);
+ GCStatInfo *tmp = _last_gc_stat;
+ _last_gc_stat = _current_gc_stat;
+ _current_gc_stat = tmp;
+ // reset the current stat for diagnosability purposes
+ _current_gc_stat->clear();
+ }
}
}
+
+size_t GCMemoryManager::get_last_gc_stat(GCStatInfo* dest) {
+ MutexLockerEx ml(_last_gc_lock, Mutex::_no_safepoint_check_flag);
+ if (_last_gc_stat->gc_index() != 0) {
+ dest->set_index(_last_gc_stat->gc_index());
+ dest->set_start_time(_last_gc_stat->start_time());
+ dest->set_end_time(_last_gc_stat->end_time());
+ assert(dest->usage_array_size() == _last_gc_stat->usage_array_size(),
+ "Must have same array size");
+ size_t len = dest->usage_array_size() * sizeof(MemoryUsage);
+ memcpy(dest->before_gc_usage_array(), _last_gc_stat->before_gc_usage_array(), len);
+ memcpy(dest->after_gc_usage_array(), _last_gc_stat->after_gc_usage_array(), len);
+ }
+ return _last_gc_stat->gc_index();
+}
--- a/hotspot/src/share/vm/services/memoryManager.hpp Wed Sep 08 14:04:18 2010 -0700
+++ b/hotspot/src/share/vm/services/memoryManager.hpp Wed Jul 05 17:21:22 2017 +0200
@@ -131,6 +131,9 @@
return _after_gc_usage_array[pool_index];
}
+ MemoryUsage* before_gc_usage_array() { return _before_gc_usage_array; }
+ MemoryUsage* after_gc_usage_array() { return _after_gc_usage_array; }
+
void set_index(size_t index) { _index = index; }
void set_start_time(jlong time) { _start_time = time; }
void set_end_time(jlong time) { _end_time = time; }
@@ -143,7 +146,7 @@
set_gc_usage(pool_index, usage, false /* after gc */);
}
- void copy_stat(GCStatInfo* stat);
+ void clear();
};
class GCMemoryManager : public MemoryManager {
@@ -153,6 +156,8 @@
elapsedTimer _accumulated_timer;
elapsedTimer _gc_timer; // for measuring every GC duration
GCStatInfo* _last_gc_stat;
+ Mutex* _last_gc_lock;
+ GCStatInfo* _current_gc_stat;
int _num_gc_threads;
public:
GCMemoryManager();
@@ -166,11 +171,16 @@
int num_gc_threads() { return _num_gc_threads; }
void set_num_gc_threads(int count) { _num_gc_threads = count; }
- void gc_begin();
- void gc_end();
+ void gc_begin(bool recordGCBeginTime, bool recordPreGCUsage,
+ bool recordAccumulatedGCTime);
+ void gc_end(bool recordPostGCUsage, bool recordAccumulatedGCTime,
+ bool recordGCEndTime, bool countCollection);
void reset_gc_stat() { _num_collections = 0; _accumulated_timer.reset(); }
- GCStatInfo* last_gc_stat() { return _last_gc_stat; }
+
+ // Copy out _last_gc_stat to the given destination, returning
+ // the collection count. Zero signifies no gc has taken place.
+ size_t get_last_gc_stat(GCStatInfo* dest);
virtual MemoryManager::Name kind() = 0;
};
--- a/hotspot/src/share/vm/services/memoryService.cpp Wed Sep 08 14:04:18 2010 -0700
+++ b/hotspot/src/share/vm/services/memoryService.cpp Wed Jul 05 17:21:22 2017 +0200
@@ -509,7 +509,10 @@
}
}
-void MemoryService::gc_begin(bool fullGC) {
+void MemoryService::gc_begin(bool fullGC, bool recordGCBeginTime,
+ bool recordAccumulatedGCTime,
+ bool recordPreGCUsage, bool recordPeakUsage) {
+
GCMemoryManager* mgr;
if (fullGC) {
mgr = _major_gc_manager;
@@ -517,16 +520,21 @@
mgr = _minor_gc_manager;
}
assert(mgr->is_gc_memory_manager(), "Sanity check");
- mgr->gc_begin();
+ mgr->gc_begin(recordGCBeginTime, recordPreGCUsage, recordAccumulatedGCTime);
// Track the peak memory usage when GC begins
- for (int i = 0; i < _pools_list->length(); i++) {
- MemoryPool* pool = _pools_list->at(i);
- pool->record_peak_memory_usage();
+ if (recordPeakUsage) {
+ for (int i = 0; i < _pools_list->length(); i++) {
+ MemoryPool* pool = _pools_list->at(i);
+ pool->record_peak_memory_usage();
+ }
}
}
-void MemoryService::gc_end(bool fullGC) {
+void MemoryService::gc_end(bool fullGC, bool recordPostGCUsage,
+ bool recordAccumulatedGCTime,
+ bool recordGCEndTime, bool countCollection) {
+
GCMemoryManager* mgr;
if (fullGC) {
mgr = (GCMemoryManager*) _major_gc_manager;
@@ -536,7 +544,8 @@
assert(mgr->is_gc_memory_manager(), "Sanity check");
// register the GC end statistics and memory usage
- mgr->gc_end();
+ mgr->gc_end(recordPostGCUsage, recordAccumulatedGCTime, recordGCEndTime,
+ countCollection);
}
void MemoryService::oops_do(OopClosure* f) {
@@ -585,12 +594,12 @@
return obj;
}
//
-// GC manager type depends on the type of Generation. Depending the space
-// availablity and vm option the gc uses major gc manager or minor gc
+// GC manager type depends on the type of Generation. Depending on the space
+// availablity and vm options the gc uses major gc manager or minor gc
// manager or both. The type of gc manager depends on the generation kind.
-// For DefNew, ParNew and ASParNew generation doing scavange gc uses minor
-// gc manager (so _fullGC is set to false ) and for other generation kind
-// DOing mark-sweep-compact uses major gc manager (so _fullGC is set
+// For DefNew, ParNew and ASParNew generation doing scavenge gc uses minor
+// gc manager (so _fullGC is set to false ) and for other generation kinds
+// doing mark-sweep-compact uses major gc manager (so _fullGC is set
// to true).
TraceMemoryManagerStats::TraceMemoryManagerStats(Generation::Name kind) {
switch (kind) {
@@ -611,13 +620,48 @@
default:
assert(false, "Unrecognized gc generation kind.");
}
- MemoryService::gc_begin(_fullGC);
+ // this has to be called in a stop the world pause and represent
+ // an entire gc pause, start to finish:
+ initialize(_fullGC, true, true, true, true, true, true, true);
+}
+TraceMemoryManagerStats::TraceMemoryManagerStats(bool fullGC,
+ bool recordGCBeginTime,
+ bool recordPreGCUsage,
+ bool recordPeakUsage,
+ bool recordPostGCUsage,
+ bool recordAccumulatedGCTime,
+ bool recordGCEndTime,
+ bool countCollection) {
+ initialize(fullGC, recordGCBeginTime, recordPreGCUsage, recordPeakUsage,
+ recordPostGCUsage, recordAccumulatedGCTime, recordGCEndTime,
+ countCollection);
}
-TraceMemoryManagerStats::TraceMemoryManagerStats(bool fullGC) {
+
+// for a subclass to create then initialize an instance before invoking
+// the MemoryService
+void TraceMemoryManagerStats::initialize(bool fullGC,
+ bool recordGCBeginTime,
+ bool recordPreGCUsage,
+ bool recordPeakUsage,
+ bool recordPostGCUsage,
+ bool recordAccumulatedGCTime,
+ bool recordGCEndTime,
+ bool countCollection) {
_fullGC = fullGC;
- MemoryService::gc_begin(_fullGC);
+ _recordGCBeginTime = recordGCBeginTime;
+ _recordPreGCUsage = recordPreGCUsage;
+ _recordPeakUsage = recordPeakUsage;
+ _recordPostGCUsage = recordPostGCUsage;
+ _recordAccumulatedGCTime = recordAccumulatedGCTime;
+ _recordGCEndTime = recordGCEndTime;
+ _countCollection = countCollection;
+
+ MemoryService::gc_begin(_fullGC, _recordGCBeginTime, _recordAccumulatedGCTime,
+ _recordPreGCUsage, _recordPeakUsage);
}
TraceMemoryManagerStats::~TraceMemoryManagerStats() {
- MemoryService::gc_end(_fullGC);
+ MemoryService::gc_end(_fullGC, _recordPostGCUsage, _recordAccumulatedGCTime,
+ _recordGCEndTime, _countCollection);
}
+
--- a/hotspot/src/share/vm/services/memoryService.hpp Wed Sep 08 14:04:18 2010 -0700
+++ b/hotspot/src/share/vm/services/memoryService.hpp Wed Jul 05 17:21:22 2017 +0200
@@ -149,8 +149,13 @@
}
static void track_memory_pool_usage(MemoryPool* pool);
- static void gc_begin(bool fullGC);
- static void gc_end(bool fullGC);
+ static void gc_begin(bool fullGC, bool recordGCBeginTime,
+ bool recordAccumulatedGCTime,
+ bool recordPreGCUsage, bool recordPeakUsage);
+ static void gc_end(bool fullGC, bool recordPostGCUsage,
+ bool recordAccumulatedGCTime,
+ bool recordGCEndTime, bool countCollection);
+
static void oops_do(OopClosure* f);
@@ -164,8 +169,34 @@
class TraceMemoryManagerStats : public StackObj {
private:
bool _fullGC;
+ bool _recordGCBeginTime;
+ bool _recordPreGCUsage;
+ bool _recordPeakUsage;
+ bool _recordPostGCUsage;
+ bool _recordAccumulatedGCTime;
+ bool _recordGCEndTime;
+ bool _countCollection;
+
public:
- TraceMemoryManagerStats(bool fullGC);
+ TraceMemoryManagerStats() {}
+ TraceMemoryManagerStats(bool fullGC,
+ bool recordGCBeginTime = true,
+ bool recordPreGCUsage = true,
+ bool recordPeakUsage = true,
+ bool recordPostGCUsage = true,
+ bool recordAccumulatedGCTime = true,
+ bool recordGCEndTime = true,
+ bool countCollection = true);
+
+ void initialize(bool fullGC,
+ bool recordGCBeginTime,
+ bool recordPreGCUsage,
+ bool recordPeakUsage,
+ bool recordPostGCUsage,
+ bool recordAccumulatedGCTime,
+ bool recordGCEndTime,
+ bool countCollection);
+
TraceMemoryManagerStats(Generation::Name kind);
~TraceMemoryManagerStats();
};
--- a/hotspot/src/share/vm/utilities/taskqueue.cpp Wed Sep 08 14:04:18 2010 -0700
+++ b/hotspot/src/share/vm/utilities/taskqueue.cpp Wed Jul 05 17:21:22 2017 +0200
@@ -36,6 +36,14 @@
"qpush", "qpop", "qpop-s", "qattempt", "qsteal", "opush", "omax"
};
+TaskQueueStats & TaskQueueStats::operator +=(const TaskQueueStats & addend)
+{
+ for (unsigned int i = 0; i < last_stat_id; ++i) {
+ _stats[i] += addend._stats[i];
+ }
+ return *this;
+}
+
void TaskQueueStats::print_header(unsigned int line, outputStream* const stream,
unsigned int width)
{
@@ -71,6 +79,29 @@
}
#undef FMT
}
+
+#ifdef ASSERT
+// Invariants which should hold after a TaskQueue has been emptied and is
+// quiescent; they do not hold at arbitrary times.
+void TaskQueueStats::verify() const
+{
+ assert(get(push) == get(pop) + get(steal),
+ err_msg("push=" SIZE_FORMAT " pop=" SIZE_FORMAT " steal=" SIZE_FORMAT,
+ get(push), get(pop), get(steal)));
+ assert(get(pop_slow) <= get(pop),
+ err_msg("pop_slow=" SIZE_FORMAT " pop=" SIZE_FORMAT,
+ get(pop_slow), get(pop)));
+ assert(get(steal) <= get(steal_attempt),
+ err_msg("steal=" SIZE_FORMAT " steal_attempt=" SIZE_FORMAT,
+ get(steal), get(steal_attempt)));
+ assert(get(overflow) == 0 || get(push) != 0,
+ err_msg("overflow=" SIZE_FORMAT " push=" SIZE_FORMAT,
+ get(overflow), get(push)));
+ assert(get(overflow_max_len) == 0 || get(overflow) != 0,
+ err_msg("overflow_max_len=" SIZE_FORMAT " overflow=" SIZE_FORMAT,
+ get(overflow_max_len), get(overflow)));
+}
+#endif // ASSERT
#endif // TASKQUEUE_STATS
int TaskQueueSetSuper::randomParkAndMiller(int *seed0) {
--- a/hotspot/src/share/vm/utilities/taskqueue.hpp Wed Sep 08 14:04:18 2010 -0700
+++ b/hotspot/src/share/vm/utilities/taskqueue.hpp Wed Jul 05 17:21:22 2017 +0200
@@ -59,15 +59,21 @@
inline void record_steal(bool success);
inline void record_overflow(size_t new_length);
+ TaskQueueStats & operator +=(const TaskQueueStats & addend);
+
inline size_t get(StatId id) const { return _stats[id]; }
inline const size_t* get() const { return _stats; }
inline void reset();
+ // Print the specified line of the header (does not include a line separator).
static void print_header(unsigned int line, outputStream* const stream = tty,
unsigned int width = 10);
+ // Print the statistics (does not include a line separator).
void print(outputStream* const stream = tty, unsigned int width = 10) const;
+ DEBUG_ONLY(void verify() const;)
+
private:
size_t _stats[last_stat_id];
static const char * const _names[last_stat_id];
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/compiler/6894807/IsInstanceTest.java Wed Jul 05 17:21:22 2017 +0200
@@ -0,0 +1,44 @@
+/*
+ * @test
+ * @bug 6894807
+ * @summary No ClassCastException for HashAttributeSet constructors if run with -Xcomp
+ * @compile IsInstanceTest.java
+ * @run shell Test6894807.sh
+*/
+
+public class IsInstanceTest {
+
+ public static void main(String[] args) {
+ BaseInterface baseInterfaceImpl = new BaseInterfaceImpl();
+ for (int i = 0; i < 100000; i++) {
+ if (isInstanceOf(baseInterfaceImpl, ExtendedInterface.class)) {
+ System.out.println("Failed at index:" + i);
+ System.out.println("Arch: "+System.getProperty("os.arch", "")+
+ " OS: "+System.getProperty("os.name", "")+
+ " OSV: "+System.getProperty("os.version", "")+
+ " Cores: "+Runtime.getRuntime().availableProcessors()+
+ " JVM: "+System.getProperty("java.version", "")+" "+System.getProperty("sun.arch.data.model", ""));
+ break;
+ }
+ }
+ System.out.println("Done!");
+ }
+
+ public static boolean isInstanceOf(BaseInterface baseInterfaceImpl, Class... baseInterfaceClasses) {
+ for (Class baseInterfaceClass : baseInterfaceClasses) {
+ if (baseInterfaceClass.isInstance(baseInterfaceImpl)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ private interface BaseInterface {
+ }
+
+ private interface ExtendedInterface extends BaseInterface {
+ }
+
+ private static class BaseInterfaceImpl implements BaseInterface {
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/compiler/6894807/Test6894807.sh Wed Jul 05 17:21:22 2017 +0200
@@ -0,0 +1,68 @@
+#!/bin/sh
+
+if [ "${TESTSRC}" = "" ]
+then TESTSRC=.
+fi
+
+if [ "${TESTJAVA}" = "" ]
+then
+ PARENT=`dirname \`which java\``
+ TESTJAVA=`dirname ${PARENT}`
+ echo "TESTJAVA not set, selecting " ${TESTJAVA}
+ echo "If this is incorrect, try setting the variable manually."
+fi
+
+if [ "${TESTCLASSES}" = "" ]
+then
+ echo "TESTCLASSES not set. Test cannot execute. Failed."
+ exit 1
+fi
+
+BIT_FLAG=""
+
+# set platform-dependent variables
+OS=`uname -s`
+case "$OS" in
+ SunOS | Linux )
+ NULL=/dev/null
+ PS=":"
+ FS="/"
+ ## for solaris, linux it's HOME
+ FILE_LOCATION=$HOME
+ if [ -f ${FILE_LOCATION}${FS}JDK64BIT -a ${OS} = "SunOS" ]
+ then
+ BIT_FLAG=`cat ${FILE_LOCATION}${FS}JDK64BIT | grep -v '^#'`
+ fi
+ ;;
+ Windows_* )
+ NULL=NUL
+ PS=";"
+ FS="\\"
+ ;;
+ * )
+ echo "Unrecognized system!"
+ exit 1;
+ ;;
+esac
+
+JEMMYPATH=${CPAPPEND}
+CLASSPATH=.${PS}${TESTCLASSES}${PS}${JEMMYPATH} ; export CLASSPATH
+
+THIS_DIR=`pwd`
+
+${TESTJAVA}${FS}bin${FS}java ${BIT_FLAG} -version
+
+${TESTJAVA}${FS}bin${FS}java ${BIT_FLAG} -server IsInstanceTest > test.out 2>&1
+
+cat test.out
+
+grep "Failed at index" test.out
+
+if [ $? = 0 ]
+then
+ echo "Test Failed"
+ exit 1
+else
+ echo "Test Passed"
+ exit 0
+fi
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/gc/6581734/Test6581734.java Wed Jul 05 17:21:22 2017 +0200
@@ -0,0 +1,149 @@
+/*
+ * Copyright (c) 2010, 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 Test6581734.java
+ * @bug 6581734
+ * @summary CMS Old Gen's collection usage is zero after GC which is incorrect
+ * @run main/othervm -Xmx512m -verbose:gc -XX:+UseConcMarkSweepGC Test6581734
+ *
+ */
+import java.util.*;
+import java.lang.management.*;
+
+// 6581734 states that memory pool usage via the mbean is wrong
+// for CMS (zero, even after a collection).
+//
+// 6580448 states that the collection count similarly is wrong
+// (stays at zero for CMS collections)
+// -- closed as dup of 6581734 as the same fix resolves both.
+
+
+public class Test6581734 {
+
+ private String poolName = "CMS";
+ private String collectorName = "ConcurrentMarkSweep";
+
+ public static void main(String [] args) {
+
+ Test6581734 t = null;
+ if (args.length==2) {
+ t = new Test6581734(args[0], args[1]);
+ } else {
+ System.out.println("Defaulting to monitor CMS pool and collector.");
+ t = new Test6581734();
+ }
+ t.run();
+ }
+
+ public Test6581734(String pool, String collector) {
+ poolName = pool;
+ collectorName = collector;
+ }
+
+ public Test6581734() {
+ }
+
+ public void run() {
+ // Use some memory, enough that we expect collections should
+ // have happened.
+ // Must run with options to ensure no stop the world full GC,
+ // but e.g. at least one CMS cycle.
+ allocationWork(300*1024*1024);
+ System.out.println("Done allocationWork");
+
+ // Verify some non-zero results are stored.
+ List<MemoryPoolMXBean> pools = ManagementFactory.getMemoryPoolMXBeans();
+ int poolsFound = 0;
+ int poolsWithStats = 0;
+ for (int i=0; i<pools.size(); i++) {
+ MemoryPoolMXBean pool = pools.get(i);
+ String name = pool.getName();
+ System.out.println("found pool: " + name);
+
+ if (name.contains(poolName)) {
+ long usage = pool.getCollectionUsage().getUsed();
+ System.out.println(name + ": usage after GC = " + usage);
+ poolsFound++;
+ if (usage > 0) {
+ poolsWithStats++;
+ }
+ }
+ }
+ if (poolsFound == 0) {
+ throw new RuntimeException("No matching memory pools found: test with -XX:+UseConcMarkSweepGC");
+ }
+
+ List<GarbageCollectorMXBean> collectors = ManagementFactory.getGarbageCollectorMXBeans();
+ int collectorsFound = 0;
+ int collectorsWithTime= 0;
+ for (int i=0; i<collectors.size(); i++) {
+ GarbageCollectorMXBean collector = collectors.get(i);
+ String name = collector.getName();
+ System.out.println("found collector: " + name);
+ if (name.contains(collectorName)) {
+ collectorsFound++;
+ System.out.println(name + ": collection count = "
+ + collector.getCollectionCount());
+ System.out.println(name + ": collection time = "
+ + collector.getCollectionTime());
+ if (collector.getCollectionCount() <= 0) {
+ throw new RuntimeException("collection count <= 0");
+ }
+ if (collector.getCollectionTime() > 0) {
+ collectorsWithTime++;
+ }
+ }
+ }
+ // verify:
+ if (poolsWithStats < poolsFound) {
+ throw new RuntimeException("pools found with zero stats");
+ }
+
+ if (collectorsWithTime<collectorsFound) {
+ throw new RuntimeException("collectors found with zero time";
+ }
+ System.out.println("Test passed.");
+ }
+
+ public void allocationWork(long target) {
+
+ long sizeAllocated = 0;
+ List list = new LinkedList();
+ long delay = 50;
+ long count = 0;
+
+ while (sizeAllocated < target) {
+ int size = 1024*1024;
+ byte [] alloc = new byte[size];
+ if (count % 2 == 0) {
+ list.add(alloc);
+ sizeAllocated+=size;
+ System.out.print(".");
+ }
+ try { Thread.sleep(delay); } catch (InterruptedException ie) { }
+ count++;
+ }
+ }
+
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/runtime/6626217/IFace.java Wed Jul 05 17:21:22 2017 +0200
@@ -0,0 +1,6 @@
+// A simple interface, to allow an unknown foreign call from a class
+// loaded with LOADER1 to a class loaded with LOADER2.
+public interface IFace {
+ public many_loader[] gen();
+}
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/runtime/6626217/Loader2.java Wed Jul 05 17:21:22 2017 +0200
@@ -0,0 +1,52 @@
+import java.io.ByteArrayInputStream;
+import java.io.FileInputStream;
+public class Loader2 extends ClassLoader {
+ int _recur;
+ public void print( String msg ) {
+ for( int i=0; i<_recur; i++ )
+ System.out.print(" ");
+ System.out.println(">>Loader2>> "+msg);
+ }
+
+ protected Class findClass2(String name) throws ClassNotFoundException {
+ print("Fetching the implementation of "+name);
+ int old = _recur;
+ try {
+ FileInputStream fi = new FileInputStream(name+".impl2");
+ byte result[] = new byte[fi.available()];
+ fi.read(result);
+
+ print("DefineClass1 on "+name);
+ _recur++;
+ Class clazz = defineClass(name, result, 0, result.length);
+ _recur = old;
+ print("Returning newly loaded class.");
+ return clazz;
+ } catch (Exception e) {
+ _recur = old;
+ print("Not found on disk.");
+ // If we caught an exception, either the class was not found or
+ // it was unreadable by our process.
+ return null;
+ //throw new ClassNotFoundException(e.toString());
+ }
+ }
+
+ protected synchronized Class loadClass(String name, boolean resolve) throws ClassNotFoundException {
+ // Attempt a disk load first
+ Class c = findClass2(name);
+ if( c == null ) {
+ // check if the class has already been loaded
+ print("Checking for prior loaded class "+name);
+ c = findLoadedClass(name);
+ print("Letting super-loader load "+name);
+ int old = _recur;
+ _recur++;
+ c = super.loadClass(name, false);
+ _recur=old;
+ }
+ if (resolve) { print("Resolving class "+name); resolveClass(c); }
+ print("Returning clazz "+c.getClassLoader()+":"+name);
+ return c;
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/runtime/6626217/Test6626217.sh Wed Jul 05 17:21:22 2017 +0200
@@ -0,0 +1,101 @@
+#
+# Copyright 2009 Sun Microsystems, Inc. All rights reserved.
+# SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
+#
+
+#
+# @test @(#)Test6626217.sh
+# @bug 6626217
+# @summary Loader-constraint table allows arrays instead of only the base-classes
+# @run shell Test6626217.sh
+#
+
+if [ "${TESTSRC}" = "" ]
+ then TESTSRC=.
+fi
+
+if [ "${TESTJAVA}" = "" ]
+then
+ PARENT=`dirname \`which java\``
+ TESTJAVA=`dirname ${PARENT}`
+ echo "TESTJAVA not set, selecting " ${TESTJAVA}
+ echo "If this is incorrect, try setting the variable manually."
+fi
+
+if [ "${TESTCLASSES}" = "" ]
+then
+ echo "TESTCLASSES not set. Test cannot execute. Failed."
+ exit 1
+fi
+
+BIT_FLAG=""
+
+# set platform-dependent variables
+OS=`uname -s`
+case "$OS" in
+ SunOS | Linux )
+ NULL=/dev/null
+ PS=":"
+ FS="/"
+ RM=/bin/rm
+ CP=/bin/cp
+ MV=/bin/mv
+ ## for solaris, linux it's HOME
+ FILE_LOCATION=$HOME
+ if [ -f ${FILE_LOCATION}${FS}JDK64BIT -a ${OS} = "SunOS" ]
+ then
+ BIT_FLAG=`cat ${FILE_LOCATION}${FS}JDK64BIT`
+ fi
+ ;;
+ Windows_* )
+ NULL=NUL
+ PS=";"
+ FS="\\"
+ RM=rm
+ CP=cp
+ MV=mv
+ ;;
+ * )
+ echo "Unrecognized system!"
+ exit 1;
+ ;;
+esac
+
+JEMMYPATH=${CPAPPEND}
+CLASSPATH=.${PS}${TESTCLASSES}${PS}${JEMMYPATH} ; export CLASSPATH
+
+THIS_DIR=`pwd`
+
+JAVA=${TESTJAVA}${FS}bin${FS}java
+JAVAC=${TESTJAVA}${FS}bin${FS}javac
+
+${JAVA} ${BIT_FLAG} -version
+
+# Current directory is scratch directory, copy all the test source there
+# (for the subsequent moves to work).
+${CP} ${TESTSRC}${FS}* ${THIS_DIR}
+
+# A Clean Compile: this line will probably fail within jtreg as have a clean dir:
+${RM} -f *.class *.impl many_loader.java
+
+# Compile all the usual suspects, including the default 'many_loader'
+${CP} many_loader1.java.foo many_loader.java
+${JAVAC} -source 1.4 -target 1.4 -Xlint *.java
+
+# Rename the class files, so the custom loader (and not the system loader) will find it
+${MV} from_loader2.class from_loader2.impl2
+
+# Compile the next version of 'many_loader'
+${MV} many_loader.class many_loader.impl1
+${CP} many_loader2.java.foo many_loader.java
+${JAVAC} -source 1.4 -target 1.4 -Xlint many_loader.java
+
+# Rename the class file, so the custom loader (and not the system loader) will find it
+${MV} many_loader.class many_loader.impl2
+${MV} many_loader.impl1 many_loader.class
+${RM} many_loader.java
+
+${JAVA} ${BIT_FLAG} -Xverify -Xint -cp . bug_21227 >test.out 2>&1
+grep "violates loader constraints" test.out
+exit $?
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/runtime/6626217/You_Have_Been_P0wned.java Wed Jul 05 17:21:22 2017 +0200
@@ -0,0 +1,11 @@
+
+// I can cast any old thing I want to this type object:
+public class You_Have_Been_P0wned {
+ // Make a bunch of int-fields so I can peek & poke it
+ int _a;
+ int _b;
+ int _c;
+ int _d;
+
+}
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/runtime/6626217/bug_21227.java Wed Jul 05 17:21:22 2017 +0200
@@ -0,0 +1,61 @@
+
+import java.lang.reflect.*;
+import java.security.*;
+
+abstract public class bug_21227 {
+
+ // Jam anything you want in here, it will be cast to a You_Have_Been_P0wned
+ public static Object _p0wnee;
+
+ public static void main(String argv[]) throws ClassNotFoundException, InstantiationException, IllegalAccessException {
+ System.out.println("Warmup");
+
+ // Make a Class 'many_loader' under the default loader
+ bug_21227 bug = new many_loader();
+
+ // Some classes under a new Loader, LOADER2, including another version of 'many_loader'
+ ClassLoader LOADER2 = new Loader2();
+ Class clazz2 = LOADER2.loadClass("from_loader2");
+ IFace iface = (IFace)clazz2.newInstance();
+
+ // Set the victim, a String of length 6
+ String s = "victim";
+ _p0wnee = s;
+
+ // Go cast '_p0wnee' to type You_Have_Been_P0wned
+ many_loader[] x2 = bug.make(iface);
+
+ many_loader b = x2[0];
+
+ // Make it clear that the runtime type many_loader (what we get from the
+ // array X2) varies from the static type of many_loader.
+ Class cl1 = b.getClass();
+ ClassLoader ld1 = cl1.getClassLoader();
+ Class cl2 = many_loader.class;
+ ClassLoader ld2 = cl2.getClassLoader();
+ System.out.println("bug.make() "+ld1+":"+cl1);
+ System.out.println("many_loader "+ld2+":"+cl2);
+
+ // Read the victims guts out
+ You_Have_Been_P0wned q = b._p0wnee;
+ System.out.println("q._a = 0x"+Integer.toHexString(q._a));
+ System.out.println("q._b = 0x"+Integer.toHexString(q._b));
+ System.out.println("q._c = 0x"+Integer.toHexString(q._c));
+ System.out.println("q._d = 0x"+Integer.toHexString(q._d));
+
+ System.out.println("I will now crash the VM:");
+ // On 32-bit HotSpot Java6 this sets the victim String length shorter, then crashes the VM
+ //q._c = 3;
+ q._a = -1;
+
+ System.out.println(s);
+
+ }
+
+ // I need to compile (hence call in a loop) a function which returns a value
+ // loaded from classloader other than the system one. The point of this
+ // call is to give me an abstract 'hook' into a function loaded with a
+ // foreign loader.
+ public abstract many_loader[] make( IFace iface ); // abstract factory
+}
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/runtime/6626217/from_loader2.java Wed Jul 05 17:21:22 2017 +0200
@@ -0,0 +1,9 @@
+// A simple class to extend an abstract class and get loaded with different
+// loaders. This class is loaded via LOADER2.
+public class from_loader2 implements IFace {
+ public many_loader[] gen() {
+ many_loader[] x = new many_loader[1];
+ x[0] = new many_loader();
+ return x;
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/runtime/6626217/many_loader1.java.foo Wed Jul 05 17:21:22 2017 +0200
@@ -0,0 +1,23 @@
+// A simple class to extend an abstract class and get loaded with different
+// loaders. This class is loaded via LOADER1. A similar named class will
+// be loaded via LOADER2.
+public class many_loader extends bug_21227 {
+ public You_Have_Been_P0wned _p0wnee;
+
+ // I need to compile (hence call in a loop) a function which returns a value
+ // loaded from classloader other than the system one. The point of this
+ // call is to give me an abstract 'hook' into a function loaded with a
+ // foreign loader.
+
+ // The original 'make(boolean)' returns a bug_21227. The VM will inject a
+ // synthetic method to up-cast the returned 'from_loader1' into a
+ // 'bug_21227'.
+ public many_loader[] make( IFace iface ) {
+ // This function needs to return a value known to be loaded from LOADER2.
+ // Since I need to use a yet different loader, I need to make an unknown
+ // foreign call. In this case I'll be using an interface to make the
+ // unknown call, with but a single implementor so the compiler can do the
+ // upcast statically.
+ return iface==null ? null : iface.gen();
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/runtime/6626217/many_loader2.java.foo Wed Jul 05 17:21:22 2017 +0200
@@ -0,0 +1,19 @@
+// A simple class to extend an abstract class and get loaded with different
+// loaders. This class is loaded via LOADER2. A similar named class will
+// be loaded via LOADER1.
+public class many_loader extends bug_21227 {
+ final Object _ref_to_be_p0wned;
+
+ many_loader() {
+ _ref_to_be_p0wned = bug_21227._p0wnee;
+ System.out.println("Gonna hack this thing: " + _ref_to_be_p0wned.toString() );
+ }
+
+ // I need to compile (hence call in a loop) a function which returns a value
+ // loaded from classloader other than the system one. The point of this
+ // call is to give me an abstract 'hook' into a function loaded with a
+ // foreign loader.
+ public many_loader[] make( IFace iface ) {
+ throw new Error("do not call me");
+ }
+}
--- a/jdk/.hgtags Wed Sep 08 14:04:18 2010 -0700
+++ b/jdk/.hgtags Wed Jul 05 17:21:22 2017 +0200
@@ -82,3 +82,4 @@
3b0abcb512807bb6f6d27755bc50103211bde6ee jdk7-b105
b91ef6b60f4e19bf4592c6dd594c9bac62487519 jdk7-b106
882103f334bb23745d3fd70fb7928c347478b0f4 jdk7-b107
+17a5d84b75610255a3527e8ede1da19c91ba7a7e jdk7-b108
--- a/jdk/make/common/shared/Defs-windows.gmk Wed Sep 08 14:04:18 2010 -0700
+++ b/jdk/make/common/shared/Defs-windows.gmk Wed Jul 05 17:21:22 2017 +0200
@@ -89,7 +89,7 @@
$(shell $(CYGPATH_CMD) $1 2> $(DEV_NULL))
endef
define OptFullPath
-$(shell if [ "$1" != "" -a -d "$1" ]; then $(CYGPATH_CMD) "$1"; else echo "$1"; fi)
+$(shell if [ "$1" != "" -a -d "$1" ]; then $(CYGPATH_CMD) "$1" 2> $(DEV_NULL); else echo "$1"; fi)
endef
else
# Temporary until we upgrade to MKS 8.7, MKS pwd returns mixed mode path
--- a/jdk/make/common/shared/Defs.gmk Wed Sep 08 14:04:18 2010 -0700
+++ b/jdk/make/common/shared/Defs.gmk Wed Jul 05 17:21:22 2017 +0200
@@ -136,15 +136,20 @@
$(shell echo $1 | sed -e 's@[^0-9]*\([0-9][0-9]*\.[0-9][.0-9]*\).*@\1@' )
endef
+# Return one part of the version numbers, watch out for non digits.
+define VersionWord # Number Version
+$(word $1,$(subst ., ,$(subst -, ,$2)))
+endef
+
# Given a major.minor.micro version, return the major, minor, or micro number
define MajorVersion
-$(if $(word 1, $(subst ., ,$1)),$(word 1, $(subst ., ,$1)),0)
+$(if $(call VersionWord,1,$1),$(call VersionWord,1,$1),0)
endef
define MinorVersion
-$(if $(word 2, $(subst ., ,$1)),$(word 2, $(subst ., ,$1)),0)
+$(if $(call VersionWord,2,$1),$(call VersionWord,2,$1),0)
endef
define MicroVersion
-$(if $(word 3, $(subst ., ,$1)),$(word 3, $(subst ., ,$1)),0)
+$(if $(call VersionWord,3,$1),$(call VersionWord,3,$1),0)
endef
# Macro that returns missing, same, newer, or older $1=version $2=required
--- a/jdk/make/jdk_generic_profile.sh Wed Sep 08 14:04:18 2010 -0700
+++ b/jdk/make/jdk_generic_profile.sh Wed Jul 05 17:21:22 2017 +0200
@@ -340,6 +340,10 @@
export PATH
# Export variables required for Zero
+if [ "${SHARK_BUILD}" = true ] ; then
+ ZERO_BUILD=true
+ export ZERO_BUILD
+fi
if [ "${ZERO_BUILD}" = true ] ; then
# ZERO_LIBARCH is the name of the architecture-specific
# subdirectory under $JAVA_HOME/jre/lib
@@ -417,4 +421,55 @@
fi
export LIBFFI_CFLAGS
export LIBFFI_LIBS
+
+ # LLVM_CFLAGS, LLVM_LDFLAGS and LLVM_LIBS tell the compiler how to
+ # compile and link against LLVM
+ if [ "${SHARK_BUILD}" = true ] ; then
+ if [ "${LLVM_CONFIG}" = "" ] ; then
+ LLVM_CONFIG=$(which llvm-config 2>/dev/null)
+ fi
+ if [ ! -x "${LLVM_CONFIG}" ] ; then
+ echo "ERROR: Unable to locate llvm-config"
+ exit 1
+ fi
+ llvm_components="jit engine nativecodegen"
+
+ unset LLVM_CFLAGS
+ for flag in $("${LLVM_CONFIG}" --cxxflags $llvm_components); do
+ if echo "${flag}" | grep -q '^-[ID]'; then
+ if [ "${flag}" != "-D_DEBUG" ] ; then
+ if [ "${LLVM_CFLAGS}" != "" ] ; then
+ LLVM_CFLAGS="${LLVM_CFLAGS} "
+ fi
+ LLVM_CFLAGS="${LLVM_CFLAGS}${flag}"
+ fi
+ fi
+ done
+ llvm_version=$("${LLVM_CONFIG}" --version | sed 's/\.//; s/svn.*//')
+ LLVM_CFLAGS="${LLVM_CFLAGS} -DSHARK_LLVM_VERSION=${llvm_version}"
+
+ unset LLVM_LDFLAGS
+ for flag in $("${LLVM_CONFIG}" --ldflags $llvm_components); do
+ if echo "${flag}" | grep -q '^-L'; then
+ if [ "${LLVM_LDFLAGS}" != "" ] ; then
+ LLVM_LDFLAGS="${LLVM_LDFLAGS} "
+ fi
+ LLVM_LDFLAGS="${LLVM_LDFLAGS}${flag}"
+ fi
+ done
+
+ unset LLVM_LIBS
+ for flag in $("${LLVM_CONFIG}" --libs $llvm_components); do
+ if echo "${flag}" | grep -q '^-l'; then
+ if [ "${LLVM_LIBS}" != "" ] ; then
+ LLVM_LIBS="${LLVM_LIBS} "
+ fi
+ LLVM_LIBS="${LLVM_LIBS}${flag}"
+ fi
+ done
+
+ export LLVM_CFLAGS
+ export LLVM_LDFLAGS
+ export LLVM_LIBS
+ fi
fi
--- a/jdk/make/jprt.properties Wed Sep 08 14:04:18 2010 -0700
+++ b/jdk/make/jprt.properties Wed Jul 05 17:21:22 2017 +0200
@@ -24,32 +24,12 @@
#
# Properties for jprt
-jprt.tools.default.release=jdk1.7.0
-
-# Specific platform list
-jprt.build.platforms=\
-solaris_sparc_5.10,\
-solaris_sparcv9_5.10,\
-solaris_i586_5.10,\
-solaris_x64_5.10,\
-linux_i586_2.6,\
-linux_x64_2.6,\
-windows_i586_5.0,\
-windows_x64_5.2
-# The different build flavors we want
+# Use whatever release that the submitted job requests
+jprt.tools.default.release=${jprt.submit.release}
+
+# The different build flavors we want, we override here so we just get these 2
jprt.build.flavors=product,fastdebug
-jprt.run.flavors=c1,c2
-jprt.solaris_sparcv9.run.flavors=c2
-jprt.solaris_x64.run.flavors=c2
-jprt.windows_x64.run.flavors=c2
-jprt.linux_x64.run.flavors=c2
-jprt.run.flavor.c1.option=-client
-jprt.run.flavor.c2.option=-server
-
-# Explicitly designate what the 32bit match is for the 64bit build
-jprt.solaris_sparcv9.build.platform.match32=solaris_sparc_5.10
-jprt.solaris_x64.build.platform.match32=solaris_i586_5.10
# Standard test target for everybody
jprt.test.targets=*-*-*-jvm98
@@ -83,6 +63,6 @@
*-product-*-jdk_rmi, \
*-product-*-jdk_swing, \
-# Directories needed to build
-jprt.bundle.exclude.src.dirs=build
+# Directories to be excluded from the source bundles
+jprt.bundle.exclude.src.dirs=build dist webrev
--- a/jdk/make/sun/javazic/tzdata/VERSION Wed Sep 08 14:04:18 2010 -0700
+++ b/jdk/make/sun/javazic/tzdata/VERSION Wed Jul 05 17:21:22 2017 +0200
@@ -21,4 +21,4 @@
# or visit www.oracle.com if you need additional information or have any
# questions.
#
-tzdata2010i
+tzdata2010l
--- a/jdk/make/sun/javazic/tzdata/africa Wed Sep 08 14:04:18 2010 -0700
+++ b/jdk/make/sun/javazic/tzdata/africa Wed Jul 05 17:21:22 2017 +0200
@@ -316,8 +316,25 @@
# and can be found by searching for "winter" in their search engine
# (at least today).
+# From Alexander Krivenyshev (2010-07-20):
+# According to News from Egypt - Al-Masry Al-Youm Egypt's cabinet has
+# decided that Daylight Saving Time will not be used in Egypt during
+# Ramadan.
+#
+# Arabic translation:
+# "Clocks to go back during Ramadan--and then forward again"
+# <a href="http://www.almasryalyoum.com/en/news/clocks-go-back-during-ramadan-and-then-forward-again">
+# http://www.almasryalyoum.com/en/news/clocks-go-back-during-ramadan-and-then-forward-again
+# </a>
+# or
+# <a href="http://www.worldtimezone.com/dst_news/dst_news_egypt02.html">
+# http://www.worldtimezone.com/dst_news/dst_news_egypt02.html
+# </a>
+
Rule Egypt 2008 only - Aug lastThu 23:00s 0 -
Rule Egypt 2009 only - Aug 20 23:00s 0 -
+Rule Egypt 2010 only - Aug 11 0:00 0 -
+Rule Egypt 2010 only - Sep 10 0:00 1:00 S
Rule Egypt 2010 max - Sep lastThu 23:00s 0 -
# Zone NAME GMTOFF RULES FORMAT [UNTIL]
--- a/jdk/make/sun/javazic/tzdata/asia Wed Sep 08 14:04:18 2010 -0700
+++ b/jdk/make/sun/javazic/tzdata/asia Wed Jul 05 17:21:22 2017 +0200
@@ -2200,6 +2200,18 @@
# "At 12:01am Friday, clocks in Israel and the West Bank will change to
# 1:01am, while Gaza clocks will change at 12:01am Saturday morning."
+# From Steffen Thorsen (2010-08-11):
+# According to several sources, including
+# <a href="http://www.maannews.net/eng/ViewDetails.aspx?ID=306795">
+# http://www.maannews.net/eng/ViewDetails.aspx?ID=306795
+# </a>
+# the clocks were set back one hour at 2010-08-11 00:00:00 local time in
+# Gaza and the West Bank.
+# Some more background info:
+# <a href="http://www.timeanddate.com/news/time/westbank-gaza-end-dst-2010.html">
+# http://www.timeanddate.com/news/time/westbank-gaza-end-dst-2010.html
+# </a>
+
# The rules for Egypt are stolen from the `africa' file.
# Rule NAME FROM TO TYPE IN ON AT SAVE LETTER/S
Rule EgyptAsia 1957 only - May 10 0:00 1:00 S
@@ -2220,6 +2232,7 @@
Rule Palestine 2009 only - Mar lastFri 0:00 1:00 S
Rule Palestine 2010 max - Mar lastSat 0:01 1:00 S
Rule Palestine 2009 max - Sep Fri>=1 2:00 0 -
+Rule Palestine 2010 only - Aug 11 0:00 0 -
# Zone NAME GMTOFF RULES FORMAT [UNTIL]
Zone Asia/Gaza 2:17:52 - LMT 1900 Oct
--- a/jdk/make/sun/javazic/tzdata/australasia Wed Sep 08 14:04:18 2010 -0700
+++ b/jdk/make/sun/javazic/tzdata/australasia Wed Jul 05 17:21:22 2017 +0200
@@ -368,10 +368,10 @@
# Micronesia
# Zone NAME GMTOFF RULES FORMAT [UNTIL]
-Zone Pacific/Truk 10:07:08 - LMT 1901
- 10:00 - TRUT # Truk Time
-Zone Pacific/Ponape 10:32:52 - LMT 1901 # Kolonia
- 11:00 - PONT # Ponape Time
+Zone Pacific/Chuuk 10:07:08 - LMT 1901
+ 10:00 - CHUT # Chuuk Time
+Zone Pacific/Pohnpei 10:32:52 - LMT 1901 # Kolonia
+ 11:00 - PONT # Pohnpei Time
Zone Pacific/Kosrae 10:51:56 - LMT 1901
11:00 - KOST 1969 Oct # Kosrae Time
12:00 - KOST 1999
--- a/jdk/make/sun/javazic/tzdata/backward Wed Sep 08 14:04:18 2010 -0700
+++ b/jdk/make/sun/javazic/tzdata/backward Wed Jul 05 17:21:22 2017 +0200
@@ -112,7 +112,9 @@
Link America/Denver Navajo
Link Asia/Shanghai PRC
Link Pacific/Pago_Pago Pacific/Samoa
-Link Pacific/Truk Pacific/Yap
+Link Pacific/Chuuk Pacific/Yap
+Link Pacific/Chuuk Pacific/Truk
+Link Pacific/Pohnpei Pacific/Ponape
Link Europe/Warsaw Poland
Link Europe/Lisbon Portugal
Link Asia/Taipei ROC
--- a/jdk/make/sun/javazic/tzdata/europe Wed Sep 08 14:04:18 2010 -0700
+++ b/jdk/make/sun/javazic/tzdata/europe Wed Jul 05 17:21:22 2017 +0200
@@ -1035,22 +1035,47 @@
2:00 EU EE%sT
# Finland
-#
+
# From Hannu Strang (1994-09-25 06:03:37 UTC):
# Well, here in Helsinki we're just changing from summer time to regular one,
# and it's supposed to change at 4am...
+
+# From Janne Snabb (2010-0715):
#
-# From Paul Eggert (2006-03-22):
-# Shanks & Pottenger say Finland has switched at 02:00 standard time
-# since 1981. Go with Strang instead.
+# I noticed that the Finland data is not accurate for years 1981 and 1982.
+# During these two first trial years the DST adjustment was made one hour
+# earlier than in forthcoming years. Starting 1983 the adjustment was made
+# according to the central European standards.
+#
+# This is documented in Heikki Oja: Aikakirja 2007, published by The Almanac
+# Office of University of Helsinki, ISBN 952-10-3221-9, available online (in
+# Finnish) at
+#
+# <a href="http://almanakka.helsinki.fi/aikakirja/Aikakirja2007kokonaan.pdf">
+# http://almanakka.helsinki.fi/aikakirja/Aikakirja2007kokonaan.pdf
+# </a>
#
+# Page 105 (56 in PDF version) has a handy table of all past daylight savings
+# transitions. It is easy enough to interpret without Finnish skills.
+#
+# This is also confirmed by Finnish Broadcasting Company's archive at:
+#
+# <a href="http://www.yle.fi/elavaarkisto/?s=s&g=1&ag=5&t=&a=3401">
+# http://www.yle.fi/elavaarkisto/?s=s&g=1&ag=5&t=&a=3401
+# </a>
+#
+# The news clip from 1981 says that "the time between 2 and 3 o'clock does not
+# exist tonight."
+
# Rule NAME FROM TO TYPE IN ON AT SAVE LETTER/S
Rule Finland 1942 only - Apr 3 0:00 1:00 S
Rule Finland 1942 only - Oct 3 0:00 0 -
+Rule Finland 1981 1982 - Mar lastSun 2:00 1:00 S
+Rule Finland 1981 1982 - Sep lastSun 3:00 0 -
# Zone NAME GMTOFF RULES FORMAT [UNTIL]
Zone Europe/Helsinki 1:39:52 - LMT 1878 May 31
1:39:52 - HMT 1921 May # Helsinki Mean Time
- 2:00 Finland EE%sT 1981 Mar 29 2:00
+ 2:00 Finland EE%sT 1983
2:00 EU EE%sT
# Aaland Is
--- a/jdk/make/sun/javazic/tzdata/leapseconds Wed Sep 08 14:04:18 2010 -0700
+++ b/jdk/make/sun/javazic/tzdata/leapseconds Wed Jul 05 17:21:22 2017 +0200
@@ -82,9 +82,9 @@
# FAX : 33 (0) 1 40 51 22 91
# Internet : services.iers@obspm.fr
#
-# Paris, 4 July 2009
+# Paris, 14 July 2010
#
-# Bulletin C 38
+# Bulletin C 40
#
# To authorities responsible
# for the measurement and
@@ -92,9 +92,9 @@
#
# INFORMATION ON UTC - TAI
#
-# NO positive leap second will be introduced at the end of December 2009.
+# NO positive leap second will be introduced at the end of December 2010.
# The difference between Coordinated Universal Time UTC and the
-# International Atomic Time TAI is :
+# International Atomic Time TAI is :
#
# from 2009 January 1, 0h UTC, until further notice : UTC-TAI = -34 s
#
@@ -104,6 +104,6 @@
# will be no time step at the next possible date.
#
# Daniel GAMBIS
-# Director
+# Director
# Earth Orientation Center of IERS
# Observatoire de Paris, France
--- a/jdk/make/sun/javazic/tzdata/northamerica Wed Sep 08 14:04:18 2010 -0700
+++ b/jdk/make/sun/javazic/tzdata/northamerica Wed Jul 05 17:21:22 2017 +0200
@@ -1346,6 +1346,83 @@
# entry since our cutoff date of 1970, so we can move
# America/Coral_Harbour to the 'backward' file.
+# From Mark Brader (2010-03-06):
+#
+# Currently the database has:
+#
+# # Ontario
+#
+# # From Paul Eggert (2006-07-09):
+# # Shanks & Pottenger write that since 1970 most of Ontario has been like
+# # Toronto.
+# # Thunder Bay skipped DST in 1973.
+# # Many smaller locales did not observe peacetime DST until 1974;
+# # Nipigon (EST) and Rainy River (CST) are the largest that we know of.
+#
+# In the (Toronto) Globe and Mail for Saturday, 1955-09-24, in the bottom
+# right corner of page 1, it says that Toronto will return to standard
+# time at 2 am Sunday morning (which agrees with the database), and that:
+#
+# The one-hour setback will go into effect throughout most of Ontario,
+# except in areas like Windsor which remains on standard time all year.
+#
+# Windsor is, of course, a lot larger than Nipigon.
+#
+# I only came across this incidentally. I don't know if Windsor began
+# observing DST when Detroit did, or in 1974, or on some other date.
+#
+# By the way, the article continues by noting that:
+#
+# Some cities in the United States have pushed the deadline back
+# three weeks and will change over from daylight saving in October.
+
+# From Arthur David Olson (2010-07-17):
+#
+# "Standard Time and Time Zones in Canada" appeared in
+# The Journal of The Royal Astronomical Society of Canada,
+# volume 26, number 2 (February 1932) and, as of 2010-07-17,
+# was available at
+# <a href="http://adsabs.harvard.edu/full/1932JRASC..26...49S">
+# http://adsabs.harvard.edu/full/1932JRASC..26...49S
+# </a>
+#
+# It includes the text below (starting on page 57):
+#
+# A list of the places in Canada using daylight saving time would
+# require yearly revision. From information kindly furnished by
+# the provincial governments and by the postmasters in many cities
+# and towns, it is found that the following places used daylight sav-
+# ing in 1930. The information for the province of Quebec is definite,
+# for the other provinces only approximate:
+#
+# Province Daylight saving time used
+# Prince Edward Island Not used.
+# Nova Scotia In Halifax only.
+# New Brunswick In St. John only.
+# Quebec In the following places:
+# Montreal Lachine
+# Quebec Mont-Royal
+# Levis Iberville
+# St. Lambert Cap de la Madeleine
+# Verdun Loretteville
+# Westmount Richmond
+# Outremont St. Jerome
+# Longueuil Greenfield Park
+# Arvida Waterloo
+# Chambly-Canton Beaulieu
+# Melbourne La Tuque
+# St. Theophile Buckingham
+# Ontario Used generally in the cities and towns along
+# the southerly part of the province. Not
+# used in the northwesterlhy part.
+# Manitoba Not used.
+# Saskatchewan In Regina only.
+# Alberta Not used.
+# British Columbia Not used.
+#
+# With some exceptions, the use of daylight saving may be said to be limited
+# to those cities and towns lying between Quebec city and Windsor, Ont.
+
# Rule NAME FROM TO TYPE IN ON AT SAVE LETTER/S
Rule Toronto 1919 only - Mar 30 23:30 1:00 D
Rule Toronto 1919 only - Oct 26 0:00 0 S
@@ -2111,7 +2188,44 @@
-8:00 - PST 1970
-7:00 Mexico M%sT 1999
-7:00 - MST
+
+# From Alexander Krivenyshev (2010-04-21):
+# According to news, Bahía de Banderas (Mexican state of Nayarit)
+# changed time zone UTC-7 to new time zone UTC-6 on April 4, 2010 (to
+# share the same time zone as nearby city Puerto Vallarta, Jalisco).
+#
+# (Spanish)
+# Bahía de Banderas homologa su horario al del centro del
+# país, a partir de este domingo
+# <a href="http://www.nayarit.gob.mx/notes.asp?id=20748">
+# http://www.nayarit.gob.mx/notes.asp?id=20748
+# </a>
+#
+# Bahía de Banderas homologa su horario con el del Centro del
+# País
+# <a href="http://www.bahiadebanderas.gob.mx/principal/index.php?option=com_content&view=article&id=261:bahia-de-banderas-homologa-su-horario-con-el-del-centro-del-pais&catid=42:comunicacion-social&Itemid=50">
+# http://www.bahiadebanderas.gob.mx/principal/index.php?option=com_content&view=article&id=261:bahia-de-banderas-homologa-su-horario-con-el-del-centro-del-pais&catid=42:comunicacion-social&Itemid=50"
+# </a>
+#
+# (English)
+# Puerto Vallarta and Bahía de Banderas: One Time Zone
+# <a href="http://virtualvallarta.com/puertovallarta/puertovallarta/localnews/2009-12-03-Puerto-Vallarta-and-Bahia-de-Banderas-One-Time-Zone.shtml">
+# http://virtualvallarta.com/puertovallarta/puertovallarta/localnews/2009-12-03-Puerto-Vallarta-and-Bahia-de-Banderas-One-Time-Zone.shtml
+# </a>
+#
+# or
+# <a href="http://www.worldtimezone.com/dst_news/dst_news_mexico08.html">
+# http://www.worldtimezone.com/dst_news/dst_news_mexico08.html
+# </a>
+#
+# "Mexico's Senate approved the amendments to the Mexican Schedule System that
+# will allow Bahía de Banderas and Puerto Vallarta to share the same time
+# zone ..."
# Baja California Sur, Nayarit, Sinaloa
+
+# From Arthur David Olson (2010-05-01):
+# Use "Bahia_Banderas" to keep the name to fourteen characters.
+
Zone America/Mazatlan -7:05:40 - LMT 1921 Dec 31 23:54:20
-7:00 - MST 1927 Jun 10 23:00
-6:00 - CST 1930 Nov 15
@@ -2122,6 +2236,19 @@
-7:00 - MST 1949 Jan 14
-8:00 - PST 1970
-7:00 Mexico M%sT
+
+Zone America/Bahia_Banderas -7:01:00 - LMT 1921 Dec 31 23:59:00
+ -7:00 - MST 1927 Jun 10 23:00
+ -6:00 - CST 1930 Nov 15
+ -7:00 - MST 1931 May 1 23:00
+ -6:00 - CST 1931 Oct
+ -7:00 - MST 1932 Apr 1
+ -6:00 - CST 1942 Apr 24
+ -7:00 - MST 1949 Jan 14
+ -8:00 - PST 1970
+ -7:00 Mexico M%sT 2010 Apr 4 2:00
+ -6:00 Mexico C%sT
+
# Baja California (near US border)
Zone America/Tijuana -7:48:04 - LMT 1922 Jan 1 0:11:56
-7:00 - MST 1924
--- a/jdk/make/sun/javazic/tzdata/zone.tab Wed Sep 08 14:04:18 2010 -0700
+++ b/jdk/make/sun/javazic/tzdata/zone.tab Wed Jul 05 17:21:22 2017 +0200
@@ -199,8 +199,8 @@
FI +6010+02458 Europe/Helsinki
FJ -1808+17825 Pacific/Fiji
FK -5142-05751 Atlantic/Stanley
-FM +0725+15147 Pacific/Truk Truk (Chuuk) and Yap
-FM +0658+15813 Pacific/Ponape Ponape (Pohnpei)
+FM +0725+15147 Pacific/Chuuk Chuuk (Truk) and Yap
+FM +0658+15813 Pacific/Pohnpei Pohnpei (Ponape)
FM +0519+16259 Pacific/Kosrae Kosrae
FO +6201-00646 Atlantic/Faroe
FR +4852+00220 Europe/Paris
@@ -310,6 +310,7 @@
MX +2904-11058 America/Hermosillo Mountain Standard Time - Sonora
MX +3232-11701 America/Tijuana US Pacific Time - Baja California near US border
MX +3018-11452 America/Santa_Isabel Mexican Pacific Time - Baja California away from US border
+MX +2048-10515 America/Bahia_Banderas Mexican Central Time - Bahia de Banderas
MY +0310+10142 Asia/Kuala_Lumpur peninsular Malaysia
MY +0133+11020 Asia/Kuching Sabah & Sarawak
MZ -2558+03235 Africa/Maputo
--- a/jdk/src/share/classes/com/sun/java/util/jar/pack/Attribute.java Wed Sep 08 14:04:18 2010 -0700
+++ b/jdk/src/share/classes/com/sun/java/util/jar/pack/Attribute.java Wed Jul 05 17:21:22 2017 +0200
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2003, 2005, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 2010, 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
@@ -27,7 +27,6 @@
import java.io.*;
import java.util.*;
-import com.sun.java.util.jar.pack.Package.Class;
import com.sun.java.util.jar.pack.ConstantPool.*;
/**
@@ -96,20 +95,20 @@
return this.def.compareTo(that.def);
}
- static private final byte[] noBytes = {};
- static private final HashMap canonLists = new HashMap();
- static private final HashMap attributes = new HashMap();
- static private final HashMap standardDefs = new HashMap();
+ private static final byte[] noBytes = {};
+ private static final Map<List<Attribute>, List<Attribute>> canonLists = new HashMap<>();
+ private static final Map<Layout, Attribute> attributes = new HashMap<>();
+ private static final Map<Layout, Attribute> standardDefs = new HashMap<>();
// Canonicalized lists of trivial attrs (Deprecated, etc.)
// are used by trimToSize, in order to reduce footprint
// of some common cases. (Note that Code attributes are
// always zero size.)
- public static List getCanonList(List al) {
+ public static List getCanonList(List<Attribute> al) {
synchronized (canonLists) {
- List cl = (List) canonLists.get(al);
+ List<Attribute> cl = canonLists.get(al);
if (cl == null) {
- cl = new ArrayList(al.size());
+ cl = new ArrayList<>(al.size());
cl.addAll(al);
cl = Collections.unmodifiableList(cl);
canonLists.put(al, cl);
@@ -122,7 +121,7 @@
public static Attribute find(int ctype, String name, String layout) {
Layout key = Layout.makeKey(ctype, name, layout);
synchronized (attributes) {
- Attribute a = (Attribute) attributes.get(key);
+ Attribute a = attributes.get(key);
if (a == null) {
a = new Layout(ctype, name, layout).canonicalInstance();
attributes.put(key, a);
@@ -131,24 +130,29 @@
}
}
- public static Object keyForLookup(int ctype, String name) {
+ public static Layout keyForLookup(int ctype, String name) {
return Layout.makeKey(ctype, name);
}
// Find canonical empty attribute with given ctype and name,
// and with the standard layout.
- public static Attribute lookup(Map defs, int ctype, String name) {
- if (defs == null) defs = standardDefs;
- return (Attribute) defs.get(Layout.makeKey(ctype, name));
+ public static Attribute lookup(Map<Layout, Attribute> defs, int ctype,
+ String name) {
+ if (defs == null) {
+ defs = standardDefs;
+ }
+ return defs.get(Layout.makeKey(ctype, name));
}
- public static Attribute define(Map defs, int ctype, String name, String layout) {
+
+ public static Attribute define(Map<Layout, Attribute> defs, int ctype,
+ String name, String layout) {
Attribute a = find(ctype, name, layout);
defs.put(Layout.makeKey(ctype, name), a);
return a;
}
static {
- Map sd = standardDefs;
+ Map<Layout, Attribute> sd = standardDefs;
define(sd, ATTR_CONTEXT_CLASS, "Signature", "RSH");
define(sd, ATTR_CONTEXT_CLASS, "Synthetic", "");
define(sd, ATTR_CONTEXT_CLASS, "Deprecated", "");
@@ -244,7 +248,7 @@
+"\n ()[] ]"
)
};
- Map sd = standardDefs;
+ Map<Layout, Attribute> sd = standardDefs;
String defaultLayout = mdLayouts[2];
String annotationsLayout = mdLayouts[1] + mdLayouts[2];
String paramsLayout = mdLayouts[0] + annotationsLayout;
@@ -275,10 +279,6 @@
return null;
}
- public static Map getStandardDefs() {
- return new HashMap(standardDefs);
- }
-
/** Base class for any attributed object (Class, Field, Method, Code).
* Flags are included because they are used to help transmit the
* presence of attributes. That is, flags are a mix of modifier
@@ -291,7 +291,7 @@
protected abstract Entry[] getCPMap();
protected int flags; // defined here for convenience
- protected List attributes;
+ protected List<Attribute> attributes;
public int attributeSize() {
return (attributes == null) ? 0 : attributes.size();
@@ -301,16 +301,15 @@
if (attributes == null) {
return;
}
- if (attributes.size() == 0) {
+ if (attributes.isEmpty()) {
attributes = null;
return;
}
if (attributes instanceof ArrayList) {
- ArrayList al = (ArrayList) attributes;
+ ArrayList<Attribute> al = (ArrayList<Attribute>)attributes;
al.trimToSize();
boolean allCanon = true;
- for (Iterator i = al.iterator(); i.hasNext(); ) {
- Attribute a = (Attribute) i.next();
+ for (Attribute a : al) {
if (!a.isCanonical()) {
allCanon = false;
}
@@ -330,9 +329,9 @@
public void addAttribute(Attribute a) {
if (attributes == null)
- attributes = new ArrayList(3);
+ attributes = new ArrayList<>(3);
else if (!(attributes instanceof ArrayList))
- attributes = new ArrayList(attributes); // unfreeze it
+ attributes = new ArrayList<>(attributes); // unfreeze it
attributes.add(a);
}
@@ -340,32 +339,31 @@
if (attributes == null) return null;
if (!attributes.contains(a)) return null;
if (!(attributes instanceof ArrayList))
- attributes = new ArrayList(attributes); // unfreeze it
+ attributes = new ArrayList<>(attributes); // unfreeze it
attributes.remove(a);
return a;
}
public Attribute getAttribute(int n) {
- return (Attribute) attributes.get(n);
+ return attributes.get(n);
}
- protected void visitRefs(int mode, Collection refs) {
+ protected void visitRefs(int mode, Collection<Entry> refs) {
if (attributes == null) return;
- for (Iterator i = attributes.iterator(); i.hasNext(); ) {
- Attribute a = (Attribute) i.next();
+ for (Attribute a : attributes) {
a.visitRefs(this, mode, refs);
}
}
- static final List noAttributes = Arrays.asList(new Object[0]);
+ static final List<Attribute> noAttributes = Arrays.asList(new Attribute[0]);
- public List getAttributes() {
+ public List<Attribute> getAttributes() {
if (attributes == null)
return noAttributes;
return attributes;
}
- public void setAttributes(List attrList) {
+ public void setAttributes(List<Attribute> attrList) {
if (attrList.isEmpty())
attributes = null;
else
@@ -374,8 +372,7 @@
public Attribute getAttribute(String attrName) {
if (attributes == null) return null;
- for (Iterator i = attributes.iterator(); i.hasNext(); ) {
- Attribute a = (Attribute) i.next();
+ for (Attribute a : attributes) {
if (a.name().equals(attrName))
return a;
}
@@ -384,8 +381,7 @@
public Attribute getAttribute(Layout attrDef) {
if (attributes == null) return null;
- for (Iterator i = attributes.iterator(); i.hasNext(); ) {
- Attribute a = (Attribute) i.next();
+ for (Attribute a : attributes) {
if (a.layout() == attrDef)
return a;
}
@@ -457,14 +453,8 @@
public String layout() { return layout; }
public Attribute canonicalInstance() { return canon; }
- // Cache of name reference.
- private Entry nameRef; // name, for use by visitRefs
public Entry getNameRef() {
- Entry nameRef = this.nameRef;
- if (nameRef == null) {
- this.nameRef = nameRef = ConstantPool.getUtf8Entry(name());
- }
- return nameRef;
+ return ConstantPool.getUtf8Entry(name());
}
public boolean isEmpty() { return layout == ""; }
@@ -834,14 +824,14 @@
*/
static //private
Layout.Element[] tokenizeLayout(Layout self, int curCble, String layout) {
- ArrayList col = new ArrayList(layout.length());
+ ArrayList<Layout.Element> col = new ArrayList<>(layout.length());
tokenizeLayout(self, curCble, layout, col);
Layout.Element[] res = new Layout.Element[col.size()];
col.toArray(res);
return res;
}
static //private
- void tokenizeLayout(Layout self, int curCble, String layout, ArrayList col) {
+ void tokenizeLayout(Layout self, int curCble, String layout, ArrayList<Layout.Element> col) {
boolean prevBCI = false;
for (int len = layout.length(), i = 0; i < len; ) {
int start = i;
@@ -899,7 +889,7 @@
case 'T': // union: 'T' any_int union_case* '(' ')' '[' body ']'
kind = EK_UN;
i = tokenizeSInt(e, layout, i);
- ArrayList cases = new ArrayList();
+ ArrayList<Layout.Element> cases = new ArrayList<>();
for (;;) {
// Keep parsing cases until we hit the default case.
if (layout.charAt(i++) != '(')
@@ -1053,7 +1043,7 @@
}
static //private
String[] splitBodies(String layout) {
- ArrayList bodies = new ArrayList();
+ ArrayList<String> bodies = new ArrayList<>();
// Parse several independent layout bodies: "[foo][bar]...[baz]"
for (int i = 0; i < layout.length(); i++) {
if (layout.charAt(i++) != '[')
@@ -1132,7 +1122,9 @@
int parseIntBefore(String layout, int dash) {
int end = dash;
int beg = end;
- while (beg > 0 && isDigit(layout.charAt(beg-1))) --beg;
+ while (beg > 0 && isDigit(layout.charAt(beg-1))) {
+ --beg;
+ }
if (beg == end) return Integer.parseInt("empty");
// skip backward over a sign
if (beg >= 1 && layout.charAt(beg-1) == '-') --beg;
@@ -1145,7 +1137,9 @@
int end = beg;
int limit = layout.length();
if (end < limit && layout.charAt(end) == '-') ++end;
- while (end < limit && isDigit(layout.charAt(end))) ++end;
+ while (end < limit && isDigit(layout.charAt(end))) {
+ ++end;
+ }
if (beg == end) return Integer.parseInt("empty");
return Integer.parseInt(layout.substring(beg, end));
}
--- a/jdk/src/share/classes/com/sun/java/util/jar/pack/ConstantPool.java Wed Sep 08 14:04:18 2010 -0700
+++ b/jdk/src/share/classes/com/sun/java/util/jar/pack/ConstantPool.java Wed Jul 05 17:21:22 2017 +0200
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2001, 2003, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2001, 2010, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -25,7 +25,6 @@
package com.sun.java.util.jar.pack;
-import java.io.*;
import java.util.*;
/**
@@ -40,20 +39,13 @@
return Utils.currentPropMap().getInteger(Utils.DEBUG_VERBOSE);
}
- // Uniquification tables for factory methods:
- private static final HashMap utf8Entries = new HashMap();
- private static final HashMap classEntries = new HashMap();
- private static final HashMap literalEntries = new HashMap();
- private static final HashMap signatureEntries = new HashMap();
- private static final HashMap descriptorEntries = new HashMap();
- private static final HashMap memberEntries = new HashMap();
-
/** Factory for Utf8 string constants.
* Used for well-known strings like "SourceFile", "<init>", etc.
* Also used to back up more complex constant pool entries, like Class.
*/
public static synchronized Utf8Entry getUtf8Entry(String value) {
- Utf8Entry e = (Utf8Entry) utf8Entries.get(value);
+ Map<String, Utf8Entry> utf8Entries = Utils.getUtf8Entries();
+ Utf8Entry e = utf8Entries.get(value);
if (e == null) {
e = new Utf8Entry(value);
utf8Entries.put(e.stringValue(), e);
@@ -62,9 +54,10 @@
}
/** Factory for Class constants. */
public static synchronized ClassEntry getClassEntry(String name) {
- ClassEntry e = (ClassEntry) classEntries.get(name);
+ Map<String, ClassEntry> classEntries = Utils.getClassEntries();
+ ClassEntry e = classEntries.get(name);
if (e == null) {
- e = (ClassEntry) new ClassEntry(getUtf8Entry(name));
+ e = new ClassEntry(getUtf8Entry(name));
assert(name.equals(e.stringValue()));
classEntries.put(e.stringValue(), e);
}
@@ -72,7 +65,8 @@
}
/** Factory for literal constants (String, Integer, etc.). */
public static synchronized LiteralEntry getLiteralEntry(Comparable value) {
- LiteralEntry e = (LiteralEntry) literalEntries.get(value);
+ Map<Object, LiteralEntry> literalEntries = Utils.getLiteralEntries();
+ LiteralEntry e = literalEntries.get(value);
if (e == null) {
if (value instanceof String)
e = new StringEntry(getUtf8Entry((String)value));
@@ -89,7 +83,8 @@
/** Factory for signature (type) constants. */
public static synchronized SignatureEntry getSignatureEntry(String type) {
- SignatureEntry e = (SignatureEntry) signatureEntries.get(type);
+ Map<String, SignatureEntry> signatureEntries = Utils.getSignatureEntries();
+ SignatureEntry e = signatureEntries.get(type);
if (e == null) {
e = new SignatureEntry(type);
assert(e.stringValue().equals(type));
@@ -104,8 +99,9 @@
/** Factory for descriptor (name-and-type) constants. */
public static synchronized DescriptorEntry getDescriptorEntry(Utf8Entry nameRef, SignatureEntry typeRef) {
+ Map<String, DescriptorEntry> descriptorEntries = Utils.getDescriptorEntries();
String key = DescriptorEntry.stringValueOf(nameRef, typeRef);
- DescriptorEntry e = (DescriptorEntry) descriptorEntries.get(key);
+ DescriptorEntry e = descriptorEntries.get(key);
if (e == null) {
e = new DescriptorEntry(nameRef, typeRef);
assert(e.stringValue().equals(key))
@@ -121,8 +117,9 @@
/** Factory for member reference constants. */
public static synchronized MemberEntry getMemberEntry(byte tag, ClassEntry classRef, DescriptorEntry descRef) {
+ Map<String, MemberEntry> memberEntries = Utils.getMemberEntries();
String key = MemberEntry.stringValueOf(tag, classRef, descRef);
- MemberEntry e = (MemberEntry) memberEntries.get(key);
+ MemberEntry e = memberEntries.get(key);
if (e == null) {
e = new MemberEntry(tag, classRef, descRef);
assert(e.stringValue().equals(key))
@@ -489,8 +486,9 @@
String[] parts = structureSignature(value);
formRef = getUtf8Entry(parts[0]);
classRefs = new ClassEntry[parts.length-1];
- for (int i = 1; i < parts.length; i++)
- classRefs[i-1] = getClassEntry(parts[i]);
+ for (int i = 1; i < parts.length; i++) {
+ classRefs[i - 1] = getClassEntry(parts[i]);
+ }
hashCode(); // force computation of valueHash
}
protected int computeValueHash() {
@@ -527,8 +525,9 @@
String stringValueOf(Utf8Entry formRef, ClassEntry[] classRefs) {
String[] parts = new String[1+classRefs.length];
parts[0] = formRef.stringValue();
- for (int i = 1; i < parts.length; i++)
- parts[i] = classRefs[i-1].stringValue();
+ for (int i = 1; i < parts.length; i++) {
+ parts[i] = classRefs[i - 1].stringValue();
+ }
return flattenSignature(parts).intern();
}
@@ -543,19 +542,23 @@
int size = 0;
for (int i = min; i < max; i++) {
switch (form.charAt(i)) {
- case 'D':
- case 'J':
- if (countDoublesTwice) size++;
- break;
- case '[':
- // Skip rest of array info.
- while (form.charAt(i) == '[') ++i;
- break;
- case ';':
- continue;
- default:
- assert(0 <= JAVA_SIGNATURE_CHARS.indexOf(form.charAt(i)));
- break;
+ case 'D':
+ case 'J':
+ if (countDoublesTwice) {
+ size++;
+ }
+ break;
+ case '[':
+ // Skip rest of array info.
+ while (form.charAt(i) == '[') {
+ ++i;
+ }
+ break;
+ case ';':
+ continue;
+ default:
+ assert (0 <= JAVA_SIGNATURE_CHARS.indexOf(form.charAt(i)));
+ break;
}
size++;
}
@@ -586,8 +589,9 @@
s = "/" + formRef.stringValue();
}
int i;
- while ((i = s.indexOf(';')) >= 0)
- s = s.substring(0,i) + s.substring(i+1);
+ while ((i = s.indexOf(';')) >= 0) {
+ s = s.substring(0, i) + s.substring(i + 1);
+ }
return s;
}
}
@@ -732,11 +736,11 @@
clearIndex();
this.cpMap = cpMap;
}
- protected Index(String debugName, Collection cpMapList) {
+ protected Index(String debugName, Collection<Entry> cpMapList) {
this(debugName);
setMap(cpMapList);
}
- protected void setMap(Collection cpMapList) {
+ protected void setMap(Collection<Entry> cpMapList) {
cpMap = new Entry[cpMapList.size()];
cpMapList.toArray(cpMap);
setMap(cpMap);
@@ -756,11 +760,13 @@
//
// As a special hack, if flattenSigs, signatures are
// treated as equivalent entries of cpMap. This is wrong
- // fron a Collection point of view, because contains()
+ // from a Collection point of view, because contains()
// reports true for signatures, but the iterator()
// never produces them!
private int findIndexOf(Entry e) {
- if (indexKey == null) initializeIndex();
+ if (indexKey == null) {
+ initializeIndex();
+ }
int probe = findIndexLocation(e);
if (indexKey[probe] != e) {
if (flattenSigs && e.tag == CONSTANT_Signature) {
@@ -832,7 +838,9 @@
System.out.println("initialize Index "+debugName+" ["+size()+"]");
int hsize0 = (int)((cpMap.length + 10) * 1.5);
int hsize = 1;
- while (hsize < hsize0) hsize <<= 1;
+ while (hsize < hsize0) {
+ hsize <<= 1;
+ }
indexKey = new Entry[hsize];
indexValue = new int[hsize];
for (int i = 0; i < cpMap.length; i++) {
@@ -855,7 +863,7 @@
return toArray(new Entry[size()]);
}
public Object clone() {
- return new Index(debugName, (Entry[]) cpMap.clone());
+ return new Index(debugName, cpMap.clone());
}
public String toString() {
return "Index "+debugName+" ["+size()+"]";
@@ -901,22 +909,24 @@
public static
Index[] partition(Index ix, int[] keys) {
// %%% Should move this into class Index.
- ArrayList parts = new ArrayList();
+ ArrayList<List<Entry>> parts = new ArrayList<>();
Entry[] cpMap = ix.cpMap;
assert(keys.length == cpMap.length);
for (int i = 0; i < keys.length; i++) {
int key = keys[i];
if (key < 0) continue;
- while (key >= parts.size()) parts.add(null);
- ArrayList part = (ArrayList) parts.get(key);
+ while (key >= parts.size()) {
+ parts.add(null);
+ }
+ List<Entry> part = parts.get(key);
if (part == null) {
- parts.set(key, part = new ArrayList());
+ parts.set(key, part = new ArrayList<>());
}
part.add(cpMap[i]);
}
Index[] indexes = new Index[parts.size()];
for (int key = 0; key < indexes.length; key++) {
- ArrayList part = (ArrayList) parts.get(key);
+ List<Entry> part = parts.get(key);
if (part == null) continue;
indexes[key] = new Index(ix.debugName+"/part#"+key, part);
assert(indexes[key].indexOf(part.get(0)) == 0);
@@ -1048,9 +1058,10 @@
whichClasses[i] = whichClass;
}
perClassIndexes = partition(allMembers, whichClasses);
- for (int i = 0; i < perClassIndexes.length; i++)
- assert(perClassIndexes[i]==null
- || perClassIndexes[i].assertIsSorted());
+ for (int i = 0; i < perClassIndexes.length; i++) {
+ assert (perClassIndexes[i] == null ||
+ perClassIndexes[i].assertIsSorted());
+ }
indexByTagAndClass[tag] = perClassIndexes;
}
int whichClass = allClasses.indexOf(classRef);
@@ -1113,7 +1124,7 @@
* Also, discard null from cpRefs.
*/
public static
- void completeReferencesIn(Set cpRefs, boolean flattenSigs) {
+ void completeReferencesIn(Set<Entry> cpRefs, boolean flattenSigs) {
cpRefs.remove(null);
for (ListIterator work =
new ArrayList(cpRefs).listIterator(cpRefs.size());
--- a/jdk/src/share/classes/com/sun/java/util/jar/pack/Driver.java Wed Sep 08 14:04:18 2010 -0700
+++ b/jdk/src/share/classes/com/sun/java/util/jar/pack/Driver.java Wed Jul 05 17:21:22 2017 +0200
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2003, 2005, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -25,7 +25,6 @@
package com.sun.java.util.jar.pack;
-import java.lang.Error;
import java.io.*;
import java.text.MessageFormat;
import java.util.*;
@@ -35,10 +34,11 @@
/** Command line interface for Pack200.
*/
class Driver {
- private static final ResourceBundle RESOURCE= ResourceBundle.getBundle("com.sun.java.util.jar.pack.DriverResource");
+ private static final ResourceBundle RESOURCE =
+ ResourceBundle.getBundle("com.sun.java.util.jar.pack.DriverResource");
public static void main(String[] ava) throws IOException {
- ArrayList<String> av = new ArrayList<String>(Arrays.asList(ava));
+ ArrayList<String> av = new ArrayList<>(Arrays.asList(ava));
boolean doPack = true;
boolean doUnpack = false;
@@ -61,7 +61,7 @@
}
// Collect engine properties here:
- HashMap<String,String> engProps = new HashMap<String,String>();
+ HashMap<String,String> engProps = new HashMap<>();
engProps.put(verboseProp, System.getProperty(verboseProp));
String optionMap;
@@ -75,7 +75,7 @@
}
// Collect argument properties here:
- HashMap<String,String> avProps = new HashMap<String,String>();
+ HashMap<String,String> avProps = new HashMap<>();
try {
for (;;) {
String state = parseCommandOptions(av, optionMap, avProps);
@@ -133,8 +133,9 @@
if (engProps.get(verboseProp) != null)
fileProps.list(System.out);
propIn.close();
- for (Map.Entry<Object,Object> me : fileProps.entrySet())
- engProps.put((String)me.getKey(), (String)me.getValue());
+ for (Map.Entry<Object,Object> me : fileProps.entrySet()) {
+ engProps.put((String) me.getKey(), (String) me.getValue());
+ }
} else if (state == "--version") {
System.out.println(MessageFormat.format(RESOURCE.getString(DriverResource.VERSION), Driver.class.getName(), "1.31, 07/05/05"));
return;
@@ -493,7 +494,7 @@
String resultString = null;
// Convert options string into optLines dictionary.
- TreeMap<String,String[]> optmap = new TreeMap<String,String[]>();
+ TreeMap<String,String[]> optmap = new TreeMap<>();
loadOptmap:
for (String optline : options.split("\n")) {
String[] words = optline.split("\\p{Space}+");
@@ -687,7 +688,9 @@
// Report number of arguments consumed.
args.subList(0, argp.nextIndex()).clear();
// Report any unconsumed partial argument.
- while (pbp.hasPrevious()) args.add(0, pbp.previous());
+ while (pbp.hasPrevious()) {
+ args.add(0, pbp.previous());
+ }
//System.out.println(args+" // "+properties+" -> "+resultString);
return resultString;
}
--- a/jdk/src/share/classes/com/sun/java/util/jar/pack/NativeUnpack.java Wed Sep 08 14:04:18 2010 -0700
+++ b/jdk/src/share/classes/com/sun/java/util/jar/pack/NativeUnpack.java Wed Jul 05 17:21:22 2017 +0200
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2003, 2004, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -28,13 +28,8 @@
import java.nio.*;
import java.io.*;
-import java.nio.channels.*;
-import java.util.Date;
import java.util.jar.*;
import java.util.zip.*;
-import java.util.*;
-//import com.sun.java.util.jar.pack.Pack200;
-
class NativeUnpack {
// Pointer to the native unpacker obj
@@ -91,13 +86,13 @@
NativeUnpack(UnpackerImpl p200) {
super();
_p200 = p200;
- _props = p200._props;
+ _props = p200.props;
p200._nunp = this;
}
// for JNI callbacks
static private Object currentInstance() {
- UnpackerImpl p200 = (UnpackerImpl) Utils.currentInstance.get();
+ UnpackerImpl p200 = (UnpackerImpl) Utils.getTLGlobals();
return (p200 == null)? null: p200._nunp;
}
@@ -216,10 +211,10 @@
++_fileCount;
updateProgress();
}
+ presetInput = getUnusedInput();
long consumed = finish();
if (_verbose > 0)
Utils.log.info("bytes consumed = "+consumed);
- presetInput = getUnusedInput();
if (presetInput == null &&
!Utils.isPackMagic(Utils.readMagic(in))) {
break;
--- a/jdk/src/share/classes/com/sun/java/util/jar/pack/Package.java Wed Sep 08 14:04:18 2010 -0700
+++ b/jdk/src/share/classes/com/sun/java/util/jar/pack/Package.java Wed Jul 05 17:21:22 2017 +0200
@@ -25,9 +25,9 @@
package com.sun.java.util.jar.pack;
+import com.sun.java.util.jar.pack.Attribute.Layout;
import java.lang.reflect.Modifier;
import java.util.*;
-import java.util.zip.*;
import java.util.jar.*;
import java.io.*;
import com.sun.java.util.jar.pack.ConstantPool.*;
@@ -77,10 +77,11 @@
cp = new ConstantPool.IndexGroup();
classes.clear();
files.clear();
+ BandStructure.nextSeqForDebug = 0;
}
int getPackageVersion() {
- return (package_majver << 16) + (int)package_minver;
+ return (package_majver << 16) + package_minver;
}
// Special empty versions of Code and InnerClasses, used for markers.
@@ -89,7 +90,7 @@
public static final Attribute.Layout attrSourceFileSpecial;
public static final Map attrDefs;
static {
- HashMap ad = new HashMap(2);
+ HashMap<Layout, Attribute> ad = new HashMap<>(3);
attrCodeEmpty = Attribute.define(ad, ATTR_CONTEXT_METHOD,
"Code", "").layout();
attrInnerClassesEmpty = Attribute.define(ad, ATTR_CONTEXT_CLASS,
@@ -159,9 +160,9 @@
}
}
- ArrayList classes = new ArrayList();
+ ArrayList<Package.Class> classes = new ArrayList<>();
- public List getClasses() {
+ public List<Package.Class> getClasses() {
return classes;
}
@@ -186,11 +187,11 @@
ClassEntry[] interfaces;
// Class parts
- ArrayList fields;
- ArrayList methods;
+ ArrayList<Field> fields;
+ ArrayList<Method> methods;
//ArrayList attributes; // in Attribute.Holder.this.attributes
// Note that InnerClasses may be collected at the package level.
- ArrayList innerClasses;
+ ArrayList<InnerClass> innerClasses;
Class(int flags, ClassEntry thisClass, ClassEntry superClass, ClassEntry[] interfaces) {
this.magic = JAVA_MAGIC;
@@ -270,7 +271,7 @@
if (a != olda) {
if (verbose > 2)
Utils.log.fine("recoding obvious SourceFile="+obvious);
- List newAttrs = new ArrayList(getAttributes());
+ List<Attribute> newAttrs = new ArrayList<>(getAttributes());
int where = newAttrs.indexOf(olda);
newAttrs.set(where, a);
setAttributes(newAttrs);
@@ -295,12 +296,12 @@
boolean hasInnerClasses() {
return innerClasses != null;
}
- List getInnerClasses() {
+ List<InnerClass> getInnerClasses() {
return innerClasses;
}
- public void setInnerClasses(Collection ics) {
- innerClasses = (ics == null) ? null : new ArrayList(ics);
+ public void setInnerClasses(Collection<InnerClass> ics) {
+ innerClasses = (ics == null) ? null : new ArrayList<InnerClass>(ics);
// Edit the attribute list, if necessary.
Attribute a = getAttribute(attrInnerClassesEmpty);
if (innerClasses != null && a == null)
@@ -318,19 +319,18 @@
* The order of the resulting list is consistent
* with that of Package.this.allInnerClasses.
*/
- public List computeGloballyImpliedICs() {
- HashSet cpRefs = new HashSet();
+ public List<InnerClass> computeGloballyImpliedICs() {
+ HashSet<Entry> cpRefs = new HashSet<>();
{ // This block temporarily displaces this.innerClasses.
- ArrayList innerClassesSaved = innerClasses;
+ ArrayList<InnerClass> innerClassesSaved = innerClasses;
innerClasses = null; // ignore for the moment
visitRefs(VRM_CLASSIC, cpRefs);
innerClasses = innerClassesSaved;
}
ConstantPool.completeReferencesIn(cpRefs, true);
- HashSet icRefs = new HashSet();
- for (Iterator i = cpRefs.iterator(); i.hasNext(); ) {
- Entry e = (Entry) i.next();
+ HashSet<Entry> icRefs = new HashSet<>();
+ for (Entry e : cpRefs) {
// Restrict cpRefs to InnerClasses entries only.
if (!(e instanceof ClassEntry)) continue;
// For every IC reference, add its outers also.
@@ -345,9 +345,8 @@
// This loop is structured this way so as to accumulate
// entries into impliedICs in an order which reflects
// the order of allInnerClasses.
- ArrayList impliedICs = new ArrayList();
- for (Iterator i = allInnerClasses.iterator(); i.hasNext(); ) {
- InnerClass ic = (InnerClass) i.next();
+ ArrayList<InnerClass> impliedICs = new ArrayList<>();
+ for (InnerClass ic : allInnerClasses) {
// This one is locally relevant if it describes
// a member of the current class, or if the current
// class uses it somehow. In the particular case
@@ -366,10 +365,11 @@
// Helper for both minimizing and expanding.
// Computes a symmetric difference.
- private List computeICdiff() {
- List impliedICs = computeGloballyImpliedICs();
- List actualICs = getInnerClasses();
- if (actualICs == null) actualICs = Collections.EMPTY_LIST;
+ private List<InnerClass> computeICdiff() {
+ List<InnerClass> impliedICs = computeGloballyImpliedICs();
+ List<InnerClass> actualICs = getInnerClasses();
+ if (actualICs == null)
+ actualICs = Collections.EMPTY_LIST;
// Symmetric difference is calculated from I, A like this:
// diff = (I+A) - (I*A)
@@ -388,8 +388,8 @@
// Diff is A since I is empty.
}
// (I*A) is non-trivial
- HashSet center = new HashSet(actualICs);
- center.retainAll(new HashSet(impliedICs));
+ HashSet<InnerClass> center = new HashSet<>(actualICs);
+ center.retainAll(new HashSet<>(impliedICs));
impliedICs.addAll(actualICs);
impliedICs.removeAll(center);
// Diff is now I^A = (I+A)-(I*A).
@@ -407,9 +407,9 @@
* to use the globally implied ICs changed.
*/
void minimizeLocalICs() {
- List diff = computeICdiff();
- List actualICs = innerClasses;
- List localICs; // will be the diff, modulo edge cases
+ List<InnerClass> diff = computeICdiff();
+ List<InnerClass> actualICs = innerClasses;
+ List<InnerClass> localICs; // will be the diff, modulo edge cases
if (diff.isEmpty()) {
// No diff, so transmit no attribute.
localICs = null;
@@ -439,12 +439,12 @@
* Otherwise, return positive if any IC tuples were added.
*/
int expandLocalICs() {
- List localICs = innerClasses;
- List actualICs;
+ List<InnerClass> localICs = innerClasses;
+ List<InnerClass> actualICs;
int changed;
if (localICs == null) {
// Diff was empty. (Common case.)
- List impliedICs = computeGloballyImpliedICs();
+ List<InnerClass> impliedICs = computeGloballyImpliedICs();
if (impliedICs.isEmpty()) {
actualICs = null;
changed = 0;
@@ -490,7 +490,7 @@
protected Entry[] getCPMap() {
return cpMap;
}
- protected void visitRefs(int mode, Collection refs) {
+ protected void visitRefs(int mode, Collection<Entry> refs) {
if (verbose > 2) Utils.log.fine("visitRefs "+this);
// Careful: The descriptor is used by the package,
// but the classfile breaks it into component refs.
@@ -518,7 +518,7 @@
super(flags, descriptor);
assert(!descriptor.isMethod());
if (fields == null)
- fields = new ArrayList();
+ fields = new ArrayList<>();
boolean added = fields.add(this);
assert(added);
order = fields.size();
@@ -543,7 +543,7 @@
super(flags, descriptor);
assert(descriptor.isMethod());
if (methods == null)
- methods = new ArrayList();
+ methods = new ArrayList<>();
boolean added = methods.add(this);
assert(added);
}
@@ -573,7 +573,7 @@
code.strip(attrName);
super.strip(attrName);
}
- protected void visitRefs(int mode, Collection refs) {
+ protected void visitRefs(int mode, Collection<Entry> refs) {
super.visitRefs(mode, refs);
if (code != null) {
if (mode == VRM_CLASSIC) {
@@ -614,7 +614,7 @@
super.strip(attrName);
}
- protected void visitRefs(int mode, Collection refs) {
+ protected void visitRefs(int mode, Collection<Entry> refs) {
if (verbose > 2) Utils.log.fine("visitRefs "+this);
refs.add(thisClass);
refs.add(superClass);
@@ -641,7 +641,7 @@
super.visitRefs(mode, refs);
}
- protected void visitInnerClassRefs(int mode, Collection refs) {
+ protected void visitInnerClassRefs(int mode, Collection<Entry> refs) {
Package.visitInnerClassRefs(innerClasses, mode, refs);
}
@@ -713,16 +713,15 @@
}
// What non-class files are in this unit?
- ArrayList files = new ArrayList();
+ ArrayList<File> files = new ArrayList<>();
- public List getFiles() {
+ public List<File> getFiles() {
return files;
}
- public List getClassStubs() {
- ArrayList classStubs = new ArrayList(classes.size());
- for (Iterator i = classes.iterator(); i.hasNext(); ) {
- Class cls = (Class) i.next();
+ public List<File> getClassStubs() {
+ ArrayList<File> classStubs = new ArrayList<>(classes.size());
+ for (Class cls : classes) {
assert(cls.file.isClassStub());
classStubs.add(cls.file);
}
@@ -840,7 +839,7 @@
public InputStream getInputStream() {
InputStream in = new ByteArrayInputStream(append.toByteArray());
if (prepend.size() == 0) return in;
- ArrayList isa = new ArrayList(prepend.size()+1);
+ ArrayList<InputStream> isa = new ArrayList<>(prepend.size()+1);
for (Iterator i = prepend.iterator(); i.hasNext(); ) {
byte[] bytes = (byte[]) i.next();
isa.add(new ByteArrayInputStream(bytes));
@@ -849,7 +848,7 @@
return new SequenceInputStream(Collections.enumeration(isa));
}
- protected void visitRefs(int mode, Collection refs) {
+ protected void visitRefs(int mode, Collection<Entry> refs) {
assert(name != null);
refs.add(name);
}
@@ -877,8 +876,8 @@
}
// Is there a globally declared table of inner classes?
- ArrayList allInnerClasses = new ArrayList();
- HashMap allInnerClassesByThis;
+ ArrayList<InnerClass> allInnerClasses = new ArrayList<>();
+ HashMap<ClassEntry, InnerClass> allInnerClassesByThis;
public
List getAllInnerClasses() {
@@ -886,15 +885,14 @@
}
public
- void setAllInnerClasses(Collection ics) {
+ void setAllInnerClasses(Collection<InnerClass> ics) {
assert(ics != allInnerClasses);
allInnerClasses.clear();
allInnerClasses.addAll(ics);
// Make an index:
- allInnerClassesByThis = new HashMap(allInnerClasses.size());
- for (Iterator i = allInnerClasses.iterator(); i.hasNext(); ) {
- InnerClass ic = (InnerClass) i.next();
+ allInnerClassesByThis = new HashMap<>(allInnerClasses.size());
+ for (InnerClass ic : allInnerClasses) {
Object pic = allInnerClassesByThis.put(ic.thisClass, ic);
assert(pic == null); // caller must ensure key uniqueness!
}
@@ -904,7 +902,7 @@
public
InnerClass getGlobalInnerClass(Entry thisClass) {
assert(thisClass instanceof ClassEntry);
- return (InnerClass) allInnerClassesByThis.get(thisClass);
+ return allInnerClassesByThis.get(thisClass);
}
static
@@ -963,7 +961,7 @@
return this.thisClass.compareTo(that.thisClass);
}
- protected void visitRefs(int mode, Collection refs) {
+ protected void visitRefs(int mode, Collection<Entry> refs) {
refs.add(thisClass);
if (mode == VRM_CLASSIC || !predictable) {
// If the name can be demangled, the package omits
@@ -980,7 +978,7 @@
// Helper for building InnerClasses attributes.
static private
- void visitInnerClassRefs(Collection innerClasses, int mode, Collection refs) {
+ void visitInnerClassRefs(Collection innerClasses, int mode, Collection<Entry> refs) {
if (innerClasses == null) {
return; // no attribute; nothing to do
}
@@ -1165,9 +1163,8 @@
}
}
- protected void visitRefs(int mode, Collection refs) {
- for (Iterator i = classes.iterator(); i.hasNext(); ) {
- Class c = (Class)i.next();
+ protected void visitRefs(int mode, Collection<Entry> refs) {
+ for ( Class c : classes) {
c.visitRefs(mode, refs);
}
if (mode != VRM_CLASSIC) {
@@ -1259,7 +1256,7 @@
}
// Use this before writing the package file.
- void buildGlobalConstantPool(Set requiredEntries) {
+ void buildGlobalConstantPool(Set<Entry> requiredEntries) {
if (verbose > 1)
Utils.log.fine("Checking for unused CP entries");
requiredEntries.add(getRefString("")); // uconditionally present
@@ -1291,9 +1288,8 @@
// Use this before writing the class files.
void ensureAllClassFiles() {
- HashSet fileSet = new HashSet(files);
- for (Iterator i = classes.iterator(); i.hasNext(); ) {
- Class cls = (Class) i.next();
+ HashSet<File> fileSet = new HashSet<>(files);
+ for (Class cls : classes) {
// Add to the end of ths list:
if (!fileSet.contains(cls.file))
files.add(cls.file);
--- a/jdk/src/share/classes/com/sun/java/util/jar/pack/PackerImpl.java Wed Sep 08 14:04:18 2010 -0700
+++ b/jdk/src/share/classes/com/sun/java/util/jar/pack/PackerImpl.java Wed Jul 05 17:21:22 2017 +0200
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2003, 2005, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -25,12 +25,11 @@
package com.sun.java.util.jar.pack;
+import com.sun.java.util.jar.pack.Attribute.Layout;
import java.util.*;
import java.util.jar.*;
-import java.util.zip.*;
import java.io.*;
import java.beans.PropertyChangeListener;
-import java.beans.PropertyChangeEvent;
/*
@@ -41,31 +40,22 @@
*/
-public class PackerImpl implements Pack200.Packer {
+public class PackerImpl extends TLGlobals implements Pack200.Packer {
/**
* Constructs a Packer object and sets the initial state of
* the packer engines.
*/
- public PackerImpl() {
- _props = new PropMap();
- //_props.getProperty() consults defaultProps invisibly.
- //_props.putAll(defaultProps);
- }
-
-
- // Private stuff.
- final PropMap _props;
+ public PackerImpl() {}
/**
* Get the set of options for the pack and unpack engines.
* @return A sorted association of option key strings to option values.
*/
- public SortedMap properties() {
- return _props;
+ public SortedMap<String, String> properties() {
+ return props;
}
-
//Driver routines
/**
@@ -78,21 +68,22 @@
*/
public void pack(JarFile in, OutputStream out) throws IOException {
assert(Utils.currentInstance.get() == null);
- TimeZone tz = (_props.getBoolean(Utils.PACK_DEFAULT_TIMEZONE)) ? null :
- TimeZone.getDefault();
+ TimeZone tz = (props.getBoolean(Utils.PACK_DEFAULT_TIMEZONE))
+ ? null
+ : TimeZone.getDefault();
try {
Utils.currentInstance.set(this);
if (tz != null) TimeZone.setDefault(TimeZone.getTimeZone("UTC"));
- if ("0".equals(_props.getProperty(Pack200.Packer.EFFORT))) {
+ if ("0".equals(props.getProperty(Pack200.Packer.EFFORT))) {
Utils.copyJarFile(in, out);
} else {
(new DoPack()).run(in, out);
- in.close();
}
} finally {
Utils.currentInstance.set(null);
if (tz != null) TimeZone.setDefault(tz);
+ in.close();
}
}
@@ -112,21 +103,20 @@
*/
public void pack(JarInputStream in, OutputStream out) throws IOException {
assert(Utils.currentInstance.get() == null);
- TimeZone tz = (_props.getBoolean(Utils.PACK_DEFAULT_TIMEZONE)) ? null :
+ TimeZone tz = (props.getBoolean(Utils.PACK_DEFAULT_TIMEZONE)) ? null :
TimeZone.getDefault();
try {
Utils.currentInstance.set(this);
if (tz != null) TimeZone.setDefault(TimeZone.getTimeZone("UTC"));
- if ("0".equals(_props.getProperty(Pack200.Packer.EFFORT))) {
+ if ("0".equals(props.getProperty(Pack200.Packer.EFFORT))) {
Utils.copyJarFile(in, out);
} else {
(new DoPack()).run(in, out);
- in.close();
}
} finally {
Utils.currentInstance.set(null);
if (tz != null) TimeZone.setDefault(tz);
-
+ in.close();
}
}
/**
@@ -134,7 +124,7 @@
* @param listener An object to be invoked when a property is changed.
*/
public void addPropertyChangeListener(PropertyChangeListener listener) {
- _props.addListener(listener);
+ props.addListener(listener);
}
/**
@@ -142,7 +132,7 @@
* @param listener The PropertyChange listener to be removed.
*/
public void removePropertyChangeListener(PropertyChangeListener listener) {
- _props.removeListener(listener);
+ props.removeListener(listener);
}
@@ -151,11 +141,11 @@
// The packer worker.
private class DoPack {
- final int verbose = _props.getInteger(Utils.DEBUG_VERBOSE);
+ final int verbose = props.getInteger(Utils.DEBUG_VERBOSE);
{
- _props.setInteger(Pack200.Packer.PROGRESS, 0);
- if (verbose > 0) Utils.log.info(_props.toString());
+ props.setInteger(Pack200.Packer.PROGRESS, 0);
+ if (verbose > 0) Utils.log.info(props.toString());
}
// Here's where the bits are collected before getting packed:
@@ -163,7 +153,7 @@
final String unknownAttrCommand;
{
- String uaMode = _props.getProperty(Pack200.Packer.UNKNOWN_ATTRIBUTE, Pack200.Packer.PASS);
+ String uaMode = props.getProperty(Pack200.Packer.UNKNOWN_ATTRIBUTE, Pack200.Packer.PASS);
if (!(Pack200.Packer.STRIP.equals(uaMode) ||
Pack200.Packer.PASS.equals(uaMode) ||
Pack200.Packer.ERROR.equals(uaMode))) {
@@ -191,13 +181,12 @@
};
for (int i = 0; i < ctypes.length; i++) {
String pfx = keys[i];
- Map map = _props.prefixMap(pfx);
- for (Iterator j = map.keySet().iterator(); j.hasNext(); ) {
- String key = (String) j.next();
+ Map<String, String> map = props.prefixMap(pfx);
+ for (String key : map.keySet()) {
assert(key.startsWith(pfx));
String name = key.substring(pfx.length());
- String layout = _props.getProperty(key);
- Object lkey = Attribute.keyForLookup(ctypes[i], name);
+ String layout = props.getProperty(key);
+ Layout lkey = Attribute.keyForLookup(ctypes[i], name);
if (Pack200.Packer.STRIP.equals(layout) ||
Pack200.Packer.PASS.equals(layout) ||
Pack200.Packer.ERROR.equals(layout)) {
@@ -222,25 +211,25 @@
}
final boolean keepFileOrder
- = _props.getBoolean(Pack200.Packer.KEEP_FILE_ORDER);
+ = props.getBoolean(Pack200.Packer.KEEP_FILE_ORDER);
final boolean keepClassOrder
- = _props.getBoolean(Utils.PACK_KEEP_CLASS_ORDER);
+ = props.getBoolean(Utils.PACK_KEEP_CLASS_ORDER);
final boolean keepModtime
- = Pack200.Packer.KEEP.equals(_props.getProperty(Pack200.Packer.MODIFICATION_TIME));
+ = Pack200.Packer.KEEP.equals(props.getProperty(Pack200.Packer.MODIFICATION_TIME));
final boolean latestModtime
- = Pack200.Packer.LATEST.equals(_props.getProperty(Pack200.Packer.MODIFICATION_TIME));
+ = Pack200.Packer.LATEST.equals(props.getProperty(Pack200.Packer.MODIFICATION_TIME));
final boolean keepDeflateHint
- = Pack200.Packer.KEEP.equals(_props.getProperty(Pack200.Packer.DEFLATE_HINT));
+ = Pack200.Packer.KEEP.equals(props.getProperty(Pack200.Packer.DEFLATE_HINT));
{
if (!keepModtime && !latestModtime) {
- int modtime = _props.getTime(Pack200.Packer.MODIFICATION_TIME);
+ int modtime = props.getTime(Pack200.Packer.MODIFICATION_TIME);
if (modtime != Constants.NO_MODTIME) {
pkg.default_modtime = modtime;
}
}
if (!keepDeflateHint) {
- boolean deflate_hint = _props.getBoolean(Pack200.Packer.DEFLATE_HINT);
+ boolean deflate_hint = props.getBoolean(Pack200.Packer.DEFLATE_HINT);
if (deflate_hint) {
pkg.default_options |= Constants.AO_DEFLATE_HINT;
}
@@ -254,10 +243,10 @@
final long segmentLimit;
{
long limit;
- if (_props.getProperty(Pack200.Packer.SEGMENT_LIMIT, "").equals(""))
+ if (props.getProperty(Pack200.Packer.SEGMENT_LIMIT, "").equals(""))
limit = -1;
else
- limit = _props.getLong(Pack200.Packer.SEGMENT_LIMIT);
+ limit = props.getLong(Pack200.Packer.SEGMENT_LIMIT);
limit = Math.min(Integer.MAX_VALUE, limit);
limit = Math.max(-1, limit);
if (limit == -1)
@@ -265,10 +254,10 @@
segmentLimit = limit;
}
- final List passFiles; // parsed pack.pass.file options
+ final List<String> passFiles; // parsed pack.pass.file options
{
// Which class files will be passed through?
- passFiles = _props.getProperties(Pack200.Packer.PASS_FILE_PFX);
+ passFiles = props.getProperties(Pack200.Packer.PASS_FILE_PFX);
for (ListIterator i = passFiles.listIterator(); i.hasNext(); ) {
String file = (String) i.next();
if (file == null) { i.remove(); continue; }
@@ -283,28 +272,28 @@
{
// Fill in permitted range of major/minor version numbers.
int ver;
- if ((ver = _props.getInteger(Utils.COM_PREFIX+"min.class.majver")) != 0)
+ if ((ver = props.getInteger(Utils.COM_PREFIX+"min.class.majver")) != 0)
pkg.min_class_majver = (short) ver;
- if ((ver = _props.getInteger(Utils.COM_PREFIX+"min.class.minver")) != 0)
+ if ((ver = props.getInteger(Utils.COM_PREFIX+"min.class.minver")) != 0)
pkg.min_class_minver = (short) ver;
- if ((ver = _props.getInteger(Utils.COM_PREFIX+"max.class.majver")) != 0)
+ if ((ver = props.getInteger(Utils.COM_PREFIX+"max.class.majver")) != 0)
pkg.max_class_majver = (short) ver;
- if ((ver = _props.getInteger(Utils.COM_PREFIX+"max.class.minver")) != 0)
+ if ((ver = props.getInteger(Utils.COM_PREFIX+"max.class.minver")) != 0)
pkg.max_class_minver = (short) ver;
- if ((ver = _props.getInteger(Utils.COM_PREFIX+"package.minver")) != 0)
+ if ((ver = props.getInteger(Utils.COM_PREFIX+"package.minver")) != 0)
pkg.package_minver = (short) ver;
- if ((ver = _props.getInteger(Utils.COM_PREFIX+"package.majver")) != 0)
+ if ((ver = props.getInteger(Utils.COM_PREFIX+"package.majver")) != 0)
pkg.package_majver = (short) ver;
}
{
// Hook for testing: Forces use of special archive modes.
- int opt = _props.getInteger(Utils.COM_PREFIX+"archive.options");
+ int opt = props.getInteger(Utils.COM_PREFIX+"archive.options");
if (opt != 0)
pkg.default_options |= opt;
}
- // (Done collecting options from _props.)
+ // (Done collecting options from props.)
boolean isClassFile(String name) {
if (!name.endsWith(".class")) return false;
@@ -423,16 +412,18 @@
Package.File file = null;
// (5078608) : discount the resource files in META-INF
// from segment computation.
- long inflen = (isMetaInfFile(name)) ? 0L :
- inFile.getInputLength();
+ long inflen = (isMetaInfFile(name))
+ ? 0L
+ : inFile.getInputLength();
if ((segmentSize += inflen) > segmentLimit) {
segmentSize -= inflen;
int nextCount = -1; // don't know; it's a stream
flushPartial(out, nextCount);
}
- if (verbose > 1)
+ if (verbose > 1) {
Utils.log.fine("Reading " + name);
+ }
assert(je.isDirectory() == name.endsWith("/"));
@@ -450,18 +441,18 @@
}
void run(JarFile in, OutputStream out) throws IOException {
- List inFiles = scanJar(in);
+ List<InFile> inFiles = scanJar(in);
if (verbose > 0)
Utils.log.info("Reading " + inFiles.size() + " files...");
int numDone = 0;
- for (Iterator i = inFiles.iterator(); i.hasNext(); ) {
- InFile inFile = (InFile) i.next();
+ for (InFile inFile : inFiles) {
String name = inFile.name;
// (5078608) : discount the resource files completely from segmenting
- long inflen = (isMetaInfFile(name)) ? 0L :
- inFile.getInputLength() ;
+ long inflen = (isMetaInfFile(name))
+ ? 0L
+ : inFile.getInputLength() ;
if ((segmentSize += inflen) > segmentLimit) {
segmentSize -= inflen;
// Estimate number of remaining segments:
@@ -530,11 +521,11 @@
}
void flushPartial(OutputStream out, int nextCount) throws IOException {
- if (pkg.files.size() == 0 && pkg.classes.size() == 0) {
+ if (pkg.files.isEmpty() && pkg.classes.isEmpty()) {
return; // do not flush an empty segment
}
flushPackage(out, Math.max(1, nextCount));
- _props.setInteger(Pack200.Packer.PROGRESS, 25);
+ props.setInteger(Pack200.Packer.PROGRESS, 25);
// In case there will be another segment:
makeNextPackage();
segmentCount += 1;
@@ -543,10 +534,10 @@
}
void flushAll(OutputStream out) throws IOException {
- _props.setInteger(Pack200.Packer.PROGRESS, 50);
+ props.setInteger(Pack200.Packer.PROGRESS, 50);
flushPackage(out, 0);
out.flush();
- _props.setInteger(Pack200.Packer.PROGRESS, 100);
+ props.setInteger(Pack200.Packer.PROGRESS, 100);
segmentCount += 1;
segmentTotalSize += segmentSize;
segmentSize = 0;
@@ -582,11 +573,11 @@
pkg.trimStubs();
// Do some stripping, maybe.
- if (_props.getBoolean(Utils.COM_PREFIX+"strip.debug")) pkg.stripAttributeKind("Debug");
- if (_props.getBoolean(Utils.COM_PREFIX+"strip.compile")) pkg.stripAttributeKind("Compile");
- if (_props.getBoolean(Utils.COM_PREFIX+"strip.constants")) pkg.stripAttributeKind("Constant");
- if (_props.getBoolean(Utils.COM_PREFIX+"strip.exceptions")) pkg.stripAttributeKind("Exceptions");
- if (_props.getBoolean(Utils.COM_PREFIX+"strip.innerclasses")) pkg.stripAttributeKind("InnerClasses");
+ if (props.getBoolean(Utils.COM_PREFIX+"strip.debug")) pkg.stripAttributeKind("Debug");
+ if (props.getBoolean(Utils.COM_PREFIX+"strip.compile")) pkg.stripAttributeKind("Compile");
+ if (props.getBoolean(Utils.COM_PREFIX+"strip.constants")) pkg.stripAttributeKind("Constant");
+ if (props.getBoolean(Utils.COM_PREFIX+"strip.exceptions")) pkg.stripAttributeKind("Exceptions");
+ if (props.getBoolean(Utils.COM_PREFIX+"strip.innerclasses")) pkg.stripAttributeKind("InnerClasses");
// Must choose an archive version; PackageWriter does not.
if (pkg.package_majver <= 0) pkg.choosePackageVersion();
@@ -606,11 +597,10 @@
}
}
- List scanJar(JarFile jf) throws IOException {
+ List<InFile> scanJar(JarFile jf) throws IOException {
// Collect jar entries, preserving order.
- List inFiles = new ArrayList();
- for (Enumeration e = jf.entries(); e.hasMoreElements(); ) {
- JarEntry je = (JarEntry) e.nextElement();
+ List<InFile> inFiles = new ArrayList<>();
+ for (JarEntry je : Collections.list(jf.entries())) {
InFile inFile = new InFile(jf, je);
assert(je.isDirectory() == inFile.name.endsWith("/"));
inFiles.add(inFile);
--- a/jdk/src/share/classes/com/sun/java/util/jar/pack/PropMap.java Wed Sep 08 14:04:18 2010 -0700
+++ b/jdk/src/share/classes/com/sun/java/util/jar/pack/PropMap.java Wed Jul 05 17:21:22 2017 +0200
@@ -91,7 +91,7 @@
String.valueOf(Boolean.getBoolean(Utils.PACK_DEFAULT_TIMEZONE)));
// The segment size is unlimited
- props.put(Pack200.Packer.SEGMENT_LIMIT, "");
+ props.put(Pack200.Packer.SEGMENT_LIMIT, "-1");
// Preserve file ordering by default.
props.put(Pack200.Packer.KEEP_FILE_ORDER, Pack200.Packer.TRUE);
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/com/sun/java/util/jar/pack/TLGlobals.java Wed Jul 05 17:21:22 2017 +0200
@@ -0,0 +1,97 @@
+/*
+ * Copyright (c) 2010, 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.
+ */
+package com.sun.java.util.jar.pack;
+
+import com.sun.java.util.jar.pack.ConstantPool.ClassEntry;
+import com.sun.java.util.jar.pack.ConstantPool.DescriptorEntry;
+import com.sun.java.util.jar.pack.ConstantPool.LiteralEntry;
+import com.sun.java.util.jar.pack.ConstantPool.MemberEntry;
+import com.sun.java.util.jar.pack.ConstantPool.SignatureEntry;
+import com.sun.java.util.jar.pack.ConstantPool.Utf8Entry;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.SortedMap;
+
+/*
+ * @author ksrini
+ */
+
+/*
+ * This class provides a container to hold the global variables, for packer
+ * and unpacker instances. This is typically stashed away in a ThreadLocal,
+ * and the storage is destroyed upon completion. Therefore any local
+ * references to these members must be eliminated appropriately to prevent a
+ * memory leak.
+ */
+class TLGlobals {
+ // Global environment
+ final PropMap props;
+
+ // Needed by ConstantPool.java
+ private final Map<String, Utf8Entry> utf8Entries;
+ private final Map<String, ClassEntry> classEntries;
+ private final Map<Object, LiteralEntry> literalEntries;
+ private final Map<String, SignatureEntry> signatureEntries;
+ private final Map<String, DescriptorEntry> descriptorEntries;
+ private final Map<String, MemberEntry> memberEntries;
+
+ TLGlobals() {
+ utf8Entries = new HashMap<>();
+ classEntries = new HashMap<>();
+ literalEntries = new HashMap<>();
+ signatureEntries = new HashMap<>();
+ descriptorEntries = new HashMap<>();
+ memberEntries = new HashMap<>();
+ props = new PropMap();
+ }
+
+ SortedMap<Object, Object> getPropMap() {
+ return props;
+ }
+
+ Map<String, Utf8Entry> getUtf8Entries() {
+ return utf8Entries;
+ }
+
+ Map<String, ClassEntry> getClassEntries() {
+ return classEntries;
+ }
+
+ Map<Object, LiteralEntry> getLiteralEntries() {
+ return literalEntries;
+ }
+
+ Map<String, DescriptorEntry> getDescriptorEntries() {
+ return descriptorEntries;
+ }
+
+ Map<String, SignatureEntry> getSignatureEntries() {
+ return signatureEntries;
+ }
+
+ Map<String, MemberEntry> getMemberEntries() {
+ return memberEntries;
+ }
+}
--- a/jdk/src/share/classes/com/sun/java/util/jar/pack/UnpackerImpl.java Wed Sep 08 14:04:18 2010 -0700
+++ b/jdk/src/share/classes/com/sun/java/util/jar/pack/UnpackerImpl.java Wed Jul 05 17:21:22 2017 +0200
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2003, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 2010, 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
@@ -30,7 +30,6 @@
import java.util.zip.*;
import java.io.*;
import java.beans.PropertyChangeListener;
-import java.beans.PropertyChangeEvent;
/*
* Implementation of the Pack provider.
@@ -40,7 +39,7 @@
*/
-public class UnpackerImpl implements Pack200.Unpacker {
+public class UnpackerImpl extends TLGlobals implements Pack200.Unpacker {
/**
@@ -48,7 +47,7 @@
* @param listener An object to be invoked when a property is changed.
*/
public void addPropertyChangeListener(PropertyChangeListener listener) {
- _props.addListener(listener);
+ props.addListener(listener);
}
@@ -57,25 +56,19 @@
* @param listener The PropertyChange listener to be removed.
*/
public void removePropertyChangeListener(PropertyChangeListener listener) {
- _props.removeListener(listener);
+ props.removeListener(listener);
}
- public UnpackerImpl() {
- _props = new PropMap();
- //_props.getProperty() consults defaultProps invisibly.
- //_props.putAll(defaultProps);
- }
+ public UnpackerImpl() {}
- // Private stuff.
- final PropMap _props;
/**
* Get the set of options for the pack and unpack engines.
* @return A sorted association of option key strings to option values.
*/
- public SortedMap properties() {
- return _props;
+ public SortedMap<String, String> properties() {
+ return props;
}
// Back-pointer to NativeUnpacker, when active.
@@ -101,19 +94,20 @@
*/
public void unpack(InputStream in0, JarOutputStream out) throws IOException {
assert(Utils.currentInstance.get() == null);
- TimeZone tz = (_props.getBoolean(Utils.PACK_DEFAULT_TIMEZONE)) ? null :
- TimeZone.getDefault();
+ TimeZone tz = (props.getBoolean(Utils.PACK_DEFAULT_TIMEZONE))
+ ? null
+ : TimeZone.getDefault();
try {
Utils.currentInstance.set(this);
if (tz != null) TimeZone.setDefault(TimeZone.getTimeZone("UTC"));
- final int verbose = _props.getInteger(Utils.DEBUG_VERBOSE);
+ final int verbose = props.getInteger(Utils.DEBUG_VERBOSE);
BufferedInputStream in = new BufferedInputStream(in0);
if (Utils.isJarMagic(Utils.readMagic(in))) {
if (verbose > 0)
Utils.log.info("Copying unpacked JAR file...");
Utils.copyJarFile(new JarInputStream(in), out);
- } else if (_props.getBoolean(Utils.DEBUG_DISABLE_NATIVE)) {
+ } else if (props.getBoolean(Utils.DEBUG_DISABLE_NATIVE)) {
(new DoUnpack()).run(in, out);
in.close();
Utils.markJarFile(out);
@@ -142,36 +136,38 @@
// %%% Reconsider if native unpacker learns to memory-map the file.
FileInputStream instr = new FileInputStream(in);
unpack(instr, out);
- if (_props.getBoolean(Utils.UNPACK_REMOVE_PACKFILE)) {
+ if (props.getBoolean(Utils.UNPACK_REMOVE_PACKFILE)) {
in.delete();
}
}
private class DoUnpack {
- final int verbose = _props.getInteger(Utils.DEBUG_VERBOSE);
+ final int verbose = props.getInteger(Utils.DEBUG_VERBOSE);
{
- _props.setInteger(Pack200.Unpacker.PROGRESS, 0);
+ props.setInteger(Pack200.Unpacker.PROGRESS, 0);
}
// Here's where the bits are read from disk:
final Package pkg = new Package();
final boolean keepModtime
- = Pack200.Packer.KEEP.equals(_props.getProperty(Utils.UNPACK_MODIFICATION_TIME, Pack200.Packer.KEEP));
+ = Pack200.Packer.KEEP.equals(
+ props.getProperty(Utils.UNPACK_MODIFICATION_TIME, Pack200.Packer.KEEP));
final boolean keepDeflateHint
- = Pack200.Packer.KEEP.equals(_props.getProperty(Pack200.Unpacker.DEFLATE_HINT, Pack200.Packer.KEEP));
+ = Pack200.Packer.KEEP.equals(
+ props.getProperty(Pack200.Unpacker.DEFLATE_HINT, Pack200.Packer.KEEP));
final int modtime;
final boolean deflateHint;
{
if (!keepModtime) {
- modtime = _props.getTime(Utils.UNPACK_MODIFICATION_TIME);
+ modtime = props.getTime(Utils.UNPACK_MODIFICATION_TIME);
} else {
modtime = pkg.default_modtime;
}
deflateHint = (keepDeflateHint) ? false :
- _props.getBoolean(java.util.jar.Pack200.Unpacker.DEFLATE_HINT);
+ props.getBoolean(java.util.jar.Pack200.Unpacker.DEFLATE_HINT);
}
// Checksum apparatus.
@@ -181,7 +177,7 @@
public void run(BufferedInputStream in, JarOutputStream out) throws IOException {
if (verbose > 0) {
- _props.list(System.out);
+ props.list(System.out);
}
for (int seg = 1; ; seg++) {
unpackSegment(in, out);
@@ -194,25 +190,26 @@
}
private void unpackSegment(InputStream in, JarOutputStream out) throws IOException {
- _props.setProperty(java.util.jar.Pack200.Unpacker.PROGRESS,"0");
+ props.setProperty(java.util.jar.Pack200.Unpacker.PROGRESS,"0");
// Process the output directory or jar output.
new PackageReader(pkg, in).read();
- if (_props.getBoolean("unpack.strip.debug")) pkg.stripAttributeKind("Debug");
- if (_props.getBoolean("unpack.strip.compile")) pkg.stripAttributeKind("Compile");
- _props.setProperty(java.util.jar.Pack200.Unpacker.PROGRESS,"50");
+ if (props.getBoolean("unpack.strip.debug")) pkg.stripAttributeKind("Debug");
+ if (props.getBoolean("unpack.strip.compile")) pkg.stripAttributeKind("Compile");
+ props.setProperty(java.util.jar.Pack200.Unpacker.PROGRESS,"50");
pkg.ensureAllClassFiles();
// Now write out the files.
- HashSet classesToWrite = new HashSet(pkg.getClasses());
+ HashSet<Package.Class> classesToWrite = new HashSet<>(pkg.getClasses());
for (Iterator i = pkg.getFiles().iterator(); i.hasNext(); ) {
Package.File file = (Package.File) i.next();
String name = file.nameString;
JarEntry je = new JarEntry(Utils.getJarEntryName(name));
boolean deflate;
- deflate = (keepDeflateHint) ? (((file.options & Constants.FO_DEFLATE_HINT) != 0) ||
- ((pkg.default_options & Constants.AO_DEFLATE_HINT) != 0)) :
- deflateHint;
+ deflate = (keepDeflateHint)
+ ? (((file.options & Constants.FO_DEFLATE_HINT) != 0) ||
+ ((pkg.default_options & Constants.AO_DEFLATE_HINT) != 0))
+ : deflateHint;
boolean needCRC = !deflate; // STORE mode requires CRC
@@ -250,7 +247,7 @@
Utils.log.info("Writing "+Utils.zeString((ZipEntry)je));
}
assert(classesToWrite.isEmpty());
- _props.setProperty(java.util.jar.Pack200.Unpacker.PROGRESS,"100");
+ props.setProperty(java.util.jar.Pack200.Unpacker.PROGRESS,"100");
pkg.reset(); // reset for the next segment, if any
}
}
--- a/jdk/src/share/classes/com/sun/java/util/jar/pack/Utils.java Wed Sep 08 14:04:18 2010 -0700
+++ b/jdk/src/share/classes/com/sun/java/util/jar/pack/Utils.java Wed Jul 05 17:21:22 2017 +0200
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2003, 2005, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -25,6 +25,13 @@
package com.sun.java.util.jar.pack;
+import com.sun.java.util.jar.pack.Attribute.Layout;
+import com.sun.java.util.jar.pack.ConstantPool.ClassEntry;
+import com.sun.java.util.jar.pack.ConstantPool.DescriptorEntry;
+import com.sun.java.util.jar.pack.ConstantPool.LiteralEntry;
+import com.sun.java.util.jar.pack.ConstantPool.MemberEntry;
+import com.sun.java.util.jar.pack.ConstantPool.SignatureEntry;
+import com.sun.java.util.jar.pack.ConstantPool.Utf8Entry;
import java.util.*;
import java.util.jar.*;
import java.util.zip.*;
@@ -113,17 +120,46 @@
*/
static final String PACK_ZIP_ARCHIVE_MARKER_COMMENT = "PACK200";
- // Keep a TLS point to the current Packer or Unpacker.
- // This makes it simpler to supply environmental options
+ // Keep a TLS point to the global data and environment.
+ // This makes it simpler to supply environmental options
// to the engine code, especially the native code.
- static final ThreadLocal currentInstance = new ThreadLocal();
+ static final ThreadLocal<TLGlobals> currentInstance = new ThreadLocal<>();
+
+ // convenience methods to access the TL globals
+ static TLGlobals getTLGlobals() {
+ return currentInstance.get();
+ }
+
+ static Map<String, Utf8Entry> getUtf8Entries() {
+ return getTLGlobals().getUtf8Entries();
+ }
+
+ static Map<String, ClassEntry> getClassEntries() {
+ return getTLGlobals().getClassEntries();
+ }
+
+ static Map<Object, LiteralEntry> getLiteralEntries() {
+ return getTLGlobals().getLiteralEntries();
+ }
+
+ static Map<String, DescriptorEntry> getDescriptorEntries() {
+ return getTLGlobals().getDescriptorEntries();
+ }
+
+ static Map<String, SignatureEntry> getSignatureEntries() {
+ return getTLGlobals().getSignatureEntries();
+ }
+
+ static Map<String, MemberEntry> getMemberEntries() {
+ return getTLGlobals().getMemberEntries();
+ }
static PropMap currentPropMap() {
Object obj = currentInstance.get();
if (obj instanceof PackerImpl)
- return ((PackerImpl)obj)._props;
+ return ((PackerImpl)obj).props;
if (obj instanceof UnpackerImpl)
- return ((UnpackerImpl)obj)._props;
+ return ((UnpackerImpl)obj).props;
return null;
}
--- a/jdk/src/share/classes/com/sun/jndi/ldap/Connection.java Wed Sep 08 14:04:18 2010 -0700
+++ b/jdk/src/share/classes/com/sun/jndi/ldap/Connection.java Wed Jul 05 17:21:22 2017 +0200
@@ -813,7 +813,8 @@
try {
while (true) {
try {
- inbuf = new byte[10];
+ // type and length (at most 128 octets for long form)
+ inbuf = new byte[129];
offset = 0;
seqlen = 0;
--- a/jdk/src/share/classes/java/lang/AbstractStringBuilder.java Wed Sep 08 14:04:18 2010 -0700
+++ b/jdk/src/share/classes/java/lang/AbstractStringBuilder.java Wed Jul 05 17:21:22 2017 +0200
@@ -470,7 +470,7 @@
public AbstractStringBuilder append(CharSequence s, int start, int end) {
if (s == null)
s = "null";
- if ((start < 0) || (end < 0) || (start > end) || (end > s.length()))
+ if ((start < 0) || (start > end) || (end > s.length()))
throw new IndexOutOfBoundsException(
"start " + start + ", end " + end + ", s.length() "
+ s.length());
@@ -529,7 +529,8 @@
* or {@code offset+len > str.length}
*/
public AbstractStringBuilder append(char str[], int offset, int len) {
- ensureCapacityInternal(count + len);
+ if (len > 0) // let arraycopy report AIOOBE for len < 0
+ ensureCapacityInternal(count + len);
System.arraycopy(str, offset, value, count, len);
count += len;
return this;
--- a/jdk/src/share/classes/java/lang/Thread.java Wed Sep 08 14:04:18 2010 -0700
+++ b/jdk/src/share/classes/java/lang/Thread.java Wed Jul 05 17:21:22 2017 +0200
@@ -414,6 +414,18 @@
}
/**
+ * Throws CloneNotSupportedException as a Thread can not be meaningfully
+ * cloned. Construct a new Thread instead.
+ *
+ * @throws CloneNotSupportedException
+ * always
+ */
+ @Override
+ protected Object clone() throws CloneNotSupportedException {
+ throw new CloneNotSupportedException();
+ }
+
+ /**
* Allocates a new {@code Thread} object. This constructor has the same
* effect as {@linkplain #Thread(ThreadGroup,Runnable,String) Thread}
* {@code (null, null, gname)}, where {@code gname} is a newly generated
--- a/jdk/src/share/classes/java/lang/Throwable.java Wed Sep 08 14:04:18 2010 -0700
+++ b/jdk/src/share/classes/java/lang/Throwable.java Wed Jul 05 17:21:22 2017 +0200
@@ -200,7 +200,16 @@
* @serial
* @since 1.7
*/
- private List<Throwable> suppressedExceptions = Collections.emptyList();
+ private List<Throwable> suppressedExceptions = null;
+ /*
+ * This field is lazily initialized when the first suppressed
+ * exception is added.
+ *
+ * OutOfMemoryError is preallocated in the VM for better OOM
+ * diagnosability during VM initialization. Constructor can't
+ * be not invoked. If a new field to be added in the future must
+ * be initialized to non-null, it requires a synchronized VM change.
+ */
/** Message for trying to suppress a null exception. */
private static final String NULL_CAUSE_MESSAGE = "Cannot suppress a null exception.";
@@ -329,7 +338,7 @@
* cause is nonexistent or unknown.
* @since 1.4
*/
- public Throwable getCause() {
+ public synchronized Throwable getCause() {
return (cause==this ? null : cause);
}
@@ -563,7 +572,7 @@
s.println("\tat " + traceElement);
// Print suppressed exceptions, if any
- for (Throwable se : suppressedExceptions)
+ for (Throwable se : getSuppressedExceptions())
se.printEnclosedStackTrace(s, trace, SUPPRESSED_CAPTION, "\t", dejaVu);
// Print cause, if any
@@ -604,7 +613,7 @@
s.println(prefix + "\t... " + framesInCommon + " more");
// Print suppressed exceptions, if any
- for (Throwable se : suppressedExceptions)
+ for (Throwable se : getSuppressedExceptions())
se.printEnclosedStackTrace(s, trace, SUPPRESSED_CAPTION,
prefix +"\t", dejaVu);
@@ -747,7 +756,9 @@
if (defensiveCopy[i] == null)
throw new NullPointerException("stackTrace[" + i + "]");
- this.stackTrace = defensiveCopy;
+ synchronized (this) {
+ this.stackTrace = defensiveCopy;
+ }
}
/**
@@ -772,11 +783,11 @@
private void readObject(ObjectInputStream s)
throws IOException, ClassNotFoundException {
s.defaultReadObject(); // read in all fields
- List<Throwable> suppressed = Collections.emptyList();
+ List<Throwable> suppressed = null;
if (suppressedExceptions != null &&
!suppressedExceptions.isEmpty()) { // Copy Throwables to new list
suppressed = new ArrayList<Throwable>();
- for(Throwable t : suppressedExceptions) {
+ for (Throwable t : suppressedExceptions) {
if (t == null)
throw new NullPointerException(NULL_CAUSE_MESSAGE);
suppressed.add(t);
@@ -819,7 +830,7 @@
if (exception == this)
throw new IllegalArgumentException("Self-suppression not permitted");
- if (suppressedExceptions.size() == 0)
+ if (suppressedExceptions == null)
suppressedExceptions = new ArrayList<Throwable>();
suppressedExceptions.add(exception);
}
@@ -835,7 +846,10 @@
* suppressed to deliver this exception.
* @since 1.7
*/
- public Throwable[] getSuppressedExceptions() {
- return suppressedExceptions.toArray(EMPTY_THROWABLE_ARRAY);
+ public synchronized Throwable[] getSuppressedExceptions() {
+ if (suppressedExceptions == null)
+ return EMPTY_THROWABLE_ARRAY;
+ else
+ return suppressedExceptions.toArray(EMPTY_THROWABLE_ARRAY);
}
}
--- a/jdk/src/share/classes/java/net/HttpCookie.java Wed Sep 08 14:04:18 2010 -0700
+++ b/jdk/src/share/classes/java/net/HttpCookie.java Wed Jul 05 17:21:22 2017 +0200
@@ -1093,14 +1093,8 @@
return sb.toString();
}
- private static SimpleDateFormat[] cDateFormats = null;
- static {
- cDateFormats = new SimpleDateFormat[COOKIE_DATE_FORMATS.length];
- for (int i = 0; i < COOKIE_DATE_FORMATS.length; i++) {
- cDateFormats[i] = new SimpleDateFormat(COOKIE_DATE_FORMATS[i], Locale.US);
- cDateFormats[i].setTimeZone(TimeZone.getTimeZone("GMT"));
- }
- }
+ static final TimeZone GMT = TimeZone.getTimeZone("GMT");
+
/*
* @param dateString a date string in one of the formats
* defined in Netscape cookie spec
@@ -1109,12 +1103,14 @@
* time and the time specified by dateString
*/
private long expiryDate2DeltaSeconds(String dateString) {
- for (SimpleDateFormat df : cDateFormats) {
+ for (int i = 0; i < COOKIE_DATE_FORMATS.length; i++) {
+ SimpleDateFormat df = new SimpleDateFormat(COOKIE_DATE_FORMATS[i], Locale.US);
+ df.setTimeZone(GMT);
try {
Date date = df.parse(dateString);
return (date.getTime() - whenCreated) / 1000;
} catch (Exception e) {
-
+ // Ignore, try the next date format
}
}
return 0;
--- a/jdk/src/share/classes/java/net/URI.java Wed Sep 08 14:04:18 2010 -0700
+++ b/jdk/src/share/classes/java/net/URI.java Wed Jul 05 17:21:22 2017 +0200
@@ -856,9 +856,7 @@
try {
return new URI(str);
} catch (URISyntaxException x) {
- IllegalArgumentException y = new IllegalArgumentException();
- y.initCause(x);
- throw y;
+ throw new IllegalArgumentException(x.getMessage(), x);
}
}
--- a/jdk/src/share/classes/java/security/KeyStore.java Wed Sep 08 14:04:18 2010 -0700
+++ b/jdk/src/share/classes/java/security/KeyStore.java Wed Jul 05 17:21:22 2017 +0200
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997, 2008, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2010, 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
@@ -131,17 +131,19 @@
* to read existing entries from the keystore, or to write new entries
* into the keystore:
* <pre>
+ * KeyStore.ProtectionParameter protParam =
+ * new KeyStore.PasswordProtection(password);
+ *
* // get my private key
* KeyStore.PrivateKeyEntry pkEntry = (KeyStore.PrivateKeyEntry)
- * ks.getEntry("privateKeyAlias", password);
+ * ks.getEntry("privateKeyAlias", protParam);
* PrivateKey myPrivateKey = pkEntry.getPrivateKey();
*
* // save my secret key
* javax.crypto.SecretKey mySecretKey;
* KeyStore.SecretKeyEntry skEntry =
* new KeyStore.SecretKeyEntry(mySecretKey);
- * ks.setEntry("secretKeyAlias", skEntry,
- * new KeyStore.PasswordProtection(password));
+ * ks.setEntry("secretKeyAlias", skEntry, protParam);
*
* // store away the keystore
* java.io.FileOutputStream fos = null;
--- a/jdk/src/share/classes/java/sql/Date.java Wed Sep 08 14:04:18 2010 -0700
+++ b/jdk/src/share/classes/java/sql/Date.java Wed Jul 05 17:21:22 2017 +0200
@@ -103,27 +103,46 @@
* JDBC date escape format (yyyy-mm-dd)
*/
public static Date valueOf(String s) {
- int year;
- int month;
- int day;
+ final int YEAR_LENGTH = 4;
+ final int MONTH_LENGTH = 2;
+ final int DAY_LENGTH = 2;
+ final int MAX_MONTH = 12;
+ final int MAX_DAY = 31;
int firstDash;
int secondDash;
-
- if (s == null) throw new java.lang.IllegalArgumentException();
+ Date d = null;
- firstDash = s.indexOf('-');
- secondDash = s.indexOf('-', firstDash+1);
- if ((firstDash > 0) & (secondDash > 0) & (secondDash < s.length()-1)) {
- year = Integer.parseInt(s.substring(0, firstDash)) - 1900;
- month = Integer.parseInt(s.substring(firstDash+1, secondDash)) - 1;
- day = Integer.parseInt(s.substring(secondDash+1));
- } else {
+ if (s == null) {
throw new java.lang.IllegalArgumentException();
}
- return new Date(year, month, day);
+ firstDash = s.indexOf('-');
+ secondDash = s.indexOf('-', firstDash + 1);
+
+ if ((firstDash > 0) && (secondDash > 0) && (secondDash < s.length() - 1)) {
+ String yyyy = s.substring(0, firstDash);
+ String mm = s.substring(firstDash + 1, secondDash);
+ String dd = s.substring(secondDash + 1);
+ if (yyyy.length() == YEAR_LENGTH && mm.length() == MONTH_LENGTH &&
+ dd.length() == DAY_LENGTH) {
+ int year = Integer.parseInt(yyyy);
+ int month = Integer.parseInt(mm);
+ int day = Integer.parseInt(dd);
+
+ if ((month >= 1 && month <= MAX_MONTH) && (day >= 1 && day <= MAX_DAY)) {
+ d = new Date(year - 1900, month - 1, day);
+ }
+ }
+ }
+ if (d == null) {
+ throw new java.lang.IllegalArgumentException();
+ }
+
+ return d;
+
}
+
/**
* Formats a date in the date escape format yyyy-mm-dd.
* <P>
--- a/jdk/src/share/classes/javax/swing/JTable.java Wed Sep 08 14:04:18 2010 -0700
+++ b/jdk/src/share/classes/javax/swing/JTable.java Wed Jul 05 17:21:22 2017 +0200
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997, 2008, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2010, 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
@@ -946,7 +946,6 @@
/**
* Returns the height of a table row, in pixels.
- * The default row height is 16.0.
*
* @return the height in pixels of a table row
* @see #setRowHeight
--- a/jdk/src/share/classes/sun/java2d/pisces/Dasher.java Wed Sep 08 14:04:18 2010 -0700
+++ b/jdk/src/share/classes/sun/java2d/pisces/Dasher.java Wed Jul 05 17:21:22 2017 +0200
@@ -36,117 +36,71 @@
* semantics are unclear.
*
*/
-public class Dasher extends LineSink {
+public class Dasher implements LineSink {
+ private final LineSink output;
+ private final float[] dash;
+ private final float startPhase;
+ private final boolean startDashOn;
+ private final int startIdx;
- LineSink output;
- int[] dash;
- int startPhase;
- boolean startDashOn;
- int startIdx;
-
- int idx;
- boolean dashOn;
- int phase;
-
- int sx, sy;
- int x0, y0;
+ private final float m00, m10, m01, m11;
+ private final float det;
- int m00, m01;
- int m10, m11;
-
- Transform4 transform;
-
- boolean symmetric;
- long ldet;
+ private boolean firstDashOn;
+ private boolean starting;
- boolean firstDashOn;
- boolean starting;
- int sx1, sy1;
+ private int idx;
+ private boolean dashOn;
+ private float phase;
- /**
- * Empty constructor. <code>setOutput</code> and
- * <code>setParameters</code> must be called prior to calling any
- * other methods.
- */
- public Dasher() {}
+ private float sx, sy;
+ private float x0, y0;
+ private float sx1, sy1;
+
/**
* Constructs a <code>Dasher</code>.
*
* @param output an output <code>LineSink</code>.
- * @param dash an array of <code>int</code>s containing the dash
- * pattern in S15.16 format.
- * @param phase an <code>int</code> containing the dash phase in
- * S15.16 format.
+ * @param dash an array of <code>int</code>s containing the dash pattern
+ * @param phase an <code>int</code> containing the dash phase
* @param transform a <code>Transform4</code> object indicating
* the transform that has been previously applied to all incoming
* coordinates. This is required in order to compute dash lengths
* properly.
*/
public Dasher(LineSink output,
- int[] dash, int phase,
- Transform4 transform) {
- setOutput(output);
- setParameters(dash, phase, transform);
- }
-
- /**
- * Sets the output <code>LineSink</code> of this
- * <code>Dasher</code>.
- *
- * @param output an output <code>LineSink</code>.
- */
- public void setOutput(LineSink output) {
- this.output = output;
- }
-
- /**
- * Sets the parameters of this <code>Dasher</code>.
- *
- * @param dash an array of <code>int</code>s containing the dash
- * pattern in S15.16 format.
- * @param phase an <code>int</code> containing the dash phase in
- * S15.16 format.
- * @param transform a <code>Transform4</code> object indicating
- * the transform that has been previously applied to all incoming
- * coordinates. This is required in order to compute dash lengths
- * properly.
- */
- public void setParameters(int[] dash, int phase,
- Transform4 transform) {
+ float[] dash, float phase,
+ float a00, float a01, float a10, float a11) {
if (phase < 0) {
throw new IllegalArgumentException("phase < 0 !");
}
+ this.output = output;
+
// Normalize so 0 <= phase < dash[0]
int idx = 0;
dashOn = true;
- int d;
+ float d;
while (phase >= (d = dash[idx])) {
phase -= d;
idx = (idx + 1) % dash.length;
dashOn = !dashOn;
}
- this.dash = new int[dash.length];
- for (int i = 0; i < dash.length; i++) {
- this.dash[i] = dash[i];
- }
+ this.dash = dash;
this.startPhase = this.phase = phase;
this.startDashOn = dashOn;
this.startIdx = idx;
- this.transform = transform;
-
- this.m00 = transform.m00;
- this.m01 = transform.m01;
- this.m10 = transform.m10;
- this.m11 = transform.m11;
- this.ldet = ((long)m00*m11 - (long)m01*m10) >> 16;
- this.symmetric = (m00 == m11 && m10 == -m01);
+ m00 = a00;
+ m01 = a01;
+ m10 = a10;
+ m11 = a11;
+ det = m00 * m11 - m01 * m10;
}
- public void moveTo(int x0, int y0) {
+ public void moveTo(float x0, float y0) {
output.moveTo(x0, y0);
this.idx = startIdx;
this.dashOn = this.startDashOn;
@@ -160,7 +114,7 @@
output.lineJoin();
}
- private void goTo(int x1, int y1) {
+ private void goTo(float x1, float y1) {
if (dashOn) {
if (starting) {
this.sx1 = x1;
@@ -180,52 +134,64 @@
this.y0 = y1;
}
- public void lineTo(int x1, int y1) {
- while (true) {
- int d = dash[idx] - phase;
- int lx = x1 - x0;
- int ly = y1 - y0;
+ public void lineTo(float x1, float y1) {
+ // The widened line is squished to a 0 width one, so no drawing is done
+ if (det == 0) {
+ goTo(x1, y1);
+ return;
+ }
+ float dx = x1 - x0;
+ float dy = y1 - y0;
- // Compute segment length in the untransformed
- // coordinate system
- // IMPL NOTE - use fixed point
+
+ // Compute segment length in the untransformed
+ // coordinate system
- int l;
- if (symmetric) {
- l = (int)((PiscesMath.hypot(lx, ly)*65536L)/ldet);
- } else{
- long la = ((long)ly*m00 - (long)lx*m10)/ldet;
- long lb = ((long)ly*m01 - (long)lx*m11)/ldet;
- l = (int)PiscesMath.hypot(la, lb);
- }
+ float la = (dy*m00 - dx*m10)/det;
+ float lb = (dy*m01 - dx*m11)/det;
+ float origLen = (float) Math.hypot(la, lb);
- if (l < d) {
+ if (origLen == 0) {
+ // Let the output LineSink deal with cases where dx, dy are 0.
+ goTo(x1, y1);
+ return;
+ }
+
+ // The scaling factors needed to get the dx and dy of the
+ // transformed dash segments.
+ float cx = dx / origLen;
+ float cy = dy / origLen;
+
+ while (true) {
+ float leftInThisDashSegment = dash[idx] - phase;
+ if (origLen < leftInThisDashSegment) {
goTo(x1, y1);
// Advance phase within current dash segment
- phase += l;
+ phase += origLen;
+ return;
+ } else if (origLen == leftInThisDashSegment) {
+ goTo(x1, y1);
+ phase = 0f;
+ idx = (idx + 1) % dash.length;
+ dashOn = !dashOn;
return;
}
- long t;
- int xsplit, ysplit;
-// // For zero length dashses, SE appears to move 1/8 unit
-// // in device space
-// if (d == 0) {
-// double dlx = lx/65536.0;
-// double dly = ly/65536.0;
-// len = PiscesMath.hypot(dlx, dly);
-// double dt = 1.0/(8*len);
-// double dxsplit = (x0/65536.0) + dt*dlx;
-// double dysplit = (y0/65536.0) + dt*dly;
-// xsplit = (int)(dxsplit*65536.0);
-// ysplit = (int)(dysplit*65536.0);
-// } else {
- t = ((long)d << 16)/l;
- xsplit = x0 + (int)(t*(x1 - x0) >> 16);
- ysplit = y0 + (int)(t*(y1 - y0) >> 16);
-// }
- goTo(xsplit, ysplit);
+ float dashx, dashy;
+ float dashdx = dash[idx] * cx;
+ float dashdy = dash[idx] * cy;
+ if (phase == 0) {
+ dashx = x0 + dashdx;
+ dashy = y0 + dashdy;
+ } else {
+ float p = (leftInThisDashSegment) / dash[idx];
+ dashx = x0 + p * dashdx;
+ dashy = y0 + p * dashdy;
+ }
+ goTo(dashx, dashy);
+
+ origLen -= (dash[idx] - phase);
// Advance to next dash segment
idx = (idx + 1) % dash.length;
dashOn = !dashOn;
@@ -233,6 +199,7 @@
}
}
+
public void close() {
lineTo(sx, sy);
if (firstDashOn) {
--- a/jdk/src/share/classes/sun/java2d/pisces/LineSink.java Wed Sep 08 14:04:18 2010 -0700
+++ b/jdk/src/share/classes/sun/java2d/pisces/LineSink.java Wed Jul 05 17:21:22 2017 +0200
@@ -39,16 +39,16 @@
* <code>LineSink</code> interface.
*
*/
-public abstract class LineSink {
+public interface LineSink {
/**
* Moves the current drawing position to the point <code>(x0,
* y0)</code>.
*
- * @param x0 the X coordinate in S15.16 format
- * @param y0 the Y coordinate in S15.16 format
+ * @param x0 the X coordinate
+ * @param y0 the Y coordinate
*/
- public abstract void moveTo(int x0, int y0);
+ public void moveTo(float x0, float y0);
/**
* Provides a hint that the current segment should be joined to
@@ -65,29 +65,29 @@
* <p> Other <code>LineSink</code> classes should simply pass this
* hint to their output sink as needed.
*/
- public abstract void lineJoin();
+ public void lineJoin();
/**
* Draws a line from the current drawing position to the point
* <code>(x1, y1)</code> and sets the current drawing position to
* <code>(x1, y1)</code>.
*
- * @param x1 the X coordinate in S15.16 format
- * @param y1 the Y coordinate in S15.16 format
+ * @param x1 the X coordinate
+ * @param y1 the Y coordinate
*/
- public abstract void lineTo(int x1, int y1);
+ public void lineTo(float x1, float y1);
/**
* Closes the current path by drawing a line from the current
* drawing position to the point specified by the moset recent
* <code>moveTo</code> command.
*/
- public abstract void close();
+ public void close();
/**
* Ends the current path. It may be necessary to end a path in
* order to allow end caps to be drawn.
*/
- public abstract void end();
+ public void end();
}
--- a/jdk/src/share/classes/sun/java2d/pisces/PiscesMath.java Wed Sep 08 14:04:18 2010 -0700
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,155 +0,0 @@
-/*
- * Copyright (c) 2007, 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.
- */
-
-package sun.java2d.pisces;
-
-public class PiscesMath {
-
- private PiscesMath() {}
-
- private static final int SINTAB_LG_ENTRIES = 10;
- private static final int SINTAB_ENTRIES = 1 << SINTAB_LG_ENTRIES;
- private static int[] sintab;
-
- public static final int PI = (int)(Math.PI*65536.0);
- public static final int TWO_PI = (int)(2.0*Math.PI*65536.0);
- public static final int PI_OVER_TWO = (int)((Math.PI/2.0)*65536.0);
- public static final int SQRT_TWO = (int)(Math.sqrt(2.0)*65536.0);
-
- static {
- sintab = new int[SINTAB_ENTRIES + 1];
- for (int i = 0; i < SINTAB_ENTRIES + 1; i++) {
- double theta = i*(Math.PI/2.0)/SINTAB_ENTRIES;
- sintab[i] = (int)(Math.sin(theta)*65536.0);
- }
- }
-
- public static int sin(int theta) {
- int sign = 1;
- if (theta < 0) {
- theta = -theta;
- sign = -1;
- }
- // 0 <= theta
- while (theta >= TWO_PI) {
- theta -= TWO_PI;
- }
- // 0 <= theta < 2*PI
- if (theta >= PI) {
- theta = TWO_PI - theta;
- sign = -sign;
- }
- // 0 <= theta < PI
- if (theta > PI_OVER_TWO) {
- theta = PI - theta;
- }
- // 0 <= theta <= PI/2
- int itheta = (int)((long)theta*SINTAB_ENTRIES/(PI_OVER_TWO));
- return sign*sintab[itheta];
- }
-
- public static int cos(int theta) {
- return sin(PI_OVER_TWO - theta);
- }
-
-// public static double sqrt(double x) {
-// double dsqrt = Math.sqrt(x);
-// int ix = (int)(x*65536.0);
-// Int Isqrt = Isqrt(Ix);
-
-// Long Lx = (Long)(X*65536.0);
-// Long Lsqrt = Lsqrt(Lx);
-
-// System.Out.Println();
-// System.Out.Println("X = " + X);
-// System.Out.Println("Dsqrt = " + Dsqrt);
-
-// System.Out.Println("Ix = " + Ix);
-// System.Out.Println("Isqrt = " + Isqrt/65536.0);
-
-// System.Out.Println("Lx = " + Lx);
-// System.Out.Println("Lsqrt = " + Lsqrt/65536.0);
-
-// Return Dsqrt;
-// }
-
- // From Ken Turkowski, _Fixed-Point Square Root_, In Graphics Gems V
- public static int isqrt(int x) {
- int fracbits = 16;
-
- int root = 0;
- int remHi = 0;
- int remLo = x;
- int count = 15 + fracbits/2;
-
- do {
- remHi = (remHi << 2) | (remLo >>> 30); // N.B. - unsigned shift R
- remLo <<= 2;
- root <<= 1;
- int testdiv = (root << 1) + 1;
- if (remHi >= testdiv) {
- remHi -= testdiv;
- root++;
- }
- } while (count-- != 0);
-
- return root;
- }
-
- public static long lsqrt(long x) {
- int fracbits = 16;
-
- long root = 0;
- long remHi = 0;
- long remLo = x;
- int count = 31 + fracbits/2;
-
- do {
- remHi = (remHi << 2) | (remLo >>> 62); // N.B. - unsigned shift R
- remLo <<= 2;
- root <<= 1;
- long testDiv = (root << 1) + 1;
- if (remHi >= testDiv) {
- remHi -= testDiv;
- root++;
- }
- } while (count-- != 0);
-
- return root;
- }
-
- public static double hypot(double x, double y) {
- // new RuntimeException().printStackTrace();
- return Math.sqrt(x*x + y*y);
- }
-
- public static int hypot(int x, int y) {
- return (int)((lsqrt((long)x*x + (long)y*y) + 128) >> 8);
- }
-
- public static long hypot(long x, long y) {
- return (lsqrt(x*x + y*y) + 128) >> 8;
- }
-}
--- a/jdk/src/share/classes/sun/java2d/pisces/PiscesRenderingEngine.java Wed Sep 08 14:04:18 2010 -0700
+++ b/jdk/src/share/classes/sun/java2d/pisces/PiscesRenderingEngine.java Wed Jul 05 17:21:22 2017 +0200
@@ -27,6 +27,7 @@
import java.awt.Shape;
import java.awt.BasicStroke;
+import java.awt.geom.FlatteningPathIterator;
import java.awt.geom.Path2D;
import java.awt.geom.AffineTransform;
import java.awt.geom.PathIterator;
@@ -37,23 +38,9 @@
import sun.java2d.pipe.AATileGenerator;
public class PiscesRenderingEngine extends RenderingEngine {
- public static Transform4 IdentT4 = new Transform4();
public static double defaultFlat = 0.1;
- static int FloatToS15_16(float flt) {
- flt = flt * 65536f + 0.5f;
- if (flt <= -(65536f * 65536f)) {
- return Integer.MIN_VALUE;
- } else if (flt >= (65536f * 65536f)) {
- return Integer.MAX_VALUE;
- } else {
- return (int) Math.floor(flt);
- }
- }
-
- static float S15_16ToFloat(int fix) {
- return (fix / 65536f);
- }
+ private static enum NormMode {OFF, ON_NO_AA, ON_WITH_AA}
/**
* Create a widened path as specified by the parameters.
@@ -85,18 +72,19 @@
strokeTo(src,
null,
width,
+ NormMode.OFF,
caps,
join,
miterlimit,
dashes,
dashphase,
new LineSink() {
- public void moveTo(int x0, int y0) {
- p2d.moveTo(S15_16ToFloat(x0), S15_16ToFloat(y0));
+ public void moveTo(float x0, float y0) {
+ p2d.moveTo(x0, y0);
}
public void lineJoin() {}
- public void lineTo(int x1, int y1) {
- p2d.lineTo(S15_16ToFloat(x1), S15_16ToFloat(y1));
+ public void lineTo(float x1, float y1) {
+ p2d.lineTo(x1, y1);
}
public void close() {
p2d.closePath();
@@ -142,14 +130,17 @@
boolean antialias,
final PathConsumer2D consumer)
{
- strokeTo(src, at, bs, thin, normalize, antialias,
+ NormMode norm = (normalize) ?
+ ((antialias) ? NormMode.ON_WITH_AA : NormMode.ON_NO_AA)
+ : NormMode.OFF;
+ strokeTo(src, at, bs, thin, norm, antialias,
new LineSink() {
- public void moveTo(int x0, int y0) {
- consumer.moveTo(S15_16ToFloat(x0), S15_16ToFloat(y0));
+ public void moveTo(float x0, float y0) {
+ consumer.moveTo(x0, y0);
}
public void lineJoin() {}
- public void lineTo(int x1, int y1) {
- consumer.lineTo(S15_16ToFloat(x1), S15_16ToFloat(y1));
+ public void lineTo(float x1, float y1) {
+ consumer.lineTo(x1, y1);
}
public void close() {
consumer.closePath();
@@ -164,7 +155,7 @@
AffineTransform at,
BasicStroke bs,
boolean thin,
- boolean normalize,
+ NormMode normalize,
boolean antialias,
LineSink lsink)
{
@@ -181,6 +172,7 @@
strokeTo(src,
at,
lw,
+ normalize,
bs.getEndCap(),
bs.getLineJoin(),
bs.getMiterLimit(),
@@ -258,6 +250,7 @@
void strokeTo(Shape src,
AffineTransform at,
float width,
+ NormMode normalize,
int caps,
int join,
float miterlimit,
@@ -265,36 +258,139 @@
float dashphase,
LineSink lsink)
{
- Transform4 t4;
-
- if (at == null || at.isIdentity()) {
- t4 = IdentT4;
+ float a00 = 1f, a01 = 0f, a10 = 0f, a11 = 1f;
+ if (at != null && !at.isIdentity()) {
+ a00 = (float)at.getScaleX();
+ a01 = (float)at.getShearX();
+ a10 = (float)at.getShearY();
+ a11 = (float)at.getScaleY();
+ }
+ lsink = new Stroker(lsink, width, caps, join, miterlimit, a00, a01, a10, a11);
+ if (dashes != null) {
+ lsink = new Dasher(lsink, dashes, dashphase, a00, a01, a10, a11);
+ }
+ PathIterator pi;
+ if (normalize != NormMode.OFF) {
+ pi = new FlatteningPathIterator(
+ new NormalizingPathIterator(src.getPathIterator(at), normalize),
+ defaultFlat);
} else {
- t4 = new Transform4(FloatToS15_16((float) at.getScaleX()),
- FloatToS15_16((float) at.getShearX()),
- FloatToS15_16((float) at.getShearY()),
- FloatToS15_16((float) at.getScaleY()));
+ pi = src.getPathIterator(at, defaultFlat);
+ }
+ pathTo(pi, lsink);
+ }
+
+ private static class NormalizingPathIterator implements PathIterator {
+
+ private final PathIterator src;
+
+ // the adjustment applied to the current position.
+ private float curx_adjust, cury_adjust;
+ // the adjustment applied to the last moveTo position.
+ private float movx_adjust, movy_adjust;
+
+ // constants used in normalization computations
+ private final float lval, rval;
+
+ NormalizingPathIterator(PathIterator src, NormMode mode) {
+ this.src = src;
+ switch (mode) {
+ case ON_NO_AA:
+ // round to nearest (0.25, 0.25) pixel
+ lval = rval = 0.25f;
+ break;
+ case ON_WITH_AA:
+ // round to nearest pixel center
+ lval = 0f;
+ rval = 0.5f;
+ break;
+ case OFF:
+ throw new InternalError("A NormalizingPathIterator should " +
+ "not be created if no normalization is being done");
+ default:
+ throw new InternalError("Unrecognized normalization mode");
+ }
}
- lsink = new Stroker(lsink,
- FloatToS15_16(width),
- caps,
- join,
- FloatToS15_16(miterlimit),
- t4);
- if (dashes != null) {
- int fdashes[] = new int[dashes.length];
- for (int i = 0; i < dashes.length; i++) {
- fdashes[i] = FloatToS15_16(dashes[i]);
+ public int currentSegment(float[] coords) {
+ int type = src.currentSegment(coords);
+
+ int lastCoord;
+ switch(type) {
+ case PathIterator.SEG_CUBICTO:
+ lastCoord = 4;
+ break;
+ case PathIterator.SEG_QUADTO:
+ lastCoord = 2;
+ break;
+ case PathIterator.SEG_LINETO:
+ case PathIterator.SEG_MOVETO:
+ lastCoord = 0;
+ break;
+ case PathIterator.SEG_CLOSE:
+ // we don't want to deal with this case later. We just exit now
+ curx_adjust = movx_adjust;
+ cury_adjust = movy_adjust;
+ return type;
+ default:
+ throw new InternalError("Unrecognized curve type");
}
- lsink = new Dasher(lsink,
- fdashes,
- FloatToS15_16(dashphase),
- t4);
+
+ // normalize endpoint
+ float x_adjust = (float)Math.floor(coords[lastCoord] + lval) + rval -
+ coords[lastCoord];
+ float y_adjust = (float)Math.floor(coords[lastCoord+1] + lval) + rval -
+ coords[lastCoord + 1];
+
+ coords[lastCoord ] += x_adjust;
+ coords[lastCoord + 1] += y_adjust;
+
+ // now that the end points are done, normalize the control points
+ switch(type) {
+ case PathIterator.SEG_CUBICTO:
+ coords[0] += curx_adjust;
+ coords[1] += cury_adjust;
+ coords[2] += x_adjust;
+ coords[3] += y_adjust;
+ break;
+ case PathIterator.SEG_QUADTO:
+ coords[0] += (curx_adjust + x_adjust) / 2;
+ coords[1] += (cury_adjust + y_adjust) / 2;
+ break;
+ case PathIterator.SEG_LINETO:
+ break;
+ case PathIterator.SEG_MOVETO:
+ movx_adjust = x_adjust;
+ movy_adjust = y_adjust;
+ break;
+ case PathIterator.SEG_CLOSE:
+ throw new InternalError("This should be handled earlier.");
+ }
+ curx_adjust = x_adjust;
+ cury_adjust = y_adjust;
+ return type;
}
- PathIterator pi = src.getPathIterator(at, defaultFlat);
- pathTo(pi, lsink);
+ public int currentSegment(double[] coords) {
+ float[] tmp = new float[6];
+ int type = this.currentSegment(tmp);
+ for (int i = 0; i < 6; i++) {
+ coords[i] = (float) tmp[i];
+ }
+ return type;
+ }
+
+ public int getWindingRule() {
+ return src.getWindingRule();
+ }
+
+ public boolean isDone() {
+ return src.isDone();
+ }
+
+ public void next() {
+ src.next();
+ }
}
void pathTo(PathIterator pi, LineSink lsink) {
@@ -302,13 +398,11 @@
while (!pi.isDone()) {
switch (pi.currentSegment(coords)) {
case PathIterator.SEG_MOVETO:
- lsink.moveTo(FloatToS15_16(coords[0]),
- FloatToS15_16(coords[1]));
+ lsink.moveTo(coords[0], coords[1]);
break;
case PathIterator.SEG_LINETO:
lsink.lineJoin();
- lsink.lineTo(FloatToS15_16(coords[0]),
- FloatToS15_16(coords[1]));
+ lsink.lineTo(coords[0], coords[1]);
break;
case PathIterator.SEG_CLOSE:
lsink.lineJoin();
@@ -378,18 +472,28 @@
int bbox[])
{
PiscesCache pc = PiscesCache.createInstance();
- Renderer r = new Renderer();
- r.setCache(pc);
- r.setAntialiasing(3, 3);
- r.beginRendering(clip.getLoX(), clip.getLoY(),
- clip.getWidth(), clip.getHeight());
+ Renderer r;
+ NormMode norm = (normalize) ? NormMode.ON_WITH_AA : NormMode.OFF;
if (bs == null) {
- PathIterator pi = s.getPathIterator(at, defaultFlat);
- r.setWindingRule(pi.getWindingRule());
+ PathIterator pi;
+ if (normalize) {
+ pi = new FlatteningPathIterator(
+ new NormalizingPathIterator(s.getPathIterator(at), norm),
+ defaultFlat);
+ } else {
+ pi = s.getPathIterator(at, defaultFlat);
+ }
+ r = new Renderer(3, 3,
+ clip.getLoX(), clip.getLoY(),
+ clip.getWidth(), clip.getHeight(),
+ pi.getWindingRule(), pc);
pathTo(pi, r);
} else {
- r.setWindingRule(PathIterator.WIND_NON_ZERO);
- strokeTo(s, at, bs, thin, normalize, true, r);
+ r = new Renderer(3, 3,
+ clip.getLoX(), clip.getLoY(),
+ clip.getWidth(), clip.getHeight(),
+ PathIterator.WIND_NON_ZERO, pc);
+ strokeTo(s, at, bs, thin, norm, true, r);
}
r.endRendering();
PiscesTileGenerator ptg = new PiscesTileGenerator(pc, r.MAX_AA_ALPHA);
@@ -420,3 +524,4 @@
}
}
}
+
--- a/jdk/src/share/classes/sun/java2d/pisces/Renderer.java Wed Sep 08 14:04:18 2010 -0700
+++ b/jdk/src/share/classes/sun/java2d/pisces/Renderer.java Wed Jul 05 17:21:22 2017 +0200
@@ -25,446 +25,440 @@
package sun.java2d.pisces;
-public class Renderer extends LineSink {
+import java.util.Arrays;
+
+public class Renderer implements LineSink {
+
+///////////////////////////////////////////////////////////////////////////////
+// Scan line iterator and edge crossing data.
+//////////////////////////////////////////////////////////////////////////////
+
+ private int[] crossings;
+
+ // This is an array of indices into the edge array. It is initialized to
+ // [i * SIZEOF_STRUCT_EDGE for i in range(0, edgesSize/SIZEOF_STRUCT_EDGE)]
+ // (where range(i, j) is i,i+1,...,j-1 -- just like in python).
+ // The reason for keeping this is because we need the edges array sorted
+ // by y0, but we don't want to move all that data around, so instead we
+ // sort the indices into the edge array, and use edgeIndices to access
+ // the edges array. This is meant to simulate a pointer array (hence the name)
+ private int[] edgePtrs;
+
+ // crossing bounds. The bounds are not necessarily tight (the scan line
+ // at minY, for example, might have no crossings). The x bounds will
+ // be accumulated as crossings are computed.
+ private int minY, maxY;
+ private int minX, maxX;
+ private int nextY;
+
+ // indices into the edge pointer list. They indicate the "active" sublist in
+ // the edge list (the portion of the list that contains all the edges that
+ // cross the next scan line).
+ private int lo, hi;
+
+ private static final int INIT_CROSSINGS_SIZE = 50;
+ private void ScanLineItInitialize() {
+ crossings = new int[INIT_CROSSINGS_SIZE];
+ edgePtrs = new int[edgesSize / SIZEOF_STRUCT_EDGE];
+ for (int i = 0; i < edgePtrs.length; i++) {
+ edgePtrs[i] = i * SIZEOF_STRUCT_EDGE;
+ }
+
+ qsort(0, edgePtrs.length - 1);
+
+ // We don't care if we clip some of the line off with ceil, since
+ // no scan line crossings will be eliminated (in fact, the ceil is
+ // the y of the first scan line crossing).
+ nextY = minY = Math.max(boundsMinY, (int)Math.ceil(edgeMinY));
+ maxY = Math.min(boundsMaxY, (int)Math.ceil(edgeMaxY));
+
+ for (lo = 0; lo < edgePtrs.length && edges[edgePtrs[lo]+Y1] <= nextY; lo++)
+ ;
+ for (hi = lo; hi < edgePtrs.length && edges[edgePtrs[hi]+CURY] <= nextY; hi++)
+ ; // the active list is *edgePtrs[lo] (inclusive) *edgePtrs[hi] (exclusive)
+ for (int i = lo; i < hi; i++) {
+ setCurY(edgePtrs[i], nextY);
+ }
+
+ // We accumulate X in the iterator because accumulating it in addEdge
+ // like we do with Y does not do much good: if there's an edge
+ // (0,0)->(1000,10000), and if y gets clipped to 1000, then the x
+ // bound should be 100, but the accumulator from addEdge would say 1000,
+ // so we'd still have to accumulate the X bounds as we add crossings.
+ minX = boundsMinX;
+ maxX = boundsMaxX;
+ }
+
+ private int ScanLineItCurrentY() {
+ return nextY - 1;
+ }
+
+ private int ScanLineItGoToNextYAndComputeCrossings() {
+ // we go through the active list and remove the ones that don't cross
+ // the nextY scanline.
+ int crossingIdx = 0;
+ for (int i = lo; i < hi; i++) {
+ if (edges[edgePtrs[i]+Y1] <= nextY) {
+ edgePtrs[i] = edgePtrs[lo++];
+ }
+ }
+ if (hi - lo > crossings.length) {
+ int newSize = Math.max(hi - lo, crossings.length * 2);
+ crossings = Arrays.copyOf(crossings, newSize);
+ }
+ // Now every edge between lo and hi crosses nextY. Compute it's
+ // crossing and put it in the crossings array.
+ for (int i = lo; i < hi; i++) {
+ addCrossing(nextY, getCurCrossing(edgePtrs[i]), (int)edges[edgePtrs[i]+OR], crossingIdx);
+ gotoNextY(edgePtrs[i]);
+ crossingIdx++;
+ }
+
+ nextY++;
+ // Expand active list to include new edges.
+ for (; hi < edgePtrs.length && edges[edgePtrs[hi]+CURY] <= nextY; hi++) {
+ setCurY(edgePtrs[hi], nextY);
+ }
+
+ Arrays.sort(crossings, 0, crossingIdx);
+ return crossingIdx;
+ }
+
+ private boolean ScanLineItHasNext() {
+ return nextY < maxY;
+ }
+
+ private void addCrossing(int y, int x, int or, int idx) {
+ if (x < minX) {
+ minX = x;
+ }
+ if (x > maxX) {
+ maxX = x;
+ }
+ x <<= 1;
+ crossings[idx] = ((or == 1) ? (x | 0x1) : x);
+ }
+
+
+ // quicksort implementation for sorting the edge indices ("pointers")
+ // by increasing y0. first, last are indices into the "pointer" array
+ // It sorts the pointer array from first (inclusive) to last (inclusive)
+ private void qsort(int first, int last) {
+ if (last > first) {
+ int p = partition(first, last);
+ if (first < p - 1) {
+ qsort(first, p - 1);
+ }
+ if (p < last) {
+ qsort(p, last);
+ }
+ }
+ }
+
+ // i, j are indices into edgePtrs.
+ private int partition(int i, int j) {
+ int pivotVal = edgePtrs[i];
+ while (i <= j) {
+ // edges[edgePtrs[i]+1] is equivalent to (*(edgePtrs[i])).y0 in C
+ while (edges[edgePtrs[i]+CURY] < edges[pivotVal+CURY]) { i++; }
+ while (edges[edgePtrs[j]+CURY] > edges[pivotVal+CURY]) { j--; }
+ if (i <= j) {
+ int tmp = edgePtrs[i];
+ edgePtrs[i] = edgePtrs[j];
+ edgePtrs[j] = tmp;
+ i++;
+ j--;
+ }
+ }
+ return i;
+ }
+
+//============================================================================
+
+
+//////////////////////////////////////////////////////////////////////////////
+// EDGE LIST
+//////////////////////////////////////////////////////////////////////////////
+
+ private static final int INIT_NUM_EDGES = 1000;
+ private static final int SIZEOF_STRUCT_EDGE = 5;
+
+ // The following array is a poor man's struct array:
+ // it simulates a struct array by having
+ // edges[SIZEOF_STRUCT_EDGE * i + j] be the jth field in the ith element
+ // of an array of edge structs.
+ private float[] edges;
+ private int edgesSize; // size of the edge list.
+ private static final int Y1 = 0;
+ private static final int SLOPE = 1;
+ private static final int OR = 2; // the orientation. This can be -1 or 1.
+ // -1 means up, 1 means down.
+ private static final int CURY = 3; // j = 5 corresponds to the "current Y".
+ // Each edge keeps track of the last scanline
+ // crossing it computed, and this is the y coord of
+ // that scanline.
+ private static final int CURX = 4; //the x coord of the current crossing.
+
+ // Note that while the array is declared as a float[] not all of it's
+ // elements should be floats. currentY and Orientation should be ints (or int and
+ // byte respectively), but they all need to be the same type. This isn't
+ // really a problem because floats can represent exactly all 23 bit integers,
+ // which should be more than enough.
+ // Note, also, that we only need x1 for slope computation, so we don't need
+ // to store it. x0, y0 don't need to be stored either. They can be put into
+ // curx, cury, and it's ok if they're lost when curx and cury are changed.
+ // We take this undeniably ugly and error prone approach (instead of simply
+ // making an Edge class) for performance reasons. Also, it would probably be nicer
+ // to have one array for each field, but that would defeat the purpose because
+ // it would make poor use of the processor cache, since we tend to access
+ // all the fields for one edge at a time.
+
+ private float edgeMinY;
+ private float edgeMaxY;
+
+
+ private void addEdge(float x0, float y0, float x1, float y1) {
+ float or = (y0 < y1) ? 1f : -1f; // orientation: 1 = UP; -1 = DOWN
+ if (or == -1) {
+ float tmp = y0;
+ y0 = y1;
+ y1 = tmp;
+ tmp = x0;
+ x0 = x1;
+ x1 = tmp;
+ }
+ // skip edges that don't cross a scanline
+ if (Math.ceil(y0) >= Math.ceil(y1)) {
+ return;
+ }
+
+ int newSize = edgesSize + SIZEOF_STRUCT_EDGE;
+ if (edges.length < newSize) {
+ edges = Arrays.copyOf(edges, newSize * 2);
+ }
+ edges[edgesSize+CURX] = x0;
+ edges[edgesSize+CURY] = y0;
+ edges[edgesSize+Y1] = y1;
+ edges[edgesSize+SLOPE] = (x1 - x0) / (y1 - y0);
+ edges[edgesSize+OR] = or;
+ // the crossing values can't be initialized meaningfully yet. This
+ // will have to wait until setCurY is called
+ edgesSize += SIZEOF_STRUCT_EDGE;
+
+ // Accumulate edgeMinY and edgeMaxY
+ if (y0 < edgeMinY) { edgeMinY = y0; }
+ if (y1 > edgeMaxY) { edgeMaxY = y1; }
+ }
+
+ // As far as the following methods care, this edges extends to infinity.
+ // They can compute the x intersect of any horizontal line.
+ // precondition: idx is the index to the start of the desired edge.
+ // So, if the ith edge is wanted, idx should be SIZEOF_STRUCT_EDGE * i
+ private void setCurY(int idx, int y) {
+ // compute the x crossing of edge at idx and horizontal line y
+ // currentXCrossing = (y - y0)*slope + x0
+ edges[idx + CURX] = (y - edges[idx + CURY]) * edges[idx + SLOPE] + edges[idx+CURX];
+ edges[idx + CURY] = (float)y;
+ }
+
+ private void gotoNextY(int idx) {
+ edges[idx + CURY] += 1f; // i.e. curY += 1
+ edges[idx + CURX] += edges[idx + SLOPE]; // i.e. curXCrossing += slope
+ }
+
+ private int getCurCrossing(int idx) {
+ return (int)edges[idx + CURX];
+ }
+//====================================================================================
+
public static final int WIND_EVEN_ODD = 0;
public static final int WIND_NON_ZERO = 1;
- // Initial edge list size
- // IMPL_NOTE - restore size after growth
- public static final int INITIAL_EDGES = 1000;
-
- // Recommended maximum scratchpad sizes. The arrays will grow
- // larger if needed, but when finished() is called they will be released
- // if they have grown larger than these sizes.
- public static final int DEFAULT_INDICES_SIZE = 8192;
- public static final int DEFAULT_CROSSINGS_SIZE = 32*1024;
-
// Antialiasing
- private int SUBPIXEL_LG_POSITIONS_X;
- private int SUBPIXEL_LG_POSITIONS_Y;
- private int SUBPIXEL_MASK_X;
- private int SUBPIXEL_MASK_Y;
- private int SUBPIXEL_POSITIONS_X;
- private int SUBPIXEL_POSITIONS_Y;
- int MAX_AA_ALPHA;
- private int MAX_AA_ALPHA_DENOM;
- private int HALF_MAX_AA_ALPHA_DENOM;
- private int XSHIFT;
- private int YSHIFT;
- private int YSTEP;
- private int HYSTEP;
- private int YMASK;
-
- private static final int MIN_QUAD_OPT_WIDTH = 100 << 16;
+ final private int SUBPIXEL_LG_POSITIONS_X;
+ final private int SUBPIXEL_LG_POSITIONS_Y;
+ final private int SUBPIXEL_POSITIONS_X;
+ final private int SUBPIXEL_POSITIONS_Y;
+ final private int SUBPIXEL_MASK_X;
+ final private int SUBPIXEL_MASK_Y;
+ final int MAX_AA_ALPHA;
// Cache to store RLE-encoded coverage mask of the current primitive
- PiscesCache cache;
+ final PiscesCache cache;
- // Bounds of the drawing region, at S15.16 precsion
- private int boundsMinX, boundsMinY, boundsMaxX, boundsMaxY;
-
- // Bounds of the current primitive, at subsample precision
- private int rasterMinX, rasterMaxX, rasterMinY, rasterMaxY;
+ // Bounds of the drawing region, at subpixel precision.
+ final private int boundsMinX, boundsMinY, boundsMaxX, boundsMaxY;
// Pixel bounding box for current primitive
- private int bboxX0, bboxY0, bboxX1, bboxY1;
+ private int pix_bboxX0, pix_bboxY0, pix_bboxX1, pix_bboxY1;
// Current winding rule
- private int windingRule;
+ final private int windingRule;
// Current drawing position, i.e., final point of last segment
- private int x0, y0;
+ private float x0, y0;
// Position of most recent 'moveTo' command
- private int sx0, sy0;
-
- // Buffer to be filled with one row's worth of alpha values
- private byte[] rowAA; // needs to be short if 16x16 subsampling
+ private float pix_sx0, pix_sy0;
- // Track the number of vertical extrema of the incoming edge list
- // in order to determine the maximum number of crossings of a
- // scanline
- private int firstOrientation;
- private int lastOrientation;
- private int flips;
-
- // Parameters for emitRow
- private int alphaWidth;
-
- public Renderer() {
- }
-
- public void setAntialiasing(int subpixelLgPositionsX,
- int subpixelLgPositionsY) {
+ public Renderer(int subpixelLgPositionsX, int subpixelLgPositionsY,
+ int pix_boundsX, int pix_boundsY,
+ int pix_boundsWidth, int pix_boundsHeight,
+ int windingRule,
+ PiscesCache cache) {
this.SUBPIXEL_LG_POSITIONS_X = subpixelLgPositionsX;
this.SUBPIXEL_LG_POSITIONS_Y = subpixelLgPositionsY;
+ this.SUBPIXEL_MASK_X = (1 << (SUBPIXEL_LG_POSITIONS_X)) - 1;
+ this.SUBPIXEL_MASK_Y = (1 << (SUBPIXEL_LG_POSITIONS_Y)) - 1;
+ this.SUBPIXEL_POSITIONS_X = 1 << (SUBPIXEL_LG_POSITIONS_X);
+ this.SUBPIXEL_POSITIONS_Y = 1 << (SUBPIXEL_LG_POSITIONS_Y);
+ this.MAX_AA_ALPHA = (SUBPIXEL_POSITIONS_X * SUBPIXEL_POSITIONS_Y);
- this.SUBPIXEL_MASK_X =
- (1 << (SUBPIXEL_LG_POSITIONS_X)) - 1;
- this.SUBPIXEL_MASK_Y =
- (1 << (SUBPIXEL_LG_POSITIONS_Y)) - 1;
- this.SUBPIXEL_POSITIONS_X =
- 1 << (SUBPIXEL_LG_POSITIONS_X);
- this.SUBPIXEL_POSITIONS_Y =
- 1 << (SUBPIXEL_LG_POSITIONS_Y);
- this.MAX_AA_ALPHA =
- (SUBPIXEL_POSITIONS_X*SUBPIXEL_POSITIONS_Y);
- this.MAX_AA_ALPHA_DENOM = 255*MAX_AA_ALPHA;
- this.HALF_MAX_AA_ALPHA_DENOM = MAX_AA_ALPHA_DENOM/2;
- this.XSHIFT = 16 - SUBPIXEL_LG_POSITIONS_X;
- this.YSHIFT = 16 - SUBPIXEL_LG_POSITIONS_Y;
- this.YSTEP = 1 << YSHIFT;
- this.HYSTEP = 1 << (YSHIFT - 1);
- this.YMASK = ~(YSTEP - 1);
- }
+ this.edges = new float[SIZEOF_STRUCT_EDGE * INIT_NUM_EDGES];
+ edgeMinY = Float.POSITIVE_INFINITY;
+ edgeMaxY = Float.NEGATIVE_INFINITY;
+ edgesSize = 0;
+
+ this.windingRule = windingRule;
+ this.cache = cache;
- public int getSubpixelLgPositionsX() {
- return SUBPIXEL_LG_POSITIONS_X;
- }
+ this.boundsMinX = pix_boundsX * SUBPIXEL_POSITIONS_X;
+ this.boundsMinY = pix_boundsY * SUBPIXEL_POSITIONS_Y;
+ this.boundsMaxX = (pix_boundsX + pix_boundsWidth) * SUBPIXEL_POSITIONS_X;
+ this.boundsMaxY = (pix_boundsY + pix_boundsHeight) * SUBPIXEL_POSITIONS_Y;
- public int getSubpixelLgPositionsY() {
- return SUBPIXEL_LG_POSITIONS_Y;
- }
-
- public void setWindingRule(int windingRule) {
- this.windingRule = windingRule;
- }
-
- public int getWindingRule() {
- return windingRule;
+ this.pix_bboxX0 = pix_boundsX;
+ this.pix_bboxY0 = pix_boundsY;
+ this.pix_bboxX1 = pix_boundsX + pix_boundsWidth;
+ this.pix_bboxY1 = pix_boundsY + pix_boundsHeight;
}
- public void beginRendering(int boundsX, int boundsY,
- int boundsWidth, int boundsHeight) {
- lastOrientation = 0;
- flips = 0;
-
- resetEdges();
-
- this.boundsMinX = boundsX << 16;
- this.boundsMinY = boundsY << 16;
- this.boundsMaxX = (boundsX + boundsWidth) << 16;
- this.boundsMaxY = (boundsY + boundsHeight) << 16;
-
- this.bboxX0 = boundsX;
- this.bboxY0 = boundsY;
- this.bboxX1 = boundsX + boundsWidth;
- this.bboxY1 = boundsY + boundsHeight;
+ private float tosubpixx(float pix_x) {
+ return pix_x * SUBPIXEL_POSITIONS_X;
+ }
+ private float tosubpixy(float pix_y) {
+ return pix_y * SUBPIXEL_POSITIONS_Y;
}
- public void moveTo(int x0, int y0) {
- // System.out.println("Renderer: moveTo " + x0/65536.0 + " " + y0/65536.0);
+ public void moveTo(float pix_x0, float pix_y0) {
close();
- this.sx0 = this.x0 = x0;
- this.sy0 = this.y0 = y0;
- this.lastOrientation = 0;
+ this.pix_sx0 = pix_x0;
+ this.pix_sy0 = pix_y0;
+ this.y0 = tosubpixy(pix_y0);
+ this.x0 = tosubpixx(pix_x0);
}
- public void lineJoin() {
- // System.out.println("Renderer: lineJoin");
- // do nothing
- }
+ public void lineJoin() { /* do nothing */ }
- public void lineTo(int x1, int y1) {
- // System.out.println("Renderer: lineTo " + x1/65536.0 + " " + y1/65536.0);
+ public void lineTo(float pix_x1, float pix_y1) {
+ float x1 = tosubpixx(pix_x1);
+ float y1 = tosubpixy(pix_y1);
// Ignore horizontal lines
- // Next line will count flip
if (y0 == y1) {
this.x0 = x1;
return;
}
- int orientation = (y0 < y1) ? 1 : -1;
- if (lastOrientation == 0) {
- firstOrientation = orientation;
- } else if (orientation != lastOrientation) {
- ++flips;
- }
- lastOrientation = orientation;
-
- // Bias Y by 1 ULP so endpoints never lie on a scanline
- addEdge(x0, y0 | 0x1, x1, y1 | 0x1);
+ addEdge(x0, y0, x1, y1);
this.x0 = x1;
this.y0 = y1;
}
public void close() {
- // System.out.println("Renderer: close");
-
- int orientation = lastOrientation;
- if (y0 != sy0) {
- orientation = (y0 < sy0) ? 1 : -1;
- }
- if (orientation != firstOrientation) {
- ++flips;
- }
- lineTo(sx0, sy0);
+ // lineTo expects its input in pixel coordinates.
+ lineTo(pix_sx0, pix_sy0);
}
public void end() {
close();
- // System.out.println("Renderer: end");
- // do nothing
- }
-
- // Scan convert a single edge
- private void computeCrossingsForEdge(int index,
- int boundsMinY, int boundsMaxY) {
- int iy0 = edges[index + 1];
- int iy1 = edges[index + 3];
-
- // Clip to valid Y range
- int clipy0 = (iy0 > boundsMinY) ? iy0 : boundsMinY;
- int clipy1 = (iy1 < boundsMaxY) ? iy1 : boundsMaxY;
-
- int minY = ((clipy0 + HYSTEP) & YMASK) + HYSTEP;
- int maxY = ((clipy1 - HYSTEP) & YMASK) + HYSTEP;
-
- // IMPL_NOTE - If line falls outside the valid X range, could
- // draw a vertical line instead
-
- // Exit if no scanlines are crossed
- if (minY > maxY) {
- return;
- }
-
- // Scan convert line using a DDA approach
-
- int ix0 = edges[index];
- int ix1 = edges[index + 2];
- long dx = ((long) ix1) - ix0;
- long dy = ((long) iy1) - iy0;
-
- // Compute first crossing point at y = minY
- int orientation = edges[index + 4];
- int y = minY;
- long lx = (((long) y) - iy0)*dx/dy + ix0;
- addCrossing(y >> YSHIFT, (int)(lx >> XSHIFT), orientation);
-
- // Advance y to next scanline, exit if past endpoint
- y += YSTEP;
- if (y > maxY) {
- return;
- }
-
- // Compute xstep only if additional scanlines are crossed
- // For each scanline, add xstep to lx and YSTEP to y and
- // emit the new crossing
- long xstep = ((long)YSTEP*dx)/dy;
- for (; y <= maxY; y += YSTEP) {
- lx += xstep;
- addCrossing(y >> YSHIFT, (int)(lx >> XSHIFT), orientation);
- }
- }
-
- private void computeBounds() {
- rasterMinX = crossingMinX & ~SUBPIXEL_MASK_X;
- rasterMaxX = crossingMaxX | SUBPIXEL_MASK_X;
- rasterMinY = crossingMinY & ~SUBPIXEL_MASK_Y;
- rasterMaxY = crossingMaxY | SUBPIXEL_MASK_Y;
-
- // If nothing was drawn, we have:
- // minX = Integer.MAX_VALUE and maxX = Integer.MIN_VALUE
- // so nothing to render
- if (rasterMinX > rasterMaxX || rasterMinY > rasterMaxY) {
- rasterMinX = 0;
- rasterMaxX = -1;
- rasterMinY = 0;
- rasterMaxY = -1;
- return;
- }
-
- if (rasterMinX < boundsMinX >> XSHIFT) {
- rasterMinX = boundsMinX >> XSHIFT;
- }
- if (rasterMinY < boundsMinY >> YSHIFT) {
- rasterMinY = boundsMinY >> YSHIFT;
- }
- if (rasterMaxX > boundsMaxX >> XSHIFT) {
- rasterMaxX = boundsMaxX >> XSHIFT;
- }
- if (rasterMaxY > boundsMaxY >> YSHIFT) {
- rasterMaxY = boundsMaxY >> YSHIFT;
- }
- }
-
- private int clamp(int x, int min, int max) {
- if (x < min) {
- return min;
- } else if (x > max) {
- return max;
- }
- return x;
}
private void _endRendering() {
- if (flips == 0) {
- bboxX0 = bboxY0 = 0;
- bboxX1 = bboxY1 = -1;
- return;
- }
+ // Mask to determine the relevant bit of the crossing sum
+ // 0x1 if EVEN_ODD, all bits if NON_ZERO
+ int mask = (windingRule == WIND_EVEN_ODD) ? 0x1 : ~0x0;
+
+ // add 1 to better deal with the last pixel in a pixel row.
+ int width = ((boundsMaxX - boundsMinX) >> SUBPIXEL_LG_POSITIONS_X) + 1;
+ byte[] alpha = new byte[width+1];
- // Special case for filling a single rect with a flat, opaque color
- // REMIND: This special case was not originally written to fill a
- // cache object and called directly to a Blit - it needs some code
- // to fill the cache instead to be useful for this usage...
- if (false /* Does not work with cache (yet?) */ &&
- edgeIdx == 10 &&
- edges[0] == edges[2] &&
- edges[1] == edges[6] &&
- edges[3] == edges[8] &&
- edges[5] == edges[7] &&
- Math.abs(edges[0] - edges[5]) > MIN_QUAD_OPT_WIDTH)
- {
+ // Now we iterate through the scanlines. We must tell emitRow the coord
+ // of the first non-transparent pixel, so we must keep accumulators for
+ // the first and last pixels of the section of the current pixel row
+ // that we will emit.
+ // We also need to accumulate pix_bbox*, but the iterator does it
+ // for us. We will just get the values from it once this loop is done
+ int pix_maxX = Integer.MIN_VALUE;
+ int pix_minX = Integer.MAX_VALUE;
- int x0 = edges[0] >> XSHIFT;
- int y0 = edges[1] >> YSHIFT;
- int x1 = edges[5] >> XSHIFT;
- int y1 = edges[3] >> YSHIFT;
+ int y = boundsMinY; // needs to be declared here so we emit the last row properly.
+ ScanLineItInitialize();
+ for ( ; ScanLineItHasNext(); ) {
+ int numCrossings = ScanLineItGoToNextYAndComputeCrossings();
+ y = ScanLineItCurrentY();
- if (x0 > x1) {
- int tmp = x0;
- x0 = x1;
- x1 = tmp;
- }
- if (y0 > y1) {
- int tmp = y0;
- y0 = y1;
- y1 = tmp;
+ if (numCrossings > 0) {
+ int lowx = crossings[0] >> 1;
+ int highx = crossings[numCrossings - 1] >> 1;
+ int x0 = Math.max(lowx, boundsMinX);
+ int x1 = Math.min(highx, boundsMaxX);
+
+ pix_minX = Math.min(pix_minX, x0 >> SUBPIXEL_LG_POSITIONS_X);
+ pix_maxX = Math.max(pix_maxX, x1 >> SUBPIXEL_LG_POSITIONS_X);
}
- int bMinX = this.boundsMinX >> XSHIFT;
- int bMinY = this.boundsMinY >> YSHIFT;
- int bMaxX = this.boundsMaxX >> XSHIFT;
- int bMaxY = this.boundsMaxY >> YSHIFT;
+ int sum = 0;
+ int prev = boundsMinX;
+ for (int i = 0; i < numCrossings; i++) {
+ int curxo = crossings[i];
+ int curx = curxo >> 1;
+ int crorientation = ((curxo & 0x1) == 0x1) ? 1 : -1;
+ if ((sum & mask) != 0) {
+ int x0 = Math.max(prev, boundsMinX);
+ int x1 = Math.min(curx, boundsMaxX);
+ if (x0 < x1) {
+ x0 -= boundsMinX; // turn x0, x1 from coords to indeces
+ x1 -= boundsMinX; // in the alpha array.
- // Clip to image bounds in supersampled coordinates
- x0 = clamp(x0, bMinX, bMaxX);
- x1 = clamp(x1, bMinX, bMaxX);
- y0 = clamp(y0, bMinY, bMaxY);
- y1 = clamp(y1, bMinY, bMaxY);
+ int pix_x = x0 >> SUBPIXEL_LG_POSITIONS_X;
+ int pix_xmaxm1 = (x1 - 1) >> SUBPIXEL_LG_POSITIONS_X;
- /*
- * REMIND: Need to fill the cache here instead...
- Blit.fillRectSrcOver(this,
- imageData, imageType,
- imageOffset,
- imageScanlineStride, imagePixelStride,
- width, height,
- x0, y0, x1, y1,
- cred, cgreen, cblue);
- */
+ if (pix_x == pix_xmaxm1) {
+ // Start and end in same pixel
+ alpha[pix_x] += (x1 - x0);
+ alpha[pix_x+1] -= (x1 - x0);
+ } else {
+ int pix_xmax = x1 >> SUBPIXEL_LG_POSITIONS_X;
+ alpha[pix_x] += SUBPIXEL_POSITIONS_X - (x0 & SUBPIXEL_MASK_X);
+ alpha[pix_x+1] += (x0 & SUBPIXEL_MASK_X);
+ alpha[pix_xmax] -= SUBPIXEL_POSITIONS_X - (x1 & SUBPIXEL_MASK_X);
+ alpha[pix_xmax+1] -= (x1 & SUBPIXEL_MASK_X);
+ }
+ }
+ }
+ sum += crorientation;
+ prev = curx;
+ }
- bboxX0 = x0 >> SUBPIXEL_LG_POSITIONS_X;
- bboxY0 = y0 >> SUBPIXEL_LG_POSITIONS_Y;
- bboxX1 = (x1 + SUBPIXEL_POSITIONS_X - 1)
- >> SUBPIXEL_LG_POSITIONS_X;
- bboxY1 = (y1 + SUBPIXEL_POSITIONS_Y - 1)
- >> SUBPIXEL_LG_POSITIONS_Y;
-
- return;
- }
-
- int minY = (edgeMinY > boundsMinY) ? edgeMinY : boundsMinY;
- int maxY = (edgeMaxY < boundsMaxY) ? edgeMaxY : boundsMaxY;
-
- // Check for empty intersection of primitive with the drawing area
- if (minY > maxY) {
- bboxX0 = bboxY0 = 0;
- bboxX1 = bboxY1 = -1;
- return;
+ if ((y & SUBPIXEL_MASK_Y) == SUBPIXEL_MASK_Y) {
+ emitRow(alpha, y >> SUBPIXEL_LG_POSITIONS_Y, pix_minX, pix_maxX);
+ pix_minX = Integer.MAX_VALUE;
+ pix_maxX = Integer.MIN_VALUE;
+ }
}
- // Compute Y extent in subpixel coordinates
- int iminY = (minY >> YSHIFT) & ~SUBPIXEL_MASK_Y;
- int imaxY = (maxY >> YSHIFT) | SUBPIXEL_MASK_Y;
- int yextent = (imaxY - iminY) + 1;
-
- // Maximum number of crossings
- int size = flips*yextent;
-
- int bmax = (boundsMaxY >> YSHIFT) - 1;
- if (imaxY > bmax) {
- imaxY = bmax;
+ // Emit final row
+ if (pix_maxX >= pix_minX) {
+ emitRow(alpha, y >> SUBPIXEL_LG_POSITIONS_Y, pix_minX, pix_maxX);
}
-
- // Initialize X bounds, will be refined for each strip
- bboxX0 = Integer.MAX_VALUE;
- bboxX1 = Integer.MIN_VALUE;
-
- // Set Y bounds
- bboxY0 = iminY >> SUBPIXEL_LG_POSITIONS_Y;
- bboxY1 = (imaxY + SUBPIXEL_POSITIONS_Y - 1) >> SUBPIXEL_LG_POSITIONS_Y;
-
- // Compute number of rows that can be processing using
- // a crossings table no larger than DEFAULT_CROSSINGS_SIZE.
- // However, we must process at least one row, so we grow the table
- // temporarily if needed. This would require an object with a
- // huge number of flips.
- int rows = DEFAULT_CROSSINGS_SIZE/(flips*SUBPIXEL_POSITIONS_Y);
- rows = Math.min(rows, yextent);
- rows = Math.max(rows, 1);
- for (int i = iminY; i <= imaxY; i += rows*SUBPIXEL_POSITIONS_Y) {
- // Compute index of last scanline to be processed in this pass
- int last = Math.min(i + rows*SUBPIXEL_POSITIONS_Y - 1, imaxY);
- setCrossingsExtents(i, last, flips);
-
- int bminY = i << YSHIFT;
- int bmaxY = (last << YSHIFT) | ~YMASK;
+ pix_bboxX0 = minX >> SUBPIXEL_LG_POSITIONS_X;
+ pix_bboxX1 = maxX >> SUBPIXEL_LG_POSITIONS_X;
+ pix_bboxY0 = minY >> SUBPIXEL_LG_POSITIONS_Y;
+ pix_bboxY1 = maxY >> SUBPIXEL_LG_POSITIONS_Y;
+ }
- // Process edges from the edge list
- int maxIdx = edgeIdx;
- for (int index = 0; index < maxIdx; index += 5) {
- // Test y1 < min:
- //
- // If edge lies entirely above current strip,
- // discard it
- if (edges[index + 3] < bminY) {
- // Overwrite the edge with the last edge
- edgeIdx -= 5;
- int fidx = edgeIdx;
- int tidx = index;
- edges[tidx++] = edges[fidx++];
- edges[tidx++] = edges[fidx++];
- edges[tidx++] = edges[fidx++];
- edges[tidx++] = edges[fidx++];
- edges[tidx ] = edges[fidx ];
-
- maxIdx -= 5;
- index -= 5;
- continue;
- }
-
- // Test y0 > max:
- //
- // If edge lies entirely below current strip,
- // skip it for now
- if (edges[index + 1] > bmaxY) {
- continue;
- }
-
- computeCrossingsForEdge(index, bminY, bmaxY);
- }
-
- computeBounds();
- if (rasterMaxX < rasterMinX) {
- continue;
- }
-
- bboxX0 = Math.min(bboxX0,
- rasterMinX >> SUBPIXEL_LG_POSITIONS_X);
- bboxX1 = Math.max(bboxX1,
- (rasterMaxX + SUBPIXEL_POSITIONS_X - 1)
- >> SUBPIXEL_LG_POSITIONS_X);
- renderStrip();
- }
-
- // Free up any unusually large scratchpad memory used by the
- // preceding primitive
- crossingListFinished();
- }
public void endRendering() {
// Set up the cache to accumulate the bounding box
@@ -478,176 +472,31 @@
_endRendering();
}
- public void getBoundingBox(int[] bbox) {
- bbox[0] = bboxX0;
- bbox[1] = bboxY0;
- bbox[2] = bboxX1 - bboxX0;
- bbox[3] = bboxY1 - bboxY0;
+ public void getBoundingBox(int[] pix_bbox) {
+ pix_bbox[0] = pix_bboxX0;
+ pix_bbox[1] = pix_bboxY0;
+ pix_bbox[2] = pix_bboxX1 - pix_bboxX0;
+ pix_bbox[3] = pix_bboxY1 - pix_bboxY0;
}
- private void renderStrip() {
- // Grow rowAA according to the raster width
- int width = (rasterMaxX - rasterMinX + 1) >> SUBPIXEL_LG_POSITIONS_X;
- alphaWidth = width;
-
- // Allocate one extra entry in rowAA to avoid a conditional in
- // the rendering loop
- int bufLen = width + 1;
- if (this.rowAA == null || this.rowAA.length < bufLen) {
- this.rowAA = new byte[bufLen];
- }
-
- // Mask to determine the relevant bit of the crossing sum
- // 0x1 if EVEN_ODD, all bits if NON_ZERO
- int mask = (windingRule == WIND_EVEN_ODD) ? 0x1 : ~0x0;
-
- int y = 0;
- int prevY = rasterMinY - 1;
-
- int minX = Integer.MAX_VALUE;
- int maxX = Integer.MIN_VALUE;
-
- iterateCrossings();
- while (hasMoreCrossingRows()) {
- y = crossingY;
-
- // Emit any skipped rows
- for (int j = prevY + 1; j < y; j++) {
- if (((j & SUBPIXEL_MASK_Y) == SUBPIXEL_MASK_Y) ||
- (j == rasterMaxY)) {
- emitRow(j >> SUBPIXEL_LG_POSITIONS_Y, 0, -1);
- }
- }
- prevY = y;
-
- if (crossingRowIndex < crossingRowCount) {
- int lx = crossings[crossingRowOffset + crossingRowIndex];
- lx >>= 1;
- int hx = crossings[crossingRowOffset + crossingRowCount - 1];
- hx >>= 1;
- int x0 = lx > rasterMinX ? lx : rasterMinX;
- int x1 = hx < rasterMaxX ? hx : rasterMaxX;
- x0 -= rasterMinX;
- x1 -= rasterMinX;
-
- minX = Math.min(minX, x0 >> SUBPIXEL_LG_POSITIONS_X);
- maxX = Math.max(maxX, x1 >> SUBPIXEL_LG_POSITIONS_X);
- }
-
- int sum = 0;
- int prev = rasterMinX;
- while (crossingRowIndex < crossingRowCount) {
- int crxo = crossings[crossingRowOffset + crossingRowIndex];
- crossingRowIndex++;
-
- int crx = crxo >> 1;
- int crorientation = ((crxo & 0x1) == 0x1) ? 1 : -1;
-
- if ((sum & mask) != 0) {
- // Clip to active X range, if x1 < x0 loop will
- // have no effect
- int x0 = prev > rasterMinX ? prev : rasterMinX;
- int x1 = crx < rasterMaxX ? crx : rasterMaxX;
-
- // Empty spans
- if (x1 > x0) {
- x0 -= rasterMinX;
- x1 -= rasterMinX;
-
- // Accumulate alpha, equivalent to:
- // for (int x = x0; x < x1; x++) {
- // ++rowAA[x >> SUBPIXEL_LG_POSITIONS_X];
- // }
- //
- // In the middle of the span, we can update a full
- // pixel at a time (i.e., SUBPIXEL_POSITIONS_X
- // subpixels)
-
- int x = x0 >> SUBPIXEL_LG_POSITIONS_X;
- int xmaxm1 = (x1 - 1) >> SUBPIXEL_LG_POSITIONS_X;
- if (x == xmaxm1) {
- // Start and end in same pixel
- rowAA[x] += x1 - x0;
- } else {
- // Start and end in different pixels
- rowAA[x++] += SUBPIXEL_POSITIONS_X -
- (x0 & SUBPIXEL_MASK_X);
- int xmax = x1 >> SUBPIXEL_LG_POSITIONS_X;
- while (x < xmax) {
- rowAA[x++] += SUBPIXEL_POSITIONS_X;
- }
- // Note - at this point it is possible that
- // x == width, which implies that
- // x1 & SUBPIXEL_MASK_X == 0. We allocate
- // one extra entry in rowAA so this
- // assignment will be harmless. The alternative
- // is an extra conditional here, or some other
- // scheme to deal with the last pixel better.
- rowAA[x] += x1 & SUBPIXEL_MASK_X;
- }
- }
- }
- sum += crorientation;
- prev = crx;
- }
-
- // Every SUBPIXEL_POSITIONS rows, output an antialiased row
- if (((y & SUBPIXEL_MASK_Y) == SUBPIXEL_MASK_Y) ||
- (y == rasterMaxY)) {
- emitRow(y >> SUBPIXEL_LG_POSITIONS_Y, minX, maxX);
- minX = Integer.MAX_VALUE;
- maxX = Integer.MIN_VALUE;
- }
- }
-
- // Emit final row
- for (int j = prevY + 1; j <= rasterMaxY; j++) {
- if (((j & SUBPIXEL_MASK_Y) == SUBPIXEL_MASK_Y) ||
- (j == rasterMaxY)) {
- emitRow(j >> SUBPIXEL_LG_POSITIONS_Y, minX, maxX);
- minX = Integer.MAX_VALUE;
- maxX = Integer.MIN_VALUE;
- }
- }
- }
-
- private void clearAlpha(byte[] alpha,
- int width,
- int minX, int maxX) {
- if (maxX >= minX) {
- int w = maxX - minX + 1;
- if (w + minX > width) {
- w = width - minX;
- }
-
- int aidx = minX;
- for (int i = 0; i < w; i++, aidx++) {
- alpha[aidx] = (byte)0;
- }
- }
- }
-
- private void emitRow(int y, int minX, int maxX) {
+ private void emitRow(byte[] alphaRow, int pix_y, int pix_from, int pix_to) {
// Copy rowAA data into the cache if one is present
if (cache != null) {
- if (maxX >= minX) {
- int x0 = minX + (rasterMinX >> SUBPIXEL_LG_POSITIONS_X);
- int x1 = maxX + (rasterMinX >> SUBPIXEL_LG_POSITIONS_X);
+ if (pix_to >= pix_from) {
+ cache.startRow(pix_y, pix_from, pix_to);
- cache.startRow(y, x0, x1);
- int srcIdx = minX;
+ // Perform run-length encoding and store results in the cache
+ int from = pix_from - (boundsMinX >> SUBPIXEL_LG_POSITIONS_X);
+ int to = pix_to - (boundsMinX >> SUBPIXEL_LG_POSITIONS_X);
- // Perform run-length encoding
- // and store results in the cache
- byte startVal = rowAA[srcIdx++];
int runLen = 1;
- while (srcIdx <= maxX) {
- byte nextVal = rowAA[srcIdx++];
+ byte startVal = alphaRow[from];
+ for (int i = from + 1; i <= to; i++) {
+ byte nextVal = (byte)(startVal + alphaRow[i]);
if (nextVal == startVal && runLen < 255) {
- ++runLen;
+ runLen++;
} else {
cache.addRLERun(startVal, runLen);
-
runLen = 1;
startVal = nextVal;
}
@@ -656,190 +505,6 @@
cache.addRLERun((byte)0, 0);
}
}
-
- clearAlpha(rowAA,
- alphaWidth,
- minX, maxX);
- }
-
- public void setCache(PiscesCache cache) {
- this.cache = cache;
- }
-
- // Edge list data
-
- private int[] edges = new int[5*INITIAL_EDGES];
- private int edgeIdx = 0;
- private int edgeMinY = Integer.MAX_VALUE;
- private int edgeMaxY = Integer.MIN_VALUE;
-
- private void addEdge(int x0, int y0, int x1, int y1) {
- int newLen = edgeIdx + 5;
- if (edges.length < newLen) {
- int[] tmp = new int[Math.max(11*edges.length/10, newLen)];
- System.arraycopy(edges, 0, tmp, 0, edgeIdx);
- this.edges = tmp;
- }
-
- int orientation = 1;
- if (y0 > y1) {
- int tmp = y0;
- y0 = y1;
- y1 = tmp;
-
- orientation = -1;
- }
-
- // Skip edges that don't cross a subsampled scanline
- int eminY = ((y0 + HYSTEP) & YMASK);
- int emaxY = ((y1 - HYSTEP) & YMASK);
- if (eminY > emaxY) {
- return;
- }
-
- if (orientation == -1) {
- int tmp = x0;
- x0 = x1;
- x1 = tmp;
- }
-
- edges[edgeIdx++] = x0;
- edges[edgeIdx++] = y0;
- edges[edgeIdx++] = x1;
- edges[edgeIdx++] = y1;
- edges[edgeIdx++] = orientation;
-
- // Update Y bounds of primitive
- if (y0 < edgeMinY) {
- edgeMinY = y0;
- }
- if (y1 > edgeMaxY) {
- edgeMaxY = y1;
- }
- }
-
- private void resetEdges() {
- this.edgeIdx = 0;
- this.edgeMinY = Integer.MAX_VALUE;
- this.edgeMaxY = Integer.MIN_VALUE;
- }
-
- // Crossing list data
-
- private int[] crossingIndices;
- private int[] crossings;
- private int crossingMinY;
- private int crossingMaxY;
- private int crossingMinX = Integer.MAX_VALUE;
- private int crossingMaxX = Integer.MIN_VALUE;
- private int crossingMaxXEntries;
- private int numCrossings = 0;
- private boolean crossingsSorted = false;
-
- private int crossingY;
- private int crossingRowCount;
- private int crossingRowOffset;
- private int crossingRowIndex;
-
- private void setCrossingsExtents(int minY, int maxY, int maxXEntries) {
- int yextent = maxY - minY + 1;
-
- // Grow indices array as needed
- if (crossingIndices == null || crossingIndices.length < yextent) {
- this.crossingIndices =
- new int[Math.max(yextent, DEFAULT_INDICES_SIZE)];
- }
- // Grow crossings array as needed
- if (crossings == null || crossings.length < yextent*maxXEntries) {
- this.crossings = new int[Math.max(yextent*maxXEntries,
- DEFAULT_CROSSINGS_SIZE)];
- }
- this.crossingMinY = minY;
- this.crossingMaxY = maxY;
- this.crossingMaxXEntries = maxXEntries;
- resetCrossings();
- }
-
- private void resetCrossings() {
- int yextent = crossingMaxY - crossingMinY + 1;
- int start = 0;
- for (int i = 0; i < yextent; i++) {
- crossingIndices[i] = start;
- start += crossingMaxXEntries;
- }
- crossingMinX = Integer.MAX_VALUE;
- crossingMaxX = Integer.MIN_VALUE;
- numCrossings = 0;
- crossingsSorted = false;
- }
-
- // Free sorting arrays if larger than maximum size
- private void crossingListFinished() {
- if (crossings != null && crossings.length > DEFAULT_CROSSINGS_SIZE) {
- crossings = new int[DEFAULT_CROSSINGS_SIZE];
- }
- if (crossingIndices != null &&
- crossingIndices.length > DEFAULT_INDICES_SIZE)
- {
- crossingIndices = new int[DEFAULT_INDICES_SIZE];
- }
- }
-
- private void sortCrossings(int[] x, int off, int len) {
- for (int i = off + 1; i < off + len; i++) {
- int j = i;
- int xj = x[j];
- int xjm1;
-
- while (j > off && (xjm1 = x[j - 1]) > xj) {
- x[j] = xjm1;
- x[j - 1] = xj;
- j--;
- }
- }
- }
-
- private void sortCrossings() {
- int start = 0;
- for (int i = 0; i <= crossingMaxY - crossingMinY; i++) {
- sortCrossings(crossings, start, crossingIndices[i] - start);
- start += crossingMaxXEntries;
- }
- }
-
- private void addCrossing(int y, int x, int orientation) {
- if (x < crossingMinX) {
- crossingMinX = x;
- }
- if (x > crossingMaxX) {
- crossingMaxX = x;
- }
-
- int index = crossingIndices[y - crossingMinY]++;
- x <<= 1;
- crossings[index] = (orientation == 1) ? (x | 0x1) : x;
-
- ++numCrossings;
- }
-
- private void iterateCrossings() {
- if (!crossingsSorted) {
- sortCrossings();
- crossingsSorted = true;
- }
- crossingY = crossingMinY - 1;
- crossingRowOffset = -crossingMaxXEntries;
- }
-
- private boolean hasMoreCrossingRows() {
- if (++crossingY <= crossingMaxY) {
- crossingRowOffset += crossingMaxXEntries;
- int y = crossingY - crossingMinY;
- crossingRowCount = crossingIndices[y] - y*crossingMaxXEntries;
- crossingRowIndex = 0;
- return true;
- } else {
- return false;
- }
+ java.util.Arrays.fill(alphaRow, (byte)0);
}
}
--- a/jdk/src/share/classes/sun/java2d/pisces/Stroker.java Wed Sep 08 14:04:18 2010 -0700
+++ b/jdk/src/share/classes/sun/java2d/pisces/Stroker.java Wed Jul 05 17:21:22 2017 +0200
@@ -25,7 +25,7 @@
package sun.java2d.pisces;
-public class Stroker extends LineSink {
+public class Stroker implements LineSink {
private static final int MOVE_TO = 0;
private static final int LINE_TO = 1;
@@ -61,19 +61,15 @@
*/
public static final int CAP_SQUARE = 2;
- LineSink output;
+ private final LineSink output;
- int lineWidth;
- int capStyle;
- int joinStyle;
- int miterLimit;
+ private final int capStyle;
+ private final int joinStyle;
- Transform4 transform;
- int m00, m01;
- int m10, m11;
+ private final float m00, m01, m10, m11, det;
- int lineWidth2;
- long scaledLineWidth2;
+ private final float lineWidth2;
+ private final float scaledLineWidth2;
// For any pen offset (pen_dx, pen_dy) that does not depend on
// the line orientation, the pen should be transformed so that:
@@ -88,143 +84,86 @@
//
// pen_dx'(r, theta) = r*(m00*cos(theta) + m01*sin(theta))
// pen_dy'(r, theta) = r*(m10*cos(theta) + m11*sin(theta))
- int numPenSegments;
- int[] pen_dx;
- int[] pen_dy;
- boolean[] penIncluded;
- int[] join;
+ private int numPenSegments;
+ private final float[] pen_dx;
+ private final float[] pen_dy;
+ private boolean[] penIncluded;
+ private final float[] join;
- int[] offset = new int[2];
- int[] reverse = new int[100];
- int[] miter = new int[2];
- long miterLimitSq;
+ private final float[] offset = new float[2];
+ private float[] reverse = new float[100];
+ private final float[] miter = new float[2];
+ private final float miterLimitSq;
- int prev;
- int rindex;
- boolean started;
- boolean lineToOrigin;
- boolean joinToOrigin;
-
- int sx0, sy0, sx1, sy1, x0, y0, x1, y1;
- int mx0, my0, mx1, my1, omx, omy;
- int lx0, ly0, lx1, ly1, lx0p, ly0p, px0, py0;
+ private int prev;
+ private int rindex;
+ private boolean started;
+ private boolean lineToOrigin;
+ private boolean joinToOrigin;
- double m00_2_m01_2;
- double m10_2_m11_2;
- double m00_m10_m01_m11;
+ private float sx0, sy0, sx1, sy1, x0, y0, px0, py0;
+ private float mx0, my0, omx, omy;
- /**
- * Empty constructor. <code>setOutput</code> and
- * <code>setParameters</code> must be called prior to calling any
- * other methods.
- */
- public Stroker() {}
+ private float m00_2_m01_2;
+ private float m10_2_m11_2;
+ private float m00_m10_m01_m11;
/**
* Constructs a <code>Stroker</code>.
*
* @param output an output <code>LineSink</code>.
- * @param lineWidth the desired line width in pixels, in S15.16
- * format.
+ * @param lineWidth the desired line width in pixels
* @param capStyle the desired end cap style, one of
* <code>CAP_BUTT</code>, <code>CAP_ROUND</code> or
* <code>CAP_SQUARE</code>.
* @param joinStyle the desired line join style, one of
* <code>JOIN_MITER</code>, <code>JOIN_ROUND</code> or
* <code>JOIN_BEVEL</code>.
- * @param miterLimit the desired miter limit, in S15.16 format.
+ * @param miterLimit the desired miter limit
* @param transform a <code>Transform4</code> object indicating
* the transform that has been previously applied to all incoming
* coordinates. This is required in order to produce consistently
* shaped end caps and joins.
*/
public Stroker(LineSink output,
- int lineWidth,
+ float lineWidth,
int capStyle,
int joinStyle,
- int miterLimit,
- Transform4 transform) {
- setOutput(output);
- setParameters(lineWidth, capStyle, joinStyle, miterLimit, transform);
- }
-
- /**
- * Sets the output <code>LineSink</code> of this
- * <code>Stroker</code>.
- *
- * @param output an output <code>LineSink</code>.
- */
- public void setOutput(LineSink output) {
+ float miterLimit,
+ float m00, float m01, float m10, float m11) {
this.output = output;
- }
- /**
- * Sets the parameters of this <code>Stroker</code>.
- * @param lineWidth the desired line width in pixels, in S15.16
- * format.
- * @param capStyle the desired end cap style, one of
- * <code>CAP_BUTT</code>, <code>CAP_ROUND</code> or
- * <code>CAP_SQUARE</code>.
- * @param joinStyle the desired line join style, one of
- * <code>JOIN_MITER</code>, <code>JOIN_ROUND</code> or
- * <code>JOIN_BEVEL</code>.
- * @param miterLimit the desired miter limit, in S15.16 format.
- * @param transform a <code>Transform4</code> object indicating
- * the transform that has been previously applied to all incoming
- * coordinates. This is required in order to produce consistently
- * shaped end caps and joins.
- */
- public void setParameters(int lineWidth,
- int capStyle,
- int joinStyle,
- int miterLimit,
- Transform4 transform) {
- this.lineWidth = lineWidth;
- this.lineWidth2 = lineWidth >> 1;
- this.scaledLineWidth2 = ((long)transform.m00*lineWidth2) >> 16;
+ this.lineWidth2 = lineWidth / 2;
+ this.scaledLineWidth2 = m00 * lineWidth2;
this.capStyle = capStyle;
this.joinStyle = joinStyle;
- this.miterLimit = miterLimit;
- this.transform = transform;
- this.m00 = transform.m00;
- this.m01 = transform.m01;
- this.m10 = transform.m10;
- this.m11 = transform.m11;
-
- this.m00_2_m01_2 = (double)m00*m00 + (double)m01*m01;
- this.m10_2_m11_2 = (double)m10*m10 + (double)m11*m11;
- this.m00_m10_m01_m11 = (double)m00*m10 + (double)m01*m11;
+ m00_2_m01_2 = m00*m00 + m01*m01;
+ m10_2_m11_2 = m10*m10 + m11*m11;
+ m00_m10_m01_m11 = m00*m10 + m01*m11;
- double dm00 = m00/65536.0;
- double dm01 = m01/65536.0;
- double dm10 = m10/65536.0;
- double dm11 = m11/65536.0;
- double determinant = dm00*dm11 - dm01*dm10;
+ this.m00 = m00;
+ this.m01 = m01;
+ this.m10 = m10;
+ this.m11 = m11;
+ det = m00*m11 - m01*m10;
- if (joinStyle == JOIN_MITER) {
- double limit =
- (miterLimit/65536.0)*(lineWidth2/65536.0)*determinant;
- double limitSq = limit*limit;
- this.miterLimitSq = (long)(limitSq*65536.0*65536.0);
- }
+ float limit = miterLimit * lineWidth2 * det;
+ this.miterLimitSq = limit*limit;
- this.numPenSegments = (int)(3.14159f*lineWidth/65536.0f);
- if (pen_dx == null || pen_dx.length < numPenSegments) {
- this.pen_dx = new int[numPenSegments];
- this.pen_dy = new int[numPenSegments];
- this.penIncluded = new boolean[numPenSegments];
- this.join = new int[2*numPenSegments];
- }
+ this.numPenSegments = (int)(3.14159f * lineWidth);
+ this.pen_dx = new float[numPenSegments];
+ this.pen_dy = new float[numPenSegments];
+ this.penIncluded = new boolean[numPenSegments];
+ this.join = new float[2*numPenSegments];
for (int i = 0; i < numPenSegments; i++) {
- double r = lineWidth/2.0;
- double theta = (double)i*2.0*Math.PI/numPenSegments;
+ double theta = (i * 2.0 * Math.PI)/numPenSegments;
double cos = Math.cos(theta);
double sin = Math.sin(theta);
- pen_dx[i] = (int)(r*(dm00*cos + dm01*sin));
- pen_dy[i] = (int)(r*(dm10*cos + dm11*sin));
+ pen_dx[i] = (float)(lineWidth2 * (m00*cos + m01*sin));
+ pen_dy[i] = (float)(lineWidth2 * (m10*cos + m11*sin));
}
prev = CLOSE;
@@ -233,32 +172,31 @@
lineToOrigin = false;
}
- private void computeOffset(int x0, int y0, int x1, int y1, int[] m) {
- long lx = (long)x1 - (long)x0;
- long ly = (long)y1 - (long)y0;
+ private void computeOffset(float x0, float y0,
+ float x1, float y1, float[] m) {
+ float lx = x1 - x0;
+ float ly = y1 - y0;
- int dx, dy;
+ float dx, dy;
if (m00 > 0 && m00 == m11 && m01 == 0 & m10 == 0) {
- long ilen = PiscesMath.hypot(lx, ly);
+ float ilen = (float)Math.hypot(lx, ly);
if (ilen == 0) {
dx = dy = 0;
} else {
- dx = (int)( (ly*scaledLineWidth2)/ilen);
- dy = (int)(-(lx*scaledLineWidth2)/ilen);
+ dx = (ly * scaledLineWidth2)/ilen;
+ dy = -(lx * scaledLineWidth2)/ilen;
}
} else {
- double dlx = x1 - x0;
- double dly = y1 - y0;
- double det = (double)m00*m11 - (double)m01*m10;
int sdet = (det > 0) ? 1 : -1;
- double a = dly*m00 - dlx*m10;
- double b = dly*m01 - dlx*m11;
- double dh = PiscesMath.hypot(a, b);
- double div = sdet*lineWidth2/(65536.0*dh);
- double ddx = dly*m00_2_m01_2 - dlx*m00_m10_m01_m11;
- double ddy = dly*m00_m10_m01_m11 - dlx*m10_2_m11_2;
- dx = (int)(ddx*div);
- dy = (int)(ddy*div);
+ float a = ly * m00 - lx * m10;
+ float b = ly * m01 - lx * m11;
+ float dh = (float)Math.hypot(a, b);
+ float div = sdet * lineWidth2/dh;
+
+ float ddx = ly * m00_2_m01_2 - lx * m00_m10_m01_m11;
+ float ddy = ly * m00_m10_m01_m11 - lx * m10_2_m11_2;
+ dx = ddx*div;
+ dy = ddy*div;
}
m[0] = dx;
@@ -267,58 +205,43 @@
private void ensureCapacity(int newrindex) {
if (reverse.length < newrindex) {
- int[] tmp = new int[Math.max(newrindex, 6*reverse.length/5)];
- System.arraycopy(reverse, 0, tmp, 0, rindex);
- this.reverse = tmp;
+ reverse = java.util.Arrays.copyOf(reverse, 6*reverse.length/5);
}
}
- private boolean isCCW(int x0, int y0,
- int x1, int y1,
- int x2, int y2) {
- int dx0 = x1 - x0;
- int dy0 = y1 - y0;
- int dx1 = x2 - x1;
- int dy1 = y2 - y1;
- return (long)dx0*dy1 < (long)dy0*dx1;
+ private boolean isCCW(float x0, float y0,
+ float x1, float y1,
+ float x2, float y2) {
+ return (x1 - x0) * (y2 - y1) < (y1 - y0) * (x2 - x1);
}
- private boolean side(int x, int y, int x0, int y0, int x1, int y1) {
- long lx = x;
- long ly = y;
- long lx0 = x0;
- long ly0 = y0;
- long lx1 = x1;
- long ly1 = y1;
-
- return (ly0 - ly1)*lx + (lx1 - lx0)*ly + (lx0*ly1 - lx1*ly0) > 0;
+ private boolean side(float x, float y,
+ float x0, float y0,
+ float x1, float y1) {
+ return (y0 - y1)*x + (x1 - x0)*y + (x0*y1 - x1*y0) > 0;
}
- private int computeRoundJoin(int cx, int cy,
- int xa, int ya,
- int xb, int yb,
+ private int computeRoundJoin(float cx, float cy,
+ float xa, float ya,
+ float xb, float yb,
int side,
boolean flip,
- int[] join) {
- int px, py;
+ float[] join) {
+ float px, py;
int ncoords = 0;
boolean centerSide;
if (side == 0) {
centerSide = side(cx, cy, xa, ya, xb, yb);
} else {
- centerSide = (side == 1) ? true : false;
+ centerSide = (side == 1);
}
for (int i = 0; i < numPenSegments; i++) {
px = cx + pen_dx[i];
py = cy + pen_dy[i];
boolean penSide = side(px, py, xa, ya, xb, yb);
- if (penSide != centerSide) {
- penIncluded[i] = true;
- } else {
- penIncluded[i] = false;
- }
+ penIncluded[i] = (penSide != centerSide);
}
int start = -1, end = -1;
@@ -338,10 +261,10 @@
}
if (start != -1 && end != -1) {
- long dxa = cx + pen_dx[start] - xa;
- long dya = cy + pen_dy[start] - ya;
- long dxb = cx + pen_dx[start] - xb;
- long dyb = cy + pen_dy[start] - yb;
+ float dxa = cx + pen_dx[start] - xa;
+ float dya = cy + pen_dy[start] - ya;
+ float dxb = cx + pen_dx[start] - xb;
+ float dyb = cy + pen_dy[start] - yb;
boolean rev = (dxa*dxa + dya*dya > dxb*dxb + dyb*dyb);
int i = rev ? end : start;
@@ -362,22 +285,25 @@
return ncoords/2;
}
- private static final long ROUND_JOIN_THRESHOLD = 1000L;
- private static final long ROUND_JOIN_INTERNAL_THRESHOLD = 1000000000L;
+ // pisces used to use fixed point arithmetic with 16 decimal digits. I
+ // didn't want to change the values of the constants below when I converted
+ // it to floating point, so that's why the divisions by 2^16 are there.
+ private static final float ROUND_JOIN_THRESHOLD = 1000/65536f;
+ private static final float ROUND_JOIN_INTERNAL_THRESHOLD = 1000000000/65536f;
- private void drawRoundJoin(int x, int y,
- int omx, int omy, int mx, int my,
+ private void drawRoundJoin(float x, float y,
+ float omx, float omy, float mx, float my,
int side,
boolean flip,
boolean rev,
- long threshold) {
+ float threshold) {
if ((omx == 0 && omy == 0) || (mx == 0 && my == 0)) {
return;
}
- long domx = (long)omx - mx;
- long domy = (long)omy - my;
- long len = domx*domx + domy*domy;
+ float domx = omx - mx;
+ float domy = omy - my;
+ float len = domx*domx + domy*domy;
if (len < threshold) {
return;
}
@@ -389,10 +315,10 @@
my = -my;
}
- int bx0 = x + omx;
- int by0 = y + omy;
- int bx1 = x + mx;
- int by1 = y + my;
+ float bx0 = x + omx;
+ float by0 = y + omy;
+ float bx1 = x + mx;
+ float by1 = y + my;
int npoints = computeRoundJoin(x, y,
bx0, by0, bx1, by1, side, flip,
@@ -404,40 +330,30 @@
// Return the intersection point of the lines (ix0, iy0) -> (ix1, iy1)
// and (ix0p, iy0p) -> (ix1p, iy1p) in m[0] and m[1]
- private void computeMiter(int ix0, int iy0, int ix1, int iy1,
- int ix0p, int iy0p, int ix1p, int iy1p,
- int[] m) {
- long x0 = ix0;
- long y0 = iy0;
- long x1 = ix1;
- long y1 = iy1;
+ private void computeMiter(float x0, float y0, float x1, float y1,
+ float x0p, float y0p, float x1p, float y1p,
+ float[] m) {
+ float x10 = x1 - x0;
+ float y10 = y1 - y0;
+ float x10p = x1p - x0p;
+ float y10p = y1p - y0p;
- long x0p = ix0p;
- long y0p = iy0p;
- long x1p = ix1p;
- long y1p = iy1p;
-
- long x10 = x1 - x0;
- long y10 = y1 - y0;
- long x10p = x1p - x0p;
- long y10p = y1p - y0p;
-
- long den = (x10*y10p - x10p*y10) >> 16;
+ float den = x10*y10p - x10p*y10;
if (den == 0) {
- m[0] = ix0;
- m[1] = iy0;
+ m[0] = x0;
+ m[1] = y0;
return;
}
- long t = (x1p*(y0 - y0p) - x0*y10p + x0p*(y1p - y0)) >> 16;
- m[0] = (int)(x0 + (t*x10)/den);
- m[1] = (int)(y0 + (t*y10)/den);
+ float t = x1p*(y0 - y0p) - x0*y10p + x0p*(y1p - y0);
+ m[0] = x0 + (t*x10)/den;
+ m[1] = y0 + (t*y10)/den;
}
- private void drawMiter(int px0, int py0,
- int x0, int y0,
- int x1, int y1,
- int omx, int omy, int mx, int my,
+ private void drawMiter(float px0, float py0,
+ float x0, float y0,
+ float x1, float y1,
+ float omx, float omy, float mx, float my,
boolean rev) {
if (mx == omx && my == omy) {
return;
@@ -461,11 +377,11 @@
miter);
// Compute miter length in untransformed coordinates
- long dx = (long)miter[0] - x0;
- long dy = (long)miter[1] - y0;
- long a = (dy*m00 - dx*m10) >> 16;
- long b = (dy*m01 - dx*m11) >> 16;
- long lenSq = a*a + b*b;
+ float dx = miter[0] - x0;
+ float dy = miter[1] - y0;
+ float a = dy*m00 - dx*m10;
+ float b = dy*m01 - dx*m11;
+ float lenSq = a*a + b*b;
if (lenSq < miterLimitSq) {
emitLineTo(miter[0], miter[1], rev);
@@ -473,7 +389,7 @@
}
- public void moveTo(int x0, int y0) {
+ public void moveTo(float x0, float y0) {
// System.out.println("Stroker.moveTo(" + x0/65536.0 + ", " + y0/65536.0 + ")");
if (lineToOrigin) {
@@ -501,7 +417,7 @@
this.joinSegment = true;
}
- public void lineTo(int x1, int y1) {
+ public void lineTo(float x1, float y1) {
// System.out.println("Stroker.lineTo(" + x1/65536.0 + ", " + y1/65536.0 + ")");
if (lineToOrigin) {
@@ -526,10 +442,10 @@
joinSegment = false;
}
- private void lineToImpl(int x1, int y1, boolean joinSegment) {
+ private void lineToImpl(float x1, float y1, boolean joinSegment) {
computeOffset(x0, y0, x1, y1, offset);
- int mx = offset[0];
- int my = offset[1];
+ float mx = offset[0];
+ float my = offset[1];
if (!started) {
emitMoveTo(x0 + mx, y0 + my);
@@ -567,10 +483,6 @@
emitLineTo(x0 - mx, y0 - my, true);
emitLineTo(x1 - mx, y1 - my, true);
- lx0 = x1 + mx; ly0 = y1 + my;
- lx0p = x1 - mx; ly0p = y1 - my;
- lx1 = x1; ly1 = y1;
-
this.omx = mx;
this.omy = my;
this.px0 = x0;
@@ -594,8 +506,8 @@
}
computeOffset(x0, y0, sx0, sy0, offset);
- int mx = offset[0];
- int my = offset[1];
+ float mx = offset[0];
+ float my = offset[1];
// Draw penultimate join
boolean ccw = isCCW(px0, py0, x0, y0, sx0, sy0);
@@ -678,12 +590,10 @@
this.prev = MOVE_TO;
}
- long lineLength(long ldx, long ldy) {
- long ldet = ((long)m00*m11 - (long)m01*m10) >> 16;
- long la = ((long)ldy*m00 - (long)ldx*m10)/ldet;
- long lb = ((long)ldy*m01 - (long)ldx*m11)/ldet;
- long llen = (int)PiscesMath.hypot(la, lb);
- return llen;
+ double userSpaceLineLength(double dx, double dy) {
+ double a = (dy*m00 - dx*m10)/det;
+ double b = (dy*m01 - dx*m11)/det;
+ return Math.hypot(a, b);
}
private void finish() {
@@ -692,13 +602,13 @@
omx, omy, -omx, -omy, 1, false, false,
ROUND_JOIN_THRESHOLD);
} else if (capStyle == CAP_SQUARE) {
- long ldx = (long)(px0 - x0);
- long ldy = (long)(py0 - y0);
- long llen = lineLength(ldx, ldy);
- long s = (long)lineWidth2*65536/llen;
+ float dx = px0 - x0;
+ float dy = py0 - y0;
+ float len = (float)userSpaceLineLength(dx, dy);
+ float s = lineWidth2/len;
- int capx = x0 - (int)(ldx*s >> 16);
- int capy = y0 - (int)(ldy*s >> 16);
+ float capx = x0 - dx*s;
+ float capy = y0 - dy*s;
emitLineTo(capx + omx, capy + omy);
emitLineTo(capx - omx, capy - omy);
@@ -714,13 +624,13 @@
-mx0, -my0, mx0, my0, 1, false, false,
ROUND_JOIN_THRESHOLD);
} else if (capStyle == CAP_SQUARE) {
- long ldx = (long)(sx1 - sx0);
- long ldy = (long)(sy1 - sy0);
- long llen = lineLength(ldx, ldy);
- long s = (long)lineWidth2*65536/llen;
+ float dx = sx1 - sx0;
+ float dy = sy1 - sy0;
+ float len = (float)userSpaceLineLength(dx, dy);
+ float s = lineWidth2/len;
- int capx = sx0 - (int)(ldx*s >> 16);
- int capy = sy0 - (int)(ldy*s >> 16);
+ float capx = sx0 - dx*s;
+ float capy = sy0 - dy*s;
emitLineTo(capx - mx0, capy - my0);
emitLineTo(capx + mx0, capy + my0);
@@ -730,17 +640,17 @@
this.joinSegment = false;
}
- private void emitMoveTo(int x0, int y0) {
+ private void emitMoveTo(float x0, float y0) {
// System.out.println("Stroker.emitMoveTo(" + x0/65536.0 + ", " + y0/65536.0 + ")");
output.moveTo(x0, y0);
}
- private void emitLineTo(int x1, int y1) {
+ private void emitLineTo(float x1, float y1) {
// System.out.println("Stroker.emitLineTo(" + x0/65536.0 + ", " + y0/65536.0 + ")");
output.lineTo(x1, y1);
}
- private void emitLineTo(int x1, int y1, boolean rev) {
+ private void emitLineTo(float x1, float y1, boolean rev) {
if (rev) {
ensureCapacity(rindex + 2);
reverse[rindex++] = x1;
@@ -755,3 +665,4 @@
output.close();
}
}
+
--- a/jdk/src/share/classes/sun/java2d/pisces/Transform4.java Wed Sep 08 14:04:18 2010 -0700
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,84 +0,0 @@
-/*
- * Copyright (c) 2007, 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.
- */
-
-package sun.java2d.pisces;
-
-public class Transform4 {
-
- public int m00, m01, m10, m11;
-// double det; // det*65536
-
- public Transform4() {
- this(1 << 16, 0, 0, 1 << 16);
- }
-
- public Transform4(int m00, int m01,
- int m10, int m11) {
- this.m00 = m00;
- this.m01 = m01;
- this.m10 = m10;
- this.m11 = m11;
-
-// this.det = (double)m00*m11 - (double)m01*m10;
- }
-
-// public Transform4 createInverse() {
-// double dm00 = m00/65536.0;
-// double dm01 = m01/65536.0;
-// double dm10 = m10/65536.0;
-// double dm11 = m11/65536.0;
-
-// double invdet = 65536.0/(dm00*dm11 - dm01*dm10);
-
-// int im00 = (int)( dm11*invdet);
-// int im01 = (int)(-dm01*invdet);
-// int im10 = (int)(-dm10*invdet);
-// int im11 = (int)( dm00*invdet);
-
-// return new Transform4(im00, im01, im10, im11);
-// }
-
-// public void transform(int[] point) {
-// }
-
-// /**
-// * Returns the length of the line segment obtained by inverse
-// * transforming the points <code>(x0, y0)</code> and <code>(x1,
-// * y1)</code>.
-// */
-// public int getTransformedLength(int x0, int x1, int y0, int y1) {
-// int lx = x1 - x0;
-// int ly = y1 - y0;
-
-// double a = (double)m00*ly - (double)m10*lx;
-// double b = (double)m01*ly - (double)m11*lx;
-// double len = PiscesMath.sqrt((a*a + b*b)/(det*det));
-// return (int)(len*65536.0);
-// }
-
-// public int getType() {
-// }
-
-}
--- a/jdk/src/share/classes/sun/net/www/protocol/file/FileURLConnection.java Wed Sep 08 14:04:18 2010 -0700
+++ b/jdk/src/share/classes/sun/net/www/protocol/file/FileURLConnection.java Wed Jul 05 17:21:22 2017 +0200
@@ -59,7 +59,7 @@
String filename;
boolean isDirectory = false;
boolean exists = false;
- List files;
+ List<String> files;
long length = -1;
long lastModified = 0;
@@ -81,7 +81,10 @@
filename = file.toString();
isDirectory = file.isDirectory();
if (isDirectory) {
- files = (List) Arrays.asList(file.list());
+ String[] fileList = file.list();
+ if (fileList == null)
+ throw new FileNotFoundException(filename + " exists, but is not accessible");
+ files = Arrays.<String>asList(fileList);
} else {
is = new BufferedInputStream(new FileInputStream(filename));
@@ -197,7 +200,7 @@
Collections.sort(files, Collator.getInstance());
for (int i = 0 ; i < files.size() ; i++) {
- String fileName = (String)files.get(i);
+ String fileName = files.get(i);
buf.append(fileName);
buf.append("\n");
}
--- a/jdk/src/share/classes/sun/net/www/protocol/http/HttpURLConnection.java Wed Sep 08 14:04:18 2010 -0700
+++ b/jdk/src/share/classes/sun/net/www/protocol/http/HttpURLConnection.java Wed Jul 05 17:21:22 2017 +0200
@@ -1768,6 +1768,10 @@
// Not really necessary for a tunnel, but can't hurt
requests.setIfNotSet("Accept", acceptString);
+ if (http.getHttpKeepAliveSet()) {
+ requests.setIfNotSet("Proxy-Connection", "keep-alive");
+ }
+
setPreemptiveProxyAuthentication(requests);
/* Log the CONNECT request */
--- a/jdk/src/share/classes/sun/nio/ch/DatagramChannelImpl.java Wed Sep 08 14:04:18 2010 -0700
+++ b/jdk/src/share/classes/sun/nio/ch/DatagramChannelImpl.java Wed Jul 05 17:21:22 2017 +0200
@@ -536,9 +536,11 @@
}
}
- private long read0(ByteBuffer[] bufs) throws IOException {
- if (bufs == null)
- throw new NullPointerException();
+ public long read(ByteBuffer[] dsts, int offset, int length)
+ throws IOException
+ {
+ if ((offset < 0) || (length < 0) || (offset > dsts.length - length))
+ throw new IndexOutOfBoundsException();
synchronized (readLock) {
synchronized (stateLock) {
ensureOpen();
@@ -552,7 +554,7 @@
return 0;
readerThread = NativeThread.current();
do {
- n = IOUtil.read(fd, bufs, nd);
+ n = IOUtil.read(fd, dsts, offset, length, nd);
} while ((n == IOStatus.INTERRUPTED) && isOpen());
return IOStatus.normalize(n);
} finally {
@@ -563,15 +565,6 @@
}
}
- public long read(ByteBuffer[] dsts, int offset, int length)
- throws IOException
- {
- if ((offset < 0) || (length < 0) || (offset > dsts.length - length))
- throw new IndexOutOfBoundsException();
- // ## Fix IOUtil.write so that we can avoid this array copy
- return read0(Util.subsequence(dsts, offset, length));
- }
-
public int write(ByteBuffer buf) throws IOException {
if (buf == null)
throw new NullPointerException();
@@ -599,9 +592,11 @@
}
}
- private long write0(ByteBuffer[] bufs) throws IOException {
- if (bufs == null)
- throw new NullPointerException();
+ public long write(ByteBuffer[] srcs, int offset, int length)
+ throws IOException
+ {
+ if ((offset < 0) || (length < 0) || (offset > srcs.length - length))
+ throw new IndexOutOfBoundsException();
synchronized (writeLock) {
synchronized (stateLock) {
ensureOpen();
@@ -615,7 +610,7 @@
return 0;
writerThread = NativeThread.current();
do {
- n = IOUtil.write(fd, bufs, nd);
+ n = IOUtil.write(fd, srcs, offset, length, nd);
} while ((n == IOStatus.INTERRUPTED) && isOpen());
return IOStatus.normalize(n);
} finally {
@@ -626,15 +621,6 @@
}
}
- public long write(ByteBuffer[] srcs, int offset, int length)
- throws IOException
- {
- if ((offset < 0) || (length < 0) || (offset > srcs.length - length))
- throw new IndexOutOfBoundsException();
- // ## Fix IOUtil.write so that we can avoid this array copy
- return write0(Util.subsequence(srcs, offset, length));
- }
-
protected void implConfigureBlocking(boolean block) throws IOException {
IOUtil.configureBlocking(fd, block);
}
--- a/jdk/src/share/classes/sun/nio/ch/FileChannelImpl.java Wed Sep 08 14:04:18 2010 -0700
+++ b/jdk/src/share/classes/sun/nio/ch/FileChannelImpl.java Wed Jul 05 17:21:22 2017 +0200
@@ -143,7 +143,11 @@
}
}
- private long read0(ByteBuffer[] dsts) throws IOException {
+ public long read(ByteBuffer[] dsts, int offset, int length)
+ throws IOException
+ {
+ if ((offset < 0) || (length < 0) || (offset > dsts.length - length))
+ throw new IndexOutOfBoundsException();
ensureOpen();
if (!readable)
throw new NonReadableChannelException();
@@ -156,7 +160,7 @@
if (!isOpen())
return 0;
do {
- n = IOUtil.read(fd, dsts, nd);
+ n = IOUtil.read(fd, dsts, offset, length, nd);
} while ((n == IOStatus.INTERRUPTED) && isOpen());
return IOStatus.normalize(n);
} finally {
@@ -167,15 +171,6 @@
}
}
- public long read(ByteBuffer[] dsts, int offset, int length)
- throws IOException
- {
- if ((offset < 0) || (length < 0) || (offset > dsts.length - length))
- throw new IndexOutOfBoundsException();
- // ## Fix IOUtil.write so that we can avoid this array copy
- return read0(Util.subsequence(dsts, offset, length));
- }
-
public int write(ByteBuffer src) throws IOException {
ensureOpen();
if (!writable)
@@ -200,7 +195,11 @@
}
}
- private long write0(ByteBuffer[] srcs) throws IOException {
+ public long write(ByteBuffer[] srcs, int offset, int length)
+ throws IOException
+ {
+ if ((offset < 0) || (length < 0) || (offset > srcs.length - length))
+ throw new IndexOutOfBoundsException();
ensureOpen();
if (!writable)
throw new NonWritableChannelException();
@@ -213,7 +212,7 @@
if (!isOpen())
return 0;
do {
- n = IOUtil.write(fd, srcs, nd);
+ n = IOUtil.write(fd, srcs, offset, length, nd);
} while ((n == IOStatus.INTERRUPTED) && isOpen());
return IOStatus.normalize(n);
} finally {
@@ -224,16 +223,6 @@
}
}
- public long write(ByteBuffer[] srcs, int offset, int length)
- throws IOException
- {
- if ((offset < 0) || (length < 0) || (offset > srcs.length - length))
- throw new IndexOutOfBoundsException();
- // ## Fix IOUtil.write so that we can avoid this array copy
- return write0(Util.subsequence(srcs, offset, length));
- }
-
-
// -- Other operations --
public long position() throws IOException {
@@ -440,24 +429,45 @@
}
}
- private long transferToTrustedChannel(long position, int icount,
+ // Maximum size to map when using a mapped buffer
+ private static final long MAPPED_TRANSFER_SIZE = 8L*1024L*1024L;
+
+ private long transferToTrustedChannel(long position, long count,
WritableByteChannel target)
throws IOException
{
- if ( !((target instanceof FileChannelImpl)
- || (target instanceof SelChImpl)))
+ boolean isSelChImpl = (target instanceof SelChImpl);
+ if (!((target instanceof FileChannelImpl) || isSelChImpl))
return IOStatus.UNSUPPORTED;
// Trusted target: Use a mapped buffer
- MappedByteBuffer dbb = null;
- try {
- dbb = map(MapMode.READ_ONLY, position, icount);
- // ## Bug: Closing this channel will not terminate the write
- return target.write(dbb);
- } finally {
- if (dbb != null)
- unmap(dbb);
+ long remaining = count;
+ while (remaining > 0L) {
+ long size = Math.min(remaining, MAPPED_TRANSFER_SIZE);
+ try {
+ MappedByteBuffer dbb = map(MapMode.READ_ONLY, position, size);
+ try {
+ // ## Bug: Closing this channel will not terminate the write
+ int n = target.write(dbb);
+ assert n >= 0;
+ remaining -= n;
+ if (isSelChImpl) {
+ // one attempt to write to selectable channel
+ break;
+ }
+ assert n > 0;
+ position += n;
+ } finally {
+ unmap(dbb);
+ }
+ } catch (IOException ioe) {
+ // Only throw exception if no bytes have been written
+ if (remaining == count)
+ throw ioe;
+ break;
+ }
}
+ return count - remaining;
}
private long transferToArbitraryChannel(long position, int icount,
@@ -535,20 +545,34 @@
long position, long count)
throws IOException
{
- // Note we could loop here to accumulate more at once
synchronized (src.positionLock) {
- long p = src.position();
- int icount = (int)Math.min(Math.min(count, Integer.MAX_VALUE),
- src.size() - p);
- // ## Bug: Closing this channel will not terminate the write
- MappedByteBuffer bb = src.map(MapMode.READ_ONLY, p, icount);
- try {
- long n = write(bb, position);
- src.position(p + n);
- return n;
- } finally {
- unmap(bb);
+ long pos = src.position();
+ long max = Math.min(count, src.size() - pos);
+
+ long remaining = max;
+ long p = pos;
+ while (remaining > 0L) {
+ long size = Math.min(remaining, MAPPED_TRANSFER_SIZE);
+ // ## Bug: Closing this channel will not terminate the write
+ MappedByteBuffer bb = src.map(MapMode.READ_ONLY, p, size);
+ try {
+ long n = write(bb, position);
+ assert n > 0;
+ p += n;
+ position += n;
+ remaining -= n;
+ } catch (IOException ioe) {
+ // Only throw exception if no bytes have been written
+ if (remaining == max)
+ throw ioe;
+ break;
+ } finally {
+ unmap(bb);
+ }
}
+ long nwritten = max - remaining;
+ src.position(pos + nwritten);
+ return nwritten;
}
}
--- a/jdk/src/share/classes/sun/nio/ch/IOUtil.java Wed Sep 08 14:04:18 2010 -0700
+++ b/jdk/src/share/classes/sun/nio/ch/IOUtil.java Wed Jul 05 17:21:22 2017 +0200
@@ -38,34 +38,6 @@
private IOUtil() { } // No instantiation
- /*
- * Returns the index of first buffer in bufs with remaining,
- * or -1 if there is nothing left
- */
- private static int remaining(ByteBuffer[] bufs) {
- int numBufs = bufs.length;
- for (int i=0; i<numBufs; i++) {
- if (bufs[i].hasRemaining()) {
- return i;
- }
- }
- return -1;
- }
-
- /*
- * Returns a new ByteBuffer array with only unfinished buffers in it
- */
- private static ByteBuffer[] skipBufs(ByteBuffer[] bufs,
- int nextWithRemaining)
- {
- int newSize = bufs.length - nextWithRemaining;
- ByteBuffer[] temp = new ByteBuffer[newSize];
- for (int i=0; i<newSize; i++) {
- temp[i] = bufs[i + nextWithRemaining];
- }
- return temp;
- }
-
static int write(FileDescriptor fd, ByteBuffer src, long position,
NativeDispatcher nd, Object lock)
throws IOException
@@ -93,7 +65,7 @@
}
return n;
} finally {
- Util.releaseTemporaryDirectBuffer(bb);
+ Util.offerFirstTemporaryDirectBuffer(bb);
}
}
@@ -125,88 +97,81 @@
static long write(FileDescriptor fd, ByteBuffer[] bufs, NativeDispatcher nd)
throws IOException
{
- int nextWithRemaining = remaining(bufs);
- // if all bufs are empty we should return immediately
- if (nextWithRemaining < 0)
- return 0;
- // If some bufs are empty we should skip them
- if (nextWithRemaining > 0)
- bufs = skipBufs(bufs, nextWithRemaining);
+ return write(fd, bufs, 0, bufs.length, nd);
+ }
- int numBufs = bufs.length;
+ static long write(FileDescriptor fd, ByteBuffer[] bufs, int offset, int length,
+ NativeDispatcher nd)
+ throws IOException
+ {
+ IOVecWrapper vec = IOVecWrapper.get(length);
- // Create shadow to ensure DirectByteBuffers are used
- ByteBuffer[] shadow = new ByteBuffer[numBufs];
+ boolean completed = false;
+ int iov_len = 0;
try {
- for (int i=0; i<numBufs; i++) {
- if (!(bufs[i] instanceof DirectBuffer)) {
- int pos = bufs[i].position();
- int lim = bufs[i].limit();
- assert (pos <= lim);
- int rem = (pos <= lim ? lim - pos : 0);
+
+ // Iterate over buffers to populate native iovec array.
+ int count = offset + length;
+ for (int i=offset; i<count; i++) {
+ ByteBuffer buf = bufs[i];
+ int pos = buf.position();
+ int lim = buf.limit();
+ assert (pos <= lim);
+ int rem = (pos <= lim ? lim - pos : 0);
+ if (rem > 0) {
+ vec.setBuffer(iov_len, buf, pos, rem);
+
+ // allocate shadow buffer to ensure I/O is done with direct buffer
+ if (!(buf instanceof DirectBuffer)) {
+ ByteBuffer shadow = Util.getTemporaryDirectBuffer(rem);
+ shadow.put(buf);
+ shadow.flip();
+ vec.setShadow(iov_len, shadow);
+ buf.position(pos); // temporarily restore position in user buffer
+ buf = shadow;
+ pos = shadow.position();
+ }
- ByteBuffer bb = Util.getTemporaryDirectBuffer(rem);
- shadow[i] = bb;
- // Leave slow buffer position untouched; it will be updated
- // after we see how many bytes were really written out
- bb.put(bufs[i]);
- bufs[i].position(pos);
- bb.flip();
- } else {
- shadow[i] = bufs[i];
+ vec.putBase(iov_len, ((DirectBuffer)buf).address() + pos);
+ vec.putLen(iov_len, rem);
+ iov_len++;
}
}
+ if (iov_len == 0)
+ return 0L;
+
+ long bytesWritten = nd.writev(fd, vec.address, iov_len);
+
+ // Notify the buffers how many bytes were taken
+ long left = bytesWritten;
+ for (int j=0; j<iov_len; j++) {
+ if (left > 0) {
+ ByteBuffer buf = vec.getBuffer(j);
+ int pos = vec.getPosition(j);
+ int rem = vec.getRemaining(j);
+ int n = (left > rem) ? rem : (int)left;
+ buf.position(pos + n);
+ left -= n;
+ }
+ // return shadow buffers to buffer pool
+ ByteBuffer shadow = vec.getShadow(j);
+ if (shadow != null)
+ Util.offerLastTemporaryDirectBuffer(shadow);
+ vec.clearRefs(j);
+ }
- IOVecWrapper vec = null;
- long bytesWritten = 0;
- try {
- // Create a native iovec array
- vec= new IOVecWrapper(numBufs);
-
- // Fill in the iovec array with appropriate data
- for (int i=0; i<numBufs; i++) {
- ByteBuffer nextBuffer = shadow[i];
- // put in the buffer addresses
- long pos = nextBuffer.position();
- long len = nextBuffer.limit() - pos;
- vec.putBase(i, ((DirectBuffer)nextBuffer).address() + pos);
- vec.putLen(i, len);
- }
-
- // Invoke native call to fill the buffers
- bytesWritten = nd.writev(fd, vec.address, numBufs);
- } finally {
- vec.free();
- }
- long returnVal = bytesWritten;
+ completed = true;
+ return bytesWritten;
- // Notify the buffers how many bytes were taken
- for (int i=0; i<numBufs; i++) {
- ByteBuffer nextBuffer = bufs[i];
- int pos = nextBuffer.position();
- int lim = nextBuffer.limit();
- assert (pos <= lim);
- int len = (pos <= lim ? lim - pos : lim);
- if (bytesWritten >= len) {
- bytesWritten -= len;
- int newPosition = pos + len;
- nextBuffer.position(newPosition);
- } else { // Buffers not completely filled
- if (bytesWritten > 0) {
- assert(pos + bytesWritten < (long)Integer.MAX_VALUE);
- int newPosition = (int)(pos + bytesWritten);
- nextBuffer.position(newPosition);
- }
- break;
- }
- }
- return returnVal;
} finally {
- // return any substituted buffers to cache
- for (int i=0; i<numBufs; i++) {
- ByteBuffer bb = shadow[i];
- if (bb != null && bb != bufs[i]) {
- Util.releaseTemporaryDirectBuffer(bb);
+ // if an error occurred then clear refs to buffers and return any shadow
+ // buffers to cache
+ if (!completed) {
+ for (int j=0; j<iov_len; j++) {
+ ByteBuffer shadow = vec.getShadow(j);
+ if (shadow != null)
+ Util.offerLastTemporaryDirectBuffer(shadow);
+ vec.clearRefs(j);
}
}
}
@@ -231,7 +196,7 @@
dst.put(bb);
return n;
} finally {
- Util.releaseTemporaryDirectBuffer(bb);
+ Util.offerFirstTemporaryDirectBuffer(bb);
}
}
@@ -262,92 +227,85 @@
static long read(FileDescriptor fd, ByteBuffer[] bufs, NativeDispatcher nd)
throws IOException
{
- int nextWithRemaining = remaining(bufs);
- // if all bufs are empty we should return immediately
- if (nextWithRemaining < 0)
- return 0;
- // If some bufs are empty we should skip them
- if (nextWithRemaining > 0)
- bufs = skipBufs(bufs, nextWithRemaining);
+ return read(fd, bufs, 0, bufs.length, nd);
+ }
+
+ static long read(FileDescriptor fd, ByteBuffer[] bufs, int offset, int length,
+ NativeDispatcher nd)
+ throws IOException
+ {
+ IOVecWrapper vec = IOVecWrapper.get(length);
+
+ boolean completed = false;
+ int iov_len = 0;
+ try {
- int numBufs = bufs.length;
+ // Iterate over buffers to populate native iovec array.
+ int count = offset + length;
+ for (int i=offset; i<count; i++) {
+ ByteBuffer buf = bufs[i];
+ if (buf.isReadOnly())
+ throw new IllegalArgumentException("Read-only buffer");
+ int pos = buf.position();
+ int lim = buf.limit();
+ assert (pos <= lim);
+ int rem = (pos <= lim ? lim - pos : 0);
+
+ if (rem > 0) {
+ vec.setBuffer(iov_len, buf, pos, rem);
- // Read into the shadow to ensure DirectByteBuffers are used
- ByteBuffer[] shadow = new ByteBuffer[numBufs];
- boolean usingSlowBuffers = false;
- try {
- for (int i=0; i<numBufs; i++) {
- if (bufs[i].isReadOnly())
- throw new IllegalArgumentException("Read-only buffer");
- if (!(bufs[i] instanceof DirectBuffer)) {
- shadow[i] = Util.getTemporaryDirectBuffer(bufs[i].remaining());
- usingSlowBuffers = true;
- } else {
- shadow[i] = bufs[i];
+ // allocate shadow buffer to ensure I/O is done with direct buffer
+ if (!(buf instanceof DirectBuffer)) {
+ ByteBuffer shadow = Util.getTemporaryDirectBuffer(rem);
+ vec.setShadow(iov_len, shadow);
+ buf = shadow;
+ pos = shadow.position();
+ }
+
+ vec.putBase(iov_len, ((DirectBuffer)buf).address() + pos);
+ vec.putLen(iov_len, rem);
+ iov_len++;
}
}
+ if (iov_len == 0)
+ return 0L;
+
+ long bytesRead = nd.readv(fd, vec.address, iov_len);
+
+ // Notify the buffers how many bytes were read
+ long left = bytesRead;
+ for (int j=0; j<iov_len; j++) {
+ ByteBuffer shadow = vec.getShadow(j);
+ if (left > 0) {
+ ByteBuffer buf = vec.getBuffer(j);
+ int rem = vec.getRemaining(j);
+ int n = (left > rem) ? rem : (int)left;
+ if (shadow == null) {
+ int pos = vec.getPosition(j);
+ buf.position(pos + n);
+ } else {
+ shadow.limit(shadow.position() + n);
+ buf.put(shadow);
+ }
+ left -= n;
+ }
+ if (shadow != null)
+ Util.offerLastTemporaryDirectBuffer(shadow);
+ vec.clearRefs(j);
+ }
- IOVecWrapper vec = null;
- long bytesRead = 0;
- try {
- // Create a native iovec array
- vec = new IOVecWrapper(numBufs);
-
- // Fill in the iovec array with appropriate data
- for (int i=0; i<numBufs; i++) {
- ByteBuffer nextBuffer = shadow[i];
- // put in the buffer addresses
- long pos = nextBuffer.position();
- long len = nextBuffer.remaining();
- vec.putBase(i, ((DirectBuffer)nextBuffer).address() + pos);
- vec.putLen(i, len);
- }
-
- // Invoke native call to fill the buffers
- bytesRead = nd.readv(fd, vec.address, numBufs);
- } finally {
- vec.free();
- }
- long returnVal = bytesRead;
+ completed = true;
+ return bytesRead;
- // Notify the buffers how many bytes were read
- for (int i=0; i<numBufs; i++) {
- ByteBuffer nextBuffer = shadow[i];
- // Note: should this have been cached from above?
- int pos = nextBuffer.position();
- int len = nextBuffer.remaining();
- if (bytesRead >= len) {
- bytesRead -= len;
- int newPosition = pos + len;
- nextBuffer.position(newPosition);
- } else { // Buffers not completely filled
- if (bytesRead > 0) {
- assert(pos + bytesRead < (long)Integer.MAX_VALUE);
- int newPosition = (int)(pos + bytesRead);
- nextBuffer.position(newPosition);
- }
- break;
- }
- }
-
- // Put results from shadow into the slow buffers
- if (usingSlowBuffers) {
- for (int i=0; i<numBufs; i++) {
- if (!(bufs[i] instanceof DirectBuffer)) {
- shadow[i].flip();
- bufs[i].put(shadow[i]);
- }
- }
- }
- return returnVal;
} finally {
- // return any substituted buffers to cache
- if (usingSlowBuffers) {
- for (int i=0; i<numBufs; i++) {
- ByteBuffer bb = shadow[i];
- if (bb != null && bb != bufs[i]) {
- Util.releaseTemporaryDirectBuffer(bb);
- }
+ // if an error occurred then clear refs to buffers and return any shadow
+ // buffers to cache
+ if (!completed) {
+ for (int j=0; j<iov_len; j++) {
+ ByteBuffer shadow = vec.getShadow(j);
+ if (shadow != null)
+ Util.offerLastTemporaryDirectBuffer(shadow);
+ vec.clearRefs(j);
}
}
}
--- a/jdk/src/share/classes/sun/nio/ch/IOVecWrapper.java Wed Sep 08 14:04:18 2010 -0700
+++ b/jdk/src/share/classes/sun/nio/ch/IOVecWrapper.java Wed Jul 05 17:21:22 2017 +0200
@@ -25,6 +25,7 @@
package sun.nio.ch;
+import java.nio.ByteBuffer;
import sun.misc.*;
@@ -43,23 +44,98 @@
class IOVecWrapper {
// Miscellaneous constants
- static int BASE_OFFSET = 0;
- static int LEN_OFFSET;
- static int SIZE_IOVEC;
+ private static final int BASE_OFFSET = 0;
+ private static final int LEN_OFFSET;
+ private static final int SIZE_IOVEC;
// The iovec array
- private AllocatedNativeObject vecArray;
+ private final AllocatedNativeObject vecArray;
+
+ // Number of elements in iovec array
+ private final int size;
+
+ // Buffers and position/remaining corresponding to elements in iovec array
+ private final ByteBuffer[] buf;
+ private final int[] position;
+ private final int[] remaining;
+
+ // Shadow buffers for cases when original buffer is substituted
+ private final ByteBuffer[] shadow;
// Base address of this array
- long address;
+ final long address;
// Address size in bytes
static int addressSize;
- IOVecWrapper(int newSize) {
- newSize = (newSize + 1) * SIZE_IOVEC;
- vecArray = new AllocatedNativeObject(newSize, false);
- address = vecArray.address();
+ private static class Deallocator implements Runnable {
+ private final AllocatedNativeObject obj;
+ Deallocator(AllocatedNativeObject obj) {
+ this.obj = obj;
+ }
+ public void run() {
+ obj.free();
+ }
+ }
+
+ // per thread IOVecWrapper
+ private static final ThreadLocal<IOVecWrapper> cached =
+ new ThreadLocal<IOVecWrapper>();
+
+ private IOVecWrapper(int size) {
+ this.size = size;
+ this.buf = new ByteBuffer[size];
+ this.position = new int[size];
+ this.remaining = new int[size];
+ this.shadow = new ByteBuffer[size];
+ this.vecArray = new AllocatedNativeObject(size * SIZE_IOVEC, false);
+ this.address = vecArray.address();
+ }
+
+ static IOVecWrapper get(int size) {
+ IOVecWrapper wrapper = cached.get();
+ if (wrapper != null && wrapper.size < size) {
+ // not big enough; eagerly release memory
+ wrapper.vecArray.free();
+ wrapper = null;
+ }
+ if (wrapper == null) {
+ wrapper = new IOVecWrapper(size);
+ Cleaner.create(wrapper, new Deallocator(wrapper.vecArray));
+ cached.set(wrapper);
+ }
+ return wrapper;
+ }
+
+ void setBuffer(int i, ByteBuffer buf, int pos, int rem) {
+ this.buf[i] = buf;
+ this.position[i] = pos;
+ this.remaining[i] = rem;
+ }
+
+ void setShadow(int i, ByteBuffer buf) {
+ shadow[i] = buf;
+ }
+
+ ByteBuffer getBuffer(int i) {
+ return buf[i];
+ }
+
+ int getPosition(int i) {
+ return position[i];
+ }
+
+ int getRemaining(int i) {
+ return remaining[i];
+ }
+
+ ByteBuffer getShadow(int i) {
+ return shadow[i];
+ }
+
+ void clearRefs(int i) {
+ buf[i] = null;
+ shadow[i] = null;
}
void putBase(int i, long base) {
@@ -78,10 +154,6 @@
vecArray.putLong(offset, len);
}
- void free() {
- vecArray.free();
- }
-
static {
addressSize = Util.unsafe().addressSize();
LEN_OFFSET = addressSize;
--- a/jdk/src/share/classes/sun/nio/ch/SocketChannelImpl.java Wed Sep 08 14:04:18 2010 -0700
+++ b/jdk/src/share/classes/sun/nio/ch/SocketChannelImpl.java Wed Jul 05 17:21:22 2017 +0200
@@ -385,9 +385,11 @@
}
}
- private long read0(ByteBuffer[] bufs) throws IOException {
- if (bufs == null)
- throw new NullPointerException();
+ public long read(ByteBuffer[] dsts, int offset, int length)
+ throws IOException
+ {
+ if ((offset < 0) || (length < 0) || (offset > dsts.length - length))
+ throw new IndexOutOfBoundsException();
synchronized (readLock) {
if (!ensureReadOpen())
return -1;
@@ -401,7 +403,7 @@
}
for (;;) {
- n = IOUtil.read(fd, bufs, nd);
+ n = IOUtil.read(fd, dsts, offset, length, nd);
if ((n == IOStatus.INTERRUPTED) && isOpen())
continue;
return IOStatus.normalize(n);
@@ -418,15 +420,6 @@
}
}
- public long read(ByteBuffer[] dsts, int offset, int length)
- throws IOException
- {
- if ((offset < 0) || (length < 0) || (offset > dsts.length - length))
- throw new IndexOutOfBoundsException();
- // ## Fix IOUtil.write so that we can avoid this array copy
- return read0(Util.subsequence(dsts, offset, length));
- }
-
public int write(ByteBuffer buf) throws IOException {
if (buf == null)
throw new NullPointerException();
@@ -458,9 +451,11 @@
}
}
- public long write0(ByteBuffer[] bufs) throws IOException {
- if (bufs == null)
- throw new NullPointerException();
+ public long write(ByteBuffer[] srcs, int offset, int length)
+ throws IOException
+ {
+ if ((offset < 0) || (length < 0) || (offset > srcs.length - length))
+ throw new IndexOutOfBoundsException();
synchronized (writeLock) {
ensureWriteOpen();
long n = 0;
@@ -472,7 +467,7 @@
writerThread = NativeThread.current();
}
for (;;) {
- n = IOUtil.write(fd, bufs, nd);
+ n = IOUtil.write(fd, srcs, offset, length, nd);
if ((n == IOStatus.INTERRUPTED) && isOpen())
continue;
return IOStatus.normalize(n);
@@ -489,15 +484,6 @@
}
}
- public long write(ByteBuffer[] srcs, int offset, int length)
- throws IOException
- {
- if ((offset < 0) || (length < 0) || (offset > srcs.length - length))
- throw new IndexOutOfBoundsException();
- // ## Fix IOUtil.write so that we can avoid this array copy
- return write0(Util.subsequence(srcs, offset, length));
- }
-
// package-private
int sendOutOfBandData(byte b) throws IOException {
synchronized (writeLock) {
--- a/jdk/src/share/classes/sun/nio/ch/Util.java Wed Sep 08 14:04:18 2010 -0700
+++ b/jdk/src/share/classes/sun/nio/ch/Util.java Wed Jul 05 17:21:22 2017 +0200
@@ -41,67 +41,180 @@
class Util {
-
// -- Caches --
// The number of temp buffers in our pool
- private static final int TEMP_BUF_POOL_SIZE = 3;
+ private static final int TEMP_BUF_POOL_SIZE = 8;
- // Per-thread soft cache of the last temporary direct buffer
- private static ThreadLocal<SoftReference<ByteBuffer>>[] bufferPool;
+ // Per-thread cache of temporary direct buffers
+ private static ThreadLocal<BufferCache> bufferCache =
+ new ThreadLocal<BufferCache>()
+ {
+ @Override
+ protected BufferCache initialValue() {
+ return new BufferCache();
+ }
+ };
+
+ /**
+ * A simple cache of direct buffers.
+ */
+ private static class BufferCache {
+ // the array of buffers
+ private ByteBuffer[] buffers;
- @SuppressWarnings("unchecked")
- static ThreadLocal<SoftReference<ByteBuffer>>[] createThreadLocalBufferPool() {
- return new ThreadLocal[TEMP_BUF_POOL_SIZE];
- }
+ // the number of buffers in the cache
+ private int count;
+
+ // the index of the first valid buffer (undefined if count == 0)
+ private int start;
+
+ private int next(int i) {
+ return (i + 1) % TEMP_BUF_POOL_SIZE;
+ }
+
+ BufferCache() {
+ buffers = new ByteBuffer[TEMP_BUF_POOL_SIZE];
+ }
+
+ /**
+ * Removes and returns a buffer from the cache of at least the given
+ * size (or null if no suitable buffer is found).
+ */
+ ByteBuffer get(int size) {
+ if (count == 0)
+ return null; // cache is empty
- static {
- bufferPool = createThreadLocalBufferPool();
- for (int i=0; i<TEMP_BUF_POOL_SIZE; i++)
- bufferPool[i] = new ThreadLocal<SoftReference<ByteBuffer>>();
- }
+ ByteBuffer[] buffers = this.buffers;
- static ByteBuffer getTemporaryDirectBuffer(int size) {
- ByteBuffer buf = null;
- // Grab a buffer if available
- for (int i=0; i<TEMP_BUF_POOL_SIZE; i++) {
- SoftReference<ByteBuffer> ref = bufferPool[i].get();
- if ((ref != null) && ((buf = ref.get()) != null) &&
- (buf.capacity() >= size)) {
- buf.rewind();
- buf.limit(size);
- bufferPool[i].set(null);
- return buf;
+ // search for suitable buffer (often the first buffer will do)
+ ByteBuffer buf = buffers[start];
+ if (buf.capacity() < size) {
+ buf = null;
+ int i = start;
+ while ((i = next(i)) != start) {
+ ByteBuffer bb = buffers[i];
+ if (bb == null)
+ break;
+ if (bb.capacity() >= size) {
+ buf = bb;
+ break;
+ }
+ }
+ if (buf == null)
+ return null;
+ // move first element to here to avoid re-packing
+ buffers[i] = buffers[start];
+ }
+
+ // remove first element
+ buffers[start] = null;
+ start = next(start);
+ count--;
+
+ // prepare the buffer and return it
+ buf.rewind();
+ buf.limit(size);
+ return buf;
+ }
+
+ boolean offerFirst(ByteBuffer buf) {
+ if (count >= TEMP_BUF_POOL_SIZE) {
+ return false;
+ } else {
+ start = (start + TEMP_BUF_POOL_SIZE - 1) % TEMP_BUF_POOL_SIZE;
+ buffers[start] = buf;
+ count++;
+ return true;
}
}
- // Make a new one
- return ByteBuffer.allocateDirect(size);
- }
-
- static void releaseTemporaryDirectBuffer(ByteBuffer buf) {
- if (buf == null)
- return;
- // Put it in an empty slot if such exists
- for (int i=0; i<TEMP_BUF_POOL_SIZE; i++) {
- SoftReference<ByteBuffer> ref = bufferPool[i].get();
- if ((ref == null) || (ref.get() == null)) {
- bufferPool[i].set(new SoftReference<ByteBuffer>(buf));
- return;
- }
- }
- // Otherwise replace a smaller one in the cache if such exists
- for (int i=0; i<TEMP_BUF_POOL_SIZE; i++) {
- SoftReference<ByteBuffer> ref = bufferPool[i].get();
- ByteBuffer inCacheBuf = ref.get();
- if ((inCacheBuf == null) || (buf.capacity() > inCacheBuf.capacity())) {
- bufferPool[i].set(new SoftReference<ByteBuffer>(buf));
- return;
+ boolean offerLast(ByteBuffer buf) {
+ if (count >= TEMP_BUF_POOL_SIZE) {
+ return false;
+ } else {
+ int next = (start + count) % TEMP_BUF_POOL_SIZE;
+ buffers[next] = buf;
+ count++;
+ return true;
}
}
- // release memory
- ((DirectBuffer)buf).cleaner().clean();
+ boolean isEmpty() {
+ return count == 0;
+ }
+
+ ByteBuffer removeFirst() {
+ assert count > 0;
+ ByteBuffer buf = buffers[start];
+ buffers[start] = null;
+ start = next(start);
+ count--;
+ return buf;
+ }
+ }
+
+ /**
+ * Returns a temporary buffer of at least the given size
+ */
+ static ByteBuffer getTemporaryDirectBuffer(int size) {
+ BufferCache cache = bufferCache.get();
+ ByteBuffer buf = cache.get(size);
+ if (buf != null) {
+ return buf;
+ } else {
+ // No suitable buffer in the cache so we need to allocate a new
+ // one. To avoid the cache growing then we remove the first
+ // buffer from the cache and free it.
+ if (!cache.isEmpty()) {
+ buf = cache.removeFirst();
+ free(buf);
+ }
+ return ByteBuffer.allocateDirect(size);
+ }
+ }
+
+ /**
+ * Releases a temporary buffer by returning to the cache or freeing it.
+ */
+ static void releaseTemporaryDirectBuffer(ByteBuffer buf) {
+ offerFirstTemporaryDirectBuffer(buf);
+ }
+
+ /**
+ * Releases a temporary buffer by returning to the cache or freeing it. If
+ * returning to the cache then insert it at the start so that it is
+ * likely to be returned by a subsequent call to getTemporaryDirectBuffer.
+ */
+ static void offerFirstTemporaryDirectBuffer(ByteBuffer buf) {
+ assert buf != null;
+ BufferCache cache = bufferCache.get();
+ if (!cache.offerFirst(buf)) {
+ // cache is full
+ free(buf);
+ }
+ }
+
+ /**
+ * Releases a temporary buffer by returning to the cache or freeing it. If
+ * returning to the cache then insert it at the end. This makes it
+ * suitable for scatter/gather operations where the buffers are returned to
+ * cache in same order that they were obtained.
+ */
+ static void offerLastTemporaryDirectBuffer(ByteBuffer buf) {
+ assert buf != null;
+ BufferCache cache = bufferCache.get();
+ if (!cache.offerLast(buf)) {
+ // cache is full
+ free(buf);
+ }
+ }
+
+ /**
+ * Frees the memory for the given direct buffer
+ */
+ private static void free(ByteBuffer buf) {
+ ((DirectBuffer)buf).cleaner().clean();
}
private static class SelectorWrapper {
--- a/jdk/src/share/classes/sun/util/resources/TimeZoneNames.java Wed Sep 08 14:04:18 2010 -0700
+++ b/jdk/src/share/classes/sun/util/resources/TimeZoneNames.java Wed Jul 05 17:21:22 2017 +0200
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1996, 2008, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1996, 2010, 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
@@ -75,6 +75,8 @@
"Central European Summer Time", "CEST"};
String CHAST[] = new String[] {"Chatham Standard Time", "CHAST",
"Chatham Daylight Time", "CHADT"};
+ String CHUT[] = new String[] {"Chuuk Time", "CHUT",
+ "Chuuk Summer Time", "CHUST"};
String CIT[] = new String[] {"Central Indonesia Time", "CIT",
"Central Indonesia Summer Time", "CIST"};
String CLT[] = new String[] {"Chile Time", "CLT",
@@ -153,6 +155,8 @@
"Pitcairn Daylight Time", "PDT"};
String PKT[] = new String[] {"Pakistan Time", "PKT",
"Pakistan Summer Time", "PKST"};
+ String PONT[] = new String[] {"Pohnpei Time", "PONT",
+ "Pohnpei Summer Time", "PONST"};
String PST[] = new String[] {"Pacific Standard Time", "PST",
"Pacific Daylight Time", "PDT"};
String RST[] = new String[] {"Eastern Standard Time", "EST",
@@ -169,8 +173,6 @@
"Eastern Summer Time (Tasmania)", "EST"};
String TMT[] = new String[] {"Turkmenistan Time", "TMT",
"Turkmenistan Summer Time", "TMST"};
- String TRUT[] = new String[] {"Truk Time", "TRUT",
- "Truk Summer Time", "TRUST"};
String ULAT[]= new String[] {"Ulaanbaatar Time", "ULAT",
"Ulaanbaatar Summer Time", "ULAST"};
String WART[] = new String[] {"Western Argentine Time", "WART",
@@ -309,6 +311,7 @@
{"America/Atikokan", EST},
{"America/Atka", HAST},
{"America/Bahia", BRT},
+ {"America/Bahia_Banderas", CST},
{"America/Barbados", AST},
{"America/Belem", BRT},
{"America/Belize", CST},
@@ -755,6 +758,7 @@
{"Pacific/Apia", WST_SAMOA},
{"Pacific/Auckland", NZST},
{"Pacific/Chatham", CHAST},
+ {"Pacific/Chuuk", CHUT},
{"Pacific/Easter", EASTER},
{"Pacific/Efate", new String[] {"Vanuatu Time", "VUT",
"Vanuatu Summer Time", "VUST"}},
@@ -793,8 +797,8 @@
{"Pacific/Palau", new String[] {"Palau Time", "PWT",
"Palau Summer Time", "PWST"}},
{"Pacific/Pitcairn", PITCAIRN},
- {"Pacific/Ponape", new String[] {"Ponape Time", "PONT",
- "Ponape Summer Time", "PONST"}},
+ {"Pacific/Pohnpei", PONT},
+ {"Pacific/Ponape", PONT},
{"Pacific/Port_Moresby", new String[] {"Papua New Guinea Time", "PGT",
"Papua New Guinea Summer Time", "PGST"}},
{"Pacific/Rarotonga", new String[] {"Cook Is. Time", "CKT",
@@ -807,12 +811,12 @@
"Gilbert Is. Summer Time", "GILST"}},
{"Pacific/Tongatapu", new String[] {"Tonga Time", "TOT",
"Tonga Summer Time", "TOST"}},
- {"Pacific/Truk", TRUT},
+ {"Pacific/Truk", CHUT},
{"Pacific/Wake", new String[] {"Wake Time", "WAKT",
"Wake Summer Time", "WAKST"}},
{"Pacific/Wallis", new String[] {"Wallis & Futuna Time", "WFT",
"Wallis & Futuna Summer Time", "WFST"}},
- {"Pacific/Yap", TRUT},
+ {"Pacific/Yap", CHUT},
{"Poland", CET},
{"PRC", CTT},
{"PST8PDT", PST},
--- a/jdk/src/share/classes/sun/util/resources/TimeZoneNames_de.java Wed Sep 08 14:04:18 2010 -0700
+++ b/jdk/src/share/classes/sun/util/resources/TimeZoneNames_de.java Wed Jul 05 17:21:22 2017 +0200
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997, 2008, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2010, 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
@@ -75,6 +75,8 @@
"Mitteleurop\u00e4ische Sommerzeit", "MESZ"};
String CHAST[] = new String[] {"Chatham Normalzeit", "CHAST",
"Chatham Sommerzeit", "CHADT"};
+ String CHUT[] = new String[] {"Chuuk Time", "CHUT",
+ "Chuuk Summer Time", "CHUST"};
String CIT[] = new String[] {"Zentralindonesische Zeit", "CIT",
"Zentralindonesische Sommerzeit", "CIST"};
String CLT[] = new String[] {"Chilenische Zeit", "CLT",
@@ -153,6 +155,8 @@
"Pitcairn Sommerzeit", "PDT"};
String PKT[] = new String[] {"Pakistanische Zeit", "PKT",
"Pakistanische Sommerzeit", "PKST"};
+ String PONT[] = new String[] {"Pohnpei Time", "PONT",
+ "Pohnpei Summer Time", "PONST"};
String PST[] = new String[] {"Pazifische Normalzeit", "PST",
"Pazifische Sommerzeit", "PDT"};
String RST[] = new String[] {"\u00d6stliche Normalzeit", "EST",
@@ -169,8 +173,6 @@
"\u00d6stliche Sommerzeit (Tasmanien)", "EST"};
String TMT[] = new String[] {"Turkmenische Zeit", "TMT",
"Turkmenische Sommerzeit", "TMST"};
- String TRUT[] = new String[] {"Truk Zeit", "TRUT",
- "Truk Sommerzeit", "TRUST"};
String ULAT[]= new String[] {"Ulaanbaatar Zeit", "ULAT",
"Ulaanbaatar Sommerzeit", "ULAST"};
String WART[] = new String[] {"Westargentinische Zeit", "WART",
@@ -309,6 +311,7 @@
{"America/Atikokan", EST},
{"America/Atka", HAST},
{"America/Bahia", BRT},
+ {"America/Bahia_Banderas", CST},
{"America/Barbados", AST},
{"America/Belem", BRT},
{"America/Belize", CST},
@@ -446,10 +449,13 @@
{"America/Winnipeg", CST},
{"America/Yakutat", AKST},
{"America/Yellowknife", MST},
+ {"Antarctica/Casey", WST_AUS},
{"Antarctica/Davis", new String[] {"Davis Zeit", "DAVT",
"Davis Sommerzeit", "DAVST"}},
{"Antarctica/DumontDUrville", new String[] {"Dumont-d'Urville Zeit", "DDUT",
"Dumont-d'Urville Sommerzeit", "DDUST"}},
+ {"Antarctica/Macquarie", new String[] {"Macquarie Island Time", "MIST",
+ "Macquarie Island Summer Time", "MIST"}},
{"Antarctica/Mawson", new String[] {"Mawson Zeit", "MAWT",
"Mawson Sommerzeit", "MAWST"}},
{"Antarctica/McMurdo", NZST},
@@ -752,6 +758,7 @@
{"Pacific/Apia", WST_SAMOA},
{"Pacific/Auckland", NZST},
{"Pacific/Chatham", CHAST},
+ {"Pacific/Chuuk", CHUT},
{"Pacific/Easter", EASTER},
{"Pacific/Efate", new String[] {"Vanuatu Zeit", "VUT",
"Vanuatu Sommerzeit", "VUST"}},
@@ -790,8 +797,8 @@
{"Pacific/Palau", new String[] {"Palau Zeit", "PWT",
"Palau Sommerzeit", "PWST"}},
{"Pacific/Pitcairn", PITCAIRN},
- {"Pacific/Ponape", new String[] {"Ponape Zeit", "PONT",
- "Ponape Sommerzeit", "PONST"}},
+ {"Pacific/Pohnpei", PONT},
+ {"Pacific/Ponape", PONT},
{"Pacific/Port_Moresby", new String[] {"Papua-Neuguinea Zeit", "PGT",
"Papua-Neuguinea Sommerzeit", "PGST"}},
{"Pacific/Rarotonga", new String[] {"Cook-Inseln Zeit", "CKT",
@@ -804,12 +811,12 @@
"Gilbert-Inseln Sommerzeit", "GILST"}},
{"Pacific/Tongatapu", new String[] {"Tonga Zeit", "TOT",
"Tonga Sommerzeit", "TOST"}},
- {"Pacific/Truk", TRUT},
+ {"Pacific/Truk", CHUT},
{"Pacific/Wake", new String[] {"Wake Zeit", "WAKT",
"Wake Sommerzeit", "WAKST"}},
{"Pacific/Wallis", new String[] {"Wallis u. Futuna Zeit", "WFT",
"Wallis u. Futuna Sommerzeit", "WFST"}},
- {"Pacific/Yap", TRUT},
+ {"Pacific/Yap", CHUT},
{"Poland", CET},
{"PRC", CTT},
{"PST8PDT", PST},
--- a/jdk/src/share/classes/sun/util/resources/TimeZoneNames_es.java Wed Sep 08 14:04:18 2010 -0700
+++ b/jdk/src/share/classes/sun/util/resources/TimeZoneNames_es.java Wed Jul 05 17:21:22 2017 +0200
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997, 2008, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2010, 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
@@ -75,6 +75,8 @@
"Hora de verano de Europa Central", "CEST"};
String CHAST[] = new String[] {"Hora est\u00e1ndar de Chatham", "CHAST",
"Hora de verano de Chatham", "CHADT"};
+ String CHUT[] = new String[] {"Chuuk Time", "CHUT",
+ "Chuuk Summer Time", "CHUST"};
String CIT[] = new String[] {"Hora de Indonesia Central", "CIT",
"Hora de verano de Indonesia Central", "CIST"};
String CLT[] = new String[] {"Hora de Chile", "CLT",
@@ -153,6 +155,8 @@
"Hora de verano de Pitcairn", "PDT"};
String PKT[] = new String[] {"Hora de Pakist\u00e1n", "PKT",
"Hora de verano de Pakist\u00e1n", "PKST"};
+ String PONT[] = new String[] {"Pohnpei Time", "PONT",
+ "Pohnpei Summer Time", "PONST"};
String PST[] = new String[] {"Hora est\u00e1ndar del Pac\u00edfico", "PST",
"Hora de verano del Pac\u00edfico", "PDT"};
String RST[] = new String[] {"Hora est\u00e1ndar Oriental", "EST",
@@ -169,8 +173,6 @@
"Hora de verano del Este (Tasmania)", "EST"};
String TMT[] = new String[] {"Hora de Turkmenist\u00e1n", "TMT",
"Hora de verano de Turkmenist\u00e1n", "TMST"};
- String TRUT[] =new String[] {"Hora de Truk", "TRUT",
- "Hora de verano de Truk", "TRUST"};
String ULAT[]= new String[] {"Hora de Ulan Bator", "ULAT",
"Hora de verano de Ulan Bator", "ULAST"};
String WART[] = new String[] {"Hora de Argentina Occidental", "WART",
@@ -309,6 +311,7 @@
{"America/Atikokan", EST},
{"America/Atka", HAST},
{"America/Bahia", BRT},
+ {"America/Bahia_Banderas", CST},
{"America/Barbados", AST},
{"America/Belem", BRT},
{"America/Belize", CST},
@@ -446,10 +449,13 @@
{"America/Winnipeg", CST},
{"America/Yakutat", AKST},
{"America/Yellowknife", MST},
+ {"Antarctica/Casey", WST_AUS},
{"Antarctica/Davis", new String[] {"Hora de Davis", "DAVT",
"Hora de verano de Davis", "DAVST"}},
{"Antarctica/DumontDUrville", new String[] {"Hora de Dumont-d'Urville", "DDUT",
"Hora de verano de Dumont-d'Urville", "DDUST"}},
+ {"Antarctica/Macquarie", new String[] {"Macquarie Island Time", "MIST",
+ "Macquarie Island Summer Time", "MIST"}},
{"Antarctica/Mawson", new String[] {"Hora de Mawson", "MAWT",
"Hora de verano de Mawson", "MAWST"}},
{"Antarctica/McMurdo", NZST},
@@ -533,7 +539,6 @@
"Hora de verano de Filipinas", "PHST"}},
{"Asia/Muscat", GST},
{"Asia/Nicosia", EET},
-
{"Asia/Novokuznetsk", NOVT},
{"Asia/Novosibirsk", NOVT},
{"Asia/Oral", new String[] {"Hora de Uralsk", "ORAT",
@@ -753,6 +758,7 @@
{"Pacific/Apia", WST_SAMOA},
{"Pacific/Auckland", NZST},
{"Pacific/Chatham", CHAST},
+ {"Pacific/Chuuk", CHUT},
{"Pacific/Easter", EASTER},
{"Pacific/Efate", new String[] {"Hora de Vanuatu", "VUT",
"Hora de verano de Vanuatu", "VUST"}},
@@ -791,8 +797,8 @@
{"Pacific/Palau", new String[] {"Hora de Palau", "PWT",
"Hora de verano de Palau", "PWST"}},
{"Pacific/Pitcairn", PITCAIRN},
- {"Pacific/Ponape", new String[] {"Hora de Ponape", "PONT",
- "Hora de verano de Ponape", "PONST"}},
+ {"Pacific/Pohnpei", PONT},
+ {"Pacific/Ponape", PONT},
{"Pacific/Port_Moresby", new String[] {"Hora de Pap\u00faa-Nueva Guinea", "PGT",
"Hora de verano de Pap\u00faa-Nueva Guinea", "PGST"}},
{"Pacific/Rarotonga", new String[] {"Hora de las islas Cook", "CKT",
@@ -805,12 +811,12 @@
"Hora de verano de las islas Gilbert", "GILST"}},
{"Pacific/Tongatapu", new String[] {"Hora de Tonga", "TOT",
"Hora de verano de Tonga", "TOST"}},
- {"Pacific/Truk", TRUT},
+ {"Pacific/Truk", CHUT},
{"Pacific/Wake", new String[] {"Hora de Wake", "WAKT",
"Hora de verano de Wake", "WAKST"}},
{"Pacific/Wallis", new String[] {"Hora de Wallis y Futuna", "WFT",
"Hora de verano de Wallis y Futuna", "WFST"}},
- {"Pacific/Yap", TRUT},
+ {"Pacific/Yap", CHUT},
{"Poland", CET},
{"PRC", CTT},
{"PST8PDT", PST},
--- a/jdk/src/share/classes/sun/util/resources/TimeZoneNames_fr.java Wed Sep 08 14:04:18 2010 -0700
+++ b/jdk/src/share/classes/sun/util/resources/TimeZoneNames_fr.java Wed Jul 05 17:21:22 2017 +0200
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997, 2008, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2010, 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
@@ -75,6 +75,8 @@
"Heure d'\u00e9t\u00e9 d'Europe centrale", "CEST"} ;
String CHAST[] = new String[] {"Heure standard de Chatham", "CHAST",
"Heure avanc\u00e9e de Chatham", "CHADT"};
+ String CHUT[] = new String[] {"Chuuk Time", "CHUT",
+ "Chuuk Summer Time", "CHUST"};
String CIT[] = new String[] {"Heure d'Indon\u00e9sie centrale", "CIT",
"Heure d'\u00e9t\u00e9 d'Indon\u00e9sie centrale", "CIST"};
String CLT[] = new String[] {"Heure du Chili", "CLT",
@@ -153,6 +155,8 @@
"heure avanc\u00e9e des Pitcairn", "PDT"};
String PKT[] = new String[] {"Heure du Pakistan", "PKT",
"Heure d'\u00e9t\u00e9 du Pakistan", "PKST"} ;
+ String PONT[] = new String[] {"Pohnpei Time", "PONT",
+ "Pohnpei Summer Time", "PONST"};
String PST[] = new String[] {"Heure normale du Pacifique", "PST",
"Heure avanc\u00e9e du Pacifique", "PDT"} ;
String RST[] = new String[] {"Heure normale de l'Est", "EST",
@@ -169,8 +173,6 @@
"Heure d'\u00e9t\u00e9 d'Australie orientale (Tasmanie)", "EST"};
String TMT[] = new String[] {"Heure du Turkm\u00e9nistan", "TMT",
"Heure d'\u00e9t\u00e9 du Turkm\u00e9nistan", "TMST"} ;
- String TRUT[] = new String[] {"Heure de Truk", "TRUT",
- "Heure d'\u00e9t\u00e9 de Truk", "TRUST"};
String ULAT[]= new String[] {"Heure de l'Ulaanbaatar", "ULAT",
"Heure d'\u00e9t\u00e9 de l'Ulaanbaatar", "ULAST"} ;
String WART[] = new String[] {"Heure D'Argentine de l'Ouest", "WART",
@@ -309,6 +311,7 @@
{"America/Atikokan", EST},
{"America/Atka", HAST},
{"America/Bahia", BRT},
+ {"America/Bahia_Banderas", CST},
{"America/Barbados", AST},
{"America/Belem", BRT},
{"America/Belize", CST},
@@ -446,10 +449,13 @@
{"America/Winnipeg", CST},
{"America/Yakutat", AKST},
{"America/Yellowknife", MST},
+ {"Antarctica/Casey", WST_AUS},
{"Antarctica/Davis", new String[] {"Heure de Davis", "DAVT",
"Heure d'\u00e9t\u00e9 de Davis", "DAVST"}},
{"Antarctica/DumontDUrville", new String[] {"Heure de Dumont-d'Urville", "DDUT",
"Heure d'\u00e9t\u00e9 de Dumont-d'Urville", "DDUST"}},
+ {"Antarctica/Macquarie", new String[] {"Macquarie Island Time", "MIST",
+ "Macquarie Island Summer Time", "MIST"}},
{"Antarctica/Mawson", new String[] {"Heure de Mawson", "MAWT",
"Heure d'\u00e9t\u00e9 de Mawson", "MAWST"}},
{"Antarctica/McMurdo", NZST},
@@ -752,6 +758,7 @@
{"Pacific/Apia", WST_SAMOA},
{"Pacific/Auckland", NZST},
{"Pacific/Chatham", CHAST},
+ {"Pacific/Chuuk", CHUT},
{"Pacific/Easter", EASTER},
{"Pacific/Efate", new String[] {"Heure du Vanuatu", "VUT",
"Heure d'\u00e9t\u00e9 du Vanuatu", "VUST"}},
@@ -790,8 +797,8 @@
{"Pacific/Palau", new String[] {"Heure de Palaos", "PWT",
"Heure d'\u00e9t\u00e9 de Palaos", "PWST"}},
{"Pacific/Pitcairn", PITCAIRN},
- {"Pacific/Ponape", new String[] {"Heure de Ponap\u00e9", "PONT",
- "Heure d'\u00e9t\u00e9 de Ponap\u00e9", "PONST"}},
+ {"Pacific/Pohnpei", PONT},
+ {"Pacific/Ponape", PONT},
{"Pacific/Port_Moresby", new String[] {"Heure de Papouasie-Nouvelle-Guin\u00e9e", "PGT",
"Heure d'\u00e9t\u00e9 de de Papouasie-Nouvelle-Guin\u00e9e", "PGST"}},
{"Pacific/Rarotonga", new String[] {"Heure des \u00celes Cook", "CKT",
@@ -804,12 +811,12 @@
"Heure d'\u00e9t\u00e9 de Kiribati", "GILST"}},
{"Pacific/Tongatapu", new String[] {"Heure de Tonga", "TOT",
"Heure d'\u00e9t\u00e9 de Tonga", "TOST"}},
- {"Pacific/Truk", TRUT},
+ {"Pacific/Truk", CHUT},
{"Pacific/Wake", new String[] {"Heure de Wake", "WAKT",
"Heure d'\u00e9t\u00e9 de Wake", "WAKST"}},
{"Pacific/Wallis", new String[] {"Heure de Wallis et Futuna", "WFT",
"Heure d'\u00e9t\u00e9 de Wallis et Futuna", "WFST"}},
- {"Pacific/Yap", TRUT},
+ {"Pacific/Yap", CHUT},
{"Poland", CET},
{"PRC", CTT},
{"PST8PDT", PST},
--- a/jdk/src/share/classes/sun/util/resources/TimeZoneNames_it.java Wed Sep 08 14:04:18 2010 -0700
+++ b/jdk/src/share/classes/sun/util/resources/TimeZoneNames_it.java Wed Jul 05 17:21:22 2017 +0200
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997, 2008, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2010, 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
@@ -75,6 +75,8 @@
"Ora estiva dell'Europa centrale", "CEST"};
String CHAST[] = new String[] {"Ora di Chatham standard", "CHAST",
"Ora legale di Chatham", "CHADT"};
+ String CHUT[] = new String[] {"Chuuk Time", "CHUT",
+ "Chuuk Summer Time", "CHUST"};
String CIT[] = new String[] {"Ora dell'Indonesia centrale", "CIT",
"Ora estiva dell'Indonesia centrale", "CIST"};
String CLT[] = new String[] {"Ora del Cile", "CLT",
@@ -153,6 +155,8 @@
"Ora legale di Pitcairn", "PDT"};
String PKT[] = new String[] {"Ora del Pakistan", "PKT",
"Ora estiva del Pakistan", "PKST"};
+ String PONT[] = new String[] {"Pohnpei Time", "PONT",
+ "Pohnpei Summer Time", "PONST"};
String PST[] = new String[] {"Ora solare della costa occidentale USA", "PST",
"Ora legale della costa occidentale USA", "PDT"};
String RST[] = new String[] {"Ora solare USA orientale", "EST",
@@ -169,8 +173,6 @@
"Ora estiva orientale (Tasmania)", "EST"};
String TMT[] = new String[] {"Ora del Turkmenistan", "TMT",
"Ora estiva del Turkmenistan", "TMST"};
- String TRUT[] = new String[] {"Ora di Truk", "TRUT",
- "Ora estiva di Truk", "TRUST"};
String ULAT[]= new String[] {"Ora di Ulaanbaatar", "ULAT",
"Ora estiva di Ulaanbaatar", "ULAST"};
String WART[] = new String[] {"Ora dell'Argentina occidentale", "WART",
@@ -309,6 +311,7 @@
{"America/Atikokan", EST},
{"America/Atka", HAST},
{"America/Bahia", BRT},
+ {"America/Bahia_Banderas", CST},
{"America/Barbados", AST},
{"America/Belem", BRT},
{"America/Belize", CST},
@@ -446,10 +449,13 @@
{"America/Winnipeg", CST},
{"America/Yakutat", AKST},
{"America/Yellowknife", MST},
+ {"Antarctica/Casey", WST_AUS},
{"Antarctica/Davis", new String[] {"Ora di Davis", "DAVT",
"Ora estiva di Davis", "DAVST"}},
{"Antarctica/DumontDUrville", new String[] {"Ora di Dumont-d'Urville", "DDUT",
"Ora estiva di Dumont-d'Urville", "DDUST"}},
+ {"Antarctica/Macquarie", new String[] {"Macquarie Island Time", "MIST",
+ "Macquarie Island Summer Time", "MIST"}},
{"Antarctica/Mawson", new String[] {"Ora di Mawson", "MAWT",
"Ora estiva di Mawson", "MAWST"}},
{"Antarctica/McMurdo", NZST},
@@ -752,6 +758,7 @@
{"Pacific/Apia", WST_SAMOA},
{"Pacific/Auckland", NZST},
{"Pacific/Chatham", CHAST},
+ {"Pacific/Chuuk", CHUT},
{"Pacific/Easter", EASTER},
{"Pacific/Efate", new String[] {"Ora di Vanuatu", "VUT",
"Ora estiva di Vanuatu", "VUST"}},
@@ -790,8 +797,8 @@
{"Pacific/Palau", new String[] {"Ora di Palau", "PWT",
"Ora estiva di Palau", "PWST"}},
{"Pacific/Pitcairn", PITCAIRN},
- {"Pacific/Ponape", new String[] {"Ora di Ponape", "PONT",
- "Ora estiva di Ponape", "PONST"}},
+ {"Pacific/Pohnpei", PONT},
+ {"Pacific/Ponape", PONT},
{"Pacific/Port_Moresby", new String[] {"Ora di Papua Nuova Guinea", "PGT",
"Ora estiva di Papua Nuova Guinea", "PGST"}},
{"Pacific/Rarotonga", new String[] {"Ora delle Isole Cook", "CKT",
@@ -804,12 +811,12 @@
"Ora estiva delle Isole Gilbert", "GILST"}},
{"Pacific/Tongatapu", new String[] {"Ora di Tonga", "TOT",
"Ora estiva di Tonga", "TOST"}},
- {"Pacific/Truk", TRUT},
+ {"Pacific/Truk", CHUT},
{"Pacific/Wake", new String[] {"Ora di Wake", "WAKT",
"Ora estiva di Wake", "WAKST"}},
{"Pacific/Wallis", new String[] {"Ora di Wallis e Futuna", "WFT",
"Ora estiva di Wallis e Futuna", "WFST"}},
- {"Pacific/Yap", TRUT},
+ {"Pacific/Yap", CHUT},
{"Poland", CET},
{"PRC", CTT},
{"PST8PDT", PST},
--- a/jdk/src/share/classes/sun/util/resources/TimeZoneNames_ja.java Wed Sep 08 14:04:18 2010 -0700
+++ b/jdk/src/share/classes/sun/util/resources/TimeZoneNames_ja.java Wed Jul 05 17:21:22 2017 +0200
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997, 2008, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2010, 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
@@ -75,6 +75,8 @@
"\u4e2d\u90e8\u30e8\u30fc\u30ed\u30c3\u30d1\u590f\u6642\u9593", "CEST"};
String CHAST[] = new String[] {"\u30c1\u30e3\u30bf\u30e0\u6a19\u6e96\u6642", "CHAST",
"\u30c1\u30e3\u30bf\u30e0\u590f\u6642\u9593", "CHADT"};
+ String CHUT[] = new String[] {"Chuuk Time", "CHUT",
+ "Chuuk Summer Time", "CHUST"};
String CIT[] = new String[] {"\u4e2d\u592e\u30a4\u30f3\u30c9\u30cd\u30b7\u30a2\u6642\u9593", "CIT",
"\u4e2d\u592e\u30a4\u30f3\u30c9\u30cd\u30b7\u30a2\u590f\u6642\u9593", "CIST"};
String CLT[] = new String[] {"\u30c1\u30ea\u6642\u9593", "CLT",
@@ -153,6 +155,8 @@
"\u30d4\u30c8\u30b1\u30eb\u30f3\u5cf6\u590f\u6642\u9593", "PDT"};
String PKT[] = new String[] {"\u30d1\u30ad\u30b9\u30bf\u30f3\u6642\u9593", "PKT",
"\u30d1\u30ad\u30b9\u30bf\u30f3\u590f\u6642\u9593", "PKST"};
+ String PONT[] = new String[] {"Pohnpei Time", "PONT",
+ "Pohnpei Summer Time", "PONST"};
String PST[] = new String[] {"\u592a\u5e73\u6d0b\u6a19\u6e96\u6642", "PST",
"\u592a\u5e73\u6d0b\u590f\u6642\u9593", "PDT"};
String RST[] = new String[] {"\u6771\u90e8\u6a19\u6e96\u6642", "EST",
@@ -169,8 +173,6 @@
"\u6771\u90e8\u590f\u6642\u9593 (\u30bf\u30b9\u30de\u30cb\u30a2)", "EST"};
String TMT[] = new String[] {"\u30c8\u30eb\u30af\u30e1\u30cb\u30b9\u30bf\u30f3\u6642\u9593", "TMT",
"\u30c8\u30eb\u30af\u30e1\u30cb\u30b9\u30bf\u30f3\u590f\u6642\u9593", "TMST"};
- String TRUT[] = new String[] {"\u30c8\u30e9\u30c3\u30af\u6642\u9593", "TRUT",
- "\u30c8\u30e9\u30c3\u30af\u590f\u6642\u9593", "TRUST"};
String ULAT[]= new String[] {"\u30a6\u30e9\u30fc\u30f3\u30d0\u30fc\u30c8\u30eb\u6642\u9593", "ULAT",
"\u30a6\u30e9\u30fc\u30f3\u30d0\u30fc\u30c8\u30eb\u590f\u6642\u9593", "ULAST"};
String WART[] = new String[] {"\u897f\u30a2\u30eb\u30bc\u30f3\u30c1\u30f3\u6642\u9593", "WART",
@@ -309,6 +311,7 @@
{"America/Atikokan", EST},
{"America/Atka", HAST},
{"America/Bahia", BRT},
+ {"America/Bahia_Banderas", CST},
{"America/Barbados", AST},
{"America/Belem", BRT},
{"America/Belize", CST},
@@ -446,10 +449,13 @@
{"America/Winnipeg", CST},
{"America/Yakutat", AKST},
{"America/Yellowknife", MST},
+ {"Antarctica/Casey", WST_AUS},
{"Antarctica/Davis", new String[] {"\u30c7\u30a4\u30d3\u30b9\u6642\u9593", "DAVT",
"\u30c7\u30a4\u30d3\u30b9\u590f\u6642\u9593", "DAVST"}},
{"Antarctica/DumontDUrville", new String[] {"\u30c7\u30e5\u30e2\u30f3\u30c7\u30e5\u30eb\u30f4\u30a3\u30eb\u6642\u9593", "DDUT",
"\u30c7\u30e5\u30e2\u30f3\u30c7\u30e5\u30eb\u30f4\u30a3\u30eb\u590f\u6642\u9593", "DDUST"}},
+ {"Antarctica/Macquarie", new String[] {"Macquarie Island Time", "MIST",
+ "Macquarie Island Summer Time", "MIST"}},
{"Antarctica/Mawson", new String[] {"\u30e2\u30fc\u30bd\u30f3\u6642\u9593", "MAWT",
"\u30e2\u30fc\u30bd\u30f3\u590f\u6642\u9593", "MAWST"}},
{"Antarctica/McMurdo", NZST},
@@ -752,6 +758,7 @@
{"Pacific/Apia", WST_SAMOA},
{"Pacific/Auckland", NZST},
{"Pacific/Chatham", CHAST},
+ {"Pacific/Chuuk", CHUT},
{"Pacific/Easter", EASTER},
{"Pacific/Efate", new String[] {"\u30d0\u30cc\u30a2\u30c4\u6642\u9593", "VUT",
"\u30d0\u30cc\u30a2\u30c4\u590f\u6642\u9593", "VUST"}},
@@ -790,8 +797,8 @@
{"Pacific/Palau", new String[] {"\u30d1\u30e9\u30aa\u6642\u9593", "PWT",
"\u30d1\u30e9\u30aa\u590f\u6642\u9593", "PWST"}},
{"Pacific/Pitcairn", PITCAIRN},
- {"Pacific/Ponape", new String[] {"\u30dd\u30ca\u30da\u6642\u9593", "PONT",
- "\u30dd\u30ca\u30da\u590f\u6642\u9593", "PONST"}},
+ {"Pacific/Pohnpei", PONT},
+ {"Pacific/Ponape", PONT},
{"Pacific/Port_Moresby", new String[] {"\u30d1\u30d7\u30a2\u30cb\u30e5\u30fc\u30ae\u30cb\u30a2\u6642\u9593", "PGT",
"\u30d1\u30d7\u30a2\u30cb\u30e5\u30fc\u30ae\u30cb\u30a2\u590f\u6642\u9593", "PGST"}},
{"Pacific/Rarotonga", new String[] {"\u30af\u30c3\u30af\u8af8\u5cf6\u6642\u9593", "CKT",
@@ -804,12 +811,12 @@
"\u30ae\u30eb\u30d0\u30fc\u30c8\u8af8\u5cf6\u590f\u6642\u9593", "GILST"}},
{"Pacific/Tongatapu", new String[] {"\u30c8\u30f3\u30ac\u6642\u9593", "TOT",
"\u30c8\u30f3\u30ac\u590f\u6642\u9593", "TOST"}},
- {"Pacific/Truk", TRUT},
+ {"Pacific/Truk", CHUT},
{"Pacific/Wake", new String[] {"\u30a6\u30a7\u30fc\u30af\u6642\u9593", "WAKT",
"\u30a6\u30a7\u30fc\u30af\u590f\u6642\u9593", "WAKST"}},
{"Pacific/Wallis", new String[] {"\u30ef\u30ea\u30b9\u53ca\u3073\u30d5\u30c4\u30ca\u6642\u9593", "WFT",
"\u30ef\u30ea\u30b9\u53ca\u3073\u30d5\u30c4\u30ca\u590f\u6642\u9593", "WFST"}},
- {"Pacific/Yap", TRUT},
+ {"Pacific/Yap", CHUT},
{"Poland", CET},
{"PRC", CTT},
{"PST8PDT", PST},
--- a/jdk/src/share/classes/sun/util/resources/TimeZoneNames_ko.java Wed Sep 08 14:04:18 2010 -0700
+++ b/jdk/src/share/classes/sun/util/resources/TimeZoneNames_ko.java Wed Jul 05 17:21:22 2017 +0200
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997, 2008, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2010, 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
@@ -75,6 +75,8 @@
"\uc911\uc559 \uc720\ub7fd \uc77c\uad11\uc808\uc57d\uc2dc\uac04", "CEST"};
String CHAST[] = new String[] {"Chatham \ud45c\uc900\uc2dc", "CHAST",
"Chatham \uc77c\uad11\uc808\uc57d\uc2dc\uac04", "CHADT"};
+ String CHUT[] = new String[] {"Chuuk Time", "CHUT",
+ "Chuuk Summer Time", "CHUST"};
String CIT[] = new String[] {"\uc911\uc559 \uc778\ub3c4\ub124\uc2dc\uc544 \uc2dc\uac04", "CIT",
"\uc911\uc559 \uc778\ub3c4\ub124\uc2dc\uc544 \uc77c\uad11\uc808\uc57d\uc2dc\uac04", "CIST"};
String CLT[] = new String[] {"\uce60\ub808 \uc2dc\uac04", "CLT",
@@ -153,6 +155,8 @@
"Pitcairn \uc77c\uad11\uc808\uc57d\uc2dc\uac04", "PDT"};
String PKT[] = new String[] {"\ud30c\ud0a4\uc2a4\ud0c4 \uc2dc\uac04", "PKT",
"\ud30c\ud0a4\uc2a4\ud0c4 \uc77c\uad11\uc808\uc57d\uc2dc\uac04", "PKST"};
+ String PONT[] = new String[] {"Pohnpei Time", "PONT",
+ "Pohnpei Summer Time", "PONST"};
String PST[] = new String[] {"\ud0dc\ud3c9\uc591 \ud45c\uc900\uc2dc", "PST",
"\ud0dc\ud3c9\uc591 \uc77c\uad11\uc808\uc57d\uc2dc\uac04", "PDT"};
String RST[] = new String[] {"\ub3d9\ubd80 \ud45c\uc900\uc2dc", "EST",
@@ -169,8 +173,6 @@
"\ub3d9\ubd80 \uc77c\uad11\uc808\uc57d\uc2dc\uac04(\ud0dc\uc988\uba54\uc774\ub2c8\uc544)", "EST"};
String TMT[] = new String[] {"\ud22c\ub974\ud06c\uba54\ub2c8\uc2a4\ud0c4 \uc2dc\uac04", "TMT",
"\ud22c\ub974\ud06c\uba54\ub2c8\uc2a4\ud0c4 \uc77c\uad11\uc808\uc57d\uc2dc\uac04", "TMST"};
- String TRUT[] = new String[] {"\ud2b8\ub8e8\ud06c \uc2dc\uac04", "TRUT",
- "\ud2b8\ub8e8\ud06c \uc77c\uad11\uc808\uc57d\uc2dc\uac04", "TRUST"};
String ULAT[]= new String[] {"\uc6b8\ub780\ubc14\ud0c0\ub974 \uc2dc\uac04", "ULAT",
"\uc6b8\ub780\ubc14\ud0c0\ub974 \uc77c\uad11\uc808\uc57d\uc2dc\uac04", "ULAST"};
String WART[] = new String[] {"\uc11c\ubd80 \uc544\ub974\ud5e8\ud2f0\ub098 \uc2dc\uac04", "WART",
@@ -309,6 +311,7 @@
{"America/Atikokan", EST},
{"America/Atka", HAST},
{"America/Bahia", BRT},
+ {"America/Bahia_Banderas", CST},
{"America/Barbados", AST},
{"America/Belem", BRT},
{"America/Belize", CST},
@@ -446,10 +449,13 @@
{"America/Winnipeg", CST},
{"America/Yakutat", AKST},
{"America/Yellowknife", MST},
+ {"Antarctica/Casey", WST_AUS},
{"Antarctica/Davis", new String[] {"Davis \uc2dc\uac04", "DAVT",
"Davis \uc77c\uad11\uc808\uc57d\uc2dc\uac04", "DAVST"}},
{"Antarctica/DumontDUrville", new String[] {"\ub4a4\ubabd \ub4a4\ub974\ube4c \uc2dc\uac04", "DDUT",
"\ub4a4\ubabd \ub4a4\ub974\ube4c \uc77c\uad11\uc808\uc57d\uc2dc\uac04", "DDUST"}},
+ {"Antarctica/Macquarie", new String[] {"Macquarie Island Time", "MIST",
+ "Macquarie Island Summer Time", "MIST"}},
{"Antarctica/Mawson", new String[] {"\ubaa8\uc2a8 \uc2dc\uac04", "MAWT",
"\ubaa8\uc2a8 \uc77c\uad11\uc808\uc57d\uc2dc\uac04", "MAWST"}},
{"Antarctica/McMurdo", NZST},
@@ -752,6 +758,7 @@
{"Pacific/Apia", WST_SAMOA},
{"Pacific/Auckland", NZST},
{"Pacific/Chatham", CHAST},
+ {"Pacific/Chuuk", CHUT},
{"Pacific/Easter", EASTER},
{"Pacific/Efate", new String[] {"\ube44\ub204\uc544\ud22c \uc2dc\uac04", "VUT",
"\ubc14\ub204\uc544\ud22c \uc77c\uad11\uc808\uc57d\uc2dc\uac04", "VUST"}},
@@ -790,8 +797,8 @@
{"Pacific/Palau", new String[] {"\ud314\ub77c\uc6b0 \uc2dc\uac04", "PWT",
"\ud314\ub77c\uc6b0 \uc77c\uad11\uc808\uc57d\uc2dc\uac04", "PWST"}},
{"Pacific/Pitcairn", PITCAIRN},
- {"Pacific/Ponape", new String[] {"\ud3ec\ub098\ud504 \uc2dc\uac04", "PONT",
- "\ud3ec\ub098\ud504 \uc77c\uad11\uc808\uc57d\uc2dc\uac04", "PONST"}},
+ {"Pacific/Pohnpei", PONT},
+ {"Pacific/Ponape", PONT},
{"Pacific/Port_Moresby", new String[] {"\ud30c\ud478\uc544\ub274\uae30\ub2c8 \uc2dc\uac04", "PGT",
"\ud30c\ud478\uc544\ub274\uae30\ub2c8 \uc77c\uad11\uc808\uc57d\uc2dc\uac04", "PGST"}},
{"Pacific/Rarotonga", new String[] {"\ucfe0\ud06c \uad70\ub3c4 \uc2dc\uac04", "CKT",
@@ -804,12 +811,12 @@
"\uae38\ubc84\ud2b8 \uad70\ub3c4 \uc77c\uad11\uc808\uc57d\uc2dc\uac04", "GILST"}},
{"Pacific/Tongatapu", new String[] {"\ud1b5\uac00 \uc2dc\uac04", "TOT",
"\ud1b5\uac00 \uc77c\uad11\uc808\uc57d\uc2dc\uac04", "TOST"}},
- {"Pacific/Truk", TRUT},
+ {"Pacific/Truk", CHUT},
{"Pacific/Wake", new String[] {"\uc6e8\uc774\ud06c \uc2dc\uac04", "WAKT",
"\uc6e8\uc774\ud06c \uc77c\uad11\uc808\uc57d\uc2dc\uac04", "WAKST"}},
{"Pacific/Wallis", new String[] {"\uc6d4\ub9ac\uc2a4 \ud6c4\ud22c\ub098 \uc2dc\uac04", "WFT",
"\uc6d4\ub9ac\uc2a4 \ud6c4\ud2b8\ub098 \uc77c\uad11\uc808\uc57d\uc2dc\uac04", "WFST"}},
- {"Pacific/Yap", TRUT},
+ {"Pacific/Yap", CHUT},
{"Poland", CET},
{"PRC", CTT},
{"PST8PDT", PST},
--- a/jdk/src/share/classes/sun/util/resources/TimeZoneNames_sv.java Wed Sep 08 14:04:18 2010 -0700
+++ b/jdk/src/share/classes/sun/util/resources/TimeZoneNames_sv.java Wed Jul 05 17:21:22 2017 +0200
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997, 2008, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2010, 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
@@ -75,6 +75,8 @@
"Centraleuropeisk sommartid", "CEST"};
String CHAST[] = new String[] {"Chatham, normaltid", "CHAST",
"Chatham, sommartid", "CHADT"};
+ String CHUT[] = new String[] {"Chuuk Time", "CHUT",
+ "Chuuk Summer Time", "CHUST"};
String CIT[] = new String[] {"Centralindonesisk tid", "CIT",
"Centralindonesisk sommartid", "CIST"};
String CLT[] = new String[] {"Chile, normaltid", "CLT",
@@ -153,6 +155,8 @@
"Pitcairn, sommartid", "PDT"};
String PKT[] = new String[] {"Pakistan, normaltid", "PKT",
"Pakistan, sommartid", "PKST"};
+ String PONT[] = new String[] {"Pohnpei Time", "PONT",
+ "Pohnpei Summer Time", "PONST"};
String PST[] = new String[] {"Stilla havet, normaltid", "PST",
"Stilla havet, sommartid", "PDT"};
String RST[] = new String[] {"Eastern, normaltid", "EST",
@@ -169,8 +173,6 @@
"Eastern, sommartid (Tasmanien)", "EST"};
String TMT[] = new String[] {"Turkmenistan, normaltid", "TMT",
"Turkmenistan, sommartid", "TMST"};
- String TRUT[] = new String[] {"Truk, normaltid", "TRUT",
- "Truk, sommartid", "TRUST"};
String ULAT[]= new String[] {"Ulaanbaatar, normaltid", "ULAT",
"Ulaanbaatar, sommartid", "ULAST"};
String WART[] = new String[] {"V\u00e4stargentina, normaltid", "WART",
@@ -309,6 +311,7 @@
{"America/Atikokan", EST},
{"America/Atka", HAST},
{"America/Bahia", BRT},
+ {"America/Bahia_Banderas", CST},
{"America/Barbados", AST},
{"America/Belem", BRT},
{"America/Belize", CST},
@@ -446,10 +449,13 @@
{"America/Winnipeg", CST},
{"America/Yakutat", AKST},
{"America/Yellowknife", MST},
+ {"Antarctica/Casey", WST_AUS},
{"Antarctica/Davis", new String[] {"Davis, normaltid", "DAVT",
"Davis, sommartid", "DAVST"}},
{"Antarctica/DumontDUrville", new String[] {"Dumont-d'Urville, normaltid", "DDUT",
"Dumont-d'Urville, sommartid", "DDUST"}},
+ {"Antarctica/Macquarie", new String[] {"Macquarie Island Time", "MIST",
+ "Macquarie Island Summer Time", "MIST"}},
{"Antarctica/Mawson", new String[] {"Mawson, normaltid", "MAWT",
"Mawson, sommartid", "MAWST"}},
{"Antarctica/McMurdo", NZST},
@@ -752,6 +758,7 @@
{"Pacific/Apia", WST_SAMOA},
{"Pacific/Auckland", NZST},
{"Pacific/Chatham", CHAST},
+ {"Pacific/Chuuk", CHUT},
{"Pacific/Easter", EASTER},
{"Pacific/Efate", new String[] {"Vanuatu, normaltid", "VUT",
"Vanuatu, sommartid", "VUST"}},
@@ -790,8 +797,8 @@
{"Pacific/Palau", new String[] {"Palau, normaltid", "PWT",
"Palau, sommartid", "PWST"}},
{"Pacific/Pitcairn", PITCAIRN},
- {"Pacific/Ponape", new String[] {"Ponape, normaltid", "PONT",
- "Ponape, sommartid", "PONST"}},
+ {"Pacific/Pohnpei", PONT},
+ {"Pacific/Ponape", PONT},
{"Pacific/Port_Moresby", new String[] {"Papua Nya Guinea, normaltid", "PGT",
"Papua Nya Guinea, sommartid", "PGST"}},
{"Pacific/Rarotonga", new String[] {"Cook\u00f6arna, normaltid", "CKT",
@@ -804,12 +811,12 @@
"Gilbert\u00f6arna, sommartid", "GILST"}},
{"Pacific/Tongatapu", new String[] {"Tonga, normaltid", "TOT",
"Tonga, sommartid", "TOST"}},
- {"Pacific/Truk", TRUT},
+ {"Pacific/Truk", CHUT},
{"Pacific/Wake", new String[] {"Wake, normaltid", "WAKT",
"Wake, sommartid", "WAKST"}},
{"Pacific/Wallis", new String[] {"Wallis & Futuna, normaltid", "WFT",
"Wallis & Futuna, sommartid", "WFST"}},
- {"Pacific/Yap", TRUT},
+ {"Pacific/Yap", CHUT},
{"Poland", CET},
{"PRC", CTT},
{"PST8PDT", PST},
--- a/jdk/src/share/classes/sun/util/resources/TimeZoneNames_zh_CN.java Wed Sep 08 14:04:18 2010 -0700
+++ b/jdk/src/share/classes/sun/util/resources/TimeZoneNames_zh_CN.java Wed Jul 05 17:21:22 2017 +0200
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997, 2008, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2010, 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
@@ -75,6 +75,8 @@
"\u4e2d\u6b27\u590f\u4ee4\u65f6", "CEST"};
String CHAST[] = new String[] {"\u67e5\u8428\u59c6\u6807\u51c6\u65f6\u95f4", "CHAST",
"\u67e5\u8428\u59c6\u590f\u4ee4\u65f6", "CHADT"};
+ String CHUT[] = new String[] {"Chuuk Time", "CHUT",
+ "Chuuk Summer Time", "CHUST"};
String CIT[] = new String[] {"\u4e2d\u90e8\u5370\u5ea6\u5c3c\u897f\u4e9a\u65f6\u95f4", "CIT",
"\u4e2d\u90e8\u5370\u5ea6\u5c3c\u897f\u4e9a\u590f\u4ee4\u65f6", "CIST"};
String CLT[] = new String[] {"\u667a\u5229\u65f6\u95f4", "CLT",
@@ -153,6 +155,8 @@
"\u76ae\u7279\u5eb7\u5c9b\u590f\u4ee4\u65f6", "PDT"};
String PKT[] = new String[] {"\u5df4\u57fa\u65af\u5766\u65f6\u95f4", "PKT",
"\u5df4\u57fa\u65af\u5766\u590f\u4ee4\u65f6", "PKST"};
+ String PONT[] = new String[] {"Pohnpei Time", "PONT",
+ "Pohnpei Summer Time", "PONST"};
String PST[] = new String[] {"\u592a\u5e73\u6d0b\u6807\u51c6\u65f6\u95f4", "PST",
"\u592a\u5e73\u6d0b\u590f\u4ee4\u65f6", "PDT"};
String RST[] = new String[] {"\u4e1c\u90e8\u6807\u51c6\u65f6\u95f4", "EST",
@@ -169,8 +173,6 @@
"\u4e1c\u90e8\u590f\u4ee4\u65f6\uff08\u5854\u65af\u9a6c\u5c3c\u4e9a\uff09", "EST"};
String TMT[] = new String[] {"\u571f\u5e93\u66fc\u65f6\u95f4", "TMT",
"\u571f\u5e93\u66fc\u590f\u4ee4\u65f6", "TMST"};
- String TRUT[] = new String[] {"\u7279\u9c81\u514b\u65f6\u95f4", "TRUT",
- "\u7279\u9c81\u514b\u590f\u4ee4\u65f6", "TRUST"};
String ULAT[]= new String[] {"\u5e93\u4f26\u65f6\u95f4", "ULAT",
"\u5e93\u4f26\u590f\u4ee4\u65f6", "ULAST"};
String WART[] = new String[] {"\u897f\u963f\u6839\u5ef7\u65f6\u95f4", "WART",
@@ -309,6 +311,7 @@
{"America/Atikokan", EST},
{"America/Atka", HAST},
{"America/Bahia", BRT},
+ {"America/Bahia_Banderas", CST},
{"America/Barbados", AST},
{"America/Belem", BRT},
{"America/Belize", CST},
@@ -446,10 +449,13 @@
{"America/Winnipeg", CST},
{"America/Yakutat", AKST},
{"America/Yellowknife", MST},
+ {"Antarctica/Casey", WST_AUS},
{"Antarctica/Davis", new String[] {"\u6234\u7ef4\u65af\u65f6\u95f4", "DAVT",
"\u6234\u7ef4\u65af\u590f\u4ee4\u65f6", "DAVST"}},
{"Antarctica/DumontDUrville", new String[] {"Dumont-d'Urville \u65f6\u95f4", "DDUT",
"Dumont-d'Urville \u590f\u4ee4\u65f6", "DDUST"}},
+ {"Antarctica/Macquarie", new String[] {"Macquarie Island Time", "MIST",
+ "Macquarie Island Summer Time", "MIST"}},
{"Antarctica/Mawson", new String[] {"\u83ab\u68ee\u65f6\u95f4", "MAWT",
"\u83ab\u68ee\u590f\u4ee4\u65f6", "MAWST"}},
{"Antarctica/McMurdo", NZST},
@@ -752,6 +758,7 @@
{"Pacific/Apia", WST_SAMOA},
{"Pacific/Auckland", NZST},
{"Pacific/Chatham", CHAST},
+ {"Pacific/Chuuk", CHUT},
{"Pacific/Easter", EASTER},
{"Pacific/Efate", new String[] {"\u74e6\u5974\u963f\u56fe\u65f6\u95f4", "VUT",
"\u74e6\u5974\u963f\u56fe\u590f\u4ee4\u65f6", "VUST"}},
@@ -790,8 +797,8 @@
{"Pacific/Palau", new String[] {"\u5e1b\u7409\u65f6\u95f4", "PWT",
"\u5e1b\u7409\u590f\u4ee4\u65f6", "PWST"}},
{"Pacific/Pitcairn", PITCAIRN},
- {"Pacific/Ponape", new String[] {"Ponape \u65f6\u95f4", "PONT",
- "Ponape \u590f\u4ee4\u65f6", "PONST"}},
+ {"Pacific/Pohnpei", PONT},
+ {"Pacific/Ponape", PONT},
{"Pacific/Port_Moresby", new String[] {"\u5df4\u5e03\u4e9a\u65b0\u51e0\u5185\u4e9a\u65f6\u95f4", "PGT",
"\u5df4\u5e03\u4e9a\u65b0\u51e0\u5185\u4e9a\u590f\u4ee4\u65f6", "PGST"}},
{"Pacific/Rarotonga", new String[] {"\u5e93\u514b\u7fa4\u5c9b\u65f6\u95f4", "CKT",
@@ -804,12 +811,12 @@
"\u5409\u4f2f\u7279\u7fa4\u5c9b\u590f\u4ee4\u65f6", "GILST"}},
{"Pacific/Tongatapu", new String[] {"\u4e1c\u52a0\u65f6\u95f4", "TOT",
"\u4e1c\u52a0\u590f\u4ee4\u65f6", "TOST"}},
- {"Pacific/Truk", TRUT},
+ {"Pacific/Truk", CHUT},
{"Pacific/Wake", new String[] {"\u5a01\u514b\u65f6\u95f4", "WAKT",
"\u5a01\u514b\u590f\u4ee4\u65f6", "WAKST"}},
{"Pacific/Wallis", new String[] {"\u74e6\u5229\u65af\u53ca\u798f\u675c\u7eb3\u7fa4\u5c9b\u65f6\u95f4", "WFT",
"\u74e6\u5229\u65af\u53ca\u798f\u675c\u7eb3\u7fa4\u5c9b\u590f\u4ee4\u65f6", "WFST"}},
- {"Pacific/Yap", TRUT},
+ {"Pacific/Yap", CHUT},
{"Poland", CET},
{"PRC", CTT},
{"PST8PDT", PST},
--- a/jdk/src/share/classes/sun/util/resources/TimeZoneNames_zh_TW.java Wed Sep 08 14:04:18 2010 -0700
+++ b/jdk/src/share/classes/sun/util/resources/TimeZoneNames_zh_TW.java Wed Jul 05 17:21:22 2017 +0200
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997, 2008, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2010, 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
@@ -75,6 +75,8 @@
"\u4e2d\u6b50\u590f\u4ee4\u6642\u9593", "CEST"};
String CHAST[] = new String[] {"\u67e5\u5766\u6a19\u6e96\u6642\u9593", "CHAST",
"\u67e5\u5766\u65e5\u5149\u7bc0\u7d04\u6642\u9593", "CHADT"};
+ String CHUT[] = new String[] {"Chuuk Time", "CHUT",
+ "Chuuk Summer Time", "CHUST"};
String CIT[] = new String[] {"\u4e2d\u5370\u5ea6\u5c3c\u897f\u4e9e\u6642\u9593", "CIT",
"\u4e2d\u5370\u5ea6\u5c3c\u897f\u4e9e\u590f\u4ee4\u6642\u9593", "CIST"};
String CLT[] = new String[] {"\u667a\u5229\u6642\u9593", "CLT",
@@ -153,6 +155,8 @@
"\u76ae\u7279\u5eb7\u65e5\u5149\u7bc0\u7d04\u6642\u9593", "PDT"};
String PKT[] = new String[] {"\u5df4\u57fa\u65af\u5766\u6642\u9593", "PKT",
"\u5df4\u57fa\u65af\u5766\u590f\u4ee4\u6642\u9593", "PKST"};
+ String PONT[] = new String[] {"Pohnpei Time", "PONT",
+ "Pohnpei Summer Time", "PONST"};
String PST[] = new String[] {"\u592a\u5e73\u6d0b\u6a19\u6e96\u6642\u9593", "PST",
"\u592a\u5e73\u6d0b\u65e5\u5149\u7bc0\u7d04\u6642\u9593", "PDT"};
String RST[] = new String[] {"\u6771\u65b9\u6a19\u6e96\u6642\u9593", "EST",
@@ -169,8 +173,6 @@
"\u6771\u90e8\u590f\u4ee4\u6642\u9593 (\u5854\u65af\u6885\u5c3c\u4e9e\u5cf6)", "EST"};
String TMT[] = new String[] {"\u571f\u5eab\u66fc\u6642\u9593", "TMT",
"\u571f\u5eab\u66fc\u590f\u4ee4\u6642\u9593", "TMST"};
- String TRUT[] = new String[] {"\u7279\u9b6f\u514b\u6642\u9593", "TRUT",
- "\u7279\u9b6f\u514b\u590f\u4ee4\u6642\u9593", "TRUST"};
String ULAT[]= new String[] {"\u5eab\u502b\u6642\u9593", "ULAT",
"\u5eab\u502b\u590f\u4ee4\u6642\u9593", "ULAST"};
String WART[] = new String[] {"\u897f\u963f\u6839\u5ef7\u6642\u9593", "WART",
@@ -309,6 +311,7 @@
{"America/Atikokan", EST},
{"America/Atka", HAST},
{"America/Bahia", BRT},
+ {"America/Bahia_Banderas", CST},
{"America/Barbados", AST},
{"America/Belem", BRT},
{"America/Belize", CST},
@@ -446,10 +449,13 @@
{"America/Winnipeg", CST},
{"America/Yakutat", AKST},
{"America/Yellowknife", MST},
+ {"Antarctica/Casey", WST_AUS},
{"Antarctica/Davis", new String[] {"\u81fa\u7dad\u65af\u6642\u9593", "DAVT",
"\u81fa\u7dad\u65af\u590f\u4ee4\u6642\u9593", "DAVST"}},
{"Antarctica/DumontDUrville", new String[] {"Dumont-d'Urville \u6642\u9593", "DDUT",
"Dumont-d'Urville \u590f\u4ee4\u6642\u9593", "DDUST"}},
+ {"Antarctica/Macquarie", new String[] {"Macquarie Island Time", "MIST",
+ "Macquarie Island Summer Time", "MIST"}},
{"Antarctica/Mawson", new String[] {"\u83ab\u68ee\u6642\u9593", "MAWT",
"\u83ab\u68ee\u590f\u4ee4\u6642\u9593", "MAWST"}},
{"Antarctica/McMurdo", NZST},
@@ -753,6 +759,7 @@
{"Pacific/Apia", WST_SAMOA},
{"Pacific/Auckland", NZST},
{"Pacific/Chatham", CHAST},
+ {"Pacific/Chuuk", CHUT},
{"Pacific/Easter", EASTER},
{"Pacific/Efate", new String[] {"\u74e6\u5974\u963f\u5716\u6642\u9593", "VUT",
"\u74e6\u5974\u963f\u5716\u590f\u4ee4\u6642\u9593", "VUST"}},
@@ -791,8 +798,8 @@
{"Pacific/Palau", new String[] {"\u5e1b\u7409\u6642\u9593", "PWT",
"\u5e1b\u7409\u590f\u4ee4\u6642\u9593", "PWST"}},
{"Pacific/Pitcairn", PITCAIRN},
- {"Pacific/Ponape", new String[] {"Ponape \u6642\u9593", "PONT",
- "Ponape \u590f\u4ee4\u6642\u9593", "PONST"}},
+ {"Pacific/Pohnpei", PONT},
+ {"Pacific/Ponape", PONT},
{"Pacific/Port_Moresby", new String[] {"\u5df4\u5e03\u4e9e\u65b0\u5e7e\u5167\u4e9e\u6642\u9593", "PGT",
"\u5df4\u5e03\u4e9e\u65b0\u5e7e\u5167\u4e9e\u590f\u4ee4\u6642\u9593", "PGST"}},
{"Pacific/Rarotonga", new String[] {"\u5eab\u514b\u7fa4\u5cf6\u6642\u9593", "CKT",
@@ -805,12 +812,12 @@
"\u5409\u4f2f\u7279\u7fa4\u5cf6\u590f\u4ee4\u6642\u9593", "GILST"}},
{"Pacific/Tongatapu", new String[] {"\u6771\u52a0\u6642\u9593", "TOT",
"\u6771\u52a0\u590f\u4ee4\u6642\u9593", "TOST"}},
- {"Pacific/Truk", TRUT},
+ {"Pacific/Truk", CHUT},
{"Pacific/Wake", new String[] {"\u5a01\u514b\u6642\u9593", "WAKT",
"\u5a01\u514b\u590f\u4ee4\u6642\u9593", "WAKST"}},
{"Pacific/Wallis", new String[] {"\u74e6\u5229\u65af\u53ca\u798f\u675c\u7d0d\u7fa4\u5cf6\u6642\u9593", "WFT",
"\u74e6\u5229\u65af\u53ca\u798f\u675c\u7d0d\u7fa4\u5cf6\u590f\u4ee4\u6642\u9593", "WFST"}},
- {"Pacific/Yap", TRUT},
+ {"Pacific/Yap", CHUT},
{"Poland", CET},
{"PRC", CTT},
{"PST8PDT", PST},
--- a/jdk/src/share/lib/security/java.security-solaris Wed Sep 08 14:04:18 2010 -0700
+++ b/jdk/src/share/lib/security/java.security-solaris Wed Jul 05 17:21:22 2017 +0200
@@ -260,3 +260,30 @@
# Example,
# ocsp.responderCertSerialNumber=2A:FF:00
+#
+# Policy for failed Kerberos KDC lookups:
+#
+# When a KDC is unavailable (network error, service failure, etc), it is
+# put inside a blacklist and accessed less often for future requests. The
+# value (case-insensitive) for this policy can be:
+#
+# tryLast
+# KDCs in the blacklist are always tried after those not on the list.
+#
+# tryLess[:max_retries,timeout]
+# KDCs in the blacklist are still tried by their order in the configuration,
+# but with smaller max_retries and timeout values. max_retries and timeout
+# are optional numerical parameters (default 1 and 5000, which means once
+# and 5 seconds). Please notes that if any of the values defined here is
+# more than what is defined in krb5.conf, it will be ignored.
+#
+# Whenever a KDC is detected as available, it is removed from the blacklist.
+# The blacklist is reset when krb5.conf is reloaded. You can add
+# refreshKrb5Config=true to a JAAS configuration file so that krb5.conf is
+# reloaded whenever a JAAS authentication is attempted.
+#
+# Example,
+# krb5.kdc.bad.policy = tryLast
+# krb5.kdc.bad.policy = tryLess:2,2000
+krb5.kdc.bad.policy = tryLast
+
--- a/jdk/src/share/lib/security/java.security-windows Wed Sep 08 14:04:18 2010 -0700
+++ b/jdk/src/share/lib/security/java.security-windows Wed Jul 05 17:21:22 2017 +0200
@@ -260,3 +260,30 @@
# Example,
# ocsp.responderCertSerialNumber=2A:FF:00
+#
+# Policy for failed Kerberos KDC lookups:
+#
+# When a KDC is unavailable (network error, service failure, etc), it is
+# put inside a blacklist and accessed less often for future requests. The
+# value (case-insensitive) for this policy can be:
+#
+# tryLast
+# KDCs in the blacklist are always tried after those not on the list.
+#
+# tryLess[:max_retries,timeout]
+# KDCs in the blacklist are still tried by their order in the configuration,
+# but with smaller max_retries and timeout values. max_retries and timeout
+# are optional numerical parameters (default 1 and 5000, which means once
+# and 5 seconds). Please notes that if any of the values defined here is
+# more than what is defined in krb5.conf, it will be ignored.
+#
+# Whenever a KDC is detected as available, it is removed from the blacklist.
+# The blacklist is reset when krb5.conf is reloaded. You can add
+# refreshKrb5Config=true to a JAAS configuration file so that krb5.conf is
+# reloaded whenever a JAAS authentication is attempted.
+#
+# Example,
+# krb5.kdc.bad.policy = tryLast
+# krb5.kdc.bad.policy = tryLess:2,2000
+krb5.kdc.bad.policy = tryLast
+
--- a/jdk/src/share/native/common/check_code.c Wed Sep 08 14:04:18 2010 -0700
+++ b/jdk/src/share/native/common/check_code.c Wed Jul 05 17:21:22 2017 +0200
@@ -2730,7 +2730,10 @@
operand);
const char *result_signature;
check_and_push(context, signature, VM_STRING_UTF);
- result_signature = strchr(signature, JVM_SIGNATURE_ENDFUNC) + 1;
+ result_signature = strchr(signature, JVM_SIGNATURE_ENDFUNC);
+ if (result_signature++ == NULL) {
+ CCerror(context, "Illegal signature %s", signature);
+ }
if (result_signature[0] == JVM_SIGNATURE_VOID) {
stack_results = "";
} else {
@@ -3654,14 +3657,13 @@
const char **signature_p, fullinfo_type *full_info_p)
{
const char *p = *signature_p;
- fullinfo_type full_info = MAKE_FULLINFO(0, 0, 0);
+ fullinfo_type full_info = MAKE_FULLINFO(ITEM_Bogus, 0, 0);
char result;
int array_depth = 0;
for (;;) {
switch(*p++) {
default:
- full_info = MAKE_FULLINFO(ITEM_Bogus, 0, 0);
result = 0;
break;
@@ -3714,7 +3716,14 @@
char buffer_space[256];
char *buffer = buffer_space;
char *finish = strchr(p, JVM_SIGNATURE_ENDCLASS);
- int length = finish - p;
+ int length;
+ if (finish == NULL) {
+ /* Signature must have ';' after the class name.
+ * If it does not, return 0 and ITEM_Bogus in full_info. */
+ result = 0;
+ break;
+ }
+ length = finish - p;
if (length + 1 > (int)sizeof(buffer_space)) {
buffer = malloc(length + 1);
check_and_push(context, buffer, VM_MALLOC_BLK);
--- a/jdk/src/solaris/classes/java/io/UnixFileSystem.java Wed Sep 08 14:04:18 2010 -0700
+++ b/jdk/src/solaris/classes/java/io/UnixFileSystem.java Wed Jul 05 17:21:22 2017 +0200
@@ -187,7 +187,6 @@
}
}
}
- assert canonicalize0(path).equals(res) || path.startsWith(javaHome);
return res;
}
}
--- a/jdk/src/solaris/classes/sun/nio/fs/UnixPath.java Wed Sep 08 14:04:18 2010 -0700
+++ b/jdk/src/solaris/classes/sun/nio/fs/UnixPath.java Wed Jul 05 17:21:22 2017 +0200
@@ -1141,6 +1141,13 @@
}
result = result.resolve(element);
}
+
+ // check file exists (without following links)
+ try {
+ UnixFileAttributes.get(result, false);
+ } catch (UnixException x) {
+ x.rethrowAsIOException(result);
+ }
return result;
}
--- a/jdk/src/solaris/native/java/net/PlainDatagramSocketImpl.c Wed Sep 08 14:04:18 2010 -0700
+++ b/jdk/src/solaris/native/java/net/PlainDatagramSocketImpl.c Wed Jul 05 17:21:22 2017 +0200
@@ -1052,30 +1052,38 @@
Java_java_net_PlainDatagramSocketImpl_datagramSocketCreate(JNIEnv *env,
jobject this) {
jobject fdObj = (*env)->GetObjectField(env, this, pdsi_fdID);
- int fd;
-
- int t = 1;
+ int fd, t = 1;
+#ifdef AF_INET6
+ int domain = ipv6_available() ? AF_INET6 : AF_INET;
+#else
+ int domain = AF_INET;
+#endif
if (IS_NULL(fdObj)) {
JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
"Socket closed");
return;
- } else {
-#ifdef AF_INET6
- if (ipv6_available()) {
- fd = JVM_Socket(AF_INET6, SOCK_DGRAM, 0);
- } else
-#endif /* AF_INET6 */
- {
- fd = JVM_Socket(AF_INET, SOCK_DGRAM, 0);
- }
}
- if (fd == JVM_IO_ERR) {
+
+ if ((fd = JVM_Socket(domain, SOCK_DGRAM, 0)) == JVM_IO_ERR) {
NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException",
"Error creating socket");
return;
}
+#ifdef AF_INET6
+ /* Disable IPV6_V6ONLY to ensure dual-socket support */
+ if (domain == AF_INET6) {
+ int arg = 0;
+ if (setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, (char*)&arg,
+ sizeof(int)) < 0) {
+ NET_ThrowNew(env, errno, "cannot set IPPROTO_IPV6");
+ close(fd);
+ return;
+ }
+ }
+#endif /* AF_INET6 */
+
setsockopt(fd, SOL_SOCKET, SO_BROADCAST, (char*) &t, sizeof(int));
#ifdef __linux__
@@ -1088,7 +1096,7 @@
* On Linux for IPv6 sockets we must set the hop limit
* to 1 to be compatible with default ttl of 1 for IPv4 sockets.
*/
- if (ipv6_available()) {
+ if (domain == AF_INET6) {
int ttl = 1;
setsockopt(fd, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, (char *)&ttl,
sizeof(ttl));
--- a/jdk/src/solaris/native/java/net/PlainSocketImpl.c Wed Sep 08 14:04:18 2010 -0700
+++ b/jdk/src/solaris/native/java/net/PlainSocketImpl.c Wed Jul 05 17:21:22 2017 +0200
@@ -181,6 +181,12 @@
jboolean stream) {
jobject fdObj, ssObj;
int fd;
+ int type = (stream ? SOCK_STREAM : SOCK_DGRAM);
+#ifdef AF_INET6
+ int domain = ipv6_available() ? AF_INET6 : AF_INET;
+#else
+ int domain = AF_INET;
+#endif
if (socketExceptionCls == NULL) {
jclass c = (*env)->FindClass(env, "java/net/SocketException");
@@ -194,25 +200,29 @@
(*env)->ThrowNew(env, socketExceptionCls, "null fd object");
return;
}
-#ifdef AF_INET6
- if (ipv6_available()) {
- fd = JVM_Socket(AF_INET6, (stream ? SOCK_STREAM: SOCK_DGRAM), 0);
- } else
-#endif /* AF_INET6 */
- {
- fd = JVM_Socket(AF_INET, (stream ? SOCK_STREAM: SOCK_DGRAM), 0);
- }
- if (fd == JVM_IO_ERR) {
+
+ if ((fd = JVM_Socket(domain, type, 0)) == JVM_IO_ERR) {
/* note: if you run out of fds, you may not be able to load
* the exception class, and get a NoClassDefFoundError
* instead.
*/
NET_ThrowNew(env, errno, "can't create socket");
return;
- } else {
- (*env)->SetIntField(env, fdObj, IO_fd_fdID, fd);
}
+#ifdef AF_INET6
+ /* Disable IPV6_V6ONLY to ensure dual-socket support */
+ if (domain == AF_INET6) {
+ int arg = 0;
+ if (setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, (char*)&arg,
+ sizeof(int)) < 0) {
+ NET_ThrowNew(env, errno, "cannot set IPPROTO_IPV6");
+ close(fd);
+ return;
+ }
+ }
+#endif /* AF_INET6 */
+
/*
* If this is a server socket then enable SO_REUSEADDR
* automatically and set to non blocking.
@@ -221,9 +231,15 @@
if (ssObj != NULL) {
int arg = 1;
SET_NONBLOCKING(fd);
- JVM_SetSockOpt(fd, SOL_SOCKET, SO_REUSEADDR, (char*)&arg,
- sizeof(arg));
+ if (JVM_SetSockOpt(fd, SOL_SOCKET, SO_REUSEADDR, (char*)&arg,
+ sizeof(arg)) < 0) {
+ NET_ThrowNew(env, errno, "cannot set SO_REUSEADDR");
+ close(fd);
+ return;
+ }
}
+
+ (*env)->SetIntField(env, fdObj, IO_fd_fdID, fd);
}
/*
--- a/jdk/src/solaris/native/sun/nio/ch/Net.c Wed Sep 08 14:04:18 2010 -0700
+++ b/jdk/src/solaris/native/sun/nio/ch/Net.c Wed Jul 05 17:21:22 2017 +0200
@@ -170,6 +170,22 @@
if (fd < 0) {
return handleSocketError(env, errno);
}
+
+#ifdef AF_INET6
+ /* Disable IPV6_V6ONLY to ensure dual-socket support */
+ if (domain == AF_INET6) {
+ int arg = 0;
+ if (setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, (char*)&arg,
+ sizeof(int)) < 0) {
+ JNU_ThrowByNameWithLastError(env,
+ JNU_JAVANETPKG "SocketException",
+ "sun.nio.ch.Net.setIntOption");
+ close(fd);
+ return -1;
+ }
+ }
+#endif
+
if (reuse) {
int arg = 1;
if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char*)&arg,
--- a/jdk/src/windows/classes/java/io/Win32FileSystem.java Wed Sep 08 14:04:18 2010 -0700
+++ b/jdk/src/windows/classes/java/io/Win32FileSystem.java Wed Jul 05 17:21:22 2017 +0200
@@ -424,7 +424,6 @@
}
}
}
- assert canonicalize0(path).equalsIgnoreCase(res);
return res;
}
}
--- a/jdk/test/java/lang/ClassLoader/deadlock/TestCrossDelegate.sh Wed Sep 08 14:04:18 2010 -0700
+++ b/jdk/test/java/lang/ClassLoader/deadlock/TestCrossDelegate.sh Wed Jul 05 17:21:22 2017 +0200
@@ -55,7 +55,7 @@
Linux )
FS="/"
;;
- Windows* )
+ Windows* | CYGWIN* )
FS="\\"
;;
esac
--- a/jdk/test/java/net/URI/Test.java Wed Sep 08 14:04:18 2010 -0700
+++ b/jdk/test/java/net/URI/Test.java Wed Jul 05 17:21:22 2017 +0200
@@ -1536,6 +1536,7 @@
serial();
urls();
npes();
+ bugs();
}
@@ -1572,6 +1573,19 @@
}
+ // miscellaneous bugs/rfes that don't fit in with the test framework
+
+ static void bugs() {
+ // 6339649 - include detail message from nested exception
+ try {
+ URI uri = URI.create("http://nowhere.net/should not be permitted");
+ } catch (IllegalArgumentException e) {
+ if ("".equals(e.getMessage()) || e.getMessage() == null) {
+ throw new RuntimeException ("No detail message");
+ }
+ }
+ }
+
public static void main(String[] args) throws Exception {
switch (args.length) {
--- a/jdk/test/java/nio/file/Path/Misc.java Wed Sep 08 14:04:18 2010 -0700
+++ b/jdk/test/java/nio/file/Path/Misc.java Wed Jul 05 17:21:22 2017 +0200
@@ -261,6 +261,21 @@
assertTrue(file.toRealPath(true).isSameFile(file.toRealPath(false)));
/**
+ * Test: toRealPath should fail if file does not exist
+ */
+ Path doesNotExist = dir.resolve("DoesNotExist");
+ try {
+ doesNotExist.toRealPath(true);
+ throw new RuntimeException("IOException expected");
+ } catch (IOException expected) {
+ }
+ try {
+ doesNotExist.toRealPath(false);
+ throw new RuntimeException("IOException expected");
+ } catch (IOException expected) {
+ }
+
+ /**
* Test: toRealPath(true) should resolve links
*/
if (supportsLinks) {
--- a/jdk/test/sun/jvmstat/monitor/MonitoredVm/MonitorVmStartTerminate.sh Wed Sep 08 14:04:18 2010 -0700
+++ b/jdk/test/sun/jvmstat/monitor/MonitoredVm/MonitorVmStartTerminate.sh Wed Jul 05 17:21:22 2017 +0200
@@ -23,6 +23,7 @@
#
# @test
+# @ignore until 6543856 is fixed
# @bug 4990825
# @summary attach to external but local JVM processes
# @library ../../testlibrary
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/sun/net/www/protocol/file/DirPermissionDenied.java Wed Jul 05 17:21:22 2017 +0200
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+import java.net.URL;
+import java.net.URLConnection;
+import java.io.IOException;
+
+public class DirPermissionDenied {
+ public static void main(String[] args) throws Exception {
+ URL url = new URL("file:" + args[0]);
+
+ try {
+ URLConnection uc = url.openConnection();
+ uc.connect();
+ } catch (IOException e) {
+ // OK
+ } catch (Exception e) {
+ throw new RuntimeException("Failed " + e);
+ }
+
+ try {
+ URLConnection uc = url.openConnection();
+ uc.getInputStream();
+ } catch (IOException e) {
+ // OK
+ } catch (Exception e) {
+ throw new RuntimeException("Failed " + e);
+ }
+
+ try {
+ URLConnection uc = url.openConnection();
+ uc.getContentLengthLong();
+ } catch (IOException e) {
+ // OK
+ } catch (Exception e) {
+ throw new RuntimeException("Failed " + e);
+ }
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/sun/net/www/protocol/file/DirPermissionDenied.sh Wed Jul 05 17:21:22 2017 +0200
@@ -0,0 +1,41 @@
+#
+# Copyright (c) 2010, 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 6977851
+# @summary NPE from FileURLConnection.connect
+# @build DirPermissionDenied
+# @run shell DirPermissionDenied.sh
+
+TESTDIR="${TESTCLASSES}/DirPermissionDeniedDirectory"
+echo ${TESTDIR}
+
+rm -rf ${TESTDIR}
+mkdir -p ${TESTDIR}
+chmod 333 ${TESTDIR}
+
+$TESTJAVA/bin/java -classpath $TESTCLASSES DirPermissionDenied ${TESTDIR}
+result=$?
+rm -rf ${TESTDIR}
+exit $result
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/sun/security/krb5/BadKdcDefaultValue.java Wed Jul 05 17:21:22 2017 +0200
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2010, 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 6976536
+ * @summary Solaris JREs do not have the krb5.kdc.bad.policy configured by default.
+ * @run main/othervm BadKdcDefaultValue
+ */
+
+import java.security.Security;
+
+public class BadKdcDefaultValue {
+ public static void main(String[] args) throws Exception {
+ if (!"tryLast".equalsIgnoreCase(
+ Security.getProperty("krb5.kdc.bad.policy"))) {
+ throw new Exception("Default value not correct");
+ }
+ }
+}
+
--- a/jdk/test/sun/security/ssl/sun/net/www/protocol/https/HttpsURLConnection/B6226610.java Wed Sep 08 14:04:18 2010 -0700
+++ b/jdk/test/sun/security/ssl/sun/net/www/protocol/https/HttpsURLConnection/B6226610.java Wed Jul 05 17:21:22 2017 +0200
@@ -23,7 +23,7 @@
/*
* @test
- * @bug 6226610
+ * @bug 6226610 6973030
* @run main/othervm B6226610
* @summary HTTP tunnel connections send user headers to proxy
*/
@@ -36,45 +36,23 @@
import java.io.*;
import java.net.*;
-import javax.net.ssl.*;
-import javax.net.ServerSocketFactory;
-import sun.net.www.*;
-import java.util.Enumeration;
+import sun.net.www.MessageHeader;
public class B6226610 {
static HeaderCheckerProxyTunnelServer proxy;
- // it seems there's no proxy ever if a url points to 'localhost',
- // even if proxy related properties are set. so we need to bind
- // our simple http proxy and http server to a non-loopback address
- static InetAddress firstNonLoAddress = null;
-
- public static void main(String[] args)
+ public static void main(String[] args) throws Exception
{
- try {
- proxy = new HeaderCheckerProxyTunnelServer();
- proxy.start();
- } catch (Exception e) {
- System.out.println("Cannot create proxy: " + e);
- }
+ proxy = new HeaderCheckerProxyTunnelServer();
+ proxy.start();
- try {
- firstNonLoAddress = getNonLoAddress();
-
- if (firstNonLoAddress == null) {
- System.out.println("The test needs at least one non-loopback address to run. Quit now.");
- System.exit(0);
- }
- } catch (Exception e) {
- e.printStackTrace();
- }
-
- System.setProperty( "https.proxyHost", firstNonLoAddress.getHostAddress());
- System.setProperty( "https.proxyPort", (new Integer(proxy.getLocalPort())).toString() );
+ String hostname = InetAddress.getLocalHost().getHostName();
try {
- URL u = new URL("https://" + firstNonLoAddress.getHostAddress());
- java.net.URLConnection c = u.openConnection();
+ URL u = new URL("https://" + hostname + "/");
+ System.out.println("Connecting to " + u);
+ InetSocketAddress proxyAddr = new InetSocketAddress(hostname, proxy.getLocalPort());
+ java.net.URLConnection c = u.openConnection(new Proxy(Proxy.Type.HTTP, proxyAddr));
/* I want this header to go to the destination server only, protected
* by SSL
@@ -89,33 +67,15 @@
}
else
System.out.println(e);
-
+ } finally {
+ if (proxy != null) proxy.shutdown();
}
if (HeaderCheckerProxyTunnelServer.failed)
- throw new RuntimeException("Test failed: Proxy should not receive user defined headers for tunneled requests");
+ throw new RuntimeException("Test failed; see output");
}
-
- public static InetAddress getNonLoAddress() throws Exception {
- NetworkInterface loNIC = NetworkInterface.getByInetAddress(InetAddress.getByName("localhost"));
- Enumeration<NetworkInterface> nics = NetworkInterface.getNetworkInterfaces();
- while (nics.hasMoreElements()) {
- NetworkInterface nic = nics.nextElement();
- if (!nic.getName().equalsIgnoreCase(loNIC.getName())) {
- Enumeration<InetAddress> addrs = nic.getInetAddresses();
- while (addrs.hasMoreElements()) {
- InetAddress addr = addrs.nextElement();
- if (!addr.isLoopbackAddress())
- return addr;
- }
- }
- }
- return null;
- }
-
}
-
class HeaderCheckerProxyTunnelServer extends Thread
{
public static boolean failed = false;
@@ -139,6 +99,10 @@
}
}
+ void shutdown() {
+ try { ss.close(); } catch (IOException e) {}
+ }
+
public void run()
{
try {
@@ -178,6 +142,15 @@
retrieveConnectInfo(statusLine);
if (mheader.findValue("X-TestHeader") != null) {
+ System.out.println("Proxy should not receive user defined headers for tunneled requests");
+ failed = true;
+ }
+
+ // 6973030
+ String value;
+ if ((value = mheader.findValue("Proxy-Connection")) == null ||
+ !value.equals("keep-alive")) {
+ System.out.println("Proxy-Connection:keep-alive not being sent");
failed = true;
}
--- a/jdk/test/tools/jar/JarEntryTime.java Wed Sep 08 14:04:18 2010 -0700
+++ b/jdk/test/tools/jar/JarEntryTime.java Wed Jul 05 17:21:22 2017 +0200
@@ -23,7 +23,7 @@
/**
* @test
- * @bug 4225317
+ * @bug 4225317 6969651
* @summary Check extracted files have date as per those in the .jar file
*/
@@ -68,17 +68,9 @@
}
public static void realMain(String[] args) throws Throwable {
- final long now = System.currentTimeMillis();
- final long earlier = now - (60L * 60L * 6L * 1000L);
- final long yesterday = now - (60L * 60L * 24L * 1000L);
-
- // ZipEntry's mod date has 2 seconds precision: give extra time to
- // allow for e.g. rounding/truncation and networked/samba drives.
- final long PRECISION = 10000L;
File dirOuter = new File("outer");
File dirInner = new File(dirOuter, "inner");
-
File jarFile = new File("JarEntryTime.jar");
// Remove any leftovers from prior run
@@ -99,6 +91,17 @@
PrintWriter pw = new PrintWriter(fileInner);
pw.println("hello, world");
pw.close();
+
+ // Get the "now" from the "last-modified-time" of the last file we
+ // just created, instead of the "System.currentTimeMillis()", to
+ // workaround the possible "time difference" due to nfs.
+ final long now = fileInner.lastModified();
+ final long earlier = now - (60L * 60L * 6L * 1000L);
+ final long yesterday = now - (60L * 60L * 24L * 1000L);
+ // ZipEntry's mod date has 2 seconds precision: give extra time to
+ // allow for e.g. rounding/truncation and networked/samba drives.
+ final long PRECISION = 10000L;
+
dirOuter.setLastModified(now);
dirInner.setLastModified(yesterday);
fileInner.setLastModified(earlier);
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/tools/pack200/CommandLineTests.java Wed Jul 05 17:21:22 2017 +0200
@@ -0,0 +1,179 @@
+/*
+ * Copyright (c) 2007, 2010 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 CommandLineTests.sh
+ * @bug 6521334 6965836 6965836
+ * @compile -XDignore.symbol.file CommandLineTests.java Pack200Test.java
+ * @run main/timeout=1200 CommandLineTests
+ * @summary An ad hoc test to verify the behavior of pack200/unpack200 CLIs,
+ * and a simulation of pack/unpacking in the install repo.
+ * @author ksrini
+ */
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.PrintStream;
+import java.util.ArrayList;
+import java.util.List;
+/*
+ * We try a potpouri of things ie. we have pack.conf to setup some
+ * options as well as a couple of command line options. We also test
+ * the packing and unpacking mechanism using the Java APIs. This also
+ * simulates pack200 the install workspace, noting that this is a simulation
+ * and can only test jars that are guaranteed to be available, also the
+ * configuration may not be in sync with the installer workspace.
+ */
+
+public class CommandLineTests {
+ private static final File CWD = new File(".");
+ private static final File EXP_SDK = new File(CWD, "exp-sdk-image");
+ private static final File EXP_SDK_LIB_DIR = new File(EXP_SDK, "lib");
+ private static final File EXP_SDK_BIN_DIR = new File(EXP_SDK, "bin");
+ private static final File EXP_JRE_DIR = new File(EXP_SDK, "jre");
+ private static final File EXP_JRE_LIB_DIR = new File(EXP_JRE_DIR, "lib");
+ private static final File RtJar = new File(EXP_JRE_LIB_DIR, "rt.jar");
+ private static final File CharsetsJar = new File(EXP_JRE_LIB_DIR, "charsets.jar");
+ private static final File JsseJar = new File(EXP_JRE_LIB_DIR, "jsse.jar");
+ private static final File ToolsJar = new File(EXP_SDK_LIB_DIR, "tools.jar");
+ private static final File javaCmd;
+ private static final File javacCmd;
+ private static final File ConfigFile = new File("pack.conf");
+ private static final List<File> jarList;
+
+ static {
+ javaCmd = Utils.IsWindows
+ ? new File(EXP_SDK_BIN_DIR, "java.exe")
+ : new File(EXP_SDK_BIN_DIR, "java");
+
+ javacCmd = Utils.IsWindows
+ ? new File(EXP_SDK_BIN_DIR, "javac.exe")
+ : new File(EXP_SDK_BIN_DIR, "javac");
+
+ jarList = new ArrayList<File>();
+ jarList.add(RtJar);
+ jarList.add(CharsetsJar);
+ jarList.add(JsseJar);
+ jarList.add(ToolsJar);
+ }
+
+ // init test area with a copy of the sdk
+ static void init() throws IOException {
+ Utils.recursiveCopy(Utils.JavaSDK, EXP_SDK);
+ creatConfigFile();
+ }
+
+ // Hopefully, this should be kept in sync with what the installer does.
+ static void creatConfigFile() throws IOException {
+ FileOutputStream fos = null;
+ PrintStream ps = null;
+ try {
+ fos = new FileOutputStream(ConfigFile);
+ ps = new PrintStream(fos);
+ ps.println("com.sun.java.util.jar.pack.debug.verbose=0");
+ ps.println("pack.modification.time=keep");
+ ps.println("pack.keep.class.order=true");
+ ps.println("pack.deflate.hint=false");
+ // Fail the build, if new or unknown attributes are introduced.
+ ps.println("pack.unknown.attribute=error");
+ ps.println("pack.segment.limit=-1");
+ // BugId: 6328502, These files will be passed-through as-is.
+ ps.println("pack.pass.file.0=java/lang/Error.class");
+ ps.println("pack.pass.file.1=java/lang/LinkageError.class");
+ ps.println("pack.pass.file.2=java/lang/Object.class");
+ ps.println("pack.pass.file.3=java/lang/Throwable.class");
+ ps.println("pack.pass.file.4=java/lang/VerifyError.class");
+ ps.println("pack.pass.file.5=com/sun/demo/jvmti/hprof/Tracker.class");
+ } finally {
+ Utils.close(ps);
+ Utils.close(fos);
+ }
+ }
+
+ static void runPack200(boolean jre) throws IOException {
+ List<String> cmdsList = new ArrayList<String>();
+ for (File f : jarList) {
+ if (jre && f.getName().equals("tools.jar")) {
+ continue; // need not worry about tools.jar for JRE
+ }
+ // make a backup copy for re-use
+ File bakFile = new File(f.getName() + ".bak");
+ if (!bakFile.exists()) { // backup
+ Utils.copyFile(f.getAbsoluteFile(), bakFile.getAbsoluteFile());
+ } else { // restore
+ Utils.copyFile(bakFile.getAbsoluteFile(), f.getAbsoluteFile());
+ }
+ cmdsList.clear();
+ cmdsList.add(Utils.getPack200Cmd());
+ cmdsList.add("-J-esa");
+ cmdsList.add("-J-ea");
+ cmdsList.add(Utils.Is64Bit ? "-J-Xmx1g" : "-J-Xmx512m");
+ cmdsList.add("--repack");
+ cmdsList.add("--config-file=" + ConfigFile.getAbsolutePath());
+ if (jre) {
+ cmdsList.add("--strip-debug");
+ }
+ // NOTE: commented until 6965836 is fixed
+ // cmdsList.add("--code-attribute=StackMapTable=strip");
+ cmdsList.add(f.getAbsolutePath());
+ Utils.runExec(cmdsList);
+ }
+ }
+
+ static void testJRE() throws IOException {
+ runPack200(true);
+ // the speciment JRE
+ List<String> cmdsList = new ArrayList<String>();
+ cmdsList.add(javaCmd.getAbsolutePath());
+ cmdsList.add("-verify");
+ cmdsList.add("-version");
+ Utils.runExec(cmdsList);
+ }
+
+ static void testJDK() throws IOException {
+ runPack200(false);
+ // test the specimen JDK
+ List<String> cmdsList = new ArrayList<String>();
+ cmdsList.add(javaCmd.getAbsolutePath());
+ cmdsList.add("-verify");
+ cmdsList.add("-version");
+ Utils.runExec(cmdsList);
+
+ // invoke javac to test the tools.jar
+ cmdsList.clear();
+ cmdsList.add(javacCmd.getAbsolutePath());
+ cmdsList.add("-J-verify");
+ cmdsList.add("-help");
+ Utils.runExec(cmdsList);
+ }
+ public static void main(String... args) {
+ try {
+ init();
+ testJRE();
+ testJDK();
+ } catch (IOException ioe) {
+ throw new RuntimeException(ioe);
+ }
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/tools/pack200/Pack200Props.java Wed Jul 05 17:21:22 2017 +0200
@@ -0,0 +1,128 @@
+/*
+ * Copyright (c) 2010, 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 6575373 6969063
+ * @summary verify default properties of the packer/unpacker and segment limit
+ * @compile -XDignore.symbol.file Utils.java Pack200Props.java
+ * @run main Pack200Props
+ * @author ksrini
+ */
+
+import java.io.File;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.jar.Pack200;
+import java.util.jar.Pack200.Packer;
+
+/*
+ * Run this against a large jar file, by default the packer should generate only
+ * one segment, parse the output of the packer to verify if this is indeed true.
+ */
+
+public class Pack200Props {
+
+ public static void main(String... args) {
+ verifyDefaults();
+ File out = new File("test" + Utils.PACK_FILE_EXT);
+ out.delete();
+ verifySegmentLimit(out);
+ }
+
+ static void verifySegmentLimit(File outFile) {
+ File sdkHome = Utils.JavaSDK;
+ File testJar = new File(new File(sdkHome, "lib"), "tools.jar");
+
+ System.out.println("using pack200: " + Utils.getPack200Cmd());
+
+ List<String> cmdsList = new ArrayList<>();
+ cmdsList.add(Utils.getPack200Cmd());
+ cmdsList.add("--effort=1");
+ cmdsList.add("--verbose");
+ cmdsList.add("--no-gzip");
+ cmdsList.add(outFile.getName());
+ cmdsList.add(testJar.getAbsolutePath());
+ List<String> outList = Utils.runExec(cmdsList);
+
+ int count = 0;
+ for (String line : outList) {
+ System.out.println(line);
+ if (line.matches(".*Transmitted.*files of.*input bytes in a segment of.*bytes")) {
+ count++;
+ }
+ }
+ if (count == 0) {
+ throw new RuntimeException("no segments or no output ????");
+ } else if (count > 1) {
+ throw new RuntimeException("multiple segments detected, expected 1");
+ }
+ }
+
+ private static void verifyDefaults() {
+ Map<String, String> expectedDefaults = new HashMap<>();
+ Packer p = Pack200.newPacker();
+ expectedDefaults.put("com.sun.java.util.jar.pack.default.timezone",
+ p.FALSE);
+ expectedDefaults.put("com.sun.java.util.jar.pack.disable.native",
+ p.FALSE);
+ expectedDefaults.put("com.sun.java.util.jar.pack.verbose", "0");
+ expectedDefaults.put(p.CLASS_ATTRIBUTE_PFX + "CompilationID", "RUH");
+ expectedDefaults.put(p.CLASS_ATTRIBUTE_PFX + "SourceID", "RUH");
+ expectedDefaults.put(p.CODE_ATTRIBUTE_PFX + "CharacterRangeTable",
+ "NH[PHPOHIIH]");
+ expectedDefaults.put(p.CODE_ATTRIBUTE_PFX + "CoverageTable",
+ "NH[PHHII]");
+ expectedDefaults.put(p.DEFLATE_HINT, p.KEEP);
+ expectedDefaults.put(p.EFFORT, "5");
+ expectedDefaults.put(p.KEEP_FILE_ORDER, p.TRUE);
+ expectedDefaults.put(p.MODIFICATION_TIME, p.KEEP);
+ expectedDefaults.put(p.SEGMENT_LIMIT, "-1");
+ expectedDefaults.put(p.UNKNOWN_ATTRIBUTE, p.PASS);
+
+ Map<String, String> props = p.properties();
+ int errors = 0;
+ for (String key : expectedDefaults.keySet()) {
+ String def = expectedDefaults.get(key);
+ String x = props.get(key);
+ if (x == null) {
+ System.out.println("Error: key not found:" + key);
+ errors++;
+ } else {
+ if (!def.equals(x)) {
+ System.out.println("Error: key " + key
+ + "\n value expected: " + def
+ + "\n value obtained: " + x);
+ errors++;
+ }
+ }
+ }
+ if (errors > 0) {
+ throw new RuntimeException(errors +
+ " error(s) encountered in default properties verification");
+ }
+ }
+}
+
--- a/jdk/test/tools/pack200/Pack200Simple.sh Wed Sep 08 14:04:18 2010 -0700
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,197 +0,0 @@
-#
-# Copyright (c) 2003, 2007, 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 Pack200Simple.sh
-# @bug 6521334
-# @build Pack200Test
-# @run shell/timeout=1200 Pack200Simple.sh
-# @summary An ad hoc test to verify class-file format.
-# @author Kumar Srinivasan
-
-# The goal of this test is to assist javac or other developers
-# who modify class file formats, to quickly test those modifications
-# without having to build the install workspace. However it must
-# be noted that building the install workspace is the only know
-# way to prevent build breakages.
-
-# Pack200 developers could use this as a basic smoke-test, however
-# please note, there are other more elaborate and thorough tests for
-# this very purpose.
-
-# We try a potpouri of things ie. we have pack.conf to setup some
-# options as well as a couple of command line options. We also test
-# the packing and unpacking mechanism using the Java APIs.
-
-# print error and exit with a message
-errorOut() {
- if [ "x$1" = "x" ]; then
- printf "Error: Unknown error\n"
- else
- printf "Error: %s\n" "$1"
- fi
-
- exit 1
-}
-
-# Verify directory context variables are set
-if [ "${TESTJAVA}" = "" ]; then
- errorOut "TESTJAVA not set. Test cannot execute. Failed."
-fi
-
-if [ "${TESTSRC}" = "" ]; then
- errorOut "TESTSRC not set. Test cannot execute. Failed."
-fi
-
-
-if [ "${TESTCLASSES}" = "" ]; then
- errorOut "TESTCLASSES not set. Test cannot execute. Failed."
-fi
-
-# The common java utils we need
-PACK200=${TESTJAVA}/bin/pack200
-UNPACK200=${TESTJAVA}/bin/unpack200
-JAR=${TESTJAVA}/bin/jar
-
-# For Windows and Linux needs the heap to be set, for others ergonomics
-# will do the rest. It is important to use ea, which can expose class
-# format errors much earlier than later.
-
-OS=`uname -s`
-
-
-case "$OS" in
- Windows*|CYGWIN* )
- PackOptions="-J-Xmx512m -J-ea"
- break
- ;;
-
- Linux )
- PackOptions="-J-Xmx512m -J-ea"
- break
- ;;
-
- * )
- PackOptions="-J-ea"
- ;;
-esac
-
-# Creates a packfile of choice expects 1 argument the filename
-createConfigFile() {
- # optimize for speed
- printf "pack.effort=1\n" > $1
- # we DO want to know about new attributes
- printf "pack.unknown.attribute=error\n" >> $1
- # optimize for speed
- printf "pack.deflate.hint=false\n" >> $1
- # keep the ordering for easy compare
- printf "pack.keep.class.order=true\n" >> $1
-}
-
-
-# Tests a given jar, expects 1 argument the fully qualified
-# name to a test jar, it writes all output to the current
-# directory which is a scratch area.
-testAJar() {
- PackConf="pack.conf"
- createConfigFile $PackConf
-
- # Try some command line options
- CLIPackOptions="$PackOptions -v --no-gzip --segment-limit=10000 --config-file=$PackConf"
-
- jfName=`basename $1`
-
- ${PACK200} $CLIPackOptions ${jfName}.pack $1 > ${jfName}.pack.log 2>&1
- if [ $? != 0 ]; then
- errorOut "$jfName packing failed"
- fi
-
- # We want to test unpack200, therefore we dont use -r with pack
- ${UNPACK200} -v ${jfName}.pack $jfName > ${jfName}.unpack.log 2>&1
- if [ $? != 0 ]; then
- errorOut "$jfName unpacking failed"
- fi
-
- # A quick crc compare test to ensure a well formed zip
- # archive, this is a critical unpack200 behaviour.
-
- unzip -t $jfName > ${jfName}.unzip.log 2>&1
- if [ $? != 0 ]; then
- errorOut "$jfName unzip -t test failed"
- fi
-
- # The PACK200 signature should be at the top of the log
- # this tag is critical for deployment related tools.
-
- head -5 ${jfName}.unzip.log | grep PACK200 > /dev/null 2>&1
- if [ $? != 0 ]; then
- errorOut "$jfName PACK200 signature missing"
- fi
-
-
- # we know the size fields don't match, strip 'em out, its
- # extremely important to ensure that the date stamps match up.
- # Don't EVER sort the output we are checking for correct ordering.
-
- ${JAR} -tvf $1 | sed -e 's/^ *[0-9]* //g'> ${jfName}.ref.txt
- ${JAR} -tvf $jfName | sed -e 's/^ *[0-9]* //g'> ${jfName}.cmp.txt
-
- diff ${jfName}.ref.txt ${jfName}.cmp.txt > ${jfName}.diff.log 2>&1
- if [ $? != 0 ]; then
- errorOut "$jfName files missing"
- fi
-}
-
-# These JARs are the largest and also the most likely specimens to
-# expose class format issues and stress the packer as well.
-
-JLIST="${TESTJAVA}/lib/tools.jar ${TESTJAVA}/jre/lib/rt.jar"
-
-
-# Test the Command Line Interfaces (CLI).
-mkdir cliTestDir
-_pwd=`pwd`
-cd cliTestDir
-
-for jarfile in $JLIST ; do
- if [ -f $jarfile ]; then
- testAJar $jarfile
- else
- errorOut "Error: '$jarFile' does not exist\nTest requires a j2sdk-image\n"
- fi
-done
-cd $_pwd
-
-# Test the Java APIs.
-mkdir apiTestDir
-_pwd=`pwd`
-cd apiTestDir
-
-# Strip out the -J prefixes.
-JavaPackOptions=`printf %s "$PackOptions" | sed -e 's/-J//g'`
-
-# Test the Java APIs now.
-$TESTJAVA/bin/java $JavaPackOptions -cp $TESTCLASSES Pack200Test $JLIST || exit 1
-
-cd $_pwd
-
-exit 0
--- a/jdk/test/tools/pack200/Pack200Test.java Wed Sep 08 14:04:18 2010 -0700
+++ b/jdk/test/tools/pack200/Pack200Test.java Wed Jul 05 17:21:22 2017 +0200
@@ -24,111 +24,97 @@
import java.util.*;
import java.io.*;
+import java.lang.management.ManagementFactory;
+import java.lang.management.MemoryMXBean;
import java.util.jar.*;
-import java.util.zip.*;
-/*
- * Pack200Test.java
- *
- * @author ksrini
- */
+ /*
+ * @test
+ * @bug 6521334 6712743
+ * @summary check for memory leaks, test general packer/unpacker functionality\
+ * using native and java unpackers
+ * @compile -XDignore.symbol.file Utils.java Pack200Test.java
+ * @run main/othervm/timeout=1200 -Xmx512m Pack200Test
+ * @author ksrini
+ */
/**
- * These tests are very rudimentary smoke tests to ensure that the packing
- * unpacking process works on a select set of JARs.
+ * Tests the packing/unpacking via the APIs.
*/
public class Pack200Test {
private static ArrayList <File> jarList = new ArrayList<File>();
- static final String PACKEXT = ".pack";
+ static final MemoryMXBean mmxbean = ManagementFactory.getMemoryMXBean();
+ static final long m0 = getUsedMemory();
+ static final int LEAK_TOLERANCE = 20000; // OS and GC related variations.
/** Creates a new instance of Pack200Test */
private Pack200Test() {}
- private static void doPackUnpack() {
- for (File in : jarList) {
- Pack200.Packer packer = Pack200.newPacker();
- Map<String, String> p = packer.properties();
- // Take the time optimization vs. space
- p.put(packer.EFFORT, "1"); // CAUTION: do not use 0.
- // Make the memory consumption as effective as possible
- p.put(packer.SEGMENT_LIMIT,"10000");
- // throw an error if an attribute is unrecognized
- p.put(packer.UNKNOWN_ATTRIBUTE, packer.ERROR);
- // ignore all JAR deflation requests to save time
- p.put(packer.DEFLATE_HINT, packer.FALSE);
- // save the file ordering of the original JAR
- p.put(packer.KEEP_FILE_ORDER, packer.TRUE);
-
- try {
- JarFile jarFile = new JarFile(in);
-
- // Write out to a jtreg scratch area
- FileOutputStream fos = new FileOutputStream(in.getName() + PACKEXT);
+ static long getUsedMemory() {
+ mmxbean.gc();
+ mmxbean.gc();
+ mmxbean.gc();
+ return mmxbean.getHeapMemoryUsage().getUsed()/1024;
+ }
- System.out.print("Packing [" + in.toString() + "]...");
- // Call the packer
- packer.pack(jarFile, fos);
- jarFile.close();
- fos.close();
-
- System.out.print("Unpacking...");
- File f = new File(in.getName() + PACKEXT);
-
- // Write out to current directory, jtreg will setup a scratch area
- JarOutputStream jostream = new JarOutputStream(new FileOutputStream(in.getName()));
-
- // Unpack the files
- Pack200.Unpacker unpacker = Pack200.newUnpacker();
- // Call the unpacker
- unpacker.unpack(f, jostream);
- // Must explicitly close the output.
- jostream.close();
- System.out.print("Testing...");
- // Ok we have unpacked the file, lets test it.
- doTest(in);
- System.out.println("Done.");
- } catch (Exception e) {
- System.out.println("ERROR: " + e.getMessage());
- System.exit(1);
- }
+ private static void leakCheck() throws Exception {
+ long diff = getUsedMemory() - m0;
+ System.out.println(" Info: memory diff = " + diff + "K");
+ if ( diff > LEAK_TOLERANCE) {
+ throw new Exception("memory leak detected " + diff);
}
}
- private static ArrayList <String> getZipFileEntryNames(ZipFile z) {
- ArrayList <String> out = new ArrayList<String>();
- for (ZipEntry ze : Collections.list(z.entries())) {
- out.add(ze.getName());
- }
- return out;
- }
+ private static void doPackUnpack() {
+ for (File in : jarList) {
+ JarOutputStream javaUnpackerStream = null;
+ JarOutputStream nativeUnpackerStream = null;
+ JarFile jarFile = null;
+ try {
+ jarFile = new JarFile(in);
- private static void doTest(File in) throws Exception {
- // make sure all the files in the original jar exists in the other
- ArrayList <String> refList = getZipFileEntryNames(new ZipFile(in));
- ArrayList <String> cmpList = getZipFileEntryNames(new ZipFile(in.getName()));
+ // Write out to a jtreg scratch area
+ File packFile = new File(in.getName() + Utils.PACK_FILE_EXT);
- System.out.print(refList.size() + "/" + cmpList.size() + " entries...");
+ System.out.println("Packing [" + in.toString() + "]");
+ // Call the packer
+ Utils.pack(jarFile, packFile);
+ jarFile.close();
+ leakCheck();
- if (refList.size() != cmpList.size()) {
- throw new Exception("Missing: files ?, entries don't match");
- }
+ System.out.println(" Unpacking using java unpacker");
+ File javaUnpackedJar = new File("java-" + in.getName());
+ // Write out to current directory, jtreg will setup a scratch area
+ javaUnpackerStream = new JarOutputStream(
+ new FileOutputStream(javaUnpackedJar));
+ Utils.unpackj(packFile, javaUnpackerStream);
+ javaUnpackerStream.close();
+ System.out.println(" Testing...java unpacker");
+ leakCheck();
+ // Ok we have unpacked the file, lets test it.
+ Utils.doCompareVerify(in.getAbsoluteFile(), javaUnpackedJar);
- for (String ename: refList) {
- if (!cmpList.contains(ename)) {
- throw new Exception("Does not contain : " + ename);
- }
- }
- }
-
- private static void doSanity(String[] args) {
- for (String s: args) {
- File f = new File(s);
- if (f.exists()) {
- jarList.add(f);
- } else {
- System.out.println("Warning: The JAR file " + f.toString() + " does not exist,");
- System.out.println(" this test requires a JDK image, this file will be skipped.");
+ System.out.println(" Unpacking using native unpacker");
+ // Write out to current directory
+ File nativeUnpackedJar = new File("native-" + in.getName());
+ nativeUnpackerStream = new JarOutputStream(
+ new FileOutputStream(nativeUnpackedJar));
+ Utils.unpackn(packFile, nativeUnpackerStream);
+ nativeUnpackerStream.close();
+ System.out.println(" Testing...native unpacker");
+ leakCheck();
+ // the unpackers (native and java) should produce identical bits
+ // so we use use bit wise compare, the verification compare is
+ // very expensive wrt. time.
+ Utils.doCompareBitWise(javaUnpackedJar, nativeUnpackedJar);
+ System.out.println("Done.");
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ } finally {
+ Utils.close(nativeUnpackerStream);
+ Utils.close(javaUnpackerStream);
+ Utils.close((Closeable) jarFile);
}
}
}
@@ -137,11 +123,12 @@
* @param args the command line arguments
*/
public static void main(String[] args) {
- if (args.length < 1) {
- System.out.println("Usage: jar1 jar2 jar3 .....");
- System.exit(1);
- }
- doSanity(args);
+ // select the jars carefully, adding more jars will increase the
+ // testing time, especially for jprt.
+ jarList.add(Utils.locateJar("tools.jar"));
+ jarList.add(Utils.locateJar("rt.jar"));
+ jarList.add(Utils.locateJar("golden.jar"));
+ System.out.println(jarList);
doPackUnpack();
}
}
--- a/jdk/test/tools/pack200/PackageVersionTest.java Wed Sep 08 14:04:18 2010 -0700
+++ b/jdk/test/tools/pack200/PackageVersionTest.java Wed Jul 05 17:21:22 2017 +0200
@@ -22,13 +22,14 @@
* questions.
*/
-/**
- * @test
- * @bug 6712743
- * @summary verify package versioning
- * @compile -XDignore.symbol.file PackageVersionTest.java
- * @run main PackageVersionTest
- */
+/*
+ * @test
+ * @bug 6712743
+ * @summary verify package versions
+ * @compile -XDignore.symbol.file Utils.java PackageVersionTest.java
+ * @run main PackageVersionTest
+ * @author ksrini
+ */
import java.io.ByteArrayOutputStream;
import java.io.Closeable;
@@ -74,14 +75,6 @@
JAVA5_PACKAGE_MINOR_VERSION);
}
- static void close(Closeable c) {
- if (c == null) {
- return;
- }
- try {
- c.close();
- } catch (IOException ignore) {}
- }
static void createClassFile(String name) {
createJavaFile(name);
@@ -93,7 +86,7 @@
name.substring(name.length() - 1),
name + ".java"
};
- compileJava(javacCmds);
+ Utils.compiler(javacCmds);
}
static void createJavaFile(String name) {
@@ -108,22 +101,8 @@
} catch (IOException ioe) {
throw new RuntimeException("creation of test file failed");
} finally {
- close(ps);
- close(fos);
- }
- }
-
- static void compileJava(String... javacCmds) {
- if (com.sun.tools.javac.Main.compile(javacCmds) != 0) {
- throw new RuntimeException("compilation failed");
- }
- }
-
- static void makeJar(String... jargs) {
- sun.tools.jar.Main jarTool =
- new sun.tools.jar.Main(System.out, System.err, "jartool");
- if (!jarTool.run(jargs)) {
- throw new RuntimeException("jar command failed");
+ Utils.close(ps);
+ Utils.close(fos);
}
}
@@ -136,7 +115,7 @@
jarFileName.getName(),
filename
};
- makeJar(jargs);
+ Utils.jar(jargs);
JarFile jfin = null;
try {
@@ -163,7 +142,7 @@
} catch (IOException ioe) {
throw new RuntimeException(ioe.getMessage());
} finally {
- close(jfin);
+ Utils.close((Closeable) jfin);
}
}
}
--- a/jdk/test/tools/pack200/SegmentLimit.java Wed Sep 08 14:04:18 2010 -0700
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,134 +0,0 @@
-/*
- * Copyright (c) 2010, 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 6575373
- * @summary verify default segment limit
- * @compile SegmentLimit.java
- * @run main SegmentLimit
- */
-
-import java.io.BufferedReader;
-import java.io.Closeable;
-import java.io.File;
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.InputStreamReader;
-import java.io.PrintStream;
-
-/*
- * Run this against a large jar file, by default the packer should generate only
- * one segment, parse the output of the packer to verify if this is indeed true.
- */
-
-public class SegmentLimit {
-
- private static final File javaHome = new File(System.getProperty("java.home"));
-
- public static void main(String... args) {
- if (!javaHome.getName().endsWith("jre")) {
- throw new RuntimeException("Error: requires an SDK to run");
- }
-
- File out = new File("test" + Pack200Test.PACKEXT);
- out.delete();
- runPack200(out);
- }
-
- static void close(Closeable c) {
- if (c == null) {
- return;
- }
- try {
- c.close();
- } catch (IOException ignore) {}
- }
-
- static void runPack200(File outFile) {
- File binDir = new File(javaHome, "bin");
- File pack200Exe = System.getProperty("os.name").startsWith("Windows")
- ? new File(binDir, "pack200.exe")
- : new File(binDir, "pack200");
- File sdkHome = javaHome.getParentFile();
- File testJar = new File(new File(sdkHome, "lib"), "tools.jar");
-
- System.out.println("using pack200: " + pack200Exe.getAbsolutePath());
-
- String[] cmds = { pack200Exe.getAbsolutePath(),
- "--effort=1",
- "--verbose",
- "--no-gzip",
- outFile.getName(),
- testJar.getAbsolutePath()
- };
- InputStream is = null;
- BufferedReader br = null;
- InputStreamReader ir = null;
-
- FileOutputStream fos = null;
- PrintStream ps = null;
-
- try {
- ProcessBuilder pb = new ProcessBuilder(cmds);
- pb.redirectErrorStream(true);
- Process p = pb.start();
- is = p.getInputStream();
- ir = new InputStreamReader(is);
- br = new BufferedReader(ir);
-
- File logFile = new File("pack200.log");
- fos = new FileOutputStream(logFile);
- ps = new PrintStream(fos);
-
- String line = br.readLine();
- int count = 0;
- while (line != null) {
- line = line.trim();
- if (line.matches(".*Transmitted.*files of.*input bytes in a segment of.*bytes")) {
- count++;
- }
- ps.println(line);
- line=br.readLine();
- }
- p.waitFor();
- if (p.exitValue() != 0) {
- throw new RuntimeException("pack200 failed");
- }
- p.destroy();
- if (count > 1) {
- throw new Error("test fails: check for multiple segments(" +
- count + ") in: " + logFile.getAbsolutePath());
- }
- } catch (IOException ex) {
- throw new RuntimeException(ex.getMessage());
- } catch (InterruptedException ignore){
- } finally {
- close(is);
- close(ps);
- close(fos);
- }
- }
-}
-
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/tools/pack200/TimeStamp.java Wed Jul 05 17:21:22 2017 +0200
@@ -0,0 +1,156 @@
+/*
+ * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.TimeZone;
+import java.util.jar.JarEntry;
+import java.util.jar.JarFile;
+import java.util.jar.JarOutputStream;
+
+/*
+ * @test
+ * @bug 6966740
+ * @summary verify identical timestamps, unpacked in any timezone
+ * @compile -XDignore.symbol.file Utils.java TimeStamp.java
+ * @run main/othervm TimeStamp
+ * @author ksrini
+ */
+
+/**
+ * First we pack the file in some time zone say India, then we unpack the file
+ * in the current time zone, and ensure the timestamp recorded in the unpacked
+ * jar are the same.
+ */
+public class TimeStamp {
+ static final TimeZone tz = TimeZone.getDefault();
+
+
+ public static void main(String... args) throws IOException {
+
+ // make a local copy of our test file
+ File srcFile = Utils.locateJar("golden.jar");
+ File goldenFile = new File("golden.jar");
+ Utils.copyFile(srcFile, goldenFile.getAbsoluteFile());
+
+ JarFile goldenJarFile = new JarFile(goldenFile);
+ File packFile = new File("golden.pack");
+
+ // set the test timezone and pack the file
+ TimeZone.setDefault(TimeZone.getTimeZone("IST"));
+ Utils.pack(goldenJarFile, packFile);
+ TimeZone.setDefault(tz); // reset the timezone
+
+ // unpack in the test timezone
+ File istFile = new File("golden.jar.java.IST");
+ unpackJava(packFile, istFile);
+ verifyJar(goldenFile, istFile);
+ istFile.delete();
+
+ // unpack in some other timezone
+ File pstFile = new File("golden.jar.java.PST");
+ unpackJava(packFile, pstFile);
+ verifyJar(goldenFile, pstFile);
+ pstFile.delete();
+
+ // repeat the test for unpack200 tool.
+ istFile = new File("golden.jar.native.IST");
+ unpackNative(packFile, istFile);
+ verifyJar(goldenFile, istFile);
+ istFile.delete();
+
+ pstFile = new File("golden.jar.native.PST");
+ unpackNative(packFile, pstFile);
+ verifyJar(goldenFile, pstFile);
+ pstFile.delete();
+ }
+
+ static void unpackNative(File packFile, File outFile) {
+ String name = outFile.getName();
+ String tzname = name.substring(name.lastIndexOf(".") + 1);
+ HashMap<String, String> env = new HashMap<>();
+ switch(tzname) {
+ case "PST":
+ env.put("TZ", "US/Pacific");
+ break;
+ case "IST":
+ env.put("TZ", "Asia/Calcutta");
+ break;
+ default:
+ throw new RuntimeException("not implemented: " + tzname);
+ }
+ List<String> cmdsList = new ArrayList<>();
+ cmdsList.add(Utils.getUnpack200Cmd());
+ cmdsList.add(packFile.getName());
+ cmdsList.add(outFile.getName());
+ Utils.runExec(cmdsList, env);
+ }
+
+ static void unpackJava(File packFile, File outFile) throws IOException {
+ String name = outFile.getName();
+ String tzname = name.substring(name.lastIndexOf(".") + 1);
+ JarOutputStream jos = null;
+ try {
+ TimeZone.setDefault(TimeZone.getTimeZone(tzname));
+ jos = new JarOutputStream(new FileOutputStream(outFile));
+ System.out.println("Using timezone: " + TimeZone.getDefault());
+ Utils.unpackj(packFile, jos);
+ } finally {
+ Utils.close(jos);
+ TimeZone.setDefault(tz); // always reset
+ }
+ }
+
+ static void verifyJar(File f1, File f2) throws IOException {
+ int errors = 0;
+ JarFile jf1 = null;
+ JarFile jf2 = null;
+ try {
+ jf1 = new JarFile(f1);
+ jf2 = new JarFile(f2);
+ System.out.println("Verifying: " + f1 + " and " + f2);
+ for (JarEntry je1 : Collections.list(jf1.entries())) {
+ JarEntry je2 = jf2.getJarEntry(je1.getName());
+ if (je1.getTime() != je2.getTime()) {
+ System.out.println("Error:");
+ System.out.println(" expected:" + jf1.getName() + ":"
+ + je1.getName() + ":" + je1.getTime());
+ System.out.println(" obtained:" + jf2.getName() + ":"
+ + je2.getName() + ":" + je2.getTime());
+ errors++;
+ }
+ }
+ } finally {
+ Utils.close(jf1);
+ Utils.close(jf2);
+ }
+ if (errors > 0) {
+ throw new RuntimeException("FAIL:" + errors + " error(s) encounted");
+ }
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/tools/pack200/UnpackerMemoryTest.java Wed Jul 05 17:21:22 2017 +0200
@@ -0,0 +1,86 @@
+/*
+ * Copyright (c) 2010, 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 6531345
+ * @summary check for unpacker memory leaks
+ * @compile -XDignore.symbol.file Utils.java UnpackerMemoryTest.java
+ * @run main/othervm/timeout=1200 -Xmx32m UnpackerMemoryTest
+ * @author ksrini
+ */
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.PrintStream;
+import java.io.IOException;
+import java.util.jar.JarFile;
+import java.util.jar.JarOutputStream;
+
+public class UnpackerMemoryTest {
+
+ private static void createPackFile(File packFile) throws IOException {
+ File tFile = new File("test.dat");
+ FileOutputStream fos = null;
+ PrintStream ps = null;
+ String jarFileName = Utils.baseName(packFile, Utils.PACK_FILE_EXT)
+ + Utils.JAR_FILE_EXT;
+ JarFile jarFile = null;
+ try {
+ fos = new FileOutputStream(tFile);
+ ps = new PrintStream(fos);
+ ps.println("A quick brown fox");
+ Utils.jar("cvf", jarFileName, tFile.getName());
+ jarFile = new JarFile(jarFileName);
+ Utils.pack(jarFile, packFile);
+ } finally {
+ Utils.close(ps);
+ tFile.delete();
+ Utils.close(jarFile);
+ }
+ }
+
+ public static void main(String[] args) throws Exception {
+ String name = "foo";
+ File packFile = new File(name + Utils.PACK_FILE_EXT);
+ createPackFile(packFile);
+ if (!packFile.exists()) {
+ throw new RuntimeException(packFile + " not found");
+ }
+ File jarOut = new File(name + ".out");
+ for (int i = 0; i < 2000; i++) {
+ JarOutputStream jarOS = null;
+ FileOutputStream fos = null;
+ try {
+ fos = new FileOutputStream(jarOut);
+ jarOS = new JarOutputStream(fos);
+ System.out.println("Unpacking[" + i + "]" + packFile);
+ Utils.unpackn(packFile, jarOS);
+ } finally {
+ Utils.close(jarOS);
+ Utils.close(fos);
+ }
+ }
+ }
+}
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/tools/pack200/Utils.java Wed Jul 05 17:21:22 2017 +0200
@@ -0,0 +1,516 @@
+/*
+ * Copyright (c) 2007, 2010 Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+import java.io.BufferedReader;
+import java.io.ByteArrayOutputStream;
+import java.io.Closeable;
+import java.io.File;
+import java.io.FileFilter;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.PrintStream;
+import java.nio.channels.FileChannel;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+import java.util.jar.JarFile;
+import java.util.jar.JarOutputStream;
+import java.util.jar.Pack200;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipFile;
+
+/**
+ *
+ * @author ksrini
+ */
+
+/*
+ * This class contains all the commonly used utilities used by various tests
+ * in this directory.
+ */
+class Utils {
+ static final String JavaHome = System.getProperty("test.java",
+ System.getProperty("java.home"));
+ static final boolean IsWindows =
+ System.getProperty("os.name").startsWith("Windows");
+ static final boolean Is64Bit =
+ System.getProperty("sun.arch.data.model", "32").equals("64");
+ static final File JavaSDK = new File(JavaHome).getParentFile();
+
+ static final String PACK_FILE_EXT = ".pack";
+ static final String JAVA_FILE_EXT = ".java";
+ static final String CLASS_FILE_EXT = ".class";
+ static final String JAR_FILE_EXT = ".jar";
+
+ static final File TEST_SRC_DIR = new File(System.getProperty("test.src"));
+ static final String VERIFIER_DIR_NAME = "pack200-verifier";
+ static final File VerifierJar = new File(VERIFIER_DIR_NAME + JAR_FILE_EXT);
+
+ private Utils() {} // all static
+
+ static {
+ if (!JavaHome.endsWith("jre")) {
+ throw new RuntimeException("Error: requires an SDK to run");
+ }
+ }
+
+ private static void init() throws IOException {
+ if (VerifierJar.exists()) {
+ return;
+ }
+ File srcDir = new File(TEST_SRC_DIR, VERIFIER_DIR_NAME);
+ List<File> javaFileList = findFiles(srcDir, createFilter(JAVA_FILE_EXT));
+ File tmpFile = File.createTempFile("javac", ".tmp");
+ File classesDir = new File("xclasses");
+ classesDir.mkdirs();
+ FileOutputStream fos = null;
+ PrintStream ps = null;
+ try {
+ fos = new FileOutputStream(tmpFile);
+ ps = new PrintStream(fos);
+ for (File f : javaFileList) {
+ ps.println(f.getAbsolutePath());
+ }
+ } finally {
+ close(ps);
+ close(fos);
+ }
+
+ compiler("-d",
+ "xclasses",
+ "@" + tmpFile.getAbsolutePath());
+
+ jar("cvfe",
+ VerifierJar.getName(),
+ "sun.tools.pack.verify.Main",
+ "-C",
+ "xclasses",
+ ".");
+ }
+
+ static void dirlist(File dir) {
+ File[] files = dir.listFiles();
+ System.out.println("--listing " + dir.getAbsolutePath() + "---");
+ for (File f : files) {
+ StringBuffer sb = new StringBuffer();
+ sb.append(f.isDirectory() ? "d " : "- ");
+ sb.append(f.getName());
+ System.out.println(sb);
+ }
+ }
+ static void doCompareVerify(File reference, File specimen) throws IOException {
+ init();
+ List<String> cmds = new ArrayList<String>();
+ cmds.add(getJavaCmd());
+ cmds.add("-jar");
+ cmds.add(VerifierJar.getName());
+ cmds.add(reference.getAbsolutePath());
+ cmds.add(specimen.getAbsolutePath());
+ cmds.add("-O");
+ runExec(cmds);
+ }
+
+ static void doCompareBitWise(File reference, File specimen)
+ throws IOException {
+ init();
+ List<String> cmds = new ArrayList<String>();
+ cmds.add(getJavaCmd());
+ cmds.add("-jar");
+ cmds.add(VerifierJar.getName());
+ cmds.add(reference.getName());
+ cmds.add(specimen.getName());
+ cmds.add("-O");
+ cmds.add("-b");
+ runExec(cmds);
+ }
+
+ static FileFilter createFilter(final String extension) {
+ return new FileFilter() {
+ @Override
+ public boolean accept(File pathname) {
+ String name = pathname.getName();
+ if (name.endsWith(extension)) {
+ return true;
+ }
+ return false;
+ }
+ };
+ }
+
+ static final FileFilter DIR_FILTER = new FileFilter() {
+ public boolean accept(File pathname) {
+ if (pathname.isDirectory()) {
+ return true;
+ }
+ return false;
+ }
+ };
+
+ static final FileFilter FILE_FILTER = new FileFilter() {
+ public boolean accept(File pathname) {
+ if (pathname.isFile()) {
+ return true;
+ }
+ return false;
+ }
+ };
+
+ private static void setFileAttributes(File src, File dst) throws IOException {
+ dst.setExecutable(src.canExecute());
+ dst.setReadable(src.canRead());
+ dst.setWritable(src.canWrite());
+ dst.setLastModified(src.lastModified());
+ }
+
+ static void copyFile(File src, File dst) throws IOException {
+ if (src.isDirectory()) {
+ dst.mkdirs();
+ setFileAttributes(src, dst);
+ return;
+ } else {
+ File baseDirFile = dst.getParentFile();
+ if (!baseDirFile.exists()) {
+ baseDirFile.mkdirs();
+ }
+ }
+ FileInputStream in = null;
+ FileOutputStream out = null;
+ FileChannel srcChannel = null;
+ FileChannel dstChannel = null;
+ try {
+ in = new FileInputStream(src);
+ out = new FileOutputStream(dst);
+ srcChannel = in.getChannel();
+ dstChannel = out.getChannel();
+
+ long retval = srcChannel.transferTo(0, src.length(), dstChannel);
+ if (src.length() != dst.length()) {
+ throw new IOException("file copy failed for " + src);
+ }
+ } finally {
+ close(srcChannel);
+ close(dstChannel);
+ close(in);
+ close(out);
+ }
+ setFileAttributes(src, dst);
+ }
+
+ static String baseName(File file, String extension) {
+ return baseName(file.getAbsolutePath(), extension);
+ }
+
+ static String baseName(String name, String extension) {
+ int cut = name.length() - extension.length();
+ return name.lastIndexOf(extension) == cut
+ ? name.substring(0, cut)
+ : name;
+
+ }
+
+ /*
+ * Suppose a path is provided which consists of a full path
+ * this method returns the sub path for a full path ex: /foo/bar/baz/foobar.z
+ * and the base path is /foo/bar it will will return baz/foobar.z.
+ */
+ private static String getEntryPath(String basePath, String fullPath) {
+ if (!fullPath.startsWith(basePath)) {
+ return null;
+ }
+ return fullPath.substring(basePath.length());
+ }
+
+ static String getEntryPath(File basePathFile, File fullPathFile) {
+ return getEntryPath(basePathFile.toString(), fullPathFile.toString());
+ }
+
+ public static void recursiveCopy(File src, File dest) throws IOException {
+ if (!src.exists() || !src.canRead()) {
+ throw new IOException("file not found or readable: " + src);
+ }
+ if (dest.exists() && !dest.isDirectory() && !dest.canWrite()) {
+ throw new IOException("file not found or writeable: " + dest);
+ }
+ if (!dest.exists()) {
+ dest.mkdirs();
+ }
+ List<File> a = directoryList(src);
+ for (File f : a) {
+ copyFile(f, new File(dest, getEntryPath(src, f)));
+ }
+ }
+
+ static List<File> directoryList(File dirname) {
+ List<File> dirList = new ArrayList<File>();
+ return directoryList(dirname, dirList, null);
+ }
+
+ private static List<File> directoryList(File dirname, List<File> dirList,
+ File[] dirs) {
+ dirList.addAll(Arrays.asList(dirname.listFiles(FILE_FILTER)));
+ dirs = dirname.listFiles(DIR_FILTER);
+ for (File f : dirs) {
+ if (f.isDirectory() && !f.equals(dirname)) {
+ dirList.add(f);
+ directoryList(f, dirList, dirs);
+ }
+ }
+ return dirList;
+ }
+
+ static void recursiveDelete(File dir) throws IOException {
+ if (dir.isFile()) {
+ dir.delete();
+ } else if (dir.isDirectory()) {
+ File[] entries = dir.listFiles();
+ for (int i = 0; i < entries.length; i++) {
+ if (entries[i].isDirectory()) {
+ recursiveDelete(entries[i]);
+ }
+ entries[i].delete();
+ }
+ dir.delete();
+ }
+ }
+
+ static List<File> findFiles(File startDir, FileFilter filter)
+ throws IOException {
+ List<File> list = new ArrayList<File>();
+ findFiles0(startDir, list, filter);
+ return list;
+ }
+ /*
+ * finds files in the start directory using the the filter, appends
+ * the files to the dirList.
+ */
+ private static void findFiles0(File startDir, List<File> list,
+ FileFilter filter) throws IOException {
+ File[] foundFiles = startDir.listFiles(filter);
+ list.addAll(Arrays.asList(foundFiles));
+ File[] dirs = startDir.listFiles(DIR_FILTER);
+ for (File dir : dirs) {
+ findFiles0(dir, list, filter);
+ }
+ }
+
+ static void close(Closeable c) {
+ if (c == null) {
+ return;
+ }
+ try {
+ c.close();
+ } catch (IOException ignore) {
+ }
+ }
+
+ static void compiler(String... javacCmds) {
+ if (com.sun.tools.javac.Main.compile(javacCmds) != 0) {
+ throw new RuntimeException("compilation failed");
+ }
+ }
+
+ static void jar(String... jargs) {
+ sun.tools.jar.Main jarTool =
+ new sun.tools.jar.Main(System.out, System.err, "jartool");
+ if (!jarTool.run(jargs)) {
+ throw new RuntimeException("jar command failed");
+ }
+ }
+
+ // given a jar file foo.jar will write to foo.pack
+ static void pack(JarFile jarFile, File packFile) throws IOException {
+ Pack200.Packer packer = Pack200.newPacker();
+ Map<String, String> p = packer.properties();
+ // Take the time optimization vs. space
+ p.put(packer.EFFORT, "1"); // CAUTION: do not use 0.
+ // Make the memory consumption as effective as possible
+ p.put(packer.SEGMENT_LIMIT, "10000");
+ // ignore all JAR deflation requests to save time
+ p.put(packer.DEFLATE_HINT, packer.FALSE);
+ // save the file ordering of the original JAR
+ p.put(packer.KEEP_FILE_ORDER, packer.TRUE);
+ FileOutputStream fos = null;
+ try {
+ // Write out to a jtreg scratch area
+ fos = new FileOutputStream(packFile);
+ // Call the packer
+ packer.pack(jarFile, fos);
+ } finally {
+ close(fos);
+ }
+ }
+
+ // uses java unpacker, slow but useful to discover issues with the packer
+ static void unpackj(File inFile, JarOutputStream jarStream)
+ throws IOException {
+ unpack0(inFile, jarStream, true);
+
+ }
+
+ // uses native unpacker using the java APIs
+ static void unpackn(File inFile, JarOutputStream jarStream)
+ throws IOException {
+ unpack0(inFile, jarStream, false);
+ }
+
+ // given a packed file, create the jar file in the current directory.
+ private static void unpack0(File inFile, JarOutputStream jarStream,
+ boolean useJavaUnpack) throws IOException {
+ // Unpack the files
+ Pack200.Unpacker unpacker = Pack200.newUnpacker();
+ Map<String, String> props = unpacker.properties();
+ if (useJavaUnpack) {
+ props.put("com.sun.java.util.jar.pack.disable.native", "true");
+ }
+ // Call the unpacker
+ unpacker.unpack(inFile, jarStream);
+ }
+
+ static byte[] getBuffer(ZipFile zf, ZipEntry ze) throws IOException {
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ byte buf[] = new byte[8192];
+ InputStream is = null;
+ try {
+ is = zf.getInputStream(ze);
+ int n = is.read(buf);
+ while (n > 0) {
+ baos.write(buf, 0, n);
+ n = is.read(buf);
+ }
+ return baos.toByteArray();
+ } finally {
+ close(is);
+ }
+ }
+
+ static ArrayList<String> getZipFileEntryNames(ZipFile z) {
+ ArrayList<String> out = new ArrayList<String>();
+ for (ZipEntry ze : Collections.list(z.entries())) {
+ out.add(ze.getName());
+ }
+ return out;
+ }
+ static List<String> runExec(List<String> cmdsList) {
+ return runExec(cmdsList, null);
+ }
+ static List<String> runExec(List<String> cmdsList, Map<String, String> penv) {
+ ArrayList<String> alist = new ArrayList<String>();
+ ProcessBuilder pb =
+ new ProcessBuilder(cmdsList);
+ Map<String, String> env = pb.environment();
+ if (penv != null && !penv.isEmpty()) {
+ env.putAll(penv);
+ }
+ pb.directory(new File("."));
+ dirlist(new File("."));
+ for (String x : cmdsList) {
+ System.out.print(x + " ");
+ }
+ System.out.println("");
+ int retval = 0;
+ Process p = null;
+ InputStreamReader ir = null;
+ BufferedReader rd = null;
+ InputStream is = null;
+ try {
+ pb.redirectErrorStream(true);
+ p = pb.start();
+ is = p.getInputStream();
+ ir = new InputStreamReader(is);
+ rd = new BufferedReader(ir, 8192);
+
+ String in = rd.readLine();
+ while (in != null) {
+ alist.add(in);
+ System.out.println(in);
+ in = rd.readLine();
+ }
+ retval = p.waitFor();
+ if (retval != 0) {
+ throw new RuntimeException("process failed with non-zero exit");
+ }
+ } catch (Exception ex) {
+ throw new RuntimeException(ex.getMessage());
+ } finally {
+ close(rd);
+ close(ir);
+ close(is);
+ if (p != null) {
+ p.destroy();
+ }
+ }
+ return alist;
+ }
+
+ static String getUnpack200Cmd() {
+ return getAjavaCmd("unpack200");
+ }
+
+ static String getPack200Cmd() {
+ return getAjavaCmd("pack200");
+ }
+
+ static String getJavaCmd() {
+ return getAjavaCmd("java");
+ }
+
+ static String getAjavaCmd(String cmdStr) {
+ File binDir = new File(JavaHome, "bin");
+ File unpack200File = IsWindows
+ ? new File(binDir, cmdStr + ".exe")
+ : new File(binDir, cmdStr);
+
+ String cmd = unpack200File.getAbsolutePath();
+ if (!unpack200File.canExecute()) {
+ throw new RuntimeException("please check" +
+ cmd + " exists and is executable");
+ }
+ return cmd;
+ }
+
+ private static List<File> locaterCache = null;
+ // search the source dir and jdk dir for requested file and returns
+ // the first location it finds.
+ static File locateJar(String name) {
+ try {
+ if (locaterCache == null) {
+ locaterCache = new ArrayList<File>();
+ locaterCache.addAll(findFiles(TEST_SRC_DIR, createFilter(JAR_FILE_EXT)));
+ locaterCache.addAll(findFiles(JavaSDK, createFilter(JAR_FILE_EXT)));
+ }
+ for (File f : locaterCache) {
+ if (f.getName().equals(name)) {
+ return f;
+ }
+ }
+ throw new IOException("file not found: " + name);
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/tools/pack200/pack200-verifier/data/README Wed Jul 05 17:21:22 2017 +0200
@@ -0,0 +1,45 @@
+The files contained in the golden.jar have been harvested from many
+different sources, some are hand-crafted invalid class files (odds directory),
+or from random JDK builds.
+
+Generally these files serve to ensure the integrity of the packer and unpacker
+by,
+ 1. maximizing the test coverage.
+ 2. exercising all the Bands in the pack200 specification.
+ 2. testing the behavior of the packer with invalid classes.
+ 3. testing the archive integrity, ordering and description (date, sizes,
+ CRC etc.)
+
+Build:
+To rebuild this JAR follow these steps:
+ 1. unzip the golden.jar to some directory lets call it "example"
+ 2. now we can add any directories with files into example.
+ 2. run the script BUILDME.sh as
+ % sh BUILDME.sh example
+
+Note: the BUILDME.sh is known to work on all Unix platforms as well as Windows
+ using Cygwin.
+
+The above will create two JAR files in the current directory,
+example.jar and example-cls.jar, now the example.jar can be used as the
+golden.jar.
+
+To ensure the JAR has been built correctly use jar -tvf and compare the
+results of the old jar and the newly built one, note that the compressed sizes
+may differ, however the timestamps etc. should be consistent.
+
+Test:
+ Basic:
+ % pack200 --repack test.jar golden.jar
+
+ Advanced:
+ Create a pack.conf as follows:
+ % cat pack.conf
+ com.sun.java.util.jar.pack.dump.bands=true
+
+ % pack200 --no-gzip --config-file=pack.conf \
+ --verbose golden.jar.pack golden.jar
+
+ This command will dump the Bands in a unique directory BD_XXXXXX,
+ one can inspect the directory to ensure all of the bands are being
+ generated. Familiarity of the Pack200 specification is suggested.
\ No newline at end of file
Binary file jdk/test/tools/pack200/pack200-verifier/data/golden.jar has changed
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/tools/pack200/pack200-verifier/make/build.xml Wed Jul 05 17:21:22 2017 +0200
@@ -0,0 +1,59 @@
+<project name="PackageVerify" default="dist" basedir="..">
+ <!-- Requires ant 1.6.1+ and JDK 1.6+-->
+
+ <!-- set global properties for this build -->
+ <property name="src" value="${basedir}/src"/>
+ <property name="build" value="${basedir}/build"/>
+ <property name="dist" value="${basedir}/dist"/>
+ <property name="make" value="${basedir}/make"/>
+ <property name="classes" value="${build}/classes"/>
+ <property name="api" value="${build}/api"/>
+
+ <target name="init">
+ <!-- Create the time stamp -->
+ <tstamp/>
+ <!-- Create the build directory structure used by compile -->
+ <mkdir dir="${build}"/>
+ <mkdir dir="${dist}"/>
+ <mkdir dir="${classes}"/>
+ <mkdir dir="${api}"/>
+ </target>
+
+ <target name="compile" depends="init">
+ <!-- Compile the java code from ${src} into ${build} -->
+ <javac
+ source="1.6"
+ srcdir="${src}"
+ destdir="${build}/classes"
+ verbose="no"
+ debug="on"
+ />
+ </target>
+
+ <target name="doc" depends="init, compile">
+ <javadoc
+ source="1.6"
+ sourcepath="${src}"
+ destdir="${api}"
+ />
+ </target>
+ <target name="dist" depends="compile, doc">
+ <!-- Put everything in jar file -->
+ <jar destfile="${dist}/pack200-verifier.jar">
+ <manifest>
+ <attribute name="Main-Class" value="sun.tools.pack.verify.Main"/>
+ </manifest>
+ <fileset dir="${classes}"/>
+ </jar>
+ <zip destfile="dist/pack200-verifier-doc.zip">
+ <fileset dir="${api}"/>
+ </zip>
+ </target>
+
+ <target name="clean">
+ <!-- Delete the ${build} and ${dist} directory trees -->
+ <delete dir="${build}"/>
+ <delete dir="${dist}"/>
+ </target>
+
+</project>
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/tools/pack200/pack200-verifier/src/sun/tools/pack/verify/ClassCompare.java Wed Jul 05 17:21:22 2017 +0200
@@ -0,0 +1,160 @@
+/*
+ * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package sun.tools.pack.verify;
+
+import java.io.*;
+import java.util.*;
+import java.util.jar.*;
+import xmlkit.*;
+
+public class ClassCompare {
+
+ /*
+ * @author ksrini
+ */
+ private static XMLKit.Element getXMLelement(InputStream is,
+ boolean ignoreUnkAttrs,
+ List<String> ignoreElements) throws IOException {
+
+ ClassReader cr = new ClassReader();
+ cr.keepOrder = false;
+ XMLKit.Element e = cr.readFrom(is);
+
+ if (ignoreElements != null) {
+ XMLKit.Filter filter = XMLKit.elementFilter(ignoreElements);
+ e.removeAllInTree(filter);
+ }
+
+ if (ignoreUnkAttrs == true) {
+ // This removes any unknown attributes
+ e.removeAllInTree(XMLKit.elementFilter("Attribute"));
+ }
+ return e;
+ }
+
+ private static String getXMLPrettyString(XMLKit.Element e) throws IOException {
+ StringWriter out = new StringWriter();
+ e.writePrettyTo(out);
+ return out.toString();
+ }
+
+ private static boolean compareClass0(JarFile jf1, JarFile jf2,
+ JarEntry je, boolean ignoreUnkAttrs,
+ List<String> ignoreElements)
+ throws IOException {
+
+ InputStream is1 = jf1.getInputStream(je);
+ InputStream is2 = jf2.getInputStream(je);
+
+ // First we try to compare the bits if they are the same
+ boolean bCompare = JarFileCompare.compareStreams(is1, is2);
+
+ // If they are the same there is nothing more to do.
+ if (bCompare) {
+ Globals.println("+++" + je.getName() + "+++\t"
+ + "b/b:PASS");
+ return bCompare;
+ }
+ is1.close();
+ is2.close();
+
+ is1 = jf1.getInputStream(je);
+ is2 = jf2.getInputStream(je);
+
+
+ XMLKit.Element e1 = getXMLelement(is1, ignoreUnkAttrs, ignoreElements);
+ XMLKit.Element e2 = getXMLelement(is2, ignoreUnkAttrs, ignoreElements);
+
+ Globals.print("+++" + je.getName() + "+++\t"
+ + e1.size() + "/" + e1.size() + ":");
+
+ boolean result = true;
+
+ if (e1.equals(e2)) {
+ Globals.println("PASS");
+ } else {
+ Globals.println("FAIL");
+ Globals.log("Strings differs");
+ Globals.log(getXMLPrettyString(e1));
+ Globals.log("----------");
+ Globals.log(getXMLPrettyString(e2));
+ result = false;
+ }
+ return result;
+ }
+
+ /*
+ * Given two Class Paths could be jars the first being a reference
+ * will execute a series of comparisons on the classname specified
+ * The className could be null in which case it will iterate through
+ * all the classes, otherwise it will compare one class and exit.
+ */
+ public static boolean compareClass(String jar1, String jar2,
+ String className, boolean ignoreUnkAttrs,
+ List<String> ignoreElements)
+ throws IOException {
+
+ Globals.println("Unknown attributes ignored:" + ignoreUnkAttrs);
+ if (ignoreElements != null) {
+ Globals.println(ignoreElements.toString());
+ }
+
+ JarFile jf1 = new JarFile(jar1);
+ JarFile jf2 = new JarFile(jar2);
+
+ boolean result = true;
+
+ if (className == null) {
+ for (JarEntry je1 : Collections.list((Enumeration<JarEntry>) jf1.entries())) {
+ if (je1.getName().endsWith(".class")) {
+ JarEntry je2 = jf2.getJarEntry(je1.getName());
+ boolean pf = compareClass0(jf1, jf2, je1, ignoreUnkAttrs, ignoreElements);
+ if (result == true) {
+ result = pf;
+ }
+ }
+ }
+ } else {
+ JarEntry je1 = jf1.getJarEntry(className);
+ result = compareClass0(jf1, jf2, je1, ignoreUnkAttrs, ignoreElements);
+ }
+ if (result == false) {
+ throw new RuntimeException("Class structural comparison failure");
+ }
+ return result;
+ }
+
+ public static boolean compareClass(String jar1, String jar2,
+ String className) throws IOException {
+
+ Stack<String> s = new Stack();
+ if (Globals.ignoreDebugAttributes()) {
+ s = new Stack();
+ s.push("LocalVariable");
+ s.push("LocalVariableType");
+ s.push("LineNumber");
+ s.push("SourceFile");
+ }
+ return compareClass(jar1, jar2, className, Globals.ignoreUnknownAttributes(), s);
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/tools/pack200/pack200-verifier/src/sun/tools/pack/verify/Globals.java Wed Jul 05 17:21:22 2017 +0200
@@ -0,0 +1,310 @@
+/*
+ * Copyright (c) 2010, 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.
+ */
+
+/*
+ * A collection of useful global utilities commonly used.
+ */
+package sun.tools.pack.verify;
+
+import java.io.*;
+import java.util.*;
+
+/*
+ * @author ksrini
+ */
+
+class Globals {
+
+ private static int errors = 0;
+ private static PrintWriter _pw = null;
+ private static String _logFileName = null;
+ private static final String DEFAULT_LOG_FILE = "verifier.log";
+ private static boolean _verbose = true;
+ private static boolean _ignoreJarDirectories = false;
+ private static boolean _checkJarClassOrdering = true;
+ private static boolean _bitWiseClassCompare = false;
+ // Ignore Deprecated, SourceFile and Synthetic
+ private static boolean _ignoreCompileAttributes = false;
+ // Ignore Debug Attributes LocalVariableTable, LocalVariableType,LineNumberTable
+ private static boolean _ignoreDebugAttributes = false;
+ private static boolean _ignoreUnknownAttributes = false;
+ private static boolean _validateClass = true;
+ private static Globals _instance = null;
+
+ static Globals getInstance() {
+ if (_instance == null) {
+ _instance = new Globals();
+ _verbose = (System.getProperty("sun.tools.pack.verify.verbose") == null)
+ ? false : true;
+ _ignoreJarDirectories = (System.getProperty("ignoreJarDirectories") == null)
+ ? false : true;
+ }
+ return _instance;
+ }
+
+ static boolean ignoreCompileAttributes() {
+ return _ignoreCompileAttributes;
+ }
+
+ static boolean ignoreDebugAttributes() {
+ return _ignoreDebugAttributes;
+ }
+
+ static boolean ignoreUnknownAttributes() {
+ return _ignoreUnknownAttributes;
+ }
+
+ static boolean ignoreJarDirectories() {
+ return _ignoreJarDirectories;
+ }
+
+ static boolean validateClass() {
+ return _validateClass;
+ }
+
+ static void setCheckJarClassOrdering(boolean flag) {
+ _checkJarClassOrdering = flag;
+ }
+
+ static boolean checkJarClassOrdering() {
+ return _checkJarClassOrdering;
+ }
+
+ static boolean bitWiseClassCompare() {
+ return _bitWiseClassCompare;
+ }
+
+ static boolean setBitWiseClassCompare(boolean flag) {
+ return _bitWiseClassCompare = flag;
+ }
+
+ public static boolean setIgnoreCompileAttributes(boolean flag) {
+ return _ignoreCompileAttributes = flag;
+ }
+
+ static boolean setIgnoreDebugAttributes(boolean flag) {
+ return _ignoreDebugAttributes = flag;
+ }
+
+ static boolean setIgnoreUnknownAttributes(boolean flag) {
+ return _ignoreUnknownAttributes = flag;
+ }
+
+ static boolean setValidateClass(boolean flag) {
+ return _validateClass = flag;
+ }
+
+ static int getErrors() {
+ return errors;
+ }
+
+ static void trace(String s) {
+ if (_verbose) {
+ println(s);
+ }
+ }
+
+ static void print(String s) {
+ _pw.print(s);
+ }
+
+ static void println(String s) {
+ _pw.println(s);
+ }
+
+ static void log(String s) {
+ errors++;
+ _pw.println("ERROR:" + s);
+ }
+
+ static void lognoln(String s) {
+ errors++;
+ _pw.print(s);
+ }
+
+ private static PrintWriter openFile(String fileName) {
+ //Lets create the directory if it does not exist.
+ File f = new File(fileName);
+ File baseDir = f.getParentFile();
+ if (baseDir != null && baseDir.exists() == false) {
+ baseDir.mkdirs();
+ }
+ try {
+ return new PrintWriter(new FileWriter(f), true);
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ private static void closeFile() {
+ _pw.flush();
+ _pw.close();
+ }
+
+ static void printPropsToLog() {
+ println("Log started " + new Date(System.currentTimeMillis()));
+ print(System.getProperty("java.vm.version"));
+ println("\t" + System.getProperty("java.vm.name"));
+
+ println("System properties");
+ println("\tjava.home=" + System.getProperty("java.home"));
+ println("\tjava.class.version=" + System.getProperty("java.class.version"));
+ println("\tjava.class.path=" + System.getProperty("java.class.path"));
+ println("\tjava.ext.dirs=" + System.getProperty("java.ext.dirs"));
+ println("\tos.name=" + System.getProperty("os.name"));
+ println("\tos.arch=" + System.getProperty("os.arch"));
+ println("\tos.version=" + System.getProperty("os.version"));
+ println("\tuser.name=" + System.getProperty("user.name"));
+ println("\tuser.home=" + System.getProperty("user.home"));
+ println("\tuser.dir=" + System.getProperty("user.dir"));
+ println("\tLocale.getDefault=" + Locale.getDefault());
+ println("System properties end");
+ }
+
+ static void openLog(String s) {
+ _logFileName = (s != null) ? s : "." + File.separator + DEFAULT_LOG_FILE;
+ _logFileName = (new File(_logFileName).isDirectory())
+ ? _logFileName + File.separator + DEFAULT_LOG_FILE : _logFileName;
+ _pw = openFile(_logFileName);
+ printPropsToLog();
+ }
+
+ static void closeLog() {
+ closeFile();
+ }
+
+ static String getLogFileName() {
+ return _logFileName;
+ }
+
+ static void diffCharData(String s1, String s2) {
+ boolean diff = false;
+ char[] c1 = s1.toCharArray();
+ char[] c2 = s2.toCharArray();
+ if (c1.length != c2.length) {
+ diff = true;
+ Globals.log("Length differs: " + (c1.length - c2.length));
+ }
+ // Take the smaller of the two arrays to prevent Array...Exception
+ int minlen = (c1.length < c2.length) ? c1.length : c2.length;
+ for (int i = 0; i < c1.length; i++) {
+ if (c1[i] != c2[i]) {
+ diff = true;
+ Globals.lognoln("\t idx[" + i + "] 0x" + Integer.toHexString(c1[i]) + "<>" + "0x" + Integer.toHexString(c2[i]));
+ Globals.log(" -> " + c1[i] + "<>" + c2[i]);
+ }
+ }
+ }
+
+ static void diffByteData(String s1, String s2) {
+ boolean diff = false;
+ byte[] b1 = s1.getBytes();
+ byte[] b2 = s2.getBytes();
+
+ if (b1.length != b2.length) {
+ diff = true;
+ //(+) b1 is greater, (-) b2 is greater
+ Globals.log("Length differs diff: " + (b1.length - b2.length));
+ }
+ // Take the smaller of the two array to prevent Array...Exception
+ int minlen = (b1.length < b2.length) ? b1.length : b2.length;
+ for (int i = 0; i < b1.length; i++) {
+ if (b1[i] != b2[i]) {
+ diff = true;
+ Globals.log("\t" + "idx[" + i + "] 0x" + Integer.toHexString(b1[i]) + "<>" + "0x" + Integer.toHexString(b2[i]));
+ }
+ }
+ }
+
+ static void dumpToHex(String s) {
+ try {
+ dumpToHex(s.getBytes("UTF-8"));
+ } catch (UnsupportedEncodingException uce) {
+ throw new RuntimeException(uce);
+ }
+ }
+
+ static void dumpToHex(byte[] buffer) {
+ int linecount = 0;
+ byte[] b = new byte[16];
+ for (int i = 0; i < buffer.length; i += 16) {
+ if (buffer.length - i > 16) {
+ System.arraycopy(buffer, i, b, 0, 16);
+ print16Bytes(b, linecount);
+ linecount += 16;
+ } else {
+ System.arraycopy(buffer, i, b, 0, buffer.length - i);
+ for (int n = buffer.length - (i + 1); n < 16; n++) {
+ b[n] = 0;
+ }
+ print16Bytes(b, linecount);
+ linecount += 16;
+ }
+ }
+ Globals.log("-----------------------------------------------------------------");
+ }
+
+ static void print16Bytes(byte[] buffer, int linecount) {
+ final int MAX = 4;
+ Globals.lognoln(paddedHexString(linecount, 4) + " ");
+
+ for (int i = 0; i < buffer.length; i += 2) {
+ int iOut = pack2Bytes2Int(buffer[i], buffer[i + 1]);
+ Globals.lognoln(paddedHexString(iOut, 4) + " ");
+ }
+
+ Globals.lognoln("| ");
+
+ StringBuilder sb = new StringBuilder(new String(buffer));
+
+ for (int i = 0; i < buffer.length; i++) {
+ if (Character.isISOControl(sb.charAt(i))) {
+ sb.setCharAt(i, '.');
+ }
+ }
+ Globals.log(sb.toString());
+ }
+
+ static int pack2Bytes2Int(byte b1, byte b2) {
+ int out = 0x0;
+ out += b1;
+ out <<= 8;
+ out &= 0x0000ffff;
+ out |= 0x000000ff & b2;
+ return out;
+ }
+
+ static String paddedHexString(int n, int max) {
+ char[] c = Integer.toHexString(n).toCharArray();
+ char[] out = new char[max];
+
+ for (int i = 0; i < max; i++) {
+ out[i] = '0';
+ }
+ int offset = (max - c.length < 0) ? 0 : max - c.length;
+ for (int i = 0; i < c.length; i++) {
+ out[offset + i] = c[i];
+ }
+ return new String(out);
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/tools/pack200/pack200-verifier/src/sun/tools/pack/verify/JarFileCompare.java Wed Jul 05 17:21:22 2017 +0200
@@ -0,0 +1,199 @@
+/*
+ * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package sun.tools.pack.verify;
+
+import java.io.*;
+import java.util.*;
+import java.util.jar.*;
+
+class JarFileCompare {
+ /*
+ * @author ksrini
+ */
+
+ private static VerifyTreeSet getVerifyTreeSet(String jarPath) {
+ VerifyTreeSet vts = new VerifyTreeSet();
+ try {
+ JarFile j = new JarFile(jarPath);
+ for (JarEntry je : Collections.list((Enumeration<JarEntry>) j.entries())) {
+ if (!je.isDirectory()) { // totally ignore directories
+ vts.add(je.getName());
+ }
+ }
+ } catch (IOException ioe) {
+ throw new RuntimeException(ioe);
+ }
+ return vts;
+ }
+
+ private static LinkedList getListOfClasses(String jarPath) {
+ LinkedList l = new LinkedList();
+ try {
+ JarFile j = new JarFile(jarPath);
+ for (JarEntry je : Collections.list((Enumeration<JarEntry>) j.entries())) {
+ if (!je.isDirectory() && je.getName().endsWith(".class")) {
+ l.add(je.getName());
+ }
+ }
+ } catch (IOException ioe) {
+ throw new RuntimeException(ioe);
+ }
+ return l;
+ }
+
+ private static void jarDirectoryCompare(String jarPath1, String jarPath2) {
+ VerifyTreeSet vts1 = getVerifyTreeSet(jarPath1);
+ VerifyTreeSet vts2 = getVerifyTreeSet(jarPath2);
+
+ TreeSet diff1 = vts1.diff(vts2);
+ if (diff1.size() > 0) {
+ Globals.log("Left has the following entries that right does not have");
+ Globals.log(diff1.toString());
+ }
+ TreeSet diff2 = vts2.diff(vts1);
+ if (diff2.size() > 0) {
+ Globals.log("Right has the following entries that left does not have");
+ Globals.log(diff2.toString());
+ }
+ if (Globals.checkJarClassOrdering()) {
+ boolean error = false;
+ Globals.println("Checking Class Ordering");
+ LinkedList l1 = getListOfClasses(jarPath1);
+ LinkedList l2 = getListOfClasses(jarPath2);
+ if (l1.size() != l2.size()) {
+ error = true;
+ Globals.log("The number of classes differs");
+ Globals.log("\t" + l1.size() + "<>" + l2.size());
+ }
+ for (int i = 0; i < l1.size(); i++) {
+ String s1 = (String) l1.get(i);
+ String s2 = (String) l2.get(i);
+ if (s1.compareTo(s2) != 0) {
+ error = true;
+ Globals.log("Ordering differs at[" + i + "] = " + s1);
+ Globals.log("\t" + s2);
+ }
+ }
+ }
+ }
+
+ /*
+ * Returns true if the two Streams are bit identical, and false if they
+ * are not, no further diagnostics
+ */
+ static boolean compareStreams(InputStream is1, InputStream is2) {
+
+ BufferedInputStream bis1 = new BufferedInputStream(is1, 8192);
+ BufferedInputStream bis2 = new BufferedInputStream(is2, 8192);
+ try {
+ int i1, i2;
+ int count = 0;
+ while ((i1 = bis1.read()) == (i2 = bis2.read())) {
+ count++;
+ if (i1 < 0) {
+ // System.out.println("bytes read " + count);
+ return true; // got all the way to EOF
+ }
+ }
+ return false; // reads returned dif
+
+ } catch (IOException ioe) {
+ throw new RuntimeException(ioe);
+ }
+ }
+
+ private static void checkEntry(JarFile jf1, JarFile jf2, JarEntry je) throws IOException {
+ InputStream is1 = jf1.getInputStream(je);
+ InputStream is2 = jf2.getInputStream(je);
+ if (is1 != null && is2 != null) {
+ if (!compareStreams(jf1.getInputStream(je), jf2.getInputStream(je))) {
+ Globals.println("+++" + je.getName() + "+++");
+ Globals.log("Error: File:" + je.getName()
+ + " differs, use a diff util for further diagnostics");
+ }
+ } else {
+ Globals.println("+++" + je.getName() + "+++");
+ Globals.log("Error: File:" + je.getName() + " not found in " + jf2.getName());
+ }
+ }
+
+ /*
+ * Given two jar files we compare and see if the jarfiles have all the
+ * entries. The property ignoreJarDirectories is set to true by default
+ * which means that Directory entries in a jar may be ignore.
+ */
+ static void jarCompare(String jarPath1, String jarPath2) {
+ jarDirectoryCompare(jarPath1, jarPath2);
+
+ try {
+ JarFile jf1 = new JarFile(jarPath1);
+ JarFile jf2 = new JarFile(jarPath2);
+
+ int nclasses = 0;
+ int nentries = 0;
+ int entries_checked = 0;
+ int classes_checked = 0;
+
+ for (JarEntry je : Collections.list((Enumeration<JarEntry>) jf1.entries())) {
+ if (!je.isDirectory() && !je.getName().endsWith(".class")) {
+ nentries++;
+ } else if (je.getName().endsWith(".class")) {
+ nclasses++;
+ }
+ }
+
+ for (JarEntry je : Collections.list((Enumeration<JarEntry>) jf1.entries())) {
+ if (je.isDirectory()) {
+ continue; // Ignore directories
+ }
+ if (!je.getName().endsWith(".class")) {
+ entries_checked++;
+ if (je.getName().compareTo("META-INF/MANIFEST.MF") == 0) {
+ Manifest mf1 = new Manifest(jf1.getInputStream(je));
+ Manifest mf2 = new Manifest(jf2.getInputStream(je));
+ if (!mf1.equals(mf2)) {
+ Globals.log("Error: Manifests differ");
+ Globals.log("Manifest1");
+ Globals.log(mf1.getMainAttributes().entrySet().toString());
+ Globals.log("Manifest2");
+ Globals.log(mf2.getMainAttributes().entrySet().toString());
+ }
+ } else {
+ checkEntry(jf1, jf2, je);
+ }
+ } else if (Globals.bitWiseClassCompare() == true) {
+ checkEntry(jf1, jf2, je);
+ classes_checked++;
+ }
+ }
+ if (Globals.bitWiseClassCompare()) {
+ Globals.println("Class entries checked (byte wise)/Total Class entries = "
+ + classes_checked + "/" + nclasses);
+ }
+ Globals.println("Non-class entries checked/Total non-class entries = "
+ + entries_checked + "/" + nentries);
+ } catch (IOException ioe) {
+ throw new RuntimeException(ioe);
+ }
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/tools/pack200/pack200-verifier/src/sun/tools/pack/verify/Main.java Wed Jul 05 17:21:22 2017 +0200
@@ -0,0 +1,171 @@
+/*
+ * Copyright (c) 2010, 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.
+ */
+// The Main Entry point
+package sun.tools.pack.verify;
+
+import java.io.*;
+
+/**
+ * This class provides a convenient entry point to the pack200 verifier. This
+ * compares two classes, either in path or in an archive.
+ * @see xmlkit.XMLKit
+ * @author ksrini
+ */
+public class Main {
+
+ private static void syntax() {
+ System.out.println("Usage: ");
+ System.out.println("\tREFERENCE_CLASSPATH COMPARED_CLASSPATH [Options]");
+ System.out.println("\tOptions:");
+ System.out.println("\t\t-O check jar ordering");
+ System.out.println("\t\t-C ignore compile attributes (Deprecated, SourceFile, Synthetic, )");
+ System.out.println("\t\t-D ignore debug attributes (LocalVariable, LineNumber)");
+ System.out.println("\t\t-u ignore unknown attributes");
+ System.out.println("\t\t-V turn off class validation");
+ System.out.println("\t\t-c CLASS, compare CLASS only");
+ System.out.println("\t\t-b Compares all entries bitwise only");
+ System.out.println("\t\t-l Directory or Log File Name");
+ }
+
+ /**
+ * main entry point to the class file comparator, which compares semantically
+ * class files in a classpath or an archive.
+ * @param args String array as described below
+ * @throws RuntimeException
+ * <pre>
+ * Usage:
+ * ReferenceClasspath SpecimenClaspath [Options]
+ * Options:
+ * -O check jar ordering
+ * -C do not compare compile attributes (Deprecated, SourceFile, Synthetic)
+ * -D do not compare debug attribute (LocalVariableTable, LineNumberTable)
+ * -u ignore unknown attributes
+ * -V turn off class validation
+ * -c class, compare a single class
+ * -b compares all entries bitwise (fastest)
+ * -l directory or log file name
+ * </pre>
+ */
+ public static void main(String args[]) {
+ Globals.getInstance();
+ if (args == null || args.length < 2) {
+ syntax();
+ System.exit(1);
+ }
+ String refJarFileName = null;
+ String cmpJarFileName = null;
+ String specificClass = null;
+ String logDirFileName = null;
+
+ for (int i = 0; i < args.length; i++) {
+ if (i == 0) {
+ refJarFileName = args[0];
+ continue;
+ }
+ if (i == 1) {
+ cmpJarFileName = args[1];
+ continue;
+ }
+
+ if (args[i].startsWith("-O")) {
+ Globals.setCheckJarClassOrdering(true);
+ }
+
+ if (args[i].startsWith("-b")) {
+ Globals.setBitWiseClassCompare(true);
+ }
+
+ if (args[i].startsWith("-C")) {
+ Globals.setIgnoreCompileAttributes(true);
+ }
+
+ if (args[i].startsWith("-D")) {
+ Globals.setIgnoreDebugAttributes(true);
+ }
+
+ if (args[i].startsWith("-V")) {
+ Globals.setValidateClass(false);
+ }
+
+ if (args[i].startsWith("-c")) {
+ i++;
+ specificClass = args[i].trim();
+ }
+
+ if (args[i].startsWith("-u")) {
+ i++;
+ Globals.setIgnoreUnknownAttributes(true);
+ }
+
+ if (args[i].startsWith("-l")) {
+ i++;
+ logDirFileName = args[i].trim();
+ }
+ }
+
+ Globals.openLog(logDirFileName);
+
+ File refJarFile = new File(refJarFileName);
+ File cmpJarFile = new File(cmpJarFileName);
+
+ String f1 = refJarFile.getAbsoluteFile().toString();
+ String f2 = cmpJarFile.getAbsoluteFile().toString();
+
+ System.out.println("LogFile:" + Globals.getLogFileName());
+ System.out.println("Reference JAR:" + f1);
+ System.out.println("Compared JAR:" + f2);
+
+ Globals.println("LogFile:" + Globals.getLogFileName());
+ Globals.println("Reference JAR:" + f1);
+ Globals.println("Compared JAR:" + f2);
+
+ Globals.println("Ignore Compile Attributes:" + Globals.ignoreCompileAttributes());
+ Globals.println("Ignore Debug Attributes:" + Globals.ignoreDebugAttributes());
+ Globals.println("Ignore Unknown Attributes:" + Globals.ignoreUnknownAttributes());
+ Globals.println("Class ordering check:" + Globals.checkJarClassOrdering());
+ Globals.println("Class validation check:" + Globals.validateClass());
+ Globals.println("Bit-wise compare:" + Globals.bitWiseClassCompare());
+ Globals.println("ClassName:" + ((specificClass == null) ? "ALL" : specificClass));
+
+ if (specificClass == null && Globals.bitWiseClassCompare() == true) {
+ JarFileCompare.jarCompare(refJarFileName, cmpJarFileName);
+ } else {
+ try {
+ ClassCompare.compareClass(refJarFileName, cmpJarFileName, specificClass);
+ } catch (Exception e) {
+ Globals.log("Exception " + e);
+ throw new RuntimeException(e);
+ }
+ }
+
+ if (Globals.getErrors() > 0) {
+ System.out.println("FAIL");
+ Globals.println("FAIL");
+ System.exit(Globals.getErrors());
+ }
+
+ System.out.println("PASS");
+ Globals.println("PASS");
+ System.exit(Globals.getErrors());
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/tools/pack200/pack200-verifier/src/sun/tools/pack/verify/VerifyTreeSet.java Wed Jul 05 17:21:22 2017 +0200
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package sun.tools.pack.verify;
+
+import java.util.*;
+/*
+ * @author ksrini
+ */
+
+class VerifyTreeSet<K> extends java.util.TreeSet {
+
+ VerifyTreeSet() {
+ super();
+ }
+
+ public VerifyTreeSet(Comparator c) {
+ super(c);
+ }
+
+ public TreeSet<K> diff(TreeSet in) {
+ TreeSet<K> delta = (TreeSet<K>) this.clone();
+ delta.removeAll(in);
+ return delta;
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/tools/pack200/pack200-verifier/src/xmlkit/ClassReader.java Wed Jul 05 17:21:22 2017 +0200
@@ -0,0 +1,1003 @@
+/*
+ * Copyright (c) 2010, 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.
+ */
+package xmlkit; // -*- mode: java; indent-tabs-mode: nil -*-
+
+import java.util.*;
+import java.util.jar.*;
+import java.lang.reflect.*;
+import java.io.*;
+import xmlkit.XMLKit.Element;
+
+/*
+ * @author jrose
+ */
+public class ClassReader extends ClassSyntax {
+
+ private static final CommandLineParser CLP = new CommandLineParser(""
+ + "-source: +> = \n"
+ + "-dest: +> = \n"
+ + "-encoding: +> = \n"
+ + "-jcov $ \n -nojcov !-jcov \n"
+ + "-verbose $ \n -noverbose !-verbose \n"
+ + "-pretty $ \n -nopretty !-pretty \n"
+ + "-keepPath $ \n -nokeepPath !-keepPath \n"
+ + "-keepCP $ \n -nokeepCP !-keepCP \n"
+ + "-keepBytes $ \n -nokeepBytes !-keepBytes \n"
+ + "-parseBytes $ \n -noparseBytes !-parseBytes \n"
+ + "-resolveRefs $ \n -noresolveRefs !-resolveRefs \n"
+ + "-keepOrder $ \n -nokeepOrder !-keepOrder \n"
+ + "-keepSizes $ \n -nokeepSizes !-keepSizes \n"
+ + "-continue $ \n -nocontinue !-continue \n"
+ + "-attrDef & \n"
+ + "-@ >-@ . \n"
+ + "- +? \n"
+ + "\n");
+
+ public static void main(String[] ava) throws IOException {
+ ArrayList<String> av = new ArrayList<String>(Arrays.asList(ava));
+ HashMap<String, String> props = new HashMap<String, String>();
+ props.put("-encoding:", "UTF8"); // default
+ props.put("-keepOrder", null); // CLI default
+ props.put("-pretty", "1"); // CLI default
+ props.put("-continue", "1"); // CLI default
+ CLP.parse(av, props);
+ //System.out.println(props+" ++ "+av);
+ File source = asFile(props.get("-source:"));
+ File dest = asFile(props.get("-dest:"));
+ String encoding = props.get("-encoding:");
+ boolean contError = props.containsKey("-continue");
+ ClassReader options = new ClassReader();
+ options.copyOptionsFrom(props);
+ /*
+ if (dest == null && av.size() > 1) {
+ dest = File.createTempFile("TestOut", ".dir", new File("."));
+ dest.delete();
+ if (!dest.mkdir())
+ throw new RuntimeException("Cannot create "+dest);
+ System.out.println("Writing results to "+dest);
+ }
+ */
+ if (av.isEmpty()) {
+ av.add("doit"); //to enter this loop
+ }
+ boolean readList = false;
+ for (String a : av) {
+ if (readList) {
+ readList = false;
+ InputStream fin;
+ if (a.equals("-")) {
+ fin = System.in;
+ } else {
+ fin = new FileInputStream(a);
+ }
+
+ BufferedReader files = makeReader(fin, encoding);
+ for (String file; (file = files.readLine()) != null;) {
+ doFile(file, source, dest, options, encoding, contError);
+ }
+ if (fin != System.in) {
+ fin.close();
+ }
+ } else if (a.equals("-@")) {
+ readList = true;
+ } else if (a.startsWith("-")) {
+ throw new RuntimeException("Bad flag argument: " + a);
+ } else if (source.getName().endsWith(".jar")) {
+ doJar(a, source, dest, options, encoding, contError);
+ } else {
+ doFile(a, source, dest, options, encoding, contError);
+ }
+ }
+ }
+
+ private static File asFile(String str) {
+ return (str == null) ? null : new File(str);
+ }
+
+ private static void doFile(String a,
+ File source, File dest,
+ ClassReader options, String encoding,
+ boolean contError) throws IOException {
+ if (!contError) {
+ doFile(a, source, dest, options, encoding);
+ } else {
+ try {
+ doFile(a, source, dest, options, encoding);
+ } catch (Exception ee) {
+ System.out.println("Error processing " + source + ": " + ee);
+ }
+ }
+ }
+
+ private static void doJar(String a, File source, File dest, ClassReader options,
+ String encoding, Boolean contError) throws IOException {
+ try {
+ JarFile jf = new JarFile(source);
+ for (JarEntry je : Collections.list((Enumeration<JarEntry>) jf.entries())) {
+ String name = je.getName();
+ if (!name.endsWith(".class")) {
+ continue;
+ }
+ doStream(name, jf.getInputStream(je), dest, options, encoding);
+ }
+ } catch (IOException ioe) {
+ if (contError) {
+ System.out.println("Error processing " + source + ": " + ioe);
+ } else {
+ throw ioe;
+ }
+ }
+ }
+
+ private static void doStream(String a, InputStream in, File dest,
+ ClassReader options, String encoding) throws IOException {
+
+ File f = new File(a);
+ ClassReader cr = new ClassReader(options);
+ Element e = cr.readFrom(in);
+
+ OutputStream out;
+ if (dest == null) {
+ //System.out.println(e.prettyString());
+ out = System.out;
+ } else {
+ File outf = new File(dest, f.isAbsolute() ? f.getName() : f.getPath());
+ String outName = outf.getName();
+ File outSubdir = outf.getParentFile();
+ outSubdir.mkdirs();
+ int extPos = outName.lastIndexOf('.');
+ if (extPos > 0) {
+ outf = new File(outSubdir, outName.substring(0, extPos) + ".xml");
+ }
+ out = new FileOutputStream(outf);
+ }
+
+ Writer outw = makeWriter(out, encoding);
+ if (options.pretty || !options.keepOrder) {
+ e.writePrettyTo(outw);
+ } else {
+ e.writeTo(outw);
+ }
+ if (out == System.out) {
+ outw.write("\n");
+ outw.flush();
+ } else {
+ outw.close();
+ }
+ }
+
+ private static void doFile(String a,
+ File source, File dest,
+ ClassReader options, String encoding) throws IOException {
+ File inf = new File(source, a);
+ if (dest != null && options.verbose) {
+ System.out.println("Reading " + inf);
+ }
+
+ BufferedInputStream in = new BufferedInputStream(new FileInputStream(inf));
+
+ doStream(a, in, dest, options, encoding);
+
+ }
+
+ public static BufferedReader makeReader(InputStream in, String encoding) throws IOException {
+ // encoding in DEFAULT, '', UTF8, 8BIT, , or any valid encoding name
+ if (encoding.equals("8BIT")) {
+ encoding = EIGHT_BIT_CHAR_ENCODING;
+ }
+ if (encoding.equals("UTF8")) {
+ encoding = UTF8_ENCODING;
+ }
+ if (encoding.equals("DEFAULT")) {
+ encoding = null;
+ }
+ if (encoding.equals("-")) {
+ encoding = null;
+ }
+ Reader inw;
+ in = new BufferedInputStream(in); // add buffering
+ if (encoding == null) {
+ inw = new InputStreamReader(in);
+ } else {
+ inw = new InputStreamReader(in, encoding);
+ }
+ return new BufferedReader(inw); // add buffering
+ }
+
+ public static Writer makeWriter(OutputStream out, String encoding) throws IOException {
+ // encoding in DEFAULT, '', UTF8, 8BIT, , or any valid encoding name
+ if (encoding.equals("8BIT")) {
+ encoding = EIGHT_BIT_CHAR_ENCODING;
+ }
+ if (encoding.equals("UTF8")) {
+ encoding = UTF8_ENCODING;
+ }
+ if (encoding.equals("DEFAULT")) {
+ encoding = null;
+ }
+ if (encoding.equals("-")) {
+ encoding = null;
+ }
+ Writer outw;
+ if (encoding == null) {
+ outw = new OutputStreamWriter(out);
+ } else {
+ outw = new OutputStreamWriter(out, encoding);
+ }
+ return new BufferedWriter(outw); // add buffering
+ }
+
+ public Element result() {
+ return cfile;
+ }
+ protected InputStream in;
+ protected ByteArrayOutputStream buf = new ByteArrayOutputStream(1024);
+ protected byte cpTag[];
+ protected String cpName[];
+ protected String[] callables; // varies
+ public static final String REF_PREFIX = "#";
+ // input options
+ public boolean pretty = false;
+ public boolean verbose = false;
+ public boolean keepPath = false;
+ public boolean keepCP = false;
+ public boolean keepBytes = false;
+ public boolean parseBytes = true;
+ public boolean resolveRefs = true;
+ public boolean keepOrder = true;
+ public boolean keepSizes = false;
+
+ public ClassReader() {
+ super.cfile = new Element("ClassFile");
+ }
+
+ public ClassReader(ClassReader options) {
+ this();
+ copyOptionsFrom(options);
+ }
+
+ public void copyOptionsFrom(ClassReader options) {
+ pretty = options.pretty;
+ verbose = options.verbose;
+ keepPath = options.keepPath;
+ keepCP = options.keepCP;
+ keepBytes = options.keepBytes;
+ parseBytes = options.parseBytes;
+ resolveRefs = options.resolveRefs;
+ keepSizes = options.keepSizes;
+ keepOrder = options.keepOrder;
+ attrTypes = options.attrTypes;
+ }
+
+ public void copyOptionsFrom(Map<String, String> options) {
+ if (options.containsKey("-pretty")) {
+ pretty = (options.get("-pretty") != null);
+ }
+ if (options.containsKey("-verbose")) {
+ verbose = (options.get("-verbose") != null);
+ }
+ if (options.containsKey("-keepPath")) {
+ keepPath = (options.get("-keepPath") != null);
+ }
+ if (options.containsKey("-keepCP")) {
+ keepCP = (options.get("-keepCP") != null);
+ }
+ if (options.containsKey("-keepBytes")) {
+ keepBytes = (options.get("-keepBytes") != null);
+ }
+ if (options.containsKey("-parseBytes")) {
+ parseBytes = (options.get("-parseBytes") != null);
+ }
+ if (options.containsKey("-resolveRefs")) {
+ resolveRefs = (options.get("-resolveRefs") != null);
+ }
+ if (options.containsKey("-keepSizes")) {
+ keepSizes = (options.get("-keepSizes") != null);
+ }
+ if (options.containsKey("-keepOrder")) {
+ keepOrder = (options.get("-keepOrder") != null);
+ }
+ if (options.containsKey("-attrDef")) {
+ addAttrTypes(options.get("-attrDef").split(" "));
+ }
+ if (options.get("-jcov") != null) {
+ addJcovAttrTypes();
+ }
+ }
+
+ public Element readFrom(InputStream in) throws IOException {
+ this.in = in;
+ // read the file header
+ int magic = u4();
+ if (magic != 0xCAFEBABE) {
+ throw new RuntimeException("bad magic number " + Integer.toHexString(magic));
+ }
+ cfile.setAttr("magic", "" + magic);
+ int minver = u2();
+ int majver = u2();
+ cfile.setAttr("minver", "" + minver);
+ cfile.setAttr("majver", "" + majver);
+ readCP();
+ readClass();
+ return result();
+ }
+
+ public Element readFrom(File file) throws IOException {
+ InputStream in = null;
+ try {
+ in = new FileInputStream(file);
+ Element e = readFrom(new BufferedInputStream(in));
+ if (keepPath) {
+ e.setAttr("path", file.toString());
+ }
+ return e;
+ } finally {
+ if (in != null) {
+ in.close();
+ }
+ }
+ }
+
+ private void readClass() throws IOException {
+ klass = new Element("Class");
+ cfile.add(klass);
+ int flags = u2();
+ String thisk = cpRef();
+ String superk = cpRef();
+ klass.setAttr("name", thisk);
+ boolean flagsSync = ((flags & Modifier.SYNCHRONIZED) != 0);
+ flags &= ~Modifier.SYNCHRONIZED;
+ String flagString = flagString(flags, klass);
+ if (!flagsSync) {
+ if (flagString.length() > 0) {
+ flagString += " ";
+ }
+ flagString += "!synchronized";
+ }
+ klass.setAttr("flags", flagString);
+ klass.setAttr("super", superk);
+ for (int len = u2(), i = 0; i < len; i++) {
+ String interk = cpRef();
+ klass.add(new Element("Interface", "name", interk));
+ }
+ Element fields = readMembers("Field");
+ klass.addAll(fields);
+ Element methods = readMembers("Method");
+ if (!keepOrder) {
+ methods.sort();
+ }
+ klass.addAll(methods);
+ readAttributesFor(klass);
+ klass.trimToSize();
+ if (keepSizes) {
+ attachTo(cfile, formatAttrSizes());
+ }
+ if (paddingSize != 0) {
+ cfile.setAttr("padding", "" + paddingSize);
+ }
+ }
+
+ private Element readMembers(String kind) throws IOException {
+ int len = u2();
+ Element members = new Element(len);
+ for (int i = 0; i < len; i++) {
+ Element member = new Element(kind);
+ int flags = u2();
+ String name = cpRef();
+ String type = cpRef();
+ member.setAttr("name", name);
+ member.setAttr("type", type);
+ member.setAttr("flags", flagString(flags, member));
+ readAttributesFor(member);
+ member.trimToSize();
+ members.add(member);
+ }
+ return members;
+ }
+
+ protected String flagString(int flags, Element holder) {
+ // Superset of Modifier.toString.
+ int kind = 0;
+ if (holder.getName() == "Field") {
+ kind = 1;
+ }
+ if (holder.getName() == "Method") {
+ kind = 2;
+ }
+ StringBuffer sb = new StringBuffer();
+ for (int i = 0; flags != 0; i++, flags >>>= 1) {
+ if ((flags & 1) != 0) {
+ if (sb.length() > 0) {
+ sb.append(' ');
+ }
+ if (i < modifierNames.length) {
+ String[] names = modifierNames[i];
+ String name = (kind < names.length) ? names[kind] : null;
+ for (String name2 : names) {
+ if (name != null) {
+ break;
+ }
+ name = name2;
+ }
+ sb.append(name);
+ } else {
+ sb.append("#").append(1 << i);
+ }
+ }
+ }
+ return sb.toString();
+ }
+
+ private void readAttributesFor(Element x) throws IOException {
+ Element prevCurrent;
+ Element y = new Element();
+ if (x.getName() == "Code") {
+ prevCurrent = currentCode;
+ currentCode = x;
+ } else {
+ prevCurrent = currentMember;
+ currentMember = x;
+ }
+ for (int len = u2(), i = 0; i < len; i++) {
+ int ref = u2();
+ String uname = cpName(ref).intern();
+ String refName = uname;
+ if (!resolveRefs) {
+ refName = (REF_PREFIX + ref).intern();
+ }
+ String qname = (x.getName() + "." + uname).intern();
+ String wname = ("*." + uname).intern();
+ String type = attrTypes.get(qname);
+ if (type == null || "".equals(type)) {
+ type = attrTypes.get(wname);
+ }
+ if ("".equals(type)) {
+ type = null;
+ }
+ int size = u4();
+ int[] countVar = attrSizes.get(qname);
+ if (countVar == null) {
+ attrSizes.put(qname, countVar = new int[2]);
+ }
+ countVar[0] += 1;
+ countVar[1] += size;
+ buf.reset();
+ for (int j = 0; j < size; j++) {
+ buf.write(u1());
+ }
+ if (type == null && size == 0) {
+ y.add(new Element(uname)); // <Bridge>, etc.
+ } else if (type == null) {
+ //System.out.println("Warning: No attribute type description: "+qname);
+ // write cdata attribute
+ Element a = new Element("Attribute",
+ new String[]{"Name", refName},
+ buf.toString(EIGHT_BIT_CHAR_ENCODING));
+ a.addContent(getCPDigest());
+ y.add(a);
+ } else if (type.equals("")) {
+ // ignore this attribute...
+ } else {
+ InputStream in0 = in;
+ int fileSize0 = fileSize;
+ ByteArrayInputStream in1 = new ByteArrayInputStream(buf.toByteArray());
+ boolean ok = false;
+ try {
+ in = in1;
+ // parse according to type desc.
+ Element aval;
+ if (type.equals("<Code>...")) {
+ // delve into Code attribute
+ aval = readCode();
+ } else if (type.equals("<Frame>...")) {
+ // delve into StackMap attribute
+ aval = readStackMap(false);
+ } else if (type.equals("<FrameX>...")) {
+ // delve into StackMap attribute
+ aval = readStackMap(true);
+ } else if (type.startsWith("[")) {
+ aval = readAttributeCallables(type);
+ } else {
+ aval = readAttribute(type);
+ }
+ //System.out.println("attachTo 1 "+y+" <- "+aval);
+ attachTo(y, aval);
+ if (false
+ && in1.available() != 0) {
+ throw new RuntimeException("extra bytes in " + qname + " :" + in1.available());
+ }
+ ok = true;
+ } finally {
+ in = in0;
+ fileSize = fileSize0;
+ if (!ok) {
+ System.out.println("*** Failed to read " + type);
+ }
+ }
+ }
+ }
+ if (x.getName() == "Code") {
+ currentCode = prevCurrent;
+ } else {
+ currentMember = prevCurrent;
+ }
+ if (!keepOrder) {
+ y.sort();
+ y.sortAttrs();
+ }
+ //System.out.println("attachTo 2 "+x+" <- "+y);
+ attachTo(x, y);
+ }
+ private int fileSize = 0;
+ private int paddingSize = 0;
+ private HashMap<String, int[]> attrSizes = new HashMap<String, int[]>();
+
+ private Element formatAttrSizes() {
+ Element e = new Element("Sizes");
+ e.setAttr("fileSize", "" + fileSize);
+ for (Map.Entry<String, int[]> ie : attrSizes.entrySet()) {
+ int[] countVar = ie.getValue();
+ e.add(new Element("AttrSize",
+ "name", ie.getKey().toString(),
+ "count", "" + countVar[0],
+ "size", "" + countVar[1]));
+ }
+ return e;
+ }
+
+ private void attachTo(Element x, Object aval0) {
+ if (aval0 == null) {
+ return;
+ }
+ //System.out.println("attachTo "+x+" : "+aval0);
+ if (!(aval0 instanceof Element)) {
+ x.add(aval0);
+ return;
+ }
+ Element aval = (Element) aval0;
+ if (!aval.isAnonymous()) {
+ x.add(aval);
+ return;
+ }
+ for (int imax = aval.attrSize(), i = 0; i < imax; i++) {
+ //%%
+ attachAttrTo(x, aval.getAttrName(i), aval.getAttr(i));
+ }
+ x.addAll(aval);
+ }
+
+ private void attachAttrTo(Element x, String aname, String aval) {
+ //System.out.println("attachAttrTo "+x+" : "+aname+"="+aval);
+ String aval0 = x.getAttr(aname);
+ if (aval0 != null) {
+ aval = aval0 + " " + aval;
+ }
+ x.setAttr(aname, aval);
+ }
+
+ private Element readAttributeCallables(String type) throws IOException {
+ assert (callables == null);
+ callables = getBodies(type);
+ Element res = readAttribute(callables[0]);
+ callables = null;
+ return res;
+ }
+
+ private Element readAttribute(String type) throws IOException {
+ //System.out.println("readAttribute "+type);
+ Element aval = new Element();
+ String nextAttrName = null;
+ for (int len = type.length(), next, i = 0; i < len; i = next) {
+ String value;
+ switch (type.charAt(i)) {
+ case '<':
+ assert (nextAttrName == null);
+ next = type.indexOf('>', ++i);
+ String form = type.substring(i, next++);
+ if (form.indexOf('=') < 0) {
+ // elem_placement = '<' elemname '>'
+ assert (aval.attrSize() == 0);
+ assert (aval.isAnonymous());
+ aval.setName(form.intern());
+ } else {
+ // attr_placement = '<' attrname '=' (value)? '>'
+ int eqPos = form.indexOf('=');
+ nextAttrName = form.substring(0, eqPos).intern();
+ if (eqPos != form.length() - 1) {
+ value = form.substring(eqPos + 1);
+ attachAttrTo(aval, nextAttrName, value);
+ nextAttrName = null;
+ }
+ // ...else subsequent type parsing will find the attr value
+ // and add it as "nextAttrName".
+ }
+ continue;
+ case '(':
+ next = type.indexOf(')', ++i);
+ int callee = Integer.parseInt(type.substring(i, next++));
+ attachTo(aval, readAttribute(callables[callee]));
+ continue;
+ case 'N': // replication = 'N' int '[' type ... ']'
+ {
+ int count = getInt(type.charAt(i + 1), false);
+ assert (count >= 0);
+ next = i + 2;
+ String type1 = getBody(type, next);
+ next += type1.length() + 2; // skip body and brackets
+ for (int j = 0; j < count; j++) {
+ attachTo(aval, readAttribute(type1));
+ }
+ }
+ continue;
+ case 'T': // union = 'T' any_int union_case* '(' ')' '[' body ']'
+ int tagValue;
+ if (type.charAt(++i) == 'S') {
+ tagValue = getInt(type.charAt(++i), true);
+ } else {
+ tagValue = getInt(type.charAt(i), false);
+ }
+ attachAttrTo(aval, "tag", "" + tagValue); // always named "tag"
+ ++i; // skip the int type char
+ // union_case = '(' uc_tag (',' uc_tag)* ')' '[' body ']'
+ // uc_tag = ('-')? digit+
+ for (boolean foundCase = false;; i = next) {
+ assert (type.charAt(i) == '(');
+ next = type.indexOf(')', ++i);
+ assert (next >= i);
+ if (type.charAt(next - 1) == '\\'
+ && type.charAt(next - 2) != '\\') // Skip an escaped paren.
+ {
+ next = type.indexOf(')', next + 1);
+ }
+ String caseStr = type.substring(i, next++);
+ String type1 = getBody(type, next);
+ next += type1.length() + 2; // skip body and brackets
+ boolean lastCase = (caseStr.length() == 0);
+ if (!foundCase
+ && (lastCase || matchTag(tagValue, caseStr))) {
+ foundCase = true;
+ // Execute this body.
+ attachTo(aval, readAttribute(type1));
+ }
+ if (lastCase) {
+ break;
+ }
+ }
+ continue;
+ case 'B':
+ case 'H':
+ case 'I': // int = oneof "BHI"
+ next = i + 1;
+ value = "" + getInt(type.charAt(i), false);
+ break;
+ case 'K':
+ assert ("IJFDLQ".indexOf(type.charAt(i + 1)) >= 0);
+ assert (type.charAt(i + 2) == 'H'); // only H works for now
+ next = i + 3;
+ value = cpRef();
+ break;
+ case 'R':
+ assert ("CSDFMIU?".indexOf(type.charAt(i + 1)) >= 0);
+ assert (type.charAt(i + 2) == 'H'); // only H works for now
+ next = i + 3;
+ value = cpRef();
+ break;
+ case 'P': // bci = 'P' int
+ next = i + 2;
+ value = "" + getInt(type.charAt(i + 1), false);
+ break;
+ case 'S': // signed_int = 'S' int
+ next = i + 2;
+ value = "" + getInt(type.charAt(i + 1), true);
+ break;
+ case 'F':
+ next = i + 2;
+ value = flagString(getInt(type.charAt(i + 1), false), currentMember);
+ break;
+ default:
+ throw new RuntimeException("bad attr format '" + type.charAt(i) + "': " + type);
+ }
+ // store the value
+ if (nextAttrName != null) {
+ attachAttrTo(aval, nextAttrName, value);
+ nextAttrName = null;
+ } else {
+ attachTo(aval, value);
+ }
+ }
+ //System.out.println("readAttribute => "+aval);
+ assert (nextAttrName == null);
+ return aval;
+ }
+
+ private int getInt(char ch, boolean signed) throws IOException {
+ if (signed) {
+ switch (ch) {
+ case 'B':
+ return (byte) u1();
+ case 'H':
+ return (short) u2();
+ case 'I':
+ return (int) u4();
+ }
+ } else {
+ switch (ch) {
+ case 'B':
+ return u1();
+ case 'H':
+ return u2();
+ case 'I':
+ return u4();
+ }
+ }
+ assert ("BHIJ".indexOf(ch) >= 0);
+ return 0;
+ }
+
+ private Element readCode() throws IOException {
+ int stack = u2();
+ int local = u2();
+ int length = u4();
+ StringBuilder sb = new StringBuilder(length);
+ for (int i = 0; i < length; i++) {
+ sb.append((char) u1());
+ }
+ String bytecodes = sb.toString();
+ Element e = new Element("Code",
+ "stack", "" + stack,
+ "local", "" + local);
+ Element bytes = new Element("Bytes", (String[]) null, bytecodes);
+ if (keepBytes) {
+ e.add(bytes);
+ }
+ if (parseBytes) {
+ e.add(parseByteCodes(bytecodes));
+ }
+ for (int len = u2(), i = 0; i < len; i++) {
+ int start = u2();
+ int end = u2();
+ int catsh = u2();
+ String clasz = cpRef();
+ e.add(new Element("Handler",
+ "start", "" + start,
+ "end", "" + end,
+ "catch", "" + catsh,
+ "class", clasz));
+ }
+ readAttributesFor(e);
+ e.trimToSize();
+ return e;
+ }
+
+ private Element parseByteCodes(String bytecodes) {
+ Element e = InstructionSyntax.parse(bytecodes);
+ for (Element ins : e.elements()) {
+ Number ref = ins.getAttrNumber("ref");
+ if (ref != null && resolveRefs) {
+ int id = ref.intValue();
+ String val = cpName(id);
+ if (ins.getName().startsWith("ldc")) {
+ // Yuck: Arb. string cannot be an XML attribute.
+ ins.add(val);
+ val = "";
+ byte tag = (id >= 0 && id < cpTag.length) ? cpTag[id] : 0;
+ if (tag != 0) {
+ ins.setAttrLong("tag", tag);
+ }
+ }
+ if (ins.getName() == "invokeinterface"
+ && computeInterfaceNum(val) == ins.getAttrLong("num")) {
+ ins.setAttr("num", null); // garbage bytes
+ }
+ ins.setAttr("ref", null);
+ ins.setAttr("val", val);
+ }
+ }
+ return e;
+ }
+
+ private Element readStackMap(boolean hasXOption) throws IOException {
+ Element result = new Element();
+ Element bytes = currentCode.findElement("Bytes");
+ assert (bytes != null && bytes.size() == 1);
+ int byteLength = ((String) bytes.get(0)).length();
+ boolean uoffsetIsU4 = (byteLength >= (1 << 16));
+ boolean ulocalvarIsU4 = currentCode.getAttrLong("local") >= (1 << 16);
+ boolean ustackIsU4 = currentCode.getAttrLong("stack") >= (1 << 16);
+ if (hasXOption || uoffsetIsU4 || ulocalvarIsU4 || ustackIsU4) {
+ Element flags = new Element("StackMapFlags");
+ if (hasXOption) {
+ flags.setAttr("hasXOption", "true");
+ }
+ if (uoffsetIsU4) {
+ flags.setAttr("uoffsetIsU4", "true");
+ }
+ if (ulocalvarIsU4) {
+ flags.setAttr("ulocalvarIsU4", "true");
+ }
+ if (ustackIsU4) {
+ flags.setAttr("ustackIsU4", "true");
+ }
+ currentCode.add(flags);
+ }
+ int frame_count = (uoffsetIsU4 ? u4() : u2());
+ for (int i = 0; i < frame_count; i++) {
+ int bci = (uoffsetIsU4 ? u4() : u2());
+ int flags = (hasXOption ? u1() : 0);
+ Element frame = new Element("Frame");
+ result.add(frame);
+ if (flags != 0) {
+ frame.setAttr("flags", "" + flags);
+ }
+ frame.setAttr("bci", "" + bci);
+ // Scan local and stack types in this frame:
+ final int LOCALS = 0, STACK = 1;
+ for (int j = LOCALS; j <= STACK; j++) {
+ int typeSize;
+ if (j == LOCALS) {
+ typeSize = (ulocalvarIsU4 ? u4() : u2());
+ } else { // STACK
+ typeSize = (ustackIsU4 ? u4() : u2());
+ }
+ Element types = new Element(j == LOCALS ? "Local" : "Stack");
+ for (int k = 0; k < typeSize; k++) {
+ int tag = u1();
+ Element type = new Element(itemTagName(tag));
+ types.add(type);
+ switch (tag) {
+ case ITEM_Object:
+ type.setAttr("class", cpRef());
+ break;
+ case ITEM_Uninitialized:
+ case ITEM_ReturnAddress:
+ type.setAttr("bci", "" + (uoffsetIsU4 ? u4() : u2()));
+ break;
+ }
+ }
+ if (types.size() > 0) {
+ frame.add(types);
+ }
+ }
+ }
+ return result;
+ }
+
+ private void readCP() throws IOException {
+ int cpLen = u2();
+ cpTag = new byte[cpLen];
+ cpName = new String[cpLen];
+ int cpTem[][] = new int[cpLen][];
+ for (int i = 1; i < cpLen; i++) {
+ cpTag[i] = (byte) u1();
+ switch (cpTag[i]) {
+ case CONSTANT_Utf8:
+ buf.reset();
+ for (int len = u2(), j = 0; j < len; j++) {
+ buf.write(u1());
+ }
+ cpName[i] = buf.toString(UTF8_ENCODING);
+ break;
+ case CONSTANT_Integer:
+ cpName[i] = String.valueOf((int) u4());
+ break;
+ case CONSTANT_Float:
+ cpName[i] = String.valueOf(Float.intBitsToFloat(u4()));
+ break;
+ case CONSTANT_Long:
+ cpName[i] = String.valueOf(u8());
+ i += 1;
+ break;
+ case CONSTANT_Double:
+ cpName[i] = String.valueOf(Double.longBitsToDouble(u8()));
+ i += 1;
+ break;
+ case CONSTANT_Class:
+ case CONSTANT_String:
+ cpTem[i] = new int[]{u2()};
+ break;
+ case CONSTANT_Fieldref:
+ case CONSTANT_Methodref:
+ case CONSTANT_InterfaceMethodref:
+ case CONSTANT_NameAndType:
+ cpTem[i] = new int[]{u2(), u2()};
+ break;
+ }
+ }
+ for (int i = 1; i < cpLen; i++) {
+ switch (cpTag[i]) {
+ case CONSTANT_Class:
+ case CONSTANT_String:
+ cpName[i] = cpName[cpTem[i][0]];
+ break;
+ case CONSTANT_NameAndType:
+ cpName[i] = cpName[cpTem[i][0]] + " " + cpName[cpTem[i][1]];
+ break;
+ }
+ }
+ // do fieldref et al after nameandtype are all resolved
+ for (int i = 1; i < cpLen; i++) {
+ switch (cpTag[i]) {
+ case CONSTANT_Fieldref:
+ case CONSTANT_Methodref:
+ case CONSTANT_InterfaceMethodref:
+ cpName[i] = cpName[cpTem[i][0]] + " " + cpName[cpTem[i][1]];
+ break;
+ }
+ }
+ cpool = new Element("ConstantPool", cpName.length);
+ for (int i = 0; i < cpName.length; i++) {
+ if (cpName[i] == null) {
+ continue;
+ }
+ cpool.add(new Element(cpTagName(cpTag[i]),
+ new String[]{"id", "" + i},
+ cpName[i]));
+ }
+ if (keepCP) {
+ cfile.add(cpool);
+ }
+ }
+
+ private String cpRef() throws IOException {
+ int ref = u2();
+ if (resolveRefs) {
+ return cpName(ref);
+ } else {
+ return REF_PREFIX + ref;
+ }
+ }
+
+ private String cpName(int id) {
+ if (id >= 0 && id < cpName.length) {
+ return cpName[id];
+ } else {
+ return "[CP#" + Integer.toHexString(id) + "]";
+ }
+ }
+
+ private long u8() throws IOException {
+ return ((long) u4() << 32) + (((long) u4() << 32) >>> 32);
+ }
+
+ private int u4() throws IOException {
+ return (u2() << 16) + u2();
+ }
+
+ private int u2() throws IOException {
+ return (u1() << 8) + u1();
+ }
+
+ private int u1() throws IOException {
+ int x = in.read();
+ if (x < 0) {
+ paddingSize++;
+ return 0; // error recovery
+ }
+ fileSize++;
+ assert (x == (x & 0xFF));
+ return x;
+ }
+}
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/tools/pack200/pack200-verifier/src/xmlkit/ClassSyntax.java Wed Jul 05 17:21:22 2017 +0200
@@ -0,0 +1,518 @@
+/*
+ * Copyright (c) 2010, 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.
+ */
+package xmlkit; // -*- mode: java; indent-tabs-mode: nil -*-
+import xmlkit.XMLKit.*;
+
+import java.util.*;
+import java.security.MessageDigest;
+import java.nio.ByteBuffer;
+import xmlkit.XMLKit.Element;
+/*
+ * @author jrose
+ */
+public abstract class ClassSyntax {
+
+ public interface GetCPIndex {
+
+ int getCPIndex(int tag, String name); // cp finder
+ }
+ public static final int CONSTANT_Utf8 = 1,
+ CONSTANT_Integer = 3,
+ CONSTANT_Float = 4,
+ CONSTANT_Long = 5,
+ CONSTANT_Double = 6,
+ CONSTANT_Class = 7,
+ CONSTANT_String = 8,
+ CONSTANT_Fieldref = 9,
+ CONSTANT_Methodref = 10,
+ CONSTANT_InterfaceMethodref = 11,
+ CONSTANT_NameAndType = 12;
+ private static final String[] cpTagName = {
+ /* 0: */null,
+ /* 1: */ "Utf8",
+ /* 2: */ null,
+ /* 3: */ "Integer",
+ /* 4: */ "Float",
+ /* 5: */ "Long",
+ /* 6: */ "Double",
+ /* 7: */ "Class",
+ /* 8: */ "String",
+ /* 9: */ "Fieldref",
+ /* 10: */ "Methodref",
+ /* 11: */ "InterfaceMethodref",
+ /* 12: */ "NameAndType",
+ null
+ };
+ private static final Set<String> cpTagNames;
+
+ static {
+ Set<String> set = new HashSet<String>(Arrays.asList(cpTagName));
+ set.remove(null);
+ cpTagNames = Collections.unmodifiableSet(set);
+ }
+ public static final int ITEM_Top = 0, // replicates by [1..4,1..4]
+ ITEM_Integer = 1, // (ditto)
+ ITEM_Float = 2,
+ ITEM_Double = 3,
+ ITEM_Long = 4,
+ ITEM_Null = 5,
+ ITEM_UninitializedThis = 6,
+ ITEM_Object = 7,
+ ITEM_Uninitialized = 8,
+ ITEM_ReturnAddress = 9,
+ ITEM_LIMIT = 10;
+ private static final String[] itemTagName = {
+ "Top",
+ "Integer",
+ "Float",
+ "Double",
+ "Long",
+ "Null",
+ "UninitializedThis",
+ "Object",
+ "Uninitialized",
+ "ReturnAddress",};
+ private static final Set<String> itemTagNames;
+
+ static {
+ Set<String> set = new HashSet<String>(Arrays.asList(itemTagName));
+ set.remove(null);
+ itemTagNames = Collections.unmodifiableSet(set);
+ }
+ protected static final HashMap<String, String> attrTypesBacking;
+ protected static final Map<String, String> attrTypesInit;
+
+ static {
+ HashMap<String, String> at = new HashMap<String, String>();
+
+ //at.put("*.Deprecated", "<deprecated=true>");
+ //at.put("*.Synthetic", "<synthetic=true>");
+ ////at.put("Field.ConstantValue", "<constantValue=>KQH");
+ //at.put("Class.SourceFile", "<sourceFile=>RUH");
+ at.put("Method.Bridge", "<Bridge>");
+ at.put("Method.Varargs", "<Varargs>");
+ at.put("Class.Enum", "<Enum>");
+ at.put("*.Signature", "<Signature>RSH");
+ //at.put("*.Deprecated", "<Deprecated>");
+ //at.put("*.Synthetic", "<Synthetic>");
+ at.put("Field.ConstantValue", "<ConstantValue>KQH");
+ at.put("Class.SourceFile", "<SourceFile>RUH");
+ at.put("Class.InnerClasses", "NH[<InnerClass><class=>RCH<outer=>RCH<name=>RUH<flags=>FH]");
+ at.put("Code.LineNumberTable", "NH[<LineNumber><bci=>PH<line=>H]");
+ at.put("Code.LocalVariableTable", "NH[<LocalVariable><bci=>PH<span=>H<name=>RUH<type=>RSH<slot=>H]");
+ at.put("Code.LocalVariableTypeTable", "NH[<LocalVariableType><bci=>PH<span=>H<name=>RUH<type=>RSH<slot=>H]");
+ at.put("Method.Exceptions", "NH[<Exception><name=>RCH]");
+ at.put("Method.Code", "<Code>...");
+ at.put("Code.StackMapTable", "<Frame>...");
+ //at.put("Code.StkMapX", "<FrameX>...");
+ if (true) {
+ at.put("Code.StackMapTable",
+ "[NH[<Frame>(1)]]"
+ + "[TB"
+ + "(64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79"
+ + ",80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95"
+ + ",96,97,98,99,100,101,102,103,104,105,106,107,108,109,110,111"
+ + ",112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127"
+ + ")[<SameLocals1StackItemFrame>(4)]"
+ + "(247)[<SameLocals1StackItemExtended>H(4)]"
+ + "(248)[<Chop3>H]"
+ + "(249)[<Chop2>H]"
+ + "(250)[<Chop1>H]"
+ + "(251)[<SameFrameExtended>H]"
+ + "(252)[<Append1>H(4)]"
+ + "(253)[<Append2>H(4)(4)]"
+ + "(254)[<Append3>H(4)(4)(4)]"
+ + "(255)[<FullFrame>H(2)(3)]"
+ + "()[<SameFrame>]]"
+ + "[NH[<Local>(4)]]"
+ + "[NH[<Stack>(4)]]"
+ + "[TB"
+ + ("(0)[<Top>]"
+ + "(1)[<ItemInteger>](2)[<ItemFloat>](3)[<ItemDouble>](4)[<ItemLong>]"
+ + "(5)[<ItemNull>](6)[<ItemUninitializedThis>]"
+ + "(7)[<ItemObject><class=>RCH]"
+ + "(8)[<ItemUninitialized><bci=>PH]"
+ + "()[<ItemUnknown>]]"));
+ }
+
+ at.put("Class.EnclosingMethod", "<EnclosingMethod><class=>RCH<desc=>RDH");//RDNH
+
+ // Layouts of metadata attrs:
+ String vpf = "[<RuntimeVisibleAnnotation>";
+ String ipf = "[<RuntimeInvisibleAnnotation>";
+ String apf = "[<Annotation>";
+ String mdanno2 = ""
+ + "<type=>RSHNH[<Member><name=>RUH(3)]]"
+ + ("[TB"
+ + "(\\B,\\C,\\I,\\S,\\Z)[<value=>KIH]"
+ + "(\\D)[<value=>KDH]"
+ + "(\\F)[<value=>KFH]"
+ + "(\\J)[<value=>KJH]"
+ + "(\\c)[<class=>RSH]"
+ + "(\\e)[<type=>RSH<name=>RUH]"
+ + "(\\s)[<String>RUH]"
+ + "(\\@)[(2)]"
+ + "(\\[)[NH[<Element>(3)]]"
+ + "()[]"
+ + "]");
+ String visanno = "[NH[(2)]][(1)]" + vpf + mdanno2;
+ String invanno = "[NH[(2)]][(1)]" + ipf + mdanno2;
+ String vparamanno = ""
+ + "[NB[<RuntimeVisibleParameterAnnotation>(1)]][NH[(2)]]"
+ + apf + mdanno2;
+ String iparamanno = ""
+ + "[NB[<RuntimeInvisibleParameterAnnotation>(1)]][NH[(2)]]"
+ + apf + mdanno2;
+ String mdannodef = "[<AnnotationDefault>(3)][(1)]" + apf + mdanno2;
+ String[] mdplaces = {"Class", "Field", "Method"};
+ for (String place : mdplaces) {
+ at.put(place + ".RuntimeVisibleAnnotations", visanno);
+ at.put(place + ".RuntimeInvisibleAnnotations", invanno);
+ }
+ at.put("Method.RuntimeVisibleParameterAnnotations", vparamanno);
+ at.put("Method.RuntimeInvisibleParameterAnnotations", iparamanno);
+ at.put("Method.AnnotationDefault", mdannodef);
+
+ attrTypesBacking = at;
+ attrTypesInit = Collections.unmodifiableMap(at);
+ }
+
+ ;
+ private static final String[] jcovAttrTypes = {
+ "Code.CoverageTable=NH[<Coverage><bci=>PH<type=>H<line=>I<pos=>I]",
+ "Code.CharacterRangeTable=NH[<CharacterRange><bci=>PH<endbci=>POH<from=>I<to=>I<flag=>H]",
+ "Class.SourceID=<SourceID><id=>RUH",
+ "Class.CompilationID=<CompilationID><id=>RUH"
+ };
+ protected static final String[][] modifierNames = {
+ {"public"},
+ {"private"},
+ {"protected"},
+ {"static"},
+ {"final"},
+ {"synchronized"},
+ {null, "volatile", "bridge"},
+ {null, "transient", "varargs"},
+ {null, null, "native"},
+ {"interface"},
+ {"abstract"},
+ {"strictfp"},
+ {"synthetic"},
+ {"annotation"},
+ {"enum"},};
+ protected static final String EIGHT_BIT_CHAR_ENCODING = "ISO8859_1";
+ protected static final String UTF8_ENCODING = "UTF8";
+ // What XML tags are used by this syntax, apart from attributes?
+ protected static final Set<String> nonAttrTags;
+
+ static {
+ HashSet<String> tagSet = new HashSet<String>();
+ Collections.addAll(tagSet, new String[]{
+ "ConstantPool",// the CP
+ "Class", // the class
+ "Interface", // implemented interfaces
+ "Method", // methods
+ "Field", // fields
+ "Handler", // exception handler pseudo-attribute
+ "Attribute", // unparsed attribute
+ "Bytes", // bytecodes
+ "Instructions" // bytecodes, parsed
+ });
+ nonAttrTags = Collections.unmodifiableSet(tagSet);
+ }
+
+ // Accessors.
+ public static Set<String> nonAttrTags() {
+ return nonAttrTags;
+ }
+
+ public static String cpTagName(int t) {
+ t &= 0xFF;
+ String ts = null;
+ if (t < cpTagName.length) {
+ ts = cpTagName[t];
+ }
+ if (ts != null) {
+ return ts;
+ }
+ return ("UnknownTag" + (int) t).intern();
+ }
+
+ public static int cpTagValue(String name) {
+ for (int t = 0; t < cpTagName.length; t++) {
+ if (name.equals(cpTagName[t])) {
+ return t;
+ }
+ }
+ return 0;
+ }
+
+ public static String itemTagName(int t) {
+ t &= 0xFF;
+ String ts = null;
+ if (t < itemTagName.length) {
+ ts = itemTagName[t];
+ }
+ if (ts != null) {
+ return ts;
+ }
+ return ("UnknownItem" + (int) t).intern();
+ }
+
+ public static int itemTagValue(String name) {
+ for (int t = 0; t < itemTagName.length; t++) {
+ if (name.equals(itemTagName[t])) {
+ return t;
+ }
+ }
+ return -1;
+ }
+
+ public void addJcovAttrTypes() {
+ addAttrTypes(jcovAttrTypes);
+ }
+ // Public methods for declaring attribute types.
+ protected Map<String, String> attrTypes = attrTypesInit;
+
+ public void addAttrType(String opt) {
+ int eqpos = opt.indexOf('=');
+ addAttrType(opt.substring(0, eqpos), opt.substring(eqpos + 1));
+ }
+
+ public void addAttrTypes(String[] opts) {
+ for (String opt : opts) {
+ addAttrType(opt);
+ }
+ }
+
+ private void checkAttr(String attr) {
+ if (!attr.startsWith("Class.")
+ && !attr.startsWith("Field.")
+ && !attr.startsWith("Method.")
+ && !attr.startsWith("Code.")
+ && !attr.startsWith("*.")) {
+ throw new IllegalArgumentException("attr name must start with 'Class.', etc.");
+ }
+ String uattr = attr.substring(attr.indexOf('.') + 1);
+ if (nonAttrTags.contains(uattr)) {
+ throw new IllegalArgumentException("attr name must not be one of " + nonAttrTags);
+ }
+ }
+
+ private void checkAttrs(Map<String, String> at) {
+ for (String attr : at.keySet()) {
+ checkAttr(attr);
+ }
+ }
+
+ private void modAttrs() {
+ if (attrTypes == attrTypesInit) {
+ // Make modifiable.
+ attrTypes = new HashMap<String, String>(attrTypesBacking);
+ }
+ }
+
+ public void addAttrType(String attr, String fmt) {
+ checkAttr(attr);
+ modAttrs();
+ attrTypes.put(attr, fmt);
+ }
+
+ public void addAttrTypes(Map<String, String> at) {
+ checkAttrs(at);
+ modAttrs();
+ attrTypes.putAll(at);
+ }
+
+ public Map<String, String> getAttrTypes() {
+ if (attrTypes == attrTypesInit) {
+ return attrTypes;
+ }
+ return Collections.unmodifiableMap(attrTypes);
+ }
+
+ public void setAttrTypes(Map<String, String> at) {
+ checkAttrs(at);
+ modAttrs();
+ attrTypes.keySet().retainAll(at.keySet());
+ attrTypes.putAll(at);
+ }
+
+ // attr format helpers
+ protected static boolean matchTag(int tagValue, String caseStr) {
+ //System.out.println("matchTag "+tagValue+" in "+caseStr);
+ for (int pos = 0, max = caseStr.length(), comma;
+ pos < max;
+ pos = comma + 1) {
+ int caseValue;
+ if (caseStr.charAt(pos) == '\\') {
+ caseValue = caseStr.charAt(pos + 1);
+ comma = pos + 2;
+ assert (comma == max || caseStr.charAt(comma) == ',');
+ } else {
+ comma = caseStr.indexOf(',', pos);
+ if (comma < 0) {
+ comma = max;
+ }
+ caseValue = Integer.parseInt(caseStr.substring(pos, comma));
+ }
+ if (tagValue == caseValue) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ protected static String[] getBodies(String type) {
+ ArrayList<String> bodies = new ArrayList<String>();
+ for (int i = 0; i < type.length();) {
+ String body = getBody(type, i);
+ bodies.add(body);
+ i += body.length() + 2; // skip body and brackets
+ }
+ return bodies.toArray(new String[bodies.size()]);
+ }
+
+ protected static String getBody(String type, int i) {
+ assert (type.charAt(i) == '[');
+ int next = ++i; // skip bracket
+ for (int depth = 1; depth > 0; next++) {
+ switch (type.charAt(next)) {
+ case '[':
+ depth++;
+ break;
+ case ']':
+ depth--;
+ break;
+ case '(':
+ next = type.indexOf(')', next);
+ break;
+ case '<':
+ next = type.indexOf('>', next);
+ break;
+ }
+ assert (next > 0);
+ }
+ --next; // get before bracket
+ assert (type.charAt(next) == ']');
+ return type.substring(i, next);
+ }
+
+ public Element makeCPDigest(int length) {
+ MessageDigest md;
+ try {
+ md = MessageDigest.getInstance("MD5");
+ } catch (java.security.NoSuchAlgorithmException ee) {
+ throw new Error(ee);
+ }
+ int items = 0;
+ for (Element e : cpool.elements()) {
+ if (items == length) {
+ break;
+ }
+ if (cpTagNames.contains(e.getName())) {
+ items += 1;
+ md.update((byte) cpTagValue(e.getName()));
+ try {
+ md.update(e.getText().toString().getBytes(UTF8_ENCODING));
+ } catch (java.io.UnsupportedEncodingException ee) {
+ throw new Error(ee);
+ }
+ }
+ }
+ ByteBuffer bb = ByteBuffer.wrap(md.digest());
+ String l0 = Long.toHexString(bb.getLong(0));
+ String l1 = Long.toHexString(bb.getLong(8));
+ while (l0.length() < 16) {
+ l0 = "0" + l0;
+ }
+ while (l1.length() < 16) {
+ l1 = "0" + l1;
+ }
+ return new Element("Digest",
+ "length", "" + items,
+ "bytes", l0 + l1);
+ }
+
+ public Element getCPDigest(int length) {
+ if (length == -1) {
+ length = cpool.countAll(XMLKit.elementFilter(cpTagNames));
+ }
+ for (Element md : cpool.findAllElements("Digest").elements()) {
+ if (md.getAttrLong("length") == length) {
+ return md;
+ }
+ }
+ Element md = makeCPDigest(length);
+ cpool.add(md);
+ return md;
+ }
+
+ public Element getCPDigest() {
+ return getCPDigest(-1);
+ }
+
+ public boolean checkCPDigest(Element md) {
+ return md.equals(getCPDigest((int) md.getAttrLong("length")));
+ }
+
+ public static int computeInterfaceNum(String intMethRef) {
+ intMethRef = intMethRef.substring(1 + intMethRef.lastIndexOf(' '));
+ if (!intMethRef.startsWith("(")) {
+ return -1;
+ }
+ int signum = 1; // start with one for "this"
+ scanSig:
+ for (int i = 1; i < intMethRef.length(); i++) {
+ char ch = intMethRef.charAt(i);
+ signum++;
+ switch (ch) {
+ case ')':
+ --signum;
+ break scanSig;
+ case 'L':
+ i = intMethRef.indexOf(';', i);
+ break;
+ case '[':
+ while (ch == '[') {
+ ch = intMethRef.charAt(++i);
+ }
+ if (ch == 'L') {
+ i = intMethRef.indexOf(';', i);
+ }
+ break;
+ }
+ }
+ int num = (signum << 8) | 0;
+ //System.out.println("computeInterfaceNum "+intMethRef+" => "+num);
+ return num;
+ }
+ // Protected state for representing the class file.
+ protected Element cfile; // <ClassFile ...>
+ protected Element cpool; // <ConstantPool ...>
+ protected Element klass; // <Class ...>
+ protected Element currentMember; // varies during scans
+ protected Element currentCode; // varies during scans
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/tools/pack200/pack200-verifier/src/xmlkit/ClassWriter.java Wed Jul 05 17:21:22 2017 +0200
@@ -0,0 +1,818 @@
+/*
+ * Copyright (c) 2010, 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.
+ */
+package xmlkit; // -*- mode: java; indent-tabs-mode: nil -*-
+
+import java.util.*;
+import java.lang.reflect.*;
+import java.io.*;
+import xmlkit.XMLKit.Element;
+/*
+ * @author jrose
+ */
+public class ClassWriter extends ClassSyntax implements ClassSyntax.GetCPIndex {
+
+ private static final CommandLineParser CLP = new CommandLineParser(""
+ + "-source: +> = \n"
+ + "-dest: +> = \n"
+ + "-encoding: +> = \n"
+ + "-parseBytes $ \n"
+ + "- *? \n"
+ + "\n");
+
+ public static void main(String[] ava) throws IOException {
+ ArrayList<String> av = new ArrayList<String>(Arrays.asList(ava));
+ HashMap<String, String> props = new HashMap<String, String>();
+ props.put("-encoding:", "UTF8"); // default
+ CLP.parse(av, props);
+ File source = asFile(props.get("-source:"));
+ File dest = asFile(props.get("-dest:"));
+ String encoding = props.get("-encoding:");
+ boolean parseBytes = props.containsKey("-parseBytes");
+ boolean destMade = false;
+
+ for (String a : av) {
+ File f;
+ File inf = new File(source, a);
+ System.out.println("Reading " + inf);
+ Element e;
+ if (inf.getName().endsWith(".class")) {
+ ClassReader cr = new ClassReader();
+ cr.parseBytes = parseBytes;
+ e = cr.readFrom(inf);
+ f = new File(a);
+ } else if (inf.getName().endsWith(".xml")) {
+ InputStream in = new FileInputStream(inf);
+ Reader inw = ClassReader.makeReader(in, encoding);
+ e = XMLKit.readFrom(inw);
+ e.findAllInTree(XMLKit.and(XMLKit.elementFilter(nonAttrTags()),
+ XMLKit.methodFilter(Element.method("trimText"))));
+ //System.out.println(e);
+ inw.close();
+ f = new File(a.substring(0, a.length() - ".xml".length()) + ".class");
+ } else {
+ System.out.println("Warning: unknown input " + a);
+ continue;
+ }
+ // Now write it:
+ if (!destMade) {
+ destMade = true;
+ if (dest == null) {
+ dest = File.createTempFile("TestOut", ".dir", new File("."));
+ dest.delete();
+ System.out.println("Writing results to " + dest);
+ }
+ if (!(dest.isDirectory() || dest.mkdir())) {
+ throw new RuntimeException("Cannot create " + dest);
+ }
+ }
+ File outf = new File(dest, f.isAbsolute() ? f.getName() : f.getPath());
+ outf.getParentFile().mkdirs();
+ new ClassWriter(e).writeTo(outf);
+ }
+ }
+
+ private static File asFile(String str) {
+ return (str == null) ? null : new File(str);
+ }
+
+ public void writeTo(File file) throws IOException {
+ OutputStream out = null;
+ try {
+ out = new BufferedOutputStream(new FileOutputStream(file));
+ writeTo(out);
+ } finally {
+ if (out != null) {
+ out.close();
+ }
+ }
+ }
+ protected String[] callables; // varies
+ protected int cpoolSize = 0;
+ protected HashMap<String, String> attrTypesByTag;
+ protected OutputStream out;
+ protected HashMap<String, int[]> cpMap = new HashMap<String, int[]>();
+ protected ArrayList<ByteArrayOutputStream> attrBufs = new ArrayList<ByteArrayOutputStream>();
+
+ private void setupAttrTypes() {
+ attrTypesByTag = new HashMap<String, String>();
+ for (String key : attrTypes.keySet()) {
+ String pfx = key.substring(0, key.indexOf('.') + 1);
+ String val = attrTypes.get(key);
+ int pos = val.indexOf('<');
+ if (pos >= 0) {
+ String tag = val.substring(pos + 1, val.indexOf('>', pos));
+ attrTypesByTag.put(pfx + tag, key);
+ }
+ }
+ //System.out.println("attrTypesByTag: "+attrTypesByTag);
+ }
+
+ protected ByteArrayOutputStream getAttrBuf() {
+ int nab = attrBufs.size();
+ if (nab == 0) {
+ return new ByteArrayOutputStream(1024);
+ }
+ ByteArrayOutputStream ab = attrBufs.get(nab - 1);
+ attrBufs.remove(nab - 1);
+ return ab;
+ }
+
+ protected void putAttrBuf(ByteArrayOutputStream ab) {
+ ab.reset();
+ attrBufs.add(ab);
+ }
+
+ public ClassWriter(Element root) {
+ this(root, null);
+ }
+
+ public ClassWriter(Element root, ClassSyntax cr) {
+ if (cr != null) {
+ attrTypes = cr.attrTypes;
+ }
+ setupAttrTypes();
+ if (root.getName() == "ClassFile") {
+ cfile = root;
+ cpool = root.findElement("ConstantPool");
+ klass = root.findElement("Class");
+ } else if (root.getName() == "Class") {
+ cfile = new Element("ClassFile",
+ new String[]{
+ "magic", String.valueOf(0xCAFEBABE),
+ "minver", "0", "majver", "46",});
+ cpool = new Element("ConstantPool");
+ klass = root;
+ } else {
+ throw new IllegalArgumentException("bad element type " + root.getName());
+ }
+ if (cpool == null) {
+ cpool = new Element("ConstantPool");
+ }
+
+ int cpLen = 1 + cpool.size();
+ for (Element c : cpool.elements()) {
+ int id = (int) c.getAttrLong("id");
+ int tag = cpTagValue(c.getName());
+ setCPIndex(tag, c.getText().toString(), id);
+ switch (tag) {
+ case CONSTANT_Long:
+ case CONSTANT_Double:
+ cpLen += 1;
+ }
+ }
+ cpoolSize = cpLen;
+ }
+
+ public int findCPIndex(int tag, String name) {
+ if (name == null) {
+ return 0;
+ }
+ int[] ids = cpMap.get(name.toString());
+ return (ids == null) ? 0 : ids[tag];
+ }
+
+ public int getCPIndex(int tag, String name) {
+ //System.out.println("getCPIndex "+cpTagName(tag)+" "+name);
+ if (name == null) {
+ return 0;
+ }
+ int id = findCPIndex(tag, name);
+ if (id == 0) {
+ id = cpoolSize;
+ cpoolSize += 1;
+ setCPIndex(tag, name, id);
+ cpool.add(new Element(cpTagName(tag),
+ new String[]{"id", "" + id},
+ new Object[]{name}));
+ int pos;
+ switch (tag) {
+ case CONSTANT_Long:
+ case CONSTANT_Double:
+ cpoolSize += 1;
+ break;
+ case CONSTANT_Class:
+ case CONSTANT_String:
+ getCPIndex(CONSTANT_Utf8, name);
+ break;
+ case CONSTANT_Fieldref:
+ case CONSTANT_Methodref:
+ case CONSTANT_InterfaceMethodref:
+ pos = name.indexOf(' ');
+ getCPIndex(CONSTANT_Class, name.substring(0, pos));
+ getCPIndex(CONSTANT_NameAndType, name.substring(pos + 1));
+ break;
+ case CONSTANT_NameAndType:
+ pos = name.indexOf(' ');
+ getCPIndex(CONSTANT_Utf8, name.substring(0, pos));
+ getCPIndex(CONSTANT_Utf8, name.substring(pos + 1));
+ break;
+ }
+ }
+ return id;
+ }
+
+ public void setCPIndex(int tag, String name, int id) {
+ //System.out.println("setCPIndex id="+id+" tag="+tag+" name="+name);
+ int[] ids = cpMap.get(name);
+ if (ids == null) {
+ cpMap.put(name, ids = new int[13]);
+ }
+ if (ids[tag] != 0 && ids[tag] != id) {
+ System.out.println("Warning: Duplicate CP entries for " + ids[tag] + " and " + id);
+ }
+ //assert(ids[tag] == 0 || ids[tag] == id);
+ ids[tag] = id;
+ }
+
+ public int parseFlags(String flagString) {
+ int flags = 0;
+ int i = -1;
+ for (String[] names : modifierNames) {
+ ++i;
+ for (String name : names) {
+ if (name == null) {
+ continue;
+ }
+ int pos = flagString.indexOf(name);
+ if (pos >= 0) {
+ flags |= (1 << i);
+ }
+ }
+ }
+ return flags;
+ }
+
+ public void writeTo(OutputStream realOut) throws IOException {
+ OutputStream headOut = realOut;
+ ByteArrayOutputStream tailOut = new ByteArrayOutputStream();
+
+ // write the body of the class file first
+ this.out = tailOut;
+ writeClass();
+
+ // write the file header last
+ this.out = headOut;
+ u4((int) cfile.getAttrLong("magic"));
+ u2((int) cfile.getAttrLong("minver"));
+ u2((int) cfile.getAttrLong("majver"));
+ writeCP();
+
+ // recopy the file tail
+ this.out = null;
+ tailOut.writeTo(realOut);
+ }
+
+ void writeClass() throws IOException {
+ int flags = parseFlags(klass.getAttr("flags"));
+ flags ^= Modifier.SYNCHRONIZED;
+ u2(flags);
+ cpRef(CONSTANT_Class, klass.getAttr("name"));
+ cpRef(CONSTANT_Class, klass.getAttr("super"));
+ Element interfaces = klass.findAllElements("Interface");
+ u2(interfaces.size());
+ for (Element e : interfaces.elements()) {
+ cpRef(CONSTANT_Class, e.getAttr("name"));
+ }
+ for (int isMethod = 0; isMethod <= 1; isMethod++) {
+ Element members = klass.findAllElements(isMethod != 0 ? "Method" : "Field");
+ u2(members.size());
+ for (Element m : members.elements()) {
+ writeMember(m, isMethod != 0);
+ }
+ }
+ writeAttributesFor(klass);
+ }
+
+ private void writeMember(Element member, boolean isMethod) throws IOException {
+ //System.out.println("writeMember "+member);
+ u2(parseFlags(member.getAttr("flags")));
+ cpRef(CONSTANT_Utf8, member.getAttr("name"));
+ cpRef(CONSTANT_Utf8, member.getAttr("type"));
+ writeAttributesFor(member);
+ }
+
+ protected void writeAttributesFor(Element x) throws IOException {
+ LinkedHashSet<String> attrNames = new LinkedHashSet<String>();
+ for (Element e : x.elements()) {
+ attrNames.add(e.getName()); // uniquifying
+ }
+ attrNames.removeAll(nonAttrTags());
+ u2(attrNames.size());
+ if (attrNames.isEmpty()) {
+ return;
+ }
+ Element prevCurrent;
+ if (x.getName() == "Code") {
+ prevCurrent = currentCode;
+ currentCode = x;
+ } else {
+ prevCurrent = currentMember;
+ currentMember = x;
+ }
+ OutputStream realOut = this.out;
+ for (String utag : attrNames) {
+ String qtag = x.getName() + "." + utag;
+ String wtag = "*." + utag;
+ String key = attrTypesByTag.get(qtag);
+ if (key == null) {
+ key = attrTypesByTag.get(wtag);
+ }
+ String type = attrTypes.get(key);
+ //System.out.println("tag "+qtag+" => key "+key+"; type "+type);
+ Element attrs = x.findAllElements(utag);
+ ByteArrayOutputStream attrBuf = getAttrBuf();
+ if (type == null) {
+ if (attrs.size() != 1 || !attrs.get(0).equals(new Element(utag))) {
+ System.out.println("Warning: No attribute type description: " + qtag);
+ }
+ key = wtag;
+ } else {
+ try {
+ this.out = attrBuf;
+ // unparse according to type desc.
+ if (type.equals("<Code>...")) {
+ writeCode((Element) attrs.get(0)); // assume only 1
+ } else if (type.equals("<Frame>...")) {
+ writeStackMap(attrs, false);
+ } else if (type.equals("<FrameX>...")) {
+ writeStackMap(attrs, true);
+ } else if (type.startsWith("[")) {
+ writeAttributeRecursive(attrs, type);
+ } else {
+ writeAttribute(attrs, type);
+ }
+ } finally {
+ //System.out.println("Attr Bytes = \""+attrBuf.toString(EIGHT_BIT_CHAR_ENCODING).replace('"', (char)('"'|0x80))+"\"");
+ this.out = realOut;
+ }
+ }
+ cpRef(CONSTANT_Utf8, key.substring(key.indexOf('.') + 1));
+ u4(attrBuf.size());
+ attrBuf.writeTo(out);
+ putAttrBuf(attrBuf);
+ }
+ if (x.getName() == "Code") {
+ currentCode = prevCurrent;
+ } else {
+ currentMember = prevCurrent;
+ }
+ }
+
+ private void writeAttributeRecursive(Element aval, String type) throws IOException {
+ assert (callables == null);
+ callables = getBodies(type);
+ writeAttribute(aval, callables[0]);
+ callables = null;
+ }
+
+ private void writeAttribute(Element aval, String type) throws IOException {
+ //System.out.println("writeAttribute "+aval+" using "+type);
+ String nextAttrName = null;
+ boolean afterElemHead = false;
+ for (int len = type.length(), next, i = 0; i < len; i = next) {
+ int value;
+ char intKind;
+ int tag;
+ int sigChar;
+ String attrValue;
+ switch (type.charAt(i)) {
+ case '<':
+ assert (nextAttrName == null);
+ next = type.indexOf('>', i);
+ String form = type.substring(i + 1, next++);
+ if (form.indexOf('=') < 0) {
+ // elem_placement = '<' elemname '>'
+ if (aval.isAnonymous()) {
+ assert (aval.size() == 1);
+ aval = (Element) aval.get(0);
+ }
+ assert (aval.getName().equals(form)) : aval + " // " + form;
+ afterElemHead = true;
+ } else {
+ // attr_placement = '(' attrname '=' (value)? ')'
+ int eqPos = form.indexOf('=');
+ assert (eqPos >= 0);
+ nextAttrName = form.substring(0, eqPos).intern();
+ if (eqPos != form.length() - 1) {
+ // value is implicit, not placed in file
+ nextAttrName = null;
+ }
+ afterElemHead = false;
+ }
+ continue;
+ case '(':
+ next = type.indexOf(')', ++i);
+ int callee = Integer.parseInt(type.substring(i, next++));
+ writeAttribute(aval, callables[callee]);
+ continue;
+ case 'N': // replication = 'N' int '[' type ... ']'
+ {
+ assert (nextAttrName == null);
+ afterElemHead = false;
+ char countType = type.charAt(i + 1);
+ next = i + 2;
+ String type1 = getBody(type, next);
+ Element elems = aval;
+ if (type1.startsWith("<")) {
+ // Select only matching members of aval.
+ String elemName = type1.substring(1, type1.indexOf('>'));
+ elems = aval.findAllElements(elemName);
+ }
+ putInt(elems.size(), countType);
+ next += type1.length() + 2; // skip body and brackets
+ for (Element elem : elems.elements()) {
+ writeAttribute(elem, type1);
+ }
+ }
+ continue;
+ case 'T': // union = 'T' any_int union_case* '(' ')' '[' body ']'
+ // write the value
+ value = (int) aval.getAttrLong("tag");
+ assert (aval.getAttr("tag") != null) : aval;
+ intKind = type.charAt(++i);
+ if (intKind == 'S') {
+ intKind = type.charAt(++i);
+ }
+ putInt(value, intKind);
+ nextAttrName = null;
+ afterElemHead = false;
+ ++i; // skip the int type char
+ // union_case = '(' ('-')? digit+ ')' '[' body ']'
+ for (boolean foundCase = false;;) {
+ assert (type.charAt(i) == '(');
+ next = type.indexOf(')', ++i);
+ assert (next >= i);
+ String caseStr = type.substring(i, next++);
+ String type1 = getBody(type, next);
+ next += type1.length() + 2; // skip body and brackets
+ boolean lastCase = (caseStr.length() == 0);
+ if (!foundCase
+ && (lastCase || matchTag(value, caseStr))) {
+ foundCase = true;
+ // Execute this body.
+ writeAttribute(aval, type1);
+ }
+ if (lastCase) {
+ break;
+ }
+ }
+ continue;
+ case 'B':
+ case 'H':
+ case 'I': // int = oneof "BHI"
+ value = (int) aval.getAttrLong(nextAttrName);
+ intKind = type.charAt(i);
+ next = i + 1;
+ break;
+ case 'K':
+ sigChar = type.charAt(i + 1);
+ if (sigChar == 'Q') {
+ assert (currentMember.getName() == "Field");
+ assert (aval.getName() == "ConstantValue");
+ String sig = currentMember.getAttr("type");
+ sigChar = sig.charAt(0);
+ switch (sigChar) {
+ case 'Z':
+ case 'B':
+ case 'C':
+ case 'S':
+ sigChar = 'I';
+ break;
+ }
+ }
+ switch (sigChar) {
+ case 'I':
+ tag = CONSTANT_Integer;
+ break;
+ case 'J':
+ tag = CONSTANT_Long;
+ break;
+ case 'F':
+ tag = CONSTANT_Float;
+ break;
+ case 'D':
+ tag = CONSTANT_Double;
+ break;
+ case 'L':
+ tag = CONSTANT_String;
+ break;
+ default:
+ assert (false);
+ tag = 0;
+ }
+ assert (type.charAt(i + 2) == 'H'); // only H works for now
+ next = i + 3;
+ assert (afterElemHead || nextAttrName != null);
+ //System.out.println("get attr "+nextAttrName+" in "+aval);
+ if (nextAttrName != null) {
+ attrValue = aval.getAttr(nextAttrName);
+ assert (attrValue != null);
+ } else {
+ assert (aval.isText()) : aval;
+ attrValue = aval.getText().toString();
+ }
+ value = getCPIndex(tag, attrValue);
+ intKind = 'H'; //type.charAt(i+2);
+ break;
+ case 'R':
+ sigChar = type.charAt(i + 1);
+ switch (sigChar) {
+ case 'C':
+ tag = CONSTANT_Class;
+ break;
+ case 'S':
+ tag = CONSTANT_Utf8;
+ break;
+ case 'D':
+ tag = CONSTANT_Class;
+ break;
+ case 'F':
+ tag = CONSTANT_Fieldref;
+ break;
+ case 'M':
+ tag = CONSTANT_Methodref;
+ break;
+ case 'I':
+ tag = CONSTANT_InterfaceMethodref;
+ break;
+ case 'U':
+ tag = CONSTANT_Utf8;
+ break;
+ //case 'Q': tag = CONSTANT_Class; break;
+ default:
+ assert (false);
+ tag = 0;
+ }
+ assert (type.charAt(i + 2) == 'H'); // only H works for now
+ next = i + 3;
+ assert (afterElemHead || nextAttrName != null);
+ //System.out.println("get attr "+nextAttrName+" in "+aval);
+ if (nextAttrName != null) {
+ attrValue = aval.getAttr(nextAttrName);
+ } else if (aval.hasText()) {
+ attrValue = aval.getText().toString();
+ } else {
+ attrValue = null;
+ }
+ value = getCPIndex(tag, attrValue);
+ intKind = 'H'; //type.charAt(i+2);
+ break;
+ case 'P': // bci = 'P' int
+ case 'S': // signed_int = 'S' int
+ next = i + 2;
+ value = (int) aval.getAttrLong(nextAttrName);
+ intKind = type.charAt(i + 1);
+ break;
+ case 'F':
+ next = i + 2;
+ value = parseFlags(aval.getAttr(nextAttrName));
+ intKind = type.charAt(i + 1);
+ break;
+ default:
+ throw new RuntimeException("bad attr format '" + type.charAt(i) + "': " + type);
+ }
+ // write the value
+ putInt(value, intKind);
+ nextAttrName = null;
+ afterElemHead = false;
+ }
+ assert (nextAttrName == null);
+ }
+
+ private void putInt(int x, char ch) throws IOException {
+ switch (ch) {
+ case 'B':
+ u1(x);
+ break;
+ case 'H':
+ u2(x);
+ break;
+ case 'I':
+ u4(x);
+ break;
+ }
+ assert ("BHI".indexOf(ch) >= 0);
+ }
+
+ private void writeCode(Element code) throws IOException {
+ //System.out.println("writeCode "+code);
+ //Element m = new Element(currentMember); m.remove(code);
+ //System.out.println(" in "+m);
+ int stack = (int) code.getAttrLong("stack");
+ int local = (int) code.getAttrLong("local");
+ Element bytes = code.findElement("Bytes");
+ Element insns = code.findElement("Instructions");
+ String bytecodes;
+ if (insns == null) {
+ bytecodes = bytes.getText().toString();
+ } else {
+ bytecodes = InstructionSyntax.assemble(insns, this);
+ // Cache the assembled bytecodes:
+ bytes = new Element("Bytes", (String[]) null, bytecodes);
+ code.add(0, bytes);
+ }
+ u2(stack);
+ u2(local);
+ int length = bytecodes.length();
+ u4(length);
+ for (int i = 0; i < length; i++) {
+ u1((byte) bytecodes.charAt(i));
+ }
+ Element handlers = code.findAllElements("Handler");
+ u2(handlers.size());
+ for (Element handler : handlers.elements()) {
+ int start = (int) handler.getAttrLong("start");
+ int end = (int) handler.getAttrLong("end");
+ int catsh = (int) handler.getAttrLong("catch");
+ u2(start);
+ u2(end);
+ u2(catsh);
+ cpRef(CONSTANT_Class, handler.getAttr("class"));
+ }
+ writeAttributesFor(code);
+ }
+
+ protected void writeStackMap(Element attrs, boolean hasXOption) throws IOException {
+ Element bytes = currentCode.findElement("Bytes");
+ assert (bytes != null && bytes.size() == 1);
+ int byteLength = ((String) bytes.get(0)).length();
+ boolean uoffsetIsU4 = (byteLength >= (1 << 16));
+ boolean ulocalvarIsU4 = currentCode.getAttrLong("local") >= (1 << 16);
+ boolean ustackIsU4 = currentCode.getAttrLong("stack") >= (1 << 16);
+ if (uoffsetIsU4) {
+ u4(attrs.size());
+ } else {
+ u2(attrs.size());
+ }
+ for (Element frame : attrs.elements()) {
+ int bci = (int) frame.getAttrLong("bci");
+ if (uoffsetIsU4) {
+ u4(bci);
+ } else {
+ u2(bci);
+ }
+ if (hasXOption) {
+ u1((int) frame.getAttrLong("flags"));
+ }
+ // Scan local and stack types in this frame:
+ final int LOCALS = 0, STACK = 1;
+ for (int j = LOCALS; j <= STACK; j++) {
+ Element types = frame.findElement(j == LOCALS ? "Local" : "Stack");
+ int typeSize = (types == null) ? 0 : types.size();
+ if (j == LOCALS) {
+ if (ulocalvarIsU4) {
+ u4(typeSize);
+ } else {
+ u2(typeSize);
+ }
+ } else { // STACK
+ if (ustackIsU4) {
+ u4(typeSize);
+ } else {
+ u2(typeSize);
+ }
+ }
+ if (types == null) {
+ continue;
+ }
+ for (Element type : types.elements()) {
+ int tag = itemTagValue(type.getName());
+ u1(tag);
+ switch (tag) {
+ case ITEM_Object:
+ cpRef(CONSTANT_Class, type.getAttr("class"));
+ break;
+ case ITEM_Uninitialized:
+ case ITEM_ReturnAddress: {
+ int offset = (int) type.getAttrLong("bci");
+ if (uoffsetIsU4) {
+ u4(offset);
+ } else {
+ u2(offset);
+ }
+ }
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ public void writeCP() throws IOException {
+ int cpLen = cpoolSize;
+ u2(cpLen);
+ ByteArrayOutputStream buf = getAttrBuf();
+ for (Element c : cpool.elements()) {
+ if (!c.isText()) {
+ System.out.println("## !isText " + c);
+ }
+ int id = (int) c.getAttrLong("id");
+ int tag = cpTagValue(c.getName());
+ String name = c.getText().toString();
+ int pos;
+ u1(tag);
+ switch (tag) {
+ case CONSTANT_Utf8: {
+ int done = 0;
+ buf.reset();
+ int nameLen = name.length();
+ while (done < nameLen) {
+ int next = name.indexOf((char) 0, done);
+ if (next < 0) {
+ next = nameLen;
+ }
+ if (done < next) {
+ buf.write(name.substring(done, next).getBytes(UTF8_ENCODING));
+ }
+ if (next < nameLen) {
+ buf.write(0300);
+ buf.write(0200);
+ next++;
+ }
+ done = next;
+ }
+ u2(buf.size());
+ buf.writeTo(out);
+ }
+ break;
+ case CONSTANT_Integer:
+ u4(Integer.parseInt(name));
+ break;
+ case CONSTANT_Float:
+ u4(Float.floatToIntBits(Float.parseFloat(name)));
+ break;
+ case CONSTANT_Long:
+ u8(Long.parseLong(name));
+ //i += 1; // no need: extra cp slot is implicit
+ break;
+ case CONSTANT_Double:
+ u8(Double.doubleToLongBits(Double.parseDouble(name)));
+ //i += 1; // no need: extra cp slot is implicit
+ break;
+ case CONSTANT_Class:
+ case CONSTANT_String:
+ u2(getCPIndex(CONSTANT_Utf8, name));
+ break;
+ case CONSTANT_Fieldref:
+ case CONSTANT_Methodref:
+ case CONSTANT_InterfaceMethodref:
+ pos = name.indexOf(' ');
+ u2(getCPIndex(CONSTANT_Class, name.substring(0, pos)));
+ u2(getCPIndex(CONSTANT_NameAndType, name.substring(pos + 1)));
+ break;
+ case CONSTANT_NameAndType:
+ pos = name.indexOf(' ');
+ u2(getCPIndex(CONSTANT_Utf8, name.substring(0, pos)));
+ u2(getCPIndex(CONSTANT_Utf8, name.substring(pos + 1)));
+ break;
+ }
+ }
+ putAttrBuf(buf);
+ }
+
+ public void cpRef(int tag, String name) throws IOException {
+ u2(getCPIndex(tag, name));
+ }
+
+ public void u8(long x) throws IOException {
+ u4((int) (x >>> 32));
+ u4((int) (x >>> 0));
+ }
+
+ public void u4(int x) throws IOException {
+ u2(x >>> 16);
+ u2(x >>> 0);
+ }
+
+ public void u2(int x) throws IOException {
+ u1(x >>> 8);
+ u1(x >>> 0);
+ }
+
+ public void u1(int x) throws IOException {
+ out.write(x & 0xFF);
+ }
+}
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/tools/pack200/pack200-verifier/src/xmlkit/CommandLineParser.java Wed Jul 05 17:21:22 2017 +0200
@@ -0,0 +1,284 @@
+/*
+ * Copyright (c) 2010, 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.
+ */
+package xmlkit; // -*- mode: java; indent-tabs-mode: nil -*-
+
+import java.util.*;
+/*
+ * @author jrose
+ */
+public class CommandLineParser {
+
+ public CommandLineParser(String optionString) {
+ setOptionMap(optionString);
+ }
+ TreeMap<String, String[]> optionMap;
+
+ public void setOptionMap(String options) {
+ // Convert options string into optLines dictionary.
+ TreeMap<String, String[]> optmap = new TreeMap<String, String[]>();
+ loadOptmap:
+ for (String optline : options.split("\n")) {
+ String[] words = optline.split("\\p{Space}+");
+ if (words.length == 0) {
+ continue loadOptmap;
+ }
+ String opt = words[0];
+ words[0] = ""; // initial word is not a spec
+ if (opt.length() == 0 && words.length >= 1) {
+ opt = words[1]; // initial "word" is empty due to leading ' '
+ words[1] = "";
+ }
+ if (opt.length() == 0) {
+ continue loadOptmap;
+ }
+ String[] prevWords = optmap.put(opt, words);
+ if (prevWords != null) {
+ throw new RuntimeException("duplicate option: "
+ + optline.trim());
+ }
+ }
+ optionMap = optmap;
+ }
+
+ public String getOptionMap() {
+ TreeMap<String, String[]> optmap = optionMap;
+ StringBuffer sb = new StringBuffer();
+ for (String opt : optmap.keySet()) {
+ sb.append(opt);
+ for (String spec : optmap.get(opt)) {
+ sb.append(' ').append(spec);
+ }
+ sb.append('\n');
+ }
+ return sb.toString();
+ }
+
+ /**
+ * Remove a set of command-line options from args,
+ * storing them in the properties map in a canonicalized form.
+ */
+ public String parse(List<String> args, Map<String, String> properties) {
+ //System.out.println(args+" // "+properties);
+
+ String resultString = null;
+ TreeMap<String, String[]> optmap = optionMap;
+
+ // State machine for parsing a command line.
+ ListIterator<String> argp = args.listIterator();
+ ListIterator<String> pbp = new ArrayList<String>().listIterator();
+ doArgs:
+ for (;;) {
+ // One trip through this loop per argument.
+ // Multiple trips per option only if several options per argument.
+ String arg;
+ if (pbp.hasPrevious()) {
+ arg = pbp.previous();
+ pbp.remove();
+ } else if (argp.hasNext()) {
+ arg = argp.next();
+ } else {
+ // No more arguments at all.
+ break doArgs;
+ }
+ tryOpt:
+ for (int optlen = arg.length();; optlen--) {
+ // One time through this loop for each matching arg prefix.
+ String opt;
+ // Match some prefix of the argument to a key in optmap.
+ findOpt:
+ for (;;) {
+ opt = arg.substring(0, optlen);
+ if (optmap.containsKey(opt)) {
+ break findOpt;
+ }
+ if (optlen == 0) {
+ break tryOpt;
+ }
+ // Decide on a smaller prefix to search for.
+ SortedMap<String, String[]> pfxmap = optmap.headMap(opt);
+ // pfxmap.lastKey is no shorter than any prefix in optmap.
+ int len = pfxmap.isEmpty() ? 0 : pfxmap.lastKey().length();
+ optlen = Math.min(len, optlen - 1);
+ opt = arg.substring(0, optlen);
+ // (Note: We could cut opt down to its common prefix with
+ // pfxmap.lastKey, but that wouldn't save many cycles.)
+ }
+ opt = opt.intern();
+ assert (arg.startsWith(opt));
+ assert (opt.length() == optlen);
+ String val = arg.substring(optlen); // arg == opt+val
+
+ // Execute the option processing specs for this opt.
+ // If no actions are taken, then look for a shorter prefix.
+ boolean didAction = false;
+ boolean isError = false;
+
+ int pbpMark = pbp.nextIndex(); // in case of backtracking
+ String[] specs = optmap.get(opt);
+ eachSpec:
+ for (String spec : specs) {
+ if (spec.length() == 0) {
+ continue eachSpec;
+ }
+ if (spec.startsWith("#")) {
+ break eachSpec;
+ }
+ int sidx = 0;
+ char specop = spec.charAt(sidx++);
+
+ // Deal with '+'/'*' prefixes (spec conditions).
+ boolean ok;
+ switch (specop) {
+ case '+':
+ // + means we want an non-empty val suffix.
+ ok = (val.length() != 0);
+ specop = spec.charAt(sidx++);
+ break;
+ case '*':
+ // * means we accept empty or non-empty
+ ok = true;
+ specop = spec.charAt(sidx++);
+ break;
+ default:
+ // No condition prefix means we require an exact
+ // match, as indicated by an empty val suffix.
+ ok = (val.length() == 0);
+ break;
+ }
+ if (!ok) {
+ continue eachSpec;
+ }
+
+ String specarg = spec.substring(sidx);
+ switch (specop) {
+ case '.': // terminate the option sequence
+ resultString = (specarg.length() != 0) ? specarg.intern() : opt;
+ break doArgs;
+ case '?': // abort the option sequence
+ resultString = (specarg.length() != 0) ? specarg.intern() : arg;
+ isError = true;
+ break eachSpec;
+ case '@': // change the effective opt name
+ opt = specarg.intern();
+ break;
+ case '>': // shift remaining arg val to next arg
+ pbp.add(specarg + val); // push a new argument
+ val = "";
+ break;
+ case '!': // negation option
+ String negopt = (specarg.length() != 0) ? specarg.intern() : opt;
+ properties.remove(negopt);
+ properties.put(negopt, null); // leave placeholder
+ didAction = true;
+ break;
+ case '$': // normal "boolean" option
+ String boolval;
+ if (specarg.length() != 0) {
+ // If there is a given spec token, store it.
+ boolval = specarg;
+ } else {
+ String old = properties.get(opt);
+ if (old == null || old.length() == 0) {
+ boolval = "1";
+ } else {
+ // Increment any previous value as a numeral.
+ boolval = "" + (1 + Integer.parseInt(old));
+ }
+ }
+ properties.put(opt, boolval);
+ didAction = true;
+ break;
+ case '=': // "string" option
+ case '&': // "collection" option
+ // Read an option.
+ boolean append = (specop == '&');
+ String strval;
+ if (pbp.hasPrevious()) {
+ strval = pbp.previous();
+ pbp.remove();
+ } else if (argp.hasNext()) {
+ strval = argp.next();
+ } else {
+ resultString = arg + " ?";
+ isError = true;
+ break eachSpec;
+ }
+ if (append) {
+ String old = properties.get(opt);
+ if (old != null) {
+ // Append new val to old with embedded delim.
+ String delim = specarg;
+ if (delim.length() == 0) {
+ delim = " ";
+ }
+ strval = old + specarg + strval;
+ }
+ }
+ properties.put(opt, strval);
+ didAction = true;
+ break;
+ default:
+ throw new RuntimeException("bad spec for "
+ + opt + ": " + spec);
+ }
+ }
+
+ // Done processing specs.
+ if (didAction && !isError) {
+ continue doArgs;
+ }
+
+ // The specs should have done something, but did not.
+ while (pbp.nextIndex() > pbpMark) {
+ // Remove anything pushed during these specs.
+ pbp.previous();
+ pbp.remove();
+ }
+
+ if (isError) {
+ throw new IllegalArgumentException(resultString);
+ }
+
+ if (optlen == 0) {
+ // We cannot try a shorter matching option.
+ break tryOpt;
+ }
+ }
+
+ // If we come here, there was no matching option.
+ // So, push back the argument, and return to caller.
+ pbp.add(arg);
+ break doArgs;
+ }
+ // Report number of arguments consumed.
+ args.subList(0, argp.nextIndex()).clear();
+ // Report any unconsumed partial argument.
+ while (pbp.hasPrevious()) {
+ args.add(0, pbp.previous());
+ }
+ //System.out.println(args+" // "+properties+" -> "+resultString);
+ return resultString;
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/tools/pack200/pack200-verifier/src/xmlkit/InstructionAssembler.java Wed Jul 05 17:21:22 2017 +0200
@@ -0,0 +1,464 @@
+/*
+ * Copyright (c) 2010, 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.
+ */
+package xmlkit; // -*- mode: java; indent-tabs-mode: nil -*-
+
+import xmlkit.XMLKit.Element;
+import java.util.HashMap;
+/*
+ * @author jrose
+ */
+abstract class InstructionAssembler extends InstructionSyntax {
+
+ InstructionAssembler() {
+ }
+
+ public static String assemble(Element instructions, String pcAttrName,
+ ClassSyntax.GetCPIndex getCPI) {
+ int insCount = instructions.size();
+ Element[] insElems = new Element[insCount];
+ int[] elemToIndexMap;
+ int[] insLocs;
+ byte[] ops = new byte[insCount];
+ int[] operands = new int[insCount];
+ boolean[] isWide = new boolean[insCount];
+ int[] branches;
+ int[] branchInsLocs;
+ HashMap<String, String> labels = new HashMap<String, String>();
+
+ final int WIDE = 0xc4;
+ final int GOTO = 0xa7;
+ final int GOTO_W = 0xc8;
+ final int GOTO_LEN = 3;
+ final int GOTO_W_LEN = 5;
+ assert ("wide".equals(bcNames[WIDE]));
+ assert ("goto".equals(bcNames[GOTO]));
+ assert ("goto_w".equals(bcNames[GOTO_W]));
+ assert (bcFormats[GOTO].length() == GOTO_LEN);
+ assert (bcFormats[GOTO_W].length() == GOTO_W_LEN);
+
+ // Unpack instructions into temp. arrays, and find branches and labels.
+ {
+ elemToIndexMap = (pcAttrName != null) ? new int[insCount] : null;
+ int[] buffer = operands;
+ int id = 0;
+ int branchCount = 0;
+ for (int i = 0; i < insCount; i++) {
+ Element ins = (Element) instructions.get(i);
+ if (elemToIndexMap != null) {
+ elemToIndexMap[i] = (ins.getAttr(pcAttrName) != null ? id : -1);
+ }
+ String lab = ins.getAttr("pc");
+ if (lab != null) {
+ labels.put(lab, String.valueOf(id));
+ }
+ int op = opCode(ins.getName());
+ if (op < 0) {
+ assert (ins.getAttr(pcAttrName) != null
+ || ins.getName().equals("label"));
+ continue; // delete PC holder element
+ }
+ if (op == WIDE) { //0xc4
+ isWide[id] = true; // force wide format
+ continue;
+ }
+ if (bcFormats[op].indexOf('o') >= 0) {
+ buffer[branchCount++] = id;
+ }
+ if (bcFormats[op] == bcWideFormats[op]) {
+ isWide[id] = false;
+ }
+ insElems[id] = ins;
+ ops[id] = (byte) op;
+ id++;
+ }
+ insCount = id; // maybe we deleted some wide prefixes, etc.
+ branches = new int[branchCount + 1];
+ System.arraycopy(buffer, 0, branches, 0, branchCount);
+ branches[branchCount] = -1; // sentinel
+ }
+
+ // Compute instruction sizes. These sizes are final,
+ // except for branch instructions, which may need lengthening.
+ // Some instructions (ldc, bipush, iload, iinc) are automagically widened.
+ insLocs = new int[insCount + 1];
+ int loc = 0;
+ for (int bn = 0, id = 0; id < insCount; id++) {
+ insLocs[id] = loc;
+ Element ins = insElems[id];
+ int op = ops[id] & 0xFF;
+ String format = opFormat(op, isWide[id]);
+ // Make sure operands fit within the given format.
+ for (int j = 1, jlimit = format.length(); j < jlimit; j++) {
+ char fc = format.charAt(j);
+ int x = 0;
+ switch (fc) {
+ case 'l':
+ x = (int) ins.getAttrLong("loc");
+ assert (x >= 0);
+ if (x > 0xFF && !isWide[id]) {
+ isWide[id] = true;
+ format = opFormat(op, isWide[id]);
+ }
+ assert (x <= 0xFFFF);
+ break;
+ case 'k':
+ char fc2 = format.charAt(Math.min(j + 1, format.length() - 1));
+ x = getCPIndex(ins, fc2, getCPI);
+ if (x > 0xFF && j == jlimit - 1) {
+ assert (op == 0x12); //ldc
+ ops[id] = (byte) (op = 0x13); //ldc_w
+ format = opFormat(op);
+ }
+ assert (x <= 0xFFFF);
+ j++; // skip type-of-constant marker
+ break;
+ case 'x':
+ x = (int) ins.getAttrLong("num");
+ assert (x >= 0 && x <= ((j == jlimit - 1) ? 0xFF : 0xFFFF));
+ break;
+ case 's':
+ x = (int) ins.getAttrLong("num");
+ if (x != (byte) x && j == jlimit - 1) {
+ switch (op) {
+ case 0x10: //bipush
+ ops[id] = (byte) (op = 0x11); //sipush
+ break;
+ case 0x84: //iinc
+ isWide[id] = true;
+ format = opFormat(op, isWide[id]);
+ break;
+ default:
+ assert (false); // cannot lengthen
+ }
+ }
+ // unsign the value now, to make later steps clearer
+ if (j == jlimit - 1) {
+ assert (x == (byte) x);
+ x = x & 0xFF;
+ } else {
+ assert (x == (short) x);
+ x = x & 0xFFFF;
+ }
+ break;
+ case 'o':
+ assert (branches[bn] == id);
+ bn++;
+ // make local copies of the branches, and fix up labels
+ insElems[id] = ins = new Element(ins);
+ String newLab = labels.get(ins.getAttr("lab"));
+ assert (newLab != null);
+ ins.setAttr("lab", newLab);
+ int prevCas = 0;
+ int k = 0;
+ for (Element cas : ins.elements()) {
+ assert (cas.getName().equals("Case"));
+ ins.set(k++, cas = new Element(cas));
+ newLab = labels.get(cas.getAttr("lab"));
+ assert (newLab != null);
+ cas.setAttr("lab", newLab);
+ int thisCas = (int) cas.getAttrLong("num");
+ assert (op == 0xab
+ || op == 0xaa && (k == 0 || thisCas == prevCas + 1));
+ prevCas = thisCas;
+ }
+ break;
+ case 't':
+ // switch table is represented as Switch.Case sub-elements
+ break;
+ default:
+ assert (false);
+ }
+ operands[id] = x; // record operand (last if there are 2)
+ // skip redundant chars
+ while (j + 1 < jlimit && format.charAt(j + 1) == fc) {
+ ++j;
+ }
+ }
+
+ switch (op) {
+ case 0xaa: //tableswitch
+ loc = switchBase(loc);
+ loc += 4 * (3 + ins.size());
+ break;
+ case 0xab: //lookupswitch
+ loc = switchBase(loc);
+ loc += 4 * (2 + 2 * ins.size());
+ break;
+ default:
+ if (isWide[id]) {
+ loc++; // 'wide' opcode prefix
+ }
+ loc += format.length();
+ break;
+ }
+ }
+ insLocs[insCount] = loc;
+
+ // compute branch offsets, and see if any branches need expansion
+ for (int maxTries = 9, tries = 0;; ++tries) {
+ boolean overflowing = false;
+ boolean[] branchExpansions = null;
+ for (int bn = 0; bn < branches.length - 1; bn++) {
+ int id = branches[bn];
+ Element ins = insElems[id];
+ int insSize = insLocs[id + 1] - insLocs[id];
+ int origin = insLocs[id];
+ int target = insLocs[(int) ins.getAttrLong("lab")];
+ int offset = target - origin;
+ operands[id] = offset;
+ //System.out.println("branch id="+id+" len="+insSize+" to="+target+" offset="+offset);
+ assert (insSize == GOTO_LEN || insSize == GOTO_W_LEN || ins.getName().indexOf("switch") > 0);
+ boolean thisOverflow = (insSize == GOTO_LEN && (offset != (short) offset));
+ if (thisOverflow && !overflowing) {
+ overflowing = true;
+ branchExpansions = new boolean[branches.length];
+ }
+ if (thisOverflow || tries == maxTries - 1) {
+ // lengthen the branch
+ assert (!(thisOverflow && isWide[id]));
+ isWide[id] = true;
+ branchExpansions[bn] = true;
+ }
+ }
+ if (!overflowing) {
+ break; // done, usually on first try
+ }
+ assert (tries <= maxTries);
+
+ // Walk over all instructions, expanding branches and updating locations.
+ int fixup = 0;
+ for (int bn = 0, id = 0; id < insCount; id++) {
+ insLocs[id] += fixup;
+ if (branches[bn] == id) {
+ int op = ops[id] & 0xFF;
+ int wop;
+ boolean invert;
+ if (branchExpansions[bn]) {
+ switch (op) {
+ case GOTO: //0xa7
+ wop = GOTO_W; //0xc8
+ invert = false;
+ break;
+ case 0xa8: //jsr
+ wop = 0xc9; //jsr_w
+ invert = false;
+ break;
+ default:
+ wop = invertBranchOp(op);
+ invert = true;
+ break;
+ }
+ assert (op != wop);
+ ops[id] = (byte) wop;
+ isWide[id] = invert;
+ if (invert) {
+ fixup += GOTO_W_LEN; //branch around a wide goto
+ } else {
+ fixup += (GOTO_W_LEN - GOTO_LEN);
+ }
+ // done expanding: ops and isWide reflect the decision
+ }
+ bn++;
+ }
+ }
+ insLocs[insCount] += fixup;
+ }
+ // we know the layout now
+
+ // notify the caller of offsets, if requested
+ if (elemToIndexMap != null) {
+ for (int i = 0; i < elemToIndexMap.length; i++) {
+ int id = elemToIndexMap[i];
+ if (id >= 0) {
+ Element ins = (Element) instructions.get(i);
+ ins.setAttr(pcAttrName, "" + insLocs[id]);
+ }
+ }
+ elemToIndexMap = null; // release the pointer
+ }
+
+ // output the bytes
+ StringBuffer sbuf = new StringBuffer(insLocs[insCount]);
+ for (int bn = 0, id = 0; id < insCount; id++) {
+ //System.out.println("output id="+id+" loc="+insLocs[id]+" len="+(insLocs[id+1]-insLocs[id])+" #sbuf="+sbuf.length());
+ assert (sbuf.length() == insLocs[id]);
+ Element ins;
+ int pc = insLocs[id];
+ int nextpc = insLocs[id + 1];
+ int op = ops[id] & 0xFF;
+ int opnd = operands[id];
+ String format;
+ if (branches[bn] == id) {
+ bn++;
+ sbuf.append((char) op);
+ if (isWide[id]) {
+ // emit <ifop lab=1f> <goto_w target> <label pc=1f>
+ int target = pc + opnd;
+ putInt(sbuf, nextpc - pc, -2);
+ assert (sbuf.length() == pc + GOTO_LEN);
+ sbuf.append((char) GOTO_W);
+ putInt(sbuf, target - (pc + GOTO_LEN), 4);
+ } else if (op == 0xaa || //tableswitch
+ op == 0xab) { //lookupswitch
+ ins = insElems[id];
+ for (int pad = switchBase(pc) - (pc + 1); pad > 0; pad--) {
+ sbuf.append((char) 0);
+ }
+ assert (pc + opnd == insLocs[(int) ins.getAttrLong("lab")]);
+ putInt(sbuf, opnd, 4); // default label
+ if (op == 0xaa) { //tableswitch
+ Element cas0 = (Element) ins.get(0);
+ int lowCase = (int) cas0.getAttrLong("num");
+ Element casN = (Element) ins.get(ins.size() - 1);
+ int highCase = (int) casN.getAttrLong("num");
+ assert (highCase - lowCase + 1 == ins.size());
+ putInt(sbuf, lowCase, 4);
+ putInt(sbuf, highCase, 4);
+ int caseForAssert = lowCase;
+ for (Element cas : ins.elements()) {
+ int target = insLocs[(int) cas.getAttrLong("lab")];
+ assert (cas.getAttrLong("num") == caseForAssert++);
+ putInt(sbuf, target - pc, 4);
+ }
+ } else { //lookupswitch
+ int caseCount = ins.size();
+ putInt(sbuf, caseCount, 4);
+ for (Element cas : ins.elements()) {
+ int target = insLocs[(int) cas.getAttrLong("lab")];
+ putInt(sbuf, (int) cas.getAttrLong("num"), 4);
+ putInt(sbuf, target - pc, 4);
+ }
+ }
+ assert (nextpc == sbuf.length());
+ } else {
+ putInt(sbuf, opnd, -(nextpc - (pc + 1)));
+ }
+ } else if (nextpc == pc + 1) {
+ // a single-byte instruction
+ sbuf.append((char) op);
+ } else {
+ // picky stuff
+ boolean wide = isWide[id];
+ if (wide) {
+ sbuf.append((char) WIDE);
+ pc++;
+ }
+ sbuf.append((char) op);
+ int opnd1;
+ int opnd2 = opnd;
+ switch (op) {
+ case 0x84: //iinc
+ ins = insElems[id];
+ opnd1 = (int) ins.getAttrLong("loc");
+ if (isWide[id]) {
+ putInt(sbuf, opnd1, 2);
+ putInt(sbuf, opnd2, 2);
+ } else {
+ putInt(sbuf, opnd1, 1);
+ putInt(sbuf, opnd2, 1);
+ }
+ break;
+ case 0xc5: //multianewarray
+ ins = insElems[id];
+ opnd1 = getCPIndex(ins, 'c', getCPI);
+ putInt(sbuf, opnd1, 2);
+ putInt(sbuf, opnd2, 1);
+ break;
+ case 0xb9: //invokeinterface
+ ins = insElems[id];
+ opnd1 = getCPIndex(ins, 'n', getCPI);
+ putInt(sbuf, opnd1, 2);
+ opnd2 = (int) ins.getAttrLong("num");
+ if (opnd2 == 0) {
+ opnd2 = ClassSyntax.computeInterfaceNum(ins.getAttr("val"));
+ }
+ putInt(sbuf, opnd2, 2);
+ break;
+ default:
+ // put the single operand and be done
+ putInt(sbuf, opnd, nextpc - (pc + 1));
+ break;
+ }
+ }
+ }
+ assert (sbuf.length() == insLocs[insCount]);
+
+ return sbuf.toString();
+ }
+
+ static int getCPIndex(Element ins, char ctype,
+ ClassSyntax.GetCPIndex getCPI) {
+ int x = (int) ins.getAttrLong("ref");
+ if (x == 0 && getCPI != null) {
+ String val = ins.getAttr("val");
+ if (val == null || val.equals("")) {
+ val = ins.getText().toString();
+ }
+ byte tag;
+ switch (ctype) {
+ case 'k':
+ tag = (byte) ins.getAttrLong("tag");
+ break;
+ case 'c':
+ tag = ClassSyntax.CONSTANT_Class;
+ break;
+ case 'f':
+ tag = ClassSyntax.CONSTANT_Fieldref;
+ break;
+ case 'm':
+ tag = ClassSyntax.CONSTANT_Methodref;
+ break;
+ case 'n':
+ tag = ClassSyntax.CONSTANT_InterfaceMethodref;
+ break;
+ default:
+ throw new Error("bad ctype " + ctype + " in " + ins);
+ }
+ x = getCPI.getCPIndex(tag, val);
+ //System.out.println("getCPIndex "+ins+" => "+tag+"/"+val+" => "+x);
+ } else {
+ assert (x > 0);
+ }
+ return x;
+ }
+
+ static void putInt(StringBuffer sbuf, int x, int len) {
+ //System.out.println("putInt x="+x+" len="+len);
+ boolean isSigned = false;
+ if (len < 0) {
+ len = -len;
+ isSigned = true;
+ }
+ assert (len == 1 || len == 2 || len == 4);
+ int insig = ((4 - len) * 8); // how many insignificant bits?
+ int sx = x << insig;
+ ;
+ assert (x == (isSigned ? (sx >> insig) : (sx >>> insig)));
+ for (int i = 0; i < len; i++) {
+ sbuf.append((char) (sx >>> 24));
+ sx <<= 8;
+ }
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/tools/pack200/pack200-verifier/src/xmlkit/InstructionSyntax.java Wed Jul 05 17:21:22 2017 +0200
@@ -0,0 +1,483 @@
+/*
+ * Copyright (c) 2010, 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.
+ */
+package xmlkit; // -*- mode: java; indent-tabs-mode: nil -*-
+
+import xmlkit.XMLKit.Element;
+import java.util.HashMap;
+import java.util.Map;
+/*
+ * @author jrose
+ */
+public abstract class InstructionSyntax {
+
+ InstructionSyntax() {
+ }
+ static final String[] bcNames;
+ static final String[] bcFormats;
+ static final String[] bcWideFormats;
+ static final HashMap<String, Integer> bcCodes;
+ static final HashMap<String, Element> abbrevs;
+ static final HashMap<Element, String> rabbrevs;
+
+ static {
+ TokenList tl = new TokenList(
+ " nop aconst_null iconst_m1 iconst_0 iconst_1 iconst_2 iconst_3"
+ + " iconst_4 iconst_5 lconst_0 lconst_1 fconst_0 fconst_1 fconst_2"
+ + " dconst_0 dconst_1 bipush/s sipush/ss ldc/k ldc_w/kk ldc2_w/kk"
+ + " iload/wl lload/wl fload/wl dload/wl aload/wl iload_0 iload_1"
+ + " iload_2 iload_3 lload_0 lload_1 lload_2 lload_3 fload_0 fload_1"
+ + " fload_2 fload_3 dload_0 dload_1 dload_2 dload_3 aload_0 aload_1"
+ + " aload_2 aload_3 iaload laload faload daload aaload baload caload"
+ + " saload istore/wl lstore/wl fstore/wl dstore/wl astore/wl"
+ + " istore_0 istore_1 istore_2 istore_3 lstore_0 lstore_1 lstore_2"
+ + " lstore_3 fstore_0 fstore_1 fstore_2 fstore_3 dstore_0 dstore_1"
+ + " dstore_2 dstore_3 astore_0 astore_1 astore_2 astore_3 iastore"
+ + " lastore fastore dastore aastore bastore castore sastore pop pop2"
+ + " dup dup_x1 dup_x2 dup2 dup2_x1 dup2_x2 swap iadd ladd fadd dadd"
+ + " isub lsub fsub dsub imul lmul fmul dmul idiv ldiv fdiv ddiv irem"
+ + " lrem frem drem ineg lneg fneg dneg ishl lshl ishr lshr iushr"
+ + " lushr iand land ior lor ixor lxor iinc/wls i2l i2f i2d l2i l2f"
+ + " l2d f2i f2l f2d d2i d2l d2f i2b i2c i2s lcmp fcmpl fcmpg dcmpl"
+ + " dcmpg ifeq/oo ifne/oo iflt/oo ifge/oo ifgt/oo ifle/oo"
+ + " if_icmpeq/oo if_icmpne/oo if_icmplt/oo if_icmpge/oo if_icmpgt/oo"
+ + " if_icmple/oo if_acmpeq/oo if_acmpne/oo goto/oo jsr/oo ret/wl"
+ + " tableswitch/oooot lookupswitch/oooot ireturn lreturn freturn dreturn areturn"
+ + " return getstatic/kf putstatic/kf getfield/kf putfield/kf"
+ + " invokevirtual/km invokespecial/km invokestatic/km"
+ + " invokeinterface/knxx xxxunusedxxx new/kc newarray/x anewarray/kc"
+ + " arraylength athrow checkcast/kc instanceof/kc monitorenter"
+ + " monitorexit wide multianewarray/kcx ifnull/oo ifnonnull/oo"
+ + " goto_w/oooo jsr_w/oooo");
+ assert (tl.size() == 202); // this many instructions!
+ HashMap<String, Integer> map = new HashMap<String, Integer>(tl.size());
+ String[] names = tl.toArray(new String[tl.size()]);
+ String[] formats = new String[names.length];
+ String[] wideFormats = new String[names.length];
+ StringBuilder sbuf = new StringBuilder();
+ sbuf.append('i'); // all op formats begin with "i"
+ int i = 0;
+ for (String ins : names) {
+ assert (ins == ins.trim()); // no whitespace
+ int sfx = ins.indexOf('/');
+ String format = "i";
+ String wideFormat = null;
+ if (sfx >= 0) {
+ format = ins.substring(sfx + 1);
+ ins = ins.substring(0, sfx);
+ if (format.charAt(0) == 'w') {
+ format = format.substring(1);
+ sbuf.setLength(1);
+ for (int j = 0; j < format.length(); j++) {
+ // double everything except the initial 'i'
+ sbuf.append(format.charAt(j));
+ sbuf.append(format.charAt(j));
+ }
+ wideFormat = sbuf.toString().intern();
+ }
+ sbuf.setLength(1);
+ sbuf.append(format);
+ format = sbuf.toString().intern();
+ }
+ ins = ins.intern();
+ names[i] = ins;
+ formats[i] = format;
+ wideFormats[i] = (wideFormat != null) ? wideFormat : format;
+ //System.out.println(ins+" "+format+" "+wideFormat);
+ map.put(ins, i++);
+ }
+ //map = Collections.unmodifiableMap(map);
+
+ HashMap<String, Element> abb = new HashMap<String, Element>(tl.size() / 2);
+ abb.put("iconst_m1", new Element("bipush", "num", "-1"));
+ for (String ins : names) {
+ int sfx = ins.indexOf('_');
+ if (sfx >= 0 && Character.isDigit(ins.charAt(sfx + 1))) {
+ String pfx = ins.substring(0, sfx).intern();
+ String num = ins.substring(sfx + 1);
+ String att = pfx.endsWith("const") ? "num" : "loc";
+ Element exp = new Element(pfx, att, num).deepFreeze();
+ abb.put(ins, exp);
+ }
+ }
+ //abb = Collections.unmodifiableMap(abb);
+ HashMap<Element, String> rabb = new HashMap<Element, String>(tl.size() / 2);
+ for (Map.Entry<String, Element> e : abb.entrySet()) {
+ rabb.put(e.getValue(), e.getKey());
+ }
+ //rabb = Collections.unmodifiableMap(rabb);
+
+
+ bcNames = names;
+ bcFormats = formats;
+ bcWideFormats = wideFormats;
+ bcCodes = map;
+ abbrevs = abb;
+ rabbrevs = rabb;
+ }
+
+ public static String opName(int op) {
+ if (op >= 0 && op < bcNames.length) {
+ return bcNames[op];
+ }
+ return "unknown#" + op;
+ }
+
+ public static String opFormat(int op) {
+ return opFormat(op, false);
+ }
+
+ public static String opFormat(int op, boolean isWide) {
+ if (op >= 0 && op < bcFormats.length) {
+ return (isWide ? bcWideFormats[op] : bcFormats[op]);
+ }
+ return "?";
+ }
+
+ public static int opCode(String opName) {
+ Integer op = (Integer) bcCodes.get(opName);
+ if (op != null) {
+ return op.intValue();
+ }
+ return -1;
+ }
+
+ public static Element expandAbbrev(String opName) {
+ return abbrevs.get(opName);
+ }
+
+ public static String findAbbrev(Element op) {
+ return rabbrevs.get(op);
+ }
+
+ public static int invertBranchOp(int op) {
+ assert (opFormat(op).indexOf('o') >= 0);
+ final int IFMIN = 0x99;
+ final int IFMAX = 0xa6;
+ final int IFMIN2 = 0xc6;
+ final int IFMAX2 = 0xc7;
+ assert (bcNames[IFMIN] == "ifeq");
+ assert (bcNames[IFMAX] == "if_acmpne");
+ assert (bcNames[IFMIN2] == "ifnonnull");
+ assert (bcNames[IFMAX2] == "ifnull");
+ int rop;
+ if (op >= IFMIN && op <= IFMAX) {
+ rop = IFMIN + ((op - IFMIN) ^ 1);
+ } else if (op >= IFMIN2 && op <= IFMAX2) {
+ rop = IFMIN2 + ((op - IFMIN2) ^ 1);
+ } else {
+ assert (false);
+ rop = op;
+ }
+ assert (opFormat(rop).indexOf('o') >= 0);
+ return rop;
+ }
+
+ public static Element parse(String bytes) {
+ Element e = new Element("Instructions", bytes.length());
+ boolean willBeWide;
+ boolean isWide = false;
+ Element[] tempMap = new Element[bytes.length()];
+ for (int pc = 0, nextpc; pc < bytes.length(); pc = nextpc) {
+ int op = bytes.charAt(pc);
+ Element i = new Element(opName(op));
+
+ nextpc = pc + 1;
+ int locarg = 0;
+ int cparg = 0;
+ int intarg = 0;
+ int labelarg = 0;
+
+ willBeWide = false;
+ switch (op) {
+ case 0xc4: //wide
+ willBeWide = true;
+ break;
+ case 0x10: //bipush
+ intarg = nextpc++;
+ intarg *= -1; //mark signed
+ break;
+ case 0x11: //sipush
+ intarg = nextpc;
+ nextpc += 2;
+ intarg *= -1; //mark signed
+ break;
+ case 0x12: //ldc
+ cparg = nextpc++;
+ break;
+ case 0x13: //ldc_w
+ case 0x14: //ldc2_w
+ case 0xb2: //getstatic
+ case 0xb3: //putstatic
+ case 0xb4: //getfield
+ case 0xb5: //putfield
+ case 0xb6: //invokevirtual
+ case 0xb7: //invokespecial
+ case 0xb8: //invokestatic
+ case 0xbb: //new
+ case 0xbd: //anewarray
+ case 0xc0: //checkcast
+ case 0xc1: //instanceof
+ cparg = nextpc;
+ nextpc += 2;
+ break;
+ case 0xb9: //invokeinterface
+ cparg = nextpc;
+ nextpc += 2;
+ intarg = nextpc;
+ nextpc += 2;
+ break;
+ case 0xc5: //multianewarray
+ cparg = nextpc;
+ nextpc += 2;
+ intarg = nextpc++;
+ break;
+ case 0x15: //iload
+ case 0x16: //lload
+ case 0x17: //fload
+ case 0x18: //dload
+ case 0x19: //aload
+ case 0x36: //istore
+ case 0x37: //lstore
+ case 0x38: //fstore
+ case 0x39: //dstore
+ case 0x3a: //astore
+ case 0xa9: //ret
+ locarg = nextpc++;
+ if (isWide) {
+ nextpc++;
+ }
+ break;
+ case 0x84: //iinc
+ locarg = nextpc++;
+ if (isWide) {
+ nextpc++;
+ }
+ intarg = nextpc++;
+ if (isWide) {
+ nextpc++;
+ }
+ intarg *= -1; //mark signed
+ break;
+ case 0x99: //ifeq
+ case 0x9a: //ifne
+ case 0x9b: //iflt
+ case 0x9c: //ifge
+ case 0x9d: //ifgt
+ case 0x9e: //ifle
+ case 0x9f: //if_icmpeq
+ case 0xa0: //if_icmpne
+ case 0xa1: //if_icmplt
+ case 0xa2: //if_icmpge
+ case 0xa3: //if_icmpgt
+ case 0xa4: //if_icmple
+ case 0xa5: //if_acmpeq
+ case 0xa6: //if_acmpne
+ case 0xa7: //goto
+ case 0xa8: //jsr
+ labelarg = nextpc;
+ nextpc += 2;
+ break;
+ case 0xbc: //newarray
+ intarg = nextpc++;
+ break;
+ case 0xc6: //ifnull
+ case 0xc7: //ifnonnull
+ labelarg = nextpc;
+ nextpc += 2;
+ break;
+ case 0xc8: //goto_w
+ case 0xc9: //jsr_w
+ labelarg = nextpc;
+ nextpc += 4;
+ break;
+
+ // save the best for last:
+ case 0xaa: //tableswitch
+ nextpc = parseSwitch(bytes, pc, true, i);
+ break;
+ case 0xab: //lookupswitch
+ nextpc = parseSwitch(bytes, pc, false, i);
+ break;
+ }
+
+ String format = null;
+ assert ((format = opFormat(op, isWide)) != null);
+ //System.out.println("pc="+pc+" len="+(nextpc - pc)+" w="+isWide+" op="+op+" name="+opName(op)+" format="+format);
+ assert ((nextpc - pc) == format.length() || format.indexOf('t') >= 0);
+
+ // Parse out instruction fields.
+ if (locarg != 0) {
+ int len = nextpc - locarg;
+ if (intarg != 0) {
+ len /= 2; // split
+ }
+ i.setAttr("loc", "" + getInt(bytes, locarg, len));
+ assert ('l' == format.charAt(locarg - pc + 0));
+ assert ('l' == format.charAt(locarg - pc + len - 1));
+ }
+ if (cparg != 0) {
+ int len = nextpc - cparg;
+ if (len > 2) {
+ len = 2;
+ }
+ i.setAttr("ref", "" + getInt(bytes, cparg, len));
+ assert ('k' == format.charAt(cparg - pc + 0));
+ }
+ if (intarg != 0) {
+ boolean isSigned = (intarg < 0);
+ if (isSigned) {
+ intarg *= -1;
+ }
+ int len = nextpc - intarg;
+ i.setAttr("num", "" + getInt(bytes, intarg, isSigned ? -len : len));
+ assert ((isSigned ? 's' : 'x') == format.charAt(intarg - pc + 0));
+ assert ((isSigned ? 's' : 'x') == format.charAt(intarg - pc + len - 1));
+ }
+ if (labelarg != 0) {
+ int len = nextpc - labelarg;
+ int offset = getInt(bytes, labelarg, -len);
+ int target = pc + offset;
+ i.setAttr("lab", "" + target);
+ assert ('o' == format.charAt(labelarg - pc + 0));
+ assert ('o' == format.charAt(labelarg - pc + len - 1));
+ }
+
+ e.add(i);
+ tempMap[pc] = i;
+ isWide = willBeWide;
+ }
+
+ // Mark targets of branches.
+ for (Element i : e.elements()) {
+ for (int j = -1; j < i.size(); j++) {
+ Element c = (j < 0) ? i : (Element) i.get(j);
+ Number targetNum = c.getAttrNumber("lab");
+ if (targetNum != null) {
+ int target = targetNum.intValue();
+ Element ti = null;
+ if (target >= 0 && target < tempMap.length) {
+ ti = tempMap[target];
+ }
+ if (ti != null) {
+ ti.setAttr("pc", "" + target);
+ } else {
+ c.setAttr("lab.error", "");
+ }
+ }
+ }
+ }
+
+ // Shrink to fit:
+ for (Element i : e.elements()) {
+ i.trimToSize();
+ }
+ e.trimToSize();
+
+ /*
+ String assem = assemble(e);
+ if (!assem.equals(bytes)) {
+ System.out.println("Bytes: "+bytes);
+ System.out.println("Insns: "+e);
+ System.out.println("Assem: "+parse(assem));
+ }
+ */
+
+ return e;
+ }
+
+ static int switchBase(int pc) {
+ int apc = pc + 1;
+ apc += (-apc) & 3;
+ return apc;
+ }
+
+ static int parseSwitch(String s, int pc, boolean isTable, Element i) {
+ int apc = switchBase(pc);
+ int defLabel = pc + getInt(s, apc + 4 * 0, 4);
+ i.setAttr("lab", "" + defLabel);
+ if (isTable) {
+ int lowCase = getInt(s, apc + 4 * 1, 4);
+ int highCase = getInt(s, apc + 4 * 2, 4);
+ int caseCount = highCase - lowCase + 1;
+ for (int n = 0; n < caseCount; n++) {
+ Element c = new Element("Case", 4);
+ int caseVal = lowCase + n;
+ int caseLab = getInt(s, apc + 4 * (3 + n), 4) + pc;
+ c.setAttr("num", "" + caseVal);
+ c.setAttr("lab", "" + caseLab);
+ assert (c.getExtraCapacity() == 0);
+ i.add(c);
+ }
+ return apc + 4 * (3 + caseCount);
+ } else {
+ int caseCount = getInt(s, apc + 4 * 1, 4);
+ for (int n = 0; n < caseCount; n++) {
+ Element c = new Element("Case", 4);
+ int caseVal = getInt(s, apc + 4 * (2 + (2 * n) + 0), 4);
+ int caseLab = getInt(s, apc + 4 * (2 + (2 * n) + 1), 4) + pc;
+ c.setAttr("num", "" + caseVal);
+ c.setAttr("lab", "" + caseLab);
+ assert (c.getExtraCapacity() == 0);
+ i.add(c);
+ }
+ return apc + 4 * (2 + 2 * caseCount);
+ }
+ }
+
+ static int getInt(String s, int pc, int len) {
+ //System.out.println("getInt s["+s.length()+"] pc="+pc+" len="+len);
+ int result = s.charAt(pc);
+ if (len < 0) {
+ len = -len;
+ result = (byte) result;
+ }
+ if (!(len == 1 || len == 2 || len == 4)) {
+ System.out.println("len=" + len);
+ }
+ assert (len == 1 || len == 2 || len == 4);
+ for (int i = 1; i < len; i++) {
+ result <<= 8;
+ result += s.charAt(pc + i) & 0xFF;
+ }
+ return result;
+ }
+
+ public static String assemble(Element instructions) {
+ return InstructionAssembler.assemble(instructions, null, null);
+ }
+
+ public static String assemble(Element instructions, String pcAttrName) {
+ return InstructionAssembler.assemble(instructions, pcAttrName, null);
+ }
+
+ public static String assemble(Element instructions, ClassSyntax.GetCPIndex getCPI) {
+ return InstructionAssembler.assemble(instructions, null, getCPI);
+ }
+
+ public static String assemble(Element instructions, String pcAttrName,
+ ClassSyntax.GetCPIndex getCPI) {
+ return InstructionAssembler.assemble(instructions, pcAttrName, getCPI);
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/tools/pack200/pack200-verifier/src/xmlkit/TokenList.java Wed Jul 05 17:21:22 2017 +0200
@@ -0,0 +1,449 @@
+/*
+ * Copyright (c) 2010, 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.
+ */
+package xmlkit; // -*- mode: java; indent-tabs-mode: nil -*-
+
+import java.util.*;
+
+/**
+ * A List of Strings each representing a word or token.
+ * This object itself is a CharSequence whose characters consist
+ * of all the tokens, separated by blanks.
+ *
+ * @author jrose
+ */
+public class TokenList extends ArrayList<String> implements CharSequence {
+
+ protected String separator;
+ protected boolean frozen;
+
+ public TokenList() {
+ this.separator = " ";
+ }
+
+ public TokenList(Collection<? extends Object> tokens) {
+ super(tokens.size());
+ this.separator = " ";
+ addTokens(tokens);
+ }
+
+ public TokenList(Collection<? extends Object> tokens, String separator) {
+ super(tokens.size());
+ this.separator = separator;
+ addTokens(tokens);
+ }
+
+ public TokenList(Object[] tokens) {
+ super(tokens.length);
+ this.separator = " ";
+ addTokens(tokens, 0, tokens.length);
+ }
+
+ public TokenList(Object[] tokens, int beg, int end) {
+ super(end - beg); // capacity
+ this.separator = " ";
+ addTokens(tokens, beg, end);
+ }
+
+ public TokenList(Object[] tokens, int beg, int end, String separator) {
+ super(end - beg); // capacity
+ this.separator = separator;
+ addTokens(tokens, beg, end);
+ }
+
+ public TokenList(String tokenStr) {
+ this(tokenStr, " ", false);
+ }
+
+ public TokenList(String tokenStr, String separator) {
+ this(tokenStr, separator, true);
+ }
+
+ public TokenList(String tokenStr, String separator, boolean allowNulls) {
+ super(tokenStr.length() / 5);
+ this.separator = separator;
+ addTokens(tokenStr, allowNulls);
+ }
+ static public final TokenList EMPTY;
+
+ static {
+ TokenList tl = new TokenList(new Object[0]);
+ tl.freeze();
+ EMPTY = tl;
+ }
+
+ public void freeze() {
+ if (!frozen) {
+ for (ListIterator<String> i = listIterator(); i.hasNext();) {
+ i.set(i.next().toString());
+ }
+ trimToSize();
+ frozen = true;
+ }
+ }
+
+ public boolean isFrozen() {
+ return frozen;
+ }
+
+ void checkNotFrozen() {
+ if (isFrozen()) {
+ throw new UnsupportedOperationException("cannot modify frozen TokenList");
+ }
+ }
+
+ public String getSeparator() {
+ return separator;
+ }
+
+ public void setSeparator(String separator) {
+ checkNotFrozen();
+ this.separator = separator;
+ }
+
+ /// All normal List mutators must check the frozen bit:
+ public String set(int index, String o) {
+ checkNotFrozen();
+ return super.set(index, o);
+ }
+
+ public boolean add(String o) {
+ checkNotFrozen();
+ return super.add(o);
+ }
+
+ public void add(int index, String o) {
+ checkNotFrozen();
+ super.add(index, o);
+ }
+
+ public boolean addAll(Collection<? extends String> c) {
+ checkNotFrozen();
+ return super.addAll(c);
+ }
+
+ public boolean addAll(int index, Collection<? extends String> c) {
+ checkNotFrozen();
+ return super.addAll(index, c);
+ }
+
+ public boolean remove(Object o) {
+ checkNotFrozen();
+ return super.remove(o);
+ }
+
+ public String remove(int index) {
+ checkNotFrozen();
+ return super.remove(index);
+ }
+
+ public void clear() {
+ checkNotFrozen();
+ super.clear();
+ }
+
+ /** Add a collection of tokens to the list, applying toString to each. */
+ public boolean addTokens(Collection<? extends Object> tokens) {
+ // Note that if this sequence is empty, no tokens are added.
+ // This is different from adding a null string, which is
+ // a single token.
+ boolean added = false;
+ for (Object token : tokens) {
+ add(token.toString());
+ added = true;
+ }
+ return added;
+ }
+
+ public boolean addTokens(Object[] tokens, int beg, int end) {
+ boolean added = false;
+ for (int i = beg; i < end; i++) {
+ add(tokens[i].toString());
+ added = true;
+ }
+ return added;
+ }
+
+ public boolean addTokens(String tokenStr) {
+ return addTokens(tokenStr, false);
+ }
+
+ public boolean addTokens(String tokenStr, boolean allowNulls) {
+ boolean added = false;
+ int pos = 0, limit = tokenStr.length(), sep = limit;
+ while (pos < limit) {
+ sep = tokenStr.indexOf(separator, pos);
+ if (sep < 0) {
+ sep = limit;
+ }
+ if (sep == pos) {
+ if (allowNulls) {
+ add("");
+ added = true;
+ }
+ pos += separator.length();
+ } else {
+ add(tokenStr.substring(pos, sep));
+ added = true;
+ pos = sep + separator.length();
+ }
+ }
+ if (allowNulls && sep < limit) {
+ // Input was something like "tok1 tok2 ".
+ add("");
+ added = true;
+ }
+ return added;
+ }
+
+ public boolean addToken(Object token) {
+ return add(token.toString());
+ }
+
+ /** Format the token string, using quotes and escapes.
+ * Quotes must contain an odd number of 3 or more elements,
+ * a sequence of begin/end quote pairs, plus a superquote.
+ * For each token, the first begin/end pair is used for
+ * which the end quote does not occur in the token.
+ * If the token contains all end quotes, the last pair
+ * is used, with all occurrences of the end quote replaced
+ * by the superquote. If an end quote is the empty string,
+ * the separator is used instead.
+ */
+ public String format(String separator, String[] quotes) {
+ return ""; //@@
+ }
+ protected int[] lengths;
+ protected static final int MODC = 0, HINT = 1, BEG0 = 2, END0 = 3;
+
+ // Layout of lengths:
+ // { modCount, hint, -1==beg[0], end[0]==beg[1], ..., length }
+ // Note that each beg[i]..end[i] span includes a leading separator,
+ // which is not part of the corresponding token.
+ protected final CharSequence getCS(int i) {
+ return (CharSequence) get(i);
+ }
+
+ // Produce (and cache) an table of indexes for each token.
+ protected int[] getLengths() {
+ int[] lengths = this.lengths;
+ ;
+ int sepLength = separator.length();
+ if (lengths == null || lengths[MODC] != modCount) {
+ int size = this.size();
+ lengths = new int[END0 + size + (size == 0 ? 1 : 0)];
+ lengths[MODC] = modCount;
+ int end = -sepLength; // cancels leading separator
+ lengths[BEG0] = end;
+ for (int i = 0; i < size; i++) {
+ end += sepLength; // count leading separator
+ end += getCS(i).length();
+ lengths[END0 + i] = end;
+ }
+ this.lengths = lengths;
+ }
+ return lengths;
+ }
+
+ public int length() {
+ int[] lengths = getLengths();
+ return lengths[lengths.length - 1];
+ }
+
+ // Which token does the given index belong to?
+ protected int which(int i) {
+ if (i < 0) {
+ return -1;
+ }
+ int[] lengths = getLengths();
+ for (int hint = lengths[HINT];; hint = 0) {
+ for (int wh = hint; wh < lengths.length - END0; wh++) {
+ int beg = lengths[BEG0 + wh];
+ int end = lengths[END0 + wh];
+ if (i >= beg && i < end) {
+ lengths[HINT] = wh;
+ return wh;
+ }
+ }
+ if (hint == 0) {
+ return size(); // end of the line
+ }
+ }
+ }
+
+ public char charAt(int i) {
+ if (i < 0) {
+ return "".charAt(i);
+ }
+ int wh = which(i);
+ int beg = lengths[BEG0 + wh];
+ int j = i - beg;
+ int sepLength = separator.length();
+ if (j < sepLength) {
+ return separator.charAt(j);
+ }
+ return getCS(wh).charAt(j - sepLength);
+ }
+
+ public CharSequence subSequence(int beg, int end) {
+ //System.out.println("i: "+beg+".."+end);
+ if (beg == end) {
+ return "";
+ }
+ if (beg < 0) {
+ charAt(beg); // raise exception
+ }
+ if (beg > end) {
+ charAt(-1); // raise exception
+ }
+ int begWh = which(beg);
+ int endWh = which(end);
+ if (endWh == size() || end == lengths[BEG0 + endWh]) {
+ --endWh;
+ }
+ //System.out.println("wh: "+begWh+".."+endWh);
+ int begBase = lengths[BEG0 + begWh];
+ int endBase = lengths[BEG0 + endWh];
+ int sepLength = separator.length();
+ int begFrag = 0;
+ if ((beg - begBase) < sepLength) {
+ begFrag = sepLength - (beg - begBase);
+ beg += begFrag;
+ }
+ int endFrag = 0;
+ if ((end - endBase) < sepLength) {
+ endFrag = (end - endBase);
+ end = endBase;
+ endBase = lengths[BEG0 + --endWh];
+ }
+ if (false) {
+ System.out.print("beg[wbf]end[wbf]");
+ int pr[] = {begWh, begBase, begFrag, beg, endWh, endBase, endFrag, end};
+ for (int k = 0; k < pr.length; k++) {
+ System.out.print((k == 4 ? " " : " ") + (pr[k]));
+ }
+ System.out.println();
+ }
+ if (begFrag > 0 && (end + endFrag) - begBase <= sepLength) {
+ // Special case: Slice the separator.
+ beg -= begFrag;
+ end += endFrag;
+ return separator.substring(beg - begBase, end - begBase);
+ }
+ if (begWh == endWh && (begFrag + endFrag) == 0) {
+ // Special case: Slice a single token.
+ return getCS(begWh).subSequence(beg - begBase - sepLength,
+ end - endBase - sepLength);
+ }
+ Object[] subTokens = new Object[1 + (endWh - begWh) + 1];
+ int fillp = 0;
+ if (begFrag == sepLength) {
+ // Insert a leading null token to force an initial separator.
+ subTokens[fillp++] = "";
+ begFrag = 0;
+ }
+ for (int wh = begWh; wh <= endWh; wh++) {
+ CharSequence cs = getCS(wh);
+ if (wh == begWh || wh == endWh) {
+ // Slice it.
+ int csBeg = (wh == begWh) ? (beg - begBase) - sepLength : 0;
+ int csEnd = (wh == endWh) ? (end - endBase) - sepLength : cs.length();
+ cs = cs.subSequence(csBeg, csEnd);
+ if (begFrag > 0 && wh == begWh) {
+ cs = separator.substring(sepLength - begFrag) + cs;
+ }
+ if (endFrag > 0 && wh == endWh) {
+ cs = cs.toString() + separator.substring(0, endFrag);
+ }
+ }
+ subTokens[fillp++] = cs;
+ }
+ return new TokenList(subTokens, 0, fillp, separator);
+ }
+
+ /** Returns the concatenation of all tokens,
+ * with intervening separator characters.
+ */
+ public String toString() {
+ StringBuilder buf = new StringBuilder(length());
+ int size = this.size();
+ for (int i = 0; i < size; i++) {
+ if (i > 0) {
+ buf.append(separator);
+ }
+ buf.append(get(i));
+ }
+ return buf.toString();
+ }
+
+ /*---- TESTING CODE ----
+ public static void main(String[] av) {
+ if (av.length == 0) av = new String[]{"one", "2", "", "four"};
+ TokenList ts = new TokenList();
+ final String SEP = ", ";
+ ts.setSeparator(SEP);
+ for (int i = -1; i < av.length; i++) {
+ if (i >= 0) ts.addToken(av[i]);
+ {
+ TokenList tsCopy = new TokenList(ts.toString(), SEP);
+ if (!tsCopy.equals(ts)) {
+ tsCopy.setSeparator(")(");
+ System.out.println("!= ("+tsCopy+")");
+ }
+ }
+ {
+ TokenList tsBar = new TokenList(ts, "|");
+ tsBar.add(0, "[");
+ tsBar.add("]");
+ System.out.println(tsBar);
+ }
+ if (false) {
+ int[] ls = ts.getLengths();
+ System.out.println("ts: "+ts);
+ System.out.print("ls: {");
+ for (int j = 0; j < ls.length; j++) System.out.print(" "+ls[j]);
+ System.out.println(" }");
+ }
+ assert0(ts.size() == i+1);
+ assert0(i < 0 || ts.get(i) == av[i]);
+ String tss = ts.toString();
+ int tslen = tss.length();
+ assert0(ts.length() == tss.length());
+ for (int n = 0; n < tslen; n++) {
+ assert0(ts.charAt(n) == tss.charAt(n));
+ }
+ for (int j = 0; j < tslen; j++) {
+ for (int k = tslen; k >= j; k--) {
+ CharSequence sub = ts.subSequence(j, k);
+ //System.out.println("|"+sub+"|");
+ assert0(sub.toString().equals(tss.substring(j, k)));
+ }
+ }
+ }
+ }
+ static void assert0(boolean z) {
+ if (!z) throw new RuntimeException("assert failed");
+ }
+ // ---- TESTING CODE ----*/
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/tools/pack200/pack200-verifier/src/xmlkit/XMLKit.java Wed Jul 05 17:21:22 2017 +0200
@@ -0,0 +1,4330 @@
+/*
+ * Copyright (c) 2010, 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.
+ */
+package xmlkit; // -*- mode: java; indent-tabs-mode: nil -*-
+
+// XML Implementation packages:
+import java.util.*;
+
+import java.io.Reader;
+import java.io.Writer;
+import java.io.OutputStream;
+import java.io.InputStreamReader;
+import java.io.OutputStreamWriter;
+import java.io.BufferedReader;
+import java.io.PrintWriter;
+import java.io.StringWriter;
+import java.io.StringReader;
+
+import java.io.IOException;
+
+import org.xml.sax.XMLReader;
+import org.xml.sax.InputSource;
+import org.xml.sax.ContentHandler;
+import org.xml.sax.SAXException;
+import org.xml.sax.SAXParseException;
+import org.xml.sax.Attributes;
+import org.xml.sax.ext.LexicalHandler;
+import org.xml.sax.helpers.AttributesImpl;
+
+/**
+ * A kit of methods and classes useful for manipulating XML trees in
+ * memory. They are very compact and easy to use. An XML element
+ * occupies six pointers of overhead (like two arrays) plus a pointer
+ * for its name, each attribute name and value, and each sub-element.
+ * Many useful XML operations (or Lisp-like calls) can be accomplished
+ * with a single method call on an element itself.
+ * <p>
+ * There is strong integration with the Java collection classes.
+ * There are viewing and conversion operators to and from various
+ * collection types. Elements directly support list iterators.
+ * Most <tt>List</tt> methods work analogously on elements.
+ * <p>
+ * Because of implementation compromises, these XML trees are less
+ * functional than many standard XML classes.
+ * <ul>
+ * <li>There are no parent or sibling pointers in the tree.</li>
+ * <li>Attribute names are simple strings, with no namespaces.</li>
+ * <li>There is no internal support for schemas or validation.</li>
+ * </ul>
+ * <p>
+ * Here is a summary of functionality in <tt>XMLKit</tt>.
+ * (Overloaded groups of methods are summarized by marking some
+ * arguments optional with their default values. Some overloaded
+ * arguments are marked with their alternative types separated by
+ * a bar "|". Arguments or return values for which a null is
+ * specially significant are marked by an alternative "|null".
+ * Accessors which have corresponding setters are marked
+ * by "/set". Removers which have corresponding retainers are marked
+ * by "/retain".)
+ * <pre>
+ * --- element construction
+ * new Element(int elemCapacity=4), String name=""
+ * new Element(String name, String[] attrs={}, Element[] elems={}, int elemCapacity=4)
+ * new Element(String name, String[] attrs, Object[] elems, int elemCapacity=4)
+ * new Element(Element original) // shallow copy
+ * new Element(String name="", Collection elems) // coercion
+ *
+ * Element shallowCopy()
+ * Element shallowFreeze() // side-effecting
+ * Element deepCopy()
+ * Element deepFreeze() // not side-effecting
+ *
+ * EMPTY // frozen empty anonymous element
+ * void ensureExtraCapacity(int)
+ * void trimToSize()
+ * void sortAttrs() // sort by key
+ *
+ * --- field accessors
+ * String getName()/set
+ * int size()
+ * boolean isEmpty()
+ * boolean isFrozen()
+ * boolean isAnonymous()
+ * int getExtraCapacity()/set
+ * int attrSize()
+ *
+ * --- attribute accessors
+ * String getAttr(int i)/set
+ * String getAttrName(int i)
+ *
+ * String getAttr(String key)/set
+ * List getAttrList(String key)/set
+ * Number getAttrNumber(String key)/set
+ * long getAttrLong(String key)/set
+ * double getAttrDouble(String key)/set
+ *
+ * String getAttr(String key, String dflt=null)
+ * long getAttrLong(String key, long dflt=0)
+ * double getAttrDouble(String key, double dflt=0)
+ *
+ * Element copyAttrsOnly()
+ * Element getAttrs()/set => <em><><key>value</key>...</></em>
+ * void addAttrs(Element attrs)
+ *
+ * void removeAttr(int i)
+ * void clearAttrs()
+ *
+ * --- element accessors
+ * Object get(int i)/set
+ * Object getLast() | null
+ * Object[] toArray()
+ * Element copyContentOnly()
+ *
+ * void add(int i=0, Object subElem)
+ * int addAll(int i=0, Collection | Element elems)
+ * int addContent(int i=0, TokenList|Element|Object|null)
+ * void XMLKit.addContent(TokenList|Element|Object|null, Collection sink|null)
+ *
+ * void clear(int beg=0, int end=size)
+ * void sort(Comparator=contentOrder())
+ * void reverse()
+ * void shuffle(Random rnd=(anonymous))
+ * void rotate(int distance)
+ * Object min/max(Comparator=contentOrder())
+ *
+ * --- text accessors
+ * CharSequence getText()/set
+ * CharSequence getUnmarkedText()
+ * int addText(int i=size, CharSequence)
+ * void trimText();
+ *
+ * --- views
+ * List asList() // element view
+ * ListIterator iterator()
+ * PrintWriter asWriter()
+ * Map asAttrMap()
+ * Iterable<CharSequence> texts()
+ * Iterable<Element> elements()
+ * Iterable<T> partsOnly(Class<T>)
+ * String[] toStrings()
+ *
+ * --- queries
+ * boolean equals(Element | Object)
+ * int compareTo(Element | Object)
+ * boolean equalAttrs(Element)
+ * int hashCode()
+ * boolean isText() // every sub-elem is CharSequence
+ * boolean hasText() // some sub-elem is CharSequence
+ *
+ * boolean contains(Object)
+ * boolean containsAttr(String)
+ *
+ * int indexOf(Object)
+ * int indexOf(Filter, int fromIndex=0)
+ * int lastIndexOf(Object)
+ * int lastIndexOf(Filter, int fromIndex=size-1)
+ *
+ * int indexOfAttr(String)
+ *
+ * // finders, removers, and replacers do addContent of each filtered value
+ * // (i.e., TokenLists and anonymous Elements are broken out into their parts)
+ * boolean matches(Filter)
+ *
+ * Object find(Filter, int fromIndex=0)
+ * Object findLast(Filter, int fromIndex=size-1)
+ * Element findAll(Filter, int fromIndex=0 & int toIndex=size)
+ * int findAll(Filter, Collection sink | null, int fromIndex=0 & int toIndex=size)
+ *
+ * Element removeAllInTree(Filter)/retain
+ * int findAllInTree(Filter, Collection sink | null)
+ * int countAllInTree(Filter)
+ * Element removeAllInTree(Filter)/retain
+ * int removeAllInTree(Filter, Collection sink | null)/retain
+ * void replaceAllInTree(Filter)
+ *
+ * Element findElement(String name=any)
+ * Element findAllElements(String name=any)
+ *
+ * Element findWithAttr(String key, String value=any)
+ * Element findAllWithAttr(String key, String value=any)
+ *
+ * Element removeElement(String name=any)
+ * Element removeAllElements(String name=any)/retain
+ *
+ * Element removeWithAttr(String key, String value=any)
+ * Element removeAllWithAttr(String key, String value=any)/retain
+ *
+ * //countAll is the same as findAll but with null sink
+ * int countAll(Filter)
+ * int countAllElements(String name=any)
+ * int countAllWithAttr(String key, String value=any)
+ *
+ * void replaceAll(Filter, int fromIndex=0 & int toIndex=size)
+ * void replaceAllInTree(Filter)
+ * void XMLKit.replaceAll(Filter, List target) //if(fx){remove x;addContent fx}
+ *
+ * --- element mutators
+ * boolean remove(Object)
+ * Object remove(int)
+ * Object removeLast() | null
+ *
+ * Object remove(Filter, int fromIndex=0)
+ * Object removeLast(Filter, int fromIndex=size-1)
+ * Element sink = removeAll(Filter, int fromIndex=0 & int toIndex=size)/retain
+ * int count = removeAll(Filter, int fromIndex=0 & int toIndex=size, Collection sink | null)/retain
+ *
+ * Element removeAllElements(String name=any)
+ *
+ * --- attribute mutators
+ * ??int addAllAttrsFrom(Element attrSource)
+ *
+ * --- parsing and printing
+ * void tokenize(String delims=whitespace, returnDelims=false)
+ * void writeTo(Writer)
+ * void writePrettyTo(Writer)
+ * String prettyString()
+ * String toString()
+ *
+ * ContentHandler XMLKit.makeBuilder(Collection sink, tokenizing=false, makeFrozen=false) // for standard XML parser
+ * Element XMLKit.readFrom(Reader, tokenizing=false, makeFrozen=false)
+ * void XMLKit.prettyPrintTo(Writer | OutputStream, Element)
+ * class XMLKit.Printer(Writer) { void print/Recursive(Element) }
+ * void XMLKit.output(Object elem, ContentHandler, LexicalHandler=null)
+ * void XMLKit.writeToken(String, char quote, Writer)
+ * void XMLKit.writeCData(String, Writer)
+ * Number XMLKit.convertToNumber(String, Number dflt=null)
+ * long XMLKit.convertToLong(String, long dflt=0)
+ * double XMLKit.convertToDouble(String, double dflt=0)
+ *
+ * --- filters
+ * XMLKit.ElementFilter { Element filter(Element) }
+ * XMLKit.elementFilter(String name=any | Collection nameSet)
+ * XMLKit.AttrFilter(String key) { boolean test(String value) }
+ * XMLKit.attrFilter(String key, String value=any)
+ * XMLKit.attrFilter(Element matchThis, String key)
+ * XMLKit.classFilter(Class)
+ * XMLKit.textFilter() // matches any CharSequence
+ * XMLKit.specialFilter() // matches any Special element
+ * XMLKit.methodFilter(Method m, Object[] args=null, falseResult=null)
+ * XMLKit.testMethodFilter(Method m, Object[] args=null)
+ * XMLKit.not(Filter) // inverts sense of Filter
+ * XMLKit.and(Filter&Filter | Filter[])
+ * XMLKit.or(Filter&Filter | Filter[])
+ * XMLKit.stack(Filter&Filter | Filter[]) // result is (fx && g(fx))
+ * XMLKit.content(Filter, Collection sink) // copies content to sink
+ * XMLKit.replaceInTree(Filter pre, Filter post=null) // pre-replace else recur
+ * XMLKit.findInTree(Filter pre, Collection sink=null) // pre-find else recur
+ * XMLKit.nullFilter() // ignores input, always returns null (i.e., false)
+ * XMLKit.selfFilter( ) // always returns input (i.e., true)
+ * XMLKit.emptyFilter() // ignores input, always returns EMPTY
+ * XMLKit.constantFilter(Object) // ignores input, always returns constant
+ *
+ * --- misc
+ * Comparator XMLKit.contentOrder() // for comparing/sorting mixed content
+ * Method XMLKit.Element.method(String name) // returns Element method
+ * </pre>
+ *
+ * @author jrose
+ */
+public abstract class XMLKit {
+
+ private XMLKit() {
+ }
+ // We need at least this much slop if the element is to stay unfrozen.
+ static final int NEED_SLOP = 1;
+ static final Object[] noPartsFrozen = {};
+ static final Object[] noPartsNotFrozen = new Object[NEED_SLOP];
+ static final String WHITESPACE_CHARS = " \t\n\r\f";
+ static final String ANON_NAME = new String("*"); // unique copy of "*"
+
+ public static final class Element implements Comparable<Element>, Iterable<Object> {
+ // Note: Does not implement List, because it has more
+ // significant parts besides its sub-elements. Therefore,
+ // hashCode and equals must be more distinctive than Lists.
+
+ // <name> of element
+ String name;
+ // number of child elements, in parts[0..size-1]
+ int size;
+ // The parts start with child elements:: {e0, e1, e2, ...}.
+ // Following that are optional filler elements, all null.
+ // Following that are attributes as key/value pairs.
+ // They are in reverse: {...key2, val2, key1, val1, key0, val0}.
+ // Child elements and attr keys and values are never null.
+ Object[] parts;
+
+ // Build a partially-constructed node.
+ // Caller is responsible for initializing promised attributes.
+ Element(String name, int size, int capacity) {
+ this.name = name.toString();
+ this.size = size;
+ assert (size <= capacity);
+ this.parts = capacity > 0 ? new Object[capacity] : noPartsFrozen;
+ }
+
+ /** An anonymous, empty element.
+ * Optional elemCapacity argument is expected number of sub-elements.
+ */
+ public Element() {
+ this(ANON_NAME, 0, NEED_SLOP + 4);
+ }
+
+ public Element(int extraCapacity) {
+ this(ANON_NAME, 0, NEED_SLOP + Math.max(0, extraCapacity));
+ }
+
+ /** An empty element with the given name.
+ * Optional extraCapacity argument is expected number of sub-elements.
+ */
+ public Element(String name) {
+ this(name, 0, NEED_SLOP + 4);
+ }
+
+ public Element(String name, int extraCapacity) {
+ this(name, 0, NEED_SLOP + Math.max(0, extraCapacity));
+ }
+
+ /** An empty element with the given name and attributes.
+ * Optional extraCapacity argument is expected number of sub-elements.
+ */
+ public Element(String name, String... attrs) {
+ this(name, attrs, (Element[]) null, 0);
+ }
+
+ public Element(String name, String[] attrs, int extraCapacity) {
+ this(name, attrs, (Element[]) null, extraCapacity);
+ }
+
+ /** An empty element with the given name and sub-elements.
+ * Optional extraCapacity argument is expected extra sub-elements.
+ */
+ public Element(String name, Element... elems) {
+ this(name, (String[]) null, elems, 0);
+ }
+
+ public Element(String name, Element[] elems, int extraCapacity) {
+ this(name, (String[]) null, elems, extraCapacity);
+ }
+
+ /** An empty element with the given name, attributes, and sub-elements.
+ * Optional extraCapacity argument is expected extra sub-elements.
+ */
+ public Element(String name, String[] attrs, Object... elems) {
+ this(name, attrs, elems, 0);
+ }
+
+ public Element(String name, String[] attrs, Object[] elems, int extraCapacity) {
+ this(name, 0,
+ ((elems == null) ? 0 : elems.length)
+ + Math.max(0, extraCapacity)
+ + NEED_SLOP
+ + ((attrs == null) ? 0 : attrs.length));
+ int ne = ((elems == null) ? 0 : elems.length);
+ int na = ((attrs == null) ? 0 : attrs.length);
+ int fillp = 0;
+ for (int i = 0; i < ne; i++) {
+ if (elems[i] != null) {
+ parts[fillp++] = elems[i];
+ }
+ }
+ size = fillp;
+ for (int i = 0; i < na; i += 2) {
+ setAttr(attrs[i + 0], attrs[i + 1]);
+ }
+ }
+
+ public Element(Collection c) {
+ this(c.size());
+ addAll(c);
+ }
+
+ public Element(String name, Collection c) {
+ this(name, c.size());
+ addAll(c);
+ }
+
+ /** Shallow copy. Same as old.shallowCopy().
+ * Optional extraCapacity argument is expected extra sub-elements.
+ */
+ public Element(Element old) {
+ this(old, 0);
+ }
+
+ public Element(Element old, int extraCapacity) {
+ this(old.name, old.size,
+ old.size
+ + Math.max(0, extraCapacity) + NEED_SLOP
+ + old.attrLength());
+ // copy sub-elements
+ System.arraycopy(old.parts, 0, parts, 0, size);
+ int alen = parts.length
+ - (size + Math.max(0, extraCapacity) + NEED_SLOP);
+ // copy attributes
+ System.arraycopy(old.parts, old.parts.length - alen,
+ parts, parts.length - alen,
+ alen);
+ assert (!isFrozen());
+ }
+
+ /** Shallow copy. Same as new Element(this). */
+ public Element shallowCopy() {
+ return new Element(this);
+ }
+ static public final Element EMPTY = new Element(ANON_NAME, 0, 0);
+
+ Element deepFreezeOrCopy(boolean makeFrozen) {
+ if (makeFrozen && isFrozen()) {
+ return this; // no need to copy it
+ }
+ int alen = attrLength();
+ int plen = size + (makeFrozen ? 0 : NEED_SLOP) + alen;
+ Element copy = new Element(name, size, plen);
+ // copy attributes
+ System.arraycopy(parts, parts.length - alen, copy.parts, plen - alen, alen);
+ // copy sub-elements
+ for (int i = 0; i < size; i++) {
+ Object e = parts[i];
+ String str;
+ if (e instanceof Element) { // recursion is common case
+ e = ((Element) e).deepFreezeOrCopy(makeFrozen);
+ } else if (makeFrozen) {
+ // Freeze StringBuffers, etc.
+ e = fixupString(e);
+ }
+ copy.setRaw(i, e);
+ }
+ return copy;
+ }
+
+ /** Returns new Element(this), and also recursively copies sub-elements. */
+ public Element deepCopy() {
+ return deepFreezeOrCopy(false);
+ }
+
+ /** Returns frozen version of deepCopy. */
+ public Element deepFreeze() {
+ return deepFreezeOrCopy(true);
+ }
+
+ /** Freeze this element.
+ * Throw an IllegalArgumentException if any sub-element is not already frozen.
+ * (Use deepFreeze() to make a frozen copy of an entire element tree.)
+ */
+ public void shallowFreeze() {
+ if (isFrozen()) {
+ return;
+ }
+ int alen = attrLength();
+ Object[] nparts = new Object[size + alen];
+ // copy attributes
+ System.arraycopy(parts, parts.length - alen, nparts, size, alen);
+ // copy sub-elements
+ for (int i = 0; i < size; i++) {
+ Object e = parts[i];
+ String str;
+ if (e instanceof Element) { // recursion is common case
+ if (!((Element) e).isFrozen()) {
+ throw new IllegalArgumentException("Sub-element must be frozen.");
+ }
+ } else {
+ // Freeze StringBuffers, etc.
+ e = fixupString(e);
+ }
+ nparts[i] = e;
+ }
+ parts = nparts;
+ assert (isFrozen());
+ }
+
+ /** Return the name of this element. */
+ public String getName() {
+ return name;
+ }
+
+ /** Change the name of this element. */
+ public void setName(String name) {
+ checkNotFrozen();
+ this.name = name.toString();
+ }
+
+ /** Reports if the element's name is a particular string (spelled "*").
+ * Such elements are created by the nullary Element constructor,
+ * and by query functions which return multiple values,
+ * such as <tt>findAll</tt>.
+ */
+ public boolean isAnonymous() {
+ return name == ANON_NAME;
+ }
+
+ /** Return number of elements. (Does not include attributes.) */
+ public int size() {
+ return size;
+ }
+
+ /** True if no elements. (Does not consider attributes.) */
+ public boolean isEmpty() {
+ return size == 0;
+ }
+
+ /** True if this element does not allow modification. */
+ public boolean isFrozen() {
+ // It is frozen iff there is no slop space.
+ return !hasNulls(NEED_SLOP);
+ }
+
+ void checkNotFrozen() {
+ if (isFrozen()) {
+ throw new UnsupportedOperationException("cannot modify frozen element");
+ }
+ }
+
+ /** Remove specified elements. (Does not affect attributes.) */
+ public void clear() {
+ clear(0, size);
+ }
+
+ public void clear(int beg) {
+ clear(beg, size);
+ }
+
+ public void clear(int beg, int end) {
+ if (end > size) {
+ badIndex(end);
+ }
+ if (beg < 0 || beg > end) {
+ badIndex(beg);
+ }
+ if (beg == end) {
+ return;
+ }
+ checkNotFrozen();
+ if (end == size) {
+ if (beg == 0
+ && parts.length > 0 && parts[parts.length - 1] == null) {
+ // If no attributes, free the parts array.
+ parts = noPartsNotFrozen;
+ size = 0;
+ } else {
+ clearParts(beg, size);
+ size = beg;
+ }
+ } else {
+ close(beg, end - beg);
+ }
+ }
+
+ void clearParts(int beg, int end) {
+ for (int i = beg; i < end; i++) {
+ parts[i] = null;
+ }
+ }
+
+ /** True if name, attributes, and elements are the same. */
+ public boolean equals(Element that) {
+ if (!this.name.equals(that.name)) {
+ return false;
+ }
+ if (this.size != that.size) {
+ return false;
+ }
+ // elements must be equal and ordered
+ Object[] thisParts = this.parts;
+ Object[] thatParts = that.parts;
+ for (int i = 0; i < size; i++) {
+ Object thisPart = thisParts[i];
+ Object thatPart = thatParts[i];
+
+ if (thisPart instanceof Element) { // recursion is common case
+ if (!thisPart.equals(thatPart)) {
+ return false;
+ }
+ } else {
+ // If either is a non-string char sequence, normalize it.
+ thisPart = fixupString(thisPart);
+ thatPart = fixupString(thatPart);
+ if (!thisPart.equals(thatPart)) {
+ return false;
+ }
+ }
+ }
+ // finally, attributes must be equal (unordered)
+ return this.equalAttrs(that);
+ }
+ // bridge method
+
+ public boolean equals(Object o) {
+ if (!(o instanceof Element)) {
+ return false;
+ }
+ return equals((Element) o);
+ }
+
+ public int hashCode() {
+ int hc = 0;
+ int alen = attrLength();
+ for (int i = parts.length - alen; i < parts.length; i += 2) {
+ hc += (parts[i + 0].hashCode() ^ parts[i + 1].hashCode());
+ }
+ hc ^= hc << 11;
+ hc += name.hashCode();
+ for (int i = 0; i < size; i++) {
+ hc ^= hc << 7;
+ Object p = parts[i];
+ if (p instanceof Element) {
+ hc += p.hashCode(); // recursion is common case
+ } else {
+ hc += fixupString(p).hashCode();
+ }
+ }
+ hc ^= hc >>> 19;
+ return hc;
+ }
+
+ /** Compare lexicographically. Earlier-spelled attrs are more sigificant. */
+ public int compareTo(Element that) {
+ int r;
+ // Primary key is element name.
+ r = this.name.compareTo(that.name);
+ if (r != 0) {
+ return r;
+ }
+
+ // Secondary key is attributes, as if in normal key order.
+ // The key/value pairs are sorted as a token sequence.
+ int thisAlen = this.attrLength();
+ int thatAlen = that.attrLength();
+ if (thisAlen != 0 || thatAlen != 0) {
+ r = compareAttrs(thisAlen, that, thatAlen, true);
+ assert (assertAttrCompareOK(r, that));
+ if (r != 0) {
+ return r;
+ }
+ }
+
+ // Finally, elements should be equal and ordered,
+ // and the first difference rules.
+ Object[] thisParts = this.parts;
+ Object[] thatParts = that.parts;
+ int minSize = this.size;
+ if (minSize > that.size) {
+ minSize = that.size;
+ }
+ Comparator<Object> cc = contentOrder();
+ for (int i = 0; i < minSize; i++) {
+ r = cc.compare(thisParts[i], thatParts[i]);
+ if (r != 0) {
+ return r;
+ }
+ }
+ //if (this.size < that.size) return -1;
+ return this.size - that.size;
+ }
+
+ private boolean assertAttrCompareOK(int r, Element that) {
+ Element e0 = this.copyAttrsOnly();
+ Element e1 = that.copyAttrsOnly();
+ e0.sortAttrs();
+ e1.sortAttrs();
+ int r2;
+ for (int k = 0;; k++) {
+ boolean con0 = e0.containsAttr(k);
+ boolean con1 = e1.containsAttr(k);
+ if (con0 != con1) {
+ if (!con0) {
+ r2 = 0 - 1;
+ break;
+ }
+ if (!con1) {
+ r2 = 1 - 0;
+ break;
+ }
+ }
+ if (!con0) {
+ r2 = 0;
+ break;
+ }
+ String k0 = e0.getAttrName(k);
+ String k1 = e1.getAttrName(k);
+ r2 = k0.compareTo(k1);
+ if (r2 != 0) {
+ break;
+ }
+ String v0 = e0.getAttr(k);
+ String v1 = e1.getAttr(k);
+ r2 = v0.compareTo(v1);
+ if (r2 != 0) {
+ break;
+ }
+ }
+ if (r != 0) {
+ r = (r > 0) ? 1 : -1;
+ }
+ if (r2 != 0) {
+ r2 = (r2 > 0) ? 1 : -1;
+ }
+ if (r != r2) {
+ System.out.println("*** wrong attr compare, " + r + " != " + r2);
+ System.out.println(" this = " + this);
+ System.out.println(" attr->" + e0);
+ System.out.println(" that = " + that);
+ System.out.println(" attr->" + e1);
+ }
+ return r == r2;
+ }
+
+ private void badIndex(int i) {
+ Object badRef = (new Object[0])[i];
+ }
+
+ public Object get(int i) {
+ if (i >= size) {
+ badIndex(i);
+ }
+ return parts[i];
+ }
+
+ public Object set(int i, Object e) {
+ if (i >= size) {
+ badIndex(i);
+ }
+ e.getClass(); // null check
+ checkNotFrozen();
+ Object old = parts[i];
+ setRaw(i, e);
+ return old;
+ }
+
+ void setRaw(int i, Object e) {
+ parts[i] = e;
+ }
+
+ public boolean remove(Object e) {
+ int i = indexOf(e);
+ if (i < 0) {
+ return false;
+ }
+ close(i, 1);
+ return true;
+ }
+
+ public Object remove(int i) {
+ if (i >= size) {
+ badIndex(i);
+ }
+ Object e = parts[i];
+ close(i, 1);
+ return e;
+ }
+
+ public Object removeLast() {
+ if (size == 0) {
+ return null;
+ }
+ return remove(size - 1);
+ }
+
+ /** Remove the first element matching the given filter.
+ * Return the filtered value.
+ */
+ public Object remove(Filter f) {
+ return findOrRemove(f, 0, true);
+ }
+
+ public Object remove(Filter f, int fromIndex) {
+ if (fromIndex < 0) {
+ fromIndex = 0;
+ }
+ return findOrRemove(f, fromIndex, true);
+ }
+
+ /** Remove the last element matching the given filter.
+ * Return the filtered value.
+ */
+ public Object removeLast(Filter f) {
+ return findOrRemoveLast(f, size - 1, true);
+ }
+
+ public Object removeLast(Filter f, int fromIndex) {
+ if (fromIndex >= size) {
+ fromIndex = size - 1;
+ }
+ return findOrRemoveLast(f, fromIndex, true);
+ }
+
+ /** Remove all elements matching the given filter.
+ * If there is a non-null collection given as a sink,
+ * transfer removed elements to the given collection.
+ * The int result is the number of removed elements.
+ * If there is a null sink given, the removed elements
+ * are discarded. If there is no sink given, the removed
+ * elements are returned in an anonymous container element.
+ */
+ public Element removeAll(Filter f) {
+ Element result = new Element();
+ findOrRemoveAll(f, false, 0, size, result.asList(), true);
+ return result;
+ }
+
+ public Element removeAll(Filter f, int fromIndex, int toIndex) {
+ Element result = new Element();
+ findOrRemoveAll(f, true, fromIndex, toIndex, result.asList(), true);
+ return result;
+ }
+
+ public int removeAll(Filter f, Collection<Object> sink) {
+ return findOrRemoveAll(f, false, 0, size, sink, true);
+ }
+
+ public int removeAll(Filter f, int fromIndex, int toIndex, Collection<Object> sink) {
+ return findOrRemoveAll(f, false, fromIndex, toIndex, sink, true);
+ }
+
+ /** Remove all elements not matching the given filter.
+ * If there is a non-null collection given as a sink,
+ * transfer removed elements to the given collection.
+ * The int result is the number of removed elements.
+ * If there is a null sink given, the removed elements
+ * are discarded. If there is no sink given, the removed
+ * elements are returned in an anonymous container element.
+ */
+ public Element retainAll(Filter f) {
+ Element result = new Element();
+ findOrRemoveAll(f, true, 0, size, result.asList(), true);
+ return result;
+ }
+
+ public Element retainAll(Filter f, int fromIndex, int toIndex) {
+ Element result = new Element();
+ findOrRemoveAll(f, true, fromIndex, toIndex, result.asList(), true);
+ return result;
+ }
+
+ public int retainAll(Filter f, Collection<Object> sink) {
+ return findOrRemoveAll(f, true, 0, size, sink, true);
+ }
+
+ public int retainAll(Filter f, int fromIndex, int toIndex, Collection<Object> sink) {
+ return findOrRemoveAll(f, true, fromIndex, toIndex, sink, true);
+ }
+
+ public void add(int i, Object e) {
+ // (The shape of this method is tweaked for common cases.)
+ e.getClass(); // force a null check on e
+ if (hasNulls(1 + NEED_SLOP)) {
+ // Common case: Have some slop space.
+ if (i == size) {
+ // Most common case: Append.
+ setRaw(i, e);
+ size++;
+ return;
+ }
+ if (i > size) {
+ badIndex(i);
+ }
+ // Second most common case: Shift right by one.
+ open(i, 1);
+ setRaw(i, e);
+ return;
+ }
+ // Ran out of space. Do something complicated.
+ size = expand(i, 1);
+ setRaw(i, e);
+ }
+
+ public boolean add(Object e) {
+ add(size, e);
+ return true;
+ }
+
+ public Object getLast() {
+ return size == 0 ? null : parts[size - 1];
+ }
+
+ /** Returns the text of this Element.
+ * All sub-elements of this Element must be of type CharSequence.
+ * A ClassCastException is raised if there are non-character sub-elements.
+ * If there is one sub-element, return it.
+ * Otherwise, returns a TokenList of all sub-elements.
+ * This results in a space being placed between each adjacent pair of sub-elements.
+ */
+ public CharSequence getText() {
+ checkTextOnly();
+ if (size == 1) {
+ return parts[0].toString();
+ } else {
+ return new TokenList(parts, 0, size);
+ }
+ }
+
+ /** Provides an iterable view of this object as a series of texts.
+ * All sub-elements of this Element must be of type CharSequence.
+ * A ClassCastException is raised if there are non-character sub-elements.
+ */
+ public Iterable<CharSequence> texts() {
+ checkTextOnly();
+ return (Iterable<CharSequence>) (Iterable) this;
+ }
+
+ /** Returns an array of strings derived from the sub-elements of this object.
+ * All sub-elements of this Element must be of type CharSequence.
+ * A ClassCastException is raised if there are non-character sub-elements.
+ */
+ public String[] toStrings() {
+ //checkTextOnly();
+ String[] result = new String[size];
+ for (int i = 0; i < size; i++) {
+ result[i] = ((CharSequence) parts[i]).toString();
+ }
+ return result;
+ }
+
+ /** Like getText, except that it disregards non-text elements.
+ * Non-text elements are replaced by their textual contents, if any.
+ * Text elements which were separated only by non-text element
+ * boundaries are merged into single tokens.
+ * <p>
+ * There is no corresponding setter, since this accessor does
+ * not report the full state of the element.
+ */
+ public CharSequence getFlatText() {
+ if (size == 1) {
+ // Simple cases.
+ if (parts[0] instanceof CharSequence) {
+ return parts[0].toString();
+ } else {
+ return new TokenList();
+ }
+ }
+ if (isText()) {
+ return getText();
+ }
+ // Filter and merge.
+ Element result = new Element(size);
+ boolean merge = false;
+ for (int i = 0; i < size; i++) {
+ Object text = parts[i];
+ if (!(text instanceof CharSequence)) {
+ // Skip, but erase this boundary.
+ if (text instanceof Element) {
+ Element te = (Element) text;
+ if (!te.isEmpty()) {
+ result.addText(te.getFlatText());
+ }
+ }
+ merge = true;
+ continue;
+ }
+ if (merge) {
+ // Merge w/ previous token.
+ result.addText((CharSequence) text);
+ merge = false;
+ } else {
+ result.add(text);
+ }
+ }
+ if (result.size() == 1) {
+ return (CharSequence) result.parts[0];
+ } else {
+ return result.getText();
+ }
+ }
+
+ /** Return true if all sub-elements are of type CharSequence. */
+ public boolean isText() {
+ for (int i = 0; i < size; i++) {
+ if (!(parts[i] instanceof CharSequence)) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ /** Return true if at least one sub-element is of type CharSequence. */
+ public boolean hasText() {
+ for (int i = 0; i < size; i++) {
+ if (parts[i] instanceof CharSequence) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /** Raise a ClassCastException if !isText. */
+ public void checkTextOnly() {
+ for (int i = 0; i < size; i++) {
+ ((CharSequence) parts[i]).getClass();
+ }
+ }
+
+ /** Clears out all sub-elements, and replaces them by the given text.
+ * A ClassCastException is raised if there are non-character sub-elements,
+ * either before or after the change.
+ */
+ public void setText(CharSequence text) {
+ checkTextOnly();
+ clear();
+ if (text instanceof TokenList) {
+ // TL's contain only strings
+ addAll(0, (TokenList) text);
+ } else {
+ add(text);
+ }
+ }
+
+ /** Add text at the given position, merging with any previous
+ * text element, but preserving token boundaries where possible.
+ * <p>
+ * In all cases, the new value of getText() is the string
+ * concatenation of the old value of getText() plus the new text.
+ * <p>
+ * The total effect is to concatenate the given text to any
+ * pre-existing text, and to do so efficiently even if there
+ * are many such concatenations. Also, getText calls which
+ * return multiple tokens (in a TokenList) are respected.
+ * For example, if x is empty, x.addText(y.getText()) puts
+ * an exact structural copy of y's text into x.
+ * <p>
+ * Internal token boundaries in the original text, and in the new
+ * text (i.e., if it is a TokenList), are preserved. However,
+ * at the point where new text joins old text, a StringBuffer
+ * or new String may be created to join the last old and first
+ * new token.
+ * <p>
+ * If the given text is a TokenList, add the tokens as
+ * separate sub-elements, possibly merging the first token to
+ * a previous text item (to avoid making a new token boundary).
+ * <p>
+ * If the element preceding position i is a StringBuffer,
+ * append the first new token to it.
+ * <p>
+ * If the preceding element is a CharSequence, replace it by a
+ * StringBuffer containing both its and the first new token.
+ * <p>
+ * If tokens are added after a StringBuffer, freeze it into a String.
+ * <p>
+ * Every token not merged into a previous CharSequence is added
+ * as a new sub-element, starting at position i.
+ * <p>
+ * Returns the number of elements added, which is useful
+ * for further calls to addText. This number is zero
+ * if the input string was null, or was successfully
+ * merged into a StringBuffer at position i-1.
+ * <p>
+ * By contrast, calling add(text) always adds a new sub-element.
+ * In that case, if there is a previous string, a separating
+ * space is virtually present also, and will be observed if
+ * getText() is used to return all the text together.
+ */
+ public int addText(int i, CharSequence text) {
+ if (text instanceof String) {
+ return addText(i, (String) text);
+ } else if (text instanceof TokenList) {
+ // Text is a list of tokens.
+ TokenList tl = (TokenList) text;
+ int tlsize = tl.size();
+ if (tlsize == 0) {
+ return 0;
+ }
+ String token0 = tl.get(0).toString();
+ if (tlsize == 1) {
+ return addText(i, token0);
+ }
+ if (mergeWithPrev(i, token0, false)) {
+ // Add the n-1 remaining tokens.
+ addAll(i, tl.subList(1, tlsize));
+ return tlsize - 1;
+ } else {
+ addAll(i, (Collection) tl);
+ return tlsize;
+ }
+ } else {
+ return addText(i, text.toString());
+ }
+ }
+
+ public int addText(CharSequence text) {
+ return addText(size, text);
+ }
+
+ private // no reason to make this helper public
+ int addText(int i, String text) {
+ if (text.length() == 0) {
+ return 0; // Trivial success.
+ }
+ if (mergeWithPrev(i, text, true)) {
+ return 0; // Merged with previous token.
+ }
+ // No previous token.
+ add(i, text);
+ return 1;
+ }
+
+ // Tries to merge token with previous contents.
+ // Returns true if token is successfully disposed of.
+ // If keepSB is false, any previous StringBuffer is frozen.
+ // If keepSB is true, a StringBuffer may be created to hold
+ // the merged token.
+ private boolean mergeWithPrev(int i, String token, boolean keepSB) {
+ if (i == 0) // Trivial success if the token is length zero.
+ {
+ return (token.length() == 0);
+ }
+ Object prev = parts[i - 1];
+ if (prev instanceof StringBuffer) {
+ StringBuffer psb = (StringBuffer) prev;
+ psb.append(token);
+ if (!keepSB) {
+ parts[i - 1] = psb.toString();
+ }
+ return true;
+ }
+ if (token.length() == 0) {
+ return true; // Trivial success.
+ }
+ if (prev instanceof CharSequence) {
+ // Must concatenate.
+ StringBuffer psb = new StringBuffer(prev.toString());
+ psb.append(token);
+ if (keepSB) {
+ parts[i - 1] = psb;
+ } else {
+ parts[i - 1] = psb.toString();
+ }
+ return true;
+ }
+ return false;
+ }
+
+ /** Trim all strings, using String.trim().
+ * Remove empty strings.
+ * Normalize CharSequences to Strings.
+ */
+ public void trimText() {
+ checkNotFrozen();
+ int fillp = 0;
+ int size = this.size;
+ Object[] parts = this.parts;
+ for (int i = 0; i < size; i++) {
+ Object e = parts[i];
+ if (e instanceof CharSequence) {
+ String tt = e.toString().trim();
+ if (tt.length() == 0) {
+ continue;
+ }
+ e = tt;
+ }
+ parts[fillp++] = e;
+ }
+ while (size > fillp) {
+ parts[--size] = null;
+ }
+ this.size = fillp;
+ }
+
+ /** Add one or more subelements at the given position.
+ * If the object reference is null, nothing happens.
+ * If the object is an anonymous Element, addAll is called.
+ * If the object is a TokenList, addAll is called (to add the tokens).
+ * Otherwise, add is called, adding a single subelement or string.
+ * The net effect is to add zero or more tokens.
+ * The returned value is the number of added elements.
+ * <p>
+ * Note that getText() can return a TokenList which preserves
+ * token boundaries in the text source. Such a text will be
+ * added as multiple text sub-elements.
+ * <p>
+ * If a text string is added adjacent to an immediately
+ * preceding string, there will be a token boundary between
+ * the strings, which will print as an extra space.
+ */
+ public int addContent(int i, Object e) {
+ if (e == null) {
+ return 0;
+ } else if (e instanceof TokenList) {
+ return addAll(i, (Collection) e);
+ } else if (e instanceof Element
+ && ((Element) e).isAnonymous()) {
+ return addAll(i, (Element) e);
+ } else {
+ add(i, e);
+ return 1;
+ }
+ }
+
+ public int addContent(Object e) {
+ return addContent(size, e);
+ }
+
+ public Object[] toArray() {
+ Object[] result = new Object[size];
+ System.arraycopy(parts, 0, result, 0, size);
+ return result;
+ }
+
+ public Element copyContentOnly() {
+ Element content = new Element(size);
+ System.arraycopy(parts, 0, content.parts, 0, size);
+ content.size = size;
+ return content;
+ }
+
+ public void sort(Comparator<Object> c) {
+ Arrays.sort(parts, 0, size, c);
+ }
+
+ public void sort() {
+ sort(CONTENT_ORDER);
+ }
+
+ /** Equivalent to Collections.reverse(this.asList()). */
+ public void reverse() {
+ for (int i = 0, mid = size >> 1, j = size - 1; i < mid; i++, j--) {
+ Object p = parts[i];
+ parts[i] = parts[j];
+ parts[j] = p;
+ }
+ }
+
+ /** Equivalent to Collections.shuffle(this.asList() [, rnd]). */
+ public void shuffle() {
+ Collections.shuffle(this.asList());
+ }
+
+ public void shuffle(Random rnd) {
+ Collections.shuffle(this.asList(), rnd);
+ }
+
+ /** Equivalent to Collections.rotate(this.asList(), dist). */
+ public void rotate(int dist) {
+ Collections.rotate(this.asList(), dist);
+ }
+
+ /** Equivalent to Collections.min(this.asList(), c). */
+ public Object min(Comparator<Object> c) {
+ return Collections.min(this.asList(), c);
+ }
+
+ public Object min() {
+ return min(CONTENT_ORDER);
+ }
+
+ /** Equivalent to Collections.max(this.asList(), c). */
+ public Object max(Comparator<Object> c) {
+ return Collections.max(this.asList(), c);
+ }
+
+ public Object max() {
+ return max(CONTENT_ORDER);
+ }
+
+ public int addAll(int i, Collection c) {
+ if (c instanceof LView) {
+ return addAll(i, ((LView) c).asElement());
+ } else {
+ int csize = c.size();
+ if (csize == 0) {
+ return 0;
+ }
+ openOrExpand(i, csize);
+ int fill = i;
+ for (Object part : c) {
+ parts[fill++] = part;
+ }
+ return csize;
+ }
+ }
+
+ public int addAll(int i, Element e) {
+ int esize = e.size;
+ if (esize == 0) {
+ return 0;
+ }
+ openOrExpand(i, esize);
+ System.arraycopy(e.parts, 0, parts, i, esize);
+ return esize;
+ }
+
+ public int addAll(Collection c) {
+ return addAll(size, c);
+ }
+
+ public int addAll(Element e) {
+ return addAll(size, e);
+ }
+
+ public int addAllAttrsFrom(Element e) {
+ int added = 0;
+ for (int k = 0; e.containsAttr(k); k++) {
+ String old = setAttr(e.getAttrName(k), e.getAttr(k));
+ if (old == null) {
+ added += 1;
+ }
+ }
+ // Return number of added (not merely changed) attrs.
+ return added;
+ }
+
+ // Search.
+ public boolean matches(Filter f) {
+ return f.filter(this) != null;
+ }
+
+ public Object find(Filter f) {
+ return findOrRemove(f, 0, false);
+ }
+
+ public Object find(Filter f, int fromIndex) {
+ if (fromIndex < 0) {
+ fromIndex = 0;
+ }
+ return findOrRemove(f, fromIndex, false);
+ }
+
+ /** Find the last element matching the given filter.
+ * Return the filtered value.
+ */
+ public Object findLast(Filter f) {
+ return findOrRemoveLast(f, size - 1, false);
+ }
+
+ public Object findLast(Filter f, int fromIndex) {
+ if (fromIndex >= size) {
+ fromIndex = size - 1;
+ }
+ return findOrRemoveLast(f, fromIndex, false);
+ }
+
+ /** Find all elements matching the given filter.
+ * If there is a non-null collection given as a sink,
+ * transfer matching elements to the given collection.
+ * The int result is the number of matching elements.
+ * If there is a null sink given, the matching elements are
+ * not collected. If there is no sink given, the matching
+ * elements are returned in an anonymous container element.
+ * In no case is the receiver element changed.
+ * <p>
+ * Note that a simple count of matching elements can be
+ * obtained by passing a null collection argument.
+ */
+ public Element findAll(Filter f) {
+ Element result = new Element();
+ findOrRemoveAll(f, false, 0, size, result.asList(), false);
+ return result;
+ }
+
+ public Element findAll(Filter f, int fromIndex, int toIndex) {
+ Element result = new Element(name);
+ findOrRemoveAll(f, false, fromIndex, toIndex, result.asList(), false);
+ return result;
+ }
+
+ public int findAll(Filter f, Collection<Object> sink) {
+ return findOrRemoveAll(f, false, 0, size, sink, false);
+ }
+
+ public int findAll(Filter f, int fromIndex, int toIndex, Collection<Object> sink) {
+ return findOrRemoveAll(f, false, fromIndex, toIndex, sink, false);
+ }
+
+ /// Driver routines.
+ private Object findOrRemove(Filter f, int fromIndex, boolean remove) {
+ for (int i = fromIndex; i < size; i++) {
+ Object x = f.filter(parts[i]);
+ if (x != null) {
+ if (remove) {
+ close(i, 1);
+ }
+ return x;
+ }
+ }
+ return null;
+ }
+
+ private Object findOrRemoveLast(Filter f, int fromIndex, boolean remove) {
+ for (int i = fromIndex; i >= 0; i--) {
+ Object x = f.filter(parts[i]);
+ if (x != null) {
+ if (remove) {
+ close(i, 1);
+ }
+ return x;
+ }
+ }
+ return null;
+ }
+
+ private int findOrRemoveAll(Filter f, boolean fInvert,
+ int fromIndex, int toIndex,
+ Collection<Object> sink, boolean remove) {
+ if (fromIndex < 0) {
+ badIndex(fromIndex);
+ }
+ if (toIndex > size) {
+ badIndex(toIndex);
+ }
+ int found = 0;
+ for (int i = fromIndex; i < toIndex; i++) {
+ Object p = parts[i];
+ Object x = f.filter(p);
+ if (fInvert ? (x == null) : (x != null)) {
+ if (remove) {
+ close(i--, 1);
+ toIndex--;
+ }
+ found += XMLKit.addContent(fInvert ? p : x, sink);
+ }
+ }
+ return found;
+ }
+
+ public void replaceAll(Filter f) {
+ XMLKit.replaceAll(f, this.asList());
+ }
+
+ public void replaceAll(Filter f, int fromIndex, int toIndex) {
+ XMLKit.replaceAll(f, this.asList().subList(fromIndex, toIndex));
+ }
+
+ /// Recursive walks.
+ // findAllInTree(f) == findAll(findInTree(f,S)), S.toElement
+ // findAllInTree(f,S) == findAll(findInTree(content(f,S)))
+ // removeAllInTree(f) == replaceAll(replaceInTree(and(f,emptyF)))
+ // removeAllInTree(f,S) == replaceAll(replaceInTree(and(content(f,S),emptyF)))
+ // retainAllInTree(f) == removeAllInTree(not(f))
+ // replaceAllInTree(f) == replaceAll(replaceInTree(f))
+ public Element findAllInTree(Filter f) {
+ Element result = new Element();
+ findAllInTree(f, result.asList());
+ return result;
+ }
+
+ public int findAllInTree(Filter f, Collection<Object> sink) {
+ int found = 0;
+ int size = this.size; // cache copy
+ for (int i = 0; i < size; i++) {
+ Object p = parts[i];
+ Object x = f.filter(p);
+ if (x != null) {
+ found += XMLKit.addContent(x, sink);
+ } else if (p instanceof Element) {
+ found += ((Element) p).findAllInTree(f, sink);
+ }
+ }
+ return found;
+ }
+
+ public int countAllInTree(Filter f) {
+ return findAllInTree(f, null);
+ }
+
+ public int removeAllInTree(Filter f, Collection<Object> sink) {
+ if (sink == null) {
+ sink = newCounterColl();
+ }
+ replaceAll(replaceInTree(and(content(f, sink), emptyFilter())));
+ return sink.size();
+ }
+
+ public Element removeAllInTree(Filter f) {
+ Element result = new Element();
+ removeAllInTree(f, result.asList());
+ return result;
+ }
+
+ public int retainAllInTree(Filter f, Collection<Object> sink) {
+ return removeAllInTree(not(f), sink);
+ }
+
+ public Element retainAllInTree(Filter f) {
+ Element result = new Element();
+ retainAllInTree(f, result.asList());
+ return result;
+ }
+
+ public void replaceAllInTree(Filter f) {
+ replaceAll(replaceInTree(f));
+ }
+
+ /** Raise a ClassCastException if any subelements are the wrong type. */
+ public void checkPartsOnly(Class<?> elementClass) {
+ for (int i = 0; i < size; i++) {
+ elementClass.cast(parts[i]).getClass();
+ }
+ }
+
+ /** Return true if all sub-elements are of the given type. */
+ public boolean isPartsOnly(Class<?> elementClass) {
+ for (int i = 0; i < size; i++) {
+ if (!elementClass.isInstance(parts[i])) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ /** Provides an iterable view of this object as a series of elements.
+ * All sub-elements of this Element must be of type Element.
+ * A ClassCastException is raised if there are non-Element sub-elements.
+ */
+ public <T> Iterable<T> partsOnly(Class<T> elementClass) {
+ checkPartsOnly(elementClass);
+ return (Iterable<T>) (Iterable) this;
+ }
+
+ public Iterable<Element> elements() {
+ return partsOnly(Element.class);
+ }
+
+ /// Useful shorthands.
+ // Finding or removing elements w/o regard to their type or content.
+ public Element findElement() {
+ return (Element) find(elementFilter());
+ }
+
+ public Element findAllElements() {
+ return findAll(elementFilter());
+ }
+
+ public Element removeElement() {
+ return (Element) remove(elementFilter());
+ }
+
+ public Element removeAllElements() {
+ return (Element) removeAll(elementFilter());
+ }
+
+ // Finding or removing by element tag or selected attribute,
+ // as if by elementFilter(name) or attrFilter(name, value).
+ // Roughly akin to Common Lisp ASSOC.
+ public Element findElement(String name) {
+ return (Element) find(elementFilter(name));
+ }
+
+ public Element removeElement(String name) {
+ return (Element) remove(elementFilter(name));
+ }
+
+ public Element findWithAttr(String key) {
+ return (Element) find(attrFilter(name));
+ }
+
+ public Element findWithAttr(String key, String value) {
+ return (Element) find(attrFilter(name, value));
+ }
+
+ public Element removeWithAttr(String key) {
+ return (Element) remove(attrFilter(name));
+ }
+
+ public Element removeWithAttr(String key, String value) {
+ return (Element) remove(attrFilter(name, value));
+ }
+
+ public Element findAllElements(String name) {
+ return findAll(elementFilter(name));
+ }
+
+ public Element removeAllElements(String name) {
+ return removeAll(elementFilter(name));
+ }
+
+ public Element retainAllElements(String name) {
+ return retainAll(elementFilter(name));
+ }
+
+ public Element findAllWithAttr(String key) {
+ return findAll(attrFilter(key));
+ }
+
+ public Element removeAllWithAttr(String key) {
+ return removeAll(attrFilter(key));
+ }
+
+ public Element retainAllWithAttr(String key) {
+ return retainAll(attrFilter(key));
+ }
+
+ public Element findAllWithAttr(String key, String value) {
+ return findAll(attrFilter(key, value));
+ }
+
+ public Element removeAllWithAttr(String key, String value) {
+ return removeAll(attrFilter(key, value));
+ }
+
+ public Element retainAllWithAttr(String key, String value) {
+ return retainAll(attrFilter(key, value));
+ }
+
+ public int countAll(Filter f) {
+ return findAll(f, null);
+ }
+
+ public int countAllElements() {
+ return countAll(elementFilter());
+ }
+
+ public int countAllElements(String name) {
+ return countAll(elementFilter(name));
+ }
+
+ public int countAllWithAttr(String key) {
+ return countAll(attrFilter(name));
+ }
+
+ public int countAllWithAttr(String key, String value) {
+ return countAll(attrFilter(key, value));
+ }
+
+ public int indexOf(Object e) {
+ for (int i = 0; i < size; i++) {
+ if (e.equals(parts[i])) {
+ return i;
+ }
+ }
+ return -1;
+ }
+
+ public int lastIndexOf(Object e) {
+ for (int i = size - 1; i >= 0; i--) {
+ if (e.equals(parts[i])) {
+ return i;
+ }
+ }
+ return -1;
+ }
+
+ /** Remove the first element matching the given filter.
+ * Return the filtered value.
+ */
+ public int indexOf(Filter f) {
+ return indexOf(f, 0);
+ }
+
+ public int indexOf(Filter f, int fromIndex) {
+ if (fromIndex < 0) {
+ fromIndex = 0;
+ }
+ for (int i = fromIndex; i < size; i++) {
+ Object x = f.filter(parts[i]);
+ if (x != null) {
+ return i;
+ }
+ }
+ return -1;
+ }
+
+ /** Remove the last element matching the given filter.
+ * Return the filtered value.
+ */
+ public int lastIndexOf(Filter f) {
+ return lastIndexOf(f, size - 1);
+ }
+
+ public int lastIndexOf(Filter f, int fromIndex) {
+ if (fromIndex >= size) {
+ fromIndex = size - 1;
+ }
+ for (int i = fromIndex; i >= 0; i--) {
+ Object x = f.filter(parts[i]);
+ if (x != null) {
+ return i;
+ }
+ }
+ return -1;
+ }
+
+ public boolean contains(Object e) {
+ return indexOf(e) >= 0;
+ }
+
+ // attributes
+ private int findOrCreateAttr(String key, boolean create) {
+ key.toString(); // null check
+ int attrBase = parts.length;
+ for (int i = parts.length - 2; i >= size; i -= 2) {
+ String akey = (String) parts[i + 0];
+ if (akey == null) {
+ if (!create) {
+ return -1;
+ }
+ if (i == size) {
+ break; // NEED_SLOP
+ }
+ parts[i + 0] = key;
+ //parts[i+1] = ""; //caller responsibility
+ return i;
+ }
+ attrBase = i;
+ if (akey.equals(key)) {
+ return i;
+ }
+ }
+ // If we fell through, we ran into an element part.
+ // Therefore we have run out of empty slots.
+ if (!create) {
+ return -1;
+ }
+ assert (!isFrozen());
+ int alen = parts.length - attrBase;
+ expand(size, 2); // generally expands by more than 2
+ // since there was a reallocation, the garbage slots are really null
+ assert (parts[size + 0] == null && parts[size + 1] == null);
+ alen += 2;
+ int i = parts.length - alen;
+ parts[i + 0] = key;
+ //parts[i+1] = ""; //caller responsibility
+ return i;
+ }
+
+ public int attrSize() {
+ return attrLength() >>> 1;
+ }
+
+ public int indexOfAttr(String key) {
+ return findOrCreateAttr(key, false);
+ }
+
+ public boolean containsAttr(String key) {
+ return indexOfAttr(key) >= 0;
+ }
+
+ public String getAttr(String key) {
+ return getAttr(key, null);
+ }
+
+ public String getAttr(String key, String dflt) {
+ int i = findOrCreateAttr(key, false);
+ return (i < 0) ? dflt : (String) parts[i + 1];
+ }
+
+ public TokenList getAttrList(String key) {
+ return convertToList(getAttr(key));
+ }
+
+ public Number getAttrNumber(String key) {
+ return convertToNumber(getAttr(key));
+ }
+
+ public long getAttrLong(String key) {
+ return getAttrLong(key, 0);
+ }
+
+ public double getAttrDouble(String key) {
+ return getAttrDouble(key, 0.0);
+ }
+
+ public long getAttrLong(String key, long dflt) {
+ return convertToLong(getAttr(key), dflt);
+ }
+
+ public double getAttrDouble(String key, double dflt) {
+ return convertToDouble(getAttr(key), dflt);
+ }
+
+ int indexAttr(int k) {
+ int i = parts.length - (k * 2) - 2;
+ if (i < size || parts[i] == null) {
+ return -2; // always oob
+ }
+ return i;
+ }
+
+ public boolean containsAttr(int k) {
+ return indexAttr(k) >= 0;
+ }
+
+ public String getAttr(int k) {
+ return (String) parts[indexAttr(k) + 1];
+ }
+
+ public String getAttrName(int k) {
+ return (String) parts[indexAttr(k) + 0];
+ }
+
+ public Iterable<String> attrNames() {
+ //return asAttrMap().keySet();
+ return new Iterable<String>() {
+
+ public Iterator<String> iterator() {
+ return new ANItr();
+ }
+ };
+ }
+
+ // Hand-inlined replacement for asAttrMap().keySet().iterator():
+ class ANItr implements Iterator<String> {
+
+ boolean lastRet;
+ int cursor = -2; // pointer from end of parts
+
+ public boolean hasNext() {
+ int i = cursor + parts.length;
+ return i >= size && parts[i] == null;
+ }
+
+ public String next() {
+ int i = cursor + parts.length;
+ Object x;
+ if (i < size || (x = parts[i]) == null) {
+ nsee();
+ return null;
+ }
+ cursor -= 2;
+ lastRet = true;
+ return (String) x;
+ }
+
+ public void remove() {
+ if (!lastRet) {
+ throw new IllegalStateException();
+ }
+ Element.this.removeAttr((-4 - cursor) / 2);
+ cursor += 2;
+ lastRet = false;
+ }
+
+ Exception nsee() {
+ throw new NoSuchElementException("attribute " + (-2 - cursor) / 2);
+ }
+ }
+
+ /** Return an anonymous copy of self, but only with attributes.
+ */
+ public Element copyAttrsOnly() {
+ int alen = attrLength();
+ Element attrs = new Element(alen);
+ Object[] attrParts = attrs.parts;
+ assert (attrParts.length == NEED_SLOP + alen);
+ System.arraycopy(parts, parts.length - alen,
+ attrParts, NEED_SLOP,
+ alen);
+ return attrs;
+ }
+
+ /** Get all attributes, represented as an element with sub-elements.
+ * The name of each sub-element is the attribute key, and the text
+ * This is a fresh copy, and can be updated with affecting the original.
+ * of each sub-element is the corresponding attribute value.
+ * See also asAttrMap() for a "live" view of all the attributes as a Map.
+ */
+ public Element getAttrs() {
+ int asize = attrSize();
+ Element attrs = new Element(ANON_NAME, asize, NEED_SLOP + asize);
+ for (int i = 0; i < asize; i++) {
+ Element attr = new Element(getAttrName(i), 1, NEED_SLOP + 1);
+ // %%% normalize attrs to token lists?
+ attr.setRaw(0, getAttr(i));
+ attrs.setRaw(i, attr);
+ }
+ return attrs;
+ }
+
+ public void setAttrs(Element attrs) {
+ int alen = attrLength();
+ clearParts(parts.length - alen, alen);
+ if (!hasNulls(NEED_SLOP + attrs.size * 2)) {
+ expand(size, attrs.size * 2);
+ }
+ addAttrs(attrs);
+ }
+
+ public void addAttrs(Element attrs) {
+ for (int i = 0; i < attrs.size; i++) {
+ Element attr = (Element) attrs.get(i);
+ setAttr(attr.name, attr.getText().toString());
+ }
+ }
+
+ public void removeAttr(int i) {
+ checkNotFrozen();
+ while ((i -= 2) >= size) {
+ Object k = parts[i + 0];
+ Object v = parts[i + 1];
+ if (k == null) {
+ break;
+ }
+ parts[i + 2] = k;
+ parts[i + 3] = v;
+ }
+ parts[i + 2] = null;
+ parts[i + 3] = null;
+ }
+
+ public void clearAttrs() {
+ if (parts.length == 0 || parts[parts.length - 1] == null) {
+ return; // no attrs to clear
+ }
+ checkNotFrozen();
+ if (size == 0) {
+ // If no elements, free the parts array.
+ parts = noPartsNotFrozen;
+ return;
+ }
+ for (int i = parts.length - 1; parts[i] != null; i--) {
+ assert (i >= size);
+ parts[i] = null;
+ }
+ }
+
+ public String setAttr(String key, String value) {
+ String old;
+ if (value == null) {
+ int i = findOrCreateAttr(key, false);
+ if (i >= 0) {
+ old = (String) parts[i + 1];
+ removeAttr(i);
+ } else {
+ old = null;
+ }
+ } else {
+ checkNotFrozen();
+ int i = findOrCreateAttr(key, true);
+ old = (String) parts[i + 1];
+ parts[i + 1] = value;
+ }
+ return old;
+ }
+
+ public String setAttrList(String key, List<String> l) {
+ if (l == null) {
+ return setAttr(key, null);
+ }
+ if (!(l instanceof TokenList)) {
+ l = new TokenList(l);
+ }
+ return setAttr(key, l.toString());
+ }
+
+ public String setAttrNumber(String key, Number n) {
+ return setAttr(key, (n == null) ? null : n.toString());
+ }
+
+ public String setAttrLong(String key, long n) {
+ return setAttr(key, (n == 0) ? null : String.valueOf(n));
+ }
+
+ public String setAttrDouble(String key, double n) {
+ return setAttr(key, (n == 0) ? null : String.valueOf(n));
+ }
+
+ public String setAttr(int k, String value) {
+ int i = indexAttr(k);
+ String old = (String) parts[i + 1];
+ if (value == null) {
+ removeAttr(i);
+ } else {
+ checkNotFrozen();
+ parts[i + 1] = value;
+ }
+ return old;
+ }
+
+ int attrLength() {
+ return parts.length - attrBase();
+ }
+
+ /** Are the attributes of the two two elements equal?
+ * Disregards name, sub-elements, and ordering of attributes.
+ */
+ public boolean equalAttrs(Element that) {
+ int alen = this.attrLength();
+ if (alen != that.attrLength()) {
+ return false;
+ }
+ if (alen == 0) {
+ return true;
+ }
+ return compareAttrs(alen, that, alen, false) == 0;
+ }
+
+ private int compareAttrs(int thisAlen,
+ Element that, int thatAlen,
+ boolean fullCompare) {
+ Object[] thisParts = this.parts;
+ Object[] thatParts = that.parts;
+ int thisBase = thisParts.length - thisAlen;
+ int thatBase = thatParts.length - thatAlen;
+ // search indexes into unmatched parts of this.attrs:
+ int firstI = 0;
+ // search indexes into unmatched parts of that.attrs:
+ int firstJ = 0;
+ int lastJ = thatAlen - 2;
+ // try to find the mismatch with the first key:
+ String firstKey = null;
+ int firstKeyValCmp = 0;
+ int foundKeys = 0;
+ for (int i = 0; i < thisAlen; i += 2) {
+ String key = (String) thisParts[thisBase + i + 0];
+ String val = (String) thisParts[thisBase + i + 1];
+ String otherVal = null;
+ for (int j = firstJ; j <= lastJ; j += 2) {
+ if (key.equals(thatParts[thatBase + j + 0])) {
+ foundKeys += 1;
+ otherVal = (String) thatParts[thatBase + j + 1];
+ // Optimization: Narrow subsequent searches when easy.
+ if (j == lastJ) {
+ lastJ -= 2;
+ } else if (j == firstJ) {
+ firstJ += 2;
+ }
+ if (i == firstI) {
+ firstI += 2;
+ }
+ break;
+ }
+ }
+ int valCmp;
+ if (otherVal != null) {
+ // The key was found.
+ if (!fullCompare) {
+ if (!val.equals(otherVal)) {
+ return 1 - 0; //arb.
+ }
+ continue;
+ }
+ valCmp = val.compareTo(otherVal);
+ } else {
+ // Found the key in this but not that.
+ // Such a mismatch puts the guy missing the key last.
+ valCmp = 0 - 1;
+ }
+ if (valCmp != 0) {
+ // found a mismatch, key present in both elems
+ if (firstKey == null
+ || firstKey.compareTo(key) > 0) {
+ // found a better key
+ firstKey = key;
+ firstKeyValCmp = valCmp;
+ }
+ }
+ }
+ // We have located the first mismatch of all keys in this.attrs.
+ // In general we must also look for keys in that.attrs but missing
+ // from this.attrs; such missing keys, if earlier than firstKey,
+ // rule the comparison.
+
+ // We can sometimes prove quickly there is no missing key.
+ if (foundKeys == thatAlen / 2) {
+ // Exhausted all keys in that.attrs.
+ return firstKeyValCmp;
+ }
+
+ // Search for a missing key in that.attrs earlier than firstKey.
+ findMissingKey:
+ for (int j = firstJ; j <= lastJ; j += 2) {
+ String otherKey = (String) thatParts[thatBase + j + 0];
+ if (firstKey == null
+ || firstKey.compareTo(otherKey) > 0) {
+ // Found a better key; is it missing?
+ for (int i = firstI; i < thisAlen; i += 2) {
+ if (otherKey.equals(thisParts[thisBase + i + 0])) {
+ continue findMissingKey;
+ }
+ }
+ // If we get here, there was no match in this.attrs.
+ return 1 - 0;
+ }
+ }
+
+ // No missing key. Previous comparison value rules.
+ return firstKeyValCmp;
+ }
+
+ // Binary search looking for first non-null after size.
+ int attrBase() {
+ // Smallest & largest possible attribute indexes:
+ int kmin = 0;
+ int kmax = (parts.length - size) >>> 1;
+ // earlist possible attribute position:
+ int abase = parts.length - (kmax * 2);
+ // binary search using scaled indexes:
+ while (kmin != kmax) {
+ int kmid = kmin + ((kmax - kmin) >>> 1);
+ if (parts[abase + (kmid * 2)] == null) {
+ kmin = kmid + 1;
+ } else {
+ kmax = kmid;
+ }
+ assert (kmin <= kmax);
+ }
+ return abase + (kmax * 2);
+ }
+
+ /** Sort attributes by name. */
+ public void sortAttrs() {
+ checkNotFrozen();
+ int abase = attrBase();
+ int alen = parts.length - abase;
+ String[] buf = new String[alen];
+ // collect keys
+ for (int k = 0; k < alen / 2; k++) {
+ String akey = (String) parts[abase + (k * 2) + 0];
+ buf[k] = akey;
+ }
+ Arrays.sort(buf, 0, alen / 2);
+ // collect values
+ for (int k = 0; k < alen / 2; k++) {
+ String akey = buf[k];
+ buf[k + alen / 2] = getAttr(akey);
+ }
+ // reorder keys and values
+ int fillp = parts.length;
+ for (int k = 0; k < alen / 2; k++) {
+ String akey = buf[k];
+ String aval = buf[k + alen / 2];
+ fillp -= 2;
+ parts[fillp + 0] = akey;
+ parts[fillp + 1] = aval;
+ }
+ assert (fillp == abase);
+ }
+
+ /*
+ Notes on whitespace and tokenization.
+ On input, never split CDATA blocks. They remain single tokens.
+ ?Try to treat encoded characters as CDATA-quoted, also?
+
+ Internally, each String sub-element is logically a token.
+ However, if there was no token-splitting on input,
+ consecutive strings are merged by the parser.
+
+ Internally, we need addToken (intervening blank) and addText
+ (hard concatenation).
+
+ Optionally on input, tokenize unquoted text into words.
+ Between each adjacent word pair, elide either one space
+ or all space.
+
+ On output, we always add spaces between tokens.
+ The Element("a", {"b", "c", Element("d"), "e f"})
+ outputs as "<a>b c<d/>e f</a>"
+ */
+ /** Split strings into tokens, using a StringTokenizer. */
+ public void tokenize(String delims, boolean returnDelims) {
+ checkNotFrozen();
+ if (delims == null) {
+ delims = WHITESPACE_CHARS; // StringTokenizer default
+ }
+ for (int i = 0; i < size; i++) {
+ if (!(parts[i] instanceof CharSequence)) {
+ continue;
+ }
+ int osize = size;
+ String str = parts[i].toString();
+ StringTokenizer st = new StringTokenizer(str, delims, returnDelims);
+ int nstrs = st.countTokens();
+ switch (nstrs) {
+ case 0:
+ close(i--, 1);
+ break;
+ case 1:
+ parts[i] = st.nextToken();
+ break;
+ default:
+ openOrExpand(i + 1, nstrs - 1);
+ for (int j = 0; j < nstrs; j++) {
+ parts[i + j] = st.nextToken();
+ }
+ i += nstrs - 1;
+ break;
+ }
+ }
+ }
+
+ public void tokenize(String delims) {
+ tokenize(delims, false);
+ }
+
+ public void tokenize() {
+ tokenize(null, false);
+ }
+
+ // views
+ class LView extends AbstractList<Object> {
+
+ Element asElement() {
+ return Element.this;
+ }
+
+ public int size() {
+ return Element.this.size();
+ }
+
+ public Object get(int i) {
+ return Element.this.get(i);
+ }
+
+ @Override
+ public boolean contains(Object e) {
+ return Element.this.contains(e);
+ }
+
+ @Override
+ public Object[] toArray() {
+ return Element.this.toArray();
+ }
+
+ @Override
+ public int indexOf(Object e) {
+ return Element.this.indexOf(e);
+ }
+
+ @Override
+ public int lastIndexOf(Object e) {
+ return Element.this.lastIndexOf(e);
+ }
+
+ @Override
+ public void add(int i, Object e) {
+ ++modCount;
+ Element.this.add(i, e);
+ }
+
+ @Override
+ public boolean addAll(int i, Collection<? extends Object> c) {
+ ++modCount;
+ return Element.this.addAll(i, c) > 0;
+ }
+
+ @Override
+ public boolean addAll(Collection<? extends Object> c) {
+ ++modCount;
+ return Element.this.addAll(c) > 0;
+ }
+
+ @Override
+ public Object remove(int i) {
+ ++modCount;
+ return Element.this.remove(i);
+ }
+
+ @Override
+ public Object set(int i, Object e) {
+ ++modCount;
+ return Element.this.set(i, e);
+ }
+
+ @Override
+ public void clear() {
+ ++modCount;
+ Element.this.clear();
+ }
+ // Others: toArray(Object[]), containsAll, removeAll, retainAll
+ }
+
+ /** Produce a list view of sub-elements.
+ * (The list view does not provide access to the element's
+ * name or attributes.)
+ * Changes to this view are immediately reflected in the
+ * element itself.
+ */
+ public List<Object> asList() {
+ return new LView();
+ }
+
+ /** Produce a list iterator on all sub-elements. */
+ public ListIterator<Object> iterator() {
+ //return asList().listIterator();
+ return new Itr();
+ }
+
+ // Hand-inlined replacement for LView.listIterator():
+ class Itr implements ListIterator<Object> {
+
+ int lastRet = -1;
+ int cursor = 0;
+
+ public boolean hasNext() {
+ return cursor < size;
+ }
+
+ public boolean hasPrevious() {
+ return cursor > 0 && cursor <= size;
+ }
+
+ public Object next() {
+ if (!hasNext()) {
+ nsee();
+ }
+ return parts[lastRet = cursor++];
+ }
+
+ public Object previous() {
+ if (!hasPrevious()) {
+ nsee();
+ }
+ return parts[--cursor];
+ }
+
+ public int nextIndex() {
+ return cursor;
+ }
+
+ public int previousIndex() {
+ return cursor - 1;
+ }
+
+ public void set(Object x) {
+ parts[lastRet] = x;
+ }
+
+ public void add(Object x) {
+ lastRet = -1;
+ Element.this.add(cursor++, x);
+ }
+
+ public void remove() {
+ if (lastRet < 0) {
+ throw new IllegalStateException();
+ }
+ Element.this.remove(lastRet);
+ if (lastRet < cursor) {
+ --cursor;
+ }
+ lastRet = -1;
+ }
+
+ void nsee() {
+ throw new NoSuchElementException("element " + cursor);
+ }
+ }
+
+ /** A PrintWriter which always appends as if by addText.
+ * Use of this stream may insert a StringBuffer at the end
+ * of the Element. The user must not directly modify this
+ * StringBuffer, or use it in other data structures.
+ * From time to time, the StringBuffer may be replaced by a
+ * constant string as a result of using the PrintWriter.
+ */
+ public PrintWriter asWriter() {
+ return new ElemW();
+ }
+
+ class ElemW extends PrintWriter {
+
+ ElemW() {
+ super(new StringWriter());
+ }
+ final StringBuffer buf = ((StringWriter) out).getBuffer();
+
+ {
+ lock = buf;
+ } // synchronize on this buffer
+
+ @Override
+ public void println() {
+ synchronized (buf) {
+ ensureCursor();
+ super.println();
+ }
+ }
+
+ @Override
+ public void write(int ch) {
+ synchronized (buf) {
+ ensureCursor();
+ //buf.append(ch);
+ super.write(ch);
+ }
+ }
+
+ @Override
+ public void write(char buf[], int off, int len) {
+ synchronized (buf) {
+ ensureCursor();
+ super.write(buf, off, len);
+ }
+ }
+
+ @Override
+ public void write(String s, int off, int len) {
+ synchronized (buf) {
+ ensureCursor();
+ //buf.append(s.substring(off, off+len));
+ super.write(s, off, len);
+ }
+ }
+
+ @Override
+ public void write(String s) {
+ synchronized (buf) {
+ ensureCursor();
+ //buf.append(s);
+ super.write(s);
+ }
+ }
+
+ private void ensureCursor() {
+ checkNotFrozen();
+ if (getLast() != buf) {
+ int pos = indexOf(buf);
+ if (pos >= 0) {
+ // Freeze the pre-existing use of buf.
+ setRaw(pos, buf.toString());
+ }
+ add(buf);
+ }
+ }
+ }
+
+ /** Produce a map view of attributes, in which the attribute
+ * name strings are the keys.
+ * (The map view does not provide access to the element's
+ * name or sub-elements.)
+ * Changes to this view are immediately reflected in the
+ * element itself.
+ */
+ public Map<String, String> asAttrMap() {
+ class Entry implements Map.Entry<String, String> {
+
+ final int k;
+
+ Entry(int k) {
+ this.k = k;
+ assert (((String) getKey()).toString() != null); // check, fail-fast
+ }
+
+ public String getKey() {
+ return Element.this.getAttrName(k);
+ }
+
+ public String getValue() {
+ return Element.this.getAttr(k);
+ }
+
+ public String setValue(String v) {
+ return Element.this.setAttr(k, v.toString());
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (!(o instanceof Map.Entry)) {
+ return false;
+ }
+ Map.Entry that = (Map.Entry) o;
+ return (this.getKey().equals(that.getKey())
+ && this.getValue().equals(that.getValue()));
+ }
+
+ @Override
+ public int hashCode() {
+ return getKey().hashCode() ^ getValue().hashCode();
+ }
+ }
+ class EIter implements Iterator<Map.Entry<String, String>> {
+
+ int k = 0; // index of pending next() attribute
+
+ public boolean hasNext() {
+ return Element.this.containsAttr(k);
+ }
+
+ public Map.Entry<String, String> next() {
+ return new Entry(k++);
+ }
+
+ public void remove() {
+ Element.this.removeAttr(--k);
+ }
+ }
+ class ESet extends AbstractSet<Map.Entry<String, String>> {
+
+ public int size() {
+ return Element.this.attrSize();
+ }
+
+ public Iterator<Map.Entry<String, String>> iterator() {
+ return new EIter();
+ }
+
+ @Override
+ public void clear() {
+ Element.this.clearAttrs();
+ }
+ }
+ class AView extends AbstractMap<String, String> {
+
+ private transient Set<Map.Entry<String, String>> eSet;
+
+ public Set<Map.Entry<String, String>> entrySet() {
+ if (eSet == null) {
+ eSet = new ESet();
+ }
+ return eSet;
+ }
+
+ @Override
+ public int size() {
+ return Element.this.attrSize();
+ }
+
+ public boolean containsKey(String k) {
+ return Element.this.containsAttr(k);
+ }
+
+ public String get(String k) {
+ return Element.this.getAttr(k);
+ }
+
+ @Override
+ public String put(String k, String v) {
+ return Element.this.setAttr(k, v.toString());
+ }
+
+ public String remove(String k) {
+ return Element.this.setAttr(k, null);
+ }
+ }
+ return new AView();
+ }
+
+ /** Reports number of additional elements this object can accommodate
+ * without reallocation.
+ */
+ public int getExtraCapacity() {
+ int abase = attrBase();
+ return Math.max(0, abase - size - NEED_SLOP);
+ }
+
+ /** Ensures that at least the given number of additional elements
+ * can be added to this object without reallocation.
+ */
+ public void ensureExtraCapacity(int cap) {
+ if (cap == 0 || hasNulls(cap + NEED_SLOP)) {
+ return;
+ }
+ setExtraCapacity(cap);
+ }
+
+ /**
+ * Trim excess capacity to zero, or do nothing if frozen.
+ * This minimizes the space occupied by this Element,
+ * at the expense of a reallocation if sub-elements or attributes
+ * are added later.
+ */
+ public void trimToSize() {
+ if (isFrozen()) {
+ return;
+ }
+ setExtraCapacity(0);
+ }
+
+ /** Changes the number of additional elements this object can accommodate
+ * without reallocation.
+ */
+ public void setExtraCapacity(int cap) {
+ checkNotFrozen();
+ int abase = attrBase();
+ int alen = parts.length - abase; // slots allocated for attrs
+ int nlen = size + cap + NEED_SLOP + alen;
+ if (nlen != parts.length) {
+ Object[] nparts = new Object[nlen];
+ // copy attributes
+ System.arraycopy(parts, abase, nparts, nlen - alen, alen);
+ // copy sub-elements
+ System.arraycopy(parts, 0, nparts, 0, size);
+ parts = nparts;
+ }
+ assert (cap == getExtraCapacity());
+ }
+
+ // Return true if there are at least len nulls of slop available.
+ boolean hasNulls(int len) {
+ if (len == 0) {
+ return true;
+ }
+ int lastNull = size + len - 1;
+ if (lastNull >= parts.length) {
+ return false;
+ }
+ return (parts[lastNull] == null);
+ }
+
+ // Opens up parts array at pos by len spaces.
+ void open(int pos, int len) {
+ assert (pos < size);
+ assert (hasNulls(len + NEED_SLOP));
+ checkNotFrozen();
+ int nsize = size + len;
+ int tlen = size - pos;
+ System.arraycopy(parts, pos, parts, pos + len, tlen);
+ size = nsize;
+ }
+
+ // Reallocate and open up at parts[pos] to at least len empty places.
+ // Shift anything after pos right by len. Reallocate if necessary.
+ // If pos < size, caller must fill it in with non-null values.
+ // Returns incremented size; caller is responsible for storing it
+ // down, if desired.
+ int expand(int pos, int len) {
+ assert (pos <= size);
+ // There must be at least len nulls between elems and attrs.
+ assert (!hasNulls(NEED_SLOP + len)); // caller responsibility
+ checkNotFrozen();
+ int nsize = size + len; // length of all elements
+ int tlen = size - pos; // length of elements in post-pos tail
+ int abase = attrBase();
+ int alen = parts.length - abase; // slots allocated for attrs
+ int nlen = nsize + alen + NEED_SLOP;
+ nlen += (nlen >>> 1); // add new slop!
+ Object[] nparts = new Object[nlen];
+ // copy head of sub-elements
+ System.arraycopy(parts, 0, nparts, 0, pos);
+ // copy tail of sub-elements
+ System.arraycopy(parts, pos, nparts, pos + len, tlen);
+ // copy attributes
+ System.arraycopy(parts, abase, nparts, nlen - alen, alen);
+ // update self
+ parts = nparts;
+ //assert(hasNulls(len)); <- not yet true, since size != nsize
+ return nsize;
+ }
+
+ // Open or expand at the given position, as appropriate.
+ boolean openOrExpand(int pos, int len) {
+ if (pos < 0 || pos > size) {
+ badIndex(pos);
+ }
+ if (hasNulls(len + NEED_SLOP)) {
+ if (pos == size) {
+ size += len;
+ } else {
+ open(pos, len);
+ }
+ return false;
+ } else {
+ size = expand(pos, len);
+ return true;
+ }
+ }
+
+ // Close up at parts[pos] len old places.
+ // Shift anything after pos left by len.
+ // Fill unused end of parts with null.
+ void close(int pos, int len) {
+ assert (len > 0);
+ assert ((size - pos) >= len);
+ checkNotFrozen();
+ int tlen = (size - pos) - len; // length of elements in post-pos tail
+ int nsize = size - len;
+ System.arraycopy(parts, pos + len, parts, pos, tlen);
+ // reinitialize the unoccupied slots to null
+ clearParts(nsize, nsize + len);
+ // update self
+ size = nsize;
+ assert (hasNulls(len));
+ }
+
+ public void writeTo(Writer w) throws IOException {
+ new Printer(w).print(this);
+ }
+
+ public void writePrettyTo(Writer w) throws IOException {
+ prettyPrintTo(w, this);
+ }
+
+ public String prettyString() {
+ StringWriter sw = new StringWriter();
+ try {
+ writePrettyTo(sw);
+ } catch (IOException ee) {
+ throw new Error(ee); // should not happen
+ }
+ return sw.toString();
+ }
+
+ @Override
+ public String toString() {
+ StringWriter sw = new StringWriter();
+ try {
+ writeTo(sw);
+ } catch (IOException ee) {
+ throw new Error(ee); // should not happen
+ }
+ return sw.toString();
+ }
+
+ public String dump() {
+ // For debugging only. Reveals internal layout.
+ StringBuilder buf = new StringBuilder();
+ buf.append("<").append(name).append("[").append(size).append("]");
+ for (int i = 0; i < parts.length; i++) {
+ Object p = parts[i];
+ if (p == null) {
+ buf.append(" null");
+ } else {
+ buf.append(" {");
+ String cname = p.getClass().getName();
+ cname = cname.substring(1 + cname.indexOf('/'));
+ cname = cname.substring(1 + cname.indexOf('$'));
+ cname = cname.substring(1 + cname.indexOf('#'));
+ if (!cname.equals("String")) {
+ buf.append(cname).append(":");
+ }
+ buf.append(p);
+ buf.append("}");
+ }
+ }
+ return buf.append(">").toString();
+ }
+
+ public static java.lang.reflect.Method method(String name) {
+ HashMap allM = allMethods;
+ if (allM == null) {
+ allM = makeAllMethods();
+ }
+ java.lang.reflect.Method res = (java.lang.reflect.Method) allMethods.get(name);
+ if (res == null) {
+ throw new IllegalArgumentException(name);
+ }
+ return res;
+ }
+ private static HashMap allMethods;
+
+ private static synchronized HashMap makeAllMethods() {
+ if (allMethods != null) {
+ return allMethods;
+ }
+ java.lang.reflect.Method[] methods = Element.class.getMethods();
+ HashMap<String, java.lang.reflect.Method> allM = new HashMap<String, java.lang.reflect.Method>(),
+ ambig = new HashMap<String, java.lang.reflect.Method>();
+ for (int i = 0; i < methods.length; i++) {
+ java.lang.reflect.Method m = methods[i];
+ Class[] args = m.getParameterTypes();
+ String name = m.getName();
+ assert (java.lang.reflect.Modifier.isPublic(m.getModifiers()));
+ if (name.startsWith("notify")) {
+ continue;
+ }
+ if (name.endsWith("Attr")
+ && args.length > 0 && args[0] == int.class) // ignore getAttr(int), etc.
+ {
+ continue;
+ }
+ if (name.endsWith("All")
+ && args.length > 1 && args[0] == Filter.class) // ignore findAll(Filter, int...), etc.
+ {
+ continue;
+ }
+ java.lang.reflect.Method pm = allM.put(name, m);
+ if (pm != null) {
+ Class[] pargs = pm.getParameterTypes();
+ if (pargs.length > args.length) {
+ allM.put(name, pm); // put it back
+ } else if (pargs.length == args.length) {
+ ambig.put(name, pm); // make a note of it
+ }
+ }
+ }
+ // Delete ambiguous methods.
+ for (Map.Entry<String, java.lang.reflect.Method> e : ambig.entrySet()) {
+ String name = e.getKey();
+ java.lang.reflect.Method pm = e.getValue();
+ java.lang.reflect.Method m = allM.get(name);
+ Class[] args = m.getParameterTypes();
+ Class[] pargs = pm.getParameterTypes();
+ if (pargs.length == args.length) {
+ //System.out.println("ambig: "+pm);
+ //System.out.println(" with: "+m);
+ //ambig: int addAll(int,Element)
+ // with: int addAll(int,Collection)
+ allM.put(name, null); // get rid of
+ }
+ }
+ //System.out.println("allM: "+allM);
+ return allMethods = allM;
+ }
+ }
+
+ static Object fixupString(Object part) {
+ if (part instanceof CharSequence && !(part instanceof String)) {
+ return part.toString();
+ } else {
+ return part;
+ }
+ }
+
+ public static final class Special implements Comparable<Special> {
+
+ String kind;
+ Object value;
+
+ public Special(String kind, Object value) {
+ this.kind = kind;
+ this.value = value;
+ }
+
+ public String getKind() {
+ return kind;
+ }
+
+ public Object getValue() {
+ return value;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (!(o instanceof Special)) {
+ return false;
+ }
+ Special that = (Special) o;
+ return this.kind.equals(that.kind) && this.value.equals(that.value);
+ }
+
+ @Override
+ public int hashCode() {
+ return kind.hashCode() * 65 + value.hashCode();
+ }
+
+ public int compareTo(Special that) {
+ int r = this.kind.compareTo(that.kind);
+ if (r != 0) {
+ return r;
+ }
+ return ((Comparable) this.value).compareTo(that.value);
+ }
+
+ @Override
+ public String toString() {
+ int split = kind.indexOf(' ');
+ String pref = kind.substring(0, split < 0 ? 0 : split);
+ String post = kind.substring(split + 1);
+ return pref + value + post;
+ }
+ }
+
+ /** Supports sorting of mixed content. Sorts strings first,
+ * then Elements, then everything else (as Comparable).
+ */
+ public static Comparator<Object> contentOrder() {
+ return CONTENT_ORDER;
+ }
+ private static Comparator<Object> CONTENT_ORDER = new ContentComparator();
+
+ private static class ContentComparator implements Comparator<Object> {
+
+ public int compare(Object o1, Object o2) {
+ boolean cs1 = (o1 instanceof CharSequence);
+ boolean cs2 = (o2 instanceof CharSequence);
+ if (cs1 && cs2) {
+ String s1 = (String) fixupString(o1);
+ String s2 = (String) fixupString(o2);
+ return s1.compareTo(s2);
+ }
+ if (cs1) {
+ return 0 - 1;
+ }
+ if (cs2) {
+ return 1 - 0;
+ }
+ boolean el1 = (o1 instanceof Element);
+ boolean el2 = (o2 instanceof Element);
+ if (el1 && el2) {
+ return ((Element) o1).compareTo((Element) o2);
+ }
+ if (el1) {
+ return 0 - 1;
+ }
+ if (el2) {
+ return 1 - 0;
+ }
+ return ((Comparable) o1).compareTo(o2);
+ }
+ }
+
+ /** Used to find, filter, or transform sub-elements.
+ * When used as a predicate, the filter returns a null
+ * value for false, and the original object value for true.
+ * When used as a transformer, the filter may return
+ * null, for no values, the original object, a new object,
+ * or an anonymous Element (meaning multiple results).
+ */
+ public interface Filter {
+
+ Object filter(Object value);
+ }
+
+ /** Use this to find an element, perhaps with a given name. */
+ public static class ElementFilter implements Filter {
+
+ /** Subclasses may override this to implement better value tests.
+ * By default, it returns the element itself, thus recognizing
+ * all elements, regardless of name.
+ */
+ public Element filter(Element elem) {
+ return elem; // override this
+ }
+
+ public final Object filter(Object value) {
+ if (!(value instanceof Element)) {
+ return null;
+ }
+ return filter((Element) value);
+ }
+
+ @Override
+ public String toString() {
+ return "<ElementFilter name='*'/>";
+ }
+ }
+ private static Filter elementFilter;
+
+ public static Filter elementFilter() {
+ return (elementFilter != null) ? elementFilter : (elementFilter = new ElementFilter());
+ }
+
+ public static Filter elementFilter(final String name) {
+ name.toString(); // null check
+ return new ElementFilter() {
+
+ @Override
+ public Element filter(Element elem) {
+ return name.equals(elem.name) ? elem : null;
+ }
+
+ @Override
+ public String toString() {
+ return "<ElementFilter name='" + name + "'/>";
+ }
+ };
+ }
+
+ public static Filter elementFilter(final Collection nameSet) {
+ nameSet.getClass(); // null check
+ return new ElementFilter() {
+
+ @Override
+ public Element filter(Element elem) {
+ return nameSet.contains(elem.name) ? elem : null;
+ }
+
+ @Override
+ public String toString() {
+ return "<ElementFilter name='" + nameSet + "'/>";
+ }
+ };
+ }
+
+ public static Filter elementFilter(String... nameSet) {
+ Collection<String> ncoll = Arrays.asList(nameSet);
+ if (nameSet.length > 10) {
+ ncoll = new HashSet<String>(ncoll);
+ }
+ return elementFilter(ncoll);
+ }
+
+ /** Use this to find an element with a named attribute,
+ * possibly with a particular value.
+ * (Note that an attribute is missing if and only if its value is null.)
+ */
+ public static class AttrFilter extends ElementFilter {
+
+ protected final String attrName;
+
+ public AttrFilter(String attrName) {
+ this.attrName = attrName.toString();
+ }
+
+ /** Subclasses may override this to implement better value tests.
+ * By default, it returns true for any non-null value, thus
+ * recognizing any attribute of the given name, regardless of value.
+ */
+ public boolean test(String attrVal) {
+ return attrVal != null; // override this
+ }
+
+ @Override
+ public final Element filter(Element elem) {
+ return test(elem.getAttr(attrName)) ? elem : null;
+ }
+
+ @Override
+ public String toString() {
+ return "<AttrFilter name='" + attrName + "' value='*'/>";
+ }
+ }
+
+ public static Filter attrFilter(String attrName) {
+ return new AttrFilter(attrName);
+ }
+
+ public static Filter attrFilter(String attrName, final String attrVal) {
+ if (attrVal == null) {
+ return not(attrFilter(attrName));
+ }
+ return new AttrFilter(attrName) {
+
+ @Override
+ public boolean test(String attrVal2) {
+ return attrVal.equals(attrVal2);
+ }
+
+ @Override
+ public String toString() {
+ return "<AttrFilter name='" + attrName + "' value='" + attrVal + "'/>";
+ }
+ };
+ }
+
+ public static Filter attrFilter(Element matchThis, String attrName) {
+ return attrFilter(attrName, matchThis.getAttr(attrName));
+ }
+
+ /** Use this to find a sub-element of a given class. */
+ public static Filter classFilter(final Class clazz) {
+ return new Filter() {
+
+ public Object filter(Object value) {
+ return clazz.isInstance(value) ? value : null;
+ }
+
+ @Override
+ public String toString() {
+ return "<ClassFilter class='" + clazz.getName() + "'/>";
+ }
+ };
+ }
+ private static Filter textFilter;
+
+ public static Filter textFilter() {
+ return (textFilter != null) ? textFilter : (textFilter = classFilter(CharSequence.class));
+ }
+ private static Filter specialFilter;
+
+ public static Filter specialFilter() {
+ return (specialFilter != null) ? specialFilter : (specialFilter = classFilter(Special.class));
+ }
+ private static Filter selfFilter;
+
+ /** This filter always returns its own argument. */
+ public static Filter selfFilter() {
+ if (selfFilter != null) {
+ return selfFilter;
+ }
+ return selfFilter = new Filter() {
+
+ public Object filter(Object value) {
+ return value;
+ }
+
+ @Override
+ public String toString() {
+ return "<Self/>";
+ }
+ };
+ }
+
+ /** This filter always returns a fixed value, regardless of argument. */
+ public static Filter constantFilter(final Object value) {
+ return new Filter() {
+
+ public Object filter(Object ignore) {
+ return value;
+ }
+
+ @Override
+ public String toString() {
+ return "<Constant>" + value + "</Constant>";
+ }
+ };
+ }
+ private static Filter nullFilter;
+
+ public static Filter nullFilter() {
+ return (nullFilter != null) ? nullFilter : (nullFilter = constantFilter(null));
+ }
+ private static Filter emptyFilter;
+
+ public static Filter emptyFilter() {
+ return (emptyFilter != null) ? emptyFilter : (emptyFilter = constantFilter(Element.EMPTY));
+ }
+
+ /** Use this to invert the logical sense of the given filter. */
+ public static Filter not(final Filter f) {
+ return new Filter() {
+
+ public Object filter(Object value) {
+ return f.filter(value) == null ? value : null;
+ }
+
+ @Override
+ public String toString() {
+ return "<Not>" + f + "</Not>";
+ }
+ };
+ }
+
+ /** Use this to combine several filters with logical AND.
+ * Returns either the first null or the last non-null value.
+ */
+ public static Filter and(final Filter f0, final Filter f1) {
+ return and(new Filter[]{f0, f1});
+ }
+
+ public static Filter and(final Filter... fs) {
+ switch (fs.length) {
+ case 0:
+ return selfFilter(); // always true (on non-null inputs)
+ case 1:
+ return fs[0];
+ }
+ return new Filter() {
+
+ public Object filter(Object value) {
+ Object res = fs[0].filter(value);
+ if (res != null) {
+ res = fs[1].filter(value);
+ for (int i = 2; res != null && i < fs.length; i++) {
+ res = fs[i].filter(value);
+ }
+ }
+ return res;
+ }
+
+ @Override
+ public String toString() {
+ return opToString("<And>", fs, "</And>");
+ }
+ };
+ }
+
+ /** Use this to combine several filters with logical OR.
+ * Returns either the first non-null or the last null value.
+ */
+ public static Filter or(final Filter f0, final Filter f1) {
+ return or(new Filter[]{f0, f1});
+ }
+
+ public static Filter or(final Filter... fs) {
+ switch (fs.length) {
+ case 0:
+ return nullFilter();
+ case 1:
+ return fs[0];
+ }
+ return new Filter() {
+
+ public Object filter(Object value) {
+ Object res = fs[0].filter(value);
+ if (res == null) {
+ res = fs[1].filter(value);
+ for (int i = 2; res == null && i < fs.length; i++) {
+ res = fs[i].filter(value);
+ }
+ }
+ return res;
+ }
+
+ @Override
+ public String toString() {
+ return opToString("<Or>", fs, "</Or>");
+ }
+ };
+ }
+
+ /** Use this to combine several filters with logical AND,
+ * and where each non-null result is passed as the argument
+ * to the next filter.
+ * Returns either the first null or the last non-null value.
+ */
+ public static Filter stack(final Filter f0, final Filter f1) {
+ return stack(new Filter[]{f0, f1});
+ }
+
+ public static Filter stack(final Filter... fs) {
+ switch (fs.length) {
+ case 0:
+ return nullFilter();
+ case 1:
+ return fs[0];
+ }
+ return new Filter() {
+
+ public Object filter(Object value) {
+ Object res = fs[0].filter(value);
+ if (res != null) {
+ res = fs[1].filter(res);
+ for (int i = 2; res != null && i < fs.length; i++) {
+ res = fs[i].filter(res);
+ }
+ }
+ return res;
+ }
+
+ @Override
+ public String toString() {
+ return opToString("<Stack>", fs, "</Stack>");
+ }
+ };
+ }
+
+ /** Copy everything produced by f to sink, using addContent. */
+ public static Filter content(final Filter f, final Collection<Object> sink) {
+ return new Filter() {
+
+ public Object filter(Object value) {
+ Object res = f.filter(value);
+ addContent(res, sink);
+ return res;
+ }
+
+ @Override
+ public String toString() {
+ return opToString("<addContent>", new Object[]{f, sink},
+ "</addContent>");
+ }
+ };
+ }
+
+ /** Look down the tree using f, collecting fx, else recursing into x.
+ * Identities:
+ * <code>
+ * findInTree(f, s) == findInTree(content(f, s))
+ * findInTree(f) == replaceInTree(and(f, selfFilter())).
+ * </code>
+ */
+ public static Filter findInTree(Filter f, Collection<Object> sink) {
+ if (sink != null) {
+ f = content(f, sink);
+ }
+ return findInTree(f);
+ }
+
+ /** Look down the tree using f, recursing into x unless fx. */
+ public static Filter findInTree(final Filter f) {
+ return new Filter() {
+
+ public Object filter(Object value) {
+ Object res = f.filter(value);
+ if (res != null) {
+ return res;
+ }
+ if (value instanceof Element) {
+ // recurse
+ return ((Element) value).find(this);
+ }
+ return null;
+ }
+
+ @Override
+ public String toString() {
+ return opToString("<FindInTree>", new Object[]{f},
+ "</FindInTree>");
+ }
+ };
+ }
+
+ /** Look down the tree using f. Replace each x with fx, else recurse.
+ * If post filter g is given, optionally replace with gx after recursion.
+ */
+ public static Filter replaceInTree(final Filter f, final Filter g) {
+ return new Filter() {
+
+ public Object filter(Object value) {
+ Object res = (f == null) ? null : f.filter(value);
+ if (res != null) {
+ return res;
+ }
+ if (value instanceof Element) {
+ // recurse
+ ((Element) value).replaceAll(this);
+ // Optional postorder traversal:
+ if (g != null) {
+ res = g.filter(value);
+ }
+ }
+ return res; // usually null, meaning no replacement
+ }
+
+ @Override
+ public String toString() {
+ return opToString("<ReplaceInTree>",
+ new Object[]{f, g},
+ "</ReplaceInTree>");
+ }
+ };
+ }
+
+ public static Filter replaceInTree(Filter f) {
+ f.getClass(); // null check
+ return replaceInTree(f, null);
+ }
+
+ /** Make a filter which calls this method on the given element.
+ * If the method is static, the first argument is passed the
+ * the subtree value being filtered.
+ * If the method is non-static, the receiver is the subtree value itself.
+ * <p>
+ * Optionally, additional arguments may be specified.
+ * <p>
+ * If the filtered value does not match the receiver class
+ * (or else the first argument type, if the method is static),
+ * the filter returns null without invoking the method.
+ * <p>
+ * The returned filter value is the result returned from the method.
+ * Optionally, a non-null special false result value may be specified.
+ * If the result returned from the method is equal to that false value,
+ * the filter will return null.
+ */
+ public static Filter methodFilter(java.lang.reflect.Method m, Object[] extraArgs,
+ Object falseResult) {
+ return methodFilter(m, false, extraArgs, falseResult);
+ }
+
+ public static Filter methodFilter(java.lang.reflect.Method m,
+ Object[] args) {
+ return methodFilter(m, args, null);
+ }
+
+ public static Filter methodFilter(java.lang.reflect.Method m) {
+ return methodFilter(m, null, null);
+ }
+
+ public static Filter testMethodFilter(java.lang.reflect.Method m, Object[] extraArgs,
+ Object falseResult) {
+ return methodFilter(m, true, extraArgs, falseResult);
+ }
+
+ public static Filter testMethodFilter(java.lang.reflect.Method m, Object[] extraArgs) {
+ return methodFilter(m, true, extraArgs, zeroArgs.get(m.getReturnType()));
+ }
+
+ public static Filter testMethodFilter(java.lang.reflect.Method m) {
+ return methodFilter(m, true, null, zeroArgs.get(m.getReturnType()));
+ }
+
+ private static Filter methodFilter(final java.lang.reflect.Method m,
+ final boolean isTest,
+ Object[] extraArgs, final Object falseResult) {
+ Class[] params = m.getParameterTypes();
+ final boolean isStatic = java.lang.reflect.Modifier.isStatic(m.getModifiers());
+ int insertLen = (isStatic ? 1 : 0);
+ if (insertLen + (extraArgs == null ? 0 : extraArgs.length) > params.length) {
+ throw new IllegalArgumentException("too many arguments");
+ }
+ final Object[] args = (params.length == insertLen) ? null
+ : new Object[params.length];
+ final Class valueType = !isStatic ? m.getDeclaringClass() : params[0];
+ if (valueType.isPrimitive()) {
+ throw new IllegalArgumentException("filtered value must be reference type");
+ }
+ int fillp = insertLen;
+ if (extraArgs != null) {
+ for (int i = 0; i < extraArgs.length; i++) {
+ args[fillp++] = extraArgs[i];
+ }
+ }
+ if (args != null) {
+ while (fillp < args.length) {
+ Class param = params[fillp];
+ args[fillp++] = param.isPrimitive() ? zeroArgs.get(param) : null;
+ }
+ }
+ final Thread curt = Thread.currentThread();
+ class MFilt implements Filter {
+
+ public Object filter(Object value) {
+ if (!valueType.isInstance(value)) {
+ return null; // filter fails quickly
+ }
+ Object[] args1 = args;
+ if (isStatic) {
+ if (args1 == null) {
+ args1 = new Object[1];
+ } else if (curt != Thread.currentThread()) // Dirty hack to curtail array copying in common case.
+ {
+ args1 = (Object[]) args1.clone();
+ }
+ args1[0] = value;
+ }
+ Object res;
+ try {
+ res = m.invoke(value, args1);
+ } catch (java.lang.reflect.InvocationTargetException te) {
+ Throwable ee = te.getCause();
+ if (ee instanceof RuntimeException) {
+ throw (RuntimeException) ee;
+ }
+ if (ee instanceof Error) {
+ throw (Error) ee;
+ }
+ throw new RuntimeException("throw in filter", ee);
+ } catch (IllegalAccessException ee) {
+ throw new RuntimeException("access error in filter", ee);
+ }
+ if (res == null) {
+ if (!isTest && m.getReturnType() == Void.TYPE) {
+ // Void methods return self by convention.
+ // (But void "tests" always return false.)
+ res = value;
+ }
+ } else {
+ if (falseResult != null && falseResult.equals(res)) {
+ res = null;
+ } else if (isTest) {
+ // Tests return self by convention.
+ res = value;
+ }
+ }
+ return res;
+ }
+
+ @Override
+ public String toString() {
+ return "<Method>" + m + "</Method>";
+ }
+ }
+ return new MFilt();
+ }
+ private static HashMap<Class, Object> zeroArgs = new HashMap<Class, Object>();
+
+ static {
+ zeroArgs.put(Boolean.TYPE, Boolean.FALSE);
+ zeroArgs.put(Character.TYPE, new Character((char) 0));
+ zeroArgs.put(Byte.TYPE, new Byte((byte) 0));
+ zeroArgs.put(Short.TYPE, new Short((short) 0));
+ zeroArgs.put(Integer.TYPE, new Integer(0));
+ zeroArgs.put(Float.TYPE, new Float(0));
+ zeroArgs.put(Long.TYPE, new Long(0));
+ zeroArgs.put(Double.TYPE, new Double(0));
+ }
+
+ private static String opToString(String s1, Object[] s2, String s3) {
+ StringBuilder buf = new StringBuilder(s1);
+ for (int i = 0; i < s2.length; i++) {
+ if (s2[i] != null) {
+ buf.append(s2[i]);
+ }
+ }
+ buf.append(s3);
+ return buf.toString();
+ }
+
+ /** Call the filter on each list element x, and replace x with the
+ * resulting filter value e, or its parts.
+ * If e is null, keep x. (This eases use of partial-domain filters.)
+ * If e is a TokenList or an anonymous Element, add e's parts
+ * to the list instead of x.
+ * Otherwise, replace x by e.
+ * <p>
+ * The effect at each list position <code>n</code> may be expressed
+ * in terms of XMLKit.addContent as follows:
+ * <pre>
+ * Object e = f.filter(target.get(n));
+ * if (e != null) {
+ * target.remove(n);
+ * addContent(e, target.subList(n,n));
+ * }
+ * </pre>
+ * <p>
+ * Note: To force deletion of x, simply have the filter return
+ * Element.EMPTY or TokenList.EMPTY.
+ * To force null filter values to have this effect,
+ * use the expression: <code>or(f, emptyFilter())</code>.
+ */
+ public static void replaceAll(Filter f, List<Object> target) {
+ for (ListIterator<Object> i = target.listIterator(); i.hasNext();) {
+ Object x = i.next();
+ Object fx = f.filter(x);
+ if (fx == null) {
+ // Unliked addContent, a null is a no-op here.
+ // i.remove();
+ } else if (fx instanceof TokenList) {
+ TokenList tl = (TokenList) fx;
+ if (tl.size() == 1) {
+ i.set(tl);
+ } else {
+ i.remove();
+ for (String part : tl) {
+ i.add(part);
+ }
+ }
+ } else if (fx instanceof Element
+ && ((Element) fx).isAnonymous()) {
+ Element anon = (Element) fx;
+ if (anon.size() == 1) {
+ i.set(anon);
+ } else {
+ i.remove();
+ for (Object part : anon) {
+ i.add(part);
+ }
+ }
+ } else if (x != fx) {
+ i.set(fx);
+ }
+ }
+ }
+
+ /** If e is null, return zero.
+ * If e is a TokenList or an anonymous Element, add e's parts
+ * to the collection, and return the number of parts.
+ * Otherwise, add e to the collection, and return one.
+ * If the collection reference is null, the result is as if
+ * a throwaway collection were used.
+ */
+ public static int addContent(Object e, Collection<Object> sink) {
+ if (e == null) {
+ return 0;
+ } else if (e instanceof TokenList) {
+ TokenList tl = (TokenList) e;
+ if (sink != null) {
+ sink.addAll(tl);
+ }
+ return tl.size();
+ } else if (e instanceof Element
+ && ((Element) e).isAnonymous()) {
+ Element anon = (Element) e;
+ if (sink != null) {
+ sink.addAll(anon.asList());
+ }
+ return anon.size();
+ } else {
+ if (sink != null) {
+ sink.add(e);
+ }
+ return 1;
+ }
+ }
+
+ static Collection<Object> newCounterColl() {
+ return new AbstractCollection<Object>() {
+
+ int size;
+
+ public int size() {
+ return size;
+ }
+
+ @Override
+ public boolean add(Object o) {
+ ++size;
+ return true;
+ }
+
+ public Iterator<Object> iterator() {
+ throw new UnsupportedOperationException();
+ }
+ };
+ }
+
+ /** SAX2 document handler for building Element trees. */
+ private static class Builder implements ContentHandler, LexicalHandler {
+ /*, EntityResolver, DTDHandler, ErrorHandler*/
+
+ Collection<Object> sink;
+ boolean makeFrozen;
+ boolean tokenizing;
+
+ Builder(Collection<Object> sink, boolean tokenizing, boolean makeFrozen) {
+ this.sink = sink;
+ this.tokenizing = tokenizing;
+ this.makeFrozen = makeFrozen;
+ }
+ Object[] parts = new Object[30];
+ int nparts = 0;
+ int[] attrBases = new int[10]; // index into parts
+ int[] elemBases = new int[10]; // index into parts
+ int depth = -1; // index into attrBases, elemBases
+ // Parts is organized this way:
+ // | name0 | akey aval ... | subelem ... | name1 | ... |
+ // The position of the first "akey" after name0 is attrBases[0].
+ // The position of the first "subelem" after name0 is elemBases[0].
+ // The position after the last part is always nparts.
+ int mergeableToken = -1; // index into parts of recent CharSequence
+ boolean inCData = false;
+
+ void addPart(Object x) {
+ //System.out.println("addPart "+x);
+ if (nparts == parts.length) {
+ Object[] newParts = new Object[parts.length * 2];
+ System.arraycopy(parts, 0, newParts, 0, parts.length);
+ parts = newParts;
+ }
+ parts[nparts++] = x;
+ }
+
+ Object getMergeableToken() {
+ if (mergeableToken == nparts - 1) {
+ assert (parts[mergeableToken] instanceof CharSequence);
+ return parts[nparts - 1];
+ } else {
+ return null;
+ }
+ }
+
+ void clearMergeableToken() {
+ if (mergeableToken >= 0) {
+ // Freeze temporary StringBuffers into strings.
+ assert (parts[mergeableToken] instanceof CharSequence);
+ parts[mergeableToken] = parts[mergeableToken].toString();
+ mergeableToken = -1;
+ }
+ }
+
+ void setMergeableToken() {
+ if (mergeableToken != nparts - 1) {
+ clearMergeableToken();
+ mergeableToken = nparts - 1;
+ assert (parts[mergeableToken] instanceof CharSequence);
+ }
+ }
+
+ // ContentHandler callbacks
+ public void startElement(String ns, String localName, String name, Attributes atts) {
+ clearMergeableToken();
+ addPart(name.intern());
+ ++depth;
+ if (depth == attrBases.length) {
+ int oldlen = depth;
+ int newlen = depth * 2;
+ int[] newAB = new int[newlen];
+ int[] newEB = new int[newlen];
+ System.arraycopy(attrBases, 0, newAB, 0, oldlen);
+ System.arraycopy(elemBases, 0, newEB, 0, oldlen);
+ attrBases = newAB;
+ elemBases = newEB;
+ }
+ attrBases[depth] = nparts;
+ // Collect attributes.
+ int na = atts.getLength();
+ for (int k = 0; k < na; k++) {
+ addPart(atts.getQName(k).intern());
+ addPart(atts.getValue(k));
+ }
+ // Get ready to collect elements.
+ elemBases[depth] = nparts;
+ }
+
+ public void endElement(String ns, String localName, String name) {
+ assert (depth >= 0);
+ clearMergeableToken();
+ int ebase = elemBases[depth];
+ int elen = nparts - ebase;
+ int abase = attrBases[depth];
+ int alen = ebase - abase;
+ int nbase = abase - 1;
+ int cap = alen + (makeFrozen ? 0 : NEED_SLOP) + elen;
+ Element e = new Element((String) parts[nbase], elen, cap);
+ // Set up attributes.
+ for (int k = 0; k < alen; k += 2) {
+ e.parts[cap - k - 2] = parts[abase + k + 0];
+ e.parts[cap - k - 1] = parts[abase + k + 1];
+ }
+ // Set up sub-elements.
+ System.arraycopy(parts, ebase, e.parts, 0, elen);
+ // Back out of this level.
+ --depth;
+ nparts = nbase;
+ assert (e.isFrozen() == makeFrozen);
+ assert (e.size() == elen);
+ assert (e.attrSize() * 2 == alen);
+ if (depth >= 0) {
+ addPart(e);
+ } else {
+ sink.add(e);
+ }
+ }
+
+ public void startCDATA() {
+ inCData = true;
+ }
+
+ public void endCDATA() {
+ inCData = false;
+ }
+
+ public void characters(char[] buf, int off, int len) {
+ boolean headSpace = false;
+ boolean tailSpace = false;
+ int firstLen;
+ if (tokenizing && !inCData) {
+ // Strip unquoted blanks.
+ while (len > 0 && isWhitespace(buf[off])) {
+ headSpace = true;
+ ++off;
+ --len;
+ }
+ if (len == 0) {
+ tailSpace = true; // it is all space
+ }
+ while (len > 0 && isWhitespace(buf[off + len - 1])) {
+ tailSpace = true;
+ --len;
+ }
+ firstLen = 0;
+ while (firstLen < len && !isWhitespace(buf[off + firstLen])) {
+ ++firstLen;
+ }
+ } else {
+ firstLen = len;
+ }
+ if (headSpace) {
+ clearMergeableToken();
+ }
+ boolean mergeAtEnd = !tailSpace;
+ // If buffer was empty, or had only ignorable blanks, do nothing.
+ if (len == 0) {
+ return;
+ }
+ // Decide whether to merge some of these chars into a previous token.
+ Object prev = getMergeableToken();
+ if (prev instanceof StringBuffer) {
+ ((StringBuffer) prev).append(buf, off, firstLen);
+ } else if (prev == null) {
+ addPart(new String(buf, off, firstLen));
+ } else {
+ // Merge two strings.
+ String prevStr = prev.toString();
+ StringBuffer prevBuf = new StringBuffer(prevStr.length() + firstLen);
+ prevBuf.append(prevStr);
+ prevBuf.append(buf, off, firstLen);
+ if (mergeAtEnd && len == firstLen) {
+ // Replace previous string with new StringBuffer.
+ parts[nparts - 1] = prevBuf;
+ } else {
+ // Freeze it now.
+ parts[nparts - 1] = prevBuf.toString();
+ }
+ }
+ off += firstLen;
+ len -= firstLen;
+ if (len > 0) {
+ // Appended only the first token.
+ clearMergeableToken();
+ // Add the rest as separate parts.
+ while (len > 0) {
+ while (len > 0 && isWhitespace(buf[off])) {
+ ++off;
+ --len;
+ }
+ int nextLen = 0;
+ while (nextLen < len && !isWhitespace(buf[off + nextLen])) {
+ ++nextLen;
+ }
+ assert (nextLen > 0);
+ addPart(new String(buf, off, nextLen));
+ off += nextLen;
+ len -= nextLen;
+ }
+ }
+ if (mergeAtEnd) {
+ setMergeableToken();
+ }
+ }
+
+ public void ignorableWhitespace(char[] buf, int off, int len) {
+ clearMergeableToken();
+ if (false) {
+ characters(buf, off, len);
+ clearMergeableToken();
+ }
+ }
+
+ public void comment(char[] buf, int off, int len) {
+ addPart(new Special("<!-- -->", new String(buf, off, len)));
+ }
+
+ public void processingInstruction(String name, String instruction) {
+ Element pi = new Element(name);
+ pi.add(instruction);
+ addPart(new Special("<? ?>", pi));
+ }
+
+ public void skippedEntity(String name) {
+ }
+
+ public void startDTD(String name, String publicId, String systemId) {
+ }
+
+ public void endDTD() {
+ }
+
+ public void startEntity(String name) {
+ }
+
+ public void endEntity(String name) {
+ }
+
+ public void setDocumentLocator(org.xml.sax.Locator locator) {
+ }
+
+ public void startDocument() {
+ }
+
+ public void endDocument() {
+ }
+
+ public void startPrefixMapping(String prefix, String uri) {
+ }
+
+ public void endPrefixMapping(String prefix) {
+ }
+ }
+
+ /** Produce a ContentHandler for use with an XML parser.
+ * The object is <em>also</em> a LexicalHandler.
+ * Every top-level Element produced will get added to sink.
+ * All elements will be frozen iff makeFrozen is true.
+ */
+ public static ContentHandler makeBuilder(Collection<Object> sink, boolean tokenizing, boolean makeFrozen) {
+ return new Builder(sink, tokenizing, makeFrozen);
+ }
+
+ public static ContentHandler makeBuilder(Collection<Object> sink, boolean tokenizing) {
+ return new Builder(sink, tokenizing, false);
+ }
+
+ public static ContentHandler makeBuilder(Collection<Object> sink) {
+ return makeBuilder(sink, false, false);
+ }
+
+ public static Element readFrom(Reader in, boolean tokenizing, boolean makeFrozen) throws IOException {
+ Element sink = new Element();
+ ContentHandler b = makeBuilder(sink.asList(), tokenizing, makeFrozen);
+ XMLReader parser;
+ try {
+ parser = org.xml.sax.helpers.XMLReaderFactory.createXMLReader();
+ } catch (SAXException ee) {
+ throw new Error(ee);
+ }
+ //parser.setFastStandalone(true);
+ parser.setContentHandler(b);
+ try {
+ parser.setProperty("http://xml.org/sax/properties/lexical-handler",
+ (LexicalHandler) b);
+ } catch (SAXException ee) {
+ // Ignore. We will miss the comments and whitespace.
+ }
+ try {
+ parser.parse(new InputSource(in));
+ } catch (SAXParseException ee) {
+ throw new RuntimeException("line " + ee.getLineNumber() + " col " + ee.getColumnNumber() + ": ", ee);
+ } catch (SAXException ee) {
+ throw new RuntimeException(ee);
+ }
+ switch (sink.size()) {
+ case 0:
+ return null;
+ case 1:
+ if (sink.get(0) instanceof Element) {
+ return (Element) sink.get(0);
+ }
+ // fall through
+ default:
+ if (makeFrozen) {
+ sink.shallowFreeze();
+ }
+ return sink;
+ }
+ }
+
+ public static Element readFrom(Reader in, boolean tokenizing) throws IOException {
+ return readFrom(in, tokenizing, false);
+ }
+
+ public static Element readFrom(Reader in) throws IOException {
+ return readFrom(in, false, false);
+ }
+
+ public static void prettyPrintTo(OutputStream out, Element e) throws IOException {
+ prettyPrintTo(new OutputStreamWriter(out), e);
+ }
+
+ public static void prettyPrintTo(Writer out, Element e) throws IOException {
+ Printer pr = new Printer(out);
+ pr.pretty = true;
+ pr.print(e);
+ }
+
+ static class Outputter {
+
+ ContentHandler ch;
+ LexicalHandler lh;
+
+ Outputter(ContentHandler ch, LexicalHandler lh) {
+ this.ch = ch;
+ this.lh = lh;
+ }
+ AttributesImpl atts = new AttributesImpl(); // handy
+
+ void output(Object x) throws SAXException {
+ // Cf. jdom.org/jdom-b8/src/java/org/jdom/output/SAXOutputter.java
+ if (x instanceof Element) {
+ Element e = (Element) x;
+ atts.clear();
+ for (int asize = e.attrSize(), k = 0; k < asize; k++) {
+ String key = e.getAttrName(k);
+ String val = e.getAttr(k);
+ atts.addAttribute("", "", key, "CDATA", val);
+ }
+ ch.startElement("", "", e.getName(), atts);
+ for (int i = 0; i < e.size(); i++) {
+ output(e.get(i));
+ }
+ ch.endElement("", "", e.getName());
+ } else if (x instanceof Special) {
+ Special sp = (Special) x;
+ if (sp.kind.startsWith("<!--")) {
+ char[] chars = sp.value.toString().toCharArray();
+ lh.comment(chars, 0, chars.length);
+ } else if (sp.kind.startsWith("<?")) {
+ Element nameInstr = (Element) sp.value;
+ ch.processingInstruction(nameInstr.name,
+ nameInstr.get(0).toString());
+ } else {
+ // drop silently
+ }
+ } else {
+ char[] chars = x.toString().toCharArray();
+ ch.characters(chars, 0, chars.length);
+ }
+ }
+ }
+
+ public static class Printer {
+
+ public Writer w;
+ public boolean tokenizing;
+ public boolean pretty;
+ public boolean abbreviated; // nonstandard format cuts down on noise
+ int depth = 0;
+ boolean prevStr;
+ int tabStop = 2;
+
+ public Printer(Writer w) {
+ this.w = w;
+ }
+
+ public Printer() {
+ StringWriter sw = new StringWriter();
+ this.w = sw;
+
+ }
+
+ public String nextString() {
+ StringBuffer sb = ((StringWriter) w).getBuffer();
+ String next = sb.toString();
+ sb.setLength(0); // reset
+ return next;
+ }
+
+ void indent(int depth) throws IOException {
+ if (depth > 0) {
+ w.write("\n");
+ }
+ int nsp = tabStop * depth;
+ while (nsp > 0) {
+ String s = " ";
+ String t = s.substring(0, nsp < s.length() ? nsp : s.length());
+ w.write(t);
+ nsp -= t.length();
+ }
+ }
+
+ public void print(Element e) throws IOException {
+ if (e.isAnonymous()) {
+ printParts(e);
+ return;
+ }
+ printRecursive(e);
+ }
+
+ public void println(Element e) throws IOException {
+ print(e);
+ w.write("\n");
+ w.flush();
+ }
+
+ public void printRecursive(Element e) throws IOException {
+ boolean indented = false;
+ if (pretty && !prevStr && e.size() + e.attrSize() > 0) {
+ indent(depth);
+ indented = true;
+ }
+ w.write("<");
+ w.write(e.name);
+ for (int asize = e.attrSize(), k = 0; k < asize; k++) {
+ String key = e.getAttrName(k);
+ String val = e.getAttr(k);
+ w.write(" ");
+ w.write(key);
+ w.write("=");
+ if (val == null) {
+ w.write("null"); // Should not happen....
+ } else if (val.indexOf("\"") < 0) {
+ w.write("\"");
+ writeToken(val, '"', w);
+ w.write("\"");
+ } else {
+ w.write("'");
+ writeToken(val, '\'', w);
+ w.write("'");
+ }
+ }
+ if (e.size() == 0) {
+ w.write("/>");
+ } else {
+ ++depth;
+ if (abbreviated) {
+ w.write("/");
+ } else {
+ w.write(">");
+ }
+ prevStr = false;
+ printParts(e);
+ if (abbreviated) {
+ w.write(">");
+ } else {
+ if (indented && !prevStr) {
+ indent(depth - 1);
+ }
+ w.write("</");
+ w.write(e.name);
+ w.write(">");
+ }
+ prevStr = false;
+ --depth;
+ }
+ }
+
+ private void printParts(Element e) throws IOException {
+ for (int i = 0; i < e.size(); i++) {
+ Object x = e.get(i);
+ if (x instanceof Element) {
+ printRecursive((Element) x);
+ prevStr = false;
+ } else if (x instanceof Special) {
+ w.write(((Special) x).toString());
+ prevStr = false;
+ } else {
+ String s = String.valueOf(x);
+ if (pretty) {
+ s = s.trim();
+ if (s.length() == 0) {
+ continue;
+ }
+ }
+ if (prevStr) {
+ w.write(' ');
+ }
+ writeToken(s, tokenizing ? ' ' : (char) -1, w);
+ prevStr = true;
+ }
+ if (pretty && depth == 0) {
+ w.write("\n");
+ prevStr = false;
+ }
+ }
+ }
+ }
+
+ public static void output(Object e, ContentHandler ch, LexicalHandler lh) throws SAXException {
+ new Outputter(ch, lh).output(e);
+ }
+
+ public static void output(Object e, ContentHandler ch) throws SAXException {
+ if (ch instanceof LexicalHandler) {
+ output(e, ch, (LexicalHandler) ch);
+ } else {
+ output(e, ch, null);
+ }
+ }
+
+ public static void writeToken(String val, char quote, Writer w) throws IOException {
+ int len = val.length();
+ boolean canUseCData = (quote != '"' && quote != '\'');
+ int vpos = 0;
+ for (int i = 0; i < len; i++) {
+ char ch = val.charAt(i);
+ if ((ch == '<' || ch == '&' || ch == '>' || ch == quote)
+ || (quote == ' ' && isWhitespace(ch))) {
+ if (canUseCData) {
+ assert (vpos == 0);
+ writeCData(val, w);
+ return;
+ } else {
+ if (vpos < i) {
+ w.write(val, vpos, i - vpos);
+ }
+ String esc;
+ switch (ch) {
+ case '&':
+ esc = "&";
+ break;
+ case '<':
+ esc = "<";
+ break;
+ case '\'':
+ esc = "'";
+ break;
+ case '"':
+ esc = """;
+ break;
+ case '>':
+ esc = ">";
+ break;
+ default:
+ esc = "&#" + (int) ch + ";";
+ break;
+ }
+ w.write(esc);
+ vpos = i + 1; // skip escaped char
+ }
+ }
+ }
+ // write the unquoted tail
+ w.write(val, vpos, val.length() - vpos);
+ }
+
+ public static void writeCData(String val, Writer w) throws IOException {
+ String begCData = "<![CDATA[";
+ String endCData = "]]>";
+ w.write(begCData);
+ for (int vpos = 0, split;; vpos = split) {
+ split = val.indexOf(endCData, vpos);
+ if (split < 0) {
+ w.write(val, vpos, val.length() - vpos);
+ w.write(endCData);
+ return;
+ }
+ split += 2; // bisect the "]]>" goo
+ w.write(val, vpos, split - vpos);
+ w.write(endCData);
+ w.write(begCData);
+ }
+ }
+
+ public static TokenList convertToList(String str) {
+ if (str == null) {
+ return null;
+ }
+ return new TokenList(str);
+ }
+
+ /** If str is null, empty, or blank, returns null.
+ * Otherwise, return a Double if str spells a double value and contains '.' or 'e'.
+ * Otherwise, return an Integer if str spells an int value.
+ * Otherwise, return a Long if str spells a long value.
+ * Otherwise, return a BigInteger for the string.
+ * Otherwise, throw NumberFormatException.
+ */
+ public static Number convertToNumber(String str) {
+ if (str == null) {
+ return null;
+ }
+ str = str.trim();
+ if (str.length() == 0) {
+ return null;
+ }
+ if (str.indexOf('.') >= 0
+ || str.indexOf('e') >= 0
+ || str.indexOf('E') >= 0) {
+ return Double.valueOf(str);
+ }
+ try {
+ long lval = Long.parseLong(str);
+ if (lval == (int) lval) {
+ // Narrow to Integer, if possible.
+ return new Integer((int) lval);
+ }
+ return new Long(lval);
+ } catch (NumberFormatException ee) {
+ // Could not represent it as a long.
+ return new java.math.BigInteger(str, 10);
+ }
+ }
+
+ public static Number convertToNumber(String str, Number dflt) {
+ Number n = convertToNumber(str);
+ return (n == null) ? dflt : n;
+ }
+
+ public static long convertToLong(String str) {
+ return convertToLong(str, 0);
+ }
+
+ public static long convertToLong(String str, long dflt) {
+ Number n = convertToNumber(str);
+ return (n == null) ? dflt : n.longValue();
+ }
+
+ public static double convertToDouble(String str) {
+ return convertToDouble(str, 0);
+ }
+
+ public static double convertToDouble(String str, double dflt) {
+ Number n = convertToNumber(str);
+ return (n == null) ? dflt : n.doubleValue();
+ }
+
+ // Testing:
+ public static void main(String... av) throws Exception {
+ Element.method("getAttr");
+ //new org.jdom.input.SAXBuilder().build(file).getRootElement();
+ //jdom.org/jdom-b8/src/java/org/jdom/input/SAXBuilder.java
+ //Document build(InputSource in) throws JDOMException
+
+ int reps = 0;
+
+ boolean tokenizing = false;
+ boolean makeFrozen = false;
+ if (av.length > 0) {
+ tokenizing = true;
+ try {
+ reps = Integer.parseInt(av[0]);
+ } catch (NumberFormatException ee) {
+ }
+ }
+ Reader inR = new BufferedReader(new InputStreamReader(System.in));
+ String inS = null;
+ if (reps > 1) {
+ StringWriter inBufR = new StringWriter(1 << 14);
+ char[] cbuf = new char[1024];
+ for (int nr; (nr = inR.read(cbuf)) >= 0;) {
+ inBufR.write(cbuf, 0, nr);
+ }
+ inS = inBufR.toString();
+ inR = new StringReader(inS);
+ }
+ Element e = XMLKit.readFrom(inR, tokenizing, makeFrozen);
+ System.out.println("transform = " + e.findAll(methodFilter(Element.method("prettyString"))));
+ System.out.println("transform = " + e.findAll(testMethodFilter(Element.method("hasText"))));
+ long tm0 = 0;
+ int warmup = 10;
+ for (int i = 1; i < reps; i++) {
+ inR = new StringReader(inS);
+ readFrom(inR, tokenizing, makeFrozen);
+ if (i == warmup) {
+ System.out.println("Start timing...");
+ tm0 = System.currentTimeMillis();
+ }
+ }
+ if (tm0 != 0) {
+ long tm1 = System.currentTimeMillis();
+ System.out.println((reps - warmup) + " in " + (tm1 - tm0) + " ms");
+ }
+ System.out.println("hashCode = " + e.hashCode());
+ String eStr = e.toString();
+ System.out.println(eStr);
+ Element e2 = readFrom(new StringReader(eStr), tokenizing, !makeFrozen);
+ System.out.println("hashCode = " + e2.hashCode());
+ if (!e.equals(e2)) {
+ System.out.println("**** NOT EQUAL 1\n" + e2);
+ }
+ e = e.deepCopy();
+ System.out.println("hashCode = " + e.hashCode());
+ if (!e.equals(e2)) {
+ System.out.println("**** NOT EQUAL 2");
+ }
+ e2.shallowFreeze();
+ System.out.println("hashCode = " + e2.hashCode());
+ if (!e.equals(e2)) {
+ System.out.println("**** NOT EQUAL 3");
+ }
+ if (false) {
+ System.out.println(e);
+ } else {
+ prettyPrintTo(new OutputStreamWriter(System.out), e);
+ }
+ System.out.println("Flat text:|" + e.getFlatText() + "|");
+ {
+ System.out.println("<!--- Sorted: --->");
+ Element ce = e.copyContentOnly();
+ ce.sort();
+ prettyPrintTo(new OutputStreamWriter(System.out), ce);
+ }
+ {
+ System.out.println("<!--- Trimmed: --->");
+ Element tr = e.deepCopy();
+ findInTree(testMethodFilter(Element.method("trimText"))).filter(tr);
+ System.out.println(tr);
+ }
+ {
+ System.out.println("<!--- Unstrung: --->");
+ Element us = e.deepCopy();
+ int nr = us.retainAllInTree(elementFilter(), null);
+ System.out.println("nr=" + nr);
+ System.out.println(us);
+ }
+ {
+ System.out.println("<!--- Rollup: --->");
+ Element ru = e.deepCopy();
+ Filter makeAnonF =
+ methodFilter(Element.method("setName"),
+ new Object[]{ANON_NAME});
+ Filter testSizeF =
+ testMethodFilter(Element.method("size"));
+ Filter walk =
+ replaceInTree(and(not(elementFilter()), emptyFilter()),
+ and(testSizeF, makeAnonF));
+ ru = (Element) walk.filter(ru);
+ //System.out.println(ru);
+ prettyPrintTo(new OutputStreamWriter(System.out), ru);
+ }
+ }
+
+ static boolean isWhitespace(char c) {
+ switch (c) {
+ case 0x20:
+ case 0x09:
+ case 0x0D:
+ case 0x0A:
+ return true;
+ }
+ return false;
+ }
+}
--- a/make/jprt.properties Wed Sep 08 14:04:18 2010 -0700
+++ b/make/jprt.properties Wed Jul 05 17:21:22 2017 +0200
@@ -24,32 +24,12 @@
#
# Properties for jprt
-jprt.tools.default.release=jdk1.7.0
-
-# Specific platform list
-jprt.build.platforms= \
- solaris_sparc_5.10, \
- solaris_sparcv9_5.10, \
- solaris_i586_5.10, \
- solaris_x64_5.10, \
- linux_i586_2.6, \
- linux_x64_2.6, \
- windows_i586_5.0, \
- windows_x64_5.2
-# The different build flavors we want
+# Use whatever release that the submitted job requests
+jprt.tools.default.release=${jprt.submit.release}
+
+# The different build flavors we want, we override here so we just get these 2
jprt.build.flavors=product,fastdebug
-jprt.run.flavors=c1,c2
-jprt.solaris_sparcv9.run.flavors=c2
-jprt.solaris_x64.run.flavors=c2
-jprt.windows_x64.run.flavors=c2
-jprt.linux_x64.run.flavors=c2
-jprt.run.flavor.c1.option=-client
-jprt.run.flavor.c2.option=-server
-
-# Explicitly designate what the 32bit match is for the 64bit build
-jprt.solaris_sparcv9.build.platform.match32=solaris_sparc_5.10
-jprt.solaris_x64.build.platform.match32=solaris_i586_5.10
# Shortened list of vm tests
jprt.test.targets= \
@@ -89,6 +69,7 @@
# *-product-*-jdk_rmi
# *-product-*-jdk_swing
-# Directories to be excluded from source bundles
+# Directories to be excluded from the source bundles
jprt.bundle.exclude.src.dirs=build dist webrev
+