From 8e29aab602560986277d72023443aa733b32799e Mon Sep 17 00:00:00 2001 From: Michail Chernov Date: Fri, 23 Dec 2016 20:44:48 +0300 Subject: [PATCH 001/157] 8171045: gc/stress/TestStressG1Humongous.java fails to allocate the heap Reviewed-by: tschatzl, kzhaldyb --- hotspot/test/ProblemList.txt | 1 - .../test/gc/stress/TestStressG1Humongous.java | 54 +++++++++++++++---- 2 files changed, 43 insertions(+), 12 deletions(-) diff --git a/hotspot/test/ProblemList.txt b/hotspot/test/ProblemList.txt index 907597bd228..7a7f6a64e29 100644 --- a/hotspot/test/ProblemList.txt +++ b/hotspot/test/ProblemList.txt @@ -55,7 +55,6 @@ compiler/types/correctness/OffTest.java 8066173 generic-all gc/g1/humongousObjects/objectGraphTest/TestObjectGraphAfterGC.java 8156755 generic-all gc/survivorAlignment/TestPromotionToSurvivor.java 8129886 generic-all -gc/stress/TestStressG1Humongous.java 8171045 generic-all ############################################################################# diff --git a/hotspot/test/gc/stress/TestStressG1Humongous.java b/hotspot/test/gc/stress/TestStressG1Humongous.java index cd951ea31c6..37014295f99 100644 --- a/hotspot/test/gc/stress/TestStressG1Humongous.java +++ b/hotspot/test/gc/stress/TestStressG1Humongous.java @@ -28,14 +28,9 @@ * @summary Stress G1 by humongous allocations in situation near OOM * @requires vm.gc.G1 * @requires !vm.flightRecorder - * @run main/othervm/timeout=200 -Xlog:gc=debug -Xmx1g -XX:+UseG1GC -XX:G1HeapRegionSize=4m - * -Dtimeout=120 -Dthreads=3 -Dhumongoussize=1.1 -Dregionsize=4 TestStressG1Humongous - * @run main/othervm/timeout=200 -Xlog:gc=debug -Xmx1g -XX:+UseG1GC -XX:G1HeapRegionSize=16m - * -Dtimeout=120 -Dthreads=5 -Dhumongoussize=2.1 -Dregionsize=16 TestStressG1Humongous - * @run main/othervm/timeout=200 -Xlog:gc=debug -Xmx1g -XX:+UseG1GC -XX:G1HeapRegionSize=32m - * -Dtimeout=120 -Dthreads=4 -Dhumongoussize=0.6 -Dregionsize=32 TestStressG1Humongous - * @run main/othervm/timeout=700 -Xlog:gc=debug -Xmx1g -XX:+UseG1GC -XX:G1HeapRegionSize=1m - * -Dtimeout=600 -Dthreads=7 -Dhumongoussize=0.6 -Dregionsize=1 TestStressG1Humongous + * @library /test/lib + * @modules java.base/jdk.internal.misc + * @run driver/timeout=1300 TestStressG1Humongous */ import java.util.ArrayList; @@ -44,8 +39,45 @@ import java.util.Collections; import java.util.concurrent.CountDownLatch; import java.util.concurrent.atomic.AtomicInteger; -public class TestStressG1Humongous { +import jdk.test.lib.Platform; +import jdk.test.lib.Utils; +import jdk.test.lib.process.ProcessTools; +import jdk.test.lib.process.OutputAnalyzer; +public class TestStressG1Humongous{ + + public static void main(String[] args) throws Exception { + // Limit heap size on 32-bit platforms + int heapSize = Platform.is32bit() ? 512 : 1024; + // Heap size, region size, threads, humongous size, timeout + run(heapSize, 4, 3, 1.1, 120); + run(heapSize, 16, 5, 2.1, 120); + run(heapSize, 32, 4, 0.6, 120); + run(heapSize, 1, 7, 0.6, 600); + } + + private static void run(int heapSize, int regionSize, int threads, double humongousSize, int timeout) + throws Exception { + ArrayList options = new ArrayList<>(); + Collections.addAll(options, Utils.getTestJavaOpts()); + Collections.addAll(options, + "-Xlog:gc=debug", + "-Xmx" + heapSize + "m", + "-XX:+UseG1GC", + "-XX:G1HeapRegionSize=" + regionSize + "m", + "-Dtimeout=" + timeout, + "-Dthreads=" + threads, + "-Dhumongoussize=" + humongousSize, + "-Dregionsize=" + regionSize, + TestStressG1HumongousImpl.class.getName() + ); + ProcessBuilder pb = ProcessTools.createJavaProcessBuilder(options.toArray(new String[options.size()])); + OutputAnalyzer output = new OutputAnalyzer(pb.start()); + output.shouldHaveExitValue(0); + } +} + +class TestStressG1HumongousImpl { // Timeout in seconds private static final int TIMEOUT = Integer.getInteger("timeout", 60); private static final int THREAD_COUNT = Integer.getInteger("threads", 2); @@ -60,10 +92,10 @@ public class TestStressG1Humongous { public static final List GARBAGE = Collections.synchronizedList(new ArrayList<>()); public static void main(String[] args) throws InterruptedException { - new TestStressG1Humongous().run(); + new TestStressG1HumongousImpl().run(); } - public TestStressG1Humongous() { + public TestStressG1HumongousImpl() { isRunning = true; threads = new Thread[THREAD_COUNT]; alocatedObjectsCount = new AtomicInteger(0); From 37f332b8eeb1d3b1d7ac886ef17835e7faa39ace Mon Sep 17 00:00:00 2001 From: Ioi Lam Date: Thu, 15 Dec 2016 19:26:41 -0800 Subject: [PATCH 002/157] 8171809: Remove unused CDS code from JDK 9 Reviewed-by: jiangli, ccheung, mseledtsov --- hotspot/src/share/vm/classfile/classLoaderData.cpp | 2 +- hotspot/src/share/vm/classfile/classLoaderData.hpp | 12 ------------ .../share/vm/classfile/systemDictionaryShared.hpp | 3 --- hotspot/src/share/vm/memory/metaspaceShared.cpp | 4 ---- 4 files changed, 1 insertion(+), 20 deletions(-) diff --git a/hotspot/src/share/vm/classfile/classLoaderData.cpp b/hotspot/src/share/vm/classfile/classLoaderData.cpp index fbafa936950..d1e37d82761 100644 --- a/hotspot/src/share/vm/classfile/classLoaderData.cpp +++ b/hotspot/src/share/vm/classfile/classLoaderData.cpp @@ -94,7 +94,7 @@ ClassLoaderData::ClassLoaderData(Handle h_class_loader, bool is_anonymous, Depen _metaspace(NULL), _unloading(false), _klasses(NULL), _modules(NULL), _packages(NULL), _claimed(0), _jmethod_ids(NULL), _handles(NULL), _deallocate_list(NULL), - _next(NULL), _dependencies(dependencies), _shared_class_loader_id(-1), + _next(NULL), _dependencies(dependencies), _metaspace_lock(new Mutex(Monitor::leaf+1, "Metaspace allocation lock", true, Monitor::_safepoint_check_never)) { TRACE_INIT_ID(this); diff --git a/hotspot/src/share/vm/classfile/classLoaderData.hpp b/hotspot/src/share/vm/classfile/classLoaderData.hpp index b69c4e681d4..8c8df5187a7 100644 --- a/hotspot/src/share/vm/classfile/classLoaderData.hpp +++ b/hotspot/src/share/vm/classfile/classLoaderData.hpp @@ -204,9 +204,6 @@ class ClassLoaderData : public CHeapObj { // Support for walking class loader data objects ClassLoaderData* _next; /// Next loader_datas created - // CDS - int _shared_class_loader_id; - // ReadOnly and ReadWrite metaspaces (static because only on the null // class loader for now). static Metaspace* _ro_metaspace; @@ -338,15 +335,6 @@ class ClassLoaderData : public CHeapObj { Metaspace* rw_metaspace(); void initialize_shared_metaspaces(); - int shared_class_loader_id() const { - return _shared_class_loader_id; - } - void set_shared_class_loader_id(int id) { - assert(id >= 0, "sanity"); - assert(_shared_class_loader_id <0, "cannot be assigned more than once"); - _shared_class_loader_id = id; - } - TRACE_DEFINE_TRACE_ID_METHODS; }; diff --git a/hotspot/src/share/vm/classfile/systemDictionaryShared.hpp b/hotspot/src/share/vm/classfile/systemDictionaryShared.hpp index 4da4869cef2..764e1eaa348 100644 --- a/hotspot/src/share/vm/classfile/systemDictionaryShared.hpp +++ b/hotspot/src/share/vm/classfile/systemDictionaryShared.hpp @@ -29,7 +29,6 @@ #include "classfile/dictionary.hpp" class ClassFileStream; -class SerializeClosure; class SystemDictionaryShared: public SystemDictionary { public: @@ -79,8 +78,6 @@ public: return NULL; } - static void serialize(SerializeClosure* soc) {} - // The (non-application) CDS implementation supports only classes in the boot // class loader, which ensures that the verification constraints are the same // during archive creation time and runtime. Thus we can do the constraint checks diff --git a/hotspot/src/share/vm/memory/metaspaceShared.cpp b/hotspot/src/share/vm/memory/metaspaceShared.cpp index 61d6fa37b41..446517fd426 100644 --- a/hotspot/src/share/vm/memory/metaspaceShared.cpp +++ b/hotspot/src/share/vm/memory/metaspaceShared.cpp @@ -145,10 +145,6 @@ void MetaspaceShared::serialize(SerializeClosure* soc, GrowableArray StringTable::serialize(soc, string_space, space_size); soc->do_tag(--tag); - // Dump/restore the misc information for system dictionary - SystemDictionaryShared::serialize(soc); - soc->do_tag(--tag); - soc->do_tag(666); } From f82263efb849653eb6234eca2d2f2fd37f8a57bb Mon Sep 17 00:00:00 2001 From: Dmitry Fazunenko Date: Thu, 22 Dec 2016 10:17:18 +0000 Subject: [PATCH 003/157] 8170860: Get rid of the humanReadableByteCount() method in openjdk/hotspot Reviewed-by: mgerdin, mchernov --- .../test/gc/g1/TestHumongousShrinkHeap.java | 26 +++++++------------ .../gc/g1/TestShrinkDefragmentedHeap.java | 24 +++++++---------- .../test/gc/parallel/TestDynShrinkHeap.java | 20 +++++--------- hotspot/test/gc/testlibrary/Helpers.java | 15 +++++++++++ 4 files changed, 41 insertions(+), 44 deletions(-) diff --git a/hotspot/test/gc/g1/TestHumongousShrinkHeap.java b/hotspot/test/gc/g1/TestHumongousShrinkHeap.java index 47ea9450988..b65079020f4 100644 --- a/hotspot/test/gc/g1/TestHumongousShrinkHeap.java +++ b/hotspot/test/gc/g1/TestHumongousShrinkHeap.java @@ -27,7 +27,7 @@ * @requires vm.gc.G1 * @summary Verify that heap shrinks after GC in the presence of fragmentation * due to humongous objects - * @library /test/lib + * @library /test/lib / * @modules java.base/jdk.internal.misc * @modules java.management/sun.management * @run main/othervm -XX:-ExplicitGCInvokesConcurrent -XX:MinHeapFreeRatio=10 @@ -40,6 +40,8 @@ import java.lang.management.ManagementFactory; import java.lang.management.MemoryUsage; import java.util.ArrayList; import java.util.List; +import java.text.NumberFormat; +import gc.testlibrary.Helpers; import static jdk.test.lib.Asserts.*; public class TestHumongousShrinkHeap { @@ -70,9 +72,9 @@ public class TestHumongousShrinkHeap { System.out.format("Running with %s initial heap size of %s maximum heap size. " + "Will allocate humongous object of %s size %d times.%n", - MemoryUsagePrinter.humanReadableByteCount(TOTAL_MEMORY, false), - MemoryUsagePrinter.humanReadableByteCount(MAX_MEMORY, false), - MemoryUsagePrinter.humanReadableByteCount(HUMON_SIZE, false), + MemoryUsagePrinter.NF.format(TOTAL_MEMORY), + MemoryUsagePrinter.NF.format(MAX_MEMORY), + MemoryUsagePrinter.NF.format(HUMON_SIZE), HUMON_COUNT ); new TestHumongousShrinkHeap().test(); @@ -134,24 +136,16 @@ public class TestHumongousShrinkHeap { */ class MemoryUsagePrinter { - public static String humanReadableByteCount(long bytes, boolean si) { - int unit = si ? 1000 : 1024; - if (bytes < unit) { - return bytes + " B"; - } - int exp = (int) (Math.log(bytes) / Math.log(unit)); - String pre = (si ? "kMGTPE" : "KMGTPE").charAt(exp - 1) + (si ? "" : "i"); - return String.format("%.1f %sB", bytes / Math.pow(unit, exp), pre); - } + public static final NumberFormat NF = Helpers.numberFormatter(); public static void printMemoryUsage(String label) { MemoryUsage memusage = ManagementFactory.getMemoryMXBean().getHeapMemoryUsage(); float freeratio = 1f - (float) memusage.getUsed() / memusage.getCommitted(); System.out.format("[%-24s] init: %-7s, used: %-7s, comm: %-7s, freeRatio ~= %.1f%%%n", label, - humanReadableByteCount(memusage.getInit(), false), - humanReadableByteCount(memusage.getUsed(), false), - humanReadableByteCount(memusage.getCommitted(), false), + NF.format(memusage.getInit()), + NF.format(memusage.getUsed()), + NF.format(memusage.getCommitted()), freeratio * 100 ); } diff --git a/hotspot/test/gc/g1/TestShrinkDefragmentedHeap.java b/hotspot/test/gc/g1/TestShrinkDefragmentedHeap.java index fa3126f2498..f15439e702f 100644 --- a/hotspot/test/gc/g1/TestShrinkDefragmentedHeap.java +++ b/hotspot/test/gc/g1/TestShrinkDefragmentedHeap.java @@ -31,7 +31,7 @@ * "..................................H" * 3. invoke gc and check that memory returned to the system (amount of committed memory got down) * - * @library /test/lib + * @library /test/lib / * @modules java.base/jdk.internal.misc * java.management/sun.management */ @@ -39,10 +39,12 @@ import java.lang.management.ManagementFactory; import java.lang.management.MemoryUsage; import java.util.ArrayList; import java.util.List; +import java.text.NumberFormat; import static jdk.test.lib.Asserts.*; import jdk.test.lib.process.OutputAnalyzer; import jdk.test.lib.process.ProcessTools; import com.sun.management.HotSpotDiagnosticMXBean; +import gc.testlibrary.Helpers; public class TestShrinkDefragmentedHeap { // Since we store all the small objects, they become old and old regions are also allocated at the bottom of the heap @@ -114,8 +116,8 @@ public class TestShrinkDefragmentedHeap { private void allocate() { System.out.format("Will allocate objects of small size = %s and humongous size = %s", - MemoryUsagePrinter.humanReadableByteCount(SMALL_OBJS_SIZE, false), - MemoryUsagePrinter.humanReadableByteCount(HUMONG_OBJS_SIZE, false) + MemoryUsagePrinter.NF.format(SMALL_OBJS_SIZE), + MemoryUsagePrinter.NF.format(HUMONG_OBJS_SIZE) ); for (int i = 0; i < ALLOCATE_COUNT; i++) { @@ -170,24 +172,16 @@ public class TestShrinkDefragmentedHeap { */ static class MemoryUsagePrinter { - public static String humanReadableByteCount(long bytes, boolean si) { - int unit = si ? 1000 : 1024; - if (bytes < unit) { - return bytes + " B"; - } - int exp = (int) (Math.log(bytes) / Math.log(unit)); - String pre = (si ? "kMGTPE" : "KMGTPE").charAt(exp - 1) + (si ? "" : "i"); - return String.format("%.1f %sB", bytes / Math.pow(unit, exp), pre); - } + public static final NumberFormat NF = Helpers.numberFormatter(); public static void printMemoryUsage(String label) { MemoryUsage memusage = ManagementFactory.getMemoryMXBean().getHeapMemoryUsage(); float freeratio = 1f - (float) memusage.getUsed() / memusage.getCommitted(); System.out.format("[%-24s] init: %-7s, used: %-7s, comm: %-7s, freeRatio ~= %.1f%%%n", label, - humanReadableByteCount(memusage.getInit(), false), - humanReadableByteCount(memusage.getUsed(), false), - humanReadableByteCount(memusage.getCommitted(), false), + NF.format(memusage.getInit()), + NF.format(memusage.getUsed()), + NF.format(memusage.getCommitted()), freeratio * 100 ); } diff --git a/hotspot/test/gc/parallel/TestDynShrinkHeap.java b/hotspot/test/gc/parallel/TestDynShrinkHeap.java index 4b6e7d21d24..f5e78ab7346 100644 --- a/hotspot/test/gc/parallel/TestDynShrinkHeap.java +++ b/hotspot/test/gc/parallel/TestDynShrinkHeap.java @@ -28,15 +28,17 @@ * @summary Verify that the heap shrinks after full GC according to the current values of the Min/MaxHeapFreeRatio flags * @modules java.base/jdk.internal.misc * @modules jdk.management - * @library /test/lib + * @library /test/lib / * @run main/othervm -XX:+UseAdaptiveSizePolicyWithSystemGC -XX:+UseParallelGC -XX:MinHeapFreeRatio=0 -XX:MaxHeapFreeRatio=100 -Xmx1g -verbose:gc TestDynShrinkHeap */ import jdk.test.lib.DynamicVMOption; import java.lang.management.ManagementFactory; import java.lang.management.MemoryUsage; import java.util.ArrayList; +import java.text.NumberFormat; import static jdk.test.lib.Asserts.assertLessThan; import com.sun.management.HotSpotDiagnosticMXBean; +import gc.testlibrary.Helpers; public class TestDynShrinkHeap { @@ -101,24 +103,16 @@ public class TestDynShrinkHeap { */ class MemoryUsagePrinter { - public static String humanReadableByteCount(long bytes, boolean si) { - int unit = si ? 1000 : 1024; - if (bytes < unit) { - return bytes + " B"; - } - int exp = (int) (Math.log(bytes) / Math.log(unit)); - String pre = (si ? "kMGTPE" : "KMGTPE").charAt(exp - 1) + (si ? "" : "i"); - return String.format("%.1f %sB", bytes / Math.pow(unit, exp), pre); - } + public static final NumberFormat NF = Helpers.numberFormatter(); public static void printMemoryUsage(String label) { MemoryUsage memusage = ManagementFactory.getMemoryMXBean().getHeapMemoryUsage(); float freeratio = 1f - (float) memusage.getUsed() / memusage.getCommitted(); System.out.format("[%-24s] init: %-7s, used: %-7s, comm: %-7s, freeRatio ~= %.1f%%%n", label, - humanReadableByteCount(memusage.getInit(), true), - humanReadableByteCount(memusage.getUsed(), true), - humanReadableByteCount(memusage.getCommitted(), true), + NF.format(memusage.getInit()), + NF.format(memusage.getUsed()), + NF.format(memusage.getCommitted()), freeratio * 100 ); } diff --git a/hotspot/test/gc/testlibrary/Helpers.java b/hotspot/test/gc/testlibrary/Helpers.java index e18640fe39a..b70b1631859 100644 --- a/hotspot/test/gc/testlibrary/Helpers.java +++ b/hotspot/test/gc/testlibrary/Helpers.java @@ -31,6 +31,9 @@ import java.io.File; import java.io.IOException; import java.nio.file.Files; import java.nio.file.Path; +import java.text.DecimalFormat; +import java.text.DecimalFormatSymbols; +import java.text.NumberFormat; public class Helpers { @@ -320,4 +323,16 @@ public class Helpers { } } + /** + * @return a number formatter instance which prints numbers in a human + * readable form, like 9_223_372_036_854_775_807. + */ + public static NumberFormat numberFormatter() { + DecimalFormat df = new DecimalFormat(); + DecimalFormatSymbols dfs = df.getDecimalFormatSymbols(); + dfs.setGroupingSeparator('_'); + dfs.setDecimalSeparator('.'); + df.setDecimalFormatSymbols(dfs); + return df; + } } From 43b7b1bd770c79dc05464b838bce56267c58466d Mon Sep 17 00:00:00 2001 From: Arno Zeller Date: Thu, 22 Dec 2016 16:51:25 +0100 Subject: [PATCH 004/157] 8171924: Use SIZE_FORMAT to print size_t values Reviewed-by: dholmes, tschatzl, coleenp, goetz --- hotspot/src/share/vm/code/codeCache.cpp | 9 +++++---- hotspot/src/share/vm/gc/g1/g1BiasedArray.hpp | 8 ++++---- hotspot/src/share/vm/prims/jniCheck.cpp | 4 ++-- hotspot/src/share/vm/prims/jvmtiEnter.xsl | 2 +- hotspot/src/share/vm/services/diagnosticCommand.cpp | 2 +- hotspot/src/share/vm/utilities/copy.cpp | 2 +- 6 files changed, 14 insertions(+), 13 deletions(-) diff --git a/hotspot/src/share/vm/code/codeCache.cpp b/hotspot/src/share/vm/code/codeCache.cpp index 80ce54f847e..bfe643ab683 100644 --- a/hotspot/src/share/vm/code/codeCache.cpp +++ b/hotspot/src/share/vm/code/codeCache.cpp @@ -149,16 +149,17 @@ void CodeCache::check_heap_sizes(size_t non_nmethod_size, size_t profiled_size, size_t total_size = non_nmethod_size + profiled_size + non_profiled_size; // Prepare error message const char* error = "Invalid code heap sizes"; - err_msg message("NonNMethodCodeHeapSize (%zuK) + ProfiledCodeHeapSize (%zuK) + NonProfiledCodeHeapSize (%zuK) = %zuK", + err_msg message("NonNMethodCodeHeapSize (" SIZE_FORMAT "K) + ProfiledCodeHeapSize (" SIZE_FORMAT "K)" + " + NonProfiledCodeHeapSize (" SIZE_FORMAT "K) = " SIZE_FORMAT "K", non_nmethod_size/K, profiled_size/K, non_profiled_size/K, total_size/K); if (total_size > cache_size) { // Some code heap sizes were explicitly set: total_size must be <= cache_size - message.append(" is greater than ReservedCodeCacheSize (%zuK).", cache_size/K); + message.append(" is greater than ReservedCodeCacheSize (" SIZE_FORMAT "K).", cache_size/K); vm_exit_during_initialization(error, message); } else if (all_set && total_size != cache_size) { // All code heap sizes were explicitly set: total_size must equal cache_size - message.append(" is not equal to ReservedCodeCacheSize (%zuK).", cache_size/K); + message.append(" is not equal to ReservedCodeCacheSize (" SIZE_FORMAT "K).", cache_size/K); vm_exit_during_initialization(error, message); } } @@ -267,7 +268,7 @@ void CodeCache::initialize_heaps() { uint min_code_cache_size = CodeCacheMinimumUseSpace DEBUG_ONLY(* 3); if (non_nmethod_size < (min_code_cache_size + code_buffers_size)) { vm_exit_during_initialization(err_msg( - "Not enough space in non-nmethod code heap to run VM: %zuK < %zuK", + "Not enough space in non-nmethod code heap to run VM: " SIZE_FORMAT "K < " SIZE_FORMAT "K", non_nmethod_size/K, (min_code_cache_size + code_buffers_size)/K)); } diff --git a/hotspot/src/share/vm/gc/g1/g1BiasedArray.hpp b/hotspot/src/share/vm/gc/g1/g1BiasedArray.hpp index 42069703b27..93b07b21e2d 100644 --- a/hotspot/src/share/vm/gc/g1/g1BiasedArray.hpp +++ b/hotspot/src/share/vm/gc/g1/g1BiasedArray.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 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 @@ -69,12 +69,12 @@ protected: void initialize(HeapWord* bottom, HeapWord* end, size_t target_elem_size_in_bytes, size_t mapping_granularity_in_bytes) { assert(mapping_granularity_in_bytes > 0, "just checking"); assert(is_power_of_2(mapping_granularity_in_bytes), - "mapping granularity must be power of 2, is %zd", mapping_granularity_in_bytes); + "mapping granularity must be power of 2, is " SIZE_FORMAT, mapping_granularity_in_bytes); assert((uintptr_t)bottom % mapping_granularity_in_bytes == 0, - "bottom mapping area address must be a multiple of mapping granularity %zd, is " PTR_FORMAT, + "bottom mapping area address must be a multiple of mapping granularity " SIZE_FORMAT ", is " PTR_FORMAT, mapping_granularity_in_bytes, p2i(bottom)); assert((uintptr_t)end % mapping_granularity_in_bytes == 0, - "end mapping area address must be a multiple of mapping granularity %zd, is " PTR_FORMAT, + "end mapping area address must be a multiple of mapping granularity " SIZE_FORMAT ", is " PTR_FORMAT, mapping_granularity_in_bytes, p2i(end)); size_t num_target_elems = pointer_delta(end, bottom, mapping_granularity_in_bytes); idx_t bias = (uintptr_t)bottom / mapping_granularity_in_bytes; diff --git a/hotspot/src/share/vm/prims/jniCheck.cpp b/hotspot/src/share/vm/prims/jniCheck.cpp index ea80b5b8110..9ba9e1ad419 100644 --- a/hotspot/src/share/vm/prims/jniCheck.cpp +++ b/hotspot/src/share/vm/prims/jniCheck.cpp @@ -238,8 +238,8 @@ functionExit(JavaThread* thr) size_t live_handles = handles->get_number_of_live_handles(); if (live_handles > planned_capacity) { IN_VM( - tty->print_cr("WARNING: JNI local refs: %zu, exceeds capacity: %zu", - live_handles, planned_capacity); + tty->print_cr("WARNING: JNI local refs: " SIZE_FORMAT ", exceeds capacity: " SIZE_FORMAT, + live_handles, planned_capacity); thr->print_stack(); ) // Complain just the once, reset to current + warn threshold diff --git a/hotspot/src/share/vm/prims/jvmtiEnter.xsl b/hotspot/src/share/vm/prims/jvmtiEnter.xsl index 3ce93d1f289..3c426424f39 100644 --- a/hotspot/src/share/vm/prims/jvmtiEnter.xsl +++ b/hotspot/src/share/vm/prims/jvmtiEnter.xsl @@ -1246,7 +1246,7 @@ static jvmtiError JNICALL - =0x%zx + =" SIZE_FORMAT_HEX " diff --git a/hotspot/src/share/vm/services/diagnosticCommand.cpp b/hotspot/src/share/vm/services/diagnosticCommand.cpp index d9e8a628e8a..fd389322e4b 100644 --- a/hotspot/src/share/vm/services/diagnosticCommand.cpp +++ b/hotspot/src/share/vm/services/diagnosticCommand.cpp @@ -292,7 +292,7 @@ void JVMTIAgentLoadDCmd::execute(DCmdSource source, TRAPS) { char *opt = (char *)os::malloc(opt_len, mtInternal); if (opt == NULL) { output()->print_cr("JVMTI agent attach failed: " - "Could not allocate %zu bytes for argument.", + "Could not allocate " SIZE_FORMAT " bytes for argument.", opt_len); return; } diff --git a/hotspot/src/share/vm/utilities/copy.cpp b/hotspot/src/share/vm/utilities/copy.cpp index b04d6519319..7ccf0059351 100644 --- a/hotspot/src/share/vm/utilities/copy.cpp +++ b/hotspot/src/share/vm/utilities/copy.cpp @@ -214,7 +214,7 @@ private: case 2: do_conjoint_swap(src, dst, byte_count); break; case 4: do_conjoint_swap(src, dst, byte_count); break; case 8: do_conjoint_swap(src, dst, byte_count); break; - default: guarantee(false, "do_conjoint_swap: Invalid elem_size %zd\n", elem_size); + default: guarantee(false, "do_conjoint_swap: Invalid elem_size " SIZE_FORMAT "\n", elem_size); } } }; From 9b98f88304ed9f18ccb9a7f57cc62cac5324f7db Mon Sep 17 00:00:00 2001 From: Lutz Schmidt Date: Thu, 22 Dec 2016 15:01:20 -0600 Subject: [PATCH 005/157] 8170981: Possible access to char array with negative index Check arithmetic before trying to access array by index. Reviewed-by: rprotacio, dholmes, gziemski --- hotspot/src/share/vm/runtime/globals.cpp | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/hotspot/src/share/vm/runtime/globals.cpp b/hotspot/src/share/vm/runtime/globals.cpp index 68ec6b058cc..3262ab279ab 100644 --- a/hotspot/src/share/vm/runtime/globals.cpp +++ b/hotspot/src/share/vm/runtime/globals.cpp @@ -469,14 +469,18 @@ void Flag::print_on(outputStream* st, bool withComments, bool printRanges) { } if (!printRanges) { + // Use some named constants to make code more readable. + const unsigned int nSpaces = 10; + const unsigned int maxFlagLen = 40 + nSpaces; + // The print below assumes that the flag name is 40 characters or less. // This works for most flags, but there are exceptions. Our longest flag // name right now is UseAdaptiveGenerationSizePolicyAtMajorCollection and // its minor collection buddy. These are 48 characters. We use a buffer of - // 10 spaces below to adjust the space between the flag value and the + // nSpaces spaces below to adjust the space between the flag value and the // column of flag type and origin that is printed in the end of the line. - char spaces[10 + 1] = " "; - st->print("%9s %-40s = ", _type, _name); + char spaces[nSpaces + 1] = " "; + st->print("%9s %-*s = ", _type, maxFlagLen-nSpaces, _name); if (is_bool()) { st->print("%-20s", get_bool() ? "true" : "false"); @@ -509,9 +513,12 @@ void Flag::print_on(outputStream* st, bool withComments, bool printRanges) { } else st->print("%-20s", ""); } - assert(strlen(_name) < 50, "Flag name is longer than expected"); - spaces[50 - MAX2((size_t)40, strlen(_name))] = '\0'; - st->print("%s", spaces); + // Make sure we do not punch a '\0' at a negative char array index. + unsigned int nameLen = (unsigned int)strlen(_name); + if (nameLen <= maxFlagLen) { + spaces[maxFlagLen - MAX2(maxFlagLen-nSpaces, nameLen)] = '\0'; + st->print("%s", spaces); + } print_kind_and_origin(st); #ifndef PRODUCT From 2d444d6f19fa6e356bfe540d601ebd40d2aebfa9 Mon Sep 17 00:00:00 2001 From: Igor Veresov Date: Thu, 22 Dec 2016 17:26:02 -0800 Subject: [PATCH 006/157] 8168792: [AOT] problems in MethodHandle with aot-compiled java.base Properly support assertions in AOT Reviewed-by: kvn --- .../jaotc/binformat/BinaryContainer.java | 44 ++++++++++--------- .../src/jdk/tools/jaotc/AOTBackend.java | 10 +++-- .../src/jdk/tools/jaotc/Main.java | 34 ++++++++++---- .../hotspot/meta/HotSpotNodePlugin.java | 6 --- hotspot/src/share/vm/aot/aotCodeHeap.cpp | 9 +++- hotspot/src/share/vm/aot/aotCodeHeap.hpp | 3 +- 6 files changed, 66 insertions(+), 40 deletions(-) diff --git a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/BinaryContainer.java b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/BinaryContainer.java index 7be7a80192e..0c411fb7f1d 100644 --- a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/BinaryContainer.java +++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/BinaryContainer.java @@ -37,6 +37,7 @@ import jdk.tools.jaotc.binformat.Symbol.Binding; import jdk.tools.jaotc.binformat.Symbol.Kind; import jdk.tools.jaotc.binformat.elf.JELFRelocObject; import org.graalvm.compiler.hotspot.GraalHotSpotVMConfig; +import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration; /** * A format-agnostic container class that holds various components of a binary. @@ -257,9 +258,9 @@ public class BinaryContainer implements SymbolTable { * prefix {@code prefix}. It also initializes internal code container, symbol table and * relocation tables. */ - public BinaryContainer(GraalHotSpotVMConfig config, String jvmVersion) { - this.codeSegmentSize = config.codeSegmentSize; - this.codeEntryAlignment = config.codeEntryAlignment; + public BinaryContainer(GraalHotSpotVMConfig graalHotSpotVMConfig, GraphBuilderConfiguration graphBuilderConfig, String jvmVersion) { + this.codeSegmentSize = graalHotSpotVMConfig.codeSegmentSize; + this.codeEntryAlignment = graalHotSpotVMConfig.codeEntryAlignment; // read only, code codeContainer = new CodeContainer(".text", this); @@ -289,30 +290,31 @@ public class BinaryContainer implements SymbolTable { addGlobalSymbols(); - recordConfiguration(config); + recordConfiguration(graalHotSpotVMConfig, graphBuilderConfig); } - private void recordConfiguration(GraalHotSpotVMConfig config) { + private void recordConfiguration(GraalHotSpotVMConfig graalHotSpotVMConfig, GraphBuilderConfiguration graphBuilderConfig) { // @formatter:off - boolean[] booleanFlags = { config.cAssertions, // Debug VM - config.useCompressedOops, - config.useCompressedClassPointers, - config.compactFields, - config.useG1GC, - config.useCMSGC, - config.useTLAB, - config.useBiasedLocking, + boolean[] booleanFlags = { graalHotSpotVMConfig.cAssertions, // Debug VM + graalHotSpotVMConfig.useCompressedOops, + graalHotSpotVMConfig.useCompressedClassPointers, + graalHotSpotVMConfig.compactFields, + graalHotSpotVMConfig.useG1GC, + graalHotSpotVMConfig.useCMSGC, + graalHotSpotVMConfig.useTLAB, + graalHotSpotVMConfig.useBiasedLocking, TieredAOT.getValue(), - config.enableContended, - config.restrictContended, + graalHotSpotVMConfig.enableContended, + graalHotSpotVMConfig.restrictContended, + graphBuilderConfig.omitAssertions() }; - int[] intFlags = { config.narrowOopShift, - config.narrowKlassShift, - config.contendedPaddingWidth, - config.fieldsAllocationStyle, - config.objectAlignment, - config.codeSegmentSize, + int[] intFlags = { graalHotSpotVMConfig.narrowOopShift, + graalHotSpotVMConfig.narrowKlassShift, + graalHotSpotVMConfig.contendedPaddingWidth, + graalHotSpotVMConfig.fieldsAllocationStyle, + graalHotSpotVMConfig.objectAlignment, + graalHotSpotVMConfig.codeSegmentSize, }; // @formatter:on diff --git a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/AOTBackend.java b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/AOTBackend.java index b5d081a51ca..3ba1067b959 100644 --- a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/AOTBackend.java +++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/AOTBackend.java @@ -77,10 +77,14 @@ public class AOTBackend { this.filters = filters; providers = backend.getProviders(); codeCache = providers.getCodeCache(); - graphBuilderSuite = initGraphBuilderSuite(backend); + graphBuilderSuite = initGraphBuilderSuite(backend, main.options.compileWithAssertions); highTierContext = new HighTierContext(providers, graphBuilderSuite, OptimisticOptimizations.ALL); } + public PhaseSuite getGraphBuilderSuite() { + return graphBuilderSuite; + } + private Suites getSuites() { // create suites every time, as we modify options for the compiler return backend.getSuites().getDefaultSuites(); @@ -146,14 +150,14 @@ public class AOTBackend { return backend.getRuntime().getVMConfig().cAssertions; } - private static PhaseSuite initGraphBuilderSuite(HotSpotBackend backend) { + private static PhaseSuite initGraphBuilderSuite(HotSpotBackend backend, boolean compileWithAssertions) { PhaseSuite graphBuilderSuite = backend.getSuites().getDefaultGraphBuilderSuite().copy(); ListIterator> iterator = graphBuilderSuite.findPhase(GraphBuilderPhase.class); GraphBuilderConfiguration baseConfig = ((GraphBuilderPhase) iterator.previous()).getGraphBuilderConfig(); // Use all default plugins. Plugins plugins = baseConfig.getPlugins(); - GraphBuilderConfiguration aotConfig = GraphBuilderConfiguration.getDefault(plugins).withEagerResolving(true); + GraphBuilderConfiguration aotConfig = GraphBuilderConfiguration.getDefault(plugins).withEagerResolving(true).withOmitAssertions(!compileWithAssertions); iterator.next(); iterator.remove(); diff --git a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/Main.java b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/Main.java index a1257b7a013..2af308732e4 100644 --- a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/Main.java +++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/Main.java @@ -45,6 +45,7 @@ import java.util.ArrayList; import java.util.Date; import java.util.LinkedList; import java.util.List; +import java.util.ListIterator; import java.util.Set; import java.util.stream.Stream; @@ -54,8 +55,14 @@ import jdk.tools.jaotc.collect.ClassCollector; import jdk.tools.jaotc.utils.Timer; import org.graalvm.compiler.api.runtime.GraalJVMCICompiler; +import org.graalvm.compiler.hotspot.GraalHotSpotVMConfig; import org.graalvm.compiler.hotspot.HotSpotGraalRuntimeProvider; import org.graalvm.compiler.hotspot.HotSpotHostBackend; +import org.graalvm.compiler.java.GraphBuilderPhase; +import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration; +import org.graalvm.compiler.phases.BasePhase; +import org.graalvm.compiler.phases.PhaseSuite; +import org.graalvm.compiler.phases.tiers.HighTierContext; import org.graalvm.compiler.runtime.RuntimeProvider; import jdk.vm.ci.meta.MetaAccessProvider; @@ -144,11 +151,16 @@ public class Main implements LogPrinter { void process(Main task, String opt, String arg) { task.options.methodList = arg; } - }, new Option(" --compile-for-tiered Generated profiling code for tiered compilation", false, "--compile-for-tiered") { + }, new Option(" --compile-for-tiered Generate profiling code for tiered compilation", false, "--compile-for-tiered") { @Override void process(Main task, String opt, String arg) { TieredAOT.setValue(true); } + }, new Option(" --compile-with-assertions Compile assertions", false, "--compile-with-assertions") { + @Override + void process(Main task, String opt, String arg) { + task.options.compileWithAssertions = true; + } }, new Option(" --classpath Specify where to find user class files", true, "--classpath", "--class-path") { @Override void process(Main task, String opt, String arg) { @@ -225,15 +237,16 @@ public class Main implements LogPrinter { */ private static final int COMPILER_THREADS = 16; - int threads = Integer.min(COMPILER_THREADS, Runtime.getRuntime().availableProcessors()); + public int threads = Integer.min(COMPILER_THREADS, Runtime.getRuntime().availableProcessors()); public boolean ignoreClassLoadingErrors; public boolean exitOnError; - boolean info; - boolean verbose; - boolean debug; - boolean help; - boolean version; + public boolean info; + public boolean verbose; + public boolean debug; + public boolean help; + public boolean version; + public boolean compileWithAssertions; } /* package */final Options options = new Options(); @@ -356,6 +369,11 @@ public class Main implements LogPrinter { AOTCompiler compiler = new AOTCompiler(this, aotBackend, options.threads); classes = compiler.compileClasses(classes); + GraalHotSpotVMConfig graalHotSpotVMConfig = runtime.getVMConfig(); + PhaseSuite graphBuilderSuite = aotBackend.getGraphBuilderSuite(); + ListIterator> iterator = graphBuilderSuite.findPhase(GraphBuilderPhase.class); + GraphBuilderConfiguration graphBuilderConfig = ((GraphBuilderPhase) iterator.previous()).getGraphBuilderConfig(); + // Free memory! try (Timer t = options.verbose ? new Timer(this, "Freeing memory") : null) { printMemoryUsage(); @@ -364,7 +382,7 @@ public class Main implements LogPrinter { System.gc(); } - BinaryContainer binaryContainer = new BinaryContainer(runtime.getVMConfig(), JVM_VERSION); + BinaryContainer binaryContainer = new BinaryContainer(graalHotSpotVMConfig, graphBuilderConfig, JVM_VERSION); DataBuilder dataBuilder = new DataBuilder(this, backend, classes, binaryContainer); dataBuilder.prepareData(); diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotNodePlugin.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotNodePlugin.java index 89729e7e3f4..10b2255a3dc 100644 --- a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotNodePlugin.java +++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotNodePlugin.java @@ -22,7 +22,6 @@ */ package org.graalvm.compiler.hotspot.meta; -import static org.graalvm.compiler.core.common.GraalOptions.GeneratePIC; import static org.graalvm.compiler.core.common.GraalOptions.ImmutableCode; import static org.graalvm.compiler.hotspot.meta.HotSpotGraalConstantFieldProvider.FieldReadEnabledInImmutableCode; @@ -112,11 +111,6 @@ public final class HotSpotNodePlugin implements NodePlugin, TypePlugin { return true; } } - if (GeneratePIC.getValue()) { - if (field.isSynthetic() && field.getName().startsWith("$assertionsDisabled")) { - return tryReadField(b, field, null); - } - } if (b.parsingIntrinsic() && wordOperationPlugin.handleLoadStaticField(b, field)) { return true; } diff --git a/hotspot/src/share/vm/aot/aotCodeHeap.cpp b/hotspot/src/share/vm/aot/aotCodeHeap.cpp index 08283a92fbe..3d0a22255da 100644 --- a/hotspot/src/share/vm/aot/aotCodeHeap.cpp +++ b/hotspot/src/share/vm/aot/aotCodeHeap.cpp @@ -25,6 +25,7 @@ #include "aot/aotCodeHeap.hpp" #include "aot/aotLoader.hpp" +#include "classfile/javaAssertions.hpp" #include "gc/g1/heapRegion.hpp" #include "gc/shared/gcLocker.hpp" #include "interpreter/abstractInterpreter.hpp" @@ -706,6 +707,12 @@ bool AOTCodeHeap::load_klass_data(instanceKlassHandle kh, Thread* thread) { return false; } + if (_lib->config()->_omitAssertions && JavaAssertions::enabled(kh->name()->as_C_string(), kh->class_loader() == NULL)) { + // Assertions are omitted in the compiled code, but are enabled right now. Bail out. + sweep_dependent_methods(klass_data); + return false; + } + NOT_PRODUCT( aot_klasses_found++; ) log_trace(aot, class, load)("found %s in %s for classloader %p tid=" INTPTR_FORMAT, kh->internal_name(), _lib->name(), kh->class_loader_data(), p2i(thread)); @@ -714,7 +721,7 @@ bool AOTCodeHeap::load_klass_data(instanceKlassHandle kh, Thread* thread) { // Set klass's Resolve (second) got cell. _metaspace_got[klass_data->_got_index] = kh(); - // Initialize global symbols of the DSO to the correspondingVM symbol values. + // Initialize global symbols of the DSO to the corresponding VM symbol values. link_global_lib_symbols(); int methods_offset = klass_data->_compiled_methods_offset; diff --git a/hotspot/src/share/vm/aot/aotCodeHeap.hpp b/hotspot/src/share/vm/aot/aotCodeHeap.hpp index 21ce9a042f0..0e0d0038d10 100644 --- a/hotspot/src/share/vm/aot/aotCodeHeap.hpp +++ b/hotspot/src/share/vm/aot/aotCodeHeap.hpp @@ -88,7 +88,7 @@ typedef struct { } AOTHeader; typedef struct { - enum { CONFIG_SIZE = 11 + 7 * 4 }; + enum { CONFIG_SIZE = 12 + 7 * 4 }; int _config_size; int _narrowOopShift; int _narrowKlassShift; @@ -108,6 +108,7 @@ typedef struct { bool _tieredAOT; bool _enableContended; bool _restrictContended; + bool _omitAssertions; } AOTConfiguration; class AOTLib : public CHeapObj { From 89bfef80d05d822e9ece715ff03f0612c4c43816 Mon Sep 17 00:00:00 2001 From: George Triantafillou Date: Thu, 22 Dec 2016 11:37:49 -0500 Subject: [PATCH 007/157] 8171318: serviceability/sa/jmap-hprof/JMapHProfLargeHeapTest.java fails latest Jigsaw integration Reviewed-by: sspitsyn, dholmes --- .../sa/jmap-hprof/JMapHProfLargeHeapProc.java | 25 ++----------------- .../sa/jmap-hprof/JMapHProfLargeHeapTest.java | 3 +++ 2 files changed, 5 insertions(+), 23 deletions(-) diff --git a/hotspot/test/serviceability/sa/jmap-hprof/JMapHProfLargeHeapProc.java b/hotspot/test/serviceability/sa/jmap-hprof/JMapHProfLargeHeapProc.java index c3dced229db..855fbad95c6 100644 --- a/hotspot/test/serviceability/sa/jmap-hprof/JMapHProfLargeHeapProc.java +++ b/hotspot/test/serviceability/sa/jmap-hprof/JMapHProfLargeHeapProc.java @@ -21,12 +21,9 @@ * questions. */ -import java.lang.management.ManagementFactory; -import java.lang.management.RuntimeMXBean; -import java.lang.reflect.Field; -import java.lang.reflect.Method; import java.util.ArrayList; import java.util.List; +import jdk.test.lib.process.ProcessTools; import sun.management.VMManagement; @@ -38,7 +35,7 @@ public class JMapHProfLargeHeapProc { buildLargeHeap(args); // Print our pid on stdout - System.out.println("PID[" + getProcessId() + "]"); + System.out.println("PID[" + ProcessTools.getProcessId() + "]"); // Wait for input before termination System.in.read(); @@ -50,22 +47,4 @@ public class JMapHProfLargeHeapProc { } } - public static int getProcessId() throws Exception { - - // Get the current process id using a reflection hack - RuntimeMXBean runtime = ManagementFactory.getRuntimeMXBean(); - Field jvm = runtime.getClass().getDeclaredField("jvm"); - - jvm.setAccessible(true); - VMManagement mgmt = (sun.management.VMManagement) jvm.get(runtime); - - Method pid_method = mgmt.getClass().getDeclaredMethod("getProcessId"); - - pid_method.setAccessible(true); - - int pid = (Integer) pid_method.invoke(mgmt); - - return pid; - } - } diff --git a/hotspot/test/serviceability/sa/jmap-hprof/JMapHProfLargeHeapTest.java b/hotspot/test/serviceability/sa/jmap-hprof/JMapHProfLargeHeapTest.java index d2e64f75d34..a95ae0d4ff3 100644 --- a/hotspot/test/serviceability/sa/jmap-hprof/JMapHProfLargeHeapTest.java +++ b/hotspot/test/serviceability/sa/jmap-hprof/JMapHProfLargeHeapTest.java @@ -90,6 +90,9 @@ public class JMapHProfLargeHeapTest { try (Scanner largeHeapScanner = new Scanner( largeHeapProc.getInputStream());) { String pidstring = null; + if (!largeHeapScanner.hasNext()) { + throw new RuntimeException ("Test failed: could not open largeHeapScanner."); + } while ((pidstring = largeHeapScanner.findInLine("PID\\[[0-9].*\\]")) == null) { Thread.sleep(500); } From f805a3a054059b94a25b5efbcf06e8e7510271fd Mon Sep 17 00:00:00 2001 From: Boris Molodenkov Date: Wed, 21 Dec 2016 15:01:01 +0300 Subject: [PATCH 008/157] 8170918: Remove shell script from test/compiler/c2/cr7200264/TestIntVect.java Reviewed-by: kvn --- hotspot/test/TEST.ROOT | 1 + .../test/compiler/c2/cr7200264/Test7200264.sh | 132 ------------------ .../compiler/c2/cr7200264/TestDriver.java | 68 +++++++++ .../compiler/c2/cr7200264/TestIntVect.java | 10 +- .../c2/cr7200264/TestSSE2IntVect.java | 48 +++++++ .../c2/cr7200264/TestSSE4IntVect.java | 41 ++++++ 6 files changed, 159 insertions(+), 141 deletions(-) delete mode 100644 hotspot/test/compiler/c2/cr7200264/Test7200264.sh create mode 100644 hotspot/test/compiler/c2/cr7200264/TestDriver.java create mode 100644 hotspot/test/compiler/c2/cr7200264/TestSSE2IntVect.java create mode 100644 hotspot/test/compiler/c2/cr7200264/TestSSE4IntVect.java diff --git a/hotspot/test/TEST.ROOT b/hotspot/test/TEST.ROOT index 45e21c61479..14d3a1c0135 100644 --- a/hotspot/test/TEST.ROOT +++ b/hotspot/test/TEST.ROOT @@ -46,6 +46,7 @@ requires.properties= \ vm.gc.Parallel \ vm.gc.ConcMarkSweep \ vm.jvmci \ + vm.cpu.features \ vm.debug # Tests using jtreg 4.2 b04 features diff --git a/hotspot/test/compiler/c2/cr7200264/Test7200264.sh b/hotspot/test/compiler/c2/cr7200264/Test7200264.sh deleted file mode 100644 index 7848bff2d70..00000000000 --- a/hotspot/test/compiler/c2/cr7200264/Test7200264.sh +++ /dev/null @@ -1,132 +0,0 @@ -#!/bin/sh -# -# Copyright (c) 2012, 2015, 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. -# -# - -## some tests require path to find test source dir -if [ "${TESTSRC}" = "" ] -then - TESTSRC=${PWD} - echo "TESTSRC not set. Using "${TESTSRC}" as default" -fi -echo "TESTSRC=${TESTSRC}" -## Adding common setup Variables for running shell tests. -. ${TESTSRC}/../../../test_env.sh - -${TESTJAVA}${FS}bin${FS}java ${TESTOPTS} -Xinternalversion | sed 's/amd64/x86/' | grep "x86" | grep "Server VM" | grep "debug" - -# Only test fastdebug Server VM on x86 -if [ $? != 0 ] -then - echo "Test Passed" - exit 0 -fi - -# grep for support integer multiply vectors (cpu with SSE4.1) -${TESTJAVA}${FS}bin${FS}java ${TESTOPTS} -XX:+PrintMiscellaneous -XX:+Verbose -version | grep "cores per cpu" | grep "sse4.1" - -if [ $? != 0 ] -then - SSE=2 -else - SSE=4 -fi - -cp ${TESTSRC}${FS}TestIntVect.java . -${COMPILEJAVA}${FS}bin${FS}javac ${TESTJAVACOPTS} -d . TestIntVect.java - -# CICompilerCount must be at least 2 with -TieredCompilation -${TESTJAVA}${FS}bin${FS}java ${TESTOPTS} -Xbatch -XX:-TieredCompilation \ - -XX:CICompilerCount=2 -XX:+PrintCompilation -XX:+TraceNewVectors \ - compiler.c2.cr7200264.TestIntVect > test.out 2>&1 - -COUNT=`grep AddVI test.out | wc -l | awk '{print $1}'` -if [ $COUNT -lt 4 ] -then - echo "Test Failed: AddVI $COUNT < 4" - exit 1 -fi - -# AddVI is generated for test_subc -COUNT=`grep SubVI test.out | wc -l | awk '{print $1}'` -if [ $COUNT -lt 4 ] -then - echo "Test Failed: SubVI $COUNT < 4" - exit 1 -fi - -# MulVI is only supported with SSE4.1. -if [ $SSE -gt 3 ] -then -# LShiftVI+SubVI is generated for test_mulc -COUNT=`grep MulVI test.out | wc -l | awk '{print $1}'` -if [ $COUNT -lt 2 ] -then - echo "Test Failed: MulVI $COUNT < 2" - exit 1 -fi -fi - -COUNT=`grep AndV test.out | wc -l | awk '{print $1}'` -if [ $COUNT -lt 3 ] -then - echo "Test Failed: AndV $COUNT < 3" - exit 1 -fi - -COUNT=`grep OrV test.out | wc -l | awk '{print $1}'` -if [ $COUNT -lt 3 ] -then - echo "Test Failed: OrV $COUNT < 3" - exit 1 -fi - -COUNT=`grep XorV test.out | wc -l | awk '{print $1}'` -if [ $COUNT -lt 3 ] -then - echo "Test Failed: XorV $COUNT < 3" - exit 1 -fi - -# LShiftVI+SubVI is generated for test_mulc -COUNT=`grep LShiftVI test.out | wc -l | awk '{print $1}'` -if [ $COUNT -lt 5 ] -then - echo "Test Failed: LShiftVI $COUNT < 5" - exit 1 -fi - -COUNT=`grep RShiftVI test.out | sed '/URShiftVI/d' | wc -l | awk '{print $1}'` -if [ $COUNT -lt 3 ] -then - echo "Test Failed: RShiftVI $COUNT < 3" - exit 1 -fi - -COUNT=`grep URShiftVI test.out | wc -l | awk '{print $1}'` -if [ $COUNT -lt 3 ] -then - echo "Test Failed: URShiftVI $COUNT < 3" - exit 1 -fi - diff --git a/hotspot/test/compiler/c2/cr7200264/TestDriver.java b/hotspot/test/compiler/c2/cr7200264/TestDriver.java new file mode 100644 index 00000000000..558592ba693 --- /dev/null +++ b/hotspot/test/compiler/c2/cr7200264/TestDriver.java @@ -0,0 +1,68 @@ +/* + * 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 compiler.c2.cr7200264; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.regex.Pattern; + +import jdk.test.lib.Asserts; +import jdk.test.lib.process.OutputAnalyzer; +import jdk.test.lib.process.ProcessTools; + +public class TestDriver { + private final Map expectedVectorizationNumbers + = new HashMap<>(); + + public void addExpectedVectorization(String v, long num) { + expectedVectorizationNumbers.put(v, num); + } + + public void run() throws Throwable { + verifyVectorizationNumber(executeApplication()); + } + + private List executeApplication() throws Throwable { + OutputAnalyzer outputAnalyzer = ProcessTools.executeTestJvmAllArgs( + "-Xbatch", + "-XX:-TieredCompilation", + "-XX:+PrintCompilation", + "-XX:+TraceNewVectors", + TestIntVect.class.getName()); + outputAnalyzer.shouldHaveExitValue(0); + return outputAnalyzer.asLines(); + } + + private void verifyVectorizationNumber(List vectorizationLog) { + for (Map.Entry entry : expectedVectorizationNumbers.entrySet()) { + String v = "\t" + entry.getKey(); + long actualNum = vectorizationLog.stream() + .filter(s -> s.contains(v)).count(); + long expectedNum = entry.getValue(); + Asserts.assertGTE(actualNum, expectedNum, + "Unexpected " + entry.getKey() + " number"); + } + } +} diff --git a/hotspot/test/compiler/c2/cr7200264/TestIntVect.java b/hotspot/test/compiler/c2/cr7200264/TestIntVect.java index 088df3346b1..51226a8576e 100644 --- a/hotspot/test/compiler/c2/cr7200264/TestIntVect.java +++ b/hotspot/test/compiler/c2/cr7200264/TestIntVect.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 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 @@ -21,14 +21,6 @@ * questions. */ -/** - * @test - * @bug 7200264 - * @summary 7192963 changes disabled shift vectors - * - * @run shell Test7200264.sh - */ - package compiler.c2.cr7200264; /* * Copy of test/compiler/6340864/TestIntVect.java without performance tests. diff --git a/hotspot/test/compiler/c2/cr7200264/TestSSE2IntVect.java b/hotspot/test/compiler/c2/cr7200264/TestSSE2IntVect.java new file mode 100644 index 00000000000..f8a3e6607d2 --- /dev/null +++ b/hotspot/test/compiler/c2/cr7200264/TestSSE2IntVect.java @@ -0,0 +1,48 @@ +/* + * 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 7200264 + * @summary 7192963 changes disabled shift vectors + * @requires vm.cpu.features ~= ".*sse2.*" & vm.debug & vm.flavor == "server" + * @library /test/lib / + * @run driver compiler.c2.cr7200264.TestSSE2IntVect + */ + +package compiler.c2.cr7200264; + +public class TestSSE2IntVect { + public static void main(String[] args) throws Throwable { + TestDriver test = new TestDriver(); + test.addExpectedVectorization("AddVI", 4); + test.addExpectedVectorization("SubVI", 4); + test.addExpectedVectorization("AndV", 3); + test.addExpectedVectorization("OrV", 3); + test.addExpectedVectorization("XorV", 3); + test.addExpectedVectorization("LShiftVI", 5); + test.addExpectedVectorization("RShiftVI", 3); + test.addExpectedVectorization("URShiftVI", 3); + test.run(); + } +} diff --git a/hotspot/test/compiler/c2/cr7200264/TestSSE4IntVect.java b/hotspot/test/compiler/c2/cr7200264/TestSSE4IntVect.java new file mode 100644 index 00000000000..c3c2c6aa52a --- /dev/null +++ b/hotspot/test/compiler/c2/cr7200264/TestSSE4IntVect.java @@ -0,0 +1,41 @@ +/* + * 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 7200264 + * @summary 7192963 changes disabled shift vectors + * @requires vm.cpu.features ~= ".*sse4\\.1.*" & vm.debug & vm.flavor == "server" + * @library /test/lib / + * @run driver compiler.c2.cr7200264.TestSSE4IntVect + */ + +package compiler.c2.cr7200264; + +public class TestSSE4IntVect { + public static void main(String[] args) throws Throwable { + TestDriver test = new TestDriver(); + test.addExpectedVectorization("MulVI", 2); + test.run(); + } +} From 475d592e3db89418b6a7d9ba6d71b765df26c699 Mon Sep 17 00:00:00 2001 From: Igor Ignatyev Date: Fri, 30 Dec 2016 20:11:49 +0300 Subject: [PATCH 009/157] 8172149: CTW library should call System::exit Reviewed-by: vlivanov --- .../hotspot/tools/ctw/CompileTheWorld.java | 8 ++-- .../testlibrary_tests/ctw/ClassesDirTest.java | 10 ++--- .../ctw/ClassesListTest.java | 10 ++--- .../test/testlibrary_tests/ctw/CtwTest.java | 39 +++++++++++++++---- .../testlibrary_tests/ctw/JarDirTest.java | 10 ++--- .../test/testlibrary_tests/ctw/JarsTest.java | 10 ++--- 6 files changed, 56 insertions(+), 31 deletions(-) diff --git a/hotspot/test/testlibrary/ctw/src/sun/hotspot/tools/ctw/CompileTheWorld.java b/hotspot/test/testlibrary/ctw/src/sun/hotspot/tools/ctw/CompileTheWorld.java index 88a94f66cdf..98a3d29bfa4 100644 --- a/hotspot/test/testlibrary/ctw/src/sun/hotspot/tools/ctw/CompileTheWorld.java +++ b/hotspot/test/testlibrary/ctw/src/sun/hotspot/tools/ctw/CompileTheWorld.java @@ -59,6 +59,8 @@ public class CompileTheWorld { OUT = os; } + boolean passed = false; + try { try { if (ManagementFactory.getCompilationMXBean() == null) { @@ -84,10 +86,10 @@ public class CompileTheWorld { PathHandler.getClassCount(), Compiler.getMethodCount(), System.currentTimeMillis() - start); + passed = true; } finally { - if (os != null) { - os.close(); - } + // might have started new threads + System.exit(passed ? 0 : 1); } } diff --git a/hotspot/test/testlibrary_tests/ctw/ClassesDirTest.java b/hotspot/test/testlibrary_tests/ctw/ClassesDirTest.java index 31f24081fa1..e24461cdac9 100644 --- a/hotspot/test/testlibrary_tests/ctw/ClassesDirTest.java +++ b/hotspot/test/testlibrary_tests/ctw/ClassesDirTest.java @@ -30,11 +30,11 @@ * java.base/jdk.internal.reflect * java.management * @build sun.hotspot.WhiteBox Foo Bar - * @run main ClassFileInstaller sun.hotspot.WhiteBox Foo Bar - * sun.hotspot.WhiteBox$WhiteBoxPermission - * @run main ClassesDirTest prepare - * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Dsun.hotspot.tools.ctw.logfile=ctw.log sun.hotspot.tools.ctw.CompileTheWorld classes - * @run main ClassesDirTest check ctw.log + * @run driver ClassFileInstaller sun.hotspot.WhiteBox Foo Bar + * sun.hotspot.WhiteBox$WhiteBoxPermission + * @run driver ClassesDirTest prepare + * @run driver ClassesDirTest compile classes + * @run driver ClassesDirTest check * @summary testing of CompileTheWorld :: classes in directory * @author igor.ignatyev@oracle.com */ diff --git a/hotspot/test/testlibrary_tests/ctw/ClassesListTest.java b/hotspot/test/testlibrary_tests/ctw/ClassesListTest.java index c2823de598c..5ffe27ba0c6 100644 --- a/hotspot/test/testlibrary_tests/ctw/ClassesListTest.java +++ b/hotspot/test/testlibrary_tests/ctw/ClassesListTest.java @@ -30,11 +30,11 @@ * java.base/jdk.internal.reflect * java.management * @build sun.hotspot.WhiteBox Foo Bar - * @run main ClassFileInstaller sun.hotspot.WhiteBox Foo Bar - * sun.hotspot.WhiteBox$WhiteBoxPermission - * @run main ClassesListTest prepare - * @run main/othervm/timeout=600 -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Dsun.hotspot.tools.ctw.logfile=ctw.log sun.hotspot.tools.ctw.CompileTheWorld classes.lst - * @run main ClassesListTest check ctw.log + * @run driver ClassFileInstaller sun.hotspot.WhiteBox Foo Bar + * sun.hotspot.WhiteBox$WhiteBoxPermission + * @run driver ClassesListTest prepare + * @run driver/timeout=600 ClassesListTest compile classes.lst + * @run driver ClassesListTest check * @summary testing of CompileTheWorld :: list of classes in file * @author igor.ignatyev@oracle.com */ diff --git a/hotspot/test/testlibrary_tests/ctw/CtwTest.java b/hotspot/test/testlibrary_tests/ctw/CtwTest.java index 06b16b631b9..eb6aedc1fbe 100644 --- a/hotspot/test/testlibrary_tests/ctw/CtwTest.java +++ b/hotspot/test/testlibrary_tests/ctw/CtwTest.java @@ -21,6 +21,7 @@ * questions. */ +import java.util.Arrays; import java.util.List; import java.util.Collections; import java.util.ArrayList; @@ -38,8 +39,20 @@ import java.nio.charset.Charset; import jdk.test.lib.JDKToolFinder; import jdk.test.lib.process.OutputAnalyzer; +import jdk.test.lib.process.ProcessTools; public abstract class CtwTest { + private static final String LOG_FILE = "ctw.log"; + private static final String[] CTW_COMMAND = { + "-Xbootclasspath/a:.", + "-XX:+UnlockDiagnosticVMOptions", + "-XX:+WhiteBoxAPI", + "-Dsun.hotspot.tools.ctw.logfile=" + LOG_FILE, + "--add-exports", "java.base/jdk.internal.jimage=ALL-UNNAMED", + "--add-exports", "java.base/jdk.internal.misc=ALL-UNNAMED", + "--add-exports", "java.base/jdk.internal.reflect=ALL-UNNAMED", + sun.hotspot.tools.ctw.CompileTheWorld.class.getName(), + }; protected final String[] shouldContain; protected CtwTest(String[] shouldContain) { this.shouldContain = shouldContain; @@ -54,7 +67,10 @@ public abstract class CtwTest { prepare(); break; case "check": - check(args); + check(); + break; + case "compile": + compile(args); break; default: throw new Error("unregonized action -- " + args[0]); @@ -63,20 +79,27 @@ public abstract class CtwTest { protected void prepare() throws Exception { } - protected void check(String[] args) throws Exception { - if (args.length < 2) { - throw new Error("logfile isn't specified"); - } - String logfile = args[1]; - try (BufferedReader r = Files.newBufferedReader(Paths.get(logfile), + protected void check() throws Exception { + try (BufferedReader r = Files.newBufferedReader(Paths.get(LOG_FILE), Charset.defaultCharset())) { OutputAnalyzer output = readOutput(r); - for (String test : shouldContain) { + for (String test : shouldContain) { output.shouldContain(test); } } } + protected void compile(String[] args) throws Exception { + // concat CTW_COMMAND and args w/o 0th element + String[] cmd = Arrays.copyOf(CTW_COMMAND, CTW_COMMAND.length + args.length - 1); + System.arraycopy(args, 1, cmd, CTW_COMMAND.length, args.length - 1); + + ProcessBuilder pb = ProcessTools.createJavaProcessBuilder(true, cmd); + OutputAnalyzer output = new OutputAnalyzer(pb.start()); + dump(output, "compile"); + output.shouldHaveExitValue(0); + } + private static OutputAnalyzer readOutput(BufferedReader reader) throws IOException { StringBuilder builder = new StringBuilder(); diff --git a/hotspot/test/testlibrary_tests/ctw/JarDirTest.java b/hotspot/test/testlibrary_tests/ctw/JarDirTest.java index a784bda84ad..a5158554fa7 100644 --- a/hotspot/test/testlibrary_tests/ctw/JarDirTest.java +++ b/hotspot/test/testlibrary_tests/ctw/JarDirTest.java @@ -32,11 +32,11 @@ * java.management * jdk.jvmstat/sun.jvmstat.monitor * @build sun.hotspot.WhiteBox Foo Bar - * @run main ClassFileInstaller sun.hotspot.WhiteBox Foo Bar - * sun.hotspot.WhiteBox$WhiteBoxPermission - * @run main JarDirTest prepare - * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Dsun.hotspot.tools.ctw.logfile=ctw.log sun.hotspot.tools.ctw.CompileTheWorld jars/* - * @run main JarDirTest check ctw.log + * @run driver ClassFileInstaller sun.hotspot.WhiteBox Foo Bar + * sun.hotspot.WhiteBox$WhiteBoxPermission + * @run driver JarDirTest prepare + * @run driver JarDirTest compile jars/* + * @run driver JarDirTest check * @summary testing of CompileTheWorld :: jars in directory * @author igor.ignatyev@oracle.com */ diff --git a/hotspot/test/testlibrary_tests/ctw/JarsTest.java b/hotspot/test/testlibrary_tests/ctw/JarsTest.java index 16af1639854..d0d40d49c4d 100644 --- a/hotspot/test/testlibrary_tests/ctw/JarsTest.java +++ b/hotspot/test/testlibrary_tests/ctw/JarsTest.java @@ -32,11 +32,11 @@ * java.management * jdk.jvmstat/sun.jvmstat.monitor * @build sun.hotspot.WhiteBox Foo Bar - * @run main ClassFileInstaller sun.hotspot.WhiteBox Foo Bar - * sun.hotspot.WhiteBox$WhiteBoxPermission - * @run main JarsTest prepare - * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Dsun.hotspot.tools.ctw.logfile=ctw.log sun.hotspot.tools.ctw.CompileTheWorld foo.jar bar.jar - * @run main JarsTest check ctw.log + * @run driver ClassFileInstaller sun.hotspot.WhiteBox Foo Bar + * sun.hotspot.WhiteBox$WhiteBoxPermission + * @run driver JarsTest prepare + * @run driver JarsTest compile foo.jar bar.jar + * @run driver JarsTest check * @summary testing of CompileTheWorld :: jars * @author igor.ignatyev@oracle.com */ From 0f853d0c9477759e84d2a1d9a48f7a5d9f0f4372 Mon Sep 17 00:00:00 2001 From: Rahul Raghavan Date: Mon, 2 Jan 2017 00:26:40 -0800 Subject: [PATCH 010/157] 8156762: test/compiler/ciReplay/TestVMNoCompLevel.java fails with - 'Unexpected exit code for negative case: [-client]: expected 0 to not equal 0' Corrected CLIENT_VM_AVAILABLE case Reviewed-by: dpochepk, zmajo --- hotspot/test/compiler/ciReplay/TestVMNoCompLevel.java | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/hotspot/test/compiler/ciReplay/TestVMNoCompLevel.java b/hotspot/test/compiler/ciReplay/TestVMNoCompLevel.java index a7c195a64b1..97b74c7c87c 100644 --- a/hotspot/test/compiler/ciReplay/TestVMNoCompLevel.java +++ b/hotspot/test/compiler/ciReplay/TestVMNoCompLevel.java @@ -65,7 +65,11 @@ public class TestVMNoCompLevel extends CiReplayBase { throw new Error("Failed to read/write replay data: " + ioe, ioe); } if (CLIENT_VM_AVAILABLE) { - negativeTest(CLIENT_VM_OPTION); + if (SERVER_VM_AVAILABLE) { + negativeTest(CLIENT_VM_OPTION); + } else { + positiveTest(CLIENT_VM_OPTION); + } } if (SERVER_VM_AVAILABLE) { positiveTest(TIERED_DISABLED_VM_OPTION, SERVER_VM_OPTION); From 4559d9da014aa84bc3589f33a41a42f88f9e943f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rickard=20B=C3=A4ckman?= Date: Tue, 3 Jan 2017 08:54:29 +0100 Subject: [PATCH 011/157] 8171082: [AOT] AOT'd SystemModules.modules() fails to load when too large Reviewed-by: kvn, redestad --- hotspot/src/share/vm/aot/aotCodeHeap.cpp | 2 ++ hotspot/src/share/vm/jvmci/jvmciCodeInstaller.cpp | 8 ++++---- hotspot/src/share/vm/jvmci/jvmciCodeInstaller.hpp | 2 +- 3 files changed, 7 insertions(+), 5 deletions(-) diff --git a/hotspot/src/share/vm/aot/aotCodeHeap.cpp b/hotspot/src/share/vm/aot/aotCodeHeap.cpp index 3d0a22255da..f473cc3e4fd 100644 --- a/hotspot/src/share/vm/aot/aotCodeHeap.cpp +++ b/hotspot/src/share/vm/aot/aotCodeHeap.cpp @@ -295,6 +295,8 @@ void AOTCodeHeap::publish_aot(const methodHandle& mh, AOTMethodData* method_data // When the AOT compiler compiles something big we fail to generate metadata // in CodeInstaller::gather_metadata. In that case the scopes_pcs_begin == scopes_pcs_end. // In all successful cases we always have 2 entries of scope pcs. + log_info(aot, class, resolve)("Failed to load %s (no metadata available)", mh->name_and_sig_as_C_string()); + _code_to_aot[code_id]._state = invalid; return; } diff --git a/hotspot/src/share/vm/jvmci/jvmciCodeInstaller.cpp b/hotspot/src/share/vm/jvmci/jvmciCodeInstaller.cpp index 745fb5199ec..9e686ec1568 100644 --- a/hotspot/src/share/vm/jvmci/jvmciCodeInstaller.cpp +++ b/hotspot/src/share/vm/jvmci/jvmciCodeInstaller.cpp @@ -554,7 +554,7 @@ JVMCIEnv::CodeInstallResult CodeInstaller::gather_metadata(Handle target, Handle _constants = buffer.consts(); initialize_fields(target(), JNIHandles::resolve(compiled_code_obj), CHECK_OK); - JVMCIEnv::CodeInstallResult result = initialize_buffer(buffer, CHECK_OK); + JVMCIEnv::CodeInstallResult result = initialize_buffer(buffer, false, CHECK_OK); if (result != JVMCIEnv::ok) { return result; } @@ -587,7 +587,7 @@ JVMCIEnv::CodeInstallResult CodeInstaller::install(JVMCICompiler* compiler, Hand _constants = buffer.consts(); initialize_fields(target(), JNIHandles::resolve(compiled_code_obj), CHECK_OK); - JVMCIEnv::CodeInstallResult result = initialize_buffer(buffer, CHECK_OK); + JVMCIEnv::CodeInstallResult result = initialize_buffer(buffer, true, CHECK_OK); if (result != JVMCIEnv::ok) { return result; } @@ -726,7 +726,7 @@ int CodeInstaller::estimate_stubs_size(TRAPS) { } // perform data and call relocation on the CodeBuffer -JVMCIEnv::CodeInstallResult CodeInstaller::initialize_buffer(CodeBuffer& buffer, TRAPS) { +JVMCIEnv::CodeInstallResult CodeInstaller::initialize_buffer(CodeBuffer& buffer, bool check_size, TRAPS) { HandleMark hm; objArrayHandle sites = this->sites(); int locs_buffer_size = sites->length() * (relocInfo::length_limit + sizeof(relocInfo)); @@ -738,7 +738,7 @@ JVMCIEnv::CodeInstallResult CodeInstaller::initialize_buffer(CodeBuffer& buffer, int stubs_size = estimate_stubs_size(CHECK_OK); int total_size = round_to(_code_size, buffer.insts()->alignment()) + round_to(_constants_size, buffer.consts()->alignment()) + round_to(stubs_size, buffer.stubs()->alignment()); - if (total_size > JVMCINMethodSizeLimit) { + if (check_size && total_size > JVMCINMethodSizeLimit) { return JVMCIEnv::code_too_large; } diff --git a/hotspot/src/share/vm/jvmci/jvmciCodeInstaller.hpp b/hotspot/src/share/vm/jvmci/jvmciCodeInstaller.hpp index 775a8c19f40..e3b38c0688d 100644 --- a/hotspot/src/share/vm/jvmci/jvmciCodeInstaller.hpp +++ b/hotspot/src/share/vm/jvmci/jvmciCodeInstaller.hpp @@ -227,7 +227,7 @@ protected: int estimate_stubs_size(TRAPS); // perform data and call relocation on the CodeBuffer - JVMCIEnv::CodeInstallResult initialize_buffer(CodeBuffer& buffer, TRAPS); + JVMCIEnv::CodeInstallResult initialize_buffer(CodeBuffer& buffer, bool check_size, TRAPS); void assumption_NoFinalizableSubclass(Handle assumption); void assumption_ConcreteSubtype(Handle assumption); From b07b96aa7cd33b09d542c9bf7ef56ff43c25f6af Mon Sep 17 00:00:00 2001 From: Marcus Larsson Date: Tue, 3 Jan 2017 12:24:52 +0100 Subject: [PATCH 012/157] 8170855: Example for -Xlog:help do not contain one with multiple tags Reviewed-by: dholmes --- hotspot/src/share/vm/logging/logConfiguration.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/hotspot/src/share/vm/logging/logConfiguration.cpp b/hotspot/src/share/vm/logging/logConfiguration.cpp index b8a5932ba0e..e01daf7dd00 100644 --- a/hotspot/src/share/vm/logging/logConfiguration.cpp +++ b/hotspot/src/share/vm/logging/logConfiguration.cpp @@ -514,6 +514,14 @@ void LogConfiguration::print_command_line_help(FILE* out) { " -Xlog:gc\n" "\t Log messages tagged with 'gc' tag using 'info' level to stdout, with default decorations.\n\n" + " -Xlog:gc,safepoint\n" + "\t Log messages tagged either with 'gc' or 'safepoint' tags, both using 'info' level, to stdout, with default decorations.\n" + "\t (Messages tagged with both 'gc' and 'safepoint' will not be logged.)\n\n" + + " -Xlog:gc+ref=debug\n" + "\t Log messages tagged with both 'gc' and 'ref' tags, using 'debug' level, to stdout, with default decorations.\n" + "\t (Messages tagged only with one of the two tags will not be logged.)\n\n" + " -Xlog:gc=debug:file=gc.txt:none\n" "\t Log messages tagged with 'gc' tag using 'debug' level to file 'gc.txt' with no decorations.\n\n" From 6688dfcb492d42557368eb0bb5c1e50b553bbc43 Mon Sep 17 00:00:00 2001 From: Marcus Larsson Date: Tue, 3 Jan 2017 12:25:19 +0100 Subject: [PATCH 013/157] 8170857: Typo in -Xlog:help output Reviewed-by: dholmes --- hotspot/src/share/vm/logging/logConfiguration.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hotspot/src/share/vm/logging/logConfiguration.cpp b/hotspot/src/share/vm/logging/logConfiguration.cpp index e01daf7dd00..9b77b220e70 100644 --- a/hotspot/src/share/vm/logging/logConfiguration.cpp +++ b/hotspot/src/share/vm/logging/logConfiguration.cpp @@ -478,7 +478,7 @@ void LogConfiguration::describe(outputStream* out) { void LogConfiguration::print_command_line_help(FILE* out) { jio_fprintf(out, "-Xlog Usage: -Xlog[:[what][:[output][:[decorators][:output-options]]]]\n" - "\t where 'what' is a combination of tags and levels on the form tag1[+tag2...][*][=level][,...]\n" + "\t where 'what' is a combination of tags and levels of the form tag1[+tag2...][*][=level][,...]\n" "\t Unless wildcard (*) is specified, only log messages tagged with exactly the tags specified will be matched.\n\n"); jio_fprintf(out, "Available log levels:\n"); From 3965a72bb30774b645c8047e178981883e78e550 Mon Sep 17 00:00:00 2001 From: Martin Doerr Date: Tue, 3 Jan 2017 11:22:37 +0100 Subject: [PATCH 014/157] 8172145: C2: anti dependence missed because store hidden by membar Reviewed-by: kvn --- hotspot/src/share/vm/adlc/formssel.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/hotspot/src/share/vm/adlc/formssel.cpp b/hotspot/src/share/vm/adlc/formssel.cpp index d9e8726bb58..3bc1fa6aec8 100644 --- a/hotspot/src/share/vm/adlc/formssel.cpp +++ b/hotspot/src/share/vm/adlc/formssel.cpp @@ -650,6 +650,7 @@ bool InstructForm::is_wide_memory_kill(FormDict &globals) const { if( strcmp(_matrule->_opType,"MemBarReleaseLock") == 0 ) return true; if( strcmp(_matrule->_opType,"MemBarAcquireLock") == 0 ) return true; if( strcmp(_matrule->_opType,"MemBarStoreStore") == 0 ) return true; + if( strcmp(_matrule->_opType,"MemBarVolatile") == 0 ) return true; if( strcmp(_matrule->_opType,"StoreFence") == 0 ) return true; if( strcmp(_matrule->_opType,"LoadFence") == 0 ) return true; From 0d99993d6e953e15e3c054794d97d19c4256ea36 Mon Sep 17 00:00:00 2001 From: Goetz Lindenmaier Date: Tue, 27 Dec 2016 16:10:59 +0100 Subject: [PATCH 015/157] 8172049: [s390] Implement "JEP 270: Reserved Stack Areas for Critical Sections" Reviewed-by: mdoerr --- .../src/cpu/s390/vm/c1_LIRAssembler_s390.cpp | 12 ++-- .../cpu/s390/vm/globalDefinitions_s390.hpp | 2 + hotspot/src/cpu/s390/vm/globals_s390.hpp | 2 +- hotspot/src/cpu/s390/vm/interp_masm_s390.cpp | 25 ++++++++- .../src/cpu/s390/vm/macroAssembler_s390.cpp | 26 +++++++++ .../src/cpu/s390/vm/macroAssembler_s390.hpp | 5 ++ hotspot/src/cpu/s390/vm/s390.ad | 20 +++---- .../src/cpu/s390/vm/stubGenerator_s390.cpp | 7 +-- .../vm/templateInterpreterGenerator_s390.cpp | 21 ++++--- .../os_cpu/linux_s390/vm/os_linux_s390.cpp | 56 ++++++++++++++++++- .../ReservedStack/ReservedStackTest.java | 3 +- 11 files changed, 148 insertions(+), 31 deletions(-) diff --git a/hotspot/src/cpu/s390/vm/c1_LIRAssembler_s390.cpp b/hotspot/src/cpu/s390/vm/c1_LIRAssembler_s390.cpp index 524a91fe07f..84fb4205099 100644 --- a/hotspot/src/cpu/s390/vm/c1_LIRAssembler_s390.cpp +++ b/hotspot/src/cpu/s390/vm/c1_LIRAssembler_s390.cpp @@ -1105,16 +1105,16 @@ void LIR_Assembler::reg2mem(LIR_Opr from, LIR_Opr dest_opr, BasicType type, } case T_FLOAT : if (short_disp) { - __ z_ste(from->as_float_reg(), disp_value, disp_reg, dest); + __ z_ste(from->as_float_reg(), disp_value, disp_reg, dest); } else { - __ z_stey(from->as_float_reg(), disp_value, disp_reg, dest); + __ z_stey(from->as_float_reg(), disp_value, disp_reg, dest); } break; case T_DOUBLE: if (short_disp) { - __ z_std(from->as_double_reg(), disp_value, disp_reg, dest); + __ z_std(from->as_double_reg(), disp_value, disp_reg, dest); } else { - __ z_stdy(from->as_double_reg(), disp_value, disp_reg, dest); + __ z_stdy(from->as_double_reg(), disp_value, disp_reg, dest); } break; default: ShouldNotReachHere(); @@ -1148,6 +1148,10 @@ void LIR_Assembler::return_op(LIR_Opr result) { __ restore_return_pc(); } + if (StackReservedPages > 0 && compilation()->has_reserved_stack_access()) { + __ reserved_stack_check(Z_R14); + } + // We need to mark the code position where the load from the safepoint // polling page was emitted as relocInfo::poll_return_type here. __ relocate(relocInfo::poll_return_type); diff --git a/hotspot/src/cpu/s390/vm/globalDefinitions_s390.hpp b/hotspot/src/cpu/s390/vm/globalDefinitions_s390.hpp index 83261cfdf47..63a9cb5abef 100644 --- a/hotspot/src/cpu/s390/vm/globalDefinitions_s390.hpp +++ b/hotspot/src/cpu/s390/vm/globalDefinitions_s390.hpp @@ -52,4 +52,6 @@ const bool CCallingConventionRequiresIntsAsLongs = true; // The expected size in bytes of a cache line, used to pad data structures. #define DEFAULT_CACHE_LINE_SIZE 256 +#define SUPPORT_RESERVED_STACK_AREA + #endif // CPU_S390_VM_GLOBALDEFINITIONS_S390_HPP diff --git a/hotspot/src/cpu/s390/vm/globals_s390.hpp b/hotspot/src/cpu/s390/vm/globals_s390.hpp index fcd3ff45227..cb5adff3ef5 100644 --- a/hotspot/src/cpu/s390/vm/globals_s390.hpp +++ b/hotspot/src/cpu/s390/vm/globals_s390.hpp @@ -56,7 +56,7 @@ define_pd_global(intx, InlineSmallCode, 2000); // Java_java_net_SocketOutputStream_socketWrite0() uses a 64k buffer on the // stack. To pass stack overflow tests we need 20 shadow pages. #define DEFAULT_STACK_SHADOW_PAGES (20 DEBUG_ONLY(+2)) -#define DEFAULT_STACK_RESERVED_PAGES (0) +#define DEFAULT_STACK_RESERVED_PAGES (1) #define MIN_STACK_YELLOW_PAGES DEFAULT_STACK_YELLOW_PAGES #define MIN_STACK_RED_PAGES DEFAULT_STACK_RED_PAGES diff --git a/hotspot/src/cpu/s390/vm/interp_masm_s390.cpp b/hotspot/src/cpu/s390/vm/interp_masm_s390.cpp index c53fa419a27..8cec2da25ac 100644 --- a/hotspot/src/cpu/s390/vm/interp_masm_s390.cpp +++ b/hotspot/src/cpu/s390/vm/interp_masm_s390.cpp @@ -860,16 +860,39 @@ void InterpreterMacroAssembler::remove_activation(TosState state, bool throw_monitor_exception, bool install_monitor_exception, bool notify_jvmti) { - + BLOCK_COMMENT("remove_activation {"); unlock_if_synchronized_method(state, throw_monitor_exception, install_monitor_exception); // Save result (push state before jvmti call and pop it afterwards) and notify jvmti. notify_method_exit(false, state, notify_jvmti ? NotifyJVMTI : SkipNotifyJVMTI); + if (StackReservedPages > 0) { + BLOCK_COMMENT("reserved_stack_check:"); + // Test if reserved zone needs to be enabled. + Label no_reserved_zone_enabling; + + // Compare frame pointers. There is no good stack pointer, as with stack + // frame compression we can get different SPs when we do calls. A subsequent + // call could have a smaller SP, so that this compare succeeds for an + // inner call of the method annotated with ReservedStack. + z_lg(Z_R0, Address(Z_SP, (intptr_t)_z_abi(callers_sp))); + z_clg(Z_R0, Address(Z_thread, JavaThread::reserved_stack_activation_offset())); // Compare with frame pointer in memory. + z_brl(no_reserved_zone_enabling); + + // Enable reserved zone again, throw stack overflow exception. + call_VM_leaf(CAST_FROM_FN_PTR(address, SharedRuntime::enable_stack_reserved_zone), Z_thread); + call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::throw_delayed_StackOverflowError)); + + should_not_reach_here(); + + bind(no_reserved_zone_enabling); + } + verify_oop(Z_tos, state); verify_thread(); pop_interpreter_frame(return_pc, Z_ARG2, Z_ARG3); + BLOCK_COMMENT("} remove_activation"); } // lock object diff --git a/hotspot/src/cpu/s390/vm/macroAssembler_s390.cpp b/hotspot/src/cpu/s390/vm/macroAssembler_s390.cpp index a7cbd706255..0f78e5a6250 100644 --- a/hotspot/src/cpu/s390/vm/macroAssembler_s390.cpp +++ b/hotspot/src/cpu/s390/vm/macroAssembler_s390.cpp @@ -2666,6 +2666,32 @@ void MacroAssembler::bang_stack_with_offset(int offset) { } } +void MacroAssembler::reserved_stack_check(Register return_pc) { + // Test if reserved zone needs to be enabled. + Label no_reserved_zone_enabling; + assert(return_pc == Z_R14, "Return pc must be in R14 before z_br() to StackOverflow stub."); + BLOCK_COMMENT("reserved_stack_check {"); + + z_clg(Z_SP, Address(Z_thread, JavaThread::reserved_stack_activation_offset())); + z_brl(no_reserved_zone_enabling); + + // Enable reserved zone again, throw stack overflow exception. + save_return_pc(); + push_frame_abi160(0); + call_VM_leaf(CAST_FROM_FN_PTR(address, SharedRuntime::enable_stack_reserved_zone), Z_thread); + pop_frame(); + restore_return_pc(); + + load_const_optimized(Z_R1, StubRoutines::throw_delayed_StackOverflowError_entry()); + // Don't use call() or z_basr(), they will invalidate Z_R14 which contains the return pc. + z_br(Z_R1); + + should_not_reach_here(); + + bind(no_reserved_zone_enabling); + BLOCK_COMMENT("} reserved_stack_check"); +} + // Defines obj, preserves var_size_in_bytes, okay for t2 == var_size_in_bytes. void MacroAssembler::tlab_allocate(Register obj, Register var_size_in_bytes, diff --git a/hotspot/src/cpu/s390/vm/macroAssembler_s390.hpp b/hotspot/src/cpu/s390/vm/macroAssembler_s390.hpp index c9540860958..588bde6207e 100644 --- a/hotspot/src/cpu/s390/vm/macroAssembler_s390.hpp +++ b/hotspot/src/cpu/s390/vm/macroAssembler_s390.hpp @@ -627,6 +627,11 @@ class MacroAssembler: public Assembler { // Stack overflow checking void bang_stack_with_offset(int offset); + // Check for reserved stack access in method being exited. If the reserved + // stack area was accessed, protect it again and throw StackOverflowError. + // Uses Z_R1. + void reserved_stack_check(Register return_pc); + // Atomics // -- none? diff --git a/hotspot/src/cpu/s390/vm/s390.ad b/hotspot/src/cpu/s390/vm/s390.ad index 8ab6a5026d3..fd188525c46 100644 --- a/hotspot/src/cpu/s390/vm/s390.ad +++ b/hotspot/src/cpu/s390/vm/s390.ad @@ -909,15 +909,8 @@ void MachEpilogNode::emit(CodeBuffer &cbuf, PhaseRegAlloc *ra_) const { // If this does safepoint polling, then do it here. bool need_polling = do_polling() && C->is_method_compilation(); - // Touch the polling page. - // Part 1: get the page's address. - if (need_polling) { - AddressLiteral pp(os::get_polling_page()); - __ load_const_optimized(Z_R1_scratch, pp); - } - // Pop frame, restore return_pc, and all stuff needed by interpreter. - // Pop frame by add insted of load (a penny saved is a penny got :-). + // Pop frame by add instead of load (a penny saved is a penny got :-). int frame_size_in_bytes = Assembler::align((C->frame_slots() << LogBytesPerInt), frame::alignment_in_bytes); int retPC_offset = frame_size_in_bytes + _z_abi16(return_pc); if (Displacement::is_validDisp(retPC_offset)) { @@ -928,9 +921,14 @@ void MachEpilogNode::emit(CodeBuffer &cbuf, PhaseRegAlloc *ra_) const { __ restore_return_pc(); } - // Touch the polling page, - // part 2: touch the page now. + if (StackReservedPages > 0 && C->has_reserved_stack_access()) { + __ reserved_stack_check(Z_R14); + } + + // Touch the polling page. if (need_polling) { + AddressLiteral pp(os::get_polling_page()); + __ load_const_optimized(Z_R1_scratch, pp); // We need to mark the code position where the load from the safepoint // polling page was emitted as relocInfo::poll_return_type here. __ relocate(relocInfo::poll_return_type); @@ -939,7 +937,7 @@ void MachEpilogNode::emit(CodeBuffer &cbuf, PhaseRegAlloc *ra_) const { } uint MachEpilogNode::size(PhaseRegAlloc *ra_) const { - // variable size. determine dynamically. + // Variable size. determine dynamically. return MachNode::size(ra_); } diff --git a/hotspot/src/cpu/s390/vm/stubGenerator_s390.cpp b/hotspot/src/cpu/s390/vm/stubGenerator_s390.cpp index 8b872c5c922..be107222636 100644 --- a/hotspot/src/cpu/s390/vm/stubGenerator_s390.cpp +++ b/hotspot/src/cpu/s390/vm/stubGenerator_s390.cpp @@ -2433,13 +2433,12 @@ class StubGenerator: public StubCodeGenerator { StubRoutines::_throw_StackOverflowError_entry = generate_throw_exception("StackOverflowError throw_exception", CAST_FROM_FN_PTR(address, SharedRuntime::throw_StackOverflowError), false); + StubRoutines::_throw_delayed_StackOverflowError_entry = + generate_throw_exception("delayed StackOverflowError throw_exception", + CAST_FROM_FN_PTR(address, SharedRuntime::throw_delayed_StackOverflowError), false); //---------------------------------------------------------------------- // Entry points that are platform specific. - // Build this early so it's available for the interpreter. - StubRoutines::_throw_StackOverflowError_entry = - generate_throw_exception("StackOverflowError throw_exception", - CAST_FROM_FN_PTR(address, SharedRuntime::throw_StackOverflowError), false); if (UseCRC32Intrinsics) { // We have no CRC32 table on z/Architecture. diff --git a/hotspot/src/cpu/s390/vm/templateInterpreterGenerator_s390.cpp b/hotspot/src/cpu/s390/vm/templateInterpreterGenerator_s390.cpp index de266db04fc..2084f36006f 100644 --- a/hotspot/src/cpu/s390/vm/templateInterpreterGenerator_s390.cpp +++ b/hotspot/src/cpu/s390/vm/templateInterpreterGenerator_s390.cpp @@ -1112,16 +1112,21 @@ void TemplateInterpreterGenerator::generate_fixed_frame(bool native_call) { // top_frame_size = TOP_IJAVA_FRAME_ABI + max_stack + size of interpreter state __ add2reg(top_frame_size, frame::z_top_ijava_frame_abi_size + - frame::z_ijava_state_size + - frame::interpreter_frame_monitor_size() * wordSize, + frame::z_ijava_state_size + + frame::interpreter_frame_monitor_size() * wordSize, max_stack); - // Check if there's room for the new frame... - Register frame_size = max_stack; // Reuse the regiser for max_stack. - __ z_lgr(frame_size, Z_SP); - __ z_sgr(frame_size, sp_after_resize); - __ z_agr(frame_size, top_frame_size); - generate_stack_overflow_check(frame_size, fp/*tmp1*/); + if (!native_call) { + // Stack overflow check. + // Native calls don't need the stack size check since they have no + // expression stack and the arguments are already on the stack and + // we only add a handful of words to the stack. + Register frame_size = max_stack; // Reuse the regiser for max_stack. + __ z_lgr(frame_size, Z_SP); + __ z_sgr(frame_size, sp_after_resize); + __ z_agr(frame_size, top_frame_size); + generate_stack_overflow_check(frame_size, fp/*tmp1*/); + } DEBUG_ONLY(__ z_cg(Z_R14, _z_abi16(return_pc), Z_SP)); __ asm_assert_eq("killed Z_R14", 0); diff --git a/hotspot/src/os_cpu/linux_s390/vm/os_linux_s390.cpp b/hotspot/src/os_cpu/linux_s390/vm/os_linux_s390.cpp index 684853cfd34..e9120a8b696 100644 --- a/hotspot/src/os_cpu/linux_s390/vm/os_linux_s390.cpp +++ b/hotspot/src/os_cpu/linux_s390/vm/os_linux_s390.cpp @@ -144,6 +144,42 @@ frame os::fetch_frame_from_context(const void* ucVoid) { return frame(sp, epc.pc()); } +bool os::Linux::get_frame_at_stack_banging_point(JavaThread* thread, ucontext_t* uc, frame* fr) { + address pc = (address) os::Linux::ucontext_get_pc(uc); + if (Interpreter::contains(pc)) { + // Interpreter performs stack banging after the fixed frame header has + // been generated while the compilers perform it before. To maintain + // semantic consistency between interpreted and compiled frames, the + // method returns the Java sender of the current frame. + *fr = os::fetch_frame_from_context(uc); + if (!fr->is_first_java_frame()) { + assert(fr->safe_for_sender(thread), "Safety check"); + *fr = fr->java_sender(); + } + } else { + // More complex code with compiled code. + assert(!Interpreter::contains(pc), "Interpreted methods should have been handled above"); + CodeBlob* cb = CodeCache::find_blob(pc); + if (cb == NULL || !cb->is_nmethod() || cb->is_frame_complete_at(pc)) { + // Not sure where the pc points to, fallback to default + // stack overflow handling. In compiled code, we bang before + // the frame is complete. + return false; + } else { + intptr_t* fp = os::Linux::ucontext_get_fp(uc); + intptr_t* sp = os::Linux::ucontext_get_sp(uc); + *fr = frame(sp, (address)*sp); + if (!fr->is_java_frame()) { + assert(fr->safe_for_sender(thread), "Safety check"); + assert(!fr->is_first_frame(), "Safety check"); + *fr = fr->java_sender(); + } + } + } + assert(fr->is_java_frame(), "Safety check"); + return true; +} + frame os::get_sender_for_C_frame(frame* fr) { if (*fr->sp() == 0) { // fr is the last C frame. @@ -279,13 +315,31 @@ JVM_handle_linux_signal(int sig, if (thread->on_local_stack(addr)) { // stack overflow if (thread->in_stack_yellow_reserved_zone(addr)) { - thread->disable_stack_yellow_reserved_zone(); if (thread->thread_state() == _thread_in_Java) { + if (thread->in_stack_reserved_zone(addr)) { + frame fr; + if (os::Linux::get_frame_at_stack_banging_point(thread, uc, &fr)) { + assert(fr.is_java_frame(), "Must be a Javac frame"); + frame activation = + SharedRuntime::look_for_reserved_stack_annotated_method(thread, fr); + if (activation.sp() != NULL) { + thread->disable_stack_reserved_zone(); + if (activation.is_interpreted_frame()) { + thread->set_reserved_stack_activation((address)activation.fp()); + } else { + thread->set_reserved_stack_activation((address)activation.unextended_sp()); + } + return 1; + } + } + } // Throw a stack overflow exception. // Guard pages will be reenabled while unwinding the stack. + thread->disable_stack_yellow_reserved_zone(); stub = SharedRuntime::continuation_for_implicit_exception(thread, pc, SharedRuntime::STACK_OVERFLOW); } else { // Thread was in the vm or native code. Return and try to finish. + thread->disable_stack_yellow_reserved_zone(); return 1; } } else if (thread->in_stack_red_zone(addr)) { diff --git a/hotspot/test/runtime/ReservedStack/ReservedStackTest.java b/hotspot/test/runtime/ReservedStack/ReservedStackTest.java index 6a095155349..216f731d2b7 100644 --- a/hotspot/test/runtime/ReservedStack/ReservedStackTest.java +++ b/hotspot/test/runtime/ReservedStack/ReservedStackTest.java @@ -199,7 +199,8 @@ public class ReservedStackTest { // corruptions are still possible. boolean supportedPlatform = Platform.isAix() || - (Platform.isLinux() && (Platform.isPPC() || Platform.isX64() || Platform.isX86())) || + (Platform.isLinux() && + (Platform.isPPC() || Platform.isS390x() || Platform.isX64() || Platform.isX86())) || Platform.isOSX() || Platform.isSolaris(); if (supportedPlatform && !result.contains("PASSED")) { From 2e0248d2fc08e937cfd2d9c58e5aeb5148dc9302 Mon Sep 17 00:00:00 2001 From: Martin Doerr Date: Tue, 3 Jan 2017 17:17:14 +0100 Subject: [PATCH 016/157] 8172199: s390: Use same get_key_start_from_aescrypt_object implementation as PPC64 Reviewed-by: kvn --- hotspot/src/share/vm/opto/library_call.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hotspot/src/share/vm/opto/library_call.cpp b/hotspot/src/share/vm/opto/library_call.cpp index c298e318ab5..5d837d6ecb0 100644 --- a/hotspot/src/share/vm/opto/library_call.cpp +++ b/hotspot/src/share/vm/opto/library_call.cpp @@ -6335,7 +6335,7 @@ bool LibraryCallKit::inline_counterMode_AESCrypt(vmIntrinsics::ID id) { //------------------------------get_key_start_from_aescrypt_object----------------------- Node * LibraryCallKit::get_key_start_from_aescrypt_object(Node *aescrypt_object) { -#ifdef PPC64 +#if defined(PPC64) || defined(S390) // MixColumns for decryption can be reduced by preprocessing MixColumns with round keys. // Intel's extention is based on this optimization and AESCrypt generates round keys by preprocessing MixColumns. // However, ppc64 vncipher processes MixColumns and requires the same round keys with encryption. From 450472a24a3a1a590c73bae03986318ea1cad67e Mon Sep 17 00:00:00 2001 From: Claes Redestad Date: Tue, 3 Jan 2017 21:36:05 +0100 Subject: [PATCH 017/157] 8172169: Re-examine String field optionality Reviewed-by: kvn, thartmann --- .../src/share/vm/classfile/javaClasses.cpp | 12 ++++------ .../src/share/vm/classfile/javaClasses.hpp | 9 -------- .../share/vm/classfile/javaClasses.inline.hpp | 18 +++++---------- hotspot/src/share/vm/opto/graphKit.cpp | 22 ++++++++----------- 4 files changed, 19 insertions(+), 42 deletions(-) diff --git a/hotspot/src/share/vm/classfile/javaClasses.cpp b/hotspot/src/share/vm/classfile/javaClasses.cpp index 91b51404489..b7fe590eee1 100644 --- a/hotspot/src/share/vm/classfile/javaClasses.cpp +++ b/hotspot/src/share/vm/classfile/javaClasses.cpp @@ -163,8 +163,8 @@ void java_lang_String::compute_offsets() { Klass* k = SystemDictionary::String_klass(); compute_offset(value_offset, k, vmSymbols::value_name(), vmSymbols::byte_array_signature()); - compute_optional_offset(hash_offset, k, vmSymbols::hash_name(), vmSymbols::int_signature()); - compute_optional_offset(coder_offset, k, vmSymbols::coder_name(), vmSymbols::byte_signature()); + compute_offset(hash_offset, k, vmSymbols::hash_name(), vmSymbols::int_signature()); + compute_offset(coder_offset, k, vmSymbols::coder_name(), vmSymbols::byte_signature()); initialized = true; } @@ -3977,12 +3977,8 @@ void JavaClasses::check_offsets() { // java.lang.String CHECK_OFFSET("java/lang/String", java_lang_String, value, "[B"); - if (java_lang_String::has_hash_field()) { - CHECK_OFFSET("java/lang/String", java_lang_String, hash, "I"); - } - if (java_lang_String::has_coder_field()) { - CHECK_OFFSET("java/lang/String", java_lang_String, coder, "B"); - } + CHECK_OFFSET("java/lang/String", java_lang_String, hash, "I"); + CHECK_OFFSET("java/lang/String", java_lang_String, coder, "B"); // java.lang.Class diff --git a/hotspot/src/share/vm/classfile/javaClasses.hpp b/hotspot/src/share/vm/classfile/javaClasses.hpp index 0cf0090e851..f05db4c79b7 100644 --- a/hotspot/src/share/vm/classfile/javaClasses.hpp +++ b/hotspot/src/share/vm/classfile/javaClasses.hpp @@ -81,15 +81,6 @@ class java_lang_String : AllStatic { static Handle create_from_platform_dependent_str(const char* str, TRAPS); static Handle char_converter(Handle java_string, jchar from_char, jchar to_char, TRAPS); - static bool has_hash_field() { - assert(initialized, "Must be initialized"); - return (hash_offset > 0); - } - static bool has_coder_field() { - assert(initialized, "Must be initialized"); - return (coder_offset > 0); - } - static void set_compact_strings(bool value); static int value_offset_in_bytes() { diff --git a/hotspot/src/share/vm/classfile/javaClasses.inline.hpp b/hotspot/src/share/vm/classfile/javaClasses.inline.hpp index b1c4a3f9224..b388bb157d3 100644 --- a/hotspot/src/share/vm/classfile/javaClasses.inline.hpp +++ b/hotspot/src/share/vm/classfile/javaClasses.inline.hpp @@ -30,10 +30,8 @@ #include "oops/oopsHierarchy.hpp" void java_lang_String::set_coder(oop string, jbyte coder) { - assert(initialized, "Must be initialized"); - if (coder_offset > 0) { - string->byte_field_put(coder_offset, coder); - } + assert(initialized && (coder_offset > 0), "Must be initialized"); + string->byte_field_put(coder_offset, coder); } void java_lang_String::set_value_raw(oop string, typeArrayOop buffer) { @@ -61,15 +59,11 @@ unsigned int java_lang_String::hash(oop java_string) { return java_string->int_field(hash_offset); } bool java_lang_String::is_latin1(oop java_string) { - assert(initialized, "Must be initialized"); + assert(initialized && (coder_offset > 0), "Must be initialized"); assert(is_instance(java_string), "must be java_string"); - if (coder_offset > 0) { - jbyte coder = java_string->byte_field(coder_offset); - assert(CompactStrings || coder == CODER_UTF16, "Must be UTF16 without CompactStrings"); - return coder == CODER_LATIN1; - } else { - return false; - } + jbyte coder = java_string->byte_field(coder_offset); + assert(CompactStrings || coder == CODER_UTF16, "Must be UTF16 without CompactStrings"); + return coder == CODER_LATIN1; } int java_lang_String::length(oop java_string) { assert(initialized, "Must be initialized"); diff --git a/hotspot/src/share/vm/opto/graphKit.cpp b/hotspot/src/share/vm/opto/graphKit.cpp index c879137d882..8a9f81e0564 100644 --- a/hotspot/src/share/vm/opto/graphKit.cpp +++ b/hotspot/src/share/vm/opto/graphKit.cpp @@ -4348,20 +4348,16 @@ Node* GraphKit::load_String_value(Node* ctrl, Node* str) { } Node* GraphKit::load_String_coder(Node* ctrl, Node* str) { - if (java_lang_String::has_coder_field()) { - if (!CompactStrings) { - return intcon(java_lang_String::CODER_UTF16); - } - int coder_offset = java_lang_String::coder_offset_in_bytes(); - const TypeInstPtr* string_type = TypeInstPtr::make(TypePtr::NotNull, C->env()->String_klass(), - false, NULL, 0); - const TypePtr* coder_field_type = string_type->add_offset(coder_offset); - int coder_field_idx = C->get_alias_index(coder_field_type); - return make_load(ctrl, basic_plus_adr(str, str, coder_offset), - TypeInt::BYTE, T_BYTE, coder_field_idx, MemNode::unordered); - } else { - return intcon(0); // false + if (!CompactStrings) { + return intcon(java_lang_String::CODER_UTF16); } + int coder_offset = java_lang_String::coder_offset_in_bytes(); + const TypeInstPtr* string_type = TypeInstPtr::make(TypePtr::NotNull, C->env()->String_klass(), + false, NULL, 0); + const TypePtr* coder_field_type = string_type->add_offset(coder_offset); + int coder_field_idx = C->get_alias_index(coder_field_type); + return make_load(ctrl, basic_plus_adr(str, str, coder_offset), + TypeInt::BYTE, T_BYTE, coder_field_idx, MemNode::unordered); } void GraphKit::store_String_value(Node* ctrl, Node* str, Node* value) { From 631dc215187649728144650639d1adcf8fa803fc Mon Sep 17 00:00:00 2001 From: Vivek Deshpande Date: Tue, 3 Jan 2017 14:56:51 -0800 Subject: [PATCH 018/157] 8171974: Fix for R10 Register clobbering with usage of ExternalAddress Reviewed-by: kvn, rbackman --- hotspot/src/cpu/x86/vm/macroAssembler_x86.cpp | 6 +++--- hotspot/src/cpu/x86/vm/macroAssembler_x86.hpp | 2 +- .../src/cpu/x86/vm/macroAssembler_x86_sha.cpp | 17 ++++++++++++----- hotspot/src/cpu/x86/vm/stubGenerator_x86_64.cpp | 8 ++++---- 4 files changed, 20 insertions(+), 13 deletions(-) diff --git a/hotspot/src/cpu/x86/vm/macroAssembler_x86.cpp b/hotspot/src/cpu/x86/vm/macroAssembler_x86.cpp index 3d4dee751a5..b6d32631582 100644 --- a/hotspot/src/cpu/x86/vm/macroAssembler_x86.cpp +++ b/hotspot/src/cpu/x86/vm/macroAssembler_x86.cpp @@ -3499,12 +3499,12 @@ void MacroAssembler::movdqu(XMMRegister dst, XMMRegister src) { } } -void MacroAssembler::movdqu(XMMRegister dst, AddressLiteral src) { +void MacroAssembler::movdqu(XMMRegister dst, AddressLiteral src, Register scratchReg) { if (reachable(src)) { movdqu(dst, as_Address(src)); } else { - lea(rscratch1, src); - movdqu(dst, Address(rscratch1, 0)); + lea(scratchReg, src); + movdqu(dst, Address(scratchReg, 0)); } } diff --git a/hotspot/src/cpu/x86/vm/macroAssembler_x86.hpp b/hotspot/src/cpu/x86/vm/macroAssembler_x86.hpp index 02fb401511e..a3e81e58dc5 100644 --- a/hotspot/src/cpu/x86/vm/macroAssembler_x86.hpp +++ b/hotspot/src/cpu/x86/vm/macroAssembler_x86.hpp @@ -1085,7 +1085,7 @@ public: void movdqu(Address dst, XMMRegister src); void movdqu(XMMRegister dst, Address src); void movdqu(XMMRegister dst, XMMRegister src); - void movdqu(XMMRegister dst, AddressLiteral src); + void movdqu(XMMRegister dst, AddressLiteral src, Register scratchReg = rscratch1); // AVX Unaligned forms void vmovdqu(Address dst, XMMRegister src); void vmovdqu(XMMRegister dst, Address src); diff --git a/hotspot/src/cpu/x86/vm/macroAssembler_x86_sha.cpp b/hotspot/src/cpu/x86/vm/macroAssembler_x86_sha.cpp index 37d93a48f21..10935345f70 100644 --- a/hotspot/src/cpu/x86/vm/macroAssembler_x86_sha.cpp +++ b/hotspot/src/cpu/x86/vm/macroAssembler_x86_sha.cpp @@ -817,7 +817,7 @@ enum { movl(d, Address(CTX, 4*3)); movl(e, Address(CTX, 4*4)); movl(f, Address(CTX, 4*5)); - movl(g, Address(CTX, 4*6)); + // load g - r10 after it is used as scratch movl(h, Address(CTX, 4*7)); pshuffle_byte_flip_mask_addr = pshuffle_byte_flip_mask; @@ -825,6 +825,8 @@ enum { vmovdqu(SHUF_00BA, ExternalAddress(pshuffle_byte_flip_mask_addr + 32)); //[_SHUF_00BA wrt rip] vmovdqu(SHUF_DC00, ExternalAddress(pshuffle_byte_flip_mask_addr + 64)); //[_SHUF_DC00 wrt rip] + movl(g, Address(CTX, 4*6)); + movq(Address(rsp, _CTX), CTX); // store bind(loop0); @@ -977,7 +979,7 @@ bind(only_one_block); movl(d, Address(CTX, 4*3)); // 0xa54ff53a movl(e, Address(CTX, 4*4)); // 0x510e527f movl(f, Address(CTX, 4*5)); // 0x9b05688c - movl(g, Address(CTX, 4*6)); // 0x1f83d9ab + // load g - r10 after use as scratch movl(h, Address(CTX, 4*7)); // 0x5be0cd19 @@ -986,6 +988,8 @@ bind(only_one_block); vmovdqu(SHUF_00BA, ExternalAddress(pshuffle_byte_flip_mask_addr + 32)); //[_SHUF_00BA wrt rip] vmovdqu(SHUF_DC00, ExternalAddress(pshuffle_byte_flip_mask_addr + 64)); //[_SHUF_DC00 wrt rip] + movl(g, Address(CTX, 4*6)); // 0x1f83d9ab + movq(Address(rsp, _CTX), CTX); jmpb(do_last_block); @@ -1154,9 +1158,8 @@ void MacroAssembler::sha512_AVX2_one_round_and_schedule( // Move to appropriate lanes for calculating w[16] and w[17] vperm2f128(xmm4, xmm0, xmm0, 0); //xmm4 = W[-16] + W[-7] + s0{ BABA } - address MASK_YMM_LO = StubRoutines::x86::pshuffle_byte_flip_mask_addr_sha512(); //Move to appropriate lanes for calculating w[18] and w[19] - vpand(xmm0, xmm0, ExternalAddress(MASK_YMM_LO + 32), AVX_256bit); //xmm0 = W[-16] + W[-7] + s0{ DC00 } + vpand(xmm0, xmm0, xmm10, AVX_256bit); //xmm0 = W[-16] + W[-7] + s0{ DC00 } //Calculate w[16] and w[17] in both 128 bit lanes //Calculate sigma1 for w[16] and w[17] on both 128 bit lanes vperm2f128(xmm2, xmm7, xmm7, 17); //xmm2 = W[-2] {BABA} @@ -1250,6 +1253,7 @@ void MacroAssembler::sha512_AVX2(XMMRegister msg, XMMRegister state0, XMMRegiste const XMMRegister& XFER = xmm0; // YTMP0 const XMMRegister& BYTE_FLIP_MASK = xmm9; // ymm9 + const XMMRegister& YMM_MASK_LO = xmm10; // ymm10 #ifdef _WIN64 const Register& INP = rcx; //1st arg const Register& CTX = rdx; //2nd arg @@ -1368,11 +1372,14 @@ void MacroAssembler::sha512_AVX2(XMMRegister msg, XMMRegister state0, XMMRegiste movq(d, Address(CTX, 8 * 3)); movq(e, Address(CTX, 8 * 4)); movq(f, Address(CTX, 8 * 5)); - movq(g, Address(CTX, 8 * 6)); + // load g - r10 after it is used as scratch movq(h, Address(CTX, 8 * 7)); pshuffle_byte_flip_mask_addr = pshuffle_byte_flip_mask_sha512; vmovdqu(BYTE_FLIP_MASK, ExternalAddress(pshuffle_byte_flip_mask_addr + 0)); //PSHUFFLE_BYTE_FLIP_MASK wrt rip + vmovdqu(YMM_MASK_LO, ExternalAddress(pshuffle_byte_flip_mask_addr + 32)); + + movq(g, Address(CTX, 8 * 6)); bind(loop0); lea(TBL, ExternalAddress(K512_W)); diff --git a/hotspot/src/cpu/x86/vm/stubGenerator_x86_64.cpp b/hotspot/src/cpu/x86/vm/stubGenerator_x86_64.cpp index 1853cf9a42a..48be33ae526 100644 --- a/hotspot/src/cpu/x86/vm/stubGenerator_x86_64.cpp +++ b/hotspot/src/cpu/x86/vm/stubGenerator_x86_64.cpp @@ -3207,7 +3207,7 @@ class StubGenerator: public StubCodeGenerator { const Register len_reg = c_rarg4; // src len (must be multiple of blocksize 16) #else const Address len_mem(rbp, 6 * wordSize); // length is on stack on Win64 - const Register len_reg = r10; // pick the first volatile windows register + const Register len_reg = r11; // pick the volatile windows register #endif const Register pos = rax; @@ -3404,7 +3404,7 @@ class StubGenerator: public StubCodeGenerator { const Register len_reg = c_rarg4; // src len (must be multiple of blocksize 16) #else const Address len_mem(rbp, 6 * wordSize); // length is on stack on Win64 - const Register len_reg = r10; // pick the first volatile windows register + const Register len_reg = r11; // pick the volatile windows register #endif const Register pos = rax; @@ -3930,7 +3930,7 @@ class StubGenerator: public StubCodeGenerator { __ push(rbx); // Save RBX __ movdqu(xmm_curr_counter, Address(counter, 0x00)); // initialize counter with initial counter - __ movdqu(xmm_counter_shuf_mask, ExternalAddress(StubRoutines::x86::counter_shuffle_mask_addr())); + __ movdqu(xmm_counter_shuf_mask, ExternalAddress(StubRoutines::x86::counter_shuffle_mask_addr()), pos); // pos as scratch __ pshufb(xmm_curr_counter, xmm_counter_shuf_mask); //counter is shuffled __ movptr(pos, 0); @@ -3953,7 +3953,7 @@ class StubGenerator: public StubCodeGenerator { __ movl(Address(used_addr, 0), used); // key length could be only {11, 13, 15} * 4 = {44, 52, 60} - __ movdqu(xmm_key_shuf_mask, ExternalAddress(StubRoutines::x86::key_shuffle_mask_addr())); + __ movdqu(xmm_key_shuf_mask, ExternalAddress(StubRoutines::x86::key_shuffle_mask_addr()), rbx); // rbx as scratch __ movl(rbx, Address(key, arrayOopDesc::length_offset_in_bytes() - arrayOopDesc::base_offset_in_bytes(T_INT))); __ cmpl(rbx, 52); __ jcc(Assembler::equal, L_multiBlock_loopTop[1]); From 1e918ed98c115c1f14f24b109e42f603ed285df1 Mon Sep 17 00:00:00 2001 From: Christian Tornqvist Date: Wed, 4 Jan 2017 10:57:26 -0500 Subject: [PATCH 019/157] 8168137: import-hotspot build target not removed from hotspot-ide-project Reviewed-by: erikj --- hotspot/make/ide/CreateVSProject.gmk | 4 ++-- .../build/tools/projectcreator/WinGammaPlatformVC10.java | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/hotspot/make/ide/CreateVSProject.gmk b/hotspot/make/ide/CreateVSProject.gmk index d6f5324adb8..db0aca87e28 100644 --- a/hotspot/make/ide/CreateVSProject.gmk +++ b/hotspot/make/ide/CreateVSProject.gmk @@ -1,5 +1,5 @@ # -# Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2016, 2017, 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 @@ -121,7 +121,7 @@ ifeq ($(OPENJDK_TARGET_OS), windows) -buildBase $(call FixPath, $(IDE_OUTPUTDIR)/vs-output) \ -buildSpace $(call FixPath, $(IDE_OUTPUTDIR)) \ -makeBinary $(call FixPath, $(MAKE)) \ - -makeOutput $(call FixPath, $(HOTSPOT_OUTPUTDIR)/variant-%f/libjvm) \ + -makeOutput $(call FixPath, $(JDK_OUTPUTDIR)/bin/server) \ -absoluteInclude $(call FixPath, $(HOTSPOT_OUTPUTDIR)/variant-server/gensrc) \ -absoluteSrcInclude $(call FixPath, $(HOTSPOT_OUTPUTDIR)/variant-server/gensrc) \ $(EXTRACTED_DEFINES_client) \ diff --git a/hotspot/make/src/classes/build/tools/projectcreator/WinGammaPlatformVC10.java b/hotspot/make/src/classes/build/tools/projectcreator/WinGammaPlatformVC10.java index d44fb04c588..50413e52792 100644 --- a/hotspot/make/src/classes/build/tools/projectcreator/WinGammaPlatformVC10.java +++ b/hotspot/make/src/classes/build/tools/projectcreator/WinGammaPlatformVC10.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2017, 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 @@ -114,8 +114,8 @@ public class WinGammaPlatformVC10 extends WinGammaPlatform { tag(cfg, "CodeAnalysisRuleAssemblies"); } for (BuildConfig cfg : allConfigs) { - tagData(cfg, "NMakeBuildCommandLine", cfg.get("MakeBinary") + " -f ../../Makefile import-hotspot LOG=info"); - tagData(cfg, "NMakeReBuildCommandLine", cfg.get("MakeBinary") + " -f ../../Makefile clean-hotspot import-hotspot LOG=info"); + tagData(cfg, "NMakeBuildCommandLine", cfg.get("MakeBinary") + " -f ../../Makefile hotspot LOG=info"); + tagData(cfg, "NMakeReBuildCommandLine", cfg.get("MakeBinary") + " -f ../../Makefile clean-hotspot hotspot LOG=info"); tagData(cfg, "NMakeCleanCommandLine", cfg.get("MakeBinary") + " -f ../../Makefile clean-hotspot LOG=info"); tagData(cfg, "NMakeOutput", cfg.get("MakeOutput") + Util.sep + "jvm.dll"); tagData(cfg, "NMakePreprocessorDefinitions", Util.join(";", cfg.getDefines())); From b58bb4740e570ef3c95819ac0bc2e9b8ea44211e Mon Sep 17 00:00:00 2001 From: Vladimir Kozlov Date: Wed, 4 Jan 2017 11:44:26 -0800 Subject: [PATCH 020/157] 8172054: Aot tests should include Java assertions into AOT compiled code Reviewed-by: iveresov --- hotspot/src/share/vm/aot/aotCodeHeap.cpp | 2 +- hotspot/test/compiler/aot/AotCompiler.java | 1 + hotspot/test/compiler/aot/cli/jaotc/JaotcTestHelper.java | 1 + 3 files changed, 3 insertions(+), 1 deletion(-) diff --git a/hotspot/src/share/vm/aot/aotCodeHeap.cpp b/hotspot/src/share/vm/aot/aotCodeHeap.cpp index f473cc3e4fd..1cd9576253f 100644 --- a/hotspot/src/share/vm/aot/aotCodeHeap.cpp +++ b/hotspot/src/share/vm/aot/aotCodeHeap.cpp @@ -710,7 +710,7 @@ bool AOTCodeHeap::load_klass_data(instanceKlassHandle kh, Thread* thread) { } if (_lib->config()->_omitAssertions && JavaAssertions::enabled(kh->name()->as_C_string(), kh->class_loader() == NULL)) { - // Assertions are omitted in the compiled code, but are enabled right now. Bail out. + log_trace(aot, class, load)("class %s in %s does not have java assertions in compiled code, but assertions are enabled for this execution.", kh->internal_name(), _lib->name()); sweep_dependent_methods(klass_data); return false; } diff --git a/hotspot/test/compiler/aot/AotCompiler.java b/hotspot/test/compiler/aot/AotCompiler.java index 68a22468763..b9ace71767b 100644 --- a/hotspot/test/compiler/aot/AotCompiler.java +++ b/hotspot/test/compiler/aot/AotCompiler.java @@ -93,6 +93,7 @@ public class AotCompiler { } } List args = new ArrayList<>(); + args.add("--compile-with-assertions"); args.add("--output"); args.add(libName); if (file != null) { diff --git a/hotspot/test/compiler/aot/cli/jaotc/JaotcTestHelper.java b/hotspot/test/compiler/aot/cli/jaotc/JaotcTestHelper.java index 06bca2a9292..e6136ba1b98 100644 --- a/hotspot/test/compiler/aot/cli/jaotc/JaotcTestHelper.java +++ b/hotspot/test/compiler/aot/cli/jaotc/JaotcTestHelper.java @@ -44,6 +44,7 @@ public class JaotcTestHelper { for (String vmOpt : Utils.getTestJavaOpts()) { launcher.addVMArg(vmOpt); } + launcher.addToolArg("--compile-with-assertions"); for (String arg : args) { launcher.addToolArg(arg); } From 08aa21deb77b2f9589bddca40836a7960a49d9ff Mon Sep 17 00:00:00 2001 From: Coleen Phillimore Date: Wed, 4 Jan 2017 21:13:04 -0500 Subject: [PATCH 021/157] 8172246: [TESTBUG] runtime/RedefineTests/RedefinePreviousVersions.java 'Class unloading: has_previous_versions = true' missing from stdout/stderr Add boolean to gate redefinition start Reviewed-by: sspitsyn, dholmes --- .../RedefineTests/RedefinePreviousVersions.java | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/hotspot/test/runtime/RedefineTests/RedefinePreviousVersions.java b/hotspot/test/runtime/RedefineTests/RedefinePreviousVersions.java index 45555dcf4ab..dda3e872c72 100644 --- a/hotspot/test/runtime/RedefineTests/RedefinePreviousVersions.java +++ b/hotspot/test/runtime/RedefineTests/RedefinePreviousVersions.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2017, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -48,20 +48,23 @@ public class RedefinePreviousVersions { public static String newRunning = "class RedefinePreviousVersions$Running {" + " public static volatile boolean stop = true;" + + " public static volatile boolean running = true;" + " static void localSleep() { }" + " public static void infinite() { }" + "}"; static class Running { public static volatile boolean stop = false; + public static volatile boolean running = false; static void localSleep() { try{ - Thread.currentThread().sleep(10);//sleep for 10 ms + Thread.sleep(10); // sleep for 10 ms } catch(InterruptedException ie) { } } public static void infinite() { + running = true; while (!stop) { localSleep(); } } } @@ -70,8 +73,6 @@ public class RedefinePreviousVersions { if (args.length > 0) { - String jarFile = System.getProperty("test.src") + "/testcase.jar"; - // java -javaagent:redefineagent.jar -Xlog:stuff RedefinePreviousVersions ProcessBuilder pb = ProcessTools.createJavaProcessBuilder( "-javaagent:redefineagent.jar", "-Xlog:redefine+class+iklass+add=trace,redefine+class+iklass+purge=trace", @@ -100,6 +101,10 @@ public class RedefinePreviousVersions { } }.start(); + while (!Running.running) { + Thread.sleep(10); // sleep for 10 ms + } + // Since a method of newRunning is running, this class should be added to the previous_version_list // of Running, and _has_previous_versions should return true at class unloading. RedefineClassHelper.redefineClass(Running.class, newRunning); From f238905f2b2ca50a59cee5907c3f7d2f764676fb Mon Sep 17 00:00:00 2001 From: Tobias Hartmann Date: Thu, 5 Jan 2017 09:25:36 +0100 Subject: [PATCH 022/157] 8172010: [AOT] RecompilationTest.java fails with "expected compilation level after compilation to be no less than 1" Disabled probabilistic profiling to ensure recompilation of AOT compiled method. Reviewed-by: kvn, iveresov --- hotspot/test/compiler/aot/RecompilationTest.java | 1 + 1 file changed, 1 insertion(+) diff --git a/hotspot/test/compiler/aot/RecompilationTest.java b/hotspot/test/compiler/aot/RecompilationTest.java index 466c8348e7e..dda00bc28e5 100644 --- a/hotspot/test/compiler/aot/RecompilationTest.java +++ b/hotspot/test/compiler/aot/RecompilationTest.java @@ -33,6 +33,7 @@ * @run main compiler.aot.AotCompiler -libname libRecompilationTest1.so * -class compiler.whitebox.SimpleTestCaseHelper * -extraopt -Dgraal.TieredAOT=true -extraopt -Dgraal.ProfileSimpleMethods=true + * -extraopt -Dgraal.ProbabilisticProfiling=false * -extraopt -XX:+UnlockDiagnosticVMOptions -extraopt -XX:+WhiteBoxAPI -extraopt -Xbootclasspath/a:. * -extraopt -XX:-UseCompressedOops * -extraopt -XX:CompileCommand=dontinline,compiler.whitebox.SimpleTestCaseHelper::* From b9b80751e2b76406a523c0a984604cef79d699bd Mon Sep 17 00:00:00 2001 From: Gustavo Romero Date: Thu, 15 Dec 2016 08:56:32 -0500 Subject: [PATCH 023/157] 8171266: PPC64: Add support to -XX:RTMSpinLoopCount=0 Reviewed-by: mdoerr, dholmes --- hotspot/src/cpu/ppc/vm/macroAssembler_ppc.cpp | 21 ++++++++++++------- hotspot/src/cpu/ppc/vm/vm_version_ppc.cpp | 5 ++++- 2 files changed, 18 insertions(+), 8 deletions(-) diff --git a/hotspot/src/cpu/ppc/vm/macroAssembler_ppc.cpp b/hotspot/src/cpu/ppc/vm/macroAssembler_ppc.cpp index 2d1f0c7230b..a5d5613a414 100644 --- a/hotspot/src/cpu/ppc/vm/macroAssembler_ppc.cpp +++ b/hotspot/src/cpu/ppc/vm/macroAssembler_ppc.cpp @@ -2569,7 +2569,7 @@ void MacroAssembler::rtm_retry_lock_on_abort(Register retry_count_Reg, Register } // Spin and retry if lock is busy. -// inputs: box_Reg (monitor address) +// inputs: owner_addr_Reg (monitor address) // : retry_count_Reg // output: retry_count_Reg decremented by 1 // CTR is killed @@ -2577,15 +2577,22 @@ void MacroAssembler::rtm_retry_lock_on_busy(Register retry_count_Reg, Register o Label SpinLoop, doneRetry; addic_(retry_count_Reg, retry_count_Reg, -1); blt(CCR0, doneRetry); - li(R0, RTMSpinLoopCount); - mtctr(R0); + + if (RTMSpinLoopCount > 1) { + li(R0, RTMSpinLoopCount); + mtctr(R0); + } bind(SpinLoop); smt_yield(); // Can't use waitrsv(). No permission (SIGILL). - bdz(retryLabel); - ld(R0, 0, owner_addr_Reg); - cmpdi(CCR0, R0, 0); - bne(CCR0, SpinLoop); + + if (RTMSpinLoopCount > 1) { + bdz(retryLabel); + ld(R0, 0, owner_addr_Reg); + cmpdi(CCR0, R0, 0); + bne(CCR0, SpinLoop); + } + b(retryLabel); bind(doneRetry); diff --git a/hotspot/src/cpu/ppc/vm/vm_version_ppc.cpp b/hotspot/src/cpu/ppc/vm/vm_version_ppc.cpp index 6c6b83d257f..5e8be1425fa 100644 --- a/hotspot/src/cpu/ppc/vm/vm_version_ppc.cpp +++ b/hotspot/src/cpu/ppc/vm/vm_version_ppc.cpp @@ -327,7 +327,10 @@ void VM_Version::initialize() { warning("RTMAbortRatio must be in the range 0 to 100, resetting it to 50"); FLAG_SET_DEFAULT(RTMAbortRatio, 50); } - guarantee(RTMSpinLoopCount > 0, "unsupported"); + if (RTMSpinLoopCount < 0) { + warning("RTMSpinLoopCount must not be a negative value, resetting it to 0"); + FLAG_SET_DEFAULT(RTMSpinLoopCount, 0); + } #else // Only C2 does RTM locking optimization. // Can't continue because UseRTMLocking affects UseBiasedLocking flag From 396af967d63efb78f4cb652f51dc247b92bc2c67 Mon Sep 17 00:00:00 2001 From: Boris Molodenkov Date: Wed, 21 Dec 2016 14:41:48 +0300 Subject: [PATCH 024/157] 8170918: Remove shell script from test/compiler/c2/cr7200264/TestIntVect.java Reviewed-by: kvn --- test/jtreg-ext/requires/VMProps.java | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/test/jtreg-ext/requires/VMProps.java b/test/jtreg-ext/requires/VMProps.java index 06299e7ecd5..15c854f964b 100644 --- a/test/jtreg-ext/requires/VMProps.java +++ b/test/jtreg-ext/requires/VMProps.java @@ -33,6 +33,8 @@ import java.util.Map; import java.util.concurrent.Callable; import java.util.regex.Matcher; import java.util.regex.Pattern; + +import sun.hotspot.cpuinfo.CPUInfo; import sun.hotspot.gc.GC; import sun.hotspot.WhiteBox; @@ -62,6 +64,7 @@ public class VMProps implements Callable> { map.put("vm.simpleArch", vmArch()); map.put("vm.debug", vmDebug()); map.put("vm.jvmci", vmJvmci()); + map.put("vm.cpu.features", cpuFeatures()); vmGC(map); // vm.gc.X = true/false VMProps.dump(map); @@ -165,6 +168,13 @@ public class VMProps implements Callable> { return "" + (WB.getBooleanVMFlag("EnableJVMCI") != null); } + /** + * @return supported CPU features + */ + protected String cpuFeatures() { + return CPUInfo.getFeatures().toString(); + } + /** * For all existing GC sets vm.gc.X property. * Example vm.gc.G1=true means: From dcb007ab96d2b9cf120a6caa554fc62241bc2cb2 Mon Sep 17 00:00:00 2001 From: Igor Ignatyev Date: Wed, 28 Dec 2016 18:37:09 +0300 Subject: [PATCH 025/157] 8172094: 8171433 changes in generated-configure should be restored Reviewed-by: erikj, kzhaldyb --- common/autoconf/generated-configure.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/common/autoconf/generated-configure.sh b/common/autoconf/generated-configure.sh index 644f25ab435..13c74505795 100644 --- a/common/autoconf/generated-configure.sh +++ b/common/autoconf/generated-configure.sh @@ -5170,7 +5170,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=1482309967 +DATE_WHEN_GENERATED=1483099656 ############################################################################### # @@ -52997,7 +52997,7 @@ $as_echo "yes, forced" >&6; } $as_echo "no, forced" >&6; } BUILD_GTEST="false" elif test "x$enable_hotspot_gtest" = "x"; then - if test "x$GTEST_DIR_EXISTS" = "xtrue" && test "x$OPENJDK_TARGET_OS" != "xaix"; then + if test "x$GTEST_DIR_EXISTS" = "xtrue"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } BUILD_GTEST="true" From 5b1d170debed17398aed5ec9a9f9ef16986c92a1 Mon Sep 17 00:00:00 2001 From: Tobias Hartmann Date: Fri, 6 Jan 2017 10:55:30 +0100 Subject: [PATCH 026/157] 8171435: "assert(is_single_cpu() && !is_virtual()) failed: type check" with -XX:+PatchALot on SPARC Fixed several issues with PatchALot or unaligned accesses on SPARC. Reviewed-by: kvn --- .../src/cpu/sparc/vm/c1_LIRAssembler_sparc.cpp | 16 ++++++++++------ .../compiler/c1/CanonicalizeArrayLength.java | 6 +++--- 2 files changed, 13 insertions(+), 9 deletions(-) diff --git a/hotspot/src/cpu/sparc/vm/c1_LIRAssembler_sparc.cpp b/hotspot/src/cpu/sparc/vm/c1_LIRAssembler_sparc.cpp index 97fb2745a26..ae2942f19b5 100644 --- a/hotspot/src/cpu/sparc/vm/c1_LIRAssembler_sparc.cpp +++ b/hotspot/src/cpu/sparc/vm/c1_LIRAssembler_sparc.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2017, 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 @@ -694,6 +694,7 @@ void LIR_Assembler::vtable_call(LIR_OpJavaCall* op) { int LIR_Assembler::store(LIR_Opr from_reg, Register base, int offset, BasicType type, bool wide, bool unaligned) { int store_offset; if (!Assembler::is_simm13(offset + (type == T_LONG) ? wordSize : 0)) { + assert(base != O7, "destroying register"); assert(!unaligned, "can't handle this"); // for offsets larger than a simm13 we setup the offset in O7 __ set(offset, O7); @@ -712,9 +713,12 @@ int LIR_Assembler::store(LIR_Opr from_reg, Register base, int offset, BasicType case T_LONG : #ifdef _LP64 if (unaligned || PatchALot) { - __ srax(from_reg->as_register_lo(), 32, O7); + // Don't use O7 here because it may be equal to 'base' (see LIR_Assembler::reg2mem) + assert(G3_scratch != base, "can't handle this"); + assert(G3_scratch != from_reg->as_register_lo(), "can't handle this"); + __ srax(from_reg->as_register_lo(), 32, G3_scratch); __ stw(from_reg->as_register_lo(), base, offset + lo_word_offset_in_bytes); - __ stw(O7, base, offset + hi_word_offset_in_bytes); + __ stw(G3_scratch, base, offset + hi_word_offset_in_bytes); } else { __ stx(from_reg->as_register_lo(), base, offset); } @@ -821,7 +825,7 @@ int LIR_Assembler::load(Register base, int offset, LIR_Opr to_reg, BasicType typ case T_SHORT : __ ldsh(base, offset, to_reg->as_register()); break; case T_INT : __ ld(base, offset, to_reg->as_register()); break; case T_LONG : - if (!unaligned) { + if (!unaligned && !PatchALot) { #ifdef _LP64 __ ldx(base, offset, to_reg->as_register_lo()); #else @@ -1297,7 +1301,7 @@ void LIR_Assembler::mem2reg(LIR_Opr src_opr, LIR_Opr dest, BasicType type, disp_reg = O7; } } else if (unaligned || PatchALot) { - __ add(src, addr->index()->as_register(), O7); + __ add(src, addr->index()->as_pointer_register(), O7); src = O7; } else { disp_reg = addr->index()->as_pointer_register(); @@ -1424,7 +1428,7 @@ void LIR_Assembler::reg2mem(LIR_Opr from_reg, LIR_Opr dest, BasicType type, disp_reg = O7; } } else if (unaligned || PatchALot) { - __ add(src, addr->index()->as_register(), O7); + __ add(src, addr->index()->as_pointer_register(), O7); src = O7; } else { disp_reg = addr->index()->as_pointer_register(); diff --git a/hotspot/test/compiler/c1/CanonicalizeArrayLength.java b/hotspot/test/compiler/c1/CanonicalizeArrayLength.java index 64255c936ed..fb8f09028af 100644 --- a/hotspot/test/compiler/c1/CanonicalizeArrayLength.java +++ b/hotspot/test/compiler/c1/CanonicalizeArrayLength.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 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 @@ -23,7 +23,7 @@ /* * @test - * @bug 8150102 8150514 8150534 + * @bug 8150102 8150514 8150534 8171435 * @summary C1 crashes in Canonicalizer::do_ArrayLength() after fix for JDK-8150102 * * @run main/othervm -XX:+IgnoreUnrecognizedVMOptions -XX:+UnlockDiagnosticVMOptions @@ -31,7 +31,7 @@ * -XX:-BackgroundCompilation * compiler.c1.CanonicalizeArrayLength * @run main/othervm -XX:+IgnoreUnrecognizedVMOptions -XX:+UnlockDiagnosticVMOptions - * -XX:CompileThreshold=100 -XX:+TieredCompilation -XX:TieredStopAtLevel=1 + * -XX:CompileThreshold=100 -XX:+TieredCompilation -XX:TieredStopAtLevel=3 * -XX:-BackgroundCompilation * -XX:+PatchALot * compiler.c1.CanonicalizeArrayLength From 482d791b2cbbf244e18c761c3ac531aae4d10d23 Mon Sep 17 00:00:00 2001 From: Ioi Lam Date: Sun, 8 Jan 2017 10:39:42 -0800 Subject: [PATCH 027/157] 8170959: unloading archived shared class caused crash Reviewed-by: coleenp, sspitsyn, mockner --- hotspot/src/share/vm/oops/instanceKlass.cpp | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/hotspot/src/share/vm/oops/instanceKlass.cpp b/hotspot/src/share/vm/oops/instanceKlass.cpp index 5b2180f945c..41f5fd143a8 100644 --- a/hotspot/src/share/vm/oops/instanceKlass.cpp +++ b/hotspot/src/share/vm/oops/instanceKlass.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2017, 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 @@ -2139,8 +2139,6 @@ 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 // redefine classes. @@ -2191,7 +2189,7 @@ void InstanceKlass::release_C_heap_structures() { } // deallocate the cached class file - if (_cached_class_file != NULL) { + if (_cached_class_file != NULL && !MetaspaceShared::is_in_shared_space(_cached_class_file)) { os::free(_cached_class_file); _cached_class_file = NULL; } From 3dfc3e19ff8b5bb64b1e62c786103e3c1d590516 Mon Sep 17 00:00:00 2001 From: Kirill Zhaldybin Date: Wed, 28 Dec 2016 19:13:34 +0300 Subject: [PATCH 028/157] 8172098: A lot of gtests uses TEST instead of TEST_VM Reviewed-by: iignatyev --- .../native/code/test_dependencyContext.cpp | 2 +- .../native/gc/g1/test_workerDataArray.cpp | 40 +++++++++---------- hotspot/test/native/logging/test_log.cpp | 16 ++++---- .../native/logging/test_logConfiguration.cpp | 4 +- .../native/logging/test_logMessageTest.cpp | 16 ++++---- .../logging/test_logTagSetDescriptions.cpp | 4 +- 6 files changed, 41 insertions(+), 41 deletions(-) diff --git a/hotspot/test/native/code/test_dependencyContext.cpp b/hotspot/test/native/code/test_dependencyContext.cpp index 45b54d7cd80..fec730f9637 100644 --- a/hotspot/test/native/code/test_dependencyContext.cpp +++ b/hotspot/test/native/code/test_dependencyContext.cpp @@ -86,7 +86,7 @@ static void test_remove_dependent_nmethod(int id, bool delete_immediately) { NOT_PRODUCT(ASSERT_FALSE(depContext.is_dependent_nmethod(nm))); } -TEST(code, dependency_context) { +TEST_VM(code, dependency_context) { test_remove_dependent_nmethod(0, false); test_remove_dependent_nmethod(1, false); test_remove_dependent_nmethod(2, false); diff --git a/hotspot/test/native/gc/g1/test_workerDataArray.cpp b/hotspot/test/native/gc/g1/test_workerDataArray.cpp index 2895fecbec0..e950f1d480f 100644 --- a/hotspot/test/native/gc/g1/test_workerDataArray.cpp +++ b/hotspot/test/native/gc/g1/test_workerDataArray.cpp @@ -123,19 +123,19 @@ class BasicWorkerDataArrayTest : public WorkerDataArrayTest { } }; -TEST_F(BasicWorkerDataArrayTest, sum_test) { +TEST_VM_F(BasicWorkerDataArrayTest, sum_test) { ASSERT_EQ(15u, array.sum()); } -TEST_F(BasicWorkerDataArrayTest, average_test) { +TEST_VM_F(BasicWorkerDataArrayTest, average_test) { ASSERT_NEAR(5.0, array.average(), epsilon); } -TEST_F(BasicWorkerDataArrayTest, print_summary_on_test) { +TEST_VM_F(BasicWorkerDataArrayTest, print_summary_on_test) { ASSERT_STREQ(print_expected_summary(), print_summary()); } -TEST_F(BasicWorkerDataArrayTest, print_details_on_test) { +TEST_VM_F(BasicWorkerDataArrayTest, print_details_on_test) { ASSERT_STREQ(print_expected_details(), print_details()); } @@ -161,19 +161,19 @@ class AddWorkerDataArrayTest : public WorkerDataArrayTest { } }; -TEST_F(AddWorkerDataArrayTest, sum_test) { +TEST_VM_F(AddWorkerDataArrayTest, sum_test) { ASSERT_EQ(18u, array.sum()); } -TEST_F(AddWorkerDataArrayTest, average_test) { +TEST_VM_F(AddWorkerDataArrayTest, average_test) { ASSERT_NEAR(6.0, array.average(), epsilon); } -TEST_F(AddWorkerDataArrayTest, print_summary_on_test) { +TEST_VM_F(AddWorkerDataArrayTest, print_summary_on_test) { ASSERT_STREQ(print_expected_summary(), print_summary()); } -TEST_F(AddWorkerDataArrayTest, print_details_on_test) { +TEST_VM_F(AddWorkerDataArrayTest, print_details_on_test) { ASSERT_STREQ(print_expected_details(), print_details()); } @@ -195,19 +195,19 @@ class UninitializedElementWorkerDataArrayTest : public WorkerDataArrayTest { } }; -TEST_F(UninitializedWorkerDataArrayTest, sum_test) { +TEST_VM_F(UninitializedWorkerDataArrayTest, sum_test) { ASSERT_EQ(0u, array.sum()); } -TEST_F(UninitializedWorkerDataArrayTest, average_test) { +TEST_VM_F(UninitializedWorkerDataArrayTest, average_test) { ASSERT_NEAR(0.0, array.average(), epsilon); } -TEST_F(UninitializedWorkerDataArrayTest, print_summary_on_test) { +TEST_VM_F(UninitializedWorkerDataArrayTest, print_summary_on_test) { ASSERT_STREQ(print_expected_summary(), print_summary()); } -TEST_F(UninitializedWorkerDataArrayTest, print_details_on_test) { +TEST_VM_F(UninitializedWorkerDataArrayTest, print_details_on_test) { ASSERT_STREQ(print_expected_details(), print_details()); } @@ -265,18 +265,18 @@ class UninitializedDoubleElementWorkerDataArrayTest : public WorkerDataArrayTest } }; -TEST_F(UninitializedDoubleElementWorkerDataArrayTest, sum_test) { +TEST_VM_F(UninitializedDoubleElementWorkerDataArrayTest, sum_test) { ASSERT_NEAR(12.3 / MILLIUNITS, array.sum(), epsilon); } -TEST_F(UninitializedDoubleElementWorkerDataArrayTest, average_test) { +TEST_VM_F(UninitializedDoubleElementWorkerDataArrayTest, average_test) { ASSERT_NEAR(6.15 / MILLIUNITS, array.average(), epsilon); } -TEST_F(UninitializedDoubleElementWorkerDataArrayTest, print_summary_on_test) { +TEST_VM_F(UninitializedDoubleElementWorkerDataArrayTest, print_summary_on_test) { ASSERT_STREQ(print_expected_summary(), print_summary()); } -TEST_F(UninitializedDoubleElementWorkerDataArrayTest, print_details_on_test) { +TEST_VM_F(UninitializedDoubleElementWorkerDataArrayTest, print_details_on_test) { ASSERT_STREQ(print_expected_details(), print_details()); } diff --git a/hotspot/test/native/logging/test_log.cpp b/hotspot/test/native/logging/test_log.cpp index 50a5c9ce724..f3bdacaf4bc 100644 --- a/hotspot/test/native/logging/test_log.cpp +++ b/hotspot/test/native/logging/test_log.cpp @@ -41,14 +41,14 @@ size_t Test_log_prefix_prefixer(char* buf, size_t len) { } #ifdef ASSERT // 'test' tag is debug only -TEST_F(LogTest, prefix) { +TEST_VM_F(LogTest, prefix) { set_log_config(TestLogFileName, "logging+test=trace"); log_trace(logging, test)(LOG_LINE_STR); EXPECT_TRUE(file_contains_substring(TestLogFileName, LOG_PREFIX_STR LOG_LINE_STR)); } #endif -TEST_F(LogTest, large_message) { +TEST_VM_F(LogTest, large_message) { char big_msg[4096] = {0}; char Xchar = '~'; @@ -68,7 +68,7 @@ TEST_F(LogTest, large_message) { EXPECT_EQ(sizeof(big_msg) - 1, count); } -TEST_F(LogTest, enabled_logtarget) { +TEST_VM_F(LogTest, enabled_logtarget) { set_log_config(TestLogFileName, "gc=debug"); LogTarget(Debug, gc) log; @@ -80,7 +80,7 @@ TEST_F(LogTest, enabled_logtarget) { EXPECT_TRUE(file_contains_substring(TestLogFileName, LOG_TEST_STRING_LITERAL)); } -TEST_F(LogTest, disabled_logtarget) { +TEST_VM_F(LogTest, disabled_logtarget) { set_log_config(TestLogFileName, "gc=info"); LogTarget(Debug, gc) log; @@ -95,7 +95,7 @@ TEST_F(LogTest, disabled_logtarget) { EXPECT_FALSE(file_contains_substring(TestLogFileName, LOG_TEST_STRING_LITERAL)); } -TEST_F(LogTest, enabled_loghandle) { +TEST_VM_F(LogTest, enabled_loghandle) { set_log_config(TestLogFileName, "gc=debug"); Log(gc) log; @@ -109,7 +109,7 @@ TEST_F(LogTest, enabled_loghandle) { EXPECT_TRUE(file_contains_substring(TestLogFileName, "3 workers")); } -TEST_F(LogTest, disabled_loghandle) { +TEST_VM_F(LogTest, disabled_loghandle) { set_log_config(TestLogFileName, "gc=info"); Log(gc) log; @@ -126,7 +126,7 @@ TEST_F(LogTest, disabled_loghandle) { EXPECT_FALSE(file_contains_substring(TestLogFileName, "3 workers")); } -TEST_F(LogTest, enabled_logtargethandle) { +TEST_VM_F(LogTest, enabled_logtargethandle) { set_log_config(TestLogFileName, "gc=debug"); LogTarget(Debug, gc) log; @@ -140,7 +140,7 @@ TEST_F(LogTest, enabled_logtargethandle) { EXPECT_TRUE(file_contains_substring(TestLogFileName, "3 workers")); } -TEST_F(LogTest, disabled_logtargethandle) { +TEST_VM_F(LogTest, disabled_logtargethandle) { set_log_config(TestLogFileName, "gc=info"); LogTarget(Debug, gc) log; diff --git a/hotspot/test/native/logging/test_logConfiguration.cpp b/hotspot/test/native/logging/test_logConfiguration.cpp index 92d595e8059..74ae2aab707 100644 --- a/hotspot/test/native/logging/test_logConfiguration.cpp +++ b/hotspot/test/native/logging/test_logConfiguration.cpp @@ -297,7 +297,7 @@ TEST_VM_F(LogConfigurationTest, parse_log_arguments) { } } -TEST_F(LogConfigurationTest, configure_stdout) { +TEST_VM_F(LogConfigurationTest, configure_stdout) { // Start out with all logging disabled LogConfiguration::disable_logging(); @@ -355,7 +355,7 @@ static void Test_logconfiguration_subscribe_helper() { Test_logconfiguration_subscribe_triggered++; } -TEST_F(LogConfigurationTest, subscribe) { +TEST_VM_F(LogConfigurationTest, subscribe) { ResourceMark rm; Log(logging) log; set_log_config("stdout", "logging*=trace"); diff --git a/hotspot/test/native/logging/test_logMessageTest.cpp b/hotspot/test/native/logging/test_logMessageTest.cpp index f23ba944426..9e567b79798 100644 --- a/hotspot/test/native/logging/test_logMessageTest.cpp +++ b/hotspot/test/native/logging/test_logMessageTest.cpp @@ -65,7 +65,7 @@ LogMessageTest::~LogMessageTest() { // Verify that messages with multiple levels are written // to outputs configured for all the corresponding levels -TEST_F(LogMessageTest, level_inclusion) { +TEST_VM_F(LogMessageTest, level_inclusion) { const size_t message_count = 10; LogMessageBuffer msg[message_count]; @@ -119,7 +119,7 @@ LOG_LEVEL_LIST } // Verify that messages are logged in the order they are added to the log message -TEST_F(LogMessageTest, line_order) { +TEST_VM_F(LogMessageTest, line_order) { LogMessageBuffer msg; msg.info("info line").error("error line").trace("trace line") .error("another error").warning("warning line").debug("debug line"); @@ -131,7 +131,7 @@ TEST_F(LogMessageTest, line_order) { << "output missing or in incorrect order"; } -TEST_F(LogMessageTest, long_message) { +TEST_VM_F(LogMessageTest, long_message) { // Write 10K bytes worth of log data LogMessageBuffer msg; const size_t size = 10 * K; @@ -155,7 +155,7 @@ TEST_F(LogMessageTest, long_message) { FREE_C_HEAP_ARRAY(char, data); } -TEST_F(LogMessageTest, message_with_many_lines) { +TEST_VM_F(LogMessageTest, message_with_many_lines) { const size_t lines = 100; const size_t line_length = 16; @@ -188,7 +188,7 @@ static size_t dummy_prefixer(char* buf, size_t len) { return prefix_len; } -TEST_F(LogMessageTest, prefixing) { +TEST_VM_F(LogMessageTest, prefixing) { LogMessageBuffer msg; msg.set_prefix(dummy_prefixer); for (int i = 0; i < 3; i++) { @@ -209,7 +209,7 @@ TEST_F(LogMessageTest, prefixing) { << "error in prefixed output"; } -TEST_F(LogMessageTest, scoped_messages) { +TEST_VM_F(LogMessageTest, scoped_messages) { { LogMessage(logging) msg; msg.info("scoped info"); @@ -223,7 +223,7 @@ TEST_F(LogMessageTest, scoped_messages) { << "missing output from scoped log message"; } -TEST_F(LogMessageTest, scoped_flushing) { +TEST_VM_F(LogMessageTest, scoped_flushing) { { LogMessage(logging) msg; msg.info("manual flush info"); @@ -236,7 +236,7 @@ TEST_F(LogMessageTest, scoped_flushing) { << "log file contains duplicate lines from single scoped log message"; } -TEST_F(LogMessageTest, scoped_reset) { +TEST_VM_F(LogMessageTest, scoped_reset) { { LogMessage(logging) msg, partial; msg.info("%s", "info reset msg"); diff --git a/hotspot/test/native/logging/test_logTagSetDescriptions.cpp b/hotspot/test/native/logging/test_logTagSetDescriptions.cpp index 1669f86c34a..77c0a3191dc 100644 --- a/hotspot/test/native/logging/test_logTagSetDescriptions.cpp +++ b/hotspot/test/native/logging/test_logTagSetDescriptions.cpp @@ -30,7 +30,7 @@ #include "unittest.hpp" #include "utilities/ostream.hpp" -TEST(LogTagSetDescriptions, describe) { +TEST_VM(LogTagSetDescriptions, describe) { for (LogTagSetDescription* d = tagset_descriptions; d->tagset != NULL; d++) { char expected[1 * K]; d->tagset->label(expected, sizeof(expected), "+"); @@ -46,7 +46,7 @@ TEST(LogTagSetDescriptions, describe) { } } -TEST(LogTagSetDescriptions, command_line_help) { +TEST_VM(LogTagSetDescriptions, command_line_help) { const char* filename = "logtagset_descriptions"; FILE* fp = fopen(filename, "w+"); ASSERT_NE((void*)NULL, fp); From 9b81c0637e114f9cd645e4c6883250f82a44cbde Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rickard=20B=C3=A4ckman?= Date: Thu, 5 Jan 2017 08:37:10 +0100 Subject: [PATCH 029/157] 8169588: [AOT] jaotc --classpath option is confusing Reviewed-by: kvn, dlong --- .../src/jdk/tools/jaotc/LoadedClass.java | 64 ++++ .../src/jdk/tools/jaotc/Main.java | 95 +++-- .../tools/jaotc/collect/ClassCollector.java | 332 ------------------ .../jdk/tools/jaotc/collect/ClassSearch.java | 93 +++++ .../jdk/tools/jaotc/collect/ClassSource.java | 52 +++ .../jdk/tools/jaotc/collect/FileSupport.java | 90 +++++ .../tools/jaotc/collect/FileSystemFinder.java | 76 ++++ .../jdk/tools/jaotc/collect/SearchFor.java | 54 +++ .../jdk/tools/jaotc/collect/SearchPath.java | 87 +++++ .../tools/jaotc/collect/SourceProvider.java | 29 ++ .../collect/classname/ClassNameSource.java | 42 +++ .../classname/ClassNameSourceProvider.java | 62 ++++ .../collect/directory/DirectorySource.java | 53 +++ .../directory/DirectorySourceProvider.java | 68 ++++ .../jaotc/collect/jar/JarFileSource.java | 55 +++ .../jaotc/collect/jar/JarSourceProvider.java | 83 +++++ .../jaotc/collect/module/ModuleSource.java | 57 +++ .../collect/module/ModuleSourceProvider.java | 82 +++++ hotspot/test/compiler/aot/AotCompiler.java | 3 +- .../aot/cli/jaotc/ClasspathOptionTest.java | 63 ---- .../ClasspathOptionUnknownClassTest.java | 2 +- .../aot/cli/jaotc/CompileClassTest.java | 2 +- .../aot/cli/jaotc/CompileDirectoryTest.java | 2 +- .../aot/cli/jaotc/CompileJarTest.java | 2 +- .../aot/cli/jaotc/JaotcTestHelper.java | 6 +- .../cli/jaotc/ListOptionNotExistingTest.java | 2 +- .../aot/cli/jaotc/ListOptionTest.java | 2 +- .../cli/jaotc/ListOptionWrongFileTest.java | 7 +- .../jaotc/test/collect/ClassSearchTest.java | 143 ++++++++ .../jaotc/test/collect/ClassSourceTest.java | 52 +++ .../jaotc/test/collect/FakeFileSupport.java | 110 ++++++ .../jaotc/test/collect/FakeSearchPath.java | 47 +++ .../jaotc/test/collect/SearchPathTest.java | 102 ++++++ .../jdk/tools/jaotc/test/collect/Utils.java | 36 ++ .../DirectorySourceProviderTest.java | 77 ++++ .../collect/jar/JarSourceProviderTest.java | 112 ++++++ .../module/ModuleSourceProviderTest.java | 69 ++++ .../ClassAndLibraryNotMatchTest.java | 5 +- .../vmflags/BasicFlagsChange.java | 2 +- 39 files changed, 1884 insertions(+), 436 deletions(-) create mode 100644 hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/LoadedClass.java delete mode 100644 hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/collect/ClassCollector.java create mode 100644 hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/collect/ClassSearch.java create mode 100644 hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/collect/ClassSource.java create mode 100644 hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/collect/FileSupport.java create mode 100644 hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/collect/FileSystemFinder.java create mode 100644 hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/collect/SearchFor.java create mode 100644 hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/collect/SearchPath.java create mode 100644 hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/collect/SourceProvider.java create mode 100644 hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/collect/classname/ClassNameSource.java create mode 100644 hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/collect/classname/ClassNameSourceProvider.java create mode 100644 hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/collect/directory/DirectorySource.java create mode 100644 hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/collect/directory/DirectorySourceProvider.java create mode 100644 hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/collect/jar/JarFileSource.java create mode 100644 hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/collect/jar/JarSourceProvider.java create mode 100644 hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/collect/module/ModuleSource.java create mode 100644 hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/collect/module/ModuleSourceProvider.java delete mode 100644 hotspot/test/compiler/aot/cli/jaotc/ClasspathOptionTest.java create mode 100644 hotspot/test/compiler/aot/jdk.tools.jaotc.test/src/jdk/tools/jaotc/test/collect/ClassSearchTest.java create mode 100644 hotspot/test/compiler/aot/jdk.tools.jaotc.test/src/jdk/tools/jaotc/test/collect/ClassSourceTest.java create mode 100644 hotspot/test/compiler/aot/jdk.tools.jaotc.test/src/jdk/tools/jaotc/test/collect/FakeFileSupport.java create mode 100644 hotspot/test/compiler/aot/jdk.tools.jaotc.test/src/jdk/tools/jaotc/test/collect/FakeSearchPath.java create mode 100644 hotspot/test/compiler/aot/jdk.tools.jaotc.test/src/jdk/tools/jaotc/test/collect/SearchPathTest.java create mode 100644 hotspot/test/compiler/aot/jdk.tools.jaotc.test/src/jdk/tools/jaotc/test/collect/Utils.java create mode 100644 hotspot/test/compiler/aot/jdk.tools.jaotc.test/src/jdk/tools/jaotc/test/collect/directory/DirectorySourceProviderTest.java create mode 100644 hotspot/test/compiler/aot/jdk.tools.jaotc.test/src/jdk/tools/jaotc/test/collect/jar/JarSourceProviderTest.java create mode 100644 hotspot/test/compiler/aot/jdk.tools.jaotc.test/src/jdk/tools/jaotc/test/collect/module/ModuleSourceProviderTest.java diff --git a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/LoadedClass.java b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/LoadedClass.java new file mode 100644 index 00000000000..a0a01f7c1c9 --- /dev/null +++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/LoadedClass.java @@ -0,0 +1,64 @@ +package jdk.tools.jaotc;/* + * Copyright (c) 2015, 2017, 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 LoadedClass { + private final String name; + private final Class clz; + + public LoadedClass(String name, Class clz) { + this.name = name; + this.clz = clz; + } + + public String getName() { + return name; + } + + public Class getLoadedClass() { + return clz; + } + + @Override + public String toString() { + return name; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (!(o instanceof LoadedClass)) return false; + + LoadedClass that = (LoadedClass) o; + + if (name != null ? !name.equals(that.name) : that.name != null) return false; + return clz != null ? clz.equals(that.clz) : that.clz == null; + + } + + @Override + public int hashCode() { + int result = name != null ? name.hashCode() : 0; + result = 31 * result + (clz != null ? clz.hashCode() : 0); + return result; + } +} diff --git a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/Main.java b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/Main.java index 2af308732e4..8ea8ebf81c5 100644 --- a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/Main.java +++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/Main.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2017, 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 @@ -43,6 +43,7 @@ import java.nio.file.Paths; import java.text.MessageFormat; import java.util.ArrayList; import java.util.Date; +import java.util.HashSet; import java.util.LinkedList; import java.util.List; import java.util.ListIterator; @@ -51,7 +52,11 @@ import java.util.stream.Stream; import jdk.tools.jaotc.binformat.BinaryContainer; import jdk.tools.jaotc.binformat.ByteContainer; -import jdk.tools.jaotc.collect.ClassCollector; +import jdk.tools.jaotc.collect.*; +import jdk.tools.jaotc.collect.classname.ClassNameSourceProvider; +import jdk.tools.jaotc.collect.directory.DirectorySourceProvider; +import jdk.tools.jaotc.collect.jar.JarSourceProvider; +import jdk.tools.jaotc.collect.module.ModuleSourceProvider; import jdk.tools.jaotc.utils.Timer; import org.graalvm.compiler.api.runtime.GraalJVMCICompiler; @@ -127,17 +132,7 @@ public class Main implements LogPrinter { abstract void process(Main task, String opt, String arg) throws BadArgs; } - static Option[] recognizedOptions = {new Option(" --module Module to compile", true, "--module") { - @Override - void process(Main task, String opt, String arg) { - task.options.module = arg; - } - }, new Option(" --module-path Specify where to find module to compile", true, "--module-path") { - @Override - void process(Main task, String opt, String arg) { - task.options.modulepath = arg; - } - }, new Option(" --output Output file name", true, "--output") { + static Option[] recognizedOptions = { new Option(" --output Output file name", true, "--output") { @Override void process(Main task, String opt, String arg) { String name = arg; @@ -161,10 +156,25 @@ public class Main implements LogPrinter { void process(Main task, String opt, String arg) { task.options.compileWithAssertions = true; } - }, new Option(" --classpath Specify where to find user class files", true, "--classpath", "--class-path") { + }, new Option(" --classname > Class names to AOT compile (: separated list)", true, "--classname") { @Override void process(Main task, String opt, String arg) { - task.options.classpath = arg; + task.options.files.addAll(ClassSearch.makeList(ClassNameSourceProvider.TYPE, arg)); + } + }, new Option(" --directory Directories to search for class files. (: separated list)", true, "--directory") { + @Override + void process(Main task, String opt, String arg) { + task.options.files.addAll(ClassSearch.makeList(DirectorySourceProvider.TYPE, arg)); + } + }, new Option(" --jar Jar files to search for class files. (: separated list)", true, "--jar") { + @Override + void process(Main task, String opt, String arg) { + task.options.files.addAll(ClassSearch.makeList(JarSourceProvider.TYPE, arg)); + } + }, new Option(" --module module names to AOT compile (: separated list)", true, "--module") { + @Override + void process(Main task, String opt, String arg) { + task.options.files.addAll(ClassSearch.makeList(ModuleSourceProvider.TYPE, arg)); } }, new Option(" --threads Number of compilation threads to be used", true, "--threads") { @Override @@ -218,6 +228,12 @@ public class Main implements LogPrinter { void process(Main task, String opt, String arg) { task.options.version = true; } + }, new Option(" --search-path Where to search for jarfiles and modules", true, "--search-path") { + @Override + void process(Main task, String opt, String arg) { + String[] elements = arg.split(":"); + task.options.searchPath.add(elements); + } }, new Option(" -J Pass directly to the runtime system", false, "-J") { @Override void process(Main task, String opt, String arg) { @@ -225,12 +241,11 @@ public class Main implements LogPrinter { }}; public static class Options { - public List files = new LinkedList<>(); - public String module = null; - public String modulepath = "modules"; + public List files = new LinkedList<>(); public String outputName = "unnamed"; public String methodList; - public String classpath = "."; + public List sources = new ArrayList<>(); + public SearchPath searchPath = new SearchPath(); /** * We don't see scaling beyond 16 threads. @@ -288,7 +303,9 @@ public class Main implements LogPrinter { printlnInfo("Compiling " + options.outputName + "..."); final long start = System.currentTimeMillis(); - run(); + if (!run()) { + return EXIT_ABNORMAL; + } final long end = System.currentTimeMillis(); printlnInfo("Total time: " + (end - start) + " ms"); @@ -331,17 +348,34 @@ public class Main implements LogPrinter { } @SuppressWarnings("try") - private void run() throws Exception { + private boolean run() throws Exception { openLog(); try { CompilationSpec compilationRestrictions = collectSpecifiedMethods(); - Set> classesToCompile; + Set> classesToCompile = new HashSet<>(); try (Timer t = new Timer(this, "")) { - ClassCollector collector = new ClassCollector(this.options, this); - classesToCompile = collector.collectClassesToCompile(); + FileSupport fileSupport = new FileSupport(); + ClassSearch lookup = new ClassSearch(); + lookup.addProvider(new ModuleSourceProvider()); + lookup.addProvider(new ClassNameSourceProvider(fileSupport)); + lookup.addProvider(new JarSourceProvider()); + lookup.addProvider(new DirectorySourceProvider(fileSupport)); + + List found = null; + try { + found = lookup.search(options.files, options.searchPath); + } catch (InternalError e) { + reportError(e); + return false; + } + + for (LoadedClass loadedClass : found) { + classesToCompile.add(loadedClass.getLoadedClass()); + } + printInfo(classesToCompile.size() + " classes found"); } @@ -464,6 +498,7 @@ public class Main implements LogPrinter { } finally { closeLog(); } + return true; } private void addMethods(AOTCompiledClass aotClass, ResolvedJavaMethod[] methods, CompilationSpec compilationRestrictions, GraalFilters filters) { @@ -527,7 +562,7 @@ public class Main implements LogPrinter { break; } } else { - options.files.add(arg); + options.files.add(new SearchFor(arg)); } } } @@ -588,6 +623,12 @@ public class Main implements LogPrinter { log.flush(); } + private void reportError(Throwable e) { + log.println("Error: " + e.getMessage()); + e.printStackTrace(log); + log.flush(); + } + private void reportError(String key, Object... args) { printError(MessageFormat.format(key, args)); } @@ -603,9 +644,9 @@ public class Main implements LogPrinter { } private void showHelp() { - log.println("Usage: " + PROGNAME + " <--module name> | "); + log.println("Usage: " + PROGNAME + " | "); log.println(); - log.println(" list A list of class files, jar files or directories which"); + log.println(" list A list of class names, jar files or directories which"); log.println(" contains class files."); log.println(); log.println("where possible options include:"); diff --git a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/collect/ClassCollector.java b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/collect/ClassCollector.java deleted file mode 100644 index c46b3bfd062..00000000000 --- a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/collect/ClassCollector.java +++ /dev/null @@ -1,332 +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. - */ - -package jdk.tools.jaotc.collect; - -import jdk.tools.jaotc.LogPrinter; -import jdk.tools.jaotc.Main; - -import java.io.File; -import java.io.IOException; -import java.net.*; -import java.nio.file.*; -import java.nio.file.attribute.BasicFileAttributes; -import java.util.*; - -import static java.nio.file.FileVisitResult.CONTINUE; - -public class ClassCollector { - private final Main.Options options; - private final LogPrinter log; - - public ClassCollector(Main.Options options, LogPrinter log) { - this.options = options; - this.log = log; - } - - /** - * Collect all class names passed by the user. - * - * @return array list of classes - */ - public Set> collectClassesToCompile() { - Set> classes = new HashSet<>(); - List filesToScan = new LinkedList<>(options.files); - - if (options.module != null) { - classes.addAll(scanModule(filesToScan)); - } - - classes.addAll(scanFiles(filesToScan)); - return classes; - } - - private Set> scanModule(List filesToScan) { - String module = options.module; - // Search module in standard JDK installation. - Path dir = getModuleDirectory(options.modulepath, module); - - if (Files.isDirectory(dir)) { - return loadFromModuleDirectory(dir); - } else { - findFilesToScan(filesToScan, module); - return new HashSet<>(); - } - } - - private Set> loadFromModuleDirectory(Path dir) { - log.printInfo("Scanning module: " + dir + " ..."); - log.printlnVerbose(" "); // Break line - - FileSystemFinder finder = new FileSystemFinder(dir, pathname -> entryIsClassFile(pathname.toString())); - Set> cls = loadWithClassLoader(() -> ClassLoader.getSystemClassLoader(), dir, finder); - log.printlnInfo(" " + cls.size() + " classes loaded."); - return cls; - } - - private void findFilesToScan(List filesToScan, String module) { - // Try to search regular directory, .jar or .class files - Path path = Paths.get(options.modulepath, module); - - if (Files.isDirectory(path)) { - filesToScan.add("."); - options.classpath = path.toString(); - } else if (path.endsWith(".jar") || path.endsWith(".class")) { - filesToScan.add(path.toString()); - } else { - path = Paths.get(options.modulepath, module + ".jar"); - if (Files.exists(path)) { - filesToScan.add(path.toString()); - } else { - path = Paths.get(options.modulepath, module + ".class"); - if (Files.exists(path)) { - filesToScan.add(path.toString()); - } else { - throw new InternalError("Expecting a .class, .jar or directory: " + path); - } - } - } - } - - private boolean entryIsClassFile(String entry) { - return entry.endsWith(".class") && !entry.endsWith("module-info.class"); - } - - private Set> scanFiles(List filesToScan) { - Set> classes = new HashSet<>(); - for (String fileName : filesToScan) { - Set> loaded = scanFile(fileName); - log.printlnInfo(" " + loaded.size() + " classes loaded."); - classes.addAll(loaded); - } - return classes; - } - - interface ClassLoaderFactory { - ClassLoader create() throws IOException; - } - - private Set> loadWithClassLoader(ClassLoaderFactory factory, Path root, FileSystemFinder finder) { - ClassLoader loader = null; - try { - loader = factory.create(); - return loadClassFiles(root, finder, loader); - } catch (IOException e) { - throw new InternalError(e); - } finally { - if (loader instanceof AutoCloseable) { - try { - ((AutoCloseable) loader).close(); - } catch (Exception e) { - throw new InternalError(e); - } - } - } - } - - private Set> scanFile(String fileName) { - log.printInfo("Scanning: " + fileName + " ..."); - log.printlnVerbose(" "); // Break line - - if (fileName.endsWith(".jar")) { - return loadFromJarFile(fileName); - } else if (fileName.endsWith(".class")) { - Set> classes = new HashSet<>(); - loadFromClassFile(fileName, classes); - return classes; - } else { - return scanClassPath(fileName); - } - } - - private Set> loadFromJarFile(String fileName) { - FileSystem fs = makeFileSystem(fileName); - FileSystemFinder finder = new FileSystemFinder(fs.getPath("/"), pathname -> entryIsClassFile(pathname.toString())); - return loadWithClassLoader(() -> URLClassLoader.newInstance(buildUrls(fileName)), fs.getPath("/"), finder); - } - - private void loadFromClassFile(String fileName, Set> classes) { - Class result; - File file = new File(options.classpath); - try (URLClassLoader loader = URLClassLoader.newInstance(buildUrls(file))) { - result = loadClassFile(loader, fileName); - } catch (IOException e) { - throw new InternalError(e); - } - Class c = result; - addClass(classes, fileName, c); - } - - private Set> scanClassPath(String fileName) { - Path classPath = Paths.get(options.classpath); - if (!Files.exists(classPath)) { - throw new InternalError("Path does not exist: " + classPath); - } - if (!Files.isDirectory(classPath)) { - throw new InternalError("Path must be a directory: " + classPath); - } - - // Combine class path and file name and see what it is. - Path combinedPath = Paths.get(options.classpath + File.separator + fileName); - if (combinedPath.endsWith(".class")) { - throw new InternalError("unimplemented"); - } else if (Files.isDirectory(combinedPath)) { - return scanDirectory(classPath, combinedPath); - } else { - throw new InternalError("Expecting a .class, .jar or directory: " + fileName); - } - } - - private FileSystem makeFileSystem(String fileName) { - try { - return FileSystems.newFileSystem(makeJarFileURI(fileName), new HashMap<>()); - } catch (IOException e) { - throw new InternalError(e); - } - } - - private URI makeJarFileURI(String fileName) { - try { - return new URI("jar:file:" + Paths.get(fileName).toAbsolutePath() + "!/"); - } catch (URISyntaxException e) { - throw new InternalError(e); - } - } - - private PathMatcher combine(PathMatcher m1, PathMatcher m2) { - return path -> m1.matches(path) && m2.matches(path); - } - - private Set> scanDirectory(Path classPath, Path combinedPath) { - String dir = options.classpath; - - FileSystem fileSystem = FileSystems.getDefault(); - PathMatcher matcher = fileSystem.getPathMatcher("glob:" + "*.class"); - FileSystemFinder finder = new FileSystemFinder(combinedPath, - combine(matcher, pathname -> entryIsClassFile(pathname.toString()))); - - File file = new File(dir); - try (URLClassLoader loader = URLClassLoader.newInstance(buildUrls(file))) { - return loadClassFiles(classPath, finder, loader); - } catch (IOException e) { - throw new InternalError(e); - } - } - - private Set> loadClassFiles(Path root, FileSystemFinder finder, ClassLoader loader) { - Set> classes = new HashSet<>(); - for (Path name : finder.done()) { - // Now relativize to the class path so we get the actual class names. - String entry = root.relativize(name).normalize().toString(); - Class c = loadClassFile(loader, entry); - addClass(classes, entry, c); - } - return classes; - } - - private void addClass(Set> classes, String name, Class c) { - if (c != null) { - classes.add(c); - log.printlnVerbose(" loaded " + name); - } - } - - private URL[] buildUrls(String fileName) throws MalformedURLException { - return new URL[]{ new URL("jar:file:" + Paths.get(fileName).toAbsolutePath() + "!/") }; - } - - private URL[] buildUrls(File file) throws MalformedURLException { - return new URL[] {file.toURI().toURL() }; - } - - private Path getModuleDirectory(String modulepath, String module) { - FileSystem fs = FileSystems.getFileSystem(URI.create("jrt:/")); - return fs.getPath(modulepath, module); - } - - /** - * Loads a class with the given file name from the specified {@link URLClassLoader}. - */ - private Class loadClassFile(final ClassLoader loader, final String fileName) { - int start = 0; - if (fileName.startsWith("/")) { - start = 1; - } - String className = fileName.substring(start, fileName.length() - ".class".length()); - className = className.replace('/', '.'); - try { - return loader.loadClass(className); - } catch (Throwable e) { - // If we are running in JCK mode we ignore all exceptions. - if (options.ignoreClassLoadingErrors) { - log.printError(className + ": " + e); - return null; - } - throw new InternalError(e); - } - } - - /** - * {@link FileVisitor} implementation to find class files recursively. - */ - private static class FileSystemFinder extends SimpleFileVisitor { - private final ArrayList fileNames = new ArrayList<>(); - private final PathMatcher filter; - - FileSystemFinder(Path combinedPath, PathMatcher filter) { - this.filter = filter; - try { - Files.walkFileTree(combinedPath, this); - } catch (IOException e) { - throw new InternalError(e); - } - } - - /** - * Compares the glob pattern against the file name. - */ - void find(Path file) { - Path name = file.getFileName(); - if (name != null && filter.matches(name)) { - fileNames.add(file); - } - } - - List done() { - return fileNames; - } - - @Override - public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) { - find(file); - return CONTINUE; - } - - @Override - public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) { - find(dir); - return CONTINUE; - } - - } -} diff --git a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/collect/ClassSearch.java b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/collect/ClassSearch.java new file mode 100644 index 00000000000..3fd63b2c0b8 --- /dev/null +++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/collect/ClassSearch.java @@ -0,0 +1,93 @@ +/* + * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.tools.jaotc.collect; + +import jdk.tools.jaotc.LoadedClass; + +import java.util.ArrayList; +import java.util.List; + +public class ClassSearch { + private List providers = new ArrayList<>(); + + public void addProvider(SourceProvider provider) { + providers.add(provider); + } + + public List search(List search, SearchPath searchPath) { + List loaded = new ArrayList<>(); + + List sources = new ArrayList<>(); + + for (SearchFor entry : search) { + sources.add(findSource(entry, searchPath)); + } + + for (ClassSource source : sources) { + source.eachClass((name, loader) -> loaded.add(loadClass(name, loader))); + } + + return loaded; + } + + private LoadedClass loadClass(String name, ClassLoader loader) { + try { + Class clzz = loader.loadClass(name); + return new LoadedClass(name, clzz); + } catch (ClassNotFoundException e) { + throw new InternalError("Failed to load with: " + loader, e); + } + } + + private ClassSource findSource(SearchFor searchFor, SearchPath searchPath) { + ClassSource found = null; + + for (SourceProvider provider : providers) { + if (!searchFor.isUnknown() && !provider.supports(searchFor.getType())) { + continue; + } + + ClassSource source = provider.findSource(searchFor.getName(), searchPath); + if (source != null) { + if (found != null) { + throw new InternalError("Multiple possible sources: " + source + " and: " + found); + } + found = source; + } + } + + if (found == null) { + throw new InternalError("Failed to find: " + searchFor.toString()); + } + return found; + } + + public static List makeList(String type, String argument) { + List list = new ArrayList<>(); + String[] elements = argument.split(":"); + for (String element : elements) { + list.add(new SearchFor(element, type)); + } + return list; + } +} diff --git a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/collect/ClassSource.java b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/collect/ClassSource.java new file mode 100644 index 00000000000..8d9b8439760 --- /dev/null +++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/collect/ClassSource.java @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.tools.jaotc.collect; + +import java.nio.file.Path; +import java.util.function.BiConsumer; + +public interface ClassSource { + static boolean pathIsClassFile(Path entry) { + String fileName = entry.getFileName().toString(); + return fileName.endsWith(".class") && !fileName.endsWith("module-info.class"); + } + + static String makeClassName(Path path) { + String fileName = path.toString(); + + if (!fileName.endsWith(".class")) { + throw new IllegalArgumentException("File doesn't end with .class: '" + fileName + "'"); + } + + int start = 0; + if (fileName.startsWith("/")) { + start = 1; + } + + String className = fileName.substring(start, fileName.length() - ".class".length()); + className = className.replace('/', '.'); + return className; + } + + void eachClass(BiConsumer consumer); +} diff --git a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/collect/FileSupport.java b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/collect/FileSupport.java new file mode 100644 index 00000000000..0761c0ae8e1 --- /dev/null +++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/collect/FileSupport.java @@ -0,0 +1,90 @@ +/* + * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.tools.jaotc.collect; + +import java.io.IOException; +import java.net.*; +import java.nio.file.*; +import java.util.HashMap; + +public class FileSupport { + public boolean exists(Path path) { + return Files.exists(path); + } + + public boolean isDirectory(Path path) { + return Files.isDirectory(path); + } + + private FileSystem makeJarFileSystem(Path path) { + try { + return FileSystems.newFileSystem(makeJarFileURI(path), new HashMap<>()); + } catch (IOException e) { + throw new InternalError(e); + } + } + + private URI makeJarFileURI(Path path) { + try { + return new URI("jar:file:" + path.toAbsolutePath() + "!/"); + } catch (URISyntaxException e) { + throw new InternalError(e); + } + } + + public ClassLoader createClassLoader(Path path, ClassLoader parent) { + try { + return URLClassLoader.newInstance(buildUrls(path), parent); + } catch (MalformedURLException e) { + throw new InternalError(e); + } + } + + public ClassLoader createClassLoader(Path path) throws MalformedURLException { + return URLClassLoader.newInstance(buildUrls(path)); + } + + private URL[] buildUrls(Path path) throws MalformedURLException { + return new URL[] { path.toUri().toURL() }; + } + + public Path getJarFileSystemRoot(Path jarFile) { + FileSystem fileSystem = makeJarFileSystem(jarFile); + return fileSystem.getPath("/"); + } + + public boolean isAbsolute(Path entry) { + return entry.isAbsolute(); + } + + public Path getSubDirectory(FileSystem fileSystem, Path root, Path path) throws IOException { + DirectoryStream paths = fileSystem.provider().newDirectoryStream(root,null); + for (Path entry : paths) { + Path relative = root.relativize(entry); + if (relative.equals(path)) { + return entry; + } + } + return null; + } +} diff --git a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/collect/FileSystemFinder.java b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/collect/FileSystemFinder.java new file mode 100644 index 00000000000..7838104b89c --- /dev/null +++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/collect/FileSystemFinder.java @@ -0,0 +1,76 @@ +/* + * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.tools.jaotc.collect; + +import java.io.IOException; +import java.nio.file.*; +import java.nio.file.attribute.BasicFileAttributes; +import java.util.ArrayList; +import java.util.Iterator; + +import static java.nio.file.FileVisitResult.CONTINUE; + +/** + * {@link FileVisitor} implementation to find class files recursively. + */ +public class FileSystemFinder extends SimpleFileVisitor implements Iterable { + private final ArrayList fileNames = new ArrayList<>(); + private final PathMatcher filter; + + public FileSystemFinder(Path combinedPath, PathMatcher filter) { + this.filter = filter; + try { + Files.walkFileTree(combinedPath, this); + } catch (IOException e) { + throw new InternalError(e); + } + } + + /** + * Compares the glob pattern against the file name. + */ + private void find(Path file) { + Path name = file.getFileName(); + if (name != null && filter.matches(name)) { + fileNames.add(file); + } + } + + @Override + public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) { + find(file); + return CONTINUE; + } + + @Override + public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) { + find(dir); + return CONTINUE; + } + + + @Override + public Iterator iterator() { + return fileNames.iterator(); + } +} diff --git a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/collect/SearchFor.java b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/collect/SearchFor.java new file mode 100644 index 00000000000..49e0cdd9945 --- /dev/null +++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/collect/SearchFor.java @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.tools.jaotc.collect; + +public class SearchFor { + private final String name; + private final String type; + + public SearchFor(String name) { + this(name, "unknown"); + } + + public SearchFor(String name, String type) { + this.name = name; + this.type = type; + } + + public boolean isUnknown() { + return "unknown".equals(type); + } + + public String getType() { + return this.type; + } + + public String getName() { + return this.name; + } + + @Override + public String toString() { + return type + ":" + name; + } +} diff --git a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/collect/SearchPath.java b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/collect/SearchPath.java new file mode 100644 index 00000000000..19442069f16 --- /dev/null +++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/collect/SearchPath.java @@ -0,0 +1,87 @@ +/* + * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.tools.jaotc.collect; + +import java.nio.file.FileSystem; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.ArrayList; +import java.util.List; + +public class SearchPath { + private final List searchPaths = new ArrayList<>(); + private final FileSupport fileSupport; + + public SearchPath() { + this(new FileSupport()); + } + + public SearchPath(FileSupport fileSupport) { + this.fileSupport = fileSupport; + } + + public Path find(FileSystem fileSystem, Path entry, String... defaults) { + if (isAbsolute(entry)) { + if (exists(entry)) { + return entry; + } + return null; + } + + if (exists(entry)) { + return entry; + } + + for (String searchPath : defaults) { + Path newPath = fileSystem.getPath(searchPath, entry.toString()); + if (exists(newPath)) { + return newPath; + } + } + + for (Path searchPath : searchPaths) { + Path newPath = fileSystem.getPath(searchPath.toString(), entry.toString()); + if (exists(newPath)) { + return newPath; + } + } + + return null; + } + + private boolean isAbsolute(Path entry) { + return fileSupport.isAbsolute(entry); + } + + private boolean exists(Path entry) { + return fileSupport.exists(entry); + } + + public void add(String... paths) { + for (String name : paths) { + Path path = Paths.get(name); + searchPaths.add(path); + } + } +} + diff --git a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/collect/SourceProvider.java b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/collect/SourceProvider.java new file mode 100644 index 00000000000..5effa83c8fa --- /dev/null +++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/collect/SourceProvider.java @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.tools.jaotc.collect; + +public interface SourceProvider { + ClassSource findSource(String name, SearchPath searchPath); + + boolean supports(String type); +} diff --git a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/collect/classname/ClassNameSource.java b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/collect/classname/ClassNameSource.java new file mode 100644 index 00000000000..22227d03882 --- /dev/null +++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/collect/classname/ClassNameSource.java @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.tools.jaotc.collect.classname; + +import jdk.tools.jaotc.collect.ClassSource; + +import java.util.function.BiConsumer; + +public class ClassNameSource implements ClassSource { + private final String name; + private final ClassLoader classLoader; + + public ClassNameSource(String name, ClassLoader classLoader) { + this.name = name; + this.classLoader = classLoader; + } + + @Override + public void eachClass(BiConsumer consumer) { + consumer.accept(name, classLoader); + } +} diff --git a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/collect/classname/ClassNameSourceProvider.java b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/collect/classname/ClassNameSourceProvider.java new file mode 100644 index 00000000000..b5bc2804ed4 --- /dev/null +++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/collect/classname/ClassNameSourceProvider.java @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.tools.jaotc.collect.classname; + +import jdk.tools.jaotc.collect.ClassSource; +import jdk.tools.jaotc.collect.FileSupport; +import jdk.tools.jaotc.collect.SearchPath; +import jdk.tools.jaotc.collect.SourceProvider; + +import java.nio.file.Path; +import java.nio.file.Paths; + +public class ClassNameSourceProvider implements SourceProvider { + public final static String TYPE = "classname"; + private final ClassLoader classLoader; + + public ClassNameSourceProvider(FileSupport fileSupport) { + String classPath = System.getProperty("java.class.path"); + ClassLoader systemClassLoader = ClassLoader.getSystemClassLoader(); + if (classPath != null && !classPath.isEmpty()) { + classLoader = systemClassLoader; + } else { + Path path = Paths.get(".").toAbsolutePath(); + classLoader = fileSupport.createClassLoader(path, systemClassLoader); + } + } + + @Override + public ClassSource findSource(String name, SearchPath searchPath) { + try { + classLoader.loadClass(name); + return new ClassNameSource(name, classLoader); + } catch (ClassNotFoundException e) { + return null; + } + } + + @Override + public boolean supports(String type) { + return TYPE.equals(type); + } +} diff --git a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/collect/directory/DirectorySource.java b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/collect/directory/DirectorySource.java new file mode 100644 index 00000000000..8e5cdb5bc47 --- /dev/null +++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/collect/directory/DirectorySource.java @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.tools.jaotc.collect.directory; + +import jdk.tools.jaotc.collect.ClassSource; +import jdk.tools.jaotc.collect.FileSystemFinder; + +import java.nio.file.Path; +import java.util.function.BiConsumer; + +public class DirectorySource implements ClassSource { + private final Path directoryPath; + private final ClassLoader classLoader; + + public DirectorySource(Path directoryPath, ClassLoader classLoader) { + this.directoryPath = directoryPath; + this.classLoader = classLoader; + } + + @Override + public void eachClass(BiConsumer consumer) { + FileSystemFinder finder = new FileSystemFinder(directoryPath, ClassSource::pathIsClassFile); + + for (Path path : finder) { + consumer.accept(ClassSource.makeClassName(directoryPath.relativize(path).normalize()), classLoader); + } + } + + @Override + public String toString() { + return "directory:" + directoryPath.toString(); + } +} diff --git a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/collect/directory/DirectorySourceProvider.java b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/collect/directory/DirectorySourceProvider.java new file mode 100644 index 00000000000..013e3858830 --- /dev/null +++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/collect/directory/DirectorySourceProvider.java @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.tools.jaotc.collect.directory; + +import jdk.tools.jaotc.collect.ClassSource; +import jdk.tools.jaotc.collect.FileSupport; +import jdk.tools.jaotc.collect.SearchPath; +import jdk.tools.jaotc.collect.SourceProvider; + +import java.net.MalformedURLException; +import java.nio.file.FileSystem; +import java.nio.file.FileSystems; +import java.nio.file.Path; + +public class DirectorySourceProvider implements SourceProvider { + private final FileSupport fileSupport; + private final FileSystem fileSystem; + public final static String TYPE = "directory"; + + public DirectorySourceProvider(FileSupport fileSupport) { + this.fileSupport = fileSupport; + fileSystem = FileSystems.getDefault(); + } + + @Override + public ClassSource findSource(String name, SearchPath searchPath) { + Path directoryPath = fileSystem.getPath(name); + + if (!fileSupport.exists(directoryPath)) { + return null; + } + if (!fileSupport.isDirectory(directoryPath)) { + return null; + } + + try { + ClassLoader classLoader = fileSupport.createClassLoader(directoryPath); + return new DirectorySource(directoryPath, classLoader); + } catch (MalformedURLException e) { + return null; + } + } + + @Override + public boolean supports(String type) { + return TYPE.equals(type); + } +} diff --git a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/collect/jar/JarFileSource.java b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/collect/jar/JarFileSource.java new file mode 100644 index 00000000000..af7330a53b8 --- /dev/null +++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/collect/jar/JarFileSource.java @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.tools.jaotc.collect.jar; + +import jdk.tools.jaotc.collect.ClassSource; +import jdk.tools.jaotc.collect.FileSystemFinder; + +import java.nio.file.Path; +import java.util.function.BiConsumer; + +public class JarFileSource implements ClassSource { + private final Path jarFile; + private final Path jarRootPath; + private final ClassLoader classLoader; + + + public JarFileSource(Path jarFile, Path jarRootPath, ClassLoader classLoader) { + this.jarFile = jarFile; + this.jarRootPath = jarRootPath; + this.classLoader = classLoader; + } + + public void eachClass(BiConsumer consumer) { + FileSystemFinder finder = new FileSystemFinder(jarRootPath, ClassSource::pathIsClassFile); + + for (Path path : finder) { + consumer.accept(ClassSource.makeClassName(jarRootPath.relativize(path).normalize()), classLoader); + } + } + + @Override + public String toString() { + return "jar:" + jarFile.toString(); + } +} diff --git a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/collect/jar/JarSourceProvider.java b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/collect/jar/JarSourceProvider.java new file mode 100644 index 00000000000..f876c740b74 --- /dev/null +++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/collect/jar/JarSourceProvider.java @@ -0,0 +1,83 @@ +/* + * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.tools.jaotc.collect.jar; + +import jdk.tools.jaotc.collect.ClassSource; +import jdk.tools.jaotc.collect.FileSupport; +import jdk.tools.jaotc.collect.SearchPath; +import jdk.tools.jaotc.collect.SourceProvider; + +import java.net.MalformedURLException; +import java.nio.file.FileSystem; +import java.nio.file.FileSystems; +import java.nio.file.Path; +import java.nio.file.ProviderNotFoundException; + +public class JarSourceProvider implements SourceProvider { + private final FileSystem fileSystem; + private final FileSupport fileSupport; + public final static String TYPE = "jar"; + + public JarSourceProvider() { + this(new FileSupport()); + } + + public JarSourceProvider(FileSupport fileSupport) { + this.fileSupport = fileSupport; + fileSystem = FileSystems.getDefault(); + } + + @Override + public ClassSource findSource(String name, SearchPath searchPath) { + Path fileName = fileSystem.getPath(name); + Path jarFile = searchPath.find(fileSystem, fileName); + + if (!validPath(jarFile)) { + return null; + } + + return createSource(jarFile); + } + + private ClassSource createSource(Path jarFile) { + try { + Path jarRootPath = fileSupport.getJarFileSystemRoot(jarFile); + if (jarRootPath == null) { + return null; + } + ClassLoader classLoader = fileSupport.createClassLoader(jarFile); + return new JarFileSource(jarFile, jarRootPath, classLoader); + } catch (ProviderNotFoundException | MalformedURLException e) { + } + return null; + } + + @Override + public boolean supports(String type) { + return TYPE.equals(type); + } + + private boolean validPath(Path jarFile) { + return jarFile != null && !fileSupport.isDirectory(jarFile); + } +} diff --git a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/collect/module/ModuleSource.java b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/collect/module/ModuleSource.java new file mode 100644 index 00000000000..bac5624ab6a --- /dev/null +++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/collect/module/ModuleSource.java @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.tools.jaotc.collect.module; + +import jdk.tools.jaotc.collect.ClassSource; +import jdk.tools.jaotc.collect.FileSystemFinder; + +import java.nio.file.Path; +import java.util.function.BiConsumer; + +public class ModuleSource implements ClassSource { + private final Path modulePath; + private final ClassLoader classLoader; + + public ModuleSource(Path modulePath, ClassLoader classLoader) { + this.modulePath = modulePath; + this.classLoader = classLoader; + } + + @Override + public void eachClass(BiConsumer consumer) { + FileSystemFinder finder = new FileSystemFinder(modulePath, ClassSource::pathIsClassFile); + + for (Path path : finder) { + consumer.accept(ClassSource.makeClassName(modulePath.relativize(path).normalize()), classLoader); + } + } + + public Path getModulePath() { + return modulePath; + } + + @Override + public String toString() { + return "module:" + modulePath.toString(); + } +} diff --git a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/collect/module/ModuleSourceProvider.java b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/collect/module/ModuleSourceProvider.java new file mode 100644 index 00000000000..cd1a464b6f9 --- /dev/null +++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/collect/module/ModuleSourceProvider.java @@ -0,0 +1,82 @@ +/* + * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.tools.jaotc.collect.module; + +import jdk.tools.jaotc.collect.ClassSource; +import jdk.tools.jaotc.collect.FileSupport; +import jdk.tools.jaotc.collect.SearchPath; +import jdk.tools.jaotc.collect.SourceProvider; + +import java.io.IOException; +import java.net.URI; +import java.nio.file.FileSystem; +import java.nio.file.FileSystems; +import java.nio.file.Path; + +public class ModuleSourceProvider implements SourceProvider { + private final FileSystem fileSystem; + private final ClassLoader classLoader; + private final FileSupport fileSupport; + public final static String TYPE = "module"; + + public ModuleSourceProvider() { + this(FileSystems.getFileSystem(URI.create("jrt:/")), ClassLoader.getSystemClassLoader(), new FileSupport()); + } + + public ModuleSourceProvider(FileSystem fileSystem, ClassLoader classLoader, FileSupport fileSupport) { + this.fileSystem = fileSystem; + this.classLoader = classLoader; + this.fileSupport = fileSupport; + } + + @Override + public ClassSource findSource(String name, SearchPath searchPath) { + Path path = fileSystem.getPath(name); + Path dir = fileSystem.getPath("modules"); + + if (dir == null || !fileSupport.isDirectory(dir)) { + return null; + } + + Path found = findModuleDirectory(dir, path); + + if (found == null) { + return null; + } + + return new ModuleSource(found, classLoader); + } + + private Path findModuleDirectory(Path root, Path path) { + try { + return fileSupport.getSubDirectory(fileSystem, root, path); + } catch (IOException e) { + throw new InternalError(e); + } + } + + @Override + public boolean supports(String type) { + return TYPE.equals(type); + } +} diff --git a/hotspot/test/compiler/aot/AotCompiler.java b/hotspot/test/compiler/aot/AotCompiler.java index b9ace71767b..a9e4df91195 100644 --- a/hotspot/test/compiler/aot/AotCompiler.java +++ b/hotspot/test/compiler/aot/AotCompiler.java @@ -69,7 +69,7 @@ public class AotCompiler { extraopts.add("-classpath"); extraopts.add(Utils.TEST_CLASS_PATH + File.pathSeparator + Utils.TEST_SRC); if (className != null && libName != null) { - OutputAnalyzer oa = launchCompiler(libName, className + ".class", extraopts, compileList); + OutputAnalyzer oa = launchCompiler(libName, className, extraopts, compileList); oa.shouldHaveExitValue(0); } else { printUsage(); @@ -100,6 +100,7 @@ public class AotCompiler { args.add("--compile-commands"); args.add(file.toString()); } + args.add("--classname"); args.add(item); return launchJaotc(args, extraopts); } diff --git a/hotspot/test/compiler/aot/cli/jaotc/ClasspathOptionTest.java b/hotspot/test/compiler/aot/cli/jaotc/ClasspathOptionTest.java deleted file mode 100644 index eeee8db6cde..00000000000 --- a/hotspot/test/compiler/aot/cli/jaotc/ClasspathOptionTest.java +++ /dev/null @@ -1,63 +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. - */ - -/* - * @test - * @library / /test/lib /testlibrary - * @modules java.base/jdk.internal.misc - * @requires vm.bits == "64" & os.arch == "amd64" & os.family == "linux" - * @build compiler.aot.cli.jaotc.ClasspathOptionTest - * @run driver ClassFileInstaller compiler.aot.cli.jaotc.data.HelloWorldOne - * @run driver compiler.aot.cli.jaotc.ClasspathOptionTest - * @summary check jaotc can compile class from classpath - */ - -package compiler.aot.cli.jaotc; - -import compiler.aot.cli.jaotc.data.HelloWorldOne; -import java.io.File; -import java.io.IOException; -import java.nio.file.Files; -import java.nio.file.Path; -import java.nio.file.Paths; -import jdk.test.lib.Asserts; -import jdk.test.lib.process.OutputAnalyzer; - -public class ClasspathOptionTest { - public static void main(String[] args) { - Path cp = Paths.get("testClasspath"); - try { - Files.createDirectory(cp); - Files.move(Paths.get("compiler"), cp.resolve("compiler")); - } catch (IOException e) { - throw new Error("TESTBUG: can't create test data " + e, e); - } - OutputAnalyzer oa = JaotcTestHelper.compileLibrary("--classpath", cp.toString(), - JaotcTestHelper.getClassAotCompilationName(HelloWorldOne.class)); - oa.shouldHaveExitValue(0); - File compiledLibrary = new File(JaotcTestHelper.DEFAULT_LIB_PATH); - Asserts.assertTrue(compiledLibrary.exists(), "Compiled library file missing"); - Asserts.assertGT(compiledLibrary.length(), 0L, "Unexpected compiled library size"); - JaotcTestHelper.checkLibraryUsage(HelloWorldOne.class.getName()); - } -} diff --git a/hotspot/test/compiler/aot/cli/jaotc/ClasspathOptionUnknownClassTest.java b/hotspot/test/compiler/aot/cli/jaotc/ClasspathOptionUnknownClassTest.java index 1b99249abec..94af41f39bb 100644 --- a/hotspot/test/compiler/aot/cli/jaotc/ClasspathOptionUnknownClassTest.java +++ b/hotspot/test/compiler/aot/cli/jaotc/ClasspathOptionUnknownClassTest.java @@ -39,7 +39,7 @@ import jdk.test.lib.process.OutputAnalyzer; public class ClasspathOptionUnknownClassTest { public static void main(String[] args) { - OutputAnalyzer oa = JaotcTestHelper.compileLibrary("HelloWorldOne.class"); + OutputAnalyzer oa = JaotcTestHelper.compileLibrary("--classname", "HelloWorldOne"); Asserts.assertNE(oa.getExitValue(), 0, "Unexpected compilation exit code"); File compiledLibrary = new File(JaotcTestHelper.DEFAULT_LIB_PATH); Asserts.assertFalse(compiledLibrary.exists(), "Compiler library unexpectedly exists"); diff --git a/hotspot/test/compiler/aot/cli/jaotc/CompileClassTest.java b/hotspot/test/compiler/aot/cli/jaotc/CompileClassTest.java index a59e9e52b69..84ffa60c31e 100644 --- a/hotspot/test/compiler/aot/cli/jaotc/CompileClassTest.java +++ b/hotspot/test/compiler/aot/cli/jaotc/CompileClassTest.java @@ -41,7 +41,7 @@ import jdk.test.lib.process.OutputAnalyzer; public class CompileClassTest { public static void main(String[] args) { - OutputAnalyzer oa = JaotcTestHelper.compileLibrary(JaotcTestHelper + OutputAnalyzer oa = JaotcTestHelper.compileLibrary("--classname", JaotcTestHelper .getClassAotCompilationName(HelloWorldOne.class)); oa.shouldHaveExitValue(0); File compiledLibrary = new File(JaotcTestHelper.DEFAULT_LIB_PATH); diff --git a/hotspot/test/compiler/aot/cli/jaotc/CompileDirectoryTest.java b/hotspot/test/compiler/aot/cli/jaotc/CompileDirectoryTest.java index 7157294b9ad..051591bbe43 100644 --- a/hotspot/test/compiler/aot/cli/jaotc/CompileDirectoryTest.java +++ b/hotspot/test/compiler/aot/cli/jaotc/CompileDirectoryTest.java @@ -42,7 +42,7 @@ import jdk.test.lib.process.OutputAnalyzer; public class CompileDirectoryTest { public static void main(String[] args) { - OutputAnalyzer oa =JaotcTestHelper.compileLibrary("."); + OutputAnalyzer oa =JaotcTestHelper.compileLibrary("--directory", "."); oa.shouldHaveExitValue(0); File compiledLibrary = new File(JaotcTestHelper.DEFAULT_LIB_PATH); Asserts.assertTrue(compiledLibrary.exists(), "Compiled library file missing"); diff --git a/hotspot/test/compiler/aot/cli/jaotc/CompileJarTest.java b/hotspot/test/compiler/aot/cli/jaotc/CompileJarTest.java index b94265a4038..6253a4d55f3 100644 --- a/hotspot/test/compiler/aot/cli/jaotc/CompileJarTest.java +++ b/hotspot/test/compiler/aot/cli/jaotc/CompileJarTest.java @@ -48,7 +48,7 @@ public class CompileJarTest { public static void main(String[] args) { createJar(); - OutputAnalyzer oa = JaotcTestHelper.compileLibrary(JAR_NAME); + OutputAnalyzer oa = JaotcTestHelper.compileLibrary("--jar", JAR_NAME); oa.shouldHaveExitValue(0); File compiledLibrary = new File(JaotcTestHelper.DEFAULT_LIB_PATH); Asserts.assertTrue(compiledLibrary.exists(), "Compiled library file missing"); diff --git a/hotspot/test/compiler/aot/cli/jaotc/JaotcTestHelper.java b/hotspot/test/compiler/aot/cli/jaotc/JaotcTestHelper.java index e6136ba1b98..3cf87e61685 100644 --- a/hotspot/test/compiler/aot/cli/jaotc/JaotcTestHelper.java +++ b/hotspot/test/compiler/aot/cli/jaotc/JaotcTestHelper.java @@ -71,7 +71,11 @@ public class JaotcTestHelper { } } - public static String getClassAotCompilationName(Class classToCompile) { + public static String getClassAotCompilationFilename(Class classToCompile) { return classToCompile.getName().replaceAll("\\.", File.separator) + ".class"; } + + public static String getClassAotCompilationName(Class classToCompile) { + return classToCompile.getName(); + } } diff --git a/hotspot/test/compiler/aot/cli/jaotc/ListOptionNotExistingTest.java b/hotspot/test/compiler/aot/cli/jaotc/ListOptionNotExistingTest.java index 099554f3e13..9d3b6af5d22 100644 --- a/hotspot/test/compiler/aot/cli/jaotc/ListOptionNotExistingTest.java +++ b/hotspot/test/compiler/aot/cli/jaotc/ListOptionNotExistingTest.java @@ -45,7 +45,7 @@ public class ListOptionNotExistingTest { public static void main(String[] args) { OutputAnalyzer oa = JaotcTestHelper.compileLibrary("--compile-commands", "./notExisting.list", - COMPILE_ITEM); + "--classname", COMPILE_ITEM); int exitCode = oa.getExitValue(); Asserts.assertNE(exitCode, 0, "Unexpected compilation exit code"); File compiledLibrary = new File(JaotcTestHelper.DEFAULT_LIB_PATH); diff --git a/hotspot/test/compiler/aot/cli/jaotc/ListOptionTest.java b/hotspot/test/compiler/aot/cli/jaotc/ListOptionTest.java index e0b52f5799c..9de50bfe649 100644 --- a/hotspot/test/compiler/aot/cli/jaotc/ListOptionTest.java +++ b/hotspot/test/compiler/aot/cli/jaotc/ListOptionTest.java @@ -66,7 +66,7 @@ public class ListOptionTest { throw new Error("TESTBUG: can't write list file " + e, e); } OutputAnalyzer oa = JaotcTestHelper.compileLibrary("--compile-commands", COMPILE_COMMAND_FILE.toString(), - JaotcTestHelper.getClassAotCompilationName(HelloWorldOne.class)); + "--classname", JaotcTestHelper.getClassAotCompilationName(HelloWorldOne.class)); oa.shouldHaveExitValue(0); File compiledLibrary = new File(JaotcTestHelper.DEFAULT_LIB_PATH); Asserts.assertTrue(compiledLibrary.exists(), "Compiled library file missing"); diff --git a/hotspot/test/compiler/aot/cli/jaotc/ListOptionWrongFileTest.java b/hotspot/test/compiler/aot/cli/jaotc/ListOptionWrongFileTest.java index b3f0d1e626f..0f3fd1260fb 100644 --- a/hotspot/test/compiler/aot/cli/jaotc/ListOptionWrongFileTest.java +++ b/hotspot/test/compiler/aot/cli/jaotc/ListOptionWrongFileTest.java @@ -49,12 +49,15 @@ public class ListOptionWrongFileTest { private static final String COMPILE_ITEM = JaotcTestHelper.getClassAotCompilationName(HelloWorldOne.class); + private static final String COMPILE_FILE + = JaotcTestHelper.getClassAotCompilationFilename(HelloWorldOne.class); + public static void main(String[] args) { // expecting wrong file to be read but no compilation directive recognized, so, all compiled - OutputAnalyzer oa = JaotcTestHelper.compileLibrary("--compile-commands", COMPILE_ITEM, COMPILE_ITEM); + OutputAnalyzer oa = JaotcTestHelper.compileLibrary("--compile-commands", COMPILE_FILE, "--classname", COMPILE_ITEM); oa.shouldHaveExitValue(0); File compiledLibrary = new File(JaotcTestHelper.DEFAULT_LIB_PATH); - Asserts.assertTrue(compiledLibrary.exists(), "Expecte compiler library to exist"); + Asserts.assertTrue(compiledLibrary.exists(), "Expected compiler library to exist"); JaotcTestHelper.checkLibraryUsage(HelloWorldOne.class.getName(), EXPECTED, null); } } diff --git a/hotspot/test/compiler/aot/jdk.tools.jaotc.test/src/jdk/tools/jaotc/test/collect/ClassSearchTest.java b/hotspot/test/compiler/aot/jdk.tools.jaotc.test/src/jdk/tools/jaotc/test/collect/ClassSearchTest.java new file mode 100644 index 00000000000..b212fc3139c --- /dev/null +++ b/hotspot/test/compiler/aot/jdk.tools.jaotc.test/src/jdk/tools/jaotc/test/collect/ClassSearchTest.java @@ -0,0 +1,143 @@ +/* + * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.tools.jaotc.test.collect; + + +import jdk.tools.jaotc.LoadedClass; +import org.junit.Assert; +import org.junit.Test; + +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Set; +import java.util.function.BiConsumer; + +public class ClassSearchTest { + @Test(expected = InternalError.class) + public void itShouldThrowExceptionIfNoProvidersAvailable() { + ClassSearch target = new ClassSearch(); + SearchPath searchPath = new SearchPath(); + target.search(list("foo"), searchPath); + } + + @Test + public void itShouldFindAProviderForEachEntry() { + Set searched = new HashSet<>(); + ClassSearch target = new ClassSearch(); + target.addProvider(new SourceProvider() { + @Override + public ClassSource findSource(String name, SearchPath searchPath) { + searched.add(name); + return new NoopSource(); + } + }); + target.search(list("foo", "bar", "foobar"), null); + Assert.assertEquals(hashset("foo", "bar", "foobar"), searched); + } + + @Test + public void itShouldSearchAllProviders() { + Set visited = new HashSet<>(); + ClassSearch target = new ClassSearch(); + target.addProvider((name, searchPath) -> { + visited.add("1"); + return null; + }); + target.addProvider((name, searchPath) -> { + visited.add("2"); + return null; + }); + + try { + target.search(list("foo"), null); + } catch (InternalError e) { + // throws because no provider gives a source + } + + Assert.assertEquals(hashset("1", "2"), visited); + } + + @Test + public void itShouldTryToLoadSaidClassFromClassLoader() { + Set loaded = new HashSet<>(); + + ClassSearch target = new ClassSearch(); + target.addProvider(new SourceProvider() { + @Override + public ClassSource findSource(String name, SearchPath searchPath) { + return new ClassSource() { + @Override + public void eachClass(BiConsumer consumer) { + consumer.accept("foo.Bar", new ClassLoader() { + @Override + public Class loadClass(String name) throws ClassNotFoundException { + loaded.add(name); + return null; + } + }); + } + }; + } + }); + + java.util.List search = target.search(list("/tmp/something"), null); + Assert.assertEquals(list(new LoadedClass("foo.Bar", null)), search); + } + + @Test(expected = InternalError.class) + public void itShouldThrowInternalErrorWhenClassLoaderFails() { + ClassLoader classLoader = new ClassLoader() { + @Override + public Class loadClass(String name1) throws ClassNotFoundException { + throw new ClassNotFoundException("failed to find " + name1); + } + }; + + ClassSearch target = new ClassSearch(); + target.addProvider((name, searchPath) -> consumer -> consumer.accept("foo.Bar", classLoader)); + target.search(list("foobar"), null); + } + + private List list(T... entries) { + List list = new ArrayList(); + for (T entry : entries) { + list.add(entry); + } + return list; + } + + private Set hashset(T... entries) { + Set set = new HashSet(); + for (T entry : entries) { + set.add(entry); + } + return set; + } + + private static class NoopSource implements ClassSource { + @Override + public void eachClass(BiConsumer consumer) { + } + } +} diff --git a/hotspot/test/compiler/aot/jdk.tools.jaotc.test/src/jdk/tools/jaotc/test/collect/ClassSourceTest.java b/hotspot/test/compiler/aot/jdk.tools.jaotc.test/src/jdk/tools/jaotc/test/collect/ClassSourceTest.java new file mode 100644 index 00000000000..5fad5f57d76 --- /dev/null +++ b/hotspot/test/compiler/aot/jdk.tools.jaotc.test/src/jdk/tools/jaotc/test/collect/ClassSourceTest.java @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.tools.jaotc.test.collect; + +import org.junit.Assert; +import org.junit.Test; + +import java.nio.file.Paths; + +import static jdk.tools.jaotc.collect.ClassSource.makeClassName; + +public class ClassSourceTest { + @Test(expected=IllegalArgumentException.class) + public void itShouldThrowExceptionIfPathDoesntEndWithClass() { + makeClassName(Paths.get("Bar.clazz")); + } + + @Test + public void itShouldReplaceSlashesWithDots() { + Assert.assertEquals("foo.Bar", makeClassName(Paths.get("foo/Bar.class"))); + } + + @Test + public void itShouldStripLeadingSlash() { + Assert.assertEquals("Hello", makeClassName(Paths.get("/Hello.class"))); + } + + @Test + public void itShouldReplaceMultipleDots() { + Assert.assertEquals("some.foo.bar.FooBar", makeClassName(Paths.get("/some/foo/bar/FooBar.class"))); + } +} diff --git a/hotspot/test/compiler/aot/jdk.tools.jaotc.test/src/jdk/tools/jaotc/test/collect/FakeFileSupport.java b/hotspot/test/compiler/aot/jdk.tools.jaotc.test/src/jdk/tools/jaotc/test/collect/FakeFileSupport.java new file mode 100644 index 00000000000..178c3d47353 --- /dev/null +++ b/hotspot/test/compiler/aot/jdk.tools.jaotc.test/src/jdk/tools/jaotc/test/collect/FakeFileSupport.java @@ -0,0 +1,110 @@ +/* + * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.tools.jaotc.test.collect; + +import java.net.MalformedURLException; +import java.nio.file.Path; +import java.util.HashSet; +import java.util.Set; + +public class FakeFileSupport extends FileSupport { + private final Set exists = new HashSet<>(); + private final Set directories = new HashSet<>(); + + private final Set checkedExists = new HashSet<>(); + private final Set checkedDirectory = new HashSet<>(); + private final Set checkedJarFileSystemRoots = new HashSet<>(); + private final Set classloaderPaths = new HashSet<>(); + + private Path jarFileSystemRoot = null; + private final ClassLoader classLoader; + + public FakeFileSupport(Set existing, Set directories) { + this.exists.addAll(existing); + this.directories.addAll(directories); + + classLoader = new ClassLoader() { + @Override + public Class loadClass(String name) throws ClassNotFoundException { + return null; + } + }; + } + + public void setJarFileSystemRoot(Path path) { + jarFileSystemRoot = path; + } + + @Override + public boolean exists(Path path) { + checkedExists.add(path.toString()); + return exists.contains(path.toString()); + } + + @Override + public boolean isDirectory(Path path) { + checkedDirectory.add(path.toString()); + return directories.contains(path.toString()); + } + + @Override + public ClassLoader createClassLoader(Path path) throws MalformedURLException { + classloaderPaths.add(path.toString()); + return classLoader; + } + + @Override + public Path getJarFileSystemRoot(Path jarFile) { + checkedJarFileSystemRoots.add(jarFile.toString()); + return jarFileSystemRoot; + } + + @Override + public boolean isAbsolute(Path entry) { + return entry.toString().startsWith("/"); + } + + public void addExist(String name) { + exists.add(name); + } + + public void addDirectory(String name) { + directories.add(name); + } + + public Set getCheckedExists() { + return checkedExists; + } + + public Set getCheckedDirectory() { + return checkedDirectory; + } + + public Set getCheckedJarFileSystemRoots() { + return checkedJarFileSystemRoots; + } + + public Set getClassloaderPaths() { + return classloaderPaths; + } +} diff --git a/hotspot/test/compiler/aot/jdk.tools.jaotc.test/src/jdk/tools/jaotc/test/collect/FakeSearchPath.java b/hotspot/test/compiler/aot/jdk.tools.jaotc.test/src/jdk/tools/jaotc/test/collect/FakeSearchPath.java new file mode 100644 index 00000000000..9a7873ccf96 --- /dev/null +++ b/hotspot/test/compiler/aot/jdk.tools.jaotc.test/src/jdk/tools/jaotc/test/collect/FakeSearchPath.java @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.tools.jaotc.test.collect; + +import java.nio.file.FileSystem; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.Set; + +import static jdk.tools.jaotc.test.collect.Utils.set; + +public class FakeSearchPath extends SearchPath { + private Path path = null; + public Set entries = set(); + + public FakeSearchPath(String name) { + if (name != null) { + path = Paths.get(name); + } + } + + @Override + public Path find(FileSystem fileSystem, Path entry, String... defaults) { + entries.add(entry.toString()); + return path; + } +} diff --git a/hotspot/test/compiler/aot/jdk.tools.jaotc.test/src/jdk/tools/jaotc/test/collect/SearchPathTest.java b/hotspot/test/compiler/aot/jdk.tools.jaotc.test/src/jdk/tools/jaotc/test/collect/SearchPathTest.java new file mode 100644 index 00000000000..8ceca8dc5cf --- /dev/null +++ b/hotspot/test/compiler/aot/jdk.tools.jaotc.test/src/jdk/tools/jaotc/test/collect/SearchPathTest.java @@ -0,0 +1,102 @@ +/* + * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.tools.jaotc.test.collect; + +import org.junit.Before; +import org.junit.Test; + +import java.nio.file.FileSystem; +import java.nio.file.FileSystems; +import java.nio.file.Path; +import java.nio.file.Paths; + +import static jdk.tools.jaotc.test.collect.Utils.set; +import static org.junit.Assert.*; + +public class SearchPathTest { + private FakeFileSupport fileSupport; + private FileSystem fs; + + @Before + public void setUp() throws Exception { + fs = FileSystems.getDefault(); + } + + @Test + public void itShouldUsePathIfPathIsAbsoluteAndExisting() { + fileSupport = new FakeFileSupport(set("/foo"), set()); + SearchPath target = new SearchPath(fileSupport); + Path foo = Paths.get("/foo"); + Path result = target.find(fs, foo); + assertSame(result, foo); + } + + @Test + public void itShouldReturnNullIfPathIsAbsoluteAndNonExisting() { + fileSupport = new FakeFileSupport(set(), set()); + SearchPath target = new SearchPath(fileSupport); + Path result = target.find(fs, Paths.get("/bar")); + assertNull(result); + } + + @Test + public void itShouldUseRelativeExisting() { + fileSupport = new FakeFileSupport(set("hello", "tmp/hello", "search/hello"), set()); + SearchPath target = new SearchPath(fileSupport); + target.add("search"); + Path hello = Paths.get("hello"); + Path result = target.find(fs, hello, "tmp"); + assertSame(result, hello); + } + + @Test + public void itShouldSearchDefaultsBeforeSearchPaths() { + fileSupport = new FakeFileSupport(set("bar/foobar"), set()); + SearchPath target = new SearchPath(fileSupport); + Path result = target.find(fs, Paths.get("foobar"), "default1", "bar"); + assertEquals("bar/foobar", result.toString()); + assertEquals(set("foobar", "default1/foobar", "bar/foobar"), fileSupport.getCheckedExists()); + } + + @Test + public void itShouldUseSearchPathsIfNotInDefaults() { + fileSupport = new FakeFileSupport(set("bar/tmp/foobar"), set()); + SearchPath target = new SearchPath(fileSupport); + target.add("foo/tmp", "bar/tmp"); + + Path result = target.find(fs, Paths.get("foobar"), "foo", "bar"); + assertEquals("bar/tmp/foobar", result.toString()); + assertEquals(set("foobar", "foo/foobar", "bar/foobar", "bar/tmp/foobar", "foo/tmp/foobar"), fileSupport.getCheckedExists()); + } + + @Test + public void itShouldReturnNullIfNoExistingPathIsFound() { + fileSupport = new FakeFileSupport(set(), set()); + SearchPath target = new SearchPath(fileSupport); + target.add("dir1", "dir2"); + + Path result = target.find(fs, Paths.get("entry"), "dir3", "dir4"); + assertNull(result); + assertEquals(set("entry", "dir1/entry", "dir2/entry", "dir3/entry", "dir4/entry"), fileSupport.getCheckedExists()); + } +} diff --git a/hotspot/test/compiler/aot/jdk.tools.jaotc.test/src/jdk/tools/jaotc/test/collect/Utils.java b/hotspot/test/compiler/aot/jdk.tools.jaotc.test/src/jdk/tools/jaotc/test/collect/Utils.java new file mode 100644 index 00000000000..589027cde4c --- /dev/null +++ b/hotspot/test/compiler/aot/jdk.tools.jaotc.test/src/jdk/tools/jaotc/test/collect/Utils.java @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.tools.jaotc.test.collect; + +import java.util.HashSet; +import java.util.Set; + +public class Utils { + public static Set set(T... entries) { + Set set = new HashSet(); + for (T entry : entries) { + set.add(entry); + } + return set; + } +} diff --git a/hotspot/test/compiler/aot/jdk.tools.jaotc.test/src/jdk/tools/jaotc/test/collect/directory/DirectorySourceProviderTest.java b/hotspot/test/compiler/aot/jdk.tools.jaotc.test/src/jdk/tools/jaotc/test/collect/directory/DirectorySourceProviderTest.java new file mode 100644 index 00000000000..6608c01ab50 --- /dev/null +++ b/hotspot/test/compiler/aot/jdk.tools.jaotc.test/src/jdk/tools/jaotc/test/collect/directory/DirectorySourceProviderTest.java @@ -0,0 +1,77 @@ +/* + * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.tools.jaotc.test.collect.directory; + +import jdk.tools.jaotc.collect.ClassSource; +import jdk.tools.jaotc.test.collect.FakeFileSupport; +import jdk.tools.jaotc.test.collect.FileSupport; +import org.junit.Assert; +import org.junit.Test; + +import java.net.MalformedURLException; +import java.nio.file.Path; +import java.util.Set; + +import static jdk.tools.jaotc.test.collect.Utils.set; + +public class DirectorySourceProviderTest { + @Test + public void itShouldReturnNullForNonExistantPath() { + DirectorySourceProvider target = new DirectorySourceProvider(new FakeFileSupport(set(), set())); + ClassSource result = target.findSource("hello", null); + Assert.assertNull(result); + } + + @Test + public void itShouldReturnNullForNonDirectory() { + DirectorySourceProvider target = new DirectorySourceProvider(new FakeFileSupport(set("foobar"), set())); + ClassSource result = target.findSource("foobar", null); + Assert.assertNull(result); + } + + @Test + public void itShouldReturnNullForMalformedURI() { + Set visited = set(); + DirectorySourceProvider target = new DirectorySourceProvider(new FakeFileSupport(set("foobar"), set("foobar")) { + @Override + public ClassLoader createClassLoader(Path path) throws MalformedURLException { + visited.add("1"); + throw new MalformedURLException("..."); + } + }); + ClassSource result = target.findSource("foobar", null); + Assert.assertNull(result); + Assert.assertEquals(set("1"), visited); + } + + @Test + public void itShouldCreateSourceIfNameExistsAndIsADirectory() { + FileSupport fileSupport = new FakeFileSupport(set("foo"), set("foo")); + DirectorySourceProvider target = new DirectorySourceProvider(fileSupport); + ClassSource foo = target.findSource("foo", null); + Assert.assertNotNull(foo); + Assert.assertEquals("directory:foo", foo.toString()); + } + +} diff --git a/hotspot/test/compiler/aot/jdk.tools.jaotc.test/src/jdk/tools/jaotc/test/collect/jar/JarSourceProviderTest.java b/hotspot/test/compiler/aot/jdk.tools.jaotc.test/src/jdk/tools/jaotc/test/collect/jar/JarSourceProviderTest.java new file mode 100644 index 00000000000..14059883538 --- /dev/null +++ b/hotspot/test/compiler/aot/jdk.tools.jaotc.test/src/jdk/tools/jaotc/test/collect/jar/JarSourceProviderTest.java @@ -0,0 +1,112 @@ +/* + * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.tools.jaotc.test.collect.jar; + +import jdk.tools.jaotc.collect.ClassSource; +import jdk.tools.jaotc.test.collect.FakeFileSupport; +import jdk.tools.jaotc.test.collect.FakeSearchPath; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; + +import java.nio.file.Path; +import java.nio.file.Paths; +import java.nio.file.ProviderNotFoundException; +import java.util.Set; + +import static jdk.tools.jaotc.test.collect.Utils.set; + +public class JarSourceProviderTest { + + private FakeFileSupport fileSupport; + private JarSourceProvider target; + + @Before + public void setUp() throws Exception { + fileSupport = new FakeFileSupport(set(), set()); + target = new JarSourceProvider(fileSupport); + } + + @Test + public void itShouldUseSearchPathToFindPath() { + Set visited = set(); + JarSourceProvider target = new JarSourceProvider(fileSupport); + FakeSearchPath searchPath = new FakeSearchPath(null); + ClassSource source = target.findSource("hello", searchPath); + + Assert.assertEquals(set("hello"), searchPath.entries); + } + + @Test + public void itShouldReturnNullIfPathIsNull() { + JarSourceProvider target = new JarSourceProvider(fileSupport); + ClassSource source = target.findSource("foobar", new FakeSearchPath(null)); + Assert.assertNull(source); + } + + @Test + public void itShouldReturnNullIfPathIsDirectory() { + fileSupport.addDirectory("hello/foobar"); + ClassSource source = target.findSource("foobar", new FakeSearchPath("hello/foobar")); + + Assert.assertNull(source); + Assert.assertEquals(set("hello/foobar"), fileSupport.getCheckedDirectory()); + } + + @Test + public void itShouldReturnNullIfUnableToMakeJarFileSystem() { + fileSupport.setJarFileSystemRoot(null); + ClassSource result = target.findSource("foobar", new FakeSearchPath("foo/bar")); + + Assert.assertEquals(set("foo/bar"), fileSupport.getCheckedJarFileSystemRoots()); + Assert.assertNull(result); + } + + @Test + public void itShouldReturnNullIfNotValidJarProvider() { + fileSupport = new FakeFileSupport(set(), set()) { + + @Override + public Path getJarFileSystemRoot(Path jarFile) { + super.getJarFileSystemRoot(jarFile); + throw new ProviderNotFoundException(); + } + }; + fileSupport.setJarFileSystemRoot(null); + target = new JarSourceProvider(fileSupport); + + ClassSource result = target.findSource("foobar", new FakeSearchPath("foo/bar")); + + Assert.assertEquals(set("foo/bar"), fileSupport.getCheckedJarFileSystemRoots()); + Assert.assertNull(result); + } + + @Test + public void itShouldReturnSourceWhenAllIsValid() { + fileSupport.setJarFileSystemRoot(Paths.get("some/bar")); + ClassSource result = target.findSource("foobar", new FakeSearchPath("this/bar")); + + Assert.assertEquals(set("this/bar"), fileSupport.getClassloaderPaths()); + Assert.assertEquals("jar:this/bar", result.toString()); + } +} diff --git a/hotspot/test/compiler/aot/jdk.tools.jaotc.test/src/jdk/tools/jaotc/test/collect/module/ModuleSourceProviderTest.java b/hotspot/test/compiler/aot/jdk.tools.jaotc.test/src/jdk/tools/jaotc/test/collect/module/ModuleSourceProviderTest.java new file mode 100644 index 00000000000..80f06913269 --- /dev/null +++ b/hotspot/test/compiler/aot/jdk.tools.jaotc.test/src/jdk/tools/jaotc/test/collect/module/ModuleSourceProviderTest.java @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.tools.jaotc.test.collect.module; + +import jdk.tools.jaotc.*; +import jdk.tools.jaotc.test.collect.FakeSearchPath; +import jdk.tools.jaotc.test.collect.Utils; +import org.junit.Before; +import org.junit.Test; + +import java.nio.file.FileSystems; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNull; + +public class ModuleSourceProviderTest { + private ClassLoader classLoader; + private ModuleSourceProvider target; + + @Before + public void setUp() { + classLoader = new FakeClassLoader(); + target = new ModuleSourceProvider(FileSystems.getDefault(), classLoader); + } + + @Test + public void itShouldUseSearchPath() { + FakeSearchPath searchPath = new FakeSearchPath("blah/java.base"); + ModuleSource source = (ModuleSource) target.findSource("java.base", searchPath); + assertEquals(Utils.set("java.base"), searchPath.entries); + assertEquals("blah/java.base", source.getModulePath().toString()); + assertEquals("module:blah/java.base", source.toString()); + } + + @Test + public void itShouldReturnNullIfSearchPathReturnsNull() { + FakeSearchPath searchPath = new FakeSearchPath(null); + ModuleSource source = (ModuleSource) target.findSource("jdk.base", searchPath); + assertEquals(Utils.set("jdk.base"), searchPath.entries); + assertNull(source); + } + + private static class FakeClassLoader extends ClassLoader { + @Override + public Class loadClass(String name) throws ClassNotFoundException { + return null; + } + } +} diff --git a/hotspot/test/compiler/aot/verification/ClassAndLibraryNotMatchTest.java b/hotspot/test/compiler/aot/verification/ClassAndLibraryNotMatchTest.java index b2741387fa7..c702de31ae8 100644 --- a/hotspot/test/compiler/aot/verification/ClassAndLibraryNotMatchTest.java +++ b/hotspot/test/compiler/aot/verification/ClassAndLibraryNotMatchTest.java @@ -85,9 +85,8 @@ public class ClassAndLibraryNotMatchTest { } private void compileAotLibrary() { - AotCompiler.launchCompiler(LIB_NAME, HELLO_WORLD_CLASS_NAME + ".class", - Arrays.asList("-classpath", Utils.TEST_CLASS_PATH + File.pathSeparator - + Utils.TEST_SRC), null); + AotCompiler.launchCompiler(LIB_NAME, HELLO_WORLD_CLASS_NAME, + Arrays.asList("-classpath", Utils.TEST_CLASS_PATH + ":."), null); } private void runAndCheckHelloWorld(String checkString) { diff --git a/hotspot/test/compiler/aot/verification/vmflags/BasicFlagsChange.java b/hotspot/test/compiler/aot/verification/vmflags/BasicFlagsChange.java index bc60c1cd1ef..f7fd37a5e4a 100644 --- a/hotspot/test/compiler/aot/verification/vmflags/BasicFlagsChange.java +++ b/hotspot/test/compiler/aot/verification/vmflags/BasicFlagsChange.java @@ -76,7 +76,7 @@ public class BasicFlagsChange { extraOpts.add(option); extraOpts.add("-classpath"); extraOpts.add(Utils.TEST_CLASS_PATH + File.pathSeparator + Utils.TEST_SRC); - AotCompiler.launchCompiler(libName, className + ".class", extraOpts, null); + AotCompiler.launchCompiler(libName, className, extraOpts, null); } private static void runAndCheck(String option, String libName, From 26a978276c3416212c1b06299b7de2498dd516e4 Mon Sep 17 00:00:00 2001 From: David Leopoldseder Date: Mon, 9 Jan 2017 19:36:47 +0000 Subject: [PATCH 030/157] 8166125: [JVMCI] Missing JVMCI flag default values Reviewed-by: twisti, kvn --- hotspot/src/share/vm/runtime/arguments.cpp | 40 +++++++++++++++++----- hotspot/src/share/vm/runtime/arguments.hpp | 1 + 2 files changed, 33 insertions(+), 8 deletions(-) diff --git a/hotspot/src/share/vm/runtime/arguments.cpp b/hotspot/src/share/vm/runtime/arguments.cpp index e7e91083416..0ddbb30a8c5 100644 --- a/hotspot/src/share/vm/runtime/arguments.cpp +++ b/hotspot/src/share/vm/runtime/arguments.cpp @@ -1854,6 +1854,34 @@ void Arguments::select_gc() { } } +#if INCLUDE_JVMCI +void Arguments::set_jvmci_specific_flags() { + if (UseJVMCICompiler) { + if (FLAG_IS_DEFAULT(TypeProfileWidth)) { + FLAG_SET_DEFAULT(TypeProfileWidth, 8); + } + if (FLAG_IS_DEFAULT(OnStackReplacePercentage)) { + FLAG_SET_DEFAULT(OnStackReplacePercentage, 933); + } + if (FLAG_IS_DEFAULT(ReservedCodeCacheSize)) { + FLAG_SET_DEFAULT(ReservedCodeCacheSize, 64*M); + } + if (FLAG_IS_DEFAULT(InitialCodeCacheSize)) { + FLAG_SET_DEFAULT(InitialCodeCacheSize, 16*M); + } + if (FLAG_IS_DEFAULT(MetaspaceSize)) { + FLAG_SET_DEFAULT(MetaspaceSize, 12*M); + } + if (FLAG_IS_DEFAULT(NewSizeThreadIncrease)) { + FLAG_SET_DEFAULT(NewSizeThreadIncrease, 4*K); + } + if (FLAG_IS_DEFAULT(TypeProfileLevel)) { + FLAG_SET_DEFAULT(TypeProfileLevel, 0); + } + } +} +#endif + void Arguments::set_ergonomics_flags() { select_gc(); @@ -2463,14 +2491,6 @@ bool Arguments::check_vm_args_consistency() { warning("forcing ScavengeRootsInCode non-zero because JVMCI is enabled"); ScavengeRootsInCode = 1; } - if (FLAG_IS_DEFAULT(TypeProfileLevel)) { - TypeProfileLevel = 0; - } - if (UseJVMCICompiler) { - if (FLAG_IS_DEFAULT(TypeProfileWidth)) { - TypeProfileWidth = 8; - } - } } #endif @@ -4420,6 +4440,10 @@ jint Arguments::apply_ergo() { // Set flags based on ergonomics. set_ergonomics_flags(); +#if INCLUDE_JVMCI + set_jvmci_specific_flags(); +#endif + set_shared_spaces_flags(); // Check the GC selections again. diff --git a/hotspot/src/share/vm/runtime/arguments.hpp b/hotspot/src/share/vm/runtime/arguments.hpp index ce94e553d04..36bf75c6b2a 100644 --- a/hotspot/src/share/vm/runtime/arguments.hpp +++ b/hotspot/src/share/vm/runtime/arguments.hpp @@ -638,6 +638,7 @@ class Arguments : AllStatic { #if INCLUDE_JVMCI // Check consistency of jvmci vm argument settings. static bool check_jvmci_args_consistency(); + static void set_jvmci_specific_flags(); #endif // Check for consistency in the selection of the garbage collector. static bool check_gc_consistency(); // Check user-selected gc From dbec733773fb3c12075f043711169a39afaa4c22 Mon Sep 17 00:00:00 2001 From: Dmitrij Pochepko Date: Tue, 10 Jan 2017 20:45:04 +0300 Subject: [PATCH 031/157] 8166374: compiler/loopopts/UseCountedLoopSafepointsTest.java fails with "Safepoint not found" Reviewed-by: thartmann --- .../test/compiler/loopopts/UseCountedLoopSafepointsTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hotspot/test/compiler/loopopts/UseCountedLoopSafepointsTest.java b/hotspot/test/compiler/loopopts/UseCountedLoopSafepointsTest.java index 741f0d93d67..25a2ad4e087 100644 --- a/hotspot/test/compiler/loopopts/UseCountedLoopSafepointsTest.java +++ b/hotspot/test/compiler/loopopts/UseCountedLoopSafepointsTest.java @@ -27,7 +27,7 @@ * @bug 6869327 * @summary Test that C2 flag UseCountedLoopSafepoints ensures a safepoint is kept in a CountedLoop * @library /test/lib / - * @requires vm.compMode != "Xint" & vm.flavor == "server" & (vm.opt.TieredStopAtLevel == null | vm.opt.TieredStopAtLevel == 4) + * @requires vm.compMode != "Xint" & vm.flavor == "server" & (vm.opt.TieredStopAtLevel == null | vm.opt.TieredStopAtLevel == 4) & vm.debug == true * @modules java.base/jdk.internal.misc * @build sun.hotspot.WhiteBox * @run driver ClassFileInstaller sun.hotspot.WhiteBox From 5b9a2a728bbfed473080eb4aceb52bc6f2bfe679 Mon Sep 17 00:00:00 2001 From: Igor Veresov Date: Tue, 10 Jan 2017 21:39:20 +0300 Subject: [PATCH 032/157] 8172310: [AOT] Fix unverified entry point Fix AOT code for the unverified entry point Reviewed-by: kvn --- .../jdk/tools/jaotc/binformat/BinaryContainer.java | 5 +++++ .../src/jdk/tools/jaotc/AOTCompiledClass.java | 14 ++++++++++---- .../src/jdk/tools/jaotc/MarkId.java | 1 + .../src/jdk/tools/jaotc/MarkProcessor.java | 4 ++++ .../hotspot/amd64/AMD64HotSpotBackend.java | 13 +++++++++---- .../compiler/hotspot/amd64/AMD64HotSpotMove.java | 13 ++++++++++--- .../compiler/hotspot/GraalHotSpotVMConfig.java | 7 ++++--- hotspot/src/share/vm/aot/aotCodeHeap.cpp | 1 + hotspot/src/share/vm/jvmci/jvmciCodeInstaller.cpp | 1 + hotspot/src/share/vm/jvmci/jvmciCodeInstaller.hpp | 7 ++++--- hotspot/src/share/vm/jvmci/vmStructs_jvmci.cpp | 1 + 11 files changed, 50 insertions(+), 17 deletions(-) diff --git a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/BinaryContainer.java b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/BinaryContainer.java index 0c411fb7f1d..34ecf011e77 100644 --- a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/BinaryContainer.java +++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/BinaryContainer.java @@ -397,6 +397,10 @@ public class BinaryContainer implements SymbolTable { return "_aot_narrow_klass_base_address"; } + public String getNarrowOopBaseAddressSymbolName() { + return "_aot_narrow_oop_base_address"; + } + public String getLogOfHeapRegionGrainBytesSymbolName() { return "_aot_log_of_heap_region_grain_bytes"; } @@ -447,6 +451,7 @@ public class BinaryContainer implements SymbolTable { createGotSymbol(getHeapTopAddressSymbolName()); createGotSymbol(getHeapEndAddressSymbolName()); createGotSymbol(getNarrowKlassBaseAddressSymbolName()); + createGotSymbol(getNarrowOopBaseAddressSymbolName()); createGotSymbol(getPollingPageSymbolName()); createGotSymbol(getLogOfHeapRegionGrainBytesSymbolName()); createGotSymbol(getInlineContiguousAllocationSupportedSymbolName()); diff --git a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/AOTCompiledClass.java b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/AOTCompiledClass.java index cbf26294b0d..68fb146b8ce 100644 --- a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/AOTCompiledClass.java +++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/AOTCompiledClass.java @@ -293,12 +293,18 @@ public class AOTCompiledClass { // Record methods holder methodInfo.addDependentKlassData(binaryContainer, resolvedJavaType); // Record inlinee classes - for (ResolvedJavaMethod m : methodInfo.getCompilationResult().getMethods()) { - methodInfo.addDependentKlassData(binaryContainer, (HotSpotResolvedObjectType) m.getDeclaringClass()); + ResolvedJavaMethod[] inlinees = methodInfo.getCompilationResult().getMethods(); + if (inlinees != null) { + for (ResolvedJavaMethod m : inlinees) { + methodInfo.addDependentKlassData(binaryContainer, (HotSpotResolvedObjectType) m.getDeclaringClass()); + } } // Record classes of fields that were accessed - for (ResolvedJavaField f : methodInfo.getCompilationResult().getFields()) { - methodInfo.addDependentKlassData(binaryContainer, (HotSpotResolvedObjectType) f.getDeclaringClass()); + ResolvedJavaField[] fields = methodInfo.getCompilationResult().getFields(); + if (fields != null) { + for (ResolvedJavaField f : fields) { + methodInfo.addDependentKlassData(binaryContainer, (HotSpotResolvedObjectType) f.getDeclaringClass()); + } } } } diff --git a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/MarkId.java b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/MarkId.java index 4bbd4665434..eedeac3b720 100644 --- a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/MarkId.java +++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/MarkId.java @@ -48,6 +48,7 @@ enum MarkId { HEAP_TOP_ADDRESS("CodeInstaller::HEAP_TOP_ADDRESS"), HEAP_END_ADDRESS("CodeInstaller::HEAP_END_ADDRESS"), NARROW_KLASS_BASE_ADDRESS("CodeInstaller::NARROW_KLASS_BASE_ADDRESS"), + NARROW_OOP_BASE_ADDRESS("CodeInstaller::NARROW_OOP_BASE_ADDRESS"), CRC_TABLE_ADDRESS("CodeInstaller::CRC_TABLE_ADDRESS"), LOG_OF_HEAP_REGION_GRAIN_BYTES("CodeInstaller::LOG_OF_HEAP_REGION_GRAIN_BYTES"), INLINE_CONTIGUOUS_ALLOCATION_SUPPORTED("CodeInstaller::INLINE_CONTIGUOUS_ALLOCATION_SUPPORTED"); diff --git a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/MarkProcessor.java b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/MarkProcessor.java index 1e1944bc274..7a833c13914 100644 --- a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/MarkProcessor.java +++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/MarkProcessor.java @@ -57,6 +57,7 @@ class MarkProcessor { case HEAP_TOP_ADDRESS: case HEAP_END_ADDRESS: case NARROW_KLASS_BASE_ADDRESS: + case NARROW_OOP_BASE_ADDRESS: case CRC_TABLE_ADDRESS: case LOG_OF_HEAP_REGION_GRAIN_BYTES: case INLINE_CONTIGUOUS_ALLOCATION_SUPPORTED: @@ -78,6 +79,9 @@ class MarkProcessor { case NARROW_KLASS_BASE_ADDRESS: vmSymbolName = binaryContainer.getNarrowKlassBaseAddressSymbolName(); break; + case NARROW_OOP_BASE_ADDRESS: + vmSymbolName = binaryContainer.getNarrowOopBaseAddressSymbolName(); + break; case CRC_TABLE_ADDRESS: vmSymbolName = binaryContainer.getCrcTableAddressSymbolName(); break; diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotBackend.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotBackend.java index 4ccc1bbc9ef..7cb4b03b27e 100644 --- a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotBackend.java +++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotBackend.java @@ -267,10 +267,15 @@ public class AMD64HotSpotBackend extends HotSpotHostBackend { if (config.useCompressedClassPointers) { Register register = r10; - AMD64HotSpotMove.decodeKlassPointer(asm, register, providers.getRegisters().getHeapBaseRegister(), src, config.getKlassEncoding()); - if (config.narrowKlassBase != 0) { - // The heap base register was destroyed above, so restore it - asm.movq(providers.getRegisters().getHeapBaseRegister(), config.narrowOopBase); + AMD64HotSpotMove.decodeKlassPointer(crb, asm, register, providers.getRegisters().getHeapBaseRegister(), src, config); + if (GeneratePIC.getValue()) { + asm.movq(providers.getRegisters().getHeapBaseRegister(), asm.getPlaceholder(-1)); + crb.recordMark(config.MARKID_NARROW_OOP_BASE_ADDRESS); + } else { + if (config.narrowKlassBase != 0) { + // The heap base register was destroyed above, so restore it + asm.movq(providers.getRegisters().getHeapBaseRegister(), config.narrowOopBase); + } } asm.cmpq(inlineCacheKlass, register); } else { diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotMove.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotMove.java index f7a5f205c26..168282ebcbf 100644 --- a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotMove.java +++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotMove.java @@ -265,14 +265,21 @@ public class AMD64HotSpotMove { } } - public static void decodeKlassPointer(AMD64MacroAssembler masm, Register register, Register scratch, AMD64Address address, CompressEncoding encoding) { + public static void decodeKlassPointer(CompilationResultBuilder crb, AMD64MacroAssembler masm, Register register, Register scratch, AMD64Address address, GraalHotSpotVMConfig config) { + CompressEncoding encoding = config.getKlassEncoding(); masm.movl(register, address); if (encoding.shift != 0) { assert encoding.alignment == encoding.shift : "Decode algorithm is wrong"; masm.shlq(register, encoding.alignment); } - if (encoding.base != 0) { - masm.movq(scratch, encoding.base); + if (GeneratePIC.getValue() || encoding.base != 0) { + if (GeneratePIC.getValue()) { + masm.movq(scratch, masm.getPlaceholder(-1)); + crb.recordMark(config.MARKID_NARROW_KLASS_BASE_ADDRESS); + } else { + assert encoding.base != 0; + masm.movq(scratch, encoding.base); + } masm.addq(register, scratch); } } diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/GraalHotSpotVMConfig.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/GraalHotSpotVMConfig.java index e7ce8f68cce..4400099efc5 100644 --- a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/GraalHotSpotVMConfig.java +++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/GraalHotSpotVMConfig.java @@ -773,9 +773,10 @@ public class GraalHotSpotVMConfig extends HotSpotVMConfigAccess { public final int MARKID_HEAP_TOP_ADDRESS = getConstant("CodeInstaller::HEAP_TOP_ADDRESS", Integer.class, 17); public final int MARKID_HEAP_END_ADDRESS = getConstant("CodeInstaller::HEAP_END_ADDRESS", Integer.class, 18); public final int MARKID_NARROW_KLASS_BASE_ADDRESS = getConstant("CodeInstaller::NARROW_KLASS_BASE_ADDRESS", Integer.class, 19); - public final int MARKID_CRC_TABLE_ADDRESS = getConstant("CodeInstaller::CRC_TABLE_ADDRESS", Integer.class, 20); - public final int MARKID_LOG_OF_HEAP_REGION_GRAIN_BYTES = getConstant("CodeInstaller::LOG_OF_HEAP_REGION_GRAIN_BYTES", Integer.class, 21); - public final int MARKID_INLINE_CONTIGUOUS_ALLOCATION_SUPPORTED = getConstant("CodeInstaller::INLINE_CONTIGUOUS_ALLOCATION_SUPPORTED", Integer.class, 22); + public final int MARKID_NARROW_OOP_BASE_ADDRESS = getConstant("CodeInstaller::NARROW_OOP_BASE_ADDRESS", Integer.class, 20); + public final int MARKID_CRC_TABLE_ADDRESS = getConstant("CodeInstaller::CRC_TABLE_ADDRESS", Integer.class, 21); + public final int MARKID_LOG_OF_HEAP_REGION_GRAIN_BYTES = getConstant("CodeInstaller::LOG_OF_HEAP_REGION_GRAIN_BYTES", Integer.class, 22); + public final int MARKID_INLINE_CONTIGUOUS_ALLOCATION_SUPPORTED = getConstant("CodeInstaller::INLINE_CONTIGUOUS_ALLOCATION_SUPPORTED", Integer.class, 23); // Checkstyle: resume diff --git a/hotspot/src/share/vm/aot/aotCodeHeap.cpp b/hotspot/src/share/vm/aot/aotCodeHeap.cpp index 1cd9576253f..52e2c8d55b1 100644 --- a/hotspot/src/share/vm/aot/aotCodeHeap.cpp +++ b/hotspot/src/share/vm/aot/aotCodeHeap.cpp @@ -539,6 +539,7 @@ void AOTCodeHeap::link_global_lib_symbols() { SET_AOT_GLOBAL_SYMBOL_VALUE("_aot_heap_end_address", address, (heap->supports_inline_contig_alloc() ? heap->end_addr() : NULL)); SET_AOT_GLOBAL_SYMBOL_VALUE("_aot_polling_page", address, os::get_polling_page()); SET_AOT_GLOBAL_SYMBOL_VALUE("_aot_narrow_klass_base_address", address, Universe::narrow_klass_base()); + SET_AOT_GLOBAL_SYMBOL_VALUE("_aot_narrow_oop_base_address", address, Universe::narrow_oop_base()); SET_AOT_GLOBAL_SYMBOL_VALUE("_aot_log_of_heap_region_grain_bytes", int, HeapRegion::LogOfHRGrainBytes); SET_AOT_GLOBAL_SYMBOL_VALUE("_aot_inline_contiguous_allocation_supported", bool, heap->supports_inline_contig_alloc()); link_shared_runtime_symbols(); diff --git a/hotspot/src/share/vm/jvmci/jvmciCodeInstaller.cpp b/hotspot/src/share/vm/jvmci/jvmciCodeInstaller.cpp index 9e686ec1568..cca40f1aeb2 100644 --- a/hotspot/src/share/vm/jvmci/jvmciCodeInstaller.cpp +++ b/hotspot/src/share/vm/jvmci/jvmciCodeInstaller.cpp @@ -1258,6 +1258,7 @@ void CodeInstaller::site_Mark(CodeBuffer& buffer, jint pc_offset, Handle site, T case HEAP_TOP_ADDRESS: case HEAP_END_ADDRESS: case NARROW_KLASS_BASE_ADDRESS: + case NARROW_OOP_BASE_ADDRESS: case CRC_TABLE_ADDRESS: case LOG_OF_HEAP_REGION_GRAIN_BYTES: case INLINE_CONTIGUOUS_ALLOCATION_SUPPORTED: diff --git a/hotspot/src/share/vm/jvmci/jvmciCodeInstaller.hpp b/hotspot/src/share/vm/jvmci/jvmciCodeInstaller.hpp index e3b38c0688d..a700174de1d 100644 --- a/hotspot/src/share/vm/jvmci/jvmciCodeInstaller.hpp +++ b/hotspot/src/share/vm/jvmci/jvmciCodeInstaller.hpp @@ -133,9 +133,10 @@ private: HEAP_TOP_ADDRESS = 17, HEAP_END_ADDRESS = 18, NARROW_KLASS_BASE_ADDRESS = 19, - CRC_TABLE_ADDRESS = 20, - LOG_OF_HEAP_REGION_GRAIN_BYTES = 21, - INLINE_CONTIGUOUS_ALLOCATION_SUPPORTED = 22, + NARROW_OOP_BASE_ADDRESS = 20, + CRC_TABLE_ADDRESS = 21, + LOG_OF_HEAP_REGION_GRAIN_BYTES = 22, + INLINE_CONTIGUOUS_ALLOCATION_SUPPORTED = 23, INVOKE_INVALID = -1 }; diff --git a/hotspot/src/share/vm/jvmci/vmStructs_jvmci.cpp b/hotspot/src/share/vm/jvmci/vmStructs_jvmci.cpp index 2dad27fdfd9..5c69ecb4d65 100644 --- a/hotspot/src/share/vm/jvmci/vmStructs_jvmci.cpp +++ b/hotspot/src/share/vm/jvmci/vmStructs_jvmci.cpp @@ -429,6 +429,7 @@ declare_constant(CodeInstaller::HEAP_TOP_ADDRESS) \ declare_constant(CodeInstaller::HEAP_END_ADDRESS) \ declare_constant(CodeInstaller::NARROW_KLASS_BASE_ADDRESS) \ + declare_constant(CodeInstaller::NARROW_OOP_BASE_ADDRESS) \ declare_constant(CodeInstaller::CRC_TABLE_ADDRESS) \ declare_constant(CodeInstaller::LOG_OF_HEAP_REGION_GRAIN_BYTES) \ declare_constant(CodeInstaller::INLINE_CONTIGUOUS_ALLOCATION_SUPPORTED) \ From 421bf2f22d4ebbdd92ba0476a7dc33b20528827a Mon Sep 17 00:00:00 2001 From: Zoltan Majo Date: Wed, 11 Jan 2017 09:40:42 +0100 Subject: [PATCH 033/157] 8168926: C2: Bytecode escape analyzer crashes due to stack overflow Whether current call site needs an appendix is determined only based on the target method and the current bytecode instruction. Reviewed-by: kvn, thartmann --- hotspot/src/share/vm/ci/bcEscapeAnalyzer.cpp | 28 ++++++++++++++++++-- hotspot/src/share/vm/ci/ciMethod.hpp | 12 ++++++--- 2 files changed, 34 insertions(+), 6 deletions(-) diff --git a/hotspot/src/share/vm/ci/bcEscapeAnalyzer.cpp b/hotspot/src/share/vm/ci/bcEscapeAnalyzer.cpp index f7916cb1dab..e960d142abe 100644 --- a/hotspot/src/share/vm/ci/bcEscapeAnalyzer.cpp +++ b/hotspot/src/share/vm/ci/bcEscapeAnalyzer.cpp @@ -895,8 +895,32 @@ void BCEscapeAnalyzer::iterate_one_block(ciBlock *blk, StateInfo &state, Growabl ciMethod* target = s.get_method(ignored_will_link, &declared_signature); ciKlass* holder = s.get_declared_method_holder(); assert(declared_signature != NULL, "cannot be null"); - // Push appendix argument, if one. - if (s.has_appendix()) { + // If the current bytecode has an attached appendix argument, + // push an unknown object to represent that argument. (Analysis + // of dynamic call sites, especially invokehandle calls, needs + // the appendix argument on the stack, in addition to "regular" arguments + // pushed onto the stack by bytecode instructions preceding the call.) + // + // The escape analyzer does _not_ use the ciBytecodeStream::has_appendix(s) + // method to determine whether the current bytecode has an appendix argument. + // The has_appendix() method obtains the appendix from the + // ConstantPoolCacheEntry::_f1 field, which can happen concurrently with + // resolution of dynamic call sites. Callees in the + // ciBytecodeStream::get_method() call above also access the _f1 field; + // interleaving the get_method() and has_appendix() calls in the current + // method with call site resolution can lead to an inconsistent view of + // the current method's argument count. In particular, some interleaving(s) + // can cause the method's argument count to not include the appendix, which + // then leads to stack over-/underflow in the escape analyzer. + // + // Instead of pushing the argument if has_appendix() is true, the escape analyzer + // pushes an appendix for all call sites targeted by invokedynamic and invokehandle + // instructions, except if the call site is the _invokeBasic intrinsic + // (that intrinsic is always targeted by an invokehandle instruction but does + // not have an appendix argument). + if (target->is_loaded() && + Bytecodes::has_optional_appendix(s.cur_bc_raw()) && + target->intrinsic_id() != vmIntrinsics::_invokeBasic) { state.apush(unknown_obj); } // Pass in raw bytecode because we need to see invokehandle instructions. diff --git a/hotspot/src/share/vm/ci/ciMethod.hpp b/hotspot/src/share/vm/ci/ciMethod.hpp index 2580f40f3ea..f16948e71d7 100644 --- a/hotspot/src/share/vm/ci/ciMethod.hpp +++ b/hotspot/src/share/vm/ci/ciMethod.hpp @@ -136,15 +136,19 @@ class ciMethod : public ciMetadata { check_is_loaded(); return _signature->size() + (_flags.is_static() ? 0 : 1); } - // Report the number of elements on stack when invoking this method. - // This is different than the regular arg_size because invokedynamic - // has an implicit receiver. + // Report the number of elements on stack when invoking the current method. + // If the method is loaded, arg_size() gives precise information about the + // number of stack elements (using the method's signature and its flags). + // However, if the method is not loaded, the number of stack elements must + // be determined differently, as the method's flags are not yet available. + // The invoke_arg_size() method assumes in that case that all bytecodes except + // invokestatic and invokedynamic have a receiver that is also pushed onto the + // stack by the caller of the current method. int invoke_arg_size(Bytecodes::Code code) const { if (is_loaded()) { return arg_size(); } else { int arg_size = _signature->size(); - // Add a receiver argument, maybe: if (code != Bytecodes::_invokestatic && code != Bytecodes::_invokedynamic) { arg_size++; From b1c82624b9a700c74339139dee096b07c46db854 Mon Sep 17 00:00:00 2001 From: Robbin Ehn Date: Wed, 11 Jan 2017 12:47:16 +0100 Subject: [PATCH 034/157] 8079441: Intermittent failures on Windows with "Unexpected exit from test [exit code: 1080890248]" (0x406d1388) Do not raise (windows thread name) exception 0x406d1388 when no debugger is attached. Reviewed-by: iklam, stuefe --- hotspot/src/os/windows/vm/os_windows.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/hotspot/src/os/windows/vm/os_windows.cpp b/hotspot/src/os/windows/vm/os_windows.cpp index 5142cd37a25..23ad8e209cb 100644 --- a/hotspot/src/os/windows/vm/os_windows.cpp +++ b/hotspot/src/os/windows/vm/os_windows.cpp @@ -778,6 +778,11 @@ void os::set_native_thread_name(const char *name) { // is already attached to a debugger; debugger must observe // the exception below to show the correct name. + // If there is no debugger attached skip raising the exception + if (!IsDebuggerPresent()) { + return; + } + const DWORD MS_VC_EXCEPTION = 0x406D1388; struct { DWORD dwType; // must be 0x1000 From 8ab1255ff1dc9fe2856bceb876a5d7cc904cafa5 Mon Sep 17 00:00:00 2001 From: Igor Ignatyev Date: Wed, 11 Jan 2017 17:43:36 +0300 Subject: [PATCH 035/157] 8172557: quarantine ctw/JarDirTest Reviewed-by: ctornqvi --- hotspot/test/ProblemList.txt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/hotspot/test/ProblemList.txt b/hotspot/test/ProblemList.txt index 7a7f6a64e29..1acd8e90e2b 100644 --- a/hotspot/test/ProblemList.txt +++ b/hotspot/test/ProblemList.txt @@ -77,5 +77,7 @@ serviceability/sa/sadebugd/SADebugDTest.java 8163805 generic-all # :hotspot_misc +testlibrary_tests/ctw/JarDirTest.java 8172457 windows-all + ############################################################################# From b9f711fc74c1d54a07e8ce55e9d2b16f42523f61 Mon Sep 17 00:00:00 2001 From: Andrew Haley Date: Wed, 11 Jan 2017 15:09:58 +0000 Subject: [PATCH 036/157] 8172144: AArch64: Implement "JEP 270: Reserved Stack Areas for Critical Sections" Reviewed-by: fparain --- hotspot/src/cpu/aarch64/vm/aarch64.ad | 4 ++ .../aarch64/vm/c1_LIRAssembler_aarch64.cpp | 6 ++ hotspot/src/cpu/aarch64/vm/frame_aarch64.cpp | 1 + hotspot/src/cpu/aarch64/vm/frame_aarch64.hpp | 3 + .../aarch64/vm/globalDefinitions_aarch64.hpp | 2 + .../src/cpu/aarch64/vm/globals_aarch64.hpp | 2 +- .../cpu/aarch64/vm/interp_masm_aarch64.cpp | 16 +++++ .../cpu/aarch64/vm/macroAssembler_aarch64.cpp | 24 ++++++++ .../cpu/aarch64/vm/macroAssembler_aarch64.hpp | 3 + .../cpu/aarch64/vm/stubGenerator_aarch64.cpp | 7 ++- .../linux_aarch64/vm/os_linux_aarch64.cpp | 59 +++++++++++++++++++ .../ReservedStack/ReservedStackTest.java | 3 +- 12 files changed, 126 insertions(+), 4 deletions(-) diff --git a/hotspot/src/cpu/aarch64/vm/aarch64.ad b/hotspot/src/cpu/aarch64/vm/aarch64.ad index 2294bab8db8..87b0bc1e79e 100644 --- a/hotspot/src/cpu/aarch64/vm/aarch64.ad +++ b/hotspot/src/cpu/aarch64/vm/aarch64.ad @@ -3008,6 +3008,10 @@ void MachEpilogNode::emit(CodeBuffer &cbuf, PhaseRegAlloc *ra_) const { __ notify(Assembler::method_reentry); } + if (StackReservedPages > 0 && C->has_reserved_stack_access()) { + __ reserved_stack_check(); + } + if (do_polling() && C->is_method_compilation()) { __ read_polling_page(rscratch1, os::get_polling_page(), relocInfo::poll_return_type); } diff --git a/hotspot/src/cpu/aarch64/vm/c1_LIRAssembler_aarch64.cpp b/hotspot/src/cpu/aarch64/vm/c1_LIRAssembler_aarch64.cpp index 70c8f909337..b139a44f9a1 100644 --- a/hotspot/src/cpu/aarch64/vm/c1_LIRAssembler_aarch64.cpp +++ b/hotspot/src/cpu/aarch64/vm/c1_LIRAssembler_aarch64.cpp @@ -532,8 +532,14 @@ void LIR_Assembler::poll_for_safepoint(relocInfo::relocType rtype, CodeEmitInfo* void LIR_Assembler::return_op(LIR_Opr result) { assert(result->is_illegal() || !result->is_single_cpu() || result->as_register() == r0, "word returns are in r0,"); + // Pop the stack before the safepoint code __ remove_frame(initial_frame_size_in_bytes()); + + if (StackReservedPages > 0 && compilation()->has_reserved_stack_access()) { + __ reserved_stack_check(); + } + address polling_page(os::get_polling_page()); __ read_polling_page(rscratch1, polling_page, relocInfo::poll_return_type); __ ret(lr); diff --git a/hotspot/src/cpu/aarch64/vm/frame_aarch64.cpp b/hotspot/src/cpu/aarch64/vm/frame_aarch64.cpp index b74bce2d415..924aab146c2 100644 --- a/hotspot/src/cpu/aarch64/vm/frame_aarch64.cpp +++ b/hotspot/src/cpu/aarch64/vm/frame_aarch64.cpp @@ -629,6 +629,7 @@ void frame::describe_pd(FrameValues& values, int frame_no) { DESCRIBE_FP_OFFSET(interpreter_frame_last_sp); DESCRIBE_FP_OFFSET(interpreter_frame_method); DESCRIBE_FP_OFFSET(interpreter_frame_mdp); + DESCRIBE_FP_OFFSET(interpreter_frame_mirror); DESCRIBE_FP_OFFSET(interpreter_frame_cache); DESCRIBE_FP_OFFSET(interpreter_frame_locals); DESCRIBE_FP_OFFSET(interpreter_frame_bcp); diff --git a/hotspot/src/cpu/aarch64/vm/frame_aarch64.hpp b/hotspot/src/cpu/aarch64/vm/frame_aarch64.hpp index 5bcee325945..64a35bd3c30 100644 --- a/hotspot/src/cpu/aarch64/vm/frame_aarch64.hpp +++ b/hotspot/src/cpu/aarch64/vm/frame_aarch64.hpp @@ -46,6 +46,9 @@ // [pointer to locals ] = locals() locals_offset // [constant pool cache ] = cache() cache_offset +// [klass of method ] = mirror() mirror_offset +// [padding ] + // [methodData ] = mdp() mdx_offset // [methodOop ] = method() method_offset diff --git a/hotspot/src/cpu/aarch64/vm/globalDefinitions_aarch64.hpp b/hotspot/src/cpu/aarch64/vm/globalDefinitions_aarch64.hpp index 4c9d377ff09..0d78e2da1fe 100644 --- a/hotspot/src/cpu/aarch64/vm/globalDefinitions_aarch64.hpp +++ b/hotspot/src/cpu/aarch64/vm/globalDefinitions_aarch64.hpp @@ -53,4 +53,6 @@ const bool CCallingConventionRequiresIntsAsLongs = false; // evidence that it's worth doing. #define DEOPTIMIZE_WHEN_PATCHING +#define SUPPORT_RESERVED_STACK_AREA + #endif // CPU_AARCH64_VM_GLOBALDEFINITIONS_AARCH64_HPP diff --git a/hotspot/src/cpu/aarch64/vm/globals_aarch64.hpp b/hotspot/src/cpu/aarch64/vm/globals_aarch64.hpp index 3226ef5cf72..2ba8d7f9e48 100644 --- a/hotspot/src/cpu/aarch64/vm/globals_aarch64.hpp +++ b/hotspot/src/cpu/aarch64/vm/globals_aarch64.hpp @@ -47,7 +47,7 @@ define_pd_global(intx, InlineFrequencyCount, 100); #define DEFAULT_STACK_YELLOW_PAGES (2) #define DEFAULT_STACK_RED_PAGES (1) #define DEFAULT_STACK_SHADOW_PAGES (4 DEBUG_ONLY(+5)) -#define DEFAULT_STACK_RESERVED_PAGES (0) +#define DEFAULT_STACK_RESERVED_PAGES (1) #define MIN_STACK_YELLOW_PAGES DEFAULT_STACK_YELLOW_PAGES #define MIN_STACK_RED_PAGES DEFAULT_STACK_RED_PAGES diff --git a/hotspot/src/cpu/aarch64/vm/interp_masm_aarch64.cpp b/hotspot/src/cpu/aarch64/vm/interp_masm_aarch64.cpp index ed95d410e36..81636fb8ea1 100644 --- a/hotspot/src/cpu/aarch64/vm/interp_masm_aarch64.cpp +++ b/hotspot/src/cpu/aarch64/vm/interp_masm_aarch64.cpp @@ -619,6 +619,22 @@ void InterpreterMacroAssembler::remove_activation( // get sender esp ldr(esp, Address(rfp, frame::interpreter_frame_sender_sp_offset * wordSize)); + if (StackReservedPages > 0) { + // testing if reserved zone needs to be re-enabled + Label no_reserved_zone_enabling; + + ldr(rscratch1, Address(rthread, JavaThread::reserved_stack_activation_offset())); + cmp(esp, rscratch1); + br(Assembler::LS, no_reserved_zone_enabling); + + call_VM_leaf( + CAST_FROM_FN_PTR(address, SharedRuntime::enable_stack_reserved_zone), rthread); + call_VM(noreg, CAST_FROM_FN_PTR(address, + InterpreterRuntime::throw_delayed_StackOverflowError)); + should_not_reach_here(); + + bind(no_reserved_zone_enabling); + } // remove frame anchor leave(); // If we're returning to interpreted code we will shortly be diff --git a/hotspot/src/cpu/aarch64/vm/macroAssembler_aarch64.cpp b/hotspot/src/cpu/aarch64/vm/macroAssembler_aarch64.cpp index dc90886ab68..1c955d5afe3 100644 --- a/hotspot/src/cpu/aarch64/vm/macroAssembler_aarch64.cpp +++ b/hotspot/src/cpu/aarch64/vm/macroAssembler_aarch64.cpp @@ -402,6 +402,30 @@ void MacroAssembler::far_jump(Address entry, CodeBuffer *cbuf, Register tmp) { } } +void MacroAssembler::reserved_stack_check() { + // testing if reserved zone needs to be enabled + Label no_reserved_zone_enabling; + + ldr(rscratch1, Address(rthread, JavaThread::reserved_stack_activation_offset())); + cmp(sp, rscratch1); + br(Assembler::LO, no_reserved_zone_enabling); + + enter(); // LR and FP are live. + lea(rscratch1, CAST_FROM_FN_PTR(address, SharedRuntime::enable_stack_reserved_zone)); + mov(c_rarg0, rthread); + blr(rscratch1); + leave(); + + // We have already removed our own frame. + // throw_delayed_StackOverflowError will think that it's been + // called by our caller. + lea(rscratch1, RuntimeAddress(StubRoutines::throw_delayed_StackOverflowError_entry())); + br(rscratch1); + should_not_reach_here(); + + bind(no_reserved_zone_enabling); +} + int MacroAssembler::biased_locking_enter(Register lock_reg, Register obj_reg, Register swap_reg, diff --git a/hotspot/src/cpu/aarch64/vm/macroAssembler_aarch64.hpp b/hotspot/src/cpu/aarch64/vm/macroAssembler_aarch64.hpp index 3418189f1b4..2f17699a262 100644 --- a/hotspot/src/cpu/aarch64/vm/macroAssembler_aarch64.hpp +++ b/hotspot/src/cpu/aarch64/vm/macroAssembler_aarch64.hpp @@ -957,6 +957,9 @@ public: // stack overflow + shadow pages. Also, clobbers tmp void bang_stack_size(Register size, Register tmp); + // Check for reserved stack access in method being exited (for JIT) + void reserved_stack_check(); + virtual RegisterOrConstant delayed_value_impl(intptr_t* delayed_value_addr, Register tmp, int offset); diff --git a/hotspot/src/cpu/aarch64/vm/stubGenerator_aarch64.cpp b/hotspot/src/cpu/aarch64/vm/stubGenerator_aarch64.cpp index 681ecf34277..3143fe97d88 100644 --- a/hotspot/src/cpu/aarch64/vm/stubGenerator_aarch64.cpp +++ b/hotspot/src/cpu/aarch64/vm/stubGenerator_aarch64.cpp @@ -4676,8 +4676,11 @@ class StubGenerator: public StubCodeGenerator { StubRoutines::_throw_StackOverflowError_entry = generate_throw_exception("StackOverflowError throw_exception", CAST_FROM_FN_PTR(address, - SharedRuntime:: - throw_StackOverflowError)); + SharedRuntime::throw_StackOverflowError)); + StubRoutines::_throw_delayed_StackOverflowError_entry = + generate_throw_exception("delayed StackOverflowError throw_exception", + CAST_FROM_FN_PTR(address, + SharedRuntime::throw_delayed_StackOverflowError)); if (UseCRC32Intrinsics) { // set table address before stub generation which use it StubRoutines::_crc_table_adr = (address)StubRoutines::aarch64::_crc_table; diff --git a/hotspot/src/os_cpu/linux_aarch64/vm/os_linux_aarch64.cpp b/hotspot/src/os_cpu/linux_aarch64/vm/os_linux_aarch64.cpp index 4c425c4040d..989f8aef17e 100644 --- a/hotspot/src/os_cpu/linux_aarch64/vm/os_linux_aarch64.cpp +++ b/hotspot/src/os_cpu/linux_aarch64/vm/os_linux_aarch64.cpp @@ -87,6 +87,7 @@ #define SPELL_REG_FP "rbp" #else #define REG_FP 29 +#define REG_LR 30 #define SPELL_REG_SP "sp" #define SPELL_REG_FP "x29" @@ -182,6 +183,46 @@ frame os::fetch_frame_from_context(const void* ucVoid) { return frame(sp, fp, epc.pc()); } +bool os::Linux::get_frame_at_stack_banging_point(JavaThread* thread, ucontext_t* uc, frame* fr) { + address pc = (address) os::Linux::ucontext_get_pc(uc); + if (Interpreter::contains(pc)) { + // interpreter performs stack banging after the fixed frame header has + // been generated while the compilers perform it before. To maintain + // semantic consistency between interpreted and compiled frames, the + // method returns the Java sender of the current frame. + *fr = os::fetch_frame_from_context(uc); + if (!fr->is_first_java_frame()) { + assert(fr->safe_for_sender(thread), "Safety check"); + *fr = fr->java_sender(); + } + } else { + // more complex code with compiled code + assert(!Interpreter::contains(pc), "Interpreted methods should have been handled above"); + CodeBlob* cb = CodeCache::find_blob(pc); + if (cb == NULL || !cb->is_nmethod() || cb->is_frame_complete_at(pc)) { + // Not sure where the pc points to, fallback to default + // stack overflow handling + return false; + } else { + // In compiled code, the stack banging is performed before LR + // has been saved in the frame. LR is live, and SP and FP + // belong to the caller. + intptr_t* fp = os::Linux::ucontext_get_fp(uc); + intptr_t* sp = os::Linux::ucontext_get_sp(uc); + void* pc = (void*)(uc->uc_mcontext.regs[REG_LR] + - NativeInstruction::instruction_size); + *fr = frame(sp, fp, pc); + if (!fr->is_java_frame()) { + assert(fr->safe_for_sender(thread), "Safety check"); + assert(!fr->is_first_frame(), "Safety check"); + *fr = fr->java_sender(); + } + } + } + assert(fr->is_java_frame(), "Safety check"); + return true; +} + // By default, gcc always saves frame pointer rfp on this stack. This // may get turned off by -fomit-frame-pointer. frame os::get_sender_for_C_frame(frame* fr) { @@ -313,6 +354,24 @@ JVM_handle_linux_signal(int sig, if (thread->in_stack_yellow_reserved_zone(addr)) { thread->disable_stack_yellow_reserved_zone(); if (thread->thread_state() == _thread_in_Java) { + if (thread->in_stack_reserved_zone(addr)) { + frame fr; + if (os::Linux::get_frame_at_stack_banging_point(thread, uc, &fr)) { + assert(fr.is_java_frame(), "Must be a Java frame"); + frame activation = + SharedRuntime::look_for_reserved_stack_annotated_method(thread, fr); + if (activation.sp() != NULL) { + thread->disable_stack_reserved_zone(); + if (activation.is_interpreted_frame()) { + thread->set_reserved_stack_activation((address)( + activation.fp() + frame::interpreter_frame_initial_sp_offset)); + } else { + thread->set_reserved_stack_activation((address)activation.unextended_sp()); + } + return 1; + } + } + } // Throw a stack overflow exception. Guard pages will be reenabled // while unwinding the stack. stub = SharedRuntime::continuation_for_implicit_exception(thread, pc, SharedRuntime::STACK_OVERFLOW); diff --git a/hotspot/test/runtime/ReservedStack/ReservedStackTest.java b/hotspot/test/runtime/ReservedStack/ReservedStackTest.java index 216f731d2b7..c0ba4c1af9c 100644 --- a/hotspot/test/runtime/ReservedStack/ReservedStackTest.java +++ b/hotspot/test/runtime/ReservedStack/ReservedStackTest.java @@ -200,7 +200,8 @@ public class ReservedStackTest { boolean supportedPlatform = Platform.isAix() || (Platform.isLinux() && - (Platform.isPPC() || Platform.isS390x() || Platform.isX64() || Platform.isX86())) || + (Platform.isPPC() || Platform.isS390x() || Platform.isX64() || + Platform.isX86() || Platform.isAArch64())) || Platform.isOSX() || Platform.isSolaris(); if (supportedPlatform && !result.contains("PASSED")) { From 3ccbc26ee9dd89ef5443bbd0ba7bdcd7104de63f Mon Sep 17 00:00:00 2001 From: Dmitry Fazunenko Date: Thu, 12 Jan 2017 09:53:01 +0300 Subject: [PATCH 037/157] 8169643: [TESTBUG] GCBasher test fails with G1, CMS and Serial Reviewed-by: tschatzl, iignatyev, mchernov --- hotspot/test/gc/stress/gcbasher/TestGCBasherWithCMS.java | 4 ++-- hotspot/test/gc/stress/gcbasher/TestGCBasherWithG1.java | 4 ++-- hotspot/test/gc/stress/gcbasher/TestGCBasherWithSerial.java | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/hotspot/test/gc/stress/gcbasher/TestGCBasherWithCMS.java b/hotspot/test/gc/stress/gcbasher/TestGCBasherWithCMS.java index d22a7c49d62..c85acf5be82 100644 --- a/hotspot/test/gc/stress/gcbasher/TestGCBasherWithCMS.java +++ b/hotspot/test/gc/stress/gcbasher/TestGCBasherWithCMS.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2017, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -31,7 +31,7 @@ import java.io.IOException; * @requires vm.gc.ConcMarkSweep * @requires vm.flavor == "server" * @summary Stress the CMS GC by trying to make old objects more likely to be garbage than young objects. - * @run main/othervm/timeout=200 -Xlog:gc*=info -Xmx128m -server -XX:+UseConcMarkSweepGC TestGCBasherWithCMS 120000 + * @run main/othervm/timeout=200 -Xlog:gc*=info -Xmx256m -server -XX:+UseConcMarkSweepGC TestGCBasherWithCMS 120000 */ public class TestGCBasherWithCMS { public static void main(String[] args) throws IOException { diff --git a/hotspot/test/gc/stress/gcbasher/TestGCBasherWithG1.java b/hotspot/test/gc/stress/gcbasher/TestGCBasherWithG1.java index 6fe81c22ec7..0e87aa82c6b 100644 --- a/hotspot/test/gc/stress/gcbasher/TestGCBasherWithG1.java +++ b/hotspot/test/gc/stress/gcbasher/TestGCBasherWithG1.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2017, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -31,7 +31,7 @@ import java.io.IOException; * @requires vm.gc.G1 * @requires vm.flavor == "server" * @summary Stress the G1 GC by trying to make old objects more likely to be garbage than young objects. - * @run main/othervm/timeout=200 -Xlog:gc*=info -Xmx128m -server -XX:+UseG1GC TestGCBasherWithG1 120000 + * @run main/othervm/timeout=200 -Xlog:gc*=info -Xmx256m -server -XX:+UseG1GC TestGCBasherWithG1 120000 */ public class TestGCBasherWithG1 { public static void main(String[] args) throws IOException { diff --git a/hotspot/test/gc/stress/gcbasher/TestGCBasherWithSerial.java b/hotspot/test/gc/stress/gcbasher/TestGCBasherWithSerial.java index 0ba15ccb7cd..7ca865dd112 100644 --- a/hotspot/test/gc/stress/gcbasher/TestGCBasherWithSerial.java +++ b/hotspot/test/gc/stress/gcbasher/TestGCBasherWithSerial.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2017, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -31,7 +31,7 @@ import java.io.IOException; * @requires vm.gc.Serial * @requires vm.flavor == "server" * @summary Stress the Serial GC by trying to make old objects more likely to be garbage than young objects. - * @run main/othervm/timeout=200 -Xlog:gc*=info -Xmx128m -server -XX:+UseSerialGC TestGCBasherWithSerial 120000 + * @run main/othervm/timeout=200 -Xlog:gc*=info -Xmx256m -server -XX:+UseSerialGC TestGCBasherWithSerial 120000 */ public class TestGCBasherWithSerial { public static void main(String[] args) throws IOException { From 6037c36e675f773729e040e2c121ebd8040550b3 Mon Sep 17 00:00:00 2001 From: Andrew Haley Date: Thu, 12 Jan 2017 16:27:40 +0000 Subject: [PATCH 038/157] 8172721: Fix for 8172144 breaks AArch64 build Reviewed-by: dsamersoff --- hotspot/src/os_cpu/linux_aarch64/vm/os_linux_aarch64.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hotspot/src/os_cpu/linux_aarch64/vm/os_linux_aarch64.cpp b/hotspot/src/os_cpu/linux_aarch64/vm/os_linux_aarch64.cpp index 989f8aef17e..6d0a02fff6a 100644 --- a/hotspot/src/os_cpu/linux_aarch64/vm/os_linux_aarch64.cpp +++ b/hotspot/src/os_cpu/linux_aarch64/vm/os_linux_aarch64.cpp @@ -209,7 +209,7 @@ bool os::Linux::get_frame_at_stack_banging_point(JavaThread* thread, ucontext_t* // belong to the caller. intptr_t* fp = os::Linux::ucontext_get_fp(uc); intptr_t* sp = os::Linux::ucontext_get_sp(uc); - void* pc = (void*)(uc->uc_mcontext.regs[REG_LR] + address pc = (address)(uc->uc_mcontext.regs[REG_LR] - NativeInstruction::instruction_size); *fr = frame(sp, fp, pc); if (!fr->is_java_frame()) { From f0136f8b692afb8657e29b9ae61f549a32c9266c Mon Sep 17 00:00:00 2001 From: Rachel Protacio Date: Thu, 12 Jan 2017 14:04:08 -0500 Subject: [PATCH 039/157] 8170821: Ensure access checks result in consistent answers Added jtreg test to verify consistent access check results even when access is added between checks Reviewed-by: hseigel, lfoltan --- .../AccessCheck/AccessExportTwice.java | 146 +++++++++++++++++ .../modules/AccessCheck/AccessReadTwice.java | 154 ++++++++++++++++++ .../runtime/modules/AccessCheck/p4/c4.java | 35 ++++ 3 files changed, 335 insertions(+) create mode 100644 hotspot/test/runtime/modules/AccessCheck/AccessExportTwice.java create mode 100644 hotspot/test/runtime/modules/AccessCheck/AccessReadTwice.java create mode 100644 hotspot/test/runtime/modules/AccessCheck/p4/c4.java diff --git a/hotspot/test/runtime/modules/AccessCheck/AccessExportTwice.java b/hotspot/test/runtime/modules/AccessCheck/AccessExportTwice.java new file mode 100644 index 00000000000..a1eb2cce85d --- /dev/null +++ b/hotspot/test/runtime/modules/AccessCheck/AccessExportTwice.java @@ -0,0 +1,146 @@ +/* + * Copyright (c) 2017, 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 Class p1.c1 in an unnamed module cannot read p2.c2 in module second_mod, + * even after p2 is exported to all unnamed. Ensures constant + * access check answers when not accessible due to exportedness. + * @library /test/lib + * @modules java.base/jdk.internal.misc + * @modules java.base/jdk.internal.module + * @compile myloaders/MySameClassLoader.java + * @compile p2/c2.java + * @compile p1/c1.java + * @run main/othervm AccessExportTwice + */ + +import static jdk.test.lib.Asserts.*; + +import java.lang.module.Configuration; +import java.lang.module.ModuleDescriptor; +import java.lang.module.ModuleFinder; +import java.lang.reflect.Layer; +import java.lang.reflect.Module; +import java.util.HashMap; +import java.util.Map; +import java.util.Set; +import myloaders.MySameClassLoader; + +// +// ClassLoader1 --> defines first_mod --> no packages +// defines second_mod --> packages p2 +// +// first_mod can read second_mod +// package p2 in second_mod is exported to first_mod +// +// class p1.c1 defined in an unnamed module tries to access p2.c2 defined in second_mod +// Access is not allowed, even after p2 is exported to all unnamed modules. + +public class AccessExportTwice { + + // Create a Layer over the boot layer. + // Define modules within this layer to test access between + // publicly defined classes within packages of those modules. + public void createLayerOnBoot() throws Throwable { + + // Define module: first_mod + // Can read: java.base, second_mod + // Packages: none + // Packages exported: none + ModuleDescriptor descriptor_first_mod = + ModuleDescriptor.module("first_mod") + .requires("java.base") + .requires("second_mod") + .build(); + + // Define module: second_mod + // Can read: java.base + // Packages: p2 + // Packages exported: p2 is exported to first_mod + ModuleDescriptor descriptor_second_mod = + ModuleDescriptor.module("second_mod") + .requires("java.base") + .exports("p2", Set.of("first_mod")) + .build(); + + // Set up a ModuleFinder containing all modules for this layer + ModuleFinder finder = ModuleLibrary.of(descriptor_first_mod, descriptor_second_mod); + + // Resolves "first_mod" + Configuration cf = Layer.boot() + .configuration() + .resolveRequires(finder, ModuleFinder.of(), Set.of("first_mod")); + + // Map each module to the same class loader + Map map = new HashMap<>(); + map.put("first_mod", MySameClassLoader.loader1); + map.put("second_mod", MySameClassLoader.loader1); + + // Create Layer that contains first_mod & second_mod + Layer layer = Layer.boot().defineModules(cf, map::get); + + assertTrue(layer.findLoader("first_mod") == MySameClassLoader.loader1); + assertTrue(layer.findLoader("second_mod") == MySameClassLoader.loader1); + assertTrue(layer.findLoader("java.base") == null); + + Class p2_c2_class = MySameClassLoader.loader1.loadClass("p2.c2"); + // Use the same loader to load class p1.c1 + Class p1_c1_class = MySameClassLoader.loader1.loadClass("p1.c1"); + // First access check for p1.c1 + try { + p1_c1_class.newInstance(); + throw new RuntimeException("Test Failed, the unnamed module should not have access to public type p2.c2"); + } catch (IllegalAccessError e) { + String message = e.getMessage(); + if (!(message.contains("cannot access") && + message.contains("because module second_mod does not export p2 to unnamed module"))) { + throw new RuntimeException("Wrong message: " + message); + } else { + System.out.println("Test Succeeded at attempt #1"); + } + } + + // Export second_mod/p2 to all unnamed modules. + Module second_mod = p2_c2_class.getModule(); + jdk.internal.module.Modules.addExportsToAllUnnamed(second_mod, "p2"); + + // Second access check for p1.c1, should have same result as first + try { + p1_c1_class.newInstance(); + throw new RuntimeException("Test Failed, access should have been cached above"); + } catch (IllegalAccessError e) { + String message = e.getMessage(); + if (!(message.contains("cannot access") && + message.contains("because module second_mod does not export p2 to unnamed module"))) { + throw new RuntimeException("Wrong message: " + message); + } else { + System.out.println("Test Succeeded at attempt #2"); + } + } + } + + public static void main(String args[]) throws Throwable { + AccessExportTwice test = new AccessExportTwice(); + test.createLayerOnBoot(); + } +} diff --git a/hotspot/test/runtime/modules/AccessCheck/AccessReadTwice.java b/hotspot/test/runtime/modules/AccessCheck/AccessReadTwice.java new file mode 100644 index 00000000000..5d1a690a740 --- /dev/null +++ b/hotspot/test/runtime/modules/AccessCheck/AccessReadTwice.java @@ -0,0 +1,154 @@ +/* + * Copyright (c) 2017, 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 Class p1.c1 in module first_mod cannot read p2.c2 in module second_mod, + * even after a read edge is added between first_mod and second_mod. + * Ensures constant access check answers when not accessible due to readability. + * @library /test/lib + * @modules java.base/jdk.internal.misc + * @modules java.base/jdk.internal.module + * @compile p2/c2.java + * @compile p1/c1.java + * @compile p4/c4.java + * @run main/othervm AccessReadTwice + */ + +import static jdk.test.lib.Asserts.*; + +import java.lang.module.Configuration; +import java.lang.module.ModuleDescriptor; +import java.lang.module.ModuleFinder; +import java.lang.reflect.Layer; +import java.lang.reflect.Module; +import java.util.HashMap; +import java.util.Map; +import java.util.Set; + +// +// ClassLoader1 --> defines first_mod --> packages p1, p4 +// defines second_mod --> package p2 +// +// package p2 in second_mod is exported to first_mod +// +// class p1.c1 defined in first_mod tries to access p2.c2 defined in second_mod +// Access is not allowed, even after a read edge is added between first_mod and second_mod. + +public class AccessReadTwice { + + // Create a Layer over the boot layer. + // Define modules within this layer to test access between + // publicly defined classes within packages of those modules. + public void createLayerOnBoot() throws Throwable { + + // Define module: first_mod + // Can read: java.base + // Packages: p1, p4 + // Packages exported: none + ModuleDescriptor descriptor_first_mod = + ModuleDescriptor.module("first_mod") + .requires("java.base") + .contains(Set.of("p1", "p4")) + .build(); + + // Define module: second_mod + // Can read: java.base + // Packages: p2 + // Packages exported: p2 is exported to first_mod + ModuleDescriptor descriptor_second_mod = + ModuleDescriptor.module("second_mod") + .requires("java.base") + .exports("p2", Set.of("first_mod")) + .build(); + + // Set up a ModuleFinder containing all modules for this layer + ModuleFinder finder = ModuleLibrary.of(descriptor_first_mod, descriptor_second_mod); + + // Resolves "first_mod" and "second_mod" + Configuration cf = Layer.boot() + .configuration() + .resolveRequires(finder, ModuleFinder.of(), Set.of("first_mod", "second_mod")); + + // Map each module to this class loader + Map map = new HashMap<>(); + ClassLoader loader = AccessReadTwice.class.getClassLoader(); + map.put("first_mod", loader); + map.put("second_mod", loader); + + // Create Layer that contains first_mod & second_mod + Layer layer = Layer.boot().defineModules(cf, map::get); + + assertTrue(layer.findLoader("first_mod") == loader); + assertTrue(layer.findLoader("second_mod") == loader); + assertTrue(layer.findLoader("java.base") == null); + + Class p2_c2_class = loader.loadClass("p2.c2"); + Class p1_c1_class = loader.loadClass("p1.c1"); + Class p4_c4_class = loader.loadClass("p4.c4"); + + Module first_mod = p1_c1_class.getModule(); + Module second_mod = p2_c2_class.getModule(); + + // Export first_mod/p1 and first_mod/p4 to all unnamed modules so that + // this test can use them + jdk.internal.module.Modules.addExportsToAllUnnamed(first_mod, "p1"); + jdk.internal.module.Modules.addExportsToAllUnnamed(first_mod, "p4"); + + // First access check for p1.c1 + try { + p1_c1_class.newInstance(); + throw new RuntimeException("Test Failed, module first_mod should not have access to p2.c2"); + } catch (IllegalAccessError e) { + String message = e.getMessage(); + if (!(message.contains("cannot access") && + message.contains("because module first_mod does not read module second_mod"))) { + throw new RuntimeException("Wrong message: " + message); + } else { + System.out.println("Test Succeeded at attempt #1"); + } + } + + // Add a read edge from p4/c4's module (first_mod) to second_mod + p4.c4 c4_obj = new p4.c4(); + c4_obj.addReads(second_mod); + + // Second access check for p1.c1, should have same result as first + try { + p1_c1_class.newInstance(); + throw new RuntimeException("Test Failed, access should have been cached above"); + } catch (IllegalAccessError e) { + String message = e.getMessage(); + if (!(message.contains("cannot access") && + message.contains("because module first_mod does not read module second_mod"))) { + throw new RuntimeException("Wrong message: " + message); + } else { + System.out.println("Test Succeeded at attempt #2"); + } + } + } + + public static void main(String args[]) throws Throwable { + AccessReadTwice test = new AccessReadTwice(); + test.createLayerOnBoot(); + } +} diff --git a/hotspot/test/runtime/modules/AccessCheck/p4/c4.java b/hotspot/test/runtime/modules/AccessCheck/p4/c4.java new file mode 100644 index 00000000000..d0098674672 --- /dev/null +++ b/hotspot/test/runtime/modules/AccessCheck/p4/c4.java @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2017, 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. + */ + +// Small class used by multiple hotspot/runtime/modules/AccessCheck/* tests. + +package p4; + +import java.lang.reflect.Module; + +public class c4 { + // Add a read edge from c4's module to given module m + public void addReads(Module m) { + c4.class.getModule().addReads(m); + } +} From c95329970d5361a541935c5a9a01b97127a1ba33 Mon Sep 17 00:00:00 2001 From: Harold Seigel Date: Fri, 13 Jan 2017 07:19:03 -0500 Subject: [PATCH 040/157] 8172288: Fix Jigsaw related module/package error messages and throw correct exceptions Reword error messages and throw IllegalStateExceptions where appropriate Reviewed-by: alanb, acorn, lfoltan, gtriantafill --- hotspot/src/share/vm/classfile/modules.cpp | 49 +++++++++++-------- .../runtime/modules/JVMAddModulePackage.java | 8 +-- .../test/runtime/modules/JVMDefineModule.java | 24 ++++----- 3 files changed, 44 insertions(+), 37 deletions(-) diff --git a/hotspot/src/share/vm/classfile/modules.cpp b/hotspot/src/share/vm/classfile/modules.cpp index becda5363a6..34f32df8ea3 100644 --- a/hotspot/src/share/vm/classfile/modules.cpp +++ b/hotspot/src/share/vm/classfile/modules.cpp @@ -1,5 +1,5 @@ /* -* Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. +* Copyright (c) 2017, 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 @@ -239,7 +239,7 @@ static void define_javabase_module(jobject module, jstring version, } } if (duplicate_javabase) { - THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(), + THROW_MSG(vmSymbols::java_lang_InternalError(), "Module " JAVA_BASE_NAME " is already defined"); } @@ -262,6 +262,20 @@ static void define_javabase_module(jobject module, jstring version, } } +// Caller needs ResourceMark. +void throw_dup_pkg_exception(const char* module_name, PackageEntry* package, TRAPS) { + const char* package_name = package->name()->as_C_string(); + if (package->module()->is_named()) { + THROW_MSG(vmSymbols::java_lang_IllegalStateException(), + err_msg("Package %s for module %s is already in another module, %s, defined to the class loader", + package_name, module_name, package->module()->name()->as_C_string())); + } else { + THROW_MSG(vmSymbols::java_lang_IllegalStateException(), + err_msg("Package %s for module %s is already in the unnamed module defined to the class loader", + package_name, module_name)); + } +} + void Modules::define_module(jobject module, jstring version, jstring location, jobjectArray packages, TRAPS) { ResourceMark rm(THREAD); @@ -347,7 +361,6 @@ void Modules::define_module(jobject module, jstring version, // Create symbol* entry for module name. TempNewSymbol module_symbol = SymbolTable::new_symbol(module_name, CHECK); - int dupl_pkg_index = -1; bool dupl_modules = false; // Create symbol* entry for module version. @@ -373,6 +386,7 @@ void Modules::define_module(jobject module, jstring version, assert(loader_data != NULL, "class loader data shouldn't be null"); PackageEntryTable* package_table = NULL; + PackageEntry* existing_pkg = NULL; { MutexLocker ml(Module_lock, THREAD); @@ -382,13 +396,12 @@ void Modules::define_module(jobject module, jstring version, // Check that none of the packages exist in the class loader's package table. for (int x = 0; x < pkg_list->length(); x++) { - if (package_table->lookup_only(pkg_list->at(x)) != NULL) { + existing_pkg = package_table->lookup_only(pkg_list->at(x)); + if (existing_pkg != NULL) { // This could be because the module was already defined. If so, // report that error instead of the package error. if (module_table->lookup_only(module_symbol) != NULL) { dupl_modules = true; - } else { - dupl_pkg_index = x; } break; } @@ -396,9 +409,8 @@ void Modules::define_module(jobject module, jstring version, } // if (num_packages > 0)... // Add the module and its packages. - if (!dupl_modules && dupl_pkg_index == -1) { + if (!dupl_modules && existing_pkg == NULL) { // Create the entry for this module in the class loader's module entry table. - ModuleEntry* module_entry = module_table->locked_create_entry_or_null(module_handle, module_symbol, version_symbol, location_symbol, loader_data); @@ -426,13 +438,10 @@ void Modules::define_module(jobject module, jstring version, // any errors ? if (dupl_modules) { - THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(), + THROW_MSG(vmSymbols::java_lang_IllegalStateException(), err_msg("Module %s is already defined", module_name)); - } - if (dupl_pkg_index != -1) { - THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(), - err_msg("Package %s for module %s already exists for class loader", - pkg_list->at(dupl_pkg_index)->as_C_string(), module_name)); + } else if (existing_pkg != NULL) { + throw_dup_pkg_exception(module_name, existing_pkg, CHECK); } if (log_is_enabled(Debug, modules)) { @@ -776,21 +785,19 @@ void Modules::add_module_package(jobject module, jstring package, TRAPS) { PackageEntryTable* package_table = loader_data->packages(); assert(package_table != NULL, "Missing package_table"); - bool pkg_exists = false; + PackageEntry* existing_pkg = NULL; { MutexLocker ml(Module_lock, THREAD); // Check that the package does not exist in the class loader's package table. - if (!package_table->lookup_only(pkg_symbol)) { + existing_pkg = package_table->lookup_only(pkg_symbol); + if (existing_pkg == NULL) { PackageEntry* pkg = package_table->locked_create_entry_or_null(pkg_symbol, module_entry); assert(pkg != NULL, "Unable to create a module's package entry"); - } else { - pkg_exists = true; } } - if (pkg_exists) { - THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(), - err_msg("Package %s already exists for class loader", package_name)); + if (existing_pkg != NULL) { + throw_dup_pkg_exception(module_entry->name()->as_C_string(), existing_pkg, CHECK); } } diff --git a/hotspot/test/runtime/modules/JVMAddModulePackage.java b/hotspot/test/runtime/modules/JVMAddModulePackage.java index 62106f8597f..3f7f2fd29a0 100644 --- a/hotspot/test/runtime/modules/JVMAddModulePackage.java +++ b/hotspot/test/runtime/modules/JVMAddModulePackage.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 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 @@ -84,11 +84,11 @@ public class JVMAddModulePackage { // Expected } - // Existing package, expect an IAE + // Existing package, expect an ISE try { ModuleHelper.AddModulePackage(module1, "yourpackage"); - throw new RuntimeException("Failed to get the expected IAE"); - } catch(IllegalArgumentException e) { + throw new RuntimeException("Failed to get the expected ISE"); + } catch(IllegalStateException e) { // Expected } diff --git a/hotspot/test/runtime/modules/JVMDefineModule.java b/hotspot/test/runtime/modules/JVMDefineModule.java index dd19770ee98..9e44878490d 100644 --- a/hotspot/test/runtime/modules/JVMDefineModule.java +++ b/hotspot/test/runtime/modules/JVMDefineModule.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 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 @@ -127,27 +127,27 @@ public class JVMDefineModule { } } - // Duplicate module name, expect an IAE - m = ModuleHelper.ModuleObject("module.name", cl, new String[] { "mypackage6" }); + // Duplicate module name, expect an ISE + m = ModuleHelper.ModuleObject("Module_A", cl, new String[] { "mypackage6" }); assertNotNull(m, "Module should not be null"); ModuleHelper.DefineModule(m, "9.0", "module.name/here", new String[] { "mypackage6" }); try { ModuleHelper.DefineModule(m, "9.0", "module.name/here", new String[] { "mypackage6a" }); - throw new RuntimeException("Failed to get IAE for duplicate module"); - } catch(IllegalArgumentException e) { - if (!e.getMessage().contains("Module module.name is already defined")) { - throw new RuntimeException("Failed to get expected IAE message for duplicate module: " + e.getMessage()); + throw new RuntimeException("Failed to get ISE for duplicate module"); + } catch(IllegalStateException e) { + if (!e.getMessage().contains("Module Module_A is already defined")) { + throw new RuntimeException("Failed to get expected ISE message for duplicate module: " + e.getMessage()); } } - // Package is already defined for class loader, expect an IAE + // Package is already defined for class loader, expect an ISE m = ModuleHelper.ModuleObject("dupl.pkg.module", cl, new String[] { "mypackage6b" }); try { ModuleHelper.DefineModule(m, "9.0", "module.name/here", new String[] { "mypackage6" }); - throw new RuntimeException("Failed to get IAE for existing package"); - } catch(IllegalArgumentException e) { - if (!e.getMessage().contains("Package mypackage6 for module dupl.pkg.module already exists for class loader")) { - throw new RuntimeException("Failed to get expected IAE message for duplicate package: " + e.getMessage()); + throw new RuntimeException("Failed to get ISE for existing package"); + } catch(IllegalStateException e) { + if (!e.getMessage().contains("Package mypackage6 for module dupl.pkg.module is already in another module, Module_A, defined to the class loader")) { + throw new RuntimeException("Failed to get expected ISE message for duplicate package: " + e.getMessage()); } } From cc5730af708ac0ff43db2051e474a8f748457610 Mon Sep 17 00:00:00 2001 From: Alexander Harlap Date: Fri, 13 Jan 2017 12:27:54 -0500 Subject: [PATCH 041/157] 8140588: Internal Error: gc/g1/ptrQueue.hpp:126 assert(_index == _sz) failed: invariant: queues are empty when activated Re-check queue active state before updating Reviewed-by: pliden, kbarrett, mdoerr --- .../src/cpu/aarch64/vm/c1_Runtime1_aarch64.cpp | 11 ++++++++++- hotspot/src/cpu/arm/vm/c1_Runtime1_arm.cpp | 9 ++++++++- hotspot/src/cpu/ppc/vm/c1_Runtime1_ppc.cpp | 18 ++++++++++++++++-- hotspot/src/cpu/s390/vm/c1_Runtime1_s390.cpp | 17 +++++++++++++++-- hotspot/src/cpu/sparc/vm/c1_Runtime1_sparc.cpp | 17 +++++++++++++++-- hotspot/src/cpu/x86/vm/c1_Runtime1_x86.cpp | 13 ++++++++++++- 6 files changed, 76 insertions(+), 9 deletions(-) diff --git a/hotspot/src/cpu/aarch64/vm/c1_Runtime1_aarch64.cpp b/hotspot/src/cpu/aarch64/vm/c1_Runtime1_aarch64.cpp index 58ba9c0b613..8c83dc4125c 100644 --- a/hotspot/src/cpu/aarch64/vm/c1_Runtime1_aarch64.cpp +++ b/hotspot/src/cpu/aarch64/vm/c1_Runtime1_aarch64.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2017, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2014, Red Hat Inc. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -1179,6 +1179,15 @@ OopMapSet* Runtime1::generate_code_for(StubID id, StubAssembler* sasm) { Label done; Label runtime; + // Is marking still active? + if (in_bytes(SATBMarkQueue::byte_width_of_active()) == 4) { + __ ldrw(tmp, in_progress); + } else { + assert(in_bytes(SATBMarkQueue::byte_width_of_active()) == 1, "Assumption"); + __ ldrb(tmp, in_progress); + } + __ cbzw(tmp, done); + // Can we store original value in the thread's buffer? __ ldr(tmp, queue_index); __ cbz(tmp, runtime); diff --git a/hotspot/src/cpu/arm/vm/c1_Runtime1_arm.cpp b/hotspot/src/cpu/arm/vm/c1_Runtime1_arm.cpp index 937dfe91242..9f17c8fc810 100644 --- a/hotspot/src/cpu/arm/vm/c1_Runtime1_arm.cpp +++ b/hotspot/src/cpu/arm/vm/c1_Runtime1_arm.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2008, 2017, 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 @@ -551,6 +551,8 @@ OopMapSet* Runtime1::generate_code_for(StubID id, StubAssembler* sasm) { const Register r_index_1 = R1; const Register r_buffer_2 = R2; + Address queue_active(Rthread, in_bytes(JavaThread::satb_mark_queue_offset() + + SATBMarkQueue::byte_offset_of_active())); Address queue_index(Rthread, in_bytes(JavaThread::satb_mark_queue_offset() + SATBMarkQueue::byte_offset_of_index())); Address buffer(Rthread, in_bytes(JavaThread::satb_mark_queue_offset() + @@ -559,6 +561,11 @@ OopMapSet* Runtime1::generate_code_for(StubID id, StubAssembler* sasm) { Label done; Label runtime; + // Is marking still active? + assert(in_bytes(SATBMarkQueue::byte_width_of_active()) == 1, "Assumption"); + __ ldrb(R1, queue_active); + __ cbz(R1, done); + __ ldr(r_index_1, queue_index); __ ldr(r_pre_val_0, Address(SP, nb_saved_regs*wordSize)); __ ldr(r_buffer_2, buffer); diff --git a/hotspot/src/cpu/ppc/vm/c1_Runtime1_ppc.cpp b/hotspot/src/cpu/ppc/vm/c1_Runtime1_ppc.cpp index 1aa158b4a8f..3562a79825f 100644 --- a/hotspot/src/cpu/ppc/vm/c1_Runtime1_ppc.cpp +++ b/hotspot/src/cpu/ppc/vm/c1_Runtime1_ppc.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2017, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2012, 2015 SAP SE. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -741,7 +741,10 @@ OopMapSet* Runtime1::generate_code_for(StubID id, StubAssembler* sasm) { Register tmp = R14; Register tmp2 = R15; - Label refill, restart; + Label refill, restart, marking_not_active; + int satb_q_active_byte_offset = + in_bytes(JavaThread::satb_mark_queue_offset() + + SATBMarkQueue::byte_offset_of_active()); int satb_q_index_byte_offset = in_bytes(JavaThread::satb_mark_queue_offset() + SATBMarkQueue::byte_offset_of_index()); @@ -753,6 +756,16 @@ OopMapSet* Runtime1::generate_code_for(StubID id, StubAssembler* sasm) { __ std(tmp, -16, R1_SP); __ std(tmp2, -24, R1_SP); + // Is marking still active? + if (in_bytes(SATBMarkQueue::byte_width_of_active()) == 4) { + __ lwz(tmp, satb_q_active_byte_offset, R16_thread); + } else { + assert(in_bytes(SATBMarkQueue::byte_width_of_active()) == 1, "Assumption"); + __ lbz(tmp, satb_q_active_byte_offset, R16_thread); + } + __ cmpdi(CCR0, tmp, 0); + __ beq(CCR0, marking_not_active); + __ bind(restart); // Load the index into the SATB buffer. SATBMarkQueue::_index is a // size_t so ld_ptr is appropriate. @@ -769,6 +782,7 @@ OopMapSet* Runtime1::generate_code_for(StubID id, StubAssembler* sasm) { __ std(tmp, satb_q_index_byte_offset, R16_thread); __ stdx(pre_val, tmp2, tmp); // [_buf + index] := + __ bind(marking_not_active); // Restore temp registers and return-from-leaf. __ ld(tmp2, -24, R1_SP); __ ld(tmp, -16, R1_SP); diff --git a/hotspot/src/cpu/s390/vm/c1_Runtime1_s390.cpp b/hotspot/src/cpu/s390/vm/c1_Runtime1_s390.cpp index c0fbee53da7..7b65476212f 100644 --- a/hotspot/src/cpu/s390/vm/c1_Runtime1_s390.cpp +++ b/hotspot/src/cpu/s390/vm/c1_Runtime1_s390.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2017 Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2016 SAP SE. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -784,7 +784,10 @@ OopMapSet* Runtime1::generate_code_for(StubID id, StubAssembler* sasm) { Register tmp = Z_R6; // Must be non-volatile because it is used to save pre_val. Register tmp2 = Z_R7; - Label refill, restart; + Label refill, restart, marking_not_active; + int satb_q_active_byte_offset = + in_bytes(JavaThread::satb_mark_queue_offset() + + SATBMarkQueue::byte_offset_of_active()); int satb_q_index_byte_offset = in_bytes(JavaThread::satb_mark_queue_offset() + SATBMarkQueue::byte_offset_of_index()); @@ -796,6 +799,15 @@ OopMapSet* Runtime1::generate_code_for(StubID id, StubAssembler* sasm) { __ z_stg(tmp, 0*BytesPerWord + FrameMap::first_available_sp_in_frame, Z_SP); __ z_stg(tmp2, 1*BytesPerWord + FrameMap::first_available_sp_in_frame, Z_SP); + // Is marking still active? + if (in_bytes(SATBMarkQueue::byte_width_of_active()) == 4) { + __ load_and_test_int(tmp, Address(Z_thread, satb_q_active_byte_offset)); + } else { + assert(in_bytes(SATBMarkQueue::byte_width_of_active()) == 1, "Assumption"); + __ load_and_test_byte(tmp, Address(Z_thread, satb_q_active_byte_offset)); + } + __ z_bre(marking_not_active); // Activity indicator is zero, so there is no marking going on currently. + __ bind(restart); // Load the index into the SATB buffer. SATBMarkQueue::_index is a // size_t so ld_ptr is appropriate. @@ -810,6 +822,7 @@ OopMapSet* Runtime1::generate_code_for(StubID id, StubAssembler* sasm) { __ z_stg(pre_val, 0, tmp, tmp2); // [_buf + index] := __ z_stg(tmp, satb_q_index_byte_offset, Z_thread); + __ bind(marking_not_active); // Restore tmp registers (see assertion in G1PreBarrierStub::emit_code()). __ z_lg(tmp, 0*BytesPerWord + FrameMap::first_available_sp_in_frame, Z_SP); __ z_lg(tmp2, 1*BytesPerWord + FrameMap::first_available_sp_in_frame, Z_SP); diff --git a/hotspot/src/cpu/sparc/vm/c1_Runtime1_sparc.cpp b/hotspot/src/cpu/sparc/vm/c1_Runtime1_sparc.cpp index 5530a85cb4c..40e30551967 100644 --- a/hotspot/src/cpu/sparc/vm/c1_Runtime1_sparc.cpp +++ b/hotspot/src/cpu/sparc/vm/c1_Runtime1_sparc.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2017, 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 @@ -856,7 +856,9 @@ OopMapSet* Runtime1::generate_code_for(StubID id, StubAssembler* sasm) { Register tmp2 = G3_scratch; Label refill, restart; - bool with_frame = false; // I don't know if we can do with-frame. + int satb_q_active_byte_offset = + in_bytes(JavaThread::satb_mark_queue_offset() + + SATBMarkQueue::byte_offset_of_active()); int satb_q_index_byte_offset = in_bytes(JavaThread::satb_mark_queue_offset() + SATBMarkQueue::byte_offset_of_index()); @@ -864,6 +866,17 @@ OopMapSet* Runtime1::generate_code_for(StubID id, StubAssembler* sasm) { in_bytes(JavaThread::satb_mark_queue_offset() + SATBMarkQueue::byte_offset_of_buf()); + // Is marking still active? + if (in_bytes(SATBMarkQueue::byte_width_of_active()) == 4) { + __ ld(G2_thread, satb_q_active_byte_offset, tmp); + } else { + assert(in_bytes(SATBMarkQueue::byte_width_of_active()) == 1, "Assumption"); + __ ldsb(G2_thread, satb_q_active_byte_offset, tmp); + } + __ cmp_and_br_short(tmp, G0, Assembler::notEqual, Assembler::pt, restart); + __ retl(); + __ delayed()->nop(); + __ bind(restart); // Load the index into the SATB buffer. SATBMarkQueue::_index is a // size_t so ld_ptr is appropriate diff --git a/hotspot/src/cpu/x86/vm/c1_Runtime1_x86.cpp b/hotspot/src/cpu/x86/vm/c1_Runtime1_x86.cpp index 5fe455600d1..58db92dcd32 100644 --- a/hotspot/src/cpu/x86/vm/c1_Runtime1_x86.cpp +++ b/hotspot/src/cpu/x86/vm/c1_Runtime1_x86.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2017, 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 @@ -1623,6 +1623,8 @@ OopMapSet* Runtime1::generate_code_for(StubID id, StubAssembler* sasm) { NOT_LP64(__ get_thread(thread);) + Address queue_active(thread, in_bytes(JavaThread::satb_mark_queue_offset() + + SATBMarkQueue::byte_offset_of_active())); Address queue_index(thread, in_bytes(JavaThread::satb_mark_queue_offset() + SATBMarkQueue::byte_offset_of_index())); Address buffer(thread, in_bytes(JavaThread::satb_mark_queue_offset() + @@ -1631,6 +1633,15 @@ OopMapSet* Runtime1::generate_code_for(StubID id, StubAssembler* sasm) { Label done; Label runtime; + // Is marking still active? + if (in_bytes(SATBMarkQueue::byte_width_of_active()) == 4) { + __ cmpl(queue_active, 0); + } else { + assert(in_bytes(SATBMarkQueue::byte_width_of_active()) == 1, "Assumption"); + __ cmpb(queue_active, 0); + } + __ jcc(Assembler::equal, done); + // Can we store original value in the thread's buffer? __ movptr(tmp, queue_index); From 3cfbc5a63058554c31dc9c8f5eda011119e18fc2 Mon Sep 17 00:00:00 2001 From: Rachel Protacio Date: Fri, 13 Jan 2017 16:49:34 -0500 Subject: [PATCH 042/157] 8170827: Correct errant "java.base" string to macro Used JAVA_BASE_NAME instead of "java.base" string in one location Reviewed-by: coleenp, jiangli --- hotspot/src/share/vm/runtime/os.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/hotspot/src/share/vm/runtime/os.cpp b/hotspot/src/share/vm/runtime/os.cpp index 18359effe52..e3463ae56e5 100644 --- a/hotspot/src/share/vm/runtime/os.cpp +++ b/hotspot/src/share/vm/runtime/os.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2017, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,6 +25,7 @@ #include "precompiled.hpp" #include "classfile/classLoader.hpp" #include "classfile/javaClasses.hpp" +#include "classfile/moduleEntry.hpp" #include "classfile/systemDictionary.hpp" #include "classfile/vmSymbols.hpp" #include "code/codeCache.hpp" @@ -1229,7 +1230,7 @@ bool os::set_boot_path(char fileSep, char pathSep) { FREE_C_HEAP_ARRAY(char, jimage); // check if developer build with exploded modules - char* base_classes = format_boot_path("%/modules/java.base", home, home_len, fileSep, pathSep); + char* base_classes = format_boot_path("%/modules/" JAVA_BASE_NAME, home, home_len, fileSep, pathSep); if (base_classes == NULL) return false; if (os::stat(base_classes, &st) == 0) { Arguments::set_sysclasspath(base_classes, false); From 09dee71ddd9358bdeb30051589112463d0717d26 Mon Sep 17 00:00:00 2001 From: Tobias Hartmann Date: Tue, 17 Jan 2017 08:53:42 +0100 Subject: [PATCH 043/157] 8172731: runtime/Thread/TooSmallStackSize.java fails on solaris-x64 with product build The C2 compiler threads require a large stack with the Solaris Studio C++ compiler version 5.13 and product VM build. Reviewed-by: sspitsyn, dcubed, goetz, dholmes --- hotspot/src/os_cpu/solaris_x86/vm/os_solaris_x86.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/hotspot/src/os_cpu/solaris_x86/vm/os_solaris_x86.cpp b/hotspot/src/os_cpu/solaris_x86/vm/os_solaris_x86.cpp index f5c0ff370a0..5fcd2de83df 100644 --- a/hotspot/src/os_cpu/solaris_x86/vm/os_solaris_x86.cpp +++ b/hotspot/src/os_cpu/solaris_x86/vm/os_solaris_x86.cpp @@ -89,7 +89,10 @@ // Minimum usable stack sizes required to get to user code. Space for // HotSpot guard pages is added later. #ifdef _LP64 -size_t os::Posix::_compiler_thread_min_stack_allowed = 202 * K; +// The adlc generated method 'State::MachNodeGenerator(int)' used by the C2 compiler +// threads requires a large stack with the Solaris Studio C++ compiler version 5.13 +// and product VM builds (debug builds require significantly less stack space). +size_t os::Posix::_compiler_thread_min_stack_allowed = 325 * K; size_t os::Posix::_java_thread_min_stack_allowed = 48 * K; size_t os::Posix::_vm_internal_thread_min_stack_allowed = 224 * K; #else From 2bc33c2996c239ee8d912375e54ea7e36644d682 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Markus=20Gr=C3=B6nlund?= Date: Tue, 17 Jan 2017 16:18:03 +0100 Subject: [PATCH 044/157] 8171960: Event-based tracing needs separate flag representation for Method Reviewed-by: hseigel, gtriantafill, dholmes --- .../hotspot/GraalHotSpotVMConfig.java | 1 - .../src/share/vm/jvmci/vmStructs_jvmci.cpp | 1 - hotspot/src/share/vm/oops/method.cpp | 1 - hotspot/src/share/vm/oops/method.hpp | 28 ++++++++----------- hotspot/src/share/vm/runtime/vmStructs.cpp | 1 - hotspot/src/share/vm/trace/traceMacros.hpp | 2 ++ 6 files changed, 14 insertions(+), 20 deletions(-) diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/GraalHotSpotVMConfig.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/GraalHotSpotVMConfig.java index 4400099efc5..4bfd1fbbed3 100644 --- a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/GraalHotSpotVMConfig.java +++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/GraalHotSpotVMConfig.java @@ -479,7 +479,6 @@ public class GraalHotSpotVMConfig extends HotSpotVMConfigAccess { public final int methodCompiledEntryOffset = getFieldOffset("Method::_from_compiled_entry", Integer.class, "address"); public final int methodCodeOffset = getFieldOffset("Method::_code", Integer.class, isJDK8 ? "nmethod*" : "CompiledMethod*"); - public final int methodFlagsJfrTowrite = getConstant("Method::_jfr_towrite", Integer.class); public final int methodFlagsCallerSensitive = getConstant("Method::_caller_sensitive", Integer.class); public final int methodFlagsForceInline = getConstant("Method::_force_inline", Integer.class); public final int methodFlagsDontInline = getConstant("Method::_dont_inline", Integer.class); diff --git a/hotspot/src/share/vm/jvmci/vmStructs_jvmci.cpp b/hotspot/src/share/vm/jvmci/vmStructs_jvmci.cpp index 5c69ecb4d65..a01651f55aa 100644 --- a/hotspot/src/share/vm/jvmci/vmStructs_jvmci.cpp +++ b/hotspot/src/share/vm/jvmci/vmStructs_jvmci.cpp @@ -535,7 +535,6 @@ \ declare_constant(markOopDesc::no_hash) \ \ - declare_constant(Method::_jfr_towrite) \ declare_constant(Method::_caller_sensitive) \ declare_constant(Method::_force_inline) \ declare_constant(Method::_dont_inline) \ diff --git a/hotspot/src/share/vm/oops/method.cpp b/hotspot/src/share/vm/oops/method.cpp index 4e3dcf03bd8..f37278edd13 100644 --- a/hotspot/src/share/vm/oops/method.cpp +++ b/hotspot/src/share/vm/oops/method.cpp @@ -85,7 +85,6 @@ Method::Method(ConstMethod* xconst, AccessFlags access_flags) { set_constMethod(xconst); set_access_flags(access_flags); set_intrinsic_id(vmIntrinsics::_none); - set_jfr_towrite(false); set_force_inline(false); set_hidden(false); set_dont_inline(false); diff --git a/hotspot/src/share/vm/oops/method.hpp b/hotspot/src/share/vm/oops/method.hpp index 1c6e72df0fc..ebd5f0feef2 100644 --- a/hotspot/src/share/vm/oops/method.hpp +++ b/hotspot/src/share/vm/oops/method.hpp @@ -75,18 +75,19 @@ class Method : public Metadata { // Flags enum Flags { - _jfr_towrite = 1 << 0, - _caller_sensitive = 1 << 1, - _force_inline = 1 << 2, - _dont_inline = 1 << 3, - _hidden = 1 << 4, - _has_injected_profile = 1 << 5, - _running_emcp = 1 << 6, - _intrinsic_candidate = 1 << 7, - _reserved_stack_access = 1 << 8 + _caller_sensitive = 1 << 0, + _force_inline = 1 << 1, + _dont_inline = 1 << 2, + _hidden = 1 << 3, + _has_injected_profile = 1 << 4, + _running_emcp = 1 << 5, + _intrinsic_candidate = 1 << 6, + _reserved_stack_access = 1 << 7 }; mutable u2 _flags; + TRACE_DEFINE_FLAG; + #ifndef PRODUCT int _compiled_invocation_count; // Number of nmethod invocations so far (for perf. debugging) #endif @@ -833,13 +834,6 @@ class Method : public Metadata { void init_intrinsic_id(); // updates from _none if a match static vmSymbols::SID klass_id_for_intrinsics(const Klass* holder); - bool jfr_towrite() const { - return (_flags & _jfr_towrite) != 0; - } - void set_jfr_towrite(bool x) const { - _flags = x ? (_flags | _jfr_towrite) : (_flags & ~_jfr_towrite); - } - bool caller_sensitive() { return (_flags & _caller_sensitive) != 0; } @@ -890,6 +884,8 @@ class Method : public Metadata { _flags = x ? (_flags | _reserved_stack_access) : (_flags & ~_reserved_stack_access); } + TRACE_DEFINE_FLAG_ACCESSOR; + ConstMethod::MethodType method_type() const { return _constMethod->method_type(); } diff --git a/hotspot/src/share/vm/runtime/vmStructs.cpp b/hotspot/src/share/vm/runtime/vmStructs.cpp index 46824eb7553..d5b9e3db03c 100644 --- a/hotspot/src/share/vm/runtime/vmStructs.cpp +++ b/hotspot/src/share/vm/runtime/vmStructs.cpp @@ -2453,7 +2453,6 @@ typedef CompactHashtable SymbolCompactHashTable; /* ConstMethod anon-enum */ \ /********************************/ \ \ - declare_constant(Method::_jfr_towrite) \ declare_constant(Method::_caller_sensitive) \ declare_constant(Method::_force_inline) \ declare_constant(Method::_dont_inline) \ diff --git a/hotspot/src/share/vm/trace/traceMacros.hpp b/hotspot/src/share/vm/trace/traceMacros.hpp index 32849885e14..65603e2609c 100644 --- a/hotspot/src/share/vm/trace/traceMacros.hpp +++ b/hotspot/src/share/vm/trace/traceMacros.hpp @@ -55,6 +55,8 @@ extern "C" void JNICALL trace_register_natives(JNIEnv*, jclass); #define TRACE_DEFINE_THREAD_ID_SIZE typedef int ___IGNORED_hs_trace_type6 #define TRACE_DEFINE_THREAD_DATA_WRITER_OFFSET typedef int ___IGNORED_hs_trace_type7 #define TRACE_THREAD_DATA_WRITER_OFFSET in_ByteSize(0); ShouldNotReachHere() +#define TRACE_DEFINE_FLAG typedef int ___IGNORED_hs_trace_type8 +#define TRACE_DEFINE_FLAG_ACCESSOR typedef int ___IGNORED_hs_trace_type9 #define TRACE_TEMPLATES(template) #define TRACE_INTRINSICS(do_intrinsic, do_class, do_name, do_signature, do_alias) From 197ce5bafabd12ec7ae6d8542188fea17358bacb Mon Sep 17 00:00:00 2001 From: Jamsheed Mohammed C M Date: Tue, 17 Jan 2017 21:38:07 -0800 Subject: [PATCH 045/157] 8166002: Emulate client build on platforms with reduced virtual address space The default VM ergonomics on Windows/x86 (32-bit) are changed to client like. Reviewed-by: kvn, iveresov --- .../share/vm/compiler/compilerDefinitions.cpp | 79 +++++++++++++++++++ .../share/vm/compiler/compilerDefinitions.hpp | 41 +++++----- .../share/vm/compiler/compilerDirectives.cpp | 4 +- .../src/share/vm/gc/shared/collectedHeap.cpp | 2 +- .../share/vm/gc/shared/genCollectedHeap.cpp | 2 +- .../share/vm/gc/shared/referenceProcessor.cpp | 10 +-- .../vm/gc/shared/threadLocalAllocBuffer.cpp | 8 +- hotspot/src/share/vm/oops/methodData.cpp | 18 ++--- hotspot/src/share/vm/prims/whitebox.cpp | 3 + hotspot/src/share/vm/runtime/arguments.cpp | 36 ++++++++- hotspot/src/share/vm/runtime/arguments.hpp | 4 + .../share/vm/runtime/compilationPolicy.cpp | 26 ++---- hotspot/src/share/vm/runtime/vm_version.cpp | 23 ++++-- hotspot/test/TEST.ROOT | 1 + .../arraycopy/TestArrayCopyNoInitDeopt.java | 6 +- .../c2/cr7200264/TestSSE2IntVect.java | 1 + .../c2/cr7200264/TestSSE4IntVect.java | 1 + .../stress/OverloadCompileQueueTest.java | 4 +- .../TestAESIntrinsicsOnSupportedConfig.java | 2 +- .../intrinsics/IntrinsicAvailableTest.java | 2 +- .../intrinsics/IntrinsicDisabledTest.java | 3 +- .../bigInteger/MontgomeryMultiplyTest.java | 6 +- .../intrinsics/bmi/verifycode/AndnTestI.java | 2 +- .../intrinsics/bmi/verifycode/AndnTestL.java | 2 +- .../intrinsics/bmi/verifycode/BlsiTestI.java | 2 +- .../intrinsics/bmi/verifycode/BlsiTestL.java | 2 +- .../bmi/verifycode/BlsmskTestI.java | 2 +- .../bmi/verifycode/BlsmskTestL.java | 2 +- .../intrinsics/bmi/verifycode/BlsrTestI.java | 2 +- .../intrinsics/bmi/verifycode/BlsrTestL.java | 2 +- .../bmi/verifycode/BmiIntrinsicBase.java | 2 +- .../intrinsics/bmi/verifycode/LZcntTestI.java | 2 +- .../intrinsics/bmi/verifycode/LZcntTestL.java | 2 +- .../intrinsics/bmi/verifycode/TZcntTestI.java | 2 +- .../intrinsics/bmi/verifycode/TZcntTestL.java | 2 +- .../klass/CastNullCheckDroppingsTest.java | 6 +- .../mathexact/sanity/IntrinsicBase.java | 2 +- .../TestCountedLoopSafepointBackedge.java | 2 +- .../UseCountedLoopSafepointsTest.java | 5 ++ .../rangechecks/TestExplicitRangeChecks.java | 2 +- .../compiler/testlibrary/CompilerUtils.java | 4 +- .../sha/predicate/IntrinsicPredicates.java | 2 +- .../compiler/tiered/NonTieredLevelsTest.java | 4 +- .../types/correctness/CorrectnessTest.java | 6 +- .../uncommontrap/TestUnstableIfTrap.java | 2 +- .../unsafe/UnsafeGetConstantField.java | 6 +- .../unsafe/UnsafeGetStableArrayElement.java | 6 +- .../whitebox/IsMethodCompilableTest.java | 7 +- .../stress/gcbasher/TestGCBasherWithCMS.java | 2 +- .../stress/gcbasher/TestGCBasherWithG1.java | 2 +- .../gcbasher/TestGCBasherWithParallel.java | 2 +- .../gcbasher/TestGCBasherWithSerial.java | 2 +- .../CDSCompressedKPtrs/XShareAuto.java | 3 +- .../ReservedStackTestCompiler.java | 2 +- .../compiler/CompilerDirectivesDCMDTest.java | 2 +- .../ctw/src/sun/hotspot/tools/ctw/Utils.java | 6 +- ...stMutuallyExclusivePlatformPredicates.java | 2 +- 57 files changed, 261 insertions(+), 124 deletions(-) diff --git a/hotspot/src/share/vm/compiler/compilerDefinitions.cpp b/hotspot/src/share/vm/compiler/compilerDefinitions.cpp index a0d379773eb..b6ebdec1310 100644 --- a/hotspot/src/share/vm/compiler/compilerDefinitions.cpp +++ b/hotspot/src/share/vm/compiler/compilerDefinitions.cpp @@ -23,6 +23,8 @@ */ #include "precompiled.hpp" +#include "runtime/globals.hpp" +#include "runtime/globals_extension.hpp" #include "compiler/compilerDefinitions.hpp" const char* compilertype2name_tab[compiler_number_of_types] = { @@ -32,3 +34,80 @@ const char* compilertype2name_tab[compiler_number_of_types] = { "jvmci", "shark" }; + +#if defined(COMPILER2) || defined(SHARK) +CompLevel CompLevel_highest_tier = CompLevel_full_optimization; // pure C2 and tiered or JVMCI and tiered +#elif defined(COMPILER1) +CompLevel CompLevel_highest_tier = CompLevel_simple; // pure C1 or JVMCI +#else +CompLevel CompLevel_highest_tier = CompLevel_none; +#endif + +#if defined(TIERED) +CompLevel CompLevel_initial_compile = CompLevel_full_profile; // tiered +#elif defined(COMPILER1) || INCLUDE_JVMCI +CompLevel CompLevel_initial_compile = CompLevel_simple; // pure C1 or JVMCI +#elif defined(COMPILER2) || defined(SHARK) +CompLevel CompLevel_initial_compile = CompLevel_full_optimization; // pure C2 +#else +CompLevel CompLevel_initial_compile = CompLevel_none; +#endif + +#if defined(COMPILER2) +CompMode Compilation_mode = CompMode_server; +#elif defined(COMPILER1) +CompMode Compilation_mode = CompMode_client; +#else +CompMode Compilation_mode = CompMode_none; +#endif + +#ifdef TIERED +void set_client_compilation_mode() { + Compilation_mode = CompMode_client; + CompLevel_highest_tier = CompLevel_simple; + CompLevel_initial_compile = CompLevel_simple; + FLAG_SET_ERGO(bool, TieredCompilation, false); + FLAG_SET_ERGO(bool, ProfileInterpreter, false); + FLAG_SET_ERGO(bool, NeverActAsServerClassMachine, true); +#if INCLUDE_JVMCI + FLAG_SET_ERGO(bool, EnableJVMCI, false); + FLAG_SET_ERGO(bool, UseJVMCICompiler, false); +#endif +#if INCLUDE_AOT + FLAG_SET_ERGO(bool, UseAOT, false); +#endif + if (FLAG_IS_DEFAULT(InitialCodeCacheSize)) { + FLAG_SET_ERGO(uintx, InitialCodeCacheSize, 160*K); + } + if (FLAG_IS_DEFAULT(ReservedCodeCacheSize)) { + FLAG_SET_ERGO(uintx, ReservedCodeCacheSize, 32*M); + } + if (FLAG_IS_DEFAULT(NonProfiledCodeHeapSize)) { + FLAG_SET_ERGO(uintx, NonProfiledCodeHeapSize, 27*M); + } + if (FLAG_IS_DEFAULT(ProfiledCodeHeapSize)) { + FLAG_SET_ERGO(uintx, ProfiledCodeHeapSize, 0); + } + if (FLAG_IS_DEFAULT(NonNMethodCodeHeapSize)) { + FLAG_SET_ERGO(uintx, NonNMethodCodeHeapSize, 5*M); + } + if (FLAG_IS_DEFAULT(CodeCacheExpansionSize)) { + FLAG_SET_ERGO(uintx, CodeCacheExpansionSize, 32*K); + } + if (FLAG_IS_DEFAULT(MetaspaceSize)) { + FLAG_SET_ERGO(size_t, MetaspaceSize, 12*M); + } + if (FLAG_IS_DEFAULT(MaxRAM)) { + FLAG_SET_ERGO(uint64_t, MaxRAM, 1ULL*G); + } + if (FLAG_IS_DEFAULT(CompileThreshold)) { + FLAG_SET_ERGO(intx, CompileThreshold, 1500); + } + if (FLAG_IS_DEFAULT(OnStackReplacePercentage)) { + FLAG_SET_ERGO(intx, OnStackReplacePercentage, 933); + } + if (FLAG_IS_DEFAULT(CICompilerCount)) { + FLAG_SET_ERGO(intx, CICompilerCount, 1); + } +} +#endif // TIERED diff --git a/hotspot/src/share/vm/compiler/compilerDefinitions.hpp b/hotspot/src/share/vm/compiler/compilerDefinitions.hpp index 9a08a97b303..a2378ea1e92 100644 --- a/hotspot/src/share/vm/compiler/compilerDefinitions.hpp +++ b/hotspot/src/share/vm/compiler/compilerDefinitions.hpp @@ -54,27 +54,30 @@ enum CompLevel { CompLevel_simple = 1, // C1 CompLevel_limited_profile = 2, // C1, invocation & backedge counters CompLevel_full_profile = 3, // C1, invocation & backedge counters + mdo - CompLevel_full_optimization = 4, // C2, Shark or JVMCI - -#if defined(COMPILER2) || defined(SHARK) - CompLevel_highest_tier = CompLevel_full_optimization, // pure C2 and tiered or JVMCI and tiered -#elif defined(COMPILER1) - CompLevel_highest_tier = CompLevel_simple, // pure C1 or JVMCI -#else - CompLevel_highest_tier = CompLevel_none, -#endif - -#if defined(TIERED) - CompLevel_initial_compile = CompLevel_full_profile // tiered -#elif defined(COMPILER1) || INCLUDE_JVMCI - CompLevel_initial_compile = CompLevel_simple // pure C1 or JVMCI -#elif defined(COMPILER2) || defined(SHARK) - CompLevel_initial_compile = CompLevel_full_optimization // pure C2 -#else - CompLevel_initial_compile = CompLevel_none -#endif + CompLevel_full_optimization = 4 // C2, Shark or JVMCI }; +extern CompLevel CompLevel_highest_tier; +extern CompLevel CompLevel_initial_compile; + +enum CompMode { + CompMode_none = 0, + CompMode_client = 1, + CompMode_server = 2 +}; + +extern CompMode Compilation_mode; + +inline bool is_server_compilation_mode_vm() { + return Compilation_mode == CompMode_server; +} + +inline bool is_client_compilation_mode_vm() { + return Compilation_mode == CompMode_client; +} + +extern void set_client_compilation_mode(); + inline bool is_c1_compile(int comp_level) { return comp_level > CompLevel_none && comp_level < CompLevel_full_optimization; } diff --git a/hotspot/src/share/vm/compiler/compilerDirectives.cpp b/hotspot/src/share/vm/compiler/compilerDirectives.cpp index ed224cea90f..4388f348e92 100644 --- a/hotspot/src/share/vm/compiler/compilerDirectives.cpp +++ b/hotspot/src/share/vm/compiler/compilerDirectives.cpp @@ -445,7 +445,9 @@ void DirectivesStack::init() { _default_directives->_c1_store->EnableOption = true; #endif #ifdef COMPILER2 - _default_directives->_c2_store->EnableOption = true; + if (is_server_compilation_mode_vm()) { + _default_directives->_c2_store->EnableOption = true; + } #endif assert(error_msg == NULL, "Must succeed."); push(_default_directives); diff --git a/hotspot/src/share/vm/gc/shared/collectedHeap.cpp b/hotspot/src/share/vm/gc/shared/collectedHeap.cpp index 4f2c46913db..737c57c117d 100644 --- a/hotspot/src/share/vm/gc/shared/collectedHeap.cpp +++ b/hotspot/src/share/vm/gc/shared/collectedHeap.cpp @@ -233,7 +233,7 @@ void CollectedHeap::pre_initialize() { // Used for ReduceInitialCardMarks (when COMPILER2 is used); // otherwise remains unused. #if defined(COMPILER2) || INCLUDE_JVMCI - _defer_initial_card_mark = ReduceInitialCardMarks && can_elide_tlab_store_barriers() + _defer_initial_card_mark = is_server_compilation_mode_vm() && ReduceInitialCardMarks && can_elide_tlab_store_barriers() && (DeferInitialCardMark || card_mark_must_follow_store()); #else assert(_defer_initial_card_mark == false, "Who would set it?"); diff --git a/hotspot/src/share/vm/gc/shared/genCollectedHeap.cpp b/hotspot/src/share/vm/gc/shared/genCollectedHeap.cpp index 5248654f2f7..0119e115104 100644 --- a/hotspot/src/share/vm/gc/shared/genCollectedHeap.cpp +++ b/hotspot/src/share/vm/gc/shared/genCollectedHeap.cpp @@ -1209,7 +1209,7 @@ void GenCollectedHeap::gc_epilogue(bool full) { #if defined(COMPILER2) || INCLUDE_JVMCI assert(DerivedPointerTable::is_empty(), "derived pointer present"); size_t actual_gap = pointer_delta((HeapWord*) (max_uintx-3), *(end_addr())); - guarantee(actual_gap > (size_t)FastAllocateSizeLimit, "inline allocation wraps"); + guarantee(is_client_compilation_mode_vm() || actual_gap > (size_t)FastAllocateSizeLimit, "inline allocation wraps"); #endif /* COMPILER2 || INCLUDE_JVMCI */ resize_all_tlabs(); diff --git a/hotspot/src/share/vm/gc/shared/referenceProcessor.cpp b/hotspot/src/share/vm/gc/shared/referenceProcessor.cpp index 38df96ddd4c..5d6d160a4ee 100644 --- a/hotspot/src/share/vm/gc/shared/referenceProcessor.cpp +++ b/hotspot/src/share/vm/gc/shared/referenceProcessor.cpp @@ -57,11 +57,11 @@ void ReferenceProcessor::init_statics() { java_lang_ref_SoftReference::set_clock(_soft_ref_timestamp_clock); _always_clear_soft_ref_policy = new AlwaysClearPolicy(); -#if defined(COMPILER2) || INCLUDE_JVMCI - _default_soft_ref_policy = new LRUMaxHeapPolicy(); -#else - _default_soft_ref_policy = new LRUCurrentHeapPolicy(); -#endif + if (is_server_compilation_mode_vm()) { + _default_soft_ref_policy = new LRUMaxHeapPolicy(); + } else { + _default_soft_ref_policy = new LRUCurrentHeapPolicy(); + } if (_always_clear_soft_ref_policy == NULL || _default_soft_ref_policy == NULL) { vm_exit_during_initialization("Could not allocate reference policy object"); } diff --git a/hotspot/src/share/vm/gc/shared/threadLocalAllocBuffer.cpp b/hotspot/src/share/vm/gc/shared/threadLocalAllocBuffer.cpp index 0df1ba020a2..b004ba58c89 100644 --- a/hotspot/src/share/vm/gc/shared/threadLocalAllocBuffer.cpp +++ b/hotspot/src/share/vm/gc/shared/threadLocalAllocBuffer.cpp @@ -233,9 +233,11 @@ void ThreadLocalAllocBuffer::startup_initialization() { // If the C2 compiler is not present, no space is reserved. // +1 for rounding up to next cache line, +1 to be safe - int lines = MAX2(AllocatePrefetchLines, AllocateInstancePrefetchLines) + 2; - _reserve_for_allocation_prefetch = (AllocatePrefetchDistance + AllocatePrefetchStepSize * lines) / - (int)HeapWordSize; + if (is_server_compilation_mode_vm()) { + int lines = MAX2(AllocatePrefetchLines, AllocateInstancePrefetchLines) + 2; + _reserve_for_allocation_prefetch = (AllocatePrefetchDistance + AllocatePrefetchStepSize * lines) / + (int)HeapWordSize; + } #endif // During jvm startup, the main (primordial) thread is initialized diff --git a/hotspot/src/share/vm/oops/methodData.cpp b/hotspot/src/share/vm/oops/methodData.cpp index 85f7c9b6098..a99000aabcf 100644 --- a/hotspot/src/share/vm/oops/methodData.cpp +++ b/hotspot/src/share/vm/oops/methodData.cpp @@ -717,9 +717,9 @@ MethodData* MethodData::allocate(ClassLoaderData* loader_data, const methodHandl } int MethodData::bytecode_cell_count(Bytecodes::Code code) { -#if defined(COMPILER1) && !(defined(COMPILER2) || INCLUDE_JVMCI) - return no_profile_data; -#else + if (is_client_compilation_mode_vm()) { + return no_profile_data; + } switch (code) { case Bytecodes::_checkcast: case Bytecodes::_instanceof: @@ -778,7 +778,6 @@ int MethodData::bytecode_cell_count(Bytecodes::Code code) { return variable_cell_count; } return no_profile_data; -#endif } // Compute the size of the profiling information corresponding to @@ -840,7 +839,9 @@ bool MethodData::is_speculative_trap_bytecode(Bytecodes::Code code) { case Bytecodes::_ifnonnull: case Bytecodes::_invokestatic: #ifdef COMPILER2 - return UseTypeSpeculation; + if (is_server_compilation_mode_vm()) { + return UseTypeSpeculation; + } #endif default: return false; @@ -942,9 +943,9 @@ int MethodData::compute_allocation_size_in_words(const methodHandle& method) { // the segment in bytes. int MethodData::initialize_data(BytecodeStream* stream, int data_index) { -#if defined(COMPILER1) && !(defined(COMPILER2) || INCLUDE_JVMCI) - return 0; -#else + if (is_client_compilation_mode_vm()) { + return 0; + } int cell_count = -1; int tag = DataLayout::no_tag; DataLayout* data_layout = data_layout_at(data_index); @@ -1061,7 +1062,6 @@ int MethodData::initialize_data(BytecodeStream* stream, assert(!bytecode_has_profile(c), "agree w/ !BHP"); return 0; } -#endif } // Get the data at an arbitrary (sort of) data index. diff --git a/hotspot/src/share/vm/prims/whitebox.cpp b/hotspot/src/share/vm/prims/whitebox.cpp index 0440fabb9c2..edea100cbe0 100644 --- a/hotspot/src/share/vm/prims/whitebox.cpp +++ b/hotspot/src/share/vm/prims/whitebox.cpp @@ -659,6 +659,9 @@ WB_ENTRY(jboolean, WB_IsMethodCompiled(JNIEnv* env, jobject o, jobject method, j WB_END WB_ENTRY(jboolean, WB_IsMethodCompilable(JNIEnv* env, jobject o, jobject method, jint comp_level, jboolean is_osr)) + if (method == NULL || comp_level > MIN2((CompLevel) TieredStopAtLevel, CompLevel_highest_tier)) { + return false; + } jmethodID jmid = reflected_method_to_jmid(thread, env, method); CHECK_JNI_EXCEPTION_(env, JNI_FALSE); MutexLockerEx mu(Compile_lock); diff --git a/hotspot/src/share/vm/runtime/arguments.cpp b/hotspot/src/share/vm/runtime/arguments.cpp index 0ddbb30a8c5..c090e189be4 100644 --- a/hotspot/src/share/vm/runtime/arguments.cpp +++ b/hotspot/src/share/vm/runtime/arguments.cpp @@ -1819,6 +1819,25 @@ bool Arguments::gc_selected() { #endif // INCLUDE_ALL_GCS } +#ifdef TIERED +bool Arguments::compilation_mode_selected() { + return !FLAG_IS_DEFAULT(TieredCompilation) || !FLAG_IS_DEFAULT(TieredStopAtLevel) || + !FLAG_IS_DEFAULT(UseAOT) JVMCI_ONLY(|| !FLAG_IS_DEFAULT(EnableJVMCI) || !FLAG_IS_DEFAULT(UseJVMCICompiler)); + +} + +void Arguments::select_compilation_mode_ergonomically() { +#if defined(_WINDOWS) && !defined(_LP64) + if (FLAG_IS_DEFAULT(NeverActAsServerClassMachine)) { + NeverActAsServerClassMachine = true; + } +#endif + if (NeverActAsServerClassMachine) { + set_client_compilation_mode(); + } +} +#endif //TIERED + void Arguments::select_gc_ergonomically() { #if INCLUDE_ALL_GCS if (os::is_server_class_machine()) { @@ -1883,6 +1902,11 @@ void Arguments::set_jvmci_specific_flags() { #endif void Arguments::set_ergonomics_flags() { +#ifdef TIERED + if (!compilation_mode_selected()) { + select_compilation_mode_ergonomically(); + } +#endif select_gc(); #if defined(COMPILER2) || INCLUDE_JVMCI @@ -1891,7 +1915,7 @@ void Arguments::set_ergonomics_flags() { // server performance. When -server is specified, keep the default off // unless it is asked for. Future work: either add bytecode rewriting // at link time, or rewrite bytecodes in non-shared methods. - if (!DumpSharedSpaces && !RequireSharedSpaces && + if (is_server_compilation_mode_vm() && !DumpSharedSpaces && !RequireSharedSpaces && (FLAG_IS_DEFAULT(UseSharedSpaces) || !UseSharedSpaces)) { no_shared_spaces("COMPILER2 default: -Xshare:auto | off, have to manually setup to on."); } @@ -3711,6 +3735,12 @@ jint Arguments::finalize_vm_init_args() { return JNI_ERR; } +#if INCLUDE_JVMCI + if (UseJVMCICompiler) { + Compilation_mode = CompMode_server; + } +#endif + return JNI_OK; } @@ -4456,7 +4486,9 @@ jint Arguments::apply_ergo() { } else { int max_compilation_policy_choice = 1; #ifdef COMPILER2 - max_compilation_policy_choice = 2; + if (is_server_compilation_mode_vm()) { + max_compilation_policy_choice = 2; + } #endif // Check if the policy is valid. if (CompilationPolicyChoice >= max_compilation_policy_choice) { diff --git a/hotspot/src/share/vm/runtime/arguments.hpp b/hotspot/src/share/vm/runtime/arguments.hpp index 36bf75c6b2a..daa91c22bd7 100644 --- a/hotspot/src/share/vm/runtime/arguments.hpp +++ b/hotspot/src/share/vm/runtime/arguments.hpp @@ -455,6 +455,10 @@ class Arguments : AllStatic { static intx _Tier3InvokeNotifyFreqLog; static intx _Tier4InvocationThreshold; + // Compilation mode. + static bool compilation_mode_selected(); + static void select_compilation_mode_ergonomically(); + // Tiered static void set_tiered_flags(); // CMS/ParNew garbage collectors diff --git a/hotspot/src/share/vm/runtime/compilationPolicy.cpp b/hotspot/src/share/vm/runtime/compilationPolicy.cpp index 7333d0d1327..2044fdd8494 100644 --- a/hotspot/src/share/vm/runtime/compilationPolicy.cpp +++ b/hotspot/src/share/vm/runtime/compilationPolicy.cpp @@ -238,31 +238,17 @@ void NonTieredCompPolicy::initialize() { // Note: this policy is used ONLY if TieredCompilation is off. // compiler_count() behaves the following way: // - with TIERED build (with both COMPILER1 and COMPILER2 defined) it should return -// zero for the c1 compilation levels, hence the particular ordering of the -// statements. -// - the same should happen when COMPILER2 is defined and COMPILER1 is not -// (server build without TIERED defined). -// - if only COMPILER1 is defined (client build), zero should be returned for -// the c2 level. +// zero for the c1 compilation levels in server compilation mode runs +// and c2 compilation levels in client compilation mode runs. +// - with COMPILER2 not defined it should return zero for c2 compilation levels. +// - with COMPILER1 not defined it should return zero for c1 compilation levels. // - if neither is defined - always return zero. int NonTieredCompPolicy::compiler_count(CompLevel comp_level) { assert(!TieredCompilation, "This policy should not be used with TieredCompilation"); -#ifdef COMPILER2 - if (is_c2_compile(comp_level)) { + if (COMPILER2_PRESENT(is_server_compilation_mode_vm() && is_c2_compile(comp_level) ||) + is_client_compilation_mode_vm() && is_c1_compile(comp_level)) { return _compiler_count; - } else { - return 0; } -#endif - -#ifdef COMPILER1 - if (is_c1_compile(comp_level)) { - return _compiler_count; - } else { - return 0; - } -#endif - return 0; } diff --git a/hotspot/src/share/vm/runtime/vm_version.cpp b/hotspot/src/share/vm/runtime/vm_version.cpp index 7d7dcc47949..61a064703c2 100644 --- a/hotspot/src/share/vm/runtime/vm_version.cpp +++ b/hotspot/src/share/vm/runtime/vm_version.cpp @@ -131,19 +131,32 @@ const char* Abstract_VM_Version::vm_info_string() { return UseSharedSpaces ? "interpreted mode, sharing" : "interpreted mode"; case Arguments::_mixed: if (UseSharedSpaces) { - if (UseAOT) { - return "mixed mode, aot, sharing"; - } else { - return "mixed mode, sharing"; - } + if (UseAOT) { + return "mixed mode, aot, sharing"; +#ifdef TIERED + } else if(is_client_compilation_mode_vm()) { + return "mixed mode, emulated-client, sharing"; +#endif + } else { + return "mixed mode, sharing"; + } } else { if (UseAOT) { return "mixed mode, aot"; +#ifdef TIERED + } else if(is_client_compilation_mode_vm()) { + return "mixed mode, emulated-client"; +#endif } else { return "mixed mode"; } } case Arguments::_comp: +#ifdef TIERED + if (is_client_compilation_mode_vm()) { + return UseSharedSpaces ? "compiled mode, emulated-client, sharing" : "compiled mode, emulated-client"; + } +#endif return UseSharedSpaces ? "compiled mode, sharing" : "compiled mode"; }; ShouldNotReachHere(); diff --git a/hotspot/test/TEST.ROOT b/hotspot/test/TEST.ROOT index 14d3a1c0135..54b61ac1406 100644 --- a/hotspot/test/TEST.ROOT +++ b/hotspot/test/TEST.ROOT @@ -46,6 +46,7 @@ requires.properties= \ vm.gc.Parallel \ vm.gc.ConcMarkSweep \ vm.jvmci \ + vm.emulatedClient \ vm.cpu.features \ vm.debug diff --git a/hotspot/test/compiler/arraycopy/TestArrayCopyNoInitDeopt.java b/hotspot/test/compiler/arraycopy/TestArrayCopyNoInitDeopt.java index e121ab36b6b..023bd266f31 100644 --- a/hotspot/test/compiler/arraycopy/TestArrayCopyNoInitDeopt.java +++ b/hotspot/test/compiler/arraycopy/TestArrayCopyNoInitDeopt.java @@ -25,7 +25,7 @@ * @test * @bug 8072016 * @summary Infinite deoptimization/recompilation cycles in case of arraycopy with tightly coupled allocation - * @requires vm.flavor == "server" + * @requires vm.flavor == "server" & !vm.emulatedClient * @library /test/lib / * @modules java.base/jdk.internal.misc * java.management @@ -86,8 +86,8 @@ public class TestArrayCopyNoInitDeopt { } static public void main(String[] args) throws Exception { - if (!Platform.isServer()) { - throw new Error("TESTBUG: Not server VM"); + if (!Platform.isServer() || Platform.isEmulatedClient()) { + throw new Error("TESTBUG: Not server mode"); } // Only execute if C2 is available if (TIERED_STOP_AT_LEVEL == CompilerWhiteBoxTest.COMP_LEVEL_FULL_OPTIMIZATION) { diff --git a/hotspot/test/compiler/c2/cr7200264/TestSSE2IntVect.java b/hotspot/test/compiler/c2/cr7200264/TestSSE2IntVect.java index f8a3e6607d2..a8d4144b489 100644 --- a/hotspot/test/compiler/c2/cr7200264/TestSSE2IntVect.java +++ b/hotspot/test/compiler/c2/cr7200264/TestSSE2IntVect.java @@ -26,6 +26,7 @@ * @bug 7200264 * @summary 7192963 changes disabled shift vectors * @requires vm.cpu.features ~= ".*sse2.*" & vm.debug & vm.flavor == "server" + * @requires !vm.emulatedClient * @library /test/lib / * @run driver compiler.c2.cr7200264.TestSSE2IntVect */ diff --git a/hotspot/test/compiler/c2/cr7200264/TestSSE4IntVect.java b/hotspot/test/compiler/c2/cr7200264/TestSSE4IntVect.java index c3c2c6aa52a..bab678e32b6 100644 --- a/hotspot/test/compiler/c2/cr7200264/TestSSE4IntVect.java +++ b/hotspot/test/compiler/c2/cr7200264/TestSSE4IntVect.java @@ -26,6 +26,7 @@ * @bug 7200264 * @summary 7192963 changes disabled shift vectors * @requires vm.cpu.features ~= ".*sse4\\.1.*" & vm.debug & vm.flavor == "server" + * @requires !vm.emulatedClient * @library /test/lib / * @run driver compiler.c2.cr7200264.TestSSE4IntVect */ diff --git a/hotspot/test/compiler/codecache/stress/OverloadCompileQueueTest.java b/hotspot/test/compiler/codecache/stress/OverloadCompileQueueTest.java index 535e7026a7f..72886587ec9 100644 --- a/hotspot/test/compiler/codecache/stress/OverloadCompileQueueTest.java +++ b/hotspot/test/compiler/codecache/stress/OverloadCompileQueueTest.java @@ -65,9 +65,9 @@ public class OverloadCompileQueueTest implements Runnable { AVAILABLE_LEVELS = IntStream .rangeClosed(LEVEL_SIMPLE, TIERED_STOP_AT_LEVEL) .toArray(); - } else if (Platform.isServer()) { + } else if (Platform.isServer() && !Platform.isEmulatedClient()) { AVAILABLE_LEVELS = new int[] { LEVEL_FULL_OPTIMIZATION }; - } else if (Platform.isClient() || Platform.isMinimal()) { + } else if (Platform.isClient() || Platform.isMinimal() || Platform.isEmulatedClient()) { AVAILABLE_LEVELS = new int[] { LEVEL_SIMPLE }; } else { throw new Error("TESTBUG: unknown VM: " + Platform.vmName); diff --git a/hotspot/test/compiler/cpuflags/TestAESIntrinsicsOnSupportedConfig.java b/hotspot/test/compiler/cpuflags/TestAESIntrinsicsOnSupportedConfig.java index 5fa126bad72..dd8c4aa6925 100644 --- a/hotspot/test/compiler/cpuflags/TestAESIntrinsicsOnSupportedConfig.java +++ b/hotspot/test/compiler/cpuflags/TestAESIntrinsicsOnSupportedConfig.java @@ -75,7 +75,7 @@ public class TestAESIntrinsicsOnSupportedConfig extends AESIntrinsicsBase { prepareArguments(prepareBooleanFlag(AESIntrinsicsBase .USE_AES, true))); final String errorMessage = "Case testUseAES failed"; - if (Platform.isServer()) { + if (Platform.isServer() && !Platform.isEmulatedClient()) { verifyOutput(new String[]{AESIntrinsicsBase.CIPHER_INTRINSIC, AESIntrinsicsBase.AES_INTRINSIC}, null, errorMessage, outputAnalyzer); diff --git a/hotspot/test/compiler/intrinsics/IntrinsicAvailableTest.java b/hotspot/test/compiler/intrinsics/IntrinsicAvailableTest.java index 2be9bf6aca4..a2ca8d50837 100644 --- a/hotspot/test/compiler/intrinsics/IntrinsicAvailableTest.java +++ b/hotspot/test/compiler/intrinsics/IntrinsicAvailableTest.java @@ -114,7 +114,7 @@ public class IntrinsicAvailableTest extends CompilerWhiteBoxTest { public void test() throws Exception { Executable intrinsicMethod = testCase.getExecutable(); - if (Platform.isServer() && (TIERED_STOP_AT_LEVEL == COMP_LEVEL_FULL_OPTIMIZATION)) { + if (Platform.isServer() && !Platform.isEmulatedClient() && (TIERED_STOP_AT_LEVEL == COMP_LEVEL_FULL_OPTIMIZATION)) { if (TIERED_COMPILATION) { checkIntrinsicForCompilationLevel(intrinsicMethod, COMP_LEVEL_SIMPLE); } diff --git a/hotspot/test/compiler/intrinsics/IntrinsicDisabledTest.java b/hotspot/test/compiler/intrinsics/IntrinsicDisabledTest.java index 155956cb87f..aed0acab0ab 100644 --- a/hotspot/test/compiler/intrinsics/IntrinsicDisabledTest.java +++ b/hotspot/test/compiler/intrinsics/IntrinsicDisabledTest.java @@ -197,7 +197,8 @@ public class IntrinsicDisabledTest { } public static void main(String args[]) { - if (Platform.isServer() && (TIERED_STOP_AT_LEVEL == CompilerWhiteBoxTest.COMP_LEVEL_FULL_OPTIMIZATION)) { + if (Platform.isServer() && !Platform.isEmulatedClient() && + (TIERED_STOP_AT_LEVEL == CompilerWhiteBoxTest.COMP_LEVEL_FULL_OPTIMIZATION)) { if (TIERED_COMPILATION) { test(CompilerWhiteBoxTest.COMP_LEVEL_SIMPLE); } diff --git a/hotspot/test/compiler/intrinsics/bigInteger/MontgomeryMultiplyTest.java b/hotspot/test/compiler/intrinsics/bigInteger/MontgomeryMultiplyTest.java index a8c3455b322..0600ed22ec1 100644 --- a/hotspot/test/compiler/intrinsics/bigInteger/MontgomeryMultiplyTest.java +++ b/hotspot/test/compiler/intrinsics/bigInteger/MontgomeryMultiplyTest.java @@ -26,7 +26,7 @@ * @test * @bug 8130150 8131779 8139907 * @summary Verify that the Montgomery multiply and square intrinsic works and correctly checks their arguments. - * @requires vm.flavor == "server" + * @requires vm.flavor == "server" & !vm.emulatedClient * @modules java.base/jdk.internal.misc:open * @modules java.base/java.math:open * @library /test/lib / @@ -314,8 +314,8 @@ public class MontgomeryMultiplyTest { } public static void main(String args[]) { - if (!Platform.isServer()) { - throw new Error("TESTBUG: Not server VM"); + if (!Platform.isServer() || Platform.isEmulatedClient()) { + throw new Error("TESTBUG: Not server mode"); } if (wb.isIntrinsicAvailable(getExecutable(true), CompilerWhiteBoxTest.COMP_LEVEL_FULL_OPTIMIZATION) && wb.isIntrinsicAvailable(getExecutable(false), CompilerWhiteBoxTest.COMP_LEVEL_FULL_OPTIMIZATION)) { diff --git a/hotspot/test/compiler/intrinsics/bmi/verifycode/AndnTestI.java b/hotspot/test/compiler/intrinsics/bmi/verifycode/AndnTestI.java index f307a3ec555..d0d1b9fa835 100644 --- a/hotspot/test/compiler/intrinsics/bmi/verifycode/AndnTestI.java +++ b/hotspot/test/compiler/intrinsics/bmi/verifycode/AndnTestI.java @@ -24,7 +24,7 @@ /* * @test * @bug 8031321 - * @requires vm.flavor == "server" + * @requires vm.flavor == "server" & !vm.emulatedClient * @library /test/lib / * @modules java.base/jdk.internal.misc * java.management diff --git a/hotspot/test/compiler/intrinsics/bmi/verifycode/AndnTestL.java b/hotspot/test/compiler/intrinsics/bmi/verifycode/AndnTestL.java index dd1bc571787..f485eda7109 100644 --- a/hotspot/test/compiler/intrinsics/bmi/verifycode/AndnTestL.java +++ b/hotspot/test/compiler/intrinsics/bmi/verifycode/AndnTestL.java @@ -24,7 +24,7 @@ /* * @test * @bug 8031321 - * @requires vm.flavor == "server" + * @requires vm.flavor == "server" & !vm.emulatedClient * @library /test/lib / * @modules java.base/jdk.internal.misc * java.management diff --git a/hotspot/test/compiler/intrinsics/bmi/verifycode/BlsiTestI.java b/hotspot/test/compiler/intrinsics/bmi/verifycode/BlsiTestI.java index a5e34b5f6a8..7bb38602598 100644 --- a/hotspot/test/compiler/intrinsics/bmi/verifycode/BlsiTestI.java +++ b/hotspot/test/compiler/intrinsics/bmi/verifycode/BlsiTestI.java @@ -24,7 +24,7 @@ /* * @test * @bug 8031321 - * @requires vm.flavor == "server" + * @requires vm.flavor == "server" & !vm.emulatedClient * @library /test/lib / * @modules java.base/jdk.internal.misc * java.management diff --git a/hotspot/test/compiler/intrinsics/bmi/verifycode/BlsiTestL.java b/hotspot/test/compiler/intrinsics/bmi/verifycode/BlsiTestL.java index 72eb85a322f..c5daec36435 100644 --- a/hotspot/test/compiler/intrinsics/bmi/verifycode/BlsiTestL.java +++ b/hotspot/test/compiler/intrinsics/bmi/verifycode/BlsiTestL.java @@ -24,7 +24,7 @@ /* * @test * @bug 8031321 - * @requires vm.flavor == "server" + * @requires vm.flavor == "server" & !vm.emulatedClient * @library /test/lib / * @modules java.base/jdk.internal.misc * java.management diff --git a/hotspot/test/compiler/intrinsics/bmi/verifycode/BlsmskTestI.java b/hotspot/test/compiler/intrinsics/bmi/verifycode/BlsmskTestI.java index a5829a7e931..4dc005a1dbd 100644 --- a/hotspot/test/compiler/intrinsics/bmi/verifycode/BlsmskTestI.java +++ b/hotspot/test/compiler/intrinsics/bmi/verifycode/BlsmskTestI.java @@ -24,7 +24,7 @@ /* * @test * @bug 8031321 - * @requires vm.flavor == "server" + * @requires vm.flavor == "server" & !vm.emulatedClient * @library /test/lib / * @modules java.base/jdk.internal.misc * java.management diff --git a/hotspot/test/compiler/intrinsics/bmi/verifycode/BlsmskTestL.java b/hotspot/test/compiler/intrinsics/bmi/verifycode/BlsmskTestL.java index 9198bc734fd..f043de26bbf 100644 --- a/hotspot/test/compiler/intrinsics/bmi/verifycode/BlsmskTestL.java +++ b/hotspot/test/compiler/intrinsics/bmi/verifycode/BlsmskTestL.java @@ -24,7 +24,7 @@ /* * @test * @bug 8031321 - * @requires vm.flavor == "server" + * @requires vm.flavor == "server" & !vm.emulatedClient * @library /test/lib / * @modules java.base/jdk.internal.misc * java.management diff --git a/hotspot/test/compiler/intrinsics/bmi/verifycode/BlsrTestI.java b/hotspot/test/compiler/intrinsics/bmi/verifycode/BlsrTestI.java index 2ab1c78dfba..d7f75741384 100644 --- a/hotspot/test/compiler/intrinsics/bmi/verifycode/BlsrTestI.java +++ b/hotspot/test/compiler/intrinsics/bmi/verifycode/BlsrTestI.java @@ -24,7 +24,7 @@ /* * @test * @bug 8031321 - * @requires vm.flavor == "server" + * @requires vm.flavor == "server" & !vm.emulatedClient * @library /test/lib / * @modules java.base/jdk.internal.misc * java.management diff --git a/hotspot/test/compiler/intrinsics/bmi/verifycode/BlsrTestL.java b/hotspot/test/compiler/intrinsics/bmi/verifycode/BlsrTestL.java index 3addea222c1..7545802107f 100644 --- a/hotspot/test/compiler/intrinsics/bmi/verifycode/BlsrTestL.java +++ b/hotspot/test/compiler/intrinsics/bmi/verifycode/BlsrTestL.java @@ -24,7 +24,7 @@ /* * @test * @bug 8031321 - * @requires vm.flavor == "server" + * @requires vm.flavor == "server" & !vm.emulatedClient * @library /test/lib / * @modules java.base/jdk.internal.misc * java.management diff --git a/hotspot/test/compiler/intrinsics/bmi/verifycode/BmiIntrinsicBase.java b/hotspot/test/compiler/intrinsics/bmi/verifycode/BmiIntrinsicBase.java index 3533aa9ecdb..813053d85f1 100644 --- a/hotspot/test/compiler/intrinsics/bmi/verifycode/BmiIntrinsicBase.java +++ b/hotspot/test/compiler/intrinsics/bmi/verifycode/BmiIntrinsicBase.java @@ -78,7 +78,7 @@ public class BmiIntrinsicBase extends CompilerWhiteBoxTest { System.out.println(testCase.name()); - if (TIERED_COMPILATION && TIERED_STOP_AT_LEVEL != CompilerWhiteBoxTest.COMP_LEVEL_MAX) { + if (TIERED_COMPILATION && TIERED_STOP_AT_LEVEL != CompilerWhiteBoxTest.COMP_LEVEL_MAX || Platform.isEmulatedClient()) { System.out.println("TieredStopAtLevel value (" + TIERED_STOP_AT_LEVEL + ") is too low, test SKIPPED"); return; } diff --git a/hotspot/test/compiler/intrinsics/bmi/verifycode/LZcntTestI.java b/hotspot/test/compiler/intrinsics/bmi/verifycode/LZcntTestI.java index 886d4623032..2fb39220aa4 100644 --- a/hotspot/test/compiler/intrinsics/bmi/verifycode/LZcntTestI.java +++ b/hotspot/test/compiler/intrinsics/bmi/verifycode/LZcntTestI.java @@ -24,7 +24,7 @@ /* * @test * @bug 8031321 - * @requires vm.flavor == "server" + * @requires vm.flavor == "server" & !vm.emulatedClient * @library /test/lib / * @modules java.base/jdk.internal.misc * java.management diff --git a/hotspot/test/compiler/intrinsics/bmi/verifycode/LZcntTestL.java b/hotspot/test/compiler/intrinsics/bmi/verifycode/LZcntTestL.java index b6bf6b5c48f..18b366e2ebb 100644 --- a/hotspot/test/compiler/intrinsics/bmi/verifycode/LZcntTestL.java +++ b/hotspot/test/compiler/intrinsics/bmi/verifycode/LZcntTestL.java @@ -24,7 +24,7 @@ /* * @test * @bug 8031321 - * @requires vm.flavor == "server" + * @requires vm.flavor == "server" & !vm.emulatedClient * @library /test/lib / * @modules java.base/jdk.internal.misc * java.management diff --git a/hotspot/test/compiler/intrinsics/bmi/verifycode/TZcntTestI.java b/hotspot/test/compiler/intrinsics/bmi/verifycode/TZcntTestI.java index 8a5e86187b9..ce65f84151b 100644 --- a/hotspot/test/compiler/intrinsics/bmi/verifycode/TZcntTestI.java +++ b/hotspot/test/compiler/intrinsics/bmi/verifycode/TZcntTestI.java @@ -24,7 +24,7 @@ /* * @test * @bug 8031321 - * @requires vm.flavor == "server" + * @requires vm.flavor == "server" & !vm.emulatedClient * @library /test/lib / * @modules java.base/jdk.internal.misc * java.management diff --git a/hotspot/test/compiler/intrinsics/bmi/verifycode/TZcntTestL.java b/hotspot/test/compiler/intrinsics/bmi/verifycode/TZcntTestL.java index 44f79d03012..4cc396373ce 100644 --- a/hotspot/test/compiler/intrinsics/bmi/verifycode/TZcntTestL.java +++ b/hotspot/test/compiler/intrinsics/bmi/verifycode/TZcntTestL.java @@ -24,7 +24,7 @@ /* * @test * @bug 8031321 - * @requires vm.flavor == "server" + * @requires vm.flavor == "server" & !vm.emulatedClient * @library /test/lib / * @modules java.base/jdk.internal.misc * java.management diff --git a/hotspot/test/compiler/intrinsics/klass/CastNullCheckDroppingsTest.java b/hotspot/test/compiler/intrinsics/klass/CastNullCheckDroppingsTest.java index b2a9554060d..3285b904bf7 100644 --- a/hotspot/test/compiler/intrinsics/klass/CastNullCheckDroppingsTest.java +++ b/hotspot/test/compiler/intrinsics/klass/CastNullCheckDroppingsTest.java @@ -25,7 +25,7 @@ * @test NullCheckDroppingsTest * @bug 8054492 * @summary Casting can result in redundant null checks in generated code - * @requires vm.flavor == "server" + * @requires vm.flavor == "server" & !vm.emulatedClient * @library /test/lib * @modules java.base/jdk.internal.misc * java.management @@ -84,8 +84,8 @@ public class CastNullCheckDroppingsTest { int[] asink; public static void main(String[] args) throws Exception { - if (!Platform.isServer()) { - throw new Error("TESTBUG: Not server VM"); + if (!Platform.isServer() || Platform.isEmulatedClient()) { + throw new Error("TESTBUG: Not server mode"); } // Make sure background compilation is disabled if (WHITE_BOX.getBooleanVMFlag("BackgroundCompilation")) { diff --git a/hotspot/test/compiler/intrinsics/mathexact/sanity/IntrinsicBase.java b/hotspot/test/compiler/intrinsics/mathexact/sanity/IntrinsicBase.java index 10ae924c794..f9b2e156f0c 100644 --- a/hotspot/test/compiler/intrinsics/mathexact/sanity/IntrinsicBase.java +++ b/hotspot/test/compiler/intrinsics/mathexact/sanity/IntrinsicBase.java @@ -50,7 +50,7 @@ public abstract class IntrinsicBase extends CompilerWhiteBoxTest { int expectedIntrinsicCount = 0; - if (Platform.isServer()) { + if (Platform.isServer() && !Platform.isEmulatedClient()) { if (TIERED_COMPILATION) { int max_level = TIERED_STOP_AT_LEVEL; expectedIntrinsicCount = (max_level == COMP_LEVEL_MAX) ? 1 : 0; diff --git a/hotspot/test/compiler/loopopts/TestCountedLoopSafepointBackedge.java b/hotspot/test/compiler/loopopts/TestCountedLoopSafepointBackedge.java index 31c32f2cd2a..e277f15035a 100644 --- a/hotspot/test/compiler/loopopts/TestCountedLoopSafepointBackedge.java +++ b/hotspot/test/compiler/loopopts/TestCountedLoopSafepointBackedge.java @@ -24,7 +24,7 @@ /** * @test * @bug 8161147 - * @requires vm.flavor == "server" + * @requires vm.flavor == "server" & !vm.emulatedClient * @summary Safepoint on backedge breaks UseCountedLoopSafepoints * @run main/othervm -XX:-BackgroundCompilation -XX:-UseOnStackReplacement -XX:+UseCountedLoopSafepoints TestCountedLoopSafepointBackedge * diff --git a/hotspot/test/compiler/loopopts/UseCountedLoopSafepointsTest.java b/hotspot/test/compiler/loopopts/UseCountedLoopSafepointsTest.java index 25a2ad4e087..b7cd0338d66 100644 --- a/hotspot/test/compiler/loopopts/UseCountedLoopSafepointsTest.java +++ b/hotspot/test/compiler/loopopts/UseCountedLoopSafepointsTest.java @@ -28,6 +28,7 @@ * @summary Test that C2 flag UseCountedLoopSafepoints ensures a safepoint is kept in a CountedLoop * @library /test/lib / * @requires vm.compMode != "Xint" & vm.flavor == "server" & (vm.opt.TieredStopAtLevel == null | vm.opt.TieredStopAtLevel == 4) & vm.debug == true + * @requires !vm.emulatedClient * @modules java.base/jdk.internal.misc * @build sun.hotspot.WhiteBox * @run driver ClassFileInstaller sun.hotspot.WhiteBox @@ -37,6 +38,7 @@ package compiler.loopopts; +import jdk.test.lib.Platform; import jdk.test.lib.process.ProcessTools; import jdk.test.lib.process.OutputAnalyzer; import java.util.List; @@ -51,6 +53,9 @@ import jdk.test.lib.Asserts; public class UseCountedLoopSafepointsTest { public static void main (String args[]) { + if (!Platform.isServer() || Platform.isEmulatedClient()) { + throw new Error("TESTBUG: Not server mode"); + } check(true); // check ideal graph with UseCountedLoopSafepoint enabled check(false); // ... and disabled } diff --git a/hotspot/test/compiler/rangechecks/TestExplicitRangeChecks.java b/hotspot/test/compiler/rangechecks/TestExplicitRangeChecks.java index 75adaa3551b..f1736178b2d 100644 --- a/hotspot/test/compiler/rangechecks/TestExplicitRangeChecks.java +++ b/hotspot/test/compiler/rangechecks/TestExplicitRangeChecks.java @@ -445,7 +445,7 @@ public class TestExplicitRangeChecks { success = false; } // Only perform these additional checks if C2 is available - if (Platform.isServer() && + if (Platform.isServer() && !Platform.isEmulatedClient() && TIERED_STOP_AT_LEVEL == CompilerWhiteBoxTest.COMP_LEVEL_FULL_OPTIMIZATION) { if (deoptimize && WHITE_BOX.isMethodCompiled(m)) { System.out.println(name + " not deoptimized on invalid access"); diff --git a/hotspot/test/compiler/testlibrary/CompilerUtils.java b/hotspot/test/compiler/testlibrary/CompilerUtils.java index fea72bd4c4b..85607db8ee7 100644 --- a/hotspot/test/compiler/testlibrary/CompilerUtils.java +++ b/hotspot/test/compiler/testlibrary/CompilerUtils.java @@ -53,10 +53,10 @@ public class CompilerUtils { "TieredStopAtLevel has value out of int capacity"); return IntStream.rangeClosed(1, maxLevel).toArray(); } else { - if (Platform.isServer()) { + if (Platform.isServer() && !Platform.isEmulatedClient()) { return new int[]{4}; } - if (Platform.isClient() || Platform.isMinimal()) { + if (Platform.isClient() || Platform.isMinimal() || Platform.isEmulatedClient()) { return new int[]{1}; } } diff --git a/hotspot/test/compiler/testlibrary/sha/predicate/IntrinsicPredicates.java b/hotspot/test/compiler/testlibrary/sha/predicate/IntrinsicPredicates.java index 98612cdde42..d866377049b 100644 --- a/hotspot/test/compiler/testlibrary/sha/predicate/IntrinsicPredicates.java +++ b/hotspot/test/compiler/testlibrary/sha/predicate/IntrinsicPredicates.java @@ -55,7 +55,7 @@ public class IntrinsicPredicates { "TieredStopAtLevel"); boolean maxLevelIsReachable = (tieredMaxLevel == IntrinsicPredicates.TIERED_MAX_LEVEL); - return Platform.isServer() && (!isTiered || maxLevelIsReachable); + return Platform.isServer() && !Platform.isEmulatedClient() && (!isTiered || maxLevelIsReachable); }; public static final BooleanSupplier SHA1_INSTRUCTION_AVAILABLE diff --git a/hotspot/test/compiler/tiered/NonTieredLevelsTest.java b/hotspot/test/compiler/tiered/NonTieredLevelsTest.java index 45d039f7551..19a47753bde 100644 --- a/hotspot/test/compiler/tiered/NonTieredLevelsTest.java +++ b/hotspot/test/compiler/tiered/NonTieredLevelsTest.java @@ -47,10 +47,10 @@ public class NonTieredLevelsTest extends CompLevelsTest { private static final int AVAILABLE_COMP_LEVEL; private static final IntPredicate IS_AVAILABLE_COMPLEVEL; static { - if (Platform.isServer()) { + if (Platform.isServer() && !Platform.isEmulatedClient()) { AVAILABLE_COMP_LEVEL = COMP_LEVEL_FULL_OPTIMIZATION; IS_AVAILABLE_COMPLEVEL = x -> x == COMP_LEVEL_FULL_OPTIMIZATION; - } else if (Platform.isClient() || Platform.isMinimal()) { + } else if (Platform.isClient() || Platform.isMinimal() || Platform.isEmulatedClient()) { AVAILABLE_COMP_LEVEL = COMP_LEVEL_SIMPLE; IS_AVAILABLE_COMPLEVEL = x -> x >= COMP_LEVEL_SIMPLE && x <= COMP_LEVEL_FULL_PROFILE; diff --git a/hotspot/test/compiler/types/correctness/CorrectnessTest.java b/hotspot/test/compiler/types/correctness/CorrectnessTest.java index 6b588cfc3af..b4fc31062a8 100644 --- a/hotspot/test/compiler/types/correctness/CorrectnessTest.java +++ b/hotspot/test/compiler/types/correctness/CorrectnessTest.java @@ -25,7 +25,7 @@ * @test CorrectnessTest * @bug 8038418 * @summary Tests correctness of type usage with type profiling and speculations - * @requires vm.flavor == "server" + * @requires vm.flavor == "server" & !vm.emulatedClient * @library /test/lib / * @modules java.base/jdk.internal.misc * java.management @@ -88,8 +88,8 @@ public class CorrectnessTest { private static final WhiteBox WHITE_BOX = WhiteBox.getWhiteBox(); public static void main(String[] args) { - if (!Platform.isServer()) { - throw new Error("TESTBUG: Not server VM"); + if (!Platform.isServer() || Platform.isEmulatedClient()) { + throw new Error("TESTBUG: Not server mode"); } Asserts.assertGTE(args.length, 1); ProfilingType profilingType = ProfilingType.valueOf(args[0]); diff --git a/hotspot/test/compiler/uncommontrap/TestUnstableIfTrap.java b/hotspot/test/compiler/uncommontrap/TestUnstableIfTrap.java index 84f53c89246..5d6f8cbae6c 100644 --- a/hotspot/test/compiler/uncommontrap/TestUnstableIfTrap.java +++ b/hotspot/test/compiler/uncommontrap/TestUnstableIfTrap.java @@ -206,7 +206,7 @@ public class TestUnstableIfTrap { boolean isMethodCompiledAtMaxTier = WB.getMethodCompilationLevel(m) == MAX_TIER; - return Platform.isServer() && isMethodCompiled + return Platform.isServer() && !Platform.isEmulatedClient() && isMethodCompiled && (!isTiered || isMethodCompiledAtMaxTier); } diff --git a/hotspot/test/compiler/unsafe/UnsafeGetConstantField.java b/hotspot/test/compiler/unsafe/UnsafeGetConstantField.java index e2e315818c9..56913e307d3 100644 --- a/hotspot/test/compiler/unsafe/UnsafeGetConstantField.java +++ b/hotspot/test/compiler/unsafe/UnsafeGetConstantField.java @@ -28,7 +28,7 @@ * @summary tests on constant folding of unsafe get operations * @library /test/lib * - * @requires vm.flavor == "server" + * @requires vm.flavor == "server" & !vm.emulatedClient * * @modules java.base/jdk.internal.org.objectweb.asm * java.base/jdk.internal.vm.annotation @@ -93,8 +93,8 @@ public class UnsafeGetConstantField { static final Unsafe U = Unsafe.getUnsafe(); public static void main(String[] args) { - if (!Platform.isServer()) { - throw new Error("TESTBUG: Not server VM"); + if (!Platform.isServer() || Platform.isEmulatedClient()) { + throw new Error("TESTBUG: Not server mode"); } testUnsafeGetAddress(); testUnsafeGetField(); diff --git a/hotspot/test/compiler/unsafe/UnsafeGetStableArrayElement.java b/hotspot/test/compiler/unsafe/UnsafeGetStableArrayElement.java index bc321049b1d..b938bc6a4fd 100644 --- a/hotspot/test/compiler/unsafe/UnsafeGetStableArrayElement.java +++ b/hotspot/test/compiler/unsafe/UnsafeGetStableArrayElement.java @@ -28,7 +28,7 @@ * @summary tests on constant folding of unsafe get operations from stable arrays * @library /test/lib * - * @requires vm.flavor == "server" + * @requires vm.flavor == "server" & !vm.emulatedClient * * @modules java.base/jdk.internal.vm.annotation * java.base/jdk.internal.misc @@ -332,8 +332,8 @@ public class UnsafeGetStableArrayElement { } public static void main(String[] args) throws Exception { - if (!Platform.isServer()) { - throw new Error("TESTBUG: Not server VM"); + if (!Platform.isServer() || Platform.isEmulatedClient()) { + throw new Error("TESTBUG: Not server mode"); } testUnsafeAccess(); System.out.println("TEST PASSED"); diff --git a/hotspot/test/compiler/whitebox/IsMethodCompilableTest.java b/hotspot/test/compiler/whitebox/IsMethodCompilableTest.java index c5f4687ffa9..0e5c20bcf87 100644 --- a/hotspot/test/compiler/whitebox/IsMethodCompilableTest.java +++ b/hotspot/test/compiler/whitebox/IsMethodCompilableTest.java @@ -25,7 +25,8 @@ * @test IsMethodCompilableTest * @bug 8007270 8006683 8007288 8022832 * @summary testing of WB::isMethodCompilable() - * @requires vm.flavor == "server" + * @requires vm.flavor == "server" & (vm.opt.TieredStopAtLevel == null | vm.opt.TieredStopAtLevel == 4) + * @requires !vm.emulatedClient * @library /test/lib / * @modules java.base/jdk.internal.misc * java.management @@ -82,8 +83,8 @@ public class IsMethodCompilableTest extends CompilerWhiteBoxTest { protected void test() throws Exception { // Only c2 compilations can be disabled through PerMethodRecompilationCutoff - if (!Platform.isServer()) { - throw new Error("TESTBUG: Not server VM"); + if (!Platform.isServer() || Platform.isEmulatedClient()) { + throw new Error("TESTBUG: Not server mode"); } if (skipXcompOSR()) { diff --git a/hotspot/test/gc/stress/gcbasher/TestGCBasherWithCMS.java b/hotspot/test/gc/stress/gcbasher/TestGCBasherWithCMS.java index c85acf5be82..24a1b2d10d6 100644 --- a/hotspot/test/gc/stress/gcbasher/TestGCBasherWithCMS.java +++ b/hotspot/test/gc/stress/gcbasher/TestGCBasherWithCMS.java @@ -29,7 +29,7 @@ import java.io.IOException; * @key gc * @key stress * @requires vm.gc.ConcMarkSweep - * @requires vm.flavor == "server" + * @requires vm.flavor == "server" & !vm.emulatedClient * @summary Stress the CMS GC by trying to make old objects more likely to be garbage than young objects. * @run main/othervm/timeout=200 -Xlog:gc*=info -Xmx256m -server -XX:+UseConcMarkSweepGC TestGCBasherWithCMS 120000 */ diff --git a/hotspot/test/gc/stress/gcbasher/TestGCBasherWithG1.java b/hotspot/test/gc/stress/gcbasher/TestGCBasherWithG1.java index 0e87aa82c6b..90e87534310 100644 --- a/hotspot/test/gc/stress/gcbasher/TestGCBasherWithG1.java +++ b/hotspot/test/gc/stress/gcbasher/TestGCBasherWithG1.java @@ -29,7 +29,7 @@ import java.io.IOException; * @key gc * @key stress * @requires vm.gc.G1 - * @requires vm.flavor == "server" + * @requires vm.flavor == "server" & !vm.emulatedClient * @summary Stress the G1 GC by trying to make old objects more likely to be garbage than young objects. * @run main/othervm/timeout=200 -Xlog:gc*=info -Xmx256m -server -XX:+UseG1GC TestGCBasherWithG1 120000 */ diff --git a/hotspot/test/gc/stress/gcbasher/TestGCBasherWithParallel.java b/hotspot/test/gc/stress/gcbasher/TestGCBasherWithParallel.java index a60deeb00a7..ddda7d0caf7 100644 --- a/hotspot/test/gc/stress/gcbasher/TestGCBasherWithParallel.java +++ b/hotspot/test/gc/stress/gcbasher/TestGCBasherWithParallel.java @@ -29,7 +29,7 @@ import java.io.IOException; * @key gc * @key stress * @requires vm.gc.Parallel - * @requires vm.flavor == "server" + * @requires vm.flavor == "server" & !vm.emulatedClient * @summary Stress the Parallel GC by trying to make old objects more likely to be garbage than young objects. * @run main/othervm/timeout=200 -Xlog:gc*=info -Xmx256m -server -XX:+UseParallelGC -XX:-UseGCOverheadLimit TestGCBasherWithParallel 120000 */ diff --git a/hotspot/test/gc/stress/gcbasher/TestGCBasherWithSerial.java b/hotspot/test/gc/stress/gcbasher/TestGCBasherWithSerial.java index 7ca865dd112..e69da5de2ef 100644 --- a/hotspot/test/gc/stress/gcbasher/TestGCBasherWithSerial.java +++ b/hotspot/test/gc/stress/gcbasher/TestGCBasherWithSerial.java @@ -29,7 +29,7 @@ import java.io.IOException; * @key gc * @key stress * @requires vm.gc.Serial - * @requires vm.flavor == "server" + * @requires vm.flavor == "server" & !vm.emulatedClient * @summary Stress the Serial GC by trying to make old objects more likely to be garbage than young objects. * @run main/othervm/timeout=200 -Xlog:gc*=info -Xmx256m -server -XX:+UseSerialGC TestGCBasherWithSerial 120000 */ diff --git a/hotspot/test/runtime/CDSCompressedKPtrs/XShareAuto.java b/hotspot/test/runtime/CDSCompressedKPtrs/XShareAuto.java index 425a2e5ba4e..17fa71def6f 100644 --- a/hotspot/test/runtime/CDSCompressedKPtrs/XShareAuto.java +++ b/hotspot/test/runtime/CDSCompressedKPtrs/XShareAuto.java @@ -48,8 +48,9 @@ public class XShareAuto { "-server", "-XX:+UnlockDiagnosticVMOptions", "-XX:SharedArchiveFile=./XShareAuto.jsa", "-version"); output = new OutputAnalyzer(pb.start()); + String outputString = output.getOutput(); // We asked for server but it could be aliased to something else - if (output.getOutput().contains("Server VM")) { + if (outputString.contains("Server VM") && !outputString.contains("emulated-client")) { // In server case we don't expect to see sharing flag output.shouldNotContain("sharing"); output.shouldHaveExitValue(0); diff --git a/hotspot/test/runtime/ReservedStack/ReservedStackTestCompiler.java b/hotspot/test/runtime/ReservedStack/ReservedStackTestCompiler.java index 1bc41f61355..616788fe251 100644 --- a/hotspot/test/runtime/ReservedStack/ReservedStackTestCompiler.java +++ b/hotspot/test/runtime/ReservedStack/ReservedStackTestCompiler.java @@ -24,7 +24,7 @@ /* * @test ReservedStackTestCompiler * @summary Run ReservedStackTest with dedicated compilers C1 and C2. - * @requires vm.flavor == "server" + * @requires vm.flavor == "server" & !vm.emulatedClient * @library /test/lib * @modules java.base/jdk.internal.misc * @modules java.base/jdk.internal.vm.annotation diff --git a/hotspot/test/serviceability/dcmd/compiler/CompilerDirectivesDCMDTest.java b/hotspot/test/serviceability/dcmd/compiler/CompilerDirectivesDCMDTest.java index c43dfafa56f..8d40423b5e8 100644 --- a/hotspot/test/serviceability/dcmd/compiler/CompilerDirectivesDCMDTest.java +++ b/hotspot/test/serviceability/dcmd/compiler/CompilerDirectivesDCMDTest.java @@ -49,7 +49,7 @@ public class CompilerDirectivesDCMDTest { public void run(CommandExecutor executor) { - if (Platform.isServer()) { + if (Platform.isServer() && !Platform.isEmulatedClient()) { filename = System.getProperty("test.src", ".") + File.separator + "control2.txt"; } else { filename = System.getProperty("test.src", ".") + File.separator + "control1.txt"; diff --git a/hotspot/test/testlibrary/ctw/src/sun/hotspot/tools/ctw/Utils.java b/hotspot/test/testlibrary/ctw/src/sun/hotspot/tools/ctw/Utils.java index 4159c483408..75d82dd1ebd 100644 --- a/hotspot/test/testlibrary/ctw/src/sun/hotspot/tools/ctw/Utils.java +++ b/hotspot/test/testlibrary/ctw/src/sun/hotspot/tools/ctw/Utils.java @@ -101,10 +101,12 @@ public class Utils { INITIAL_COMP_LEVEL = 1; } else { String vmName = System.getProperty("java.vm.name"); - if (Utils.endsWithIgnoreCase(vmName, " Server VM")) { + String vmInfo = System.getProperty("java.vm.info"); + boolean isEmulatedClient = (vmInfo != null) && vmInfo.contains("emulated-client"); + if (Utils.endsWithIgnoreCase(vmName, " Server VM") && !isEmulatedClient) { INITIAL_COMP_LEVEL = 4; } else if (Utils.endsWithIgnoreCase(vmName, " Client VM") - || Utils.endsWithIgnoreCase(vmName, " Minimal VM")) { + || Utils.endsWithIgnoreCase(vmName, " Minimal VM") || isEmulatedClient) { INITIAL_COMP_LEVEL = 1; } else { throw new RuntimeException("Unknown VM: " + vmName); diff --git a/hotspot/test/testlibrary_tests/TestMutuallyExclusivePlatformPredicates.java b/hotspot/test/testlibrary_tests/TestMutuallyExclusivePlatformPredicates.java index 43c9715a95e..5e56d66bd4a 100644 --- a/hotspot/test/testlibrary_tests/TestMutuallyExclusivePlatformPredicates.java +++ b/hotspot/test/testlibrary_tests/TestMutuallyExclusivePlatformPredicates.java @@ -50,7 +50,7 @@ public class TestMutuallyExclusivePlatformPredicates { OS("isAix", "isLinux", "isOSX", "isSolaris", "isWindows"), VM_TYPE("isClient", "isServer", "isGraal", "isMinimal", "isZero", "isEmbedded"), MODE("isInt", "isMixed", "isComp"), - IGNORED("isDebugBuild", "isFastDebugBuild", "isSlowDebugBuild", + IGNORED("isEmulatedClient", "isDebugBuild", "isFastDebugBuild", "isSlowDebugBuild", "shouldSAAttach", "canPtraceAttachLinux", "canAttachOSX", "isTieredSupported"); From 0ac0d9ac29c0226fce7a965163e96e2a536d3716 Mon Sep 17 00:00:00 2001 From: Jamsheed Mohammed C M Date: Tue, 17 Jan 2017 21:39:22 -0800 Subject: [PATCH 046/157] 8166002: Emulate client build on platforms with reduced virtual address space The default VM ergonomics on Windows/x86 (32-bit) are changed to client like. Reviewed-by: kvn, iveresov --- test/jtreg-ext/requires/VMProps.java | 12 ++++++++++++ test/lib/jdk/test/lib/Platform.java | 4 ++++ 2 files changed, 16 insertions(+) diff --git a/test/jtreg-ext/requires/VMProps.java b/test/jtreg-ext/requires/VMProps.java index 15c854f964b..8ac981d28b2 100644 --- a/test/jtreg-ext/requires/VMProps.java +++ b/test/jtreg-ext/requires/VMProps.java @@ -64,6 +64,7 @@ public class VMProps implements Callable> { map.put("vm.simpleArch", vmArch()); map.put("vm.debug", vmDebug()); map.put("vm.jvmci", vmJvmci()); + map.put("vm.emulatedClient", vmEmulatedClient()); map.put("vm.cpu.features", cpuFeatures()); vmGC(map); // vm.gc.X = true/false @@ -168,6 +169,17 @@ public class VMProps implements Callable> { return "" + (WB.getBooleanVMFlag("EnableJVMCI") != null); } + /** + * @return true if VM runs in emulated-client mode and false otherwise. + */ + protected String vmEmulatedClient() { + String vmInfo = System.getProperty("java.vm.info"); + if (vmInfo == null) { + return "false"; + } + return "" + vmInfo.contains(" emulated-client"); + } + /** * @return supported CPU features */ diff --git a/test/lib/jdk/test/lib/Platform.java b/test/lib/jdk/test/lib/Platform.java index 3f924371c43..26bbf1bae94 100644 --- a/test/lib/jdk/test/lib/Platform.java +++ b/test/lib/jdk/test/lib/Platform.java @@ -63,6 +63,10 @@ public class Platform { return vmName.contains("Embedded"); } + public static boolean isEmulatedClient() { + return vmInfo.contains(" emulated-client"); + } + public static boolean isTieredSupported() { return compiler.contains("Tiered Compilers"); } From a6092584f9c8e87c36ff4b31f645fe4efa92156f Mon Sep 17 00:00:00 2001 From: Tobias Hartmann Date: Wed, 18 Jan 2017 08:54:29 +0100 Subject: [PATCH 047/157] 8172884: TraceOptoPipelining and TraceOptoOutput are broken Compiler Control code needs not set the default values for the directive according to the flag value. Reviewed-by: neliasso, redestad --- hotspot/src/share/vm/compiler/compilerDirectives.hpp | 5 ++--- hotspot/src/share/vm/opto/compile.cpp | 2 +- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/hotspot/src/share/vm/compiler/compilerDirectives.hpp b/hotspot/src/share/vm/compiler/compilerDirectives.hpp index 283fd48127e..7c4efa650a5 100644 --- a/hotspot/src/share/vm/compiler/compilerDirectives.hpp +++ b/hotspot/src/share/vm/compiler/compilerDirectives.hpp @@ -60,13 +60,12 @@ cflags(BlockLayoutByFrequency, bool, BlockLayoutByFrequency, BlockLayoutByFrequency) \ cflags(PrintOptoAssembly, bool, PrintOptoAssembly, PrintOptoAssembly) \ cflags(PrintIntrinsics, bool, PrintIntrinsics, PrintIntrinsics) \ - cflags(TraceOptoPipelining, bool, false, TraceOptoPipelining) \ - cflags(TraceOptoOutput, bool, false, TraceOptoOutput) \ +NOT_PRODUCT(cflags(TraceOptoPipelining, bool, TraceOptoPipelining, TraceOptoPipelining)) \ +NOT_PRODUCT(cflags(TraceOptoOutput, bool, TraceOptoOutput, TraceOptoOutput)) \ cflags(TraceSpilling, bool, TraceSpilling, TraceSpilling) \ cflags(Vectorize, bool, false, Vectorize) \ cflags(VectorizeDebug, uintx, 0, VectorizeDebug) \ cflags(CloneMapDebug, bool, false, CloneMapDebug) \ - cflags(DoReserveCopyInSuperWordDebug, bool, false, DoReserveCopyInSuperWordDebug) \ cflags(IGVPrintLevel, intx, PrintIdealGraphLevel, IGVPrintLevel) \ cflags(MaxNodeLimit, intx, MaxNodeLimit, MaxNodeLimit) #else diff --git a/hotspot/src/share/vm/opto/compile.cpp b/hotspot/src/share/vm/opto/compile.cpp index 77e20b264cb..4c84b0339ec 100644 --- a/hotspot/src/share/vm/opto/compile.cpp +++ b/hotspot/src/share/vm/opto/compile.cpp @@ -971,7 +971,7 @@ Compile::Compile( ciEnv* ci_env, _java_calls(0), _inner_loops(0), #ifndef PRODUCT - _trace_opto_output(TraceOptoOutput), + _trace_opto_output(directive->TraceOptoOutputOption), _in_dump_cnt(0), _printer(NULL), #endif From 362fbe12e8a725d48f73acbebd37270d5ea3cf21 Mon Sep 17 00:00:00 2001 From: Coleen Phillimore Date: Wed, 18 Jan 2017 10:30:56 -0500 Subject: [PATCH 048/157] 8144518: ClassVerboseTest crashes on Windows Simplify Bytecode_tableswitch code so windows doesn't generate bad code for it. Reviewed-by: ctornqvi, dholmes --- hotspot/src/share/vm/interpreter/bytecode.cpp | 4 ++-- hotspot/src/share/vm/interpreter/bytecode.hpp | 14 +++++++------- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/hotspot/src/share/vm/interpreter/bytecode.cpp b/hotspot/src/share/vm/interpreter/bytecode.cpp index 80b95d627b5..6cc38a5a0cd 100644 --- a/hotspot/src/share/vm/interpreter/bytecode.cpp +++ b/hotspot/src/share/vm/interpreter/bytecode.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2017, 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 @@ -112,7 +112,7 @@ void Bytecode::assert_native_index(Bytecodes::Code bc, bool is_wide) { // Implementation of Bytecode_tableupswitch int Bytecode_tableswitch::dest_offset_at(int i) const { - return get_Java_u4_at(aligned_offset(1 + (3 + i)*jintSize)); + return get_aligned_Java_u4_at(1 + (3 + i)*jintSize); } diff --git a/hotspot/src/share/vm/interpreter/bytecode.hpp b/hotspot/src/share/vm/interpreter/bytecode.hpp index f3fc9ea9d6a..5c53ab4121f 100644 --- a/hotspot/src/share/vm/interpreter/bytecode.hpp +++ b/hotspot/src/share/vm/interpreter/bytecode.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2017, 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 @@ -45,11 +45,11 @@ class Bytecode: public StackObj { address addr_at (int offset) const { return (address)_bcp + offset; } u_char byte_at(int offset) const { return *addr_at(offset); } address aligned_addr_at (int offset) const { return (address)round_to((intptr_t)addr_at(offset), jintSize); } - int aligned_offset (int offset) const { return aligned_addr_at(offset) - addr_at(0); } // Word access: int get_Java_u2_at (int offset) const { return Bytes::get_Java_u2(addr_at(offset)); } int get_Java_u4_at (int offset) const { return Bytes::get_Java_u4(addr_at(offset)); } + int get_aligned_Java_u4_at(int offset) const { return Bytes::get_Java_u4(aligned_addr_at(offset)); } int get_native_u2_at (int offset) const { return Bytes::get_native_u2(addr_at(offset)); } int get_native_u4_at (int offset) const { return Bytes::get_native_u4(addr_at(offset)); } @@ -150,8 +150,8 @@ class Bytecode_lookupswitch: public Bytecode { void verify() const PRODUCT_RETURN; // Attributes - int default_offset() const { return get_Java_u4_at(aligned_offset(1 + 0*jintSize)); } - int number_of_pairs() const { return get_Java_u4_at(aligned_offset(1 + 1*jintSize)); } + int default_offset() const { return get_aligned_Java_u4_at(1 + 0*jintSize); } + int number_of_pairs() const { return get_aligned_Java_u4_at(1 + 1*jintSize); } LookupswitchPair pair_at(int i) const { assert(0 <= i && i < number_of_pairs(), "pair index out of bounds"); return LookupswitchPair(aligned_addr_at(1 + (1 + i)*2*jintSize)); @@ -166,9 +166,9 @@ class Bytecode_tableswitch: public Bytecode { void verify() const PRODUCT_RETURN; // Attributes - int default_offset() const { return get_Java_u4_at(aligned_offset(1 + 0*jintSize)); } - int low_key() const { return get_Java_u4_at(aligned_offset(1 + 1*jintSize)); } - int high_key() const { return get_Java_u4_at(aligned_offset(1 + 2*jintSize)); } + int default_offset() const { return get_aligned_Java_u4_at(1 + 0*jintSize); } + int low_key() const { return get_aligned_Java_u4_at(1 + 1*jintSize); } + int high_key() const { return get_aligned_Java_u4_at(1 + 2*jintSize); } int dest_offset_at(int i) const; int length() { return high_key()-low_key()+1; } }; From 3d5e2ddf611f78793f394fd602981aea508c3aa3 Mon Sep 17 00:00:00 2001 From: Vladimir Kozlov Date: Wed, 18 Jan 2017 14:36:54 -0800 Subject: [PATCH 049/157] 8172990: [AOT] Missing GC scan of _metaspace_got array containing Klass* Added back _metaspace_got array scan. Reviewed-by: dlong --- .../tools/jaotc/CallSiteRelocationSymbol.java | 6 ---- .../jaotc/JavaCallSiteRelocationSymbol.java | 16 +++++++-- hotspot/src/share/vm/aot/aotCodeHeap.cpp | 33 ++++--------------- .../src/share/vm/aot/aotCompiledMethod.cpp | 27 +++++++-------- .../src/share/vm/aot/aotCompiledMethod.hpp | 2 -- .../src/share/vm/runtime/deoptimization.cpp | 4 +-- 6 files changed, 35 insertions(+), 53 deletions(-) diff --git a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/CallSiteRelocationSymbol.java b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/CallSiteRelocationSymbol.java index 68f86ef65e3..5fce078a470 100644 --- a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/CallSiteRelocationSymbol.java +++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/CallSiteRelocationSymbol.java @@ -59,12 +59,6 @@ abstract class CallSiteRelocationSymbol { addExternalPltToGotRelocation(binaryContainer, symbol, relocationOffset); } - protected static void addMetaspaceGotRelocation(BinaryContainer binaryContainer, String symbolName, int symbolOffset, int relocationOffset) { - ByteContainer container = binaryContainer.getMetaspaceGotContainer(); - Symbol symbol = container.createGotSymbol(symbolOffset, symbolName); - addExternalPltToGotRelocation(binaryContainer, symbol, relocationOffset); - } - /** * Add an {@link RelocType#EXTERNAL_GOT_TO_PLT} relocation to the * {@link BinaryContainer#getExtLinkageGOTContainer()}. diff --git a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/JavaCallSiteRelocationSymbol.java b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/JavaCallSiteRelocationSymbol.java index a14049dd87f..f589610ded8 100644 --- a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/JavaCallSiteRelocationSymbol.java +++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/JavaCallSiteRelocationSymbol.java @@ -37,6 +37,7 @@ import jdk.vm.ci.hotspot.HotSpotResolvedJavaMethod; final class JavaCallSiteRelocationSymbol extends CallSiteRelocationSymbol { private static final byte[] zeroSlot = new byte[8]; + // -1 represents Universe::non_oop_word() value private static final byte[] minusOneSlot = {-1, -1, -1, -1, -1, -1, -1, -1}; public JavaCallSiteRelocationSymbol(CompiledMethodInfo mi, Call call, CallSiteRelocationInfo callSiteRelocation, BinaryContainer binaryContainer) { @@ -79,30 +80,39 @@ final class JavaCallSiteRelocationSymbol extends CallSiteRelocationSymbol { } // Add relocation to GOT cell for call resolution jump. + // This GOT cell will be initialized during JVM startup with address + // of JVM runtime call resolution function. String gotSymbolName = "got." + getResolveSymbolName(binaryContainer, mi, call); Symbol gotSymbol = binaryContainer.getGotSymbol(gotSymbolName); addExternalPltToGotRelocation(binaryContainer, gotSymbol, stub.getResolveJumpOffset()); // Add relocation to resolve call jump instruction address for GOT cell. + // This GOT cell will be initialized with address of resolution jump instruction and + // will be updated with call destination address by JVM runtime call resolution code. String pltJmpSymbolName = relocationSymbolName("plt.jmp", mi, call, callSiteRelocation); addCodeContainerRelocation(binaryContainer, pltJmpSymbolName, stub.getResolveJumpStart(), gotStartOffset); // Add relocation to GOT cell for dispatch jump. + // The dispatch jump loads destination address from this GOT cell. String gotEntrySymbolName = relocationSymbolName("got.entry", mi, call, callSiteRelocation); addExtLinkageGotContainerRelocation(binaryContainer, gotEntrySymbolName, gotStartOffset, stub.getDispatchJumpOffset()); - // Virtual call needs initial -1 value. + // Virtual call needs initial -1 value for Klass pointer. + // Non virtual call needs initial 0 value for Method pointer to call c2i adapter. byte[] slot = isVirtualCall ? minusOneSlot : zeroSlot; - final int gotMetaOffset = binaryContainer.appendMetaspaceGotBytes(slot, 0, slot.length); + final int gotMetaOffset = binaryContainer.appendExtLinkageGotBytes(slot, 0, slot.length); // Add relocation to GOT cell for move instruction (Klass* for virtual, Method* otherwise). String gotMoveSymbolName = relocationSymbolName("got.move", mi, call, callSiteRelocation); - addMetaspaceGotRelocation(binaryContainer, gotMoveSymbolName, gotMetaOffset, stub.getMovOffset()); + addExtLinkageGotContainerRelocation(binaryContainer, gotMoveSymbolName, gotMetaOffset, stub.getMovOffset()); if (isVirtualCall) { // Nothing. } else { // Add relocation to GOT cell for c2i adapter jump. + // The c2i jump instruction loads destination address from this GOT cell. + // This GOT cell is initialized with -1 and will be updated + // by JVM runtime call resolution code. String gotC2ISymbolName = relocationSymbolName("got.c2i", mi, call, callSiteRelocation); addExtLinkageGotContainerRelocation(binaryContainer, gotC2ISymbolName, gotStartOffset + 8, stub.getC2IJumpOffset()); } diff --git a/hotspot/src/share/vm/aot/aotCodeHeap.cpp b/hotspot/src/share/vm/aot/aotCodeHeap.cpp index 52e2c8d55b1..87d41f80777 100644 --- a/hotspot/src/share/vm/aot/aotCodeHeap.cpp +++ b/hotspot/src/share/vm/aot/aotCodeHeap.cpp @@ -830,38 +830,19 @@ void AOTCodeHeap::oops_do(OopClosure* f) { } } -// Yes, this is faster than going through the relocations, -// but there are two problems: -// 1) GOT slots are sometimes patched with non-Metadata values -// 2) We don't want to scan metadata for dead methods -// Unfortunately we don't know if the metadata belongs to -// live aot methods or not, so process them all. If this -// is for mark_on_stack, some old methods may stick around -// forever instead of getting cleaned up. +// Scan only metaspace_got cells which should have only Klass*, +// metadata_got cells are scanned only for alive AOT methods +// by AOTCompiledMethod::metadata_do(). void AOTCodeHeap::got_metadata_do(void f(Metadata*)) { for (int i = 1; i < _metaspace_got_size; i++) { Metadata** p = &_metaspace_got[i]; Metadata* md = *p; if (md == NULL) continue; // skip non-oops - intptr_t meta = (intptr_t)md; - if (meta == -1) continue; // skip non-oops if (Metaspace::contains(md)) { f(md); - } - } - for (int i = 1; i < _metadata_got_size; i++) { - Metadata** p = &_metadata_got[i]; - Metadata* md = *p; - intptr_t meta = (intptr_t)md; - if ((meta & 1) == 1) { - // already resolved - md = (Metadata*)(meta & ~1); } else { - continue; - } - if (md == NULL) continue; // skip non-oops - if (Metaspace::contains(md)) { - f(md); + intptr_t meta = (intptr_t)md; + fatal("Invalid value in _metaspace_got[%d] = " INTPTR_FORMAT, i, meta); } } } @@ -910,8 +891,6 @@ void AOTCodeHeap::metadata_do(void f(Metadata*)) { aot->metadata_do(f); } } -#if 0 - // With the marking above, this call doesn't seem to be needed + // Scan metaspace_got cells. got_metadata_do(f); -#endif } diff --git a/hotspot/src/share/vm/aot/aotCompiledMethod.cpp b/hotspot/src/share/vm/aot/aotCompiledMethod.cpp index 1f40284da7e..c501ce12e69 100644 --- a/hotspot/src/share/vm/aot/aotCompiledMethod.cpp +++ b/hotspot/src/share/vm/aot/aotCompiledMethod.cpp @@ -71,15 +71,6 @@ static void metadata_oops_do(Metadata** metadata_begin, Metadata **metadata_end, } #endif -void AOTCompiledMethod::oops_do(OopClosure* f) { - if (_oop != NULL) { - f->do_oop(&_oop); - } -#if 0 - metadata_oops_do(metadata_begin(), metadata_end(), f); -#endif -} - bool AOTCompiledMethod::do_unloading_oops(address low_boundary, BoolObjectClosure* is_alive, bool unloading_occurred) { return false; } @@ -161,9 +152,6 @@ Metadata* AOTCompiledMethod::metadata_at(int index) const { *entry = (Metadata*)meta; // Should be atomic on x64 return (Metadata*)m; } - // need to resolve it here..., patching of GOT need to be CAS or atomic operation. - // FIXIT: need methods for debuginfo. - // return _method; } ShouldNotReachHere(); return NULL; } @@ -288,11 +276,19 @@ void AOTCompiledMethod::metadata_do(void f(Metadata*)) { f(cichk->holder_method()); f(cichk->holder_klass()); } else { + // Get Klass* or NULL (if value is -1) from GOT cell of virtual call PLT stub. Metadata* ic_oop = ic->cached_metadata(); if (ic_oop != NULL) { f(ic_oop); } } + } else if (iter.type() == relocInfo::static_call_type || + iter.type() == relocInfo::opt_virtual_call_type){ + // Check Method* in AOT c2i stub for other calls. + Metadata* meta = (Metadata*)nativeLoadGot_at(nativePltCall_at(iter.addr())->plt_c2i_stub())->data(); + if (meta != NULL) { + f(meta); + } } } } @@ -332,7 +328,12 @@ void AOTCompiledMethod::print_on(outputStream* st, const char* msg) const { st->print("%4d ", _aot_id); // print compilation number st->print(" aot[%2d]", _heap->dso_id()); // Stubs have _method == NULL - st->print(" %s", (_method == NULL ? _name : _method->name_and_sig_as_C_string())); + if (_method == NULL) { + st->print(" %s", _name); + } else { + ResourceMark m; + st->print(" %s", _method->name_and_sig_as_C_string()); + } if (Verbose) { st->print(" entry at " INTPTR_FORMAT, p2i(_code)); } diff --git a/hotspot/src/share/vm/aot/aotCompiledMethod.hpp b/hotspot/src/share/vm/aot/aotCompiledMethod.hpp index 7fef6fdb433..723bbdb8d30 100644 --- a/hotspot/src/share/vm/aot/aotCompiledMethod.hpp +++ b/hotspot/src/share/vm/aot/aotCompiledMethod.hpp @@ -257,8 +257,6 @@ private: return (int) (*_state_adr); } - virtual void oops_do(OopClosure* f); - // inlined and non-virtual for AOTCodeHeap::oops_do void do_oops(OopClosure* f) { assert(_is_alive(), ""); diff --git a/hotspot/src/share/vm/runtime/deoptimization.cpp b/hotspot/src/share/vm/runtime/deoptimization.cpp index e3b88640768..aba4f3f478a 100644 --- a/hotspot/src/share/vm/runtime/deoptimization.cpp +++ b/hotspot/src/share/vm/runtime/deoptimization.cpp @@ -1596,9 +1596,9 @@ JRT_ENTRY(void, Deoptimization::uncommon_trap_inner(JavaThread* thread, jint tra get_method_data(thread, profiled_method, create_if_missing); // Log a message - Events::log_deopt_message(thread, "Uncommon trap: reason=%s action=%s pc=" INTPTR_FORMAT " method=%s @ %d", + Events::log_deopt_message(thread, "Uncommon trap: reason=%s action=%s pc=" INTPTR_FORMAT " method=%s @ %d %s", trap_reason_name(reason), trap_action_name(action), p2i(fr.pc()), - trap_method->name_and_sig_as_C_string(), trap_bci); + trap_method->name_and_sig_as_C_string(), trap_bci, nm->compiler_name()); // Print a bunch of diagnostics, if requested. if (TraceDeoptimization || LogCompilation) { From 417f6a4ac86b5323527cb8fe570de76f65072545 Mon Sep 17 00:00:00 2001 From: David Holmes Date: Wed, 18 Jan 2017 19:54:18 -0500 Subject: [PATCH 050/157] 8172261: [JVMTI] Specification for early VM start event needs to lower expectations in relation class loading Reviewed-by: dcubed, sspitsyn, alanb --- hotspot/src/share/vm/prims/jvmti.xml | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/hotspot/src/share/vm/prims/jvmti.xml b/hotspot/src/share/vm/prims/jvmti.xml index 0f390214eb2..7a0515c2bc4 100644 --- a/hotspot/src/share/vm/prims/jvmti.xml +++ b/hotspot/src/share/vm/prims/jvmti.xml @@ -1,7 +1,7 @@ m2 (meaning m1 reads m2) - * m1 --> m3 - * m2 --> m3 - * } - * - *

Resolution is an additive process. When computing the transitive closure - * then the dependence relation may include dependences on modules in parent - * configurations. The result is a relative configuration that is - * relative to one or more parent configurations and where the readability graph - * may have edges from modules in the configuration to modules in parent - * configurations. - * - *

- * - *

Suppose we have the following observable modules:

- *
 {@code
- *     module m1 { requires m2; requires java.xml; }
- *     module m2 { }
- * } 
- * - *

If module {@code m1} is resolved with the configuration for the {@link - * java.lang.reflect.Layer#boot() boot} layer as the parent then the resulting - * configuration contains two modules ({@code m1}, {@code m2}). The edges in - * its readability graph are: - *

 {@code
- *     m1 --> m2
- *     m1 --> java.xml
- * } 
- * where module {@code java.xml} is in the parent configuration. For - * simplicity, this example omits the implicitly declared dependence on the - * {@code java.base} module. - * - * - *

{@link ModuleDescriptor#isAutomatic() Automatic} modules receive special - * treatment during resolution. Each automatic module is resolved so that it - * reads all other modules in the configuration and all parent configurations. - * Each automatic module is also resolved as if it {@code requires transitive} - * all other automatic modules in the configuration (and all automatic modules - * in parent configurations).

- - *

Service binding

- * - *

Service binding is the process of augmenting a graph of resolved modules - * from the set of observable modules induced by the service-use dependence - * ({@code uses} and {@code provides} clauses). Any module that was not - * previously in the graph requires resolution to compute its transitive - * closure. Service binding is an iterative process in that adding a module - * that satisfies some service-use dependence may introduce new service-use - * dependences.

- * - *

Suppose we have the following observable modules:

- *
 {@code
- *     module m1 { exports p; uses p.S; }
- *     module m2 { requires m1; provides p.S with p2.S2; }
- *     module m3 { requires m1; requires m4; provides p.S with p3.S3; }
- *     module m4 { }
- * } 
- * - *

If the module {@code m1} is resolved then the resulting graph of modules - * has one module ({@code m1}). If the graph is augmented with modules induced - * by the service-use dependence relation then the configuration will contain - * four modules ({@code m1}, {@code m2}, {@code m3}, {@code m4}). The edges in - * its readability graph are:

- *
 {@code
- *     m2 --> m1
- *     m3 --> m1
- *     m3 --> m4
- * } 
- *

The edges in the conceptual service-use graph are:

- *
 {@code
- *     m1 --> m2  (meaning m1 uses a service that is provided by m2)
- *     m1 --> m3
- * } 
- * - *

If this configuration is instantiated as a {@code Layer}, and if code in - * module {@code m1} uses {@link java.util.ServiceLoader ServiceLoader} to - * iterate over implementations of {@code p.S.class}, then it will iterate over - * an instance of {@code p2.S2} and {@code p3.S3}.

+ *

Each {@link java.lang.reflect.Layer layer} of modules in the Java virtual + * machine is created from a configuration. The configuration for the {@link + * java.lang.reflect.Layer#boot() boot} layer is obtained by invoking {@code + * Layer.boot().configuration()}. The configuration for the boot layer will + * often be the parent when creating new configurations.

* *

Example

* - *

The following example uses the {@code resolveRequires} method to resolve - * a module named myapp with the configuration for the boot layer as - * the parent configuration. It prints the name of each resolved module and - * the names of the modules that each module reads.

+ *

The following example uses the {@link + * #resolve(ModuleFinder,ModuleFinder,Collection) resolve} method to resolve a + * module named myapp with the configuration for the boot layer as the + * parent configuration. It prints the name of each resolved module and the + * names of the modules that each module reads.

* *
{@code
  *    ModuleFinder finder = ModuleFinder.of(dir1, dir2, dir3);
  *
  *    Configuration parent = Layer.boot().configuration();
  *
- *    Configuration cf = parent.resolveRequires(finder,
- *                                              ModuleFinder.of(),
- *                                              Set.of("myapp"));
+ *    Configuration cf = parent.resolve(finder, ModuleFinder.of(), Set.of("myapp"));
  *    cf.modules().forEach(m -> {
  *        System.out.format("%s -> %s%n",
  *            m.name(),
@@ -172,6 +94,7 @@ import java.util.stream.Stream;
  * }
* * @since 9 + * @spec JPMS * @see java.lang.reflect.Layer */ public final class Configuration { @@ -186,11 +109,23 @@ public final class Configuration { private final Set modules; private final Map nameToModule; + // module constraints on target + private final String osName; + private final String osArch; + private final String osVersion; + + String osName() { return osName; } + String osArch() { return osArch; } + String osVersion() { return osVersion; } + private Configuration() { this.parents = Collections.emptyList(); this.graph = Collections.emptyMap(); this.modules = Collections.emptySet(); this.nameToModule = Collections.emptyMap(); + this.osName = null; + this.osArch = null; + this.osVersion = null; } private Configuration(List parents, @@ -214,27 +149,30 @@ public final class Configuration { this.graph = g; this.modules = Set.of(moduleArray); this.nameToModule = Map.ofEntries(nameEntries); - } + this.osName = resolver.osName(); + this.osArch = resolver.osArch(); + this.osVersion = resolver.osVersion(); + } /** * Resolves a collection of root modules, with this configuration as its * parent, to create a new configuration. This method works exactly as * specified by the static {@link - * #resolveRequires(ModuleFinder,List,ModuleFinder,Collection) resolveRequires} + * #resolve(ModuleFinder,List,ModuleFinder,Collection) resolve} * method when invoked with this configuration as the parent. In other words, * if this configuration is {@code cf} then this method is equivalent to * invoking: *
 {@code
-     *     Configuration.resolveRequires(before, List.of(cf), after, roots);
+     *     Configuration.resolve(before, List.of(cf), after, roots);
      * }
* * @param before * The before module finder to find modules * @param after - * The after module finder to locate modules when a - * module cannot be located by the {@code before} module finder - * and the module is not in this configuration + * The after module finder to locate modules when not + * located by the {@code before} module finder or in parent + * configurations * @param roots * The possibly-empty collection of module names of the modules * to resolve @@ -242,16 +180,20 @@ public final class Configuration { * @return The configuration that is the result of resolving the given * root modules * + * @throws FindException + * If resolution fails for any of the observability-related reasons + * specified by the static {@code resolve} method * @throws ResolutionException - * If resolution or the post-resolution checks fail + * If any of the post-resolution consistency checks specified by + * the static {@code resolve} method fail * @throws SecurityException * If locating a module is denied by the security manager */ - public Configuration resolveRequires(ModuleFinder before, - ModuleFinder after, - Collection roots) + public Configuration resolve(ModuleFinder before, + ModuleFinder after, + Collection roots) { - return resolveRequires(before, List.of(this), after, roots); + return resolve(before, List.of(this), after, roots); } @@ -259,12 +201,12 @@ public final class Configuration { * Resolves a collection of root modules, with service binding, and with * this configuration as its parent, to create a new configuration. * This method works exactly as specified by the static {@link - * #resolveRequiresAndUses(ModuleFinder,List,ModuleFinder,Collection) - * resolveRequiresAndUses} method when invoked with this configuration + * #resolveAndBind(ModuleFinder,List,ModuleFinder,Collection) + * resolveAndBind} method when invoked with this configuration * as the parent. In other words, if this configuration is {@code cf} then * this method is equivalent to invoking: *
 {@code
-     *     Configuration.resolveRequiresAndUses(before, List.of(cf), after, roots);
+     *     Configuration.resolveAndBind(before, List.of(cf), after, roots);
      * }
* * @@ -272,25 +214,29 @@ public final class Configuration { * The before module finder to find modules * @param after * The after module finder to locate modules when not - * located by the {@code before} module finder and this - * configuration + * located by the {@code before} module finder or in parent + * configurations * @param roots * The possibly-empty collection of module names of the modules * to resolve * - * @return The configuration that is the result of resolving the given - * root modules + * @return The configuration that is the result of resolving, with service + * binding, the given root modules * + * @throws FindException + * If resolution fails for any of the observability-related reasons + * specified by the static {@code resolve} method * @throws ResolutionException - * If resolution or the post-resolution checks fail + * If any of the post-resolution consistency checks specified by + * the static {@code resolve} method fail * @throws SecurityException * If locating a module is denied by the security manager */ - public Configuration resolveRequiresAndUses(ModuleFinder before, - ModuleFinder after, - Collection roots) + public Configuration resolveAndBind(ModuleFinder before, + ModuleFinder after, + Collection roots) { - return resolveRequiresAndUses(before, List.of(this), after, roots); + return resolveAndBind(before, List.of(this), after, roots); } @@ -301,14 +247,14 @@ public final class Configuration { * * This method is used to create the configuration for the boot layer. */ - static Configuration resolveRequiresAndUses(ModuleFinder finder, - Collection roots, - boolean check, - PrintStream traceOutput) + static Configuration resolveAndBind(ModuleFinder finder, + Collection roots, + boolean check, + PrintStream traceOutput) { List parents = List.of(empty()); Resolver resolver = new Resolver(finder, parents, ModuleFinder.of(), traceOutput); - resolver.resolveRequires(roots).resolveUses(); + resolver.resolve(roots).bind(); return new Configuration(parents, resolver, check); } @@ -328,11 +274,11 @@ public final class Configuration { * *

When all modules have been resolved then the resulting dependency * graph is checked to ensure that it does not contain cycles. A - * readability graph is constructed and in conjunction with the module + * readability graph is constructed, and in conjunction with the module * exports and service use, checked for consistency.

* - *

Resolution and the (post-resolution) consistency checks may fail for - * following reasons:

+ *

Resolution may fail with {@code FindException} for the following + * observability-related reasons:

* *
    *
  • A root module, or a direct or transitive dependency, is not @@ -343,6 +289,20 @@ public final class Configuration { * descriptor ({@code module-info.class}) or two versions of the same * module are found in the same directory.

  • * + *
  • A module with the required name is found but the module + * requires a different {@link ModuleDescriptor#osName() operating + * system}, {@link ModuleDescriptor#osArch() architecture}, or {@link + * ModuleDescriptor#osVersion() version} to other modules that have + * been resolved for the new configuration or modules in the parent + * configurations.

  • + * + *
+ * + *

Post-resolution consistency checks may fail with {@code + * ResolutionException} for the following reasons:

+ * + *
    + * *
  • A cycle is detected, say where module {@code m1} requires * module {@code m2} and {@code m2} requires {@code m1}.

  • * @@ -356,21 +316,12 @@ public final class Configuration { * module {@code M} nor exported to {@code M} by any module that * {@code M} reads.

    * - *
  • A module {@code M} declares that it - * "{@code provides ... with q.T}" but package {@code q} is not in - * module {@code M}.

  • - * - *
  • Two or more modules in the configuration are specific to - * different {@link ModuleDescriptor#osName() operating systems}, - * {@link ModuleDescriptor#osArch() architectures}, or {@link - * ModuleDescriptor#osVersion() versions}.

  • - * - *
  • Other implementation specific checks, for example referential - * integrity checks to ensure that different versions of tighly coupled - * modules cannot be combined in the same configuration.

  • - * *
* + * @implNote In the implementation then observability of modules may depend + * on referential integrity checks that ensure different builds of tightly + * coupled modules are not combined in the same configuration. + * * @param before * The before module finder to find modules * @param parents @@ -386,17 +337,22 @@ public final class Configuration { * @return The configuration that is the result of resolving the given * root modules * + * @throws FindException + * If resolution fails for an observability-related reason * @throws ResolutionException - * If resolution or the post-resolution checks fail + * If a post-resolution consistency checks fails * @throws IllegalArgumentException - * If the list of parents is empty + * If the list of parents is empty, or the list has two or more + * parents with modules for different target operating systems, + * architectures, or versions + * * @throws SecurityException * If locating a module is denied by the security manager */ - public static Configuration resolveRequires(ModuleFinder before, - List parents, - ModuleFinder after, - Collection roots) + public static Configuration resolve(ModuleFinder before, + List parents, + ModuleFinder after, + Collection roots) { Objects.requireNonNull(before); Objects.requireNonNull(after); @@ -407,7 +363,7 @@ public final class Configuration { throw new IllegalArgumentException("'parents' is empty"); Resolver resolver = new Resolver(before, parentList, after, null); - resolver.resolveRequires(roots); + resolver.resolve(roots); return new Configuration(parentList, resolver, true); } @@ -417,24 +373,24 @@ public final class Configuration { * configuration. * *

This method works exactly as specified by {@link - * #resolveRequires(ModuleFinder,List,ModuleFinder,Collection) - * resolveRequires} except that the graph of resolved modules is augmented + * #resolve(ModuleFinder,List,ModuleFinder,Collection) + * resolve} except that the graph of resolved modules is augmented * with modules induced by the service-use dependence relation.

* *

More specifically, the root modules are resolved as if by calling - * {@code resolveRequires}. The resolved modules, and all modules in the + * {@code resolve}. The resolved modules, and all modules in the * parent configurations, with {@link ModuleDescriptor#uses() service * dependences} are then examined. All modules found by the given module * finders that {@link ModuleDescriptor#provides() provide} an * implementation of one or more of the service types are added to the * module graph and then resolved as if by calling the {@code - * resolveRequires} method. Adding modules to the module graph may - * introduce new service-use dependences and so the process works - * iteratively until no more modules are added.

+ * resolve} method. Adding modules to the module graph may introduce new + * service-use dependences and so the process works iteratively until no + * more modules are added.

* - *

As service binding involves resolution then it may fail with {@link - * ResolutionException} for exactly the same reasons specified in - * {@code resolveRequires}.

+ *

As service binding involves resolution then it may fail with {@code + * FindException} or {@code ResolutionException} for exactly the same + * reasons specified in {@code resolve}.

* * @param before * The before module finder to find modules @@ -448,20 +404,26 @@ public final class Configuration { * The possibly-empty collection of module names of the modules * to resolve * - * @return The configuration that is the result of resolving the given - * root modules + * @return The configuration that is the result of resolving, with service + * binding, the given root modules * + * @throws FindException + * If resolution fails for any of the observability-related reasons + * specified by the static {@code resolve} method * @throws ResolutionException - * If resolution or the post-resolution checks fail + * If any of the post-resolution consistency checks specified by + * the static {@code resolve} method fail * @throws IllegalArgumentException - * If the list of parents is empty + * If the list of parents is empty, or the list has two or more + * parents with modules for different target operating systems, + * architectures, or versions * @throws SecurityException * If locating a module is denied by the security manager */ - public static Configuration resolveRequiresAndUses(ModuleFinder before, - List parents, - ModuleFinder after, - Collection roots) + public static Configuration resolveAndBind(ModuleFinder before, + List parents, + ModuleFinder after, + Collection roots) { Objects.requireNonNull(before); Objects.requireNonNull(after); @@ -472,7 +434,7 @@ public final class Configuration { throw new IllegalArgumentException("'parents' is empty"); Resolver resolver = new Resolver(before, parentList, after, null); - resolver.resolveRequires(roots).resolveUses(); + resolver.resolve(roots).bind(); return new Configuration(parentList, resolver, true); } diff --git a/jdk/src/java.base/share/classes/java/lang/module/FindException.java b/jdk/src/java.base/share/classes/java/lang/module/FindException.java index d76f2935e7e..411959eb418 100644 --- a/jdk/src/java.base/share/classes/java/lang/module/FindException.java +++ b/jdk/src/java.base/share/classes/java/lang/module/FindException.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2017, 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 @@ -26,10 +26,14 @@ package java.lang.module; /** - * Thrown by module finders when finding a module fails. + * Thrown by a {@link ModuleFinder ModuleFinder} when an error occurs finding + * a module. Also thrown by {@link + * Configuration#resolve(ModuleFinder,java.util.List,ModuleFinder,java.util.Collection) + * Configuration.resolve} when resolution fails for observability-related + * reasons. * - * @see ModuleFinder * @since 9 + * @spec JPMS */ public class FindException extends RuntimeException { diff --git a/jdk/src/java.base/share/classes/java/lang/module/InvalidModuleDescriptorException.java b/jdk/src/java.base/share/classes/java/lang/module/InvalidModuleDescriptorException.java index 981f23a5189..3e306886fb2 100644 --- a/jdk/src/java.base/share/classes/java/lang/module/InvalidModuleDescriptorException.java +++ b/jdk/src/java.base/share/classes/java/lang/module/InvalidModuleDescriptorException.java @@ -31,6 +31,7 @@ package java.lang.module; * * @see ModuleDescriptor#read * @since 9 + * @spec JPMS */ public class InvalidModuleDescriptorException extends RuntimeException { private static final long serialVersionUID = 4863390386809347380L; diff --git a/jdk/src/java.base/share/classes/java/lang/module/ModuleDescriptor.java b/jdk/src/java.base/share/classes/java/lang/module/ModuleDescriptor.java index b10d986ade9..6c05e821026 100644 --- a/jdk/src/java.base/share/classes/java/lang/module/ModuleDescriptor.java +++ b/jdk/src/java.base/share/classes/java/lang/module/ModuleDescriptor.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2009, 2017, 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 @@ import java.io.UncheckedIOException; import java.nio.ByteBuffer; import java.nio.file.Path; import java.util.ArrayList; +import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.EnumSet; @@ -56,29 +57,83 @@ import jdk.internal.module.ModuleInfo; /** * A module descriptor. * - *

A {@code ModuleDescriptor} is typically created from the binary form - * of a module declaration. Alternatively, the {@link ModuleDescriptor.Builder} - * class can be used to create a {@code ModuleDescriptor} from its components. - * The {@link #module module}, {@link #openModule openModule}, and {@link - * #automaticModule automaticModule} methods create builders for building - * different kinds of modules.

+ *

A module descriptor describes a named module and defines methods to + * obtain each of its components. The module descriptor for a named module + * in the Java virtual machine is obtained by invoking the {@link + * java.lang.reflect.Module Module}'s {@link java.lang.reflect.Module#getDescriptor + * getDescriptor} method. Module descriptors can also be created using the + * {@link ModuleDescriptor.Builder} class or by reading the binary form of a + * module declaration ({@code module-info.class}) using the {@link + * #read(InputStream,Supplier) read} methods defined here.

+ * + *

A module descriptor describes a normal, open, or automatic + * module. Normal modules and open modules describe their {@link + * #requires() dependences}, {@link #exports() exported-packages}, the services + * that they {@link #uses() use} or {@link #provides() provide}, and other + * components. Normal modules may {@link #opens() open} specific + * packages. The module descriptor for an open modules does not declare any + * open packages (its {@code opens} method returns an empty set) but when + * instantiated in the Java virtual machine then it is treated as if all + * packages are open. The module descriptor for an automatic module does not + * declare any dependences (except for the mandatory dependency on {@code + * java.base}), and does not declare any exported or open packages. Automatic + * module receive special treatment during resolution so that they read all + * other modules in the configuration. When an automatic module is instantiated + * in the Java virtual machine then it reads every unnamed module and is + * treated as if all packages are exported and open.

* *

{@code ModuleDescriptor} objects are immutable and safe for use by * multiple concurrent threads.

* - * @since 9 * @see java.lang.reflect.Module + * @since 9 + * @spec JPMS */ public class ModuleDescriptor implements Comparable { + /** + * A modifier on a module. + * + * @see ModuleDescriptor#modifiers() + * @since 9 + */ + public static enum Modifier { + /** + * An open module. An open module does not declare any open packages + * but the resulting module is treated as if all packages are open. + */ + OPEN, + + /** + * An automatic module. An automatic module is treated as if it exports + * and opens all packages. + * + * @apiNote This modifier does not correspond to a module flag in the + * binary form of a module declaration ({@code module-info.class}). + */ + AUTOMATIC, + + /** + * The module was not explicitly or implicitly declared. + */ + SYNTHETIC, + + /** + * The module was implicitly declared. + */ + MANDATED; + } + + /** *

A dependence upon a module

* * @see ModuleDescriptor#requires() * @since 9 + * @spec JPMS */ public final static class Requires @@ -88,7 +143,9 @@ public class ModuleDescriptor /** * A modifier on a module dependence. * + * @see Requires#modifiers() * @since 9 + * @spec JPMS */ public static enum Modifier { @@ -171,14 +228,18 @@ public class ModuleDescriptor * Compares this module dependence to another. * *

Two {@code Requires} objects are compared by comparing their - * module name lexicographically. Where the module names are equal then - * the sets of modifiers are compared based on a value computed from the - * ordinal of each modifier. Where the module names are equal and the - * set of modifiers are equal then the version of the modules recorded - * at compile-time are compared. When comparing the versions recorded - * at compile-time then a dependence that has a recorded version is - * considered to succeed a dependence that does not have a recorded - * version.

+ * module names lexicographically. Where the module names are equal + * then the sets of modifiers are compared in the same way that + * module modifiers are compared (see {@link ModuleDescriptor#compareTo + * ModuleDescriptor.compareTo}). Where the module names are equal and + * the set of modifiers are equal then the version of the modules + * recorded at compile-time are compared. When comparing the versions + * recorded at compile-time then a dependence that has a recorded + * version is considered to succeed a dependence that does not have a + * recorded version.

+ * + * @param that + * The module dependence to compare * * @return A negative integer, zero, or a positive integer if this module * dependence is less than, equal to, or greater than the given @@ -186,39 +247,22 @@ public class ModuleDescriptor */ @Override public int compareTo(Requires that) { + if (this == that) return 0; + int c = this.name().compareTo(that.name()); - if (c != 0) - return c; + if (c != 0) return c; // modifiers - c = Long.compare(this.modsValue(), that.modsValue()); - if (c != 0) - return c; + long v1 = modsValue(this.modifiers()); + long v2 = modsValue(that.modifiers()); + c = Long.compare(v1, v2); + if (c != 0) return c; // compiledVersion - if (this.compiledVersion != null) { - if (that.compiledVersion != null) - c = this.compiledVersion.compareTo(that.compiledVersion); - else - c = 1; - } else { - if (that.compiledVersion != null) - c = -1; - } + c = compare(this.compiledVersion, that.compiledVersion); + if (c != 0) return c; - return c; - } - - /** - * Return a value for the modifiers to allow sets of modifiers to be - * compared. - */ - private long modsValue() { - long value = 0; - for (Modifier m : mods) { - value += 1 << m.ordinal(); - } - return value; + return 0; } /** @@ -266,9 +310,9 @@ public class ModuleDescriptor } /** - * Returns a string describing module dependence. + * Returns a string describing this module dependence. * - * @return A string describing module dependence + * @return A string describing this module dependence */ @Override public String toString() { @@ -285,18 +329,23 @@ public class ModuleDescriptor /** - *

A module export, may be qualified or unqualified.

+ *

A package exported by a module, may be qualified or unqualified.

* * @see ModuleDescriptor#exports() * @since 9 + * @spec JPMS */ - public final static class Exports { + public final static class Exports + implements Comparable + { /** - * A modifier on a module export. + * A modifier on an exported package. * + * @see Exports#modifiers() * @since 9 + * @spec JPMS */ public static enum Modifier { @@ -380,6 +429,52 @@ public class ModuleDescriptor return targets; } + /** + * Compares this module export to another. + * + *

Two {@code Exports} objects are compared by comparing the package + * names lexicographically. Where the packages names are equal then the + * sets of modifiers are compared in the same way that module modifiers + * are compared (see {@link ModuleDescriptor#compareTo + * ModuleDescriptor.compareTo}). Where the package names are equal and + * the set of modifiers are equal then the set of target modules are + * compared. This is done by sorting the names of the target modules + * in ascending order, and according to their natural ordering, and then + * comparing the corresponding elements lexicographically. Where the + * sets differ in size, and the larger set contains all elements of the + * smaller set, then the larger set is considered to succeed the smaller + * set.

+ * + * @param that + * The module export to compare + * + * @return A negative integer, zero, or a positive integer if this module + * export is less than, equal to, or greater than the given + * export dependence + */ + @Override + public int compareTo(Exports that) { + if (this == that) return 0; + + int c = source.compareTo(that.source); + if (c != 0) + return c; + + // modifiers + long v1 = modsValue(this.modifiers()); + long v2 = modsValue(that.modifiers()); + c = Long.compare(v1, v2); + if (c != 0) + return c; + + // targets + c = compare(targets, that.targets); + if (c != 0) + return c; + + return 0; + } + /** * Computes a hash code for this module export. * @@ -425,9 +520,9 @@ public class ModuleDescriptor } /** - * Returns a string describing module export. + * Returns a string describing the exported package. * - * @return A string describing module export + * @return A string describing the exported package */ @Override public String toString() { @@ -441,8 +536,7 @@ public class ModuleDescriptor /** - *

Represents a module opens directive, may be qualified or - * unqualified.

+ *

A package opened by a module, may be qualified or unqualified.

* *

The opens directive in a module declaration declares a * package to be open to allow all types in the package, and all their @@ -452,26 +546,30 @@ public class ModuleDescriptor * * @see ModuleDescriptor#opens() * @since 9 + * @spec JPMS */ - public final static class Opens { - + public final static class Opens + implements Comparable + { /** - * A modifier on a module opens directive. + * A modifier on an open package. * + * @see Opens#modifiers() * @since 9 + * @spec JPMS */ public static enum Modifier { /** - * The opens was not explicitly or implicitly declared in the - * source of the module declaration. + * The open package was not explicitly or implicitly declared in + * the source of the module declaration. */ SYNTHETIC, /** - * The opens was implicitly declared in the source of the module - * declaration. + * The open package was implicitly declared in the source of the + * module declaration. */ MANDATED; @@ -543,6 +641,52 @@ public class ModuleDescriptor return targets; } + /** + * Compares this module opens to another. + * + *

Two {@code Opens} objects are compared by comparing the package + * names lexicographically. Where the packages names are equal then the + * sets of modifiers are compared in the same way that module modifiers + * are compared (see {@link ModuleDescriptor#compareTo + * ModuleDescriptor.compareTo}). Where the package names are equal and + * the set of modifiers are equal then the set of target modules are + * compared. This is done by sorting the names of the target modules + * in ascending order, and according to their natural ordering, and then + * comparing the corresponding elements lexicographically. Where the + * sets differ in size, and the larger set contains all elements of the + * smaller set, then the larger set is considered to succeed the smaller + * set.

+ * + * @param that + * The module opens to compare + * + * @return A negative integer, zero, or a positive integer if this module + * opens is less than, equal to, or greater than the given + * module opens + */ + @Override + public int compareTo(Opens that) { + if (this == that) return 0; + + int c = source.compareTo(that.source); + if (c != 0) + return c; + + // modifiers + long v1 = modsValue(this.modifiers()); + long v2 = modsValue(that.modifiers()); + c = Long.compare(v1, v2); + if (c != 0) + return c; + + // targets + c = compare(targets, that.targets); + if (c != 0) + return c; + + return 0; + } + /** * Computes a hash code for this module opens. * @@ -588,9 +732,9 @@ public class ModuleDescriptor } /** - * Returns a string describing module opens. + * Returns a string describing the open package. * - * @return A string describing module opens + * @return A string describing the open package */ @Override public String toString() { @@ -608,10 +752,12 @@ public class ModuleDescriptor * * @see ModuleDescriptor#provides() * @since 9 + * @spec JPMS */ - public final static class Provides { - + public final static class Provides + implements Comparable + { private final String service; private final List providers; @@ -641,6 +787,46 @@ public class ModuleDescriptor */ public List providers() { return providers; } + /** + * Compares this provides to another. + * + *

Two {@code Provides} objects are compared by comparing the fully + * qualified class name of the service type lexicographically. Where the + * class names are equal then the list of the provider class names are + * compared by comparing the corresponding elements of both lists + * lexicographically and in sequence. Where the lists differ in size, + * {@code N} is the size of the shorter list, and the first {@code N} + * corresponding elements are equal, then the longer list is considered + * to succeed the shorter list.

+ * + * @param that + * The {@code Provides} to compare + * + * @return A negative integer, zero, or a positive integer if this provides + * is less than, equal to, or greater than the given provides + */ + public int compareTo(Provides that) { + if (this == that) return 0; + + int c = service.compareTo(that.service); + if (c != 0) return c; + + // compare provider class names in sequence + int size1 = this.providers.size(); + int size2 = that.providers.size(); + for (int index=0; index size2) ? 1 : -1; + } + } + /** * Computes a hash code for this provides. * @@ -699,7 +885,7 @@ public class ModuleDescriptor * *

A version string has three components: The version number itself, an * optional pre-release version, and an optional build version. Each - * component is sequence of tokens; each token is either a non-negative + * component is a sequence of tokens; each token is either a non-negative * integer or a string. Tokens are separated by the punctuation characters * {@code '.'}, {@code '-'}, or {@code '+'}, or by transitions from a * sequence of digits to a sequence of characters that are neither digits @@ -740,6 +926,7 @@ public class ModuleDescriptor * * @see ModuleDescriptor#version() * @since 9 + * @spec JPMS */ public final static class Version @@ -1009,36 +1196,26 @@ public class ModuleDescriptor } - + private final String name; private final Version version; - private final boolean open; - - // Indicates if synthesised for a JAR file found on the module path - private final boolean automatic; - - // Not generated from a module-info.java - private final boolean synthetic; - + private final Set modifiers; + private final boolean open; // true if modifiers contains OPEN + private final boolean automatic; // true if modifiers contains AUTOMATIC private final Set requires; private final Set exports; private final Set opens; private final Set uses; private final Set provides; - - // Added post-compilation by tools private final Set packages; private final String mainClass; private final String osName; private final String osArch; private final String osVersion; - private ModuleDescriptor(String name, Version version, - boolean open, - boolean automatic, - boolean synthetic, + Set modifiers, Set requires, Set exports, Set opens, @@ -1052,10 +1229,9 @@ public class ModuleDescriptor { this.name = name; this.version = version; - this.open = open; - this.automatic = automatic; - this.synthetic = synthetic; - + this.modifiers = emptyOrUnmodifiableSet(modifiers); + this.open = modifiers.contains(Modifier.OPEN); + this.automatic = modifiers.contains(Modifier.AUTOMATIC); assert (requires.stream().map(Requires::name).distinct().count() == requires.size()); this.requires = emptyOrUnmodifiableSet(requires); @@ -1071,41 +1247,13 @@ public class ModuleDescriptor this.osVersion = osVersion; } - /** - * Clones the given module descriptor with an augmented set of packages - */ - ModuleDescriptor(ModuleDescriptor md, Set pkgs) { - this.name = md.name; - this.version = md.version; - this.open = md.open; - this.automatic = md.automatic; - this.synthetic = md.synthetic; - - this.requires = md.requires; - this.exports = md.exports; - this.opens = md.opens; - this.uses = md.uses; - this.provides = md.provides; - - Set packages = new HashSet<>(md.packages); - packages.addAll(pkgs); - this.packages = emptyOrUnmodifiableSet(packages); - - this.mainClass = md.mainClass; - this.osName = md.osName; - this.osArch = md.osArch; - this.osVersion = md.osVersion; - } - /** * Creates a module descriptor from its components. * The arguments are pre-validated and sets are unmodifiable sets. */ ModuleDescriptor(String name, Version version, - boolean open, - boolean automatic, - boolean synthetic, + Set modifiers, Set requires, Set exports, Set opens, @@ -1120,9 +1268,9 @@ public class ModuleDescriptor boolean unused) { this.name = name; this.version = version; - this.open = open; - this.automatic = automatic; - this.synthetic = synthetic; + this.modifiers = modifiers; + this.open = modifiers.contains(Modifier.OPEN); + this.automatic = modifiers.contains(Modifier.AUTOMATIC); this.requires = requires; this.exports = exports; this.opens = opens; @@ -1137,7 +1285,7 @@ public class ModuleDescriptor } /** - *

The module name.

+ *

Returns the module name.

* * @return The module name */ @@ -1145,12 +1293,20 @@ public class ModuleDescriptor return name; } + /** + *

Returns the set of module modifiers.

+ * + * @return A possibly-empty unmodifiable set of modifiers + */ + public Set modifiers() { + return modifiers; + } + /** *

Returns {@code true} if this is an open module.

* - *

An open module does not declare any open packages (the {@link #opens() - * opens} method returns an empty set) but the resulting module is treated - * as if all packages are open.

+ *

This method is equivalent to testing if the set of {@link #modifiers + * modifiers} contains the {@link Modifier#OPEN OPEN} modifier.

* * @return {@code true} if this is an open module */ @@ -1161,12 +1317,8 @@ public class ModuleDescriptor /** *

Returns {@code true} if this is an automatic module.

* - *

An automatic module is defined implicitly rather than explicitly - * and therefore does not have a module declaration. JAR files located on - * the application module path, or by the {@link ModuleFinder} returned by - * {@link ModuleFinder#of(java.nio.file.Path[]) ModuleFinder.of}, are - * treated as automatic modules if they do have not have a module - * declaration.

+ *

This method is equivalent to testing if the set of {@link #modifiers + * modifiers} contains the {@link Modifier#OPEN AUTOMATIC} modifier.

* * @return {@code true} if this is an automatic module */ @@ -1175,20 +1327,13 @@ public class ModuleDescriptor } /** - *

Returns {@code true} if this module descriptor was not generated - * from an explicit module declaration ({@code module-info.java}) - * or an implicit module declaration (an {@link #isAutomatic() automatic} - * module).

+ *

Returns the set of {@code Requires} objects representing the module + * dependences.

* - * @return {@code true} if this module descriptor was not generated by - * an explicit or implicit module declaration - */ - public boolean isSynthetic() { - return synthetic; - } - - /** - *

The dependences of this module.

+ *

The set includes a dependency on "{@code java.base}" when this + * module is not named "{@code java.base}". If this module is an automatic + * module then it does not have a dependency on any module other than + * "{@code java.base}".

* * @return A possibly-empty unmodifiable set of {@link Requires} objects */ @@ -1197,7 +1342,11 @@ public class ModuleDescriptor } /** - *

The module exports.

+ *

Returns the set of {@code Exports} objects representing the exported + * packages.

+ * + *

If this module is an automatic module then the set of exports + * is empty.

* * @return A possibly-empty unmodifiable set of exported packages */ @@ -1206,16 +1355,11 @@ public class ModuleDescriptor } /** - *

The module opens directives.

+ *

Returns the set of {@code Opens} objects representing the open + * packages.

* - *

Each {@code Opens} object in the set represents a package (and - * the set of target module names when qualified) where all types in the - * package, and all their members, not just public types and their public - * members, can be reflected on when using APIs that bypass or suppress - * default Java language access control checks.

- * - *

This method returns an empty set when invoked on {@link #isOpen() - * open} module.

+ *

If this module is an open module or an automatic module then the + * set of open packages is empty.

* * @return A possibly-empty unmodifiable set of open packages */ @@ -1224,7 +1368,10 @@ public class ModuleDescriptor } /** - *

The service dependences of this module.

+ *

Returns the set of service dependences.

+ * + *

If this module is an automatic module then the set of service + * dependences is empty.

* * @return A possibly-empty unmodifiable set of the fully qualified class * names of the service types used @@ -1234,7 +1381,8 @@ public class ModuleDescriptor } /** - *

The services that this module provides.

+ *

Returns the set of {@code Provides} objects representing the + * services that the module provides.

* * @return The possibly-empty unmodifiable set of the services that this * module provides @@ -1244,7 +1392,7 @@ public class ModuleDescriptor } /** - * Returns this module's version. + *

Returns the module version.

* * @return This module's version */ @@ -1253,10 +1401,10 @@ public class ModuleDescriptor } /** - * Returns a string containing this module's name and, if present, its - * version. + *

Returns a string containing the module name and, if present, its + * version.

* - * @return A string containing this module's name and, if present, its + * @return A string containing the module name and, if present, its * version. */ public String toNameAndVersion() { @@ -1268,51 +1416,51 @@ public class ModuleDescriptor } /** - * Returns the module's main class. + *

Returns the module main class.

* - * @return The fully qualified class name of this module's main class + * @return The fully qualified class name of the module's main class */ public Optional mainClass() { return Optional.ofNullable(mainClass); } /** - * Returns the operating system name if this module is operating system + * Returns the operating system name if the module is operating system * specific. * * @return The operating system name or an empty {@code Optional} - * if this module is not operating system specific + * if the module is not operating system specific */ public Optional osName() { return Optional.ofNullable(osName); } /** - * Returns the operating system architecture if this module is operating + * Returns the operating system architecture if the module is operating * system architecture specific. * * @return The operating system architecture or an empty {@code Optional} - * if this module is not operating system architecture specific + * if the module is not operating system architecture specific */ public Optional osArch() { return Optional.ofNullable(osArch); } /** - * Returns the operating system version if this module is operating + * Returns the operating system version if the module is operating * system version specific. * * @return The operating system version or an empty {@code Optional} - * if this module is not operating system version specific + * if the module is not operating system version specific */ public Optional osVersion() { return Optional.ofNullable(osVersion); } /** - * Returns the names of all packages in this module. + * Returns the set of packages in the module. * - * @return A possibly-empty unmodifiable set of all packages in the module + * @return A possibly-empty unmodifiable set of the packages in the module */ public Set packages() { return packages; @@ -1320,37 +1468,53 @@ public class ModuleDescriptor /** - * A builder used for building {@link ModuleDescriptor} objects. + * A builder for building {@link ModuleDescriptor} objects. * - *

{@code ModuleDescriptor} defines the {@link #module module}, {@link - * #openModule openModule}, and {@link #automaticModule automaticModule} - * methods to create builders for building different kinds of modules.

+ *

{@code ModuleDescriptor} defines the {@link #newModule newModule}, + * {@link #newOpenModule newOpenModule}, and {@link #newAutomaticModule + * newAutomaticModule} methods to create builders for building + * normal, open, and automatic modules.

+ * + *

The set of packages in the module are accumulated by the {@code + * Builder} as the {@link ModuleDescriptor.Builder#exports(String) exports}, + * {@link ModuleDescriptor.Builder#opens(String) opens}, + * {@link ModuleDescriptor.Builder#packages(Set) packages}, + * {@link ModuleDescriptor.Builder#provides(String,List) provides}, and + * {@link ModuleDescriptor.Builder#mainClass(String) mainClass} methods are + * invoked.

+ * + *

The module names, package names, and class names that are parameters + * specified to the builder methods are the module names, package names, + * and qualified names of classes (in named packages) as defined in the + * The Java™ Language Specification.

* *

Example usage:

- *
{@code    ModuleDescriptor descriptor = ModuleDescriptor.module("m1")
-     *         .exports("p")
-     *         .requires("m2")
+     * 
{@code    ModuleDescriptor descriptor = ModuleDescriptor.newModule("stats.core")
+     *         .requires("java.base")
+     *         .exports("org.acme.stats.core.clustering")
+     *         .exports("org.acme.stats.core.regression")
+     *         .packages(Set.of("org.acme.stats.core.internal"))
      *         .build();
      * }
* * @apiNote A {@code Builder} checks the components and invariants as - * components are added to the builder. The rational for this is to detect + * components are added to the builder. The rationale for this is to detect * errors as early as possible and not defer all validation to the - * {@link #build build} method. A {@code Builder} cannot be used to create - * a {@link ModuleDescriptor#isSynthetic() synthetic} module. + * {@link #build build} method. * * @since 9 + * @spec JPMS */ public static final class Builder { final String name; - final boolean strict; // true if module names are checked + final boolean strict; + final Set modifiers; final boolean open; - final boolean synthetic; - boolean automatic; + final boolean automatic; + final Set packages = new HashSet<>(); final Map requires = new HashMap<>(); final Map exports = new HashMap<>(); final Map opens = new HashMap<>(); - final Set concealedPackages = new HashSet<>(); final Set uses = new HashSet<>(); final Map provides = new HashMap<>(); Version version; @@ -1362,35 +1526,25 @@ public class ModuleDescriptor /** * Initializes a new builder with the given module name. * - * @param strict - * Indicates whether module names are checked or not + * If {@code strict} is {@code true} then module, package, and class + * names are checked to ensure they are legal names. In addition, the + * {@link #build buid} method will add "{@code requires java.base}" if + * the dependency is not declared. */ - Builder(String name, boolean strict, boolean open, boolean synthetic) { + Builder(String name, boolean strict, Set modifiers) { this.name = (strict) ? requireModuleName(name) : name; this.strict = strict; - this.open = open; - this.synthetic = synthetic; - } - - /* package */ Builder automatic(boolean automatic) { - this.automatic = automatic; - return this; + this.modifiers = modifiers; + this.open = modifiers.contains(Modifier.OPEN); + this.automatic = modifiers.contains(Modifier.AUTOMATIC); + assert !open || !automatic; } /** - * Returns the set of packages that are exported (unconditionally or - * unconditionally). + * Returns a snapshot of the packages in the module. */ - /* package */ Set exportedPackages() { - return exports.keySet(); - } - - /** - * Returns the set of packages that are opened (unconditionally or - * unconditionally). - */ - /* package */Set openPackages() { - return opens.keySet(); + /* package */ Set packages() { + return Collections.unmodifiableSet(packages); } /** @@ -1406,8 +1560,12 @@ public class ModuleDescriptor * initialized to build * @throws IllegalStateException * If the dependence on the module has already been declared + * or this builder is for an automatic module */ public Builder requires(Requires req) { + if (automatic) + throw new IllegalStateException("Automatic modules cannot declare" + + " dependences"); String mn = req.name(); if (name.equals(mn)) throw new IllegalArgumentException("Dependence on self"); @@ -1433,11 +1591,12 @@ public class ModuleDescriptor * @return This builder * * @throws IllegalArgumentException - * If the module name is {@code null}, is not a legal Java - * identifier, or is equal to the module name that this builder + * If the module name is {@code null}, is not a legal module + * name, or is equal to the module name that this builder * was initialized to build * @throws IllegalStateException * If the dependence on the module has already been declared + * or this builder is for an automatic module */ public Builder requires(Set ms, String mn, @@ -1448,6 +1607,23 @@ public class ModuleDescriptor return requires(new Requires(ms, mn, compiledVersion)); } + /* package */Builder requires(Set ms, + String mn, + String compiledVersion) { + Version v = null; + try { + v = Version.parse(compiledVersion); + } catch (IllegalArgumentException e) { + // for now, drop un-parsable version when non-strict + if (strict) throw e; + } + if (v == null) { + return requires(ms, mn); + } else { + return requires(ms, mn, v); + } + } + /** * Adds a dependence on a module with the given (and possibly empty) * set of modifiers. @@ -1460,11 +1636,12 @@ public class ModuleDescriptor * @return This builder * * @throws IllegalArgumentException - * If the module name is {@code null}, is not a legal Java - * identifier, or is equal to the module name that this builder + * If the module name is {@code null}, is not a legal module + * name, or is equal to the module name that this builder * was initialized to build * @throws IllegalStateException * If the dependence on the module has already been declared + * or this builder is for an automatic module */ public Builder requires(Set ms, String mn) { if (strict) @@ -1481,18 +1658,19 @@ public class ModuleDescriptor * @return This builder * * @throws IllegalArgumentException - * If the module name is {@code null}, is not a legal Java - * identifier, or is equal to the module name that this builder + * If the module name is {@code null}, is not a legal module + * name, or is equal to the module name that this builder * was initialized to build * @throws IllegalStateException * If the dependence on the module has already been declared + * or this builder is for an automatic module */ public Builder requires(String mn) { return requires(EnumSet.noneOf(Requires.Modifier.class), mn); } /** - * Adds an export. + * Adds an exported package. * * @param e * The export @@ -1500,29 +1678,27 @@ public class ModuleDescriptor * @return This builder * * @throws IllegalStateException - * If the package is already declared as a package with the - * {@link #contains contains} method or the package is already - * declared as exported + * If the {@link Exports#source package} is already declared as + * exported or this builder is for an automatic module */ public Builder exports(Exports e) { - // can't be exported and concealed - String source = e.source(); - if (concealedPackages.contains(source)) { - throw new IllegalStateException("Package " + source - + " already declared"); + if (automatic) { + throw new IllegalStateException("Automatic modules cannot declare" + + " exported packages"); } + String source = e.source(); if (exports.containsKey(source)) { throw new IllegalStateException("Exported package " + source + " already declared"); } - exports.put(source, e); + packages.add(source); return this; } /** - * Adds an export, with the given (and possibly empty) set of modifiers, - * to export a package to a set of target modules. + * Adds an exported package with the given (and possibly empty) set of + * modifiers. The package is exported to a set of target modules. * * @param ms * The set of modifiers @@ -1534,33 +1710,34 @@ public class ModuleDescriptor * @return This builder * * @throws IllegalArgumentException - * If the package name or any of the target modules is {@code - * null} or is not a legal Java identifier, or the set of - * targets is empty + * If the package name is {@code null} or is not a legal + * package name, the set of target modules is empty, or the set + * of target modules contains a name that is not a legal module + * name * @throws IllegalStateException - * If the package is already declared as a package with the - * {@link #contains contains} method or the package is already - * declared as exported + * If the package is already declared as exported + * or this builder is for an automatic module */ public Builder exports(Set ms, String pn, Set targets) { - Exports e = new Exports(ms, requirePackageName(pn), targets); + Exports e = new Exports(ms, pn, targets); // check targets targets = e.targets(); if (targets.isEmpty()) throw new IllegalArgumentException("Empty target set"); - if (strict) + if (strict) { + requirePackageName(e.source()); targets.stream().forEach(Checks::requireModuleName); - + } return exports(e); } /** - * Adds an unqualified export with the given (and possibly empty) set - * of modifiers. + * Adds an exported package with the given (and possibly empty) set of + * modifiers. The package is exported to all modules. * * @param ms * The set of modifiers @@ -1570,160 +1747,22 @@ public class ModuleDescriptor * @return This builder * * @throws IllegalArgumentException - * If the package name is {@code null} or is not a legal Java - * identifier + * If the package name is {@code null} or is not a legal + * package name * @throws IllegalStateException - * If the package is already declared as a package with the - * {@link #contains contains} method or the package is already - * declared as exported + * If the package is already declared as exported + * or this builder is for an automatic module */ public Builder exports(Set ms, String pn) { - Exports e = new Exports(ms, requirePackageName(pn), Collections.emptySet()); + if (strict) { + requirePackageName(pn); + } + Exports e = new Exports(ms, pn, Collections.emptySet()); return exports(e); } /** - * Adds an export to export a package to a set of target modules. - * - * @param pn - * The package name - * @param targets - * The set of target modules names - * - * @return This builder - * - * @throws IllegalArgumentException - * If the package name or any of the target modules is {@code - * null} or is not a legal Java identifier, or the set of - * targets is empty - * @throws IllegalStateException - * If the package is already declared as a package with the - * {@link #contains contains} method or the package is already - * declared as exported - */ - public Builder exports(String pn, Set targets) { - return exports(Collections.emptySet(), pn, targets); - } - - /** - * Adds an unqualified export. - * - * @param pn - * The package name - * - * @return This builder - * - * @throws IllegalArgumentException - * If the package name is {@code null} or is not a legal Java - * identifier - * @throws IllegalStateException - * If the package is already declared as a package with the - * {@link #contains contains} method or the package is already - * declared as exported - */ - public Builder exports(String pn) { - return exports(Collections.emptySet(), pn); - } - - /** - * Adds an opens directive. - * - * @param obj - * The {@code Opens} object - * - * @return This builder - * - * @throws IllegalStateException - * If the package is already declared as a package with the - * {@link #contains contains} method, the package is already - * declared as open, or this is a builder for an open module - */ - public Builder opens(Opens obj) { - if (open) { - throw new IllegalStateException("open modules cannot declare" - + " open packages"); - } - - // can't be open and concealed - String source = obj.source(); - if (concealedPackages.contains(source)) { - throw new IllegalStateException("Package " + source - + " already declared"); - } - if (opens.containsKey(source)) { - throw new IllegalStateException("Open package " + source - + " already declared"); - } - - opens.put(source, obj); - return this; - } - - - /** - * Adds an opens directive, with the given (and possibly empty) - * set of modifiers, to open a package to a set of target modules. - * - * @param ms - * The set of modifiers - * @param pn - * The package name - * @param targets - * The set of target modules names - * - * @return This builder - * - * @throws IllegalArgumentException - * If the package name or any of the target modules is {@code - * null} or is not a legal Java identifier, or the set of - * targets is empty - * @throws IllegalStateException - * If the package is already declared as a package with the - * {@link #contains contains} method, the package is already - * declared as open, or this is a builder for an open module - */ - public Builder opens(Set ms, - String pn, - Set targets) - { - Opens e = new Opens(ms, requirePackageName(pn), targets); - - // check targets - targets = e.targets(); - if (targets.isEmpty()) - throw new IllegalArgumentException("Empty target set"); - if (strict) - targets.stream().forEach(Checks::requireModuleName); - - return opens(e); - } - - /** - * Adds an opens directive to open a package with the given (and - * possibly empty) set of modifiers. - * - * @param ms - * The set of modifiers - * @param pn - * The package name - * - * @return This builder - * - * @throws IllegalArgumentException - * If the package name is {@code null} or is not a legal Java - * identifier - * @throws IllegalStateException - * If the package is already declared as a package with the - * {@link #contains contains} method, the package is already - * declared as open, or this is a builder for an open module - */ - public Builder opens(Set ms, String pn) { - Opens e = new Opens(ms, requirePackageName(pn), Collections.emptySet()); - return opens(e); - } - - /** - * Adds an opens directive to open a package to a set of target + * Adds an exported package. The package is exported to a set of target * modules. * * @param pn @@ -1734,20 +1773,20 @@ public class ModuleDescriptor * @return This builder * * @throws IllegalArgumentException - * If the package name or any of the target modules is {@code - * null} or is not a legal Java identifier, or the set of - * targets is empty + * If the package name is {@code null} or is not a legal + * package name, the set of target modules is empty, or the set + * of target modules contains a name that is not a legal module + * name * @throws IllegalStateException - * If the package is already declared as a package with the - * {@link #contains contains} method, the package is already - * declared as open, or this is a builder for an open module + * If the package is already declared as exported + * or this builder is for an automatic module */ - public Builder opens(String pn, Set targets) { - return opens(Collections.emptySet(), pn, targets); + public Builder exports(String pn, Set targets) { + return exports(Collections.emptySet(), pn, targets); } /** - * Adds an opens directive to open a package. + * Adds an exported package. The package is exported to all modules. * * @param pn * The package name @@ -1755,12 +1794,146 @@ public class ModuleDescriptor * @return This builder * * @throws IllegalArgumentException - * If the package name is {@code null} or is not a legal Java - * identifier + * If the package name is {@code null} or is not a legal + * package name * @throws IllegalStateException - * If the package is already declared as a package with the - * {@link #contains contains} method, the package is already - * declared as open, or this is a builder for an open module + * If the package is already declared as exported + * or this builder is for an automatic module + */ + public Builder exports(String pn) { + return exports(Collections.emptySet(), pn); + } + + /** + * Adds an open package. + * + * @param obj + * The {@code Opens} object + * + * @return This builder + * + * @throws IllegalStateException + * If the package is already declared as open, or this is a + * builder for an open module or automatic module + */ + public Builder opens(Opens obj) { + if (open || automatic) { + throw new IllegalStateException("Open or automatic modules cannot" + + " declare open packages"); + } + String source = obj.source(); + if (opens.containsKey(source)) { + throw new IllegalStateException("Open package " + source + + " already declared"); + } + opens.put(source, obj); + packages.add(source); + return this; + } + + + /** + * Adds an open package with the given (and possibly empty) set of + * modifiers. The package is open to a set of target modules. + * + * @param ms + * The set of modifiers + * @param pn + * The package name + * @param targets + * The set of target modules names + * + * @return This builder + * + * @throws IllegalArgumentException + * If the package name is {@code null} or is not a legal + * package name, the set of target modules is empty, or the set + * of target modules contains a name that is not a legal module + * name + * @throws IllegalStateException + * If the package is already declared as open, or this is a + * builder for an open module or automatic module + */ + public Builder opens(Set ms, + String pn, + Set targets) + { + Opens opens = new Opens(ms, pn, targets); + + // check targets + targets = opens.targets(); + if (targets.isEmpty()) + throw new IllegalArgumentException("Empty target set"); + if (strict) { + requirePackageName(opens.source()); + targets.stream().forEach(Checks::requireModuleName); + } + return opens(opens); + } + + /** + * Adds an open package with the given (and possibly empty) set of + * modifiers. The package is open to all modules. + * + * @param ms + * The set of modifiers + * @param pn + * The package name + * + * @return This builder + * + * @throws IllegalArgumentException + * If the package name is {@code null} or is not a legal + * package name + * @throws IllegalStateException + * If the package is already declared as open, or this is a + * builder for an open module or automatic module + */ + public Builder opens(Set ms, String pn) { + if (strict) { + requirePackageName(pn); + } + Opens e = new Opens(ms, pn, Collections.emptySet()); + return opens(e); + } + + /** + * Adds an open package. The package is open to a set of target modules. + * + * @param pn + * The package name + * @param targets + * The set of target modules names + * + * @return This builder + * + * @throws IllegalArgumentException + * If the package name is {@code null} or is not a legal + * package name, the set of target modules is empty, or the set + * of target modules contains a name that is not a legal module + * name + * @throws IllegalStateException + * If the package is already declared as open, or this is a + * builder for an open module or automatic module + */ + public Builder opens(String pn, Set targets) { + return opens(Collections.emptySet(), pn, targets); + } + + /** + * Adds an open package. The package is open to all modules. + * + * @param pn + * The package name + * + * @return This builder + * + * @throws IllegalArgumentException + * If the package name is {@code null} or is not a legal + * package name + * @throws IllegalStateException + * If the package is already declared as open, or this is a + * builder for an open module or automatic module */ public Builder opens(String pn) { return opens(Collections.emptySet(), pn); @@ -1775,12 +1948,16 @@ public class ModuleDescriptor * @return This builder * * @throws IllegalArgumentException - * If the service type is {@code null} or is not a legal Java - * identifier + * If the service type is {@code null} or not a qualified name of + * a class in a named package * @throws IllegalStateException * If a dependency on the service type has already been declared + * or this is a builder for an an automatic module */ public Builder uses(String service) { + if (automatic) + throw new IllegalStateException("Automatic modules can not declare" + + " service dependences"); if (uses.contains(requireServiceTypeName(service))) throw new IllegalStateException("Dependence upon service " + service + " already declared"); @@ -1789,7 +1966,9 @@ public class ModuleDescriptor } /** - * Provides a service with one or more implementations. + * Provides a service with one or more implementations. The package for + * each {@link Provides#providers provider} (or provider factory) is + * added to the module if not already added. * * @param p * The provides @@ -1801,16 +1980,18 @@ public class ModuleDescriptor * declared */ public Builder provides(Provides p) { - String st = p.service(); - if (provides.containsKey(st)) + String service = p.service(); + if (provides.containsKey(service)) throw new IllegalStateException("Providers of service " - + st + " already declared"); - provides.put(st, p); + + service + " already declared"); + provides.put(service, p); + p.providers().forEach(name -> packages.add(packageName(name))); return this; } /** - * Provides implementations of a service. + * Provides implementations of a service. The package for each provider + * (or provider factory) is added to the module if not already added. * * @param service * The service type @@ -1821,103 +2002,59 @@ public class ModuleDescriptor * * @throws IllegalArgumentException * If the service type or any of the provider class names is - * {@code null} or is not a legal Java identifier, or the list - * of provider class names is empty + * {@code null} or not a qualified name of a class in a named + * package, or the list of provider class names is empty * @throws IllegalStateException * If the providers for the service type have already been * declared */ public Builder provides(String service, List providers) { - if (provides.containsKey(service)) - throw new IllegalStateException("Providers of service " - + service + " already declared by " + name); - - Provides p = new Provides(requireServiceTypeName(service), providers); + Provides p = new Provides(service, providers); // check providers after the set has been copied. List providerNames = p.providers(); if (providerNames.isEmpty()) throw new IllegalArgumentException("Empty providers set"); - providerNames.forEach(Checks::requireServiceProviderName); - provides.put(service, p); - return this; + if (strict) { + requireServiceTypeName(p.service()); + providerNames.forEach(Checks::requireServiceProviderName); + } else { + // Disallow service/providers in unnamed package + String pn = packageName(service); + if (pn.isEmpty()) { + throw new IllegalArgumentException(service + + ": unnamed package"); + } + for (String name : providerNames) { + pn = packageName(name); + if (pn.isEmpty()) { + throw new IllegalArgumentException(name + + ": unnamed package"); + } + } + } + return provides(p); } /** - * Provides an implementation of a service. - * - * @param service - * The service type - * @param provider - * The provider or provider factory class name - * - * @return This builder - * - * @throws IllegalArgumentException - * If the service type or the provider class name is {@code - * null} or is not a legal Java identifier - * @throws IllegalStateException - * If the providers for the service type have already been - * declared - */ - public Builder provides(String service, String provider) { - if (provider == null) - throw new IllegalArgumentException("'provider' is null"); - return provides(service, List.of(provider)); - } - - /** - * Adds a (possible empty) set of packages to the module + * Adds packages to the module. All packages in the set of package names + * that are not in the module are added to module. * * @param pns - * The set of package names + * The (possibly empty) set of package names * * @return This builder * * @throws IllegalArgumentException * If any of the package names is {@code null} or is not a - * legal Java identifier - * @throws IllegalStateException - * If any of packages are already declared as packages in - * the module. This includes packages that are already - * declared as exported or open packages. + * legal package name */ - public Builder contains(Set pns) { - pns.forEach(this::contains); - return this; - } - - /** - * Adds a package to the module. - * - * @param pn - * The package name - * - * @return This builder - * - * @throws IllegalArgumentException - * If the package name is {@code null}, or is not a legal Java - * identifier - * @throws IllegalStateException - * If the package is already declared as a package in the - * module. This includes the package already declared as an - * exported or open package. - */ - public Builder contains(String pn) { - Checks.requirePackageName(pn); - if (concealedPackages.contains(pn)) { - throw new IllegalStateException("Package " + pn - + " already declared"); + public Builder packages(Set pns) { + if (strict) { + pns = new HashSet<>(pns); + pns.forEach(Checks::requirePackageName); } - if (exports.containsKey(pn)) { - throw new IllegalStateException("Exported package " - + pn + " already declared"); - } - if (opens.containsKey(pn)) { - throw new IllegalStateException("Open package " - + pn + " already declared"); - } - concealedPackages.add(pn); + this.packages.addAll(pns); return this; } @@ -1937,22 +2074,35 @@ public class ModuleDescriptor /** * Sets the module version. * - * @param v + * @param vs * The version string to parse * * @return This builder * * @throws IllegalArgumentException - * If {@code v} is null or cannot be parsed as a version string + * If {@code vs} is {@code null} or cannot be parsed as a + * version string * * @see Version#parse(String) */ - public Builder version(String v) { - return version(Version.parse(v)); + public Builder version(String vs) { + Version v; + if (strict) { + v = Version.parse(vs); + } else { + try { + v = Version.parse(vs); + } catch (IllegalArgumentException ignore) { + // for now, ignore when non-strict + return this; + } + } + return version(v); } /** - * Sets the module main class. + * Sets the module main class. The package for the main class is added + * to the module if not already added. * * @param mc * The module main class @@ -1960,10 +2110,24 @@ public class ModuleDescriptor * @return This builder * * @throws IllegalArgumentException - * If {@code mainClass} is null or is not a legal Java identifier + * If {@code mainClass} is {@code null} or not a qualified + * name of a class in a named package */ public Builder mainClass(String mc) { - mainClass = requireBinaryName("main class name", mc); + String pn; + if (strict) { + mc = requireQualifiedClassName("main class name", mc); + pn = packageName(mc); + assert !pn.isEmpty(); + } else { + // Disallow main class in unnamed package + pn = packageName(mc); + if (pn.isEmpty()) { + throw new IllegalArgumentException(mc + ": unnamed package"); + } + } + mainClass = mc; + packages.add(pn); return this; } @@ -1976,7 +2140,7 @@ public class ModuleDescriptor * @return This builder * * @throws IllegalArgumentException - * If {@code name} is null or the empty String + * If {@code name} is {@code null} or the empty String */ public Builder osName(String name) { if (name == null || name.isEmpty()) @@ -1994,7 +2158,7 @@ public class ModuleDescriptor * @return This builder * * @throws IllegalArgumentException - * If {@code name} is null or the empty String + * If {@code name} is {@code null} or the empty String */ public Builder osArch(String arch) { if (arch == null || arch.isEmpty()) @@ -2012,7 +2176,7 @@ public class ModuleDescriptor * @return This builder * * @throws IllegalArgumentException - * If {@code name} is null or the empty String + * If {@code name} is {@code null} or the empty String */ public Builder osVersion(String version) { if (version == null || version.isEmpty()) @@ -2024,26 +2188,34 @@ public class ModuleDescriptor /** * Builds and returns a {@code ModuleDescriptor} from its components. * + *

The module will require "{@code java.base}" even if the dependence + * has not been declared (the exception is when building a module named + * "{@code java.base}" as it cannot require itself). The dependence on + * "{@code java.base}" will have the {@link + * java.lang.module.ModuleDescriptor.Requires.Modifier#MANDATED MANDATED} + * modifier if the dependence was not declared.

+ * * @return The module descriptor */ public ModuleDescriptor build() { Set requires = new HashSet<>(this.requires.values()); - - Set packages = new HashSet<>(); - packages.addAll(exports.keySet()); - packages.addAll(opens.keySet()); - packages.addAll(concealedPackages); - Set exports = new HashSet<>(this.exports.values()); Set opens = new HashSet<>(this.opens.values()); + // add dependency on java.base + if (strict + && !name.equals("java.base") + && !this.requires.containsKey("java.base")) { + requires.add(new Requires(Set.of(Requires.Modifier.MANDATED), + "java.base", + null)); + } + Set provides = new HashSet<>(this.provides.values()); return new ModuleDescriptor(name, version, - open, - automatic, - synthetic, + modifiers, requires, exports, opens, @@ -2062,16 +2234,20 @@ public class ModuleDescriptor * Compares this module descriptor to another. * *

Two {@code ModuleDescriptor} objects are compared by comparing their - * module name lexicographically. Where the module names are equal then - * the versions, if present, are compared.

- * - * @apiNote For now, the natural ordering is not consistent with equals. - * If two module descriptors have equal module names, equal versions if - * present, but their corresponding components are not equal, then they - * will be considered equal by this method. + * module names lexicographically. Where the module names are equal then the + * module versions are compared. When comparing the module versions then a + * module descriptor with a version is considered to succeed a module + * descriptor that does not have a version. Where the module names are equal + * and the versions are equal (or not present in both), then the set of + * modifiers are compared. Sets of modifiers are compared by comparing + * a binary value computed for each set. If a modifier is present + * in the set then the bit at the position of its ordinal is {@code 1} + * in the binary value, otherwise {@code 0}. If the two set of modifiers + * are also equal then the other components of the module descriptors are + * compared in a manner that is consistent with {@code equals}.

* * @param that - * The object to which this module descriptor is to be compared + * The module descriptor to compare * * @return A negative integer, zero, or a positive integer if this module * descriptor is less than, equal to, or greater than the given @@ -2079,16 +2255,50 @@ public class ModuleDescriptor */ @Override public int compareTo(ModuleDescriptor that) { + if (this == that) return 0; + int c = this.name().compareTo(that.name()); if (c != 0) return c; - if (version == null) { - if (that.version == null) - return 0; - return -1; - } - if (that.version == null) - return +1; - return version.compareTo(that.version); + + c = compare(this.version, that.version); + if (c != 0) return c; + + long v1 = modsValue(this.modifiers()); + long v2 = modsValue(that.modifiers()); + c = Long.compare(v1, v2); + if (c != 0) return c; + + c = compare(this.requires, that.requires); + if (c != 0) return c; + + c = compare(this.packages, that.packages); + if (c != 0) return c; + + c = compare(this.exports, that.exports); + if (c != 0) return c; + + c = compare(this.opens, that.opens); + if (c != 0) return c; + + c = compare(this.uses, that.uses); + if (c != 0) return c; + + c = compare(this.provides, that.provides); + if (c != 0) return c; + + c = compare(this.mainClass, that.mainClass); + if (c != 0) return c; + + c = compare(this.osName, that.osName); + if (c != 0) return c; + + c = compare(this.osArch, that.osArch); + if (c != 0) return c; + + c = compare(this.osVersion, that.osVersion); + if (c != 0) return c; + + return 0; } /** @@ -2115,10 +2325,9 @@ public class ModuleDescriptor return false; ModuleDescriptor that = (ModuleDescriptor)ob; return (name.equals(that.name) - && open == that.open - && automatic == that.automatic - && synthetic == that.synthetic + && modifiers.equals(that.modifiers) && requires.equals(that.requires) + && Objects.equals(packages, that.packages) && exports.equals(that.exports) && opens.equals(that.opens) && uses.equals(that.uses) @@ -2127,12 +2336,9 @@ public class ModuleDescriptor && Objects.equals(mainClass, that.mainClass) && Objects.equals(osName, that.osName) && Objects.equals(osArch, that.osArch) - && Objects.equals(osVersion, that.osVersion) - && Objects.equals(packages, that.packages)); + && Objects.equals(osVersion, that.osVersion)); } - private transient int hash; // cached hash code - /** * Computes a hash code for this module descriptor. * @@ -2147,10 +2353,9 @@ public class ModuleDescriptor int hc = hash; if (hc == 0) { hc = name.hashCode(); - hc = hc * 43 + Boolean.hashCode(open); - hc = hc * 43 + Boolean.hashCode(automatic); - hc = hc * 43 + Boolean.hashCode(synthetic); + hc = hc * 43 + Objects.hashCode(modifiers); hc = hc * 43 + requires.hashCode(); + hc = hc * 43 + Objects.hashCode(packages); hc = hc * 43 + exports.hashCode(); hc = hc * 43 + opens.hashCode(); hc = hc * 43 + uses.hashCode(); @@ -2160,18 +2365,18 @@ public class ModuleDescriptor hc = hc * 43 + Objects.hashCode(osName); hc = hc * 43 + Objects.hashCode(osArch); hc = hc * 43 + Objects.hashCode(osVersion); - hc = hc * 43 + Objects.hashCode(packages); if (hc == 0) hc = -1; hash = hc; } return hc; } + private transient int hash; // cached hash code /** - * Returns a string describing this descriptor. + *

Returns a string describing the module.

* - * @return A string describing this descriptor + * @return A string describing the module */ @Override public String toString() { @@ -2201,31 +2406,50 @@ public class ModuleDescriptor * * @param name * The module name + * @param ms + * The set of module modifiers * * @return A new builder * * @throws IllegalArgumentException - * If the module name is {@code null} or is not a legal Java - * identifier + * If the module name is {@code null} or is not a legal module + * name, or the set of modifiers contains {@link + * Modifier#AUTOMATIC AUTOMATIC} with other modifiers */ - public static Builder module(String name) { - return new Builder(name, true, false, false); + public static Builder newModule(String name, Set ms) { + Set mods = new HashSet<>(ms); + if (mods.contains(Modifier.AUTOMATIC) && mods.size() > 1) + throw new IllegalArgumentException("AUTOMATIC cannot be used with" + + " other modifiers"); + + return new Builder(name, true, mods); + } + + /** + * Instantiates a builder to build a module descriptor for a normal + * module. This method is equivalent to invoking {@link #newModule(String,Set) + * newModule} with an empty set of {@link ModuleDescriptor.Modifier modifiers}. + * + * @param name + * The module name + * + * @return A new builder + * + * @throws IllegalArgumentException + * If the module name is {@code null} or is not a legal module + * name + */ + public static Builder newModule(String name) { + return new Builder(name, true, Set.of()); } /** * Instantiates a builder to build a module descriptor for an open module. - * An open module does not declare any open packages but the resulting - * module is treated as if all packages are open. + * This method is equivalent to invoking {@link #newModule(String,Set) + * newModule} with the {@link ModuleDescriptor.Modifier#OPEN OPEN} modifier. * - *

As an example, the following creates a module descriptor for an open - * name "{@code m}" containing two packages, one of which is exported.

- *
{@code
-     *     ModuleDescriptor descriptor = ModuleDescriptor.openModule("m")
-     *         .requires("java.base")
-     *         .exports("p")
-     *         .contains("q")
-     *         .build();
-     * }
+ *

The builder for an open module cannot be used to declare any open + * packages.

* * @param name * The module name @@ -2233,19 +2457,22 @@ public class ModuleDescriptor * @return A new builder that builds an open module * * @throws IllegalArgumentException - * If the module name is {@code null} or is not a legal Java - * identifier + * If the module name is {@code null} or is not a legal module + * name */ - public static Builder openModule(String name) { - return new Builder(name, true, true, false); + public static Builder newOpenModule(String name) { + return new Builder(name, true, Set.of(Modifier.OPEN)); } /** * Instantiates a builder to build a module descriptor for an automatic - * module. Automatic modules receive special treatment during resolution - * (see {@link Configuration}) so that they read all other modules. When - * Instantiated in the Java virtual machine as a {@link java.lang.reflect.Module} - * then the Module reads every unnamed module in the Java virtual machine. + * module. This method is equivalent to invoking {@link #newModule(String,Set) + * newModule} with the {@link ModuleDescriptor.Modifier#AUTOMATIC AUTOMATIC} + * modifier. + * + *

The builder for an automatic module cannot be used to declare module + * or service dependences. It also cannot be used to declare any exported + * or open packages.

* * @param name * The module name @@ -2253,13 +2480,13 @@ public class ModuleDescriptor * @return A new builder that builds an automatic module * * @throws IllegalArgumentException - * If the module name is {@code null} or is not a legal Java - * identifier + * If the module name is {@code null} or is not a legal module + * name * * @see ModuleFinder#of(Path[]) */ - public static Builder automaticModule(String name) { - return new Builder(name, true, false, false).automatic(true); + public static Builder newAutomaticModule(String name) { + return new Builder(name, true, Set.of(Modifier.AUTOMATIC)); } @@ -2269,8 +2496,12 @@ public class ModuleDescriptor * *

If the descriptor encoded in the input stream does not indicate a * set of packages in the module then the {@code packageFinder} will be - * invoked. If the {@code packageFinder} throws an {@link UncheckedIOException} - * then {@link IOException} cause will be re-thrown.

+ * invoked. The set of packages that the {@code packageFinder} returns + * must include all the packages that the module exports, opens, as well + * as the packages of the service implementations that the module provides, + * and the package of the main class (if the module has a main class). If + * the {@code packageFinder} throws an {@link UncheckedIOException} then + * {@link IOException} cause will be re-thrown.

* *

If there are bytes following the module descriptor then it is * implementation specific as to whether those bytes are read, ignored, @@ -2292,7 +2523,9 @@ public class ModuleDescriptor * @return The module descriptor * * @throws InvalidModuleDescriptorException - * If an invalid module descriptor is detected + * If an invalid module descriptor is detected or the set of + * packages returned by the {@code packageFinder} does not include + * all of the packages obtained from the module descriptor * @throws IOException * If an I/O error occurs reading from the input stream or {@code * UncheckedIOException} is thrown by the package finder @@ -2305,8 +2538,12 @@ public class ModuleDescriptor } /** - * Reads the binary form of a module declaration from an input stream - * as a module descriptor. + * Reads the binary form of a module declaration from an input stream as a + * module descriptor. This method works exactly as specified by the 2-arg + * {@link #read(InputStream,Supplier) read} method with the exception that + * a packager finder is not used to find additional packages when the + * module descriptor read from the stream does not indicate the set of + * packages. * * @param in * The input stream @@ -2327,7 +2564,13 @@ public class ModuleDescriptor * as a module descriptor. * *

If the descriptor encoded in the byte buffer does not indicate a - * set of packages then the {@code packageFinder} will be invoked.

+ * set of packages in the module then the {@code packageFinder} will be + * invoked. The set of packages that the {@code packageFinder} returns + * must include all the packages that the module exports, opens, as well + * as the packages of the service implementations that the module provides, + * and the package of the main class (if the module has a main class). If + * the {@code packageFinder} throws an {@link UncheckedIOException} then + * {@link IOException} cause will be re-thrown.

* *

The module descriptor is read from the buffer stating at index * {@code p}, where {@code p} is the buffer's {@link ByteBuffer#position() @@ -2353,7 +2596,9 @@ public class ModuleDescriptor * @return The module descriptor * * @throws InvalidModuleDescriptorException - * If an invalid module descriptor is detected + * If an invalid module descriptor is detected or the set of + * packages returned by the {@code packageFinder} does not include + * all of the packages obtained from the module descriptor */ public static ModuleDescriptor read(ByteBuffer bb, Supplier> packageFinder) @@ -2362,8 +2607,11 @@ public class ModuleDescriptor } /** - * Reads the binary form of a module declaration from a byte buffer - * as a module descriptor. + * Reads the binary form of a module declaration from a byte buffer as a + * module descriptor. This method works exactly as specified by the 2-arg + * {@link #read(ByteBuffer,Supplier) read} method with the exception that a + * packager finder is not used to find additional packages when the module + * descriptor encoded in the buffer does not indicate the set of packages. * * @param bb * The byte buffer @@ -2398,6 +2646,11 @@ public class ModuleDescriptor } } + private static String packageName(String cn) { + int index = cn.lastIndexOf('.'); + return (index == -1) ? "" : cn.substring(0, index); + } + /** * Returns a string containing the given set of modifiers and label. */ @@ -2407,6 +2660,36 @@ public class ModuleDescriptor .collect(Collectors.joining(" ")); } + private static > + int compare(T obj1, T obj2) { + if (obj1 != null) { + return (obj2 != null) ? obj1.compareTo(obj2) : 1; + } else { + return (obj2 == null) ? 0 : -1; + } + } + + /** + * Compares two sets of {@code Comparable} objects. + */ + @SuppressWarnings("unchecked") + private static > + int compare(Set s1, Set s2) { + T[] a1 = (T[]) s1.toArray(); + T[] a2 = (T[]) s2.toArray(); + Arrays.sort(a1); + Arrays.sort(a2); + return Arrays.compare(a1, a2); + } + + private static > long modsValue(Set set) { + long value = 0; + for (Enum e : set) { + value += 1 << e.ordinal(); + } + return value; + } + static { /** * Setup the shared secret to allow code in other packages access @@ -2417,19 +2700,21 @@ public class ModuleDescriptor @Override public Builder newModuleBuilder(String mn, boolean strict, - boolean open, - boolean synthetic) { - return new Builder(mn, strict, open, synthetic); + Set modifiers) { + return new Builder(mn, strict, modifiers); } @Override - public Set exportedPackages(ModuleDescriptor.Builder builder) { - return builder.exportedPackages(); + public Set packages(ModuleDescriptor.Builder builder) { + return builder.packages(); } @Override - public Set openPackages(ModuleDescriptor.Builder builder) { - return builder.openPackages(); + public void requires(ModuleDescriptor.Builder builder, + Set ms, + String mn, + String compiledVersion) { + builder.requires(ms, mn, compiledVersion); } @Override @@ -2466,23 +2751,10 @@ public class ModuleDescriptor return new Provides(service, providers, true); } - @Override - public Version newVersion(String v) { - return new Version(v); - } - - @Override - public ModuleDescriptor newModuleDescriptor(ModuleDescriptor md, - Set pkgs) { - return new ModuleDescriptor(md, pkgs); - } - @Override public ModuleDescriptor newModuleDescriptor(String name, Version version, - boolean open, - boolean automatic, - boolean synthetic, + Set modifiers, Set requires, Set exports, Set opens, @@ -2496,9 +2768,7 @@ public class ModuleDescriptor int hashCode) { return new ModuleDescriptor(name, version, - open, - automatic, - synthetic, + modifiers, requires, exports, opens, @@ -2514,12 +2784,12 @@ public class ModuleDescriptor } @Override - public Configuration resolveRequiresAndUses(ModuleFinder finder, - Collection roots, - boolean check, - PrintStream traceOutput) + public Configuration resolveAndBind(ModuleFinder finder, + Collection roots, + boolean check, + PrintStream traceOutput) { - return Configuration.resolveRequiresAndUses(finder, roots, check, traceOutput); + return Configuration.resolveAndBind(finder, roots, check, traceOutput); } }); } diff --git a/jdk/src/java.base/share/classes/java/lang/module/ModuleFinder.java b/jdk/src/java.base/share/classes/java/lang/module/ModuleFinder.java index 5d01f698806..9fc03dc87b5 100644 --- a/jdk/src/java.base/share/classes/java/lang/module/ModuleFinder.java +++ b/jdk/src/java.base/share/classes/java/lang/module/ModuleFinder.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2017, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -42,14 +42,15 @@ import java.util.Objects; import java.util.Optional; import java.util.Set; +import jdk.internal.module.ModuleBootstrap; import jdk.internal.module.ModulePath; import jdk.internal.module.SystemModuleFinder; import sun.security.action.GetPropertyAction; /** * A finder of modules. A {@code ModuleFinder} is used to find modules during - * resolution or - * service binding. + * resolution or + * service binding. * *

A {@code ModuleFinder} can only find one module with a given name. A * {@code ModuleFinder} that finds modules in a sequence of directories, for @@ -85,6 +86,7 @@ import sun.security.action.GetPropertyAction; *

A {@code ModuleFinder} is not required to be thread safe.

* * @since 9 + * @spec JPMS */ public interface ModuleFinder { @@ -124,8 +126,8 @@ public interface ModuleFinder { * to find that module.

* * @apiNote This is important to have for methods such as {@link - * Configuration#resolveRequiresAndUses resolveRequiresAndUses} that need - * to scan the module path to find modules that provide a specific service. + * Configuration#resolveAndBind resolveAndBind} that need to scan the + * module path to find modules that provide a specific service. * * @return The set of all module references that this finder locates * @@ -172,7 +174,8 @@ public interface ModuleFinder { } else { Path mlib = Paths.get(home, "modules"); if (Files.isDirectory(mlib)) { - return of(mlib); + // exploded build may be patched + return ModulePath.of(ModuleBootstrap.patcher(), mlib); } else { throw new InternalError("Unable to detect the run-time image"); } @@ -198,13 +201,9 @@ public interface ModuleFinder { * *

If an element is a path to a directory of modules then each entry in * the directory is a packaged module or the top-level directory of an - * exploded module. The module finder's {@link #find(String) find} or - * {@link #findAll() findAll} methods throw {@link FindException} if a - * directory containing more than one module with the same name is - * encountered.

- * - *

If an element in the array is a path to a directory, and that - * directory contains a file named {@code module-info.class}, then the + * exploded module. It it an error if a directory contains more than one + * module with the same name. If an element is a path to a directory, and + * that directory contains a file named {@code module-info.class}, then the * directory is treated as an exploded module rather than a directory of * modules.

* @@ -214,9 +213,8 @@ public interface ModuleFinder { * entry in a {@link java.util.jar.JarFile#isMultiRelease() multi-release} * JAR file) is a modular JAR and is an explicit module. * A JAR file that does not have a {@code module-info.class} in the - * top-level directory is an {@link ModuleDescriptor#isAutomatic automatic} - * module. The {@link ModuleDescriptor} for an automatic module is created as - * follows: + * top-level directory is created as an automatic module. The components + * for the automatic module are derived as follows: * *
    * @@ -248,46 +246,48 @@ public interface ModuleFinder { * *
* - *
  • It {@link ModuleDescriptor#requires() requires} {@code - * java.base}.

  • - * - *
  • The set of packages in the module is derived from the names - * of non-directory entries in the JAR file. A candidate package name - * is derived from an entry using the characters up to, but not - * including, the last forward slash. All remaining forward slashes are - * replaced with dot ({@code "."}). If the resulting string is a valid - * Java identifier then it is assumed to be a package name. For example, - * if the JAR file contains an entry "{@code p/q/Foo.class}" then the - * package name derived is "{@code p.q}". All packages are {@link - * ModuleDescriptor#exports() exported}.

  • + *
  • The set of packages in the module is derived from the + * non-directory entries in the JAR file that have names ending in + * "{@code .class}". A candidate package name is derived from the name + * using the characters up to, but not including, the last forward slash. + * All remaining forward slashes are replaced with dot ({@code "."}). If + * the resulting string is a legal package name then it is assumed to be + * a package name. For example, if the JAR file contains the entry + * "{@code p/q/Foo.class}" then the package name derived is + * "{@code p.q}".

  • * *
  • The contents of entries starting with {@code * META-INF/services/} are assumed to be service configuration files * (see {@link java.util.ServiceLoader}). If the name of a file - * (that follows {@code META-INF/services/}) is a legal Java identifier - * then it is assumed to be the fully-qualified binary name of a - * service type. The entries in the file are assumed to be the - * fully-qualified binary names of provider classes.

  • + * (that follows {@code META-INF/services/}) is a legal class name + * then it is assumed to be the fully-qualified class name of a service + * type. The entries in the file are assumed to be the fully-qualified + * class names of provider classes.

    * *
  • If the JAR file has a {@code Main-Class} attribute in its - * main manifest then its value is the {@link + * main manifest then its value is the module {@link * ModuleDescriptor#mainClass() main class}.

  • * * * *

    If a {@code ModuleDescriptor} cannot be created (by means of the * {@link ModuleDescriptor.Builder ModuleDescriptor.Builder} API) for an - * automatic module then {@code FindException} is thrown. This can arise, - * for example, when a legal Java identifier name cannot be derived from - * the file name of the JAR file or where the JAR file contains a {@code - * .class} in the top-level directory of the JAR file.

    + * automatic module then {@code FindException} is thrown. This can arise + * when a legal module name cannot be derived from the file name of the JAR + * file, where the JAR file contains a {@code .class} in the top-level + * directory of the JAR file, where an entry in a service configuration + * file is not a legal class name or its package name is not in the set of + * packages derived for the module, or where the module main class is not + * a legal class name or its package is not in the module.

    * *

    In addition to JAR files, an implementation may also support modules - * that are packaged in other implementation specific module formats. When - * a file is encountered that is not recognized as a packaged module then - * {@code FindException} is thrown. An implementation may choose to ignore - * some files, {@link java.nio.file.Files#isHidden hidden} files for - * example. Paths to files that do not exist are always ignored.

    + * that are packaged in other implementation specific module formats. If + * an element in the array specified to this method is a path to a directory + * of modules then entries in the directory that not recognized as modules + * are ignored. If an element in the array is a path to a packaged module + * that is not recognized then a {@code FindException} is thrown when the + * file is encountered. Paths to files that do not exist are always ignored. + *

    * *

    As with automatic modules, the contents of a packaged or exploded * module may need to be scanned in order to determine the packages @@ -325,7 +325,7 @@ public interface ModuleFinder { }; } - return new ModulePath(entries); + return ModulePath.of(entries); } /** diff --git a/jdk/src/java.base/share/classes/java/lang/module/ModuleReader.java b/jdk/src/java.base/share/classes/java/lang/module/ModuleReader.java index d79d210edd0..c5a7b61c695 100644 --- a/jdk/src/java.base/share/classes/java/lang/module/ModuleReader.java +++ b/jdk/src/java.base/share/classes/java/lang/module/ModuleReader.java @@ -45,7 +45,7 @@ import java.util.stream.Stream; * module. A module reader is also intended to be used by {@code ClassLoader} * implementations that load classes and resources from modules.

    * - *

    A resource in a module is identified by a name that is a + *

    A resource in a module is identified by an abstract name that is a * '{@code /}'-separated path string. For example, module {@code java.base} may * have a resource "{@code java/lang/Object.class}" that, by convention, is the * class file for {@code java.lang.Object}.

    @@ -61,8 +61,18 @@ import java.util.stream.Stream; * open}, {@link #read read}, and {@link #list list} methods may throw {@code * SecurityException} if access is denied by the security manager.

    * + * @implSpec Implementations of {@code ModuleReader} should take great care + * when translating an abstract resource name to the location of a resource in + * a packaged module or on the file system. Implementations are advised to + * treat resource names with elements such as '{@code .}, '{@code ..}', + * elements containing file separators, or empty elements as "not found". More + * generally, if the resource name is not in the stream of elements that the + * {@code list} method returns then the resource should be treated as "not + * found" to avoid inconsistencies. + * * @see ModuleReference * @since 9 + * @spec JPMS */ public interface ModuleReader extends Closeable { @@ -148,6 +158,9 @@ public interface ModuleReader extends Closeable { * If an I/O error occurs or the module reader is closed * @throws SecurityException * If denied by the security manager + * @throws OutOfMemoryError + * If the resource is larger than {@code Integer.MAX_VALUE}, + * the maximum capacity of a byte buffer * * @see ClassLoader#defineClass(String, ByteBuffer, java.security.ProtectionDomain) */ diff --git a/jdk/src/java.base/share/classes/java/lang/module/ModuleReference.java b/jdk/src/java.base/share/classes/java/lang/module/ModuleReference.java index 09a5acec219..54291e78dcc 100644 --- a/jdk/src/java.base/share/classes/java/lang/module/ModuleReference.java +++ b/jdk/src/java.base/share/classes/java/lang/module/ModuleReference.java @@ -44,6 +44,7 @@ import java.util.Optional; * @see ModuleFinder * @see ModuleReader * @since 9 + * @spec JPMS */ public abstract class ModuleReference { @@ -76,7 +77,7 @@ public abstract class ModuleReference { /** * Returns the location of this module's content, if known. * - *

    This URI, when present, is used as the {@linkplain + *

    This URI, when present, can be used as the {@linkplain * java.security.CodeSource#getLocation location} value of a {@link * java.security.CodeSource CodeSource} so that a module's classes can be * granted specific permissions when loaded by a {@link diff --git a/jdk/src/java.base/share/classes/java/lang/module/ResolutionException.java b/jdk/src/java.base/share/classes/java/lang/module/ResolutionException.java index fb14cfe8200..69cc71f3466 100644 --- a/jdk/src/java.base/share/classes/java/lang/module/ResolutionException.java +++ b/jdk/src/java.base/share/classes/java/lang/module/ResolutionException.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2017, 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 @@ -26,10 +26,12 @@ package java.lang.module; /** - * Thrown when resolving a set of modules or binding fails. + * Thrown when resolving a set of modules, or resolving a set of modules with + * service binding, fails. * * @see Configuration * @since 9 + * @spec JPMS */ public class ResolutionException extends RuntimeException { private static final long serialVersionUID = -1031186845316729450L; diff --git a/jdk/src/java.base/share/classes/java/lang/module/ResolvedModule.java b/jdk/src/java.base/share/classes/java/lang/module/ResolvedModule.java index 05ef3c4dc1c..a3858ef6c13 100644 --- a/jdk/src/java.base/share/classes/java/lang/module/ResolvedModule.java +++ b/jdk/src/java.base/share/classes/java/lang/module/ResolvedModule.java @@ -37,6 +37,7 @@ import java.util.Set; * module's content. * * @since 9 + * @spec JPMS * @see Configuration#modules() */ public final class ResolvedModule { diff --git a/jdk/src/java.base/share/classes/java/lang/module/Resolver.java b/jdk/src/java.base/share/classes/java/lang/module/Resolver.java index d2aafdc5d87..1a44475b442 100644 --- a/jdk/src/java.base/share/classes/java/lang/module/Resolver.java +++ b/jdk/src/java.base/share/classes/java/lang/module/Resolver.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2017, 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,8 +49,8 @@ import jdk.internal.module.ModuleHashes; import jdk.internal.module.ModuleReferenceImpl; /** - * The resolver used by {@link Configuration#resolveRequires} and - * {@link Configuration#resolveRequiresAndUses}. + * The resolver used by {@link Configuration#resolve} and {@link + * Configuration#resolveAndBind}. * * @implNote The resolver is used at VM startup and so deliberately avoids * using lambda and stream usages in code paths used during startup. @@ -66,7 +66,19 @@ final class Resolver { // maps module name to module reference private final Map nameToReference = new HashMap<>(); + // module constraints on target platform + private String osName; + private String osArch; + private String osVersion; + String osName() { return osName; } + String osArch() { return osArch; } + String osVersion() { return osVersion; } + + /** + * @throws IllegalArgumentException if there are more than one parent and + * the constraints on the target platform conflict + */ Resolver(ModuleFinder beforeFinder, List parents, ModuleFinder afterFinder, @@ -75,15 +87,54 @@ final class Resolver { this.parents = parents; this.afterFinder = afterFinder; this.traceOutput = traceOutput; + + // record constraints on target platform, checking that they don't conflict + for (Configuration parent : parents) { + String value = parent.osName(); + if (value != null) { + if (osName == null) { + osName = value; + } else { + if (!value.equals(osName)) { + failParentConflict("Operating System", osName, value); + } + } + } + value = parent.osArch(); + if (value != null) { + if (osArch == null) { + osArch = value; + } else { + if (!value.equals(osArch)) { + failParentConflict("OS architecture", osArch, value); + } + } + } + value = parent.osVersion(); + if (value != null) { + if (osVersion == null) { + osVersion = value; + } else { + if (!value.equals(osVersion)) { + failParentConflict("OS version", osVersion, value); + } + } + } + } } + private void failParentConflict(String constraint, String s1, String s2) { + String msg = "Parents have conflicting constraints on target " + + constraint + ": " + s1 + ", " + s2; + throw new IllegalArgumentException(msg); + } /** * Resolves the given named modules. * * @throws ResolutionException */ - Resolver resolveRequires(Collection roots) { + Resolver resolve(Collection roots) { // create the visit stack to get us started Deque q = new ArrayDeque<>(); @@ -100,7 +151,7 @@ final class Resolver { mref = findWithAfterFinder(root); if (mref == null) { - fail("Module %s not found", root); + findFail("Module %s not found", root); } } @@ -109,8 +160,7 @@ final class Resolver { mref.location().ifPresent(uri -> trace(" (%s)", uri)); } - assert mref.descriptor().name().equals(root); - nameToReference.put(root, mref); + addFoundModule(mref); q.push(mref.descriptor()); } @@ -152,19 +202,19 @@ final class Resolver { mref = findWithAfterFinder(dn); if (mref == null) { - fail("Module %s not found, required by %s", - dn, descriptor.name()); + findFail("Module %s not found, required by %s", + dn, descriptor.name()); } } if (!nameToReference.containsKey(dn)) { - nameToReference.put(dn, mref); + addFoundModule(mref); q.offer(mref.descriptor()); resolved.add(mref.descriptor()); if (isTracing()) { trace("Module %s located, required by %s", - dn, descriptor.name()); + dn, descriptor.name()); mref.location().ifPresent(uri -> trace(" (%s)", uri)); } } @@ -181,7 +231,7 @@ final class Resolver { * Augments the set of resolved modules with modules induced by the * service-use relation. */ - Resolver resolveUses() { + Resolver bind() { // Scan the finders for all available service provider modules. As // java.base uses services then then module finders will be scanned @@ -246,7 +296,7 @@ final class Resolver { mref.location() .ifPresent(uri -> trace(" (%s)", uri)); } - nameToReference.put(pn, mref); + addFoundModule(mref); q.push(provider); } } @@ -263,6 +313,81 @@ final class Resolver { } + /** + * Add the module to the nameToReference map. Also check any constraints on + * the target platform with the constraints of other modules. + */ + private void addFoundModule(ModuleReference mref) { + ModuleDescriptor descriptor = mref.descriptor(); + nameToReference.put(descriptor.name(), mref); + + if (descriptor.osName().isPresent() + || descriptor.osArch().isPresent() + || descriptor.osVersion().isPresent()) + checkTargetConstraints(descriptor); + } + + /** + * Check that the module's constraints on the target platform do not + * conflict with the constraints of other modules resolved so far or + * modules in parent configurations. + */ + private void checkTargetConstraints(ModuleDescriptor descriptor) { + String value = descriptor.osName().orElse(null); + if (value != null) { + if (osName == null) { + osName = value; + } else { + if (!value.equals(osName)) { + failTargetConstraint(descriptor); + } + } + } + value = descriptor.osArch().orElse(null); + if (value != null) { + if (osArch == null) { + osArch = value; + } else { + if (!value.equals(osArch)) { + failTargetConstraint(descriptor); + } + } + } + value = descriptor.osVersion().orElse(null); + if (value != null) { + if (osVersion == null) { + osVersion = value; + } else { + if (!value.equals(osVersion)) { + failTargetConstraint(descriptor); + } + } + } + } + + private void failTargetConstraint(ModuleDescriptor md) { + String s1 = targetAsString(osName, osArch, osVersion); + String s2 = targetAsString(md); + findFail("Module %s has constraints on target platform that conflict" + + " with other modules: %s, %s", md.name(), s1, s2); + } + + private String targetAsString(ModuleDescriptor descriptor) { + String osName = descriptor.osName().orElse(null); + String osArch = descriptor.osArch().orElse(null); + String osVersion = descriptor.osVersion().orElse(null); + return targetAsString(osName, osArch, osVersion); + } + + private String targetAsString(String osName, String osArch, String osVersion) { + return new StringJoiner("-") + .add(Objects.toString(osName, "*")) + .add(Objects.toString(osArch, "*")) + .add(Objects.toString(osVersion, "*")) + .toString(); + } + + /** * Execute post-resolution checks and returns the module graph of resolved * modules as {@code Map}. The resolved modules will be in the given @@ -281,7 +406,6 @@ final class Resolver { if (check) { detectCycles(); - checkPlatformConstraints(); checkHashes(); } @@ -319,8 +443,7 @@ final class Resolver { if (!visited.contains(descriptor)) { boolean added = visitPath.add(descriptor); if (!added) { - throw new ResolutionException("Cycle detected: " + - cycleAsString(descriptor)); + resolveFail("Cycle detected: %s", cycleAsString(descriptor)); } for (ModuleDescriptor.Requires requires : descriptor.requires()) { String dn = requires.name(); @@ -353,86 +476,6 @@ final class Resolver { } - /** - * If there are platform specific modules then check that the OS name, - * architecture and version match. - * - * @apiNote This method does not currently check if the OS matches - * platform specific modules in parent configurations. - */ - private void checkPlatformConstraints() { - - // first module encountered that is platform specific - String savedModuleName = null; - String savedOsName = null; - String savedOsArch = null; - String savedOsVersion = null; - - for (ModuleReference mref : nameToReference.values()) { - ModuleDescriptor descriptor = mref.descriptor(); - - String osName = descriptor.osName().orElse(null); - String osArch = descriptor.osArch().orElse(null); - String osVersion = descriptor.osVersion().orElse(null); - - if (osName != null || osArch != null || osVersion != null) { - - if (savedModuleName == null) { - - savedModuleName = descriptor.name(); - savedOsName = osName; - savedOsArch = osArch; - savedOsVersion = osVersion; - - } else { - - boolean matches = platformMatches(osName, savedOsName) - && platformMatches(osArch, savedOsArch) - && platformMatches(osVersion, savedOsVersion); - - if (!matches) { - String s1 = platformAsString(savedOsName, - savedOsArch, - savedOsVersion); - - String s2 = platformAsString(osName, osArch, osVersion); - fail("Mismatching constraints on target platform: " - + savedModuleName + ": " + s1 - + ", " + descriptor.name() + ": " + s2); - } - - } - - } - } - - } - - /** - * Returns true if the s1 and s2 are equal or one of them is null. - */ - private boolean platformMatches(String s1, String s2) { - if (s1 == null || s2 == null) - return true; - else - return Objects.equals(s1, s2); - } - - /** - * Return a string that encodes the OS name/arch/version. - */ - private String platformAsString(String osName, - String osArch, - String osVersion) { - - return new StringJoiner("-") - .add(Objects.toString(osName, "*")) - .add(Objects.toString(osArch, "*")) - .add(Objects.toString(osVersion, "*")) - .toString(); - - } - /** * Checks the hashes in the module descriptor to ensure that they match * any recorded hashes. @@ -460,7 +503,7 @@ final class Resolver { continue; if (!(mref2 instanceof ModuleReferenceImpl)) { - fail("Unable to compute the hash of module %s", dn); + findFail("Unable to compute the hash of module %s", dn); } // skip checking the hash if the module has been patched @@ -469,11 +512,11 @@ final class Resolver { byte[] recordedHash = hashes.hashFor(dn); byte[] actualHash = other.computeHash(algorithm); if (actualHash == null) - fail("Unable to compute the hash of module %s", dn); + findFail("Unable to compute the hash of module %s", dn); if (!Arrays.equals(recordedHash, actualHash)) { - fail("Hash of %s (%s) differs to expected hash (%s)" + - " recorded in %s", dn, toHexString(actualHash), - toHexString(recordedHash), descriptor.name()); + findFail("Hash of %s (%s) differs to expected hash (%s)" + + " recorded in %s", dn, toHexString(actualHash), + toHexString(recordedHash), descriptor.name()); } } } @@ -694,37 +737,38 @@ final class Resolver { for (ResolvedModule endpoint : reads) { ModuleDescriptor descriptor2 = endpoint.descriptor(); - for (ModuleDescriptor.Exports export : descriptor2.exports()) { + if (descriptor2.isAutomatic()) { + // automatic modules read self and export all packages + if (descriptor2 != descriptor1){ + for (String source : descriptor2.packages()) { + ModuleDescriptor supplier + = packageToExporter.putIfAbsent(source, descriptor2); - if (export.isQualified()) { - if (!export.targets().contains(descriptor1.name())) - continue; - } - - // source is exported to descriptor2 - String source = export.source(); - ModuleDescriptor other - = packageToExporter.putIfAbsent(source, descriptor2); - - if (other != null && other != descriptor2) { - // package might be local to descriptor1 - if (other == descriptor1) { - fail("Module %s contains package %s" - + ", module %s exports package %s to %s", - descriptor1.name(), - source, - descriptor2.name(), - source, - descriptor1.name()); - } else { - fail("Modules %s and %s export package %s to module %s", - descriptor2.name(), - other.name(), - source, - descriptor1.name()); + // descriptor2 and 'supplier' export source to descriptor1 + if (supplier != null) { + failTwoSuppliers(descriptor1, source, descriptor2, supplier); + } } } + } else { + for (ModuleDescriptor.Exports export : descriptor2.exports()) { + if (export.isQualified()) { + if (!export.targets().contains(descriptor1.name())) + continue; + } + + // source is exported by descriptor2 + String source = export.source(); + ModuleDescriptor supplier + = packageToExporter.putIfAbsent(source, descriptor2); + + // descriptor2 and 'supplier' export source to descriptor1 + if (supplier != null) { + failTwoSuppliers(descriptor1, source, descriptor2, supplier); + } + } + } } @@ -735,8 +779,8 @@ final class Resolver { for (String service : descriptor1.uses()) { String pn = packageName(service); if (!packageToExporter.containsKey(pn)) { - fail("Module %s does not read a module that exports %s", - descriptor1.name(), pn); + resolveFail("Module %s does not read a module that exports %s", + descriptor1.name(), pn); } } @@ -744,15 +788,8 @@ final class Resolver { for (ModuleDescriptor.Provides provides : descriptor1.provides()) { String pn = packageName(provides.service()); if (!packageToExporter.containsKey(pn)) { - fail("Module %s does not read a module that exports %s", - descriptor1.name(), pn); - } - - for (String provider : provides.providers()) { - if (!packages.contains(packageName(provider))) { - fail("Provider %s not in module %s", - provider, descriptor1.name()); - } + resolveFail("Module %s does not read a module that exports %s", + descriptor1.name(), pn); } } @@ -762,6 +799,42 @@ final class Resolver { } + /** + * Fail because a module in the configuration exports the same package to + * a module that reads both. This includes the case where a module M + * containing a package p reads another module that exports p to at least + * module M. + */ + private void failTwoSuppliers(ModuleDescriptor descriptor, + String source, + ModuleDescriptor supplier1, + ModuleDescriptor supplier2) { + + if (supplier2 == descriptor) { + ModuleDescriptor tmp = supplier1; + supplier1 = supplier2; + supplier2 = tmp; + } + + if (supplier1 == descriptor) { + resolveFail("Module %s contains package %s" + + ", module %s exports package %s to %s", + descriptor.name(), + source, + supplier2.name(), + source, + descriptor.name()); + } else { + resolveFail("Modules %s and %s export package %s to module %s", + supplier1.name(), + supplier2.name(), + source, + descriptor.name()); + } + + } + + /** * Find a module of the given name in the parent configurations */ @@ -779,24 +852,16 @@ final class Resolver { * Invokes the beforeFinder to find method to find the given module. */ private ModuleReference findWithBeforeFinder(String mn) { - try { - return beforeFinder.find(mn).orElse(null); - } catch (FindException e) { - // unwrap - throw new ResolutionException(e.getMessage(), e.getCause()); - } + + return beforeFinder.find(mn).orElse(null); + } /** * Invokes the afterFinder to find method to find the given module. */ private ModuleReference findWithAfterFinder(String mn) { - try { - return afterFinder.find(mn).orElse(null); - } catch (FindException e) { - // unwrap - throw new ResolutionException(e.getMessage(), e.getCause()); - } + return afterFinder.find(mn).orElse(null); } /** @@ -804,34 +869,27 @@ final class Resolver { * and after ModuleFinders. */ private Set findAll() { - try { + Set beforeModules = beforeFinder.findAll(); + Set afterModules = afterFinder.findAll(); - Set beforeModules = beforeFinder.findAll(); - Set afterModules = afterFinder.findAll(); + if (afterModules.isEmpty()) + return beforeModules; - if (afterModules.isEmpty()) - return beforeModules; + if (beforeModules.isEmpty() + && parents.size() == 1 + && parents.get(0) == Configuration.empty()) + return afterModules; - if (beforeModules.isEmpty() - && parents.size() == 1 - && parents.get(0) == Configuration.empty()) - return afterModules; - - Set result = new HashSet<>(beforeModules); - for (ModuleReference mref : afterModules) { - String name = mref.descriptor().name(); - if (!beforeFinder.find(name).isPresent() - && findInParent(name) == null) { - result.add(mref); - } + Set result = new HashSet<>(beforeModules); + for (ModuleReference mref : afterModules) { + String name = mref.descriptor().name(); + if (!beforeFinder.find(name).isPresent() + && findInParent(name) == null) { + result.add(mref); } - - return result; - - } catch (FindException e) { - // unwrap - throw new ResolutionException(e.getMessage(), e.getCause()); } + + return result; } /** @@ -842,10 +900,18 @@ final class Resolver { return (index == -1) ? "" : cn.substring(0, index); } + /** + * Throw FindException with the given format string and arguments + */ + private static void findFail(String fmt, Object ... args) { + String msg = String.format(fmt, args); + throw new FindException(msg); + } + /** * Throw ResolutionException with the given format string and arguments */ - private static void fail(String fmt, Object ... args) { + private static void resolveFail(String fmt, Object ... args) { String msg = String.format(fmt, args); throw new ResolutionException(msg); } diff --git a/jdk/src/java.base/share/classes/java/lang/module/package-info.java b/jdk/src/java.base/share/classes/java/lang/module/package-info.java index f641638cb2c..1d830079cab 100644 --- a/jdk/src/java.base/share/classes/java/lang/module/package-info.java +++ b/jdk/src/java.base/share/classes/java/lang/module/package-info.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2017, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -27,6 +27,112 @@ * Classes to support module descriptors and creating configurations of modules * by means of resolution and service binding. * + *

    Resolution

    + * + *

    Resolution is the process of computing the transitive closure of a set + * of root modules over a set of observable modules by resolving the + * dependences expressed by {@link + * java.lang.module.ModuleDescriptor.Requires requires} clauses. + * The dependence graph is augmented with edges that take account of + * implicitly declared dependences ({@code requires transitive}) to create a + * readability graph. The result of resolution is a {@link + * java.lang.module.Configuration Configuration} that encapsulates the + * readability graph.

    + * + *

    As an example, suppose we have the following observable modules:

    + *
     {@code
    + *     module m1 { requires m2; }
    + *     module m2 { requires transitive m3; }
    + *     module m3 { }
    + *     module m4 { }
    + * } 
    + * + *

    If the module {@code m1} is resolved then the resulting configuration + * contains three modules ({@code m1}, {@code m2}, {@code m3}). The edges in + * its readability graph are:

    + *
     {@code
    + *     m1 --> m2  (meaning m1 reads m2)
    + *     m1 --> m3
    + *     m2 --> m3
    + * } 
    + * + *

    Resolution is an additive process. When computing the transitive closure + * then the dependence relation may include dependences on modules in {@link + * java.lang.module.Configuration#parents() parent} configurations. The result + * is a relative configuration that is relative to one or more parent + * configurations and where the readability graph may have edges from modules + * in the configuration to modules in parent configurations.

    + * + *

    As an example, suppose we have the following observable modules:

    + *
     {@code
    + *     module m1 { requires m2; requires java.xml; }
    + *     module m2 { }
    + * } 
    + * + *

    If module {@code m1} is resolved with the configuration for the {@link + * java.lang.reflect.Layer#boot() boot} layer as the parent then the resulting + * configuration contains two modules ({@code m1}, {@code m2}). The edges in + * its readability graph are: + *

     {@code
    + *     m1 --> m2
    + *     m1 --> java.xml
    + * } 
    + * where module {@code java.xml} is in the parent configuration. For + * simplicity, this example omits the implicitly declared dependence on the + * {@code java.base} module. + * + *

    Requires clauses that are "{@code requires static}" express an optional + * dependence (except at compile-time). If a module declares that it + * "{@code requires static M}" then resolution does not search the observable + * modules for "{@code M}". However, if "{@code M}" is resolved (because resolution + * resolves a module that requires "{@code M}" without the {@link + * java.lang.module.ModuleDescriptor.Requires.Modifier#STATIC static} modifier) + * then the readability graph will contain read edges for each module that + * "{@code requires static M}".

    + * + *

    {@link java.lang.module.ModuleDescriptor#isAutomatic() Automatic} modules + * receive special treatment during resolution. Each automatic module is resolved + * so that it reads all other modules in the configuration and all parent + * configurations. Each automatic module is also resolved as if it + * "{@code requires transitive}" all other automatic modules in the configuration + * (and all automatic modules in parent configurations).

    + * + *

    Service binding

    + * + *

    Service binding is the process of augmenting a graph of resolved modules + * from the set of observable modules induced by the service-use dependence + * ({@code uses} and {@code provides} clauses). Any module that was not + * previously in the graph requires resolution to compute its transitive + * closure. Service binding is an iterative process in that adding a module + * that satisfies some service-use dependence may introduce new service-use + * dependences.

    + * + *

    Suppose we have the following observable modules:

    + *
     {@code
    + *     module m1 { exports p; uses p.S; }
    + *     module m2 { requires m1; provides p.S with p2.S2; }
    + *     module m3 { requires m1; requires m4; provides p.S with p3.S3; }
    + *     module m4 { }
    + * } 
    + * + *

    If the module {@code m1} is resolved then the resulting graph of modules + * has one module ({@code m1}). If the graph is augmented with modules induced + * by the service-use dependence relation then the configuration will contain + * four modules ({@code m1}, {@code m2}, {@code m3}, {@code m4}). The edges in + * its readability graph are:

    + *
     {@code
    + *     m2 --> m1
    + *     m3 --> m1
    + *     m3 --> m4
    + * } 
    + *

    The edges in the conceptual service-use graph are:

    + *
     {@code
    + *     m1 --> m2  (meaning m1 uses a service that is provided by m2)
    + *     m1 --> m3
    + * } 
    + * + *

    General Exceptions

    + * *

    Unless otherwise noted, passing a {@code null} argument to a constructor * or method of any class or interface in this package will cause a {@link * java.lang.NullPointerException NullPointerException} to be thrown. Additionally, @@ -34,6 +140,7 @@ * will cause a {@code NullPointerException}, unless otherwise specified.

    * * @since 9 + * @spec JPMS */ package java.lang.module; diff --git a/jdk/src/java.base/share/classes/java/lang/reflect/AccessibleObject.java b/jdk/src/java.base/share/classes/java/lang/reflect/AccessibleObject.java index f585b476504..503ce8dfb1e 100644 --- a/jdk/src/java.base/share/classes/java/lang/reflect/AccessibleObject.java +++ b/jdk/src/java.base/share/classes/java/lang/reflect/AccessibleObject.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2017, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -28,38 +28,44 @@ package java.lang.reflect; import java.lang.annotation.Annotation; import java.security.AccessController; -import jdk.internal.misc.VM; import jdk.internal.reflect.CallerSensitive; import jdk.internal.reflect.Reflection; import jdk.internal.reflect.ReflectionFactory; -import sun.security.action.GetPropertyAction; /** - * The AccessibleObject class is the base class for Field, Method and - * Constructor objects. It provides the ability to flag a reflected - * object as suppressing default Java language access control checks - * when it is used. The access checks -- module boundaries, - * public, default (package) access, protected, and private members -- - * are performed when Fields, Methods or Constructors are used to set - * or get fields, to invoke methods or to create and initialize new - * instances of classes, respectively. Unlike access control specified - * in the The Java™ Language Specification and - * The Java Virtual Machine Specification, access checks - * with reflected objects assume {@link Module#canRead readability}. + * The {@code AccessibleObject} class is the base class for {@code Field}, + * {@code Method}, and {@code Constructor} objects (known as reflected + * objects). It provides the ability to flag a reflected object as + * suppressing checks for Java language access control when it is used. This + * permits sophisticated applications with sufficient privilege, such as Java + * Object Serialization or other persistence mechanisms, to manipulate objects + * in a manner that would normally be prohibited. * - *

    Setting the {@code accessible} flag in a reflected object - * permits sophisticated applications with sufficient privilege, such - * as Java Object Serialization or other persistence mechanisms, to - * manipulate objects in a manner that would normally be prohibited. + *

    Java language access control prevents use of private members outside + * their class; package access members outside their package; protected members + * outside their package or subclasses; and public members outside their + * module unless they are declared in an {@link Module#isExported(String,Module) + * exported} package and the user {@link Module#canRead reads} their module. By + * default, Java language access control is enforced (with one variation) when + * {@code Field}s, {@code Method}s, or {@code Constructor}s are used to get or + * set fields, to invoke methods, or to create and initialize new instances of + * classes, respectively. Every reflected object checks that the code using it + * is in an appropriate class, package, or module.

    * - *

    By default, a reflected object is not accessible. + *

    The one variation from Java language access control is that the checks + * by reflected objects assume readability. That is, the module containing + * the use of a reflected object is assumed to read the module in which + * the underlying field, method, or constructor is declared.

    * - * @see Field - * @see Method - * @see Constructor - * @see ReflectPermission + *

    Whether the checks for Java language access control can be suppressed + * (and thus, whether access can be enabled) depends on whether the reflected + * object corresponds to a member in an exported or open package + * (see {@link #setAccessible(boolean)}).

    * + * @jls 6.6 Access Control * @since 1.2 + * @revised 9 + * @spec JPMS */ public class AccessibleObject implements AnnotatedElement { @@ -78,15 +84,11 @@ public class AccessibleObject implements AnnotatedElement { /** * Convenience method to set the {@code accessible} flag for an - * array of objects with a single security check (for efficiency). + * array of reflected objects with a single security check (for efficiency). * - *

    This method cannot be used to enable access to an object that is a - * {@link Member member} of a class in a different module to the caller and - * where the class is in a package that is not exported to the caller's - * module. Additionally, if the member is non-public or its declaring - * class is non-public, then this method can only be used to enable access - * if the package is {@link Module#isOpen(String,Module) open} to at least - * the caller's module. + *

    This method may be used to enable access to all reflected objects in + * the array when access to each reflected object can be enabled as + * specified by {@link #setAccessible(boolean) setAccessible(boolean)}.

    * *

    If there is a security manager, its * {@code checkPermission} method is first called with a @@ -99,10 +101,15 @@ public class AccessibleObject implements AnnotatedElement { * @param array the array of AccessibleObjects * @param flag the new value for the {@code accessible} flag * in each object - * @throws InaccessibleObjectException if access cannot be enabled - * @throws SecurityException if the request is denied. + * @throws InaccessibleObjectException if access cannot be enabled for all + * objects in the array + * @throws SecurityException if the request is denied by the security manager + * or an element in the array is a constructor for {@code + * java.lang.Class} * @see SecurityManager#checkPermission * @see ReflectPermission + * @revised 9 + * @spec JPMS */ @CallerSensitive public static void setAccessible(AccessibleObject[] array, boolean flag) { @@ -120,41 +127,143 @@ public class AccessibleObject implements AnnotatedElement { } /** - * Set the {@code accessible} flag for this object to + * Set the {@code accessible} flag for this reflected object to * the indicated boolean value. A value of {@code true} indicates that - * the reflected object should suppress Java language access - * checking when it is used. A value of {@code false} indicates - * that the reflected object should enforce Java language access checks - * while assuming readability (as noted in the class description). + * the reflected object should suppress checks for Java language access + * control when it is used. A value of {@code false} indicates that + * the reflected object should enforce checks for Java language access + * control when it is used, with the variation noted in the class description. * - *

    This method cannot be used to enable access to an object that is a - * {@link Member member} of a class in a different module to the caller and - * where the class is in a package that is not exported to the caller's - * module. Additionally, if the member is non-public or its declaring - * class is non-public, then this method can only be used to enable access - * if the package is {@link Module#isOpen(String,Module) open} to at least - * the caller's module. + *

    This method may be used by a caller in class {@code C} to enable + * access to a {@link Member member} of {@link Member#getDeclaringClass() + * declaring class} {@code D} if any of the following hold:

    * - *

    If there is a security manager, its + *

      + *
    • {@code C} and {@code D} are in the same module.
    • + * + *
    • The member is {@code public} and {@code D} is {@code public} in + * a package that the module containing {@code D} {@link + * Module#isExported(String,Module) exports} to at least the module + * containing {@code C}.
    • + * + *
    • The member is {@code protected} {@code static}, {@code D} is + * {@code public} in a package that the module containing {@code D} + * exports to at least the module containing {@code C}, and {@code C} + * is a subclass of {@code D}.
    • + * + *
    • {@code D} is in a package that the module containing {@code D} + * {@link Module#isOpen(String,Module) opens} to at least the module + * containing {@code C}. + * All packages in unnamed and open modules are open to all modules and + * so this method always succeeds when {@code D} is in an unnamed or + * open module.
    • + *
    + * + *

    This method cannot be used to enable access to private members, + * members with default (package) access, protected instance members, or + * protected constructors when the declaring class is in a different module + * to the caller and the package containing the declaring class is not open + * to the caller's module.

    + * + *

    If there is a security manager, its * {@code checkPermission} method is first called with a * {@code ReflectPermission("suppressAccessChecks")} permission. * * @param flag the new value for the {@code accessible} flag * @throws InaccessibleObjectException if access cannot be enabled - * @throws SecurityException if the request is denied - * @see SecurityManager#checkPermission - * @see ReflectPermission + * @throws SecurityException if the request is denied by the security manager + * @see #trySetAccessible * @see java.lang.invoke.MethodHandles#privateLookupIn + * @revised 9 + * @spec JPMS */ public void setAccessible(boolean flag) { AccessibleObject.checkPermission(); setAccessible0(flag); } - void setAccessible0(boolean flag) { + /** + * Sets the accessible flag and returns the new value + */ + boolean setAccessible0(boolean flag) { this.override = flag; + return flag; } + /** + * Set the {@code accessible} flag for this reflected object to {@code true} + * if possible. This method sets the {@code accessible} flag, as if by + * invoking {@link #setAccessible(boolean) setAccessible(true)}, and returns + * the possibly-updated value for the {@code accessible} flag. If access + * cannot be enabled, i.e. the checks or Java language access control cannot + * be suppressed, this method returns {@code false} (as opposed to {@code + * setAccessible(true)} throwing {@code InaccessibleObjectException} when + * it fails). + * + *

    This method is a no-op if the {@code accessible} flag for + * this reflected object is {@code true}. + * + *

    For example, a caller can invoke {@code trySetAccessible} + * on a {@code Method} object for a private instance method + * {@code p.T::privateMethod} to suppress the checks for Java language access + * control when the {@code Method} is invoked. + * If {@code p.T} class is in a different module to the caller and + * package {@code p} is open to at least the caller's module, + * the code below successfully sets the {@code accessible} flag + * to {@code true}. + * + *

    +     * {@code
    +     *     p.T obj = ....;  // instance of p.T
    +     *     :
    +     *     Method m = p.T.class.getDeclaredMethod("privateMethod");
    +     *     if (m.trySetAccessible()) {
    +     *         m.invoke(obj);
    +     *     } else {
    +     *         // package p is not opened to the caller to access private member of T
    +     *         ...
    +     *     }
    +     * }
    + * + *

    If there is a security manager, its {@code checkPermission} method + * is first called with a {@code ReflectPermission("suppressAccessChecks")} + * permission.

    + * + * @return {@code true} if the {@code accessible} flag is set to {@code true}; + * {@code false} if access cannot be enabled. + * @throws SecurityException if the request is denied by the security manager + * + * @since 9 + * @spec JPMS + * @see java.lang.invoke.MethodHandles#privateLookupIn + */ + @CallerSensitive + public final boolean trySetAccessible() { + AccessibleObject.checkPermission(); + + if (override == true) return true; + + // if it's not a Constructor, Method, Field then no access check + if (!Member.class.isInstance(this)) { + return setAccessible0(true); + } + + // does not allow to suppress access check for Class's constructor + Class declaringClass = ((Member) this).getDeclaringClass(); + if (declaringClass == Class.class && this instanceof Constructor) { + return false; + } + + if (checkCanSetAccessible(Reflection.getCallerClass(), + declaringClass, + false)) { + return setAccessible0(true); + } else { + return false; + } + } + + /** * If the given AccessibleObject is a {@code Constructor}, {@code Method} * or {@code Field} then checks that its declaring class is in a package @@ -164,22 +273,29 @@ public class AccessibleObject implements AnnotatedElement { // do nothing, needs to be overridden by Constructor, Method, Field } + void checkCanSetAccessible(Class caller, Class declaringClass) { + checkCanSetAccessible(caller, declaringClass, true); + } + + private boolean checkCanSetAccessible(Class caller, + Class declaringClass, + boolean throwExceptionIfDenied) { Module callerModule = caller.getModule(); Module declaringModule = declaringClass.getModule(); - if (callerModule == declaringModule) return; - if (callerModule == Object.class.getModule()) return; - if (!declaringModule.isNamed()) return; + if (callerModule == declaringModule) return true; + if (callerModule == Object.class.getModule()) return true; + if (!declaringModule.isNamed()) return true; // package is open to caller String pn = packageName(declaringClass); if (declaringModule.isOpen(pn, callerModule)) { - printStackTraceIfOpenedReflectively(declaringModule, pn, callerModule); - return; + dumpStackIfOpenedReflectively(declaringModule, pn, callerModule); + return true; } - // package is exported to caller and class/member is public + // package is exported to caller boolean isExported = declaringModule.isExported(pn, callerModule); boolean isClassPublic = Modifier.isPublic(declaringClass.getModifiers()); int modifiers; @@ -188,48 +304,72 @@ public class AccessibleObject implements AnnotatedElement { } else { modifiers = ((Field) this).getModifiers(); } - boolean isMemberPublic = Modifier.isPublic(modifiers); - if (isExported && isClassPublic && isMemberPublic) { - printStackTraceIfExportedReflectively(declaringModule, pn, callerModule); - return; + if (isExported && isClassPublic) { + + // member is public + if (Modifier.isPublic(modifiers)) { + dumpStackIfExportedReflectively(declaringModule, pn, callerModule); + return true; + } + + // member is protected-static + if (Modifier.isProtected(modifiers) + && Modifier.isStatic(modifiers) + && isSubclassOf(caller, declaringClass)) { + dumpStackIfExportedReflectively(declaringModule, pn, callerModule); + return true; + } } - // not accessible - String msg = "Unable to make "; - if (this instanceof Field) - msg += "field "; - msg += this + " accessible: " + declaringModule + " does not \""; - if (isClassPublic && isMemberPublic) - msg += "exports"; - else - msg += "opens"; - msg += " " + pn + "\" to " + callerModule; - InaccessibleObjectException e = new InaccessibleObjectException(msg); - if (Reflection.printStackTraceWhenAccessFails()) { - e.printStackTrace(System.err); + if (throwExceptionIfDenied) { + // not accessible + String msg = "Unable to make "; + if (this instanceof Field) + msg += "field "; + msg += this + " accessible: " + declaringModule + " does not \""; + if (isClassPublic && Modifier.isPublic(modifiers)) + msg += "exports"; + else + msg += "opens"; + msg += " " + pn + "\" to " + callerModule; + InaccessibleObjectException e = new InaccessibleObjectException(msg); + if (Reflection.printStackTraceWhenAccessFails()) { + e.printStackTrace(System.err); + } + throw e; } - throw e; + return false; } - private void printStackTraceIfOpenedReflectively(Module module, - String pn, - Module other) { - printStackTraceIfExposedReflectively(module, pn, other, true); + private boolean isSubclassOf(Class queryClass, Class ofClass) { + while (queryClass != null) { + if (queryClass == ofClass) { + return true; + } + queryClass = queryClass.getSuperclass(); + } + return false; } - private void printStackTraceIfExportedReflectively(Module module, - String pn, - Module other) { - printStackTraceIfExposedReflectively(module, pn, other, false); + private void dumpStackIfOpenedReflectively(Module module, + String pn, + Module other) { + dumpStackIfExposedReflectively(module, pn, other, true); } - private void printStackTraceIfExposedReflectively(Module module, - String pn, - Module other, - boolean open) + private void dumpStackIfExportedReflectively(Module module, + String pn, + Module other) { + dumpStackIfExposedReflectively(module, pn, other, false); + } + + private void dumpStackIfExposedReflectively(Module module, + String pn, + Module other, + boolean open) { if (Reflection.printStackTraceWhenAccessSucceeds() - && !module.isStaticallyExportedOrOpen(pn, other, open)) + && !module.isStaticallyExportedOrOpen(pn, other, open)) { String msg = other + " allowed to invoke setAccessible on "; if (this instanceof Field) @@ -256,14 +396,99 @@ public class AccessibleObject implements AnnotatedElement { } /** - * Get the value of the {@code accessible} flag for this object. + * Get the value of the {@code accessible} flag for this reflected object. * * @return the value of the object's {@code accessible} flag + * + * @deprecated + * This method is deprecated because its name hints that it checks + * if the reflected object is accessible when it actually indicates + * if the checks for Java language access control are suppressed. + * This method may return {@code false} on a reflected object that is + * accessible to the caller. To test if this reflected object is accessible, + * it should use {@link #canAccess(Object)}. + * + * @revised 9 */ + @Deprecated(since="9") public boolean isAccessible() { return override; } + /** + * Test if the caller can access this reflected object. If this reflected + * object corresponds to an instance method or field then this method tests + * if the caller can access the given {@code obj} with the reflected object. + * For instance methods or fields then the {@code obj} argument must be an + * instance of the {@link Member#getDeclaringClass() declaring class}. For + * static members and constructors then {@code obj} must be {@code null}. + * + *

    This method returns {@code true} if the {@code accessible} flag + * is set to {@code true}, i.e. the checks for Java language access control + * are suppressed, or if the caller can access the member as + * specified in The Java™ Language Specification, + * with the variation noted in the class description.

    + * + * @param obj an instance object of the declaring class of this reflected + * object if it is an instance method or field + * + * @return {@code true} if the caller can access this reflected object. + * + * @throws IllegalArgumentException + *
      + *
    • if this reflected object is a static member or constructor and + * the given {@code obj} is non-{@code null}, or
    • + *
    • if this reflected object is an instance method or field + * and the given {@code obj} is {@code null} or of type + * that is not a subclass of the {@link Member#getDeclaringClass() + * declaring class} of the member.
    • + *
    + * + * @since 9 + * @spec JPMS + * @jls 6.6 Access Control + * @see #trySetAccessible + * @see #setAccessible(boolean) + */ + @CallerSensitive + public final boolean canAccess(Object obj) { + if (!Member.class.isInstance(this)) { + return override; + } + + Class declaringClass = ((Member) this).getDeclaringClass(); + int modifiers = ((Member) this).getModifiers(); + if (!Modifier.isStatic(modifiers) && + (this instanceof Method || this instanceof Field)) { + if (obj == null) { + throw new IllegalArgumentException("null object for " + this); + } + // if this object is an instance member, the given object + // must be a subclass of the declaring class of this reflected object + if (!declaringClass.isAssignableFrom(obj.getClass())) { + throw new IllegalArgumentException("object is not an instance of " + + declaringClass.getName()); + } + } else if (obj != null) { + throw new IllegalArgumentException("non-null object for " + this); + } + + // access check is suppressed + if (override) return true; + + Class caller = Reflection.getCallerClass(); + Class targetClass; + if (this instanceof Constructor) { + targetClass = declaringClass; + } else { + targetClass = Modifier.isStatic(modifiers) ? null : obj.getClass(); + } + return Reflection.verifyMemberAccess(caller, + declaringClass, + targetClass, + modifiers); + } + /** * Constructor: only used by the Java Virtual Machine. */ diff --git a/jdk/src/java.base/share/classes/java/lang/reflect/Constructor.java b/jdk/src/java.base/share/classes/java/lang/reflect/Constructor.java index f64e84f7f37..968e3f30af4 100644 --- a/jdk/src/java.base/share/classes/java/lang/reflect/Constructor.java +++ b/jdk/src/java.base/share/classes/java/lang/reflect/Constructor.java @@ -168,6 +168,13 @@ public final class Constructor extends Executable { * is true.

    * * @param flag {@inheritDoc} + * + * @throws InaccessibleObjectException {@inheritDoc} + * @throws SecurityException if the request is denied by the security manager + * or this is a constructor for {@code java.lang.Class} + * + * @since 9 + * @spec JPMS */ @Override @CallerSensitive diff --git a/jdk/src/java.base/share/classes/java/lang/reflect/Field.java b/jdk/src/java.base/share/classes/java/lang/reflect/Field.java index 05b71785ffa..ef892714b03 100644 --- a/jdk/src/java.base/share/classes/java/lang/reflect/Field.java +++ b/jdk/src/java.base/share/classes/java/lang/reflect/Field.java @@ -158,6 +158,10 @@ class Field extends AccessibleObject implements Member { return res; } + /** + * @throws InaccessibleObjectException {@inheritDoc} + * @throws SecurityException {@inheritDoc} + */ @Override @CallerSensitive public void setAccessible(boolean flag) { diff --git a/jdk/src/java.base/share/classes/java/lang/reflect/InaccessibleObjectException.java b/jdk/src/java.base/share/classes/java/lang/reflect/InaccessibleObjectException.java index 34db5150f85..b03d449fecc 100644 --- a/jdk/src/java.base/share/classes/java/lang/reflect/InaccessibleObjectException.java +++ b/jdk/src/java.base/share/classes/java/lang/reflect/InaccessibleObjectException.java @@ -30,6 +30,7 @@ package java.lang.reflect; * * @see AccessibleObject#setAccessible(boolean) * @since 9 + * @spec JPMS */ public class InaccessibleObjectException extends RuntimeException { diff --git a/jdk/src/java.base/share/classes/java/lang/reflect/Layer.java b/jdk/src/java.base/share/classes/java/lang/reflect/Layer.java index 9eaf90d0ca8..d6d89980aae 100644 --- a/jdk/src/java.base/share/classes/java/lang/reflect/Layer.java +++ b/jdk/src/java.base/share/classes/java/lang/reflect/Layer.java @@ -56,20 +56,19 @@ import sun.security.util.SecurityConstants; /** * A layer of modules in the Java virtual machine. * - *

    A layer is created from a graph of modules that is the {@link - * Configuration} and a function that maps each module to a {@link ClassLoader}. + *

    A layer is created from a graph of modules in a {@link Configuration} + * and a function that maps each module to a {@link ClassLoader}. * Creating a layer informs the Java virtual machine about the classes that - * may be loaded from modules so that the Java virtual machine knows which - * module that each class is a member of. Each layer, except the {@link - * #empty() empty} layer, has at least one {@link #parents() parent}.

    + * may be loaded from the modules so that the Java virtual machine knows which + * module that each class is a member of.

    * *

    Creating a layer creates a {@link Module} object for each {@link * ResolvedModule} in the configuration. For each resolved module that is * {@link ResolvedModule#reads() read}, the {@code Module} {@link * Module#canRead reads} the corresponding run-time {@code Module}, which may - * be in the same layer or a parent layer. The {@code Module} {@link - * Module#isExported(String) exports} the packages described by its {@link - * ModuleDescriptor}.

    + * be in the same layer or a {@link #parents() parent} layer. The {@code Module} + * {@link Module#isExported(String) exports} and {@link Module#isOpen(String) + * opens} the packages described by its {@link ModuleDescriptor}.

    * *

    The {@link #defineModulesWithOneLoader defineModulesWithOneLoader} and * {@link #defineModulesWithManyLoaders defineModulesWithManyLoaders} methods @@ -80,7 +79,7 @@ import sun.security.util.SecurityConstants; * a function specified to the method. Each of these methods has an instance * and static variant. The instance methods create a layer with the receiver * as the parent layer. The static methods are for more advanced cases where - * there can be more than one parent layer or a {@link Layer.Controller + * there can be more than one parent layer or where a {@link Layer.Controller * Controller} is needed to control modules in the layer.

    * *

    A Java virtual machine has at least one non-empty layer, the {@link @@ -93,9 +92,8 @@ import sun.security.util.SecurityConstants; * the {@link #parents() parent} when creating additional layers.

    * *

    As when creating a {@code Configuration}, - * {@link ModuleDescriptor#isAutomatic() automatic} modules receive - * special - * treatment when creating a layer. An automatic module is created in the + * {@link ModuleDescriptor#isAutomatic() automatic} modules receive special + * treatment when creating a layer. An automatic module is created in the * Java virtual machine as a {@code Module} that reads every unnamed {@code * Module} in the Java virtual machine.

    * @@ -115,8 +113,7 @@ import sun.security.util.SecurityConstants; * * Layer parent = Layer.boot(); * - * Configuration cf = parent.configuration() - * .resolveRequires(finder, ModuleFinder.of(), Set.of("myapp")); + * Configuration cf = parent.configuration().resolve(finder, ModuleFinder.of(), Set.of("myapp")); * * ClassLoader scl = ClassLoader.getSystemClassLoader(); * @@ -126,6 +123,7 @@ import sun.security.util.SecurityConstants; * }
    * * @since 9 + * @spec JPMS * @see Module#getLayer() */ @@ -168,10 +166,15 @@ public final class Layer { * module layers return a {@code Controller} that can be used to control * modules in the layer. * + *

    Unless otherwise specified, passing a {@code null} argument to a + * method in this class causes a {@link NullPointerException + * NullPointerException} to be thrown.

    + * * @apiNote Care should be taken with {@code Controller} objects, they * should never be shared with untrusted code. * * @since 9 + * @spec JPMS */ public static final class Controller { private final Layer layer; @@ -281,10 +284,8 @@ public final class Layer { * If the parent of the given configuration is not the configuration * for this layer * @throws LayerInstantiationException - * If all modules cannot be defined to the same class loader for any - * of the reasons listed above or the layer cannot be created because - * the configuration contains a module named "{@code java.base}" or - * a module with a package name starting with "{@code java.}" + * If the layer cannot be created for any of the reasons specified + * by the static {@code defineModulesWithOneLoader} method * @throws SecurityException * If {@code RuntimePermission("createClassLoader")} or * {@code RuntimePermission("getClassLoader")} is denied by @@ -325,9 +326,8 @@ public final class Layer { * If the parent of the given configuration is not the configuration * for this layer * @throws LayerInstantiationException - * If the layer cannot be created because the configuration contains - * a module named "{@code java.base}" or a module with a package - * name starting with "{@code java.}" + * If the layer cannot be created for any of the reasons specified + * by the static {@code defineModulesWithManyLoaders} method * @throws SecurityException * If {@code RuntimePermission("createClassLoader")} or * {@code RuntimePermission("getClassLoader")} is denied by @@ -365,14 +365,8 @@ public final class Layer { * If the parent of the given configuration is not the configuration * for this layer * @throws LayerInstantiationException - * If creating the {@code Layer} fails for any of the reasons - * listed above, the layer cannot be created because the - * configuration contains a module named "{@code java.base}", - * a module with a package name starting with "{@code java.}" is - * mapped to a class loader other than the {@link - * ClassLoader#getPlatformClassLoader() platform class loader}, - * or the function to map a module name to a class loader returns - * {@code null} + * If the layer cannot be created for any of the reasons specified + * by the static {@code defineModules} method * @throws SecurityException * If {@code RuntimePermission("getClassLoader")} is denied by * the security manager @@ -396,7 +390,6 @@ public final class Layer { * exported to one or more of the modules in this layer. The class * loader delegates to the class loader of the module, throwing {@code * ClassNotFoundException} if not found by that class loader. - * * When {@code loadClass} is invoked to load classes that do not map to a * module then it delegates to the parent class loader.

    * @@ -414,6 +407,10 @@ public final class Layer { * * * + *

    In addition, a layer cannot be created if the configuration contains + * a module named "{@code java.base}" or a module with a package name + * starting with "{@code java.}".

    + * *

    If there is a security manager then the class loader created by * this method will load classes and resources with privileges that are * restricted by the calling context of this method.

    @@ -433,9 +430,7 @@ public final class Layer { * the parent layers, including order * @throws LayerInstantiationException * If all modules cannot be defined to the same class loader for any - * of the reasons listed above or the layer cannot be created because - * the configuration contains a module named "{@code java.base}" or - * a module with a package name starting with "{@code java.}" + * of the reasons listed above * @throws SecurityException * If {@code RuntimePermission("createClassLoader")} or * {@code RuntimePermission("getClassLoader")} is denied by @@ -480,7 +475,6 @@ public final class Layer { * module in a parent layer. The class loader delegates to the class loader * of the module, throwing {@code ClassNotFoundException} if not found by * that class loader. - * * When {@code loadClass} is invoked to load classes that do not map to a * module then it delegates to the parent class loader.

    * @@ -533,15 +527,19 @@ public final class Layer { /** * Creates a new layer by defining the modules in the given {@code - * Configuration} to the Java virtual machine. - * Each module is mapped, by name, to its class loader by means of the - * given function. The class loader delegation implemented by these class - * loaders must respect module readability. The class loaders should be + * Configuration} to the Java virtual machine. The given function maps each + * module in the configuration, by name, to a class loader. Creating the + * layer informs the Java virtual machine about the classes that may be + * loaded so that the Java virtual machine knows which module that each + * class is a member of. + * + *

    The class loader delegation implemented by the class loaders must + * respect module readability. The class loaders should be * {@link ClassLoader#registerAsParallelCapable parallel-capable} so as to * avoid deadlocks during class loading. In addition, the entity creating - * a new layer with this method should arrange that the class loaders are + * a new layer with this method should arrange that the class loaders be * ready to load from these modules before there are any attempts to load - * classes or resources. + * classes or resources.

    * *

    Creating a {@code Layer} can fail for the following reasons:

    * @@ -558,6 +556,13 @@ public final class Layer { * * * + *

    In addition, a layer cannot be created if the configuration contains + * a module named "{@code java.base}", a configuration contains a module + * with a package name starting with "{@code java.}" is mapped to a class + * loader other than the {@link ClassLoader#getPlatformClassLoader() + * platform class loader}, or the function to map a module name to a class + * loader returns {@code null}.

    + * *

    If the function to map a module name to class loader throws an error * or runtime exception then it is propagated to the caller of this method. *

    @@ -565,7 +570,7 @@ public final class Layer { * @apiNote It is implementation specific as to whether creating a Layer * with this method is an atomic operation or not. Consequentially it is * possible for this method to fail with some modules, but not all, defined - * to Java virtual machine. + * to the Java virtual machine. * * @param cf * The configuration for the layer @@ -580,14 +585,7 @@ public final class Layer { * If the parent configurations do not match the configuration of * the parent layers, including order * @throws LayerInstantiationException - * If creating the {@code Layer} fails for any of the reasons - * listed above, the layer cannot be created because the - * configuration contains a module named "{@code java.base}", - * a module with a package name starting with "{@code java.}" is - * mapped to a class loader other than the {@link - * ClassLoader#getPlatformClassLoader() platform class loader}, - * or the function to map a module name to a class loader returns - * {@code null} + * If creating the layer fails for any of the reasons listed above * @throws SecurityException * If {@code RuntimePermission("getClassLoader")} is denied by * the security manager @@ -763,7 +761,7 @@ public final class Layer { /** * Returns the module with the given name in this layer, or if not in this - * layer, the {@linkplain #parents parents} layers. Finding a module in + * layer, the {@linkplain #parents parent} layers. Finding a module in * parent layers is equivalent to invoking {@code findModule} on each * parent, in search order, until the module is found or all parents have * been searched. In a tree of layers then this is equivalent to diff --git a/jdk/src/java.base/share/classes/java/lang/reflect/LayerInstantiationException.java b/jdk/src/java.base/share/classes/java/lang/reflect/LayerInstantiationException.java index ff61c41590f..fbd0de0ac85 100644 --- a/jdk/src/java.base/share/classes/java/lang/reflect/LayerInstantiationException.java +++ b/jdk/src/java.base/share/classes/java/lang/reflect/LayerInstantiationException.java @@ -31,6 +31,7 @@ package java.lang.reflect; * @see Layer * * @since 9 + * @spec JPMS */ public class LayerInstantiationException extends RuntimeException { private static final long serialVersionUID = -906239691613568347L; diff --git a/jdk/src/java.base/share/classes/java/lang/reflect/Method.java b/jdk/src/java.base/share/classes/java/lang/reflect/Method.java index 027a711d3e1..2208a5cbd81 100644 --- a/jdk/src/java.base/share/classes/java/lang/reflect/Method.java +++ b/jdk/src/java.base/share/classes/java/lang/reflect/Method.java @@ -179,6 +179,10 @@ public final class Method extends Executable { return res; } + /** + * @throws InaccessibleObjectException {@inheritDoc} + * @throws SecurityException {@inheritDoc} + */ @Override @CallerSensitive public void setAccessible(boolean flag) { diff --git a/jdk/src/java.base/share/classes/java/lang/reflect/Module.java b/jdk/src/java.base/share/classes/java/lang/reflect/Module.java index 5134b64caf8..e70d9fbb872 100644 --- a/jdk/src/java.base/share/classes/java/lang/reflect/Module.java +++ b/jdk/src/java.base/share/classes/java/lang/reflect/Module.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2017, 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 @@ -39,7 +39,6 @@ import java.net.URI; import java.net.URL; import java.security.AccessController; import java.security.PrivilegedAction; -import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.Map; @@ -74,16 +73,15 @@ import sun.security.util.SecurityConstants; * Java Virtual Machine when a graph of modules is defined to the Java virtual * machine to create a module {@link Layer Layer}.

    * - *

    An unnamed module does not have a name. There is an unnamed module - * per {@link ClassLoader ClassLoader} that is obtained by invoking the class - * loader's {@link ClassLoader#getUnnamedModule() getUnnamedModule} method. The - * {@link Class#getModule() getModule} method of all types defined by a class - * loader that are not in a named module return the class loader's unnamed + *

    An unnamed module does not have a name. There is an unnamed module for + * each {@link ClassLoader ClassLoader}, obtained by invoking its {@link + * ClassLoader#getUnnamedModule() getUnnamedModule} method. All types that are + * not in a named module are members of their defining class loader's unnamed * module.

    * *

    The package names that are parameters or returned by methods defined in * this class are the fully-qualified names of the packages as defined in - * section 6.5.3 of The Java™ Language Specification , for + * section 6.5.3 of The Java™ Language Specification, for * example, {@code "java.lang"}.

    * *

    Unless otherwise specified, passing a {@code null} argument to a method @@ -91,6 +89,7 @@ import sun.security.util.SecurityConstants; * be thrown.

    * * @since 9 + * @spec JPMS * @see java.lang.Class#getModule */ @@ -327,8 +326,9 @@ public final class Module implements AnnotatedElement { * * @return this module * - * @throws IllegalStateException - * If this is a named module and the caller is not this module + * @throws IllegalCallerException + * If this is a named module and the caller's module is not this + * module * * @see #canRead */ @@ -338,7 +338,7 @@ public final class Module implements AnnotatedElement { if (this.isNamed()) { Module caller = Reflection.getCallerClass().getModule(); if (caller != this) { - throw new IllegalStateException(caller + " != " + this); + throw new IllegalCallerException(caller + " != " + this); } implAddReads(other, true); } @@ -533,8 +533,8 @@ public final class Module implements AnnotatedElement { if (other == this && containsPackage(pn)) return true; - // all packages in open modules are open - if (descriptor.isOpen()) + // all packages in open and automatic modules are open + if (descriptor.isOpen() || descriptor.isAutomatic()) return containsPackage(pn); // exported/opened via module declaration/descriptor @@ -634,8 +634,7 @@ public final class Module implements AnnotatedElement { * the given package to the given module. * *

    This method has no effect if the package is already exported (or - * open) to the given module. It also has no effect if - * invoked on an {@link ModuleDescriptor#isOpen open} module.

    + * open) to the given module.

    * * @apiNote As specified in section 5.4.3 of the The Java™ * Virtual Machine Specification , if an attempt to resolve a @@ -653,8 +652,9 @@ public final class Module implements AnnotatedElement { * @throws IllegalArgumentException * If {@code pn} is {@code null}, or this is a named module and the * package {@code pn} is not a package in this module - * @throws IllegalStateException - * If this is a named module and the caller is not this module + * @throws IllegalCallerException + * If this is a named module and the caller's module is not this + * module * * @jvms 5.4.3 Resolution * @see #isExported(String,Module) @@ -665,10 +665,10 @@ public final class Module implements AnnotatedElement { throw new IllegalArgumentException("package is null"); Objects.requireNonNull(other); - if (isNamed() && !descriptor.isOpen()) { + if (isNamed()) { Module caller = Reflection.getCallerClass().getModule(); if (caller != this) { - throw new IllegalStateException(caller + " != " + this); + throw new IllegalCallerException(caller + " != " + this); } implAddExportsOrOpens(pn, other, /*open*/false, /*syncVM*/true); } @@ -686,8 +686,7 @@ public final class Module implements AnnotatedElement { * access control checks. * *

    This method has no effect if the package is already open - * to the given module. It also has no effect if invoked on an {@link - * ModuleDescriptor#isOpen open} module.

    + * to the given module.

    * * @param pn * The package name @@ -699,9 +698,9 @@ public final class Module implements AnnotatedElement { * @throws IllegalArgumentException * If {@code pn} is {@code null}, or this is a named module and the * package {@code pn} is not a package in this module - * @throws IllegalStateException + * @throws IllegalCallerException * If this is a named module and this module has not opened the - * package to at least the caller + * package to at least the caller's module * * @see #isOpen(String,Module) * @see AccessibleObject#setAccessible(boolean) @@ -713,10 +712,10 @@ public final class Module implements AnnotatedElement { throw new IllegalArgumentException("package is null"); Objects.requireNonNull(other); - if (isNamed() && !descriptor.isOpen()) { + if (isNamed()) { Module caller = Reflection.getCallerClass().getModule(); if (caller != this && !isOpen(pn, caller)) - throw new IllegalStateException(pn + " is not open to " + caller); + throw new IllegalCallerException(pn + " is not open to " + caller); implAddExportsOrOpens(pn, other, /*open*/true, /*syncVM*/true); } @@ -767,8 +766,8 @@ public final class Module implements AnnotatedElement { Objects.requireNonNull(other); Objects.requireNonNull(pn); - // all packages are open in unnamed and open modules - if (!isNamed() || descriptor.isOpen()) + // all packages are open in unnamed, open, and automatic modules + if (!isNamed() || descriptor.isOpen() || descriptor.isAutomatic()) return; // nothing to do if already exported/open to other @@ -819,17 +818,17 @@ public final class Module implements AnnotatedElement { * passed a reference to the service type by other code. This method is * a no-op when invoked on an unnamed module or an automatic module. * - *

    This method does not cause {@link - * Configuration#resolveRequiresAndUses resolveRequiresAndUses} to be - * re-run.

    + *

    This method does not cause {@link Configuration#resolveAndBind + * resolveAndBind} to be re-run.

    * * @param service * The service type * * @return this module * - * @throws IllegalStateException - * If this is a named module and the caller is not this module + * @throws IllegalCallerException + * If this is a named module and the caller's module is not this + * module * * @see #canUse(Class) * @see ModuleDescriptor#uses() @@ -841,7 +840,7 @@ public final class Module implements AnnotatedElement { if (isNamed() && !descriptor.isAutomatic()) { Module caller = Reflection.getCallerClass().getModule(); if (caller != this) { - throw new IllegalStateException(caller + " != " + this); + throw new IllegalCallerException(caller + " != " + this); } implAddUses(service); } @@ -894,14 +893,13 @@ public final class Module implements AnnotatedElement { // -- packages -- // Additional packages that are added to the module at run-time. - // The field is volatile as it may be replaced at run-time - private volatile Set extraPackages; + private volatile Map extraPackages; private boolean containsPackage(String pn) { if (descriptor.packages().contains(pn)) return true; - Set extraPackages = this.extraPackages; - if (extraPackages != null && extraPackages.contains(pn)) + Map extraPackages = this.extraPackages; + if (extraPackages != null && extraPackages.containsKey(pn)) return true; return false; } @@ -915,7 +913,7 @@ public final class Module implements AnnotatedElement { * added to the module, dynamic modules * for example, after it was loaded. * - *

    For unnamed modules, this method is the equivalent of invoking the + *

    For unnamed modules, this method is the equivalent to invoking the * {@link ClassLoader#getDefinedPackages() getDefinedPackages} method of * this module's class loader and returning the array of package names.

    * @@ -930,12 +928,12 @@ public final class Module implements AnnotatedElement { if (isNamed()) { Set packages = descriptor.packages(); - Set extraPackages = this.extraPackages; + Map extraPackages = this.extraPackages; if (extraPackages == null) { return packages.toArray(new String[0]); } else { return Stream.concat(packages.stream(), - extraPackages.stream()) + extraPackages.keySet().stream()) .toArray(String[]::new); } @@ -955,10 +953,6 @@ public final class Module implements AnnotatedElement { * Add a package to this module. * * @apiNote This method is for Proxy use. - * - * @apiNote This is an expensive operation, not expected to be used often. - * At this time then it does not validate that the package name is a - * valid java identifier. */ void addPackage(String pn) { implAddPackage(pn, true); @@ -976,49 +970,52 @@ public final class Module implements AnnotatedElement { /** * Add a package to this module. * - * If {@code syncVM} is {@code true} then the VM is notified. + * If {@code syncVM} is {@code true} then the VM is notified. This method is + * a no-op if this is an unnamed module or the module already contains the + * package. + * + * @throws IllegalArgumentException if the package name is not legal + * @throws IllegalStateException if the package is defined to another module */ private void implAddPackage(String pn, boolean syncVM) { + // no-op if unnamed module if (!isNamed()) - throw new InternalError("adding package to unnamed module?"); - if (descriptor.isOpen()) - throw new InternalError("adding package to open module?"); + return; + + // no-op if module contains the package + if (containsPackage(pn)) + return; + + // check package name is legal for named modules if (pn.isEmpty()) - throw new InternalError("adding package to module?"); - - if (descriptor.packages().contains(pn)) { - // already in module - return; - } - - Set extraPackages = this.extraPackages; - if (extraPackages != null && extraPackages.contains(pn)) { - // already added - return; - } - synchronized (this) { - // recheck under lock - extraPackages = this.extraPackages; - if (extraPackages != null) { - if (extraPackages.contains(pn)) { - // already added - return; - } - - // copy the set - extraPackages = new HashSet<>(extraPackages); - extraPackages.add(pn); - } else { - extraPackages = Collections.singleton(pn); + throw new IllegalArgumentException("Cannot add package"); + for (int i=0; i extraPackages = this.extraPackages; + if (extraPackages == null) { + synchronized (this) { + extraPackages = this.extraPackages; + if (extraPackages == null) + this.extraPackages = extraPackages = new ConcurrentHashMap<>(); + } + } + + // update VM first in case it fails. This is a no-op if another thread + // beats us to add the package first + if (syncVM) { + // throws IllegalStateException if defined to another module + addPackage0(this, pn); + if (descriptor.isOpen() || descriptor.isAutomatic()) { + addExportsToAll0(this, pn); + } + } + extraPackages.putIfAbsent(pn, Boolean.TRUE); } @@ -1169,8 +1166,9 @@ public final class Module implements AnnotatedElement { Map nameToModule, Module m) { - // The VM doesn't know about open modules so need to export all packages - if (descriptor.isOpen()) { + // The VM doesn't special case open or automatic modules so need to + // export all packages + if (descriptor.isOpen() || descriptor.isAutomatic()) { assert descriptor.opens().isEmpty(); for (String source : descriptor.packages()) { addExportsToAll0(m, source); @@ -1375,35 +1373,44 @@ public final class Module implements AnnotatedElement { /** - * Returns an input stream for reading a resource in this module. The - * {@code name} parameter is a {@code '/'}-separated path name that - * identifies the resource. + * Returns an input stream for reading a resource in this module. + * The {@code name} parameter is a {@code '/'}-separated path name that + * identifies the resource. As with {@link Class#getResourceAsStream + * Class.getResourceAsStream}, this method delegates to the module's class + * loader {@link ClassLoader#findResource(String,String) + * findResource(String,String)} method, invoking it with the module name + * (or {@code null} when the module is unnamed) and the name of the + * resource. If the resource name has a leading slash then it is dropped + * before delegation. * - *

    A resource in a named modules may be encapsulated so that + *

    A resource in a named module may be encapsulated so that * it cannot be located by code in other modules. Whether a resource can be - * located or not is determined as follows: + * located or not is determined as follows:

    * *
      - *
    • The package name of the resource is derived from the - * subsequence of characters that precedes the last {@code '/'} and then - * replacing each {@code '/'} character in the subsequence with - * {@code '.'}. For example, the package name derived for a resource - * named "{@code a/b/c/foo.properties}" is "{@code a.b.c}".
    • + *
    • If the resource name ends with "{@code .class}" then it is not + * encapsulated.
    • * - *
    • If the package name is a package in the module then the package - * must be {@link #isOpen open} the module of the caller of this method. - * If the package is not in the module then the resource is not - * encapsulated. Resources in the unnamed package or "{@code META-INF}", - * for example, are never encapsulated because they can never be - * packages in a named module.
    • - * - *
    • As a special case, resources ending with "{@code .class}" are - * never encapsulated.
    • + *
    • A package name is derived from the resource name. If + * the package name is a {@link #getPackages() package} in the module + * then the resource can only be located by the caller of this method + * when the package is {@link #isOpen(String,Module) open} to at least + * the caller's module. If the resource is not in a package in the module + * then the resource is not encapsulated.
    • *
    * + *

    In the above, the package name for a resource is derived + * from the subsequence of characters that precedes the last {@code '/'} in + * the name and then replacing each {@code '/'} character in the subsequence + * with {@code '.'}. A leading slash is ignored when deriving the package + * name. As an example, the package name derived for a resource named + * "{@code a/b/c/foo.properties}" is "{@code a.b.c}". A resource name + * with the name "{@code META-INF/MANIFEST.MF}" is never encapsulated + * because "{@code META-INF}" is not a legal package name.

    + * *

    This method returns {@code null} if the resource is not in this * module, the resource is encapsulated and cannot be located by the caller, - * or access to the resource is denied by the security manager. + * or access to the resource is denied by the security manager.

    * * @param name * The resource name @@ -1413,11 +1420,13 @@ public final class Module implements AnnotatedElement { * @throws IOException * If an I/O error occurs * - * @see java.lang.module.ModuleReader#open(String) + * @see Class#getResourceAsStream(String) */ @CallerSensitive public InputStream getResourceAsStream(String name) throws IOException { - Objects.requireNonNull(name); + if (name.startsWith("/")) { + name = name.substring(1); + } if (isNamed() && !ResourceHelper.isSimpleResource(name)) { Module caller = Reflection.getCallerClass().getModule(); diff --git a/jdk/src/java.base/share/classes/java/lang/reflect/Proxy.java b/jdk/src/java.base/share/classes/java/lang/reflect/Proxy.java index 15d41a4101d..685aebff39a 100644 --- a/jdk/src/java.base/share/classes/java/lang/reflect/Proxy.java +++ b/jdk/src/java.base/share/classes/java/lang/reflect/Proxy.java @@ -25,6 +25,7 @@ package java.lang.reflect; +import java.lang.module.ModuleDescriptor; import java.security.AccessController; import java.security.PrivilegedAction; import java.util.Arrays; @@ -52,6 +53,9 @@ import sun.reflect.misc.ReflectUtil; import sun.security.action.GetPropertyAction; import sun.security.util.SecurityConstants; +import static java.lang.module.ModuleDescriptor.Modifier.SYNTHETIC; + + /** * * {@code Proxy} provides static methods for creating objects that act like instances @@ -164,7 +168,8 @@ import sun.security.util.SecurityConstants; * methods is specified as follows: * *
      - *
    1. If all the proxy interfaces are in exported packages: + *
    2. If all the proxy interfaces are in exported or open + * packages: *
        *
      1. if all the proxy interfaces are public, then the proxy class is * public in a package exported by the @@ -178,10 +183,11 @@ import sun.security.util.SecurityConstants; * not possible.
      2. *
      *
    3. - *
    4. If at least one proxy interface is a non-exported package: + *
    5. If at least one proxy interface is in a package that is + * non-exported and non-open: *
        *
      1. if all the proxy interfaces are public, then the proxy class is - * public in a non-exported package of + * public in a non-exported, non-open package of * dynamic module. * The names of the package and the module are unspecified.
      2. * @@ -195,21 +201,22 @@ import sun.security.util.SecurityConstants; *
      * *

      - * Note that if proxy interfaces with a mix of accessibilities -- - * exported public, exported non-public, non-exported public, non-exported non-public -- - * are proxied by the same instance, then the proxy class's accessibility is + * Note that if proxy interfaces with a mix of accessibilities -- for example, + * an exported public interface and a non-exported non-public interface -- are + * proxied by the same instance, then the proxy class's accessibility is * governed by the least accessible proxy interface. *

      * Note that it is possible for arbitrary code to obtain access to a proxy class - * in an exported package with {@link AccessibleObject#setAccessible setAccessible}, - * whereas a proxy class in a non-exported package is never accessible to + * in an open package with {@link AccessibleObject#setAccessible setAccessible}, + * whereas a proxy class in a non-open package is never accessible to * code outside the module of the proxy class. * *

      - * Throughout this specification, a "non-exported package" refers to a package that - * is not exported to all modules. Specifically, it refers to a package that - * either is not exported at all by its containing module or is exported in a - * qualified fashion by its containing module. + * Throughout this specification, a "non-exported package" refers to a package + * that is not exported to all modules, and a "non-open package" refers to + * a package that is not open to all modules. Specifically, these terms refer to + * a package that either is not exported/open by its containing module or is + * exported/open in a qualified fashion by its containing module. * *

      Dynamic Modules

      *

      @@ -272,6 +279,8 @@ import sun.security.util.SecurityConstants; * @author Peter Jones * @see InvocationHandler * @since 1.3 + * @revised 9 + * @spec JPMS */ public class Proxy implements java.io.Serializable { private static final long serialVersionUID = -2222568056686623797L; @@ -358,6 +367,8 @@ public class Proxy implements java.io.Serializable { * to create a proxy instance instead. * * @see Package and Module Membership of Proxy Class + * @revised 9 + * @spec JPMS */ @Deprecated @CallerSensitive @@ -855,7 +866,11 @@ public class Proxy implements java.io.Serializable { // create a dynamic module and setup module access String mn = "jdk.proxy" + counter.incrementAndGet(); String pn = PROXY_PACKAGE_PREFIX + "." + mn; - Module m = Modules.defineModule(ld, mn, Collections.singleton(pn)); + ModuleDescriptor descriptor = + ModuleDescriptor.newModule(mn, Set.of(SYNTHETIC)) + .packages(Set.of(pn)) + .build(); + Module m = Modules.defineModule(ld, descriptor, null); Modules.addReads(m, Proxy.class.getModule()); // java.base to create proxy instance Modules.addExports(m, pn, Object.class.getModule()); @@ -955,6 +970,8 @@ public class Proxy implements java.io.Serializable { * {@code null} * * @see Package and Module Membership of Proxy Class + * @revised 9 + * @spec JPMS */ @CallerSensitive public static Object newProxyInstance(ClassLoader loader, @@ -1039,6 +1056,9 @@ public class Proxy implements java.io.Serializable { * @return {@code true} if the class is a proxy class and * {@code false} otherwise * @throws NullPointerException if {@code cl} is {@code null} + * + * @revised 9 + * @spec JPMS */ public static boolean isProxyClass(Class cl) { return Proxy.class.isAssignableFrom(cl) && ProxyBuilder.isProxyClass(cl); diff --git a/jdk/src/java.base/share/classes/java/lang/reflect/package-info.java b/jdk/src/java.base/share/classes/java/lang/reflect/package-info.java index c8cb0257b2a..97800b1ce13 100644 --- a/jdk/src/java.base/share/classes/java/lang/reflect/package-info.java +++ b/jdk/src/java.base/share/classes/java/lang/reflect/package-info.java @@ -45,5 +45,7 @@ * members declared by a given class. * * @since 1.1 + * @revised 9 + * @spec JPMS */ package java.lang.reflect; diff --git a/jdk/src/java.base/share/classes/java/net/URLClassLoader.java b/jdk/src/java.base/share/classes/java/net/URLClassLoader.java index 2e52fe2b4e9..d6bd9546750 100644 --- a/jdk/src/java.base/share/classes/java/net/URLClassLoader.java +++ b/jdk/src/java.base/share/classes/java/net/URLClassLoader.java @@ -228,6 +228,7 @@ public class URLClassLoader extends SecureClassLoader implements Closeable { * allow creation of a class loader. * * @since 9 + * @spec JPMS */ public URLClassLoader(String name, URL[] urls, @@ -262,6 +263,7 @@ public class URLClassLoader extends SecureClassLoader implements Closeable { * creation of a class loader. * * @since 9 + * @spec JPMS */ public URLClassLoader(String name, URL[] urls, ClassLoader parent, URLStreamHandlerFactory factory) { @@ -558,6 +560,9 @@ public class URLClassLoader extends SecureClassLoader implements Closeable { * @throws IllegalArgumentException if the package name is * already defined by this class loader * @return the newly defined {@code Package} object + * + * @revised 9 + * @spec JPMS */ protected Package definePackage(String name, Manifest man, URL url) { String path = name.replace('.', '/').concat("/"); diff --git a/jdk/src/java.base/share/classes/java/security/SecureClassLoader.java b/jdk/src/java.base/share/classes/java/security/SecureClassLoader.java index 8f84e10324e..4f0bfa4c27f 100644 --- a/jdk/src/java.base/share/classes/java/security/SecureClassLoader.java +++ b/jdk/src/java.base/share/classes/java/security/SecureClassLoader.java @@ -125,6 +125,7 @@ public class SecureClassLoader extends ClassLoader { * doesn't allow creation of a class loader. * * @since 9 + * @spec JPMS */ protected SecureClassLoader(String name, ClassLoader parent) { super(name, parent); diff --git a/jdk/src/java.base/share/classes/java/security/Security.java b/jdk/src/java.base/share/classes/java/security/Security.java index 49b7e991b40..1076b1d7da7 100644 --- a/jdk/src/java.base/share/classes/java/security/Security.java +++ b/jdk/src/java.base/share/classes/java/security/Security.java @@ -25,11 +25,12 @@ package java.security; -import java.lang.reflect.*; import java.util.*; import java.util.concurrent.ConcurrentHashMap; import java.io.*; import java.net.URL; + +import jdk.internal.misc.SharedSecrets; import sun.security.util.Debug; import sun.security.util.PropertyExpander; @@ -800,9 +801,6 @@ public final class Security { * "package.definition", we need to signal to the SecurityManager * class that the value has just changed, and that it should * invalidate it's local cache values. - * - * Rather than create a new API entry for this function, - * we use reflection to set a private variable. */ private static void invalidateSMCache(String key) { @@ -810,42 +808,8 @@ public final class Security { final boolean pd = key.equals("package.definition"); if (pa || pd) { - AccessController.doPrivileged(new PrivilegedAction<>() { - public Void run() { - try { - /* Get the class via the bootstrap class loader. */ - Class cl = Class.forName( - "java.lang.SecurityManager", false, null); - Field f = null; - boolean accessible = false; - - if (pa) { - f = cl.getDeclaredField("packageAccessValid"); - accessible = f.isAccessible(); - f.setAccessible(true); - } else { - f = cl.getDeclaredField("packageDefinitionValid"); - accessible = f.isAccessible(); - f.setAccessible(true); - } - f.setBoolean(f, false); - f.setAccessible(accessible); - } - catch (Exception e1) { - /* If we couldn't get the class, it hasn't - * been loaded yet. If there is no such - * field, we shouldn't try to set it. There - * shouldn't be a security execption, as we - * are loaded by boot class loader, and we - * are inside a doPrivileged() here. - * - * NOOP: don't do anything... - */ - } - return null; - } /* run */ - }); /* PrivilegedAction */ - } /* if */ + SharedSecrets.getJavaLangAccess().invalidatePackageAccessCache(); + } } private static void check(String directive) { diff --git a/jdk/src/java.base/share/classes/java/util/ResourceBundle.java b/jdk/src/java.base/share/classes/java/util/ResourceBundle.java index 600b1810a2e..b587da9b9e3 100644 --- a/jdk/src/java.base/share/classes/java/util/ResourceBundle.java +++ b/jdk/src/java.base/share/classes/java/util/ResourceBundle.java @@ -350,6 +350,8 @@ import static sun.security.util.SecurityConstants.GET_CLASSLOADER_PERMISSION; * @see MissingResourceException * @see ResourceBundleProvider * @since 1.1 + * @revised 9 + * @spec JPMS */ public abstract class ResourceBundle { @@ -870,6 +872,8 @@ public abstract class ResourceBundle { * @throws UnsupportedOperationException * if this method is called in a named module * @since 1.6 + * @revised 9 + * @spec JPMS */ @CallerSensitive public static final ResourceBundle getBundle(String baseName, @@ -938,6 +942,7 @@ public abstract class ResourceBundle { * specified module * @return a resource bundle for the given base name and the default locale * @since 9 + * @spec JPMS * @see ResourceBundleProvider */ @CallerSensitive @@ -991,6 +996,7 @@ public abstract class ResourceBundle { * be found in the specified {@code module} * @return a resource bundle for the given base name and locale in the module * @since 9 + * @spec JPMS */ @CallerSensitive public static ResourceBundle getBundle(String baseName, Locale targetLocale, Module module) { @@ -1036,6 +1042,8 @@ public abstract class ResourceBundle { * @throws UnsupportedOperationException * if this method is called in a named module * @since 1.6 + * @revised 9 + * @spec JPMS */ @CallerSensitive public static final ResourceBundle getBundle(String baseName, Locale targetLocale, @@ -1243,6 +1251,8 @@ public abstract class ResourceBundle { * @exception MissingResourceException * if no resource bundle for the specified base name can be found * @since 1.2 + * @revised 9 + * @spec JPMS */ @CallerSensitive public static ResourceBundle getBundle(String baseName, Locale locale, @@ -1465,6 +1475,8 @@ public abstract class ResourceBundle { * @throws UnsupportedOperationException * if this method is called in a named module * @since 1.6 + * @revised 9 + * @spec JPMS */ @CallerSensitive public static ResourceBundle getBundle(String baseName, Locale targetLocale, @@ -2194,6 +2206,8 @@ public abstract class ResourceBundle { * by the caller's module. * * @since 1.6 + * @revised 9 + * @spec JPMS * @see ResourceBundle.Control#getTimeToLive(String,Locale) */ @CallerSensitive @@ -2475,6 +2489,8 @@ public abstract class ResourceBundle { * of {@link ResourceBundleControlProvider} are ignored in named modules. * * @since 1.6 + * @revised 9 + * @spec JPMS * @see java.util.spi.ResourceBundleProvider */ public static class Control { @@ -3103,6 +3119,8 @@ public abstract class ResourceBundle { * if an error occurred when reading resources using * any I/O operations * @see java.util.spi.ResourceBundleProvider#getBundle(String, Locale) + * @revised 9 + * @spec JPMS */ public ResourceBundle newBundle(String baseName, Locale locale, String format, ClassLoader loader, boolean reload) diff --git a/jdk/src/java.base/share/classes/java/util/ServiceLoader.java b/jdk/src/java.base/share/classes/java/util/ServiceLoader.java index 0b437d44e2e..6ffb6177e39 100644 --- a/jdk/src/java.base/share/classes/java/util/ServiceLoader.java +++ b/jdk/src/java.base/share/classes/java/util/ServiceLoader.java @@ -119,7 +119,7 @@ import jdk.internal.reflect.Reflection; * and deployed as an explicit module must have an appropriate uses * clause in its module descriptor to declare that the module uses * implementations of the service. A corresponding requirement is that a - * provider deployed as a named module must have an appropriate + * provider deployed as an explicit module must have an appropriate * provides clause in its module descriptor to declare that the module * provides an implementation of the service. The uses and * provides allow consumers of a service to be linked to modules @@ -203,8 +203,11 @@ import jdk.internal.reflect.Reflection; * ordering of modules in a layer, is not defined.

    6. * *
    7. If a named module declares more than one provider then the providers - * are located in the order that they appear in the {@code provides} table of - * the {@code Module} class file attribute ({@code module-info.class}).
    8. + * are located in the iteration order of the {@link + * java.lang.module.ModuleDescriptor.Provides#providers() providers} list. + * Providers added dynamically by instrumentation agents ({@link + * java.lang.instrument.Instrumentation#redefineModule redefineModule}) + * are always located after providers declared by the module. * *
    9. When locating providers in unnamed modules then the ordering is * based on the order that the class loader's {@link @@ -335,6 +338,8 @@ import jdk.internal.reflect.Reflection; * * @author Mark Reinhold * @since 1.6 + * @revised 9 + * @spec JPMS */ public final class ServiceLoader @@ -386,6 +391,7 @@ public final class ServiceLoader * * @param The service type * @since 9 + * @spec JPMS */ public static interface Provider extends Supplier { /** @@ -927,26 +933,28 @@ public final class ServiceLoader } else { catalog = ServicesCatalog.getServicesCatalogOrNull(loader); } - Stream stream1; + List providers; if (catalog == null) { - stream1 = Stream.empty(); + providers = List.of(); } else { - stream1 = catalog.findServices(serviceName).stream(); + providers = catalog.findServices(serviceName); } // modules in custom layers that define modules to the class loader - Stream stream2; if (loader == null) { - stream2 = Stream.empty(); + return providers.iterator(); } else { + List allProviders = new ArrayList<>(providers); Layer bootLayer = Layer.boot(); - stream2 = JLRM_ACCESS.layers(loader) - .filter(l -> (l != bootLayer)) - .map(l -> providers(l)) - .flatMap(List::stream); + Iterator iterator = JLRM_ACCESS.layers(loader).iterator(); + while (iterator.hasNext()) { + Layer layer = iterator.next(); + if (layer != bootLayer) { + allProviders.addAll(providers(layer)); + } + } + return allProviders.iterator(); } - - return Stream.concat(stream1, stream2).iterator(); } @Override @@ -1214,6 +1222,9 @@ public final class ServiceLoader * * @return An iterator that lazily loads providers for this loader's * service + * + * @revised 9 + * @spec JPMS */ public Iterator iterator() { @@ -1279,8 +1290,10 @@ public final class ServiceLoader * provider to be loaded.

      * *

      If this loader's provider caches are cleared by invoking the {@link - * #reload() reload} method then existing streams for this service - * loader should be discarded.

      + * #reload() reload} method then existing streams for this service loader + * should be discarded. The returned stream's source {@code Spliterator} is + * fail-fast and will throw {@link ConcurrentModificationException} + * if the provider cache has been cleared.

      * *

      The following examples demonstrate usage. The first example * creates a stream of providers, the second example is the same except @@ -1300,6 +1313,7 @@ public final class ServiceLoader * @return A stream that lazily loads providers for this loader's service * * @since 9 + * @spec JPMS */ public Stream> stream() { // use cached providers as the source when all providers loaded @@ -1414,6 +1428,9 @@ public final class ServiceLoader * if the service type is not accessible to the caller or the * caller is in an explicit module and its module descriptor does * not declare that it uses {@code service} + * + * @revised 9 + * @spec JPMS */ @CallerSensitive public static ServiceLoader load(Class service, @@ -1457,6 +1474,9 @@ public final class ServiceLoader * if the service type is not accessible to the caller or the * caller is in an explicit module and its module descriptor does * not declare that it uses {@code service} + * + * @revised 9 + * @spec JPMS */ @CallerSensitive public static ServiceLoader load(Class service) { @@ -1490,6 +1510,9 @@ public final class ServiceLoader * if the service type is not accessible to the caller or the * caller is in an explicit module and its module descriptor does * not declare that it uses {@code service} + * + * @revised 9 + * @spec JPMS */ @CallerSensitive public static ServiceLoader loadInstalled(Class service) { @@ -1522,6 +1545,7 @@ public final class ServiceLoader * not declare that it uses {@code service} * * @since 9 + * @spec JPMS */ @CallerSensitive public static ServiceLoader load(Layer layer, Class service) { @@ -1551,6 +1575,7 @@ public final class ServiceLoader * or error is thrown when locating or instantiating the provider. * * @since 9 + * @spec JPMS */ public Optional findFirst() { Iterator iterator = iterator(); diff --git a/jdk/src/java.base/share/classes/java/util/spi/AbstractResourceBundleProvider.java b/jdk/src/java.base/share/classes/java/util/spi/AbstractResourceBundleProvider.java index 06b6c266c89..b0cba4f4915 100644 --- a/jdk/src/java.base/share/classes/java/util/spi/AbstractResourceBundleProvider.java +++ b/jdk/src/java.base/share/classes/java/util/spi/AbstractResourceBundleProvider.java @@ -81,6 +81,7 @@ import static sun.security.util.SecurityConstants.GET_CLASSLOADER_PERMISSION; * ResourceBundleProvider Service Providers * * @since 9 + * @spec JPMS */ public abstract class AbstractResourceBundleProvider implements ResourceBundleProvider { private static final JavaUtilResourceBundleAccess RB_ACCESS = diff --git a/jdk/src/java.base/share/classes/java/util/spi/ResourceBundleControlProvider.java b/jdk/src/java.base/share/classes/java/util/spi/ResourceBundleControlProvider.java index f74830b4d6a..871d9192ec0 100644 --- a/jdk/src/java.base/share/classes/java/util/spi/ResourceBundleControlProvider.java +++ b/jdk/src/java.base/share/classes/java/util/spi/ResourceBundleControlProvider.java @@ -44,6 +44,8 @@ import java.util.ResourceBundle; * * @author Masayoshi Okutsu * @since 1.8 + * @revised 9 + * @spec JPMS * @see ResourceBundle#getBundle(String, java.util.Locale, ClassLoader, ResourceBundle.Control) * ResourceBundle.getBundle * @see java.util.ServiceLoader#load(Class) diff --git a/jdk/src/java.base/share/classes/java/util/spi/ResourceBundleProvider.java b/jdk/src/java.base/share/classes/java/util/spi/ResourceBundleProvider.java index 0074ae32090..251831f1dcb 100644 --- a/jdk/src/java.base/share/classes/java/util/spi/ResourceBundleProvider.java +++ b/jdk/src/java.base/share/classes/java/util/spi/ResourceBundleProvider.java @@ -57,6 +57,7 @@ import java.util.ResourceBundle; * @see * ResourceBundleProvider Service Providers * @since 9 + * @spec JPMS */ public interface ResourceBundleProvider { /** diff --git a/jdk/src/java.base/share/classes/jdk/internal/jmod/JmodFile.java b/jdk/src/java.base/share/classes/jdk/internal/jmod/JmodFile.java index 34e99dfdd9b..289a80fdca6 100644 --- a/jdk/src/java.base/share/classes/jdk/internal/jmod/JmodFile.java +++ b/jdk/src/java.base/share/classes/jdk/internal/jmod/JmodFile.java @@ -186,7 +186,7 @@ public class JmodFile implements AutoCloseable { public Entry getEntry(Section section, String name) { String entry = section.jmodDir() + "/" + name; ZipEntry ze = zipfile.getEntry(entry); - return (ze != null) ? new Entry(ze) : null; + return (ze == null || ze.isDirectory()) ? null : new Entry(ze); } /** @@ -201,7 +201,7 @@ public class JmodFile implements AutoCloseable { { String entry = section.jmodDir() + "/" + name; ZipEntry e = zipfile.getEntry(entry); - if (e == null) { + if (e == null || e.isDirectory()) { throw new IOException(name + " not found: " + file); } return zipfile.getInputStream(e); diff --git a/jdk/src/java.base/share/classes/jdk/internal/loader/BuiltinClassLoader.java b/jdk/src/java.base/share/classes/jdk/internal/loader/BuiltinClassLoader.java index ab052ec0b30..a0886e82080 100644 --- a/jdk/src/java.base/share/classes/jdk/internal/loader/BuiltinClassLoader.java +++ b/jdk/src/java.base/share/classes/jdk/internal/loader/BuiltinClassLoader.java @@ -57,8 +57,9 @@ import java.util.jar.Attributes; import java.util.jar.Manifest; import java.util.stream.Stream; -import jdk.internal.module.ModulePatcher.PatchedModuleReader; import jdk.internal.misc.VM; +import jdk.internal.module.ModulePatcher.PatchedModuleReader; +import jdk.internal.module.SystemModules; /** @@ -135,7 +136,7 @@ public class BuiltinClassLoader // maps package name to loaded module for modules in the boot layer private static final Map packageToModule - = new ConcurrentHashMap<>(1024); + = new ConcurrentHashMap<>(SystemModules.PACKAGES_IN_BOOT_LAYER); // maps a module name to a module reference private final Map nameToModule; @@ -922,13 +923,13 @@ public class BuiltinClassLoader * Returns the ModuleReader for the given module. */ private ModuleReader moduleReaderFor(ModuleReference mref) { - return moduleToReader.computeIfAbsent(mref, m -> createModuleReader(mref)); + return moduleToReader.computeIfAbsent(mref, BuiltinClassLoader::createModuleReader); } /** * Creates a ModuleReader for the given module. */ - private ModuleReader createModuleReader(ModuleReference mref) { + private static ModuleReader createModuleReader(ModuleReference mref) { try { return mref.open(); } catch (IOException e) { diff --git a/jdk/src/java.base/share/classes/jdk/internal/loader/ResourceHelper.java b/jdk/src/java.base/share/classes/jdk/internal/loader/ResourceHelper.java index a9e0750391a..18a42b7b6f3 100644 --- a/jdk/src/java.base/share/classes/jdk/internal/loader/ResourceHelper.java +++ b/jdk/src/java.base/share/classes/jdk/internal/loader/ResourceHelper.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2017, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -24,6 +24,10 @@ */ package jdk.internal.loader; +import java.io.File; +import java.nio.file.Path; +import java.nio.file.Paths; + import jdk.internal.module.Checks; /** @@ -34,7 +38,8 @@ public final class ResourceHelper { private ResourceHelper() { } /** - * Returns the package name for a resource. + * Returns the package name for a resource or the empty package if + * the resource name does not contain a slash. */ public static String getPackageName(String name) { int index = name.lastIndexOf('/'); @@ -46,19 +51,75 @@ public final class ResourceHelper { } /** - * Returns true if the resource is a simple resource that can - * never be encapsulated. Resources ending in "{@code .class}" or where - * the package name is not a Java identifier are resources that can - * never be encapsulated. + * Returns true if the resource is a simple resource. Simple + * resources can never be encapsulated. Resources ending in "{@code .class}" + * or where the package name is not a legal package name can not be + * encapsulated. */ public static boolean isSimpleResource(String name) { int len = name.length(); if (len > 6 && name.endsWith(".class")) { return true; } - if (!Checks.isJavaIdentifier(getPackageName(name))) { + if (!Checks.isPackageName(getPackageName(name))) { return true; } return false; } + + /** + * Converts a resource name to a file path. Returns {@code null} if the + * resource name cannot be converted into a file path. Resource names + * with empty elements, or elements that are "." or ".." are rejected, + * as is a resource name that translates to a file path with a root + * component. + */ + public static Path toFilePath(String name) { + // scan the resource name to eagerly reject obviously invalid names + int next; + int off = 0; + while ((next = name.indexOf('/', off)) != -1) { + int len = next - off; + if (!mayTranslate(name, off, len)) { + return null; + } + off = next + 1; + } + int rem = name.length() - off; + if (!mayTranslate(name, off, rem)) { + return null; + } + + // convert to file path + Path path; + if (File.separatorChar == '/') { + path = Paths.get(name); + } else { + // not allowed to embed file separators + if (name.contains(File.separator)) + return null; + path = Paths.get(name.replace('/', File.separatorChar)); + } + + // file path not allowed to have root component + return (path.getRoot() == null) ? path : null; + } + + /** + * Returns {@code true} if the element in a resource name is a candidate + * to translate to the element of a file path. + */ + private static boolean mayTranslate(String name, int off, int len) { + if (len <= 2) { + if (len == 0) + return false; + boolean starsWithDot = (name.charAt(off) == '.'); + if (len == 1 && starsWithDot) + return false; + if (len == 2 && starsWithDot && (name.charAt(off+1) == '.')) + return false; + } + return true; + } + } diff --git a/jdk/src/java.base/share/classes/jdk/internal/misc/JavaLangAccess.java b/jdk/src/java.base/share/classes/jdk/internal/misc/JavaLangAccess.java index 6838111c35d..7cb2c1e74a4 100644 --- a/jdk/src/java.base/share/classes/jdk/internal/misc/JavaLangAccess.java +++ b/jdk/src/java.base/share/classes/jdk/internal/misc/JavaLangAccess.java @@ -174,4 +174,9 @@ public interface JavaLangAccess { * Invokes Long.fastUUID */ String fastUUID(long lsb, long msb); + + /** + * Invalidate package access cache + */ + void invalidatePackageAccessCache(); } diff --git a/jdk/src/java.base/share/classes/jdk/internal/misc/JavaLangModuleAccess.java b/jdk/src/java.base/share/classes/jdk/internal/misc/JavaLangModuleAccess.java index eed7a2d2aff..53e8b4c82c7 100644 --- a/jdk/src/java.base/share/classes/jdk/internal/misc/JavaLangModuleAccess.java +++ b/jdk/src/java.base/share/classes/jdk/internal/misc/JavaLangModuleAccess.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2017, 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 @@ -59,20 +59,21 @@ public interface JavaLangModuleAccess { */ ModuleDescriptor.Builder newModuleBuilder(String mn, boolean strict, - boolean open, - boolean synthetic); + Set ms); /** - * Returns the set of packages that are exported (unconditionally or - * unconditionally). + * Returns a snapshot of the packages in the module. */ - Set exportedPackages(ModuleDescriptor.Builder builder); + Set packages(ModuleDescriptor.Builder builder); /** - * Returns the set of packages that are opened (unconditionally or - * unconditionally). + * Adds a dependence on a module with the given (possibly un-parsable) + * version string. */ - Set openPackages(ModuleDescriptor.Builder builder); + void requires(ModuleDescriptor.Builder builder, + Set ms, + String mn, + String compiledVersion); /** * Returns a {@code ModuleDescriptor.Requires} of the given modifiers @@ -113,24 +114,12 @@ public interface JavaLangModuleAccess { */ Provides newProvides(String service, List providers); - /** - * Returns a {@code ModuleDescriptor.Version} of the given version. - */ - Version newVersion(String v); - - /** - * Clones the given module descriptor with an augmented set of packages - */ - ModuleDescriptor newModuleDescriptor(ModuleDescriptor md, Set pkgs); - /** * Returns a new {@code ModuleDescriptor} instance. */ ModuleDescriptor newModuleDescriptor(String name, Version version, - boolean open, - boolean automatic, - boolean synthetic, + Set ms, Set requires, Set exports, Set opens, @@ -148,9 +137,9 @@ public interface JavaLangModuleAccess { * and the empty configuration as the parent. The post resolution * checks are optionally run. */ - Configuration resolveRequiresAndUses(ModuleFinder finder, - Collection roots, - boolean check, - PrintStream traceOutput); + Configuration resolveAndBind(ModuleFinder finder, + Collection roots, + boolean check, + PrintStream traceOutput); } diff --git a/jdk/src/java.base/share/classes/jdk/internal/module/Builder.java b/jdk/src/java.base/share/classes/jdk/internal/module/Builder.java index 2ef9c11d248..9196f39ff77 100644 --- a/jdk/src/java.base/share/classes/jdk/internal/module/Builder.java +++ b/jdk/src/java.base/share/classes/jdk/internal/module/Builder.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2017, 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 @@ -38,7 +38,7 @@ import jdk.internal.misc.JavaLangModuleAccess; import jdk.internal.misc.SharedSecrets; /** - * This builder is optimized for reconstituting ModuleDescriptor + * This builder is optimized for reconstituting the {@code ModuleDescriptor}s * for system modules. The validation should be done at jlink time. * * 1. skip name validation @@ -136,9 +136,7 @@ final class Builder { } final String name; - boolean open; - boolean automatic; - boolean synthetic; + boolean open, synthetic, mandated; Set requires; Set exports; Set opens; @@ -165,13 +163,13 @@ final class Builder { return this; } - Builder automatic(boolean value) { - this.automatic = value; + Builder synthetic(boolean value) { + this.synthetic = value; return this; } - Builder synthetic(boolean value) { - this.synthetic = value; + Builder mandated(boolean value) { + this.mandated = value; return this; } @@ -228,13 +226,10 @@ final class Builder { * * @throws IllegalArgumentException if {@code v} is null or cannot be * parsed as a version string - * @throws IllegalStateException if the module version is already set * * @see Version#parse(String) */ public Builder version(String v) { - if (version != null) - throw new IllegalStateException("module version already set"); Version ver = cachedVersion; if (ver != null && v.equals(ver.toString())) { version = ver; @@ -246,63 +241,63 @@ final class Builder { /** * Sets the module main class. - * - * @throws IllegalStateException if already set */ public Builder mainClass(String mc) { - if (mainClass != null) - throw new IllegalStateException("main class already set"); mainClass = mc; return this; } /** * Sets the OS name. - * - * @throws IllegalStateException if already set */ public Builder osName(String name) { - if (osName != null) - throw new IllegalStateException("OS name already set"); this.osName = name; return this; } /** * Sets the OS arch. - * - * @throws IllegalStateException if already set */ public Builder osArch(String arch) { - if (osArch != null) - throw new IllegalStateException("OS arch already set"); this.osArch = arch; return this; } /** * Sets the OS version. - * - * @throws IllegalStateException if already set */ public Builder osVersion(String version) { - if (osVersion != null) - throw new IllegalStateException("OS version already set"); this.osVersion = version; return this; } + /** + * Returns an immutable set of the module modifiers derived from the flags. + */ + private Set modifiers() { + int n = 0; + if (open) n++; + if (synthetic) n++; + if (mandated) n++; + if (n == 0) { + return Collections.emptySet(); + } else { + ModuleDescriptor.Modifier[] mods = new ModuleDescriptor.Modifier[n]; + if (open) mods[--n] = ModuleDescriptor.Modifier.OPEN; + if (synthetic) mods[--n] = ModuleDescriptor.Modifier.SYNTHETIC; + if (mandated) mods[--n] = ModuleDescriptor.Modifier.MANDATED; + return Set.of(mods); + } + } + /** * Builds a {@code ModuleDescriptor} from the components. */ public ModuleDescriptor build(int hashCode) { assert name != null; - return JLMA.newModuleDescriptor(name, version, - open, - automatic, - synthetic, + modifiers(), requires, exports, opens, diff --git a/jdk/src/java.base/share/classes/jdk/internal/module/Checks.java b/jdk/src/java.base/share/classes/jdk/internal/module/Checks.java index 2fdeaab6211..e19e6528ce0 100644 --- a/jdk/src/java.base/share/classes/jdk/internal/module/Checks.java +++ b/jdk/src/java.base/share/classes/jdk/internal/module/Checks.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2009, 2017, 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 @@ -26,7 +26,7 @@ package jdk.internal.module; /** - * Utility class for checking module name and binary names. + * Utility class for checking module, package, and class names. */ public final class Checks { @@ -58,8 +58,6 @@ public final class Checks { throw new IllegalArgumentException(name + ": Invalid module name" + ": '" + id + "' is not a Java identifier"); } - //if (!Character.isJavaIdentifierStart(last)) - // throw new IllegalArgumentException(name + ": Module name ends in digit"); return name; } @@ -77,8 +75,6 @@ public final class Checks { int last = isJavaIdentifier(name, off, name.length() - off); if (last == -1) return false; - //if (!Character.isJavaIdentifierStart(last)) - // return false; return true; } @@ -89,40 +85,62 @@ public final class Checks { * package name */ public static String requirePackageName(String name) { - return requireBinaryName("package name", name); + return requireTypeName("package name", name); } /** - * Checks a name to ensure that it's a legal type name. + * Returns {@code true} if the given name is a legal package name. + */ + public static boolean isPackageName(String name) { + return isTypeName(name); + } + + /** + * Checks a name to ensure that it's a legal qualified class name * * @throws IllegalArgumentException if name is null or not a legal - * type name + * qualified class name */ public static String requireServiceTypeName(String name) { - return requireBinaryName("service type name", name); + return requireQualifiedClassName("service type name", name); } /** - * Checks a name to ensure that it's a legal type name. + * Checks a name to ensure that it's a legal qualified class name. * * @throws IllegalArgumentException if name is null or not a legal - * type name + * qualified class name */ public static String requireServiceProviderName(String name) { - return requireBinaryName("service provider name", name); + return requireQualifiedClassName("service provider name", name); } /** - * Returns {@code true} if the given name is a legal binary name. + * Checks a name to ensure that it's a legal qualified class name in + * a named package. + * + * @throws IllegalArgumentException if name is null or not a legal + * qualified class name in a named package */ - public static boolean isJavaIdentifier(String name) { - return isBinaryName(name); + public static String requireQualifiedClassName(String what, String name) { + requireTypeName(what, name); + if (name.indexOf('.') == -1) + throw new IllegalArgumentException(name + ": is not a qualified name of" + + " a Java class in a named package"); + return name; } /** - * Returns {@code true} if the given name is a legal binary name. + * Returns {@code true} if the given name is a legal class name. */ - public static boolean isBinaryName(String name) { + public static boolean isClassName(String name) { + return isTypeName(name); + } + + /** + * Returns {@code true} if the given name is a legal type name. + */ + private static boolean isTypeName(String name) { int next; int off = 0; while ((next = name.indexOf('.', off)) != -1) { @@ -135,12 +153,12 @@ public final class Checks { } /** - * Checks if the given name is a legal binary name. + * Checks if the given name is a legal type name. * * @throws IllegalArgumentException if name is null or not a legal - * binary name + * type name */ - public static String requireBinaryName(String what, String name) { + private static String requireTypeName(String what, String name) { if (name == null) throw new IllegalArgumentException("Null " + what); int next; diff --git a/jdk/src/java.base/share/classes/jdk/internal/module/ClassFileAttributes.java b/jdk/src/java.base/share/classes/jdk/internal/module/ClassFileAttributes.java index 69c7ee670dd..fc3c3904850 100644 --- a/jdk/src/java.base/share/classes/jdk/internal/module/ClassFileAttributes.java +++ b/jdk/src/java.base/share/classes/jdk/internal/module/ClassFileAttributes.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2017, 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 @@ -26,6 +26,7 @@ package jdk.internal.module; import java.lang.module.ModuleDescriptor; +import java.lang.module.ModuleDescriptor.Builder; import java.lang.module.ModuleDescriptor.Requires; import java.lang.module.ModuleDescriptor.Exports; import java.lang.module.ModuleDescriptor.Opens; @@ -98,14 +99,17 @@ public final class ClassFileAttributes { // module_flags int module_flags = cr.readUnsignedShort(off); - boolean open = ((module_flags & ACC_OPEN) != 0); - boolean synthetic = ((module_flags & ACC_SYNTHETIC) != 0); off += 2; - ModuleDescriptor.Builder builder = JLMA.newModuleBuilder(mn, - false, - open, - synthetic); + Set modifiers = new HashSet<>(); + if ((module_flags & ACC_OPEN) != 0) + modifiers.add(ModuleDescriptor.Modifier.OPEN); + if ((module_flags & ACC_SYNTHETIC) != 0) + modifiers.add(ModuleDescriptor.Modifier.SYNTHETIC); + if ((module_flags & ACC_MANDATED) != 0) + modifiers.add(ModuleDescriptor.Modifier.MANDATED); + + Builder builder = JLMA.newModuleBuilder(mn, false, modifiers); // module_version String module_version = cr.readUTF8(off, buf); @@ -142,19 +146,13 @@ public final class ClassFileAttributes { mods.add(Requires.Modifier.MANDATED); } - // requires_version - Version compiledVersion = null; String requires_version = cr.readUTF8(off, buf); off += 2; - if (requires_version != null) { - compiledVersion = Version.parse(requires_version); - } - - if (compiledVersion == null) { + if (requires_version == null) { builder.requires(mods, dn); } else { - builder.requires(mods, dn, compiledVersion); + JLMA.requires(builder, mods, dn, requires_version); } } @@ -283,11 +281,14 @@ public final class ClassFileAttributes { attr.putShort(module_name_index); // module_flags + Set modifiers = descriptor.modifiers(); int module_flags = 0; - if (descriptor.isOpen()) + if (modifiers.contains(ModuleDescriptor.Modifier.OPEN)) module_flags |= ACC_OPEN; - if (descriptor.isSynthetic()) + if (modifiers.contains(ModuleDescriptor.Modifier.SYNTHETIC)) module_flags |= ACC_SYNTHETIC; + if (modifiers.contains(ModuleDescriptor.Modifier.MANDATED)) + module_flags |= ACC_MANDATED; attr.putShort(module_flags); // module_version diff --git a/jdk/src/java.base/share/classes/jdk/internal/module/ClassFileConstants.java b/jdk/src/java.base/share/classes/jdk/internal/module/ClassFileConstants.java index 48fe536c7aa..66e241ee555 100644 --- a/jdk/src/java.base/share/classes/jdk/internal/module/ClassFileConstants.java +++ b/jdk/src/java.base/share/classes/jdk/internal/module/ClassFileConstants.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2017, 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 @@ -46,8 +46,8 @@ public class ClassFileConstants { // access, requires, exports, and opens flags public static final int ACC_MODULE = 0x8000; public static final int ACC_OPEN = 0x0020; - public static final int ACC_TRANSITIVE = 0x0010; - public static final int ACC_STATIC_PHASE = 0x0020; + public static final int ACC_TRANSITIVE = 0x0020; + public static final int ACC_STATIC_PHASE = 0x0040; public static final int ACC_SYNTHETIC = 0x1000; public static final int ACC_MANDATED = 0x8000; diff --git a/jdk/src/java.base/share/classes/jdk/internal/module/ModuleBootstrap.java b/jdk/src/java.base/share/classes/jdk/internal/module/ModuleBootstrap.java index 71406460c41..833b1cf5e24 100644 --- a/jdk/src/java.base/share/classes/jdk/internal/module/ModuleBootstrap.java +++ b/jdk/src/java.base/share/classes/jdk/internal/module/ModuleBootstrap.java @@ -26,7 +26,9 @@ package jdk.internal.module; import java.io.File; +import java.io.IOException; import java.io.PrintStream; +import java.io.UncheckedIOException; import java.lang.module.Configuration; import java.lang.module.ModuleDescriptor; import java.lang.module.ModuleFinder; @@ -35,6 +37,7 @@ import java.lang.module.ResolvedModule; import java.lang.reflect.Layer; import java.lang.reflect.Module; import java.net.URI; +import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; import java.util.ArrayList; @@ -46,6 +49,7 @@ import java.util.Map; import java.util.Optional; import java.util.Set; import java.util.function.Function; +import java.util.stream.Stream; import jdk.internal.loader.BootLoader; import jdk.internal.loader.BuiltinClassLoader; @@ -114,7 +118,12 @@ public final class ModuleBootstrap { long t0 = System.nanoTime(); // system modules (may be patched) - ModuleFinder systemModules = ModuleFinder.ofSystem(); + ModuleFinder systemModules; + if (SystemModules.MODULE_NAMES.length > 0) { + systemModules = SystemModuleFinder.getInstance(); + } else { + systemModules = ModuleFinder.ofSystem(); + } PerfCounters.systemModulesTime.addElapsedTimeFrom(t0); @@ -275,10 +284,10 @@ public final class ModuleBootstrap { // run the resolver to create the configuration Configuration cf = SharedSecrets.getJavaLangModuleAccess() - .resolveRequiresAndUses(finder, - roots, - needPostResolutionChecks, - traceOutput); + .resolveAndBind(finder, + roots, + needPostResolutionChecks, + traceOutput); // time to create configuration PerfCounters.resolveTime.addElapsedTimeFrom(t3); @@ -318,20 +327,20 @@ public final class ModuleBootstrap { // if needed check that there are no split packages in the set of // resolved modules for the boot layer if (SystemModules.hasSplitPackages() || needPostResolutionChecks) { - Map packageToModule = new HashMap<>(); - for (ResolvedModule resolvedModule : cf.modules()) { - ModuleDescriptor descriptor = - resolvedModule.reference().descriptor(); - String name = descriptor.name(); - for (String p : descriptor.packages()) { - String other = packageToModule.putIfAbsent(p, name); - if (other != null) { - fail("Package " + p + " in both module " - + name + " and module " + other); - } + Map packageToModule = new HashMap<>(); + for (ResolvedModule resolvedModule : cf.modules()) { + ModuleDescriptor descriptor = + resolvedModule.reference().descriptor(); + String name = descriptor.name(); + for (String p : descriptor.packages()) { + String other = packageToModule.putIfAbsent(p, name); + if (other != null) { + fail("Package " + p + " in both module " + + name + " and module " + other); } } } + } long t4 = System.nanoTime(); @@ -380,10 +389,9 @@ public final class ModuleBootstrap { Set otherMods) { // resolve all root modules - Configuration cf = Configuration.empty() - .resolveRequires(finder, - ModuleFinder.of(), - roots); + Configuration cf = Configuration.empty().resolve(finder, + ModuleFinder.of(), + roots); // module name -> reference Map map = new HashMap<>(); @@ -416,7 +424,7 @@ public final class ModuleBootstrap { /** * Creates a finder from the module path that is the value of the given - * system property. + * system property and optionally patched by --patch-module */ private static ModuleFinder createModulePathFinder(String prop) { String s = System.getProperty(prop); @@ -429,7 +437,7 @@ public final class ModuleBootstrap { for (String dir: dirs) { paths[i++] = Paths.get(dir); } - return ModuleFinder.of(paths); + return ModulePath.of(patcher, paths); } } @@ -528,8 +536,48 @@ public final class ModuleBootstrap { if (!extraOpens.isEmpty()) { addExtraExportsOrOpens(bootLayer, extraOpens, true); } + + // DEBUG_ADD_OPENS is for debugging purposes only + String home = System.getProperty("java.home"); + Path file = Paths.get(home, "conf", "DEBUG_ADD_OPENS"); + if (Files.exists(file)) { + warn(file + " detected; may break encapsulation"); + try (Stream lines = Files.lines(file)) { + lines.map(line -> line.trim()) + .filter(line -> (!line.isEmpty() && !line.startsWith("#"))) + .forEach(line -> { + String[] s = line.split("/"); + if (s.length != 2) { + fail("Unable to parse as /: " + line); + } else { + String mn = s[0]; + String pkg = s[1]; + openPackage(bootLayer, mn, pkg); + } + }); + } catch (IOException ioe) { + throw new UncheckedIOException(ioe); + } + } } + private static void openPackage(Layer bootLayer, String mn, String pkg) { + if (mn.equals("ALL-RESOLVED") && pkg.equals("ALL-PACKAGES")) { + bootLayer.modules().stream().forEach(m -> + m.getDescriptor().packages().forEach(pn -> openPackage(m, pn))); + } else { + bootLayer.findModule(mn) + .filter(m -> m.getDescriptor().packages().contains(pkg)) + .ifPresent(m -> openPackage(m, pkg)); + } + } + + private static void openPackage(Module m, String pn) { + Modules.addOpensToAllUnnamed(m, pn); + warn("Opened for deep reflection: " + m.getName() + "/" + pn); + } + + private static void addExtraExportsOrOpens(Layer bootLayer, Map> map, boolean opens) diff --git a/jdk/src/java.base/share/classes/jdk/internal/module/ModuleInfo.java b/jdk/src/java.base/share/classes/jdk/internal/module/ModuleInfo.java index 3aac651577c..b58c717affe 100644 --- a/jdk/src/java.base/share/classes/jdk/internal/module/ModuleInfo.java +++ b/jdk/src/java.base/share/classes/jdk/internal/module/ModuleInfo.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2017, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -37,7 +37,6 @@ import java.lang.module.ModuleDescriptor.Builder; import java.lang.module.ModuleDescriptor.Requires; import java.lang.module.ModuleDescriptor.Exports; import java.lang.module.ModuleDescriptor.Opens; -import java.lang.module.ModuleDescriptor.Version; import java.nio.ByteBuffer; import java.nio.BufferUnderflowException; import java.util.ArrayList; @@ -51,7 +50,6 @@ import java.util.function.Supplier; import jdk.internal.misc.JavaLangModuleAccess; import jdk.internal.misc.SharedSecrets; -import jdk.internal.module.ModuleResolution; import static jdk.internal.module.ClassFileConstants.*; @@ -221,7 +219,7 @@ public final class ModuleInfo { Set attributes = new HashSet<>(); Builder builder = null; - Set packages = null; + Set allPackages = null; String mainClass = null; String[] osValues = null; ModuleHashes hashes = null; @@ -245,7 +243,7 @@ public final class ModuleInfo { break; case MODULE_PACKAGES : - packages = readModulePackagesAttribute(in, cpool); + allPackages = readModulePackagesAttribute(in, cpool); break; case MODULE_MAIN_CLASS : @@ -284,51 +282,44 @@ public final class ModuleInfo { throw invalidModuleDescriptor(MODULE + " attribute not found"); } + // ModuleMainClass and ModuleTarget attributes + if (mainClass != null) { + builder.mainClass(mainClass); + } + if (osValues != null) { + if (osValues[0] != null) builder.osName(osValues[0]); + if (osValues[1] != null) builder.osArch(osValues[1]); + if (osValues[2] != null) builder.osVersion(osValues[2]); + } + // If the ModulePackages attribute is not present then the packageFinder // is used to find the set of packages boolean usedPackageFinder = false; - if (packages == null && packageFinder != null) { + if (allPackages == null && packageFinder != null) { try { - packages = new HashSet<>(packageFinder.get()); + allPackages = packageFinder.get(); } catch (UncheckedIOException x) { throw x.getCause(); } usedPackageFinder = true; } - if (packages != null) { - Set exportedPackages = JLMA.exportedPackages(builder); - Set openPackages = JLMA.openPackages(builder); - if (packages.containsAll(exportedPackages) - && packages.containsAll(openPackages)) { - packages.removeAll(exportedPackages); - packages.removeAll(openPackages); - } else { - // the set of packages is not complete - Set exportedAndOpenPackages = new HashSet<>(); - exportedAndOpenPackages.addAll(exportedPackages); - exportedAndOpenPackages.addAll(openPackages); - for (String pn : exportedAndOpenPackages) { - if (!packages.contains(pn)) { - String tail; - if (usedPackageFinder) { - tail = " not found by package finder"; - } else { - tail = " missing from ModulePackages attribute"; - } - throw invalidModuleDescriptor("Package " + pn + tail); - } + if (allPackages != null) { + Set knownPackages = JLMA.packages(builder); + if (!allPackages.containsAll(knownPackages)) { + Set missingPackages = new HashSet<>(knownPackages); + missingPackages.removeAll(allPackages); + assert !missingPackages.isEmpty(); + String missingPackage = missingPackages.iterator().next(); + String tail; + if (usedPackageFinder) { + tail = " not found in module"; + } else { + tail = " missing from ModulePackages class file attribute"; } - assert false; // should not get here - } - builder.contains(packages); - } + throw invalidModuleDescriptor("Package " + missingPackage + tail); - if (mainClass != null) - builder.mainClass(mainClass); - if (osValues != null) { - if (osValues[0] != null) builder.osName(osValues[0]); - if (osValues[1] != null) builder.osArch(osValues[1]); - if (osValues[2] != null) builder.osVersion(osValues[2]); + } + builder.packages(allPackages); } ModuleDescriptor descriptor = builder.build(); @@ -347,10 +338,17 @@ public final class ModuleInfo { String mn = cpool.getModuleName(module_name_index); int module_flags = in.readUnsignedShort(); - boolean open = ((module_flags & ACC_OPEN) != 0); - boolean synthetic = ((module_flags & ACC_SYNTHETIC) != 0); - Builder builder = JLMA.newModuleBuilder(mn, false, open, synthetic); + Set modifiers = new HashSet<>(); + boolean open = ((module_flags & ACC_OPEN) != 0); + if (open) + modifiers.add(ModuleDescriptor.Modifier.OPEN); + if ((module_flags & ACC_SYNTHETIC) != 0) + modifiers.add(ModuleDescriptor.Modifier.SYNTHETIC); + if ((module_flags & ACC_MANDATED) != 0) + modifiers.add(ModuleDescriptor.Modifier.MANDATED); + + Builder builder = JLMA.newModuleBuilder(mn, false, modifiers); int module_version_index = in.readUnsignedShort(); if (module_version_index != 0) { @@ -381,16 +379,11 @@ public final class ModuleInfo { } int requires_version_index = in.readUnsignedShort(); - Version compiledVersion = null; - if (requires_version_index != 0) { - String vs = cpool.getUtf8(requires_version_index); - compiledVersion = Version.parse(vs); - } - - if (compiledVersion == null) { + if (requires_version_index == 0) { builder.requires(mods, dn); } else { - builder.requires(mods, dn, compiledVersion); + String vs = cpool.getUtf8(requires_version_index); + JLMA.requires(builder, mods, dn, vs); } if (dn.equals("java.base")) @@ -629,10 +622,7 @@ public final class ModuleInfo { /** * Return true if the given attribute name is the name of a pre-defined - * attribute that is not allowed in the class file. - * - * Except for Module, InnerClasses, SourceFile, SourceDebugExtension, and - * Deprecated, none of the pre-defined attributes in JVMS 4.7 may appear. + * attribute in JVMS 4.7 that is not allowed in a module-info class. */ private static boolean isAttributeDisallowed(String name) { Set notAllowed = predefinedNotAllowed; @@ -640,6 +630,7 @@ public final class ModuleInfo { notAllowed = Set.of( "ConstantValue", "Code", + "Deprecated", "StackMapTable", "Exceptions", "EnclosingMethod", diff --git a/jdk/src/java.base/share/classes/jdk/internal/module/ModuleInfoExtender.java b/jdk/src/java.base/share/classes/jdk/internal/module/ModuleInfoExtender.java index 0d05ad296e9..73fb660ed7f 100644 --- a/jdk/src/java.base/share/classes/jdk/internal/module/ModuleInfoExtender.java +++ b/jdk/src/java.base/share/classes/jdk/internal/module/ModuleInfoExtender.java @@ -56,7 +56,7 @@ public final class ModuleInfoExtender { // the packages in the ModulePackages attribute private Set packages; - // the value of the module_version in Module attribute + // the value for the module version in the Module attribute private Version version; // the value of the ModuleMainClass attribute @@ -78,7 +78,11 @@ public final class ModuleInfoExtender { } /** - * Sets the set of packages for the ModulePackages attribute + * Sets the packages for the ModulePackages attribute + * + * @apiNote This method does not check that the package names are legal + * package names or that the set of packages is a super set of the + * packages in the module. */ public ModuleInfoExtender packages(Set packages) { this.packages = Collections.unmodifiableSet(packages); @@ -86,7 +90,7 @@ public final class ModuleInfoExtender { } /** - * Sets the value of the module_version in Module attribute. + * Sets the value for the module version in the Module attribute */ public ModuleInfoExtender version(Version version) { this.version = version; @@ -95,6 +99,9 @@ public final class ModuleInfoExtender { /** * Sets the value of the ModuleMainClass attribute. + * + * @apiNote This method does not check that the main class is a legal + * class name in a named package. */ public ModuleInfoExtender mainClass(String mainClass) { this.mainClass = mainClass; @@ -133,7 +140,7 @@ public final class ModuleInfoExtender { /** * A ClassVisitor that supports adding class file attributes. If an - * attribute already exists then the first occurence of the attribute + * attribute already exists then the first occurrence of the attribute * is replaced. */ private static class AttributeAddingClassVisitor extends ClassVisitor { diff --git a/jdk/src/java.base/share/classes/jdk/internal/module/ModuleLoaderMap.java b/jdk/src/java.base/share/classes/jdk/internal/module/ModuleLoaderMap.java index 9c3308f97a0..15e60d0d611 100644 --- a/jdk/src/java.base/share/classes/jdk/internal/module/ModuleLoaderMap.java +++ b/jdk/src/java.base/share/classes/jdk/internal/module/ModuleLoaderMap.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -41,13 +41,6 @@ import jdk.internal.loader.ClassLoaders; * are generated at build time. */ final class ModuleLoaderMap { - /* - * The list of boot modules and platform modules are generated at build time. - */ - private static final String[] BOOT_MODULES - = new String[] { "@@BOOT_MODULE_NAMES@@" }; - private static final String[] PLATFORM_MODULES - = new String[] { "@@PLATFORM_MODULE_NAMES@@" }; /** * Returns the function to map modules in the given configuration to the @@ -55,6 +48,10 @@ final class ModuleLoaderMap { */ static Function mappingFunction(Configuration cf) { + // The list of boot modules and platform modules are generated at build time. + final String[] BOOT_MODULES = new String[] { "@@BOOT_MODULE_NAMES@@" }; + final String[] PLATFORM_MODULES = new String[] { "@@PLATFORM_MODULE_NAMES@@" }; + Set bootModules = new HashSet<>(BOOT_MODULES.length); for (String mn : BOOT_MODULES) { bootModules.add(mn); diff --git a/jdk/src/java.base/share/classes/jdk/internal/module/ModulePatcher.java b/jdk/src/java.base/share/classes/jdk/internal/module/ModulePatcher.java index 5bd7ef5ed04..fe3f8930ad2 100644 --- a/jdk/src/java.base/share/classes/jdk/internal/module/ModulePatcher.java +++ b/jdk/src/java.base/share/classes/jdk/internal/module/ModulePatcher.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -31,6 +31,7 @@ import java.io.IOException; import java.io.InputStream; import java.io.UncheckedIOException; import java.lang.module.ModuleDescriptor; +import java.lang.module.ModuleDescriptor.Builder; import java.lang.module.ModuleReader; import java.lang.module.ModuleReference; import java.net.MalformedURLException; @@ -54,6 +55,7 @@ import java.util.stream.Collectors; import java.util.stream.Stream; import jdk.internal.loader.Resource; +import jdk.internal.loader.ResourceHelper; import jdk.internal.misc.JavaLangModuleAccess; import jdk.internal.misc.SharedSecrets; import sun.net.www.ParseUtil; @@ -108,8 +110,11 @@ public final class ModulePatcher { if (paths == null) return mref; - // scan the JAR file or directory tree to get the set of packages + // Scan the JAR file or directory tree to get the set of packages. + // For automatic modules then packages that do not contain class files + // must be ignored. Set packages = new HashSet<>(); + boolean isAutomatic = descriptor.isAutomatic(); try { for (Path file : paths) { if (Files.isRegularFile(file)) { @@ -118,8 +123,10 @@ public final class ModulePatcher { // is not supported by the boot class loader try (JarFile jf = new JarFile(file.toFile())) { jf.stream() + .filter(e -> !e.isDirectory() + && (!isAutomatic || e.getName().endsWith(".class"))) .map(e -> toPackageName(file, e)) - .filter(Checks::isJavaIdentifier) + .filter(Checks::isPackageName) .forEach(packages::add); } @@ -129,8 +136,10 @@ public final class ModulePatcher { Path top = file; Files.find(top, Integer.MAX_VALUE, ((path, attrs) -> attrs.isRegularFile())) + .filter(path -> !isAutomatic + || path.toString().endsWith(".class")) .map(path -> toPackageName(top, path)) - .filter(Checks::isJavaIdentifier) + .filter(Checks::isPackageName) .forEach(packages::add); } @@ -141,10 +150,30 @@ public final class ModulePatcher { } // if there are new packages then we need a new ModuleDescriptor - Set original = descriptor.packages(); - packages.addAll(original); - if (packages.size() > original.size()) { - descriptor = JLMA.newModuleDescriptor(descriptor, packages); + packages.removeAll(descriptor.packages()); + if (!packages.isEmpty()) { + Builder builder = JLMA.newModuleBuilder(descriptor.name(), + /*strict*/ false, + descriptor.modifiers()); + if (!descriptor.isAutomatic()) { + descriptor.requires().forEach(builder::requires); + descriptor.exports().forEach(builder::exports); + descriptor.opens().forEach(builder::opens); + descriptor.uses().forEach(builder::uses); + } + descriptor.provides().forEach(builder::provides); + + descriptor.version().ifPresent(builder::version); + descriptor.mainClass().ifPresent(builder::mainClass); + descriptor.osName().ifPresent(builder::osName); + descriptor.osArch().ifPresent(builder::osArch); + descriptor.osVersion().ifPresent(builder::osVersion); + + // original + new packages + builder.packages(descriptor.packages()); + builder.packages(packages); + + descriptor = builder.build(); } // return a module reference to the patched module @@ -471,23 +500,14 @@ public final class ModulePatcher { @Override public Resource find(String name) throws IOException { - Path file = Paths.get(name.replace('/', File.separatorChar)); - if (file.getRoot() == null) { - file = dir.resolve(file); - } else { - // drop the root component so that the resource is - // located relative to the module directory - int n = file.getNameCount(); - if (n == 0) - return null; - file = dir.resolve(file.subpath(0, n)); - } - - if (Files.isRegularFile(file)) { - return newResource(name, dir, file); - } else { - return null; + Path path = ResourceHelper.toFilePath(name); + if (path != null) { + Path file = dir.resolve(path); + if (Files.isRegularFile(file)) { + return newResource(name, dir, file); + } } + return null; } private Resource newResource(String name, Path top, Path file) { diff --git a/jdk/src/java.base/share/classes/jdk/internal/module/ModulePath.java b/jdk/src/java.base/share/classes/jdk/internal/module/ModulePath.java index fb7871d3c31..ae337423965 100644 --- a/jdk/src/java.base/share/classes/jdk/internal/module/ModulePath.java +++ b/jdk/src/java.base/share/classes/jdk/internal/module/ModulePath.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2017, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -35,7 +35,6 @@ import java.io.UncheckedIOException; import java.lang.module.FindException; import java.lang.module.InvalidModuleDescriptorException; import java.lang.module.ModuleDescriptor; -import java.lang.module.ModuleDescriptor.Requires; import java.lang.module.ModuleFinder; import java.lang.module.ModuleReference; import java.net.URI; @@ -70,12 +69,11 @@ import jdk.internal.util.jar.VersionedStream; /** * A {@code ModuleFinder} that locates modules on the file system by searching - * a sequence of directories or packaged modules. - * - * The {@code ModuleFinder} can be created to work in either the run-time - * or link-time phases. In both cases it locates modular JAR and exploded - * modules. When created for link-time then it additionally locates - * modules in JMOD files. + * a sequence of directories or packaged modules. The ModuleFinder can be + * created to work in either the run-time or link-time phases. In both cases it + * locates modular JAR and exploded modules. When created for link-time then it + * additionally locates modules in JMOD files. The ModuleFinder can also + * optionally patch any modules that it locates with a ModulePatcher. */ public class ModulePath implements ModuleFinder { @@ -87,6 +85,9 @@ public class ModulePath implements ModuleFinder { // true for the link phase (supports modules packaged in JMOD format) private final boolean isLinkPhase; + // for patching modules, can be null + private final ModulePatcher patcher; + // the entries on this module path private final Path[] entries; private int next; @@ -94,19 +95,51 @@ public class ModulePath implements ModuleFinder { // map of module name to module reference map for modules already located private final Map cachedModules = new HashMap<>(); - public ModulePath(Runtime.Version version, boolean isLinkPhase, Path... entries) { + + private ModulePath(Runtime.Version version, + boolean isLinkPhase, + ModulePatcher patcher, + Path... entries) { this.releaseVersion = version; this.isLinkPhase = isLinkPhase; + this.patcher = patcher; this.entries = entries.clone(); for (Path entry : this.entries) { Objects.requireNonNull(entry); } } - public ModulePath(Path... entries) { - this(JarFile.runtimeVersion(), false, entries); + /** + * Returns a ModuleFinder that that locates modules on the file system by + * searching a sequence of directories and/or packaged modules. The modules + * may be patched by the given ModulePatcher. + */ + public static ModuleFinder of(ModulePatcher patcher, Path... entries) { + return new ModulePath(JarFile.runtimeVersion(), false, patcher, entries); } + /** + * Returns a ModuleFinder that that locates modules on the file system by + * searching a sequence of directories and/or packaged modules. + */ + public static ModuleFinder of(Path... entries) { + return of((ModulePatcher)null, entries); + } + + /** + * Returns a ModuleFinder that that locates modules on the file system by + * searching a sequence of directories and/or packaged modules. + * + * @param version The release version to use for multi-release JAR files + * @param isLinkPhase {@code true} if the link phase to locate JMOD files + */ + public static ModuleFinder of(Runtime.Version version, + boolean isLinkPhase, + Path... entries) { + return new ModulePath(version, isLinkPhase, null, entries); + } + + @Override public Optional find(String name) { Objects.requireNonNull(name); @@ -195,8 +228,7 @@ public class ModulePath implements ModuleFinder { if (attrs.isDirectory()) { Path mi = entry.resolve(MODULE_INFO); if (!Files.exists(mi)) { - // does not exist or unable to determine so assume a - // directory of modules + // assume a directory of modules return scanDirectory(entry); } } @@ -206,11 +238,17 @@ public class ModulePath implements ModuleFinder { if (mref != null) { String name = mref.descriptor().name(); return Collections.singletonMap(name, mref); - } else { - // skipped - return Collections.emptyMap(); } + // not recognized + String msg; + if (!isLinkPhase && entry.toString().endsWith(".jmod")) { + msg = "JMOD format not supported at execution time"; + } else { + msg = "Module format not recognized"; + } + throw new FindException(msg + ": " + entry); + } catch (IOException ioe) { throw new FindException(ioe); } @@ -266,14 +304,11 @@ public class ModulePath implements ModuleFinder { /** - * Locates a packaged or exploded module, returning a {@code ModuleReference} - * to the module. Returns {@code null} if the entry is skipped because it is - * to a directory that does not contain a module-info.class or it's a hidden - * file. + * Reads a packaged or exploded module, returning a {@code ModuleReference} + * to the module. Returns {@code null} if the entry is not recognized. * * @throws IOException if an I/O error occurs - * @throws FindException if the file is not recognized as a module or an - * error occurs parsing its module descriptor + * @throws FindException if an error occurs parsing its module descriptor */ private ModuleReference readModule(Path entry, BasicFileAttributes attrs) throws IOException @@ -282,24 +317,16 @@ public class ModulePath implements ModuleFinder { if (attrs.isDirectory()) { return readExplodedModule(entry); // may return null - } - - String fn = entry.getFileName().toString(); - if (attrs.isRegularFile()) { - if (fn.endsWith(".jar")) { - return readJar(entry); - } else if (fn.endsWith(".jmod")) { - if (isLinkPhase) - return readJMod(entry); - throw new FindException("JMOD files not supported: " + entry); - } - } - - // skip hidden files - if (fn.startsWith(".") || Files.isHidden(entry)) { - return null; } else { - throw new FindException("Unrecognized module: " + entry); + String fn = entry.getFileName().toString(); + if (attrs.isRegularFile()) { + if (fn.endsWith(".jar")) { + return readJar(entry); + } else if (isLinkPhase && fn.endsWith(".jmod")) { + return readJMod(entry); + } + } + return null; } } catch (InvalidModuleDescriptorException e) { @@ -327,7 +354,7 @@ public class ModulePath implements ModuleFinder { } } - // -- jmod files -- + // -- JMOD files -- private Set jmodPackages(JmodFile jf) { return jf.stream() @@ -339,7 +366,7 @@ public class ModulePath implements ModuleFinder { } /** - * Returns a {@code ModuleReference} to a module in jmod file on the + * Returns a {@code ModuleReference} to a module in JMOD file on the * file system. * * @throws IOException @@ -362,7 +389,7 @@ public class ModulePath implements ModuleFinder { /** * Returns the service type corresponding to the name of a services - * configuration file if it is a valid Java identifier. + * configuration file if it is a legal type name. * * For example, if called with "META-INF/services/p.S" then this method * returns a container with the value "p.S". @@ -374,7 +401,7 @@ public class ModulePath implements ModuleFinder { String prefix = cf.substring(0, index); if (prefix.equals(SERVICES_PREFIX)) { String sn = cf.substring(index); - if (Checks.isJavaIdentifier(sn)) + if (Checks.isClassName(sn)) return Optional.of(sn); } } @@ -403,11 +430,10 @@ public class ModulePath implements ModuleFinder { * * 1. The module name (and optionally the version) is derived from the file * name of the JAR file - * 2. All packages are exported and open - * 3. It has no non-exported/non-open packages - * 4. The contents of any META-INF/services configuration files are mapped + * 2. All packages are derived from the .class files in the JAR file + * 3. The contents of any META-INF/services configuration files are mapped * to "provides" declarations - * 5. The Main-Class attribute in the main attributes of the JAR manifest + * 4. The Main-Class attribute in the main attributes of the JAR manifest * is mapped to the module descriptor mainClass */ private ModuleDescriptor deriveModuleDescriptor(JarFile jf) @@ -443,9 +469,7 @@ public class ModulePath implements ModuleFinder { mn = cleanModuleName(mn); // Builder throws IAE if module name is empty or invalid - ModuleDescriptor.Builder builder - = ModuleDescriptor.automaticModule(mn) - .requires(Set.of(Requires.Modifier.MANDATED), "java.base"); + ModuleDescriptor.Builder builder = ModuleDescriptor.newAutomaticModule(mn); if (vs != null) builder.version(vs); @@ -453,17 +477,22 @@ public class ModulePath implements ModuleFinder { Map> map = VersionedStream.stream(jf) .filter(e -> !e.isDirectory()) .map(JarEntry::getName) + .filter(e -> (e.endsWith(".class") ^ e.startsWith(SERVICES_PREFIX))) .collect(Collectors.partitioningBy(e -> e.startsWith(SERVICES_PREFIX), Collectors.toSet())); - Set resources = map.get(Boolean.FALSE); + Set classFiles = map.get(Boolean.FALSE); Set configFiles = map.get(Boolean.TRUE); - // all packages are exported and open - resources.stream() + + // the packages containing class files + Set packages = classFiles.stream() .map(this::toPackageName) .flatMap(Optional::stream) .distinct() - .forEach(pn -> builder.exports(pn).opens(pn)); + .collect(Collectors.toSet()); + + // all packages are exported and open + builder.packages(packages); // map names of service configuration files to service names Set serviceNames = configFiles.stream() @@ -481,6 +510,11 @@ public class ModulePath implements ModuleFinder { String cn; while ((cn = nextLine(reader)) != null) { if (cn.length() > 0) { + String pn = packageName(cn); + if (!packages.contains(pn)) { + String msg = "Provider class " + cn + " not in module"; + throw new IOException(msg); + } providerClasses.add(cn); } } @@ -494,8 +528,15 @@ public class ModulePath implements ModuleFinder { if (man != null) { Attributes attrs = man.getMainAttributes(); String mainClass = attrs.getValue(Attributes.Name.MAIN_CLASS); - if (mainClass != null) - builder.mainClass(mainClass.replace("/", ".")); + if (mainClass != null) { + mainClass = mainClass.replace("/", "."); + String pn = packageName(mainClass); + if (!packages.contains(pn)) { + String msg = "Main-Class " + mainClass + " not in module"; + throw new IOException(msg); + } + builder.mainClass(mainClass); + } } return builder.build(); @@ -569,10 +610,10 @@ public class ModulePath implements ModuleFinder { try { ModuleDescriptor md = deriveModuleDescriptor(jf); attrs = new ModuleInfo.Attributes(md, null, null); - } catch (IllegalArgumentException iae) { + } catch (IllegalArgumentException e) { throw new FindException( "Unable to derive module descriptor for: " - + jf.getName(), iae); + + jf.getName(), e); } } else { @@ -580,7 +621,7 @@ public class ModulePath implements ModuleFinder { () -> jarPackages(jf)); } - return ModuleReferences.newJarModule(attrs, file); + return ModuleReferences.newJarModule(attrs, patcher, file); } } @@ -617,7 +658,15 @@ public class ModulePath implements ModuleFinder { // for now return null; } - return ModuleReferences.newExplodedModule(attrs, dir); + return ModuleReferences.newExplodedModule(attrs, patcher, dir); + } + + /** + * Maps a type name to its package name. + */ + private static String packageName(String cn) { + int index = cn.lastIndexOf('.'); + return (index == -1) ? "" : cn.substring(0, index); } /** @@ -629,19 +678,18 @@ public class ModulePath implements ModuleFinder { */ private Optional toPackageName(String name) { assert !name.endsWith("/"); - int index = name.lastIndexOf("/"); if (index == -1) { if (name.endsWith(".class") && !name.equals(MODULE_INFO)) { throw new IllegalArgumentException(name - + " found in top-level directory:" + + " found in top-level directory" + " (unnamed package not allowed in module)"); } return Optional.empty(); } String pn = name.substring(0, index).replace('/', '.'); - if (Checks.isJavaIdentifier(pn)) { + if (Checks.isPackageName(pn)) { return Optional.of(pn); } else { // not a valid package name @@ -654,7 +702,7 @@ public class ModulePath implements ModuleFinder { * name. * * @throws IllegalArgumentException if the name is a class file in - * the top-level directory (and it's not module-info.class) + * the top-level directory (and it's not module-info.class) */ private Optional toPackageName(Path file) { assert file.getRoot() == null; @@ -664,14 +712,14 @@ public class ModulePath implements ModuleFinder { String name = file.toString(); if (name.endsWith(".class") && !name.equals(MODULE_INFO)) { throw new IllegalArgumentException(name - + " found in in top-level directory" + + " found in top-level directory" + " (unnamed package not allowed in module)"); } return Optional.empty(); } String pn = parent.toString().replace(File.separatorChar, '.'); - if (Checks.isJavaIdentifier(pn)) { + if (Checks.isPackageName(pn)) { return Optional.of(pn); } else { // not a valid package name diff --git a/jdk/src/java.base/share/classes/jdk/internal/module/ModuleReferenceImpl.java b/jdk/src/java.base/share/classes/jdk/internal/module/ModuleReferenceImpl.java index 2ab42bdb4a2..f861b294aef 100644 --- a/jdk/src/java.base/share/classes/jdk/internal/module/ModuleReferenceImpl.java +++ b/jdk/src/java.base/share/classes/jdk/internal/module/ModuleReferenceImpl.java @@ -163,7 +163,14 @@ public class ModuleReferenceImpl extends ModuleReference { @Override public String toString() { - return super.toString(); + StringBuilder sb = new StringBuilder(); + sb.append("[module "); + sb.append(descriptor().name()); + sb.append(", location="); + sb.append(location().orElseThrow(() -> new InternalError())); + if (isPatched()) sb.append(" (patched)"); + sb.append("]"); + return sb.toString(); } } diff --git a/jdk/src/java.base/share/classes/jdk/internal/module/ModuleReferences.java b/jdk/src/java.base/share/classes/jdk/internal/module/ModuleReferences.java index a2aff8f76be..2e2af727599 100644 --- a/jdk/src/java.base/share/classes/jdk/internal/module/ModuleReferences.java +++ b/jdk/src/java.base/share/classes/jdk/internal/module/ModuleReferences.java @@ -36,7 +36,6 @@ import java.net.URI; import java.nio.ByteBuffer; import java.nio.file.Files; import java.nio.file.Path; -import java.nio.file.Paths; import java.util.List; import java.util.Objects; import java.util.Optional; @@ -51,7 +50,7 @@ import java.util.stream.Stream; import java.util.zip.ZipFile; import jdk.internal.jmod.JmodFile; -import jdk.internal.misc.JavaLangAccess; +import jdk.internal.loader.ResourceHelper; import jdk.internal.misc.SharedSecrets; import jdk.internal.module.ModuleHashes.HashSupplier; import jdk.internal.util.jar.VersionedStream; @@ -65,20 +64,16 @@ import sun.net.www.ParseUtil; */ class ModuleReferences { - - private static final JavaLangAccess JLA = SharedSecrets.getJavaLangAccess(); - private ModuleReferences() { } /** - * Creates a ModuleReference to a module or to patched module when - * creating modules for the boot Layer and --patch-module is specified. + * Creates a ModuleReference to a possibly-patched module */ private static ModuleReference newModule(ModuleInfo.Attributes attrs, URI uri, Supplier supplier, + ModulePatcher patcher, HashSupplier hasher) { - ModuleReference mref = new ModuleReferenceImpl(attrs.descriptor(), uri, supplier, @@ -86,38 +81,42 @@ class ModuleReferences { attrs.recordedHashes(), hasher, attrs.moduleResolution()); - if (JLA.getBootLayer() == null) - mref = ModuleBootstrap.patcher().patchIfNeeded(mref); + if (patcher != null) + mref = patcher.patchIfNeeded(mref); return mref; } /** - * Creates a ModuleReference to a module packaged as a modular JAR. + * Creates a ModuleReference to a possibly-patched module in a modular JAR. */ - static ModuleReference newJarModule(ModuleInfo.Attributes attrs, Path file) { + static ModuleReference newJarModule(ModuleInfo.Attributes attrs, + ModulePatcher patcher, + Path file) { URI uri = file.toUri(); Supplier supplier = () -> new JarModuleReader(file, uri); HashSupplier hasher = (a) -> ModuleHashes.computeHash(file, a); - return newModule(attrs, uri, supplier, hasher); + return newModule(attrs, uri, supplier, patcher, hasher); } /** - * Creates a ModuleReference to a module packaged as a JMOD. + * Creates a ModuleReference to a module in a JMOD file. */ static ModuleReference newJModModule(ModuleInfo.Attributes attrs, Path file) { URI uri = file.toUri(); Supplier supplier = () -> new JModModuleReader(file, uri); HashSupplier hasher = (a) -> ModuleHashes.computeHash(file, a); - return newModule(attrs, uri, supplier, hasher); + return newModule(attrs, uri, supplier, null, hasher); } /** - * Creates a ModuleReference to an exploded module. + * Creates a ModuleReference to a possibly-patched exploded module. */ - static ModuleReference newExplodedModule(ModuleInfo.Attributes attrs, Path dir) { + static ModuleReference newExplodedModule(ModuleInfo.Attributes attrs, + ModulePatcher patcher, + Path dir) { Supplier supplier = () -> new ExplodedModuleReader(dir); - return newModule(attrs, dir.toUri(), supplier, null); + return newModule(attrs, dir.toUri(), supplier, patcher, null); } @@ -243,7 +242,8 @@ class ModuleReferences { } private JarEntry getEntry(String name) { - return jf.getJarEntry(Objects.requireNonNull(name)); + JarEntry entry = jf.getJarEntry(Objects.requireNonNull(name)); + return (entry == null || entry.isDirectory()) ? null : entry; } @Override @@ -369,21 +369,6 @@ class ModuleReferences { } } - /** - * Returns a Path to access to the given resource. - */ - private Path toPath(String name) { - Path path = Paths.get(name.replace('/', File.separatorChar)); - if (path.getRoot() == null) { - return dir.resolve(path); - } else { - // drop the root component so that the resource is - // located relative to the module directory - int n = path.getNameCount(); - return (n > 0) ? dir.resolve(path.subpath(0, n)) : null; - } - } - /** * Throws IOException if the module reader is closed; */ @@ -391,11 +376,27 @@ class ModuleReferences { if (closed) throw new IOException("ModuleReader is closed"); } + /** + * Returns a Path to access the given resource. Returns null if the + * resource name does not convert to a file path that locates a regular + * file in the module. + */ + private Path toFilePath(String name) { + Path path = ResourceHelper.toFilePath(name); + if (path != null) { + Path file = dir.resolve(path); + if (Files.isRegularFile(file)) { + return file; + } + } + return null; + } + @Override public Optional find(String name) throws IOException { ensureOpen(); - Path path = toPath(name); - if (path != null && Files.isRegularFile(path)) { + Path path = toFilePath(name); + if (path != null) { try { return Optional.of(path.toUri()); } catch (IOError e) { @@ -409,8 +410,8 @@ class ModuleReferences { @Override public Optional open(String name) throws IOException { ensureOpen(); - Path path = toPath(name); - if (path != null && Files.isRegularFile(path)) { + Path path = toFilePath(name); + if (path != null) { return Optional.of(Files.newInputStream(path)); } else { return Optional.empty(); @@ -420,8 +421,8 @@ class ModuleReferences { @Override public Optional read(String name) throws IOException { ensureOpen(); - Path path = toPath(name); - if (path != null && Files.isRegularFile(path)) { + Path path = toFilePath(name); + if (path != null) { return Optional.of(ByteBuffer.wrap(Files.readAllBytes(path))); } else { return Optional.empty(); diff --git a/jdk/src/java.base/share/classes/jdk/internal/module/Modules.java b/jdk/src/java.base/share/classes/jdk/internal/module/Modules.java index 9f68cfbc421..485d2e130b5 100644 --- a/jdk/src/java.base/share/classes/jdk/internal/module/Modules.java +++ b/jdk/src/java.base/share/classes/jdk/internal/module/Modules.java @@ -82,8 +82,8 @@ public class Modules { String name, Set packages) { - ModuleDescriptor descriptor = ModuleDescriptor.module(name) - .contains(packages) + ModuleDescriptor descriptor = ModuleDescriptor.newModule(name) + .packages(packages) .build(); return JLRMA.defineModule(loader, descriptor, null); @@ -185,7 +185,8 @@ public class Modules { /** * Adds a package to a module's content. * - * This method is a no-op if the module already contains the package. + * This method is a no-op if the module already contains the package or the + * module is an unnamed module. */ public static void addPackage(Module m, String pn) { JLRMA.addPackage(m, pn); diff --git a/jdk/src/java.base/share/classes/jdk/internal/module/SystemModuleFinder.java b/jdk/src/java.base/share/classes/jdk/internal/module/SystemModuleFinder.java index 5ec0a62ca69..a7ee7ffe74f 100644 --- a/jdk/src/java.base/share/classes/jdk/internal/module/SystemModuleFinder.java +++ b/jdk/src/java.base/share/classes/jdk/internal/module/SystemModuleFinder.java @@ -80,8 +80,6 @@ public class SystemModuleFinder implements ModuleFinder { = PerfCounter.newPerfCounter("jdk.module.finder.jimage.packages"); private static final PerfCounter exportsCount = PerfCounter.newPerfCounter("jdk.module.finder.jimage.exports"); - // ImageReader used to access all modules in the image - private static final ImageReader imageReader; // singleton finder to find modules in the run-time images private static final SystemModuleFinder INSTANCE; @@ -96,13 +94,28 @@ public class SystemModuleFinder implements ModuleFinder { */ static { long t0 = System.nanoTime(); - imageReader = ImageReaderFactory.getImageReader(); INSTANCE = new SystemModuleFinder(); initTime.addElapsedTimeFrom(t0); } + /** + * Holder class for the ImageReader + */ + private static class SystemImage { + static final ImageReader READER; + static { + long t0 = System.nanoTime(); + READER = ImageReaderFactory.getImageReader(); + initTime.addElapsedTimeFrom(t0); + } + + static ImageReader reader() { + return READER; + } + } + private static boolean isFastPathSupported() { return SystemModules.MODULE_NAMES.length > 0; } @@ -114,7 +127,7 @@ public class SystemModuleFinder implements ModuleFinder { // this happens when java.base is patched with java.base // from an exploded image - return imageReader.getModuleNames(); + return SystemImage.reader().getModuleNames(); } // the set of modules in the run-time image @@ -151,6 +164,7 @@ public class SystemModuleFinder implements ModuleFinder { descriptors = new ModuleDescriptor[n]; recordedHashes = new ModuleHashes[n]; moduleResolutions = new ModuleResolution[n]; + ImageReader imageReader = SystemImage.reader(); for (int i = 0; i < names.length; i++) { String mn = names[i]; ImageLocation loc = imageReader.findLocation(mn, "module-info.class"); @@ -291,6 +305,7 @@ public class SystemModuleFinder implements ModuleFinder { Objects.requireNonNull(name); if (closed) throw new IOException("ModuleReader is closed"); + ImageReader imageReader = SystemImage.reader(); if (imageReader != null) { return imageReader.findLocation(module, name); } else { @@ -330,7 +345,7 @@ public class SystemModuleFinder implements ModuleFinder { public Optional read(String name) throws IOException { ImageLocation location = findImageLocation(name); if (location != null) { - return Optional.of(imageReader.getResourceBuffer(location)); + return Optional.of(SystemImage.reader().getResourceBuffer(location)); } else { return Optional.empty(); } @@ -372,7 +387,7 @@ public class SystemModuleFinder implements ModuleFinder { stack = new ArrayDeque<>(); // push the root node to the stack to get started - ImageReader.Node dir = imageReader.findNode(moduleRoot); + ImageReader.Node dir = SystemImage.reader().findNode(moduleRoot); if (dir == null || !dir.isDirectory()) throw new IOException(moduleRoot + " not a directory"); stack.push(dir); @@ -390,7 +405,7 @@ public class SystemModuleFinder implements ModuleFinder { String name = node.getName(); if (node.isDirectory()) { // build node - ImageReader.Node dir = imageReader.findNode(name); + ImageReader.Node dir = SystemImage.reader().findNode(name); assert dir.isDirectory(); stack.push(dir); } else { diff --git a/jdk/src/java.base/share/classes/jdk/internal/reflect/Reflection.java b/jdk/src/java.base/share/classes/jdk/internal/reflect/Reflection.java index 9a410049188..61969590d92 100644 --- a/jdk/src/java.base/share/classes/jdk/internal/reflect/Reflection.java +++ b/jdk/src/java.base/share/classes/jdk/internal/reflect/Reflection.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2017, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -211,15 +211,7 @@ public class Reflection { if (currentModule == memberModule) return true; // same module (named or unnamed) - // memberClass may be primitive or array class - Class c = memberClass; - while (c.isArray()) { - c = c.getComponentType(); - } - if (c.isPrimitive()) - return true; - - String pkg = c.getPackageName(); + String pkg = memberClass.getPackageName(); boolean allowed = memberModule.isExported(pkg, currentModule); if (allowed && memberModule.isNamed() && printStackTraceWhenAccessSucceeds()) { if (!SharedSecrets.getJavaLangReflectModuleAccess() @@ -237,10 +229,6 @@ public class Reflection { private static boolean isSameClassPackage(Class c1, Class c2) { if (c1.getClassLoader() != c2.getClassLoader()) return false; - while (c1.isArray()) - c1 = c1.getComponentType(); - while (c2.isArray()) - c2 = c2.getComponentType(); return Objects.equals(c1.getPackageName(), c2.getPackageName()); } @@ -378,12 +366,6 @@ public class Reflection { } } - public static void enableStackTraces() { - printStackWhenAccessFails = true; - printStackWhenAccessSucceeds = true; - printStackPropertiesSet = true; - } - public static boolean printStackTraceWhenAccessFails() { ensurePrintStackPropertiesSet(); return printStackWhenAccessFails; @@ -413,11 +395,7 @@ public class Reflection { if (m2.isNamed()) memberSuffix = " (in " + m2 + ")"; - Class c = memberClass; - while (c.isArray()) { - c = c.getComponentType(); - } - String memberPackageName = c.getPackageName(); + String memberPackageName = memberClass.getPackageName(); String msg = currentClass + currentSuffix + " cannot access "; if (m2.isExported(memberPackageName, m1)) { diff --git a/jdk/src/java.base/share/classes/sun/invoke/util/VerifyAccess.java b/jdk/src/java.base/share/classes/sun/invoke/util/VerifyAccess.java index 9c46aad018f..c3633ff8aab 100644 --- a/jdk/src/java.base/share/classes/sun/invoke/util/VerifyAccess.java +++ b/jdk/src/java.base/share/classes/sun/invoke/util/VerifyAccess.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2008, 2017, 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 @@ -39,6 +39,7 @@ public class VerifyAccess { private VerifyAccess() { } // cannot instantiate + private static final int UNCONDITIONAL_ALLOWED = java.lang.invoke.MethodHandles.Lookup.UNCONDITIONAL; private static final int MODULE_ALLOWED = java.lang.invoke.MethodHandles.Lookup.MODULE; private static final int PACKAGE_ONLY = 0; private static final int PACKAGE_ALLOWED = java.lang.invoke.MethodHandles.Lookup.PACKAGE; @@ -92,7 +93,7 @@ public class VerifyAccess { int allowedModes) { if (allowedModes == 0) return false; assert((allowedModes & PUBLIC) != 0 && - (allowedModes & ~(ALL_ACCESS_MODES|PACKAGE_ALLOWED|MODULE_ALLOWED)) == 0); + (allowedModes & ~(ALL_ACCESS_MODES|PACKAGE_ALLOWED|MODULE_ALLOWED|UNCONDITIONAL_ALLOWED)) == 0); // The symbolic reference class (refc) must always be fully verified. if (!isClassAccessible(refc, lookupClass, allowedModes)) { return false; @@ -173,7 +174,7 @@ public class VerifyAccess { int allowedModes) { if (allowedModes == 0) return false; assert((allowedModes & PUBLIC) != 0 && - (allowedModes & ~(ALL_ACCESS_MODES|PACKAGE_ALLOWED|MODULE_ALLOWED)) == 0); + (allowedModes & ~(ALL_ACCESS_MODES|PACKAGE_ALLOWED|MODULE_ALLOWED|UNCONDITIONAL_ALLOWED)) == 0); int mods = getClassModifiers(refc); if (isPublic(mods)) { @@ -191,22 +192,17 @@ public class VerifyAccess { (lookupModule == refModule)) return true; - // check readability - if (lookupModule.canRead(refModule)) { + // check readability when UNCONDITIONAL not allowed + if (((allowedModes & UNCONDITIONAL_ALLOWED) != 0) + || lookupModule.canRead(refModule)) { // check that refc is in an exported package - Class c = refc; - while (c.isArray()) { - c = c.getComponentType(); - } - if (c.isPrimitive()) - return true; if ((allowedModes & MODULE_ALLOWED) != 0) { - if (refModule.isExported(c.getPackageName(), lookupModule)) + if (refModule.isExported(refc.getPackageName(), lookupModule)) return true; } else { // exported unconditionally - if (refModule.isExported(c.getPackageName())) + if (refModule.isExported(refc.getPackageName())) return true; } diff --git a/jdk/src/java.base/share/classes/sun/launcher/LauncherHelper.java b/jdk/src/java.base/share/classes/sun/launcher/LauncherHelper.java index ee8f311d2e4..9e60d9e9081 100644 --- a/jdk/src/java.base/share/classes/sun/launcher/LauncherHelper.java +++ b/jdk/src/java.base/share/classes/sun/launcher/LauncherHelper.java @@ -966,6 +966,10 @@ public final class LauncherHelper { ostream.print("open "); if (md.isAutomatic()) ostream.print("automatic "); + if (md.modifiers().contains(ModuleDescriptor.Modifier.SYNTHETIC)) + ostream.print("synthetic "); + if (md.modifiers().contains(ModuleDescriptor.Modifier.MANDATED)) + ostream.print("mandated "); ostream.println("module " + midAndLocation(md, mref.location())); // unqualified exports (sorted by package) diff --git a/jdk/src/java.base/share/classes/sun/net/www/protocol/jrt/JavaRuntimeURLConnection.java b/jdk/src/java.base/share/classes/sun/net/www/protocol/jrt/JavaRuntimeURLConnection.java index 88e6f5b7caa..893bb55c10a 100644 --- a/jdk/src/java.base/share/classes/sun/net/www/protocol/jrt/JavaRuntimeURLConnection.java +++ b/jdk/src/java.base/share/classes/sun/net/www/protocol/jrt/JavaRuntimeURLConnection.java @@ -32,7 +32,9 @@ import java.io.IOException; import java.io.InputStream; import java.net.MalformedURLException; import java.net.URL; +import java.security.AccessController; import java.security.Permission; +import java.security.PrivilegedAction; import jdk.internal.jimage.ImageLocation; import jdk.internal.jimage.ImageReader; @@ -51,7 +53,11 @@ import sun.security.action.GetPropertyAction; public class JavaRuntimeURLConnection extends URLConnection { // ImageReader to access resources in jimage - private static final ImageReader reader = ImageReaderFactory.getImageReader(); + private static final ImageReader reader; + static { + PrivilegedAction pa = ImageReaderFactory::getImageReader; + reader = AccessController.doPrivileged(pa); + } // the module and resource name in the URL private final String module; diff --git a/jdk/src/java.instrument/share/classes/java/lang/instrument/ClassFileTransformer.java b/jdk/src/java.instrument/share/classes/java/lang/instrument/ClassFileTransformer.java index 17c5bede590..ab0d540f9c8 100644 --- a/jdk/src/java.instrument/share/classes/java/lang/instrument/ClassFileTransformer.java +++ b/jdk/src/java.instrument/share/classes/java/lang/instrument/ClassFileTransformer.java @@ -229,6 +229,7 @@ public interface ClassFileTransformer { * or {@code null} if no transform is performed * * @since 9 + * @spec JPMS */ default byte[] transform( Module module, diff --git a/jdk/src/java.instrument/share/classes/java/lang/instrument/Instrumentation.java b/jdk/src/java.instrument/share/classes/java/lang/instrument/Instrumentation.java index 97986c2e610..bc4170d3af2 100644 --- a/jdk/src/java.instrument/share/classes/java/lang/instrument/Instrumentation.java +++ b/jdk/src/java.instrument/share/classes/java/lang/instrument/Instrumentation.java @@ -714,6 +714,7 @@ public interface Instrumentation { * @throws NullPointerException if any of the arguments are {@code null} or * any of the Sets or Maps contains a {@code null} key or value * @since 9 + * @spec JPMS */ void redefineModule(Module module, Set extraReads, diff --git a/jdk/src/java.management.rmi/share/classes/javax/management/remote/rmi/RMIConnector.java b/jdk/src/java.management.rmi/share/classes/javax/management/remote/rmi/RMIConnector.java index 7684567c1ca..7c5cd32811f 100644 --- a/jdk/src/java.management.rmi/share/classes/javax/management/remote/rmi/RMIConnector.java +++ b/jdk/src/java.management.rmi/share/classes/javax/management/remote/rmi/RMIConnector.java @@ -38,6 +38,7 @@ import java.io.InvalidObjectException; import java.io.ObjectInputStream; import java.io.ObjectStreamClass; import java.io.Serializable; +import java.lang.module.ModuleDescriptor; import java.lang.ref.WeakReference; import java.lang.reflect.Constructor; import java.lang.reflect.InvocationHandler; @@ -107,6 +108,8 @@ import sun.rmi.server.UnicastRef2; import sun.rmi.transport.LiveRef; import java.io.NotSerializableException; +import static java.lang.module.ModuleDescriptor.Modifier.SYNTHETIC; + /** *

      A connection to a remote RMI connector. Usually, such * connections are made using {@link @@ -2020,8 +2023,14 @@ public class RMIConnector implements JMXConnector, Serializable, JMXAddressable Module rmiModule = RemoteRef.class.getModule(); String pkg = packageOf(pRefClassName); - assert pkg != null && pkg.length() > 0 && !pkg.equals(packageOf(proxyRefCName)); - Module m = Modules.defineModule(cl, "jdk.remoteref", Collections.singleton(pkg)); + assert pkg != null && pkg.length() > 0 && + !pkg.equals(packageOf(proxyRefCName)); + + ModuleDescriptor descriptor = + ModuleDescriptor.newModule("jdk.remoteref", Set.of(SYNTHETIC)) + .packages(Set.of(pkg)) + .build(); + Module m = Modules.defineModule(cl, descriptor, null); // jdk.remoteref needs to read to java.base and jmxModule Modules.addReads(m, Object.class.getModule()); diff --git a/jdk/src/jdk.jartool/share/classes/sun/tools/jar/GNUStyleOptions.java b/jdk/src/jdk.jartool/share/classes/sun/tools/jar/GNUStyleOptions.java index 601a5371932..a95ccd8e116 100644 --- a/jdk/src/jdk.jartool/share/classes/sun/tools/jar/GNUStyleOptions.java +++ b/jdk/src/jdk.jartool/share/classes/sun/tools/jar/GNUStyleOptions.java @@ -157,8 +157,7 @@ class GNUStyleOptions { for (String dir : dirs) { paths[i++] = Paths.get(dir); } - jartool.moduleFinder = - new ModulePath(Runtime.version(), true, paths); + jartool.moduleFinder = ModulePath.of(Runtime.version(), true, paths); } }, new Option(false, OptionType.CREATE_UPDATE, "--do-not-resolve-by-default") { diff --git a/jdk/src/jdk.jartool/share/classes/sun/tools/jar/Main.java b/jdk/src/jdk.jartool/share/classes/sun/tools/jar/Main.java index 36e2ad3b78b..e0d617bd029 100644 --- a/jdk/src/jdk.jartool/share/classes/sun/tools/jar/Main.java +++ b/jdk/src/jdk.jartool/share/classes/sun/tools/jar/Main.java @@ -699,7 +699,7 @@ public class Main { } String pn = toPackageName(name); // add if this is a class or resource in a package - if (Checks.isJavaIdentifier(pn)) { + if (Checks.isPackageName(pn)) { packages.add(pn); } } @@ -1995,7 +1995,7 @@ public class Main { } // get a resolved module graph Configuration config = - Configuration.empty().resolveRequires(system, finder, roots); + Configuration.empty().resolve(system, finder, roots); // filter modules resolved from the system module finder this.modules = config.modules().stream() diff --git a/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/JlinkTask.java b/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/JlinkTask.java index 0eb7ade59fa..40413d491ca 100644 --- a/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/JlinkTask.java +++ b/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/JlinkTask.java @@ -29,6 +29,7 @@ import java.io.IOException; import java.io.PrintWriter; import java.io.UncheckedIOException; import java.lang.module.Configuration; +import java.lang.module.FindException; import java.lang.module.ModuleDescriptor; import java.lang.module.ModuleFinder; import java.lang.module.ModuleReference; @@ -232,7 +233,7 @@ public class JlinkTask { return EXIT_OK; } catch (PluginException | IllegalArgumentException | - UncheckedIOException |IOException | ResolutionException e) { + UncheckedIOException |IOException | FindException | ResolutionException e) { log.println(taskHelper.getMessage("error.prefix") + " " + e.getMessage()); if (DEBUG) { e.printStackTrace(log); @@ -370,7 +371,7 @@ public class JlinkTask { */ private ModuleFinder modulePathFinder() { Path[] entries = options.modulePath.toArray(new Path[0]); - ModuleFinder finder = new ModulePath(Runtime.version(), true, entries); + ModuleFinder finder = ModulePath.of(Runtime.version(), true, entries); if (!options.limitMods.isEmpty()) { finder = limitFinder(finder, options.limitMods, Collections.emptySet()); } @@ -388,7 +389,7 @@ public class JlinkTask { Set roots) { Path[] entries = paths.toArray(new Path[0]); - ModuleFinder finder = new ModulePath(Runtime.version(), true, entries); + ModuleFinder finder = ModulePath.of(Runtime.version(), true, entries); // if limitmods is specified then limit the universe if (!limitMods.isEmpty()) { @@ -418,9 +419,9 @@ public class JlinkTask { } Configuration cf = Configuration.empty() - .resolveRequires(finder, - ModuleFinder.of(), - roots); + .resolve(finder, + ModuleFinder.of(), + roots); // emit warning for modules that end with a digit cf.modules().stream() @@ -458,9 +459,9 @@ public class JlinkTask { // resolve all root modules Configuration cf = Configuration.empty() - .resolveRequires(finder, - ModuleFinder.of(), - roots); + .resolve(finder, + ModuleFinder.of(), + roots); // module name -> reference Map map = new HashMap<>(); diff --git a/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/ResourcePoolConfiguration.java b/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/ResourcePoolConfiguration.java index 9c81c7740c6..37d96c64413 100644 --- a/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/ResourcePoolConfiguration.java +++ b/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/ResourcePoolConfiguration.java @@ -51,7 +51,7 @@ final class ResourcePoolConfiguration { ModuleDescriptor md = mod.descriptor(); // drop hashes - ModuleDescriptor.Builder builder = ModuleDescriptor.module(md.name()); + ModuleDescriptor.Builder builder = ModuleDescriptor.newModule(md.name()); md.requires().stream() .forEach(builder::requires); md.exports().stream() @@ -62,12 +62,7 @@ final class ResourcePoolConfiguration { .forEach(builder::uses); md.provides().stream() .forEach(builder::provides); - - // build the proper concealed packages - Set concealed = new HashSet<>(mod.packages()); - md.exports().stream().map(ModuleDescriptor.Exports::source).forEach(concealed::remove); - md.opens().stream().map(ModuleDescriptor.Opens::source).forEach(concealed::remove); - concealed.stream().forEach(builder::contains); + builder.packages(md.packages()); md.version().ifPresent(builder::version); md.mainClass().ifPresent(builder::mainClass); @@ -124,7 +119,7 @@ final class ResourcePoolConfiguration { } }; - return Configuration.empty().resolveRequires( + return Configuration.empty().resolve( finder, ModuleFinder.of(), nameToModRef.keySet()); } } diff --git a/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/TaskHelper.java b/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/TaskHelper.java index 7c60d79657e..2f45403a27c 100644 --- a/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/TaskHelper.java +++ b/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/TaskHelper.java @@ -718,13 +718,13 @@ public final class TaskHelper { static Layer createPluginsLayer(List paths) { Path[] dirs = paths.toArray(new Path[0]); - ModuleFinder finder = new ModulePath(Runtime.version(), true, dirs); + ModuleFinder finder = ModulePath.of(Runtime.version(), true, dirs); Configuration bootConfiguration = Layer.boot().configuration(); try { Configuration cf = bootConfiguration - .resolveRequiresAndUses(ModuleFinder.of(), - finder, - Collections.emptySet()); + .resolveAndBind(ModuleFinder.of(), + finder, + Collections.emptySet()); ClassLoader scl = ClassLoader.getSystemClassLoader(); return Layer.boot().defineModulesWithOneLoader(cf, scl); } catch (Exception ex) { diff --git a/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/SystemModulesPlugin.java b/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/SystemModulesPlugin.java index 8c3f3ea114e..14cd3f501a4 100644 --- a/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/SystemModulesPlugin.java +++ b/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/SystemModulesPlugin.java @@ -771,9 +771,12 @@ public final class SystemModulesPlugin implements Plugin { if (md.isOpen()) { setModuleBit("open", true); } - if (md.isSynthetic()) { + if (md.modifiers().contains(ModuleDescriptor.Modifier.SYNTHETIC)) { setModuleBit("synthetic", true); } + if (md.modifiers().contains(ModuleDescriptor.Modifier.MANDATED)) { + setModuleBit("mandated", true); + } } /* diff --git a/jdk/src/jdk.jlink/share/classes/jdk/tools/jmod/JmodTask.java b/jdk/src/jdk.jlink/share/classes/jdk/tools/jmod/JmodTask.java index 3ed482b7d99..be88c492297 100644 --- a/jdk/src/jdk.jlink/share/classes/jdk/tools/jmod/JmodTask.java +++ b/jdk/src/jdk.jlink/share/classes/jdk/tools/jmod/JmodTask.java @@ -34,6 +34,7 @@ import java.io.OutputStream; import java.io.PrintWriter; import java.io.UncheckedIOException; import java.lang.module.Configuration; +import java.lang.module.FindException; import java.lang.module.ModuleReader; import java.lang.module.ModuleReference; import java.lang.module.ModuleFinder; @@ -851,8 +852,8 @@ public class JmodTask { // get a resolved module graph Configuration config = null; try { - config = Configuration.empty().resolveRequires(system, finder, roots); - } catch (ResolutionException e) { + config = Configuration.empty().resolve(system, finder, roots); + } catch (FindException | ResolutionException e) { throw new CommandException("err.module.resolution.fail", e.getMessage()); } @@ -1392,7 +1393,7 @@ public class JmodTask { options.legalNotices = getLastElement(opts.valuesOf(legalNotices)); if (opts.has(modulePath)) { Path[] dirs = getLastElement(opts.valuesOf(modulePath)).toArray(new Path[0]); - options.moduleFinder = new ModulePath(Runtime.version(), true, dirs); + options.moduleFinder = ModulePath.of(Runtime.version(), true, dirs); } if (opts.has(moduleVersion)) options.moduleVersion = getLastElement(opts.valuesOf(moduleVersion)); diff --git a/jdk/test/ProblemList.txt b/jdk/test/ProblemList.txt index f94c56a05e4..c2105dbdbb1 100644 --- a/jdk/test/ProblemList.txt +++ b/jdk/test/ProblemList.txt @@ -296,6 +296,8 @@ java/util/BitSet/BitSetStreamTest.java 8079538 generic- sun/tools/jcmd/TestJcmdSanity.java 8031482 windows-all +sun/tools/jstat/jstatClassloadOutput1.sh 8173942 generic-all + sun/jvmstat/monitor/MonitoredVm/MonitorVmStartTerminate.java 8057732 generic-all demo/jvmti/compiledMethodLoad/CompiledMethodLoadTest.java 8151899 generic-all diff --git a/jdk/test/java/io/FilePermission/ReadFileOnPath.java b/jdk/test/java/io/FilePermission/ReadFileOnPath.java index 42ed7542030..9ce8fb9b006 100644 --- a/jdk/test/java/io/FilePermission/ReadFileOnPath.java +++ b/jdk/test/java/io/FilePermission/ReadFileOnPath.java @@ -57,7 +57,7 @@ public class ReadFileOnPath { "module-info.class", "base", "p/App.class", "p/child"); // exploded module - test("--module-path", "modules", "-m", "m/p.App", "SS+++++"); + test("--module-path", "modules", "-m", "m/p.App", "SS++++0"); // module in jar test("--module-path", "new.jar", "-m", "m/p.App", "SSSS++0"); diff --git a/jdk/test/java/lang/Class/forName/modules/TestLayer.java b/jdk/test/java/lang/Class/forName/modules/TestLayer.java index 645e04d7e9b..ff9a772ceeb 100644 --- a/jdk/test/java/lang/Class/forName/modules/TestLayer.java +++ b/jdk/test/java/lang/Class/forName/modules/TestLayer.java @@ -46,9 +46,9 @@ public class TestLayer { ModuleFinder finder = ModuleFinder.of(MODS_DIR); Configuration parent = Layer.boot().configuration(); - Configuration cf = parent.resolveRequiresAndUses(ModuleFinder.of(), - finder, - modules); + Configuration cf = parent.resolveAndBind(ModuleFinder.of(), + finder, + modules); ClassLoader scl = ClassLoader.getSystemClassLoader(); Layer layer = Layer.boot().defineModulesWithManyLoaders(cf, scl); diff --git a/jdk/test/java/lang/Class/forName/modules/src/m3/p3/NoAccess.java b/jdk/test/java/lang/Class/forName/modules/src/m3/p3/NoAccess.java index 618b2fde67a..25e8779ab48 100644 --- a/jdk/test/java/lang/Class/forName/modules/src/m3/p3/NoAccess.java +++ b/jdk/test/java/lang/Class/forName/modules/src/m3/p3/NoAccess.java @@ -50,9 +50,9 @@ public class NoAccess { Layer bootLayer = Layer.boot(); Configuration parent = bootLayer.configuration(); - Configuration cf = parent.resolveRequiresAndUses(finder, - ModuleFinder.of(), - Set.of("m1", "m2")); + Configuration cf = parent.resolveAndBind(finder, + ModuleFinder.of(), + Set.of("m1", "m2")); ClassLoader scl = ClassLoader.getSystemClassLoader(); Layer layer = bootLayer.defineModulesWithManyLoaders(cf, scl); diff --git a/jdk/test/java/lang/Class/getPackageName/Basic.java b/jdk/test/java/lang/Class/getPackageName/Basic.java index e0c0bd17d3c..c079d653205 100644 --- a/jdk/test/java/lang/Class/getPackageName/Basic.java +++ b/jdk/test/java/lang/Class/getPackageName/Basic.java @@ -154,8 +154,8 @@ public class Basic { return new Object[][] { { Basic.class, TEST_PACKAGE }, - { Basic[].class, null }, - { Basic[][].class, null }, + { Basic[].class, TEST_PACKAGE }, + { Basic[][].class, TEST_PACKAGE }, { getNestedClass1(), TEST_PACKAGE }, { getNestedClass2(), TEST_PACKAGE }, @@ -174,14 +174,14 @@ public class Basic { { getAnonymousClass6(), TEST_PACKAGE }, { Object.class, "java.lang" }, - { Object[].class, null }, - { Object[][].class, null }, + { Object[].class, "java.lang" }, + { Object[][].class, "java.lang" }, - { int.class, null }, - { int[].class, null }, - { int[][].class, null }, + { int.class, "java.lang" }, + { int[].class, "java.lang" }, + { int[][].class, "java.lang" }, - { void.class, null }, + { void.class, "java.lang" }, }; } diff --git a/jdk/test/java/lang/StackWalker/CallerFromMain.java b/jdk/test/java/lang/StackWalker/CallerFromMain.java index 9bc289a7f38..0eb0b2bdc46 100644 --- a/jdk/test/java/lang/StackWalker/CallerFromMain.java +++ b/jdk/test/java/lang/StackWalker/CallerFromMain.java @@ -51,7 +51,7 @@ public class CallerFromMain { try { Class c = sw.getCallerClass(); throw new RuntimeException("UOE not thrown. Caller: " + c); - } catch (IllegalStateException e) {} + } catch (IllegalCallerException e) {} // StackWalker::getCallerClass // Runnable::run diff --git a/jdk/test/java/lang/invoke/AccessControlTest.java b/jdk/test/java/lang/invoke/AccessControlTest.java index 57cec50b2ec..616ba798ba6 100644 --- a/jdk/test/java/lang/invoke/AccessControlTest.java +++ b/jdk/test/java/lang/invoke/AccessControlTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2017, 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 @@ -118,6 +118,8 @@ public class AccessControlTest { suffix = "/noaccess"; else if (lookupModes == PUBLIC) suffix = "/public"; + else if (lookupModes == (PUBLIC|UNCONDITIONAL)) + suffix = "/publicLookup"; else if (lookupModes == (PUBLIC|MODULE)) suffix = "/module"; else if (lookupModes == (PUBLIC|MODULE|PACKAGE)) @@ -140,23 +142,24 @@ public class AccessControlTest { * [A2] However, the resulting {@code Lookup} object is guaranteed * to have no more access capabilities than the original. * In particular, access capabilities can be lost as follows:

        - *
      • [A3] If the new lookup class differs from the old one, - * protected members will not be accessible by virtue of inheritance. + *
      • [A3] If the old lookup class is in a named module, and the new + * lookup class is in a different module {@code M}, then no members, not + * even public members in {@code M}'s exported packages, will be accessible. + * The exception to this is when this lookup is publicLookup, in which case + * public access is not lost. + *
      • [A4] If the old lookup class is in an unnamed module, and the new + * lookup class is a different module then module access is lost. + *
      • [A5] If the new lookup class differs from the old one then UNCONDITIONAL + * is lost. If the new lookup class is not within the same package member as the + * old one, protected members will not be accessible by virtue of inheritance. * (Protected members may continue to be accessible because of package sharing.) - *
      • [A4] If the new lookup class is in a different package - * than the old one, protected and default (package) members will not be accessible. - *
      • [A5] If the new lookup class is not within the same package member + *
      • [A6] If the new lookup class is in a different package than the old one, + * protected and default (package) members will not be accessible. + *
      • [A7] If the new lookup class is not within the same package member * as the old one, private members will not be accessible. - *
      • [A6] If the new lookup class is not accessible to the old lookup class, - * using the original access modes, + *
      • [A8] If the new lookup class is not accessible to the old lookup class, * then no members, not even public members, will be accessible. - *
      • [A7] If the new lookup class for this {@code Lookup} is in the unnamed module, - * and the new lookup class is in a named module {@code M}, then no members in - * {@code M}'s non-exported packages will be accessible. - *
      • [A8] If the lookup for this {@code Lookup} is in a named module, and the - * new lookup class is in a different module, then no members, not even - * public members in {@code M}'s exported packages, will be accessible. - * [A8] (In all other cases, public members will continue to be accessible.) + *
      • [A9] (In all other cases, public members will continue to be accessible.) *
      * Other than the above cases, the new lookup will have the same * access capabilities as the original. [A10] @@ -171,36 +174,35 @@ public class AccessControlTest { boolean sameModule = (c1.getModule() == c2.getModule()) || (!c1.getModule().isNamed() && !c2.getModule().isNamed()); boolean samePackage = (c1.getClassLoader() == c2.getClassLoader() && - packagePrefix(c1).equals(packagePrefix(c2))); + c1.getPackageName().equals(c2.getPackageName())); boolean sameTopLevel = (topLevelClass(c1) == topLevelClass(c2)); boolean sameClass = (c1 == c2); assert(samePackage || !sameTopLevel); assert(sameTopLevel || !sameClass); - boolean accessible = sameClass; // [A6] + boolean accessible = sameClass; if ((m1 & PACKAGE) != 0) accessible |= samePackage; if ((m1 & PUBLIC ) != 0) accessible |= (c2.getModifiers() & PUBLIC) != 0; if (!sameModule) { - if (c1.getModule().isNamed()) { - accessible = false; // [A8] + if (c1.getModule().isNamed() && (m1 & UNCONDITIONAL) == 0) { + accessible = false; // [A3] } else { - // Different module; loose MODULE and lower access. - changed |= (MODULE|PACKAGE|PRIVATE|PROTECTED); // [A7] + changed |= (MODULE|PACKAGE|PRIVATE|PROTECTED); // [A3] [A4] } } if (!accessible) { // Different package and no access to c2; lose all access. - changed |= (PUBLIC|MODULE|PACKAGE|PRIVATE|PROTECTED); // [A6] + changed |= (PUBLIC|MODULE|PACKAGE|PRIVATE|PROTECTED); // [A8] } if (!samePackage) { // Different package; loose PACKAGE and lower access. - changed |= (PACKAGE|PRIVATE|PROTECTED); // [A4] + changed |= (PACKAGE|PRIVATE|PROTECTED); // [A6] } if (!sameTopLevel) { - // Different top-level class. Lose PRIVATE and lower access. - changed |= (PRIVATE|PROTECTED); // [A5] + // Different top-level class. Lose PRIVATE and PROTECTED access. + changed |= (PRIVATE|PROTECTED); // [A5] [A7] } if (!sameClass) { - changed |= (PROTECTED); // [A3] + changed |= (UNCONDITIONAL); // [A5] } else { assert(changed == 0); // [A10] (no deprivation if same class) } @@ -228,11 +230,10 @@ public class AccessControlTest { Class c1 = lookupClass(); Class c2 = m.getDeclaringClass(); - // if the lookup class is in a loose module with PUBLIC access then - // public members of public types in all unnamed modules can be accessed - if (isLooseModule(c1.getModule()) + // publicLookup has access to all public types/members of types in unnamed modules + if ((lookupModes & UNCONDITIONAL) != 0 && (lookupModes & PUBLIC) != 0 - && (!c2.getModule().isNamed()) + && !c2.getModule().isNamed() && Modifier.isPublic(c2.getModifiers()) && Modifier.isPublic(m.getModifiers())) return true; @@ -261,17 +262,12 @@ public class AccessControlTest { if (load && c2.getClassLoader() != null) { if (c1.getClassLoader() == null) { // not visible - return false; - } - if (c1 == publicLookup().lookupClass()) { - // not visible as lookup class is defined by child of the boot loader return false; } } - // if the lookup class is in a loose module with PUBLIC access then - // public types in all unnamed modules can be accessed - if (isLooseModule(c1.getModule()) + // publicLookup has access to all public types/members of types in unnamed modules + if ((lookupModes & UNCONDITIONAL) != 0 && (lookupModes & PUBLIC) != 0 && (!c2.getModule().isNamed()) && Modifier.isPublic(c2.getModifiers())) @@ -295,11 +291,6 @@ public class AccessControlTest { } return r; } - - private boolean isLooseModule(Module m) { - ClassLoader cl = new ClassLoader() { }; - return m.canRead(cl.getUnnamedModule()); - } } private static Class topLevelClass(Class cls) { @@ -311,14 +302,6 @@ public class AccessControlTest { return c; } - private static String packagePrefix(Class c) { - while (c.isArray()) c = c.getComponentType(); - String s = c.getName(); - assert(s.indexOf('/') < 0); - return s.substring(0, s.lastIndexOf('.')+1); - } - - private final TreeSet CASES = new TreeSet<>(); private final TreeMap> CASE_EDGES = new TreeMap<>(); private final ArrayList LOADERS = new ArrayList<>(); diff --git a/jdk/test/java/lang/invoke/DropLookupModeTest.java b/jdk/test/java/lang/invoke/DropLookupModeTest.java index be7d0a60e54..64cb99e15e7 100644 --- a/jdk/test/java/lang/invoke/DropLookupModeTest.java +++ b/jdk/test/java/lang/invoke/DropLookupModeTest.java @@ -65,6 +65,10 @@ public class DropLookupModeTest { lookup = fullPowerLookup.dropLookupMode(PUBLIC); assertTrue(lookup.lookupClass() == lc); assertTrue(lookup.lookupModes() == 0); + + lookup = fullPowerLookup.dropLookupMode(UNCONDITIONAL); + assertTrue(lookup.lookupClass() == lc); + assertTrue(lookup.lookupModes() == (PUBLIC|MODULE|PACKAGE|PRIVATE)); } /** @@ -108,7 +112,7 @@ public class DropLookupModeTest { public void testPublicLookup() { final Lookup publicLookup = MethodHandles.publicLookup(); final Class lc = publicLookup.lookupClass(); - assertTrue(publicLookup.lookupModes() == PUBLIC); + assertTrue(publicLookup.lookupModes() == (PUBLIC|UNCONDITIONAL)); Lookup lookup = publicLookup.dropLookupMode(PRIVATE); assertTrue(lookup.lookupClass() == lc); @@ -129,6 +133,10 @@ public class DropLookupModeTest { lookup = publicLookup.dropLookupMode(PUBLIC); assertTrue(lookup.lookupClass() == lc); assertTrue(lookup.lookupModes() == 0); + + lookup = publicLookup.dropLookupMode(UNCONDITIONAL); + assertTrue(lookup.lookupClass() == lc); + assertTrue(lookup.lookupModes() == PUBLIC); } @DataProvider(name = "badInput") diff --git a/jdk/test/java/lang/invoke/MethodHandles/privateLookupIn/Driver.java b/jdk/test/java/lang/invoke/MethodHandles/privateLookupIn/Driver.java index 5abe4eb2383..810351bae3e 100644 --- a/jdk/test/java/lang/invoke/MethodHandles/privateLookupIn/Driver.java +++ b/jdk/test/java/lang/invoke/MethodHandles/privateLookupIn/Driver.java @@ -23,7 +23,7 @@ /** * @test - * @build test/* m1/* m2/* m3/* + * @build test/* m1/* m2/* m3/* Unnamed * @run testng/othervm test/p.PrivateLookupInTests * @summary Unit tests for MethodHandles.privateLookupIn */ diff --git a/jdk/test/java/lang/invoke/MethodHandles/privateLookupIn/Unnamed.java b/jdk/test/java/lang/invoke/MethodHandles/privateLookupIn/Unnamed.java new file mode 100644 index 00000000000..9bb0ff042a3 --- /dev/null +++ b/jdk/test/java/lang/invoke/MethodHandles/privateLookupIn/Unnamed.java @@ -0,0 +1,24 @@ +/* + * Copyright (c) 2017, 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 Unnamed { } diff --git a/jdk/test/java/lang/invoke/MethodHandles/privateLookupIn/test/p/PrivateLookupInTests.java b/jdk/test/java/lang/invoke/MethodHandles/privateLookupIn/test/p/PrivateLookupInTests.java index 823ae8797b5..f2391743bd0 100644 --- a/jdk/test/java/lang/invoke/MethodHandles/privateLookupIn/test/p/PrivateLookupInTests.java +++ b/jdk/test/java/lang/invoke/MethodHandles/privateLookupIn/test/p/PrivateLookupInTests.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2017, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -126,6 +126,26 @@ public class PrivateLookupInTests { Object obj = mh.invokeExact(); } + // test target class in unnamed module + public void testTargetClassInUnnamedModule() throws Throwable { + Class clazz = Class.forName("Unnamed"); + assertFalse(clazz.getModule().isNamed()); + + // thisModule does not read the unnamed module + Module thisModule = getClass().getModule(); + assertFalse(thisModule.canRead(clazz.getModule())); + try { + MethodHandles.privateLookupIn(clazz, MethodHandles.lookup()); + assertTrue(false); + } catch (IllegalAccessException expected) { } + + // thisModule reads the unnamed module + thisModule.addReads(clazz.getModule()); + Lookup lookup = MethodHandles.privateLookupIn(clazz, MethodHandles.lookup()); + assertTrue(lookup.lookupClass() == clazz); + assertTrue(lookup.hasPrivateAccess()); + } + // test does not read m2, m2 opens p2 to test @Test(expectedExceptions = {IllegalAccessException.class}) public void testCallerDoesNotRead() throws Throwable { diff --git a/jdk/test/java/lang/invoke/modules/Driver.java b/jdk/test/java/lang/invoke/modules/Driver.java new file mode 100644 index 00000000000..5c00de3ad47 --- /dev/null +++ b/jdk/test/java/lang/invoke/modules/Driver.java @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2017, 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 + * @build m1/* m2/* Unnamed + * @run testng/othervm m1/p1.Main + * @summary Basic test case for module access checks and Lookup.in. + */ diff --git a/jdk/test/java/lang/invoke/modules/ModuleAccessControlTest.java b/jdk/test/java/lang/invoke/modules/ModuleAccessControlTest.java deleted file mode 100644 index 32adfd9d5e0..00000000000 --- a/jdk/test/java/lang/invoke/modules/ModuleAccessControlTest.java +++ /dev/null @@ -1,81 +0,0 @@ -/* - * Copyright (c) 2015, 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.nio.file.Path; -import java.nio.file.Paths; -import java.util.Arrays; -import java.util.List; - -import static jdk.testlibrary.ProcessTools.executeTestJava; - -import org.testng.annotations.BeforeTest; -import org.testng.annotations.Test; -import static org.testng.Assert.*; - -/** - * @test - * @library /lib/testlibrary - * @modules jdk.compiler - * @build CompilerUtils jdk.testlibrary.* - * @run testng ModuleAccessControlTest - * @summary Driver for testing module access checking by MethodHandles.Lookup - */ - -public class ModuleAccessControlTest { - - private static final String TEST_SRC = System.getProperty("test.src"); - - private static final Path SRC_DIR = Paths.get(TEST_SRC, "src"); - private static final Path MODS_DIR = Paths.get("mods"); - - // the names of the modules in this test - private static List modules = Arrays.asList("m1", "m2"); - - - /** - * Compiles all modules used by the test - */ - @BeforeTest - public void compileAll() throws Exception { - for (String mn : modules) { - Path msrc = SRC_DIR.resolve(mn); - assertTrue(CompilerUtils - .compile(msrc, MODS_DIR, "--module-source-path", SRC_DIR.toString())); - } - } - - /** - * Launch the test - */ - @Test - public void runTest() throws Exception { - int exitValue = executeTestJava("--module-path", MODS_DIR.toString(), - "-m", "m1/p1.Main") - .outputTo(System.out) - .errorTo(System.out) - .getExitValue(); - - assertTrue(exitValue == 0); - } - -} diff --git a/jdk/test/java/lang/invoke/modules/Unnamed.java b/jdk/test/java/lang/invoke/modules/Unnamed.java new file mode 100644 index 00000000000..9bb0ff042a3 --- /dev/null +++ b/jdk/test/java/lang/invoke/modules/Unnamed.java @@ -0,0 +1,24 @@ +/* + * Copyright (c) 2017, 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 Unnamed { } diff --git a/jdk/test/java/lang/invoke/modules/src/m1/module-info.java b/jdk/test/java/lang/invoke/modules/m1/module-info.java similarity index 98% rename from jdk/test/java/lang/invoke/modules/src/m1/module-info.java rename to jdk/test/java/lang/invoke/modules/m1/module-info.java index 175c7727611..9c09afcf7e1 100644 --- a/jdk/test/java/lang/invoke/modules/src/m1/module-info.java +++ b/jdk/test/java/lang/invoke/modules/m1/module-info.java @@ -22,5 +22,6 @@ */ module m1 { requires m2; + requires testng; exports p1; } diff --git a/jdk/test/java/lang/invoke/modules/m1/p1/Main.java b/jdk/test/java/lang/invoke/modules/m1/p1/Main.java new file mode 100644 index 00000000000..7a10022d78f --- /dev/null +++ b/jdk/test/java/lang/invoke/modules/m1/p1/Main.java @@ -0,0 +1,367 @@ +/* + * Copyright (c) 2015, 2017, 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 p1; + +import java.lang.invoke.MethodHandle; +import java.lang.invoke.MethodHandles; +import java.lang.invoke.MethodHandles.Lookup; +import java.lang.invoke.MethodType; +import java.lang.reflect.Layer; +import java.lang.reflect.Module; + +import static java.lang.invoke.MethodHandles.Lookup.*; + +import org.testng.annotations.BeforeTest; +import org.testng.annotations.Test; +import static org.testng.Assert.*; + +/** + * Basic test case for module access checks and Lookup.in. + */ + +@Test +public class Main { + + private Class p1_Type1; // m1, exported + private Class p2_Type2; // m1, not exported + private Class q1_Type1; // m2, exported + private Class q2_Type2; // m2, not exported + private Class x500NameClass; // java.base, not exported + private Class unnamedClass; // class in unnamed module + + @BeforeTest + public void setup() throws Exception { + try { + p1_Type1 = Class.forName("p1.Type1"); + p2_Type2 = Class.forName("p2.Type2"); + q1_Type1 = Class.forName("q1.Type1"); + q2_Type2 = Class.forName("q2.Type2"); + x500NameClass = Class.forName("sun.security.x509.X500Name"); + unnamedClass = Class.forName("Unnamed"); + } catch (ClassNotFoundException e) { + throw new AssertionError(e); + } + + // check setup + Module m1 = Layer.boot().findModule("m1").orElse(null); + assertNotNull(m1); + assertTrue(p1_Type1.getModule() == m1); + assertTrue(p2_Type2.getModule() == m1); + assertTrue(m1.isExported("p1")); + assertFalse(m1.isExported("p2")); + + Module m2 = Layer.boot().findModule("m2").orElse(null); + assertNotNull(m2); + assertTrue(q1_Type1.getModule() == m2); + assertTrue(q2_Type2.getModule() == m2); + assertTrue(m2.isExported("q1")); + assertFalse(m2.isExported("q2")); + + Module unnamedModule = unnamedClass.getModule(); + assertFalse(unnamedModule.isNamed()); + + // m1 needs to read unnamed module + Main.class.getModule().addReads(unnamedModule); + } + + /** + * MethodHandles.lookup() + * + * [A0] has module access + * [A1] can access all public types in m1 + * [A2] can access public types in packages exported by modules that m1 reads + * [A3] cannot access public types in non-exported modules of modules that m1 reads + */ + public void testLookup() throws Exception { + Lookup lookup = MethodHandles.lookup(); + assertTrue((lookup.lookupModes() & MODULE) == MODULE); // [A0] + + // m1 + findConstructor(lookup, p1_Type1, void.class); // [A1] + findConstructor(lookup, p2_Type2, void.class); // [A1] + + // m2 + findConstructor(lookup, q1_Type1, void.class); // [A2] + findConstructorExpectingIAE(lookup, q2_Type2, void.class); // [A3] + + // java.base + findConstructor(lookup, Object.class, void.class); // [A2] + findConstructorExpectingIAE(lookup, x500NameClass, void.class, String.class); // [A3] + + // unnamed + findConstructor(lookup, unnamedClass, void.class); // [A3] + } + + /** + * Hop to lookup class in the same module + * + * [A0] module and public access is not lost + */ + public void testToSameModule() throws Exception { + Lookup lookup = MethodHandles.lookup().in(p2_Type2); + assertTrue(lookup.lookupModes() == (MODULE|PUBLIC)); // [A0] + + // m1 + findConstructor(lookup, p1_Type1, void.class); + findConstructor(lookup, p2_Type2, void.class); + + // m2 + findConstructor(lookup, q1_Type1, void.class); + findConstructorExpectingIAE(lookup, q2_Type2, void.class); + + // java.base + findConstructor(lookup, Object.class, void.class); + findConstructorExpectingIAE(lookup, x500NameClass, void.class, String.class); + + // unnamed + findConstructor(lookup, unnamedClass, void.class); + } + + /** + * Hop to lookup class in another named module + * + * [A0] has no access + */ + public void testFromNamedToNamedModule() throws Exception { + Lookup lookup = MethodHandles.lookup().in(q1_Type1); + assertTrue(lookup.lookupModes() == 0); // [A0] + + // m1 + findConstructorExpectingIAE(lookup, p1_Type1, void.class); + findConstructorExpectingIAE(lookup, p2_Type2, void.class); + + // m2 + findConstructorExpectingIAE(lookup, q1_Type1, void.class); + findConstructorExpectingIAE(lookup, q2_Type2, void.class); + + // java.base + findConstructorExpectingIAE(lookup, Object.class, void.class); + findConstructorExpectingIAE(lookup, x500NameClass, void.class, String.class); + + // unnamed + findConstructorExpectingIAE(lookup, unnamedClass, void.class); + } + + /** + * Hop to lookup class in an unnamed module + * + * [A0] has no access + */ + public void testFromNamedToUnnamedModule() throws Exception { + Lookup lookup = MethodHandles.lookup().in(unnamedClass); + assertTrue(lookup.lookupModes() == 0); // [A0] + + // m1 + findConstructorExpectingIAE(lookup, p1_Type1, void.class); + findConstructorExpectingIAE(lookup, p2_Type2, void.class); + + // m2 + findConstructorExpectingIAE(lookup, q1_Type1, void.class); + findConstructorExpectingIAE(lookup, q2_Type2, void.class); + + // java.base + findConstructorExpectingIAE(lookup, Object.class, void.class); + findConstructorExpectingIAE(lookup, x500NameClass, void.class, String.class); + + // unnamed + findConstructorExpectingIAE(lookup, unnamedClass, void.class); + } + + /** + * Hop from unnamed to named module. + * + * [A0] retains PUBLIC access + */ + public void testFromUnnamedToNamedModule() throws Exception { + Lookup lookup = MethodHandles.lookup(); + lookup = MethodHandles.privateLookupIn(unnamedClass, lookup).in(p1_Type1); + assertTrue(lookup.lookupModes() == PUBLIC); // A0 + + // m1 + findConstructor(lookup, p1_Type1, void.class); + findConstructorExpectingIAE(lookup, p2_Type2, void.class); + + // m2 + findConstructor(lookup, q1_Type1, void.class); + findConstructorExpectingIAE(lookup, q2_Type2, void.class); + + // java.base + findConstructor(lookup, Object.class, void.class); + findConstructorExpectingIAE(lookup, x500NameClass, void.class, String.class); + + // unnamed + findConstructor(lookup, unnamedClass, void.class); + } + + /** + * MethodHandles.publicLookup() + * + * [A0] has PUBLIC|UNCONDITIONAL access + */ + public void testPublicLookup() throws Exception { + Lookup lookup = MethodHandles.publicLookup(); + assertTrue(lookup.lookupModes() == (PUBLIC|UNCONDITIONAL)); // A0 + + // m1 + findConstructor(lookup, p1_Type1, void.class); + findConstructorExpectingIAE(lookup, p2_Type2, void.class); + + // m2 + findConstructor(lookup, q1_Type1, void.class); + findConstructorExpectingIAE(lookup, q2_Type2, void.class); + + // java.base + findConstructor(lookup, Object.class, void.class); + findConstructorExpectingIAE(lookup, x500NameClass, void.class, String.class); + + // unnamed + findConstructor(lookup, unnamedClass, void.class); + } + + /** + * Hop from publicLookup to accessible type in java.base + */ + public void testPublicLookupToBaseModule() throws Exception { + Lookup lookup = MethodHandles.publicLookup().in(String.class); + assertTrue(lookup.lookupModes() == PUBLIC); // A0 + + // m1 + findConstructorExpectingIAE(lookup, p1_Type1, void.class); + findConstructorExpectingIAE(lookup, p2_Type2, void.class); + + // m2 + findConstructorExpectingIAE(lookup, q1_Type1, void.class); + findConstructorExpectingIAE(lookup, q2_Type2, void.class); + + // java.base + findConstructor(lookup, Object.class, void.class); + findConstructorExpectingIAE(lookup, x500NameClass, void.class, String.class); + + // unnamed + findConstructorExpectingIAE(lookup, unnamedClass, void.class); + } + + + /** + * Hop from publicLookup to accessible type in named module. + * + * [A0] has PUBLIC access + */ + public void testPublicLookupToAccessibleTypeInNamedModule() throws Exception { + Lookup lookup = MethodHandles.publicLookup().in(p1_Type1); + assertTrue(lookup.lookupModes() == PUBLIC); // A0 + + // m1 + findConstructor(lookup, p1_Type1, void.class); + findConstructorExpectingIAE(lookup, p2_Type2, void.class); + + // m2 + findConstructor(lookup, q1_Type1, void.class); + findConstructorExpectingIAE(lookup, q2_Type2, void.class); + + // java.base + findConstructor(lookup, Object.class, void.class); + findConstructorExpectingIAE(lookup, x500NameClass, void.class, String.class); + + // unnamed + findConstructor(lookup, unnamedClass, void.class); + } + + /** + * Teleport from publicLookup to inaccessible type in named module. + * + * [A0] has no access + */ + public void testPublicLookupToInaccessibleTypeInNamedModule() throws Exception { + Lookup lookup = MethodHandles.publicLookup().in(p2_Type2); + assertTrue(lookup.lookupModes() == 0); // A0 + + // m1 + findConstructorExpectingIAE(lookup, p1_Type1, void.class); + findConstructorExpectingIAE(lookup, p2_Type2, void.class); + + // m2 + findConstructorExpectingIAE(lookup, q1_Type1, void.class); + findConstructorExpectingIAE(lookup, q2_Type2, void.class); + + // java.base + findConstructorExpectingIAE(lookup, Object.class, void.class); + findConstructorExpectingIAE(lookup, x500NameClass, void.class, String.class); + + // unnamed + findConstructorExpectingIAE(lookup, unnamedClass, void.class); + } + + /** + * Teleport from publicLookup to public type in unnamed module + * + * [A0] has PUBLIC access + */ + public void testPublicLookupToUnnamedModule() throws Exception { + Lookup lookup = MethodHandles.publicLookup().in(unnamedClass); + assertTrue(lookup.lookupModes() == PUBLIC); // A0 + + // m1 + findConstructor(lookup, p1_Type1, void.class); + findConstructorExpectingIAE(lookup, p2_Type2, void.class); + + // m2 + findConstructor(lookup, q1_Type1, void.class); + findConstructorExpectingIAE(lookup, q2_Type2, void.class); + + // java.base + findConstructor(lookup, Object.class, void.class); + findConstructorExpectingIAE(lookup, x500NameClass, void.class, String.class); + + // unnamed + findConstructor(lookup, unnamedClass, void.class); + } + + /** + * Invokes Lookup findConstructor with a method type constructored from the + * given return and parameter types, expecting IllegalAccessException to be + * thrown. + */ + static void findConstructorExpectingIAE(Lookup lookup, + Class clazz, + Class rtype, + Class... ptypes) throws Exception { + try { + findConstructor(lookup, clazz, rtype, ptypes); + assertTrue(false); + } catch (IllegalAccessException expected) { } + } + + /** + * Invokes Lookup findConstructor with a method type constructored from the + * given return and parameter types. + */ + static MethodHandle findConstructor(Lookup lookup, + Class clazz, + Class rtype, + Class... ptypes) throws Exception { + MethodType mt = MethodType.methodType(rtype, ptypes); + return lookup.findConstructor(clazz, mt); + } +} diff --git a/jdk/test/java/lang/invoke/modules/src/m1/p1/Type1.java b/jdk/test/java/lang/invoke/modules/m1/p1/Type1.java similarity index 100% rename from jdk/test/java/lang/invoke/modules/src/m1/p1/Type1.java rename to jdk/test/java/lang/invoke/modules/m1/p1/Type1.java diff --git a/jdk/test/java/lang/invoke/modules/src/m1/p2/Type2.java b/jdk/test/java/lang/invoke/modules/m1/p2/Type2.java similarity index 100% rename from jdk/test/java/lang/invoke/modules/src/m1/p2/Type2.java rename to jdk/test/java/lang/invoke/modules/m1/p2/Type2.java diff --git a/jdk/test/java/lang/invoke/modules/src/m2/module-info.java b/jdk/test/java/lang/invoke/modules/m2/module-info.java similarity index 100% rename from jdk/test/java/lang/invoke/modules/src/m2/module-info.java rename to jdk/test/java/lang/invoke/modules/m2/module-info.java diff --git a/jdk/test/java/lang/invoke/modules/src/m2/q1/Type1.java b/jdk/test/java/lang/invoke/modules/m2/q1/Type1.java similarity index 100% rename from jdk/test/java/lang/invoke/modules/src/m2/q1/Type1.java rename to jdk/test/java/lang/invoke/modules/m2/q1/Type1.java diff --git a/jdk/test/java/lang/invoke/modules/src/m2/q2/Type2.java b/jdk/test/java/lang/invoke/modules/m2/q2/Type2.java similarity index 100% rename from jdk/test/java/lang/invoke/modules/src/m2/q2/Type2.java rename to jdk/test/java/lang/invoke/modules/m2/q2/Type2.java diff --git a/jdk/test/java/lang/invoke/modules/src/m1/p1/Main.java b/jdk/test/java/lang/invoke/modules/src/m1/p1/Main.java deleted file mode 100644 index 3fd1a0eb43d..00000000000 --- a/jdk/test/java/lang/invoke/modules/src/m1/p1/Main.java +++ /dev/null @@ -1,225 +0,0 @@ -/* - * Copyright (c) 2015, 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 p1; - -import java.lang.invoke.MethodHandle; -import java.lang.invoke.MethodHandles; -import java.lang.invoke.MethodHandles.Lookup; -import java.lang.invoke.MethodType; - -/** - * Basic test case for module access check, supplements AccessControlTest. - * - * The tests consists of two modules: - * - * module m1 { requires m2; exports p1; } - * module m2 { exports q1; } - * - * Both modules read java.base (as every module reads java.base) - * - * module m1 has public types in packages p1 and p2, p2 is not exported. - * module m2 has public types in packages q1 and q2, q2 is not exported. - */ - -public class Main { - - static final int MODULE = Lookup.MODULE; - - // Use Class.forName to get classes for test because some - // are not accessible at compile-time - - static final Class p1_Type1; // m1, exported - static final Class p2_Type2; // m1, not exported - static final Class q1_Type1; // m2, exported, m1 reads m2 - static final Class q2_Type2; // m2, not exported, m1 reads m2 - static final Class x500NameClass; // java.base, not exported - - static { - try { - p1_Type1 = Class.forName("p1.Type1"); - p2_Type2 = Class.forName("p2.Type2"); - q1_Type1 = Class.forName("q1.Type1"); - q2_Type2 = Class.forName("q2.Type2"); - x500NameClass = Class.forName("sun.security.x509.X500Name"); - } catch (ClassNotFoundException e) { - throw new AssertionError(e); - } - } - - public static void main(String[] args) throws Exception { - Lookup lookup, lookup2; - - /** - * MethodHandles.lookup() - * has module access [A0] - * can access all public types in m1 [A1] - * can access public types in packages exported by modules that m1 reads [A2] - * cannot access public types in non-exported modules of modules that m1 reads [A3] - */ - lookup = MethodHandles.lookup(); - assertTrue((lookup.lookupModes() & MODULE) == MODULE); // [A0] - findConstructor(lookup, p1_Type1, void.class); // [A1] - findConstructor(lookup, p2_Type2, void.class); // [A1] - findConstructor(lookup, q1_Type1, void.class); // [A2] - findConstructorExpectingIAE(lookup, q2_Type2, void.class); // [A3] - findConstructor(lookup, Object.class, void.class); // [A2] - findConstructorExpectingIAE(lookup, x500NameClass, void.class, String.class); // [A3] - - /** - * Teleport from MethodHandles.lookup() to lookup class in the same module - * module access is retained [A0] - * can access all public types in m1 [A1] - * can access public types in packages exported by modules that m1 reads [A2] - * cannot access public types in non-exported modules of modules that m1 reads [A3] - */ - lookup2 = lookup.in(p2_Type2); - assertTrue((lookup2.lookupModes() & MODULE) == MODULE); // [A0] - findConstructor(lookup2, p1_Type1, void.class); // [A1] - findConstructor(lookup2, p2_Type2, void.class); // [A1] - findConstructor(lookup2, q1_Type1, void.class); // [A2] - findConstructorExpectingIAE(lookup2, q2_Type2, void.class); // [A3] - findConstructor(lookup2, Object.class, void.class); // [A2] - findConstructorExpectingIAE(lookup2, x500NameClass, void.class, String.class); // [A3] - - /** - * Teleport from MethodHandles.lookup() to lookup class in another named module - * has no access [A0] - */ - lookup2 = lookup.in(Object.class); - assertTrue(lookup2.lookupModes() == 0); // [A0] - findConstructorExpectingIAE(lookup2, Object.class, void.class); // [A0] - - /** - * Teleport from MethodHandles.lookup() to lookup class in an unnamed module - * has no access [A0] - */ - Class c = MethodHandles.publicLookup().lookupClass(); - assertTrue(!c.getModule().isNamed()); - lookup2 = lookup.in(c); - assertTrue(lookup2.lookupModes() == 0); // [A0] - findConstructorExpectingIAE(lookup2, Object.class, void.class); - - /** - * MethodHandles.publicLookup() - * has no module access [A0] - * can access public types in exported packages [A1] - * cannot access public types in non-exported packages [A2] - */ - lookup = MethodHandles.publicLookup(); - assertTrue((lookup.lookupModes() & MODULE) == 0); // [A0] - findConstructor(lookup, p1_Type1, void.class); // [A1] - findConstructorExpectingIAE(lookup, p2_Type2, void.class); // [A1] - findConstructor(lookup, q1_Type1, void.class); // [A1] - findConstructorExpectingIAE(lookup, q2_Type2, void.class); // [A2] - findConstructor(lookup, Object.class, void.class); // [A1] - findConstructorExpectingIAE(lookup, x500NameClass, void.class); // [A2] - - /** - * Teleport from MethodHandles.publicLookup() to lookup class in java.base - * has no module access [A0] - * can access public types in packages exported by java.base [A1] - * cannot access public types in non-exported packages [A2] - * no access to types in other named modules [A3] - */ - lookup2 = lookup.in(Object.class); - assertTrue((lookup2.lookupModes() & MODULE) == 0); // [A0] - findConstructor(lookup2, String.class, void.class); // [A1] - findConstructorExpectingIAE(lookup2, x500NameClass, void.class, String.class); // [A2] - findConstructorExpectingIAE(lookup2, p1_Type1, void.class); // [A3] - findConstructorExpectingIAE(lookup2, q1_Type1, void.class); // [A3] - - /** - * Teleport from MethodHandles.publicLookup() to lookup class in m1 - * has no module access [A0] - * can access public types in packages exported by m1, m2 and java.base [A1] - * cannot access public types is non-exported packages [A2] - */ - lookup2 = lookup.in(p1_Type1); - assertTrue((lookup2.lookupModes() & MODULE) == 0); // [A0] - findConstructor(lookup2, p1_Type1, void.class); // [A1] - findConstructor(lookup2, q1_Type1, void.class); // [A1] - findConstructor(lookup2, Object.class, void.class); // [A1] - findConstructorExpectingIAE(lookup, p2_Type2, void.class); // [A2] - findConstructorExpectingIAE(lookup, q2_Type2, void.class); // [A2] - findConstructorExpectingIAE(lookup2, x500NameClass, void.class, String.class); // [A2] - - /** - * Teleport from MethodHandles.publicLookup() to lookup class in m2 - * has no module access [A0] - * can access public types in packages exported by m2 and java.base [A1] - * cannot access public types is non-exported packages or modules that m2 does - * not read [A2] - */ - lookup2 = lookup.in(q1_Type1); - assertTrue((lookup2.lookupModes() & MODULE) == 0); // [A0] - findConstructor(lookup2, q1_Type1, void.class); // [A1] - findConstructor(lookup2, Object.class, void.class); // [A1] - findConstructorExpectingIAE(lookup2, p1_Type1, void.class); // [A2] - findConstructorExpectingIAE(lookup, q2_Type2, void.class); // [A2] - findConstructorExpectingIAE(lookup2, x500NameClass, void.class, String.class); // [A2] - - /** - * Teleport from MethodHandles.publicLookup() to lookup class that is not - * in an exported package, should get no access [A0] - */ - lookup2 = lookup.in(p2_Type2); - assertTrue(lookup2.lookupModes() == 0); // [A0] - findConstructorExpectingIAE(lookup, q2_Type2, void.class); // [A0] - } - - /** - * Invokes Lookup findConstructor with a method type constructored from the - * given return and parameter types, expecting IllegalAccessException to be - * thrown. - */ - static MethodHandle findConstructorExpectingIAE(Lookup lookup, - Class clazz, - Class rtype, - Class... ptypes) throws Exception { - try { - findConstructor(lookup, clazz, rtype, ptypes); - throw new RuntimeException("IllegalAccessError expected"); - } catch (IllegalAccessException expected) { - return null; - } - } - - /** - * Invokes Lookup findConstructor with a method type constructored from the - * given return and parameter types. - */ - static MethodHandle findConstructor(Lookup lookup, - Class clazz, - Class rtype, - Class... ptypes) throws Exception { - MethodType mt = MethodType.methodType(rtype, ptypes); - return lookup.findConstructor(clazz, mt); - } - - static void assertTrue(boolean condition) { - if (!condition) - throw new RuntimeException(); - } - -} diff --git a/jdk/test/java/lang/module/AutomaticModulesTest.java b/jdk/test/java/lang/module/AutomaticModulesTest.java index 07d25b9be85..1c020c309f2 100644 --- a/jdk/test/java/lang/module/AutomaticModulesTest.java +++ b/jdk/test/java/lang/module/AutomaticModulesTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2017, 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 @@ -33,10 +33,10 @@ import java.io.IOException; import java.lang.module.Configuration; import java.lang.module.FindException; import java.lang.module.ModuleDescriptor; -import java.lang.module.ModuleDescriptor.Exports; import java.lang.module.ModuleDescriptor.Requires.Modifier; import java.lang.module.ModuleFinder; import java.lang.module.ModuleReference; +import java.lang.module.ResolutionException; import java.lang.module.ResolvedModule; import java.lang.reflect.Layer; import java.lang.reflect.Module; @@ -137,6 +137,7 @@ public class AutomaticModulesTest { assertTrue(mref.isPresent(), mn + " not found"); ModuleDescriptor descriptor = mref.get().descriptor(); + assertTrue(descriptor.isAutomatic()); assertEquals(descriptor.name(), mn); if (vs == null) { assertFalse(descriptor.version().isPresent()); @@ -175,17 +176,14 @@ public class AutomaticModulesTest { assertTrue(mref.isPresent(), "m not found"); ModuleDescriptor descriptor = mref.get().descriptor(); + assertTrue(descriptor.isAutomatic()); assertTrue(descriptor.packages().size() == 2); assertTrue(descriptor.packages().contains("p")); assertTrue(descriptor.packages().contains("q")); - Set exports = descriptor.exports().stream() - .map(Exports::source) - .collect(Collectors.toSet()); - assertTrue(exports.size() == 2); - assertTrue(exports.contains("p")); - assertTrue(exports.contains("q")); + assertTrue(descriptor.exports().isEmpty()); + assertTrue(descriptor.opens().isEmpty()); } /** @@ -201,15 +199,13 @@ public class AutomaticModulesTest { assertTrue(mref.isPresent(), "m not found"); ModuleDescriptor descriptor = mref.get().descriptor(); + assertTrue(descriptor.isAutomatic()); assertTrue(descriptor.packages().size() == 1); assertTrue(descriptor.packages().contains("p")); - Set exports = descriptor.exports().stream() - .map(Exports::source) - .collect(Collectors.toSet()); - assertTrue(exports.size() == 1); - assertTrue(exports.contains("p")); + assertTrue(descriptor.exports().isEmpty()); + assertTrue(descriptor.opens().isEmpty()); } /** @@ -229,10 +225,10 @@ public class AutomaticModulesTest { assertTrue(mref.isPresent(), "m not found"); ModuleDescriptor descriptor = mref.get().descriptor(); + assertTrue(descriptor.isAutomatic()); - assertTrue(descriptor.packages().size() == 2); + assertTrue(descriptor.packages().size() == 1); assertTrue(descriptor.packages().contains("p")); - assertTrue(descriptor.packages().contains("p.resources")); } /** @@ -254,9 +250,17 @@ public class AutomaticModulesTest { String provider = "p.S1"; Path tmpdir = Files.createTempDirectory(USER_DIR, "tmp"); + + // provider class + Path providerClass = tmpdir.resolve(provider.replace('.', '/') + ".class"); + Files.createDirectories(providerClass.getParent()); + Files.createFile(providerClass); + + // services configuration file Path services = tmpdir.resolve("META-INF").resolve("services"); Files.createDirectories(services); Files.write(services.resolve(service), Set.of(provider)); + Path dir = Files.createTempDirectory(USER_DIR, "mods"); JarUtils.createJarFile(dir.resolve("m.jar"), tmpdir); @@ -314,7 +318,7 @@ public class AutomaticModulesTest { // service type provider type { "p.S", "-" }, - { "p.S", ".S1" }, + { "p.S", "p..S1" }, { "p.S", "S1." }, }; } @@ -324,13 +328,41 @@ public class AutomaticModulesTest { * values or names. */ @Test(dataProvider = "badproviders", expectedExceptions = FindException.class) - public void testBadProvideNames(String service, String provider) + public void testBadProviderNames(String service, String provider) throws IOException { Path tmpdir = Files.createTempDirectory(USER_DIR, "tmp"); + + // provider class + Path providerClass = tmpdir.resolve(provider.replace('.', '/') + ".class"); + Files.createDirectories(providerClass.getParent()); + Files.createFile(providerClass); + + // services configuration file Path services = tmpdir.resolve("META-INF").resolve("services"); Files.createDirectories(services); Files.write(services.resolve(service), Set.of(provider)); + + Path dir = Files.createTempDirectory(USER_DIR, "mods"); + JarUtils.createJarFile(dir.resolve("m.jar"), tmpdir); + + // should throw FindException + ModuleFinder.of(dir).findAll(); + } + + /** + * Test JAR file with META-INF/services configuration file listing a + * provider that is not in the module. + */ + @Test(expectedExceptions = FindException.class) + public void testMissingProviderPackage() throws IOException { + Path tmpdir = Files.createTempDirectory(USER_DIR, "tmp"); + + // services configuration file + Path services = tmpdir.resolve("META-INF").resolve("services"); + Files.createDirectories(services); + Files.write(services.resolve("p.S"), Set.of("q.P")); + Path dir = Files.createTempDirectory(USER_DIR, "mods"); JarUtils.createJarFile(dir.resolve("m.jar"), tmpdir); @@ -352,7 +384,8 @@ public class AutomaticModulesTest { attrs.put(Attributes.Name.MAIN_CLASS, mainClass); Path dir = Files.createTempDirectory(USER_DIR, "mods"); - createDummyJarFile(dir.resolve("m.jar"), man); + String entry = mainClass.replace('.', '/') + ".class"; + createDummyJarFile(dir.resolve("m.jar"), man, entry); ModuleFinder finder = ModuleFinder.of(dir); @@ -366,20 +399,21 @@ public class AutomaticModulesTest { } - // Main-Class files that do not map to a legal Java identifier + // Main-Class files that do not map to a legal qualified type name @DataProvider(name = "badmainclass") public Object[][] createBadMainClass() { return new Object[][]{ + { "Main", null }, + { "p..Main", null }, { "p-.Main", null }, - { ".Main", null } }; } /** - * Test that a JAR file with a Main-Class attribute that is not a valid - * Java identifier + * Test that a JAR file with a Main-Class attribute that is not a qualified + * type name. */ @Test(dataProvider = "badmainclass", expectedExceptions = FindException.class) public void testBadMainClass(String mainClass, String ignore) throws IOException { @@ -388,6 +422,24 @@ public class AutomaticModulesTest { attrs.put(Attributes.Name.MANIFEST_VERSION, "1.0.0"); attrs.put(Attributes.Name.MAIN_CLASS, mainClass); + Path dir = Files.createTempDirectory(USER_DIR, "mods"); + String entry = mainClass.replace('.', '/') + ".class"; + createDummyJarFile(dir.resolve("m.jar"), man, entry); + + // should throw FindException + ModuleFinder.of(dir).findAll(); + } + + /** + * Test that a JAR file with a Main-Class attribute that is not in the module + */ + @Test(expectedExceptions = FindException.class) + public void testMissingMainClassPackage() throws IOException { + Manifest man = new Manifest(); + Attributes attrs = man.getMainAttributes(); + attrs.put(Attributes.Name.MANIFEST_VERSION, "1.0.0"); + attrs.put(Attributes.Name.MAIN_CLASS, "p.Main"); + Path dir = Files.createTempDirectory(USER_DIR, "mods"); createDummyJarFile(dir.resolve("m.jar"), man); @@ -405,7 +457,7 @@ public class AutomaticModulesTest { */ public void testConfiguration1() throws Exception { ModuleDescriptor descriptor1 - = ModuleDescriptor.module("a") + = ModuleDescriptor.newModule("a") .requires("b") .requires("c") .requires("java.base") @@ -465,13 +517,13 @@ public class AutomaticModulesTest { */ public void testInConfiguration2() throws IOException { ModuleDescriptor descriptor1 - = ModuleDescriptor.module("a") + = ModuleDescriptor.newModule("a") .requires("b") .requires("java.base") .build(); ModuleDescriptor descriptor2 - = ModuleDescriptor.module("b") + = ModuleDescriptor.newModule("b") .requires("c") .requires("java.base") .build(); @@ -538,13 +590,13 @@ public class AutomaticModulesTest { */ public void testInConfiguration3() throws IOException { ModuleDescriptor descriptor1 - = ModuleDescriptor.module("a") + = ModuleDescriptor.newModule("a") .requires("b") .requires("java.base") .build(); ModuleDescriptor descriptor2 - = ModuleDescriptor.module("b") + = ModuleDescriptor.newModule("b") .requires(Set.of(Modifier.TRANSITIVE), "c") .requires("java.base") .build(); @@ -608,12 +660,68 @@ public class AutomaticModulesTest { } + /** + * Basic test of a configuration created with automatic modules + * a requires b* and c* + * b* contains p + * c* contains p + */ + @Test(expectedExceptions = { ResolutionException.class }) + public void testDuplicateSuppliers1() throws IOException { + ModuleDescriptor descriptor + = ModuleDescriptor.newModule("a") + .requires("b") + .requires("c") + .build(); + + // c and d are automatic modules with the same package + Path dir = Files.createTempDirectory(USER_DIR, "mods"); + createDummyJarFile(dir.resolve("b.jar"), "p/T.class"); + createDummyJarFile(dir.resolve("c.jar"), "p/T.class"); + + // module finder locates 'a' and the modules in the directory + ModuleFinder finder + = ModuleFinder.compose(ModuleUtils.finderOf(descriptor), + ModuleFinder.of(dir)); + + Configuration parent = Layer.boot().configuration(); + resolve(parent, finder, "a"); + } + + + /** + * Basic test of a configuration created with automatic modules + * a contains p, requires b* + * b* contains p + */ + @Test(expectedExceptions = { ResolutionException.class }) + public void testDuplicateSuppliers2() throws IOException { + ModuleDescriptor descriptor + = ModuleDescriptor.newModule("a") + .packages(Set.of("p")) + .requires("b") + .build(); + + // c and d are automatic modules with the same package + Path dir = Files.createTempDirectory(USER_DIR, "mods"); + createDummyJarFile(dir.resolve("b.jar"), "p/T.class"); + + // module finder locates 'a' and the modules in the directory + ModuleFinder finder + = ModuleFinder.compose(ModuleUtils.finderOf(descriptor), + ModuleFinder.of(dir)); + + Configuration parent = Layer.boot().configuration(); + resolve(parent, finder, "a"); + } + + /** * Basic test of Layer containing automatic modules */ public void testInLayer() throws IOException { ModuleDescriptor descriptor - = ModuleDescriptor.module("a") + = ModuleDescriptor.newModule("a") .requires("b") .requires("c") .build(); @@ -664,7 +772,7 @@ public class AutomaticModulesTest { // test miscellaneous methods assertTrue(m.isAutomatic()); - assertFalse(m.isSynthetic()); + assertFalse(m.modifiers().contains(ModuleDescriptor.Modifier.SYNTHETIC)); assertFalse(m.osName().isPresent()); assertFalse(m.osArch().isPresent()); assertFalse(m.osVersion().isPresent()); @@ -672,12 +780,12 @@ public class AutomaticModulesTest { /** - * Invokes parent.resolveRequires to resolve the given root modules. + * Invokes parent.resolve to resolve the given root modules. */ static Configuration resolve(Configuration parent, ModuleFinder finder, String... roots) { - return parent.resolveRequires(finder, ModuleFinder.of(), Set.of(roots)); + return parent.resolve(finder, ModuleFinder.of(), Set.of(roots)); } /** diff --git a/jdk/test/java/lang/module/ConfigurationTest.java b/jdk/test/java/lang/module/ConfigurationTest.java index 7ae867217c6..28f414736b1 100644 --- a/jdk/test/java/lang/module/ConfigurationTest.java +++ b/jdk/test/java/lang/module/ConfigurationTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2017, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -24,23 +24,26 @@ /** * @test * @library /lib/testlibrary + * @modules java.base/jdk.internal.misc * @build ConfigurationTest ModuleUtils * @run testng ConfigurationTest * @summary Basic tests for java.lang.module.Configuration */ import java.lang.module.Configuration; +import java.lang.module.FindException; import java.lang.module.ModuleDescriptor; +import java.lang.module.ModuleDescriptor.Builder; import java.lang.module.ModuleDescriptor.Requires; import java.lang.module.ModuleFinder; import java.lang.module.ResolutionException; import java.lang.module.ResolvedModule; import java.lang.reflect.Layer; -import java.util.HashSet; import java.util.List; import java.util.Optional; import java.util.Set; +import jdk.internal.misc.SharedSecrets; import org.testng.annotations.DataProvider; import org.testng.annotations.Test; import static org.testng.Assert.*; @@ -48,30 +51,35 @@ import static org.testng.Assert.*; @Test public class ConfigurationTest { + /** + * Creates a "non-strict" builder for building a module. This allows the + * test the create ModuleDescriptor objects that do not require java.base. + */ + private static ModuleDescriptor.Builder newBuilder(String mn) { + return SharedSecrets.getJavaLangModuleAccess() + .newModuleBuilder(mn, false, Set.of()); + } /** * Basic test of resolver * m1 requires m2, m2 requires m3 */ public void testBasic() { - ModuleDescriptor descriptor1 - = ModuleDescriptor.module("m1") + ModuleDescriptor descriptor1 = newBuilder("m1") .requires("m2") .build(); - ModuleDescriptor descriptor2 - = ModuleDescriptor.module("m2") + ModuleDescriptor descriptor2 = newBuilder("m2") .requires("m3") .build(); - ModuleDescriptor descriptor3 - = ModuleDescriptor.module("m3") + ModuleDescriptor descriptor3 = newBuilder("m3") .build(); ModuleFinder finder = ModuleUtils.finderOf(descriptor1, descriptor2, descriptor3); - Configuration cf = resolveRequires(finder, "m1"); + Configuration cf = resolve(finder, "m1"); assertTrue(cf.modules().size() == 3); @@ -110,24 +118,21 @@ public class ConfigurationTest { */ public void testRequiresTransitive1() { // m1 requires m2, m2 requires transitive m3 - ModuleDescriptor descriptor1 - = ModuleDescriptor.module("m1") + ModuleDescriptor descriptor1 = newBuilder("m1") .requires("m2") .build(); - ModuleDescriptor descriptor2 - = ModuleDescriptor.module("m2") + ModuleDescriptor descriptor2 = newBuilder("m2") .requires(Set.of(Requires.Modifier.TRANSITIVE), "m3") .build(); - ModuleDescriptor descriptor3 - = ModuleDescriptor.module("m3") + ModuleDescriptor descriptor3 = newBuilder("m3") .build(); ModuleFinder finder = ModuleUtils.finderOf(descriptor1, descriptor2, descriptor3); - Configuration cf = resolveRequires(finder, "m1"); + Configuration cf = resolve(finder, "m1"); assertTrue(cf.modules().size() == 3); @@ -167,18 +172,16 @@ public class ConfigurationTest { // cf1: m1 and m2, m2 requires transitive m1 - ModuleDescriptor descriptor1 - = ModuleDescriptor.module("m1") + ModuleDescriptor descriptor1 = newBuilder("m1") .build(); - ModuleDescriptor descriptor2 - = ModuleDescriptor.module("m2") + ModuleDescriptor descriptor2 = newBuilder("m2") .requires(Set.of(Requires.Modifier.TRANSITIVE), "m1") .build(); ModuleFinder finder1 = ModuleUtils.finderOf(descriptor1, descriptor2); - Configuration cf1 = resolveRequires(finder1, "m2"); + Configuration cf1 = resolve(finder1, "m2"); assertTrue(cf1.modules().size() == 2); assertTrue(cf1.findModule("m1").isPresent()); @@ -196,14 +199,13 @@ public class ConfigurationTest { // cf2: m3, m3 requires m2 - ModuleDescriptor descriptor3 - = ModuleDescriptor.module("m3") + ModuleDescriptor descriptor3 = newBuilder("m3") .requires("m2") .build(); ModuleFinder finder2 = ModuleUtils.finderOf(descriptor3); - Configuration cf2 = resolveRequires(cf1, finder2, "m3"); + Configuration cf2 = resolve(cf1, finder2, "m3"); assertTrue(cf2.modules().size() == 1); assertTrue(cf2.findModule("m1").isPresent()); // in parent @@ -231,13 +233,11 @@ public class ConfigurationTest { // cf1: m1 - ModuleDescriptor descriptor1 - = ModuleDescriptor.module("m1") - .build(); + ModuleDescriptor descriptor1 = newBuilder("m1").build(); ModuleFinder finder1 = ModuleUtils.finderOf(descriptor1); - Configuration cf1 = resolveRequires(finder1, "m1"); + Configuration cf1 = resolve(finder1, "m1"); assertTrue(cf1.modules().size() == 1); assertTrue(cf1.findModule("m1").isPresent()); @@ -250,19 +250,17 @@ public class ConfigurationTest { // cf2: m2, m3: m2 requires transitive m1, m3 requires m2 - ModuleDescriptor descriptor2 - = ModuleDescriptor.module("m2") + ModuleDescriptor descriptor2 = newBuilder("m2") .requires(Set.of(Requires.Modifier.TRANSITIVE), "m1") .build(); - ModuleDescriptor descriptor3 - = ModuleDescriptor.module("m3") + ModuleDescriptor descriptor3 = newBuilder("m3") .requires("m2") .build(); ModuleFinder finder2 = ModuleUtils.finderOf(descriptor2, descriptor3); - Configuration cf2 = resolveRequires(cf1, finder2, "m3"); + Configuration cf2 = resolve(cf1, finder2, "m3"); assertTrue(cf2.modules().size() == 2); assertTrue(cf2.findModule("m1").isPresent()); // in parent @@ -297,13 +295,11 @@ public class ConfigurationTest { // cf1: m1 - ModuleDescriptor descriptor1 - = ModuleDescriptor.module("m1") - .build(); + ModuleDescriptor descriptor1 = newBuilder("m1").build(); ModuleFinder finder1 = ModuleUtils.finderOf(descriptor1); - Configuration cf1 = resolveRequires(finder1, "m1"); + Configuration cf1 = resolve(finder1, "m1"); assertTrue(cf1.modules().size() == 1); assertTrue(cf1.findModule("m1").isPresent()); @@ -316,14 +312,13 @@ public class ConfigurationTest { // cf2: m2 requires transitive m1 - ModuleDescriptor descriptor2 - = ModuleDescriptor.module("m2") + ModuleDescriptor descriptor2 = newBuilder("m2") .requires(Set.of(Requires.Modifier.TRANSITIVE), "m1") .build(); ModuleFinder finder2 = ModuleUtils.finderOf(descriptor2); - Configuration cf2 = resolveRequires(cf1, finder2, "m2"); + Configuration cf2 = resolve(cf1, finder2, "m2"); assertTrue(cf2.modules().size() == 1); assertTrue(cf2.findModule("m1").isPresent()); // in parent @@ -340,14 +335,13 @@ public class ConfigurationTest { // cf3: m3 requires m2 - ModuleDescriptor descriptor3 - = ModuleDescriptor.module("m3") + ModuleDescriptor descriptor3 = newBuilder("m3") .requires("m2") .build(); ModuleFinder finder3 = ModuleUtils.finderOf(descriptor3); - Configuration cf3 = resolveRequires(cf2, finder3, "m3"); + Configuration cf3 = resolve(cf2, finder3, "m3"); assertTrue(cf3.modules().size() == 1); assertTrue(cf3.findModule("m1").isPresent()); // in parent @@ -376,18 +370,16 @@ public class ConfigurationTest { // cf1: m1, m2 requires transitive m1 - ModuleDescriptor descriptor1 - = ModuleDescriptor.module("m1") + ModuleDescriptor descriptor1 = newBuilder("m1") .build(); - ModuleDescriptor descriptor2 - = ModuleDescriptor.module("m2") + ModuleDescriptor descriptor2 = newBuilder("m2") .requires(Set.of(Requires.Modifier.TRANSITIVE), "m1") .build(); ModuleFinder finder1 = ModuleUtils.finderOf(descriptor1, descriptor2); - Configuration cf1 = resolveRequires(finder1, "m2"); + Configuration cf1 = resolve(finder1, "m2"); assertTrue(cf1.modules().size() == 2); assertTrue(cf1.findModule("m1").isPresent()); @@ -408,20 +400,18 @@ public class ConfigurationTest { // cf2: m3 requires transitive m2, m4 requires m3 - ModuleDescriptor descriptor3 - = ModuleDescriptor.module("m3") + ModuleDescriptor descriptor3 = newBuilder("m3") .requires(Set.of(Requires.Modifier.TRANSITIVE), "m2") .build(); - ModuleDescriptor descriptor4 - = ModuleDescriptor.module("m4") + ModuleDescriptor descriptor4 = newBuilder("m4") .requires("m3") .build(); ModuleFinder finder2 = ModuleUtils.finderOf(descriptor3, descriptor4); - Configuration cf2 = resolveRequires(cf1, finder2, "m3", "m4"); + Configuration cf2 = resolve(cf1, finder2, "m3", "m4"); assertTrue(cf2.modules().size() == 2); assertTrue(cf2.findModule("m1").isPresent()); // in parent @@ -456,28 +446,24 @@ public class ConfigurationTest { * - Configuration cf3(cf1,cf2): m4 requires m2, m3 */ public void testRequiresTransitive6() { - ModuleDescriptor descriptor1 - = ModuleDescriptor.module("m1") + ModuleDescriptor descriptor1 = newBuilder("m1") .build(); - ModuleDescriptor descriptor2 - = ModuleDescriptor.module("m2") + ModuleDescriptor descriptor2 = newBuilder("m2") .requires(Set.of(Requires.Modifier.TRANSITIVE), "m1") .build(); - ModuleDescriptor descriptor3 - = ModuleDescriptor.module("m3") + ModuleDescriptor descriptor3 = newBuilder("m3") .requires(Set.of(Requires.Modifier.TRANSITIVE), "m1") .build(); - ModuleDescriptor descriptor4 - = ModuleDescriptor.module("m4") + ModuleDescriptor descriptor4 = newBuilder("m4") .requires("m2") .requires("m3") .build(); ModuleFinder finder1 = ModuleUtils.finderOf(descriptor1, descriptor2); - Configuration cf1 = resolveRequires(finder1, "m2"); + Configuration cf1 = resolve(finder1, "m2"); assertTrue(cf1.modules().size() == 2); assertTrue(cf1.findModule("m1").isPresent()); assertTrue(cf1.findModule("m2").isPresent()); @@ -485,7 +471,7 @@ public class ConfigurationTest { assertTrue(cf1.parents().get(0) == Configuration.empty()); ModuleFinder finder2 = ModuleUtils.finderOf(descriptor1, descriptor3); - Configuration cf2 = resolveRequires(finder2, "m3"); + Configuration cf2 = resolve(finder2, "m3"); assertTrue(cf2.modules().size() == 2); assertTrue(cf2.findModule("m3").isPresent()); assertTrue(cf2.findModule("m1").isPresent()); @@ -493,7 +479,7 @@ public class ConfigurationTest { assertTrue(cf2.parents().get(0) == Configuration.empty()); ModuleFinder finder3 = ModuleUtils.finderOf(descriptor4); - Configuration cf3 = Configuration.resolveRequires(finder3, + Configuration cf3 = Configuration.resolve(finder3, List.of(cf1, cf2), ModuleFinder.of(), Set.of("m4")); @@ -522,14 +508,13 @@ public class ConfigurationTest { * resolve m1 */ public void testRequiresStatic1() { - ModuleDescriptor descriptor1 - = ModuleDescriptor.module("m1") + ModuleDescriptor descriptor1 = newBuilder("m1") .requires(Set.of(Requires.Modifier.STATIC), "m2") .build(); ModuleFinder finder = ModuleUtils.finderOf(descriptor1); - Configuration cf = resolveRequires(finder, "m1"); + Configuration cf = resolve(finder, "m1"); assertTrue(cf.modules().size() == 1); @@ -545,18 +530,16 @@ public class ConfigurationTest { * resolve m1 */ public void testRequiresStatic2() { - ModuleDescriptor descriptor1 - = ModuleDescriptor.module("m1") + ModuleDescriptor descriptor1 = newBuilder("m1") .requires(Set.of(Requires.Modifier.STATIC), "m2") .build(); - ModuleDescriptor descriptor2 - = ModuleDescriptor.module("m2") + ModuleDescriptor descriptor2 = newBuilder("m2") .build(); ModuleFinder finder = ModuleUtils.finderOf(descriptor1, descriptor2); - Configuration cf = resolveRequires(finder, "m1"); + Configuration cf = resolve(finder, "m1"); assertTrue(cf.modules().size() == 1); @@ -572,18 +555,16 @@ public class ConfigurationTest { * resolve m1, m2 */ public void testRequiresStatic3() { - ModuleDescriptor descriptor1 - = ModuleDescriptor.module("m1") + ModuleDescriptor descriptor1 = newBuilder("m1") .requires(Set.of(Requires.Modifier.STATIC), "m2") .build(); - ModuleDescriptor descriptor2 - = ModuleDescriptor.module("m2") + ModuleDescriptor descriptor2 = newBuilder("m2") .build(); ModuleFinder finder = ModuleUtils.finderOf(descriptor1, descriptor2); - Configuration cf = resolveRequires(finder, "m1", "m2"); + Configuration cf = resolve(finder, "m1", "m2"); assertTrue(cf.modules().size() == 2); @@ -604,25 +585,22 @@ public class ConfigurationTest { * m3 */ public void testRequiresStatic4() { - ModuleDescriptor descriptor1 - = ModuleDescriptor.module("m1") + ModuleDescriptor descriptor1 = newBuilder("m1") .requires("m2") .requires("m3") .build(); - ModuleDescriptor descriptor2 - = ModuleDescriptor.module("m2") + ModuleDescriptor descriptor2 = newBuilder("m2") .requires(Set.of(Requires.Modifier.STATIC), "m3") .build(); - ModuleDescriptor descriptor3 - = ModuleDescriptor.module("m3") + ModuleDescriptor descriptor3 = newBuilder("m3") .build(); ModuleFinder finder - = ModuleUtils.finderOf(descriptor1, descriptor2, descriptor3); + = ModuleUtils.finderOf(descriptor1, descriptor2, descriptor3); - Configuration cf = resolveRequires(finder, "m1"); + Configuration cf = resolve(finder, "m1"); assertTrue(cf.modules().size() == 3); @@ -648,31 +626,28 @@ public class ConfigurationTest { * - Configuration cf2: m3 requires m1, requires static m2 */ public void testRequiresStatic5() { - ModuleDescriptor descriptor1 - = ModuleDescriptor.module("m1") + ModuleDescriptor descriptor1 = newBuilder("m1") .build(); - ModuleDescriptor descriptor2 - = ModuleDescriptor.module("m2") + ModuleDescriptor descriptor2 = newBuilder("m2") .build(); ModuleFinder finder1 = ModuleUtils.finderOf(descriptor1, descriptor2); - Configuration cf1 = resolveRequires(finder1, "m1", "m2"); + Configuration cf1 = resolve(finder1, "m1", "m2"); assertTrue(cf1.modules().size() == 2); assertTrue(cf1.findModule("m1").isPresent()); assertTrue(cf1.findModule("m2").isPresent()); - ModuleDescriptor descriptor3 - = ModuleDescriptor.module("m3") + ModuleDescriptor descriptor3 = newBuilder("m3") .requires("m1") .requires(Set.of(Requires.Modifier.STATIC), "m2") .build(); ModuleFinder finder2 = ModuleUtils.finderOf(descriptor3); - Configuration cf2 = resolveRequires(cf1, finder2, "m3"); + Configuration cf2 = resolve(cf1, finder2, "m3"); assertTrue(cf2.modules().size() == 1); assertTrue(cf2.findModule("m3").isPresent()); @@ -694,26 +669,24 @@ public class ConfigurationTest { * - Configuration cf2: m3 requires m1, requires static m2 */ public void testRequiresStatic6() { - ModuleDescriptor descriptor1 - = ModuleDescriptor.module("m1") + ModuleDescriptor descriptor1 = newBuilder("m1") .build(); ModuleFinder finder1 = ModuleUtils.finderOf(descriptor1); - Configuration cf1 = resolveRequires(finder1, "m1"); + Configuration cf1 = resolve(finder1, "m1"); assertTrue(cf1.modules().size() == 1); assertTrue(cf1.findModule("m1").isPresent()); - ModuleDescriptor descriptor3 - = ModuleDescriptor.module("m3") + ModuleDescriptor descriptor3 = newBuilder("m3") .requires("m1") .requires(Set.of(Requires.Modifier.STATIC), "m2") .build(); ModuleFinder finder2 = ModuleUtils.finderOf(descriptor3); - Configuration cf2 = resolveRequires(cf1, finder2, "m3"); + Configuration cf2 = resolve(cf1, finder2, "m3"); assertTrue(cf2.modules().size() == 1); assertTrue(cf2.findModule("m3").isPresent()); @@ -735,21 +708,19 @@ public class ConfigurationTest { public void testRequiresStatic7() { ModuleDescriptor descriptor1 = null; // not observable - ModuleDescriptor descriptor2 - = ModuleDescriptor.module("m2") + ModuleDescriptor descriptor2 = newBuilder("m2") .requires(Set.of(Requires.Modifier.TRANSITIVE, Requires.Modifier.STATIC), "m1") .build(); - ModuleDescriptor descriptor3 - = ModuleDescriptor.module("m3") + ModuleDescriptor descriptor3 = newBuilder("m3") .requires("m2") .build(); ModuleFinder finder = ModuleUtils.finderOf(descriptor2, descriptor3); - Configuration cf = resolveRequires(finder, "m3"); + Configuration cf = resolve(finder, "m3"); assertTrue(cf.modules().size() == 2); assertTrue(cf.findModule("m2").isPresent()); @@ -770,8 +741,7 @@ public class ConfigurationTest { public void testRequiresStatic8() { ModuleDescriptor descriptor1 = null; // not observable - ModuleDescriptor descriptor2 - = ModuleDescriptor.module("m2") + ModuleDescriptor descriptor2 = newBuilder("m2") .requires(Set.of(Requires.Modifier.TRANSITIVE, Requires.Modifier.STATIC), "m1") @@ -779,21 +749,20 @@ public class ConfigurationTest { ModuleFinder finder1 = ModuleUtils.finderOf(descriptor2); - Configuration cf1 = resolveRequires(finder1, "m2"); + Configuration cf1 = resolve(finder1, "m2"); assertTrue(cf1.modules().size() == 1); assertTrue(cf1.findModule("m2").isPresent()); ResolvedModule m2 = cf1.findModule("m2").get(); assertTrue(m2.reads().isEmpty()); - ModuleDescriptor descriptor3 - = ModuleDescriptor.module("m3") + ModuleDescriptor descriptor3 = newBuilder("m3") .requires("m2") .build(); ModuleFinder finder2 = ModuleUtils.finderOf(descriptor3); - Configuration cf2 = resolveRequires(cf1, finder2, "m3"); + Configuration cf2 = resolve(cf1, finder2, "m3"); assertTrue(cf2.modules().size() == 1); assertTrue(cf2.findModule("m3").isPresent()); @@ -810,22 +779,19 @@ public class ConfigurationTest { */ public void testServiceBinding1() { - ModuleDescriptor descriptor1 - = ModuleDescriptor.module("m1") + ModuleDescriptor descriptor1 = newBuilder("m1") .exports("p") .uses("p.S") .build(); - ModuleDescriptor descriptor2 - = ModuleDescriptor.module("m2") + ModuleDescriptor descriptor2 = newBuilder("m2") .requires("m1") - .contains("q") - .provides("p.S", "q.T") + .provides("p.S", List.of("q.T")) .build(); ModuleFinder finder = ModuleUtils.finderOf(descriptor1, descriptor2); - Configuration cf = resolveRequiresAndUses(finder, "m1"); + Configuration cf = resolveAndBind(finder, "m1"); assertTrue(cf.modules().size() == 2); assertTrue(cf.findModule("m1").isPresent()); @@ -853,31 +819,26 @@ public class ConfigurationTest { */ public void testServiceBinding2() { - ModuleDescriptor descriptor1 - = ModuleDescriptor.module("m1") + ModuleDescriptor descriptor1 = newBuilder("m1") .exports("p") .uses("p.S1") .build(); - ModuleDescriptor descriptor2 - = ModuleDescriptor.module("m2") + ModuleDescriptor descriptor2 = newBuilder("m2") .requires("m1") .uses("p.S2") - .contains("q") - .provides("p.S1", "q.Service1Impl") + .provides("p.S1", List.of("q.Service1Impl")) .build(); - ModuleDescriptor descriptor3 - = ModuleDescriptor.module("m3") + ModuleDescriptor descriptor3 = newBuilder("m3") .requires("m1") - .contains("q") - .provides("p.S2", "q.Service2Impl") + .provides("p.S2", List.of("q.Service2Impl")) .build(); ModuleFinder finder = ModuleUtils.finderOf(descriptor1, descriptor2, descriptor3); - Configuration cf = resolveRequiresAndUses(finder, "m1"); + Configuration cf = resolveAndBind(finder, "m1"); assertTrue(cf.modules().size() == 3); assertTrue(cf.findModule("m1").isPresent()); @@ -912,29 +873,26 @@ public class ConfigurationTest { */ public void testServiceBindingWithConfigurations1() { - ModuleDescriptor descriptor1 - = ModuleDescriptor.module("m1") + ModuleDescriptor descriptor1 = newBuilder("m1") .exports("p") .uses("p.S") .build(); ModuleFinder finder1 = ModuleUtils.finderOf(descriptor1); - Configuration cf1 = resolveRequires(finder1, "m1"); + Configuration cf1 = resolve(finder1, "m1"); assertTrue(cf1.modules().size() == 1); assertTrue(cf1.findModule("m1").isPresent()); - ModuleDescriptor descriptor2 - = ModuleDescriptor.module("m2") + ModuleDescriptor descriptor2 = newBuilder("m2") .requires("m1") - .contains("q") - .provides("p.S", "q.T") + .provides("p.S", List.of("q.T")) .build(); ModuleFinder finder2 = ModuleUtils.finderOf(descriptor2); - Configuration cf2 = resolveRequiresAndUses(cf1, finder2); // no roots + Configuration cf2 = resolveAndBind(cf1, finder2); // no roots assertTrue(cf2.parents().size() == 1); assertTrue(cf2.parents().get(0) == cf1); @@ -961,47 +919,39 @@ public class ConfigurationTest { */ public void testServiceBindingWithConfigurations2() { - ModuleDescriptor descriptor1 - = ModuleDescriptor.module("m1") + ModuleDescriptor descriptor1 = newBuilder("m1") .exports("p") .uses("p.S") - .contains("p1") - .provides("p.S", "p1.ServiceImpl") + .provides("p.S", List.of("p1.ServiceImpl")) .build(); - ModuleDescriptor descriptor2 - = ModuleDescriptor.module("m2") + ModuleDescriptor descriptor2 = newBuilder("m2") .requires("m1") - .contains("p2") - .provides("p.S", "p2.ServiceImpl") + .provides("p.S", List.of("p2.ServiceImpl")) .build(); ModuleFinder finder1 = ModuleUtils.finderOf(descriptor1, descriptor2); - Configuration cf1 = resolveRequiresAndUses(finder1, "m1"); + Configuration cf1 = resolveAndBind(finder1, "m1"); assertTrue(cf1.modules().size() == 2); assertTrue(cf1.findModule("m1").isPresent()); assertTrue(cf1.findModule("m2").isPresent()); - ModuleDescriptor descriptor3 - = ModuleDescriptor.module("m3") + ModuleDescriptor descriptor3 = newBuilder("m3") .requires("m1") - .contains("p3") - .provides("p.S", "p3.ServiceImpl") + .provides("p.S", List.of("p3.ServiceImpl")) .build(); - ModuleDescriptor descriptor4 - = ModuleDescriptor.module("m4") + ModuleDescriptor descriptor4 = newBuilder("m4") .requires("m1") - .contains("p4") - .provides("p.S", "p4.ServiceImpl") + .provides("p.S", List.of("p4.ServiceImpl")) .build(); ModuleFinder finder2 = ModuleUtils.finderOf(descriptor3, descriptor4); - Configuration cf2 = resolveRequiresAndUses(cf1, finder2); // no roots + Configuration cf2 = resolveAndBind(cf1, finder2); // no roots assertTrue(cf2.parents().size() == 1); assertTrue(cf2.parents().get(0) == cf1); @@ -1037,22 +987,19 @@ public class ConfigurationTest { */ public void testServiceBindingWithConfigurations3() { - ModuleDescriptor service - = ModuleDescriptor.module("s") + ModuleDescriptor service = newBuilder("s") .exports("p") .build(); - ModuleDescriptor provider_v1 - = ModuleDescriptor.module("p") + ModuleDescriptor provider_v1 = newBuilder("p") .version("1.0") .requires("s") - .contains("q") - .provides("p.S", "q.T") + .provides("p.S", List.of("q.T")) .build(); ModuleFinder finder1 = ModuleUtils.finderOf(service, provider_v1); - Configuration cf1 = resolveRequires(finder1, "p"); + Configuration cf1 = resolve(finder1, "p"); assertTrue(cf1.modules().size() == 2); assertTrue(cf1.findModule("s").isPresent()); @@ -1063,18 +1010,15 @@ public class ConfigurationTest { assertEquals(p.reference().descriptor(), provider_v1); - ModuleDescriptor descriptor1 - = ModuleDescriptor.module("m1") + ModuleDescriptor descriptor1 = newBuilder("m1") .requires("s") .uses("p.S") .build(); - ModuleDescriptor provider_v2 - = ModuleDescriptor.module("p") + ModuleDescriptor provider_v2 = newBuilder("p") .version("2.0") .requires("s") - .contains("q") - .provides("p.S", "q.T") + .provides("p.S", List.of("q.T")) .build(); ModuleFinder finder2 = ModuleUtils.finderOf(descriptor1, provider_v2); @@ -1082,7 +1026,7 @@ public class ConfigurationTest { // finder2 is the before ModuleFinder and so p@2.0 should be located - Configuration cf2 = resolveRequiresAndUses(cf1, finder2, "m1"); + Configuration cf2 = resolveAndBind(cf1, finder2, "m1"); assertTrue(cf2.parents().size() == 1); assertTrue(cf2.parents().get(0) == cf1); @@ -1097,7 +1041,7 @@ public class ConfigurationTest { // finder2 is the after ModuleFinder and so p@2.0 should not be located // as module p is in parent configuration. - cf2 = resolveRequiresAndUses(cf1, ModuleFinder.of(), finder2, "m1"); + cf2 = resolveAndBind(cf1, ModuleFinder.of(), finder2, "m1"); assertTrue(cf2.parents().size() == 1); assertTrue(cf2.parents().get(0) == cf1); @@ -1117,25 +1061,22 @@ public class ConfigurationTest { */ public void testWithTwoFinders1() { - ModuleDescriptor descriptor1 - = ModuleDescriptor.module("m1") + ModuleDescriptor descriptor1 = newBuilder("m1") .requires("m2") .build(); - ModuleDescriptor descriptor2_v1 - = ModuleDescriptor.module("m2") + ModuleDescriptor descriptor2_v1 = newBuilder("m2") .version("1.0") .build(); - ModuleDescriptor descriptor2_v2 - = ModuleDescriptor.module("m2") + ModuleDescriptor descriptor2_v2 = newBuilder("m2") .version("2.0") .build(); ModuleFinder finder1 = ModuleUtils.finderOf(descriptor2_v1); ModuleFinder finder2 = ModuleUtils.finderOf(descriptor1, descriptor2_v2); - Configuration cf = resolveRequires(finder1, finder2, "m1"); + Configuration cf = resolve(finder1, finder2, "m1"); assertTrue(cf.modules().size() == 2); assertTrue(cf.findModule("m1").isPresent()); @@ -1157,30 +1098,25 @@ public class ConfigurationTest { */ public void testWithTwoFinders2() { - ModuleDescriptor descriptor1 - = ModuleDescriptor.module("m1") + ModuleDescriptor descriptor1 = newBuilder("m1") .exports("p") .uses("p.S") .build(); - ModuleDescriptor descriptor2_v1 - = ModuleDescriptor.module("m2") + ModuleDescriptor descriptor2_v1 = newBuilder("m2") .requires("m1") - .contains("q") - .provides("p.S", "q.T") + .provides("p.S", List.of("q.T")) .build(); - ModuleDescriptor descriptor2_v2 - = ModuleDescriptor.module("m2") + ModuleDescriptor descriptor2_v2 = newBuilder("m2") .requires("m1") - .contains("q") - .provides("p.S", "q.T") + .provides("p.S", List.of("q.T")) .build(); ModuleFinder finder1 = ModuleUtils.finderOf(descriptor1, descriptor2_v1); ModuleFinder finder2 = ModuleUtils.finderOf(descriptor2_v2); - Configuration cf = resolveRequiresAndUses(finder1, finder2, "m1"); + Configuration cf = resolveAndBind(finder1, finder2, "m1"); assertTrue(cf.modules().size() == 2); assertTrue(cf.findModule("m1").isPresent()); @@ -1200,18 +1136,17 @@ public class ConfigurationTest { */ public void testResolvedInParent1() { - ModuleDescriptor descriptor1 - = ModuleDescriptor.module("m1") + ModuleDescriptor descriptor1 = newBuilder("m1") .build(); ModuleFinder finder = ModuleUtils.finderOf(descriptor1); - Configuration cf1 = resolveRequires(finder, "m1"); + Configuration cf1 = resolve(finder, "m1"); assertTrue(cf1.modules().size() == 1); assertTrue(cf1.findModule("m1").isPresent()); - Configuration cf2 = resolveRequires(cf1, finder, "m1"); + Configuration cf2 = resolve(cf1, finder, "m1"); assertTrue(cf2.modules().size() == 1); } @@ -1223,26 +1158,23 @@ public class ConfigurationTest { */ public void testResolvedInParent2() { - ModuleDescriptor descriptor1 - = ModuleDescriptor.module("m1") - .build(); + ModuleDescriptor descriptor1 = newBuilder("m1").build(); ModuleFinder finder1 = ModuleUtils.finderOf(descriptor1); - Configuration cf1 = resolveRequires(finder1, "m1"); + Configuration cf1 = resolve(finder1, "m1"); assertTrue(cf1.modules().size() == 1); assertTrue(cf1.findModule("m1").isPresent()); - ModuleDescriptor descriptor2 - = ModuleDescriptor.module("m2") + ModuleDescriptor descriptor2 = newBuilder("m2") .requires("m1") .build(); ModuleFinder finder2 = ModuleUtils.finderOf(descriptor2); - Configuration cf2 = resolveRequires(cf1, ModuleFinder.of(), finder2, "m2"); + Configuration cf2 = resolve(cf1, ModuleFinder.of(), finder2, "m2"); assertTrue(cf2.modules().size() == 1); assertTrue(cf2.findModule("m2").isPresent()); @@ -1268,29 +1200,28 @@ public class ConfigurationTest { public void testResolvedInMultipleParents1() { // Configuration cf1: m1 - ModuleDescriptor descriptor1 = ModuleDescriptor.module("m1").build(); - Configuration cf1 = resolveRequires(ModuleUtils.finderOf(descriptor1), "m1"); + ModuleDescriptor descriptor1 = newBuilder("m1").build(); + Configuration cf1 = resolve(ModuleUtils.finderOf(descriptor1), "m1"); assertEquals(cf1.parents(), List.of(Configuration.empty())); assertTrue(cf1.findModule("m1").isPresent()); ResolvedModule m1 = cf1.findModule("m1").get(); assertTrue(m1.configuration() == cf1); // Configuration cf2: m2 - ModuleDescriptor descriptor2 = ModuleDescriptor.module("m2").build(); - Configuration cf2 = resolveRequires(ModuleUtils.finderOf(descriptor2), "m2"); + ModuleDescriptor descriptor2 = newBuilder("m2").build(); + Configuration cf2 = resolve(ModuleUtils.finderOf(descriptor2), "m2"); assertEquals(cf2.parents(), List.of(Configuration.empty())); assertTrue(cf2.findModule("m2").isPresent()); ResolvedModule m2 = cf2.findModule("m2").get(); assertTrue(m2.configuration() == cf2); // Configuration cf3(cf1,cf2): m3 requires m1 and m2 - ModuleDescriptor descriptor3 - = ModuleDescriptor.module("m3") + ModuleDescriptor descriptor3 = newBuilder("m3") .requires("m1") .requires("m2") .build(); ModuleFinder finder = ModuleUtils.finderOf(descriptor3); - Configuration cf3 = Configuration.resolveRequires( + Configuration cf3 = Configuration.resolve( finder, List.of(cf1, cf2), // parents ModuleFinder.of(), @@ -1319,19 +1250,18 @@ public class ConfigurationTest { */ public void testResolvedInMultipleParents2() { // Configuration cf1: m1 - ModuleDescriptor descriptor1 = ModuleDescriptor.module("m1").build(); - Configuration cf1 = resolveRequires(ModuleUtils.finderOf(descriptor1), "m1"); + ModuleDescriptor descriptor1 = newBuilder("m1").build(); + Configuration cf1 = resolve(ModuleUtils.finderOf(descriptor1), "m1"); assertEquals(cf1.parents(), List.of(Configuration.empty())); assertTrue(cf1.findModule("m1").isPresent()); ResolvedModule m1 = cf1.findModule("m1").get(); assertTrue(m1.configuration() == cf1); // Configuration cf2(cf1): m2 requires m1 - ModuleDescriptor descriptor2 - = ModuleDescriptor.module("m2") + ModuleDescriptor descriptor2 = newBuilder("m2") .requires("m1") .build(); - Configuration cf2 = Configuration.resolveRequires( + Configuration cf2 = Configuration.resolve( ModuleUtils.finderOf(descriptor2), List.of(cf1), // parents ModuleFinder.of(), @@ -1342,11 +1272,10 @@ public class ConfigurationTest { assertTrue(m2.configuration() == cf2); // Configuration cf3(cf1): m3 requires m1 - ModuleDescriptor descriptor3 - = ModuleDescriptor.module("m3") + ModuleDescriptor descriptor3 = newBuilder("m3") .requires("m1") .build(); - Configuration cf3 = Configuration.resolveRequires( + Configuration cf3 = Configuration.resolve( ModuleUtils.finderOf(descriptor3), List.of(cf1), // parents ModuleFinder.of(), @@ -1357,13 +1286,12 @@ public class ConfigurationTest { assertTrue(m3.configuration() == cf3); // Configuration cf4(cf2,cf3): m4 requires m1,m2,m3 - ModuleDescriptor descriptor4 - = ModuleDescriptor.module("m4") + ModuleDescriptor descriptor4 = newBuilder("m4") .requires("m1") .requires("m2") .requires("m3") .build(); - Configuration cf4 = Configuration.resolveRequires( + Configuration cf4 = Configuration.resolve( ModuleUtils.finderOf(descriptor4), List.of(cf2, cf3), // parents ModuleFinder.of(), @@ -1395,35 +1323,34 @@ public class ConfigurationTest { ModuleDescriptor descriptor1, descriptor2, descriptor3; // Configuration cf1: m1@1 - descriptor1 = ModuleDescriptor.module("m1").version("1").build(); - Configuration cf1 = resolveRequires(ModuleUtils.finderOf(descriptor1), "m1"); + descriptor1 = newBuilder("m1").version("1").build(); + Configuration cf1 = resolve(ModuleUtils.finderOf(descriptor1), "m1"); assertEquals(cf1.parents(), List.of(Configuration.empty())); // Configuration cf2: m1@2, m2@2 - descriptor1 = ModuleDescriptor.module("m1").version("2").build(); - descriptor2 = ModuleDescriptor.module("m2").version("2").build(); - Configuration cf2 = resolveRequires( + descriptor1 = newBuilder("m1").version("2").build(); + descriptor2 = newBuilder("m2").version("2").build(); + Configuration cf2 = resolve( ModuleUtils.finderOf(descriptor1, descriptor2), "m1", "m2"); assertEquals(cf2.parents(), List.of(Configuration.empty())); // Configuration cf3: m1@3, m2@3, m3@3 - descriptor1 = ModuleDescriptor.module("m1").version("3").build(); - descriptor2 = ModuleDescriptor.module("m2").version("3").build(); - descriptor3 = ModuleDescriptor.module("m3").version("3").build(); - Configuration cf3 = resolveRequires( + descriptor1 = newBuilder("m1").version("3").build(); + descriptor2 = newBuilder("m2").version("3").build(); + descriptor3 = newBuilder("m3").version("3").build(); + Configuration cf3 = resolve( ModuleUtils.finderOf(descriptor1, descriptor2, descriptor3), "m1", "m2", "m3"); assertEquals(cf3.parents(), List.of(Configuration.empty())); // Configuration cf4(cf1,cf2,cf3): m4 requires m1,m2,m3 - ModuleDescriptor descriptor4 - = ModuleDescriptor.module("m4") + ModuleDescriptor descriptor4 = newBuilder("m4") .requires("m1") .requires("m2") .requires("m3") .build(); - Configuration cf4 = Configuration.resolveRequires( + Configuration cf4 = Configuration.resolve( ModuleUtils.finderOf(descriptor4), List.of(cf1, cf2, cf3), // parents ModuleFinder.of(), @@ -1470,17 +1397,15 @@ public class ConfigurationTest { * configuration. */ public void testOverriding1() { - ModuleDescriptor descriptor1 - = ModuleDescriptor.module("m1") - .build(); + ModuleDescriptor descriptor1 = newBuilder("m1").build(); ModuleFinder finder = ModuleUtils.finderOf(descriptor1); - Configuration cf1 = resolveRequires(finder, "m1"); + Configuration cf1 = resolve(finder, "m1"); assertTrue(cf1.modules().size() == 1); assertTrue(cf1.findModule("m1").isPresent()); - Configuration cf2 = resolveRequires(cf1, finder, "m1"); + Configuration cf2 = resolve(cf1, finder, "m1"); assertTrue(cf2.modules().size() == 1); assertTrue(cf2.findModule("m1").isPresent()); } @@ -1490,24 +1415,24 @@ public class ConfigurationTest { * configuration. */ public void testOverriding2() { - ModuleDescriptor descriptor1 = ModuleDescriptor.module("m1").build(); - Configuration cf1 = resolveRequires(ModuleUtils.finderOf(descriptor1), "m1"); + ModuleDescriptor descriptor1 = newBuilder("m1").build(); + Configuration cf1 = resolve(ModuleUtils.finderOf(descriptor1), "m1"); assertTrue(cf1.modules().size() == 1); assertTrue(cf1.findModule("m1").isPresent()); - ModuleDescriptor descriptor2 = ModuleDescriptor.module("m2").build(); - Configuration cf2 = resolveRequires(ModuleUtils.finderOf(descriptor2), "m2"); + ModuleDescriptor descriptor2 = newBuilder("m2").build(); + Configuration cf2 = resolve(ModuleUtils.finderOf(descriptor2), "m2"); assertTrue(cf2.modules().size() == 1); assertTrue(cf2.findModule("m2").isPresent()); - ModuleDescriptor descriptor3 = ModuleDescriptor.module("m3").build(); - Configuration cf3 = resolveRequires(ModuleUtils.finderOf(descriptor3), "m3"); + ModuleDescriptor descriptor3 = newBuilder("m3").build(); + Configuration cf3 = resolve(ModuleUtils.finderOf(descriptor3), "m3"); assertTrue(cf3.modules().size() == 1); assertTrue(cf3.findModule("m3").isPresent()); // override m2, m1 and m3 should be found in parent configurations ModuleFinder finder = ModuleUtils.finderOf(descriptor2); - Configuration cf4 = Configuration.resolveRequires( + Configuration cf4 = Configuration.resolve( finder, List.of(cf1, cf2, cf3), ModuleFinder.of(), @@ -1530,18 +1455,16 @@ public class ConfigurationTest { */ public void testOverriding3() { - ModuleDescriptor descriptor1 - = ModuleDescriptor.module("m1") + ModuleDescriptor descriptor1 = newBuilder("m1") .build(); - ModuleDescriptor descriptor2 - = ModuleDescriptor.module("m2") + ModuleDescriptor descriptor2 = newBuilder("m2") .requires(Set.of(Requires.Modifier.TRANSITIVE), "m1") .build(); ModuleFinder finder1 = ModuleUtils.finderOf(descriptor1, descriptor2); - Configuration cf1 = resolveRequires(finder1, "m2"); + Configuration cf1 = resolve(finder1, "m2"); assertTrue(cf1.modules().size() == 2); assertTrue(cf1.findModule("m1").isPresent()); @@ -1549,14 +1472,13 @@ public class ConfigurationTest { // cf2: m3 requires m2, m1 - ModuleDescriptor descriptor3 - = ModuleDescriptor.module("m3") + ModuleDescriptor descriptor3 = newBuilder("m3") .requires("m2") .build(); ModuleFinder finder2 = ModuleUtils.finderOf(descriptor1, descriptor3); - Configuration cf2 = resolveRequires(cf1, finder2, "m1", "m3"); + Configuration cf2 = resolve(cf1, finder2, "m1", "m3"); assertTrue(cf2.parents().size() == 1); assertTrue(cf2.parents().get(0) == cf1); @@ -1585,64 +1507,58 @@ public class ConfigurationTest { /** * Root module not found */ - @Test(expectedExceptions = { ResolutionException.class }) + @Test(expectedExceptions = { FindException.class }) public void testRootNotFound() { - resolveRequires(ModuleFinder.of(), "m1"); + resolve(ModuleFinder.of(), "m1"); } /** * Direct dependency not found */ - @Test(expectedExceptions = { ResolutionException.class }) + @Test(expectedExceptions = { FindException.class }) public void testDirectDependencyNotFound() { - ModuleDescriptor descriptor1 - = ModuleDescriptor.module("m1").requires("m2").build(); + ModuleDescriptor descriptor1 = newBuilder("m1").requires("m2").build(); ModuleFinder finder = ModuleUtils.finderOf(descriptor1); - resolveRequires(finder, "m1"); + resolve(finder, "m1"); } /** * Transitive dependency not found */ - @Test(expectedExceptions = { ResolutionException.class }) + @Test(expectedExceptions = { FindException.class }) public void testTransitiveDependencyNotFound() { - ModuleDescriptor descriptor1 - = ModuleDescriptor.module("m1").requires("m2").build(); - ModuleDescriptor descriptor2 - = ModuleDescriptor.module("m2").requires("m3").build(); + ModuleDescriptor descriptor1 = newBuilder("m1").requires("m2").build(); + ModuleDescriptor descriptor2 = newBuilder("m2").requires("m3").build(); ModuleFinder finder = ModuleUtils.finderOf(descriptor1, descriptor2); - resolveRequires(finder, "m1"); + resolve(finder, "m1"); } /** * Service provider dependency not found */ - @Test(expectedExceptions = { ResolutionException.class }) + @Test(expectedExceptions = { FindException.class }) public void testServiceProviderDependencyNotFound() { // service provider dependency (on m3) not found - ModuleDescriptor descriptor1 - = ModuleDescriptor.module("m1") + ModuleDescriptor descriptor1 = newBuilder("m1") .exports("p") .uses("p.S") .build(); - ModuleDescriptor descriptor2 - = ModuleDescriptor.module("m2") + ModuleDescriptor descriptor2 = newBuilder("m2") .requires("m1") .requires("m3") - .contains("q") - .provides("p.S", "q.T") + .provides("p.S", List.of("q.T")) .build(); ModuleFinder finder = ModuleUtils.finderOf(descriptor1, descriptor2); // should throw ResolutionException because m3 is not found - Configuration cf = resolveRequiresAndUses(finder, "m1"); + Configuration cf = resolveAndBind(finder, "m1"); } @@ -1651,15 +1567,12 @@ public class ConfigurationTest { */ @Test(expectedExceptions = { ResolutionException.class }) public void testSimpleCycle() { - ModuleDescriptor descriptor1 - = ModuleDescriptor.module("m1").requires("m2").build(); - ModuleDescriptor descriptor2 - = ModuleDescriptor.module("m2").requires("m3").build(); - ModuleDescriptor descriptor3 - = ModuleDescriptor.module("m3").requires("m1").build(); + ModuleDescriptor descriptor1 = newBuilder("m1").requires("m2").build(); + ModuleDescriptor descriptor2 = newBuilder("m2").requires("m3").build(); + ModuleDescriptor descriptor3 = newBuilder("m3").requires("m1").build(); ModuleFinder finder = ModuleUtils.finderOf(descriptor1, descriptor2, descriptor3); - resolveRequires(finder, "m1"); + resolve(finder, "m1"); } /** @@ -1668,20 +1581,16 @@ public class ConfigurationTest { @Test(expectedExceptions = { ResolutionException.class }) public void testCycleInProvider() { - ModuleDescriptor descriptor1 - = ModuleDescriptor.module("m1") + ModuleDescriptor descriptor1 = newBuilder("m1") .exports("p") .uses("p.S") .build(); - ModuleDescriptor descriptor2 - = ModuleDescriptor.module("m2") + ModuleDescriptor descriptor2 = newBuilder("m2") .requires("m1") .requires("m3") - .contains("q") - .provides("p.S", "q.T") + .provides("p.S", List.of("q.T")) .build(); - ModuleDescriptor descriptor3 - = ModuleDescriptor.module("m3") + ModuleDescriptor descriptor3 = newBuilder("m3") .requires("m2") .build(); @@ -1689,7 +1598,7 @@ public class ConfigurationTest { = ModuleUtils.finderOf(descriptor1, descriptor2, descriptor3); // should throw ResolutionException because of the m2 <--> m3 cycle - resolveRequiresAndUses(finder, "m1"); + resolveAndBind(finder, "m1"); } @@ -1699,19 +1608,16 @@ public class ConfigurationTest { @Test(expectedExceptions = { ResolutionException.class }) public void testPackageSuppliedByTwoOthers() { - ModuleDescriptor descriptor1 - = ModuleDescriptor.module("m1") + ModuleDescriptor descriptor1 = newBuilder("m1") .requires("m2") .requires("m3") .build(); - ModuleDescriptor descriptor2 - = ModuleDescriptor.module("m2") + ModuleDescriptor descriptor2 = newBuilder("m2") .exports("p") .build(); - ModuleDescriptor descriptor3 - = ModuleDescriptor.module("m3") + ModuleDescriptor descriptor3 = newBuilder("m3") .exports("p", Set.of("m1")) .build(); @@ -1719,7 +1625,7 @@ public class ConfigurationTest { = ModuleUtils.finderOf(descriptor1, descriptor2, descriptor3); // m2 and m3 export package p to module m1 - resolveRequires(finder, "m1"); + resolve(finder, "m1"); } @@ -1730,21 +1636,19 @@ public class ConfigurationTest { @Test(expectedExceptions = { ResolutionException.class }) public void testPackageSuppliedBySelfAndOther() { - ModuleDescriptor descriptor1 - = ModuleDescriptor.module("m1") + ModuleDescriptor descriptor1 = newBuilder("m1") .requires("m2") - .contains("p") + .packages(Set.of("p")) .build(); - ModuleDescriptor descriptor2 - = ModuleDescriptor.module("m2") + ModuleDescriptor descriptor2 = newBuilder("m2") .exports("p") .build(); ModuleFinder finder = ModuleUtils.finderOf(descriptor1, descriptor2); // m1 contains package p, module m2 exports package p to m1 - resolveRequires(finder, "m1"); + resolve(finder, "m1"); } @@ -1753,20 +1657,18 @@ public class ConfigurationTest { * a module that also contains a package p. */ public void testContainsPackageInSelfAndOther() { - ModuleDescriptor descriptor1 - = ModuleDescriptor.module("m1") + ModuleDescriptor descriptor1 = newBuilder("m1") .requires("m2") - .contains("p") + .packages(Set.of("p")) .build(); - ModuleDescriptor descriptor2 - = ModuleDescriptor.module("m2") - .contains("p") + ModuleDescriptor descriptor2 = newBuilder("m2") + .packages(Set.of("p")) .build(); ModuleFinder finder = ModuleUtils.finderOf(descriptor1, descriptor2); - Configuration cf = resolveRequires(finder, "m1"); + Configuration cf = resolve(finder, "m1"); assertTrue(cf.modules().size() == 2); assertTrue(cf.findModule("m1").isPresent()); @@ -1787,8 +1689,7 @@ public class ConfigurationTest { */ @Test(expectedExceptions = { ResolutionException.class }) public void testExportSamePackageAsBootLayer() { - ModuleDescriptor descriptor - = ModuleDescriptor.module("m1") + ModuleDescriptor descriptor = newBuilder("m1") .requires("java.base") .exports("java.lang") .build(); @@ -1798,7 +1699,7 @@ public class ConfigurationTest { Configuration bootConfiguration = Layer.boot().configuration(); // m1 contains package java.lang, java.base exports package java.lang to m1 - resolveRequires(bootConfiguration, finder, "m1"); + resolve(bootConfiguration, finder, "m1"); } @@ -1806,15 +1707,14 @@ public class ConfigurationTest { * Test "uses p.S" where p is contained in the same module. */ public void testContainsService1() { - ModuleDescriptor descriptor1 - = ModuleDescriptor.module("m1") - .contains("p") + ModuleDescriptor descriptor1 = newBuilder("m1") + .packages(Set.of("p")) .uses("p.S") .build(); ModuleFinder finder = ModuleUtils.finderOf(descriptor1); - Configuration cf = resolveRequires(finder, "m1"); + Configuration cf = resolve(finder, "m1"); assertTrue(cf.modules().size() == 1); assertTrue(cf.findModule("m1").isPresent()); @@ -1826,13 +1726,11 @@ public class ConfigurationTest { */ @Test(expectedExceptions = { ResolutionException.class }) public void testContainsService2() { - ModuleDescriptor descriptor1 - = ModuleDescriptor.module("m1") - .contains("p") + ModuleDescriptor descriptor1 = newBuilder("m1") + .packages(Set.of("p")) .build(); - ModuleDescriptor descriptor2 - = ModuleDescriptor.module("m2") + ModuleDescriptor descriptor2 = newBuilder("m2") .requires("m1") .uses("p.S") .build(); @@ -1840,7 +1738,7 @@ public class ConfigurationTest { ModuleFinder finder = ModuleUtils.finderOf(descriptor1, descriptor2); // m2 does not read a module that exports p - resolveRequires(finder, "m2"); + resolve(finder, "m2"); } @@ -1848,16 +1746,14 @@ public class ConfigurationTest { * Test "provides p.S" where p is contained in the same module. */ public void testContainsService3() { - ModuleDescriptor descriptor1 - = ModuleDescriptor.module("m1") - .contains("p") - .contains("q") - .provides("p.S", "q.S1") + ModuleDescriptor descriptor1 = newBuilder("m1") + .packages(Set.of("p", "q")) + .provides("p.S", List.of("q.S1")) .build(); ModuleFinder finder = ModuleUtils.finderOf(descriptor1); - Configuration cf = resolveRequires(finder, "m1"); + Configuration cf = resolve(finder, "m1"); assertTrue(cf.modules().size() == 1); assertTrue(cf.findModule("m1").isPresent()); @@ -1869,22 +1765,19 @@ public class ConfigurationTest { */ @Test(expectedExceptions = { ResolutionException.class }) public void testContainsService4() { - ModuleDescriptor descriptor1 - = ModuleDescriptor.module("m1") - .contains("p") + ModuleDescriptor descriptor1 = newBuilder("m1") + .packages(Set.of("p")) .build(); - ModuleDescriptor descriptor2 - = ModuleDescriptor.module("m2") + ModuleDescriptor descriptor2 = newBuilder("m2") .requires("m1") - .contains("q") - .provides("p.S", "q.S1") + .provides("p.S", List.of("q.S1")) .build(); ModuleFinder finder = ModuleUtils.finderOf(descriptor1, descriptor2); // m2 does not read a module that exports p - resolveRequires(finder, "m2"); + resolve(finder, "m2"); } @@ -1893,15 +1786,14 @@ public class ConfigurationTest { */ @Test(expectedExceptions = { ResolutionException.class }) public void testServiceTypePackageNotExported1() { - ModuleDescriptor descriptor1 - = ModuleDescriptor.module("m1") + ModuleDescriptor descriptor1 = newBuilder("m1") .uses("p.S") .build(); ModuleFinder finder = ModuleUtils.finderOf(descriptor1); // m1 does not read a module that exports p - resolveRequires(finder, "m1"); + resolve(finder, "m1"); } @@ -1910,40 +1802,14 @@ public class ConfigurationTest { */ @Test(expectedExceptions = { ResolutionException.class }) public void testServiceTypePackageNotExported2() { - ModuleDescriptor descriptor1 - = ModuleDescriptor.module("m1") - .contains("q") - .provides("p.S", "q.T") + ModuleDescriptor descriptor1 = newBuilder("m1") + .provides("p.S", List.of("q.T")) .build(); ModuleFinder finder = ModuleUtils.finderOf(descriptor1); // m1 does not read a module that exports p - resolveRequires(finder, "m1"); - } - - - /** - * Test "provides p.S with q.T" where q.T is not local - */ - @Test(expectedExceptions = { ResolutionException.class }) - public void testProviderPackageNotLocal() { - ModuleDescriptor descriptor1 - = ModuleDescriptor.module("m1") - .exports("p") - .exports("q") - .build(); - - ModuleDescriptor descriptor2 - = ModuleDescriptor.module("m2") - .requires("m1") - .provides("p.S", "q.T") - .build(); - - ModuleFinder finder = ModuleUtils.finderOf(descriptor1, descriptor2); - - // q.T not in module m2 - resolveRequires(finder, "m2"); + resolve(finder, "m1"); } @@ -2007,34 +1873,17 @@ public class ConfigurationTest { @Test(dataProvider = "platformmatch") public void testPlatformMatch(String s1, String s2) { - ModuleDescriptor.Builder builder - = ModuleDescriptor.module("m1").requires("m2"); - - String[] s = s1.split("-"); - if (!s[0].equals("*")) - builder.osName(s[0]); - if (!s[1].equals("*")) - builder.osArch(s[1]); - if (!s[2].equals("*")) - builder.osVersion(s[2]); - + Builder builder = newBuilder("m1").requires("m2"); + addPlatformConstraints(builder, s1); ModuleDescriptor descriptor1 = builder.build(); - builder = ModuleDescriptor.module("m2"); - - s = s2.split("-"); - if (!s[0].equals("*")) - builder.osName(s[0]); - if (!s[1].equals("*")) - builder.osArch(s[1]); - if (!s[2].equals("*")) - builder.osVersion(s[2]); - + builder = newBuilder("m2"); + addPlatformConstraints(builder, s2); ModuleDescriptor descriptor2 = builder.build(); ModuleFinder finder = ModuleUtils.finderOf(descriptor1, descriptor2); - Configuration cf = resolveRequires(finder, "m1"); + Configuration cf = resolve(finder, "m1"); assertTrue(cf.modules().size() == 2); assertTrue(cf.findModule("m1").isPresent()); @@ -2046,7 +1895,7 @@ public class ConfigurationTest { * platforms. */ @Test(dataProvider = "platformmismatch", - expectedExceptions = ResolutionException.class ) + expectedExceptions = FindException.class ) public void testPlatformMisMatch(String s1, String s2) { testPlatformMatch(s1, s2); } @@ -2057,16 +1906,67 @@ public class ConfigurationTest { @Test(expectedExceptions = { IllegalArgumentException.class }) public void testResolveRequiresWithNoParents() { ModuleFinder empty = ModuleFinder.of(); - Configuration.resolveRequires(empty, List.of(), empty, Set.of()); + Configuration.resolve(empty, List.of(), empty, Set.of()); } @Test(expectedExceptions = { IllegalArgumentException.class }) public void testResolveRequiresAndUsesWithNoParents() { ModuleFinder empty = ModuleFinder.of(); - Configuration.resolveRequiresAndUses(empty, List.of(), empty, Set.of()); + Configuration.resolveAndBind(empty, List.of(), empty, Set.of()); } + // parents with modules for specific platforms + + @Test(dataProvider = "platformmatch") + public void testResolveRequiresWithCompatibleParents(String s1, String s2) { + Builder builder = newBuilder("m1"); + addPlatformConstraints(builder, s1); + ModuleDescriptor descriptor1 = builder.build(); + + builder = newBuilder("m2"); + addPlatformConstraints(builder, s2); + ModuleDescriptor descriptor2 = builder.build(); + + ModuleFinder finder1 = ModuleUtils.finderOf(descriptor1); + Configuration cf1 = resolve(finder1, "m1"); + + ModuleFinder finder2 = ModuleUtils.finderOf(descriptor2); + Configuration cf2 = resolve(finder2, "m2"); + + Configuration cf3 = Configuration.resolve(ModuleFinder.of(), + List.of(cf1, cf2), + ModuleFinder.of(), + Set.of()); + assertTrue(cf3.parents().size() == 2); + } + + @Test(dataProvider = "platformmismatch", + expectedExceptions = IllegalArgumentException.class ) + public void testResolveRequiresWithConflictingParents(String s1, String s2) { + Builder builder = newBuilder("m1"); + addPlatformConstraints(builder, s1); + ModuleDescriptor descriptor1 = builder.build(); + + builder = newBuilder("m2"); + addPlatformConstraints(builder, s2); + ModuleDescriptor descriptor2 = builder.build(); + + ModuleFinder finder1 = ModuleUtils.finderOf(descriptor1); + Configuration cf1 = resolve(finder1, "m1"); + + ModuleFinder finder2 = ModuleUtils.finderOf(descriptor2); + Configuration cf2 = resolve(finder2, "m2"); + + // should throw IAE + Configuration.resolve(ModuleFinder.of(), + List.of(cf1, cf2), + ModuleFinder.of(), + Set.of()); + } + + + // null handling // finder1, finder2, roots @@ -2074,72 +1974,72 @@ public class ConfigurationTest { @Test(expectedExceptions = { NullPointerException.class }) public void testResolveRequiresWithNull1() { - resolveRequires((ModuleFinder)null, ModuleFinder.of()); + resolve((ModuleFinder)null, ModuleFinder.of()); } @Test(expectedExceptions = { NullPointerException.class }) public void testResolveRequiresWithNull2() { - resolveRequires(ModuleFinder.of(), (ModuleFinder)null); + resolve(ModuleFinder.of(), (ModuleFinder)null); } @Test(expectedExceptions = { NullPointerException.class }) public void testResolveRequiresWithNull3() { Configuration empty = Configuration.empty(); - Configuration.resolveRequires(null, List.of(empty), ModuleFinder.of(), Set.of()); + Configuration.resolve(null, List.of(empty), ModuleFinder.of(), Set.of()); } @Test(expectedExceptions = { NullPointerException.class }) public void testResolveRequiresWithNull4() { ModuleFinder empty = ModuleFinder.of(); - Configuration.resolveRequires(empty, null, empty, Set.of()); + Configuration.resolve(empty, null, empty, Set.of()); } @Test(expectedExceptions = { NullPointerException.class }) public void testResolveRequiresWithNull5() { Configuration cf = Layer.boot().configuration(); - Configuration.resolveRequires(ModuleFinder.of(), List.of(cf), null, Set.of()); + Configuration.resolve(ModuleFinder.of(), List.of(cf), null, Set.of()); } @Test(expectedExceptions = { NullPointerException.class }) public void testResolveRequiresWithNull6() { ModuleFinder empty = ModuleFinder.of(); Configuration cf = Layer.boot().configuration(); - Configuration.resolveRequires(empty, List.of(cf), empty, null); + Configuration.resolve(empty, List.of(cf), empty, null); } @Test(expectedExceptions = { NullPointerException.class }) public void testResolveRequiresAndUsesWithNull1() { - resolveRequiresAndUses((ModuleFinder) null, ModuleFinder.of()); + resolveAndBind((ModuleFinder) null, ModuleFinder.of()); } @Test(expectedExceptions = { NullPointerException.class }) public void testResolveRequiresAndUsesWithNull2() { - resolveRequiresAndUses(ModuleFinder.of(), (ModuleFinder) null); + resolveAndBind(ModuleFinder.of(), (ModuleFinder) null); } @Test(expectedExceptions = { NullPointerException.class }) public void testResolveRequiresAndUsesWithNull3() { Configuration empty = Configuration.empty(); - Configuration.resolveRequiresAndUses(null, List.of(empty), ModuleFinder.of(), Set.of()); + Configuration.resolveAndBind(null, List.of(empty), ModuleFinder.of(), Set.of()); } @Test(expectedExceptions = { NullPointerException.class }) public void testResolveRequiresAndUsesWithNull4() { ModuleFinder empty = ModuleFinder.of(); - Configuration.resolveRequiresAndUses(empty, null, empty, Set.of()); + Configuration.resolveAndBind(empty, null, empty, Set.of()); } @Test(expectedExceptions = { NullPointerException.class }) public void testResolveRequiresAndUsesWithNull5() { Configuration cf = Layer.boot().configuration(); - Configuration.resolveRequiresAndUses(ModuleFinder.of(), List.of(cf), null, Set.of()); + Configuration.resolveAndBind(ModuleFinder.of(), List.of(cf), null, Set.of()); } @Test(expectedExceptions = { NullPointerException.class }) public void testResolveRequiresAndUsesWithNull6() { ModuleFinder empty = ModuleFinder.of(); Configuration cf = Layer.boot().configuration(); - Configuration.resolveRequiresAndUses(empty, List.of(cf), empty, null); + Configuration.resolveAndBind(empty, List.of(cf), empty, null); } @Test(expectedExceptions = { NullPointerException.class }) @@ -2165,58 +2065,58 @@ public class ConfigurationTest { /** - * Invokes parent.resolveRequires(...) + * Invokes parent.resolve(...) */ - private Configuration resolveRequires(Configuration parent, - ModuleFinder before, - ModuleFinder after, - String... roots) { - return parent.resolveRequires(before, after, Set.of(roots)); + private Configuration resolve(Configuration parent, + ModuleFinder before, + ModuleFinder after, + String... roots) { + return parent.resolve(before, after, Set.of(roots)); } - private Configuration resolveRequires(Configuration parent, - ModuleFinder before, - String... roots) { - return resolveRequires(parent, before, ModuleFinder.of(), roots); + private Configuration resolve(Configuration parent, + ModuleFinder before, + String... roots) { + return resolve(parent, before, ModuleFinder.of(), roots); } - private Configuration resolveRequires(ModuleFinder before, - ModuleFinder after, - String... roots) { - return resolveRequires(Configuration.empty(), before, after, roots); + private Configuration resolve(ModuleFinder before, + ModuleFinder after, + String... roots) { + return resolve(Configuration.empty(), before, after, roots); } - private Configuration resolveRequires(ModuleFinder before, - String... roots) { - return resolveRequires(Configuration.empty(), before, roots); + private Configuration resolve(ModuleFinder before, + String... roots) { + return resolve(Configuration.empty(), before, roots); } /** - * Invokes parent.resolveRequiresAndUses(...) + * Invokes parent.resolveAndBind(...) */ - private Configuration resolveRequiresAndUses(Configuration parent, - ModuleFinder before, - ModuleFinder after, - String... roots) { - return parent.resolveRequiresAndUses(before, after, Set.of(roots)); + private Configuration resolveAndBind(Configuration parent, + ModuleFinder before, + ModuleFinder after, + String... roots) { + return parent.resolveAndBind(before, after, Set.of(roots)); } - private Configuration resolveRequiresAndUses(Configuration parent, - ModuleFinder before, - String... roots) { - return resolveRequiresAndUses(parent, before, ModuleFinder.of(), roots); + private Configuration resolveAndBind(Configuration parent, + ModuleFinder before, + String... roots) { + return resolveAndBind(parent, before, ModuleFinder.of(), roots); } - private Configuration resolveRequiresAndUses(ModuleFinder before, - ModuleFinder after, - String... roots) { - return resolveRequiresAndUses(Configuration.empty(), before, after, roots); + private Configuration resolveAndBind(ModuleFinder before, + ModuleFinder after, + String... roots) { + return resolveAndBind(Configuration.empty(), before, after, roots); } - private Configuration resolveRequiresAndUses(ModuleFinder before, - String... roots) { - return resolveRequiresAndUses(Configuration.empty(), before, roots); + private Configuration resolveAndBind(ModuleFinder before, + String... roots) { + return resolveAndBind(Configuration.empty(), before, roots); } @@ -2234,5 +2134,17 @@ public class ConfigurationTest { .anyMatch(mn2::equals); } - + /** + * Decodes the platform string and calls the builder osName/osArch/osVersion + * methods to set the platform constraints. + */ + static void addPlatformConstraints(Builder builder, String platformString) { + String[] s = platformString.split("-"); + if (!s[0].equals("*")) + builder.osName(s[0]); + if (!s[1].equals("*")) + builder.osArch(s[1]); + if (!s[2].equals("*")) + builder.osVersion(s[2]); + } } diff --git a/jdk/test/java/lang/module/ModuleDescriptorTest.java b/jdk/test/java/lang/module/ModuleDescriptorTest.java index 276ecf71048..b16b9e66e92 100644 --- a/jdk/test/java/lang/module/ModuleDescriptorTest.java +++ b/jdk/test/java/lang/module/ModuleDescriptorTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2017, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -24,6 +24,7 @@ /** * @test * @modules java.base/jdk.internal.module + * java.base/jdk.internal.misc * @run testng ModuleDescriptorTest * @summary Basic test for java.lang.module.ModuleDescriptor and its builder */ @@ -42,14 +43,19 @@ import java.lang.module.ModuleDescriptor.Requires.Modifier; import java.lang.module.ModuleDescriptor.Version; import java.lang.reflect.Module; import java.nio.ByteBuffer; +import java.util.ArrayList; import java.util.Collections; import java.util.EnumSet; import java.util.HashSet; +import java.util.Iterator; import java.util.List; +import java.util.Objects; import java.util.Set; +import java.util.stream.Collectors; import static java.lang.module.ModuleDescriptor.Requires.Modifier.*; +import jdk.internal.misc.SharedSecrets; import jdk.internal.module.ModuleInfoWriter; import org.testng.annotations.DataProvider; import org.testng.annotations.Test; @@ -84,21 +90,27 @@ public class ModuleDescriptorTest { // requires private Requires requires(Set mods, String mn) { - return ModuleDescriptor.module("m") - .requires(mods, mn) - .build() - .requires() - .iterator() - .next(); + return requires(mods, mn, null); } private Requires requires(Set mods, String mn, Version v) { - return ModuleDescriptor.module("m") - .requires(mods, mn, v) - .build() - .requires() - .iterator() - .next(); + Builder builder = ModuleDescriptor.newModule("m"); + if (v == null) { + builder.requires(mods, mn); + } else { + builder.requires(mods, mn, v); + } + Set requires = builder.build().requires(); + assertTrue(requires.size() == 2); + Iterator iterator = requires.iterator(); + Requires r = iterator.next(); + if (r.name().equals("java.base")) { + r = iterator.next(); + } else { + Requires other = iterator.next(); + assertEquals(other.name(), "java.base"); + } + return r; } private Requires requires(String mn) { @@ -107,7 +119,7 @@ public class ModuleDescriptorTest { public void testRequiresWithRequires() { Requires r1 = requires("foo"); - ModuleDescriptor descriptor = ModuleDescriptor.module("m").requires(r1).build(); + ModuleDescriptor descriptor = ModuleDescriptor.newModule("m").requires(r1).build(); Requires r2 = descriptor.requires().iterator().next(); assertEquals(r1, r2); } @@ -162,28 +174,28 @@ public class ModuleDescriptorTest { @Test(expectedExceptions = IllegalStateException.class) public void testRequiresWithDuplicatesRequires() { Requires r = requires("foo"); - ModuleDescriptor.module("m").requires(r).requires(r); + ModuleDescriptor.newModule("m").requires(r).requires(r); } @Test(expectedExceptions = IllegalArgumentException.class) public void testRequiresSelfWithRequires() { Requires r = requires("foo"); - ModuleDescriptor.module("foo").requires(r); + ModuleDescriptor.newModule("foo").requires(r); } @Test(expectedExceptions = IllegalArgumentException.class) public void testRequiresSelfWithNoModifier() { - ModuleDescriptor.module("m").requires("m"); + ModuleDescriptor.newModule("m").requires("m"); } @Test(expectedExceptions = IllegalArgumentException.class) public void testRequiresSelfWithOneModifier() { - ModuleDescriptor.module("m").requires(Set.of(TRANSITIVE), "m"); + ModuleDescriptor.newModule("m").requires(Set.of(TRANSITIVE), "m"); } @Test(expectedExceptions = IllegalArgumentException.class) public void testRequiresSelfWithAllModifiers() { - ModuleDescriptor.module("m").requires(EnumSet.allOf(Modifier.class), "m"); + ModuleDescriptor.newModule("m").requires(EnumSet.allOf(Modifier.class), "m"); } @Test(dataProvider = "invalidjavaidentifiers", @@ -194,17 +206,17 @@ public class ModuleDescriptorTest { @Test(expectedExceptions = NullPointerException.class) public void testRequiresWithNullRequires() { - ModuleDescriptor.module("m").requires((Requires) null); + ModuleDescriptor.newModule("m").requires((Requires) null); } @Test(expectedExceptions = NullPointerException.class) public void testRequiresWithNullModifiers() { - ModuleDescriptor.module("m").requires(null, "foo"); + ModuleDescriptor.newModule("m").requires(null, "foo"); } @Test(expectedExceptions = NullPointerException.class) public void testRequiresWithNullVersion() { - ModuleDescriptor.module("m").requires(Set.of(), "foo", null); + ModuleDescriptor.newModule("m").requires(Set.of(), "foo", null); } public void testRequiresCompare() { @@ -284,7 +296,7 @@ public class ModuleDescriptorTest { // exports private Exports exports(Set mods, String pn) { - return ModuleDescriptor.module("foo") + return ModuleDescriptor.newModule("foo") .exports(mods, pn) .build() .exports() @@ -297,7 +309,7 @@ public class ModuleDescriptorTest { } private Exports exports(Set mods, String pn, String target) { - return ModuleDescriptor.module("foo") + return ModuleDescriptor.newModule("foo") .exports(mods, pn, Set.of(target)) .build() .exports() @@ -312,7 +324,7 @@ public class ModuleDescriptorTest { public void testExportsExports() { Exports e1 = exports("p"); - ModuleDescriptor descriptor = ModuleDescriptor.module("m").exports(e1).build(); + ModuleDescriptor descriptor = ModuleDescriptor.newModule("m").exports(e1).build(); Exports e2 = descriptor.exports().iterator().next(); assertEquals(e1, e2); } @@ -341,7 +353,7 @@ public class ModuleDescriptorTest { targets.add("bar"); targets.add("gus"); Exports e - = ModuleDescriptor.module("foo") + = ModuleDescriptor.newModule("foo") .exports("p", targets) .build() .exports() @@ -380,69 +392,80 @@ public class ModuleDescriptorTest { @Test(expectedExceptions = IllegalStateException.class) public void testExportsWithDuplicate1() { Exports e = exports("p"); - ModuleDescriptor.module("foo").exports(e).exports(e); + ModuleDescriptor.newModule("foo").exports(e).exports(e); } @Test(expectedExceptions = IllegalStateException.class) public void testExportsWithDuplicate2() { - ModuleDescriptor.module("foo").exports("p").exports("p"); - } - - @Test(expectedExceptions = IllegalStateException.class) - public void testExportsOnContainedPackage() { - ModuleDescriptor.module("foo").contains("p").exports("p"); - } - - @Test(expectedExceptions = IllegalStateException.class) - public void testExportsToTargetOnContainedPackage() { - ModuleDescriptor.module("foo").contains("p").exports("p", Set.of("bar")); + ModuleDescriptor.newModule("foo").exports("p").exports("p"); } @Test(expectedExceptions = IllegalArgumentException.class ) public void testExportsWithEmptySet() { - ModuleDescriptor.module("foo").exports("p", Collections.emptySet()); + ModuleDescriptor.newModule("foo").exports("p", Collections.emptySet()); } @Test(dataProvider = "invalidjavaidentifiers", expectedExceptions = IllegalArgumentException.class ) public void testExportsWithBadName(String pn, String ignore) { - ModuleDescriptor.module("foo").exports(pn); + ModuleDescriptor.newModule("foo").exports(pn); } @Test(expectedExceptions = NullPointerException.class ) public void testExportsWithNullExports() { - ModuleDescriptor.module("foo").exports((Exports) null); + ModuleDescriptor.newModule("foo").exports((Exports) null); } @Test(expectedExceptions = NullPointerException.class ) public void testExportsWithNullTargets() { - ModuleDescriptor.module("foo").exports("p", (Set) null); + ModuleDescriptor.newModule("foo").exports("p", (Set) null); } - public void testExportsEqualsAndHashCode() { - Exports e1, e2; - - e1 = exports("p"); - e2 = exports("p"); + public void testExportsCompare() { + Exports e1 = exports("p"); + Exports e2 = exports("p"); assertEquals(e1, e2); assertTrue(e1.hashCode() == e2.hashCode()); + assertTrue(e1.compareTo(e2) == 0); + assertTrue(e2.compareTo(e1) == 0); + } - e1 = exports(Set.of(Exports.Modifier.SYNTHETIC), "p"); - e2 = exports(Set.of(Exports.Modifier.SYNTHETIC), "p"); + public void testExportsCompareWithSameModifiers() { + Exports e1 = exports(Set.of(Exports.Modifier.SYNTHETIC), "p"); + Exports e2 = exports(Set.of(Exports.Modifier.SYNTHETIC), "p"); assertEquals(e1, e2); assertTrue(e1.hashCode() == e2.hashCode()); + assertTrue(e1.compareTo(e2) == 0); + assertTrue(e2.compareTo(e1) == 0); + } - e1 = exports("p"); - e2 = exports("q"); + public void testExportsCompareWithDifferentModifiers() { + Exports e1 = exports(Set.of(Exports.Modifier.SYNTHETIC), "p"); + Exports e2 = exports("p"); assertNotEquals(e1, e2); + assertTrue(e1.compareTo(e2) == 1); + assertTrue(e2.compareTo(e1) == -1); + } - e1 = exports(Set.of(Exports.Modifier.SYNTHETIC), "p"); - e2 = exports(Set.of(), "p"); + public void testExportsCompareWithSameTargets() { + Exports e1 = exports("p", "x"); + Exports e2 = exports("p", "x"); + assertEquals(e1, e2); + assertTrue(e1.hashCode() == e2.hashCode()); + assertTrue(e1.compareTo(e2) == 0); + assertTrue(e2.compareTo(e1) == 0); + } + + public void testExportsCompareWithDifferentTargets() { + Exports e1 = exports("p", "y"); + Exports e2 = exports("p", "x"); assertNotEquals(e1, e2); + assertTrue(e1.compareTo(e2) == 1); + assertTrue(e2.compareTo(e1) == -1); } public void testExportsToString() { - String s = ModuleDescriptor.module("foo") + String s = ModuleDescriptor.newModule("foo") .exports("p1", Set.of("bar")) .build() .exports() @@ -457,7 +480,7 @@ public class ModuleDescriptorTest { // opens private Opens opens(Set mods, String pn) { - return ModuleDescriptor.module("foo") + return ModuleDescriptor.newModule("foo") .opens(mods, pn) .build() .opens() @@ -470,7 +493,7 @@ public class ModuleDescriptorTest { } private Opens opens(Set mods, String pn, String target) { - return ModuleDescriptor.module("foo") + return ModuleDescriptor.newModule("foo") .opens(mods, pn, Set.of(target)) .build() .opens() @@ -484,7 +507,7 @@ public class ModuleDescriptorTest { public void testOpensOpens() { Opens o1 = opens("p"); - ModuleDescriptor descriptor = ModuleDescriptor.module("m").opens(o1).build(); + ModuleDescriptor descriptor = ModuleDescriptor.newModule("m").opens(o1).build(); Opens o2 = descriptor.opens().iterator().next(); assertEquals(o1, o2); } @@ -513,7 +536,7 @@ public class ModuleDescriptorTest { Set targets = new HashSet<>(); targets.add("bar"); targets.add("gus"); - Opens o = ModuleDescriptor.module("foo") + Opens o = ModuleDescriptor.newModule("foo") .opens("p", targets) .build() .opens() @@ -528,98 +551,83 @@ public class ModuleDescriptorTest { assertTrue(o.targets().contains("gus")); } - /* - - public void testOpensToAllWithModifier() { - Exports e = exports(Set.of(Exports.Modifier.SYNTHETIC), "p"); - assertEquals(e, e); - assertTrue(e.modifiers().size() == 1); - assertTrue(e.modifiers().contains(Exports.Modifier.SYNTHETIC)); - assertEquals(e.source(), "p"); - assertFalse(e.isQualified()); - assertTrue(e.targets().isEmpty()); - } - - public void testOpensToTargetWithModifier() { - Exports e = exports(Set.of(Exports.Modifier.SYNTHETIC), "p", Set.of("bar")); - assertEquals(e, e); - assertTrue(e.modifiers().size() == 1); - assertTrue(e.modifiers().contains(Exports.Modifier.SYNTHETIC)); - assertEquals(e.source(), "p"); - assertTrue(e.isQualified()); - assertTrue(e.targets().size() == 1); - assertTrue(e.targets().contains("bar")); - } - - - */ - @Test(expectedExceptions = IllegalStateException.class) public void testOpensWithDuplicate1() { Opens o = opens("p"); - ModuleDescriptor.module("foo").opens(o).opens(o); + ModuleDescriptor.newModule("foo").opens(o).opens(o); } @Test(expectedExceptions = IllegalStateException.class) public void testOpensWithDuplicate2() { - ModuleDescriptor.module("foo").opens("p").opens("p"); - } - - @Test(expectedExceptions = IllegalStateException.class) - public void testOpensOnContainedPackage() { - ModuleDescriptor.module("foo").contains("p").opens("p"); - } - - @Test(expectedExceptions = IllegalStateException.class) - public void testOpensToTargetOnContainedPackage() { - ModuleDescriptor.module("foo").contains("p").opens("p", Set.of("bar")); + ModuleDescriptor.newModule("foo").opens("p").opens("p"); } @Test(expectedExceptions = IllegalArgumentException.class ) public void testOpensWithEmptySet() { - ModuleDescriptor.module("foo").opens("p", Collections.emptySet()); + ModuleDescriptor.newModule("foo").opens("p", Collections.emptySet()); } @Test(dataProvider = "invalidjavaidentifiers", expectedExceptions = IllegalArgumentException.class ) public void testOpensWithBadName(String pn, String ignore) { - ModuleDescriptor.module("foo").opens(pn); + ModuleDescriptor.newModule("foo").opens(pn); } @Test(expectedExceptions = NullPointerException.class ) public void testOpensWithNullExports() { - ModuleDescriptor.module("foo").opens((Opens) null); + ModuleDescriptor.newModule("foo").opens((Opens) null); } @Test(expectedExceptions = NullPointerException.class ) public void testOpensWithNullTargets() { - ModuleDescriptor.module("foo").opens("p", (Set) null); + ModuleDescriptor.newModule("foo").opens("p", (Set) null); } - public void testOpensEqualsAndHashCode() { - Opens o1, o2; - - o1 = opens("p"); - o2 = opens("p"); - assertEquals(o1, o2); - assertTrue(o1.hashCode() == o1.hashCode()); - - o1 = opens(Set.of(Opens.Modifier.SYNTHETIC), "p"); - o2 = opens(Set.of(Opens.Modifier.SYNTHETIC), "p"); + public void testOpensCompare() { + Opens o1 = opens("p"); + Opens o2 = opens("p"); assertEquals(o1, o2); assertTrue(o1.hashCode() == o2.hashCode()); + assertTrue(o1.compareTo(o2) == 0); + assertTrue(o2.compareTo(o1) == 0); + } - o1 = opens("p"); - o2 = opens("q"); - assertNotEquals(o1, o2); + public void testOpensCompareWithSameModifiers() { + Opens o1 = opens(Set.of(Opens.Modifier.SYNTHETIC), "p"); + Opens o2 = opens(Set.of(Opens.Modifier.SYNTHETIC), "p"); + assertEquals(o1, o2); + assertTrue(o1.hashCode() == o2.hashCode()); + assertTrue(o1.compareTo(o2) == 0); + assertTrue(o2.compareTo(o1) == 0); + } - o1 = opens(Set.of(Opens.Modifier.SYNTHETIC), "p"); - o2 = opens(Set.of(), "p"); + public void testOpensCompareWithDifferentModifiers() { + Opens o1 = opens(Set.of(Opens.Modifier.SYNTHETIC), "p"); + Opens o2 = opens("p"); assertNotEquals(o1, o2); + assertTrue(o1.compareTo(o2) == 1); + assertTrue(o2.compareTo(o1) == -1); + } + + public void testOpensCompareWithSameTargets() { + Opens o1 = opens("p", "x"); + Opens o2 = opens("p", "x"); + assertEquals(o1, o2); + assertTrue(o1.hashCode() == o2.hashCode()); + assertTrue(o1.compareTo(o2) == 0); + assertTrue(o2.compareTo(o1) == 0); + } + + public void testOpensCompareWithDifferentTargets() { + Opens o1 = opens("p", "y"); + Opens o2 = opens("p", "x"); + assertNotEquals(o1, o2); + assertTrue(o1.compareTo(o2) == 1); + assertTrue(o2.compareTo(o1) == -1); } public void testOpensToString() { - String s = ModuleDescriptor.module("foo") + String s = ModuleDescriptor.newModule("foo") .opens("p1", Set.of("bar")) .build() .opens() @@ -635,7 +643,7 @@ public class ModuleDescriptorTest { public void testUses() { Set uses - = ModuleDescriptor.module("foo") + = ModuleDescriptor.newModule("foo") .uses("p.S") .uses("q.S") .build() @@ -647,30 +655,44 @@ public class ModuleDescriptorTest { @Test(expectedExceptions = IllegalStateException.class) public void testUsesWithDuplicate() { - ModuleDescriptor.module("foo").uses("p.S").uses("p.S"); + ModuleDescriptor.newModule("foo").uses("p.S").uses("p.S"); + } + + @Test(expectedExceptions = IllegalArgumentException.class) + public void testUsesWithSimpleIdentifier() { + ModuleDescriptor.newModule("foo").uses("S"); } @Test(dataProvider = "invalidjavaidentifiers", expectedExceptions = IllegalArgumentException.class ) public void testUsesWithBadName(String service, String ignore) { - ModuleDescriptor.module("foo").uses(service); + ModuleDescriptor.newModule("foo").uses(service); } // provides private Provides provides(String st, String pc) { - return ModuleDescriptor.module("foo") - .provides(st, pc) + return ModuleDescriptor.newModule("foo") + .provides(st, List.of(pc)) .build() .provides() .iterator() .next(); } + private Provides provides(String st, List pns) { + return ModuleDescriptor.newModule("foo") + .provides(st, pns) + .build() + .provides() + .iterator() + .next(); + } + public void testProvidesWithProvides() { Provides p1 = provides("p.S", "q.S1"); - ModuleDescriptor descriptor = ModuleDescriptor.module("m") + ModuleDescriptor descriptor = ModuleDescriptor.newModule("m") .provides(p1) .build(); Provides p2 = descriptor.provides().iterator().next(); @@ -679,7 +701,7 @@ public class ModuleDescriptorTest { public void testProvides() { - Set set = ModuleDescriptor.module("foo") + Set set = ModuleDescriptor.newModule("foo") .provides("p.S", List.of("q.P1", "q.P2")) .build() .provides(); @@ -696,59 +718,86 @@ public class ModuleDescriptorTest { @Test(expectedExceptions = IllegalStateException.class ) public void testProvidesWithDuplicateProvides() { Provides p = provides("p.S", "q.S2"); - ModuleDescriptor.module("m").provides("p.S", "q.S1").provides(p); + ModuleDescriptor.newModule("m").provides("p.S", List.of("q.S1")).provides(p); } @Test(expectedExceptions = IllegalArgumentException.class ) public void testProvidesWithEmptySet() { - ModuleDescriptor.module("foo").provides("p.Service", Collections.emptyList()); + ModuleDescriptor.newModule("foo").provides("p.Service", Collections.emptyList()); + } + + @Test(expectedExceptions = IllegalArgumentException.class ) + public void testProvidesWithSimpleIdentifier1() { + ModuleDescriptor.newModule("foo").provides("S", List.of("q.P")); + } + + @Test(expectedExceptions = IllegalArgumentException.class ) + public void testProvidesWithSimpleIdentifier2() { + ModuleDescriptor.newModule("foo").provides("p.S", List.of("P")); } @Test(dataProvider = "invalidjavaidentifiers", expectedExceptions = IllegalArgumentException.class ) public void testProvidesWithBadService(String service, String ignore) { - ModuleDescriptor.module("foo").provides(service, "p.Provider"); + ModuleDescriptor.newModule("foo").provides(service, List.of("p.Provider")); } @Test(dataProvider = "invalidjavaidentifiers", expectedExceptions = IllegalArgumentException.class ) public void testProvidesWithBadProvider(String provider, String ignore) { - ModuleDescriptor.module("foo").provides("p.Service", provider); + List names = new ArrayList<>(); // allows nulls + names.add(provider); + ModuleDescriptor.newModule("foo").provides("p.Service", names); } @Test(expectedExceptions = NullPointerException.class ) public void testProvidesWithNullProvides() { - ModuleDescriptor.module("foo").provides((Provides) null); + ModuleDescriptor.newModule("foo").provides((Provides) null); } @Test(expectedExceptions = NullPointerException.class ) public void testProvidesWithNullProviders() { - ModuleDescriptor.module("foo").provides("p.S", (List) null); + ModuleDescriptor.newModule("foo").provides("p.S", (List) null); } - public void testProvidesEqualsAndHashCode() { - Provides p1, p2; - - p1 = provides("p.S", "q.S1"); - p2 = provides("p.S", "q.S1"); + public void testProvidesCompare() { + Provides p1 = provides("p.S", "q.S1"); + Provides p2 = provides("p.S", "q.S1"); assertEquals(p1, p2); assertTrue(p1.hashCode() == p2.hashCode()); - - p1 = provides("p.S", "q.S1"); - p2 = provides("p.S", "q.S2"); - assertNotEquals(p1, p2); - - p1 = provides("p.S", "q.S1"); - p2 = provides("p.S2", "q.S1"); - assertNotEquals(p1, p2); + assertTrue(p1.compareTo(p2) == 0); + assertTrue(p2.compareTo(p1) == 0); } - // contains + public void testProvidesCompareWithDifferentService() { + Provides p1 = provides("p.S2", "q.S1"); + Provides p2 = provides("p.S1", "q.S1"); + assertNotEquals(p1, p2); + assertTrue(p1.compareTo(p2) == 1); + assertTrue(p2.compareTo(p1) == -1); + } - public void testContains() { - Set packages = ModuleDescriptor.module("foo") - .contains("p") - .contains("q") + public void testProvidesCompareWithDifferentProviders1() { + Provides p1 = provides("p.S", "q.S2"); + Provides p2 = provides("p.S", "q.S1"); + assertNotEquals(p1, p2); + assertTrue(p1.compareTo(p2) == 1); + assertTrue(p2.compareTo(p1) == -1); + } + + public void testProvidesCompareWithDifferentProviders2() { + Provides p1 = provides("p.S", List.of("q.S1", "q.S2")); + Provides p2 = provides("p.S", "q.S1"); + assertNotEquals(p1, p2); + assertTrue(p1.compareTo(p2) == 1); + assertTrue(p2.compareTo(p1) == -1); + } + + // packages + + public void testPackages1() { + Set packages = ModuleDescriptor.newModule("foo") + .packages(Set.of("p", "q")) .build() .packages(); assertTrue(packages.size() == 2); @@ -756,56 +805,147 @@ public class ModuleDescriptorTest { assertTrue(packages.contains("q")); } - public void testContainsWithEmptySet() { - Set packages = ModuleDescriptor.module("foo") - .contains(Collections.emptySet()) + public void testPackages2() { + Set packages = ModuleDescriptor.newModule("foo") + .packages(Set.of("p")) + .packages(Set.of("q")) + .build() + .packages(); + assertTrue(packages.size() == 2); + assertTrue(packages.contains("p")); + assertTrue(packages.contains("q")); + } + + + public void testPackagesWithEmptySet() { + Set packages = ModuleDescriptor.newModule("foo") + .packages(Collections.emptySet()) .build() .packages(); assertTrue(packages.size() == 0); } - @Test(expectedExceptions = IllegalStateException.class) - public void testContainsWithDuplicate() { - ModuleDescriptor.module("foo").contains("p").contains("p"); + public void testPackagesDuplicate() { + Set packages = ModuleDescriptor.newModule("foo") + .packages(Set.of("p")) + .packages(Set.of("p")) + .build() + .packages(); + assertTrue(packages.size() == 1); + assertTrue(packages.contains("p")); } - @Test(expectedExceptions = IllegalStateException.class) - public void testContainsWithExportedPackage() { - ModuleDescriptor.module("foo").exports("p").contains("p"); + public void testPackagesAndExportsPackage1() { + Set packages = ModuleDescriptor.newModule("foo") + .packages(Set.of("p")) + .exports("p") + .build() + .packages(); + assertTrue(packages.size() == 1); + assertTrue(packages.contains("p")); + } + + public void testPackagesAndExportsPackage2() { + Set packages = ModuleDescriptor.newModule("foo") + .exports("p") + .packages(Set.of("p")) + .build() + .packages(); + assertTrue(packages.size() == 1); + assertTrue(packages.contains("p")); + } + + public void testPackagesAndOpensPackage1() { + Set packages = ModuleDescriptor.newModule("foo") + .packages(Set.of("p")) + .opens("p") + .build() + .packages(); + assertTrue(packages.size() == 1); + assertTrue(packages.contains("p")); + } + + public void testPackagesAndOpensPackage2() { + Set packages = ModuleDescriptor.newModule("foo") + .opens("p") + .packages(Set.of("p")) + .build() + .packages(); + assertTrue(packages.size() == 1); + assertTrue(packages.contains("p")); + } + + public void testPackagesAndProvides1() { + Set packages = ModuleDescriptor.newModule("foo") + .packages(Set.of("p")) + .provides("q.S", List.of("p.T")) + .build() + .packages(); + assertTrue(packages.size() == 1); + assertTrue(packages.contains("p")); + } + + public void testPackagesAndProvides2() { + Set packages = ModuleDescriptor.newModule("foo") + .provides("q.S", List.of("p.T")) + .packages(Set.of("p")) + .build() + .packages(); + assertTrue(packages.size() == 1); + assertTrue(packages.contains("p")); + } + + public void testPackagesAndMainClass1() { + Set packages = ModuleDescriptor.newModule("foo") + .packages(Set.of("p")) + .mainClass("p.Main") + .build() + .packages(); + assertTrue(packages.size() == 1); + assertTrue(packages.contains("p")); + } + + public void testPackagesAndMainClass2() { + Set packages = ModuleDescriptor.newModule("foo") + .mainClass("p.Main") + .packages(Set.of("p")) + .build() + .packages(); + assertTrue(packages.size() == 1); + assertTrue(packages.contains("p")); + } + + public void testPackagesAndAll() { + Set packages = ModuleDescriptor.newModule("foo") + .exports("p1") + .opens("p2") + .packages(Set.of("p3")) + .provides("q.S", List.of("p4.T")) + .mainClass("p5.Main") + .build() + .packages(); + assertTrue(Objects.equals(packages, Set.of("p1", "p2", "p3", "p4", "p5"))); } @Test(dataProvider = "invalidjavaidentifiers", expectedExceptions = IllegalArgumentException.class ) - public void testContainsWithBadName(String pn, String ignore) { - ModuleDescriptor.module("foo").contains(pn); + public void testPackagesWithBadName(String pn, String ignore) { + Set pkgs = new HashSet<>(); // allows nulls + pkgs.add(pn); + ModuleDescriptor.newModule("foo").packages(pkgs); } - - // packages - - public void testPackages() { - Set packages = ModuleDescriptor.module("foo") - .exports("p") - .contains("q") - .build() - .packages(); - assertTrue(packages.size() == 2); - assertTrue(packages.contains("p")); - assertTrue(packages.contains("q")); - } - - // name public void testModuleName() { - String mn = ModuleDescriptor.module("foo").build().name(); + String mn = ModuleDescriptor.newModule("foo").build().name(); assertEquals(mn, "foo"); } @Test(dataProvider = "invalidjavaidentifiers", expectedExceptions = IllegalArgumentException.class ) public void testBadModuleName(String mn, String ignore) { - ModuleDescriptor.module(mn); + ModuleDescriptor.newModule(mn); } @@ -813,7 +953,7 @@ public class ModuleDescriptorTest { public void testVersion1() { Version v1 = Version.parse("1.0"); - Version v2 = ModuleDescriptor.module("foo") + Version v2 = ModuleDescriptor.newModule("foo") .version(v1) .build() .version() @@ -823,7 +963,7 @@ public class ModuleDescriptorTest { public void testVersion2() { String vs = "1.0"; - Version v1 = ModuleDescriptor.module("foo") + Version v1 = ModuleDescriptor.newModule("foo") .version(vs) .build() .version() @@ -834,86 +974,178 @@ public class ModuleDescriptorTest { @Test(expectedExceptions = NullPointerException.class ) public void testNullVersion1() { - ModuleDescriptor.module("foo").version((Version) null); + ModuleDescriptor.newModule("foo").version((Version) null); } @Test(expectedExceptions = IllegalArgumentException.class ) public void testNullVersion2() { - ModuleDescriptor.module("foo").version((String) null); + ModuleDescriptor.newModule("foo").version((String) null); } @Test(expectedExceptions = IllegalArgumentException.class ) public void testEmptyVersion() { - ModuleDescriptor.module("foo").version(""); + ModuleDescriptor.newModule("foo").version(""); } // toNameAndVersion public void testToNameAndVersion() { - ModuleDescriptor md1 = ModuleDescriptor.module("foo").build(); + ModuleDescriptor md1 = ModuleDescriptor.newModule("foo").build(); assertEquals(md1.toNameAndVersion(), "foo"); - ModuleDescriptor md2 = ModuleDescriptor.module("foo").version("1.0").build(); + ModuleDescriptor md2 = ModuleDescriptor.newModule("foo").version("1.0").build(); assertEquals(md2.toNameAndVersion(), "foo@1.0"); } // open modules - public void testOpenModules() { - ModuleDescriptor descriptor = ModuleDescriptor.openModule("m") - .requires("java.base") - .contains("p") + public void testOpenModule() { + ModuleDescriptor descriptor = ModuleDescriptor.newOpenModule("foo") + .requires("bar") + .exports("p") + .provides("p.Service", List.of("q.ServiceImpl")) .build(); + + // modifiers + assertTrue(descriptor.modifiers().contains(ModuleDescriptor.Modifier.OPEN)); assertTrue(descriptor.isOpen()); - assertTrue(descriptor.packages().size() == 1); - assertTrue(descriptor.packages().contains("p")); - assertTrue(descriptor.exports().isEmpty()); + + // requires + assertTrue(descriptor.requires().size() == 2); + Set names = descriptor.requires() + .stream() + .map(Requires::name) + .collect(Collectors.toSet()); + assertEquals(names, Set.of("bar", "java.base")); + + // packages + assertEquals(descriptor.packages(), Set.of("p", "q")); + + // exports + assertTrue(descriptor.exports().size() == 1); + names = descriptor.exports() + .stream() + .map(Exports::source) + .collect(Collectors.toSet()); + assertEquals(names, Set.of("p")); + + // opens + assertTrue(descriptor.opens().isEmpty()); } @Test(expectedExceptions = IllegalStateException.class) - public void testOpensOnWeakModule1() { - ModuleDescriptor.openModule("foo").opens("p"); + public void testOpensOnOpenModule1() { + ModuleDescriptor.newOpenModule("foo").opens("p"); } @Test(expectedExceptions = IllegalStateException.class) - public void testOpensOnWeakModule2() { - ModuleDescriptor.openModule("foo").opens("p", Set.of("bar")); + public void testOpensOnOpenModule2() { + ModuleDescriptor.newOpenModule("foo").opens("p", Set.of("bar")); } public void testIsOpen() { - assertFalse(ModuleDescriptor.module("m").build().isOpen()); - assertFalse(ModuleDescriptor.automaticModule("m").build().isOpen()); - assertTrue(ModuleDescriptor.openModule("m").build().isOpen()); + assertFalse(ModuleDescriptor.newModule("m").build().isOpen()); + assertFalse(ModuleDescriptor.newAutomaticModule("m").build().isOpen()); + assertTrue(ModuleDescriptor.newOpenModule("m").build().isOpen()); } // automatic modules + public void testAutomaticModule() { + ModuleDescriptor descriptor = ModuleDescriptor.newAutomaticModule("foo") + .packages(Set.of("p")) + .provides("p.Service", List.of("q.ServiceImpl")) + .build(); + + // modifiers + assertTrue(descriptor.modifiers().contains(ModuleDescriptor.Modifier.AUTOMATIC)); + assertTrue(descriptor.isAutomatic()); + + // requires + assertTrue(descriptor.requires().size() == 1); + Set names = descriptor.requires() + .stream() + .map(Requires::name) + .collect(Collectors.toSet()); + assertEquals(names, Set.of("java.base")); + + // packages + assertEquals(descriptor.packages(), Set.of("p", "q")); + assertTrue(descriptor.exports().isEmpty()); + assertTrue(descriptor.opens().isEmpty()); + } + + @Test(expectedExceptions = IllegalStateException.class) + public void testRequiresOnAutomaticModule() { + ModuleDescriptor.newAutomaticModule("foo").requires("java.base"); + } + + @Test(expectedExceptions = IllegalStateException.class) + public void testExportsOnAutomaticModule1() { + ModuleDescriptor.newAutomaticModule("foo").exports("p"); + } + + @Test(expectedExceptions = IllegalStateException.class) + public void testExportsOnAutomaticModule2() { + ModuleDescriptor.newAutomaticModule("foo").exports("p", Set.of("bar")); + } + + @Test(expectedExceptions = IllegalStateException.class) + public void testOpensOnAutomaticModule1() { + ModuleDescriptor.newAutomaticModule("foo").opens("p"); + } + + @Test(expectedExceptions = IllegalStateException.class) + public void testOpensOnAutomaticModule2() { + ModuleDescriptor.newAutomaticModule("foo").opens("p", Set.of("bar")); + } + + @Test(expectedExceptions = IllegalStateException.class) + public void testUsesOnAutomaticModule() { + ModuleDescriptor.newAutomaticModule("foo").uses("p.Service"); + } + public void testIsAutomatic() { - ModuleDescriptor descriptor1 = ModuleDescriptor.module("foo").build(); + ModuleDescriptor descriptor1 = ModuleDescriptor.newModule("foo").build(); assertFalse(descriptor1.isAutomatic()); - ModuleDescriptor descriptor2 = ModuleDescriptor.openModule("foo").build(); + ModuleDescriptor descriptor2 = ModuleDescriptor.newOpenModule("foo").build(); assertFalse(descriptor2.isAutomatic()); - ModuleDescriptor descriptor3 = ModuleDescriptor.automaticModule("foo").build(); + ModuleDescriptor descriptor3 = ModuleDescriptor.newAutomaticModule("foo").build(); assertTrue(descriptor3.isAutomatic()); } - // isSynthetic - public void testIsSynthetic() { - assertFalse(Object.class.getModule().getDescriptor().isSynthetic()); - ModuleDescriptor descriptor1 = ModuleDescriptor.module("foo").build(); - assertFalse(descriptor1.isSynthetic()); + // newModule with modifiers - ModuleDescriptor descriptor2 = ModuleDescriptor.openModule("foo").build(); - assertFalse(descriptor2.isSynthetic()); + public void testNewModuleToBuildAutomaticModule() { + Set ms = Set.of(ModuleDescriptor.Modifier.AUTOMATIC); + ModuleDescriptor descriptor = ModuleDescriptor.newModule("foo", ms).build(); + assertTrue(descriptor.modifiers().equals(ms)); + assertTrue(descriptor.isAutomatic()); + } - ModuleDescriptor descriptor3 = ModuleDescriptor.automaticModule("foo").build(); - assertFalse(descriptor3.isSynthetic()); + public void testNewModuleToBuildOpenModule() { + Set ms = Set.of(ModuleDescriptor.Modifier.OPEN); + ModuleDescriptor descriptor = ModuleDescriptor.newModule("foo", ms).build(); + assertTrue(descriptor.modifiers().equals(ms)); + assertTrue(descriptor.isOpen()); + + ms = Set.of(ModuleDescriptor.Modifier.OPEN, ModuleDescriptor.Modifier.SYNTHETIC); + descriptor = ModuleDescriptor.newModule("foo", ms).build(); + assertTrue(descriptor.modifiers().equals(ms)); + assertTrue(descriptor.isOpen()); + } + + @Test(expectedExceptions = IllegalArgumentException.class) + public void testNewModuleToBuildAutomaticAndOpenModule() { + Set ms = Set.of(ModuleDescriptor.Modifier.AUTOMATIC, + ModuleDescriptor.Modifier.OPEN); + ModuleDescriptor.newModule("foo", ms); } @@ -921,14 +1153,19 @@ public class ModuleDescriptorTest { public void testMainClass() { String mainClass - = ModuleDescriptor.module("foo").mainClass("p.Main").build().mainClass().get(); + = ModuleDescriptor.newModule("foo").mainClass("p.Main").build().mainClass().get(); assertEquals(mainClass, "p.Main"); } + @Test(expectedExceptions = IllegalArgumentException.class) + public void testMainClassWithSimpleIdentifier() { + ModuleDescriptor.newModule("foo").mainClass("Main"); + } + @Test(dataProvider = "invalidjavaidentifiers", expectedExceptions = IllegalArgumentException.class ) public void testMainClassWithBadName(String mainClass, String ignore) { - Builder builder = ModuleDescriptor.module("foo"); + Builder builder = ModuleDescriptor.newModule("foo"); builder.mainClass(mainClass); } @@ -936,54 +1173,54 @@ public class ModuleDescriptorTest { // osName public void testOsName() { - String osName = ModuleDescriptor.module("foo").osName("Linux").build().osName().get(); + String osName = ModuleDescriptor.newModule("foo").osName("Linux").build().osName().get(); assertEquals(osName, "Linux"); } @Test(expectedExceptions = IllegalArgumentException.class) public void testNullOsName() { - ModuleDescriptor.module("foo").osName(null); + ModuleDescriptor.newModule("foo").osName(null); } @Test(expectedExceptions = IllegalArgumentException.class) public void testEmptyOsName() { - ModuleDescriptor.module("foo").osName(""); + ModuleDescriptor.newModule("foo").osName(""); } // osArch public void testOsArch() { - String osArch = ModuleDescriptor.module("foo").osName("arm").build().osName().get(); + String osArch = ModuleDescriptor.newModule("foo").osName("arm").build().osName().get(); assertEquals(osArch, "arm"); } @Test(expectedExceptions = IllegalArgumentException.class) public void testNullOsArch() { - ModuleDescriptor.module("foo").osArch(null); + ModuleDescriptor.newModule("foo").osArch(null); } @Test(expectedExceptions = IllegalArgumentException.class) public void testEmptyOsArch() { - ModuleDescriptor.module("foo").osArch(""); + ModuleDescriptor.newModule("foo").osArch(""); } // osVersion public void testOsVersion() { - String osVersion = ModuleDescriptor.module("foo").osName("11.2").build().osName().get(); + String osVersion = ModuleDescriptor.newModule("foo").osName("11.2").build().osName().get(); assertEquals(osVersion, "11.2"); } @Test(expectedExceptions = IllegalArgumentException.class) public void testNullOsVersion() { - ModuleDescriptor.module("foo").osVersion(null); + ModuleDescriptor.newModule("foo").osVersion(null); } @Test(expectedExceptions = IllegalArgumentException.class) public void testEmptyOsVersion() { - ModuleDescriptor.module("foo").osVersion(""); + ModuleDescriptor.newModule("foo").osVersion(""); } // reads @@ -1023,7 +1260,7 @@ public class ModuleDescriptorTest { * Test ModuleDescriptor with a packager finder */ public void testReadsWithPackageFinder() throws Exception { - ModuleDescriptor descriptor = ModuleDescriptor.module("foo") + ModuleDescriptor descriptor = ModuleDescriptor.newModule("foo") .requires("java.base") .build(); @@ -1044,7 +1281,7 @@ public class ModuleDescriptorTest { */ @Test(expectedExceptions = InvalidModuleDescriptorException.class) public void testReadsWithBadPackageFinder() throws Exception { - ModuleDescriptor descriptor = ModuleDescriptor.module("foo") + ModuleDescriptor descriptor = ModuleDescriptor.newModule("foo") .requires("java.base") .exports("p") .build(); @@ -1077,7 +1314,7 @@ public class ModuleDescriptorTest { @Test(expectedExceptions = InvalidModuleDescriptorException.class) public void testReadOfJavaBaseWithRequires() { ModuleDescriptor descriptor - = ModuleDescriptor.module("java.base") + = ModuleDescriptor.newModule("java.base") .requires("other") .build(); ByteBuffer bb = ModuleInfoWriter.toByteBuffer(descriptor); @@ -1087,7 +1324,8 @@ public class ModuleDescriptorTest { // The requires table must have an entry for java.base @Test(expectedExceptions = InvalidModuleDescriptorException.class) public void testReadWithEmptyRequires() { - ModuleDescriptor descriptor = ModuleDescriptor.module("m1").build(); + ModuleDescriptor descriptor = SharedSecrets.getJavaLangModuleAccess() + .newModuleBuilder("m1", false, Set.of()).build(); ByteBuffer bb = ModuleInfoWriter.toByteBuffer(descriptor); ModuleDescriptor.read(bb); } @@ -1095,10 +1333,8 @@ public class ModuleDescriptorTest { // The requires table must have an entry for java.base @Test(expectedExceptions = InvalidModuleDescriptorException.class) public void testReadWithNoRequiresBase() { - ModuleDescriptor descriptor - = ModuleDescriptor.module("m1") - .requires("m2") - .build(); + ModuleDescriptor descriptor = SharedSecrets.getJavaLangModuleAccess() + .newModuleBuilder("m1", false, Set.of()).requires("m2").build(); ByteBuffer bb = ModuleInfoWriter.toByteBuffer(descriptor); ModuleDescriptor.read(bb); } @@ -1138,22 +1374,50 @@ public class ModuleDescriptorTest { // equals/hashCode/compareTo/toString public void testEqualsAndHashCode() { - ModuleDescriptor md1 = ModuleDescriptor.module("foo").build(); - ModuleDescriptor md2 = ModuleDescriptor.module("foo").build(); + ModuleDescriptor md1 = ModuleDescriptor.newModule("m").build(); + ModuleDescriptor md2 = ModuleDescriptor.newModule("m").build(); assertEquals(md1, md1); assertEquals(md1.hashCode(), md2.hashCode()); + assertTrue(md1.compareTo(md2) == 0); + assertTrue(md2.compareTo(md1) == 0); } - public void testCompare() { - ModuleDescriptor md1 = ModuleDescriptor.module("foo").build(); - ModuleDescriptor md2 = ModuleDescriptor.module("bar").build(); - int n = "foo".compareTo("bar"); - assertTrue(md1.compareTo(md2) == n); - assertTrue(md2.compareTo(md1) == -n); + @DataProvider(name = "sortedModuleDescriptors") + public Object[][] sortedModuleDescriptors() { + return new Object[][]{ + + { ModuleDescriptor.newModule("m2").build(), + ModuleDescriptor.newModule("m1").build() + }, + + { ModuleDescriptor.newModule("m").version("2").build(), + ModuleDescriptor.newModule("m").version("1").build() + }, + + { ModuleDescriptor.newModule("m").version("1").build(), + ModuleDescriptor.newModule("m").build() + }, + + { ModuleDescriptor.newOpenModule("m").build(), + ModuleDescriptor.newModule("m").build() + }, + + }; + } + + @Test(dataProvider = "sortedModuleDescriptors") + public void testCompare(ModuleDescriptor md1, ModuleDescriptor md2) { + assertNotEquals(md1, md2); + assertTrue(md1.compareTo(md2) == 1); + assertTrue(md2.compareTo(md1) == -1); } public void testToString() { - String s = ModuleDescriptor.module("m1").requires("m2").exports("p1").build().toString(); + String s = ModuleDescriptor.newModule("m1") + .requires("m2") + .exports("p1") + .build() + .toString(); assertTrue(s.contains("m1")); assertTrue(s.contains("m2")); assertTrue(s.contains("p1")); diff --git a/jdk/test/java/lang/module/ModuleFinderTest.java b/jdk/test/java/lang/module/ModuleFinderTest.java index 278b4b98714..29d8f234c8b 100644 --- a/jdk/test/java/lang/module/ModuleFinderTest.java +++ b/jdk/test/java/lang/module/ModuleFinderTest.java @@ -471,36 +471,10 @@ public class ModuleFinderTest { * Test ModuleFinder.of with a file path to a directory containing a file * that will not be recognized as a module. */ - public void testOfWithUnrecognizedEntryInDirectory() throws Exception { + public void testOfWithUnrecognizedEntryInDirectory1() throws Exception { Path dir = Files.createTempDirectory(USER_DIR, "mods"); Files.createTempFile(dir, "m", ".junk"); - ModuleFinder finder = ModuleFinder.of(dir); - try { - finder.find("java.rhubarb"); - assertTrue(false); - } catch (FindException e) { - // expected - } - - finder = ModuleFinder.of(dir); - try { - finder.findAll(); - assertTrue(false); - } catch (FindException e) { - // expected - } - } - - - /** - * Test ModuleFinder.of with a file path to a directory containing a file - * starting with ".", the file should be ignored. - */ - public void testOfWithHiddenEntryInDirectory() throws Exception { - Path dir = Files.createTempDirectory(USER_DIR, "mods"); - Files.createTempFile(dir, ".marker", ""); - ModuleFinder finder = ModuleFinder.of(dir); assertFalse(finder.find("java.rhubarb").isPresent()); @@ -509,6 +483,24 @@ public class ModuleFinderTest { } + /** + * Test ModuleFinder.of with a file path to a directory containing a file + * that will not be recognized as a module. + */ + public void testOfWithUnrecognizedEntryInDirectory2() throws Exception { + Path dir = Files.createTempDirectory(USER_DIR, "mods"); + createModularJar(dir.resolve("m1.jar"), "m1"); + Files.createTempFile(dir, "m2", ".junk"); + + ModuleFinder finder = ModuleFinder.of(dir); + assertTrue(finder.find("m1").isPresent()); + assertFalse(finder.find("m2").isPresent()); + + finder = ModuleFinder.of(dir); + assertTrue(finder.findAll().size() == 1); + } + + /** * Test ModuleFinder.of with a directory that contains two * versions of the same module @@ -748,7 +740,7 @@ public class ModuleFinderTest { vs = mid.substring(i+1); } ModuleDescriptor.Builder builder - = ModuleDescriptor.module(mn).requires("java.base"); + = ModuleDescriptor.newModule(mn).requires("java.base"); if (vs != null) builder.version(vs); return builder.build(); diff --git a/jdk/test/java/lang/module/ModuleNamesTest.java b/jdk/test/java/lang/module/ModuleNamesTest.java index c0790eab202..afeadacec86 100644 --- a/jdk/test/java/lang/module/ModuleNamesTest.java +++ b/jdk/test/java/lang/module/ModuleNamesTest.java @@ -235,7 +235,7 @@ public class ModuleNamesTest { */ private Builder newBuilder(String mn) { return SharedSecrets.getJavaLangModuleAccess() - .newModuleBuilder(mn, false, false, false); + .newModuleBuilder(mn, false, Set.of()); } /** diff --git a/jdk/test/java/lang/module/ModuleReader/ModuleReaderTest.java b/jdk/test/java/lang/module/ModuleReader/ModuleReaderTest.java index d956c249651..12e53b0f5fb 100644 --- a/jdk/test/java/lang/module/ModuleReader/ModuleReaderTest.java +++ b/jdk/test/java/lang/module/ModuleReader/ModuleReaderTest.java @@ -79,14 +79,52 @@ public class ModuleReaderTest { "java/lang/Object.class" }; + // resource names that should not be found in the base module + private static final String[] BAD_BASE_RESOURCES = { + "NotFound", + "java", + "/java", + "//java", + "java/", + "java/lang", + "/java/lang", + "//java/lang", + "java/lang/", + "java//lang", + "/java/lang/Object.class", + "//java/lang/Object.class", + "java/lang/Object.class/", + "java//lang//Object.class", + "./java/lang/Object.class", + "java/./lang/Object.class", + "java/lang/./Object.class", + "../java/lang/Object.class", + "java/../lang/Object.class", + "java/lang/../Object.class", + }; + // resources in test module (can't use module-info.class as a test // resource as it will be modified by the jmod tool) private static final String[] TEST_RESOURCES = { "p/Main.class" }; - // a resource that is not in the base or test module - private static final String NOT_A_RESOURCE = "NotAResource"; + // resource names that should not be found in the test module + private static final String[] BAD_TEST_RESOURCES = { + "NotFound", + "p", + "/p", + "//p", + "p/", + "/p/Main.class", + "//p/Main.class", + "p/Main.class/", + "p//Main.class", + "./p/Main.class", + "p/./Main.class", + "../p/Main.class", + "p/../p/Main.class" + }; @BeforeTest @@ -126,10 +164,11 @@ public class ModuleReaderTest { } // test "not found" - assertFalse(reader.find(NOT_A_RESOURCE).isPresent()); - assertFalse(reader.open(NOT_A_RESOURCE).isPresent()); - assertFalse(reader.read(NOT_A_RESOURCE).isPresent()); - + for (String name : BAD_BASE_RESOURCES) { + assertFalse(reader.find(name).isPresent()); + assertFalse(reader.open(name).isPresent()); + assertFalse(reader.read(name).isPresent()); + } // test nulls try { @@ -216,7 +255,7 @@ public class ModuleReaderTest { */ void test(Path mp) throws IOException { - ModuleFinder finder = new ModulePath(Runtime.version(), true, mp); + ModuleFinder finder = ModulePath.of(Runtime.version(), true, mp); ModuleReference mref = finder.find(TEST_MODULE).get(); ModuleReader reader = mref.open(); @@ -236,9 +275,11 @@ public class ModuleReaderTest { } // test "not found" - assertFalse(reader.find(NOT_A_RESOURCE).isPresent()); - assertFalse(reader.open(NOT_A_RESOURCE).isPresent()); - assertFalse(reader.read(NOT_A_RESOURCE).isPresent()); + for (String name : BAD_TEST_RESOURCES) { + assertFalse(reader.find(name).isPresent()); + assertFalse(reader.open(name).isPresent()); + assertFalse(reader.read(name).isPresent()); + } // test nulls try { diff --git a/jdk/test/java/lang/module/ModuleReferenceTest.java b/jdk/test/java/lang/module/ModuleReferenceTest.java index bf2db124de5..f3cbb28babd 100644 --- a/jdk/test/java/lang/module/ModuleReferenceTest.java +++ b/jdk/test/java/lang/module/ModuleReferenceTest.java @@ -31,6 +31,7 @@ import java.lang.module.ModuleDescriptor; import java.lang.module.ModuleReader; import java.lang.module.ModuleReference; import java.net.URI; +import java.util.Set; import org.testng.annotations.Test; import static org.testng.Assert.*; @@ -49,10 +50,10 @@ public class ModuleReferenceTest { public void testBasic() throws Exception { ModuleDescriptor descriptor - = ModuleDescriptor.module("m") + = ModuleDescriptor.newModule("m") .exports("p") .exports("q") - .contains("p.internal") + .packages(Set.of("p.internal")) .build(); URI uri = URI.create("module:/m"); @@ -71,7 +72,7 @@ public class ModuleReferenceTest { public void testNullLocation() { ModuleDescriptor descriptor - = ModuleDescriptor.module("m") + = ModuleDescriptor.newModule("m") .exports("p") .build(); ModuleReference mref = newModuleReference(descriptor, null); diff --git a/jdk/test/java/lang/module/MultiReleaseJarTest.java b/jdk/test/java/lang/module/MultiReleaseJarTest.java index 7daddb11993..4c58e930b08 100644 --- a/jdk/test/java/lang/module/MultiReleaseJarTest.java +++ b/jdk/test/java/lang/module/MultiReleaseJarTest.java @@ -65,7 +65,7 @@ public class MultiReleaseJarTest { private static final String MODULE_INFO = "module-info.class"; - private static final int RELEASE = Runtime.version().major(); + private static final int VERSION = Runtime.version().major(); // are multi-release JARs enabled? private static final boolean MULTI_RELEASE; @@ -80,7 +80,7 @@ public class MultiReleaseJarTest { public void testBasic() throws Exception { String name = "m1"; - ModuleDescriptor descriptor = ModuleDescriptor.module(name) + ModuleDescriptor descriptor = ModuleDescriptor.newModule(name) .requires("java.base") .build(); @@ -88,8 +88,8 @@ public class MultiReleaseJarTest { .moduleInfo("module-info.class", descriptor) .resource("p/Main.class") .resource("p/Helper.class") - .resource("META-INF/versions/9/p/Helper.class") - .resource("META-INF/versions/9/p/internal/Helper9.class") + .resource("META-INF/versions/" + VERSION + "/p/Helper.class") + .resource("META-INF/versions/" + VERSION + "/p/internal/Helper.class") .build(); // find the module @@ -117,12 +117,12 @@ public class MultiReleaseJarTest { public void testModuleInfoInVersionedSection() throws Exception { String name = "m1"; - ModuleDescriptor descriptor1 = ModuleDescriptor.module(name) + ModuleDescriptor descriptor1 = ModuleDescriptor.newModule(name) .requires("java.base") .build(); // module descriptor for versioned section - ModuleDescriptor descriptor2 = ModuleDescriptor.module(name) + ModuleDescriptor descriptor2 = ModuleDescriptor.newModule(name) .requires("java.base") .requires("jdk.unsupported") .build(); @@ -131,9 +131,9 @@ public class MultiReleaseJarTest { .moduleInfo(MODULE_INFO, descriptor1) .resource("p/Main.class") .resource("p/Helper.class") - .moduleInfo("META-INF/versions/9/" + MODULE_INFO, descriptor2) - .resource("META-INF/versions/9/p/Helper.class") - .resource("META-INF/versions/9/p/internal/Helper9.class") + .moduleInfo("META-INF/versions/" + VERSION + "/" + MODULE_INFO, descriptor2) + .resource("META-INF/versions/" + VERSION + "/p/Helper.class") + .resource("META-INF/versions/" + VERSION + "/p/internal/Helper.class") .build(); // find the module @@ -161,8 +161,8 @@ public class MultiReleaseJarTest { Path jar = new JarBuilder(name) .resource("p/Main.class") .resource("p/Helper.class") - .resource("META-INF/versions/9/p/Helper.class") - .resource("META-INF/versions/9/p/internal/Helper9.class") + .resource("META-INF/versions/" + VERSION + "/p/Helper.class") + .resource("META-INF/versions/" + VERSION + "/p/internal/Helper.class") .build(); // find the module @@ -188,19 +188,19 @@ public class MultiReleaseJarTest { public void testModuleReader() throws Exception { String name = "m1"; - ModuleDescriptor descriptor1 = ModuleDescriptor.module(name) + ModuleDescriptor descriptor1 = ModuleDescriptor.newModule(name) .requires("java.base") .build(); // module descriptor for versioned section - ModuleDescriptor descriptor2 = ModuleDescriptor.module(name) + ModuleDescriptor descriptor2 = ModuleDescriptor.newModule(name) .requires("java.base") .requires("jdk.unsupported") .build(); Path jar = new JarBuilder(name) .moduleInfo(MODULE_INFO, descriptor1) - .moduleInfo("META-INF/versions/9/" + MODULE_INFO, descriptor2) + .moduleInfo("META-INF/versions/" + VERSION + "/" + MODULE_INFO, descriptor2) .build(); // find the module @@ -243,7 +243,7 @@ public class MultiReleaseJarTest { String expectedTail = "!/"; if (MULTI_RELEASE) - expectedTail += "META-INF/versions/" + RELEASE + "/"; + expectedTail += "META-INF/versions/" + VERSION + "/"; expectedTail += MODULE_INFO; assertTrue(uri.toString().endsWith(expectedTail)); diff --git a/jdk/test/java/lang/reflect/AccessibleObject/CanAccessTest.java b/jdk/test/java/lang/reflect/AccessibleObject/CanAccessTest.java new file mode 100644 index 00000000000..c73eb795b26 --- /dev/null +++ b/jdk/test/java/lang/reflect/AccessibleObject/CanAccessTest.java @@ -0,0 +1,138 @@ +/* + * Copyright (c) 2017, 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 + * @build CanAccessTest + * @modules java.base/jdk.internal.misc:+open + * @run testng CanAccessTest + * @summary Test AccessibleObject::canAccess method + */ + +import java.lang.reflect.Constructor; +import java.lang.reflect.Method; +import java.security.SecureClassLoader; + +import jdk.internal.misc.Unsafe; +import org.testng.annotations.Test; +import static org.testng.Assert.*; + +@Test +public class CanAccessTest { + private static Unsafe INSTANCE = Unsafe.getUnsafe(); + + /** + * null object parameter for Constructor + */ + public void testConstructor() throws Exception { + Constructor ctor = Unsafe.class.getDeclaredConstructor(); + assertFalse(ctor.canAccess(null)); + assertTrue(ctor.trySetAccessible()); + + try { + // non-null object parameter + ctor.canAccess(INSTANCE); + assertTrue(false); + } catch (IllegalArgumentException expected) {} + } + + /** + * Test protected constructors + */ + public void testProtectedConstructor() throws Exception { + TestLoader.testProtectedConstructorNonOpenedPackage(); + + Constructor ctor = TestLoader.class.getDeclaredConstructor(); + assertTrue(ctor.canAccess(null)); + } + + /** + * null object parameter for static members + */ + public void testStaticMember() throws Exception { + Method m = Unsafe.class.getDeclaredMethod("throwIllegalAccessError"); + assertFalse(m.canAccess(null)); + assertTrue(m.trySetAccessible()); + + try { + // non-null object parameter + m.canAccess(INSTANCE); + assertTrue(false); + } catch (IllegalArgumentException expected) { } + } + + /** + * Test protected static + */ + public void testProtectedStatic() throws Exception { + Method m = TestLoader.testProtectedStatic(); + assertFalse(m.canAccess(null)); + } + + /** + * the specified object must be an instance of the declaring class + * for instance members + */ + public void testInstanceMethod() throws Exception { + Method m = Unsafe.class.getDeclaredMethod("addressSize0"); + assertFalse(m.canAccess(INSTANCE)); + + try { + m.canAccess(null); + assertTrue(false); + } catch (IllegalArgumentException expected) { } + } + + /** + * the specified object must be an instance of the declaring class + * for instance members + */ + public void testInvalidInstanceObject() throws Exception { + Class clazz = Class.forName("sun.security.x509.X500Name"); + Method m = clazz.getDeclaredMethod("size"); + + try { + m.canAccess(INSTANCE); + assertTrue(false); + } catch (IllegalArgumentException expected) { } + } + + + static class TestLoader extends SecureClassLoader { + public static Method testProtectedStatic() throws Exception { + Method m = ClassLoader.class.getDeclaredMethod("registerAsParallelCapable"); + assertTrue(m.canAccess(null)); + return m; + } + + protected TestLoader() throws Exception { + Constructor ctor = SecureClassLoader.class.getDeclaredConstructor(); + assertFalse(ctor.canAccess(null)); + assertFalse(ctor.trySetAccessible()); + } + + public static void testProtectedConstructorNonOpenedPackage() throws Exception { + new TestLoader(); + } + } +} diff --git a/jdk/test/java/lang/reflect/AccessibleObject/ModuleSetAccessibleTest.java b/jdk/test/java/lang/reflect/AccessibleObject/ModuleSetAccessibleTest.java index da5d264b1fd..3e2bf3911c7 100644 --- a/jdk/test/java/lang/reflect/AccessibleObject/ModuleSetAccessibleTest.java +++ b/jdk/test/java/lang/reflect/AccessibleObject/ModuleSetAccessibleTest.java @@ -30,7 +30,6 @@ * @summary Test java.lang.reflect.AccessibleObject with modules */ -import java.lang.module.ModuleDescriptor; import java.lang.reflect.AccessibleObject; import java.lang.reflect.Constructor; import java.lang.reflect.Field; diff --git a/jdk/test/java/lang/reflect/AccessibleObject/TrySetAccessibleTest.java b/jdk/test/java/lang/reflect/AccessibleObject/TrySetAccessibleTest.java new file mode 100644 index 00000000000..340e7d00613 --- /dev/null +++ b/jdk/test/java/lang/reflect/AccessibleObject/TrySetAccessibleTest.java @@ -0,0 +1,201 @@ +/* + * Copyright (c) 2017, 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 + * @build TrySetAccessibleTest + * @modules java.base/java.lang:open + * java.base/jdk.internal.perf + * java.base/jdk.internal.misc:+open + * @run testng TrySetAccessibleTest + * @summary Test AccessibleObject::trySetAccessible method + */ + +import java.lang.reflect.AccessibleObject; +import java.lang.reflect.Constructor; +import java.lang.reflect.Field; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; + +import jdk.internal.misc.Unsafe; +import jdk.internal.perf.Perf; + +import org.testng.annotations.Test; +import static org.testng.Assert.*; + +@Test +public class TrySetAccessibleTest { + /** + * Invoke a private constructor on a public class in an exported package + */ + public void testPrivateConstructorInExportedPackage() throws Exception { + Constructor ctor = Perf.class.getDeclaredConstructor(); + + try { + ctor.newInstance(); + assertTrue(false); + } catch (IllegalAccessException expected) { } + + assertFalse(ctor.trySetAccessible()); + assertFalse(ctor.canAccess(null)); + } + + /** + * Invoke a private constructor on a public class in an open package + */ + public void testPrivateConstructorInOpenedPackage() throws Exception { + Constructor ctor = Unsafe.class.getDeclaredConstructor(); + + try { + ctor.newInstance(); + assertTrue(false); + } catch (IllegalAccessException expected) { } + + assertTrue(ctor.trySetAccessible()); + assertTrue(ctor.canAccess(null)); + Unsafe unsafe = (Unsafe) ctor.newInstance(); + } + + /** + * Invoke a private method on a public class in an exported package + */ + public void testPrivateMethodInExportedPackage() throws Exception { + Method m = Perf.class.getDeclaredMethod("getBytes", String.class); + try { + m.invoke(null); + assertTrue(false); + } catch (IllegalAccessException expected) { } + + assertFalse(m.trySetAccessible()); + assertFalse(m.canAccess(null)); + } + + + /** + * Invoke a private method on a public class in an open package + */ + public void testPrivateMethodInOpenedPackage() throws Exception { + Method m = Unsafe.class.getDeclaredMethod("throwIllegalAccessError"); + assertFalse(m.canAccess(null)); + + try { + m.invoke(null); + assertTrue(false); + } catch (IllegalAccessException expected) { } + + assertTrue(m.trySetAccessible()); + assertTrue(m.canAccess(null)); + try { + m.invoke(null); + assertTrue(false); + } catch (InvocationTargetException e) { + // thrown by throwIllegalAccessError + assertTrue(e.getCause() instanceof IllegalAccessError); + } + } + + /** + * Invoke a private method on a public class in an exported package + */ + public void testPrivateFieldInExportedPackage() throws Exception { + Field f = Perf.class.getDeclaredField("instance"); + try { + f.get(null); + assertTrue(false); + } catch (IllegalAccessException expected) { } + + assertFalse(f.trySetAccessible()); + assertFalse(f.canAccess(null)); + try { + f.get(null); + assertTrue(false); + } catch (IllegalAccessException expected) {} + } + + /** + * Access a private field in a public class that is an exported package + */ + public void testPrivateFieldInOpenedPackage() throws Exception { + Field f = Unsafe.class.getDeclaredField("theUnsafe"); + + try { + f.get(null); + assertTrue(false); + } catch (IllegalAccessException expected) { } + + assertTrue(f.trySetAccessible()); + assertTrue(f.canAccess(null)); + Unsafe unsafe = (Unsafe) f.get(null); + } + + + /** + * Invoke a public constructor on a public class in a non-exported package + */ + public void testPublicConstructorInNonExportedPackage() throws Exception { + Class clazz = Class.forName("sun.security.x509.X500Name"); + Constructor ctor = clazz.getConstructor(String.class); + + try { + ctor.newInstance("cn=duke"); + assertTrue(false); + } catch (IllegalAccessException expected) { } + + assertFalse(ctor.trySetAccessible()); + assertFalse(ctor.canAccess(null)); + assertTrue(ctor.trySetAccessible() == ctor.isAccessible()); + } + + + /** + * Access a public field in a public class that in a non-exported package + */ + public void testPublicFieldInNonExportedPackage() throws Exception { + Class clazz = Class.forName("sun.security.x509.X500Name"); + Field f = clazz.getField("SERIALNUMBER_OID"); + + try { + f.get(null); + assertTrue(false); + } catch (IllegalAccessException expected) { } + + assertFalse(f.trySetAccessible()); + assertFalse(f.canAccess(null)); + } + + + /** + * Test that the Class constructor cannot be make accessible. + */ + public void testJavaLangClass() throws Exception { + + // non-public constructor + Constructor ctor + = Class.class.getDeclaredConstructor(ClassLoader.class, Class.class); + AccessibleObject[] ctors = { ctor }; + + assertFalse(ctor.trySetAccessible()); + assertFalse(ctor.canAccess(null)); + } + +} diff --git a/jdk/test/java/lang/reflect/Layer/BasicLayerTest.java b/jdk/test/java/lang/reflect/Layer/BasicLayerTest.java index 8f14171ce87..1bb04d9c12e 100644 --- a/jdk/test/java/lang/reflect/Layer/BasicLayerTest.java +++ b/jdk/test/java/lang/reflect/Layer/BasicLayerTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2017, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -24,6 +24,7 @@ /** * @test * @library /lib/testlibrary + * @modules java.base/jdk.internal.misc * @build BasicLayerTest ModuleUtils * @compile layertest/Test.java * @run testng BasicLayerTest @@ -43,12 +44,22 @@ import java.util.Optional; import java.util.Set; import java.util.stream.Collectors; +import jdk.internal.misc.SharedSecrets; import org.testng.annotations.Test; import static org.testng.Assert.*; @Test public class BasicLayerTest { + /** + * Creates a "non-strict" builder for building a module. This allows the + * test the create ModuleDescriptor objects that do not require java.base. + */ + private static ModuleDescriptor.Builder newBuilder(String mn) { + return SharedSecrets.getJavaLangModuleAccess() + .newModuleBuilder(mn, false, Set.of()); + } + /** * Exercise Layer.empty() */ @@ -109,25 +120,22 @@ public class BasicLayerTest { * Exercise Layer defineModules, created with empty layer as parent */ public void testLayerOnEmpty() { - ModuleDescriptor descriptor1 - = ModuleDescriptor.module("m1") + ModuleDescriptor descriptor1 = newBuilder("m1") .requires("m2") .exports("p1") .build(); - ModuleDescriptor descriptor2 - = ModuleDescriptor.module("m2") + ModuleDescriptor descriptor2 = newBuilder("m2") .requires("m3") .build(); - ModuleDescriptor descriptor3 - = ModuleDescriptor.module("m3") + ModuleDescriptor descriptor3 = newBuilder("m3") .build(); ModuleFinder finder = ModuleUtils.finderOf(descriptor1, descriptor2, descriptor3); - Configuration cf = resolveRequires(finder, "m1"); + Configuration cf = resolve(finder, "m1"); // map each module to its own class loader for this test ClassLoader loader1 = new ClassLoader() { }; @@ -191,15 +199,13 @@ public class BasicLayerTest { * Exercise Layer defineModules, created with boot layer as parent */ public void testLayerOnBoot() { - ModuleDescriptor descriptor1 - = ModuleDescriptor.module("m1") + ModuleDescriptor descriptor1 = newBuilder("m1") .requires("m2") .requires("java.base") .exports("p1") .build(); - ModuleDescriptor descriptor2 - = ModuleDescriptor.module("m2") + ModuleDescriptor descriptor2 = newBuilder("m2") .requires("java.base") .build(); @@ -207,7 +213,7 @@ public class BasicLayerTest { = ModuleUtils.finderOf(descriptor1, descriptor2); Configuration parent = Layer.boot().configuration(); - Configuration cf = resolveRequires(parent, finder, "m1"); + Configuration cf = resolve(parent, finder, "m1"); ClassLoader loader = new ClassLoader() { }; @@ -256,21 +262,19 @@ public class BasicLayerTest { * have the same module-private package. */ public void testPackageContainedInSelfAndOther() { - ModuleDescriptor descriptor1 - = ModuleDescriptor.module("m1") + ModuleDescriptor descriptor1 = newBuilder("m1") .requires("m2") - .contains("p") + .packages(Set.of("p")) .build(); - ModuleDescriptor descriptor2 - = ModuleDescriptor.module("m2") - .contains("p") + ModuleDescriptor descriptor2 = newBuilder("m2") + .packages(Set.of("p")) .build(); ModuleFinder finder = ModuleUtils.finderOf(descriptor1, descriptor2); - Configuration cf = resolveRequires(finder, "m1"); + Configuration cf = resolve(finder, "m1"); assertTrue(cf.modules().size() == 2); // one loader per module, should be okay @@ -292,22 +296,18 @@ public class BasicLayerTest { public void testSameExportInPartitionedGraph() { // m1 reads m2, m2 exports p to m1 - ModuleDescriptor descriptor1 - = ModuleDescriptor.module("m1") + ModuleDescriptor descriptor1 = newBuilder("m1") .requires("m2") .build(); - ModuleDescriptor descriptor2 - = ModuleDescriptor.module("m2") + ModuleDescriptor descriptor2 = newBuilder("m2") .exports("p", Set.of("m1")) .build(); // m3 reads m4, m4 exports p to m3 - ModuleDescriptor descriptor3 - = ModuleDescriptor.module("m3") + ModuleDescriptor descriptor3 = newBuilder("m3") .requires("m4") .build(); - ModuleDescriptor descriptor4 - = ModuleDescriptor.module("m4") + ModuleDescriptor descriptor4 = newBuilder("m4") .exports("p", Set.of("m3")) .build(); @@ -317,7 +317,7 @@ public class BasicLayerTest { descriptor3, descriptor4); - Configuration cf = resolveRequires(finder, "m1", "m3"); + Configuration cf = resolve(finder, "m1", "m3"); assertTrue(cf.modules().size() == 4); // one loader per module @@ -353,16 +353,15 @@ public class BasicLayerTest { ModuleDescriptor base = Object.class.getModule().getDescriptor(); assertTrue(base.packages().contains("sun.launcher")); - ModuleDescriptor descriptor - = ModuleDescriptor.module("m1") + ModuleDescriptor descriptor = newBuilder("m1") .requires("java.base") - .contains("sun.launcher") + .packages(Set.of("sun.launcher")) .build(); ModuleFinder finder = ModuleUtils.finderOf(descriptor); Configuration parent = Layer.boot().configuration(); - Configuration cf = parent.resolveRequires(finder, ModuleFinder.of(), Set.of("m1")); + Configuration cf = parent.resolve(finder, ModuleFinder.of(), Set.of("m1")); assertTrue(cf.modules().size() == 1); ClassLoader loader = new ClassLoader() { }; @@ -382,18 +381,16 @@ public class BasicLayerTest { // cf1: m1 and m2, m2 requires transitive m1 - ModuleDescriptor descriptor1 - = ModuleDescriptor.module("m1") + ModuleDescriptor descriptor1 = newBuilder("m1") .build(); - ModuleDescriptor descriptor2 - = ModuleDescriptor.module("m2") + ModuleDescriptor descriptor2 = newBuilder("m2") .requires(Set.of(Requires.Modifier.TRANSITIVE), "m1") .build(); ModuleFinder finder1 = ModuleUtils.finderOf(descriptor1, descriptor2); - Configuration cf1 = resolveRequires(finder1, "m2"); + Configuration cf1 = resolve(finder1, "m2"); ClassLoader cl1 = new ClassLoader() { }; Layer layer1 = Layer.empty().defineModules(cf1, mn -> cl1); @@ -401,14 +398,13 @@ public class BasicLayerTest { // cf2: m3, m3 requires m2 - ModuleDescriptor descriptor3 - = ModuleDescriptor.module("m3") + ModuleDescriptor descriptor3 = newBuilder("m3") .requires("m2") .build(); ModuleFinder finder2 = ModuleUtils.finderOf(descriptor3); - Configuration cf2 = resolveRequires(cf1, finder2, "m3"); + Configuration cf2 = resolve(cf1, finder2, "m3"); ClassLoader cl2 = new ClassLoader() { }; Layer layer2 = layer1.defineModules(cf2, mn -> cl2); @@ -456,13 +452,11 @@ public class BasicLayerTest { // cf1: m1 - ModuleDescriptor descriptor1 - = ModuleDescriptor.module("m1") - .build(); + ModuleDescriptor descriptor1 = newBuilder("m1").build(); ModuleFinder finder1 = ModuleUtils.finderOf(descriptor1); - Configuration cf1 = resolveRequires(finder1, "m1"); + Configuration cf1 = resolve(finder1, "m1"); ClassLoader cl1 = new ClassLoader() { }; Layer layer1 = Layer.empty().defineModules(cf1, mn -> cl1); @@ -470,19 +464,17 @@ public class BasicLayerTest { // cf2: m2, m3: m2 requires transitive m1, m3 requires m2 - ModuleDescriptor descriptor2 - = ModuleDescriptor.module("m2") + ModuleDescriptor descriptor2 = newBuilder("m2") .requires(Set.of(Requires.Modifier.TRANSITIVE), "m1") .build(); - ModuleDescriptor descriptor3 - = ModuleDescriptor.module("m3") + ModuleDescriptor descriptor3 = newBuilder("m3") .requires("m2") .build(); ModuleFinder finder2 = ModuleUtils.finderOf(descriptor2, descriptor3); - Configuration cf2 = resolveRequires(cf1, finder2, "m3"); + Configuration cf2 = resolve(cf1, finder2, "m3"); ClassLoader cl2 = new ClassLoader() { }; Layer layer2 = layer1.defineModules(cf2, mn -> cl2); @@ -527,13 +519,11 @@ public class BasicLayerTest { // cf1: m1 - ModuleDescriptor descriptor1 - = ModuleDescriptor.module("m1") - .build(); + ModuleDescriptor descriptor1 = newBuilder("m1").build(); ModuleFinder finder1 = ModuleUtils.finderOf(descriptor1); - Configuration cf1 = resolveRequires(finder1, "m1"); + Configuration cf1 = resolve(finder1, "m1"); ClassLoader cl1 = new ClassLoader() { }; Layer layer1 = Layer.empty().defineModules(cf1, mn -> cl1); @@ -541,14 +531,13 @@ public class BasicLayerTest { // cf2: m2 requires transitive m1 - ModuleDescriptor descriptor2 - = ModuleDescriptor.module("m2") + ModuleDescriptor descriptor2 = newBuilder("m2") .requires(Set.of(Requires.Modifier.TRANSITIVE), "m1") .build(); ModuleFinder finder2 = ModuleUtils.finderOf(descriptor2); - Configuration cf2 = resolveRequires(cf1, finder2, "m2"); + Configuration cf2 = resolve(cf1, finder2, "m2"); ClassLoader cl2 = new ClassLoader() { }; Layer layer2 = layer1.defineModules(cf2, mn -> cl2); @@ -556,14 +545,13 @@ public class BasicLayerTest { // cf3: m3 requires m2 - ModuleDescriptor descriptor3 - = ModuleDescriptor.module("m3") + ModuleDescriptor descriptor3 = newBuilder("m3") .requires("m2") .build(); ModuleFinder finder3 = ModuleUtils.finderOf(descriptor3); - Configuration cf3 = resolveRequires(cf2, finder3, "m3"); + Configuration cf3 = resolve(cf2, finder3, "m3"); ClassLoader cl3 = new ClassLoader() { }; Layer layer3 = layer2.defineModules(cf3, mn -> cl3); @@ -610,18 +598,16 @@ public class BasicLayerTest { // cf1: m1, m2 requires transitive m1 - ModuleDescriptor descriptor1 - = ModuleDescriptor.module("m1") + ModuleDescriptor descriptor1 = newBuilder("m1") .build(); - ModuleDescriptor descriptor2 - = ModuleDescriptor.module("m2") + ModuleDescriptor descriptor2 = newBuilder("m2") .requires(Set.of(Requires.Modifier.TRANSITIVE), "m1") .build(); ModuleFinder finder1 = ModuleUtils.finderOf(descriptor1, descriptor2); - Configuration cf1 = resolveRequires(finder1, "m2"); + Configuration cf1 = resolve(finder1, "m2"); ClassLoader cl1 = new ClassLoader() { }; Layer layer1 = Layer.empty().defineModules(cf1, mn -> cl1); @@ -629,20 +615,18 @@ public class BasicLayerTest { // cf2: m3 requires transitive m2, m4 requires m3 - ModuleDescriptor descriptor3 - = ModuleDescriptor.module("m3") + ModuleDescriptor descriptor3 = newBuilder("m3") .requires(Set.of(Requires.Modifier.TRANSITIVE), "m2") .build(); - ModuleDescriptor descriptor4 - = ModuleDescriptor.module("m4") + ModuleDescriptor descriptor4 = newBuilder("m4") .requires("m3") .build(); ModuleFinder finder2 = ModuleUtils.finderOf(descriptor3, descriptor4); - Configuration cf2 = resolveRequires(cf1, finder2, "m3", "m4"); + Configuration cf2 = resolve(cf1, finder2, "m3", "m4"); ClassLoader cl2 = new ClassLoader() { }; Layer layer2 = layer1.defineModules(cf2, mn -> cl2); @@ -693,8 +677,7 @@ public class BasicLayerTest { @Test(expectedExceptions = { LayerInstantiationException.class }) public void testModuleAlreadyDefinedToLoader() { - ModuleDescriptor md - = ModuleDescriptor.module("m") + ModuleDescriptor md = newBuilder("m") .requires("java.base") .build(); @@ -702,7 +685,7 @@ public class BasicLayerTest { Configuration parent = Layer.boot().configuration(); - Configuration cf = parent.resolveRequires(finder, ModuleFinder.of(), Set.of("m")); + Configuration cf = parent.resolve(finder, ModuleFinder.of(), Set.of("m")); ClassLoader loader = new ClassLoader() { }; @@ -722,15 +705,13 @@ public class BasicLayerTest { @Test(expectedExceptions = { LayerInstantiationException.class }) public void testPackageAlreadyInNamedModule() { - ModuleDescriptor md1 - = ModuleDescriptor.module("m1") - .contains("p") + ModuleDescriptor md1 = newBuilder("m1") + .packages(Set.of("p")) .requires("java.base") .build(); - ModuleDescriptor md2 - = ModuleDescriptor.module("m2") - .contains("p") + ModuleDescriptor md2 = newBuilder("m2") + .packages(Set.of("p")) .requires("java.base") .build(); @@ -742,13 +723,13 @@ public class BasicLayerTest { Configuration parent = Layer.boot().configuration(); - Configuration cf1 = parent.resolveRequires(finder, ModuleFinder.of(), Set.of("m1")); + Configuration cf1 = parent.resolve(finder, ModuleFinder.of(), Set.of("m1")); Layer layer1 = Layer.boot().defineModules(cf1, mn -> loader); // attempt to define m2 containing package p to class loader - Configuration cf2 = parent.resolveRequires(finder, ModuleFinder.of(), Set.of("m2")); + Configuration cf2 = parent.resolve(finder, ModuleFinder.of(), Set.of("m2")); // should throw exception because p already in m1 Layer layer2 = Layer.boot().defineModules(cf2, mn -> loader); @@ -767,16 +748,15 @@ public class BasicLayerTest { Class c = layertest.Test.class; assertFalse(c.getModule().isNamed()); // in unnamed module - ModuleDescriptor md - = ModuleDescriptor.module("m") - .contains(c.getPackageName()) + ModuleDescriptor md = newBuilder("m") + .packages(Set.of(c.getPackageName())) .requires("java.base") .build(); ModuleFinder finder = ModuleUtils.finderOf(md); Configuration parent = Layer.boot().configuration(); - Configuration cf = parent.resolveRequires(finder, ModuleFinder.of(), Set.of("m")); + Configuration cf = parent.resolve(finder, ModuleFinder.of(), Set.of("m")); Layer.boot().defineModules(cf, mn -> c.getClassLoader()); } @@ -786,8 +766,7 @@ public class BasicLayerTest { * Attempt to create a Layer with a module named "java.base". */ public void testLayerWithJavaBase() { - ModuleDescriptor descriptor - = ModuleDescriptor.module("java.base") + ModuleDescriptor descriptor = newBuilder("java.base") .exports("java.lang") .build(); @@ -795,7 +774,7 @@ public class BasicLayerTest { Configuration cf = Layer.boot() .configuration() - .resolveRequires(finder, ModuleFinder.of(), Set.of("java.base")); + .resolve(finder, ModuleFinder.of(), Set.of("java.base")); assertTrue(cf.modules().size() == 1); ClassLoader scl = ClassLoader.getSystemClassLoader(); @@ -824,16 +803,15 @@ public class BasicLayerTest { */ @Test(enabled = false) public void testLayerWithJavaPackage() { - ModuleDescriptor descriptor - = ModuleDescriptor.module("foo") - .contains("java.foo") + ModuleDescriptor descriptor = newBuilder("foo") + .packages(Set.of("java.foo")) .build(); ModuleFinder finder = ModuleUtils.finderOf(descriptor); Configuration cf = Layer.boot() .configuration() - .resolveRequires(finder, ModuleFinder.of(), Set.of("foo")); + .resolve(finder, ModuleFinder.of(), Set.of("foo")); assertTrue(cf.modules().size() == 1); ClassLoader pcl = ClassLoader.getPlatformClassLoader(); @@ -870,15 +848,14 @@ public class BasicLayerTest { */ @Test(expectedExceptions = { LayerInstantiationException.class }) public void testLayerWithBootLoader() { - ModuleDescriptor descriptor - = ModuleDescriptor.module("m1") + ModuleDescriptor descriptor = newBuilder("m1") .build(); ModuleFinder finder = ModuleUtils.finderOf(descriptor); Configuration cf = Layer.boot() .configuration() - .resolveRequires(finder, ModuleFinder.of(), Set.of("m1")); + .resolve(finder, ModuleFinder.of(), Set.of("m1")); assertTrue(cf.modules().size() == 1); Layer.boot().defineModules(cf, mn -> null ); @@ -891,15 +868,14 @@ public class BasicLayerTest { @Test(expectedExceptions = { IllegalArgumentException.class }) public void testIncorrectParent1() { - ModuleDescriptor descriptor1 - = ModuleDescriptor.module("m1") + ModuleDescriptor descriptor1 = newBuilder("m1") .requires("java.base") .build(); ModuleFinder finder = ModuleUtils.finderOf(descriptor1); Configuration parent = Layer.boot().configuration(); - Configuration cf = parent.resolveRequires(finder, ModuleFinder.of(), Set.of("m1")); + Configuration cf = parent.resolve(finder, ModuleFinder.of(), Set.of("m1")); ClassLoader loader = new ClassLoader() { }; Layer.empty().defineModules(cf, mn -> loader); @@ -912,13 +888,12 @@ public class BasicLayerTest { @Test(expectedExceptions = { IllegalArgumentException.class }) public void testIncorrectParent2() { - ModuleDescriptor descriptor1 - = ModuleDescriptor.module("m1") + ModuleDescriptor descriptor1 = newBuilder("m1") .build(); ModuleFinder finder = ModuleUtils.finderOf(descriptor1); - Configuration cf = resolveRequires(finder, "m1"); + Configuration cf = resolve(finder, "m1"); ClassLoader loader = new ClassLoader() { }; Layer.boot().defineModules(cf, mn -> loader); @@ -935,7 +910,7 @@ public class BasicLayerTest { @Test(expectedExceptions = { NullPointerException.class }) public void testCreateWithNull2() { - Configuration cf = resolveRequires(Layer.boot().configuration(), ModuleFinder.of()); + Configuration cf = resolve(Layer.boot().configuration(), ModuleFinder.of()); Layer.boot().defineModules(cf, null); } @@ -975,14 +950,14 @@ public class BasicLayerTest { * Resolve the given modules, by name, and returns the resulting * Configuration. */ - private static Configuration resolveRequires(Configuration cf, - ModuleFinder finder, - String... roots) { - return cf.resolveRequires(finder, ModuleFinder.of(), Set.of(roots)); + private static Configuration resolve(Configuration cf, + ModuleFinder finder, + String... roots) { + return cf.resolve(finder, ModuleFinder.of(), Set.of(roots)); } - private static Configuration resolveRequires(ModuleFinder finder, - String... roots) { - return resolveRequires(Configuration.empty(), finder, roots); + private static Configuration resolve(ModuleFinder finder, + String... roots) { + return resolve(Configuration.empty(), finder, roots); } } diff --git a/jdk/test/java/lang/reflect/Layer/LayerAndLoadersTest.java b/jdk/test/java/lang/reflect/Layer/LayerAndLoadersTest.java index 23c7d06d15d..ac6c035c297 100644 --- a/jdk/test/java/lang/reflect/Layer/LayerAndLoadersTest.java +++ b/jdk/test/java/lang/reflect/Layer/LayerAndLoadersTest.java @@ -81,7 +81,7 @@ public class LayerAndLoadersTest { */ public void testWithOneLoader() throws Exception { - Configuration cf = resolveRequires("m1"); + Configuration cf = resolve("m1"); ClassLoader scl = ClassLoader.getSystemClassLoader(); @@ -110,7 +110,7 @@ public class LayerAndLoadersTest { */ public void testWithManyLoaders() throws Exception { - Configuration cf = resolveRequires("m1"); + Configuration cf = resolve("m1"); ClassLoader scl = ClassLoader.getSystemClassLoader(); @@ -145,7 +145,7 @@ public class LayerAndLoadersTest { */ public void testServicesWithOneLoader() throws Exception { - Configuration cf = resolveRequiresAndUses("m1"); + Configuration cf = resolveAndBind("m1"); ClassLoader scl = ClassLoader.getSystemClassLoader(); @@ -186,7 +186,7 @@ public class LayerAndLoadersTest { */ public void testServicesWithManyLoaders() throws Exception { - Configuration cf = resolveRequiresAndUses("m1"); + Configuration cf = resolveAndBind("m1"); ClassLoader scl = ClassLoader.getSystemClassLoader(); @@ -233,7 +233,7 @@ public class LayerAndLoadersTest { */ public void testDelegationToParent() throws Exception { - Configuration cf = resolveRequires("m1"); + Configuration cf = resolve("m1"); ClassLoader parent = this.getClass().getClassLoader(); String cn = this.getClass().getName(); @@ -267,16 +267,16 @@ public class LayerAndLoadersTest { public void testOverlappingPackages() { ModuleDescriptor descriptor1 - = ModuleDescriptor.module("m1").exports("p").build(); + = ModuleDescriptor.newModule("m1").exports("p").build(); ModuleDescriptor descriptor2 - = ModuleDescriptor.module("m2").exports("p").build(); + = ModuleDescriptor.newModule("m2").exports("p").build(); ModuleFinder finder = ModuleUtils.finderOf(descriptor1, descriptor2); Configuration cf = Layer.boot() .configuration() - .resolveRequires(finder, ModuleFinder.of(), Set.of("m1", "m2")); + .resolve(finder, ModuleFinder.of(), Set.of("m1", "m2")); // cannot define both module m1 and m2 to the same class loader try { @@ -301,29 +301,29 @@ public class LayerAndLoadersTest { public void testSplitDelegation() { ModuleDescriptor descriptor1 - = ModuleDescriptor.module("m1").exports("p").build(); + = ModuleDescriptor.newModule("m1").exports("p").build(); ModuleDescriptor descriptor2 - = ModuleDescriptor.module("m2").exports("p").build(); + = ModuleDescriptor.newModule("m2").exports("p").build(); ModuleFinder finder1 = ModuleUtils.finderOf(descriptor1, descriptor2); Configuration cf1 = Layer.boot() .configuration() - .resolveRequires(finder1, ModuleFinder.of(), Set.of("m1", "m2")); + .resolve(finder1, ModuleFinder.of(), Set.of("m1", "m2")); Layer layer1 = Layer.boot().defineModulesWithManyLoaders(cf1, null); checkLayer(layer1, "m1", "m2"); ModuleDescriptor descriptor3 - = ModuleDescriptor.module("m3").requires("m1").build(); + = ModuleDescriptor.newModule("m3").requires("m1").build(); ModuleDescriptor descriptor4 - = ModuleDescriptor.module("m4").requires("m2").build(); + = ModuleDescriptor.newModule("m4").requires("m2").build(); ModuleFinder finder2 = ModuleUtils.finderOf(descriptor3, descriptor4); - Configuration cf2 = cf1.resolveRequires(finder2, ModuleFinder.of(), + Configuration cf2 = cf1.resolve(finder2, ModuleFinder.of(), Set.of("m3", "m4")); // package p cannot be supplied by two class loaders @@ -349,13 +349,13 @@ public class LayerAndLoadersTest { */ public void testOverriding1() throws Exception { - Configuration cf1 = resolveRequires("m1"); + Configuration cf1 = resolve("m1"); Layer layer1 = Layer.boot().defineModulesWithOneLoader(cf1, null); checkLayer(layer1, "m1", "m2", "m3"); ModuleFinder finder = ModuleFinder.of(MODS_DIR); - Configuration cf2 = cf1.resolveRequires(finder, ModuleFinder.of(), + Configuration cf2 = cf1.resolve(finder, ModuleFinder.of(), Set.of("m1")); Layer layer2 = layer1.defineModulesWithOneLoader(cf2, null); @@ -398,13 +398,13 @@ public class LayerAndLoadersTest { */ public void testOverriding2() throws Exception { - Configuration cf1 = resolveRequires("m1"); + Configuration cf1 = resolve("m1"); Layer layer1 = Layer.boot().defineModulesWithManyLoaders(cf1, null); checkLayer(layer1, "m1", "m2", "m3"); ModuleFinder finder = ModuleFinder.of(MODS_DIR); - Configuration cf2 = cf1.resolveRequires(finder, ModuleFinder.of(), + Configuration cf2 = cf1.resolve(finder, ModuleFinder.of(), Set.of("m1")); Layer layer2 = layer1.defineModulesWithManyLoaders(cf2, null); @@ -492,14 +492,14 @@ public class LayerAndLoadersTest { */ public void testOverriding3() throws Exception { - Configuration cf1 = resolveRequires("m1"); + Configuration cf1 = resolve("m1"); Layer layer1 = Layer.boot().defineModulesWithOneLoader(cf1, null); checkLayer(layer1, "m1", "m2", "m3"); ModuleFinder finder = finderFor("m1", "m3"); - Configuration cf2 = cf1.resolveRequires(finder, ModuleFinder.of(), + Configuration cf2 = cf1.resolve(finder, ModuleFinder.of(), Set.of("m1")); Layer layer2 = layer1.defineModulesWithOneLoader(cf2, null); @@ -529,14 +529,14 @@ public class LayerAndLoadersTest { */ public void testOverriding4() throws Exception { - Configuration cf1 = resolveRequires("m1"); + Configuration cf1 = resolve("m1"); Layer layer1 = Layer.boot().defineModulesWithManyLoaders(cf1, null); checkLayer(layer1, "m1", "m2", "m3"); ModuleFinder finder = finderFor("m1", "m3"); - Configuration cf2 = cf1.resolveRequires(finder, ModuleFinder.of(), + Configuration cf2 = cf1.resolve(finder, ModuleFinder.of(), Set.of("m1")); Layer layer2 = layer1.defineModulesWithManyLoaders(cf2, null); @@ -577,7 +577,7 @@ public class LayerAndLoadersTest { * Layer.defineModulesWithOneLoader. */ public void testResourcesOneLoader() throws Exception { - Configuration cf = resolveRequires("m1"); + Configuration cf = resolve("m1"); ClassLoader scl = ClassLoader.getSystemClassLoader(); Layer layer = Layer.boot().defineModulesWithOneLoader(cf, scl); ClassLoader loader = layer.findLoader("m1"); @@ -589,7 +589,7 @@ public class LayerAndLoadersTest { * Layer.defineModulesWithOneLoader. */ public void testResourcesManyLoaders() throws Exception { - Configuration cf = resolveRequires("m1"); + Configuration cf = resolve("m1"); ClassLoader scl = ClassLoader.getSystemClassLoader(); Layer layer = Layer.boot().defineModulesWithManyLoaders(cf, scl); ClassLoader loader = layer.findLoader("m1"); @@ -621,22 +621,22 @@ public class LayerAndLoadersTest { * Resolve the given modules, by name, and returns the resulting * Configuration. */ - private static Configuration resolveRequires(String... roots) { + private static Configuration resolve(String... roots) { ModuleFinder finder = ModuleFinder.of(MODS_DIR); return Layer.boot() .configuration() - .resolveRequires(finder, ModuleFinder.of(), Set.of(roots)); + .resolve(finder, ModuleFinder.of(), Set.of(roots)); } /** * Resolve the given modules, by name, and returns the resulting * Configuration. */ - private static Configuration resolveRequiresAndUses(String... roots) { + private static Configuration resolveAndBind(String... roots) { ModuleFinder finder = ModuleFinder.of(MODS_DIR); return Layer.boot() .configuration() - .resolveRequiresAndUses(finder, ModuleFinder.of(), Set.of(roots)); + .resolveAndBind(finder, ModuleFinder.of(), Set.of(roots)); } diff --git a/jdk/test/java/lang/reflect/Layer/LayerControllerTest.java b/jdk/test/java/lang/reflect/Layer/LayerControllerTest.java index 6582e493c07..4e4a0dbd5bd 100644 --- a/jdk/test/java/lang/reflect/Layer/LayerControllerTest.java +++ b/jdk/test/java/lang/reflect/Layer/LayerControllerTest.java @@ -50,22 +50,22 @@ public class LayerControllerTest { */ private Layer.Controller createTestLayer() { ModuleDescriptor descriptor1 - = ModuleDescriptor.module("m1") - .contains("p1") + = ModuleDescriptor.newModule("m1") + .packages(Set.of("p1")) .requires("java.base") .build(); ModuleDescriptor descriptor2 - = ModuleDescriptor.module("m2") + = ModuleDescriptor.newModule("m2") .requires("java.base") - .contains("p2") + .packages(Set.of("p2")) .build(); ModuleFinder finder = ModuleUtils.finderOf(descriptor1, descriptor2); Layer bootLayer = Layer.boot(); Configuration cf = bootLayer.configuration() - .resolveRequires(finder, ModuleFinder.of(), Set.of("m1", "m2")); + .resolve(finder, ModuleFinder.of(), Set.of("m1", "m2")); ClassLoader scl = ClassLoader.getSystemClassLoader(); @@ -193,4 +193,4 @@ public class LayerControllerTest { assertTrue(false); } catch (NullPointerException expected) { } } -} \ No newline at end of file +} diff --git a/jdk/test/java/lang/reflect/Module/AnnotationsTest.java b/jdk/test/java/lang/reflect/Module/AnnotationsTest.java index 0390698b282..d30a0c07779 100644 --- a/jdk/test/java/lang/reflect/Module/AnnotationsTest.java +++ b/jdk/test/java/lang/reflect/Module/AnnotationsTest.java @@ -144,7 +144,7 @@ public class AnnotationsTest { Layer bootLayer = Layer.boot(); Configuration cf = bootLayer.configuration() - .resolveRequires(finder, ModuleFinder.of(), Set.of(name)); + .resolve(finder, ModuleFinder.of(), Set.of(name)); ClassLoader scl = ClassLoader.getSystemClassLoader(); Layer layer = bootLayer.defineModulesWithOneLoader(cf, scl); diff --git a/jdk/test/java/lang/reflect/Module/BasicModuleTest.java b/jdk/test/java/lang/reflect/Module/BasicModuleTest.java index bafa57ba3a8..90fb62b4a2e 100644 --- a/jdk/test/java/lang/reflect/Module/BasicModuleTest.java +++ b/jdk/test/java/lang/reflect/Module/BasicModuleTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2017, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,8 +25,10 @@ import java.lang.module.ModuleDescriptor.Exports; import java.lang.module.ResolvedModule; import java.lang.reflect.Layer; import java.lang.reflect.Module; +import java.nio.file.spi.FileSystemProvider; // service type in java.base import java.util.function.Predicate; import java.util.stream.Stream; +import javax.print.PrintServiceLookup; // service type in java.desktop import org.testng.annotations.Test; import static org.testng.Assert.*; @@ -170,6 +172,14 @@ public class BasicModuleTest { // canRead assertTrue(base.canRead(base)); + assertFalse(base.canRead(thisModule)); + + // addReads + try { + base.addReads(thisModule); + assertTrue(false); + } catch (IllegalCallerException expected) { } + assertFalse(base.canRead(thisModule)); // isExported assertTrue(base.isExported("java.lang")); @@ -182,6 +192,18 @@ public class BasicModuleTest { assertFalse(base.isExported("java.wombat", thisModule)); assertFalse(base.isExported("java.wombat", base)); + // addExports + try { + base.addExports("java.lang", thisModule); + assertTrue(false); + } catch (IllegalCallerException expected) { } + try { + base.addExports("jdk.internal.misc", thisModule); + assertTrue(false); + } catch (IllegalCallerException expected) { } + assertFalse(base.isExported("jdk.internal.misc")); + assertFalse(base.isExported("jdk.internal.misc", thisModule)); + // isOpen assertFalse(base.isOpen("java.lang")); assertFalse(base.isOpen("java.lang", thisModule)); @@ -192,6 +214,29 @@ public class BasicModuleTest { assertFalse(base.isOpen("java.wombat")); assertFalse(base.isOpen("java.wombat", thisModule)); assertFalse(base.isOpen("java.wombat", base)); + + // addOpens + try { + base.addOpens("jdk.internal.misc", thisModule); + assertTrue(false); + } catch (IllegalCallerException expected) { } + assertFalse(base.isOpen("jdk.internal.misc")); + assertFalse(base.isOpen("jdk.internal.misc", thisModule)); + + // canUse + assertTrue(base.canUse(FileSystemProvider.class)); + assertFalse(base.canUse(Thread.class)); + + // addUses + try { + base.addUses(FileSystemProvider.class); + assertTrue(false); + } catch (IllegalCallerException expected) { } + try { + base.addUses(Thread.class); + assertTrue(false); + } catch (IllegalCallerException expected) { } + assertFalse(base.canUse(Thread.class)); } @@ -226,26 +271,68 @@ public class BasicModuleTest { assertTrue(desktop.canRead(base)); assertTrue(desktop.canRead(xml)); + // addReads + try { + desktop.addReads(thisModule); + assertTrue(false); + } catch (IllegalCallerException expected) { } + assertFalse(desktop.canRead(thisModule)); + // isExported assertTrue(desktop.isExported("java.awt")); assertTrue(desktop.isExported("java.awt", thisModule)); + assertFalse(desktop.isExported("sun.awt")); + assertFalse(desktop.isExported("sun.awt", thisModule)); + assertTrue(desktop.isExported("sun.awt", desktop)); assertFalse(desktop.isExported("java.wombat")); assertFalse(desktop.isExported("java.wombat", thisModule)); + assertFalse(desktop.isExported("java.wombat", base)); + + // addExports + try { + desktop.addExports("java.awt", thisModule); + assertTrue(false); + } catch (IllegalCallerException expected) { } + try { + desktop.addExports("sun.awt", thisModule); + assertTrue(false); + } catch (IllegalCallerException expected) { } + assertFalse(desktop.isExported("sun.awt")); + assertFalse(desktop.isExported("sun.awt", thisModule)); + + // isOpen + assertFalse(desktop.isOpen("java.awt")); + assertFalse(desktop.isOpen("java.awt", thisModule)); + assertTrue(desktop.isOpen("java.awt", desktop)); + assertFalse(desktop.isOpen("sun.awt")); + assertFalse(desktop.isOpen("sun.awt", thisModule)); + assertTrue(desktop.isOpen("sun.awt", desktop)); + assertFalse(desktop.isOpen("java.wombat")); + assertFalse(desktop.isOpen("java.wombat", thisModule)); + assertFalse(desktop.isOpen("java.wombat", desktop)); + + // addOpens + try { + base.addOpens("sun.awt", thisModule); + assertTrue(false); + } catch (IllegalCallerException expected) { } + assertFalse(desktop.isOpen("sun.awt")); + assertFalse(desktop.isOpen("sun.awt", thisModule)); + + // canUse + assertTrue(base.canUse(FileSystemProvider.class)); + assertFalse(base.canUse(Thread.class)); + + // addUses + try { + desktop.addUses(PrintServiceLookup.class); + assertTrue(false); + } catch (IllegalCallerException expected) { } + try { + desktop.addUses(Thread.class); + assertTrue(false); + } catch (IllegalCallerException expected) { } + assertFalse(desktop.canUse(Thread.class)); } - - @Test(expectedExceptions = { NullPointerException.class }) - public void testIsExportedNull() { - Module thisModule = this.getClass().getModule(); - thisModule.isExported(null, thisModule); - } - - - @Test(expectedExceptions = { NullPointerException.class }) - public void testIsExportedToNull() { - Module thisModule = this.getClass().getModule(); - thisModule.isExported("", null); - } - - } diff --git a/jdk/test/java/lang/reflect/Module/WithSecurityManager.java b/jdk/test/java/lang/reflect/Module/WithSecurityManager.java index dfb6b760f10..794ebf00e44 100644 --- a/jdk/test/java/lang/reflect/Module/WithSecurityManager.java +++ b/jdk/test/java/lang/reflect/Module/WithSecurityManager.java @@ -126,7 +126,7 @@ public class WithSecurityManager { Layer bootLayer = Layer.boot(); Configuration cf = bootLayer .configuration() - .resolveRequires(finder, ModuleFinder.of(), Set.of(ANOTHER_MODULE)); + .resolve(finder, ModuleFinder.of(), Set.of(ANOTHER_MODULE)); Layer layer = bootLayer.defineModulesWithOneLoader(cf, null); Optional om = layer.findModule(mn); diff --git a/jdk/test/java/lang/reflect/Module/addXXX/Driver.java b/jdk/test/java/lang/reflect/Module/addXXX/Driver.java new file mode 100644 index 00000000000..0daf09ffe2a --- /dev/null +++ b/jdk/test/java/lang/reflect/Module/addXXX/Driver.java @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2017, 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 + * @build test/* m1/* m2/* m3/* m4/* + * @run testng/othervm test/test.Main + * @summary Basic test case for Module::addXXX methods + */ diff --git a/jdk/test/java/lang/reflect/Module/addXXX/m1/module-info.java b/jdk/test/java/lang/reflect/Module/addXXX/m1/module-info.java new file mode 100644 index 00000000000..a34a266ef57 --- /dev/null +++ b/jdk/test/java/lang/reflect/Module/addXXX/m1/module-info.java @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2017, 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. + */ +module m1 { + exports p1; +} diff --git a/jdk/test/java/lang/reflect/Module/addXXX/m1/p1/C.java b/jdk/test/java/lang/reflect/Module/addXXX/m1/p1/C.java new file mode 100644 index 00000000000..86357613dc5 --- /dev/null +++ b/jdk/test/java/lang/reflect/Module/addXXX/m1/p1/C.java @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2017, 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 p1; + +public class C { + public C() { } +} diff --git a/jdk/test/java/lang/reflect/Module/addXXX/m2/module-info.java b/jdk/test/java/lang/reflect/Module/addXXX/m2/module-info.java new file mode 100644 index 00000000000..918d72aac64 --- /dev/null +++ b/jdk/test/java/lang/reflect/Module/addXXX/m2/module-info.java @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2017, 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. + */ +module m2 { + exports p2; +} diff --git a/jdk/test/java/lang/reflect/Module/addXXX/m2/p2/C.java b/jdk/test/java/lang/reflect/Module/addXXX/m2/p2/C.java new file mode 100644 index 00000000000..6a87a2eba87 --- /dev/null +++ b/jdk/test/java/lang/reflect/Module/addXXX/m2/p2/C.java @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2017, 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 p2; + +import java.lang.reflect.Module; + +public class C { + + public static void export(String pn, Module m) { + C.class.getModule().addExports(pn, m); + } +} diff --git a/jdk/test/java/lang/reflect/Module/addXXX/m2/p2/internal/C.java b/jdk/test/java/lang/reflect/Module/addXXX/m2/p2/internal/C.java new file mode 100644 index 00000000000..b3009610032 --- /dev/null +++ b/jdk/test/java/lang/reflect/Module/addXXX/m2/p2/internal/C.java @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2017, 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 p2.internal; + +public class C { +} diff --git a/jdk/test/java/lang/reflect/Module/addXXX/m3/module-info.java b/jdk/test/java/lang/reflect/Module/addXXX/m3/module-info.java new file mode 100644 index 00000000000..75d5c1664be --- /dev/null +++ b/jdk/test/java/lang/reflect/Module/addXXX/m3/module-info.java @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2017, 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. + */ +module m3 { + exports p3 to test; + opens p3 to test; +} diff --git a/jdk/test/java/lang/reflect/Module/addXXX/m3/p3/C.java b/jdk/test/java/lang/reflect/Module/addXXX/m3/p3/C.java new file mode 100644 index 00000000000..c1013ce13db --- /dev/null +++ b/jdk/test/java/lang/reflect/Module/addXXX/m3/p3/C.java @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2017, 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 p3; + +public class C { +} diff --git a/jdk/test/java/lang/reflect/Module/addXXX/m4/module-info.java b/jdk/test/java/lang/reflect/Module/addXXX/m4/module-info.java new file mode 100644 index 00000000000..313ea941316 --- /dev/null +++ b/jdk/test/java/lang/reflect/Module/addXXX/m4/module-info.java @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2017, 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. + */ +module m4 { + exports p4; +} diff --git a/jdk/test/java/lang/reflect/Module/addXXX/m4/p4/C.java b/jdk/test/java/lang/reflect/Module/addXXX/m4/p4/C.java new file mode 100644 index 00000000000..a5e9a127f8c --- /dev/null +++ b/jdk/test/java/lang/reflect/Module/addXXX/m4/p4/C.java @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2017, 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 p4; + +import java.lang.reflect.Constructor; + +public class C { + public static Object tryNewInstance(Class clazz) throws Exception { + Constructor ctor = clazz.getDeclaredConstructor(); + return ctor.newInstance(); + } +} diff --git a/jdk/test/java/lang/reflect/Module/addXXX/test/module-info.java b/jdk/test/java/lang/reflect/Module/addXXX/test/module-info.java new file mode 100644 index 00000000000..ebfab744dec --- /dev/null +++ b/jdk/test/java/lang/reflect/Module/addXXX/test/module-info.java @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2017, 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. + */ +module test { + exports test to testng; + + requires m2; + requires m3; + requires m4; + requires testng; +} diff --git a/jdk/test/java/lang/reflect/Module/addXXX/test/test/C.java b/jdk/test/java/lang/reflect/Module/addXXX/test/test/C.java new file mode 100644 index 00000000000..e031680445c --- /dev/null +++ b/jdk/test/java/lang/reflect/Module/addXXX/test/test/C.java @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2017, 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 test; + +public class C { } diff --git a/jdk/test/java/lang/reflect/Module/addXXX/test/test/Main.java b/jdk/test/java/lang/reflect/Module/addXXX/test/test/Main.java new file mode 100644 index 00000000000..924f0a87de4 --- /dev/null +++ b/jdk/test/java/lang/reflect/Module/addXXX/test/test/Main.java @@ -0,0 +1,196 @@ +/* + * Copyright (c) 2017, 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 test; + +import java.lang.invoke.MethodHandle; +import java.lang.invoke.MethodHandles; +import java.lang.invoke.MethodType; +import java.lang.reflect.Constructor; +import java.lang.reflect.Module; +import java.util.ServiceConfigurationError; +import java.util.ServiceLoader; + +import org.testng.annotations.Test; +import static org.testng.Assert.*; + +/** + * Basic test case for Module::addXXXX methods + */ + +@Test +public class Main { + + /** + * Test Module::addReads + * + * module test { } + * + * module m1 { + * exports p1; + * } + */ + public void testAddReads() throws Throwable { + Module thisModule = Main.class.getModule(); + Class clazz = Class.forName("p1.C"); + Module m1 = clazz.getModule(); + + // test does not read m1 + assertFalse(thisModule.canRead(m1)); + MethodHandles.Lookup lookup = MethodHandles.lookup(); + MethodType mt = MethodType.methodType(void.class); + try { + lookup.findConstructor(clazz, mt); + assertTrue(false); + } catch (IllegalAccessException expected) { } + + // update test to read m1 + Module result = thisModule.addReads(m1); + assertTrue(result== thisModule); + assertTrue(thisModule.canRead(m1)); + MethodHandle mh = lookup.findConstructor(clazz, mt); + Object obj = mh.invoke(); + + // attempt to update m1 to read test + try { + m1.addReads(thisModule); + assertTrue(false); + } catch (IllegalCallerException expected) { } + } + + + /** + * Test Module::addExports + * + * module test { + * requires m2; + * } + * module m2 { + * exports p2; + * contains package p2.internal; + * } + */ + public void testAddExports() throws Exception { + Module thisModule = Main.class.getModule(); + Module m2 = p2.C.class.getModule(); + Class targetClass = Class.forName("p2.internal.C"); + String p2Internal = targetClass.getPackageName(); + assertTrue(targetClass.getModule() == m2); + + // m2 does not export p2.internal to test + assertFalse(m2.isExported(p2Internal, thisModule)); + Constructor ctor = targetClass.getDeclaredConstructor(); + try { + ctor.newInstance(); + assertTrue(false); + } catch (IllegalAccessException expected) { } + + // update m2 to export p2.internal to test + p2.C.export(p2Internal, thisModule); + assertTrue(m2.isExported(p2Internal, thisModule)); + ctor.newInstance(); // should succeed + + // attempt to update m2 to export a package to test + try { + m2.addExports("p2.other", thisModule); + assertTrue(false); + } catch (IllegalCallerException expected) { } + } + + /** + * Test Module::addOpens + * + * module test { + * requires m3; + * requires m4; + * } + * + * module m3 { + * exports p3 to test; + * opens p3 to test; + * } + * + * module m4 { + * exports p4; + * } + */ + public void testAddOpens() throws Exception { + Module thisModule = Main.class.getModule(); + Module m3 = p3.C.class.getModule(); + Module m4 = p4.C.class.getModule(); + + // test does not open package test to m4 + assertFalse(thisModule.isOpen("test", m4)); + try { + p4.C.tryNewInstance(test.C.class); + assertTrue(false); + } catch (IllegalAccessException expected) { } + + // open test to m4 + thisModule.addOpens("test", m4); + p4.C.tryNewInstance(test.C.class); // should succeed + + + // m3 does not open p3 to m4 + assertFalse(m3.isOpen("p3", m4)); + try { + p4.C.tryNewInstance(p3.C.class); + assertTrue(false); + } catch (IllegalAccessException expected) { } + + + // m3 opens p3 to test => test allowed to open m3/p3 to m4 + assertTrue(m3.isOpen("p3", thisModule)); + m3.addOpens("p3", m4); + assertTrue(m3.isOpen("p3", m4)); + p4.C.tryNewInstance(p3.C.class); // should succeed + + + // attempt to update m4 to open package to m3 + try { + m4.addOpens("p4", m3); + assertTrue(false); + } catch (IllegalCallerException expected) { } + } + + + /** + * Test Module::addUses + */ + public void testAddUses() { + Module thisModule = Main.class.getModule(); + + assertFalse(thisModule.canUse(Service.class)); + try { + ServiceLoader.load(Service.class); + assertTrue(false); + } catch (ServiceConfigurationError expected) { } + + Module result = thisModule.addUses(Service.class); + assertTrue(result== thisModule); + + assertTrue(thisModule.canUse(Service.class)); + ServiceLoader.load(Service.class); // no exception + } + +} diff --git a/jdk/test/java/lang/reflect/Module/addXXX/test/test/Service.java b/jdk/test/java/lang/reflect/Module/addXXX/test/test/Service.java new file mode 100644 index 00000000000..9fd5b8d862a --- /dev/null +++ b/jdk/test/java/lang/reflect/Module/addXXX/test/test/Service.java @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2017, 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 test; + +/** + * Simple service type + */ +public interface Service { } diff --git a/jdk/test/java/lang/reflect/Proxy/ProxyClassAccessTest.java b/jdk/test/java/lang/reflect/Proxy/ProxyClassAccessTest.java index 55e11f1b3ec..3ef48cd79fa 100644 --- a/jdk/test/java/lang/reflect/Proxy/ProxyClassAccessTest.java +++ b/jdk/test/java/lang/reflect/Proxy/ProxyClassAccessTest.java @@ -91,7 +91,7 @@ public class ProxyClassAccessTest { Layer bootLayer = Layer.boot(); Configuration cf = bootLayer .configuration() - .resolveRequiresAndUses(ModuleFinder.of(), finder, modules); + .resolveAndBind(ModuleFinder.of(), finder, modules); ClassLoader parentLoader = this.getClass().getClassLoader(); Layer layer = bootLayer.defineModulesWithOneLoader(cf, parentLoader); diff --git a/jdk/test/java/lang/reflect/Proxy/ProxyLayerTest.java b/jdk/test/java/lang/reflect/Proxy/ProxyLayerTest.java index 5b04c93596b..767afd23323 100644 --- a/jdk/test/java/lang/reflect/Proxy/ProxyLayerTest.java +++ b/jdk/test/java/lang/reflect/Proxy/ProxyLayerTest.java @@ -79,7 +79,7 @@ public class ProxyLayerTest { Layer bootLayer = Layer.boot(); Configuration cf = bootLayer .configuration() - .resolveRequiresAndUses(ModuleFinder.of(), finder, Arrays.asList(modules)); + .resolveAndBind(ModuleFinder.of(), finder, Arrays.asList(modules)); ClassLoader scl = ClassLoader.getSystemClassLoader(); Layer layer = bootLayer.defineModulesWithOneLoader(cf, scl); @@ -113,7 +113,7 @@ public class ProxyLayerTest { Layer bootLayer = Layer.boot(); Configuration cf = bootLayer .configuration() - .resolveRequiresAndUses(ModuleFinder.of(), finder, Arrays.asList(modules)); + .resolveAndBind(ModuleFinder.of(), finder, Arrays.asList(modules)); ClassLoader scl = ClassLoader.getSystemClassLoader(); Layer layer = bootLayer.defineModulesWithOneLoader(cf, scl); @@ -143,7 +143,7 @@ public class ProxyLayerTest { Layer bootLayer = Layer.boot(); Configuration cf = bootLayer .configuration() - .resolveRequiresAndUses(ModuleFinder.of(), finder, Arrays.asList(modules)); + .resolveAndBind(ModuleFinder.of(), finder, Arrays.asList(modules)); ClassLoader scl = ClassLoader.getSystemClassLoader(); Layer layer = bootLayer.defineModulesWithOneLoader(cf, scl); diff --git a/jdk/test/java/security/modules/ModularTest.java b/jdk/test/java/security/modules/ModularTest.java index 9e67094944f..56635c99b8d 100644 --- a/jdk/test/java/security/modules/ModularTest.java +++ b/jdk/test/java/security/modules/ModularTest.java @@ -164,9 +164,9 @@ public abstract class ModularTest { final Builder builder; if (moduleType == MODULE_TYPE.EXPLICIT) { System.out.format(" %nGenerating ModuleDescriptor object"); - builder = ModuleDescriptor.module(moduleName).exports(pkg); + builder = ModuleDescriptor.newModule(moduleName).exports(pkg); if (isService && serviceInterface != null && serviceImpl != null) { - builder.provides(serviceInterface, serviceImpl); + builder.provides(serviceInterface, List.of(serviceImpl)); } else { if (serviceInterface != null) { builder.uses(serviceInterface); diff --git a/jdk/test/java/util/ServiceLoader/modules/BadProvidersTest.java b/jdk/test/java/util/ServiceLoader/modules/BadProvidersTest.java index c28e3b91911..8d3c2d27d3a 100644 --- a/jdk/test/java/util/ServiceLoader/modules/BadProvidersTest.java +++ b/jdk/test/java/util/ServiceLoader/modules/BadProvidersTest.java @@ -90,7 +90,7 @@ public class BadProvidersTest { Layer bootLayer = Layer.boot(); Configuration cf = bootLayer.configuration() - .resolveRequiresAndUses(finder, ModuleFinder.of(), Set.of(moduleName)); + .resolveAndBind(finder, ModuleFinder.of(), Set.of(moduleName)); ClassLoader scl = ClassLoader.getSystemClassLoader(); diff --git a/jdk/test/java/util/ServiceLoader/modules/Basic.java b/jdk/test/java/util/ServiceLoader/modules/Basic.java index 7833c0e2771..4dca546ea36 100644 --- a/jdk/test/java/util/ServiceLoader/modules/Basic.java +++ b/jdk/test/java/util/ServiceLoader/modules/Basic.java @@ -311,17 +311,17 @@ public class Basic { ModuleFinder finder = ModuleFinder.of(dir); // layer1 - Configuration cf1 = cf0.resolveRequiresAndUses(finder, ModuleFinder.of(), Set.of()); + Configuration cf1 = cf0.resolveAndBind(finder, ModuleFinder.of(), Set.of()); Layer layer1 = bootLayer.defineModulesWithOneLoader(cf1, scl); assertTrue(layer1.modules().size() == 1); // layer2 - Configuration cf2 = cf0.resolveRequiresAndUses(finder, ModuleFinder.of(), Set.of()); + Configuration cf2 = cf0.resolveAndBind(finder, ModuleFinder.of(), Set.of()); Layer layer2 = bootLayer.defineModulesWithOneLoader(cf2, scl); assertTrue(layer2.modules().size() == 1); // layer3 with layer1 and layer2 as parents - Configuration cf3 = Configuration.resolveRequiresAndUses(finder, + Configuration cf3 = Configuration.resolveAndBind(finder, List.of(cf1, cf2), ModuleFinder.of(), Set.of()); @@ -413,7 +413,7 @@ public class Basic { Collections.addAll(roots, modules); Layer bootLayer = Layer.boot(); Configuration parent = bootLayer.configuration(); - Configuration cf = parent.resolveRequires(finder, ModuleFinder.of(), roots); + Configuration cf = parent.resolve(finder, ModuleFinder.of(), roots); ClassLoader scl = ClassLoader.getSystemClassLoader(); Layer layer = bootLayer.defineModulesWithOneLoader(cf, scl); assertTrue(layer.modules().size() == 1); diff --git a/jdk/test/jdk/internal/reflect/CallerSensitive/CheckCSMs.java b/jdk/test/jdk/internal/reflect/CallerSensitive/CheckCSMs.java new file mode 100644 index 00000000000..126df3a75e6 --- /dev/null +++ b/jdk/test/jdk/internal/reflect/CallerSensitive/CheckCSMs.java @@ -0,0 +1,251 @@ +/* + * Copyright (c) 2017, 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 com.sun.tools.classfile.*; +import com.sun.tools.jdeps.ClassFileReader; +import static com.sun.tools.classfile.ConstantPool.*; +import java.io.File; +import java.io.IOException; +import java.io.UncheckedIOException; +import java.net.URI; +import java.nio.file.FileSystem; +import java.nio.file.FileSystems; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Set; +import java.util.concurrent.Callable; +import java.util.concurrent.ConcurrentSkipListSet; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.FutureTask; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +/* + * @test + * @summary CallerSensitive methods should be static or final instance + * methods except the known list of non-final instance methods + * @modules jdk.jdeps/com.sun.tools.classfile + * jdk.jdeps/com.sun.tools.jdeps + * @build CheckCSMs + * @run main/othervm/timeout=900 CheckCSMs + */ +public class CheckCSMs { + private static int numThreads = 3; + private static boolean listCSMs = false; + private final ExecutorService pool; + + // The goal is to remove this list of Non-final instance @CS methods + // over time. Do not add any new one to this list. + private static Set KNOWN_NON_FINAL_CSMS = + Set.of("java/io/ObjectStreamField#getType ()Ljava/lang/Class;", + "java/io/ObjectStreamClass#forClass ()Ljava/lang/Class;", + "java/lang/Runtime#load (Ljava/lang/String;)V", + "java/lang/Runtime#loadLibrary (Ljava/lang/String;)V", + "java/lang/Thread#getContextClassLoader ()Ljava/lang/ClassLoader;", + "javax/sql/rowset/serial/SerialJavaObject#getFields ()[Ljava/lang/reflect/Field;" + ); + + public static void main(String[] args) throws Exception { + if (args.length > 0 && args[0].equals("--list")) { + listCSMs = true; + } + + CheckCSMs checkCSMs = new CheckCSMs(); + Set result = checkCSMs.run(getPlatformClasses()); + if (!KNOWN_NON_FINAL_CSMS.equals(result)) { + Set diff = new HashSet<>(result); + diff.removeAll(KNOWN_NON_FINAL_CSMS); + throw new RuntimeException("Unexpected non-final instance method: " + + result.stream().sorted() + .collect(Collectors.joining("\n", "\n", ""))); + } + } + + private final Set nonFinalCSMs = new ConcurrentSkipListSet<>(); + private final ReferenceFinder finder; + public CheckCSMs() { + this.finder = new ReferenceFinder(getFilter(), getVisitor()); + pool = Executors.newFixedThreadPool(numThreads); + + } + + public Set run(Stream classes) + throws IOException, InterruptedException, ExecutionException, + ConstantPoolException + { + classes.forEach(this::processPath); + waitForCompletion(); + pool.shutdown(); + return nonFinalCSMs; + } + + + private ReferenceFinder.Filter getFilter() { + final String classname = "jdk/internal/reflect/Reflection"; + final String method = "getCallerClass"; + return new ReferenceFinder.Filter() { + public boolean accept(ConstantPool cpool, CPRefInfo cpref) { + try { + CONSTANT_NameAndType_info nat = cpref.getNameAndTypeInfo(); + return cpref.getClassName().equals(classname) && nat.getName().equals(method); + } catch (ConstantPoolException ex) { + throw new RuntimeException(ex); + } + } + }; + } + + private ReferenceFinder.Visitor getVisitor() { + return new ReferenceFinder.Visitor() { + public void visit(ClassFile cf, Method m, List refs) { + try { + // ignore jdk.unsupported/sun.reflect.Reflection.getCallerClass + // which is a "special" delegate to the internal getCallerClass + if (cf.getName().equals("sun/reflect/Reflection") && + m.getName(cf.constant_pool).equals("getCallerClass")) + return; + + String name = String.format("%s#%s %s", cf.getName(), + m.getName(cf.constant_pool), + m.descriptor.getValue(cf.constant_pool)); + if (!CheckCSMs.isStaticOrFinal(cf, m, cf.constant_pool)) { + System.err.println("Unsupported @CallerSensitive: " + name); + nonFinalCSMs.add(name); + } else { + if (listCSMs) { + System.out.format("@CS %s%n", name); + } + } + } catch (ConstantPoolException ex) { + throw new RuntimeException(ex); + } + } + }; + } + + void processPath(Path path) { + try { + ClassFileReader reader = ClassFileReader.newInstance(path); + for (ClassFile cf : reader.getClassFiles()) { + if (cf.access_flags.is(AccessFlags.ACC_MODULE)) + continue; + + String classFileName = cf.getName(); + // for each ClassFile + // parse constant pool to find matching method refs + // parse each method (caller) + // - visit and find method references matching the given method name + pool.submit(getTask(cf)); + } + } catch (IOException x) { + throw new UncheckedIOException(x); + } catch (ConstantPoolException x) { + throw new RuntimeException(x); + } + } + + private static final String CALLER_SENSITIVE_ANNOTATION + = "Ljdk/internal/reflect/CallerSensitive;"; + + private static boolean isCallerSensitive(Method m, ConstantPool cp) + throws ConstantPoolException + { + RuntimeAnnotations_attribute attr = + (RuntimeAnnotations_attribute)m.attributes.get(Attribute.RuntimeVisibleAnnotations); + if (attr != null) { + for (int i = 0; i < attr.annotations.length; i++) { + Annotation ann = attr.annotations[i]; + String annType = cp.getUTF8Value(ann.type_index); + if (CALLER_SENSITIVE_ANNOTATION.equals(annType)) { + return true; + } + } + } + return false; + } + + private static boolean isStaticOrFinal(ClassFile cf, Method m, ConstantPool cp) + throws ConstantPoolException + { + if (!isCallerSensitive(m, cp)) + return false; + + // either a static method or a final instance method + return m.access_flags.is(AccessFlags.ACC_STATIC) || + m.access_flags.is(AccessFlags.ACC_FINAL) || + cf.access_flags.is(AccessFlags.ACC_FINAL); + } + + private final List> tasks = new ArrayList>(); + private FutureTask getTask(final ClassFile cf) { + FutureTask task = new FutureTask(new Callable() { + public Void call() throws Exception { + finder.parse(cf); + return null; + } + }); + tasks.add(task); + return task; + } + + private void waitForCompletion() throws InterruptedException, ExecutionException { + for (FutureTask t : tasks) { + t.get(); + } + if (tasks.isEmpty()) { + throw new RuntimeException("No classes found, or specified."); + } + System.out.println("Parsed " + tasks.size() + " classfiles"); + } + + static Stream getPlatformClasses() throws IOException { + Path home = Paths.get(System.getProperty("java.home")); + + // Either an exploded build or an image. + File classes = home.resolve("modules").toFile(); + if (classes.isDirectory()) { + return Stream.of(classes.toPath()); + } else { + return jrtPaths(); + } + } + + static Stream jrtPaths() { + FileSystem jrt = FileSystems.getFileSystem(URI.create("jrt:/")); + Path root = jrt.getPath("/"); + + try { + return Files.walk(root) + .filter(p -> p.getNameCount() > 1) + .filter(p -> p.toString().endsWith(".class")); + } catch (IOException x) { + throw new UncheckedIOException(x); + } + } +} diff --git a/jdk/test/jdk/modules/etc/VerifyModuleDelegation.java b/jdk/test/jdk/modules/etc/VerifyModuleDelegation.java index 72e337066cb..182fb4ee985 100644 --- a/jdk/test/jdk/modules/etc/VerifyModuleDelegation.java +++ b/jdk/test/jdk/modules/etc/VerifyModuleDelegation.java @@ -46,7 +46,7 @@ public class VerifyModuleDelegation { private static final String JAVA_BASE = "java.base"; private static final ModuleDescriptor BASE - = ModuleDescriptor.module(JAVA_BASE).build(); + = ModuleDescriptor.newModule(JAVA_BASE).build(); private static final Set MREFS = Layer.boot().modules().stream().map(Module::getDescriptor) diff --git a/jdk/test/jdk/modules/scenarios/container/src/container/container/Main.java b/jdk/test/jdk/modules/scenarios/container/src/container/container/Main.java index 67f2416187f..ca3f0f3a0d2 100644 --- a/jdk/test/jdk/modules/scenarios/container/src/container/container/Main.java +++ b/jdk/test/jdk/modules/scenarios/container/src/container/container/Main.java @@ -71,9 +71,9 @@ public class Main { ModuleFinder finder = ModuleFinder.of(paths); Configuration cf = Layer.boot().configuration() - .resolveRequiresAndUses(finder, - ModuleFinder.of(), - Set.of(appModuleName)); + .resolveAndBind(finder, + ModuleFinder.of(), + Set.of(appModuleName)); System.out.println("Resolved"); cf.modules().stream() diff --git a/jdk/test/sun/management/jdp/JdpJmxRemoteDynamicPortTest.java b/jdk/test/sun/management/jdp/JdpJmxRemoteDynamicPortTest.java index 9ee4a0cd820..4e628995c18 100644 --- a/jdk/test/sun/management/jdp/JdpJmxRemoteDynamicPortTest.java +++ b/jdk/test/sun/management/jdp/JdpJmxRemoteDynamicPortTest.java @@ -27,7 +27,7 @@ * @summary Verify a non-zero value is assigned to jmxremote.port * when VM is started with jmxremote.port=0. * @library /lib/testlibrary - * @modules java.management/sun.management.jdp + * @modules jdk.management.agent/sun.management.jdp * @build jdk.testlibrary.* ClientConnection JdpTestUtil JdpTestCase JdpJmxRemoteDynamicPortTestCase DynamicLauncher * @run main JdpJmxRemoteDynamicPortTest */ diff --git a/jdk/test/tools/jar/mmrjar/Basic.java b/jdk/test/tools/jar/mmrjar/Basic.java index 6b0ad843641..0e83508b74d 100644 --- a/jdk/test/tools/jar/mmrjar/Basic.java +++ b/jdk/test/tools/jar/mmrjar/Basic.java @@ -331,7 +331,7 @@ public class Basic { ModuleInfoExtender mie = ModuleInfoExtender.newExtender( new ByteArrayInputStream(mdBytes)); - mie.mainClass("foo.main"); + mie.mainClass("p.Main"); mie.version(Version.parse("1.0")); ByteArrayOutputStream baos = new ByteArrayOutputStream(); @@ -345,7 +345,7 @@ public class Basic { // different main-class mie = ModuleInfoExtender.newExtender(new ByteArrayInputStream(mdBytes)); - mie.mainClass("foo.main2"); + mie.mainClass("p.Main2"); mie.version(Version.parse("1.0")); baos.reset(); mie.write(baos); @@ -360,7 +360,7 @@ public class Basic { // different version mie = ModuleInfoExtender.newExtender(new ByteArrayInputStream(mdBytes)); - mie.mainClass("foo.main"); + mie.mainClass("p.Main"); mie.version(Version.parse("2.0")); baos.reset(); mie.write(baos); @@ -395,7 +395,7 @@ public class Basic { Files.copy(Paths.get("test7-v9", "module-info.class"), Paths.get("test7-v10", "module-info.class")); - int rc = jar("--create --file mmr.jar --main-class=foo.main -C test7 . --release 9 -C test7-v9 . --release 10 -C test7-v10 ."); + int rc = jar("--create --file mmr.jar --main-class=p.Main -C test7 . --release 9 -C test7-v9 . --release 10 -C test7-v10 ."); System.out.println("-----------------------"); System.out.println( new String(errbytes.toByteArray())); @@ -409,7 +409,7 @@ System.out.println( new String(errbytes.toByteArray())); System.out.println("-----------------------"); System.out.println( new String(outbytes.toByteArray())); - Optional exp = Optional.of("foo.main"); + Optional exp = Optional.of("p.Main"); try (ZipFile zf = new ZipFile("mmr.jar")) { Assert.assertTrue(zf.getEntry("module-info.class") == null); diff --git a/jdk/test/tools/jar/modularJar/Basic.java b/jdk/test/tools/jar/modularJar/Basic.java index 8a9d44132fc..497853b769e 100644 --- a/jdk/test/tools/jar/modularJar/Basic.java +++ b/jdk/test/tools/jar/modularJar/Basic.java @@ -328,7 +328,7 @@ public class Basic { .resultChecker(r -> assertModuleData(r, FOO)); } - @Test + @Test(enabled = false) public void partialUpdateFooMainClass() throws IOException { Path mp = Paths.get("partialUpdateFooMainClass"); createTestDir(mp); diff --git a/jdk/test/tools/jlink/JLinkNegativeTest.java b/jdk/test/tools/jlink/JLinkNegativeTest.java index f8ac8093f33..b97092e4bac 100644 --- a/jdk/test/tools/jlink/JLinkNegativeTest.java +++ b/jdk/test/tools/jlink/JLinkNegativeTest.java @@ -274,7 +274,7 @@ public class JLinkNegativeTest { helper.getJmodSrcDir(), helper.getJmodClassesDir(), moduleName2, classNames); try (OutputStream out = Files.newOutputStream(module2.resolve("module-info.class"))) { - ModuleInfoWriter.write(ModuleDescriptor.module(moduleName1) + ModuleInfoWriter.write(ModuleDescriptor.newModule(moduleName1) .requires("java.base").build(), out); } @@ -332,7 +332,7 @@ public class JLinkNegativeTest { helper.getJarSrcDir(), helper.getJarClassesDir(), moduleName2, classNames); try (OutputStream out = Files.newOutputStream(module2.resolve("module-info.class"))) { - ModuleInfoWriter.write(ModuleDescriptor.module(moduleName1) + ModuleInfoWriter.write(ModuleDescriptor.newModule(moduleName1) .requires("java.base").build(), out); } diff --git a/jdk/test/tools/jmod/hashes/HashesTest.java b/jdk/test/tools/jmod/hashes/HashesTest.java index 3700554983f..10680927c19 100644 --- a/jdk/test/tools/jmod/hashes/HashesTest.java +++ b/jdk/test/tools/jmod/hashes/HashesTest.java @@ -312,9 +312,7 @@ public class HashesTest { assertTrue(ht.hashes("m2") == null); // should not override any JDK packaged modules - ModuleFinder finder = new ModulePath(Runtime.version(), - true, - mpath); + ModuleFinder finder = ModulePath.of(Runtime.version(), true, mpath); assertTrue(ht.hashes(finder,"jdk.compiler") == null); assertTrue(ht.hashes(finder,"jdk.attach") == null); } @@ -325,9 +323,7 @@ public class HashesTest { } private ModuleHashes hashes(String name) { - ModuleFinder finder = new ModulePath(Runtime.version(), - true, - lib); + ModuleFinder finder = ModulePath.of(Runtime.version(), true, lib); return hashes(finder, name); } diff --git a/jdk/test/tools/launcher/modules/patch/systemmodules/src1/java.base/jdk/internal/modules/SystemModules.java b/jdk/test/tools/launcher/modules/patch/systemmodules/src1/java.base/jdk/internal/modules/SystemModules.java index a774fc7427f..0eef57b33fb 100644 --- a/jdk/test/tools/launcher/modules/patch/systemmodules/src1/java.base/jdk/internal/modules/SystemModules.java +++ b/jdk/test/tools/launcher/modules/patch/systemmodules/src1/java.base/jdk/internal/modules/SystemModules.java @@ -30,6 +30,8 @@ package jdk.internal.module; public final class SystemModules { public static final String[] MODULE_NAMES = new String[0]; + public static int PACKAGES_IN_BOOT_LAYER = 1024; + public static boolean hasSplitPackages() { return true; } From a7c0fa1045c663550135d5e3635a04771d58cbd0 Mon Sep 17 00:00:00 2001 From: Michael McMahon Date: Fri, 10 Feb 2017 09:55:19 +0000 Subject: [PATCH 156/157] 8174716: java/net/httpclient/security/Driver.java failing in JDK 9 Reviewed-by: alanb --- jdk/test/java/net/httpclient/security/Driver.java | 1 + 1 file changed, 1 insertion(+) diff --git a/jdk/test/java/net/httpclient/security/Driver.java b/jdk/test/java/net/httpclient/security/Driver.java index 64b56084d41..5b58757adc3 100644 --- a/jdk/test/java/net/httpclient/security/Driver.java +++ b/jdk/test/java/net/httpclient/security/Driver.java @@ -127,6 +127,7 @@ public class Driver { cmd.add("-Dtest.src=" + testSrc); cmd.add("-Dtest.classes=" + testClasses); cmd.add("-Djava.security.manager"); + cmd.add("--add-modules=jdk.incubator.httpclient"); cmd.add("-Djava.security.policy=" + testSrc + sep + policy); cmd.add("-Dport.number=" + Integer.toString(Utils.getFreePort())); cmd.add("-Dport.number1=" + Integer.toString(Utils.getFreePort())); From f3847cff6214828fcb31e634249694fcbdca553e Mon Sep 17 00:00:00 2001 From: Denis Kononenko Date: Thu, 9 Feb 2017 19:43:53 +0300 Subject: [PATCH 157/157] 8170113: jimage extract to readonly directory causes MissingResourceException Added a missing resource. Reviewed-by: alanb, anazarov --- .../share/classes/jdk/tools/jimage/resources/jimage.properties | 1 + 1 file changed, 1 insertion(+) diff --git a/jdk/src/jdk.jlink/share/classes/jdk/tools/jimage/resources/jimage.properties b/jdk/src/jdk.jlink/share/classes/jdk/tools/jimage/resources/jimage.properties index 13faa3b40e4..2bc96bd30af 100644 --- a/jdk/src/jdk.jlink/share/classes/jdk/tools/jimage/resources/jimage.properties +++ b/jdk/src/jdk.jlink/share/classes/jdk/tools/jimage/resources/jimage.properties @@ -98,3 +98,4 @@ err.not.a.jimage=not a jimage file: {0} err.no.jimage=no jimage provided err.option.unsupported={0} not supported: {1} err.unknown.option=unknown option: {0} +err.cannot.create.dir=cannot create directory {0}