From b9d46eee2cf17e61d0510b76facd0acbb0f3d700 Mon Sep 17 00:00:00 2001 From: Antonios Printezis Date: Wed, 10 Sep 2014 11:55:33 +0200 Subject: [PATCH 01/81] 8057799: Unnecessary NULL check in G1KeepAliveClosure Reviewed-by: tschatzl, stefank --- hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp b/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp index b7bf1ffdb9c..706fb1970bd 100644 --- a/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp +++ b/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp @@ -5448,9 +5448,10 @@ public: void do_oop(narrowOop* p) { guarantee(false, "Not needed"); } void do_oop(oop* p) { oop obj = *p; + assert(obj != NULL, "the caller should have filtered out NULL values"); G1CollectedHeap::in_cset_state_t cset_state = _g1->in_cset_state(obj); - if (obj == NULL || cset_state == G1CollectedHeap::InNeither) { + if (cset_state == G1CollectedHeap::InNeither) { return; } if (cset_state == G1CollectedHeap::InCSet) { From a2d9ba3fd6712b2406d035de7614e8da86bac237 Mon Sep 17 00:00:00 2001 From: Mikael Gerdin Date: Tue, 26 Aug 2014 11:53:24 +0200 Subject: [PATCH 02/81] 8056039: Hotspot does not compile with clang 3.4 on Linux Reviewed-by: brutisso, sla --- hotspot/src/os/aix/vm/os_aix.cpp | 4 ---- hotspot/src/os/bsd/vm/os_bsd.cpp | 5 ----- hotspot/src/os/linux/vm/os_linux.cpp | 4 ---- hotspot/src/os/solaris/vm/os_solaris.cpp | 21 ------------------- .../share/vm/utilities/globalDefinitions.hpp | 3 +++ .../vm/utilities/globalDefinitions_gcc.hpp | 7 ++++--- .../globalDefinitions_sparcWorks.hpp | 8 ------- 7 files changed, 7 insertions(+), 45 deletions(-) diff --git a/hotspot/src/os/aix/vm/os_aix.cpp b/hotspot/src/os/aix/vm/os_aix.cpp index 6d8c55bf541..387a679bc6d 100644 --- a/hotspot/src/os/aix/vm/os_aix.cpp +++ b/hotspot/src/os/aix/vm/os_aix.cpp @@ -4002,10 +4002,6 @@ bool os::check_heap(bool force) { return true; } -// int local_vsnprintf(char* buf, size_t count, const char* format, va_list args) { -// return ::vsnprintf(buf, count, format, args); -// } - // Is a (classpath) directory empty? bool os::dir_is_empty(const char* path) { DIR *dir = NULL; diff --git a/hotspot/src/os/bsd/vm/os_bsd.cpp b/hotspot/src/os/bsd/vm/os_bsd.cpp index 4f54ad94a6a..d0797359042 100644 --- a/hotspot/src/os/bsd/vm/os_bsd.cpp +++ b/hotspot/src/os/bsd/vm/os_bsd.cpp @@ -3797,11 +3797,6 @@ bool os::check_heap(bool force) { return true; } -ATTRIBUTE_PRINTF(3, 0) -int local_vsnprintf(char* buf, size_t count, const char* format, va_list args) { - return ::vsnprintf(buf, count, format, args); -} - // Is a (classpath) directory empty? bool os::dir_is_empty(const char* path) { DIR *dir = NULL; diff --git a/hotspot/src/os/linux/vm/os_linux.cpp b/hotspot/src/os/linux/vm/os_linux.cpp index 586f46a26b3..61aa11d1790 100644 --- a/hotspot/src/os/linux/vm/os_linux.cpp +++ b/hotspot/src/os/linux/vm/os_linux.cpp @@ -5007,10 +5007,6 @@ bool os::check_heap(bool force) { return true; } -int local_vsnprintf(char* buf, size_t count, const char* format, va_list args) { - return ::vsnprintf(buf, count, format, args); -} - // Is a (classpath) directory empty? bool os::dir_is_empty(const char* path) { DIR *dir = NULL; diff --git a/hotspot/src/os/solaris/vm/os_solaris.cpp b/hotspot/src/os/solaris/vm/os_solaris.cpp index 21cb27a3c0e..0a61f78370e 100644 --- a/hotspot/src/os/solaris/vm/os_solaris.cpp +++ b/hotspot/src/os/solaris/vm/os_solaris.cpp @@ -4729,27 +4729,6 @@ void os::make_polling_page_readable(void) { bool os::check_heap(bool force) { return true; } -typedef int (*vsnprintf_t)(char* buf, size_t count, const char* fmt, va_list argptr); -static vsnprintf_t sol_vsnprintf = NULL; - -int local_vsnprintf(char* buf, size_t count, const char* fmt, va_list argptr) { - if (!sol_vsnprintf) { - //search for the named symbol in the objects that were loaded after libjvm - void* where = RTLD_NEXT; - if ((sol_vsnprintf = CAST_TO_FN_PTR(vsnprintf_t, dlsym(where, "__vsnprintf"))) == NULL) - sol_vsnprintf = CAST_TO_FN_PTR(vsnprintf_t, dlsym(where, "vsnprintf")); - if (!sol_vsnprintf){ - //search for the named symbol in the objects that were loaded before libjvm - where = RTLD_DEFAULT; - if ((sol_vsnprintf = CAST_TO_FN_PTR(vsnprintf_t, dlsym(where, "__vsnprintf"))) == NULL) - sol_vsnprintf = CAST_TO_FN_PTR(vsnprintf_t, dlsym(where, "vsnprintf")); - assert(sol_vsnprintf != NULL, "vsnprintf not found"); - } - } - return (*sol_vsnprintf)(buf, count, fmt, argptr); -} - - // Is a (classpath) directory empty? bool os::dir_is_empty(const char* path) { DIR *dir = NULL; diff --git a/hotspot/src/share/vm/utilities/globalDefinitions.hpp b/hotspot/src/share/vm/utilities/globalDefinitions.hpp index 269853ee674..187ac4c2caa 100644 --- a/hotspot/src/share/vm/utilities/globalDefinitions.hpp +++ b/hotspot/src/share/vm/utilities/globalDefinitions.hpp @@ -66,6 +66,9 @@ #ifndef ATTRIBUTE_PRINTF #define ATTRIBUTE_PRINTF(fmt, vargs) #endif +#ifndef ATTRIBUTE_SCANF +#define ATTRIBUTE_SCANF(fmt, vargs) +#endif #include "utilities/macros.hpp" diff --git a/hotspot/src/share/vm/utilities/globalDefinitions_gcc.hpp b/hotspot/src/share/vm/utilities/globalDefinitions_gcc.hpp index 576b0235af4..9a00b912048 100644 --- a/hotspot/src/share/vm/utilities/globalDefinitions_gcc.hpp +++ b/hotspot/src/share/vm/utilities/globalDefinitions_gcc.hpp @@ -271,15 +271,16 @@ inline int wcslen(const jchar* x) { return wcslen((const wchar_t*)x); } #define PRAGMA_IMPLEMENTATION #pragma implementation #define VALUE_OBJ_CLASS_SPEC -#ifndef ATTRIBUTE_PRINTF // Diagnostic pragmas like the ones defined below in PRAGMA_FORMAT_NONLITERAL_IGNORED // were only introduced in GCC 4.2. Because we have no other possibility to ignore // these warnings for older versions of GCC, we simply don't decorate our printf-style // functions with __attribute__(format) in that case. #if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 2)) || (__GNUC__ > 4) +#ifndef ATTRIBUTE_PRINTF #define ATTRIBUTE_PRINTF(fmt,vargs) __attribute__((format(printf, fmt, vargs))) -#else -#define ATTRIBUTE_PRINTF(fmt,vargs) +#endif +#ifndef ATTRIBUTE_SCANF +#define ATTRIBUTE_SCANF(fmt,vargs) __attribute__((format(scanf, fmt, vargs))) #endif #endif diff --git a/hotspot/src/share/vm/utilities/globalDefinitions_sparcWorks.hpp b/hotspot/src/share/vm/utilities/globalDefinitions_sparcWorks.hpp index b64bbf8da0f..352d2c709f7 100644 --- a/hotspot/src/share/vm/utilities/globalDefinitions_sparcWorks.hpp +++ b/hotspot/src/share/vm/utilities/globalDefinitions_sparcWorks.hpp @@ -265,14 +265,6 @@ inline int g_isfinite(jdouble f) { return finite(f); } inline int wcslen(const jchar* x) { return wcslen((const wchar_t*)x); } - -// Misc -// NOTE: This one leads to an infinite recursion on Linux -#ifndef LINUX -int local_vsnprintf(char* buf, size_t count, const char* fmt, va_list argptr); -#define vsnprintf local_vsnprintf -#endif - // Portability macros #define PRAGMA_INTERFACE #define PRAGMA_IMPLEMENTATION From f494735340ae63bba754d49f5b5599b2148d9598 Mon Sep 17 00:00:00 2001 From: Andrey Zakharov Date: Thu, 11 Sep 2014 14:21:13 +0200 Subject: [PATCH 03/81] 8041946: CMM Testing: 8u40 an allocated humongous object at the end of the heap should not prevents shrinking the heap New test added Reviewed-by: jwilhelm, tschatzl --- .../gc/g1/TestShrinkDefragmentedHeap.java | 188 ++++++++++++++++++ 1 file changed, 188 insertions(+) create mode 100644 hotspot/test/gc/g1/TestShrinkDefragmentedHeap.java diff --git a/hotspot/test/gc/g1/TestShrinkDefragmentedHeap.java b/hotspot/test/gc/g1/TestShrinkDefragmentedHeap.java new file mode 100644 index 00000000000..94eb690e97d --- /dev/null +++ b/hotspot/test/gc/g1/TestShrinkDefragmentedHeap.java @@ -0,0 +1,188 @@ +/* + * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/** + * @test TestShrinkDefragmentedHeap + * @bug 8038423 + * @summary Verify that heap shrinks after GC in the presence of fragmentation due to humongous objects + * 1. allocate small objects mixed with humongous ones + * "ssssHssssHssssHssssHssssHssssHssssH" + * 2. release all allocated object except the last humongous one + * "..................................H" + * 3. invoke gc and check that memory returned to the system (amount of committed memory got down) + * + * @library /testlibrary + */ +import java.lang.management.ManagementFactory; +import java.lang.management.MemoryUsage; +import java.util.ArrayList; +import java.util.List; +import sun.management.ManagementFactoryHelper; +import static com.oracle.java.testlibrary.Asserts.*; +import com.oracle.java.testlibrary.ProcessTools; +import com.oracle.java.testlibrary.OutputAnalyzer; + +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 + // together with humongous regions. So if there are a lot of old regions in the lower part of the heap, + // the humongous regions will be allocated in the upper part of the heap anyway. + // To avoid this the Eden needs to be big enough to fit all the small objects. + private static final int INITIAL_HEAP_SIZE = 200 * 1024 * 1024; + private static final int MINIMAL_YOUNG_SIZE = 190 * 1024 * 1024; + private static final int REGION_SIZE = 1 * 1024 * 1024; + + public static void main(String[] args) throws Exception, Throwable { + ProcessBuilder pb = ProcessTools.createJavaProcessBuilder( + "-XX:InitialHeapSize=" + INITIAL_HEAP_SIZE, + "-Xmn" + MINIMAL_YOUNG_SIZE, + "-XX:MinHeapFreeRatio=10", + "-XX:MaxHeapFreeRatio=11", + "-XX:+UseG1GC", + "-XX:G1HeapRegionSize=" + REGION_SIZE, + "-verbose:gc", + GCTest.class.getName() + ); + + OutputAnalyzer output = ProcessTools.executeProcess(pb); + output.shouldHaveExitValue(0); + } + + static class GCTest { + + private static final String MIN_FREE_RATIO_FLAG_NAME = "MinHeapFreeRatio"; + private static final String MAX_FREE_RATIO_FLAG_NAME = "MaxHeapFreeRatio"; + private static final String NEW_SIZE_FLAG_NAME = "NewSize"; + + private static final ArrayList> garbage = new ArrayList<>(); + + private static final int SMALL_OBJS_SIZE = 10 * 1024; // 10kB + private static final int SMALL_OBJS_COUNT = MINIMAL_YOUNG_SIZE / (SMALL_OBJS_SIZE-1); + private static final int ALLOCATE_COUNT = 3; + // try to put all humongous object into gap between min young size and initial heap size + // to avoid implicit GCs + private static final int HUMONG_OBJS_SIZE = (int) Math.max( + (INITIAL_HEAP_SIZE - MINIMAL_YOUNG_SIZE) / ALLOCATE_COUNT / 4, + REGION_SIZE * 1.1 + ); + + private static final long initialHeapSize = getHeapMemoryUsage().getUsed(); + + public static void main(String[] args) throws InterruptedException { + new GCTest().test(); + } + + private void test() throws InterruptedException { + MemoryUsagePrinter.printMemoryUsage("init"); + + allocate(); + System.gc(); + MemoryUsage muFull = getHeapMemoryUsage(); + MemoryUsagePrinter.printMemoryUsage("allocated"); + + free(); + //Thread.sleep(1000); // sleep before measures due lags in JMX + MemoryUsage muFree = getHeapMemoryUsage(); + MemoryUsagePrinter.printMemoryUsage("free"); + + assertLessThan(muFree.getCommitted(), muFull.getCommitted(), prepareMessageCommittedIsNotLess() ); + } + + 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) + ); + + for (int i = 0; i < ALLOCATE_COUNT; i++) { + ArrayList stuff = new ArrayList<>(); + allocateList(stuff, SMALL_OBJS_COUNT / ALLOCATE_COUNT, SMALL_OBJS_SIZE); + garbage.add(stuff); + + ArrayList humongousStuff = new ArrayList<>(); + allocateList(humongousStuff, 4, HUMONG_OBJS_SIZE); + garbage.add(humongousStuff); + } + } + + private void free() { + // do not free last one list + garbage.subList(0, garbage.size() - 1).clear(); + + // do not free last one element from last list + ArrayList stuff = garbage.get(garbage.size() - 1); + if (stuff.size() > 1) { + stuff.subList(0, stuff.size() - 1).clear(); + } + System.gc(); + } + + private String prepareMessageCommittedIsNotLess() { + return String.format( + "committed free heap size is not less than committed full heap size, heap hasn't been shrunk?%n" + + "%s = %s%n%s = %s", + MIN_FREE_RATIO_FLAG_NAME, + ManagementFactoryHelper.getDiagnosticMXBean().getVMOption(MIN_FREE_RATIO_FLAG_NAME).getValue(), + MAX_FREE_RATIO_FLAG_NAME, + ManagementFactoryHelper.getDiagnosticMXBean().getVMOption(MAX_FREE_RATIO_FLAG_NAME).getValue() + ); + } + + private static void allocateList(List garbage, int count, int size) { + for (int i = 0; i < count; i++) { + garbage.add(new byte[size]); + } + } + } + + static MemoryUsage getHeapMemoryUsage() { + return ManagementFactory.getMemoryMXBean().getHeapMemoryUsage(); + } + + /** + * Prints memory usage to standard output + */ + 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 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), + freeratio * 100 + ); + } + } +} From debb101f7b751c9bbcb160c1fecc5910f84de5b7 Mon Sep 17 00:00:00 2001 From: Andrey Zakharov Date: Thu, 11 Sep 2014 14:21:24 +0200 Subject: [PATCH 04/81] 8056237: [TESTBUG] gc/g1/TestHumongousShrinkHeap.java fails due to OOM Added respect for available memory. Renamed function names Reviewed-by: jwilhelm, tschatzl --- .../test/gc/g1/TestHumongousShrinkHeap.java | 47 +++++++++++-------- 1 file changed, 28 insertions(+), 19 deletions(-) diff --git a/hotspot/test/gc/g1/TestHumongousShrinkHeap.java b/hotspot/test/gc/g1/TestHumongousShrinkHeap.java index 5a15f9f11d8..97d60546b25 100644 --- a/hotspot/test/gc/g1/TestHumongousShrinkHeap.java +++ b/hotspot/test/gc/g1/TestHumongousShrinkHeap.java @@ -26,7 +26,7 @@ * @bug 8036025 8056043 * @summary Verify that heap shrinks after GC in the presence of fragmentation due to humongous objects * @library /testlibrary - * @run main/othervm -XX:MinHeapFreeRatio=10 -XX:MaxHeapFreeRatio=50 -XX:+UseG1GC -XX:G1HeapRegionSize=1M -verbose:gc TestHumongousShrinkHeap + * @run main/othervm -XX:MinHeapFreeRatio=10 -XX:MaxHeapFreeRatio=12 -XX:+UseG1GC -XX:G1HeapRegionSize=1M -verbose:gc TestHumongousShrinkHeap */ import java.lang.management.ManagementFactory; @@ -41,12 +41,24 @@ public class TestHumongousShrinkHeap { public static final String MIN_FREE_RATIO_FLAG_NAME = "MinHeapFreeRatio"; public static final String MAX_FREE_RATIO_FLAG_NAME = "MaxHeapFreeRatio"; - private static final ArrayList> garbage = new ArrayList<>(); - private static final int PAGE_SIZE = 1024 * 1024; // 1M - private static final int PAGES_NUM = 5; + private static final List> garbage = new ArrayList(); + private static final int REGION_SIZE = 1024 * 1024; // 1M + private static final int LISTS_COUNT = 10; + private static final int HUMON_SIZE = Math.round(.9f * REGION_SIZE); + private static final long AVAILABLE_MEMORY + = Runtime.getRuntime().freeMemory(); + private static final int HUMON_COUNT + = (int) ((AVAILABLE_MEMORY / HUMON_SIZE) + / LISTS_COUNT); public static void main(String[] args) { + System.out.format("Running with %s max heap size. " + + "Will allocate humongous object of %s size %d times.%n", + MemoryUsagePrinter.humanReadableByteCount(AVAILABLE_MEMORY, false), + MemoryUsagePrinter.humanReadableByteCount(HUMON_SIZE, false), + HUMON_COUNT + ); new TestHumongousShrinkHeap().test(); } @@ -54,8 +66,8 @@ public class TestHumongousShrinkHeap { System.gc(); MemoryUsagePrinter.printMemoryUsage("init"); - eat(); - MemoryUsagePrinter.printMemoryUsage("eaten"); + allocate(); + MemoryUsagePrinter.printMemoryUsage("allocated"); MemoryUsage muFull = ManagementFactory.getMemoryMXBean().getHeapMemoryUsage(); free(); @@ -72,15 +84,12 @@ public class TestHumongousShrinkHeap { )); } - private void eat() { - int HumongousObjectSize = Math.round(.9f * PAGE_SIZE); - System.out.println("Will allocate objects of size=" + - MemoryUsagePrinter.humanReadableByteCount(HumongousObjectSize, true)); + private void allocate() { - for (int i = 0; i < PAGES_NUM; i++) { - ArrayList stuff = new ArrayList<>(); - eatList(stuff, 100, HumongousObjectSize); - MemoryUsagePrinter.printMemoryUsage("eat #" + i); + for (int i = 0; i < LISTS_COUNT; i++) { + List stuff = new ArrayList(); + allocateList(stuff, HUMON_COUNT, HUMON_SIZE); + MemoryUsagePrinter.printMemoryUsage("allocate #" + (i+1)); garbage.add(stuff); } } @@ -90,12 +99,12 @@ public class TestHumongousShrinkHeap { garbage.subList(0, garbage.size() - 1).clear(); // do not free last one element from last list - ArrayList stuff = garbage.get(garbage.size() - 1); + List stuff = garbage.get(garbage.size() - 1); stuff.subList(0, stuff.size() - 1).clear(); System.gc(); } - private static void eatList(List garbage, int count, int size) { + private static void allocateList(List garbage, int count, int size) { for (int i = 0; i < count; i++) { garbage.add(new byte[size]); } @@ -122,9 +131,9 @@ class MemoryUsagePrinter { 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), + humanReadableByteCount(memusage.getInit(), false), + humanReadableByteCount(memusage.getUsed(), false), + humanReadableByteCount(memusage.getCommitted(), false), freeratio * 100 ); } From 1d4a5e9412ccfd2fff9167772a6c661ea8c91d09 Mon Sep 17 00:00:00 2001 From: Erik Helin Date: Mon, 15 Sep 2014 10:57:22 +0200 Subject: [PATCH 05/81] 8049536: os::commit_memory on Solaris uses aligment_hint as page size Reviewed-by: stefank, tschatzl --- hotspot/src/os/solaris/vm/os_solaris.cpp | 56 +++++++++++------ hotspot/src/os/solaris/vm/os_solaris.hpp | 2 + .../LargePages/TestLargePageSizeInBytes.java | 61 +++++++++++++++++++ 3 files changed, 99 insertions(+), 20 deletions(-) create mode 100644 hotspot/test/runtime/memory/LargePages/TestLargePageSizeInBytes.java diff --git a/hotspot/src/os/solaris/vm/os_solaris.cpp b/hotspot/src/os/solaris/vm/os_solaris.cpp index 0a61f78370e..9c94232e3e1 100644 --- a/hotspot/src/os/solaris/vm/os_solaris.cpp +++ b/hotspot/src/os/solaris/vm/os_solaris.cpp @@ -2525,29 +2525,30 @@ void os::pd_commit_memory_or_exit(char* addr, size_t bytes, bool exec, } } +size_t os::Solaris::page_size_for_alignment(size_t alignment) { + assert(is_size_aligned(alignment, (size_t) vm_page_size()), + err_msg(SIZE_FORMAT " is not aligned to " SIZE_FORMAT, + alignment, (size_t) vm_page_size())); + + for (int i = 0; _page_sizes[i] != 0; i++) { + if (is_size_aligned(alignment, _page_sizes[i])) { + return _page_sizes[i]; + } + } + + return (size_t) vm_page_size(); +} + int os::Solaris::commit_memory_impl(char* addr, size_t bytes, size_t alignment_hint, bool exec) { int err = Solaris::commit_memory_impl(addr, bytes, exec); - if (err == 0) { - if (UseLargePages && (alignment_hint > (size_t)vm_page_size())) { - // If the large page size has been set and the VM - // is using large pages, use the large page size - // if it is smaller than the alignment hint. This is - // a case where the VM wants to use a larger alignment size - // for its own reasons but still want to use large pages - // (which is what matters to setting the mpss range. - size_t page_size = 0; - if (large_page_size() < alignment_hint) { - assert(UseLargePages, "Expected to be here for large page use only"); - page_size = large_page_size(); - } else { - // If the alignment hint is less than the large page - // size, the VM wants a particular alignment (thus the hint) - // for internal reasons. Try to set the mpss range using - // the alignment_hint. - page_size = alignment_hint; - } - // Since this is a hint, ignore any failures. + if (err == 0 && UseLargePages && alignment_hint > 0) { + assert(is_size_aligned(bytes, alignment_hint), + err_msg(SIZE_FORMAT " is not aligned to " SIZE_FORMAT, bytes, alignment_hint)); + + // The syscall memcntl requires an exact page size (see man memcntl for details). + size_t page_size = page_size_for_alignment(alignment_hint); + if (page_size > (size_t) vm_page_size()) { (void)Solaris::setup_large_pages(addr, bytes, page_size); } } @@ -3080,7 +3081,22 @@ void os::large_page_init() { } } +bool os::Solaris::is_valid_page_size(size_t bytes) { + for (int i = 0; _page_sizes[i] != 0; i++) { + if (_page_sizes[i] == bytes) { + return true; + } + } + return false; +} + bool os::Solaris::setup_large_pages(caddr_t start, size_t bytes, size_t align) { + assert(is_valid_page_size(align), err_msg(SIZE_FORMAT " is not a valid page size", align)); + assert(is_ptr_aligned((void*) start, align), + err_msg(PTR_FORMAT " is not aligned to " SIZE_FORMAT, p2i((void*) start), align)); + assert(is_size_aligned(bytes, align), + err_msg(SIZE_FORMAT " is not aligned to " SIZE_FORMAT, bytes, align)); + // Signal to OS that we want large pages for addresses // from addr, addr + bytes struct memcntl_mha mpss_struct; diff --git a/hotspot/src/os/solaris/vm/os_solaris.hpp b/hotspot/src/os/solaris/vm/os_solaris.hpp index ab0ab85f438..58589eac584 100644 --- a/hotspot/src/os/solaris/vm/os_solaris.hpp +++ b/hotspot/src/os/solaris/vm/os_solaris.hpp @@ -97,6 +97,8 @@ class Solaris { static meminfo_func_t _meminfo; // Large Page Support + static bool is_valid_page_size(size_t bytes); + static size_t page_size_for_alignment(size_t alignment); static bool setup_large_pages(caddr_t start, size_t bytes, size_t align); static void init_thread_fpu_state(void); diff --git a/hotspot/test/runtime/memory/LargePages/TestLargePageSizeInBytes.java b/hotspot/test/runtime/memory/LargePages/TestLargePageSizeInBytes.java new file mode 100644 index 00000000000..0f90d5fb1ab --- /dev/null +++ b/hotspot/test/runtime/memory/LargePages/TestLargePageSizeInBytes.java @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* @test TestLargePageSizeInBytes + * @summary Tests that the flag -XX:LargePageSizeInBytes does not cause warnings on Solaris + * @bug 8049536 + * @library /testlibrary + * @run driver TestLargePageSizeInBytes + */ + +import com.oracle.java.testlibrary.OutputAnalyzer; +import com.oracle.java.testlibrary.Platform; +import com.oracle.java.testlibrary.ProcessTools; + +public class TestLargePageSizeInBytes { + private static long M = 1024L * 1024L; + private static long G = 1024L * M; + + public static void main(String[] args) throws Exception { + if (!Platform.isSolaris()) { + // We only use the syscall mencntl on Solaris + return; + } + + testLargePageSizeInBytes(4 * M); + testLargePageSizeInBytes(256 * M); + testLargePageSizeInBytes(512 * M); + testLargePageSizeInBytes(2 * G); + } + + private static void testLargePageSizeInBytes(long size) throws Exception { + ProcessBuilder pb = + ProcessTools.createJavaProcessBuilder("-XX:+UseLargePages", + "-XX:LargePageSizeInBytes=" + size, + "-version"); + + OutputAnalyzer out = new OutputAnalyzer(pb.start()); + out.shouldNotContain("Attempt to use MPSS failed."); + out.shouldHaveExitValue(0); + } +} From a2984b6c881d0018cef11f2cbb8f552288e0f1a5 Mon Sep 17 00:00:00 2001 From: Antonios Printezis Date: Mon, 15 Sep 2014 12:19:31 +0200 Subject: [PATCH 06/81] 8057768: Make heap region region type in G1 HeapRegion explicit Reviewed-by: brutisso, tschatzl --- .../gc_implementation/g1/concurrentMark.cpp | 15 +- .../gc_implementation/g1/g1CollectedHeap.cpp | 85 +++++------ .../g1/g1CollectorPolicy.cpp | 12 +- .../g1/g1CollectorPolicy.hpp | 4 +- .../gc_implementation/g1/g1HotCardCache.cpp | 2 - .../gc_implementation/g1/g1RemSetSummary.cpp | 10 +- .../g1/g1SATBCardTableModRefBS.hpp | 5 - .../vm/gc_implementation/g1/heapRegion.cpp | 32 +---- .../vm/gc_implementation/g1/heapRegion.hpp | 63 ++++---- .../vm/gc_implementation/g1/heapRegionSet.cpp | 10 +- .../vm/gc_implementation/g1/heapRegionSet.hpp | 12 +- .../gc_implementation/g1/heapRegionType.cpp | 69 +++++++++ .../gc_implementation/g1/heapRegionType.hpp | 134 ++++++++++++++++++ 13 files changed, 309 insertions(+), 144 deletions(-) create mode 100644 hotspot/src/share/vm/gc_implementation/g1/heapRegionType.cpp create mode 100644 hotspot/src/share/vm/gc_implementation/g1/heapRegionType.hpp diff --git a/hotspot/src/share/vm/gc_implementation/g1/concurrentMark.cpp b/hotspot/src/share/vm/gc_implementation/g1/concurrentMark.cpp index e02b4e7a320..f22bc262d2a 100644 --- a/hotspot/src/share/vm/gc_implementation/g1/concurrentMark.cpp +++ b/hotspot/src/share/vm/gc_implementation/g1/concurrentMark.cpp @@ -4737,7 +4737,7 @@ void G1PrintRegionLivenessInfoClosure::get_hum_bytes(size_t* used_bytes, } bool G1PrintRegionLivenessInfoClosure::doHeapRegion(HeapRegion* r) { - const char* type = ""; + const char* type = r->get_type_str(); HeapWord* bottom = r->bottom(); HeapWord* end = r->end(); size_t capacity_bytes = r->capacity(); @@ -4748,15 +4748,7 @@ bool G1PrintRegionLivenessInfoClosure::doHeapRegion(HeapRegion* r) { size_t remset_bytes = r->rem_set()->mem_size(); size_t strong_code_roots_bytes = r->rem_set()->strong_code_roots_mem_size(); - if (r->used() == 0) { - type = "FREE"; - } else if (r->is_survivor()) { - type = "SURV"; - } else if (r->is_young()) { - type = "EDEN"; - } else if (r->startsHumongous()) { - type = "HUMS"; - + if (r->startsHumongous()) { assert(_hum_used_bytes == 0 && _hum_capacity_bytes == 0 && _hum_prev_live_bytes == 0 && _hum_next_live_bytes == 0, "they should have been zeroed after the last time we used them"); @@ -4769,12 +4761,9 @@ bool G1PrintRegionLivenessInfoClosure::doHeapRegion(HeapRegion* r) { &prev_live_bytes, &next_live_bytes); end = bottom + HeapRegion::GrainWords; } else if (r->continuesHumongous()) { - type = "HUMC"; get_hum_bytes(&used_bytes, &capacity_bytes, &prev_live_bytes, &next_live_bytes); assert(end == bottom + HeapRegion::GrainWords, "invariant"); - } else { - type = "OLD"; } _total_used_bytes += used_bytes; diff --git a/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp b/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp index 706fb1970bd..021dbe406e0 100644 --- a/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp +++ b/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp @@ -211,7 +211,10 @@ void YoungList::empty_list(HeapRegion* list) { HeapRegion* next = list->get_next_young_region(); list->set_next_young_region(NULL); list->uninstall_surv_rate_group(); - list->set_not_young(); + // This is called before a Full GC and all the non-empty / + // non-humongous regions at the end of the Full GC will end up as + // old anyway. + list->set_old(); list = next; } } @@ -370,7 +373,7 @@ void YoungList::print() { if (curr == NULL) gclog_or_tty->print_cr(" empty"); while (curr != NULL) { - gclog_or_tty->print_cr(" "HR_FORMAT", P: "PTR_FORMAT "N: "PTR_FORMAT", age: %4d", + gclog_or_tty->print_cr(" "HR_FORMAT", P: "PTR_FORMAT ", N: "PTR_FORMAT", age: %4d", HR_FORMAT_PARAMS(curr), curr->prev_top_at_mark_start(), curr->next_top_at_mark_start(), @@ -802,6 +805,7 @@ HeapWord* G1CollectedHeap::humongous_obj_allocate(size_t word_size) { #ifdef ASSERT for (uint i = first; i < first + obj_regions; ++i) { HeapRegion* hr = region_at(i); + assert(hr->is_free(), "sanity"); assert(hr->is_empty(), "sanity"); assert(is_on_master_free_list(hr), "sanity"); } @@ -1225,21 +1229,21 @@ private: public: bool doHeapRegion(HeapRegion* hr) { assert(!hr->is_young(), "not expecting to find young regions"); - // We only generate output for non-empty regions. - if (!hr->is_empty()) { - if (!hr->isHumongous()) { - _hr_printer->post_compaction(hr, G1HRPrinter::Old); - } else if (hr->startsHumongous()) { - if (hr->region_num() == 1) { - // single humongous region - _hr_printer->post_compaction(hr, G1HRPrinter::SingleHumongous); - } else { - _hr_printer->post_compaction(hr, G1HRPrinter::StartsHumongous); - } + if (hr->is_free()) { + // We only generate output for non-empty regions. + } else if (hr->startsHumongous()) { + if (hr->region_num() == 1) { + // single humongous region + _hr_printer->post_compaction(hr, G1HRPrinter::SingleHumongous); } else { - assert(hr->continuesHumongous(), "only way to get here"); - _hr_printer->post_compaction(hr, G1HRPrinter::ContinuesHumongous); + _hr_printer->post_compaction(hr, G1HRPrinter::StartsHumongous); } + } else if (hr->continuesHumongous()) { + _hr_printer->post_compaction(hr, G1HRPrinter::ContinuesHumongous); + } else if (hr->is_old()) { + _hr_printer->post_compaction(hr, G1HRPrinter::Old); + } else { + ShouldNotReachHere(); } return false; } @@ -2121,8 +2125,8 @@ jint G1CollectedHeap::initialize() { // We'll re-use the same region whether the alloc region will // require BOT updates or not and, if it doesn't, then a non-young // region will complain that it cannot support allocations without - // BOT updates. So we'll tag the dummy region as young to avoid that. - dummy_region->set_young(); + // BOT updates. So we'll tag the dummy region as eden to avoid that. + dummy_region->set_eden(); // Make sure it's full. dummy_region->set_top(dummy_region->end()); G1AllocRegion::setup(this, dummy_region); @@ -4031,14 +4035,6 @@ G1CollectedHeap::do_collection_pause_at_safepoint(double target_pause_time_ms) { if (_hr_printer.is_active()) { HeapRegion* hr = g1_policy()->collection_set(); while (hr != NULL) { - G1HRPrinter::RegionType type; - if (!hr->is_young()) { - type = G1HRPrinter::Old; - } else if (hr->is_survivor()) { - type = G1HRPrinter::Survivor; - } else { - type = G1HRPrinter::Eden; - } _hr_printer.cset(hr); hr = hr->next_in_collection_set(); } @@ -6063,7 +6059,7 @@ void G1CollectedHeap::free_region(HeapRegion* hr, FreeRegionList* free_list, bool par, bool locked) { - assert(!hr->isHumongous(), "this is only for non-humongous regions"); + assert(!hr->is_free(), "the region should not be free"); assert(!hr->is_empty(), "the region should not be empty"); assert(_hrm.is_available(hr->hrm_index()), "region should be committed"); assert(free_list != NULL, "pre-condition"); @@ -6093,14 +6089,14 @@ void G1CollectedHeap::free_humongous_region(HeapRegion* hr, // We need to read this before we make the region non-humongous, // otherwise the information will be gone. uint last_index = hr->last_hc_index(); - hr->set_notHumongous(); + hr->clear_humongous(); free_region(hr, free_list, par); uint i = hr->hrm_index() + 1; while (i < last_index) { HeapRegion* curr_hr = region_at(i); assert(curr_hr->continuesHumongous(), "invariant"); - curr_hr->set_notHumongous(); + curr_hr->clear_humongous(); free_region(curr_hr, free_list, par); i += 1; } @@ -6408,9 +6404,9 @@ void G1CollectedHeap::free_collection_set(HeapRegion* cs_head, EvacuationInfo& e if (cur->is_young()) { cur->set_young_index_in_cset(-1); } - cur->set_not_young(); cur->set_evacuation_failed(false); // The region is now considered to be old. + cur->set_old(); _old_set.add(cur); evacuation_info.increment_collectionset_used_after(cur->used()); } @@ -6697,16 +6693,15 @@ public: TearDownRegionSetsClosure(HeapRegionSet* old_set) : _old_set(old_set) { } bool doHeapRegion(HeapRegion* r) { - if (r->is_empty()) { - // We ignore empty regions, we'll empty the free list afterwards - } else if (r->is_young()) { - // We ignore young regions, we'll empty the young list afterwards - } else if (r->isHumongous()) { - // We ignore humongous regions, we're not tearing down the - // humongous region set - } else { - // The rest should be old + if (r->is_old()) { _old_set->remove(r); + } else { + // We ignore free regions, we'll empty the free list afterwards. + // We ignore young regions, we'll empty the young list afterwards. + // We ignore humongous regions, we're not tearing down the + // humongous regions set. + assert(r->is_free() || r->is_young() || r->isHumongous(), + "it cannot be another type"); } return false; } @@ -6756,6 +6751,7 @@ public: if (r->is_empty()) { // Add free regions to the free list + r->set_free(); _hrm->insert_into_free_list(r); } else if (!_free_list_only) { assert(!r->is_young(), "we should not come across young regions"); @@ -6763,7 +6759,11 @@ public: if (r->isHumongous()) { // We ignore humongous regions, we left the humongous set unchanged } else { - // The rest should be old, add them to the old set + // Objects that were compacted would have ended up on regions + // that were previously old or free. + assert(r->is_free() || r->is_old(), "invariant"); + // We now consider them old, so register as such. + r->set_old(); _old_set->add(r); } _total_used += r->used(); @@ -6830,7 +6830,7 @@ HeapRegion* G1CollectedHeap::new_mutator_alloc_region(size_t word_size, void G1CollectedHeap::retire_mutator_alloc_region(HeapRegion* alloc_region, size_t allocated_bytes) { assert_heap_locked_or_at_safepoint(true /* should_be_vm_thread */); - assert(alloc_region->is_young(), "all mutator alloc regions should be young"); + assert(alloc_region->is_eden(), "all mutator alloc regions should be eden"); g1_policy()->add_region_to_incremental_cset_lhs(alloc_region); _summary_bytes_used += allocated_bytes; @@ -6889,6 +6889,7 @@ HeapRegion* G1CollectedHeap::new_gc_alloc_region(size_t word_size, _hr_printer.alloc(new_alloc_region, G1HRPrinter::Survivor); check_bitmaps("Survivor Region Allocation", new_alloc_region); } else { + new_alloc_region->set_old(); _hr_printer.alloc(new_alloc_region, G1HRPrinter::Old); check_bitmaps("Old Region Allocation", new_alloc_region); } @@ -7000,9 +7001,11 @@ public: } else if (hr->is_empty()) { assert(_hrm->is_free(hr), err_msg("Heap region %u is empty but not on the free list.", hr->hrm_index())); _free_count.increment(1u, hr->capacity()); - } else { + } else if (hr->is_old()) { assert(hr->containing_set() == _old_set, err_msg("Heap region %u is old but not in the old set.", hr->hrm_index())); _old_count.increment(1u, hr->capacity()); + } else { + ShouldNotReachHere(); } return false; } diff --git a/hotspot/src/share/vm/gc_implementation/g1/g1CollectorPolicy.cpp b/hotspot/src/share/vm/gc_implementation/g1/g1CollectorPolicy.cpp index 931c4e3d25e..a2f33d12c38 100644 --- a/hotspot/src/share/vm/gc_implementation/g1/g1CollectorPolicy.cpp +++ b/hotspot/src/share/vm/gc_implementation/g1/g1CollectorPolicy.cpp @@ -1665,7 +1665,7 @@ G1CollectorPolicy::record_concurrent_mark_cleanup_end(int no_of_gc_threads) { // Add the heap region at the head of the non-incremental collection set void G1CollectorPolicy::add_old_region_to_cset(HeapRegion* hr) { assert(_inc_cset_build_state == Active, "Precondition"); - assert(!hr->is_young(), "non-incremental add of young region"); + assert(hr->is_old(), "the region should be old"); assert(!hr->in_collection_set(), "should not already be in the CSet"); hr->set_in_collection_set(true); @@ -1811,7 +1811,7 @@ void G1CollectorPolicy::add_region_to_incremental_cset_common(HeapRegion* hr) { // Add the region at the RHS of the incremental cset void G1CollectorPolicy::add_region_to_incremental_cset_rhs(HeapRegion* hr) { // We should only ever be appending survivors at the end of a pause - assert( hr->is_survivor(), "Logic"); + assert(hr->is_survivor(), "Logic"); // Do the 'common' stuff add_region_to_incremental_cset_common(hr); @@ -1829,7 +1829,7 @@ void G1CollectorPolicy::add_region_to_incremental_cset_rhs(HeapRegion* hr) { // Add the region to the LHS of the incremental cset void G1CollectorPolicy::add_region_to_incremental_cset_lhs(HeapRegion* hr) { // Survivors should be added to the RHS at the end of a pause - assert(!hr->is_survivor(), "Logic"); + assert(hr->is_eden(), "Logic"); // Do the 'common' stuff add_region_to_incremental_cset_common(hr); @@ -1989,7 +1989,11 @@ void G1CollectorPolicy::finalize_cset(double target_pause_time_ms, EvacuationInf HeapRegion* hr = young_list->first_survivor_region(); while (hr != NULL) { assert(hr->is_survivor(), "badly formed young list"); - hr->set_young(); + // There is a convention that all the young regions in the CSet + // are tagged as "eden", so we do this for the survivors here. We + // use the special set_eden_pre_gc() as it doesn't check that the + // region is free (which is not the case here). + hr->set_eden_pre_gc(); hr = hr->get_next_young_region(); } diff --git a/hotspot/src/share/vm/gc_implementation/g1/g1CollectorPolicy.hpp b/hotspot/src/share/vm/gc_implementation/g1/g1CollectorPolicy.hpp index 4f141892e1f..4746e0aac8a 100644 --- a/hotspot/src/share/vm/gc_implementation/g1/g1CollectorPolicy.hpp +++ b/hotspot/src/share/vm/gc_implementation/g1/g1CollectorPolicy.hpp @@ -299,13 +299,13 @@ public: // Accessors void set_region_eden(HeapRegion* hr, int young_index_in_cset) { - hr->set_young(); + hr->set_eden(); hr->install_surv_rate_group(_short_lived_surv_rate_group); hr->set_young_index_in_cset(young_index_in_cset); } void set_region_survivor(HeapRegion* hr, int young_index_in_cset) { - assert(hr->is_young() && hr->is_survivor(), "pre-condition"); + assert(hr->is_survivor(), "pre-condition"); hr->install_surv_rate_group(_survivor_surv_rate_group); hr->set_young_index_in_cset(young_index_in_cset); } diff --git a/hotspot/src/share/vm/gc_implementation/g1/g1HotCardCache.cpp b/hotspot/src/share/vm/gc_implementation/g1/g1HotCardCache.cpp index 79655933da7..9a86e0f2e7f 100644 --- a/hotspot/src/share/vm/gc_implementation/g1/g1HotCardCache.cpp +++ b/hotspot/src/share/vm/gc_implementation/g1/g1HotCardCache.cpp @@ -27,7 +27,6 @@ #include "gc_implementation/g1/g1CollectedHeap.inline.hpp" #include "gc_implementation/g1/g1HotCardCache.hpp" #include "gc_implementation/g1/g1RemSet.hpp" -#include "gc_implementation/g1/heapRegion.hpp" #include "runtime/atomic.inline.hpp" G1HotCardCache::G1HotCardCache(G1CollectedHeap *g1h): @@ -136,7 +135,6 @@ void G1HotCardCache::drain(uint worker_i, } void G1HotCardCache::reset_card_counts(HeapRegion* hr) { - assert(!hr->isHumongous(), "Should have been cleared"); _card_counts.clear_region(hr); } diff --git a/hotspot/src/share/vm/gc_implementation/g1/g1RemSetSummary.cpp b/hotspot/src/share/vm/gc_implementation/g1/g1RemSetSummary.cpp index 69b1c1f8707..c55165bdc7b 100644 --- a/hotspot/src/share/vm/gc_implementation/g1/g1RemSetSummary.cpp +++ b/hotspot/src/share/vm/gc_implementation/g1/g1RemSetSummary.cpp @@ -259,14 +259,16 @@ public: size_t code_root_elems = hrrs->strong_code_roots_list_length(); RegionTypeCounter* current = NULL; - if (r->is_young()) { + if (r->is_free()) { + current = &_free; + } else if (r->is_young()) { current = &_young; } else if (r->isHumongous()) { current = &_humonguous; - } else if (r->is_empty()) { - current = &_free; - } else { + } else if (r->is_old()) { current = &_old; + } else { + ShouldNotReachHere(); } current->add(rs_mem_sz, occupied_cards, code_root_mem_sz, code_root_elems); _all.add(rs_mem_sz, occupied_cards, code_root_mem_sz, code_root_elems); diff --git a/hotspot/src/share/vm/gc_implementation/g1/g1SATBCardTableModRefBS.hpp b/hotspot/src/share/vm/gc_implementation/g1/g1SATBCardTableModRefBS.hpp index f02c28c227b..80c402e9954 100644 --- a/hotspot/src/share/vm/gc_implementation/g1/g1SATBCardTableModRefBS.hpp +++ b/hotspot/src/share/vm/gc_implementation/g1/g1SATBCardTableModRefBS.hpp @@ -31,8 +31,6 @@ #include "oops/oop.inline.hpp" #include "utilities/macros.hpp" -#if INCLUDE_ALL_GCS - class DirtyCardQueueSet; class G1SATBCardTableLoggingModRefBS; @@ -180,7 +178,4 @@ class G1SATBCardTableLoggingModRefBS: public G1SATBCardTableModRefBS { void write_ref_array_work(MemRegion mr) { invalidate(mr); } }; - -#endif // INCLUDE_ALL_GCS - #endif // SHARE_VM_GC_IMPLEMENTATION_G1_G1SATBCARDTABLEMODREFBS_HPP diff --git a/hotspot/src/share/vm/gc_implementation/g1/heapRegion.cpp b/hotspot/src/share/vm/gc_implementation/g1/heapRegion.cpp index 0c7c3906cb3..26c83211d6b 100644 --- a/hotspot/src/share/vm/gc_implementation/g1/heapRegion.cpp +++ b/hotspot/src/share/vm/gc_implementation/g1/heapRegion.cpp @@ -211,8 +211,6 @@ void HeapRegion::reset_after_compaction() { } void HeapRegion::hr_clear(bool par, bool clear_space, bool locked) { - assert(_humongous_type == NotHumongous, - "we should have already filtered out humongous regions"); assert(_humongous_start_region == NULL, "we should have already filtered out humongous regions"); assert(_end == _orig_end, @@ -222,7 +220,7 @@ void HeapRegion::hr_clear(bool par, bool clear_space, bool locked) { set_young_index_in_cset(-1); uninstall_surv_rate_group(); - set_young_type(NotYoung); + set_free(); reset_pre_dummy_top(); if (!par) { @@ -273,7 +271,7 @@ void HeapRegion::set_startsHumongous(HeapWord* new_top, HeapWord* new_end) { assert(top() == bottom(), "should be empty"); assert(bottom() <= new_top && new_top <= new_end, "pre-condition"); - _humongous_type = StartsHumongous; + _type.set_starts_humongous(); _humongous_start_region = this; set_end(new_end); @@ -287,11 +285,11 @@ void HeapRegion::set_continuesHumongous(HeapRegion* first_hr) { assert(top() == bottom(), "should be empty"); assert(first_hr->startsHumongous(), "pre-condition"); - _humongous_type = ContinuesHumongous; + _type.set_continues_humongous(); _humongous_start_region = first_hr; } -void HeapRegion::set_notHumongous() { +void HeapRegion::clear_humongous() { assert(isHumongous(), "pre-condition"); if (startsHumongous()) { @@ -307,7 +305,6 @@ void HeapRegion::set_notHumongous() { } assert(capacity() == HeapRegion::GrainBytes, "pre-condition"); - _humongous_type = NotHumongous; _humongous_start_region = NULL; } @@ -327,12 +324,12 @@ HeapRegion::HeapRegion(uint hrm_index, MemRegion mr) : G1OffsetTableContigSpace(sharedOffsetArray, mr), _hrm_index(hrm_index), - _humongous_type(NotHumongous), _humongous_start_region(NULL), + _humongous_start_region(NULL), _in_collection_set(false), _next_in_special_set(NULL), _orig_end(NULL), _claimed(InitialClaimValue), _evacuation_failed(false), _prev_marked_bytes(0), _next_marked_bytes(0), _gc_efficiency(0.0), - _young_type(NotYoung), _next_young_region(NULL), + _next_young_region(NULL), _next_dirty_cards_region(NULL), _next(NULL), _prev(NULL), #ifdef ASSERT _containing_set(NULL), @@ -686,26 +683,11 @@ void HeapRegion::verify_strong_code_roots(VerifyOption vo, bool* failures) const void HeapRegion::print() const { print_on(gclog_or_tty); } void HeapRegion::print_on(outputStream* st) const { - if (isHumongous()) { - if (startsHumongous()) - st->print(" HS"); - else - st->print(" HC"); - } else { - st->print(" "); - } + st->print(" %2s", get_short_type_str()); if (in_collection_set()) st->print(" CS"); else st->print(" "); - if (is_young()) - st->print(is_survivor() ? " SU" : " Y "); - else - st->print(" "); - if (is_empty()) - st->print(" F"); - else - st->print(" "); st->print(" TS %5d", _gc_time_stamp); st->print(" PTAMS "PTR_FORMAT" NTAMS "PTR_FORMAT, prev_top_at_mark_start(), next_top_at_mark_start()); diff --git a/hotspot/src/share/vm/gc_implementation/g1/heapRegion.hpp b/hotspot/src/share/vm/gc_implementation/g1/heapRegion.hpp index a311fd5e92d..0484fc3aa89 100644 --- a/hotspot/src/share/vm/gc_implementation/g1/heapRegion.hpp +++ b/hotspot/src/share/vm/gc_implementation/g1/heapRegion.hpp @@ -27,6 +27,7 @@ #include "gc_implementation/g1/g1BlockOffsetTable.hpp" #include "gc_implementation/g1/g1_specialized_oop_closures.hpp" +#include "gc_implementation/g1/heapRegionType.hpp" #include "gc_implementation/g1/survRateGroup.hpp" #include "gc_implementation/shared/ageTable.hpp" #include "gc_implementation/shared/spaceDecorator.hpp" @@ -34,8 +35,6 @@ #include "memory/watermark.hpp" #include "utilities/macros.hpp" -#if INCLUDE_ALL_GCS - // A HeapRegion is the smallest piece of a G1CollectedHeap that // can be collected independently. @@ -55,10 +54,7 @@ class nmethod; #define HR_FORMAT "%u:(%s)["PTR_FORMAT","PTR_FORMAT","PTR_FORMAT"]" #define HR_FORMAT_PARAMS(_hr_) \ (_hr_)->hrm_index(), \ - (_hr_)->is_survivor() ? "S" : (_hr_)->is_young() ? "E" : \ - (_hr_)->startsHumongous() ? "HS" : \ - (_hr_)->continuesHumongous() ? "HC" : \ - !(_hr_)->is_empty() ? "O" : "F", \ + (_hr_)->get_short_type_str(), \ p2i((_hr_)->bottom()), p2i((_hr_)->top()), p2i((_hr_)->end()) // sentinel value for hrm_index @@ -215,12 +211,6 @@ class HeapRegion: public G1OffsetTableContigSpace { friend class VMStructs; private: - enum HumongousType { - NotHumongous = 0, - StartsHumongous, - ContinuesHumongous - }; - // The remembered set for this region. // (Might want to make this "inline" later, to avoid some alloc failure // issues.) @@ -232,7 +222,8 @@ class HeapRegion: public G1OffsetTableContigSpace { // The index of this region in the heap region sequence. uint _hrm_index; - HumongousType _humongous_type; + HeapRegionType _type; + // For a humongous region, region in which it starts. HeapRegion* _humongous_start_region; // For the start region of a humongous sequence, it's original end(). @@ -274,13 +265,6 @@ class HeapRegion: public G1OffsetTableContigSpace { // The calculated GC efficiency of the region. double _gc_efficiency; - enum YoungType { - NotYoung, // a region is not young - Young, // a region is young - Survivor // a region is young and it contains survivors - }; - - volatile YoungType _young_type; int _young_index_in_cset; SurvRateGroup* _surv_rate_group; int _age_index; @@ -305,12 +289,6 @@ class HeapRegion: public G1OffsetTableContigSpace { _next_top_at_mark_start = bot; } - void set_young_type(YoungType new_type) { - //assert(_young_type != new_type, "setting the same type" ); - // TODO: add more assertions here - _young_type = new_type; - } - // Cached attributes used in the collection set policy information // The RSet length that was added to the total value @@ -430,9 +408,21 @@ class HeapRegion: public G1OffsetTableContigSpace { _prev_marked_bytes = _next_marked_bytes = 0; } - bool isHumongous() const { return _humongous_type != NotHumongous; } - bool startsHumongous() const { return _humongous_type == StartsHumongous; } - bool continuesHumongous() const { return _humongous_type == ContinuesHumongous; } + const char* get_type_str() const { return _type.get_str(); } + const char* get_short_type_str() const { return _type.get_short_str(); } + + bool is_free() const { return _type.is_free(); } + + bool is_young() const { return _type.is_young(); } + bool is_eden() const { return _type.is_eden(); } + bool is_survivor() const { return _type.is_survivor(); } + + bool isHumongous() const { return _type.is_humongous(); } + bool startsHumongous() const { return _type.is_starts_humongous(); } + bool continuesHumongous() const { return _type.is_continues_humongous(); } + + bool is_old() const { return _type.is_old(); } + // For a humongous region, region in which it starts. HeapRegion* humongous_start_region() const { return _humongous_start_region; @@ -496,7 +486,7 @@ class HeapRegion: public G1OffsetTableContigSpace { void set_continuesHumongous(HeapRegion* first_hr); // Unsets the humongous-related fields on the region. - void set_notHumongous(); + void clear_humongous(); // If the region has a remembered set, return a pointer to it. HeapRegionRemSet* rem_set() const { @@ -623,9 +613,6 @@ class HeapRegion: public G1OffsetTableContigSpace { void calc_gc_efficiency(void); double gc_efficiency() { return _gc_efficiency;} - bool is_young() const { return _young_type != NotYoung; } - bool is_survivor() const { return _young_type == Survivor; } - int young_index_in_cset() const { return _young_index_in_cset; } void set_young_index_in_cset(int index) { assert( (index == -1) || is_young(), "pre-condition" ); @@ -677,11 +664,13 @@ class HeapRegion: public G1OffsetTableContigSpace { } } - void set_young() { set_young_type(Young); } + void set_free() { _type.set_free(); } - void set_survivor() { set_young_type(Survivor); } + void set_eden() { _type.set_eden(); } + void set_eden_pre_gc() { _type.set_eden_pre_gc(); } + void set_survivor() { _type.set_survivor(); } - void set_not_young() { set_young_type(NotYoung); } + void set_old() { _type.set_old(); } // Determine if an object has been allocated since the last // mark performed by the collector. This returns true iff the object @@ -809,6 +798,4 @@ class HeapRegionClosure : public StackObj { bool complete() { return _complete; } }; -#endif // INCLUDE_ALL_GCS - #endif // SHARE_VM_GC_IMPLEMENTATION_G1_HEAPREGION_HPP diff --git a/hotspot/src/share/vm/gc_implementation/g1/heapRegionSet.cpp b/hotspot/src/share/vm/gc_implementation/g1/heapRegionSet.cpp index 7f3e76ad15c..8fde2455f1d 100644 --- a/hotspot/src/share/vm/gc_implementation/g1/heapRegionSet.cpp +++ b/hotspot/src/share/vm/gc_implementation/g1/heapRegionSet.cpp @@ -42,7 +42,9 @@ void HeapRegionSetBase::verify_region(HeapRegion* hr) { assert(hr->containing_set() == this, err_msg("Inconsistent containing set for %u", hr->hrm_index())); assert(!hr->is_young(), err_msg("Adding young region %u", hr->hrm_index())); // currently we don't use these sets for young regions assert(hr->isHumongous() == regions_humongous(), err_msg("Wrong humongous state for region %u and set %s", hr->hrm_index(), name())); - assert(hr->is_empty() == regions_empty(), err_msg("Wrong empty state for region %u and set %s", hr->hrm_index(), name())); + assert(hr->is_free() == regions_free(), err_msg("Wrong free state for region %u and set %s", hr->hrm_index(), name())); + assert(!hr->is_free() || hr->is_empty(), err_msg("Free region %u is not empty for set %s", hr->hrm_index(), name())); + assert(!hr->is_empty() || hr->is_free(), err_msg("Empty region %u is not free for set %s", hr->hrm_index(), name())); assert(hr->rem_set()->verify_ready_for_par_iteration(), err_msg("Wrong iteration state %u", hr->hrm_index())); } #endif @@ -85,16 +87,16 @@ void HeapRegionSetBase::print_on(outputStream* out, bool print_contents) { out->print_cr("Set: %s ("PTR_FORMAT")", name(), this); out->print_cr(" Region Assumptions"); out->print_cr(" humongous : %s", BOOL_TO_STR(regions_humongous())); - out->print_cr(" empty : %s", BOOL_TO_STR(regions_empty())); + out->print_cr(" free : %s", BOOL_TO_STR(regions_free())); out->print_cr(" Attributes"); out->print_cr(" length : %14u", length()); out->print_cr(" total capacity : "SIZE_FORMAT_W(14)" bytes", total_capacity_bytes()); } -HeapRegionSetBase::HeapRegionSetBase(const char* name, bool humongous, bool empty, HRSMtSafeChecker* mt_safety_checker) +HeapRegionSetBase::HeapRegionSetBase(const char* name, bool humongous, bool free, HRSMtSafeChecker* mt_safety_checker) : _name(name), _verify_in_progress(false), - _is_humongous(humongous), _is_empty(empty), _mt_safety_checker(mt_safety_checker), + _is_humongous(humongous), _is_free(free), _mt_safety_checker(mt_safety_checker), _count() { } diff --git a/hotspot/src/share/vm/gc_implementation/g1/heapRegionSet.hpp b/hotspot/src/share/vm/gc_implementation/g1/heapRegionSet.hpp index db501993685..9a9267c4b9b 100644 --- a/hotspot/src/share/vm/gc_implementation/g1/heapRegionSet.hpp +++ b/hotspot/src/share/vm/gc_implementation/g1/heapRegionSet.hpp @@ -81,7 +81,7 @@ class HeapRegionSetBase VALUE_OBJ_CLASS_SPEC { friend class VMStructs; private: bool _is_humongous; - bool _is_empty; + bool _is_free; HRSMtSafeChecker* _mt_safety_checker; protected: @@ -102,9 +102,9 @@ protected: // not. Only used during verification. bool regions_humongous() { return _is_humongous; } - // Indicates whether all regions in the set should be empty or + // Indicates whether all regions in the set should be free or // not. Only used during verification. - bool regions_empty() { return _is_empty; } + bool regions_free() { return _is_free; } void check_mt_safety() { if (_mt_safety_checker != NULL) { @@ -114,7 +114,7 @@ protected: virtual void fill_in_ext_msg_extra(hrs_ext_msg* msg) { } - HeapRegionSetBase(const char* name, bool humongous, bool empty, HRSMtSafeChecker* mt_safety_checker); + HeapRegionSetBase(const char* name, bool humongous, bool free, HRSMtSafeChecker* mt_safety_checker); public: const char* name() { return _name; } @@ -171,7 +171,7 @@ public: do { \ assert(((_set1_)->regions_humongous() == \ (_set2_)->regions_humongous()) && \ - ((_set1_)->regions_empty() == (_set2_)->regions_empty()), \ + ((_set1_)->regions_free() == (_set2_)->regions_free()), \ hrs_err_msg("the contents of set %s and set %s should match", \ (_set1_)->name(), (_set2_)->name())); \ } while (0) @@ -184,7 +184,7 @@ public: class HeapRegionSet : public HeapRegionSetBase { public: HeapRegionSet(const char* name, bool humongous, HRSMtSafeChecker* mt_safety_checker): - HeapRegionSetBase(name, humongous, false /* empty */, mt_safety_checker) { } + HeapRegionSetBase(name, humongous, false /* free */, mt_safety_checker) { } void bulk_remove(const HeapRegionSetCount& removed) { _count.decrement(removed.length(), removed.capacity()); diff --git a/hotspot/src/share/vm/gc_implementation/g1/heapRegionType.cpp b/hotspot/src/share/vm/gc_implementation/g1/heapRegionType.cpp new file mode 100644 index 00000000000..347b58d7996 --- /dev/null +++ b/hotspot/src/share/vm/gc_implementation/g1/heapRegionType.cpp @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#include "precompiled.hpp" +#include "gc_implementation/g1/heapRegionType.hpp" + +bool HeapRegionType::is_valid(Tag tag) { + switch (tag) { + case FreeTag: + case EdenTag: + case SurvTag: + case HumStartsTag: + case HumContTag: + case OldTag: + return true; + } + return false; +} + +const char* HeapRegionType::get_str() const { + hrt_assert_is_valid(_tag); + switch (_tag) { + case FreeTag: return "FREE"; + case EdenTag: return "EDEN"; + case SurvTag: return "SURV"; + case HumStartsTag: return "HUMS"; + case HumContTag: return "HUMC"; + case OldTag: return "OLD"; + } + ShouldNotReachHere(); + // keep some compilers happy + return NULL; +} + +const char* HeapRegionType::get_short_str() const { + hrt_assert_is_valid(_tag); + switch (_tag) { + case FreeTag: return "F"; + case EdenTag: return "E"; + case SurvTag: return "S"; + case HumStartsTag: return "HS"; + case HumContTag: return "HC"; + case OldTag: return "O"; + } + ShouldNotReachHere(); + // keep some compilers happy + return NULL; +} diff --git a/hotspot/src/share/vm/gc_implementation/g1/heapRegionType.hpp b/hotspot/src/share/vm/gc_implementation/g1/heapRegionType.hpp new file mode 100644 index 00000000000..b00590a6b78 --- /dev/null +++ b/hotspot/src/share/vm/gc_implementation/g1/heapRegionType.hpp @@ -0,0 +1,134 @@ +/* + * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#ifndef SHARE_VM_GC_IMPLEMENTATION_G1_HEAPREGIONTYPE_HPP +#define SHARE_VM_GC_IMPLEMENTATION_G1_HEAPREGIONTYPE_HPP + +#include "memory/allocation.hpp" + +#define hrt_assert_is_valid(tag) \ + assert(is_valid((tag)), err_msg("invalid HR type: %u", (uint) (tag))) + +class HeapRegionType VALUE_OBJ_CLASS_SPEC { +private: + // We encode the value of the heap region type so the generation can be + // determined quickly. The tag is split into two parts: + // + // major type (young, humongous) : top N-1 bits + // minor type (eden / survivor, starts / cont hum, etc.) : bottom 1 bit + // + // If there's need to increase the number of minor types in the + // future, we'll have to increase the size of the latter and hence + // decrease the size of the former. + // + // 0000 0 [ 0] Free + // + // 0001 0 Young Mask + // 0001 0 [ 2] Eden + // 0001 1 [ 3] Survivor + // + // 0010 0 Humongous Mask + // 0010 0 [ 4] Humongous Starts + // 0010 1 [ 5] Humongous Continues + // + // 01000 [ 8] Old + typedef enum { + FreeTag = 0, + + YoungMask = 2, + EdenTag = YoungMask, + SurvTag = YoungMask + 1, + + HumMask = 4, + HumStartsTag = HumMask, + HumContTag = HumMask + 1, + + OldTag = 8 + } Tag; + + volatile Tag _tag; + + static bool is_valid(Tag tag); + + Tag get() const { + hrt_assert_is_valid(_tag); + return _tag; + } + + // Sets the type to 'tag'. + void set(Tag tag) { + hrt_assert_is_valid(tag); + hrt_assert_is_valid(_tag); + _tag = tag; + } + + // Sets the type to 'tag', expecting the type to be 'before'. This + // is available for when we want to add sanity checking to the type + // transition. + void set_from(Tag tag, Tag before) { + hrt_assert_is_valid(tag); + hrt_assert_is_valid(before); + hrt_assert_is_valid(_tag); + assert(_tag == before, + err_msg("HR tag: %u, expected: %u new tag; %u", _tag, before, tag)); + _tag = tag; + } + +public: + // Queries + + bool is_free() const { return get() == FreeTag; } + + bool is_young() const { return (get() & YoungMask) != 0; } + bool is_eden() const { return get() == EdenTag; } + bool is_survivor() const { return get() == SurvTag; } + + bool is_humongous() const { return (get() & HumMask) != 0; } + bool is_starts_humongous() const { return get() == HumStartsTag; } + bool is_continues_humongous() const { return get() == HumContTag; } + + bool is_old() const { return get() == OldTag; } + + // Setters + + void set_free() { set(FreeTag); } + + void set_eden() { set_from(EdenTag, FreeTag); } + void set_eden_pre_gc() { set_from(EdenTag, SurvTag); } + void set_survivor() { set_from(SurvTag, FreeTag); } + + void set_starts_humongous() { set_from(HumStartsTag, FreeTag); } + void set_continues_humongous() { set_from(HumContTag, FreeTag); } + + void set_old() { set(OldTag); } + + // Misc + + const char* get_str() const; + const char* get_short_str() const; + + HeapRegionType() : _tag(FreeTag) { hrt_assert_is_valid(_tag); } +}; + +#endif // SHARE_VM_GC_IMPLEMENTATION_G1_HEAPREGIONTYPE_HPP From 3eff7a8f6401db1c34304bdecbbb6e4946f5cfdc Mon Sep 17 00:00:00 2001 From: Erik Helin Date: Tue, 24 Jun 2014 15:50:50 +0200 Subject: [PATCH 07/81] 8049864: TestParallelHeapSizeFlags fails with unexpected heap size Reviewed-by: sjohanss, jmasa --- .../parallelScavenge/generationSizer.cpp | 7 +- .../parallelScavenge/parMarkBitMap.cpp | 2 +- .../parallelScavenge/psParallelCompact.cpp | 2 +- hotspot/src/share/vm/memory/heap.cpp | 10 ++- hotspot/src/share/vm/prims/jni.cpp | 2 + hotspot/src/share/vm/runtime/os.cpp | 81 +++++++++++++++---- hotspot/src/share/vm/runtime/os.hpp | 18 ++--- hotspot/src/share/vm/runtime/virtualspace.cpp | 6 +- .../arguments/TestParallelHeapSizeFlags.java | 1 - 9 files changed, 89 insertions(+), 40 deletions(-) diff --git a/hotspot/src/share/vm/gc_implementation/parallelScavenge/generationSizer.cpp b/hotspot/src/share/vm/gc_implementation/parallelScavenge/generationSizer.cpp index ff4b53057b8..e5defc98edc 100644 --- a/hotspot/src/share/vm/gc_implementation/parallelScavenge/generationSizer.cpp +++ b/hotspot/src/share/vm/gc_implementation/parallelScavenge/generationSizer.cpp @@ -66,9 +66,10 @@ void GenerationSizer::initialize_flags() { void GenerationSizer::initialize_size_info() { trace_gen_sizes("ps heap raw"); - const size_t page_sz = os::page_size_for_region(_min_heap_byte_size, - _max_heap_byte_size, - 8); + const size_t max_page_sz = os::page_size_for_region(_max_heap_byte_size, 8); + const size_t min_pages = 4; // 1 for eden + 1 for each survivor + 1 for old + const size_t min_page_sz = os::page_size_for_region(_min_heap_byte_size, min_pages); + const size_t page_sz = MIN2(max_page_sz, min_page_sz); // Can a page size be something else than a power of two? assert(is_power_of_2((intptr_t)page_sz), "must be a power of 2"); diff --git a/hotspot/src/share/vm/gc_implementation/parallelScavenge/parMarkBitMap.cpp b/hotspot/src/share/vm/gc_implementation/parallelScavenge/parMarkBitMap.cpp index 47d5068a9c3..a8ab19357ce 100644 --- a/hotspot/src/share/vm/gc_implementation/parallelScavenge/parMarkBitMap.cpp +++ b/hotspot/src/share/vm/gc_implementation/parallelScavenge/parMarkBitMap.cpp @@ -41,7 +41,7 @@ ParMarkBitMap::initialize(MemRegion covered_region) const size_t words = bits / BitsPerWord; const size_t raw_bytes = words * sizeof(idx_t); - const size_t page_sz = os::page_size_for_region(raw_bytes, raw_bytes, 10); + const size_t page_sz = os::page_size_for_region(raw_bytes, 10); const size_t granularity = os::vm_allocation_granularity(); _reserved_byte_size = align_size_up(raw_bytes, MAX2(page_sz, granularity)); diff --git a/hotspot/src/share/vm/gc_implementation/parallelScavenge/psParallelCompact.cpp b/hotspot/src/share/vm/gc_implementation/parallelScavenge/psParallelCompact.cpp index 1a2fd30c6ce..be903293269 100644 --- a/hotspot/src/share/vm/gc_implementation/parallelScavenge/psParallelCompact.cpp +++ b/hotspot/src/share/vm/gc_implementation/parallelScavenge/psParallelCompact.cpp @@ -403,7 +403,7 @@ PSVirtualSpace* ParallelCompactData::create_vspace(size_t count, size_t element_size) { const size_t raw_bytes = count * element_size; - const size_t page_sz = os::page_size_for_region(raw_bytes, raw_bytes, 10); + const size_t page_sz = os::page_size_for_region(raw_bytes, 10); const size_t granularity = os::vm_allocation_granularity(); _reserved_byte_size = align_size_up(raw_bytes, MAX2(page_sz, granularity)); diff --git a/hotspot/src/share/vm/memory/heap.cpp b/hotspot/src/share/vm/memory/heap.cpp index db0105fb3a1..cf137e74a00 100644 --- a/hotspot/src/share/vm/memory/heap.cpp +++ b/hotspot/src/share/vm/memory/heap.cpp @@ -98,9 +98,13 @@ bool CodeHeap::reserve(size_t reserved_size, size_t committed_size, _log2_segment_size = exact_log2(segment_size); // Reserve and initialize space for _memory. - const size_t page_size = os::can_execute_large_page_memory() ? - os::page_size_for_region(committed_size, reserved_size, 8) : - os::vm_page_size(); + size_t page_size = os::vm_page_size(); + if (os::can_execute_large_page_memory()) { + const size_t min_pages = 8; + page_size = MIN2(os::page_size_for_region(committed_size, min_pages), + os::page_size_for_region(reserved_size, min_pages)); + } + const size_t granularity = os::vm_allocation_granularity(); const size_t r_align = MAX2(page_size, granularity); const size_t r_size = align_size_up(reserved_size, r_align); diff --git a/hotspot/src/share/vm/prims/jni.cpp b/hotspot/src/share/vm/prims/jni.cpp index c404b4c7de5..398ad5d2270 100644 --- a/hotspot/src/share/vm/prims/jni.cpp +++ b/hotspot/src/share/vm/prims/jni.cpp @@ -3848,6 +3848,7 @@ _JNI_IMPORT_OR_EXPORT_ jint JNICALL JNI_GetDefaultJavaVMInitArgs(void *args_) { unit_test_function_call // Forward declaration +void TestOS_test(); void TestReservedSpace_test(); void TestReserveMemorySpecial_test(); void TestVirtualSpace_test(); @@ -3871,6 +3872,7 @@ void FreeRegionList_test(); void execute_internal_vm_tests() { if (ExecuteInternalVMTests) { tty->print_cr("Running internal VM tests"); + run_unit_test(TestOS_test()); run_unit_test(TestReservedSpace_test()); run_unit_test(TestReserveMemorySpecial_test()); run_unit_test(TestVirtualSpace_test()); diff --git a/hotspot/src/share/vm/runtime/os.cpp b/hotspot/src/share/vm/runtime/os.cpp index 5d8d0d598a9..8d7450b1d97 100644 --- a/hotspot/src/share/vm/runtime/os.cpp +++ b/hotspot/src/share/vm/runtime/os.cpp @@ -1406,24 +1406,15 @@ bool os::stack_shadow_pages_available(Thread *thread, methodHandle method) { return (sp > (stack_limit + reserved_area)); } -size_t os::page_size_for_region(size_t region_min_size, size_t region_max_size, - uint min_pages) -{ +size_t os::page_size_for_region(size_t region_size, size_t min_pages) { assert(min_pages > 0, "sanity"); if (UseLargePages) { - const size_t max_page_size = region_max_size / min_pages; + const size_t max_page_size = region_size / min_pages; - for (unsigned int i = 0; _page_sizes[i] != 0; ++i) { - const size_t sz = _page_sizes[i]; - const size_t mask = sz - 1; - if ((region_min_size & mask) == 0 && (region_max_size & mask) == 0) { - // The largest page size with no fragmentation. - return sz; - } - - if (sz <= max_page_size) { - // The largest page size that satisfies the min_pages requirement. - return sz; + for (size_t i = 0; _page_sizes[i] != 0; ++i) { + const size_t page_size = _page_sizes[i]; + if (page_size <= max_page_size && is_size_aligned(region_size, page_size)) { + return page_size; } } } @@ -1660,3 +1651,63 @@ os::SuspendResume::State os::SuspendResume::switch_state(os::SuspendResume::Stat return result; } #endif + +/////////////// Unit tests /////////////// + +#ifndef PRODUCT + +#define assert_eq(a,b) assert(a == b, err_msg(SIZE_FORMAT " != " SIZE_FORMAT, a, b)) + +class TestOS : AllStatic { + static size_t small_page_size() { + return os::vm_page_size(); + } + + static size_t large_page_size() { + const size_t large_page_size_example = 4 * M; + return os::page_size_for_region(large_page_size_example, 1); + } + + static void test_page_size_for_region() { + if (UseLargePages) { + const size_t small_page = small_page_size(); + const size_t large_page = large_page_size(); + + if (large_page > small_page) { + size_t num_small_pages_in_large = large_page / small_page; + size_t page = os::page_size_for_region(large_page, num_small_pages_in_large); + + assert_eq(page, small_page); + } + } + } + + static void test_page_size_for_region_alignment() { + if (UseLargePages) { + const size_t small_page = small_page_size(); + const size_t large_page = large_page_size(); + if (large_page > small_page) { + const size_t unaligned_region = large_page + 17; + size_t page = os::page_size_for_region(unaligned_region, 1); + assert_eq(page, small_page); + + const size_t num_pages = 5; + const size_t aligned_region = large_page * num_pages; + page = os::page_size_for_region(aligned_region, num_pages); + assert_eq(page, large_page); + } + } + } + + public: + static void run_tests() { + test_page_size_for_region(); + test_page_size_for_region_alignment(); + } +}; + +void TestOS_test() { + TestOS::run_tests(); +} + +#endif // PRODUCT diff --git a/hotspot/src/share/vm/runtime/os.hpp b/hotspot/src/share/vm/runtime/os.hpp index 350a998aca4..8e43fd1c193 100644 --- a/hotspot/src/share/vm/runtime/os.hpp +++ b/hotspot/src/share/vm/runtime/os.hpp @@ -265,19 +265,11 @@ class os: AllStatic { // Return the default page size. static int vm_page_size(); - // Return the page size to use for a region of memory. The min_pages argument - // is a hint intended to limit fragmentation; it says the returned page size - // should be <= region_max_size / min_pages. Because min_pages is a hint, - // this routine may return a size larger than region_max_size / min_pages. - // - // The current implementation ignores min_pages if a larger page size is an - // exact multiple of both region_min_size and region_max_size. This allows - // larger pages to be used when doing so would not cause fragmentation; in - // particular, a single page can be used when region_min_size == - // region_max_size == a supported page size. - static size_t page_size_for_region(size_t region_min_size, - size_t region_max_size, - uint min_pages); + // Returns the page size to use for a region of memory. + // region_size / min_pages will always be greater than or equal to the + // returned value. + static size_t page_size_for_region(size_t region_size, size_t min_pages); + // Return the largest page size that can be used static size_t max_page_size() { // The _page_sizes array is sorted in descending order. diff --git a/hotspot/src/share/vm/runtime/virtualspace.cpp b/hotspot/src/share/vm/runtime/virtualspace.cpp index 4cc2e04c1a1..ea557f338e2 100644 --- a/hotspot/src/share/vm/runtime/virtualspace.cpp +++ b/hotspot/src/share/vm/runtime/virtualspace.cpp @@ -38,7 +38,7 @@ ReservedSpace::ReservedSpace() : _base(NULL), _size(0), _noaccess_prefix(0), } ReservedSpace::ReservedSpace(size_t size) { - size_t page_size = os::page_size_for_region(size, size, 1); + size_t page_size = os::page_size_for_region(size, 1); bool large_pages = page_size != (size_t)os::vm_page_size(); // Don't force the alignment to be large page aligned, // since that will waste memory. @@ -357,7 +357,7 @@ VirtualSpace::VirtualSpace() { bool VirtualSpace::initialize(ReservedSpace rs, size_t committed_size) { - const size_t max_commit_granularity = os::page_size_for_region(rs.size(), rs.size(), 1); + const size_t max_commit_granularity = os::page_size_for_region(rs.size(), 1); return initialize_with_granularity(rs, committed_size, max_commit_granularity); } @@ -992,7 +992,7 @@ class TestVirtualSpace : AllStatic { case Disable: return vs.initialize_with_granularity(rs, 0, os::vm_page_size()); case Commit: - return vs.initialize_with_granularity(rs, 0, os::page_size_for_region(rs.size(), rs.size(), 1)); + return vs.initialize_with_granularity(rs, 0, os::page_size_for_region(rs.size(), 1)); } } diff --git a/hotspot/test/gc/arguments/TestParallelHeapSizeFlags.java b/hotspot/test/gc/arguments/TestParallelHeapSizeFlags.java index bf627db8b0e..c9837f50b7c 100644 --- a/hotspot/test/gc/arguments/TestParallelHeapSizeFlags.java +++ b/hotspot/test/gc/arguments/TestParallelHeapSizeFlags.java @@ -22,7 +22,6 @@ */ /* - * @ignore 8049864 * @test TestParallelHeapSizeFlags * @key gc * @bug 8006088 From 04ec3bf1d4a8a6481b6ea0469cd03163d9f97bd5 Mon Sep 17 00:00:00 2001 From: Shanliang Jiang Date: Fri, 12 Sep 2014 12:19:27 +0200 Subject: [PATCH 08/81] 8049303: Transient network problems cause JMX thread to fail silenty Reviewed-by: dfuchs, jbachorik --- .../management/remote/rmi/RMIConnector.java | 106 +++++++++++------- 1 file changed, 67 insertions(+), 39 deletions(-) diff --git a/jdk/src/java.management/share/classes/javax/management/remote/rmi/RMIConnector.java b/jdk/src/java.management/share/classes/javax/management/remote/rmi/RMIConnector.java index 545a79aeee1..ac54a1e7e8a 100644 --- a/jdk/src/java.management/share/classes/javax/management/remote/rmi/RMIConnector.java +++ b/jdk/src/java.management/share/classes/javax/management/remote/rmi/RMIConnector.java @@ -1335,66 +1335,94 @@ public class RMIConnector implements JMXConnector, Serializable, JMXAddressable int maxNotifications, long timeout) throws IOException, ClassNotFoundException { - IOException org; + boolean retried = false; while (true) { // used for a successful re-connection + // or a transient network problem try { return connection.fetchNotifications(clientSequenceNumber, maxNotifications, - timeout); + timeout); // return normally } catch (IOException ioe) { - org = ioe; + // Examine the chain of exceptions to determine whether this + // is a deserialization issue. If so - we propagate the + // appropriate exception to the caller, who will then + // proceed with fetching notifications one by one + rethrowDeserializationException(ioe); - // inform of IOException try { communicatorAdmin.gotIOException(ioe); - - // The connection should be re-established. - continue; + // reconnection OK, back to "while" to do again } catch (IOException ee) { - // No more fetch, the Exception will be re-thrown. - break; - } // never reached - } // never reached - } + boolean toClose = false; - // specially treating for an UnmarshalException - if (org instanceof UnmarshalException) { - UnmarshalException ume = (UnmarshalException)org; + synchronized (this) { + if (terminated) { + // the connection is closed. + throw ioe; + } else if (retried) { + toClose = true; + } + } - if (ume.detail instanceof ClassNotFoundException) - throw (ClassNotFoundException) ume.detail; + if (toClose) { + // JDK-8049303 + // We received an IOException - but the communicatorAdmin + // did not close the connection - possibly because + // the original exception was raised by a transient network + // problem? + // We already know that this exception is not due to a deserialization + // issue as we already took care of that before involving the + // communicatorAdmin. Moreover - we already made one retry attempt + // at fetching the same batch of notifications - and the + // problem persisted. + // Since trying again doesn't seem to solve the issue, we will now + // close the connection. Doing otherwise might cause the + // NotifFetcher thread to die silently. + final Notification failedNotif = + new JMXConnectionNotification( + JMXConnectionNotification.FAILED, + this, + connectionId, + clientNotifSeqNo++, + "Failed to communicate with the server: " + ioe.toString(), + ioe); - /* In Sun's RMI implementation, if a method return - contains an unserializable object, then we get - UnmarshalException wrapping WriteAbortedException - wrapping NotSerializableException. In that case we - extract the NotSerializableException so that our - caller can realize it should try to skip past the - notification that presumably caused it. It's not - certain that every other RMI implementation will - generate this exact exception sequence. If not, we - will not detect that the problem is due to an - unserializable object, and we will stop trying to - receive notifications from the server. It's not - clear we can do much better. */ - if (ume.detail instanceof WriteAbortedException) { - WriteAbortedException wae = - (WriteAbortedException) ume.detail; - if (wae.detail instanceof IOException) - throw (IOException) wae.detail; + sendNotification(failedNotif); + + try { + close(true); + } catch (Exception e) { + // OK. + // We are closing + } + throw ioe; // the connection is closed here. + } else { + // JDK-8049303 possible transient network problem, + // let's try one more time + retried = true; + } + } } - } else if (org instanceof MarshalException) { + } + } + + private void rethrowDeserializationException(IOException ioe) + throws ClassNotFoundException, IOException { + // specially treating for an UnmarshalException + if (ioe instanceof UnmarshalException) { + throw ioe; // the fix of 6937053 made ClientNotifForwarder.fetchNotifs + // fetch one by one with UnmarshalException + } else if (ioe instanceof MarshalException) { // IIOP will throw MarshalException wrapping a NotSerializableException // when a server fails to serialize a response. - MarshalException me = (MarshalException)org; + MarshalException me = (MarshalException)ioe; if (me.detail instanceof NotSerializableException) { throw (NotSerializableException)me.detail; } } - // Not serialization problem, simply re-throw the orginal exception - throw org; + // Not serialization problem, return. } protected Integer addListenerForMBeanRemovedNotif() From 2daf96018c7d9711c584fc5d546481dd016aa22a Mon Sep 17 00:00:00 2001 From: Chris Hegarty Date: Fri, 12 Sep 2014 15:51:22 +0100 Subject: [PATCH 09/81] 8058216: NetworkInterface.getHardwareAddress can return zero length byte array when run with preferIPv4Stack Reviewed-by: michaelm --- .../java.base/windows/native/libnet/NetworkInterface.c | 8 +++++--- jdk/test/java/net/NetworkInterface/Test.java | 4 +++- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/jdk/src/java.base/windows/native/libnet/NetworkInterface.c b/jdk/src/java.base/windows/native/libnet/NetworkInterface.c index 8ba5eda3c1f..56d822ddb8f 100644 --- a/jdk/src/java.base/windows/native/libnet/NetworkInterface.c +++ b/jdk/src/java.base/windows/native/libnet/NetworkInterface.c @@ -990,9 +990,11 @@ JNIEXPORT jbyteArray JNICALL Java_java_net_NetworkInterface_getMacAddr0 case MIB_IF_TYPE_FDDI: case IF_TYPE_IEEE80211: len = ifRowP->dwPhysAddrLen; - ret = (*env)->NewByteArray(env, len); - if (!IS_NULL(ret)) { - (*env)->SetByteArrayRegion(env, ret, 0, len, (jbyte *) ifRowP->bPhysAddr); + if (len > 0) { + ret = (*env)->NewByteArray(env, len); + if (!IS_NULL(ret)) { + (*env)->SetByteArrayRegion(env, ret, 0, len, (jbyte *) ifRowP->bPhysAddr); + } } break; } diff --git a/jdk/test/java/net/NetworkInterface/Test.java b/jdk/test/java/net/NetworkInterface/Test.java index 6db3079992d..de74eec5ca4 100644 --- a/jdk/test/java/net/NetworkInterface/Test.java +++ b/jdk/test/java/net/NetworkInterface/Test.java @@ -22,7 +22,9 @@ */ /* @test - * @bug 4405354 6594296 + * @bug 4405354 6594296 8058216 + * @run main Test + * @run main/othervm -Djava.net.preferIPv4Stack=true Test * @summary Basic tests for NetworkInterface */ import java.net.NetworkInterface; From 85cc6b9fde72fd4931deb4a0de60ff332e31aa18 Mon Sep 17 00:00:00 2001 From: Claes Redestad Date: Wed, 13 Aug 2014 18:40:16 +0200 Subject: [PATCH 10/81] 8055055: Improve numeric parsing in java.sql Reviewed-by: lancea --- .../java.sql/share/classes/java/sql/Date.java | 30 ++++---- .../java.sql/share/classes/java/sql/Time.java | 23 +++--- .../share/classes/java/sql/Timestamp.java | 76 ++++++++----------- 3 files changed, 55 insertions(+), 74 deletions(-) diff --git a/jdk/src/java.sql/share/classes/java/sql/Date.java b/jdk/src/java.sql/share/classes/java/sql/Date.java index ab5121fca21..a0e8c287b2c 100644 --- a/jdk/src/java.sql/share/classes/java/sql/Date.java +++ b/jdk/src/java.sql/share/classes/java/sql/Date.java @@ -108,31 +108,27 @@ public class Date extends java.util.Date { * JDBC date escape format (yyyy-[m]m-[d]d) */ public static Date valueOf(String s) { + if (s == null) { + throw new java.lang.IllegalArgumentException(); + } final int YEAR_LENGTH = 4; final int MONTH_LENGTH = 2; final int DAY_LENGTH = 2; final int MAX_MONTH = 12; final int MAX_DAY = 31; - int firstDash; - int secondDash; Date d = null; - if (s == null) { - throw new java.lang.IllegalArgumentException(); - } - firstDash = s.indexOf('-'); - secondDash = s.indexOf('-', firstDash + 1); + int firstDash = s.indexOf('-'); + int secondDash = s.indexOf('-', firstDash + 1); + int len = s.length(); - if ((firstDash > 0) && (secondDash > 0) && (secondDash < s.length() - 1)) { - String yyyy = s.substring(0, firstDash); - String mm = s.substring(firstDash + 1, secondDash); - String dd = s.substring(secondDash + 1); - if (yyyy.length() == YEAR_LENGTH && - (mm.length() >= 1 && mm.length() <= MONTH_LENGTH) && - (dd.length() >= 1 && dd.length() <= DAY_LENGTH)) { - int year = Integer.parseInt(yyyy); - int month = Integer.parseInt(mm); - int day = Integer.parseInt(dd); + if ((firstDash > 0) && (secondDash > 0) && (secondDash < len - 1)) { + if (firstDash == YEAR_LENGTH && + (secondDash - firstDash > 1 && secondDash - firstDash <= MONTH_LENGTH + 1) && + (len - secondDash > 1 && len - secondDash <= DAY_LENGTH + 1)) { + int year = Integer.parseInt(s, 0, firstDash, 10); + int month = Integer.parseInt(s, firstDash + 1, secondDash, 10); + int day = Integer.parseInt(s, secondDash + 1, len, 10); if ((month >= 1 && month <= MAX_MONTH) && (day >= 1 && day <= MAX_DAY)) { d = new Date(year - 1900, month - 1, day); diff --git a/jdk/src/java.sql/share/classes/java/sql/Time.java b/jdk/src/java.sql/share/classes/java/sql/Time.java index 46a14b59a80..209a4b646a9 100644 --- a/jdk/src/java.sql/share/classes/java/sql/Time.java +++ b/jdk/src/java.sql/share/classes/java/sql/Time.java @@ -90,22 +90,19 @@ public class Time extends java.util.Date { * @return a corresponding Time object */ public static Time valueOf(String s) { + if (s == null) throw new java.lang.IllegalArgumentException(); + int hour; int minute; int second; - int firstColon; - int secondColon; - - if (s == null) throw new java.lang.IllegalArgumentException(); - - firstColon = s.indexOf(':'); - secondColon = s.indexOf(':', firstColon+1); - if ((firstColon > 0) & (secondColon > 0) & - (secondColon < s.length()-1)) { - hour = Integer.parseInt(s.substring(0, firstColon)); - minute = - Integer.parseInt(s.substring(firstColon+1, secondColon)); - second = Integer.parseInt(s.substring(secondColon+1)); + int firstColon = s.indexOf(':'); + int secondColon = s.indexOf(':', firstColon + 1); + int len = s.length(); + if (firstColon > 0 && secondColon > 0 && + secondColon < len - 1) { + hour = Integer.parseInt(s, 0, firstColon, 10); + minute = Integer.parseInt(s, firstColon + 1, secondColon, 10); + second = Integer.parseInt(s, secondColon + 1, len, 10); } else { throw new java.lang.IllegalArgumentException(); } diff --git a/jdk/src/java.sql/share/classes/java/sql/Timestamp.java b/jdk/src/java.sql/share/classes/java/sql/Timestamp.java index 06ca2648814..1fb64c60be6 100644 --- a/jdk/src/java.sql/share/classes/java/sql/Timestamp.java +++ b/jdk/src/java.sql/share/classes/java/sql/Timestamp.java @@ -171,9 +171,6 @@ public class Timestamp extends java.util.Date { final int DAY_LENGTH = 2; final int MAX_MONTH = 12; final int MAX_DAY = 31; - String date_s; - String time_s; - String nanos_s; int year = 0; int month = 0; int day = 0; @@ -184,49 +181,38 @@ public class Timestamp extends java.util.Date { int firstDash; int secondDash; int dividingSpace; - int firstColon = 0; - int secondColon = 0; - int period = 0; + int firstColon; + int secondColon; + int period; String formatError = "Timestamp format must be yyyy-mm-dd hh:mm:ss[.fffffffff]"; - String zeros = "000000000"; - String delimiterDate = "-"; - String delimiterTime = ":"; if (s == null) throw new java.lang.IllegalArgumentException("null string"); // Split the string into date and time components s = s.trim(); dividingSpace = s.indexOf(' '); - if (dividingSpace > 0) { - date_s = s.substring(0,dividingSpace); - time_s = s.substring(dividingSpace+1); - } else { + if (dividingSpace < 0) { throw new java.lang.IllegalArgumentException(formatError); } // Parse the date - firstDash = date_s.indexOf('-'); - secondDash = date_s.indexOf('-', firstDash+1); + firstDash = s.indexOf('-'); + secondDash = s.indexOf('-', firstDash+1); // Parse the time - if (time_s == null) - throw new java.lang.IllegalArgumentException(formatError); - firstColon = time_s.indexOf(':'); - secondColon = time_s.indexOf(':', firstColon+1); - period = time_s.indexOf('.', secondColon+1); + firstColon = s.indexOf(':', dividingSpace + 1); + secondColon = s.indexOf(':', firstColon + 1); + period = s.indexOf('.', secondColon + 1); // Convert the date boolean parsedDate = false; - if ((firstDash > 0) && (secondDash > 0) && (secondDash < date_s.length() - 1)) { - String yyyy = date_s.substring(0, firstDash); - String mm = date_s.substring(firstDash + 1, secondDash); - String dd = date_s.substring(secondDash + 1); - if (yyyy.length() == YEAR_LENGTH && - (mm.length() >= 1 && mm.length() <= MONTH_LENGTH) && - (dd.length() >= 1 && dd.length() <= DAY_LENGTH)) { - year = Integer.parseInt(yyyy); - month = Integer.parseInt(mm); - day = Integer.parseInt(dd); + if (firstDash > 0 && secondDash > 0 && secondDash < dividingSpace - 1) { + if (firstDash == YEAR_LENGTH && + (secondDash - firstDash > 1 && secondDash - firstDash <= MONTH_LENGTH + 1) && + (dividingSpace - secondDash > 1 && dividingSpace - secondDash <= DAY_LENGTH + 1)) { + year = Integer.parseInt(s, 0, firstDash, 10); + month = Integer.parseInt(s, firstDash + 1, secondDash, 10); + day = Integer.parseInt(s, secondDash + 1, dividingSpace, 10); if ((month >= 1 && month <= MAX_MONTH) && (day >= 1 && day <= MAX_DAY)) { parsedDate = true; @@ -238,25 +224,27 @@ public class Timestamp extends java.util.Date { } // Convert the time; default missing nanos - if ((firstColon > 0) & (secondColon > 0) & - (secondColon < time_s.length()-1)) { - hour = Integer.parseInt(time_s.substring(0, firstColon)); - minute = - Integer.parseInt(time_s.substring(firstColon+1, secondColon)); - if ((period > 0) & (period < time_s.length()-1)) { - second = - Integer.parseInt(time_s.substring(secondColon+1, period)); - nanos_s = time_s.substring(period+1); - if (nanos_s.length() > 9) + int len = s.length(); + if (firstColon > 0 && secondColon > 0 && secondColon < len - 1) { + hour = Integer.parseInt(s, dividingSpace + 1, firstColon, 10); + minute = Integer.parseInt(s, firstColon + 1, secondColon, 10); + if (period > 0 && period < len - 1) { + second = Integer.parseInt(s, secondColon + 1, period, 10); + int nanoPrecision = len - (period + 1); + if (nanoPrecision > 9) throw new java.lang.IllegalArgumentException(formatError); - if (!Character.isDigit(nanos_s.charAt(0))) + if (!Character.isDigit(s.charAt(period + 1))) throw new java.lang.IllegalArgumentException(formatError); - nanos_s = nanos_s + zeros.substring(0,9-nanos_s.length()); - a_nanos = Integer.parseInt(nanos_s); + int tmpNanos = Integer.parseInt(s, period + 1, len, 10); + while (nanoPrecision < 9) { + tmpNanos *= 10; + nanoPrecision++; + } + a_nanos = tmpNanos; } else if (period > 0) { throw new java.lang.IllegalArgumentException(formatError); } else { - second = Integer.parseInt(time_s.substring(secondColon+1)); + second = Integer.parseInt(s, secondColon + 1, len, 10); } } else { throw new java.lang.IllegalArgumentException(formatError); From 288d75cbc3fcd4191375da8eaea3dc7dd89d12fd Mon Sep 17 00:00:00 2001 From: Dmitriy Ermashov Date: Tue, 26 Aug 2014 15:04:49 +0400 Subject: [PATCH 11/81] 8055360: Move the rest part of AWT ShapedAndTranslucent tests to OpenJDK Reviewed-by: alexsch --- .../ShapedAndTranslucentWindows/Common.java | 417 ++++++++++++++++++ .../PerPixelTranslucent.java | 62 +++ .../PerPixelTranslucentCanvas.java | 104 +++++ .../PerPixelTranslucentGradient.java | 70 +++ .../PerPixelTranslucentSwing.java | 95 ++++ .../SetShapeAndClickSwing.java | 172 ++++++++ .../ShapedPerPixelTranslucentGradient.java | 77 ++++ ...ranslucentPerPixelTranslucentGradient.java | 77 ++++ .../TranslucentJComboBox.java | 152 +++++++ ...ranslucentPerPixelTranslucentGradient.java | 72 +++ .../TranslucentWindowClickSwing.java | 105 +++++ 11 files changed, 1403 insertions(+) create mode 100644 jdk/test/javax/swing/JWindow/ShapedAndTranslucentWindows/Common.java create mode 100644 jdk/test/javax/swing/JWindow/ShapedAndTranslucentWindows/PerPixelTranslucent.java create mode 100644 jdk/test/javax/swing/JWindow/ShapedAndTranslucentWindows/PerPixelTranslucentCanvas.java create mode 100644 jdk/test/javax/swing/JWindow/ShapedAndTranslucentWindows/PerPixelTranslucentGradient.java create mode 100644 jdk/test/javax/swing/JWindow/ShapedAndTranslucentWindows/PerPixelTranslucentSwing.java create mode 100644 jdk/test/javax/swing/JWindow/ShapedAndTranslucentWindows/SetShapeAndClickSwing.java create mode 100644 jdk/test/javax/swing/JWindow/ShapedAndTranslucentWindows/ShapedPerPixelTranslucentGradient.java create mode 100644 jdk/test/javax/swing/JWindow/ShapedAndTranslucentWindows/ShapedTranslucentPerPixelTranslucentGradient.java create mode 100644 jdk/test/javax/swing/JWindow/ShapedAndTranslucentWindows/TranslucentJComboBox.java create mode 100644 jdk/test/javax/swing/JWindow/ShapedAndTranslucentWindows/TranslucentPerPixelTranslucentGradient.java create mode 100644 jdk/test/javax/swing/JWindow/ShapedAndTranslucentWindows/TranslucentWindowClickSwing.java diff --git a/jdk/test/javax/swing/JWindow/ShapedAndTranslucentWindows/Common.java b/jdk/test/javax/swing/JWindow/ShapedAndTranslucentWindows/Common.java new file mode 100644 index 00000000000..e43365bba9f --- /dev/null +++ b/jdk/test/javax/swing/JWindow/ShapedAndTranslucentWindows/Common.java @@ -0,0 +1,417 @@ +/* + * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import javax.swing.*; +import javax.swing.border.EmptyBorder; +import java.awt.*; +import java.awt.event.*; +import java.awt.geom.Area; +import java.awt.geom.Rectangle2D; +import java.awt.image.BufferedImage; +import java.security.SecureRandom; + +public abstract class Common { + + ExtendedRobot robot; + Class windowClass; + JFrame background; + BufferedImage foreground; + Window window; + volatile boolean gradientBackgroundEnabled = false; + volatile int gradientWidth = 255; + volatile int gradientHeight = 255; + + float opacity = 1.0f; + float perPixelTranslucency = 1.0f; + static Color BG_COLOR = Color.BLUE; + static Color FG_COLOR = Color.RED; + static final int delay = 1000; + static final SecureRandom random = new SecureRandom(); + static final int dl = 100; + static final Class[] WINDOWS_TO_TEST = { JWindow.class, JFrame.class, JDialog.class }; + + volatile int clicked; + + public Common(Class windowClass, float opacity, float perPixelTranslucency, boolean gradient) throws Exception { + this.gradientBackgroundEnabled = gradient; + this.perPixelTranslucency = perPixelTranslucency; + this.opacity = opacity; + robot = new ExtendedRobot(); + this.windowClass = windowClass; + EventQueue.invokeAndWait(this::initBackgroundFrame); + EventQueue.invokeAndWait(this::initGUI); + } + + public Common(Class windowClass) throws Exception { + this(windowClass, 1.0f, 1.0f, false); + } + + public Common(Class windowClass, boolean gradient) throws Exception { + this(windowClass, 1.0f, 1.0f, gradient); + } + + public abstract void doTest() throws Exception; + + public void dispose() { + window.dispose(); + background.dispose(); + } + + public void applyShape() {}; + + public void applyDynamicShape() { + final Area a = new Area(); + Dimension size = window.getSize(); + for (int x = 0; x < 3; x++) { + for (int y = 0; y < 3; y++) { + a.add(new Area(new Rectangle2D.Double( + x * size.getWidth() / 17*6, y * size.getHeight() / 17*6, + size.getWidth() / 17*5, size.getHeight() / 17*5))); + } + } + window.setShape(a); + } + + public BufferedImage getForegroundWindow() throws Exception { + final BufferedImage f[] = new BufferedImage[1]; + EventQueue.invokeAndWait( () -> { + f[0] = new BufferedImage(window.getWidth(), + window.getHeight(), BufferedImage.TYPE_INT_RGB); + window.printAll(f[0].createGraphics()); + }); + robot.waitForIdle(delay); + return f[0]; + } + + public static boolean checkTranslucencyMode(GraphicsDevice.WindowTranslucency mode) { + + if (!GraphicsEnvironment + .getLocalGraphicsEnvironment() + .getDefaultScreenDevice() + .isWindowTranslucencySupported(mode)){ + System.out.println(mode+" translucency mode isn't supported"); + return false; + } else { + return true; + } + + } + + public void applyAppDragNResizeSupport() { + MouseAdapter m = new MouseAdapter() { + + private Point dragOrigin = null; + private Dimension origSize = null; + private Point origLoc = null; + private boolean left = false; + private boolean top = false; + private boolean bottom = false; + private boolean right = false; + + public void mousePressed(MouseEvent e) { + dragOrigin = e.getLocationOnScreen(); + origSize = window.getSize(); + origLoc = window.getLocationOnScreen(); + right = (origLoc.x + window.getWidth() - dragOrigin.x) < 5; + left = !right && dragOrigin.x - origLoc.x < 5; + bottom = (origLoc.y + window.getHeight() - dragOrigin.y) < 5; + top = !bottom && dragOrigin.y - origLoc.y < 5; + } + + public void mouseReleased(MouseEvent e) { resize(e); } + public void mouseDragged(MouseEvent e) { resize(e); } + + void resize(MouseEvent e) { + Point dragDelta = e.getLocationOnScreen(); + dragDelta.translate(-dragOrigin.x, -dragOrigin.y); + Point newLoc = new Point(origLoc); + newLoc.translate(dragDelta.x, dragDelta.y); + Dimension newSize = new Dimension(origSize); + if (left || right) { + newSize.width += right ? dragDelta.x : -dragDelta.x; + } + if (top || bottom) { + newSize.height += bottom ? dragDelta.y : -dragDelta.y; + } + if (right || (top || bottom) && !left) { + newLoc.x = origLoc.x; + } + if (bottom || (left || right) && !top) { + newLoc.y = origLoc.y; + } + window.setBounds(newLoc.x, newLoc.y, newSize.width, newSize.height); + } + }; + for (Component comp : window.getComponents()) { + comp.addMouseListener(m); + comp.addMouseMotionListener(m); + } + + window.addMouseListener(m); + window.addMouseMotionListener(m); + } + + public void checkTranslucentShape() throws Exception { + foreground = getForegroundWindow(); + Point[] points = new Point[4]; + + Dimension size = window.getSize(); + Point location = window.getLocationOnScreen(); + + points[0] = new Point(20, 20); + points[1] = new Point(20, size.height-20); + points[2] = new Point(size.width-20, 20); + points[3] = new Point(size.width-20, size.height-20); + + for (Point p : points){ + p.translate(location.x, location.y); + Color actual = robot.getPixelColor(p.x, p.y); + if (actual.equals(BG_COLOR)|| actual.equals(FG_COLOR)) + throw new RuntimeException("Error in point "+p+": "+actual+" equals to foreground or background color"); + else + System.out.println("OK with foreground point "+p); + } + } + + public void checkDynamicShape() throws Exception { + Point[] points = new Point[4]; + + Dimension size = window.getSize(); + + int blockSizeX = (int) (size.getWidth() / 17); + int blockSizeY = (int) (size.getHeight() / 17); + + // background + points[0] = new Point((int) (blockSizeX * 5.5), (int) (blockSizeY * 5.5)); + points[1] = new Point((int) (size.getWidth() - blockSizeX * 5.5), (int) (size.getHeight() - blockSizeY * 5.5)); + points[2] = new Point((int) (blockSizeX * 5.5), (int) (size.getHeight() - blockSizeY * 5.5)); + points[3] = new Point((int) (size.getWidth() - blockSizeX * 5.5), (int) (blockSizeY * 5.5)); + checkShape(points, true); + + // foreground + if (opacity < 1.0f){ + checkTranslucentShape(); + } else { + points[0] = new Point(3 * blockSizeX, 3 * blockSizeY); + points[1] = new Point(14 * blockSizeX, 14 * blockSizeY); + points[2] = new Point(3 * blockSizeX, 14 * blockSizeY); + points[3] = new Point(14 * blockSizeX, 3 * blockSizeY); + checkShape(points, false); + } + } + + public void checkShape(Point[] points, boolean areBackgroundPoints) throws Exception { + + Point location = window.getLocationOnScreen(); + + for (Point p : points) { + p.translate(location.x, location.y); + Color pixel = robot.getPixelColor(p.x, p.y); + if (areBackgroundPoints) { + if (pixel.getRed() != 0 + || pixel.getGreen() != 0 ) + throw new RuntimeException("Background point " + p + + " color " + pixel + + " does not equal to background color " + BG_COLOR); + else + System.out.println("OK with background point " + p); + } else { + if (pixel.equals(BG_COLOR)) + throw new RuntimeException("Foreground point " + p + + " color " + pixel + + " equals to background color " + BG_COLOR); + else + System.out.println("OK with foreground point " + p); + } + } + } + + public void initBackgroundFrame() { + background = new JFrame(); + background.setUndecorated(true); + background.getContentPane().setBackground(BG_COLOR); + background.setSize(500, 500); + background.setLocation(dl, dl); + background.setVisible(true); + } + + public void initGUI() { + Container contentPane; + if (windowClass.equals(Frame.class)) { + window = new JFrame(); + ((JFrame) window).setUndecorated(true); + contentPane = ((JFrame) window).getContentPane(); + } else if (windowClass.equals(Dialog.class)) { + window = new JDialog(background); + ((JDialog) window).setUndecorated(true); + contentPane = ((JDialog) window).getContentPane(); + } else { + window = new JWindow(background); + contentPane = ((JWindow) window).getContentPane(); + } + + if (perPixelTranslucency < 1.0f) { + contentPane.setBackground(colorWithOpacity(FG_COLOR, perPixelTranslucency)); + window.setBackground(colorWithOpacity(FG_COLOR, perPixelTranslucency)); + } else { + contentPane.setBackground(FG_COLOR); + window.setBackground(FG_COLOR); + } + + window.setLocation(2 * dl, 2 * dl); + window.setSize(255, 255); + window.setPreferredSize(new Dimension(255, 255)); + createSwingComponents(); + if (opacity < 1.0f) + window.setOpacity(opacity); + + window.addComponentListener(new ComponentAdapter() { + @Override + public void componentResized(ComponentEvent e) { + applyShape(); + } + }); + applyShape(); + window.setVisible(true); + applyAppDragNResizeSupport(); + window.toFront(); + } + + public void createSwingComponents() { + Container contentPane; + if (gradientBackgroundEnabled) { + JPanel jPanel = new JPanel() { + @Override + protected void paintComponent(Graphics g) { + if (g instanceof Graphics2D) { + Color background = Color.RED; + Paint p = new GradientPaint(0.0f, 0.0f, colorWithOpacity(background, 0), + 0.0f, gradientHeight - 3, colorWithOpacity(background, 1), true); + Graphics2D g2d = (Graphics2D) g; + g2d.setPaint(p); + g2d.fillRect(0, 3, gradientWidth, gradientHeight - 3); + } else { + super.paintComponent(g); + } + } + }; + jPanel.setBorder(new EmptyBorder(15, 5, 5, 5)); + jPanel.setOpaque(false); + + contentPane = jPanel; + + RootPaneContainer.class.cast(window).setContentPane(contentPane); + } else { + contentPane = RootPaneContainer.class.cast(window).getContentPane(); + } + contentPane.setLayout(new BoxLayout(contentPane, BoxLayout.Y_AXIS)); + + JButton button = new JButton("JButton"); + window.add(button); + + JTextArea textArea = new JTextArea("JTextArea"); + window.add(textArea); + + JCheckBox checkbox = new JCheckBox("JCheckBox"); + checkbox.setOpaque(false); + window.add(checkbox); + + JComboBox comboBox = new JComboBox(new String[]{"JComboBox", "Some item"}); + window.add(comboBox); + + JLabel label = new JLabel("JLabel"); + window.add(label); + + JTextField textField = new JTextField("JTextField"); + window.add(textField); + + JPanel panel = new JPanel(); + panel.setOpaque(false); + window.add(panel); + + JComboBox comboBox2 = new JComboBox(new String[]{"JComboBox2", "Another item"}); + window.add(comboBox2); + + JRadioButton radioButton = new JRadioButton("JRadioButton"); + radioButton.setOpaque(false); + window.add(radioButton); + } + + Color colorWithOpacity(Color color, float opacity) { + return new Color(color.getColorSpace(), color.getColorComponents(null), opacity); + } + + public void checkTranslucent() throws Exception { + checkTranslucentShape(); + + // Drag + Point location = window.getLocationOnScreen(); + robot.dragAndDrop(location.x + 30, location.y + 5, location.x + dl + random.nextInt(dl), location.y + random.nextInt(dl)); + robot.waitForIdle(delay); + checkTranslucentShape(); + + // Resize + location = window.getLocationOnScreen(); + robot.dragAndDrop(location.x + 4, location.y + 4, location.x + random.nextInt(2*dl)-dl, location.y + random.nextInt(2*dl)-dl); + robot.waitForIdle(delay); + checkTranslucentShape(); + + EventQueue.invokeAndWait(this::dispose); + } + + public void checkDynamic() throws Exception { + checkDynamicShape(); + + // Drag + Point location = window.getLocationOnScreen(); + robot.dragAndDrop(location.x + 30, location.y + 5, location.x + dl + random.nextInt(dl), location.y + random.nextInt(dl)); + robot.waitForIdle(delay); + checkDynamicShape(); + + // Resize + location = window.getLocationOnScreen(); + robot.dragAndDrop(location.x + 4, location.y + 4, location.x + random.nextInt(2*dl)-dl, location.y + random.nextInt(2*dl)-dl); + robot.waitForIdle(delay); + checkDynamicShape(); + + EventQueue.invokeAndWait(this::dispose); + } + + void checkClick(int x, int y, int flag) throws Exception { + + System.out.println("Trying to click point " + x + ", " + y + ", looking for " + flag + " flag to trigger."); + + clicked = 0; + robot.mouseMove(x, y); + robot.click(); + + for (int i = 0; i < 100; i++) + if ((clicked & (1 << flag)) == 0) + robot.delay(50); + else + break; + + if ((clicked & (1 << flag)) == 0) + throw new RuntimeException("FAIL: Flag " + flag + " is not triggered for point " + x + ", " + y + "!"); + } +} diff --git a/jdk/test/javax/swing/JWindow/ShapedAndTranslucentWindows/PerPixelTranslucent.java b/jdk/test/javax/swing/JWindow/ShapedAndTranslucentWindows/PerPixelTranslucent.java new file mode 100644 index 00000000000..92ddf3d2974 --- /dev/null +++ b/jdk/test/javax/swing/JWindow/ShapedAndTranslucentWindows/PerPixelTranslucent.java @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2010, 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.awt.*; + +/* + * @test + * @summary Check if a per-pixel translucent window is dragged and resized + * by mouse correctly. + * Test Description: Check if PERPIXEL_TRANSLUCENT translucency type is supported + * on the current platform. Proceed if they are supported. Create a window + * with some components in it, make window undecorated, apply translucent + * background of 0.5. Drag and resize the window using AWT Robot and verify + * that translucency is correctly applied with pixels checking. Make the + * window appear on top of a known background. Repeat this for JWindow, + * JDialog, JFrame. + * Expected Result: If PERPIXEL_TRANSLUCENT translucency type is supported, the + * window should appear with the translucency. Only window background + * should be translucent, all the controls should be opaque. + * @author mrkam + * @library ../../../../lib/testlibrary + * @build Common ExtendedRobot + * @run main PerPixelTranslucent + */ + +public class PerPixelTranslucent extends Common { + + public static void main(String[] ignored) throws Exception { + if (checkTranslucencyMode(GraphicsDevice.WindowTranslucency.PERPIXEL_TRANSLUCENT)) + for (Class windowClass: WINDOWS_TO_TEST) + new PerPixelTranslucent(windowClass).doTest(); + } + + public PerPixelTranslucent(Class windowClass) throws Exception { + super(windowClass, 1.0f, 0.5f, false); + } + + public void doTest() throws Exception { + robot.waitForIdle(delay); + checkTranslucent(); + } +} diff --git a/jdk/test/javax/swing/JWindow/ShapedAndTranslucentWindows/PerPixelTranslucentCanvas.java b/jdk/test/javax/swing/JWindow/ShapedAndTranslucentWindows/PerPixelTranslucentCanvas.java new file mode 100644 index 00000000000..fed42ceb012 --- /dev/null +++ b/jdk/test/javax/swing/JWindow/ShapedAndTranslucentWindows/PerPixelTranslucentCanvas.java @@ -0,0 +1,104 @@ +/* + * Copyright (c) 2010, 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.awt.*; +import javax.swing.*; +import java.awt.image.BufferedImage; + +/* + * @test + * @summary Check if a per-pixel translucent window shows up with correct translucency + * @author mrkam + * @library ../../../../lib/testlibrary + * @build Common ExtendedRobot + * @run main PerPixelTranslucentCanvas + */ + +public class PerPixelTranslucentCanvas extends Common { + + JPanel center; + Color OVAL_COLOR = Color.BLUE; + + public static void main(String[] ignored) throws Exception { + FG_COLOR = new Color(200, 0, 0, 100); + BG_COLOR = Color.GREEN; + for (Class windowClass: WINDOWS_TO_TEST) + new PerPixelTranslucentCanvas(windowClass).doTest(); + } + + public PerPixelTranslucentCanvas(Class windowClass) throws Exception { + super(windowClass); + } + + @Override + public void createSwingComponents() { + Container contentPane = RootPaneContainer.class.cast(window).getContentPane(); + BorderLayout bl = new BorderLayout(10, 10); + contentPane.setLayout(bl); + + JLabel label = new JLabel("North", new ImageIcon( + new BufferedImage(30, 30, BufferedImage.TYPE_INT_RGB)), SwingConstants.CENTER); + contentPane.add(label, BorderLayout.NORTH); + + JButton button = new JButton("West"); + contentPane.add(button, BorderLayout.WEST); + + center = new JPanel() { + @Override + public void paint(Graphics g) { + g.setColor(OVAL_COLOR); + g.fillOval(0, 0, getWidth(), getHeight()); + } + }; + contentPane.add(center, BorderLayout.CENTER); + + JTextField jTextField = new JTextField("South"); + contentPane.add(jTextField, BorderLayout.SOUTH); + } + + @Override + public void doTest() throws Exception { + robot.waitForIdle(delay); + + Rectangle bounds = center.getBounds(); + Point loc = center.getLocationOnScreen(); + + final int x = loc.x + bounds.width / 2; + final int y = loc.y + bounds.height / 2; + + Color color = robot.getPixelColor(x, y); + if (OVAL_COLOR.getRGB() != color.getRGB()) + throw new RuntimeException("bounds = " + bounds + "\n" + + "loc = " + loc + "\n" + + "background loc = " + background.getX() + ", " + background.getY() + "\n" + + "so middle point over background is " + (x - background.getX()) + ", " + (y - background.getY()) + "\n" + + "Oval is not opaque in the middle point (" + x + ", " + y + ", " + color + ")"); + + color = robot.getPixelColor(loc.x - 5, loc.y - 5); + if (FG_COLOR.getRGB() == color.getRGB()) + throw new RuntimeException("Background is not translucent (" + color + ")"); + + EventQueue.invokeAndWait(this::dispose); + robot.waitForIdle(); + } +} diff --git a/jdk/test/javax/swing/JWindow/ShapedAndTranslucentWindows/PerPixelTranslucentGradient.java b/jdk/test/javax/swing/JWindow/ShapedAndTranslucentWindows/PerPixelTranslucentGradient.java new file mode 100644 index 00000000000..62b72d0fe3c --- /dev/null +++ b/jdk/test/javax/swing/JWindow/ShapedAndTranslucentWindows/PerPixelTranslucentGradient.java @@ -0,0 +1,70 @@ +/* + * Copyright (c) 2010, 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.awt.*; + +/* + * @test + * @bug 8032644 + * @summary Check if a per-pixel translucent window is dragged and resized by + * mouse correctly + * Test Description: Check if PERPIXEL_TRANSLUCENT translucency type is supported + * on the current platform. Proceed if they are supported. Create a window + * with some components in it, make window undecorated, apply translucent + * background of 0 and have a gradient painted as background from + * fully-transparent to fully-opaque in componentResized listener. Drag and + * resize the window using AWT Robot and verify that translucency is + * correctly applied with pixels checking. Make the window appear on top of + * a known background. Repeat this for JWindow, JDialog, JFrame. + * Expected Result: If PERPIXEL_TRANSLUCENT translucency type is supported, + * the window should appear as specified with the translucency. Only window + * background should be translucent, all the controls should be opaque. + * @author mrkam + * @library ../../../../lib/testlibrary + * @build Common ExtendedRobot + * @run main PerPixelTranslucentGradient + */ + +public class PerPixelTranslucentGradient extends Common { + + public static void main(String[] ignored) throws Exception { + if (checkTranslucencyMode(GraphicsDevice.WindowTranslucency.PERPIXEL_TRANSLUCENT)) + for (Class windowClass: WINDOWS_TO_TEST) + new PerPixelTranslucentGradient(windowClass).doTest(); + } + + public PerPixelTranslucentGradient(Class windowClass) throws Exception { + super(windowClass, 1.0f, 0f, true); + } + + public void doTest() throws Exception { + robot.waitForIdle(delay); + checkTranslucent(); + } + + @Override + public void applyShape() { + gradientWidth = window.getWidth(); + gradientHeight = window.getHeight(); + } +} diff --git a/jdk/test/javax/swing/JWindow/ShapedAndTranslucentWindows/PerPixelTranslucentSwing.java b/jdk/test/javax/swing/JWindow/ShapedAndTranslucentWindows/PerPixelTranslucentSwing.java new file mode 100644 index 00000000000..4f6afe9b2db --- /dev/null +++ b/jdk/test/javax/swing/JWindow/ShapedAndTranslucentWindows/PerPixelTranslucentSwing.java @@ -0,0 +1,95 @@ +/* + * Copyright (c) 2010, 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import javax.swing.*; +import java.awt.*; + +/* + * @test + * @summary Check if a per-pixel translucent window shows only the area having + * opaque pixels + * Test Description: Check if PERPIXEL_TRANSLUCENT Translucency type is supported + * on the current platform. Proceed if it is supported. Create a swing window + * with some swing components in it and a transparent background (alpha 0.0). + * Bring this window on top of a known background. Do this test for JFrame, + * JWindow and JDialog + * Expected Result: Only the components present in the window must be shown. Other + * areas of the window must be transparent so that the background shows + * @author mrkam + * @library ../../../../lib/testlibrary + * @build Common ExtendedRobot + * @run main PerPixelTranslucentSwing + */ + +public class PerPixelTranslucentSwing extends Common { + + JButton north; + + public static void main(String[] ignored) throws Exception { + FG_COLOR = new Color(200, 0, 0, 0); + if (checkTranslucencyMode(GraphicsDevice.WindowTranslucency.PERPIXEL_TRANSLUCENT)) + for (Class windowClass: WINDOWS_TO_TEST) + new PerPixelTranslucentSwing(windowClass).doTest(); + } + + public PerPixelTranslucentSwing(Class windowClass) throws Exception { + super(windowClass); + } + + @Override + public void createSwingComponents() { + Container contentPane = RootPaneContainer.class.cast(window).getContentPane(); + BorderLayout bl = new BorderLayout(10, 5); + contentPane.setLayout(bl); + + north = new JButton("North"); + contentPane.add(north, BorderLayout.NORTH); + + JList center = new JList(new String[] {"Center"}); + contentPane.add(center, BorderLayout.CENTER); + + JTextField south = new JTextField("South"); + contentPane.add(south, BorderLayout.SOUTH); + + window.pack(); + window.setVisible(true); + + north.requestFocus(); + } + + @Override + public void doTest() throws Exception { + robot.waitForIdle(delay); + + // Check for background translucency + Rectangle bounds = north.getBounds(); + Point loc = north.getLocationOnScreen(); + + Color color = robot.getPixelColor(loc.x + bounds.width / 2, loc.y + bounds.height + 3); + System.out.println(color); + if (FG_COLOR.getRGB() == color.getRGB()) + throw new RuntimeException("Background is not translucent (" + color + ")"); + + EventQueue.invokeAndWait(this::dispose); + } +} diff --git a/jdk/test/javax/swing/JWindow/ShapedAndTranslucentWindows/SetShapeAndClickSwing.java b/jdk/test/javax/swing/JWindow/ShapedAndTranslucentWindows/SetShapeAndClickSwing.java new file mode 100644 index 00000000000..9705e534e7c --- /dev/null +++ b/jdk/test/javax/swing/JWindow/ShapedAndTranslucentWindows/SetShapeAndClickSwing.java @@ -0,0 +1,172 @@ +/* + * Copyright (c) 2010, 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import javax.swing.*; +import java.awt.*; +import java.awt.event.ComponentAdapter; +import java.awt.event.ComponentEvent; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; +import java.awt.geom.Area; +import java.awt.geom.GeneralPath; +import java.awt.geom.Rectangle2D; + +/* + * @test + * @summary Check if a window set with shape clips the contents + * Test Description: Check if PERPIXEL_TRANSPARENT translucency type is supported + * by the current platform. Proceed if it is supported. Apply different types + * of shapes on a Window which contains some awt components. Shape should be + * applied in such a way that some components are partially clipped off. Check + * if the components appear only partially and events work correctly for those + * components - i.e. events occur only on the areas which appear and do not + * occur on the clipped off areas. Events should be checked by clicking on the + * visible and clipped regions. Repeat this for Window, Dialog and Frame. + * Expected Result: If PERPIXEL_TRANSPARENT translucency type is supported, clicking + * on clipped region should deliver the event to the background (it should be + * another Window behind the test window) + * @author mrkam + * @library ../../../../lib/testlibrary + * @build Common ExtendedRobot + * @run main SetShapeAndClickSwing + */ + +public class SetShapeAndClickSwing extends Common { + + Component south, center, north; + + public static void main(String[] args) throws Exception { + if (checkTranslucencyMode(GraphicsDevice.WindowTranslucency.PERPIXEL_TRANSPARENT)) + for (Class windowClass: WINDOWS_TO_TEST) + new SetShapeAndClickSwing(windowClass).doTest(); + } + + public SetShapeAndClickSwing(Class windowClass) throws Exception { + super(windowClass); + } + + @Override + public void initBackgroundFrame() { + super.initBackgroundFrame(); + background.addMouseListener(new MouseAdapter() { + @Override + public void mouseClicked(MouseEvent e) { + clicked |= 1 << 0; + } + }); + } + + @Override + public void createSwingComponents() { + window.setSize(200,200); + window.setLayout(new BorderLayout()); + + south = new JLabel("South"); + south.addMouseListener(new MouseAdapter() { + @Override + public void mouseClicked(MouseEvent e) { + clicked |= 1 << 3; + } + }); + window.add(south, BorderLayout.SOUTH); + + center = new JList(); + center.addMouseListener(new MouseAdapter() { + @Override + public void mouseClicked(MouseEvent e) { + clicked |= 1 << 2; + } + }); + window.add(center, BorderLayout.CENTER); + + north = new JTextField("North"); + north.addMouseListener(new MouseAdapter() { + @Override + public void mouseClicked(MouseEvent e) { + clicked |= 1 << 1; + } + }); + window.add(north, BorderLayout.NORTH); + } + + @Override + public void doTest() throws Exception { + + robot.waitForIdle(); + + Point wls = window.getLocationOnScreen(); + Point ls; + int y; + ls = north.getLocationOnScreen(); + checkClick(ls.x + north.getWidth() / 3, ls.y + north.getHeight() / 2, 1); + + ls = center.getLocationOnScreen(); + checkClick(ls.x + center.getWidth() * 3 / 4, ls.y + center.getHeight() * 3 / 4, 2); + + ls = south.getLocationOnScreen(); + checkClick(ls.x + south.getWidth() * 2 / 3, ls.y + south.getHeight() / 2, 3); + + ls = center.getLocationOnScreen(); + checkClick(ls.x + center.getWidth() / 4, ls.y + center.getHeight() / 4, 2); + + ls = north.getLocationOnScreen(); + y = ls.y + north.getHeight() / 2; + checkClick(wls.x + 200 - (y - wls.y), y, 0); + + EventQueue.invokeAndWait(window::toFront); + robot.waitForIdle(); + + ls = center.getLocationOnScreen(); + y = ls.y + center.getHeight() / 2; + checkClick(wls.x + 200 - (y - wls.y), y, 0); + + EventQueue.invokeAndWait(window::toFront); + robot.waitForIdle(); + + ls = south.getLocationOnScreen(); + y = ls.y + south.getHeight() / 2; + checkClick(wls.x + 200 - (y - wls.y), y, 0); + + EventQueue.invokeAndWait(window::dispose); + EventQueue.invokeAndWait(background::dispose); + + robot.waitForIdle(); + } + + @Override + public void applyShape() { + Area shape = new Area(new Rectangle2D.Float(0, 0, 200, 200)); + GeneralPath gp; + gp = new GeneralPath(); + gp.moveTo(190, 0); + gp.lineTo(200, 0); + gp.lineTo(200, 10); + gp.lineTo(10, 200); + gp.lineTo(0, 200); + gp.lineTo(0, 190); + gp.closePath(); + shape.subtract(new Area(gp)); + + window.setShape(shape); + } +} diff --git a/jdk/test/javax/swing/JWindow/ShapedAndTranslucentWindows/ShapedPerPixelTranslucentGradient.java b/jdk/test/javax/swing/JWindow/ShapedAndTranslucentWindows/ShapedPerPixelTranslucentGradient.java new file mode 100644 index 00000000000..b0acdd080d1 --- /dev/null +++ b/jdk/test/javax/swing/JWindow/ShapedAndTranslucentWindows/ShapedPerPixelTranslucentGradient.java @@ -0,0 +1,77 @@ +/* + * Copyright (c) 2010, 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.awt.*; + +/* + * @test + * @bug 7043845 + * @summary Check if shaped and per-pixel translucent window is dragged and + * resized by mouse correctly. + * Test Description: Check if PERPIXEL_TRANSLUCENT and PERPIXEL_TRANSPARENT + * translucency types are supported on the current platform. Proceed if + * they are supported. Create a window with some components in it, make + * window undecorated, apply shape in componentResized listener. The shape + * should match the window size; apply translucent background of 0 and have + * a gradient painted as background from fully-transparent to fully-opaque + * in componentResized listener. Drag and resize the window using AWT Robot + * and verify that shape and translucency are correctly applied with pixels + * checking. Make the window appear on top of a known background. Repeat + * this for JWindow, JDialog, JFrame. + * Expected Result: If PERPIXEL_TRANSLUCENT and PERPIXEL_TRANSPARENT translucency + * types are supported, the window should appear as specified with the + * expected shape and translucency. Window background should have + * translucent gradient in parts that are not clipped by shape, all the + * controls should be opaque. + * @author mrkam + * @library ../../../../lib/testlibrary + * @build Common ExtendedRobot + * @run main ShapedPerPixelTranslucentGradient + */ + +public class ShapedPerPixelTranslucentGradient extends Common { + + public static void main(String[] ignored) throws Exception { + if (checkTranslucencyMode(GraphicsDevice.WindowTranslucency.PERPIXEL_TRANSLUCENT) + && checkTranslucencyMode(GraphicsDevice.WindowTranslucency.PERPIXEL_TRANSPARENT)) + for (Class windowClass: WINDOWS_TO_TEST) + new ShapedPerPixelTranslucentGradient(windowClass).doTest(); + } + + public ShapedPerPixelTranslucentGradient(Class windowClass) throws Exception { + super(windowClass, 1.0f, 0f, true); + } + + public void doTest() throws Exception { + robot.waitForIdle(delay); + checkDynamic(); + } + + @Override + public void applyShape() { + applyDynamicShape(); + gradientWidth = window.getWidth(); + gradientHeight = window.getHeight(); + } + +} diff --git a/jdk/test/javax/swing/JWindow/ShapedAndTranslucentWindows/ShapedTranslucentPerPixelTranslucentGradient.java b/jdk/test/javax/swing/JWindow/ShapedAndTranslucentWindows/ShapedTranslucentPerPixelTranslucentGradient.java new file mode 100644 index 00000000000..285bcf80452 --- /dev/null +++ b/jdk/test/javax/swing/JWindow/ShapedAndTranslucentWindows/ShapedTranslucentPerPixelTranslucentGradient.java @@ -0,0 +1,77 @@ +/* + * Copyright (c) 2010, 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.awt.*; + +/* + * @test + * @summary Check if shaped, translucent and per-pixel translucent window is + * dragged and resized by mouse correctly. + * Test Description: Check if PERPIXEL_TRANSLUCENT, TRANSLUCENT and + * PERPIXEL_TRANSPARENT translucency types are supported on the current + * platform. Proceed if they are supported. Create a window with some + * components in it, make window undecorated, apply shape in componentResized + * listener. The shape should match the window size; apply opacity of 0.7, + * apply translucent background of 0 and have a gradient painted as + * background from fully-transparent to fully-opaque in componentResized + * listener. Drag and resize the window using AWT Robot and verify that + * shape and translucency are correctly applied with pixels checking. Make + * the window appear on top of a known background. Repeat this for JWindow, + * JDialog, JFrame. + * Expected Result: If PERPIXEL_TRANSLUCENT, TRANSLUCENT and PERPIXEL_TRANSPARENT + * translucency types are supported, the window should appear as specified + * with the expected shape and translucency. Window background should have + * translucent gradient in parts that are not clipped by shape, all the + * controls should be equally translucent. + * @author mrkam + * @library ../../../../lib/testlibrary + * @build Common ExtendedRobot + * @run main ShapedTranslucentPerPixelTranslucentGradient + */ + +public class ShapedTranslucentPerPixelTranslucentGradient extends Common { + + public static void main(String[] ignored) throws Exception { + if (checkTranslucencyMode(GraphicsDevice.WindowTranslucency.PERPIXEL_TRANSLUCENT) + && checkTranslucencyMode(GraphicsDevice.WindowTranslucency.PERPIXEL_TRANSPARENT) + && checkTranslucencyMode(GraphicsDevice.WindowTranslucency.TRANSLUCENT)) + for (Class windowClass: WINDOWS_TO_TEST) + new ShapedTranslucentPerPixelTranslucentGradient(windowClass).doTest(); + } + + public ShapedTranslucentPerPixelTranslucentGradient(Class windowClass) throws Exception { + super(windowClass, 0.7f, 0f, true); + } + + public void doTest() throws Exception { + robot.waitForIdle(delay); + checkDynamic(); + } + + @Override + public void applyShape() { + applyDynamicShape(); + gradientWidth = window.getWidth(); + gradientHeight = window.getHeight(); + } +} diff --git a/jdk/test/javax/swing/JWindow/ShapedAndTranslucentWindows/TranslucentJComboBox.java b/jdk/test/javax/swing/JWindow/ShapedAndTranslucentWindows/TranslucentJComboBox.java new file mode 100644 index 00000000000..c9aa638ba97 --- /dev/null +++ b/jdk/test/javax/swing/JWindow/ShapedAndTranslucentWindows/TranslucentJComboBox.java @@ -0,0 +1,152 @@ +/* + * Copyright (c) 2010, 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import javax.swing.*; +import java.awt.*; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; + +/* + * @test + * @bug 8024627 + * @summary Check if a JComboBox present in a window set with opacity less than + * 1.0 shows a translucent drop down + * Test Description: Check if TRANSLUCENT translucency type is supported on the + * current platform. Proceed if supported. Show a window which contains an + * JComboBox and set with opacity less than 1.0. Another Window having a canvas + * component drawn with an image can be used as the background for the test + * window. Click on the ComboBox to show the drop down. Check if the drop down + * appears translucent. Repeat this for JWindow, JDialog and JFrame + * Expected Result: If TRANSLUCENT Translucency type is supported, the drop down + * should appear translucent. + * @author mrkam + * @library ../../../../lib/testlibrary + * @build Common ExtendedRobot + * @run main TranslucentJComboBox + */ + +public class TranslucentJComboBox extends Common { + + JComponent south; + JComponent center; + JPanel north; + volatile boolean southClicked = false; + + public static void main(String[] args) throws Exception { + if (checkTranslucencyMode(GraphicsDevice.WindowTranslucency.TRANSLUCENT)) + for (Class windowClass: WINDOWS_TO_TEST) + new TranslucentJComboBox(windowClass).doTest(); + } + + public TranslucentJComboBox(Class windowClass) throws Exception { + super(windowClass, 0.3f, 1.0f, false); + } + + @Override + public void initBackgroundFrame() { + super.initBackgroundFrame(); + } + + @Override + public void createSwingComponents() { + Container contentPane = RootPaneContainer.class.cast(window).getContentPane(); + window.setLayout(new BorderLayout()); + + north = new JPanel(); + contentPane.add(north, BorderLayout.NORTH); + + center = new JList(new String [] { "Center" }); + contentPane.add(center, BorderLayout.CENTER); + + JComboBox jComboBox = new JComboBox(); + for(int i = 0; i < 20; i++) { + jComboBox.addItem("item " + i); + } + south = jComboBox; + + south.addMouseListener(new MouseAdapter() { + @Override + public void mouseClicked(MouseEvent e) { + southClicked = true; + } + }); + contentPane.add(south, BorderLayout.SOUTH); + } + + + @Override + public void doTest() throws Exception { + robot.waitForIdle(delay); + // Make window an active + Point ls = north.getLocationOnScreen(); + robot.mouseMove(ls.x + north.getWidth()/2, ls.y + north.getHeight()/2); + robot.click(); + + // Invoke list + ls = south.getLocationOnScreen(); + + Point p1 = new Point( + (int) (ls.x + south.getWidth() * 0.75), + ls.y + south.getHeight() * 3); + + Point p2 = new Point( + (int) (ls.x + south.getWidth() * 0.75), + ls.y - south.getHeight() * 2); + + Color c1 = robot.getPixelColor(p1.x, p1.y); + Color c2 = robot.getPixelColor(p2.x, p2.y); + + int x = ls.x + south.getWidth()/2; + int y = ls.y + south.getHeight()/2; + + System.out.println("Trying to click point "+x+", "+y+ + ", looking for flag to trigger."); + + robot.mouseMove(x, y); + robot.waitForIdle(delay); + robot.click(); + robot.waitForIdle(delay); + + if (!southClicked) + throw new RuntimeException("Flag is not triggered for point "+x+", "+y+"!"); + + robot.waitForIdle(); + + Color c1b = robot.getPixelColor(p1.x, p1.y); + Color c2b = robot.getPixelColor(p2.x, p2.y); + + if (!c1.equals(c1b) && !south.getBackground().equals(c1b)) + throw new RuntimeException( + "Check for opaque drop down failed at point " + p1 + + ". Before click: " + c1 + ", after click: " + c1b + + ", expected is " + south.getBackground()); + + if (!c2.equals(c2b) && !south.getBackground().equals(c2b)) + throw new RuntimeException( + "Check for opaque drop down failed at point " + p2 + + ". Before click: " + c2 + ", after click: " + c2b + + ", expected is " + south.getBackground()); + + EventQueue.invokeAndWait(this::dispose); + } +} diff --git a/jdk/test/javax/swing/JWindow/ShapedAndTranslucentWindows/TranslucentPerPixelTranslucentGradient.java b/jdk/test/javax/swing/JWindow/ShapedAndTranslucentWindows/TranslucentPerPixelTranslucentGradient.java new file mode 100644 index 00000000000..3c406430142 --- /dev/null +++ b/jdk/test/javax/swing/JWindow/ShapedAndTranslucentWindows/TranslucentPerPixelTranslucentGradient.java @@ -0,0 +1,72 @@ +/* + * Copyright (c) 2010, 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.awt.*; + +/* + * @test + * @summary Check if a per-pixel translucent and translucent window is dragged + * and resized by mouse correctly + * Test Description: Check if PERPIXEL_TRANSLUCENT and TRANSLUCENT translucency + * types are supported on the current platform. Proceed if they are supported. + * Create a window with some components in it, make window undecorated, apply + * opacity of 0.7, apply translucent background of 0 and have a gradient + * painted as background from fully-transparent to fully-opaque in + * componentResized listener. Drag and resize the window using AWT Robot and + * verify that translucency is correctly applied with pixels checking. Make + * the window appear on top of a known background. Repeat this for specified + * JWindow, JDialog, JFrame. + * Expected Result: If PERPIXEL_TRANSLUCENT and TRANSLUCENT translucency types + * are supported, the window should appear as specified with the translucency. + * Both window background and all the controls should be translucent but + * background should have a gradient in translucency while controls - not. + * @author mrkam + * @library ../../../../lib/testlibrary + * @build Common ExtendedRobot + * @run main TranslucentPerPixelTranslucentGradient + */ + +public class TranslucentPerPixelTranslucentGradient extends Common { + + public static void main(String[] ignored) throws Exception { + if (checkTranslucencyMode(GraphicsDevice.WindowTranslucency.PERPIXEL_TRANSLUCENT) + && checkTranslucencyMode(GraphicsDevice.WindowTranslucency.TRANSLUCENT)) + for (Class windowClass: WINDOWS_TO_TEST) + new TranslucentPerPixelTranslucentGradient(windowClass).doTest(); + } + + public TranslucentPerPixelTranslucentGradient(Class windowClass) throws Exception { + super(windowClass, 0.7f, 0f, true); + } + + public void doTest() throws Exception { + robot.waitForIdle(delay); + checkTranslucent(); + } + + @Override + public void applyShape() { + gradientWidth = window.getWidth(); + gradientHeight = window.getHeight(); + } +} diff --git a/jdk/test/javax/swing/JWindow/ShapedAndTranslucentWindows/TranslucentWindowClickSwing.java b/jdk/test/javax/swing/JWindow/ShapedAndTranslucentWindows/TranslucentWindowClickSwing.java new file mode 100644 index 00000000000..1ee3ff808d4 --- /dev/null +++ b/jdk/test/javax/swing/JWindow/ShapedAndTranslucentWindows/TranslucentWindowClickSwing.java @@ -0,0 +1,105 @@ +/* + * Copyright (c) 2010, 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import javax.swing.*; +import java.awt.*; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; + +/* + * @test + * @summary Check if swing components present in a window set with opacity less + * than 1.0 appears translucent + * Test Description: Check if TRANSLUCENT Translucency type is supported for the + * current platform. Proceed if supported. Show a window containing some swing + * components and set it with opacity less than 1.0. Check if the swing components + * appear translucent and check if events trigger correctly for the components + * Expected Result: If TRANSLUCENT Translucency type is supported, the components + * should appear translucent showing the background. They should trigger events + * correctly + * @author mrkam + * @library ../../../../lib/testlibrary + * @build Common ExtendedRobot + * @run main TranslucentWindowClickSwing + */ + +public class TranslucentWindowClickSwing extends Common { + + private Component south; + private Component center; + private Component north; + + public static void main(String[] args) throws Exception{ + if (checkTranslucencyMode(GraphicsDevice.WindowTranslucency.TRANSLUCENT)) + new TranslucentWindowClickSwing(JWindow.class).doTest(); + } + + public TranslucentWindowClickSwing(Class windowClass) throws Exception { + super(windowClass, 0.2f, 1.0f, false); + } + + @Override + public void createSwingComponents() { + south = new JButton("South"); + south.addMouseListener(new MouseAdapter() { + @Override + public void mouseClicked(MouseEvent e) { clicked |= 1 << 2; } + }); + window.add(south, BorderLayout.SOUTH); + + center = new JList(); + center.addMouseListener(new MouseAdapter() { + @Override + public void mouseClicked(MouseEvent e) { clicked |= 1 << 1; } + }); + window.add(center, BorderLayout.CENTER); + + north = new JTextField("North"); + north.addMouseListener(new MouseAdapter() { + @Override + public void mouseClicked(MouseEvent e) { clicked |= 1 << 0; } + }); + window.add(north, BorderLayout.NORTH); + } + + @Override + public void doTest() throws Exception { + Point ls; + robot.waitForIdle(); + + ls = north.getLocationOnScreen(); + checkClick(ls.x + north.getWidth() / 3, ls.y + north.getHeight() / 2, 0); + + ls = center.getLocationOnScreen(); + checkClick(ls.x + center.getWidth() / 4, ls.y + center.getHeight() / 4, 1); + + ls = center.getLocationOnScreen(); + checkClick(ls.x + center.getWidth() * 3 / 4, ls.y + center.getHeight() * 3 / 4, 1); + + ls = south.getLocationOnScreen(); + checkClick(ls.x + south.getWidth() * 2 / 3, ls.y + south.getHeight() / 2, 2); + + EventQueue.invokeAndWait(this::dispose); + robot.waitForIdle(); + } +} From 305fd1b6c424448f90869b654400be4defe05359 Mon Sep 17 00:00:00 2001 From: Andrew Brygin Date: Tue, 26 Aug 2014 14:10:10 +0100 Subject: [PATCH 12/81] 8040617: [macosx] Large JTable cell results in a OutOfMemoryException Reviewed-by: serb, prr --- .../java2d/opengl/OGLSurfaceDataProxy.java | 6 +- .../sun/java2d/OpenGL/DrawHugeImageTest.java | 108 ++++++++++++++++++ 2 files changed, 113 insertions(+), 1 deletion(-) create mode 100644 jdk/test/sun/java2d/OpenGL/DrawHugeImageTest.java diff --git a/jdk/src/java.desktop/share/classes/sun/java2d/opengl/OGLSurfaceDataProxy.java b/jdk/src/java.desktop/share/classes/sun/java2d/opengl/OGLSurfaceDataProxy.java index d0718cb1246..0cfd0b0c282 100644 --- a/jdk/src/java.desktop/share/classes/sun/java2d/opengl/OGLSurfaceDataProxy.java +++ b/jdk/src/java.desktop/share/classes/sun/java2d/opengl/OGLSurfaceDataProxy.java @@ -65,7 +65,11 @@ public class OGLSurfaceDataProxy extends SurfaceDataProxy { int w, int h) { if (cachedData == null) { - cachedData = oglgc.createManagedSurface(w, h, transparency); + try { + cachedData = oglgc.createManagedSurface(w, h, transparency); + } catch (OutOfMemoryError er) { + return null; + } } return cachedData; } diff --git a/jdk/test/sun/java2d/OpenGL/DrawHugeImageTest.java b/jdk/test/sun/java2d/OpenGL/DrawHugeImageTest.java new file mode 100644 index 00000000000..f43568278f9 --- /dev/null +++ b/jdk/test/sun/java2d/OpenGL/DrawHugeImageTest.java @@ -0,0 +1,108 @@ +/* + * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +/* + * @test + * @bug 8040617 + * @summary Test verifies that an attempt to get an accelerated copy of + * a huge buffered image does not result in an OOME. + * + * @run main DrawHugeImageTest + */ + +import java.awt.Color; +import java.awt.Graphics2D; +import java.awt.GraphicsConfiguration; +import java.awt.GraphicsEnvironment; +import java.awt.image.BufferedImage; +import java.awt.image.VolatileImage; + +public class DrawHugeImageTest { + // we have to render the BI source several times in order + // to get an accelerated copy to be used. + static { + System.setProperty("sun.java2d.accthreshold", "1"); + } + private static final int max_rendering_count = 5; + + private static final Color srcColor = Color.red; + private static final Color dstColor = Color.blue; + + public static void main(String[] args) { + BufferedImage src = createSrc(); + + VolatileImage dst = createDst(); + System.out.println("Dst: " + dst); + boolean status; + int count = max_rendering_count; + + do { + System.out.println("render image: " + (max_rendering_count - count)); + status = render(src, dst); + + } while (status && count-- > 0); + + if (!status || count > 0) { + throw new RuntimeException("Test failed: " + count); + } + } + + private static boolean render(BufferedImage src, VolatileImage dst) { + int cnt = 5; + do { + Graphics2D g = dst.createGraphics(); + g.setColor(dstColor); + g.fillRect(0, 0, dst.getWidth(), dst.getHeight()); + g.drawImage(src, 0, 0, null); + g.dispose(); + } while (dst.contentsLost() && (--cnt > 0)); + + if (cnt == 0) { + System.err.println("Test failed: unable to render to volatile destination"); + return false; + } + + BufferedImage s = dst.getSnapshot(); + + return s.getRGB(1,1) == srcColor.getRGB(); + } + + private static BufferedImage createSrc() { + final int w = 20000; + final int h = 5; + + BufferedImage img = new BufferedImage(w, h, BufferedImage.TYPE_3BYTE_BGR); + Graphics2D g = img.createGraphics(); + g.setColor(srcColor); + g.fillRect(0, 0, w, h); + g.dispose(); + + return img; + } + + private static VolatileImage createDst() { + GraphicsConfiguration gc = + GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice().getDefaultConfiguration(); + + return gc.createCompatibleVolatileImage(200, 200); + } +} From e185c7ed20570c1c915e018583f73c758e0c0482 Mon Sep 17 00:00:00 2001 From: Clemens Eisserer Date: Wed, 27 Aug 2014 08:29:39 -0700 Subject: [PATCH 13/81] 8054638: xrender: text drawn after setColor(Color.white) is actually black Reviewed-by: bae, prr --- .../classes/sun/java2d/xr/XRSolidSrcPict.java | 6 +- .../awt/Graphics2D/WhiteTextColorTest.java | 76 +++++++++++++++++++ 2 files changed, 80 insertions(+), 2 deletions(-) create mode 100644 jdk/test/java/awt/Graphics2D/WhiteTextColorTest.java diff --git a/jdk/src/java.desktop/unix/classes/sun/java2d/xr/XRSolidSrcPict.java b/jdk/src/java.desktop/unix/classes/sun/java2d/xr/XRSolidSrcPict.java index 9d95769b8a4..f9997489796 100644 --- a/jdk/src/java.desktop/unix/classes/sun/java2d/xr/XRSolidSrcPict.java +++ b/jdk/src/java.desktop/unix/classes/sun/java2d/xr/XRSolidSrcPict.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2014 Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -31,12 +31,14 @@ public class XRSolidSrcPict { XRSurfaceData srcPict; XRColor xrCol; - int curPixVal = -1; + int curPixVal; public XRSolidSrcPict(XRBackend con, int parentXid) { this.con = con; xrCol = new XRColor(); + curPixVal = 0xFF000000; + int solidPixmap = con.createPixmap(parentXid, 32, 1, 1); int solidSrcPictXID = con.createPicture(solidPixmap, XRUtils.PictStandardARGB32); con.setPictureRepeat(solidSrcPictXID, XRUtils.RepeatNormal); diff --git a/jdk/test/java/awt/Graphics2D/WhiteTextColorTest.java b/jdk/test/java/awt/Graphics2D/WhiteTextColorTest.java new file mode 100644 index 00000000000..8c2ddf41a89 --- /dev/null +++ b/jdk/test/java/awt/Graphics2D/WhiteTextColorTest.java @@ -0,0 +1,76 @@ +/* + * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.awt.*; +import java.awt.image.*; +import javax.swing.*; + +/** + * @test + * @bug 8056009 + * @summary tests whether Graphics.setColor-calls with Color.white are ignored directly + * after pipeline initialization for a certain set of operations. + * @author ceisserer + */ +public class WhiteTextColorTest extends Frame { + public static volatile boolean success = false; + + public WhiteTextColorTest() { + Image dstImg = getGraphicsConfiguration() + .createCompatibleVolatileImage(30, 20); + Graphics g = dstImg.getGraphics(); + + g.setColor(Color.BLACK); + g.fillRect(0, 0, dstImg.getWidth(null), dstImg.getHeight(null)); + g.setColor(Color.WHITE); + g.drawString("Test", 0, 15); + + BufferedImage readBackImg = new BufferedImage(dstImg.getWidth(null), + dstImg.getHeight(null), BufferedImage.TYPE_INT_RGB); + readBackImg.getGraphics().drawImage(dstImg, 0, 0, null); + + for (int x = 0; x < readBackImg.getWidth(); x++) { + for (int y = 0; y < readBackImg.getHeight(); y++) { + int pixel = readBackImg.getRGB(x, y); + + // In case a single white pixel is found, the + // setColor(Color.WHITE) + // call before was not ignored and the bug is not present + if (pixel == 0xFFFFFFFF) { + return; + } + } + } + + throw new RuntimeException("Test Failed"); + } + + public static void main(String[] args) throws Exception { + SwingUtilities.invokeLater(new Runnable() { + public void run() { + new WhiteTextColorTest(); + } + }); + } +} + From 46bde90a2b9a89653564bd41d83607f8c938adfd Mon Sep 17 00:00:00 2001 From: Erik Joelsson Date: Thu, 28 Aug 2014 11:58:49 +0200 Subject: [PATCH 14/81] 8056053: Disable HOTSPOT_BUILD_JOBS when building with configure Reviewed-by: dholmes, ihse, dcubed --- common/autoconf/hotspot-spec.gmk.in | 2 -- make/HotspotWrapper.gmk | 2 +- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/common/autoconf/hotspot-spec.gmk.in b/common/autoconf/hotspot-spec.gmk.in index 057d882c28e..dcd2fd8f360 100644 --- a/common/autoconf/hotspot-spec.gmk.in +++ b/common/autoconf/hotspot-spec.gmk.in @@ -97,8 +97,6 @@ ifeq ($(JVM_INTERPRETER), cpp) endif HOTSPOT_MAKE_ARGS:=@HOTSPOT_MAKE_ARGS@ @STATIC_CXX_SETTING@ -# This is used from the libjvm build for C/C++ code. -HOTSPOT_BUILD_JOBS:=$(JOBS) # Control wether Hotspot runs Queens test after building TEST_IN_BUILD=@TEST_IN_BUILD@ diff --git a/make/HotspotWrapper.gmk b/make/HotspotWrapper.gmk index 51437dfb17b..0677deb0080 100644 --- a/make/HotspotWrapper.gmk +++ b/make/HotspotWrapper.gmk @@ -42,7 +42,7 @@ HOTSPOT_FILES := $(shell $(FIND) -L $(HOTSPOT_TOPDIR) -name ".hg" -prune -o -pri # not doing it breaks builds on msys. $(HOTSPOT_OUTPUTDIR)/_hotspot.timestamp: $(HOTSPOT_FILES) @$(MKDIR) -p $(HOTSPOT_OUTPUTDIR) - @($(CD) $(HOTSPOT_TOPDIR)/make && $(MAKE) -j1 $(HOTSPOT_MAKE_ARGS) SPEC=$(HOTSPOT_SPEC) BASE_SPEC=$(BASE_SPEC)) + @($(CD) $(HOTSPOT_TOPDIR)/make && $(MAKE) $(HOTSPOT_MAKE_ARGS) SPEC=$(HOTSPOT_SPEC) BASE_SPEC=$(BASE_SPEC)) $(TOUCH) $@ hotspot: $(HOTSPOT_OUTPUTDIR)/_hotspot.timestamp From 11492e4215cb14f5ac08bd8e73c4e2939827f9a0 Mon Sep 17 00:00:00 2001 From: Yuri Nesterenko Date: Fri, 29 Aug 2014 14:27:43 +0400 Subject: [PATCH 15/81] 8055664: move 14 tests about setLocationRelativeTo to jdk Reviewed-by: alexsch, azvegint --- .../SetLocationRelativeToTest.java | 293 ++++++++++++++++++ 1 file changed, 293 insertions(+) create mode 100644 jdk/test/java/awt/Window/setLocRelativeTo/SetLocationRelativeToTest.java diff --git a/jdk/test/java/awt/Window/setLocRelativeTo/SetLocationRelativeToTest.java b/jdk/test/java/awt/Window/setLocRelativeTo/SetLocationRelativeToTest.java new file mode 100644 index 00000000000..0cf3cec9066 --- /dev/null +++ b/jdk/test/java/awt/Window/setLocRelativeTo/SetLocationRelativeToTest.java @@ -0,0 +1,293 @@ +/* + * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.awt.*; +import java.util.ArrayList; +import javax.swing.*; + +/* +@test +@summary Toplevel should be correctly positioned as relative to a component: + so that their centers coincide + or, if the component is hidden, centered on the screen. +@bug 8036915 +@library ../../../../lib/testlibrary +@build ExtendedRobot +@run main/timeout=1200 SetLocationRelativeToTest +*/ + +public class SetLocationRelativeToTest { + private static int delay = 500; + private static boolean testEverything = false;// NB: change this to true to test everything + java.util.List awtToplevels = new ArrayList(); + java.util.List swingToplevels = new ArrayList(); + java.util.List allToplevels = new ArrayList(); + java.util.List awtComponents = new ArrayList(); + java.util.List swingComponents = new ArrayList(); + java.util.List allComponents = new ArrayList(); + Label placeholder = new Label(); + JLabel jplaceholder = new JLabel(); + JFrame jcontainer; + public SetLocationRelativeToTest() { + Frame frame = new Frame("Frame"); + frame.setSize(200,100); + Frame uframe = new Frame("U.Frame"); + uframe.setUndecorated(true); + uframe.setSize(200,100); + Window window = new Window(frame); + window.setSize(200,100); + Dialog dialog = new Dialog(frame, "Dialog"); + dialog.setSize(200,100); + awtToplevels.add(frame); + awtToplevels.add(uframe); + awtToplevels.add(window); + awtToplevels.add(dialog); + + awtComponents.add(new TextArea("Am a TextArea")); + awtComponents.add(new TextField("Am a TextField")); + awtComponents.add(new Button("Press")); + awtComponents.add(new Label("Label")); + Choice aChoice = new Choice(); + aChoice.add("One"); + aChoice.add("Two"); + awtComponents.add(aChoice); + awtComponents.add(new Canvas()); + awtComponents.add(new List(4)); + awtComponents.add(new Checkbox("Me CheckBox")); + awtComponents.add(new Scrollbar()); + + swingComponents.add(new JTextArea("Am a JTextArea")); + swingComponents.add(new JTextField("Am a JTextField")); + swingComponents.add(new JButton("Press")); + swingComponents.add(new JLabel("JLabel")); + JComboBox jcombo = new JComboBox(); + swingComponents.add(jcombo); + swingComponents.add(new JPanel()); + swingComponents.add(new JList()); + swingComponents.add(new JCheckBox("Me JCheckBox")); + swingComponents.add(new JScrollBar()); + } + + public static void main(String args[]) { + SetLocationRelativeToTest test = new SetLocationRelativeToTest(); + test.doAWTTest(true); + test.doAWTTest(false); + try { + test.doSwingTest(true); + test.doSwingTest(false); + }catch(InterruptedException ie) { + ie.printStackTrace(); + }catch(java.lang.reflect.InvocationTargetException ite) { + ite.printStackTrace(); + throw new RuntimeException("InvocationTarget?"); + } + return; + } + + // In regular testing, we select just few components to test + // randomly. If full testing required, select many ("all"). + void selectObjectsToTest(boolean doSwing) { + allToplevels.clear(); + allComponents.clear(); + if(testEverything) { + allToplevels.addAll(0, awtToplevels); + allComponents.addAll(0, awtComponents); + if(doSwing) { + allToplevels.addAll(allToplevels.size(), swingToplevels); + allComponents.addAll(allComponents.size(), swingComponents); + } + }else{ + //select a random of each + int i = (int)(java.lang.Math.random()*awtToplevels.size()); + allToplevels.add(awtToplevels.get(i)); + i = (int)(java.lang.Math.random()*awtComponents.size()); + allComponents.add(awtComponents.get(i)); + if(doSwing) { + i = (int)(java.lang.Math.random()*swingToplevels.size()); + allToplevels.add(swingToplevels.get(i)); + i = (int)(java.lang.Math.random()*swingComponents.size()); + allComponents.add(swingComponents.get(i)); + } + } + } + + // create Frame, add an AWT component to it, + // hide it (or not) and position a new toplevel + // relativeTo + void doAWTTest(boolean isHidden) { + boolean res; + ExtendedRobot robot; + try { + robot = new ExtendedRobot(); + }catch(Exception ex) { + ex.printStackTrace(); + throw new RuntimeException("Failed: "+ex.getMessage()); + } + Frame container = new Frame("Frame"); + container.setBounds(100,100,300,300); + container.setLayout(new GridLayout(3,1)); + container.add(placeholder); + container.setVisible(true); + selectObjectsToTest(false); + for(Component c: allComponents) { + placeholder.setText((isHidden ? "Hidden: " : "Below is ")+ c.getClass().getName()); + c.setVisible(true); + container.add(c); + container.doLayout(); + if(isHidden) { + c.setVisible(false); + } + robot.waitForIdle(delay); + for(Window w: allToplevels) { + w.setLocationRelativeTo(c); + w.setVisible(true); + robot.waitForIdle(delay); + res = compareLocations(w, c, robot); + System.out.println(c.getClass().getName()+" \t: "+w.getClass().getName()+ + ((w instanceof Frame) && (((Frame)w).isUndecorated()) ? " undec\t\t:" : "\t\t:")+" "+ + (res ? "" : "Failed")); + if(!res) { + throw new RuntimeException("Test failed."); + } + w.dispose(); + } + container.remove(c); + robot.waitForIdle(delay); + } + container.dispose(); + } + + // Create JFrame, add an AWT or Swing component to it, + // hide it (or not) and position a new toplevel + // relativeTo + void doSwingTest(boolean isHidden) throws InterruptedException, + java.lang.reflect.InvocationTargetException { + boolean res; + ExtendedRobot robot; + try { + robot = new ExtendedRobot(); + }catch(Exception ex) { + ex.printStackTrace(); + throw new RuntimeException("Failed: "+ex.getMessage()); + } + + EventQueue.invokeAndWait( () -> { + JFrame jframe = new JFrame("jframe"); + jframe.setSize(200,100); + swingToplevels.add(jframe); + JFrame ujframe = new JFrame("ujframe"); + ujframe.setSize(200,100); + ujframe.setUndecorated(true); + swingToplevels.add(ujframe); + JWindow jwin = new JWindow(); + jwin.setSize(200,100); + swingToplevels.add(jwin); + JDialog jdia = new JDialog((Frame)null, "JDialog"); + jdia.setSize(200,100); + swingToplevels.add(jdia); + jcontainer = new JFrame("JFrame"); + jcontainer.setBounds(100,100,300,300); + jcontainer.setLayout(new GridLayout(3,1)); + jcontainer.add(jplaceholder); + jcontainer.setVisible(true); + selectObjectsToTest(true); + }); + robot.waitForIdle(delay); + + for(Component c: allComponents) { + EventQueue.invokeAndWait( () -> { + jplaceholder.setText((isHidden ? "Hidden: " : "Below is: ")+ c.getClass().getName()); + c.setVisible(true); + jcontainer.add(c); + jcontainer.doLayout(); + if(isHidden) { + c.setVisible(false); + } + }); + robot.waitForIdle(delay); + for(Window w: allToplevels) { + EventQueue.invokeAndWait( () -> { + w.setLocationRelativeTo(c); + w.setVisible(true); + }); + robot.waitForIdle(delay); + res = compareLocations(w, c, robot); + System.out.println(c.getClass().getName()+" \t: "+w.getClass().getName()+ + ((w instanceof Frame) && (((Frame)w).isUndecorated()) ? " undec\t\t:" : "\t\t:")+" "+ + (res ? "" : "Failed")); + EventQueue.invokeAndWait( () -> { + w.dispose(); + }); + robot.waitForIdle(); + if(!res) { + throw new RuntimeException("Test failed."); + } + } + EventQueue.invokeAndWait( () -> { + jcontainer.remove(c); + }); + robot.waitForIdle(delay); + } + EventQueue.invokeAndWait( () -> { + jcontainer.dispose(); + }); + } + + // Check, finally, if w either is concentric with c + // or sits in the center of the screen (if c is hidden) + boolean compareLocations(final Window w, final Component c, ExtendedRobot robot) { + final Point pc = new Point(); + final Point pw = new Point(); + try { + EventQueue.invokeAndWait( () -> { + pw.setLocation(w.getLocationOnScreen()); + pw.translate(w.getWidth()/2, w.getHeight()/2); + if(!c.isVisible()) { + Rectangle screenRect = w.getGraphicsConfiguration().getBounds(); + pc.setLocation(screenRect.x+screenRect.width/2, + screenRect.y+screenRect.height/2); + }else{ + pc.setLocation(c.getLocationOnScreen()); + pc.translate(c.getWidth()/2, c.getHeight()/2); + } + }); + } catch(InterruptedException ie) { + throw new RuntimeException("Interrupted"); + } catch(java.lang.reflect.InvocationTargetException ite) { + ite.printStackTrace(); + throw new RuntimeException("InvocationTarget?"); + } + robot.waitForIdle(delay); + // Compare with 1 tolerance to forgive possible rounding errors + if(pc.x - pw.x > 1 || + pc.x - pw.x < -1 || + pc.y - pw.y > 1 || + pc.y - pw.y < -1 ) { + System.out.println("Center of "+(c.isVisible() ? "Component:" : "screen:")+pc); + System.out.println("Center of Window:"+pw); + System.out.println("Centers of "+w+" and "+c+" do not coincide"); + return false; + } + return true; + } +} From e4ff32f580a2b0637d7f48b53d0ebb2028e808bf Mon Sep 17 00:00:00 2001 From: Alex Henrie Date: Fri, 29 Aug 2014 15:27:29 +0400 Subject: [PATCH 16/81] 6624085: Fourth mouse button (wheel) is treated like second button - isPopupTrigger returns true Reviewed-by: anthony, azvegint --- .../unix/classes/sun/awt/X11/XWindow.java | 24 +------------------ 1 file changed, 1 insertion(+), 23 deletions(-) diff --git a/jdk/src/java.desktop/unix/classes/sun/awt/X11/XWindow.java b/jdk/src/java.desktop/unix/classes/sun/awt/X11/XWindow.java index 49384a9e54e..9bb7c3cc2fb 100644 --- a/jdk/src/java.desktop/unix/classes/sun/awt/X11/XWindow.java +++ b/jdk/src/java.desktop/unix/classes/sun/awt/X11/XWindow.java @@ -55,7 +55,6 @@ class XWindow extends XBaseWindow implements X11ComponentPeer { */ private final static int AWT_MULTICLICK_SMUDGE = 4; // ButtonXXX events stuff - static int rbutton = 0; static int lastX = 0, lastY = 0; static long lastTime = 0; static long lastButton = 0; @@ -632,23 +631,6 @@ class XWindow extends XBaseWindow implements X11ComponentPeer { return res; } - /** - * Returns true if this event is disabled and shouldn't be passed to Java. - * Default implementation returns false for all events. - */ - static int getRightButtonNumber() { - if (rbutton == 0) { // not initialized yet - XToolkit.awtLock(); - try { - rbutton = XlibWrapper.XGetPointerMapping(XToolkit.getDisplay(), XlibWrapper.ibuffer, 3); - } - finally { - XToolkit.awtUnlock(); - } - } - return rbutton; - } - static int getMouseMovementSmudge() { //TODO: It's possible to read corresponding settings return AWT_MULTICLICK_SMUDGE; @@ -716,11 +698,7 @@ class XWindow extends XBaseWindow implements X11ComponentPeer { /* Check for popup trigger !! */ - if (lbutton == getRightButtonNumber() || lbutton > 2) { - popupTrigger = true; - } else { - popupTrigger = false; - } + popupTrigger = (lbutton == 3); } button = XConstants.buttons[lbutton - 1]; From 1a77a29985c5c71c02cb773669642b77372b5eed Mon Sep 17 00:00:00 2001 From: Alexander Zvegintsev Date: Tue, 2 Sep 2014 17:35:58 +0400 Subject: [PATCH 17/81] 8055746: plenty of clipboard/dnd tests fail and break X11 Reviewed-by: alexsch, pchelko --- .../datatransfer => datatransfer/resources}/flavormap.properties | 0 .../datatransfer => datatransfer/resources}/flavormap.properties | 0 .../datatransfer => datatransfer/resources}/flavormap.properties | 0 3 files changed, 0 insertions(+), 0 deletions(-) rename jdk/src/java.desktop/macosx/classes/sun/{awt/datatransfer => datatransfer/resources}/flavormap.properties (100%) rename jdk/src/java.desktop/unix/classes/sun/{awt/datatransfer => datatransfer/resources}/flavormap.properties (100%) rename jdk/src/java.desktop/windows/classes/sun/{awt/datatransfer => datatransfer/resources}/flavormap.properties (100%) diff --git a/jdk/src/java.desktop/macosx/classes/sun/awt/datatransfer/flavormap.properties b/jdk/src/java.desktop/macosx/classes/sun/datatransfer/resources/flavormap.properties similarity index 100% rename from jdk/src/java.desktop/macosx/classes/sun/awt/datatransfer/flavormap.properties rename to jdk/src/java.desktop/macosx/classes/sun/datatransfer/resources/flavormap.properties diff --git a/jdk/src/java.desktop/unix/classes/sun/awt/datatransfer/flavormap.properties b/jdk/src/java.desktop/unix/classes/sun/datatransfer/resources/flavormap.properties similarity index 100% rename from jdk/src/java.desktop/unix/classes/sun/awt/datatransfer/flavormap.properties rename to jdk/src/java.desktop/unix/classes/sun/datatransfer/resources/flavormap.properties diff --git a/jdk/src/java.desktop/windows/classes/sun/awt/datatransfer/flavormap.properties b/jdk/src/java.desktop/windows/classes/sun/datatransfer/resources/flavormap.properties similarity index 100% rename from jdk/src/java.desktop/windows/classes/sun/awt/datatransfer/flavormap.properties rename to jdk/src/java.desktop/windows/classes/sun/datatransfer/resources/flavormap.properties From 127abcdf4d773630fe3702910ac0b56270455775 Mon Sep 17 00:00:00 2001 From: Alexey Ivanov Date: Tue, 2 Sep 2014 17:42:35 +0400 Subject: [PATCH 18/81] 8056211: api/java_awt/Event/InputMethodEvent/serial/index.html#Input[serial2002] failure Reviewed-by: pchelko, alexsch --- .../share/classes/java/awt/event/InputMethodEvent.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/jdk/src/java.desktop/share/classes/java/awt/event/InputMethodEvent.java b/jdk/src/java.desktop/share/classes/java/awt/event/InputMethodEvent.java index ca214ed6e45..e1ec9abbcf5 100644 --- a/jdk/src/java.desktop/share/classes/java/awt/event/InputMethodEvent.java +++ b/jdk/src/java.desktop/share/classes/java/awt/event/InputMethodEvent.java @@ -418,7 +418,8 @@ public class InputMethodEvent extends AWTEvent { private void readObject(ObjectInputStream s) throws ClassNotFoundException, IOException { s.defaultReadObject(); if (when == 0) { - when = getMostRecentEventTimeForSource(this.source); + // Can't use getMostRecentEventTimeForSource because source is always null during deserialization + when = EventQueue.getMostRecentEventTime(); } } From 692cce9567eafa5d58843edb18117ca972ff1a0c Mon Sep 17 00:00:00 2001 From: Phil Race Date: Thu, 4 Sep 2014 09:32:08 -0700 Subject: [PATCH 19/81] 8056122: Upgrade JDK to use LittleCMS 2.6 Reviewed-by: bae, jgodinez --- .../share/native/liblcms/cmscam02.c | 7 +- .../share/native/liblcms/cmscgats.c | 6 +- .../share/native/liblcms/cmscnvrt.c | 106 ++++- .../share/native/liblcms/cmserr.c | 322 +++++++++++-- .../share/native/liblcms/cmsgamma.c | 95 +++- .../share/native/liblcms/cmsgmt.c | 2 +- .../share/native/liblcms/cmsintrp.c | 43 +- .../share/native/liblcms/cmsio0.c | 273 +++++++---- .../share/native/liblcms/cmsio1.c | 154 +++--- .../share/native/liblcms/cmsopt.c | 97 +++- .../share/native/liblcms/cmspack.c | 147 +++++- .../share/native/liblcms/cmsplugin.c | 385 +++++++++++++-- .../share/native/liblcms/cmsps2.c | 4 +- .../share/native/liblcms/cmstypes.c | 265 ++++++++--- .../share/native/liblcms/cmsvirt.c | 8 +- .../share/native/liblcms/cmswtpnt.c | 2 +- .../share/native/liblcms/cmsxform.c | 266 +++++++++-- .../java.desktop/share/native/liblcms/lcms2.h | 92 +++- .../share/native/liblcms/lcms2_internal.h | 441 +++++++++++++++++- .../share/native/liblcms/lcms2_plugin.h | 45 +- 20 files changed, 2292 insertions(+), 468 deletions(-) diff --git a/jdk/src/java.desktop/share/native/liblcms/cmscam02.c b/jdk/src/java.desktop/share/native/liblcms/cmscam02.c index 38d164ad3cf..86ec167cd95 100644 --- a/jdk/src/java.desktop/share/native/liblcms/cmscam02.c +++ b/jdk/src/java.desktop/share/native/liblcms/cmscam02.c @@ -467,11 +467,12 @@ void CMSEXPORT cmsCIECAM02Forward(cmsHANDLE hModel, const cmsCIEXYZ* pIn, cmsJCh CAM02COLOR clr; cmsCIECAM02* lpMod = (cmsCIECAM02*) hModel; - memset(&clr, 0, sizeof(clr)); _cmsAssert(lpMod != NULL); _cmsAssert(pIn != NULL); _cmsAssert(pOut != NULL); + memset(&clr, 0, sizeof(clr)); + clr.XYZ[0] = pIn ->X; clr.XYZ[1] = pIn ->Y; clr.XYZ[2] = pIn ->Z; @@ -492,11 +493,12 @@ void CMSEXPORT cmsCIECAM02Reverse(cmsHANDLE hModel, const cmsJCh* pIn, cmsCIEXYZ CAM02COLOR clr; cmsCIECAM02* lpMod = (cmsCIECAM02*) hModel; - memset(&clr, 0, sizeof(clr)); _cmsAssert(lpMod != NULL); _cmsAssert(pIn != NULL); _cmsAssert(pOut != NULL); + memset(&clr, 0, sizeof(clr)); + clr.J = pIn -> J; clr.C = pIn -> C; clr.h = pIn -> h; @@ -511,4 +513,3 @@ void CMSEXPORT cmsCIECAM02Reverse(cmsHANDLE hModel, const cmsJCh* pIn, cmsCIEXYZ pOut ->Y = clr.XYZ[1]; pOut ->Z = clr.XYZ[2]; } - diff --git a/jdk/src/java.desktop/share/native/liblcms/cmscgats.c b/jdk/src/java.desktop/share/native/liblcms/cmscgats.c index 11fe36e6c2c..4610a232f5f 100644 --- a/jdk/src/java.desktop/share/native/liblcms/cmscgats.c +++ b/jdk/src/java.desktop/share/native/liblcms/cmscgats.c @@ -2179,9 +2179,9 @@ void CookPointers(cmsIT8* it8) if (cmsstrcasecmp(Fld, "SAMPLE_ID") == 0) { - t -> SampleID = idField; + t -> SampleID = idField; - for (i=0; i < t -> nPatches; i++) { + for (i=0; i < t -> nPatches; i++) { char *Data = GetData(it8, i, idField); if (Data) { @@ -2196,7 +2196,7 @@ void CookPointers(cmsIT8* it8) SetData(it8, i, idField, Buffer); } - } + } } diff --git a/jdk/src/java.desktop/share/native/liblcms/cmscnvrt.c b/jdk/src/java.desktop/share/native/liblcms/cmscnvrt.c index cea3b8bb424..bc2b0daf5c9 100644 --- a/jdk/src/java.desktop/share/native/liblcms/cmscnvrt.c +++ b/jdk/src/java.desktop/share/native/liblcms/cmscnvrt.c @@ -137,15 +137,68 @@ static cmsIntentsList DefaultIntents[] = { // A pointer to the begining of the list -static cmsIntentsList *Intents = DefaultIntents; +_cmsIntentsPluginChunkType _cmsIntentsPluginChunk = { NULL }; + +// Duplicates the zone of memory used by the plug-in in the new context +static +void DupPluginIntentsList(struct _cmsContext_struct* ctx, + const struct _cmsContext_struct* src) +{ + _cmsIntentsPluginChunkType newHead = { NULL }; + cmsIntentsList* entry; + cmsIntentsList* Anterior = NULL; + _cmsIntentsPluginChunkType* head = (_cmsIntentsPluginChunkType*) src->chunks[IntentPlugin]; + + // Walk the list copying all nodes + for (entry = head->Intents; + entry != NULL; + entry = entry ->Next) { + + cmsIntentsList *newEntry = ( cmsIntentsList *) _cmsSubAllocDup(ctx ->MemPool, entry, sizeof(cmsIntentsList)); + + if (newEntry == NULL) + return; + + // We want to keep the linked list order, so this is a little bit tricky + newEntry -> Next = NULL; + if (Anterior) + Anterior -> Next = newEntry; + + Anterior = newEntry; + + if (newHead.Intents == NULL) + newHead.Intents = newEntry; + } + + ctx ->chunks[IntentPlugin] = _cmsSubAllocDup(ctx->MemPool, &newHead, sizeof(_cmsIntentsPluginChunkType)); +} + +void _cmsAllocIntentsPluginChunk(struct _cmsContext_struct* ctx, + const struct _cmsContext_struct* src) +{ + if (src != NULL) { + + // Copy all linked list + DupPluginIntentsList(ctx, src); + } + else { + static _cmsIntentsPluginChunkType IntentsPluginChunkType = { NULL }; + ctx ->chunks[IntentPlugin] = _cmsSubAllocDup(ctx ->MemPool, &IntentsPluginChunkType, sizeof(_cmsIntentsPluginChunkType)); + } +} + // Search the list for a suitable intent. Returns NULL if not found static -cmsIntentsList* SearchIntent(cmsUInt32Number Intent) +cmsIntentsList* SearchIntent(cmsContext ContextID, cmsUInt32Number Intent) { + _cmsIntentsPluginChunkType* ctx = ( _cmsIntentsPluginChunkType*) _cmsContextGetClientChunk(ContextID, IntentPlugin); cmsIntentsList* pt; - for (pt = Intents; pt != NULL; pt = pt -> Next) + for (pt = ctx -> Intents; pt != NULL; pt = pt -> Next) + if (pt ->Intent == Intent) return pt; + + for (pt = DefaultIntents; pt != NULL; pt = pt -> Next) if (pt ->Intent == Intent) return pt; return NULL; @@ -1031,7 +1084,7 @@ cmsPipeline* _cmsLinkProfiles(cmsContext ContextID, // this case would present some issues if the custom intent tries to do things like // preserve primaries. This solution is not perfect, but works well on most cases. - Intent = SearchIntent(TheIntents[0]); + Intent = SearchIntent(ContextID, TheIntents[0]); if (Intent == NULL) { cmsSignalError(ContextID, cmsERROR_UNKNOWN_EXTENSION, "Unsupported intent '%d'", TheIntents[0]); return NULL; @@ -1046,12 +1099,14 @@ cmsPipeline* _cmsLinkProfiles(cmsContext ContextID, // Get information about available intents. nMax is the maximum space for the supplied "Codes" // and "Descriptions" the function returns the total number of intents, which may be greater // than nMax, although the matrices are not populated beyond this level. -cmsUInt32Number CMSEXPORT cmsGetSupportedIntents(cmsUInt32Number nMax, cmsUInt32Number* Codes, char** Descriptions) +cmsUInt32Number CMSEXPORT cmsGetSupportedIntentsTHR(cmsContext ContextID, cmsUInt32Number nMax, cmsUInt32Number* Codes, char** Descriptions) { + _cmsIntentsPluginChunkType* ctx = ( _cmsIntentsPluginChunkType*) _cmsContextGetClientChunk(ContextID, IntentPlugin); cmsIntentsList* pt; cmsUInt32Number nIntents; - for (nIntents=0, pt = Intents; pt != NULL; pt = pt -> Next) + + for (nIntents=0, pt = ctx->Intents; pt != NULL; pt = pt -> Next) { if (nIntents < nMax) { if (Codes != NULL) @@ -1064,37 +1119,52 @@ cmsUInt32Number CMSEXPORT cmsGetSupportedIntents(cmsUInt32Number nMax, cmsUInt32 nIntents++; } + for (nIntents=0, pt = DefaultIntents; pt != NULL; pt = pt -> Next) + { + if (nIntents < nMax) { + if (Codes != NULL) + Codes[nIntents] = pt ->Intent; + + if (Descriptions != NULL) + Descriptions[nIntents] = pt ->Description; + } + + nIntents++; + } return nIntents; } +cmsUInt32Number CMSEXPORT cmsGetSupportedIntents(cmsUInt32Number nMax, cmsUInt32Number* Codes, char** Descriptions) +{ + return cmsGetSupportedIntentsTHR(NULL, nMax, Codes, Descriptions); +} + // The plug-in registration. User can add new intents or override default routines cmsBool _cmsRegisterRenderingIntentPlugin(cmsContext id, cmsPluginBase* Data) { + _cmsIntentsPluginChunkType* ctx = ( _cmsIntentsPluginChunkType*) _cmsContextGetClientChunk(id, IntentPlugin); cmsPluginRenderingIntent* Plugin = (cmsPluginRenderingIntent*) Data; cmsIntentsList* fl; - // Do we have to reset the intents? + // Do we have to reset the custom intents? if (Data == NULL) { - Intents = DefaultIntents; - return TRUE; + ctx->Intents = NULL; + return TRUE; } - fl = SearchIntent(Plugin ->Intent); + fl = (cmsIntentsList*) _cmsPluginMalloc(id, sizeof(cmsIntentsList)); + if (fl == NULL) return FALSE; - if (fl == NULL) { - fl = (cmsIntentsList*) _cmsPluginMalloc(id, sizeof(cmsIntentsList)); - if (fl == NULL) return FALSE; - } fl ->Intent = Plugin ->Intent; - strncpy(fl ->Description, Plugin ->Description, 255); - fl ->Description[255] = 0; + strncpy(fl ->Description, Plugin ->Description, sizeof(fl ->Description)-1); + fl ->Description[sizeof(fl ->Description)-1] = 0; fl ->Link = Plugin ->Link; - fl ->Next = Intents; - Intents = fl; + fl ->Next = ctx ->Intents; + ctx ->Intents = fl; return TRUE; } diff --git a/jdk/src/java.desktop/share/native/liblcms/cmserr.c b/jdk/src/java.desktop/share/native/liblcms/cmserr.c index bf1e2606324..306d036fc61 100644 --- a/jdk/src/java.desktop/share/native/liblcms/cmserr.c +++ b/jdk/src/java.desktop/share/native/liblcms/cmserr.c @@ -60,13 +60,14 @@ // compare two strings ignoring case int CMSEXPORT cmsstrcasecmp(const char* s1, const char* s2) { - register const unsigned char *us1 = (const unsigned char *)s1, - *us2 = (const unsigned char *)s2; + register const unsigned char *us1 = (const unsigned char *)s1, + *us2 = (const unsigned char *)s2; - while (toupper(*us1) == toupper(*us2++)) - if (*us1++ == '\0') - return (0); - return (toupper(*us1) - toupper(*--us2)); + while (toupper(*us1) == toupper(*us2++)) + if (*us1++ == '\0') + return 0; + + return (toupper(*us1) - toupper(*--us2)); } // long int because C99 specifies ftell in such way (7.19.9.2) @@ -91,9 +92,8 @@ long int CMSEXPORT cmsfilelength(FILE* f) // // This is the interface to low-level memory management routines. By default a simple // wrapping to malloc/free/realloc is provided, although there is a limit on the max -// amount of memoy that can be reclaimed. This is mostly as a safety feature to -// prevent bogus or malintentionated code to allocate huge blocks that otherwise lcms -// would never need. +// amount of memoy that can be reclaimed. This is mostly as a safety feature to prevent +// bogus or evil code to allocate huge blocks that otherwise lcms would never need. #define MAX_MEMORY_FOR_ALLOC ((cmsUInt32Number)(1024U*1024U*512U)) @@ -103,7 +103,7 @@ long int CMSEXPORT cmsfilelength(FILE* f) // required to be implemented: malloc, realloc and free, although the user may want to // replace the optional mallocZero, calloc and dup as well. -cmsBool _cmsRegisterMemHandlerPlugin(cmsPluginBase* Plugin); +cmsBool _cmsRegisterMemHandlerPlugin(cmsContext ContextID, cmsPluginBase* Plugin); // ********************************************************************************* @@ -143,7 +143,7 @@ void _cmsFreeDefaultFn(cmsContext ContextID, void *Ptr) cmsUNUSED_PARAMETER(ContextID); } -// The default realloc function. Again it check for exploits. If Ptr is NULL, +// The default realloc function. Again it checks for exploits. If Ptr is NULL, // realloc behaves the same way as malloc and allocates a new block of size bytes. static void* _cmsReallocDefaultFn(cmsContext ContextID, void* Ptr, cmsUInt32Number size) @@ -196,28 +196,73 @@ void* _cmsDupDefaultFn(cmsContext ContextID, const void* Org, cmsUInt32Number si return mem; } -// Pointers to malloc and _cmsFree functions in current environment -static void * (* MallocPtr)(cmsContext ContextID, cmsUInt32Number size) = _cmsMallocDefaultFn; -static void * (* MallocZeroPtr)(cmsContext ContextID, cmsUInt32Number size) = _cmsMallocZeroDefaultFn; -static void (* FreePtr)(cmsContext ContextID, void *Ptr) = _cmsFreeDefaultFn; -static void * (* ReallocPtr)(cmsContext ContextID, void *Ptr, cmsUInt32Number NewSize) = _cmsReallocDefaultFn; -static void * (* CallocPtr)(cmsContext ContextID, cmsUInt32Number num, cmsUInt32Number size)= _cmsCallocDefaultFn; -static void * (* DupPtr)(cmsContext ContextID, const void* Org, cmsUInt32Number size) = _cmsDupDefaultFn; + +// Pointers to memory manager functions in Context0 +_cmsMemPluginChunkType _cmsMemPluginChunk = { _cmsMallocDefaultFn, _cmsMallocZeroDefaultFn, _cmsFreeDefaultFn, + _cmsReallocDefaultFn, _cmsCallocDefaultFn, _cmsDupDefaultFn + }; + + +// Reset and duplicate memory manager +void _cmsAllocMemPluginChunk(struct _cmsContext_struct* ctx, const struct _cmsContext_struct* src) +{ + _cmsAssert(ctx != NULL); + + if (src != NULL) { + + // Duplicate + ctx ->chunks[MemPlugin] = _cmsSubAllocDup(ctx ->MemPool, src ->chunks[MemPlugin], sizeof(_cmsMemPluginChunkType)); + } + else { + + // To reset it, we use the default allocators, which cannot be overriden + ctx ->chunks[MemPlugin] = &ctx ->DefaultMemoryManager; + } +} + +// Auxiliar to fill memory management functions from plugin (or context 0 defaults) +void _cmsInstallAllocFunctions(cmsPluginMemHandler* Plugin, _cmsMemPluginChunkType* ptr) +{ + if (Plugin == NULL) { + + memcpy(ptr, &_cmsMemPluginChunk, sizeof(_cmsMemPluginChunk)); + } + else { + + ptr ->MallocPtr = Plugin -> MallocPtr; + ptr ->FreePtr = Plugin -> FreePtr; + ptr ->ReallocPtr = Plugin -> ReallocPtr; + + // Make sure we revert to defaults + ptr ->MallocZeroPtr= _cmsMallocZeroDefaultFn; + ptr ->CallocPtr = _cmsCallocDefaultFn; + ptr ->DupPtr = _cmsDupDefaultFn; + + if (Plugin ->MallocZeroPtr != NULL) ptr ->MallocZeroPtr = Plugin -> MallocZeroPtr; + if (Plugin ->CallocPtr != NULL) ptr ->CallocPtr = Plugin -> CallocPtr; + if (Plugin ->DupPtr != NULL) ptr ->DupPtr = Plugin -> DupPtr; + + } +} + // Plug-in replacement entry -cmsBool _cmsRegisterMemHandlerPlugin(cmsPluginBase *Data) +cmsBool _cmsRegisterMemHandlerPlugin(cmsContext ContextID, cmsPluginBase *Data) { cmsPluginMemHandler* Plugin = (cmsPluginMemHandler*) Data; + _cmsMemPluginChunkType* ptr; - // NULL forces to reset to defaults + // NULL forces to reset to defaults. In this special case, the defaults are stored in the context structure. + // Remaining plug-ins does NOT have any copy in the context structure, but this is somehow special as the + // context internal data should be malloce'd by using those functions. if (Data == NULL) { - MallocPtr = _cmsMallocDefaultFn; - MallocZeroPtr= _cmsMallocZeroDefaultFn; - FreePtr = _cmsFreeDefaultFn; - ReallocPtr = _cmsReallocDefaultFn; - CallocPtr = _cmsCallocDefaultFn; - DupPtr = _cmsDupDefaultFn; + struct _cmsContext_struct* ctx = ( struct _cmsContext_struct*) ContextID; + + // Return to the default allocators + if (ContextID != NULL) { + ctx->chunks[MemPlugin] = (void*) &ctx->DefaultMemoryManager; + } return TRUE; } @@ -227,51 +272,56 @@ cmsBool _cmsRegisterMemHandlerPlugin(cmsPluginBase *Data) Plugin -> ReallocPtr == NULL) return FALSE; // Set replacement functions - MallocPtr = Plugin -> MallocPtr; - FreePtr = Plugin -> FreePtr; - ReallocPtr = Plugin -> ReallocPtr; - - if (Plugin ->MallocZeroPtr != NULL) MallocZeroPtr = Plugin ->MallocZeroPtr; - if (Plugin ->CallocPtr != NULL) CallocPtr = Plugin -> CallocPtr; - if (Plugin ->DupPtr != NULL) DupPtr = Plugin -> DupPtr; + ptr = (_cmsMemPluginChunkType*) _cmsContextGetClientChunk(ContextID, MemPlugin); + if (ptr == NULL) + return FALSE; + _cmsInstallAllocFunctions(Plugin, ptr); return TRUE; } // Generic allocate void* CMSEXPORT _cmsMalloc(cmsContext ContextID, cmsUInt32Number size) { - return MallocPtr(ContextID, size); + _cmsMemPluginChunkType* ptr = (_cmsMemPluginChunkType*) _cmsContextGetClientChunk(ContextID, MemPlugin); + return ptr ->MallocPtr(ContextID, size); } // Generic allocate & zero void* CMSEXPORT _cmsMallocZero(cmsContext ContextID, cmsUInt32Number size) { - return MallocZeroPtr(ContextID, size); + _cmsMemPluginChunkType* ptr = (_cmsMemPluginChunkType*) _cmsContextGetClientChunk(ContextID, MemPlugin); + return ptr->MallocZeroPtr(ContextID, size); } // Generic calloc void* CMSEXPORT _cmsCalloc(cmsContext ContextID, cmsUInt32Number num, cmsUInt32Number size) { - return CallocPtr(ContextID, num, size); + _cmsMemPluginChunkType* ptr = (_cmsMemPluginChunkType*) _cmsContextGetClientChunk(ContextID, MemPlugin); + return ptr->CallocPtr(ContextID, num, size); } // Generic reallocate void* CMSEXPORT _cmsRealloc(cmsContext ContextID, void* Ptr, cmsUInt32Number size) { - return ReallocPtr(ContextID, Ptr, size); + _cmsMemPluginChunkType* ptr = (_cmsMemPluginChunkType*) _cmsContextGetClientChunk(ContextID, MemPlugin); + return ptr->ReallocPtr(ContextID, Ptr, size); } // Generic free memory void CMSEXPORT _cmsFree(cmsContext ContextID, void* Ptr) { - if (Ptr != NULL) FreePtr(ContextID, Ptr); + if (Ptr != NULL) { + _cmsMemPluginChunkType* ptr = (_cmsMemPluginChunkType*) _cmsContextGetClientChunk(ContextID, MemPlugin); + ptr ->FreePtr(ContextID, Ptr); + } } // Generic block duplication void* CMSEXPORT _cmsDupMem(cmsContext ContextID, const void* Org, cmsUInt32Number size) { - return DupPtr(ContextID, Org, size); + _cmsMemPluginChunkType* ptr = (_cmsMemPluginChunkType*) _cmsContextGetClientChunk(ContextID, MemPlugin); + return ptr ->DupPtr(ContextID, Org, size); } // ******************************************************************************************** @@ -380,6 +430,26 @@ void* _cmsSubAlloc(_cmsSubAllocator* sub, cmsUInt32Number size) return (void*) ptr; } +// Duplicate in pool +void* _cmsSubAllocDup(_cmsSubAllocator* s, const void *ptr, cmsUInt32Number size) +{ + void *NewPtr; + + // Dup of null pointer is also NULL + if (ptr == NULL) + return NULL; + + NewPtr = _cmsSubAlloc(s, size); + + if (ptr != NULL && NewPtr != NULL) { + memcpy(NewPtr, ptr, size); + } + + return NewPtr; +} + + + // Error logging ****************************************************************** // There is no error handling at all. When a funtion fails, it returns proper value. @@ -401,8 +471,26 @@ void* _cmsSubAlloc(_cmsSubAllocator* sub, cmsUInt32Number size) // This is our default log error static void DefaultLogErrorHandlerFunction(cmsContext ContextID, cmsUInt32Number ErrorCode, const char *Text); -// The current handler in actual environment -static cmsLogErrorHandlerFunction LogErrorHandler = DefaultLogErrorHandlerFunction; +// Context0 storage, which is global +_cmsLogErrorChunkType _cmsLogErrorChunk = { DefaultLogErrorHandlerFunction }; + +// Allocates and inits error logger container for a given context. If src is NULL, only initializes the value +// to the default. Otherwise, it duplicates the value. The interface is standard across all context clients +void _cmsAllocLogErrorChunk(struct _cmsContext_struct* ctx, + const struct _cmsContext_struct* src) +{ + static _cmsLogErrorChunkType LogErrorChunk = { DefaultLogErrorHandlerFunction }; + void* from; + + if (src != NULL) { + from = src ->chunks[Logger]; + } + else { + from = &LogErrorChunk; + } + + ctx ->chunks[Logger] = _cmsSubAllocDup(ctx ->MemPool, from, sizeof(_cmsLogErrorChunkType)); +} // The default error logger does nothing. static @@ -416,13 +504,24 @@ void DefaultLogErrorHandlerFunction(cmsContext ContextID, cmsUInt32Number ErrorC cmsUNUSED_PARAMETER(Text); } -// Change log error +// Change log error, context based +void CMSEXPORT cmsSetLogErrorHandlerTHR(cmsContext ContextID, cmsLogErrorHandlerFunction Fn) +{ + _cmsLogErrorChunkType* lhg = (_cmsLogErrorChunkType*) _cmsContextGetClientChunk(ContextID, Logger); + + if (lhg != NULL) { + + if (Fn == NULL) + lhg -> LogErrorHandler = DefaultLogErrorHandlerFunction; + else + lhg -> LogErrorHandler = Fn; + } +} + +// Change log error, legacy void CMSEXPORT cmsSetLogErrorHandler(cmsLogErrorHandlerFunction Fn) { - if (Fn == NULL) - LogErrorHandler = DefaultLogErrorHandlerFunction; - else - LogErrorHandler = Fn; + cmsSetLogErrorHandlerTHR(NULL, Fn); } // Log an error @@ -431,13 +530,18 @@ void CMSEXPORT cmsSignalError(cmsContext ContextID, cmsUInt32Number ErrorCode, c { va_list args; char Buffer[MAX_ERROR_MESSAGE_LEN]; + _cmsLogErrorChunkType* lhg; + va_start(args, ErrorText); vsnprintf(Buffer, MAX_ERROR_MESSAGE_LEN-1, ErrorText, args); va_end(args); - // Call handler - LogErrorHandler(ContextID, ErrorCode, Buffer); + // Check for the context, if specified go there. If not, go for the global + lhg = (_cmsLogErrorChunkType*) _cmsContextGetClientChunk(ContextID, Logger); + if (lhg ->LogErrorHandler) { + lhg ->LogErrorHandler(ContextID, ErrorCode, Buffer); + } } // Utility function to print signatures @@ -455,3 +559,125 @@ void _cmsTagSignature2String(char String[5], cmsTagSignature sig) String[4] = 0; } +//-------------------------------------------------------------------------------------------------- + + +static +void* defMtxCreate(cmsContext id) +{ + _cmsMutex* ptr_mutex = (_cmsMutex*) _cmsMalloc(id, sizeof(_cmsMutex)); + _cmsInitMutexPrimitive(ptr_mutex); + return (void*) ptr_mutex; +} + +static +void defMtxDestroy(cmsContext id, void* mtx) +{ + _cmsDestroyMutexPrimitive((_cmsMutex *) mtx); + _cmsFree(id, mtx); +} + +static +cmsBool defMtxLock(cmsContext id, void* mtx) +{ + cmsUNUSED_PARAMETER(id); + return _cmsLockPrimitive((_cmsMutex *) mtx) == 0; +} + +static +void defMtxUnlock(cmsContext id, void* mtx) +{ + cmsUNUSED_PARAMETER(id); + _cmsUnlockPrimitive((_cmsMutex *) mtx); +} + + + +// Pointers to memory manager functions in Context0 +_cmsMutexPluginChunkType _cmsMutexPluginChunk = { defMtxCreate, defMtxDestroy, defMtxLock, defMtxUnlock }; + +// Allocate and init mutex container. +void _cmsAllocMutexPluginChunk(struct _cmsContext_struct* ctx, + const struct _cmsContext_struct* src) +{ + static _cmsMutexPluginChunkType MutexChunk = {defMtxCreate, defMtxDestroy, defMtxLock, defMtxUnlock }; + void* from; + + if (src != NULL) { + from = src ->chunks[MutexPlugin]; + } + else { + from = &MutexChunk; + } + + ctx ->chunks[MutexPlugin] = _cmsSubAllocDup(ctx ->MemPool, from, sizeof(_cmsMutexPluginChunkType)); +} + +// Register new ways to transform +cmsBool _cmsRegisterMutexPlugin(cmsContext ContextID, cmsPluginBase* Data) +{ + cmsPluginMutex* Plugin = (cmsPluginMutex*) Data; + _cmsMutexPluginChunkType* ctx = ( _cmsMutexPluginChunkType*) _cmsContextGetClientChunk(ContextID, MutexPlugin); + + if (Data == NULL) { + + // No lock routines + ctx->CreateMutexPtr = NULL; + ctx->DestroyMutexPtr = NULL; + ctx->LockMutexPtr = NULL; + ctx ->UnlockMutexPtr = NULL; + return TRUE; + } + + // Factory callback is required + if (Plugin ->CreateMutexPtr == NULL || Plugin ->DestroyMutexPtr == NULL || + Plugin ->LockMutexPtr == NULL || Plugin ->UnlockMutexPtr == NULL) return FALSE; + + + ctx->CreateMutexPtr = Plugin->CreateMutexPtr; + ctx->DestroyMutexPtr = Plugin ->DestroyMutexPtr; + ctx ->LockMutexPtr = Plugin ->LockMutexPtr; + ctx ->UnlockMutexPtr = Plugin ->UnlockMutexPtr; + + // All is ok + return TRUE; +} + +// Generic Mutex fns +void* CMSEXPORT _cmsCreateMutex(cmsContext ContextID) +{ + _cmsMutexPluginChunkType* ptr = (_cmsMutexPluginChunkType*) _cmsContextGetClientChunk(ContextID, MutexPlugin); + + if (ptr ->CreateMutexPtr == NULL) return NULL; + + return ptr ->CreateMutexPtr(ContextID); +} + +void CMSEXPORT _cmsDestroyMutex(cmsContext ContextID, void* mtx) +{ + _cmsMutexPluginChunkType* ptr = (_cmsMutexPluginChunkType*) _cmsContextGetClientChunk(ContextID, MutexPlugin); + + if (ptr ->DestroyMutexPtr != NULL) { + + ptr ->DestroyMutexPtr(ContextID, mtx); + } +} + +cmsBool CMSEXPORT _cmsLockMutex(cmsContext ContextID, void* mtx) +{ + _cmsMutexPluginChunkType* ptr = (_cmsMutexPluginChunkType*) _cmsContextGetClientChunk(ContextID, MutexPlugin); + + if (ptr ->LockMutexPtr == NULL) return TRUE; + + return ptr ->LockMutexPtr(ContextID, mtx); +} + +void CMSEXPORT _cmsUnlockMutex(cmsContext ContextID, void* mtx) +{ + _cmsMutexPluginChunkType* ptr = (_cmsMutexPluginChunkType*) _cmsContextGetClientChunk(ContextID, MutexPlugin); + + if (ptr ->UnlockMutexPtr != NULL) { + + ptr ->UnlockMutexPtr(ContextID, mtx); + } +} diff --git a/jdk/src/java.desktop/share/native/liblcms/cmsgamma.c b/jdk/src/java.desktop/share/native/liblcms/cmsgamma.c index 79affb09fb4..e68f2585d0e 100644 --- a/jdk/src/java.desktop/share/native/liblcms/cmsgamma.c +++ b/jdk/src/java.desktop/share/native/liblcms/cmsgamma.c @@ -82,7 +82,6 @@ typedef struct _cmsParametricCurvesCollection_st { } _cmsParametricCurvesCollection; - // This is the default (built-in) evaluator static cmsFloat64Number DefaultEvalParametricFn(cmsInt32Number Type, const cmsFloat64Number Params[], cmsFloat64Number R); @@ -95,22 +94,77 @@ static _cmsParametricCurvesCollection DefaultCurves = { NULL // Next in chain }; +// Duplicates the zone of memory used by the plug-in in the new context +static +void DupPluginCurvesList(struct _cmsContext_struct* ctx, + const struct _cmsContext_struct* src) +{ + _cmsCurvesPluginChunkType newHead = { NULL }; + _cmsParametricCurvesCollection* entry; + _cmsParametricCurvesCollection* Anterior = NULL; + _cmsCurvesPluginChunkType* head = (_cmsCurvesPluginChunkType*) src->chunks[CurvesPlugin]; + + _cmsAssert(head != NULL); + + // Walk the list copying all nodes + for (entry = head->ParametricCurves; + entry != NULL; + entry = entry ->Next) { + + _cmsParametricCurvesCollection *newEntry = ( _cmsParametricCurvesCollection *) _cmsSubAllocDup(ctx ->MemPool, entry, sizeof(_cmsParametricCurvesCollection)); + + if (newEntry == NULL) + return; + + // We want to keep the linked list order, so this is a little bit tricky + newEntry -> Next = NULL; + if (Anterior) + Anterior -> Next = newEntry; + + Anterior = newEntry; + + if (newHead.ParametricCurves == NULL) + newHead.ParametricCurves = newEntry; + } + + ctx ->chunks[CurvesPlugin] = _cmsSubAllocDup(ctx->MemPool, &newHead, sizeof(_cmsCurvesPluginChunkType)); +} + +// The allocator have to follow the chain +void _cmsAllocCurvesPluginChunk(struct _cmsContext_struct* ctx, + const struct _cmsContext_struct* src) +{ + _cmsAssert(ctx != NULL); + + if (src != NULL) { + + // Copy all linked list + DupPluginCurvesList(ctx, src); + } + else { + static _cmsCurvesPluginChunkType CurvesPluginChunk = { NULL }; + ctx ->chunks[CurvesPlugin] = _cmsSubAllocDup(ctx ->MemPool, &CurvesPluginChunk, sizeof(_cmsCurvesPluginChunkType)); + } +} + + // The linked list head -static _cmsParametricCurvesCollection* ParametricCurves = &DefaultCurves; +_cmsCurvesPluginChunkType _cmsCurvesPluginChunk = { NULL }; // As a way to install new parametric curves -cmsBool _cmsRegisterParametricCurvesPlugin(cmsContext id, cmsPluginBase* Data) +cmsBool _cmsRegisterParametricCurvesPlugin(cmsContext ContextID, cmsPluginBase* Data) { + _cmsCurvesPluginChunkType* ctx = ( _cmsCurvesPluginChunkType*) _cmsContextGetClientChunk(ContextID, CurvesPlugin); cmsPluginParametricCurves* Plugin = (cmsPluginParametricCurves*) Data; _cmsParametricCurvesCollection* fl; if (Data == NULL) { - ParametricCurves = &DefaultCurves; + ctx -> ParametricCurves = NULL; return TRUE; } - fl = (_cmsParametricCurvesCollection*) _cmsPluginMalloc(id, sizeof(_cmsParametricCurvesCollection)); + fl = (_cmsParametricCurvesCollection*) _cmsPluginMalloc(ContextID, sizeof(_cmsParametricCurvesCollection)); if (fl == NULL) return FALSE; // Copy the parameters @@ -126,8 +180,8 @@ cmsBool _cmsRegisterParametricCurvesPlugin(cmsContext id, cmsPluginBase* Data) memmove(fl->ParameterCount, Plugin ->ParameterCount, fl->nFunctions * sizeof(cmsUInt32Number)); // Keep linked list - fl ->Next = ParametricCurves; - ParametricCurves = fl; + fl ->Next = ctx->ParametricCurves; + ctx->ParametricCurves = fl; // All is ok return TRUE; @@ -149,12 +203,24 @@ int IsInSet(int Type, _cmsParametricCurvesCollection* c) // Search for the collection which contains a specific type static -_cmsParametricCurvesCollection *GetParametricCurveByType(int Type, int* index) +_cmsParametricCurvesCollection *GetParametricCurveByType(cmsContext ContextID, int Type, int* index) { _cmsParametricCurvesCollection* c; int Position; + _cmsCurvesPluginChunkType* ctx = ( _cmsCurvesPluginChunkType*) _cmsContextGetClientChunk(ContextID, CurvesPlugin); - for (c = ParametricCurves; c != NULL; c = c ->Next) { + for (c = ctx->ParametricCurves; c != NULL; c = c ->Next) { + + Position = IsInSet(Type, c); + + if (Position != -1) { + if (index != NULL) + *index = Position; + return c; + } + } + // If none found, revert for defaults + for (c = &DefaultCurves; c != NULL; c = c ->Next) { Position = IsInSet(Type, c); @@ -251,7 +317,7 @@ cmsToneCurve* AllocateToneCurveStruct(cmsContext ContextID, cmsInt32Number nEntr p ->Segments[i].SampledPoints = NULL; - c = GetParametricCurveByType(Segments[i].Type, NULL); + c = GetParametricCurveByType(ContextID, Segments[i].Type, NULL); if (c != NULL) p ->Evals[i] = c ->Evaluator; } @@ -677,12 +743,12 @@ cmsToneCurve* CMSEXPORT cmsBuildParametricToneCurve(cmsContext ContextID, cmsInt cmsCurveSegment Seg0; int Pos = 0; cmsUInt32Number size; - _cmsParametricCurvesCollection* c = GetParametricCurveByType(Type, &Pos); + _cmsParametricCurvesCollection* c = GetParametricCurveByType(ContextID, Type, &Pos); _cmsAssert(Params != NULL); if (c == NULL) { - cmsSignalError(ContextID, cmsERROR_UNKNOWN_EXTENSION, "Invalid parametric curve type %d", Type); + cmsSignalError(ContextID, cmsERROR_UNKNOWN_EXTENSION, "Invalid parametric curve type %d", Type); return NULL; } @@ -872,7 +938,10 @@ cmsToneCurve* CMSEXPORT cmsReverseToneCurveEx(cmsInt32Number nResultSamples, con _cmsAssert(InCurve != NULL); // Try to reverse it analytically whatever possible - if (InCurve ->nSegments == 1 && InCurve ->Segments[0].Type > 0 && InCurve -> Segments[0].Type <= 5) { + + if (InCurve ->nSegments == 1 && InCurve ->Segments[0].Type > 0 && + /* InCurve -> Segments[0].Type <= 5 */ + GetParametricCurveByType(InCurve ->InterpParams->ContextID, InCurve ->Segments[0].Type, NULL) != NULL) { return cmsBuildParametricToneCurve(InCurve ->InterpParams->ContextID, -(InCurve -> Segments[0].Type), diff --git a/jdk/src/java.desktop/share/native/liblcms/cmsgmt.c b/jdk/src/java.desktop/share/native/liblcms/cmsgmt.c index 8ace203e86d..0be9173948a 100644 --- a/jdk/src/java.desktop/share/native/liblcms/cmsgmt.c +++ b/jdk/src/java.desktop/share/native/liblcms/cmsgmt.c @@ -191,7 +191,7 @@ cmsToneCurve* _cmsBuildKToneCurve(cmsContext ContextID, out = ComputeKToLstar(ContextID, nPoints, 1, Intents + (nProfiles - 1), - hProfiles + (nProfiles - 1), + &hProfiles [nProfiles - 1], BPC + (nProfiles - 1), AdaptationStates + (nProfiles - 1), dwFlags); diff --git a/jdk/src/java.desktop/share/native/liblcms/cmsintrp.c b/jdk/src/java.desktop/share/native/liblcms/cmsintrp.c index ad971b5bc60..e57e6ea0e1c 100644 --- a/jdk/src/java.desktop/share/native/liblcms/cmsintrp.c +++ b/jdk/src/java.desktop/share/native/liblcms/cmsintrp.c @@ -62,31 +62,57 @@ static cmsInterpFunction DefaultInterpolatorsFactory(cmsUInt32Number nInputChannels, cmsUInt32Number nOutputChannels, cmsUInt32Number dwFlags); // This is the default factory -static cmsInterpFnFactory Interpolators = DefaultInterpolatorsFactory; +_cmsInterpPluginChunkType _cmsInterpPluginChunk = { NULL }; + +// The interpolation plug-in memory chunk allocator/dup +void _cmsAllocInterpPluginChunk(struct _cmsContext_struct* ctx, const struct _cmsContext_struct* src) +{ + void* from; + + _cmsAssert(ctx != NULL); + + if (src != NULL) { + from = src ->chunks[InterpPlugin]; + } + else { + static _cmsInterpPluginChunkType InterpPluginChunk = { NULL }; + + from = &InterpPluginChunk; + } + + _cmsAssert(from != NULL); + ctx ->chunks[InterpPlugin] = _cmsSubAllocDup(ctx ->MemPool, from, sizeof(_cmsInterpPluginChunkType)); +} // Main plug-in entry -cmsBool _cmsRegisterInterpPlugin(cmsPluginBase* Data) +cmsBool _cmsRegisterInterpPlugin(cmsContext ContextID, cmsPluginBase* Data) { cmsPluginInterpolation* Plugin = (cmsPluginInterpolation*) Data; + _cmsInterpPluginChunkType* ptr = (_cmsInterpPluginChunkType*) _cmsContextGetClientChunk(ContextID, InterpPlugin); if (Data == NULL) { - Interpolators = DefaultInterpolatorsFactory; + ptr ->Interpolators = NULL; return TRUE; } // Set replacement functions - Interpolators = Plugin ->InterpolatorsFactory; + ptr ->Interpolators = Plugin ->InterpolatorsFactory; return TRUE; } // Set the interpolation method -cmsBool _cmsSetInterpolationRoutine(cmsInterpParams* p) +cmsBool _cmsSetInterpolationRoutine(cmsContext ContextID, cmsInterpParams* p) { - // Invoke factory, possibly in the Plug-in - p ->Interpolation = Interpolators(p -> nInputs, p ->nOutputs, p ->dwFlags); + _cmsInterpPluginChunkType* ptr = (_cmsInterpPluginChunkType*) _cmsContextGetClientChunk(ContextID, InterpPlugin); + + p ->Interpolation.Lerp16 = NULL; + + // Invoke factory, possibly in the Plug-in + if (ptr ->Interpolators != NULL) + p ->Interpolation = ptr->Interpolators(p -> nInputs, p ->nOutputs, p ->dwFlags); // If unsupported by the plug-in, go for the LittleCMS default. // If happens only if an extern plug-in is being used @@ -97,6 +123,7 @@ cmsBool _cmsSetInterpolationRoutine(cmsInterpParams* p) if (p ->Interpolation.Lerp16 == NULL) { return FALSE; } + return TRUE; } @@ -141,7 +168,7 @@ cmsInterpParams* _cmsComputeInterpParamsEx(cmsContext ContextID, p ->opta[i] = p ->opta[i-1] * nSamples[InputChan-i]; - if (!_cmsSetInterpolationRoutine(p)) { + if (!_cmsSetInterpolationRoutine(ContextID, p)) { cmsSignalError(ContextID, cmsERROR_UNKNOWN_EXTENSION, "Unsupported interpolation (%d->%d channels)", InputChan, OutputChan); _cmsFree(ContextID, p); return NULL; diff --git a/jdk/src/java.desktop/share/native/liblcms/cmsio0.c b/jdk/src/java.desktop/share/native/liblcms/cmsio0.c index 8f421c2f4ec..d4dc1b0d876 100644 --- a/jdk/src/java.desktop/share/native/liblcms/cmsio0.c +++ b/jdk/src/java.desktop/share/native/liblcms/cmsio0.c @@ -229,15 +229,14 @@ cmsBool MemoryWrite(struct _cms_io_handler* iohandler, cmsUInt32Number size, con if (ResData == NULL) return FALSE; // Housekeeping // Check for available space. Clip. - if (iohandler ->UsedSpace + size > ResData->Size) { - size = ResData ->Size - iohandler ->UsedSpace; + if (ResData->Pointer + size > ResData->Size) { + size = ResData ->Size - ResData->Pointer; } if (size == 0) return TRUE; // Write zero bytes is ok, but does nothing memmove(ResData ->Block + ResData ->Pointer, Ptr, size); ResData ->Pointer += size; - iohandler->UsedSpace += size; if (ResData ->Pointer > iohandler->UsedSpace) iohandler->UsedSpace = ResData ->Pointer; @@ -371,7 +370,7 @@ cmsBool FileSeek(cmsIOHANDLER* iohandler, cmsUInt32Number offset) static cmsUInt32Number FileTell(cmsIOHANDLER* iohandler) { - return ftell((FILE*)iohandler ->stream); + return (cmsUInt32Number) ftell((FILE*)iohandler ->stream); } // Writes data to stream, also keeps used space for further reference. Returns TRUE on success, FALSE on error @@ -414,7 +413,7 @@ cmsIOHANDLER* CMSEXPORT cmsOpenIOhandlerFromFile(cmsContext ContextID, const cha cmsSignalError(ContextID, cmsERROR_FILE, "File '%s' not found", FileName); return NULL; } - iohandler -> ReportedSize = cmsfilelength(fm); + iohandler -> ReportedSize = (cmsUInt32Number) cmsfilelength(fm); break; case 'w': @@ -461,7 +460,7 @@ cmsIOHANDLER* CMSEXPORT cmsOpenIOhandlerFromStream(cmsContext ContextID, FILE* S iohandler -> ContextID = ContextID; iohandler -> stream = (void*) Stream; iohandler -> UsedSpace = 0; - iohandler -> ReportedSize = cmsfilelength(Stream); + iohandler -> ReportedSize = (cmsUInt32Number) cmsfilelength(Stream); iohandler -> PhysicalFile[0] = 0; iohandler ->Read = FileRead; @@ -501,6 +500,9 @@ cmsHPROFILE CMSEXPORT cmsCreateProfilePlaceholder(cmsContext ContextID) // Set creation date/time memmove(&Icc ->Created, gmtime(&now), sizeof(Icc ->Created)); + // Create a mutex if the user provided proper plugin. NULL otherwise + Icc ->UsrMutex = _cmsCreateMutex(ContextID); + // Return the handle return (cmsHPROFILE) Icc; } @@ -579,9 +581,39 @@ int _cmsSearchTag(_cmsICCPROFILE* Icc, cmsTagSignature sig, cmsBool lFollowLinks return n; } +// Deletes a tag entry -// Create a new tag entry +static +void _cmsDeleteTagByPos(_cmsICCPROFILE* Icc, int i) +{ + _cmsAssert(Icc != NULL); + _cmsAssert(i >= 0); + + if (Icc -> TagPtrs[i] != NULL) { + + // Free previous version + if (Icc ->TagSaveAsRaw[i]) { + _cmsFree(Icc ->ContextID, Icc ->TagPtrs[i]); + } + else { + cmsTagTypeHandler* TypeHandler = Icc ->TagTypeHandlers[i]; + + if (TypeHandler != NULL) { + + cmsTagTypeHandler LocalTypeHandler = *TypeHandler; + LocalTypeHandler.ContextID = Icc ->ContextID; // As an additional parameter + LocalTypeHandler.ICCVersion = Icc ->Version; + LocalTypeHandler.FreePtr(&LocalTypeHandler, Icc -> TagPtrs[i]); + Icc ->TagPtrs[i] = NULL; + } + } + + } +} + + +// Creates a new tag entry static cmsBool _cmsNewTag(_cmsICCPROFILE* Icc, cmsTagSignature sig, int* NewPos) { @@ -589,15 +621,15 @@ cmsBool _cmsNewTag(_cmsICCPROFILE* Icc, cmsTagSignature sig, int* NewPos) // Search for the tag i = _cmsSearchTag(Icc, sig, FALSE); - - // Now let's do it easy. If the tag has been already written, that's an error if (i >= 0) { - cmsSignalError(Icc ->ContextID, cmsERROR_ALREADY_DEFINED, "Tag '%x' already exists", sig); - return FALSE; + + // Already exists? delete it + _cmsDeleteTagByPos(Icc, i); + *NewPos = i; } else { - // New one + // No, make a new one if (Icc -> TagCount >= MAX_TABLE_TAG) { cmsSignalError(Icc ->ContextID, cmsERROR_RANGE, "Too many tags (%d)", MAX_TABLE_TAG); @@ -979,7 +1011,7 @@ void CMSEXPORT cmsSetProfileVersion(cmsHPROFILE hProfile, cmsFloat64Number Vers // 4.2 -> 0x4200000 - Icc -> Version = BaseToBase((cmsUInt32Number) floor(Version * 100.0), 10, 16) << 16; + Icc -> Version = BaseToBase((cmsUInt32Number) floor(Version * 100.0 + 0.5), 10, 16) << 16; } cmsFloat64Number CMSEXPORT cmsGetProfileVersion(cmsHPROFILE hProfile) @@ -1011,6 +1043,32 @@ Error: return NULL; } +// Create profile from IOhandler +cmsHPROFILE CMSEXPORT cmsOpenProfileFromIOhandler2THR(cmsContext ContextID, cmsIOHANDLER* io, cmsBool write) +{ + _cmsICCPROFILE* NewIcc; + cmsHPROFILE hEmpty = cmsCreateProfilePlaceholder(ContextID); + + if (hEmpty == NULL) return NULL; + + NewIcc = (_cmsICCPROFILE*) hEmpty; + + NewIcc ->IOhandler = io; + if (write) { + + NewIcc -> IsWrite = TRUE; + return hEmpty; + } + + if (!_cmsReadHeader(NewIcc)) goto Error; + return hEmpty; + +Error: + cmsCloseProfile(hEmpty); + return NULL; +} + + // Create profile from disk file cmsHPROFILE CMSEXPORT cmsOpenProfileFromFileTHR(cmsContext ContextID, const char *lpFileName, const char *sAccess) { @@ -1202,7 +1260,7 @@ cmsBool SaveTags(_cmsICCPROFILE* Icc, _cmsICCPROFILE* FileOrig) else { // Search for support on this tag - TagDescriptor = _cmsGetTagDescriptor(Icc -> TagNames[i]); + TagDescriptor = _cmsGetTagDescriptor(Icc-> ContextID, Icc -> TagNames[i]); if (TagDescriptor == NULL) continue; // Unsupported, ignore it if (TagDescriptor ->DecideType != NULL) { @@ -1214,7 +1272,7 @@ cmsBool SaveTags(_cmsICCPROFILE* Icc, _cmsICCPROFILE* FileOrig) Type = TagDescriptor ->SupportedTypes[0]; } - TypeHandler = _cmsGetTagTypeHandler(Type); + TypeHandler = _cmsGetTagTypeHandler(Icc->ContextID, Type); if (TypeHandler == NULL) { cmsSignalError(Icc ->ContextID, cmsERROR_INTERNAL, "(Internal) no handler for tag %x", Icc -> TagNames[i]); @@ -1282,10 +1340,12 @@ cmsUInt32Number CMSEXPORT cmsSaveProfileToIOhandler(cmsHPROFILE hProfile, cmsIOH { _cmsICCPROFILE* Icc = (_cmsICCPROFILE*) hProfile; _cmsICCPROFILE Keep; - cmsIOHANDLER* PrevIO; + cmsIOHANDLER* PrevIO = NULL; cmsUInt32Number UsedSpace; cmsContext ContextID; + _cmsAssert(hProfile != NULL); + memmove(&Keep, Icc, sizeof(_cmsICCPROFILE)); ContextID = cmsGetProfileContextID(hProfile); @@ -1294,18 +1354,19 @@ cmsUInt32Number CMSEXPORT cmsSaveProfileToIOhandler(cmsHPROFILE hProfile, cmsIOH // Pass #1 does compute offsets - if (!_cmsWriteHeader(Icc, 0)) return 0; - if (!SaveTags(Icc, &Keep)) return 0; + if (!_cmsWriteHeader(Icc, 0)) goto Error; + if (!SaveTags(Icc, &Keep)) goto Error; UsedSpace = PrevIO ->UsedSpace; // Pass #2 does save to iohandler if (io != NULL) { + Icc ->IOhandler = io; - if (!SetLinks(Icc)) goto CleanUp; - if (!_cmsWriteHeader(Icc, UsedSpace)) goto CleanUp; - if (!SaveTags(Icc, &Keep)) goto CleanUp; + if (!SetLinks(Icc)) goto Error; + if (!_cmsWriteHeader(Icc, UsedSpace)) goto Error; + if (!SaveTags(Icc, &Keep)) goto Error; } memmove(Icc, &Keep, sizeof(_cmsICCPROFILE)); @@ -1314,7 +1375,7 @@ cmsUInt32Number CMSEXPORT cmsSaveProfileToIOhandler(cmsHPROFILE hProfile, cmsIOH return UsedSpace; -CleanUp: +Error: cmsCloseIOhandler(PrevIO); memmove(Icc, &Keep, sizeof(_cmsICCPROFILE)); return 0; @@ -1362,11 +1423,13 @@ cmsBool CMSEXPORT cmsSaveProfileToMem(cmsHPROFILE hProfile, void *MemPtr, cmsUIn cmsIOHANDLER* io; cmsContext ContextID = cmsGetProfileContextID(hProfile); + _cmsAssert(BytesNeeded != NULL); + // Should we just calculate the needed space? if (MemPtr == NULL) { *BytesNeeded = cmsSaveProfileToIOhandler(hProfile, NULL); - return (*BytesNeeded == 0 ? FALSE : TRUE); + return (*BytesNeeded == 0) ? FALSE : TRUE; } // That is a real write operation @@ -1419,6 +1482,8 @@ cmsBool CMSEXPORT cmsCloseProfile(cmsHPROFILE hProfile) rc &= cmsCloseIOhandler(Icc->IOhandler); } + _cmsDestroyMutex(Icc->ContextID, Icc->UsrMutex); + _cmsFree(Icc ->ContextID, Icc); // Free placeholder memory return rc; @@ -1459,14 +1524,18 @@ void* CMSEXPORT cmsReadTag(cmsHPROFILE hProfile, cmsTagSignature sig) cmsUInt32Number ElemCount; int n; + if (!_cmsLockMutex(Icc->ContextID, Icc ->UsrMutex)) return NULL; + n = _cmsSearchTag(Icc, sig, TRUE); - if (n < 0) return NULL; // Not found, return NULL + if (n < 0) goto Error; // Not found, return NULL // If the element is already in memory, return the pointer if (Icc -> TagPtrs[n]) { - if (Icc ->TagSaveAsRaw[n]) return NULL; // We don't support read raw tags as cooked + if (Icc ->TagSaveAsRaw[n]) goto Error; // We don't support read raw tags as cooked + + _cmsUnlockMutex(Icc->ContextID, Icc ->UsrMutex); return Icc -> TagPtrs[n]; } @@ -1476,23 +1545,32 @@ void* CMSEXPORT cmsReadTag(cmsHPROFILE hProfile, cmsTagSignature sig) // Seek to its location if (!io -> Seek(io, Offset)) - return NULL; + goto Error; // Search for support on this tag - TagDescriptor = _cmsGetTagDescriptor(sig); - if (TagDescriptor == NULL) return NULL; // Unsupported. + TagDescriptor = _cmsGetTagDescriptor(Icc-> ContextID, sig); + if (TagDescriptor == NULL) { + + char String[5]; + + _cmsTagSignature2String(String, sig); + + // An unknown element was found. + cmsSignalError(Icc ->ContextID, cmsERROR_UNKNOWN_EXTENSION, "Unknown tag type '%s' found.", String); + goto Error; // Unsupported. + } // if supported, get type and check if in list BaseType = _cmsReadTypeBase(io); - if (BaseType == 0) return NULL; + if (BaseType == 0) goto Error; - if (!IsTypeSupported(TagDescriptor, BaseType)) return NULL; + if (!IsTypeSupported(TagDescriptor, BaseType)) goto Error; TagSize -= 8; // Alredy read by the type base logic // Get type handler - TypeHandler = _cmsGetTagTypeHandler(BaseType); - if (TypeHandler == NULL) return NULL; + TypeHandler = _cmsGetTagTypeHandler(Icc ->ContextID, BaseType); + if (TypeHandler == NULL) goto Error; LocalTypeHandler = *TypeHandler; @@ -1511,7 +1589,7 @@ void* CMSEXPORT cmsReadTag(cmsHPROFILE hProfile, cmsTagSignature sig) _cmsTagSignature2String(String, sig); cmsSignalError(Icc ->ContextID, cmsERROR_CORRUPTION_DETECTED, "Corrupted tag '%s'", String); - return NULL; + goto Error; } // This is a weird error that may be a symptom of something more serious, the number of @@ -1527,7 +1605,14 @@ void* CMSEXPORT cmsReadTag(cmsHPROFILE hProfile, cmsTagSignature sig) // Return the data + _cmsUnlockMutex(Icc->ContextID, Icc ->UsrMutex); return Icc -> TagPtrs[n]; + + + // Return error and unlock tha data +Error: + _cmsUnlockMutex(Icc->ContextID, Icc ->UsrMutex); + return NULL; } @@ -1561,49 +1646,26 @@ cmsBool CMSEXPORT cmsWriteTag(cmsHPROFILE hProfile, cmsTagSignature sig, const v cmsFloat64Number Version; char TypeString[5], SigString[5]; + if (!_cmsLockMutex(Icc->ContextID, Icc ->UsrMutex)) return FALSE; + // To delete tags. if (data == NULL) { + // Delete the tag i = _cmsSearchTag(Icc, sig, FALSE); - if (i >= 0) + if (i >= 0) { + + // Use zero as a mark of deleted + _cmsDeleteTagByPos(Icc, i); Icc ->TagNames[i] = (cmsTagSignature) 0; - // Unsupported by now, reserved for future ampliations (delete) - return FALSE; + _cmsUnlockMutex(Icc->ContextID, Icc ->UsrMutex); + return TRUE; + } + // Didn't find the tag + goto Error; } - i = _cmsSearchTag(Icc, sig, FALSE); - if (i >=0) { - - if (Icc -> TagPtrs[i] != NULL) { - - // Already exists. Free previous version - if (Icc ->TagSaveAsRaw[i]) { - _cmsFree(Icc ->ContextID, Icc ->TagPtrs[i]); - } - else { - TypeHandler = Icc ->TagTypeHandlers[i]; - - if (TypeHandler != NULL) { - - LocalTypeHandler = *TypeHandler; - LocalTypeHandler.ContextID = Icc ->ContextID; // As an additional parameter - LocalTypeHandler.ICCVersion = Icc ->Version; - LocalTypeHandler.FreePtr(&LocalTypeHandler, Icc -> TagPtrs[i]); - } - } - } - } - else { - // New one - i = Icc -> TagCount; - - if (i >= MAX_TABLE_TAG) { - cmsSignalError(Icc ->ContextID, cmsERROR_RANGE, "Too many tags (%d)", MAX_TABLE_TAG); - return FALSE; - } - - Icc -> TagCount++; - } + if (!_cmsNewTag(Icc, sig, &i)) goto Error; // This is not raw Icc ->TagSaveAsRaw[i] = FALSE; @@ -1612,10 +1674,10 @@ cmsBool CMSEXPORT cmsWriteTag(cmsHPROFILE hProfile, cmsTagSignature sig, const v Icc ->TagLinked[i] = (cmsTagSignature) 0; // Get information about the TAG. - TagDescriptor = _cmsGetTagDescriptor(sig); + TagDescriptor = _cmsGetTagDescriptor(Icc-> ContextID, sig); if (TagDescriptor == NULL){ cmsSignalError(Icc ->ContextID, cmsERROR_UNKNOWN_EXTENSION, "Unsupported tag '%x'", sig); - return FALSE; + goto Error; } @@ -1633,7 +1695,6 @@ cmsBool CMSEXPORT cmsWriteTag(cmsHPROFILE hProfile, cmsTagSignature sig, const v } else { - Type = TagDescriptor ->SupportedTypes[0]; } @@ -1644,18 +1705,18 @@ cmsBool CMSEXPORT cmsWriteTag(cmsHPROFILE hProfile, cmsTagSignature sig, const v _cmsTagSignature2String(SigString, sig); cmsSignalError(Icc ->ContextID, cmsERROR_UNKNOWN_EXTENSION, "Unsupported type '%s' for tag '%s'", TypeString, SigString); - return FALSE; + goto Error; } // Does we have a handler for this type? - TypeHandler = _cmsGetTagTypeHandler(Type); + TypeHandler = _cmsGetTagTypeHandler(Icc->ContextID, Type); if (TypeHandler == NULL) { _cmsTagSignature2String(TypeString, (cmsTagSignature) Type); _cmsTagSignature2String(SigString, sig); cmsSignalError(Icc ->ContextID, cmsERROR_UNKNOWN_EXTENSION, "Unsupported type '%s' for tag '%s'", TypeString, SigString); - return FALSE; // Should never happen + goto Error; // Should never happen } @@ -1668,7 +1729,7 @@ cmsBool CMSEXPORT cmsWriteTag(cmsHPROFILE hProfile, cmsTagSignature sig, const v LocalTypeHandler = *TypeHandler; LocalTypeHandler.ContextID = Icc ->ContextID; LocalTypeHandler.ICCVersion = Icc ->Version; - Icc ->TagPtrs[i] = LocalTypeHandler.DupPtr(&LocalTypeHandler, data, TagDescriptor ->ElemCount); + Icc ->TagPtrs[i] = LocalTypeHandler.DupPtr(&LocalTypeHandler, data, TagDescriptor ->ElemCount); if (Icc ->TagPtrs[i] == NULL) { @@ -1676,10 +1737,16 @@ cmsBool CMSEXPORT cmsWriteTag(cmsHPROFILE hProfile, cmsTagSignature sig, const v _cmsTagSignature2String(SigString, sig); cmsSignalError(Icc ->ContextID, cmsERROR_CORRUPTION_DETECTED, "Malformed struct in type '%s' for tag '%s'", TypeString, SigString); - return FALSE; + goto Error; } + _cmsUnlockMutex(Icc->ContextID, Icc ->UsrMutex); return TRUE; + +Error: + _cmsUnlockMutex(Icc->ContextID, Icc ->UsrMutex); + return FALSE; + } // Read and write raw data. The only way those function would work and keep consistence with normal read and write @@ -1700,9 +1767,11 @@ cmsInt32Number CMSEXPORT cmsReadRawTag(cmsHPROFILE hProfile, cmsTagSignature sig cmsUInt32Number rc; cmsUInt32Number Offset, TagSize; + if (!_cmsLockMutex(Icc->ContextID, Icc ->UsrMutex)) return 0; + // Search for given tag in ICC profile directory i = _cmsSearchTag(Icc, sig, TRUE); - if (i < 0) return 0; // Not found, return 0 + if (i < 0) goto Error; // Not found, // It is already read? if (Icc -> TagPtrs[i] == NULL) { @@ -1717,12 +1786,14 @@ cmsInt32Number CMSEXPORT cmsReadRawTag(cmsHPROFILE hProfile, cmsTagSignature sig if (BufferSize < TagSize) TagSize = BufferSize; - if (!Icc ->IOhandler ->Seek(Icc ->IOhandler, Offset)) return 0; - if (!Icc ->IOhandler ->Read(Icc ->IOhandler, data, 1, TagSize)) return 0; + if (!Icc ->IOhandler ->Seek(Icc ->IOhandler, Offset)) goto Error; + if (!Icc ->IOhandler ->Read(Icc ->IOhandler, data, 1, TagSize)) goto Error; + _cmsUnlockMutex(Icc->ContextID, Icc ->UsrMutex); return TagSize; } + _cmsUnlockMutex(Icc->ContextID, Icc ->UsrMutex); return Icc ->TagSizes[i]; } @@ -1738,16 +1809,22 @@ cmsInt32Number CMSEXPORT cmsReadRawTag(cmsHPROFILE hProfile, cmsTagSignature sig memmove(data, Icc ->TagPtrs[i], TagSize); + _cmsUnlockMutex(Icc->ContextID, Icc ->UsrMutex); return TagSize; } + _cmsUnlockMutex(Icc->ContextID, Icc ->UsrMutex); return Icc ->TagSizes[i]; } // Already readed, or previously set by cmsWriteTag(). We need to serialize that // data to raw in order to maintain consistency. + + _cmsUnlockMutex(Icc->ContextID, Icc ->UsrMutex); Object = cmsReadTag(hProfile, sig); - if (Object == NULL) return 0; + if (!_cmsLockMutex(Icc->ContextID, Icc ->UsrMutex)) return 0; + + if (Object == NULL) goto Error; // Now we need to serialize to a memory block: just use a memory iohandler @@ -1756,17 +1833,18 @@ cmsInt32Number CMSEXPORT cmsReadRawTag(cmsHPROFILE hProfile, cmsTagSignature sig } else{ MemIO = cmsOpenIOhandlerFromMem(cmsGetProfileContextID(hProfile), data, BufferSize, "w"); } - if (MemIO == NULL) return 0; + if (MemIO == NULL) goto Error; // Obtain type handling for the tag TypeHandler = Icc ->TagTypeHandlers[i]; - TagDescriptor = _cmsGetTagDescriptor(sig); + TagDescriptor = _cmsGetTagDescriptor(Icc-> ContextID, sig); if (TagDescriptor == NULL) { cmsCloseIOhandler(MemIO); - return 0; + goto Error; } - // FIXME: No handling for TypeHandler == NULL here? + if (TypeHandler == NULL) goto Error; + // Serialize LocalTypeHandler = *TypeHandler; LocalTypeHandler.ContextID = Icc ->ContextID; @@ -1774,19 +1852,24 @@ cmsInt32Number CMSEXPORT cmsReadRawTag(cmsHPROFILE hProfile, cmsTagSignature sig if (!_cmsWriteTypeBase(MemIO, TypeHandler ->Signature)) { cmsCloseIOhandler(MemIO); - return 0; + goto Error; } if (!LocalTypeHandler.WritePtr(&LocalTypeHandler, MemIO, Object, TagDescriptor ->ElemCount)) { cmsCloseIOhandler(MemIO); - return 0; + goto Error; } // Get Size and close rc = MemIO ->Tell(MemIO); cmsCloseIOhandler(MemIO); // Ignore return code this time + _cmsUnlockMutex(Icc->ContextID, Icc ->UsrMutex); return rc; + +Error: + _cmsUnlockMutex(Icc->ContextID, Icc ->UsrMutex); + return 0; } // Similar to the anterior. This function allows to write directly to the ICC profile any data, without @@ -1798,7 +1881,12 @@ cmsBool CMSEXPORT cmsWriteRawTag(cmsHPROFILE hProfile, cmsTagSignature sig, cons _cmsICCPROFILE* Icc = (_cmsICCPROFILE*) hProfile; int i; - if (!_cmsNewTag(Icc, sig, &i)) return FALSE; + if (!_cmsLockMutex(Icc->ContextID, Icc ->UsrMutex)) return 0; + + if (!_cmsNewTag(Icc, sig, &i)) { + _cmsUnlockMutex(Icc->ContextID, Icc ->UsrMutex); + return FALSE; + } // Mark the tag as being written as RAW Icc ->TagSaveAsRaw[i] = TRUE; @@ -1809,6 +1897,7 @@ cmsBool CMSEXPORT cmsWriteRawTag(cmsHPROFILE hProfile, cmsTagSignature sig, cons Icc ->TagPtrs[i] = _cmsDupMem(Icc ->ContextID, data, Size); Icc ->TagSizes[i] = Size; + _cmsUnlockMutex(Icc->ContextID, Icc ->UsrMutex); return TRUE; } @@ -1818,7 +1907,12 @@ cmsBool CMSEXPORT cmsLinkTag(cmsHPROFILE hProfile, cmsTagSignature sig, cmsTagSi _cmsICCPROFILE* Icc = (_cmsICCPROFILE*) hProfile; int i; - if (!_cmsNewTag(Icc, sig, &i)) return FALSE; + if (!_cmsLockMutex(Icc->ContextID, Icc ->UsrMutex)) return FALSE; + + if (!_cmsNewTag(Icc, sig, &i)) { + _cmsUnlockMutex(Icc->ContextID, Icc ->UsrMutex); + return FALSE; + } // Keep necessary information Icc ->TagSaveAsRaw[i] = FALSE; @@ -1829,6 +1923,7 @@ cmsBool CMSEXPORT cmsLinkTag(cmsHPROFILE hProfile, cmsTagSignature sig, cmsTagSi Icc ->TagSizes[i] = 0; Icc ->TagOffsets[i] = 0; + _cmsUnlockMutex(Icc->ContextID, Icc ->UsrMutex); return TRUE; } diff --git a/jdk/src/java.desktop/share/native/liblcms/cmsio1.c b/jdk/src/java.desktop/share/native/liblcms/cmsio1.c index efdc6bf9d24..61c2ca5338a 100644 --- a/jdk/src/java.desktop/share/native/liblcms/cmsio1.c +++ b/jdk/src/java.desktop/share/native/liblcms/cmsio1.c @@ -334,7 +334,8 @@ Error: // Read and create a BRAND NEW MPE LUT from a given profile. All stuff dependent of version, etc -// is adjusted here in order to create a LUT that takes care of all those details +// is adjusted here in order to create a LUT that takes care of all those details. +// We add intent = -1 as a way to read matrix shaper always, no matter of other LUT cmsPipeline* _cmsReadInputLUT(cmsHPROFILE hProfile, int Intent) { cmsTagTypeSignature OriginalType; @@ -364,49 +365,54 @@ cmsPipeline* _cmsReadInputLUT(cmsHPROFILE hProfile, int Intent) return Lut; } - if (cmsIsTag(hProfile, tagFloat)) { // Float tag takes precedence + // This is an attempt to reuse this funtion to retrieve the matrix-shaper as pipeline no + // matter other LUT are present and have precedence. Intent = -1 means just this. + if (Intent != -1) { - // Floating point LUT are always V4, but the encoding range is no - // longer 0..1.0, so we need to add an stage depending on the color space - return _cmsReadFloatInputTag(hProfile, tagFloat); - } + if (cmsIsTag(hProfile, tagFloat)) { // Float tag takes precedence - // Revert to perceptual if no tag is found - if (!cmsIsTag(hProfile, tag16)) { - tag16 = Device2PCS16[0]; - } + // Floating point LUT are always V4, but the encoding range is no + // longer 0..1.0, so we need to add an stage depending on the color space + return _cmsReadFloatInputTag(hProfile, tagFloat); + } - if (cmsIsTag(hProfile, tag16)) { // Is there any LUT-Based table? + // Revert to perceptual if no tag is found + if (!cmsIsTag(hProfile, tag16)) { + tag16 = Device2PCS16[0]; + } - // Check profile version and LUT type. Do the necessary adjustments if needed + if (cmsIsTag(hProfile, tag16)) { // Is there any LUT-Based table? - // First read the tag - cmsPipeline* Lut = (cmsPipeline*) cmsReadTag(hProfile, tag16); - if (Lut == NULL) return NULL; + // Check profile version and LUT type. Do the necessary adjustments if needed - // After reading it, we have now info about the original type - OriginalType = _cmsGetTagTrueType(hProfile, tag16); + // First read the tag + cmsPipeline* Lut = (cmsPipeline*) cmsReadTag(hProfile, tag16); + if (Lut == NULL) return NULL; - // The profile owns the Lut, so we need to copy it - Lut = cmsPipelineDup(Lut); + // After reading it, we have now info about the original type + OriginalType = _cmsGetTagTrueType(hProfile, tag16); + + // The profile owns the Lut, so we need to copy it + Lut = cmsPipelineDup(Lut); + + // We need to adjust data only for Lab16 on output + if (OriginalType != cmsSigLut16Type || cmsGetPCS(hProfile) != cmsSigLabData) + return Lut; + + // If the input is Lab, add also a conversion at the begin + if (cmsGetColorSpace(hProfile) == cmsSigLabData && + !cmsPipelineInsertStage(Lut, cmsAT_BEGIN, _cmsStageAllocLabV4ToV2(ContextID))) + goto Error; + + // Add a matrix for conversion V2 to V4 Lab PCS + if (!cmsPipelineInsertStage(Lut, cmsAT_END, _cmsStageAllocLabV2ToV4(ContextID))) + goto Error; - // We need to adjust data only for Lab16 on output - if (OriginalType != cmsSigLut16Type || cmsGetPCS(hProfile) != cmsSigLabData) return Lut; - - // If the input is Lab, add also a conversion at the begin - if (cmsGetColorSpace(hProfile) == cmsSigLabData && - !cmsPipelineInsertStage(Lut, cmsAT_BEGIN, _cmsStageAllocLabV4ToV2(ContextID))) - goto Error; - - // Add a matrix for conversion V2 to V4 Lab PCS - if (!cmsPipelineInsertStage(Lut, cmsAT_END, _cmsStageAllocLabV2ToV4(ContextID))) - goto Error; - - return Lut; Error: - cmsPipelineFree(Lut); - return NULL; + cmsPipelineFree(Lut); + return NULL; + } } // Lut was not found, try to create a matrix-shaper @@ -551,7 +557,7 @@ void ChangeInterpolationToTrilinear(cmsPipeline* Lut) _cmsStageCLutData* CLUT = (_cmsStageCLutData*) Stage ->Data; CLUT ->Params->dwFlags |= CMS_LERP_FLAGS_TRILINEAR; - _cmsSetInterpolationRoutine(CLUT ->Params); + _cmsSetInterpolationRoutine(Lut->ContextID, CLUT ->Params); } } } @@ -609,54 +615,58 @@ cmsPipeline* _cmsReadOutputLUT(cmsHPROFILE hProfile, int Intent) cmsTagSignature tagFloat = PCS2DeviceFloat[Intent]; cmsContext ContextID = cmsGetProfileContextID(hProfile); - if (cmsIsTag(hProfile, tagFloat)) { // Float tag takes precedence - // Floating point LUT are always V4 - return _cmsReadFloatOutputTag(hProfile, tagFloat); - } + if (Intent != -1) { - // Revert to perceptual if no tag is found - if (!cmsIsTag(hProfile, tag16)) { - tag16 = PCS2Device16[0]; - } + if (cmsIsTag(hProfile, tagFloat)) { // Float tag takes precedence - if (cmsIsTag(hProfile, tag16)) { // Is there any LUT-Based table? + // Floating point LUT are always V4 + return _cmsReadFloatOutputTag(hProfile, tagFloat); + } - // Check profile version and LUT type. Do the necessary adjustments if needed + // Revert to perceptual if no tag is found + if (!cmsIsTag(hProfile, tag16)) { + tag16 = PCS2Device16[0]; + } - // First read the tag - cmsPipeline* Lut = (cmsPipeline*) cmsReadTag(hProfile, tag16); - if (Lut == NULL) return NULL; + if (cmsIsTag(hProfile, tag16)) { // Is there any LUT-Based table? - // After reading it, we have info about the original type - OriginalType = _cmsGetTagTrueType(hProfile, tag16); + // Check profile version and LUT type. Do the necessary adjustments if needed - // The profile owns the Lut, so we need to copy it - Lut = cmsPipelineDup(Lut); - if (Lut == NULL) return NULL; + // First read the tag + cmsPipeline* Lut = (cmsPipeline*) cmsReadTag(hProfile, tag16); + if (Lut == NULL) return NULL; - // Now it is time for a controversial stuff. I found that for 3D LUTS using - // Lab used as indexer space, trilinear interpolation should be used - if (cmsGetPCS(hProfile) == cmsSigLabData) - ChangeInterpolationToTrilinear(Lut); + // After reading it, we have info about the original type + OriginalType = _cmsGetTagTrueType(hProfile, tag16); - // We need to adjust data only for Lab and Lut16 type - if (OriginalType != cmsSigLut16Type || cmsGetPCS(hProfile) != cmsSigLabData) - return Lut; + // The profile owns the Lut, so we need to copy it + Lut = cmsPipelineDup(Lut); + if (Lut == NULL) return NULL; - // Add a matrix for conversion V4 to V2 Lab PCS - if (!cmsPipelineInsertStage(Lut, cmsAT_BEGIN, _cmsStageAllocLabV4ToV2(ContextID))) - goto Error; + // Now it is time for a controversial stuff. I found that for 3D LUTS using + // Lab used as indexer space, trilinear interpolation should be used + if (cmsGetPCS(hProfile) == cmsSigLabData) + ChangeInterpolationToTrilinear(Lut); - // If the output is Lab, add also a conversion at the end - if (cmsGetColorSpace(hProfile) == cmsSigLabData) - if (!cmsPipelineInsertStage(Lut, cmsAT_END, _cmsStageAllocLabV2ToV4(ContextID))) + // We need to adjust data only for Lab and Lut16 type + if (OriginalType != cmsSigLut16Type || cmsGetPCS(hProfile) != cmsSigLabData) + return Lut; + + // Add a matrix for conversion V4 to V2 Lab PCS + if (!cmsPipelineInsertStage(Lut, cmsAT_BEGIN, _cmsStageAllocLabV4ToV2(ContextID))) goto Error; - return Lut; + // If the output is Lab, add also a conversion at the end + if (cmsGetColorSpace(hProfile) == cmsSigLabData) + if (!cmsPipelineInsertStage(Lut, cmsAT_END, _cmsStageAllocLabV2ToV4(ContextID))) + goto Error; + + return Lut; Error: - cmsPipelineFree(Lut); - return NULL; + cmsPipelineFree(Lut); + return NULL; + } } // Lut not found, try to create a matrix-shaper @@ -782,7 +792,7 @@ Error: // Now it is time for a controversial stuff. I found that for 3D LUTS using // Lab used as indexer space, trilinear interpolation should be used - if (cmsGetColorSpace(hProfile) == cmsSigLabData) + if (cmsGetPCS(hProfile) == cmsSigLabData) ChangeInterpolationToTrilinear(Lut); // After reading it, we have info about the original type @@ -793,12 +803,12 @@ Error: // Here it is possible to get Lab on both sides - if (cmsGetPCS(hProfile) == cmsSigLabData) { + if (cmsGetColorSpace(hProfile) == cmsSigLabData) { if(!cmsPipelineInsertStage(Lut, cmsAT_BEGIN, _cmsStageAllocLabV4ToV2(ContextID))) goto Error2; } - if (cmsGetColorSpace(hProfile) == cmsSigLabData) { + if (cmsGetPCS(hProfile) == cmsSigLabData) { if(!cmsPipelineInsertStage(Lut, cmsAT_END, _cmsStageAllocLabV2ToV4(ContextID))) goto Error2; } diff --git a/jdk/src/java.desktop/share/native/liblcms/cmsopt.c b/jdk/src/java.desktop/share/native/liblcms/cmsopt.c index d184ed74b44..b9d69512cdd 100644 --- a/jdk/src/java.desktop/share/native/liblcms/cmsopt.c +++ b/jdk/src/java.desktop/share/native/liblcms/cmsopt.c @@ -542,11 +542,13 @@ cmsBool FixWhiteMisalignment(cmsPipeline* Lut, cmsColorSpaceSignature EntryColor cmsToneCurve* InversePostLin = cmsReverseToneCurve(Curves[i]); if (InversePostLin == NULL) { - WhiteOut[i] = 0; - continue; + WhiteOut[i] = WhitePointOut[i]; + + } else { + + WhiteOut[i] = cmsEvalToneCurve16(InversePostLin, WhitePointOut[i]); + cmsFreeToneCurve(InversePostLin); } - WhiteOut[i] = cmsEvalToneCurve16(InversePostLin, WhitePointOut[i]); - cmsFreeToneCurve(InversePostLin); } } else { @@ -1666,44 +1668,102 @@ static _cmsOptimizationCollection DefaultOptimization[] = { }; // The linked list head -static _cmsOptimizationCollection* OptimizationCollection = DefaultOptimization; +_cmsOptimizationPluginChunkType _cmsOptimizationPluginChunk = { NULL }; + + +// Duplicates the zone of memory used by the plug-in in the new context +static +void DupPluginOptimizationList(struct _cmsContext_struct* ctx, + const struct _cmsContext_struct* src) +{ + _cmsOptimizationPluginChunkType newHead = { NULL }; + _cmsOptimizationCollection* entry; + _cmsOptimizationCollection* Anterior = NULL; + _cmsOptimizationPluginChunkType* head = (_cmsOptimizationPluginChunkType*) src->chunks[OptimizationPlugin]; + + _cmsAssert(ctx != NULL); + _cmsAssert(head != NULL); + + // Walk the list copying all nodes + for (entry = head->OptimizationCollection; + entry != NULL; + entry = entry ->Next) { + + _cmsOptimizationCollection *newEntry = ( _cmsOptimizationCollection *) _cmsSubAllocDup(ctx ->MemPool, entry, sizeof(_cmsOptimizationCollection)); + + if (newEntry == NULL) + return; + + // We want to keep the linked list order, so this is a little bit tricky + newEntry -> Next = NULL; + if (Anterior) + Anterior -> Next = newEntry; + + Anterior = newEntry; + + if (newHead.OptimizationCollection == NULL) + newHead.OptimizationCollection = newEntry; + } + + ctx ->chunks[OptimizationPlugin] = _cmsSubAllocDup(ctx->MemPool, &newHead, sizeof(_cmsOptimizationPluginChunkType)); +} + +void _cmsAllocOptimizationPluginChunk(struct _cmsContext_struct* ctx, + const struct _cmsContext_struct* src) +{ + if (src != NULL) { + + // Copy all linked list + DupPluginOptimizationList(ctx, src); + } + else { + static _cmsOptimizationPluginChunkType OptimizationPluginChunkType = { NULL }; + ctx ->chunks[OptimizationPlugin] = _cmsSubAllocDup(ctx ->MemPool, &OptimizationPluginChunkType, sizeof(_cmsOptimizationPluginChunkType)); + } +} + // Register new ways to optimize -cmsBool _cmsRegisterOptimizationPlugin(cmsContext id, cmsPluginBase* Data) +cmsBool _cmsRegisterOptimizationPlugin(cmsContext ContextID, cmsPluginBase* Data) { cmsPluginOptimization* Plugin = (cmsPluginOptimization*) Data; + _cmsOptimizationPluginChunkType* ctx = ( _cmsOptimizationPluginChunkType*) _cmsContextGetClientChunk(ContextID, OptimizationPlugin); _cmsOptimizationCollection* fl; if (Data == NULL) { - OptimizationCollection = DefaultOptimization; + ctx->OptimizationCollection = NULL; return TRUE; } // Optimizer callback is required if (Plugin ->OptimizePtr == NULL) return FALSE; - fl = (_cmsOptimizationCollection*) _cmsPluginMalloc(id, sizeof(_cmsOptimizationCollection)); + fl = (_cmsOptimizationCollection*) _cmsPluginMalloc(ContextID, sizeof(_cmsOptimizationCollection)); if (fl == NULL) return FALSE; // Copy the parameters fl ->OptimizePtr = Plugin ->OptimizePtr; // Keep linked list - fl ->Next = OptimizationCollection; - OptimizationCollection = fl; + fl ->Next = ctx->OptimizationCollection; + + // Set the head + ctx ->OptimizationCollection = fl; // All is ok return TRUE; } // The entry point for LUT optimization -cmsBool _cmsOptimizePipeline(cmsPipeline** PtrLut, +cmsBool _cmsOptimizePipeline(cmsContext ContextID, + cmsPipeline** PtrLut, int Intent, cmsUInt32Number* InputFormat, cmsUInt32Number* OutputFormat, cmsUInt32Number* dwFlags) { + _cmsOptimizationPluginChunkType* ctx = ( _cmsOptimizationPluginChunkType*) _cmsContextGetClientChunk(ContextID, OptimizationPlugin); _cmsOptimizationCollection* Opts; cmsBool AnySuccess = FALSE; @@ -1733,8 +1793,8 @@ cmsBool _cmsOptimizePipeline(cmsPipeline** PtrLut, if (*dwFlags & cmsFLAGS_NOOPTIMIZE) return FALSE; - // Try built-in optimizations and plug-in - for (Opts = OptimizationCollection; + // Try plug-in optimizations + for (Opts = ctx->OptimizationCollection; Opts != NULL; Opts = Opts ->Next) { @@ -1745,6 +1805,17 @@ cmsBool _cmsOptimizePipeline(cmsPipeline** PtrLut, } } + // Try built-in optimizations + for (Opts = DefaultOptimization; + Opts != NULL; + Opts = Opts ->Next) { + + if (Opts ->OptimizePtr(PtrLut, Intent, InputFormat, OutputFormat, dwFlags)) { + + return TRUE; + } + } + // Only simple optimizations succeeded return AnySuccess; } diff --git a/jdk/src/java.desktop/share/native/liblcms/cmspack.c b/jdk/src/java.desktop/share/native/liblcms/cmspack.c index b89830c5506..66597747cc5 100644 --- a/jdk/src/java.desktop/share/native/liblcms/cmspack.c +++ b/jdk/src/java.desktop/share/native/liblcms/cmspack.c @@ -883,6 +883,42 @@ cmsUInt8Number* UnrollXYZDoubleTo16(register _cmsTRANSFORM* info, } } +// This is a conversion of XYZ float to 16 bits +static +cmsUInt8Number* UnrollXYZFloatTo16(register _cmsTRANSFORM* info, + register cmsUInt16Number wIn[], + register cmsUInt8Number* accum, + register cmsUInt32Number Stride) +{ + if (T_PLANAR(info -> InputFormat)) { + + cmsFloat32Number* Pt = (cmsFloat32Number*) accum; + cmsCIEXYZ XYZ; + + XYZ.X = Pt[0]; + XYZ.Y = Pt[Stride]; + XYZ.Z = Pt[Stride*2]; + cmsFloat2XYZEncoded(wIn, &XYZ); + + return accum + sizeof(cmsFloat32Number); + + } + + else { + cmsFloat32Number* Pt = (cmsFloat32Number*) accum; + cmsCIEXYZ XYZ; + + XYZ.X = Pt[0]; + XYZ.Y = Pt[1]; + XYZ.Z = Pt[2]; + cmsFloat2XYZEncoded(wIn, &XYZ); + + accum += 3 * sizeof(cmsFloat32Number) + T_EXTRA(info ->InputFormat) * sizeof(cmsFloat32Number); + + return accum; + } +} + // Check if space is marked as ink cmsINLINE cmsBool IsInkSpace(cmsUInt32Number Type) { @@ -2333,6 +2369,39 @@ cmsUInt8Number* PackXYZDoubleFrom16(register _cmsTRANSFORM* Info, } } +static +cmsUInt8Number* PackXYZFloatFrom16(register _cmsTRANSFORM* Info, + register cmsUInt16Number wOut[], + register cmsUInt8Number* output, + register cmsUInt32Number Stride) +{ + if (T_PLANAR(Info -> OutputFormat)) { + + cmsCIEXYZ XYZ; + cmsFloat32Number* Out = (cmsFloat32Number*) output; + cmsXYZEncoded2Float(&XYZ, wOut); + + Out[0] = (cmsFloat32Number) XYZ.X; + Out[Stride] = (cmsFloat32Number) XYZ.Y; + Out[Stride*2] = (cmsFloat32Number) XYZ.Z; + + return output + sizeof(cmsFloat32Number); + + } + else { + + cmsCIEXYZ XYZ; + cmsFloat32Number* Out = (cmsFloat32Number*) output; + cmsXYZEncoded2Float(&XYZ, wOut); + + Out[0] = (cmsFloat32Number) XYZ.X; + Out[1] = (cmsFloat32Number) XYZ.Y; + Out[2] = (cmsFloat32Number) XYZ.Z; + + return output + (3 * sizeof(cmsFloat32Number) + T_EXTRA(Info ->OutputFormat) * sizeof(cmsFloat32Number)); + } +} + static cmsUInt8Number* PackDoubleFrom16(register _cmsTRANSFORM* info, register cmsUInt16Number wOut[], @@ -2893,6 +2962,7 @@ static cmsFormatters16 InputFormatters16[] = { { TYPE_Lab_DBL, ANYPLANAR|ANYEXTRA, UnrollLabDoubleTo16}, { TYPE_XYZ_DBL, ANYPLANAR|ANYEXTRA, UnrollXYZDoubleTo16}, { TYPE_Lab_FLT, ANYPLANAR|ANYEXTRA, UnrollLabFloatTo16}, + { TYPE_XYZ_FLT, ANYPLANAR|ANYEXTRA, UnrollXYZFloatTo16}, { TYPE_GRAY_DBL, 0, UnrollDouble1Chan}, { FLOAT_SH(1)|BYTES_SH(0), ANYCHANNELS|ANYPLANAR|ANYSWAPFIRST|ANYFLAVOR| ANYSWAP|ANYEXTRA|ANYSPACE, UnrollDoubleTo16}, @@ -3027,6 +3097,7 @@ static cmsFormatters16 OutputFormatters16[] = { { TYPE_XYZ_DBL, ANYPLANAR|ANYEXTRA, PackXYZDoubleFrom16}, { TYPE_Lab_FLT, ANYPLANAR|ANYEXTRA, PackLabFloatFrom16}, + { TYPE_XYZ_FLT, ANYPLANAR|ANYEXTRA, PackXYZFloatFrom16}, { FLOAT_SH(1)|BYTES_SH(0), ANYFLAVOR|ANYSWAPFIRST|ANYSWAP| ANYCHANNELS|ANYPLANAR|ANYEXTRA|ANYSPACE, PackDoubleFrom16}, @@ -3182,40 +3253,98 @@ typedef struct _cms_formatters_factory_list { } cmsFormattersFactoryList; -static cmsFormattersFactoryList* FactoryList = NULL; +_cmsFormattersPluginChunkType _cmsFormattersPluginChunk = { NULL }; + + +// Duplicates the zone of memory used by the plug-in in the new context +static +void DupFormatterFactoryList(struct _cmsContext_struct* ctx, + const struct _cmsContext_struct* src) +{ + _cmsFormattersPluginChunkType newHead = { NULL }; + cmsFormattersFactoryList* entry; + cmsFormattersFactoryList* Anterior = NULL; + _cmsFormattersPluginChunkType* head = (_cmsFormattersPluginChunkType*) src->chunks[FormattersPlugin]; + + _cmsAssert(head != NULL); + + // Walk the list copying all nodes + for (entry = head->FactoryList; + entry != NULL; + entry = entry ->Next) { + + cmsFormattersFactoryList *newEntry = ( cmsFormattersFactoryList *) _cmsSubAllocDup(ctx ->MemPool, entry, sizeof(cmsFormattersFactoryList)); + + if (newEntry == NULL) + return; + + // We want to keep the linked list order, so this is a little bit tricky + newEntry -> Next = NULL; + if (Anterior) + Anterior -> Next = newEntry; + + Anterior = newEntry; + + if (newHead.FactoryList == NULL) + newHead.FactoryList = newEntry; + } + + ctx ->chunks[FormattersPlugin] = _cmsSubAllocDup(ctx->MemPool, &newHead, sizeof(_cmsFormattersPluginChunkType)); +} + +// The interpolation plug-in memory chunk allocator/dup +void _cmsAllocFormattersPluginChunk(struct _cmsContext_struct* ctx, + const struct _cmsContext_struct* src) +{ + _cmsAssert(ctx != NULL); + + if (src != NULL) { + + // Duplicate the LIST + DupFormatterFactoryList(ctx, src); + } + else { + static _cmsFormattersPluginChunkType FormattersPluginChunk = { NULL }; + ctx ->chunks[FormattersPlugin] = _cmsSubAllocDup(ctx ->MemPool, &FormattersPluginChunk, sizeof(_cmsFormattersPluginChunkType)); + } +} + // Formatters management -cmsBool _cmsRegisterFormattersPlugin(cmsContext id, cmsPluginBase* Data) +cmsBool _cmsRegisterFormattersPlugin(cmsContext ContextID, cmsPluginBase* Data) { + _cmsFormattersPluginChunkType* ctx = ( _cmsFormattersPluginChunkType*) _cmsContextGetClientChunk(ContextID, FormattersPlugin); cmsPluginFormatters* Plugin = (cmsPluginFormatters*) Data; cmsFormattersFactoryList* fl ; - // Reset + // Reset to built-in defaults if (Data == NULL) { - FactoryList = NULL; + ctx ->FactoryList = NULL; return TRUE; } - fl = (cmsFormattersFactoryList*) _cmsPluginMalloc(id, sizeof(cmsFormattersFactoryList)); + fl = (cmsFormattersFactoryList*) _cmsPluginMalloc(ContextID, sizeof(cmsFormattersFactoryList)); if (fl == NULL) return FALSE; fl ->Factory = Plugin ->FormattersFactory; - fl ->Next = FactoryList; - FactoryList = fl; + fl ->Next = ctx -> FactoryList; + ctx ->FactoryList = fl; return TRUE; } -cmsFormatter _cmsGetFormatter(cmsUInt32Number Type, // Specific type, i.e. TYPE_RGB_8 +cmsFormatter _cmsGetFormatter(cmsContext ContextID, + cmsUInt32Number Type, // Specific type, i.e. TYPE_RGB_8 cmsFormatterDirection Dir, cmsUInt32Number dwFlags) { + _cmsFormattersPluginChunkType* ctx = ( _cmsFormattersPluginChunkType*) _cmsContextGetClientChunk(ContextID, FormattersPlugin); cmsFormattersFactoryList* f; - for (f = FactoryList; f != NULL; f = f ->Next) { + for (f =ctx->FactoryList; f != NULL; f = f ->Next) { cmsFormatter fn = f ->Factory(Type, Dir, dwFlags); if (fn.Fmt16 != NULL) return fn; diff --git a/jdk/src/java.desktop/share/native/liblcms/cmsplugin.c b/jdk/src/java.desktop/share/native/liblcms/cmsplugin.c index 3d434859e09..ef75e13935b 100644 --- a/jdk/src/java.desktop/share/native/liblcms/cmsplugin.c +++ b/jdk/src/java.desktop/share/native/liblcms/cmsplugin.c @@ -544,22 +544,31 @@ cmsBool CMSEXPORT _cmsIOPrintf(cmsIOHANDLER* io, const char* frm, ...) // Plugin memory management ------------------------------------------------------------------------------------------------- -static _cmsSubAllocator* PluginPool = NULL; - // Specialized malloc for plug-ins, that is freed upon exit. -void* _cmsPluginMalloc(cmsContext id, cmsUInt32Number size) +void* _cmsPluginMalloc(cmsContext ContextID, cmsUInt32Number size) { - if (PluginPool == NULL) - PluginPool = _cmsCreateSubAlloc(id, 4*1024); + struct _cmsContext_struct* ctx = _cmsGetContext(ContextID); - return _cmsSubAlloc(PluginPool, size); + if (ctx ->MemPool == NULL) { + + if (ContextID == NULL) { + + ctx->MemPool = _cmsCreateSubAlloc(0, 2*1024); + } + else { + cmsSignalError(ContextID, cmsERROR_CORRUPTION_DETECTED, "NULL memory pool on context"); + return NULL; + } + } + + return _cmsSubAlloc(ctx->MemPool, size); } // Main plug-in dispatcher cmsBool CMSEXPORT cmsPlugin(void* Plug_in) { - return cmsPluginTHR(NULL, Plug_in); + return cmsPluginTHR(NULL, Plug_in); } cmsBool CMSEXPORT cmsPluginTHR(cmsContext id, void* Plug_in) @@ -571,12 +580,12 @@ cmsBool CMSEXPORT cmsPluginTHR(cmsContext id, void* Plug_in) Plugin = Plugin -> Next) { if (Plugin -> Magic != cmsPluginMagicNumber) { - cmsSignalError(0, cmsERROR_UNKNOWN_EXTENSION, "Unrecognized plugin"); + cmsSignalError(id, cmsERROR_UNKNOWN_EXTENSION, "Unrecognized plugin"); return FALSE; } if (Plugin ->ExpectedVersion > LCMS_VERSION) { - cmsSignalError(0, cmsERROR_UNKNOWN_EXTENSION, "plugin needs Little CMS %d, current version is %d", + cmsSignalError(id, cmsERROR_UNKNOWN_EXTENSION, "plugin needs Little CMS %d, current version is %d", Plugin ->ExpectedVersion, LCMS_VERSION); return FALSE; } @@ -584,11 +593,11 @@ cmsBool CMSEXPORT cmsPluginTHR(cmsContext id, void* Plug_in) switch (Plugin -> Type) { case cmsPluginMemHandlerSig: - if (!_cmsRegisterMemHandlerPlugin(Plugin)) return FALSE; + if (!_cmsRegisterMemHandlerPlugin(id, Plugin)) return FALSE; break; case cmsPluginInterpolationSig: - if (!_cmsRegisterInterpPlugin(Plugin)) return FALSE; + if (!_cmsRegisterInterpPlugin(id, Plugin)) return FALSE; break; case cmsPluginTagTypeSig: @@ -623,8 +632,12 @@ cmsBool CMSEXPORT cmsPluginTHR(cmsContext id, void* Plug_in) if (!_cmsRegisterTransformPlugin(id, Plugin)) return FALSE; break; + case cmsPluginMutexSig: + if (!_cmsRegisterMutexPlugin(id, Plugin)) return FALSE; + break; + default: - cmsSignalError(0, cmsERROR_UNKNOWN_EXTENSION, "Unrecognized plugin type '%X'", Plugin -> Type); + cmsSignalError(id, cmsERROR_UNKNOWN_EXTENSION, "Unrecognized plugin type '%X'", Plugin -> Type); return FALSE; } } @@ -637,19 +650,337 @@ cmsBool CMSEXPORT cmsPluginTHR(cmsContext id, void* Plug_in) // Revert all plug-ins to default void CMSEXPORT cmsUnregisterPlugins(void) { - _cmsRegisterMemHandlerPlugin(NULL); - _cmsRegisterInterpPlugin(NULL); - _cmsRegisterTagTypePlugin(NULL, NULL); - _cmsRegisterTagPlugin(NULL, NULL); - _cmsRegisterFormattersPlugin(NULL, NULL); - _cmsRegisterRenderingIntentPlugin(NULL, NULL); - _cmsRegisterParametricCurvesPlugin(NULL, NULL); - _cmsRegisterMultiProcessElementPlugin(NULL, NULL); - _cmsRegisterOptimizationPlugin(NULL, NULL); - _cmsRegisterTransformPlugin(NULL, NULL); - - if (PluginPool != NULL) - _cmsSubAllocDestroy(PluginPool); - - PluginPool = NULL; + cmsUnregisterPluginsTHR(NULL); } + + +// The Global storage for system context. This is the one and only global variable +// pointers structure. All global vars are referenced here. +static struct _cmsContext_struct globalContext = { + + NULL, // Not in the linked list + NULL, // No suballocator + { + NULL, // UserPtr, + &_cmsLogErrorChunk, // Logger, + &_cmsAlarmCodesChunk, // AlarmCodes, + &_cmsAdaptationStateChunk, // AdaptationState, + &_cmsMemPluginChunk, // MemPlugin, + &_cmsInterpPluginChunk, // InterpPlugin, + &_cmsCurvesPluginChunk, // CurvesPlugin, + &_cmsFormattersPluginChunk, // FormattersPlugin, + &_cmsTagTypePluginChunk, // TagTypePlugin, + &_cmsTagPluginChunk, // TagPlugin, + &_cmsIntentsPluginChunk, // IntentPlugin, + &_cmsMPETypePluginChunk, // MPEPlugin, + &_cmsOptimizationPluginChunk, // OptimizationPlugin, + &_cmsTransformPluginChunk, // TransformPlugin, + &_cmsMutexPluginChunk // MutexPlugin + }, + + { NULL, NULL, NULL, NULL, NULL, NULL } // The default memory allocator is not used for context 0 +}; + + +// The context pool (linked list head) +static _cmsMutex _cmsContextPoolHeadMutex = CMS_MUTEX_INITIALIZER; +static struct _cmsContext_struct* _cmsContextPoolHead = NULL; + +// Internal, get associated pointer, with guessing. Never returns NULL. +struct _cmsContext_struct* _cmsGetContext(cmsContext ContextID) +{ + struct _cmsContext_struct* id = (struct _cmsContext_struct*) ContextID; + struct _cmsContext_struct* ctx; + + + // On 0, use global settings + if (id == NULL) + return &globalContext; + + // Search + for (ctx = _cmsContextPoolHead; + ctx != NULL; + ctx = ctx ->Next) { + + // Found it? + if (id == ctx) + return ctx; // New-style context, + } + + return &globalContext; +} + + +// Internal: get the memory area associanted with each context client +// Returns the block assigned to the specific zone. +void* _cmsContextGetClientChunk(cmsContext ContextID, _cmsMemoryClient mc) +{ + struct _cmsContext_struct* ctx; + void *ptr; + + if (mc < 0 || mc >= MemoryClientMax) { + cmsSignalError(ContextID, cmsERROR_RANGE, "Bad context client"); + return NULL; + } + + ctx = _cmsGetContext(ContextID); + ptr = ctx ->chunks[mc]; + + if (ptr != NULL) + return ptr; + + // A null ptr means no special settings for that context, and this + // reverts to Context0 globals + return globalContext.chunks[mc]; +} + + +// This function returns the given context its default pristine state, +// as no plug-ins were declared. There is no way to unregister a single +// plug-in, as a single call to cmsPluginTHR() function may register +// many different plug-ins simultaneously, then there is no way to +// identify which plug-in to unregister. +void CMSEXPORT cmsUnregisterPluginsTHR(cmsContext ContextID) +{ + _cmsRegisterMemHandlerPlugin(ContextID, NULL); + _cmsRegisterInterpPlugin(ContextID, NULL); + _cmsRegisterTagTypePlugin(ContextID, NULL); + _cmsRegisterTagPlugin(ContextID, NULL); + _cmsRegisterFormattersPlugin(ContextID, NULL); + _cmsRegisterRenderingIntentPlugin(ContextID, NULL); + _cmsRegisterParametricCurvesPlugin(ContextID, NULL); + _cmsRegisterMultiProcessElementPlugin(ContextID, NULL); + _cmsRegisterOptimizationPlugin(ContextID, NULL); + _cmsRegisterTransformPlugin(ContextID, NULL); + _cmsRegisterMutexPlugin(ContextID, NULL); +} + + +// Returns the memory manager plug-in, if any, from the Plug-in bundle +static +cmsPluginMemHandler* _cmsFindMemoryPlugin(void* PluginBundle) +{ + cmsPluginBase* Plugin; + + for (Plugin = (cmsPluginBase*) PluginBundle; + Plugin != NULL; + Plugin = Plugin -> Next) { + + if (Plugin -> Magic == cmsPluginMagicNumber && + Plugin -> ExpectedVersion <= LCMS_VERSION && + Plugin -> Type == cmsPluginMemHandlerSig) { + + // Found! + return (cmsPluginMemHandler*) Plugin; + } + } + + // Nope, revert to defaults + return NULL; +} + + +// Creates a new context with optional associated plug-ins. Caller may also specify an optional pointer to user-defined +// data that will be forwarded to plug-ins and logger. +cmsContext CMSEXPORT cmsCreateContext(void* Plugin, void* UserData) +{ + struct _cmsContext_struct* ctx; + struct _cmsContext_struct fakeContext; + + _cmsInstallAllocFunctions(_cmsFindMemoryPlugin(Plugin), &fakeContext.DefaultMemoryManager); + + fakeContext.chunks[UserPtr] = UserData; + fakeContext.chunks[MemPlugin] = &fakeContext.DefaultMemoryManager; + + // Create the context structure. + ctx = (struct _cmsContext_struct*) _cmsMalloc(&fakeContext, sizeof(struct _cmsContext_struct)); + if (ctx == NULL) + return NULL; // Something very wrong happened! + + // Init the structure and the memory manager + memset(ctx, 0, sizeof(struct _cmsContext_struct)); + + // Keep memory manager + memcpy(&ctx->DefaultMemoryManager, &fakeContext.DefaultMemoryManager, sizeof(_cmsMemPluginChunk)); + + // Maintain the linked list (with proper locking) + _cmsEnterCriticalSectionPrimitive(&_cmsContextPoolHeadMutex); + ctx ->Next = _cmsContextPoolHead; + _cmsContextPoolHead = ctx; + _cmsLeaveCriticalSectionPrimitive(&_cmsContextPoolHeadMutex); + + ctx ->chunks[UserPtr] = UserData; + ctx ->chunks[MemPlugin] = &ctx->DefaultMemoryManager; + + // Now we can allocate the pool by using default memory manager + ctx ->MemPool = _cmsCreateSubAlloc(ctx, 22 * sizeof(void*)); // default size about 32 pointers + if (ctx ->MemPool == NULL) { + + cmsDeleteContext(ctx); + return NULL; + } + + _cmsAllocLogErrorChunk(ctx, NULL); + _cmsAllocAlarmCodesChunk(ctx, NULL); + _cmsAllocAdaptationStateChunk(ctx, NULL); + _cmsAllocMemPluginChunk(ctx, NULL); + _cmsAllocInterpPluginChunk(ctx, NULL); + _cmsAllocCurvesPluginChunk(ctx, NULL); + _cmsAllocFormattersPluginChunk(ctx, NULL); + _cmsAllocTagTypePluginChunk(ctx, NULL); + _cmsAllocMPETypePluginChunk(ctx, NULL); + _cmsAllocTagPluginChunk(ctx, NULL); + _cmsAllocIntentsPluginChunk(ctx, NULL); + _cmsAllocOptimizationPluginChunk(ctx, NULL); + _cmsAllocTransformPluginChunk(ctx, NULL); + _cmsAllocMutexPluginChunk(ctx, NULL); + + // Setup the plug-ins + if (!cmsPluginTHR(ctx, Plugin)) { + + cmsDeleteContext(ctx); + return NULL; + } + + return (cmsContext) ctx; +} + +// Duplicates a context with all associated plug-ins. +// Caller may specify an optional pointer to user-defined +// data that will be forwarded to plug-ins and logger. +cmsContext CMSEXPORT cmsDupContext(cmsContext ContextID, void* NewUserData) +{ + int i; + struct _cmsContext_struct* ctx; + const struct _cmsContext_struct* src = _cmsGetContext(ContextID); + + void* userData = (NewUserData != NULL) ? NewUserData : src -> chunks[UserPtr]; + + + ctx = (struct _cmsContext_struct*) _cmsMalloc(ContextID, sizeof(struct _cmsContext_struct)); + if (ctx == NULL) + return NULL; // Something very wrong happened + + // Setup default memory allocators + memcpy(&ctx->DefaultMemoryManager, &src->DefaultMemoryManager, sizeof(ctx->DefaultMemoryManager)); + + // Maintain the linked list + _cmsEnterCriticalSectionPrimitive(&_cmsContextPoolHeadMutex); + ctx ->Next = _cmsContextPoolHead; + _cmsContextPoolHead = ctx; + _cmsLeaveCriticalSectionPrimitive(&_cmsContextPoolHeadMutex); + + ctx ->chunks[UserPtr] = userData; + ctx ->chunks[MemPlugin] = &ctx->DefaultMemoryManager; + + ctx ->MemPool = _cmsCreateSubAlloc(ctx, 22 * sizeof(void*)); + if (ctx ->MemPool == NULL) { + + cmsDeleteContext(ctx); + return NULL; + } + + // Allocate all required chunks. + _cmsAllocLogErrorChunk(ctx, src); + _cmsAllocAlarmCodesChunk(ctx, src); + _cmsAllocAdaptationStateChunk(ctx, src); + _cmsAllocMemPluginChunk(ctx, src); + _cmsAllocInterpPluginChunk(ctx, src); + _cmsAllocCurvesPluginChunk(ctx, src); + _cmsAllocFormattersPluginChunk(ctx, src); + _cmsAllocTagTypePluginChunk(ctx, src); + _cmsAllocMPETypePluginChunk(ctx, src); + _cmsAllocTagPluginChunk(ctx, src); + _cmsAllocIntentsPluginChunk(ctx, src); + _cmsAllocOptimizationPluginChunk(ctx, src); + _cmsAllocTransformPluginChunk(ctx, src); + _cmsAllocMutexPluginChunk(ctx, src); + + // Make sure no one failed + for (i=Logger; i < MemoryClientMax; i++) { + + if (src ->chunks[i] == NULL) { + cmsDeleteContext((cmsContext) ctx); + return NULL; + } + } + + return (cmsContext) ctx; +} + + + +static +struct _cmsContext_struct* FindPrev(struct _cmsContext_struct* id) +{ + struct _cmsContext_struct* prev; + + // Search for previous + for (prev = _cmsContextPoolHead; + prev != NULL; + prev = prev ->Next) + { + if (prev ->Next == id) + return prev; + } + + return NULL; // List is empty or only one element! +} + +// Frees any resources associated with the given context, +// and destroys the context placeholder. +// The ContextID can no longer be used in any THR operation. +void CMSEXPORT cmsDeleteContext(cmsContext ContextID) +{ + if (ContextID != NULL) { + + struct _cmsContext_struct* ctx = (struct _cmsContext_struct*) ContextID; + struct _cmsContext_struct fakeContext; + struct _cmsContext_struct* prev; + + memcpy(&fakeContext.DefaultMemoryManager, &ctx->DefaultMemoryManager, sizeof(ctx->DefaultMemoryManager)); + + fakeContext.chunks[UserPtr] = ctx ->chunks[UserPtr]; + fakeContext.chunks[MemPlugin] = &fakeContext.DefaultMemoryManager; + + // Get rid of plugins + cmsUnregisterPluginsTHR(ContextID); + + // Since all memory is allocated in the private pool, all what we need to do is destroy the pool + if (ctx -> MemPool != NULL) + _cmsSubAllocDestroy(ctx ->MemPool); + ctx -> MemPool = NULL; + + // Maintain list + _cmsEnterCriticalSectionPrimitive(&_cmsContextPoolHeadMutex); + if (_cmsContextPoolHead == ctx) { + + _cmsContextPoolHead = ctx->Next; + } + else { + + // Search for previous + for (prev = _cmsContextPoolHead; + prev != NULL; + prev = prev ->Next) + { + if (prev -> Next == ctx) { + prev -> Next = ctx ->Next; + break; + } + } + } + _cmsLeaveCriticalSectionPrimitive(&_cmsContextPoolHeadMutex); + + // free the memory block itself + _cmsFree(&fakeContext, ctx); + } +} + +// Returns the user data associated to the given ContextID, or NULL if no user data was attached on context creation +void* CMSEXPORT cmsGetContextUserData(cmsContext ContextID) +{ + return _cmsContextGetClientChunk(ContextID, UserPtr); +} + + diff --git a/jdk/src/java.desktop/share/native/liblcms/cmsps2.c b/jdk/src/java.desktop/share/native/liblcms/cmsps2.c index 2da5a2b6a0d..22089d094ab 100644 --- a/jdk/src/java.desktop/share/native/liblcms/cmsps2.c +++ b/jdk/src/java.desktop/share/native/liblcms/cmsps2.c @@ -942,7 +942,7 @@ int WriteInputLUT(cmsIOHANDLER* m, cmsHPROFILE hProfile, int Intent, cmsUInt32Nu if (DeviceLink == NULL) return 0; dwFlags |= cmsFLAGS_FORCE_CLUT; - _cmsOptimizePipeline(&DeviceLink, Intent, &InputFormat, &OutFrm, &dwFlags); + _cmsOptimizePipeline(m->ContextID, &DeviceLink, Intent, &InputFormat, &OutFrm, &dwFlags); rc = EmitCIEBasedDEF(m, DeviceLink, Intent, &BlackPointAdaptedToD50); cmsPipelineFree(DeviceLink); @@ -1359,7 +1359,7 @@ int WriteOutputLUT(cmsIOHANDLER* m, cmsHPROFILE hProfile, int Intent, cmsUInt32N // We need a CLUT dwFlags |= cmsFLAGS_FORCE_CLUT; - _cmsOptimizePipeline(&DeviceLink, RelativeEncodingIntent, &InFrm, &OutputFormat, &dwFlags); + _cmsOptimizePipeline(m->ContextID, &DeviceLink, RelativeEncodingIntent, &InFrm, &OutputFormat, &dwFlags); _cmsIOPrintf(m, "<<\n"); _cmsIOPrintf(m, "/ColorRenderingType 1\n"); diff --git a/jdk/src/java.desktop/share/native/liblcms/cmstypes.c b/jdk/src/java.desktop/share/native/liblcms/cmstypes.c index f434cfde6b0..08cad5ea619 100644 --- a/jdk/src/java.desktop/share/native/liblcms/cmstypes.c +++ b/jdk/src/java.desktop/share/native/liblcms/cmstypes.c @@ -30,7 +30,7 @@ //--------------------------------------------------------------------------------- // // Little Color Management System -// Copyright (c) 1998-2011 Marti Maria Saguer +// Copyright (c) 1998-2014 Marti Maria Saguer // // Permission is hereby granted, free of charge, to any person obtaining // a copy of this software and associated documentation files (the "Software"), @@ -61,7 +61,7 @@ // are no profiles holding them. The programmer can also extend this list by defining his own types // by using the appropiate plug-in. There are three types of plug ins regarding that. First type // allows to define new tags using any existing type. Next plug-in type allows to define new types -// and the third one is very specific: allows to extend the number of elements in the multiprofile +// and the third one is very specific: allows to extend the number of elements in the multiprocessing // elements special type. //-------------------------------------------------------------------------------------------------- @@ -89,54 +89,49 @@ typedef struct _cmsTagTypeLinkedList_st { // Helper macro to define a MPE handler. Callbacks do have a fixed naming convention #define TYPE_MPE_HANDLER(t, x) { (t), READ_FN(x), WRITE_FN(x), GenericMPEdup, GenericMPEfree, NULL, 0 } -// Register a new type handler. This routine is shared between normal types and MPE +// Register a new type handler. This routine is shared between normal types and MPE. LinkedList points to the optional list head static -cmsBool RegisterTypesPlugin(cmsContext id, cmsPluginBase* Data, _cmsTagTypeLinkedList* LinkedList, cmsUInt32Number DefaultListCount) +cmsBool RegisterTypesPlugin(cmsContext id, cmsPluginBase* Data, _cmsMemoryClient pos) { cmsPluginTagType* Plugin = (cmsPluginTagType*) Data; - _cmsTagTypeLinkedList *pt, *Anterior = NULL; + _cmsTagTypePluginChunkType* ctx = ( _cmsTagTypePluginChunkType*) _cmsContextGetClientChunk(id, pos); + _cmsTagTypeLinkedList *pt; // Calling the function with NULL as plug-in would unregister the plug in. if (Data == NULL) { - LinkedList[DefaultListCount-1].Next = NULL; + // There is no need to set free the memory, as pool is destroyed as a whole. + ctx ->TagTypes = NULL; return TRUE; } - pt = Anterior = LinkedList; - while (pt != NULL) { - - if (Plugin->Handler.Signature == pt -> Handler.Signature) { - pt ->Handler = Plugin ->Handler; // Replace old behaviour. - // Note that since no memory is allocated, unregister does not - // reset this action. - return TRUE; - } - - Anterior = pt; - pt = pt ->Next; - } - - // Registering happens in plug-in memory pool + // Registering happens in plug-in memory pool. pt = (_cmsTagTypeLinkedList*) _cmsPluginMalloc(id, sizeof(_cmsTagTypeLinkedList)); if (pt == NULL) return FALSE; pt ->Handler = Plugin ->Handler; - pt ->Next = NULL; + pt ->Next = ctx ->TagTypes; - if (Anterior) - Anterior -> Next = pt; + ctx ->TagTypes = pt; return TRUE; } -// Return handler for a given type or NULL if not found. Shared between normal types and MPE +// Return handler for a given type or NULL if not found. Shared between normal types and MPE. It first tries the additons +// made by plug-ins and then the built-in defaults. static -cmsTagTypeHandler* GetHandler(cmsTagTypeSignature sig, _cmsTagTypeLinkedList* LinkedList) +cmsTagTypeHandler* GetHandler(cmsTagTypeSignature sig, _cmsTagTypeLinkedList* PluginLinkedList, _cmsTagTypeLinkedList* DefaultLinkedList) { _cmsTagTypeLinkedList* pt; - for (pt = LinkedList; + for (pt = PluginLinkedList; + pt != NULL; + pt = pt ->Next) { + + if (sig == pt -> Handler.Signature) return &pt ->Handler; + } + + for (pt = DefaultLinkedList; pt != NULL; pt = pt ->Next) { @@ -163,6 +158,7 @@ cmsBool _cmsWriteWCharArray(cmsIOHANDLER* io, cmsUInt32Number n, const wchar_t* return TRUE; } +// Auxiliar to read an array of wchar_t static cmsBool _cmsReadWCharArray(cmsIOHANDLER* io, cmsUInt32Number n, wchar_t* Array) { @@ -777,6 +773,8 @@ cmsBool Type_Text_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, // Create memory Text = (char*) _cmsMalloc(self ->ContextID, size); + if (Text == NULL) return FALSE; + cmsMLUgetASCII(mlu, cmsNoLanguage, cmsNoCountry, Text, size); // Write it, including separator @@ -1783,7 +1781,6 @@ void *Type_LUT8_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cms if (!_cmsReadUInt8Number(io, NULL)) goto Error; // Do some checking - if (InputChannels > cmsMAXCHANNELS) goto Error; if (OutputChannels > cmsMAXCHANNELS) goto Error; @@ -1824,9 +1821,16 @@ void *Type_LUT8_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cms if (T == NULL) goto Error; Temp = (cmsUInt8Number*) _cmsMalloc(self ->ContextID, nTabSize); - if (Temp == NULL) goto Error; + if (Temp == NULL) { + _cmsFree(self ->ContextID, T); + goto Error; + } - if (io ->Read(io, Temp, nTabSize, 1) != 1) goto Error; + if (io ->Read(io, Temp, nTabSize, 1) != 1) { + _cmsFree(self ->ContextID, T); + _cmsFree(self ->ContextID, Temp); + goto Error; + } for (i = 0; i < nTabSize; i++) { @@ -2371,27 +2375,30 @@ cmsStage* ReadCLUT(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUI // Precision can be 1 or 2 bytes if (Precision == 1) { - cmsUInt8Number v; + cmsUInt8Number v; for (i=0; i < Data ->nEntries; i++) { - if (io ->Read(io, &v, sizeof(cmsUInt8Number), 1) != 1) return NULL; - Data ->Tab.T[i] = FROM_8_TO_16(v); + if (io ->Read(io, &v, sizeof(cmsUInt8Number), 1) != 1) return NULL; + Data ->Tab.T[i] = FROM_8_TO_16(v); } } else if (Precision == 2) { - if (!_cmsReadUInt16Array(io, Data->nEntries, Data ->Tab.T)) return NULL; - } - else { - cmsSignalError(self ->ContextID, cmsERROR_UNKNOWN_EXTENSION, "Unknown precision of '%d'", Precision); - return NULL; - } + if (!_cmsReadUInt16Array(io, Data->nEntries, Data ->Tab.T)) { + cmsStageFree(CLUT); + return NULL; + } + } + else { + cmsStageFree(CLUT); + cmsSignalError(self ->ContextID, cmsERROR_UNKNOWN_EXTENSION, "Unknown precision of '%d'", Precision); + return NULL; + } - - return CLUT; + return CLUT; } static @@ -4374,7 +4381,7 @@ static _cmsTagTypeLinkedList SupportedMPEtypes[] = { {TYPE_MPE_HANDLER((cmsTagTypeSignature) cmsSigCLutElemType, MPEclut), NULL }, }; -#define DEFAULT_MPE_TYPE_COUNT (sizeof(SupportedMPEtypes) / sizeof(_cmsTagTypeLinkedList)) +_cmsTagTypePluginChunkType _cmsMPETypePluginChunk = { NULL }; static cmsBool ReadMPEElem(struct _cms_typehandler_struct* self, @@ -4387,6 +4394,8 @@ cmsBool ReadMPEElem(struct _cms_typehandler_struct* self, cmsTagTypeHandler* TypeHandler; cmsUInt32Number nItems; cmsPipeline *NewLUT = (cmsPipeline *) Cargo; + _cmsTagTypePluginChunkType* MPETypePluginChunk = ( _cmsTagTypePluginChunkType*) _cmsContextGetClientChunk(self->ContextID, MPEPlugin); + // Take signature and channels for each element. if (!_cmsReadUInt32Number(io, (cmsUInt32Number*) &ElementSig)) return FALSE; @@ -4395,7 +4404,7 @@ cmsBool ReadMPEElem(struct _cms_typehandler_struct* self, if (!_cmsReadUInt32Number(io, NULL)) return FALSE; // Read diverse MPE types - TypeHandler = GetHandler((cmsTagTypeSignature) ElementSig, SupportedMPEtypes); + TypeHandler = GetHandler((cmsTagTypeSignature) ElementSig, MPETypePluginChunk ->TagTypes, SupportedMPEtypes); if (TypeHandler == NULL) { char String[5]; @@ -4472,6 +4481,7 @@ cmsBool Type_MPE_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, v cmsPipeline* Lut = (cmsPipeline*) Ptr; cmsStage* Elem = Lut ->Elements; cmsTagTypeHandler* TypeHandler; + _cmsTagTypePluginChunkType* MPETypePluginChunk = ( _cmsTagTypePluginChunkType*) _cmsContextGetClientChunk(self->ContextID, MPEPlugin); BaseOffset = io ->Tell(io) - sizeof(_cmsTagBase); @@ -4505,7 +4515,7 @@ cmsBool Type_MPE_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, v ElementSig = Elem ->Type; - TypeHandler = GetHandler((cmsTagTypeSignature) ElementSig, SupportedMPEtypes); + TypeHandler = GetHandler((cmsTagTypeSignature) ElementSig, MPETypePluginChunk->TagTypes, SupportedMPEtypes); if (TypeHandler == NULL) { char String[5]; @@ -5125,7 +5135,7 @@ void *Type_Dictionary_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* i } else { - rc = cmsDictAddEntry(hDict, NameWCS, ValueWCS, DisplayNameMLU, DisplayValueMLU); + rc = cmsDictAddEntry(hDict, NameWCS, ValueWCS, DisplayNameMLU, DisplayValueMLU); } if (NameWCS != NULL) _cmsFree(self ->ContextID, NameWCS); @@ -5282,24 +5292,95 @@ static _cmsTagTypeLinkedList SupportedTagTypes[] = { {TYPE_HANDLER(cmsSigVcgtType, vcgt), NULL } }; -#define DEFAULT_TAG_TYPE_COUNT (sizeof(SupportedTagTypes) / sizeof(_cmsTagTypeLinkedList)) + +_cmsTagTypePluginChunkType _cmsTagTypePluginChunk = { NULL }; + + + +// Duplicates the zone of memory used by the plug-in in the new context +static +void DupTagTypeList(struct _cmsContext_struct* ctx, + const struct _cmsContext_struct* src, + int loc) +{ + _cmsTagTypePluginChunkType newHead = { NULL }; + _cmsTagTypeLinkedList* entry; + _cmsTagTypeLinkedList* Anterior = NULL; + _cmsTagTypePluginChunkType* head = (_cmsTagTypePluginChunkType*) src->chunks[loc]; + + // Walk the list copying all nodes + for (entry = head->TagTypes; + entry != NULL; + entry = entry ->Next) { + + _cmsTagTypeLinkedList *newEntry = ( _cmsTagTypeLinkedList *) _cmsSubAllocDup(ctx ->MemPool, entry, sizeof(_cmsTagTypeLinkedList)); + + if (newEntry == NULL) + return; + + // We want to keep the linked list order, so this is a little bit tricky + newEntry -> Next = NULL; + if (Anterior) + Anterior -> Next = newEntry; + + Anterior = newEntry; + + if (newHead.TagTypes == NULL) + newHead.TagTypes = newEntry; + } + + ctx ->chunks[loc] = _cmsSubAllocDup(ctx->MemPool, &newHead, sizeof(_cmsTagTypePluginChunkType)); +} + + +void _cmsAllocTagTypePluginChunk(struct _cmsContext_struct* ctx, + const struct _cmsContext_struct* src) +{ + if (src != NULL) { + + // Duplicate the LIST + DupTagTypeList(ctx, src, TagTypePlugin); + } + else { + static _cmsTagTypePluginChunkType TagTypePluginChunk = { NULL }; + ctx ->chunks[TagTypePlugin] = _cmsSubAllocDup(ctx ->MemPool, &TagTypePluginChunk, sizeof(_cmsTagTypePluginChunkType)); + } +} + +void _cmsAllocMPETypePluginChunk(struct _cmsContext_struct* ctx, + const struct _cmsContext_struct* src) +{ + if (src != NULL) { + + // Duplicate the LIST + DupTagTypeList(ctx, src, MPEPlugin); + } + else { + static _cmsTagTypePluginChunkType TagTypePluginChunk = { NULL }; + ctx ->chunks[MPEPlugin] = _cmsSubAllocDup(ctx ->MemPool, &TagTypePluginChunk, sizeof(_cmsTagTypePluginChunkType)); + } + +} + // Both kind of plug-ins share same structure cmsBool _cmsRegisterTagTypePlugin(cmsContext id, cmsPluginBase* Data) { - return RegisterTypesPlugin(id, Data, SupportedTagTypes, DEFAULT_TAG_TYPE_COUNT); + return RegisterTypesPlugin(id, Data, TagTypePlugin); } cmsBool _cmsRegisterMultiProcessElementPlugin(cmsContext id, cmsPluginBase* Data) { - return RegisterTypesPlugin(id, Data, SupportedMPEtypes, DEFAULT_MPE_TYPE_COUNT); + return RegisterTypesPlugin(id, Data,MPEPlugin); } // Wrapper for tag types -cmsTagTypeHandler* _cmsGetTagTypeHandler(cmsTagTypeSignature sig) +cmsTagTypeHandler* _cmsGetTagTypeHandler(cmsContext ContextID, cmsTagTypeSignature sig) { - return GetHandler(sig, SupportedTagTypes); + _cmsTagTypePluginChunkType* ctx = ( _cmsTagTypePluginChunkType*) _cmsContextGetClientChunk(ContextID, TagTypePlugin); + + return GetHandler(sig, ctx->TagTypes, SupportedTagTypes); } // ******************************************************************************** @@ -5414,48 +5495,94 @@ static _cmsTagLinkedList SupportedTags[] = { cmsSigDeviceSettingsTag ==> Deprecated, useless */ -#define DEFAULT_TAG_COUNT (sizeof(SupportedTags) / sizeof(_cmsTagLinkedList)) + +_cmsTagPluginChunkType _cmsTagPluginChunk = { NULL }; + + +// Duplicates the zone of memory used by the plug-in in the new context +static +void DupTagList(struct _cmsContext_struct* ctx, + const struct _cmsContext_struct* src) +{ + _cmsTagPluginChunkType newHead = { NULL }; + _cmsTagLinkedList* entry; + _cmsTagLinkedList* Anterior = NULL; + _cmsTagPluginChunkType* head = (_cmsTagPluginChunkType*) src->chunks[TagPlugin]; + + // Walk the list copying all nodes + for (entry = head->Tag; + entry != NULL; + entry = entry ->Next) { + + _cmsTagLinkedList *newEntry = ( _cmsTagLinkedList *) _cmsSubAllocDup(ctx ->MemPool, entry, sizeof(_cmsTagLinkedList)); + + if (newEntry == NULL) + return; + + // We want to keep the linked list order, so this is a little bit tricky + newEntry -> Next = NULL; + if (Anterior) + Anterior -> Next = newEntry; + + Anterior = newEntry; + + if (newHead.Tag == NULL) + newHead.Tag = newEntry; + } + + ctx ->chunks[TagPlugin] = _cmsSubAllocDup(ctx->MemPool, &newHead, sizeof(_cmsTagPluginChunkType)); +} + +void _cmsAllocTagPluginChunk(struct _cmsContext_struct* ctx, + const struct _cmsContext_struct* src) +{ + if (src != NULL) { + + DupTagList(ctx, src); + } + else { + static _cmsTagPluginChunkType TagPluginChunk = { NULL }; + ctx ->chunks[TagPlugin] = _cmsSubAllocDup(ctx ->MemPool, &TagPluginChunk, sizeof(_cmsTagPluginChunkType)); + } + +} cmsBool _cmsRegisterTagPlugin(cmsContext id, cmsPluginBase* Data) { cmsPluginTag* Plugin = (cmsPluginTag*) Data; - _cmsTagLinkedList *pt, *Anterior; - + _cmsTagLinkedList *pt; + _cmsTagPluginChunkType* TagPluginChunk = ( _cmsTagPluginChunkType*) _cmsContextGetClientChunk(id, TagPlugin); if (Data == NULL) { - SupportedTags[DEFAULT_TAG_COUNT-1].Next = NULL; + TagPluginChunk->Tag = NULL; return TRUE; } - pt = Anterior = SupportedTags; - while (pt != NULL) { - - if (Plugin->Signature == pt -> Signature) { - pt ->Descriptor = Plugin ->Descriptor; // Replace old behaviour - return TRUE; - } - - Anterior = pt; - pt = pt ->Next; - } - pt = (_cmsTagLinkedList*) _cmsPluginMalloc(id, sizeof(_cmsTagLinkedList)); if (pt == NULL) return FALSE; pt ->Signature = Plugin ->Signature; pt ->Descriptor = Plugin ->Descriptor; - pt ->Next = NULL; + pt ->Next = TagPluginChunk ->Tag; - if (Anterior != NULL) Anterior -> Next = pt; + TagPluginChunk ->Tag = pt; return TRUE; } // Return a descriptor for a given tag or NULL -cmsTagDescriptor* _cmsGetTagDescriptor(cmsTagSignature sig) +cmsTagDescriptor* _cmsGetTagDescriptor(cmsContext ContextID, cmsTagSignature sig) { _cmsTagLinkedList* pt; + _cmsTagPluginChunkType* TagPluginChunk = ( _cmsTagPluginChunkType*) _cmsContextGetClientChunk(ContextID, TagPlugin); + + for (pt = TagPluginChunk->Tag; + pt != NULL; + pt = pt ->Next) { + + if (sig == pt -> Signature) return &pt ->Descriptor; + } for (pt = SupportedTags; pt != NULL; diff --git a/jdk/src/java.desktop/share/native/liblcms/cmsvirt.c b/jdk/src/java.desktop/share/native/liblcms/cmsvirt.c index 699abcc93ca..359875149fc 100644 --- a/jdk/src/java.desktop/share/native/liblcms/cmsvirt.c +++ b/jdk/src/java.desktop/share/native/liblcms/cmsvirt.c @@ -30,7 +30,7 @@ //--------------------------------------------------------------------------------- // // Little Color Management System -// Copyright (c) 1998-2011 Marti Maria Saguer +// Copyright (c) 1998-2014 Marti Maria Saguer // // Permission is hereby granted, free of charge, to any person obtaining // a copy of this software and associated documentation files (the "Software"), @@ -1019,7 +1019,7 @@ typedef struct { static const cmsAllowedLUT AllowedLUTTypes[] = { - { FALSE, 0, cmsSigLut16Type, 4, { cmsSigMatrixElemType, cmsSigCurveSetElemType, cmsSigCLutElemType, cmsSigCurveSetElemType}}, + { FALSE, 0, cmsSigLut16Type, 4, { cmsSigMatrixElemType, cmsSigCurveSetElemType, cmsSigCLutElemType, cmsSigCurveSetElemType}}, { FALSE, 0, cmsSigLut16Type, 3, { cmsSigCurveSetElemType, cmsSigCLutElemType, cmsSigCurveSetElemType}}, { FALSE, 0, cmsSigLut16Type, 2, { cmsSigCurveSetElemType, cmsSigCLutElemType}}, { TRUE , 0, cmsSigLutAtoBType, 1, { cmsSigCurveSetElemType }}, @@ -1150,7 +1150,7 @@ cmsHPROFILE CMSEXPORT cmsTransform2DeviceLink(cmsHTRANSFORM hTransform, cmsFloat if (AllowedLUT == NULL) { // Try to optimize - _cmsOptimizePipeline(&LUT, xform ->RenderingIntent, &FrmIn, &FrmOut, &dwFlags); + _cmsOptimizePipeline(ContextID, &LUT, xform ->RenderingIntent, &FrmIn, &FrmOut, &dwFlags); AllowedLUT = FindCombination(LUT, Version >= 4.0, DestinationTag); } @@ -1159,7 +1159,7 @@ cmsHPROFILE CMSEXPORT cmsTransform2DeviceLink(cmsHTRANSFORM hTransform, cmsFloat if (AllowedLUT == NULL) { dwFlags |= cmsFLAGS_FORCE_CLUT; - _cmsOptimizePipeline(&LUT, xform ->RenderingIntent, &FrmIn, &FrmOut, &dwFlags); + _cmsOptimizePipeline(ContextID, &LUT, xform ->RenderingIntent, &FrmIn, &FrmOut, &dwFlags); // Put identity curves if needed if (cmsPipelineGetPtrToFirstStage(LUT) ->Type != cmsSigCurveSetElemType) diff --git a/jdk/src/java.desktop/share/native/liblcms/cmswtpnt.c b/jdk/src/java.desktop/share/native/liblcms/cmswtpnt.c index 71fb7650836..1eb9a87800f 100644 --- a/jdk/src/java.desktop/share/native/liblcms/cmswtpnt.c +++ b/jdk/src/java.desktop/share/native/liblcms/cmswtpnt.c @@ -30,7 +30,7 @@ //--------------------------------------------------------------------------------- // // Little Color Management System -// Copyright (c) 1998-2012 Marti Maria Saguer +// Copyright (c) 1998-2014 Marti Maria Saguer // // Permission is hereby granted, free of charge, to any person obtaining // a copy of this software and associated documentation files (the "Software"), diff --git a/jdk/src/java.desktop/share/native/liblcms/cmsxform.c b/jdk/src/java.desktop/share/native/liblcms/cmsxform.c index 879056f41ce..3e244c390a8 100644 --- a/jdk/src/java.desktop/share/native/liblcms/cmsxform.c +++ b/jdk/src/java.desktop/share/native/liblcms/cmsxform.c @@ -30,7 +30,7 @@ //--------------------------------------------------------------------------------- // // Little Color Management System -// Copyright (c) 1998-2011 Marti Maria Saguer +// Copyright (c) 1998-2014 Marti Maria Saguer // // Permission is hereby granted, free of charge, to any person obtaining // a copy of this software and associated documentation files (the "Software"), @@ -58,44 +58,120 @@ // Transformations stuff // ----------------------------------------------------------------------- -// Alarm codes for 16-bit transformations, because the fixed range of containers there are -// no values left to mark out of gamut. volatile is C99 per 6.2.5 -static volatile cmsUInt16Number Alarm[cmsMAXCHANNELS] = { 0x7F00, 0x7F00, 0x7F00, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; -static volatile cmsFloat64Number GlobalAdaptationState = 1; +#define DEFAULT_OBSERVER_ADAPTATION_STATE 1.0 + +// The Context0 observer adaptation state. +_cmsAdaptationStateChunkType _cmsAdaptationStateChunk = { DEFAULT_OBSERVER_ADAPTATION_STATE }; + +// Init and duplicate observer adaptation state +void _cmsAllocAdaptationStateChunk(struct _cmsContext_struct* ctx, + const struct _cmsContext_struct* src) +{ + static _cmsAdaptationStateChunkType AdaptationStateChunk = { DEFAULT_OBSERVER_ADAPTATION_STATE }; + void* from; + + if (src != NULL) { + from = src ->chunks[AdaptationStateContext]; + } + else { + from = &AdaptationStateChunk; + } + + ctx ->chunks[AdaptationStateContext] = _cmsSubAllocDup(ctx ->MemPool, from, sizeof(_cmsAdaptationStateChunkType)); +} + + +// Sets adaptation state for absolute colorimetric intent in the given context. Adaptation state applies on all +// but cmsCreateExtendedTransformTHR(). Little CMS can handle incomplete adaptation states. +cmsFloat64Number CMSEXPORT cmsSetAdaptationStateTHR(cmsContext ContextID, cmsFloat64Number d) +{ + cmsFloat64Number prev; + _cmsAdaptationStateChunkType* ptr = (_cmsAdaptationStateChunkType*) _cmsContextGetClientChunk(ContextID, AdaptationStateContext); + + // Get previous value for return + prev = ptr ->AdaptationState; + + // Set the value if d is positive or zero + if (d >= 0.0) { + + ptr ->AdaptationState = d; + } + + // Always return previous value + return prev; +} + // The adaptation state may be defaulted by this function. If you don't like it, use the extended transform routine cmsFloat64Number CMSEXPORT cmsSetAdaptationState(cmsFloat64Number d) { - cmsFloat64Number OldVal = GlobalAdaptationState; - - if (d >= 0) - GlobalAdaptationState = d; - - return OldVal; + return cmsSetAdaptationStateTHR(NULL, d); } -// Alarm codes are always global -void CMSEXPORT cmsSetAlarmCodes(cmsUInt16Number NewAlarm[cmsMAXCHANNELS]) -{ - int i; +// ----------------------------------------------------------------------- +// Alarm codes for 16-bit transformations, because the fixed range of containers there are +// no values left to mark out of gamut. + +#define DEFAULT_ALARM_CODES_VALUE {0x7F00, 0x7F00, 0x7F00, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} + +_cmsAlarmCodesChunkType _cmsAlarmCodesChunk = { DEFAULT_ALARM_CODES_VALUE }; + +// Sets the codes used to mark out-out-gamut on Proofing transforms for a given context. Values are meant to be +// encoded in 16 bits. +void CMSEXPORT cmsSetAlarmCodesTHR(cmsContext ContextID, const cmsUInt16Number AlarmCodesP[cmsMAXCHANNELS]) +{ + _cmsAlarmCodesChunkType* ContextAlarmCodes = (_cmsAlarmCodesChunkType*) _cmsContextGetClientChunk(ContextID, AlarmCodesContext); + + _cmsAssert(ContextAlarmCodes != NULL); // Can't happen + + memcpy(ContextAlarmCodes->AlarmCodes, AlarmCodesP, sizeof(ContextAlarmCodes->AlarmCodes)); +} + +// Gets the current codes used to mark out-out-gamut on Proofing transforms for the given context. +// Values are meant to be encoded in 16 bits. +void CMSEXPORT cmsGetAlarmCodesTHR(cmsContext ContextID, cmsUInt16Number AlarmCodesP[cmsMAXCHANNELS]) +{ + _cmsAlarmCodesChunkType* ContextAlarmCodes = (_cmsAlarmCodesChunkType*) _cmsContextGetClientChunk(ContextID, AlarmCodesContext); + + _cmsAssert(ContextAlarmCodes != NULL); // Can't happen + + memcpy(AlarmCodesP, ContextAlarmCodes->AlarmCodes, sizeof(ContextAlarmCodes->AlarmCodes)); +} + +void CMSEXPORT cmsSetAlarmCodes(const cmsUInt16Number NewAlarm[cmsMAXCHANNELS]) +{ _cmsAssert(NewAlarm != NULL); - for (i=0; i < cmsMAXCHANNELS; i++) - Alarm[i] = NewAlarm[i]; + cmsSetAlarmCodesTHR(NULL, NewAlarm); } -// You can get the codes cas well void CMSEXPORT cmsGetAlarmCodes(cmsUInt16Number OldAlarm[cmsMAXCHANNELS]) { - int i; - _cmsAssert(OldAlarm != NULL); - - for (i=0; i < cmsMAXCHANNELS; i++) - OldAlarm[i] = Alarm[i]; + cmsGetAlarmCodesTHR(NULL, OldAlarm); } + +// Init and duplicate alarm codes +void _cmsAllocAlarmCodesChunk(struct _cmsContext_struct* ctx, + const struct _cmsContext_struct* src) +{ + static _cmsAlarmCodesChunkType AlarmCodesChunk = { DEFAULT_ALARM_CODES_VALUE }; + void* from; + + if (src != NULL) { + from = src ->chunks[AlarmCodesContext]; + } + else { + from = &AlarmCodesChunk; + } + + ctx ->chunks[AlarmCodesContext] = _cmsSubAllocDup(ctx ->MemPool, from, sizeof(_cmsAlarmCodesChunkType)); +} + +// ----------------------------------------------------------------------- + // Get rid of transform resources void CMSEXPORT cmsDeleteTransform(cmsHTRANSFORM hTransform) { @@ -202,6 +278,30 @@ void FloatXFORM(_cmsTRANSFORM* p, } } + +static +void NullFloatXFORM(_cmsTRANSFORM* p, + const void* in, + void* out, + cmsUInt32Number Size, + cmsUInt32Number Stride) +{ + cmsUInt8Number* accum; + cmsUInt8Number* output; + cmsFloat32Number fIn[cmsMAXCHANNELS]; + cmsUInt32Number i, n; + + accum = (cmsUInt8Number*) in; + output = (cmsUInt8Number*) out; + n = Size; + + for (i=0; i < n; i++) { + + accum = p -> FromInputFloat(p, fIn, accum, Stride); + output = p -> ToOutputFloat(p, fIn, output, Stride); + } +} + // 16 bit precision ----------------------------------------------------------------------------------------------------------- // Null transformation, only applies formatters. No caché @@ -252,7 +352,7 @@ void PrecalculatedXFORM(_cmsTRANSFORM* p, } -// Auxiliar: Handle precalculated gamut check +// Auxiliar: Handle precalculated gamut check. The retrieval of context may be alittle bit slow, but this function is not critical. static void TransformOnePixelWithGamutCheck(_cmsTRANSFORM* p, const cmsUInt16Number wIn[], @@ -264,9 +364,12 @@ void TransformOnePixelWithGamutCheck(_cmsTRANSFORM* p, if (wOutOfGamut >= 1) { cmsUInt16Number i; + _cmsAlarmCodesChunkType* ContextAlarmCodes = (_cmsAlarmCodesChunkType*) _cmsContextGetClientChunk(p->ContextID, AlarmCodesContext); - for (i=0; i < p ->Lut->OutputChannels; i++) - wOut[i] = Alarm[i]; + for (i=0; i < p ->Lut->OutputChannels; i++) { + + wOut[i] = ContextAlarmCodes ->AlarmCodes[i]; + } } else p ->Lut ->Eval16Fn(wIn, wOut, p -> Lut->Data); @@ -393,34 +496,86 @@ typedef struct _cmsTransformCollection_st { } _cmsTransformCollection; // The linked list head -static _cmsTransformCollection* TransformCollection = NULL; +_cmsTransformPluginChunkType _cmsTransformPluginChunk = { NULL }; + + +// Duplicates the zone of memory used by the plug-in in the new context +static +void DupPluginTransformList(struct _cmsContext_struct* ctx, + const struct _cmsContext_struct* src) +{ + _cmsTransformPluginChunkType newHead = { NULL }; + _cmsTransformCollection* entry; + _cmsTransformCollection* Anterior = NULL; + _cmsTransformPluginChunkType* head = (_cmsTransformPluginChunkType*) src->chunks[TransformPlugin]; + + // Walk the list copying all nodes + for (entry = head->TransformCollection; + entry != NULL; + entry = entry ->Next) { + + _cmsTransformCollection *newEntry = ( _cmsTransformCollection *) _cmsSubAllocDup(ctx ->MemPool, entry, sizeof(_cmsTransformCollection)); + + if (newEntry == NULL) + return; + + // We want to keep the linked list order, so this is a little bit tricky + newEntry -> Next = NULL; + if (Anterior) + Anterior -> Next = newEntry; + + Anterior = newEntry; + + if (newHead.TransformCollection == NULL) + newHead.TransformCollection = newEntry; + } + + ctx ->chunks[TransformPlugin] = _cmsSubAllocDup(ctx->MemPool, &newHead, sizeof(_cmsTransformPluginChunkType)); +} + +void _cmsAllocTransformPluginChunk(struct _cmsContext_struct* ctx, + const struct _cmsContext_struct* src) +{ + if (src != NULL) { + + // Copy all linked list + DupPluginTransformList(ctx, src); + } + else { + static _cmsTransformPluginChunkType TransformPluginChunkType = { NULL }; + ctx ->chunks[TransformPlugin] = _cmsSubAllocDup(ctx ->MemPool, &TransformPluginChunkType, sizeof(_cmsTransformPluginChunkType)); + } +} + + // Register new ways to transform -cmsBool _cmsRegisterTransformPlugin(cmsContext id, cmsPluginBase* Data) +cmsBool _cmsRegisterTransformPlugin(cmsContext ContextID, cmsPluginBase* Data) { cmsPluginTransform* Plugin = (cmsPluginTransform*) Data; _cmsTransformCollection* fl; + _cmsTransformPluginChunkType* ctx = ( _cmsTransformPluginChunkType*) _cmsContextGetClientChunk(ContextID,TransformPlugin); - if (Data == NULL) { + if (Data == NULL) { // Free the chain. Memory is safely freed at exit - TransformCollection = NULL; + ctx->TransformCollection = NULL; return TRUE; } // Factory callback is required - if (Plugin ->Factory == NULL) return FALSE; + if (Plugin ->Factory == NULL) return FALSE; - fl = (_cmsTransformCollection*) _cmsPluginMalloc(id, sizeof(_cmsTransformCollection)); + fl = (_cmsTransformCollection*) _cmsPluginMalloc(ContextID, sizeof(_cmsTransformCollection)); if (fl == NULL) return FALSE; - // Copy the parameters + // Copy the parameters fl ->Factory = Plugin ->Factory; // Keep linked list - fl ->Next = TransformCollection; - TransformCollection = fl; + fl ->Next = ctx->TransformCollection; + ctx->TransformCollection = fl; // All is ok return TRUE; @@ -463,6 +618,7 @@ static _cmsTRANSFORM* AllocEmptyTransform(cmsContext ContextID, cmsPipeline* lut, cmsUInt32Number Intent, cmsUInt32Number* InputFormat, cmsUInt32Number* OutputFormat, cmsUInt32Number* dwFlags) { + _cmsTransformPluginChunkType* ctx = ( _cmsTransformPluginChunkType*) _cmsContextGetClientChunk(ContextID, TransformPlugin); _cmsTransformCollection* Plugin; // Allocate needed memory @@ -473,7 +629,7 @@ _cmsTRANSFORM* AllocEmptyTransform(cmsContext ContextID, cmsPipeline* lut, p ->Lut = lut; // Let's see if any plug-in want to do the transform by itself - for (Plugin = TransformCollection; + for (Plugin = ctx ->TransformCollection; Plugin != NULL; Plugin = Plugin ->Next) { @@ -493,10 +649,10 @@ _cmsTRANSFORM* AllocEmptyTransform(cmsContext ContextID, cmsPipeline* lut, // Fill the formatters just in case the optimized routine is interested. // No error is thrown if the formatter doesn't exist. It is up to the optimization // factory to decide what to do in those cases. - p ->FromInput = _cmsGetFormatter(*InputFormat, cmsFormatterInput, CMS_PACK_FLAGS_16BITS).Fmt16; - p ->ToOutput = _cmsGetFormatter(*OutputFormat, cmsFormatterOutput, CMS_PACK_FLAGS_16BITS).Fmt16; - p ->FromInputFloat = _cmsGetFormatter(*InputFormat, cmsFormatterInput, CMS_PACK_FLAGS_FLOAT).FmtFloat; - p ->ToOutputFloat = _cmsGetFormatter(*OutputFormat, cmsFormatterOutput, CMS_PACK_FLAGS_FLOAT).FmtFloat; + p ->FromInput = _cmsGetFormatter(ContextID, *InputFormat, cmsFormatterInput, CMS_PACK_FLAGS_16BITS).Fmt16; + p ->ToOutput = _cmsGetFormatter(ContextID, *OutputFormat, cmsFormatterOutput, CMS_PACK_FLAGS_16BITS).Fmt16; + p ->FromInputFloat = _cmsGetFormatter(ContextID, *InputFormat, cmsFormatterInput, CMS_PACK_FLAGS_FLOAT).FmtFloat; + p ->ToOutputFloat = _cmsGetFormatter(ContextID, *OutputFormat, cmsFormatterOutput, CMS_PACK_FLAGS_FLOAT).FmtFloat; return p; } @@ -504,14 +660,14 @@ _cmsTRANSFORM* AllocEmptyTransform(cmsContext ContextID, cmsPipeline* lut, // Not suitable for the transform plug-in, let's check the pipeline plug-in if (p ->Lut != NULL) - _cmsOptimizePipeline(&p->Lut, Intent, InputFormat, OutputFormat, dwFlags); + _cmsOptimizePipeline(ContextID, &p->Lut, Intent, InputFormat, OutputFormat, dwFlags); // Check whatever this is a true floating point transform if (_cmsFormatterIsFloat(*InputFormat) && _cmsFormatterIsFloat(*OutputFormat)) { // Get formatter function always return a valid union, but the contents of this union may be NULL. - p ->FromInputFloat = _cmsGetFormatter(*InputFormat, cmsFormatterInput, CMS_PACK_FLAGS_FLOAT).FmtFloat; - p ->ToOutputFloat = _cmsGetFormatter(*OutputFormat, cmsFormatterOutput, CMS_PACK_FLAGS_FLOAT).FmtFloat; + p ->FromInputFloat = _cmsGetFormatter(ContextID, *InputFormat, cmsFormatterInput, CMS_PACK_FLAGS_FLOAT).FmtFloat; + p ->ToOutputFloat = _cmsGetFormatter(ContextID, *OutputFormat, cmsFormatterOutput, CMS_PACK_FLAGS_FLOAT).FmtFloat; *dwFlags |= cmsFLAGS_CAN_CHANGE_FORMATTER; if (p ->FromInputFloat == NULL || p ->ToOutputFloat == NULL) { @@ -521,8 +677,15 @@ _cmsTRANSFORM* AllocEmptyTransform(cmsContext ContextID, cmsPipeline* lut, return NULL; } - // Float transforms don't use caché, always are non-NULL - p ->xform = FloatXFORM; + if (*dwFlags & cmsFLAGS_NULLTRANSFORM) { + + p ->xform = NullFloatXFORM; + } + else { + // Float transforms don't use caché, always are non-NULL + p ->xform = FloatXFORM; + } + } else { @@ -534,8 +697,8 @@ _cmsTRANSFORM* AllocEmptyTransform(cmsContext ContextID, cmsPipeline* lut, int BytesPerPixelInput; - p ->FromInput = _cmsGetFormatter(*InputFormat, cmsFormatterInput, CMS_PACK_FLAGS_16BITS).Fmt16; - p ->ToOutput = _cmsGetFormatter(*OutputFormat, cmsFormatterOutput, CMS_PACK_FLAGS_16BITS).Fmt16; + p ->FromInput = _cmsGetFormatter(ContextID, *InputFormat, cmsFormatterInput, CMS_PACK_FLAGS_16BITS).Fmt16; + p ->ToOutput = _cmsGetFormatter(ContextID, *OutputFormat, cmsFormatterOutput, CMS_PACK_FLAGS_16BITS).Fmt16; if (p ->FromInput == NULL || p ->ToOutput == NULL) { @@ -727,6 +890,7 @@ cmsHTRANSFORM CMSEXPORT cmsCreateExtendedTransform(cmsContext ContextID, // Check channel count if ((cmsChannelsOf(EntryColorSpace) != cmsPipelineInputChannels(Lut)) || (cmsChannelsOf(ExitColorSpace) != cmsPipelineOutputChannels(Lut))) { + cmsPipelineFree(Lut); cmsSignalError(ContextID, cmsERROR_NOT_SUITABLE, "Channel count doesn't match. Profile is corrupted"); return NULL; } @@ -829,7 +993,7 @@ cmsHTRANSFORM CMSEXPORT cmsCreateMultiprofileTransformTHR(cmsContext ContextID, for (i=0; i < nProfiles; i++) { BPC[i] = dwFlags & cmsFLAGS_BLACKPOINTCOMPENSATION ? TRUE : FALSE; Intents[i] = Intent; - AdaptationStates[i] = GlobalAdaptationState; + AdaptationStates[i] = cmsSetAdaptationStateTHR(ContextID, -1); } @@ -909,7 +1073,7 @@ cmsHTRANSFORM CMSEXPORT cmsCreateProofingTransformTHR(cmsContext ContextID, Intents[0] = nIntent; Intents[1] = nIntent; Intents[2] = INTENT_RELATIVE_COLORIMETRIC; Intents[3] = ProofingIntent; BPC[0] = DoBPC; BPC[1] = DoBPC; BPC[2] = 0; BPC[3] = 0; - Adaptation[0] = Adaptation[1] = Adaptation[2] = Adaptation[3] = GlobalAdaptationState; + Adaptation[0] = Adaptation[1] = Adaptation[2] = Adaptation[3] = cmsSetAdaptationStateTHR(ContextID, -1); if (!(dwFlags & (cmsFLAGS_SOFTPROOFING|cmsFLAGS_GAMUTCHECK))) return cmsCreateTransformTHR(ContextID, InputProfile, InputFormat, OutputProfile, OutputFormat, nIntent, dwFlags); @@ -984,8 +1148,8 @@ cmsBool CMSEXPORT cmsChangeBuffersFormat(cmsHTRANSFORM hTransform, return FALSE; } - FromInput = _cmsGetFormatter(InputFormat, cmsFormatterInput, CMS_PACK_FLAGS_16BITS).Fmt16; - ToOutput = _cmsGetFormatter(OutputFormat, cmsFormatterOutput, CMS_PACK_FLAGS_16BITS).Fmt16; + FromInput = _cmsGetFormatter(xform->ContextID, InputFormat, cmsFormatterInput, CMS_PACK_FLAGS_16BITS).Fmt16; + ToOutput = _cmsGetFormatter(xform->ContextID, OutputFormat, cmsFormatterOutput, CMS_PACK_FLAGS_16BITS).Fmt16; if (FromInput == NULL || ToOutput == NULL) { diff --git a/jdk/src/java.desktop/share/native/liblcms/lcms2.h b/jdk/src/java.desktop/share/native/liblcms/lcms2.h index c6c35b185f6..2fd2b56bdb8 100644 --- a/jdk/src/java.desktop/share/native/liblcms/lcms2.h +++ b/jdk/src/java.desktop/share/native/liblcms/lcms2.h @@ -30,7 +30,7 @@ //--------------------------------------------------------------------------------- // // Little Color Management System -// Copyright (c) 1998-2013 Marti Maria Saguer +// Copyright (c) 1998-2014 Marti Maria Saguer // // Permission is hereby granted, free of charge, to any person obtaining // a copy of this software and associated documentation files (the "Software"), @@ -52,7 +52,7 @@ // //--------------------------------------------------------------------------------- // -// Version 2.5 +// Version 2.6 // #ifndef _lcms2_H @@ -84,6 +84,9 @@ // Uncomment to get rid of the tables for "half" float support // #define CMS_NO_HALF_SUPPORT 1 +// Uncomment to get rid of pthreads/windows dependency +// #define CMS_NO_PTHREADS 1 + // ********** End of configuration toggles ****************************** // Needed for streams @@ -101,7 +104,7 @@ extern "C" { #endif // Version/release -#define LCMS_VERSION 2050 +#define LCMS_VERSION 2060 // I will give the chance of redefining basic types for compilers that are not fully C99 compliant #ifndef CMS_BASIC_TYPES_ALREADY_DEFINED @@ -202,28 +205,42 @@ typedef int cmsBool; // Try to detect big endian platforms. This list can be endless, so only some checks are performed over here. // you can pass this toggle to the compiler by using -DCMS_USE_BIG_ENDIAN or something similar +#if defined(__sgi__) || defined(__sgi) || defined(sparc) +# define CMS_USE_BIG_ENDIAN 1 +#endif + +#if defined(__s390__) || defined(__s390x__) +# define CMS_USE_BIG_ENDIAN 1 +#endif + +# ifdef TARGET_CPU_PPC +# if TARGET_CPU_PPC +# define CMS_USE_BIG_ENDIAN 1 +# endif +# endif + +#if defined(__powerpc__) || defined(__ppc__) || defined(TARGET_CPU_PPC) +# define CMS_USE_BIG_ENDIAN 1 +# if defined (__GNUC__) && defined(__BYTE_ORDER) && defined(__LITTLE_ENDIAN) +# if __BYTE_ORDER == __LITTLE_ENDIAN +// // Don't use big endian for PowerPC little endian mode +# undef CMS_USE_BIG_ENDIAN +# endif +# endif +#endif + +// WORDS_BIGENDIAN takes precedence #if defined(_HOST_BIG_ENDIAN) || defined(__BIG_ENDIAN__) || defined(WORDS_BIGENDIAN) # define CMS_USE_BIG_ENDIAN 1 #endif -#if defined(__sgi__) || defined(__sgi) || defined(__powerpc__) || defined(sparc) -# define CMS_USE_BIG_ENDIAN 1 -#endif - -#if defined(__ppc__) || defined(__s390__) || defined(__s390x__) -# define CMS_USE_BIG_ENDIAN 1 -#endif - -#ifdef TARGET_CPU_PPC -# if TARGET_CPU_PPC -# define CMS_USE_BIG_ENDIAN 1 -# endif -#endif - #ifdef macintosh # ifdef __BIG_ENDIAN__ # define CMS_USE_BIG_ENDIAN 1 # endif +# ifdef __LITTLE_ENDIAN__ +# undef CMS_USE_BIG_ENDIAN +# endif #endif // Calling convention -- this is hardly platform and compiler dependent @@ -249,6 +266,14 @@ typedef int cmsBool; # define CMSAPI #endif +#ifdef HasTHREADS +# if HasTHREADS == 1 +# undef CMS_NO_PTHREADS +# else +# define CMS_NO_PTHREADS 1 +# endif +#endif + // Some common definitions #define cmsMAX_PATH 256 @@ -642,7 +667,6 @@ typedef struct { // Little CMS specific typedefs -typedef void* cmsContext; // Context identifier for multithreaded environments typedef void* cmsHANDLE ; // Generic handle typedef void* cmsHPROFILE; // Opaque typedefs to hide internals typedef void* cmsHTRANSFORM; @@ -1012,11 +1036,25 @@ typedef struct { CMSAPI int CMSEXPORT cmsstrcasecmp(const char* s1, const char* s2); CMSAPI long int CMSEXPORT cmsfilelength(FILE* f); -// Plug-In registering --------------------------------------------------------------------------------------------------- + +// Context handling -------------------------------------------------------------------------------------------------------- + +// Each context holds its owns globals and its own plug-ins. There is a global context with the id = 0 for lecacy compatibility +// though using the global context is not recomended. Proper context handling makes lcms more thread-safe. + +typedef struct _cmsContext_struct* cmsContext; + +CMSAPI cmsContext CMSEXPORT cmsCreateContext(void* Plugin, void* UserData); +CMSAPI void CMSEXPORT cmsDeleteContext(cmsContext ContexID); +CMSAPI cmsContext CMSEXPORT cmsDupContext(cmsContext ContextID, void* NewUserData); +CMSAPI void* CMSEXPORT cmsGetContextUserData(cmsContext ContextID); + +// Plug-In registering -------------------------------------------------------------------------------------------------- CMSAPI cmsBool CMSEXPORT cmsPlugin(void* Plugin); CMSAPI cmsBool CMSEXPORT cmsPluginTHR(cmsContext ContextID, void* Plugin); CMSAPI void CMSEXPORT cmsUnregisterPlugins(void); +CMSAPI void CMSEXPORT cmsUnregisterPluginsTHR(cmsContext ContextID); // Error logging ---------------------------------------------------------------------------------------------------------- @@ -1053,6 +1091,7 @@ typedef void (* cmsLogErrorHandlerFunction)(cmsContext ContextID, cmsUInt32Numb // Allows user to set any specific logger CMSAPI void CMSEXPORT cmsSetLogErrorHandler(cmsLogErrorHandlerFunction Fn); +CMSAPI void CMSEXPORT cmsSetLogErrorHandlerTHR(cmsContext ContextID, cmsLogErrorHandlerFunction Fn); // Conversions -------------------------------------------------------------------------------------------------------------- @@ -1514,6 +1553,7 @@ CMSAPI cmsHPROFILE CMSEXPORT cmsOpenProfileFromStreamTHR(cmsContext Context CMSAPI cmsHPROFILE CMSEXPORT cmsOpenProfileFromMem(const void * MemPtr, cmsUInt32Number dwSize); CMSAPI cmsHPROFILE CMSEXPORT cmsOpenProfileFromMemTHR(cmsContext ContextID, const void * MemPtr, cmsUInt32Number dwSize); CMSAPI cmsHPROFILE CMSEXPORT cmsOpenProfileFromIOhandlerTHR(cmsContext ContextID, cmsIOHANDLER* io); +CMSAPI cmsHPROFILE CMSEXPORT cmsOpenProfileFromIOhandler2THR(cmsContext ContextID, cmsIOHANDLER* io, cmsBool write); CMSAPI cmsBool CMSEXPORT cmsCloseProfile(cmsHPROFILE hProfile); CMSAPI cmsBool CMSEXPORT cmsSaveProfileToFile(cmsHPROFILE hProfile, const char* FileName); @@ -1604,6 +1644,7 @@ CMSAPI cmsHPROFILE CMSEXPORT cmsTransform2DeviceLink(cmsHTRANSFORM hTransfo // Call with NULL as parameters to get the intent count CMSAPI cmsUInt32Number CMSEXPORT cmsGetSupportedIntents(cmsUInt32Number nMax, cmsUInt32Number* Codes, char** Descriptions); +CMSAPI cmsUInt32Number CMSEXPORT cmsGetSupportedIntentsTHR(cmsContext ContextID, cmsUInt32Number nMax, cmsUInt32Number* Codes, char** Descriptions); // Flags @@ -1715,11 +1756,22 @@ CMSAPI void CMSEXPORT cmsDoTransformStride(cmsHTRANSFORM Transform, cmsUInt32Number Stride); -CMSAPI void CMSEXPORT cmsSetAlarmCodes(cmsUInt16Number NewAlarm[cmsMAXCHANNELS]); +CMSAPI void CMSEXPORT cmsSetAlarmCodes(const cmsUInt16Number NewAlarm[cmsMAXCHANNELS]); CMSAPI void CMSEXPORT cmsGetAlarmCodes(cmsUInt16Number NewAlarm[cmsMAXCHANNELS]); + +CMSAPI void CMSEXPORT cmsSetAlarmCodesTHR(cmsContext ContextID, + const cmsUInt16Number AlarmCodes[cmsMAXCHANNELS]); +CMSAPI void CMSEXPORT cmsGetAlarmCodesTHR(cmsContext ContextID, + cmsUInt16Number AlarmCodes[cmsMAXCHANNELS]); + + + // Adaptation state for absolute colorimetric intent CMSAPI cmsFloat64Number CMSEXPORT cmsSetAdaptationState(cmsFloat64Number d); +CMSAPI cmsFloat64Number CMSEXPORT cmsSetAdaptationStateTHR(cmsContext ContextID, cmsFloat64Number d); + + // Grab the ContextID from an open transform. Returns NULL if a NULL transform is passed CMSAPI cmsContext CMSEXPORT cmsGetTransformContextID(cmsHTRANSFORM hTransform); diff --git a/jdk/src/java.desktop/share/native/liblcms/lcms2_internal.h b/jdk/src/java.desktop/share/native/liblcms/lcms2_internal.h index 6fbbb95b244..7f28f3d277a 100644 --- a/jdk/src/java.desktop/share/native/liblcms/lcms2_internal.h +++ b/jdk/src/java.desktop/share/native/liblcms/lcms2_internal.h @@ -30,7 +30,7 @@ // // Little Color Management System -// Copyright (c) 1998-2011 Marti Maria Saguer +// Copyright (c) 1998-2014 Marti Maria Saguer // // Permission is hereby granted, free of charge, to any person obtaining // a copy of this software and associated documentation files (the "Software"), @@ -193,16 +193,171 @@ cmsINLINE cmsUInt16Number _cmsQuickSaturateWord(cmsFloat64Number d) return _cmsQuickFloorWord(d); } -// Plug-In registering --------------------------------------------------------------- + +// Pthread support -------------------------------------------------------------------- +#ifndef CMS_NO_PTHREADS + +// This is the threading support. Unfortunately, it has to be platform-dependent because +// windows does not support pthreads. + +#ifdef CMS_IS_WINDOWS_ + +#define WIN32_LEAN_AND_MEAN 1 +#include + + +// From: http://locklessinc.com/articles/pthreads_on_windows/ +// The pthreads API has an initialization macro that has no correspondence to anything in +// the windows API. By investigating the internal definition of the critical section type, +// one may work out how to initialize one without calling InitializeCriticalSection(). +// The trick here is that InitializeCriticalSection() is not allowed to fail. It tries +// to allocate a critical section debug object, but if no memory is available, it sets +// the pointer to a specific value. (One would expect that value to be NULL, but it is +// actually (void *)-1 for some reason.) Thus we can use this special value for that +// pointer, and the critical section code will work. + +// The other important part of the critical section type to initialize is the number +// of waiters. This controls whether or not the mutex is locked. Fortunately, this +// part of the critical section is unlikely to change. Apparently, many programs +// already test critical sections to see if they are locked using this value, so +// Microsoft felt that it was necessary to keep it set at -1 for an unlocked critical +// section, even when they changed the underlying algorithm to be more scalable. +// The final parts of the critical section object are unimportant, and can be set +// to zero for their defaults. This yields an initialization macro: + +typedef CRITICAL_SECTION _cmsMutex; + +#define CMS_MUTEX_INITIALIZER {(void*) -1,-1,0,0,0,0} + +cmsINLINE int _cmsLockPrimitive(_cmsMutex *m) +{ + EnterCriticalSection(m); + return 0; +} + +cmsINLINE int _cmsUnlockPrimitive(_cmsMutex *m) +{ + LeaveCriticalSection(m); + return 0; +} + +cmsINLINE int _cmsInitMutexPrimitive(_cmsMutex *m) +{ + InitializeCriticalSection(m); + return 0; +} + +cmsINLINE int _cmsDestroyMutexPrimitive(_cmsMutex *m) +{ + DeleteCriticalSection(m); + return 0; +} + +cmsINLINE int _cmsEnterCriticalSectionPrimitive(_cmsMutex *m) +{ + EnterCriticalSection(m); + return 0; +} + +cmsINLINE int _cmsLeaveCriticalSectionPrimitive(_cmsMutex *m) +{ + LeaveCriticalSection(m); + return 0; +} + +#else + +// Rest of the wide world +#include + +#define CMS_MUTEX_INITIALIZER PTHREAD_MUTEX_INITIALIZER +typedef pthread_mutex_t _cmsMutex; + + +cmsINLINE int _cmsLockPrimitive(_cmsMutex *m) +{ + return pthread_mutex_lock(m); +} + +cmsINLINE int _cmsUnlockPrimitive(_cmsMutex *m) +{ + return pthread_mutex_unlock(m); +} + +cmsINLINE int _cmsInitMutexPrimitive(_cmsMutex *m) +{ + return pthread_mutex_init(m, NULL); +} + +cmsINLINE int _cmsDestroyMutexPrimitive(_cmsMutex *m) +{ + return pthread_mutex_destroy(m); +} + +cmsINLINE int _cmsEnterCriticalSectionPrimitive(_cmsMutex *m) +{ + return pthread_mutex_lock(m); +} + +cmsINLINE int _cmsLeaveCriticalSectionPrimitive(_cmsMutex *m) +{ + return pthread_mutex_unlock(m); +} + +#endif +#else + +#define CMS_MUTEX_INITIALIZER 0 +typedef int _cmsMutex; + + +cmsINLINE int _cmsLockPrimitive(_cmsMutex *m) +{ + return 0; + cmsUNUSED_PARAMETER(m); +} + +cmsINLINE int _cmsUnlockPrimitive(_cmsMutex *m) +{ + return 0; + cmsUNUSED_PARAMETER(m); +} + +cmsINLINE int _cmsInitMutexPrimitive(_cmsMutex *m) +{ + return 0; + cmsUNUSED_PARAMETER(m); +} + +cmsINLINE int _cmsDestroyMutexPrimitive(_cmsMutex *m) +{ + return 0; + cmsUNUSED_PARAMETER(m); +} + +cmsINLINE int _cmsEnterCriticalSectionPrimitive(_cmsMutex *m) +{ + return 0; + cmsUNUSED_PARAMETER(m); +} + +cmsINLINE int _cmsLeaveCriticalSectionPrimitive(_cmsMutex *m) +{ + return 0; + cmsUNUSED_PARAMETER(m); +} +#endif + +// Plug-In registration --------------------------------------------------------------- // Specialized function for plug-in memory management. No pairing free() since whole pool is freed at once. void* _cmsPluginMalloc(cmsContext ContextID, cmsUInt32Number size); // Memory management -cmsBool _cmsRegisterMemHandlerPlugin(cmsPluginBase* Plugin); +cmsBool _cmsRegisterMemHandlerPlugin(cmsContext ContextID, cmsPluginBase* Plugin); // Interpolation -cmsBool _cmsRegisterInterpPlugin(cmsPluginBase* Plugin); +cmsBool _cmsRegisterInterpPlugin(cmsContext ContextID, cmsPluginBase* Plugin); // Parametric curves cmsBool _cmsRegisterParametricCurvesPlugin(cmsContext ContextID, cmsPluginBase* Plugin); @@ -228,9 +383,12 @@ cmsBool _cmsRegisterOptimizationPlugin(cmsContext ContextID, cmsPluginBase* Plu // Transform cmsBool _cmsRegisterTransformPlugin(cmsContext ContextID, cmsPluginBase* Plugin); +// Mutex +cmsBool _cmsRegisterMutexPlugin(cmsContext ContextID, cmsPluginBase* Plugin); + // --------------------------------------------------------------------------------------------------------- -// Suballocators. Those are blocks of memory that is freed at the end on whole block. +// Suballocators. typedef struct _cmsSubAllocator_chunk_st { cmsUInt8Number* Block; @@ -253,9 +411,264 @@ typedef struct { _cmsSubAllocator* _cmsCreateSubAlloc(cmsContext ContextID, cmsUInt32Number Initial); void _cmsSubAllocDestroy(_cmsSubAllocator* s); void* _cmsSubAlloc(_cmsSubAllocator* s, cmsUInt32Number size); +void* _cmsSubAllocDup(_cmsSubAllocator* s, const void *ptr, cmsUInt32Number size); // ---------------------------------------------------------------------------------- +// The context clients. +typedef enum { + + UserPtr, // User-defined pointer + Logger, + AlarmCodesContext, + AdaptationStateContext, + MemPlugin, + InterpPlugin, + CurvesPlugin, + FormattersPlugin, + TagTypePlugin, + TagPlugin, + IntentPlugin, + MPEPlugin, + OptimizationPlugin, + TransformPlugin, + MutexPlugin, + + // Last in list + MemoryClientMax + +} _cmsMemoryClient; + + +// Container for memory management plug-in. +typedef struct { + + _cmsMallocFnPtrType MallocPtr; + _cmsMalloZerocFnPtrType MallocZeroPtr; + _cmsFreeFnPtrType FreePtr; + _cmsReallocFnPtrType ReallocPtr; + _cmsCallocFnPtrType CallocPtr; + _cmsDupFnPtrType DupPtr; + +} _cmsMemPluginChunkType; + +// Copy memory management function pointers from plug-in to chunk, taking care of missing routines +void _cmsInstallAllocFunctions(cmsPluginMemHandler* Plugin, _cmsMemPluginChunkType* ptr); + +// Internal structure for context +struct _cmsContext_struct { + + struct _cmsContext_struct* Next; // Points to next context in the new style + _cmsSubAllocator* MemPool; // The memory pool that stores context data + + void* chunks[MemoryClientMax]; // array of pointers to client chunks. Memory itself is hold in the suballocator. + // If NULL, then it reverts to global Context0 + + _cmsMemPluginChunkType DefaultMemoryManager; // The allocators used for creating the context itself. Cannot be overriden +}; + +// Returns a pointer to a valid context structure, including the global one if id is zero. +// Verifies the magic number. +struct _cmsContext_struct* _cmsGetContext(cmsContext ContextID); + +// Returns the block assigned to the specific zone. +void* _cmsContextGetClientChunk(cmsContext id, _cmsMemoryClient mc); + + +// Chunks of context memory by plug-in client ------------------------------------------------------- + +// Those structures encapsulates all variables needed by the several context clients (mostly plug-ins) + +// Container for error logger -- not a plug-in +typedef struct { + + cmsLogErrorHandlerFunction LogErrorHandler; // Set to NULL for Context0 fallback + +} _cmsLogErrorChunkType; + +// The global Context0 storage for error logger +extern _cmsLogErrorChunkType _cmsLogErrorChunk; + +// Allocate and init error logger container. +void _cmsAllocLogErrorChunk(struct _cmsContext_struct* ctx, + const struct _cmsContext_struct* src); + +// Container for alarm codes -- not a plug-in +typedef struct { + + cmsUInt16Number AlarmCodes[cmsMAXCHANNELS]; + +} _cmsAlarmCodesChunkType; + +// The global Context0 storage for alarm codes +extern _cmsAlarmCodesChunkType _cmsAlarmCodesChunk; + +// Allocate and init alarm codes container. +void _cmsAllocAlarmCodesChunk(struct _cmsContext_struct* ctx, + const struct _cmsContext_struct* src); + +// Container for adaptation state -- not a plug-in +typedef struct { + + cmsFloat64Number AdaptationState; + +} _cmsAdaptationStateChunkType; + +// The global Context0 storage for adaptation state +extern _cmsAdaptationStateChunkType _cmsAdaptationStateChunk; + +// Allocate and init adaptation state container. +void _cmsAllocAdaptationStateChunk(struct _cmsContext_struct* ctx, + const struct _cmsContext_struct* src); + + +// The global Context0 storage for memory management +extern _cmsMemPluginChunkType _cmsMemPluginChunk; + +// Allocate and init memory management container. +void _cmsAllocMemPluginChunk(struct _cmsContext_struct* ctx, + const struct _cmsContext_struct* src); + +// Container for interpolation plug-in +typedef struct { + + cmsInterpFnFactory Interpolators; + +} _cmsInterpPluginChunkType; + +// The global Context0 storage for interpolation plug-in +extern _cmsInterpPluginChunkType _cmsInterpPluginChunk; + +// Allocate and init interpolation container. +void _cmsAllocInterpPluginChunk(struct _cmsContext_struct* ctx, + const struct _cmsContext_struct* src); + +// Container for parametric curves plug-in +typedef struct { + + struct _cmsParametricCurvesCollection_st* ParametricCurves; + +} _cmsCurvesPluginChunkType; + +// The global Context0 storage for tone curves plug-in +extern _cmsCurvesPluginChunkType _cmsCurvesPluginChunk; + +// Allocate and init parametric curves container. +void _cmsAllocCurvesPluginChunk(struct _cmsContext_struct* ctx, + const struct _cmsContext_struct* src); + +// Container for formatters plug-in +typedef struct { + + struct _cms_formatters_factory_list* FactoryList; + +} _cmsFormattersPluginChunkType; + +// The global Context0 storage for formatters plug-in +extern _cmsFormattersPluginChunkType _cmsFormattersPluginChunk; + +// Allocate and init formatters container. +void _cmsAllocFormattersPluginChunk(struct _cmsContext_struct* ctx, + const struct _cmsContext_struct* src); + +// This chunk type is shared by TagType plug-in and MPE Plug-in +typedef struct { + + struct _cmsTagTypeLinkedList_st* TagTypes; + +} _cmsTagTypePluginChunkType; + + +// The global Context0 storage for tag types plug-in +extern _cmsTagTypePluginChunkType _cmsTagTypePluginChunk; + + +// The global Context0 storage for mult process elements plug-in +extern _cmsTagTypePluginChunkType _cmsMPETypePluginChunk; + +// Allocate and init Tag types container. +void _cmsAllocTagTypePluginChunk(struct _cmsContext_struct* ctx, + const struct _cmsContext_struct* src); +// Allocate and init MPE container. +void _cmsAllocMPETypePluginChunk(struct _cmsContext_struct* ctx, + const struct _cmsContext_struct* src); +// Container for tag plug-in +typedef struct { + + struct _cmsTagLinkedList_st* Tag; + +} _cmsTagPluginChunkType; + + +// The global Context0 storage for tag plug-in +extern _cmsTagPluginChunkType _cmsTagPluginChunk; + +// Allocate and init Tag container. +void _cmsAllocTagPluginChunk(struct _cmsContext_struct* ctx, + const struct _cmsContext_struct* src); + +// Container for intents plug-in +typedef struct { + + struct _cms_intents_list* Intents; + +} _cmsIntentsPluginChunkType; + + +// The global Context0 storage for intents plug-in +extern _cmsIntentsPluginChunkType _cmsIntentsPluginChunk; + +// Allocate and init intents container. +void _cmsAllocIntentsPluginChunk(struct _cmsContext_struct* ctx, + const struct _cmsContext_struct* src); + +// Container for optimization plug-in +typedef struct { + + struct _cmsOptimizationCollection_st* OptimizationCollection; + +} _cmsOptimizationPluginChunkType; + + +// The global Context0 storage for optimizers plug-in +extern _cmsOptimizationPluginChunkType _cmsOptimizationPluginChunk; + +// Allocate and init optimizers container. +void _cmsAllocOptimizationPluginChunk(struct _cmsContext_struct* ctx, + const struct _cmsContext_struct* src); + +// Container for transform plug-in +typedef struct { + + struct _cmsTransformCollection_st* TransformCollection; + +} _cmsTransformPluginChunkType; + +// The global Context0 storage for full-transform replacement plug-in +extern _cmsTransformPluginChunkType _cmsTransformPluginChunk; + +// Allocate and init transform container. +void _cmsAllocTransformPluginChunk(struct _cmsContext_struct* ctx, + const struct _cmsContext_struct* src); + +// Container for mutex plug-in +typedef struct { + + _cmsCreateMutexFnPtrType CreateMutexPtr; + _cmsDestroyMutexFnPtrType DestroyMutexPtr; + _cmsLockMutexFnPtrType LockMutexPtr; + _cmsUnlockMutexFnPtrType UnlockMutexPtr; + +} _cmsMutexPluginChunkType; + +// The global Context0 storage for mutex plug-in +extern _cmsMutexPluginChunkType _cmsMutexPluginChunk; + +// Allocate and init mutex container. +void _cmsAllocMutexPluginChunk(struct _cmsContext_struct* ctx, + const struct _cmsContext_struct* src); + +// ---------------------------------------------------------------------------------- // MLU internal representation typedef struct { @@ -347,10 +760,14 @@ typedef struct _cms_iccprofile_struct { cmsBool TagSaveAsRaw[MAX_TABLE_TAG]; // True to write uncooked void * TagPtrs[MAX_TABLE_TAG]; cmsTagTypeHandler* TagTypeHandlers[MAX_TABLE_TAG]; // Same structure may be serialized on different types - // depending on profile version, so we keep track of the // type handler for each tag in the list. + // depending on profile version, so we keep track of the + // type handler for each tag in the list. // Special cmsBool IsWrite; + // Keep a mutex for cmsReadTag -- Note that this only works if the user includes a mutex plugin + void * UsrMutex; + } _cmsICCPROFILE; // IO helpers for profiles @@ -359,9 +776,9 @@ cmsBool _cmsWriteHeader(_cmsICCPROFILE* Icc, cmsUInt32Number UsedSp int _cmsSearchTag(_cmsICCPROFILE* Icc, cmsTagSignature sig, cmsBool lFollowLinks); // Tag types -cmsTagTypeHandler* _cmsGetTagTypeHandler(cmsTagTypeSignature sig); +cmsTagTypeHandler* _cmsGetTagTypeHandler(cmsContext ContextID, cmsTagTypeSignature sig); cmsTagTypeSignature _cmsGetTagTrueType(cmsHPROFILE hProfile, cmsTagSignature sig); -cmsTagDescriptor* _cmsGetTagDescriptor(cmsTagSignature sig); +cmsTagDescriptor* _cmsGetTagDescriptor(cmsContext ContextID, cmsTagSignature sig); // Error logging --------------------------------------------------------------------------------------------------------- @@ -372,7 +789,7 @@ void _cmsTagSignature2String(char String[5], cmsTagSignature sig cmsInterpParams* _cmsComputeInterpParams(cmsContext ContextID, int nSamples, int InputChan, int OutputChan, const void* Table, cmsUInt32Number dwFlags); cmsInterpParams* _cmsComputeInterpParamsEx(cmsContext ContextID, const cmsUInt32Number nSamples[], int InputChan, int OutputChan, const void* Table, cmsUInt32Number dwFlags); void _cmsFreeInterpParams(cmsInterpParams* p); -cmsBool _cmsSetInterpolationRoutine(cmsInterpParams* p); +cmsBool _cmsSetInterpolationRoutine(cmsContext ContextID, cmsInterpParams* p); // Curves ---------------------------------------------------------------------------------------------------------------- @@ -503,7 +920,8 @@ cmsBool _cmsEndPointsBySpace(cmsColorSpaceSignature Space, cmsUInt16Number **Black, cmsUInt32Number *nOutputs); -cmsBool _cmsOptimizePipeline(cmsPipeline** Lut, +cmsBool _cmsOptimizePipeline(cmsContext ContextID, + cmsPipeline** Lut, int Intent, cmsUInt32Number* InputFormat, cmsUInt32Number* OutputFormat, @@ -528,7 +946,8 @@ cmsPipeline* _cmsCreateGamutCheckPipeline(cmsContext ContextID, cmsBool _cmsFormatterIsFloat(cmsUInt32Number Type); cmsBool _cmsFormatterIs8bit(cmsUInt32Number Type); -cmsFormatter _cmsGetFormatter(cmsUInt32Number Type, // Specific type, i.e. TYPE_RGB_8 +cmsFormatter _cmsGetFormatter(cmsContext ContextID, + cmsUInt32Number Type, // Specific type, i.e. TYPE_RGB_8 cmsFormatterDirection Dir, cmsUInt32Number dwFlags); diff --git a/jdk/src/java.desktop/share/native/liblcms/lcms2_plugin.h b/jdk/src/java.desktop/share/native/liblcms/lcms2_plugin.h index 1df7cf79b8d..77ff22846eb 100644 --- a/jdk/src/java.desktop/share/native/liblcms/lcms2_plugin.h +++ b/jdk/src/java.desktop/share/native/liblcms/lcms2_plugin.h @@ -231,6 +231,7 @@ typedef void* (* _cmsDupUserDataFn)(cmsContext ContextID, const void* Data); #define cmsPluginMultiProcessElementSig 0x6D706548 // 'mpeH' #define cmsPluginOptimizationSig 0x6F707448 // 'optH' #define cmsPluginTransformSig 0x7A666D48 // 'xfmH' +#define cmsPluginMutexSig 0x6D747A48 // 'mtxH' typedef struct _cmsPluginBaseStruct { @@ -247,19 +248,28 @@ typedef struct _cmsPluginBaseStruct { //---------------------------------------------------------------------------------------------------------- // Memory handler. Each new plug-in type replaces current behaviour + +typedef void* (* _cmsMallocFnPtrType)(cmsContext ContextID, cmsUInt32Number size); +typedef void (* _cmsFreeFnPtrType)(cmsContext ContextID, void *Ptr); +typedef void* (* _cmsReallocFnPtrType)(cmsContext ContextID, void* Ptr, cmsUInt32Number NewSize); + +typedef void* (* _cmsMalloZerocFnPtrType)(cmsContext ContextID, cmsUInt32Number size); +typedef void* (* _cmsCallocFnPtrType)(cmsContext ContextID, cmsUInt32Number num, cmsUInt32Number size); +typedef void* (* _cmsDupFnPtrType)(cmsContext ContextID, const void* Org, cmsUInt32Number size); + typedef struct { cmsPluginBase base; // Required - void * (* MallocPtr)(cmsContext ContextID, cmsUInt32Number size); - void (* FreePtr)(cmsContext ContextID, void *Ptr); - void * (* ReallocPtr)(cmsContext ContextID, void* Ptr, cmsUInt32Number NewSize); + _cmsMallocFnPtrType MallocPtr; + _cmsFreeFnPtrType FreePtr; + _cmsReallocFnPtrType ReallocPtr; // Optional - void * (* MallocZeroPtr)(cmsContext ContextID, cmsUInt32Number size); - void * (* CallocPtr)(cmsContext ContextID, cmsUInt32Number num, cmsUInt32Number size); - void * (* DupPtr)(cmsContext ContextID, const void* Org, cmsUInt32Number size); + _cmsMalloZerocFnPtrType MallocZeroPtr; + _cmsCallocFnPtrType CallocPtr; + _cmsDupFnPtrType DupPtr; } cmsPluginMemHandler; @@ -622,6 +632,29 @@ typedef struct { } cmsPluginTransform; +//---------------------------------------------------------------------------------------------------------- +// Mutex + +typedef void* (* _cmsCreateMutexFnPtrType)(cmsContext ContextID); +typedef void (* _cmsDestroyMutexFnPtrType)(cmsContext ContextID, void* mtx); +typedef cmsBool (* _cmsLockMutexFnPtrType)(cmsContext ContextID, void* mtx); +typedef void (* _cmsUnlockMutexFnPtrType)(cmsContext ContextID, void* mtx); + +typedef struct { + cmsPluginBase base; + + _cmsCreateMutexFnPtrType CreateMutexPtr; + _cmsDestroyMutexFnPtrType DestroyMutexPtr; + _cmsLockMutexFnPtrType LockMutexPtr; + _cmsUnlockMutexFnPtrType UnlockMutexPtr; + +} cmsPluginMutex; + +CMSAPI void* CMSEXPORT _cmsCreateMutex(cmsContext ContextID); +CMSAPI void CMSEXPORT _cmsDestroyMutex(cmsContext ContextID, void* mtx); +CMSAPI cmsBool CMSEXPORT _cmsLockMutex(cmsContext ContextID, void* mtx); +CMSAPI void CMSEXPORT _cmsUnlockMutex(cmsContext ContextID, void* mtx); + #ifndef CMS_USE_CPP_API # ifdef __cplusplus From 1d67714f2af98fab7812b651d32aeb0e477c3139 Mon Sep 17 00:00:00 2001 From: Alexander Scherbatiy Date: Fri, 5 Sep 2014 12:57:24 +0400 Subject: [PATCH 20/81] 8057184: JCK8's api/javax_swing/JDesktopPane/descriptions.html#getset failed with GTKLookAndFeel on Linux and Solaris Reviewed-by: ant, azvegint --- .../java.desktop/share/classes/javax/swing/JDesktopPane.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/jdk/src/java.desktop/share/classes/javax/swing/JDesktopPane.java b/jdk/src/java.desktop/share/classes/javax/swing/JDesktopPane.java index 54142344e37..047070460bc 100644 --- a/jdk/src/java.desktop/share/classes/javax/swing/JDesktopPane.java +++ b/jdk/src/java.desktop/share/classes/javax/swing/JDesktopPane.java @@ -43,6 +43,7 @@ import java.io.IOException; import java.beans.PropertyVetoException; import java.util.Set; import java.util.TreeSet; +import java.util.LinkedHashSet; /** * A container used to create a multiple-document interface or a virtual desktop. * You create JInternalFrame objects and add them to the @@ -271,7 +272,7 @@ public class JDesktopPane extends JLayeredPane implements Accessible private static Collection getAllFrames(Container parent) { int i, count; - Collection results = new ArrayList(); + Collection results = new LinkedHashSet<>(); count = parent.getComponentCount(); for (i = 0; i < count; i++) { Component next = parent.getComponent(i); From e18a2c3b29338a65e45046ccb82b77dd92b505a5 Mon Sep 17 00:00:00 2001 From: Phil Race Date: Mon, 8 Sep 2014 09:07:59 -0700 Subject: [PATCH 21/81] 8056209: Remove unused files for libawt Reviewed-by: erikj, ihse, serb --- jdk/make/lib/Awt2dLibraries.gmk | 2 - .../sun/awt/windows/WBufferStrategy.java | 49 --------------- .../libawt/sun/java2d/d3d/D3DPipeline.cpp | 40 ------------- .../libawt/sun/windows/WBufferStrategy.cpp | 60 ------------------- 4 files changed, 151 deletions(-) delete mode 100644 jdk/src/java.desktop/windows/classes/sun/awt/windows/WBufferStrategy.java delete mode 100644 jdk/src/java.desktop/windows/native/libawt/sun/java2d/d3d/D3DPipeline.cpp delete mode 100644 jdk/src/java.desktop/windows/native/libawt/sun/windows/WBufferStrategy.cpp diff --git a/jdk/make/lib/Awt2dLibraries.gmk b/jdk/make/lib/Awt2dLibraries.gmk index e5161a35552..fa74e6e3694 100644 --- a/jdk/make/lib/Awt2dLibraries.gmk +++ b/jdk/make/lib/Awt2dLibraries.gmk @@ -217,10 +217,8 @@ ifeq ($(OPENJDK_TARGET_OS), windows) -I$(JDK_OUTPUTDIR)/gensrc_headers/java.base \ # LIBAWT_EXFILES += \ - sun/java2d/d3d/D3DPipeline.cpp \ sun/java2d/d3d/D3DShaderGen.c \ sun/awt/image/cvutils/img_colors.c \ - sun/windows/WBufferStrategy.cpp \ # LIBAWT_LANG := C++ diff --git a/jdk/src/java.desktop/windows/classes/sun/awt/windows/WBufferStrategy.java b/jdk/src/java.desktop/windows/classes/sun/awt/windows/WBufferStrategy.java deleted file mode 100644 index 372b3ccf6d8..00000000000 --- a/jdk/src/java.desktop/windows/classes/sun/awt/windows/WBufferStrategy.java +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright (c) 2002, 2014, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - - -package sun.awt.windows; - -import java.awt.Image; -import java.awt.Component; - -/** - * This sun-private class exists solely to get a handle to - * the back buffer associated with a Component. If that - * Component has a BufferStrategy with >1 buffer, then the - * Image subclass associated with that buffer will be returned. - * Note: the class is used by the JAWT3d. - */ -public final class WBufferStrategy { - - private static native void initIDs(Class componentClass); - - static { - initIDs(Component.class); - } - - public static native Image getDrawBuffer(Component comp); - -} diff --git a/jdk/src/java.desktop/windows/native/libawt/sun/java2d/d3d/D3DPipeline.cpp b/jdk/src/java.desktop/windows/native/libawt/sun/java2d/d3d/D3DPipeline.cpp deleted file mode 100644 index 16e9e2209d7..00000000000 --- a/jdk/src/java.desktop/windows/native/libawt/sun/java2d/d3d/D3DPipeline.cpp +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Copyright (c) 2007, 2008, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -#include "D3DPipeline.h" - -BOOL APIENTRY DllMain( HANDLE hModule, - DWORD ul_reason_for_call, - LPVOID lpReserved) -{ - switch (ul_reason_for_call) { - case DLL_PROCESS_ATTACH: - case DLL_THREAD_ATTACH: - case DLL_THREAD_DETACH: - case DLL_PROCESS_DETACH: - break; - } - return TRUE; -} diff --git a/jdk/src/java.desktop/windows/native/libawt/sun/windows/WBufferStrategy.cpp b/jdk/src/java.desktop/windows/native/libawt/sun/windows/WBufferStrategy.cpp deleted file mode 100644 index daf24f3d54f..00000000000 --- a/jdk/src/java.desktop/windows/native/libawt/sun/windows/WBufferStrategy.cpp +++ /dev/null @@ -1,60 +0,0 @@ -/* - * Copyright (c) 2002, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -#include "sun_awt_windows_WBufferStrategy.h" -#include "jni_util.h" - - -static jmethodID getBackBufferID; - -/* - * Class: sun_awt_windows_WBufferStrategy - * Method: initIDs - * Signature: (Ljava/lang/Class;)V - */ -JNIEXPORT void JNICALL -Java_sun_awt_windows_WBufferStrategy_initIDs(JNIEnv *env, jclass wbs, - jclass componentClass) -{ - getBackBufferID = env->GetMethodID(componentClass, "getBackBuffer", - "()Ljava/awt/Image;"); -} - -/** - * Native method of WBufferStrategy.java. Given a Component - * object, this method will find the back buffer associated - * with the Component's BufferStrategy and return a handle - * to it. - */ -extern "C" JNIEXPORT jobject JNICALL -Java_sun_awt_windows_WBufferStrategy_getDrawBuffer(JNIEnv *env, jclass wbs, - jobject component) -{ - if (!JNU_IsNull(env, getBackBufferID)) { - return env->CallObjectMethod(component, getBackBufferID); - } else { - return NULL; - } -} From 52682ab314dacdf28003c222bfce83f38204fd54 Mon Sep 17 00:00:00 2001 From: Claes Redestad Date: Fri, 12 Sep 2014 17:34:13 +0200 Subject: [PATCH 22/81] 8058230: Improve java.sql toString formatting Reviewed-by: lancea --- .../java.sql/share/classes/java/sql/Date.java | 37 ++++-- .../java.sql/share/classes/java/sql/Time.java | 31 ++---- .../share/classes/java/sql/Timestamp.java | 105 +++++------------- 3 files changed, 66 insertions(+), 107 deletions(-) diff --git a/jdk/src/java.sql/share/classes/java/sql/Date.java b/jdk/src/java.sql/share/classes/java/sql/Date.java index a0e8c287b2c..ccf450f985e 100644 --- a/jdk/src/java.sql/share/classes/java/sql/Date.java +++ b/jdk/src/java.sql/share/classes/java/sql/Date.java @@ -27,6 +27,8 @@ package java.sql; import java.time.Instant; import java.time.LocalDate; +import sun.misc.SharedSecrets; +import sun.misc.JavaLangAccess; /** *

A thin wrapper around a millisecond value that allows @@ -42,6 +44,8 @@ import java.time.LocalDate; */ public class Date extends java.util.Date { + private static final JavaLangAccess jla = SharedSecrets.getJavaLangAccess(); + /** * Constructs a Date object initialized with the given * year, month, and day. @@ -155,17 +159,30 @@ public class Date extends java.util.Date { int month = super.getMonth() + 1; int day = super.getDate(); - char buf[] = "2000-00-00".toCharArray(); - buf[0] = Character.forDigit(year/1000,10); - buf[1] = Character.forDigit((year/100)%10,10); - buf[2] = Character.forDigit((year/10)%10,10); - buf[3] = Character.forDigit(year%10,10); - buf[5] = Character.forDigit(month/10,10); - buf[6] = Character.forDigit(month%10,10); - buf[8] = Character.forDigit(day/10,10); - buf[9] = Character.forDigit(day%10,10); + char buf[] = new char[10]; + formatDecimalInt(year, buf, 0, 4); + buf[4] = '-'; + Date.formatDecimalInt(month, buf, 5, 2); + buf[7] = '-'; + Date.formatDecimalInt(day, buf, 8, 2); - return new String(buf); + return jla.newStringUnsafe(buf); + } + + /* + * Formats an unsigned integer into a char array in decimal output format. + * Numbers will be zero-padded or truncated if the string representation + * of the integer is smaller than or exceeds len, respectively. + * + * Should consider moving this to Integer and expose it through + * JavaLangAccess similar to Integer::formatUnsignedInt + */ + protected static void formatDecimalInt(int val, char[] buf, int offset, int len) { + int charPos = offset + len; + do { + buf[--charPos] = (char)('0' + (val % 10)); + val /= 10; + } while (charPos > offset); } // Override all the time operations inherited from java.util.Date; diff --git a/jdk/src/java.sql/share/classes/java/sql/Time.java b/jdk/src/java.sql/share/classes/java/sql/Time.java index 209a4b646a9..ec4863a7535 100644 --- a/jdk/src/java.sql/share/classes/java/sql/Time.java +++ b/jdk/src/java.sql/share/classes/java/sql/Time.java @@ -27,6 +27,8 @@ package java.sql; import java.time.Instant; import java.time.LocalTime; +import sun.misc.SharedSecrets; +import sun.misc.JavaLangAccess; /** *

A thin wrapper around the java.util.Date class that allows the JDBC @@ -39,6 +41,8 @@ import java.time.LocalTime; */ public class Time extends java.util.Date { + private static final JavaLangAccess jla = SharedSecrets.getJavaLangAccess(); + /** * Constructs a Time object initialized with the * given values for the hour, minute, and second. @@ -120,26 +124,15 @@ public class Time extends java.util.Date { int hour = super.getHours(); int minute = super.getMinutes(); int second = super.getSeconds(); - String hourString; - String minuteString; - String secondString; - if (hour < 10) { - hourString = "0" + hour; - } else { - hourString = Integer.toString(hour); - } - if (minute < 10) { - minuteString = "0" + minute; - } else { - minuteString = Integer.toString(minute); - } - if (second < 10) { - secondString = "0" + second; - } else { - secondString = Integer.toString(second); - } - return (hourString + ":" + minuteString + ":" + secondString); + char[] buf = new char[8]; + Date.formatDecimalInt(hour, buf, 0, 2); + buf[2] = ':'; + Date.formatDecimalInt(minute, buf, 3, 2); + buf[5] = ':'; + Date.formatDecimalInt(second, buf, 6, 2); + + return jla.newStringUnsafe(buf); } // Override all the date operations inherited from java.util.Date; diff --git a/jdk/src/java.sql/share/classes/java/sql/Timestamp.java b/jdk/src/java.sql/share/classes/java/sql/Timestamp.java index 1fb64c60be6..e66831f85b9 100644 --- a/jdk/src/java.sql/share/classes/java/sql/Timestamp.java +++ b/jdk/src/java.sql/share/classes/java/sql/Timestamp.java @@ -27,7 +27,8 @@ package java.sql; import java.time.Instant; import java.time.LocalDateTime; -import java.util.StringTokenizer; +import sun.misc.SharedSecrets; +import sun.misc.JavaLangAccess; /** *

A thin wrapper around java.util.Date that allows @@ -71,6 +72,8 @@ import java.util.StringTokenizer; */ public class Timestamp extends java.util.Date { + private static final JavaLangAccess jla = SharedSecrets.getJavaLangAccess(); + /** * Constructs a Timestamp object initialized * with the given values. @@ -262,95 +265,41 @@ public class Timestamp extends java.util.Date { * yyyy-mm-dd hh:mm:ss.fffffffff format */ @SuppressWarnings("deprecation") - public String toString () { - + public String toString() { int year = super.getYear() + 1900; int month = super.getMonth() + 1; int day = super.getDate(); int hour = super.getHours(); int minute = super.getMinutes(); int second = super.getSeconds(); - String yearString; - String monthString; - String dayString; - String hourString; - String minuteString; - String secondString; - String nanosString; - String zeros = "000000000"; - String yearZeros = "0000"; - StringBuffer timestampBuf; - if (year < 1000) { - // Add leading zeros - yearString = "" + year; - yearString = yearZeros.substring(0, (4-yearString.length())) + - yearString; + int trailingZeros = 0; + int tmpNanos = nanos; + if (tmpNanos == 0) { + trailingZeros = 8; } else { - yearString = "" + year; - } - if (month < 10) { - monthString = "0" + month; - } else { - monthString = Integer.toString(month); - } - if (day < 10) { - dayString = "0" + day; - } else { - dayString = Integer.toString(day); - } - if (hour < 10) { - hourString = "0" + hour; - } else { - hourString = Integer.toString(hour); - } - if (minute < 10) { - minuteString = "0" + minute; - } else { - minuteString = Integer.toString(minute); - } - if (second < 10) { - secondString = "0" + second; - } else { - secondString = Integer.toString(second); - } - if (nanos == 0) { - nanosString = "0"; - } else { - nanosString = Integer.toString(nanos); - - // Add leading zeros - nanosString = zeros.substring(0, (9-nanosString.length())) + - nanosString; - - // Truncate trailing zeros - char[] nanosChar = new char[nanosString.length()]; - nanosString.getChars(0, nanosString.length(), nanosChar, 0); - int truncIndex = 8; - while (nanosChar[truncIndex] == '0') { - truncIndex--; + while (tmpNanos % 10 == 0) { + tmpNanos /= 10; + trailingZeros++; } - - nanosString = new String(nanosChar, 0, truncIndex + 1); } - // do a string buffer here instead. - timestampBuf = new StringBuffer(20+nanosString.length()); - timestampBuf.append(yearString); - timestampBuf.append("-"); - timestampBuf.append(monthString); - timestampBuf.append("-"); - timestampBuf.append(dayString); - timestampBuf.append(" "); - timestampBuf.append(hourString); - timestampBuf.append(":"); - timestampBuf.append(minuteString); - timestampBuf.append(":"); - timestampBuf.append(secondString); - timestampBuf.append("."); - timestampBuf.append(nanosString); + char[] buf = new char[29 - trailingZeros]; + Date.formatDecimalInt(year, buf, 0, 4); + buf[4] = '-'; + Date.formatDecimalInt(month, buf, 5, 2); + buf[7] = '-'; + Date.formatDecimalInt(day, buf, 8, 2); + buf[10] = ' '; + Date.formatDecimalInt(hour, buf, 11, 2); + buf[13] = ':'; + Date.formatDecimalInt(minute, buf, 14, 2); + buf[16] = ':'; + Date.formatDecimalInt(second, buf, 17, 2); + buf[19] = '.'; + Date.formatDecimalInt(tmpNanos, buf, 20, 9 - trailingZeros); - return (timestampBuf.toString()); + return jla.newStringUnsafe(buf); } /** From 657d8c6e77ce4d77eb181ba70d3b30b7c4f80315 Mon Sep 17 00:00:00 2001 From: Shanliang Jiang Date: Fri, 12 Sep 2014 20:19:24 +0200 Subject: [PATCH 23/81] 8057951: javax/management/monitor/... should be quarantined Reviewed-by: jbachorik --- jdk/test/ProblemList.txt | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/jdk/test/ProblemList.txt b/jdk/test/ProblemList.txt index 9b69db7c116..7acfaef1e72 100644 --- a/jdk/test/ProblemList.txt +++ b/jdk/test/ProblemList.txt @@ -142,6 +142,13 @@ javax/management/MBeanServer/OldMBeanServerTest.java aix-all # 8050115 javax/management/monitor/GaugeMonitorDeadlockTest.java generic-all +# 8042205 8057951 generic-all +javax/management/monitor/CounterMonitorTest.java +javax/management/monitor/NonComparableAttributeValueTest.java +javax/management/monitor/ReflectionExceptionTest.java +javax/management/monitor/RuntimeExceptionTest.java +javax/management/monitor/AttributeArbitraryDataTypeTest.java + ############################################################################ # jdk_math From 9e30841d2885357ade9ce1fdf331e823c0018696 Mon Sep 17 00:00:00 2001 From: Konstantin Shefov Date: Fri, 12 Sep 2014 22:33:09 +0400 Subject: [PATCH 24/81] 8057707: TEST library enhancement in lib/testlibrary/jsr292/com/oracle/testlibrary/jsr292/Helper.java Reviewed-by: iignatyev, vlivanov --- .../MethodHandles/CatchExceptionTest.java | 41 ++-------------- .../com/oracle/testlibrary/jsr292/Helper.java | 48 +++++++++++++++++-- 2 files changed, 49 insertions(+), 40 deletions(-) diff --git a/jdk/test/java/lang/invoke/MethodHandles/CatchExceptionTest.java b/jdk/test/java/lang/invoke/MethodHandles/CatchExceptionTest.java index 739ca6dc255..52c41dfd991 100644 --- a/jdk/test/java/lang/invoke/MethodHandles/CatchExceptionTest.java +++ b/jdk/test/java/lang/invoke/MethodHandles/CatchExceptionTest.java @@ -42,6 +42,7 @@ import java.util.function.Supplier; public class CatchExceptionTest { private static final List> ARGS_CLASSES; protected static final int MAX_ARITY = Helper.MAX_ARITY - 1; + static { Class classes[] = { Object.class, @@ -52,11 +53,8 @@ public class CatchExceptionTest { double[].class, String.class, }; - List> list = new ArrayList<>(MAX_ARITY); - for (int i = 0; i < MAX_ARITY; ++i) { - list.add(classes[Helper.RNG.nextInt(classes.length)]); - } - ARGS_CLASSES = Collections.unmodifiableList(list); + ARGS_CLASSES = Collections.unmodifiableList( + Helper.randomClasses(classes, MAX_ARITY)); } private final TestCase testCase; @@ -66,7 +64,6 @@ public class CatchExceptionTest { private int dropped; private MethodHandle thrower; - public CatchExceptionTest(TestCase testCase, final boolean isVararg, final int argsCount, final int catchDrops) { this.testCase = testCase; @@ -107,37 +104,7 @@ public class CatchExceptionTest { } private List> getThrowerParams(boolean isVararg, int argsCount) { - boolean unmodifiable = true; - List> classes; - classes = ARGS_CLASSES.subList(0, - Math.min(argsCount, (MAX_ARITY / 2) - 1)); - int extra = 0; - if (argsCount >= MAX_ARITY / 2) { - classes = new ArrayList<>(classes); - unmodifiable = false; - extra = (int) classes.stream().filter(Helper::isDoubleCost).count(); - int i = classes.size(); - while (classes.size() + extra < argsCount) { - Class aClass = ARGS_CLASSES.get(i); - if (Helper.isDoubleCost(aClass)) { - ++extra; - if (classes.size() + extra >= argsCount) { - break; - } - } - classes.add(aClass); - } - } - if (isVararg && classes.size() > 0) { - if (unmodifiable) { - classes = new ArrayList<>(classes); - } - int last = classes.size() - 1; - Class aClass = classes.get(classes.size() - 1); - aClass = Array.newInstance(aClass, 2).getClass(); - classes.set(last, aClass); - } - return classes; + return Helper.getParams(ARGS_CLASSES, isVararg, argsCount); } diff --git a/jdk/test/lib/testlibrary/jsr292/com/oracle/testlibrary/jsr292/Helper.java b/jdk/test/lib/testlibrary/jsr292/com/oracle/testlibrary/jsr292/Helper.java index bbed7f42185..3d720b3507c 100644 --- a/jdk/test/lib/testlibrary/jsr292/com/oracle/testlibrary/jsr292/Helper.java +++ b/jdk/test/lib/testlibrary/jsr292/com/oracle/testlibrary/jsr292/Helper.java @@ -52,7 +52,7 @@ public class Helper { public static final long TEST_LIMIT; static { String str = System.getProperty("testLimit"); - TEST_LIMIT = str != null ? Long.parseUnsignedLong(str) : 2_000L; + TEST_LIMIT = str != null ? Long.parseUnsignedLong(str) : 2000L; System.out.printf("-DtestLimit=%d%n", TEST_LIMIT); } @@ -116,6 +116,48 @@ public class Helper { return size <= lag ? null : calledLog.get(size - lag - 1); } + public static List> randomClasses(Class[] classes, int size) { + List> result = new ArrayList<>(size); + for (int i = 0; i < size; ++i) { + result.add(classes[RNG.nextInt(classes.length)]); + } + return result; + } + + public static List> getParams(List> classes, + boolean isVararg, int argsCount) { + boolean unmodifiable = true; + List> result = classes.subList(0, + Math.min(argsCount, (MAX_ARITY / 2) - 1)); + int extra = 0; + if (argsCount >= MAX_ARITY / 2) { + result = new ArrayList<>(result); + unmodifiable = false; + extra = (int) result.stream().filter(Helper::isDoubleCost).count(); + int i = result.size(); + while (result.size() + extra < argsCount) { + Class aClass = classes.get(i); + if (Helper.isDoubleCost(aClass)) { + ++extra; + if (result.size() + extra >= argsCount) { + break; + } + } + result.add(aClass); + } + } + if (isVararg && result.size() > 0) { + if (unmodifiable) { + result = new ArrayList<>(result); + } + int last = result.size() - 1; + Class aClass = result.get(last); + aClass = Array.newInstance(aClass, 2).getClass(); + result.set(last, aClass); + } + return result; + } + public static MethodHandle addTrailingArgs(MethodHandle target, int nargs, List> classes) { int targetLen = target.type().parameterCount(); @@ -230,7 +272,7 @@ public class Helper { return randomArgs(params.toArray(new Class[params.size()])); } - private static Object castToWrapper(Object value, Class dst) { + public static Object castToWrapper(Object value, Class dst) { Object wrap = null; if (value instanceof Number) { wrap = castToWrapperOrNull(((Number) value).longValue(), dst); @@ -268,7 +310,7 @@ public class Helper { if (dst == byte.class || dst == Byte.class) { return (byte) (value); } - if (dst == boolean.class || dst == boolean.class) { + if (dst == boolean.class || dst == Boolean.class) { return ((value % 29) & 1) == 0; } return null; From 881fa79cfe042b31679ec0fdc104f0166b94f95a Mon Sep 17 00:00:00 2001 From: Konstantin Shefov Date: Fri, 12 Sep 2014 22:33:09 +0400 Subject: [PATCH 25/81] 8057719: Develop new tests for LambdaForm Reduction and Caching feature Reviewed-by: iignatyev, vlivanov, psandoz --- .../invoke/LFCaching/LFCachingTestCase.java | 78 ++ .../LFCaching/LFGarbageCollectedTest.java | 102 +++ .../LFCaching/LFMultiThreadCachingTest.java | 111 +++ .../LFCaching/LFSingleThreadCachingTest.java | 78 ++ .../invoke/LFCaching/LambdaFormTestCase.java | 117 +++ .../lang/invoke/LFCaching/TestMethods.java | 698 ++++++++++++++++++ 6 files changed, 1184 insertions(+) create mode 100644 jdk/test/java/lang/invoke/LFCaching/LFCachingTestCase.java create mode 100644 jdk/test/java/lang/invoke/LFCaching/LFGarbageCollectedTest.java create mode 100644 jdk/test/java/lang/invoke/LFCaching/LFMultiThreadCachingTest.java create mode 100644 jdk/test/java/lang/invoke/LFCaching/LFSingleThreadCachingTest.java create mode 100644 jdk/test/java/lang/invoke/LFCaching/LambdaFormTestCase.java create mode 100644 jdk/test/java/lang/invoke/LFCaching/TestMethods.java diff --git a/jdk/test/java/lang/invoke/LFCaching/LFCachingTestCase.java b/jdk/test/java/lang/invoke/LFCaching/LFCachingTestCase.java new file mode 100644 index 00000000000..30ba39ac2e0 --- /dev/null +++ b/jdk/test/java/lang/invoke/LFCaching/LFCachingTestCase.java @@ -0,0 +1,78 @@ +/* + * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.lang.invoke.MethodHandle; +import java.lang.reflect.InvocationTargetException; + +/** + * Abstract class for lambda forms caching testing. + * + * @author kshefov + */ +public abstract class LFCachingTestCase extends LambdaFormTestCase { + + /** + * Constructor for lambda forms caching test case. + * + * @param testMethod A method from {@code j.l.i.MethodHandles} class that + * returns a {@code j.l.i.MethodHandle} instance. + */ + protected LFCachingTestCase(TestMethods testMethod) { + super(testMethod); + } + + /** + * Checks that the lambda forms of the two adapter method handles adapter1 + * and adapter2 are the same. + * + * @param adapter1 First method handle. + * @param adapter2 Second method handle. + */ + public void checkLFCaching(MethodHandle adapter1, MethodHandle adapter2) { + try { + + if (!adapter1.type().equals(adapter2.type())) { + throw new Error("TESTBUG: Types of the two method handles are not the same"); + } + + Object lambdaForm0 = LambdaFormTestCase.INTERNAL_FORM.invoke(adapter1); + Object lambdaForm1 = LambdaFormTestCase.INTERNAL_FORM.invoke(adapter2); + + if (lambdaForm0 == null || lambdaForm1 == null) { + throw new Error("Unexpected error: One or both lambda forms of the method handles are null"); + } + + if (lambdaForm0 != lambdaForm1) { + System.err.println("Lambda form 0 toString is:"); + System.err.println(lambdaForm0); + System.err.println("Lambda form 1 toString is:"); + System.err.println(lambdaForm1); + throw new AssertionError("Error: Lambda forms of the two method handles" + + " are not the same. LF cahing does not work"); + } + } catch (IllegalAccessException | IllegalArgumentException | + SecurityException | InvocationTargetException ex) { + throw new Error("Unexpected exception: ", ex); + } + } +} diff --git a/jdk/test/java/lang/invoke/LFCaching/LFGarbageCollectedTest.java b/jdk/test/java/lang/invoke/LFCaching/LFGarbageCollectedTest.java new file mode 100644 index 00000000000..f204074698b --- /dev/null +++ b/jdk/test/java/lang/invoke/LFCaching/LFGarbageCollectedTest.java @@ -0,0 +1,102 @@ +/* + * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test LFGarbageCollectedTest + * @bug 8046703 + * @summary Test verifies that lambda forms are garbage collected + * @author kshefov + * @library /lib/testlibrary/jsr292 /lib/testlibrary + * @build TestMethods + * @build LambdaFormTestCase + * @build LFGarbageCollectedTest + * @run main/othervm/timeout=600 -Djava.lang.invoke.MethodHandle.USE_LF_EDITOR=true -DtestLimit=150 -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI LFGarbageCollectedTest + */ + +import java.lang.invoke.MethodHandle; +import java.lang.ref.PhantomReference; +import java.lang.ref.ReferenceQueue; +import java.lang.reflect.InvocationTargetException; +import java.util.Arrays; +import java.util.EnumSet; +import java.util.Map; + +/** + * Lambda forms garbage collection test class. + */ +public final class LFGarbageCollectedTest extends LambdaFormTestCase { + + /** + * Constructor for a lambda forms garbage collection test case. + * + * @param testMethod A method from {@code j.l.i.MethodHandles} class that + * returns a {@code j.l.i.MethodHandle} instance. + */ + public LFGarbageCollectedTest(TestMethods testMethod) { + super(testMethod); + } + + @Override + public void doTest() { + try { + Map data = getTestMethod().getTestCaseData(); + MethodHandle adapter; + try { + adapter = getTestMethod().getTestCaseMH(data, TestMethods.Kind.ONE); + } catch (NoSuchMethodException ex) { + throw new Error("Unexpected exception: ", ex); + } + Object lambdaForm = LambdaFormTestCase.INTERNAL_FORM.invoke(adapter); + if (lambdaForm == null) { + throw new Error("Unexpected error: Lambda form of the method handle is null"); + } + ReferenceQueue rq = new ReferenceQueue(); + PhantomReference ph = new PhantomReference(lambdaForm, rq); + lambdaForm = null; + data = null; + adapter = null; + for (int i = 0; i < 1000 && !ph.isEnqueued(); i++) { + System.gc(); + } + if (!ph.isEnqueued()) { + throw new AssertionError("Error: Lambda form is not garbage collected"); + } + } catch (IllegalAccessException | IllegalArgumentException | + InvocationTargetException ex) { + throw new Error("Unexpected exception: ", ex); + } + } + + /** + * Main routine for lambda forms garbage collection test. + * + * @param args Accepts no arguments. + */ + public static void main(String[] args) { + // The "identity" and "constant" methods should be removed from this test, + // because their lambda forms are stored in a static filed and are not GC'ed. + // There can be only 5 such LFs for each method, so no memory leak happens. + EnumSet testMethods = EnumSet.complementOf(EnumSet.of(TestMethods.IDENTITY, TestMethods.CONSTANT)); + LambdaFormTestCase.runTests(LFGarbageCollectedTest::new, testMethods); + } +} diff --git a/jdk/test/java/lang/invoke/LFCaching/LFMultiThreadCachingTest.java b/jdk/test/java/lang/invoke/LFCaching/LFMultiThreadCachingTest.java new file mode 100644 index 00000000000..a41647246bc --- /dev/null +++ b/jdk/test/java/lang/invoke/LFCaching/LFMultiThreadCachingTest.java @@ -0,0 +1,111 @@ +/* + * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test LFMultiThreadCachingTest + * @bug 8046703 + * @summary Test verifies that lambda forms are cached when run with multiple threads + * @author kshefov + * @library /lib/testlibrary/jsr292 /lib/testlibrary + * @build TestMethods + * @build LambdaFormTestCase + * @build LFCachingTestCase + * @build LFMultiThreadCachingTest + * @run main/othervm/timeout=300 -Djava.lang.invoke.MethodHandle.USE_LF_EDITOR=true LFMultiThreadCachingTest + */ + +import java.lang.invoke.MethodHandle; +import java.util.EnumSet; +import java.util.Map; +import java.util.concurrent.BrokenBarrierException; +import java.util.concurrent.ConcurrentLinkedQueue; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.CyclicBarrier; + +/** + * Multiple threaded lambda forms caching test class. + */ +public final class LFMultiThreadCachingTest extends LFCachingTestCase { + private static final TestMethods.Kind[] KINDS; + static { + EnumSet set = EnumSet.complementOf(EnumSet.of(TestMethods.Kind.EXCEPT)); + KINDS = set.toArray(new TestMethods.Kind[set.size()]); + if (KINDS.length < 2) { + throw new Error("TESTBUG: KINDS.length[" + KINDS.length + "] should be at least 2"); + } + } + private static final int CORES = Math.max(KINDS.length, Runtime.getRuntime().availableProcessors()); + + /** + * Constructor a for multiple threaded lambda forms caching test case. + * + * @param testMethod A method from {@code j.l.i.MethodHandles} class that + * returns a {@code j.l.i.MethodHandle} instance. + */ + public LFMultiThreadCachingTest(TestMethods testMethod) { + super(testMethod); + } + + @Override + public void doTest() { + Map data = getTestMethod().getTestCaseData(); + ConcurrentLinkedQueue adapters = new ConcurrentLinkedQueue<>(); + CyclicBarrier begin = new CyclicBarrier(CORES); + CountDownLatch end = new CountDownLatch(CORES); + for (int i = 0; i < CORES; ++i) { + TestMethods.Kind kind = KINDS[i % KINDS.length]; + new Thread(() -> { + try { + begin.await(); + adapters.add(getTestMethod().getTestCaseMH(data, kind)); + } catch (InterruptedException | BrokenBarrierException | IllegalAccessException | NoSuchMethodException ex) { + throw new Error("Unexpected exception: ", ex); + } finally { + end.countDown(); + } + }).start(); + } + try { + end.await(); + } catch (InterruptedException ex) { + throw new Error("Unexpected exception: ", ex); + } + if (adapters.size() < CORES) { + throw new Error("adapters size[" + adapters.size() + "] is less than " + CORES); + } + MethodHandle prev = adapters.poll(); + for (MethodHandle current : adapters) { + checkLFCaching(prev, current); + prev = current; + } + } + + /** + * Main routine for multiple threaded lambda forms caching test. + * + * @param args Accepts no arguments. + */ + public static void main(String[] args) { + LambdaFormTestCase.runTests(LFMultiThreadCachingTest::new, EnumSet.allOf(TestMethods.class)); + } +} diff --git a/jdk/test/java/lang/invoke/LFCaching/LFSingleThreadCachingTest.java b/jdk/test/java/lang/invoke/LFCaching/LFSingleThreadCachingTest.java new file mode 100644 index 00000000000..21221aa7caf --- /dev/null +++ b/jdk/test/java/lang/invoke/LFCaching/LFSingleThreadCachingTest.java @@ -0,0 +1,78 @@ +/* + * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test LFSingleThreadCachingTest + * @bug 8046703 + * @summary Test verifies that lambda forms are cached when run with single thread + * @author kshefov + * @library /lib/testlibrary/jsr292 /lib/testlibrary + * @build TestMethods + * @build LambdaFormTestCase + * @build LFCachingTestCase + * @build LFSingleThreadCachingTest + * @run main/othervm/timeout=300 -Djava.lang.invoke.MethodHandle.USE_LF_EDITOR=true LFSingleThreadCachingTest + */ + +import java.lang.invoke.MethodHandle; +import java.util.EnumSet; +import java.util.Map; + +/** + * Single threaded lambda forms caching test class. + */ +public final class LFSingleThreadCachingTest extends LFCachingTestCase { + + /** + * Constructor for a single threaded lambda forms caching test case. + * + * @param testMethod A method from {@code j.l.i.MethodHandles} class that + * returns a {@code j.l.i.MethodHandle} instance. + */ + public LFSingleThreadCachingTest(TestMethods testMethod) { + super(testMethod); + } + + @Override + public void doTest() { + MethodHandle adapter1; + MethodHandle adapter2; + Map data = getTestMethod().getTestCaseData(); + try { + adapter1 = getTestMethod().getTestCaseMH(data, TestMethods.Kind.ONE); + adapter2 = getTestMethod().getTestCaseMH(data, TestMethods.Kind.TWO); + } catch (NoSuchMethodException | IllegalAccessException ex) { + throw new Error("Unexpected exception: ", ex); + } + checkLFCaching(adapter1, adapter2); + } + + /** + * Main routine for single threaded lambda forms caching test. + * + * @param args Accepts no arguments. + */ + public static void main(String[] args) { + LambdaFormTestCase.runTests(LFSingleThreadCachingTest::new, EnumSet.allOf(TestMethods.class)); + } +} diff --git a/jdk/test/java/lang/invoke/LFCaching/LambdaFormTestCase.java b/jdk/test/java/lang/invoke/LFCaching/LambdaFormTestCase.java new file mode 100644 index 00000000000..45585b2c4bc --- /dev/null +++ b/jdk/test/java/lang/invoke/LFCaching/LambdaFormTestCase.java @@ -0,0 +1,117 @@ +/* + * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import com.oracle.testlibrary.jsr292.Helper; +import java.lang.reflect.Method; +import java.util.Collection; +import java.util.function.Function; + +/** + * Lambda forms caching test case class. Contains all necessary test routines to + * test lambda forms caching in method handles returned by methods of + * MethodHandles class. + * + * @author kshefov + */ +public abstract class LambdaFormTestCase { + + private final static String METHOD_HANDLE_CLASS_NAME = "java.lang.invoke.MethodHandle"; + private final static String INTERNAL_FORM_METHOD_NAME = "internalForm"; + + /** + * Reflection link to {@code j.l.i.MethodHandle.internalForm} method. It is + * used to get a lambda form from a method handle. + */ + protected final static Method INTERNAL_FORM; + + static { + try { + Class mhClass = Class.forName(METHOD_HANDLE_CLASS_NAME); + INTERNAL_FORM = mhClass.getDeclaredMethod(INTERNAL_FORM_METHOD_NAME); + INTERNAL_FORM.setAccessible(true); + } catch (Exception ex) { + throw new Error("Unexpected exception: ", ex); + } + } + + private final TestMethods testMethod; + + /** + * Test case constructor. Generates test cases with random method types for + * given methods form {@code j.l.i.MethodHandles} class. + * + * @param testMethod A method from {@code j.l.i.MethodHandles} class which + * returns a {@code j.l.i.MethodHandle}. + */ + protected LambdaFormTestCase(TestMethods testMethod) { + this.testMethod = testMethod; + } + + public TestMethods getTestMethod() { + return testMethod; + } + + /** + * Routine that executes a test case. + */ + public abstract void doTest(); + + /** + * Runs a number of test cases defined by the size of testCases list. + * + * @param ctor constructor of LambdaFormCachingTest or its child classes + * object. + * @param testMethods list of test methods + */ + public static void runTests(Function ctor, Collection testMethods) { + boolean passed = true; + int testCounter = 0; + int failCounter = 0; + long iterations = Math.max(1, Helper.TEST_LIMIT / testMethods.size()); + for (long i = 0; i < iterations; i++) { + System.err.println(String.format("Iteration %d:", i)); + for (TestMethods testMethod : testMethods) { + LambdaFormTestCase testCase = ctor.apply(testMethod); + try { + System.err.printf("Tested LF caching feature with MethodHandles.%s method.%n", + testCase.getTestMethod().name); + testCase.doTest(); + System.err.println("PASSED"); + } catch (Throwable t) { + t.printStackTrace(); + System.err.println("FAILED"); + passed = false; + failCounter++; + } + testCounter++; + } + } + if (!passed) { + throw new Error(String.format("%d of %d test cases FAILED! %n" + + "Rerun the test with the same \"-Dseed=\" option as in the log file!", + failCounter, testCounter)); + } else { + System.err.println(String.format("All %d test cases PASSED!", testCounter)); + } + } +} diff --git a/jdk/test/java/lang/invoke/LFCaching/TestMethods.java b/jdk/test/java/lang/invoke/LFCaching/TestMethods.java new file mode 100644 index 00000000000..794709a7919 --- /dev/null +++ b/jdk/test/java/lang/invoke/LFCaching/TestMethods.java @@ -0,0 +1,698 @@ +/* + * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import com.oracle.testlibrary.jsr292.Helper; +import java.lang.invoke.MethodHandle; +import java.lang.invoke.MethodHandles; +import java.lang.invoke.MethodType; +import java.lang.reflect.Array; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * Enumeration containing information about methods from + * {@code j.l.i.MethodHandles} class that are used for testing lambda forms + * caching. + * + * @author kshefov + */ +public enum TestMethods { + + FOLD_ARGUMENTS("foldArguments") { + @Override + public Map getTestCaseData() { + Map data = new HashMap<>(); + int desiredArity = Helper.RNG.nextInt(Helper.MAX_ARITY); + MethodType mtTarget = TestMethods.randomMethodTypeGenerator(desiredArity); + data.put("mtTarget", mtTarget); + // Arity after reducing because of long and double take 2 slots. + int realArity = mtTarget.parameterCount(); + int modifierMHArgNum = Helper.RNG.nextInt(realArity + 1); + data.put("modifierMHArgNum", modifierMHArgNum); + Class combinerReturnType; + if (realArity == 0) { + combinerReturnType = void.class; + } else { + combinerReturnType = Helper.RNG.nextBoolean() ? void.class : mtTarget.parameterType(0); + } + data.put("combinerReturnType", combinerReturnType); + return data; + } + + @Override + protected MethodHandle getMH(Map data, TestMethods.Kind kind) throws NoSuchMethodException, IllegalAccessException { + MethodType mtTarget = (MethodType) data.get("mtTarget"); + Class combinerReturnType = (Class) data.get("combinerReturnType"); + int modifierMHArgNum = (int) data.get("modifierMHArgNum"); + MethodHandle target = TestMethods.methodHandleGenerator(mtTarget.returnType(), + mtTarget.parameterList(), kind); + Class rType = mtTarget.returnType(); + int combListStart = (combinerReturnType == void.class) ? 0 : 1; + if (modifierMHArgNum < combListStart) { + modifierMHArgNum = combListStart; + } + MethodHandle combiner = TestMethods.methodHandleGenerator(combinerReturnType, + mtTarget.parameterList().subList(combListStart, + modifierMHArgNum), kind); + return MethodHandles.foldArguments(target, combiner); + } + }, + DROP_ARGUMENTS("dropArguments") { + @Override + public Map getTestCaseData() { + Map data = new HashMap<>(); + int desiredArity = Helper.RNG.nextInt(Helper.MAX_ARITY); + MethodType mtTarget = TestMethods.randomMethodTypeGenerator(desiredArity); + data.put("mtTarget", mtTarget); + // Arity after reducing because of long and double take 2 slots. + int realArity = mtTarget.parameterCount(); + int dropArgsPos = Helper.RNG.nextInt(realArity + 1); + data.put("dropArgsPos", dropArgsPos); + MethodType mtDropArgs = TestMethods.randomMethodTypeGenerator( + Helper.RNG.nextInt(Helper.MAX_ARITY - realArity)); + data.put("mtDropArgs", mtDropArgs); + return data; + } + + @Override + protected MethodHandle getMH(Map data, TestMethods.Kind kind) throws NoSuchMethodException, IllegalAccessException { + MethodType mtTarget = (MethodType) data.get("mtTarget"); + MethodType mtDropArgs = (MethodType) data.get("mtDropArgs"); + int dropArgsPos = (int) data.get("dropArgsPos"); + MethodHandle target = TestMethods.methodHandleGenerator(mtTarget.returnType(), + mtTarget.parameterList(), kind); + int mtTgtSlotsCount = TestMethods.argSlotsCount(mtTarget); + int mtDASlotsCount = TestMethods.argSlotsCount(mtDropArgs); + List> fakeParList; + if (mtTgtSlotsCount + mtDASlotsCount > Helper.MAX_ARITY - 1) { + fakeParList = TestMethods.reduceArgListToSlotsCount(mtDropArgs.parameterList(), + Helper.MAX_ARITY - mtTgtSlotsCount - 1); + } else { + fakeParList = mtDropArgs.parameterList(); + } + return MethodHandles.dropArguments(target, dropArgsPos, fakeParList); + } + }, + EXPLICIT_CAST_ARGUMENTS("explicitCastArguments") { + @Override + public Map getTestCaseData() { + Map data = new HashMap<>(); + int desiredArity = Helper.RNG.nextInt(Helper.MAX_ARITY / 2); + MethodType mtTarget = TestMethods.randomMethodTypeGenerator(desiredArity); + data.put("mtTarget", mtTarget); + // Arity after reducing because of long and double take 2 slots. + int realArity = mtTarget.parameterCount(); + MethodType mtExcplCastArgs = TestMethods.randomMethodTypeGenerator(realArity); + if (mtTarget.returnType() == void.class) { + mtExcplCastArgs = MethodType.methodType(void.class, + mtExcplCastArgs.parameterArray()); + } + if (mtExcplCastArgs.returnType() == void.class) { + mtExcplCastArgs = MethodType.methodType(mtTarget.returnType(), + mtExcplCastArgs.parameterArray()); + } + data.put("mtExcplCastArgs", mtExcplCastArgs); + return data; + } + + @Override + protected MethodHandle getMH(Map data, TestMethods.Kind kind) throws NoSuchMethodException, IllegalAccessException { + MethodType mtTarget = (MethodType) data.get("mtTarget"); + MethodType mtExcplCastArgs = (MethodType) data.get("mtExcplCastArgs"); + MethodHandle target = TestMethods.methodHandleGenerator(mtTarget.returnType(), + mtTarget.parameterList(), kind); + return MethodHandles.explicitCastArguments(target, mtExcplCastArgs); + } + }, + FILTER_ARGUMENTS("filterArguments") { + @Override + public Map getTestCaseData() { + Map data = new HashMap<>(); + int desiredArity = Helper.RNG.nextInt(Helper.MAX_ARITY / 2); + MethodType mtTarget = TestMethods.randomMethodTypeGenerator(desiredArity); + data.put("mtTarget", mtTarget); + // Arity after reducing because of long and double take 2 slots. + int realArity = mtTarget.parameterCount(); + int filterArgsPos = Helper.RNG.nextInt(realArity + 1); + data.put("filterArgsPos", filterArgsPos); + int filtersArgsArrayLength = Helper.RNG.nextInt(realArity + 1 - filterArgsPos); + data.put("filtersArgsArrayLength", filtersArgsArrayLength); + MethodType mtFilter = TestMethods.randomMethodTypeGenerator(filtersArgsArrayLength); + data.put("mtFilter", mtFilter); + return data; + } + + @Override + protected MethodHandle getMH(Map data, TestMethods.Kind kind) throws NoSuchMethodException, IllegalAccessException { + MethodType mtTarget = (MethodType) data.get("mtTarget"); + MethodType mtFilter = (MethodType) data.get("mtFilter"); + int filterArgsPos = (int) data.get("filterArgsPos"); + int filtersArgsArrayLength = (int) data.get("filtersArgsArrayLength"); + MethodHandle target = TestMethods.methodHandleGenerator(mtTarget.returnType(), + mtTarget.parameterList(), kind); + MethodHandle[] filters = new MethodHandle[filtersArgsArrayLength]; + for (int i = 0; i < filtersArgsArrayLength; i++) { + filters[i] = TestMethods.filterGenerator(mtFilter.parameterType(i), + mtTarget.parameterType(filterArgsPos + i), kind); + } + return MethodHandles.filterArguments(target, filterArgsPos, filters); + } + }, + FILTER_RETURN_VALUE("filterReturnValue") { + @Override + public Map getTestCaseData() { + Map data = new HashMap<>(); + int desiredArity = Helper.RNG.nextInt(Helper.MAX_ARITY); + MethodType mtTarget = TestMethods.randomMethodTypeGenerator(desiredArity); + data.put("mtTarget", mtTarget); + // Arity after reducing because of long and double take 2 slots. + int realArity = mtTarget.parameterCount(); + int filterArgsPos = Helper.RNG.nextInt(realArity + 1); + int filtersArgsArrayLength = Helper.RNG.nextInt(realArity + 1 - filterArgsPos); + MethodType mtFilter = TestMethods.randomMethodTypeGenerator(filtersArgsArrayLength); + data.put("mtFilter", mtFilter); + return data; + } + + @Override + protected MethodHandle getMH(Map data, TestMethods.Kind kind) throws NoSuchMethodException, IllegalAccessException { + MethodType mtTarget = (MethodType) data.get("mtTarget"); + MethodType mtFilter = (MethodType) data.get("mtFilter"); + MethodHandle target = TestMethods.methodHandleGenerator(mtTarget.returnType(), + mtTarget.parameterList(), kind); + MethodHandle filter = TestMethods.filterGenerator(mtTarget.returnType(), + mtFilter.returnType(), kind); + return MethodHandles.filterReturnValue(target, filter); + } + }, + INSERT_ARGUMENTS("insertArguments") { + @Override + public Map getTestCaseData() { + Map data = new HashMap<>(); + int desiredArity = Helper.RNG.nextInt(Helper.MAX_ARITY); + MethodType mtTarget = TestMethods.randomMethodTypeGenerator(desiredArity); + data.put("mtTarget", mtTarget); + // Arity after reducing because of long and double take 2 slots. + int realArity = mtTarget.parameterCount(); + int insertArgsPos = Helper.RNG.nextInt(realArity + 1); + data.put("insertArgsPos", insertArgsPos); + int insertArgsArrayLength = Helper.RNG.nextInt(realArity + 1 - insertArgsPos); + MethodType mtInsertArgs = MethodType.methodType(void.class, mtTarget.parameterList() + .subList(insertArgsPos, insertArgsPos + insertArgsArrayLength)); + data.put("mtInsertArgs", mtInsertArgs); + return data; + } + + @Override + protected MethodHandle getMH(Map data, TestMethods.Kind kind) throws NoSuchMethodException, IllegalAccessException { + MethodType mtTarget = (MethodType) data.get("mtTarget"); + MethodType mtInsertArgs = (MethodType) data.get("mtInsertArgs"); + int insertArgsPos = (int) data.get("insertArgsPos"); + MethodHandle target = TestMethods.methodHandleGenerator(mtTarget.returnType(), + mtTarget.parameterList(), kind); + Object[] insertList = Helper.randomArgs(mtInsertArgs.parameterList()); + return MethodHandles.insertArguments(target, insertArgsPos, insertList); + } + }, + PERMUTE_ARGUMENTS("permuteArguments") { + @Override + public Map getTestCaseData() { + Map data = new HashMap<>(); + int desiredArity = Helper.RNG.nextInt(Helper.MAX_ARITY / 2); + MethodType mtTarget = TestMethods.randomMethodTypeGenerator(desiredArity); + // Arity after reducing because of long and double take 2 slots. + int realArity = mtTarget.parameterCount(); + int[] permuteArgsReorderArray = new int[realArity]; + int mtParmuteArgsNum = Helper.RNG.nextInt(Helper.MAX_ARITY); + mtParmuteArgsNum = mtParmuteArgsNum == 0 ? 1 : mtParmuteArgsNum; + MethodType mtPermuteArgs = TestMethods.randomMethodTypeGenerator(mtParmuteArgsNum); + mtTarget = mtTarget.changeReturnType(mtPermuteArgs.returnType()); + for (int i = 0; i < realArity; i++) { + int mtPermuteArgsParNum = Helper.RNG.nextInt(mtPermuteArgs.parameterCount()); + permuteArgsReorderArray[i] = mtPermuteArgsParNum; + mtTarget = mtTarget.changeParameterType( + i, mtPermuteArgs.parameterType(mtPermuteArgsParNum)); + } + data.put("mtTarget", mtTarget); + data.put("permuteArgsReorderArray", permuteArgsReorderArray); + data.put("mtPermuteArgs", mtPermuteArgs); + return data; + } + + @Override + protected MethodHandle getMH(Map data, TestMethods.Kind kind) throws NoSuchMethodException, IllegalAccessException { + MethodType mtTarget = (MethodType) data.get("mtTarget"); + MethodType mtPermuteArgs = (MethodType) data.get("mtPermuteArgs"); + int[] permuteArgsReorderArray = (int[]) data.get("permuteArgsReorderArray"); + MethodHandle target = TestMethods.methodHandleGenerator(mtTarget.returnType(), + mtTarget.parameterList(), kind); + return MethodHandles.permuteArguments(target, mtPermuteArgs, permuteArgsReorderArray); + } + }, + THROW_EXCEPTION("throwException") { + @Override + public Map getTestCaseData() { + Map data = new HashMap<>(); + int desiredArity = Helper.RNG.nextInt(Helper.MAX_ARITY); + MethodType mtTarget = TestMethods.randomMethodTypeGenerator(desiredArity); + data.put("mtTarget", mtTarget); + return data; + } + + @Override + protected MethodHandle getMH(Map data, TestMethods.Kind kind) { + MethodType mtTarget = (MethodType) data.get("mtTarget"); + Class rType = mtTarget.returnType(); + return MethodHandles.throwException(rType, Exception.class + ); + } + }, + GUARD_WITH_TEST("guardWithTest") { + @Override + public Map getTestCaseData() { + Map data = new HashMap<>(); + int desiredArity = Helper.RNG.nextInt(Helper.MAX_ARITY); + MethodType mtTarget = TestMethods.randomMethodTypeGenerator(desiredArity); + data.put("mtTarget", mtTarget); + // Arity after reducing because of long and double take 2 slots. + int realArity = mtTarget.parameterCount(); + int modifierMHArgNum = Helper.RNG.nextInt(realArity + 1); + data.put("modifierMHArgNum", modifierMHArgNum); + return data; + } + + @Override + protected MethodHandle getMH(Map data, TestMethods.Kind kind) throws NoSuchMethodException, IllegalAccessException { + MethodType mtTarget = (MethodType) data.get("mtTarget"); + int modifierMHArgNum = (int) data.get("modifierMHArgNum"); + TestMethods.Kind targetKind; + TestMethods.Kind fallbackKind; + if (kind.equals(TestMethods.Kind.ONE)) { + targetKind = TestMethods.Kind.ONE; + fallbackKind = TestMethods.Kind.TWO; + } else { + targetKind = TestMethods.Kind.TWO; + fallbackKind = TestMethods.Kind.ONE; + } + MethodHandle target = TestMethods.methodHandleGenerator(mtTarget.returnType(), + mtTarget.parameterList(), targetKind); + MethodHandle fallback = TestMethods.methodHandleGenerator(mtTarget.returnType(), + mtTarget.parameterList(), fallbackKind); + MethodHandle test = TestMethods.methodHandleGenerator(boolean.class, + mtTarget.parameterList().subList(0, modifierMHArgNum), kind); + return MethodHandles.guardWithTest(test, target, fallback); + } + }, + CATCH_EXCEPTION("catchException") { + @Override + public Map getTestCaseData() { + Map data = new HashMap<>(); + int desiredArity = Helper.RNG.nextInt(Helper.MAX_ARITY); + MethodType mtTarget = TestMethods.randomMethodTypeGenerator(desiredArity); + data.put("mtTarget", mtTarget); + // Arity after reducing because of long and double take 2 slots. + int realArity = mtTarget.parameterCount(); + int modifierMHArgNum = Helper.RNG.nextInt(realArity + 1); + data.put("modifierMHArgNum", modifierMHArgNum); + return data; + } + + @Override + protected MethodHandle getMH(Map data, TestMethods.Kind kind) throws NoSuchMethodException, IllegalAccessException { + MethodType mtTarget = (MethodType) data.get("mtTarget"); + int modifierMHArgNum = (int) data.get("modifierMHArgNum"); + MethodHandle target; + if (kind.equals(TestMethods.Kind.ONE)) { + target = TestMethods.methodHandleGenerator(mtTarget.returnType(), + mtTarget.parameterList(), TestMethods.Kind.ONE); + } else { + target = TestMethods.methodHandleGenerator(mtTarget.returnType(), + mtTarget.parameterList(), TestMethods.Kind.EXCEPT); + } + List> handlerParamList = new ArrayList<>(mtTarget.parameterCount() + 1); + handlerParamList.add(Exception.class); + handlerParamList.addAll(mtTarget.parameterList().subList(0, modifierMHArgNum)); + MethodHandle handler = TestMethods.methodHandleGenerator( + mtTarget.returnType(), handlerParamList, TestMethods.Kind.TWO); + return MethodHandles.catchException(target, Exception.class, handler); + } + }, + INVOKER("invoker") { + @Override + public Map getTestCaseData() { + Map data = new HashMap<>(); + int desiredArity = Helper.RNG.nextInt(Helper.MAX_ARITY); + MethodType mtTarget = TestMethods.randomMethodTypeGenerator(desiredArity); + data.put("mtTarget", mtTarget); + return data; + } + + @Override + protected MethodHandle getMH(Map data, TestMethods.Kind kind) { + MethodType mtTarget = (MethodType) data.get("mtTarget"); + return MethodHandles.invoker(mtTarget); + } + }, + EXACT_INVOKER("exactInvoker") { + @Override + public Map getTestCaseData() { + Map data = new HashMap<>(); + int desiredArity = Helper.RNG.nextInt(Helper.MAX_ARITY); + MethodType mtTarget = TestMethods.randomMethodTypeGenerator(desiredArity); + data.put("mtTarget", mtTarget); + return data; + } + + @Override + protected MethodHandle getMH(Map data, TestMethods.Kind kind) { + MethodType mtTarget = (MethodType) data.get("mtTarget"); + return MethodHandles.exactInvoker(mtTarget); + } + }, + SPREAD_INVOKER("spreadInvoker") { + @Override + public Map getTestCaseData() { + Map data = new HashMap<>(); + int desiredArity = Helper.RNG.nextInt(Helper.MAX_ARITY); + MethodType mtTarget = TestMethods.randomMethodTypeGenerator(desiredArity); + data.put("mtTarget", mtTarget); + // Arity after reducing because of long and double take 2 slots. + int realArity = mtTarget.parameterCount(); + int modifierMHArgNum = Helper.RNG.nextInt(realArity + 1); + data.put("modifierMHArgNum", modifierMHArgNum); + return data; + } + + @Override + protected MethodHandle getMH(Map data, TestMethods.Kind kind) { + MethodType mtTarget = (MethodType) data.get("mtTarget"); + int modifierMHArgNum = (int) data.get("modifierMHArgNum"); + return MethodHandles.spreadInvoker(mtTarget, modifierMHArgNum); + } + }, + ARRAY_ELEMENT_GETTER("arrayElementGetter") { + @Override + public Map getTestCaseData() { + Map data = new HashMap<>(); + int desiredArity = Helper.RNG.nextInt(Helper.MAX_ARITY); + MethodType mtTarget = TestMethods.randomMethodTypeGenerator(desiredArity); + data.put("mtTarget", mtTarget); + return data; + } + + @Override + protected MethodHandle getMH(Map data, TestMethods.Kind kind) { + MethodType mtTarget = (MethodType) data.get("mtTarget"); + Class rType = mtTarget.returnType(); + if (rType == void.class) { + rType = Object.class; + } + return MethodHandles.arrayElementGetter(Array.newInstance(rType, 2).getClass()); + } + }, + ARRAY_ELEMENT_SETTER("arrayElementSetter") { + @Override + public Map getTestCaseData() { + Map data = new HashMap<>(); + int desiredArity = Helper.RNG.nextInt(Helper.MAX_ARITY); + MethodType mtTarget = TestMethods.randomMethodTypeGenerator(desiredArity); + data.put("mtTarget", mtTarget); + return data; + } + + @Override + protected MethodHandle getMH(Map data, TestMethods.Kind kind) { + MethodType mtTarget = (MethodType) data.get("mtTarget"); + Class rType = mtTarget.returnType(); + if (rType == void.class) { + rType = Object.class; + } + return MethodHandles.arrayElementSetter(Array.newInstance(rType, 2).getClass()); + } + }, + CONSTANT("constant") { + @Override + public Map getTestCaseData() { + Map data = new HashMap<>(); + int desiredArity = Helper.RNG.nextInt(Helper.MAX_ARITY); + MethodType mtTarget = TestMethods.randomMethodTypeGenerator(desiredArity); + data.put("mtTarget", mtTarget); + return data; + } + + @Override + protected MethodHandle getMH(Map data, TestMethods.Kind kind) { + MethodType mtTarget = (MethodType) data.get("mtTarget"); + Class rType = mtTarget.returnType(); + if (rType == void.class) { + rType = Object.class; + } + if (rType.equals(boolean.class)) { + // There should be the same return values because for default values there are special "zero" forms + return MethodHandles.constant(rType, true); + } else { + return MethodHandles.constant(rType, kind.getValue(rType)); + } + } + }, + IDENTITY("identity") { + @Override + public Map getTestCaseData() { + Map data = new HashMap<>(); + int desiredArity = Helper.RNG.nextInt(Helper.MAX_ARITY); + MethodType mtTarget = TestMethods.randomMethodTypeGenerator(desiredArity); + data.put("mtTarget", mtTarget); + return data; + } + + @Override + protected MethodHandle getMH(Map data, TestMethods.Kind kind) { + MethodType mtTarget = (MethodType) data.get("mtTarget"); + Class rType = mtTarget.returnType(); + if (rType == void.class) { + rType = Object.class; + } + return MethodHandles.identity(rType); + } + }; + + /** + * Test method's name. + */ + public final String name; + + private TestMethods(String name) { + this.name = name; + } + + protected MethodHandle getMH(Map data, TestMethods.Kind kind) throws NoSuchMethodException, IllegalAccessException { + throw new UnsupportedOperationException("TESTBUG: getMH method is not implemented for test method " + this); + } + + /** + * Creates an adapter method handle depending on a test method from + * MethodHandles class. Adapter is what is returned by the test method. This + * method is able to create two kinds of adapters, their type will be the + * same, but return values are different. + * + * @param data a Map containing data to create a method handle, can be + * obtained by {@link #getTestCaseData} method + * @param kind defines whether adapter ONE or adapter TWO will be + * initialized. Should be equal to TestMethods.Kind.ONE or + * TestMethods.Kind.TWO + * @return Method handle adapter that behaves according to + * TestMethods.Kind.ONE or TestMethods.Kind.TWO + * @throws java.lang.NoSuchMethodException + * @throws java.lang.IllegalAccessException + */ + public MethodHandle getTestCaseMH(Map data, TestMethods.Kind kind) + throws NoSuchMethodException, IllegalAccessException { + if (data == null) { + throw new Error(String.format("TESTBUG: Data for test method %s is not prepared", + this.name)); + } + if (!kind.equals(TestMethods.Kind.ONE) && !kind.equals(TestMethods.Kind.TWO)) { + throw new IllegalArgumentException("TESTBUG: Wrong \"kind\" (" + kind + + ") arg to getTestCaseMH function." + + " Should be Kind.ONE or Kind.TWO"); + } + return getMH(data, kind); + } + + /** + * Returns a data Map needed for {@link #getTestCaseMH} method. + * + * @return data Map needed for {@link #getTestCaseMH} method + */ + public Map getTestCaseData() { + throw new UnsupportedOperationException( + "TESTBUG: getTestCaseData method is not implemented for test method " + this); + } + + /** + * Enumeration used in methodHandleGenerator to define whether a MH returned + * by this method returns "2" in different type representations, "4", or + * throw an Exception. + */ + public static enum Kind { + + ONE(2), + TWO(4), + EXCEPT(0); + + private final int value; + + private Object getValue(Class cl) { + return Helper.castToWrapper(value, cl); + } + + private MethodHandle getBasicMH(Class rType) throws NoSuchMethodException, IllegalAccessException { + MethodHandle result = null; + switch (this) { + case ONE: + case TWO: + if (rType.equals(void.class)) { + result = MethodHandles.lookup().findVirtual(Kind.class, "returnVoid", MethodType.methodType(void.class)); + result = MethodHandles.insertArguments(result, 0, this); + } else { + result = MethodHandles.constant(rType, getValue(rType)); + } + break; + case EXCEPT: + result = MethodHandles.throwException(rType, Exception.class); + result = MethodHandles.insertArguments(result, 0, new Exception()); + break; + } + return result; + } + + private void returnVoid() { + } + + private Kind(int value) { + this.value = value; + } + } + + /** + * Routine used to obtain a randomly generated method type. + * + * @param arity Arity of returned method type. + * @return MethodType generated randomly. + */ + private static MethodType randomMethodTypeGenerator(int arity) { + final Class[] CLASSES = { + Object.class, + int.class, + boolean.class, + byte.class, + short.class, + char.class, + long.class, + float.class, + double.class + }; + if (arity > Helper.MAX_ARITY) { + throw new IllegalArgumentException( + String.format("Arity should not exceed %d!", Helper.MAX_ARITY)); + } + List> list = Helper.randomClasses(CLASSES, arity); + list = Helper.getParams(list, false, arity); + int i = Helper.RNG.nextInt(CLASSES.length + 1); + Class rtype = i == CLASSES.length ? void.class : CLASSES[i]; + return MethodType.methodType(rtype, list); + } + + /** + * Routine used to obtain a method handles of a given type an kind (return + * value). + * + * @param returnType Type of MH return value. + * @param argTypes Types of MH args. + * @param kind Defines whether the obtained MH returns "1" or "2". + * @return Method handle of the given type. + * @throws NoSuchMethodException + * @throws IllegalAccessException + */ + private static MethodHandle methodHandleGenerator(Class returnType, + List> argTypes, TestMethods.Kind kind) + throws NoSuchMethodException, IllegalAccessException { + MethodHandle result; + result = kind.getBasicMH(returnType); + return Helper.addTrailingArgs(result, argTypes.size(), argTypes); + } + + /** + * Routine that generates filter method handles to test + * MethodHandles.filterArguments method. + * + * @param inputType Filter's argument type. + * @param returnType Filter's return type. + * @param kind Filter's return value definer. + * @return A filter method handle, that takes one argument. + * @throws NoSuchMethodException + * @throws IllegalAccessException + */ + private static MethodHandle filterGenerator(Class inputType, Class returnType, + TestMethods.Kind kind) throws NoSuchMethodException, IllegalAccessException { + MethodHandle tmpMH = kind.getBasicMH(returnType); + if (inputType.equals(void.class)) { + return tmpMH; + } + ArrayList> inputTypeList = new ArrayList<>(1); + inputTypeList.add(inputType); + return Helper.addTrailingArgs(tmpMH, 1, inputTypeList); + } + + private static int argSlotsCount(MethodType mt) { + int result = 0; + for (Class cl : mt.parameterArray()) { + if (cl.equals(long.class) || cl.equals(double.class)) { + result += 2; + } else { + result++; + } + } + return result; + } + + private static List> reduceArgListToSlotsCount(List> list, + int desiredSlotCount) { + List> result = new ArrayList<>(desiredSlotCount); + int count = 0; + for (Class cl : list) { + if (count >= desiredSlotCount) { + break; + } + if (cl.equals(long.class) || cl.equals(double.class)) { + count += 2; + } else { + count++; + } + result.add(cl); + } + return result; + } +} From 3951dda4cf06c6e61e19d3df26a792022c1701b9 Mon Sep 17 00:00:00 2001 From: Martin Buchholz Date: Fri, 29 Aug 2014 12:07:11 -0700 Subject: [PATCH 26/81] 8056934: ZipInputStream does not correctly handle local header data descriptors with the optional signature missing Fix off-by-one bug in EXTSIG handling; add docs. Reviewed-by: sherman, alanb --- .../classes/java/util/zip/ZipInputStream.java | 19 ++- .../zip/DataDescriptorSignatureMissing.java | 147 ++++++++++++++++++ 2 files changed, 163 insertions(+), 3 deletions(-) create mode 100644 jdk/test/java/util/zip/DataDescriptorSignatureMissing.java diff --git a/jdk/src/java.base/share/classes/java/util/zip/ZipInputStream.java b/jdk/src/java.base/share/classes/java/util/zip/ZipInputStream.java index 7b4ccc86c76..c9e8077c342 100644 --- a/jdk/src/java.base/share/classes/java/util/zip/ZipInputStream.java +++ b/jdk/src/java.base/share/classes/java/util/zip/ZipInputStream.java @@ -336,8 +336,21 @@ class ZipInputStream extends InflaterInputStream implements ZipConstants { return new ZipEntry(name); } - /* + /** * Reads end of deflated entry as well as EXT descriptor if present. + * + * Local headers for DEFLATED entries may optionally be followed by a + * data descriptor, and that data descriptor may optionally contain a + * leading signature (EXTSIG). + * + * From the zip spec http://www.pkware.com/documents/casestudies/APPNOTE.TXT + * + * """Although not originally assigned a signature, the value 0x08074b50 + * has commonly been adopted as a signature value for the data descriptor + * record. Implementers should be aware that ZIP files may be + * encountered with or without this signature marking data descriptors + * and should account for either case when reading ZIP files to ensure + * compatibility.""" */ private void readEnd(ZipEntry e) throws IOException { int n = inf.getRemaining(); @@ -356,7 +369,7 @@ class ZipInputStream extends InflaterInputStream implements ZipConstants { e.csize = get64(tmpbuf, ZIP64_EXTSIZ - ZIP64_EXTCRC); e.size = get64(tmpbuf, ZIP64_EXTLEN - ZIP64_EXTCRC); ((PushbackInputStream)in).unread( - tmpbuf, ZIP64_EXTHDR - ZIP64_EXTCRC - 1, ZIP64_EXTCRC); + tmpbuf, ZIP64_EXTHDR - ZIP64_EXTCRC, ZIP64_EXTCRC); } else { e.crc = get32(tmpbuf, ZIP64_EXTCRC); e.csize = get64(tmpbuf, ZIP64_EXTSIZ); @@ -370,7 +383,7 @@ class ZipInputStream extends InflaterInputStream implements ZipConstants { e.csize = get32(tmpbuf, EXTSIZ - EXTCRC); e.size = get32(tmpbuf, EXTLEN - EXTCRC); ((PushbackInputStream)in).unread( - tmpbuf, EXTHDR - EXTCRC - 1, EXTCRC); + tmpbuf, EXTHDR - EXTCRC, EXTCRC); } else { e.crc = get32(tmpbuf, EXTCRC); e.csize = get32(tmpbuf, EXTSIZ); diff --git a/jdk/test/java/util/zip/DataDescriptorSignatureMissing.java b/jdk/test/java/util/zip/DataDescriptorSignatureMissing.java new file mode 100644 index 00000000000..f7a2ae2f8eb --- /dev/null +++ b/jdk/test/java/util/zip/DataDescriptorSignatureMissing.java @@ -0,0 +1,147 @@ +/* + * Copyright 2012 Google, Inc. 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 8056934 + * @summary Check ability to read zip files created by python zipfile + * implementation, which fails to write optional (but recommended) data + * descriptor signatures. Repro scenario is a Java -> Python -> Java round trip: + * - ZipOutputStream creates zip file with DEFLATED entries and data + * descriptors with optional signature "PK0x0708". + * - Python reads those entries, preserving the 0x08 flag byte + * - Python outputs those entries with data descriptors lacking the + * optional signature. + * - ZipInputStream cannot handle the missing signature + * + * No way to adapt the technique in this test to get a ZIP64 zip file + * without data descriptors was found. + * + * @ignore This test has brittle dependencies on an external working python. + */ + +import java.io.*; +import java.util.zip.*; + +public class DataDescriptorSignatureMissing { + void printStream(InputStream is) throws IOException { + Reader r = new InputStreamReader(is); + StringBuilder sb = new StringBuilder(); + char[] buf = new char[1024]; + int n; + while ((n = r.read(buf)) > 0) { + sb.append(buf, 0, n); + } + System.out.print(sb); + } + + int entryCount(File zipFile) throws IOException { + try (FileInputStream fis = new FileInputStream(zipFile); + ZipInputStream zis = new ZipInputStream(fis)) { + for (int count = 0;; count++) + if (zis.getNextEntry() == null) + return count; + } + } + + void test(String[] args) throws Throwable { + if (! new File("/usr/bin/python").canExecute()) + return; + + // Create a java zip file with DEFLATED entries and data + // descriptors with signatures. + final File in = new File("in.zip"); + final File out = new File("out.zip"); + final int count = 3; + try (FileOutputStream fos = new FileOutputStream(in); + ZipOutputStream zos = new ZipOutputStream(fos)) { + for (int i = 0; i < count; i++) { + ZipEntry ze = new ZipEntry("hello.python" + i); + ze.setMethod(ZipEntry.DEFLATED); + zos.putNextEntry(ze); + zos.write(new byte[10]); + zos.closeEntry(); + } + } + + // Copy the zip file using python's zipfile module + String[] python_program_lines = { + "import os", + "import zipfile", + "input_zip = zipfile.ZipFile('in.zip', mode='r')", + "output_zip = zipfile.ZipFile('out.zip', mode='w')", + "count08 = 0", + "for input_info in input_zip.infolist():", + " output_info = input_info", + " if output_info.flag_bits & 0x08 == 0x08:", + " count08 += 1", + " output_zip.writestr(output_info, input_zip.read(input_info))", + "output_zip.close()", + "if count08 == 0:", + " raise ValueError('Expected to see entries with 0x08 flag_bits set')", + }; + StringBuilder python_program_builder = new StringBuilder(); + for (String line : python_program_lines) + python_program_builder.append(line).append('\n'); + String python_program = python_program_builder.toString(); + String[] cmdline = { "/usr/bin/python", "-c", python_program }; + ProcessBuilder pb = new ProcessBuilder(cmdline); + pb.redirectErrorStream(true); + Process p = pb.start(); + printStream(p.getInputStream()); + p.waitFor(); + equal(p.exitValue(), 0); + + File pythonZipFile = new File("out.zip"); + check(pythonZipFile.exists()); + + equal(entryCount(in), + entryCount(out)); + + // We expect out to be identical to in, except for the removal of + // the optional data descriptor signatures. + final int SIG_LENGTH = 4; // length of a zip signature - PKxx + equal(in.length(), + out.length() + SIG_LENGTH * count); + + in.delete(); + out.delete(); + } + + //--------------------- Infrastructure --------------------------- + volatile int passed = 0, failed = 0; + void pass() {passed++;} + void fail() {failed++; Thread.dumpStack();} + void fail(String msg) {System.err.println(msg); fail();} + void unexpected(Throwable t) {failed++; t.printStackTrace();} + void check(boolean cond) {if (cond) pass(); else fail();} + void equal(Object x, Object y) { + if (x == null ? y == null : x.equals(y)) pass(); + else fail(x + " not equal to " + y);} + public static void main(String[] args) throws Throwable { + new DataDescriptorSignatureMissing().instanceMain(args);} + public void instanceMain(String[] args) throws Throwable { + try {test(args);} catch (Throwable t) {unexpected(t);} + System.out.printf("%nPassed = %d, failed = %d%n%n", passed, failed); + if (failed > 0) throw new AssertionError("Some tests failed");} +} From acba04a5b834cf9536345ee3802559765d0b30c4 Mon Sep 17 00:00:00 2001 From: Lance Andersen Date: Fri, 12 Sep 2014 18:37:58 -0400 Subject: [PATCH 27/81] 8058394: Doclint clean up in java.sql.Date Reviewed-by: darcy --- jdk/src/java.sql/share/classes/java/sql/Date.java | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/jdk/src/java.sql/share/classes/java/sql/Date.java b/jdk/src/java.sql/share/classes/java/sql/Date.java index ccf450f985e..74f90fa45f8 100644 --- a/jdk/src/java.sql/share/classes/java/sql/Date.java +++ b/jdk/src/java.sql/share/classes/java/sql/Date.java @@ -169,13 +169,17 @@ public class Date extends java.util.Date { return jla.newStringUnsafe(buf); } - /* + /** * Formats an unsigned integer into a char array in decimal output format. * Numbers will be zero-padded or truncated if the string representation * of the integer is smaller than or exceeds len, respectively. * * Should consider moving this to Integer and expose it through * JavaLangAccess similar to Integer::formatUnsignedInt + * @param val Value to convert + * @param buf Array containing converted value + * @param offset Starting pos in buf + * @param len length of output value */ protected static void formatDecimalInt(int val, char[] buf, int offset, int len) { int charPos = offset + len; From c29aa1d7b99bd9a7a1787faa1baf1dc5bcdb9e93 Mon Sep 17 00:00:00 2001 From: Behdad Esfahbod Date: Fri, 5 Sep 2014 19:06:07 -0700 Subject: [PATCH 28/81] 8057986: freetype code to get glyph outline does not handle initial control point properly Co-authored-by: Igor Kopylov Reviewed-by: prr, dougfelt --- .../native/libfontmanager/freetypeScaler.c | 130 +++++++----------- .../font/GlyphVector/GlyphVectorOutline.java | 91 ++++++++++++ 2 files changed, 143 insertions(+), 78 deletions(-) create mode 100644 jdk/test/java/awt/font/GlyphVector/GlyphVectorOutline.java diff --git a/jdk/src/java.desktop/share/native/libfontmanager/freetypeScaler.c b/jdk/src/java.desktop/share/native/libfontmanager/freetypeScaler.c index 55ca4ebc82c..12371110af7 100644 --- a/jdk/src/java.desktop/share/native/libfontmanager/freetypeScaler.c +++ b/jdk/src/java.desktop/share/native/libfontmanager/freetypeScaler.c @@ -1082,86 +1082,60 @@ static int allocateSpaceForGP(GPData* gpdata, int npoints, int ncontours) { return 1; } +static void addSeg(GPData *gp, jbyte type) { + gp->pointTypes[gp->numTypes++] = type; +} + +static void addCoords(GPData *gp, FT_Vector *p) { + gp->pointCoords[gp->numCoords++] = F26Dot6ToFloat(p->x); + gp->pointCoords[gp->numCoords++] = -F26Dot6ToFloat(p->y); +} + +static int moveTo(FT_Vector *to, GPData *gp) { + if (gp->numCoords) + addSeg(gp, SEG_CLOSE); + addCoords(gp, to); + addSeg(gp, SEG_MOVETO); + return FT_Err_Ok; +} + +static int lineTo(FT_Vector *to, GPData *gp) { + addCoords(gp, to); + addSeg(gp, SEG_LINETO); + return FT_Err_Ok; +} + +static int conicTo(FT_Vector *control, FT_Vector *to, GPData *gp) { + addCoords(gp, control); + addCoords(gp, to); + addSeg(gp, SEG_QUADTO); + return FT_Err_Ok; +} + +static int cubicTo(FT_Vector *control1, + FT_Vector *control2, + FT_Vector *to, + GPData *gp) { + addCoords(gp, control1); + addCoords(gp, control2); + addCoords(gp, to); + addSeg(gp, SEG_CUBICTO); + return FT_Err_Ok; +} + static void addToGP(GPData* gpdata, FT_Outline*outline) { - jbyte current_type=SEG_UNKNOWN; - int i, j; - jfloat x, y; + static const FT_Outline_Funcs outline_funcs = { + (FT_Outline_MoveToFunc) moveTo, + (FT_Outline_LineToFunc) lineTo, + (FT_Outline_ConicToFunc) conicTo, + (FT_Outline_CubicToFunc) cubicTo, + 0, /* shift */ + 0, /* delta */ + }; - j = 0; - for(i=0; in_points; i++) { - x = F26Dot6ToFloat(outline->points[i].x); - y = -F26Dot6ToFloat(outline->points[i].y); - - if (FT_CURVE_TAG(outline->tags[i]) == FT_CURVE_TAG_ON) { - /* If bit 0 is unset, the point is "off" the curve, - i.e., a Bezier control point, while it is "on" when set. */ - if (current_type == SEG_UNKNOWN) { /* special case: - very first point */ - /* add segment */ - gpdata->pointTypes[gpdata->numTypes++] = SEG_MOVETO; - current_type = SEG_LINETO; - } else { - gpdata->pointTypes[gpdata->numTypes++] = current_type; - current_type = SEG_LINETO; - } - } else { - if (current_type == SEG_UNKNOWN) { /* special case: - very first point */ - if (FT_CURVE_TAG(outline->tags[i+1]) == FT_CURVE_TAG_ON) { - /* just skip first point. Adhoc heuristic? */ - continue; - } else { - x = (x + F26Dot6ToFloat(outline->points[i+1].x))/2; - y = (y - F26Dot6ToFloat(outline->points[i+1].y))/2; - gpdata->pointTypes[gpdata->numTypes++] = SEG_MOVETO; - current_type = SEG_LINETO; - } - } else if (FT_CURVE_TAG(outline->tags[i]) == FT_CURVE_TAG_CUBIC) { - /* Bit 1 is meaningful for 'off' points only. - If set, it indicates a third-order Bezier arc control - point; and a second-order control point if unset. */ - current_type = SEG_CUBICTO; - } else { - /* two successive conic "off" points forces the rasterizer - to create (during the scan-line conversion process - exclusively) a virtual "on" point amidst them, at their - exact middle. This greatly facilitates the definition of - successive conic Bezier arcs. Moreover, it is the way - outlines are described in the TrueType specification. */ - if (current_type == SEG_QUADTO) { - gpdata->pointCoords[gpdata->numCoords++] = - F26Dot6ToFloat(outline->points[i].x + - outline->points[i-1].x)/2; - gpdata->pointCoords[gpdata->numCoords++] = - - F26Dot6ToFloat(outline->points[i].y + - outline->points[i-1].y)/2; - gpdata->pointTypes[gpdata->numTypes++] = SEG_QUADTO; - } - current_type = SEG_QUADTO; - } - } - gpdata->pointCoords[gpdata->numCoords++] = x; - gpdata->pointCoords[gpdata->numCoords++] = y; - if (outline->contours[j] == i) { //end of contour - int start = j > 0 ? outline->contours[j-1]+1 : 0; - gpdata->pointTypes[gpdata->numTypes++] = current_type; - if (current_type == SEG_QUADTO && - FT_CURVE_TAG(outline->tags[start]) != FT_CURVE_TAG_ON) { - gpdata->pointCoords[gpdata->numCoords++] = - (F26Dot6ToFloat(outline->points[start].x) + x)/2; - gpdata->pointCoords[gpdata->numCoords++] = - (-F26Dot6ToFloat(outline->points[start].y) + y)/2; - } else { - gpdata->pointCoords[gpdata->numCoords++] = - F26Dot6ToFloat(outline->points[start].x); - gpdata->pointCoords[gpdata->numCoords++] = - -F26Dot6ToFloat(outline->points[start].y); - } - gpdata->pointTypes[gpdata->numTypes++] = SEG_CLOSE; - current_type = SEG_UNKNOWN; - j++; - } - } + FT_Outline_Decompose(outline, &outline_funcs, gpdata); + if (gpdata->numCoords) + addSeg(gpdata, SEG_CLOSE); /* If set to 1, the outline will be filled using the even-odd fill rule */ if (outline->flags & FT_OUTLINE_EVEN_ODD_FILL) { diff --git a/jdk/test/java/awt/font/GlyphVector/GlyphVectorOutline.java b/jdk/test/java/awt/font/GlyphVector/GlyphVectorOutline.java new file mode 100644 index 00000000000..5680f7bc42a --- /dev/null +++ b/jdk/test/java/awt/font/GlyphVector/GlyphVectorOutline.java @@ -0,0 +1,91 @@ +/* + * Copyright (c) 2014 Google Inc. 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.awt.Color; +import java.awt.Font; +import java.awt.Graphics2D; +import java.awt.Image; +import java.awt.font.FontRenderContext; +import java.awt.font.GlyphVector; +import java.awt.font.LineBreakMeasurer; +import java.awt.font.TextAttribute; +import java.awt.font.TextLayout; +import java.awt.image.BufferedImage; +import java.io.File; +import java.text.AttributedString; + +import javax.imageio.ImageIO; + +/** + * Manual test for: + * JDK-8057986: freetype code to get glyph outline does not handle initial control point properly + * + * Manual repro recipe: + * (cd test/java/awt/font/GlyphVector/ && javac GlyphVectorOutline.java && wget -q -O/tmp/msgothic.ttc https://browserlinux-jp.googlecode.com/files/msgothic.ttc && java GlyphVectorOutline /tmp/msgothic.ttc /tmp/katakana.png) + * + * Then examine the two rendered Japanese characters in the png file. + * + * Renders text to a PNG by + * 1. using the native Graphics2D#drawGlyphVector implementation + * 2. filling in the result of GlyphVector#getOutline + * + * Should be the same but is different for some CJK characters + * (e.g. Katakana character \u30AF). + * + * @author ikopylov@google.com (Igor Kopylov) + */ +public class GlyphVectorOutline { + public static void main(String[] args) throws Exception { + if (args.length != 2) { + throw new Error("Usage: java GlyphVectorOutline fontfile outputfile"); + } + writeImage(new File(args[0]), + new File(args[1]), + "\u30AF"); + } + + public static void writeImage(File fontFile, File outputFile, String value) throws Exception { + BufferedImage image = new BufferedImage(200, 200, BufferedImage.TYPE_INT_RGB); + Graphics2D g = image.createGraphics(); + g.setColor(Color.WHITE); + g.fillRect(0, 0, image.getWidth(), image.getHeight()); + g.setColor(Color.BLACK); + + Font font = Font.createFont(Font.TRUETYPE_FONT, fontFile); + font = font.deriveFont(Font.PLAIN, 72f); + FontRenderContext frc = new FontRenderContext(null, false, false); + GlyphVector gv = font.createGlyphVector(frc, value); + g.drawGlyphVector(gv, 10, 80); + g.fill(gv.getOutline(10, 180)); + ImageIO.write(image, "png", outputFile); + } + + private static void drawString(Graphics2D g, Font font, String value, float x, float y) { + AttributedString str = new AttributedString(value); + str.addAttribute(TextAttribute.FOREGROUND, Color.BLACK); + str.addAttribute(TextAttribute.FONT, font); + FontRenderContext frc = new FontRenderContext(null, true, true); + TextLayout layout = new LineBreakMeasurer(str.getIterator(), frc).nextLayout(Integer.MAX_VALUE); + layout.draw(g, x, y); + } +} From 1e000f777daed28ab10b499997f1e65c4138887d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hannes=20Walln=C3=B6fer?= Date: Fri, 12 Sep 2014 11:00:51 +0200 Subject: [PATCH 29/81] 8057743: Single quotes must be escaped in message resource file Reviewed-by: attila, lagergren, sundar --- .../internal/runtime/resources/Messages.properties | 10 +++++----- nashorn/test/script/basic/JDK-8043232.js.EXPECTED | 6 +++--- nashorn/test/script/basic/JDK-8049242.js.EXPECTED | 2 +- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/resources/Messages.properties b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/resources/Messages.properties index 16b4e05d290..056dc87deed 100644 --- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/resources/Messages.properties +++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/resources/Messages.properties @@ -92,7 +92,7 @@ type.error.cant.delete.property.of.undefined=Cannot delete property "{0}" of und # other wrong usages of property type.error.property.has.no.setter=Cannot set property "{0}" of {1} that has only a getter -type.error.cant.set.proto.to.non.object=Cannot set Object {0}'s __proto__ to be a non-object like {1} +type.error.cant.set.proto.to.non.object=Cannot set Object {0}''s __proto__ to be a non-object like {1} type.error.no.such.function={1} has no such function "{0}" type.error.no.such.java.class=No such Java class: {0} type.error.no.such.java.constructor=No such Java constructor: {0} @@ -125,10 +125,10 @@ type.error.prototype.not.an.object="prototype" of {0} is not an Object, it is {1 type.error.cant.load.script=Cannot load script from {0} type.error.JSON.stringify.cyclic=JSON.stringify got a cyclic data structure type.error.cant.convert.string.to.char=Cannot convert string to character; its length must be exactly 1 -type.error.cant.convert.number.to.char=Cannot convert number to character; it's out of 0-65535 range +type.error.cant.convert.number.to.char=Cannot convert number to character; it is out of 0-65535 range type.error.cant.convert.to.java.string=Cannot convert object of type {0} to a Java argument of string type type.error.cant.convert.to.java.number=Cannot convert object of type {0} to a Java argument of number type -type.error.cant.convert.to.javascript.array=Can only convert Java arrays and lists to JavaScript arrays. Can't convert object of type {0}. +type.error.cant.convert.to.javascript.array=Can only convert Java arrays and lists to JavaScript arrays. Cannot convert object of type {0}. type.error.extend.expects.at.least.one.argument=Java.extend needs at least one argument. type.error.extend.expects.at.least.one.type.argument=Java.extend needs at least one type argument. type.error.extend.expects.java.types=Java.extend needs Java types as its arguments. @@ -141,10 +141,10 @@ type.error.extend.ERROR_NO_COMMON_LOADER=Can not find a common class loader for type.error.extend.ERROR_FINAL_FINALIZER=Can not extend class because {0} has a final finalize method. type.error.no.constructor.matches.args=Can not construct {0} with the passed arguments; they do not match any of its constructor signatures. type.error.no.method.matches.args=Can not invoke method {0} with the passed arguments; they do not match any of its method signatures. -type.error.method.not.constructor=Java method {0} can't be used as a constructor. +type.error.method.not.constructor=Java method {0} cannot be used as a constructor. type.error.env.not.object=$ENV must be an Object. type.error.unsupported.java.to.type=Unsupported Java.to target type {0}. -type.error.constructor.requires.new=Constructor {0} requires 'new'. +type.error.constructor.requires.new=Constructor {0} requires "new". type.error.new.on.nonpublic.javatype=new cannot be used with non-public java type {0}. range.error.dataview.constructor.offset=Wrong offset or length in DataView constructor diff --git a/nashorn/test/script/basic/JDK-8043232.js.EXPECTED b/nashorn/test/script/basic/JDK-8043232.js.EXPECTED index 5fcfab8e24d..03382ea512d 100644 --- a/nashorn/test/script/basic/JDK-8043232.js.EXPECTED +++ b/nashorn/test/script/basic/JDK-8043232.js.EXPECTED @@ -6,9 +6,9 @@ TypeError: No such Java constructor: Object(String) TypeError: Java constructor signature invalid: Object()xxxxx TypeError: Java constructor signature invalid: Object( TypeError: Java constructor signature invalid: Object) -TypeError: Java method [jdk.internal.dynalink.beans.OverloadedDynamicMethod java.lang.System.getProperty] cant be used as a constructor. -TypeError: Java method [jdk.internal.dynalink.beans.OverloadedDynamicMethod java.io.PrintStream.println] cant be used as a constructor. -TypeError: Constructor [jdk.internal.dynalink.beans.SimpleDynamicMethod Color java.awt.Color.java.awt.Color(int,int,int)] requires new. +TypeError: Java method [jdk.internal.dynalink.beans.OverloadedDynamicMethod java.lang.System.getProperty] cannot be used as a constructor. +TypeError: Java method [jdk.internal.dynalink.beans.OverloadedDynamicMethod java.io.PrintStream.println] cannot be used as a constructor. +TypeError: Constructor [jdk.internal.dynalink.beans.SimpleDynamicMethod Color java.awt.Color.java.awt.Color(int,int,int)] requires "new". TypeError: No such Java constructor: Runnable() TypeError: No such Java constructor: Runnable(int) java.lang.InstantiationException: java.io.InputStream diff --git a/nashorn/test/script/basic/JDK-8049242.js.EXPECTED b/nashorn/test/script/basic/JDK-8049242.js.EXPECTED index 4aa4627659f..4a2f4169153 100644 --- a/nashorn/test/script/basic/JDK-8049242.js.EXPECTED +++ b/nashorn/test/script/basic/JDK-8049242.js.EXPECTED @@ -4,7 +4,7 @@ java.awt.Color[r=33,g=233,b=2] TypeError: null is not a function TypeError: null is not a function TypeError: null is not a function -TypeError: Constructor [jdk.internal.dynalink.beans.SimpleDynamicMethod Color java.awt.Color.java.awt.Color(int,int,int)] requires new. +TypeError: Constructor [jdk.internal.dynalink.beans.SimpleDynamicMethod Color java.awt.Color.java.awt.Color(int,int,int)] requires "new". TypeError: null is not a function TypeError: null is not a function java.lang.InstantiationException: java.io.InputStream From 9afdb7964c4e66a21c6381f3ba0c71bebca3ccc9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hannes=20Walln=C3=B6fer?= Date: Fri, 12 Sep 2014 15:01:48 +0200 Subject: [PATCH 30/81] 8058304: Non-serializable fields in serializable classes Reviewed-by: lagergren, sundar --- .../share/classes/jdk/nashorn/internal/parser/Parser.java | 5 ++++- .../jdk/nashorn/internal/runtime/AccessorProperty.java | 2 +- .../share/classes/jdk/nashorn/internal/runtime/Property.java | 2 +- 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/parser/Parser.java b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/parser/Parser.java index 6f47c3fc6a1..3162e184468 100644 --- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/parser/Parser.java +++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/parser/Parser.java @@ -54,6 +54,7 @@ import static jdk.nashorn.internal.parser.TokenType.SEMICOLON; import static jdk.nashorn.internal.parser.TokenType.TERNARY; import static jdk.nashorn.internal.parser.TokenType.WHILE; +import java.io.Serializable; import java.util.ArrayDeque; import java.util.ArrayList; import java.util.Collections; @@ -2977,11 +2978,13 @@ loop: * Encapsulates part of the state of the parser, enough to reconstruct the state of both parser and lexer * for resuming parsing after skipping a function body. */ - private static class ParserState { + private static class ParserState implements Serializable { private final int position; private final int line; private final int linePosition; + private static final long serialVersionUID = -2382565130754093694L; + ParserState(final int position, final int line, final int linePosition) { this.position = position; this.line = line; diff --git a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/AccessorProperty.java b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/AccessorProperty.java index e030354ab8f..44b3c3b075d 100644 --- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/AccessorProperty.java +++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/AccessorProperty.java @@ -119,7 +119,7 @@ public class AccessorProperty extends Property { * produce different boun method handles wrapping the same access mechanism * depending on callsite */ - private MethodHandle[] GETTER_CACHE = new MethodHandle[NOOF_TYPES]; + private transient MethodHandle[] GETTER_CACHE = new MethodHandle[NOOF_TYPES]; /** * Create a new accessor property. Factory method used by nasgen generated code. diff --git a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/Property.java b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/Property.java index c83c4531d36..1f9f1459313 100644 --- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/Property.java +++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/Property.java @@ -101,7 +101,7 @@ public abstract class Property implements Serializable { private final int slot; /** SwitchPoint that is invalidated when property is changed, optional */ - protected SwitchPoint changeCallback; + protected transient SwitchPoint changeCallback; private static final long serialVersionUID = 2099814273074501176L; From 78ea4569e271eb434f05028312c567a81044aa96 Mon Sep 17 00:00:00 2001 From: Miroslav Kos Date: Fri, 12 Sep 2014 17:20:37 +0200 Subject: [PATCH 31/81] 8054548: JAX-WS tools need to updated to work with modular image Removing java reflection API to get JavaCompiler; using standard javax.tools API instead Reviewed-by: alanb --- .../internal/xjc/api/util/ApClassLoader.java | 152 ------------------ .../api/util/ToolsJarNotFoundException.java | 51 ------ .../com/sun/tools/internal/ws/Invoker.java | 64 ++------ .../com/sun/tools/internal/ws/WsGen.java | 7 +- .../com/sun/tools/internal/ws/WsImport.java | 7 +- .../ws/resources/JavacompilerMessages.java | 36 +---- .../ws/resources/javacompiler.properties | 6 +- .../ws/wscompile/JavaCompilerHelper.java | 36 ++--- 8 files changed, 32 insertions(+), 327 deletions(-) delete mode 100644 jaxws/src/jdk.xml.bind/share/classes/com/sun/tools/internal/xjc/api/util/ApClassLoader.java delete mode 100644 jaxws/src/jdk.xml.bind/share/classes/com/sun/tools/internal/xjc/api/util/ToolsJarNotFoundException.java diff --git a/jaxws/src/jdk.xml.bind/share/classes/com/sun/tools/internal/xjc/api/util/ApClassLoader.java b/jaxws/src/jdk.xml.bind/share/classes/com/sun/tools/internal/xjc/api/util/ApClassLoader.java deleted file mode 100644 index d5996ff0c53..00000000000 --- a/jaxws/src/jdk.xml.bind/share/classes/com/sun/tools/internal/xjc/api/util/ApClassLoader.java +++ /dev/null @@ -1,152 +0,0 @@ -/* - * Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package com.sun.tools.internal.xjc.api.util; - -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.io.InputStream; -import java.io.File; -import java.net.URL; -import java.net.URLClassLoader; -import java.net.MalformedURLException; - -import com.sun.istack.internal.Nullable; - -/** - * {@link ClassLoader} that loads Annotation Processing and specified classes - * both into the same classloader, so that they can reference each other. - * - * @author Bhakti Mehta - * @since 2.0 beta - */ -public final class ApClassLoader extends URLClassLoader { - /** - * List of package prefixes we want to mask the - * parent classLoader from loading - */ - private final String[] packagePrefixes; - - /** - * - * @param packagePrefixes - * The package prefixes that are forced to resolve within this class loader. - * @param parent - * The parent class loader to delegate to. Null to indicate bootstrap classloader. - */ - public ApClassLoader(@Nullable ClassLoader parent, String[] packagePrefixes) throws ToolsJarNotFoundException { - super(getToolsJar(parent),parent); - if(getURLs().length==0) - // if tools.jar was found in our classloader, no need to create - // a parallel classes - this.packagePrefixes = new String[0]; - else - this.packagePrefixes = packagePrefixes; - } - - public Class loadClass(String className) throws ClassNotFoundException { - for( String prefix : packagePrefixes ) { - if (className.startsWith(prefix) ) { - // we need to load those classes in this class loader - // without delegation. - return findClass(className); - } - } - - return super.loadClass(className); - - } - - protected Class findClass(String name) throws ClassNotFoundException { - - StringBuilder sb = new StringBuilder(name.length() + 6); - sb.append(name.replace('.','/')).append(".class"); - - InputStream is = getResourceAsStream(sb.toString()); - if (is==null) - throw new ClassNotFoundException("Class not found" + sb); - - try { - ByteArrayOutputStream baos = new ByteArrayOutputStream(); - byte[] buf = new byte[1024]; - int len; - while((len=is.read(buf))>=0) - baos.write(buf,0,len); - - buf = baos.toByteArray(); - - // define package if not defined yet - int i = name.lastIndexOf('.'); - if (i != -1) { - String pkgname = name.substring(0, i); - Package pkg = getPackage(pkgname); - if(pkg==null) - definePackage(pkgname, null, null, null, null, null, null, null); - } - - return defineClass(name,buf,0,buf.length); - } catch (IOException e) { - throw new ClassNotFoundException(name,e); - } finally { - try { - is.close(); - } catch (IOException ioe) { - //ignore - } - } - } - - /** - * Returns a class loader that can load classes from JDK tools.jar. - * @param parent - */ - private static URL[] getToolsJar(@Nullable ClassLoader parent) throws ToolsJarNotFoundException { - - try { - Class.forName("com.sun.tools.javac.Main", false, parent); - return new URL[0]; - // we can already load them in the parent class loader. - // so no need to look for tools.jar. - // this happens when we are run inside IDE/Ant, or - // in Mac OS. - } catch (ClassNotFoundException e) { - // otherwise try to find tools.jar - } - - File jreHome = new File(System.getProperty("java.home")); - File toolsJar = new File( jreHome.getParent(), "lib/tools.jar" ); - - if (!toolsJar.exists()) { - throw new ToolsJarNotFoundException(toolsJar); - } - - try { - return new URL[]{toolsJar.toURL()}; - } catch (MalformedURLException e) { - // impossible - throw new AssertionError(e); - } - } -} diff --git a/jaxws/src/jdk.xml.bind/share/classes/com/sun/tools/internal/xjc/api/util/ToolsJarNotFoundException.java b/jaxws/src/jdk.xml.bind/share/classes/com/sun/tools/internal/xjc/api/util/ToolsJarNotFoundException.java deleted file mode 100644 index 07ef4657e6c..00000000000 --- a/jaxws/src/jdk.xml.bind/share/classes/com/sun/tools/internal/xjc/api/util/ToolsJarNotFoundException.java +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package com.sun.tools.internal.xjc.api.util; - -import java.io.File; - -/** - * Signals an error when tools.jar was not found. - * - * Simply print out the message obtained by {@link #getMessage()}. - * - * @author Kohsuke Kawaguchi - */ -public final class ToolsJarNotFoundException extends Exception { - /** - * Location where we expected to find tools.jar - */ - public final File toolsJar; - - public ToolsJarNotFoundException(File toolsJar) { - super(calcMessage(toolsJar)); - this.toolsJar = toolsJar; - } - - private static String calcMessage(File toolsJar) { - return Messages.TOOLS_JAR_NOT_FOUND.format(toolsJar.getPath()); - } -} diff --git a/jaxws/src/jdk.xml.ws/share/classes/com/sun/tools/internal/ws/Invoker.java b/jaxws/src/jdk.xml.ws/share/classes/com/sun/tools/internal/ws/Invoker.java index a0368e87109..c81b9a55291 100644 --- a/jaxws/src/jdk.xml.ws/share/classes/com/sun/tools/internal/ws/Invoker.java +++ b/jaxws/src/jdk.xml.ws/share/classes/com/sun/tools/internal/ws/Invoker.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -29,19 +29,16 @@ import com.sun.istack.internal.tools.MaskingClassLoader; import com.sun.istack.internal.tools.ParallelWorldClassLoader; import com.sun.tools.internal.ws.resources.WscompileMessages; import com.sun.tools.internal.ws.wscompile.Options; -import com.sun.tools.internal.xjc.api.util.ToolsJarNotFoundException; import com.sun.xml.internal.bind.util.Which; import javax.xml.ws.Service; import javax.xml.ws.WebServiceFeature; import javax.xml.namespace.QName; -import java.io.File; import java.io.OutputStream; import java.io.IOException; import java.lang.reflect.Constructor; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; -import java.net.MalformedURLException; import java.net.URL; import java.net.URLClassLoader; import java.util.ArrayList; @@ -59,7 +56,7 @@ public final class Invoker { /** * The list of package prefixes we want the * {@link MaskingClassLoader} to prevent the parent - * classLoader from loading + * class loader from loading */ static final String[] maskedPackages = new String[]{ "com.sun.istack.internal.tools.", @@ -130,24 +127,6 @@ public final class Invoker { return -1; } - //find and load tools.jar - List urls = new ArrayList(); - findToolsJar(cl, urls); - - if(urls.size() > 0){ - List mask = new ArrayList(Arrays.asList(maskedPackages)); - - // first create a protected area so that we load JAXB/WS 2.1 API - // and everything that depends on them inside - cl = new MaskingClassLoader(cl,mask); - - // then this classloader loads the API and tools.jar - cl = new URLClassLoader(urls.toArray(new URL[urls.size()]), cl); - - // finally load the rest of the RI. The actual class files are loaded from ancestors - cl = new ParallelWorldClassLoader(cl,""); - } - } Thread.currentThread().setContextClassLoader(cl); @@ -158,8 +137,6 @@ public final class Invoker { Method runMethod = compileTool.getMethod("run",String[].class); boolean r = (Boolean)runMethod.invoke(tool,new Object[]{args}); return r ? 0 : 1; - } catch (ToolsJarNotFoundException e) { - System.err.println(e.getMessage()); } catch (InvocationTargetException e) { throw e.getCause(); } catch(ClassNotFoundException e){ @@ -167,8 +144,6 @@ public final class Invoker { }finally { Thread.currentThread().setContextClassLoader(oldcc); } - - return -1; } /** @@ -203,10 +178,10 @@ public final class Invoker { /** - * Creates a classloader that can load JAXB/WS 2.2 API and tools.jar, - * and then return a classloader that can RI classes, which can see all those APIs and tools.jar. + * Creates a class loader that can load JAXB/WS 2.2 API, + * and then return a class loader that can RI classes, which can see all those APIs. */ - public static ClassLoader createClassLoader(ClassLoader cl) throws ClassNotFoundException, IOException, ToolsJarNotFoundException { + public static ClassLoader createClassLoader(ClassLoader cl) throws ClassNotFoundException, IOException { URL[] urls = findIstack22APIs(cl); if(urls.length==0) @@ -223,7 +198,7 @@ public final class Invoker { // and everything that depends on them inside cl = new MaskingClassLoader(cl,mask); - // then this classloader loads the API and tools.jar + // then this class loader loads the API cl = new URLClassLoader(urls, cl); // finally load the rest of the RI. The actual class files are loaded from ancestors @@ -233,13 +208,13 @@ public final class Invoker { } /** - * Creates a classloader for loading JAXB/WS 2.2 jar and tools.jar + * Creates a class loader for loading JAXB/WS 2.2 jar */ - private static URL[] findIstack22APIs(ClassLoader cl) throws ClassNotFoundException, IOException, ToolsJarNotFoundException { + private static URL[] findIstack22APIs(ClassLoader cl) throws ClassNotFoundException, IOException { List urls = new ArrayList(); if(Service.class.getClassLoader()==null) { - // JAX-WS API is loaded from bootstrap classloader + // JAX-WS API is loaded from bootstrap class loader URL res = cl.getResource("javax/xml/ws/EndpointContext.class"); if(res==null) throw new ClassNotFoundException("There's no JAX-WS 2.2 API in the classpath"); @@ -250,28 +225,7 @@ public final class Invoker { urls.add(ParallelWorldClassLoader.toJarUrl(res)); } - findToolsJar(cl, urls); - return urls.toArray(new URL[urls.size()]); } - private static void findToolsJar(ClassLoader cl, List urls) throws ToolsJarNotFoundException, MalformedURLException { - try { - Class.forName("com.sun.tools.javac.Main",false,cl); - // we can already load them in the parent class loader. - // so no need to look for tools.jar. - // this happens when we are run inside IDE/Ant, or - // in Mac OS. - } catch (ClassNotFoundException e) { - // otherwise try to find tools.jar - File jreHome = new File(System.getProperty("java.home")); - File toolsJar = new File( jreHome.getParent(), "lib/tools.jar" ); - - if (!toolsJar.exists()) { - throw new ToolsJarNotFoundException(toolsJar); - } - urls.add(toolsJar.toURL()); - } - } - } diff --git a/jaxws/src/jdk.xml.ws/share/classes/com/sun/tools/internal/ws/WsGen.java b/jaxws/src/jdk.xml.ws/share/classes/com/sun/tools/internal/ws/WsGen.java index f6a4cc49c69..57cdca18dc7 100644 --- a/jaxws/src/jdk.xml.ws/share/classes/com/sun/tools/internal/ws/WsGen.java +++ b/jaxws/src/jdk.xml.ws/share/classes/com/sun/tools/internal/ws/WsGen.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -35,8 +35,7 @@ import com.sun.tools.internal.ws.wscompile.WsgenTool; */ public class WsGen { /** - * CLI entry point. Use {@link Invoker} to - * load tools.jar + * CLI entry point. Use {@link Invoker} to load proper API version */ public static void main(String[] args) throws Throwable { System.exit(Invoker.invoke("com.sun.tools.internal.ws.wscompile.WsgenTool", args)); @@ -50,7 +49,7 @@ public class WsGen { * it doesn't invoke {@link System#exit(int)}. This method * also doesn't play with classloaders. It's the caller's * responsibility to set up the classloader to load all jars - * needed to run the tool, including $JAVA_HOME/lib/tools.jar + * needed to run the tool. * * @return * 0 if the tool runs successfully. diff --git a/jaxws/src/jdk.xml.ws/share/classes/com/sun/tools/internal/ws/WsImport.java b/jaxws/src/jdk.xml.ws/share/classes/com/sun/tools/internal/ws/WsImport.java index 5c84e92dc26..4a23faf97e5 100644 --- a/jaxws/src/jdk.xml.ws/share/classes/com/sun/tools/internal/ws/WsImport.java +++ b/jaxws/src/jdk.xml.ws/share/classes/com/sun/tools/internal/ws/WsImport.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -35,8 +35,7 @@ import com.sun.tools.internal.ws.wscompile.WsimportTool; */ public class WsImport { /** - * CLI entry point. Use {@link Invoker} to - * load tools.jar + * CLI entry point. Use {@link Invoker} to load proper API version */ public static void main(String[] args) throws Throwable { System.exit(Invoker.invoke("com.sun.tools.internal.ws.wscompile.WsimportTool", args)); @@ -50,7 +49,7 @@ public class WsImport { * it doesn't invoke {@link System#exit(int)}. This method * also doesn't play with classloaders. It's the caller's * responsibility to set up the classloader to load all jars - * needed to run the tool, including $JAVA_HOME/lib/tools.jar + * needed to run the tool. * * @return * 0 if the tool runs successfully. diff --git a/jaxws/src/jdk.xml.ws/share/classes/com/sun/tools/internal/ws/resources/JavacompilerMessages.java b/jaxws/src/jdk.xml.ws/share/classes/com/sun/tools/internal/ws/resources/JavacompilerMessages.java index 81aac4434fa..7e9c3d49fae 100644 --- a/jaxws/src/jdk.xml.ws/share/classes/com/sun/tools/internal/ws/resources/JavacompilerMessages.java +++ b/jaxws/src/jdk.xml.ws/share/classes/com/sun/tools/internal/ws/resources/JavacompilerMessages.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -39,40 +39,16 @@ public final class JavacompilerMessages { private final static LocalizableMessageFactory messageFactory = new LocalizableMessageFactory("com.sun.tools.internal.ws.resources.javacompiler"); private final static Localizer localizer = new Localizer(); - public static Localizable localizableJAVACOMPILER_CLASSPATH_ERROR(Object arg0) { - return messageFactory.getMessage("javacompiler.classpath.error", arg0); + public static Localizable localizableNO_JAVACOMPILER_ERROR() { + return messageFactory.getMessage("no.javacompiler.error"); } /** - * {0} is not available in the classpath, requires Sun's JDK version 5.0 or latter. + * No system compiler found, check your jdk. * */ - public static String JAVACOMPILER_CLASSPATH_ERROR(Object arg0) { - return localizer.localize(localizableJAVACOMPILER_CLASSPATH_ERROR(arg0)); - } - - public static Localizable localizableJAVACOMPILER_NOSUCHMETHOD_ERROR(Object arg0) { - return messageFactory.getMessage("javacompiler.nosuchmethod.error", arg0); - } - - /** - * There is no such method {0} available, requires Sun's JDK version 5.0 or latter. - * - */ - public static String JAVACOMPILER_NOSUCHMETHOD_ERROR(Object arg0) { - return localizer.localize(localizableJAVACOMPILER_NOSUCHMETHOD_ERROR(arg0)); - } - - public static Localizable localizableJAVACOMPILER_ERROR(Object arg0) { - return messageFactory.getMessage("javacompiler.error", arg0); - } - - /** - * error : {0}. - * - */ - public static String JAVACOMPILER_ERROR(Object arg0) { - return localizer.localize(localizableJAVACOMPILER_ERROR(arg0)); + public static String NO_JAVACOMPILER_ERROR() { + return localizer.localize(localizableNO_JAVACOMPILER_ERROR()); } } diff --git a/jaxws/src/jdk.xml.ws/share/classes/com/sun/tools/internal/ws/resources/javacompiler.properties b/jaxws/src/jdk.xml.ws/share/classes/com/sun/tools/internal/ws/resources/javacompiler.properties index 30dd83aee6e..03a64d092f6 100644 --- a/jaxws/src/jdk.xml.ws/share/classes/com/sun/tools/internal/ws/resources/javacompiler.properties +++ b/jaxws/src/jdk.xml.ws/share/classes/com/sun/tools/internal/ws/resources/javacompiler.properties @@ -1,5 +1,5 @@ # -# Copyright (c) 2005, 2013, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2005, 2014, Oracle and/or its affiliates. All rights reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # This code is free software; you can redistribute it and/or modify it @@ -26,6 +26,4 @@ # # Generic Messages # -javacompiler.classpath.error={0} is not available in the classpath, requires Sun's JDK version 5.0 or latter. -javacompiler.nosuchmethod.error=There is no such method {0} available, requires Sun's JDK version 5.0 or latter. -javacompiler.error=error : {0}. +no.javacompiler.error=No system compiler found, check your jdk. diff --git a/jaxws/src/jdk.xml.ws/share/classes/com/sun/tools/internal/ws/wscompile/JavaCompilerHelper.java b/jaxws/src/jdk.xml.ws/share/classes/com/sun/tools/internal/ws/wscompile/JavaCompilerHelper.java index b8fecadc938..f887cd705dd 100644 --- a/jaxws/src/jdk.xml.ws/share/classes/com/sun/tools/internal/ws/wscompile/JavaCompilerHelper.java +++ b/jaxws/src/jdk.xml.ws/share/classes/com/sun/tools/internal/ws/wscompile/JavaCompilerHelper.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -28,14 +28,13 @@ package com.sun.tools.internal.ws.wscompile; import com.sun.istack.internal.tools.ParallelWorldClassLoader; import com.sun.tools.internal.ws.resources.JavacompilerMessages; +import javax.tools.JavaCompiler; +import javax.tools.ToolProvider; import java.io.File; import java.io.OutputStream; -import java.io.PrintWriter; -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; import java.net.MalformedURLException; -import java.net.URL; import java.net.URISyntaxException; +import java.net.URL; /** * A helper class to invoke javac. @@ -61,34 +60,17 @@ class JavaCompilerHelper{ } static boolean compile(String[] args, OutputStream out, ErrorReceiver receiver){ - ClassLoader cl = Thread.currentThread().getContextClassLoader(); try { - /* try to use the new compiler */ - Class comSunToolsJavacMainClass = - cl.loadClass("com.sun.tools.javac.Main"); - try { - Method compileMethod = - comSunToolsJavacMainClass.getMethod( - "compile", - compileMethodSignature); - Object result = - compileMethod.invoke( - null, args, new PrintWriter(out)); - return result instanceof Integer && (Integer) result == 0; - } catch (NoSuchMethodException e2) { - receiver.error(JavacompilerMessages.JAVACOMPILER_NOSUCHMETHOD_ERROR("getMethod(\"compile\", Class[])"), e2); - } catch (IllegalAccessException e) { - receiver.error(e); - } catch (InvocationTargetException e) { - receiver.error(e); + JavaCompiler comp = ToolProvider.getSystemJavaCompiler(); + if (comp == null) { + receiver.error(JavacompilerMessages.NO_JAVACOMPILER_ERROR(), null); + return false; } - } catch (ClassNotFoundException e) { - receiver.error(JavacompilerMessages.JAVACOMPILER_CLASSPATH_ERROR("com.sun.tools.javac.Main"), e); + return 0 == comp.run(null, out, out, args); } catch (SecurityException e) { receiver.error(e); } return false; } - private static final Class[] compileMethodSignature = {String[].class, PrintWriter.class}; } From 5ddfb6abe14261b7ea73b5148dd959d3e541dbe6 Mon Sep 17 00:00:00 2001 From: Lance Andersen Date: Fri, 12 Sep 2014 17:46:05 -0400 Subject: [PATCH 32/81] 8058366: Export sun.misc to java.sql Reviewed-by: mchung --- modules.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/modules.xml b/modules.xml index c961ec5628e..2e287a5f3be 100644 --- a/modules.xml +++ b/modules.xml @@ -243,6 +243,7 @@ java.rmi java.security.jgss java.security.sasl + java.sql jdk.charsets jdk.deploy.osx jdk.dev From 79efb2b9d82e78c799ab3332331436118123ecf2 Mon Sep 17 00:00:00 2001 From: Sonali Goel Date: Fri, 12 Sep 2014 17:05:18 -0700 Subject: [PATCH 33/81] 8055080: Group 9d: golden files for tests in tools/javac dir Reviewed-by: jjg, mcimadamore, jlahoda --- langtools/test/tools/javac/Parens1.java | 27 ++------------- langtools/test/tools/javac/Parens1.out | 2 ++ langtools/test/tools/javac/Parens2.java | 27 ++------------- langtools/test/tools/javac/Parens2.out | 2 ++ langtools/test/tools/javac/Parens3.java | 27 ++------------- langtools/test/tools/javac/Parens3.out | 3 ++ langtools/test/tools/javac/Parens4.java | 27 ++------------- langtools/test/tools/javac/Parens4.out | 2 ++ .../test/tools/javac/ParseConditional.java | 34 +++++-------------- .../test/tools/javac/ParseConditional.out | 2 ++ langtools/test/tools/javac/StoreClass.java | 27 ++------------- langtools/test/tools/javac/StoreClass.out | 3 ++ langtools/test/tools/javac/SwitchScope.java | 27 ++------------- langtools/test/tools/javac/SwitchScope.out | 2 ++ langtools/test/tools/javac/SynthName2.java | 29 ++-------------- langtools/test/tools/javac/SynthName2.out | 4 +++ langtools/test/tools/javac/T6234077.java | 29 ++-------------- langtools/test/tools/javac/T6234077.out | 2 ++ 18 files changed, 48 insertions(+), 228 deletions(-) create mode 100644 langtools/test/tools/javac/Parens1.out create mode 100644 langtools/test/tools/javac/Parens2.out create mode 100644 langtools/test/tools/javac/Parens3.out create mode 100644 langtools/test/tools/javac/Parens4.out create mode 100644 langtools/test/tools/javac/ParseConditional.out create mode 100644 langtools/test/tools/javac/StoreClass.out create mode 100644 langtools/test/tools/javac/SwitchScope.out create mode 100644 langtools/test/tools/javac/SynthName2.out create mode 100644 langtools/test/tools/javac/T6234077.out diff --git a/langtools/test/tools/javac/Parens1.java b/langtools/test/tools/javac/Parens1.java index 73d8e469448..2ad17e09f5c 100644 --- a/langtools/test/tools/javac/Parens1.java +++ b/langtools/test/tools/javac/Parens1.java @@ -1,33 +1,10 @@ /* - * Copyright (c) 2001, 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 + * @test /nodynamiccopyright/ * @bug 4391330 * @summary compiler accepted (Integer).toString(123) * @author gafter * - * @compile/fail Parens1.java + * @compile/fail/ref=Parens1.out -XDrawDiagnostics Parens1.java */ class Parens1 { diff --git a/langtools/test/tools/javac/Parens1.out b/langtools/test/tools/javac/Parens1.out new file mode 100644 index 00000000000..8797c53578d --- /dev/null +++ b/langtools/test/tools/javac/Parens1.out @@ -0,0 +1,2 @@ +Parens1.java:12:20: compiler.err.illegal.start.of.type +1 error diff --git a/langtools/test/tools/javac/Parens2.java b/langtools/test/tools/javac/Parens2.java index 858e5871a95..a7f3f1d2f52 100644 --- a/langtools/test/tools/javac/Parens2.java +++ b/langtools/test/tools/javac/Parens2.java @@ -1,33 +1,10 @@ /* - * Copyright (c) 2001, 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 + * @test /nodynamiccopyright/ * @bug 4408036 * @summary Compiler accepted "(i=2);" as a valid expession statement. * @author gafter * - * @compile/fail Parens2.java + * @compile/fail/ref=Parens2.out -XDrawDiagnostics Parens2.java */ class Parens2 { diff --git a/langtools/test/tools/javac/Parens2.out b/langtools/test/tools/javac/Parens2.out new file mode 100644 index 00000000000..46d080ed02f --- /dev/null +++ b/langtools/test/tools/javac/Parens2.out @@ -0,0 +1,2 @@ +Parens2.java:13:9: compiler.err.not.stmt +1 error diff --git a/langtools/test/tools/javac/Parens3.java b/langtools/test/tools/javac/Parens3.java index 13e1a8df974..919d4a7675a 100644 --- a/langtools/test/tools/javac/Parens3.java +++ b/langtools/test/tools/javac/Parens3.java @@ -1,33 +1,10 @@ /* - * Copyright (c) 2001, 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 + * @test /nodynamiccopyright/ * @bug 4394546 * @summary get no err msg if label wrapped in parentheses * @author gafter * - * @compile/fail Parens3.java + * @compile/fail/ref=Parens3.out -XDrawDiagnostics Parens3.java */ class Parens3 { diff --git a/langtools/test/tools/javac/Parens3.out b/langtools/test/tools/javac/Parens3.out new file mode 100644 index 00000000000..b32c91ac7a6 --- /dev/null +++ b/langtools/test/tools/javac/Parens3.out @@ -0,0 +1,3 @@ +Parens3.java:12:5: compiler.err.not.stmt +Parens3.java:12:10: compiler.err.expected: ';' +2 errors diff --git a/langtools/test/tools/javac/Parens4.java b/langtools/test/tools/javac/Parens4.java index a3e7ae68707..1811cccfcf2 100644 --- a/langtools/test/tools/javac/Parens4.java +++ b/langtools/test/tools/javac/Parens4.java @@ -1,33 +1,10 @@ /* - * Copyright (c) 2004, 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 + * @test /nodynamiccopyright/ * @bug 4933317 * @summary javac accepts parens in package names * @author gafter * - * @compile/fail Parens4.java + * @compile/fail/ref=Parens4.out -XDrawDiagnostics Parens4.java */ class Parens4 { diff --git a/langtools/test/tools/javac/Parens4.out b/langtools/test/tools/javac/Parens4.out new file mode 100644 index 00000000000..1d44883b7d3 --- /dev/null +++ b/langtools/test/tools/javac/Parens4.out @@ -0,0 +1,2 @@ +Parens4.java:12:16: compiler.err.illegal.start.of.type +1 error diff --git a/langtools/test/tools/javac/ParseConditional.java b/langtools/test/tools/javac/ParseConditional.java index 9a2f21393e7..afedfc41216 100644 --- a/langtools/test/tools/javac/ParseConditional.java +++ b/langtools/test/tools/javac/ParseConditional.java @@ -1,34 +1,11 @@ /* - * Copyright (c) 1997, 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 + * @test /nodynamiccopyright/ * @bug 4092958 * @summary The compiler was too permissive in its parsing of conditional * expressions. * @author turnidge * - * @compile/fail ParseConditional.java + * @compile/fail/ref=ParseConditional.out -XDrawDiagnostics ParseConditional.java */ public class ParseConditional { @@ -38,6 +15,11 @@ public class ParseConditional { int b = 2; int c = 3; int d = 4; - a = condition ? b = c : c = d; // Should get a parse error. + // The following line should give an error because the conditional ?: operator + // is higher priority than the final assignment operator, between c and d. + // As such, the correct parsing is: + // a = (condition ? b = c : c) = d; + // and it is illegal to try and assign to the value of the conditional expression. + a = condition ? b = c : c = d; } } diff --git a/langtools/test/tools/javac/ParseConditional.out b/langtools/test/tools/javac/ParseConditional.out new file mode 100644 index 00000000000..96918c2ace3 --- /dev/null +++ b/langtools/test/tools/javac/ParseConditional.out @@ -0,0 +1,2 @@ +ParseConditional.java:23:23: compiler.err.unexpected.type: kindname.variable, kindname.value +1 error diff --git a/langtools/test/tools/javac/StoreClass.java b/langtools/test/tools/javac/StoreClass.java index 07b64bf5f73..eacbd833749 100644 --- a/langtools/test/tools/javac/StoreClass.java +++ b/langtools/test/tools/javac/StoreClass.java @@ -1,33 +1,10 @@ /* - * Copyright (c) 2001, 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 + * @test /nodynamiccopyright/ * @bug 4350352 * @summary InternalError: store unsupported: com.sun.tools.javac.v8.comp.Items * @author gafter * - * @compile/fail StoreClass.java + * @compile/fail/ref=StoreClass.out -XDrawDiagnostics StoreClass.java */ class StoreClass { diff --git a/langtools/test/tools/javac/StoreClass.out b/langtools/test/tools/javac/StoreClass.out new file mode 100644 index 00000000000..c465a71f135 --- /dev/null +++ b/langtools/test/tools/javac/StoreClass.out @@ -0,0 +1,3 @@ +StoreClass.java:12:19: compiler.err.cant.assign.val.to.final.var: class +StoreClass.java:13:12: compiler.err.cant.assign.val.to.final.var: class +2 errors diff --git a/langtools/test/tools/javac/SwitchScope.java b/langtools/test/tools/javac/SwitchScope.java index b6fdfa92aec..a7c0aabe75f 100644 --- a/langtools/test/tools/javac/SwitchScope.java +++ b/langtools/test/tools/javac/SwitchScope.java @@ -1,33 +1,10 @@ /* - * Copyright (c) 2002, 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 + * @test /nodynamiccopyright/ * @bug 4725650 * @summary Restrict scope of local classes in switch-block-group * @author gafter * - * @compile/fail SwitchScope.java + * @compile/fail/ref=SwitchScope.out -XDrawDiagnostics SwitchScope.java */ public class SwitchScope { diff --git a/langtools/test/tools/javac/SwitchScope.out b/langtools/test/tools/javac/SwitchScope.out new file mode 100644 index 00000000000..87e4f68d032 --- /dev/null +++ b/langtools/test/tools/javac/SwitchScope.out @@ -0,0 +1,2 @@ +SwitchScope.java:22:28: compiler.err.cant.resolve.location: kindname.class, Local, , , (compiler.misc.location: kindname.class, SwitchScope, null) +1 error diff --git a/langtools/test/tools/javac/SynthName2.java b/langtools/test/tools/javac/SynthName2.java index 01fffeebe88..ee0a183a448 100644 --- a/langtools/test/tools/javac/SynthName2.java +++ b/langtools/test/tools/javac/SynthName2.java @@ -1,38 +1,15 @@ /* - * Copyright (c) 2001, 2004, 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 + * @test /nodynamiccopyright/ * @bug 4462714 * @summary using of synthetic names in local class causes ClassFormatError * @author gafter * - * @compile/fail SynthName2.java + * @compile/fail/ref=SynthName2.out -XDrawDiagnostics SynthName2.java */ import java.io.PrintStream; -class SynthName1 { +class SynthName2 { public static void main(String args[]) { run(args, System.out); } diff --git a/langtools/test/tools/javac/SynthName2.out b/langtools/test/tools/javac/SynthName2.out new file mode 100644 index 00000000000..9906c82c407 --- /dev/null +++ b/langtools/test/tools/javac/SynthName2.out @@ -0,0 +1,4 @@ +SynthName2.java:33:9: compiler.err.synthetic.name.conflict: val$zzz, InnClass +SynthName2.java:34:17: compiler.err.synthetic.name.conflict: val$prm1, InnClass +SynthName2.java:35:17: compiler.err.synthetic.name.conflict: val$zzz, InnClass +3 errors diff --git a/langtools/test/tools/javac/T6234077.java b/langtools/test/tools/javac/T6234077.java index 12f439c72ed..7f8f195a13a 100644 --- a/langtools/test/tools/javac/T6234077.java +++ b/langtools/test/tools/javac/T6234077.java @@ -1,30 +1,7 @@ /* - * Copyright (c) 2005, 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 /nodynamiccopyright/ + * @bug 6234077 + * @compile/fail/ref=T6234077.out -XDrawDiagnostics T6234077.java */ -/* - * @test - * @bug 6234077 - * @compile/fail T6234077.java - */ -@Deprecated /** @deprecated */ public class Foo { } diff --git a/langtools/test/tools/javac/T6234077.out b/langtools/test/tools/javac/T6234077.out new file mode 100644 index 00000000000..2a77ac7e7f7 --- /dev/null +++ b/langtools/test/tools/javac/T6234077.out @@ -0,0 +1,2 @@ +T6234077.java:7:8: compiler.err.class.public.should.be.in.file: Foo +1 error From 2426fa797f6bed28c6f3f21ce767abbf6a0bfab8 Mon Sep 17 00:00:00 2001 From: Ivan Gerasimov Date: Sat, 13 Sep 2014 20:06:15 +0400 Subject: [PATCH 34/81] 8054029: (fc) FileChannel.size() returns 0 for block devices on Linux Reviewed-by: alanb --- .../native/libnio/ch/FileDispatcherImpl.c | 17 ++++- .../channels/FileChannel/BlockDeviceSize.java | 62 +++++++++++++++++++ 2 files changed, 78 insertions(+), 1 deletion(-) create mode 100644 jdk/test/java/nio/channels/FileChannel/BlockDeviceSize.java diff --git a/jdk/src/java.base/unix/native/libnio/ch/FileDispatcherImpl.c b/jdk/src/java.base/unix/native/libnio/ch/FileDispatcherImpl.c index c9d20112479..403c15cad06 100644 --- a/jdk/src/java.base/unix/native/libnio/ch/FileDispatcherImpl.c +++ b/jdk/src/java.base/unix/native/libnio/ch/FileDispatcherImpl.c @@ -34,6 +34,10 @@ #include #include #include +#if defined(__linux__) +#include +#include +#endif #include "nio.h" #include "nio_util.h" @@ -177,10 +181,21 @@ Java_sun_nio_ch_FileDispatcherImpl_truncate0(JNIEnv *env, jobject this, JNIEXPORT jlong JNICALL Java_sun_nio_ch_FileDispatcherImpl_size0(JNIEnv *env, jobject this, jobject fdo) { + jint fd = fdval(env, fdo); struct stat64 fbuf; - if (fstat64(fdval(env, fdo), &fbuf) < 0) + if (fstat64(fd, &fbuf) < 0) return handle(env, -1, "Size failed"); + +#ifdef BLKGETSIZE64 + if (S_ISBLK(fbuf.st_mode)) { + uint64_t size; + if (ioctl(fd, BLKGETSIZE64, &size) < 0) + return handle(env, -1, "Size failed"); + return (jlong)size; + } +#endif + return fbuf.st_size; } diff --git a/jdk/test/java/nio/channels/FileChannel/BlockDeviceSize.java b/jdk/test/java/nio/channels/FileChannel/BlockDeviceSize.java new file mode 100644 index 00000000000..aafe4192d32 --- /dev/null +++ b/jdk/test/java/nio/channels/FileChannel/BlockDeviceSize.java @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* @test + * @bug 8054029 + * @summary Block devices should not report size=0 on Linux + */ + +import java.io.RandomAccessFile; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.nio.channels.FileChannel; +import java.nio.file.AccessDeniedException; +import java.nio.file.NoSuchFileException; +import static java.nio.file.StandardOpenOption.*; + + +public class BlockDeviceSize { + private static final String BLK_FNAME = "/dev/sda1"; + private static final Path BLK_PATH = Paths.get(BLK_FNAME); + + public static void main(String[] args) throws Throwable { + try (FileChannel ch = FileChannel.open(BLK_PATH, READ); + RandomAccessFile file = new RandomAccessFile(BLK_FNAME, "r")) { + + long size1 = ch.size(); + long size2 = file.length(); + if (size1 != size2) { + throw new RuntimeException("size differs when retrieved" + + " in different ways: " + size1 + " != " + size2); + } + System.out.println("OK"); + + } catch (NoSuchFileException nsfe) { + System.err.println("File " + BLK_FNAME + " not found." + + " Skipping test"); + } catch (AccessDeniedException ade) { + System.err.println("Access to " + BLK_FNAME + " is denied." + + " Run test as root."); + } + } +} From c8ca51ee3ccae968adfe8331b28acab2d03ce4d9 Mon Sep 17 00:00:00 2001 From: Lance Andersen Date: Sat, 13 Sep 2014 13:26:18 -0400 Subject: [PATCH 35/81] 8058413: Change formatDecimalInt so it is package private Reviewed-by: darcy --- jdk/src/java.sql/share/classes/java/sql/Date.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/jdk/src/java.sql/share/classes/java/sql/Date.java b/jdk/src/java.sql/share/classes/java/sql/Date.java index 74f90fa45f8..0c425de4148 100644 --- a/jdk/src/java.sql/share/classes/java/sql/Date.java +++ b/jdk/src/java.sql/share/classes/java/sql/Date.java @@ -181,7 +181,7 @@ public class Date extends java.util.Date { * @param offset Starting pos in buf * @param len length of output value */ - protected static void formatDecimalInt(int val, char[] buf, int offset, int len) { + static void formatDecimalInt(int val, char[] buf, int offset, int len) { int charPos = offset + len; do { buf[--charPos] = (char)('0' + (val % 10)); From dd6285d984c38fab027ece1bd19737e0869937c4 Mon Sep 17 00:00:00 2001 From: Tobias Hartmann Date: Mon, 15 Sep 2014 08:08:22 +0200 Subject: [PATCH 36/81] 8048721: -XX:+PrintCompilation prints negative bci for non entrant OSR methods Removed 'InvalidOSREntryBci' and checking nmethod::_state instead to determine if an osr method is non-entrant. Reviewed-by: kvn, vlivanov, drchase --- .../classes/sun/jvm/hotspot/runtime/VM.java | 7 ------- hotspot/src/cpu/ppc/vm/interp_masm_ppc_64.cpp | 6 +++--- hotspot/src/cpu/ppc/vm/templateTable_ppc_64.cpp | 6 +++--- hotspot/src/cpu/sparc/vm/interp_masm_sparc.cpp | 4 ++-- hotspot/src/cpu/sparc/vm/templateTable_sparc.cpp | 4 ++-- hotspot/src/cpu/x86/vm/templateTable_x86_32.cpp | 8 +++----- hotspot/src/cpu/x86/vm/templateTable_x86_64.cpp | 5 ++--- hotspot/src/share/vm/code/nmethod.cpp | 2 -- hotspot/src/share/vm/code/nmethod.hpp | 16 ++++++++-------- .../share/vm/interpreter/bytecodeInterpreter.cpp | 2 +- hotspot/src/share/vm/runtime/vmStructs.cpp | 1 - .../src/share/vm/utilities/globalDefinitions.hpp | 3 +-- 12 files changed, 25 insertions(+), 39 deletions(-) diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/runtime/VM.java b/hotspot/agent/src/share/classes/sun/jvm/hotspot/runtime/VM.java index 29bf9efea7d..caf06eadf76 100644 --- a/hotspot/agent/src/share/classes/sun/jvm/hotspot/runtime/VM.java +++ b/hotspot/agent/src/share/classes/sun/jvm/hotspot/runtime/VM.java @@ -107,7 +107,6 @@ public class VM { private Runtime1 runtime1; /** These constants come from globalDefinitions.hpp */ private int invocationEntryBCI; - private int invalidOSREntryBCI; private ReversePtrs revPtrs; private VMRegImpl vmregImpl; private int reserveForAllocationPrefetch; @@ -295,7 +294,6 @@ public class VM { stackBias = db.lookupIntConstant("STACK_BIAS").intValue(); invocationEntryBCI = db.lookupIntConstant("InvocationEntryBci").intValue(); - invalidOSREntryBCI = db.lookupIntConstant("InvalidOSREntryBci").intValue(); // We infer the presence of C1 or C2 from a couple of fields we // already have present in the type database @@ -733,11 +731,6 @@ public class VM { return invocationEntryBCI; } - /** FIXME: figure out where to stick this */ - public int getInvalidOSREntryBCI() { - return invalidOSREntryBCI; - } - // FIXME: figure out where to stick this public boolean wizardMode() { return true; diff --git a/hotspot/src/cpu/ppc/vm/interp_masm_ppc_64.cpp b/hotspot/src/cpu/ppc/vm/interp_masm_ppc_64.cpp index a47f9f56593..91decd076e7 100644 --- a/hotspot/src/cpu/ppc/vm/interp_masm_ppc_64.cpp +++ b/hotspot/src/cpu/ppc/vm/interp_masm_ppc_64.cpp @@ -1166,9 +1166,9 @@ void InterpreterMacroAssembler::test_backedge_count_for_osr(Register backedge_co beq(CCR0, overflow_with_error); // Has the nmethod been invalidated already? - lwz(Rtmp, nmethod::entry_bci_offset(), R3_RET); - cmpwi(CCR0, Rtmp, InvalidOSREntryBci); - beq(CCR0, overflow_with_error); + lbz(Rtmp, nmethod::state_offset(), R3_RET); + cmpwi(CCR0, Rtmp, nmethod::in_use); + bne(CCR0, overflow_with_error); // Migrate the interpreter frame off of the stack. // We can use all registers because we will not return to interpreter from this point. diff --git a/hotspot/src/cpu/ppc/vm/templateTable_ppc_64.cpp b/hotspot/src/cpu/ppc/vm/templateTable_ppc_64.cpp index 6a34053a496..663c5744095 100644 --- a/hotspot/src/cpu/ppc/vm/templateTable_ppc_64.cpp +++ b/hotspot/src/cpu/ppc/vm/templateTable_ppc_64.cpp @@ -1674,9 +1674,9 @@ void TemplateTable::branch(bool is_jsr, bool is_wide) { __ beq(CCR0, Lforward); // Has the nmethod been invalidated already? - __ lwz(R0, nmethod::entry_bci_offset(), R3_RET); - __ cmpwi(CCR0, R0, InvalidOSREntryBci); - __ beq(CCR0, Lforward); + __ lbz(R0, nmethod::state_offset(), R3_RET); + __ cmpwi(CCR0, R0, nmethod::in_use); + __ bne(CCR0, Lforward); // Migrate the interpreter frame off of the stack. // We can use all registers because we will not return to interpreter from this point. diff --git a/hotspot/src/cpu/sparc/vm/interp_masm_sparc.cpp b/hotspot/src/cpu/sparc/vm/interp_masm_sparc.cpp index 6f2e16c3c66..51f237ba626 100644 --- a/hotspot/src/cpu/sparc/vm/interp_masm_sparc.cpp +++ b/hotspot/src/cpu/sparc/vm/interp_masm_sparc.cpp @@ -2407,8 +2407,8 @@ void InterpreterMacroAssembler::test_backedge_count_for_osr( Register backedge_c br_null_short(O0, Assembler::pn, overflow_with_error); // Has the nmethod been invalidated already? - ld(O0, nmethod::entry_bci_offset(), O2); - cmp_and_br_short(O2, InvalidOSREntryBci, Assembler::equal, Assembler::pn, overflow_with_error); + ldub(O0, nmethod::state_offset(), O2); + cmp_and_br_short(O2, nmethod::in_use, Assembler::notEqual, Assembler::pn, overflow_with_error); // migrate the interpreter frame off of the stack diff --git a/hotspot/src/cpu/sparc/vm/templateTable_sparc.cpp b/hotspot/src/cpu/sparc/vm/templateTable_sparc.cpp index f85864df878..cd40653a2fb 100644 --- a/hotspot/src/cpu/sparc/vm/templateTable_sparc.cpp +++ b/hotspot/src/cpu/sparc/vm/templateTable_sparc.cpp @@ -1636,8 +1636,8 @@ void TemplateTable::branch(bool is_jsr, bool is_wide) { __ br_null_short(O0, Assembler::pn, Lforward); // Has the nmethod been invalidated already? - __ ld(O0, nmethod::entry_bci_offset(), O2); - __ cmp_and_br_short(O2, InvalidOSREntryBci, Assembler::equal, Assembler::pn, Lforward); + __ ldub(O0, nmethod::state_offset(), O2); + __ cmp_and_br_short(O2, nmethod::in_use, Assembler::notEqual, Assembler::pn, Lforward); // migrate the interpreter frame off of the stack diff --git a/hotspot/src/cpu/x86/vm/templateTable_x86_32.cpp b/hotspot/src/cpu/x86/vm/templateTable_x86_32.cpp index da56c1449cd..958613081f3 100644 --- a/hotspot/src/cpu/x86/vm/templateTable_x86_32.cpp +++ b/hotspot/src/cpu/x86/vm/templateTable_x86_32.cpp @@ -1724,9 +1724,8 @@ void TemplateTable::branch(bool is_jsr, bool is_wide) { __ testptr(rax, rax); // test result __ jcc(Assembler::zero, dispatch); // no osr if null // nmethod may have been invalidated (VM may block upon call_VM return) - __ movl(rcx, Address(rax, nmethod::entry_bci_offset())); - __ cmpl(rcx, InvalidOSREntryBci); - __ jcc(Assembler::equal, dispatch); + __ cmpb(Address(rax, nmethod::state_offset()), nmethod::in_use); + __ jcc(Assembler::notEqual, dispatch); // We have the address of an on stack replacement routine in rax, // We need to prepare to execute the OSR method. First we must @@ -1734,8 +1733,7 @@ void TemplateTable::branch(bool is_jsr, bool is_wide) { __ mov(rbx, rax); // save the nmethod - const Register thread = rcx; - __ get_thread(thread); + __ get_thread(rcx); call_VM(noreg, CAST_FROM_FN_PTR(address, SharedRuntime::OSR_migration_begin)); // rax, is OSR buffer, move it to expected parameter location __ mov(rcx, rax); diff --git a/hotspot/src/cpu/x86/vm/templateTable_x86_64.cpp b/hotspot/src/cpu/x86/vm/templateTable_x86_64.cpp index 00d2d58cdfb..cd7ee3b65b0 100644 --- a/hotspot/src/cpu/x86/vm/templateTable_x86_64.cpp +++ b/hotspot/src/cpu/x86/vm/templateTable_x86_64.cpp @@ -1751,9 +1751,8 @@ void TemplateTable::branch(bool is_jsr, bool is_wide) { __ testptr(rax, rax); // test result __ jcc(Assembler::zero, dispatch); // no osr if null // nmethod may have been invalidated (VM may block upon call_VM return) - __ movl(rcx, Address(rax, nmethod::entry_bci_offset())); - __ cmpl(rcx, InvalidOSREntryBci); - __ jcc(Assembler::equal, dispatch); + __ cmpb(Address(rax, nmethod::state_offset()), nmethod::in_use); + __ jcc(Assembler::notEqual, dispatch); // We have the address of an on stack replacement routine in eax // We need to prepare to execute the OSR method. First we must diff --git a/hotspot/src/share/vm/code/nmethod.cpp b/hotspot/src/share/vm/code/nmethod.cpp index 3e52e42d411..ce875397f20 100644 --- a/hotspot/src/share/vm/code/nmethod.cpp +++ b/hotspot/src/share/vm/code/nmethod.cpp @@ -1364,8 +1364,6 @@ void nmethod::invalidate_osr_method() { // Remove from list of active nmethods if (method() != NULL) method()->method_holder()->remove_osr_nmethod(this); - // Set entry as invalid - _entry_bci = InvalidOSREntryBci; } void nmethod::log_state_change() const { diff --git a/hotspot/src/share/vm/code/nmethod.hpp b/hotspot/src/share/vm/code/nmethod.hpp index d3ed6ae2143..1791bbfbb6a 100644 --- a/hotspot/src/share/vm/code/nmethod.hpp +++ b/hotspot/src/share/vm/code/nmethod.hpp @@ -202,13 +202,6 @@ class nmethod : public CodeBlob { bool _oops_are_stale; // indicates that it's no longer safe to access oops section #endif - enum { in_use = 0, // executable nmethod - not_entrant = 1, // marked for deoptimization but activations may still exist, - // will be transformed to zombie when all activations are gone - zombie = 2, // no activations exist, nmethod is ready for purge - unloaded = 3 }; // there should be no activations, should not be called, - // will be transformed to zombie immediately - jbyte _scavenge_root_state; #if INCLUDE_RTM_OPT @@ -431,6 +424,13 @@ class nmethod : public CodeBlob { address entry_point() const { return _entry_point; } // normal entry point address verified_entry_point() const { return _verified_entry_point; } // if klass is correct + enum { in_use = 0, // executable nmethod + not_entrant = 1, // marked for deoptimization but activations may still exist, + // will be transformed to zombie when all activations are gone + zombie = 2, // no activations exist, nmethod is ready for purge + unloaded = 3 }; // there should be no activations, should not be called, + // will be transformed to zombie immediately + // flag accessing and manipulation bool is_in_use() const { return _state == in_use; } bool is_alive() const { return _state == in_use || _state == not_entrant; } @@ -759,7 +759,7 @@ public: // support for code generation static int verified_entry_point_offset() { return offset_of(nmethod, _verified_entry_point); } static int osr_entry_point_offset() { return offset_of(nmethod, _osr_entry_point); } - static int entry_bci_offset() { return offset_of(nmethod, _entry_bci); } + static int state_offset() { return offset_of(nmethod, _state); } // RedefineClasses support. Mark metadata in nmethods as on_stack so that // redefine classes doesn't purge it. diff --git a/hotspot/src/share/vm/interpreter/bytecodeInterpreter.cpp b/hotspot/src/share/vm/interpreter/bytecodeInterpreter.cpp index dc2a782ea05..2bf9a20f27d 100644 --- a/hotspot/src/share/vm/interpreter/bytecodeInterpreter.cpp +++ b/hotspot/src/share/vm/interpreter/bytecodeInterpreter.cpp @@ -330,7 +330,7 @@ if (do_OSR) { \ nmethod* osr_nmethod; \ OSR_REQUEST(osr_nmethod, branch_pc); \ - if (osr_nmethod != NULL && osr_nmethod->osr_entry_bci() != InvalidOSREntryBci) { \ + if (osr_nmethod != NULL && osr_nmethod->is_in_use()) { \ intptr_t* buf; \ /* Call OSR migration with last java frame only, no checks. */ \ CALL_VM_NAKED_LJF(buf=SharedRuntime::OSR_migration_begin(THREAD)); \ diff --git a/hotspot/src/share/vm/runtime/vmStructs.cpp b/hotspot/src/share/vm/runtime/vmStructs.cpp index d3ad9bd9b88..c221cd96bf7 100644 --- a/hotspot/src/share/vm/runtime/vmStructs.cpp +++ b/hotspot/src/share/vm/runtime/vmStructs.cpp @@ -2518,7 +2518,6 @@ typedef TwoOopHashtable SymbolTwoOopHashtable; /*********************************************/ \ \ declare_constant(InvocationEntryBci) \ - declare_constant(InvalidOSREntryBci) \ \ /***************/ \ /* OopMapValue */ \ diff --git a/hotspot/src/share/vm/utilities/globalDefinitions.hpp b/hotspot/src/share/vm/utilities/globalDefinitions.hpp index 269853ee674..2bcdbbcb551 100644 --- a/hotspot/src/share/vm/utilities/globalDefinitions.hpp +++ b/hotspot/src/share/vm/utilities/globalDefinitions.hpp @@ -882,8 +882,7 @@ enum JavaThreadState { // Handy constants for deciding which compiler mode to use. enum MethodCompilation { - InvocationEntryBci = -1, // i.e., not a on-stack replacement compilation - InvalidOSREntryBci = -2 + InvocationEntryBci = -1 // i.e., not a on-stack replacement compilation }; // Enumeration to distinguish tiers of compilation From 8c0e33df1782207535f91409f9ecb4e2206584c5 Mon Sep 17 00:00:00 2001 From: Athijegannathan Sundararajan Date: Mon, 15 Sep 2014 15:18:13 +0530 Subject: [PATCH 37/81] 8058422: Users should be able to overwrite "context" and "engine" variables Reviewed-by: lagergren, attila --- .../jdk/nashorn/internal/objects/Global.java | 16 ++++-- nashorn/test/script/basic/JDK-8058422.js | 55 +++++++++++++++++++ .../jdk/nashorn/api/scripting/ScopeTest.java | 54 ++++++++++++++++++ 3 files changed, 119 insertions(+), 6 deletions(-) create mode 100644 nashorn/test/script/basic/JDK-8058422.js diff --git a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/Global.java b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/Global.java index 03a2c9ae700..eb7fd63ae8e 100644 --- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/Global.java +++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/Global.java @@ -439,8 +439,8 @@ public final class Global extends ScriptObject implements Scope { // current ScriptContext to use - can be null. private ScriptContext scontext; - // associated Property object for "context" property. - private jdk.nashorn.internal.runtime.Property scontextProperty; + // current ScriptEngine associated - can be null. + private ScriptEngine engine; /** * Set the current script context @@ -448,7 +448,6 @@ public final class Global extends ScriptObject implements Scope { */ public void setScriptContext(final ScriptContext scontext) { this.scontext = scontext; - scontextProperty.setValue(this, this, scontext, false); } // global constants for this global - they can be replaced with MethodHandle.constant until invalidated @@ -581,6 +580,7 @@ public final class Global extends ScriptObject implements Scope { return; } + this.engine = engine; init(engine); } @@ -917,6 +917,13 @@ public final class Global extends ScriptObject implements Scope { } } + switch (nameStr) { + case "context": + return sctxt; + case "engine": + return global.engine; + } + if (self == UNDEFINED) { // scope access and so throw ReferenceError throw referenceError(global, "not.defined", nameStr); @@ -1789,9 +1796,6 @@ public final class Global extends ScriptObject implements Scope { } if (engine != null) { - final int NOT_ENUMERABLE_NOT_CONFIG = Attribute.NOT_ENUMERABLE | Attribute.NOT_CONFIGURABLE; - scontextProperty = addOwnProperty("context", NOT_ENUMERABLE_NOT_CONFIG, null); - addOwnProperty("engine", NOT_ENUMERABLE_NOT_CONFIG, engine); // default file name addOwnProperty(ScriptEngine.FILENAME, Attribute.NOT_ENUMERABLE, null); // __noSuchProperty__ hook for ScriptContext search of missing variables diff --git a/nashorn/test/script/basic/JDK-8058422.js b/nashorn/test/script/basic/JDK-8058422.js new file mode 100644 index 00000000000..b15c7cfbad3 --- /dev/null +++ b/nashorn/test/script/basic/JDK-8058422.js @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/** + * JDK-8058422: Users should be able to overwrite "context" and "engine" variables + * + * @test + * @run + */ + +var m = new javax.script.ScriptEngineManager(); +var e = m.getEngineByName("nashorn"); +e.put("foo", "hello"); +var obj = e.eval("context.getAttribute('foo')"); +if (obj != "hello") { + fail("Expected 'obj' to be 'hello'"); +} + +e.put("context", "bar"); +if (e.eval("context") != "bar") { + fail("Expected 'context' to be 'bar'"); +} + +if (e.eval("foo") != "hello") { + fail("Expected 'foo' to be 'hello'"); +} + +if (e.eval("engine") != e) { + fail("'engine' is not evaluaed to current engine"); +} + +e.put("engine", "foobar"); +if (e.eval("engine") != "foobar") { + fail("'engine' is not evalued to 'foobar'"); +} diff --git a/nashorn/test/src/jdk/nashorn/api/scripting/ScopeTest.java b/nashorn/test/src/jdk/nashorn/api/scripting/ScopeTest.java index 865c97d6fdf..3e2a6b6e8d4 100644 --- a/nashorn/test/src/jdk/nashorn/api/scripting/ScopeTest.java +++ b/nashorn/test/src/jdk/nashorn/api/scripting/ScopeTest.java @@ -582,6 +582,60 @@ public class ScopeTest { assertEquals(e.eval("x", newCtxt), 2); } + // @bug 8058422: Users should be able to overwrite "context" and "engine" variables + @Test + public static void contextOverwriteTest() throws ScriptException { + final ScriptEngineManager m = new ScriptEngineManager(); + final ScriptEngine e = m.getEngineByName("nashorn"); + final Bindings b = new SimpleBindings(); + b.put("context", "hello"); + b.put("foo", 32); + final ScriptContext newCtxt = new SimpleScriptContext(); + newCtxt.setBindings(b, ScriptContext.ENGINE_SCOPE); + e.setContext(newCtxt); + assertEquals(e.eval("context"), "hello"); + assertEquals(((Number)e.eval("foo")).intValue(), 32); + } + + // @bug 8058422: Users should be able to overwrite "context" and "engine" variables + @Test + public static void contextOverwriteInScriptTest() throws ScriptException { + final ScriptEngineManager m = new ScriptEngineManager(); + final ScriptEngine e = m.getEngineByName("nashorn"); + e.put("foo", 32); + + assertEquals(((Number)e.eval("foo")).intValue(), 32); + assertEquals(e.eval("context = 'bar'"), "bar"); + assertEquals(((Number)e.eval("foo")).intValue(), 32); + } + + // @bug 8058422: Users should be able to overwrite "context" and "engine" variables + @Test + public static void engineOverwriteTest() throws ScriptException { + final ScriptEngineManager m = new ScriptEngineManager(); + final ScriptEngine e = m.getEngineByName("nashorn"); + final Bindings b = new SimpleBindings(); + b.put("engine", "hello"); + b.put("foo", 32); + final ScriptContext newCtxt = new SimpleScriptContext(); + newCtxt.setBindings(b, ScriptContext.ENGINE_SCOPE); + e.setContext(newCtxt); + assertEquals(e.eval("engine"), "hello"); + assertEquals(((Number)e.eval("foo")).intValue(), 32); + } + + // @bug 8058422: Users should be able to overwrite "context" and "engine" variables + @Test + public static void engineOverwriteInScriptTest() throws ScriptException { + final ScriptEngineManager m = new ScriptEngineManager(); + final ScriptEngine e = m.getEngineByName("nashorn"); + e.put("foo", 32); + + assertEquals(((Number)e.eval("foo")).intValue(), 32); + assertEquals(e.eval("engine = 'bar'"), "bar"); + assertEquals(((Number)e.eval("foo")).intValue(), 32); + } + // @bug 8044750: megamorphic getter for scope objects does not call __noSuchProperty__ hook @Test public static void testMegamorphicGetInGlobal() throws Exception { From ae97aeb0d98f734b9fe2babdad191bcadcf5608d Mon Sep 17 00:00:00 2001 From: Maurizio Cimadamore Date: Mon, 15 Sep 2014 12:43:35 +0100 Subject: [PATCH 38/81] 8055963: Inference failure with nested invocation Revise heuristics to force eager instantiation of return inference vars Reviewed-by: vromero --- .../com/sun/tools/javac/comp/Infer.java | 8 ++-- .../generics/inference/8055963/T8055963.java | 41 +++++++++++++++++++ 2 files changed, 44 insertions(+), 5 deletions(-) create mode 100644 langtools/test/tools/javac/generics/inference/8055963/T8055963.java diff --git a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Infer.java b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Infer.java index d6557065f17..d51e147d523 100644 --- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Infer.java +++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Infer.java @@ -358,11 +358,9 @@ public class Infer { for (Type aLowerBound : from.getBounds(InferenceBound.LOWER)) { for (Type anotherLowerBound : from.getBounds(InferenceBound.LOWER)) { if (aLowerBound != anotherLowerBound && - commonSuperWithDiffParameterization(aLowerBound, anotherLowerBound)) { - /* self comment check if any lower bound may be and undetVar, - * in that case the result of this call may be a false positive. - * Should this be restricted to non free types? - */ + !inferenceContext.free(aLowerBound) && + !inferenceContext.free(anotherLowerBound) && + commonSuperWithDiffParameterization(aLowerBound, anotherLowerBound)) { return generateReferenceToTargetConstraint(tree, from, to, resultInfo, inferenceContext); } diff --git a/langtools/test/tools/javac/generics/inference/8055963/T8055963.java b/langtools/test/tools/javac/generics/inference/8055963/T8055963.java new file mode 100644 index 00000000000..82f00275b8d --- /dev/null +++ b/langtools/test/tools/javac/generics/inference/8055963/T8055963.java @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/** + * @test + * @bug 8055963 + * @summary Inference failure with nested invocation + * @compile T8055963.java + */ +class T8055963 { + + static class C {} + + T choose(T first, T second) { return null; } + + void test() { + C cs = choose(new C(), new C<>()); + } +} From 2f0bf4e52160282a5ab0c6a1875bb3c17e454950 Mon Sep 17 00:00:00 2001 From: Erik Helin Date: Mon, 15 Sep 2014 16:30:08 +0200 Subject: [PATCH 39/81] 8058317: Top-level Makefiles uses deprecated target jvmg in HotSpot Makefiles Reviewed-by: erikj, tbell --- common/autoconf/generated-configure.sh | 4 ++-- common/autoconf/jdk-options.m4 | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/common/autoconf/generated-configure.sh b/common/autoconf/generated-configure.sh index 8ceccb58d54..394b8f02e4d 100644 --- a/common/autoconf/generated-configure.sh +++ b/common/autoconf/generated-configure.sh @@ -4327,7 +4327,7 @@ TOOLCHAIN_DESCRIPTION_xlc="IBM XL C/C++" #CUSTOM_AUTOCONF_INCLUDE # Do not change or remove the following line, it is needed for consistency checks: -DATE_WHEN_GENERATED=1410377275 +DATE_WHEN_GENERATED=1410791401 ############################################################################### # @@ -14642,7 +14642,7 @@ $as_echo "$DEBUG_LEVEL" >&6; } FASTDEBUG="false" DEBUG_CLASSFILES="true" BUILD_VARIANT_RELEASE="-debug" - HOTSPOT_DEBUG_LEVEL="jvmg" + HOTSPOT_DEBUG_LEVEL="debug" HOTSPOT_EXPORT="debug" ;; optimized ) diff --git a/common/autoconf/jdk-options.m4 b/common/autoconf/jdk-options.m4 index f3dca31575d..204ba87636a 100644 --- a/common/autoconf/jdk-options.m4 +++ b/common/autoconf/jdk-options.m4 @@ -234,7 +234,7 @@ AC_DEFUN_ONCE([JDKOPT_SETUP_DEBUG_LEVEL], FASTDEBUG="false" DEBUG_CLASSFILES="true" BUILD_VARIANT_RELEASE="-debug" - HOTSPOT_DEBUG_LEVEL="jvmg" + HOTSPOT_DEBUG_LEVEL="debug" HOTSPOT_EXPORT="debug" ;; optimized ) From 9352e3ed5534b757e9a79931ddd8035ceb0ef0fd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hannes=20Walln=C3=B6fer?= Date: Mon, 15 Sep 2014 17:51:11 +0200 Subject: [PATCH 40/81] 8056978: ClassCastException: cannot cast jdk.nashorn.internal.scripts.JO* Reviewed-by: jlaskey, sundar --- .../internal/codegen/FieldObjectCreator.java | 2 +- .../nashorn/internal/runtime/PropertyMap.java | 4 +- nashorn/test/script/basic/JDK-8056978.js | 46 +++++++++++++++++++ .../test/script/basic/JDK-8056978.js.EXPECTED | 2 + 4 files changed, 50 insertions(+), 4 deletions(-) create mode 100644 nashorn/test/script/basic/JDK-8056978.js create mode 100644 nashorn/test/script/basic/JDK-8056978.js.EXPECTED diff --git a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/FieldObjectCreator.java b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/FieldObjectCreator.java index 774a0be6878..491af86f63f 100644 --- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/FieldObjectCreator.java +++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/FieldObjectCreator.java @@ -231,7 +231,7 @@ public abstract class FieldObjectCreator extends ObjectCreator { if (symbol != null) { if (hasArguments() && symbol.isParam()) { symbol.setFieldIndex(paramCount++); - } else { + } else if (!isValidArrayIndex(getArrayIndex(tuple.key))) { symbol.setFieldIndex(fieldCount++); } } diff --git a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/PropertyMap.java b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/PropertyMap.java index 0246b53108e..d8e76082996 100644 --- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/PropertyMap.java +++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/PropertyMap.java @@ -568,9 +568,7 @@ public final class PropertyMap implements Iterable, Serializable { for (final Property property : otherProperties) { // This method is only safe to use with non-slotted, native getter/setter properties assert property.getSlot() == -1; - if (isValidArrayIndex(getArrayIndex(property.getKey()))) { - newMap.setContainsArrayKeys(); - } + assert !(isValidArrayIndex(getArrayIndex(property.getKey()))); } return newMap; diff --git a/nashorn/test/script/basic/JDK-8056978.js b/nashorn/test/script/basic/JDK-8056978.js new file mode 100644 index 00000000000..1b3577d4c90 --- /dev/null +++ b/nashorn/test/script/basic/JDK-8056978.js @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/** + * JDK-8056978: ClassCastException: cannot cast jdk.nashorn.internal.scripts.JO* + * + * @test + * @run + */ + +var obj1 = { + 'name': 'test name', + '1': '1', + '2': '2', + '3': '3', + '4': '4', + '5': '5' +}; + +var obj2 = { + 'name': 'hello' +}; + +print(obj2['name']); +print(obj2.name); + diff --git a/nashorn/test/script/basic/JDK-8056978.js.EXPECTED b/nashorn/test/script/basic/JDK-8056978.js.EXPECTED new file mode 100644 index 00000000000..317e9677c3b --- /dev/null +++ b/nashorn/test/script/basic/JDK-8056978.js.EXPECTED @@ -0,0 +1,2 @@ +hello +hello From f5de6e94601f47836eed45e3977c22790ed6b199 Mon Sep 17 00:00:00 2001 From: Robert Gibson Date: Mon, 15 Sep 2014 13:05:04 -0700 Subject: [PATCH 41/81] 8057793: BigDecimal is no longer effectively immutable Modify MutableBigInteger.divideAndRemainderBurnikelZiegler() to copy the instance (this) to a new MutableBigInteger to use as the dividend. Reviewed-by: darcy --- .../classes/java/math/MutableBigInteger.java | 17 +++++++++-------- .../java/math/BigDecimal/ZeroScalingTests.java | 17 +++++++++++++++-- 2 files changed, 24 insertions(+), 10 deletions(-) diff --git a/jdk/src/java.base/share/classes/java/math/MutableBigInteger.java b/jdk/src/java.base/share/classes/java/math/MutableBigInteger.java index 5bb5c37d9d7..00e95aad8ec 100644 --- a/jdk/src/java.base/share/classes/java/math/MutableBigInteger.java +++ b/jdk/src/java.base/share/classes/java/math/MutableBigInteger.java @@ -1261,19 +1261,20 @@ class MutableBigInteger { int sigma = (int) Math.max(0, n32 - b.bitLength()); // step 3: sigma = max{T | (2^T)*B < beta^n} MutableBigInteger bShifted = new MutableBigInteger(b); bShifted.safeLeftShift(sigma); // step 4a: shift b so its length is a multiple of n - safeLeftShift(sigma); // step 4b: shift this by the same amount + MutableBigInteger aShifted = new MutableBigInteger (this); + aShifted.safeLeftShift(sigma); // step 4b: shift a by the same amount - // step 5: t is the number of blocks needed to accommodate this plus one additional bit - int t = (int) ((bitLength()+n32) / n32); + // step 5: t is the number of blocks needed to accommodate a plus one additional bit + int t = (int) ((aShifted.bitLength()+n32) / n32); if (t < 2) { t = 2; } - // step 6: conceptually split this into blocks a[t-1], ..., a[0] - MutableBigInteger a1 = getBlock(t-1, t, n); // the most significant block of this + // step 6: conceptually split a into blocks a[t-1], ..., a[0] + MutableBigInteger a1 = aShifted.getBlock(t-1, t, n); // the most significant block of a // step 7: z[t-2] = [a[t-1], a[t-2]] - MutableBigInteger z = getBlock(t-2, t, n); // the second to most significant block + MutableBigInteger z = aShifted.getBlock(t-2, t, n); // the second to most significant block z.addDisjoint(a1, n); // z[t-2] // do schoolbook division on blocks, dividing 2-block numbers by 1-block numbers @@ -1284,7 +1285,7 @@ class MutableBigInteger { ri = z.divide2n1n(bShifted, qi); // step 8b: z = [ri, a[i-1]] - z = getBlock(i-1, t, n); // a[i-1] + z = aShifted.getBlock(i-1, t, n); // a[i-1] z.addDisjoint(ri, n); quotient.addShifted(qi, i*n); // update q (part of step 9) } @@ -1292,7 +1293,7 @@ class MutableBigInteger { ri = z.divide2n1n(bShifted, qi); quotient.add(qi); - ri.rightShift(sigma); // step 9: this and b were shifted, so shift back + ri.rightShift(sigma); // step 9: a and b were shifted, so shift back return ri; } } diff --git a/jdk/test/java/math/BigDecimal/ZeroScalingTests.java b/jdk/test/java/math/BigDecimal/ZeroScalingTests.java index 3ebd47a1ef5..05a59150b13 100644 --- a/jdk/test/java/math/BigDecimal/ZeroScalingTests.java +++ b/jdk/test/java/math/BigDecimal/ZeroScalingTests.java @@ -23,8 +23,10 @@ /* * @test - * @bug 4902952 4905407 4916149 - * @summary Tests that the scale of zero is propagated properly and has the proper effect. + * @bug 4902952 4905407 4916149 8057793 + * @summary Tests that the scale of zero is propagated properly and has the + * proper effect and that setting the scale to zero does not mutate the + * BigDecimal. * @author Joseph D. Darcy */ @@ -445,6 +447,16 @@ public class ZeroScalingTests { return failures; } + static int setScaleDoesNotMutateTest() { + BigDecimal total = new BigDecimal("258815507198903607775511093103396443816569106750031264155319238473795838680758514810110764742309284477206138527975952150289602995045050194333030191178778772026538699925775139201970526695485362661420908248887297829319881475178467494779683293036572059595504702727301324759997409522995072582369210284334718757260859794972695026582432867589093687280300148141501712013226636373167978223780290547640482160818746599330924736802844173226042389174403401903999447463440670236056324929325189403433689" + + ".426167432065785331444814035799717606745777287606858873045971898862329763544687891847664736523584843544347118836628373041412918374550458884706686730726101338872517021688769782894793734049819222924171842793485919753186993388451909096042127903835765393729547730953942175461146061715108701615615142134282261293656760570061554783195726716403304101469782303957325142638493327692352838806741611887655695029948975509680496573999174402058593454203190963443179532640446352828089016874853634851387762579319853267317320515941105912189838719919259277721994880193541634872882180184303434360412344059435559680494807415573269199203376126242271766939666939316648575065702750502798973418978204972336924254702551350654650573582614211506856383897692911422458286912085339575875324832979140870119455620532272318122103640233069115700020760625493816902806241630788230268031695140687964931377988962507263990468276009750998066442971308866347136022907166625330623130307555914930120150437900510530537258665172619821272937026713977709974434967165159545592482710663639966781678268622620229577009317698254134914742098420792313931843709810905414336383757407675429663714210967924767434203021205270369316797752411974617662200898086335322218191674846795163102021505555508444216708745911194321674887527227200297039471799580744303346354057273540730643842091810899490590914195225087593013834388801018488174855060306804024894292757613618190472234110859436472645203753139820658279559340251226992556744343475086923568365637919479462424794554522865559888240039662899509652221329892034706445253487898044421278283079233226845124525434586324657471286953226255430662125870993375281512713207125720748163498642795960457639954616530163959004770092547297392499137383176609646505351001304840762905826237024982330597805063521162285806541220110524989649256399233792799406995068469271941269511818994954109392839548141262324660472253632382325038836831429045617036015122388070240133760858500132713255407855625837956886349324981003917084922808187223285051144454915441134217743066575863563572152133978905444998209075763950909784148142018992367290485890072303179512881131769414783097454103103347826517701720263541869335631166977965013552647906729408522950996105479525445916501155305220090853891226367184989434453290788068397817927893708837722255115237672194162924260945492012622891770365546831236789867922136747819364833843397165107825773447549885351449899330007200651144003961228091210630807333236718793283427788965479074476288255387824982443633190938302785760754436525586544523339170400053128503337395428393881357669568532722167493096151221381017320147344991331421789379785964440840684363041795410525097564979585773948558651896834067324427900848255265001498890329859444233861478388742393060996236783742654761350763876989363052609107226398858310051497856931093693697981165801539060516895227818925342535261227134364063673285588256280386915163875872231395348293505967057794409379709079685798908660258077792158532257603211711587587586356431658240229896344639704"); + if (total.setScale(0, RoundingMode.DOWN).equals(total.setScale(0, RoundingMode.DOWN))) { + return 0; + } else { + return 1; + } + } + public static void main(String argv[]) { int failures = 0; @@ -455,6 +467,7 @@ public class ZeroScalingTests { failures += setScaleTests(); failures += toEngineeringStringTests(); failures += ulpTests(); + failures += setScaleDoesNotMutateTest(); if (failures > 0 ) { throw new RuntimeException("Incurred " + failures + " failures" + From 2aafc0ee9f46d39454f716e85f2343d9e0b3b4b7 Mon Sep 17 00:00:00 2001 From: Claes Redestad Date: Mon, 15 Sep 2014 21:20:46 +0200 Subject: [PATCH 42/81] 8058429: JCK test api/java_sql/Timestamp/descriptions.html start failing after 8058230 Reviewed-by: lancea --- .../share/classes/java/sql/Timestamp.java | 40 +++++++++++------- .../java/sql/test/sql/TimestampTests.java | 41 +++++++++++++++++++ 2 files changed, 67 insertions(+), 14 deletions(-) diff --git a/jdk/src/java.sql/share/classes/java/sql/Timestamp.java b/jdk/src/java.sql/share/classes/java/sql/Timestamp.java index e66831f85b9..dac08f5fe19 100644 --- a/jdk/src/java.sql/share/classes/java/sql/Timestamp.java +++ b/jdk/src/java.sql/share/classes/java/sql/Timestamp.java @@ -284,20 +284,32 @@ public class Timestamp extends java.util.Date { } } - char[] buf = new char[29 - trailingZeros]; - Date.formatDecimalInt(year, buf, 0, 4); - buf[4] = '-'; - Date.formatDecimalInt(month, buf, 5, 2); - buf[7] = '-'; - Date.formatDecimalInt(day, buf, 8, 2); - buf[10] = ' '; - Date.formatDecimalInt(hour, buf, 11, 2); - buf[13] = ':'; - Date.formatDecimalInt(minute, buf, 14, 2); - buf[16] = ':'; - Date.formatDecimalInt(second, buf, 17, 2); - buf[19] = '.'; - Date.formatDecimalInt(tmpNanos, buf, 20, 9 - trailingZeros); + // 8058429: To comply with current JCK tests, we need to deal with year + // being any number between 0 and 292278995 + int count = 10000; + int yearSize = 4; + do { + if (year < count) { + break; + } + yearSize++; + count *= 10; + } while (count < 1000000000); + + char[] buf = new char[25 + yearSize - trailingZeros]; + Date.formatDecimalInt(year, buf, 0, yearSize); + buf[yearSize] = '-'; + Date.formatDecimalInt(month, buf, yearSize + 1, 2); + buf[yearSize + 3] = '-'; + Date.formatDecimalInt(day, buf, yearSize + 4, 2); + buf[yearSize + 6] = ' '; + Date.formatDecimalInt(hour, buf, yearSize + 7, 2); + buf[yearSize + 9] = ':'; + Date.formatDecimalInt(minute, buf, yearSize + 10, 2); + buf[yearSize + 12] = ':'; + Date.formatDecimalInt(second, buf, yearSize + 13, 2); + buf[yearSize + 15] = '.'; + Date.formatDecimalInt(tmpNanos, buf, yearSize + 16, 9 - trailingZeros); return jla.newStringUnsafe(buf); } diff --git a/jdk/test/java/sql/test/sql/TimestampTests.java b/jdk/test/java/sql/test/sql/TimestampTests.java index a555b6ae0b5..da966f54a99 100644 --- a/jdk/test/java/sql/test/sql/TimestampTests.java +++ b/jdk/test/java/sql/test/sql/TimestampTests.java @@ -27,6 +27,7 @@ import java.sql.Time; import java.sql.Timestamp; import java.time.Instant; import java.time.LocalDateTime; +import java.time.ZoneId; import java.util.Calendar; import static org.testng.Assert.*; import org.testng.annotations.DataProvider; @@ -610,6 +611,12 @@ public class TimestampTests extends BaseTest { "Error with Nanos"); } + @Test(dataProvider = "validTimestampLongValues") + public void test52(long value, String ts) { + Timestamp ts1 = new Timestamp(value); + assertEquals(ts1.toString(), ts, "ts1.toString() != ts"); + } + /* * DataProvider used to provide Timestamps which are not valid and are used * to validate that an IllegalArgumentException will be thrown from the @@ -678,6 +685,40 @@ public class TimestampTests extends BaseTest { }; } + @DataProvider(name = "validTimestampLongValues") + private Object[][] validTimestampLongValues() { + return new Object[][]{ + {1L, "1970-01-01 01:00:00.001"}, + {-3600*1000L - 1, "1969-12-31 23:59:59.999"}, + {-(20000L*365*24*60*60*1000), "18018-08-28 01:00:00.0"}, + {Timestamp.valueOf("1961-08-30 11:22:33").getTime(), "1961-08-30 11:22:33.0"}, + {Timestamp.valueOf("1961-08-30 11:22:33.54321000").getTime(), "1961-08-30 11:22:33.543"}, // nanoprecision lost + {new Timestamp(114, 10, 10, 10, 10, 10, 100000000).getTime(), "2014-11-10 10:10:10.1"}, + {new Timestamp(0, 10, 10, 10, 10, 10, 100000).getTime(), "1900-11-10 10:10:10.0"}, // nanoprecision lost + {new Date(114, 10, 10).getTime(), "2014-11-10 00:00:00.0"}, + {new Date(0, 10, 10).getTime(), "1900-11-10 00:00:00.0"}, + {LocalDateTime.of(1960, 10, 10, 10, 10, 10, 50000).atZone(ZoneId.of("America/Los_Angeles")) + .toInstant().toEpochMilli(), "1960-10-10 19:10:10.0"}, + + // millisecond timestamps wraps around at year 1, so Long.MIN_VALUE looks similar + // Long.MAX_VALUE, while actually representing 292278994 BCE + {Long.MIN_VALUE, "292278994-08-17 08:12:55.192"}, + {Long.MAX_VALUE + 1, "292278994-08-17 08:12:55.192"}, + {Long.MAX_VALUE, "292278994-08-17 08:12:55.807"}, + {Long.MIN_VALUE - 1, "292278994-08-17 08:12:55.807"}, + + // wrap around point near 0001-01-01, test that we never get a negative year: + {-(1970L*365*24*60*60*1000), "0001-04-25 01:00:00.0"}, + {-(1970L*365*24*60*60*1000 + 115*24*60*60*1000L), "0001-12-31 01:00:00.0"}, + {-(1970L*365*24*60*60*1000 + 115*24*60*60*1000L - 23*60*60*1000L), "0001-01-01 00:00:00.0"}, + + {LocalDateTime.of(0, 1, 1, 10, 10, 10, 50000).atZone(ZoneId.of("America/Los_Angeles")) + .toInstant().toEpochMilli() - 2*24*60*60*1000L, "0001-01-01 19:03:08.0"}, // 1 BCE + {LocalDateTime.of(0, 1, 1, 10, 10, 10, 50000).atZone(ZoneId.of("America/Los_Angeles")) + .toInstant().toEpochMilli() - 3*24*60*60*1000L, "0002-12-31 19:03:08.0"} // 2 BCE + }; + } + /* * DataProvider used to provide Timestamp and Nanos values in order to * validate that the correct Nanos value is generated from the specified From 2edb29385b7005a345f9873fb5eb9544b95023b0 Mon Sep 17 00:00:00 2001 From: Mandy Chung Date: Mon, 15 Sep 2014 12:23:32 -0700 Subject: [PATCH 43/81] 8058367: Add verify-modules target to the default and images target Reviewed-by: alanb, erikj, ihse, prr --- make/Main.gmk | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/make/Main.gmk b/make/Main.gmk index 230fec4140e..aa87b6ff601 100644 --- a/make/Main.gmk +++ b/make/Main.gmk @@ -298,7 +298,9 @@ ALL_TARGETS += test test-make # Verification targets verify-modules: + @$(call TargetEnter) +($(CD) $(SRC_ROOT)/make && $(MAKE) $(MAKE_ARGS) -f CheckModules.gmk) + @$(call TargetExit) ALL_TARGETS += verify-modules @@ -400,7 +402,7 @@ else main-jars: java.security.jgss-libs endif - images: jars demos samples exploded-image source-tips + images: jars demos samples exploded-image verify-modules source-tips bootcycle-images: images @@ -476,7 +478,7 @@ ALL_TARGETS += gensrc gendata copy java rmic libs launchers \ ################################################################################ -all: images docs verify-modules +all: images docs default: exploded-image ALL_TARGETS += default all From d28777cff80b27bfaee2456b305bff5d833dd011 Mon Sep 17 00:00:00 2001 From: Claes Redestad Date: Tue, 16 Sep 2014 00:26:58 +0200 Subject: [PATCH 44/81] 8058514: TEST_BUG: New tests introduced in 8058429 are TimeZone dependent Reviewed-by: lancea --- .../java/sql/test/sql/TimestampTests.java | 25 +++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/jdk/test/java/sql/test/sql/TimestampTests.java b/jdk/test/java/sql/test/sql/TimestampTests.java index da966f54a99..7766b5a2b4c 100644 --- a/jdk/test/java/sql/test/sql/TimestampTests.java +++ b/jdk/test/java/sql/test/sql/TimestampTests.java @@ -29,13 +29,38 @@ import java.time.Instant; import java.time.LocalDateTime; import java.time.ZoneId; import java.util.Calendar; +import java.util.TimeZone; import static org.testng.Assert.*; +import org.testng.annotations.AfterClass; +import org.testng.annotations.BeforeClass; import org.testng.annotations.DataProvider; import org.testng.annotations.Test; import util.BaseTest; public class TimestampTests extends BaseTest { + private static TimeZone defaultTimeZone = null; + + /* + * Need to set and use a custom TimeZone which does not + * observe daylight savings time for this test. + */ + @BeforeClass + public static void setUpClass() throws Exception { + defaultTimeZone = TimeZone.getDefault(); + TimeZone tzone = TimeZone.getTimeZone("GMT+01"); + assertFalse(tzone.observesDaylightTime()); + TimeZone.setDefault(tzone); + } + + /* + * Conservatively reset the default time zone after test. + */ + @AfterClass + public static void tearDownClass() throws Exception { + TimeZone.setDefault(defaultTimeZone); + } + /* * Validate an IllegalArgumentException is thrown for an invalid Timestamp */ From 797b24f7a011994f5d698f4ff6a94d0c69c8f004 Mon Sep 17 00:00:00 2001 From: Shanliang Jiang Date: Tue, 16 Sep 2014 09:01:57 +0200 Subject: [PATCH 45/81] 8042205: javax/management/monitor/*: some tests didn't get all the notifications Reviewed-by: dfuchs --- jdk/test/ProblemList.txt | 7 --- .../AttributeArbitraryDataTypeTest.java | 57 +++++++++++++++++-- .../monitor/CounterMonitorTest.java | 28 +++------ .../NonComparableAttributeValueTest.java | 38 ++++++++----- .../monitor/ReflectionExceptionTest.java | 38 ++++++++----- .../monitor/RuntimeExceptionTest.java | 38 ++++++++----- 6 files changed, 132 insertions(+), 74 deletions(-) diff --git a/jdk/test/ProblemList.txt b/jdk/test/ProblemList.txt index 7acfaef1e72..9b69db7c116 100644 --- a/jdk/test/ProblemList.txt +++ b/jdk/test/ProblemList.txt @@ -142,13 +142,6 @@ javax/management/MBeanServer/OldMBeanServerTest.java aix-all # 8050115 javax/management/monitor/GaugeMonitorDeadlockTest.java generic-all -# 8042205 8057951 generic-all -javax/management/monitor/CounterMonitorTest.java -javax/management/monitor/NonComparableAttributeValueTest.java -javax/management/monitor/ReflectionExceptionTest.java -javax/management/monitor/RuntimeExceptionTest.java -javax/management/monitor/AttributeArbitraryDataTypeTest.java - ############################################################################ # jdk_math diff --git a/jdk/test/javax/management/monitor/AttributeArbitraryDataTypeTest.java b/jdk/test/javax/management/monitor/AttributeArbitraryDataTypeTest.java index deb43582208..aa386062b27 100644 --- a/jdk/test/javax/management/monitor/AttributeArbitraryDataTypeTest.java +++ b/jdk/test/javax/management/monitor/AttributeArbitraryDataTypeTest.java @@ -58,9 +58,9 @@ import javax.management.openmbean.SimpleType; public class AttributeArbitraryDataTypeTest implements NotificationListener { // Flag to notify that a message has been received - private boolean counterMessageReceived = false; - private boolean gaugeMessageReceived = false; - private boolean stringMessageReceived = false; + private volatile boolean counterMessageReceived = false; + private volatile boolean gaugeMessageReceived = false; + private volatile boolean stringMessageReceived = false; // Match enum public enum Match { do_not_match_0, @@ -195,21 +195,33 @@ public class AttributeArbitraryDataTypeTest implements NotificationListener { " has reached or exceeded the threshold"); echo("\t\tDerived Gauge = " + n.getDerivedGauge()); echo("\t\tTrigger = " + n.getTrigger()); - counterMessageReceived = true; + + synchronized (this) { + counterMessageReceived = true; + notifyAll(); + } } else if (type.equals(MonitorNotification. THRESHOLD_HIGH_VALUE_EXCEEDED)) { echo("\t\t" + n.getObservedAttribute() + " has reached or exceeded the high threshold"); echo("\t\tDerived Gauge = " + n.getDerivedGauge()); echo("\t\tTrigger = " + n.getTrigger()); - gaugeMessageReceived = true; + + synchronized (this) { + gaugeMessageReceived = true; + notifyAll(); + } } else if (type.equals(MonitorNotification. STRING_TO_COMPARE_VALUE_MATCHED)) { echo("\t\t" + n.getObservedAttribute() + " matches the string-to-compare value"); echo("\t\tDerived Gauge = " + n.getDerivedGauge()); echo("\t\tTrigger = " + n.getTrigger()); - stringMessageReceived = true; + + synchronized (this) { + stringMessageReceived = true; + notifyAll(); + } } else { echo("\t\tSkipping notification of type: " + type); } @@ -358,6 +370,17 @@ public class AttributeArbitraryDataTypeTest implements NotificationListener { // Check if notification was received // + synchronized (this) { + while (!counterMessageReceived) { + try { + wait(); + } catch (InterruptedException e) { + System.err.println("Got unexpected exception: " + e); + e.printStackTrace(); + break; + } + } + } if (counterMessageReceived) { echo("\tOK: CounterMonitor notification received"); } else { @@ -525,6 +548,17 @@ public class AttributeArbitraryDataTypeTest implements NotificationListener { // Check if notification was received // + synchronized (this) { + while (!gaugeMessageReceived) { + try { + wait(); + } catch (InterruptedException e) { + System.err.println("Got unexpected exception: " + e); + e.printStackTrace(); + break; + } + } + } if (gaugeMessageReceived) { echo("\tOK: GaugeMonitor notification received"); } else { @@ -680,6 +714,17 @@ public class AttributeArbitraryDataTypeTest implements NotificationListener { // Check if notification was received // + synchronized (this) { + while (!stringMessageReceived) { + try { + wait(); + } catch (InterruptedException e) { + System.err.println("Got unexpected exception: " + e); + e.printStackTrace(); + break; + } + } + } if (stringMessageReceived) { echo("\tOK: StringMonitor notification received"); } else { diff --git a/jdk/test/javax/management/monitor/CounterMonitorTest.java b/jdk/test/javax/management/monitor/CounterMonitorTest.java index bf134c6cb99..6c4ea1022e3 100644 --- a/jdk/test/javax/management/monitor/CounterMonitorTest.java +++ b/jdk/test/javax/management/monitor/CounterMonitorTest.java @@ -43,9 +43,6 @@ public class CounterMonitorTest implements NotificationListener { // modulus number private Number modulus = new Integer(7); - // offset number - private int offset = 0; - // difference mode flag private boolean differenceModeFlag = true; @@ -58,9 +55,6 @@ public class CounterMonitorTest implements NotificationListener { // counter values private int[] values = new int[] {4, 6, 9, 11}; - // time to wait for notification (in seconds) - private int timeout = 5; - // flag to notify that a message has been received private volatile boolean messageReceived = false; @@ -92,8 +86,9 @@ public class CounterMonitorTest implements NotificationListener { echo("\t\t" + n.getObservedAttribute() + " has reached or exceeded the threshold"); echo("\t\tDerived Gauge = " + n.getDerivedGauge()); - messageReceived = true; + synchronized (this) { + messageReceived = true; notifyAll(); } } else { @@ -205,21 +200,16 @@ public class CounterMonitorTest implements NotificationListener { } /* - * Wait until timeout reached + * Wait messageReceived to be true */ - void doWait() { - for (int i = 0; i < timeout; i++) { - echo("\tdoWait: Waiting for " + timeout + " seconds. " + - "i = " + i + ", messageReceived = " + messageReceived); - if (messageReceived) { - break; - } + synchronized void doWait() { + while (!messageReceived) { try { - synchronized (this) { - wait(1000); - } + wait(); } catch (InterruptedException e) { - // OK: Ignore... + System.err.println("Got unexpected exception: " + e); + e.printStackTrace(); + break; } } } diff --git a/jdk/test/javax/management/monitor/NonComparableAttributeValueTest.java b/jdk/test/javax/management/monitor/NonComparableAttributeValueTest.java index c9c153a4959..c382ec8cac5 100644 --- a/jdk/test/javax/management/monitor/NonComparableAttributeValueTest.java +++ b/jdk/test/javax/management/monitor/NonComparableAttributeValueTest.java @@ -39,7 +39,7 @@ import javax.management.monitor.*; public class NonComparableAttributeValueTest implements NotificationListener { // Flag to notify that a message has been received - private boolean messageReceived = false; + private volatile boolean messageReceived = false; // MBean class public class ObservedObject implements ObservedObjectMBean { @@ -69,7 +69,11 @@ public class NonComparableAttributeValueTest implements NotificationListener { echo("\t\t" + n.getObservedAttribute() + " is null"); echo("\t\tDerived Gauge = " + n.getDerivedGauge()); echo("\t\tTrigger = " + n.getTrigger()); - messageReceived = true; + + synchronized (this) { + messageReceived = true; + notifyAll(); + } } else { echo("\t\tSkipping notification of type: " + type); } @@ -134,12 +138,9 @@ public class NonComparableAttributeValueTest implements NotificationListener { echo(">>> START the CounterMonitor"); counterMonitor.start(); - // Wait for granularity period (multiplied by 2 for sure) - // - Thread.sleep(granularityperiod * 2); - // Check if notification was received // + doWait(); if (messageReceived) { echo("\tOK: CounterMonitor notification received"); } else { @@ -212,12 +213,9 @@ public class NonComparableAttributeValueTest implements NotificationListener { echo(">>> START the GaugeMonitor"); gaugeMonitor.start(); - // Wait for granularity period (multiplied by 2 for sure) - // - Thread.sleep(granularityperiod * 2); - // Check if notification was received // + doWait(); if (messageReceived) { echo("\tOK: GaugeMonitor notification received"); } else { @@ -289,12 +287,9 @@ public class NonComparableAttributeValueTest implements NotificationListener { echo(">>> START the StringMonitor"); stringMonitor.start(); - // Wait for granularity period (multiplied by 2 for sure) - // - Thread.sleep(granularityperiod * 2); - // Check if notification was received // + doWait(); if (messageReceived) { echo("\tOK: StringMonitor notification received"); } else { @@ -333,6 +328,21 @@ public class NonComparableAttributeValueTest implements NotificationListener { System.out.println(message); } + /* + * Wait messageReceived to be true + */ + synchronized void doWait() { + while (!messageReceived) { + try { + wait(); + } catch (InterruptedException e) { + System.err.println("Got unexpected exception: " + e); + e.printStackTrace(); + break; + } + } + } + /* * Standalone entry point. * diff --git a/jdk/test/javax/management/monitor/ReflectionExceptionTest.java b/jdk/test/javax/management/monitor/ReflectionExceptionTest.java index db13caff5b6..d4acde3a928 100644 --- a/jdk/test/javax/management/monitor/ReflectionExceptionTest.java +++ b/jdk/test/javax/management/monitor/ReflectionExceptionTest.java @@ -87,7 +87,11 @@ public class ReflectionExceptionTest implements NotificationListener { echo("\tObservedAttribute: " + mn.getObservedAttribute()); echo("\tDerivedGauge: " + mn.getDerivedGauge()); echo("\tTrigger: " + mn.getTrigger()); - messageReceived = true; + + synchronized (this) { + messageReceived = true; + notifyAll(); + } } } } @@ -135,12 +139,9 @@ public class ReflectionExceptionTest implements NotificationListener { echo(">>> START the CounterMonitor"); counterMonitor.start(); - // Wait for granularity period (multiplied by 2 for sure) - // - Thread.sleep(granularityperiod * 2); - // Check if notification was received // + doWait(); if (messageReceived) { echo("\tOK: CounterMonitor got RUNTIME_ERROR notification!"); } else { @@ -203,12 +204,9 @@ public class ReflectionExceptionTest implements NotificationListener { echo(">>> START the GaugeMonitor"); gaugeMonitor.start(); - // Wait for granularity period (multiplied by 2 for sure) - // - Thread.sleep(granularityperiod * 2); - // Check if notification was received // + doWait(); if (messageReceived) { echo("\tOK: GaugeMonitor got RUNTIME_ERROR notification!"); } else { @@ -270,12 +268,9 @@ public class ReflectionExceptionTest implements NotificationListener { echo(">>> START the StringMonitor"); stringMonitor.start(); - // Wait for granularity period (multiplied by 2 for sure) - // - Thread.sleep(granularityperiod * 2); - // Check if notification was received // + doWait(); if (messageReceived) { echo("\tOK: StringMonitor got RUNTIME_ERROR notification!"); } else { @@ -349,8 +344,23 @@ public class ReflectionExceptionTest implements NotificationListener { } } + /* + * Wait messageReceived to be true + */ + synchronized void doWait() { + while (!messageReceived) { + try { + wait(); + } catch (InterruptedException e) { + System.err.println("Got unexpected exception: " + e); + e.printStackTrace(); + break; + } + } + } + // Flag to notify that a message has been received - private boolean messageReceived = false; + private volatile boolean messageReceived = false; private MBeanServer server; private ObjectName obsObjName; diff --git a/jdk/test/javax/management/monitor/RuntimeExceptionTest.java b/jdk/test/javax/management/monitor/RuntimeExceptionTest.java index a10322a141a..53ee24db702 100644 --- a/jdk/test/javax/management/monitor/RuntimeExceptionTest.java +++ b/jdk/test/javax/management/monitor/RuntimeExceptionTest.java @@ -86,7 +86,11 @@ public class RuntimeExceptionTest implements NotificationListener { echo("\tObservedAttribute: " + mn.getObservedAttribute()); echo("\tDerivedGauge: " + mn.getDerivedGauge()); echo("\tTrigger: " + mn.getTrigger()); - messageReceived = true; + + synchronized (this) { + messageReceived = true; + notifyAll(); + } } } } @@ -134,12 +138,9 @@ public class RuntimeExceptionTest implements NotificationListener { echo(">>> START the CounterMonitor"); counterMonitor.start(); - // Wait for granularity period (multiplied by 2 for sure) - // - Thread.sleep(granularityperiod * 2); - // Check if notification was received // + doWait(); if (messageReceived) { echo("\tOK: CounterMonitor got RUNTIME_ERROR notification!"); } else { @@ -202,12 +203,9 @@ public class RuntimeExceptionTest implements NotificationListener { echo(">>> START the GaugeMonitor"); gaugeMonitor.start(); - // Wait for granularity period (multiplied by 2 for sure) - // - Thread.sleep(granularityperiod * 2); - // Check if notification was received // + doWait(); if (messageReceived) { echo("\tOK: GaugeMonitor got RUNTIME_ERROR notification!"); } else { @@ -269,12 +267,9 @@ public class RuntimeExceptionTest implements NotificationListener { echo(">>> START the StringMonitor"); stringMonitor.start(); - // Wait for granularity period (multiplied by 2 for sure) - // - Thread.sleep(granularityperiod * 2); - // Check if notification was received // + doWait(); if (messageReceived) { echo("\tOK: StringMonitor got RUNTIME_ERROR notification!"); } else { @@ -347,8 +342,23 @@ public class RuntimeExceptionTest implements NotificationListener { } } + /* + * Wait messageReceived to be true + */ + synchronized void doWait() { + while (!messageReceived) { + try { + wait(); + } catch (InterruptedException e) { + System.err.println("Got unexpected exception: " + e); + e.printStackTrace(); + break; + } + } + } + // Flag to notify that a message has been received - private boolean messageReceived = false; + private volatile boolean messageReceived = false; private MBeanServer server; private ObjectName obsObjName; From 375020d61a07d4b2dfb24d8b2f6f9f5eb1a657eb Mon Sep 17 00:00:00 2001 From: Chris Hegarty Date: Tue, 16 Sep 2014 12:06:53 +0200 Subject: [PATCH 46/81] 8058118: Generate modules.list during the build Reviewed-by: alanb, mchung --- .../tools/module/GenJdepsModulesXml.java | 389 +----------------- .../build/tools/module/GenModulesList.java | 159 +++++++ .../classes/build/tools/module/Module.java | 178 ++++++++ .../build/tools/module/ModulesXmlReader.java | 165 ++++++++ .../build/tools/module/ModulesXmlWriter.java | 179 ++++++++ 5 files changed, 698 insertions(+), 372 deletions(-) create mode 100644 jdk/make/src/classes/build/tools/module/GenModulesList.java create mode 100644 jdk/make/src/classes/build/tools/module/Module.java create mode 100644 jdk/make/src/classes/build/tools/module/ModulesXmlReader.java create mode 100644 jdk/make/src/classes/build/tools/module/ModulesXmlWriter.java diff --git a/jdk/make/src/classes/build/tools/module/GenJdepsModulesXml.java b/jdk/make/src/classes/build/tools/module/GenJdepsModulesXml.java index 43ba458f326..17a63e79546 100644 --- a/jdk/make/src/classes/build/tools/module/GenJdepsModulesXml.java +++ b/jdk/make/src/classes/build/tools/module/GenJdepsModulesXml.java @@ -25,29 +25,17 @@ package build.tools.module; -import java.io.BufferedInputStream; import java.io.File; import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; +import java.io.UncheckedIOException; import java.nio.file.Files; import java.nio.file.NoSuchFileException; import java.nio.file.Path; import java.nio.file.Paths; import java.nio.file.attribute.BasicFileAttributes; -import java.util.Collections; -import java.util.Comparator; -import java.util.HashMap; import java.util.HashSet; -import java.util.Map; -import java.util.Objects; import java.util.Set; -import java.util.jar.JarEntry; -import java.util.jar.JarFile; -import javax.xml.namespace.QName; -import javax.xml.stream.*; -import javax.xml.stream.events.Attribute; -import javax.xml.stream.events.XMLEvent; +import java.util.stream.Collectors; /** * GenJdepsModulesXml augments the input modules.xml file(s) @@ -97,14 +85,14 @@ public final class GenJdepsModulesXml { Set modules = new HashSet<>(); for (; i < args.length; i++) { Path p = Paths.get(args[i]); - try (InputStream in = new BufferedInputStream(Files.newInputStream(p))) { - Set mods = gentool.load(in); - modules.addAll(mods); - } + modules.addAll(ModulesXmlReader.readModules(p) + .stream() + .map(gentool::buildIncludes) + .collect(Collectors.toSet())); } Files.createDirectories(outfile.getParent()); - gentool.writeXML(modules, outfile); + ModulesXmlWriter.writeModules(modules, outfile); } final Path modulepath; @@ -112,228 +100,21 @@ public final class GenJdepsModulesXml { this.modulepath = modulepath; } - private static final String MODULES = "modules"; - private static final String MODULE = "module"; - private static final String NAME = "name"; - private static final String DEPEND = "depend"; - private static final String EXPORT = "export"; - private static final String TO = "to"; - private static final String INCLUDE = "include"; - private static final QName REEXPORTS = new QName("re-exports"); - private Set load(InputStream in) throws XMLStreamException, IOException { - Set modules = new HashSet<>(); - XMLInputFactory factory = XMLInputFactory.newInstance(); - XMLEventReader stream = factory.createXMLEventReader(in); - Module.Builder mb = null; - String modulename = null; - String pkg = null; - Set permits = new HashSet<>(); - while (stream.hasNext()) { - XMLEvent event = stream.nextEvent(); - if (event.isStartElement()) { - String startTag = event.asStartElement().getName().getLocalPart(); - switch (startTag) { - case MODULES: - break; - case MODULE: - if (mb != null) { - throw new RuntimeException("end tag for module is missing"); - } - modulename = getNextTag(stream, NAME); - mb = new Module.Builder(); - mb.name(modulename); - break; - case NAME: - throw new RuntimeException(event.toString()); - case DEPEND: - boolean reexports = false; - Attribute attr = event.asStartElement().getAttributeByName(REEXPORTS); - if (attr != null) { - String value = attr.getValue(); - if (value.equals("true") || value.equals("false")) { - reexports = Boolean.parseBoolean(value); - } else { - throw new RuntimeException("unexpected attribute " + attr.toString()); - } - } - mb.require(getData(stream), reexports); - break; - case INCLUDE: - throw new RuntimeException("unexpected " + event); - case EXPORT: - pkg = getNextTag(stream, NAME); - break; - case TO: - permits.add(getData(stream)); - break; - default: - } - } else if (event.isEndElement()) { - String endTag = event.asEndElement().getName().getLocalPart(); - switch (endTag) { - case MODULE: - buildIncludes(mb, modulename); - modules.add(mb.build()); - mb = null; - break; - case EXPORT: - if (pkg == null) { - throw new RuntimeException("export-to is malformed"); - } - mb.exportTo(pkg, permits); - pkg = null; - permits.clear(); - break; - default: - } - } else if (event.isCharacters()) { - String s = event.asCharacters().getData(); - if (!s.trim().isEmpty()) { - throw new RuntimeException("export-to is malformed"); - } - } - } - return modules; - } - - private String getData(XMLEventReader reader) throws XMLStreamException { - XMLEvent e = reader.nextEvent(); - if (e.isCharacters()) { - return e.asCharacters().getData(); - } - throw new RuntimeException(e.toString()); - } - - private String getNextTag(XMLEventReader reader, String tag) throws XMLStreamException { - XMLEvent e = reader.nextTag(); - if (e.isStartElement()) { - String t = e.asStartElement().getName().getLocalPart(); - if (!tag.equals(t)) { - throw new RuntimeException(e + " expected: " + tag); - } - return getData(reader); - } - throw new RuntimeException("export-to name is missing:" + e); - } - private void writeXML(Set modules, Path path) - throws IOException, XMLStreamException - { - XMLOutputFactory xof = XMLOutputFactory.newInstance(); - try (OutputStream out = Files.newOutputStream(path)) { - int depth = 0; - XMLStreamWriter xtw = xof.createXMLStreamWriter(out, "UTF-8"); - xtw.writeStartDocument("utf-8","1.0"); - writeStartElement(xtw, MODULES, depth); - modules.stream() - .sorted(Comparator.comparing(Module::name)) - .forEach(m -> writeModuleElement(xtw, m, depth+1)); - writeEndElement(xtw, depth); - xtw.writeCharacters("\n"); - xtw.writeEndDocument(); - xtw.flush(); - xtw.close(); - } - } - - private void writeElement(XMLStreamWriter xtw, String element, String value, int depth) { - try { - writeStartElement(xtw, element, depth); - xtw.writeCharacters(value); - xtw.writeEndElement(); - } catch (XMLStreamException e) { - throw new RuntimeException(e); - } - } - - private void writeDependElement(XMLStreamWriter xtw, Module.Dependence d, int depth) { - try { - writeStartElement(xtw, DEPEND, depth); - if (d.reexport) { - xtw.writeAttribute("re-exports", "true"); - } - xtw.writeCharacters(d.name); - xtw.writeEndElement(); - } catch (XMLStreamException e) { - throw new RuntimeException(e); - } - } - - private void writeExportElement(XMLStreamWriter xtw, String pkg, int depth) { - writeExportElement(xtw, pkg, Collections.emptySet(), depth); - } - - private void writeExportElement(XMLStreamWriter xtw, String pkg, - Set permits, int depth) { - try { - writeStartElement(xtw, EXPORT, depth); - writeElement(xtw, NAME, pkg, depth+1); - if (!permits.isEmpty()) { - permits.stream().sorted() - .forEach(m -> writeElement(xtw, TO, m, depth + 1)); - } - writeEndElement(xtw, depth); - } catch (XMLStreamException e) { - throw new RuntimeException(e); - } - } - private void writeModuleElement(XMLStreamWriter xtw, Module m, int depth) { - try { - writeStartElement(xtw, MODULE, depth); - writeElement(xtw, NAME, m.name(), depth+1); - m.requires().stream().sorted(Comparator.comparing(d -> d.name)) - .forEach(d -> writeDependElement(xtw, d, depth+1)); - m.exports().keySet().stream() - .filter(pn -> m.exports().get(pn).isEmpty()) - .sorted() - .forEach(pn -> writeExportElement(xtw, pn, depth+1)); - m.exports().entrySet().stream() - .filter(e -> !e.getValue().isEmpty()) - .sorted(Map.Entry.comparingByKey()) - .forEach(e -> writeExportElement(xtw, e.getKey(), e.getValue(), depth+1)); - m.packages().stream().sorted() - .forEach(p -> writeElement(xtw, INCLUDE, p, depth+1)); - writeEndElement(xtw, depth); - } catch (XMLStreamException e) { - throw new RuntimeException(e); - - } - } - - /** Two spaces; the default indentation. */ - public static final String DEFAULT_INDENT = " "; - - /** stack[depth] indicates what's been written into the current scope. */ - private static String[] stack = new String[] { "\n", - "\n" + DEFAULT_INDENT, - "\n" + DEFAULT_INDENT + DEFAULT_INDENT, - "\n" + DEFAULT_INDENT + DEFAULT_INDENT + DEFAULT_INDENT}; - - private void writeStartElement(XMLStreamWriter xtw, String name, int depth) - throws XMLStreamException - { - xtw.writeCharacters(stack[depth]); - xtw.writeStartElement(name); - } - - private void writeEndElement(XMLStreamWriter xtw, int depth) throws XMLStreamException { - xtw.writeCharacters(stack[depth]); - xtw.writeEndElement(); - } - - private String packageName(Path p) { + private static String packageName(Path p) { return packageName(p.toString().replace(File.separatorChar, '/')); } - private String packageName(String name) { + private static String packageName(String name) { int i = name.lastIndexOf('/'); return (i > 0) ? name.substring(0, i).replace('/', '.') : ""; } - private boolean includes(String name) { - return name.endsWith(".class") && !name.equals("module-info.class"); + private static boolean includes(String name) { + return name.endsWith(".class"); } - public void buildIncludes(Module.Builder mb, String modulename) throws IOException { - Path mclasses = modulepath.resolve(modulename); + public Module buildIncludes(Module module) { + Module.Builder mb = new Module.Builder(module); + Path mclasses = modulepath.resolve(module.name()); try { Files.find(mclasses, Integer.MAX_VALUE, (Path p, BasicFileAttributes attr) -> includes(p.getFileName().toString())) @@ -341,145 +122,9 @@ public final class GenJdepsModulesXml { .forEach(mb::include); } catch (NoSuchFileException e) { // aggregate module may not have class + } catch (IOException ioe) { + throw new UncheckedIOException(ioe); } - } - - static class Module { - static class Dependence { - final String name; - final boolean reexport; - Dependence(String name) { - this(name, false); - } - Dependence(String name, boolean reexport) { - this.name = name; - this.reexport = reexport; - } - - @Override - public int hashCode() { - int hash = 5; - hash = 11 * hash + Objects.hashCode(this.name); - hash = 11 * hash + (this.reexport ? 1 : 0); - return hash; - } - - public boolean equals(Object o) { - Dependence d = (Dependence)o; - return this.name.equals(d.name) && this.reexport == d.reexport; - } - } - private final String moduleName; - private final Set requires; - private final Map> exports; - private final Set packages; - - private Module(String name, - Set requires, - Map> exports, - Set packages) { - this.moduleName = name; - this.requires = Collections.unmodifiableSet(requires); - this.exports = Collections.unmodifiableMap(exports); - this.packages = Collections.unmodifiableSet(packages); - } - - public String name() { - return moduleName; - } - - public Set requires() { - return requires; - } - - public Map> exports() { - return exports; - } - - public Set packages() { - return packages; - } - - @Override - public boolean equals(Object ob) { - if (!(ob instanceof Module)) { - return false; - } - Module that = (Module) ob; - return (moduleName.equals(that.moduleName) - && requires.equals(that.requires) - && exports.equals(that.exports) - && packages.equals(that.packages)); - } - - @Override - public int hashCode() { - int hc = moduleName.hashCode(); - hc = hc * 43 + requires.hashCode(); - hc = hc * 43 + exports.hashCode(); - hc = hc * 43 + packages.hashCode(); - return hc; - } - - @Override - public String toString() { - StringBuilder sb = new StringBuilder(); - sb.append("module ").append(moduleName).append(" {").append("\n"); - requires.stream().sorted().forEach(d -> - sb.append(String.format(" requires %s%s%n", d.reexport ? "public " : "", d.name))); - exports.entrySet().stream().filter(e -> e.getValue().isEmpty()) - .sorted(Map.Entry.comparingByKey()) - .forEach(e -> sb.append(String.format(" exports %s%n", e.getKey()))); - exports.entrySet().stream().filter(e -> !e.getValue().isEmpty()) - .sorted(Map.Entry.comparingByKey()) - .forEach(e -> sb.append(String.format(" exports %s to %s%n", e.getKey(), e.getValue()))); - packages.stream().sorted().forEach(pn -> sb.append(String.format(" includes %s%n", pn))); - sb.append("}"); - return sb.toString(); - } - - static class Builder { - private String name; - private final Set requires = new HashSet<>(); - private final Map> exports = new HashMap<>(); - private final Set packages = new HashSet<>(); - - public Builder() { - } - - public Builder name(String n) { - name = n; - return this; - } - - public Builder require(String d, boolean reexport) { - requires.add(new Dependence(d, reexport)); - return this; - } - - public Builder include(String p) { - packages.add(p); - return this; - } - - public Builder export(String p) { - return exportTo(p, Collections.emptySet()); - } - - public Builder exportTo(String p, Set ms) { - Objects.requireNonNull(p); - Objects.requireNonNull(ms); - if (exports.containsKey(p)) { - throw new RuntimeException(name + " already exports " + p); - } - exports.put(p, new HashSet<>(ms)); - return this; - } - - public Module build() { - Module m = new Module(name, requires, exports, packages); - return m; - } - } + return mb.build(); } } diff --git a/jdk/make/src/classes/build/tools/module/GenModulesList.java b/jdk/make/src/classes/build/tools/module/GenModulesList.java new file mode 100644 index 00000000000..ac9df5fa683 --- /dev/null +++ b/jdk/make/src/classes/build/tools/module/GenModulesList.java @@ -0,0 +1,159 @@ +/* + * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package build.tools.module; + +import java.io.PrintWriter; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.*; +import java.util.stream.Collectors; + +/** + * $ java build.tools.module.GenModulesList \ + * -o modules.list \ + * top/modules.xml ... + */ +public final class GenModulesList { + private final static String USAGE = + "Usage: GenModulesList -o path-to-modules-xml"; + + private Set modules = new HashSet<>(); + private HashMap nameToModule = new HashMap<>(); + + public static void main(String[] args) throws Exception { + GenModulesList gen = new GenModulesList(); + gen.run(args); + } + + void run(String[] args) throws Exception { + Path outfile = null; + int i = 0; + while (i < args.length) { + String arg = args[i]; + if (arg.equals("-o")) { + outfile = Paths.get(args[i+1]); + i = i+2; + } else { + break; + } + } + if (outfile == null || i >= args.length) { + System.err.println(USAGE); + System.exit(-1); + } + + for (; i < args.length; i++) { + Path p = Paths.get(args[i]); + modules.addAll(ModulesXmlReader.readModules(p)); + } + + modules.stream() + .forEach(m -> nameToModule.put(m.name(), m)); + + Path parent = outfile.getParent(); + if (parent != null) + Files.createDirectories(parent); + + Iterable sortedModules = (new TopoSorter(modules)).result(); + try (PrintWriter writer = new PrintWriter(outfile.toFile())) { + for (Module m : sortedModules) { + if (isNotAggregator(m)) { + String deps = getModuleDependences(m).stream() + .filter(GenModulesList::isNotAggregator) + .map(Module::name) + .collect(Collectors.joining(" ")); + writer.format("%s: %s%n", m.name(), deps); + } + } + } + } + + private Module nameToModule(String name) { + return nameToModule.get(name); + } + + private Set getModuleDependences(Module m) { + return m.requires().stream() + .map(d -> d.name()) + .map(this::nameToModule) + .collect(Collectors.toSet()); + } + + static boolean isNotAggregator(Module m) { + return isNotAggregator(m.name()); + } + + static boolean isNotAggregator(String name) { + return AGGREGATORS.contains(name) ? false : true; + } + + static final List AGGREGATORS = Arrays.asList(new String[] { + "java.se", "java.compact1", "java.compact2", + "java.compact3", "jdk.compact3"}); + + class TopoSorter { + final Deque result = new LinkedList<>(); + final Deque nodes = new LinkedList<>(); + + TopoSorter(Collection nodes) { + nodes.stream() + .forEach(m -> this.nodes.add(m)); + + sort(); + } + + public Iterable result() { + return result; + } + + private void sort() { + Deque visited = new LinkedList<>(); + Deque done = new LinkedList<>(); + Module node; + while ((node = nodes.poll()) != null) { + if (!visited.contains(node)) { + visit(node, visited, done); + } + } + } + + private void visit(Module m, Deque visited, Deque done) { + if (visited.contains(m)) { + if (!done.contains(m)) { + throw new IllegalArgumentException("Cyclic detected: " + + m + " " + getModuleDependences(m)); + } + return; + } + visited.add(m); + getModuleDependences(m).stream() + .forEach(x -> visit(x, visited, done)); + done.add(m); + result.addLast(m); + } + } +} diff --git a/jdk/make/src/classes/build/tools/module/Module.java b/jdk/make/src/classes/build/tools/module/Module.java new file mode 100644 index 00000000000..8264f3c7c76 --- /dev/null +++ b/jdk/make/src/classes/build/tools/module/Module.java @@ -0,0 +1,178 @@ +/* + * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package build.tools.module; + +import java.util.*; + +public class Module { + static class Dependence { + final String name; + final boolean reexport; + Dependence(String name) { + this(name, false); + } + Dependence(String name, boolean reexport) { + this.name = name; + this.reexport = reexport; + } + + public String name() { + return name; + } + + @Override + public int hashCode() { + int hash = 5; + hash = 11 * hash + Objects.hashCode(this.name); + hash = 11 * hash + (this.reexport ? 1 : 0); + return hash; + } + + public boolean equals(Object o) { + Dependence d = (Dependence)o; + return this.name.equals(d.name) && this.reexport == d.reexport; + } + } + private final String moduleName; + private final Set requires; + private final Map> exports; + private final Set packages; + + private Module(String name, + Set requires, + Map> exports, + Set packages) { + this.moduleName = name; + this.requires = Collections.unmodifiableSet(requires); + this.exports = Collections.unmodifiableMap(exports); + this.packages = Collections.unmodifiableSet(packages); + } + + public String name() { + return moduleName; + } + + public Set requires() { + return requires; + } + + public Map> exports() { + return exports; + } + + public Set packages() { + return packages; + } + + @Override + public boolean equals(Object ob) { + if (!(ob instanceof Module)) { + return false; + } + Module that = (Module) ob; + return (moduleName.equals(that.moduleName) + && requires.equals(that.requires) + && exports.equals(that.exports) + && packages.equals(that.packages)); + } + + @Override + public int hashCode() { + int hc = moduleName.hashCode(); + hc = hc * 43 + requires.hashCode(); + hc = hc * 43 + exports.hashCode(); + hc = hc * 43 + packages.hashCode(); + return hc; + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("module ").append(moduleName).append(" {").append("\n"); + requires.stream().sorted().forEach(d -> + sb.append(String.format(" requires %s%s%n", d.reexport ? "public " : "", d.name))); + exports.entrySet().stream().filter(e -> e.getValue().isEmpty()) + .sorted(Map.Entry.comparingByKey()) + .forEach(e -> sb.append(String.format(" exports %s%n", e.getKey()))); + exports.entrySet().stream().filter(e -> !e.getValue().isEmpty()) + .sorted(Map.Entry.comparingByKey()) + .forEach(e -> sb.append(String.format(" exports %s to %s%n", e.getKey(), e.getValue()))); + packages.stream().sorted().forEach(pn -> sb.append(String.format(" includes %s%n", pn))); + sb.append("}"); + return sb.toString(); + } + + static class Builder { + private String name; + private final Set requires = new HashSet<>(); + private final Map> exports = new HashMap<>(); + private final Set packages = new HashSet<>(); + + public Builder() { + } + + public Builder(Module module) { + name = module.name(); + requires.addAll(module.requires()); + exports.putAll(module.exports()); + packages.addAll(module.packages()); + } + + public Builder name(String n) { + name = n; + return this; + } + + public Builder require(String d, boolean reexport) { + requires.add(new Dependence(d, reexport)); + return this; + } + + public Builder include(String p) { + packages.add(p); + return this; + } + + public Builder export(String p) { + return exportTo(p, Collections.emptySet()); + } + + public Builder exportTo(String p, Set ms) { + Objects.requireNonNull(p); + Objects.requireNonNull(ms); + if (exports.containsKey(p)) { + throw new RuntimeException(name + " already exports " + p); + } + exports.put(p, new HashSet<>(ms)); + return this; + } + + public Module build() { + Module m = new Module(name, requires, exports, packages); + return m; + } + } +} diff --git a/jdk/make/src/classes/build/tools/module/ModulesXmlReader.java b/jdk/make/src/classes/build/tools/module/ModulesXmlReader.java new file mode 100644 index 00000000000..0d1121867d2 --- /dev/null +++ b/jdk/make/src/classes/build/tools/module/ModulesXmlReader.java @@ -0,0 +1,165 @@ +/* + * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package build.tools.module; + +import javax.xml.namespace.QName; +import javax.xml.stream.XMLEventReader; +import javax.xml.stream.XMLInputFactory; +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.events.Attribute; +import javax.xml.stream.events.XMLEvent; +import java.io.BufferedInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.HashSet; +import java.util.Set; + +public class ModulesXmlReader { + + private ModulesXmlReader() {} + + public static Set readModules(Path modulesXml) + throws XMLStreamException, IOException + { + Set modules = new HashSet<>(); + try (InputStream in = new BufferedInputStream(Files.newInputStream(modulesXml))) { + Set mods = ModulesXmlReader.load(in); + modules.addAll(mods); + } + return modules; + } + + private static final String MODULES = "modules"; + private static final String MODULE = "module"; + private static final String NAME = "name"; + private static final String DEPEND = "depend"; + private static final String EXPORT = "export"; + private static final String TO = "to"; + private static final String INCLUDE = "include"; + private static final QName REEXPORTS = new QName("re-exports"); + private static Set load(InputStream in) + throws XMLStreamException, IOException + { + Set modules = new HashSet<>(); + XMLInputFactory factory = XMLInputFactory.newInstance(); + XMLEventReader stream = factory.createXMLEventReader(in); + Module.Builder mb = null; + String modulename = null; + String pkg = null; + Set permits = new HashSet<>(); + while (stream.hasNext()) { + XMLEvent event = stream.nextEvent(); + if (event.isStartElement()) { + String startTag = event.asStartElement().getName().getLocalPart(); + switch (startTag) { + case MODULES: + break; + case MODULE: + if (mb != null) { + throw new RuntimeException("end tag for module is missing"); + } + modulename = getNextTag(stream, NAME); + mb = new Module.Builder(); + mb.name(modulename); + break; + case NAME: + throw new RuntimeException(event.toString()); + case DEPEND: + boolean reexports = false; + Attribute attr = event.asStartElement().getAttributeByName(REEXPORTS); + if (attr != null) { + String value = attr.getValue(); + if (value.equals("true") || value.equals("false")) { + reexports = Boolean.parseBoolean(value); + } else { + throw new RuntimeException("unexpected attribute " + attr.toString()); + } + } + mb.require(getData(stream), reexports); + break; + case INCLUDE: + throw new RuntimeException("unexpected " + event); + case EXPORT: + pkg = getNextTag(stream, NAME); + break; + case TO: + permits.add(getData(stream)); + break; + default: + } + } else if (event.isEndElement()) { + String endTag = event.asEndElement().getName().getLocalPart(); + switch (endTag) { + case MODULE: + modules.add(mb.build()); + mb = null; + break; + case EXPORT: + if (pkg == null) { + throw new RuntimeException("export-to is malformed"); + } + mb.exportTo(pkg, permits); + pkg = null; + permits.clear(); + break; + default: + } + } else if (event.isCharacters()) { + String s = event.asCharacters().getData(); + if (!s.trim().isEmpty()) { + throw new RuntimeException("export-to is malformed"); + } + } + } + return modules; + } + + private static String getData(XMLEventReader reader) + throws XMLStreamException + { + XMLEvent e = reader.nextEvent(); + if (e.isCharacters()) + return e.asCharacters().getData(); + + throw new RuntimeException(e.toString()); + } + + private static String getNextTag(XMLEventReader reader, String tag) + throws XMLStreamException + { + XMLEvent e = reader.nextTag(); + if (e.isStartElement()) { + String t = e.asStartElement().getName().getLocalPart(); + if (!tag.equals(t)) { + throw new RuntimeException(e + " expected: " + tag); + } + return getData(reader); + } + throw new RuntimeException("export-to name is missing:" + e); + } +} diff --git a/jdk/make/src/classes/build/tools/module/ModulesXmlWriter.java b/jdk/make/src/classes/build/tools/module/ModulesXmlWriter.java new file mode 100644 index 00000000000..51ad32ab9a1 --- /dev/null +++ b/jdk/make/src/classes/build/tools/module/ModulesXmlWriter.java @@ -0,0 +1,179 @@ +/* + * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package build.tools.module; + +import javax.xml.namespace.QName; +import javax.xml.stream.XMLOutputFactory; +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.XMLStreamWriter; +import java.io.IOException; +import java.io.OutputStream; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.Collections; +import java.util.Comparator; +import java.util.Map; +import java.util.Set; + +public final class ModulesXmlWriter { + + private ModulesXmlWriter() {} + + public static void writeModules(Set modules, Path path) + throws IOException, XMLStreamException + { + writeXML(modules, path); + } + + private static final String MODULES = "modules"; + private static final String MODULE = "module"; + private static final String NAME = "name"; + private static final String DEPEND = "depend"; + private static final String EXPORT = "export"; + private static final String TO = "to"; + private static final String INCLUDE = "include"; + private static final QName REEXPORTS = new QName("re-exports"); + + private static void writeXML(Set modules, Path path) + throws IOException, XMLStreamException + { + XMLOutputFactory xof = XMLOutputFactory.newInstance(); + try (OutputStream out = Files.newOutputStream(path)) { + int depth = 0; + XMLStreamWriter xtw = xof.createXMLStreamWriter(out, "UTF-8"); + xtw.writeStartDocument("utf-8","1.0"); + writeStartElement(xtw, MODULES, depth); + modules.stream() + .sorted(Comparator.comparing(Module::name)) + .forEach(m -> writeModuleElement(xtw, m, depth+1)); + writeEndElement(xtw, depth); + xtw.writeCharacters("\n"); + xtw.writeEndDocument(); + xtw.flush(); + xtw.close(); + } + } + + private static void writeElement(XMLStreamWriter xtw, + String element, + String value, + int depth) { + try { + writeStartElement(xtw, element, depth); + xtw.writeCharacters(value); + xtw.writeEndElement(); + } catch (XMLStreamException e) { + throw new RuntimeException(e); + } + } + + private static void writeDependElement(XMLStreamWriter xtw, + Module.Dependence d, + int depth) { + try { + writeStartElement(xtw, DEPEND, depth); + if (d.reexport) { + xtw.writeAttribute("re-exports", "true"); + } + xtw.writeCharacters(d.name); + xtw.writeEndElement(); + } catch (XMLStreamException e) { + throw new RuntimeException(e); + } + } + + private static void writeExportElement(XMLStreamWriter xtw, + String pkg, + int depth) { + writeExportElement(xtw, pkg, Collections.emptySet(), depth); + } + + private static void writeExportElement(XMLStreamWriter xtw, + String pkg, + Set permits, + int depth) { + try { + writeStartElement(xtw, EXPORT, depth); + writeElement(xtw, NAME, pkg, depth+1); + if (!permits.isEmpty()) { + permits.stream().sorted() + .forEach(m -> writeElement(xtw, TO, m, depth + 1)); + } + writeEndElement(xtw, depth); + } catch (XMLStreamException e) { + throw new RuntimeException(e); + } + } + private static void writeModuleElement(XMLStreamWriter xtw, + Module m, + int depth) { + try { + writeStartElement(xtw, MODULE, depth); + writeElement(xtw, NAME, m.name(), depth+1); + m.requires().stream().sorted(Comparator.comparing(d -> d.name)) + .forEach(d -> writeDependElement(xtw, d, depth+1)); + m.exports().keySet().stream() + .filter(pn -> m.exports().get(pn).isEmpty()) + .sorted() + .forEach(pn -> writeExportElement(xtw, pn, depth+1)); + m.exports().entrySet().stream() + .filter(e -> !e.getValue().isEmpty()) + .sorted(Map.Entry.comparingByKey()) + .forEach(e -> writeExportElement(xtw, e.getKey(), e.getValue(), depth+1)); + m.packages().stream().sorted() + .forEach(p -> writeElement(xtw, INCLUDE, p, depth+1)); + writeEndElement(xtw, depth); + } catch (XMLStreamException e) { + throw new RuntimeException(e); + + } + } + + /** Two spaces; the default indentation. */ + public static final String DEFAULT_INDENT = " "; + + /** stack[depth] indicates what's been written into the current scope. */ + private static String[] stack = new String[] { "\n", + "\n" + DEFAULT_INDENT, + "\n" + DEFAULT_INDENT + DEFAULT_INDENT, + "\n" + DEFAULT_INDENT + DEFAULT_INDENT + DEFAULT_INDENT}; + + private static void writeStartElement(XMLStreamWriter xtw, + String name, + int depth) + throws XMLStreamException + { + xtw.writeCharacters(stack[depth]); + xtw.writeStartElement(name); + } + + private static void writeEndElement(XMLStreamWriter xtw, int depth) + throws XMLStreamException + { + xtw.writeCharacters(stack[depth]); + xtw.writeEndElement(); + } +} From e490ad1e61bb6135fb0fa2c9315e2e4be7776eae Mon Sep 17 00:00:00 2001 From: Vladimir Ivanov Date: Tue, 16 Sep 2014 18:05:01 +0400 Subject: [PATCH 47/81] 8058291: Missing some checks during parameter validation Reviewed-by: jrose --- .../classes/java/lang/invoke/MethodHandleImpl.java | 2 +- .../share/classes/java/lang/invoke/MethodHandles.java | 11 +++++++++-- .../share/classes/java/lang/invoke/MethodType.java | 4 +--- 3 files changed, 11 insertions(+), 6 deletions(-) diff --git a/jdk/src/java.base/share/classes/java/lang/invoke/MethodHandleImpl.java b/jdk/src/java.base/share/classes/java/lang/invoke/MethodHandleImpl.java index 7b018f036cf..d24a1ed5614 100644 --- a/jdk/src/java.base/share/classes/java/lang/invoke/MethodHandleImpl.java +++ b/jdk/src/java.base/share/classes/java/lang/invoke/MethodHandleImpl.java @@ -188,7 +188,6 @@ import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP; static MethodHandle makePairwiseConvert(MethodHandle target, MethodType srcType, boolean strict, boolean monobox) { MethodType dstType = target.type(); - assert(dstType.parameterCount() == target.type().parameterCount()); if (srcType == dstType) return target; if (USE_LAMBDA_FORM_EDITOR) { @@ -265,6 +264,7 @@ import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP; static MethodHandle makePairwiseConvertIndirect(MethodHandle target, MethodType srcType, boolean strict, boolean monobox) { + assert(target.type().parameterCount() == srcType.parameterCount()); // Calculate extra arguments (temporaries) required in the names array. Object[] convSpecs = computeValueConversions(srcType, target.type(), strict, monobox); final int INARG_COUNT = srcType.parameterCount(); diff --git a/jdk/src/java.base/share/classes/java/lang/invoke/MethodHandles.java b/jdk/src/java.base/share/classes/java/lang/invoke/MethodHandles.java index ea692345d66..b4540151421 100644 --- a/jdk/src/java.base/share/classes/java/lang/invoke/MethodHandles.java +++ b/jdk/src/java.base/share/classes/java/lang/invoke/MethodHandles.java @@ -2023,8 +2023,9 @@ return invoker; */ public static MethodHandle explicitCastArguments(MethodHandle target, MethodType newType) { - MethodType oldType = target.type(); + explicitCastArgumentsChecks(target, newType); // use the asTypeCache when possible: + MethodType oldType = target.type(); if (oldType == newType) return target; if (oldType.explicitCastEquivalentToAsType(newType)) { return target.asType(newType); @@ -2032,6 +2033,12 @@ return invoker; return MethodHandleImpl.makePairwiseConvert(target, newType, false); } + private static void explicitCastArgumentsChecks(MethodHandle target, MethodType newType) { + if (target.type().parameterCount() != newType.parameterCount()) { + throw new WrongMethodTypeException("cannot explicitly cast " + target + " to " + newType); + } + } + /** * Produces a method handle which adapts the calling sequence of the * given method handle to a new type, by reordering the arguments. @@ -2479,6 +2486,7 @@ assertEquals("yz", (String) d0.invokeExact(123, "x", "y", "z")); MethodHandle dropArguments(MethodHandle target, int pos, List> valueTypes) { MethodType oldType = target.type(); // get NPE int dropped = dropArgumentChecks(oldType, pos, valueTypes); + MethodType newType = oldType.insertParameterTypes(pos, valueTypes); if (dropped == 0) return target; BoundMethodHandle result = target.rebind(); LambdaForm lform = result.form; @@ -2490,7 +2498,6 @@ assertEquals("yz", (String) d0.invokeExact(123, "x", "y", "z")); } else { lform = lform.addArguments(pos, valueTypes); } - MethodType newType = oldType.insertParameterTypes(pos, valueTypes); result = result.copyWith(newType, lform); return result; } diff --git a/jdk/src/java.base/share/classes/java/lang/invoke/MethodType.java b/jdk/src/java.base/share/classes/java/lang/invoke/MethodType.java index 2762227f5c2..3eab50e26ea 100644 --- a/jdk/src/java.base/share/classes/java/lang/invoke/MethodType.java +++ b/jdk/src/java.base/share/classes/java/lang/invoke/MethodType.java @@ -869,9 +869,7 @@ class MethodType implements java.io.Serializable { if (dstTypes == srcTypes) { return true; } - if (dstTypes.length != srcTypes.length) { - return false; - } + assert(dstTypes.length == srcTypes.length); for (int i = 0; i < dstTypes.length; i++) { if (!explicitCastEquivalentToAsType(srcTypes[i], dstTypes[i])) { return false; From 475c0a767aac3523fb095f84d81418808b40d7f9 Mon Sep 17 00:00:00 2001 From: Vladimir Ivanov Date: Tue, 16 Sep 2014 18:05:03 +0400 Subject: [PATCH 48/81] 8058293: Bit set computation in MHs.findFirstDupOrDrop/findFirstDrop is broken Reviewed-by: jrose --- .../java/lang/invoke/MethodHandles.java | 50 ++++++++++++------- 1 file changed, 31 insertions(+), 19 deletions(-) diff --git a/jdk/src/java.base/share/classes/java/lang/invoke/MethodHandles.java b/jdk/src/java.base/share/classes/java/lang/invoke/MethodHandles.java index b4540151421..1600658e938 100644 --- a/jdk/src/java.base/share/classes/java/lang/invoke/MethodHandles.java +++ b/jdk/src/java.base/share/classes/java/lang/invoke/MethodHandles.java @@ -2171,7 +2171,7 @@ assert((int)twice.invokeExact(21) == 42); // dropIdx is missing from reorder; add it in at the end int oldArity = reorder.length; target = dropArguments(target, oldArity, newType.parameterType(dropIdx)); - reorder = Arrays.copyOf(reorder, oldArity+1); + reorder = Arrays.copyOf(reorder, oldArity + 1); reorder[oldArity] = dropIdx; } assert(target == originalTarget || permuteArgumentChecks(reorder, newType, target.type())); @@ -2189,9 +2189,9 @@ assert((int)twice.invokeExact(21) == 42); long mask = 0; for (int arg : reorder) { assert(arg < newArity); - mask |= (1 << arg); + mask |= (1L << arg); } - if (mask == (1 << newArity) - 1) { + if (mask == (1L << newArity) - 1) { assert(Long.numberOfTrailingZeros(Long.lowestOneBit(~mask)) == newArity); return -1; } @@ -2200,16 +2200,18 @@ assert((int)twice.invokeExact(21) == 42); int zeroPos = Long.numberOfTrailingZeros(zeroBit); assert(zeroPos < newArity); return zeroPos; + } else { + BitSet mask = new BitSet(newArity); + for (int arg : reorder) { + assert (arg < newArity); + mask.set(arg); + } + int zeroPos = mask.nextClearBit(0); + assert(zeroPos <= newArity); + if (zeroPos == newArity) + return -1; + return zeroPos; } - BitSet mask = new BitSet(newArity); - for (int arg : reorder) { - assert(arg < newArity); - mask.set(arg); - } - int zeroPos = mask.nextClearBit(0); - if (zeroPos == newArity) - return -1; - return zeroPos; } /** @@ -2225,32 +2227,42 @@ assert((int)twice.invokeExact(21) == 42); long mask = 0; for (int i = 0; i < reorder.length; i++) { int arg = reorder[i]; - if (arg >= newArity) return reorder.length; - int bit = 1 << arg; - if ((mask & bit) != 0) + if (arg >= newArity) { + return reorder.length; + } + long bit = 1L << arg; + if ((mask & bit) != 0) { return i; // >0 indicates a dup + } mask |= bit; } - if (mask == (1 << newArity) - 1) { + if (mask == (1L << newArity) - 1) { assert(Long.numberOfTrailingZeros(Long.lowestOneBit(~mask)) == newArity); return 0; } // find first zero long zeroBit = Long.lowestOneBit(~mask); int zeroPos = Long.numberOfTrailingZeros(zeroBit); - assert(zeroPos < newArity); + assert(zeroPos <= newArity); + if (zeroPos == newArity) { + return 0; + } return ~zeroPos; } else { // same algorithm, different bit set BitSet mask = new BitSet(newArity); for (int i = 0; i < reorder.length; i++) { int arg = reorder[i]; - if (arg >= newArity) return reorder.length; - if (mask.get(arg)) + if (arg >= newArity) { + return reorder.length; + } + if (mask.get(arg)) { return i; // >0 indicates a dup + } mask.set(arg); } int zeroPos = mask.nextClearBit(0); + assert(zeroPos <= newArity); if (zeroPos == newArity) { return 0; } From 8acf66df11a2908d10a21f3a87871ffd1d2fa2ac Mon Sep 17 00:00:00 2001 From: Robert Gibson Date: Mon, 15 Sep 2014 13:25:08 -0700 Subject: [PATCH 49/81] 8058505: BigIntegerTest does not exercise Burnikel-Ziegler division Modify divideLarge() method such that the w/z division exercises the B-Z branch. Reviewed-by: darcy --- .../java/math/BigInteger/BigIntegerTest.java | 27 ++++++++++--------- 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/jdk/test/java/math/BigInteger/BigIntegerTest.java b/jdk/test/java/math/BigInteger/BigIntegerTest.java index 8d7ad255dd0..3f7c00a810b 100644 --- a/jdk/test/java/math/BigInteger/BigIntegerTest.java +++ b/jdk/test/java/math/BigInteger/BigIntegerTest.java @@ -71,6 +71,7 @@ public class BigIntegerTest { static final int BITS_TOOM_COOK_SQUARE = 6912; static final int BITS_SCHOENHAGE_BASE = 640; static final int BITS_BURNIKEL_ZIEGLER = 2560; + static final int BITS_BURNIKEL_ZIEGLER_OFFSET = 1280; static final int ORDER_SMALL = 60; static final int ORDER_MEDIUM = 100; @@ -288,19 +289,19 @@ public class BigIntegerTest { * where {@code abs(u) > abs(v)} and {@code a > b && b > 0}, then if * {@code w/z = q1*z + r1} and {@code u/v = q2*v + r2}, then * {@code q1 = q2*pow(2,a-b)} and {@code r1 = r2*pow(2,b)}. The test - * ensures that {@code v} is just under the B-Z threshold and that {@code w} - * and {@code z} are both over the threshold. This implies that {@code u/v} - * uses the standard division algorithm and {@code w/z} uses the B-Z - * algorithm. The results of the two algorithms are then compared using the - * observation described in the foregoing and if they are not equal a - * failure is logged. +     * ensures that {@code v} is just under the B-Z threshold, that {@code z} is +     * over the threshold and {@code w} is much larger than {@code z}. This +     * implies that {@code u/v} uses the standard division algorithm and +     * {@code w/z} uses the B-Z algorithm.  The results of the two algorithms +     * are then compared using the observation described in the foregoing and +     * if they are not equal a failure is logged. */ public static void divideLarge() { int failCount = 0; - BigInteger base = BigInteger.ONE.shiftLeft(BITS_BURNIKEL_ZIEGLER - 33); + BigInteger base = BigInteger.ONE.shiftLeft(BITS_BURNIKEL_ZIEGLER + BITS_BURNIKEL_ZIEGLER_OFFSET - 33); for (int i=0; i Date: Tue, 16 Sep 2014 10:13:45 +0200 Subject: [PATCH 50/81] 8058475: TestCMSClassUnloadingEnabledHWM.java fails with '.*CMS Initial Mark.*' missing from stdout/stderr Reviewed-by: mgerdin, tschatzl, brutisso --- .../AllocateBeyondMetaspaceSize.java | 59 ------------------- .../TestCMSClassUnloadingEnabledHWM.java | 47 +++++++++++++-- .../TestG1ClassUnloadingHWM.java | 37 +++++++++++- 3 files changed, 76 insertions(+), 67 deletions(-) delete mode 100644 hotspot/test/gc/class_unloading/AllocateBeyondMetaspaceSize.java diff --git a/hotspot/test/gc/class_unloading/AllocateBeyondMetaspaceSize.java b/hotspot/test/gc/class_unloading/AllocateBeyondMetaspaceSize.java deleted file mode 100644 index 4998fa8e562..00000000000 --- a/hotspot/test/gc/class_unloading/AllocateBeyondMetaspaceSize.java +++ /dev/null @@ -1,59 +0,0 @@ -/* - * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -import sun.hotspot.WhiteBox; - -class AllocateBeyondMetaspaceSize { - public static Object dummy; - - public static void main(String [] args) { - if (args.length != 2) { - throw new IllegalArgumentException("Usage: "); - } - - long metaspaceSize = Long.parseLong(args[0]); - long youngGenSize = Long.parseLong(args[1]); - - run(metaspaceSize, youngGenSize); - } - - private static void run(long metaspaceSize, long youngGenSize) { - WhiteBox wb = WhiteBox.getWhiteBox(); - - long allocationBeyondMetaspaceSize = metaspaceSize * 2; - long metaspace = wb.allocateMetaspace(null, allocationBeyondMetaspaceSize); - - triggerYoungGC(youngGenSize); - - wb.freeMetaspace(null, metaspace, metaspace); - } - - private static void triggerYoungGC(long youngGenSize) { - long approxAllocSize = 32 * 1024; - long numAllocations = 2 * youngGenSize / approxAllocSize; - - for (long i = 0; i < numAllocations; i++) { - dummy = new byte[(int)approxAllocSize]; - } - } -} diff --git a/hotspot/test/gc/class_unloading/TestCMSClassUnloadingEnabledHWM.java b/hotspot/test/gc/class_unloading/TestCMSClassUnloadingEnabledHWM.java index 38c1e16cea1..0e33bcf967d 100644 --- a/hotspot/test/gc/class_unloading/TestCMSClassUnloadingEnabledHWM.java +++ b/hotspot/test/gc/class_unloading/TestCMSClassUnloadingEnabledHWM.java @@ -26,7 +26,7 @@ * @key gc * @bug 8049831 * @library /testlibrary /testlibrary/whitebox - * @build TestCMSClassUnloadingEnabledHWM AllocateBeyondMetaspaceSize + * @build TestCMSClassUnloadingEnabledHWM * @run main ClassFileInstaller sun.hotspot.WhiteBox * sun.hotspot.WhiteBox$WhiteBoxPermission * @run driver TestCMSClassUnloadingEnabledHWM @@ -35,9 +35,11 @@ import com.oracle.java.testlibrary.OutputAnalyzer; import com.oracle.java.testlibrary.ProcessTools; - +import java.lang.management.GarbageCollectorMXBean; +import java.lang.management.ManagementFactory; import java.util.ArrayList; import java.util.Arrays; +import sun.hotspot.WhiteBox; public class TestCMSClassUnloadingEnabledHWM { private static long MetaspaceSize = 32 * 1024 * 1024; @@ -48,15 +50,18 @@ public class TestCMSClassUnloadingEnabledHWM { "-Xbootclasspath/a:.", "-XX:+UnlockDiagnosticVMOptions", "-XX:+WhiteBoxAPI", + "-Xmx128m", + "-XX:CMSMaxAbortablePrecleanTime=1", + "-XX:CMSWaitDuration=50", "-XX:MetaspaceSize=" + MetaspaceSize, "-Xmn" + YoungGenSize, "-XX:+UseConcMarkSweepGC", "-XX:" + (enableUnloading ? "+" : "-") + "CMSClassUnloadingEnabled", "-XX:+PrintHeapAtGC", "-XX:+PrintGCDetails", - "AllocateBeyondMetaspaceSize", - "" + MetaspaceSize, - "" + YoungGenSize); + "-XX:+PrintGCTimeStamps", + TestCMSClassUnloadingEnabledHWM.AllocateBeyondMetaspaceSize.class.getName(), + "" + MetaspaceSize); return new OutputAnalyzer(pb.start()); } @@ -88,5 +93,37 @@ public class TestCMSClassUnloadingEnabledHWM { testWithCMSClassUnloading(); testWithoutCMSClassUnloading(); } + + public static class AllocateBeyondMetaspaceSize { + public static void main(String [] args) throws Exception { + if (args.length != 1) { + throw new IllegalArgumentException("Usage: "); + } + + WhiteBox wb = WhiteBox.getWhiteBox(); + + // Allocate past the MetaspaceSize limit. + long metaspaceSize = Long.parseLong(args[0]); + long allocationBeyondMetaspaceSize = metaspaceSize * 2; + long metaspace = wb.allocateMetaspace(null, allocationBeyondMetaspaceSize); + + // Wait for at least one GC to occur. The caller will parse the log files produced. + GarbageCollectorMXBean cmsGCBean = getCMSGCBean(); + while (cmsGCBean.getCollectionCount() == 0) { + Thread.sleep(100); + } + + wb.freeMetaspace(null, metaspace, metaspace); + } + + private static GarbageCollectorMXBean getCMSGCBean() { + for (GarbageCollectorMXBean gcBean : ManagementFactory.getGarbageCollectorMXBeans()) { + if (gcBean.getObjectName().toString().equals("java.lang:type=GarbageCollector,name=ConcurrentMarkSweep")) { + return gcBean; + } + } + return null; + } + } } diff --git a/hotspot/test/gc/class_unloading/TestG1ClassUnloadingHWM.java b/hotspot/test/gc/class_unloading/TestG1ClassUnloadingHWM.java index c2c17145762..7a2ebc18b42 100644 --- a/hotspot/test/gc/class_unloading/TestG1ClassUnloadingHWM.java +++ b/hotspot/test/gc/class_unloading/TestG1ClassUnloadingHWM.java @@ -26,7 +26,7 @@ * @key gc * @bug 8049831 * @library /testlibrary /testlibrary/whitebox - * @build TestG1ClassUnloadingHWM AllocateBeyondMetaspaceSize + * @build TestG1ClassUnloadingHWM * @run main ClassFileInstaller sun.hotspot.WhiteBox * sun.hotspot.WhiteBox$WhiteBoxPermission * @run driver TestG1ClassUnloadingHWM @@ -35,9 +35,9 @@ import com.oracle.java.testlibrary.OutputAnalyzer; import com.oracle.java.testlibrary.ProcessTools; - import java.util.ArrayList; import java.util.Arrays; +import sun.hotspot.WhiteBox; public class TestG1ClassUnloadingHWM { private static long MetaspaceSize = 32 * 1024 * 1024; @@ -54,7 +54,7 @@ public class TestG1ClassUnloadingHWM { "-XX:" + (enableUnloading ? "+" : "-") + "ClassUnloadingWithConcurrentMark", "-XX:+PrintHeapAtGC", "-XX:+PrintGCDetails", - "AllocateBeyondMetaspaceSize", + TestG1ClassUnloadingHWM.AllocateBeyondMetaspaceSize.class.getName(), "" + MetaspaceSize, "" + YoungGenSize); return new OutputAnalyzer(pb.start()); @@ -88,5 +88,36 @@ public class TestG1ClassUnloadingHWM { testWithG1ClassUnloading(); testWithoutG1ClassUnloading(); } + + public static class AllocateBeyondMetaspaceSize { + public static Object dummy; + + public static void main(String [] args) throws Exception { + if (args.length != 2) { + throw new IllegalArgumentException("Usage: "); + } + + WhiteBox wb = WhiteBox.getWhiteBox(); + + // Allocate past the MetaspaceSize limit + long metaspaceSize = Long.parseLong(args[0]); + long allocationBeyondMetaspaceSize = metaspaceSize * 2; + long metaspace = wb.allocateMetaspace(null, allocationBeyondMetaspaceSize); + + long youngGenSize = Long.parseLong(args[1]); + triggerYoungGCs(youngGenSize); + + wb.freeMetaspace(null, metaspace, metaspace); + } + + public static void triggerYoungGCs(long youngGenSize) { + long approxAllocSize = 32 * 1024; + long numAllocations = 2 * youngGenSize / approxAllocSize; + + for (long i = 0; i < numAllocations; i++) { + dummy = new byte[(int)approxAllocSize]; + } + } + } } From adf66602a0a96382d722743eca19fb78ec6e701d Mon Sep 17 00:00:00 2001 From: Thomas Schatzl Date: Tue, 16 Sep 2014 10:28:15 +0200 Subject: [PATCH 51/81] 8052172: Evacuation failure handling in G1 does not evacuate all objects if -XX:-G1DeferredRSUpdate is set Remove -XX:-G1DeferredRSUpdate functionality as it is racy. During evacuation failure handling, threads where evacuation failure handling occurred may try to add remembered sets to regions which remembered sets are currently being scanned. The iterator to handle the remembered set scan does not support addition of entries during scan and so may skip valid references. Reviewed-by: iveresov, brutisso, mgerdin --- .../gc_implementation/g1/g1CollectedHeap.cpp | 25 ++--- .../vm/gc_implementation/g1/g1EvacFailure.hpp | 25 ++--- .../gc_implementation/g1/g1GCPhaseTimes.cpp | 16 ++-- .../g1/g1ParScanThreadState.hpp | 27 +++--- .../g1/g1ParScanThreadState.inline.hpp | 14 --- .../vm/gc_implementation/g1/g1RemSet.cpp | 92 ++----------------- .../vm/gc_implementation/g1/g1RemSet.hpp | 14 --- .../gc_implementation/g1/g1RemSet.inline.hpp | 9 -- .../vm/gc_implementation/g1/g1_globals.hpp | 3 - hotspot/test/gc/g1/TestDeferredRSUpdate.java | 79 ---------------- 10 files changed, 41 insertions(+), 263 deletions(-) delete mode 100644 hotspot/test/gc/g1/TestDeferredRSUpdate.java diff --git a/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp b/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp index 021dbe406e0..fda7d94a9df 100644 --- a/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp +++ b/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp @@ -1481,9 +1481,7 @@ bool G1CollectedHeap::do_collection(bool explicit_gc, // Discard all rset updates JavaThread::dirty_card_queue_set().abandon_logs(); - assert(!G1DeferredRSUpdate - || (G1DeferredRSUpdate && - (dirty_card_queue_set().completed_buffers_num() == 0)), "Should not be any"); + assert(dirty_card_queue_set().completed_buffers_num() == 0, "DCQS should be empty"); _young_list->reset_sampled_info(); // At this point there should be no regions in the @@ -2094,15 +2092,13 @@ jint G1CollectedHeap::initialize() { concurrent_g1_refine()->red_zone(), Shared_DirtyCardQ_lock); - if (G1DeferredRSUpdate) { - dirty_card_queue_set().initialize(NULL, // Should never be called by the Java code - DirtyCardQ_CBL_mon, - DirtyCardQ_FL_lock, - -1, // never trigger processing - -1, // no limit on length - Shared_DirtyCardQ_lock, - &JavaThread::dirty_card_queue_set()); - } + dirty_card_queue_set().initialize(NULL, // Should never be called by the Java code + DirtyCardQ_CBL_mon, + DirtyCardQ_FL_lock, + -1, // never trigger processing + -1, // no limit on length + Shared_DirtyCardQ_lock, + &JavaThread::dirty_card_queue_set()); // Initialize the card queue set used to hold cards containing // references into the collection set. @@ -5389,7 +5385,6 @@ class G1RedirtyLoggedCardsTask : public AbstractGangTask { }; void G1CollectedHeap::redirty_logged_cards() { - guarantee(G1DeferredRSUpdate, "Must only be called when using deferred RS updates."); double redirty_logged_cards_start = os::elapsedTime(); uint n_workers = (G1CollectedHeap::use_parallel_gc_threads() ? @@ -6049,9 +6044,7 @@ void G1CollectedHeap::evacuate_collection_set(EvacuationInfo& evacuation_info) { // RSets. enqueue_discovered_references(n_workers); - if (G1DeferredRSUpdate) { - redirty_logged_cards(); - } + redirty_logged_cards(); COMPILER2_PRESENT(DerivedPointerTable::update_pointers()); } diff --git a/hotspot/src/share/vm/gc_implementation/g1/g1EvacFailure.hpp b/hotspot/src/share/vm/gc_implementation/g1/g1EvacFailure.hpp index 72d1ca179f8..e628340105f 100644 --- a/hotspot/src/share/vm/gc_implementation/g1/g1EvacFailure.hpp +++ b/hotspot/src/share/vm/gc_implementation/g1/g1EvacFailure.hpp @@ -176,15 +176,17 @@ public: class RemoveSelfForwardPtrHRClosure: public HeapRegionClosure { G1CollectedHeap* _g1h; ConcurrentMark* _cm; - OopsInHeapRegionClosure *_update_rset_cl; uint _worker_id; + DirtyCardQueue _dcq; + UpdateRSetDeferred _update_rset_cl; + public: RemoveSelfForwardPtrHRClosure(G1CollectedHeap* g1h, - OopsInHeapRegionClosure* update_rset_cl, uint worker_id) : - _g1h(g1h), _update_rset_cl(update_rset_cl), - _worker_id(worker_id), _cm(_g1h->concurrent_mark()) { } + _g1h(g1h), _dcq(&g1h->dirty_card_queue_set()), _update_rset_cl(g1h, &_dcq), + _worker_id(worker_id), _cm(_g1h->concurrent_mark()) { + } bool doHeapRegion(HeapRegion *hr) { bool during_initial_mark = _g1h->g1_policy()->during_initial_mark_pause(); @@ -195,7 +197,7 @@ public: if (hr->claimHeapRegion(HeapRegion::ParEvacFailureClaimValue)) { if (hr->evacuation_failed()) { - RemoveSelfForwardPtrObjClosure rspc(_g1h, _cm, hr, _update_rset_cl, + RemoveSelfForwardPtrObjClosure rspc(_g1h, _cm, hr, &_update_rset_cl, during_initial_mark, during_conc_mark, _worker_id); @@ -214,7 +216,7 @@ public: // whenever this might be required in the future. hr->rem_set()->reset_for_par_iteration(); hr->reset_bot(); - _update_rset_cl->set_region(hr); + _update_rset_cl.set_region(hr); hr->object_iterate(&rspc); hr->rem_set()->clean_strong_code_roots(hr); @@ -238,16 +240,7 @@ public: _g1h(g1h) { } void work(uint worker_id) { - UpdateRSetImmediate immediate_update(_g1h->g1_rem_set()); - DirtyCardQueue dcq(&_g1h->dirty_card_queue_set()); - UpdateRSetDeferred deferred_update(_g1h, &dcq); - - OopsInHeapRegionClosure *update_rset_cl = &deferred_update; - if (!G1DeferredRSUpdate) { - update_rset_cl = &immediate_update; - } - - RemoveSelfForwardPtrHRClosure rsfp_cl(_g1h, update_rset_cl, worker_id); + RemoveSelfForwardPtrHRClosure rsfp_cl(_g1h, worker_id); HeapRegion* hr = _g1h->start_cset_region_for_worker(worker_id); _g1h->collection_set_iterate_from(hr, &rsfp_cl); diff --git a/hotspot/src/share/vm/gc_implementation/g1/g1GCPhaseTimes.cpp b/hotspot/src/share/vm/gc_implementation/g1/g1GCPhaseTimes.cpp index bf7e3533b71..13d1c9de7d7 100644 --- a/hotspot/src/share/vm/gc_implementation/g1/g1GCPhaseTimes.cpp +++ b/hotspot/src/share/vm/gc_implementation/g1/g1GCPhaseTimes.cpp @@ -237,10 +237,8 @@ void G1GCPhaseTimes::note_gc_end() { _last_gc_worker_times_ms.verify(); _last_gc_worker_other_times_ms.verify(); - if (G1DeferredRSUpdate) { - _last_redirty_logged_cards_time_ms.verify(); - _last_redirty_logged_cards_processed_cards.verify(); - } + _last_redirty_logged_cards_time_ms.verify(); + _last_redirty_logged_cards_processed_cards.verify(); } void G1GCPhaseTimes::note_string_dedup_fixup_start() { @@ -352,12 +350,10 @@ void G1GCPhaseTimes::print(double pause_time_sec) { _recorded_non_young_cset_choice_time_ms)); print_stats(2, "Ref Proc", _cur_ref_proc_time_ms); print_stats(2, "Ref Enq", _cur_ref_enq_time_ms); - if (G1DeferredRSUpdate) { - print_stats(2, "Redirty Cards", _recorded_redirty_logged_cards_time_ms); - if (G1Log::finest()) { - _last_redirty_logged_cards_time_ms.print(3, "Parallel Redirty"); - _last_redirty_logged_cards_processed_cards.print(3, "Redirtied Cards"); - } + print_stats(2, "Redirty Cards", _recorded_redirty_logged_cards_time_ms); + if (G1Log::finest()) { + _last_redirty_logged_cards_time_ms.print(3, "Parallel Redirty"); + _last_redirty_logged_cards_processed_cards.print(3, "Redirtied Cards"); } if (G1ReclaimDeadHumongousObjectsAtYoungGC) { print_stats(2, "Humongous Reclaim", _cur_fast_reclaim_humongous_time_ms); diff --git a/hotspot/src/share/vm/gc_implementation/g1/g1ParScanThreadState.hpp b/hotspot/src/share/vm/gc_implementation/g1/g1ParScanThreadState.hpp index e590a9ee86d..2878e09448c 100644 --- a/hotspot/src/share/vm/gc_implementation/g1/g1ParScanThreadState.hpp +++ b/hotspot/src/share/vm/gc_implementation/g1/g1ParScanThreadState.hpp @@ -84,20 +84,6 @@ class G1ParScanThreadState : public StackObj { DirtyCardQueue& dirty_card_queue() { return _dcq; } G1SATBCardTableModRefBS* ctbs() { return _ct_bs; } - template inline void immediate_rs_update(HeapRegion* from, T* p, int tid); - - template void deferred_rs_update(HeapRegion* from, T* p, int tid) { - // If the new value of the field points to the same region or - // is the to-space, we don't need to include it in the Rset updates. - if (!from->is_in_reserved(oopDesc::load_decode_heap_oop(p)) && !from->is_survivor()) { - size_t card_index = ctbs()->index_for(p); - // If the card hasn't been added to the buffer, do it. - if (ctbs()->mark_card_deferred(card_index)) { - dirty_card_queue().enqueue((jbyte*)ctbs()->byte_for_index(card_index)); - } - } - } - public: G1ParScanThreadState(G1CollectedHeap* g1h, uint queue_num, ReferenceProcessor* rp); ~G1ParScanThreadState(); @@ -124,8 +110,17 @@ class G1ParScanThreadState : public StackObj { _refs->push(ref); } - template inline void update_rs(HeapRegion* from, T* p, int tid); - + template void update_rs(HeapRegion* from, T* p, int tid) { + // If the new value of the field points to the same region or + // is the to-space, we don't need to include it in the Rset updates. + if (!from->is_in_reserved(oopDesc::load_decode_heap_oop(p)) && !from->is_survivor()) { + size_t card_index = ctbs()->index_for(p); + // If the card hasn't been added to the buffer, do it. + if (ctbs()->mark_card_deferred(card_index)) { + dirty_card_queue().enqueue((jbyte*)ctbs()->byte_for_index(card_index)); + } + } + } private: inline HeapWord* allocate(GCAllocPurpose purpose, size_t word_sz); diff --git a/hotspot/src/share/vm/gc_implementation/g1/g1ParScanThreadState.inline.hpp b/hotspot/src/share/vm/gc_implementation/g1/g1ParScanThreadState.inline.hpp index 75517fb3f9d..3fb1829f20d 100644 --- a/hotspot/src/share/vm/gc_implementation/g1/g1ParScanThreadState.inline.hpp +++ b/hotspot/src/share/vm/gc_implementation/g1/g1ParScanThreadState.inline.hpp @@ -29,20 +29,6 @@ #include "gc_implementation/g1/g1RemSet.inline.hpp" #include "oops/oop.inline.hpp" -template inline void G1ParScanThreadState::immediate_rs_update(HeapRegion* from, T* p, int tid) { - if (!from->is_survivor()) { - _g1_rem->par_write_ref(from, p, tid); - } -} - -template void G1ParScanThreadState::update_rs(HeapRegion* from, T* p, int tid) { - if (G1DeferredRSUpdate) { - deferred_rs_update(from, p, tid); - } else { - immediate_rs_update(from, p, tid); - } -} - template void G1ParScanThreadState::do_oop_evac(T* p, HeapRegion* from) { assert(!oopDesc::is_null(oopDesc::load_decode_heap_oop(p)), "Reference should not be NULL here as such are never pushed to the task queue."); diff --git a/hotspot/src/share/vm/gc_implementation/g1/g1RemSet.cpp b/hotspot/src/share/vm/gc_implementation/g1/g1RemSet.cpp index f1628f63968..94d77b4043f 100644 --- a/hotspot/src/share/vm/gc_implementation/g1/g1RemSet.cpp +++ b/hotspot/src/share/vm/gc_implementation/g1/g1RemSet.cpp @@ -339,12 +339,8 @@ void G1RemSet::oops_into_collection_set_do(OopsInHeapRegionClosure* oc, // are just discarded (there's no need to update the RSets of regions // that were in the collection set - after the pause these regions // are wholly 'free' of live objects. In the event of an evacuation - // failure the cards/buffers in this queue set are: - // * passed to the DirtyCardQueueSet that is used to manage deferred - // RSet updates, or - // * scanned for references that point into the collection set - // and the RSet of the corresponding region in the collection set - // is updated immediately. + // failure the cards/buffers in this queue set are passed to the + // DirtyCardQueueSet that is used to manage RSet updates DirtyCardQueue into_cset_dcq(&_g1->into_cset_dirty_card_queue_set()); assert((ParallelGCThreads > 0) || worker_i == 0, "invariant"); @@ -358,7 +354,6 @@ void G1RemSet::oops_into_collection_set_do(OopsInHeapRegionClosure* oc, void G1RemSet::prepare_for_oops_into_collection_set_do() { cleanupHRRS(); - ConcurrentG1Refine* cg1r = _g1->concurrent_g1_refine(); _g1->set_refine_cte_cl_concurrency(false); DirtyCardQueueSet& dcqs = JavaThread::dirty_card_queue_set(); dcqs.concatenate_logs(); @@ -371,66 +366,6 @@ void G1RemSet::prepare_for_oops_into_collection_set_do() { _total_cards_scanned = 0; } - -// This closure, applied to a DirtyCardQueueSet, is used to immediately -// update the RSets for the regions in the CSet. For each card it iterates -// through the oops which coincide with that card. It scans the reference -// fields in each oop; when it finds an oop that points into the collection -// set, the RSet for the region containing the referenced object is updated. -class UpdateRSetCardTableEntryIntoCSetClosure: public CardTableEntryClosure { - G1CollectedHeap* _g1; - CardTableModRefBS* _ct_bs; -public: - UpdateRSetCardTableEntryIntoCSetClosure(G1CollectedHeap* g1, - CardTableModRefBS* bs): - _g1(g1), _ct_bs(bs) - { } - - bool do_card_ptr(jbyte* card_ptr, uint worker_i) { - // Construct the region representing the card. - HeapWord* start = _ct_bs->addr_for(card_ptr); - // And find the region containing it. - HeapRegion* r = _g1->heap_region_containing(start); - - // Scan oops in the card looking for references into the collection set - // Don't use addr_for(card_ptr + 1) which can ask for - // a card beyond the heap. This is not safe without a perm - // gen. - HeapWord* end = start + CardTableModRefBS::card_size_in_words; - MemRegion scanRegion(start, end); - - UpdateRSetImmediate update_rs_cl(_g1->g1_rem_set()); - FilterIntoCSClosure update_rs_cset_oop_cl(NULL, _g1, &update_rs_cl); - FilterOutOfRegionClosure filter_then_update_rs_cset_oop_cl(r, &update_rs_cset_oop_cl); - - // We can pass false as the "filter_young" parameter here as: - // * we should be in a STW pause, - // * the DCQS to which this closure is applied is used to hold - // references that point into the collection set from the prior - // RSet updating, - // * the post-write barrier shouldn't be logging updates to young - // regions (but there is a situation where this can happen - see - // the comment in G1RemSet::refine_card() below - - // that should not be applicable here), and - // * during actual RSet updating, the filtering of cards in young - // regions in HeapRegion::oops_on_card_seq_iterate_careful is - // employed. - // As a result, when this closure is applied to "refs into cset" - // DCQS, we shouldn't see any cards in young regions. - update_rs_cl.set_region(r); - HeapWord* stop_point = - r->oops_on_card_seq_iterate_careful(scanRegion, - &filter_then_update_rs_cset_oop_cl, - false /* filter_young */, - NULL /* card_ptr */); - - // Since this is performed in the event of an evacuation failure, we - // we shouldn't see a non-null stop point - assert(stop_point == NULL, "saw an unallocated region"); - return true; - } -}; - void G1RemSet::cleanup_after_oops_into_collection_set_do() { guarantee( _cards_scanned != NULL, "invariant" ); _total_cards_scanned = 0; @@ -451,25 +386,10 @@ void G1RemSet::cleanup_after_oops_into_collection_set_do() { double restore_remembered_set_start = os::elapsedTime(); // Restore remembered sets for the regions pointing into the collection set. - if (G1DeferredRSUpdate) { - // If deferred RS updates are enabled then we just need to transfer - // the completed buffers from (a) the DirtyCardQueueSet used to hold - // cards that contain references that point into the collection set - // to (b) the DCQS used to hold the deferred RS updates - _g1->dirty_card_queue_set().merge_bufferlists(&into_cset_dcqs); - } else { - - CardTableModRefBS* bs = (CardTableModRefBS*)_g1->barrier_set(); - UpdateRSetCardTableEntryIntoCSetClosure update_rs_cset_immediate(_g1, bs); - - int n_completed_buffers = 0; - while (into_cset_dcqs.apply_closure_to_completed_buffer(&update_rs_cset_immediate, - 0, 0, true)) { - n_completed_buffers++; - } - assert(n_completed_buffers == into_cset_n_buffers, "missed some buffers"); - } - + // We just need to transfer the completed buffers from the DirtyCardQueueSet + // used to hold cards that contain references that point into the collection set + // to the DCQS used to hold the deferred RS updates. + _g1->dirty_card_queue_set().merge_bufferlists(&into_cset_dcqs); _g1->g1_policy()->phase_times()->record_evac_fail_restore_remsets((os::elapsedTime() - restore_remembered_set_start) * 1000.0); } diff --git a/hotspot/src/share/vm/gc_implementation/g1/g1RemSet.hpp b/hotspot/src/share/vm/gc_implementation/g1/g1RemSet.hpp index 35279a52e20..5a629fad2d0 100644 --- a/hotspot/src/share/vm/gc_implementation/g1/g1RemSet.hpp +++ b/hotspot/src/share/vm/gc_implementation/g1/g1RemSet.hpp @@ -193,18 +193,4 @@ public: bool apply_to_weak_ref_discovered_field() { return true; } }; -class UpdateRSetImmediate: public OopsInHeapRegionClosure { -private: - G1RemSet* _g1_rem_set; - - template void do_oop_work(T* p); -public: - UpdateRSetImmediate(G1RemSet* rs) : - _g1_rem_set(rs) {} - - virtual void do_oop(narrowOop* p) { do_oop_work(p); } - virtual void do_oop( oop* p) { do_oop_work(p); } -}; - - #endif // SHARE_VM_GC_IMPLEMENTATION_G1_G1REMSET_HPP diff --git a/hotspot/src/share/vm/gc_implementation/g1/g1RemSet.inline.hpp b/hotspot/src/share/vm/gc_implementation/g1/g1RemSet.inline.hpp index 949614b28fc..1afef2fb501 100644 --- a/hotspot/src/share/vm/gc_implementation/g1/g1RemSet.inline.hpp +++ b/hotspot/src/share/vm/gc_implementation/g1/g1RemSet.inline.hpp @@ -79,13 +79,4 @@ inline void UpdateRSOopClosure::do_oop_work(T* p) { _rs->par_write_ref(_from, p, _worker_i); } -template -inline void UpdateRSetImmediate::do_oop_work(T* p) { - assert(_from->is_in_reserved(p), "paranoia"); - T heap_oop = oopDesc::load_heap_oop(p); - if (!oopDesc::is_null(heap_oop) && !_from->is_survivor()) { - _g1_rem_set->par_write_ref(_from, p, 0); - } -} - #endif // SHARE_VM_GC_IMPLEMENTATION_G1_G1REMSET_INLINE_HPP diff --git a/hotspot/src/share/vm/gc_implementation/g1/g1_globals.hpp b/hotspot/src/share/vm/gc_implementation/g1/g1_globals.hpp index 1913327309c..8a3b7386f85 100644 --- a/hotspot/src/share/vm/gc_implementation/g1/g1_globals.hpp +++ b/hotspot/src/share/vm/gc_implementation/g1/g1_globals.hpp @@ -108,9 +108,6 @@ develop(bool, G1RSBarrierRegionFilter, true, \ "If true, generate region filtering code in RS barrier") \ \ - develop(bool, G1DeferredRSUpdate, true, \ - "If true, use deferred RS updates") \ - \ develop(bool, G1RSLogCheckCardTable, false, \ "If true, verify that no dirty cards remain after RS log " \ "processing.") \ diff --git a/hotspot/test/gc/g1/TestDeferredRSUpdate.java b/hotspot/test/gc/g1/TestDeferredRSUpdate.java deleted file mode 100644 index f00967d1df4..00000000000 --- a/hotspot/test/gc/g1/TestDeferredRSUpdate.java +++ /dev/null @@ -1,79 +0,0 @@ -/* - * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -/* - * @test TestDeferredRSUpdate - * @bug 8040977 8052170 - * @summary Ensure that running with -XX:-G1DeferredRSUpdate does not crash the VM - * @key gc - * @library /testlibrary - */ - -import com.oracle.java.testlibrary.ProcessTools; -import com.oracle.java.testlibrary.OutputAnalyzer; - -public class TestDeferredRSUpdate { - public static void main(String[] args) throws Exception { - GCTest.main(args); - - ProcessBuilder pb = ProcessTools.createJavaProcessBuilder("-XX:+UseG1GC", - "-Xmx10M", - "-XX:+PrintGCDetails", - // G1DeferredRSUpdate is a develop option, but we cannot limit execution of this test to only debug VMs. - "-XX:+IgnoreUnrecognizedVMOptions", - "-XX:-G1DeferredRSUpdate", - GCTest.class.getName()); - - OutputAnalyzer output = new OutputAnalyzer(pb.start()); - output.shouldHaveExitValue(0); - } - - static class GCTest { - private static Object[] garbage = new Object[32]; - - public static void main(String [] args) { - System.out.println("Creating garbage"); - // Create 128MB of garbage. This should result in at least one minor GC, with - // some objects copied to old gen. As references from old to young are installed, - // the crash due to the use before initialize occurs. - Object prev = null; - Object prevPrev = null; - for (int i = 0; i < 1024; i++) { - Object[] next = new Object[32 * 1024]; - next[0] = prev; - next[1] = prevPrev; - - Object[] cur = (Object[]) garbage[i % garbage.length]; - if (cur != null) { - cur[0] = null; - cur[1] = null; - } - garbage[i % garbage.length] = next; - - prevPrev = prev; - prev = next; - } - System.out.println("Done"); - } - } -} From beef99304666df8304348ae6272bb9f8332a8548 Mon Sep 17 00:00:00 2001 From: Erik Joelsson Date: Tue, 16 Sep 2014 12:08:04 +0200 Subject: [PATCH 52/81] 8058118: Generate modules.list during the build Reviewed-by: alanb, ihse, tbell, mchung --- Makefile | 8 ++--- common/autoconf/spec.gmk.in | 1 + make/Main.gmk | 2 +- make/common/Modules.gmk | 39 +++++++++++++++------ make/common/SetupJavaCompilers.gmk | 6 ++++ make/common/modules.list | 54 ------------------------------ modules.xml | 9 +++++ 7 files changed, 50 insertions(+), 69 deletions(-) delete mode 100644 make/common/modules.list diff --git a/Makefile b/Makefile index d385e0f3299..d4b36e4539d 100644 --- a/Makefile +++ b/Makefile @@ -70,8 +70,8 @@ else # Run the makefile with an arbitrary SPEC using -p -q (quiet dry-run and dump rules) to find # available PHONY targets. Use this list as valid targets to pass on to the repeated calls. all_phony_targets := $(sort $(filter-out $(global_targets), $(strip $(shell \ - cd $(root_dir)/make && $(MAKE) -f Main.gmk -p -q FRC SPEC=$(firstword $(SPEC)) | \ - grep "^.PHONY:" | head -n 1 | cut -d " " -f 2-)))) + cd $(root_dir)/make && $(MAKE) -f Main.gmk -p -q FRC SPEC=$(firstword $(SPEC)) \ + -I $(root_dir)/make/common | grep "^.PHONY:" | head -n 1 | cut -d " " -f 2-)))) # Loop through the configurations and call the main-wrapper for each one. The wrapper # target will execute with a single configuration loaded. @@ -115,12 +115,12 @@ else main-wrapper: ifneq ($(SEQUENTIAL_TARGETS), ) - (cd $(root_dir)/make && $(MAKE) -f Main.gmk SPEC=$(SPEC) -j 1 \ + (cd $(SRC_ROOT)/make && $(MAKE) -f Main.gmk SPEC=$(SPEC) -j 1 \ $(VERBOSE) VERBOSE=$(VERBOSE) LOG_LEVEL=$(LOG_LEVEL) $(SEQUENTIAL_TARGETS)) endif ifneq ($(PARALLEL_TARGETS), ) @$(call AtMakeStart) - (cd $(root_dir)/make && $(BUILD_LOG_WRAPPER) $(MAKE) -f Main.gmk SPEC=$(SPEC) -j $(JOBS) \ + (cd $(SRC_ROOT)/make && $(BUILD_LOG_WRAPPER) $(MAKE) -f Main.gmk SPEC=$(SPEC) -j $(JOBS) \ $(VERBOSE) VERBOSE=$(VERBOSE) LOG_LEVEL=$(LOG_LEVEL) $(PARALLEL_TARGETS) \ $(if $(filter true, $(OUTPUT_SYNC_SUPPORTED)), -O$(OUTPUT_SYNC))) @$(call AtMakeEnd) diff --git a/common/autoconf/spec.gmk.in b/common/autoconf/spec.gmk.in index e85c830783c..00e45f90c72 100644 --- a/common/autoconf/spec.gmk.in +++ b/common/autoconf/spec.gmk.in @@ -245,6 +245,7 @@ JDK_OUTPUTDIR=$(BUILD_OUTPUT)/jdk NASHORN_OUTPUTDIR=$(BUILD_OUTPUT)/nashorn IMAGES_OUTPUTDIR=$(BUILD_OUTPUT)/images TESTMAKE_OUTPUTDIR=$(BUILD_OUTPUT)/testmake +MAKESUPPORT_OUTPUTDIR=$(BUILD_OUTPUT)/make-support LANGTOOLS_DIST=$(LANGTOOLS_OUTPUTDIR)/dist CORBA_DIST=$(CORBA_OUTPUTDIR)/dist diff --git a/make/Main.gmk b/make/Main.gmk index aa87b6ff601..2a4eb550250 100644 --- a/make/Main.gmk +++ b/make/Main.gmk @@ -493,7 +493,7 @@ ALL_TARGETS += default all # file. CLEAN_COMPONENTS += langtools corba hotspot jdk nashorn images \ - bootcycle-build docs docstemp test + bootcycle-build docs docstemp test make-support CLEAN_TARGETS := $(addprefix clean-, $(CLEAN_COMPONENTS)) # Remove everything, except the output from configure. diff --git a/make/common/Modules.gmk b/make/common/Modules.gmk index 87b03f8b0ec..248f3ab6dbe 100644 --- a/make/common/Modules.gmk +++ b/make/common/Modules.gmk @@ -26,6 +26,9 @@ ifndef _MODULES_GMK _MODULES_GMK := 1 +include JavaCompilation.gmk +include SetupJavaCompilers.gmk + ################################################################################ # Module list macros @@ -50,8 +53,32 @@ define FindJavaModules $(patsubst %,%/*/$(OPENJDK_TARGET_OS)/classes/*, $(ALL_TOP_SRC_DIRS)))))))))))) endef -MODULES_LIST_FILE := $(SRC_ROOT)/make/common/modules.list -MODULE_DEPS_MAKEFILE := $(OUTPUT_ROOT)/module-deps.gmk +# Find all modules with source for the target platform. +define FindAllModules + $(sort $(filter-out closed demo sample, $(notdir $(patsubst %/,%, $(dir \ + $(wildcard $(patsubst %, %/*/share, $(ALL_TOP_SRC_DIRS)) \ + $(patsubst %, %/*/$(OPENJDK_TARGET_OS), $(ALL_TOP_SRC_DIRS)) \ + $(patsubst %, %/*/$(OPENJDK_TARGET_OS_API_DIR), $(ALL_TOP_SRC_DIRS)))))))) +endef + +################################################################################ + +$(eval $(call SetupJavaCompilation,BUILD_GENMODULESLIST, \ + SETUP := BOOT_JAVAC, \ + SRC := $(JDK_TOPDIR)/make/src/classes, \ + INCLUDES := build/tools/module, \ + BIN := $(MAKESUPPORT_OUTPUTDIR)/bt_classes_moduleslist)) + +TOOL_GENMODULESLIST = $(JAVA_SMALL) \ + -cp "$(MAKESUPPORT_OUTPUTDIR)/bt_classes_moduleslist" \ + build.tools.module.GenModulesList + +MODULES_LIST_FILE := $(MAKESUPPORT_OUTPUTDIR)/modules.list +MODULE_DEPS_MAKEFILE := $(MAKESUPPORT_OUTPUTDIR)/module-deps.gmk + +$(MODULES_LIST_FILE): $(SRC_ROOT)/modules.xml \ + $(BUILD_GENMODULESLIST) + $(TOOL_GENMODULESLIST) -o $@ $(filter %.xml, $^) $(MODULE_DEPS_MAKEFILE): $(MODULES_LIST_FILE) $(CAT) $^ | $(SED) -e 's/^\([^:]*\):/DEPS_\1 :=/g' > $@ @@ -63,14 +90,6 @@ define FindDepsForModule $(DEPS_$(strip $1)) endef -# Find all modules with source for the target platform. -define FindAllModules - $(sort $(filter-out closed demo sample, $(notdir $(patsubst %/,%, $(dir \ - $(wildcard $(patsubst %, %/*/share, $(ALL_TOP_SRC_DIRS)) \ - $(patsubst %, %/*/$(OPENJDK_TARGET_OS), $(ALL_TOP_SRC_DIRS)) \ - $(patsubst %, %/*/$(OPENJDK_TARGET_OS_API_DIR), $(ALL_TOP_SRC_DIRS)))))))) -endef - ################################################################################ # Hook to include the corresponding custom file, if present. diff --git a/make/common/SetupJavaCompilers.gmk b/make/common/SetupJavaCompilers.gmk index 6c3cb0b119e..c9aa92075e5 100644 --- a/make/common/SetupJavaCompilers.gmk +++ b/make/common/SetupJavaCompilers.gmk @@ -34,6 +34,12 @@ DISABLE_WARNINGS := -Xlint:all,-deprecation,-unchecked,-rawtypes,-cast,-serial,- # make JAVAC_WARNINGS="-Xlint:all -Xmaxwarns 10000" JAVAC_WARNINGS := -Xlint:all,-deprecation -Werror +# The BOOT_JAVAC setup uses the boot jdk compiler to compile the tools +# and the interim javac, to be run by the boot jdk. +$(eval $(call SetupJavaCompiler,BOOT_JAVAC, \ + JAVAC := $(JAVAC), \ + FLAGS := -XDignore.symbol.file=true -g -Xlint:all$(COMMA)-deprecation -Werror)) + # Any java code executed during a JDK build to build other parts of the JDK must be # executed by the bootstrap JDK (probably with -Xbootclasspath/p: ) and for this # purpose must be built with -target PREVIOUS for bootstrapping purposes, which diff --git a/make/common/modules.list b/make/common/modules.list deleted file mode 100644 index f2a3daa4c46..00000000000 --- a/make/common/modules.list +++ /dev/null @@ -1,54 +0,0 @@ -java.base: -java.logging: java.base -java.security.sasl: java.logging java.base -java.naming: java.security.sasl java.base -java.security.acl: java.base -jdk.charsets: java.base -java.scripting: java.base -java.xml: java.base -java.sql: java.xml java.logging java.base -jdk.scripting.nashorn: java.scripting java.logging java.base -java.rmi: java.logging java.base -java.prefs: java.xml java.base -java.desktop: jdk.charsets java.prefs java.xml java.logging java.base -java.corba: java.naming java.rmi java.desktop java.logging java.base -java.compiler: java.logging java.base -jdk.compiler: java.compiler java.base -jdk.javadoc: java.compiler java.xml jdk.compiler java.base -jdk.rmic: java.corba jdk.compiler jdk.javadoc java.base -jdk.jvmstat: java.rmi java.base -jdk.attach: jdk.jvmstat java.base -jdk.jcmd: jdk.jvmstat jdk.attach java.base -jdk.jdi: jdk.attach java.base -jdk.hotspot.agent: java.rmi java.scripting java.desktop java.base jdk.jdi -jdk.hprof.agent: java.base -java.management: java.naming java.rmi java.logging java.base -jdk.jconsole: java.management jdk.jvmstat java.rmi jdk.attach java.desktop java.logging java.base -java.activation: java.desktop java.logging java.base -java.xml.bind: java.activation java.compiler java.xml java.desktop java.logging java.base -jdk.xml.bind: java.activation java.compiler java.xml.bind java.xml java.desktop java.logging jdk.compiler java.base -jdk.httpserver: java.logging java.base -java.annotations.common: java.base -java.xml.soap: java.activation java.xml.bind java.xml java.desktop java.logging java.base -java.xml.ws: java.activation java.management jdk.httpserver java.rmi java.annotations.common java.xml.bind java.xml java.desktop java.logging java.xml.soap java.base -jdk.xml.ws: jdk.xml.bind java.compiler java.rmi java.xml.ws java.xml.bind java.xml java.logging java.base -java.sql.rowset: java.naming java.sql java.xml java.logging java.base -java.instrument: java.base -java.security.jgss: java.naming java.security.sasl java.logging java.base -java.xml.crypto: java.xml java.logging java.base -jdk.localedata: java.base -jdk.crypto.ec: java.base -jdk.crypto.pkcs11: jdk.crypto.ec java.base -jdk.crypto.mscapi: java.base -jdk.naming.rmi: java.naming java.rmi java.base -jdk.zipfs: java.base -jdk.naming.dns: java.naming java.base -java.smartcardio: java.base -jdk.dev: jdk.xml.bind jdk.xml.ws java.scripting jdk.rmic java.xml jdk.compiler java.base -jdk.snmp: java.management java.security.acl java.logging java.base -jdk.jdwp.agent: java.base -jdk.security.auth: java.naming java.security.jgss java.base -jdk.sctp: java.base -jdk.runtime: java.desktop java.base -jdk.jfr: java.management java.xml java.base -jdk.deploy.osx: java.scripting java.desktop java.base diff --git a/modules.xml b/modules.xml index 2e287a5f3be..162cd7e0125 100644 --- a/modules.xml +++ b/modules.xml @@ -327,6 +327,7 @@ sun.security.internal.spec + jdk.crypto.mscapi jdk.crypto.pkcs11 jdk.crypto.ucrypto @@ -731,6 +732,10 @@ javax.swing.undo + + sun.awt + oracle.accessbridge + java.instrument @@ -1570,6 +1575,10 @@ jdk.crypto.pkcs11 + + jdk.crypto.mscapi + java.base + jdk.crypto.pkcs11 java.base From 4dd455e254342542b7d20ab23f35bcbe10f99565 Mon Sep 17 00:00:00 2001 From: Athijegannathan Sundararajan Date: Tue, 16 Sep 2014 17:04:35 +0530 Subject: [PATCH 53/81] 8058545: With strict mode, bean property assignment of a non-existent property should result in TypeError Reviewed-by: hannesw, lagergren --- nashorn/README | 153 +----------------- .../runtime/linker/NashornBottomLinker.java | 7 +- nashorn/test/script/basic/JDK-8058545.js | 41 +++++ 3 files changed, 48 insertions(+), 153 deletions(-) create mode 100644 nashorn/test/script/basic/JDK-8058545.js diff --git a/nashorn/README b/nashorn/README index 242d6077b67..5e25297509d 100644 --- a/nashorn/README +++ b/nashorn/README @@ -1,152 +1 @@ -- What is Nashorn? - -Nashorn is a runtime environment for programs written in ECMAScript 5.1 -that runs on top of JVM. - -- How to find out more about ECMAScript 5.1? - -The specification can be found at - - http://www.ecma-international.org/publications/standards/Ecma-262.htm - -- How to checkout sources of Nashorn project? - -Nashorn project uses Mercurial source code control system. You can -download Mercurial from http://mercurial.selenic.com/wiki/Download - -Information about the forest extension can be found at - - http://mercurial.selenic.com/wiki/ForestExtension - -and downlaoded using - - hg clone https://bitbucket.org/gxti/hgforest - -You can clone Nashorn Mercurial forest using this command: - - hg fclone http://hg.openjdk.java.net/nashorn/jdk8 nashorn~jdk8 - -To update your copy of the forest (fwith the latest code: - - (cd nashorn~jdk8 ; hg fpull) - -Or just the nashorn subdirectory with - - (cd nashorn~jdk8/nashorn ; hg pull -u) - -To learn about Mercurial in detail, please visit http://hgbook.red-bean.com. - -- How to build? - -To build Nashorn, you need to install JDK 8. You may use the Nashorn -forest build (recommended) or down load from java.net. You will need to -set JAVA_HOME environmental variable to point to your JDK installation -directory. - - cd nashorn~jdk8/nashorn/make - ant clean; ant - -- How to run? - -Use the jjs script (see RELESE_README): - - cd nashorn~jdk8/nashorn - sh bin/jjs - -Nashorn supports javax.script API. It is possible to drop nashorn.jar in -class path and request for "nashorn" script engine from -javax.script.ScriptEngineManager. - -Look for samples under the directory test/src/jdk/nashorn/api/scripting/. - -- Documentation - -Comprehensive development documentation is found in the Nashorn JavaDoc. You can -build it using: - - cd nashorn~jdk8/nashorn/make - ant javadoc - -after which you can view the generated documentation at dist/javadoc/index.html. - -- Running tests - -Nashorn tests are TestNG based. Running tests requires downloading the -TestNG library and placing its jar file into the lib subdirectory: - - # download and install TestNG - wget http://testng.org/testng-x.y.z.zip - unzip testng-x.y.z.zip - cp testng-x.y.z/testng-x.y.z.jar test/lib/testng.jar - -After that, you can run the tests using: - cd make - ant clean test - -You can also run the ECMA-262 test suite with Nashorn. In order to do -that, you will need to get a copy of it and put it in -test/script/external/test262 directory. A convenient way to do it is: - - git clone https://github.com/tc39/test262 test/script/external/test262 - -Alternatively, you can check it out elsewhere and make -test/script/external/test262 a symbolic link to that directory. After -you've done this, you can run the ECMA-262 tests using: - - cd nashorn~jdk8/nashorn/make - ant test262 - -Ant target to get/update external test suites: - - ant externals - ant update-externals - -These tests take time, so we have a parallelized runner for them that -takes advantage of all processor cores on the computer: - - cd nashorn~jdk8/nashorn/make - ant test262parallel - -- How to write your own test? - -Nashorn uses it's own simple test framework. Any .js file dropped under -nashorn/test directory is considered as a test. A test file can -optionally have .js.EXPECTED (foo.js.EXPECTED for foo.js) associated -with it. The .EXPECTED file, if exists, should contain the output -expected from compiling and/or running the test file. - -The test runner crawls these directories for .js files and looks for -JTReg-style @foo comments to identify tests. - - * @test - A test is tagged with @test. - - * @test/fail - Tests that are supposed to fail (compiling, see @run/fail - for runtime) are tagged with @test/fail. - - * @test/compile-error - Test expects compilation to fail, compares - output. - - * @test/warning - Test expects compiler warnings, compares output. - - * @test/nocompare - Test expects to compile [and/or run?] - successfully(may be warnings), does not compare output. - - * @subtest - denotes necessary file for a main test file; itself is not - a test. - - * @run - A test that should be run is also tagged with @run (otherwise - the test runner only compiles the test). - - * @run/fail - A test that should compile but fail with a runtime error. - - * @run/ignore-std-error - script may produce output on stderr, ignore - this output. - - * @argument - pass an argument to script. - - * @option \ - pass option to engine, sample. - -/** - * @option --dump-ir-graph - * @test - */ +8058545: With strict mode, bean property assignment of a non-existent property should result in TypeError diff --git a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/linker/NashornBottomLinker.java b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/linker/NashornBottomLinker.java index f859f7bb631..4ed6e3a26ca 100644 --- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/linker/NashornBottomLinker.java +++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/linker/NashornBottomLinker.java @@ -131,11 +131,16 @@ final class NashornBottomLinker implements GuardingDynamicLinker, GuardingTypeCo } return getInvocation(EMPTY_ELEM_GETTER, self, linkerServices, desc); case "setProp": - case "setElem": + case "setElem": { + final boolean strict = NashornCallSiteDescriptor.isStrict(desc); + if (strict) { + throw typeError("cant.set.property", getArgument(linkRequest), ScriptRuntime.safeToString(self)); + } if (desc.getOperand() != null) { return getInvocation(EMPTY_PROP_SETTER, self, linkerServices, desc); } return getInvocation(EMPTY_ELEM_SETTER, self, linkerServices, desc); + } default: break; } diff --git a/nashorn/test/script/basic/JDK-8058545.js b/nashorn/test/script/basic/JDK-8058545.js new file mode 100644 index 00000000000..3b3a7c60ea8 --- /dev/null +++ b/nashorn/test/script/basic/JDK-8058545.js @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/** + * JDK-8058545: With strict mode, bean property assignment of a non-existent property should result in TypeError + * + * @test + * @run + */ + +'use strict'; +var File = Java.type("java.io.File"); +var f = new File("."); +try { + f.foo = 33; + fail("Should have thrown TypeError"); +} catch (e) { + if (! (e instanceof TypeError)) { + fail("Expected TypeError, got " + e); + } +} From e149222854f2c5a8be6316ca52ee43cd30e86f24 Mon Sep 17 00:00:00 2001 From: Athijegannathan Sundararajan Date: Tue, 16 Sep 2014 17:47:58 +0530 Subject: [PATCH 54/81] 8058551: Top level README accidentally modified with changeset 1025:1d7a917a35e2 Reviewed-by: jlaskey, hannesw --- nashorn/README | 153 ++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 152 insertions(+), 1 deletion(-) diff --git a/nashorn/README b/nashorn/README index 5e25297509d..242d6077b67 100644 --- a/nashorn/README +++ b/nashorn/README @@ -1 +1,152 @@ -8058545: With strict mode, bean property assignment of a non-existent property should result in TypeError +- What is Nashorn? + +Nashorn is a runtime environment for programs written in ECMAScript 5.1 +that runs on top of JVM. + +- How to find out more about ECMAScript 5.1? + +The specification can be found at + + http://www.ecma-international.org/publications/standards/Ecma-262.htm + +- How to checkout sources of Nashorn project? + +Nashorn project uses Mercurial source code control system. You can +download Mercurial from http://mercurial.selenic.com/wiki/Download + +Information about the forest extension can be found at + + http://mercurial.selenic.com/wiki/ForestExtension + +and downlaoded using + + hg clone https://bitbucket.org/gxti/hgforest + +You can clone Nashorn Mercurial forest using this command: + + hg fclone http://hg.openjdk.java.net/nashorn/jdk8 nashorn~jdk8 + +To update your copy of the forest (fwith the latest code: + + (cd nashorn~jdk8 ; hg fpull) + +Or just the nashorn subdirectory with + + (cd nashorn~jdk8/nashorn ; hg pull -u) + +To learn about Mercurial in detail, please visit http://hgbook.red-bean.com. + +- How to build? + +To build Nashorn, you need to install JDK 8. You may use the Nashorn +forest build (recommended) or down load from java.net. You will need to +set JAVA_HOME environmental variable to point to your JDK installation +directory. + + cd nashorn~jdk8/nashorn/make + ant clean; ant + +- How to run? + +Use the jjs script (see RELESE_README): + + cd nashorn~jdk8/nashorn + sh bin/jjs + +Nashorn supports javax.script API. It is possible to drop nashorn.jar in +class path and request for "nashorn" script engine from +javax.script.ScriptEngineManager. + +Look for samples under the directory test/src/jdk/nashorn/api/scripting/. + +- Documentation + +Comprehensive development documentation is found in the Nashorn JavaDoc. You can +build it using: + + cd nashorn~jdk8/nashorn/make + ant javadoc + +after which you can view the generated documentation at dist/javadoc/index.html. + +- Running tests + +Nashorn tests are TestNG based. Running tests requires downloading the +TestNG library and placing its jar file into the lib subdirectory: + + # download and install TestNG + wget http://testng.org/testng-x.y.z.zip + unzip testng-x.y.z.zip + cp testng-x.y.z/testng-x.y.z.jar test/lib/testng.jar + +After that, you can run the tests using: + cd make + ant clean test + +You can also run the ECMA-262 test suite with Nashorn. In order to do +that, you will need to get a copy of it and put it in +test/script/external/test262 directory. A convenient way to do it is: + + git clone https://github.com/tc39/test262 test/script/external/test262 + +Alternatively, you can check it out elsewhere and make +test/script/external/test262 a symbolic link to that directory. After +you've done this, you can run the ECMA-262 tests using: + + cd nashorn~jdk8/nashorn/make + ant test262 + +Ant target to get/update external test suites: + + ant externals + ant update-externals + +These tests take time, so we have a parallelized runner for them that +takes advantage of all processor cores on the computer: + + cd nashorn~jdk8/nashorn/make + ant test262parallel + +- How to write your own test? + +Nashorn uses it's own simple test framework. Any .js file dropped under +nashorn/test directory is considered as a test. A test file can +optionally have .js.EXPECTED (foo.js.EXPECTED for foo.js) associated +with it. The .EXPECTED file, if exists, should contain the output +expected from compiling and/or running the test file. + +The test runner crawls these directories for .js files and looks for +JTReg-style @foo comments to identify tests. + + * @test - A test is tagged with @test. + + * @test/fail - Tests that are supposed to fail (compiling, see @run/fail + for runtime) are tagged with @test/fail. + + * @test/compile-error - Test expects compilation to fail, compares + output. + + * @test/warning - Test expects compiler warnings, compares output. + + * @test/nocompare - Test expects to compile [and/or run?] + successfully(may be warnings), does not compare output. + + * @subtest - denotes necessary file for a main test file; itself is not + a test. + + * @run - A test that should be run is also tagged with @run (otherwise + the test runner only compiles the test). + + * @run/fail - A test that should compile but fail with a runtime error. + + * @run/ignore-std-error - script may produce output on stderr, ignore + this output. + + * @argument - pass an argument to script. + + * @option \ - pass option to engine, sample. + +/** + * @option --dump-ir-graph + * @test + */ From b2620f89c3c3c979e7fed558294a21b5d4524378 Mon Sep 17 00:00:00 2001 From: Albert Noll Date: Tue, 16 Sep 2014 14:39:11 +0200 Subject: [PATCH 55/81] 8058452: ciInstanceKlass::non_static_fields() can be removed CiInstanceKlass::non_static_fields() and all associated data structures can be removed since they are unused. Reviewed-by: kvn, thartmann --- hotspot/src/share/vm/ci/ciField.hpp | 1 - hotspot/src/share/vm/ci/ciInstanceKlass.cpp | 33 +-------------------- hotspot/src/share/vm/ci/ciInstanceKlass.hpp | 4 --- 3 files changed, 1 insertion(+), 37 deletions(-) diff --git a/hotspot/src/share/vm/ci/ciField.hpp b/hotspot/src/share/vm/ci/ciField.hpp index cdd5cf40c55..9711960d92f 100644 --- a/hotspot/src/share/vm/ci/ciField.hpp +++ b/hotspot/src/share/vm/ci/ciField.hpp @@ -39,7 +39,6 @@ class ciField : public ResourceObj { CI_PACKAGE_ACCESS friend class ciEnv; friend class ciInstanceKlass; - friend class NonStaticFieldFiller; private: ciFlags _flags; diff --git a/hotspot/src/share/vm/ci/ciInstanceKlass.cpp b/hotspot/src/share/vm/ci/ciInstanceKlass.cpp index f8b39ed79c9..7a8bad33c6a 100644 --- a/hotspot/src/share/vm/ci/ciInstanceKlass.cpp +++ b/hotspot/src/share/vm/ci/ciInstanceKlass.cpp @@ -44,7 +44,7 @@ // // Loaded instance klass. ciInstanceKlass::ciInstanceKlass(KlassHandle h_k) : - ciKlass(h_k), _non_static_fields(NULL) + ciKlass(h_k) { assert(get_Klass()->oop_is_instance(), "wrong type"); assert(get_instanceKlass()->is_loaded(), "must be at least loaded"); @@ -407,37 +407,6 @@ ciField* ciInstanceKlass::get_field_by_name(ciSymbol* name, ciSymbol* signature, return field; } -// ------------------------------------------------------------------ -// ciInstanceKlass::non_static_fields. - -class NonStaticFieldFiller: public FieldClosure { - GrowableArray* _arr; - ciEnv* _curEnv; -public: - NonStaticFieldFiller(ciEnv* curEnv, GrowableArray* arr) : - _curEnv(curEnv), _arr(arr) - {} - void do_field(fieldDescriptor* fd) { - ciField* field = new (_curEnv->arena()) ciField(fd); - _arr->append(field); - } -}; - -GrowableArray* ciInstanceKlass::non_static_fields() { - if (_non_static_fields == NULL) { - VM_ENTRY_MARK; - ciEnv* curEnv = ciEnv::current(); - InstanceKlass* ik = get_instanceKlass(); - int max_n_fields = ik->java_fields_count(); - - Arena* arena = curEnv->arena(); - _non_static_fields = - new (arena) GrowableArray(arena, max_n_fields, 0, NULL); - NonStaticFieldFiller filler(curEnv, _non_static_fields); - ik->do_nonstatic_fields(&filler); - } - return _non_static_fields; -} static int sort_field_by_offset(ciField** a, ciField** b) { return (*a)->offset_in_bytes() - (*b)->offset_in_bytes(); diff --git a/hotspot/src/share/vm/ci/ciInstanceKlass.hpp b/hotspot/src/share/vm/ci/ciInstanceKlass.hpp index 41c42935a6a..ce39664b711 100644 --- a/hotspot/src/share/vm/ci/ciInstanceKlass.hpp +++ b/hotspot/src/share/vm/ci/ciInstanceKlass.hpp @@ -71,8 +71,6 @@ private: // Itsef: more than one implementors. ciInstanceKlass* _implementor; - GrowableArray* _non_static_fields; - protected: ciInstanceKlass(KlassHandle h_k); ciInstanceKlass(ciSymbol* name, jobject loader, jobject protection_domain); @@ -181,8 +179,6 @@ public: ciField* get_field_by_offset(int field_offset, bool is_static); ciField* get_field_by_name(ciSymbol* name, ciSymbol* signature, bool is_static); - GrowableArray* non_static_fields(); - // total number of nonstatic fields (including inherited): int nof_nonstatic_fields() { if (_nonstatic_fields == NULL) From 652c27e15d87e77c20927459efb6c02bd1713d77 Mon Sep 17 00:00:00 2001 From: Boris Molodenkov Date: Tue, 16 Sep 2014 21:29:30 +0400 Subject: [PATCH 56/81] 8057165: [TESTBUG] Need a test to cover JDK-8054883 Reviewed-by: kvn, iveresov, iignatyev --- hotspot/test/compiler/osr/TestRangeCheck.java | 52 +++++++++++++++++++ 1 file changed, 52 insertions(+) create mode 100644 hotspot/test/compiler/osr/TestRangeCheck.java diff --git a/hotspot/test/compiler/osr/TestRangeCheck.java b/hotspot/test/compiler/osr/TestRangeCheck.java new file mode 100644 index 00000000000..6079cb9ba4f --- /dev/null +++ b/hotspot/test/compiler/osr/TestRangeCheck.java @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test TestRangeCheck + * @bug 8054883 + * @summary Tests that range check is not skipped + */ + +public class TestRangeCheck { + public static void main(String args[]) { + try { + test(); + throw new AssertionError("Expected ArrayIndexOutOfBoundsException was not thrown"); + } catch (ArrayIndexOutOfBoundsException e) { + System.out.println("Expected ArrayIndexOutOfBoundsException was thrown"); + } + } + + private static void test() { + int arr[] = new int[1]; + int result = 1; + + // provoke OSR compilation + for (int i = 0; i < Integer.MAX_VALUE; i++) { + } + + if (result > 0 && arr[~result] > 0) { + arr[~result] = 0; + } + } +} From 21e3c51138f4ec0bbc41b8bffc97306cd4f3b5b2 Mon Sep 17 00:00:00 2001 From: Vladimir Ivanov Date: Tue, 16 Sep 2014 23:04:13 +0400 Subject: [PATCH 57/81] 8058584: Ignore java/lang/invoke/LFCaching/LFGarbageCollectedTest until 8057020 is fixed Reviewed-by: darcy, alanb --- jdk/test/java/lang/invoke/LFCaching/LFGarbageCollectedTest.java | 1 + 1 file changed, 1 insertion(+) diff --git a/jdk/test/java/lang/invoke/LFCaching/LFGarbageCollectedTest.java b/jdk/test/java/lang/invoke/LFCaching/LFGarbageCollectedTest.java index f204074698b..dfa6f58f567 100644 --- a/jdk/test/java/lang/invoke/LFCaching/LFGarbageCollectedTest.java +++ b/jdk/test/java/lang/invoke/LFCaching/LFGarbageCollectedTest.java @@ -26,6 +26,7 @@ * @bug 8046703 * @summary Test verifies that lambda forms are garbage collected * @author kshefov + * @ignore 8057020 * @library /lib/testlibrary/jsr292 /lib/testlibrary * @build TestMethods * @build LambdaFormTestCase From f18f44bce370711b5fbf1bc9dfe6b7aaf25c7abc Mon Sep 17 00:00:00 2001 From: Weijun Wang Date: Wed, 17 Sep 2014 13:55:12 +0800 Subject: [PATCH 58/81] 8042900: Allow com.sun.security.jgss to be in different module than org.ietf.jgss Reviewed-by: valeriep, alanb --- .../sun/security/jgss/ExtendedGSSContext.java | 41 ++++++- .../security/jgss/ExtendedGSSCredential.java | 10 ++ .../com/sun/security/jgss/Extender.java | 56 +++++++++ .../classes/org/ietf/jgss/GSSContext.java | 1 - .../share/classes/org/ietf/jgss/GSSName.java | 4 - .../protocol/http/spnego/NegotiatorImpl.java | 6 +- .../sun/security/jgss/GSSContextImpl.java | 36 ++++-- .../sun/security/jgss/GSSCredentialImpl.java | 18 ++- .../sun/security/jgss/GSSManagerImpl.java | 28 ++++- .../sun/security/jgss/JgssExtender.java | 81 ++++++++++++ .../jgss/krb5/InitSecContextToken.java | 13 +- .../sun/security/jgss/krb5/Krb5Context.java | 22 ++-- .../sun/security/jgss/spi/GSSContextSpi.java | 3 +- .../security/jgss/spnego/SpNegoContext.java | 21 ++-- .../jgss/spnego/SpNegoCredElement.java | 2 - .../jgss/wrapper/NativeGSSContext.java | 3 +- jdk/test/sun/security/krb5/auto/Context.java | 116 ++++++++---------- .../security/krb5/auto/NewInquireTypes.java | 7 +- .../sun/security/krb5/auto/OkAsDelegate.java | 3 +- .../krb5/auto/OkAsDelegateXRealm.java | 4 +- jdk/test/sun/security/krb5/auto/SSL.java | 4 +- 21 files changed, 334 insertions(+), 145 deletions(-) create mode 100644 jdk/src/java.security.jgss/share/classes/com/sun/security/jgss/Extender.java create mode 100644 jdk/src/java.security.jgss/share/classes/sun/security/jgss/JgssExtender.java diff --git a/jdk/src/java.security.jgss/share/classes/com/sun/security/jgss/ExtendedGSSContext.java b/jdk/src/java.security.jgss/share/classes/com/sun/security/jgss/ExtendedGSSContext.java index 0f3a27dfac9..32e6b0412e2 100644 --- a/jdk/src/java.security.jgss/share/classes/com/sun/security/jgss/ExtendedGSSContext.java +++ b/jdk/src/java.security.jgss/share/classes/com/sun/security/jgss/ExtendedGSSContext.java @@ -26,6 +26,8 @@ package com.sun.security.jgss; import org.ietf.jgss.*; +import sun.security.jgss.GSSContextImpl; +import sun.security.krb5.internal.AuthorizationData; /** * The extended GSSContext interface for supporting additional @@ -34,13 +36,48 @@ import org.ietf.jgss.*; */ @jdk.Exported public interface ExtendedGSSContext extends GSSContext { + + // The impl is almost identical to GSSContextImpl with only 2 differences: + // 1. It implements the extended interface + // 2. It translates result to data types here in inquireSecContext + static class ExtendedGSSContextImpl extends GSSContextImpl + implements ExtendedGSSContext { + + public ExtendedGSSContextImpl(GSSContextImpl old) { + super(old); + } + + @Override + public Object inquireSecContext(InquireType type) throws GSSException { + SecurityManager security = System.getSecurityManager(); + if (security != null) { + security.checkPermission( + new InquireSecContextPermission(type.toString())); + } + Object output = super.inquireSecContext(type.name()); + if (output != null) { + if (type == InquireType.KRB5_GET_AUTHZ_DATA) { + AuthorizationData ad = (AuthorizationData) output; + AuthorizationDataEntry[] authzData = + new AuthorizationDataEntry[ad.count()]; + for (int i = 0; i < ad.count(); i++) { + authzData[i] = new AuthorizationDataEntry( + ad.item(i).adType, ad.item(i).adData); + } + output = authzData; + } + } + return output; + } + } + /** * Return the mechanism-specific attribute associated with {@code type}. *

* If there is a security manager, an {@link InquireSecContextPermission} * with the name {@code type.mech} must be granted. Otherwise, this could - * result in a {@link SecurityException}.

- * + * result in a {@link SecurityException}. + *

* Example: *

      *      GSSContext ctxt = m.createContext(...)
diff --git a/jdk/src/java.security.jgss/share/classes/com/sun/security/jgss/ExtendedGSSCredential.java b/jdk/src/java.security.jgss/share/classes/com/sun/security/jgss/ExtendedGSSCredential.java
index 6727ddd99ba..56fe1030744 100644
--- a/jdk/src/java.security.jgss/share/classes/com/sun/security/jgss/ExtendedGSSCredential.java
+++ b/jdk/src/java.security.jgss/share/classes/com/sun/security/jgss/ExtendedGSSCredential.java
@@ -26,6 +26,7 @@
 package com.sun.security.jgss;
 
 import org.ietf.jgss.*;
+import sun.security.jgss.GSSCredentialImpl;
 
 /**
  * The extended GSSCredential interface for supporting additional
@@ -34,6 +35,15 @@ import org.ietf.jgss.*;
  */
 @jdk.Exported
 public interface ExtendedGSSCredential extends GSSCredential {
+
+    static class ExtendedGSSCredentialImpl extends GSSCredentialImpl
+            implements ExtendedGSSCredential {
+
+        public ExtendedGSSCredentialImpl(GSSCredentialImpl old) {
+            super(old);
+        }
+    }
+
     /**
      * Impersonates a principal. In Kerberos, this can be implemented
      * using the Microsoft S4U2self extension.
diff --git a/jdk/src/java.security.jgss/share/classes/com/sun/security/jgss/Extender.java b/jdk/src/java.security.jgss/share/classes/com/sun/security/jgss/Extender.java
new file mode 100644
index 00000000000..c09d7b6a6a7
--- /dev/null
+++ b/jdk/src/java.security.jgss/share/classes/com/sun/security/jgss/Extender.java
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package com.sun.security.jgss;
+
+import org.ietf.jgss.GSSContext;
+import org.ietf.jgss.GSSCredential;
+import sun.security.jgss.GSSContextImpl;
+import sun.security.jgss.GSSCredentialImpl;
+import sun.security.jgss.JgssExtender;
+
+// The com.sun.security.jgss extension to JGSS-API
+class Extender extends JgssExtender {
+
+    static {
+        JgssExtender.setExtender(new Extender());
+    }
+
+    public GSSCredential wrap(GSSCredential cred) {
+        if (cred instanceof ExtendedGSSCredential.ExtendedGSSCredentialImpl) {
+            return cred;
+        } else {
+            return new ExtendedGSSCredential.ExtendedGSSCredentialImpl((GSSCredentialImpl)cred);
+        }
+    }
+
+    public GSSContext wrap(GSSContext ctxt) {
+        if (ctxt instanceof ExtendedGSSContext.ExtendedGSSContextImpl) {
+            return ctxt;
+        } else {
+            return new ExtendedGSSContext.ExtendedGSSContextImpl((GSSContextImpl)ctxt);
+        }
+    }
+}
diff --git a/jdk/src/java.security.jgss/share/classes/org/ietf/jgss/GSSContext.java b/jdk/src/java.security.jgss/share/classes/org/ietf/jgss/GSSContext.java
index d0c6b833503..48c77e6988e 100644
--- a/jdk/src/java.security.jgss/share/classes/org/ietf/jgss/GSSContext.java
+++ b/jdk/src/java.security.jgss/share/classes/org/ietf/jgss/GSSContext.java
@@ -25,7 +25,6 @@
 
 package org.ietf.jgss;
 
-import sun.security.jgss.spi.*;
 import java.io.InputStream;
 import java.io.OutputStream;
 
diff --git a/jdk/src/java.security.jgss/share/classes/org/ietf/jgss/GSSName.java b/jdk/src/java.security.jgss/share/classes/org/ietf/jgss/GSSName.java
index c3626ac8c63..580ab39383a 100644
--- a/jdk/src/java.security.jgss/share/classes/org/ietf/jgss/GSSName.java
+++ b/jdk/src/java.security.jgss/share/classes/org/ietf/jgss/GSSName.java
@@ -25,10 +25,6 @@
 
 package org.ietf.jgss;
 
-import sun.security.jgss.spi.*;
-import java.util.Vector;
-import java.util.Enumeration;
-
 /**
  * This interface encapsulates a single GSS-API principal entity. The
  * application obtains an implementation of this interface
diff --git a/jdk/src/java.security.jgss/share/classes/sun/net/www/protocol/http/spnego/NegotiatorImpl.java b/jdk/src/java.security.jgss/share/classes/sun/net/www/protocol/http/spnego/NegotiatorImpl.java
index e241a36c708..60dea44e3b9 100644
--- a/jdk/src/java.security.jgss/share/classes/sun/net/www/protocol/http/spnego/NegotiatorImpl.java
+++ b/jdk/src/java.security.jgss/share/classes/sun/net/www/protocol/http/spnego/NegotiatorImpl.java
@@ -25,7 +25,6 @@
 
 package sun.net.www.protocol.http.spnego;
 
-import com.sun.security.jgss.ExtendedGSSContext;
 import java.io.IOException;
 
 import org.ietf.jgss.GSSContext;
@@ -36,6 +35,7 @@ import org.ietf.jgss.Oid;
 import sun.net.www.protocol.http.HttpCallerInfo;
 import sun.net.www.protocol.http.Negotiator;
 import sun.security.jgss.GSSManagerImpl;
+import sun.security.jgss.GSSContextImpl;
 import sun.security.jgss.GSSUtil;
 import sun.security.jgss.HttpCaller;
 
@@ -102,8 +102,8 @@ public class NegotiatorImpl extends Negotiator {
                                         GSSContext.DEFAULT_LIFETIME);
 
         // Always respect delegation policy in HTTP/SPNEGO.
-        if (context instanceof ExtendedGSSContext) {
-            ((ExtendedGSSContext)context).requestDelegPolicy(true);
+        if (context instanceof GSSContextImpl) {
+            ((GSSContextImpl)context).requestDelegPolicy(true);
         }
         oneToken = context.initSecContext(new byte[0], 0, 0);
     }
diff --git a/jdk/src/java.security.jgss/share/classes/sun/security/jgss/GSSContextImpl.java b/jdk/src/java.security.jgss/share/classes/sun/security/jgss/GSSContextImpl.java
index b25987ff93d..d1e09de1b77 100644
--- a/jdk/src/java.security.jgss/share/classes/sun/security/jgss/GSSContextImpl.java
+++ b/jdk/src/java.security.jgss/share/classes/sun/security/jgss/GSSContextImpl.java
@@ -33,7 +33,8 @@ import java.io.OutputStream;
 import java.io.ByteArrayInputStream;
 import java.io.ByteArrayOutputStream;
 import java.io.IOException;
-import com.sun.security.jgss.*;
+import java.lang.reflect.Field;
+import java.lang.reflect.Modifier;
 
 /**
  * This class represents the JGSS security context and its associated
@@ -87,10 +88,10 @@ import com.sun.security.jgss.*;
  * per-message operations are returned in an instance of the MessageProp
  * class, which is used as an argument in these calls.
  */
-class GSSContextImpl implements ExtendedGSSContext {
+public class GSSContextImpl implements GSSContext {
 
-    private final GSSManagerImpl gssManager;
-    private final boolean initiator;
+    private GSSManagerImpl gssManager;
+    private boolean initiator;
 
     // private flags for the context state
     private static final int PRE_INIT = 1;
@@ -122,6 +123,22 @@ class GSSContextImpl implements ExtendedGSSContext {
     private boolean reqAnonState = false;
     private boolean reqDelegPolicyState = false;
 
+    public GSSContextImpl() {
+        // Useless
+    }
+
+    // Used by new ExtendedGSSContext.ExtendedGSSContextImpl(ctxt)
+    protected GSSContextImpl(GSSContextImpl src) {
+        for (Field f: GSSContextImpl.class.getDeclaredFields()) {
+            if (!Modifier.isStatic(f.getModifiers())) {
+                try {
+                    f.set(this, f.get(src));
+                } catch (Exception e) {
+                    throw new RuntimeException(e);
+                }
+            }
+        }
+    }
     /**
      * Creates a GSSContextImp on the context initiator's side.
      */
@@ -613,7 +630,7 @@ class GSSContextImpl implements ExtendedGSSContext {
                                    "No mechanism context yet!");
         GSSCredentialSpi delCredElement = mechCtxt.getDelegCred();
         return (delCredElement == null ?
-            null : new GSSCredentialImpl(gssManager, delCredElement));
+            null : GSSManagerImpl.wrap(new GSSCredentialImpl(gssManager, delCredElement)));
     }
 
     public boolean isInitiator() throws GSSException {
@@ -633,25 +650,18 @@ class GSSContextImpl implements ExtendedGSSContext {
 
     // ExtendedGSSContext methods:
 
-    @Override
-    public Object inquireSecContext(InquireType type) throws GSSException {
-        SecurityManager security = System.getSecurityManager();
-        if (security != null) {
-            security.checkPermission(new InquireSecContextPermission(type.toString()));
-        }
+    public Object inquireSecContext(String type) throws GSSException {
         if (mechCtxt == null) {
             throw new GSSException(GSSException.NO_CONTEXT);
         }
         return mechCtxt.inquireSecContext(type);
     }
 
-    @Override
     public void requestDelegPolicy(boolean state) throws GSSException {
         if (mechCtxt == null && initiator)
             reqDelegPolicyState = state;
     }
 
-    @Override
     public boolean getDelegPolicyState() {
         if (mechCtxt != null)
             return mechCtxt.getDelegPolicyState();
diff --git a/jdk/src/java.security.jgss/share/classes/sun/security/jgss/GSSCredentialImpl.java b/jdk/src/java.security.jgss/share/classes/sun/security/jgss/GSSCredentialImpl.java
index 0cff2fa7937..617505f8320 100644
--- a/jdk/src/java.security.jgss/share/classes/sun/security/jgss/GSSCredentialImpl.java
+++ b/jdk/src/java.security.jgss/share/classes/sun/security/jgss/GSSCredentialImpl.java
@@ -27,11 +27,11 @@ package sun.security.jgss;
 
 import org.ietf.jgss.*;
 import sun.security.jgss.spi.*;
+
 import java.util.*;
-import com.sun.security.jgss.*;
 import sun.security.jgss.spnego.SpNegoCredElement;
 
-public class GSSCredentialImpl implements ExtendedGSSCredential {
+public class GSSCredentialImpl implements GSSCredential {
 
     private GSSManagerImpl gssManager = null;
     private boolean destroyed = false;
@@ -47,6 +47,18 @@ public class GSSCredentialImpl implements ExtendedGSSCredential {
     // XXX Optimization for single mech usage
     private GSSCredentialSpi tempCred = null;
 
+    public GSSCredentialImpl() {
+        // Useless
+    }
+
+    // Used by new ExtendedGSSCredential.ExtendedGSSCredentialImpl(cred)
+    protected GSSCredentialImpl(GSSCredentialImpl src) {
+        this.gssManager = src.gssManager;
+        this.destroyed = src.destroyed;
+        this.hashtable = src.hashtable;
+        this.tempCred = src.tempCred;
+    }
+
     GSSCredentialImpl(GSSManagerImpl gssManager, int usage)
         throws GSSException {
         this(gssManager, null, GSSCredential.DEFAULT_LIFETIME,
@@ -140,7 +152,7 @@ public class GSSCredentialImpl implements ExtendedGSSCredential {
                                   ((GSSNameImpl)name).getElement(mech));
         GSSCredentialSpi cred = tempCred.impersonate(nameElement);
         return (cred == null ?
-            null : new GSSCredentialImpl(gssManager, cred));
+            null : GSSManagerImpl.wrap(new GSSCredentialImpl(gssManager, cred)));
     }
 
     public GSSName getName() throws GSSException {
diff --git a/jdk/src/java.security.jgss/share/classes/sun/security/jgss/GSSManagerImpl.java b/jdk/src/java.security.jgss/share/classes/sun/security/jgss/GSSManagerImpl.java
index 736ef98fcd8..9d27b53822b 100644
--- a/jdk/src/java.security.jgss/share/classes/sun/security/jgss/GSSManagerImpl.java
+++ b/jdk/src/java.security.jgss/share/classes/sun/security/jgss/GSSManagerImpl.java
@@ -145,35 +145,35 @@ public class GSSManagerImpl extends GSSManager {
 
     public GSSCredential createCredential(int usage)
         throws GSSException {
-        return new GSSCredentialImpl(this, usage);
+        return wrap(new GSSCredentialImpl(this, usage));
     }
 
     public GSSCredential createCredential(GSSName aName,
                                           int lifetime, Oid mech, int usage)
         throws GSSException {
-        return new GSSCredentialImpl(this, aName, lifetime, mech, usage);
+        return wrap(new GSSCredentialImpl(this, aName, lifetime, mech, usage));
     }
 
     public GSSCredential createCredential(GSSName aName,
                                           int lifetime, Oid mechs[], int usage)
         throws GSSException {
-        return new GSSCredentialImpl(this, aName, lifetime, mechs, usage);
+        return wrap(new GSSCredentialImpl(this, aName, lifetime, mechs, usage));
     }
 
     public GSSContext createContext(GSSName peer, Oid mech,
                                     GSSCredential myCred, int lifetime)
         throws GSSException {
-        return new GSSContextImpl(this, peer, mech, myCred, lifetime);
+        return wrap(new GSSContextImpl(this, peer, mech, myCred, lifetime));
     }
 
     public GSSContext createContext(GSSCredential myCred)
         throws GSSException {
-        return new GSSContextImpl(this, myCred);
+        return wrap(new GSSContextImpl(this, myCred));
     }
 
     public GSSContext createContext(byte[] interProcessToken)
         throws GSSException {
-        return new GSSContextImpl(this, interProcessToken);
+        return wrap(new GSSContextImpl(this, interProcessToken));
     }
 
     public void addProviderAtFront(Provider p, Oid mech)
@@ -257,4 +257,20 @@ public class GSSManagerImpl extends GSSManager {
         }
         return result;
     }
+
+    static {
+        // Load the extended JGSS interfaces if exist
+        try {
+            Class.forName("com.sun.security.jgss.Extender");
+        } catch (Exception e) {
+        }
+    }
+
+    static GSSCredential wrap(GSSCredentialImpl cred) {
+        return sun.security.jgss.JgssExtender.getExtender().wrap(cred);
+    }
+
+    static GSSContext wrap(GSSContextImpl ctxt) {
+        return sun.security.jgss.JgssExtender.getExtender().wrap(ctxt);
+    }
 }
diff --git a/jdk/src/java.security.jgss/share/classes/sun/security/jgss/JgssExtender.java b/jdk/src/java.security.jgss/share/classes/sun/security/jgss/JgssExtender.java
new file mode 100644
index 00000000000..4d204e5c652
--- /dev/null
+++ b/jdk/src/java.security.jgss/share/classes/sun/security/jgss/JgssExtender.java
@@ -0,0 +1,81 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package sun.security.jgss;
+
+import org.ietf.jgss.GSSContext;
+import org.ietf.jgss.GSSCredential;
+
+/**
+ * The extending point of basic JGSS-API.
+ * 

+ * If a module wants to extend basic JGSS-API classes, it should extends this + * class and register itself as "the extender" using the setExtender method. + * When various GSSManager.createXXX methods are called, they will call + * "the extender"'s wrap methods to create objects of extended types + * instead of basic types. + *

+ * We have only one extension now defined in com.sun.security.jgss, and the + * registering process is triggered in {@link GSSManagerImpl} by calling + * Class.forName("com.sun.security.jgss.Extender"). Only GSSContext + * and GSSCredential are extended now. + *

+ * The setExtender method should be called before any JGSS call. + */ +public class JgssExtender { + + // "The extender" + private static volatile JgssExtender theOne = new JgssExtender(); + + /** + * Gets "the extender". GSSManager calls this method so that it can + * wrap basic objects into extended objects. + * @return the extender + */ + public static JgssExtender getExtender() { + return theOne; + } + + /** + * Set "the extender" so that GSSManager can create extended objects. + */ + protected static void setExtender(JgssExtender theOne) { + JgssExtender.theOne = theOne; + } + + /** + * Wraps a plain GSSCredential object into an extended type. + */ + public GSSCredential wrap(GSSCredential cred) { + return cred; + } + + /** + * Wraps a plain GSSContext object into an extended type. + */ + public GSSContext wrap(GSSContext ctxt) { + return ctxt; + } +} diff --git a/jdk/src/java.security.jgss/share/classes/sun/security/jgss/krb5/InitSecContextToken.java b/jdk/src/java.security.jgss/share/classes/sun/security/jgss/krb5/InitSecContextToken.java index 0077e7edb28..13c999b6472 100644 --- a/jdk/src/java.security.jgss/share/classes/sun/security/jgss/krb5/InitSecContextToken.java +++ b/jdk/src/java.security.jgss/share/classes/sun/security/jgss/krb5/InitSecContextToken.java @@ -25,7 +25,6 @@ package sun.security.jgss.krb5; -import com.sun.security.jgss.AuthorizationDataEntry; import org.ietf.jgss.*; import java.io.InputStream; import java.io.IOException; @@ -152,17 +151,7 @@ class InitSecContextToken extends InitialToken { new KerberosTime(apReq.getCreds().getAuthTime()).toString()); context.setTktFlags(apReq.getCreds().getFlags()); AuthorizationData ad = apReq.getCreds().getAuthzData(); - if (ad == null) { - context.setAuthzData(null); - } else { - AuthorizationDataEntry[] authzData = - new AuthorizationDataEntry[ad.count()]; - for (int i=0; i " + x.getTargName()); } - System.out.println("Context status of " + name + ": " + sb.toString()); - System.out.println(x.getSrcName() + " -> " + x.getTargName()); - } catch (Exception e) { - ;// Don't care } + xstatus(); if (s != null) { System.out.println("====== START SUBJECT CONTENT ====="); - for (Principal p: s.getPrincipals()) { + for (Principal p : s.getPrincipals()) { System.out.println(" Principal: " + p); } for (Object o : s.getPublicCredentials()) { @@ -405,51 +395,42 @@ public class Context { } System.out.println("====== END SUBJECT CONTENT ====="); } - if (x != null && x instanceof ExtendedGSSContext) { - if (x.isEstablished()) { - ExtendedGSSContext ex = (ExtendedGSSContext)x; - Key k = (Key)ex.inquireSecContext( - InquireType.KRB5_GET_SESSION_KEY); - if (k == null) { - throw new Exception("(Old) Session key cannot be null"); - } - System.out.println("(Old) Session key is: " + k); - Key k2 = (Key)ex.inquireSecContext( - InquireType.KRB5_GET_SESSION_KEY_EX); - if (k2 == null) { - throw new Exception("Session key cannot be null"); - } - System.out.println("Session key is: " + k); - boolean[] flags = (boolean[])ex.inquireSecContext( - InquireType.KRB5_GET_TKT_FLAGS); - if (flags == null) { - throw new Exception("Ticket flags cannot be null"); - } - System.out.println("Ticket flags is: " + Arrays.toString(flags)); - String authTime = (String)ex.inquireSecContext( - InquireType.KRB5_GET_AUTHTIME); - if (authTime == null) { - throw new Exception("Auth time cannot be null"); - } - System.out.println("AuthTime is: " + authTime); - if (!x.isInitiator()) { - AuthorizationDataEntry[] ad = (AuthorizationDataEntry[])ex.inquireSecContext( - InquireType.KRB5_GET_AUTHZ_DATA); - System.out.println("AuthzData is: " + Arrays.toString(ad)); - } - try { - KerberosCredMessage tok = (KerberosCredMessage)ex.inquireSecContext( - InquireType.KRB5_GET_KRB_CRED); - System.out.println("KRB_CRED is " + - (tok == null?"not ":"") + "available"); - if (tok != null) { - System.out.println("From " + tok.getSender() + " to " - + tok.getRecipient()); - System.out.println(Base64.getEncoder().encodeToString(tok.getEncoded())); + } + + public void xstatus() throws Exception { + System.out.println(" Extended context status:"); + if (x != null) { + try { + Class clazz = Class.forName("com.sun.security.jgss.ExtendedGSSContext"); + if (clazz.isAssignableFrom(x.getClass())) { + if (clazz.getMethod("getDelegPolicyState").invoke(x) == Boolean.TRUE) { + System.out.println(" deleg policy"); + } + if (x.isEstablished()) { + Class inqType = Class.forName("com.sun.security.jgss.InquireType"); + Method inqMethod = clazz.getMethod("inquireSecContext", inqType); + for (Object o : inqType.getEnumConstants()) { + System.out.println(" " + o + ":"); + try { + System.out.println(" " + inqMethod.invoke(x, o)); + } catch (Exception e) { + System.out.println(e.getCause()); + } + } } - } catch (Exception e) { - System.out.println("KRB_CRED is not available: " + e); } + } catch (ClassNotFoundException cnfe) { + System.out.println(" -- ExtendedGSSContext not available"); + } + } + if (cred != null) { + try { + Class clazz2 = Class.forName("com.sun.security.jgss.ExtendedGSSCredential"); + if (!clazz2.isAssignableFrom(cred.getClass())) { + throw new Exception("cred is not extended"); + } + } catch (ClassNotFoundException cnfe) { + System.out.println(" -- ExtendedGSSCredential not available"); } } } @@ -591,7 +572,10 @@ public class Context { if (Context.this.cred == null) { Context.this.cred = m.createCredential(GSSCredential.INITIATE_ONLY); } - return ((ExtendedGSSCredential)Context.this.cred).impersonate(other); + return (GSSCredential) + Class.forName("com.sun.security.jgss.ExtendedGSSCredential") + .getMethod("impersonate", GSSName.class) + .invoke(Context.this.cred, other); } }); Context out = new Context(); diff --git a/jdk/test/sun/security/krb5/auto/NewInquireTypes.java b/jdk/test/sun/security/krb5/auto/NewInquireTypes.java index 0a922468b62..bb4d041b413 100644 --- a/jdk/test/sun/security/krb5/auto/NewInquireTypes.java +++ b/jdk/test/sun/security/krb5/auto/NewInquireTypes.java @@ -29,6 +29,7 @@ * @run main/othervm NewInquireTypes */ +import com.sun.security.jgss.ExtendedGSSContext; import com.sun.security.jgss.InquireType; import sun.security.jgss.GSSUtil; import sun.security.krb5.internal.KRBCred; @@ -52,10 +53,12 @@ public class NewInquireTypes { Context.handshake(c, s); + ExtendedGSSContext ctxt = (ExtendedGSSContext)c.x(); EncryptionKey key = (EncryptionKey) - c.x().inquireSecContext(InquireType.KRB5_GET_SESSION_KEY_EX); + ctxt.inquireSecContext(InquireType.KRB5_GET_SESSION_KEY_EX); KerberosCredMessage cred = (KerberosCredMessage) - c.x().inquireSecContext(InquireType.KRB5_GET_KRB_CRED); + ctxt.inquireSecContext(InquireType.KRB5_GET_KRB_CRED); + c.status(); // Confirm the KRB_CRED message is encrypted with the session key. new KRBCred(cred.getEncoded()).encPart.decrypt( diff --git a/jdk/test/sun/security/krb5/auto/OkAsDelegate.java b/jdk/test/sun/security/krb5/auto/OkAsDelegate.java index d66e2421b82..198de7d78ca 100644 --- a/jdk/test/sun/security/krb5/auto/OkAsDelegate.java +++ b/jdk/test/sun/security/krb5/auto/OkAsDelegate.java @@ -48,6 +48,7 @@ * @summary Support OK-AS-DELEGATE flag */ import com.sun.security.jgss.ExtendedGSSContext; +import org.ietf.jgss.GSSContext; import org.ietf.jgss.GSSCredential; import org.ietf.jgss.GSSException; import org.ietf.jgss.Oid; @@ -102,7 +103,7 @@ public class OkAsDelegate { cx.requestCredDeleg(requestDelegState); cx.requestDelegPolicy(requestDelegPolicyState); s.startAsServer(mech); - ExtendedGSSContext sx = (ExtendedGSSContext)s.x(); + GSSContext sx = s.x(); Context.handshake(c, s); diff --git a/jdk/test/sun/security/krb5/auto/OkAsDelegateXRealm.java b/jdk/test/sun/security/krb5/auto/OkAsDelegateXRealm.java index 4607619ec31..ce71314339e 100644 --- a/jdk/test/sun/security/krb5/auto/OkAsDelegateXRealm.java +++ b/jdk/test/sun/security/krb5/auto/OkAsDelegateXRealm.java @@ -42,6 +42,8 @@ import javax.security.auth.callback.CallbackHandler; import javax.security.auth.callback.NameCallback; import javax.security.auth.callback.PasswordCallback; import javax.security.auth.callback.UnsupportedCallbackException; + +import com.sun.security.jgss.ExtendedGSSContext; import org.ietf.jgss.GSSException; import sun.security.jgss.GSSUtil; import sun.security.krb5.Config; @@ -129,7 +131,7 @@ public class OkAsDelegateXRealm implements CallbackHandler { for (int i=0; i<2; i++) { c.startAsClient("host@host.r3.local", GSSUtil.GSS_KRB5_MECH_OID); s.startAsServer(GSSUtil.GSS_KRB5_MECH_OID); - c.x().requestDelegPolicy(true); + ((ExtendedGSSContext)c.x()).requestDelegPolicy(true); Context.handshake(c, s); boolean succeed = true; diff --git a/jdk/test/sun/security/krb5/auto/SSL.java b/jdk/test/sun/security/krb5/auto/SSL.java index aab262244ac..db7aae88bd4 100644 --- a/jdk/test/sun/security/krb5/auto/SSL.java +++ b/jdk/test/sun/security/krb5/auto/SSL.java @@ -186,13 +186,13 @@ public class SSL extends SecurityManager { // Client checks "initiate", then server gets the name // and checks "accept". Second connection resume. if (!permChecks.equals("IA")) { - throw new Exception(); + throw new Exception(permChecks); } } else { // For bound, JAAS checks "accept" once. Server checks again, // client then checks "initiate". Second connection resume. if (!permChecks.equals("AAI")) { - throw new Exception(); + throw new Exception(permChecks); } } } From 0c4519a09672361f02f2c0b8bd5eeba8af22cc66 Mon Sep 17 00:00:00 2001 From: Weijun Wang Date: Wed, 17 Sep 2014 13:55:30 +0800 Subject: [PATCH 59/81] 8056141: Move com.sun.security.jgss into a new module Reviewed-by: alanb, chegar, mchung --- .../classes/com/sun/security/jgss/AuthorizationDataEntry.java | 0 .../share/classes/com/sun/security/jgss/ExtendedGSSContext.java | 0 .../classes/com/sun/security/jgss/ExtendedGSSCredential.java | 0 .../share/classes/com/sun/security/jgss/Extender.java | 0 .../share/classes/com/sun/security/jgss/GSSUtil.java | 0 .../com/sun/security/jgss/InquireSecContextPermission.java | 0 .../share/classes/com/sun/security/jgss/InquireType.java | 0 .../share/classes/com/sun/security/jgss/package-info.java | 0 .../share/classes/com/sun/security/sasl/gsskerb/FactoryImpl.java | 0 .../share/classes/com/sun/security/sasl/gsskerb/GssKrb5Base.java | 0 .../classes/com/sun/security/sasl/gsskerb/GssKrb5Client.java | 0 .../classes/com/sun/security/sasl/gsskerb/GssKrb5Server.java | 0 12 files changed, 0 insertions(+), 0 deletions(-) rename jdk/src/{java.security.jgss => jdk.security.jgss}/share/classes/com/sun/security/jgss/AuthorizationDataEntry.java (100%) rename jdk/src/{java.security.jgss => jdk.security.jgss}/share/classes/com/sun/security/jgss/ExtendedGSSContext.java (100%) rename jdk/src/{java.security.jgss => jdk.security.jgss}/share/classes/com/sun/security/jgss/ExtendedGSSCredential.java (100%) rename jdk/src/{java.security.jgss => jdk.security.jgss}/share/classes/com/sun/security/jgss/Extender.java (100%) rename jdk/src/{java.security.jgss => jdk.security.jgss}/share/classes/com/sun/security/jgss/GSSUtil.java (100%) rename jdk/src/{java.security.jgss => jdk.security.jgss}/share/classes/com/sun/security/jgss/InquireSecContextPermission.java (100%) rename jdk/src/{java.security.jgss => jdk.security.jgss}/share/classes/com/sun/security/jgss/InquireType.java (100%) rename jdk/src/{java.security.jgss => jdk.security.jgss}/share/classes/com/sun/security/jgss/package-info.java (100%) rename jdk/src/{java.security.jgss => jdk.security.jgss}/share/classes/com/sun/security/sasl/gsskerb/FactoryImpl.java (100%) rename jdk/src/{java.security.jgss => jdk.security.jgss}/share/classes/com/sun/security/sasl/gsskerb/GssKrb5Base.java (100%) rename jdk/src/{java.security.jgss => jdk.security.jgss}/share/classes/com/sun/security/sasl/gsskerb/GssKrb5Client.java (100%) rename jdk/src/{java.security.jgss => jdk.security.jgss}/share/classes/com/sun/security/sasl/gsskerb/GssKrb5Server.java (100%) diff --git a/jdk/src/java.security.jgss/share/classes/com/sun/security/jgss/AuthorizationDataEntry.java b/jdk/src/jdk.security.jgss/share/classes/com/sun/security/jgss/AuthorizationDataEntry.java similarity index 100% rename from jdk/src/java.security.jgss/share/classes/com/sun/security/jgss/AuthorizationDataEntry.java rename to jdk/src/jdk.security.jgss/share/classes/com/sun/security/jgss/AuthorizationDataEntry.java diff --git a/jdk/src/java.security.jgss/share/classes/com/sun/security/jgss/ExtendedGSSContext.java b/jdk/src/jdk.security.jgss/share/classes/com/sun/security/jgss/ExtendedGSSContext.java similarity index 100% rename from jdk/src/java.security.jgss/share/classes/com/sun/security/jgss/ExtendedGSSContext.java rename to jdk/src/jdk.security.jgss/share/classes/com/sun/security/jgss/ExtendedGSSContext.java diff --git a/jdk/src/java.security.jgss/share/classes/com/sun/security/jgss/ExtendedGSSCredential.java b/jdk/src/jdk.security.jgss/share/classes/com/sun/security/jgss/ExtendedGSSCredential.java similarity index 100% rename from jdk/src/java.security.jgss/share/classes/com/sun/security/jgss/ExtendedGSSCredential.java rename to jdk/src/jdk.security.jgss/share/classes/com/sun/security/jgss/ExtendedGSSCredential.java diff --git a/jdk/src/java.security.jgss/share/classes/com/sun/security/jgss/Extender.java b/jdk/src/jdk.security.jgss/share/classes/com/sun/security/jgss/Extender.java similarity index 100% rename from jdk/src/java.security.jgss/share/classes/com/sun/security/jgss/Extender.java rename to jdk/src/jdk.security.jgss/share/classes/com/sun/security/jgss/Extender.java diff --git a/jdk/src/java.security.jgss/share/classes/com/sun/security/jgss/GSSUtil.java b/jdk/src/jdk.security.jgss/share/classes/com/sun/security/jgss/GSSUtil.java similarity index 100% rename from jdk/src/java.security.jgss/share/classes/com/sun/security/jgss/GSSUtil.java rename to jdk/src/jdk.security.jgss/share/classes/com/sun/security/jgss/GSSUtil.java diff --git a/jdk/src/java.security.jgss/share/classes/com/sun/security/jgss/InquireSecContextPermission.java b/jdk/src/jdk.security.jgss/share/classes/com/sun/security/jgss/InquireSecContextPermission.java similarity index 100% rename from jdk/src/java.security.jgss/share/classes/com/sun/security/jgss/InquireSecContextPermission.java rename to jdk/src/jdk.security.jgss/share/classes/com/sun/security/jgss/InquireSecContextPermission.java diff --git a/jdk/src/java.security.jgss/share/classes/com/sun/security/jgss/InquireType.java b/jdk/src/jdk.security.jgss/share/classes/com/sun/security/jgss/InquireType.java similarity index 100% rename from jdk/src/java.security.jgss/share/classes/com/sun/security/jgss/InquireType.java rename to jdk/src/jdk.security.jgss/share/classes/com/sun/security/jgss/InquireType.java diff --git a/jdk/src/java.security.jgss/share/classes/com/sun/security/jgss/package-info.java b/jdk/src/jdk.security.jgss/share/classes/com/sun/security/jgss/package-info.java similarity index 100% rename from jdk/src/java.security.jgss/share/classes/com/sun/security/jgss/package-info.java rename to jdk/src/jdk.security.jgss/share/classes/com/sun/security/jgss/package-info.java diff --git a/jdk/src/java.security.jgss/share/classes/com/sun/security/sasl/gsskerb/FactoryImpl.java b/jdk/src/jdk.security.jgss/share/classes/com/sun/security/sasl/gsskerb/FactoryImpl.java similarity index 100% rename from jdk/src/java.security.jgss/share/classes/com/sun/security/sasl/gsskerb/FactoryImpl.java rename to jdk/src/jdk.security.jgss/share/classes/com/sun/security/sasl/gsskerb/FactoryImpl.java diff --git a/jdk/src/java.security.jgss/share/classes/com/sun/security/sasl/gsskerb/GssKrb5Base.java b/jdk/src/jdk.security.jgss/share/classes/com/sun/security/sasl/gsskerb/GssKrb5Base.java similarity index 100% rename from jdk/src/java.security.jgss/share/classes/com/sun/security/sasl/gsskerb/GssKrb5Base.java rename to jdk/src/jdk.security.jgss/share/classes/com/sun/security/sasl/gsskerb/GssKrb5Base.java diff --git a/jdk/src/java.security.jgss/share/classes/com/sun/security/sasl/gsskerb/GssKrb5Client.java b/jdk/src/jdk.security.jgss/share/classes/com/sun/security/sasl/gsskerb/GssKrb5Client.java similarity index 100% rename from jdk/src/java.security.jgss/share/classes/com/sun/security/sasl/gsskerb/GssKrb5Client.java rename to jdk/src/jdk.security.jgss/share/classes/com/sun/security/sasl/gsskerb/GssKrb5Client.java diff --git a/jdk/src/java.security.jgss/share/classes/com/sun/security/sasl/gsskerb/GssKrb5Server.java b/jdk/src/jdk.security.jgss/share/classes/com/sun/security/sasl/gsskerb/GssKrb5Server.java similarity index 100% rename from jdk/src/java.security.jgss/share/classes/com/sun/security/sasl/gsskerb/GssKrb5Server.java rename to jdk/src/jdk.security.jgss/share/classes/com/sun/security/sasl/gsskerb/GssKrb5Server.java From 25244f5b117c81243949c49ded7c8e925bc0caf8 Mon Sep 17 00:00:00 2001 From: Weijun Wang Date: Wed, 17 Sep 2014 13:55:36 +0800 Subject: [PATCH 60/81] 8056141: Move com.sun.security.jgss into a new module Reviewed-by: alanb, chegar, mchung --- common/bin/unshuffle_list.txt | 5 +++-- modules.xml | 26 ++++++++++++++++++++------ 2 files changed, 23 insertions(+), 8 deletions(-) diff --git a/common/bin/unshuffle_list.txt b/common/bin/unshuffle_list.txt index 66f1fcd7b3e..2ba90cf18dd 100644 --- a/common/bin/unshuffle_list.txt +++ b/common/bin/unshuffle_list.txt @@ -1216,14 +1216,13 @@ jdk/src/java.security.acl/share/classes/java/security/acl : jdk/src/share/classe jdk/src/java.security.acl/share/classes/sun/security/acl : jdk/src/share/classes/sun/security/acl jdk/src/java.security.jgss/macosx/native/libosxkrb5/nativeccache.c : jdk/src/share/native/sun/security/krb5/nativeccache.c jdk/src/java.security.jgss/macosx/native/libosxkrb5/SCDynamicStoreConfig.m : jdk/src/macosx/native/sun/security/krb5/SCDynamicStoreConfig.m -jdk/src/java.security.jgss/share/classes/com/sun/security/jgss : jdk/src/share/classes/com/sun/security/jgss -jdk/src/java.security.jgss/share/classes/com/sun/security/sasl/gsskerb : jdk/src/share/classes/com/sun/security/sasl/gsskerb jdk/src/java.security.jgss/share/classes/javax/security/auth/kerberos : jdk/src/share/classes/javax/security/auth/kerberos jdk/src/java.security.jgss/share/classes/jgss-overview.html : jdk/src/share/classes/com/sun/security/jgss/jgss-overview.html jdk/src/java.security.jgss/share/classes/org/ietf/jgss : jdk/src/share/classes/org/ietf/jgss jdk/src/java.security.jgss/share/classes/sun/net/www/protocol/http/spnego : jdk/src/share/classes/sun/net/www/protocol/http/spnego jdk/src/java.security.jgss/share/classes/sun/security/jgss : jdk/src/share/classes/sun/security/jgss jdk/src/java.security.jgss/share/classes/sun/security/krb5 : jdk/src/share/classes/sun/security/krb5 +jdk/src/java.security.jgss/windows/classes/sun/security/krb5 : jdk/src/windows/classes/sun/security/krb5 jdk/src/java.security.jgss/share/classes/sun/security/ssl/krb5 : jdk/src/share/classes/sun/security/ssl/krb5 jdk/src/java.security.jgss/share/native/libj2gss : jdk/src/share/native/sun/security/jgss/wrapper jdk/src/java.security.jgss/unix/native/libj2gss : jdk/src/solaris/native/sun/security/jgss/wrapper @@ -1477,6 +1476,8 @@ jdk/src/jdk.security.auth/share/classes/com/sun/security/auth : jdk/src/share/cl jdk/src/jdk.security.auth/share/classes/jaas-overview.html : jdk/src/share/classes/com/sun/security/auth/jaas-overview.html jdk/src/jdk.security.auth/unix/native/libjaas : jdk/src/solaris/native/com/sun/security/auth/module jdk/src/jdk.security.auth/windows/native/libjaas : jdk/src/windows/native/com/sun/security/auth/module +jdk/src/jdk.security.jgss/share/classes/com/sun/security/jgss : jdk/src/share/classes/com/sun/security/jgss +jdk/src/jdk.security.jgss/share/classes/com/sun/security/sasl/gsskerb : jdk/src/share/classes/com/sun/security/sasl/gsskerb jdk/src/jdk.snmp/share/classes/com/sun/jmx/snmp : jdk/src/share/classes/com/sun/jmx/snmp jdk/src/jdk.snmp/share/classes/sun/management/snmp : jdk/src/share/classes/sun/management/snmp jdk/src/jdk.zipfs/share/classes/jdk/nio/zipfs : jdk/src/share/classes/jdk/nio/zipfs diff --git a/modules.xml b/modules.xml index 162cd7e0125..12874815d35 100644 --- a/modules.xml +++ b/modules.xml @@ -251,6 +251,7 @@ jdk.jvmstat jdk.runtime jdk.security.auth + jdk.security.jgss sun.net.dns @@ -906,12 +907,7 @@ java.security.jgss java.base - java.logging java.naming - java.security.sasl - - com.sun.security.jgss - javax.security.auth.kerberos @@ -930,6 +926,14 @@ sun.security.krb5.internal.ktab jdk.security.auth + + sun.security.jgss + jdk.security.jgss + + + sun.security.krb5.internal + jdk.security.jgss + java.security.sasl @@ -940,7 +944,7 @@ com.sun.security.sasl.util - java.security.jgss + jdk.security.jgss @@ -1761,6 +1765,16 @@ com.sun.security.auth.module + + jdk.security.jgss + java.base + java.logging + java.security.jgss + java.security.sasl + + com.sun.security.jgss + + jdk.xml.bind java.activation From bddf81075a409ba131a833d086e80155ac4bca35 Mon Sep 17 00:00:00 2001 From: Athijegannathan Sundararajan Date: Wed, 17 Sep 2014 15:02:42 +0530 Subject: [PATCH 61/81] 8058615: Overload resolution ambiguity involving ConsString Reviewed-by: lagergren, hannesw --- .../runtime/linker/NashornBeansLinker.java | 9 +++++ nashorn/test/script/basic/JDK-8058615.js | 36 +++++++++++++++++++ .../test/script/basic/JDK-8058615.js.EXPECTED | 1 + 3 files changed, 46 insertions(+) create mode 100644 nashorn/test/script/basic/JDK-8058615.js create mode 100644 nashorn/test/script/basic/JDK-8058615.js.EXPECTED diff --git a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/linker/NashornBeansLinker.java b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/linker/NashornBeansLinker.java index e6b8b90b56c..f802e039607 100644 --- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/linker/NashornBeansLinker.java +++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/linker/NashornBeansLinker.java @@ -125,6 +125,15 @@ public class NashornBeansLinker implements GuardingDynamicLinker { @Override public Comparison compareConversion(final Class sourceType, final Class targetType1, final Class targetType2) { + if (sourceType == ConsString.class) { + if (String.class == targetType1 || CharSequence.class == targetType1) { + return Comparison.TYPE_1_BETTER; + } + + if (String.class == targetType2 || CharSequence.class == targetType2) { + return Comparison.TYPE_2_BETTER; + } + } return linkerServices.compareConversion(sourceType, targetType1, targetType2); } } diff --git a/nashorn/test/script/basic/JDK-8058615.js b/nashorn/test/script/basic/JDK-8058615.js new file mode 100644 index 00000000000..354b5e4bf87 --- /dev/null +++ b/nashorn/test/script/basic/JDK-8058615.js @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/** + * JDK-8058615: Overload resolution ambiguity involving ConsString + * + * @test + * @run + */ + +var strw = new java.io.StringWriter(); +var bufw = new java.io.BufferedWriter(strw); +var s = "hello "; +bufw.write(s + "world"); +bufw.close(); +print(strw.toString()); diff --git a/nashorn/test/script/basic/JDK-8058615.js.EXPECTED b/nashorn/test/script/basic/JDK-8058615.js.EXPECTED new file mode 100644 index 00000000000..3b18e512dba --- /dev/null +++ b/nashorn/test/script/basic/JDK-8058615.js.EXPECTED @@ -0,0 +1 @@ +hello world From 3d7f4564c66bcdbf8930e90b5a8f32e3571e09d0 Mon Sep 17 00:00:00 2001 From: Sergey Lugovoy Date: Wed, 17 Sep 2014 16:44:23 +0400 Subject: [PATCH 62/81] 8057035: Some tests failed using java.awt.Color on Solaris without X11 libraries Reviewed-by: lagergren --- nashorn/test/script/basic/JDK-8043232.js | 8 ++++---- nashorn/test/script/basic/JDK-8043232.js.EXPECTED | 8 ++++---- nashorn/test/script/basic/JDK-8049086.js | 2 +- nashorn/test/script/basic/JDK-8049086.js.EXPECTED | 2 +- nashorn/test/script/basic/JDK-8049242.js | 8 ++++---- nashorn/test/script/basic/JDK-8049242.js.EXPECTED | 8 ++++---- 6 files changed, 18 insertions(+), 18 deletions(-) diff --git a/nashorn/test/script/basic/JDK-8043232.js b/nashorn/test/script/basic/JDK-8043232.js index fa46b415b1c..d1f3d85d552 100644 --- a/nashorn/test/script/basic/JDK-8043232.js +++ b/nashorn/test/script/basic/JDK-8043232.js @@ -29,14 +29,14 @@ */ // call explicit constructor -print(new (java.awt["Color(int,int,int)"])(255,0,255)); +print(new (java.lang["String(char[],int,int)"])(['a','b', 'c', 'd'], 1, 3)); // print the constructor itself -print(java.awt["Color(int,int,int)"]); +print(java.lang["String(char[],int,int)"]); // store constructor to call later -var Color = java.awt["Color(int,int,int)"]; +var Color = java.lang["String(char[],int,int)"]; // call stored constructor -print(new Color(33, 233, 2)) +print(new Color(['r','r', 'e', 'd'], 1, 3)) // check if default constructor works var obj = new (java.lang["Object()"])(); diff --git a/nashorn/test/script/basic/JDK-8043232.js.EXPECTED b/nashorn/test/script/basic/JDK-8043232.js.EXPECTED index 03382ea512d..0ff18b41fab 100644 --- a/nashorn/test/script/basic/JDK-8043232.js.EXPECTED +++ b/nashorn/test/script/basic/JDK-8043232.js.EXPECTED @@ -1,6 +1,6 @@ -java.awt.Color[r=255,g=0,b=255] -[jdk.internal.dynalink.beans.SimpleDynamicMethod Color java.awt.Color.java.awt.Color(int,int,int)] -java.awt.Color[r=33,g=233,b=2] +bcd +[jdk.internal.dynalink.beans.SimpleDynamicMethod String java.lang.String.java.lang.String(char[],int,int)] +red TypeError: No such Java class: java.lang.NonExistent TypeError: No such Java constructor: Object(String) TypeError: Java constructor signature invalid: Object()xxxxx @@ -8,7 +8,7 @@ TypeError: Java constructor signature invalid: Object( TypeError: Java constructor signature invalid: Object) TypeError: Java method [jdk.internal.dynalink.beans.OverloadedDynamicMethod java.lang.System.getProperty] cannot be used as a constructor. TypeError: Java method [jdk.internal.dynalink.beans.OverloadedDynamicMethod java.io.PrintStream.println] cannot be used as a constructor. -TypeError: Constructor [jdk.internal.dynalink.beans.SimpleDynamicMethod Color java.awt.Color.java.awt.Color(int,int,int)] requires "new". +TypeError: Constructor [jdk.internal.dynalink.beans.SimpleDynamicMethod String java.lang.String.java.lang.String(char[],int,int)] requires "new". TypeError: No such Java constructor: Runnable() TypeError: No such Java constructor: Runnable(int) java.lang.InstantiationException: java.io.InputStream diff --git a/nashorn/test/script/basic/JDK-8049086.js b/nashorn/test/script/basic/JDK-8049086.js index da4a9627bfb..7dd7ac481f4 100644 --- a/nashorn/test/script/basic/JDK-8049086.js +++ b/nashorn/test/script/basic/JDK-8049086.js @@ -58,7 +58,7 @@ print("/foo/ is script object? " + Java.isScriptObject(/foo/)); // (a) Java methods (b) Java classes (as these respond to new) // (c) FunctionalInterface objects (d) JSObjects that are 'functions' -print("java.awt.Color is java function? " + Java.isJavaFunction(java.awt.Color)); +print("java.lang.String is java function? " + Java.isJavaFunction(java.lang.String)); print("java.lang.Runnable instance is java function? " + Java.isJavaFunction(new java.lang.Runnable(function() {}))); print("eval is java function? " + Java.isJavaFunction(eval)); diff --git a/nashorn/test/script/basic/JDK-8049086.js.EXPECTED b/nashorn/test/script/basic/JDK-8049086.js.EXPECTED index d67db5da266..e8685728950 100644 --- a/nashorn/test/script/basic/JDK-8049086.js.EXPECTED +++ b/nashorn/test/script/basic/JDK-8049086.js.EXPECTED @@ -13,7 +13,7 @@ System is script object? false Object is script object? true {} is script object? true /foo/ is script object? true -java.awt.Color is java function? true +java.lang.String is java function? true java.lang.Runnable instance is java function? true eval is java function? false println is java function? true diff --git a/nashorn/test/script/basic/JDK-8049242.js b/nashorn/test/script/basic/JDK-8049242.js index 3e803b3e8be..c44e330cbc9 100644 --- a/nashorn/test/script/basic/JDK-8049242.js +++ b/nashorn/test/script/basic/JDK-8049242.js @@ -29,14 +29,14 @@ */ // call explicit constructor -print(new (Java.type("java.awt.Color")["(int,int,int)"])(255,0,255)); +print(new (Java.type("java.lang.String")["(char[],int,int)"])(['a', 'b', 'c'],0, 3)); // print the constructor itself -print(Java.type("java.awt.Color")["(int,int,int)"]); +print(Java.type("java.lang.String")["(char[],int,int)"]); // store constructor to call later -var Color = Java.type("java.awt.Color")["(int,int,int)"]; +var Color = Java.type("java.lang.String")["(char[],int,int)"]; // call stored constructor -print(new Color(33, 233, 2)) +print(new Color(['j', 'a', 'v', 'a'], 1, 3)) // check if default constructor works var obj = new (Java.type("java.lang.Object")["()"])(); diff --git a/nashorn/test/script/basic/JDK-8049242.js.EXPECTED b/nashorn/test/script/basic/JDK-8049242.js.EXPECTED index 4a2f4169153..a5dc016dd9c 100644 --- a/nashorn/test/script/basic/JDK-8049242.js.EXPECTED +++ b/nashorn/test/script/basic/JDK-8049242.js.EXPECTED @@ -1,10 +1,10 @@ -java.awt.Color[r=255,g=0,b=255] -[jdk.internal.dynalink.beans.SimpleDynamicMethod Color java.awt.Color.java.awt.Color(int,int,int)] -java.awt.Color[r=33,g=233,b=2] +abc +[jdk.internal.dynalink.beans.SimpleDynamicMethod String java.lang.String.java.lang.String(char[],int,int)] +ava TypeError: null is not a function TypeError: null is not a function TypeError: null is not a function -TypeError: Constructor [jdk.internal.dynalink.beans.SimpleDynamicMethod Color java.awt.Color.java.awt.Color(int,int,int)] requires "new". +TypeError: Constructor [jdk.internal.dynalink.beans.SimpleDynamicMethod String java.lang.String.java.lang.String(char[],int,int)] requires "new". TypeError: null is not a function TypeError: null is not a function java.lang.InstantiationException: java.io.InputStream From af548efaa7f57e57075fb64f5b3771d4f383cf7a Mon Sep 17 00:00:00 2001 From: Paul Sandoz Date: Wed, 17 Sep 2014 16:47:52 +0200 Subject: [PATCH 63/81] 8058204: stream tests timeout, intermittently but more likely to happen after JDK-8056248 Reviewed-by: alanb, dholmes --- jdk/test/TEST.ROOT | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/jdk/test/TEST.ROOT b/jdk/test/TEST.ROOT index 7288a0921d8..58a91d89a03 100644 --- a/jdk/test/TEST.ROOT +++ b/jdk/test/TEST.ROOT @@ -8,7 +8,7 @@ keys=2d dnd i18n othervm.dirs=java/awt java/beans javax/accessibility javax/imageio javax/sound javax/print javax/management com/sun/awt sun/awt sun/java2d sun/pisces # Tests that cannot run concurrently -exclusiveAccess.dirs=java/rmi/Naming java/util/prefs sun/management/jmxremote sun/tools/jstatd sun/security/mscapi +exclusiveAccess.dirs=java/rmi/Naming java/util/prefs sun/management/jmxremote sun/tools/jstatd sun/security/mscapi java/util/stream # Group definitions groups=TEST.groups [closed/TEST.groups] From 9dc0d55e1ca406ddaa2e822477094ef6cc0f2433 Mon Sep 17 00:00:00 2001 From: Naoto Sato Date: Wed, 17 Sep 2014 09:43:04 -0700 Subject: [PATCH 64/81] 8058509: CLDRLocaleDataMetaInfo should be in jdk.localedata Reviewed-by: mchung, erikj, ihse --- jdk/make/CreateJars.gmk | 3 -- jdk/make/gensrc/Gensrc-java.base.gmk | 3 +- jdk/make/gensrc/Gensrc-jdk.localedata.gmk | 38 +++++++++++++++++++ jdk/make/gensrc/GensrcCLDR.gmk | 15 +------- ...eDataMetaInfo.gmk => GensrcLocaleData.gmk} | 9 +++-- .../ResourceBundleGenerator.java | 7 ++-- ...un.util.locale.provider.LocaleDataMetaInfo | 2 +- 7 files changed, 51 insertions(+), 26 deletions(-) create mode 100644 jdk/make/gensrc/Gensrc-jdk.localedata.gmk rename jdk/make/gensrc/{GensrcLocaleDataMetaInfo.gmk => GensrcLocaleData.gmk} (95%) diff --git a/jdk/make/CreateJars.gmk b/jdk/make/CreateJars.gmk index aca0f42904a..e3d2ac42de9 100644 --- a/jdk/make/CreateJars.gmk +++ b/jdk/make/CreateJars.gmk @@ -220,7 +220,6 @@ RT_JAR_EXCLUDES += \ sun/tools/serialver \ sun/tools/tree \ sun/tools/util \ - sun/util/cldr/CLDRLocaleDataMetaInfo.class \ sun/util/resources/provider/NonEnLocaleDataMetaInfo.class \ META-INF/services/sun.util.locale.provider.LocaleDataMetaInfo \ sun/util/resources/cldr \ @@ -452,11 +451,9 @@ $(CLDR_METAINF_SERVICES): $(JDK_TOPDIR)/src/jdk.localedata/META-INF/cldrdata-ser $(eval $(call SetupArchive,BUILD_CLDRDATA_JAR, \ $(CLDR_METAINF_SERVICES), \ SRCS := $(JDK_OUTPUTDIR)/modules/jdk.localedata \ - $(JDK_OUTPUTDIR)/modules/java.base \ $(CLDR_SERVICES_DIR), \ SUFFIXES := .class, \ INCLUDES := sun/text/resources/cldr \ - sun/util/cldr/CLDRLocaleDataMetaInfo.class \ sun/util/resources/cldr, \ EXTRA_FILES := META-INF/services/sun.util.locale.provider.LocaleDataMetaInfo, \ JAR := $(CLDRDATA_JAR_DST), \ diff --git a/jdk/make/gensrc/Gensrc-java.base.gmk b/jdk/make/gensrc/Gensrc-java.base.gmk index 2f0346ce514..b43e822402c 100644 --- a/jdk/make/gensrc/Gensrc-java.base.gmk +++ b/jdk/make/gensrc/Gensrc-java.base.gmk @@ -29,14 +29,13 @@ include GensrcCommon.gmk include GensrcProperties.gmk GENSRC_JAVA_BASE += $(GENSRC_PROPERTIES) -include GensrcLocaleDataMetaInfo.gmk +include GensrcLocaleData.gmk include GensrcCharacterData.gmk include GensrcMisc.gmk include GensrcCharsetMapping.gmk include GensrcCharsetCoder.gmk include GensrcBuffer.gmk include GensrcExceptions.gmk -include GensrcCLDR.gmk java.base: $(GENSRC_JAVA_BASE) diff --git a/jdk/make/gensrc/Gensrc-jdk.localedata.gmk b/jdk/make/gensrc/Gensrc-jdk.localedata.gmk new file mode 100644 index 00000000000..bdc26421172 --- /dev/null +++ b/jdk/make/gensrc/Gensrc-jdk.localedata.gmk @@ -0,0 +1,38 @@ +# +# Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +# +# This code is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License version 2 only, as +# published by the Free Software Foundation. Oracle designates this +# particular file as subject to the "Classpath" exception as provided +# by Oracle in the LICENSE file that accompanied this code. +# +# This code is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +# version 2 for more details (a copy is included in the LICENSE file that +# accompanied this code). +# +# You should have received a copy of the GNU General Public License version +# 2 along with this work; if not, write to the Free Software Foundation, +# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. +# +# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA +# or visit www.oracle.com if you need additional information or have any +# questions. +# + +include GensrcCommon.gmk + +# Hook to include the corresponding custom file, if present. +$(eval $(call IncludeCustomExtension, jdk, gensrc/Gensrc-jdk.localedata.gmk)) + +include GensrcLocaleData.gmk +include GensrcCLDR.gmk + +jdk.localedata: $(GENSRC_JDK_LOCALEDATA) + +all: jdk.localedata + +.PHONY: all jdk.localedata diff --git a/jdk/make/gensrc/GensrcCLDR.gmk b/jdk/make/gensrc/GensrcCLDR.gmk index ed6f7f75c2a..a0f2a0d4748 100644 --- a/jdk/make/gensrc/GensrcCLDR.gmk +++ b/jdk/make/gensrc/GensrcCLDR.gmk @@ -27,9 +27,8 @@ CLDRVERSION := 21.0.1 CLDRSRCDIR := $(JDK_TOPDIR)/src/jdk.localedata/share/classes/sun/util/cldr/resources/$(subst .,_,$(CLDRVERSION)) GENSRC_DIR := $(JDK_OUTPUTDIR)/gensrc/jdk.localedata -BASE_GENSRC_DIR := $(JDK_OUTPUTDIR)/gensrc/java.base -CLDR_METAINFO_FILE := $(BASE_GENSRC_DIR)/sun/util/cldr/CLDRLocaleDataMetaInfo.java +CLDR_METAINFO_FILE := $(GENSRC_DIR)/sun/util/resources/cldr/provider/CLDRLocaleDataMetaInfo.java $(CLDR_METAINFO_FILE): $(wildcard $(CLDRSRCDIR)/common/dtd/*.dtd) \ $(wildcard $(CLDRSRCDIR)/common/main/*.xml) \ @@ -37,16 +36,6 @@ $(CLDR_METAINFO_FILE): $(wildcard $(CLDRSRCDIR)/common/dtd/*.dtd) \ $(BUILD_TOOLS_JDK) $(MKDIR) -p $(GENSRC_DIR) $(TOOL_CLDRCONVERTER) -base $(CLDRSRCDIR) -o $(GENSRC_DIR) - $(MKDIR) -p $(BASE_GENSRC_DIR)/sun/text/resources/cldr - $(MKDIR) -p $(BASE_GENSRC_DIR)/sun/util/resources/cldr - $(RM) -r $(BASE_GENSRC_DIR)/sun/text/resources/cldr/en \ - $(BASE_GENSRC_DIR)/sun/util/resources/cldr/en - $(MV) $(GENSRC_DIR)/sun/text/resources/cldr/en $(BASE_GENSRC_DIR)/sun/text/resources/cldr/en - $(MV) $(GENSRC_DIR)/sun/util/resources/cldr/en $(BASE_GENSRC_DIR)/sun/util/resources/cldr/en - $(MV) $(GENSRC_DIR)/sun/text/resources/cldr/*.java $(BASE_GENSRC_DIR)/sun/text/resources/cldr - $(MV) $(GENSRC_DIR)/sun/util/resources/cldr/*.java $(BASE_GENSRC_DIR)/sun/util/resources/cldr - $(MKDIR) -p $(@D) - $(MV) $(GENSRC_DIR)/sun/util/cldr/CLDRLocaleDataMetaInfo.java $@ GENSRC_CLDR := $(CLDR_METAINFO_FILE) -GENSRC_JAVA_BASE += $(GENSRC_CLDR) +GENSRC_JDK_LOCALEDATA += $(GENSRC_CLDR) diff --git a/jdk/make/gensrc/GensrcLocaleDataMetaInfo.gmk b/jdk/make/gensrc/GensrcLocaleData.gmk similarity index 95% rename from jdk/make/gensrc/GensrcLocaleDataMetaInfo.gmk rename to jdk/make/gensrc/GensrcLocaleData.gmk index b251026c2cb..c7b73dc7d39 100644 --- a/jdk/make/gensrc/GensrcLocaleDataMetaInfo.gmk +++ b/jdk/make/gensrc/GensrcLocaleData.gmk @@ -130,8 +130,8 @@ $(JDK_OUTPUTDIR)/gensrc/jdk.localedata/sun/util/resources/provider/NonEnLocaleDa $(PRINTF) "PREV_LOCALE_RESOURCES:=$(LOCALE_RESOURCES)" > $(JDK_OUTPUTDIR)/gensrc/_the.locale_resources $(SED) $(SED_NONENARGS) $< > $@ -GENSRC_LOCALEDATAMETAINFO := $(JDK_OUTPUTDIR)/gensrc/java.base/sun/util/locale/provider/EnLocaleDataMetaInfo.java \ - $(JDK_OUTPUTDIR)/gensrc/jdk.localedata/sun/util/resources/provider/NonEnLocaleDataMetaInfo.java +GENSRC_BASELOCALEDATA := $(JDK_OUTPUTDIR)/gensrc/java.base/sun/util/locale/provider/EnLocaleDataMetaInfo.java +GENSRC_LOCALEDATA := $(JDK_OUTPUTDIR)/gensrc/jdk.localedata/sun/util/resources/provider/NonEnLocaleDataMetaInfo.java ################################################################################ @@ -145,7 +145,8 @@ $(GENSRC_CRBC_DST): $(JDK_TOPDIR)/src/java.base/share/classes/sun/util/CoreResou $(MKDIR) -p $(@D) NAWK="$(NAWK)" SED="$(SED)" $(SH) $(GENSRC_CRBC_CMD) "$(JRE_NONEXIST_LOCALES)" $< $@ -GENSRC_LOCALEDATAMETAINFO += $(GENSRC_CRBC_DST) -GENSRC_JAVA_BASE += $(GENSRC_LOCALEDATAMETAINFO) +GENSRC_BASELOCALEDATA += $(GENSRC_CRBC_DST) +GENSRC_JAVA_BASE += $(GENSRC_BASELOCALEDATA) +GENSRC_JDK_LOCALEDATA += $(GENSRC_LOCALEDATA) ################################################################################ diff --git a/jdk/make/src/classes/build/tools/cldrconverter/ResourceBundleGenerator.java b/jdk/make/src/classes/build/tools/cldrconverter/ResourceBundleGenerator.java index 27a7b1fbd20..77e740ad354 100644 --- a/jdk/make/src/classes/build/tools/cldrconverter/ResourceBundleGenerator.java +++ b/jdk/make/src/classes/build/tools/cldrconverter/ResourceBundleGenerator.java @@ -143,8 +143,9 @@ class ResourceBundleGenerator implements BundleGenerator { @Override public void generateMetaInfo(Map> metaInfo) throws IOException { - String dirName = CLDRConverter.DESTINATION_DIR + File.separator + "sun" + File.separator + "util" + File.separator - + "cldr" + File.separator; + String dirName = CLDRConverter.DESTINATION_DIR + File.separator + "sun" + File.separator + "util" + + File.separator + "resources" + File.separator + "cldr" + File.separator + + "provider" + File.separator ; File dir = new File(dirName); if (!dir.exists()) { dir.mkdirs(); @@ -158,7 +159,7 @@ class ResourceBundleGenerator implements BundleGenerator { try (PrintWriter out = new PrintWriter(file, "us-ascii")) { out.println(CopyrightHeaders.getOpenJDKCopyright()); - out.println("package sun.util.cldr;\n\n" + out.println("package sun.util.resources.cldr.provider;\n\n" + "import java.util.ListResourceBundle;\n" + "import sun.util.locale.provider.LocaleProviderAdapter;\n" + "import sun.util.locale.provider.LocaleDataMetaInfo;\n"); diff --git a/jdk/src/jdk.localedata/META-INF/cldrdata-services/sun.util.locale.provider.LocaleDataMetaInfo b/jdk/src/jdk.localedata/META-INF/cldrdata-services/sun.util.locale.provider.LocaleDataMetaInfo index 799dfdcc49a..07d15578e88 100644 --- a/jdk/src/jdk.localedata/META-INF/cldrdata-services/sun.util.locale.provider.LocaleDataMetaInfo +++ b/jdk/src/jdk.localedata/META-INF/cldrdata-services/sun.util.locale.provider.LocaleDataMetaInfo @@ -1 +1 @@ -sun.util.cldr.CLDRLocaleDataMetaInfo +sun.util.resources.cldr.provider.CLDRLocaleDataMetaInfo From 0c71a5e8f4b218956d00ec3d6b11879297c3b4da Mon Sep 17 00:00:00 2001 From: Brian Burkhalter Date: Wed, 17 Sep 2014 11:04:16 -0700 Subject: [PATCH 65/81] 8058664: Bad fonts in BigIntegerTest Replace bad fonts with spaces. Reviewed-by: alanb --- jdk/test/java/math/BigInteger/BigIntegerTest.java | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/jdk/test/java/math/BigInteger/BigIntegerTest.java b/jdk/test/java/math/BigInteger/BigIntegerTest.java index 3f7c00a810b..b56b0063d74 100644 --- a/jdk/test/java/math/BigInteger/BigIntegerTest.java +++ b/jdk/test/java/math/BigInteger/BigIntegerTest.java @@ -289,12 +289,12 @@ public class BigIntegerTest { * where {@code abs(u) > abs(v)} and {@code a > b && b > 0}, then if * {@code w/z = q1*z + r1} and {@code u/v = q2*v + r2}, then * {@code q1 = q2*pow(2,a-b)} and {@code r1 = r2*pow(2,b)}. The test -     * ensures that {@code v} is just under the B-Z threshold, that {@code z} is -     * over the threshold and {@code w} is much larger than {@code z}. This -     * implies that {@code u/v} uses the standard division algorithm and -     * {@code w/z} uses the B-Z algorithm.  The results of the two algorithms -     * are then compared using the observation described in the foregoing and -     * if they are not equal a failure is logged. + * ensures that {@code v} is just under the B-Z threshold, that {@code z} is + * over the threshold and {@code w} is much larger than {@code z}. This + * implies that {@code u/v} uses the standard division algorithm and + * {@code w/z} uses the B-Z algorithm.  The results of the two algorithms + * are then compared using the observation described in the foregoing and + * if they are not equal a failure is logged. */ public static void divideLarge() { int failCount = 0; From 6d148f368dca457f3a6e94df5a346723690c9076 Mon Sep 17 00:00:00 2001 From: Brian Burkhalter Date: Wed, 17 Sep 2014 14:11:40 -0700 Subject: [PATCH 66/81] 8058679: More bad characters in BigIntegerTest Remove remaining non-US-ASCII characters Reviewed-by: alanb --- jdk/test/java/math/BigInteger/BigIntegerTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/jdk/test/java/math/BigInteger/BigIntegerTest.java b/jdk/test/java/math/BigInteger/BigIntegerTest.java index b56b0063d74..c8d63261e70 100644 --- a/jdk/test/java/math/BigInteger/BigIntegerTest.java +++ b/jdk/test/java/math/BigInteger/BigIntegerTest.java @@ -292,7 +292,7 @@ public class BigIntegerTest { * ensures that {@code v} is just under the B-Z threshold, that {@code z} is * over the threshold and {@code w} is much larger than {@code z}. This * implies that {@code u/v} uses the standard division algorithm and - * {@code w/z} uses the B-Z algorithm.  The results of the two algorithms + * {@code w/z} uses the B-Z algorithm. The results of the two algorithms * are then compared using the observation described in the foregoing and * if they are not equal a failure is logged. */ From 6f7645f43cd40837bed54a1d61f43c319034ebb1 Mon Sep 17 00:00:00 2001 From: Amy Lu Date: Wed, 17 Sep 2014 23:27:59 -0400 Subject: [PATCH 67/81] 8058569: Update java/lang/invoke/lambda tests to eliminate dependency on sun.tools.jar.Main Reviewed-by: dholmes, alanb --- jdk/test/java/lang/invoke/lambda/LUtils.java | 6 ++++-- .../lambda/LambdaAccessControlDoPrivilegedTest.java | 13 +++++++++---- 2 files changed, 13 insertions(+), 6 deletions(-) diff --git a/jdk/test/java/lang/invoke/lambda/LUtils.java b/jdk/test/java/lang/invoke/lambda/LUtils.java index a09d9b87c4d..24c4feaf235 100644 --- a/jdk/test/java/lang/invoke/lambda/LUtils.java +++ b/jdk/test/java/lang/invoke/lambda/LUtils.java @@ -37,8 +37,6 @@ import java.util.Map; * support infrastructure to invoke a java class from the command line */ class LUtils { - static final sun.tools.jar.Main jarTool = - new sun.tools.jar.Main(System.out, System.err, "jar-tool"); static final com.sun.tools.javac.Main javac = new com.sun.tools.javac.Main(); static final File cwd = new File(".").getAbsoluteFile(); @@ -49,6 +47,10 @@ class LUtils { static final File JAVA_BIN_FILE = new File(JAVAHOME, "bin"); static final File JAVA_CMD = new File(JAVA_BIN_FILE, isWindows ? "java.exe" : "java"); + static final File JAR_BIN_FILE = + new File(new File(JAVAHOME).getParentFile(), "bin"); + static final File JAR_CMD = new File(JAR_BIN_FILE, + isWindows ? "jar.exe" : "jar"); protected LUtils() { } diff --git a/jdk/test/java/lang/invoke/lambda/LambdaAccessControlDoPrivilegedTest.java b/jdk/test/java/lang/invoke/lambda/LambdaAccessControlDoPrivilegedTest.java index bd58112f890..4761967e83d 100644 --- a/jdk/test/java/lang/invoke/lambda/LambdaAccessControlDoPrivilegedTest.java +++ b/jdk/test/java/lang/invoke/lambda/LambdaAccessControlDoPrivilegedTest.java @@ -67,12 +67,17 @@ public class LambdaAccessControlDoPrivilegedTest extends LUtils { compile(javacArgs); File jarFile = new File("foo.jar"); String[] jargs = {"cvf", jarFile.getName(), doprivClass.getName()}; - jarTool.run(jargs); + TestResult tr = doExec(JAR_CMD.getAbsolutePath(), + "cvf", jarFile.getName(), + doprivClass.getName()); + if (tr.exitValue != 0){ + throw new RuntimeException(tr.toString()); + } doprivJava.delete(); doprivClass.delete(); - TestResult tr = doExec(JAVA_CMD.getAbsolutePath(), - "-Xbootclasspath/p:foo.jar", - "-cp", ".", "Bar"); + tr = doExec(JAVA_CMD.getAbsolutePath(), + "-Xbootclasspath/p:foo.jar", + "-cp", ".", "Bar"); tr.assertZero("testDoPrivileged fails"); barJava.delete(); barClass.delete(); From 4f5b8de590a22518890f07def2ff1c6b6fbe01e5 Mon Sep 17 00:00:00 2001 From: David Katleman Date: Wed, 17 Sep 2014 22:55:49 -0700 Subject: [PATCH 68/81] Added tag jdk9-b31 for changeset 2b84f4818a54 --- .hgtags-top-repo | 1 + 1 file changed, 1 insertion(+) diff --git a/.hgtags-top-repo b/.hgtags-top-repo index 0f468dba94d..f999c59a70d 100644 --- a/.hgtags-top-repo +++ b/.hgtags-top-repo @@ -273,3 +273,4 @@ ba5645f2735b41ed085d07ba20fa7b322afff318 jdk9-b27 ea2f7981236f3812436958748ab3d26e80a35130 jdk9-b28 9e6581aeda388a23fbee021fc33e6aa152a60657 jdk9-b29 36e9bc875325813ac9c44ac0c617a463091fa9f5 jdk9-b30 +69a84c16d9c28e0e3d504b9c8766c24bafcd58f6 jdk9-b31 From 0c813c1b9e715c4384ef29e56662b991d4eedabd Mon Sep 17 00:00:00 2001 From: David Katleman Date: Wed, 17 Sep 2014 22:55:51 -0700 Subject: [PATCH 69/81] Added tag jdk9-b31 for changeset 8d0d35462d9b --- hotspot/.hgtags | 1 + 1 file changed, 1 insertion(+) diff --git a/hotspot/.hgtags b/hotspot/.hgtags index a7b7e9b5c01..2cd0f3f9909 100644 --- a/hotspot/.hgtags +++ b/hotspot/.hgtags @@ -433,3 +433,4 @@ f95347244306affc32ce3056f27ceff7b2100810 jdk9-b27 657294869d7ff063e055f5492cab7ce5612ca851 jdk9-b28 deb29e92f68ace2808a36ecfa18c7d61dcb645bb jdk9-b29 5c722dffbc0f34eb8d903dca7b261e52248fa17e jdk9-b30 +9f7d155d28e519f3e4645dc21cf185c25f3176ed jdk9-b31 From 1a8d48432f8a18f35a04e67d8eef7c85682d28d6 Mon Sep 17 00:00:00 2001 From: David Katleman Date: Wed, 17 Sep 2014 22:55:51 -0700 Subject: [PATCH 70/81] Added tag jdk9-b31 for changeset 45ea6e55697b --- corba/.hgtags | 1 + 1 file changed, 1 insertion(+) diff --git a/corba/.hgtags b/corba/.hgtags index 210911039ff..0614d2d8d68 100644 --- a/corba/.hgtags +++ b/corba/.hgtags @@ -273,3 +273,4 @@ da08cca6b97f41b7081a3e176dcb400af6e4bb26 jdk9-b25 a00b04ef067e39f50b9a0fea6f1904e35d632a73 jdk9-b28 163a9cd806fd09970baf1f5f42b92a3cfe7ee945 jdk9-b29 98967ae6ae53ebf15615e07cd5a6b1ae04dfd84c jdk9-b30 +c432b80aadd0cb2b2361b02add4d671957d4cec9 jdk9-b31 From 6f31d1df92bf3a8fb02642fabd4813b20f598d19 Mon Sep 17 00:00:00 2001 From: David Katleman Date: Wed, 17 Sep 2014 22:55:55 -0700 Subject: [PATCH 71/81] Added tag jdk9-b31 for changeset abaac15e3bd1 --- jaxp/.hgtags | 1 + 1 file changed, 1 insertion(+) diff --git a/jaxp/.hgtags b/jaxp/.hgtags index ea01e6ee220..b4e86b446b6 100644 --- a/jaxp/.hgtags +++ b/jaxp/.hgtags @@ -273,3 +273,4 @@ a5aea8318ae4a9c2105228568688875142d70344 jdk9-b26 dc1e26434b3fd7e9b8eeab149103c1e30965f95c jdk9-b28 30adcd13a313ea91e81164801a2f89282756d933 jdk9-b29 d181d4002214e4914d5525bd5ee13369311c765c jdk9-b30 +292317ebc7dbaca6b3965f0bc7b38a2cee733b7a jdk9-b31 From 07da4cfb66e935a60754f2e8c9de2e9e4722cf6e Mon Sep 17 00:00:00 2001 From: David Katleman Date: Wed, 17 Sep 2014 22:56:04 -0700 Subject: [PATCH 72/81] Added tag jdk9-b31 for changeset 38f3aee12cf1 --- jaxws/.hgtags | 1 + 1 file changed, 1 insertion(+) diff --git a/jaxws/.hgtags b/jaxws/.hgtags index e768a03efa3..9a4f2b0c12b 100644 --- a/jaxws/.hgtags +++ b/jaxws/.hgtags @@ -276,3 +276,4 @@ dcaa586ab756420e9a62643793bacef2c84bf637 jdk9-b27 5282a14f131f897cc9575872c0fae72d47dc4e65 jdk9-b28 3d1a4bfb6abbf5011ba6d8896301ee3b6ef3ba72 jdk9-b29 e58d3ea638c3824f01547596b2a98aa5f77c4a5c jdk9-b30 +7af228ae847f3c02aaafb7b01cdbb3bdc2e89e77 jdk9-b31 From b7819d0dd92f5e32b3e5b1f91b9dedd9b3dd89c7 Mon Sep 17 00:00:00 2001 From: David Katleman Date: Wed, 17 Sep 2014 22:56:07 -0700 Subject: [PATCH 73/81] Added tag jdk9-b31 for changeset fe7c921b71f0 --- jdk/.hgtags | 1 + 1 file changed, 1 insertion(+) diff --git a/jdk/.hgtags b/jdk/.hgtags index bea594c1bfc..51363dadfc8 100644 --- a/jdk/.hgtags +++ b/jdk/.hgtags @@ -273,3 +273,4 @@ f0870554049807d3392bd7976ab114f7f2b7bafa jdk9-b27 1828f73b35cfe35e460e41fd6e087ab1f83e0621 jdk9-b28 2da27e8e2c865e154f0c2eb9009f011a44649b11 jdk9-b29 8d24fb4493f13d380a2adf62d444e1e5a4451f37 jdk9-b30 +71e99dae28f9791287b88d46e16a266b564f22be jdk9-b31 From caab6b308c1ee57047fad4eeeb5d6c01ab036e17 Mon Sep 17 00:00:00 2001 From: David Katleman Date: Wed, 17 Sep 2014 22:56:11 -0700 Subject: [PATCH 74/81] Added tag jdk9-b31 for changeset 34aa137c3d5f --- langtools/.hgtags | 1 + 1 file changed, 1 insertion(+) diff --git a/langtools/.hgtags b/langtools/.hgtags index 7000df2d0bb..db7e64f292e 100644 --- a/langtools/.hgtags +++ b/langtools/.hgtags @@ -273,3 +273,4 @@ d60b572d759449913d02478219ad87e0574a3909 jdk9-b25 016786f793149135ab6b23c71087c1ca12691d77 jdk9-b28 13705e2ddeb20a78e066595a1709e61f257189e9 jdk9-b29 ef5427c13e1e741c457a2ed868e3b6d6bf717754 jdk9-b30 +0046d55383a9d873ffbc7253d7c5e28ab98c5bea jdk9-b31 From a1186e07b99580e05418a08ae39ff95330f2e496 Mon Sep 17 00:00:00 2001 From: David Katleman Date: Wed, 17 Sep 2014 22:56:12 -0700 Subject: [PATCH 75/81] Added tag jdk9-b31 for changeset 12198895df07 --- nashorn/.hgtags | 1 + 1 file changed, 1 insertion(+) diff --git a/nashorn/.hgtags b/nashorn/.hgtags index fc829400c18..4ae5386fc05 100644 --- a/nashorn/.hgtags +++ b/nashorn/.hgtags @@ -264,3 +264,4 @@ ed60a4e9dd35dcabb9b24e90434f5f615d988981 jdk9-b26 00c31e5eaf26f9b238165157b9d1c617b03abcb6 jdk9-b28 e541ebaf2ab7038333ad0c13f4decd327c26dd15 jdk9-b29 072dbed6c5d968a6b9e156c36cd8838b4ff86ea1 jdk9-b30 +77efdecfa2a5c28672b7c7dcc2d1b52dcb90d493 jdk9-b31 From 99ec33372d84f813ce5b436e94ddc369922f08be Mon Sep 17 00:00:00 2001 From: Bhavesh Patel Date: Wed, 17 Sep 2014 23:52:19 -0700 Subject: [PATCH 76/81] 8043698: tag not getting generated in package-summary pages for un-named packages Reviewed-by: jjg, ksrini --- .../sun/tools/doclets/formats/html/PackageWriterImpl.java | 3 +-- .../tools/doclets/formats/html/ProfilePackageWriterImpl.java | 3 +-- .../sun/javadoc/testUnnamedPackage/TestUnnamedPackage.java | 5 ++++- 3 files changed, 6 insertions(+), 5 deletions(-) diff --git a/langtools/src/jdk.javadoc/share/classes/com/sun/tools/doclets/formats/html/PackageWriterImpl.java b/langtools/src/jdk.javadoc/share/classes/com/sun/tools/doclets/formats/html/PackageWriterImpl.java index a3d4ddd208b..7aa5c5dd07c 100644 --- a/langtools/src/jdk.javadoc/share/classes/com/sun/tools/doclets/formats/html/PackageWriterImpl.java +++ b/langtools/src/jdk.javadoc/share/classes/com/sun/tools/doclets/formats/html/PackageWriterImpl.java @@ -90,8 +90,7 @@ public class PackageWriterImpl extends HtmlDocletWriter * {@inheritDoc} */ public Content getPackageHeader(String heading) { - String pkgName = packageDoc.name(); - Content bodyTree = getBody(true, getWindowTitle(pkgName)); + Content bodyTree = getBody(true, getWindowTitle(utils.getPackageName(packageDoc))); addTop(bodyTree); addNavLinks(true, bodyTree); HtmlTree div = new HtmlTree(HtmlTag.DIV); diff --git a/langtools/src/jdk.javadoc/share/classes/com/sun/tools/doclets/formats/html/ProfilePackageWriterImpl.java b/langtools/src/jdk.javadoc/share/classes/com/sun/tools/doclets/formats/html/ProfilePackageWriterImpl.java index 6d66ed26faf..f85bc38813c 100644 --- a/langtools/src/jdk.javadoc/share/classes/com/sun/tools/doclets/formats/html/ProfilePackageWriterImpl.java +++ b/langtools/src/jdk.javadoc/share/classes/com/sun/tools/doclets/formats/html/ProfilePackageWriterImpl.java @@ -103,8 +103,7 @@ public class ProfilePackageWriterImpl extends HtmlDocletWriter * {@inheritDoc} */ public Content getPackageHeader(String heading) { - String pkgName = packageDoc.name(); - Content bodyTree = getBody(true, getWindowTitle(pkgName)); + Content bodyTree = getBody(true, getWindowTitle(utils.getPackageName(packageDoc))); addTop(bodyTree); addNavLinks(true, bodyTree); HtmlTree div = new HtmlTree(HtmlTag.DIV); diff --git a/langtools/test/com/sun/javadoc/testUnnamedPackage/TestUnnamedPackage.java b/langtools/test/com/sun/javadoc/testUnnamedPackage/TestUnnamedPackage.java index 85e8a42d912..13e976452ee 100644 --- a/langtools/test/com/sun/javadoc/testUnnamedPackage/TestUnnamedPackage.java +++ b/langtools/test/com/sun/javadoc/testUnnamedPackage/TestUnnamedPackage.java @@ -23,7 +23,7 @@ /* * @test - * @bug 4904075 4774450 5015144 + * @bug 4904075 4774450 5015144 8043698 * @summary Reference unnamed package as "Unnamed", not empty string. * Generate a package summary for the unnamed package. * @author jamieh @@ -51,6 +51,9 @@ public class TestUnnamedPackage extends JavadocTester { "This is a package comment for the unnamed package.", "This is a class in the unnamed package."); + checkOutput("package-summary.html", true, + "<title><Unnamed>"); + checkOutput("package-tree.html", true, "

Hierarchy For Package <Unnamed>

"); From b02c07123c114d53c20d66db548c09f4a38384b5 Mon Sep 17 00:00:00 2001 From: Bhavesh Patel Date: Thu, 18 Sep 2014 00:50:48 -0700 Subject: [PATCH 77/81] 8047745: Javadoc should include encoding information in generated html files Reviewed-by: jjg, ksrini --- .../formats/html/HtmlDocletWriter.java | 13 +++++----- .../formats/html/markup/HtmlConstants.java | 5 ++++ .../formats/html/markup/HtmlDocWriter.java | 9 +++---- .../sun/javadoc/testCharset/TestCharset.java | 25 ++++++++++++++----- 4 files changed, 34 insertions(+), 18 deletions(-) diff --git a/langtools/src/jdk.javadoc/share/classes/com/sun/tools/doclets/formats/html/HtmlDocletWriter.java b/langtools/src/jdk.javadoc/share/classes/com/sun/tools/doclets/formats/html/HtmlDocletWriter.java index 78f14723010..7d9bc435733 100644 --- a/langtools/src/jdk.javadoc/share/classes/com/sun/tools/doclets/formats/html/HtmlDocletWriter.java +++ b/langtools/src/jdk.javadoc/share/classes/com/sun/tools/doclets/formats/html/HtmlDocletWriter.java @@ -397,20 +397,19 @@ public class HtmlDocletWriter extends HtmlDocWriter { Content htmlComment = new Comment(configuration.getText("doclet.New_Page")); Content head = new HtmlTree(HtmlTag.HEAD); head.addContent(getGeneratedBy(!configuration.notimestamp)); - if (configuration.charset.length() > 0) { - Content meta = HtmlTree.META("Content-Type", CONTENT_TYPE, - configuration.charset); - head.addContent(meta); - } head.addContent(getTitle()); + Content meta = HtmlTree.META("Content-Type", CONTENT_TYPE, + (configuration.charset.length() > 0) ? + configuration.charset : HtmlConstants.HTML_DEFAULT_CHARSET); + head.addContent(meta); if (!configuration.notimestamp) { SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd"); - Content meta = HtmlTree.META("date", dateFormat.format(new Date())); + meta = HtmlTree.META("date", dateFormat.format(new Date())); head.addContent(meta); } if (metakeywords != null) { for (String metakeyword : metakeywords) { - Content meta = HtmlTree.META("keywords", metakeyword); + meta = HtmlTree.META("keywords", metakeyword); head.addContent(meta); } } diff --git a/langtools/src/jdk.javadoc/share/classes/com/sun/tools/doclets/formats/html/markup/HtmlConstants.java b/langtools/src/jdk.javadoc/share/classes/com/sun/tools/doclets/formats/html/markup/HtmlConstants.java index 98651468f95..aa18de71eb2 100644 --- a/langtools/src/jdk.javadoc/share/classes/com/sun/tools/doclets/formats/html/markup/HtmlConstants.java +++ b/langtools/src/jdk.javadoc/share/classes/com/sun/tools/doclets/formats/html/markup/HtmlConstants.java @@ -220,4 +220,9 @@ public class HtmlConstants { * Html tag for the member heading. */ public static final HtmlTag MEMBER_HEADING = HtmlTag.H4; + + /** + * Default charset for HTML. + */ + public static final String HTML_DEFAULT_CHARSET = "utf-8"; } diff --git a/langtools/src/jdk.javadoc/share/classes/com/sun/tools/doclets/formats/html/markup/HtmlDocWriter.java b/langtools/src/jdk.javadoc/share/classes/com/sun/tools/doclets/formats/html/markup/HtmlDocWriter.java index 1ddf6e67b01..ab3200a0301 100644 --- a/langtools/src/jdk.javadoc/share/classes/com/sun/tools/doclets/formats/html/markup/HtmlDocWriter.java +++ b/langtools/src/jdk.javadoc/share/classes/com/sun/tools/doclets/formats/html/markup/HtmlDocWriter.java @@ -311,13 +311,12 @@ public abstract class HtmlDocWriter extends HtmlWriter { Content htmlComment = new Comment(configuration.getText("doclet.New_Page")); Content head = new HtmlTree(HtmlTag.HEAD); head.addContent(getGeneratedBy(!noTimeStamp)); - if (configuration.charset.length() > 0) { - Content meta = HtmlTree.META("Content-Type", CONTENT_TYPE, - configuration.charset); - head.addContent(meta); - } Content windowTitle = HtmlTree.TITLE(new StringContent(title)); head.addContent(windowTitle); + Content meta = HtmlTree.META("Content-Type", CONTENT_TYPE, + (configuration.charset.length() > 0) ? + configuration.charset : HtmlConstants.HTML_DEFAULT_CHARSET); + head.addContent(meta); head.addContent(getFramesetJavaScript()); Content htmlTree = HtmlTree.HTML(configuration.getLocale().getLanguage(), head, frameset); diff --git a/langtools/test/com/sun/javadoc/testCharset/TestCharset.java b/langtools/test/com/sun/javadoc/testCharset/TestCharset.java index eede6110636..b08c128f3ac 100644 --- a/langtools/test/com/sun/javadoc/testCharset/TestCharset.java +++ b/langtools/test/com/sun/javadoc/testCharset/TestCharset.java @@ -23,7 +23,7 @@ /* * @test - * @bug 7052170 + * @bug 7052170 8047745 * @summary Run a test on -charset to make sure the charset gets generated as a * part of the meta tag. * @author Bhavesh Patel @@ -42,19 +42,32 @@ public class TestCharset extends JavadocTester { @Test void test() { javadoc("-d", "out", - "-charset", "UTF-8", + "-charset", "ISO-8859-1", "-sourcepath", testSrc, "pkg"); checkExit(Exit.OK); checkOutput("index.html", true, - ""); + ""); checkOutput("pkg/Foo.html", true, - ""); + ""); checkOutput("index.html", false, - ""); + ""); checkOutput("pkg/Foo.html", false, - ""); + ""); + } + + @Test + void test1() { + javadoc("-d", "out-1", + "-sourcepath", testSrc, + "pkg"); + checkExit(Exit.OK); + + checkOutput("index.html", true, + ""); + checkOutput("pkg/Foo.html", true, + ""); } } From 83a26602a9b18f539d9f53a00a125e389c8f7b79 Mon Sep 17 00:00:00 2001 From: Shanliang Jiang Date: Thu, 18 Sep 2014 16:16:07 +0200 Subject: [PATCH 78/81] 8050115: javax/management/monitor/GaugeMonitorDeadlockTest.java fails intermittently Reviewed-by: dfuchs, dholmes --- jdk/test/ProblemList.txt | 3 - .../monitor/GaugeMonitorDeadlockTest.java | 80 ++++++++++++++----- 2 files changed, 61 insertions(+), 22 deletions(-) diff --git a/jdk/test/ProblemList.txt b/jdk/test/ProblemList.txt index 9b69db7c116..7aed17601cd 100644 --- a/jdk/test/ProblemList.txt +++ b/jdk/test/ProblemList.txt @@ -139,9 +139,6 @@ com/sun/management/OperatingSystemMXBean/GetProcessCpuLoad.java aix-all com/sun/management/OperatingSystemMXBean/GetSystemCpuLoad.java aix-all javax/management/MBeanServer/OldMBeanServerTest.java aix-all -# 8050115 -javax/management/monitor/GaugeMonitorDeadlockTest.java generic-all - ############################################################################ # jdk_math diff --git a/jdk/test/javax/management/monitor/GaugeMonitorDeadlockTest.java b/jdk/test/javax/management/monitor/GaugeMonitorDeadlockTest.java index b2157056b5a..c85c223dff8 100644 --- a/jdk/test/javax/management/monitor/GaugeMonitorDeadlockTest.java +++ b/jdk/test/javax/management/monitor/GaugeMonitorDeadlockTest.java @@ -36,8 +36,9 @@ */ import java.lang.management.ManagementFactory; +import java.lang.management.ThreadInfo; +import java.lang.management.ThreadMXBean; import java.util.concurrent.atomic.AtomicInteger; -import javax.management.Attribute; import javax.management.JMX; import javax.management.MBeanServer; import javax.management.Notification; @@ -47,10 +48,16 @@ import javax.management.monitor.GaugeMonitor; import javax.management.monitor.GaugeMonitorMBean; public class GaugeMonitorDeadlockTest { + private static enum When {IN_GET_ATTRIBUTE, IN_NOTIFY}; + private static long checkingTime; public static void main(String[] args) throws Exception { if (args.length != 1) throw new Exception("Arg should be test number"); + double factor = Double.parseDouble(System.getProperty("test.timeout.factor", "1.0")); + checkingTime = (long)factor*1000; + System.out.println("=== checkingTime = " + checkingTime + "ms"); + int testNo = Integer.parseInt(args[0]) - 1; TestCase test = testCases[testNo]; System.out.println("Test: " + test.getDescription()); @@ -58,8 +65,6 @@ public class GaugeMonitorDeadlockTest { System.out.println("Test passed"); } - private static enum When {IN_GET_ATTRIBUTE, IN_NOTIFY}; - private static abstract class TestCase { TestCase(String description, When when) { this.description = description; @@ -98,16 +103,29 @@ public class GaugeMonitorDeadlockTest { monitorProxy.setNotifyLow(true); monitorProxy.start(); + System.out.println("=== Waiting observedProxy.getGetCount() to be " + + "changed, presumable deadlock if timeout?"); final int initGetCount = observedProxy.getGetCount(); - int getCount = initGetCount; - for (int i = 0; i < 2000; i++) { // 2000 * 10 = 20 seconds - getCount = observedProxy.getGetCount(); - if (getCount != initGetCount) - break; - Thread.sleep(10); + long checkedTime = System.currentTimeMillis(); + long nowTime; + ThreadMXBean threadMXBean = ManagementFactory.getThreadMXBean(); + while (observedProxy.getGetCount() == initGetCount) { + Thread.sleep(100); + + nowTime = System.currentTimeMillis(); + if (nowTime - checkedTime >= checkingTime) { + System.out.println("=== Checking deadlocked ..."); + if (threadMXBean.findDeadlockedThreads() != null) { + for (ThreadInfo info : threadMXBean.dumpAllThreads(true, true)) { + System.out.println(info); + } + throw new Error("Found deadlocked threads: " + + threadMXBean.findDeadlockedThreads().length); + } + checkedTime = System.currentTimeMillis(); + } } - if (getCount <= initGetCount) - throw new Exception("Test failed: presumable deadlock"); + // This won't show up as a deadlock in CTRL-\ or in // ThreadMXBean.findDeadlockedThreads(), because they don't // see that thread A is waiting for thread B (B.join()), and @@ -117,13 +135,13 @@ public class GaugeMonitorDeadlockTest { // so if we want to test notify behaviour we can trigger by // exceeding the threshold. if (when == When.IN_NOTIFY) { + final Thread testedThread = new Thread(sensitiveThing); final AtomicInteger notifCount = new AtomicInteger(); final NotificationListener listener = new NotificationListener() { public void handleNotification(Notification n, Object h) { - Thread t = new Thread(sensitiveThing); - t.start(); + testedThread.start(); try { - t.join(); + testedThread.join(); } catch (InterruptedException e) { throw new RuntimeException(e); } @@ -132,12 +150,36 @@ public class GaugeMonitorDeadlockTest { }; mbs.addNotificationListener(monitorName, listener, null, null); observedProxy.setThing(1000); - for (int i = 0; i < 2000 && notifCount.get() == 0; i++) - Thread.sleep(10); - if (notifCount.get() == 0) - throw new Exception("Test failed: presumable deadlock"); - } + System.out.println("=== Waiting notifications, presumable " + + "deadlock if timeout?"); + long startTime = System.currentTimeMillis(); + checkedTime = startTime; + while (notifCount.get() == 0) { + Thread.sleep(100); + nowTime = System.currentTimeMillis(); + if (nowTime - checkedTime >= checkingTime) { + System.out.println("=== Checking the thread state ..."); + if (testedThread.isAlive()) { + System.out.println("=== Waiting testedThread to die " + + "after " + (nowTime - startTime) + "ms"); + + ThreadInfo tinfo = threadMXBean.getThreadInfo(testedThread.getId()); + if (Thread.State.BLOCKED.equals(tinfo.getThreadState())) { + for (ThreadInfo info : threadMXBean.dumpAllThreads(true, true)) { + System.out.println(info); + } + } else { + System.out.println(tinfo); + } + } else { + System.out.println("=== The testedThread is dead as wished, " + + "the test must be passed soon."); + } + checkedTime = System.currentTimeMillis(); + } + } + } } abstract void doSensitiveThing(GaugeMonitorMBean monitorProxy, From 20abfd774aafc09789e535c245f1a8c8d842fd17 Mon Sep 17 00:00:00 2001 From: Aleksey Shipilev Date: Thu, 18 Sep 2014 18:33:05 +0400 Subject: [PATCH 79/81] 8058661: Compiled LambdaForms should inherit from Object to improve class loading performance Reviewed-by: vlivanov, jrose --- .../classes/java/lang/invoke/InvokerBytecodeGenerator.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/jdk/src/java.base/share/classes/java/lang/invoke/InvokerBytecodeGenerator.java b/jdk/src/java.base/share/classes/java/lang/invoke/InvokerBytecodeGenerator.java index 0bfa6e32a98..96a302a0dcc 100644 --- a/jdk/src/java.base/share/classes/java/lang/invoke/InvokerBytecodeGenerator.java +++ b/jdk/src/java.base/share/classes/java/lang/invoke/InvokerBytecodeGenerator.java @@ -62,7 +62,7 @@ class InvokerBytecodeGenerator { private static final String CLL_SIG = "(L" + CLS + ";L" + OBJ + ";)L" + OBJ + ";"; /** Name of its super class*/ - private static final String superName = LF; + private static final String superName = OBJ; /** Name of new class */ private final String className; @@ -97,7 +97,7 @@ class InvokerBytecodeGenerator { if (DUMP_CLASS_FILES) { className = makeDumpableClassName(className); } - this.className = superName + "$" + className; + this.className = LF + "$" + className; this.sourceFile = "LambdaForm$" + className; this.lambdaForm = lambdaForm; this.invokerName = invokerName; From 746ed2b4eb6c4b0052ce4aa7efae7076bc2f7664 Mon Sep 17 00:00:00 2001 From: Amanda Jiang Date: Thu, 18 Sep 2014 15:36:38 -0400 Subject: [PATCH 80/81] 8050281: New permission tests for JEP 140 Reviewed-by: mullan --- .../LimitedDoPrivilegedWithNullPerms.java | 96 ++++++++++++++++ .../LimitedDoPrivilegedWithThread.java | 108 ++++++++++++++++++ .../java/security/AccessController/policy | 4 + 3 files changed, 208 insertions(+) create mode 100644 jdk/test/java/security/AccessController/LimitedDoPrivilegedWithNullPerms.java create mode 100644 jdk/test/java/security/AccessController/LimitedDoPrivilegedWithThread.java create mode 100644 jdk/test/java/security/AccessController/policy diff --git a/jdk/test/java/security/AccessController/LimitedDoPrivilegedWithNullPerms.java b/jdk/test/java/security/AccessController/LimitedDoPrivilegedWithNullPerms.java new file mode 100644 index 00000000000..13b2db47c0f --- /dev/null +++ b/jdk/test/java/security/AccessController/LimitedDoPrivilegedWithNullPerms.java @@ -0,0 +1,96 @@ +/* + * Copyright (c) 2013,2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8050281 + * @summary Test that NullPointerException is thrown if any element of perms + * parameter is null + * @run testng LimitedDoPrivilegedWithNullPerms + */ +import java.security.AccessControlContext; +import java.security.AccessController; +import java.security.Permission; +import java.security.PrivilegedAction; +import java.security.PrivilegedActionException; +import java.security.PrivilegedExceptionAction; +import java.util.PropertyPermission; +import org.testng.annotations.Test; + +public class LimitedDoPrivilegedWithNullPerms { + + AccessControlContext acc = AccessController.getContext(); + Permission p1 = new PropertyPermission("user.name", "read"); + + @Test(expectedExceptions = NullPointerException.class) + public void test1() { + AccessController.doPrivileged( + (PrivilegedAction) () -> null, acc, null); + } + + @Test(expectedExceptions = NullPointerException.class) + public void test2() { + AccessController.doPrivileged( + (PrivilegedAction) () -> null, acc, p1, null); + } + + @Test(expectedExceptions = NullPointerException.class) + public void test3() { + AccessController.doPrivilegedWithCombiner( + (PrivilegedAction) () -> null, acc, null); + } + + @Test(expectedExceptions = NullPointerException.class) + public void test4() { + AccessController.doPrivilegedWithCombiner( + (PrivilegedAction) () -> null, acc, p1, null); + } + + @Test(expectedExceptions = NullPointerException.class) + public void test5() throws PrivilegedActionException { + AccessController.doPrivileged( + (PrivilegedExceptionAction) () -> null, + acc, null); + } + + @Test(expectedExceptions = NullPointerException.class) + public void test6() throws PrivilegedActionException { + AccessController.doPrivileged( + (PrivilegedExceptionAction) () -> null, + acc, p1, null); + } + + @Test(expectedExceptions = NullPointerException.class) + public void test7() throws PrivilegedActionException { + AccessController.doPrivilegedWithCombiner( + (PrivilegedExceptionAction) () -> null, + acc, null); + } + + @Test(expectedExceptions = NullPointerException.class) + public void test8() throws PrivilegedActionException { + AccessController.doPrivilegedWithCombiner( + (PrivilegedExceptionAction) () -> null, + acc, p1, null); + } +} diff --git a/jdk/test/java/security/AccessController/LimitedDoPrivilegedWithThread.java b/jdk/test/java/security/AccessController/LimitedDoPrivilegedWithThread.java new file mode 100644 index 00000000000..955f39d86fb --- /dev/null +++ b/jdk/test/java/security/AccessController/LimitedDoPrivilegedWithThread.java @@ -0,0 +1,108 @@ +/* + * Copyright (c) 2013,2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8050281 + * @summary Test limited doprivileged action with trhead calls. + * @run main/othervm/policy=policy LimitedDoPrivilegedWithThread + */ +import java.io.FilePermission; +import java.security.AccessControlContext; +import java.security.AccessControlException; +import java.security.AccessController; +import java.security.Permission; +import java.security.PrivilegedAction; +import java.security.ProtectionDomain; +import java.util.PropertyPermission; + +public class LimitedDoPrivilegedWithThread { + + private static final Permission PROPERTYPERM + = new PropertyPermission("user.name", "read"); + private static final Permission FILEPERM + = new FilePermission("*", "read"); + private static final AccessControlContext ACC + = new AccessControlContext( + new ProtectionDomain[]{new ProtectionDomain(null, null)}); + + public static void main(String args[]) { + //parent thread without any permission + AccessController.doPrivileged( + (PrivilegedAction) () -> { + Thread ct = new Thread( + new ChildThread(PROPERTYPERM, FILEPERM)); + ct.start(); + try { + ct.join(); + } catch (InterruptedException ie) { + Thread.currentThread().interrupt(); + ie.printStackTrace(); + throw new RuntimeException("Unexpected InterruptedException"); + } + return null; + }, ACC); + } +} + +class ChildThread implements Runnable { + + private final Permission P1; + private final Permission P2; + private boolean catchACE = false; + + public ChildThread(Permission p1, Permission p2) { + this.P1 = p1; + this.P2 = p2; + } + + @Override + public void run() { + //Verified that child thread has permission p1, + runTest(null, P1, false, 1); + //Verified that child thread inherits parent thread's access control context + AccessControlContext childAcc = AccessController.getContext(); + runTest(childAcc, P1, true, 2); + //Verified that we can give permision p2 to limit the "privilege" of the + //class calling doprivileged action, stack walk will continue + runTest(null, P2, true, 3); + + } + + public void runTest(AccessControlContext acc, Permission perm, + boolean expectACE, int id) { + + AccessController.doPrivileged( + (PrivilegedAction) () -> { + try { + AccessController.getContext().checkPermission(P1); + } catch (AccessControlException ace) { + catchACE = true; + } + if (catchACE ^ expectACE) { + throw new RuntimeException("test" + id + " failed"); + } + return null; + }, acc, perm); + } +} diff --git a/jdk/test/java/security/AccessController/policy b/jdk/test/java/security/AccessController/policy new file mode 100644 index 00000000000..83ed146df9e --- /dev/null +++ b/jdk/test/java/security/AccessController/policy @@ -0,0 +1,4 @@ +grant{ + permission java.util.PropertyPermission "user.name", "read"; + permission java.io.FilePermission "*", "read"; +}; From 4498f2b1ca47eb960fe8956de5c4d40c2b79429e Mon Sep 17 00:00:00 2001 From: "J. Duke" Date: Wed, 5 Jul 2017 20:01:05 +0200 Subject: [PATCH 81/81] Added tag jdk9-b31 for changeset 9d0e6639a4d7 --- .hgtags | 1 + 1 file changed, 1 insertion(+) diff --git a/.hgtags b/.hgtags index 1cb41f0429d..5c8ee1a580f 100644 --- a/.hgtags +++ b/.hgtags @@ -273,3 +273,4 @@ d06a6d3c66c08293b2a9650f3cc01fd55c620e65 jdk9-b27 f4269e8f454eb77763ecee228a88ae102a9aef6e jdk9-b28 c36c0092693707a8255561433647e8c3cd724ccd jdk9-b29 b2287cac7813c70ed7f679d9a46fe774bd4005f8 jdk9-b30 +9d0e6639a4d71b63507dd94b1a028e963b27e798 jdk9-b31