--- a/.hgtags-top-repo Thu Nov 17 10:46:00 2011 -0800
+++ b/.hgtags-top-repo Wed Jul 05 17:56:12 2017 +0200
@@ -135,3 +135,4 @@
1defbc57940a56f0aa41e9dee87b71e8c8b71103 jdk8-b11
8e2104d565baee473895d5eba20e39f85ab4bf9f jdk8-b12
26fb81a1e9ceb9baffba216acd9ded62e9e9d5ab jdk8-b13
+23aa7f2c80a2fa354c80decf03e7c2018177ef4e jdk8-b14
--- a/corba/.hgtags Thu Nov 17 10:46:00 2011 -0800
+++ b/corba/.hgtags Wed Jul 05 17:56:12 2017 +0200
@@ -135,3 +135,4 @@
0199e4fef5cc2bd234c65b93220459ef7a3bb3b1 jdk8-b11
31d70911b712c6b4e580a3110363d5f044cfed7a jdk8-b12
5b9d9b839d3d7fe02347827221c97c6d242a6f96 jdk8-b13
+e59c47de1ad8982ff3b0e843773a6902b36c2337 jdk8-b14
--- a/corba/src/share/classes/com/sun/corba/se/impl/encoding/CDRInputStream.java Thu Nov 17 10:46:00 2011 -0800
+++ b/corba/src/share/classes/com/sun/corba/se/impl/encoding/CDRInputStream.java Wed Jul 05 17:56:12 2017 +0200
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2000, 2004, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2000, 2011, 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
@@ -423,6 +423,13 @@
impl.setByteBufferWithInfo(bbwi);
}
+ /**
+ * return true if our ByteBuffer is sharing/equal to bb
+ */
+ protected final boolean isSharing(ByteBuffer bb) {
+ return (getByteBuffer() == bb);
+ }
+
public final int getBufferLength() {
return impl.getBufferLength();
}
--- a/corba/src/share/classes/com/sun/corba/se/impl/encoding/CDRInputStream_1_0.java Thu Nov 17 10:46:00 2011 -0800
+++ b/corba/src/share/classes/com/sun/corba/se/impl/encoding/CDRInputStream_1_0.java Wed Jul 05 17:56:12 2017 +0200
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997, 2004, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2011, 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
@@ -2412,7 +2412,6 @@
if (bbwi != null && getByteBuffer() != null)
{
- int bbHash = System.identityHashCode(bbwi.byteBuffer);
MessageMediator messageMediator = parent.getMessageMediator();
if (messageMediator != null)
{
@@ -2420,19 +2419,12 @@
(CDROutputObject)messageMediator.getOutputObject();
if (outputObj != null)
{
- ByteBuffer outputBb = outputObj.getByteBuffer();
-
- int oBbHash = 0;
- if (outputBb != null)
+ if (outputObj.isSharing(getByteBuffer()))
{
- oBbHash = System.identityHashCode(outputBb);
- if (bbHash == oBbHash) // shared?
- {
- // Set OutputStream's ByteBuffer and bbwi to null
- // so its ByteBuffer cannot be released to the pool
- outputObj.setByteBuffer(null);
- outputObj.setByteBufferWithInfo(null);
- }
+ // Set OutputStream's ByteBuffer and bbwi to null
+ // so its ByteBuffer cannot be released to the pool
+ outputObj.setByteBuffer(null);
+ outputObj.setByteBufferWithInfo(null);
}
}
}
--- a/corba/src/share/classes/com/sun/corba/se/impl/encoding/CDROutputStream.java Thu Nov 17 10:46:00 2011 -0800
+++ b/corba/src/share/classes/com/sun/corba/se/impl/encoding/CDROutputStream.java Wed Jul 05 17:56:12 2017 +0200
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2000, 2004, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2000, 2011, 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
@@ -357,6 +357,13 @@
impl.setByteBuffer(byteBuffer);
}
+ /**
+ * return true if our ByteBuffer is sharing/equal to bb
+ */
+ protected final boolean isSharing(ByteBuffer bb) {
+ return (getByteBuffer() == bb);
+ }
+
public final boolean isLittleEndian() {
return impl.isLittleEndian();
}
--- a/corba/src/share/classes/com/sun/corba/se/impl/encoding/CDROutputStream_1_0.java Thu Nov 17 10:46:00 2011 -0800
+++ b/corba/src/share/classes/com/sun/corba/se/impl/encoding/CDROutputStream_1_0.java Wed Jul 05 17:56:12 2017 +0200
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997, 2004, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2011, 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
@@ -1902,7 +1902,6 @@
if (getByteBufferWithInfo() != null && getByteBuffer() != null)
{
- int bbHash = System.identityHashCode(bbwi.byteBuffer);
MessageMediator messageMediator = parent.getMessageMediator();
if (messageMediator != null)
{
@@ -1910,19 +1909,12 @@
(CDRInputObject)messageMediator.getInputObject();
if (inputObj != null)
{
- ByteBuffer inputBb = inputObj.getByteBuffer();
-
- int iBbHash = 0;
- if (inputBb != null)
+ if (inputObj.isSharing(getByteBuffer()))
{
- iBbHash = System.identityHashCode(inputBb);
- if (bbHash == iBbHash) // shared?
- {
- // Set InputStream's ByteBuffer and bbwi to null
- // so its ByteBuffer cannot be released to the pool
- inputObj.setByteBuffer(null);
- inputObj.setByteBufferWithInfo(null);
- }
+ // Set InputStream's ByteBuffer and bbwi to null
+ // so its ByteBuffer cannot be released to the pool
+ inputObj.setByteBuffer(null);
+ inputObj.setByteBufferWithInfo(null);
}
}
}
--- a/hotspot/.hgtags Thu Nov 17 10:46:00 2011 -0800
+++ b/hotspot/.hgtags Wed Jul 05 17:56:12 2017 +0200
@@ -198,3 +198,5 @@
1d3900713a67a0a39faf4e12c9c158d55aebef87 jdk8-b12
3e609627e780736f372eb14d29bb9b5e53b21fbf hs23-b05
b92ca8e229d29004f840c67e620833d23a346761 jdk8-b13
+088d09a130ff02d8f5f05e92256baabe412f0439 jdk8-b14
+6c2a55d4902f202e1c2de1df17b7da083a2c31e8 hs23-b06
--- a/hotspot/agent/src/share/classes/sun/jvm/hotspot/tools/HeapSummary.java Thu Nov 17 10:46:00 2011 -0800
+++ b/hotspot/agent/src/share/classes/sun/jvm/hotspot/tools/HeapSummary.java Wed Jul 05 17:56:12 2017 +0200
@@ -30,6 +30,7 @@
import sun.jvm.hotspot.gc_implementation.parallelScavenge.*;
import sun.jvm.hotspot.gc_implementation.shared.*;
import sun.jvm.hotspot.memory.*;
+import sun.jvm.hotspot.oops.*;
import sun.jvm.hotspot.runtime.*;
public class HeapSummary extends Tool {
@@ -134,6 +135,9 @@
} else {
throw new RuntimeException("unknown CollectedHeap type : " + heap.getClass());
}
+
+ System.out.println();
+ printInternStringStatistics();
}
// Helper methods
@@ -248,4 +252,41 @@
return -1;
}
}
+
+ private void printInternStringStatistics() {
+ class StringStat implements StringTable.StringVisitor {
+ private int count;
+ private long size;
+ private OopField stringValueField;
+
+ StringStat() {
+ VM vm = VM.getVM();
+ SystemDictionary sysDict = vm.getSystemDictionary();
+ InstanceKlass strKlass = sysDict.getStringKlass();
+ // String has a field named 'value' of type 'char[]'.
+ stringValueField = (OopField) strKlass.findField("value", "[C");
+ }
+
+ private long stringSize(Instance instance) {
+ // We include String content in size calculation.
+ return instance.getObjectSize() +
+ stringValueField.getValue(instance).getObjectSize();
+ }
+
+ public void visit(Instance str) {
+ count++;
+ size += stringSize(str);
+ }
+
+ public void print() {
+ System.out.println(count +
+ " interned Strings occupying " + size + " bytes.");
+ }
+ }
+
+ StringStat stat = new StringStat();
+ StringTable strTable = VM.getVM().getStringTable();
+ strTable.stringsDo(stat);
+ stat.print();
+ }
}
--- a/hotspot/agent/src/share/classes/sun/jvm/hotspot/tools/PermStat.java Thu Nov 17 10:46:00 2011 -0800
+++ b/hotspot/agent/src/share/classes/sun/jvm/hotspot/tools/PermStat.java Wed Jul 05 17:56:12 2017 +0200
@@ -63,47 +63,9 @@
}
public void run() {
- printInternStringStatistics();
printClassLoaderStatistics();
}
- private void printInternStringStatistics() {
- class StringStat implements StringTable.StringVisitor {
- private int count;
- private long size;
- private OopField stringValueField;
-
- StringStat() {
- VM vm = VM.getVM();
- SystemDictionary sysDict = vm.getSystemDictionary();
- InstanceKlass strKlass = sysDict.getStringKlass();
- // String has a field named 'value' of type 'char[]'.
- stringValueField = (OopField) strKlass.findField("value", "[C");
- }
-
- private long stringSize(Instance instance) {
- // We include String content in size calculation.
- return instance.getObjectSize() +
- stringValueField.getValue(instance).getObjectSize();
- }
-
- public void visit(Instance str) {
- count++;
- size += stringSize(str);
- }
-
- public void print() {
- System.out.println(count +
- " intern Strings occupying " + size + " bytes.");
- }
- }
-
- StringStat stat = new StringStat();
- StringTable strTable = VM.getVM().getStringTable();
- strTable.stringsDo(stat);
- stat.print();
- }
-
private void printClassLoaderStatistics() {
final PrintStream out = System.out;
final PrintStream err = System.err;
--- a/hotspot/make/hotspot_version Thu Nov 17 10:46:00 2011 -0800
+++ b/hotspot/make/hotspot_version Wed Jul 05 17:56:12 2017 +0200
@@ -35,7 +35,7 @@
HS_MAJOR_VER=23
HS_MINOR_VER=0
-HS_BUILD_NUMBER=05
+HS_BUILD_NUMBER=06
JDK_MAJOR_VER=1
JDK_MINOR_VER=8
--- a/hotspot/make/jprt.properties Thu Nov 17 10:46:00 2011 -0800
+++ b/hotspot/make/jprt.properties Wed Jul 05 17:56:12 2017 +0200
@@ -541,9 +541,20 @@
${jprt.my.windows.i586}-*-c2-servertest, \
${jprt.my.windows.x64}-*-c2-servertest
+jprt.make.rule.test.targets.standard.internalvmtests = \
+ ${jprt.my.solaris.sparc}-fastdebug-c2-internalvmtests, \
+ ${jprt.my.solaris.sparcv9}-fastdebug-c2-internalvmtests, \
+ ${jprt.my.solaris.i586}-fastdebug-c2-internalvmtests, \
+ ${jprt.my.solaris.x64}-fastdebug-c2-internalvmtests, \
+ ${jprt.my.linux.i586}-fastdebug-c2-internalvmtests, \
+ ${jprt.my.linux.x64}-fastdebug-c2-internalvmtests, \
+ ${jprt.my.windows.i586}-fastdebug-c2-internalvmtests, \
+ ${jprt.my.windows.x64}-fastdebug-c2-internalvmtests
+
jprt.make.rule.test.targets.standard = \
${jprt.make.rule.test.targets.standard.client}, \
- ${jprt.make.rule.test.targets.standard.server}
+ ${jprt.make.rule.test.targets.standard.server}, \
+ ${jprt.make.rule.test.targets.standard.internalvmtests}
jprt.make.rule.test.targets.embedded = \
${jprt.make.rule.test.targets.standard.client}
--- a/hotspot/src/cpu/sparc/vm/assembler_sparc.inline.hpp Thu Nov 17 10:46:00 2011 -0800
+++ b/hotspot/src/cpu/sparc/vm/assembler_sparc.inline.hpp Wed Jul 05 17:56:12 2017 +0200
@@ -597,6 +597,10 @@
inline void MacroAssembler::jmp( Register s1, int simm13a, RelocationHolder const& rspec ) { jmpl( s1, simm13a, G0, rspec); }
inline bool MacroAssembler::is_far_target(address d) {
+ if (ForceUnreachable) {
+ // References outside the code cache should be treated as far
+ return d < CodeCache::low_bound() || d > CodeCache::high_bound();
+ }
return !is_in_wdisp30_range(d, CodeCache::low_bound()) || !is_in_wdisp30_range(d, CodeCache::high_bound());
}
@@ -679,28 +683,44 @@
inline void MacroAssembler::load_contents(const AddressLiteral& addrlit, Register d, int offset) {
assert_not_delayed();
- sethi(addrlit, d);
+ if (ForceUnreachable) {
+ patchable_sethi(addrlit, d);
+ } else {
+ sethi(addrlit, d);
+ }
ld(d, addrlit.low10() + offset, d);
}
inline void MacroAssembler::load_ptr_contents(const AddressLiteral& addrlit, Register d, int offset) {
assert_not_delayed();
- sethi(addrlit, d);
+ if (ForceUnreachable) {
+ patchable_sethi(addrlit, d);
+ } else {
+ sethi(addrlit, d);
+ }
ld_ptr(d, addrlit.low10() + offset, d);
}
inline void MacroAssembler::store_contents(Register s, const AddressLiteral& addrlit, Register temp, int offset) {
assert_not_delayed();
- sethi(addrlit, temp);
+ if (ForceUnreachable) {
+ patchable_sethi(addrlit, temp);
+ } else {
+ sethi(addrlit, temp);
+ }
st(s, temp, addrlit.low10() + offset);
}
inline void MacroAssembler::store_ptr_contents(Register s, const AddressLiteral& addrlit, Register temp, int offset) {
assert_not_delayed();
- sethi(addrlit, temp);
+ if (ForceUnreachable) {
+ patchable_sethi(addrlit, temp);
+ } else {
+ sethi(addrlit, temp);
+ }
st_ptr(s, temp, addrlit.low10() + offset);
}
--- a/hotspot/src/cpu/sparc/vm/c1_CodeStubs_sparc.cpp Thu Nov 17 10:46:00 2011 -0800
+++ b/hotspot/src/cpu/sparc/vm/c1_CodeStubs_sparc.cpp Wed Jul 05 17:56:12 2017 +0200
@@ -367,10 +367,10 @@
void DeoptimizeStub::emit_code(LIR_Assembler* ce) {
__ bind(_entry);
- __ call(SharedRuntime::deopt_blob()->unpack_with_reexecution());
+ __ call(Runtime1::entry_for(Runtime1::deoptimize_id), relocInfo::runtime_call_type);
__ delayed()->nop();
ce->add_call_info_here(_info);
- debug_only(__ should_not_reach_here());
+ DEBUG_ONLY(__ should_not_reach_here());
}
--- a/hotspot/src/cpu/sparc/vm/c1_LIRAssembler_sparc.cpp Thu Nov 17 10:46:00 2011 -0800
+++ b/hotspot/src/cpu/sparc/vm/c1_LIRAssembler_sparc.cpp Wed Jul 05 17:56:12 2017 +0200
@@ -1116,7 +1116,7 @@
} else {
__ set(value_hi, O7);
}
- offset = store(tmp, base, addr->disp() + hi_word_offset_in_bytes, T_INT, wide, false);
+ store(tmp, base, addr->disp() + hi_word_offset_in_bytes, T_INT, wide, false);
break;
}
case T_OBJECT: {
--- a/hotspot/src/cpu/sparc/vm/c1_Runtime1_sparc.cpp Thu Nov 17 10:46:00 2011 -0800
+++ b/hotspot/src/cpu/sparc/vm/c1_Runtime1_sparc.cpp Wed Jul 05 17:56:12 2017 +0200
@@ -766,7 +766,22 @@
__ ret();
__ delayed()->restore();
+ }
+ break;
+ case deoptimize_id:
+ {
+ __ set_info("deoptimize", dont_gc_arguments);
+ OopMap* oop_map = save_live_registers(sasm);
+ int call_offset = __ call_RT(noreg, noreg, CAST_FROM_FN_PTR(address, deoptimize));
+ oop_maps = new OopMapSet();
+ oop_maps->add_gc_map(call_offset, oop_map);
+ restore_live_registers(sasm);
+ DeoptimizationBlob* deopt_blob = SharedRuntime::deopt_blob();
+ assert(deopt_blob != NULL, "deoptimization blob must have been created");
+ AddressLiteral dest(deopt_blob->unpack_with_reexecution());
+ __ jump_to(dest, O0);
+ __ delayed()->restore();
}
break;
--- a/hotspot/src/cpu/sparc/vm/methodHandles_sparc.cpp Thu Nov 17 10:46:00 2011 -0800
+++ b/hotspot/src/cpu/sparc/vm/methodHandles_sparc.cpp Wed Jul 05 17:56:12 2017 +0200
@@ -352,6 +352,7 @@
BLOCK_COMMENT("load_stack_move {");
__ ldsw(G3_amh_conversion, stack_move_reg);
__ sra(stack_move_reg, CONV_STACK_MOVE_SHIFT, stack_move_reg);
+#ifdef ASSERT
if (VerifyMethodHandles) {
Label L_ok, L_bad;
int32_t stack_move_limit = 0x0800; // extra-large
@@ -363,6 +364,7 @@
__ stop("load_stack_move of garbage value");
__ BIND(L_ok);
}
+#endif
BLOCK_COMMENT("} load_stack_move");
}
--- a/hotspot/src/cpu/sparc/vm/methodHandles_sparc.hpp Thu Nov 17 10:46:00 2011 -0800
+++ b/hotspot/src/cpu/sparc/vm/methodHandles_sparc.hpp Wed Jul 05 17:56:12 2017 +0200
@@ -27,7 +27,7 @@
// Adapters
enum /* platform_dependent_constants */ {
- adapter_code_size = NOT_LP64(22000 DEBUG_ONLY(+ 40000)) LP64_ONLY(32000 DEBUG_ONLY(+ 80000))
+ adapter_code_size = NOT_LP64(23000 DEBUG_ONLY(+ 40000)) LP64_ONLY(35000 DEBUG_ONLY(+ 50000))
};
public:
--- a/hotspot/src/cpu/sparc/vm/sparc.ad Thu Nov 17 10:46:00 2011 -0800
+++ b/hotspot/src/cpu/sparc/vm/sparc.ad Wed Jul 05 17:56:12 2017 +0200
@@ -1860,6 +1860,14 @@
// Threshold size for cleararray.
const int Matcher::init_array_short_size = 8 * BytesPerLong;
+// No additional cost for CMOVL.
+const int Matcher::long_cmove_cost() { return 0; }
+
+// CMOVF/CMOVD are expensive on T4 and on SPARC64.
+const int Matcher::float_cmove_cost() {
+ return (VM_Version::is_T4() || VM_Version::is_sparc64()) ? ConditionalMoveLimit : 0;
+}
+
// Should the Matcher clone shifts on addressing modes, expecting them to
// be subsumed into complex addressing expressions or compute them into
// registers? True for Intel but false for most RISCs
--- a/hotspot/src/cpu/sparc/vm/vm_version_sparc.cpp Thu Nov 17 10:46:00 2011 -0800
+++ b/hotspot/src/cpu/sparc/vm/vm_version_sparc.cpp Wed Jul 05 17:56:12 2017 +0200
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2011, 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
@@ -211,7 +211,7 @@
#ifdef COMPILER2
// T4 and newer Sparc cpus have fast RDPC.
if (has_fast_rdpc() && FLAG_IS_DEFAULT(UseRDPCForConstantTableBase)) {
-// FLAG_SET_DEFAULT(UseRDPCForConstantTableBase, true);
+ FLAG_SET_DEFAULT(UseRDPCForConstantTableBase, true);
}
// Currently not supported anywhere.
--- a/hotspot/src/cpu/x86/vm/c1_CodeStubs_x86.cpp Thu Nov 17 10:46:00 2011 -0800
+++ b/hotspot/src/cpu/x86/vm/c1_CodeStubs_x86.cpp Wed Jul 05 17:56:12 2017 +0200
@@ -387,9 +387,9 @@
void DeoptimizeStub::emit_code(LIR_Assembler* ce) {
__ bind(_entry);
- __ call(RuntimeAddress(SharedRuntime::deopt_blob()->unpack_with_reexecution()));
+ __ call(RuntimeAddress(Runtime1::entry_for(Runtime1::deoptimize_id)));
ce->add_call_info_here(_info);
- debug_only(__ should_not_reach_here());
+ DEBUG_ONLY(__ should_not_reach_here());
}
--- a/hotspot/src/cpu/x86/vm/c1_Runtime1_x86.cpp Thu Nov 17 10:46:00 2011 -0800
+++ b/hotspot/src/cpu/x86/vm/c1_Runtime1_x86.cpp Wed Jul 05 17:56:12 2017 +0200
@@ -1447,7 +1447,22 @@
oop_maps = new OopMapSet();
oop_maps->add_gc_map(call_offset, map);
restore_live_registers(sasm, save_fpu_registers);
+ }
+ break;
+ case deoptimize_id:
+ {
+ StubFrame f(sasm, "deoptimize", dont_gc_arguments);
+ const int num_rt_args = 1; // thread
+ OopMap* oop_map = save_live_registers(sasm, num_rt_args);
+ int call_offset = __ call_RT(noreg, noreg, CAST_FROM_FN_PTR(address, deoptimize));
+ oop_maps = new OopMapSet();
+ oop_maps->add_gc_map(call_offset, oop_map);
+ restore_live_registers(sasm);
+ DeoptimizationBlob* deopt_blob = SharedRuntime::deopt_blob();
+ assert(deopt_blob != NULL, "deoptimization blob must have been created");
+ __ leave();
+ __ jump(RuntimeAddress(deopt_blob->unpack_with_reexecution()));
}
break;
--- a/hotspot/src/cpu/x86/vm/frame_x86.cpp Thu Nov 17 10:46:00 2011 -0800
+++ b/hotspot/src/cpu/x86/vm/frame_x86.cpp Wed Jul 05 17:56:12 2017 +0200
@@ -234,10 +234,12 @@
void frame::patch_pc(Thread* thread, address pc) {
address* pc_addr = &(((address*) sp())[-1]);
if (TracePcPatching) {
- tty->print_cr("patch_pc at address " INTPTR_FORMAT " [" INTPTR_FORMAT " -> " INTPTR_FORMAT "] ",
+ tty->print_cr("patch_pc at address " INTPTR_FORMAT " [" INTPTR_FORMAT " -> " INTPTR_FORMAT "]",
pc_addr, *pc_addr, pc);
}
- assert(_pc == *pc_addr, err_msg("must be: " INTPTR_FORMAT " == " INTPTR_FORMAT, _pc, *pc_addr));
+ // Either the return address is the original one or we are going to
+ // patch in the same address that's already there.
+ assert(_pc == *pc_addr || pc == *pc_addr, "must be");
*pc_addr = pc;
_cb = CodeCache::find_blob(pc);
address original_pc = nmethod::get_deopt_original_pc(this);
--- a/hotspot/src/cpu/x86/vm/methodHandles_x86.cpp Thu Nov 17 10:46:00 2011 -0800
+++ b/hotspot/src/cpu/x86/vm/methodHandles_x86.cpp Wed Jul 05 17:56:12 2017 +0200
@@ -382,6 +382,7 @@
__ movslq(rdi_stack_move, rdi_stack_move);
}
#endif //_LP64
+#ifdef ASSERT
if (VerifyMethodHandles) {
Label L_ok, L_bad;
int32_t stack_move_limit = 0x4000; // extra-large
@@ -393,6 +394,7 @@
__ stop("load_stack_move of garbage value");
__ BIND(L_ok);
}
+#endif
BLOCK_COMMENT("} load_stack_move");
}
--- a/hotspot/src/cpu/x86/vm/methodHandles_x86.hpp Thu Nov 17 10:46:00 2011 -0800
+++ b/hotspot/src/cpu/x86/vm/methodHandles_x86.hpp Wed Jul 05 17:56:12 2017 +0200
@@ -27,7 +27,7 @@
// Adapters
enum /* platform_dependent_constants */ {
- adapter_code_size = NOT_LP64(30000 DEBUG_ONLY(+ 10000)) LP64_ONLY(80000 DEBUG_ONLY(+ 120000))
+ adapter_code_size = NOT_LP64(16000 DEBUG_ONLY(+ 15000)) LP64_ONLY(32000 DEBUG_ONLY(+ 80000))
};
public:
--- a/hotspot/src/cpu/x86/vm/sharedRuntime_x86_64.cpp Thu Nov 17 10:46:00 2011 -0800
+++ b/hotspot/src/cpu/x86/vm/sharedRuntime_x86_64.cpp Wed Jul 05 17:56:12 2017 +0200
@@ -2797,17 +2797,25 @@
// void Deoptimization::unpack_frames(JavaThread* thread, int exec_mode)
// Use rbp because the frames look interpreted now
- __ set_last_Java_frame(noreg, rbp, NULL);
-
+ // Save "the_pc" since it cannot easily be retrieved using the last_java_SP after we aligned SP.
+ // Don't need the precise return PC here, just precise enough to point into this code blob.
+ address the_pc = __ pc();
+ __ set_last_Java_frame(noreg, rbp, the_pc);
+
+ __ andptr(rsp, -(StackAlignmentInBytes)); // Fix stack alignment as required by ABI
__ mov(c_rarg0, r15_thread);
__ movl(c_rarg1, r14); // second arg: exec_mode
__ call(RuntimeAddress(CAST_FROM_FN_PTR(address, Deoptimization::unpack_frames)));
+ // Revert SP alignment after call since we're going to do some SP relative addressing below
+ __ movptr(rsp, Address(r15_thread, JavaThread::last_Java_sp_offset()));
// Set an oopmap for the call site
- oop_maps->add_gc_map(__ pc() - start,
+ // Use the same PC we used for the last java frame
+ oop_maps->add_gc_map(the_pc - start,
new OopMap( frame_size_in_words, 0 ));
- __ reset_last_Java_frame(true, false);
+ // Clear fp AND pc
+ __ reset_last_Java_frame(true, true);
// Collect return values
__ movdbl(xmm0, Address(rsp, RegisterSaver::xmm0_offset_in_bytes()));
@@ -2968,7 +2976,10 @@
// Prolog
// Use rbp because the frames look interpreted now
- __ set_last_Java_frame(noreg, rbp, NULL);
+ // Save "the_pc" since it cannot easily be retrieved using the last_java_SP after we aligned SP.
+ // Don't need the precise return PC here, just precise enough to point into this code blob.
+ address the_pc = __ pc();
+ __ set_last_Java_frame(noreg, rbp, the_pc);
// Call C code. Need thread but NOT official VM entry
// crud. We cannot block on this call, no GC can happen. Call should
@@ -2977,14 +2988,17 @@
//
// BasicType unpack_frames(JavaThread* thread, int exec_mode);
+ __ andptr(rsp, -(StackAlignmentInBytes)); // Align SP as required by ABI
__ mov(c_rarg0, r15_thread);
__ movl(c_rarg1, Deoptimization::Unpack_uncommon_trap);
__ call(RuntimeAddress(CAST_FROM_FN_PTR(address, Deoptimization::unpack_frames)));
// Set an oopmap for the call site
- oop_maps->add_gc_map(__ pc() - start, new OopMap(SimpleRuntimeFrame::framesize, 0));
-
- __ reset_last_Java_frame(true, false);
+ // Use the same PC we used for the last java frame
+ oop_maps->add_gc_map(the_pc - start, new OopMap(SimpleRuntimeFrame::framesize, 0));
+
+ // Clear fp AND pc
+ __ reset_last_Java_frame(true, true);
// Pop self-frame.
__ leave(); // Epilog
--- a/hotspot/src/cpu/x86/vm/templateInterpreter_x86_32.cpp Thu Nov 17 10:46:00 2011 -0800
+++ b/hotspot/src/cpu/x86/vm/templateInterpreter_x86_32.cpp Wed Jul 05 17:56:12 2017 +0200
@@ -1609,6 +1609,12 @@
// and sender_sp is fp+8
intptr_t* locals = interpreter_frame->sender_sp() + max_locals - 1;
+#ifdef ASSERT
+ if (caller->is_interpreted_frame()) {
+ assert(locals < caller->fp() + frame::interpreter_frame_initial_sp_offset, "bad placement");
+ }
+#endif
+
interpreter_frame->interpreter_frame_set_locals(locals);
BasicObjectLock* montop = interpreter_frame->interpreter_frame_monitor_begin();
BasicObjectLock* monbot = montop - moncount;
--- a/hotspot/src/cpu/x86/vm/templateInterpreter_x86_64.cpp Thu Nov 17 10:46:00 2011 -0800
+++ b/hotspot/src/cpu/x86/vm/templateInterpreter_x86_64.cpp Wed Jul 05 17:56:12 2017 +0200
@@ -1622,6 +1622,12 @@
// sender_sp is fp+16 XXX
intptr_t* locals = interpreter_frame->sender_sp() + max_locals - 1;
+#ifdef ASSERT
+ if (caller->is_interpreted_frame()) {
+ assert(locals < caller->fp() + frame::interpreter_frame_initial_sp_offset, "bad placement");
+ }
+#endif
+
interpreter_frame->interpreter_frame_set_locals(locals);
BasicObjectLock* montop = interpreter_frame->interpreter_frame_monitor_begin();
BasicObjectLock* monbot = montop - moncount;
--- a/hotspot/src/cpu/x86/vm/x86_32.ad Thu Nov 17 10:46:00 2011 -0800
+++ b/hotspot/src/cpu/x86/vm/x86_32.ad Wed Jul 05 17:56:12 2017 +0200
@@ -1393,6 +1393,12 @@
// Threshold size for cleararray.
const int Matcher::init_array_short_size = 8 * BytesPerLong;
+// Needs 2 CMOV's for longs.
+const int Matcher::long_cmove_cost() { return 1; }
+
+// No CMOVF/CMOVD with SSE/SSE2
+const int Matcher::float_cmove_cost() { return (UseSSE>=1) ? ConditionalMoveLimit : 0; }
+
// Should the Matcher clone shifts on addressing modes, expecting them to
// be subsumed into complex addressing expressions or compute them into
// registers? True for Intel but false for most RISCs
@@ -7905,6 +7911,40 @@
//----------Conditional Move---------------------------------------------------
// Conditional move
+instruct jmovI_reg(cmpOp cop, eFlagsReg cr, eRegI dst, eRegI src) %{
+ predicate(!VM_Version::supports_cmov() );
+ match(Set dst (CMoveI (Binary cop cr) (Binary dst src)));
+ ins_cost(200);
+ format %{ "J$cop,us skip\t# signed cmove\n\t"
+ "MOV $dst,$src\n"
+ "skip:" %}
+ ins_encode %{
+ Label Lskip;
+ // Invert sense of branch from sense of CMOV
+ __ jccb((Assembler::Condition)($cop$$cmpcode^1), Lskip);
+ __ movl($dst$$Register, $src$$Register);
+ __ bind(Lskip);
+ %}
+ ins_pipe( pipe_cmov_reg );
+%}
+
+instruct jmovI_regU(cmpOpU cop, eFlagsRegU cr, eRegI dst, eRegI src) %{
+ predicate(!VM_Version::supports_cmov() );
+ match(Set dst (CMoveI (Binary cop cr) (Binary dst src)));
+ ins_cost(200);
+ format %{ "J$cop,us skip\t# unsigned cmove\n\t"
+ "MOV $dst,$src\n"
+ "skip:" %}
+ ins_encode %{
+ Label Lskip;
+ // Invert sense of branch from sense of CMOV
+ __ jccb((Assembler::Condition)($cop$$cmpcode^1), Lskip);
+ __ movl($dst$$Register, $src$$Register);
+ __ bind(Lskip);
+ %}
+ ins_pipe( pipe_cmov_reg );
+%}
+
instruct cmovI_reg(eRegI dst, eRegI src, eFlagsReg cr, cmpOp cop ) %{
predicate(VM_Version::supports_cmov() );
match(Set dst (CMoveI (Binary cop cr) (Binary dst src)));
--- a/hotspot/src/cpu/x86/vm/x86_64.ad Thu Nov 17 10:46:00 2011 -0800
+++ b/hotspot/src/cpu/x86/vm/x86_64.ad Wed Jul 05 17:56:12 2017 +0200
@@ -1993,6 +1993,12 @@
// Threshold size for cleararray.
const int Matcher::init_array_short_size = 8 * BytesPerLong;
+// No additional cost for CMOVL.
+const int Matcher::long_cmove_cost() { return 0; }
+
+// No CMOVF/CMOVD with SSE2
+const int Matcher::float_cmove_cost() { return ConditionalMoveLimit; }
+
// Should the Matcher clone shifts on addressing modes, expecting them
// to be subsumed into complex addressing expressions or compute them
// into registers? True for Intel but false for most RISCs
--- a/hotspot/src/share/vm/asm/codeBuffer.cpp Thu Nov 17 10:46:00 2011 -0800
+++ b/hotspot/src/share/vm/asm/codeBuffer.cpp Wed Jul 05 17:56:12 2017 +0200
@@ -26,6 +26,7 @@
#include "asm/codeBuffer.hpp"
#include "compiler/disassembler.hpp"
#include "utilities/copy.hpp"
+#include "utilities/xmlstream.hpp"
// The structure of a CodeSection:
//
@@ -81,7 +82,7 @@
CodeBuffer::CodeBuffer(CodeBlob* blob) {
initialize_misc("static buffer");
initialize(blob->content_begin(), blob->content_size());
- assert(verify_section_allocation(), "initial use of buffer OK");
+ verify_section_allocation();
}
void CodeBuffer::initialize(csize_t code_size, csize_t locs_size) {
@@ -108,17 +109,18 @@
_insts.initialize_locs(locs_size / sizeof(relocInfo));
}
- assert(verify_section_allocation(), "initial use of blob is OK");
+ verify_section_allocation();
}
CodeBuffer::~CodeBuffer() {
+ verify_section_allocation();
+
// If we allocate our code buffer from the CodeCache
// via a BufferBlob, and it's not permanent, then
// free the BufferBlob.
// The rest of the memory will be freed when the ResourceObj
// is released.
- assert(verify_section_allocation(), "final storage configuration still OK");
for (CodeBuffer* cb = this; cb != NULL; cb = cb->before_expand()) {
// Previous incarnations of this buffer are held live, so that internal
// addresses constructed before expansions will not be confused.
@@ -484,7 +486,7 @@
// Done calculating sections; did it come out to the right end?
assert(buf_offset == total_content_size(), "sanity");
- assert(dest->verify_section_allocation(), "final configuration works");
+ dest->verify_section_allocation();
}
csize_t CodeBuffer::total_offset_of(CodeSection* cs) const {
@@ -632,7 +634,8 @@
// CodeBuffer gets the final layout (consts, insts, stubs in order of
// ascending address).
void CodeBuffer::relocate_code_to(CodeBuffer* dest) const {
- DEBUG_ONLY(address dest_end = dest->_total_start + dest->_total_size);
+ address dest_end = dest->_total_start + dest->_total_size;
+ address dest_filled = NULL;
for (int n = (int) SECT_FIRST; n < (int) SECT_LIMIT; n++) {
// pull code out of each section
const CodeSection* cs = code_section(n);
@@ -654,6 +657,8 @@
Copy::fill_to_bytes(dest_cs->end(), dest_cs->remaining(),
Assembler::code_fill_byte());
}
+ // Keep track of the highest filled address
+ dest_filled = MAX2(dest_filled, dest_cs->end() + dest_cs->remaining());
assert(cs->locs_start() != (relocInfo*)badAddress,
"this section carries no reloc storage, but reloc was attempted");
@@ -668,6 +673,14 @@
}
}
}
+
+ if (dest->blob() == NULL) {
+ // Destination is a final resting place, not just another buffer.
+ // Normalize uninitialized bytes in the final padding.
+ Copy::fill_to_bytes(dest_filled, dest_end - dest_filled,
+ Assembler::code_fill_byte());
+
+ }
}
csize_t CodeBuffer::figure_expanded_capacities(CodeSection* which_cs,
@@ -799,7 +812,7 @@
_decode_begin = NULL; // sanity
// Make certain that the new sections are all snugly inside the new blob.
- assert(verify_section_allocation(), "expanded allocation is ship-shape");
+ verify_section_allocation();
#ifndef PRODUCT
if (PrintNMethods && (WizardMode || Verbose)) {
@@ -828,35 +841,48 @@
DEBUG_ONLY(cb->_blob = (BufferBlob*)badAddress);
}
-#ifdef ASSERT
-bool CodeBuffer::verify_section_allocation() {
+void CodeBuffer::verify_section_allocation() {
address tstart = _total_start;
- if (tstart == badAddress) return true; // smashed by set_blob(NULL)
+ if (tstart == badAddress) return; // smashed by set_blob(NULL)
address tend = tstart + _total_size;
if (_blob != NULL) {
- assert(tstart >= _blob->content_begin(), "sanity");
- assert(tend <= _blob->content_end(), "sanity");
+
+ guarantee(tstart >= _blob->content_begin(), "sanity");
+ guarantee(tend <= _blob->content_end(), "sanity");
}
// Verify disjointness.
for (int n = (int) SECT_FIRST; n < (int) SECT_LIMIT; n++) {
CodeSection* sect = code_section(n);
if (!sect->is_allocated() || sect->is_empty()) continue;
- assert((intptr_t)sect->start() % sect->alignment() == 0
+ guarantee((intptr_t)sect->start() % sect->alignment() == 0
|| sect->is_empty() || _blob == NULL,
"start is aligned");
for (int m = (int) SECT_FIRST; m < (int) SECT_LIMIT; m++) {
CodeSection* other = code_section(m);
if (!other->is_allocated() || other == sect) continue;
- assert(!other->contains(sect->start() ), "sanity");
+ guarantee(!other->contains(sect->start() ), "sanity");
// limit is an exclusive address and can be the start of another
// section.
- assert(!other->contains(sect->limit() - 1), "sanity");
+ guarantee(!other->contains(sect->limit() - 1), "sanity");
}
- assert(sect->end() <= tend, "sanity");
+ guarantee(sect->end() <= tend, "sanity");
+ guarantee(sect->end() <= sect->limit(), "sanity");
}
- return true;
}
-#endif //ASSERT
+
+void CodeBuffer::log_section_sizes(const char* name) {
+ if (xtty != NULL) {
+ // log info about buffer usage
+ xtty->print_cr("<blob name='%s' size='%d'>", name, _total_size);
+ for (int n = (int) CodeBuffer::SECT_FIRST; n < (int) CodeBuffer::SECT_LIMIT; n++) {
+ CodeSection* sect = code_section(n);
+ if (!sect->is_allocated() || sect->is_empty()) continue;
+ xtty->print_cr("<sect index='%d' size='" SIZE_FORMAT "' free='" SIZE_FORMAT "'/>",
+ n, sect->limit() - sect->start(), sect->limit() - sect->end());
+ }
+ xtty->print_cr("</blob>");
+ }
+}
#ifndef PRODUCT
@@ -884,7 +910,6 @@
_comments.add_comment(offset, comment);
}
-
class CodeComment: public CHeapObj {
private:
friend class CodeComments;
--- a/hotspot/src/share/vm/asm/codeBuffer.hpp Thu Nov 17 10:46:00 2011 -0800
+++ b/hotspot/src/share/vm/asm/codeBuffer.hpp Wed Jul 05 17:56:12 2017 +0200
@@ -362,10 +362,8 @@
// helper for CodeBuffer::expand()
void take_over_code_from(CodeBuffer* cs);
-#ifdef ASSERT
// ensure sections are disjoint, ordered, and contained in the blob
- bool verify_section_allocation();
-#endif
+ void verify_section_allocation();
// copies combined relocations to the blob, returns bytes copied
// (if target is null, it is a dry run only, just for sizing)
@@ -393,7 +391,7 @@
assert(code_start != NULL, "sanity");
initialize_misc("static buffer");
initialize(code_start, code_size);
- assert(verify_section_allocation(), "initial use of buffer OK");
+ verify_section_allocation();
}
// (2) CodeBuffer referring to pre-allocated CodeBlob.
@@ -545,6 +543,9 @@
void block_comment(intptr_t offset, const char * comment) PRODUCT_RETURN;
+ // Log a little info about section usage in the CodeBuffer
+ void log_section_sizes(const char* name);
+
#ifndef PRODUCT
public:
// Printing / Decoding
--- a/hotspot/src/share/vm/c1/c1_Canonicalizer.hpp Thu Nov 17 10:46:00 2011 -0800
+++ b/hotspot/src/share/vm/c1/c1_Canonicalizer.hpp Wed Jul 05 17:56:12 2017 +0200
@@ -51,6 +51,7 @@
public:
Canonicalizer(Compilation* c, Value x, int bci) : _compilation(c), _canonical(x), _bci(bci) {
+ NOT_PRODUCT(x->set_printable_bci(bci));
if (CanonicalizeNodes) x->visit(this);
}
Value canonical() const { return _canonical; }
--- a/hotspot/src/share/vm/c1/c1_Runtime1.cpp Thu Nov 17 10:46:00 2011 -0800
+++ b/hotspot/src/share/vm/c1/c1_Runtime1.cpp Wed Jul 05 17:56:12 2017 +0200
@@ -681,6 +681,23 @@
}
JRT_END
+// Cf. OptoRuntime::deoptimize_caller_frame
+JRT_ENTRY(void, Runtime1::deoptimize(JavaThread* thread))
+ // Called from within the owner thread, so no need for safepoint
+ RegisterMap reg_map(thread, false);
+ frame stub_frame = thread->last_frame();
+ assert(stub_frame.is_runtime_frame(), "sanity check");
+ frame caller_frame = stub_frame.sender(®_map);
+
+ // We are coming from a compiled method; check this is true.
+ assert(CodeCache::find_nmethod(caller_frame.pc()) != NULL, "sanity");
+
+ // Deoptimize the caller frame.
+ Deoptimization::deoptimize_frame(thread, caller_frame.id());
+
+ // Return to the now deoptimized frame.
+JRT_END
+
static klassOop resolve_field_return_klass(methodHandle caller, int bci, TRAPS) {
Bytecode_field field_access(caller, bci);
--- a/hotspot/src/share/vm/c1/c1_Runtime1.hpp Thu Nov 17 10:46:00 2011 -0800
+++ b/hotspot/src/share/vm/c1/c1_Runtime1.hpp Wed Jul 05 17:56:12 2017 +0200
@@ -63,6 +63,7 @@
stub(monitorenter_nofpu) /* optimized version that does not preserve fpu registers */ \
stub(monitorexit) \
stub(monitorexit_nofpu) /* optimized version that does not preserve fpu registers */ \
+ stub(deoptimize) \
stub(access_field_patching) \
stub(load_klass_patching) \
stub(g1_pre_barrier_slow) \
@@ -152,6 +153,8 @@
static void monitorenter(JavaThread* thread, oopDesc* obj, BasicObjectLock* lock);
static void monitorexit (JavaThread* thread, BasicObjectLock* lock);
+ static void deoptimize(JavaThread* thread);
+
static int access_field_patching(JavaThread* thread);
static int move_klass_patching(JavaThread* thread);
--- a/hotspot/src/share/vm/ci/ciMethodHandle.cpp Thu Nov 17 10:46:00 2011 -0800
+++ b/hotspot/src/share/vm/ci/ciMethodHandle.cpp Wed Jul 05 17:56:12 2017 +0200
@@ -86,12 +86,12 @@
}
-#ifndef PRODUCT
+#ifdef ASSERT
// ------------------------------------------------------------------
// ciMethodHandle::print_chain_impl
//
// Implementation of the print method.
-void ciMethodHandle::print_chain_impl(outputStream* st) {
+void ciMethodHandle::print_chain_impl() {
ASSERT_IN_VM;
MethodHandleChain::print(get_oop());
}
@@ -101,7 +101,7 @@
// ciMethodHandle::print_chain
//
// Implementation of the print_chain method.
-void ciMethodHandle::print_chain(outputStream* st) {
- GUARDED_VM_ENTRY(print_chain_impl(st););
+void ciMethodHandle::print_chain() {
+ GUARDED_VM_ENTRY(print_chain_impl(););
}
#endif
--- a/hotspot/src/share/vm/ci/ciMethodHandle.hpp Thu Nov 17 10:46:00 2011 -0800
+++ b/hotspot/src/share/vm/ci/ciMethodHandle.hpp Wed Jul 05 17:56:12 2017 +0200
@@ -45,7 +45,7 @@
ciMethod* get_adapter( bool is_invokedynamic);
protected:
- void print_chain_impl(outputStream* st) PRODUCT_RETURN;
+ void print_chain_impl() NOT_DEBUG_RETURN;
public:
ciMethodHandle(instanceHandle h_i) :
@@ -79,7 +79,7 @@
return _invokedynamic_adapter;
}
- void print_chain(outputStream* st = tty) PRODUCT_RETURN;
+ void print_chain() NOT_DEBUG_RETURN;
};
#endif // SHARE_VM_CI_CIMETHODHANDLE_HPP
--- a/hotspot/src/share/vm/code/dependencies.cpp Thu Nov 17 10:46:00 2011 -0800
+++ b/hotspot/src/share/vm/code/dependencies.cpp Wed Jul 05 17:56:12 2017 +0200
@@ -763,9 +763,14 @@
// Method m is inherited into ctxk.
return true;
if (lm != NULL) {
- if (!(lm->is_public() || lm->is_protected()))
+ if (!(lm->is_public() || lm->is_protected())) {
// Method is [package-]private, so the override story is complex.
return true; // Must punt the assertion to true.
+ }
+ if (lm->is_static()) {
+ // Static methods don't override non-static so punt
+ return true;
+ }
if ( !Dependencies::is_concrete_method(lm)
&& !Dependencies::is_concrete_method(m)
&& Klass::cast(lm->method_holder())->is_subtype_of(m->method_holder()))
@@ -1091,9 +1096,11 @@
}
bool Dependencies::is_concrete_method(methodOop m) {
- if (m->is_abstract()) return false;
- // %%% We could treat unexecuted methods as virtually abstract also.
- // This would require a deoptimization barrier on first execution.
+ // Statics are irrelevant to virtual call sites.
+ if (m->is_static()) return false;
+
+ // We could also return false if m does not yet appear to be
+ // executed, if the VM version supports this distinction also.
return !m->is_abstract();
}
@@ -1113,7 +1120,7 @@
bool Dependencies::is_concrete_klass(ciInstanceKlass* k) {
if (k->is_abstract()) return false;
- // We could return also false if k does not yet appear to be
+ // We could also return false if k does not yet appear to be
// instantiated, if the VM version supports this distinction also.
//if (k->is_not_instantiated()) return false;
return true;
@@ -1123,7 +1130,7 @@
// Statics are irrelevant to virtual call sites.
if (m->is_static()) return false;
- // We could return also false if m does not yet appear to be
+ // We could also return false if m does not yet appear to be
// executed, if the VM version supports this distinction also.
return !m->is_abstract();
}
--- a/hotspot/src/share/vm/compiler/compileBroker.cpp Thu Nov 17 10:46:00 2011 -0800
+++ b/hotspot/src/share/vm/compiler/compileBroker.cpp Wed Jul 05 17:56:12 2017 +0200
@@ -1722,11 +1722,11 @@
if (PrintCompilation) {
const char* reason = ci_env.failure_reason();
if (compilable == ciEnv::MethodCompilable_not_at_tier) {
- tty->print_cr("%3d COMPILE SKIPPED: %s (retry at different tier)", compile_id, reason);
+ tty->print_cr("%4d COMPILE SKIPPED: %s (retry at different tier)", compile_id, reason);
} else if (compilable == ciEnv::MethodCompilable_never) {
- tty->print_cr("%3d COMPILE SKIPPED: %s (not retryable)", compile_id, reason);
+ tty->print_cr("%4d COMPILE SKIPPED: %s (not retryable)", compile_id, reason);
} else if (compilable == ciEnv::MethodCompilable) {
- tty->print_cr("%3d COMPILE SKIPPED: %s", compile_id, reason);
+ tty->print_cr("%4d COMPILE SKIPPED: %s", compile_id, reason);
}
}
} else {
@@ -1743,6 +1743,14 @@
collect_statistics(thread, time, task);
+ if (PrintCompilation && PrintCompilation2) {
+ tty->print("%7d ", (int) tty->time_stamp().milliseconds()); // print timestamp
+ tty->print("%4d ", compile_id); // print compilation number
+ tty->print("%s ", (is_osr ? "%" : " "));
+ int code_size = (task->code() == NULL) ? 0 : task->code()->total_size();
+ tty->print_cr("size: %d time: %d inlined: %d bytes", code_size, time.milliseconds(), task->num_inlined_bytecodes());
+ }
+
if (compilable == ciEnv::MethodCompilable_never) {
if (is_osr) {
method->set_not_osr_compilable();
--- a/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/compactibleFreeListSpace.cpp Thu Nov 17 10:46:00 2011 -0800
+++ b/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/compactibleFreeListSpace.cpp Wed Jul 05 17:56:12 2017 +0200
@@ -50,8 +50,8 @@
int CompactibleFreeListSpace::_lockRank = Mutex::leaf + 3;
// Defaults are 0 so things will break badly if incorrectly initialized.
-int CompactibleFreeListSpace::IndexSetStart = 0;
-int CompactibleFreeListSpace::IndexSetStride = 0;
+size_t CompactibleFreeListSpace::IndexSetStart = 0;
+size_t CompactibleFreeListSpace::IndexSetStride = 0;
size_t MinChunkSize = 0;
@@ -62,7 +62,7 @@
MinChunkSize = numQuanta(sizeof(FreeChunk), MinObjAlignmentInBytes) * MinObjAlignment;
assert(IndexSetStart == 0 && IndexSetStride == 0, "already set");
- IndexSetStart = (int) MinChunkSize;
+ IndexSetStart = MinChunkSize;
IndexSetStride = MinObjAlignment;
}
@@ -250,7 +250,7 @@
}
void CompactibleFreeListSpace::resetIndexedFreeListArray() {
- for (int i = 1; i < IndexSetSize; i++) {
+ for (size_t i = 1; i < IndexSetSize; i++) {
assert(_indexedFreeList[i].size() == (size_t) i,
"Indexed free list sizes are incorrect");
_indexedFreeList[i].reset(IndexSetSize);
@@ -337,7 +337,7 @@
size_t CompactibleFreeListSpace::totalCountInIndexedFreeLists() const {
size_t count = 0;
- for (int i = (int)MinChunkSize; i < IndexSetSize; i++) {
+ for (size_t i = IndexSetStart; i < IndexSetSize; i++) {
debug_only(
ssize_t total_list_count = 0;
for (FreeChunk* fc = _indexedFreeList[i].head(); fc != NULL;
@@ -2200,7 +2200,7 @@
void CompactibleFreeListSpace::clearFLCensus() {
assert_locked();
- int i;
+ size_t i;
for (i = IndexSetStart; i < IndexSetSize; i += IndexSetStride) {
FreeList *fl = &_indexedFreeList[i];
fl->set_prevSweep(fl->count());
@@ -2494,7 +2494,7 @@
void CompactibleFreeListSpace::verifyIndexedFreeLists() const {
size_t i = 0;
- for (; i < MinChunkSize; i++) {
+ for (; i < IndexSetStart; i++) {
guarantee(_indexedFreeList[i].head() == NULL, "should be NULL");
}
for (; i < IndexSetSize; i++) {
@@ -2507,7 +2507,7 @@
FreeChunk* tail = _indexedFreeList[size].tail();
size_t num = _indexedFreeList[size].count();
size_t n = 0;
- guarantee(((size >= MinChunkSize) && (size % IndexSetStride == 0)) || fc == NULL,
+ guarantee(((size >= IndexSetStart) && (size % IndexSetStride == 0)) || fc == NULL,
"Slot should have been empty");
for (; fc != NULL; fc = fc->next(), n++) {
guarantee(fc->size() == size, "Size inconsistency");
@@ -2527,7 +2527,7 @@
"else MIN_TREE_CHUNK_SIZE is wrong");
assert((IndexSetStride == 2 && IndexSetStart == 4) || // 32-bit
(IndexSetStride == 1 && IndexSetStart == 3), "just checking"); // 64-bit
- assert((IndexSetStride != 2) || (MinChunkSize % 2 == 0),
+ assert((IndexSetStride != 2) || (IndexSetStart % 2 == 0),
"Some for-loops may be incorrectly initialized");
assert((IndexSetStride != 2) || (IndexSetSize % 2 == 1),
"For-loops that iterate over IndexSet with stride 2 may be wrong");
--- a/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/compactibleFreeListSpace.hpp Thu Nov 17 10:46:00 2011 -0800
+++ b/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/compactibleFreeListSpace.hpp Wed Jul 05 17:56:12 2017 +0200
@@ -104,8 +104,8 @@
SmallForDictionary = 257, // size < this then use _indexedFreeList
IndexSetSize = SmallForDictionary // keep this odd-sized
};
- static int IndexSetStart;
- static int IndexSetStride;
+ static size_t IndexSetStart;
+ static size_t IndexSetStride;
private:
enum FitStrategyOptions {
--- a/hotspot/src/share/vm/gc_implementation/g1/concurrentMark.cpp Thu Nov 17 10:46:00 2011 -0800
+++ b/hotspot/src/share/vm/gc_implementation/g1/concurrentMark.cpp Wed Jul 05 17:56:12 2017 +0200
@@ -1518,6 +1518,7 @@
size_t _regions_claimed;
size_t _freed_bytes;
FreeRegionList* _local_cleanup_list;
+ OldRegionSet* _old_proxy_set;
HumongousRegionSet* _humongous_proxy_set;
HRRSCleanupTask* _hrrs_cleanup_task;
double _claimed_region_time;
@@ -1527,6 +1528,7 @@
G1NoteEndOfConcMarkClosure(G1CollectedHeap* g1,
int worker_num,
FreeRegionList* local_cleanup_list,
+ OldRegionSet* old_proxy_set,
HumongousRegionSet* humongous_proxy_set,
HRRSCleanupTask* hrrs_cleanup_task);
size_t freed_bytes() { return _freed_bytes; }
@@ -1557,9 +1559,11 @@
void work(int i) {
double start = os::elapsedTime();
FreeRegionList local_cleanup_list("Local Cleanup List");
+ OldRegionSet old_proxy_set("Local Cleanup Old Proxy Set");
HumongousRegionSet humongous_proxy_set("Local Cleanup Humongous Proxy Set");
HRRSCleanupTask hrrs_cleanup_task;
G1NoteEndOfConcMarkClosure g1_note_end(_g1h, i, &local_cleanup_list,
+ &old_proxy_set,
&humongous_proxy_set,
&hrrs_cleanup_task);
if (G1CollectedHeap::use_parallel_gc_threads()) {
@@ -1573,6 +1577,7 @@
// Now update the lists
_g1h->update_sets_after_freeing_regions(g1_note_end.freed_bytes(),
NULL /* free_list */,
+ &old_proxy_set,
&humongous_proxy_set,
true /* par */);
{
@@ -1643,6 +1648,7 @@
G1NoteEndOfConcMarkClosure(G1CollectedHeap* g1,
int worker_num,
FreeRegionList* local_cleanup_list,
+ OldRegionSet* old_proxy_set,
HumongousRegionSet* humongous_proxy_set,
HRRSCleanupTask* hrrs_cleanup_task)
: _g1(g1), _worker_num(worker_num),
@@ -1650,6 +1656,7 @@
_freed_bytes(0),
_claimed_region_time(0.0), _max_region_time(0.0),
_local_cleanup_list(local_cleanup_list),
+ _old_proxy_set(old_proxy_set),
_humongous_proxy_set(humongous_proxy_set),
_hrrs_cleanup_task(hrrs_cleanup_task) { }
@@ -1665,6 +1672,7 @@
_g1->free_region_if_empty(hr,
&_freed_bytes,
_local_cleanup_list,
+ _old_proxy_set,
_humongous_proxy_set,
_hrrs_cleanup_task,
true /* par */);
@@ -1689,6 +1697,7 @@
return;
}
+ HRSPhaseSetter x(HRSPhaseCleanup);
g1h->verify_region_sets_optional();
if (VerifyDuringGC) {
--- a/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp Thu Nov 17 10:46:00 2011 -0800
+++ b/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp Wed Jul 05 17:56:12 2017 +0200
@@ -1203,6 +1203,7 @@
Universe::print_heap_before_gc();
}
+ HRSPhaseSetter x(HRSPhaseFullGC);
verify_region_sets_optional();
const bool do_clear_all_soft_refs = clear_all_soft_refs ||
@@ -1263,7 +1264,6 @@
release_mutator_alloc_region();
abandon_gc_alloc_regions();
g1_rem_set()->cleanupHRRS();
- tear_down_region_lists();
// We should call this after we retire any currently active alloc
// regions so that all the ALLOC / RETIRE events are generated
@@ -1278,7 +1278,7 @@
g1_policy()->clear_incremental_cset();
g1_policy()->stop_incremental_cset_building();
- empty_young_list();
+ tear_down_region_sets(false /* free_list_only */);
g1_policy()->set_full_young_gcs(true);
// See the comments in g1CollectedHeap.hpp and
@@ -1301,9 +1301,7 @@
}
assert(free_regions() == 0, "we should not have added any free regions");
- rebuild_region_lists();
-
- _summary_bytes_used = recalculate_used();
+ rebuild_region_sets(false /* free_list_only */);
// Enqueue any discovered reference objects that have
// not been removed from the discovered lists.
@@ -1764,9 +1762,9 @@
// Instead of tearing down / rebuilding the free lists here, we
// could instead use the remove_all_pending() method on free_list to
// remove only the ones that we need to remove.
- tear_down_region_lists(); // We will rebuild them in a moment.
+ tear_down_region_sets(true /* free_list_only */);
shrink_helper(shrink_bytes);
- rebuild_region_lists();
+ rebuild_region_sets(true /* free_list_only */);
_hrs.verify_optional();
verify_region_sets_optional();
@@ -1799,6 +1797,7 @@
_full_collection(false),
_free_list("Master Free List"),
_secondary_free_list("Secondary Free List"),
+ _old_set("Old Set"),
_humongous_set("Master Humongous Set"),
_free_regions_coming(false),
_young_list(new YoungList(this)),
@@ -3007,7 +3006,10 @@
if (failures) {
gclog_or_tty->print_cr("Heap:");
- print_on(gclog_or_tty, true /* extended */);
+ // It helps to have the per-region information in the output to
+ // help us track down what went wrong. This is why we call
+ // print_extended_on() instead of print_on().
+ print_extended_on(gclog_or_tty);
gclog_or_tty->print_cr("");
#ifndef PRODUCT
if (VerifyDuringGC && G1VerifyDuringGCPrintReachable) {
@@ -3033,13 +3035,7 @@
}
};
-void G1CollectedHeap::print() const { print_on(tty); }
-
void G1CollectedHeap::print_on(outputStream* st) const {
- print_on(st, PrintHeapAtGCExtended);
-}
-
-void G1CollectedHeap::print_on(outputStream* st, bool extended) const {
st->print(" %-20s", "garbage-first heap");
st->print(" total " SIZE_FORMAT "K, used " SIZE_FORMAT "K",
capacity()/K, used_unlocked()/K);
@@ -3057,13 +3053,14 @@
survivor_regions, survivor_regions * HeapRegion::GrainBytes / K);
st->cr();
perm()->as_gen()->print_on(st);
- if (extended) {
- st->cr();
- print_on_extended(st);
- }
-}
-
-void G1CollectedHeap::print_on_extended(outputStream* st) const {
+}
+
+void G1CollectedHeap::print_extended_on(outputStream* st) const {
+ print_on(st);
+
+ // Print the per-region information.
+ st->cr();
+ st->print_cr("Heap Regions: (Y=young(eden), SU=young(survivor), HS=humongous(starts), HC=humongous(continues), CS=collection set, F=free, TS=gc time stamp, PTAMS=previous top-at-mark-start, NTAMS=next top-at-mark-start)");
PrintRegionClosure blk(st);
heap_region_iterate(&blk);
}
@@ -3352,6 +3349,7 @@
Universe::print_heap_before_gc();
}
+ HRSPhaseSetter x(HRSPhaseEvacuation);
verify_region_sets_optional();
verify_dirty_young_regions();
@@ -3774,6 +3772,11 @@
!retained_region->is_empty() &&
!retained_region->isHumongous()) {
retained_region->set_saved_mark();
+ // The retained region was added to the old region set when it was
+ // retired. We have to remove it now, since we don't allow regions
+ // we allocate to in the region sets. We'll re-add it later, when
+ // it's retired again.
+ _old_set.remove(retained_region);
_old_gc_alloc_region.set(retained_region);
_hr_printer.reuse(retained_region);
}
@@ -5338,6 +5341,7 @@
void G1CollectedHeap::free_region_if_empty(HeapRegion* hr,
size_t* pre_used,
FreeRegionList* free_list,
+ OldRegionSet* old_proxy_set,
HumongousRegionSet* humongous_proxy_set,
HRRSCleanupTask* hrrs_cleanup_task,
bool par) {
@@ -5346,6 +5350,7 @@
assert(hr->startsHumongous(), "we should only see starts humongous");
free_humongous_region(hr, pre_used, free_list, humongous_proxy_set, par);
} else {
+ _old_set.remove_with_proxy(hr, old_proxy_set);
free_region(hr, pre_used, free_list, par);
}
} else {
@@ -5402,6 +5407,7 @@
void G1CollectedHeap::update_sets_after_freeing_regions(size_t pre_used,
FreeRegionList* free_list,
+ OldRegionSet* old_proxy_set,
HumongousRegionSet* humongous_proxy_set,
bool par) {
if (pre_used > 0) {
@@ -5417,6 +5423,10 @@
MutexLockerEx x(FreeList_lock, Mutex::_no_safepoint_check_flag);
_free_list.add_as_head(free_list);
}
+ if (old_proxy_set != NULL && !old_proxy_set->is_empty()) {
+ MutexLockerEx x(OldSets_lock, Mutex::_no_safepoint_check_flag);
+ _old_set.update_from_proxy(old_proxy_set);
+ }
if (humongous_proxy_set != NULL && !humongous_proxy_set->is_empty()) {
MutexLockerEx x(OldSets_lock, Mutex::_no_safepoint_check_flag);
_humongous_set.update_from_proxy(humongous_proxy_set);
@@ -5614,6 +5624,8 @@
cur->set_young_index_in_cset(-1);
cur->set_not_young();
cur->set_evacuation_failed(false);
+ // The region is now considered to be old.
+ _old_set.add(cur);
}
cur = next;
}
@@ -5629,6 +5641,7 @@
young_time_ms += elapsed_ms;
update_sets_after_freeing_regions(pre_used, &local_free_list,
+ NULL /* old_proxy_set */,
NULL /* humongous_proxy_set */,
false /* par */);
policy->record_young_free_cset_time_ms(young_time_ms);
@@ -5740,52 +5753,106 @@
return ret;
}
-void G1CollectedHeap::empty_young_list() {
- assert(heap_lock_held_for_gc(),
- "the heap lock should already be held by or for this thread");
-
- _young_list->empty_list();
-}
-
-// Done at the start of full GC.
-void G1CollectedHeap::tear_down_region_lists() {
- _free_list.remove_all();
-}
-
-class RegionResetter: public HeapRegionClosure {
- G1CollectedHeap* _g1h;
- FreeRegionList _local_free_list;
+class TearDownRegionSetsClosure : public HeapRegionClosure {
+private:
+ OldRegionSet *_old_set;
public:
- RegionResetter() : _g1h(G1CollectedHeap::heap()),
- _local_free_list("Local Free List for RegionResetter") { }
+ TearDownRegionSetsClosure(OldRegionSet* old_set) : _old_set(old_set) { }
bool doHeapRegion(HeapRegion* r) {
- if (r->continuesHumongous()) return false;
- if (r->top() > r->bottom()) {
- if (r->top() < r->end()) {
- Copy::fill_to_words(r->top(),
- pointer_delta(r->end(), r->top()));
- }
+ if (r->is_empty()) {
+ // We ignore empty regions, we'll empty the free list afterwards
+ } else if (r->is_young()) {
+ // We ignore young regions, we'll empty the young list afterwards
+ } else if (r->isHumongous()) {
+ // We ignore humongous regions, we're not tearing down the
+ // humongous region set
} else {
- assert(r->is_empty(), "tautology");
- _local_free_list.add_as_tail(r);
+ // The rest should be old
+ _old_set->remove(r);
}
return false;
}
- void update_free_lists() {
- _g1h->update_sets_after_freeing_regions(0, &_local_free_list, NULL,
- false /* par */);
+ ~TearDownRegionSetsClosure() {
+ assert(_old_set->is_empty(), "post-condition");
}
};
-// Done at the end of full GC.
-void G1CollectedHeap::rebuild_region_lists() {
- // This needs to go at the end of the full GC.
- RegionResetter rs;
- heap_region_iterate(&rs);
- rs.update_free_lists();
+void G1CollectedHeap::tear_down_region_sets(bool free_list_only) {
+ assert_at_safepoint(true /* should_be_vm_thread */);
+
+ if (!free_list_only) {
+ TearDownRegionSetsClosure cl(&_old_set);
+ heap_region_iterate(&cl);
+
+ // Need to do this after the heap iteration to be able to
+ // recognize the young regions and ignore them during the iteration.
+ _young_list->empty_list();
+ }
+ _free_list.remove_all();
+}
+
+class RebuildRegionSetsClosure : public HeapRegionClosure {
+private:
+ bool _free_list_only;
+ OldRegionSet* _old_set;
+ FreeRegionList* _free_list;
+ size_t _total_used;
+
+public:
+ RebuildRegionSetsClosure(bool free_list_only,
+ OldRegionSet* old_set, FreeRegionList* free_list) :
+ _free_list_only(free_list_only),
+ _old_set(old_set), _free_list(free_list), _total_used(0) {
+ assert(_free_list->is_empty(), "pre-condition");
+ if (!free_list_only) {
+ assert(_old_set->is_empty(), "pre-condition");
+ }
+ }
+
+ bool doHeapRegion(HeapRegion* r) {
+ if (r->continuesHumongous()) {
+ return false;
+ }
+
+ if (r->is_empty()) {
+ // Add free regions to the free list
+ _free_list->add_as_tail(r);
+ } else if (!_free_list_only) {
+ assert(!r->is_young(), "we should not come across young regions");
+
+ if (r->isHumongous()) {
+ // We ignore humongous regions, we left the humongous set unchanged
+ } else {
+ // The rest should be old, add them to the old set
+ _old_set->add(r);
+ }
+ _total_used += r->used();
+ }
+
+ return false;
+ }
+
+ size_t total_used() {
+ return _total_used;
+ }
+};
+
+void G1CollectedHeap::rebuild_region_sets(bool free_list_only) {
+ assert_at_safepoint(true /* should_be_vm_thread */);
+
+ RebuildRegionSetsClosure cl(free_list_only, &_old_set, &_free_list);
+ heap_region_iterate(&cl);
+
+ if (!free_list_only) {
+ _summary_bytes_used = cl.total_used();
+ }
+ assert(_summary_bytes_used == recalculate_used(),
+ err_msg("inconsistent _summary_bytes_used, "
+ "value: "SIZE_FORMAT" recalculated: "SIZE_FORMAT,
+ _summary_bytes_used, recalculate_used()));
}
void G1CollectedHeap::set_refine_cte_cl_concurrency(bool concurrent) {
@@ -5882,6 +5949,8 @@
g1_policy()->record_bytes_copied_during_gc(allocated_bytes);
if (ap == GCAllocForSurvived) {
young_list()->add_survivor_region(alloc_region);
+ } else {
+ _old_set.add(alloc_region);
}
_hr_printer.retire(alloc_region);
}
@@ -5913,15 +5982,17 @@
class VerifyRegionListsClosure : public HeapRegionClosure {
private:
+ FreeRegionList* _free_list;
+ OldRegionSet* _old_set;
HumongousRegionSet* _humongous_set;
- FreeRegionList* _free_list;
size_t _region_count;
public:
- VerifyRegionListsClosure(HumongousRegionSet* humongous_set,
+ VerifyRegionListsClosure(OldRegionSet* old_set,
+ HumongousRegionSet* humongous_set,
FreeRegionList* free_list) :
- _humongous_set(humongous_set), _free_list(free_list),
- _region_count(0) { }
+ _old_set(old_set), _humongous_set(humongous_set),
+ _free_list(free_list), _region_count(0) { }
size_t region_count() { return _region_count; }
@@ -5938,6 +6009,8 @@
_humongous_set->verify_next_region(hr);
} else if (hr->is_empty()) {
_free_list->verify_next_region(hr);
+ } else {
+ _old_set->verify_next_region(hr);
}
return false;
}
@@ -5964,6 +6037,7 @@
MutexLockerEx x(SecondaryFreeList_lock, Mutex::_no_safepoint_check_flag);
_secondary_free_list.verify();
}
+ _old_set.verify();
_humongous_set.verify();
// If a concurrent region freeing operation is in progress it will
@@ -5987,12 +6061,14 @@
// Finally, make sure that the region accounting in the lists is
// consistent with what we see in the heap.
+ _old_set.verify_start();
_humongous_set.verify_start();
_free_list.verify_start();
- VerifyRegionListsClosure cl(&_humongous_set, &_free_list);
+ VerifyRegionListsClosure cl(&_old_set, &_humongous_set, &_free_list);
heap_region_iterate(&cl);
+ _old_set.verify_end();
_humongous_set.verify_end();
_free_list.verify_end();
}
--- a/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.hpp Thu Nov 17 10:46:00 2011 -0800
+++ b/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.hpp Wed Jul 05 17:56:12 2017 +0200
@@ -239,6 +239,9 @@
// master free list when appropriate.
SecondaryFreeRegionList _secondary_free_list;
+ // It keeps track of the old regions.
+ MasterOldRegionSet _old_set;
+
// It keeps track of the humongous regions.
MasterHumongousRegionSet _humongous_set;
@@ -248,10 +251,21 @@
// The block offset table for the G1 heap.
G1BlockOffsetSharedArray* _bot_shared;
- // Move all of the regions off the free lists, then rebuild those free
- // lists, before and after full GC.
- void tear_down_region_lists();
- void rebuild_region_lists();
+ // Tears down the region sets / lists so that they are empty and the
+ // regions on the heap do not belong to a region set / list. The
+ // only exception is the humongous set which we leave unaltered. If
+ // free_list_only is true, it will only tear down the master free
+ // list. It is called before a Full GC (free_list_only == false) or
+ // before heap shrinking (free_list_only == true).
+ void tear_down_region_sets(bool free_list_only);
+
+ // Rebuilds the region sets / lists so that they are repopulated to
+ // reflect the contents of the heap. The only exception is the
+ // humongous set which was not torn down in the first place. If
+ // free_list_only is true, it will only rebuild the master free
+ // list. It is called after a Full GC (free_list_only == false) or
+ // after heap shrinking (free_list_only == true).
+ void rebuild_region_sets(bool free_list_only);
// The sequence of all heap regions in the heap.
HeapRegionSeq _hrs;
@@ -1124,6 +1138,10 @@
}
}
+ void old_set_remove(HeapRegion* hr) {
+ _old_set.remove(hr);
+ }
+
void set_free_regions_coming();
void reset_free_regions_coming();
bool free_regions_coming() { return _free_regions_coming; }
@@ -1153,6 +1171,7 @@
void free_region_if_empty(HeapRegion* hr,
size_t* pre_used,
FreeRegionList* free_list,
+ OldRegionSet* old_proxy_set,
HumongousRegionSet* humongous_proxy_set,
HRRSCleanupTask* hrrs_cleanup_task,
bool par);
@@ -1163,6 +1182,7 @@
// (if par is true, it will do so by taking the ParGCRareEvent_lock).
void update_sets_after_freeing_regions(size_t pre_used,
FreeRegionList* free_list,
+ OldRegionSet* old_proxy_set,
HumongousRegionSet* humongous_proxy_set,
bool par);
@@ -1429,14 +1449,8 @@
// Override; it uses the "prev" marking information
virtual void verify(bool allow_dirty, bool silent);
- // Default behavior by calling print(tty);
- virtual void print() const;
- // This calls print_on(st, PrintHeapAtGCExtended).
virtual void print_on(outputStream* st) const;
- // If extended is true, it will print out information for all
- // regions in the heap by calling print_on_extended(st).
- virtual void print_on(outputStream* st, bool extended) const;
- virtual void print_on_extended(outputStream* st) const;
+ virtual void print_extended_on(outputStream* st) const;
virtual void print_gc_threads_on(outputStream* st) const;
virtual void gc_threads_do(ThreadClosure* tc) const;
@@ -1452,8 +1466,6 @@
// asserted to be this type.
static G1CollectedHeap* heap();
- void empty_young_list();
-
void set_region_short_lived_locked(HeapRegion* hr);
// add appropriate methods for any other surv rate groups
--- a/hotspot/src/share/vm/gc_implementation/g1/g1CollectorPolicy.cpp Thu Nov 17 10:46:00 2011 -0800
+++ b/hotspot/src/share/vm/gc_implementation/g1/g1CollectorPolicy.cpp Wed Jul 05 17:56:12 2017 +0200
@@ -3015,6 +3015,7 @@
hr = _collectionSetChooser->getNextMarkedRegion(time_remaining_ms,
avg_prediction);
if (hr != NULL) {
+ _g1->old_set_remove(hr);
double predicted_time_ms = predict_region_elapsed_time_ms(hr, false);
time_remaining_ms -= predicted_time_ms;
predicted_pause_time_ms += predicted_time_ms;
--- a/hotspot/src/share/vm/gc_implementation/g1/g1MarkSweep.cpp Thu Nov 17 10:46:00 2011 -0800
+++ b/hotspot/src/share/vm/gc_implementation/g1/g1MarkSweep.cpp Wed Jul 05 17:56:12 2017 +0200
@@ -236,6 +236,7 @@
// at the end of the GC, so no point in updating those values here.
_g1h->update_sets_after_freeing_regions(0, /* pre_used */
NULL, /* free_list */
+ NULL, /* old_proxy_set */
&_humongous_proxy_set,
false /* par */);
}
--- a/hotspot/src/share/vm/gc_implementation/g1/g1RemSet.cpp Thu Nov 17 10:46:00 2011 -0800
+++ b/hotspot/src/share/vm/gc_implementation/g1/g1RemSet.cpp Wed Jul 05 17:56:12 2017 +0200
@@ -635,10 +635,18 @@
ct_freq_note_card(_ct_bs->index_for(start));
#endif
- assert(!check_for_refs_into_cset || _cset_rs_update_cl[worker_i] != NULL, "sanity");
+ OopsInHeapRegionClosure* oops_in_heap_closure = NULL;
+ if (check_for_refs_into_cset) {
+ // ConcurrentG1RefineThreads have worker numbers larger than what
+ // _cset_rs_update_cl[] is set up to handle. But those threads should
+ // only be active outside of a collection which means that when they
+ // reach here they should have check_for_refs_into_cset == false.
+ assert((size_t)worker_i < n_workers(), "index of worker larger than _cset_rs_update_cl[].length");
+ oops_in_heap_closure = _cset_rs_update_cl[worker_i];
+ }
UpdateRSOrPushRefOopClosure update_rs_oop_cl(_g1,
_g1->g1_rem_set(),
- _cset_rs_update_cl[worker_i],
+ oops_in_heap_closure,
check_for_refs_into_cset,
worker_i);
update_rs_oop_cl.set_from(r);
--- a/hotspot/src/share/vm/gc_implementation/g1/heapRegion.cpp Thu Nov 17 10:46:00 2011 -0800
+++ b/hotspot/src/share/vm/gc_implementation/g1/heapRegion.cpp Wed Jul 05 17:56:12 2017 +0200
@@ -722,7 +722,7 @@
st->print(" F");
else
st->print(" ");
- st->print(" %5d", _gc_time_stamp);
+ st->print(" TS %5d", _gc_time_stamp);
st->print(" PTAMS "PTR_FORMAT" NTAMS "PTR_FORMAT,
prev_top_at_mark_start(), next_top_at_mark_start());
G1OffsetTableContigSpace::print_on(st);
--- a/hotspot/src/share/vm/gc_implementation/g1/heapRegionSet.cpp Thu Nov 17 10:46:00 2011 -0800
+++ b/hotspot/src/share/vm/gc_implementation/g1/heapRegionSet.cpp Wed Jul 05 17:56:12 2017 +0200
@@ -26,6 +26,7 @@
#include "gc_implementation/g1/heapRegionSet.inline.hpp"
size_t HeapRegionSetBase::_unrealistically_long_length = 0;
+HRSPhase HeapRegionSetBase::_phase = HRSPhaseNone;
//////////////////// HeapRegionSetBase ////////////////////
@@ -192,6 +193,17 @@
_verify_in_progress = false;
}
+void HeapRegionSetBase::clear_phase() {
+ assert(_phase != HRSPhaseNone, "pre-condition");
+ _phase = HRSPhaseNone;
+}
+
+void HeapRegionSetBase::set_phase(HRSPhase phase) {
+ assert(_phase == HRSPhaseNone, "pre-condition");
+ assert(phase != HRSPhaseNone, "pre-condition");
+ _phase = phase;
+}
+
void HeapRegionSetBase::print_on(outputStream* out, bool print_contents) {
out->cr();
out->print_cr("Set: %s ("PTR_FORMAT")", name(), this);
--- a/hotspot/src/share/vm/gc_implementation/g1/heapRegionSet.hpp Thu Nov 17 10:46:00 2011 -0800
+++ b/hotspot/src/share/vm/gc_implementation/g1/heapRegionSet.hpp Wed Jul 05 17:56:12 2017 +0200
@@ -47,8 +47,18 @@
class hrs_ext_msg;
+typedef enum {
+ HRSPhaseNone,
+ HRSPhaseEvacuation,
+ HRSPhaseCleanup,
+ HRSPhaseFullGC
+} HRSPhase;
+
+class HRSPhaseSetter;
+
class HeapRegionSetBase VALUE_OBJ_CLASS_SPEC {
friend class hrs_ext_msg;
+ friend class HRSPhaseSetter;
protected:
static size_t calculate_region_num(HeapRegion* hr);
@@ -80,6 +90,15 @@
size_t _calc_total_capacity_bytes;
size_t _calc_total_used_bytes;
+ // This is here so that it can be used in the subclasses to assert
+ // something different depending on which phase the GC is in. This
+ // can be particularly helpful in the check_mt_safety() methods.
+ static HRSPhase _phase;
+
+ // Only used by HRSPhaseSetter.
+ static void clear_phase();
+ static void set_phase(HRSPhase phase);
+
// verify_region() is used to ensure that the contents of a region
// added to / removed from a set are consistent. Different sets
// make different assumptions about the regions added to them. So
@@ -177,6 +196,16 @@
}
};
+class HRSPhaseSetter {
+public:
+ HRSPhaseSetter(HRSPhase phase) {
+ HeapRegionSetBase::set_phase(phase);
+ }
+ ~HRSPhaseSetter() {
+ HeapRegionSetBase::clear_phase();
+ }
+};
+
// These two macros are provided for convenience, to keep the uses of
// these two asserts a bit more concise.
--- a/hotspot/src/share/vm/gc_implementation/g1/heapRegionSets.cpp Thu Nov 17 10:46:00 2011 -0800
+++ b/hotspot/src/share/vm/gc_implementation/g1/heapRegionSets.cpp Wed Jul 05 17:56:12 2017 +0200
@@ -26,6 +26,17 @@
#include "gc_implementation/g1/heapRegionRemSet.hpp"
#include "gc_implementation/g1/heapRegionSets.hpp"
+// Note on the check_mt_safety() methods below:
+//
+// Verification of the "master" heap region sets / lists that are
+// maintained by G1CollectedHeap is always done during a STW pause and
+// by the VM thread at the start / end of the pause. The standard
+// verification methods all assert check_mt_safety(). This is
+// important as it ensures that verification is done without
+// concurrent updates taking place at the same time. It follows, that,
+// for the "master" heap region sets / lists, the check_mt_safety()
+// method should include the VM thread / STW case.
+
//////////////////// FreeRegionList ////////////////////
const char* FreeRegionList::verify_region_extra(HeapRegion* hr) {
@@ -33,7 +44,7 @@
return "the region should not be young";
}
// The superclass will check that the region is empty and
- // not-humongous.
+ // not humongous.
return HeapRegionLinkedList::verify_region_extra(hr);
}
@@ -58,12 +69,16 @@
// (b) If we're not at a safepoint, operations on the master free
// list should be invoked while holding the Heap_lock.
- guarantee((SafepointSynchronize::is_at_safepoint() &&
- (Thread::current()->is_VM_thread() ||
- FreeList_lock->owned_by_self())) ||
- (!SafepointSynchronize::is_at_safepoint() &&
- Heap_lock->owned_by_self()),
- hrs_ext_msg(this, "master free list MT safety protocol"));
+ if (SafepointSynchronize::is_at_safepoint()) {
+ guarantee(Thread::current()->is_VM_thread() ||
+ FreeList_lock->owned_by_self(),
+ hrs_ext_msg(this, "master free list MT safety protocol "
+ "at a safepoint"));
+ } else {
+ guarantee(Heap_lock->owned_by_self(),
+ hrs_ext_msg(this, "master free list MT safety protocol "
+ "outside a safepoint"));
+ }
return FreeRegionList::check_mt_safety();
}
@@ -81,6 +96,48 @@
return FreeRegionList::check_mt_safety();
}
+//////////////////// OldRegionSet ////////////////////
+
+const char* OldRegionSet::verify_region_extra(HeapRegion* hr) {
+ if (hr->is_young()) {
+ return "the region should not be young";
+ }
+ // The superclass will check that the region is not empty and not
+ // humongous.
+ return HeapRegionSet::verify_region_extra(hr);
+}
+
+//////////////////// MasterOldRegionSet ////////////////////
+
+bool MasterOldRegionSet::check_mt_safety() {
+ // Master Old Set MT safety protocol:
+ // (a) If we're at a safepoint, operations on the master old set
+ // should be invoked:
+ // - by the VM thread (which will serialize them), or
+ // - by the GC workers while holding the FreeList_lock, if we're
+ // at a safepoint for an evacuation pause (this lock is taken
+ // anyway when an GC alloc region is retired so that a new one
+ // is allocated from the free list), or
+ // - by the GC workers while holding the OldSets_lock, if we're at a
+ // safepoint for a cleanup pause.
+ // (b) If we're not at a safepoint, operations on the master old set
+ // should be invoked while holding the Heap_lock.
+
+ if (SafepointSynchronize::is_at_safepoint()) {
+ guarantee(Thread::current()->is_VM_thread() ||
+ _phase == HRSPhaseEvacuation && FreeList_lock->owned_by_self() ||
+ _phase == HRSPhaseCleanup && OldSets_lock->owned_by_self(),
+ hrs_ext_msg(this, "master old set MT safety protocol "
+ "at a safepoint"));
+ } else {
+ guarantee(Heap_lock->owned_by_self(),
+ hrs_ext_msg(this, "master old set MT safety protocol "
+ "outside a safepoint"));
+ }
+
+ return OldRegionSet::check_mt_safety();
+}
+
//////////////////// HumongousRegionSet ////////////////////
const char* HumongousRegionSet::verify_region_extra(HeapRegion* hr) {
@@ -103,11 +160,16 @@
// (b) If we're not at a safepoint, operations on the master
// humongous set should be invoked while holding the Heap_lock.
- guarantee((SafepointSynchronize::is_at_safepoint() &&
- (Thread::current()->is_VM_thread() ||
- OldSets_lock->owned_by_self())) ||
- (!SafepointSynchronize::is_at_safepoint() &&
- Heap_lock->owned_by_self()),
- hrs_ext_msg(this, "master humongous set MT safety protocol"));
+ if (SafepointSynchronize::is_at_safepoint()) {
+ guarantee(Thread::current()->is_VM_thread() ||
+ OldSets_lock->owned_by_self(),
+ hrs_ext_msg(this, "master humongous set MT safety protocol "
+ "at a safepoint"));
+ } else {
+ guarantee(Heap_lock->owned_by_self(),
+ hrs_ext_msg(this, "master humongous set MT safety protocol "
+ "outside a safepoint"));
+ }
+
return HumongousRegionSet::check_mt_safety();
}
--- a/hotspot/src/share/vm/gc_implementation/g1/heapRegionSets.hpp Thu Nov 17 10:46:00 2011 -0800
+++ b/hotspot/src/share/vm/gc_implementation/g1/heapRegionSets.hpp Wed Jul 05 17:56:12 2017 +0200
@@ -61,6 +61,30 @@
SecondaryFreeRegionList(const char* name) : FreeRegionList(name) { }
};
+//////////////////// OldRegionSet ////////////////////
+
+class OldRegionSet : public HeapRegionSet {
+protected:
+ virtual const char* verify_region_extra(HeapRegion* hr);
+
+ virtual bool regions_humongous() { return false; }
+ virtual bool regions_empty() { return false; }
+
+public:
+ OldRegionSet(const char* name) : HeapRegionSet(name) { }
+};
+
+//////////////////// MasterOldRegionSet ////////////////////
+
+class MasterOldRegionSet : public OldRegionSet {
+private:
+protected:
+ virtual bool check_mt_safety();
+
+public:
+ MasterOldRegionSet(const char* name) : OldRegionSet(name) { }
+};
+
//////////////////// HumongousRegionSet ////////////////////
class HumongousRegionSet : public HeapRegionSet {
--- a/hotspot/src/share/vm/gc_implementation/parallelScavenge/parallelScavengeHeap.cpp Thu Nov 17 10:46:00 2011 -0800
+++ b/hotspot/src/share/vm/gc_implementation/parallelScavenge/parallelScavengeHeap.cpp Wed Jul 05 17:56:12 2017 +0200
@@ -863,8 +863,6 @@
ensure_parsability(false); // no need to retire TLABs for verification
}
-void ParallelScavengeHeap::print() const { print_on(tty); }
-
void ParallelScavengeHeap::print_on(outputStream* st) const {
young_gen()->print_on(st);
old_gen()->print_on(st);
--- a/hotspot/src/share/vm/gc_implementation/parallelScavenge/parallelScavengeHeap.hpp Thu Nov 17 10:46:00 2011 -0800
+++ b/hotspot/src/share/vm/gc_implementation/parallelScavenge/parallelScavengeHeap.hpp Wed Jul 05 17:56:12 2017 +0200
@@ -246,8 +246,7 @@
jlong millis_since_last_gc();
void prepare_for_verify();
- void print() const;
- void print_on(outputStream* st) const;
+ virtual void print_on(outputStream* st) const;
virtual void print_gc_threads_on(outputStream* st) const;
virtual void gc_threads_do(ThreadClosure* tc) const;
virtual void print_tracing_info() const;
--- a/hotspot/src/share/vm/gc_interface/collectedHeap.hpp Thu Nov 17 10:46:00 2011 -0800
+++ b/hotspot/src/share/vm/gc_interface/collectedHeap.hpp Wed Jul 05 17:56:12 2017 +0200
@@ -590,13 +590,27 @@
void pre_full_gc_dump();
void post_full_gc_dump();
- virtual void print() const = 0;
+ // Print heap information on the given outputStream.
virtual void print_on(outputStream* st) const = 0;
+ // The default behavior is to call print_on() on tty.
+ virtual void print() const {
+ print_on(tty);
+ }
+ // Print more detailed heap information on the given
+ // outputStream. The default behaviour is to call print_on(). It is
+ // up to each subclass to override it and add any additional output
+ // it needs.
+ virtual void print_extended_on(outputStream* st) const {
+ print_on(st);
+ }
// Print all GC threads (other than the VM thread)
// used by this heap.
virtual void print_gc_threads_on(outputStream* st) const = 0;
- void print_gc_threads() { print_gc_threads_on(tty); }
+ // The default behavior is to call print_gc_threads_on() on tty.
+ void print_gc_threads() {
+ print_gc_threads_on(tty);
+ }
// Iterator for all GC threads (other than VM thread)
virtual void gc_threads_do(ThreadClosure* tc) const = 0;
--- a/hotspot/src/share/vm/gc_interface/gcCause.cpp Thu Nov 17 10:46:00 2011 -0800
+++ b/hotspot/src/share/vm/gc_interface/gcCause.cpp Wed Jul 05 17:56:12 2017 +0200
@@ -42,12 +42,6 @@
case _jvmti_force_gc:
return "JvmtiEnv ForceGarbageCollection";
- case _no_gc:
- return "No GC";
-
- case _allocation_failure:
- return "Allocation Failure";
-
case _gc_locker:
return "GCLocker Initiated GC";
@@ -57,6 +51,12 @@
case _heap_dump:
return "Heap Dump Initiated GC";
+ case _no_gc:
+ return "No GC";
+
+ case _allocation_failure:
+ return "Allocation Failure";
+
case _tenured_generation_full:
return "Tenured Generation Full";
@@ -78,6 +78,9 @@
case _old_generation_too_full_to_scavenge:
return "Old Generation Too Full To Scavenge";
+ case _adaptive_size_policy:
+ return "Ergonomics";
+
case _g1_inc_collection_pause:
return "G1 Evacuation Pause";
--- a/hotspot/src/share/vm/interpreter/bytecode.hpp Thu Nov 17 10:46:00 2011 -0800
+++ b/hotspot/src/share/vm/interpreter/bytecode.hpp Wed Jul 05 17:56:12 2017 +0200
@@ -234,6 +234,13 @@
is_invokespecial() ||
is_invokedynamic(); }
+ bool is_method_handle_invoke() const {
+ return (is_invokedynamic() ||
+ (is_invokevirtual() &&
+ method()->constants()->klass_ref_at_noresolve(index()) == vmSymbols::java_lang_invoke_MethodHandle() &&
+ methodOopDesc::is_method_handle_invoke_name(name())));
+ }
+
// Helper to skip verification. Used is_valid() to check if the result is really an invoke
inline friend Bytecode_invoke Bytecode_invoke_check(methodHandle method, int bci);
};
--- a/hotspot/src/share/vm/interpreter/bytecodeTracer.cpp Thu Nov 17 10:46:00 2011 -0800
+++ b/hotspot/src/share/vm/interpreter/bytecodeTracer.cpp Wed Jul 05 17:56:12 2017 +0200
@@ -241,7 +241,7 @@
st->print_cr(" not secondary entry?", i);
return false;
}
- i = cache->entry_at(i)->main_entry_index();
+ i = cache->entry_at(i)->main_entry_index() + constantPoolOopDesc::CPCACHE_INDEX_TAG;
goto check_cache_index;
} else {
st->print_cr(" not in cache[*]?", i);
--- a/hotspot/src/share/vm/interpreter/interpreterRuntime.cpp Thu Nov 17 10:46:00 2011 -0800
+++ b/hotspot/src/share/vm/interpreter/interpreterRuntime.cpp Wed Jul 05 17:56:12 2017 +0200
@@ -549,8 +549,8 @@
if (is_put && !is_static && klass->is_subclass_of(SystemDictionary::CallSite_klass()) && (info.name() == vmSymbols::target_name())) {
const jint direction = frame::interpreter_frame_expression_stack_direction();
- oop call_site = *((oop*) thread->last_frame().interpreter_frame_tos_at(-1 * direction));
- oop method_handle = *((oop*) thread->last_frame().interpreter_frame_tos_at( 0 * direction));
+ Handle call_site (THREAD, *((oop*) thread->last_frame().interpreter_frame_tos_at(-1 * direction)));
+ Handle method_handle(THREAD, *((oop*) thread->last_frame().interpreter_frame_tos_at( 0 * direction)));
assert(call_site ->is_a(SystemDictionary::CallSite_klass()), "must be");
assert(method_handle->is_a(SystemDictionary::MethodHandle_klass()), "must be");
--- a/hotspot/src/share/vm/libadt/vectset.cpp Thu Nov 17 10:46:00 2011 -0800
+++ b/hotspot/src/share/vm/libadt/vectset.cpp Wed Jul 05 17:56:12 2017 +0200
@@ -350,6 +350,21 @@
return (int)_xor;
}
+//------------------------------iterate----------------------------------------
+// Used by Set::print().
+class VSetI_ : public SetI_ {
+ VectorSetI vsi;
+public:
+ VSetI_( const VectorSet *vset, uint &elem ) : vsi(vset) { elem = vsi.elem; }
+
+ uint next(void) { ++vsi; return vsi.elem; }
+ int test(void) { return vsi.test(); }
+};
+
+SetI_ *VectorSet::iterate(uint &elem) const {
+ return new(ResourceObj::C_HEAP) VSetI_(this, elem);
+}
+
//=============================================================================
//------------------------------next-------------------------------------------
// Find and return the next element of a vector set, or return garbage and
--- a/hotspot/src/share/vm/libadt/vectset.hpp Thu Nov 17 10:46:00 2011 -0800
+++ b/hotspot/src/share/vm/libadt/vectset.hpp Wed Jul 05 17:56:12 2017 +0200
@@ -151,7 +151,7 @@
private:
- SetI_ *iterate(uint&) const { ShouldNotCallThis(); return NULL; } // Removed
+ SetI_ *iterate(uint&) const;
};
//------------------------------Iteration--------------------------------------
--- a/hotspot/src/share/vm/memory/genCollectedHeap.cpp Thu Nov 17 10:46:00 2011 -0800
+++ b/hotspot/src/share/vm/memory/genCollectedHeap.cpp Wed Jul 05 17:56:12 2017 +0200
@@ -1270,7 +1270,6 @@
rem_set()->verify();
}
-void GenCollectedHeap::print() const { print_on(tty); }
void GenCollectedHeap::print_on(outputStream* st) const {
for (int i = 0; i < _n_gens; i++) {
_gens[i]->print_on(st);
--- a/hotspot/src/share/vm/memory/genCollectedHeap.hpp Thu Nov 17 10:46:00 2011 -0800
+++ b/hotspot/src/share/vm/memory/genCollectedHeap.hpp Wed Jul 05 17:56:12 2017 +0200
@@ -360,8 +360,7 @@
void verify(bool allow_dirty, bool silent, VerifyOption option);
// Override.
- void print() const;
- void print_on(outputStream* st) const;
+ virtual void print_on(outputStream* st) const;
virtual void print_gc_threads_on(outputStream* st) const;
virtual void gc_threads_do(ThreadClosure* tc) const;
virtual void print_tracing_info() const;
--- a/hotspot/src/share/vm/memory/universe.cpp Thu Nov 17 10:46:00 2011 -0800
+++ b/hotspot/src/share/vm/memory/universe.cpp Wed Jul 05 17:56:12 2017 +0200
@@ -1281,11 +1281,17 @@
}
}
-void Universe::print() { print_on(gclog_or_tty); }
+void Universe::print() {
+ print_on(gclog_or_tty);
+}
-void Universe::print_on(outputStream* st) {
+void Universe::print_on(outputStream* st, bool extended) {
st->print_cr("Heap");
- heap()->print_on(st);
+ if (!extended) {
+ heap()->print_on(st);
+ } else {
+ heap()->print_extended_on(st);
+ }
}
void Universe::print_heap_at_SIGBREAK() {
@@ -1301,14 +1307,22 @@
st->print_cr("{Heap before GC invocations=%u (full %u):",
heap()->total_collections(),
heap()->total_full_collections());
- heap()->print_on(st);
+ if (!PrintHeapAtGCExtended) {
+ heap()->print_on(st);
+ } else {
+ heap()->print_extended_on(st);
+ }
}
void Universe::print_heap_after_gc(outputStream* st) {
st->print_cr("Heap after GC invocations=%u (full %u):",
heap()->total_collections(),
heap()->total_full_collections());
- heap()->print_on(st);
+ if (!PrintHeapAtGCExtended) {
+ heap()->print_on(st);
+ } else {
+ heap()->print_extended_on(st);
+ }
st->print_cr("}");
}
--- a/hotspot/src/share/vm/memory/universe.hpp Thu Nov 17 10:46:00 2011 -0800
+++ b/hotspot/src/share/vm/memory/universe.hpp Wed Jul 05 17:56:12 2017 +0200
@@ -414,9 +414,13 @@
static bool verify_in_progress() { return _verify_in_progress; }
static void verify(bool allow_dirty = true, bool silent = false,
VerifyOption option = VerifyOption_Default );
- static int verify_count() { return _verify_count; }
+ static int verify_count() { return _verify_count; }
+ // The default behavior is to call print_on() on gclog_or_tty.
static void print();
- static void print_on(outputStream* st);
+ // The extended parameter determines which method on the heap will
+ // be called: print_on() (extended == false) or print_extended_on()
+ // (extended == true).
+ static void print_on(outputStream* st, bool extended = false);
static void print_heap_at_SIGBREAK();
static void print_heap_before_gc() { print_heap_before_gc(gclog_or_tty); }
static void print_heap_after_gc() { print_heap_after_gc(gclog_or_tty); }
--- a/hotspot/src/share/vm/oops/arrayOop.cpp Thu Nov 17 10:46:00 2011 -0800
+++ b/hotspot/src/share/vm/oops/arrayOop.cpp Wed Jul 05 17:56:12 2017 +0200
@@ -23,9 +23,40 @@
*/
#include "precompiled.hpp"
+
+/////////////// Unit tests ///////////////
+
+#ifndef PRODUCT
+
#include "oops/arrayOop.hpp"
-#include "oops/objArrayOop.hpp"
-#include "oops/oop.inline.hpp"
-#include "oops/symbol.hpp"
+#include "utilities/globalDefinitions.hpp"
+
+bool arrayOopDesc::check_max_length_overflow(BasicType type) {
+ julong length = max_array_length(type);
+ julong bytes_per_element = type2aelembytes(type);
+ julong bytes = length * bytes_per_element + header_size_in_bytes();
+ return (julong)(size_t)bytes == bytes;
+}
+
+bool arrayOopDesc::test_max_array_length() {
+ tty->print_cr("test_max_array_length");
-// <<this page is intentionally left blank>>
+ assert(check_max_length_overflow(T_BOOLEAN), "size_t overflow for boolean array");
+ assert(check_max_length_overflow(T_CHAR), "size_t overflow for char array");
+ assert(check_max_length_overflow(T_FLOAT), "size_t overflow for float array");
+ assert(check_max_length_overflow(T_DOUBLE), "size_t overflow for double array");
+ assert(check_max_length_overflow(T_BYTE), "size_t overflow for byte array");
+ assert(check_max_length_overflow(T_SHORT), "size_t overflow for short array");
+ assert(check_max_length_overflow(T_INT), "size_t overflow for int array");
+ assert(check_max_length_overflow(T_LONG), "size_t overflow for long array");
+ assert(check_max_length_overflow(T_OBJECT), "size_t overflow for object array");
+ assert(check_max_length_overflow(T_ARRAY), "size_t overflow for array array");
+ assert(check_max_length_overflow(T_NARROWOOP), "size_t overflow for narrowOop array");
+
+ // T_VOID and T_ADDRESS are not supported by max_array_length()
+
+ return true;
+}
+
+
+#endif //PRODUCT
--- a/hotspot/src/share/vm/oops/arrayOop.hpp Thu Nov 17 10:46:00 2011 -0800
+++ b/hotspot/src/share/vm/oops/arrayOop.hpp Wed Jul 05 17:56:12 2017 +0200
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2011, 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
@@ -104,20 +104,32 @@
// Return the maximum length of an array of BasicType. The length can passed
// to typeArrayOop::object_size(scale, length, header_size) without causing an
- // overflow.
+ // overflow. We also need to make sure that this will not overflow a size_t on
+ // 32 bit platforms when we convert it to a byte size.
static int32_t max_array_length(BasicType type) {
assert(type >= 0 && type < T_CONFLICT, "wrong type");
assert(type2aelembytes(type) != 0, "wrong type");
- const int bytes_per_element = type2aelembytes(type);
- if (bytes_per_element < HeapWordSize) {
- return max_jint;
- }
- const int32_t max_words = align_size_down(max_jint, MinObjAlignment);
- const int32_t max_element_words = max_words - header_size(type);
- const int32_t words_per_element = bytes_per_element >> LogHeapWordSize;
- return max_element_words / words_per_element;
+ const size_t max_element_words_per_size_t =
+ align_size_down((SIZE_MAX/HeapWordSize - header_size(type)), MinObjAlignment);
+ const size_t max_elements_per_size_t =
+ HeapWordSize * max_element_words_per_size_t / type2aelembytes(type);
+ if ((size_t)max_jint < max_elements_per_size_t) {
+ // It should be ok to return max_jint here, but parts of the code
+ // (CollectedHeap, Klass::oop_oop_iterate(), and more) uses an int for
+ // passing around the size (in words) of an object. So, we need to avoid
+ // overflowing an int when we add the header. See CRs 4718400 and 7110613.
+ return align_size_down(max_jint - header_size(type), MinObjAlignment);
+ }
+ return (int32_t)max_elements_per_size_t;
}
+
+// for unit testing
+#ifndef PRODUCT
+ static bool check_max_length_overflow(BasicType type);
+ static int32_t old_max_array_length(BasicType type);
+ static bool test_max_array_length();
+#endif
};
#endif // SHARE_VM_OOPS_ARRAYOOP_HPP
--- a/hotspot/src/share/vm/oops/constantPoolKlass.cpp Thu Nov 17 10:46:00 2011 -0800
+++ b/hotspot/src/share/vm/oops/constantPoolKlass.cpp Wed Jul 05 17:56:12 2017 +0200
@@ -532,7 +532,7 @@
if (cp->tag_at(i).is_unresolved_klass()) {
// This will force loading of the class
klassOop klass = cp->klass_at(i, CHECK);
- if (klass->is_instance()) {
+ if (klass->klass_part()->oop_is_instance()) {
// Force initialization of class
instanceKlass::cast(klass)->initialize(CHECK);
}
--- a/hotspot/src/share/vm/opto/addnode.cpp Thu Nov 17 10:46:00 2011 -0800
+++ b/hotspot/src/share/vm/opto/addnode.cpp Wed Jul 05 17:56:12 2017 +0200
@@ -34,8 +34,6 @@
// Portions of code courtesy of Clifford Click
-#define MAXFLOAT ((float)3.40282346638528860e+38)
-
// Classic Add functionality. This covers all the usual 'add' behaviors for
// an algebraic ring. Add-integer, add-float, add-double, and binary-or are
// all inherited from this class. The various identity values are supplied
--- a/hotspot/src/share/vm/opto/c2_globals.hpp Thu Nov 17 10:46:00 2011 -0800
+++ b/hotspot/src/share/vm/opto/c2_globals.hpp Wed Jul 05 17:56:12 2017 +0200
@@ -201,7 +201,7 @@
diagnostic(bool, UnrollLimitCheck, true, \
"Additional overflow checks during loop unroll") \
\
- product(bool, OptimizeFill, false, \
+ product(bool, OptimizeFill, true, \
"convert fill/copy loops into intrinsic") \
\
develop(bool, TraceOptimizeFill, false, \
@@ -459,7 +459,7 @@
product(bool, UseOptoBiasInlining, true, \
"Generate biased locking code in C2 ideal graph") \
\
- product(bool, OptimizeStringConcat, false, \
+ product(bool, OptimizeStringConcat, true, \
"Optimize the construction of Strings by StringBuilder") \
\
notproduct(bool, PrintOptimizeStringConcat, false, \
--- a/hotspot/src/share/vm/opto/callGenerator.cpp Thu Nov 17 10:46:00 2011 -0800
+++ b/hotspot/src/share/vm/opto/callGenerator.cpp Wed Jul 05 17:56:12 2017 +0200
@@ -775,15 +775,15 @@
Node* bol = NULL;
int bc = jvms->method()->java_code_at_bci(jvms->bci());
- if (bc == Bytecodes::_invokespecial) {
- // This is the selectAlternative idiom for guardWithTest
+ if (bc != Bytecodes::_invokedynamic) {
+ // This is the selectAlternative idiom for guardWithTest or
+ // similar idioms.
Node* receiver = kit.argument(0);
// Check if the MethodHandle is the expected one
Node* cmp = gvn.transform(new(kit.C, 3) CmpPNode(receiver, predicted_mh));
bol = gvn.transform(new(kit.C, 2) BoolNode(cmp, BoolTest::eq) );
} else {
- assert(bc == Bytecodes::_invokedynamic, "must be");
// Get the constant pool cache from the caller class.
ciMethod* caller_method = jvms->method();
ciBytecodeStream str(caller_method);
--- a/hotspot/src/share/vm/opto/compile.cpp Thu Nov 17 10:46:00 2011 -0800
+++ b/hotspot/src/share/vm/opto/compile.cpp Wed Jul 05 17:56:12 2017 +0200
@@ -346,15 +346,15 @@
// Disconnect all useless nodes by disconnecting those at the boundary.
void Compile::remove_useless_nodes(Unique_Node_List &useful) {
uint next = 0;
- while( next < useful.size() ) {
+ while (next < useful.size()) {
Node *n = useful.at(next++);
// Use raw traversal of out edges since this code removes out edges
int max = n->outcnt();
- for (int j = 0; j < max; ++j ) {
+ for (int j = 0; j < max; ++j) {
Node* child = n->raw_out(j);
- if( ! useful.member(child) ) {
- assert( !child->is_top() || child != top(),
- "If top is cached in Compile object it is in useful list");
+ if (! useful.member(child)) {
+ assert(!child->is_top() || child != top(),
+ "If top is cached in Compile object it is in useful list");
// Only need to remove this out-edge to the useless node
n->raw_del_out(j);
--j;
@@ -362,7 +362,14 @@
}
}
if (n->outcnt() == 1 && n->has_special_unique_user()) {
- record_for_igvn( n->unique_out() );
+ record_for_igvn(n->unique_out());
+ }
+ }
+ // Remove useless macro and predicate opaq nodes
+ for (int i = C->macro_count()-1; i >= 0; i--) {
+ Node* n = C->macro_node(i);
+ if (!useful.member(n)) {
+ remove_macro_node(n);
}
}
debug_only(verify_graph_edges(true/*check for no_dead_code*/);)
@@ -719,6 +726,7 @@
while (_late_inlines.length() > 0) {
CallGenerator* cg = _late_inlines.pop();
cg->do_late_inline();
+ if (failing()) return;
}
}
assert(_late_inlines.length() == 0, "should have been processed");
@@ -1691,13 +1699,20 @@
// Perform escape analysis
if (_do_escape_analysis && ConnectionGraph::has_candidates(this)) {
+ if (has_loops()) {
+ // Cleanup graph (remove dead nodes).
+ TracePhase t2("idealLoop", &_t_idealLoop, true);
+ PhaseIdealLoop ideal_loop( igvn, false, true );
+ if (major_progress()) print_method("PhaseIdealLoop before EA", 2);
+ if (failing()) return;
+ }
TracePhase t2("escapeAnalysis", &_t_escapeAnalysis, true);
ConnectionGraph::do_analysis(this, &igvn);
if (failing()) return;
igvn.optimize();
- print_method("Iter GVN 3", 2);
+ print_method("Iter GVN after EA", 2);
if (failing()) return;
--- a/hotspot/src/share/vm/opto/escape.cpp Thu Nov 17 10:46:00 2011 -0800
+++ b/hotspot/src/share/vm/opto/escape.cpp Wed Jul 05 17:56:12 2017 +0200
@@ -108,14 +108,16 @@
// Add ConP(#NULL) and ConN(#NULL) nodes.
Node* oop_null = igvn->zerocon(T_OBJECT);
_oop_null = oop_null->_idx;
- assert(_oop_null < C->unique(), "should be created already");
+ assert(_oop_null < nodes_size(), "should be created already");
add_node(oop_null, PointsToNode::JavaObject, PointsToNode::NoEscape, true);
if (UseCompressedOops) {
Node* noop_null = igvn->zerocon(T_NARROWOOP);
_noop_null = noop_null->_idx;
- assert(_noop_null < C->unique(), "should be created already");
+ assert(_noop_null < nodes_size(), "should be created already");
add_node(noop_null, PointsToNode::JavaObject, PointsToNode::NoEscape, true);
+ } else {
+ _noop_null = _oop_null; // Should be initialized
}
}
@@ -174,6 +176,9 @@
}
void ConnectionGraph::set_escape_state(uint ni, PointsToNode::EscapeState es) {
+ // Don't change non-escaping state of NULL pointer.
+ if (ni == _noop_null || ni == _oop_null)
+ return;
PointsToNode *npt = ptnode_adr(ni);
PointsToNode::EscapeState old_es = npt->escape_state();
if (es > old_es)
@@ -231,8 +236,8 @@
}
if (orig_es != es) {
// cache the computed escape state
- assert(es != PointsToNode::UnknownEscape, "should have computed an escape state");
- ptnode_adr(idx)->set_escape_state(es);
+ assert(es > orig_es, "should have computed an escape state");
+ set_escape_state(idx, es);
} // orig_es could be PointsToNode::UnknownEscape
return es;
}
@@ -334,7 +339,7 @@
add_pointsto_edge(ni, etgt);
if(etgt == _phantom_object) {
// Special case - field set outside (globally escaping).
- ptn->set_escape_state(PointsToNode::GlobalEscape);
+ set_escape_state(ni, PointsToNode::GlobalEscape);
}
} else if (et == PointsToNode::DeferredEdge) {
deferred_edges->append(etgt);
@@ -373,16 +378,17 @@
// whose offset matches "offset".
void ConnectionGraph::add_deferred_edge_to_fields(uint from_i, uint adr_i, int offs) {
PointsToNode* an = ptnode_adr(adr_i);
+ bool is_alloc = an->_node->is_Allocate();
for (uint fe = 0; fe < an->edge_count(); fe++) {
assert(an->edge_type(fe) == PointsToNode::FieldEdge, "expecting a field edge");
int fi = an->edge_target(fe);
PointsToNode* pf = ptnode_adr(fi);
- int po = pf->offset();
- if (pf->edge_count() == 0) {
- // we have not seen any stores to this field, assume it was set outside this method
+ int offset = pf->offset();
+ if (!is_alloc) {
+ // Assume the field was set outside this method if it is not Allocation
add_pointsto_edge(fi, _phantom_object);
}
- if (po == offs || po == Type::OffsetBot || offs == Type::OffsetBot) {
+ if (offset == offs || offset == Type::OffsetBot || offs == Type::OffsetBot) {
add_deferred_edge(from_i, fi);
}
}
@@ -1036,7 +1042,7 @@
PointsToNode::EscapeState es = escape_state(alloc);
// We have an allocation or call which returns a Java object,
// see if it is unescaped.
- if (es != PointsToNode::NoEscape || !ptn->_scalar_replaceable)
+ if (es != PointsToNode::NoEscape || !ptn->scalar_replaceable())
continue;
// Find CheckCastPP for the allocate or for the return value of a call
@@ -1085,7 +1091,7 @@
// so it could be eliminated.
alloc->as_Allocate()->_is_scalar_replaceable = true;
}
- set_escape_state(n->_idx, es);
+ set_escape_state(n->_idx, es); // CheckCastPP escape state
// in order for an object to be scalar-replaceable, it must be:
// - a direct allocation (not a call returning an object)
// - non-escaping
@@ -1097,15 +1103,14 @@
set_map(n->_idx, alloc);
const TypeOopPtr *t = igvn->type(n)->isa_oopptr();
if (t == NULL)
- continue; // not a TypeInstPtr
+ continue; // not a TypeOopPtr
tinst = t->cast_to_exactness(true)->is_oopptr()->cast_to_instance_id(ni);
igvn->hash_delete(n);
igvn->set_type(n, tinst);
n->raise_bottom_type(tinst);
igvn->hash_insert(n);
record_for_optimizer(n);
- if (alloc->is_Allocate() && ptn->_scalar_replaceable &&
- (t->isa_instptr() || t->isa_aryptr())) {
+ if (alloc->is_Allocate() && (t->isa_instptr() || t->isa_aryptr())) {
// First, put on the worklist all Field edges from Connection Graph
// which is more accurate then putting immediate users from Ideal Graph.
@@ -1533,7 +1538,8 @@
worklist_init.push(C->root());
}
- GrowableArray<int> cg_worklist;
+ GrowableArray<Node*> alloc_worklist;
+ GrowableArray<Node*> addp_worklist;
PhaseGVN* igvn = _igvn;
bool has_allocations = false;
@@ -1546,11 +1552,13 @@
if (n->is_Allocate() || n->is_CallStaticJava() &&
ptnode_adr(n->_idx)->node_type() == PointsToNode::JavaObject) {
has_allocations = true;
+ if (n->is_Allocate())
+ alloc_worklist.append(n);
}
if(n->is_AddP()) {
// Collect address nodes. Use them during stage 3 below
// to build initial connection graph field edges.
- cg_worklist.append(n->_idx);
+ addp_worklist.append(n);
} else if (n->is_MergeMem()) {
// Collect all MergeMem nodes to add memory slices for
// scalar replaceable objects in split_unique_types().
@@ -1576,10 +1584,9 @@
// 3. Pass to create initial fields edges (JavaObject -F-> AddP)
// to reduce number of iterations during stage 4 below.
- uint cg_length = cg_worklist.length();
- for( uint next = 0; next < cg_length; ++next ) {
- int ni = cg_worklist.at(next);
- Node* n = ptnode_adr(ni)->_node;
+ uint addp_length = addp_worklist.length();
+ for( uint next = 0; next < addp_length; ++next ) {
+ Node* n = addp_worklist.at(next);
Node* base = get_addp_base(n);
if (base->is_Proj())
base = base->in(0);
@@ -1589,7 +1596,7 @@
}
}
- cg_worklist.clear();
+ GrowableArray<int> cg_worklist;
cg_worklist.append(_phantom_object);
GrowableArray<uint> worklist;
@@ -1648,73 +1655,44 @@
Arena* arena = Thread::current()->resource_area();
VectorSet visited(arena);
+
+ // 5. Find fields initializing values for not escaped allocations
+ uint alloc_length = alloc_worklist.length();
+ for (uint next = 0; next < alloc_length; ++next) {
+ Node* n = alloc_worklist.at(next);
+ if (ptnode_adr(n->_idx)->escape_state() == PointsToNode::NoEscape) {
+ find_init_values(n, &visited, igvn);
+ }
+ }
+
worklist.clear();
- // 5. Remove deferred edges from the graph and adjust
- // escape state of nonescaping objects.
- cg_length = cg_worklist.length();
- for( uint next = 0; next < cg_length; ++next ) {
+ // 6. Remove deferred edges from the graph.
+ uint cg_length = cg_worklist.length();
+ for (uint next = 0; next < cg_length; ++next) {
int ni = cg_worklist.at(next);
PointsToNode* ptn = ptnode_adr(ni);
PointsToNode::NodeType nt = ptn->node_type();
if (nt == PointsToNode::LocalVar || nt == PointsToNode::Field) {
remove_deferred(ni, &worklist, &visited);
Node *n = ptn->_node;
- if (n->is_AddP()) {
- // Search for objects which are not scalar replaceable
- // and adjust their escape state.
- adjust_escape_state(ni, igvn);
- }
}
}
- // 6. Propagate escape states.
- worklist.clear();
- bool has_non_escaping_obj = false;
-
- // push all GlobalEscape nodes on the worklist
- for( uint next = 0; next < cg_length; ++next ) {
- int nk = cg_worklist.at(next);
- if (ptnode_adr(nk)->escape_state() == PointsToNode::GlobalEscape)
- worklist.push(nk);
- }
- // mark all nodes reachable from GlobalEscape nodes
- while(worklist.length() > 0) {
- PointsToNode* ptn = ptnode_adr(worklist.pop());
- uint e_cnt = ptn->edge_count();
- for (uint ei = 0; ei < e_cnt; ei++) {
- uint npi = ptn->edge_target(ei);
- PointsToNode *np = ptnode_adr(npi);
- if (np->escape_state() < PointsToNode::GlobalEscape) {
- np->set_escape_state(PointsToNode::GlobalEscape);
- worklist.push(npi);
- }
- }
+ // 7. Adjust escape state of nonescaping objects.
+ for (uint next = 0; next < addp_length; ++next) {
+ Node* n = addp_worklist.at(next);
+ adjust_escape_state(n);
}
- // push all ArgEscape nodes on the worklist
- for( uint next = 0; next < cg_length; ++next ) {
- int nk = cg_worklist.at(next);
- if (ptnode_adr(nk)->escape_state() == PointsToNode::ArgEscape)
- worklist.push(nk);
- }
+ // 8. Propagate escape states.
+ worklist.clear();
+
+ // mark all nodes reachable from GlobalEscape nodes
+ (void)propagate_escape_state(&cg_worklist, &worklist, PointsToNode::GlobalEscape);
+
// mark all nodes reachable from ArgEscape nodes
- while(worklist.length() > 0) {
- PointsToNode* ptn = ptnode_adr(worklist.pop());
- if (ptn->node_type() == PointsToNode::JavaObject)
- has_non_escaping_obj = true; // Non GlobalEscape
- uint e_cnt = ptn->edge_count();
- for (uint ei = 0; ei < e_cnt; ei++) {
- uint npi = ptn->edge_target(ei);
- PointsToNode *np = ptnode_adr(npi);
- if (np->escape_state() < PointsToNode::ArgEscape) {
- np->set_escape_state(PointsToNode::ArgEscape);
- worklist.push(npi);
- }
- }
- }
-
- GrowableArray<Node*> alloc_worklist;
+ bool has_non_escaping_obj = propagate_escape_state(&cg_worklist, &worklist, PointsToNode::ArgEscape);
// push all NoEscape nodes on the worklist
for( uint next = 0; next < cg_length; ++next ) {
@@ -1722,15 +1700,20 @@
if (ptnode_adr(nk)->escape_state() == PointsToNode::NoEscape)
worklist.push(nk);
}
+ alloc_worklist.clear();
// mark all nodes reachable from NoEscape nodes
while(worklist.length() > 0) {
- PointsToNode* ptn = ptnode_adr(worklist.pop());
- if (ptn->node_type() == PointsToNode::JavaObject)
- has_non_escaping_obj = true; // Non GlobalEscape
+ uint nk = worklist.pop();
+ PointsToNode* ptn = ptnode_adr(nk);
+ if (ptn->node_type() == PointsToNode::JavaObject &&
+ !(nk == _noop_null || nk == _oop_null))
+ has_non_escaping_obj = true; // Non Escape
Node* n = ptn->_node;
- if (n->is_Allocate() && ptn->_scalar_replaceable ) {
+ bool scalar_replaceable = ptn->scalar_replaceable();
+ if (n->is_Allocate() && scalar_replaceable) {
// Push scalar replaceable allocations on alloc_worklist
- // for processing in split_unique_types().
+ // for processing in split_unique_types(). Note,
+ // following code may change scalar_replaceable value.
alloc_worklist.append(n);
}
uint e_cnt = ptn->edge_count();
@@ -1738,7 +1721,14 @@
uint npi = ptn->edge_target(ei);
PointsToNode *np = ptnode_adr(npi);
if (np->escape_state() < PointsToNode::NoEscape) {
- np->set_escape_state(PointsToNode::NoEscape);
+ set_escape_state(npi, PointsToNode::NoEscape);
+ if (!scalar_replaceable) {
+ np->set_scalar_replaceable(false);
+ }
+ worklist.push(npi);
+ } else if (np->scalar_replaceable() && !scalar_replaceable) {
+ // Propagate scalar_replaceable value.
+ np->set_scalar_replaceable(false);
worklist.push(npi);
}
}
@@ -1747,7 +1737,12 @@
_collecting = false;
assert(C->unique() == nodes_size(), "there should be no new ideal nodes during ConnectionGraph build");
- if (EliminateLocks) {
+ assert(ptnode_adr(_oop_null)->escape_state() == PointsToNode::NoEscape, "sanity");
+ if (UseCompressedOops) {
+ assert(ptnode_adr(_noop_null)->escape_state() == PointsToNode::NoEscape, "sanity");
+ }
+
+ if (EliminateLocks && has_non_escaping_obj) {
// Mark locks before changing ideal graph.
int cnt = C->macro_count();
for( int i=0; i < cnt; i++ ) {
@@ -1772,7 +1767,18 @@
}
#endif
- bool has_scalar_replaceable_candidates = alloc_worklist.length() > 0;
+ bool has_scalar_replaceable_candidates = false;
+ alloc_length = alloc_worklist.length();
+ for (uint next = 0; next < alloc_length; ++next) {
+ Node* n = alloc_worklist.at(next);
+ PointsToNode* ptn = ptnode_adr(n->_idx);
+ assert(ptn->escape_state() == PointsToNode::NoEscape, "sanity");
+ if (ptn->scalar_replaceable()) {
+ has_scalar_replaceable_candidates = true;
+ break;
+ }
+ }
+
if ( has_scalar_replaceable_candidates &&
C->AliasLevel() >= 3 && EliminateAllocations ) {
@@ -1801,53 +1807,32 @@
return has_non_escaping_obj;
}
-// Adjust escape state after Connection Graph is built.
-void ConnectionGraph::adjust_escape_state(int nidx, PhaseTransform* phase) {
- PointsToNode* ptn = ptnode_adr(nidx);
- Node* n = ptn->_node;
- assert(n->is_AddP(), "Should be called for AddP nodes only");
- // Search for objects which are not scalar replaceable.
- // Mark their escape state as ArgEscape to propagate the state
- // to referenced objects.
- // Note: currently there are no difference in compiler optimizations
- // for ArgEscape objects and NoEscape objects which are not
- // scalar replaceable.
+// Find fields initializing values for allocations.
+void ConnectionGraph::find_init_values(Node* alloc, VectorSet* visited, PhaseTransform* phase) {
+ assert(alloc->is_Allocate(), "Should be called for Allocate nodes only");
+ PointsToNode* pta = ptnode_adr(alloc->_idx);
+ assert(pta->escape_state() == PointsToNode::NoEscape, "Not escaped Allocate nodes only");
+ InitializeNode* ini = alloc->as_Allocate()->initialization();
Compile* C = _compile;
-
- int offset = ptn->offset();
- Node* base = get_addp_base(n);
- VectorSet* ptset = PointsTo(base);
- int ptset_size = ptset->Size();
-
+ visited->Reset();
// Check if a oop field's initializing value is recorded and add
// a corresponding NULL field's value if it is not recorded.
// Connection Graph does not record a default initialization by NULL
// captured by Initialize node.
//
- // Note: it will disable scalar replacement in some cases:
- //
- // Point p[] = new Point[1];
- // p[0] = new Point(); // Will be not scalar replaced
- //
- // but it will save us from incorrect optimizations in next cases:
- //
- // Point p[] = new Point[1];
- // if ( x ) p[0] = new Point(); // Will be not scalar replaced
- //
- // Do a simple control flow analysis to distinguish above cases.
- //
- if (offset != Type::OffsetBot && ptset_size == 1) {
- uint elem = ptset->getelem(); // Allocation node's index
- // It does not matter if it is not Allocation node since
- // only non-escaping allocations are scalar replaced.
- if (ptnode_adr(elem)->_node->is_Allocate() &&
- ptnode_adr(elem)->escape_state() == PointsToNode::NoEscape) {
- AllocateNode* alloc = ptnode_adr(elem)->_node->as_Allocate();
- InitializeNode* ini = alloc->initialization();
+ uint ae_cnt = pta->edge_count();
+ for (uint ei = 0; ei < ae_cnt; ei++) {
+ uint nidx = pta->edge_target(ei); // Field (AddP)
+ PointsToNode* ptn = ptnode_adr(nidx);
+ assert(ptn->_node->is_AddP(), "Should be AddP nodes only");
+ int offset = ptn->offset();
+ if (offset != Type::OffsetBot &&
+ offset != oopDesc::klass_offset_in_bytes() &&
+ !visited->test_set(offset)) {
// Check only oop fields.
- const Type* adr_type = n->as_AddP()->bottom_type();
+ const Type* adr_type = ptn->_node->as_AddP()->bottom_type();
BasicType basic_field_type = T_INT;
if (adr_type->isa_instptr()) {
ciField* field = C->alias_type(adr_type->isa_instptr())->field();
@@ -1857,12 +1842,20 @@
// Ignore non field load (for example, klass load)
}
} else if (adr_type->isa_aryptr()) {
- const Type* elemtype = adr_type->isa_aryptr()->elem();
- basic_field_type = elemtype->array_element_basic_type();
+ if (offset != arrayOopDesc::length_offset_in_bytes()) {
+ const Type* elemtype = adr_type->isa_aryptr()->elem();
+ basic_field_type = elemtype->array_element_basic_type();
+ } else {
+ // Ignore array length load
+ }
+#ifdef ASSERT
} else {
- // Raw pointers are used for initializing stores so skip it.
+ // Raw pointers are used for initializing stores so skip it
+ // since it should be recorded already
+ Node* base = get_addp_base(ptn->_node);
assert(adr_type->isa_rawptr() && base->is_Proj() &&
(base->in(0) == alloc),"unexpected pointer type");
+#endif
}
if (basic_field_type == T_OBJECT ||
basic_field_type == T_NARROWOOP ||
@@ -1877,18 +1870,33 @@
// Check for a store which follows allocation without branches.
// For example, a volatile field store is not collected
// by Initialize node. TODO: it would be nice to use idom() here.
- for (DUIterator_Fast imax, i = n->fast_outs(imax); i < imax; i++) {
- store = n->fast_out(i);
- if (store->is_Store() && store->in(0) != NULL) {
- Node* ctrl = store->in(0);
- while(!(ctrl == ini || ctrl == alloc || ctrl == NULL ||
- ctrl == C->root() || ctrl == C->top() || ctrl->is_Region() ||
- ctrl->is_IfTrue() || ctrl->is_IfFalse())) {
- ctrl = ctrl->in(0);
- }
- if (ctrl == ini || ctrl == alloc) {
- value = store->in(MemNode::ValueIn);
- break;
+ //
+ // Search all references to the same field which use different
+ // AddP nodes, for example, in the next case:
+ //
+ // Point p[] = new Point[1];
+ // if ( x ) { p[0] = new Point(); p[0].x = x; }
+ // if ( p[0] != null ) { y = p[0].x; } // has CastPP
+ //
+ for (uint next = ei; (next < ae_cnt) && (value == NULL); next++) {
+ uint fpi = pta->edge_target(next); // Field (AddP)
+ PointsToNode *ptf = ptnode_adr(fpi);
+ if (ptf->offset() == offset) {
+ Node* nf = ptf->_node;
+ for (DUIterator_Fast imax, i = nf->fast_outs(imax); i < imax; i++) {
+ store = nf->fast_out(i);
+ if (store->is_Store() && store->in(0) != NULL) {
+ Node* ctrl = store->in(0);
+ while(!(ctrl == ini || ctrl == alloc || ctrl == NULL ||
+ ctrl == C->root() || ctrl == C->top() || ctrl->is_Region() ||
+ ctrl->is_IfTrue() || ctrl->is_IfFalse())) {
+ ctrl = ctrl->in(0);
+ }
+ if (ctrl == ini || ctrl == alloc) {
+ value = store->in(MemNode::ValueIn);
+ break;
+ }
+ }
}
}
}
@@ -1897,21 +1905,35 @@
if (value == NULL || value != ptnode_adr(value->_idx)->_node) {
// A field's initializing value was not recorded. Add NULL.
uint null_idx = UseCompressedOops ? _noop_null : _oop_null;
- add_pointsto_edge(nidx, null_idx);
+ add_edge_from_fields(alloc->_idx, null_idx, offset);
}
}
}
}
+}
+
+// Adjust escape state after Connection Graph is built.
+void ConnectionGraph::adjust_escape_state(Node* n) {
+ PointsToNode* ptn = ptnode_adr(n->_idx);
+ assert(n->is_AddP(), "Should be called for AddP nodes only");
+ // Search for objects which are not scalar replaceable
+ // and mark them to propagate the state to referenced objects.
+ //
+
+ int offset = ptn->offset();
+ Node* base = get_addp_base(n);
+ VectorSet* ptset = PointsTo(base);
+ int ptset_size = ptset->Size();
// An object is not scalar replaceable if the field which may point
// to it has unknown offset (unknown element of an array of objects).
//
+
if (offset == Type::OffsetBot) {
uint e_cnt = ptn->edge_count();
for (uint ei = 0; ei < e_cnt; ei++) {
uint npi = ptn->edge_target(ei);
- set_escape_state(npi, PointsToNode::ArgEscape);
- ptnode_adr(npi)->_scalar_replaceable = false;
+ ptnode_adr(npi)->set_scalar_replaceable(false);
}
}
@@ -1930,20 +1952,62 @@
// to unknown field (unknown element for arrays, offset is OffsetBot).
//
// Or the address may point to more then one object. This may produce
- // the false positive result (set scalar_replaceable to false)
+ // the false positive result (set not scalar replaceable)
// since the flow-insensitive escape analysis can't separate
// the case when stores overwrite the field's value from the case
// when stores happened on different control branches.
//
+ // Note: it will disable scalar replacement in some cases:
+ //
+ // Point p[] = new Point[1];
+ // p[0] = new Point(); // Will be not scalar replaced
+ //
+ // but it will save us from incorrect optimizations in next cases:
+ //
+ // Point p[] = new Point[1];
+ // if ( x ) p[0] = new Point(); // Will be not scalar replaced
+ //
if (ptset_size > 1 || ptset_size != 0 &&
(has_LoadStore || offset == Type::OffsetBot)) {
for( VectorSetI j(ptset); j.test(); ++j ) {
- set_escape_state(j.elem, PointsToNode::ArgEscape);
- ptnode_adr(j.elem)->_scalar_replaceable = false;
+ ptnode_adr(j.elem)->set_scalar_replaceable(false);
}
}
}
+// Propagate escape states to referenced nodes.
+bool ConnectionGraph::propagate_escape_state(GrowableArray<int>* cg_worklist,
+ GrowableArray<uint>* worklist,
+ PointsToNode::EscapeState esc_state) {
+ bool has_java_obj = false;
+
+ // push all nodes with the same escape state on the worklist
+ uint cg_length = cg_worklist->length();
+ for (uint next = 0; next < cg_length; ++next) {
+ int nk = cg_worklist->at(next);
+ if (ptnode_adr(nk)->escape_state() == esc_state)
+ worklist->push(nk);
+ }
+ // mark all reachable nodes
+ while (worklist->length() > 0) {
+ PointsToNode* ptn = ptnode_adr(worklist->pop());
+ if (ptn->node_type() == PointsToNode::JavaObject) {
+ has_java_obj = true;
+ }
+ uint e_cnt = ptn->edge_count();
+ for (uint ei = 0; ei < e_cnt; ei++) {
+ uint npi = ptn->edge_target(ei);
+ PointsToNode *np = ptnode_adr(npi);
+ if (np->escape_state() < esc_state) {
+ set_escape_state(npi, esc_state);
+ worklist->push(npi);
+ }
+ }
+ }
+ // Has not escaping java objects
+ return has_java_obj && (esc_state < PointsToNode::GlobalEscape);
+}
+
void ConnectionGraph::process_call_arguments(CallNode *call, PhaseTransform *phase) {
switch (call->Opcode()) {
@@ -2100,6 +2164,7 @@
} else {
es = PointsToNode::NoEscape;
edge_to = call_idx;
+ assert(ptnode_adr(call_idx)->scalar_replaceable(), "sanity");
}
set_escape_state(call_idx, es);
add_pointsto_edge(resproj_idx, edge_to);
@@ -2123,10 +2188,11 @@
} else {
es = PointsToNode::NoEscape;
edge_to = call_idx;
+ assert(ptnode_adr(call_idx)->scalar_replaceable(), "sanity");
int length = call->in(AllocateNode::ALength)->find_int_con(-1);
if (length < 0 || length > EliminateAllocationArraySizeLimit) {
// Not scalar replaceable if the length is not constant or too big.
- ptnode_adr(call_idx)->_scalar_replaceable = false;
+ ptnode_adr(call_idx)->set_scalar_replaceable(false);
}
}
set_escape_state(call_idx, es);
@@ -2168,11 +2234,12 @@
// Mark it as NoEscape so that objects referenced by
// it's fields will be marked as NoEscape at least.
set_escape_state(call_idx, PointsToNode::NoEscape);
+ ptnode_adr(call_idx)->set_scalar_replaceable(false);
add_pointsto_edge(resproj_idx, call_idx);
copy_dependencies = true;
} else if (call_analyzer->is_return_local()) {
// determine whether any arguments are returned
- set_escape_state(call_idx, PointsToNode::NoEscape);
+ set_escape_state(call_idx, PointsToNode::ArgEscape);
bool ret_arg = false;
for (uint i = TypeFunc::Parms; i < d->cnt(); i++) {
const Type* at = d->field_at(i);
@@ -2189,7 +2256,6 @@
add_pointsto_edge(resproj_idx, arg->_idx);
else
add_deferred_edge(resproj_idx, arg->_idx);
- arg_esp->_hidden_alias = true;
}
}
}
@@ -2198,18 +2264,12 @@
set_escape_state(call_idx, PointsToNode::GlobalEscape);
add_pointsto_edge(resproj_idx, _phantom_object);
}
- copy_dependencies = true;
+ if (done) {
+ copy_dependencies = true;
+ }
} else {
set_escape_state(call_idx, PointsToNode::GlobalEscape);
add_pointsto_edge(resproj_idx, _phantom_object);
- for (uint i = TypeFunc::Parms; i < d->cnt(); i++) {
- const Type* at = d->field_at(i);
- if (at->isa_oopptr() != NULL) {
- Node *arg = call->in(i)->uncast();
- PointsToNode *arg_esp = ptnode_adr(arg->_idx);
- arg_esp->_hidden_alias = true;
- }
- }
}
if (copy_dependencies)
call_analyzer->copy_dependencies(_compile->dependencies());
--- a/hotspot/src/share/vm/opto/escape.hpp Thu Nov 17 10:46:00 2011 -0800
+++ b/hotspot/src/share/vm/opto/escape.hpp Wed Jul 05 17:56:12 2017 +0200
@@ -74,7 +74,7 @@
// C2 does not have local variables. However for the purposes of constructing
// the connection graph, the following IR nodes are treated as local variables:
// Phi (pointer values)
-// LoadP
+// LoadP, LoadN
// Proj#5 (value returned from callnodes including allocations)
// CheckCastPP, CastPP
//
@@ -84,7 +84,7 @@
//
// The following node types are JavaObject:
//
-// top()
+// phantom_object (general globally escaped object)
// Allocate
// AllocateArray
// Parm (for incoming arguments)
@@ -93,6 +93,7 @@
// ConP
// LoadKlass
// ThreadLocal
+// CallStaticJava (which returns Object)
//
// AddP nodes are fields.
//
@@ -130,10 +131,12 @@
typedef enum {
UnknownEscape = 0,
- NoEscape = 1, // A scalar replaceable object with unique type.
- ArgEscape = 2, // An object passed as argument or referenced by
- // argument (and not globally escape during call).
- GlobalEscape = 3 // An object escapes the method and thread.
+ NoEscape = 1, // An object does not escape method or thread and it is
+ // not passed to call. It could be replaced with scalar.
+ ArgEscape = 2, // An object does not escape method or thread but it is
+ // passed as argument to call or referenced by argument
+ // and it does not escape during call.
+ GlobalEscape = 3 // An object escapes the method or thread.
} EscapeState;
typedef enum {
@@ -153,28 +156,25 @@
NodeType _type;
EscapeState _escape;
- GrowableArray<uint>* _edges; // outgoing edges
+ GrowableArray<uint>* _edges; // outgoing edges
+ Node* _node; // Ideal node corresponding to this PointsTo node.
+ int _offset; // Object fields offsets.
+ bool _scalar_replaceable; // Not escaped object could be replaced with scalar
public:
- Node* _node; // Ideal node corresponding to this PointsTo node.
- int _offset; // Object fields offsets.
- bool _scalar_replaceable;// Not escaped object could be replaced with scalar
- bool _hidden_alias; // This node is an argument to a function.
- // which may return it creating a hidden alias.
-
PointsToNode():
_type(UnknownType),
_escape(UnknownEscape),
_edges(NULL),
_node(NULL),
_offset(-1),
- _scalar_replaceable(true),
- _hidden_alias(false) {}
+ _scalar_replaceable(true) {}
EscapeState escape_state() const { return _escape; }
NodeType node_type() const { return _type;}
int offset() { return _offset;}
+ bool scalar_replaceable() { return _scalar_replaceable;}
void set_offset(int offs) { _offset = offs;}
void set_escape_state(EscapeState state) { _escape = state; }
@@ -182,6 +182,7 @@
assert(_type == UnknownType || _type == ntype, "Can't change node type");
_type = ntype;
}
+ void set_scalar_replaceable(bool v) { _scalar_replaceable = v; }
// count of outgoing edges
uint edge_count() const { return (_edges == NULL) ? 0 : _edges->length(); }
@@ -233,8 +234,8 @@
// that pointer values loaded from
// a field which has not been set
// are assumed to point to.
- uint _oop_null; // ConP(#NULL)
- uint _noop_null; // ConN(#NULL)
+ uint _oop_null; // ConP(#NULL)->_idx
+ uint _noop_null; // ConN(#NULL)->_idx
Compile * _compile; // Compile object for current compilation
PhaseIterGVN * _igvn; // Value numbering
@@ -339,8 +340,16 @@
// Set the escape state of a node
void set_escape_state(uint ni, PointsToNode::EscapeState es);
+ // Find fields initializing values for allocations.
+ void find_init_values(Node* n, VectorSet* visited, PhaseTransform* phase);
+
// Adjust escape state after Connection Graph is built.
- void adjust_escape_state(int nidx, PhaseTransform* phase);
+ void adjust_escape_state(Node* n);
+
+ // Propagate escape states to referenced nodes.
+ bool propagate_escape_state(GrowableArray<int>* cg_worklist,
+ GrowableArray<uint>* worklist,
+ PointsToNode::EscapeState esc_state);
// Compute the escape information
bool compute_escape();
@@ -357,21 +366,6 @@
// escape state of a node
PointsToNode::EscapeState escape_state(Node *n);
- // other information we have collected
- bool is_scalar_replaceable(Node *n) {
- if (_collecting || (n->_idx >= nodes_size()))
- return false;
- PointsToNode* ptn = ptnode_adr(n->_idx);
- return ptn->escape_state() == PointsToNode::NoEscape && ptn->_scalar_replaceable;
- }
-
- bool hidden_alias(Node *n) {
- if (_collecting || (n->_idx >= nodes_size()))
- return true;
- PointsToNode* ptn = ptnode_adr(n->_idx);
- return (ptn->escape_state() != PointsToNode::NoEscape) || ptn->_hidden_alias;
- }
-
#ifndef PRODUCT
void dump();
#endif
--- a/hotspot/src/share/vm/opto/loopnode.cpp Thu Nov 17 10:46:00 2011 -0800
+++ b/hotspot/src/share/vm/opto/loopnode.cpp Wed Jul 05 17:56:12 2017 +0200
@@ -1883,7 +1883,7 @@
//----------------------------build_and_optimize-------------------------------
// Create a PhaseLoop. Build the ideal Loop tree. Map each Ideal Node to
// its corresponding LoopNode. If 'optimize' is true, do some loop cleanups.
-void PhaseIdealLoop::build_and_optimize(bool do_split_ifs) {
+void PhaseIdealLoop::build_and_optimize(bool do_split_ifs, bool skip_loop_opts) {
ResourceMark rm;
int old_progress = C->major_progress();
@@ -2072,6 +2072,16 @@
}
#endif
+ if (skip_loop_opts) {
+ // Cleanup any modified bits
+ _igvn.optimize();
+
+ if (C->log() != NULL) {
+ log_loop_tree(_ltree_root, _ltree_root, C->log());
+ }
+ return;
+ }
+
if (ReassociateInvariants) {
// Reassociate invariants and prep for split_thru_phi
for (LoopTreeIterator iter(_ltree_root); !iter.done(); iter.next()) {
--- a/hotspot/src/share/vm/opto/loopnode.hpp Thu Nov 17 10:46:00 2011 -0800
+++ b/hotspot/src/share/vm/opto/loopnode.hpp Wed Jul 05 17:56:12 2017 +0200
@@ -747,11 +747,11 @@
_dom_lca_tags(arena()), // Thread::resource_area
_verify_me(NULL),
_verify_only(true) {
- build_and_optimize(false);
+ build_and_optimize(false, false);
}
// build the loop tree and perform any requested optimizations
- void build_and_optimize(bool do_split_if);
+ void build_and_optimize(bool do_split_if, bool skip_loop_opts);
public:
// Dominators for the sea of nodes
@@ -762,13 +762,13 @@
Node *dom_lca_internal( Node *n1, Node *n2 ) const;
// Compute the Ideal Node to Loop mapping
- PhaseIdealLoop( PhaseIterGVN &igvn, bool do_split_ifs) :
+ PhaseIdealLoop( PhaseIterGVN &igvn, bool do_split_ifs, bool skip_loop_opts = false) :
PhaseTransform(Ideal_Loop),
_igvn(igvn),
_dom_lca_tags(arena()), // Thread::resource_area
_verify_me(NULL),
_verify_only(false) {
- build_and_optimize(do_split_ifs);
+ build_and_optimize(do_split_ifs, skip_loop_opts);
}
// Verify that verify_me made the same decisions as a fresh run.
@@ -778,7 +778,7 @@
_dom_lca_tags(arena()), // Thread::resource_area
_verify_me(verify_me),
_verify_only(false) {
- build_and_optimize(false);
+ build_and_optimize(false, false);
}
// Build and verify the loop tree without modifying the graph. This
--- a/hotspot/src/share/vm/opto/loopopts.cpp Thu Nov 17 10:46:00 2011 -0800
+++ b/hotspot/src/share/vm/opto/loopopts.cpp Wed Jul 05 17:56:12 2017 +0200
@@ -28,6 +28,7 @@
#include "opto/connode.hpp"
#include "opto/divnode.hpp"
#include "opto/loopnode.hpp"
+#include "opto/matcher.hpp"
#include "opto/mulnode.hpp"
#include "opto/rootnode.hpp"
#include "opto/subnode.hpp"
@@ -472,46 +473,50 @@
// 1 or 2 items with a total of 1 or 2 ops executed speculatively.
Node *PhaseIdealLoop::conditional_move( Node *region ) {
- assert( region->is_Region(), "sanity check" );
- if( region->req() != 3 ) return NULL;
+ assert(region->is_Region(), "sanity check");
+ if (region->req() != 3) return NULL;
// Check for CFG diamond
Node *lp = region->in(1);
Node *rp = region->in(2);
- if( !lp || !rp ) return NULL;
+ if (!lp || !rp) return NULL;
Node *lp_c = lp->in(0);
- if( lp_c == NULL || lp_c != rp->in(0) || !lp_c->is_If() ) return NULL;
+ if (lp_c == NULL || lp_c != rp->in(0) || !lp_c->is_If()) return NULL;
IfNode *iff = lp_c->as_If();
- // Check for highly predictable branch. No point in CMOV'ing if
- // we are going to predict accurately all the time.
- // %%% This hides patterns produced by utility methods like Math.min.
- if( iff->_prob < PROB_UNLIKELY_MAG(3) ||
- iff->_prob > PROB_LIKELY_MAG(3) )
- return NULL;
-
// Check for ops pinned in an arm of the diamond.
// Can't remove the control flow in this case
- if( lp->outcnt() > 1 ) return NULL;
- if( rp->outcnt() > 1 ) return NULL;
+ if (lp->outcnt() > 1) return NULL;
+ if (rp->outcnt() > 1) return NULL;
+
+ IdealLoopTree* r_loop = get_loop(region);
+ assert(r_loop == get_loop(iff), "sanity");
+ // Always convert to CMOVE if all results are used only outside this loop.
+ bool used_inside_loop = (r_loop == _ltree_root);
// Check profitability
int cost = 0;
int phis = 0;
for (DUIterator_Fast imax, i = region->fast_outs(imax); i < imax; i++) {
Node *out = region->fast_out(i);
- if( !out->is_Phi() ) continue; // Ignore other control edges, etc
+ if (!out->is_Phi()) continue; // Ignore other control edges, etc
phis++;
PhiNode* phi = out->as_Phi();
- switch (phi->type()->basic_type()) {
- case T_LONG:
- cost++; // Probably encodes as 2 CMOV's
+ BasicType bt = phi->type()->basic_type();
+ switch (bt) {
+ case T_FLOAT:
+ case T_DOUBLE: {
+ cost += Matcher::float_cmove_cost(); // Could be very expensive
+ break;
+ }
+ case T_LONG: {
+ cost += Matcher::long_cmove_cost(); // May encodes as 2 CMOV's
+ }
case T_INT: // These all CMOV fine
- case T_FLOAT:
- case T_DOUBLE:
- case T_ADDRESS: // (RawPtr)
+ case T_ADDRESS: { // (RawPtr)
cost++;
break;
+ }
case T_NARROWOOP: // Fall through
case T_OBJECT: { // Base oops are OK, but not derived oops
const TypeOopPtr *tp = phi->type()->make_ptr()->isa_oopptr();
@@ -524,7 +529,7 @@
// relevant bases. This puts the allocator in the business of
// manufacturing expensive instructions, generally a bad plan.
// Just Say No to Conditionally-Moved Derived Pointers.
- if( tp && tp->offset() != 0 )
+ if (tp && tp->offset() != 0)
return NULL;
cost++;
break;
@@ -533,39 +538,64 @@
return NULL; // In particular, can't do memory or I/O
}
// Add in cost any speculative ops
- for( uint j = 1; j < region->req(); j++ ) {
+ for (uint j = 1; j < region->req(); j++) {
Node *proj = region->in(j);
Node *inp = phi->in(j);
if (get_ctrl(inp) == proj) { // Found local op
cost++;
// Check for a chain of dependent ops; these will all become
// speculative in a CMOV.
- for( uint k = 1; k < inp->req(); k++ )
+ for (uint k = 1; k < inp->req(); k++)
if (get_ctrl(inp->in(k)) == proj)
- return NULL; // Too much speculative goo
+ cost += ConditionalMoveLimit; // Too much speculative goo
}
}
// See if the Phi is used by a Cmp or Narrow oop Decode/Encode.
// This will likely Split-If, a higher-payoff operation.
for (DUIterator_Fast kmax, k = phi->fast_outs(kmax); k < kmax; k++) {
Node* use = phi->fast_out(k);
- if( use->is_Cmp() || use->is_DecodeN() || use->is_EncodeP() )
- return NULL;
+ if (use->is_Cmp() || use->is_DecodeN() || use->is_EncodeP())
+ cost += ConditionalMoveLimit;
+ // Is there a use inside the loop?
+ // Note: check only basic types since CMoveP is pinned.
+ if (!used_inside_loop && is_java_primitive(bt)) {
+ IdealLoopTree* u_loop = get_loop(has_ctrl(use) ? get_ctrl(use) : use);
+ if (r_loop == u_loop || r_loop->is_member(u_loop)) {
+ used_inside_loop = true;
+ }
+ }
}
}
- if( cost >= ConditionalMoveLimit ) return NULL; // Too much goo
Node* bol = iff->in(1);
- assert( bol->Opcode() == Op_Bool, "" );
+ assert(bol->Opcode() == Op_Bool, "");
int cmp_op = bol->in(1)->Opcode();
// It is expensive to generate flags from a float compare.
// Avoid duplicated float compare.
- if( phis > 1 && (cmp_op == Op_CmpF || cmp_op == Op_CmpD)) return NULL;
+ if (phis > 1 && (cmp_op == Op_CmpF || cmp_op == Op_CmpD)) return NULL;
+
+ float infrequent_prob = PROB_UNLIKELY_MAG(3);
+ // Ignore cost and blocks frequency if CMOVE can be moved outside the loop.
+ if (used_inside_loop) {
+ if (cost >= ConditionalMoveLimit) return NULL; // Too much goo
+
+ // BlockLayoutByFrequency optimization moves infrequent branch
+ // from hot path. No point in CMOV'ing in such case (110 is used
+ // instead of 100 to take into account not exactness of float value).
+ if (BlockLayoutByFrequency) {
+ infrequent_prob = MAX2(infrequent_prob, (float)BlockLayoutMinDiamondPercentage/110.0f);
+ }
+ }
+ // Check for highly predictable branch. No point in CMOV'ing if
+ // we are going to predict accurately all the time.
+ if (iff->_prob < infrequent_prob ||
+ iff->_prob > (1.0f - infrequent_prob))
+ return NULL;
// --------------
// Now replace all Phis with CMOV's
Node *cmov_ctrl = iff->in(0);
uint flip = (lp->Opcode() == Op_IfTrue);
- while( 1 ) {
+ while (1) {
PhiNode* phi = NULL;
for (DUIterator_Fast imax, i = region->fast_outs(imax); i < imax; i++) {
Node *out = region->fast_out(i);
@@ -576,15 +606,15 @@
}
if (phi == NULL) break;
#ifndef PRODUCT
- if( PrintOpto && VerifyLoopOptimizations ) tty->print_cr("CMOV");
+ if (PrintOpto && VerifyLoopOptimizations) tty->print_cr("CMOV");
#endif
// Move speculative ops
- for( uint j = 1; j < region->req(); j++ ) {
+ for (uint j = 1; j < region->req(); j++) {
Node *proj = region->in(j);
Node *inp = phi->in(j);
if (get_ctrl(inp) == proj) { // Found local op
#ifndef PRODUCT
- if( PrintOpto && VerifyLoopOptimizations ) {
+ if (PrintOpto && VerifyLoopOptimizations) {
tty->print(" speculate: ");
inp->dump();
}
@@ -596,7 +626,15 @@
register_new_node( cmov, cmov_ctrl );
_igvn.replace_node( phi, cmov );
#ifndef PRODUCT
- if( VerifyLoopOptimizations ) verify();
+ if (TraceLoopOpts) {
+ tty->print("CMOV ");
+ r_loop->dump_head();
+ if (Verbose) {
+ bol->in(1)->dump(1);
+ cmov->dump(1);
+ }
+ }
+ if (VerifyLoopOptimizations) verify();
#endif
}
@@ -676,14 +714,14 @@
// Split 'n' through the merge point if it is profitable
Node *phi = split_thru_phi( n, n_blk, policy );
- if( !phi ) return n;
+ if (!phi) return n;
// Found a Phi to split thru!
// Replace 'n' with the new phi
_igvn.replace_node( n, phi );
// Moved a load around the loop, 'en-registering' something.
- if( n_blk->Opcode() == Op_Loop && n->is_Load() &&
- !phi->in(LoopNode::LoopBackControl)->is_Load() )
+ if (n_blk->is_Loop() && n->is_Load() &&
+ !phi->in(LoopNode::LoopBackControl)->is_Load())
C->set_major_progress();
return phi;
--- a/hotspot/src/share/vm/opto/machnode.cpp Thu Nov 17 10:46:00 2011 -0800
+++ b/hotspot/src/share/vm/opto/machnode.cpp Wed Jul 05 17:56:12 2017 +0200
@@ -484,6 +484,13 @@
// Bind the offset lazily.
if (offset == -1) {
Compile::ConstantTable& constant_table = Compile::current()->constant_table();
+ // If called from Compile::scratch_emit_size assume the worst-case
+ // for load offsets: half the constant table size.
+ // NOTE: Don't return or calculate the actual offset (which might
+ // be zero) because that leads to problems with e.g. jumpXtnd on
+ // some architectures (cf. add-optimization in SPARC jumpXtnd).
+ if (Compile::current()->in_scratch_emit_size())
+ return constant_table.size() / 2;
offset = constant_table.table_base_offset() + constant_table.find_offset(_constant);
_constant.set_offset(offset);
}
--- a/hotspot/src/share/vm/opto/matcher.cpp Thu Nov 17 10:46:00 2011 -0800
+++ b/hotspot/src/share/vm/opto/matcher.cpp Wed Jul 05 17:56:12 2017 +0200
@@ -1915,7 +1915,7 @@
set_dontcare(n);
break;
case Op_Jump:
- mstack.push(n->in(1), Visit); // Switch Value
+ mstack.push(n->in(1), Pre_Visit); // Switch Value (could be shared)
mstack.push(n->in(0), Pre_Visit); // Visit Control input
continue; // while (mstack.is_nonempty())
case Op_StrComp:
--- a/hotspot/src/share/vm/opto/matcher.hpp Thu Nov 17 10:46:00 2011 -0800
+++ b/hotspot/src/share/vm/opto/matcher.hpp Wed Jul 05 17:56:12 2017 +0200
@@ -360,6 +360,12 @@
// Anything this size or smaller may get converted to discrete scalar stores.
static const int init_array_short_size;
+ // Some hardware needs 2 CMOV's for longs.
+ static const int long_cmove_cost();
+
+ // Some hardware have expensive CMOV for float and double.
+ static const int float_cmove_cost();
+
// Should the Matcher clone shifts on addressing modes, expecting them to
// be subsumed into complex addressing expressions or compute them into
// registers? True for Intel but false for most RISCs
--- a/hotspot/src/share/vm/opto/memnode.cpp Thu Nov 17 10:46:00 2011 -0800
+++ b/hotspot/src/share/vm/opto/memnode.cpp Wed Jul 05 17:56:12 2017 +0200
@@ -1421,6 +1421,12 @@
const TypeOopPtr *t_oop = addr_t->isa_oopptr();
if (can_reshape && opt_mem->is_Phi() &&
(t_oop != NULL) && t_oop->is_known_instance_field()) {
+ PhaseIterGVN *igvn = phase->is_IterGVN();
+ if (igvn != NULL && igvn->_worklist.member(opt_mem)) {
+ // Delay this transformation until memory Phi is processed.
+ phase->is_IterGVN()->_worklist.push(this);
+ return NULL;
+ }
// Split instance field load through Phi.
Node* result = split_through_phi(phase);
if (result != NULL) return result;
--- a/hotspot/src/share/vm/opto/phaseX.cpp Thu Nov 17 10:46:00 2011 -0800
+++ b/hotspot/src/share/vm/opto/phaseX.cpp Wed Jul 05 17:56:12 2017 +0200
@@ -322,11 +322,12 @@
void NodeHash::dump() {
_total_inserts += _inserts;
_total_insert_probes += _insert_probes;
- if( PrintCompilation && PrintOptoStatistics && Verbose && (_inserts > 0) ) { // PrintOptoGVN
- if( PrintCompilation2 ) {
- for( uint i=0; i<_max; i++ )
- if( _table[i] )
- tty->print("%d/%d/%d ",i,_table[i]->hash()&(_max-1),_table[i]->_idx);
+ if (PrintCompilation && PrintOptoStatistics && Verbose && (_inserts > 0)) {
+ if (WizardMode) {
+ for (uint i=0; i<_max; i++) {
+ if (_table[i])
+ tty->print("%d/%d/%d ",i,_table[i]->hash()&(_max-1),_table[i]->_idx);
+ }
}
tty->print("\nGVN Hash stats: %d grows to %d max_size\n", _grows, _max);
tty->print(" %d/%d (%8.1f%% full)\n", _inserts, _max, (double)_inserts/_max*100.0);
--- a/hotspot/src/share/vm/opto/runtime.cpp Thu Nov 17 10:46:00 2011 -0800
+++ b/hotspot/src/share/vm/opto/runtime.cpp Wed Jul 05 17:56:12 2017 +0200
@@ -338,6 +338,24 @@
// inform GC that we won't do card marks for initializing writes.
new_store_pre_barrier(thread);
}
+
+ oop result = thread->vm_result();
+ if ((len > 0) && (result != NULL) &&
+ is_deoptimized_caller_frame(thread)) {
+ // Zero array here if the caller is deoptimized.
+ int size = ((typeArrayOop)result)->object_size();
+ BasicType elem_type = typeArrayKlass::cast(array_type)->element_type();
+ const size_t hs = arrayOopDesc::header_size(elem_type);
+ // Align to next 8 bytes to avoid trashing arrays's length.
+ const size_t aligned_hs = align_object_offset(hs);
+ HeapWord* obj = (HeapWord*)result;
+ if (aligned_hs > hs) {
+ Copy::zero_to_words(obj+hs, aligned_hs-hs);
+ }
+ // Optimized zeroing.
+ Copy::fill_to_aligned_words(obj+aligned_hs, size-aligned_hs);
+ }
+
JRT_END
// Note: multianewarray for one dimension is handled inline by GraphKit::new_array.
@@ -1130,12 +1148,22 @@
assert(stub_frame.is_runtime_frame() || exception_blob()->contains(stub_frame.pc()), "sanity check");
frame caller_frame = stub_frame.sender(®_map);
- // bypass VM_DeoptimizeFrame and deoptimize the frame directly
+ // Deoptimize the caller frame.
Deoptimization::deoptimize_frame(thread, caller_frame.id());
}
}
+bool OptoRuntime::is_deoptimized_caller_frame(JavaThread *thread) {
+ // Called from within the owner thread, so no need for safepoint
+ RegisterMap reg_map(thread);
+ frame stub_frame = thread->last_frame();
+ assert(stub_frame.is_runtime_frame() || exception_blob()->contains(stub_frame.pc()), "sanity check");
+ frame caller_frame = stub_frame.sender(®_map);
+ return caller_frame.is_deoptimized_frame();
+}
+
+
const TypeFunc *OptoRuntime::register_finalizer_Type() {
// create input type (domain)
const Type **fields = TypeTuple::fields(1);
--- a/hotspot/src/share/vm/opto/runtime.hpp Thu Nov 17 10:46:00 2011 -0800
+++ b/hotspot/src/share/vm/opto/runtime.hpp Wed Jul 05 17:56:12 2017 +0200
@@ -175,6 +175,7 @@
static address handle_exception_C_helper(JavaThread* thread, nmethod*& nm);
static address rethrow_C (oopDesc* exception, JavaThread *thread, address return_pc );
static void deoptimize_caller_frame (JavaThread *thread, bool doit);
+ static bool is_deoptimized_caller_frame (JavaThread *thread);
// CodeBlob support
// ===================================================================
--- a/hotspot/src/share/vm/prims/jni.cpp Thu Nov 17 10:46:00 2011 -0800
+++ b/hotspot/src/share/vm/prims/jni.cpp Wed Jul 05 17:56:12 2017 +0200
@@ -5042,7 +5042,8 @@
void execute_internal_vm_tests() {
if (ExecuteInternalVMTests) {
assert(QuickSort::test_quick_sort(), "test_quick_sort failed");
- tty->print_cr("All tests passed");
+ assert(arrayOopDesc::test_max_array_length(), "test_max_array_length failed");
+ tty->print_cr("All internal VM tests passed");
}
}
--- a/hotspot/src/share/vm/prims/jniCheck.cpp Thu Nov 17 10:46:00 2011 -0800
+++ b/hotspot/src/share/vm/prims/jniCheck.cpp Wed Jul 05 17:56:12 2017 +0200
@@ -107,7 +107,7 @@
if (env != xenv) { \
NativeReportJNIFatalError(thr, warn_wrong_jnienv); \
} \
- __ENTRY(result_type, header, thr)
+ VM_ENTRY_BASE(result_type, header, thr)
#define UNCHECKED() (unchecked_jni_NativeInterface)
--- a/hotspot/src/share/vm/prims/jvmtiEnter.xsl Thu Nov 17 10:46:00 2011 -0800
+++ b/hotspot/src/share/vm/prims/jvmtiEnter.xsl Wed Jul 05 17:56:12 2017 +0200
@@ -426,7 +426,7 @@
<xsl:value-of select="$space"/>
<xsl:text>ThreadInVMfromNative __tiv(current_thread);</xsl:text>
<xsl:value-of select="$space"/>
- <xsl:text>__ENTRY(jvmtiError, </xsl:text>
+ <xsl:text>VM_ENTRY_BASE(jvmtiError, </xsl:text>
<xsl:apply-templates select="." mode="functionid"/>
<xsl:text> , current_thread)</xsl:text>
<xsl:value-of select="$space"/>
--- a/hotspot/src/share/vm/prims/jvmtiEnv.cpp Thu Nov 17 10:46:00 2011 -0800
+++ b/hotspot/src/share/vm/prims/jvmtiEnv.cpp Wed Jul 05 17:56:12 2017 +0200
@@ -173,7 +173,7 @@
// from native so as to resolve the jthread.
ThreadInVMfromNative __tiv(current_thread);
- __ENTRY(jvmtiError, JvmtiEnv::GetThreadLocalStorage , current_thread)
+ VM_ENTRY_BASE(jvmtiError, JvmtiEnv::GetThreadLocalStorage , current_thread)
debug_only(VMNativeEntryWrapper __vew;)
oop thread_oop = JNIHandles::resolve_external_guard(thread);
--- a/hotspot/src/share/vm/prims/jvmtiExport.cpp Thu Nov 17 10:46:00 2011 -0800
+++ b/hotspot/src/share/vm/prims/jvmtiExport.cpp Wed Jul 05 17:56:12 2017 +0200
@@ -373,7 +373,7 @@
JavaThread* current_thread = (JavaThread*) ThreadLocalStorage::thread();
// transition code: native to VM
ThreadInVMfromNative __tiv(current_thread);
- __ENTRY(jvmtiEnv*, JvmtiExport::get_jvmti_interface, current_thread)
+ VM_ENTRY_BASE(jvmtiEnv*, JvmtiExport::get_jvmti_interface, current_thread)
debug_only(VMNativeEntryWrapper __vew;)
JvmtiEnv *jvmti_env = JvmtiEnv::create_a_jvmti(version);
--- a/hotspot/src/share/vm/prims/methodHandles.cpp Thu Nov 17 10:46:00 2011 -0800
+++ b/hotspot/src/share/vm/prims/methodHandles.cpp Wed Jul 05 17:56:12 2017 +0200
@@ -206,9 +206,12 @@
_adapter_code = MethodHandlesAdapterBlob::create(adapter_code_size);
if (_adapter_code == NULL)
vm_exit_out_of_memory(adapter_code_size, "CodeCache: no room for MethodHandles adapters");
- CodeBuffer code(_adapter_code);
- MethodHandlesAdapterGenerator g(&code);
- g.generate();
+ {
+ CodeBuffer code(_adapter_code);
+ MethodHandlesAdapterGenerator g(&code);
+ g.generate();
+ code.log_section_sizes("MethodHandlesAdapterBlob");
+ }
}
//------------------------------------------------------------------------------
@@ -3079,26 +3082,26 @@
JVM_END
JVM_ENTRY(void, MHN_setCallSiteTargetNormal(JNIEnv* env, jobject igcls, jobject call_site_jh, jobject target_jh)) {
- oop call_site = JNIHandles::resolve_non_null(call_site_jh);
- oop target = JNIHandles::resolve(target_jh);
+ Handle call_site(THREAD, JNIHandles::resolve_non_null(call_site_jh));
+ Handle target (THREAD, JNIHandles::resolve(target_jh));
{
// Walk all nmethods depending on this call site.
MutexLocker mu(Compile_lock, thread);
Universe::flush_dependents_on(call_site, target);
}
- java_lang_invoke_CallSite::set_target(call_site, target);
+ java_lang_invoke_CallSite::set_target(call_site(), target());
}
JVM_END
JVM_ENTRY(void, MHN_setCallSiteTargetVolatile(JNIEnv* env, jobject igcls, jobject call_site_jh, jobject target_jh)) {
- oop call_site = JNIHandles::resolve_non_null(call_site_jh);
- oop target = JNIHandles::resolve(target_jh);
+ Handle call_site(THREAD, JNIHandles::resolve_non_null(call_site_jh));
+ Handle target (THREAD, JNIHandles::resolve(target_jh));
{
// Walk all nmethods depending on this call site.
MutexLocker mu(Compile_lock, thread);
Universe::flush_dependents_on(call_site, target);
}
- java_lang_invoke_CallSite::set_target_volatile(call_site, target);
+ java_lang_invoke_CallSite::set_target_volatile(call_site(), target());
}
JVM_END
--- a/hotspot/src/share/vm/prims/unsafe.cpp Thu Nov 17 10:46:00 2011 -0800
+++ b/hotspot/src/share/vm/prims/unsafe.cpp Wed Jul 05 17:56:12 2017 +0200
@@ -302,21 +302,24 @@
UNSAFE_ENTRY(void, Unsafe_SetObjectVolatile(JNIEnv *env, jobject unsafe, jobject obj, jlong offset, jobject x_h))
UnsafeWrapper("Unsafe_SetObjectVolatile");
+ {
+ // Catch VolatileCallSite.target stores (via
+ // CallSite.setTargetVolatile) and check call site dependencies.
+ oop p = JNIHandles::resolve(obj);
+ if ((offset == java_lang_invoke_CallSite::target_offset_in_bytes()) && p->is_a(SystemDictionary::CallSite_klass())) {
+ Handle call_site (THREAD, p);
+ Handle method_handle(THREAD, JNIHandles::resolve(x_h));
+ assert(call_site ->is_a(SystemDictionary::CallSite_klass()), "must be");
+ assert(method_handle->is_a(SystemDictionary::MethodHandle_klass()), "must be");
+ {
+ // Walk all nmethods depending on this call site.
+ MutexLocker mu(Compile_lock, thread);
+ Universe::flush_dependents_on(call_site(), method_handle());
+ }
+ }
+ }
oop x = JNIHandles::resolve(x_h);
oop p = JNIHandles::resolve(obj);
- // Catch VolatileCallSite.target stores (via
- // CallSite.setTargetVolatile) and check call site dependencies.
- if ((offset == java_lang_invoke_CallSite::target_offset_in_bytes()) && p->is_a(SystemDictionary::CallSite_klass())) {
- oop call_site = p;
- oop method_handle = x;
- assert(call_site ->is_a(SystemDictionary::CallSite_klass()), "must be");
- assert(method_handle->is_a(SystemDictionary::MethodHandle_klass()), "must be");
- {
- // Walk all nmethods depending on this call site.
- MutexLocker mu(Compile_lock, thread);
- Universe::flush_dependents_on(call_site, method_handle);
- }
- }
void* addr = index_oop_from_field_offset_long(p, offset);
OrderAccess::release();
if (UseCompressedOops) {
--- a/hotspot/src/share/vm/runtime/arguments.cpp Thu Nov 17 10:46:00 2011 -0800
+++ b/hotspot/src/share/vm/runtime/arguments.cpp Wed Jul 05 17:56:12 2017 +0200
@@ -1577,18 +1577,9 @@
sprintf(buffer, "java.lang.Integer.IntegerCache.high=" INTX_FORMAT, AutoBoxCacheMax);
add_property(buffer);
}
- if (AggressiveOpts && FLAG_IS_DEFAULT(DoEscapeAnalysis)) {
- FLAG_SET_DEFAULT(DoEscapeAnalysis, true);
- }
if (AggressiveOpts && FLAG_IS_DEFAULT(BiasedLockingStartupDelay)) {
FLAG_SET_DEFAULT(BiasedLockingStartupDelay, 500);
}
- if (AggressiveOpts && FLAG_IS_DEFAULT(OptimizeStringConcat)) {
- FLAG_SET_DEFAULT(OptimizeStringConcat, true);
- }
- if (AggressiveOpts && FLAG_IS_DEFAULT(OptimizeFill)) {
- FLAG_SET_DEFAULT(OptimizeFill, true);
- }
#endif
if (AggressiveOpts) {
--- a/hotspot/src/share/vm/runtime/deoptimization.cpp Thu Nov 17 10:46:00 2011 -0800
+++ b/hotspot/src/share/vm/runtime/deoptimization.cpp Wed Jul 05 17:56:12 2017 +0200
@@ -362,8 +362,6 @@
intptr_t* frame_sizes = NEW_C_HEAP_ARRAY(intptr_t, number_of_frames);
// +1 because we always have an interpreter return address for the final slot.
address* frame_pcs = NEW_C_HEAP_ARRAY(address, number_of_frames + 1);
- int callee_parameters = 0;
- int callee_locals = 0;
int popframe_extra_args = 0;
// Create an interpreter return address for the stub to use as its return
// address so the skeletal frames are perfectly walkable
@@ -387,14 +385,16 @@
// handles are used. If the caller is interpreted get the real
// value so that the proper amount of space can be added to it's
// frame.
- int caller_actual_parameters = callee_parameters;
+ bool caller_was_method_handle = false;
if (deopt_sender.is_interpreted_frame()) {
methodHandle method = deopt_sender.interpreter_frame_method();
- Bytecode_invoke cur = Bytecode_invoke_check(method,
- deopt_sender.interpreter_frame_bci());
- Symbol* signature = method->constants()->signature_ref_at(cur.index());
- ArgumentSizeComputer asc(signature);
- caller_actual_parameters = asc.size() + (cur.has_receiver() ? 1 : 0);
+ Bytecode_invoke cur = Bytecode_invoke_check(method, deopt_sender.interpreter_frame_bci());
+ if (cur.is_method_handle_invoke()) {
+ // Method handle invokes may involve fairly arbitrary chains of
+ // calls so it's impossible to know how much actual space the
+ // caller has for locals.
+ caller_was_method_handle = true;
+ }
}
//
@@ -411,14 +411,15 @@
// in the frame_sizes/frame_pcs so the assembly code can do a trivial walk.
// so things look a little strange in this loop.
//
+ int callee_parameters = 0;
+ int callee_locals = 0;
for (int index = 0; index < array->frames(); index++ ) {
// frame[number_of_frames - 1 ] = on_stack_size(youngest)
// frame[number_of_frames - 2 ] = on_stack_size(sender(youngest))
// frame[number_of_frames - 3 ] = on_stack_size(sender(sender(youngest)))
int caller_parms = callee_parameters;
- if (index == array->frames() - 1) {
- // Use the value from the interpreted caller
- caller_parms = caller_actual_parameters;
+ if ((index == array->frames() - 1) && caller_was_method_handle) {
+ caller_parms = 0;
}
frame_sizes[number_of_frames - 1 - index] = BytesPerWord * array->element(index)->on_stack_size(caller_parms,
callee_parameters,
@@ -460,13 +461,13 @@
// QQQ I'd rather see this pushed down into last_frame_adjust
// and have it take the sender (aka caller).
- if (deopt_sender.is_compiled_frame()) {
+ if (deopt_sender.is_compiled_frame() || caller_was_method_handle) {
caller_adjustment = last_frame_adjust(0, callee_locals);
- } else if (callee_locals > caller_actual_parameters) {
+ } else if (callee_locals > callee_parameters) {
// The caller frame may need extending to accommodate
// non-parameter locals of the first unpacked interpreted frame.
// Compute that adjustment.
- caller_adjustment = last_frame_adjust(caller_actual_parameters, callee_locals);
+ caller_adjustment = last_frame_adjust(callee_parameters, callee_locals);
}
// If the sender is deoptimized the we must retrieve the address of the handler
@@ -481,7 +482,7 @@
UnrollBlock* info = new UnrollBlock(array->frame_size() * BytesPerWord,
caller_adjustment * BytesPerWord,
- caller_actual_parameters,
+ caller_was_method_handle ? 0 : callee_parameters,
number_of_frames,
frame_sizes,
frame_pcs,
--- a/hotspot/src/share/vm/runtime/frame.cpp Thu Nov 17 10:46:00 2011 -0800
+++ b/hotspot/src/share/vm/runtime/frame.cpp Wed Jul 05 17:56:12 2017 +0200
@@ -1338,7 +1338,11 @@
// Label values common to most frames
values.describe(-1, unextended_sp(), err_msg("unextended_sp for #%d", frame_no));
values.describe(-1, sp(), err_msg("sp for #%d", frame_no));
- values.describe(-1, fp(), err_msg("fp for #%d", frame_no));
+ if (is_compiled_frame()) {
+ values.describe(-1, sp() + _cb->frame_size(), err_msg("computed fp for #%d", frame_no));
+ } else {
+ values.describe(-1, fp(), err_msg("fp for #%d", frame_no));
+ }
}
if (is_interpreted_frame()) {
methodOop m = interpreter_frame_method();
@@ -1450,9 +1454,8 @@
}
-void FrameValues::print() {
+void FrameValues::print(JavaThread* thread) {
_values.sort(compare);
- JavaThread* thread = JavaThread::current();
// Sometimes values like the fp can be invalid values if the
// register map wasn't updated during the walk. Trim out values
@@ -1460,12 +1463,22 @@
int min_index = 0;
int max_index = _values.length() - 1;
intptr_t* v0 = _values.at(min_index).location;
- while (!thread->is_in_stack((address)v0)) {
- v0 = _values.at(++min_index).location;
- }
intptr_t* v1 = _values.at(max_index).location;
- while (!thread->is_in_stack((address)v1)) {
- v1 = _values.at(--max_index).location;
+
+ if (thread == Thread::current()) {
+ while (!thread->is_in_stack((address)v0)) {
+ v0 = _values.at(++min_index).location;
+ }
+ while (!thread->is_in_stack((address)v1)) {
+ v1 = _values.at(--max_index).location;
+ }
+ } else {
+ while (!thread->on_local_stack((address)v0)) {
+ v0 = _values.at(++min_index).location;
+ }
+ while (!thread->on_local_stack((address)v1)) {
+ v1 = _values.at(--max_index).location;
+ }
}
intptr_t* min = MIN2(v0, v1);
intptr_t* max = MAX2(v0, v1);
--- a/hotspot/src/share/vm/runtime/frame.hpp Thu Nov 17 10:46:00 2011 -0800
+++ b/hotspot/src/share/vm/runtime/frame.hpp Wed Jul 05 17:56:12 2017 +0200
@@ -516,7 +516,7 @@
void describe(int owner, intptr_t* location, const char* description, int priority = 0);
void validate();
- void print();
+ void print(JavaThread* thread);
};
#endif
--- a/hotspot/src/share/vm/runtime/globals.hpp Thu Nov 17 10:46:00 2011 -0800
+++ b/hotspot/src/share/vm/runtime/globals.hpp Wed Jul 05 17:56:12 2017 +0200
@@ -577,8 +577,8 @@
develop(bool, VerifyStack, false, \
"Verify stack of each thread when it is entering a runtime call") \
\
- develop(bool, ForceUnreachable, false, \
- "(amd64) Make all non code cache addresses to be unreachable with rip-rel forcing use of 64bit literal fixups") \
+ diagnostic(bool, ForceUnreachable, false, \
+ "Make all non code cache addresses to be unreachable with forcing use of 64bit literal fixups") \
\
notproduct(bool, StressDerivedPointers, false, \
"Force scavenge when a derived pointers is detected on stack " \
@@ -904,7 +904,7 @@
product(bool, AlwaysRestoreFPU, false, \
"Restore the FPU control word after every JNI call (expensive)") \
\
- notproduct(bool, PrintCompilation2, false, \
+ diagnostic(bool, PrintCompilation2, false, \
"Print additional statistics per compilation") \
\
diagnostic(bool, PrintAdapterHandlers, false, \
@@ -2580,7 +2580,7 @@
diagnostic(bool, DebugInlinedCalls, true, \
"If false, restricts profiled locations to the root method only") \
\
- product(bool, PrintVMOptions, NOT_EMBEDDED(trueInDebug) EMBEDDED_ONLY(false),\
+ product(bool, PrintVMOptions, false, \
"Print flags that appeared on the command line") \
\
product(bool, IgnoreUnrecognizedVMOptions, false, \
@@ -3364,7 +3364,7 @@
notproduct(bool, ExitOnFullCodeCache, false, \
"Exit the VM if we fill the code cache.") \
\
- product(bool, UseCodeCacheFlushing, false, \
+ product(bool, UseCodeCacheFlushing, true, \
"Attempt to clean the code cache before shutting off compiler") \
\
product(intx, MinCodeCacheFlushingInterval, 30, \
--- a/hotspot/src/share/vm/runtime/interfaceSupport.hpp Thu Nov 17 10:46:00 2011 -0800
+++ b/hotspot/src/share/vm/runtime/interfaceSupport.hpp Wed Jul 05 17:56:12 2017 +0200
@@ -72,9 +72,9 @@
}
};
-// InterfaceSupport provides functionality used by the __LEAF and __ENTRY
-// macros. These macros are used to guard entry points into the VM and
-// perform checks upon leave of the VM.
+// InterfaceSupport provides functionality used by the VM_LEAF_BASE and
+// VM_ENTRY_BASE macros. These macros are used to guard entry points into
+// the VM and perform checks upon leave of the VM.
class InterfaceSupport: AllStatic {
@@ -433,7 +433,7 @@
// LEAF routines do not lock, GC or throw exceptions
-#define __LEAF(result_type, header) \
+#define VM_LEAF_BASE(result_type, header) \
TRACE_CALL(result_type, header) \
debug_only(NoHandleMark __hm;) \
/* begin of body */
@@ -441,7 +441,7 @@
// ENTRY routines may lock, GC and throw exceptions
-#define __ENTRY(result_type, header, thread) \
+#define VM_ENTRY_BASE(result_type, header, thread) \
TRACE_CALL(result_type, header) \
HandleMarkCleaner __hm(thread); \
Thread* THREAD = thread; \
@@ -450,7 +450,7 @@
// QUICK_ENTRY routines behave like ENTRY but without a handle mark
-#define __QUICK_ENTRY(result_type, header, thread) \
+#define VM_QUICK_ENTRY_BASE(result_type, header, thread) \
TRACE_CALL(result_type, header) \
debug_only(NoHandleMark __hm;) \
Thread* THREAD = thread; \
@@ -463,20 +463,20 @@
#define IRT_ENTRY(result_type, header) \
result_type header { \
ThreadInVMfromJava __tiv(thread); \
- __ENTRY(result_type, header, thread) \
+ VM_ENTRY_BASE(result_type, header, thread) \
debug_only(VMEntryWrapper __vew;)
#define IRT_LEAF(result_type, header) \
result_type header { \
- __LEAF(result_type, header) \
+ VM_LEAF_BASE(result_type, header) \
debug_only(No_Safepoint_Verifier __nspv(true);)
#define IRT_ENTRY_NO_ASYNC(result_type, header) \
result_type header { \
ThreadInVMfromJavaNoAsyncException __tiv(thread); \
- __ENTRY(result_type, header, thread) \
+ VM_ENTRY_BASE(result_type, header, thread) \
debug_only(VMEntryWrapper __vew;)
// Another special case for nmethod_entry_point so the nmethod that the
@@ -487,7 +487,7 @@
result_type header { \
nmethodLocker _nmlock(nm); \
ThreadInVMfromJavaNoAsyncException __tiv(thread); \
- __ENTRY(result_type, header, thread)
+ VM_ENTRY_BASE(result_type, header, thread)
#define IRT_END }
@@ -497,20 +497,20 @@
#define JRT_ENTRY(result_type, header) \
result_type header { \
ThreadInVMfromJava __tiv(thread); \
- __ENTRY(result_type, header, thread) \
+ VM_ENTRY_BASE(result_type, header, thread) \
debug_only(VMEntryWrapper __vew;)
#define JRT_LEAF(result_type, header) \
result_type header { \
- __LEAF(result_type, header) \
+ VM_LEAF_BASE(result_type, header) \
debug_only(JRT_Leaf_Verifier __jlv;)
#define JRT_ENTRY_NO_ASYNC(result_type, header) \
result_type header { \
ThreadInVMfromJavaNoAsyncException __tiv(thread); \
- __ENTRY(result_type, header, thread) \
+ VM_ENTRY_BASE(result_type, header, thread) \
debug_only(VMEntryWrapper __vew;)
// Same as JRT Entry but allows for return value after the safepoint
@@ -543,11 +543,11 @@
assert( !VerifyJNIEnvThread || (thread == Thread::current()), "JNIEnv is only valid in same thread"); \
ThreadInVMfromNative __tiv(thread); \
debug_only(VMNativeEntryWrapper __vew;) \
- __ENTRY(result_type, header, thread)
+ VM_ENTRY_BASE(result_type, header, thread)
// Ensure that the VMNativeEntryWrapper constructor, which can cause
-// a GC, is called outside the NoHandleMark (set via __QUICK_ENTRY).
+// a GC, is called outside the NoHandleMark (set via VM_QUICK_ENTRY_BASE).
#define JNI_QUICK_ENTRY(result_type, header) \
extern "C" { \
result_type JNICALL header { \
@@ -555,7 +555,7 @@
assert( !VerifyJNIEnvThread || (thread == Thread::current()), "JNIEnv is only valid in same thread"); \
ThreadInVMfromNative __tiv(thread); \
debug_only(VMNativeEntryWrapper __vew;) \
- __QUICK_ENTRY(result_type, header, thread)
+ VM_QUICK_ENTRY_BASE(result_type, header, thread)
#define JNI_LEAF(result_type, header) \
@@ -563,7 +563,7 @@
result_type JNICALL header { \
JavaThread* thread=JavaThread::thread_from_jni_environment(env); \
assert( !VerifyJNIEnvThread || (thread == Thread::current()), "JNIEnv is only valid in same thread"); \
- __LEAF(result_type, header)
+ VM_LEAF_BASE(result_type, header)
// Close the routine and the extern "C"
@@ -579,7 +579,7 @@
JavaThread* thread=JavaThread::thread_from_jni_environment(env); \
ThreadInVMfromNative __tiv(thread); \
debug_only(VMNativeEntryWrapper __vew;) \
- __ENTRY(result_type, header, thread)
+ VM_ENTRY_BASE(result_type, header, thread)
#define JVM_ENTRY_NO_ENV(result_type, header) \
@@ -588,7 +588,7 @@
JavaThread* thread = (JavaThread*)ThreadLocalStorage::thread(); \
ThreadInVMfromNative __tiv(thread); \
debug_only(VMNativeEntryWrapper __vew;) \
- __ENTRY(result_type, header, thread)
+ VM_ENTRY_BASE(result_type, header, thread)
#define JVM_QUICK_ENTRY(result_type, header) \
@@ -597,14 +597,14 @@
JavaThread* thread=JavaThread::thread_from_jni_environment(env); \
ThreadInVMfromNative __tiv(thread); \
debug_only(VMNativeEntryWrapper __vew;) \
- __QUICK_ENTRY(result_type, header, thread)
+ VM_QUICK_ENTRY_BASE(result_type, header, thread)
#define JVM_LEAF(result_type, header) \
extern "C" { \
result_type JNICALL header { \
VM_Exit::block_if_vm_exited(); \
- __LEAF(result_type, header)
+ VM_LEAF_BASE(result_type, header)
#define JVM_END } }
--- a/hotspot/src/share/vm/runtime/sharedRuntime.cpp Thu Nov 17 10:46:00 2011 -0800
+++ b/hotspot/src/share/vm/runtime/sharedRuntime.cpp Wed Jul 05 17:56:12 2017 +0200
@@ -1672,9 +1672,12 @@
nmethod* nm = cb->as_nmethod_or_null();
assert(nm, "must be");
- // Don't fixup MethodHandle call sites as c2i/i2c adapters are used
- // to implement MethodHandle actions.
- if (nm->is_method_handle_return(caller_pc)) {
+ // Get the return PC for the passed caller PC.
+ address return_pc = caller_pc + frame::pc_return_offset;
+
+ // Don't fixup method handle call sites as the executed method
+ // handle adapters are doing the required MethodHandle chain work.
+ if (nm->is_method_handle_return(return_pc)) {
return;
}
@@ -1693,8 +1696,8 @@
// Expect to find a native call there (unless it was no-inline cache vtable dispatch)
MutexLockerEx ml_patch(Patching_lock, Mutex::_no_safepoint_check_flag);
- if (NativeCall::is_call_before(caller_pc + frame::pc_return_offset)) {
- NativeCall *call = nativeCall_before(caller_pc + frame::pc_return_offset);
+ if (NativeCall::is_call_before(return_pc)) {
+ NativeCall *call = nativeCall_before(return_pc);
//
// bug 6281185. We might get here after resolving a call site to a vanilla
// virtual call. Because the resolvee uses the verified entry it may then
@@ -1744,7 +1747,6 @@
}
}
}
-
IRT_END
--- a/hotspot/src/share/vm/runtime/thread.cpp Thu Nov 17 10:46:00 2011 -0800
+++ b/hotspot/src/share/vm/runtime/thread.cpp Wed Jul 05 17:56:12 2017 +0200
@@ -2947,7 +2947,7 @@
values.validate();
} else {
tty->print_cr("[Describe stack layout]");
- values.print();
+ values.print(this);
}
}
#endif
--- a/hotspot/src/share/vm/services/heapDumper.cpp Thu Nov 17 10:46:00 2011 -0800
+++ b/hotspot/src/share/vm/services/heapDumper.cpp Wed Jul 05 17:56:12 2017 +0200
@@ -27,6 +27,7 @@
#include "classfile/systemDictionary.hpp"
#include "classfile/vmSymbols.hpp"
#include "gc_implementation/shared/vmGCOperations.hpp"
+#include "memory/gcLocker.inline.hpp"
#include "memory/genCollectedHeap.hpp"
#include "memory/universe.hpp"
#include "oops/objArrayKlass.hpp"
@@ -1709,11 +1710,16 @@
HandleMark hm;
CollectedHeap* ch = Universe::heap();
+
+ ch->ensure_parsability(false); // must happen, even if collection does
+ // not happen (e.g. due to GC_locker)
+
if (_gc_before_heap_dump) {
- ch->collect_as_vm_thread(GCCause::_heap_dump);
- } else {
- // make the heap parsable (no need to retire TLABs)
- ch->ensure_parsability(false);
+ if (GC_locker::is_active()) {
+ warning("GC locker is held; pre-heapdump GC was skipped");
+ } else {
+ ch->collect_as_vm_thread(GCCause::_heap_dump);
+ }
}
// At this point we should be the only dumper active, so
--- a/hotspot/src/share/vm/utilities/quickSort.cpp Thu Nov 17 10:46:00 2011 -0800
+++ b/hotspot/src/share/vm/utilities/quickSort.cpp Wed Jul 05 17:56:12 2017 +0200
@@ -23,13 +23,13 @@
*/
#include "precompiled.hpp"
-#include "utilities/quickSort.hpp"
+
+/////////////// Unit tests ///////////////
#ifndef PRODUCT
-// Unit tests
-
#include "runtime/os.hpp"
+#include "utilities/quickSort.hpp"
#include <stdlib.h>
static int test_comparator(int a, int b) {
@@ -94,7 +94,7 @@
}
bool QuickSort::test_quick_sort() {
- tty->print_cr("test_quick_sort\n");
+ tty->print_cr("test_quick_sort");
{
int* test_array = NULL;
int* expected_array = NULL;
--- a/hotspot/src/share/vm/utilities/vmError.cpp Thu Nov 17 10:46:00 2011 -0800
+++ b/hotspot/src/share/vm/utilities/vmError.cpp Wed Jul 05 17:56:12 2017 +0200
@@ -680,8 +680,10 @@
STEP(190, "(printing heap information)" )
if (_verbose && Universe::is_fully_initialized()) {
- // print heap information before vm abort
- Universe::print_on(st);
+ // Print heap information before vm abort. As we'd like as much
+ // information as possible in the report we ask for the
+ // extended (i.e., more detailed) version.
+ Universe::print_on(st, true /* extended */);
st->cr();
}
--- a/hotspot/test/Makefile Thu Nov 17 10:46:00 2011 -0800
+++ b/hotspot/test/Makefile Wed Jul 05 17:56:12 2017 +0200
@@ -1,5 +1,5 @@
#
-# Copyright (c) 1995, 2010, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 1995, 2011, 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
@@ -219,6 +219,15 @@
################################################################
+# internalvmtests (run internal unit tests inside the VM)
+
+internalvmtests: prep $(PRODUCT_HOME)
+ $(PRODUCT_HOME)/bin/java $(JAVA_OPTIONS) -XX:+ExecuteInternalVMTests -version
+
+PHONY_LIST += internalvmtests
+
+################################################################
+
# packtest
# Expect JPRT to set JPRT_PACKTEST_HOME.
--- a/hotspot/test/compiler/6865265/StackOverflowBug.java Thu Nov 17 10:46:00 2011 -0800
+++ b/hotspot/test/compiler/6865265/StackOverflowBug.java Wed Jul 05 17:56:12 2017 +0200
@@ -28,7 +28,7 @@
* @summary JVM crashes with "missing exception handler" error
* @author volker.simonis@sap.com
*
- * @run main/othervm -XX:CompileThreshold=100 -Xbatch -Xss128k StackOverflowBug
+ * @run main/othervm -XX:CompileThreshold=100 -Xbatch -Xss224k StackOverflowBug
*/
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/compiler/7103261/Test7103261.java Wed Jul 05 17:56:12 2017 +0200
@@ -0,0 +1,107 @@
+/*
+ * Copyright (c) 2011, 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 7103261
+ * @summary crash with jittester on sparc
+ *
+ * @run main Test7103261
+ */
+
+// exercise implicit null checking in the compiler for various field types
+public class Test7103261 {
+ static Test7103261 null_value;
+ static Test7103261 nonnull_value = new Test7103261();
+ static Test7103261 nonnull_value2 = new Test7103261();
+
+ long l;
+ int i;
+ float f;
+ double d;
+ byte b;
+ char c;
+ short s;
+ boolean z;
+
+ public static void main(String[] args) {
+ constantStore();
+ valueTest(false);
+ valueTest(true);
+ }
+ static void constantStore() {
+ for (int field = 0; field < 8; field++) {
+ try {
+ Test7103261 o = nonnull_value;
+ for (int i = 0; i < 100000; i++) {
+ switch (field) {
+ case 0: o.l = 0; break;
+ case 1: o.i = 0; break;
+ case 2: o.f = 0; break;
+ case 3: o.d = 0; break;
+ case 4: o.b = 0; break;
+ case 5: o.c = 0; break;
+ case 6: o.s = 0; break;
+ case 7: o.z = false; break;
+ default: throw new InternalError();
+ }
+ if (i == 90000) {
+ // hide nullness from optimizer
+ o = null_value;
+ }
+ }
+ } catch (NullPointerException npe) {
+ }
+ }
+ }
+ static void valueTest(boolean store) {
+ for (int field = 0; field < 8; field++) {
+ try {
+ Test7103261 o = nonnull_value;
+ Test7103261 o2 = nonnull_value2;
+ for (int i = 0; i < 100000; i++) {
+ switch (field) {
+ case 0: o.l = o2.l; break;
+ case 1: o.i = o2.i; break;
+ case 2: o.f = o2.f; break;
+ case 3: o.d = o2.d; break;
+ case 4: o.b = o2.b; break;
+ case 5: o.c = o2.c; break;
+ case 6: o.s = o2.s; break;
+ case 7: o.z = o2.z; break;
+ default: throw new InternalError();
+ }
+ if (i == 90000) {
+ // hide nullness from optimizer
+ if (store)
+ o = null_value;
+ else
+ o2 = null_value;
+ }
+ }
+ } catch (NullPointerException npe) {
+ }
+ }
+ }
+}
--- a/jaxp/.hgtags Thu Nov 17 10:46:00 2011 -0800
+++ b/jaxp/.hgtags Wed Jul 05 17:56:12 2017 +0200
@@ -135,3 +135,4 @@
d1b7a4f6dd2065fdeafbcdfd9dcc0072da8c6881 jdk8-b11
ca977d167697a561c04894187fc1c4d927582ffa jdk8-b12
bcc739229f6384786c7ac0b52c1822c85674dcf1 jdk8-b13
+9d0c9d638757cb09de18933b946fa04b4f3fb94f jdk8-b14
--- a/jdk/.hgtags Thu Nov 17 10:46:00 2011 -0800
+++ b/jdk/.hgtags Wed Jul 05 17:56:12 2017 +0200
@@ -135,3 +135,4 @@
7ab0d613cd1a271a9763ffb894dc1f0a5b95a7e4 jdk8-b11
09fd2067f715e4505c44b01c301258a4e8f8964e jdk8-b12
4cb2e8679b27432854690cb688ea06d3b2d8e008 jdk8-b13
+99632935785e2038b2fc836da9f2ede69dea294b jdk8-b14
--- a/jdk/make/docs/Makefile Thu Nov 17 10:46:00 2011 -0800
+++ b/jdk/make/docs/Makefile Wed Jul 05 17:56:12 2017 +0200
@@ -71,7 +71,7 @@
ifeq ($(ARCH_DATA_MODEL),64)
MAX_VM_MEMORY = 1024
else
- MAX_VM_MEMORY = 512
+ MAX_VM_MEMORY = 612
endif
# List of all possible directories for javadoc to look for sources
--- a/jdk/src/share/classes/java/io/FileInputStream.java Thu Nov 17 10:46:00 2011 -0800
+++ b/jdk/src/share/classes/java/io/FileInputStream.java Wed Jul 05 17:56:12 2017 +0200
@@ -124,7 +124,7 @@
throw new NullPointerException();
}
fd = new FileDescriptor();
- fd.incrementAndGetUseCount();
+ fd.attach(this);
open(name);
}
@@ -164,10 +164,9 @@
/*
* FileDescriptor is being shared by streams.
- * Ensure that it's GC'ed only when all the streams/channels are done
- * using it.
+ * Register this stream with FileDescriptor tracker.
*/
- fd.incrementAndGetUseCount();
+ fd.attach(this);
}
/**
@@ -294,27 +293,14 @@
closed = true;
}
if (channel != null) {
- /*
- * Decrement the FD use count associated with the channel
- * The use count is incremented whenever a new channel
- * is obtained from this stream.
- */
- fd.decrementAndGetUseCount();
channel.close();
}
- /*
- * Decrement the FD use count associated with this stream
- */
- int useCount = fd.decrementAndGetUseCount();
-
- /*
- * If FileDescriptor is still in use by another stream, we
- * will not close it.
- */
- if (useCount <= 0) {
- close0();
- }
+ fd.closeAll(new Closeable() {
+ public void close() throws IOException {
+ close0();
+ }
+ });
}
/**
@@ -328,7 +314,9 @@
* @see java.io.FileDescriptor
*/
public final FileDescriptor getFD() throws IOException {
- if (fd != null) return fd;
+ if (fd != null) {
+ return fd;
+ }
throw new IOException();
}
@@ -352,13 +340,6 @@
synchronized (this) {
if (channel == null) {
channel = FileChannelImpl.open(fd, true, false, this);
-
- /*
- * Increment fd's use count. Invoking the channel's close()
- * method will result in decrementing the use count set for
- * the channel.
- */
- fd.incrementAndGetUseCount();
}
return channel;
}
@@ -381,7 +362,12 @@
*/
protected void finalize() throws IOException {
if ((fd != null) && (fd != FileDescriptor.in)) {
- close();
+ /* if fd is shared, the references in FileDescriptor
+ * will ensure that finalizer is only called when
+ * safe to do so. All references using the fd have
+ * become unreachable. We can call close()
+ */
+ close();
}
}
}
--- a/jdk/src/share/classes/java/io/FileOutputStream.java Thu Nov 17 10:46:00 2011 -0800
+++ b/jdk/src/share/classes/java/io/FileOutputStream.java Wed Jul 05 17:56:12 2017 +0200
@@ -197,9 +197,9 @@
throw new NullPointerException();
}
this.fd = new FileDescriptor();
+ fd.attach(this);
this.append = append;
- fd.incrementAndGetUseCount();
open(name, append);
}
@@ -237,12 +237,7 @@
this.fd = fdObj;
this.append = false;
- /*
- * FileDescriptor is being shared by streams.
- * Ensure that it's GC'ed only when all the streams/channels are done
- * using it.
- */
- fd.incrementAndGetUseCount();
+ fd.attach(this);
}
/**
@@ -331,27 +326,14 @@
}
if (channel != null) {
- /*
- * Decrement FD use count associated with the channel
- * The use count is incremented whenever a new channel
- * is obtained from this stream.
- */
- fd.decrementAndGetUseCount();
channel.close();
}
- /*
- * Decrement FD use count associated with this stream
- */
- int useCount = fd.decrementAndGetUseCount();
-
- /*
- * If FileDescriptor is still in use by another stream, we
- * will not close it.
- */
- if (useCount <= 0) {
- close0();
- }
+ fd.closeAll(new Closeable() {
+ public void close() throws IOException {
+ close0();
+ }
+ });
}
/**
@@ -365,7 +347,9 @@
* @see java.io.FileDescriptor
*/
public final FileDescriptor getFD() throws IOException {
- if (fd != null) return fd;
+ if (fd != null) {
+ return fd;
+ }
throw new IOException();
}
@@ -390,13 +374,6 @@
synchronized (this) {
if (channel == null) {
channel = FileChannelImpl.open(fd, false, true, append, this);
-
- /*
- * Increment fd's use count. Invoking the channel's close()
- * method will result in decrementing the use count set for
- * the channel.
- */
- fd.incrementAndGetUseCount();
}
return channel;
}
@@ -415,7 +392,12 @@
if (fd == FileDescriptor.out || fd == FileDescriptor.err) {
flush();
} else {
- close();
+ /* if fd is shared, the references in FileDescriptor
+ * will ensure that finalizer is only called when
+ * safe to do so. All references using the fd have
+ * become unreachable. We can call close()
+ */
+ close();
}
}
}
--- a/jdk/src/share/classes/java/io/RandomAccessFile.java Thu Nov 17 10:46:00 2011 -0800
+++ b/jdk/src/share/classes/java/io/RandomAccessFile.java Wed Jul 05 17:56:12 2017 +0200
@@ -229,7 +229,7 @@
throw new NullPointerException();
}
fd = new FileDescriptor();
- fd.incrementAndGetUseCount();
+ fd.attach(this);
open(name, imode);
}
@@ -242,7 +242,9 @@
* @see java.io.FileDescriptor
*/
public final FileDescriptor getFD() throws IOException {
- if (fd != null) return fd;
+ if (fd != null) {
+ return fd;
+ }
throw new IOException();
}
@@ -268,17 +270,6 @@
synchronized (this) {
if (channel == null) {
channel = FileChannelImpl.open(fd, true, rw, this);
-
- /*
- * FileDescriptor could be shared by FileInputStream or
- * FileOutputStream.
- * Ensure that FD is GC'ed only when all the streams/channels
- * are done using it.
- * Increment fd's use count. Invoking the channel's close()
- * method will result in decrementing the use count set for
- * the channel.
- */
- fd.incrementAndGetUseCount();
}
return channel;
}
@@ -577,28 +568,14 @@
closed = true;
}
if (channel != null) {
- /*
- * Decrement FD use count associated with the channel. The FD use
- * count is incremented whenever a new channel is obtained from
- * this stream.
- */
- fd.decrementAndGetUseCount();
channel.close();
}
- /*
- * Decrement FD use count associated with this stream.
- * The count got incremented by FileDescriptor during its construction.
- */
- int useCount = fd.decrementAndGetUseCount();
-
- /*
- * If FileDescriptor is still in use by another stream, we
- * will not close it.
- */
- if (useCount <= 0) {
- close0();
- }
+ fd.closeAll(new Closeable() {
+ public void close() throws IOException {
+ close0();
+ }
+ });
}
//
--- a/jdk/src/share/classes/java/io/Writer.java Thu Nov 17 10:46:00 2011 -0800
+++ b/jdk/src/share/classes/java/io/Writer.java Wed Jul 05 17:56:12 2017 +0200
@@ -57,7 +57,7 @@
/**
* Size of writeBuffer, must be >= 1
*/
- private final int writeBufferSize = 1024;
+ private static final int WRITE_BUFFER_SIZE = 1024;
/**
* The object used to synchronize operations on this stream. For
@@ -107,7 +107,7 @@
public void write(int c) throws IOException {
synchronized (lock) {
if (writeBuffer == null){
- writeBuffer = new char[writeBufferSize];
+ writeBuffer = new char[WRITE_BUFFER_SIZE];
}
writeBuffer[0] = (char) c;
write(writeBuffer, 0, 1);
@@ -180,9 +180,9 @@
public void write(String str, int off, int len) throws IOException {
synchronized (lock) {
char cbuf[];
- if (len <= writeBufferSize) {
+ if (len <= WRITE_BUFFER_SIZE) {
if (writeBuffer == null) {
- writeBuffer = new char[writeBufferSize];
+ writeBuffer = new char[WRITE_BUFFER_SIZE];
}
cbuf = writeBuffer;
} else { // Don't permanently allocate very large buffers.
--- a/jdk/src/share/classes/java/lang/AssertionError.java Thu Nov 17 10:46:00 2011 -0800
+++ b/jdk/src/share/classes/java/lang/AssertionError.java Wed Jul 05 17:56:12 2017 +0200
@@ -71,7 +71,7 @@
* @see Throwable#getCause()
*/
public AssertionError(Object detailMessage) {
- this("" + detailMessage);
+ this(String.valueOf(detailMessage));
if (detailMessage instanceof Throwable)
initCause((Throwable) detailMessage);
}
@@ -85,7 +85,7 @@
* @param detailMessage value to be used in constructing detail message
*/
public AssertionError(boolean detailMessage) {
- this("" + detailMessage);
+ this(String.valueOf(detailMessage));
}
/**
@@ -97,7 +97,7 @@
* @param detailMessage value to be used in constructing detail message
*/
public AssertionError(char detailMessage) {
- this("" + detailMessage);
+ this(String.valueOf(detailMessage));
}
/**
@@ -109,7 +109,7 @@
* @param detailMessage value to be used in constructing detail message
*/
public AssertionError(int detailMessage) {
- this("" + detailMessage);
+ this(String.valueOf(detailMessage));
}
/**
@@ -121,7 +121,7 @@
* @param detailMessage value to be used in constructing detail message
*/
public AssertionError(long detailMessage) {
- this("" + detailMessage);
+ this(String.valueOf(detailMessage));
}
/**
@@ -133,7 +133,7 @@
* @param detailMessage value to be used in constructing detail message
*/
public AssertionError(float detailMessage) {
- this("" + detailMessage);
+ this(String.valueOf(detailMessage));
}
/**
@@ -145,7 +145,7 @@
* @param detailMessage value to be used in constructing detail message
*/
public AssertionError(double detailMessage) {
- this("" + detailMessage);
+ this(String.valueOf(detailMessage));
}
/**
--- a/jdk/src/share/classes/java/lang/Class.java Thu Nov 17 10:46:00 2011 -0800
+++ b/jdk/src/share/classes/java/lang/Class.java Wed Jul 05 17:56:12 2017 +0200
@@ -3008,7 +3008,7 @@
/**
* Casts this {@code Class} object to represent a subclass of the class
- * represented by the specified class object. Checks that that the cast
+ * represented by the specified class object. Checks that the cast
* is valid, and throws a {@code ClassCastException} if it is not. If
* this method succeeds, it always returns a reference to this class object.
*
--- a/jdk/src/share/classes/java/lang/Double.java Thu Nov 17 10:46:00 2011 -0800
+++ b/jdk/src/share/classes/java/lang/Double.java Wed Jul 05 17:56:12 2017 +0200
@@ -607,8 +607,7 @@
* @see java.lang.Double#valueOf(java.lang.String)
*/
public Double(String s) throws NumberFormatException {
- // REMIND: this is inefficient
- this(valueOf(s).doubleValue());
+ value = parseDouble(s);
}
/**
--- a/jdk/src/share/classes/java/lang/Float.java Thu Nov 17 10:46:00 2011 -0800
+++ b/jdk/src/share/classes/java/lang/Float.java Wed Jul 05 17:56:12 2017 +0200
@@ -529,8 +529,7 @@
* @see java.lang.Float#valueOf(java.lang.String)
*/
public Float(String s) throws NumberFormatException {
- // REMIND: this is inefficient
- this(valueOf(s).floatValue());
+ value = parseFloat(s);
}
/**
--- a/jdk/src/share/classes/java/lang/invoke/CallSite.java Thu Nov 17 10:46:00 2011 -0800
+++ b/jdk/src/share/classes/java/lang/invoke/CallSite.java Wed Jul 05 17:56:12 2017 +0200
@@ -266,7 +266,7 @@
/*package-private*/
void setTargetNormal(MethodHandle newTarget) {
- target = newTarget;
+ MethodHandleNatives.setCallSiteTargetNormal(this, newTarget);
}
/*package-private*/
MethodHandle getTargetVolatile() {
@@ -274,7 +274,7 @@
}
/*package-private*/
void setTargetVolatile(MethodHandle newTarget) {
- unsafe.putObjectVolatile(this, TARGET_OFFSET, newTarget);
+ MethodHandleNatives.setCallSiteTargetVolatile(this, newTarget);
}
// this implements the upcall from the JVM, MethodHandleNatives.makeDynamicCallSite:
--- a/jdk/src/share/classes/java/lang/invoke/MethodHandleImpl.java Thu Nov 17 10:46:00 2011 -0800
+++ b/jdk/src/share/classes/java/lang/invoke/MethodHandleImpl.java Wed Jul 05 17:56:12 2017 +0200
@@ -934,12 +934,4 @@
return THROW_EXCEPTION;
}
static <T extends Throwable> Empty throwException(T t) throws T { throw t; }
-
- // Linkage support:
- static void registerBootstrap(Class<?> callerClass, MethodHandle bootstrapMethod) {
- MethodHandleNatives.registerBootstrap(callerClass, bootstrapMethod);
- }
- static MethodHandle getBootstrap(Class<?> callerClass) {
- return MethodHandleNatives.getBootstrap(callerClass);
- }
}
--- a/jdk/src/share/classes/java/lang/invoke/MethodHandleNatives.java Thu Nov 17 10:46:00 2011 -0800
+++ b/jdk/src/share/classes/java/lang/invoke/MethodHandleNatives.java Wed Jul 05 17:56:12 2017 +0200
@@ -61,15 +61,6 @@
/** Initialize a method type, once per form. */
static native void init(MethodType self);
- /** Tell the JVM about a class's bootstrap method. */
- static native void registerBootstrap(Class<?> caller, MethodHandle bootstrapMethod);
-
- /** Ask the JVM about a class's bootstrap method. */
- static native MethodHandle getBootstrap(Class<?> caller);
-
- /** Tell the JVM that we need to change the target of an invokedynamic. */
- static native void setCallSiteTarget(CallSite site, MethodHandle target);
-
/** Fetch the vmtarget field.
* It will be sanitized as necessary to avoid exposing non-Java references.
* This routine is for debugging and reflection.
@@ -122,6 +113,12 @@
static final boolean COUNT_GWT;
+ /// CallSite support
+
+ /** Tell the JVM that we need to change the target of a CallSite. */
+ static native void setCallSiteTargetNormal(CallSite site, MethodHandle target);
+ static native void setCallSiteTargetVolatile(CallSite site, MethodHandle target);
+
private static native void registerNatives();
static {
registerNatives();
--- a/jdk/src/share/classes/java/security/Policy.java Thu Nov 17 10:46:00 2011 -0800
+++ b/jdk/src/share/classes/java/security/Policy.java Wed Jul 05 17:56:12 2017 +0200
@@ -28,6 +28,7 @@
import java.util.Enumeration;
import java.util.WeakHashMap;
+import java.util.concurrent.atomic.AtomicReference;
import sun.security.jca.GetInstance;
import sun.security.util.Debug;
import sun.security.util.SecurityConstants;
@@ -60,8 +61,8 @@
* with a standard type. The default policy type is "JavaPolicy".
*
* <p> Once a Policy instance has been installed (either by default, or by
- * calling <code>setPolicy</code>),
- * the Java runtime invokes its <code>implies</code> when it needs to
+ * calling <code>setPolicy</code>), the Java runtime invokes its
+ * <code>implies</code> method when it needs to
* determine whether executing code (encapsulated in a ProtectionDomain)
* can perform SecurityManager-protected operations. How a Policy object
* retrieves its policy data is up to the Policy implementation itself.
@@ -94,18 +95,33 @@
public static final PermissionCollection UNSUPPORTED_EMPTY_COLLECTION =
new UnsupportedEmptyCollection();
- /** the system-wide policy. */
- private static Policy policy; // package private for AccessControlContext
+ // Information about the system-wide policy.
+ private static class PolicyInfo {
+ // the system-wide policy
+ final Policy policy;
+ // a flag indicating if the system-wide policy has been initialized
+ final boolean initialized;
+
+ PolicyInfo(Policy policy, boolean initialized) {
+ this.policy = policy;
+ this.initialized = initialized;
+ }
+ }
+
+ // PolicyInfo is stored in an AtomicReference
+ private static AtomicReference<PolicyInfo> policy =
+ new AtomicReference<>(new PolicyInfo(null, false));
private static final Debug debug = Debug.getInstance("policy");
// Cache mapping ProtectionDomain.Key to PermissionCollection
private WeakHashMap<ProtectionDomain.Key, PermissionCollection> pdMapping;
- /** package private for AccessControlContext */
+ /** package private for AccessControlContext and ProtectionDomain */
static boolean isSet()
{
- return policy != null;
+ PolicyInfo pi = policy.get();
+ return pi.policy != null && pi.initialized == true;
}
private static void checkPermission(String type) {
@@ -143,80 +159,92 @@
/**
* Returns the installed Policy object, skipping the security check.
- * Used by SecureClassLoader and getPolicy.
+ * Used by ProtectionDomain and getPolicy.
*
* @return the installed Policy.
- *
*/
- static synchronized Policy getPolicyNoCheck()
+ static Policy getPolicyNoCheck()
{
- if (policy == null) {
- String policy_class = null;
- policy_class = AccessController.doPrivileged(
- new PrivilegedAction<String>() {
- public String run() {
- return Security.getProperty("policy.provider");
- }
- });
- if (policy_class == null) {
- policy_class = "sun.security.provider.PolicyFile";
- }
-
- try {
- policy = (Policy)
- Class.forName(policy_class).newInstance();
- } catch (Exception e) {
- /*
- * The policy_class seems to be an extension
- * so we have to bootstrap loading it via a policy
- * provider that is on the bootclasspath
- * If it loads then shift gears to using the configured
- * provider.
- */
-
- // install the bootstrap provider to avoid recursion
- policy = new sun.security.provider.PolicyFile();
-
- final String pc = policy_class;
- Policy p = AccessController.doPrivileged(
- new PrivilegedAction<Policy>() {
- public Policy run() {
- try {
- ClassLoader cl =
- ClassLoader.getSystemClassLoader();
- // we want the extension loader
- ClassLoader extcl = null;
- while (cl != null) {
- extcl = cl;
- cl = cl.getParent();
- }
- return (extcl != null ? (Policy)Class.forName(
- pc, true, extcl).newInstance() : null);
- } catch (Exception e) {
- if (debug != null) {
- debug.println("policy provider " +
- pc +
- " not available");
- e.printStackTrace();
- }
- return null;
- }
+ PolicyInfo pi = policy.get();
+ // Use double-check idiom to avoid locking if system-wide policy is
+ // already initialized
+ if (pi.initialized == false || pi.policy == null) {
+ synchronized (Policy.class) {
+ PolicyInfo pinfo = policy.get();
+ if (pinfo.policy == null) {
+ String policy_class = AccessController.doPrivileged(
+ new PrivilegedAction<String>() {
+ public String run() {
+ return Security.getProperty("policy.provider");
}
});
- /*
- * if it loaded install it as the policy provider. Otherwise
- * continue to use the system default implementation
- */
- if (p != null) {
- policy = p;
- } else {
- if (debug != null) {
- debug.println("using sun.security.provider.PolicyFile");
+ if (policy_class == null) {
+ policy_class = "sun.security.provider.PolicyFile";
}
+
+ try {
+ pinfo = new PolicyInfo(
+ (Policy) Class.forName(policy_class).newInstance(),
+ true);
+ } catch (Exception e) {
+ /*
+ * The policy_class seems to be an extension
+ * so we have to bootstrap loading it via a policy
+ * provider that is on the bootclasspath.
+ * If it loads then shift gears to using the configured
+ * provider.
+ */
+
+ // install the bootstrap provider to avoid recursion
+ Policy polFile = new sun.security.provider.PolicyFile();
+ pinfo = new PolicyInfo(polFile, false);
+ policy.set(pinfo);
+
+ final String pc = policy_class;
+ Policy pol = AccessController.doPrivileged(
+ new PrivilegedAction<Policy>() {
+ public Policy run() {
+ try {
+ ClassLoader cl =
+ ClassLoader.getSystemClassLoader();
+ // we want the extension loader
+ ClassLoader extcl = null;
+ while (cl != null) {
+ extcl = cl;
+ cl = cl.getParent();
+ }
+ return (extcl != null ? (Policy)Class.forName(
+ pc, true, extcl).newInstance() : null);
+ } catch (Exception e) {
+ if (debug != null) {
+ debug.println("policy provider " +
+ pc +
+ " not available");
+ e.printStackTrace();
+ }
+ return null;
+ }
+ }
+ });
+ /*
+ * if it loaded install it as the policy provider. Otherwise
+ * continue to use the system default implementation
+ */
+ if (pol != null) {
+ pinfo = new PolicyInfo(pol, true);
+ } else {
+ if (debug != null) {
+ debug.println("using sun.security.provider.PolicyFile");
+ }
+ pinfo = new PolicyInfo(polFile, true);
+ }
+ }
+ policy.set(pinfo);
}
+ return pinfo.policy;
}
}
- return policy;
+ return pi.policy;
}
/**
@@ -245,7 +273,7 @@
initPolicy(p);
}
synchronized (Policy.class) {
- Policy.policy = p;
+ policy.set(new PolicyInfo(p, p != null));
}
}
@@ -292,14 +320,14 @@
PermissionCollection policyPerms = null;
synchronized (p) {
if (p.pdMapping == null) {
- p.pdMapping =
- new WeakHashMap<ProtectionDomain.Key, PermissionCollection>();
+ p.pdMapping = new WeakHashMap<>();
}
}
if (policyDomain.getCodeSource() != null) {
- if (Policy.isSet()) {
- policyPerms = policy.getPermissions(policyDomain);
+ Policy pol = policy.get().policy;
+ if (pol != null) {
+ policyPerms = pol.getPermissions(policyDomain);
}
if (policyPerms == null) { // assume it has all
@@ -434,7 +462,7 @@
type,
params);
} catch (NoSuchAlgorithmException nsae) {
- return handleException (nsae);
+ return handleException(nsae);
}
}
@@ -494,7 +522,7 @@
type,
params);
} catch (NoSuchAlgorithmException nsae) {
- return handleException (nsae);
+ return handleException(nsae);
}
}
@@ -808,7 +836,7 @@
*
* @param permission the Permission object to compare.
*
- * @return true if "permission" is implied by the permissions in
+ * @return true if "permission" is implied by the permissions in
* the collection, false if not.
*/
@Override public boolean implies(Permission permission) {
--- a/jdk/src/share/classes/java/sql/PreparedStatement.java Thu Nov 17 10:46:00 2011 -0800
+++ b/jdk/src/share/classes/java/sql/PreparedStatement.java Wed Jul 05 17:56:12 2017 +0200
@@ -767,7 +767,7 @@
/**
- * Sets the designated paramter to the given <code>String</code> object.
+ * Sets the designated parameter to the given <code>String</code> object.
* The driver converts this to a SQL <code>NCHAR</code> or
* <code>NVARCHAR</code> or <code>LONGNVARCHAR</code> value
* (depending on the argument's
--- a/jdk/src/share/classes/java/sql/Statement.java Thu Nov 17 10:46:00 2011 -0800
+++ b/jdk/src/share/classes/java/sql/Statement.java Wed Jul 05 17:56:12 2017 +0200
@@ -991,7 +991,7 @@
/**
* Requests that a <code>Statement</code> be pooled or not pooled. The value
* specified is a hint to the statement pool implementation indicating
- * whether the applicaiton wants the statement to be pooled. It is up to
+ * whether the application wants the statement to be pooled. It is up to
* the statement pool manager as to whether the hint is used.
* <p>
* The poolable value of a statement is applicable to both internal
--- a/jdk/src/share/classes/java/util/concurrent/LinkedBlockingDeque.java Thu Nov 17 10:46:00 2011 -0800
+++ b/jdk/src/share/classes/java/util/concurrent/LinkedBlockingDeque.java Wed Jul 05 17:56:12 2017 +0200
@@ -742,6 +742,8 @@
throw new NullPointerException();
if (c == this)
throw new IllegalArgumentException();
+ if (maxElements <= 0)
+ return 0;
final ReentrantLock lock = this.lock;
lock.lock();
try {
--- a/jdk/src/share/classes/java/util/concurrent/LinkedBlockingQueue.java Thu Nov 17 10:46:00 2011 -0800
+++ b/jdk/src/share/classes/java/util/concurrent/LinkedBlockingQueue.java Wed Jul 05 17:56:12 2017 +0200
@@ -332,7 +332,7 @@
// Note: convention in all put/take/etc is to preset local var
// holding count negative to indicate failure unless set.
int c = -1;
- Node<E> node = new Node(e);
+ Node<E> node = new Node<E>(e);
final ReentrantLock putLock = this.putLock;
final AtomicInteger count = this.count;
putLock.lockInterruptibly();
@@ -412,7 +412,7 @@
if (count.get() == capacity)
return false;
int c = -1;
- Node<E> node = new Node(e);
+ Node<E> node = new Node<E>(e);
final ReentrantLock putLock = this.putLock;
putLock.lock();
try {
@@ -728,6 +728,8 @@
throw new NullPointerException();
if (c == this)
throw new IllegalArgumentException();
+ if (maxElements <= 0)
+ return 0;
boolean signalNotFull = false;
final ReentrantLock takeLock = this.takeLock;
takeLock.lock();
--- a/jdk/src/share/classes/java/util/jar/Attributes.java Thu Nov 17 10:46:00 2011 -0800
+++ b/jdk/src/share/classes/java/util/jar/Attributes.java Wed Jul 05 17:56:12 2017 +0200
@@ -629,7 +629,7 @@
public static final Name IMPLEMENTATION_VENDOR_ID = new Name("Implementation-Vendor-Id");
/**
- * <code>Name</code> object for <code>Implementation-Vendor-URL</code>
+ * <code>Name</code> object for <code>Implementation-URL</code>
* manifest attribute used for package versioning.
* @see <a href="../../../../technotes/guides/versioning/spec/versioning2.html#wp90779">
* Java Product Versioning Specification</a>
--- a/jdk/src/share/classes/sun/net/httpserver/ServerImpl.java Thu Nov 17 10:46:00 2011 -0800
+++ b/jdk/src/share/classes/sun/net/httpserver/ServerImpl.java Wed Jul 05 17:56:12 2017 +0200
@@ -402,10 +402,10 @@
} catch (IOException e) {
logger.log (Level.FINER, "Dispatcher (4)", e);
} catch (Exception e) {
- e.printStackTrace();
logger.log (Level.FINER, "Dispatcher (7)", e);
}
}
+ try {selector.close(); } catch (Exception e) {}
}
private void handleException (SelectionKey key, Exception e) {
--- a/jdk/src/share/classes/sun/rmi/registry/RegistryImpl.java Thu Nov 17 10:46:00 2011 -0800
+++ b/jdk/src/share/classes/sun/rmi/registry/RegistryImpl.java Wed Jul 05 17:56:12 2017 +0200
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1996, 2008, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1996, 2011, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -29,6 +29,7 @@
import java.util.Hashtable;
import java.util.MissingResourceException;
import java.util.ResourceBundle;
+import java.io.FilePermission;
import java.io.IOException;
import java.net.*;
import java.rmi.*;
@@ -54,7 +55,6 @@
import sun.rmi.transport.LiveRef;
import sun.rmi.transport.ObjectTable;
import sun.rmi.transport.Target;
-import sun.security.action.GetPropertyAction;
/**
* A "registry" exists on every node that allows RMI connections to
@@ -335,19 +335,6 @@
URL[] urls = sun.misc.URLClassPath.pathToURLs(envcp);
ClassLoader cl = new URLClassLoader(urls);
- String codebaseProperty = null;
- String prop = java.security.AccessController.doPrivileged(
- new GetPropertyAction("java.rmi.server.codebase"));
- if (prop != null && prop.trim().length() > 0) {
- codebaseProperty = prop;
- }
- URL[] codebaseURLs = null;
- if (codebaseProperty != null) {
- codebaseURLs = sun.misc.URLClassPath.pathToURLs(codebaseProperty);
- } else {
- codebaseURLs = new URL[0];
- }
-
/*
* Fix bugid 4242317: Classes defined by this class loader should
* be annotated with the value of the "java.rmi.server.codebase"
@@ -365,7 +352,7 @@
public RegistryImpl run() throws RemoteException {
return new RegistryImpl(regPort);
}
- }, getAccessControlContext(codebaseURLs));
+ }, getAccessControlContext());
} catch (PrivilegedActionException ex) {
throw (RemoteException) ex.getException();
}
@@ -391,11 +378,11 @@
}
/**
- * Generates an AccessControlContext from several URLs.
+ * Generates an AccessControlContext with minimal permissions.
* The approach used here is taken from the similar method
* getAccessControlContext() in the sun.applet.AppletPanel class.
*/
- private static AccessControlContext getAccessControlContext(URL[] urls) {
+ private static AccessControlContext getAccessControlContext() {
// begin with permissions granted to all code in current policy
PermissionCollection perms = AccessController.doPrivileged(
new java.security.PrivilegedAction<PermissionCollection>() {
@@ -420,17 +407,15 @@
perms.add(new RuntimePermission("accessClassInPackage.sun.*"));
- // add permissions required to load from codebase URL path
- LoaderHandler.addPermissionsForURLs(urls, perms, false);
+ perms.add(new FilePermission("<<ALL FILES>>", "read"));
/*
* Create an AccessControlContext that consists of a single
* protection domain with only the permissions calculated above.
*/
ProtectionDomain pd = new ProtectionDomain(
- new CodeSource((urls.length > 0 ? urls[0] : null),
- (java.security.cert.Certificate[]) null),
- perms);
+ new CodeSource(null,
+ (java.security.cert.Certificate[]) null), perms);
return new AccessControlContext(new ProtectionDomain[] { pd });
}
}
--- a/jdk/src/share/classes/sun/rmi/server/LoaderHandler.java Thu Nov 17 10:46:00 2011 -0800
+++ b/jdk/src/share/classes/sun/rmi/server/LoaderHandler.java Wed Jul 05 17:56:12 2017 +0200
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1996, 2008, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1996, 2011, 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
@@ -1031,7 +1031,7 @@
* loader. A given permission is only added to the collection if
* it is not already implied by the collection.
*/
- public static void addPermissionsForURLs(URL[] urls,
+ private static void addPermissionsForURLs(URL[] urls,
PermissionCollection perms,
boolean forLoader)
{
--- a/jdk/src/share/classes/sun/security/krb5/internal/KerberosTime.java Thu Nov 17 10:46:00 2011 -0800
+++ b/jdk/src/share/classes/sun/security/krb5/internal/KerberosTime.java Wed Jul 05 17:56:12 2017 +0200
@@ -68,8 +68,8 @@
private int microSeconds; // the last three digits of the microsecond value
// The time when this class is loaded. Used in setNow()
- private static final long initMilli = System.currentTimeMillis();
- private static final long initMicro = System.nanoTime() / 1000;
+ private static long initMilli = System.currentTimeMillis();
+ private static long initMicro = System.nanoTime() / 1000;
private static long syncTime;
private static boolean DEBUG = Krb5.DEBUG;
@@ -212,9 +212,22 @@
}
public void setNow() {
- long microElapsed = System.nanoTime() / 1000 - initMicro;
- setTime(initMilli + microElapsed/1000);
- microSeconds = (int)(microElapsed % 1000);
+ long newMilli = System.currentTimeMillis();
+ long newMicro = System.nanoTime() / 1000;
+ long microElapsed = newMicro - initMicro;
+ long calcMilli = initMilli + microElapsed/1000;
+ if (calcMilli - newMilli > 100 || newMilli - calcMilli > 100) {
+ if (DEBUG) {
+ System.out.println("System time adjusted");
+ }
+ initMilli = newMilli;
+ initMicro = newMicro;
+ setTime(newMilli);
+ microSeconds = 0;
+ } else {
+ setTime(calcMilli);
+ microSeconds = (int)(microElapsed % 1000);
+ }
}
public int getMicroSeconds() {
--- a/jdk/src/share/classes/sun/security/krb5/internal/ccache/CCacheInputStream.java Thu Nov 17 10:46:00 2011 -0800
+++ b/jdk/src/share/classes/sun/security/krb5/internal/ccache/CCacheInputStream.java Wed Jul 05 17:56:12 2017 +0200
@@ -375,7 +375,7 @@
}
AuthorizationDataEntry[] auDataEntry = readAuth();
AuthorizationData auData = null;
- if (auData != null) {
+ if (auDataEntry != null) {
auData = new AuthorizationData(auDataEntry);
}
byte[] ticketData = readData();
--- a/jdk/src/share/classes/sun/security/krb5/internal/ccache/Credentials.java Thu Nov 17 10:46:00 2011 -0800
+++ b/jdk/src/share/classes/sun/security/krb5/internal/ccache/Credentials.java Wed Jul 05 17:56:12 2017 +0200
@@ -209,10 +209,24 @@
}
public sun.security.krb5.Credentials setKrbCreds() {
+ // Note: We will not pass authorizationData to s.s.k.Credentials. The
+ // field in that class will be passed to Krb5Context as the return
+ // value of ExtendedGSSContext.inquireSecContext(KRB5_GET_AUTHZ_DATA),
+ // which is documented as the authData in the service ticket. That
+ // is on the acceptor side.
+ //
+ // This class is for the initiator side. Also, authdata inside a ccache
+ // is most likely to be the one in Authenticator in PA-TGS-REQ encoded
+ // in TGS-REQ, therefore only stored with a service ticket. Currently
+ // in Java, we only reads TGTs.
return new sun.security.krb5.Credentials(ticket,
cname, sname, key, flags, authtime, starttime, endtime, renewTill, caddr);
}
+ public KerberosTime getStartTime() {
+ return starttime;
+ }
+
public KerberosTime getAuthTime() {
return authtime;
}
@@ -221,6 +235,10 @@
return endtime;
}
+ public KerberosTime getRenewTill() {
+ return renewTill;
+ }
+
public TicketFlags getTicketFlags() {
return flags;
}
@@ -228,4 +246,8 @@
public int getEType() {
return key.getEType();
}
+
+ public int getTktEType() {
+ return ticket.encPart.getEType();
+ }
}
--- a/jdk/src/share/classes/sun/security/ssl/SSLContextImpl.java Thu Nov 17 10:46:00 2011 -0800
+++ b/jdk/src/share/classes/sun/security/ssl/SSLContextImpl.java Wed Jul 05 17:56:12 2017 +0200
@@ -771,10 +771,15 @@
final class AbstractTrustManagerWrapper extends X509ExtendedTrustManager
implements X509TrustManager {
+ // the delegated trust manager
private final X509TrustManager tm;
+ // Cache the trusted certificate to optimize the performance.
+ private final Collection<X509Certificate> trustedCerts = new HashSet<>();
+
AbstractTrustManagerWrapper(X509TrustManager tm) {
this.tm = tm;
+ Collections.addAll(trustedCerts, tm.getAcceptedIssuers());
}
@Override
@@ -863,20 +868,7 @@
constraints = new SSLAlgorithmConstraints(sslSocket, true);
}
- AlgorithmChecker checker = new AlgorithmChecker(constraints);
- try {
- checker.init(false);
-
- // a forward checker, need to check from trust to target
- for (int i = chain.length - 1; i >= 0; i--) {
- Certificate cert = chain[i];
- // We don't care about the unresolved critical extensions.
- checker.check(cert, Collections.<String>emptySet());
- }
- } catch (CertPathValidatorException cpve) {
- throw new CertificateException(
- "Certificates does not conform to algorithm constraints");
- }
+ checkAlgorithmConstraints(chain, constraints);
}
}
@@ -918,20 +910,33 @@
constraints = new SSLAlgorithmConstraints(engine, true);
}
- AlgorithmChecker checker = new AlgorithmChecker(constraints);
- try {
+ checkAlgorithmConstraints(chain, constraints);
+ }
+ }
+
+ private void checkAlgorithmConstraints(X509Certificate[] chain,
+ AlgorithmConstraints constraints) throws CertificateException {
+
+ try {
+ // Does the certificate chain end with a trusted certificate?
+ int checkedLength = chain.length - 1;
+ if (trustedCerts.contains(chain[checkedLength])) {
+ checkedLength--;
+ }
+
+ // A forward checker, need to check from trust to target
+ if (checkedLength >= 0) {
+ AlgorithmChecker checker = new AlgorithmChecker(constraints);
checker.init(false);
-
- // A forward checker, need to check from trust to target
- for (int i = chain.length - 1; i >= 0; i--) {
+ for (int i = checkedLength; i >= 0; i--) {
Certificate cert = chain[i];
// We don't care about the unresolved critical extensions.
checker.check(cert, Collections.<String>emptySet());
}
- } catch (CertPathValidatorException cpve) {
- throw new CertificateException(
- "Certificates does not conform to algorithm constraints");
}
+ } catch (CertPathValidatorException cpve) {
+ throw new CertificateException(
+ "Certificates does not conform to algorithm constraints");
}
}
}
--- a/jdk/src/share/classes/sun/security/ssl/SSLSocketImpl.java Thu Nov 17 10:46:00 2011 -0800
+++ b/jdk/src/share/classes/sun/security/ssl/SSLSocketImpl.java Wed Jul 05 17:56:12 2017 +0200
@@ -1485,7 +1485,8 @@
private void closeSocket(boolean selfInitiated) throws IOException {
if ((debug != null) && Debug.isOn("ssl")) {
- System.out.println(threadName() + ", called closeSocket(selfInitiated)");
+ System.out.println(threadName() +
+ ", called closeSocket(" + selfInitiated + ")");
}
if (self == this) {
super.close();
--- a/jdk/src/share/classes/sun/security/tools/CertAndKeyGen.java Thu Nov 17 10:46:00 2011 -0800
+++ b/jdk/src/share/classes/sun/security/tools/CertAndKeyGen.java Wed Jul 05 17:56:12 2017 +0200
@@ -33,18 +33,7 @@
import java.util.Date;
import sun.security.pkcs10.PKCS10;
-import sun.security.x509.AlgorithmId;
-import sun.security.x509.CertificateAlgorithmId;
-import sun.security.x509.CertificateIssuerName;
-import sun.security.x509.CertificateSerialNumber;
-import sun.security.x509.CertificateSubjectName;
-import sun.security.x509.CertificateValidity;
-import sun.security.x509.CertificateVersion;
-import sun.security.x509.CertificateX509Key;
-import sun.security.x509.X500Name;
-import sun.security.x509.X509CertImpl;
-import sun.security.x509.X509CertInfo;
-import sun.security.x509.X509Key;
+import sun.security.x509.*;
/**
@@ -165,6 +154,13 @@
publicKey = pair.getPublic();
privateKey = pair.getPrivate();
+
+ // publicKey's format must be X.509 otherwise
+ // the whole CertGen part of this class is broken.
+ if (!"X.509".equalsIgnoreCase(publicKey.getFormat())) {
+ throw new IllegalArgumentException("publicKey's is not X.509, but "
+ + publicKey.getFormat());
+ }
}
@@ -186,6 +182,16 @@
return (X509Key)publicKey;
}
+ /**
+ * Always returns the public key of the generated key pair. Used
+ * by KeyTool only.
+ *
+ * The publicKey is not necessarily to be an instance of
+ * X509Key in some JCA/JCE providers, for example SunPKCS11.
+ */
+ public PublicKey getPublicKeyAnyway() {
+ return publicKey;
+ }
/**
* Returns the private key of the generated key pair.
@@ -200,7 +206,6 @@
return privateKey;
}
-
/**
* Returns a self-signed X.509v3 certificate for the public key.
* The certificate is immediately valid. No extensions.
@@ -225,6 +230,15 @@
throws CertificateException, InvalidKeyException, SignatureException,
NoSuchAlgorithmException, NoSuchProviderException
{
+ return getSelfCertificate(myname, firstDate, validity, null);
+ }
+
+ // Like above, plus a CertificateExtensions argument, which can be null.
+ public X509Certificate getSelfCertificate (X500Name myname, Date firstDate,
+ long validity, CertificateExtensions ext)
+ throws CertificateException, InvalidKeyException, SignatureException,
+ NoSuchAlgorithmException, NoSuchProviderException
+ {
X509CertImpl cert;
Date lastDate;
@@ -248,6 +262,7 @@
info.set(X509CertInfo.KEY, new CertificateX509Key(publicKey));
info.set(X509CertInfo.VALIDITY, interval);
info.set(X509CertInfo.ISSUER, new CertificateIssuerName(myname));
+ if (ext != null) info.set(X509CertInfo.EXTENSIONS, ext);
cert = new X509CertImpl(info);
cert.sign(privateKey, this.sigAlg);
--- a/jdk/src/share/classes/sun/security/tools/KeyTool.java Thu Nov 17 10:46:00 2011 -0800
+++ b/jdk/src/share/classes/sun/security/tools/KeyTool.java Wed Jul 05 17:56:12 2017 +0200
@@ -1518,9 +1518,16 @@
keypair.generate(keysize);
PrivateKey privKey = keypair.getPrivateKey();
+ CertificateExtensions ext = createV3Extensions(
+ null,
+ null,
+ v3ext,
+ keypair.getPublicKeyAnyway(),
+ null);
+
X509Certificate[] chain = new X509Certificate[1];
chain[0] = keypair.getSelfCertificate(
- x500Name, getStartDate(startDate), validity*24L*60L*60L);
+ x500Name, getStartDate(startDate), validity*24L*60L*60L, ext);
if (verbose) {
MessageFormat form = new MessageFormat(rb.getString
@@ -1537,9 +1544,6 @@
keyPass = promptForKeyPass(alias, null, storePass);
}
keyStore.setKeyEntry(alias, privKey, keyPass, chain);
-
- // resign so that -ext are applied.
- doSelfCert(alias, null, sigAlgName);
}
/**
--- a/jdk/src/share/native/sun/awt/medialib/mlib_types.h Thu Nov 17 10:46:00 2011 -0800
+++ b/jdk/src/share/native/sun/awt/medialib/mlib_types.h Wed Jul 05 17:56:12 2017 +0200
@@ -59,13 +59,8 @@
#if defined(__SUNPRO_C) || defined(__SUNPRO_CC) || defined(__GNUC__)
-#if defined(__linux__)
-#include <stdint.h> /* for uintptr_t */
-#include <malloc.h> /* for ptrdiff_t */
-#else
-#include <link.h> /* for uintptr_t */
-#include <stddef.h> /* for ptrdiff_t */
-#endif /* __linux__ */
+#include <stdint.h>
+#include <stddef.h>
#ifdef MLIB_OS64BIT
--- a/jdk/src/solaris/classes/java/io/FileDescriptor.java Thu Nov 17 10:46:00 2011 -0800
+++ b/jdk/src/solaris/classes/java/io/FileDescriptor.java Wed Jul 05 17:56:12 2017 +0200
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1995, 2008, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1995, 2011, 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,8 @@
package java.io;
-import java.util.concurrent.atomic.AtomicInteger;
+import java.util.ArrayList;
+import java.util.List;
/**
* Instances of the file descriptor class serve as an opaque handle
@@ -46,12 +47,9 @@
private int fd;
- /**
- * A counter for tracking the FIS/FOS/RAF instances that
- * use this FileDescriptor. The FIS/FOS.finalize() will not release
- * the FileDescriptor if it is still under user by a stream.
- */
- private AtomicInteger useCount;
+ private Closeable parent;
+ private List<Closeable> otherParents;
+ private boolean closed;
/**
* Constructs an (invalid) FileDescriptor
@@ -59,12 +57,10 @@
*/
public /**/ FileDescriptor() {
fd = -1;
- useCount = new AtomicInteger();
}
private /* */ FileDescriptor(int fd) {
this.fd = fd;
- useCount = new AtomicInteger();
}
/**
@@ -164,13 +160,67 @@
);
}
- // package private methods used by FIS, FOS and RAF
+ /*
+ * Package private methods to track referents.
+ * If multiple streams point to the same FileDescriptor, we cycle
+ * through the list of all referents and call close()
+ */
- int incrementAndGetUseCount() {
- return useCount.incrementAndGet();
+ /**
+ * Attach a Closeable to this FD for tracking.
+ * parent reference is added to otherParents when
+ * needed to make closeAll simpler.
+ */
+ synchronized void attach(Closeable c) {
+ if (parent == null) {
+ // first caller gets to do this
+ parent = c;
+ } else if (otherParents == null) {
+ otherParents = new ArrayList<>();
+ otherParents.add(parent);
+ otherParents.add(c);
+ } else {
+ otherParents.add(c);
+ }
}
- int decrementAndGetUseCount() {
- return useCount.decrementAndGet();
+ /**
+ * Cycle through all Closeables sharing this FD and call
+ * close() on each one.
+ *
+ * The caller closeable gets to call close0().
+ */
+ @SuppressWarnings("try")
+ synchronized void closeAll(Closeable releaser) throws IOException {
+ if (!closed) {
+ closed = true;
+ IOException ioe = null;
+ try (Closeable c = releaser) {
+ if (otherParents != null) {
+ for (Closeable referent : otherParents) {
+ try {
+ referent.close();
+ } catch(IOException x) {
+ if (ioe == null) {
+ ioe = x;
+ } else {
+ ioe.addSuppressed(x);
+ }
+ }
+ }
+ }
+ } catch(IOException ex) {
+ /*
+ * If releaser close() throws IOException
+ * add other exceptions as suppressed.
+ */
+ if (ioe != null)
+ ex.addSuppressed(ioe);
+ ioe = ex;
+ } finally {
+ if (ioe != null)
+ throw ioe;
+ }
+ }
}
}
--- a/jdk/src/solaris/native/java/net/Inet4AddressImpl.c Thu Nov 17 10:46:00 2011 -0800
+++ b/jdk/src/solaris/native/java/net/Inet4AddressImpl.c Wed Jul 05 17:56:12 2017 +0200
@@ -43,8 +43,9 @@
#include "java_net_Inet4AddressImpl.h"
/* the initial size of our hostent buffers */
-#define HENT_BUF_SIZE 1024
-#define BIG_HENT_BUF_SIZE 10240 /* a jumbo-sized one */
+#ifndef NI_MAXHOST
+#define NI_MAXHOST 1025
+#endif
/************************************************************************
* Inet4AddressImpl
@@ -57,60 +58,36 @@
*/
JNIEXPORT jstring JNICALL
Java_java_net_Inet4AddressImpl_getLocalHostName(JNIEnv *env, jobject this) {
- char hostname[MAXHOSTNAMELEN+1];
+ char hostname[NI_MAXHOST+1];
hostname[0] = '\0';
if (JVM_GetHostName(hostname, sizeof(hostname))) {
/* Something went wrong, maybe networking is not setup? */
strcpy(hostname, "localhost");
} else {
-#ifdef __linux__
- /* On Linux gethostname() says "host.domain.sun.com". On
- * Solaris gethostname() says "host", so extra work is needed.
- */
-#else
- /* Solaris doesn't want to give us a fully qualified domain name.
- * We do a reverse lookup to try and get one. This works
- * if DNS occurs before NIS in /etc/resolv.conf, but fails
- * if NIS comes first (it still gets only a partial name).
- * We use thread-safe system calls.
- */
-#endif /* __linux__ */
- struct hostent res, res2, *hp;
- // these buffers must be pointer-aligned so they are declared
- // with pointer type
- char *buf[HENT_BUF_SIZE/(sizeof (char *))];
- char *buf2[HENT_BUF_SIZE/(sizeof (char *))];
- int h_error=0;
+ struct addrinfo hints, *res;
+ int error;
- // ensure null-terminated
- hostname[MAXHOSTNAMELEN] = '\0';
+ hostname[NI_MAXHOST] = '\0';
+ memset(&hints, 0, sizeof(hints));
+ hints.ai_flags = AI_CANONNAME;
+ hints.ai_family = AF_INET;
+
+ error = getaddrinfo(hostname, NULL, &hints, &res);
-#ifdef __GLIBC__
- gethostbyname_r(hostname, &res, (char*)buf, sizeof(buf), &hp, &h_error);
-#else
- hp = gethostbyname_r(hostname, &res, (char*)buf, sizeof(buf), &h_error);
-#endif
- if (hp) {
-#ifdef __GLIBC__
- gethostbyaddr_r(hp->h_addr, hp->h_length, AF_INET,
- &res2, (char*)buf2, sizeof(buf2), &hp, &h_error);
-#else
- hp = gethostbyaddr_r(hp->h_addr, hp->h_length, AF_INET,
- &res2, (char*)buf2, sizeof(buf2), &h_error);
-#endif
- if (hp) {
- /*
- * If gethostbyaddr_r() found a fully qualified host name,
- * returns that name. Otherwise, returns the hostname
- * found by gethostname().
- */
- char *p = hp->h_name;
- if ((strlen(hp->h_name) > strlen(hostname))
- && (strncmp(hostname, hp->h_name, strlen(hostname)) == 0)
- && (*(p + strlen(hostname)) == '.'))
- strcpy(hostname, hp->h_name);
- }
+ if (error == 0) {/* host is known to name service */
+ getnameinfo(res->ai_addr,
+ res->ai_addrlen,
+ hostname,
+ NI_MAXHOST,
+ NULL,
+ 0,
+ NI_NAMEREQD);
+
+ /* if getnameinfo fails hostname is still the value
+ from gethostname */
+
+ freeaddrinfo(res);
}
}
return (*env)->NewStringUTF(env, hostname);
@@ -140,14 +117,9 @@
jstring host) {
const char *hostname;
jobjectArray ret = 0;
- struct hostent res, *hp = 0;
- // this buffer must be pointer-aligned so is declared
- // with pointer type
- char *buf[HENT_BUF_SIZE/(sizeof (char *))];
-
- /* temporary buffer, on the off chance we need to expand */
- char *tmp = NULL;
- int h_error=0;
+ int retLen = 0;
+ int error = 0;
+ struct addrinfo hints, *res, *resNew = NULL;
if (!initialized) {
ni_iacls = (*env)->FindClass(env, "java/net/InetAddress");
@@ -168,6 +140,11 @@
hostname = JNU_GetStringPlatformChars(env, host, JNI_FALSE);
CHECK_NULL_RETURN(hostname, NULL);
+ /* Try once, with our static buffer. */
+ memset(&hints, 0, sizeof(hints));
+ hints.ai_flags = AI_CANONNAME;
+ hints.ai_family = AF_INET;
+
#ifdef __solaris__
/*
* Workaround for Solaris bug 4160367 - if a hostname contains a
@@ -181,69 +158,93 @@
}
#endif
- /* Try once, with our static buffer. */
-#ifdef __GLIBC__
- gethostbyname_r(hostname, &res, (char*)buf, sizeof(buf), &hp, &h_error);
-#else
- hp = gethostbyname_r(hostname, &res, (char*)buf, sizeof(buf), &h_error);
-#endif
+ error = getaddrinfo(hostname, NULL, &hints, &res);
+
+ if (error) {
+ /* report error */
+ ThrowUnknownHostExceptionWithGaiError(env, hostname, error);
+ JNU_ReleaseStringPlatformChars(env, host, hostname);
+ return NULL;
+ } else {
+ int i = 0;
+ struct addrinfo *itr, *last = NULL, *iterator = res;
- /* With the re-entrant system calls, it's possible that the buffer
- * we pass to it is not large enough to hold an exceptionally
- * large DNS entry. This is signaled by errno->ERANGE. We try once
- * more, with a very big size.
- */
- if (hp == NULL && errno == ERANGE) {
- if ((tmp = (char*)malloc(BIG_HENT_BUF_SIZE))) {
-#ifdef __GLIBC__
- gethostbyname_r(hostname, &res, tmp, BIG_HENT_BUF_SIZE,
- &hp, &h_error);
-#else
- hp = gethostbyname_r(hostname, &res, tmp, BIG_HENT_BUF_SIZE,
- &h_error);
-#endif
- }
- }
- if (hp != NULL) {
- struct in_addr **addrp = (struct in_addr **) hp->h_addr_list;
- int i = 0;
+ while (iterator != NULL) {
+ // remove the duplicate one
+ int skip = 0;
+ itr = resNew;
+ while (itr != NULL) {
+ struct sockaddr_in *addr1, *addr2;
+ addr1 = (struct sockaddr_in *)iterator->ai_addr;
+ addr2 = (struct sockaddr_in *)itr->ai_addr;
+ if (addr1->sin_addr.s_addr ==
+ addr2->sin_addr.s_addr) {
+ skip = 1;
+ break;
+ }
+ itr = itr->ai_next;
+ }
- while (*addrp != (struct in_addr *) 0) {
- i++;
- addrp++;
+ if (!skip) {
+ struct addrinfo *next
+ = (struct addrinfo*) malloc(sizeof(struct addrinfo));
+ if (!next) {
+ JNU_ThrowOutOfMemoryError(env, "heap allocation failed");
+ ret = NULL;
+ goto cleanupAndReturn;
+ }
+ memcpy(next, iterator, sizeof(struct addrinfo));
+ next->ai_next = NULL;
+ if (resNew == NULL) {
+ resNew = next;
+ } else {
+ last->ai_next = next;
+ }
+ last = next;
+ i++;
+ }
+ iterator = iterator->ai_next;
}
- ret = (*env)->NewObjectArray(env, i, ni_iacls, NULL);
+ retLen = i;
+ iterator = resNew;
+
+ ret = (*env)->NewObjectArray(env, retLen, ni_iacls, NULL);
+
if (IS_NULL(ret)) {
/* we may have memory to free at the end of this */
goto cleanupAndReturn;
}
- addrp = (struct in_addr **) hp->h_addr_list;
+
i = 0;
- while (*addrp) {
- jobject iaObj = (*env)->NewObject(env, ni_ia4cls, ni_ia4ctrID);
- if (IS_NULL(iaObj)) {
- ret = NULL;
- goto cleanupAndReturn;
- }
- (*env)->SetIntField(env, iaObj, ni_iaaddressID,
- ntohl((*addrp)->s_addr));
- (*env)->SetObjectField(env, iaObj, ni_iahostID, host);
- (*env)->SetObjectArrayElement(env, ret, i, iaObj);
- addrp++;
- i++;
+ while (iterator != NULL) {
+ jobject iaObj = (*env)->NewObject(env, ni_ia4cls, ni_ia4ctrID);
+ if (IS_NULL(iaObj)) {
+ ret = NULL;
+ goto cleanupAndReturn;
+ }
+ (*env)->SetIntField(env, iaObj, ni_iaaddressID,
+ ntohl(((struct sockaddr_in*)iterator->ai_addr)->sin_addr.s_addr));
+ (*env)->SetObjectField(env, iaObj, ni_iahostID, host);
+ (*env)->SetObjectArrayElement(env, ret, i++, iaObj);
+ iterator = iterator->ai_next;
}
- } else {
- JNU_ThrowByName(env, JNU_JAVANETPKG "UnknownHostException",
- (char *)hostname);
- ret = NULL;
}
-cleanupAndReturn:
- JNU_ReleaseStringPlatformChars(env, host, hostname);
- if (tmp != NULL) {
- free(tmp);
+ cleanupAndReturn:
+ {
+ struct addrinfo *iterator, *tmp;
+ iterator = resNew;
+ while (iterator != NULL) {
+ tmp = iterator;
+ iterator = iterator->ai_next;
+ free(tmp);
+ }
+ JNU_ReleaseStringPlatformChars(env, host, hostname);
}
+
+ freeaddrinfo(res);
+
return ret;
}
@@ -256,63 +257,38 @@
Java_java_net_Inet4AddressImpl_getHostByAddr(JNIEnv *env, jobject this,
jbyteArray addrArray) {
jstring ret = NULL;
- jint addr;
- struct hostent hent, *hp = 0;
- // this buffer must be pointer-aligned so is declared
- // with pointer type
- char *buf[HENT_BUF_SIZE/(sizeof (char *))];
- int h_error = 0;
- char *tmp = NULL;
- /*
- * We are careful here to use the reentrant version of
- * gethostbyname because at the Java level this routine is not
- * protected by any synchronization.
- *
- * Still keeping the reentrant platform dependent calls temporarily
- * We should probably conform to one interface later.
- *
- */
+ char host[NI_MAXHOST+1];
+ int error = 0;
+ int len = 0;
jbyte caddr[4];
+
+ struct sockaddr_in him4;
+ struct sockaddr *sa;
+
+ jint addr;
(*env)->GetByteArrayRegion(env, addrArray, 0, 4, caddr);
addr = ((caddr[0]<<24) & 0xff000000);
addr |= ((caddr[1] <<16) & 0xff0000);
addr |= ((caddr[2] <<8) & 0xff00);
addr |= (caddr[3] & 0xff);
- addr = htonl(addr);
-#ifdef __GLIBC__
- gethostbyaddr_r((char *)&addr, sizeof(addr), AF_INET, &hent,
- (char*)buf, sizeof(buf), &hp, &h_error);
-#else
- hp = gethostbyaddr_r((char *)&addr, sizeof(addr), AF_INET, &hent,
- (char*)buf, sizeof(buf), &h_error);
-#endif
- /* With the re-entrant system calls, it's possible that the buffer
- * we pass to it is not large enough to hold an exceptionally
- * large DNS entry. This is signaled by errno->ERANGE. We try once
- * more, with a very big size.
- */
- if (hp == NULL && errno == ERANGE) {
- if ((tmp = (char*)malloc(BIG_HENT_BUF_SIZE))) {
-#ifdef __GLIBC__
- gethostbyaddr_r((char *)&addr, sizeof(addr), AF_INET,
- &hent, tmp, BIG_HENT_BUF_SIZE, &hp, &h_error);
-#else
- hp = gethostbyaddr_r((char *)&addr, sizeof(addr), AF_INET,
- &hent, tmp, BIG_HENT_BUF_SIZE, &h_error);
-#endif
- } else {
- JNU_ThrowOutOfMemoryError(env, "getHostByAddr");
- }
+ memset((void *) &him4, 0, sizeof(him4));
+ him4.sin_addr.s_addr = (uint32_t) htonl(addr);
+ him4.sin_family = AF_INET;
+ sa = (struct sockaddr *) &him4;
+ len = sizeof(him4);
+
+ error = getnameinfo(sa, len, host, NI_MAXHOST, NULL, 0,
+ NI_NAMEREQD);
+
+ if (!error) {
+ ret = (*env)->NewStringUTF(env, host);
}
- if (hp == NULL) {
+
+ if (ret == NULL) {
JNU_ThrowByName(env, JNU_JAVANETPKG "UnknownHostException", NULL);
- } else {
- ret = (*env)->NewStringUTF(env, hp->h_name);
}
- if (tmp) {
- free(tmp);
- }
+
return ret;
}
--- a/jdk/src/solaris/native/java/net/Inet6AddressImpl.c Thu Nov 17 10:46:00 2011 -0800
+++ b/jdk/src/solaris/native/java/net/Inet6AddressImpl.c Wed Jul 05 17:56:12 2017 +0200
@@ -82,31 +82,29 @@
* We use thread-safe system calls.
*/
#ifdef AF_INET6
- if (NET_addrtransAvailable()) {
- struct addrinfo hints, *res;
- int error;
+ struct addrinfo hints, *res;
+ int error;
- bzero(&hints, sizeof(hints));
- hints.ai_flags = AI_CANONNAME;
- hints.ai_family = AF_UNSPEC;
+ memset(&hints, 0, sizeof(hints));
+ hints.ai_flags = AI_CANONNAME;
+ hints.ai_family = AF_UNSPEC;
- error = (*getaddrinfo_ptr)(hostname, NULL, &hints, &res);
+ error = getaddrinfo(hostname, NULL, &hints, &res);
- if (error == 0) {
- /* host is known to name service */
- error = (*getnameinfo_ptr)(res->ai_addr,
- res->ai_addrlen,
- hostname,
- NI_MAXHOST,
- NULL,
- 0,
- NI_NAMEREQD);
+ if (error == 0) {
+ /* host is known to name service */
+ error = getnameinfo(res->ai_addr,
+ res->ai_addrlen,
+ hostname,
+ NI_MAXHOST,
+ NULL,
+ 0,
+ NI_NAMEREQD);
- /* if getnameinfo fails hostname is still the value
- from gethostname */
+ /* if getnameinfo fails hostname is still the value
+ from gethostname */
- (*freeaddrinfo_ptr)(res);
- }
+ freeaddrinfo(res);
}
#endif /* AF_INET6 */
#endif /* __linux__ */
@@ -173,193 +171,191 @@
CHECK_NULL_RETURN(hostname, NULL);
#ifdef AF_INET6
- if (NET_addrtransAvailable()) {
- static jfieldID ia_preferIPv6AddressID;
- if (ia_preferIPv6AddressID == NULL) {
- jclass c = (*env)->FindClass(env,"java/net/InetAddress");
- if (c) {
- ia_preferIPv6AddressID =
- (*env)->GetStaticFieldID(env, c, "preferIPv6Address", "Z");
- }
- if (ia_preferIPv6AddressID == NULL) {
- JNU_ReleaseStringPlatformChars(env, host, hostname);
- return NULL;
- }
+ static jfieldID ia_preferIPv6AddressID;
+ if (ia_preferIPv6AddressID == NULL) {
+ jclass c = (*env)->FindClass(env,"java/net/InetAddress");
+ if (c) {
+ ia_preferIPv6AddressID =
+ (*env)->GetStaticFieldID(env, c, "preferIPv6Address", "Z");
}
- /* get the address preference */
- preferIPv6Address
- = (*env)->GetStaticBooleanField(env, ia_class, ia_preferIPv6AddressID);
-
- /* Try once, with our static buffer. */
- bzero(&hints, sizeof(hints));
- hints.ai_flags = AI_CANONNAME;
- hints.ai_family = AF_UNSPEC;
-
-#ifdef __solaris__
- /*
- * Workaround for Solaris bug 4160367 - if a hostname contains a
- * white space then 0.0.0.0 is returned
- */
- if (isspace((unsigned char)hostname[0])) {
- JNU_ThrowByName(env, JNU_JAVANETPKG "UnknownHostException",
- hostname);
+ if (ia_preferIPv6AddressID == NULL) {
JNU_ReleaseStringPlatformChars(env, host, hostname);
return NULL;
}
+ }
+ /* get the address preference */
+ preferIPv6Address
+ = (*env)->GetStaticBooleanField(env, ia_class, ia_preferIPv6AddressID);
+
+ /* Try once, with our static buffer. */
+ memset(&hints, 0, sizeof(hints));
+ hints.ai_flags = AI_CANONNAME;
+ hints.ai_family = AF_UNSPEC;
+
+#ifdef __solaris__
+ /*
+ * Workaround for Solaris bug 4160367 - if a hostname contains a
+ * white space then 0.0.0.0 is returned
+ */
+ if (isspace((unsigned char)hostname[0])) {
+ JNU_ThrowByName(env, JNU_JAVANETPKG "UnknownHostException",
+ hostname);
+ JNU_ReleaseStringPlatformChars(env, host, hostname);
+ return NULL;
+ }
#endif
- error = (*getaddrinfo_ptr)(hostname, NULL, &hints, &res);
+ error = getaddrinfo(hostname, NULL, &hints, &res);
- if (error) {
- /* report error */
- ThrowUnknownHostExceptionWithGaiError(env, hostname, error);
- JNU_ReleaseStringPlatformChars(env, host, hostname);
- return NULL;
- } else {
- int i = 0;
- int inetCount = 0, inet6Count = 0, inetIndex, inet6Index;
- struct addrinfo *itr, *last = NULL, *iterator = res;
- while (iterator != NULL) {
- int skip = 0;
- itr = resNew;
- while (itr != NULL) {
- if (iterator->ai_family == itr->ai_family &&
- iterator->ai_addrlen == itr->ai_addrlen) {
- if (itr->ai_family == AF_INET) { /* AF_INET */
- struct sockaddr_in *addr1, *addr2;
- addr1 = (struct sockaddr_in *)iterator->ai_addr;
- addr2 = (struct sockaddr_in *)itr->ai_addr;
- if (addr1->sin_addr.s_addr ==
- addr2->sin_addr.s_addr) {
- skip = 1;
- break;
- }
- } else {
- int t;
- struct sockaddr_in6 *addr1, *addr2;
- addr1 = (struct sockaddr_in6 *)iterator->ai_addr;
- addr2 = (struct sockaddr_in6 *)itr->ai_addr;
+ if (error) {
+ /* report error */
+ ThrowUnknownHostExceptionWithGaiError(env, hostname, error);
+ JNU_ReleaseStringPlatformChars(env, host, hostname);
+ return NULL;
+ } else {
+ int i = 0;
+ int inetCount = 0, inet6Count = 0, inetIndex, inet6Index;
+ struct addrinfo *itr, *last = NULL, *iterator = res;
+ while (iterator != NULL) {
+ int skip = 0;
+ itr = resNew;
+ while (itr != NULL) {
+ if (iterator->ai_family == itr->ai_family &&
+ iterator->ai_addrlen == itr->ai_addrlen) {
+ if (itr->ai_family == AF_INET) { /* AF_INET */
+ struct sockaddr_in *addr1, *addr2;
+ addr1 = (struct sockaddr_in *)iterator->ai_addr;
+ addr2 = (struct sockaddr_in *)itr->ai_addr;
+ if (addr1->sin_addr.s_addr ==
+ addr2->sin_addr.s_addr) {
+ skip = 1;
+ break;
+ }
+ } else {
+ int t;
+ struct sockaddr_in6 *addr1, *addr2;
+ addr1 = (struct sockaddr_in6 *)iterator->ai_addr;
+ addr2 = (struct sockaddr_in6 *)itr->ai_addr;
- for (t = 0; t < 16; t++) {
- if (addr1->sin6_addr.s6_addr[t] !=
- addr2->sin6_addr.s6_addr[t]) {
- break;
- }
- }
- if (t < 16) {
- itr = itr->ai_next;
- continue;
- } else {
- skip = 1;
+ for (t = 0; t < 16; t++) {
+ if (addr1->sin6_addr.s6_addr[t] !=
+ addr2->sin6_addr.s6_addr[t]) {
break;
}
}
- } else if (iterator->ai_family != AF_INET &&
- iterator->ai_family != AF_INET6) {
- /* we can't handle other family types */
- skip = 1;
- break;
- }
- itr = itr->ai_next;
- }
-
- if (!skip) {
- struct addrinfo *next
- = (struct addrinfo*) malloc(sizeof(struct addrinfo));
- if (!next) {
- JNU_ThrowOutOfMemoryError(env, "heap allocation failed");
- ret = NULL;
- goto cleanupAndReturn;
+ if (t < 16) {
+ itr = itr->ai_next;
+ continue;
+ } else {
+ skip = 1;
+ break;
+ }
}
- memcpy(next, iterator, sizeof(struct addrinfo));
- next->ai_next = NULL;
- if (resNew == NULL) {
- resNew = next;
- } else {
- last->ai_next = next;
- }
- last = next;
- i++;
- if (iterator->ai_family == AF_INET) {
- inetCount ++;
- } else if (iterator->ai_family == AF_INET6) {
- inet6Count ++;
- }
+ } else if (iterator->ai_family != AF_INET &&
+ iterator->ai_family != AF_INET6) {
+ /* we can't handle other family types */
+ skip = 1;
+ break;
}
- iterator = iterator->ai_next;
- }
- retLen = i;
- iterator = resNew;
-
- ret = (*env)->NewObjectArray(env, retLen, ni_iacls, NULL);
-
- if (IS_NULL(ret)) {
- /* we may have memory to free at the end of this */
- goto cleanupAndReturn;
+ itr = itr->ai_next;
}
- if (preferIPv6Address) {
- /* AF_INET addresses will be offset by inet6Count */
- inetIndex = inet6Count;
- inet6Index = 0;
- } else {
- /* AF_INET6 addresses will be offset by inetCount */
- inetIndex = 0;
- inet6Index = inetCount;
+ if (!skip) {
+ struct addrinfo *next
+ = (struct addrinfo*) malloc(sizeof(struct addrinfo));
+ if (!next) {
+ JNU_ThrowOutOfMemoryError(env, "heap allocation failed");
+ ret = NULL;
+ goto cleanupAndReturn;
+ }
+ memcpy(next, iterator, sizeof(struct addrinfo));
+ next->ai_next = NULL;
+ if (resNew == NULL) {
+ resNew = next;
+ } else {
+ last->ai_next = next;
+ }
+ last = next;
+ i++;
+ if (iterator->ai_family == AF_INET) {
+ inetCount ++;
+ } else if (iterator->ai_family == AF_INET6) {
+ inet6Count ++;
+ }
}
+ iterator = iterator->ai_next;
+ }
+ retLen = i;
+ iterator = resNew;
- while (iterator != NULL) {
- if (iterator->ai_family == AF_INET) {
+ ret = (*env)->NewObjectArray(env, retLen, ni_iacls, NULL);
+
+ if (IS_NULL(ret)) {
+ /* we may have memory to free at the end of this */
+ goto cleanupAndReturn;
+ }
+
+ if (preferIPv6Address) {
+ /* AF_INET addresses will be offset by inet6Count */
+ inetIndex = inet6Count;
+ inet6Index = 0;
+ } else {
+ /* AF_INET6 addresses will be offset by inetCount */
+ inetIndex = 0;
+ inet6Index = inetCount;
+ }
+
+ while (iterator != NULL) {
+ if (iterator->ai_family == AF_INET) {
jobject iaObj = (*env)->NewObject(env, ni_ia4cls, ni_ia4ctrID);
if (IS_NULL(iaObj)) {
- ret = NULL;
- goto cleanupAndReturn;
+ ret = NULL;
+ goto cleanupAndReturn;
}
(*env)->SetIntField(env, iaObj, ni_iaaddressID,
ntohl(((struct sockaddr_in*)iterator->ai_addr)->sin_addr.s_addr));
(*env)->SetObjectField(env, iaObj, ni_iahostID, host);
(*env)->SetObjectArrayElement(env, ret, inetIndex, iaObj);
inetIndex++;
- } else if (iterator->ai_family == AF_INET6) {
+ } else if (iterator->ai_family == AF_INET6) {
jint scope = 0;
jbyteArray ipaddress;
jobject iaObj = (*env)->NewObject(env, ni_ia6cls, ni_ia6ctrID);
if (IS_NULL(iaObj)) {
- ret = NULL;
- goto cleanupAndReturn;
+ ret = NULL;
+ goto cleanupAndReturn;
}
ipaddress = (*env)->NewByteArray(env, 16);
if (IS_NULL(ipaddress)) {
- ret = NULL;
- goto cleanupAndReturn;
+ ret = NULL;
+ goto cleanupAndReturn;
}
(*env)->SetByteArrayRegion(env, ipaddress, 0, 16,
(jbyte *)&(((struct sockaddr_in6*)iterator->ai_addr)->sin6_addr));
#ifdef __linux__
if (!kernelIsV22()) {
- scope = ((struct sockaddr_in6*)iterator->ai_addr)->sin6_scope_id;
+ scope = ((struct sockaddr_in6*)iterator->ai_addr)->sin6_scope_id;
}
#else
scope = ((struct sockaddr_in6*)iterator->ai_addr)->sin6_scope_id;
#endif
if (scope != 0) { /* zero is default value, no need to set */
- (*env)->SetIntField(env, iaObj, ia6_scopeidID, scope);
- (*env)->SetBooleanField(env, iaObj, ia6_scopeidsetID, JNI_TRUE);
+ (*env)->SetIntField(env, iaObj, ia6_scopeidID, scope);
+ (*env)->SetBooleanField(env, iaObj, ia6_scopeidsetID, JNI_TRUE);
}
(*env)->SetObjectField(env, iaObj, ni_ia6ipaddressID, ipaddress);
(*env)->SetObjectField(env, iaObj, ni_iahostID, host);
(*env)->SetObjectArrayElement(env, ret, inet6Index, iaObj);
inet6Index++;
- }
- iterator = iterator->ai_next;
}
+ iterator = iterator->ai_next;
}
}
-cleanupAndReturn:
+ cleanupAndReturn:
{
- struct addrinfo *iterator, *tmp;
+ struct addrinfo *iterator, *tmp;
iterator = resNew;
while (iterator != NULL) {
tmp = iterator;
@@ -369,8 +365,7 @@
JNU_ReleaseStringPlatformChars(env, host, hostname);
}
- if (NET_addrtransAvailable())
- (*freeaddrinfo_ptr)(res);
+ freeaddrinfo(res);
#endif /* AF_INET6 */
return ret;
@@ -393,44 +388,42 @@
int len = 0;
jbyte caddr[16];
- if (NET_addrtransAvailable()) {
- struct sockaddr_in him4;
- struct sockaddr_in6 him6;
- struct sockaddr *sa;
+ struct sockaddr_in him4;
+ struct sockaddr_in6 him6;
+ struct sockaddr *sa;
+ /*
+ * For IPv4 addresses construct a sockaddr_in structure.
+ */
+ if ((*env)->GetArrayLength(env, addrArray) == 4) {
+ jint addr;
+ (*env)->GetByteArrayRegion(env, addrArray, 0, 4, caddr);
+ addr = ((caddr[0]<<24) & 0xff000000);
+ addr |= ((caddr[1] <<16) & 0xff0000);
+ addr |= ((caddr[2] <<8) & 0xff00);
+ addr |= (caddr[3] & 0xff);
+ memset((void *) &him4, 0, sizeof(him4));
+ him4.sin_addr.s_addr = (uint32_t) htonl(addr);
+ him4.sin_family = AF_INET;
+ sa = (struct sockaddr *) &him4;
+ len = sizeof(him4);
+ } else {
/*
- * For IPv4 addresses construct a sockaddr_in structure.
+ * For IPv6 address construct a sockaddr_in6 structure.
*/
- if ((*env)->GetArrayLength(env, addrArray) == 4) {
- jint addr;
- (*env)->GetByteArrayRegion(env, addrArray, 0, 4, caddr);
- addr = ((caddr[0]<<24) & 0xff000000);
- addr |= ((caddr[1] <<16) & 0xff0000);
- addr |= ((caddr[2] <<8) & 0xff00);
- addr |= (caddr[3] & 0xff);
- memset((void *) &him4, 0, sizeof(him4));
- him4.sin_addr.s_addr = (uint32_t) htonl(addr);
- him4.sin_family = AF_INET;
- sa = (struct sockaddr *) &him4;
- len = sizeof(him4);
- } else {
- /*
- * For IPv6 address construct a sockaddr_in6 structure.
- */
- (*env)->GetByteArrayRegion(env, addrArray, 0, 16, caddr);
- memset((void *) &him6, 0, sizeof(him6));
- memcpy((void *)&(him6.sin6_addr), caddr, sizeof(struct in6_addr) );
- him6.sin6_family = AF_INET6;
- sa = (struct sockaddr *) &him6 ;
- len = sizeof(him6) ;
- }
+ (*env)->GetByteArrayRegion(env, addrArray, 0, 16, caddr);
+ memset((void *) &him6, 0, sizeof(him6));
+ memcpy((void *)&(him6.sin6_addr), caddr, sizeof(struct in6_addr) );
+ him6.sin6_family = AF_INET6;
+ sa = (struct sockaddr *) &him6 ;
+ len = sizeof(him6) ;
+ }
- error = (*getnameinfo_ptr)(sa, len, host, NI_MAXHOST, NULL, 0,
- NI_NAMEREQD);
+ error = getnameinfo(sa, len, host, NI_MAXHOST, NULL, 0,
+ NI_NAMEREQD);
- if (!error) {
- ret = (*env)->NewStringUTF(env, host);
- }
+ if (!error) {
+ ret = (*env)->NewStringUTF(env, host);
}
#endif /* AF_INET6 */
--- a/jdk/src/solaris/native/java/net/net_util_md.c Thu Nov 17 10:46:00 2011 -0800
+++ b/jdk/src/solaris/native/java/net/net_util_md.c Wed Jul 05 17:56:12 2017 +0200
@@ -377,37 +377,12 @@
* we should also check if the APIs are available.
*/
ipv6_fn = JVM_FindLibraryEntry(RTLD_DEFAULT, "inet_pton");
+ close(fd);
if (ipv6_fn == NULL ) {
- close(fd);
return JNI_FALSE;
+ } else {
+ return JNI_TRUE;
}
-
- /*
- * We've got the library, let's get the pointers to some
- * IPV6 specific functions. We have to do that because, at least
- * on Solaris we may build on a system without IPV6 networking
- * libraries, therefore we can't have a hard link to these
- * functions.
- */
- getaddrinfo_ptr = (getaddrinfo_f)
- JVM_FindLibraryEntry(RTLD_DEFAULT, "getaddrinfo");
-
- freeaddrinfo_ptr = (freeaddrinfo_f)
- JVM_FindLibraryEntry(RTLD_DEFAULT, "freeaddrinfo");
-
- gai_strerror_ptr = (gai_strerror_f)
- JVM_FindLibraryEntry(RTLD_DEFAULT, "gai_strerror");
-
- getnameinfo_ptr = (getnameinfo_f)
- JVM_FindLibraryEntry(RTLD_DEFAULT, "getnameinfo");
-
- if (freeaddrinfo_ptr == NULL || getnameinfo_ptr == NULL) {
- /* We need all 3 of them */
- getaddrinfo_ptr = NULL;
- }
-
- close(fd);
- return JNI_TRUE;
#endif /* AF_INET6 */
}
@@ -920,10 +895,6 @@
return 1;
}
-jboolean NET_addrtransAvailable() {
- return (jboolean)(getaddrinfo_ptr != NULL);
-}
-
/*
* Map the Java level socket option to the platform specific
* level and option name.
--- a/jdk/src/solaris/native/java/net/net_util_md.h Thu Nov 17 10:46:00 2011 -0800
+++ b/jdk/src/solaris/native/java/net/net_util_md.h Wed Jul 05 17:56:12 2017 +0200
@@ -102,10 +102,6 @@
const char* hostname,
int gai_error);
-/* do we have address translation support */
-
-extern jboolean NET_addrtransAvailable();
-
#define NET_WAIT_READ 0x01
#define NET_WAIT_WRITE 0x02
#define NET_WAIT_CONNECT 0x04
--- a/jdk/src/windows/classes/java/io/FileDescriptor.java Thu Nov 17 10:46:00 2011 -0800
+++ b/jdk/src/windows/classes/java/io/FileDescriptor.java Wed Jul 05 17:56:12 2017 +0200
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2003, 2008, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 2011, 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,8 @@
package java.io;
-import java.util.concurrent.atomic.AtomicInteger;
+import java.util.ArrayList;
+import java.util.List;
/**
* Instances of the file descriptor class serve as an opaque handle
@@ -45,13 +46,9 @@
private long handle;
- /**
- * A use counter for tracking the FIS/FOS/RAF instances that
- * use this FileDescriptor. The FIS/FOS.finalize() will not release
- * the FileDescriptor if it is still under use by any stream.
- */
- private AtomicInteger useCount;
-
+ private Closeable parent;
+ private List<Closeable> otherParents;
+ private boolean closed;
/**
* Constructs an (invalid) FileDescriptor
@@ -60,7 +57,6 @@
public /**/ FileDescriptor() {
fd = -1;
handle = -1;
- useCount = new AtomicInteger();
}
static {
@@ -168,13 +164,67 @@
return desc;
}
- // package private methods used by FIS, FOS and RAF.
+ /*
+ * Package private methods to track referents.
+ * If multiple streams point to the same FileDescriptor, we cycle
+ * through the list of all referents and call close()
+ */
- int incrementAndGetUseCount() {
- return useCount.incrementAndGet();
+ /**
+ * Attach a Closeable to this FD for tracking.
+ * parent reference is added to otherParents when
+ * needed to make closeAll simpler.
+ */
+ synchronized void attach(Closeable c) {
+ if (parent == null) {
+ // first caller gets to do this
+ parent = c;
+ } else if (otherParents == null) {
+ otherParents = new ArrayList<>();
+ otherParents.add(parent);
+ otherParents.add(c);
+ } else {
+ otherParents.add(c);
+ }
}
- int decrementAndGetUseCount() {
- return useCount.decrementAndGet();
+ /**
+ * Cycle through all Closeables sharing this FD and call
+ * close() on each one.
+ *
+ * The caller closeable gets to call close0().
+ */
+ @SuppressWarnings("try")
+ synchronized void closeAll(Closeable releaser) throws IOException {
+ if (!closed) {
+ closed = true;
+ IOException ioe = null;
+ try (Closeable c = releaser) {
+ if (otherParents != null) {
+ for (Closeable referent : otherParents) {
+ try {
+ referent.close();
+ } catch(IOException x) {
+ if (ioe == null) {
+ ioe = x;
+ } else {
+ ioe.addSuppressed(x);
+ }
+ }
+ }
+ }
+ } catch(IOException ex) {
+ /*
+ * If releaser close() throws IOException
+ * add other exceptions as suppressed.
+ */
+ if (ioe != null)
+ ex.addSuppressed(ioe);
+ ioe = ex;
+ } finally {
+ if (ioe != null)
+ throw ioe;
+ }
+ }
}
}
--- a/jdk/src/windows/classes/java/net/PlainSocketImpl.java Thu Nov 17 10:46:00 2011 -0800
+++ b/jdk/src/windows/classes/java/net/PlainSocketImpl.java Wed Jul 05 17:56:12 2017 +0200
@@ -314,7 +314,7 @@
void socketSetOption(int cmd, boolean on, Object value)
throws SocketException {
- socketSetOption(cmd, on, value);
+ impl.socketSetOption(cmd, on, value);
}
int socketGetOption(int opt, Object iaContainerObj) throws SocketException {
--- a/jdk/src/windows/classes/sun/security/krb5/internal/tools/Klist.java Thu Nov 17 10:46:00 2011 -0800
+++ b/jdk/src/windows/classes/sun/security/krb5/internal/tools/Klist.java Wed Jul 05 17:56:12 2017 +0200
@@ -207,7 +207,7 @@
}
if (options[2] == 't') {
System.out.println("\t Time stamp: " +
- reformat(entries[i].getTimeStamp().toDate().toString()));
+ format(entries[i].getTimeStamp()));
}
}
}
@@ -234,30 +234,39 @@
System.out.println("\nDefault principal: " +
defaultPrincipal + ", " +
creds.length + " entries found.\n");
- String starttime = null;
- String endtime = null;
- String servicePrincipal = null;
- String etype = null;
if (creds != null) {
for (int i = 0; i < creds.length; i++) {
try {
- starttime =
- reformat(creds[i].getAuthTime().toDate().toString());
- endtime =
- reformat(creds[i].getEndTime().toDate().toString());
+ String starttime;
+ String endtime;
+ String renewTill;
+ String servicePrincipal;
+ if (creds[i].getStartTime() != null) {
+ starttime = format(creds[i].getStartTime());
+ } else {
+ starttime = format(creds[i].getAuthTime());
+ }
+ endtime = format(creds[i].getEndTime());
servicePrincipal =
creds[i].getServicePrincipal().toString();
System.out.println("[" + (i + 1) + "] " +
" Service Principal: " +
servicePrincipal);
- System.out.println(" Valid starting: " + starttime);
- System.out.println(" Expires: " + endtime);
+ System.out.println(" Valid starting: " + starttime);
+ System.out.println(" Expires: " + endtime);
+ if (creds[i].getRenewTill() != null) {
+ renewTill = format(creds[i].getRenewTill());
+ System.out.println(
+ " Renew until: " + renewTill);
+ }
if (options[0] == 'e') {
- etype = EType.toString(creds[i].getEType());
- System.out.println(" Encryption type: " + etype);
+ String eskey = EType.toString(creds[i].getEType());
+ String etkt = EType.toString(creds[i].getTktEType());
+ System.out.println(" EType (skey, tkt): "
+ + eskey + ", " + etkt);
}
if (options[1] == 'f') {
- System.out.println(" Flags: " +
+ System.out.println(" Flags: " +
creds[i].getTicketFlags().toString());
}
if (options[2] == 'a') {
@@ -312,13 +321,14 @@
* and yyyy is the year.
* @param date the string form of Date object.
*/
- String reformat(String date) {
+ private String format(KerberosTime kt) {
+ String date = kt.toDate().toString();
return (date.substring(4, 7) + " " + date.substring(8, 10) +
", " + date.substring(24)
- + " " + date.substring(11, 16));
+ + " " + date.substring(11, 19));
}
/**
- * Printes out the help information.
+ * Prints out the help information.
*/
void printHelp() {
System.out.println("\nUsage: klist " +
--- a/jdk/src/windows/lib/tzmappings Thu Nov 17 10:46:00 2011 -0800
+++ b/jdk/src/windows/lib/tzmappings Wed Jul 05 17:56:12 2017 +0200
@@ -167,7 +167,7 @@
Argentina Standard Time:900,900::America/Buenos_Aires:
Azerbaijan Standard Time:901,901:AZ:Asia/Baku:
Bangladesh Standard Time:902,902::Asia/Dhaka:
-Central Brazilian Standard Time:903,903:BR:America/Manaus:
+Central Brazilian Standard Time:903,903:BR:America/Cuiaba:
Central Standard Time (Mexico):904,904::America/Mexico_City:
Georgian Standard Time:905,905:GE:Asia/Tbilisi:
Jordan Standard Time:906,906:JO:Asia/Amman:
@@ -189,5 +189,7 @@
Ulaanbaatar Standard Time:922,922::Asia/Ulaanbaatar:
Venezuela Standard Time:923,923::America/Caracas:
Magadan Standard Time:924,924::Asia/Magadan:
-Western Brazilian Standard Time:925,925:BR:America/Rio_Branco:
-Armenian Standard Time:926,926:AM:Asia/Yerevan:
+Kaliningrad Standard Time:925,925:RU:Europe/Kaliningrad:
+Turkey Standard Time:926,926::Asia/Istanbul:
+Western Brazilian Standard Time:927,927:BR:America/Rio_Branco:
+Armenian Standard Time:928,928:AM:Asia/Yerevan:
--- a/jdk/test/ProblemList.txt Thu Nov 17 10:46:00 2011 -0800
+++ b/jdk/test/ProblemList.txt Wed Jul 05 17:56:12 2017 +0200
@@ -195,9 +195,6 @@
# jdk_lang
-# requires junit
-java/lang/invoke/InvokeDynamicPrintArgs.java generic-all
-
# 7079093
java/lang/instrument/ManifestTest.sh windows-all
--- a/jdk/test/java/io/FileDescriptor/FileChannelFDTest.java Thu Nov 17 10:46:00 2011 -0800
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,92 +0,0 @@
-/*
- * Copyright (c) 2006, 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 6322678
- * @summary Test for making sure that fd is closed during
- * finalization of a stream, when an associated
- * file channel is not available
- */
-
-import java.io.*;
-import java.nio.*;
-import java.nio.channels.*;
-
-public class FileChannelFDTest {
-
- static byte data[] = new byte[] {48, 49, 50, 51, 52, 53, 54, 55, 56, 57,};
- static String inFileName = "fd-in-test.txt";
- static String outFileName = "fd-out-test.txt";
- static File inFile;
- static File outFile;
-
- private static void writeToInFile() throws IOException {
- FileOutputStream out = new FileOutputStream(inFile);
- out.write(data);
- out.close();
- }
-
- public static void main(String[] args)
- throws Exception {
-
- inFile= new File(System.getProperty("test.dir", "."),
- inFileName);
- inFile.createNewFile();
- inFile.deleteOnExit();
- writeToInFile();
-
- outFile = new File(System.getProperty("test.dir", "."),
- outFileName);
- outFile.createNewFile();
- outFile.deleteOnExit();
-
- doFileChannel();
- }
-
- private static void doFileChannel() throws Exception {
-
- FileInputStream fis = new FileInputStream(inFile);
- FileDescriptor fd = fis.getFD();
- FileChannel fc = fis.getChannel();
- System.out.println("Created fis:" + fis);
-
- /**
- * Encourage the GC
- */
- fis = null;
- fc = null;
- System.gc();
- Thread.sleep(500);
-
- if (fd.valid()) {
- throw new Exception("Finalizer either didn't run --" +
- "try increasing the Thread's sleep time after System.gc();" +
- "or the finalizer didn't close the file");
- }
-
- System.out.println("File Closed successfully");
- System.out.println();
- }
-}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/io/FileDescriptor/Sharing.java Wed Jul 05 17:56:12 2017 +0200
@@ -0,0 +1,408 @@
+/*
+ * Copyright (c) 2011, 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 7105952 6322678 7082769
+ * @summary Improve finalisation for FileInputStream/FileOutputStream/RandomAccessFile
+ * @run main/othervm Sharing
+ */
+
+import java.io.*;
+import java.nio.channels.FileChannel;
+import java.nio.channels.FileLock;
+import java.util.concurrent.CountDownLatch;
+
+public class Sharing {
+
+ final static int numFiles = 10;
+ volatile static boolean fail;
+
+ public static void main(String[] args) throws Exception {
+ TestFinalizer();
+ TestMultipleFD();
+ TestIsValid();
+ MultiThreadedFD();
+ TestCloseAll();
+ }
+
+ /**
+ * Finalizer shouldn't discard a file descriptor until all streams have
+ * finished with it.
+ */
+ private static void TestFinalizer() throws Exception {
+ FileDescriptor fd = null;
+ File tempFile = new File("TestFinalizer1.txt");
+ tempFile.deleteOnExit();
+ try (Writer writer = new FileWriter(tempFile)) {
+ for (int i=0; i<5; i++) {
+ writer.write("test file content test file content");
+ }
+ }
+
+ FileInputStream fis1 = new FileInputStream(tempFile);
+ fd = fis1.getFD();
+ // Create a new FIS based on the existing FD (so the two FIS's share the same native fd)
+ try (FileInputStream fis2 = new FileInputStream(fd)) {
+ // allow fis1 to be gc'ed
+ fis1 = null;
+ int ret = 0;
+ while(ret >= 0) {
+ // encourage gc
+ System.gc();
+ // read from fis2 - when fis1 is gc'ed and finalizer is run, read will fail
+ System.out.print(".");
+ ret = fis2.read();
+ }
+ }
+
+ // variation of above. Use RandomAccessFile to obtain a filedescriptor
+ File testFinalizerFile = new File("TestFinalizer");
+ RandomAccessFile raf = new RandomAccessFile(testFinalizerFile, "rw");
+ raf.writeBytes("test file content test file content");
+ raf.seek(0L);
+ fd = raf.getFD();
+ try (FileInputStream fis3 = new FileInputStream(fd)) {
+ // allow raf to be gc'ed
+ raf = null;
+ int ret = 0;
+ while (ret >= 0) {
+ // encourage gc
+ System.gc();
+ /*
+ * read from fis3 - when raf is gc'ed and finalizer is run,
+ * fd should still be valid.
+ */
+ System.out.print(".");
+ ret = fis3.read();
+ }
+ } finally {
+ testFinalizerFile.delete();
+ }
+ }
+
+ /**
+ * Exercise FileDispatcher close()/preClose()
+ */
+ private static void TestMultipleFD() throws Exception {
+ RandomAccessFile raf = null;
+ FileOutputStream fos = null;
+ FileInputStream fis = null;
+ FileChannel fc = null;
+ FileLock fileLock = null;
+
+ File test1 = new File("test1");
+ try {
+ raf = new RandomAccessFile(test1, "rw");
+ fos = new FileOutputStream(raf.getFD());
+ fis = new FileInputStream(raf.getFD());
+ fc = raf.getChannel();
+ fileLock = fc.lock();
+ raf.setLength(0L);
+ fos.flush();
+ fos.write("TEST".getBytes());
+ } finally {
+ if (fileLock != null) fileLock.release();
+ if (fis != null) fis.close();
+ if (fos != null) fos.close();
+ if (raf != null) raf.close();
+ test1.delete();
+ }
+
+ /*
+ * Close out in different order to ensure FD is not
+ * closed out too early
+ */
+ File test2 = new File("test2");
+ try {
+ raf = new RandomAccessFile(test2, "rw");
+ fos = new FileOutputStream(raf.getFD());
+ fis = new FileInputStream(raf.getFD());
+ fc = raf.getChannel();
+ fileLock = fc.lock();
+ raf.setLength(0L);
+ fos.flush();
+ fos.write("TEST".getBytes());
+ } finally {
+ if (fileLock != null) fileLock.release();
+ if (raf != null) raf.close();
+ if (fos != null) fos.close();
+ if (fis != null) fis.close();
+ test2.delete();
+ }
+
+ // one more time, fos first this time
+ File test3 = new File("test3");
+ try {
+ raf = new RandomAccessFile(test3, "rw");
+ fos = new FileOutputStream(raf.getFD());
+ fis = new FileInputStream(raf.getFD());
+ fc = raf.getChannel();
+ fileLock = fc.lock();
+ raf.setLength(0L);
+ fos.flush();
+ fos.write("TEST".getBytes());
+ } finally {
+ if (fileLock != null) fileLock.release();
+ if (fos != null) fos.close();
+ if (raf != null) raf.close();
+ if (fis != null) fis.close();
+ test3.delete();
+ }
+ }
+
+ /**
+ * Similar to TestMultipleFD() but this time we
+ * just get and use FileDescriptor.valid() for testing.
+ */
+ private static void TestIsValid() throws Exception {
+ FileDescriptor fd = null;
+ RandomAccessFile raf = null;
+ FileOutputStream fos = null;
+ FileInputStream fis = null;
+ FileChannel fc = null;
+
+ File test1 = new File("test1");
+ try {
+ raf = new RandomAccessFile(test1, "rw");
+ fd = raf.getFD();
+ fos = new FileOutputStream(fd);
+ fis = new FileInputStream(fd);
+ } finally {
+ try {
+ if (fis != null) fis.close();
+ if (fd.valid()) {
+ throw new RuntimeException("[FIS close()] FileDescriptor shouldn't be valid");
+ }
+ if (fos != null) fos.close();
+ if (raf != null) raf.close();
+ } finally {
+ test1.delete();
+ }
+ }
+
+ /*
+ * Close out in different order to ensure FD is
+ * closed correctly.
+ */
+ File test2 = new File("test2");
+ try {
+ raf = new RandomAccessFile(test2, "rw");
+ fd = raf.getFD();
+ fos = new FileOutputStream(fd);
+ fis = new FileInputStream(fd);
+ } finally {
+ try {
+ if (raf != null) raf.close();
+ if (fd.valid()) {
+ throw new RuntimeException("[RAF close()] FileDescriptor shouldn't be valid");
+ }
+ if (fos != null) fos.close();
+ if (fis != null) fis.close();
+ } finally {
+ test2.delete();
+ }
+ }
+
+ // one more time, fos first this time
+ File test3 = new File("test3");
+ try {
+ raf = new RandomAccessFile(test3, "rw");
+ fd = raf.getFD();
+ fos = new FileOutputStream(fd);
+ fis = new FileInputStream(fd);
+ } finally {
+ try {
+ if (fos != null) fos.close();
+ if (fd.valid()) {
+ throw new RuntimeException("[FOS close()] FileDescriptor shouldn't be valid");
+ }
+ if (raf != null) raf.close();
+ if (fis != null) fis.close();
+ } finally {
+ test3.delete();
+ }
+ }
+ }
+
+ /**
+ * Test concurrent access to the same FileDescriptor
+ */
+ private static void MultiThreadedFD() throws Exception {
+ RandomAccessFile raf = null;
+ FileDescriptor fd = null;
+ int numThreads = 2;
+ CountDownLatch done = new CountDownLatch(numThreads);
+ OpenClose[] fileOpenClose = new OpenClose[numThreads];
+ File MultipleThreadedFD = new File("MultipleThreadedFD");
+ try {
+ raf = new RandomAccessFile(MultipleThreadedFD, "rw");
+ fd = raf.getFD();
+ for(int count=0;count<numThreads;count++) {
+ fileOpenClose[count] = new OpenClose(fd, done);
+ fileOpenClose[count].start();
+ }
+ done.await();
+ } finally {
+ try {
+ if(raf != null) raf.close();
+ // fd should now no longer be valid
+ if(fd.valid()) {
+ throw new RuntimeException("FileDescriptor should not be valid");
+ }
+ // OpenClose thread tests failed
+ if(fail) {
+ throw new RuntimeException("OpenClose thread tests failed.");
+ }
+ } finally {
+ MultipleThreadedFD.delete();
+ }
+ }
+ }
+
+ /**
+ * Test closeAll handling in FileDescriptor
+ */
+ private static void TestCloseAll() throws Exception {
+ File testFile = new File("test");
+ testFile.deleteOnExit();
+ RandomAccessFile raf = new RandomAccessFile(testFile, "rw");
+ FileInputStream fis = new FileInputStream(raf.getFD());
+ fis.close();
+ if (raf.getFD().valid()) {
+ throw new RuntimeException("FD should not be valid.");
+ }
+
+ // Test the suppressed exception handling - FileInputStream
+
+ raf = new RandomAccessFile(testFile, "rw");
+ fis = new FileInputStream(raf.getFD());
+ BadFileInputStream bfis1 = new BadFileInputStream(raf.getFD());
+ BadFileInputStream bfis2 = new BadFileInputStream(raf.getFD());
+ BadFileInputStream bfis3 = new BadFileInputStream(raf.getFD());
+ // extra test - set bfis3 to null
+ bfis3 = null;
+ try {
+ fis.close();
+ } catch (IOException ioe) {
+ ioe.printStackTrace();
+ if (ioe.getSuppressed().length != 2) {
+ throw new RuntimeException("[FIS]Incorrect number of suppressed " +
+ "exceptions received : " + ioe.getSuppressed().length);
+ }
+ }
+ if (raf.getFD().valid()) {
+ // we should still have closed the FD
+ // even with the exception.
+ throw new RuntimeException("[FIS]TestCloseAll : FD still valid.");
+ }
+
+ // Now test with FileOutputStream
+
+ raf = new RandomAccessFile(testFile, "rw");
+ FileOutputStream fos = new FileOutputStream(raf.getFD());
+ BadFileOutputStream bfos1 = new BadFileOutputStream(raf.getFD());
+ BadFileOutputStream bfos2 = new BadFileOutputStream(raf.getFD());
+ BadFileOutputStream bfos3 = new BadFileOutputStream(raf.getFD());
+ // extra test - set bfos3 to null
+ bfos3 = null;
+ try {
+ fos.close();
+ } catch (IOException ioe) {
+ ioe.printStackTrace();
+ if (ioe.getSuppressed().length != 2) {
+ throw new RuntimeException("[FOS]Incorrect number of suppressed " +
+ "exceptions received : " + ioe.getSuppressed().length);
+ }
+ }
+ if (raf.getFD().valid()) {
+ // we should still have closed the FD
+ // even with the exception.
+ throw new RuntimeException("[FOS]TestCloseAll : FD still valid.");
+ }
+ }
+
+ /**
+ * A thread which will open and close a number of FileInputStreams and
+ * FileOutputStreams referencing the same native file descriptor.
+ */
+ private static class OpenClose extends Thread {
+ private FileDescriptor fd = null;
+ private CountDownLatch done;
+ FileInputStream[] fisArray = new FileInputStream[numFiles];
+ FileOutputStream[] fosArray = new FileOutputStream[numFiles];
+
+ OpenClose(FileDescriptor filedescriptor, CountDownLatch done) {
+ this.fd = filedescriptor;
+ this.done = done;
+ }
+
+ public void run() {
+ try {
+ for(int i=0;i<numFiles;i++) {
+ fisArray[i] = new FileInputStream(fd);
+ fosArray[i] = new FileOutputStream(fd);
+ }
+
+ // Now close out
+ for(int i=0;i<numFiles;i++) {
+ if(fisArray[i] != null) fisArray[i].close();
+ if(fosArray[i] != null) fosArray[i].close();
+ }
+
+ } catch(IOException ioe) {
+ System.out.println("OpenClose encountered IO issue :" + ioe);
+ fail = true;
+ } finally {
+ if (fd.valid()) { // fd should not be valid after first close() call
+ System.out.println("OpenClose: FileDescriptor shouldn't be valid");
+ fail = true;
+ }
+ done.countDown();
+ }
+ }
+ }
+
+ private static class BadFileInputStream extends FileInputStream {
+
+ BadFileInputStream(FileDescriptor fd) {
+ super(fd);
+ }
+
+ public void close() throws IOException {
+ throw new IOException("Bad close operation");
+ }
+ }
+
+ private static class BadFileOutputStream extends FileOutputStream {
+
+ BadFileOutputStream(FileDescriptor fd) {
+ super(fd);
+ }
+
+ public void close() throws IOException {
+ throw new IOException("Bad close operation");
+ }
+ }
+
+}
--- a/jdk/test/java/io/etc/FileDescriptorSharing.java Thu Nov 17 10:46:00 2011 -0800
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,336 +0,0 @@
-/*
- * Copyright (c) 2011, 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 6322678 7082769
- * @summary FileInputStream/FileOutputStream/RandomAccessFile allow file descriptor
- * to be closed while still in use.
- * @run main/othervm FileDescriptorSharing
- */
-
-import java.io.*;
-import java.nio.channels.FileChannel;
-import java.nio.channels.FileLock;
-import java.util.concurrent.CountDownLatch;
-
-public class FileDescriptorSharing {
-
- final static int numFiles = 10;
- volatile static boolean fail;
-
- public static void main(String[] args) throws Exception {
- TestFinalizer();
- TestMultipleFD();
- TestIsValid();
- MultiThreadedFD();
- }
-
- /**
- * We shouldn't discard a file descriptor until all streams have
- * finished with it
- */
- private static void TestFinalizer() throws Exception {
- FileDescriptor fd = null;
- File tempFile = new File("TestFinalizer1.txt");
- tempFile.deleteOnExit();
- try (Writer writer = new FileWriter(tempFile)) {
- for (int i=0; i<5; i++) {
- writer.write("test file content test file content");
- }
- }
-
- FileInputStream fis1 = new FileInputStream(tempFile);
- fd = fis1.getFD();
- // Create a new FIS based on the existing FD (so the two FIS's share the same native fd)
- try (FileInputStream fis2 = new FileInputStream(fd)) {
- // allow fis1 to be gc'ed
- fis1 = null;
- int ret = 0;
- while(ret >= 0) {
- // encourage gc
- System.gc();
- // read from fis2 - when fis1 is gc'ed and finalizer is run, read will fail
- System.out.print(".");
- ret = fis2.read();
- }
- }
-
- // variation of above. Use RandomAccessFile to obtain a filedescriptor
- File testFinalizerFile = new File("TestFinalizer");
- RandomAccessFile raf = new RandomAccessFile(testFinalizerFile, "rw");
- raf.writeBytes("test file content test file content");
- raf.seek(0L);
- fd = raf.getFD();
- try (FileInputStream fis3 = new FileInputStream(fd)) {
- // allow raf to be gc'ed
- raf = null;
- int ret = 0;
- while (ret >= 0) {
- // encourage gc
- System.gc();
- /*
- * read from fis3 - when raf is gc'ed and finalizer is run,
- * fd should still be valid.
- */
- System.out.print(".");
- ret = fis3.read();
- }
- if(!fd.valid()) {
- throw new RuntimeException("TestFinalizer() : FileDescriptor should be valid");
- }
- } finally {
- testFinalizerFile.delete();
- }
- }
-
- /**
- * Exercise FileDispatcher close()/preClose()
- */
- private static void TestMultipleFD() throws Exception {
- RandomAccessFile raf = null;
- FileOutputStream fos = null;
- FileInputStream fis = null;
- FileChannel fc = null;
- FileLock fileLock = null;
-
- File test1 = new File("test1");
- try {
- raf = new RandomAccessFile(test1, "rw");
- fos = new FileOutputStream(raf.getFD());
- fis = new FileInputStream(raf.getFD());
- fc = raf.getChannel();
- fileLock = fc.lock();
- raf.setLength(0L);
- fos.flush();
- fos.write("TEST".getBytes());
- } finally {
- if (fileLock != null) fileLock.release();
- if (fis != null) fis.close();
- if (fos != null) fos.close();
- if (raf != null) raf.close();
- test1.delete();
- }
-
- /*
- * Close out in different order to ensure FD is not
- * closed out too early
- */
- File test2 = new File("test2");
- try {
- raf = new RandomAccessFile(test2, "rw");
- fos = new FileOutputStream(raf.getFD());
- fis = new FileInputStream(raf.getFD());
- fc = raf.getChannel();
- fileLock = fc.lock();
- raf.setLength(0L);
- fos.flush();
- fos.write("TEST".getBytes());
- } finally {
- if (fileLock != null) fileLock.release();
- if (raf != null) raf.close();
- if (fos != null) fos.close();
- if (fis != null) fis.close();
- test2.delete();
- }
-
- // one more time, fos first this time
- File test3 = new File("test3");
- try {
- raf = new RandomAccessFile(test3, "rw");
- fos = new FileOutputStream(raf.getFD());
- fis = new FileInputStream(raf.getFD());
- fc = raf.getChannel();
- fileLock = fc.lock();
- raf.setLength(0L);
- fos.flush();
- fos.write("TEST".getBytes());
- } finally {
- if (fileLock != null) fileLock.release();
- if (fos != null) fos.close();
- if (raf != null) raf.close();
- if (fis != null) fis.close();
- test3.delete();
- }
- }
-
- /**
- * Similar to TestMultipleFD() but this time we
- * just get and use FileDescriptor.valid() for testing.
- */
- private static void TestIsValid() throws Exception {
- FileDescriptor fd = null;
- RandomAccessFile raf = null;
- FileOutputStream fos = null;
- FileInputStream fis = null;
- FileChannel fc = null;
-
- File test1 = new File("test1");
- try {
- raf = new RandomAccessFile(test1, "rw");
- fd = raf.getFD();
- fos = new FileOutputStream(fd);
- fis = new FileInputStream(fd);
- } finally {
- try {
- if (fis != null) fis.close();
- if (fos != null) fos.close();
- if (!fd.valid()) {
- throw new RuntimeException("FileDescriptor should be valid");
- }
- if (raf != null) raf.close();
- if (fd.valid()) {
- throw new RuntimeException("close() called and FileDescriptor still valid");
- }
- } finally {
- if (raf != null) raf.close();
- test1.delete();
- }
- }
-
- /*
- * Close out in different order to ensure FD is not
- * closed out too early
- */
- File test2 = new File("test2");
- try {
- raf = new RandomAccessFile(test2, "rw");
- fd = raf.getFD();
- fos = new FileOutputStream(fd);
- fis = new FileInputStream(fd);
- } finally {
- try {
- if (raf != null) raf.close();
- if (fos != null) fos.close();
- if (!fd.valid()) {
- throw new RuntimeException("FileDescriptor should be valid");
- }
- if (fis != null) fis.close();
- if (fd.valid()) {
- throw new RuntimeException("close() called and FileDescriptor still valid");
- }
- } finally {
- test2.delete();
- }
- }
-
- // one more time, fos first this time
- File test3 = new File("test3");
- try {
- raf = new RandomAccessFile(test3, "rw");
- fd = raf.getFD();
- fos = new FileOutputStream(fd);
- fis = new FileInputStream(fd);
- } finally {
- try {
- if (fos != null) fos.close();
- if (raf != null) raf.close();
- if (!fd.valid()) {
- throw new RuntimeException("FileDescriptor should be valid");
- }
- if (fis != null) fis.close();
- if (fd.valid()) {
- throw new RuntimeException("close() called and FileDescriptor still valid");
- }
- } finally {
- test3.delete();
- }
- }
- }
-
- /**
- * Test concurrent access to the same fd.useCount field
- */
- private static void MultiThreadedFD() throws Exception {
- RandomAccessFile raf = null;
- FileDescriptor fd = null;
- int numThreads = 2;
- CountDownLatch done = new CountDownLatch(numThreads);
- OpenClose[] fileOpenClose = new OpenClose[numThreads];
- File MultipleThreadedFD = new File("MultipleThreadedFD");
- try {
- raf = new RandomAccessFile(MultipleThreadedFD, "rw");
- fd = raf.getFD();
- for(int count=0;count<numThreads;count++) {
- fileOpenClose[count] = new OpenClose(fd, done);
- fileOpenClose[count].start();
- }
- done.await();
- } finally {
- try {
- if(raf != null) raf.close();
- // fd should now no longer be valid
- if(fd.valid()) {
- throw new RuntimeException("FileDescriptor should not be valid");
- }
- // OpenClose thread tests failed
- if(fail) {
- throw new RuntimeException("OpenClose thread tests failed.");
- }
- } finally {
- MultipleThreadedFD.delete();
- }
- }
- }
-
- /**
- * A thread which will open and close a number of FileInputStreams and
- * FileOutputStreams referencing the same native file descriptor.
- */
- private static class OpenClose extends Thread {
- private FileDescriptor fd = null;
- private CountDownLatch done;
- FileInputStream[] fisArray = new FileInputStream[numFiles];
- FileOutputStream[] fosArray = new FileOutputStream[numFiles];
-
- OpenClose(FileDescriptor filedescriptor, CountDownLatch done) {
- this.fd = filedescriptor;
- this.done = done;
- }
-
- public void run() {
- try {
- for(int i=0;i<numFiles;i++) {
- fisArray[i] = new FileInputStream(fd);
- fosArray[i] = new FileOutputStream(fd);
- }
-
- // Now close out
- for(int i=0;i<numFiles;i++) {
- if(fisArray[i] != null) fisArray[i].close();
- if(fosArray[i] != null) fosArray[i].close();
- }
-
- } catch(IOException ioe) {
- System.out.println("OpenClose encountered IO issue :" + ioe);
- fail = true;
- } finally {
- if (!fd.valid()) { // fd should still be valid given RAF reference
- System.out.println("OpenClose: FileDescriptor should be valid");
- fail = true;
- }
- done.countDown();
- }
- }
- }
-}
--- a/jdk/test/java/lang/Runtime/exec/StreamsSurviveDestroy.java Thu Nov 17 10:46:00 2011 -0800
+++ b/jdk/test/java/lang/Runtime/exec/StreamsSurviveDestroy.java Wed Jul 05 17:56:12 2017 +0200
@@ -28,6 +28,7 @@
*/
import java.io.*;
+import java.util.concurrent.*;
public class StreamsSurviveDestroy {
@@ -40,15 +41,17 @@
boolean wantInterrupt;
boolean acceptException;
Exception exc = null;
+ CountDownLatch latch;
Copier(String name, InputStream in, OutputStream out,
- boolean ae, boolean wi)
+ boolean ae, boolean wi, CountDownLatch l)
{
this.name = name;
this.in = in;
this.out = out;
this.acceptException = ae;
this.wantInterrupt = wi;
+ this.latch = l;
setName(name);
start();
}
@@ -59,6 +62,7 @@
public void run() {
byte[] buf = new byte[4242];
+ latch.countDown();
for (;;) {
try {
int n = in.read(buf);
@@ -95,13 +99,17 @@
}
static void test() throws Exception {
+ CountDownLatch latch = new CountDownLatch(2);
+
System.err.println("test");
Process p = Runtime.getRuntime().exec("/bin/cat");
Copier cp1 = new Copier("out", p.getInputStream(), System.err,
- false, false);
+ false, false, latch);
Copier cp2 = new Copier("err", p.getErrorStream(), System.err,
- false, false);
- Thread.sleep(100);
+ false, false, latch);
+ latch.await(); // Wait till both Copiers about to read
+ Thread.sleep(100);// Give both Copiers a chance to start read
+
p.destroy();
System.err.println(" exit: " + p.waitFor());
cp1.join();
@@ -111,13 +119,17 @@
}
static void testCloseBeforeDestroy() throws Exception {
+ CountDownLatch latch = new CountDownLatch(2);
+
System.err.println("testCloseBeforeDestroy");
Process p = Runtime.getRuntime().exec("/bin/cat");
Copier cp1 = new Copier("out", p.getInputStream(), System.err,
- true, false);
+ true, false, latch);
Copier cp2 = new Copier("err", p.getErrorStream(), System.err,
- true, false);
- Thread.sleep(100);
+ true, false, latch);
+ latch.await(); // Wait till both Copiers about to read
+ Thread.sleep(100);// Give both Copiers a chance to start read
+
p.getInputStream().close();
p.getErrorStream().close();
p.destroy();
@@ -129,13 +141,17 @@
}
static void testCloseAfterDestroy() throws Exception {
+ CountDownLatch latch = new CountDownLatch(2);
System.err.println("testCloseAfterDestroy");
Process p = Runtime.getRuntime().exec("/bin/cat");
Copier cp1 = new Copier("out", p.getInputStream(), System.err,
- true, false);
+ true, false,latch);
Copier cp2 = new Copier("err", p.getErrorStream(), System.err,
- true, false);
- Thread.sleep(100);
+ true, false, latch);
+
+ latch.await(); // Wait till both Copiers about to read
+ Thread.sleep(100);// Give both Copiers a chance to start read
+
p.destroy();
p.getInputStream().close();
p.getErrorStream().close();
@@ -147,13 +163,16 @@
}
static void testInterrupt() throws Exception {
+ CountDownLatch latch = new CountDownLatch(2);
System.err.println("testInterrupt");
Process p = Runtime.getRuntime().exec("/bin/cat");
Copier cp1 = new Copier("out", p.getInputStream(), System.err,
- false, true);
+ false, true, latch);
Copier cp2 = new Copier("err", p.getErrorStream(), System.err,
- false, true);
- Thread.sleep(100);
+ false, true, latch);
+ latch.await(); // Wait till both Copiers about to read
+ Thread.sleep(100);// Give both Copiers a chance to start read
+
cp1.interrupt();
cp2.interrupt();
Thread.sleep(100);
@@ -176,7 +195,5 @@
testCloseBeforeDestroy();
testCloseAfterDestroy();
testInterrupt();
-
}
-
}
--- a/jdk/test/java/lang/ThreadGroup/NullThreadName.java Thu Nov 17 10:46:00 2011 -0800
+++ b/jdk/test/java/lang/ThreadGroup/NullThreadName.java Wed Jul 05 17:56:12 2017 +0200
@@ -24,7 +24,6 @@
/*
* @test
* @bug 6576763
- * @ignore until hotspot 6776144 bug is resolved
* @summary (thread) Thread constructors throw undocumented NPE for null name
*/
@@ -64,8 +63,8 @@
try { Thread.sleep(2000); }
catch (InterruptedException unused) {}
- /* do not wait forever */
- if (count++ > 5)
+ /* do not wait forever - allow 120 seconds same as jtreg default timeout. */
+ if (count++ > 60)
throw new AssertionError("GoodThread is still alive!");
}
--- a/jdk/test/java/lang/ThreadGroup/Stop.java Thu Nov 17 10:46:00 2011 -0800
+++ b/jdk/test/java/lang/ThreadGroup/Stop.java Wed Jul 05 17:56:12 2017 +0200
@@ -29,37 +29,58 @@
*/
public class Stop implements Runnable {
- private static Thread first=null;
- private static Thread second=null;
- private static ThreadGroup group = new ThreadGroup("");
+ private static boolean groupStopped = false ;
+ private static final Object lock = new Object();
- Stop() {
- Thread thread = new Thread(group, this);
- if (first == null)
- first = thread;
- else
- second = thread;
-
- thread.start();
- }
+ private static final ThreadGroup group = new ThreadGroup("");
+ private static final Thread first = new Thread(group, new Stop());
+ private static final Thread second = new Thread(group, new Stop());
public void run() {
while (true) {
+ // Give the other thread a chance to start
try {
- Thread.sleep(1000); // Give other thread a chance to start
- if (Thread.currentThread() == first)
- group.stop();
- } catch(InterruptedException e){
+ Thread.sleep(1000);
+ } catch (InterruptedException e) {
+ }
+
+ // When the first thread runs, it will stop the group.
+ if (Thread.currentThread() == first) {
+ synchronized (lock) {
+ try {
+ group.stop();
+ } finally {
+ // Signal the main thread it is time to check
+ // that the stopped thread group was successful
+ groupStopped = true;
+ lock.notifyAll();
+ }
+ }
}
}
}
public static void main(String[] args) throws Exception {
- for (int i=0; i<2; i++)
- new Stop();
- Thread.sleep(3000);
+ // Launch two threads as part of the same thread group
+ first.start();
+ second.start();
+
+ // Wait for the thread group stop to be issued
+ synchronized(lock){
+ while (!groupStopped) {
+ lock.wait();
+ // Give the other thread a chance to stop
+ Thread.sleep(1000);
+ }
+ }
+
+ // Check that the second thread is terminated when the
+ // first thread terminates the thread group.
boolean failed = second.isAlive();
- first.stop(); second.stop();
+
+ // Clean up any threads that may have not been terminated
+ first.stop();
+ second.stop();
if (failed)
throw new RuntimeException("Failure.");
}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/lang/invoke/CallSiteTest.java Wed Jul 05 17:56:12 2017 +0200
@@ -0,0 +1,164 @@
+/*
+ * Copyright (c) 2011, 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
+ * @summary smoke tests for CallSite
+ *
+ * @build indify.Indify
+ * @compile CallSiteTest.java
+ * @run main/othervm
+ * indify.Indify
+ * --expand-properties --classpath ${test.classes}
+ * --java test.java.lang.invoke.CallSiteTest
+ */
+
+package test.java.lang.invoke;
+
+import java.io.*;
+
+import java.lang.invoke.*;
+import static java.lang.invoke.MethodHandles.*;
+import static java.lang.invoke.MethodType.*;
+
+public class CallSiteTest {
+ private final static Class CLASS = CallSiteTest.class;
+
+ private static CallSite mcs;
+ private static CallSite vcs;
+ private static MethodHandle mh_foo;
+ private static MethodHandle mh_bar;
+
+ static {
+ try {
+ mh_foo = lookup().findStatic(CLASS, "foo", methodType(int.class, int.class, int.class));
+ mh_bar = lookup().findStatic(CLASS, "bar", methodType(int.class, int.class, int.class));
+ mcs = new MutableCallSite(mh_foo);
+ vcs = new VolatileCallSite(mh_foo);
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+
+ public static void main(String... av) throws Throwable {
+ testMutableCallSite();
+ testVolatileCallSite();
+ }
+
+ private final static int N = Integer.MAX_VALUE / 100;
+ private final static int RESULT1 = 762786192;
+ private final static int RESULT2 = -21474836;
+
+ private static void assertEquals(int expected, int actual) {
+ if (expected != actual)
+ throw new AssertionError("expected: " + expected + ", actual: " + actual);
+ }
+
+ private static void testMutableCallSite() throws Throwable {
+ // warm-up
+ for (int i = 0; i < 20000; i++) {
+ mcs.setTarget(mh_foo);
+ }
+ // run
+ for (int n = 0; n < 2; n++) {
+ mcs.setTarget(mh_foo);
+ for (int i = 0; i < 5; i++) {
+ assertEquals(RESULT1, runMutableCallSite());
+ }
+ mcs.setTarget(mh_bar);
+ for (int i = 0; i < 5; i++) {
+ assertEquals(RESULT2, runMutableCallSite());
+ }
+ }
+ }
+ private static void testVolatileCallSite() throws Throwable {
+ // warm-up
+ for (int i = 0; i < 20000; i++) {
+ vcs.setTarget(mh_foo);
+ }
+ // run
+ for (int n = 0; n < 2; n++) {
+ vcs.setTarget(mh_foo);
+ for (int i = 0; i < 5; i++) {
+ assertEquals(RESULT1, runVolatileCallSite());
+ }
+ vcs.setTarget(mh_bar);
+ for (int i = 0; i < 5; i++) {
+ assertEquals(RESULT2, runVolatileCallSite());
+ }
+ }
+ }
+
+ private static int runMutableCallSite() throws Throwable {
+ int sum = 0;
+ for (int i = 0; i < N; i++) {
+ sum += (int) INDY_mcs().invokeExact(i, i+1);
+ }
+ return sum;
+ }
+ private static int runVolatileCallSite() throws Throwable {
+ int sum = 0;
+ for (int i = 0; i < N; i++) {
+ sum += (int) INDY_vcs().invokeExact(i, i+1);
+ }
+ return sum;
+ }
+
+ static int foo(int a, int b) { return a + b; }
+ static int bar(int a, int b) { return a - b; }
+
+ private static MethodType MT_bsm() {
+ shouldNotCallThis();
+ return methodType(CallSite.class, Lookup.class, String.class, MethodType.class);
+ }
+
+ private static CallSite bsm_mcs(Lookup caller, String name, MethodType type) throws ReflectiveOperationException {
+ return mcs;
+ }
+ private static MethodHandle MH_bsm_mcs() throws ReflectiveOperationException {
+ shouldNotCallThis();
+ return lookup().findStatic(lookup().lookupClass(), "bsm_mcs", MT_bsm());
+ }
+ private static MethodHandle INDY_mcs() throws Throwable {
+ shouldNotCallThis();
+ return ((CallSite) MH_bsm_mcs().invoke(lookup(), "foo", methodType(int.class, int.class, int.class))).dynamicInvoker();
+ }
+
+ private static CallSite bsm_vcs(Lookup caller, String name, MethodType type) throws ReflectiveOperationException {
+ return vcs;
+ }
+ private static MethodHandle MH_bsm_vcs() throws ReflectiveOperationException {
+ shouldNotCallThis();
+ return lookup().findStatic(lookup().lookupClass(), "bsm_vcs", MT_bsm());
+ }
+ private static MethodHandle INDY_vcs() throws Throwable {
+ shouldNotCallThis();
+ return ((CallSite) MH_bsm_vcs().invoke(lookup(), "foo", methodType(int.class, int.class, int.class))).dynamicInvoker();
+ }
+
+ private static void shouldNotCallThis() {
+ // if this gets called, the transformation has not taken place
+ throw new AssertionError("this code should be statically transformed away by Indify");
+ }
+}
--- a/jdk/test/java/lang/invoke/InvokeDynamicPrintArgs.java Thu Nov 17 10:46:00 2011 -0800
+++ b/jdk/test/java/lang/invoke/InvokeDynamicPrintArgs.java Wed Jul 05 17:56:12 2017 +0200
@@ -38,8 +38,6 @@
package test.java.lang.invoke;
-import org.junit.Test;
-
import java.util.*;
import java.io.*;
@@ -99,21 +97,6 @@
System.setSecurityManager(new SM());
}
- @Test
- public void testInvokeDynamicPrintArgs() throws IOException {
- System.err.println(System.getProperties());
- String testClassPath = System.getProperty("build.test.classes.dir");
- if (testClassPath == null) throw new RuntimeException();
- String[] args = new String[]{
- "--verify-specifier-count=3",
- "--verbose",
- "--expand-properties", "--classpath", testClassPath,
- "--java", "test.java.lang.invoke.InvokeDynamicPrintArgs", "--check-output"
- };
- System.err.println("Indify: "+Arrays.toString(args));
- indify.Indify.main(args);
- }
-
private static PrintStream oldOut;
private static ByteArrayOutputStream buf;
private static void openBuf() {
--- a/jdk/test/java/lang/management/PlatformLoggingMXBean/LoggingMXBeanTest.java Thu Nov 17 10:46:00 2011 -0800
+++ b/jdk/test/java/lang/management/PlatformLoggingMXBean/LoggingMXBeanTest.java Wed Jul 05 17:56:12 2017 +0200
@@ -23,7 +23,7 @@
/*
* @test
- * @bug 7024172
+ * @bug 7024172 7067691
* @summary Test if proxy for PlatformLoggingMXBean is equivalent
* to proxy for LoggingMXBean
*
@@ -43,6 +43,13 @@
static String LOGGER_NAME_2 = "com.sun.management.Logger.Logger2";
static String UNKNOWN_LOGGER_NAME = "com.sun.management.Unknown";
+ // These instance variables prevent premature logger garbage collection
+ // See getLogger() weak reference warnings.
+ Logger logger1;
+ Logger logger2;
+
+ static LoggingMXBeanTest test;
+
public static void main(String[] argv) throws Exception {
MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();
LoggingMXBean proxy =
@@ -51,7 +58,7 @@
LoggingMXBean.class);
// test LoggingMXBean proxy
- LoggingMXBeanTest p = new LoggingMXBeanTest(proxy);
+ test = new LoggingMXBeanTest(proxy);
// check if the attributes implemented by PlatformLoggingMXBean
// and LoggingMXBean return the same value
@@ -64,9 +71,9 @@
// same verification as in java/util/logging/LoggingMXBeanTest2
public LoggingMXBeanTest(LoggingMXBean mbean) throws Exception {
- Logger logger1 = Logger.getLogger( LOGGER_NAME_1 );
+ logger1 = Logger.getLogger( LOGGER_NAME_1 );
logger1.setLevel(Level.FINE);
- Logger logger2 = Logger.getLogger( LOGGER_NAME_2 );
+ logger2 = Logger.getLogger( LOGGER_NAME_2 );
logger2.setLevel(null);
/*
@@ -207,6 +214,7 @@
// verify logger names
List<String> loggers1 = mxbean1.getLoggerNames();
List<String> loggers2 = mxbean2.getLoggerNames();
+
if (loggers1.size() != loggers2.size())
throw new RuntimeException("LoggerNames: unmatched number of entries");
List<String> loggers3 = new ArrayList<>(loggers1);
@@ -219,7 +227,10 @@
if (!mxbean1.getLoggerLevel(logger)
.equals(mxbean2.getLoggerLevel(logger)))
throw new RuntimeException(
- "LoggerLevel: unmatched level for " + logger);
+ "LoggerLevel: unmatched level for " + logger
+ + ", " + mxbean1.getLoggerLevel(logger)
+ + ", " + mxbean2.getLoggerLevel(logger));
+
if (!mxbean1.getParentLoggerName(logger)
.equals(mxbean2.getParentLoggerName(logger)))
throw new RuntimeException(
--- a/jdk/test/java/lang/management/PlatformLoggingMXBean/PlatformLoggingMXBeanTest.java Thu Nov 17 10:46:00 2011 -0800
+++ b/jdk/test/java/lang/management/PlatformLoggingMXBean/PlatformLoggingMXBeanTest.java Wed Jul 05 17:56:12 2017 +0200
@@ -23,7 +23,7 @@
/*
* @test
- * @bug 6876135 7024172
+ * @bug 6876135 7024172 7067691
*
* @summary Test PlatformLoggingMXBean
* This test performs similar testing as
@@ -41,11 +41,15 @@
public class PlatformLoggingMXBeanTest
{
-
ObjectName objectName = null;
static String LOGGER_NAME_1 = "com.sun.management.Logger1";
static String LOGGER_NAME_2 = "com.sun.management.Logger2";
+ // Use Logger instance variables to prevent premature garbage collection
+ // of weak references.
+ Logger logger1;
+ Logger logger2;
+
public PlatformLoggingMXBeanTest() throws Exception {
}
@@ -135,8 +139,8 @@
System.out.println( "*********** Phase 3 ***********" );
System.out.println( "*******************************" );
System.out.println( " Create and test new Loggers" );
- Logger logger1 = Logger.getLogger( LOGGER_NAME_1 );
- Logger logger2 = Logger.getLogger( LOGGER_NAME_2 );
+ logger1 = Logger.getLogger( LOGGER_NAME_1 );
+ logger2 = Logger.getLogger( LOGGER_NAME_2 );
// check that Level object are returned properly
try {
@@ -187,6 +191,7 @@
System.out.println( " Set and Check the Logger Level" );
log1 = false;
log2 = false;
+
try {
// Set the level of logger1 to ALL
params = new Object[2];
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/rmi/registry/readTest/readTest.java Wed Jul 05 17:56:12 2017 +0200
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 2011, 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.rmi.registry.Registry;
+import java.rmi.registry.LocateRegistry;
+import java.rmi.RemoteException;
+import java.rmi.server.UnicastRemoteObject;
+
+public class readTest {
+
+ public static void main(String args[]) throws Exception {
+ int port = 7491;
+ try {
+ testPkg.Server obj = new testPkg.Server();
+ testPkg.Hello stub = (testPkg.Hello) UnicastRemoteObject.exportObject(obj, 0);
+ // Bind the remote object's stub in the registry
+ Registry registry = LocateRegistry.getRegistry(port);
+ registry.bind("Hello", stub);
+
+ System.err.println("Server ready");
+
+ // now, let's test client
+ testPkg.Client client = new testPkg.Client(port);
+ String testStubReturn = client.testStub();
+ if(!testStubReturn.equals(obj.hello)) {
+ throw new RuntimeException("Test Fails : unexpected string from stub call");
+ } else {
+ System.out.println("Test passed");
+ }
+ registry.unbind("Hello");
+
+ } catch (Exception e) {
+ System.err.println("Server exception: " + e.toString());
+ e.printStackTrace();
+ }
+
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/rmi/registry/readTest/readTest.sh Wed Jul 05 17:56:12 2017 +0200
@@ -0,0 +1,95 @@
+#
+# Copyright (c) 2011, 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 7102369 7094468 7100592
+# @summary remove java.rmi.server.codebase property parsing from registyimpl
+# @run shell readTest.sh
+
+OS=`uname -s`
+case "$OS" in
+ SunOS | Linux )
+ PS=":"
+ FS="/"
+ FILEURL="file:"
+ ;;
+ Windows* | CYGWIN* )
+ PS=";"
+ FS="\\"
+ FILEURL="file:/"
+ ;;
+ * )
+ echo "Unrecognized system!"
+ exit 1;
+ ;;
+esac
+
+cp -r ${TESTSRC}${FS}* .
+${TESTJAVA}${FS}bin${FS}javac testPkg${FS}*java
+${TESTJAVA}${FS}bin${FS}javac readTest.java
+
+mkdir rmi_tmp
+RMIREG_OUT=rmi.out
+#start rmiregistry without any local classes on classpath
+cd rmi_tmp
+${TESTJAVA}${FS}bin${FS}rmiregistry 7491 > ..${FS}${RMIREG_OUT} 2>&1 &
+RMIREG_PID=$!
+# allow some time to start
+sleep 3
+cd ..
+
+# trailing / after code base is important for rmi codebase property.
+${TESTJAVA}${FS}bin${FS}java -Djava.rmi.server.codebase=${FILEURL}`pwd`/ readTest > OUT.TXT 2>&1 &
+TEST_PID=$!
+#bulk of testcase - let it run for a while
+sleep 5
+
+#we're done, kill processes first
+kill -9 ${RMIREG_PID} ${TEST_PID}
+sleep 3
+
+echo "Test output : "
+
+cat OUT.TXT
+echo "=============="
+echo "rmiregistry output : "
+cat ${RMIREG_OUT}
+echo "=============="
+
+grep "Server ready" OUT.TXT
+result1=$?
+grep "Test passed" OUT.TXT
+result2=$?
+
+if [ $result1 -eq 0 -a $result2 -eq 0 ]
+then
+ echo "Passed"
+ exitCode=0;
+else
+ echo "Failed"
+ exitCode=1
+fi
+rm -rf OUT.TXT ${RMIREG_OUT} rmi_tmp
+exit ${exitCode}
+
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/rmi/registry/readTest/testPkg/Client.java Wed Jul 05 17:56:12 2017 +0200
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2011, 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 testPkg;
+
+import java.rmi.registry.LocateRegistry;
+import java.rmi.registry.Registry;
+
+public class Client {
+ int port;
+
+ public Client(int p) {
+ port = p;
+ }
+
+ public String testStub() throws Exception {
+ try {
+ Registry registry = LocateRegistry.getRegistry(port);
+ Hello stub = (Hello) registry.lookup("Hello");
+ String response = stub.sayHello();
+ return response;
+ } catch (Exception e) {
+ System.err.println("Client exception: " + e.toString());
+ throw e;
+ }
+ }
+ }
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/rmi/registry/readTest/testPkg/Hello.java Wed Jul 05 17:56:12 2017 +0200
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) 2011, 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 testPkg;
+
+import java.rmi.Remote;
+import java.rmi.RemoteException;
+
+public interface Hello extends Remote {
+ String sayHello() throws RemoteException;
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/rmi/registry/readTest/testPkg/Server.java Wed Jul 05 17:56:12 2017 +0200
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2011, 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 testPkg;
+
+public class Server implements Hello {
+
+ public String hello = "Hello, world!";
+
+ public Server() {}
+
+ public String sayHello() {
+ return hello;
+ }
+
+}
--- a/jdk/test/java/util/Timer/Args.java Thu Nov 17 10:46:00 2011 -0800
+++ b/jdk/test/java/util/Timer/Args.java Wed Jul 05 17:56:12 2017 +0200
@@ -92,19 +92,22 @@
new F(){void f(){ t.scheduleAtFixedRate(x, (Date)null, 42); }}
);
- final long start = System.currentTimeMillis();
- final Date past = new Date(start - 10500);
final CountDownLatch y1 = new CountDownLatch(1);
final CountDownLatch y2 = new CountDownLatch(1);
final CountDownLatch y3 = new CountDownLatch(11);
+ final long start = System.currentTimeMillis();
+ final Date past = new Date(start - 10500);
+
schedule( t, counter(y1), past);
schedule( t, counter(y2), past, 1000);
scheduleAtFixedRate(t, counter(y3), past, 1000);
y3.await();
y1.await();
y2.await();
- System.out.printf("elapsed=%d%n", System.currentTimeMillis() - start);
- check(System.currentTimeMillis() - start < 500);
+
+ final long elapsed = System.currentTimeMillis() - start;
+ System.out.printf("elapsed=%d%n", elapsed);
+ check(elapsed < 500);
t.cancel();
--- a/jdk/test/java/util/Timer/KillThread.java Thu Nov 17 10:46:00 2011 -0800
+++ b/jdk/test/java/util/Timer/KillThread.java Wed Jul 05 17:56:12 2017 +0200
@@ -31,21 +31,26 @@
import java.util.*;
public class KillThread {
+ static volatile Thread tdThread;
public static void main (String[] args) throws Exception {
Timer t = new Timer();
// Start a mean event that kills the timer thread
t.schedule(new TimerTask() {
public void run() {
+ tdThread = Thread.currentThread();
throw new ThreadDeath();
}
}, 0);
// Wait for mean event to do the deed and thread to die.
try {
- Thread.sleep(100);
+ do {
+ Thread.sleep(100);
+ } while(tdThread == null);
} catch(InterruptedException e) {
}
+ tdThread.join();
// Try to start another event
try {
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/sun/security/ssl/com/sun/net/ssl/internal/ssl/SSLContextImpl/MD2InTrustAnchor.java Wed Jul 05 17:56:12 2017 +0200
@@ -0,0 +1,423 @@
+/*
+ * Copyright (c) 2011, 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.
+ */
+
+/*
+ * @test
+ * @bug 7113275
+ * @summary compatibility issue with MD2 trust anchor and old X509TrustManager
+ *
+ * SunJSSE does not support dynamic system properties, no way to re-use
+ * system properties in samevm/agentvm mode.
+ * @run main/othervm MD2InTrustAnchor PKIX TLSv1.1
+ * @run main/othervm MD2InTrustAnchor SunX509 TLSv1.1
+ * @run main/othervm MD2InTrustAnchor PKIX TLSv1.2
+ * @run main/othervm MD2InTrustAnchor SunX509 TLSv1.2
+ */
+
+import java.net.*;
+import java.util.*;
+import java.io.*;
+import javax.net.ssl.*;
+import java.security.KeyStore;
+import java.security.KeyFactory;
+import java.security.cert.Certificate;
+import java.security.cert.CertificateFactory;
+import java.security.spec.*;
+import java.security.interfaces.*;
+import sun.misc.BASE64Decoder;
+
+
+public class MD2InTrustAnchor {
+
+ /*
+ * =============================================================
+ * Set the various variables needed for the tests, then
+ * specify what tests to run on each side.
+ */
+
+ /*
+ * Should we run the client or server in a separate thread?
+ * Both sides can throw exceptions, but do you have a preference
+ * as to which side should be the main thread.
+ */
+ static boolean separateServerThread = false;
+
+ /*
+ * Certificates and key used in the test.
+ */
+
+ // It's a trust anchor signed with MD2 hash function.
+ static String trustedCertStr =
+ "-----BEGIN CERTIFICATE-----\n" +
+ "MIICkjCCAfugAwIBAgIBADANBgkqhkiG9w0BAQIFADA7MQswCQYDVQQGEwJVUzEN\n" +
+ "MAsGA1UEChMESmF2YTEdMBsGA1UECxMUU3VuSlNTRSBUZXN0IFNlcml2Y2UwHhcN\n" +
+ "MTExMTE4MTExNDA0WhcNMzIxMDI4MTExNDA0WjA7MQswCQYDVQQGEwJVUzENMAsG\n" +
+ "A1UEChMESmF2YTEdMBsGA1UECxMUU3VuSlNTRSBUZXN0IFNlcml2Y2UwgZ8wDQYJ\n" +
+ "KoZIhvcNAQEBBQADgY0AMIGJAoGBAPGyB9tugUGgxtdeqe0qJEwf9x1Gy4BOi1yR\n" +
+ "wzDZY4H5LquvIfQ2V3J9X1MQENVsFvkvp65ZcFcy+ObOucXUUPFcd/iw2DVb5QXA\n" +
+ "ffyeVqWD56GPi8Qe37wrJO3L6fBhN9oxp/BbdRLgjU81zx8qLEyPODhPMxV4OkcA\n" +
+ "SDwZTSxxAgMBAAGjgaUwgaIwHQYDVR0OBBYEFLOAtr/YrYj9H04EDLA0fd14jisF\n" +
+ "MGMGA1UdIwRcMFqAFLOAtr/YrYj9H04EDLA0fd14jisFoT+kPTA7MQswCQYDVQQG\n" +
+ "EwJVUzENMAsGA1UEChMESmF2YTEdMBsGA1UECxMUU3VuSlNTRSBUZXN0IFNlcml2\n" +
+ "Y2WCAQAwDwYDVR0TAQH/BAUwAwEB/zALBgNVHQ8EBAMCAQYwDQYJKoZIhvcNAQEC\n" +
+ "BQADgYEAr8ExpXu/FTIRiMzPm0ubqwME4lniilwQUiEOD/4DbksNjEIcUyS2hIk1\n" +
+ "qsmjJz3SHBnwhxl9dhJVwk2tZLkPGW86Zn0TPVRsttK4inTgCC9GFGeqQBdrU/uf\n" +
+ "lipBzXWljrfbg4N/kK8m2LabtKUMMnGysM8rN0Fx2PYm5xxGvtM=\n" +
+ "-----END CERTIFICATE-----";
+
+ // The certificate issued by above trust anchor, signed with MD5
+ static String targetCertStr =
+ "-----BEGIN CERTIFICATE-----\n" +
+ "MIICeDCCAeGgAwIBAgIBAjANBgkqhkiG9w0BAQQFADA7MQswCQYDVQQGEwJVUzEN\n" +
+ "MAsGA1UEChMESmF2YTEdMBsGA1UECxMUU3VuSlNTRSBUZXN0IFNlcml2Y2UwHhcN\n" +
+ "MTExMTE4MTExNDA2WhcNMzEwODA1MTExNDA2WjBPMQswCQYDVQQGEwJVUzENMAsG\n" +
+ "A1UEChMESmF2YTEdMBsGA1UECxMUU3VuSlNTRSBUZXN0IFNlcml2Y2UxEjAQBgNV\n" +
+ "BAMTCWxvY2FsaG9zdDCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAwDnm96mw\n" +
+ "fXCH4bgXk1US0VcJsQVxUtGMyncAveMuzBzNzOmKZPeqyYX1Fuh4q+cuza03WTJd\n" +
+ "G9nOkNr364e3Rn1aaHjCMcBmFflObnGnhhufNmIGYogJ9dJPmhUVPEVAXrMG+Ces\n" +
+ "NKy2E8woGnLMrqu6yiuTClbLBPK8fWzTXrECAwEAAaN4MHYwCwYDVR0PBAQDAgPo\n" +
+ "MB0GA1UdDgQWBBSdRrpocLPJXyGfDmMWJrcEf29WGDAfBgNVHSMEGDAWgBSzgLa/\n" +
+ "2K2I/R9OBAywNH3deI4rBTAnBgNVHSUEIDAeBggrBgEFBQcDAQYIKwYBBQUHAwIG\n" +
+ "CCsGAQUFBwMDMA0GCSqGSIb3DQEBBAUAA4GBAKJ71ZiCUykkJrCLYUxlFlhvUcr9\n" +
+ "sTcOc67QdroW5f412NI15SXWDiley/JOasIiuIFPjaJBjOKoHOvTjG/snVu9wEgq\n" +
+ "YNR8dPsO+NM8r79C6jO+Jx5fYAC7os2XxS75h3NX0ElJcbwIXGBJ6xRrsFh/BGYH\n" +
+ "yvudOlX4BkVR0l1K\n" +
+ "-----END CERTIFICATE-----";
+
+ // Private key in the format of PKCS#8.
+ static String targetPrivateKey =
+ "MIICdwIBADANBgkqhkiG9w0BAQEFAASCAmEwggJdAgEAAoGBAMA55vepsH1wh+G4\n" +
+ "F5NVEtFXCbEFcVLRjMp3AL3jLswczczpimT3qsmF9RboeKvnLs2tN1kyXRvZzpDa\n" +
+ "9+uHt0Z9Wmh4wjHAZhX5Tm5xp4YbnzZiBmKICfXST5oVFTxFQF6zBvgnrDSsthPM\n" +
+ "KBpyzK6rusorkwpWywTyvH1s016xAgMBAAECgYEAn9bF3oRkdDoBU0i/mcww5I+K\n" +
+ "SH9tFt+WQbiojjz9ac49trkvUfu7MO1Jui2+QbrvaSkyj+HYGFOJd1wMsPXeB7ck\n" +
+ "5mOIYV4uZK8jfNMSQ8v0tFEeIPp5lKdw1XnrQfSe+abo2eL5Lwso437Y4s3w37+H\n" +
+ "aY3d76hR5qly+Ys+Ww0CQQDjeOoX89d/xhRqGXKjCx8ImE/dPmsI8O27cwtKrDYJ\n" +
+ "6t0v/xryVIdvOYcRBvKnqEogOH7T1kI+LnWKUTJ2ehJ7AkEA2FVloPVqCehXcc7e\n" +
+ "z3TDpU9w1B0JXklcV5HddYsRqp9RukN/VK4szKE7F1yoarIUtfE9Lr9082Jwyp3M\n" +
+ "L11xwwJBAKsZ+Hur3x0tUY29No2Nf/pnFyvEF57SGwA0uPmiL8Ol9lpz+UDudDEl\n" +
+ "hIM6Rqv12kwCMuQE9i7vo1o3WU3k5KECQEqhg1L49yD935TqiiFFpe0Ur9btQXse\n" +
+ "kdXAA4d2d5zGI7q/aGD9SYU6phkUJSHR16VA2RuUfzMrpb+wmm1IrmMCQFtLoKRT\n" +
+ "A5kokFb+E3Gplu29tJvCUpfwgBFRS+wmkvtiaU/tiyDcVgDO+An5DwedxxdVzqiE\n" +
+ "njWHoKY3axDQ8OU=\n";
+
+
+ static char passphrase[] = "passphrase".toCharArray();
+
+ /*
+ * Is the server ready to serve?
+ */
+ volatile static boolean serverReady = false;
+
+ /*
+ * Turn on SSL debugging?
+ */
+ static boolean debug = false;
+
+ /*
+ * Define the server side of the test.
+ *
+ * If the server prematurely exits, serverReady will be set to true
+ * to avoid infinite hangs.
+ */
+ void doServerSide() throws Exception {
+ SSLContext context = generateSSLContext(trustedCertStr, targetCertStr,
+ targetPrivateKey);
+ SSLServerSocketFactory sslssf = context.getServerSocketFactory();
+ SSLServerSocket sslServerSocket =
+ (SSLServerSocket)sslssf.createServerSocket(serverPort);
+ sslServerSocket.setNeedClientAuth(true);
+ serverPort = sslServerSocket.getLocalPort();
+
+ /*
+ * Signal Client, we're ready for his connect.
+ */
+ serverReady = true;
+
+ SSLSocket sslSocket = (SSLSocket)sslServerSocket.accept();
+ InputStream sslIS = sslSocket.getInputStream();
+ OutputStream sslOS = sslSocket.getOutputStream();
+
+ sslIS.read();
+ sslOS.write('A');
+ sslOS.flush();
+
+ sslSocket.close();
+ }
+
+ /*
+ * Define the client side of the test.
+ *
+ * If the server prematurely exits, serverReady will be set to true
+ * to avoid infinite hangs.
+ */
+ void doClientSide() throws Exception {
+
+ /*
+ * Wait for server to get started.
+ */
+ while (!serverReady) {
+ Thread.sleep(50);
+ }
+
+ SSLContext context = generateSSLContext(trustedCertStr, targetCertStr,
+ targetPrivateKey);
+ SSLSocketFactory sslsf = context.getSocketFactory();
+
+ SSLSocket sslSocket =
+ (SSLSocket)sslsf.createSocket("localhost", serverPort);
+
+ // enable the specified TLS protocol
+ sslSocket.setEnabledProtocols(new String[] {tlsProtocol});
+
+ InputStream sslIS = sslSocket.getInputStream();
+ OutputStream sslOS = sslSocket.getOutputStream();
+
+ sslOS.write('B');
+ sslOS.flush();
+ sslIS.read();
+
+ sslSocket.close();
+ }
+
+ /*
+ * =============================================================
+ * The remainder is just support stuff
+ */
+ private static String tmAlgorithm; // trust manager
+ private static String tlsProtocol; // trust manager
+
+ private static void parseArguments(String[] args) {
+ tmAlgorithm = args[0];
+ tlsProtocol = args[1];
+ }
+
+ private static SSLContext generateSSLContext(String trustedCertStr,
+ String keyCertStr, String keySpecStr) throws Exception {
+
+ // generate certificate from cert string
+ CertificateFactory cf = CertificateFactory.getInstance("X.509");
+
+ // create a key store
+ KeyStore ks = KeyStore.getInstance("JKS");
+ ks.load(null, null);
+
+ // import the trused cert
+ Certificate trusedCert = null;
+ ByteArrayInputStream is = null;
+ if (trustedCertStr != null) {
+ is = new ByteArrayInputStream(trustedCertStr.getBytes());
+ trusedCert = cf.generateCertificate(is);
+ is.close();
+
+ ks.setCertificateEntry("RSA Export Signer", trusedCert);
+ }
+
+ if (keyCertStr != null) {
+ // generate the private key.
+ PKCS8EncodedKeySpec priKeySpec = new PKCS8EncodedKeySpec(
+ new BASE64Decoder().decodeBuffer(keySpecStr));
+ KeyFactory kf = KeyFactory.getInstance("RSA");
+ RSAPrivateKey priKey =
+ (RSAPrivateKey)kf.generatePrivate(priKeySpec);
+
+ // generate certificate chain
+ is = new ByteArrayInputStream(keyCertStr.getBytes());
+ Certificate keyCert = cf.generateCertificate(is);
+ is.close();
+
+ // It's not allowed to send MD2 signed certificate to peer,
+ // even it may be a trusted certificate. Then we will not
+ // place the trusted certficate in the chain.
+ Certificate[] chain = new Certificate[1];
+ chain[0] = keyCert;
+
+ // import the key entry.
+ ks.setKeyEntry("Whatever", priKey, passphrase, chain);
+ }
+
+ // create SSL context
+ TrustManagerFactory tmf = TrustManagerFactory.getInstance(tmAlgorithm);
+ tmf.init(ks);
+
+ SSLContext ctx = SSLContext.getInstance(tlsProtocol);
+ if (keyCertStr != null && !keyCertStr.isEmpty()) {
+ KeyManagerFactory kmf = KeyManagerFactory.getInstance("NewSunX509");
+ kmf.init(ks, passphrase);
+
+ ctx.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null);
+ ks = null;
+ } else {
+ ctx.init(null, tmf.getTrustManagers(), null);
+ }
+
+ return ctx;
+ }
+
+
+ // use any free port by default
+ volatile int serverPort = 0;
+
+ volatile Exception serverException = null;
+ volatile Exception clientException = null;
+
+ public static void main(String[] args) throws Exception {
+ if (debug)
+ System.setProperty("javax.net.debug", "all");
+
+ /*
+ * Get the customized arguments.
+ */
+ parseArguments(args);
+
+ /*
+ * Start the tests.
+ */
+ new MD2InTrustAnchor();
+ }
+
+ Thread clientThread = null;
+ Thread serverThread = null;
+
+ /*
+ * Primary constructor, used to drive remainder of the test.
+ *
+ * Fork off the other side, then do your work.
+ */
+ MD2InTrustAnchor() throws Exception {
+ try {
+ if (separateServerThread) {
+ startServer(true);
+ startClient(false);
+ } else {
+ startClient(true);
+ startServer(false);
+ }
+ } catch (Exception e) {
+ // swallow for now. Show later
+ }
+
+ /*
+ * Wait for other side to close down.
+ */
+ if (separateServerThread) {
+ serverThread.join();
+ } else {
+ clientThread.join();
+ }
+
+ /*
+ * When we get here, the test is pretty much over.
+ * Which side threw the error?
+ */
+ Exception local;
+ Exception remote;
+ String whichRemote;
+
+ if (separateServerThread) {
+ remote = serverException;
+ local = clientException;
+ whichRemote = "server";
+ } else {
+ remote = clientException;
+ local = serverException;
+ whichRemote = "client";
+ }
+
+ /*
+ * If both failed, return the curthread's exception, but also
+ * print the remote side Exception
+ */
+ if ((local != null) && (remote != null)) {
+ System.out.println(whichRemote + " also threw:");
+ remote.printStackTrace();
+ System.out.println();
+ throw local;
+ }
+
+ if (remote != null) {
+ throw remote;
+ }
+
+ if (local != null) {
+ throw local;
+ }
+ }
+
+ void startServer(boolean newThread) throws Exception {
+ if (newThread) {
+ serverThread = new Thread() {
+ public void run() {
+ try {
+ doServerSide();
+ } catch (Exception e) {
+ /*
+ * Our server thread just died.
+ *
+ * Release the client, if not active already...
+ */
+ System.err.println("Server died...");
+ serverReady = true;
+ serverException = e;
+ }
+ }
+ };
+ serverThread.start();
+ } else {
+ try {
+ doServerSide();
+ } catch (Exception e) {
+ serverException = e;
+ } finally {
+ serverReady = true;
+ }
+ }
+ }
+
+ void startClient(boolean newThread) throws Exception {
+ if (newThread) {
+ clientThread = new Thread() {
+ public void run() {
+ try {
+ doClientSide();
+ } catch (Exception e) {
+ /*
+ * Our client thread just died.
+ */
+ System.err.println("Client died...");
+ clientException = e;
+ }
+ }
+ };
+ clientThread.start();
+ } else {
+ try {
+ doClientSide();
+ } catch (Exception e) {
+ clientException = e;
+ }
+ }
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/sun/security/ssl/com/sun/net/ssl/internal/ssl/SSLContextImpl/TrustTrustedCert.java Wed Jul 05 17:56:12 2017 +0200
@@ -0,0 +1,475 @@
+/*
+ * Copyright (c) 2011, 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.
+ */
+
+/*
+ * @test
+ * @bug 7113275
+ * @summary compatibility issue with MD2 trust anchor and old X509TrustManager
+ *
+ * SunJSSE does not support dynamic system properties, no way to re-use
+ * system properties in samevm/agentvm mode.
+ * @run main/othervm TrustTrustedCert PKIX TLSv1.1
+ * @run main/othervm TrustTrustedCert SunX509 TLSv1.1
+ * @run main/othervm TrustTrustedCert PKIX TLSv1.2
+ * @run main/othervm TrustTrustedCert SunX509 TLSv1.2
+ */
+
+import java.net.*;
+import java.util.*;
+import java.io.*;
+import javax.net.ssl.*;
+import java.security.*;
+import java.security.cert.*;
+import java.security.spec.*;
+import java.security.interfaces.*;
+import sun.misc.BASE64Decoder;
+
+
+public class TrustTrustedCert {
+
+ /*
+ * =============================================================
+ * Set the various variables needed for the tests, then
+ * specify what tests to run on each side.
+ */
+
+ /*
+ * Should we run the client or server in a separate thread?
+ * Both sides can throw exceptions, but do you have a preference
+ * as to which side should be the main thread.
+ */
+ static boolean separateServerThread = false;
+
+ /*
+ * Certificates and key used in the test.
+ */
+
+ // It's a trust anchor signed with MD2 hash function.
+ static String trustedCertStr =
+ "-----BEGIN CERTIFICATE-----\n" +
+ "MIICkjCCAfugAwIBAgIBADANBgkqhkiG9w0BAQIFADA7MQswCQYDVQQGEwJVUzEN\n" +
+ "MAsGA1UEChMESmF2YTEdMBsGA1UECxMUU3VuSlNTRSBUZXN0IFNlcml2Y2UwHhcN\n" +
+ "MTExMTE4MTExNDA0WhcNMzIxMDI4MTExNDA0WjA7MQswCQYDVQQGEwJVUzENMAsG\n" +
+ "A1UEChMESmF2YTEdMBsGA1UECxMUU3VuSlNTRSBUZXN0IFNlcml2Y2UwgZ8wDQYJ\n" +
+ "KoZIhvcNAQEBBQADgY0AMIGJAoGBAPGyB9tugUGgxtdeqe0qJEwf9x1Gy4BOi1yR\n" +
+ "wzDZY4H5LquvIfQ2V3J9X1MQENVsFvkvp65ZcFcy+ObOucXUUPFcd/iw2DVb5QXA\n" +
+ "ffyeVqWD56GPi8Qe37wrJO3L6fBhN9oxp/BbdRLgjU81zx8qLEyPODhPMxV4OkcA\n" +
+ "SDwZTSxxAgMBAAGjgaUwgaIwHQYDVR0OBBYEFLOAtr/YrYj9H04EDLA0fd14jisF\n" +
+ "MGMGA1UdIwRcMFqAFLOAtr/YrYj9H04EDLA0fd14jisFoT+kPTA7MQswCQYDVQQG\n" +
+ "EwJVUzENMAsGA1UEChMESmF2YTEdMBsGA1UECxMUU3VuSlNTRSBUZXN0IFNlcml2\n" +
+ "Y2WCAQAwDwYDVR0TAQH/BAUwAwEB/zALBgNVHQ8EBAMCAQYwDQYJKoZIhvcNAQEC\n" +
+ "BQADgYEAr8ExpXu/FTIRiMzPm0ubqwME4lniilwQUiEOD/4DbksNjEIcUyS2hIk1\n" +
+ "qsmjJz3SHBnwhxl9dhJVwk2tZLkPGW86Zn0TPVRsttK4inTgCC9GFGeqQBdrU/uf\n" +
+ "lipBzXWljrfbg4N/kK8m2LabtKUMMnGysM8rN0Fx2PYm5xxGvtM=\n" +
+ "-----END CERTIFICATE-----";
+
+ // The certificate issued by above trust anchor, signed with MD5
+ static String targetCertStr =
+ "-----BEGIN CERTIFICATE-----\n" +
+ "MIICeDCCAeGgAwIBAgIBAjANBgkqhkiG9w0BAQQFADA7MQswCQYDVQQGEwJVUzEN\n" +
+ "MAsGA1UEChMESmF2YTEdMBsGA1UECxMUU3VuSlNTRSBUZXN0IFNlcml2Y2UwHhcN\n" +
+ "MTExMTE4MTExNDA2WhcNMzEwODA1MTExNDA2WjBPMQswCQYDVQQGEwJVUzENMAsG\n" +
+ "A1UEChMESmF2YTEdMBsGA1UECxMUU3VuSlNTRSBUZXN0IFNlcml2Y2UxEjAQBgNV\n" +
+ "BAMTCWxvY2FsaG9zdDCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAwDnm96mw\n" +
+ "fXCH4bgXk1US0VcJsQVxUtGMyncAveMuzBzNzOmKZPeqyYX1Fuh4q+cuza03WTJd\n" +
+ "G9nOkNr364e3Rn1aaHjCMcBmFflObnGnhhufNmIGYogJ9dJPmhUVPEVAXrMG+Ces\n" +
+ "NKy2E8woGnLMrqu6yiuTClbLBPK8fWzTXrECAwEAAaN4MHYwCwYDVR0PBAQDAgPo\n" +
+ "MB0GA1UdDgQWBBSdRrpocLPJXyGfDmMWJrcEf29WGDAfBgNVHSMEGDAWgBSzgLa/\n" +
+ "2K2I/R9OBAywNH3deI4rBTAnBgNVHSUEIDAeBggrBgEFBQcDAQYIKwYBBQUHAwIG\n" +
+ "CCsGAQUFBwMDMA0GCSqGSIb3DQEBBAUAA4GBAKJ71ZiCUykkJrCLYUxlFlhvUcr9\n" +
+ "sTcOc67QdroW5f412NI15SXWDiley/JOasIiuIFPjaJBjOKoHOvTjG/snVu9wEgq\n" +
+ "YNR8dPsO+NM8r79C6jO+Jx5fYAC7os2XxS75h3NX0ElJcbwIXGBJ6xRrsFh/BGYH\n" +
+ "yvudOlX4BkVR0l1K\n" +
+ "-----END CERTIFICATE-----";
+
+ // Private key in the format of PKCS#8.
+ static String targetPrivateKey =
+ "MIICdwIBADANBgkqhkiG9w0BAQEFAASCAmEwggJdAgEAAoGBAMA55vepsH1wh+G4\n" +
+ "F5NVEtFXCbEFcVLRjMp3AL3jLswczczpimT3qsmF9RboeKvnLs2tN1kyXRvZzpDa\n" +
+ "9+uHt0Z9Wmh4wjHAZhX5Tm5xp4YbnzZiBmKICfXST5oVFTxFQF6zBvgnrDSsthPM\n" +
+ "KBpyzK6rusorkwpWywTyvH1s016xAgMBAAECgYEAn9bF3oRkdDoBU0i/mcww5I+K\n" +
+ "SH9tFt+WQbiojjz9ac49trkvUfu7MO1Jui2+QbrvaSkyj+HYGFOJd1wMsPXeB7ck\n" +
+ "5mOIYV4uZK8jfNMSQ8v0tFEeIPp5lKdw1XnrQfSe+abo2eL5Lwso437Y4s3w37+H\n" +
+ "aY3d76hR5qly+Ys+Ww0CQQDjeOoX89d/xhRqGXKjCx8ImE/dPmsI8O27cwtKrDYJ\n" +
+ "6t0v/xryVIdvOYcRBvKnqEogOH7T1kI+LnWKUTJ2ehJ7AkEA2FVloPVqCehXcc7e\n" +
+ "z3TDpU9w1B0JXklcV5HddYsRqp9RukN/VK4szKE7F1yoarIUtfE9Lr9082Jwyp3M\n" +
+ "L11xwwJBAKsZ+Hur3x0tUY29No2Nf/pnFyvEF57SGwA0uPmiL8Ol9lpz+UDudDEl\n" +
+ "hIM6Rqv12kwCMuQE9i7vo1o3WU3k5KECQEqhg1L49yD935TqiiFFpe0Ur9btQXse\n" +
+ "kdXAA4d2d5zGI7q/aGD9SYU6phkUJSHR16VA2RuUfzMrpb+wmm1IrmMCQFtLoKRT\n" +
+ "A5kokFb+E3Gplu29tJvCUpfwgBFRS+wmkvtiaU/tiyDcVgDO+An5DwedxxdVzqiE\n" +
+ "njWHoKY3axDQ8OU=\n";
+
+
+ static char passphrase[] = "passphrase".toCharArray();
+
+ /*
+ * Is the server ready to serve?
+ */
+ volatile static boolean serverReady = false;
+
+ /*
+ * Turn on SSL debugging?
+ */
+ static boolean debug = false;
+
+ /*
+ * Define the server side of the test.
+ *
+ * If the server prematurely exits, serverReady will be set to true
+ * to avoid infinite hangs.
+ */
+ void doServerSide() throws Exception {
+ SSLContext context = generateSSLContext();
+ SSLServerSocketFactory sslssf = context.getServerSocketFactory();
+ SSLServerSocket sslServerSocket =
+ (SSLServerSocket)sslssf.createServerSocket(serverPort);
+ sslServerSocket.setNeedClientAuth(true);
+ serverPort = sslServerSocket.getLocalPort();
+
+ /*
+ * Signal Client, we're ready for his connect.
+ */
+ serverReady = true;
+
+ SSLSocket sslSocket = (SSLSocket)sslServerSocket.accept();
+ InputStream sslIS = sslSocket.getInputStream();
+ OutputStream sslOS = sslSocket.getOutputStream();
+
+ sslIS.read();
+ sslOS.write('A');
+ sslOS.flush();
+
+ sslSocket.close();
+ }
+
+ /*
+ * Define the client side of the test.
+ *
+ * If the server prematurely exits, serverReady will be set to true
+ * to avoid infinite hangs.
+ */
+ void doClientSide() throws Exception {
+
+ /*
+ * Wait for server to get started.
+ */
+ while (!serverReady) {
+ Thread.sleep(50);
+ }
+
+ SSLContext context = generateSSLContext();
+ SSLSocketFactory sslsf = context.getSocketFactory();
+
+ SSLSocket sslSocket =
+ (SSLSocket)sslsf.createSocket("localhost", serverPort);
+
+ // enable the specified TLS protocol
+ sslSocket.setEnabledProtocols(new String[] {tlsProtocol});
+
+ InputStream sslIS = sslSocket.getInputStream();
+ OutputStream sslOS = sslSocket.getOutputStream();
+
+ sslOS.write('B');
+ sslOS.flush();
+ sslIS.read();
+
+ sslSocket.close();
+ }
+
+ /*
+ * =============================================================
+ * The remainder is just support stuff
+ */
+ private static String tmAlgorithm; // trust manager
+ private static String tlsProtocol; // trust manager
+
+ private static void parseArguments(String[] args) {
+ tmAlgorithm = args[0];
+ tlsProtocol = args[1];
+ }
+
+ private static SSLContext generateSSLContext() throws Exception {
+
+ // generate certificate from cert string
+ CertificateFactory cf = CertificateFactory.getInstance("X.509");
+
+ // create a key store
+ KeyStore ks = KeyStore.getInstance("JKS");
+ ks.load(null, null);
+
+ // import the trused cert
+ X509Certificate trusedCert = null;
+ ByteArrayInputStream is =
+ new ByteArrayInputStream(trustedCertStr.getBytes());
+ trusedCert = (X509Certificate)cf.generateCertificate(is);
+ is.close();
+
+ ks.setCertificateEntry("Trusted RSA Signer", trusedCert);
+
+ // generate the private key.
+ PKCS8EncodedKeySpec priKeySpec = new PKCS8EncodedKeySpec(
+ new BASE64Decoder().decodeBuffer(targetPrivateKey));
+ KeyFactory kf = KeyFactory.getInstance("RSA");
+ RSAPrivateKey priKey =
+ (RSAPrivateKey)kf.generatePrivate(priKeySpec);
+
+ // generate certificate chain
+ is = new ByteArrayInputStream(targetCertStr.getBytes());
+ X509Certificate keyCert = (X509Certificate)cf.generateCertificate(is);
+ is.close();
+
+ X509Certificate[] chain = new X509Certificate[2];
+ chain[0] = keyCert;
+ chain[1] = trusedCert;
+
+ // import the key entry and the chain
+ ks.setKeyEntry("TheKey", priKey, passphrase, chain);
+
+ // create SSL context
+ TrustManagerFactory tmf = TrustManagerFactory.getInstance(tmAlgorithm);
+ tmf.init(ks);
+
+ // create the customized KM and TM
+ NoneExtendedX509TM myTM =
+ new NoneExtendedX509TM(tmf.getTrustManagers()[0]);
+ NoneExtendedX509KM myKM =
+ new NoneExtendedX509KM("TheKey", chain, priKey);
+
+ SSLContext ctx = SSLContext.getInstance(tlsProtocol);
+ // KeyManagerFactory kmf = KeyManagerFactory.getInstance("NewSunX509");
+ // kmf.init(ks, passphrase);
+ // ctx.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null);
+ ctx.init(new KeyManager[]{myKM}, new TrustManager[]{myTM}, null);
+ ks = null;
+
+ return ctx;
+ }
+
+ static class NoneExtendedX509TM implements X509TrustManager {
+ X509TrustManager tm;
+
+ NoneExtendedX509TM(TrustManager tm) {
+ this.tm = (X509TrustManager)tm;
+ }
+
+ public void checkClientTrusted(X509Certificate chain[], String authType)
+ throws CertificateException {
+ tm.checkClientTrusted(chain, authType);
+ }
+
+ public void checkServerTrusted(X509Certificate chain[], String authType)
+ throws CertificateException {
+ tm.checkServerTrusted(chain, authType);
+ }
+
+ public X509Certificate[] getAcceptedIssuers() {
+ return tm.getAcceptedIssuers();
+ }
+ }
+
+ static class NoneExtendedX509KM implements X509KeyManager {
+ private String keyAlias;
+ private X509Certificate[] chain;
+ private PrivateKey privateKey;
+
+ NoneExtendedX509KM(String keyAlias, X509Certificate[] chain,
+ PrivateKey privateKey) {
+ this.keyAlias = keyAlias;
+ this.chain = chain;
+ this.privateKey = privateKey;
+ }
+
+ public String[] getClientAliases(String keyType, Principal[] issuers) {
+ return new String[] {keyAlias};
+ }
+
+ public String chooseClientAlias(String[] keyType, Principal[] issuers,
+ Socket socket) {
+ return keyAlias;
+ }
+
+ public String[] getServerAliases(String keyType, Principal[] issuers) {
+ return new String[] {keyAlias};
+ }
+
+ public String chooseServerAlias(String keyType, Principal[] issuers,
+ Socket socket) {
+ return keyAlias;
+ }
+
+ public X509Certificate[] getCertificateChain(String alias) {
+ return chain;
+ }
+
+ public PrivateKey getPrivateKey(String alias) {
+ return privateKey;
+ }
+ }
+
+
+ // use any free port by default
+ volatile int serverPort = 0;
+
+ volatile Exception serverException = null;
+ volatile Exception clientException = null;
+
+ public static void main(String[] args) throws Exception {
+ if (debug)
+ System.setProperty("javax.net.debug", "all");
+
+ /*
+ * Get the customized arguments.
+ */
+ parseArguments(args);
+
+ /*
+ * Start the tests.
+ */
+ new TrustTrustedCert();
+ }
+
+ Thread clientThread = null;
+ Thread serverThread = null;
+
+ /*
+ * Primary constructor, used to drive remainder of the test.
+ *
+ * Fork off the other side, then do your work.
+ */
+ TrustTrustedCert() throws Exception {
+ try {
+ if (separateServerThread) {
+ startServer(true);
+ startClient(false);
+ } else {
+ startClient(true);
+ startServer(false);
+ }
+ } catch (Exception e) {
+ // swallow for now. Show later
+ }
+
+ /*
+ * Wait for other side to close down.
+ */
+ if (separateServerThread) {
+ serverThread.join();
+ } else {
+ clientThread.join();
+ }
+
+ /*
+ * When we get here, the test is pretty much over.
+ * Which side threw the error?
+ */
+ Exception local;
+ Exception remote;
+ String whichRemote;
+
+ if (separateServerThread) {
+ remote = serverException;
+ local = clientException;
+ whichRemote = "server";
+ } else {
+ remote = clientException;
+ local = serverException;
+ whichRemote = "client";
+ }
+
+ /*
+ * If both failed, return the curthread's exception, but also
+ * print the remote side Exception
+ */
+ if ((local != null) && (remote != null)) {
+ System.out.println(whichRemote + " also threw:");
+ remote.printStackTrace();
+ System.out.println();
+ throw local;
+ }
+
+ if (remote != null) {
+ throw remote;
+ }
+
+ if (local != null) {
+ throw local;
+ }
+ }
+
+ void startServer(boolean newThread) throws Exception {
+ if (newThread) {
+ serverThread = new Thread() {
+ public void run() {
+ try {
+ doServerSide();
+ } catch (Exception e) {
+ /*
+ * Our server thread just died.
+ *
+ * Release the client, if not active already...
+ */
+ System.err.println("Server died...");
+ serverReady = true;
+ serverException = e;
+ }
+ }
+ };
+ serverThread.start();
+ } else {
+ try {
+ doServerSide();
+ } catch (Exception e) {
+ serverException = e;
+ } finally {
+ serverReady = true;
+ }
+ }
+ }
+
+ void startClient(boolean newThread) throws Exception {
+ if (newThread) {
+ clientThread = new Thread() {
+ public void run() {
+ try {
+ doClientSide();
+ } catch (Exception e) {
+ /*
+ * Our client thread just died.
+ */
+ System.err.println("Client died...");
+ clientException = e;
+ }
+ }
+ };
+ clientThread.start();
+ } else {
+ try {
+ doClientSide();
+ } catch (Exception e) {
+ clientException = e;
+ }
+ }
+ }
+}