From 1a188cf07a10acfbcbb5b9b3aef65b90dcb25906 Mon Sep 17 00:00:00 2001 From: Vivek Deshpande Date: Fri, 26 Aug 2016 12:20:09 -0700 Subject: [PATCH 01/69] 8154122: Intrinsify fused mac operations Added FMA intrinsics on x86 Reviewed-by: kvn, aph, darcy --- jdk/src/java.base/share/classes/java/lang/Math.java | 4 ++-- jdk/test/java/lang/Math/FusedMultiplyAddTests.java | 6 ++++++ 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/jdk/src/java.base/share/classes/java/lang/Math.java b/jdk/src/java.base/share/classes/java/lang/Math.java index 37a9d8573c5..911267d5956 100644 --- a/jdk/src/java.base/share/classes/java/lang/Math.java +++ b/jdk/src/java.base/share/classes/java/lang/Math.java @@ -1626,7 +1626,7 @@ public final class Math { * * @since 9 */ - // @HotSpotIntrinsicCandidate + @HotSpotIntrinsicCandidate public static double fma(double a, double b, double c) { /* * Infinity and NaN arithmetic is not quite the same with two @@ -1743,7 +1743,7 @@ public final class Math { * * @since 9 */ - // @HotSpotIntrinsicCandidate + @HotSpotIntrinsicCandidate public static float fma(float a, float b, float c) { /* * Since the double format has more than twice the precision diff --git a/jdk/test/java/lang/Math/FusedMultiplyAddTests.java b/jdk/test/java/lang/Math/FusedMultiplyAddTests.java index b8ed3ab69f3..f4cd6518db0 100644 --- a/jdk/test/java/lang/Math/FusedMultiplyAddTests.java +++ b/jdk/test/java/lang/Math/FusedMultiplyAddTests.java @@ -221,6 +221,9 @@ public class FusedMultiplyAddTests { {Double.MIN_VALUE, -0.0, +0.0, +0.0}, + + {1.0+Math.ulp(1.0), 1.0+Math.ulp(1.0), -1.0-2.0*Math.ulp(1.0), + Math.ulp(1.0)*Math.ulp(1.0)}, }; for (double[] testCase: testCases) @@ -344,6 +347,9 @@ public class FusedMultiplyAddTests { {Float.MAX_VALUE, 2.0f, 1.0f, InfinityF}, + + {1.0f+Math.ulp(1.0f), 1.0f+Math.ulp(1.0f), -1.0f-2.0f*Math.ulp(1.0f), + Math.ulp(1.0f)*Math.ulp(1.0f)}, }; for (float[] testCase: testCases) From 21f3d1ae5fec79fc4a612ce9de50f68efd6dbb9d Mon Sep 17 00:00:00 2001 From: Jini George Date: Thu, 15 Sep 2016 10:19:11 +0300 Subject: [PATCH 02/69] 8027920: SA: Add default methods to InstanceKlass Add default methods to InstanceKlass to enable SA to inspect default methods Reviewed-by: dsamersoff, iklam --- .../sun/jvm/hotspot/oops/InstanceKlass.java | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/InstanceKlass.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/InstanceKlass.java index 79ae9497496..99dbadf0e2b 100644 --- a/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/InstanceKlass.java +++ b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/InstanceKlass.java @@ -68,6 +68,7 @@ public class InstanceKlass extends Klass { Type type = db.lookupType("InstanceKlass"); arrayKlasses = new MetadataField(type.getAddressField("_array_klasses"), 0); methods = type.getAddressField("_methods"); + defaultMethods = type.getAddressField("_default_methods"); methodOrdering = type.getAddressField("_method_ordering"); localInterfaces = type.getAddressField("_local_interfaces"); transitiveInterfaces = type.getAddressField("_transitive_interfaces"); @@ -128,6 +129,7 @@ public class InstanceKlass extends Klass { private static MetadataField arrayKlasses; private static AddressField methods; + private static AddressField defaultMethods; private static AddressField methodOrdering; private static AddressField localInterfaces; private static AddressField transitiveInterfaces; @@ -335,6 +337,20 @@ public class InstanceKlass extends Klass { // Accessors for declared fields public Klass getArrayKlasses() { return (Klass) arrayKlasses.getValue(this); } public MethodArray getMethods() { return new MethodArray(methods.getValue(getAddress())); } + + public MethodArray getDefaultMethods() { + if (defaultMethods != null) { + Address addr = defaultMethods.getValue(getAddress()); + if ((addr != null) && (addr.getAddressAt(0) != null)) { + return new MethodArray(addr); + } else { + return null; + } + } else { + return null; + } + } + public KlassArray getLocalInterfaces() { return new KlassArray(localInterfaces.getValue(getAddress())); } public KlassArray getTransitiveInterfaces() { return new KlassArray(transitiveInterfaces.getValue(getAddress())); } public int getJavaFieldsCount() { return (int) javaFieldsCount.getValue(this); } From 8a329d56cf54b798ba6292a8dd07613ead707183 Mon Sep 17 00:00:00 2001 From: Alexander Kulyakhtin Date: Wed, 14 Sep 2016 16:20:54 +0300 Subject: [PATCH 03/69] 8165017: Additional test coverage of the JDWP CLASSLOADER and MODULE commands A new JDWP test Reviewed-by: sspitsyn --- .../jdwp/AllModulesCommandTest.java | 52 ++++++++++++++----- hotspot/test/serviceability/jdwp/JdwpCmd.java | 1 - .../serviceability/jdwp/JdwpModuleCmd.java | 34 ++++++++++++ .../serviceability/jdwp/JdwpModuleReply.java | 42 +++++++++++++++ .../jdwp/JdwpVisibleClassesCmd.java | 34 ++++++++++++ .../jdwp/JdwpVisibleClassesReply.java | 49 +++++++++++++++++ 6 files changed, 199 insertions(+), 13 deletions(-) create mode 100644 hotspot/test/serviceability/jdwp/JdwpModuleCmd.java create mode 100644 hotspot/test/serviceability/jdwp/JdwpModuleReply.java create mode 100644 hotspot/test/serviceability/jdwp/JdwpVisibleClassesCmd.java create mode 100644 hotspot/test/serviceability/jdwp/JdwpVisibleClassesReply.java diff --git a/hotspot/test/serviceability/jdwp/AllModulesCommandTest.java b/hotspot/test/serviceability/jdwp/AllModulesCommandTest.java index 33bb583c59d..5fed0412a03 100644 --- a/hotspot/test/serviceability/jdwp/AllModulesCommandTest.java +++ b/hotspot/test/serviceability/jdwp/AllModulesCommandTest.java @@ -30,7 +30,7 @@ import static jdk.test.lib.Asserts.assertTrue; /** * @test - * @summary Tests AllModules JDWP command + * @summary Tests the modules-related JDWP commands * @library /test/lib * @modules java.base/jdk.internal.misc * @compile AllModulesCommandTestDebuggee.java @@ -87,8 +87,12 @@ public class AllModulesCommandTest implements DebuggeeLauncher.Listener { assertReply(reply); for (int i = 0; i < reply.getModulesCount(); ++i) { long modId = reply.getModuleId(i); - // For each module reported by JDWP get its name using the JDWP NAME command - getModuleName(modId); + // For each module reported by JDWP get its name using the JDWP NAME command + // and store the reply + String modName = getModuleName(modId); + if (modName != null) { // JDWP reports unnamed modules, ignore them + jdwpModuleNames.add(modName); + } // Assert the JDWP CANREAD and CLASSLOADER commands assertCanRead(modId); assertClassLoader(modId); @@ -114,14 +118,10 @@ public class AllModulesCommandTest implements DebuggeeLauncher.Listener { } } - private void getModuleName(long modId) throws IOException { - // Send out the JDWP NAME command and store the reply + private String getModuleName(long modId) throws IOException { JdwpModNameReply reply = new JdwpModNameCmd(modId).send(channel); assertReply(reply); - String modName = reply.getModuleName(); - if (modName != null) { // JDWP reports unnamed modules, ignore them - jdwpModuleNames.add(modName); - } + return reply.getModuleName(); } private void assertReply(JdwpReply reply) { @@ -139,11 +139,39 @@ public class AllModulesCommandTest implements DebuggeeLauncher.Listener { } private void assertClassLoader(long modId) throws IOException { - // Simple assert for the CLASSLOADER command + // Verify that the module classloader id is valid JdwpClassLoaderReply reply = new JdwpClassLoaderCmd(modId).send(channel); assertReply(reply); - long clId = reply.getClassLoaderId(); - assertTrue(clId >= 0, "bad classloader refId " + clId + " for module id " + modId); + long moduleClassLoader = reply.getClassLoaderId(); + assertTrue(moduleClassLoader >= 0, "bad classloader refId " + moduleClassLoader + " for module id " + modId); + + String clsModName = getModuleName(modId); + if ("java.base".equals(clsModName)) { + // For the java.base module, because there will be some loaded classes, we can verify + // that some of the loaded classes do report the java.base module as the module they belong to + assertGetModule(moduleClassLoader, modId); + } + } + + private void assertGetModule(long moduleClassLoader, long modId) throws IOException { + // Get all the visible classes for the module classloader + JdwpVisibleClassesReply visibleClasses = new JdwpVisibleClassesCmd(moduleClassLoader).send(channel); + assertReply(visibleClasses); + + boolean moduleFound = false; + for (long clsId : visibleClasses.getVisibleClasses()) { + // For each visible class get the module the class belongs to + JdwpModuleReply modReply = new JdwpModuleCmd(clsId).send(channel); + assertReply(modReply); + long clsModId = modReply.getModuleId(); + + // At least one of the visible classes should belong to our module + if (modId == clsModId) { + moduleFound = true; + break; + } + } + assertTrue(moduleFound, "None of the visible classes for the classloader of the module " + getModuleName(modId) + " reports the module as its own"); } } diff --git a/hotspot/test/serviceability/jdwp/JdwpCmd.java b/hotspot/test/serviceability/jdwp/JdwpCmd.java index fe7f28707a8..05dbb6efb7f 100644 --- a/hotspot/test/serviceability/jdwp/JdwpCmd.java +++ b/hotspot/test/serviceability/jdwp/JdwpCmd.java @@ -70,7 +70,6 @@ public abstract class JdwpCmd { } public final T send(JdwpChannel channel) throws IOException { - System.err.println("Sending command: " + this); channel.write(data.array(), HEADER_LEN + getDataLength()); if (reply != null) { reply.initFromStream(channel.getInputStream()); diff --git a/hotspot/test/serviceability/jdwp/JdwpModuleCmd.java b/hotspot/test/serviceability/jdwp/JdwpModuleCmd.java new file mode 100644 index 00000000000..a9ed54419fa --- /dev/null +++ b/hotspot/test/serviceability/jdwp/JdwpModuleCmd.java @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/** + * The JDWP MODULE command + */ +public class JdwpModuleCmd extends JdwpCmd { + + public JdwpModuleCmd(long refId) { + super(19, 2, JdwpModuleReply.class, refLen()); + putRefId(refId); + } + +} diff --git a/hotspot/test/serviceability/jdwp/JdwpModuleReply.java b/hotspot/test/serviceability/jdwp/JdwpModuleReply.java new file mode 100644 index 00000000000..19baa7a4dde --- /dev/null +++ b/hotspot/test/serviceability/jdwp/JdwpModuleReply.java @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.io.DataInputStream; +import java.io.IOException; + +/** + * The reply to the JDWP MODULE command + */ +public class JdwpModuleReply extends JdwpReply { + + private long moduleId; + + protected void parseData(DataInputStream ds) throws IOException { + moduleId = readRefId(ds); + } + + public long getModuleId() { + return moduleId; + } + +} diff --git a/hotspot/test/serviceability/jdwp/JdwpVisibleClassesCmd.java b/hotspot/test/serviceability/jdwp/JdwpVisibleClassesCmd.java new file mode 100644 index 00000000000..daab8a11d6a --- /dev/null +++ b/hotspot/test/serviceability/jdwp/JdwpVisibleClassesCmd.java @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/** + * The JDWP VISIBLE CLASSES command + */ +public class JdwpVisibleClassesCmd extends JdwpCmd { + + public JdwpVisibleClassesCmd(long classLoaderId) { + super(1, 14, JdwpVisibleClassesReply.class, refLen()); + putRefId(classLoaderId); + } + +} diff --git a/hotspot/test/serviceability/jdwp/JdwpVisibleClassesReply.java b/hotspot/test/serviceability/jdwp/JdwpVisibleClassesReply.java new file mode 100644 index 00000000000..5381c43c51a --- /dev/null +++ b/hotspot/test/serviceability/jdwp/JdwpVisibleClassesReply.java @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.io.DataInputStream; +import java.io.IOException; +import java.util.Arrays; + +/** + * The reply to the JDWP VISIBLE CLASSES command + */ +public class JdwpVisibleClassesReply extends JdwpReply { + + private long[] visibleClasses; + + protected void parseData(DataInputStream ds) throws IOException { + int numOfClasses = ds.readInt(); + visibleClasses = new long[numOfClasses]; + for (int i = 0; i < numOfClasses; ++i) { + byte type = ds.readByte(); + long refId = readRefId(ds); + visibleClasses[i] = refId; + } + } + + public long[] getVisibleClasses() { + return Arrays.copyOf(visibleClasses, visibleClasses.length); + } + +} From 94bbcbd378380429129972f7bcd7b539bcb0a86b Mon Sep 17 00:00:00 2001 From: Thomas Schatzl Date: Thu, 15 Sep 2016 16:44:19 +0200 Subject: [PATCH 04/69] 8159422: Very high Concurrent Mark mark stack contention Decrease contention on mark stack by splitting locks, and minimizing the amount of time these locks are held. Improve mark stack management. Reviewed-by: kbarrett, mgerdin, eosterlund --- .../src/share/vm/gc/g1/g1CollectedHeap.cpp | 2 - .../src/share/vm/gc/g1/g1ConcurrentMark.cpp | 292 +++++++++++------- .../src/share/vm/gc/g1/g1ConcurrentMark.hpp | 144 +++++---- .../vm/gc/g1/g1ConcurrentMark.inline.hpp | 22 +- hotspot/src/share/vm/gc/g1/g1OopClosures.hpp | 1 - hotspot/src/share/vm/memory/allocation.hpp | 1 + .../src/share/vm/memory/allocation.inline.hpp | 18 ++ hotspot/src/share/vm/runtime/mutexLocker.cpp | 5 + hotspot/src/share/vm/runtime/mutexLocker.hpp | 3 +- 9 files changed, 310 insertions(+), 178 deletions(-) diff --git a/hotspot/src/share/vm/gc/g1/g1CollectedHeap.cpp b/hotspot/src/share/vm/gc/g1/g1CollectedHeap.cpp index 4543ee3e021..935d935b13f 100644 --- a/hotspot/src/share/vm/gc/g1/g1CollectedHeap.cpp +++ b/hotspot/src/share/vm/gc/g1/g1CollectedHeap.cpp @@ -3165,7 +3165,6 @@ G1CollectedHeap::do_collection_pause_at_safepoint(double target_pause_time_ms) { assert(_verifier->check_cset_fast_test(), "Inconsistency in the InCSetState table."); - _cm->note_start_of_gc(); // We call this after finalize_cset() to // ensure that the CSet has been finalized. _cm->verify_no_cset_oops(); @@ -3251,7 +3250,6 @@ G1CollectedHeap::do_collection_pause_at_safepoint(double target_pause_time_ms) { // We redo the verification but now wrt to the new CSet which // has just got initialized after the previous CSet was freed. _cm->verify_no_cset_oops(); - _cm->note_end_of_gc(); // This timing is only used by the ergonomics to handle our pause target. // It is unclear why this should not include the full pause. We will diff --git a/hotspot/src/share/vm/gc/g1/g1ConcurrentMark.cpp b/hotspot/src/share/vm/gc/g1/g1ConcurrentMark.cpp index 9084f46c3be..43b227a7ef8 100644 --- a/hotspot/src/share/vm/gc/g1/g1ConcurrentMark.cpp +++ b/hotspot/src/share/vm/gc/g1/g1ConcurrentMark.cpp @@ -133,129 +133,184 @@ void G1CMBitMap::clear_range(MemRegion mr) { } G1CMMarkStack::G1CMMarkStack() : - _reserved_space(), + _max_chunk_capacity(0), _base(NULL), - _capacity(0), - _saved_index((size_t)AllBits), + _chunk_capacity(0), + _out_of_memory(false), _should_expand(false) { set_empty(); } bool G1CMMarkStack::resize(size_t new_capacity) { assert(is_empty(), "Only resize when stack is empty."); - assert(new_capacity <= MarkStackSizeMax, - "Trying to resize stack to " SIZE_FORMAT " elements when the maximum is " SIZE_FORMAT, new_capacity, MarkStackSizeMax); + assert(new_capacity <= _max_chunk_capacity, + "Trying to resize stack to " SIZE_FORMAT " chunks when the maximum is " SIZE_FORMAT, new_capacity, _max_chunk_capacity); - size_t reservation_size = ReservedSpace::allocation_align_size_up(new_capacity * sizeof(oop)); + OopChunk* new_base = MmapArrayAllocator::allocate_or_null(new_capacity); - ReservedSpace rs(reservation_size); - if (!rs.is_reserved()) { - log_warning(gc)("Failed to reserve memory for new overflow mark stack with " SIZE_FORMAT " elements and size " SIZE_FORMAT "B.", new_capacity, reservation_size); + if (new_base == NULL) { + log_warning(gc)("Failed to reserve memory for new overflow mark stack with " SIZE_FORMAT " chunks and size " SIZE_FORMAT "B.", new_capacity, new_capacity * sizeof(OopChunk)); return false; } - - VirtualSpace vs; - - if (!vs.initialize(rs, rs.size())) { - rs.release(); - log_warning(gc)("Failed to commit memory for new overflow mark stack of size " SIZE_FORMAT "B.", rs.size()); - return false; - } - - assert(vs.committed_size() == rs.size(), "Failed to commit all of the mark stack."); - // Release old mapping. - _reserved_space.release(); + if (_base != NULL) { + MmapArrayAllocator::free(_base, _chunk_capacity); + } - // Save new mapping for future unmapping. - _reserved_space = rs; - - MemTracker::record_virtual_memory_type((address)_reserved_space.base(), mtGC); - - _base = (oop*) vs.low(); - _capacity = new_capacity; + _base = new_base; + _chunk_capacity = new_capacity; set_empty(); _should_expand = false; return true; } -bool G1CMMarkStack::allocate(size_t capacity) { - return resize(capacity); +size_t G1CMMarkStack::capacity_alignment() { + return (size_t)lcm(os::vm_allocation_granularity(), sizeof(OopChunk)) / sizeof(void*); +} + +bool G1CMMarkStack::initialize(size_t initial_capacity, size_t max_capacity) { + guarantee(_max_chunk_capacity == 0, "G1CMMarkStack already initialized."); + + size_t const OopChunkSizeInVoidStar = sizeof(OopChunk) / sizeof(void*); + + _max_chunk_capacity = (size_t)align_size_up(max_capacity, capacity_alignment()) / OopChunkSizeInVoidStar; + size_t initial_chunk_capacity = (size_t)align_size_up(initial_capacity, capacity_alignment()) / OopChunkSizeInVoidStar; + + guarantee(initial_chunk_capacity <= _max_chunk_capacity, + "Maximum chunk capacity " SIZE_FORMAT " smaller than initial capacity " SIZE_FORMAT, + _max_chunk_capacity, + initial_chunk_capacity); + + log_debug(gc)("Initialize mark stack with " SIZE_FORMAT " chunks, maximum " SIZE_FORMAT, + initial_chunk_capacity, _max_chunk_capacity); + + return resize(initial_chunk_capacity); } void G1CMMarkStack::expand() { // Clear expansion flag _should_expand = false; - if (_capacity == MarkStackSizeMax) { - log_debug(gc)("Can not expand overflow mark stack further, already at maximum capacity of " SIZE_FORMAT " elements.", _capacity); + if (_chunk_capacity == _max_chunk_capacity) { + log_debug(gc)("Can not expand overflow mark stack further, already at maximum capacity of " SIZE_FORMAT " chunks.", _chunk_capacity); return; } - size_t old_capacity = _capacity; + size_t old_capacity = _chunk_capacity; // Double capacity if possible - size_t new_capacity = MIN2(old_capacity * 2, MarkStackSizeMax); + size_t new_capacity = MIN2(old_capacity * 2, _max_chunk_capacity); if (resize(new_capacity)) { - log_debug(gc)("Expanded marking stack capacity from " SIZE_FORMAT " to " SIZE_FORMAT " elements", + log_debug(gc)("Expanded mark stack capacity from " SIZE_FORMAT " to " SIZE_FORMAT " chunks", old_capacity, new_capacity); } else { - log_warning(gc)("Failed to expand marking stack capacity from " SIZE_FORMAT " to " SIZE_FORMAT " elements", + log_warning(gc)("Failed to expand mark stack capacity from " SIZE_FORMAT " to " SIZE_FORMAT " chunks", old_capacity, new_capacity); } } G1CMMarkStack::~G1CMMarkStack() { if (_base != NULL) { - _base = NULL; - _reserved_space.release(); + MmapArrayAllocator::free(_base, _chunk_capacity); } } -void G1CMMarkStack::par_push_arr(oop* buffer, size_t n) { - MutexLockerEx x(ParGCRareEvent_lock, Mutex::_no_safepoint_check_flag); - size_t start = _index; - size_t next_index = start + n; - if (next_index > _capacity) { - _overflow = true; - return; - } - // Otherwise. - _index = next_index; - for (size_t i = 0; i < n; i++) { - size_t ind = start + i; - assert(ind < _capacity, "By overflow test above."); - _base[ind] = buffer[i]; - } +void G1CMMarkStack::add_chunk_to_list(OopChunk* volatile* list, OopChunk* elem) { + elem->next = *list; + *list = elem; } -bool G1CMMarkStack::par_pop_arr(oop* buffer, size_t max, size_t* n) { - MutexLockerEx x(ParGCRareEvent_lock, Mutex::_no_safepoint_check_flag); - size_t index = _index; - if (index == 0) { - *n = 0; +void G1CMMarkStack::add_chunk_to_chunk_list(OopChunk* elem) { + MutexLockerEx x(MarkStackChunkList_lock, Mutex::_no_safepoint_check_flag); + add_chunk_to_list(&_chunk_list, elem); + _chunks_in_chunk_list++; +} + +void G1CMMarkStack::add_chunk_to_free_list(OopChunk* elem) { + MutexLockerEx x(MarkStackFreeList_lock, Mutex::_no_safepoint_check_flag); + add_chunk_to_list(&_free_list, elem); +} + +G1CMMarkStack::OopChunk* G1CMMarkStack::remove_chunk_from_list(OopChunk* volatile* list) { + OopChunk* result = *list; + if (result != NULL) { + *list = (*list)->next; + } + return result; +} + +G1CMMarkStack::OopChunk* G1CMMarkStack::remove_chunk_from_chunk_list() { + MutexLockerEx x(MarkStackChunkList_lock, Mutex::_no_safepoint_check_flag); + OopChunk* result = remove_chunk_from_list(&_chunk_list); + if (result != NULL) { + _chunks_in_chunk_list--; + } + return result; +} + +G1CMMarkStack::OopChunk* G1CMMarkStack::remove_chunk_from_free_list() { + MutexLockerEx x(MarkStackFreeList_lock, Mutex::_no_safepoint_check_flag); + return remove_chunk_from_list(&_free_list); +} + +G1CMMarkStack::OopChunk* G1CMMarkStack::allocate_new_chunk() { + // This dirty read of _hwm is okay because we only ever increase the _hwm in parallel code. + // Further this limits _hwm to a value of _chunk_capacity + #threads, avoiding + // wraparound of _hwm. + if (_hwm >= _chunk_capacity) { + return NULL; + } + + size_t cur_idx = Atomic::add(1, &_hwm) - 1; + if (cur_idx >= _chunk_capacity) { + return NULL; + } + + OopChunk* result = ::new (&_base[cur_idx]) OopChunk; + result->next = NULL; + return result; +} + +bool G1CMMarkStack::par_push_chunk(oop* ptr_arr) { + // Get a new chunk. + OopChunk* new_chunk = remove_chunk_from_free_list(); + + if (new_chunk == NULL) { + // Did not get a chunk from the free list. Allocate from backing memory. + new_chunk = allocate_new_chunk(); + } + + if (new_chunk == NULL) { + _out_of_memory = true; return false; - } else { - size_t k = MIN2(max, index); - size_t new_ind = index - k; - for (size_t j = 0; j < k; j++) { - buffer[j] = _base[new_ind + j]; - } - _index = new_ind; - *n = k; - return true; } + + Copy::conjoint_oops_atomic(ptr_arr, new_chunk->data, OopsPerChunk); + + add_chunk_to_chunk_list(new_chunk); + + return true; } -void G1CMMarkStack::note_start_of_gc() { - assert(_saved_index == (size_t)AllBits, "note_start_of_gc()/end_of_gc() calls bracketed incorrectly"); - _saved_index = _index; +bool G1CMMarkStack::par_pop_chunk(oop* ptr_arr) { + OopChunk* cur = remove_chunk_from_chunk_list(); + + if (cur == NULL) { + return false; + } + + Copy::conjoint_oops_atomic(cur->data, ptr_arr, OopsPerChunk); + + add_chunk_to_free_list(cur); + return true; } -void G1CMMarkStack::note_end_of_gc() { - guarantee(!stack_modified(), "Saved index " SIZE_FORMAT " must be the same as " SIZE_FORMAT, _saved_index, _index); - - _saved_index = (size_t)AllBits; +void G1CMMarkStack::set_empty() { + _chunks_in_chunk_list = 0; + _hwm = 0; + clear_out_of_memory(); + _chunk_list = NULL; + _free_list = NULL; } G1CMRootRegions::G1CMRootRegions() : @@ -483,9 +538,8 @@ G1ConcurrentMark::G1ConcurrentMark(G1CollectedHeap* g1h, G1RegionToSpaceMapper* } } - if (!_global_mark_stack.allocate(MarkStackSize)) { + if (!_global_mark_stack.initialize(MarkStackSize, MarkStackSizeMax)) { vm_exit_during_initialization("Failed to allocate initial concurrent mark overflow mark stack."); - return; } _tasks = NEW_C_HEAP_ARRAY(G1CMTask*, _max_worker_id, mtGC); @@ -1695,10 +1749,10 @@ void G1ConcurrentMark::weakRefsWork(bool clear_all_soft_refs) { // oop closures will set the has_overflown flag if we overflow the // global marking stack. - assert(_global_mark_stack.overflow() || _global_mark_stack.is_empty(), - "mark stack should be empty (unless it overflowed)"); + assert(_global_mark_stack.is_out_of_memory() || _global_mark_stack.is_empty(), + "Mark stack should be empty (unless it is out of memory)"); - if (_global_mark_stack.overflow()) { + if (_global_mark_stack.is_out_of_memory()) { // This should have been done already when we tried to push an // entry on to the global mark stack. But let's do it again. set_has_overflown(); @@ -2343,49 +2397,54 @@ void G1CMTask::decrease_limits() { } void G1CMTask::move_entries_to_global_stack() { - // local array where we'll store the entries that will be popped - // from the local queue - oop buffer[global_stack_transfer_size]; + // Local array where we'll store the entries that will be popped + // from the local queue. + oop buffer[G1CMMarkStack::OopsPerChunk]; - int n = 0; + size_t n = 0; oop obj; - while (n < global_stack_transfer_size && _task_queue->pop_local(obj)) { + while (n < G1CMMarkStack::OopsPerChunk && _task_queue->pop_local(obj)) { buffer[n] = obj; ++n; } + if (n < G1CMMarkStack::OopsPerChunk) { + buffer[n] = NULL; + } if (n > 0) { - // we popped at least one entry from the local queue - - if (!_cm->mark_stack_push(buffer, n)) { + if (!_cm->mark_stack_push(buffer)) { set_has_aborted(); } } - // this operation was quite expensive, so decrease the limits + // This operation was quite expensive, so decrease the limits. decrease_limits(); } -void G1CMTask::get_entries_from_global_stack() { - // local array where we'll store the entries that will be popped +bool G1CMTask::get_entries_from_global_stack() { + // Local array where we'll store the entries that will be popped // from the global stack. - oop buffer[global_stack_transfer_size]; - size_t n; - _cm->mark_stack_pop(buffer, global_stack_transfer_size, &n); - assert(n <= global_stack_transfer_size, - "we should not pop more than the given limit"); - if (n > 0) { - // yes, we did actually pop at least one entry - for (size_t i = 0; i < n; ++i) { - bool success = _task_queue->push(buffer[i]); - // We only call this when the local queue is empty or under a - // given target limit. So, we do not expect this push to fail. - assert(success, "invariant"); - } + oop buffer[G1CMMarkStack::OopsPerChunk]; + + if (!_cm->mark_stack_pop(buffer)) { + return false; } - // this operation was quite expensive, so decrease the limits + // We did actually pop at least one entry. + for (size_t i = 0; i < G1CMMarkStack::OopsPerChunk; ++i) { + oop elem = buffer[i]; + if (elem == NULL) { + break; + } + bool success = _task_queue->push(elem); + // We only call this when the local queue is empty or under a + // given target limit. So, we do not expect this push to fail. + assert(success, "invariant"); + } + + // This operation was quite expensive, so decrease the limits decrease_limits(); + return true; } void G1CMTask::drain_local_queue(bool partially) { @@ -2429,20 +2488,21 @@ void G1CMTask::drain_global_stack(bool partially) { // Decide what the target size is, depending whether we're going to // drain it partially (so that other tasks can steal if they run out - // of things to do) or totally (at the very end). Notice that, - // because we move entries from the global stack in chunks or - // because another task might be doing the same, we might in fact - // drop below the target. But, this is not a problem. - size_t target_size; + // of things to do) or totally (at the very end). + // Notice that when draining the global mark stack partially, due to the racyness + // of the mark stack size update we might in fact drop below the target. But, + // this is not a problem. + // In case of total draining, we simply process until the global mark stack is + // totally empty, disregarding the size counter. if (partially) { - target_size = _cm->partial_mark_stack_size_target(); - } else { - target_size = 0; - } - - if (_cm->mark_stack_size() > target_size) { + size_t const target_size = _cm->partial_mark_stack_size_target(); while (!has_aborted() && _cm->mark_stack_size() > target_size) { - get_entries_from_global_stack(); + if (get_entries_from_global_stack()) { + drain_local_queue(partially); + } + } + } else { + while (!has_aborted() && get_entries_from_global_stack()) { drain_local_queue(partially); } } diff --git a/hotspot/src/share/vm/gc/g1/g1ConcurrentMark.hpp b/hotspot/src/share/vm/gc/g1/g1ConcurrentMark.hpp index 0331976a4a6..68cc2b42bb8 100644 --- a/hotspot/src/share/vm/gc/g1/g1ConcurrentMark.hpp +++ b/hotspot/src/share/vm/gc/g1/g1ConcurrentMark.hpp @@ -149,42 +149,98 @@ class G1CMBitMap : public G1CMBitMapRO { // // Stores oops in a huge buffer in virtual memory that is always fully committed. // Resizing may only happen during a STW pause when the stack is empty. +// +// Memory is allocated on a "chunk" basis, i.e. a set of oops. For this, the mark +// stack memory is split into evenly sized chunks of oops. Users can only +// add or remove entries on that basis. +// Chunks are filled in increasing address order. Not completely filled chunks +// have a NULL element as a terminating element. +// +// Every chunk has a header containing a single pointer element used for memory +// management. This wastes some space, but is negligible (< .1% with current sizing). +// +// Memory management is done using a mix of tracking a high water-mark indicating +// that all chunks at a lower address are valid chunks, and a singly linked free +// list connecting all empty chunks. class G1CMMarkStack VALUE_OBJ_CLASS_SPEC { - ReservedSpace _reserved_space; // Space currently reserved for the mark stack. +public: + // Number of oops that can fit in a single chunk. + static const size_t OopsPerChunk = 1024 - 1 /* One reference for the next pointer */; +private: + struct OopChunk { + OopChunk* next; + oop data[OopsPerChunk]; + }; - oop* _base; // Bottom address of allocated memory area. - size_t _capacity; // Maximum number of elements. - size_t _index; // One more than last occupied index. + size_t _max_chunk_capacity; // Maximum number of OopChunk elements on the stack. - size_t _saved_index; // Value of _index saved at start of GC to detect mark stack modifications during that time. + OopChunk* _base; // Bottom address of allocated memory area. + size_t _chunk_capacity; // Current maximum number of OopChunk elements. + + char _pad0[DEFAULT_CACHE_LINE_SIZE]; + OopChunk* volatile _free_list; // Linked list of free chunks that can be allocated by users. + char _pad1[DEFAULT_CACHE_LINE_SIZE - sizeof(OopChunk*)]; + OopChunk* volatile _chunk_list; // List of chunks currently containing data. + volatile size_t _chunks_in_chunk_list; + char _pad2[DEFAULT_CACHE_LINE_SIZE - sizeof(OopChunk*) - sizeof(size_t)]; + + volatile size_t _hwm; // High water mark within the reserved space. + char _pad4[DEFAULT_CACHE_LINE_SIZE - sizeof(size_t)]; + + // Allocate a new chunk from the reserved memory, using the high water mark. Returns + // NULL if out of memory. + OopChunk* allocate_new_chunk(); + + volatile bool _out_of_memory; + + // Atomically add the given chunk to the list. + void add_chunk_to_list(OopChunk* volatile* list, OopChunk* elem); + // Atomically remove and return a chunk from the given list. Returns NULL if the + // list is empty. + OopChunk* remove_chunk_from_list(OopChunk* volatile* list); + + void add_chunk_to_chunk_list(OopChunk* elem); + void add_chunk_to_free_list(OopChunk* elem); + + OopChunk* remove_chunk_from_chunk_list(); + OopChunk* remove_chunk_from_free_list(); - bool _overflow; bool _should_expand; // Resizes the mark stack to the given new capacity. Releases any previous // memory if successful. bool resize(size_t new_capacity); - bool stack_modified() const { return _index != _saved_index; } public: G1CMMarkStack(); ~G1CMMarkStack(); - bool allocate(size_t capacity); + // Alignment and minimum capacity of this mark stack in number of oops. + static size_t capacity_alignment(); - // Pushes the first "n" elements of the given buffer on the stack. - void par_push_arr(oop* buffer, size_t n); + // Allocate and initialize the mark stack with the given number of oops. + bool initialize(size_t initial_capacity, size_t max_capacity); - // Moves up to max elements from the stack into the given buffer. Returns - // the number of elements pushed, and false if the array has been empty. - // Returns true if the buffer contains at least one element. - bool par_pop_arr(oop* buffer, size_t max, size_t* n); + // Pushes the given buffer containing at most OopsPerChunk elements on the mark + // stack. If less than OopsPerChunk elements are to be pushed, the array must + // be terminated with a NULL. + // Returns whether the buffer contents were successfully pushed to the global mark + // stack. + bool par_push_chunk(oop* buffer); - bool is_empty() const { return _index == 0; } - size_t capacity() const { return _capacity; } + // Pops a chunk from this mark stack, copying them into the given buffer. This + // chunk may contain up to OopsPerChunk elements. If there are less, the last + // element in the array is a NULL pointer. + bool par_pop_chunk(oop* buffer); - bool overflow() const { return _overflow; } - void clear_overflow() { _overflow = false; } + // Return whether the chunk list is empty. Racy due to unsynchronized access to + // _chunk_list. + bool is_empty() const { return _chunk_list == NULL; } + + size_t capacity() const { return _chunk_capacity; } + + bool is_out_of_memory() const { return _out_of_memory; } + void clear_out_of_memory() { _out_of_memory = false; } bool should_expand() const { return _should_expand; } void set_should_expand(bool value) { _should_expand = value; } @@ -192,20 +248,15 @@ class G1CMMarkStack VALUE_OBJ_CLASS_SPEC { // Expand the stack, typically in response to an overflow condition void expand(); - size_t size() const { return _index; } + // Return the approximate number of oops on this mark stack. Racy due to + // unsynchronized access to _chunks_in_chunk_list. + size_t size() const { return _chunks_in_chunk_list * OopsPerChunk; } - void set_empty() { _index = 0; clear_overflow(); } + void set_empty(); - // Record the current index. - void note_start_of_gc(); - - // Make sure that we have not added any entries to the stack during GC. - void note_end_of_gc(); - - // Apply fn to each oop in the mark stack, up to the bound recorded - // via one of the above "note" functions. The mark stack must not + // Apply Fn to every oop on the mark stack. The mark stack must not // be modified while iterating. - template void iterate(Fn fn); + template void iterate(Fn fn) const PRODUCT_RETURN; }; // Root Regions are regions that are not empty at the beginning of a @@ -278,7 +329,6 @@ class G1ConcurrentMark: public CHeapObj { friend class G1CMDrainMarkingStackClosure; friend class G1CMBitMapClosure; friend class G1CMConcurrentMarkingTask; - friend class G1CMMarkStack; friend class G1CMRemarkTask; friend class G1CMTask; @@ -479,22 +529,20 @@ protected: public: // Manipulation of the global mark stack. // The push and pop operations are used by tasks for transfers - // between task-local queues and the global mark stack, and use - // locking for concurrency safety. - bool mark_stack_push(oop* arr, size_t n) { - _global_mark_stack.par_push_arr(arr, n); - if (_global_mark_stack.overflow()) { + // between task-local queues and the global mark stack. + bool mark_stack_push(oop* arr) { + if (!_global_mark_stack.par_push_chunk(arr)) { set_has_overflown(); return false; } return true; } - void mark_stack_pop(oop* arr, size_t max, size_t* n) { - _global_mark_stack.par_pop_arr(arr, max, n); + bool mark_stack_pop(oop* arr) { + return _global_mark_stack.par_pop_chunk(arr); } size_t mark_stack_size() { return _global_mark_stack.size(); } size_t partial_mark_stack_size_target() { return _global_mark_stack.capacity()/3; } - bool mark_stack_overflow() { return _global_mark_stack.overflow(); } + bool mark_stack_overflow() { return _global_mark_stack.is_out_of_memory(); } bool mark_stack_empty() { return _global_mark_stack.is_empty(); } G1CMRootRegions* root_regions() { return &_root_regions; } @@ -599,16 +647,6 @@ public: // read-only, so use this carefully! void clearRangePrevBitmap(MemRegion mr); - // Notify data structures that a GC has started. - void note_start_of_gc() { - _global_mark_stack.note_start_of_gc(); - } - - // Notify data structures that a GC is finished. - void note_end_of_gc() { - _global_mark_stack.note_end_of_gc(); - } - // Verify that there are no CSet oops on the stacks (taskqueues / // global mark stack) and fingers (global / per-task). // If marking is not in progress, it's a no-op. @@ -670,10 +708,7 @@ private: // references reaches this limit refs_reached_period = 384, // Initial value for the hash seed, used in the work stealing code - init_hash_seed = 17, - // How many entries will be transferred between global stack and - // local queues at once. - global_stack_transfer_size = 1024 + init_hash_seed = 17 }; uint _worker_id; @@ -858,9 +893,10 @@ public: // It pushes an object on the local queue. inline void push(oop obj); - // These two move entries to/from the global stack. + // Move entries to the global stack. void move_entries_to_global_stack(); - void get_entries_from_global_stack(); + // Move entries from the global stack, return true if we were successful to do so. + bool get_entries_from_global_stack(); // It pops and scans objects from the local queue. If partially is // true, then it stops when the queue size is of a given limit. If diff --git a/hotspot/src/share/vm/gc/g1/g1ConcurrentMark.inline.hpp b/hotspot/src/share/vm/gc/g1/g1ConcurrentMark.inline.hpp index 40336ae6885..af42c85920c 100644 --- a/hotspot/src/share/vm/gc/g1/g1ConcurrentMark.inline.hpp +++ b/hotspot/src/share/vm/gc/g1/g1ConcurrentMark.inline.hpp @@ -89,14 +89,28 @@ inline bool G1CMBitMap::parMark(HeapWord* addr) { #undef check_mark +#ifndef PRODUCT template -inline void G1CMMarkStack::iterate(Fn fn) { +inline void G1CMMarkStack::iterate(Fn fn) const { assert_at_safepoint(true); - assert(!stack_modified(), "Saved index " SIZE_FORMAT " must be the same as " SIZE_FORMAT, _saved_index, _index); - for (size_t i = 0; i < _index; ++i) { - fn(_base[i]); + + size_t num_chunks = 0; + + OopChunk* cur = _chunk_list; + while (cur != NULL) { + guarantee(num_chunks <= _chunks_in_chunk_list, "Found " SIZE_FORMAT " oop chunks which is more than there should be", num_chunks); + + for (size_t i = 0; i < OopsPerChunk; ++i) { + if (cur->data[i] == NULL) { + break; + } + fn(cur->data[i]); + } + cur = cur->next; + num_chunks++; } } +#endif // It scans an object and visits its children. inline void G1CMTask::scan_object(oop obj) { process_grey_object(obj); } diff --git a/hotspot/src/share/vm/gc/g1/g1OopClosures.hpp b/hotspot/src/share/vm/gc/g1/g1OopClosures.hpp index 5de38f71bd2..bc594ed86e9 100644 --- a/hotspot/src/share/vm/gc/g1/g1OopClosures.hpp +++ b/hotspot/src/share/vm/gc/g1/g1OopClosures.hpp @@ -34,7 +34,6 @@ class G1RemSet; class G1ConcurrentMark; class DirtyCardToOopClosure; class G1CMBitMap; -class G1CMMarkStack; class G1ParScanThreadState; class G1CMTask; class ReferenceProcessor; diff --git a/hotspot/src/share/vm/memory/allocation.hpp b/hotspot/src/share/vm/memory/allocation.hpp index 5d9e7c830f6..c9a5f28405c 100644 --- a/hotspot/src/share/vm/memory/allocation.hpp +++ b/hotspot/src/share/vm/memory/allocation.hpp @@ -738,6 +738,7 @@ class MmapArrayAllocator : public AllStatic { static size_t size_for(size_t length); public: + static E* allocate_or_null(size_t length); static E* allocate(size_t length); static void free(E* addr, size_t length); }; diff --git a/hotspot/src/share/vm/memory/allocation.inline.hpp b/hotspot/src/share/vm/memory/allocation.inline.hpp index db09c0cfb0e..f1035490163 100644 --- a/hotspot/src/share/vm/memory/allocation.inline.hpp +++ b/hotspot/src/share/vm/memory/allocation.inline.hpp @@ -152,6 +152,24 @@ size_t MmapArrayAllocator::size_for(size_t length) { return align_size_up(size, alignment); } +template +E* MmapArrayAllocator::allocate_or_null(size_t length) { + size_t size = size_for(length); + int alignment = os::vm_allocation_granularity(); + + char* addr = os::reserve_memory(size, NULL, alignment, F); + if (addr == NULL) { + return NULL; + } + + if (os::commit_memory(addr, size, !ExecMem, "Allocator (commit)")) { + return (E*)addr; + } else { + os::release_memory(addr, size); + return NULL; + } +} + template E* MmapArrayAllocator::allocate(size_t length) { size_t size = size_for(length); diff --git a/hotspot/src/share/vm/runtime/mutexLocker.cpp b/hotspot/src/share/vm/runtime/mutexLocker.cpp index a01b4888500..88f5ab04457 100644 --- a/hotspot/src/share/vm/runtime/mutexLocker.cpp +++ b/hotspot/src/share/vm/runtime/mutexLocker.cpp @@ -77,6 +77,8 @@ Mutex* Shared_SATB_Q_lock = NULL; Mutex* DirtyCardQ_FL_lock = NULL; Monitor* DirtyCardQ_CBL_mon = NULL; Mutex* Shared_DirtyCardQ_lock = NULL; +Mutex* MarkStackFreeList_lock = NULL; +Mutex* MarkStackChunkList_lock = NULL; Mutex* ParGCRareEvent_lock = NULL; Mutex* DerivedPointerTableGC_lock = NULL; Mutex* Compile_lock = NULL; @@ -194,6 +196,9 @@ void mutex_init() { def(StringDedupQueue_lock , Monitor, leaf, true, Monitor::_safepoint_check_never); def(StringDedupTable_lock , Mutex , leaf, true, Monitor::_safepoint_check_never); + + def(MarkStackFreeList_lock , Mutex , leaf , true, Monitor::_safepoint_check_never); + def(MarkStackChunkList_lock , Mutex , leaf , true, Monitor::_safepoint_check_never); } def(ParGCRareEvent_lock , Mutex , leaf , true, Monitor::_safepoint_check_sometimes); def(DerivedPointerTableGC_lock , Mutex, leaf, true, Monitor::_safepoint_check_never); diff --git a/hotspot/src/share/vm/runtime/mutexLocker.hpp b/hotspot/src/share/vm/runtime/mutexLocker.hpp index ae4c79954ea..c0db4e9f4e6 100644 --- a/hotspot/src/share/vm/runtime/mutexLocker.hpp +++ b/hotspot/src/share/vm/runtime/mutexLocker.hpp @@ -81,7 +81,8 @@ extern Monitor* DirtyCardQ_CBL_mon; // Protects dirty card Q extern Mutex* Shared_DirtyCardQ_lock; // Lock protecting dirty card // queue shared by // non-Java threads. - // (see option ExplicitGCInvokesConcurrent) +extern Mutex* MarkStackFreeList_lock; // Protects access to the global mark stack free list. +extern Mutex* MarkStackChunkList_lock; // Protects access to the global mark stack chunk list. extern Mutex* ParGCRareEvent_lock; // Synchronizes various (rare) parallel GC ops. extern Mutex* Compile_lock; // a lock held when Compilation is updating code (used to block CodeCache traversal, CHA updates, etc) extern Monitor* MethodCompileQueue_lock; // a lock held when method compilations are enqueued, dequeued From b77d0de3d9509cfbc852f0bb590241ee1b90e020 Mon Sep 17 00:00:00 2001 From: Kim Barrett Date: Thu, 15 Sep 2016 12:10:43 -0400 Subject: [PATCH 05/69] 8165808: Add release barriers when allocating objects with concurrent collection Add release_set_klass, use in slow-path allocators. Reviewed-by: jmasa, dholmes --- .../src/share/vm/gc/shared/collectedHeap.hpp | 3 - .../vm/gc/shared/collectedHeap.inline.hpp | 65 +++++++++---------- hotspot/src/share/vm/oops/oop.hpp | 1 + hotspot/src/share/vm/oops/oop.inline.hpp | 22 ++++++- 4 files changed, 51 insertions(+), 40 deletions(-) diff --git a/hotspot/src/share/vm/gc/shared/collectedHeap.hpp b/hotspot/src/share/vm/gc/shared/collectedHeap.hpp index af26fc892e9..d5ae7733114 100644 --- a/hotspot/src/share/vm/gc/shared/collectedHeap.hpp +++ b/hotspot/src/share/vm/gc/shared/collectedHeap.hpp @@ -304,9 +304,6 @@ class CollectedHeap : public CHeapObj { inline static oop array_allocate_nozero(KlassHandle klass, int size, int length, TRAPS); inline static oop class_allocate(KlassHandle klass, int size, TRAPS); - inline static void post_allocation_install_obj_klass(KlassHandle klass, - oop obj); - // Raw memory allocation facilities // The obj and array allocate methods are covers for these methods. // mem_allocate() should never be diff --git a/hotspot/src/share/vm/gc/shared/collectedHeap.inline.hpp b/hotspot/src/share/vm/gc/shared/collectedHeap.inline.hpp index 36ef86f98c9..cd54e1fdc5b 100644 --- a/hotspot/src/share/vm/gc/shared/collectedHeap.inline.hpp +++ b/hotspot/src/share/vm/gc/shared/collectedHeap.inline.hpp @@ -41,14 +41,22 @@ // Inline allocation implementations. void CollectedHeap::post_allocation_setup_common(KlassHandle klass, - HeapWord* obj) { - post_allocation_setup_no_klass_install(klass, obj); - post_allocation_install_obj_klass(klass, oop(obj)); + HeapWord* obj_ptr) { + post_allocation_setup_no_klass_install(klass, obj_ptr); + oop obj = (oop)obj_ptr; +#if ! INCLUDE_ALL_GCS + obj->set_klass(klass()); +#else + // Need a release store to ensure array/class length, mark word, and + // object zeroing are visible before setting the klass non-NULL, for + // concurrent collectors. + obj->release_set_klass(klass()); +#endif } void CollectedHeap::post_allocation_setup_no_klass_install(KlassHandle klass, - HeapWord* objPtr) { - oop obj = (oop)objPtr; + HeapWord* obj_ptr) { + oop obj = (oop)obj_ptr; assert(obj != NULL, "NULL object pointer"); if (UseBiasedLocking && (klass() != NULL)) { @@ -59,18 +67,6 @@ void CollectedHeap::post_allocation_setup_no_klass_install(KlassHandle klass, } } -void CollectedHeap::post_allocation_install_obj_klass(KlassHandle klass, - oop obj) { - // These asserts are kind of complicated because of klassKlass - // and the beginning of the world. - assert(klass() != NULL || !Universe::is_fully_initialized(), "NULL klass"); - assert(klass() == NULL || klass()->is_klass(), "not a klass"); - assert(obj != NULL, "NULL object pointer"); - obj->set_klass(klass()); - assert(!Universe::is_fully_initialized() || obj->klass() != NULL, - "missing klass"); -} - // Support for jvmti and dtrace inline void post_allocation_notify(KlassHandle klass, oop obj, int size) { // support low memory notifications (no-op if not enabled) @@ -88,25 +84,26 @@ inline void post_allocation_notify(KlassHandle klass, oop obj, int size) { } void CollectedHeap::post_allocation_setup_obj(KlassHandle klass, - HeapWord* obj, + HeapWord* obj_ptr, int size) { - post_allocation_setup_common(klass, obj); + post_allocation_setup_common(klass, obj_ptr); + oop obj = (oop)obj_ptr; assert(Universe::is_bootstrapping() || - !((oop)obj)->is_array(), "must not be an array"); + !obj->is_array(), "must not be an array"); // notify jvmti and dtrace - post_allocation_notify(klass, (oop)obj, size); + post_allocation_notify(klass, obj, size); } void CollectedHeap::post_allocation_setup_class(KlassHandle klass, - HeapWord* obj, + HeapWord* obj_ptr, int size) { - // Set oop_size field before setting the _klass field - // in post_allocation_setup_common() because the klass field - // indicates that the object is parsable by concurrent GC. - oop new_cls = (oop)obj; + // Set oop_size field before setting the _klass field because a + // non-NULL _klass field indicates that the object is parsable by + // concurrent GC. + oop new_cls = (oop)obj_ptr; assert(size > 0, "oop_size must be positive."); java_lang_Class::set_oop_size(new_cls, size); - post_allocation_setup_common(klass, obj); + post_allocation_setup_common(klass, obj_ptr); assert(Universe::is_bootstrapping() || !new_cls->is_array(), "must not be an array"); // notify jvmti and dtrace @@ -114,15 +111,15 @@ void CollectedHeap::post_allocation_setup_class(KlassHandle klass, } void CollectedHeap::post_allocation_setup_array(KlassHandle klass, - HeapWord* obj, + HeapWord* obj_ptr, int length) { - // Set array length before setting the _klass field - // in post_allocation_setup_common() because the klass field - // indicates that the object is parsable by concurrent GC. + // Set array length before setting the _klass field because a + // non-NULL klass field indicates that the object is parsable by + // concurrent GC. assert(length >= 0, "length should be non-negative"); - ((arrayOop)obj)->set_length(length); - post_allocation_setup_common(klass, obj); - oop new_obj = (oop)obj; + ((arrayOop)obj_ptr)->set_length(length); + post_allocation_setup_common(klass, obj_ptr); + oop new_obj = (oop)obj_ptr; assert(new_obj->is_array(), "must be an array"); // notify jvmti and dtrace (must be after length is set for dtrace) post_allocation_notify(klass, new_obj, new_obj->size()); diff --git a/hotspot/src/share/vm/oops/oop.hpp b/hotspot/src/share/vm/oops/oop.hpp index 23d73067178..647cec8c83a 100644 --- a/hotspot/src/share/vm/oops/oop.hpp +++ b/hotspot/src/share/vm/oops/oop.hpp @@ -87,6 +87,7 @@ class oopDesc { inline narrowKlass* compressed_klass_addr(); inline void set_klass(Klass* k); + inline void release_set_klass(Klass* k); // For klass field compression inline int klass_gap() const; diff --git a/hotspot/src/share/vm/oops/oop.inline.hpp b/hotspot/src/share/vm/oops/oop.inline.hpp index 578bcc4e520..9a981e05c19 100644 --- a/hotspot/src/share/vm/oops/oop.inline.hpp +++ b/hotspot/src/share/vm/oops/oop.inline.hpp @@ -129,10 +129,14 @@ narrowKlass* oopDesc::compressed_klass_addr() { return &_metadata._compressed_klass; } +#define CHECK_SET_KLASS(k) \ + do { \ + assert(Universe::is_bootstrapping() || k != NULL, "NULL Klass"); \ + assert(Universe::is_bootstrapping() || k->is_klass(), "not a Klass"); \ + } while (0) + void oopDesc::set_klass(Klass* k) { - // since klasses are promoted no store check is needed - assert(Universe::is_bootstrapping() || k != NULL, "must be a real Klass*"); - assert(Universe::is_bootstrapping() || k->is_klass(), "not a Klass*"); + CHECK_SET_KLASS(k); if (UseCompressedClassPointers) { *compressed_klass_addr() = Klass::encode_klass_not_null(k); } else { @@ -140,6 +144,18 @@ void oopDesc::set_klass(Klass* k) { } } +void oopDesc::release_set_klass(Klass* k) { + CHECK_SET_KLASS(k); + if (UseCompressedClassPointers) { + OrderAccess::release_store(compressed_klass_addr(), + Klass::encode_klass_not_null(k)); + } else { + OrderAccess::release_store_ptr(klass_addr(), k); + } +} + +#undef CHECK_SET_KLASS + int oopDesc::klass_gap() const { return *(int*)(((intptr_t)this) + klass_gap_offset_in_bytes()); } From 317f1aa044a8a71c52cfe733f1f4baf656c22c4c Mon Sep 17 00:00:00 2001 From: Thomas Schatzl Date: Fri, 16 Sep 2016 11:33:47 +0200 Subject: [PATCH 06/69] 8157952: Parallelize Memory Pretouch Use multiple threads to pretouch memory using -XX:+AlwaysPreTouch to use more memory bandwidth Reviewed-by: jmasa, sangheki --- .../src/share/vm/gc/g1/g1CollectedHeap.cpp | 12 ++--- .../src/share/vm/gc/g1/g1CollectedHeap.hpp | 2 +- .../vm/gc/g1/g1PageBasedVirtualSpace.cpp | 54 +++++++++++++++++-- .../vm/gc/g1/g1PageBasedVirtualSpace.hpp | 4 ++ .../share/vm/gc/g1/g1RegionToSpaceMapper.cpp | 31 +++++++++-- .../share/vm/gc/g1/g1RegionToSpaceMapper.hpp | 4 +- .../src/share/vm/gc/g1/heapRegionManager.cpp | 28 +++++----- .../src/share/vm/gc/g1/heapRegionManager.hpp | 11 ++-- hotspot/src/share/vm/gc/shared/workgroup.hpp | 7 ++- hotspot/src/share/vm/runtime/globals.hpp | 4 ++ hotspot/src/share/vm/runtime/os.cpp | 4 +- hotspot/src/share/vm/runtime/os.hpp | 2 +- 12 files changed, 124 insertions(+), 39 deletions(-) diff --git a/hotspot/src/share/vm/gc/g1/g1CollectedHeap.cpp b/hotspot/src/share/vm/gc/g1/g1CollectedHeap.cpp index 935d935b13f..9ffbaeaad8b 100644 --- a/hotspot/src/share/vm/gc/g1/g1CollectedHeap.cpp +++ b/hotspot/src/share/vm/gc/g1/g1CollectedHeap.cpp @@ -1479,7 +1479,7 @@ void G1CollectedHeap::resize_if_necessary_after_full_collection() { "Capacity: " SIZE_FORMAT "B occupancy: " SIZE_FORMAT "B min_desired_capacity: " SIZE_FORMAT "B (" UINTX_FORMAT " %%)", capacity_after_gc, used_after_gc, minimum_desired_capacity, MinHeapFreeRatio); - expand(expand_bytes); + expand(expand_bytes, _workers); // No expansion, now see if we want to shrink } else if (capacity_after_gc > maximum_desired_capacity) { @@ -1599,7 +1599,7 @@ HeapWord* G1CollectedHeap::expand_and_allocate(size_t word_size, AllocationConte word_size * HeapWordSize); - if (expand(expand_bytes)) { + if (expand(expand_bytes, _workers)) { _hrm.verify_optional(); _verifier->verify_region_sets_optional(); return attempt_allocation_at_safepoint(word_size, @@ -1609,7 +1609,7 @@ HeapWord* G1CollectedHeap::expand_and_allocate(size_t word_size, AllocationConte return NULL; } -bool G1CollectedHeap::expand(size_t expand_bytes, double* expand_time_ms) { +bool G1CollectedHeap::expand(size_t expand_bytes, WorkGang* pretouch_workers, double* expand_time_ms) { size_t aligned_expand_bytes = ReservedSpace::page_align_size_up(expand_bytes); aligned_expand_bytes = align_size_up(aligned_expand_bytes, HeapRegion::GrainBytes); @@ -1626,7 +1626,7 @@ bool G1CollectedHeap::expand(size_t expand_bytes, double* expand_time_ms) { uint regions_to_expand = (uint)(aligned_expand_bytes / HeapRegion::GrainBytes); assert(regions_to_expand > 0, "Must expand by at least one region"); - uint expanded_by = _hrm.expand_by(regions_to_expand); + uint expanded_by = _hrm.expand_by(regions_to_expand, pretouch_workers); if (expand_time_ms != NULL) { *expand_time_ms = (os::elapsedTime() - expand_heap_start_time_sec) * MILLIUNITS; } @@ -1927,7 +1927,7 @@ jint G1CollectedHeap::initialize() { _cmThread = _cm->cmThread(); // Now expand into the initial heap size. - if (!expand(init_byte_size)) { + if (!expand(init_byte_size, _workers)) { vm_shutdown_during_initialization("Failed to allocate initial heap."); return JNI_ENOMEM; } @@ -3240,7 +3240,7 @@ G1CollectedHeap::do_collection_pause_at_safepoint(double target_pause_time_ms) { // No need for an ergo logging here, // expansion_amount() does this when it returns a value > 0. double expand_ms; - if (!expand(expand_bytes, &expand_ms)) { + if (!expand(expand_bytes, _workers, &expand_ms)) { // We failed to expand the heap. Cannot do anything about it. } g1_policy()->phase_times()->record_expand_heap_time(expand_ms); diff --git a/hotspot/src/share/vm/gc/g1/g1CollectedHeap.hpp b/hotspot/src/share/vm/gc/g1/g1CollectedHeap.hpp index 4aadccbe916..d1e8dcafb14 100644 --- a/hotspot/src/share/vm/gc/g1/g1CollectedHeap.hpp +++ b/hotspot/src/share/vm/gc/g1/g1CollectedHeap.hpp @@ -557,7 +557,7 @@ public: // Returns true if the heap was expanded by the requested amount; // false otherwise. // (Rounds up to a HeapRegion boundary.) - bool expand(size_t expand_bytes, double* expand_time_ms = NULL); + bool expand(size_t expand_bytes, WorkGang* pretouch_workers = NULL, double* expand_time_ms = NULL); // Returns the PLAB statistics for a given destination. inline G1EvacStats* alloc_buffer_stats(InCSetState dest); diff --git a/hotspot/src/share/vm/gc/g1/g1PageBasedVirtualSpace.cpp b/hotspot/src/share/vm/gc/g1/g1PageBasedVirtualSpace.cpp index 7f419bd409f..254baeab68e 100644 --- a/hotspot/src/share/vm/gc/g1/g1PageBasedVirtualSpace.cpp +++ b/hotspot/src/share/vm/gc/g1/g1PageBasedVirtualSpace.cpp @@ -24,8 +24,10 @@ #include "precompiled.hpp" #include "gc/g1/g1PageBasedVirtualSpace.hpp" +#include "gc/shared/workgroup.hpp" #include "oops/markOop.hpp" #include "oops/oop.inline.hpp" +#include "runtime/atomic.hpp" #include "runtime/os.inline.hpp" #include "services/memTracker.hpp" #include "utilities/bitMap.inline.hpp" @@ -177,7 +179,7 @@ void G1PageBasedVirtualSpace::pretouch_internal(size_t start_page, size_t end_pa guarantee(start_page < end_page, "Given start page " SIZE_FORMAT " is larger or equal to end page " SIZE_FORMAT, start_page, end_page); - os::pretouch_memory(page_start(start_page), bounded_end_addr(end_page)); + os::pretouch_memory(page_start(start_page), bounded_end_addr(end_page), _page_size); } bool G1PageBasedVirtualSpace::commit(size_t start_page, size_t size_in_pages) { @@ -198,9 +200,6 @@ bool G1PageBasedVirtualSpace::commit(size_t start_page, size_t size_in_pages) { } _committed.set_range(start_page, end_page); - if (AlwaysPreTouch) { - pretouch_internal(start_page, end_page); - } return zero_filled; } @@ -227,6 +226,53 @@ void G1PageBasedVirtualSpace::uncommit(size_t start_page, size_t size_in_pages) _committed.clear_range(start_page, end_page); } +class G1PretouchTask : public AbstractGangTask { +private: + char* volatile _cur_addr; + char* const _start_addr; + char* const _end_addr; + size_t const _page_size; +public: + G1PretouchTask(char* start_address, char* end_address, size_t page_size) : + AbstractGangTask("G1 PreTouch", + Universe::is_fully_initialized() ? GCId::current_raw() : + // During VM initialization there is + // no GC cycle that this task can be + // associated with. + GCId::undefined()), + _cur_addr(start_address), + _start_addr(start_address), + _end_addr(end_address), + _page_size(page_size) { + } + + virtual void work(uint worker_id) { + size_t const actual_chunk_size = MAX2(chunk_size(), _page_size); + while (true) { + char* touch_addr = (char*)Atomic::add_ptr((intptr_t)actual_chunk_size, (volatile void*) &_cur_addr) - actual_chunk_size; + if (touch_addr < _start_addr || touch_addr >= _end_addr) { + break; + } + char* end_addr = touch_addr + MIN2(actual_chunk_size, pointer_delta(_end_addr, touch_addr, sizeof(char))); + os::pretouch_memory(touch_addr, end_addr, _page_size); + } + } + + static size_t chunk_size() { return PreTouchParallelChunkSize; } +}; + +void G1PageBasedVirtualSpace::pretouch(size_t start_page, size_t size_in_pages, WorkGang* pretouch_gang) { + guarantee(pretouch_gang != NULL, "No pretouch gang specified."); + + size_t num_chunks = MAX2((size_t)1, size_in_pages * _page_size / MAX2(G1PretouchTask::chunk_size(), _page_size)); + + uint num_workers = MIN2((uint)num_chunks, pretouch_gang->active_workers()); + G1PretouchTask cl(page_start(start_page), bounded_end_addr(start_page + size_in_pages), _page_size); + log_debug(gc, heap)("Running %s with %u workers for " SIZE_FORMAT " work units pre-touching " SIZE_FORMAT "B.", + cl.name(), num_workers, num_chunks, size_in_pages * _page_size); + pretouch_gang->run_task(&cl, num_workers); +} + bool G1PageBasedVirtualSpace::contains(const void* p) const { return _low_boundary <= (const char*) p && (const char*) p < _high_boundary; } diff --git a/hotspot/src/share/vm/gc/g1/g1PageBasedVirtualSpace.hpp b/hotspot/src/share/vm/gc/g1/g1PageBasedVirtualSpace.hpp index ed16fac9553..f684c103f0b 100644 --- a/hotspot/src/share/vm/gc/g1/g1PageBasedVirtualSpace.hpp +++ b/hotspot/src/share/vm/gc/g1/g1PageBasedVirtualSpace.hpp @@ -30,6 +30,8 @@ #include "memory/virtualspace.hpp" #include "utilities/bitMap.hpp" +class WorkGang; + // Virtual space management helper for a virtual space with an OS page allocation // granularity. // (De-)Allocation requests are always OS page aligned by passing a page index @@ -117,6 +119,8 @@ class G1PageBasedVirtualSpace VALUE_OBJ_CLASS_SPEC { // Uncommit the given area of pages starting at start being size_in_pages large. void uncommit(size_t start_page, size_t size_in_pages); + void pretouch(size_t start_page, size_t size_in_pages, WorkGang* pretouch_gang = NULL); + // Initialize the given reserved space with the given base address and the size // actually used. // Prefer to commit in page_size chunks. diff --git a/hotspot/src/share/vm/gc/g1/g1RegionToSpaceMapper.cpp b/hotspot/src/share/vm/gc/g1/g1RegionToSpaceMapper.cpp index 80b794153ed..efcd5ce7e92 100644 --- a/hotspot/src/share/vm/gc/g1/g1RegionToSpaceMapper.cpp +++ b/hotspot/src/share/vm/gc/g1/g1RegionToSpaceMapper.cpp @@ -66,8 +66,12 @@ class G1RegionsLargerThanCommitSizeMapper : public G1RegionToSpaceMapper { guarantee(alloc_granularity >= page_size, "allocation granularity smaller than commit granularity"); } - virtual void commit_regions(uint start_idx, size_t num_regions) { - bool zero_filled = _storage.commit((size_t)start_idx * _pages_per_region, num_regions * _pages_per_region); + virtual void commit_regions(uint start_idx, size_t num_regions, WorkGang* pretouch_gang) { + size_t const start_page = (size_t)start_idx * _pages_per_region; + bool zero_filled = _storage.commit(start_page, num_regions * _pages_per_region); + if (AlwaysPreTouch) { + _storage.pretouch(start_page, num_regions * _pages_per_region, pretouch_gang); + } _commit_map.set_range(start_idx, start_idx + num_regions); fire_on_commit(start_idx, num_regions, zero_filled); } @@ -110,19 +114,38 @@ class G1RegionsSmallerThanCommitSizeMapper : public G1RegionToSpaceMapper { _refcounts.initialize((HeapWord*)rs.base(), (HeapWord*)(rs.base() + align_size_up(rs.size(), page_size)), page_size); } - virtual void commit_regions(uint start_idx, size_t num_regions) { + virtual void commit_regions(uint start_idx, size_t num_regions, WorkGang* pretouch_gang) { + size_t const NoPage = ~(size_t)0; + + size_t first_committed = NoPage; + size_t num_committed = 0; + + bool all_zero_filled = true; + for (uint i = start_idx; i < start_idx + num_regions; i++) { assert(!_commit_map.at(i), "Trying to commit storage at region %u that is already committed", i); size_t idx = region_idx_to_page_idx(i); uint old_refcount = _refcounts.get_by_index(idx); + bool zero_filled = false; if (old_refcount == 0) { + if (first_committed == NoPage) { + first_committed = idx; + num_committed = 1; + } else { + num_committed++; + } zero_filled = _storage.commit(idx, 1); } + all_zero_filled &= zero_filled; + _refcounts.set_by_index(idx, old_refcount + 1); _commit_map.set_bit(i); - fire_on_commit(i, 1, zero_filled); } + if (AlwaysPreTouch && num_committed > 0) { + _storage.pretouch(first_committed, num_committed, pretouch_gang); + } + fire_on_commit(start_idx, num_regions, all_zero_filled); } virtual void uncommit_regions(uint start_idx, size_t num_regions) { diff --git a/hotspot/src/share/vm/gc/g1/g1RegionToSpaceMapper.hpp b/hotspot/src/share/vm/gc/g1/g1RegionToSpaceMapper.hpp index 218ae1550ae..bcde9a5aa04 100644 --- a/hotspot/src/share/vm/gc/g1/g1RegionToSpaceMapper.hpp +++ b/hotspot/src/share/vm/gc/g1/g1RegionToSpaceMapper.hpp @@ -29,6 +29,8 @@ #include "memory/allocation.hpp" #include "utilities/debug.hpp" +class WorkGang; + class G1MappingChangedListener VALUE_OBJ_CLASS_SPEC { public: // Fired after commit of the memory, i.e. the memory this listener is registered @@ -68,7 +70,7 @@ class G1RegionToSpaceMapper : public CHeapObj { return _commit_map.at(idx); } - virtual void commit_regions(uint start_idx, size_t num_regions = 1) = 0; + virtual void commit_regions(uint start_idx, size_t num_regions = 1, WorkGang* pretouch_workers = NULL) = 0; virtual void uncommit_regions(uint start_idx, size_t num_regions = 1) = 0; // Creates an appropriate G1RegionToSpaceMapper for the given parameters. diff --git a/hotspot/src/share/vm/gc/g1/heapRegionManager.cpp b/hotspot/src/share/vm/gc/g1/heapRegionManager.cpp index 1f6bc95b1ad..f0887f93688 100644 --- a/hotspot/src/share/vm/gc/g1/heapRegionManager.cpp +++ b/hotspot/src/share/vm/gc/g1/heapRegionManager.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2016, 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 @@ -72,22 +72,22 @@ HeapRegion* HeapRegionManager::new_heap_region(uint hrm_index) { return g1h->new_heap_region(hrm_index, mr); } -void HeapRegionManager::commit_regions(uint index, size_t num_regions) { +void HeapRegionManager::commit_regions(uint index, size_t num_regions, WorkGang* pretouch_gang) { guarantee(num_regions > 0, "Must commit more than zero regions"); guarantee(_num_committed + num_regions <= max_length(), "Cannot commit more than the maximum amount of regions"); _num_committed += (uint)num_regions; - _heap_mapper->commit_regions(index, num_regions); + _heap_mapper->commit_regions(index, num_regions, pretouch_gang); // Also commit auxiliary data - _prev_bitmap_mapper->commit_regions(index, num_regions); - _next_bitmap_mapper->commit_regions(index, num_regions); + _prev_bitmap_mapper->commit_regions(index, num_regions, pretouch_gang); + _next_bitmap_mapper->commit_regions(index, num_regions, pretouch_gang); - _bot_mapper->commit_regions(index, num_regions); - _cardtable_mapper->commit_regions(index, num_regions); + _bot_mapper->commit_regions(index, num_regions, pretouch_gang); + _cardtable_mapper->commit_regions(index, num_regions, pretouch_gang); - _card_counts_mapper->commit_regions(index, num_regions); + _card_counts_mapper->commit_regions(index, num_regions, pretouch_gang); } void HeapRegionManager::uncommit_regions(uint start, size_t num_regions) { @@ -117,9 +117,9 @@ void HeapRegionManager::uncommit_regions(uint start, size_t num_regions) { _card_counts_mapper->uncommit_regions(start, num_regions); } -void HeapRegionManager::make_regions_available(uint start, uint num_regions) { +void HeapRegionManager::make_regions_available(uint start, uint num_regions, WorkGang* pretouch_gang) { guarantee(num_regions > 0, "No point in calling this for zero regions"); - commit_regions(start, num_regions); + commit_regions(start, num_regions, pretouch_gang); for (uint i = start; i < start + num_regions; i++) { if (_regions.get_by_index(i) == NULL) { HeapRegion* new_hr = new_heap_region(i); @@ -163,11 +163,11 @@ MemoryUsage HeapRegionManager::get_auxiliary_data_memory_usage() const { return MemoryUsage(0, used_sz, committed_sz, committed_sz); } -uint HeapRegionManager::expand_by(uint num_regions) { - return expand_at(0, num_regions); +uint HeapRegionManager::expand_by(uint num_regions, WorkGang* pretouch_workers) { + return expand_at(0, num_regions, pretouch_workers); } -uint HeapRegionManager::expand_at(uint start, uint num_regions) { +uint HeapRegionManager::expand_at(uint start, uint num_regions, WorkGang* pretouch_workers) { if (num_regions == 0) { return 0; } @@ -181,7 +181,7 @@ uint HeapRegionManager::expand_at(uint start, uint num_regions) { while (expanded < num_regions && (num_last_found = find_unavailable_from_idx(cur, &idx_last_found)) > 0) { uint to_expand = MIN2(num_regions - expanded, num_last_found); - make_regions_available(idx_last_found, to_expand); + make_regions_available(idx_last_found, to_expand, pretouch_workers); expanded += to_expand; cur = idx_last_found + num_last_found + 1; } diff --git a/hotspot/src/share/vm/gc/g1/heapRegionManager.hpp b/hotspot/src/share/vm/gc/g1/heapRegionManager.hpp index 8644d3e56e6..07c84da348b 100644 --- a/hotspot/src/share/vm/gc/g1/heapRegionManager.hpp +++ b/hotspot/src/share/vm/gc/g1/heapRegionManager.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -34,6 +34,7 @@ class HeapRegion; class HeapRegionClosure; class HeapRegionClaimer; class FreeRegionList; +class WorkGang; class G1HeapRegionTable : public G1BiasedMappedArray { protected: @@ -94,10 +95,10 @@ class HeapRegionManager: public CHeapObj { HeapWord* heap_bottom() const { return _regions.bottom_address_mapped(); } HeapWord* heap_end() const {return _regions.end_address_mapped(); } - void make_regions_available(uint index, uint num_regions = 1); + void make_regions_available(uint index, uint num_regions = 1, WorkGang* pretouch_gang = NULL); // Pass down commit calls to the VirtualSpace. - void commit_regions(uint index, size_t num_regions = 1); + void commit_regions(uint index, size_t num_regions = 1, WorkGang* pretouch_gang = NULL); void uncommit_regions(uint index, size_t num_regions = 1); // Notify other data structures about change in the heap layout. @@ -209,12 +210,12 @@ public: // HeapRegions, or re-use existing ones. Returns the number of regions the // sequence was expanded by. If a HeapRegion allocation fails, the resulting // number of regions might be smaller than what's desired. - uint expand_by(uint num_regions); + uint expand_by(uint num_regions, WorkGang* pretouch_workers = NULL); // Makes sure that the regions from start to start+num_regions-1 are available // for allocation. Returns the number of regions that were committed to achieve // this. - uint expand_at(uint start, uint num_regions); + uint expand_at(uint start, uint num_regions, WorkGang* pretouch_workers = NULL); // Find a contiguous set of empty regions of length num. Returns the start index of // that set, or G1_NO_HRM_INDEX. diff --git a/hotspot/src/share/vm/gc/shared/workgroup.hpp b/hotspot/src/share/vm/gc/shared/workgroup.hpp index 20491b66536..b71b3e0e23a 100644 --- a/hotspot/src/share/vm/gc/shared/workgroup.hpp +++ b/hotspot/src/share/vm/gc/shared/workgroup.hpp @@ -62,7 +62,12 @@ class AbstractGangTask VALUE_OBJ_CLASS_SPEC { AbstractGangTask(const char* name) : _name(name), _gc_id(GCId::current_raw()) - {} + {} + + AbstractGangTask(const char* name, const uint gc_id) : + _name(name), + _gc_id(gc_id) + {} // The abstract work method. // The argument tells you which member of the gang you are. diff --git a/hotspot/src/share/vm/runtime/globals.hpp b/hotspot/src/share/vm/runtime/globals.hpp index 1978313e48e..1c20ecf1174 100644 --- a/hotspot/src/share/vm/runtime/globals.hpp +++ b/hotspot/src/share/vm/runtime/globals.hpp @@ -1596,6 +1596,10 @@ public: product(bool, AlwaysPreTouch, false, \ "Force all freshly committed pages to be pre-touched") \ \ + product(size_t, PreTouchParallelChunkSize, 1 * G, \ + "Per-thread chunk size for parallel memory pre-touch.") \ + range(1, SIZE_MAX / 2) \ + \ product_pd(size_t, CMSYoungGenPerWorker, \ "The maximum size of young gen chosen by default per GC worker " \ "thread available") \ diff --git a/hotspot/src/share/vm/runtime/os.cpp b/hotspot/src/share/vm/runtime/os.cpp index 7089f6a6629..b73a4fa612d 100644 --- a/hotspot/src/share/vm/runtime/os.cpp +++ b/hotspot/src/share/vm/runtime/os.cpp @@ -1705,8 +1705,8 @@ bool os::release_memory(char* addr, size_t bytes) { return res; } -void os::pretouch_memory(void* start, void* end) { - for (volatile char *p = (char*)start; p < (char*)end; p += os::vm_page_size()) { +void os::pretouch_memory(void* start, void* end, size_t page_size) { + for (volatile char *p = (char*)start; p < (char*)end; p += page_size) { *p = 0; } } diff --git a/hotspot/src/share/vm/runtime/os.hpp b/hotspot/src/share/vm/runtime/os.hpp index 4f714e3cec2..0077b36d345 100644 --- a/hotspot/src/share/vm/runtime/os.hpp +++ b/hotspot/src/share/vm/runtime/os.hpp @@ -324,7 +324,7 @@ class os: AllStatic { // to make the OS back the memory range with actual memory. // Current implementation may not touch the last page if unaligned addresses // are passed. - static void pretouch_memory(void* start, void* end); + static void pretouch_memory(void* start, void* end, size_t page_size = vm_page_size()); enum ProtType { MEM_PROT_NONE, MEM_PROT_READ, MEM_PROT_RW, MEM_PROT_RWX }; static bool protect_memory(char* addr, size_t bytes, ProtType prot, From ba4a3fbd2089ec7b539b58ad3f6465d4f8f0c5cb Mon Sep 17 00:00:00 2001 From: Gerard Ziemski Date: Fri, 16 Sep 2016 12:09:53 -0500 Subject: [PATCH 07/69] 8136766: Enable ThreadStackSize range test Re-enabled max range check for StackSize runtime options Reviewed-by: dcubed --- .../CommandLine/OptionsValidation/TestOptionsWithRanges.java | 4 ---- 1 file changed, 4 deletions(-) diff --git a/hotspot/test/runtime/CommandLine/OptionsValidation/TestOptionsWithRanges.java b/hotspot/test/runtime/CommandLine/OptionsValidation/TestOptionsWithRanges.java index bd188d6cec8..fa3b79909c7 100644 --- a/hotspot/test/runtime/CommandLine/OptionsValidation/TestOptionsWithRanges.java +++ b/hotspot/test/runtime/CommandLine/OptionsValidation/TestOptionsWithRanges.java @@ -110,10 +110,6 @@ public class TestOptionsWithRanges { excludeTestMaxRange("OldSize"); excludeTestMaxRange("ParallelGCThreads"); - excludeTestMaxRange("CompilerThreadStackSize"); - excludeTestMaxRange("ThreadStackSize"); - excludeTestMaxRange("VMThreadStackSize"); - /* * Remove parameters controlling the code cache. As these * parameters have implications on the physical memory From 38eb4a4f6f98af2bc1c10cfdcf386286b233fa96 Mon Sep 17 00:00:00 2001 From: Martin Doerr Date: Tue, 6 Sep 2016 13:01:27 +0200 Subject: [PATCH 08/69] 8165489: Missing G1 barrier in Unsafe_GetObjectVolatile Add missing barrier, sharing code with Unsafe_GetObject. Reviewed-by: kbarrett, mgerdin, pliden --- hotspot/src/share/vm/prims/unsafe.cpp | 56 ++++++++++++++------------- 1 file changed, 29 insertions(+), 27 deletions(-) diff --git a/hotspot/src/share/vm/prims/unsafe.cpp b/hotspot/src/share/vm/prims/unsafe.cpp index 6703b7471c3..1c98add775b 100644 --- a/hotspot/src/share/vm/prims/unsafe.cpp +++ b/hotspot/src/share/vm/prims/unsafe.cpp @@ -272,6 +272,31 @@ public: // Get/PutObject must be special-cased, since it works with handles. +// We could be accessing the referent field in a reference +// object. If G1 is enabled then we need to register non-null +// referent with the SATB barrier. + +#if INCLUDE_ALL_GCS +static bool is_java_lang_ref_Reference_access(oop o, jlong offset) { + if (offset == java_lang_ref_Reference::referent_offset && o != NULL) { + Klass* k = o->klass(); + if (InstanceKlass::cast(k)->reference_type() != REF_NONE) { + assert(InstanceKlass::cast(k)->is_subclass_of(SystemDictionary::Reference_klass()), "sanity"); + return true; + } + } + return false; +} +#endif + +static void ensure_satb_referent_alive(oop o, jlong offset, oop v) { +#if INCLUDE_ALL_GCS + if (UseG1GC && v != NULL && is_java_lang_ref_Reference_access(o, offset)) { + G1SATBCardTableModRefBS::enqueue(v); + } +#endif +} + // These functions allow a null base pointer with an arbitrary address. // But if the base pointer is non-null, the offset should make some sense. // That is, it should be in the range [0, MAX_OBJECT_SIZE]. @@ -286,34 +311,9 @@ UNSAFE_ENTRY(jobject, Unsafe_GetObject(JNIEnv *env, jobject unsafe, jobject obj, v = *(oop*)index_oop_from_field_offset_long(p, offset); } - jobject ret = JNIHandles::make_local(env, v); + ensure_satb_referent_alive(p, offset, v); -#if INCLUDE_ALL_GCS - // We could be accessing the referent field in a reference - // object. If G1 is enabled then we need to register non-null - // referent with the SATB barrier. - if (UseG1GC) { - bool needs_barrier = false; - - if (ret != NULL) { - if (offset == java_lang_ref_Reference::referent_offset && obj != NULL) { - oop o = JNIHandles::resolve(obj); - Klass* k = o->klass(); - if (InstanceKlass::cast(k)->reference_type() != REF_NONE) { - assert(InstanceKlass::cast(k)->is_subclass_of(SystemDictionary::Reference_klass()), "sanity"); - needs_barrier = true; - } - } - } - - if (needs_barrier) { - oop referent = JNIHandles::resolve(ret); - G1SATBCardTableModRefBS::enqueue(referent); - } - } -#endif // INCLUDE_ALL_GCS - - return ret; + return JNIHandles::make_local(env, v); } UNSAFE_END UNSAFE_ENTRY(void, Unsafe_PutObject(JNIEnv *env, jobject unsafe, jobject obj, jlong offset, jobject x_h)) { @@ -344,6 +344,8 @@ UNSAFE_ENTRY(jobject, Unsafe_GetObjectVolatile(JNIEnv *env, jobject unsafe, jobj (void)const_cast(v = *(volatile oop*) addr); } + ensure_satb_referent_alive(p, offset, v); + OrderAccess::acquire(); return JNIHandles::make_local(env, v); } UNSAFE_END From eb529507040fb016dc5e3c7d34b928c30d320097 Mon Sep 17 00:00:00 2001 From: Jiangli Zhou Date: Sun, 18 Sep 2016 21:10:48 -0400 Subject: [PATCH 09/69] 8078644: CDS needs to support JVMTI CFLH Support posting CLFH for shared classes. Tests are contributed by Misha Seledtsov. Reviewed-by: iklam, coleenp, acorn, dcubed, sspitsyn --- .../src/share/vm/classfile/klassFactory.cpp | 96 +++++++++- .../src/share/vm/classfile/klassFactory.hpp | 6 + .../share/vm/classfile/systemDictionary.cpp | 29 ++- hotspot/src/share/vm/memory/filemap.cpp | 2 +- hotspot/src/share/vm/memory/filemap.hpp | 25 ++- hotspot/src/share/vm/memory/metaspace.cpp | 48 ++--- .../src/share/vm/memory/metaspaceShared.cpp | 45 ++++- .../src/share/vm/memory/metaspaceShared.hpp | 13 +- hotspot/src/share/vm/oops/instanceKlass.cpp | 27 ++- hotspot/src/share/vm/oops/instanceKlass.hpp | 9 +- hotspot/src/share/vm/utilities/debug.cpp | 6 + hotspot/src/share/vm/utilities/debug.hpp | 3 +- .../SharedArchiveFile/CDSTestUtils.java | 115 +++++++++++ .../transformRelatedClasses/Implementor.java | 37 ++++ .../transformRelatedClasses/Interface.java | 31 +++ .../transformRelatedClasses/SubClass.java | 40 ++++ .../transformRelatedClasses/SuperClazz.java | 32 ++++ .../transformRelatedClasses/TestEntry.java | 45 +++++ .../TransformInterfaceAndImplementor.java | 50 +++++ .../TransformRelatedClasses.java | 179 ++++++++++++++++++ .../TransformSuperAndSubClasses.java | 51 +++++ .../TransformSuperSubTwoPckgs.java | 52 +++++ .../TransformTestCommon.java | 114 +++++++++++ .../myPkg1/SuperClazz.java | 33 ++++ .../myPkg2/SubClass.java | 56 ++++++ .../test/testlibrary/jvmti/TransformUtil.java | 75 ++++++++ .../testlibrary/jvmti/TransformerAgent.java | 100 ++++++++++ .../testlibrary/jvmti/TransformerAgent.mf | 5 + 28 files changed, 1256 insertions(+), 68 deletions(-) create mode 100644 hotspot/test/runtime/SharedArchiveFile/CDSTestUtils.java create mode 100644 hotspot/test/runtime/SharedArchiveFile/serviceability/transformRelatedClasses/Implementor.java create mode 100644 hotspot/test/runtime/SharedArchiveFile/serviceability/transformRelatedClasses/Interface.java create mode 100644 hotspot/test/runtime/SharedArchiveFile/serviceability/transformRelatedClasses/SubClass.java create mode 100644 hotspot/test/runtime/SharedArchiveFile/serviceability/transformRelatedClasses/SuperClazz.java create mode 100644 hotspot/test/runtime/SharedArchiveFile/serviceability/transformRelatedClasses/TestEntry.java create mode 100644 hotspot/test/runtime/SharedArchiveFile/serviceability/transformRelatedClasses/TransformInterfaceAndImplementor.java create mode 100644 hotspot/test/runtime/SharedArchiveFile/serviceability/transformRelatedClasses/TransformRelatedClasses.java create mode 100644 hotspot/test/runtime/SharedArchiveFile/serviceability/transformRelatedClasses/TransformSuperAndSubClasses.java create mode 100644 hotspot/test/runtime/SharedArchiveFile/serviceability/transformRelatedClasses/TransformSuperSubTwoPckgs.java create mode 100644 hotspot/test/runtime/SharedArchiveFile/serviceability/transformRelatedClasses/TransformTestCommon.java create mode 100644 hotspot/test/runtime/SharedArchiveFile/serviceability/transformRelatedClasses/myPkg1/SuperClazz.java create mode 100644 hotspot/test/runtime/SharedArchiveFile/serviceability/transformRelatedClasses/myPkg2/SubClass.java create mode 100644 hotspot/test/testlibrary/jvmti/TransformUtil.java create mode 100644 hotspot/test/testlibrary/jvmti/TransformerAgent.java create mode 100644 hotspot/test/testlibrary/jvmti/TransformerAgent.mf diff --git a/hotspot/src/share/vm/classfile/klassFactory.cpp b/hotspot/src/share/vm/classfile/klassFactory.cpp index dc5f3963d1a..0c95ac7907d 100644 --- a/hotspot/src/share/vm/classfile/klassFactory.cpp +++ b/hotspot/src/share/vm/classfile/klassFactory.cpp @@ -25,12 +25,85 @@ #include "precompiled.hpp" #include "classfile/classFileParser.hpp" #include "classfile/classFileStream.hpp" +#include "classfile/classLoader.hpp" #include "classfile/classLoaderData.hpp" +#include "classfile/classLoaderData.inline.hpp" #include "classfile/klassFactory.hpp" +#include "classfile/sharedClassUtil.hpp" +#include "memory/metaspaceShared.hpp" #include "memory/resourceArea.hpp" #include "prims/jvmtiEnvBase.hpp" +#include "prims/jvmtiRedefineClasses.hpp" #include "trace/traceMacros.hpp" +// called during initial loading of a shared class +instanceKlassHandle KlassFactory::check_shared_class_file_load_hook( + instanceKlassHandle ik, + Symbol* class_name, + Handle class_loader, + Handle protection_domain, TRAPS) { +#if INCLUDE_CDS && INCLUDE_JVMTI + assert(ik.not_null(), "sanity"); + assert(ik()->is_shared(), "expecting a shared class"); + + if (JvmtiExport::should_post_class_file_load_hook()) { + assert(THREAD->is_Java_thread(), "must be JavaThread"); + + // Post the CFLH + JvmtiCachedClassFileData* cached_class_file = NULL; + JvmtiCachedClassFileData* archived_class_data = ik->get_archived_class_data(); + assert(archived_class_data != NULL, "shared class has no archived class data"); + unsigned char* ptr = + VM_RedefineClasses::get_cached_class_file_bytes(archived_class_data); + unsigned char* end_ptr = + ptr + VM_RedefineClasses::get_cached_class_file_len(archived_class_data); + unsigned char* old_ptr = ptr; + JvmtiExport::post_class_file_load_hook(class_name, + class_loader, + protection_domain, + &ptr, + &end_ptr, + &cached_class_file); + if (old_ptr != ptr) { + // JVMTI agent has modified class file data. + // Set new class file stream using JVMTI agent modified class file data. + ClassLoaderData* loader_data = + ClassLoaderData::class_loader_data(class_loader()); + int path_index = ik->shared_classpath_index(); + SharedClassPathEntry* ent = + (SharedClassPathEntry*)FileMapInfo::shared_classpath(path_index); + ClassFileStream* stream = new ClassFileStream(ptr, + end_ptr - ptr, + ent->_name, + ClassFileStream::verify); + ClassFileParser parser(stream, + class_name, + loader_data, + protection_domain, + NULL, + NULL, + ClassFileParser::BROADCAST, // publicity level + CHECK_NULL); + instanceKlassHandle new_ik = parser.create_instance_klass(true /* changed_by_loadhook */, + CHECK_NULL); + if (cached_class_file != NULL) { + new_ik->set_cached_class_file(cached_class_file); + } + + if (class_loader.is_null()) { + ResourceMark rm; + ClassLoader::add_package(class_name->as_C_string(), path_index, THREAD); + } + + return new_ik; + } + } +#endif + + return NULL; +} + + static ClassFileStream* check_class_file_load_hook(ClassFileStream* stream, Symbol* name, ClassLoaderData* loader_data, @@ -97,7 +170,6 @@ instanceKlassHandle KlassFactory::create_from_stream(ClassFileStream* stream, const InstanceKlass* host_klass, GrowableArray* cp_patches, TRAPS) { - assert(stream != NULL, "invariant"); assert(loader_data != NULL, "invariant"); assert(THREAD->is_Java_thread(), "must be a JavaThread"); @@ -142,5 +214,27 @@ instanceKlassHandle KlassFactory::create_from_stream(ClassFileStream* stream, TRACE_KLASS_CREATION(result, parser, THREAD); +#if INCLUDE_CDS && INCLUDE_JVMTI + if (DumpSharedSpaces) { + assert(cached_class_file == NULL, "Sanity"); + // Archive the class stream data into the optional data section + JvmtiCachedClassFileData *p; + int len; + const unsigned char *bytes; + // event based tracing might set cached_class_file + if ((bytes = result->get_cached_class_file_bytes()) != NULL) { + len = result->get_cached_class_file_len(); + } else { + len = stream->length(); + bytes = stream->buffer(); + } + p = (JvmtiCachedClassFileData*)MetaspaceShared::optional_data_space_alloc( + offset_of(JvmtiCachedClassFileData, data) + len); + p->length = len; + memcpy(p->data, bytes, len); + result->set_archived_class_data(p); + } +#endif + return result; } diff --git a/hotspot/src/share/vm/classfile/klassFactory.hpp b/hotspot/src/share/vm/classfile/klassFactory.hpp index 72dcc0dd6e4..6624e31658e 100644 --- a/hotspot/src/share/vm/classfile/klassFactory.hpp +++ b/hotspot/src/share/vm/classfile/klassFactory.hpp @@ -75,6 +75,12 @@ class KlassFactory : AllStatic { const InstanceKlass* host_klass, GrowableArray* cp_patches, TRAPS); + public: + static instanceKlassHandle check_shared_class_file_load_hook( + instanceKlassHandle ik, + Symbol* class_name, + Handle class_loader, + Handle protection_domain, TRAPS); }; #endif // SHARE_VM_CLASSFILE_KLASSFACTORY_HPP diff --git a/hotspot/src/share/vm/classfile/systemDictionary.cpp b/hotspot/src/share/vm/classfile/systemDictionary.cpp index f3b667eaf43..02e1dbae6bc 100644 --- a/hotspot/src/share/vm/classfile/systemDictionary.cpp +++ b/hotspot/src/share/vm/classfile/systemDictionary.cpp @@ -1210,16 +1210,12 @@ Klass* SystemDictionary::find_shared_class(Symbol* class_name) { instanceKlassHandle SystemDictionary::load_shared_class( Symbol* class_name, Handle class_loader, TRAPS) { - // Don't load shared class when JvmtiExport::should_post_class_file_load_hook() - // is enabled since posting CFLH is not supported when loading shared class. - if (!JvmtiExport::should_post_class_file_load_hook()) { - instanceKlassHandle ik (THREAD, find_shared_class(class_name)); - // Make sure we only return the boot class for the NULL classloader. - if (ik.not_null() && - ik->is_shared_boot_class() && class_loader.is_null()) { - Handle protection_domain; - return load_shared_class(ik, class_loader, protection_domain, THREAD); - } + instanceKlassHandle ik (THREAD, find_shared_class(class_name)); + // Make sure we only return the boot class for the NULL classloader. + if (ik.not_null() && + ik->is_shared_boot_class() && class_loader.is_null()) { + Handle protection_domain; + return load_shared_class(ik, class_loader, protection_domain, THREAD); } return instanceKlassHandle(); } @@ -1303,11 +1299,6 @@ instanceKlassHandle SystemDictionary::load_shared_class(instanceKlassHandle ik, Handle class_loader, Handle protection_domain, TRAPS) { instanceKlassHandle nh = instanceKlassHandle(); // null Handle - if (JvmtiExport::should_post_class_file_load_hook()) { - // Don't load shared class when JvmtiExport::should_post_class_file_load_hook() - // is enabled since posting CFLH is not supported when loading shared class. - return nh; - } if (ik.not_null()) { Symbol* class_name = ik->name(); @@ -1358,6 +1349,14 @@ instanceKlassHandle SystemDictionary::load_shared_class(instanceKlassHandle ik, } } + instanceKlassHandle new_ik = KlassFactory::check_shared_class_file_load_hook( + ik, class_name, class_loader, protection_domain, CHECK_(nh)); + if (new_ik.not_null()) { + // The class is changed by CFLH. Return the new class. The shared class is + // not used. + return new_ik; + } + // Adjust methods to recover missing data. They need addresses for // interpreter entry points and their default native method address // must be reset. diff --git a/hotspot/src/share/vm/memory/filemap.cpp b/hotspot/src/share/vm/memory/filemap.cpp index 6dc7d1fb1c6..08a79f11f3b 100644 --- a/hotspot/src/share/vm/memory/filemap.cpp +++ b/hotspot/src/share/vm/memory/filemap.cpp @@ -649,7 +649,7 @@ ReservedSpace FileMapInfo::reserve_shared_memory() { // Memory map a region in the address space. static const char* shared_region_name[] = { "ReadOnly", "ReadWrite", "MiscData", "MiscCode", - "String1", "String2" }; + "String1", "String2", "OptionalData" }; char* FileMapInfo::map_region(int i) { assert(!MetaspaceShared::is_string_region(i), "sanity"); diff --git a/hotspot/src/share/vm/memory/filemap.hpp b/hotspot/src/share/vm/memory/filemap.hpp index 2c02b427f0b..baffd299436 100644 --- a/hotspot/src/share/vm/memory/filemap.hpp +++ b/hotspot/src/share/vm/memory/filemap.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2016, 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 @@ -252,10 +252,27 @@ public: bool is_in_shared_region(const void* p, int idx) NOT_CDS_RETURN_(false); void print_shared_spaces() NOT_CDS_RETURN; + // The ro+rw+md+mc spaces size + static size_t core_spaces_size() { + return align_size_up((SharedReadOnlySize + SharedReadWriteSize + + SharedMiscDataSize + SharedMiscCodeSize), + os::vm_allocation_granularity()); + } + + // The estimated optional space size. + // + // Currently the optional space only has archived class bytes. + // The core_spaces_size is the size of all class metadata, which is a good + // estimate of the total class bytes to be archived. Only the portion + // containing data is written out to the archive and mapped at runtime. + // There is no memory waste due to unused portion in optional space. + static size_t optional_space_size() { + return core_spaces_size(); + } + + // Total shared_spaces size includes the ro, rw, md, mc and od spaces static size_t shared_spaces_size() { - return align_size_up(SharedReadOnlySize + SharedReadWriteSize + - SharedMiscDataSize + SharedMiscCodeSize, - os::vm_allocation_granularity()); + return core_spaces_size() + optional_space_size(); } // Stop CDS sharing and unmap CDS regions. diff --git a/hotspot/src/share/vm/memory/metaspace.cpp b/hotspot/src/share/vm/memory/metaspace.cpp index 1801a7c21cf..4ba897e7ab9 100644 --- a/hotspot/src/share/vm/memory/metaspace.cpp +++ b/hotspot/src/share/vm/memory/metaspace.cpp @@ -3172,36 +3172,28 @@ void Metaspace::global_initialize() { address cds_address = NULL; FileMapInfo* mapinfo = new FileMapInfo(); - if (JvmtiExport::should_post_class_file_load_hook()) { - // Currently CDS does not support JVMTI CFLH when loading shared class. - // If JvmtiExport::should_post_class_file_load_hook is already enabled, - // just disable UseSharedSpaces. - FileMapInfo::fail_continue("Tool agent requires sharing to be disabled."); - delete mapinfo; - } else { - // Open the shared archive file, read and validate the header. If - // initialization fails, shared spaces [UseSharedSpaces] are - // disabled and the file is closed. - // Map in spaces now also - if (mapinfo->initialize() && MetaspaceShared::map_shared_spaces(mapinfo)) { - cds_total = FileMapInfo::shared_spaces_size(); - cds_address = (address)mapinfo->header()->region_addr(0); + // Open the shared archive file, read and validate the header. If + // initialization fails, shared spaces [UseSharedSpaces] are + // disabled and the file is closed. + // Map in spaces now also + if (mapinfo->initialize() && MetaspaceShared::map_shared_spaces(mapinfo)) { + cds_total = FileMapInfo::shared_spaces_size(); + cds_address = (address)mapinfo->header()->region_addr(0); #ifdef _LP64 - if (using_class_space()) { - char* cds_end = (char*)(cds_address + cds_total); - cds_end = (char *)align_ptr_up(cds_end, _reserve_alignment); - // If UseCompressedClassPointers is set then allocate the metaspace area - // above the heap and above the CDS area (if it exists). - allocate_metaspace_compressed_klass_ptrs(cds_end, cds_address); - // Map the shared string space after compressed pointers - // because it relies on compressed class pointers setting to work - mapinfo->map_string_regions(); - } -#endif // _LP64 - } else { - assert(!mapinfo->is_open() && !UseSharedSpaces, - "archive file not closed or shared spaces not disabled."); + if (using_class_space()) { + char* cds_end = (char*)(cds_address + cds_total); + cds_end = (char *)align_ptr_up(cds_end, _reserve_alignment); + // If UseCompressedClassPointers is set then allocate the metaspace area + // above the heap and above the CDS area (if it exists). + allocate_metaspace_compressed_klass_ptrs(cds_end, cds_address); + // Map the shared string space after compressed pointers + // because it relies on compressed class pointers setting to work + mapinfo->map_string_regions(); } +#endif // _LP64 + } else { + assert(!mapinfo->is_open() && !UseSharedSpaces, + "archive file not closed or shared spaces not disabled."); } } #endif // INCLUDE_CDS diff --git a/hotspot/src/share/vm/memory/metaspaceShared.cpp b/hotspot/src/share/vm/memory/metaspaceShared.cpp index 66366273f19..61d6fa37b41 100644 --- a/hotspot/src/share/vm/memory/metaspaceShared.cpp +++ b/hotspot/src/share/vm/memory/metaspaceShared.cpp @@ -65,6 +65,7 @@ address MetaspaceShared::_cds_i2i_entry_code_buffers = NULL; size_t MetaspaceShared::_cds_i2i_entry_code_buffers_size = 0; SharedMiscRegion MetaspaceShared::_mc; SharedMiscRegion MetaspaceShared::_md; +SharedMiscRegion MetaspaceShared::_od; void SharedMiscRegion::initialize(ReservedSpace rs, size_t committed_byte_size, SharedSpaceType space_type) { _vs.initialize(rs, committed_byte_size); @@ -93,16 +94,24 @@ void MetaspaceShared::initialize_shared_rs(ReservedSpace* rs) { assert(DumpSharedSpaces, "dump time only"); _shared_rs = rs; - // Split up and initialize the misc code and data spaces + size_t core_spaces_size = FileMapInfo::core_spaces_size(); size_t metadata_size = SharedReadOnlySize + SharedReadWriteSize; - ReservedSpace shared_ro_rw = _shared_rs->first_part(metadata_size); - ReservedSpace misc_section = _shared_rs->last_part(metadata_size); - // Now split into misc sections. + // Split into the core and optional sections + ReservedSpace core_data = _shared_rs->first_part(core_spaces_size); + ReservedSpace optional_data = _shared_rs->last_part(core_spaces_size); + + // The RO/RW and the misc sections + ReservedSpace shared_ro_rw = core_data.first_part(metadata_size); + ReservedSpace misc_section = core_data.last_part(metadata_size); + + // Now split the misc code and misc data sections. ReservedSpace md_rs = misc_section.first_part(SharedMiscDataSize); ReservedSpace mc_rs = misc_section.last_part(SharedMiscDataSize); + _md.initialize(md_rs, SharedMiscDataSize, SharedMiscData); - _mc.initialize(mc_rs, SharedMiscCodeSize, SharedMiscData); + _mc.initialize(mc_rs, SharedMiscCodeSize, SharedMiscCode); + _od.initialize(optional_data, metadata_size, SharedOptional); } // Read/write a data stream for restoring/preserving metadata pointers and @@ -521,6 +530,7 @@ private: GrowableArray *_class_promote_order; VirtualSpace _md_vs; VirtualSpace _mc_vs; + VirtualSpace _od_vs; GrowableArray *_string_regions; public: @@ -598,15 +608,19 @@ void VM_PopulateDumpSharedSpace::doit() { remove_unshareable_in_classes(); tty->print_cr("done. "); - // Set up the share data and shared code segments. + // Set up the misc data, misc code and optional data segments. _md_vs = *MetaspaceShared::misc_data_region()->virtual_space(); _mc_vs = *MetaspaceShared::misc_code_region()->virtual_space(); + _od_vs = *MetaspaceShared::optional_data_region()->virtual_space(); char* md_low = _md_vs.low(); char* md_top = MetaspaceShared::misc_data_region()->alloc_top(); char* md_end = _md_vs.high(); char* mc_low = _mc_vs.low(); char* mc_top = MetaspaceShared::misc_code_region()->alloc_top(); char* mc_end = _mc_vs.high(); + char* od_low = _od_vs.low(); + char* od_top = MetaspaceShared::optional_data_region()->alloc_top(); + char* od_end = _od_vs.high(); // Reserve space for the list of Klass*s whose vtables are used // for patching others as needed. @@ -661,28 +675,32 @@ void VM_PopulateDumpSharedSpace::doit() { const size_t rw_alloced = rw_space->capacity_bytes_slow(Metaspace::NonClassType); const size_t md_alloced = md_end-md_low; const size_t mc_alloced = mc_end-mc_low; + const size_t od_alloced = od_end-od_low; const size_t total_alloced = ro_alloced + rw_alloced + md_alloced + mc_alloced - + ss_bytes; + + ss_bytes + od_alloced; // Occupied size of each space. const size_t ro_bytes = ro_space->used_bytes_slow(Metaspace::NonClassType); const size_t rw_bytes = rw_space->used_bytes_slow(Metaspace::NonClassType); const size_t md_bytes = size_t(md_top - md_low); const size_t mc_bytes = size_t(mc_top - mc_low); + const size_t od_bytes = size_t(od_top - od_low); // Percent of total size - const size_t total_bytes = ro_bytes + rw_bytes + md_bytes + mc_bytes + ss_bytes; + const size_t total_bytes = ro_bytes + rw_bytes + md_bytes + mc_bytes + ss_bytes + od_bytes; const double ro_t_perc = ro_bytes / double(total_bytes) * 100.0; const double rw_t_perc = rw_bytes / double(total_bytes) * 100.0; const double md_t_perc = md_bytes / double(total_bytes) * 100.0; const double mc_t_perc = mc_bytes / double(total_bytes) * 100.0; const double ss_t_perc = ss_bytes / double(total_bytes) * 100.0; + const double od_t_perc = od_bytes / double(total_bytes) * 100.0; // Percent of fullness of each space const double ro_u_perc = ro_bytes / double(ro_alloced) * 100.0; const double rw_u_perc = rw_bytes / double(rw_alloced) * 100.0; const double md_u_perc = md_bytes / double(md_alloced) * 100.0; const double mc_u_perc = mc_bytes / double(mc_alloced) * 100.0; + const double od_u_perc = od_bytes / double(od_alloced) * 100.0; const double total_u_perc = total_bytes / double(total_alloced) * 100.0; #define fmt_space "%s space: " SIZE_FORMAT_W(9) " [ %4.1f%% of total] out of " SIZE_FORMAT_W(9) " bytes [%5.1f%% used] at " INTPTR_FORMAT @@ -691,6 +709,7 @@ void VM_PopulateDumpSharedSpace::doit() { tty->print_cr(fmt_space, "md", md_bytes, md_t_perc, md_alloced, md_u_perc, p2i(md_low)); tty->print_cr(fmt_space, "mc", mc_bytes, mc_t_perc, mc_alloced, mc_u_perc, p2i(mc_low)); tty->print_cr(fmt_space, "st", ss_bytes, ss_t_perc, ss_bytes, 100.0, p2i(ss_low)); + tty->print_cr(fmt_space, "od", od_bytes, od_t_perc, od_alloced, od_u_perc, p2i(od_low)); tty->print_cr("total : " SIZE_FORMAT_W(9) " [100.0%% of total] out of " SIZE_FORMAT_W(9) " bytes [%5.1f%% used]", total_bytes, total_alloced, total_u_perc); @@ -734,6 +753,10 @@ void VM_PopulateDumpSharedSpace::doit() { SharedMiscCodeSize, true, true); mapinfo->write_string_regions(_string_regions); + mapinfo->write_region(MetaspaceShared::od, _od_vs.low(), + pointer_delta(od_top, _od_vs.low(), sizeof(char)), + pointer_delta(od_end, _od_vs.low(), sizeof(char)), + true, false); } mapinfo->close(); @@ -1049,8 +1072,6 @@ void MetaspaceShared::print_shared_spaces() { // Map shared spaces at requested addresses and return if succeeded. -// Need to keep the bounds of the ro and rw space for the Metaspace::contains -// call, or is_in_shared_space. bool MetaspaceShared::map_shared_spaces(FileMapInfo* mapinfo) { size_t image_alignment = mapinfo->alignment(); @@ -1068,6 +1089,7 @@ bool MetaspaceShared::map_shared_spaces(FileMapInfo* mapinfo) { char* _rw_base = NULL; char* _md_base = NULL; char* _mc_base = NULL; + char* _od_base = NULL; // Map each shared region if ((_ro_base = mapinfo->map_region(ro)) != NULL && @@ -1078,6 +1100,8 @@ bool MetaspaceShared::map_shared_spaces(FileMapInfo* mapinfo) { mapinfo->verify_region_checksum(md) && (_mc_base = mapinfo->map_region(mc)) != NULL && mapinfo->verify_region_checksum(mc) && + (_od_base = mapinfo->map_region(od)) != NULL && + mapinfo->verify_region_checksum(od) && (image_alignment == (size_t)max_alignment()) && mapinfo->validate_classpath_entry_table()) { // Success (no need to do anything) @@ -1089,6 +1113,7 @@ bool MetaspaceShared::map_shared_spaces(FileMapInfo* mapinfo) { if (_rw_base != NULL) mapinfo->unmap_region(rw); if (_md_base != NULL) mapinfo->unmap_region(md); if (_mc_base != NULL) mapinfo->unmap_region(mc); + if (_od_base != NULL) mapinfo->unmap_region(od); #ifndef _WINDOWS // Release the entire mapped region shared_rs.release(); diff --git a/hotspot/src/share/vm/memory/metaspaceShared.hpp b/hotspot/src/share/vm/memory/metaspaceShared.hpp index c60e8207328..cb96021af66 100644 --- a/hotspot/src/share/vm/memory/metaspaceShared.hpp +++ b/hotspot/src/share/vm/memory/metaspaceShared.hpp @@ -132,6 +132,7 @@ class MetaspaceShared : AllStatic { // Used only during dumping. static SharedMiscRegion _md; static SharedMiscRegion _mc; + static SharedMiscRegion _od; public: enum { vtbl_list_size = DEFAULT_VTBL_LIST_SIZE, @@ -148,7 +149,10 @@ class MetaspaceShared : AllStatic { max_strings = 2, // max number of string regions in string space num_non_strings = 4, // number of non-string regions first_string = num_non_strings, // index of first string region - n_regions = max_strings + num_non_strings // total number of regions + // The optional data region is the last region. + // Currently it only contains class file data. + od = max_strings + num_non_strings, + n_regions = od + 1 // total number of regions }; // Accessor functions to save shared space created for metadata, which has @@ -222,9 +226,10 @@ class MetaspaceShared : AllStatic { static int count_class(const char* classlist_file); static void estimate_regions_size() NOT_CDS_RETURN; - // Allocate a block of memory from the "mc" or "md" regions. + // Allocate a block of memory from the "mc", "md", or "od" regions. static char* misc_code_space_alloc(size_t num_bytes) { return _mc.alloc(num_bytes); } static char* misc_data_space_alloc(size_t num_bytes) { return _md.alloc(num_bytes); } + static char* optional_data_space_alloc(size_t num_bytes) { return _od.alloc(num_bytes); } static address cds_i2i_entry_code_buffers(size_t total_size); @@ -243,5 +248,9 @@ class MetaspaceShared : AllStatic { assert(DumpSharedSpaces, "used during dumping only"); return &_md; } + static SharedMiscRegion* optional_data_region() { + assert(DumpSharedSpaces, "used during dumping only"); + return &_od; + } }; #endif // SHARE_VM_MEMORY_METASPACESHARED_HPP diff --git a/hotspot/src/share/vm/oops/instanceKlass.cpp b/hotspot/src/share/vm/oops/instanceKlass.cpp index aaebc235e9d..54e54162c7f 100644 --- a/hotspot/src/share/vm/oops/instanceKlass.cpp +++ b/hotspot/src/share/vm/oops/instanceKlass.cpp @@ -41,6 +41,7 @@ #include "memory/heapInspection.hpp" #include "memory/iterator.inline.hpp" #include "memory/metadataFactory.hpp" +#include "memory/metaspaceShared.hpp" #include "memory/oopFactory.hpp" #include "memory/resourceArea.hpp" #include "oops/fieldStreams.hpp" @@ -1972,11 +1973,6 @@ void InstanceKlass::remove_unshareable_info() { m->remove_unshareable_info(); } - // cached_class_file might be pointing to a malloc'ed buffer allocated by - // event-based tracing code at CDS dump time. It's not usable at runtime - // so let's clear it. - set_cached_class_file(NULL); - // do array classes also. array_klasses_do(remove_unshareable_in_class); } @@ -2070,6 +2066,7 @@ void InstanceKlass::release_C_heap_structures(InstanceKlass* ik) { } void InstanceKlass::release_C_heap_structures() { + assert(!this->is_shared(), "should not be called for a shared class"); // Can't release the constant pool here because the constant pool can be // deallocated separately from the InstanceKlass for default methods and @@ -3653,6 +3650,15 @@ Method* InstanceKlass::method_with_orig_idnum(int idnum, int version) { } #if INCLUDE_JVMTI +JvmtiCachedClassFileData* InstanceKlass::get_cached_class_file() { + if (MetaspaceShared::is_in_shared_space(_cached_class_file)) { + // Ignore the archived class stream data + return NULL; + } else { + return _cached_class_file; + } +} + jint InstanceKlass::get_cached_class_file_len() { return VM_RedefineClasses::get_cached_class_file_len(_cached_class_file); } @@ -3660,4 +3666,15 @@ jint InstanceKlass::get_cached_class_file_len() { unsigned char * InstanceKlass::get_cached_class_file_bytes() { return VM_RedefineClasses::get_cached_class_file_bytes(_cached_class_file); } + +#if INCLUDE_CDS +JvmtiCachedClassFileData* InstanceKlass::get_archived_class_data() { + assert(this->is_shared(), "class should be shared"); + if (MetaspaceShared::is_in_shared_space(_cached_class_file)) { + return _cached_class_file; + } else { + return NULL; + } +} +#endif #endif diff --git a/hotspot/src/share/vm/oops/instanceKlass.hpp b/hotspot/src/share/vm/oops/instanceKlass.hpp index 330f373f001..cdba02b1119 100644 --- a/hotspot/src/share/vm/oops/instanceKlass.hpp +++ b/hotspot/src/share/vm/oops/instanceKlass.hpp @@ -783,7 +783,7 @@ public: void set_cached_class_file(JvmtiCachedClassFileData *data) { _cached_class_file = data; } - JvmtiCachedClassFileData * get_cached_class_file() { return _cached_class_file; } + JvmtiCachedClassFileData * get_cached_class_file(); jint get_cached_class_file_len(); unsigned char * get_cached_class_file_bytes(); @@ -795,6 +795,13 @@ public: return _jvmti_cached_class_field_map; } +#if INCLUDE_CDS + void set_archived_class_data(JvmtiCachedClassFileData* data) { + _cached_class_file = data; + } + + JvmtiCachedClassFileData * get_archived_class_data(); +#endif // INCLUDE_CDS #else // INCLUDE_JVMTI static void purge_previous_versions(InstanceKlass* ik) { return; }; diff --git a/hotspot/src/share/vm/utilities/debug.cpp b/hotspot/src/share/vm/utilities/debug.cpp index d48479c303d..a6fd15bdaf1 100644 --- a/hotspot/src/share/vm/utilities/debug.cpp +++ b/hotspot/src/share/vm/utilities/debug.cpp @@ -282,6 +282,12 @@ void report_untested(const char* file, int line, const char* message) { } void report_out_of_shared_space(SharedSpaceType shared_space) { + if (shared_space == SharedOptional) { + // The estimated shared_optional_space size is large enough + // for all class bytes. It should not run out of space. + ShouldNotReachHere(); + } + static const char* name[] = { "shared read only space", "shared read write space", diff --git a/hotspot/src/share/vm/utilities/debug.hpp b/hotspot/src/share/vm/utilities/debug.hpp index d5da6db4cab..3a4483e681e 100644 --- a/hotspot/src/share/vm/utilities/debug.hpp +++ b/hotspot/src/share/vm/utilities/debug.hpp @@ -271,7 +271,8 @@ enum SharedSpaceType { SharedReadOnly, SharedReadWrite, SharedMiscData, - SharedMiscCode + SharedMiscCode, + SharedOptional }; void report_out_of_shared_space(SharedSpaceType space_type); diff --git a/hotspot/test/runtime/SharedArchiveFile/CDSTestUtils.java b/hotspot/test/runtime/SharedArchiveFile/CDSTestUtils.java new file mode 100644 index 00000000000..8392b756eab --- /dev/null +++ b/hotspot/test/runtime/SharedArchiveFile/CDSTestUtils.java @@ -0,0 +1,115 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.io.IOException; +import java.io.File; +import java.io.FileOutputStream; +import java.io.PrintStream; +import jdk.test.lib.process.OutputAnalyzer; + + +// This class contains common test utilities for CDS testing +public class CDSTestUtils { + + // check result of 'dump' operation + public static void checkDump(OutputAnalyzer output, String... extraMatches) + throws Exception { + + output.shouldContain("Loading classes to share"); + output.shouldHaveExitValue(0); + + for (String match : extraMatches) { + output.shouldContain(match); + } + } + + + // check the output for indication that mapping of the archive failed + public static boolean isUnableToMap(OutputAnalyzer output) { + String outStr = output.getOutput(); + if ((output.getExitValue() == 1) && ( + outStr.contains("Unable to reserve shared space at required address") || + outStr.contains("Unable to map ReadOnly shared space at required address") || + outStr.contains("Unable to map ReadWrite shared space at required address") || + outStr.contains("Unable to map MiscData shared space at required address") || + outStr.contains("Unable to map MiscCode shared space at required address") || + outStr.contains("Unable to map shared string space at required address") || + outStr.contains("Could not allocate metaspace at a compatible address") || + outStr.contains("Unable to allocate shared string space: range is not within java heap") )) + { + return true; + } + + return false; + } + + // check result of 'exec' operation, that is when JVM is run using the archive + public static void checkExec(OutputAnalyzer output, String... extraMatches) throws Exception { + if (isUnableToMap(output)) { + System.out.println("Unable to map shared archive: test did not complete; assumed PASS"); + return; + } + output.shouldContain("sharing"); + output.shouldHaveExitValue(0); + + for (String match : extraMatches) { + output.shouldContain(match); + } + } + + + // get the file object for the test artifact + private static File getTestArtifactFile(String prefix, String name) { + File dir = new File(System.getProperty("test.classes", ".")); + return new File(dir, prefix + name); + } + + + // create file containing the specified class list + public static File makeClassList(String testCaseName, String classes[]) + throws Exception { + + File classList = getTestArtifactFile(testCaseName, "test.classlist"); + FileOutputStream fos = new FileOutputStream(classList); + PrintStream ps = new PrintStream(fos); + + addToClassList(ps, classes); + + ps.close(); + fos.close(); + + return classList; + } + + + private static void addToClassList(PrintStream ps, String classes[]) + throws IOException + { + if (classes != null) { + for (String s : classes) { + ps.println(s); + } + } + } + +} diff --git a/hotspot/test/runtime/SharedArchiveFile/serviceability/transformRelatedClasses/Implementor.java b/hotspot/test/runtime/SharedArchiveFile/serviceability/transformRelatedClasses/Implementor.java new file mode 100644 index 00000000000..96320a39468 --- /dev/null +++ b/hotspot/test/runtime/SharedArchiveFile/serviceability/transformRelatedClasses/Implementor.java @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2016, 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. + */ + +public class Implementor implements Interface { + public static void main(String[] args) { + System.out.println("Implementor: entering main()"); + test(); + } + + public static void test() { + // from interface + (new Implementor()).printString(); + // from implementor + System.out.println(TransformUtil.ChildCheckPattern + + TransformUtil.BeforePattern); + } +} diff --git a/hotspot/test/runtime/SharedArchiveFile/serviceability/transformRelatedClasses/Interface.java b/hotspot/test/runtime/SharedArchiveFile/serviceability/transformRelatedClasses/Interface.java new file mode 100644 index 00000000000..1510915ca26 --- /dev/null +++ b/hotspot/test/runtime/SharedArchiveFile/serviceability/transformRelatedClasses/Interface.java @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2016, 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. + */ + +public interface Interface { + public static final String stringToBeTransformed = + TransformUtil.ParentCheckPattern + TransformUtil.BeforePattern; + + default void printString() { + System.out.println(stringToBeTransformed); + } +} diff --git a/hotspot/test/runtime/SharedArchiveFile/serviceability/transformRelatedClasses/SubClass.java b/hotspot/test/runtime/SharedArchiveFile/serviceability/transformRelatedClasses/SubClass.java new file mode 100644 index 00000000000..e9205918b0b --- /dev/null +++ b/hotspot/test/runtime/SharedArchiveFile/serviceability/transformRelatedClasses/SubClass.java @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2016, 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. + */ + +public class SubClass extends SuperClazz { + public static void main(String[] args) { + System.out.println("SubClass: entering main()"); + test(); + } + + public static void test() { + // The line below will be used to check for successful class transformation + System.out.println(TransformUtil.ChildCheckPattern + + TransformUtil.BeforePattern); + (new SubClass()).callParent(); + } + + private void callParent() { + super.testParent(); + } +} diff --git a/hotspot/test/runtime/SharedArchiveFile/serviceability/transformRelatedClasses/SuperClazz.java b/hotspot/test/runtime/SharedArchiveFile/serviceability/transformRelatedClasses/SuperClazz.java new file mode 100644 index 00000000000..a3224c7f91e --- /dev/null +++ b/hotspot/test/runtime/SharedArchiveFile/serviceability/transformRelatedClasses/SuperClazz.java @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2016, 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. + */ + + +public class SuperClazz { + public static void testParent() { + System.out.println("SuperClazz: entering testParent()"); + + // The line below will be used to check for successful class transformation + System.out.println(TransformUtil.ParentCheckPattern + TransformUtil.BeforePattern); + } +} diff --git a/hotspot/test/runtime/SharedArchiveFile/serviceability/transformRelatedClasses/TestEntry.java b/hotspot/test/runtime/SharedArchiveFile/serviceability/transformRelatedClasses/TestEntry.java new file mode 100644 index 00000000000..b388af2a15c --- /dev/null +++ b/hotspot/test/runtime/SharedArchiveFile/serviceability/transformRelatedClasses/TestEntry.java @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2016, 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 Entry - a single entry in a test table +// that defines a test case +// See TransformRelatedClasses.java for more details +public class TestEntry { + int testCaseId; + boolean transformParent; + boolean transformChild; + boolean isParentExpectedShared; + boolean isChildExpectedShared; + + public TestEntry(int testCaseId, + boolean transformParent, boolean transformChild, + boolean isParentExpectedShared, boolean isChildExpectedShared) { + this.testCaseId = testCaseId; + this.transformParent = transformParent; + this.transformChild = transformChild; + this.isParentExpectedShared = isParentExpectedShared; + this.isChildExpectedShared = isChildExpectedShared; + } +} + diff --git a/hotspot/test/runtime/SharedArchiveFile/serviceability/transformRelatedClasses/TransformInterfaceAndImplementor.java b/hotspot/test/runtime/SharedArchiveFile/serviceability/transformRelatedClasses/TransformInterfaceAndImplementor.java new file mode 100644 index 00000000000..7cf738baae1 --- /dev/null +++ b/hotspot/test/runtime/SharedArchiveFile/serviceability/transformRelatedClasses/TransformInterfaceAndImplementor.java @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2016, 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 Exercise initial transformation (ClassFileLoadHook) + * with CDS with Interface/Implementor pair + * @library /test/lib /runtime/SharedArchiveFile /testlibrary/jvmti + * @requires (vm.opt.UseCompressedOops == null) | (vm.opt.UseCompressedOops == true) + * @requires vm.flavor != "minimal" + * @modules java.base/jdk.internal.misc + * jdk.jartool/sun.tools.jar + * java.management + * java.instrument + * @build TransformUtil TransformerAgent Interface Implementor + * @run main/othervm TransformRelatedClasses Interface Implementor + */ + +// Clarification on @requires declarations: +// CDS is not supported w/o the use of Compressed OOPs +// JVMTI's ClassFileLoadHook is not supported under minimal VM + +// This test class uses TransformRelatedClasses to do its work. +// The goal of this test is to exercise transformation of related interface +// and its implementor in combination with CDS. +// The transformation is done via ClassFileLoadHook mechanism. +// Both superclass and subclass reside in the shared archive. +// The test consists of 4 test cases where transformation is applied +// to an interface and an implementor in a combinatorial manner. +// Please see TransformRelatedClasses.java for details. diff --git a/hotspot/test/runtime/SharedArchiveFile/serviceability/transformRelatedClasses/TransformRelatedClasses.java b/hotspot/test/runtime/SharedArchiveFile/serviceability/transformRelatedClasses/TransformRelatedClasses.java new file mode 100644 index 00000000000..25cc42dfd82 --- /dev/null +++ b/hotspot/test/runtime/SharedArchiveFile/serviceability/transformRelatedClasses/TransformRelatedClasses.java @@ -0,0 +1,179 @@ +/* + * Copyright (c) 2016, 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. + */ + + +// This is the main test class for testing transformation of related classes +// in combination with CDS, to ensure these features work well together. +// The relationships that can be tested using this test class are: +// superclass/subclass, and interface/implementor relationships. +// +// The test uses combinatorial approach. +// For details on test table and test cases see main() method in this class. +// +// This test consists of multiple classes for better flexibility and reuse, +// and also relies on certain common utility code. +// Here are the details on the structure of the test +// +// Structure of the test: +// TransformRelatedClasses -- common main test driver +// The TransformRelatedClasses is invoked from test driver classes: +// TransformInterfaceAndImplementor, TransformSuperAndSubClasses +// It is responsible for preparing test artifacts (test jar, agent jar +// and the shared archive), running test cases and checking the results. +// The following test classes below are launched in a sub-process with use +// of shared archive: +// SuperClazz, SubClass -- super/sub class pair under test +// Interface, Implementor -- classes under test +// This test will transform these classes, based on the test case data, +// by changing a predefined unique string in each class. +// For more details, see the test classes' code and comments. +// +// Other related classes: +// TestEntry - a class representing a single test case, as test entry in the table +// TransformTestCommon - common methods for transformation test cases +// +// Other utility/helper classes and files used in this test: +// TransformerAgent - an agent that is used when JVM-under-test is executed +// to transform specific strings inside specified classes +// TransformerAgent.mf - accompanies transformer agent +// CDSTestUtils - Test Utilities common to all CDS tests + +import java.io.File; +import java.util.ArrayList; +import jdk.test.lib.process.OutputAnalyzer; +import jdk.test.lib.process.ProcessTools; + + +public class TransformRelatedClasses { + static final String archiveName = "./TransformRelatedClasses.jsa"; + static String agentClasses[] = { + "TransformerAgent", + "TransformerAgent$SimpleTransformer", + "TransformUtil" + }; + + String parent; + String child; + String[] testClasses = new String[2]; + String[] testNames = new String[2]; + String testJar; + String agentJar; + + + private static void log(String msg) { + System.out.println("TransformRelatedClasses: " + msg); + } + + + // This class is intended to test 2 parent-child relationships: + // 1. Base Class (parent) and Derived Class (child) + // 2. Interface (parent) and Implementor (child) + // Parameters to main(): parent, child + public static void main(String args[]) throws Exception { + TransformRelatedClasses test = new TransformRelatedClasses(args[0], args[1]); + test.prepare(); + + // Test Table + // TestEntry: (testCaseId, transformParent, tranformChild, + // isParentExpectedShared, isChildExpectedShared) + ArrayList testTable = new ArrayList<>(); + + // base case - no tranformation - all expected to be shared + testTable.add(new TestEntry(0, false, false, true, true)); + + // transform parent only - both parent and child should not be shared + testTable.add(new TestEntry(1, true, false, false, false)); + + // transform parent and child - both parent and child should not be shared + testTable.add(new TestEntry(2, true, true, false, false)); + + // transform child only - parent should still be shared, but not child + testTable.add(new TestEntry(3, false, true, true, false)); + + // run the tests + for (TestEntry entry : testTable) { + test.runTest(entry); + } + } + + + public TransformRelatedClasses(String parent, String child) { + log("Constructor: parent = " + parent + ", child = " + child); + this.parent = parent; + this.child = child; + testClasses[0] = parent; + testClasses[1] = child; + testNames[0] = parent.replace('.', '/'); + testNames[1] = child.replace('.', '/'); + } + + + // same test jar and archive can be used for all test cases + private void prepare() throws Exception { + // create agent jar + // Agent is the same for all test cases + String pathToManifest = "../../../../testlibrary/jvmti/TransformerAgent.mf"; + agentJar = ClassFileInstaller.writeJar("TransformerAgent.jar", + ClassFileInstaller.Manifest.fromSourceFile(pathToManifest), + agentClasses); + + // create a test jar + testJar = + ClassFileInstaller.writeJar(parent + "-" + child + ".jar", + testClasses); + + // create an archive + File classList = CDSTestUtils.makeClassList("transform-" + parent, + testNames); + ProcessBuilder pb = ProcessTools.createJavaProcessBuilder(true, + "-Xbootclasspath/a:" + testJar, + "-XX:+UnlockDiagnosticVMOptions", + "-XX:ExtraSharedClassListFile=" + + classList.getPath(), + "-XX:SharedArchiveFile=" + archiveName, + "-XX:+PrintSharedSpaces", + "-Xshare:dump"); + OutputAnalyzer out = new OutputAnalyzer(pb.start()); + CDSTestUtils.checkDump(out); + } + + + private void runTest(TestEntry entry) throws Exception { + log("runTest(): testCaseId = " + entry.testCaseId); + + // execute with archive + String agentParam = "-javaagent:" + agentJar + "=" + + TransformTestCommon.getAgentParams(entry, parent, child); + + ProcessBuilder pb = ProcessTools.createJavaProcessBuilder(true, + "-Xbootclasspath/a:" + testJar, + "-XX:+UnlockDiagnosticVMOptions", + "-XX:SharedArchiveFile=" + archiveName, + "-Xlog:class+load=info", + "-Xshare:on", "-showversion", + agentParam, child); + OutputAnalyzer out = new OutputAnalyzer(pb.start()); + + TransformTestCommon.checkResults(entry, out, parent, child); + } +} diff --git a/hotspot/test/runtime/SharedArchiveFile/serviceability/transformRelatedClasses/TransformSuperAndSubClasses.java b/hotspot/test/runtime/SharedArchiveFile/serviceability/transformRelatedClasses/TransformSuperAndSubClasses.java new file mode 100644 index 00000000000..1309c1b4a35 --- /dev/null +++ b/hotspot/test/runtime/SharedArchiveFile/serviceability/transformRelatedClasses/TransformSuperAndSubClasses.java @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2016, 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 Exercise initial transformation (ClassFileLoadHook) + * with CDS with SubClass and SuperClass + * @library /test/lib /runtime/SharedArchiveFile /testlibrary/jvmti + * @requires (vm.opt.UseCompressedOops == null) | (vm.opt.UseCompressedOops == true) + * @requires vm.flavor != "minimal" + * @modules java.base/jdk.internal.misc + * jdk.jartool/sun.tools.jar + * java.management + * java.instrument + * @build TransformUtil TransformerAgent SubClass SuperClazz + * @run main/othervm TransformRelatedClasses SuperClazz SubClass +*/ + +// Clarification on @requires declarations: +// CDS is not supported w/o the use of Compressed OOPs +// JVMTI's ClassFileLoadHook is not supported under minimal VM + +// This test class uses TransformRelatedClasses to do its work. +// The goal of this test is to exercise transformation of related superclass +// and subclass in combination with CDS. +// The transformation is done via ClassFileLoadHook mechanism. +// Both superclass and subclass reside in the shared archive. +// The test consists of 4 test cases where transformation is applied +// to a parent and child in combinatorial manner. +// Please see TransformRelatedClasses.java for details. diff --git a/hotspot/test/runtime/SharedArchiveFile/serviceability/transformRelatedClasses/TransformSuperSubTwoPckgs.java b/hotspot/test/runtime/SharedArchiveFile/serviceability/transformRelatedClasses/TransformSuperSubTwoPckgs.java new file mode 100644 index 00000000000..da35b7e0336 --- /dev/null +++ b/hotspot/test/runtime/SharedArchiveFile/serviceability/transformRelatedClasses/TransformSuperSubTwoPckgs.java @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2016, 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 Exercise initial transformation (ClassFileLoadHook) + * with CDS with SubClass and SuperClass, each lives in own separate package + * @library /test/lib /runtime/SharedArchiveFile /testlibrary/jvmti + * @requires (vm.opt.UseCompressedOops == null) | (vm.opt.UseCompressedOops == true) + * @requires vm.flavor != "minimal" + * @modules java.base/jdk.internal.misc + * jdk.jartool/sun.tools.jar + * java.management + * java.instrument + * @build TransformUtil TransformerAgent SubClass SuperClazz + * @compile myPkg2/SubClass.java myPkg1/SuperClazz.java + * @run main/othervm TransformRelatedClasses myPkg1.SuperClazz myPkg2.SubClass +*/ + +// Clarification on @requires declarations: +// CDS is not supported w/o the use of Compressed OOPs +// JVMTI's ClassFileLoadHook is not supported under minimal VM + +// This test class uses TransformRelatedClasses to do its work. +// The goal of this test is to exercise transformation of related superclass +// and subclass in combination with CDS; each class lives in its own package. +// The transformation is done via ClassFileLoadHook mechanism. +// Both superclass and subclass reside in the shared archive. +// The test consists of 4 test cases where transformation is applied +// to a parent and child in combinatorial manner. +// Please see TransformRelatedClasses.java for details. diff --git a/hotspot/test/runtime/SharedArchiveFile/serviceability/transformRelatedClasses/TransformTestCommon.java b/hotspot/test/runtime/SharedArchiveFile/serviceability/transformRelatedClasses/TransformTestCommon.java new file mode 100644 index 00000000000..00e25bce83c --- /dev/null +++ b/hotspot/test/runtime/SharedArchiveFile/serviceability/transformRelatedClasses/TransformTestCommon.java @@ -0,0 +1,114 @@ +/* + * Copyright (c) 2016, 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 jdk.test.lib.process.OutputAnalyzer; + + +// This class contains methods common to all transformation test cases +public class TransformTestCommon { + + // get parameters to an agent depending on the test case + // these parameters will instruct the agent which classes should be + // transformed + public static String getAgentParams(TestEntry entry, + String parent, String child) { + + if (entry.transformParent && entry.transformChild) + return parent + "," + child; + if (entry.transformParent) + return parent; + if (entry.transformChild) + return child; + + return ""; + } + + + private static void checkTransformationResults(TestEntry entry, + OutputAnalyzer out) + throws Exception { + + if (entry.transformParent) + out.shouldContain(TransformUtil.ParentCheckPattern + + TransformUtil.AfterPattern); + + if (entry.transformChild) + out.shouldContain(TransformUtil.ChildCheckPattern + + TransformUtil.AfterPattern); + } + + + private static void checkSharingByClass(TestEntry entry, OutputAnalyzer out, + String parent, String child) + throws Exception { + + String parentSharedMatch = parent + " source: shared objects file"; + String childSharedMatch = child + " source: shared objects file"; + + if (entry.isParentExpectedShared) + out.shouldContain(parentSharedMatch); + else + out.shouldNotContain(parentSharedMatch); + + if (entry.isChildExpectedShared) + out.shouldContain(childSharedMatch); + else + out.shouldNotContain(childSharedMatch); + } + + + // Both parent and child classes should be passed to ClassFileTransformer.transform() + // exactly once. + private static void checkTransformationCounts(TestEntry entry, OutputAnalyzer out, + String parent, String child) + throws Exception { + + String patternBase = "TransformerAgent: SimpleTransformer called for: "; + + out.shouldContain(patternBase + child + "@1"); + out.shouldContain(patternBase + parent + "@1"); + + out.shouldNotContain(patternBase + child + "@2"); + out.shouldNotContain(patternBase + parent + "@2"); + } + + + public static void checkResults(TestEntry entry, OutputAnalyzer out, + String parent, String child) + throws Exception { + + // If we were not able to map an archive, + // then do not perform other checks, since + // there was no sharing at all + if (CDSTestUtils.isUnableToMap(out)) + return; + + String childVmName = child.replace('.', '/'); + String parentVmName = parent.replace('.', '/'); + + CDSTestUtils.checkExec(out); + checkTransformationCounts(entry, out, parentVmName, childVmName); + checkTransformationResults(entry, out); + checkSharingByClass(entry, out, parent, child); + } +} diff --git a/hotspot/test/runtime/SharedArchiveFile/serviceability/transformRelatedClasses/myPkg1/SuperClazz.java b/hotspot/test/runtime/SharedArchiveFile/serviceability/transformRelatedClasses/myPkg1/SuperClazz.java new file mode 100644 index 00000000000..c04770dbc3c --- /dev/null +++ b/hotspot/test/runtime/SharedArchiveFile/serviceability/transformRelatedClasses/myPkg1/SuperClazz.java @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2016, 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 myPkg1; + +public class SuperClazz { + public static void testParent() { + System.out.println("SuperClazz: entering testParent()"); + + // The line below will be used to check for successful class transformation + System.out.println("parent-transform-check: this-should-be-transformed"); + } +} diff --git a/hotspot/test/runtime/SharedArchiveFile/serviceability/transformRelatedClasses/myPkg2/SubClass.java b/hotspot/test/runtime/SharedArchiveFile/serviceability/transformRelatedClasses/myPkg2/SubClass.java new file mode 100644 index 00000000000..ab67b3a6bfd --- /dev/null +++ b/hotspot/test/runtime/SharedArchiveFile/serviceability/transformRelatedClasses/myPkg2/SubClass.java @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2016, 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 myPkg2; + +import myPkg1.SuperClazz; + +public class SubClass extends SuperClazz { + public static void main(String[] args) { + System.out.println("SubClass: entering main()"); + test(); + } + + public static void test() { + // The line below will be used to check for successful class transformation + System.out.println("child-transform-check: this-should-be-transformed"); + (new SubClass()).callParent(); + + // Get the system packages, which should contain myPkg1 and myPkag2 + Package[] pkgs = Package.getPackages(); + for (int i = 0; i < pkgs.length; i++) { + if (pkgs[i].getName().equals("myPkg1")) { + for (int j = 0; j < pkgs.length; j++) { + if (pkgs[j].getName().equals("myPkg2")) { + return; // found myPkg1 & myPkg1 + } + } + } + } + throw new RuntimeException("Missing system package"); + } + + private void callParent() { + super.testParent(); + } +} diff --git a/hotspot/test/testlibrary/jvmti/TransformUtil.java b/hotspot/test/testlibrary/jvmti/TransformUtil.java new file mode 100644 index 00000000000..dfaf61a42a3 --- /dev/null +++ b/hotspot/test/testlibrary/jvmti/TransformUtil.java @@ -0,0 +1,75 @@ +/* + * Copyright (c) 2016, 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. + */ + + +public class TransformUtil { + public static final String BeforePattern = "this-should-be-transformed"; + public static final String AfterPattern = "this-has-been--transformed"; + public static final String ParentCheckPattern = "parent-transform-check: "; + public static final String ChildCheckPattern = "child-transform-check: "; + + /** + * @return the number of occurrences of the from string that + * have been replaced. + */ + public static int replace(byte buff[], String from, String to) { + if (to.length() != from.length()) { + throw new RuntimeException("bad strings"); + } + byte f[] = asciibytes(from); + byte t[] = asciibytes(to); + byte f0 = f[0]; + + int numReplaced = 0; + int max = buff.length - f.length; + for (int i = 0; i < max; ) { + if (buff[i] == f0 && replace(buff, f, t, i)) { + i += f.length; + numReplaced++; + } else { + i++; + } + } + return numReplaced; + } + + public static boolean replace(byte buff[], byte f[], byte t[], int i) { + for (int x = 0; x < f.length; x++) { + if (buff[x+i] != f[x]) { + return false; + } + } + for (int x = 0; x < f.length; x++) { + buff[x+i] = t[x]; + } + return true; + } + + static byte[] asciibytes(String s) { + byte b[] = new byte[s.length()]; + for (int i = 0; i < b.length; i++) { + b[i] = (byte)s.charAt(i); + } + return b; + } +} diff --git a/hotspot/test/testlibrary/jvmti/TransformerAgent.java b/hotspot/test/testlibrary/jvmti/TransformerAgent.java new file mode 100644 index 00000000000..7f520050487 --- /dev/null +++ b/hotspot/test/testlibrary/jvmti/TransformerAgent.java @@ -0,0 +1,100 @@ +/* + * Copyright (c) 2016, 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.lang.instrument.ClassFileTransformer; +import java.lang.instrument.IllegalClassFormatException; +import java.lang.instrument.Instrumentation; +import java.security.ProtectionDomain; +import java.util.HashMap; + +// This is a test utility class used to transform +// specified classes via initial transformation (ClassFileLoadHook). +// Names of classes to be transformed are supplied as arguments, +// the phrase to be transformed is a hard-coded predefined +// fairly unique phrase. + +public class TransformerAgent { + private static String[] classesToTransform; + + + private static void log(String msg) { + System.out.println("TransformerAgent: " + msg); + } + + + // arguments are comma-separated list of classes to transform + public static void premain(String agentArguments, Instrumentation instrumentation) { + log("premain() is called, arguments = " + agentArguments); + classesToTransform = agentArguments.split(","); + instrumentation.addTransformer(new SimpleTransformer(), /*canRetransform=*/true); + } + + + public static void agentmain(String args, Instrumentation inst) throws Exception { + log("agentmain() is called"); + premain(args, inst); + } + + + static class SimpleTransformer implements ClassFileTransformer { + public byte[] transform(ClassLoader loader, String name, Class classBeingRedefined, + ProtectionDomain pd, byte[] buffer) throws IllegalClassFormatException { + + log("SimpleTransformer called for: " + name + "@" + incrCounter(name)); + if (!shouldTransform(name)) + return null; + + log("transforming: class name = " + name); + int nrOfReplacements = TransformUtil.replace(buffer, TransformUtil.BeforePattern, + TransformUtil.AfterPattern); + log("replaced the string, nrOfReplacements = " + nrOfReplacements); + return buffer; + } + + // Check class name pattern, since test should only transform certain classes + private static boolean shouldTransform(String name) { + for (String match : classesToTransform) { + if (name.matches(match)) { + log("shouldTransform: match-found, match = " + match); + return true; + } + } + + return false; + } + } + + + static HashMap counterMap = new HashMap<>(); + + static Integer incrCounter(String className) { + Integer i = counterMap.get(className); + if (i == null) { + i = new Integer(1); + } else { + i = new Integer(i.intValue() + 1); + } + counterMap.put(className, i); + return i; + } +} diff --git a/hotspot/test/testlibrary/jvmti/TransformerAgent.mf b/hotspot/test/testlibrary/jvmti/TransformerAgent.mf new file mode 100644 index 00000000000..9f59980a5c2 --- /dev/null +++ b/hotspot/test/testlibrary/jvmti/TransformerAgent.mf @@ -0,0 +1,5 @@ +Manifest-Version: 1.0 +Premain-Class: TransformerAgent +Agent-Class: TransformerAgent +Can-Retransform-Classes: true +Can-Redefine-Classes: false From 368585d0dbf0ddc6231557869ed493f4a7c34a2d Mon Sep 17 00:00:00 2001 From: Lois Foltan Date: Mon, 19 Sep 2016 12:04:28 -0400 Subject: [PATCH 10/69] 8163406: The fixup_module_list must be protected by Module_lock when inserting new entries In java_lang_Class::create_mirror, restructure the check for adding a class to the fixup_module_list, guarded by Module_lock. Reviewed-by: acorn, coleenp, dholmes, zgu --- .../src/share/vm/classfile/classLoader.cpp | 4 +- .../src/share/vm/classfile/javaClasses.cpp | 49 ++++++++++++++----- .../src/share/vm/classfile/javaClasses.hpp | 1 + .../src/share/vm/classfile/moduleEntry.cpp | 21 +++++--- .../src/share/vm/classfile/moduleEntry.hpp | 18 +++---- hotspot/src/share/vm/classfile/modules.cpp | 7 +-- hotspot/src/share/vm/oops/instanceKlass.cpp | 4 +- hotspot/src/share/vm/oops/klass.cpp | 2 +- hotspot/src/share/vm/oops/typeArrayKlass.cpp | 4 +- .../share/vm/utilities/hashtable.inline.hpp | 10 ++-- 10 files changed, 75 insertions(+), 45 deletions(-) diff --git a/hotspot/src/share/vm/classfile/classLoader.cpp b/hotspot/src/share/vm/classfile/classLoader.cpp index 2cb586f1f54..6e74496d80c 100644 --- a/hotspot/src/share/vm/classfile/classLoader.cpp +++ b/hotspot/src/share/vm/classfile/classLoader.cpp @@ -1358,7 +1358,7 @@ ClassFileStream* ClassLoader::search_module_entries(const GrowableArraydo_local_static_fields(&initialize_static_field, mirror, CHECK); } +// Set the java.lang.reflect.Module module field in the java_lang_Class mirror +void java_lang_Class::set_mirror_module_field(KlassHandle k, Handle mirror, Handle module, TRAPS) { + if (module.is_null()) { + // During startup, the module may be NULL only if java.base has not been defined yet. + // Put the class on the fixup_module_list to patch later when the java.lang.reflect.Module + // for java.base is known. + assert(!Universe::is_module_initialized(), "Incorrect java.lang.reflect.Module pre module system initialization"); + MutexLocker m1(Module_lock, THREAD); + // Keep list of classes needing java.base module fixup + if (!ModuleEntryTable::javabase_defined()) { + if (fixup_module_field_list() == NULL) { + GrowableArray* list = + new (ResourceObj::C_HEAP, mtModule) GrowableArray(500, true); + set_fixup_module_field_list(list); + } + k->class_loader_data()->inc_keep_alive(); + fixup_module_field_list()->push(k()); + } else { + // java.base was defined at some point between calling create_mirror() + // and obtaining the Module_lock, patch this particular class with java.base. + ModuleEntry *javabase_entry = ModuleEntryTable::javabase_moduleEntry(); + assert(javabase_entry != NULL && javabase_entry->module() != NULL, + "Setting class module field, java.base should be defined"); + Handle javabase_handle(THREAD, JNIHandles::resolve(javabase_entry->module())); + set_module(mirror(), javabase_handle()); + } + } else { + assert(Universe::is_module_initialized() || + (ModuleEntryTable::javabase_defined() && + (module() == JNIHandles::resolve(ModuleEntryTable::javabase_moduleEntry()->module()))), + "Incorrect java.lang.reflect.Module specification while creating mirror"); + set_module(mirror(), module()); + } +} + void java_lang_Class::create_mirror(KlassHandle k, Handle class_loader, Handle module, Handle protection_domain, TRAPS) { assert(k->java_mirror() == NULL, "should only assign mirror once"); @@ -835,25 +870,13 @@ void java_lang_Class::create_mirror(KlassHandle k, Handle class_loader, set_class_loader(mirror(), class_loader()); // set the module field in the java_lang_Class instance - // This may be null during bootstrap but will get fixed up later on. - set_module(mirror(), module()); + set_mirror_module_field(k, mirror, module, THREAD); // Setup indirection from klass->mirror last // after any exceptions can happen during allocations. if (!k.is_null()) { k->set_java_mirror(mirror()); } - - // Keep list of classes needing java.base module fixup. - if (!ModuleEntryTable::javabase_defined()) { - if (fixup_module_field_list() == NULL) { - GrowableArray* list = - new (ResourceObj::C_HEAP, mtModule) GrowableArray(500, true); - set_fixup_module_field_list(list); - } - k->class_loader_data()->inc_keep_alive(); - fixup_module_field_list()->push(k()); - } } else { if (fixup_mirror_list() == NULL) { GrowableArray* list = diff --git a/hotspot/src/share/vm/classfile/javaClasses.hpp b/hotspot/src/share/vm/classfile/javaClasses.hpp index 307cd65d5f8..448bb4d5bd8 100644 --- a/hotspot/src/share/vm/classfile/javaClasses.hpp +++ b/hotspot/src/share/vm/classfile/javaClasses.hpp @@ -219,6 +219,7 @@ class java_lang_Class : AllStatic { static void set_class_loader(oop java_class, oop class_loader); static void set_component_mirror(oop java_class, oop comp_mirror); static void initialize_mirror_fields(KlassHandle k, Handle mirror, Handle protection_domain, TRAPS); + static void set_mirror_module_field(KlassHandle K, Handle mirror, Handle module, TRAPS); public: static void compute_offsets(); diff --git a/hotspot/src/share/vm/classfile/moduleEntry.cpp b/hotspot/src/share/vm/classfile/moduleEntry.cpp index a8b67c54e64..2be85c2ebd8 100644 --- a/hotspot/src/share/vm/classfile/moduleEntry.cpp +++ b/hotspot/src/share/vm/classfile/moduleEntry.cpp @@ -92,7 +92,7 @@ bool ModuleEntry::can_read(ModuleEntry* m) const { // read java.base. If either of these conditions // hold, readability has been established. if (!this->is_named() || - (m == ModuleEntryTable::javabase_module())) { + (m == ModuleEntryTable::javabase_moduleEntry())) { return true; } @@ -358,16 +358,27 @@ void ModuleEntryTable::finalize_javabase(Handle module_handle, Symbol* version, } // Set java.lang.reflect.Module, version and location for java.base - ModuleEntry* jb_module = javabase_module(); + ModuleEntry* jb_module = javabase_moduleEntry(); assert(jb_module != NULL, "java.base ModuleEntry not defined"); - jb_module->set_module(boot_loader_data->add_handle(module_handle)); jb_module->set_version(version); jb_module->set_location(location); + // Once java.base's ModuleEntry _module field is set with the known + // java.lang.reflect.Module, java.base is considered "defined" to the VM. + jb_module->set_module(boot_loader_data->add_handle(module_handle)); + // Store pointer to the ModuleEntry for java.base in the java.lang.reflect.Module object. java_lang_reflect_Module::set_module_entry(module_handle(), jb_module); + + // Patch any previously loaded classes' module field with java.base's java.lang.reflect.Module. + patch_javabase_entries(module_handle); } +// Within java.lang.Class instances there is a java.lang.reflect.Module field +// that must be set with the defining module. During startup, prior to java.base's +// definition, classes needing their module field set are added to the fixup_module_list. +// Their module field is set once java.base's java.lang.reflect.Module is known to the VM. void ModuleEntryTable::patch_javabase_entries(Handle module_handle) { + assert(Module_lock->owned_by_self(), "should have the Module_lock"); if (module_handle.is_null()) { fatal("Unable to patch the module field of classes loaded prior to java.base's definition, invalid java.lang.reflect.Module"); } @@ -389,9 +400,7 @@ void ModuleEntryTable::patch_javabase_entries(Handle module_handle) { for (int i = 0; i < list_length; i++) { Klass* k = list->at(i); assert(k->is_klass(), "List should only hold classes"); - Thread* THREAD = Thread::current(); - KlassHandle kh(THREAD, k); - java_lang_Class::fixup_module_field(kh, module_handle); + java_lang_Class::fixup_module_field(KlassHandle(k), module_handle); k->class_loader_data()->dec_keep_alive(); } diff --git a/hotspot/src/share/vm/classfile/moduleEntry.hpp b/hotspot/src/share/vm/classfile/moduleEntry.hpp index 8ec8237ec3f..82f0747a2ae 100644 --- a/hotspot/src/share/vm/classfile/moduleEntry.hpp +++ b/hotspot/src/share/vm/classfile/moduleEntry.hpp @@ -78,11 +78,11 @@ public: _must_walk_reads = false; } - Symbol* name() const { return literal(); } - void set_name(Symbol* n) { set_literal(n); } + Symbol* name() const { return literal(); } + void set_name(Symbol* n) { set_literal(n); } - jobject module() const { return _module; } - void set_module(jobject j) { _module = j; } + jobject module() const { return _module; } + void set_module(jobject j) { _module = j; } // The shared ProtectionDomain reference is set once the VM loads a shared class // originated from the current Module. The referenced ProtectionDomain object is @@ -217,13 +217,13 @@ public: // Special handling for unnamed module, one per class loader's ModuleEntryTable void create_unnamed_module(ClassLoaderData* loader_data); - ModuleEntry* unnamed_module() { return _unnamed_module; } + ModuleEntry* unnamed_module() { return _unnamed_module; } // Special handling for java.base - static ModuleEntry* javabase_module() { return _javabase_module; } - static void set_javabase_module(ModuleEntry* java_base) { _javabase_module = java_base; } - static bool javabase_defined() { return ((_javabase_module != NULL) && - (_javabase_module->module() != NULL)); } + static ModuleEntry* javabase_moduleEntry() { return _javabase_module; } + static void set_javabase_moduleEntry(ModuleEntry* java_base) { _javabase_module = java_base; } + static bool javabase_defined() { return ((_javabase_module != NULL) && + (_javabase_module->module() != NULL)); } static void finalize_javabase(Handle module_handle, Symbol* version, Symbol* location); static void patch_javabase_entries(Handle module_handle); diff --git a/hotspot/src/share/vm/classfile/modules.cpp b/hotspot/src/share/vm/classfile/modules.cpp index 8986eb64e96..f7b15b141d7 100644 --- a/hotspot/src/share/vm/classfile/modules.cpp +++ b/hotspot/src/share/vm/classfile/modules.cpp @@ -206,7 +206,7 @@ static void define_javabase_module(jobject module, jstring version, assert(pkg_list->length() == 0 || package_table != NULL, "Bad package_table"); // Ensure java.base's ModuleEntry has been created - assert(ModuleEntryTable::javabase_module() != NULL, "No ModuleEntry for java.base"); + assert(ModuleEntryTable::javabase_moduleEntry() != NULL, "No ModuleEntry for java.base"); bool duplicate_javabase = false; { @@ -226,7 +226,7 @@ static void define_javabase_module(jobject module, jstring version, for (int x = 0; x < pkg_list->length(); x++) { // Some of java.base's packages were added early in bootstrapping, ignore duplicates. if (package_table->lookup_only(pkg_list->at(x)) == NULL) { - pkg = package_table->locked_create_entry_or_null(pkg_list->at(x), ModuleEntryTable::javabase_module()); + pkg = package_table->locked_create_entry_or_null(pkg_list->at(x), ModuleEntryTable::javabase_moduleEntry()); assert(pkg != NULL, "Unable to create a java.base package entry"); } // Unable to have a GrowableArray of TempNewSymbol. Must decrement the refcount of @@ -255,9 +255,6 @@ static void define_javabase_module(jobject module, jstring version, log_trace(modules)("define_javabase_module(): creation of package %s for module java.base", (pkg_list->at(x))->as_C_string()); } - - // Patch any previously loaded classes' module field with java.base's jlr.Module. - ModuleEntryTable::patch_javabase_entries(module_handle); } void Modules::define_module(jobject module, jstring version, diff --git a/hotspot/src/share/vm/oops/instanceKlass.cpp b/hotspot/src/share/vm/oops/instanceKlass.cpp index 54e54162c7f..ea49b1baf85 100644 --- a/hotspot/src/share/vm/oops/instanceKlass.cpp +++ b/hotspot/src/share/vm/oops/instanceKlass.cpp @@ -2247,8 +2247,8 @@ void InstanceKlass::set_package(ClassLoaderData* loader_data, TRAPS) { // the java.base module. If a non-java.base package is erroneously placed // in the java.base module it will be caught later when java.base // is defined by ModuleEntryTable::verify_javabase_packages check. - assert(ModuleEntryTable::javabase_module() != NULL, "java.base module is NULL"); - _package_entry = loader_data->packages()->lookup(pkg_name, ModuleEntryTable::javabase_module()); + assert(ModuleEntryTable::javabase_moduleEntry() != NULL, "java.base module is NULL"); + _package_entry = loader_data->packages()->lookup(pkg_name, ModuleEntryTable::javabase_moduleEntry()); } else { assert(loader_data->modules()->unnamed_module() != NULL, "unnamed module is NULL"); _package_entry = loader_data->packages()->lookup(pkg_name, diff --git a/hotspot/src/share/vm/oops/klass.cpp b/hotspot/src/share/vm/oops/klass.cpp index 804d02d0b08..4953f383120 100644 --- a/hotspot/src/share/vm/oops/klass.cpp +++ b/hotspot/src/share/vm/oops/klass.cpp @@ -530,7 +530,7 @@ void Klass::restore_unshareable_info(ClassLoaderData* loader_data, Handle protec InstanceKlass* ik = (InstanceKlass*) k; module_entry = ik->module(); } else { - module_entry = ModuleEntryTable::javabase_module(); + module_entry = ModuleEntryTable::javabase_moduleEntry(); } // Obtain java.lang.reflect.Module, if available Handle module_handle(THREAD, ((module_entry != NULL) ? JNIHandles::resolve(module_entry->module()) : (oop)NULL)); diff --git a/hotspot/src/share/vm/oops/typeArrayKlass.cpp b/hotspot/src/share/vm/oops/typeArrayKlass.cpp index 580c4694512..5ce156026a9 100644 --- a/hotspot/src/share/vm/oops/typeArrayKlass.cpp +++ b/hotspot/src/share/vm/oops/typeArrayKlass.cpp @@ -72,7 +72,7 @@ TypeArrayKlass* TypeArrayKlass::create_klass(BasicType type, null_loader_data->add_class(ak); // Call complete_create_array_klass after all instance variables have been initialized. - complete_create_array_klass(ak, ak->super(), ModuleEntryTable::javabase_module(), CHECK_NULL); + complete_create_array_klass(ak, ak->super(), ModuleEntryTable::javabase_moduleEntry(), CHECK_NULL); return ak; } @@ -347,7 +347,7 @@ const char* TypeArrayKlass::internal_name() const { // A TypeArrayKlass is an array of a primitive type, its defining module is java.base ModuleEntry* TypeArrayKlass::module() const { - return ModuleEntryTable::javabase_module(); + return ModuleEntryTable::javabase_moduleEntry(); } PackageEntry* TypeArrayKlass::package() const { diff --git a/hotspot/src/share/vm/utilities/hashtable.inline.hpp b/hotspot/src/share/vm/utilities/hashtable.inline.hpp index 8497193bdc4..e6d7c61d4d5 100644 --- a/hotspot/src/share/vm/utilities/hashtable.inline.hpp +++ b/hotspot/src/share/vm/utilities/hashtable.inline.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2016, 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 @@ -79,8 +79,8 @@ template inline BasicHashtableEntry* BasicHashtable::bucket(i template inline void HashtableBucket::set_entry(BasicHashtableEntry* l) { - // Warning: Preserve store ordering. The SystemDictionary is read - // without locks. The new SystemDictionaryEntry must be + // Warning: Preserve store ordering. The PackageEntryTable, ModuleEntryTable and + // SystemDictionary are read without locks. The new entry must be // complete before other threads can be allowed to see it // via a store to _buckets[index]. OrderAccess::release_store_ptr(&_entry, l); @@ -88,8 +88,8 @@ template inline void HashtableBucket::set_entry(BasicHashtableEn template inline BasicHashtableEntry* HashtableBucket::get_entry() const { - // Warning: Preserve load ordering. The SystemDictionary is read - // without locks. The new SystemDictionaryEntry must be + // Warning: Preserve load ordering. The PackageEntryTable, ModuleEntryTable and + // SystemDictionary are read without locks. The new entry must be // complete before other threads can be allowed to see it // via a store to _buckets[index]. return (BasicHashtableEntry*) OrderAccess::load_ptr_acquire(&_entry); From 8617484bde07ea83d2a39d4d9093fc75ec5b1a65 Mon Sep 17 00:00:00 2001 From: Kim Barrett Date: Mon, 19 Sep 2016 13:12:26 -0400 Subject: [PATCH 11/69] 8166229: Eliminate ParNew's use of klass_or_null() Use list_ptr_from_klass instead of klass_or_null. Reviewed-by: mgerdin, jmasa --- .../src/share/vm/gc/cms/parNewGeneration.cpp | 21 ++++++++++++------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/hotspot/src/share/vm/gc/cms/parNewGeneration.cpp b/hotspot/src/share/vm/gc/cms/parNewGeneration.cpp index ddc80ce3a76..78839d983f6 100644 --- a/hotspot/src/share/vm/gc/cms/parNewGeneration.cpp +++ b/hotspot/src/share/vm/gc/cms/parNewGeneration.cpp @@ -1366,22 +1366,25 @@ bool ParNewGeneration::take_from_overflow_list_work(ParScanThreadState* par_scan return false; } assert(prefix != NULL && prefix != BUSY, "Error"); - size_t i = 1; oop cur = prefix; - while (i < objsFromOverflow && cur->klass_or_null() != NULL) { - i++; cur = cur->list_ptr_from_klass(); + for (size_t i = 1; i < objsFromOverflow; ++i) { + oop next = cur->list_ptr_from_klass(); + if (next == NULL) break; + cur = next; } + assert(cur != NULL, "Loop postcondition"); // Reattach remaining (suffix) to overflow list - if (cur->klass_or_null() == NULL) { + oop suffix = cur->list_ptr_from_klass(); + if (suffix == NULL) { // Write back the NULL in lieu of the BUSY we wrote // above and it is still the same value. if (_overflow_list == BUSY) { (void) Atomic::cmpxchg_ptr(NULL, &_overflow_list, BUSY); } } else { - assert(cur->klass_or_null() != (Klass*)(address)BUSY, "Error"); - oop suffix = cur->list_ptr_from_klass(); // suffix will be put back on global list + assert(suffix != BUSY, "Error"); + // suffix will be put back on global list cur->set_klass_to_list_ptr(NULL); // break off suffix // It's possible that the list is still in the empty(busy) state // we left it in a short while ago; in that case we may be @@ -1401,8 +1404,10 @@ bool ParNewGeneration::take_from_overflow_list_work(ParScanThreadState* par_scan // Too bad, someone else got in in between; we'll need to do a splice. // Find the last item of suffix list oop last = suffix; - while (last->klass_or_null() != NULL) { - last = last->list_ptr_from_klass(); + while (true) { + oop next = last->list_ptr_from_klass(); + if (next == NULL) break; + last = next; } // Atomically prepend suffix to current overflow list observed_overflow_list = _overflow_list; From c354a6230116c6e7d4999ff62a0ecd5d147be6ff Mon Sep 17 00:00:00 2001 From: Thomas Schatzl Date: Mon, 19 Sep 2016 22:55:26 +0200 Subject: [PATCH 12/69] 8166207: Use of Copy::conjoint_oops_atomic in global mark stack causes crashes on arm64 Use Copy::conjoint_memory_atomic() instead. Reviewed-by: kbarrett --- hotspot/src/share/vm/gc/g1/g1ConcurrentMark.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/hotspot/src/share/vm/gc/g1/g1ConcurrentMark.cpp b/hotspot/src/share/vm/gc/g1/g1ConcurrentMark.cpp index 43b227a7ef8..52a9f4817ab 100644 --- a/hotspot/src/share/vm/gc/g1/g1ConcurrentMark.cpp +++ b/hotspot/src/share/vm/gc/g1/g1ConcurrentMark.cpp @@ -285,7 +285,7 @@ bool G1CMMarkStack::par_push_chunk(oop* ptr_arr) { return false; } - Copy::conjoint_oops_atomic(ptr_arr, new_chunk->data, OopsPerChunk); + Copy::conjoint_memory_atomic(ptr_arr, new_chunk->data, OopsPerChunk * sizeof(oop)); add_chunk_to_chunk_list(new_chunk); @@ -299,7 +299,7 @@ bool G1CMMarkStack::par_pop_chunk(oop* ptr_arr) { return false; } - Copy::conjoint_oops_atomic(cur->data, ptr_arr, OopsPerChunk); + Copy::conjoint_memory_atomic(cur->data, ptr_arr, OopsPerChunk * sizeof(oop)); add_chunk_to_free_list(cur); return true; From 2e74f81187c4568c1d335429f6cec58cf9a84659 Mon Sep 17 00:00:00 2001 From: Harold Seigel Date: Mon, 19 Sep 2016 19:25:09 -0400 Subject: [PATCH 13/69] 8166312: Backout 8165017 Backout of the change for JDK-8165017 because tests failed on windows Reviewed-by: ctornqvi, dholmes, gtriantafill --- .../jdwp/AllModulesCommandTest.java | 52 +++++-------------- hotspot/test/serviceability/jdwp/JdwpCmd.java | 1 + .../serviceability/jdwp/JdwpModuleCmd.java | 34 ------------ .../serviceability/jdwp/JdwpModuleReply.java | 42 --------------- .../jdwp/JdwpVisibleClassesCmd.java | 34 ------------ .../jdwp/JdwpVisibleClassesReply.java | 49 ----------------- 6 files changed, 13 insertions(+), 199 deletions(-) delete mode 100644 hotspot/test/serviceability/jdwp/JdwpModuleCmd.java delete mode 100644 hotspot/test/serviceability/jdwp/JdwpModuleReply.java delete mode 100644 hotspot/test/serviceability/jdwp/JdwpVisibleClassesCmd.java delete mode 100644 hotspot/test/serviceability/jdwp/JdwpVisibleClassesReply.java diff --git a/hotspot/test/serviceability/jdwp/AllModulesCommandTest.java b/hotspot/test/serviceability/jdwp/AllModulesCommandTest.java index 5fed0412a03..33bb583c59d 100644 --- a/hotspot/test/serviceability/jdwp/AllModulesCommandTest.java +++ b/hotspot/test/serviceability/jdwp/AllModulesCommandTest.java @@ -30,7 +30,7 @@ import static jdk.test.lib.Asserts.assertTrue; /** * @test - * @summary Tests the modules-related JDWP commands + * @summary Tests AllModules JDWP command * @library /test/lib * @modules java.base/jdk.internal.misc * @compile AllModulesCommandTestDebuggee.java @@ -87,12 +87,8 @@ public class AllModulesCommandTest implements DebuggeeLauncher.Listener { assertReply(reply); for (int i = 0; i < reply.getModulesCount(); ++i) { long modId = reply.getModuleId(i); - // For each module reported by JDWP get its name using the JDWP NAME command - // and store the reply - String modName = getModuleName(modId); - if (modName != null) { // JDWP reports unnamed modules, ignore them - jdwpModuleNames.add(modName); - } + // For each module reported by JDWP get its name using the JDWP NAME command + getModuleName(modId); // Assert the JDWP CANREAD and CLASSLOADER commands assertCanRead(modId); assertClassLoader(modId); @@ -118,10 +114,14 @@ public class AllModulesCommandTest implements DebuggeeLauncher.Listener { } } - private String getModuleName(long modId) throws IOException { + private void getModuleName(long modId) throws IOException { + // Send out the JDWP NAME command and store the reply JdwpModNameReply reply = new JdwpModNameCmd(modId).send(channel); assertReply(reply); - return reply.getModuleName(); + String modName = reply.getModuleName(); + if (modName != null) { // JDWP reports unnamed modules, ignore them + jdwpModuleNames.add(modName); + } } private void assertReply(JdwpReply reply) { @@ -139,39 +139,11 @@ public class AllModulesCommandTest implements DebuggeeLauncher.Listener { } private void assertClassLoader(long modId) throws IOException { - // Verify that the module classloader id is valid + // Simple assert for the CLASSLOADER command JdwpClassLoaderReply reply = new JdwpClassLoaderCmd(modId).send(channel); assertReply(reply); - long moduleClassLoader = reply.getClassLoaderId(); - assertTrue(moduleClassLoader >= 0, "bad classloader refId " + moduleClassLoader + " for module id " + modId); - - String clsModName = getModuleName(modId); - if ("java.base".equals(clsModName)) { - // For the java.base module, because there will be some loaded classes, we can verify - // that some of the loaded classes do report the java.base module as the module they belong to - assertGetModule(moduleClassLoader, modId); - } - } - - private void assertGetModule(long moduleClassLoader, long modId) throws IOException { - // Get all the visible classes for the module classloader - JdwpVisibleClassesReply visibleClasses = new JdwpVisibleClassesCmd(moduleClassLoader).send(channel); - assertReply(visibleClasses); - - boolean moduleFound = false; - for (long clsId : visibleClasses.getVisibleClasses()) { - // For each visible class get the module the class belongs to - JdwpModuleReply modReply = new JdwpModuleCmd(clsId).send(channel); - assertReply(modReply); - long clsModId = modReply.getModuleId(); - - // At least one of the visible classes should belong to our module - if (modId == clsModId) { - moduleFound = true; - break; - } - } - assertTrue(moduleFound, "None of the visible classes for the classloader of the module " + getModuleName(modId) + " reports the module as its own"); + long clId = reply.getClassLoaderId(); + assertTrue(clId >= 0, "bad classloader refId " + clId + " for module id " + modId); } } diff --git a/hotspot/test/serviceability/jdwp/JdwpCmd.java b/hotspot/test/serviceability/jdwp/JdwpCmd.java index 05dbb6efb7f..fe7f28707a8 100644 --- a/hotspot/test/serviceability/jdwp/JdwpCmd.java +++ b/hotspot/test/serviceability/jdwp/JdwpCmd.java @@ -70,6 +70,7 @@ public abstract class JdwpCmd { } public final T send(JdwpChannel channel) throws IOException { + System.err.println("Sending command: " + this); channel.write(data.array(), HEADER_LEN + getDataLength()); if (reply != null) { reply.initFromStream(channel.getInputStream()); diff --git a/hotspot/test/serviceability/jdwp/JdwpModuleCmd.java b/hotspot/test/serviceability/jdwp/JdwpModuleCmd.java deleted file mode 100644 index a9ed54419fa..00000000000 --- a/hotspot/test/serviceability/jdwp/JdwpModuleCmd.java +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -/** - * The JDWP MODULE command - */ -public class JdwpModuleCmd extends JdwpCmd { - - public JdwpModuleCmd(long refId) { - super(19, 2, JdwpModuleReply.class, refLen()); - putRefId(refId); - } - -} diff --git a/hotspot/test/serviceability/jdwp/JdwpModuleReply.java b/hotspot/test/serviceability/jdwp/JdwpModuleReply.java deleted file mode 100644 index 19baa7a4dde..00000000000 --- a/hotspot/test/serviceability/jdwp/JdwpModuleReply.java +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -import java.io.DataInputStream; -import java.io.IOException; - -/** - * The reply to the JDWP MODULE command - */ -public class JdwpModuleReply extends JdwpReply { - - private long moduleId; - - protected void parseData(DataInputStream ds) throws IOException { - moduleId = readRefId(ds); - } - - public long getModuleId() { - return moduleId; - } - -} diff --git a/hotspot/test/serviceability/jdwp/JdwpVisibleClassesCmd.java b/hotspot/test/serviceability/jdwp/JdwpVisibleClassesCmd.java deleted file mode 100644 index daab8a11d6a..00000000000 --- a/hotspot/test/serviceability/jdwp/JdwpVisibleClassesCmd.java +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -/** - * The JDWP VISIBLE CLASSES command - */ -public class JdwpVisibleClassesCmd extends JdwpCmd { - - public JdwpVisibleClassesCmd(long classLoaderId) { - super(1, 14, JdwpVisibleClassesReply.class, refLen()); - putRefId(classLoaderId); - } - -} diff --git a/hotspot/test/serviceability/jdwp/JdwpVisibleClassesReply.java b/hotspot/test/serviceability/jdwp/JdwpVisibleClassesReply.java deleted file mode 100644 index 5381c43c51a..00000000000 --- a/hotspot/test/serviceability/jdwp/JdwpVisibleClassesReply.java +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -import java.io.DataInputStream; -import java.io.IOException; -import java.util.Arrays; - -/** - * The reply to the JDWP VISIBLE CLASSES command - */ -public class JdwpVisibleClassesReply extends JdwpReply { - - private long[] visibleClasses; - - protected void parseData(DataInputStream ds) throws IOException { - int numOfClasses = ds.readInt(); - visibleClasses = new long[numOfClasses]; - for (int i = 0; i < numOfClasses; ++i) { - byte type = ds.readByte(); - long refId = readRefId(ds); - visibleClasses[i] = refId; - } - } - - public long[] getVisibleClasses() { - return Arrays.copyOf(visibleClasses, visibleClasses.length); - } - -} From 9b7c58376f2463e2845a5acf76a30918431e9f1d Mon Sep 17 00:00:00 2001 From: Kim Barrett Date: Mon, 19 Sep 2016 19:59:28 -0400 Subject: [PATCH 14/69] 8166228: Remove unused HeapRegion::object_iterate_mem_careful() Removed unused function. Reviewed-by: mgerdin, tschatzl --- hotspot/src/share/vm/gc/g1/heapRegion.cpp | 29 ----------------------- hotspot/src/share/vm/gc/g1/heapRegion.hpp | 11 --------- 2 files changed, 40 deletions(-) diff --git a/hotspot/src/share/vm/gc/g1/heapRegion.cpp b/hotspot/src/share/vm/gc/g1/heapRegion.cpp index 33d8268855d..6944bcf0c44 100644 --- a/hotspot/src/share/vm/gc/g1/heapRegion.cpp +++ b/hotspot/src/share/vm/gc/g1/heapRegion.cpp @@ -352,35 +352,6 @@ void HeapRegion::note_self_forwarding_removal_end(bool during_initial_mark, _prev_marked_bytes = marked_bytes; } -HeapWord* -HeapRegion::object_iterate_mem_careful(MemRegion mr, - ObjectClosure* cl) { - G1CollectedHeap* g1h = G1CollectedHeap::heap(); - // We used to use "block_start_careful" here. But we're actually happy - // to update the BOT while we do this... - HeapWord* cur = block_start(mr.start()); - mr = mr.intersection(used_region()); - if (mr.is_empty()) return NULL; - // Otherwise, find the obj that extends onto mr.start(). - - assert(cur <= mr.start() - && (oop(cur)->klass_or_null() == NULL || - cur + oop(cur)->size() > mr.start()), - "postcondition of block_start"); - oop obj; - while (cur < mr.end()) { - obj = oop(cur); - if (obj->klass_or_null() == NULL) { - // Ran into an unparseable point. - return cur; - } else if (!g1h->is_obj_dead(obj)) { - cl->do_object(obj); - } - cur += block_size(cur); - } - return NULL; -} - HeapWord* HeapRegion:: oops_on_card_seq_iterate_careful(MemRegion mr, diff --git a/hotspot/src/share/vm/gc/g1/heapRegion.hpp b/hotspot/src/share/vm/gc/g1/heapRegion.hpp index f4bf95e055b..9542b9ffb11 100644 --- a/hotspot/src/share/vm/gc/g1/heapRegion.hpp +++ b/hotspot/src/share/vm/gc/g1/heapRegion.hpp @@ -653,17 +653,6 @@ class HeapRegion: public G1ContiguousSpace { } } - // Requires that "mr" be entirely within the region. - // Apply "cl->do_object" to all objects that intersect with "mr". - // If the iteration encounters an unparseable portion of the region, - // or if "cl->abort()" is true after a closure application, - // terminate the iteration and return the address of the start of the - // subregion that isn't done. (The two can be distinguished by querying - // "cl->abort()".) Return of "NULL" indicates that the iteration - // completed. - HeapWord* - object_iterate_mem_careful(MemRegion mr, ObjectClosure* cl); - // filter_young: if true and the region is a young region then we // skip the iteration. // card_ptr: if not NULL, and we decide that the card is not young From b339daff4b0f9b728c6a3201a1b4526efac3b357 Mon Sep 17 00:00:00 2001 From: Calvin Cheung Date: Tue, 20 Sep 2016 10:37:32 -0700 Subject: [PATCH 15/69] 8164011: --patch-module support for CDS Exports the ZIP_FreeEntry function Reviewed-by: iklam, dcubed, lfoltan --- jdk/make/lib/CoreLibraries.gmk | 2 +- jdk/make/mapfiles/libzip/mapfile-vers | 3 ++- jdk/src/java.base/share/native/libzip/zip_util.c | 2 +- jdk/src/java.base/share/native/libzip/zip_util.h | 3 ++- 4 files changed, 6 insertions(+), 4 deletions(-) diff --git a/jdk/make/lib/CoreLibraries.gmk b/jdk/make/lib/CoreLibraries.gmk index bfe94de4d6a..bec09c78db1 100644 --- a/jdk/make/lib/CoreLibraries.gmk +++ b/jdk/make/lib/CoreLibraries.gmk @@ -218,7 +218,7 @@ $(eval $(call SetupNativeCompilation,BUILD_LIBZIP, \ $(call SET_SHARED_LIBRARY_ORIGIN), \ LDFLAGS_windows := -export:ZIP_Open -export:ZIP_Close -export:ZIP_FindEntry \ -export:ZIP_ReadEntry -export:ZIP_GetNextEntry \ - -export:ZIP_InflateFully -export:ZIP_CRC32, \ + -export:ZIP_InflateFully -export:ZIP_CRC32 -export:ZIP_FreeEntry, \ LIBS_unix := -ljvm -ljava $(LIBZ), \ LIBS_solaris := -lc, \ LIBS_windows := jvm.lib $(WIN_JAVA_LIB), \ diff --git a/jdk/make/mapfiles/libzip/mapfile-vers b/jdk/make/mapfiles/libzip/mapfile-vers index c1ab48c10cf..d711d8e17f4 100644 --- a/jdk/make/mapfiles/libzip/mapfile-vers +++ b/jdk/make/mapfiles/libzip/mapfile-vers @@ -1,5 +1,5 @@ # -# Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 1997, 2016, 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 @@ -49,6 +49,7 @@ SUNWprivate_1.1 { Java_java_util_zip_Inflater_setDictionary; ZIP_Close; ZIP_CRC32; + ZIP_FreeEntry; ZIP_FindEntry; ZIP_GetEntry; ZIP_GetNextEntry; diff --git a/jdk/src/java.base/share/native/libzip/zip_util.c b/jdk/src/java.base/share/native/libzip/zip_util.c index 01c7f05ef59..f6064a469ab 100644 --- a/jdk/src/java.base/share/native/libzip/zip_util.c +++ b/jdk/src/java.base/share/native/libzip/zip_util.c @@ -1094,7 +1094,7 @@ newEntry(jzfile *zip, jzcell *zc, AccessHint accessHint) * jzentry for each zip. This optimizes a common access pattern. */ -void +void JNICALL ZIP_FreeEntry(jzfile *jz, jzentry *ze) { jzentry *last; diff --git a/jdk/src/java.base/share/native/libzip/zip_util.h b/jdk/src/java.base/share/native/libzip/zip_util.h index 1f5f3bd6cab..de6b197bb00 100644 --- a/jdk/src/java.base/share/native/libzip/zip_util.h +++ b/jdk/src/java.base/share/native/libzip/zip_util.h @@ -270,7 +270,8 @@ jzentry * ZIP_GetEntry(jzfile *zip, char *name, jint ulen); void ZIP_Lock(jzfile *zip); void ZIP_Unlock(jzfile *zip); jint ZIP_Read(jzfile *zip, jzentry *entry, jlong pos, void *buf, jint len); -void ZIP_FreeEntry(jzfile *zip, jzentry *ze); +void JNICALL +ZIP_FreeEntry(jzfile *zip, jzentry *ze); jlong ZIP_GetEntryDataOffset(jzfile *zip, jzentry *entry); jzentry * ZIP_GetEntry2(jzfile *zip, char *name, jint ulen, jboolean addSlash); From 89744d775f9a591246388f128261a38aca38fd20 Mon Sep 17 00:00:00 2001 From: Harold Seigel Date: Wed, 21 Sep 2016 08:10:48 -0400 Subject: [PATCH 16/69] 8160987: JDWP ClassType.InvokeMethod doesn't validate class Add code to validate class in JDWP instead of relying on JNI to do the check. Reviewed-by: dholmes, dcubed, sspitsyn, dsamersoff --- .../share/native/libjdwp/invoker.c | 38 ++++++++++++++++++- .../com/sun/jdi/InterfaceMethodsTest.java | 30 +++++++++------ 2 files changed, 56 insertions(+), 12 deletions(-) diff --git a/jdk/src/jdk.jdwp.agent/share/native/libjdwp/invoker.c b/jdk/src/jdk.jdwp.agent/share/native/libjdwp/invoker.c index c6078a79d78..c048c759d19 100644 --- a/jdk/src/jdk.jdwp.agent/share/native/libjdwp/invoker.c +++ b/jdk/src/jdk.jdwp.agent/share/native/libjdwp/invoker.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2007, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2016, 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 @@ -343,6 +343,35 @@ invoker_enableInvokeRequests(jthread thread) debugMonitorExit(invokerLock); } +/* + * Check that method is in the specified clazz or one of its super classes. + * We have to enforce this check at the JDWP layer because the JNI layer + * has different requirements. + */ +static jvmtiError check_methodClass(JNIEnv *env, jclass clazz, jmethodID method) +{ + jclass containing_class = NULL; + jvmtiError error; + + error = JVMTI_FUNC_PTR(gdata->jvmti,GetMethodDeclaringClass) + (gdata->jvmti, method, &containing_class); + if (error != JVMTI_ERROR_NONE) { + return JVMTI_ERROR_NONE; /* Bad jmethodID ? This will be handled elsewhere */ + } + + if (JNI_FUNC_PTR(env,IsSameObject)(env, clazz, containing_class)) { + return JVMTI_ERROR_NONE; + } + + // If not the same class then check that containing_class is a superclass of + // clazz (not a superinterface). + if (JNI_FUNC_PTR(env,IsAssignableFrom)(env, clazz, containing_class) && + referenceTypeTag(containing_class) != JDWP_TYPE_TAG(INTERFACE)) { + return JVMTI_ERROR_NONE; + } + return JVMTI_ERROR_INVALID_METHODID; +} + jvmtiError invoker_requestInvoke(jbyte invokeType, jbyte options, jint id, jthread thread, jclass clazz, jmethodID method, @@ -353,6 +382,13 @@ invoker_requestInvoke(jbyte invokeType, jbyte options, jint id, InvokeRequest *request; jvmtiError error = JVMTI_ERROR_NONE; + if (invokeType == INVOKE_STATIC) { + error = check_methodClass(env, clazz, method); + if (error != JVMTI_ERROR_NONE) { + return error; + } + } + debugMonitorEnter(invokerLock); request = threadControl_getInvokeRequest(thread); if (request != NULL) { diff --git a/jdk/test/com/sun/jdi/InterfaceMethodsTest.java b/jdk/test/com/sun/jdi/InterfaceMethodsTest.java index 3ff435fe35e..73a05dbf98e 100644 --- a/jdk/test/com/sun/jdi/InterfaceMethodsTest.java +++ b/jdk/test/com/sun/jdi/InterfaceMethodsTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2016, 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 @@ -197,14 +197,18 @@ public class InterfaceMethodsTest extends TestScaffold { // invoke interface static method A testInvokePos(ifaceClass, null, "staticMethodA", "()I", vm().mirrorOf(RESULT_A)); - // try to invoke static method A on the instance - testInvokePos(ifaceClass, ref, "staticMethodA", "()I", vm().mirrorOf(RESULT_A)); + // invoking static method A on the instance fails because static method A is + // not inherited by TargetClass. + testInvokeNeg(ifaceClass, ref, "staticMethodA", "()I", vm().mirrorOf(RESULT_A), + "Invalid MethodID"); // invoke interface static method B testInvokePos(ifaceClass, null, "staticMethodB", "()I", vm().mirrorOf(RESULT_A)); - // try to invoke static method B on the instance - testInvokePos(ifaceClass, ref, "staticMethodB", "()I", vm().mirrorOf(RESULT_A)); + // invoking static method B on the instance fails because static method B is + // not inherited by TargetClass. + testInvokeNeg(ifaceClass, ref, "staticMethodB", "()I", vm().mirrorOf(RESULT_A), + "Invalid MethodID"); // try to invoke a virtual method testInvokePos(ifaceClass, ref, "implementedMethod", "()I", vm().mirrorOf(RESULT_A), true); @@ -239,21 +243,25 @@ public class InterfaceMethodsTest extends TestScaffold { testInvokeNeg(ifaceClass, null, "staticMethodA", "()I", vm().mirrorOf(RESULT_A), "Static interface methods are not inheritable"); - // however it is possible to call "staticMethodA" on the actual instance + // "staticMethodA" is not inherited by InterfaceB even from an actual instance testInvokeNeg(ifaceClass, ref, "staticMethodA", "()I", vm().mirrorOf(RESULT_A), "Static interface methods are not inheritable"); - // "staticMethodB" is overridden in InterfaceB + // "staticMethodB" is re-defined in InterfaceB testInvokePos(ifaceClass, null, "staticMethodB", "()I", vm().mirrorOf(RESULT_B)); - // the instance invokes the overriden form of "staticMethodB" from InterfaceB - testInvokePos(ifaceClass, ref, "staticMethodB", "()I", vm().mirrorOf(RESULT_B)); + // the instance fails to invoke the re-defined form of "staticMethodB" from + // InterfaceB because staticMethodB is not inherited by TargetClass + testInvokeNeg(ifaceClass, ref, "staticMethodB", "()I", vm().mirrorOf(RESULT_B), + "Invalid MethodID"); // "staticMethodC" is present only in InterfaceB testInvokePos(ifaceClass, null, "staticMethodC", "()I", vm().mirrorOf(RESULT_B)); - // "staticMethodC" should be reachable from the instance too - testInvokePos(ifaceClass, ref, "staticMethodC", "()I", vm().mirrorOf(RESULT_B)); + // "staticMethodC" is not reachable from the instance because staticMethodC + // is not inherited by TargetClass. + testInvokeNeg(ifaceClass, ref, "staticMethodC", "()I", vm().mirrorOf(RESULT_B), + "Invalid MethodID"); } private void testImplementationClass(ReferenceType targetClass, ObjectReference thisObject) { From 7f563f156702725e6802df8c6f372377bbd5266f Mon Sep 17 00:00:00 2001 From: Chris Plummer Date: Wed, 21 Sep 2016 12:53:07 -0700 Subject: [PATCH 17/69] 8161225: Assert failure in JVMTI GetNamedModule at JPLISAgent.c line: 792 Made the assert less restrictive. Reviewed-by: dholmes, dcubed, sspitsyn --- .../java.instrument/share/native/libinstrument/JPLISAgent.c | 3 ++- jdk/test/ProblemList.txt | 2 -- .../lang/instrument/DaemonThread/TestDaemonThreadLauncher.java | 3 ++- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/jdk/src/java.instrument/share/native/libinstrument/JPLISAgent.c b/jdk/src/java.instrument/share/native/libinstrument/JPLISAgent.c index 12f2a451e49..fa1341f414b 100644 --- a/jdk/src/java.instrument/share/native/libinstrument/JPLISAgent.c +++ b/jdk/src/java.instrument/share/native/libinstrument/JPLISAgent.c @@ -790,9 +790,10 @@ getModuleObject(jvmtiEnv* jvmti, pkg_name_buf[len] = '\0'; err = (*jvmti)->GetNamedModule(jvmti, loaderObject, pkg_name_buf, &moduleObject); + free((void*)pkg_name_buf); + check_phase_ret_blob(err, NULL); jplis_assert_msg(err == JVMTI_ERROR_NONE, "error in the JVMTI GetNamedModule"); - free((void*)pkg_name_buf); return moduleObject; } diff --git a/jdk/test/ProblemList.txt b/jdk/test/ProblemList.txt index f2e96cacf20..04b610714bb 100644 --- a/jdk/test/ProblemList.txt +++ b/jdk/test/ProblemList.txt @@ -134,8 +134,6 @@ java/lang/instrument/RetransformBigClass.sh 8065756 generic- java/lang/instrument/BootClassPath/BootClassPathTest.sh 8072130 macosx-all -java/lang/instrument/DaemonThread/TestDaemonThread.java 8161225 generic-all - java/lang/management/MemoryMXBean/Pending.java 8158837 generic-all java/lang/management/MemoryMXBean/PendingAllGC.sh 8158760 generic-all diff --git a/jdk/test/java/lang/instrument/DaemonThread/TestDaemonThreadLauncher.java b/jdk/test/java/lang/instrument/DaemonThread/TestDaemonThreadLauncher.java index 419cfb3bbbd..579db8d6e75 100644 --- a/jdk/test/java/lang/instrument/DaemonThread/TestDaemonThreadLauncher.java +++ b/jdk/test/java/lang/instrument/DaemonThread/TestDaemonThreadLauncher.java @@ -1,6 +1,6 @@ /* * Copyright 2014 Goldman Sachs. - * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2016, 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 @@ -32,6 +32,7 @@ public class TestDaemonThreadLauncher { ProcessBuilder pb = ProcessTools.createJavaProcessBuilder("-javaagent:DummyAgent.jar", "TestDaemonThread", "."); OutputAnalyzer analyzer = ProcessTools.executeProcess(pb); analyzer.shouldNotContain("ASSERTION FAILED"); + analyzer.shouldHaveExitValue(0); } } } From 517cfed246af86805b3df88ae141f4c38e71034a Mon Sep 17 00:00:00 2001 From: Srikanth Adayapalam Date: Wed, 28 Sep 2016 09:05:20 +0530 Subject: [PATCH 18/69] 8166363: Method with reordered type parameter bounds compiles with @Override annotation but does not actually override superclass method Reviewed-by: vromero --- .../com/sun/tools/javac/comp/TransTypes.java | 8 +-- .../generics/bridges/ReorderedBoundsTest.java | 65 +++++++++++++++++++ 2 files changed, 69 insertions(+), 4 deletions(-) create mode 100644 langtools/test/tools/javac/generics/bridges/ReorderedBoundsTest.java diff --git a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/TransTypes.java b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/TransTypes.java index 9f2ff731f2e..3e9b2ae4107 100644 --- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/TransTypes.java +++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/TransTypes.java @@ -415,10 +415,10 @@ public class TransTypes extends TreeTranslator { if (!isSameMemberWhenErased(dest, impl, impl_erasure)) return true; - // If the erasure of the return type is different, a - // bridge is needed. - return !types.isSameType(impl_erasure.getReturnType(), - method_erasure.getReturnType()); + /* Bottom line: A bridge is needed if the erasure of the implementation + is different from that of the method that it overrides. + */ + return !types.isSameType(impl_erasure, method_erasure); } else { // method and impl are the same... if ((method.flags() & ABSTRACT) != 0) { diff --git a/langtools/test/tools/javac/generics/bridges/ReorderedBoundsTest.java b/langtools/test/tools/javac/generics/bridges/ReorderedBoundsTest.java new file mode 100644 index 00000000000..0fdaae8a40b --- /dev/null +++ b/langtools/test/tools/javac/generics/bridges/ReorderedBoundsTest.java @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2016, 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 8166363 + * @summary Method with reordered type parameter bounds compiles with Override annotation but does not actually override superclass method. + * @run main ReorderedBoundsTest + */ + +import java.io.Serializable; + +public class ReorderedBoundsTest { + public static class Parent { + public String printClassName(T t) { + return "Parent"; + } + } + + public static class OrderedChild extends Parent { + @Override + public String printClassName(T t) { + return "OrderedChild"; + } + } + + public static class ReorderedChild extends Parent { + @Override + public String printClassName(T t) { + return "ReorderedChild"; + } + } + + public static void main(String[] args) { + + String s; + Parent p = new OrderedChild(); + if (!(s = p.printClassName(new StringBuilder())).equals("OrderedChild")) + throw new AssertionError("Bad output: " + s); + + p = new ReorderedChild(); + if (!(s = p.printClassName(new StringBuilder())).equals("ReorderedChild")) + throw new AssertionError("Bad output: " + s); + } +} \ No newline at end of file From b9ad123afae6f1bb837fa265c11beae5083b0166 Mon Sep 17 00:00:00 2001 From: Shinya Yoshida Date: Wed, 28 Sep 2016 16:36:10 +0900 Subject: [PATCH 19/69] 8154714: jshell tool: add exports support Reviewed-by: jlahoda, rfield --- .../jdk/internal/jshell/tool/JShellTool.java | 31 +++++++++++++++++-- .../jshell/tool/resources/l10n.properties | 9 +++++- langtools/test/jdk/jshell/ToolBasicTest.java | 18 ++++++++++- 3 files changed, 54 insertions(+), 4 deletions(-) diff --git a/langtools/src/jdk.jshell/share/classes/jdk/internal/jshell/tool/JShellTool.java b/langtools/src/jdk.jshell/share/classes/jdk/internal/jshell/tool/JShellTool.java index 203132444f2..6cfb6e13c89 100644 --- a/langtools/src/jdk.jshell/share/classes/jdk/internal/jshell/tool/JShellTool.java +++ b/langtools/src/jdk.jshell/share/classes/jdk/internal/jshell/tool/JShellTool.java @@ -199,6 +199,7 @@ public class JShellTool implements MessageHandler { private boolean feedbackInitialized = false; private String commandLineFeedbackMode = null; private List remoteVMOptions = new ArrayList<>(); + private List compilerOptions = new ArrayList<>(); SourceCodeAnalysis analysis; JShell state = null; @@ -558,9 +559,14 @@ public class JShellTool implements MessageHandler { parser.accepts("s"); parser.accepts("v"); OptionSpec r = parser.accepts("R").withRequiredArg(); + OptionSpec c = parser.accepts("C").withRequiredArg(); parser.acceptsAll(asList("h", "help")); parser.accepts("version"); parser.accepts("full-version"); + + parser.accepts("X"); + OptionSpec addExports = parser.accepts("add-exports").withRequiredArg(); + NonOptionArgumentSpec loadFileSpec = parser.nonOptions(); OptionSet options; @@ -585,6 +591,10 @@ public class JShellTool implements MessageHandler { printUsage(); return null; } + if (options.has("X")) { + printUsageX(); + return null; + } if (options.has("version")) { cmdout.printf("jshell %s\n", version()); return null; @@ -630,7 +640,19 @@ public class JShellTool implements MessageHandler { commandLineFeedbackMode = "verbose"; } if (options.has(r)) { - remoteVMOptions = options.valuesOf(r); + remoteVMOptions.addAll(options.valuesOf(r)); + } + if (options.has(c)) { + compilerOptions.addAll(options.valuesOf(c)); + } + + if (options.has(addExports)) { + List exports = options.valuesOf(addExports).stream() + .map(mp -> mp + "=ALL-UNNAMED") + .flatMap(mp -> Stream.of("--add-exports", mp)) + .collect(toList()); + remoteVMOptions.addAll(exports); + compilerOptions.addAll(exports); } return options.valuesOf(loadFileSpec); @@ -640,6 +662,10 @@ public class JShellTool implements MessageHandler { cmdout.print(getResourceString("help.usage")); } + private void printUsageX() { + cmdout.print(getResourceString("help.usage.x")); + } + /** * Message handler to use during initial start-up. */ @@ -683,7 +709,8 @@ public class JShellTool implements MessageHandler { .idGenerator((sn, i) -> (currentNameSpace == startNamespace || state.status(sn).isActive()) ? currentNameSpace.tid(sn) : errorNamespace.tid(sn)) - .remoteVMOptions(remoteVMOptions.toArray(new String[remoteVMOptions.size()])) + .remoteVMOptions(remoteVMOptions.stream().toArray(String[]::new)) + .compilerOptions(compilerOptions.stream().toArray(String[]::new)) .build(); shutdownSubscription = state.onShutdown((JShell deadState) -> { if (deadState == state) { diff --git a/langtools/src/jdk.jshell/share/classes/jdk/internal/jshell/tool/resources/l10n.properties b/langtools/src/jdk.jshell/share/classes/jdk/internal/jshell/tool/resources/l10n.properties index 5434e949328..beb1f0fd13f 100644 --- a/langtools/src/jdk.jshell/share/classes/jdk/internal/jshell/tool/resources/l10n.properties +++ b/langtools/src/jdk.jshell/share/classes/jdk/internal/jshell/tool/resources/l10n.properties @@ -164,8 +164,15 @@ where possible options include:\n\ \ Use one -J for each runtime flag or flag argument\n\ \ -R Pass to the remote runtime system.\n\ \ Use one -R for each remote flag or flag argument\n\ +\ -C Pass to the compiler.\n\ +\ Use one -C for each compiler flag or flag argument\n\ \ --help Print this synopsis of standard options\n\ -\ --version Version information\n +\ --version Version information\n\ +\ -X Print help on non-standard options\n +help.usage.x = \ +\ --add-exports / Export specified module-private package to snippets\n\ +\ \n\ +\These options are non-standard and subject to change without notice.\n help.list.summary = list the source you have typed help.list.args = [|-all|-start] diff --git a/langtools/test/jdk/jshell/ToolBasicTest.java b/langtools/test/jdk/jshell/ToolBasicTest.java index 7ccf529fb2d..fde5a57f989 100644 --- a/langtools/test/jdk/jshell/ToolBasicTest.java +++ b/langtools/test/jdk/jshell/ToolBasicTest.java @@ -23,7 +23,7 @@ /* * @test - * @bug 8143037 8142447 8144095 8140265 8144906 8146138 8147887 8147886 8148316 8148317 8143955 8157953 8080347 + * @bug 8143037 8142447 8144095 8140265 8144906 8146138 8147887 8147886 8148316 8148317 8143955 8157953 8080347 8154714 * @summary Tests for Basic tests for REPL tool * @modules jdk.compiler/com.sun.tools.javac.api * jdk.compiler/com.sun.tools.javac.main @@ -574,4 +574,20 @@ public class ToolBasicTest extends ReplToolTesting { } } + public void testAddExports() { + test(false, new String[]{"--no-startup"}, + a -> assertCommandOutputStartsWith(a, "import jdk.internal.misc.VM;", "| Error:") + ); + test(false, new String[]{"--no-startup", + "-R--add-exports", "-Rjava.base/jdk.internal.misc=ALL-UNNAMED", + "-C--add-exports", "-Cjava.base/jdk.internal.misc=ALL-UNNAMED"}, + a -> assertImport(a, "import jdk.internal.misc.VM;", "", "jdk.internal.misc.VM"), + a -> assertCommand(a, "System.err.println(VM.isBooted())", "", "", null, "", "true\n") + ); + test(false, new String[]{"--no-startup", "--add-exports", "java.base/jdk.internal.misc"}, + a -> assertImport(a, "import jdk.internal.misc.VM;", "", "jdk.internal.misc.VM"), + a -> assertCommand(a, "System.err.println(VM.isBooted())", "", "", null, "", "true\n") + ); + } + } From 644dc8b4e97257ebb3bb6655eca02c671ed43af7 Mon Sep 17 00:00:00 2001 From: Mikael Vidstedt Date: Wed, 28 Sep 2016 08:22:54 -0700 Subject: [PATCH 20/69] 8166045: jdk/internal/misc/Unsafe tests fail due to timeout Only run the memory hungry tests on large machines Reviewed-by: dholmes, ctornqvi --- .../jdk/internal/misc/Unsafe/CopyMemory.java | 2 - .../internal/misc/Unsafe/CopyMemoryLarge.java | 58 +++++++++++++++++++ .../jdk/internal/misc/Unsafe/CopySwap.java | 2 - .../internal/misc/Unsafe/CopySwapLarge.java | 58 +++++++++++++++++++ 4 files changed, 116 insertions(+), 4 deletions(-) create mode 100644 jdk/test/jdk/internal/misc/Unsafe/CopyMemoryLarge.java create mode 100644 jdk/test/jdk/internal/misc/Unsafe/CopySwapLarge.java diff --git a/jdk/test/jdk/internal/misc/Unsafe/CopyMemory.java b/jdk/test/jdk/internal/misc/Unsafe/CopyMemory.java index d4879e603f1..12362d387fd 100644 --- a/jdk/test/jdk/internal/misc/Unsafe/CopyMemory.java +++ b/jdk/test/jdk/internal/misc/Unsafe/CopyMemory.java @@ -22,7 +22,6 @@ */ import jdk.internal.misc.Unsafe; -import java.lang.reflect.Field; /* * @test @@ -40,7 +39,6 @@ public class CopyMemory extends CopyCommon { */ private void testPositive() { testSmallCopy(false); - testLargeCopy(false); } /** diff --git a/jdk/test/jdk/internal/misc/Unsafe/CopyMemoryLarge.java b/jdk/test/jdk/internal/misc/Unsafe/CopyMemoryLarge.java new file mode 100644 index 00000000000..e8c6f0d76ef --- /dev/null +++ b/jdk/test/jdk/internal/misc/Unsafe/CopyMemoryLarge.java @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2016, 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 jdk.internal.misc.Unsafe; + +/* + * @test + * @summary Test Unsafe.copyMemory + * @modules java.base/jdk.internal.misc + * @requires os.maxMemory > 8G + */ +public class CopyMemoryLarge extends CopyCommon { + private CopyMemoryLarge() { + } + + /** + * Run positive tests + * + * @throws RuntimeException if an error is found + */ + private void testPositive() { + testLargeCopy(false); + } + + /** + * Run all tests + * + * @throws RuntimeException if an error is found + */ + private void test() { + testPositive(); + } + + public static void main(String[] args) { + CopyMemoryLarge cs = new CopyMemoryLarge(); + cs.test(); + } +} diff --git a/jdk/test/jdk/internal/misc/Unsafe/CopySwap.java b/jdk/test/jdk/internal/misc/Unsafe/CopySwap.java index 4cbd8b709d2..99371f01142 100644 --- a/jdk/test/jdk/internal/misc/Unsafe/CopySwap.java +++ b/jdk/test/jdk/internal/misc/Unsafe/CopySwap.java @@ -22,7 +22,6 @@ */ import jdk.internal.misc.Unsafe; -import java.lang.reflect.Field; /* * @test @@ -40,7 +39,6 @@ public class CopySwap extends CopyCommon { */ private void testPositive() { testSmallCopy(true); - testLargeCopy(true); } /** diff --git a/jdk/test/jdk/internal/misc/Unsafe/CopySwapLarge.java b/jdk/test/jdk/internal/misc/Unsafe/CopySwapLarge.java new file mode 100644 index 00000000000..818a35367f3 --- /dev/null +++ b/jdk/test/jdk/internal/misc/Unsafe/CopySwapLarge.java @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2016, 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 jdk.internal.misc.Unsafe; + +/* + * @test + * @summary Test Unsafe.copySwapMemory + * @modules java.base/jdk.internal.misc + * @requires os.maxMemory > 8G + */ +public class CopySwapLarge extends CopyCommon { + private CopySwapLarge() { + } + + /** + * Run positive tests + * + * @throws RuntimeException if an error is found + */ + private void testPositive() { + testLargeCopy(true); + } + + /** + * Run all tests + * + * @throws RuntimeException if an error is found + */ + private void test() { + testPositive(); + } + + public static void main(String[] args) { + CopySwapLarge cs = new CopySwapLarge(); + cs.test(); + } +} From 20a821ae7c965b4f6a2ca447ad34a97410b12789 Mon Sep 17 00:00:00 2001 From: Shinya Yoshida Date: Thu, 29 Sep 2016 17:36:22 +0900 Subject: [PATCH 21/69] 8166744: JShell: java.lang.IndexOutOfBoundsException for legal history access Reviewed-by: rfield, jlahoda --- langtools/test/jdk/jshell/HistoryTest.java | 39 ++++++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/langtools/test/jdk/jshell/HistoryTest.java b/langtools/test/jdk/jshell/HistoryTest.java index 3513e778c22..2dfc9a36a4d 100644 --- a/langtools/test/jdk/jshell/HistoryTest.java +++ b/langtools/test/jdk/jshell/HistoryTest.java @@ -23,6 +23,7 @@ /* * @test + * @bug 8166744 * @summary Test Completion * @modules jdk.internal.le/jdk.internal.jline.extra * jdk.jshell/jdk.internal.jshell.tool @@ -75,6 +76,44 @@ public class HistoryTest extends ReplToolTesting { }); } + public void test8166744() { + test( + a -> {if (!a) setCommandInput("class C {\n");}, + a -> {if (!a) setCommandInput("void f() {\n");}, + a -> {if (!a) setCommandInput("}\n");}, + a -> {assertCommand(a, "}", "| created class C");}, + a -> { + if (!a) { + try { + previousAndAssert(getHistory(), "}"); + previousAndAssert(getHistory(), "}"); + previousAndAssert(getHistory(), "void f() {"); + previousAndAssert(getHistory(), "class C {"); + getHistory().add("class C{"); + } catch (Exception ex) { + throw new IllegalStateException(ex); + } + } + assertCommand(a, "int dummy;", "dummy ==> 0"); + }); + test( + a -> {if (!a) setCommandInput("class C {\n");}, + a -> {if (!a) setCommandInput("void f() {\n");}, + a -> {if (!a) setCommandInput("}\n");}, + a -> {assertCommand(a, "}", "| created class C");}, + a -> { + if (!a) { + try { + previousSnippetAndAssert(getHistory(), "class C {"); + getHistory().add("class C{"); + } catch (Exception ex) { + throw new IllegalStateException(ex); + } + } + assertCommand(a, "int dummy;", "dummy ==> 0"); + }); + } + private EditingHistory getHistory() throws Exception { Field input = repl.getClass().getDeclaredField("input"); input.setAccessible(true); From 31db3330450f61d020427b73d5c283cdb1ec8ca6 Mon Sep 17 00:00:00 2001 From: Lana Steuck Date: Thu, 29 Sep 2016 16:45:08 +0000 Subject: [PATCH 22/69] Added tag jdk-9+138 for changeset de6f69208f82 --- .hgtags-top-repo | 1 + 1 file changed, 1 insertion(+) diff --git a/.hgtags-top-repo b/.hgtags-top-repo index a0cde0979fb..5fdee3f6017 100644 --- a/.hgtags-top-repo +++ b/.hgtags-top-repo @@ -380,3 +380,4 @@ be1218f792a450dfb5d4b1f82616b9d95a6a732e jdk-9+133 82b94cb5f342319d2cda77f9fa59703ad7fde576 jdk-9+135 3ec350f5f32af249b59620d7e37b54bdcd77b233 jdk-9+136 d7f519b004254b19e384131d9f0d0e40e31a0fd3 jdk-9+137 +67c4388142bdf58aec8fefa4475faaa8a5d7380c jdk-9+138 From 762708dbb8958afab57bc2dc54565ed377073c22 Mon Sep 17 00:00:00 2001 From: Lana Steuck Date: Thu, 29 Sep 2016 16:45:08 +0000 Subject: [PATCH 23/69] Added tag jdk-9+138 for changeset f8823c55a1b7 --- corba/.hgtags | 1 + 1 file changed, 1 insertion(+) diff --git a/corba/.hgtags b/corba/.hgtags index e47bd43b69b..46f6d728864 100644 --- a/corba/.hgtags +++ b/corba/.hgtags @@ -380,3 +380,4 @@ f7e1d5337c2e550fe553df7a3886bbed80292ecd jdk-9+131 094d0db606db976045f594dba47d4593b715cc81 jdk-9+135 aa053a3faf266c12b4fd5272da431a3e08e4a3e3 jdk-9+136 258cf18fa7fc59359b874f8743b7168dc48baf73 jdk-9+137 +27bb44be32076861a0951bcefb07a1d92509a4b6 jdk-9+138 From 5e40fe543e5ffc6f1f1471eca55cfb7ce7f18547 Mon Sep 17 00:00:00 2001 From: Lana Steuck Date: Thu, 29 Sep 2016 16:45:09 +0000 Subject: [PATCH 24/69] Added tag jdk-9+138 for changeset b4b4c1119f39 --- hotspot/.hgtags | 1 + 1 file changed, 1 insertion(+) diff --git a/hotspot/.hgtags b/hotspot/.hgtags index c6f688c2bbd..02397a6cce1 100644 --- a/hotspot/.hgtags +++ b/hotspot/.hgtags @@ -540,3 +540,4 @@ b8b694c6b4d2ab0939aed7adaf0eec1ac321a085 jdk-9+134 3b1c4562953db47e36b237a500f368d5c9746d47 jdk-9+135 a20da289f646ee44440695b81abc0548330e4ca7 jdk-9+136 dfcbf839e299e7e2bba1da69bdb347617ea4c7e8 jdk-9+137 +fc0956308c7a586267c5dd35dff74f773aa9c3eb jdk-9+138 From 54ca65037bd63ace7bfb885cf9803d544e47bc52 Mon Sep 17 00:00:00 2001 From: Lana Steuck Date: Thu, 29 Sep 2016 16:45:10 +0000 Subject: [PATCH 25/69] Added tag jdk-9+138 for changeset 7223a315fd01 --- jaxp/.hgtags | 1 + 1 file changed, 1 insertion(+) diff --git a/jaxp/.hgtags b/jaxp/.hgtags index eb923642658..0b75f1ff5b9 100644 --- a/jaxp/.hgtags +++ b/jaxp/.hgtags @@ -380,3 +380,4 @@ e66cdc2de6b02443911d386fc9217b0d824d0686 jdk-9+130 f695240370c77a25fed88225a392e7d530cb4d78 jdk-9+135 f1eafcb0eb7182b937bc93f214d8cabd01ec4d59 jdk-9+136 a8d5fe567ae72b4931040e59dd4478363f9004f5 jdk-9+137 +69c3b12ba75b2e321dee731ac545e7fbff608451 jdk-9+138 From c954db5127d86303f7406d40fc1b33c8dc4e7584 Mon Sep 17 00:00:00 2001 From: Lana Steuck Date: Thu, 29 Sep 2016 16:45:10 +0000 Subject: [PATCH 26/69] Added tag jdk-9+138 for changeset 8ced0dd94a6e --- jaxws/.hgtags | 1 + 1 file changed, 1 insertion(+) diff --git a/jaxws/.hgtags b/jaxws/.hgtags index 73800b65dcd..cada8dfb457 100644 --- a/jaxws/.hgtags +++ b/jaxws/.hgtags @@ -383,3 +383,4 @@ ab1d78d395d4cb8be426ff181211da1a4085cf01 jdk-9+134 22631824f55128a7ab6605493b3001a37af6a168 jdk-9+135 09ec13a99f50a4a346180d1e3b0fd8bc1ee399ce jdk-9+136 297c16d401c534cb879809d2a746d21ca99d2954 jdk-9+137 +7d3a8f52b124db26ba8425c2931b748dd9d2791b jdk-9+138 From 08c0fa1dbf368d004b3d7df823b47a3878e5a727 Mon Sep 17 00:00:00 2001 From: Lana Steuck Date: Thu, 29 Sep 2016 16:45:12 +0000 Subject: [PATCH 27/69] Added tag jdk-9+138 for changeset 4b05dadfb69d --- langtools/.hgtags | 1 + 1 file changed, 1 insertion(+) diff --git a/langtools/.hgtags b/langtools/.hgtags index 959e99614ce..81a826500af 100644 --- a/langtools/.hgtags +++ b/langtools/.hgtags @@ -380,3 +380,4 @@ f08683786207a48b652266b3b7b908e6c863c3fc jdk-9+134 af5eb8f3ffd21288305a54ea177ffad75021a741 jdk-9+135 c8f02f0ecbd7cd6700f47416e4b7e9d5ec20ad77 jdk-9+136 dd56c243c199a540c9f1fbff4855f0934b32a9d0 jdk-9+137 +90dd93e668a521642382561c47abe96ee2e065b7 jdk-9+138 From 6bda29a2da32074d1b59f13e316d40fe1a4118fa Mon Sep 17 00:00:00 2001 From: Lana Steuck Date: Thu, 29 Sep 2016 16:45:12 +0000 Subject: [PATCH 28/69] Added tag jdk-9+138 for changeset b9a1cb9ed1d3 --- nashorn/.hgtags | 1 + 1 file changed, 1 insertion(+) diff --git a/nashorn/.hgtags b/nashorn/.hgtags index 41633a26b9a..8157fdd8c91 100644 --- a/nashorn/.hgtags +++ b/nashorn/.hgtags @@ -371,3 +371,4 @@ e05400ba935753c77697af936db24657eb811022 jdk-9+134 cb00d5ef023a18a66fcb4311ed4474d4145c66e9 jdk-9+135 f11b8f5c4ccbf9c87d283815abac6c0117fba3c0 jdk-9+136 17ed43add2f9e3528686cd786ae2ed49c8ed36e9 jdk-9+137 +4a6ee1185fc821df063e4d1537fa7ad2ebe9eb02 jdk-9+138 From 33b751c3d4b0519ffa1eeb5d57ac2cb7165933c9 Mon Sep 17 00:00:00 2001 From: Mandy Chung Date: Thu, 29 Sep 2016 21:31:09 -0700 Subject: [PATCH 29/69] 8166238: Update jdeps for GNU-style long form options Reviewed-by: alanb --- .../com/sun/tools/jdeps/JdepsTask.java | 52 ++--- .../tools/jdeps/resources/jdeps.properties | 184 +++++++++--------- langtools/test/tools/jdeps/APIDeps.java | 2 +- .../jdeps/jdkinternals/ShowReplacement.java | 2 +- .../tools/jdeps/modules/GenModuleInfo.java | 4 +- .../test/tools/jdeps/modules/InverseDeps.java | 14 +- .../jdeps/modules/src/m3/module-info.java | 2 +- 7 files changed, 133 insertions(+), 127 deletions(-) diff --git a/langtools/src/jdk.jdeps/share/classes/com/sun/tools/jdeps/JdepsTask.java b/langtools/src/jdk.jdeps/share/classes/com/sun/tools/jdeps/JdepsTask.java index 862c5261859..3bacd6fc034 100644 --- a/langtools/src/jdk.jdeps/share/classes/com/sun/tools/jdeps/JdepsTask.java +++ b/langtools/src/jdk.jdeps/share/classes/com/sun/tools/jdeps/JdepsTask.java @@ -150,7 +150,7 @@ class JdepsTask { task.options.help = true; } }, - new Option(true, "-dotoutput") { + new Option(true, "-dotoutput", "--dot-output") { void process(JdepsTask task, String opt, String arg) throws BadArgs { Path p = Paths.get(arg); if (Files.exists(p) && (!Files.isDirectory(p) || !Files.isWritable(p))) { @@ -191,7 +191,7 @@ class JdepsTask { } } }, - new Option(false, "-apionly") { + new Option(false, "-apionly", "--api-only") { void process(JdepsTask task, String opt, String arg) { task.options.apiOnly = true; } @@ -203,7 +203,7 @@ class JdepsTask { task.options.addmods.addAll(mods); } }, - new Option(true, "--gen-module-info") { + new Option(true, "--generate-module-info") { void process(JdepsTask task, String opt, String arg) throws BadArgs { Path p = Paths.get(arg); if (Files.exists(p) && (!Files.isDirectory(p) || !Files.isWritable(p))) { @@ -212,7 +212,7 @@ class JdepsTask { task.options.genModuleInfo = Paths.get(arg); } }, - new Option(false, "-jdkinternals") { + new Option(false, "-jdkinternals", "--jdk-internals") { void process(JdepsTask task, String opt, String arg) { task.options.findJDKInternals = true; task.options.verbose = CLASS; @@ -263,19 +263,36 @@ class JdepsTask { task.options.addmods.add(arg); } }, + new Option(true, "--multi-release") { + void process(JdepsTask task, String opt, String arg) throws BadArgs { + if (arg.equalsIgnoreCase("base")) { + task.options.multiRelease = JarFile.baseVersion(); + } else { + try { + int v = Integer.parseInt(arg); + if (v < 9) { + throw new BadArgs("err.invalid.arg.for.option", arg); + } + } catch (NumberFormatException x) { + throw new BadArgs("err.invalid.arg.for.option", arg); + } + task.options.multiRelease = Runtime.Version.parse(arg); + } + } + }, // ---- Target filtering options ---- - new Option(true, "-p", "-package") { + new Option(true, "-p", "-package", "--package") { void process(JdepsTask task, String opt, String arg) { task.options.packageNames.add(arg); } }, - new Option(true, "-e", "-regex") { + new Option(true, "-e", "-regex", "--regex") { void process(JdepsTask task, String opt, String arg) { task.options.regex = Pattern.compile(arg); } }, - new Option(true, "-requires") { + new Option(true, "--require") { void process(JdepsTask task, String opt, String arg) { task.options.requires.add(arg); } @@ -336,7 +353,7 @@ class JdepsTask { } }, - new Option(false, "-I", "-inverse") { + new Option(false, "-I", "--inverse") { void process(JdepsTask task, String opt, String arg) { task.options.inverse = true; // equivalent to the inverse of compile-time view analysis @@ -361,7 +378,7 @@ class JdepsTask { } }, - new Option(false, "-version") { + new Option(false, "-version", "--version") { void process(JdepsTask task, String opt, String arg) { task.options.version = true; } @@ -390,23 +407,6 @@ class JdepsTask { } } }, - new Option(true, "--multi-release") { - void process(JdepsTask task, String opt, String arg) throws BadArgs { - if (arg.equalsIgnoreCase("base")) { - task.options.multiRelease = JarFile.baseVersion(); - } else { - try { - int v = Integer.parseInt(arg); - if (v < 9) { - throw new BadArgs("err.invalid.arg.for.option", arg); - } - } catch (NumberFormatException x) { - throw new BadArgs("err.invalid.arg.for.option", arg); - } - task.options.multiRelease = Runtime.Version.parse(arg); - } - } - }, }; private static final String PROGNAME = "jdeps"; diff --git a/langtools/src/jdk.jdeps/share/classes/com/sun/tools/jdeps/resources/jdeps.properties b/langtools/src/jdk.jdeps/share/classes/com/sun/tools/jdeps/resources/jdeps.properties index 821c99d54e9..c2858c84120 100644 --- a/langtools/src/jdk.jdeps/share/classes/com/sun/tools/jdeps/resources/jdeps.properties +++ b/langtools/src/jdk.jdeps/share/classes/com/sun/tools/jdeps/resources/jdeps.properties @@ -13,162 +13,168 @@ warn.prefix=Warning: main.opt.h=\ \ -h -? -help\n\ -\ --help Print this usage message +\ --help Print this usage message main.opt.version=\ -\ -version Version information +\ -version --version Version information main.opt.v=\ -\ -v -verbose Print all class level dependencies\n\ -\ Equivalent to -verbose:class -filter:none.\n\ -\ -verbose:package Print package-level dependencies excluding\n\ -\ dependencies within the same package by default\n\ -\ -verbose:class Print class-level dependencies excluding\n\ -\ dependencies within the same package by default +\ -v -verbose Print all class level dependences\n\ +\ Equivalent to -verbose:class -filter:none.\n\ +\ -verbose:package Print package-level dependences excluding\n\ +\ dependences within the same package by default\n\ +\ -verbose:class Print class-level dependences excluding\n\ +\ dependences within the same package by default main.opt.s=\ -\ -s -summary Print dependency summary only. +\ -s -summary Print dependency summary only. main.opt.f=\ -\ -f -filter Filter dependences matching the given\n\ -\ pattern. If given multiple times, the last\n\ -\ one will be used.\n\ -\ -filter:package Filter dependences within the same package.\n\ -\ This is the default.\n\ -\ -filter:archive Filter dependences within the same archive.\n\ -\ -filter:module Filter dependences within the same module.\n\ -\ -filter:none No -filter:package and -filter:archive\n\ -\ filtering. Filtering specified via the\n\ -\ -filter option still applies.\n\ +\ -f -filter Filter dependences matching the given\n\ +\ pattern. If given multiple times, the last\n\ +\ one will be used.\n\ +\ -filter:package Filter dependences within the same package.\n\ +\ This is the default.\n\ +\ -filter:archive Filter dependences within the same archive.\n\ +\ -filter:module Filter dependences within the same module.\n\ +\ -filter:none No -filter:package and -filter:archive\n\ +\ filtering. Filtering specified via the\n\ +\ -filter option still applies.\n\ main.opt.p=\n\ -\Options to filter dependencies:\n\ -\ -p -package Finds dependences matching the given package\n\ -\ name (may be given multiple times). +\Options to filter dependences:\n\ +\ -p \n\ +\ -package \n\ +\ --package Finds dependences matching the given package\n\ +\ name (may be given multiple times). main.opt.e=\ -\ -e -regex Finds dependences matching the given pattern. +\ -e \n\ +\ -regex \n\ +\ --regex Finds dependences matching the given pattern. -main.opt.requires=\ -\ -requires Finds dependences matching the given module\n\ -\ name (may be given multiple times).\n\ -\ -package, -regex, -requires are mutual exclusive. +main.opt.require=\ +\ --require Finds dependences matching the given module\n\ +\ name (may be given multiple times). --package,\n\ +\ --regex, --require are mutual exclusive. main.opt.include=\n\ \Options to filter classes to be analyzed:\n\ -\ -include Restrict analysis to classes matching pattern\n\ -\ This option filters the list of classes to\n\ -\ be analyzed. It can be used together with\n\ -\ -p and -e which apply pattern to the dependences +\ -include Restrict analysis to classes matching pattern\n\ +\ This option filters the list of classes to\n\ +\ be analyzed. It can be used together with\n\ +\ -p and -e which apply pattern to the dependences main.opt.P=\ -\ -P -profile Show profile containing a package +\ -P -profile Show profile containing a package main.opt.cp=\ \ -cp \n\ \ -classpath \n\ -\ --class-path Specify where to find class files +\ --class-path Specify where to find class files main.opt.module-path=\ -\ --module-path ... Specify module path +\ --module-path Specify module path main.opt.upgrade-module-path=\ -\ --upgrade-module-path ... Specify upgrade module path +\ --upgrade-module-path Specify upgrade module path main.opt.system=\ -\ --system Specify an alternate system module path +\ --system Specify an alternate system module path main.opt.add-modules=\ \ --add-modules [,...]\n\ -\ Adds modules to the root set for analysis +\ Adds modules to the root set for analysis main.opt.m=\ \ -m \n\ -\ --module Specify the root module for analysis +\ --module Specify the root module for analysis main.opt.R=\ -\ -R -recursive Recursively traverse all run-time dependencies.\n\ -\ The -R option implies -filter:none. If -p,\n\ -\ -e, -foption is specified, only the matching\n\ -\ dependences are analyzed. +\ -R -recursive Recursively traverse all run-time dependences.\n\ +\ The -R option implies -filter:none. If -p,\n\ +\ -e, -foption is specified, only the matching\n\ +\ dependences are analyzed. main.opt.I=\ -\ -I -inverse Analyzes the dependences per other given options\n\ -\ and then find all artifacts that directly\n\ -\ and indirectly depend on the matching nodes.\n\ -\ This is equivalent to the inverse of\n\ -\ compile-time view analysis and print\n\ -\ dependency summary. This option must use\n\ -\ with -requires, -package or -regex option. +\ -I --inverse Analyzes the dependences per other given options\n\ +\ and then find all artifacts that directly\n\ +\ and indirectly depend on the matching nodes.\n\ +\ This is equivalent to the inverse of\n\ +\ compile-time view analysis and print\n\ +\ dependency summary. This option must use\n\ +\ with --require, --package or --regex option. main.opt.compile-time=\ -\ --compile-time Compile-time view of transitive dependencies\n\ -\ i.e. compile-time view of -R option.\n\ -\ Analyzes the dependences per other given options\n\ -\ If a dependence is found from a directory,\n\ -\ a JAR file or a module, all classes in that \n\ -\ containing archive are analyzed. +\ --compile-time Compile-time view of transitive dependences\n\ +\ i.e. compile-time view of -R option.\n\ +\ Analyzes the dependences per other given options\n\ +\ If a dependence is found from a directory,\n\ +\ a JAR file or a module, all classes in that \n\ +\ containing archive are analyzed. main.opt.apionly=\ -\ -apionly Restrict analysis to APIs i.e. dependences\n\ -\ from the signature of public and protected\n\ -\ members of public classes including field\n\ -\ type, method parameter types, returned type,\n\ -\ checked exception types etc. +\ -apionly\n\ +\ --api-only Restrict analysis to APIs i.e. dependences\n\ +\ from the signature of public and protected\n\ +\ members of public classes including field\n\ +\ type, method parameter types, returned type,\n\ +\ checked exception types etc. -main.opt.gen-module-info=\ -\ --gen-module-info Generate module-info.java under the specified\n\ -\ directory. The specified JAR files will be\n\ -\ analyzed. This option cannot be used with\n\ -\ -dotoutput or -cp. +main.opt.generate-module-info=\ +\ --generate-module-info Generate module-info.java under the specified\n\ +\ directory. The specified JAR files will be\n\ +\ analyzed. This option cannot be used with\n\ +\ --dot-output or --class-path. main.opt.check=\ \ --check [,...\n\ -\ Analyze the dependence of the specified modules\n\ -\ It prints the module descriptor, the resulting\n\ -\ module dependences after analysis and the\n\ -\ graph after transition reduction. It also\n\ -\ identifies any unused qualified exports. +\ Analyze the dependence of the specified modules\n\ +\ It prints the module descriptor, the resulting\n\ +\ module dependences after analysis and the\n\ +\ graph after transition reduction. It also\n\ +\ identifies any unused qualified exports. main.opt.dotoutput=\ -\ -dotoutput Destination directory for DOT file output +\ -dotoutput \n\ +\ --dot-output Destination directory for DOT file output main.opt.jdkinternals=\ -\ -jdkinternals Finds class-level dependences on JDK internal\n\ -\ APIs. By default, it analyzes all classes\n\ -\ on -classpath and input files unless -include\n\ -\ option is specified. This option cannot be\n\ -\ used with -p, -e and -s options.\n\ -\ WARNING: JDK internal APIs are inaccessible. +\ -jdkinternals\n\ +\ --jdk-internals Finds class-level dependences on JDK internal\n\ +\ APIs. By default, it analyzes all classes\n\ +\ on --class-path and input files unless -include\n\ +\ option is specified. This option cannot be\n\ +\ used with -p, -e and -s options.\n\ +\ WARNING: JDK internal APIs are inaccessible. main.opt.depth=\ -\ -depth= Specify the depth of the transitive\n\ -\ dependency analysis +\ -depth= Specify the depth of the transitive\n\ +\ dependency analysis main.opt.q=\ -\ -q -quiet Do not show missing dependencies from \n\ -\ -genmoduleinfo output. +\ -q -quiet Do not show missing dependences from \n\ +\ --generate-module-info output. main.opt.multi-release=\ -\ --multi-release Specifies the version when processing\n\ -\ multi-release jar files. should\n\ -\ be integer >= 9 or base. +\ --multi-release Specifies the version when processing\n\ +\ multi-release jar files. should\n\ +\ be integer >= 9 or base. err.unknown.option=unknown option: {0} err.missing.arg=no value given for {0} err.invalid.arg.for.option=invalid argument for option: {0} err.option.after.class=option must be specified before classes: {0} -err.genmoduleinfo.not.jarfile={0} not valid for --gen-module-info option (must be non-modular JAR file) +err.genmoduleinfo.not.jarfile={0} not valid for --generate-module-info option (must be non-modular JAR file) err.profiles.msg=No profile information err.exception.message={0} err.invalid.path=invalid path: {0} err.invalid.module.option=Cannot set {0} with {1} option. -err.invalid.filters=Only one of -package (-p), -regex (-e), -requires option can be set +err.invalid.filters=Only one of --package (-p), --regex (-e), --require option can be set err.module.not.found=module not found: {0} err.root.module.not.set=root module set empty -err.invalid.inverse.option={0} cannot be used with -inverse option -err.inverse.filter.not.set={0} cannot be used with -inverse option +err.invalid.inverse.option={0} cannot be used with --inverse option err.multirelease.option.exists={0} is not a multi-release jar file, but the --multi-release option is set err.multirelease.option.notfound={0} is a multi-release jar file, but the --multi-release option is not set err.multirelease.version.associated=class {0} already associated with version {1}, trying to add version {2} @@ -178,7 +184,7 @@ warn.split.package=package {0} defined in {1} {2} warn.replace.useJDKInternals=\ JDK internal APIs are unsupported and private to JDK implementation that are\n\ subject to be removed or changed incompatibly and could break your application.\n\ -Please modify your code to eliminate dependency on any JDK internal APIs.\n\ +Please modify your code to eliminate dependence on any JDK internal APIs.\n\ For the most recent update on JDK internal API replacements, please check:\n\ {0} diff --git a/langtools/test/tools/jdeps/APIDeps.java b/langtools/test/tools/jdeps/APIDeps.java index 78665f5b258..2e50ccf0135 100644 --- a/langtools/test/tools/jdeps/APIDeps.java +++ b/langtools/test/tools/jdeps/APIDeps.java @@ -135,7 +135,7 @@ public class APIDeps { "java.util.Set", "c.C", "d.D", "c.I", "e.E", "m.Bar"}, new String[] {"compact1", testDirBasename, mDir.getName()}, - new String[] {"-classpath", testDir.getPath(), "-verbose", "-P", "-apionly"}); + new String[] {"-classpath", testDir.getPath(), "-verbose", "-P", "--api-only"}); return errors; } diff --git a/langtools/test/tools/jdeps/jdkinternals/ShowReplacement.java b/langtools/test/tools/jdeps/jdkinternals/ShowReplacement.java index dfe0f5f8a19..7f5bb5ea456 100644 --- a/langtools/test/tools/jdeps/jdkinternals/ShowReplacement.java +++ b/langtools/test/tools/jdeps/jdkinternals/ShowReplacement.java @@ -116,7 +116,7 @@ public class ShowReplacement { @Test public void removedPackage() { Path file = Paths.get("q", "RemovedPackage.class"); - String[] output = JdepsUtil.jdeps("-jdkinternals", CLASSES_DIR.resolve(file).toString()); + String[] output = JdepsUtil.jdeps("--jdk-internals", CLASSES_DIR.resolve(file).toString()); int i = 0; // expect no replacement while (i < output.length && !output[i].contains("Suggested Replacement")) { diff --git a/langtools/test/tools/jdeps/modules/GenModuleInfo.java b/langtools/test/tools/jdeps/modules/GenModuleInfo.java index b056c9405f8..3cc391af3c4 100644 --- a/langtools/test/tools/jdeps/modules/GenModuleInfo.java +++ b/langtools/test/tools/jdeps/modules/GenModuleInfo.java @@ -23,7 +23,7 @@ /* * @test - * @summary Tests jdeps --gen-module-info option + * @summary Tests jdeps --generate-module-info option * @library ../lib * @build CompilerUtils JdepsUtil * @modules jdk.jdeps/com.sun.tools.jdeps @@ -106,7 +106,7 @@ public class GenModuleInfo { .map(mn -> LIBS_DIR.resolve(mn + ".jar")) .map(Path::toString); - JdepsUtil.jdeps(Stream.concat(Stream.of("--gen-module-info", DEST_DIR.toString()), + JdepsUtil.jdeps(Stream.concat(Stream.of("--generate-module-info", DEST_DIR.toString()), files).toArray(String[]::new)); // check file exists diff --git a/langtools/test/tools/jdeps/modules/InverseDeps.java b/langtools/test/tools/jdeps/modules/InverseDeps.java index 6ec3352692b..884651d83f9 100644 --- a/langtools/test/tools/jdeps/modules/InverseDeps.java +++ b/langtools/test/tools/jdeps/modules/InverseDeps.java @@ -91,7 +91,7 @@ public class InverseDeps { @DataProvider(name = "testrequires") public Object[][] expected1() { return new Object[][] { - // -requires and result + // --require and result { "java.sql", new String[][] { new String[] { "java.sql", "m5" }, } @@ -117,7 +117,7 @@ public class InverseDeps { @Test(dataProvider = "testrequires") public void testrequires(String name, String[][] expected) throws Exception { - String cmd1 = String.format("jdeps -inverse --module-path %s -requires %s --add-modules %s%n", + String cmd1 = String.format("jdeps --inverse --module-path %s --require %s --add-modules %s%n", MODS_DIR, name, modules.stream().collect(Collectors.joining(","))); try (JdepsUtil.Command jdeps = JdepsUtil.newCommand(cmd1)) { @@ -128,7 +128,7 @@ public class InverseDeps { runJdeps(jdeps, expected); } - String cmd2 = String.format("jdeps -inverse --module-path %s -requires %s" + + String cmd2 = String.format("jdeps --inverse --module-path %s --require %s" + " --add-modules ALL-MODULE-PATH%n", LIBS_DIR, name); // automatic module @@ -164,7 +164,7 @@ public class InverseDeps { @Test(dataProvider = "testpackage") public void testpackage(String name, String[][] expected) throws Exception { - String cmd = String.format("jdeps -inverse --module-path %s -package %s --add-modules %s%n", + String cmd = String.format("jdeps --inverse --module-path %s -package %s --add-modules %s%n", MODS_DIR, name, modules.stream().collect(Collectors.joining(","))); try (JdepsUtil.Command jdeps = JdepsUtil.newCommand(cmd)) { jdeps.appModulePath(MODS_DIR.toString()) @@ -195,7 +195,7 @@ public class InverseDeps { @Test(dataProvider = "testregex") public void testregex(String name, String[][] expected) throws Exception { - String cmd = String.format("jdeps -inverse --module-path %s -regex %s --add-modules %s%n", + String cmd = String.format("jdeps --inverse --module-path %s -regex %s --add-modules %s%n", MODS_DIR, name, modules.stream().collect(Collectors.joining(","))); try (JdepsUtil.Command jdeps = JdepsUtil.newCommand(cmd)) { @@ -240,7 +240,7 @@ public class InverseDeps { Path jarfile = LIBS_DIR.resolve("m7.jar"); - String cmd1 = String.format("jdeps -inverse -classpath %s -regex %s %s%n", + String cmd1 = String.format("jdeps --inverse -classpath %s -regex %s %s%n", cpath, name, jarfile); try (JdepsUtil.Command jdeps = JdepsUtil.newCommand(cmd1)) { jdeps.verbose("-verbose:class") @@ -253,7 +253,7 @@ public class InverseDeps { Set paths = modules.stream() .map(mn -> LIBS_DIR.resolve(mn + ".jar")) .collect(Collectors.toSet()); - String cmd2 = String.format("jdeps -inverse -regex %s %s%n", name, paths); + String cmd2 = String.format("jdeps --inverse -regex %s %s%n", name, paths); try (JdepsUtil.Command jdeps = JdepsUtil.newCommand(cmd2)) { jdeps.verbose("-verbose:class").regex(name); paths.forEach(jdeps::addRoot); diff --git a/langtools/test/tools/jdeps/modules/src/m3/module-info.java b/langtools/test/tools/jdeps/modules/src/m3/module-info.java index e58165da18d..62557e8f0b6 100644 --- a/langtools/test/tools/jdeps/modules/src/m3/module-info.java +++ b/langtools/test/tools/jdeps/modules/src/m3/module-info.java @@ -24,7 +24,7 @@ module m3 { requires public java.sql; requires public m2; - requires java.logging; // TODO: --gen-module-info to do transitive reduction + requires java.logging; // TODO: --generate-module-info to do transitive reduction requires public m1; exports p3; } From 7ddf27c21d805b6971e62242bfcc66e4b16e267c Mon Sep 17 00:00:00 2001 From: Erik Joelsson Date: Fri, 30 Sep 2016 09:05:40 +0200 Subject: [PATCH 30/69] 8160630: libjimage.so and others should link statically to libgcc Reviewed-by: ihse, tbell --- common/autoconf/buildjdk-spec.gmk.in | 1 + common/autoconf/generated-configure.sh | 80 ++------------------------ common/autoconf/lib-std.m4 | 50 ++-------------- 3 files changed, 12 insertions(+), 119 deletions(-) diff --git a/common/autoconf/buildjdk-spec.gmk.in b/common/autoconf/buildjdk-spec.gmk.in index c4b7d9051cc..a643d82e45b 100644 --- a/common/autoconf/buildjdk-spec.gmk.in +++ b/common/autoconf/buildjdk-spec.gmk.in @@ -33,6 +33,7 @@ include @SPEC@ CC := @BUILD_CC@ CXX := @BUILD_CXX@ LD := @BUILD_LD@ +LDCXX := @BUILD_LDCXX@ AS := @BUILD_AS@ NM := @BUILD_NM@ AR := @BUILD_AR@ diff --git a/common/autoconf/generated-configure.sh b/common/autoconf/generated-configure.sh index 796784ed18b..48b23344af8 100644 --- a/common/autoconf/generated-configure.sh +++ b/common/autoconf/generated-configure.sh @@ -687,7 +687,6 @@ XMKMF MSVCP_DLL MSVCR_DLL LIBCXX -STATIC_CXX_SETTING FIXPATH_DETACH_FLAG FIXPATH BUILD_GTEST @@ -5092,7 +5091,7 @@ VS_SDK_PLATFORM_NAME_2013= #CUSTOM_AUTOCONF_INCLUDE # Do not change or remove the following line, it is needed for consistency checks: -DATE_WHEN_GENERATED=1474894604 +DATE_WHEN_GENERATED=1475218974 ############################################################################### # @@ -53087,49 +53086,10 @@ fi if test "x$OPENJDK_TARGET_OS" = xlinux; then - # Test if -lstdc++ works. - { $as_echo "$as_me:${as_lineno-$LINENO}: checking if dynamic link of stdc++ is possible" >&5 -$as_echo_n "checking if dynamic link of stdc++ is possible... " >&6; } - ac_ext=cpp -ac_cpp='$CXXCPP $CPPFLAGS' -ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' -ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' -ac_compiler_gnu=$ac_cv_cxx_compiler_gnu - - OLD_CXXFLAGS="$CXXFLAGS" - CXXFLAGS="$CXXFLAGS -lstdc++" - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -int -main () -{ -return 0; - ; - return 0; -} -_ACEOF -if ac_fn_cxx_try_link "$LINENO"; then : - has_dynamic_libstdcxx=yes -else - has_dynamic_libstdcxx=no -fi -rm -f core conftest.err conftest.$ac_objext \ - conftest$ac_exeext conftest.$ac_ext - CXXFLAGS="$OLD_CXXFLAGS" - ac_ext=cpp -ac_cpp='$CXXCPP $CPPFLAGS' -ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' -ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' -ac_compiler_gnu=$ac_cv_cxx_compiler_gnu - - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $has_dynamic_libstdcxx" >&5 -$as_echo "$has_dynamic_libstdcxx" >&6; } - # Test if stdc++ can be linked statically. { $as_echo "$as_me:${as_lineno-$LINENO}: checking if static link of stdc++ is possible" >&5 $as_echo_n "checking if static link of stdc++ is possible... " >&6; } - STATIC_STDCXX_FLAGS="-Wl,-Bstatic -lstdc++ -lgcc -Wl,-Bdynamic" + STATIC_STDCXX_FLAGS="-static-libstdc++ -static-libgcc" ac_ext=cpp ac_cpp='$CXXCPP $CPPFLAGS' ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' @@ -53137,9 +53097,7 @@ ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ex ac_compiler_gnu=$ac_cv_cxx_compiler_gnu OLD_LIBS="$LIBS" - OLD_CXX="$CXX" LIBS="$STATIC_STDCXX_FLAGS" - CXX="$CC" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ @@ -53159,7 +53117,6 @@ fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS="$OLD_LIBS" - CXX="$OLD_CXX" ac_ext=cpp ac_cpp='$CXXCPP $CPPFLAGS' ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' @@ -53169,59 +53126,34 @@ ac_compiler_gnu=$ac_cv_cxx_compiler_gnu { $as_echo "$as_me:${as_lineno-$LINENO}: result: $has_static_libstdcxx" >&5 $as_echo "$has_static_libstdcxx" >&6; } - if test "x$has_static_libstdcxx" = xno && test "x$has_dynamic_libstdcxx" = xno; then - as_fn_error $? "Cannot link to stdc++, neither dynamically nor statically!" "$LINENO" 5 - fi - if test "x$with_stdc__lib" = xstatic && test "x$has_static_libstdcxx" = xno; then as_fn_error $? "Static linking of libstdc++ was not possible!" "$LINENO" 5 fi - if test "x$with_stdc__lib" = xdynamic && test "x$has_dynamic_libstdcxx" = xno; then - as_fn_error $? "Dynamic linking of libstdc++ was not possible!" "$LINENO" 5 - fi - # If dynamic was requested, it's available since it would fail above otherwise. # If dynamic wasn't requested, go with static unless it isn't available. { $as_echo "$as_me:${as_lineno-$LINENO}: checking how to link with libstdc++" >&5 $as_echo_n "checking how to link with libstdc++... " >&6; } - if test "x$with_stdc__lib" = xdynamic || test "x$has_static_libstdcxx" = xno || [[ " $JVM_VARIANTS " =~ " zeroshark " ]] ; then - LIBCXX="$LIBCXX -lstdc++" - # To help comparisons with old build, put stdc++ first in JVM_LIBS - JVM_LIBS="-lstdc++ $JVM_LIBS" - # Ideally, we should test stdc++ for the BUILD toolchain separately. For now - # just use the same setting as for the TARGET toolchain. - OPENJDK_BUILD_JVM_LIBS="-lstdc++ $OPENJDK_BUILD_JVM_LIBS" - LDCXX="$CXX" - STATIC_CXX_SETTING="STATIC_CXX=false" + if test "x$with_stdc__lib" = xdynamic || test "x$has_static_libstdcxx" = xno \ + || [[ " $JVM_VARIANTS " =~ " zeroshark " ]] ; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: dynamic" >&5 $as_echo "dynamic" >&6; } else LIBCXX="$LIBCXX $STATIC_STDCXX_FLAGS" - JVM_LDFLAGS="$JVM_LDFLAGS -static-libgcc" - # To help comparisons with old build, put stdc++ first in JVM_LIBS - JVM_LIBS="-Wl,-Bstatic -lstdc++ -Wl,-Bdynamic $JVM_LIBS" + JVM_LDFLAGS="$JVM_LDFLAGS $STATIC_STDCXX_FLAGS" # Ideally, we should test stdc++ for the BUILD toolchain separately. For now # just use the same setting as for the TARGET toolchain. - OPENJDK_BUILD_JVM_LDFLAGS="$OPENJDK_BUILD_JVM_LDFLAGS -static-libgcc" - OPENJDK_BUILD_JVM_LIBS="-Wl,-Bstatic -lstdc++ -Wl,-Bdynamic $OPENJDK_BUILD_JVM_LIBS" - LDCXX="$CC" - STATIC_CXX_SETTING="STATIC_CXX=true" + OPENJDK_BUILD_JVM_LDFLAGS="$OPENJDK_BUILD_JVM_LDFLAGS $STATIC_STDCXX_FLAGS" { $as_echo "$as_me:${as_lineno-$LINENO}: result: static" >&5 $as_echo "static" >&6; } fi fi - # libCrun is the c++ runtime-library with SunStudio (roughly the equivalent of gcc's libstdc++.so) if test "x$TOOLCHAIN_TYPE" = xsolstudio && test "x$LIBCXX" = x; then LIBCXX="${SYSROOT}/usr/lib${OPENJDK_TARGET_CPU_ISADIR}/libCrun.so.1" fi - # TODO better (platform agnostic) test - if test "x$OPENJDK_TARGET_OS" = xmacosx && test "x$LIBCXX" = x && test "x$TOOLCHAIN_TYPE" = xgcc; then - LIBCXX="-lstdc++" - fi # Setup Windows runtime dlls diff --git a/common/autoconf/lib-std.m4 b/common/autoconf/lib-std.m4 index 6fa0b4844af..ceb8a45ca89 100644 --- a/common/autoconf/lib-std.m4 +++ b/common/autoconf/lib-std.m4 @@ -45,84 +45,44 @@ AC_DEFUN_ONCE([LIB_SETUP_STD_LIBS], ) if test "x$OPENJDK_TARGET_OS" = xlinux; then - # Test if -lstdc++ works. - AC_MSG_CHECKING([if dynamic link of stdc++ is possible]) - AC_LANG_PUSH(C++) - OLD_CXXFLAGS="$CXXFLAGS" - CXXFLAGS="$CXXFLAGS -lstdc++" - AC_LINK_IFELSE([AC_LANG_PROGRAM([], [return 0;])], - [has_dynamic_libstdcxx=yes], - [has_dynamic_libstdcxx=no]) - CXXFLAGS="$OLD_CXXFLAGS" - AC_LANG_POP(C++) - AC_MSG_RESULT([$has_dynamic_libstdcxx]) - # Test if stdc++ can be linked statically. AC_MSG_CHECKING([if static link of stdc++ is possible]) - STATIC_STDCXX_FLAGS="-Wl,-Bstatic -lstdc++ -lgcc -Wl,-Bdynamic" + STATIC_STDCXX_FLAGS="-static-libstdc++ -static-libgcc" AC_LANG_PUSH(C++) OLD_LIBS="$LIBS" - OLD_CXX="$CXX" LIBS="$STATIC_STDCXX_FLAGS" - CXX="$CC" AC_LINK_IFELSE([AC_LANG_PROGRAM([], [return 0;])], [has_static_libstdcxx=yes], [has_static_libstdcxx=no]) LIBS="$OLD_LIBS" - CXX="$OLD_CXX" AC_LANG_POP(C++) AC_MSG_RESULT([$has_static_libstdcxx]) - if test "x$has_static_libstdcxx" = xno && test "x$has_dynamic_libstdcxx" = xno; then - AC_MSG_ERROR([Cannot link to stdc++, neither dynamically nor statically!]) - fi - if test "x$with_stdc__lib" = xstatic && test "x$has_static_libstdcxx" = xno; then AC_MSG_ERROR([Static linking of libstdc++ was not possible!]) fi - if test "x$with_stdc__lib" = xdynamic && test "x$has_dynamic_libstdcxx" = xno; then - AC_MSG_ERROR([Dynamic linking of libstdc++ was not possible!]) - fi - # If dynamic was requested, it's available since it would fail above otherwise. # If dynamic wasn't requested, go with static unless it isn't available. AC_MSG_CHECKING([how to link with libstdc++]) - if test "x$with_stdc__lib" = xdynamic || test "x$has_static_libstdcxx" = xno || HOTSPOT_CHECK_JVM_VARIANT(zeroshark); then - LIBCXX="$LIBCXX -lstdc++" - # To help comparisons with old build, put stdc++ first in JVM_LIBS - JVM_LIBS="-lstdc++ $JVM_LIBS" - # Ideally, we should test stdc++ for the BUILD toolchain separately. For now - # just use the same setting as for the TARGET toolchain. - OPENJDK_BUILD_JVM_LIBS="-lstdc++ $OPENJDK_BUILD_JVM_LIBS" - LDCXX="$CXX" - STATIC_CXX_SETTING="STATIC_CXX=false" + if test "x$with_stdc__lib" = xdynamic || test "x$has_static_libstdcxx" = xno \ + || HOTSPOT_CHECK_JVM_VARIANT(zeroshark); then AC_MSG_RESULT([dynamic]) else LIBCXX="$LIBCXX $STATIC_STDCXX_FLAGS" - JVM_LDFLAGS="$JVM_LDFLAGS -static-libgcc" - # To help comparisons with old build, put stdc++ first in JVM_LIBS - JVM_LIBS="-Wl,-Bstatic -lstdc++ -Wl,-Bdynamic $JVM_LIBS" + JVM_LDFLAGS="$JVM_LDFLAGS $STATIC_STDCXX_FLAGS" # Ideally, we should test stdc++ for the BUILD toolchain separately. For now # just use the same setting as for the TARGET toolchain. - OPENJDK_BUILD_JVM_LDFLAGS="$OPENJDK_BUILD_JVM_LDFLAGS -static-libgcc" - OPENJDK_BUILD_JVM_LIBS="-Wl,-Bstatic -lstdc++ -Wl,-Bdynamic $OPENJDK_BUILD_JVM_LIBS" - LDCXX="$CC" - STATIC_CXX_SETTING="STATIC_CXX=true" + OPENJDK_BUILD_JVM_LDFLAGS="$OPENJDK_BUILD_JVM_LDFLAGS $STATIC_STDCXX_FLAGS" AC_MSG_RESULT([static]) fi fi - AC_SUBST(STATIC_CXX_SETTING) # libCrun is the c++ runtime-library with SunStudio (roughly the equivalent of gcc's libstdc++.so) if test "x$TOOLCHAIN_TYPE" = xsolstudio && test "x$LIBCXX" = x; then LIBCXX="${SYSROOT}/usr/lib${OPENJDK_TARGET_CPU_ISADIR}/libCrun.so.1" fi - # TODO better (platform agnostic) test - if test "x$OPENJDK_TARGET_OS" = xmacosx && test "x$LIBCXX" = x && test "x$TOOLCHAIN_TYPE" = xgcc; then - LIBCXX="-lstdc++" - fi AC_SUBST(LIBCXX) # Setup Windows runtime dlls From ebba4ba1c1bb44237f644dc10c00114c12374bdc Mon Sep 17 00:00:00 2001 From: Erik Joelsson Date: Fri, 30 Sep 2016 09:06:02 +0200 Subject: [PATCH 31/69] 8160630: libjimage.so and others should link statically to libgcc Reviewed-by: ihse, tbell --- hotspot/make/lib/CompileGtest.gmk | 4 ++-- hotspot/make/lib/CompileJvm.gmk | 9 +-------- 2 files changed, 3 insertions(+), 10 deletions(-) diff --git a/hotspot/make/lib/CompileGtest.gmk b/hotspot/make/lib/CompileGtest.gmk index 803413b8402..1f7c317a427 100644 --- a/hotspot/make/lib/CompileGtest.gmk +++ b/hotspot/make/lib/CompileGtest.gmk @@ -55,7 +55,7 @@ endif # Disabling switch warning for clang because of test source. $(eval $(call SetupNativeCompilation, BUILD_GTEST_LIBJVM, \ - TOOLCHAIN := $(JVM_TOOLCHAIN), \ + TOOLCHAIN := TOOLCHAIN_LINK_CXX, \ LIBRARY := jvm, \ OUTPUT_DIR := $(JVM_OUTPUTDIR)/gtest, \ OBJECT_DIR := $(JVM_OUTPUTDIR)/gtest/objs, \ @@ -95,7 +95,7 @@ TARGETS += $(BUILD_GTEST_LIBJVM) ################################################################################ $(eval $(call SetupNativeCompilation, BUILD_GTEST_LAUNCHER, \ - TOOLCHAIN := $(JVM_TOOLCHAIN), \ + TOOLCHAIN := TOOLCHAIN_LINK_CXX, \ PROGRAM := gtestLauncher, \ OUTPUT_DIR := $(JVM_OUTPUTDIR)/gtest, \ EXTRA_FILES := $(GTEST_LAUNCHER_SRC), \ diff --git a/hotspot/make/lib/CompileJvm.gmk b/hotspot/make/lib/CompileJvm.gmk index 65d58e40e93..6901fc27d76 100644 --- a/hotspot/make/lib/CompileJvm.gmk +++ b/hotspot/make/lib/CompileJvm.gmk @@ -143,13 +143,6 @@ ifneq ($(filter $(OPENJDK_TARGET_OS), linux macosx windows), ) JVM_PRECOMPILED_HEADER := $(HOTSPOT_TOPDIR)/src/share/vm/precompiled/precompiled.hpp endif -ifneq ($(filter $(OPENJDK_TARGET_OS), macosx aix solaris), ) - # On macosx, aix and solaris we have to link with the C++ compiler - JVM_TOOLCHAIN := TOOLCHAIN_LINK_CXX -else - JVM_TOOLCHAIN := TOOLCHAIN_DEFAULT -endif - ifeq ($(OPENJDK_TARGET_CPU), x86) JVM_EXCLUDE_PATTERNS += x86_64 else ifeq ($(OPENJDK_TARGET_CPU), x86_64) @@ -194,7 +187,7 @@ JVM_OPTIMIZATION ?= HIGHEST_JVM # Now set up the actual compilation of the main hotspot native library $(eval $(call SetupNativeCompilation, BUILD_LIBJVM, \ - TOOLCHAIN := $(JVM_TOOLCHAIN), \ + TOOLCHAIN := TOOLCHAIN_LINK_CXX, \ LIBRARY := jvm, \ OUTPUT_DIR := $(JVM_OUTPUTDIR), \ SRC := $(JVM_SRC_DIRS), \ From 6b29ad4ffc03b9163a894862f21ea95fe7636d03 Mon Sep 17 00:00:00 2001 From: Martin Buchholz Date: Fri, 30 Sep 2016 10:30:57 -0700 Subject: [PATCH 32/69] 8166976: TestCipherPBECons has wrong @run line Reviewed-by: snikandrova, wetmore, rasbold --- .../com/sun/crypto/provider/Cipher/PBE/TestCipherPBECons.java | 1 - 1 file changed, 1 deletion(-) diff --git a/jdk/test/com/sun/crypto/provider/Cipher/PBE/TestCipherPBECons.java b/jdk/test/com/sun/crypto/provider/Cipher/PBE/TestCipherPBECons.java index c42952342e0..e3167068029 100644 --- a/jdk/test/com/sun/crypto/provider/Cipher/PBE/TestCipherPBECons.java +++ b/jdk/test/com/sun/crypto/provider/Cipher/PBE/TestCipherPBECons.java @@ -36,7 +36,6 @@ import javax.crypto.NoSuchPaddingException; * @author Yun Ke * @author Bill Situ * @author Yu-Ching (Valerie) PENG - * @run main TestCipherKeyWrapperPBEKey */ public class TestCipherPBECons { From 70e402c190203e0f875117b62817ce40b9e709f1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hannes=20Walln=C3=B6fer?= Date: Fri, 30 Sep 2016 19:40:31 +0200 Subject: [PATCH 33/69] 8166902: Nested object literal property maps not reset in optimistic recompilation Reviewed-by: lagergren, attila --- .../internal/codegen/CodeGenerator.java | 53 +++++++------------ .../internal/codegen/SpillObjectCreator.java | 3 +- nashorn/test/script/basic/JDK-8166902.js | 43 +++++++++++++++ 3 files changed, 64 insertions(+), 35 deletions(-) create mode 100644 nashorn/test/script/basic/JDK-8166902.js diff --git a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/CodeGenerator.java b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/CodeGenerator.java index c9fa06880f9..fce1195c44a 100644 --- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/CodeGenerator.java +++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/CodeGenerator.java @@ -2485,11 +2485,6 @@ final class CodeGenerator extends NodeOperatorVisitor(this, tuples) { @Override protected void loadValue(final Expression node, final Type type) { - loadExpressionAsType(node, type); + // Use generic type in order to avoid conversion between object types + loadExpressionAsType(node, Type.generic(type)); }}; } @@ -2578,10 +2574,7 @@ final class CodeGenerator extends NodeOperatorVisitor objectLiteralMaps; // The line number at the continuation point private int lineNumber; // The active catch label, in case the continuation point is in a try/catch block @@ -5364,20 +5355,15 @@ final class CodeGenerator extends NodeOperatorVisitor(); + } + objectLiteralMaps.put(objectLiteralStackDepth, objectLiteralMap); } - void setObjectLiteralStackDepth(final int objectLiteralStackDepth) { - this.objectLiteralStackDepth = objectLiteralStackDepth; - } - - PropertyMap getObjectLiteralMap() { - return objectLiteralMap; - } - - void setObjectLiteralMap(final PropertyMap objectLiteralMap) { - this.objectLiteralMap = objectLiteralMap; + PropertyMap getObjectLiteralMap(final int stackDepth) { + return objectLiteralMaps == null ? null : objectLiteralMaps.get(stackDepth); } @Override @@ -5467,10 +5453,9 @@ final class CodeGenerator extends NodeOperatorVisitor { @Override protected void loadValue(final Expression expr, final Type type) { - codegen.loadExpressionAsType(expr, type); + // Use generic type in order to avoid conversion between object types + codegen.loadExpressionAsType(expr, Type.generic(type)); } @Override diff --git a/nashorn/test/script/basic/JDK-8166902.js b/nashorn/test/script/basic/JDK-8166902.js new file mode 100644 index 00000000000..fb164501681 --- /dev/null +++ b/nashorn/test/script/basic/JDK-8166902.js @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2016, 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. + */ + +/** + * JDK-8166902: Nested object literal property maps not reset in optimistic recompilation + * + * @test + * @run + */ + +var o = { + a: "A", + b: "B" +}; + +var m = { + x: { z: o.a }, + y: o.b +}; + +Assert.assertEquals(m.x.z, "A"); +Assert.assertEquals(m.y, "B"); + From e4d641863186b7d44579b991a0aae4e7371d8d56 Mon Sep 17 00:00:00 2001 From: Martin Buchholz Date: Fri, 30 Sep 2016 10:52:19 -0700 Subject: [PATCH 34/69] 8166981: RGBColorConvertTest has wrong @run line Reviewed-by: prr, rasbold, serb --- jdk/test/sun/java2d/cmm/ColorConvertOp/RGBColorConvertTest.java | 1 - 1 file changed, 1 deletion(-) diff --git a/jdk/test/sun/java2d/cmm/ColorConvertOp/RGBColorConvertTest.java b/jdk/test/sun/java2d/cmm/ColorConvertOp/RGBColorConvertTest.java index b537a5c667c..e8afd5a929e 100644 --- a/jdk/test/sun/java2d/cmm/ColorConvertOp/RGBColorConvertTest.java +++ b/jdk/test/sun/java2d/cmm/ColorConvertOp/RGBColorConvertTest.java @@ -26,7 +26,6 @@ * @bug 6279846 * @summary Verifies that transform between the same ICC color spaces does not * change pixels - * @run main ColorConvertTest */ import java.awt.image.*; From 799f344fccd19fa88b52dfb0a591b7eabbe2a1c8 Mon Sep 17 00:00:00 2001 From: Jonathan Gibbons Date: Fri, 30 Sep 2016 13:15:22 -0700 Subject: [PATCH 35/69] 8166144: New javadoc options don't conform to JEP 293 (GNU style options) Reviewed-by: ksrini, bpatel --- .../com/sun/tools/javac/main/Option.java | 5 +- .../jdk/javadoc/internal/api/JavadocTool.java | 8 +- .../formats/html/ConfigurationImpl.java | 55 +-- .../html/resources/standard.properties | 240 +++++++------ .../doclets/toolkit/Configuration.java | 117 +++---- .../jdk/javadoc/internal/tool/Messager.java | 12 +- .../jdk/javadoc/internal/tool/Start.java | 193 +++++++++-- .../jdk/javadoc/internal/tool/ToolOption.java | 212 ++++++------ .../tool/resources/javadoc.properties | 314 ++++++++++++------ .../jdk/javadoc/doclet/lib/JavadocTester.java | 18 + .../doclet/testHelpOption/TestHelpOption.java | 29 +- .../doclet/testXOption/TestXOption.java | 30 +- .../jdk/javadoc/tool/CheckResourceKeys.java | 6 + .../jdk/javadoc/tool/OptionSyntaxTest.java | 293 ++++++++++++++++ .../tool/api/basic/IsSupportedOptionTest.java | 4 +- .../javadoc/tool/modules/FilterOptions.java | 24 +- .../jdk/javadoc/tool/modules/Modules.java | 8 +- 17 files changed, 1122 insertions(+), 446 deletions(-) create mode 100644 langtools/test/jdk/javadoc/tool/OptionSyntaxTest.java diff --git a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/main/Option.java b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/main/Option.java index 03327387b47..a869718d6b3 100644 --- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/main/Option.java +++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/main/Option.java @@ -425,8 +425,7 @@ public enum Option { J("-J", "opt.arg.flag", "opt.J", STANDARD, INFO, ArgKind.ADJACENT) { @Override public boolean process(OptionHelper helper, String option) { - throw new AssertionError - ("the -J flag should be caught by the launcher."); + throw new AssertionError("the -J flag should be caught by the launcher."); } }, @@ -691,7 +690,7 @@ public enum Option { * This option takes an argument. * If the name of option ends with ':' or '=', the argument must be provided directly * after that separator. - * Otherwise, if may appear after an '=' or in the following argument position. + * Otherwise, it may appear after an '=' or in the following argument position. */ REQUIRED, diff --git a/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/api/JavadocTool.java b/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/api/JavadocTool.java index f9a5d52e454..8c9fe181321 100644 --- a/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/api/JavadocTool.java +++ b/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/api/JavadocTool.java @@ -165,9 +165,11 @@ public class JavadocTool implements DocumentationTool { public int isSupportedOption(String option) { if (option == null) throw new NullPointerException(); - for (ToolOption o: ToolOption.values()) { - if (o.opt.equals(option)) - return o.hasArg ? 1 : 0; + for (ToolOption o : ToolOption.values()) { + for (String name : o.names) { + if (name.equals(option)) + return o.hasArg ? 1 : 0; + } } return -1; } diff --git a/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/ConfigurationImpl.java b/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/ConfigurationImpl.java index c737469218e..d2607ba41b8 100644 --- a/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/ConfigurationImpl.java +++ b/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/ConfigurationImpl.java @@ -595,8 +595,9 @@ public class ConfigurationImpl extends Configuration { @Override public Set getSupportedOptions() { + Resources resources = getResources(); Doclet.Option[] options = { - new Option(this, "-bottom", 1) { + new Option(resources, "-bottom", 1) { @Override public boolean process(String opt, ListIterator args) { optionsProcessed.add(this); @@ -604,7 +605,7 @@ public class ConfigurationImpl extends Configuration { return true; } }, - new Option(this, "-charset", 1) { + new Option(resources, "-charset", 1) { @Override public boolean process(String opt, ListIterator args) { optionsProcessed.add(this); @@ -612,7 +613,7 @@ public class ConfigurationImpl extends Configuration { return true; } }, - new Option(this, "-doctitle", 1) { + new Option(resources, "-doctitle", 1) { @Override public boolean process(String opt, ListIterator args) { optionsProcessed.add(this); @@ -620,7 +621,7 @@ public class ConfigurationImpl extends Configuration { return true; } }, - new Option(this, "-footer", 1) { + new Option(resources, "-footer", 1) { @Override public boolean process(String opt, ListIterator args) { optionsProcessed.add(this); @@ -628,7 +629,7 @@ public class ConfigurationImpl extends Configuration { return true; } }, - new Option(this, "-header", 1) { + new Option(resources, "-header", 1) { @Override public boolean process(String opt, ListIterator args) { optionsProcessed.add(this); @@ -636,7 +637,7 @@ public class ConfigurationImpl extends Configuration { return true; } }, - new Option(this, "-helpfile", 1) { + new Option(resources, "-helpfile", 1) { @Override public boolean process(String opt, ListIterator args) { optionsProcessed.add(this); @@ -644,7 +645,7 @@ public class ConfigurationImpl extends Configuration { return true; } }, - new Option(this, "-html4") { + new Option(resources, "-html4") { @Override public boolean process(String opt, ListIterator args) { optionsProcessed.add(this); @@ -652,7 +653,7 @@ public class ConfigurationImpl extends Configuration { return true; } }, - new Option(this, "-html5") { + new Option(resources, "-html5") { @Override public boolean process(String opt, ListIterator args) { optionsProcessed.add(this); @@ -660,7 +661,7 @@ public class ConfigurationImpl extends Configuration { return true; } }, - new Option(this, "-nohelp") { + new Option(resources, "-nohelp") { @Override public boolean process(String opt, ListIterator args) { optionsProcessed.add(this); @@ -668,7 +669,7 @@ public class ConfigurationImpl extends Configuration { return true; } }, - new Option(this, "-nodeprecatedlist") { + new Option(resources, "-nodeprecatedlist") { @Override public boolean process(String opt, ListIterator args) { optionsProcessed.add(this); @@ -676,7 +677,7 @@ public class ConfigurationImpl extends Configuration { return true; } }, - new Option(this, "-noindex") { + new Option(resources, "-noindex") { @Override public boolean process(String opt, ListIterator args) { optionsProcessed.add(this); @@ -684,7 +685,7 @@ public class ConfigurationImpl extends Configuration { return true; } }, - new Option(this, "-nonavbar") { + new Option(resources, "-nonavbar") { @Override public boolean process(String opt, ListIterator args) { optionsProcessed.add(this); @@ -692,7 +693,7 @@ public class ConfigurationImpl extends Configuration { return true; } }, - new Hidden(this, "-nooverview") { + new Hidden(resources, "-nooverview") { @Override public boolean process(String opt, ListIterator args) { optionsProcessed.add(this); @@ -700,7 +701,7 @@ public class ConfigurationImpl extends Configuration { return true; } }, - new Option(this, "-notree") { + new Option(resources, "-notree") { @Override public boolean process(String opt, ListIterator args) { optionsProcessed.add(this); @@ -708,7 +709,7 @@ public class ConfigurationImpl extends Configuration { return true; } }, - new Option(this, "-overview", 1) { + new Option(resources, "-overview", 1) { @Override public boolean process(String opt, ListIterator args) { optionsProcessed.add(this); @@ -716,7 +717,7 @@ public class ConfigurationImpl extends Configuration { return true; } }, - new Option(this, "--frames") { + new Option(resources, "--frames") { @Override public boolean process(String opt, ListIterator args) { optionsProcessed.add(this); @@ -724,7 +725,7 @@ public class ConfigurationImpl extends Configuration { return true; } }, - new Option(this, "--no-frames") { + new Option(resources, "--no-frames") { @Override public boolean process(String opt, ListIterator args) { optionsProcessed.add(this); @@ -732,7 +733,7 @@ public class ConfigurationImpl extends Configuration { return true; } }, - new Hidden(this, "-packagesheader", 1) { + new Hidden(resources, "-packagesheader", 1) { @Override public boolean process(String opt, ListIterator args) { optionsProcessed.add(this); @@ -740,7 +741,7 @@ public class ConfigurationImpl extends Configuration { return true; } }, - new Option(this, "-splitindex") { + new Option(resources, "-splitindex") { @Override public boolean process(String opt, ListIterator args) { optionsProcessed.add(this); @@ -748,7 +749,7 @@ public class ConfigurationImpl extends Configuration { return true; } }, - new Option(this, "-stylesheetfile", 1) { + new Option(resources, "-stylesheetfile", 1) { @Override public boolean process(String opt, ListIterator args) { optionsProcessed.add(this); @@ -756,7 +757,7 @@ public class ConfigurationImpl extends Configuration { return true; } }, - new Option(this, "-top", 1) { + new Option(resources, "-top", 1) { @Override public boolean process(String opt, ListIterator args) { optionsProcessed.add(this); @@ -764,7 +765,7 @@ public class ConfigurationImpl extends Configuration { return true; } }, - new Option(this, "-use") { + new Option(resources, "-use") { @Override public boolean process(String opt, ListIterator args) { optionsProcessed.add(this); @@ -772,7 +773,7 @@ public class ConfigurationImpl extends Configuration { return true; } }, - new Option(this, "-windowtitle", 1) { + new Option(resources, "-windowtitle", 1) { @Override public boolean process(String opt, ListIterator args) { optionsProcessed.add(this); @@ -780,7 +781,7 @@ public class ConfigurationImpl extends Configuration { return true; } }, - new XOption(this, "-Xdoclint") { + new XOption(resources, "-Xdoclint") { @Override public boolean process(String opt, ListIterator args) { optionsProcessed.add(this); @@ -788,7 +789,7 @@ public class ConfigurationImpl extends Configuration { return true; } }, - new XOption(this, "-Xdocrootparent", 1) { + new XOption(resources, "-Xdocrootparent", 1) { @Override public boolean process(String opt, ListIterator args) { optionsProcessed.add(this); @@ -796,7 +797,7 @@ public class ConfigurationImpl extends Configuration { return true; } }, - new XOption(this, "doclet.xusage.xdoclint-extended.", "-Xdoclint:", 0) { + new XOption(resources, "doclet.usage.xdoclint-extended", "-Xdoclint:", 0) { @Override public boolean matches(String option) { return option.toLowerCase().startsWith(getName().toLowerCase()); @@ -809,7 +810,7 @@ public class ConfigurationImpl extends Configuration { return true; } }, - new XOption(this, "doclet.xusage.xdoclint-package.", "-Xdoclint/package:", 0) { + new XOption(resources, "doclet.usage.xdoclint-package", "-Xdoclint/package:", 0) { @Override public boolean matches(String option) { return option.toLowerCase().startsWith(getName().toLowerCase()); diff --git a/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/resources/standard.properties b/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/resources/standard.properties index 4f7018178f7..a56d6c006d1 100644 --- a/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/resources/standard.properties +++ b/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/resources/standard.properties @@ -191,144 +191,196 @@ doclet.Groupname_already_used=In -group option, groupname already used: {0} doclet.Same_package_name_used=Package name format used twice: {0} # option specifiers -doclet.usage.d.parameters= -doclet.usage.d.description=Destination directory for output files +doclet.usage.d.parameters=\ + +doclet.usage.d.description=\ + Destination directory for output files -doclet.usage.use.description=Create class and package usage pages +doclet.usage.use.description=\ + Create class and package usage pages -doclet.usage.version.description=Include @version paragraphs +doclet.usage.version.description=\ + Include @version paragraphs -doclet.usage.author.description=Include @author paragraphs +doclet.usage.author.description=\ + Include @author paragraphs -doclet.usage.docfilessubdirs.description=Recursively copy doc-file subdirectories +doclet.usage.docfilessubdirs.description=\ + Recursively copy doc-file subdirectories -doclet.usage.splitindex.description=Split index into one file per letter +doclet.usage.splitindex.description=\ + Split index into one file per letter -doclet.usage.overview.parameters= -doclet.usage.overview.description=Read overview documentation from HTML file +doclet.usage.overview.parameters=\ + +doclet.usage.overview.description=\ + Read overview documentation from HTML file +doclet.usage.windowtitle.parameters=\ + +doclet.usage.windowtitle.description=\ + Browser window title for the documentation -doclet.usage.windowtitle.parameters= -doclet.usage.windowtitle.description=Browser window title for the documentation +doclet.usage.doctitle.parameters=\ + +doclet.usage.doctitle.description=\ + Include title for the overview page -doclet.usage.doctitle.parameters= -doclet.usage.doctitle.description=Include title for the overview page +doclet.usage.header.parameters=\ + +doclet.usage.header.description=\ + Include header text for each page -doclet.usage.header.parameters= -doclet.usage.header.description=Include header text for each page +doclet.usage.html4.description=\ + Generate HTML 4.01 output -doclet.usage.html4.description=Generate HTML 4.01 output +doclet.usage.html5.description=\ + Generate HTML 5 output -doclet.usage.html5.description=Generate HTML 5 output +doclet.usage.footer.parameters=\ + +doclet.usage.footer.description=\ + Include footer text for each page -doclet.usage.footer.parameters= -doclet.usage.footer.description=Include footer text for each page +doclet.usage.top.parameters=\ + +doclet.usage.top.description=\ + Include top text for each page -doclet.usage.top.parameters= -doclet.usage.top.description=Include top text for each page +doclet.usage.bottom.parameters=\ + +doclet.usage.bottom.description=\ + Include bottom text for each page -doclet.usage.bottom.parameters= -doclet.usage.bottom.description=Include bottom text for each page +doclet.usage.link.parameters=\ + +doclet.usage.link.description=\ + Create links to javadoc output at -doclet.usage.link.parameters= -doclet.usage.link.description=Create links to javadoc output at +doclet.usage.linkoffline.parameters=\ + +doclet.usage.linkoffline.description=\ + Link to docs at using package list at -doclet.usage.linkoffline.parameters= -doclet.usage.linkoffline.description=Link to docs at using package list\n\ -\ at +doclet.usage.excludedocfilessubdir.parameters=\ + :.. +doclet.usage.excludedocfilessubdir.description=\ + Exclude any doc-files subdirectories with given name -doclet.usage.excludedocfilessubdir.parameters=:.. -doclet.usage.excludedocfilessubdir.description=\n\ -\ Exclude any doc-files subdirectories with\n\ -\ given name +doclet.usage.group.parameters=\ + :.. +doclet.usage.group.description=\ + Group specified packages together in overview page -doclet.usage.group.parameters= :.. -doclet.usage.group.description=Group specified packages together\n\ -\ in overview page +doclet.usage.nocomment.description=\ + Suppress description and tags, generate only declarations -doclet.usage.nocomment.description=Suppress description and tags, generate\n\ -\ only declarations +doclet.usage.nodeprecated.description=\ + Do not include @deprecated information -doclet.usage.nodeprecated.description=Do not include @deprecated information +doclet.usage.noqualifier.parameters=\ + ::.. +doclet.usage.noqualifier.description=\ + Exclude the list of qualifiers from the output -doclet.usage.noqualifier.parameters=::.. -doclet.usage.noqualifier.description=Exclude the list of qualifiers from the output +doclet.usage.nosince.description=\ + Do not include @since information -doclet.usage.nosince.description=Do not include @since information +doclet.usage.notimestamp.description=\ + Do not include hidden time stamp -doclet.usage.notimestamp.description=Do not include hidden time stamp +doclet.usage.nodeprecatedlist.description=\ + Do not generate deprecated list -doclet.usage.nodeprecatedlist.description=Do not generate deprecated list +doclet.usage.notree.description=\ + Do not generate class hierarchy -doclet.usage.notree.description=Do not generate class hierarchy +doclet.usage.noindex.description=\ + Do not generate index -doclet.usage.noindex.description=Do not generate index +doclet.usage.nohelp.description=\ + Do not generate help link -doclet.usage.nohelp.description=Do not generate help link +doclet.usage.nonavbar.description=\ + Do not generate navigation bar -doclet.usage.nonavbar.description=Do not generate navigation bar +doclet.usage.nooverview.description=\ + Do not generate overview pages -doclet.usage.nooverview.description=Do not generate overview pages +doclet.usage.serialwarn.description=\ + Generate warning about @serial tag -doclet.usage.serialwarn.description=Generate warning about @serial tag +doclet.usage.tag.parameters=\ + ::
+doclet.usage.tag.description=\ + Specify single argument custom tags -doclet.usage.tag.parameters=::
-doclet.usage.tag.description=\n\ -\ Specify single argument custom tags +doclet.usage.taglet.description=\ + The fully qualified name of Taglet to register -doclet.usage.taglet.description=The fully qualified name of Taglet to register +doclet.usage.tagletpath.description=\ + The path to Taglets -doclet.usage.tagletpath.description=The path to Taglets +doclet.usage.charset.parameters=\ + +doclet.usage.charset.description=\ + Charset for cross-platform viewing of generated documentation -doclet.usage.charset.parameters= -doclet.usage.charset.description=Charset for cross-platform viewing of\n\ -\ generated documentation +doclet.usage.helpfile.parameters=\ + +doclet.usage.helpfile.description=\ + Include file that help link links to -doclet.usage.helpfile.parameters= -doclet.usage.helpfile.description=Include file that help link links to +doclet.usage.linksource.description=\ + Generate source in HTML -doclet.usage.linksource.description=Generate source in HTML +doclet.usage.sourcetab.parameters=\ + +doclet.usage.sourcetab.description=\ + Specify the number of spaces each tab takes up in the source -doclet.usage.sourcetab.parameters= -doclet.usage.sourcetab.description=Specify the number of spaces each tab\n\ -\ takes up in the source +doclet.usage.keywords.description=\ + Include HTML meta tags with package, class and member info -doclet.usage.keywords.description=Include HTML meta tags with package,\n\ -\ class and member info +doclet.usage.stylesheetfile.parameters=\ + +doclet.usage.stylesheetfile.description=\ + File to change style of the generated documentation -doclet.usage.stylesheetfile.parameters= -doclet.usage.stylesheetfile.description=File to change style of the generated\n\ -\ documentation +doclet.usage.docencoding.parameters=\ + +doclet.usage.docencoding.description=\ + Specify the character encoding for the output -doclet.usage.docencoding.parameters= -doclet.usage.docencoding.description=Specify the character encoding for the output +doclet.usage.frames.description=\ + Enable the use of frames in the generated output (default) -doclet.usage.frames.description=Enable the use of frames in the generated output (default) +doclet.usage.no-frames.description=\ + Disable the use of frames in the generated output -doclet.usage.no-frames.description=Disable the use of frames in the generated output +doclet.usage.xdocrootparent.parameters=\ + +doclet.usage.xdocrootparent.description=\ + Replaces all @docRoot followed by /.. in doc comments with\n\ + -doclet.xusage.xdocrootparent.parameters= -doclet.xusage.xdocrootparent.description=Replaces all @docRoot followed by /..\n\ -\ in doc comments with +doclet.usage.xdoclint.description=\ + Enable recommended checks for problems in javadoc comments -doclet.xusage.xdoclint.description=Enable recommended checks for problems in\n\ -\ javadoc comments - -doclet.xusage.xdoclint-extended.parameters=(all|none|[-]) +doclet.usage.xdoclint-extended.parameters=\ + (all|none|[-]) # L10N: do not localize these words: all none accessibility html missing reference syntax -doclet.xusage.xdoclint-extended.description=Enable or disable specific checks\n\ -\ for problems in javadoc comments, where \n\ -\ is one of accessibility, html,\n\ -\ missing, reference, or syntax.\n +doclet.usage.xdoclint-extended.description=\ + Enable or disable specific checks for problems in javadoc\n\ + comments, where is one of accessibility, html,\n\ + missing, reference, or syntax. -doclet.xusage.xdoclint-package.parameters=([-]) -doclet.xusage.xdoclint-package.description=\n\ -\ Enable or disable checks in specific\n\ -\ packages. is a comma separated\n\ -\ list of package specifiers. Package\n\ -\ specifier is either a qualified name of a\n\ -\ package or a package name prefix followed\n\ -\ by .*, which expands to all sub-packages\n\ -\ of the given package. Prefix the package\n\ -\ specifier with - to disable checks for\n\ -\ the specified packages.\n +doclet.usage.xdoclint-package.parameters=\ + ([-]) +doclet.usage.xdoclint-package.description=\ + Enable or disable checks in specific packages. is a\n\ + comma separated list of package specifiers. A package\n\ + specifier is either a qualified name of a package or a package\n\ + name prefix followed by .*, which expands to all sub-packages\n\ + of the given package. Prefix the package specifier with - to\n\ + disable checks for the specified packages. diff --git a/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/Configuration.java b/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/Configuration.java index 393f261c607..5fbf6d9d34d 100644 --- a/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/Configuration.java +++ b/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/Configuration.java @@ -404,8 +404,9 @@ public abstract class Configuration { } public Set getSupportedOptions() { + Resources resources = getResources(); Doclet.Option[] options = { - new Option(this, "-author") { + new Option(resources, "-author") { @Override public boolean process(String opt, ListIterator args) { optionsProcessed.add(this); @@ -413,7 +414,7 @@ public abstract class Configuration { return true; } }, - new Option(this, "-d", 1) { + new Option(resources, "-d", 1) { @Override public boolean process(String opt, ListIterator args) { optionsProcessed.add(this); @@ -421,7 +422,7 @@ public abstract class Configuration { return true; } }, - new Option(this, "-docencoding", 1) { + new Option(resources, "-docencoding", 1) { @Override public boolean process(String opt, ListIterator args) { optionsProcessed.add(this); @@ -429,7 +430,7 @@ public abstract class Configuration { return true; } }, - new Option(this, "-docfilessubdirs") { + new Option(resources, "-docfilessubdirs") { @Override public boolean process(String opt, ListIterator args) { optionsProcessed.add(this); @@ -437,7 +438,7 @@ public abstract class Configuration { return true; } }, - new Hidden(this, "-encoding", 1) { + new Hidden(resources, "-encoding", 1) { @Override public boolean process(String opt, ListIterator args) { optionsProcessed.add(this); @@ -445,7 +446,7 @@ public abstract class Configuration { return true; } }, - new Option(this, "-excludedocfilessubdir", 1) { + new Option(resources, "-excludedocfilessubdir", 1) { @Override public boolean process(String opt, ListIterator args) { optionsProcessed.add(this); @@ -453,7 +454,7 @@ public abstract class Configuration { return true; } }, - new Option(this, "-group", 2) { + new Option(resources, "-group", 2) { @Override public boolean process(String opt, ListIterator args) { optionsProcessed.add(this); @@ -461,7 +462,7 @@ public abstract class Configuration { return true; } }, - new Hidden(this, "-javafx") { + new Hidden(resources, "-javafx") { @Override public boolean process(String opt, ListIterator args) { optionsProcessed.add(this); @@ -469,7 +470,7 @@ public abstract class Configuration { return true; } }, - new Option(this, "-keywords") { + new Option(resources, "-keywords") { @Override public boolean process(String opt, ListIterator args) { optionsProcessed.add(this); @@ -477,7 +478,7 @@ public abstract class Configuration { return true; } }, - new Option(this, "-link", 1) { + new Option(resources, "-link", 1) { @Override public boolean process(String opt, ListIterator args) { optionsProcessed.add(this); @@ -486,7 +487,7 @@ public abstract class Configuration { return true; } }, - new Option(this, "-linksource") { + new Option(resources, "-linksource") { @Override public boolean process(String opt, ListIterator args) { optionsProcessed.add(this); @@ -494,7 +495,7 @@ public abstract class Configuration { return true; } }, - new Option(this, "-linkoffline", 2) { + new Option(resources, "-linkoffline", 2) { @Override public boolean process(String opt, ListIterator args) { optionsProcessed.add(this); @@ -503,7 +504,7 @@ public abstract class Configuration { return true; } }, - new Option(this, "-nocomment") { + new Option(resources, "-nocomment") { @Override public boolean process(String opt, ListIterator args) { optionsProcessed.add(this); @@ -511,7 +512,7 @@ public abstract class Configuration { return true; } }, - new Option(this, "-nodeprecated") { + new Option(resources, "-nodeprecated") { @Override public boolean process(String opt, ListIterator args) { optionsProcessed.add(this); @@ -519,7 +520,7 @@ public abstract class Configuration { return true; } }, - new Option(this, "-nosince") { + new Option(resources, "-nosince") { @Override public boolean process(String opt, ListIterator args) { optionsProcessed.add(this); @@ -527,7 +528,7 @@ public abstract class Configuration { return true; } }, - new Option(this, "-notimestamp") { + new Option(resources, "-notimestamp") { @Override public boolean process(String opt, ListIterator args) { optionsProcessed.add(this); @@ -535,7 +536,7 @@ public abstract class Configuration { return true; } }, - new Option(this, "-noqualifier", 1) { + new Option(resources, "-noqualifier", 1) { @Override public boolean process(String opt, ListIterator args) { optionsProcessed.add(this); @@ -543,7 +544,7 @@ public abstract class Configuration { return true; } }, - new Hidden(this, "-quiet") { + new Hidden(resources, "-quiet") { @Override public boolean process(String opt, ListIterator args) { optionsProcessed.add(this); @@ -551,7 +552,7 @@ public abstract class Configuration { return true; } }, - new Option(this, "-serialwarn") { + new Option(resources, "-serialwarn") { @Override public boolean process(String opt, ListIterator args) { optionsProcessed.add(this); @@ -559,7 +560,7 @@ public abstract class Configuration { return true; } }, - new Option(this, "-sourcetab", 1) { + new Option(resources, "-sourcetab", 1) { @Override public boolean process(String opt, ListIterator args) { optionsProcessed.add(this); @@ -578,7 +579,7 @@ public abstract class Configuration { return true; } }, - new Option(this, "-tag", 1) { + new Option(resources, "-tag", 1) { @Override public boolean process(String opt, ListIterator args) { optionsProcessed.add(this); @@ -589,7 +590,7 @@ public abstract class Configuration { return true; } }, - new Option(this, "-taglet", 1) { + new Option(resources, "-taglet", 1) { @Override public boolean process(String opt, ListIterator args) { optionsProcessed.add(this); @@ -600,7 +601,7 @@ public abstract class Configuration { return true; } }, - new Option(this, "-tagletpath", 1) { + new Option(resources, "-tagletpath", 1) { @Override public boolean process(String opt, ListIterator args) { optionsProcessed.add(this); @@ -608,7 +609,7 @@ public abstract class Configuration { return true; } }, - new Option(this, "-version") { + new Option(resources, "-version") { @Override public boolean process(String opt, ListIterator args) { optionsProcessed.add(this); @@ -1057,37 +1058,30 @@ public abstract class Configuration { private final String description; private final int argCount; - protected final Configuration c; + protected Option(Resources resources, String name, int argCount) { + this(resources, "doclet.usage." + name.toLowerCase().replaceAll("^-*", ""), name, argCount); + } - protected Option(Configuration config, String keyName, String name, int argCount) { - c = config; + protected Option(Resources resources, String keyBase, String name, int argCount) { this.name = name; - String desc = getOptionsMessage(keyName + "description"); + String desc = getOptionsMessage(resources, keyBase + ".description"); if (desc.isEmpty()) { this.description = ""; this.parameters = ""; } else { this.description = desc; - this.parameters = getOptionsMessage(keyName + "parameters"); + this.parameters = getOptionsMessage(resources, keyBase + ".parameters"); } this.argCount = argCount; } - protected Option(String prefix, Configuration config, String name, int argCount) { - this(config, prefix + name.toLowerCase().replaceAll("^-*", "") + ".", name, argCount); + protected Option(Resources resources, String name) { + this(resources, name, 0); } - protected Option(Configuration config, String name, int argCount) { - this("doclet.usage.", config, name, argCount); - } - - protected Option(Configuration config, String name) { - this(config, name, 0); - } - - private String getOptionsMessage(String key) { + private String getOptionsMessage(Resources resources, String key) { try { - return c.getResources().getText(key); + return resources.getText(key); } catch (MissingResourceException ignore) { return ""; } @@ -1113,19 +1107,9 @@ public abstract class Configuration { return parameters; } - /** - * Maintains the formatting for javadoc -help. Note the space - * alignment. - */ @Override public String toString() { - String opt = name + (name.endsWith(":") ? "" : " ") + parameters; - StringBuffer sb = new StringBuffer(" ").append(opt).append(" "); - for (int i = opt.length(); i < 32; i++) { - sb.append(" "); - } - sb.append(description); - return sb.toString(); + return name; } @Override @@ -1135,7 +1119,14 @@ public abstract class Configuration { @Override public boolean matches(String option) { - return name.toLowerCase().equals(option.toLowerCase()); + boolean matchCase = name.startsWith("--"); + if (option.startsWith("--") && option.contains("=")) { + return name.equals(option.substring(option.indexOf("=") + 1)); + } else if (matchCase) { + return name.equals(option); + } else { + return name.toLowerCase().equals(option.toLowerCase()); + } } @Override @@ -1146,16 +1137,16 @@ public abstract class Configuration { public abstract class XOption extends Option { - public XOption(Configuration config, String keyname, String name, int argCount) { - super(config, keyname, name, argCount); + public XOption(Resources resources, String prefix, String name, int argCount) { + super(resources, prefix, name, argCount); } - public XOption(Configuration config, String name, int argCount) { - super("doclet.xusage.", config, name, argCount); + public XOption(Resources resources, String name, int argCount) { + super(resources, name, argCount); } - public XOption(Configuration config, String name) { - this(config, name, 0); + public XOption(Resources resources, String name) { + this(resources, name, 0); } @Override @@ -1166,12 +1157,12 @@ public abstract class Configuration { public abstract class Hidden extends Option { - public Hidden(Configuration config, String name, int argCount) { - super("doclet.xusage.", config, name, argCount); + public Hidden(Resources resources, String name, int argCount) { + super(resources, name, argCount); } - public Hidden(Configuration config, String name) { - this(config, name, 0); + public Hidden(Resources resources, String name) { + this(resources, name, 0); } @Override diff --git a/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/tool/Messager.java b/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/tool/Messager.java index 0da657f3d1c..37829952b91 100644 --- a/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/tool/Messager.java +++ b/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/tool/Messager.java @@ -255,7 +255,7 @@ public class Messager extends Log implements Reporter { private void incrementErrorCount(String prefix, String msg) { if (nerrors < MaxErrors) { PrintWriter errWriter = getWriter(WriterKind.ERROR); - errWriter.println(prefix + ": " + getText("javadoc.error") + " - " + msg); + printRawLines(errWriter, prefix + ": " + getText("javadoc.error") + " - " + msg); errWriter.flush(); prompt(); nerrors++; @@ -293,7 +293,7 @@ public class Messager extends Log implements Reporter { private void incrementWarningCount(String prefix, String msg) { if (nwarnings < MaxWarnings) { PrintWriter warnWriter = getWriter(WriterKind.WARNING); - warnWriter.println(prefix + ": " + getText("javadoc.warning") + " - " + msg); + printRawLines(warnWriter, prefix + ": " + getText("javadoc.warning") + " - " + msg); warnWriter.flush(); nwarnings++; } @@ -318,9 +318,9 @@ public class Messager extends Log implements Reporter { PrintWriter noticeWriter = getWriter(WriterKind.NOTICE); if (path == null) { - noticeWriter.println(msg); + printRawLines(noticeWriter, msg); } else { - noticeWriter.println(prefix + ": " + msg); + printRawLines(noticeWriter, prefix + ": " + msg); } noticeWriter.flush(); } @@ -334,9 +334,9 @@ public class Messager extends Log implements Reporter { PrintWriter noticeWriter = getWriter(WriterKind.NOTICE); if (e == null) { - noticeWriter.println(msg); + printRawLines(noticeWriter, msg); } else { - noticeWriter.println(pos + ": " + msg); + printRawLines(noticeWriter, pos + ": " + msg); } noticeWriter.flush(); } diff --git a/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/tool/Start.java b/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/tool/Start.java index 956c9cbc353..431826c5e94 100644 --- a/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/tool/Start.java +++ b/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/tool/Start.java @@ -31,14 +31,18 @@ import java.io.IOException; import java.io.PrintWriter; import java.nio.file.Path; import java.text.BreakIterator; +import java.text.Collator; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.Collections; +import java.util.Comparator; import java.util.List; import java.util.Locale; import java.util.Objects; import java.util.Set; +import java.util.stream.Collectors; +import java.util.stream.Stream; import javax.tools.JavaFileManager; import javax.tools.JavaFileObject; @@ -61,6 +65,7 @@ import com.sun.tools.javac.util.Options; import jdk.javadoc.doclet.Doclet; import jdk.javadoc.doclet.Doclet.Option; import jdk.javadoc.doclet.DocletEnvironment; +import jdk.javadoc.internal.doclets.toolkit.Resources; import static javax.tools.DocumentationTool.Location.*; @@ -168,7 +173,10 @@ public class Start extends ToolOption.Helper { } void usage(boolean exit) { - usage("main.usage", "-help", "main.usage.foot", exit); + usage("main.usage", "-help", "main.usage.foot"); + + if (exit) + throw new Messager.ExitJavadoc(); } @Override @@ -177,30 +185,128 @@ public class Start extends ToolOption.Helper { } void Xusage(boolean exit) { - usage("main.Xusage", "-X", "main.Xusage.foot", exit); - } - - private void usage(String main, String option, String foot, boolean exit) { - messager.notice(main); - // let doclet print usage information (does nothing on error) - if (docletClass != null) { - String name = doclet.getName(); - Set