From c4f814598efce30fe1e025cbdc992cece68bf971 Mon Sep 17 00:00:00 2001
From: John R Rose
Date: Wed, 21 Oct 2009 23:19:48 -0700
Subject: [PATCH 001/221] 6891770: JSR 292 API needs initial unit tests
Backport working mlvm regression test to M3 implementation of JSR 292; requires jtreg 4.1
Reviewed-by: twisti
---
jdk/test/java/dyn/MethodHandlesTest.java | 881 +++++++++++++++++++++++
1 file changed, 881 insertions(+)
create mode 100644 jdk/test/java/dyn/MethodHandlesTest.java
diff --git a/jdk/test/java/dyn/MethodHandlesTest.java b/jdk/test/java/dyn/MethodHandlesTest.java
new file mode 100644
index 00000000000..26142c8c527
--- /dev/null
+++ b/jdk/test/java/dyn/MethodHandlesTest.java
@@ -0,0 +1,881 @@
+/*
+ * Copyright 2009 Sun Microsystems, 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. Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+/* @test
+ * @summary unit tests for java.dyn.MethodHandles
+ * @compile -XDinvokedynamic MethodHandlesTest.java
+ * @run junit/othervm -XX:+UnlockExperimentalVMOptions -XX:+EnableInvokeDynamic jdk.java.dyn.MethodHandlesTest
+ */
+
+package jdk.java.dyn;
+
+import java.dyn.*;
+import java.dyn.MethodHandles.Lookup;
+import java.lang.reflect.*;
+import java.util.*;
+import org.junit.*;
+import static org.junit.Assert.*;
+import static org.junit.Assume.assumeTrue;
+
+
+/**
+ *
+ * @author jrose
+ */
+public class MethodHandlesTest {
+ // How much output?
+ static int verbosity = 1;
+
+ // Set this true during development if you want to fast-forward to
+ // a particular new, non-working test. Tests which are known to
+ // work (or have recently worked) test this flag and return on true.
+ static boolean CAN_SKIP_WORKING = false;
+ //static { CAN_SKIP_WORKING = true; }
+
+ // Set true to test more calls. If false, some tests are just
+ // lookups, without exercising the actual method handle.
+ static boolean DO_MORE_CALLS = false;
+
+
+ @Test
+ public void testFirst() throws Throwable {
+ verbosity += 9; try {
+ // left blank for debugging
+ } finally { verbosity -= 9; }
+ }
+
+ static final int MAX_ARG_INCREASE = 3;
+
+ public MethodHandlesTest() {
+ }
+
+ @Before
+ public void checkImplementedPlatform() {
+ boolean platformOK = false;
+ Properties properties = System.getProperties();
+ String vers = properties.getProperty("java.vm.version");
+ String name = properties.getProperty("java.vm.name");
+ String arch = properties.getProperty("os.arch");
+ if (arch.equals("i386") &&
+ (name.contains("Client") || name.contains("Server"))
+ ) {
+ platformOK = true;
+ } else {
+ System.err.println("Skipping tests for unsupported platform: "+Arrays.asList(vers, name, arch));
+ }
+ assumeTrue(platformOK);
+ }
+
+ String testName;
+ int posTests, negTests;
+ @After
+ public void printCounts() {
+ if (verbosity >= 1 && (posTests | negTests) != 0) {
+ System.out.println();
+ if (posTests != 0) System.out.println("=== "+testName+": "+posTests+" positive test cases run");
+ if (negTests != 0) System.out.println("=== "+testName+": "+negTests+" negative test cases run");
+ }
+ }
+ void countTest(boolean positive) {
+ if (positive) ++posTests;
+ else ++negTests;
+ }
+ void countTest() { countTest(true); }
+ void startTest(String name) {
+ if (testName != null) printCounts();
+ if (verbosity >= 0)
+ System.out.println(name);
+ posTests = negTests = 0;
+ testName = name;
+ }
+
+ @BeforeClass
+ public static void setUpClass() throws Exception {
+ calledLog.clear();
+ calledLog.add(null);
+ nextArg = 1000000;
+ }
+
+ @AfterClass
+ public static void tearDownClass() throws Exception {
+ }
+
+ static List
*
*
Relative {@link #get($type$[]) bulk get}
- * methods that transfer contiguous sequences of $fulltype$s from this buffer
+ * methods that transfer contiguous sequences of $type$s from this buffer
* into an array; {#if[!byte]?and}
*
*
Relative {@link #put($type$[]) bulk put}
- * methods that transfer contiguous sequences of $fulltype$s from $a$
- * $fulltype$ array{#if[char]?, a string,} or some other $fulltype$
+ * methods that transfer contiguous sequences of $type$s from $a$
+ * $type$ array{#if[char]?, a string,} or some other $type$
* buffer into this buffer;{#if[!byte]? and}
Methods for {@link #compact compacting}, {@link
* #duplicate duplicating}, and {@link #slice
- * slicing} $a$ $fulltype$ buffer.
+ * slicing} $a$ $type$ buffer.
*
*
*
- *
$Fulltype$ buffers can be created either by {@link #allocate
+ *
$Type$ buffers can be created either by {@link #allocate
*
allocation}, which allocates space for the buffer's
*
#if[byte]
*
* content, or by {@link #wrap($type$[]) wrapping} an
- * existing $fulltype$ array {#if[char]?or string} into a buffer.
+ * existing $type$ array {#if[char]?or string} into a buffer.
*
#else[byte]
*
* content, by {@link #wrap($type$[]) wrapping} an existing
- * $fulltype$ array {#if[char]?or string} into a buffer, or by creating a
+ * $type$ array {#if[char]?or string} into a buffer, or by creating a
* view of an existing byte buffer.
*
#end[byte]
@@ -189,12 +189,12 @@ import java.io.IOException;
*
#if[!byte]
*
- *
Like a byte buffer, $a$ $fulltype$ buffer is either Like a byte buffer, $a$ $type$ buffer is either direct or non-direct. A
- * $fulltype$ buffer created via the wrap methods of this class will
- * be non-direct. $A$ $fulltype$ buffer created as a view of a byte buffer will
+ * $type$ buffer created via the wrap methods of this class will
+ * be non-direct. $A$ $type$ buffer created as a view of a byte buffer will
* be direct if, and only if, the byte buffer itself is direct. Whether or not
- * $a$ $fulltype$ buffer is direct may be determined by invoking the {@link
+ * $a$ $type$ buffer is direct may be determined by invoking the {@link
* #isDirect isDirect} method.
*
#end[!byte]
@@ -287,7 +287,7 @@ public abstract class $Type$Buffer
#if[byte]
/**
- * Allocates a new direct $fulltype$ buffer.
+ * Allocates a new direct $type$ buffer.
*
*
The new buffer's position will be zero, its limit will be its
* capacity, its mark will be undefined, and each of its elements will be
@@ -295,9 +295,9 @@ public abstract class $Type$Buffer
* {@link #hasArray
backing array} is unspecified.
*
* @param capacity
- * The new buffer's capacity, in $fulltype$s
+ * The new buffer's capacity, in $type$s
*
- * @return The new $fulltype$ buffer
+ * @return The new $type$ buffer
*
* @throws IllegalArgumentException
* If the capacity is a negative integer
@@ -309,7 +309,7 @@ public abstract class $Type$Buffer
#end[byte]
/**
- * Allocates a new $fulltype$ buffer.
+ * Allocates a new $type$ buffer.
*
*
The new buffer's position will be zero, its limit will be its
* capacity, its mark will be undefined, and each of its elements will be
@@ -318,9 +318,9 @@ public abstract class $Type$Buffer
* offset} will be zero.
*
* @param capacity
- * The new buffer's capacity, in $fulltype$s
+ * The new buffer's capacity, in $type$s
*
- * @return The new $fulltype$ buffer
+ * @return The new $type$ buffer
*
* @throws IllegalArgumentException
* If the capacity is a negative integer
@@ -332,9 +332,9 @@ public abstract class $Type$Buffer
}
/**
- * Wraps $a$ $fulltype$ array into a buffer.
+ * Wraps $a$ $type$ array into a buffer.
*
- *
The new buffer will be backed by the given $fulltype$ array;
+ *
The new buffer will be backed by the given $type$ array;
* that is, modifications to the buffer will cause the array to be modified
* and vice versa. The new buffer's capacity will be
* array.length, its position will be offset, its limit
@@ -356,7 +356,7 @@ public abstract class $Type$Buffer
* array.length - offset.
* The new buffer's limit will be set to offset + length.
*
- * @return The new $fulltype$ buffer
+ * @return The new $type$ buffer
*
* @throws IndexOutOfBoundsException
* If the preconditions on the offset and length
@@ -373,9 +373,9 @@ public abstract class $Type$Buffer
}
/**
- * Wraps $a$ $fulltype$ array into a buffer.
+ * Wraps $a$ $type$ array into a buffer.
*
- *
The new buffer will be backed by the given $fulltype$ array;
+ *
The new buffer will be backed by the given $type$ array;
* that is, modifications to the buffer will cause the array to be modified
* and vice versa. The new buffer's capacity and limit will be
* array.length, its position will be zero, and its mark will be
@@ -386,7 +386,7 @@ public abstract class $Type$Buffer
* @param array
* The array that will back this buffer
*
- * @return The new $fulltype$ buffer
+ * @return The new $type$ buffer
*/
public static $Type$Buffer wrap($type$[] array) {
return wrap(array, 0, array.length);
@@ -486,7 +486,7 @@ public abstract class $Type$Buffer
#end[char]
/**
- * Creates a new $fulltype$ buffer whose content is a shared subsequence of
+ * Creates a new $type$ buffer whose content is a shared subsequence of
* this buffer's content.
*
*
The content of the new buffer will start at this buffer's current
@@ -495,17 +495,17 @@ public abstract class $Type$Buffer
* values will be independent.
*
*
The new buffer's position will be zero, its capacity and its limit
- * will be the number of $fulltype$s remaining in this buffer, and its mark
+ * will be the number of $type$s remaining in this buffer, and its mark
* will be undefined. The new buffer will be direct if, and only if, this
* buffer is direct, and it will be read-only if, and only if, this buffer
* is read-only.
*
- * @return The new $fulltype$ buffer
+ * @return The new $type$ buffer
*/
public abstract $Type$Buffer slice();
/**
- * Creates a new $fulltype$ buffer that shares this buffer's content.
+ * Creates a new $type$ buffer that shares this buffer's content.
*
*
The content of the new buffer will be that of this buffer. Changes
* to this buffer's content will be visible in the new buffer, and vice
@@ -517,12 +517,12 @@ public abstract class $Type$Buffer
* and only if, this buffer is direct, and it will be read-only if, and
* only if, this buffer is read-only.
*
- * @return The new $fulltype$ buffer
+ * @return The new $type$ buffer
*/
public abstract $Type$Buffer duplicate();
/**
- * Creates a new, read-only $fulltype$ buffer that shares this buffer's
+ * Creates a new, read-only $type$ buffer that shares this buffer's
* content.
*
*
The content of the new buffer will be that of this buffer. Changes
@@ -537,7 +537,7 @@ public abstract class $Type$Buffer
*
If this buffer is itself read-only then this method behaves in
* exactly the same way as the {@link #duplicate duplicate} method.
*
- * @return The new, read-only $fulltype$ buffer
+ * @return The new, read-only $type$ buffer
*/
public abstract $Type$Buffer asReadOnlyBuffer();
@@ -545,10 +545,10 @@ public abstract class $Type$Buffer
// -- Singleton get/put methods --
/**
- * Relative get method. Reads the $fulltype$ at this buffer's
+ * Relative get method. Reads the $type$ at this buffer's
* current position, and then increments the position.
*
- * @return The $fulltype$ at the buffer's current position
+ * @return The $type$ at the buffer's current position
*
* @throws BufferUnderflowException
* If the buffer's current position is not smaller than its limit
@@ -558,11 +558,11 @@ public abstract class $Type$Buffer
/**
* Relative put method (optional operation).
*
- *
Writes the given $fulltype$ into this buffer at the current
+ *
Writes the given $type$ into this buffer at the current
* position, and then increments the position.
*
* @param $x$
- * The $fulltype$ to be written
+ * The $type$ to be written
*
* @return This buffer
*
@@ -575,13 +575,13 @@ public abstract class $Type$Buffer
public abstract $Type$Buffer put($type$ $x$);
/**
- * Absolute get method. Reads the $fulltype$ at the given
+ * Absolute get method. Reads the $type$ at the given
* index.
*
* @param index
- * The index from which the $fulltype$ will be read
+ * The index from which the $type$ will be read
*
- * @return The $fulltype$ at the given index
+ * @return The $type$ at the given index
*
* @throws IndexOutOfBoundsException
* If index is negative
@@ -592,14 +592,14 @@ public abstract class $Type$Buffer
/**
* Absolute put method (optional operation).
*
- *
Writes the given $fulltype$ into this buffer at the given
+ *
Writes the given $type$ into this buffer at the given
* index.
*
* @param index
- * The index at which the $fulltype$ will be written
+ * The index at which the $type$ will be written
*
* @param $x$
- * The $fulltype$ value to be written
+ * The $type$ value to be written
*
* @return This buffer
*
@@ -618,14 +618,14 @@ public abstract class $Type$Buffer
/**
* Relative bulk get method.
*
- *
This method transfers $fulltype$s from this buffer into the given
- * destination array. If there are fewer $fulltype$s remaining in the
+ *
This method transfers $type$s from this buffer into the given
+ * destination array. If there are fewer $type$s remaining in the
* buffer than are required to satisfy the request, that is, if
* length>remaining(), then no
- * $fulltype$s are transferred and a {@link BufferUnderflowException} is
+ * $type$s are transferred and a {@link BufferUnderflowException} is
* thrown.
*
- *
Otherwise, this method copies length $fulltype$s from this
+ *
Otherwise, this method copies length $type$s from this
* buffer into the given array, starting at the current position of this
* buffer and at the given offset in the array. The position of this
* buffer is then incremented by length.
@@ -638,26 +638,26 @@ public abstract class $Type$Buffer
* for (int i = off; i < off + len; i++)
* dst[i] = src.get();
*
- * except that it first checks that there are sufficient $fulltype$s in
+ * except that it first checks that there are sufficient $type$s in
* this buffer and it is potentially much more efficient.
*
* @param dst
- * The array into which $fulltype$s are to be written
+ * The array into which $type$s are to be written
*
* @param offset
- * The offset within the array of the first $fulltype$ to be
+ * The offset within the array of the first $type$ to be
* written; must be non-negative and no larger than
* dst.length
*
* @param length
- * The maximum number of $fulltype$s to be written to the given
+ * The maximum number of $type$s to be written to the given
* array; must be non-negative and no larger than
* dst.length - offset
*
* @return This buffer
*
* @throws BufferUnderflowException
- * If there are fewer than length $fulltype$s
+ * If there are fewer than length $type$s
* remaining in this buffer
*
* @throws IndexOutOfBoundsException
@@ -677,7 +677,7 @@ public abstract class $Type$Buffer
/**
* Relative bulk get method.
*
- *
This method transfers $fulltype$s from this buffer into the given
+ *
This method transfers $type$s from this buffer into the given
* destination array. An invocation of this method of the form
* src.get(a) behaves in exactly the same way as the invocation
*
@@ -687,7 +687,7 @@ public abstract class $Type$Buffer
* @return This buffer
*
* @throws BufferUnderflowException
- * If there are fewer than length $fulltype$s
+ * If there are fewer than length $type$s
* remaining in this buffer
*/
public $Type$Buffer get($type$[] dst) {
@@ -700,15 +700,15 @@ public abstract class $Type$Buffer
/**
* Relative bulk put method (optional operation).
*
- *
This method transfers the $fulltype$s remaining in the given source
- * buffer into this buffer. If there are more $fulltype$s remaining in the
+ *
This method transfers the $type$s remaining in the given source
+ * buffer into this buffer. If there are more $type$s remaining in the
* source buffer than in this buffer, that is, if
* src.remaining()>remaining(),
- * then no $fulltype$s are transferred and a {@link
+ * then no $type$s are transferred and a {@link
* BufferOverflowException} is thrown.
*
*
Otherwise, this method copies
- * n = src.remaining() $fulltype$s from the given
+ * n = src.remaining() $type$s from the given
* buffer into this buffer, starting at each buffer's current position.
* The positions of both buffers are then incremented by n.
*
@@ -723,14 +723,14 @@ public abstract class $Type$Buffer
* buffer and it is potentially much more efficient.
*
* @param src
- * The source buffer from which $fulltype$s are to be read;
+ * The source buffer from which $type$s are to be read;
* must not be this buffer
*
* @return This buffer
*
* @throws BufferOverflowException
* If there is insufficient space in this buffer
- * for the remaining $fulltype$s in the source buffer
+ * for the remaining $type$s in the source buffer
*
* @throws IllegalArgumentException
* If the source buffer is this buffer
@@ -752,14 +752,14 @@ public abstract class $Type$Buffer
/**
* Relative bulk put method (optional operation).
*
- *
This method transfers $fulltype$s into this buffer from the given
- * source array. If there are more $fulltype$s to be copied from the array
+ *
This method transfers $type$s into this buffer from the given
+ * source array. If there are more $type$s to be copied from the array
* than remain in this buffer, that is, if
* length>remaining(), then no
- * $fulltype$s are transferred and a {@link BufferOverflowException} is
+ * $type$s are transferred and a {@link BufferOverflowException} is
* thrown.
*
- *
Otherwise, this method copies length $fulltype$s from the
+ *
Otherwise, this method copies length $type$s from the
* given array into this buffer, starting at the given offset in the array
* and at the current position of this buffer. The position of this buffer
* is then incremented by length.
@@ -776,14 +776,14 @@ public abstract class $Type$Buffer
* buffer and it is potentially much more efficient.
*
* @param src
- * The array from which $fulltype$s are to be read
+ * The array from which $type$s are to be read
*
* @param offset
- * The offset within the array of the first $fulltype$ to be read;
+ * The offset within the array of the first $type$ to be read;
* must be non-negative and no larger than array.length
*
* @param length
- * The number of $fulltype$s to be read from the given array;
+ * The number of $type$s to be read from the given array;
* must be non-negative and no larger than
* array.length - offset
*
@@ -813,7 +813,7 @@ public abstract class $Type$Buffer
* Relative bulk put method (optional operation).
*
*
This method transfers the entire content of the given source
- * $fulltype$ array into this buffer. An invocation of this method of the
+ * $type$ array into this buffer. An invocation of this method of the
* form dst.put(a) behaves in exactly the same way as the
* invocation
*
@@ -837,15 +837,15 @@ public abstract class $Type$Buffer
/**
* Relative bulk put method (optional operation).
*
- *
This method transfers $fulltype$s from the given string into this
- * buffer. If there are more $fulltype$s to be copied from the string than
+ *
This method transfers $type$s from the given string into this
+ * buffer. If there are more $type$s to be copied from the string than
* remain in this buffer, that is, if
* end - start>remaining(),
- * then no $fulltype$s are transferred and a {@link
+ * then no $type$s are transferred and a {@link
* BufferOverflowException} is thrown.
*
*
Otherwise, this method copies
- * n = end - start $fulltype$s
+ * n = end - start $type$s
* from the given string into this buffer, starting at the given
* start index and at the current position of this buffer. The
* position of this buffer is then incremented by n.
@@ -862,15 +862,15 @@ public abstract class $Type$Buffer
* buffer and it is potentially much more efficient.
*
* @param src
- * The string from which $fulltype$s are to be read
+ * The string from which $type$s are to be read
*
* @param start
- * The offset within the string of the first $fulltype$ to be read;
+ * The offset within the string of the first $type$ to be read;
* must be non-negative and no larger than
* string.length()
*
* @param end
- * The offset within the string of the last $fulltype$ to be read,
+ * The offset within the string of the last $type$ to be read,
* plus one; must be non-negative and no larger than
* string.length()
*
@@ -921,7 +921,7 @@ public abstract class $Type$Buffer
// -- Other stuff --
/**
- * Tells whether or not this buffer is backed by an accessible $fulltype$
+ * Tells whether or not this buffer is backed by an accessible $type$
* array.
*
*
If this method returns true then the {@link #array() array}
@@ -936,7 +936,7 @@ public abstract class $Type$Buffer
}
/**
- * Returns the $fulltype$ array that backs this
+ * Returns the $type$ array that backs this
* buffer (optional operation).
*
*
Modifications to this buffer's content will cause the returned
@@ -993,17 +993,17 @@ public abstract class $Type$Buffer
/**
* Compacts this buffer (optional operation).
*
- *
The $fulltype$s between the buffer's current position and its limit,
+ *
The $type$s between the buffer's current position and its limit,
* if any, are copied to the beginning of the buffer. That is, the
- * $fulltype$ at index p = position() is copied
- * to index zero, the $fulltype$ at index p + 1 is copied
- * to index one, and so forth until the $fulltype$ at index
+ * $type$ at index p = position() is copied
+ * to index zero, the $type$ at index p + 1 is copied
+ * to index one, and so forth until the $type$ at index
* limit() - 1 is copied to index
* n = limit() - 1 - p.
* The buffer's position is then set to n+1 and its limit is set to
* its capacity. The mark, if defined, is discarded.
*
- *
The buffer's position is set to the number of $fulltype$s copied,
+ *
The buffer's position is set to the number of $type$s copied,
* rather than to zero, so that an invocation of this method can be
* followed immediately by an invocation of another relative put
* method.
@@ -1032,7 +1032,7 @@ public abstract class $Type$Buffer
public abstract $Type$Buffer compact();
/**
- * Tells whether or not this $fulltype$ buffer is direct.
+ * Tells whether or not this $type$ buffer is direct.
*
* @return true if, and only if, this buffer is direct
*/
@@ -1098,6 +1098,13 @@ public abstract class $Type$Buffer
*
*
The two sequences of remaining elements, considered
* independently of their starting positions, are pointwise equal.
+#if[floatingPointType]
+ * This method considers two $type$ elements {@code a} and {@code b}
+ * to be equal if
+ * {@code (a == b) || ($Fulltype$.isNaN(a) && $Fulltype$.isNaN(b))}.
+ * The values {@code -0.0} and {@code +0.0} are considered to be
+ * equal, unlike {@link $Fulltype$#equals(Object)}.
+#end[floatingPointType]
*
*
*
@@ -1118,24 +1125,37 @@ public abstract class $Type$Buffer
if (this.remaining() != that.remaining())
return false;
int p = this.position();
- for (int i = this.limit() - 1, j = that.limit() - 1; i >= p; i--, j--) {
- $type$ v1 = this.get(i);
- $type$ v2 = that.get(j);
- if (v1 != v2) {
- if ((v1 != v1) && (v2 != v2)) // For float and double
- continue;
+ for (int i = this.limit() - 1, j = that.limit() - 1; i >= p; i--, j--)
+ if (!equals(this.get(i), that.get(j)))
return false;
- }
- }
return true;
}
+ private static boolean equals($type$ x, $type$ y) {
+#if[floatingPointType]
+ return (x == y) || ($Fulltype$.isNaN(x) && $Fulltype$.isNaN(y));
+#else[floatingPointType]
+ return x == y;
+#end[floatingPointType]
+ }
+
/**
* Compares this buffer to another.
*
*
Two $type$ buffers are compared by comparing their sequences of
* remaining elements lexicographically, without regard to the starting
* position of each sequence within its corresponding buffer.
+#if[floatingPointType]
+ * Pairs of {@code $type$} elements are compared as if by invoking
+ * {@link $Fulltype$#compare($type$,$type$)}, except that
+ * {@code -0.0} and {@code 0.0} are considered to be equal.
+ * {@code $Fulltype$.NaN} is considered by this method to be equal
+ * to itself and greater than all other {@code $type$} values
+ * (including {@code $Fulltype$.POSITIVE_INFINITY}).
+#else[floatingPointType]
+ * Pairs of {@code $type$} elements are compared as if by invoking
+ * {@link $Fulltype$#compare($type$,$type$)}.
+#end[floatingPointType]
*
*
A $type$ buffer is not comparable to any other type of object.
*
@@ -1145,20 +1165,23 @@ public abstract class $Type$Buffer
public int compareTo($Type$Buffer that) {
int n = this.position() + Math.min(this.remaining(), that.remaining());
for (int i = this.position(), j = that.position(); i < n; i++, j++) {
- $type$ v1 = this.get(i);
- $type$ v2 = that.get(j);
- if (v1 == v2)
- continue;
- if ((v1 != v1) && (v2 != v2)) // For float and double
- continue;
- if (v1 < v2)
- return -1;
- return +1;
+ int cmp = compare(this.get(i), that.get(j));
+ if (cmp != 0)
+ return cmp;
}
return this.remaining() - that.remaining();
}
-
+ private static int compare($type$ x, $type$ y) {
+#if[floatingPointType]
+ return ((x < y) ? -1 :
+ (x > y) ? +1 :
+ (x == y) ? 0 :
+ $Fulltype$.isNaN(x) ? ($Fulltype$.isNaN(y) ? 0 : +1) : -1);
+#else[floatingPointType]
+ return $Fulltype$.compare(x, y);
+#end[floatingPointType]
+ }
// -- Other char stuff --
@@ -1326,7 +1349,7 @@ public abstract class $Type$Buffer
}
/**
- * Appends the specified $fulltype$ to this
+ * Appends the specified $type$ to this
* buffer (optional operation).
*
*
An invocation of this method of the form dst.append($x$)
@@ -1336,7 +1359,7 @@ public abstract class $Type$Buffer
* dst.put($x$)
*
* @param $x$
- * The 16-bit $fulltype$ to append
+ * The 16-bit $type$ to append
*
* @return This buffer
*
@@ -1362,10 +1385,10 @@ public abstract class $Type$Buffer
/**
* Retrieves this buffer's byte order.
*
- *
The byte order of $a$ $fulltype$ buffer created by allocation or by
+ *
The byte order of $a$ $type$ buffer created by allocation or by
* wrapping an existing $type$ array is the {@link
* ByteOrder#nativeOrder
native order} of the underlying
- * hardware. The byte order of $a$ $fulltype$ buffer created as a view of a byte buffer is that of the
* byte buffer at the moment that the view is created.
*
diff --git a/jdk/test/java/nio/Buffer/Basic-X.java.template b/jdk/test/java/nio/Buffer/Basic-X.java.template
index 6612771def4..93cbe8eb5ee 100644
--- a/jdk/test/java/nio/Buffer/Basic-X.java.template
+++ b/jdk/test/java/nio/Buffer/Basic-X.java.template
@@ -38,6 +38,26 @@ public class Basic$Type$
extends Basic
{
+ private static final $type$[] VALUES = {
+ $Fulltype$.MIN_VALUE,
+ ($type$) -1,
+ ($type$) 0,
+ ($type$) 1,
+ $Fulltype$.MAX_VALUE,
+#if[float]
+ $Fulltype$.NEGATIVE_INFINITY,
+ $Fulltype$.POSITIVE_INFINITY,
+ $Fulltype$.NaN,
+ ($type$) -0.0,
+#end[float]
+#if[double]
+ $Fulltype$.NEGATIVE_INFINITY,
+ $Fulltype$.POSITIVE_INFINITY,
+ $Fulltype$.NaN,
+ ($type$) -0.0,
+#end[double]
+ };
+
private static void relGet($Type$Buffer b) {
int n = b.capacity();
$type$ v;
@@ -309,6 +329,12 @@ public class Basic$Type$
#end[byte]
+ private static void fail(String problem,
+ $Type$Buffer xb, $Type$Buffer yb,
+ $type$ x, $type$ y) {
+ fail(problem + String.format(": x=%s y=%s", x, y), xb, yb);
+ }
+
private static void tryCatch(Buffer b, Class ex, Runnable thunk) {
boolean caught = false;
try {
@@ -522,6 +548,42 @@ public class Basic$Type$
if (b.compareTo(b2) <= 0)
fail("Comparison to lesser buffer <= 0", b, b2);
+ // Check equals and compareTo with interesting values
+ for ($type$ x : VALUES) {
+ $Type$Buffer xb = $Type$Buffer.wrap(new $type$[] { x });
+ if (xb.compareTo(xb) != 0) {
+ fail("compareTo not reflexive", xb, xb, x, x);
+ }
+ if (! xb.equals(xb)) {
+ fail("equals not reflexive", xb, xb, x, x);
+ }
+ for ($type$ y : VALUES) {
+ $Type$Buffer yb = $Type$Buffer.wrap(new $type$[] { y });
+ if (xb.compareTo(yb) != - yb.compareTo(xb)) {
+ fail("compareTo not anti-symmetric",
+ xb, yb, x, y);
+ }
+ if ((xb.compareTo(yb) == 0) != xb.equals(yb)) {
+ fail("compareTo inconsistent with equals",
+ xb, yb, x, y);
+ }
+ if (xb.compareTo(yb) != $Fulltype$.compare(x, y)) {
+#if[float]
+ if (x == 0.0 && y == 0.0) continue;
+#end[float]
+#if[double]
+ if (x == 0.0 && y == 0.0) continue;
+#end[double]
+ fail("Incorrect results for $Type$Buffer.compareTo",
+ xb, yb, x, y);
+ }
+ if (xb.equals(yb) != ((x == y) || ((x != x) && (y != y)))) {
+ fail("Incorrect results for $Type$Buffer.equals",
+ xb, yb, x, y);
+ }
+ }
+ }
+
// Sub, dup
relPut(b);
diff --git a/jdk/test/java/nio/Buffer/BasicByte.java b/jdk/test/java/nio/Buffer/BasicByte.java
index 7e259a1416d..78b209936d7 100644
--- a/jdk/test/java/nio/Buffer/BasicByte.java
+++ b/jdk/test/java/nio/Buffer/BasicByte.java
@@ -38,6 +38,26 @@ public class BasicByte
extends Basic
{
+ private static final byte[] VALUES = {
+ Byte.MIN_VALUE,
+ (byte) -1,
+ (byte) 0,
+ (byte) 1,
+ Byte.MAX_VALUE,
+
+
+
+
+
+
+
+
+
+
+
+
+ };
+
private static void relGet(ByteBuffer b) {
int n = b.capacity();
byte v;
@@ -309,6 +329,12 @@ public class BasicByte
+ private static void fail(String problem,
+ ByteBuffer xb, ByteBuffer yb,
+ byte x, byte y) {
+ fail(problem + String.format(": x=%s y=%s", x, y), xb, yb);
+ }
+
private static void tryCatch(Buffer b, Class ex, Runnable thunk) {
boolean caught = false;
try {
@@ -522,6 +548,42 @@ public class BasicByte
if (b.compareTo(b2) <= 0)
fail("Comparison to lesser buffer <= 0", b, b2);
+ // Check equals and compareTo with interesting values
+ for (byte x : VALUES) {
+ ByteBuffer xb = ByteBuffer.wrap(new byte[] { x });
+ if (xb.compareTo(xb) != 0) {
+ fail("compareTo not reflexive", xb, xb, x, x);
+ }
+ if (! xb.equals(xb)) {
+ fail("equals not reflexive", xb, xb, x, x);
+ }
+ for (byte y : VALUES) {
+ ByteBuffer yb = ByteBuffer.wrap(new byte[] { y });
+ if (xb.compareTo(yb) != - yb.compareTo(xb)) {
+ fail("compareTo not anti-symmetric",
+ xb, yb, x, y);
+ }
+ if ((xb.compareTo(yb) == 0) != xb.equals(yb)) {
+ fail("compareTo inconsistent with equals",
+ xb, yb, x, y);
+ }
+ if (xb.compareTo(yb) != Byte.compare(x, y)) {
+
+
+
+
+
+
+ fail("Incorrect results for ByteBuffer.compareTo",
+ xb, yb, x, y);
+ }
+ if (xb.equals(yb) != ((x == y) || ((x != x) && (y != y)))) {
+ fail("Incorrect results for ByteBuffer.equals",
+ xb, yb, x, y);
+ }
+ }
+ }
+
// Sub, dup
relPut(b);
diff --git a/jdk/test/java/nio/Buffer/BasicChar.java b/jdk/test/java/nio/Buffer/BasicChar.java
index a0df9fcf3a9..9f3c5e4219c 100644
--- a/jdk/test/java/nio/Buffer/BasicChar.java
+++ b/jdk/test/java/nio/Buffer/BasicChar.java
@@ -38,6 +38,26 @@ public class BasicChar
extends Basic
{
+ private static final char[] VALUES = {
+ Character.MIN_VALUE,
+ (char) -1,
+ (char) 0,
+ (char) 1,
+ Character.MAX_VALUE,
+
+
+
+
+
+
+
+
+
+
+
+
+ };
+
private static void relGet(CharBuffer b) {
int n = b.capacity();
char v;
@@ -308,6 +328,12 @@ public class BasicChar
+
+ private static void fail(String problem,
+ CharBuffer xb, CharBuffer yb,
+ char x, char y) {
+ fail(problem + String.format(": x=%s y=%s", x, y), xb, yb);
+ }
private static void tryCatch(Buffer b, Class ex, Runnable thunk) {
boolean caught = false;
@@ -522,6 +548,42 @@ public class BasicChar
if (b.compareTo(b2) <= 0)
fail("Comparison to lesser buffer <= 0", b, b2);
+ // Check equals and compareTo with interesting values
+ for (char x : VALUES) {
+ CharBuffer xb = CharBuffer.wrap(new char[] { x });
+ if (xb.compareTo(xb) != 0) {
+ fail("compareTo not reflexive", xb, xb, x, x);
+ }
+ if (! xb.equals(xb)) {
+ fail("equals not reflexive", xb, xb, x, x);
+ }
+ for (char y : VALUES) {
+ CharBuffer yb = CharBuffer.wrap(new char[] { y });
+ if (xb.compareTo(yb) != - yb.compareTo(xb)) {
+ fail("compareTo not anti-symmetric",
+ xb, yb, x, y);
+ }
+ if ((xb.compareTo(yb) == 0) != xb.equals(yb)) {
+ fail("compareTo inconsistent with equals",
+ xb, yb, x, y);
+ }
+ if (xb.compareTo(yb) != Character.compare(x, y)) {
+
+
+
+
+
+
+ fail("Incorrect results for CharBuffer.compareTo",
+ xb, yb, x, y);
+ }
+ if (xb.equals(yb) != ((x == y) || ((x != x) && (y != y)))) {
+ fail("Incorrect results for CharBuffer.equals",
+ xb, yb, x, y);
+ }
+ }
+ }
+
// Sub, dup
relPut(b);
diff --git a/jdk/test/java/nio/Buffer/BasicDouble.java b/jdk/test/java/nio/Buffer/BasicDouble.java
index a627d0e9194..97f5fa200de 100644
--- a/jdk/test/java/nio/Buffer/BasicDouble.java
+++ b/jdk/test/java/nio/Buffer/BasicDouble.java
@@ -38,6 +38,26 @@ public class BasicDouble
extends Basic
{
+ private static final double[] VALUES = {
+ Double.MIN_VALUE,
+ (double) -1,
+ (double) 0,
+ (double) 1,
+ Double.MAX_VALUE,
+
+
+
+
+
+
+
+ Double.NEGATIVE_INFINITY,
+ Double.POSITIVE_INFINITY,
+ Double.NaN,
+ (double) -0.0,
+
+ };
+
private static void relGet(DoubleBuffer b) {
int n = b.capacity();
double v;
@@ -308,6 +328,12 @@ public class BasicDouble
+
+ private static void fail(String problem,
+ DoubleBuffer xb, DoubleBuffer yb,
+ double x, double y) {
+ fail(problem + String.format(": x=%s y=%s", x, y), xb, yb);
+ }
private static void tryCatch(Buffer b, Class ex, Runnable thunk) {
boolean caught = false;
@@ -522,6 +548,42 @@ public class BasicDouble
if (b.compareTo(b2) <= 0)
fail("Comparison to lesser buffer <= 0", b, b2);
+ // Check equals and compareTo with interesting values
+ for (double x : VALUES) {
+ DoubleBuffer xb = DoubleBuffer.wrap(new double[] { x });
+ if (xb.compareTo(xb) != 0) {
+ fail("compareTo not reflexive", xb, xb, x, x);
+ }
+ if (! xb.equals(xb)) {
+ fail("equals not reflexive", xb, xb, x, x);
+ }
+ for (double y : VALUES) {
+ DoubleBuffer yb = DoubleBuffer.wrap(new double[] { y });
+ if (xb.compareTo(yb) != - yb.compareTo(xb)) {
+ fail("compareTo not anti-symmetric",
+ xb, yb, x, y);
+ }
+ if ((xb.compareTo(yb) == 0) != xb.equals(yb)) {
+ fail("compareTo inconsistent with equals",
+ xb, yb, x, y);
+ }
+ if (xb.compareTo(yb) != Double.compare(x, y)) {
+
+
+
+
+ if (x == 0.0 && y == 0.0) continue;
+
+ fail("Incorrect results for DoubleBuffer.compareTo",
+ xb, yb, x, y);
+ }
+ if (xb.equals(yb) != ((x == y) || ((x != x) && (y != y)))) {
+ fail("Incorrect results for DoubleBuffer.equals",
+ xb, yb, x, y);
+ }
+ }
+ }
+
// Sub, dup
relPut(b);
diff --git a/jdk/test/java/nio/Buffer/BasicFloat.java b/jdk/test/java/nio/Buffer/BasicFloat.java
index 730dcbeac95..46bdfe163cb 100644
--- a/jdk/test/java/nio/Buffer/BasicFloat.java
+++ b/jdk/test/java/nio/Buffer/BasicFloat.java
@@ -38,6 +38,26 @@ public class BasicFloat
extends Basic
{
+ private static final float[] VALUES = {
+ Float.MIN_VALUE,
+ (float) -1,
+ (float) 0,
+ (float) 1,
+ Float.MAX_VALUE,
+
+ Float.NEGATIVE_INFINITY,
+ Float.POSITIVE_INFINITY,
+ Float.NaN,
+ (float) -0.0,
+
+
+
+
+
+
+
+ };
+
private static void relGet(FloatBuffer b) {
int n = b.capacity();
float v;
@@ -308,6 +328,12 @@ public class BasicFloat
+
+ private static void fail(String problem,
+ FloatBuffer xb, FloatBuffer yb,
+ float x, float y) {
+ fail(problem + String.format(": x=%s y=%s", x, y), xb, yb);
+ }
private static void tryCatch(Buffer b, Class ex, Runnable thunk) {
boolean caught = false;
@@ -522,6 +548,42 @@ public class BasicFloat
if (b.compareTo(b2) <= 0)
fail("Comparison to lesser buffer <= 0", b, b2);
+ // Check equals and compareTo with interesting values
+ for (float x : VALUES) {
+ FloatBuffer xb = FloatBuffer.wrap(new float[] { x });
+ if (xb.compareTo(xb) != 0) {
+ fail("compareTo not reflexive", xb, xb, x, x);
+ }
+ if (! xb.equals(xb)) {
+ fail("equals not reflexive", xb, xb, x, x);
+ }
+ for (float y : VALUES) {
+ FloatBuffer yb = FloatBuffer.wrap(new float[] { y });
+ if (xb.compareTo(yb) != - yb.compareTo(xb)) {
+ fail("compareTo not anti-symmetric",
+ xb, yb, x, y);
+ }
+ if ((xb.compareTo(yb) == 0) != xb.equals(yb)) {
+ fail("compareTo inconsistent with equals",
+ xb, yb, x, y);
+ }
+ if (xb.compareTo(yb) != Float.compare(x, y)) {
+
+ if (x == 0.0 && y == 0.0) continue;
+
+
+
+
+ fail("Incorrect results for FloatBuffer.compareTo",
+ xb, yb, x, y);
+ }
+ if (xb.equals(yb) != ((x == y) || ((x != x) && (y != y)))) {
+ fail("Incorrect results for FloatBuffer.equals",
+ xb, yb, x, y);
+ }
+ }
+ }
+
// Sub, dup
relPut(b);
diff --git a/jdk/test/java/nio/Buffer/BasicInt.java b/jdk/test/java/nio/Buffer/BasicInt.java
index b20e4bb1056..478debd76e1 100644
--- a/jdk/test/java/nio/Buffer/BasicInt.java
+++ b/jdk/test/java/nio/Buffer/BasicInt.java
@@ -38,6 +38,26 @@ public class BasicInt
extends Basic
{
+ private static final int[] VALUES = {
+ Integer.MIN_VALUE,
+ (int) -1,
+ (int) 0,
+ (int) 1,
+ Integer.MAX_VALUE,
+
+
+
+
+
+
+
+
+
+
+
+
+ };
+
private static void relGet(IntBuffer b) {
int n = b.capacity();
int v;
@@ -308,6 +328,12 @@ public class BasicInt
+
+ private static void fail(String problem,
+ IntBuffer xb, IntBuffer yb,
+ int x, int y) {
+ fail(problem + String.format(": x=%s y=%s", x, y), xb, yb);
+ }
private static void tryCatch(Buffer b, Class ex, Runnable thunk) {
boolean caught = false;
@@ -522,6 +548,42 @@ public class BasicInt
if (b.compareTo(b2) <= 0)
fail("Comparison to lesser buffer <= 0", b, b2);
+ // Check equals and compareTo with interesting values
+ for (int x : VALUES) {
+ IntBuffer xb = IntBuffer.wrap(new int[] { x });
+ if (xb.compareTo(xb) != 0) {
+ fail("compareTo not reflexive", xb, xb, x, x);
+ }
+ if (! xb.equals(xb)) {
+ fail("equals not reflexive", xb, xb, x, x);
+ }
+ for (int y : VALUES) {
+ IntBuffer yb = IntBuffer.wrap(new int[] { y });
+ if (xb.compareTo(yb) != - yb.compareTo(xb)) {
+ fail("compareTo not anti-symmetric",
+ xb, yb, x, y);
+ }
+ if ((xb.compareTo(yb) == 0) != xb.equals(yb)) {
+ fail("compareTo inconsistent with equals",
+ xb, yb, x, y);
+ }
+ if (xb.compareTo(yb) != Integer.compare(x, y)) {
+
+
+
+
+
+
+ fail("Incorrect results for IntBuffer.compareTo",
+ xb, yb, x, y);
+ }
+ if (xb.equals(yb) != ((x == y) || ((x != x) && (y != y)))) {
+ fail("Incorrect results for IntBuffer.equals",
+ xb, yb, x, y);
+ }
+ }
+ }
+
// Sub, dup
relPut(b);
diff --git a/jdk/test/java/nio/Buffer/BasicLong.java b/jdk/test/java/nio/Buffer/BasicLong.java
index 0d4c568e1e3..0abc7cdf2f4 100644
--- a/jdk/test/java/nio/Buffer/BasicLong.java
+++ b/jdk/test/java/nio/Buffer/BasicLong.java
@@ -38,6 +38,26 @@ public class BasicLong
extends Basic
{
+ private static final long[] VALUES = {
+ Long.MIN_VALUE,
+ (long) -1,
+ (long) 0,
+ (long) 1,
+ Long.MAX_VALUE,
+
+
+
+
+
+
+
+
+
+
+
+
+ };
+
private static void relGet(LongBuffer b) {
int n = b.capacity();
long v;
@@ -308,6 +328,12 @@ public class BasicLong
+
+ private static void fail(String problem,
+ LongBuffer xb, LongBuffer yb,
+ long x, long y) {
+ fail(problem + String.format(": x=%s y=%s", x, y), xb, yb);
+ }
private static void tryCatch(Buffer b, Class ex, Runnable thunk) {
boolean caught = false;
@@ -522,6 +548,42 @@ public class BasicLong
if (b.compareTo(b2) <= 0)
fail("Comparison to lesser buffer <= 0", b, b2);
+ // Check equals and compareTo with interesting values
+ for (long x : VALUES) {
+ LongBuffer xb = LongBuffer.wrap(new long[] { x });
+ if (xb.compareTo(xb) != 0) {
+ fail("compareTo not reflexive", xb, xb, x, x);
+ }
+ if (! xb.equals(xb)) {
+ fail("equals not reflexive", xb, xb, x, x);
+ }
+ for (long y : VALUES) {
+ LongBuffer yb = LongBuffer.wrap(new long[] { y });
+ if (xb.compareTo(yb) != - yb.compareTo(xb)) {
+ fail("compareTo not anti-symmetric",
+ xb, yb, x, y);
+ }
+ if ((xb.compareTo(yb) == 0) != xb.equals(yb)) {
+ fail("compareTo inconsistent with equals",
+ xb, yb, x, y);
+ }
+ if (xb.compareTo(yb) != Long.compare(x, y)) {
+
+
+
+
+
+
+ fail("Incorrect results for LongBuffer.compareTo",
+ xb, yb, x, y);
+ }
+ if (xb.equals(yb) != ((x == y) || ((x != x) && (y != y)))) {
+ fail("Incorrect results for LongBuffer.equals",
+ xb, yb, x, y);
+ }
+ }
+ }
+
// Sub, dup
relPut(b);
diff --git a/jdk/test/java/nio/Buffer/BasicShort.java b/jdk/test/java/nio/Buffer/BasicShort.java
index 58e5a3e6d68..861d356b6df 100644
--- a/jdk/test/java/nio/Buffer/BasicShort.java
+++ b/jdk/test/java/nio/Buffer/BasicShort.java
@@ -38,6 +38,26 @@ public class BasicShort
extends Basic
{
+ private static final short[] VALUES = {
+ Short.MIN_VALUE,
+ (short) -1,
+ (short) 0,
+ (short) 1,
+ Short.MAX_VALUE,
+
+
+
+
+
+
+
+
+
+
+
+
+ };
+
private static void relGet(ShortBuffer b) {
int n = b.capacity();
short v;
@@ -308,6 +328,12 @@ public class BasicShort
+
+ private static void fail(String problem,
+ ShortBuffer xb, ShortBuffer yb,
+ short x, short y) {
+ fail(problem + String.format(": x=%s y=%s", x, y), xb, yb);
+ }
private static void tryCatch(Buffer b, Class ex, Runnable thunk) {
boolean caught = false;
@@ -522,6 +548,42 @@ public class BasicShort
if (b.compareTo(b2) <= 0)
fail("Comparison to lesser buffer <= 0", b, b2);
+ // Check equals and compareTo with interesting values
+ for (short x : VALUES) {
+ ShortBuffer xb = ShortBuffer.wrap(new short[] { x });
+ if (xb.compareTo(xb) != 0) {
+ fail("compareTo not reflexive", xb, xb, x, x);
+ }
+ if (! xb.equals(xb)) {
+ fail("equals not reflexive", xb, xb, x, x);
+ }
+ for (short y : VALUES) {
+ ShortBuffer yb = ShortBuffer.wrap(new short[] { y });
+ if (xb.compareTo(yb) != - yb.compareTo(xb)) {
+ fail("compareTo not anti-symmetric",
+ xb, yb, x, y);
+ }
+ if ((xb.compareTo(yb) == 0) != xb.equals(yb)) {
+ fail("compareTo inconsistent with equals",
+ xb, yb, x, y);
+ }
+ if (xb.compareTo(yb) != Short.compare(x, y)) {
+
+
+
+
+
+
+ fail("Incorrect results for ShortBuffer.compareTo",
+ xb, yb, x, y);
+ }
+ if (xb.equals(yb) != ((x == y) || ((x != x) && (y != y)))) {
+ fail("Incorrect results for ShortBuffer.equals",
+ xb, yb, x, y);
+ }
+ }
+ }
+
// Sub, dup
relPut(b);
diff --git a/jdk/test/java/nio/Buffer/genBasic.sh b/jdk/test/java/nio/Buffer/genBasic.sh
index da5fca5df33..009cf2dbb1b 100644
--- a/jdk/test/java/nio/Buffer/genBasic.sh
+++ b/jdk/test/java/nio/Buffer/genBasic.sh
@@ -36,5 +36,3 @@ gen int Int Integer
gen long Long Long
gen float Float Float
gen double Double Double
-
-rm -rf build
From d090b4fe29044f548d8716223c71b08f11160bf1 Mon Sep 17 00:00:00 2001
From: "Y. Srinivas Ramakrishna"
Date: Tue, 8 Dec 2009 15:12:17 -0800
Subject: [PATCH 049/221] 6908208: UseCompressedOops: array_size() returns
incorrect size for MAX_INT object array following 6906727
In array_size() cast to an unsigned to avoid overflow of intermediate value.
Reviewed-by: kvn, tonyp, jmasa, jcoomes, coleenp
---
hotspot/src/share/vm/oops/objArrayOop.hpp | 8 ++++++--
1 file changed, 6 insertions(+), 2 deletions(-)
diff --git a/hotspot/src/share/vm/oops/objArrayOop.hpp b/hotspot/src/share/vm/oops/objArrayOop.hpp
index a00eb7c1a9b..1c1764a8751 100644
--- a/hotspot/src/share/vm/oops/objArrayOop.hpp
+++ b/hotspot/src/share/vm/oops/objArrayOop.hpp
@@ -58,7 +58,7 @@ private:
old_res = align_size_up(length, OopsPerHeapWord)/OopsPerHeapWord;
}
#endif // ASSERT
- int res = (length + OopsPerHeapWord - 1)/OopsPerHeapWord;
+ int res = ((uint)length + OopsPerHeapWord - 1)/OopsPerHeapWord;
assert(res == old_res, "Inconsistency between old and new.");
return res;
}
@@ -96,7 +96,11 @@ private:
static int object_size(int length) {
// This returns the object size in HeapWords.
- return align_object_size(header_size() + array_size(length));
+ uint asz = array_size(length);
+ uint osz = align_object_size(header_size() + asz);
+ assert(osz >= asz, "no overflow");
+ assert((int)osz > 0, "no overflow");
+ return (int)osz;
}
// special iterators for index ranges, returns size of object
From dfbb0bf3e28873ee5e15fa9d577de4b9ab96ab49 Mon Sep 17 00:00:00 2001
From: Tom Rodriguez
Date: Tue, 8 Dec 2009 16:27:21 -0800
Subject: [PATCH 050/221] 6908167: jbb2005, OptimizeStringConcat causes assert
in EA
Reviewed-by: kvn
---
hotspot/src/share/vm/opto/graphKit.cpp | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/hotspot/src/share/vm/opto/graphKit.cpp b/hotspot/src/share/vm/opto/graphKit.cpp
index 1b5eb54422f..3a42be98b60 100644
--- a/hotspot/src/share/vm/opto/graphKit.cpp
+++ b/hotspot/src/share/vm/opto/graphKit.cpp
@@ -1714,6 +1714,11 @@ void GraphKit::replace_call(CallNode* call, Node* result) {
C->gvn_replace_by(callprojs.catchall_catchproj, C->top());
C->gvn_replace_by(callprojs.catchall_memproj, C->top());
C->gvn_replace_by(callprojs.catchall_ioproj, C->top());
+
+ // Replace the old exception object with top
+ if (callprojs.exobj != NULL) {
+ C->gvn_replace_by(callprojs.exobj, C->top());
+ }
} else {
GraphKit ekit(ejvms);
From 8e1f9a0dd399f0fc81ea1b61eadb2097909206a5 Mon Sep 17 00:00:00 2001
From: Weijun Wang
Date: Wed, 9 Dec 2009 11:15:25 +0800
Subject: [PATCH 051/221] 6908628: ObjectIdentifier s11n test fails
Reviewed-by: xuelei
---
jdk/test/sun/security/util/Oid/S11N.sh | 15 +++++++++++----
1 file changed, 11 insertions(+), 4 deletions(-)
diff --git a/jdk/test/sun/security/util/Oid/S11N.sh b/jdk/test/sun/security/util/Oid/S11N.sh
index 081cd52298f..82046f360c0 100644
--- a/jdk/test/sun/security/util/Oid/S11N.sh
+++ b/jdk/test/sun/security/util/Oid/S11N.sh
@@ -1,5 +1,5 @@
#
-# Copyright 2004-2005 Sun Microsystems, Inc. All Rights Reserved.
+# Copyright 2004-2009 Sun Microsystems, 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
@@ -21,8 +21,8 @@
# have any questions.
#
# @test
-# @bug 4811968
-# @summary Serialization compatibility with old versions
+# @bug 4811968 6908628
+# @summary Serialization compatibility with old versions (and fix)
# @author Weijun Wang
#
# set a few environment variables so that the shell-script can run stand-alone
@@ -99,7 +99,8 @@ esac
# the test code
-${TESTJAVA}${FS}bin${FS}javac -d . ${TESTSRC}${FS}SerialTest.java || exit 10
+${TESTJAVA}${FS}bin${FS}javac -target 1.4 -source 1.4 \
+ -d . ${TESTSRC}${FS}SerialTest.java || exit 10
OLDJAVA="
/java/re/j2se/1.6.0/latest/binaries/${PF}
@@ -161,4 +162,10 @@ rm -f tmp.oid.serial
rm -f tmp.oid.serial.old
rm -f SerialTest.class
+for oldj in ${OLDJAVA}; do
+ if [ ! -d ${oldj} ]; then
+ echo WARNING: ${oldj} is missing. Test incomplete! > /dev/stderr
+ fi
+done
+
exit 0
From d87dfc7a2eb769aa82007e156bc64b9379522542 Mon Sep 17 00:00:00 2001
From: Yong Jeffrey Huang
Date: Tue, 8 Dec 2009 21:14:04 -0800
Subject: [PATCH 052/221] 6610748: Dateformat - AM-PM indicator in Finnish
appears to be from English
Reviewed-by: yhuang, peytoia
---
.../sun/text/resources/FormatData_fi.java | 6 +++++
jdk/test/sun/text/resources/LocaleData | 23 +++++++++++++++++++
.../sun/text/resources/LocaleDataTest.java | 11 ++++++++-
3 files changed, 39 insertions(+), 1 deletion(-)
diff --git a/jdk/src/share/classes/sun/text/resources/FormatData_fi.java b/jdk/src/share/classes/sun/text/resources/FormatData_fi.java
index 73956ee588c..bad7e14bbb0 100644
--- a/jdk/src/share/classes/sun/text/resources/FormatData_fi.java
+++ b/jdk/src/share/classes/sun/text/resources/FormatData_fi.java
@@ -133,6 +133,12 @@ public class FormatData_fi extends ListResourceBundle {
}
},
{ "DateTimePatternChars", "GanjkHmsSEDFwWxhKzZ" },
+ { "AmPmMarkers",
+ new String[] {
+ "ap.", // am marker
+ "ip." // pm marker
+ }
+ },
};
}
}
diff --git a/jdk/test/sun/text/resources/LocaleData b/jdk/test/sun/text/resources/LocaleData
index 7425cf9f4ed..0a6cde5918a 100644
--- a/jdk/test/sun/text/resources/LocaleData
+++ b/jdk/test/sun/text/resources/LocaleData
@@ -5526,3 +5526,26 @@ LocaleNames//IM=Isle Of Man
# BL, MF (6627549)
LocaleNames//BL=Saint Barth\u00e9lemy
LocaleNames//MF=Saint Martin
+
+# bug 6609737
+FormatData/de/DateTimePatterns/0=HH:mm' Uhr 'z
+TimeZoneNames/de/CET/1=Mitteleurop\u00e4ische Zeit
+TimeZoneNames/de/CET/2=MEZ
+TimeZoneNames/de/CET/3=Mitteleurop\u00e4ische Sommerzeit
+TimeZoneNames/de/CET/4=MESZ
+TimeZoneNames/de/EET/2=OEZ
+TimeZoneNames/de/EET/4=OESZ
+TimeZoneNames/de/WET/2=WEZ
+TimeZoneNames/de/WET/4=WESZ
+
+# bug 6610748
+FormatData/fi/AmPmMarkers/0=ap.
+FormatData/fi/AmPmMarkers/1=ip.
+
+# bug 6507067
+TimeZoneNames/zh_TW/Asia\/Taipei/1=\u53f0\u7063\u6a19\u6e96\u6642\u9593
+TimeZoneNames/zh_TW/Asia\/Taipei/2=TST
+
+# bug 6645271
+FormatData/hr_HR/DateTimePatterns/6=dd.MM.yyyy.
+FormatData/hr_HR/DateTimePatterns/7=dd.MM.yy.
diff --git a/jdk/test/sun/text/resources/LocaleDataTest.java b/jdk/test/sun/text/resources/LocaleDataTest.java
index ff36327ea77..ce57c76bd69 100644
--- a/jdk/test/sun/text/resources/LocaleDataTest.java
+++ b/jdk/test/sun/text/resources/LocaleDataTest.java
@@ -31,7 +31,7 @@
* 5102005 5074431 6182685 6208712 6277020 6245766 6351682 6386647 6379382
* 6414459 6455680 6498742 6558863 6488119 6547501 6497154 6558856 6481177
* 6379214 6485516 6486607 4225362 4494727 6533691 6531591 6531593 6570259
- * 6509039
+ * 6509039 6609737 6610748 6645271 6507067
* @summary Verify locale data
*
*/
@@ -255,6 +255,15 @@ public class LocaleDataTest
index = key.length();
resTag = key.substring(oldIndex, index);
+ // TimeZone name may have "/" in it, for example "Asia/Taipei", so use "Asia\/Taipei in LocaleData.
+ if(resTag.endsWith("\\")) {
+ resTag = resTag.substring(0, resTag.length() - 1);
+ oldIndex = index;
+ index = key.indexOf("/", oldIndex + 1);
+ if (index == -1) index = key.length();
+ resTag += key.substring(oldIndex, index);
+ }
+
if (index < key.length() - 1)
qualifier = key.substring(index + 1);
else
From c2b0820237e5ff9cad4feae40c654e5c32c24172 Mon Sep 17 00:00:00 2001
From: Yong Jeffrey Huang
Date: Tue, 8 Dec 2009 21:19:23 -0800
Subject: [PATCH 053/221] 6645271: Wrong date format for Croatian (hr) locale
Reviewed-by: yhuang, peytoia
---
.../sun/text/resources/FormatData_hr_HR.java | 13 +++++++++++++
1 file changed, 13 insertions(+)
diff --git a/jdk/src/share/classes/sun/text/resources/FormatData_hr_HR.java b/jdk/src/share/classes/sun/text/resources/FormatData_hr_HR.java
index b6d39d332fa..0498f93a006 100644
--- a/jdk/src/share/classes/sun/text/resources/FormatData_hr_HR.java
+++ b/jdk/src/share/classes/sun/text/resources/FormatData_hr_HR.java
@@ -55,6 +55,19 @@ public class FormatData_hr_HR extends ListResourceBundle {
"#,##0%" // percent pattern
}
},
+ { "DateTimePatterns",
+ new String[] {
+ "HH:mm:ss z", // full time pattern
+ "HH:mm:ss z", // long time pattern
+ "HH:mm:ss", // medium time pattern
+ "HH:mm", // short time pattern
+ "yyyy. MMMM dd", // full date pattern
+ "yyyy. MMMM dd", // long date pattern
+ "dd.MM.yyyy.", // medium date pattern
+ "dd.MM.yy.", // short date pattern
+ "{1} {0}" // date-time pattern
+ }
+ }
};
}
}
From 245eebd3c71703c91931bcd819cb9b64813e927d Mon Sep 17 00:00:00 2001
From: Yong Jeffrey Huang
Date: Tue, 8 Dec 2009 21:26:59 -0800
Subject: [PATCH 054/221] 6609737: DateFormat incorrect for German locale
Reviewed-by: yhuang, peytoia
---
.../classes/sun/text/resources/FormatData_de.java | 2 +-
.../classes/sun/util/resources/TimeZoneNames_de.java | 12 ++++++------
2 files changed, 7 insertions(+), 7 deletions(-)
diff --git a/jdk/src/share/classes/sun/text/resources/FormatData_de.java b/jdk/src/share/classes/sun/text/resources/FormatData_de.java
index 028c17344fe..745216aedad 100644
--- a/jdk/src/share/classes/sun/text/resources/FormatData_de.java
+++ b/jdk/src/share/classes/sun/text/resources/FormatData_de.java
@@ -130,7 +130,7 @@ public class FormatData_de extends ListResourceBundle {
},
{ "DateTimePatterns",
new String[] {
- "H.mm' Uhr 'z", // full time pattern
+ "HH:mm' Uhr 'z", // full time pattern
"HH:mm:ss z", // long time pattern
"HH:mm:ss", // medium time pattern
"HH:mm", // short time pattern
diff --git a/jdk/src/share/classes/sun/util/resources/TimeZoneNames_de.java b/jdk/src/share/classes/sun/util/resources/TimeZoneNames_de.java
index 896d72a5c53..1eae6abe55d 100644
--- a/jdk/src/share/classes/sun/util/resources/TimeZoneNames_de.java
+++ b/jdk/src/share/classes/sun/util/resources/TimeZoneNames_de.java
@@ -71,8 +71,8 @@ public final class TimeZoneNames_de extends TimeZoneNamesBundle {
"Bhutanische Sommerzeit", "BTST"};
String CAT[] = new String[] {"Zentralafrikanische Zeit", "CAT",
"Zentralafrikanische Sommerzeit", "CAST"};
- String CET[] = new String[] {"Zentraleurop\u00e4ische Zeit", "CET",
- "Zentraleurop\u00e4ische Sommerzeit", "CEST"};
+ String CET[] = new String[] {"Mitteleurop\u00e4ische Zeit", "MEZ",
+ "Mitteleurop\u00e4ische Sommerzeit", "MESZ"};
String CHAST[] = new String[] {"Chatham Normalzeit", "CHAST",
"Chatham Sommerzeit", "CHADT"};
String CIT[] = new String[] {"Zentralindonesische Zeit", "CIT",
@@ -93,8 +93,8 @@ public final class TimeZoneNames_de extends TimeZoneNamesBundle {
"Ostafrikanische Sommerzeit", "EAST"};
String EASTER[] = new String[] {"Osterinseln Zeit", "EAST",
"Osterinseln Sommerzeit", "EASST"};
- String EET[] = new String[] {"Osteurop\u00e4ische Zeit", "EET",
- "Osteurop\u00e4ische Sommerzeit", "EEST"};
+ String EET[] = new String[] {"Osteurop\u00e4ische Zeit", "OEZ",
+ "Osteurop\u00e4ische Sommerzeit", "OESZ"};
String EGT[] = new String[] {"Ostgr\u00f6nl\u00e4ndische Zeit", "EGT",
"Ostgr\u00f6nl\u00e4ndische Sommerzeit", "EGST"};
String EST[] = new String[] {"\u00d6stliche Normalzeit", "EST",
@@ -177,8 +177,8 @@ public final class TimeZoneNames_de extends TimeZoneNamesBundle {
"Argentinische Sommerzeit", "WARST"};
String WAT[] = new String[] {"Westafrikanische Zeit", "WAT",
"Westafrikanische Sommerzeit", "WAST"};
- String WET[] = new String[] {"Westeurop\u00e4ische Zeit", "WET",
- "Westeurop\u00e4ische Sommerzeit", "WEST"};
+ String WET[] = new String[] {"Westeurop\u00e4ische Zeit", "WEZ",
+ "Westeurop\u00e4ische Sommerzeit", "WESZ"};
String WIT[] = new String[] {"Westindonesische Zeit", "WIT",
"Westindonesische Sommerzeit", "WIST"};
String WST_AUS[] = new String[] {"Westliche Normalzeit (Australien)", "WST",
From bb806220910fab699bcc6e461b4640ab3aae673e Mon Sep 17 00:00:00 2001
From: Yong Jeffrey Huang
Date: Tue, 8 Dec 2009 21:30:37 -0800
Subject: [PATCH 055/221] 6507067: TimeZone country/area message error
Reviewed-by: peytoia
---
.../share/classes/sun/util/resources/TimeZoneNames_zh_TW.java | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/jdk/src/share/classes/sun/util/resources/TimeZoneNames_zh_TW.java b/jdk/src/share/classes/sun/util/resources/TimeZoneNames_zh_TW.java
index f5b89286ed0..ba0dc42b46e 100644
--- a/jdk/src/share/classes/sun/util/resources/TimeZoneNames_zh_TW.java
+++ b/jdk/src/share/classes/sun/util/resources/TimeZoneNames_zh_TW.java
@@ -551,7 +551,8 @@ public final class TimeZoneNames_zh_TW extends TimeZoneNamesBundle {
{"Asia/Samarkand", UZT},
{"Asia/Seoul", KST},
{"Asia/Singapore", SGT},
- {"Asia/Taipei", CTT},
+ {"Asia/Taipei", new String[] {"\u53f0\u7063\u6a19\u6e96\u6642\u9593", "TST",
+ "\u53f0\u7063\u590f\u4ee4\u6642\u9593", "TDT"}},
{"Asia/Tel_Aviv", ISRAEL},
{"Asia/Tashkent", UZT},
{"Asia/Tbilisi", new String[] {"\u55ac\u6cbb\u4e9e\u6642\u9593", "GET",
From 61c09153f3ae8b5b1ed7933e42d0cf3e106469dc Mon Sep 17 00:00:00 2001
From: Kelly O'Hair
Date: Wed, 9 Dec 2009 09:46:57 -0800
Subject: [PATCH 056/221] 6906210: Fix another minor typo in test/Makefile
Reviewed-by: tbell, dcubed
---
jdk/test/Makefile | 35 +++++++--
jdk/test/ProblemList.txt | 82 ++++++++++++++++++++
jdk/test/com/sun/jdi/NoLaunchOptionTest.java | 12 ++-
jdk/test/com/sun/jdi/OptionTest.java | 11 ++-
jdk/test/sun/tools/jhat/HatRun.java | 6 +-
5 files changed, 134 insertions(+), 12 deletions(-)
diff --git a/jdk/test/Makefile b/jdk/test/Makefile
index 25f0dc1ed6f..c3e0ad3a62c 100644
--- a/jdk/test/Makefile
+++ b/jdk/test/Makefile
@@ -291,7 +291,7 @@ TESTEXIT = \
fi ; \
testExitCode=`$(CAT) $(EXITCODE)`; \
$(ECHO) "EXIT CODE: $${testExitCode}"; \
- exit ${testExitCode}
+ exit $${testExitCode}
BUNDLE_UP_AND_EXIT = \
( \
@@ -300,7 +300,7 @@ BUNDLE_UP_AND_EXIT = \
$(RM) -f $(STATS_TXT) $(RUNLIST) $(PASSLIST) $(FAILLIST) $(EXITCODE); \
$(ECHO) "$${jtregExitCode}" > $(EXITCODE); \
if [ -r "$${_summary}" ] ; then \
- $(ECHO) "Summary: $${_summary}" > $(STATS_TXT); \
+ $(ECHO) "Summary: $(UNIQUE_DIR)" > $(STATS_TXT); \
$(EXPAND) $${_summary} | $(EGREP) -v ' Not run\.' > $(RUNLIST); \
$(EGREP) ' Passed\.' $(RUNLIST) \
| $(EGREP) -v ' Error\.' \
@@ -418,8 +418,9 @@ $(ECHO) "Running tests in othervm mode: $(call TestDirs, $?)"
$(MAKE) TESTDIRS="$(call TestDirs, $?)" USE_JTREG_SAMEVM=false UNIQUE_DIR=$@ jtreg_tests
endef
define SummaryInfo
-$(ECHO) "Summary for: $?"
+$(ECHO) "########################################################"
$(CAT) $(?:%=$(ABS_TEST_OUTPUT_DIR)/%/$(STATS_TXT_NAME))
+$(ECHO) "########################################################"
endef
# ------------------------------------------------------------------
@@ -446,10 +447,14 @@ JDK_ALL_TARGETS += jdk_beans2
jdk_beans2: java/beans/Beans java/beans/EventHandler java/beans/XMLDecoder \
java/beans/PropertyEditor
$(call RunOthervmBatch)
+
+# Stable othervm testruns (minus items from PROBLEM_LIST)
+# Using samevm has serious problems with these tests
JDK_ALL_TARGETS += jdk_beans3
jdk_beans3: java/beans/XMLEncoder
$(call RunOthervmBatch)
+# All beans tests
jdk_beans: jdk_beans1 jdk_beans2 jdk_beans3
@$(SummaryInfo)
@@ -475,6 +480,7 @@ JDK_ALL_TARGETS += jdk_management2
jdk_management2: com/sun/jmx com/sun/management sun/management
$(call RunOthervmBatch)
+# All management tests
jdk_management: jdk_management1 jdk_management2
@$(SummaryInfo)
@@ -506,10 +512,14 @@ JDK_ALL_TARGETS += jdk_nio2
jdk_nio2: java/nio/Buffer java/nio/ByteOrder \
java/nio/channels java/nio/BufferPoolMXBean java/nio/MappedByteBuffer
$(call RunOthervmBatch)
+
+# Stable othervm testruns (minus items from PROBLEM_LIST)
+# Using samevm has serious problems with these tests
JDK_ALL_TARGETS += jdk_nio3
jdk_nio3: com/sun/nio sun/nio
$(call RunOthervmBatch)
+# All nio tests
jdk_nio: jdk_nio1 jdk_nio2 jdk_nio3
@$(SummaryInfo)
@@ -529,10 +539,14 @@ jdk_security1: java/security
JDK_ALL_TARGETS += jdk_security2
jdk_security2: javax/crypto com/sun/crypto
$(call RunOthervmBatch)
+
+# Stable othervm testruns (minus items from PROBLEM_LIST)
+# Using samevm has serious problems with these tests
JDK_ALL_TARGETS += jdk_security3
jdk_security3: com/sun/security lib/security javax/security sun/security
$(call RunOthervmBatch)
+# All security tests
jdk_security: jdk_security1 jdk_security2 jdk_security3
@$(SummaryInfo)
@@ -547,15 +561,18 @@ JDK_ALL_TARGETS += jdk_text
jdk_text: java/text sun/text
$(call RunSamevmBatch)
-# Stable othervm testruns (minus items from PROBLEM_LIST)
-# Using samevm has serious problems with these tests
+# Stable samevm testruns (minus items from PROBLEM_LIST)
JDK_ALL_TARGETS += jdk_tools1
jdk_tools1: com/sun/jdi
$(call RunSamevmBatch)
+
+# Stable othervm testruns (minus items from PROBLEM_LIST)
+# Using samevm has serious problems with these tests
JDK_ALL_TARGETS += jdk_tools2
jdk_tools2: com/sun/tools sun/jvmstat sun/tools tools vm com/sun/servicetag com/sun/tracing
$(call RunOthervmBatch)
+# All tools tests
jdk_tools: jdk_tools1 jdk_tools2
@$(SummaryInfo)
@@ -567,7 +584,9 @@ jdk_util: java/util sun/util
# ------------------------------------------------------------------
# Run all tests
-jdk_all: $(filter-out jdk_awt jdk_rmi jdk_swing, $(JDK_ALL_TARGETS))
+FILTER_OUT_LIST=jdk_awt jdk_rmi jdk_swing
+JDK_ALL_STABLE_TARGETS := $(filter-out $(FILTER_OUT_LIST), $(JDK_ALL_TARGETS))
+jdk_all: $(JDK_ALL_STABLE_TARGETS)
@$(SummaryInfo)
# These are all phony targets
@@ -587,8 +606,8 @@ JTREG_BASIC_OPTIONS += -v:fail,error,time
JTREG_BASIC_OPTIONS += -retain:fail,error
# Ignore tests are not run and completely silent about it
JTREG_BASIC_OPTIONS += -ignore:quiet
-# Multiple by 2 the timeout numbers
-JTREG_BASIC_OPTIONS += -timeoutFactor:2
+# Multiple by 4 the timeout numbers
+JTREG_BASIC_OPTIONS += -timeoutFactor:4
# Boost the max memory for jtreg to avoid gc thrashing
JTREG_BASIC_OPTIONS += -J-Xmx512m
diff --git a/jdk/test/ProblemList.txt b/jdk/test/ProblemList.txt
index 2edcfd4d595..3a5d2f10584 100644
--- a/jdk/test/ProblemList.txt
+++ b/jdk/test/ProblemList.txt
@@ -431,6 +431,11 @@ java/lang/ClassLoader/deadlock/TestCrossDelegate.sh generic-all
# jdk_management
+# Fails on Windows 2000, Test failed for iiop java.lang.NullPointerException
+# at org.omg.stub.javax.management.remote.rmi._RMIConnectionImpl_Tie._invoke(Unknown Source)
+# at com.sun.corba.se.impl.protocol.CorbaServerRequestDispatcherImpl.dispatchToServant(CorbaServerRequestDispatcherImpl.java:653)
+javax/management/remote/mandatory/connection/ReconnectTest.java generic-all
+
# Solaris 10 sparc, NPE from org.omg.stub.javax.management.remote.rmi._RMIConnectionImpl_Tie._invoke
javax/management/remote/mandatory/threads/ExecutorTest.java generic-all
@@ -717,6 +722,9 @@ sun/net/www/http/KeepAliveCache/KeepAliveTimerThread.java generic-all
# Connection refused, windows samevm
sun/net/www/protocol/http/DigestTest.java generic-all
+# Fails on Fedora 9 32bit & 64bit & Solaris 10, wrong proxy for http://localhost/index.html
+java/net/ProxySelector/B6737819.java generic-all
+
############################################################################
# jdk_nio
@@ -724,6 +732,29 @@ sun/net/www/protocol/http/DigestTest.java generic-all
# Suspect many of these tests auffer from using fixed ports, no concrete
# evidence.
+# Fails on Windows 2000, Can't delete test directory .\x.SetLastModified.dir
+# at SetLastModified.main(SetLastModified.java:107)
+java/io/File/SetLastModified.java generic-all
+
+# Fails on Solaris 10 x64, address already in use
+java/nio/channels/DatagramChannel/SRTest.java generic-all
+
+# Fails on Solaris 10 x86, times out
+java/nio/channels/DatagramChannel/Sender.java generic-all
+
+# Fails on Fedora 9 x86, address in use
+java/nio/channels/Selector/SelectWrite.java generic-all
+
+# Fails on Fedora 9 32bit times out
+java/nio/channels/DatagramChannel/EmptyBuffer.java generic-all
+
+# Fails on Windows 2000, ExceptionInInitializerError
+# in WindowsAsynchronousServerSocketChannelImpl.java:316
+java/nio/channels/AsynchronousChannelGroup/Unbounded.java generic-all
+
+# Fails on Windows 2000, times out
+java/nio/channels/FileChannel/Transfer.java generic-all
+
# Fails on OpenSolaris, IllegalStateException: Cannot add or remove addresses
# from a channel that is bound to the wildcard address
com/sun/nio/sctp/SctpChannel/Bind.java generic-all
@@ -893,6 +924,45 @@ java/rmi/server/UnicastRemoteObject/unexportObject/UnexportLeak.java generic-all
# jdk_security
+# Fails on Solaris 10 X64, address already in use
+sun/security/krb5/auto/HttpNegotiateServer.java generic-all
+
+# Fails on almost all platforms
+# java.lang.UnsupportedClassVersionError: SerialTest :
+# Unsupported major.minor version 51.0
+# at java.lang.ClassLoader.defineClass1(Native Method)
+sun/security/util/Oid/S11N.sh generic-all
+
+# Fails on Fedora 9 32bit
+# GSSException: Failure unspecified at GSS-API level (Mechanism level:
+# Invalid argument (400) - Cannot find key of appropriate type to decrypt
+# AP REP - DES CBC mode with MD5)
+# at sun.security.jgss.krb5.Krb5Context.acceptSecContext(Krb5Context.java:778)
+sun/security/krb5/auto/NonMutualSpnego.java generic-all
+
+# Fails on Solaris 10 sparc, GSSException: Failure unspecified at GSS-API level
+# Also fails on Windows 2000 similar way
+sun/security/krb5/auto/ok-as-delegate.sh generic-all
+
+# Fails on Windows 2000, GSSException: Failure unspecified at GSS-API level
+# (Mechanism level: Request is a replay (34))
+sun/security/krb5/auto/ok-as-delegate-xrealm.sh generic-all
+
+# Fails on Windows 2000, ExceptionInInitializerError
+sun/security/mscapi/AccessKeyStore.sh generic-all
+
+# Fails on Windows 2000, UnsatisfiedLinkError: libnspr4.dll: Access is denied
+sun/security/pkcs11/KeyAgreement/TestDH.java generic-all
+
+# Fails on Windows 2000, UnsatisfiedLinkError: libnspr4.dll: Access is denied
+sun/security/pkcs11/fips/ClientJSSEServerJSSE.java generic-all
+
+# Fails on Solaris 10, KrbException: Additional pre-authentication required (25)
+sun/security/krb5/auto/basic.sh generic-all
+
+# Fails on Fedora 9 64bit, PKCS11Exception: CKR_DEVICE_ERROR
+sun/security/pkcs11/KeyAgreement/TestDH.java generic-all
+
# Run too slow on Solaris 10 sparc
sun/security/ssl/com/sun/net/ssl/internal/ssl/InputRecord/SSLSocketTimeoutNulls.java solaris-sparc
sun/security/ssl/com/sun/net/ssl/internal/ssl/SSLSocketImpl/ClientTimeout.java solaris-sparc
@@ -1088,6 +1158,13 @@ java/text/Bidi/Bug6665028.java linux-x64
# So most if not all tools tests are now being run with "othervm" mode.
# Some of these tools tests have a tendency to use fixed ports, bad idea.
+# Fails on Fedora 9 32bit, jps output differs problem
+sun/tools/jstatd/jstatdDefaults.sh generic-all
+
+# Fails on Linux Fedora 9 32bit, Could not read data for remote JVM 16133
+# jstat output differs from expected output
+sun/tools/jstatd/jstatdExternalRegistry.sh generic-all
+
# Output of jps differs from expected output.
# Invalid argument count on solaris-sparc and x64
sun/tools/jstatd/jstatdPort.sh generic-all
@@ -1099,6 +1176,11 @@ sun/tools/jps/jps-lm.sh generic-all
sun/tools/jps/jps-Vvml_2.sh generic-all
sun/tools/jps/jps-m_2.sh generic-all
+# Fails on Solaris 10 sparcv9, shell exits with 1
+# Turning off use of shared archive because of choice of garbage collector or large pages
+# Could not synchronize with target
+sun/tools/jps/jps-v_1.sh generic-all
+
# Fails on OpenSolaris "Could not synchronize with target"
sun/tools/jps/jps-Defaults.sh generic-all
sun/tools/jps/jps-V_2.sh generic-all
diff --git a/jdk/test/com/sun/jdi/NoLaunchOptionTest.java b/jdk/test/com/sun/jdi/NoLaunchOptionTest.java
index b65b375c85e..14e6acd2c5d 100644
--- a/jdk/test/com/sun/jdi/NoLaunchOptionTest.java
+++ b/jdk/test/com/sun/jdi/NoLaunchOptionTest.java
@@ -31,6 +31,9 @@
* @build VMConnection
* @run main/othervm NoLaunchOptionTest
*/
+
+import java.net.ServerSocket;
+
public class NoLaunchOptionTest extends Object {
private Process subprocess;
private int subprocessStatus;
@@ -121,12 +124,19 @@ public class NoLaunchOptionTest extends Object {
}
public static void main(String[] args) throws Exception {
+ // find a free port
+ ServerSocket ss = new ServerSocket(0);
+ int port = ss.getLocalPort();
+ ss.close();
+ String address = String.valueOf(port);
+
String javaExe = System.getProperty("java.home") +
java.io.File.separator + "bin" +
java.io.File.separator + "java";
String targetClass = "NotAClass";
String cmds [] = {javaExe,
- "-agentlib:jdwp=transport=dt_socket,address=8000," +
+ "-agentlib:jdwp=transport=dt_socket,address=" +
+ address + "," +
"onthrow=java.lang.ClassNotFoundException,suspend=n",
targetClass};
NoLaunchOptionTest myTest = new NoLaunchOptionTest();
diff --git a/jdk/test/com/sun/jdi/OptionTest.java b/jdk/test/com/sun/jdi/OptionTest.java
index e3d6eb60b2d..f6124d3e02a 100644
--- a/jdk/test/com/sun/jdi/OptionTest.java
+++ b/jdk/test/com/sun/jdi/OptionTest.java
@@ -32,6 +32,9 @@
* @run compile -g VMConnection.java
* @run main/othervm OptionTest
*/
+
+import java.net.ServerSocket;
+
public class OptionTest extends Object {
private Process subprocess;
private int subprocessStatus;
@@ -122,12 +125,18 @@ public class OptionTest extends Object {
}
public static void main(String[] args) throws Exception {
+ // find a free port
+ ServerSocket ss = new ServerSocket(0);
+ int port = ss.getLocalPort();
+ ss.close();
+ String address = String.valueOf(port);
+
String javaExe = System.getProperty("java.home") +
java.io.File.separator + "bin" +
java.io.File.separator + "java";
String targetClass = "HelloWorld";
String baseOptions = "transport=dt_socket" +
- ",address=8000" +
+ ",address=" + address +
",server=y" +
",suspend=n";
diff --git a/jdk/test/sun/tools/jhat/HatRun.java b/jdk/test/sun/tools/jhat/HatRun.java
index cb1e41b248e..6d736f83193 100644
--- a/jdk/test/sun/tools/jhat/HatRun.java
+++ b/jdk/test/sun/tools/jhat/HatRun.java
@@ -166,8 +166,10 @@ public class HatRun {
jre_home );
String cdir = System.getProperty("test.classes", ".");
String os_arch = System.getProperty("os.arch");
- boolean d64 = os_arch.equals("sparcv9") ||
- os_arch.equals("amd64");
+ String os_name = System.getProperty("os.name");
+ boolean d64 = os_name.equals("SunOS") && (
+ os_arch.equals("sparcv9") ||
+ os_arch.equals("amd64"));
String isa_dir = d64?(File.separator+os_arch):"";
String java = jre_home
+ File.separator + "bin" + isa_dir
From 9f5ca0249d160f721386eb410bdad7f04c86498e Mon Sep 17 00:00:00 2001
From: Vladimir Kozlov
Date: Wed, 9 Dec 2009 16:40:45 -0800
Subject: [PATCH 057/221] 6895383: JCK test throws NPE for method compiled with
Escape Analysis
Add missing checks for MemBar nodes in EA.
Reviewed-by: never
---
hotspot/src/share/vm/opto/compile.cpp | 1 +
hotspot/src/share/vm/opto/escape.cpp | 548 +++++++++++++++---------
hotspot/src/share/vm/opto/escape.hpp | 5 +
hotspot/src/share/vm/opto/lcm.cpp | 5 +-
hotspot/src/share/vm/opto/macro.cpp | 27 ++
hotspot/src/share/vm/opto/memnode.cpp | 66 ++-
hotspot/src/share/vm/opto/memnode.hpp | 8 +-
hotspot/src/share/vm/opto/node.hpp | 5 +-
hotspot/src/share/vm/opto/parse3.cpp | 6 +-
hotspot/test/compiler/6895383/Test.java | 51 +++
10 files changed, 510 insertions(+), 212 deletions(-)
create mode 100644 hotspot/test/compiler/6895383/Test.java
diff --git a/hotspot/src/share/vm/opto/compile.cpp b/hotspot/src/share/vm/opto/compile.cpp
index 02bcadb387b..f5d5387e9d3 100644
--- a/hotspot/src/share/vm/opto/compile.cpp
+++ b/hotspot/src/share/vm/opto/compile.cpp
@@ -1852,6 +1852,7 @@ void Compile::dump_asm(int *pcs, uint pc_limit) {
!n->is_Phi() && // a few noisely useless nodes
!n->is_Proj() &&
!n->is_MachTemp() &&
+ !n->is_SafePointScalarObject() &&
!n->is_Catch() && // Would be nice to print exception table targets
!n->is_MergeMem() && // Not very interesting
!n->is_top() && // Debug info table constants
diff --git a/hotspot/src/share/vm/opto/escape.cpp b/hotspot/src/share/vm/opto/escape.cpp
index 478a96a7537..ad624ee0042 100644
--- a/hotspot/src/share/vm/opto/escape.cpp
+++ b/hotspot/src/share/vm/opto/escape.cpp
@@ -779,6 +779,13 @@ Node* ConnectionGraph::find_inst_mem(Node *orig_mem, int alias_idx, GrowableArra
} else {
break;
}
+ } else if (result->is_ClearArray()) {
+ if (!ClearArrayNode::step_through(&result, (uint)tinst->instance_id(), phase)) {
+ // Can not bypass initialization of the instance
+ // we are looking for.
+ break;
+ }
+ // Otherwise skip it (the call updated 'result' value).
} else if (result->Opcode() == Op_SCMemProj) {
assert(result->in(0)->is_LoadStore(), "sanity");
const Type *at = phase->type(result->in(0)->in(MemNode::Address));
@@ -808,7 +815,6 @@ Node* ConnectionGraph::find_inst_mem(Node *orig_mem, int alias_idx, GrowableArra
return result;
}
-
//
// Convert the types of unescaped object to instance types where possible,
// propagate the new type information through the graph, and update memory
@@ -900,7 +906,6 @@ Node* ConnectionGraph::find_inst_mem(Node *orig_mem, int alias_idx, GrowableArra
//
void ConnectionGraph::split_unique_types(GrowableArray &alloc_worklist) {
GrowableArray memnode_worklist;
- GrowableArray mergemem_worklist;
GrowableArray orig_phis;
PhaseGVN *igvn = _compile->initial_gvn();
uint new_index_start = (uint) _compile->num_alias_types();
@@ -1025,7 +1030,7 @@ void ConnectionGraph::split_unique_types(GrowableArray &alloc_worklist)
alloc_worklist.append_if_missing(addp2);
}
alloc_worklist.append_if_missing(use);
- } else if (use->is_Initialize()) {
+ } else if (use->is_MemBar()) {
memnode_worklist.append_if_missing(use);
}
}
@@ -1035,10 +1040,12 @@ void ConnectionGraph::split_unique_types(GrowableArray &alloc_worklist)
PointsTo(ptset, get_addp_base(n), igvn);
assert(ptset.Size() == 1, "AddP address is unique");
uint elem = ptset.getelem(); // Allocation node's index
- if (elem == _phantom_object)
+ if (elem == _phantom_object) {
+ assert(false, "escaped allocation");
continue; // Assume the value was set outside this method.
+ }
Node *base = get_map(elem); // CheckCastPP node
- if (!split_AddP(n, base, igvn)) continue; // wrong type
+ if (!split_AddP(n, base, igvn)) continue; // wrong type from dead path
tinst = igvn->type(base)->isa_oopptr();
} else if (n->is_Phi() ||
n->is_CheckCastPP() ||
@@ -1053,8 +1060,10 @@ void ConnectionGraph::split_unique_types(GrowableArray &alloc_worklist)
PointsTo(ptset, n, igvn);
if (ptset.Size() == 1) {
uint elem = ptset.getelem(); // Allocation node's index
- if (elem == _phantom_object)
+ if (elem == _phantom_object) {
+ assert(false, "escaped allocation");
continue; // Assume the value was set outside this method.
+ }
Node *val = get_map(elem); // CheckCastPP node
TypeNode *tn = n->as_Type();
tinst = igvn->type(val)->isa_oopptr();
@@ -1069,8 +1078,7 @@ void ConnectionGraph::split_unique_types(GrowableArray &alloc_worklist)
tn_t = tn_type->isa_oopptr();
}
- if (tn_t != NULL &&
- tinst->cast_to_instance_id(TypeOopPtr::InstanceBot)->higher_equal(tn_t)) {
+ if (tn_t != NULL && tinst->klass()->is_subtype_of(tn_t->klass())) {
if (tn_type->isa_narrowoop()) {
tn_type = tinst->make_narrowoop();
} else {
@@ -1082,33 +1090,25 @@ void ConnectionGraph::split_unique_types(GrowableArray &alloc_worklist)
igvn->hash_insert(tn);
record_for_optimizer(n);
} else {
- continue; // wrong type
+ assert(tn_type == TypePtr::NULL_PTR ||
+ tn_t != NULL && !tinst->klass()->is_subtype_of(tn_t->klass()),
+ "unexpected type");
+ continue; // Skip dead path with different type
}
}
} else {
+ debug_only(n->dump();)
+ assert(false, "EA: unexpected node");
continue;
}
- // push users on appropriate worklist
+ // push allocation's users on appropriate worklist
for (DUIterator_Fast imax, i = n->fast_outs(imax); i < imax; i++) {
Node *use = n->fast_out(i);
if(use->is_Mem() && use->in(MemNode::Address) == n) {
+ // Load/store to instance's field
memnode_worklist.append_if_missing(use);
- } else if (use->is_Initialize()) {
+ } else if (use->is_MemBar()) {
memnode_worklist.append_if_missing(use);
- } else if (use->is_MergeMem()) {
- mergemem_worklist.append_if_missing(use);
- } else if (use->is_SafePoint() && tinst != NULL) {
- // Look for MergeMem nodes for calls which reference unique allocation
- // (through CheckCastPP nodes) even for debug info.
- Node* m = use->in(TypeFunc::Memory);
- uint iid = tinst->instance_id();
- while (m->is_Proj() && m->in(0)->is_SafePoint() &&
- m->in(0) != use && !m->in(0)->_idx != iid) {
- m = m->in(0)->in(TypeFunc::Memory);
- }
- if (m->is_MergeMem()) {
- mergemem_worklist.append_if_missing(m);
- }
} else if (use->is_AddP() && use->outcnt() > 0) { // No dead nodes
Node* addp2 = find_second_addp(use, n);
if (addp2 != NULL) {
@@ -1121,6 +1121,29 @@ void ConnectionGraph::split_unique_types(GrowableArray &alloc_worklist)
use->is_DecodeN() ||
(use->is_ConstraintCast() && use->Opcode() == Op_CastPP)) {
alloc_worklist.append_if_missing(use);
+#ifdef ASSERT
+ } else if (use->is_Mem()) {
+ assert(use->in(MemNode::Address) != n, "EA: missing allocation reference path");
+ } else if (use->is_MergeMem()) {
+ assert(_mergemem_worklist.contains(use->as_MergeMem()), "EA: missing MergeMem node in the worklist");
+ } else if (use->is_SafePoint()) {
+ // Look for MergeMem nodes for calls which reference unique allocation
+ // (through CheckCastPP nodes) even for debug info.
+ Node* m = use->in(TypeFunc::Memory);
+ if (m->is_MergeMem()) {
+ assert(_mergemem_worklist.contains(m->as_MergeMem()), "EA: missing MergeMem node in the worklist");
+ }
+ } else {
+ uint op = use->Opcode();
+ if (!(op == Op_CmpP || op == Op_Conv2B ||
+ op == Op_CastP2X || op == Op_StoreCM ||
+ op == Op_FastLock || op == Op_AryEq || op == Op_StrComp ||
+ op == Op_StrEquals || op == Op_StrIndexOf)) {
+ n->dump();
+ use->dump();
+ assert(false, "EA: missing allocation reference path");
+ }
+#endif
}
}
@@ -1138,13 +1161,11 @@ void ConnectionGraph::split_unique_types(GrowableArray &alloc_worklist)
Node *n = memnode_worklist.pop();
if (visited.test_set(n->_idx))
continue;
- if (n->is_Phi()) {
- assert(n->as_Phi()->adr_type() != TypePtr::BOTTOM, "narrow memory slice required");
- // we don't need to do anything, but the users must be pushed if we haven't processed
- // this Phi before
- } else if (n->is_Initialize()) {
- // we don't need to do anything, but the users of the memory projection must be pushed
- n = n->as_Initialize()->proj_out(TypeFunc::Memory);
+ if (n->is_Phi() || n->is_ClearArray()) {
+ // we don't need to do anything, but the users must be pushed
+ } else if (n->is_MemBar()) { // Initialize, MemBar nodes
+ // we don't need to do anything, but the users must be pushed
+ n = n->as_MemBar()->proj_out(TypeFunc::Memory);
if (n == NULL)
continue;
} else {
@@ -1181,31 +1202,48 @@ void ConnectionGraph::split_unique_types(GrowableArray &alloc_worklist)
// push user on appropriate worklist
for (DUIterator_Fast imax, i = n->fast_outs(imax); i < imax; i++) {
Node *use = n->fast_out(i);
- if (use->is_Phi()) {
+ if (use->is_Phi() || use->is_ClearArray()) {
memnode_worklist.append_if_missing(use);
} else if(use->is_Mem() && use->in(MemNode::Memory) == n) {
+ if (use->Opcode() == Op_StoreCM) // Ignore cardmark stores
+ continue;
memnode_worklist.append_if_missing(use);
- } else if (use->is_Initialize()) {
+ } else if (use->is_MemBar()) {
memnode_worklist.append_if_missing(use);
+#ifdef ASSERT
+ } else if(use->is_Mem()) {
+ assert(use->in(MemNode::Memory) != n, "EA: missing memory path");
} else if (use->is_MergeMem()) {
- mergemem_worklist.append_if_missing(use);
+ assert(_mergemem_worklist.contains(use->as_MergeMem()), "EA: missing MergeMem node in the worklist");
+ } else {
+ uint op = use->Opcode();
+ if (!(op == Op_StoreCM ||
+ (op == Op_CallLeaf && use->as_CallLeaf()->_name != NULL &&
+ strcmp(use->as_CallLeaf()->_name, "g1_wb_pre") == 0) ||
+ op == Op_AryEq || op == Op_StrComp ||
+ op == Op_StrEquals || op == Op_StrIndexOf)) {
+ n->dump();
+ use->dump();
+ assert(false, "EA: missing memory path");
+ }
+#endif
}
}
}
// Phase 3: Process MergeMem nodes from mergemem_worklist.
- // Walk each memory moving the first node encountered of each
+ // Walk each memory slice moving the first node encountered of each
// instance type to the the input corresponding to its alias index.
- while (mergemem_worklist.length() != 0) {
- Node *n = mergemem_worklist.pop();
- assert(n->is_MergeMem(), "MergeMem node required.");
- if (visited.test_set(n->_idx))
- continue;
- MergeMemNode *nmm = n->as_MergeMem();
+ uint length = _mergemem_worklist.length();
+ for( uint next = 0; next < length; ++next ) {
+ MergeMemNode* nmm = _mergemem_worklist.at(next);
+ assert(!visited.test_set(nmm->_idx), "should not be visited before");
// Note: we don't want to use MergeMemStream here because we only want to
- // scan inputs which exist at the start, not ones we add during processing.
- uint nslices = nmm->req();
+ // scan inputs which exist at the start, not ones we add during processing.
+ // Note 2: MergeMem may already contains instance memory slices added
+ // during find_inst_mem() call when memory nodes were processed above.
igvn->hash_delete(nmm);
+ uint nslices = nmm->req();
for (uint i = Compile::AliasIdxRaw+1; i < nslices; i++) {
Node* mem = nmm->in(i);
Node* cur = NULL;
@@ -1259,41 +1297,6 @@ void ConnectionGraph::split_unique_types(GrowableArray &alloc_worklist)
}
igvn->hash_insert(nmm);
record_for_optimizer(nmm);
-
- // Propagate new memory slices to following MergeMem nodes.
- for (DUIterator_Fast imax, i = n->fast_outs(imax); i < imax; i++) {
- Node *use = n->fast_out(i);
- if (use->is_Call()) {
- CallNode* in = use->as_Call();
- if (in->proj_out(TypeFunc::Memory) != NULL) {
- Node* m = in->proj_out(TypeFunc::Memory);
- for (DUIterator_Fast jmax, j = m->fast_outs(jmax); j < jmax; j++) {
- Node* mm = m->fast_out(j);
- if (mm->is_MergeMem()) {
- mergemem_worklist.append_if_missing(mm);
- }
- }
- }
- if (use->is_Allocate()) {
- use = use->as_Allocate()->initialization();
- if (use == NULL) {
- continue;
- }
- }
- }
- if (use->is_Initialize()) {
- InitializeNode* in = use->as_Initialize();
- if (in->proj_out(TypeFunc::Memory) != NULL) {
- Node* m = in->proj_out(TypeFunc::Memory);
- for (DUIterator_Fast jmax, j = m->fast_outs(jmax); j < jmax; j++) {
- Node* mm = m->fast_out(j);
- if (mm->is_MergeMem()) {
- mergemem_worklist.append_if_missing(mm);
- }
- }
- }
- }
- }
}
// Phase 4: Update the inputs of non-instance memory Phis and
@@ -1381,8 +1384,20 @@ bool ConnectionGraph::compute_escape() {
ptnode_adr(n->_idx)->node_type() == PointsToNode::JavaObject) {
has_allocations = true;
}
- if(n->is_AddP())
- cg_worklist.append(n->_idx);
+ if(n->is_AddP()) {
+ // Collect address nodes which directly reference an allocation.
+ // Use them during stage 3 below to build initial connection graph
+ // field edges. Other field edges could be added after StoreP/LoadP
+ // nodes are processed during stage 4 below.
+ Node* base = get_addp_base(n);
+ if(base->is_Proj() && base->in(0)->is_Allocate()) {
+ cg_worklist.append(n->_idx);
+ }
+ } else if (n->is_MergeMem()) {
+ // Collect all MergeMem nodes to add memory slices for
+ // scalar replaceable objects in split_unique_types().
+ _mergemem_worklist.append(n->as_MergeMem());
+ }
for (DUIterator_Fast imax, i = n->fast_outs(imax); i < imax; i++) {
Node* m = n->fast_out(i); // Get user
worklist_init.push(m);
@@ -1423,12 +1438,13 @@ bool ConnectionGraph::compute_escape() {
}
}
- VectorSet ptset(Thread::current()->resource_area());
+ Arena* arena = Thread::current()->resource_area();
+ VectorSet ptset(arena);
GrowableArray deferred_edges;
- VectorSet visited(Thread::current()->resource_area());
+ VectorSet visited(arena);
- // 5. Remove deferred edges from the graph and collect
- // information needed for type splitting.
+ // 5. Remove deferred edges from the graph and adjust
+ // escape state of nonescaping objects.
cg_length = cg_worklist.length();
for( uint next = 0; next < cg_length; ++next ) {
int ni = cg_worklist.at(next);
@@ -1438,98 +1454,9 @@ bool ConnectionGraph::compute_escape() {
remove_deferred(ni, &deferred_edges, &visited);
Node *n = ptn->_node;
if (n->is_AddP()) {
- // Search for objects which are not scalar replaceable.
- // Mark their escape state as ArgEscape to propagate the state
- // to referenced objects.
- // Note: currently there are no difference in compiler optimizations
- // for ArgEscape objects and NoEscape objects which are not
- // scalar replaceable.
-
- int offset = ptn->offset();
- Node *base = get_addp_base(n);
- ptset.Clear();
- PointsTo(ptset, base, igvn);
- int ptset_size = ptset.Size();
-
- // Check if a field's initializing value is recorded and add
- // a corresponding NULL field's value if it is not recorded.
- // Connection Graph does not record a default initialization by NULL
- // captured by Initialize node.
- //
- // Note: it will disable scalar replacement in some cases:
- //
- // Point p[] = new Point[1];
- // p[0] = new Point(); // Will be not scalar replaced
- //
- // but it will save us from incorrect optimizations in next cases:
- //
- // Point p[] = new Point[1];
- // if ( x ) p[0] = new Point(); // Will be not scalar replaced
- //
- // Without a control flow analysis we can't distinguish above cases.
- //
- if (offset != Type::OffsetBot && ptset_size == 1) {
- uint elem = ptset.getelem(); // Allocation node's index
- // It does not matter if it is not Allocation node since
- // only non-escaping allocations are scalar replaced.
- if (ptnode_adr(elem)->_node->is_Allocate() &&
- ptnode_adr(elem)->escape_state() == PointsToNode::NoEscape) {
- AllocateNode* alloc = ptnode_adr(elem)->_node->as_Allocate();
- InitializeNode* ini = alloc->initialization();
- Node* value = NULL;
- if (ini != NULL) {
- BasicType ft = UseCompressedOops ? T_NARROWOOP : T_OBJECT;
- Node* store = ini->find_captured_store(offset, type2aelembytes(ft), igvn);
- if (store != NULL && store->is_Store())
- value = store->in(MemNode::ValueIn);
- }
- if (value == NULL || value != ptnode_adr(value->_idx)->_node) {
- // A field's initializing value was not recorded. Add NULL.
- uint null_idx = UseCompressedOops ? _noop_null : _oop_null;
- add_pointsto_edge(ni, null_idx);
- }
- }
- }
-
- // An object is not scalar replaceable if the field which may point
- // to it has unknown offset (unknown element of an array of objects).
- //
- if (offset == Type::OffsetBot) {
- uint e_cnt = ptn->edge_count();
- for (uint ei = 0; ei < e_cnt; ei++) {
- uint npi = ptn->edge_target(ei);
- set_escape_state(npi, PointsToNode::ArgEscape);
- ptnode_adr(npi)->_scalar_replaceable = false;
- }
- }
-
- // Currently an object is not scalar replaceable if a LoadStore node
- // access its field since the field value is unknown after it.
- //
- bool has_LoadStore = false;
- for (DUIterator_Fast imax, i = n->fast_outs(imax); i < imax; i++) {
- Node *use = n->fast_out(i);
- if (use->is_LoadStore()) {
- has_LoadStore = true;
- break;
- }
- }
- // An object is not scalar replaceable if the address points
- // to unknown field (unknown element for arrays, offset is OffsetBot).
- //
- // Or the address may point to more then one object. This may produce
- // the false positive result (set scalar_replaceable to false)
- // since the flow-insensitive escape analysis can't separate
- // the case when stores overwrite the field's value from the case
- // when stores happened on different control branches.
- //
- if (ptset_size > 1 || ptset_size != 0 &&
- (has_LoadStore || offset == Type::OffsetBot)) {
- for( VectorSetI j(&ptset); j.test(); ++j ) {
- set_escape_state(j.elem, PointsToNode::ArgEscape);
- ptnode_adr(j.elem)->_scalar_replaceable = false;
- }
- }
+ // Search for objects which are not scalar replaceable
+ // and adjust their escape state.
+ verify_escape_state(ni, ptset, igvn);
}
}
}
@@ -1646,6 +1573,150 @@ bool ConnectionGraph::compute_escape() {
return has_non_escaping_obj;
}
+// Search for objects which are not scalar replaceable.
+void ConnectionGraph::verify_escape_state(int nidx, VectorSet& ptset, PhaseTransform* phase) {
+ PointsToNode* ptn = ptnode_adr(nidx);
+ Node* n = ptn->_node;
+ assert(n->is_AddP(), "Should be called for AddP nodes only");
+ // Search for objects which are not scalar replaceable.
+ // Mark their escape state as ArgEscape to propagate the state
+ // to referenced objects.
+ // Note: currently there are no difference in compiler optimizations
+ // for ArgEscape objects and NoEscape objects which are not
+ // scalar replaceable.
+
+ Compile* C = _compile;
+
+ int offset = ptn->offset();
+ Node* base = get_addp_base(n);
+ ptset.Clear();
+ PointsTo(ptset, base, phase);
+ int ptset_size = ptset.Size();
+
+ // Check if a oop field's initializing value is recorded and add
+ // a corresponding NULL field's value if it is not recorded.
+ // Connection Graph does not record a default initialization by NULL
+ // captured by Initialize node.
+ //
+ // Note: it will disable scalar replacement in some cases:
+ //
+ // Point p[] = new Point[1];
+ // p[0] = new Point(); // Will be not scalar replaced
+ //
+ // but it will save us from incorrect optimizations in next cases:
+ //
+ // Point p[] = new Point[1];
+ // if ( x ) p[0] = new Point(); // Will be not scalar replaced
+ //
+ // Do a simple control flow analysis to distinguish above cases.
+ //
+ if (offset != Type::OffsetBot && ptset_size == 1) {
+ uint elem = ptset.getelem(); // Allocation node's index
+ // It does not matter if it is not Allocation node since
+ // only non-escaping allocations are scalar replaced.
+ if (ptnode_adr(elem)->_node->is_Allocate() &&
+ ptnode_adr(elem)->escape_state() == PointsToNode::NoEscape) {
+ AllocateNode* alloc = ptnode_adr(elem)->_node->as_Allocate();
+ InitializeNode* ini = alloc->initialization();
+
+ // Check only oop fields.
+ const Type* adr_type = n->as_AddP()->bottom_type();
+ BasicType basic_field_type = T_INT;
+ if (adr_type->isa_instptr()) {
+ ciField* field = C->alias_type(adr_type->isa_instptr())->field();
+ if (field != NULL) {
+ basic_field_type = field->layout_type();
+ } else {
+ // Ignore non field load (for example, klass load)
+ }
+ } else if (adr_type->isa_aryptr()) {
+ const Type* elemtype = adr_type->isa_aryptr()->elem();
+ basic_field_type = elemtype->array_element_basic_type();
+ } else {
+ // Raw pointers are used for initializing stores so skip it.
+ assert(adr_type->isa_rawptr() && base->is_Proj() &&
+ (base->in(0) == alloc),"unexpected pointer type");
+ }
+ if (basic_field_type == T_OBJECT ||
+ basic_field_type == T_NARROWOOP ||
+ basic_field_type == T_ARRAY) {
+ Node* value = NULL;
+ if (ini != NULL) {
+ BasicType ft = UseCompressedOops ? T_NARROWOOP : T_OBJECT;
+ Node* store = ini->find_captured_store(offset, type2aelembytes(ft), phase);
+ if (store != NULL && store->is_Store()) {
+ value = store->in(MemNode::ValueIn);
+ } else if (ptn->edge_count() > 0) { // Are there oop stores?
+ // Check for a store which follows allocation without branches.
+ // For example, a volatile field store is not collected
+ // by Initialize node. TODO: it would be nice to use idom() here.
+ for (DUIterator_Fast imax, i = n->fast_outs(imax); i < imax; i++) {
+ store = n->fast_out(i);
+ if (store->is_Store() && store->in(0) != NULL) {
+ Node* ctrl = store->in(0);
+ while(!(ctrl == ini || ctrl == alloc || ctrl == NULL ||
+ ctrl == C->root() || ctrl == C->top() || ctrl->is_Region() ||
+ ctrl->is_IfTrue() || ctrl->is_IfFalse())) {
+ ctrl = ctrl->in(0);
+ }
+ if (ctrl == ini || ctrl == alloc) {
+ value = store->in(MemNode::ValueIn);
+ break;
+ }
+ }
+ }
+ }
+ }
+ if (value == NULL || value != ptnode_adr(value->_idx)->_node) {
+ // A field's initializing value was not recorded. Add NULL.
+ uint null_idx = UseCompressedOops ? _noop_null : _oop_null;
+ add_pointsto_edge(nidx, null_idx);
+ }
+ }
+ }
+ }
+
+ // An object is not scalar replaceable if the field which may point
+ // to it has unknown offset (unknown element of an array of objects).
+ //
+ if (offset == Type::OffsetBot) {
+ uint e_cnt = ptn->edge_count();
+ for (uint ei = 0; ei < e_cnt; ei++) {
+ uint npi = ptn->edge_target(ei);
+ set_escape_state(npi, PointsToNode::ArgEscape);
+ ptnode_adr(npi)->_scalar_replaceable = false;
+ }
+ }
+
+ // Currently an object is not scalar replaceable if a LoadStore node
+ // access its field since the field value is unknown after it.
+ //
+ bool has_LoadStore = false;
+ for (DUIterator_Fast imax, i = n->fast_outs(imax); i < imax; i++) {
+ Node *use = n->fast_out(i);
+ if (use->is_LoadStore()) {
+ has_LoadStore = true;
+ break;
+ }
+ }
+ // An object is not scalar replaceable if the address points
+ // to unknown field (unknown element for arrays, offset is OffsetBot).
+ //
+ // Or the address may point to more then one object. This may produce
+ // the false positive result (set scalar_replaceable to false)
+ // since the flow-insensitive escape analysis can't separate
+ // the case when stores overwrite the field's value from the case
+ // when stores happened on different control branches.
+ //
+ if (ptset_size > 1 || ptset_size != 0 &&
+ (has_LoadStore || offset == Type::OffsetBot)) {
+ for( VectorSetI j(&ptset); j.test(); ++j ) {
+ set_escape_state(j.elem, PointsToNode::ArgEscape);
+ ptnode_adr(j.elem)->_scalar_replaceable = false;
+ }
+ }
+}
+
void ConnectionGraph::process_call_arguments(CallNode *call, PhaseTransform *phase) {
switch (call->Opcode()) {
@@ -1657,6 +1728,7 @@ void ConnectionGraph::process_call_arguments(CallNode *call, PhaseTransform *pha
assert(false, "should be done already");
break;
#endif
+ case Op_CallLeaf:
case Op_CallLeafNoFP:
{
// Stub calls, objects do not escape but they are not scale replaceable.
@@ -1667,9 +1739,23 @@ void ConnectionGraph::process_call_arguments(CallNode *call, PhaseTransform *pha
const Type* at = d->field_at(i);
Node *arg = call->in(i)->uncast();
const Type *aat = phase->type(arg);
- if (!arg->is_top() && at->isa_ptr() && aat->isa_ptr()) {
+ if (!arg->is_top() && at->isa_ptr() && aat->isa_ptr() &&
+ ptnode_adr(arg->_idx)->escape_state() < PointsToNode::ArgEscape) {
+
assert(aat == Type::TOP || aat == TypePtr::NULL_PTR ||
aat->isa_ptr() != NULL, "expecting an Ptr");
+#ifdef ASSERT
+ if (!(call->Opcode() == Op_CallLeafNoFP &&
+ call->as_CallLeaf()->_name != NULL &&
+ (strstr(call->as_CallLeaf()->_name, "arraycopy") != 0) ||
+ call->as_CallLeaf()->_name != NULL &&
+ (strcmp(call->as_CallLeaf()->_name, "g1_wb_pre") == 0 ||
+ strcmp(call->as_CallLeaf()->_name, "g1_wb_post") == 0 ))
+ ) {
+ call->dump();
+ assert(false, "EA: unexpected CallLeaf");
+ }
+#endif
set_escape_state(arg->_idx, PointsToNode::ArgEscape);
if (arg->is_AddP()) {
//
@@ -1706,9 +1792,10 @@ void ConnectionGraph::process_call_arguments(CallNode *call, PhaseTransform *pha
for (uint i = TypeFunc::Parms; i < d->cnt(); i++) {
const Type* at = d->field_at(i);
int k = i - TypeFunc::Parms;
+ Node *arg = call->in(i)->uncast();
- if (at->isa_oopptr() != NULL) {
- Node *arg = call->in(i)->uncast();
+ if (at->isa_oopptr() != NULL &&
+ ptnode_adr(arg->_idx)->escape_state() < PointsToNode::ArgEscape) {
bool global_escapes = false;
bool fields_escapes = false;
@@ -1942,20 +2029,23 @@ void ConnectionGraph::record_for_escape_analysis(Node *n, PhaseTransform *phase)
record_for_optimizer(n);
_processed.set(n->_idx);
} else {
- // Have to process call's arguments first.
+ // Don't mark as processed since call's arguments have to be processed.
PointsToNode::NodeType nt = PointsToNode::UnknownType;
+ PointsToNode::EscapeState es = PointsToNode::UnknownEscape;
// Check if a call returns an object.
const TypeTuple *r = n->as_Call()->tf()->range();
- if (n->is_CallStaticJava() && r->cnt() > TypeFunc::Parms &&
+ if (r->cnt() > TypeFunc::Parms &&
+ r->field_at(TypeFunc::Parms)->isa_ptr() &&
n->as_Call()->proj_out(TypeFunc::Parms) != NULL) {
- // Note: use isa_ptr() instead of isa_oopptr() here because
- // the _multianewarray functions return a TypeRawPtr.
- if (r->field_at(TypeFunc::Parms)->isa_ptr() != NULL) {
- nt = PointsToNode::JavaObject;
+ nt = PointsToNode::JavaObject;
+ if (!n->is_CallStaticJava()) {
+ // Since the called mathod is statically unknown assume
+ // the worst case that the returned value globally escapes.
+ es = PointsToNode::GlobalEscape;
}
}
- add_node(n, nt, PointsToNode::UnknownEscape, false);
+ add_node(n, nt, es, false);
}
return;
}
@@ -2088,18 +2178,27 @@ void ConnectionGraph::record_for_escape_analysis(Node *n, PhaseTransform *phase)
}
case Op_Proj:
{
- // we are only interested in the result projection from a call
+ // we are only interested in the oop result projection from a call
if (n->as_Proj()->_con == TypeFunc::Parms && n->in(0)->is_Call() ) {
- add_node(n, PointsToNode::LocalVar, PointsToNode::UnknownEscape, false);
- process_call_result(n->as_Proj(), phase);
- if (!_processed.test(n->_idx)) {
- // The call's result may need to be processed later if the call
- // returns it's argument and the argument is not processed yet.
- _delayed_worklist.push(n);
+ const TypeTuple *r = n->in(0)->as_Call()->tf()->range();
+ assert(r->cnt() > TypeFunc::Parms, "sanity");
+ if (r->field_at(TypeFunc::Parms)->isa_ptr() != NULL) {
+ add_node(n, PointsToNode::LocalVar, PointsToNode::UnknownEscape, false);
+ int ti = n->in(0)->_idx;
+ // The call may not be registered yet (since not all its inputs are registered)
+ // if this is the projection from backbranch edge of Phi.
+ if (ptnode_adr(ti)->node_type() != PointsToNode::UnknownType) {
+ process_call_result(n->as_Proj(), phase);
+ }
+ if (!_processed.test(n->_idx)) {
+ // The call's result may need to be processed later if the call
+ // returns it's argument and the argument is not processed yet.
+ _delayed_worklist.push(n);
+ }
+ break;
}
- } else {
- _processed.set(n->_idx);
}
+ _processed.set(n->_idx);
break;
}
case Op_Return:
@@ -2160,6 +2259,15 @@ void ConnectionGraph::record_for_escape_analysis(Node *n, PhaseTransform *phase)
}
break;
}
+ case Op_AryEq:
+ case Op_StrComp:
+ case Op_StrEquals:
+ case Op_StrIndexOf:
+ {
+ // char[] arrays passed to string intrinsics are not scalar replaceable.
+ add_node(n, PointsToNode::UnknownType, PointsToNode::UnknownEscape, false);
+ break;
+ }
case Op_ThreadLocal:
{
add_node(n, PointsToNode::JavaObject, PointsToNode::ArgEscape, true);
@@ -2174,6 +2282,7 @@ void ConnectionGraph::record_for_escape_analysis(Node *n, PhaseTransform *phase)
void ConnectionGraph::build_connection_graph(Node *n, PhaseTransform *phase) {
uint n_idx = n->_idx;
+ assert(ptnode_adr(n_idx)->_node != NULL, "node should be registered");
// Don't set processed bit for AddP, LoadP, StoreP since
// they may need more then one pass to process.
@@ -2211,6 +2320,7 @@ void ConnectionGraph::build_connection_graph(Node *n, PhaseTransform *phase) {
case Op_DecodeN:
{
int ti = n->in(1)->_idx;
+ assert(ptnode_adr(ti)->node_type() != PointsToNode::UnknownType, "all nodes should be registered");
if (ptnode_adr(ti)->node_type() == PointsToNode::JavaObject) {
add_pointsto_edge(n_idx, ti);
} else {
@@ -2250,7 +2360,6 @@ void ConnectionGraph::build_connection_graph(Node *n, PhaseTransform *phase) {
#endif
Node* adr = n->in(MemNode::Address)->uncast();
- const Type *adr_type = phase->type(adr);
Node* adr_base;
if (adr->is_AddP()) {
adr_base = get_addp_base(adr);
@@ -2302,13 +2411,19 @@ void ConnectionGraph::build_connection_graph(Node *n, PhaseTransform *phase) {
}
case Op_Proj:
{
- // we are only interested in the result projection from a call
+ // we are only interested in the oop result projection from a call
if (n->as_Proj()->_con == TypeFunc::Parms && n->in(0)->is_Call() ) {
- process_call_result(n->as_Proj(), phase);
- assert(_processed.test(n_idx), "all call results should be processed");
- } else {
- assert(false, "Op_Proj");
+ assert(ptnode_adr(n->in(0)->_idx)->node_type() != PointsToNode::UnknownType,
+ "all nodes should be registered");
+ const TypeTuple *r = n->in(0)->as_Call()->tf()->range();
+ assert(r->cnt() > TypeFunc::Parms, "sanity");
+ if (r->field_at(TypeFunc::Parms)->isa_ptr() != NULL) {
+ process_call_result(n->as_Proj(), phase);
+ assert(_processed.test(n_idx), "all call results should be processed");
+ break;
+ }
}
+ assert(false, "Op_Proj");
break;
}
case Op_Return:
@@ -2320,6 +2435,7 @@ void ConnectionGraph::build_connection_graph(Node *n, PhaseTransform *phase) {
}
#endif
int ti = n->in(TypeFunc::Parms)->_idx;
+ assert(ptnode_adr(ti)->node_type() != PointsToNode::UnknownType, "node should be registered");
if (ptnode_adr(ti)->node_type() == PointsToNode::JavaObject) {
add_pointsto_edge(n_idx, ti);
} else {
@@ -2354,14 +2470,38 @@ void ConnectionGraph::build_connection_graph(Node *n, PhaseTransform *phase) {
}
break;
}
+ case Op_AryEq:
+ case Op_StrComp:
+ case Op_StrEquals:
+ case Op_StrIndexOf:
+ {
+ // char[] arrays passed to string intrinsic do not escape but
+ // they are not scalar replaceable. Adjust escape state for them.
+ // Start from in(2) edge since in(1) is memory edge.
+ for (uint i = 2; i < n->req(); i++) {
+ Node* adr = n->in(i)->uncast();
+ const Type *at = phase->type(adr);
+ if (!adr->is_top() && at->isa_ptr()) {
+ assert(at == Type::TOP || at == TypePtr::NULL_PTR ||
+ at->isa_ptr() != NULL, "expecting an Ptr");
+ if (adr->is_AddP()) {
+ adr = get_addp_base(adr);
+ }
+ // Mark as ArgEscape everything "adr" could point to.
+ set_escape_state(adr->_idx, PointsToNode::ArgEscape);
+ }
+ }
+ _processed.set(n_idx);
+ break;
+ }
case Op_ThreadLocal:
{
assert(false, "Op_ThreadLocal");
break;
}
default:
- ;
- // nothing to do
+ // This method should be called only for EA specific nodes.
+ ShouldNotReachHere();
}
}
diff --git a/hotspot/src/share/vm/opto/escape.hpp b/hotspot/src/share/vm/opto/escape.hpp
index 1ce0cc9cf29..4a5b960fa3e 100644
--- a/hotspot/src/share/vm/opto/escape.hpp
+++ b/hotspot/src/share/vm/opto/escape.hpp
@@ -210,6 +210,8 @@ private:
Unique_Node_List _delayed_worklist; // Nodes to be processed before
// the call build_connection_graph().
+ GrowableArray _mergemem_worklist; // List of all MergeMem nodes
+
VectorSet _processed; // Records which nodes have been
// processed.
@@ -315,6 +317,9 @@ private:
// Set the escape state of a node
void set_escape_state(uint ni, PointsToNode::EscapeState es);
+ // Search for objects which are not scalar replaceable.
+ void verify_escape_state(int nidx, VectorSet& ptset, PhaseTransform* phase);
+
public:
ConnectionGraph(Compile *C);
diff --git a/hotspot/src/share/vm/opto/lcm.cpp b/hotspot/src/share/vm/opto/lcm.cpp
index 31de55a5435..0afe80c8f92 100644
--- a/hotspot/src/share/vm/opto/lcm.cpp
+++ b/hotspot/src/share/vm/opto/lcm.cpp
@@ -616,8 +616,9 @@ bool Block::schedule_local(PhaseCFG *cfg, Matcher &matcher, int *ready_cnt, Vect
assert(cfg->_bbs[oop_store->_idx]->_dom_depth <= this->_dom_depth, "oop_store must dominate card-mark");
}
}
- if( n->is_Mach() && n->as_Mach()->ideal_Opcode() == Op_MemBarAcquire &&
- n->req() > TypeFunc::Parms ) {
+ if( n->is_Mach() && n->req() > TypeFunc::Parms &&
+ (n->as_Mach()->ideal_Opcode() == Op_MemBarAcquire ||
+ n->as_Mach()->ideal_Opcode() == Op_MemBarVolatile) ) {
// MemBarAcquire could be created without Precedent edge.
// del_req() replaces the specified edge with the last input edge
// and then removes the last edge. If the specified edge > number of
diff --git a/hotspot/src/share/vm/opto/macro.cpp b/hotspot/src/share/vm/opto/macro.cpp
index 6bff3539c30..2fdc335b918 100644
--- a/hotspot/src/share/vm/opto/macro.cpp
+++ b/hotspot/src/share/vm/opto/macro.cpp
@@ -316,6 +316,21 @@ static Node *scan_mem_chain(Node *mem, int alias_idx, int offset, Node *start_me
assert(adr_idx == Compile::AliasIdxRaw, "address must match or be raw");
}
mem = mem->in(MemNode::Memory);
+ } else if (mem->is_ClearArray()) {
+ if (!ClearArrayNode::step_through(&mem, alloc->_idx, phase)) {
+ // Can not bypass initialization of the instance
+ // we are looking.
+ debug_only(intptr_t offset;)
+ assert(alloc == AllocateNode::Ideal_allocation(mem->in(3), phase, offset), "sanity");
+ InitializeNode* init = alloc->as_Allocate()->initialization();
+ // We are looking for stored value, return Initialize node
+ // or memory edge from Allocate node.
+ if (init != NULL)
+ return init;
+ else
+ return alloc->in(TypeFunc::Memory); // It will produce zero value (see callers).
+ }
+ // Otherwise skip it (the call updated 'mem' value).
} else if (mem->Opcode() == Op_SCMemProj) {
assert(mem->in(0)->is_LoadStore(), "sanity");
const TypePtr* atype = mem->in(0)->in(MemNode::Address)->bottom_type()->is_ptr();
@@ -823,6 +838,18 @@ void PhaseMacroExpand::process_users_of_allocation(AllocateNode *alloc) {
Node *n = use->last_out(k);
uint oc2 = use->outcnt();
if (n->is_Store()) {
+#ifdef ASSERT
+ // Verify that there is no dependent MemBarVolatile nodes,
+ // they should be removed during IGVN, see MemBarNode::Ideal().
+ for (DUIterator_Fast pmax, p = n->fast_outs(pmax);
+ p < pmax; p++) {
+ Node* mb = n->fast_out(p);
+ assert(mb->is_Initialize() || !mb->is_MemBar() ||
+ mb->req() <= MemBarNode::Precedent ||
+ mb->in(MemBarNode::Precedent) != n,
+ "MemBarVolatile should be eliminated for non-escaping object");
+ }
+#endif
_igvn.replace_node(n, n->in(MemNode::Memory));
} else {
eliminate_card_mark(n);
diff --git a/hotspot/src/share/vm/opto/memnode.cpp b/hotspot/src/share/vm/opto/memnode.cpp
index fb14ebff8c1..4698add456b 100644
--- a/hotspot/src/share/vm/opto/memnode.cpp
+++ b/hotspot/src/share/vm/opto/memnode.cpp
@@ -123,6 +123,13 @@ Node *MemNode::optimize_simple_memory_chain(Node *mchain, const TypePtr *t_adr,
} else {
assert(false, "unexpected projection");
}
+ } else if (result->is_ClearArray()) {
+ if (!ClearArrayNode::step_through(&result, instance_id, phase)) {
+ // Can not bypass initialization of the instance
+ // we are looking for.
+ break;
+ }
+ // Otherwise skip it (the call updated 'result' value).
} else if (result->is_MergeMem()) {
result = step_through_mergemem(phase, result->as_MergeMem(), t_adr, NULL, tty);
}
@@ -537,6 +544,15 @@ Node* MemNode::find_previous_store(PhaseTransform* phase) {
} else if (mem->is_Proj() && mem->in(0)->is_MemBar()) {
mem = mem->in(0)->in(TypeFunc::Memory);
continue; // (a) advance through independent MemBar memory
+ } else if (mem->is_ClearArray()) {
+ if (ClearArrayNode::step_through(&mem, (uint)addr_t->instance_id(), phase)) {
+ // (the call updated 'mem' value)
+ continue; // (a) advance through independent allocation memory
+ } else {
+ // Can not bypass initialization of the instance
+ // we are looking for.
+ return mem;
+ }
} else if (mem->is_MergeMem()) {
int alias_idx = phase->C->get_alias_index(adr_type());
mem = mem->as_MergeMem()->memory_at(alias_idx);
@@ -2454,6 +2470,31 @@ Node *ClearArrayNode::Ideal(PhaseGVN *phase, bool can_reshape){
return mem;
}
+//----------------------------step_through----------------------------------
+// Return allocation input memory edge if it is different instance
+// or itself if it is the one we are looking for.
+bool ClearArrayNode::step_through(Node** np, uint instance_id, PhaseTransform* phase) {
+ Node* n = *np;
+ assert(n->is_ClearArray(), "sanity");
+ intptr_t offset;
+ AllocateNode* alloc = AllocateNode::Ideal_allocation(n->in(3), phase, offset);
+ // This method is called only before Allocate nodes are expanded during
+ // macro nodes expansion. Before that ClearArray nodes are only generated
+ // in LibraryCallKit::generate_arraycopy() which follows allocations.
+ assert(alloc != NULL, "should have allocation");
+ if (alloc->_idx == instance_id) {
+ // Can not bypass initialization of the instance we are looking for.
+ return false;
+ }
+ // Otherwise skip it.
+ InitializeNode* init = alloc->initialization();
+ if (init != NULL)
+ *np = init->in(TypeFunc::Memory);
+ else
+ *np = alloc->in(TypeFunc::Memory);
+ return true;
+}
+
//----------------------------clear_memory-------------------------------------
// Generate code to initialize object storage to zero.
Node* ClearArrayNode::clear_memory(Node* ctl, Node* mem, Node* dest,
@@ -2627,7 +2668,30 @@ MemBarNode* MemBarNode::make(Compile* C, int opcode, int atp, Node* pn) {
// Return a node which is more "ideal" than the current node. Strip out
// control copies
Node *MemBarNode::Ideal(PhaseGVN *phase, bool can_reshape) {
- return remove_dead_region(phase, can_reshape) ? this : NULL;
+ if (remove_dead_region(phase, can_reshape)) return this;
+
+ // Eliminate volatile MemBars for scalar replaced objects.
+ if (can_reshape && req() == (Precedent+1) &&
+ (Opcode() == Op_MemBarAcquire || Opcode() == Op_MemBarVolatile)) {
+ // Volatile field loads and stores.
+ Node* my_mem = in(MemBarNode::Precedent);
+ if (my_mem != NULL && my_mem->is_Mem()) {
+ const TypeOopPtr* t_oop = my_mem->in(MemNode::Address)->bottom_type()->isa_oopptr();
+ // Check for scalar replaced object reference.
+ if( t_oop != NULL && t_oop->is_known_instance_field() &&
+ t_oop->offset() != Type::OffsetBot &&
+ t_oop->offset() != Type::OffsetTop) {
+ // Replace MemBar projections by its inputs.
+ PhaseIterGVN* igvn = phase->is_IterGVN();
+ igvn->replace_node(proj_out(TypeFunc::Memory), in(TypeFunc::Memory));
+ igvn->replace_node(proj_out(TypeFunc::Control), in(TypeFunc::Control));
+ // Must return either the original node (now dead) or a new node
+ // (Do not return a top here, since that would break the uniqueness of top.)
+ return new (phase->C, 1) ConINode(TypeInt::ZERO);
+ }
+ }
+ }
+ return NULL;
}
//------------------------------Value------------------------------------------
diff --git a/hotspot/src/share/vm/opto/memnode.hpp b/hotspot/src/share/vm/opto/memnode.hpp
index a71df7d406a..cd0e60d971e 100644
--- a/hotspot/src/share/vm/opto/memnode.hpp
+++ b/hotspot/src/share/vm/opto/memnode.hpp
@@ -717,7 +717,10 @@ public:
//------------------------------ClearArray-------------------------------------
class ClearArrayNode: public Node {
public:
- ClearArrayNode( Node *ctrl, Node *arymem, Node *word_cnt, Node *base ) : Node(ctrl,arymem,word_cnt,base) {}
+ ClearArrayNode( Node *ctrl, Node *arymem, Node *word_cnt, Node *base )
+ : Node(ctrl,arymem,word_cnt,base) {
+ init_class_id(Class_ClearArray);
+ }
virtual int Opcode() const;
virtual const Type *bottom_type() const { return Type::MEMORY; }
// ClearArray modifies array elements, and so affects only the
@@ -743,6 +746,9 @@ public:
Node* start_offset,
Node* end_offset,
PhaseGVN* phase);
+ // Return allocation input memory edge if it is different instance
+ // or itself if it is the one we are looking for.
+ static bool step_through(Node** np, uint instance_id, PhaseTransform* phase);
};
//------------------------------StrComp-------------------------------------
diff --git a/hotspot/src/share/vm/opto/node.hpp b/hotspot/src/share/vm/opto/node.hpp
index 1fe4950e913..92da96b40a2 100644
--- a/hotspot/src/share/vm/opto/node.hpp
+++ b/hotspot/src/share/vm/opto/node.hpp
@@ -47,6 +47,7 @@ class CallStaticJavaNode;
class CatchNode;
class CatchProjNode;
class CheckCastPPNode;
+class ClearArrayNode;
class CmpNode;
class CodeBuffer;
class ConstraintCastNode;
@@ -599,8 +600,9 @@ public:
DEFINE_CLASS_ID(BoxLock, Node, 10)
DEFINE_CLASS_ID(Add, Node, 11)
DEFINE_CLASS_ID(Mul, Node, 12)
+ DEFINE_CLASS_ID(ClearArray, Node, 13)
- _max_classes = ClassMask_Mul
+ _max_classes = ClassMask_ClearArray
};
#undef DEFINE_CLASS_ID
@@ -698,6 +700,7 @@ public:
DEFINE_CLASS_QUERY(CatchProj)
DEFINE_CLASS_QUERY(CheckCastPP)
DEFINE_CLASS_QUERY(ConstraintCast)
+ DEFINE_CLASS_QUERY(ClearArray)
DEFINE_CLASS_QUERY(CMove)
DEFINE_CLASS_QUERY(Cmp)
DEFINE_CLASS_QUERY(CountedLoop)
diff --git a/hotspot/src/share/vm/opto/parse3.cpp b/hotspot/src/share/vm/opto/parse3.cpp
index 7125cb5d619..83a3927a5ee 100644
--- a/hotspot/src/share/vm/opto/parse3.cpp
+++ b/hotspot/src/share/vm/opto/parse3.cpp
@@ -240,19 +240,19 @@ void Parse::do_put_xxx(const TypePtr* obj_type, Node* obj, ciField* field, bool
// membar is dependent on the store, keeping any other membars generated
// below from floating up past the store.
int adr_idx = C->get_alias_index(adr_type);
- insert_mem_bar_volatile(Op_MemBarVolatile, adr_idx);
+ insert_mem_bar_volatile(Op_MemBarVolatile, adr_idx, store);
// Now place a membar for AliasIdxBot for the unknown yet-to-be-parsed
// volatile alias indices. Skip this if the membar is redundant.
if (adr_idx != Compile::AliasIdxBot) {
- insert_mem_bar_volatile(Op_MemBarVolatile, Compile::AliasIdxBot);
+ insert_mem_bar_volatile(Op_MemBarVolatile, Compile::AliasIdxBot, store);
}
// Finally, place alias-index-specific membars for each volatile index
// that isn't the adr_idx membar. Typically there's only 1 or 2.
for( int i = Compile::AliasIdxRaw; i < C->num_alias_types(); i++ ) {
if (i != adr_idx && C->alias_type(i)->is_volatile()) {
- insert_mem_bar_volatile(Op_MemBarVolatile, i);
+ insert_mem_bar_volatile(Op_MemBarVolatile, i, store);
}
}
}
diff --git a/hotspot/test/compiler/6895383/Test.java b/hotspot/test/compiler/6895383/Test.java
new file mode 100644
index 00000000000..719ba31134a
--- /dev/null
+++ b/hotspot/test/compiler/6895383/Test.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright 2009 Sun Microsystems, 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ *
+ */
+
+/**
+ * @test
+ * @bug 6895383
+ * @summary JCK test throws NPE for method compiled with Escape Analysis
+ *
+ * @run main/othervm -Xcomp Test
+ */
+
+public class Test {
+ public static void main(String argv[]) {
+ Test test = new Test();
+ test.testRemove1_IndexOutOfBounds();
+ test.testAddAll1_IndexOutOfBoundsException();
+ }
+
+ public void testRemove1_IndexOutOfBounds() {
+ CopyOnWriteArrayList c = new CopyOnWriteArrayList();
+ }
+
+ public void testAddAll1_IndexOutOfBoundsException() {
+ try {
+ CopyOnWriteArrayList c = new CopyOnWriteArrayList();
+ c.addAll(-1, new LinkedList()); // should throw IndexOutOfBoundsException
+ } catch (IndexOutOfBoundsException e) {
+ }
+ }
+}
From 07d94668d2dca9e256570e3e1429d16d7ff89cc3 Mon Sep 17 00:00:00 2001
From: Joe Darcy
Date: Wed, 9 Dec 2009 17:55:48 -0800
Subject: [PATCH 058/221] 6909057: @see Arrays#hashCode missing particular
method specification in j.u.Objects.hash
Reviewed-by: ksrini
---
jdk/src/share/classes/java/util/Objects.java | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/jdk/src/share/classes/java/util/Objects.java b/jdk/src/share/classes/java/util/Objects.java
index 3ef61bde98d..8b009243eb9 100644
--- a/jdk/src/share/classes/java/util/Objects.java
+++ b/jdk/src/share/classes/java/util/Objects.java
@@ -119,7 +119,7 @@ public final class Objects {
*
* @param values the values to be hashed
* @return a hash value of the sequence of input values
- * @see Arrays#hashCode
+ * @see Arrays#hashCode(Object[])
* @see List#hashCode
*/
public static int hash(Object... values) {
From 00f583219fef7064cf99e3670d0277e457530517 Mon Sep 17 00:00:00 2001
From: Vladimir Kozlov
Date: Wed, 9 Dec 2009 19:50:14 -0800
Subject: [PATCH 059/221] 6896727:
nsk/logging/LoggingPermission/LoggingPermission/logperm002 fails with G1,
EscapeAnalisys
Move instance store's memory users to corresponding memory slices when updating its memory edge.
Reviewed-by: never
---
hotspot/src/share/vm/opto/escape.cpp | 137 ++++++++++++++++++++++--
hotspot/src/share/vm/opto/escape.hpp | 3 +-
hotspot/test/compiler/6896727/Test.java | 48 +++++++++
3 files changed, 178 insertions(+), 10 deletions(-)
create mode 100644 hotspot/test/compiler/6896727/Test.java
diff --git a/hotspot/src/share/vm/opto/escape.cpp b/hotspot/src/share/vm/opto/escape.cpp
index ad624ee0042..b560151bf83 100644
--- a/hotspot/src/share/vm/opto/escape.cpp
+++ b/hotspot/src/share/vm/opto/escape.cpp
@@ -543,6 +543,7 @@ bool ConnectionGraph::split_AddP(Node *addp, Node *base, PhaseGVN *igvn) {
int alias_idx = _compile->get_alias_index(tinst);
igvn->set_type(addp, tinst);
// record the allocation in the node map
+ assert(ptnode_adr(addp->_idx)->_node != NULL, "should be registered");
set_map(addp->_idx, get_map(base->_idx));
// Set addp's Base and Address to 'base'.
@@ -618,9 +619,14 @@ PhiNode *ConnectionGraph::create_split_phi(PhiNode *orig_phi, int alias_idx, Gro
const TypePtr *atype = C->get_adr_type(alias_idx);
result = PhiNode::make(orig_phi->in(0), NULL, Type::MEMORY, atype);
C->copy_node_notes_to(result, orig_phi);
- set_map_phi(orig_phi->_idx, result);
igvn->set_type(result, result->bottom_type());
record_for_optimizer(result);
+
+ debug_only(Node* pn = ptnode_adr(orig_phi->_idx)->_node;)
+ assert(pn == NULL || pn == orig_phi, "wrong node");
+ set_map(orig_phi->_idx, result);
+ ptnode_adr(orig_phi->_idx)->_node = orig_phi;
+
new_created = true;
return result;
}
@@ -710,6 +716,81 @@ static Node *step_through_mergemem(MergeMemNode *mmem, int alias_idx, const Type
return mem;
}
+//
+// Move memory users to their memory slices.
+//
+void ConnectionGraph::move_inst_mem(Node* n, GrowableArray &orig_phis, PhaseGVN *igvn) {
+ Compile* C = _compile;
+
+ const TypePtr* tp = igvn->type(n->in(MemNode::Address))->isa_ptr();
+ assert(tp != NULL, "ptr type");
+ int alias_idx = C->get_alias_index(tp);
+ int general_idx = C->get_general_index(alias_idx);
+
+ // Move users first
+ for (DUIterator_Fast imax, i = n->fast_outs(imax); i < imax; i++) {
+ Node* use = n->fast_out(i);
+ if (use->is_MergeMem()) {
+ MergeMemNode* mmem = use->as_MergeMem();
+ assert(n == mmem->memory_at(alias_idx), "should be on instance memory slice");
+ if (n != mmem->memory_at(general_idx) || alias_idx == general_idx) {
+ continue; // Nothing to do
+ }
+ // Replace previous general reference to mem node.
+ uint orig_uniq = C->unique();
+ Node* m = find_inst_mem(n, general_idx, orig_phis, igvn);
+ assert(orig_uniq == C->unique(), "no new nodes");
+ mmem->set_memory_at(general_idx, m);
+ --imax;
+ --i;
+ } else if (use->is_MemBar()) {
+ assert(!use->is_Initialize(), "initializing stores should not be moved");
+ if (use->req() > MemBarNode::Precedent &&
+ use->in(MemBarNode::Precedent) == n) {
+ // Don't move related membars.
+ record_for_optimizer(use);
+ continue;
+ }
+ tp = use->as_MemBar()->adr_type()->isa_ptr();
+ if (tp != NULL && C->get_alias_index(tp) == alias_idx ||
+ alias_idx == general_idx) {
+ continue; // Nothing to do
+ }
+ // Move to general memory slice.
+ uint orig_uniq = C->unique();
+ Node* m = find_inst_mem(n, general_idx, orig_phis, igvn);
+ assert(orig_uniq == C->unique(), "no new nodes");
+ igvn->hash_delete(use);
+ imax -= use->replace_edge(n, m);
+ igvn->hash_insert(use);
+ record_for_optimizer(use);
+ --i;
+#ifdef ASSERT
+ } else if (use->is_Mem()) {
+ if (use->Opcode() == Op_StoreCM && use->in(MemNode::OopStore) == n) {
+ // Don't move related cardmark.
+ continue;
+ }
+ // Memory nodes should have new memory input.
+ tp = igvn->type(use->in(MemNode::Address))->isa_ptr();
+ assert(tp != NULL, "ptr type");
+ int idx = C->get_alias_index(tp);
+ assert(get_map(use->_idx) != NULL || idx == alias_idx,
+ "Following memory nodes should have new memory input or be on the same memory slice");
+ } else if (use->is_Phi()) {
+ // Phi nodes should be split and moved already.
+ tp = use->as_Phi()->adr_type()->isa_ptr();
+ assert(tp != NULL, "ptr type");
+ int idx = C->get_alias_index(tp);
+ assert(idx == alias_idx, "Following Phi nodes should be on the same memory slice");
+ } else {
+ use->dump();
+ assert(false, "should not be here");
+#endif
+ }
+ }
+}
+
//
// Search memory chain of "mem" to find a MemNode whose address
// is the specified alias index.
@@ -775,6 +856,7 @@ Node* ConnectionGraph::find_inst_mem(Node *orig_mem, int alias_idx, GrowableArra
C->get_alias_index(result->as_Phi()->adr_type()) != alias_idx) {
Node *un = result->as_Phi()->unique_input(phase);
if (un != NULL) {
+ orig_phis.append_if_missing(result->as_Phi());
result = un;
} else {
break;
@@ -907,10 +989,12 @@ Node* ConnectionGraph::find_inst_mem(Node *orig_mem, int alias_idx, GrowableArra
void ConnectionGraph::split_unique_types(GrowableArray &alloc_worklist) {
GrowableArray memnode_worklist;
GrowableArray orig_phis;
+
PhaseGVN *igvn = _compile->initial_gvn();
uint new_index_start = (uint) _compile->num_alias_types();
- VectorSet visited(Thread::current()->resource_area());
- VectorSet ptset(Thread::current()->resource_area());
+ Arena* arena = Thread::current()->resource_area();
+ VectorSet visited(arena);
+ VectorSet ptset(arena);
// Phase 1: Process possible allocations from alloc_worklist.
@@ -986,6 +1070,8 @@ void ConnectionGraph::split_unique_types(GrowableArray &alloc_worklist)
// - non-escaping
// - eligible to be a unique type
// - not determined to be ineligible by escape analysis
+ assert(ptnode_adr(alloc->_idx)->_node != NULL &&
+ ptnode_adr(n->_idx)->_node != NULL, "should be registered");
set_map(alloc->_idx, n);
set_map(n->_idx, alloc);
const TypeOopPtr *t = igvn->type(n)->isa_oopptr();
@@ -1182,6 +1268,10 @@ void ConnectionGraph::split_unique_types(GrowableArray &alloc_worklist)
return;
}
if (mem != n->in(MemNode::Memory)) {
+ // We delay the memory edge update since we need old one in
+ // MergeMem code below when instances memory slices are separated.
+ debug_only(Node* pn = ptnode_adr(n->_idx)->_node;)
+ assert(pn == NULL || pn == n, "wrong node");
set_map(n->_idx, mem);
ptnode_adr(n->_idx)->_node = n;
}
@@ -1249,6 +1339,8 @@ void ConnectionGraph::split_unique_types(GrowableArray &alloc_worklist)
Node* cur = NULL;
if (mem == NULL || mem->is_top())
continue;
+ // First, update mergemem by moving memory nodes to corresponding slices
+ // if their type became more precise since this mergemem was created.
while (mem->is_Mem()) {
const Type *at = igvn->type(mem->in(MemNode::Address));
if (at != Type::TOP) {
@@ -1267,7 +1359,7 @@ void ConnectionGraph::split_unique_types(GrowableArray &alloc_worklist)
}
nmm->set_memory_at(i, (cur != NULL) ? cur : mem);
// Find any instance of the current type if we haven't encountered
- // a value of the instance along the chain.
+ // already a memory slice of the instance along the memory chain.
for (uint ni = new_index_start; ni < new_index_end; ni++) {
if((uint)_compile->get_general_index(ni) == i) {
Node *m = (ni >= nmm->req()) ? nmm->empty_memory() : nmm->in(ni);
@@ -1283,11 +1375,11 @@ void ConnectionGraph::split_unique_types(GrowableArray &alloc_worklist)
}
// Find the rest of instances values
for (uint ni = new_index_start; ni < new_index_end; ni++) {
- const TypeOopPtr *tinst = igvn->C->get_adr_type(ni)->isa_oopptr();
+ const TypeOopPtr *tinst = _compile->get_adr_type(ni)->isa_oopptr();
Node* result = step_through_mergemem(nmm, ni, tinst);
if (result == nmm->base_memory()) {
// Didn't find instance memory, search through general slice recursively.
- result = nmm->memory_at(igvn->C->get_general_index(ni));
+ result = nmm->memory_at(_compile->get_general_index(ni));
result = find_inst_mem(result, ni, orig_phis, igvn);
if (_compile->failing()) {
return;
@@ -1325,19 +1417,48 @@ void ConnectionGraph::split_unique_types(GrowableArray &alloc_worklist)
}
// Update the memory inputs of MemNodes with the value we computed
- // in Phase 2.
+ // in Phase 2 and move stores memory users to corresponding memory slices.
+#ifdef ASSERT
+ visited.Clear();
+ Node_Stack old_mems(arena, _compile->unique() >> 2);
+#endif
for (uint i = 0; i < nodes_size(); i++) {
Node *nmem = get_map(i);
if (nmem != NULL) {
Node *n = ptnode_adr(i)->_node;
- if (n != NULL && n->is_Mem()) {
+ assert(n != NULL, "sanity");
+ if (n->is_Mem()) {
+#ifdef ASSERT
+ Node* old_mem = n->in(MemNode::Memory);
+ if (!visited.test_set(old_mem->_idx)) {
+ old_mems.push(old_mem, old_mem->outcnt());
+ }
+#endif
+ assert(n->in(MemNode::Memory) != nmem, "sanity");
+ if (!n->is_Load()) {
+ // Move memory users of a store first.
+ move_inst_mem(n, orig_phis, igvn);
+ }
+ // Now update memory input
igvn->hash_delete(n);
n->set_req(MemNode::Memory, nmem);
igvn->hash_insert(n);
record_for_optimizer(n);
+ } else {
+ assert(n->is_Allocate() || n->is_CheckCastPP() ||
+ n->is_AddP() || n->is_Phi(), "unknown node used for set_map()");
}
}
}
+#ifdef ASSERT
+ // Verify that memory was split correctly
+ while (old_mems.is_nonempty()) {
+ Node* old_mem = old_mems.node();
+ uint old_cnt = old_mems.index();
+ old_mems.pop();
+ assert(old_cnt = old_mem->outcnt(), "old mem could be lost");
+ }
+#endif
}
bool ConnectionGraph::has_candidates(Compile *C) {
diff --git a/hotspot/src/share/vm/opto/escape.hpp b/hotspot/src/share/vm/opto/escape.hpp
index 4a5b960fa3e..576043beb45 100644
--- a/hotspot/src/share/vm/opto/escape.hpp
+++ b/hotspot/src/share/vm/opto/escape.hpp
@@ -291,7 +291,7 @@ private:
bool split_AddP(Node *addp, Node *base, PhaseGVN *igvn);
PhiNode *create_split_phi(PhiNode *orig_phi, int alias_idx, GrowableArray &orig_phi_worklist, PhaseGVN *igvn, bool &new_created);
PhiNode *split_memory_phi(PhiNode *orig_phi, int alias_idx, GrowableArray &orig_phi_worklist, PhaseGVN *igvn);
- Node *find_mem(Node *mem, int alias_idx, PhaseGVN *igvn);
+ void move_inst_mem(Node* n, GrowableArray &orig_phis, PhaseGVN *igvn);
Node *find_inst_mem(Node *mem, int alias_idx,GrowableArray &orig_phi_worklist, PhaseGVN *igvn);
// Propagate unique types created for unescaped allocated objects
@@ -300,7 +300,6 @@ private:
// manage entries in _node_map
void set_map(int idx, Node *n) { _node_map.map(idx, n); }
- void set_map_phi(int idx, PhiNode *p) { _node_map.map(idx, (Node *) p); }
Node *get_map(int idx) { return _node_map[idx]; }
PhiNode *get_map_phi(int idx) {
Node *phi = _node_map[idx];
diff --git a/hotspot/test/compiler/6896727/Test.java b/hotspot/test/compiler/6896727/Test.java
new file mode 100644
index 00000000000..a9aef1d2b3d
--- /dev/null
+++ b/hotspot/test/compiler/6896727/Test.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright 2009 Sun Microsystems, 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ *
+ */
+
+/*
+ * @test
+ * @bug 6896727
+ * @summary nsk/logging/LoggingPermission/LoggingPermission/logperm002 fails with G1, EscapeAnalisys w/o COOPs
+ * @run main/othervm -XX:+IgnoreUnrecognizedVMOptions -Xcomp -XX:+DoEscapeAnalysis -XX:+UnlockExperimentalVMOptions -XX:+UseG1GC Test
+ */
+
+public class Test {
+
+ final static String testString = "abracadabra";
+ public static void main(String args[]) {
+ String params[][] = {
+ {"control", testString}
+ };
+ for (int i=0; i
Date: Wed, 9 Dec 2009 21:09:38 -0800
Subject: [PATCH 060/221] 6909082: Docs warning from
java.util.logging.PlatformLoggingMXBean
Fix incorrect tag @See with @see.
Reviewed-by: darcy
---
.../share/classes/java/util/logging/PlatformLoggingMXBean.java | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/jdk/src/share/classes/java/util/logging/PlatformLoggingMXBean.java b/jdk/src/share/classes/java/util/logging/PlatformLoggingMXBean.java
index f994e285bcd..b27339461cb 100644
--- a/jdk/src/share/classes/java/util/logging/PlatformLoggingMXBean.java
+++ b/jdk/src/share/classes/java/util/logging/PlatformLoggingMXBean.java
@@ -51,7 +51,7 @@ import java.lang.management.PlatformManagedObject;
* The {@link PlatformManagedObject#getObjectName} method
* can be used to obtain its {@code ObjectName}.
*
- * @See java.lang.management.PlatformManagedObject
+ * @see java.lang.management.PlatformManagedObject
*
* @author Mandy Chung
* @since 1.7
From 93d5e80a7e3cb778715f0747975c963de6598f73 Mon Sep 17 00:00:00 2001
From: John Cuthbertson
Date: Wed, 9 Dec 2009 23:51:38 -0800
Subject: [PATCH 061/221] 6908215: G1: SEGV with G1PolicyVerbose=2 debug flag
Change CollectionSetChooser::printSortedHeapRegions to handle null entries in _markedRegions growable array.
Reviewed-by: jmasa, tonyp, iveresov
---
.../vm/gc_implementation/g1/collectionSetChooser.cpp | 9 ++++++++-
1 file changed, 8 insertions(+), 1 deletion(-)
diff --git a/hotspot/src/share/vm/gc_implementation/g1/collectionSetChooser.cpp b/hotspot/src/share/vm/gc_implementation/g1/collectionSetChooser.cpp
index 3000f010b17..96760517637 100644
--- a/hotspot/src/share/vm/gc_implementation/g1/collectionSetChooser.cpp
+++ b/hotspot/src/share/vm/gc_implementation/g1/collectionSetChooser.cpp
@@ -351,9 +351,16 @@ void
CollectionSetChooser::printSortedHeapRegions() {
gclog_or_tty->print_cr("Printing %d Heap Regions sorted by amount of known garbage",
_numMarkedRegions);
+
+ DEBUG_ONLY(int marked_count = 0;)
for (int i = 0; i < _markedRegions.length(); i++) {
- printHeapRegion(_markedRegions.at(i));
+ HeapRegion* r = _markedRegions.at(i);
+ if (r != NULL) {
+ printHeapRegion(r);
+ DEBUG_ONLY(marked_count++;)
+ }
}
+ assert(marked_count == _numMarkedRegions, "must be");
gclog_or_tty->print_cr("Done sorted heap region print");
}
From 526f2c6d7fee7ebe53692e11279d9ff5cdac4b14 Mon Sep 17 00:00:00 2001
From: Chris Hegarty
Date: Thu, 10 Dec 2009 15:52:19 +0000
Subject: [PATCH 062/221] 6909089: Memory leak occurs by lack of free for read
buffer in SocketInputStream#read()
Reviewed-by: alanb, jccollet
---
jdk/src/windows/native/java/net/SocketInputStream.c | 3 +++
1 file changed, 3 insertions(+)
diff --git a/jdk/src/windows/native/java/net/SocketInputStream.c b/jdk/src/windows/native/java/net/SocketInputStream.c
index 54c9a8a88fe..bbf6a9ac6fc 100644
--- a/jdk/src/windows/native/java/net/SocketInputStream.c
+++ b/jdk/src/windows/native/java/net/SocketInputStream.c
@@ -121,6 +121,9 @@ Java_java_net_SocketInputStream_socketRead0(JNIEnv *env, jobject this,
newfd = (*env)->GetIntField(env, fdObj, IO_fd_fdID);
if (newfd == -1) {
NET_ThrowSocketException(env, "Socket Closed");
+ if (bufP != BUF) {
+ free(bufP);
+ }
return -1;
}
}
From 317dfd520520459203b192db11593c5439397939 Mon Sep 17 00:00:00 2001
From: Sean Mullan
Date: Thu, 10 Dec 2009 11:31:22 -0500
Subject: [PATCH 063/221] 6867348: Digest Value of References inside Manifest -
calculation order problem
Reviewed-by: xuelei
---
.../dsig/internal/dom/DOMXMLSignature.java | 5 +-
.../xml/crypto/dsig/GenerationTests.java | 56 ++++++++++++++++++-
2 files changed, 58 insertions(+), 3 deletions(-)
diff --git a/jdk/src/share/classes/org/jcp/xml/dsig/internal/dom/DOMXMLSignature.java b/jdk/src/share/classes/org/jcp/xml/dsig/internal/dom/DOMXMLSignature.java
index a758486e0cb..092681bd92d 100644
--- a/jdk/src/share/classes/org/jcp/xml/dsig/internal/dom/DOMXMLSignature.java
+++ b/jdk/src/share/classes/org/jcp/xml/dsig/internal/dom/DOMXMLSignature.java
@@ -326,7 +326,7 @@ public final class DOMXMLSignature extends DOMStructure
}
// generate references and signature value
- List allReferences = new ArrayList(si.getReferences());
+ List allReferences = new ArrayList();
// traverse the Signature and register all objects with IDs that
// may contain References
@@ -356,6 +356,9 @@ public final class DOMXMLSignature extends DOMStructure
}
}
}
+ // always add SignedInfo references after Manifest references so
+ // that Manifest reference are digested first
+ allReferences.addAll(si.getReferences());
// generate/digest each reference
for (int i = 0, size = allReferences.size(); i < size; i++) {
diff --git a/jdk/test/javax/xml/crypto/dsig/GenerationTests.java b/jdk/test/javax/xml/crypto/dsig/GenerationTests.java
index 13881966d32..1ed649cd83a 100644
--- a/jdk/test/javax/xml/crypto/dsig/GenerationTests.java
+++ b/jdk/test/javax/xml/crypto/dsig/GenerationTests.java
@@ -23,7 +23,7 @@
/**
* @test
- * @bug 4635230 6283345 6303830 6824440
+ * @bug 4635230 6283345 6303830 6824440 6867348
* @summary Basic unit tests for generating XML Signatures with JSR 105
* @compile -XDignore.symbol.file KeySelectors.java SignatureValidator.java
* X509KeySelector.java GenerationTests.java
@@ -126,13 +126,14 @@ public class GenerationTests {
test_create_signature_x509_is();
test_create_signature_x509_ski();
test_create_signature_x509_sn();
-// test_create_signature();
+ test_create_signature();
test_create_exc_signature();
test_create_sign_spec();
test_create_signature_enveloping_sha256_dsa();
test_create_signature_enveloping_sha384_rsa_sha256();
test_create_signature_enveloping_sha512_rsa_sha384();
test_create_signature_enveloping_sha512_rsa_sha512();
+ test_create_signature_reference_dependency();
}
private static void setup() throws Exception {
@@ -410,6 +411,55 @@ public class GenerationTests {
System.out.println();
}
+ static void test_create_signature_reference_dependency() throws Exception {
+ System.out.println("* Generating signature-reference-dependency.xml");
+ // create references
+ List refs = Collections.singletonList
+ (fac.newReference("#object-1", sha1));
+
+ // create SignedInfo
+ SignedInfo si = fac.newSignedInfo(withoutComments, rsaSha1, refs);
+
+ // create objects
+ List objs = new ArrayList();
+
+ // Object 1
+ List manRefs = Collections.singletonList
+ (fac.newReference("#object-2", sha1));
+ objs.add(fac.newXMLObject(Collections.singletonList
+ (fac.newManifest(manRefs, "manifest-1")), "object-1", null, null));
+
+ // Object 2
+ Document doc = db.newDocument();
+ Element nc = doc.createElementNS(null, "NonCommentandus");
+ nc.setAttributeNS("http://www.w3.org/2000/xmlns/", "xmlns", "");
+ nc.appendChild(doc.createComment(" Commentandum "));
+ objs.add(fac.newXMLObject(Collections.singletonList
+ (new DOMStructure(nc)), "object-2", null, null));
+
+ // create XMLSignature
+ XMLSignature sig = fac.newXMLSignature(si, rsa, objs, "signature", null);
+ DOMSignContext dsc = new DOMSignContext(getPrivateKey("RSA"), doc);
+
+ sig.sign(dsc);
+
+// dumpDocument(doc, new PrintWriter(System.out));
+
+ DOMValidateContext dvc = new DOMValidateContext
+ (kvks, doc.getDocumentElement());
+ XMLSignature sig2 = fac.unmarshalXMLSignature(dvc);
+
+ if (sig.equals(sig2) == false) {
+ throw new Exception
+ ("Unmarshalled signature is not equal to generated signature");
+ }
+ if (sig2.validate(dvc) == false) {
+ throw new Exception("Validation of generated signature failed");
+ }
+
+ System.out.println();
+ }
+
static void test_create_signature() throws Exception {
System.out.println("* Generating signature.xml");
@@ -645,6 +695,7 @@ public class GenerationTests {
envDoc.getElementsByTagName("YoursSincerely").item(0);
DOMSignContext dsc = new DOMSignContext(signingKey, ys);
+ dsc.setURIDereferencer(httpUd);
sig.sign(dsc);
@@ -660,6 +711,7 @@ public class GenerationTests {
DOMValidateContext dvc = new DOMValidateContext
(new X509KeySelector(ks), sigElement);
+ dvc.setURIDereferencer(httpUd);
File f = new File(
System.getProperty("dir.test.vector.baltimore") +
System.getProperty("file.separator") +
From d4acc8e0fcfc193351378efcd9b4f1d3ea0f0cc8 Mon Sep 17 00:00:00 2001
From: Joe Darcy
Date: Thu, 10 Dec 2009 13:04:13 -0800
Subject: [PATCH 064/221] 6909070: Missing package statements in java.text.Bidi
@see links
Reviewed-by: anthony
---
jdk/src/share/classes/java/text/Bidi.java | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/jdk/src/share/classes/java/text/Bidi.java b/jdk/src/share/classes/java/text/Bidi.java
index e4db4b2d086..504021ff143 100644
--- a/jdk/src/share/classes/java/text/Bidi.java
+++ b/jdk/src/share/classes/java/text/Bidi.java
@@ -121,9 +121,9 @@ public final class Bidi {
*
* @param paragraph a paragraph of text with optional character and paragraph attribute information
*
- * @see TextAttribute#BIDI_EMBEDDING
- * @see TextAttribute#NUMERIC_SHAPING
- * @see TextAttribute#RUN_DIRECTION
+ * @see java.awt.font.TextAttribute#BIDI_EMBEDDING
+ * @see java.awt.font.TextAttribute#NUMERIC_SHAPING
+ * @see java.awt.font.TextAttribute#RUN_DIRECTION
*/
public Bidi(AttributedCharacterIterator paragraph) {
if (paragraph == null) {
From 5d2842c0cf3c8a10ae4c798cc5a914d6448e351e Mon Sep 17 00:00:00 2001
From: Joe Darcy
Date: Thu, 10 Dec 2009 13:28:07 -0800
Subject: [PATCH 065/221] 4891262: API spec, javax/accessibility: few invalid
javadoc tags
Reviewed-by: jjg
---
.../accessibility/AccessibleContext.java | 6 ++---
.../accessibility/AccessibleExtendedText.java | 1 -
.../accessibility/AccessibleKeyBinding.java | 23 ++-----------------
3 files changed, 5 insertions(+), 25 deletions(-)
diff --git a/jdk/src/share/classes/javax/accessibility/AccessibleContext.java b/jdk/src/share/classes/javax/accessibility/AccessibleContext.java
index fbe7e9b1d6f..d4a093f72ec 100644
--- a/jdk/src/share/classes/javax/accessibility/AccessibleContext.java
+++ b/jdk/src/share/classes/javax/accessibility/AccessibleContext.java
@@ -296,7 +296,7 @@ public abstract class AccessibleContext {
*
* @see #getAccessibleText
* @see #addPropertyChangeListener
- * @see #AccessibleText.AccessibleTextSequence
+ * @see AccessibleTextSequence
*/
public static final String ACCESSIBLE_TEXT_PROPERTY
= "AccessibleText";
@@ -311,7 +311,7 @@ public abstract class AccessibleContext {
*
* @see #getAccessibleText
* @see #addPropertyChangeListener
- * @see #AccessibleText.AccessibleTextSequence
+ * @see AccessibleTextSequence
*
* @since 1.5
*/
@@ -334,7 +334,7 @@ public abstract class AccessibleContext {
*
* @see #getAccessibleText
* @see #addPropertyChangeListener
- * @see #AccessibleText.AccessibleAttributeSequence
+ * @see AccessibleAttributeSequence
*
* @since 1.5
*/
diff --git a/jdk/src/share/classes/javax/accessibility/AccessibleExtendedText.java b/jdk/src/share/classes/javax/accessibility/AccessibleExtendedText.java
index 4868ab85e8f..f7a04252136 100644
--- a/jdk/src/share/classes/javax/accessibility/AccessibleExtendedText.java
+++ b/jdk/src/share/classes/javax/accessibility/AccessibleExtendedText.java
@@ -45,7 +45,6 @@ import javax.swing.text.*;
* @see Accessible#getAccessibleContext
* @see AccessibleContext
* @see AccessibleContext#getAccessibleText
- * @see AccessibleText.AccessibleTextChunk
*
* @author Peter Korn
* @author Lynn Monsanto
diff --git a/jdk/src/share/classes/javax/accessibility/AccessibleKeyBinding.java b/jdk/src/share/classes/javax/accessibility/AccessibleKeyBinding.java
index cdf4c493a62..e50e9f54259 100644
--- a/jdk/src/share/classes/javax/accessibility/AccessibleKeyBinding.java
+++ b/jdk/src/share/classes/javax/accessibility/AccessibleKeyBinding.java
@@ -32,16 +32,11 @@ package javax.accessibility;
* the standard mechanism for an assistive technology to determine the
* key bindings which exist for this object.
* Any object that has such key bindings should support this
- * interface. Applications can determine if an object supports the
- * AccessibleKeyBinding interface by first obtaining its AccessibleContext
- * (see @link Accessible} and then calling the
- * {@link AccessibleContext#getAccessibleKeyBinding} method. If the return
- * value is not null, the object supports this interface.
+ * interface.
*
* @see Accessible
* @see Accessible#getAccessibleContext
* @see AccessibleContext
- * @see AccessibleContext#getAccessibleKeyBinding
*
* @author Lynn Monsanto
* @since 1.4
@@ -58,21 +53,7 @@ public interface AccessibleKeyBinding {
/**
* Returns a key binding for this object. The value returned is an
* java.lang.Object which must be cast to appropriate type depending
- * on the underlying implementation of the key. For example, if the
- * Object returned is a javax.swing.KeyStroke, the user of this
- * method should do the following:
- *
- * Component c =
- * AccessibleContext ac = c.getAccessibleContext();
- * AccessibleKeyBinding akb = ac.getAccessibleKeyBinding();
- * for (int i = 0; i < akb.getAccessibleKeyBindingCount(); i++) {
- * Object o = akb.getAccessibleKeyBinding(i);
- * if (o instanceof javax.swing.KeyStroke) {
- * javax.swing.KeyStroke keyStroke = (javax.swing.KeyStroke)o;
- *
- * }
- * }
- *
+ * on the underlying implementation of the key.
*
* @param i zero-based index of the key bindings
* @return a javax.lang.Object which specifies the key binding
From d4f1ac859c4de3a985ab6dffce991ceb7ab414bd Mon Sep 17 00:00:00 2001
From: Yong Jeffrey Huang
Date: Thu, 10 Dec 2009 17:26:47 -0800
Subject: [PATCH 066/221] 6873931: New Turkish currency since 2009
Reviewed-by: yhuang, peytoia
---
.../classes/sun/util/resources/CurrencyNames_tr_TR.properties | 2 +-
jdk/test/sun/text/resources/LocaleData | 3 +++
jdk/test/sun/text/resources/LocaleDataTest.java | 2 +-
3 files changed, 5 insertions(+), 2 deletions(-)
diff --git a/jdk/src/share/classes/sun/util/resources/CurrencyNames_tr_TR.properties b/jdk/src/share/classes/sun/util/resources/CurrencyNames_tr_TR.properties
index 4f9c764c5d2..51ed4758556 100644
--- a/jdk/src/share/classes/sun/util/resources/CurrencyNames_tr_TR.properties
+++ b/jdk/src/share/classes/sun/util/resources/CurrencyNames_tr_TR.properties
@@ -36,4 +36,4 @@
# Taligent is a registered trademark of Taligent, Inc.
TRL=TL
-TRY=YTL
+TRY=TL
diff --git a/jdk/test/sun/text/resources/LocaleData b/jdk/test/sun/text/resources/LocaleData
index 0a6cde5918a..5ee8525827d 100644
--- a/jdk/test/sun/text/resources/LocaleData
+++ b/jdk/test/sun/text/resources/LocaleData
@@ -5549,3 +5549,6 @@ TimeZoneNames/zh_TW/Asia\/Taipei/2=TST
# bug 6645271
FormatData/hr_HR/DateTimePatterns/6=dd.MM.yyyy.
FormatData/hr_HR/DateTimePatterns/7=dd.MM.yy.
+
+# bug 6873931
+CurrencyNames/tr_TR/TRY=TL
diff --git a/jdk/test/sun/text/resources/LocaleDataTest.java b/jdk/test/sun/text/resources/LocaleDataTest.java
index ce57c76bd69..9171133401b 100644
--- a/jdk/test/sun/text/resources/LocaleDataTest.java
+++ b/jdk/test/sun/text/resources/LocaleDataTest.java
@@ -31,7 +31,7 @@
* 5102005 5074431 6182685 6208712 6277020 6245766 6351682 6386647 6379382
* 6414459 6455680 6498742 6558863 6488119 6547501 6497154 6558856 6481177
* 6379214 6485516 6486607 4225362 4494727 6533691 6531591 6531593 6570259
- * 6509039 6609737 6610748 6645271 6507067
+ * 6509039 6609737 6610748 6645271 6507067 6873931
* @summary Verify locale data
*
*/
From 82e58a7b133e6fdfe50c79dfb810781e7da5d18e Mon Sep 17 00:00:00 2001
From: Joe Darcy
Date: Thu, 10 Dec 2009 20:35:31 -0800
Subject: [PATCH 067/221] 6909538: Clarify meaning of "element" in
javax.lang.model.element API
Reviewed-by: ahe
---
.../classes/javax/lang/model/element/package-info.java | 10 ++++++++++
1 file changed, 10 insertions(+)
diff --git a/langtools/src/share/classes/javax/lang/model/element/package-info.java b/langtools/src/share/classes/javax/lang/model/element/package-info.java
index 26ea184c432..7729f505578 100644
--- a/langtools/src/share/classes/javax/lang/model/element/package-info.java
+++ b/langtools/src/share/classes/javax/lang/model/element/package-info.java
@@ -26,6 +26,16 @@
/**
* Interfaces used to model elements of the Java programming language.
*
+ * The term "element" in this package is used to refer to program
+ * elements, the declared entities that make up a program. Elements
+ * include classes, interfaces, methods, constructors, and fields.
+ * The interfaces in this package do not model the structure of a
+ * program inside a method body; for example there is no
+ * representation of a {@code for} loop or {@code try}-{@code finally}
+ * block. However, the interfaces can model some structures only
+ * appearing inside method bodies, such as local variables and
+ * anonymous classes.
+ *
*
When used in the context of annotation processing, an accurate
* model of the element being represented must be returned. As this
* is a language model, the source code provides the fiducial
From 7f5baa6fe830b7622eeda16ddab41cbcf18415b3 Mon Sep 17 00:00:00 2001
From: Joe Darcy
Date: Fri, 11 Dec 2009 10:40:14 -0800
Subject: [PATCH 068/221] 6909563: Javadoc build warnings in rmi, security,
management
Reviewed-by: mchung, mullan
---
.../classes/java/lang/management/PlatformManagedObject.java | 2 +-
jdk/src/share/classes/java/rmi/activation/Activatable.java | 6 +++---
jdk/src/share/classes/java/rmi/registry/LocateRegistry.java | 4 ++--
.../java/rmi/server/RemoteObjectInvocationHandler.java | 1 -
.../java/security/cert/CertPathValidatorException.java | 2 +-
5 files changed, 7 insertions(+), 8 deletions(-)
diff --git a/jdk/src/share/classes/java/lang/management/PlatformManagedObject.java b/jdk/src/share/classes/java/lang/management/PlatformManagedObject.java
index 5f68635d4fe..ca5edbeb518 100644
--- a/jdk/src/share/classes/java/lang/management/PlatformManagedObject.java
+++ b/jdk/src/share/classes/java/lang/management/PlatformManagedObject.java
@@ -32,7 +32,7 @@ import javax.management.ObjectName;
* for monitoring and managing a component in the Java platform.
* Each platform managed object has a unique
* object name
- * for the {@linkplain ManagementFactory.getPlatformMBeanServer
+ * for the {@linkplain ManagementFactory#getPlatformMBeanServer
* platform MBeanServer} access.
* All platform MXBeans will implement this interface.
*
diff --git a/jdk/src/share/classes/java/rmi/activation/Activatable.java b/jdk/src/share/classes/java/rmi/activation/Activatable.java
index 07879812774..de02b0d6e31 100644
--- a/jdk/src/share/classes/java/rmi/activation/Activatable.java
+++ b/jdk/src/share/classes/java/rmi/activation/Activatable.java
@@ -73,7 +73,7 @@ public abstract class Activatable extends RemoteServer {
* can be handled properly.
*
*
This method invokes the {@link
- * exportObject(Remote,String,MarshalledObject,boolean,port)
+ * #exportObject(Remote,String,MarshalledObject,boolean,int)
* exportObject} method with this object, and the specified location,
* data, restart mode, and port. Subsequent calls to {@link #getID}
* will return the activation identifier returned from the call to
@@ -120,7 +120,7 @@ public abstract class Activatable extends RemoteServer {
* can be handled properly.
*
*
This method invokes the {@link
- * exportObject(Remote,String,MarshalledObject,boolean,port,RMIClientSocketFactory,RMIServerSocketFactory)
+ * #exportObject(Remote,String,MarshalledObject,boolean,int,RMIClientSocketFactory,RMIServerSocketFactory)
* exportObject} method with this object, and the specified location,
* data, restart mode, port, and client and server socket factories.
* Subsequent calls to {@link #getID} will return the activation
@@ -312,7 +312,7 @@ public abstract class Activatable extends RemoteServer {
* separately, so that exceptions can be handled properly.
*
*
This method invokes the {@link
- * exportObject(Remote,String,MarshalledObject,boolean,port,RMIClientSocketFactory,RMIServerSocketFactory)
+ * #exportObject(Remote,String,MarshalledObject,boolean,int,RMIClientSocketFactory,RMIServerSocketFactory)
* exportObject} method with the specified object, location, data,
* restart mode, and port, and null for both client and
* server socket factories, and then returns the resulting activation
diff --git a/jdk/src/share/classes/java/rmi/registry/LocateRegistry.java b/jdk/src/share/classes/java/rmi/registry/LocateRegistry.java
index d32e4035749..b65feca8c80 100644
--- a/jdk/src/share/classes/java/rmi/registry/LocateRegistry.java
+++ b/jdk/src/share/classes/java/rmi/registry/LocateRegistry.java
@@ -187,7 +187,7 @@ public final class LocateRegistry {
* host that accepts requests on the specified port.
*
*
The Registry instance is exported as if the static
- * {@link UnicastRemoteObject.exportObject(Remote,int)
+ * {@link UnicastRemoteObject#exportObject(Remote,int)
* UnicastRemoteObject.exportObject} method is invoked, passing the
* Registry instance and the specified port as
* arguments, except that the Registry instance is
@@ -213,7 +213,7 @@ public final class LocateRegistry {
*
*
The Registry instance is exported as if
* the static {@link
- * UnicastRemoteObject.exportObject(Remote,int,RMIClientSocketFactory,RMIServerSocketFactory)
+ * UnicastRemoteObject#exportObject(Remote,int,RMIClientSocketFactory,RMIServerSocketFactory)
* UnicastRemoteObject.exportObject} method is invoked, passing the
* Registry instance, the specified port, the
* specified RMIClientSocketFactory, and the specified
diff --git a/jdk/src/share/classes/java/rmi/server/RemoteObjectInvocationHandler.java b/jdk/src/share/classes/java/rmi/server/RemoteObjectInvocationHandler.java
index 59de6cfad02..06647bac951 100644
--- a/jdk/src/share/classes/java/rmi/server/RemoteObjectInvocationHandler.java
+++ b/jdk/src/share/classes/java/rmi/server/RemoteObjectInvocationHandler.java
@@ -138,7 +138,6 @@ public class RemoteObjectInvocationHandler
* instance
* @throws Throwable the exception to throw from the method invocation
* on the proxy instance
- * @see
**/
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable
diff --git a/jdk/src/share/classes/java/security/cert/CertPathValidatorException.java b/jdk/src/share/classes/java/security/cert/CertPathValidatorException.java
index c1ca1d2b8de..86b0b45e276 100644
--- a/jdk/src/share/classes/java/security/cert/CertPathValidatorException.java
+++ b/jdk/src/share/classes/java/security/cert/CertPathValidatorException.java
@@ -216,7 +216,7 @@ public class CertPathValidatorException extends GeneralSecurityException {
/**
* Returns the reason that the validation failed. The reason is
* associated with the index of the certificate returned by
- * {@link getIndex}.
+ * {@link #getIndex}.
*
* @return the reason that the validation failed, or
* BasicReason.UNSPECIFIED if a reason has not been
From 4f656a451eb20d743f73c0d37a63e63e9ca24c40 Mon Sep 17 00:00:00 2001
From: Yumin Qi
Date: Fri, 11 Dec 2009 11:09:49 -0800
Subject: [PATCH 069/221] 6361589: Print out stack trace for target thread of
GC crash
If GC crashed with java thread involved, print out the java stack trace in error report
Reviewed-by: never, ysr, coleenp, dholmes
---
hotspot/src/share/vm/runtime/frame.cpp | 16 ++++++++++++---
hotspot/src/share/vm/runtime/globals.hpp | 3 +++
hotspot/src/share/vm/runtime/thread.cpp | 24 ++++++++++++++++++++++
hotspot/src/share/vm/runtime/thread.hpp | 14 ++++++++++++-
hotspot/src/share/vm/runtime/vmStructs.cpp | 1 +
hotspot/src/share/vm/runtime/vmThread.cpp | 4 ++--
hotspot/src/share/vm/runtime/vmThread.hpp | 4 +---
hotspot/src/share/vm/utilities/vmError.cpp | 17 +++++++++++++++
8 files changed, 74 insertions(+), 9 deletions(-)
diff --git a/hotspot/src/share/vm/runtime/frame.cpp b/hotspot/src/share/vm/runtime/frame.cpp
index 4ce96408ce4..6f87873bfd4 100644
--- a/hotspot/src/share/vm/runtime/frame.cpp
+++ b/hotspot/src/share/vm/runtime/frame.cpp
@@ -1190,9 +1190,19 @@ void frame::oops_entry_do(OopClosure* f, const RegisterMap* map) {
void frame::oops_do_internal(OopClosure* f, CodeBlobClosure* cf, RegisterMap* map, bool use_interpreter_oop_map_cache) {
- if (is_interpreted_frame()) { oops_interpreted_do(f, map, use_interpreter_oop_map_cache);
- } else if (is_entry_frame()) { oops_entry_do (f, map);
- } else if (CodeCache::contains(pc())) { oops_code_blob_do (f, cf, map);
+#ifndef PRODUCT
+ // simulate GC crash here to dump java thread in error report
+ if (CrashGCForDumpingJavaThread) {
+ char *t = NULL;
+ *t = 'c';
+ }
+#endif
+ if (is_interpreted_frame()) {
+ oops_interpreted_do(f, map, use_interpreter_oop_map_cache);
+ } else if (is_entry_frame()) {
+ oops_entry_do(f, map);
+ } else if (CodeCache::contains(pc())) {
+ oops_code_blob_do(f, cf, map);
} else {
ShouldNotReachHere();
}
diff --git a/hotspot/src/share/vm/runtime/globals.hpp b/hotspot/src/share/vm/runtime/globals.hpp
index b894aac439e..62dceadc215 100644
--- a/hotspot/src/share/vm/runtime/globals.hpp
+++ b/hotspot/src/share/vm/runtime/globals.hpp
@@ -2554,6 +2554,9 @@ class CommandLineFlags {
"Include miscellaneous runtime verifications in nmethod code; " \
"default off because it disturbs nmethod size heuristics") \
\
+ notproduct(bool, CrashGCForDumpingJavaThread, false, \
+ "Manually make GC thread crash then dump java stack trace; " \
+ "Test only") \
\
/* compilation */ \
product(bool, UseCompiler, true, \
diff --git a/hotspot/src/share/vm/runtime/thread.cpp b/hotspot/src/share/vm/runtime/thread.cpp
index 5b2b90dedcb..858c09f0480 100644
--- a/hotspot/src/share/vm/runtime/thread.cpp
+++ b/hotspot/src/share/vm/runtime/thread.cpp
@@ -991,6 +991,7 @@ void JavaThread::allocate_threadObj(Handle thread_group, char* thread_name, bool
// uniquely named instances should derive from this.
NamedThread::NamedThread() : Thread() {
_name = NULL;
+ _processed_thread = NULL;
}
NamedThread::~NamedThread() {
@@ -2333,6 +2334,27 @@ void JavaThread::gc_prologue() {
frames_do(frame_gc_prologue);
}
+// If the caller is a NamedThread, then remember, in the current scope,
+// the given JavaThread in its _processed_thread field.
+class RememberProcessedThread: public StackObj {
+ NamedThread* _cur_thr;
+public:
+ RememberProcessedThread(JavaThread* jthr) {
+ Thread* thread = Thread::current();
+ if (thread->is_Named_thread()) {
+ _cur_thr = (NamedThread *)thread;
+ _cur_thr->set_processed_thread(jthr);
+ } else {
+ _cur_thr = NULL;
+ }
+ }
+
+ ~RememberProcessedThread() {
+ if (_cur_thr) {
+ _cur_thr->set_processed_thread(NULL);
+ }
+ }
+};
void JavaThread::oops_do(OopClosure* f, CodeBlobClosure* cf) {
// Flush deferred store-barriers, if any, associated with
@@ -2349,6 +2371,8 @@ void JavaThread::oops_do(OopClosure* f, CodeBlobClosure* cf) {
(has_last_Java_frame() && java_call_counter() > 0), "wrong java_sp info!");
if (has_last_Java_frame()) {
+ // Record JavaThread to GC thread
+ RememberProcessedThread rpt(this);
// Traverse the privileged stack
if (_privileged_stack_top != NULL) {
diff --git a/hotspot/src/share/vm/runtime/thread.hpp b/hotspot/src/share/vm/runtime/thread.hpp
index cb4d6168a82..e0ea0be5588 100644
--- a/hotspot/src/share/vm/runtime/thread.hpp
+++ b/hotspot/src/share/vm/runtime/thread.hpp
@@ -48,7 +48,12 @@ class IdealGraphPrinter;
// Class hierarchy
// - Thread
-// - VMThread
+// - NamedThread
+// - VMThread
+// - ConcurrentGCThread
+// - WorkerThread
+// - GangWorker
+// - GCTaskThread
// - JavaThread
// - WatcherThread
@@ -249,6 +254,7 @@ class Thread: public ThreadShadow {
virtual bool is_GC_task_thread() const { return false; }
virtual bool is_Watcher_thread() const { return false; }
virtual bool is_ConcurrentGC_thread() const { return false; }
+ virtual bool is_Named_thread() const { return false; }
virtual char* name() const { return (char*)"Unknown thread"; }
@@ -568,12 +574,18 @@ class NamedThread: public Thread {
};
private:
char* _name;
+ // log JavaThread being processed by oops_do
+ JavaThread* _processed_thread;
+
public:
NamedThread();
~NamedThread();
// May only be called once per thread.
void set_name(const char* format, ...);
+ virtual bool is_Named_thread() const { return true; }
virtual char* name() const { return _name == NULL ? (char*)"Unknown Thread" : _name; }
+ JavaThread *processed_thread() { return _processed_thread; }
+ void set_processed_thread(JavaThread *thread) { _processed_thread = thread; }
};
// Worker threads are named and have an id of an assigned work.
diff --git a/hotspot/src/share/vm/runtime/vmStructs.cpp b/hotspot/src/share/vm/runtime/vmStructs.cpp
index bbff61b478b..3e21d0d4b05 100644
--- a/hotspot/src/share/vm/runtime/vmStructs.cpp
+++ b/hotspot/src/share/vm/runtime/vmStructs.cpp
@@ -666,6 +666,7 @@ static inline uint64_t cast_uint64_t(size_t x)
nonstatic_field(Thread, _current_pending_monitor_is_from_java, bool) \
nonstatic_field(Thread, _current_waiting_monitor, ObjectMonitor*) \
nonstatic_field(NamedThread, _name, char*) \
+ nonstatic_field(NamedThread, _processed_thread, JavaThread*) \
nonstatic_field(JavaThread, _next, JavaThread*) \
nonstatic_field(JavaThread, _threadObj, oop) \
nonstatic_field(JavaThread, _anchor, JavaFrameAnchor) \
diff --git a/hotspot/src/share/vm/runtime/vmThread.cpp b/hotspot/src/share/vm/runtime/vmThread.cpp
index b54f625158e..26dad9a689c 100644
--- a/hotspot/src/share/vm/runtime/vmThread.cpp
+++ b/hotspot/src/share/vm/runtime/vmThread.cpp
@@ -204,8 +204,8 @@ void VMThread::create() {
}
-VMThread::VMThread() : Thread() {
- // nothing to do
+VMThread::VMThread() : NamedThread() {
+ set_name("VM Thread");
}
void VMThread::destroy() {
diff --git a/hotspot/src/share/vm/runtime/vmThread.hpp b/hotspot/src/share/vm/runtime/vmThread.hpp
index 7acf84a70c7..daa705138ae 100644
--- a/hotspot/src/share/vm/runtime/vmThread.hpp
+++ b/hotspot/src/share/vm/runtime/vmThread.hpp
@@ -83,7 +83,7 @@ class VMOperationQueue : public CHeapObj {
// like scavenge, garbage_collect etc.
//
-class VMThread: public Thread {
+class VMThread: public NamedThread {
private:
static ThreadPriority _current_priority;
@@ -101,8 +101,6 @@ class VMThread: public Thread {
bool is_VM_thread() const { return true; }
bool is_GC_thread() const { return true; }
- char* name() const { return (char*)"VM Thread"; }
-
// The ever running loop for the VMThread
void loop();
diff --git a/hotspot/src/share/vm/utilities/vmError.cpp b/hotspot/src/share/vm/utilities/vmError.cpp
index 2a2ddf83ab1..b758d8e9fa5 100644
--- a/hotspot/src/share/vm/utilities/vmError.cpp
+++ b/hotspot/src/share/vm/utilities/vmError.cpp
@@ -502,6 +502,23 @@ void VMError::report(outputStream* st) {
#endif // ZERO
}
+ STEP(135, "(printing target Java thread stack)" )
+
+ // printing Java thread stack trace if it is involved in GC crash
+ if (_verbose && (_thread->is_Named_thread())) {
+ JavaThread* jt = ((NamedThread *)_thread)->processed_thread();
+ if (jt != NULL) {
+ st->print_cr("JavaThread " PTR_FORMAT " (nid = " UINTX_FORMAT ") was being processed", jt, jt->osthread()->thread_id());
+ if (jt->has_last_Java_frame()) {
+ st->print_cr("Java frames: (J=compiled Java code, j=interpreted, Vv=VM code)");
+ for(StackFrameStream sfs(jt); !sfs.is_done(); sfs.next()) {
+ sfs.current()->print_on_error(st, buf, sizeof(buf), true);
+ st->cr();
+ }
+ }
+ }
+ }
+
STEP(140, "(printing VM operation)" )
if (_verbose && _thread && _thread->is_VM_thread()) {
From 75f1feee86b80ef4ffa2b69340129072d1158c6d Mon Sep 17 00:00:00 2001
From: Jonathan Gibbons
Date: Fri, 11 Dec 2009 14:26:27 -0800
Subject: [PATCH 070/221] 6906175: bridge JSR199 and JSR 203 APIs
Reviewed-by: darcy, alanb
---
langtools/make/build.properties | 19 +-
langtools/make/build.xml | 6 +-
.../sun/tools/javac/file/BaseFileObject.java | 11 +-
.../tools/javac/file/JavacFileManager.java | 302 +---------
.../com/sun/tools/javac/file/Paths.java | 2 +-
.../tools/javac/nio/JavacPathFileManager.java | 543 ++++++++++++++++++
.../sun/tools/javac/nio/PathFileManager.java | 125 ++++
.../sun/tools/javac/nio/PathFileObject.java | 319 ++++++++++
.../sun/tools/javac/util/BaseFileManager.java | 355 ++++++++++++
.../CloseableURLClassLoader.java | 7 +-
.../javax/tools/StandardJavaFileManager.java | 1 -
.../javac/nio/compileTest/CompileTest.java | 165 ++++++
.../javac/nio/compileTest/HelloPathWorld.java | 28 +
13 files changed, 1570 insertions(+), 313 deletions(-)
create mode 100644 langtools/src/share/classes/com/sun/tools/javac/nio/JavacPathFileManager.java
create mode 100644 langtools/src/share/classes/com/sun/tools/javac/nio/PathFileManager.java
create mode 100644 langtools/src/share/classes/com/sun/tools/javac/nio/PathFileObject.java
create mode 100644 langtools/src/share/classes/com/sun/tools/javac/util/BaseFileManager.java
rename langtools/src/share/classes/com/sun/tools/javac/{file => util}/CloseableURLClassLoader.java (96%)
create mode 100644 langtools/test/tools/javac/nio/compileTest/CompileTest.java
create mode 100644 langtools/test/tools/javac/nio/compileTest/HelloPathWorld.java
diff --git a/langtools/make/build.properties b/langtools/make/build.properties
index da7a65a6561..75dc6c97b32 100644
--- a/langtools/make/build.properties
+++ b/langtools/make/build.properties
@@ -149,11 +149,26 @@ apt.tests = \
#
# The following files require the import JDK to be available
-require.import.jdk.files =
+require.import.jdk.files = \
+ com/sun/tools/javac/nio/*.java
# The following files in the import jdk source directory are required
# in order to compile the files defined in ${require.import.jdk.files}
-import.jdk.stub.files =
+#
+# For NIO, the list of stub files is defined by the contents of the primary
+# API packages, together with such types that may be required in order to
+# compile the stubs. Some of these dependencies would go away if the stub
+# generator were to be improved -- e.g. by removing unnecessary imports.
+#
+import.jdk.stub.files = \
+ java/io/File.java \
+ java/nio/file/**.java \
+ java/nio/file/attribute/**.java \
+ java/nio/file/spi/**.java \
+ java/nio/channels/AsynchronousChannel.java \
+ java/nio/channels/AsynchronousFileChannel.java \
+ java/nio/channels/CompletionHandler.java \
+ java/nio/channels/SeekableByteChannel.java
# The following value is used by the main jtreg target.
# An empty value means all tests
diff --git a/langtools/make/build.xml b/langtools/make/build.xml
index fc6e0f41f1f..7081f4dff6d 100644
--- a/langtools/make/build.xml
+++ b/langtools/make/build.xml
@@ -98,7 +98,7 @@
import.jdk should be unset, or set to jdk home (to use rt.jar)
or to jdk repo (to use src/share/classes).
Based on the value, if any, set up default values for javac's sourcepath,
- classpath and bootclasspath. Note: the default values are overridden
+ classpath and bootclasspath. Note: the default values are overridden
in the build-bootstrap-classes macro. -->
-
-
+
+
diff --git a/langtools/src/share/classes/com/sun/tools/javac/file/BaseFileObject.java b/langtools/src/share/classes/com/sun/tools/javac/file/BaseFileObject.java
index 6435e05a04c..9666f1cee7e 100644
--- a/langtools/src/share/classes/com/sun/tools/javac/file/BaseFileObject.java
+++ b/langtools/src/share/classes/com/sun/tools/javac/file/BaseFileObject.java
@@ -39,6 +39,8 @@ import javax.tools.JavaFileObject;
import static javax.tools.JavaFileObject.Kind.*;
+import com.sun.tools.javac.util.BaseFileManager;
+
/**
*
This is NOT part of any API supported by Sun Microsystems.
* If you write code that depends on this, you do so at your own risk.
@@ -74,14 +76,7 @@ public abstract class BaseFileObject implements JavaFileObject {
protected abstract String inferBinaryName(Iterable extends File> path);
protected static JavaFileObject.Kind getKind(String filename) {
- if (filename.endsWith(CLASS.extension))
- return CLASS;
- else if (filename.endsWith(SOURCE.extension))
- return SOURCE;
- else if (filename.endsWith(HTML.extension))
- return HTML;
- else
- return OTHER;
+ return BaseFileManager.getKind(filename);
}
protected static String removeExtension(String fileName) {
diff --git a/langtools/src/share/classes/com/sun/tools/javac/file/JavacFileManager.java b/langtools/src/share/classes/com/sun/tools/javac/file/JavacFileManager.java
index 23f169b5392..661f89eb717 100644
--- a/langtools/src/share/classes/com/sun/tools/javac/file/JavacFileManager.java
+++ b/langtools/src/share/classes/com/sun/tools/javac/file/JavacFileManager.java
@@ -26,29 +26,16 @@
package com.sun.tools.javac.file;
import java.io.ByteArrayOutputStream;
-import java.io.Closeable;
import java.io.File;
-import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
-import java.io.InputStream;
import java.io.OutputStreamWriter;
-import java.lang.ref.SoftReference;
-import java.lang.reflect.Constructor;
import java.net.MalformedURLException;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
-import java.net.URLClassLoader;
-import java.nio.ByteBuffer;
import java.nio.CharBuffer;
-import java.nio.channels.FileChannel;
import java.nio.charset.Charset;
-import java.nio.charset.CharsetDecoder;
-import java.nio.charset.CoderResult;
-import java.nio.charset.CodingErrorAction;
-import java.nio.charset.IllegalCharsetNameException;
-import java.nio.charset.UnsupportedCharsetException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
@@ -66,18 +53,13 @@ import javax.tools.JavaFileManager;
import javax.tools.JavaFileObject;
import javax.tools.StandardJavaFileManager;
-import com.sun.tools.javac.code.Source;
import com.sun.tools.javac.file.RelativePath.RelativeFile;
import com.sun.tools.javac.file.RelativePath.RelativeDirectory;
-import com.sun.tools.javac.main.JavacOption;
import com.sun.tools.javac.main.OptionName;
-import com.sun.tools.javac.main.RecognizedOptions;
+import com.sun.tools.javac.util.BaseFileManager;
import com.sun.tools.javac.util.Context;
-import com.sun.tools.javac.util.JCDiagnostic.SimpleDiagnosticPosition;
import com.sun.tools.javac.util.List;
import com.sun.tools.javac.util.ListBuffer;
-import com.sun.tools.javac.util.Log;
-import com.sun.tools.javac.util.Options;
import static javax.tools.StandardLocation.*;
import static com.sun.tools.javac.main.OptionName.*;
@@ -91,7 +73,7 @@ import static com.sun.tools.javac.main.OptionName.*;
* This code and its internal interfaces are subject to change or
* deletion without notice.
*/
-public class JavacFileManager implements StandardJavaFileManager {
+public class JavacFileManager extends BaseFileManager implements StandardJavaFileManager {
boolean useZipFileIndex;
@@ -102,17 +84,10 @@ public class JavacFileManager implements StandardJavaFileManager {
return buffer.toString().toCharArray();
}
- /**
- * The log to be used for error reporting.
- */
- protected Log log;
-
/** Encapsulates knowledge of paths
*/
private Paths paths;
- private Options options;
-
private FSInfo fsInfo;
private final File uninited = new File("U N I N I T E D");
@@ -134,12 +109,6 @@ public class JavacFileManager implements StandardJavaFileManager {
protected boolean mmappedIO;
protected boolean ignoreSymbolFile;
- protected String classLoaderClass;
-
- /**
- * User provided charset (through javax.tools).
- */
- protected Charset charset;
/**
* Register a Context.Factory to create a JavacFileManager.
@@ -157,18 +126,18 @@ public class JavacFileManager implements StandardJavaFileManager {
* it as the JavaFileManager for that context.
*/
public JavacFileManager(Context context, boolean register, Charset charset) {
+ super(charset);
if (register)
context.put(JavaFileManager.class, this);
- byteBufferCache = new ByteBufferCache();
- this.charset = charset;
setContext(context);
}
/**
* Set the context for JavacFileManager.
*/
+ @Override
public void setContext(Context context) {
- log = Log.instance(context);
+ super.setContext(context);
if (paths == null) {
paths = Paths.instance(context);
} else {
@@ -177,14 +146,12 @@ public class JavacFileManager implements StandardJavaFileManager {
paths.setContext(context);
}
- options = Options.instance(context);
fsInfo = FSInfo.instance(context);
useZipFileIndex = System.getProperty("useJavaUtilZip") == null;// TODO: options.get("useJavaUtilZip") == null;
mmappedIO = options.get("mmappedIO") != null;
ignoreSymbolFile = options.get("ignore.symbol.file") != null;
- classLoaderClass = options.get("procloader");
}
public JavaFileObject getFileForInput(String name) {
@@ -214,17 +181,6 @@ public class JavacFileManager implements StandardJavaFileManager {
return getJavaFileObjectsFromStrings(Arrays.asList(nullCheck(names)));
}
- protected JavaFileObject.Kind getKind(String extension) {
- if (extension.equals(JavaFileObject.Kind.CLASS.extension))
- return JavaFileObject.Kind.CLASS;
- else if (extension.equals(JavaFileObject.Kind.SOURCE.extension))
- return JavaFileObject.Kind.SOURCE;
- else if (extension.equals(JavaFileObject.Kind.HTML.extension))
- return JavaFileObject.Kind.HTML;
- else
- return JavaFileObject.Kind.OTHER;
- }
-
private static boolean isValidName(String name) {
// Arguably, isValidName should reject keywords (such as in SourceVersion.isName() ),
// but the set of keywords depends on the source level, and we don't want
@@ -359,9 +315,7 @@ public class JavacFileManager implements StandardJavaFileManager {
}
private boolean isValidFile(String s, Set fileKinds) {
- int lastDot = s.lastIndexOf(".");
- String extn = (lastDot == -1 ? s : s.substring(lastDot));
- JavaFileObject.Kind kind = getKind(extn);
+ JavaFileObject.Kind kind = getKind(s);
return fileKinds.contains(kind);
}
@@ -564,18 +518,6 @@ public class JavacFileManager implements StandardJavaFileManager {
}
}
- CharBuffer getCachedContent(JavaFileObject file) {
- SoftReference r = contentCache.get(file);
- return (r == null ? null : r.get());
- }
-
- void cache(JavaFileObject file, CharBuffer cb) {
- contentCache.put(file, new SoftReference(cb));
- }
-
- private final Map> contentCache
- = new HashMap>();
-
private String defaultEncodingName;
private String getDefaultEncodingName() {
if (defaultEncodingName == null) {
@@ -585,161 +527,6 @@ public class JavacFileManager implements StandardJavaFileManager {
return defaultEncodingName;
}
- protected String getEncodingName() {
- String encName = options.get(OptionName.ENCODING);
- if (encName == null)
- return getDefaultEncodingName();
- else
- return encName;
- }
-
- protected Source getSource() {
- String sourceName = options.get(OptionName.SOURCE);
- Source source = null;
- if (sourceName != null)
- source = Source.lookup(sourceName);
- return (source != null ? source : Source.DEFAULT);
- }
-
- /**
- * Make a byte buffer from an input stream.
- */
- ByteBuffer makeByteBuffer(InputStream in)
- throws IOException {
- int limit = in.available();
- if (mmappedIO && in instanceof FileInputStream) {
- // Experimental memory mapped I/O
- FileInputStream fin = (FileInputStream)in;
- return fin.getChannel().map(FileChannel.MapMode.READ_ONLY, 0, limit);
- }
- if (limit < 1024) limit = 1024;
- ByteBuffer result = byteBufferCache.get(limit);
- int position = 0;
- while (in.available() != 0) {
- if (position >= limit)
- // expand buffer
- result = ByteBuffer.
- allocate(limit <<= 1).
- put((ByteBuffer)result.flip());
- int count = in.read(result.array(),
- position,
- limit - position);
- if (count < 0) break;
- result.position(position += count);
- }
- return (ByteBuffer)result.flip();
- }
-
- void recycleByteBuffer(ByteBuffer bb) {
- byteBufferCache.put(bb);
- }
-
- /**
- * A single-element cache of direct byte buffers.
- */
- private static class ByteBufferCache {
- private ByteBuffer cached;
- ByteBuffer get(int capacity) {
- if (capacity < 20480) capacity = 20480;
- ByteBuffer result =
- (cached != null && cached.capacity() >= capacity)
- ? (ByteBuffer)cached.clear()
- : ByteBuffer.allocate(capacity + capacity>>1);
- cached = null;
- return result;
- }
- void put(ByteBuffer x) {
- cached = x;
- }
- }
-
- private final ByteBufferCache byteBufferCache;
-
- CharsetDecoder getDecoder(String encodingName, boolean ignoreEncodingErrors) {
- Charset cs = (this.charset == null)
- ? Charset.forName(encodingName)
- : this.charset;
- CharsetDecoder decoder = cs.newDecoder();
-
- CodingErrorAction action;
- if (ignoreEncodingErrors)
- action = CodingErrorAction.REPLACE;
- else
- action = CodingErrorAction.REPORT;
-
- return decoder
- .onMalformedInput(action)
- .onUnmappableCharacter(action);
- }
-
- /**
- * Decode a ByteBuffer into a CharBuffer.
- */
- CharBuffer decode(ByteBuffer inbuf, boolean ignoreEncodingErrors) {
- String encodingName = getEncodingName();
- CharsetDecoder decoder;
- try {
- decoder = getDecoder(encodingName, ignoreEncodingErrors);
- } catch (IllegalCharsetNameException e) {
- log.error("unsupported.encoding", encodingName);
- return (CharBuffer)CharBuffer.allocate(1).flip();
- } catch (UnsupportedCharsetException e) {
- log.error("unsupported.encoding", encodingName);
- return (CharBuffer)CharBuffer.allocate(1).flip();
- }
-
- // slightly overestimate the buffer size to avoid reallocation.
- float factor =
- decoder.averageCharsPerByte() * 0.8f +
- decoder.maxCharsPerByte() * 0.2f;
- CharBuffer dest = CharBuffer.
- allocate(10 + (int)(inbuf.remaining()*factor));
-
- while (true) {
- CoderResult result = decoder.decode(inbuf, dest, true);
- dest.flip();
-
- if (result.isUnderflow()) { // done reading
- // make sure there is at least one extra character
- if (dest.limit() == dest.capacity()) {
- dest = CharBuffer.allocate(dest.capacity()+1).put(dest);
- dest.flip();
- }
- return dest;
- } else if (result.isOverflow()) { // buffer too small; expand
- int newCapacity =
- 10 + dest.capacity() +
- (int)(inbuf.remaining()*decoder.maxCharsPerByte());
- dest = CharBuffer.allocate(newCapacity).put(dest);
- } else if (result.isMalformed() || result.isUnmappable()) {
- // bad character in input
-
- // report coding error (warn only pre 1.5)
- if (!getSource().allowEncodingErrors()) {
- log.error(new SimpleDiagnosticPosition(dest.limit()),
- "illegal.char.for.encoding",
- charset == null ? encodingName : charset.name());
- } else {
- log.warning(new SimpleDiagnosticPosition(dest.limit()),
- "illegal.char.for.encoding",
- charset == null ? encodingName : charset.name());
- }
-
- // skip past the coding error
- inbuf.position(inbuf.position() + result.length());
-
- // undo the flip() to prepare the output buffer
- // for more translation
- dest.position(dest.limit());
- dest.limit(dest.capacity());
- dest.put((char)0xfffd); // backward compatible
- } else {
- throw new AssertionError(result);
- }
- }
- // unreached
- }
-
public ClassLoader getClassLoader(Location location) {
nullCheck(location);
Iterable extends File> path = getLocation(location);
@@ -754,39 +541,7 @@ public class JavacFileManager implements StandardJavaFileManager {
}
}
- URL[] urls = lb.toArray(new URL[lb.size()]);
- ClassLoader thisClassLoader = getClass().getClassLoader();
-
- // Bug: 6558476
- // Ideally, ClassLoader should be Closeable, but before JDK7 it is not.
- // On older versions, try the following, to get a closeable classloader.
-
- // 1: Allow client to specify the class to use via hidden option
- if (classLoaderClass != null) {
- try {
- Class extends ClassLoader> loader =
- Class.forName(classLoaderClass).asSubclass(ClassLoader.class);
- Class>[] constrArgTypes = { URL[].class, ClassLoader.class };
- Constructor extends ClassLoader> constr = loader.getConstructor(constrArgTypes);
- return constr.newInstance(new Object[] { urls, thisClassLoader });
- } catch (Throwable t) {
- // ignore errors loading user-provided class loader, fall through
- }
- }
-
- // 2: If URLClassLoader implements Closeable, use that.
- if (Closeable.class.isAssignableFrom(URLClassLoader.class))
- return new URLClassLoader(urls, thisClassLoader);
-
- // 3: Try using private reflection-based CloseableURLClassLoader
- try {
- return new CloseableURLClassLoader(urls, thisClassLoader);
- } catch (Throwable t) {
- // ignore errors loading workaround class loader, fall through
- }
-
- // 4: If all else fails, use plain old standard URLClassLoader
- return new URLClassLoader(urls, thisClassLoader);
+ return getClassLoader(lb.toArray(new URL[lb.size()]));
}
public Iterable list(Location location,
@@ -836,38 +591,6 @@ public class JavacFileManager implements StandardJavaFileManager {
return a.equals(b);
}
- public boolean handleOption(String current, Iterator remaining) {
- for (JavacOption o: javacFileManagerOptions) {
- if (o.matches(current)) {
- if (o.hasArg()) {
- if (remaining.hasNext()) {
- if (!o.process(options, current, remaining.next()))
- return true;
- }
- } else {
- if (!o.process(options, current))
- return true;
- }
- // operand missing, or process returned false
- throw new IllegalArgumentException(current);
- }
- }
-
- return false;
- }
- // where
- private static JavacOption[] javacFileManagerOptions =
- RecognizedOptions.getJavacFileManagerOptions(
- new RecognizedOptions.GrumpyHelper());
-
- public int isSupportedOption(String option) {
- for (JavacOption o : javacFileManagerOptions) {
- if (o.matches(option))
- return o.hasArg() ? 1 : 0;
- }
- return -1;
- }
-
public boolean hasLocation(Location location) {
return getLocation(location) != null;
}
@@ -1115,15 +838,4 @@ public class JavacFileManager implements StandardJavaFileManager {
}
throw new IllegalArgumentException("Invalid relative path: " + file);
}
-
- private static T nullCheck(T o) {
- o.getClass(); // null check
- return o;
- }
-
- private static Iterable nullCheck(Iterable it) {
- for (T t : it)
- t.getClass(); // null check
- return it;
- }
}
diff --git a/langtools/src/share/classes/com/sun/tools/javac/file/Paths.java b/langtools/src/share/classes/com/sun/tools/javac/file/Paths.java
index 6457b8107a5..c4dc9bb2301 100644
--- a/langtools/src/share/classes/com/sun/tools/javac/file/Paths.java
+++ b/langtools/src/share/classes/com/sun/tools/javac/file/Paths.java
@@ -66,7 +66,7 @@ public class Paths {
* @param context the context
* @return the Paths instance for this context
*/
- static Paths instance(Context context) {
+ public static Paths instance(Context context) {
Paths instance = context.get(pathsKey);
if (instance == null)
instance = new Paths(context);
diff --git a/langtools/src/share/classes/com/sun/tools/javac/nio/JavacPathFileManager.java b/langtools/src/share/classes/com/sun/tools/javac/nio/JavacPathFileManager.java
new file mode 100644
index 00000000000..6202b37d3b9
--- /dev/null
+++ b/langtools/src/share/classes/com/sun/tools/javac/nio/JavacPathFileManager.java
@@ -0,0 +1,543 @@
+/*
+ * Copyright 2009 Sun Microsystems, 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. Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package com.sun.tools.javac.nio;
+
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.nio.charset.Charset;
+import java.nio.file.Files;
+import java.nio.file.FileSystem;
+import java.nio.file.FileSystems;
+import java.nio.file.FileVisitOption;
+import java.nio.file.FileVisitResult;
+import java.nio.file.Path;
+import java.nio.file.SimpleFileVisitor;
+import java.nio.file.attribute.Attributes;
+import java.nio.file.attribute.BasicFileAttributes;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.EnumSet;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.LinkedHashSet;
+import java.util.Map;
+import java.util.Set;
+import javax.lang.model.SourceVersion;
+import javax.tools.FileObject;
+import javax.tools.JavaFileManager;
+import javax.tools.JavaFileObject;
+import javax.tools.JavaFileObject.Kind;
+import javax.tools.StandardLocation;
+
+import static java.nio.file.FileVisitOption.*;
+import static javax.tools.StandardLocation.*;
+
+import com.sun.tools.javac.file.Paths;
+import com.sun.tools.javac.util.BaseFileManager;
+import com.sun.tools.javac.util.Context;
+import com.sun.tools.javac.util.List;
+import com.sun.tools.javac.util.ListBuffer;
+
+import static com.sun.tools.javac.main.OptionName.*;
+
+
+// NOTE the imports carefully for this compilation unit.
+//
+// Path: java.nio.file.Path -- the new NIO type for which this file manager exists
+//
+// Paths: com.sun.tools.javac.file.Paths -- legacy javac type for handling path options
+// The other Paths (java.nio.file.Paths) is not used
+
+// NOTE this and related classes depend on new API in JDK 7.
+// This requires special handling while bootstrapping the JDK build,
+// when these classes might not yet have been compiled. To workaround
+// this, the build arranges to make stubs of these classes available
+// when compiling this and related classes. The set of stub files
+// is specified in make/build.properties.
+
+/**
+ * Implementation of PathFileManager: a JavaFileManager based on the use
+ * of java.nio.file.Path.
+ *
+ *
Just as a Path is somewhat analagous to a File, so too is this
+ * JavacPathFileManager analogous to JavacFileManager, as it relates to the
+ * support of FileObjects based on File objects (i.e. just RegularFileObject,
+ * not ZipFileObject and its variants.)
+ *
+ *
The default values for the standard locations supported by this file
+ * manager are the same as the default values provided by JavacFileManager --
+ * i.e. as determined by the javac.file.Paths class. To override these values,
+ * call {@link #setLocation}.
+ *
+ *
To reduce confusion with Path objects, the locations such as "class path",
+ * "source path", etc, are generically referred to here as "search paths".
+ *
+ *
This is NOT part of any API supported by Sun Microsystems. If
+ * you write code that depends on this, you do so at your own risk.
+ * This code and its internal interfaces are subject to change or
+ * deletion without notice.
+ */
+public class JavacPathFileManager extends BaseFileManager implements PathFileManager {
+ protected FileSystem defaultFileSystem;
+
+ /**
+ * Create a JavacPathFileManager using a given context, optionally registering
+ * it as the JavaFileManager for that context.
+ */
+ public JavacPathFileManager(Context context, boolean register, Charset charset) {
+ super(charset);
+ if (register)
+ context.put(JavaFileManager.class, this);
+ pathsForLocation = new HashMap();
+ fileSystems = new HashMap();
+ setContext(context);
+ }
+
+ /**
+ * Set the context for JavacPathFileManager.
+ */
+ @Override
+ protected void setContext(Context context) {
+ super.setContext(context);
+ searchPaths = Paths.instance(context);
+ }
+
+ @Override
+ public FileSystem getDefaultFileSystem() {
+ if (defaultFileSystem == null)
+ defaultFileSystem = FileSystems.getDefault();
+ return defaultFileSystem;
+ }
+
+ @Override
+ public void setDefaultFileSystem(FileSystem fs) {
+ defaultFileSystem = fs;
+ }
+
+ @Override
+ public void flush() throws IOException {
+ contentCache.clear();
+ }
+
+ @Override
+ public void close() throws IOException {
+ for (FileSystem fs: fileSystems.values())
+ fs.close();
+ }
+
+ @Override
+ public ClassLoader getClassLoader(Location location) {
+ nullCheck(location);
+ Iterable extends Path> path = getLocation(location);
+ if (path == null)
+ return null;
+ ListBuffer lb = new ListBuffer();
+ for (Path p: path) {
+ try {
+ lb.append(p.toUri().toURL());
+ } catch (MalformedURLException e) {
+ throw new AssertionError(e);
+ }
+ }
+
+ return getClassLoader(lb.toArray(new URL[lb.size()]));
+ }
+
+ //
+
+ public boolean hasLocation(Location location) {
+ return (getLocation(location) != null);
+ }
+
+ public Iterable extends Path> getLocation(Location location) {
+ nullCheck(location);
+ lazyInitSearchPaths();
+ PathsForLocation path = pathsForLocation.get(location);
+ if (path == null && !pathsForLocation.containsKey(location)) {
+ setDefaultForLocation(location);
+ path = pathsForLocation.get(location);
+ }
+ return path;
+ }
+
+ private Path getOutputLocation(Location location) {
+ Iterable extends Path> paths = getLocation(location);
+ return (paths == null ? null : paths.iterator().next());
+ }
+
+ public void setLocation(Location location, Iterable extends Path> searchPath)
+ throws IOException
+ {
+ nullCheck(location);
+ lazyInitSearchPaths();
+ if (searchPath == null) {
+ setDefaultForLocation(location);
+ } else {
+ if (location.isOutputLocation())
+ checkOutputPath(searchPath);
+ PathsForLocation pl = new PathsForLocation();
+ for (Path p: searchPath)
+ pl.add(p); // TODO -Xlint:path warn if path not found
+ pathsForLocation.put(location, pl);
+ }
+ }
+
+ private void checkOutputPath(Iterable extends Path> searchPath) throws IOException {
+ Iterator extends Path> pathIter = searchPath.iterator();
+ if (!pathIter.hasNext())
+ throw new IllegalArgumentException("empty path for directory");
+ Path path = pathIter.next();
+ if (pathIter.hasNext())
+ throw new IllegalArgumentException("path too long for directory");
+ if (!path.exists())
+ throw new FileNotFoundException(path + ": does not exist");
+ else if (!isDirectory(path))
+ throw new IOException(path + ": not a directory");
+ }
+
+ private void setDefaultForLocation(Location locn) {
+ Collection files = null;
+ if (locn instanceof StandardLocation) {
+ switch ((StandardLocation) locn) {
+ case CLASS_PATH:
+ files = searchPaths.userClassPath();
+ break;
+ case PLATFORM_CLASS_PATH:
+ files = searchPaths.bootClassPath();
+ break;
+ case SOURCE_PATH:
+ files = searchPaths.sourcePath();
+ break;
+ case CLASS_OUTPUT: {
+ String arg = options.get(D);
+ files = (arg == null ? null : Collections.singleton(new File(arg)));
+ break;
+ }
+ case SOURCE_OUTPUT: {
+ String arg = options.get(S);
+ files = (arg == null ? null : Collections.singleton(new File(arg)));
+ break;
+ }
+ }
+ }
+
+ PathsForLocation pl = new PathsForLocation();
+ if (files != null) {
+ for (File f: files)
+ pl.add(f.toPath());
+ }
+ pathsForLocation.put(locn, pl);
+ }
+
+ private void lazyInitSearchPaths() {
+ if (!inited) {
+ setDefaultForLocation(PLATFORM_CLASS_PATH);
+ setDefaultForLocation(CLASS_PATH);
+ setDefaultForLocation(SOURCE_PATH);
+ inited = true;
+ }
+ }
+ // where
+ private boolean inited = false;
+
+ private Map pathsForLocation;
+ private Paths searchPaths;
+
+ private static class PathsForLocation extends LinkedHashSet {
+ private static final long serialVersionUID = 6788510222394486733L;
+ }
+
+ //
+
+ //
+
+ @Override
+ public Path getPath(FileObject fo) {
+ nullCheck(fo);
+ if (!(fo instanceof PathFileObject))
+ throw new IllegalArgumentException();
+ return ((PathFileObject) fo).getPath();
+ }
+
+ @Override
+ public boolean isSameFile(FileObject a, FileObject b) {
+ nullCheck(a);
+ nullCheck(b);
+ if (!(a instanceof PathFileObject))
+ throw new IllegalArgumentException("Not supported: " + a);
+ if (!(b instanceof PathFileObject))
+ throw new IllegalArgumentException("Not supported: " + b);
+ return ((PathFileObject) a).isSameFile((PathFileObject) b);
+ }
+
+ @Override
+ public Iterable list(Location location,
+ String packageName, Set kinds, boolean recurse)
+ throws IOException {
+ // validatePackageName(packageName);
+ nullCheck(packageName);
+ nullCheck(kinds);
+
+ Iterable extends Path> paths = getLocation(location);
+ if (paths == null)
+ return List.nil();
+ ListBuffer results = new ListBuffer();
+
+ for (Path path : paths)
+ list(path, packageName, kinds, recurse, results);
+
+ return results.toList();
+ }
+
+ private void list(Path path, String packageName, final Set kinds,
+ boolean recurse, final ListBuffer results)
+ throws IOException {
+ if (!path.exists())
+ return;
+
+ final Path pathDir;
+ if (isDirectory(path))
+ pathDir = path;
+ else {
+ FileSystem fs = getFileSystem(path);
+ if (fs == null)
+ return;
+ pathDir = fs.getRootDirectories().iterator().next();
+ }
+ String sep = path.getFileSystem().getSeparator();
+ Path packageDir = packageName.isEmpty() ? pathDir
+ : pathDir.resolve(packageName.replace(".", sep));
+ if (!packageDir.exists())
+ return;
+
+/* Alternate impl of list, superceded by use of Files.walkFileTree */
+// Deque queue = new LinkedList();
+// queue.add(packageDir);
+//
+// Path dir;
+// while ((dir = queue.poll()) != null) {
+// DirectoryStream ds = dir.newDirectoryStream();
+// try {
+// for (Path p: ds) {
+// String name = p.getName().toString();
+// if (isDirectory(p)) {
+// if (recurse && SourceVersion.isIdentifier(name)) {
+// queue.add(p);
+// }
+// } else {
+// if (kinds.contains(getKind(name))) {
+// JavaFileObject fe =
+// PathFileObject.createDirectoryPathFileObject(this, p, pathDir);
+// results.append(fe);
+// }
+// }
+// }
+// } finally {
+// ds.close();
+// }
+// }
+ int maxDepth = (recurse ? Integer.MAX_VALUE : 1);
+ Set opts = EnumSet.of(DETECT_CYCLES, FOLLOW_LINKS);
+ Files.walkFileTree(packageDir, opts, maxDepth,
+ new SimpleFileVisitor() {
+ @Override
+ public FileVisitResult preVisitDirectory(Path dir) {
+ if (SourceVersion.isIdentifier(dir.getName().toString())) // JSR 292?
+ return FileVisitResult.CONTINUE;
+ else
+ return FileVisitResult.SKIP_SUBTREE;
+ }
+
+ @Override
+ public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) {
+ if (attrs.isRegularFile() && kinds.contains(getKind(file.getName().toString()))) {
+ JavaFileObject fe =
+ PathFileObject.createDirectoryPathFileObject(
+ JavacPathFileManager.this, file, pathDir);
+ results.append(fe);
+ }
+ return FileVisitResult.CONTINUE;
+ }
+ });
+ }
+
+ @Override
+ public Iterable extends JavaFileObject> getJavaFileObjectsFromPaths(
+ Iterable extends Path> paths) {
+ ArrayList result;
+ if (paths instanceof Collection>)
+ result = new ArrayList(((Collection>)paths).size());
+ else
+ result = new ArrayList();
+ for (Path p: paths)
+ result.add(PathFileObject.createSimplePathFileObject(this, nullCheck(p)));
+ return result;
+ }
+
+ @Override
+ public Iterable extends JavaFileObject> getJavaFileObjects(Path... paths) {
+ return getJavaFileObjectsFromPaths(Arrays.asList(nullCheck(paths)));
+ }
+
+ @Override
+ public JavaFileObject getJavaFileForInput(Location location,
+ String className, Kind kind) throws IOException {
+ return getFileForInput(location, getRelativePath(className, kind));
+ }
+
+ @Override
+ public FileObject getFileForInput(Location location,
+ String packageName, String relativeName) throws IOException {
+ return getFileForInput(location, getRelativePath(packageName, relativeName));
+ }
+
+ private JavaFileObject getFileForInput(Location location, String relativePath)
+ throws IOException {
+ for (Path p: getLocation(location)) {
+ if (isDirectory(p)) {
+ Path f = resolve(p, relativePath);
+ if (f.exists())
+ return PathFileObject.createDirectoryPathFileObject(this, f, p);
+ } else {
+ FileSystem fs = getFileSystem(p);
+ if (fs != null) {
+ Path file = getPath(fs, relativePath);
+ if (file.exists())
+ return PathFileObject.createJarPathFileObject(this, file);
+ }
+ }
+ }
+ return null;
+ }
+
+ @Override
+ public JavaFileObject getJavaFileForOutput(Location location,
+ String className, Kind kind, FileObject sibling) throws IOException {
+ return getFileForOutput(location, getRelativePath(className, kind), sibling);
+ }
+
+ @Override
+ public FileObject getFileForOutput(Location location, String packageName,
+ String relativeName, FileObject sibling)
+ throws IOException {
+ return getFileForOutput(location, getRelativePath(packageName, relativeName), sibling);
+ }
+
+ private JavaFileObject getFileForOutput(Location location,
+ String relativePath, FileObject sibling) {
+ Path dir = getOutputLocation(location);
+ if (dir == null) {
+ if (location == CLASS_OUTPUT) {
+ Path siblingDir = null;
+ if (sibling != null && sibling instanceof PathFileObject) {
+ siblingDir = ((PathFileObject) sibling).getPath().getParent();
+ }
+ return PathFileObject.createSiblingPathFileObject(this,
+ siblingDir.resolve(getBaseName(relativePath)),
+ relativePath);
+ } else if (location == SOURCE_OUTPUT) {
+ dir = getOutputLocation(CLASS_OUTPUT);
+ }
+ }
+
+ Path file;
+ if (dir != null) {
+ file = resolve(dir, relativePath);
+ return PathFileObject.createDirectoryPathFileObject(this, file, dir);
+ } else {
+ file = getPath(getDefaultFileSystem(), relativePath);
+ return PathFileObject.createSimplePathFileObject(this, file);
+ }
+
+ }
+
+ @Override
+ public String inferBinaryName(Location location, JavaFileObject fo) {
+ nullCheck(fo);
+ // Need to match the path semantics of list(location, ...)
+ Iterable extends Path> paths = getLocation(location);
+ if (paths == null) {
+ return null;
+ }
+
+ if (!(fo instanceof PathFileObject))
+ throw new IllegalArgumentException(fo.getClass().getName());
+
+ return ((PathFileObject) fo).inferBinaryName(paths);
+ }
+
+ private FileSystem getFileSystem(Path p) throws IOException {
+ FileSystem fs = fileSystems.get(p);
+ if (fs == null) {
+ fs = FileSystems.newFileSystem(p, Collections.emptyMap(), null);
+ fileSystems.put(p, fs);
+ }
+ return fs;
+ }
+
+ private Map fileSystems;
+
+ //
+
+ //
+
+ private static String getRelativePath(String className, Kind kind) {
+ return className.replace(".", "/") + kind.extension;
+ }
+
+ private static String getRelativePath(String packageName, String relativeName) {
+ return packageName.replace(".", "/") + relativeName;
+ }
+
+ private static String getBaseName(String relativePath) {
+ int lastSep = relativePath.lastIndexOf("/");
+ return relativePath.substring(lastSep + 1); // safe if "/" not found
+ }
+
+ private static boolean isDirectory(Path path) throws IOException {
+ BasicFileAttributes attrs = Attributes.readBasicFileAttributes(path);
+ return attrs.isDirectory();
+ }
+
+ private static Path getPath(FileSystem fs, String relativePath) {
+ return fs.getPath(relativePath.replace("/", fs.getSeparator()));
+ }
+
+ private static Path resolve(Path base, String relativePath) {
+ FileSystem fs = base.getFileSystem();
+ Path rp = fs.getPath(relativePath.replace("/", fs.getSeparator()));
+ return base.resolve(rp);
+ }
+
+ //
+
+}
diff --git a/langtools/src/share/classes/com/sun/tools/javac/nio/PathFileManager.java b/langtools/src/share/classes/com/sun/tools/javac/nio/PathFileManager.java
new file mode 100644
index 00000000000..0b55e6859ba
--- /dev/null
+++ b/langtools/src/share/classes/com/sun/tools/javac/nio/PathFileManager.java
@@ -0,0 +1,125 @@
+/*
+ * Copyright 2009 Sun Microsystems, 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. Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package com.sun.tools.javac.nio;
+
+import java.io.IOException;
+import java.nio.file.FileSystem;
+import java.nio.file.Path;
+import javax.tools.FileObject;
+import javax.tools.JavaFileManager;
+import javax.tools.JavaFileObject;
+
+/**
+ * File manager based on {@linkplain File java.nio.file.Path}.
+ *
+ * Eventually, this should be moved to javax.tools.
+ * Also, JavaCompiler might reasonably provide a method getPathFileManager,
+ * similar to {@link javax.tools.JavaCompiler#getStandardFileManager
+ * getStandardFileManager}. However, would need to be handled carefully
+ * as another forward reference from langtools to jdk.
+ *
+ *
This is NOT part of any API supported by Sun Microsystems. If
+ * you write code that depends on this, you do so at your own risk.
+ * This code and its internal interfaces are subject to change or
+ * deletion without notice.
+ */
+public interface PathFileManager extends JavaFileManager {
+ /**
+ * Get the default file system used to create paths. If no value has been
+ * set, the default file system is {@link FileSystems#getDefault}.
+ */
+ FileSystem getDefaultFileSystem();
+
+ /**
+ * Set the default file system used to create paths.
+ * @param fs the default file system used to create any new paths.
+ */
+ void setDefaultFileSystem(FileSystem fs);
+
+ /**
+ * Get file objects representing the given files.
+ *
+ * @param paths a list of paths
+ * @return a list of file objects
+ * @throws IllegalArgumentException if the list of paths includes
+ * a directory
+ */
+ Iterable extends JavaFileObject> getJavaFileObjectsFromPaths(
+ Iterable extends Path> paths);
+
+ /**
+ * Get file objects representing the given paths.
+ * Convenience method equivalent to:
+ *
+ *
+ *
+ * @param paths an array of paths
+ * @return a list of file objects
+ * @throws IllegalArgumentException if the array of files includes
+ * a directory
+ * @throws NullPointerException if the given array contains null
+ * elements
+ */
+ Iterable extends JavaFileObject> getJavaFileObjects(Path... paths);
+
+ /**
+ * Return the Path for a file object that has been obtained from this
+ * file manager.
+ *
+ * @param fo A file object that has been obtained from this file manager.
+ * @return The underlying Path object.
+ * @throws IllegalArgumentException is the file object was not obtained from
+ * from this file manager.
+ */
+ Path getPath(FileObject fo);
+
+ /**
+ * Get the search path associated with the given location.
+ *
+ * @param location a location
+ * @return a list of paths or {@code null} if this location has no
+ * associated search path
+ * @see #setLocation
+ */
+ Iterable extends Path> getLocation(Location location);
+
+ /**
+ * Associate the given search path with the given location. Any
+ * previous value will be discarded.
+ *
+ * @param location a location
+ * @param searchPath a list of files, if {@code null} use the default
+ * search path for this location
+ * @see #getLocation
+ * @throws IllegalArgumentException if location is an output
+ * location and searchpath does not contain exactly one element
+ * @throws IOException if location is an output location and searchpath
+ * does not represent an existing directory
+ */
+ void setLocation(Location location, Iterable extends Path> searchPath) throws IOException;
+}
diff --git a/langtools/src/share/classes/com/sun/tools/javac/nio/PathFileObject.java b/langtools/src/share/classes/com/sun/tools/javac/nio/PathFileObject.java
new file mode 100644
index 00000000000..80bdb2edb74
--- /dev/null
+++ b/langtools/src/share/classes/com/sun/tools/javac/nio/PathFileObject.java
@@ -0,0 +1,319 @@
+/*
+ * Copyright 2009 Sun Microsystems, 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. Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package com.sun.tools.javac.nio;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.OutputStream;
+import java.io.OutputStreamWriter;
+import java.io.Reader;
+import java.io.Writer;
+import java.net.URI;
+import java.nio.ByteBuffer;
+import java.nio.CharBuffer;
+import java.nio.charset.CharsetDecoder;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.attribute.Attributes;
+import java.nio.file.attribute.BasicFileAttributes;
+import javax.lang.model.element.Modifier;
+import javax.lang.model.element.NestingKind;
+import javax.tools.JavaFileObject;
+
+import com.sun.tools.javac.util.BaseFileManager;
+
+
+/**
+ * Implementation of JavaFileObject using java.nio.file API.
+ *
+ *
PathFileObjects are, for the most part, straightforward wrappers around
+ * Path objects. The primary complexity is the support for "inferBinaryName".
+ * This is left as an abstract method, implemented by each of a number of
+ * different factory methods, which compute the binary name based on
+ * information available at the time the file object is created.
+ *
+ *
This is NOT part of any API supported by Sun Microsystems. If
+ * you write code that depends on this, you do so at your own risk.
+ * This code and its internal interfaces are subject to change or
+ * deletion without notice.
+ */
+abstract class PathFileObject implements JavaFileObject {
+ private JavacPathFileManager fileManager;
+ private Path path;
+
+ /**
+ * Create a PathFileObject within a directory, such that the binary name
+ * can be inferred from the relationship to the parent directory.
+ */
+ static PathFileObject createDirectoryPathFileObject(JavacPathFileManager fileManager,
+ final Path path, final Path dir) {
+ return new PathFileObject(fileManager, path) {
+ @Override
+ String inferBinaryName(Iterable extends Path> paths) {
+ return toBinaryName(dir.relativize(path));
+ }
+ };
+ }
+
+ /**
+ * Create a PathFileObject in a file system such as a jar file, such that
+ * the binary name can be inferred from its position within the filesystem.
+ */
+ static PathFileObject createJarPathFileObject(JavacPathFileManager fileManager,
+ final Path path) {
+ return new PathFileObject(fileManager, path) {
+ @Override
+ String inferBinaryName(Iterable extends Path> paths) {
+ return toBinaryName(path);
+ }
+ };
+ }
+
+ /**
+ * Create a PathFileObject whose binary name can be inferred from the
+ * relative path to a sibling.
+ */
+ static PathFileObject createSiblingPathFileObject(JavacPathFileManager fileManager,
+ final Path path, final String relativePath) {
+ return new PathFileObject(fileManager, path) {
+ @Override
+ String inferBinaryName(Iterable extends Path> paths) {
+ return toBinaryName(relativePath, "/");
+ }
+ };
+ }
+
+ /**
+ * Create a PathFileObject whose binary name might be inferred from its
+ * position on a search path.
+ */
+ static PathFileObject createSimplePathFileObject(JavacPathFileManager fileManager,
+ final Path path) {
+ return new PathFileObject(fileManager, path) {
+ @Override
+ String inferBinaryName(Iterable extends Path> paths) {
+ Path absPath = path.toAbsolutePath();
+ for (Path p: paths) {
+ Path ap = p.toAbsolutePath();
+ if (absPath.startsWith(ap)) {
+ try {
+ Path rp = ap.relativize(absPath);
+ if (rp != null) // maybe null if absPath same as ap
+ return toBinaryName(rp);
+ } catch (IllegalArgumentException e) {
+ // ignore this p if cannot relativize path to p
+ }
+ }
+ }
+ return null;
+ }
+ };
+ }
+
+ protected PathFileObject(JavacPathFileManager fileManager, Path path) {
+ fileManager.getClass(); // null check
+ path.getClass(); // null check
+ this.fileManager = fileManager;
+ this.path = path;
+ }
+
+ abstract String inferBinaryName(Iterable extends Path> paths);
+
+ /**
+ * Return the Path for this object.
+ * @return the Path for this object.
+ */
+ Path getPath() {
+ return path;
+ }
+
+ @Override
+ public Kind getKind() {
+ return BaseFileManager.getKind(path.getName().toString());
+ }
+
+ @Override
+ public boolean isNameCompatible(String simpleName, Kind kind) {
+ simpleName.getClass();
+ // null check
+ if (kind == Kind.OTHER && getKind() != kind) {
+ return false;
+ }
+ String sn = simpleName + kind.extension;
+ String pn = path.getName().toString();
+ if (pn.equals(sn)) {
+ return true;
+ }
+ if (pn.equalsIgnoreCase(sn)) {
+ try {
+ // allow for Windows
+ return path.toRealPath(false).getName().toString().equals(sn);
+ } catch (IOException e) {
+ }
+ }
+ return false;
+ }
+
+ @Override
+ public NestingKind getNestingKind() {
+ return null;
+ }
+
+ @Override
+ public Modifier getAccessLevel() {
+ return null;
+ }
+
+ @Override
+ public URI toUri() {
+ return path.toUri();
+ }
+
+ @Override
+ public String getName() {
+ return path.toString();
+ }
+
+ @Override
+ public InputStream openInputStream() throws IOException {
+ return path.newInputStream();
+ }
+
+ @Override
+ public OutputStream openOutputStream() throws IOException {
+ ensureParentDirectoriesExist();
+ return path.newOutputStream();
+ }
+
+ @Override
+ public Reader openReader(boolean ignoreEncodingErrors) throws IOException {
+ CharsetDecoder decoder = fileManager.getDecoder(fileManager.getEncodingName(), ignoreEncodingErrors);
+ return new InputStreamReader(openInputStream(), decoder);
+ }
+
+ @Override
+ public CharSequence getCharContent(boolean ignoreEncodingErrors) throws IOException {
+ CharBuffer cb = fileManager.getCachedContent(this);
+ if (cb == null) {
+ InputStream in = openInputStream();
+ try {
+ ByteBuffer bb = fileManager.makeByteBuffer(in);
+ JavaFileObject prev = fileManager.log.useSource(this);
+ try {
+ cb = fileManager.decode(bb, ignoreEncodingErrors);
+ } finally {
+ fileManager.log.useSource(prev);
+ }
+ fileManager.recycleByteBuffer(bb);
+ if (!ignoreEncodingErrors) {
+ fileManager.cache(this, cb);
+ }
+ } finally {
+ in.close();
+ }
+ }
+ return cb;
+ }
+
+ @Override
+ public Writer openWriter() throws IOException {
+ ensureParentDirectoriesExist();
+ return new OutputStreamWriter(path.newOutputStream(), fileManager.getEncodingName());
+ }
+
+ @Override
+ public long getLastModified() {
+ try {
+ BasicFileAttributes attrs = Attributes.readBasicFileAttributes(path);
+ return attrs.lastModifiedTime().toMillis();
+ } catch (IOException e) {
+ return -1;
+ }
+ }
+
+ @Override
+ public boolean delete() {
+ try {
+ path.delete();
+ return true;
+ } catch (IOException e) {
+ return false;
+ }
+ }
+
+ public boolean isSameFile(PathFileObject other) {
+ try {
+ return path.isSameFile(other.path);
+ } catch (IOException e) {
+ return false;
+ }
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ return (other instanceof PathFileObject && path.equals(((PathFileObject) other).path));
+ }
+
+ @Override
+ public int hashCode() {
+ return path.hashCode();
+ }
+
+ @Override
+ public String toString() {
+ return getClass().getSimpleName() + "[" + path + "]";
+ }
+
+ private void ensureParentDirectoriesExist() throws IOException {
+ Path parent = path.getParent();
+ if (parent != null)
+ Files.createDirectories(parent);
+ }
+
+ private long size() {
+ try {
+ BasicFileAttributes attrs = Attributes.readBasicFileAttributes(path);
+ return attrs.size();
+ } catch (IOException e) {
+ return -1;
+ }
+ }
+
+ protected static String toBinaryName(Path relativePath) {
+ return toBinaryName(relativePath.toString(),
+ relativePath.getFileSystem().getSeparator());
+ }
+
+ protected static String toBinaryName(String relativePath, String sep) {
+ return removeExtension(relativePath).replaceAll(sep, ".");
+ }
+
+ protected static String removeExtension(String fileName) {
+ int lastDot = fileName.lastIndexOf(".");
+ return (lastDot == -1 ? fileName : fileName.substring(0, lastDot));
+ }
+}
diff --git a/langtools/src/share/classes/com/sun/tools/javac/util/BaseFileManager.java b/langtools/src/share/classes/com/sun/tools/javac/util/BaseFileManager.java
new file mode 100644
index 00000000000..bc91c470f7a
--- /dev/null
+++ b/langtools/src/share/classes/com/sun/tools/javac/util/BaseFileManager.java
@@ -0,0 +1,355 @@
+/*
+ * Copyright 2009 Sun Microsystems, 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. Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package com.sun.tools.javac.util;
+
+import com.sun.tools.javac.code.Source;
+import com.sun.tools.javac.main.JavacOption;
+import com.sun.tools.javac.main.OptionName;
+import com.sun.tools.javac.main.RecognizedOptions;
+import com.sun.tools.javac.util.JCDiagnostic.SimpleDiagnosticPosition;
+import java.io.ByteArrayOutputStream;
+import java.io.Closeable;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStreamWriter;
+import java.lang.ref.SoftReference;
+import java.lang.reflect.Constructor;
+import java.net.URL;
+import java.net.URLClassLoader;
+import java.nio.ByteBuffer;
+import java.nio.CharBuffer;
+import java.nio.charset.Charset;
+import java.nio.charset.CharsetDecoder;
+import java.nio.charset.CoderResult;
+import java.nio.charset.CodingErrorAction;
+import java.nio.charset.IllegalCharsetNameException;
+import java.nio.charset.UnsupportedCharsetException;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+import javax.tools.JavaFileObject;
+import javax.tools.JavaFileObject.Kind;
+
+/**
+ * Utility methods for building a filemanager.
+ * There are no references here to file-system specific objects such as
+ * java.io.File or java.nio.file.Path.
+ */
+public class BaseFileManager {
+ protected BaseFileManager(Charset charset) {
+ this.charset = charset;
+ byteBufferCache = new ByteBufferCache();
+ }
+
+ /**
+ * Set the context for JavacPathFileManager.
+ */
+ protected void setContext(Context context) {
+ log = Log.instance(context);
+ options = Options.instance(context);
+ classLoaderClass = options.get("procloader");
+ }
+
+ /**
+ * The log to be used for error reporting.
+ */
+ public Log log;
+
+ /**
+ * User provided charset (through javax.tools).
+ */
+ protected Charset charset;
+
+ protected Options options;
+
+ protected String classLoaderClass;
+
+ protected Source getSource() {
+ String sourceName = options.get(OptionName.SOURCE);
+ Source source = null;
+ if (sourceName != null)
+ source = Source.lookup(sourceName);
+ return (source != null ? source : Source.DEFAULT);
+ }
+
+ protected ClassLoader getClassLoader(URL[] urls) {
+ ClassLoader thisClassLoader = getClass().getClassLoader();
+
+ // Bug: 6558476
+ // Ideally, ClassLoader should be Closeable, but before JDK7 it is not.
+ // On older versions, try the following, to get a closeable classloader.
+
+ // 1: Allow client to specify the class to use via hidden option
+ if (classLoaderClass != null) {
+ try {
+ Class extends ClassLoader> loader =
+ Class.forName(classLoaderClass).asSubclass(ClassLoader.class);
+ Class>[] constrArgTypes = { URL[].class, ClassLoader.class };
+ Constructor extends ClassLoader> constr = loader.getConstructor(constrArgTypes);
+ return constr.newInstance(new Object[] { urls, thisClassLoader });
+ } catch (Throwable t) {
+ // ignore errors loading user-provided class loader, fall through
+ }
+ }
+
+ // 2: If URLClassLoader implements Closeable, use that.
+ if (Closeable.class.isAssignableFrom(URLClassLoader.class))
+ return new URLClassLoader(urls, thisClassLoader);
+
+ // 3: Try using private reflection-based CloseableURLClassLoader
+ try {
+ return new CloseableURLClassLoader(urls, thisClassLoader);
+ } catch (Throwable t) {
+ // ignore errors loading workaround class loader, fall through
+ }
+
+ // 4: If all else fails, use plain old standard URLClassLoader
+ return new URLClassLoader(urls, thisClassLoader);
+ }
+
+ //
+ public boolean handleOption(String current, Iterator remaining) {
+ for (JavacOption o: javacFileManagerOptions) {
+ if (o.matches(current)) {
+ if (o.hasArg()) {
+ if (remaining.hasNext()) {
+ if (!o.process(options, current, remaining.next()))
+ return true;
+ }
+ } else {
+ if (!o.process(options, current))
+ return true;
+ }
+ // operand missing, or process returned false
+ throw new IllegalArgumentException(current);
+ }
+ }
+
+ return false;
+ }
+ // where
+ private static JavacOption[] javacFileManagerOptions =
+ RecognizedOptions.getJavacFileManagerOptions(
+ new RecognizedOptions.GrumpyHelper());
+
+ public int isSupportedOption(String option) {
+ for (JavacOption o : javacFileManagerOptions) {
+ if (o.matches(option))
+ return o.hasArg() ? 1 : 0;
+ }
+ return -1;
+ }
+ //
+
+ //
+ private String defaultEncodingName;
+ private String getDefaultEncodingName() {
+ if (defaultEncodingName == null) {
+ defaultEncodingName =
+ new OutputStreamWriter(new ByteArrayOutputStream()).getEncoding();
+ }
+ return defaultEncodingName;
+ }
+
+ public String getEncodingName() {
+ String encName = options.get(OptionName.ENCODING);
+ if (encName == null)
+ return getDefaultEncodingName();
+ else
+ return encName;
+ }
+
+ public CharBuffer decode(ByteBuffer inbuf, boolean ignoreEncodingErrors) {
+ String encodingName = getEncodingName();
+ CharsetDecoder decoder;
+ try {
+ decoder = getDecoder(encodingName, ignoreEncodingErrors);
+ } catch (IllegalCharsetNameException e) {
+ log.error("unsupported.encoding", encodingName);
+ return (CharBuffer)CharBuffer.allocate(1).flip();
+ } catch (UnsupportedCharsetException e) {
+ log.error("unsupported.encoding", encodingName);
+ return (CharBuffer)CharBuffer.allocate(1).flip();
+ }
+
+ // slightly overestimate the buffer size to avoid reallocation.
+ float factor =
+ decoder.averageCharsPerByte() * 0.8f +
+ decoder.maxCharsPerByte() * 0.2f;
+ CharBuffer dest = CharBuffer.
+ allocate(10 + (int)(inbuf.remaining()*factor));
+
+ while (true) {
+ CoderResult result = decoder.decode(inbuf, dest, true);
+ dest.flip();
+
+ if (result.isUnderflow()) { // done reading
+ // make sure there is at least one extra character
+ if (dest.limit() == dest.capacity()) {
+ dest = CharBuffer.allocate(dest.capacity()+1).put(dest);
+ dest.flip();
+ }
+ return dest;
+ } else if (result.isOverflow()) { // buffer too small; expand
+ int newCapacity =
+ 10 + dest.capacity() +
+ (int)(inbuf.remaining()*decoder.maxCharsPerByte());
+ dest = CharBuffer.allocate(newCapacity).put(dest);
+ } else if (result.isMalformed() || result.isUnmappable()) {
+ // bad character in input
+
+ // report coding error (warn only pre 1.5)
+ if (!getSource().allowEncodingErrors()) {
+ log.error(new SimpleDiagnosticPosition(dest.limit()),
+ "illegal.char.for.encoding",
+ charset == null ? encodingName : charset.name());
+ } else {
+ log.warning(new SimpleDiagnosticPosition(dest.limit()),
+ "illegal.char.for.encoding",
+ charset == null ? encodingName : charset.name());
+ }
+
+ // skip past the coding error
+ inbuf.position(inbuf.position() + result.length());
+
+ // undo the flip() to prepare the output buffer
+ // for more translation
+ dest.position(dest.limit());
+ dest.limit(dest.capacity());
+ dest.put((char)0xfffd); // backward compatible
+ } else {
+ throw new AssertionError(result);
+ }
+ }
+ // unreached
+ }
+
+ public CharsetDecoder getDecoder(String encodingName, boolean ignoreEncodingErrors) {
+ Charset cs = (this.charset == null)
+ ? Charset.forName(encodingName)
+ : this.charset;
+ CharsetDecoder decoder = cs.newDecoder();
+
+ CodingErrorAction action;
+ if (ignoreEncodingErrors)
+ action = CodingErrorAction.REPLACE;
+ else
+ action = CodingErrorAction.REPORT;
+
+ return decoder
+ .onMalformedInput(action)
+ .onUnmappableCharacter(action);
+ }
+ //
+
+ //
+ /**
+ * Make a byte buffer from an input stream.
+ */
+ public ByteBuffer makeByteBuffer(InputStream in)
+ throws IOException {
+ int limit = in.available();
+ if (limit < 1024) limit = 1024;
+ ByteBuffer result = byteBufferCache.get(limit);
+ int position = 0;
+ while (in.available() != 0) {
+ if (position >= limit)
+ // expand buffer
+ result = ByteBuffer.
+ allocate(limit <<= 1).
+ put((ByteBuffer)result.flip());
+ int count = in.read(result.array(),
+ position,
+ limit - position);
+ if (count < 0) break;
+ result.position(position += count);
+ }
+ return (ByteBuffer)result.flip();
+ }
+
+ public void recycleByteBuffer(ByteBuffer bb) {
+ byteBufferCache.put(bb);
+ }
+
+ /**
+ * A single-element cache of direct byte buffers.
+ */
+ private static class ByteBufferCache {
+ private ByteBuffer cached;
+ ByteBuffer get(int capacity) {
+ if (capacity < 20480) capacity = 20480;
+ ByteBuffer result =
+ (cached != null && cached.capacity() >= capacity)
+ ? (ByteBuffer)cached.clear()
+ : ByteBuffer.allocate(capacity + capacity>>1);
+ cached = null;
+ return result;
+ }
+ void put(ByteBuffer x) {
+ cached = x;
+ }
+ }
+
+ private final ByteBufferCache byteBufferCache;
+ //
+
+ //
+ public CharBuffer getCachedContent(JavaFileObject file) {
+ SoftReference r = contentCache.get(file);
+ return (r == null ? null : r.get());
+ }
+
+ public void cache(JavaFileObject file, CharBuffer cb) {
+ contentCache.put(file, new SoftReference(cb));
+ }
+
+ protected final Map> contentCache
+ = new HashMap>();
+ //
+
+ public static Kind getKind(String name) {
+ if (name.endsWith(Kind.CLASS.extension))
+ return Kind.CLASS;
+ else if (name.endsWith(Kind.SOURCE.extension))
+ return Kind.SOURCE;
+ else if (name.endsWith(Kind.HTML.extension))
+ return Kind.HTML;
+ else
+ return Kind.OTHER;
+ }
+
+ protected static T nullCheck(T o) {
+ o.getClass(); // null check
+ return o;
+ }
+
+ protected static Collection nullCheck(Collection it) {
+ for (T t : it)
+ t.getClass(); // null check
+ return it;
+ }
+}
diff --git a/langtools/src/share/classes/com/sun/tools/javac/file/CloseableURLClassLoader.java b/langtools/src/share/classes/com/sun/tools/javac/util/CloseableURLClassLoader.java
similarity index 96%
rename from langtools/src/share/classes/com/sun/tools/javac/file/CloseableURLClassLoader.java
rename to langtools/src/share/classes/com/sun/tools/javac/util/CloseableURLClassLoader.java
index bcba74bef9f..48c1e6f0dfd 100644
--- a/langtools/src/share/classes/com/sun/tools/javac/file/CloseableURLClassLoader.java
+++ b/langtools/src/share/classes/com/sun/tools/javac/util/CloseableURLClassLoader.java
@@ -23,7 +23,7 @@
* have any questions.
*/
-package com.sun.tools.javac.file;
+package com.sun.tools.javac.util;
import java.io.Closeable;
import java.io.IOException;
@@ -45,9 +45,9 @@ import java.util.jar.JarFile;
* This code and its internal interfaces are subject to change or
* deletion without notice.
*/
-class CloseableURLClassLoader
+public class CloseableURLClassLoader
extends URLClassLoader implements Closeable {
- CloseableURLClassLoader(URL[] urls, ClassLoader parent) throws Error {
+ public CloseableURLClassLoader(URL[] urls, ClassLoader parent) throws Error {
super(urls, parent);
try {
getLoaders(); //proactive check that URLClassLoader is as expected
@@ -63,6 +63,7 @@ class CloseableURLClassLoader
* @throws java.io.IOException if the jar files cannot be found for any
* reson, or if closing the jar file itself causes an IOException.
*/
+ @Override
public void close() throws IOException {
try {
for (Object l: getLoaders()) {
diff --git a/langtools/src/share/classes/javax/tools/StandardJavaFileManager.java b/langtools/src/share/classes/javax/tools/StandardJavaFileManager.java
index 116cf8c55f4..028c8d8f509 100644
--- a/langtools/src/share/classes/javax/tools/StandardJavaFileManager.java
+++ b/langtools/src/share/classes/javax/tools/StandardJavaFileManager.java
@@ -28,7 +28,6 @@ package javax.tools;
import java.io.File;
import java.io.IOException;
import java.util.*;
-import java.util.concurrent.*;
/**
* File manager based on {@linkplain File java.io.File}. A common way
diff --git a/langtools/test/tools/javac/nio/compileTest/CompileTest.java b/langtools/test/tools/javac/nio/compileTest/CompileTest.java
new file mode 100644
index 00000000000..72df1693a8a
--- /dev/null
+++ b/langtools/test/tools/javac/nio/compileTest/CompileTest.java
@@ -0,0 +1,165 @@
+/*
+ * Copyright 2009 Sun Microsystems, 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+/**
+ * @test
+ * @compile HelloPathWorld.java
+ * @run main CompileTest
+ */
+
+import java.io.*;
+import java.nio.file.*;
+import java.util.*;
+import java.util.jar.*;
+import javax.tools.*;
+
+import com.sun.tools.javac.nio.*;
+import com.sun.tools.javac.util.Context;
+import java.nio.file.spi.FileSystemProvider;
+
+
+public class CompileTest {
+ public static void main(String[] args) throws Exception {
+ new CompileTest().run();
+ }
+
+ public void run() throws Exception {
+ File rtDir = new File("rt.dir");
+ File javaHome = new File(System.getProperty("java.home"));
+ if (javaHome.getName().equals("jre"))
+ javaHome = javaHome.getParentFile();
+ File rtJar = new File(new File(new File(javaHome, "jre"), "lib"), "rt.jar");
+ expand(rtJar, rtDir);
+
+ String[] rtDir_opts = {
+ "-bootclasspath", rtDir.toString(),
+ "-classpath", "",
+ "-sourcepath", "",
+ "-extdirs", ""
+ };
+ test(rtDir_opts, "HelloPathWorld");
+
+ if (isJarFileSystemAvailable()) {
+ String[] rtJar_opts = {
+ "-bootclasspath", rtJar.toString(),
+ "-classpath", "",
+ "-sourcepath", "",
+ "-extdirs", ""
+ };
+ test(rtJar_opts, "HelloPathWorld");
+
+ String[] default_opts = { };
+ test(default_opts, "HelloPathWorld");
+
+ // finally, a non-trivial program
+ test(default_opts, "CompileTest");
+ } else
+ System.err.println("jar file system not available: test skipped");
+ }
+
+ void test(String[] opts, String className) throws Exception {
+ count++;
+ System.err.println("Test " + count + " " + Arrays.asList(opts) + " " + className);
+ Path testSrcDir = Paths.get(System.getProperty("test.src"));
+ Path testClassesDir = Paths.get(System.getProperty("test.classes"));
+ Path classes = Paths.get("classes." + count);
+ classes.createDirectory();
+
+ Context ctx = new Context();
+ PathFileManager fm = new JavacPathFileManager(ctx, true, null);
+ JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
+ List options = new ArrayList();
+ options.addAll(Arrays.asList(opts));
+ options.addAll(Arrays.asList(
+ "-verbose", "-XDverboseCompilePolicy",
+ "-d", classes.toString()
+ ));
+ Iterable extends JavaFileObject> compilationUnits =
+ fm.getJavaFileObjects(testSrcDir.resolve(className + ".java"));
+ StringWriter sw = new StringWriter();
+ PrintWriter out = new PrintWriter(sw);
+ JavaCompiler.CompilationTask t =
+ compiler.getTask(out, fm, null, options, null, compilationUnits);
+ boolean ok = t.call();
+ System.err.println(sw.toString());
+ if (!ok) {
+ throw new Exception("compilation failed");
+ }
+
+ File expect = new File("classes." + count + "/" + className + ".class");
+ if (!expect.exists())
+ throw new Exception("expected file not found: " + expect);
+ long expectedSize = new File(testClassesDir.toString(), className + ".class").length();
+ long actualSize = expect.length();
+ if (expectedSize != actualSize)
+ throw new Exception("wrong size found: " + actualSize + "; expected: " + expectedSize);
+ }
+
+ boolean isJarFileSystemAvailable() {
+ boolean result = false;
+ for (FileSystemProvider fsp: FileSystemProvider.installedProviders()) {
+ String scheme = fsp.getScheme();
+ System.err.println("Provider: " + scheme + " " + fsp);
+ if (scheme.equalsIgnoreCase("jar") || scheme.equalsIgnoreCase("zip"))
+ result = true;
+ }
+ return result;
+ }
+
+ void expand(File jar, File dir) throws IOException {
+ JarFile jarFile = new JarFile(jar);
+ try {
+ Enumeration entries = jarFile.entries();
+ while (entries.hasMoreElements()) {
+ JarEntry je = entries.nextElement();
+ if (!je.isDirectory()) {
+ copy(jarFile.getInputStream(je), new File(dir, je.getName()));
+ }
+ }
+ } finally {
+ jarFile.close();
+ }
+ }
+
+ void copy(InputStream in, File dest) throws IOException {
+ dest.getParentFile().mkdirs();
+ OutputStream out = new BufferedOutputStream(new FileOutputStream(dest));
+ try {
+ byte[] data = new byte[8192];
+ int n;
+ while ((n = in.read(data, 0, data.length)) > 0)
+ out.write(data, 0, n);
+ } finally {
+ out.close();
+ in.close();
+ }
+ }
+
+ void error(String message) {
+ System.err.println("Error: " + message);
+ errors++;
+ }
+
+ int errors;
+ int count;
+}
diff --git a/langtools/test/tools/javac/nio/compileTest/HelloPathWorld.java b/langtools/test/tools/javac/nio/compileTest/HelloPathWorld.java
new file mode 100644
index 00000000000..a65e21a9afa
--- /dev/null
+++ b/langtools/test/tools/javac/nio/compileTest/HelloPathWorld.java
@@ -0,0 +1,28 @@
+/*
+ * Copyright 2009 Sun Microsystems, 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+class HelloPathWorld {
+ public static void main(String... args) {
+ System.out.println("Hello World!");
+ }
+}
From d44fe667d85bdb441b8a976447c4eed33be14ae8 Mon Sep 17 00:00:00 2001
From: Kelly O'Hair
Date: Fri, 11 Dec 2009 15:29:22 -0800
Subject: [PATCH 071/221] 6909373: Add -ea to the testing done by
jdk/test/Makefile
Reviewed-by: darcy
---
jdk/test/Makefile | 15 +++++++++++----
jdk/test/ProblemList.txt | 24 ++++++++++++++++++++++++
2 files changed, 35 insertions(+), 4 deletions(-)
diff --git a/jdk/test/Makefile b/jdk/test/Makefile
index c3e0ad3a62c..bffa3ad7cb0 100644
--- a/jdk/test/Makefile
+++ b/jdk/test/Makefile
@@ -370,7 +370,8 @@ ifndef USE_JTREG_SAMEVM
endif
# With samevm, you cannot use -javaoptions?
ifeq ($(USE_JTREG_SAMEVM),true)
- EXTRA_JTREG_OPTIONS += -samevm $(JAVA_ARGS) $(JAVA_ARGS:%=-vmoption:%)
+ JTREG_SAMEVM_OPTION = -samevm
+ EXTRA_JTREG_OPTIONS += $(JTREG_SAMEVM_OPTION) $(JAVA_ARGS) $(JAVA_ARGS:%=-vmoption:%)
JTREG_TEST_OPTIONS = $(JAVA_VM_ARGS:%=-vmoption:%)
else
JTREG_TEST_OPTIONS = $(JAVA_ARGS:%=-javaoptions:%) $(JAVA_VM_ARGS:%=-vmoption:%)
@@ -600,16 +601,22 @@ JTREG = $(JT_HOME)/win32/bin/jtreg
JTREG_BASIC_OPTIONS += $(EXTRA_JTREG_OPTIONS)
# Only run automatic tests
JTREG_BASIC_OPTIONS += -a
+# Always turn on assertions
+JTREG_ASSERT_OPTION = -ea -esa
+JTREG_BASIC_OPTIONS += $(JTREG_ASSERT_OPTION)
# Report details on all failed or error tests, times too
JTREG_BASIC_OPTIONS += -v:fail,error,time
# Retain all files for failing tests
JTREG_BASIC_OPTIONS += -retain:fail,error
# Ignore tests are not run and completely silent about it
-JTREG_BASIC_OPTIONS += -ignore:quiet
+JTREG_IGNORE_OPTION = -ignore:quiet
+JTREG_BASIC_OPTIONS += $(JTREG_IGNORE_OPTION)
# Multiple by 4 the timeout numbers
-JTREG_BASIC_OPTIONS += -timeoutFactor:4
+JTREG_TIMEOUT_OPTION = -timeoutFactor:4
+JTREG_BASIC_OPTIONS += $(JTREG_TIMEOUT_OPTION)
# Boost the max memory for jtreg to avoid gc thrashing
-JTREG_BASIC_OPTIONS += -J-Xmx512m
+JTREG_MEMORY_OPTION = -J-Xmx512m
+JTREG_BASIC_OPTIONS += $(JTREG_MEMORY_OPTION)
# Make sure jtreg exists
$(JTREG): $(JT_HOME)
diff --git a/jdk/test/ProblemList.txt b/jdk/test/ProblemList.txt
index 3a5d2f10584..9cf24b2a5e1 100644
--- a/jdk/test/ProblemList.txt
+++ b/jdk/test/ProblemList.txt
@@ -586,6 +586,14 @@ javax/print/attribute/MediaMappingsTest.java generic-all
# Suspect many of these tests auffer from using fixed ports, no concrete
# evidence.
+# Dies on Solaris 10 sparc and sparcv9, Linux -ea -esa with
+# Interrupted or IO exception, maybe writing to non-unique named file?
+com/sun/net/httpserver/bugs/B6373555.java generic-all
+
+# Dies on pretty much all platforms when run with -ea -esa, Assertion error
+java/net/CookieHandler/TestHttpCookie.java generic-all
+java/net/URLClassLoader/closetest/CloseTest.java generic-all
+
# Fails on OpenSolaris, BindException unexpected
java/net/BindException/Test.java generic-all
@@ -732,6 +740,10 @@ java/net/ProxySelector/B6737819.java generic-all
# Suspect many of these tests auffer from using fixed ports, no concrete
# evidence.
+# Fails with -ea -esa, Assertion error, but only on Solaris 10 machines?
+com/sun/nio/sctp/SctpChannel/Send.java generic-all
+com/sun/nio/sctp/SctpChannel/Shutdown.java generic-all
+
# Fails on Windows 2000, Can't delete test directory .\x.SetLastModified.dir
# at SetLastModified.main(SetLastModified.java:107)
java/io/File/SetLastModified.java generic-all
@@ -924,6 +936,9 @@ java/rmi/server/UnicastRemoteObject/unexportObject/UnexportLeak.java generic-all
# jdk_security
+# Fails with -ea -esa, but only on Solaris sparc? Suspect it is timing out
+sun/security/tools/keytool/standard.sh generic-all
+
# Fails on Solaris 10 X64, address already in use
sun/security/krb5/auto/HttpNegotiateServer.java generic-all
@@ -1158,6 +1173,9 @@ java/text/Bidi/Bug6665028.java linux-x64
# So most if not all tools tests are now being run with "othervm" mode.
# Some of these tools tests have a tendency to use fixed ports, bad idea.
+# Fails with -ea -esa on Solaris, Assertion error (Solaris specific test)
+com/sun/tracing/BasicFunctionality.java generic-all
+
# Fails on Fedora 9 32bit, jps output differs problem
sun/tools/jstatd/jstatdDefaults.sh generic-all
@@ -1242,6 +1260,12 @@ tools/jar/index/MetaInf.java windows-all
# jdk_util
+# Fails with -ea -esa on all platforms with Assertion error
+java/util/ResourceBundle/Test4300693.java generic-all
+
+# Failing on all -client 32bit platforms starting with b77? See 6908348.
+java/util/concurrent/BlockingQueue/CancelledProducerConsumerLoops.java generic-all
+
# Assert error, failures, on Linux Fedora 9 -server
# Windows samevm failure, assert error "Passed = 134, failed = 2"
java/util/Arrays/ArrayObjectMethods.java generic-all
From d610594e7395dac5257f4512f5fc7654aa330063 Mon Sep 17 00:00:00 2001
From: Andrew John Hughes
Date: Fri, 11 Dec 2009 23:47:10 +0000
Subject: [PATCH 072/221] 6909442: Fix comments in
test/sun/tools/jhat/HatRun.java
Update the comments in this test to match the changes in 6902325
Reviewed-by: ohair
---
jdk/test/sun/tools/jhat/HatRun.java | 14 ++++++++------
1 file changed, 8 insertions(+), 6 deletions(-)
diff --git a/jdk/test/sun/tools/jhat/HatRun.java b/jdk/test/sun/tools/jhat/HatRun.java
index cb1e41b248e..41f6911291e 100644
--- a/jdk/test/sun/tools/jhat/HatRun.java
+++ b/jdk/test/sun/tools/jhat/HatRun.java
@@ -176,13 +176,15 @@ public class HatRun {
+ File.separator + "jhat";
/* Array of strings to be passed in for exec:
* 1. java
- * 2. -Dtest.classes=.
- * 3. -d64 (optional)
- * 4. -Xcheck:jni (Just because it finds bugs)
- * 5. -Xverify:all (Make sure verification is on full blast)
- * 6. -agent
+ * 2. -cp
+ * 3. cdir
+ * 4. -Dtest.classes=.
+ * 5. -d64 (optional)
+ * 6. -Xcheck:jni (Just because it finds bugs)
+ * 7. -Xverify:all (Make sure verification is on full blast)
+ * 8. -agent
* vm_options
- * 7+i. classname
+ * 9+i. classname
*/
int nvm_options = 0;
if ( vm_options != null ) nvm_options = vm_options.length;
From 8d1a5a5750d32a7e95040697a0e01d4fb05b5b14 Mon Sep 17 00:00:00 2001
From: Jonathan Gibbons
Date: Sat, 12 Dec 2009 09:28:40 -0800
Subject: [PATCH 073/221] 6907575: [classfile] add support for classfile
dependency analysis
Reviewed-by: ksrini
---
.../com/sun/tools/classfile/Dependencies.java | 718 ++++++++++++++++++
.../com/sun/tools/classfile/Dependency.java | 90 +++
.../tools/javap/classfile/deps/GetDeps.java | 211 +++++
.../tools/javap/classfile/deps/T6907575.java | 71 ++
.../tools/javap/classfile/deps/T6907575.out | 8 +
.../test/tools/javap/classfile/deps/p/C1.java | 37 +
6 files changed, 1135 insertions(+)
create mode 100644 langtools/src/share/classes/com/sun/tools/classfile/Dependencies.java
create mode 100644 langtools/src/share/classes/com/sun/tools/classfile/Dependency.java
create mode 100644 langtools/test/tools/javap/classfile/deps/GetDeps.java
create mode 100644 langtools/test/tools/javap/classfile/deps/T6907575.java
create mode 100644 langtools/test/tools/javap/classfile/deps/T6907575.out
create mode 100644 langtools/test/tools/javap/classfile/deps/p/C1.java
diff --git a/langtools/src/share/classes/com/sun/tools/classfile/Dependencies.java b/langtools/src/share/classes/com/sun/tools/classfile/Dependencies.java
new file mode 100644
index 00000000000..4daa6ac8d15
--- /dev/null
+++ b/langtools/src/share/classes/com/sun/tools/classfile/Dependencies.java
@@ -0,0 +1,718 @@
+/*
+ * Copyright 2009 Sun Microsystems, 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. Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+package com.sun.tools.classfile;
+
+import java.util.Deque;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.regex.Pattern;
+
+import com.sun.tools.classfile.Dependency.Finder;
+import com.sun.tools.classfile.Dependency.Filter;
+import com.sun.tools.classfile.Dependency.Location;
+import com.sun.tools.classfile.Type.ArrayType;
+import com.sun.tools.classfile.Type.ClassSigType;
+import com.sun.tools.classfile.Type.ClassType;
+import com.sun.tools.classfile.Type.MethodType;
+import com.sun.tools.classfile.Type.SimpleType;
+import com.sun.tools.classfile.Type.TypeParamType;
+import com.sun.tools.classfile.Type.WildcardType;
+
+import static com.sun.tools.classfile.ConstantPool.*;
+
+/**
+ * A framework for determining {@link Dependency dependencies} between class files.
+ *
+ * A {@link Dependency.Finder finder} is used to identify the dependencies of
+ * individual classes. Some finders may return subtypes of {@code Dependency} to
+ * further characterize the type of dependency, such as a dependency on a
+ * method within a class.
+ *
+ * A {@link Dependency.Filter filter} may be used to restrict the set of
+ * dependencies found by a finder.
+ *
+ * Dependencies that are found may be passed to a {@link Dependencies.Recorder
+ * recorder} so that the dependencies can be stored in a custom data structure.
+ */
+public class Dependencies {
+ /**
+ * Thrown when a class file cannot be found.
+ */
+ public static class ClassFileNotFoundException extends Exception {
+ private static final long serialVersionUID = 3632265927794475048L;
+
+ public ClassFileNotFoundException(String className) {
+ super(className);
+ this.className = className;
+ }
+
+ public ClassFileNotFoundException(String className, Throwable cause) {
+ this(className);
+ initCause(cause);
+ }
+
+ public final String className;
+ }
+
+ /**
+ * Thrown when an exception is found processing a class file.
+ */
+ public static class ClassFileError extends Error {
+ private static final long serialVersionUID = 4111110813961313203L;
+
+ public ClassFileError(Throwable cause) {
+ initCause(cause);
+ }
+ }
+
+ /**
+ * Service provider interface to locate and read class files.
+ */
+ public interface ClassFileReader {
+ /**
+ * Get the ClassFile object for a specified class.
+ * @param className the name of the class to be returned.
+ * @return the ClassFile for the given class
+ * @throws Dependencies#ClassFileNotFoundException if the classfile cannot be
+ * found
+ */
+ public ClassFile getClassFile(String className)
+ throws ClassFileNotFoundException;
+ }
+
+ /**
+ * Service provide interface to handle results.
+ */
+ public interface Recorder {
+ /**
+ * Record a dependency that has been found.
+ * @param d
+ */
+ public void addDependency(Dependency d);
+ }
+
+ /**
+ * Get the default finder used to locate the dependencies for a class.
+ * @return the default finder
+ */
+ public static Finder getDefaultFinder() {
+ return new APIDependencyFinder(AccessFlags.ACC_PRIVATE);
+ }
+
+ /**
+ * Get a finder used to locate the API dependencies for a class.
+ * These include the superclass, superinterfaces, and classes referenced in
+ * the declarations of fields and methods. The fields and methods that
+ * are checked can be limited according to a specified access.
+ * The access parameter must be one of {@link AccessFlags#ACC_PUBLIC ACC_PUBLIC},
+ * {@link AccessFlags#ACC_PRIVATE ACC_PRIVATE},
+ * {@link AccessFlags#ACC_PROTECTED ACC_PROTECTED}, or 0 for
+ * package private access. Members with greater than or equal accessibility
+ * to that specified will be searched for dependencies.
+ * @param access the access of members to be checked
+ * @return an API finder
+ */
+ public static Finder getAPIFinder(int access) {
+ return new APIDependencyFinder(access);
+ }
+
+ /**
+ * Get the finder used to locate the dependencies for a class.
+ * @return the finder
+ */
+ public Finder getFinder() {
+ if (finder == null)
+ finder = getDefaultFinder();
+ return finder;
+ }
+
+ /**
+ * Set the finder used to locate the dependencies for a class.
+ * @param f the finder
+ */
+ public void setFinder(Finder f) {
+ f.getClass(); // null check
+ finder = f;
+ }
+
+ /**
+ * Get the default filter used to determine included when searching
+ * the transitive closure of all the dependencies.
+ * Unless overridden, the default filter accepts all dependencies.
+ * @return the default filter.
+ */
+ public static Filter getDefaultFilter() {
+ return DefaultFilter.instance();
+ }
+
+ /**
+ * Get a filter which uses a regular expression on the target's class name
+ * to determine if a dependency is of interest.
+ * @param pattern the pattern used to match the target's class name
+ * @return a filter for matching the target class name with a regular expression
+ */
+ public static Filter getRegexFilter(Pattern pattern) {
+ return new TargetRegexFilter(pattern);
+ }
+
+ /**
+ * Get a filter which checks the package of a target's class name
+ * to determine if a dependency is of interest. The filter checks if the
+ * package of the target's class matches any of a set of given package
+ * names. The match may optionally match subpackages of the given names as well.
+ * @param packageNames the package names used to match the target's class name
+ * @param matchSubpackages whether or not to match subpackages as well
+ * @return a filter for checking the target package name against a list of package names
+ */
+ public static Filter getPackageFilter(Set packageNames, boolean matchSubpackages) {
+ return new TargetPackageFilter(packageNames, matchSubpackages);
+ }
+
+ /**
+ * Get the filter used to determine the dependencies included when searching
+ * the transitive closure of all the dependencies.
+ * Unless overridden, the default filter accepts all dependencies.
+ * @return the filter
+ */
+ public Filter getFilter() {
+ if (filter == null)
+ filter = getDefaultFilter();
+ return filter;
+ }
+
+ /**
+ * Set the filter used to determine the dependencies included when searching
+ * the transitive closure of all the dependencies.
+ * @param f the filter
+ */
+ public void setFilter(Filter f) {
+ f.getClass(); // null check
+ filter = f;
+ }
+
+ /**
+ * Find the dependencies of a class, using the current
+ * {@link Dependencies#getFinder finder} and
+ * {@link Dependencies#getFilter filter}.
+ * The search may optionally include the transitive closure of all the
+ * filtered dependencies, by also searching in the classes named in those
+ * dependencies.
+ * @param classFinder a finder to locate class files
+ * @param rootClassNames the names of the root classes from which to begin
+ * searching
+ * @param transitiveClosure whether or not to also search those classes
+ * named in any filtered dependencies that are found.
+ * @return the set of dependencies that were found
+ * @throws ClassFileNotFoundException if a required class file cannot be found
+ * @throws ClassFileError if an error occurs while processing a class file,
+ * such as an error in the internal class file structure.
+ */
+ public Set findAllDependencies(
+ ClassFileReader classFinder, Set rootClassNames,
+ boolean transitiveClosure)
+ throws ClassFileNotFoundException {
+ final Set results = new HashSet();
+ Recorder r = new Recorder() {
+ public void addDependency(Dependency d) {
+ results.add(d);
+ }
+ };
+ findAllDependencies(classFinder, rootClassNames, transitiveClosure, r);
+ return results;
+ }
+
+
+
+ /**
+ * Find the dependencies of a class, using the current
+ * {@link Dependencies#getFinder finder} and
+ * {@link Dependencies#getFilter filter}.
+ * The search may optionally include the transitive closure of all the
+ * filtered dependencies, by also searching in the classes named in those
+ * dependencies.
+ * @param classFinder a finder to locate class files
+ * @param rootClassNames the names of the root classes from which to begin
+ * searching
+ * @param transitiveClosure whether or not to also search those classes
+ * named in any filtered dependencies that are found.
+ * @param recorder a recorder for handling the results
+ * @throws ClassFileNotFoundException if a required class file cannot be found
+ * @throws ClassFileError if an error occurs while processing a class file,
+ * such as an error in the internal class file structure.
+ */
+ public void findAllDependencies(
+ ClassFileReader classFinder, Set rootClassNames,
+ boolean transitiveClosure, Recorder recorder)
+ throws ClassFileNotFoundException {
+ Set doneClasses = new HashSet();
+
+ getFinder(); // ensure initialized
+ getFilter(); // ensure initialized
+
+ // Work queue of names of classfiles to be searched.
+ // Entries will be unique, and for classes that do not yet have
+ // dependencies in the results map.
+ Deque deque = new LinkedList(rootClassNames);
+
+ String className;
+ while ((className = deque.poll()) != null) {
+ assert (!doneClasses.contains(className));
+ doneClasses.add(className);
+
+ ClassFile cf = classFinder.getClassFile(className);
+
+ // The following code just applies the filter to the dependencies
+ // followed for the transitive closure.
+ for (Dependency d: finder.findDependencies(cf)) {
+ recorder.addDependency(d);
+ if (transitiveClosure && filter.accepts(d)) {
+ String cn = d.getTarget().getClassName();
+ if (!doneClasses.contains(cn))
+ deque.add(cn);
+ }
+ }
+ }
+ }
+
+ private Filter filter;
+ private Finder finder;
+
+ /**
+ * A location identifying a class.
+ */
+ static class SimpleLocation implements Location {
+ public SimpleLocation(String className) {
+ this.className = className;
+ }
+
+ /**
+ * Get the name of the class being depended on. This name will be used to
+ * locate the class file for transitive dependency analysis.
+ * @return the name of the class being depended on
+ */
+ public String getClassName() {
+ return className;
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ if (this == other)
+ return true;
+ if (!(other instanceof SimpleLocation))
+ return false;
+ return (className.equals(((SimpleLocation) other).className));
+ }
+
+ @Override
+ public int hashCode() {
+ return className.hashCode();
+ }
+
+ @Override
+ public String toString() {
+ return className;
+ }
+
+ private String className;
+ }
+
+ /**
+ * A dependency of one class on another.
+ */
+ static class SimpleDependency implements Dependency {
+ public SimpleDependency(Location origin, Location target) {
+ this.origin = origin;
+ this.target = target;
+ }
+
+ public Location getOrigin() {
+ return origin;
+ }
+
+ public Location getTarget() {
+ return target;
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ if (this == other)
+ return true;
+ if (!(other instanceof SimpleDependency))
+ return false;
+ SimpleDependency o = (SimpleDependency) other;
+ return (origin.equals(o.origin) && target.equals(o.target));
+ }
+
+ @Override
+ public int hashCode() {
+ return origin.hashCode() * 31 + target.hashCode();
+ }
+
+ @Override
+ public String toString() {
+ return origin + ":" + target;
+ }
+
+ private Location origin;
+ private Location target;
+ }
+
+
+ /**
+ * This class accepts all dependencies.
+ */
+ static class DefaultFilter implements Filter {
+ private static DefaultFilter instance;
+
+ static DefaultFilter instance() {
+ if (instance == null)
+ instance = new DefaultFilter();
+ return instance;
+ }
+
+ public boolean accepts(Dependency dependency) {
+ return true;
+ }
+ }
+
+ /**
+ * This class accepts those dependencies whose target's class name matches a
+ * regular expression.
+ */
+ static class TargetRegexFilter implements Filter {
+ TargetRegexFilter(Pattern pattern) {
+ this.pattern = pattern;
+ }
+
+ public boolean accepts(Dependency dependency) {
+ return pattern.matcher(dependency.getTarget().getClassName()).matches();
+ }
+
+ Pattern pattern;
+ }
+
+ /**
+ * This class accepts those dependencies whose class name is in a given
+ * package.
+ */
+ static class TargetPackageFilter implements Filter {
+ TargetPackageFilter(Set packageNames, boolean matchSubpackages) {
+ for (String pn: packageNames) {
+ if (pn.length() == 0) // implies null check as well
+ throw new IllegalArgumentException();
+ }
+ this.packageNames = packageNames;
+ this.matchSubpackages = matchSubpackages;
+ }
+
+ public boolean accepts(Dependency dependency) {
+ String cn = dependency.getTarget().getClassName();
+ int lastSep = cn.lastIndexOf("/");
+ String pn = (lastSep == -1 ? "" : cn.substring(0, lastSep));
+ if (packageNames.contains(pn))
+ return true;
+
+ if (matchSubpackages) {
+ for (String n: packageNames) {
+ if (pn.startsWith(n + "."))
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ Set packageNames;
+ boolean matchSubpackages;
+ }
+
+
+
+ /**
+ * This class identifies class names directly or indirectly in the constant pool.
+ */
+ static class ClassDependencyFinder extends BasicDependencyFinder {
+ public Iterable extends Dependency> findDependencies(ClassFile classfile) {
+ Visitor v = new Visitor(classfile);
+ for (CPInfo cpInfo: classfile.constant_pool.entries()) {
+ v.scan(cpInfo);
+ }
+ return v.deps;
+ }
+ }
+
+ /**
+ * This class identifies class names in the signatures of classes, fields,
+ * and methods in a class.
+ */
+ static class APIDependencyFinder extends BasicDependencyFinder {
+ APIDependencyFinder(int access) {
+ switch (access) {
+ case AccessFlags.ACC_PUBLIC:
+ case AccessFlags.ACC_PROTECTED:
+ case AccessFlags.ACC_PRIVATE:
+ case 0:
+ showAccess = access;
+ break;
+ default:
+ throw new IllegalArgumentException("invalid access 0x"
+ + Integer.toHexString(access));
+ }
+ }
+
+ public Iterable extends Dependency> findDependencies(ClassFile classfile) {
+ try {
+ Visitor v = new Visitor(classfile);
+ v.addClass(classfile.super_class);
+ v.addClasses(classfile.interfaces);
+ // inner classes?
+ for (Field f : classfile.fields) {
+ if (checkAccess(f.access_flags))
+ v.scan(f.descriptor, f.attributes);
+ }
+ for (Method m : classfile.methods) {
+ if (checkAccess(m.access_flags)) {
+ v.scan(m.descriptor, m.attributes);
+ Exceptions_attribute e =
+ (Exceptions_attribute) m.attributes.get(Attribute.Exceptions);
+ if (e != null)
+ v.addClasses(e.exception_index_table);
+ }
+ }
+ return v.deps;
+ } catch (ConstantPoolException e) {
+ throw new ClassFileError(e);
+ }
+ }
+
+ boolean checkAccess(AccessFlags flags) {
+ // code copied from javap.Options.checkAccess
+ boolean isPublic = flags.is(AccessFlags.ACC_PUBLIC);
+ boolean isProtected = flags.is(AccessFlags.ACC_PROTECTED);
+ boolean isPrivate = flags.is(AccessFlags.ACC_PRIVATE);
+ boolean isPackage = !(isPublic || isProtected || isPrivate);
+
+ if ((showAccess == AccessFlags.ACC_PUBLIC) && (isProtected || isPrivate || isPackage))
+ return false;
+ else if ((showAccess == AccessFlags.ACC_PROTECTED) && (isPrivate || isPackage))
+ return false;
+ else if ((showAccess == 0) && (isPrivate))
+ return false;
+ else
+ return true;
+ }
+
+ private int showAccess;
+ }
+
+ static abstract class BasicDependencyFinder implements Finder {
+ private Map locations = new HashMap();
+
+ Location getLocation(String className) {
+ Location l = locations.get(className);
+ if (l == null)
+ locations.put(className, l = new SimpleLocation(className));
+ return l;
+ }
+
+ class Visitor implements ConstantPool.Visitor, Type.Visitor {
+ private ConstantPool constant_pool;
+ private Set deps;
+ private Location origin;
+
+ Visitor(ClassFile classFile) {
+ try {
+ constant_pool = classFile.constant_pool;
+ origin = getLocation(classFile.getName());
+ deps = new HashSet();
+ } catch (ConstantPoolException e) {
+ throw new ClassFileError(e);
+ }
+ }
+
+ void scan(Descriptor d, Attributes attrs) {
+ try {
+ scan(new Signature(d.index).getType(constant_pool));
+ Signature_attribute sa = (Signature_attribute) attrs.get(Attribute.Signature);
+ if (sa != null)
+ scan(new Signature(sa.signature_index).getType(constant_pool));
+ } catch (ConstantPoolException e) {
+ throw new ClassFileError(e);
+ }
+ }
+
+ void scan(CPInfo cpInfo) {
+ cpInfo.accept(this, null);
+ }
+
+ void scan(Type t) {
+ t.accept(this, null);
+ }
+
+ void addClass(int index) throws ConstantPoolException {
+ if (index != 0) {
+ String name = constant_pool.getClassInfo(index).getBaseName();
+ if (name != null)
+ addDependency(name);
+ }
+ }
+
+ void addClasses(int[] indices) throws ConstantPoolException {
+ for (int i: indices)
+ addClass(i);
+ }
+
+ private void addDependency(String name) {
+ deps.add(new SimpleDependency(origin, getLocation(name)));
+ }
+
+ // ConstantPool.Visitor methods
+
+ public Void visitClass(CONSTANT_Class_info info, Void p) {
+ try {
+ if (info.getName().startsWith("["))
+ new Signature(info.name_index).getType(constant_pool).accept(this, null);
+ else
+ addDependency(info.getBaseName());
+ return null;
+ } catch (ConstantPoolException e) {
+ throw new ClassFileError(e);
+ }
+ }
+
+ public Void visitDouble(CONSTANT_Double_info info, Void p) {
+ return null;
+ }
+
+ public Void visitFieldref(CONSTANT_Fieldref_info info, Void p) {
+ return visitRef(info, p);
+ }
+
+ public Void visitFloat(CONSTANT_Float_info info, Void p) {
+ return null;
+ }
+
+ public Void visitInteger(CONSTANT_Integer_info info, Void p) {
+ return null;
+ }
+
+ public Void visitInterfaceMethodref(CONSTANT_InterfaceMethodref_info info, Void p) {
+ return visitRef(info, p);
+ }
+
+ public Void visitLong(CONSTANT_Long_info info, Void p) {
+ return null;
+ }
+
+ public Void visitNameAndType(CONSTANT_NameAndType_info info, Void p) {
+ try {
+ new Signature(info.type_index).getType(constant_pool).accept(this, null);
+ return null;
+ } catch (ConstantPoolException e) {
+ throw new ClassFileError(e);
+ }
+ }
+
+ public Void visitMethodref(CONSTANT_Methodref_info info, Void p) {
+ return visitRef(info, p);
+ }
+
+ public Void visitString(CONSTANT_String_info info, Void p) {
+ return null;
+ }
+
+ public Void visitUtf8(CONSTANT_Utf8_info info, Void p) {
+ return null;
+ }
+
+ private Void visitRef(CPRefInfo info, Void p) {
+ try {
+ visitClass(info.getClassInfo(), p);
+ return null;
+ } catch (ConstantPoolException e) {
+ throw new ClassFileError(e);
+ }
+ }
+
+ // Type.Visitor methods
+
+ private void findDependencies(Type t) {
+ if (t != null)
+ t.accept(this, null);
+ }
+
+ private void findDependencies(List extends Type> ts) {
+ if (ts != null) {
+ for (Type t: ts)
+ t.accept(this, null);
+ }
+ }
+
+ public Void visitSimpleType(SimpleType type, Void p) {
+ return null;
+ }
+
+ public Void visitArrayType(ArrayType type, Void p) {
+ findDependencies(type.elemType);
+ return null;
+ }
+
+ public Void visitMethodType(MethodType type, Void p) {
+ findDependencies(type.paramTypes);
+ findDependencies(type.returnType);
+ findDependencies(type.throwsTypes);
+ return null;
+ }
+
+ public Void visitClassSigType(ClassSigType type, Void p) {
+ findDependencies(type.superclassType);
+ findDependencies(type.superinterfaceTypes);
+ return null;
+ }
+
+ public Void visitClassType(ClassType type, Void p) {
+ findDependencies(type.outerType);
+ addDependency(type.name);
+ findDependencies(type.typeArgs);
+ return null;
+ }
+
+ public Void visitTypeParamType(TypeParamType type, Void p) {
+ findDependencies(type.classBound);
+ findDependencies(type.interfaceBounds);
+ return null;
+ }
+
+ public Void visitWildcardType(WildcardType type, Void p) {
+ findDependencies(type.boundType);
+ return null;
+ }
+ }
+ }
+}
diff --git a/langtools/src/share/classes/com/sun/tools/classfile/Dependency.java b/langtools/src/share/classes/com/sun/tools/classfile/Dependency.java
new file mode 100644
index 00000000000..b145f8081b9
--- /dev/null
+++ b/langtools/src/share/classes/com/sun/tools/classfile/Dependency.java
@@ -0,0 +1,90 @@
+/*
+ * Copyright 2009 Sun Microsystems, 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. Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package com.sun.tools.classfile;
+
+
+/**
+ * A directed relationship between two {@link Dependency.Location Location}s.
+ * Subtypes of {@code Dependency} may provide additional detail about the dependency.
+ *
+ * @see Dependency.Finder
+ * @see Dependency.Filter
+ * @see Dependencies
+ */
+public interface Dependency {
+ /**
+ * A filter used to select dependencies of interest, and to discard others.
+ */
+ public interface Filter {
+ /**
+ * Return true if the dependency is of interest.
+ * @param dependency the dependency to be considered
+ * @return true if and only if the dependency is of interest.
+ */
+ boolean accepts(Dependency dependency);
+ }
+
+ /**
+ * An interface for finding the immediate dependencies of a given class file.
+ */
+ public interface Finder {
+ /**
+ * Find the immediate dependencies of a given class file.
+ * @param classfile the class file to be examined
+ * @return the set of dependencies located in the given class file.
+ */
+ public Iterable extends Dependency> findDependencies(ClassFile classfile);
+ }
+
+
+ /**
+ * A location somewhere within a class. Subtypes of {@code Location}
+ * may be used to provide additional detail about the location.
+ */
+ public interface Location {
+ /**
+ * Get the name of the class containing the location.
+ * This name will be used to locate the class file for transitive
+ * dependency analysis.
+ * @return the name of the class containing the location.
+ */
+ String getClassName();
+ }
+
+
+ /**
+ * Get the location that has the dependency.
+ * @return the location that has the dependency.
+ */
+ Location getOrigin();
+
+ /**
+ * Get the location that is being depended upon.
+ * @return the location that is being depended upon.
+ */
+ Location getTarget();
+}
+
diff --git a/langtools/test/tools/javap/classfile/deps/GetDeps.java b/langtools/test/tools/javap/classfile/deps/GetDeps.java
new file mode 100644
index 00000000000..f5db9770ce6
--- /dev/null
+++ b/langtools/test/tools/javap/classfile/deps/GetDeps.java
@@ -0,0 +1,211 @@
+/*
+ * Copyright 2009 Sun Microsystems, 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. Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+import java.io.*;
+import java.util.*;
+import java.util.regex.Pattern;
+import javax.tools.*;
+
+import com.sun.tools.classfile.*;
+import com.sun.tools.classfile.Dependencies.*;
+import com.sun.tools.classfile.Dependency.Location;
+import com.sun.tools.javac.file.JavacFileManager;
+import com.sun.tools.javac.util.Context;
+
+/**
+ * Demo utility for using the classfile dependency analysis API framework.
+ *
+ * Usage:
+ * getdeps [options] classes
+ * where options include:
+ * -classpath path where to find classes to analyze
+ * -p package-name restrict analysis to classes in this package
+ * (may be given multiple times)
+ * -r regex restrict analysis to packages matching pattern
+ * (-p and -r are exclusive)
+ * -rev invert the dependencies in the output
+ * -t transitive closure of dependencies
+ */
+public class GetDeps {
+ public static void main(String... args) throws Exception {
+ new GetDeps().run(args);
+ }
+
+ void run(String... args) throws IOException, ClassFileNotFoundException {
+ PrintWriter pw = new PrintWriter(System.out);
+ try {
+ run(pw, args);
+ } finally {
+ pw.flush();
+ }
+ }
+
+ void run(PrintWriter out, String... args) throws IOException, ClassFileNotFoundException {
+ decodeArgs(args);
+
+ final StandardJavaFileManager fm = new JavacFileManager(new Context(), false, null);
+ if (classpath != null)
+ fm.setLocation(StandardLocation.CLASS_PATH, classpath);
+
+ ClassFileReader reader = new ClassFileReader(fm);
+
+ Dependencies d = new Dependencies();
+
+ if (regex != null)
+ d.setFilter(Dependencies.getRegexFilter(Pattern.compile(regex)));
+
+ if (packageNames.size() > 0)
+ d.setFilter(Dependencies.getPackageFilter(packageNames, false));
+
+ SortedRecorder r = new SortedRecorder(reverse);
+
+ d.findAllDependencies(reader, rootClassNames, transitiveClosure, r);
+
+ SortedMap> deps = r.getMap();
+ for (Map.Entry> e: deps.entrySet()) {
+ out.println(e.getKey());
+ for (Dependency dep: e.getValue()) {
+ out.println(" " + dep.getTarget());
+ }
+ }
+ }
+
+ void decodeArgs(String... args) {
+ rootClassNames = new TreeSet();
+ packageNames = new TreeSet();
+
+ for (int i = 0; i < args.length; i++) {
+ String arg = args[i];
+ if (arg.equals("-classpath") && (i + 1 < args.length))
+ classpath = getPathFiles(args[++i]);
+ else if (arg.equals("-p") && (i + 1 < args.length))
+ packageNames.add(args[++i]);
+ else if (arg.equals("-r") && (i + 1 < args.length))
+ regex = args[++i];
+ else if (arg.equals("-rev"))
+ reverse = true;
+ else if (arg.equals("-t"))
+ transitiveClosure = true;
+ else if (arg.startsWith("-"))
+ throw new Error(arg);
+ else {
+ for ( ; i < args.length; i++)
+ rootClassNames.add(args[i]);
+ }
+ }
+ }
+
+ List getPathFiles(String path) {
+ List files = new ArrayList();
+ for (String p: path.split(File.pathSeparator)) {
+ if (p.length() > 0)
+ files.add(new File(p));
+ }
+ return files;
+ }
+
+ boolean transitiveClosure;
+ List classpath;
+ Set rootClassNames;
+ Set packageNames;
+ String regex;
+ boolean reverse;
+
+
+ static class ClassFileReader implements Dependencies.ClassFileReader {
+ private JavaFileManager fm;
+
+ ClassFileReader(JavaFileManager fm) {
+ this.fm = fm;
+ }
+
+ @Override
+ public ClassFile getClassFile(String className) throws ClassFileNotFoundException {
+ try {
+ JavaFileObject fo = fm.getJavaFileForInput(
+ StandardLocation.CLASS_PATH, className, JavaFileObject.Kind.CLASS);
+ if (fo == null)
+ fo = fm.getJavaFileForInput(
+ StandardLocation.PLATFORM_CLASS_PATH, className, JavaFileObject.Kind.CLASS);
+ if (fo == null)
+ throw new ClassFileNotFoundException(className);
+ InputStream in = fo.openInputStream();
+ try {
+ return ClassFile.read(in);
+ } finally {
+ in.close();
+ }
+ } catch (ConstantPoolException e) {
+ throw new ClassFileNotFoundException(className, e);
+ } catch (IOException e) {
+ throw new ClassFileNotFoundException(className, e);
+ }
+ }
+ };
+
+ static class SortedRecorder implements Recorder {
+ public SortedRecorder(boolean reverse) {
+ this.reverse = reverse;
+ }
+
+ public void addDependency(Dependency d) {
+ Location o = (reverse ? d.getTarget() : d.getOrigin());
+ SortedSet odeps = map.get(o);
+ if (odeps == null) {
+ Comparator c = (reverse ? originComparator : targetComparator);
+ map.put(o, odeps = new TreeSet(c));
+ }
+ odeps.add(d);
+ }
+
+ public SortedMap> getMap() {
+ return map;
+ }
+
+ private Comparator originComparator = new Comparator() {
+ public int compare(Dependency o1, Dependency o2) {
+ return o1.getTarget().toString().compareTo(o2.getOrigin().toString());
+ }
+ };
+
+ private Comparator targetComparator = new Comparator() {
+ public int compare(Dependency o1, Dependency o2) {
+ return o1.getTarget().toString().compareTo(o2.getTarget().toString());
+ }
+ };
+
+ private Comparator locationComparator = new Comparator() {
+ public int compare(Location o1, Location o2) {
+ return o1.toString().compareTo(o2.toString());
+ }
+ };
+
+ private final SortedMap> map =
+ new TreeMap>(locationComparator);
+
+ boolean reverse;
+ }
+
+}
diff --git a/langtools/test/tools/javap/classfile/deps/T6907575.java b/langtools/test/tools/javap/classfile/deps/T6907575.java
new file mode 100644
index 00000000000..23983ec7928
--- /dev/null
+++ b/langtools/test/tools/javap/classfile/deps/T6907575.java
@@ -0,0 +1,71 @@
+/*
+ * Copyright 2009 Sun Microsystems, 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. Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+/*
+ * @test
+ * @bug 6907575
+ * @build GetDeps p.C1
+ * @run main T6907575
+ */
+
+import java.io.*;
+
+public class T6907575 {
+ public static void main(String... args) throws Exception {
+ new T6907575().run();
+ }
+
+ void run() throws Exception {
+ String testSrc = System.getProperty("test.src");
+ String testClasses = System.getProperty("test.classes");
+
+ StringWriter sw = new StringWriter();
+ PrintWriter pw = new PrintWriter(sw);
+ GetDeps gd = new GetDeps();
+ gd.run(pw, "-classpath", testClasses, "-t", "-p", "p", "p/C1");
+ pw.close();
+ System.out.println(sw);
+
+ String ref = readFile(new File(testSrc, "T6907575.out"));
+ diff(sw.toString().replaceAll("[\r\n]+", "\n"), ref);
+ }
+
+ void diff(String actual, String ref) throws Exception {
+ System.out.println("EXPECT:>>>" + ref + "<<<");
+ System.out.println("ACTUAL:>>>" + actual + "<<<");
+ if (!actual.equals(ref))
+ throw new Exception("output not as expected");
+ }
+
+ String readFile(File f) throws IOException {
+ Reader r = new FileReader(f);
+ char[] buf = new char[(int) f.length()];
+ int offset = 0;
+ int n;
+ while (offset < buf.length && (n = r.read(buf, offset, buf.length - offset)) != -1)
+ offset += n;
+ return new String(buf, 0, offset);
+ }
+}
diff --git a/langtools/test/tools/javap/classfile/deps/T6907575.out b/langtools/test/tools/javap/classfile/deps/T6907575.out
new file mode 100644
index 00000000000..f1315914eb1
--- /dev/null
+++ b/langtools/test/tools/javap/classfile/deps/T6907575.out
@@ -0,0 +1,8 @@
+p/C1
+ java/lang/Object
+ p/C2
+p/C2
+ java/lang/Object
+ p/C3
+p/C3
+ java/lang/Object
diff --git a/langtools/test/tools/javap/classfile/deps/p/C1.java b/langtools/test/tools/javap/classfile/deps/p/C1.java
new file mode 100644
index 00000000000..71f253e128b
--- /dev/null
+++ b/langtools/test/tools/javap/classfile/deps/p/C1.java
@@ -0,0 +1,37 @@
+/*
+ * Copyright 2009 Sun Microsystems, 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. Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package p;
+
+public class C1 {
+ C2 c2;
+}
+
+class C2 {
+ C3 c3;
+}
+
+class C3 {
+}
From 8dd1b6ace1b426723b80eee9328f25da8f3a805e Mon Sep 17 00:00:00 2001
From: "Daniel D. Daugherty"
Date: Mon, 14 Dec 2009 09:51:09 -0700
Subject: [PATCH 074/221] 6648438: 4/4 src/share/vm/prims/jvmtiEnv.cpp:457
assert(phase == JVMTI_PHASE_LIVE,"sanity check")
Return error on invalid JVMTI_PHASE instead of asserting.
Reviewed-by: dholmes, ohair
---
hotspot/src/share/vm/prims/jvmtiEnv.cpp | 19 +++++++++++++------
1 file changed, 13 insertions(+), 6 deletions(-)
diff --git a/hotspot/src/share/vm/prims/jvmtiEnv.cpp b/hotspot/src/share/vm/prims/jvmtiEnv.cpp
index a19c48972c8..77d63520d95 100644
--- a/hotspot/src/share/vm/prims/jvmtiEnv.cpp
+++ b/hotspot/src/share/vm/prims/jvmtiEnv.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright 2003-2007 Sun Microsystems, Inc. All Rights Reserved.
+ * Copyright 2003-2009 Sun Microsystems, 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
@@ -408,8 +408,10 @@ JvmtiEnv::AddToBootstrapClassLoaderSearch(const char* segment) {
if (phase == JVMTI_PHASE_ONLOAD) {
Arguments::append_sysclasspath(segment);
return JVMTI_ERROR_NONE;
- } else {
- assert(phase == JVMTI_PHASE_LIVE, "sanity check");
+ } else if (phase == JVMTI_PHASE_LIVE) {
+ // The phase is checked by the wrapper that called this function,
+ // but this thread could be racing with the thread that is
+ // terminating the VM so we check one more time.
// create the zip entry
ClassPathZipEntry* zip_entry = ClassLoader::create_class_path_zip_entry(segment);
@@ -430,6 +432,8 @@ JvmtiEnv::AddToBootstrapClassLoaderSearch(const char* segment) {
}
ClassLoader::add_to_list(zip_entry);
return JVMTI_ERROR_NONE;
+ } else {
+ return JVMTI_ERROR_WRONG_PHASE;
}
} /* end AddToBootstrapClassLoaderSearch */
@@ -448,11 +452,12 @@ JvmtiEnv::AddToSystemClassLoaderSearch(const char* segment) {
}
}
return JVMTI_ERROR_NONE;
- } else {
+ } else if (phase == JVMTI_PHASE_LIVE) {
+ // The phase is checked by the wrapper that called this function,
+ // but this thread could be racing with the thread that is
+ // terminating the VM so we check one more time.
HandleMark hm;
- assert(phase == JVMTI_PHASE_LIVE, "sanity check");
-
// create the zip entry (which will open the zip file and hence
// check that the segment is indeed a zip file).
ClassPathZipEntry* zip_entry = ClassLoader::create_class_path_zip_entry(segment);
@@ -501,6 +506,8 @@ JvmtiEnv::AddToSystemClassLoaderSearch(const char* segment) {
}
return JVMTI_ERROR_NONE;
+ } else {
+ return JVMTI_ERROR_WRONG_PHASE;
}
} /* end AddToSystemClassLoaderSearch */
From ce7894453911dc2fa08a9b460562c614cb2ab4b7 Mon Sep 17 00:00:00 2001
From: "Daniel D. Daugherty"
Date: Mon, 14 Dec 2009 10:05:36 -0700
Subject: [PATCH 075/221] 6849968: 3/2 JVMTI tests fails on jdk5.0 with hs14
If a JVMTI agent asks for version 1.0, then it should get version 1.0 semantics.
Reviewed-by: dholmes, ohair
---
hotspot/src/share/vm/prims/jvmtiEnv.cpp | 19 +++++++++--
hotspot/src/share/vm/prims/jvmtiEnvBase.cpp | 23 ++++++++++++--
hotspot/src/share/vm/prims/jvmtiEnvBase.hpp | 8 +++--
hotspot/src/share/vm/prims/jvmtiExport.cpp | 35 +++++++++++++++++++--
hotspot/src/share/vm/prims/jvmtiExport.hpp | 4 ++-
hotspot/src/share/vm/prims/jvmtiHpp.xsl | 6 ++--
6 files changed, 81 insertions(+), 14 deletions(-)
diff --git a/hotspot/src/share/vm/prims/jvmtiEnv.cpp b/hotspot/src/share/vm/prims/jvmtiEnv.cpp
index 77d63520d95..3de748f216e 100644
--- a/hotspot/src/share/vm/prims/jvmtiEnv.cpp
+++ b/hotspot/src/share/vm/prims/jvmtiEnv.cpp
@@ -32,15 +32,15 @@
// FIXLATER: hook into JvmtiTrace
#define TraceJVMTICalls false
-JvmtiEnv::JvmtiEnv() : JvmtiEnvBase() {
+JvmtiEnv::JvmtiEnv(jint version) : JvmtiEnvBase(version) {
}
JvmtiEnv::~JvmtiEnv() {
}
JvmtiEnv*
-JvmtiEnv::create_a_jvmti() {
- return new JvmtiEnv();
+JvmtiEnv::create_a_jvmti(jint version) {
+ return new JvmtiEnv(version);
}
// VM operation class to copy jni function table at safepoint.
@@ -408,6 +408,11 @@ JvmtiEnv::AddToBootstrapClassLoaderSearch(const char* segment) {
if (phase == JVMTI_PHASE_ONLOAD) {
Arguments::append_sysclasspath(segment);
return JVMTI_ERROR_NONE;
+ } else if (use_version_1_0_semantics()) {
+ // This JvmtiEnv requested version 1.0 semantics and this function
+ // is only allowed in the ONLOAD phase in version 1.0 so we need to
+ // return an error here.
+ return JVMTI_ERROR_WRONG_PHASE;
} else if (phase == JVMTI_PHASE_LIVE) {
// The phase is checked by the wrapper that called this function,
// but this thread could be racing with the thread that is
@@ -2857,6 +2862,14 @@ JvmtiEnv::IsMethodSynthetic(methodOop method_oop, jboolean* is_synthetic_ptr) {
// is_obsolete_ptr - pre-checked for NULL
jvmtiError
JvmtiEnv::IsMethodObsolete(methodOop method_oop, jboolean* is_obsolete_ptr) {
+ if (use_version_1_0_semantics() &&
+ get_capabilities()->can_redefine_classes == 0) {
+ // This JvmtiEnv requested version 1.0 semantics and this function
+ // requires the can_redefine_classes capability in version 1.0 so
+ // we need to return an error here.
+ return JVMTI_ERROR_MUST_POSSESS_CAPABILITY;
+ }
+
if (method_oop == NULL || method_oop->is_obsolete()) {
*is_obsolete_ptr = true;
} else {
diff --git a/hotspot/src/share/vm/prims/jvmtiEnvBase.cpp b/hotspot/src/share/vm/prims/jvmtiEnvBase.cpp
index 3152e91c3a5..f7a37a90a66 100644
--- a/hotspot/src/share/vm/prims/jvmtiEnvBase.cpp
+++ b/hotspot/src/share/vm/prims/jvmtiEnvBase.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright 2003-2008 Sun Microsystems, Inc. All Rights Reserved.
+ * Copyright 2003-2009 Sun Microsystems, 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
@@ -94,7 +94,26 @@ JvmtiEnvBase::initialize() {
}
-JvmtiEnvBase::JvmtiEnvBase() : _env_event_enable() {
+bool
+JvmtiEnvBase::use_version_1_0_semantics() {
+ int major, minor, micro;
+
+ JvmtiExport::decode_version_values(_version, &major, &minor, µ);
+ return major == 1 && minor == 0; // micro version doesn't matter here
+}
+
+
+bool
+JvmtiEnvBase::use_version_1_1_semantics() {
+ int major, minor, micro;
+
+ JvmtiExport::decode_version_values(_version, &major, &minor, µ);
+ return major == 1 && minor == 1; // micro version doesn't matter here
+}
+
+
+JvmtiEnvBase::JvmtiEnvBase(jint version) : _env_event_enable() {
+ _version = version;
_env_local_storage = NULL;
_tag_map = NULL;
_native_method_prefix_count = 0;
diff --git a/hotspot/src/share/vm/prims/jvmtiEnvBase.hpp b/hotspot/src/share/vm/prims/jvmtiEnvBase.hpp
index 477725ffec5..d2f3de552b8 100644
--- a/hotspot/src/share/vm/prims/jvmtiEnvBase.hpp
+++ b/hotspot/src/share/vm/prims/jvmtiEnvBase.hpp
@@ -1,5 +1,5 @@
/*
- * Copyright 2003-2006 Sun Microsystems, Inc. All Rights Reserved.
+ * Copyright 2003-2009 Sun Microsystems, 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
@@ -76,6 +76,7 @@ class JvmtiEnvBase : public CHeapObj {
jvmtiEnv _jvmti_external;
jint _magic;
+ jint _version; // version value passed to JNI GetEnv()
JvmtiEnvBase* _next;
bool _is_retransformable;
const void *_env_local_storage; // per env agent allocated data.
@@ -91,7 +92,7 @@ class JvmtiEnvBase : public CHeapObj {
int _native_method_prefix_count;
protected:
- JvmtiEnvBase();
+ JvmtiEnvBase(jint version);
~JvmtiEnvBase();
void dispose();
void env_dispose();
@@ -122,6 +123,9 @@ class JvmtiEnvBase : public CHeapObj {
bool is_valid() { return _magic == JVMTI_MAGIC; }
+ bool use_version_1_0_semantics(); // agent asked for version 1.0
+ bool use_version_1_1_semantics(); // agent asked for version 1.1
+
bool is_retransformable() { return _is_retransformable; }
static ByteSize jvmti_external_offset() {
diff --git a/hotspot/src/share/vm/prims/jvmtiExport.cpp b/hotspot/src/share/vm/prims/jvmtiExport.cpp
index e51e5b3d467..cbdd7234ab8 100644
--- a/hotspot/src/share/vm/prims/jvmtiExport.cpp
+++ b/hotspot/src/share/vm/prims/jvmtiExport.cpp
@@ -319,7 +319,27 @@ address JvmtiExport::get_field_modification_count_addr() {
jint
JvmtiExport::get_jvmti_interface(JavaVM *jvm, void **penv, jint version) {
- /* To Do: add version checks */
+ // The JVMTI_VERSION_INTERFACE_JVMTI part of the version number
+ // has already been validated in JNI GetEnv().
+ int major, minor, micro;
+
+ // micro version doesn't matter here (yet?)
+ decode_version_values(version, &major, &minor, µ);
+ switch (major) {
+ case 1:
+ switch (minor) {
+ case 0: // version 1.0. is recognized
+ case 1: // version 1.1. is recognized
+ break;
+
+ default:
+ return JNI_EVERSION; // unsupported minor version number
+ }
+ break;
+
+ default:
+ return JNI_EVERSION; // unsupported major version number
+ }
if (JvmtiEnv::get_phase() == JVMTI_PHASE_LIVE) {
JavaThread* current_thread = (JavaThread*) ThreadLocalStorage::thread();
@@ -328,13 +348,13 @@ JvmtiExport::get_jvmti_interface(JavaVM *jvm, void **penv, jint version) {
__ENTRY(jvmtiEnv*, JvmtiExport::get_jvmti_interface, current_thread)
debug_only(VMNativeEntryWrapper __vew;)
- JvmtiEnv *jvmti_env = JvmtiEnv::create_a_jvmti();
+ JvmtiEnv *jvmti_env = JvmtiEnv::create_a_jvmti(version);
*penv = jvmti_env->jvmti_external(); // actual type is jvmtiEnv* -- not to be confused with JvmtiEnv*
return JNI_OK;
} else if (JvmtiEnv::get_phase() == JVMTI_PHASE_ONLOAD) {
// not live, no thread to transition
- JvmtiEnv *jvmti_env = JvmtiEnv::create_a_jvmti();
+ JvmtiEnv *jvmti_env = JvmtiEnv::create_a_jvmti(version);
*penv = jvmti_env->jvmti_external(); // actual type is jvmtiEnv* -- not to be confused with JvmtiEnv*
return JNI_OK;
@@ -345,6 +365,15 @@ JvmtiExport::get_jvmti_interface(JavaVM *jvm, void **penv, jint version) {
}
}
+
+void
+JvmtiExport::decode_version_values(jint version, int * major, int * minor,
+ int * micro) {
+ *major = (version & JVMTI_VERSION_MASK_MAJOR) >> JVMTI_VERSION_SHIFT_MAJOR;
+ *minor = (version & JVMTI_VERSION_MASK_MINOR) >> JVMTI_VERSION_SHIFT_MINOR;
+ *micro = (version & JVMTI_VERSION_MASK_MICRO) >> JVMTI_VERSION_SHIFT_MICRO;
+}
+
void JvmtiExport::enter_primordial_phase() {
JvmtiEnvBase::set_phase(JVMTI_PHASE_PRIMORDIAL);
}
diff --git a/hotspot/src/share/vm/prims/jvmtiExport.hpp b/hotspot/src/share/vm/prims/jvmtiExport.hpp
index 54a9416f425..20214aecf9c 100644
--- a/hotspot/src/share/vm/prims/jvmtiExport.hpp
+++ b/hotspot/src/share/vm/prims/jvmtiExport.hpp
@@ -1,5 +1,5 @@
/*
- * Copyright 1998-2006 Sun Microsystems, Inc. All Rights Reserved.
+ * Copyright 1998-2009 Sun Microsystems, 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
@@ -236,6 +236,8 @@ class JvmtiExport : public AllStatic {
static bool is_jvmti_version(jint version) { return (version & JVMTI_VERSION_MASK) == JVMTI_VERSION_VALUE; }
static bool is_jvmdi_version(jint version) { return (version & JVMTI_VERSION_MASK) == JVMDI_VERSION_VALUE; }
static jint get_jvmti_interface(JavaVM *jvm, void **penv, jint version);
+ static void decode_version_values(jint version, int * major, int * minor,
+ int * micro);
// single stepping management methods
static void at_single_stepping_point(JavaThread *thread, methodOop method, address location) KERNEL_RETURN;
diff --git a/hotspot/src/share/vm/prims/jvmtiHpp.xsl b/hotspot/src/share/vm/prims/jvmtiHpp.xsl
index 3b3b23e90f6..e5dd49ffc6c 100644
--- a/hotspot/src/share/vm/prims/jvmtiHpp.xsl
+++ b/hotspot/src/share/vm/prims/jvmtiHpp.xsl
@@ -1,6 +1,6 @@
+
+
+
diff --git a/jdk/make/modules/tools/nbproject/project.properties b/jdk/make/modules/tools/nbproject/project.properties
new file mode 100644
index 00000000000..00b74962d97
--- /dev/null
+++ b/jdk/make/modules/tools/nbproject/project.properties
@@ -0,0 +1,92 @@
+#
+# Copyright 2009 Sun Microsystems, Inc. All Rights Reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+# - Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+#
+# - Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+#
+# - Neither the name of Sun Microsystems nor the names of its
+# contributors may be used to endorse or promote products derived
+# from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+# IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+# THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+# PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+
+application.title=classanalyzer
+application.vendor=mchung
+build.classes.dir=${build.dir}/classes
+build.classes.excludes=**/*.java,**/*.form
+
+# This directory is removed when the project is cleaned:
+build.dir=build
+build.generated.dir=${build.dir}/generated
+build.generated.sources.dir=${build.dir}/generated-sources
+
+# Only compile against the classpath explicitly listed here:
+build.sysclasspath=ignore
+build.test.classes.dir=${build.dir}/test/classes
+build.test.results.dir=${build.dir}/test/results
+
+cp.extra=${tools.jar}
+
+debug.classpath=\
+ ${run.classpath}
+debug.test.classpath=\
+ ${run.test.classpath}
+
+# This directory is removed when the project is cleaned:
+dist.dir=dist
+dist.jar=${dist.dir}/classanalyzer.jar
+dist.javadoc.dir=${dist.dir}/javadoc
+
+excludes=
+
+file.reference.tools.jar=${jdk.home}/lib/tools.jar
+file.reference.tools-src=src
+includes=**
+jar.compress=false
+javac.classpath=\
+ ${file.reference.tools.jar}
+javac.deprecation=false
+javac.source=1.5
+javac.target=1.5
+javac.test.classpath=
+javadoc.author=false
+javadoc.noindex=false
+javadoc.nonavbar=false
+javadoc.notree=false
+javadoc.private=false
+javadoc.splitindex=false
+javadoc.use=false
+javadoc.version=false
+main.class=com.sun.classanalyzer.ClassAnalyzer
+manifest.file=manifest.mf
+meta.inf.dir=${src.dir}/META-INF
+platform.active=JDK_1.6
+run.classpath=\
+ ${javac.classpath}:\
+ ${build.classes.dir}
+# Space-separated list of JVM arguments used when running the project
+# (you may also define separate properties like run-sys-prop.name=value instead of -Dname=value
+# or test-sys-prop.name=value to set system properties for unit tests):
+run.jvmargs=-Xmx256m
+run.test.classpath=
+source.encoding=UTF-8
+src.dir=${file.reference.tools-src}
diff --git a/jdk/make/modules/tools/nbproject/project.xml b/jdk/make/modules/tools/nbproject/project.xml
new file mode 100644
index 00000000000..b8b0aeafe07
--- /dev/null
+++ b/jdk/make/modules/tools/nbproject/project.xml
@@ -0,0 +1,45 @@
+
+
+
+
+ org.netbeans.modules.java.j2seproject
+
+
+ classanalyzer
+
+
+
+
+
+
+
+
diff --git a/jdk/make/modules/tools/src/com/sun/classanalyzer/AnnotatedDependency.java b/jdk/make/modules/tools/src/com/sun/classanalyzer/AnnotatedDependency.java
new file mode 100644
index 00000000000..72b21d9949e
--- /dev/null
+++ b/jdk/make/modules/tools/src/com/sun/classanalyzer/AnnotatedDependency.java
@@ -0,0 +1,627 @@
+/*
+ * Copyright 2009 Sun Microsystems, 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ *
+ */
+package com.sun.classanalyzer;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Set;
+import java.util.TreeSet;
+import java.util.Map;
+
+import com.sun.classanalyzer.Module.Reference;
+import java.util.LinkedList;
+import java.util.TreeMap;
+
+/**
+ *
+ * @author Mandy Chung
+ */
+public abstract class AnnotatedDependency implements Comparable {
+
+ final Klass from;
+ final List classes;
+ protected boolean optional;
+ String description;
+ Klass.Method method;
+ private List filters = null;
+
+ public AnnotatedDependency(Klass klass) {
+ this(klass, false);
+ }
+
+ public AnnotatedDependency(Klass klass, boolean optional) {
+ this.from = klass;
+ this.classes = new ArrayList();
+ this.optional = optional;
+ }
+
+ abstract String getTag();
+
+ abstract boolean isDynamic();
+
+ void setMethod(Klass.Method m) {
+ this.method = m;
+ }
+
+ void addElement(String element, List value) {
+ if (element.equals("value")) {
+ addValue(value);
+ } else if (element.equals("description")) {
+ description = value.get(0);
+ } else if (element.equals("optional")) {
+ optional = value.get(0).equals("1") || Boolean.parseBoolean(value.get(0));
+ }
+ }
+
+ void addValue(List value) {
+ for (String s : value) {
+ if ((s = s.trim()).length() > 0) {
+ classes.add(s);
+ }
+ }
+ }
+
+ List getValue() {
+ return classes;
+ }
+
+ boolean isOptional() {
+ return optional;
+ }
+
+ boolean isEmpty() {
+ return classes.isEmpty();
+ }
+
+ boolean matches(String classname) {
+ synchronized (this) {
+ // initialize filters
+ if (filters == null) {
+ filters = new ArrayList();
+ for (String pattern : classes) {
+ filters.add(new Filter(pattern));
+ }
+
+ }
+ }
+
+ for (Filter f : filters) {
+ if (f.matches(classname)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ @Override
+ public String toString() {
+ StringBuilder sb = new StringBuilder();
+ for (String v : getValue()) {
+ if (sb.length() == 0) {
+ sb.append(getTag());
+ sb.append("\n");
+ } else {
+ sb.append("\n");
+ }
+ sb.append(" ");
+ sb.append(from.getClassName()).append(" -> ");
+ sb.append(v);
+ }
+ return sb.toString();
+ }
+
+ @Override
+ public int compareTo(AnnotatedDependency o) {
+ if (from == o.from) {
+ if (this.getClass().getName().equals(o.getClass().getName())) {
+ String s1 = classes.isEmpty() ? "" : classes.get(0);
+ String s2 = o.classes.isEmpty() ? "" : o.classes.get(0);
+ return s1.compareTo(s2);
+ } else {
+ return this.getClass().getName().compareTo(o.getClass().getName());
+ }
+
+ } else {
+ return from.compareTo(o.from);
+ }
+ }
+
+ @Override
+ public int hashCode() {
+ int hashcode = 7 + 73 * from.hashCode();
+ for (String s : classes) {
+ hashcode ^= s.hashCode();
+ }
+ return hashcode;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (!(obj instanceof AnnotatedDependency)) {
+ return false;
+ }
+ AnnotatedDependency other = (AnnotatedDependency) obj;
+ boolean ret = this.from.equals(other.from) && this.classes.size() == other.classes.size();
+ if (ret == true) {
+ for (int i = 0; i < this.classes.size(); i++) {
+ ret = ret && this.classes.get(i).equals(other.classes.get(i));
+ }
+ }
+ return ret;
+ }
+
+ static class ClassForName extends AnnotatedDependency {
+
+ public ClassForName(Klass klass, boolean optional) {
+ super(klass, optional);
+ }
+
+ @Override
+ String getTag() {
+ if (this.optional) {
+ return TAG + "(optional)";
+ } else {
+ return TAG;
+ }
+ }
+
+ @Override
+ boolean isDynamic() {
+ return true;
+ }
+ static final String TYPE = "sun.annotation.ClassForName";
+ static final String TAG = "@ClassForName";
+ }
+
+ static class NativeFindClass extends AnnotatedDependency {
+
+ public NativeFindClass(Klass klass, boolean optional) {
+ super(klass, optional);
+ }
+
+ @Override
+ String getTag() {
+ if (this.optional) {
+ return TAG + "(optional)";
+ } else {
+ return TAG;
+ }
+ }
+
+ @Override
+ boolean isDynamic() {
+ return true;
+ }
+ static final String TYPE = "sun.annotation.NativeFindClass";
+ static final String TAG = "@NativeFindClass";
+ }
+
+ static class Provider extends AnnotatedDependency {
+
+ private List services = new ArrayList();
+
+ Provider(Klass klass) {
+ super(klass, true);
+ }
+
+ @Override
+ boolean isDynamic() {
+ return true;
+ }
+
+ public List services() {
+ return services;
+ }
+
+ @Override
+ void addElement(String element, List value) {
+ if (element.equals("service")) {
+ List configFiles = new ArrayList();
+ for (String s : value) {
+ if ((s = s.trim()).length() > 0) {
+ configFiles.add(metaInfPath + s);
+ }
+ }
+ addValue(configFiles);
+ }
+ }
+
+ @Override
+ void addValue(List value) {
+ for (String s : value) {
+ if ((s = s.trim()).length() > 0) {
+ if (s.startsWith("META-INF")) {
+ services.add(s);
+ readServiceConfiguration(s, classes);
+ } else {
+ throw new RuntimeException("invalid value" + s);
+ }
+ }
+ }
+ }
+
+ boolean isEmpty() {
+ return services.isEmpty();
+ }
+ static final String metaInfPath =
+ "META-INF" + File.separator + "services" + File.separator;
+
+ static void readServiceConfiguration(String config, List names) {
+ BufferedReader br = null;
+ try {
+ InputStream is = ClassPath.open(config);
+ if (is != null) {
+ // Properties doesn't perserve the order of the input file
+ br = new BufferedReader(new InputStreamReader(is, "utf-8"));
+ int lc = 1;
+ while ((lc = parseLine(br, lc, names)) >= 0);
+ }
+ } catch (IOException ex) {
+ throw new RuntimeException(ex);
+ } finally {
+ if (br != null) {
+ try {
+ br.close();
+ } catch (IOException ex) {
+ throw new RuntimeException(ex);
+ }
+ }
+ }
+ }
+
+ // Parse a single line from the given configuration file, adding the name
+ // on the line to the names list.
+ //
+ private static int parseLine(BufferedReader r, int lc, List names) throws IOException {
+ String ln = r.readLine();
+ if (ln == null) {
+ return -1;
+ }
+ int ci = ln.indexOf('#');
+ if (ci >= 0) {
+ ln = ln.substring(0, ci);
+ }
+ ln = ln.trim();
+ int n = ln.length();
+ if (n != 0) {
+ if ((ln.indexOf(' ') >= 0) || (ln.indexOf('\t') >= 0)) {
+ throw new RuntimeException("Illegal configuration-file syntax");
+ }
+ int cp = ln.codePointAt(0);
+ if (!Character.isJavaIdentifierStart(cp)) {
+ throw new RuntimeException("Illegal provider-class name: " + ln);
+ }
+ for (int i = Character.charCount(cp); i < n; i += Character.charCount(cp)) {
+ cp = ln.codePointAt(i);
+ if (!Character.isJavaIdentifierPart(cp) && (cp != '.')) {
+ throw new RuntimeException("Illegal provider-class name: " + ln);
+ }
+ }
+ if (!names.contains(ln)) {
+ names.add(ln);
+ }
+ }
+ return lc + 1;
+ }
+
+ @Override
+ String getTag() {
+ return TAG;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (!(obj instanceof AnnotatedDependency)) {
+ return false;
+ }
+ Provider other = (Provider) obj;
+ boolean ret = this.from.equals(other.from) &&
+ this.services.size() == other.services.size();
+ if (ret == true) {
+ for (int i = 0; i < this.services.size(); i++) {
+ ret = ret && this.services.get(i).equals(other.services.get(i));
+ }
+ }
+ return ret;
+ }
+
+ @Override
+ public int hashCode() {
+ int hashcode = 7 + 73 * from.hashCode();
+ for (String s : services) {
+ hashcode ^= s.hashCode();
+ }
+ return hashcode;
+ }
+
+ @Override
+ public List getValue() {
+ List result = new ArrayList();
+ result.addAll(services);
+ return result;
+ }
+ static final String TYPE = "sun.annotation.Provider";
+ static final String TAG = "@Provider";
+ }
+
+ static class OptionalDependency extends AnnotatedDependency {
+
+ static boolean isOptional(Klass from, Klass to) {
+ synchronized (OptionalDependency.class) {
+ if (optionalDepsMap == null) {
+ // Build a map of classes to its optional dependencies
+ initDependencies();
+ }
+ }
+ for (Reference ref : optionalDepsMap.keySet()) {
+ if (ref.referrer() == from && ref.referree() == to) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ OptionalDependency(Klass klass) {
+ super(klass, true);
+ }
+
+ @Override
+ boolean isDynamic() {
+ return false;
+ }
+
+ @Override
+ String getTag() {
+ return TAG;
+ }
+ static final String TYPE = "sun.annotation.Optional";
+ static final String TAG = "@Optional";
+ }
+
+ static class CompilerInline extends AnnotatedDependency {
+
+ public CompilerInline(Klass klass) {
+ super(klass);
+ }
+
+ @Override
+ String getTag() {
+ return TAG;
+ }
+
+ @Override
+ boolean isDynamic() {
+ return false;
+ }
+ static final String TYPE = "sun.annotation.Inline";
+ static final String TAG = "@Inline";
+ }
+
+ static class Filter {
+
+ final String pattern;
+ final String regex;
+
+ Filter(String pattern) {
+ this.pattern = pattern;
+
+ boolean isRegex = false;
+ for (int i = 0; i < pattern.length(); i++) {
+ char p = pattern.charAt(i);
+ if (p == '*' || p == '[' || p == ']') {
+ isRegex = true;
+ break;
+ }
+ }
+
+ if (isRegex) {
+ this.regex = convertToRegex(pattern);
+ } else {
+ this.regex = null;
+ }
+ }
+
+ private String convertToRegex(String pattern) {
+ StringBuilder sb = new StringBuilder();
+ int i = 0;
+ int index = 0;
+ int plen = pattern.length();
+ while (i < plen) {
+ char p = pattern.charAt(i);
+ if (p == '*') {
+ sb.append("(").append(pattern.substring(index, i)).append(")");
+ if (i + 1 < plen && pattern.charAt(i + 1) == '*') {
+ sb.append(".*");
+ index = i + 2;
+ } else {
+ sb.append("[^\\.]*");
+ index = i + 1;
+ }
+ } else if (p == '[') {
+ int j = i + 1;
+ while (j < plen) {
+ if (pattern.charAt(j) == ']') {
+ break;
+ }
+ j++;
+ }
+ if (j >= plen || pattern.charAt(j) != ']') {
+ throw new RuntimeException("Malformed pattern " + pattern);
+ }
+ sb.append("(").append(pattern.substring(index, i)).append(")");
+ sb.append(pattern.substring(i, j + 1));
+ index = j + 1;
+ i = j;
+ }
+ i++;
+ }
+ if (index < plen) {
+ sb.append("(").append(pattern.substring(index, plen)).append(")");
+ }
+ return sb.toString();
+ }
+
+ boolean matches(String name) {
+ if (regex == null) {
+ // the pattern is not a regex
+ return name.equals(pattern);
+ } else {
+ return name.matches(regex);
+ }
+ }
+ }
+
+ static boolean isValidType(String type) {
+ if (type.endsWith("(optional)")) {
+ int len = type.length() - "(optional)".length();
+ type = type.substring(0, len);
+ }
+ return type.equals(ClassForName.TYPE) || type.equals(ClassForName.TAG) ||
+ type.equals(NativeFindClass.TYPE) || type.equals(NativeFindClass.TAG) ||
+ type.equals(Provider.TYPE) || type.equals(Provider.TAG) ||
+ type.equals(CompilerInline.TYPE) || type.equals(CompilerInline.TAG) ||
+ type.equals(OptionalDependency.TYPE) || type.equals(OptionalDependency.TAG);
+ }
+
+ static AnnotatedDependency newAnnotatedDependency(String tag, String value, Klass klass) {
+ AnnotatedDependency dep = newAnnotatedDependency(tag, klass);
+ if (dep != null) {
+ dep.addValue(Collections.singletonList(value));
+ }
+ return dep;
+ }
+ static List annotatedDependencies = new LinkedList();
+ static List optionalDependencies = new LinkedList();
+
+ static AnnotatedDependency newAnnotatedDependency(String type, Klass klass) {
+ boolean optional = false;
+ if (type.endsWith("(optional)")) {
+ optional = true;
+ int len = type.length() - "(optional)".length();
+ type = type.substring(0, len);
+ }
+
+ if (type.equals(OptionalDependency.TYPE) || type.equals(OptionalDependency.TAG)) {
+ return newOptionalDependency(klass);
+ }
+
+ AnnotatedDependency dep;
+ if (type.equals(ClassForName.TYPE) || type.equals(ClassForName.TAG)) {
+ dep = new ClassForName(klass, optional);
+ } else if (type.equals(NativeFindClass.TYPE) || type.equals(NativeFindClass.TAG)) {
+ dep = new NativeFindClass(klass, optional);
+ } else if (type.equals(Provider.TYPE) || type.equals(Provider.TAG)) {
+ dep = new Provider(klass);
+ } else if (type.equals(CompilerInline.TYPE) || type.equals(CompilerInline.TAG)) {
+ dep = new CompilerInline(klass);
+ } else {
+ return null;
+ }
+ klass.addAnnotatedDep(dep);
+ annotatedDependencies.add(dep);
+ return dep;
+ }
+
+ static OptionalDependency newOptionalDependency(Klass klass) {
+ OptionalDependency dep = new OptionalDependency(klass);
+ optionalDependencies.add(dep);
+ return dep;
+ }
+ static Map> annotatedDepsMap = null;
+ static Map> optionalDepsMap = null;
+
+ static Map> getReferences(Module m) {
+ // ensure it's initialized
+ initDependencies();
+
+ Map> result = new TreeMap>();
+ for (Reference ref : annotatedDepsMap.keySet()) {
+ if (m.contains(ref.referrer()) && m.isModuleDependence(ref.referree())) {
+ result.put(ref, annotatedDepsMap.get(ref));
+ }
+ }
+ return result;
+ }
+
+ static Set getDependencies(Module m) {
+ // ensure it's initialized
+ initDependencies();
+
+ Set deps = new TreeSet();
+ for (Reference ref : annotatedDepsMap.keySet()) {
+ if (m.contains(ref.referrer())) {
+ Module other = m.getModuleDependence(ref.referree());
+ if (other != null) {
+ for (AnnotatedDependency ad : annotatedDepsMap.get(ref)) {
+ Module.Dependency d = new Module.Dependency(other, ad.isOptional(), ad.isDynamic());
+ deps.add(d);
+ }
+ }
+ }
+ }
+ return deps;
+ }
+
+ synchronized static void initDependencies() {
+ if (annotatedDepsMap != null) {
+ return;
+ }
+
+ // Build a map of references to its dependencies
+ annotatedDepsMap = new TreeMap>();
+ optionalDepsMap = new TreeMap>();
+
+ for (Klass k : Klass.getAllClasses()) {
+ for (AnnotatedDependency ad : annotatedDependencies) {
+ if (ad.matches(k.getClassName())) {
+ Reference ref = new Reference(ad.from, k);
+ Set set = annotatedDepsMap.get(ref);
+ if (set == null) {
+ set = new TreeSet();
+ annotatedDepsMap.put(ref, set);
+ }
+ set.add(ad);
+ }
+ }
+
+ for (AnnotatedDependency ad : optionalDependencies) {
+ if (ad.matches(k.getClassName())) {
+ Reference ref = new Reference(ad.from, k);
+ Set set = optionalDepsMap.get(ref);
+ if (set == null) {
+ set = new TreeSet();
+ optionalDepsMap.put(ref, set);
+ }
+ set.add(ad);
+ }
+ }
+ }
+ }
+}
diff --git a/jdk/make/modules/tools/src/com/sun/classanalyzer/AnnotationParser.java b/jdk/make/modules/tools/src/com/sun/classanalyzer/AnnotationParser.java
new file mode 100644
index 00000000000..7d984aa2e74
--- /dev/null
+++ b/jdk/make/modules/tools/src/com/sun/classanalyzer/AnnotationParser.java
@@ -0,0 +1,293 @@
+/*
+ * Copyright 2009 Sun Microsystems, 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+package com.sun.classanalyzer;
+
+import com.sun.tools.classfile.*;
+import com.sun.tools.classfile.Annotation;
+import com.sun.tools.classfile.ExtendedAnnotation;
+import com.sun.tools.classfile.Annotation.Annotation_element_value;
+import com.sun.tools.classfile.Annotation.Array_element_value;
+import com.sun.tools.classfile.Annotation.Class_element_value;
+import com.sun.tools.classfile.Annotation.Enum_element_value;
+import com.sun.tools.classfile.Annotation.Primitive_element_value;
+import com.sun.tools.classfile.ConstantPoolException;
+import com.sun.tools.classfile.Descriptor;
+import com.sun.tools.classfile.Descriptor.InvalidDescriptor;
+import java.util.ArrayList;
+import java.util.List;
+
+import com.sun.classanalyzer.AnnotatedDependency.*;
+import java.io.File;
+import java.io.PrintWriter;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ *
+ * @author Mandy Chung
+ */
+public class AnnotationParser {
+
+ static boolean parseAnnotation = false;
+ static void setParseAnnotation(boolean newValue) {
+ parseAnnotation = newValue;
+ }
+
+ private final ClassFileParser cfparser;
+ public AnnotationParser(ClassFileParser cfparser) {
+ this.cfparser = cfparser;
+ }
+
+ private AnnotatedDependency addAnnotation(Annotation annot, Klass.Method method) {
+ String type = getType(annot.type_index);
+ AnnotatedDependency dep = AnnotatedDependency.newAnnotatedDependency(type, cfparser.this_klass);
+ if (dep != null) {
+ for (int i = 0; i < annot.num_element_value_pairs; i++) {
+ Element element = getElement(annot.element_value_pairs[i]);
+ dep.addElement(element.name, element.value);
+ }
+ dep.setMethod(method);
+ }
+ return dep;
+ }
+
+ private AnnotatedDependency addAnnotation(ExtendedAnnotation annot, Klass.Method method) {
+ return addAnnotation(annot.annotation, method);
+ }
+
+ class Element {
+
+ String name;
+ List value;
+
+ Element(String name) {
+ this.name = name;
+ this.value = new ArrayList();
+ }
+
+ void add(String v) {
+ value.add(v);
+ }
+ }
+
+ Element getElement(Annotation.element_value_pair pair) {
+ Element element = new Element(getName(pair.element_name_index));
+ evp.parse(pair.value, element);
+ return element;
+ }
+
+ private String getType(int index) {
+ try {
+ Descriptor d = new Descriptor(index);
+ return d.getFieldType(cfparser.classfile.constant_pool);
+ } catch (ConstantPoolException ignore) {
+ } catch (InvalidDescriptor ignore) {
+ }
+ return "Unknown";
+ }
+
+ private String getName(int index) {
+ return cfparser.constantPoolParser.stringValue(index);
+ }
+ element_value_Parser evp = new element_value_Parser();
+
+ class element_value_Parser implements Annotation.element_value.Visitor {
+
+ public Void parse(Annotation.element_value value, Element element) {
+ value.accept(this, element);
+ return null;
+ }
+
+ public Void visitPrimitive(Primitive_element_value ev, Element element) {
+ String value = getName(ev.const_value_index);
+ element.add(value);
+ return null;
+ }
+
+ public Void visitEnum(Enum_element_value ev, Element element) {
+ String value = getName(ev.type_name_index) + "." + getName(ev.const_name_index);
+ element.add(value);
+ return null;
+ }
+
+ public Void visitClass(Class_element_value ev, Element element) {
+ String value = getName(ev.class_info_index) + ".class";
+ element.add(value);
+ return null;
+ }
+
+ public Void visitAnnotation(Annotation_element_value ev, Element element) {
+ // AnnotationParser.this.addAnnotation(ev.annotation_value);
+ throw new UnsupportedOperationException("Not supported: " + ev);
+ }
+
+ public Void visitArray(Array_element_value ev, Element element) {
+ for (int i = 0; i < ev.num_values; i++) {
+ parse(ev.values[i], element);
+ }
+ return null;
+ }
+ }
+
+ void parseAttributes(Attributes attributes, Klass.Method method) {
+ if (!parseAnnotation) {
+ return;
+ }
+
+ visitRuntimeAnnotations((RuntimeVisibleAnnotations_attribute) attributes.get(Attribute.RuntimeVisibleAnnotations), method);
+ visitRuntimeAnnotations((RuntimeInvisibleAnnotations_attribute) attributes.get(Attribute.RuntimeInvisibleAnnotations), method);
+ visitRuntimeTypeAnnotations((RuntimeVisibleTypeAnnotations_attribute) attributes.get(Attribute.RuntimeVisibleTypeAnnotations), method);
+ visitRuntimeTypeAnnotations((RuntimeInvisibleTypeAnnotations_attribute) attributes.get(Attribute.RuntimeInvisibleTypeAnnotations), method);
+ visitRuntimeParameterAnnotations((RuntimeVisibleParameterAnnotations_attribute) attributes.get(Attribute.RuntimeVisibleParameterAnnotations), method);
+ visitRuntimeParameterAnnotations((RuntimeInvisibleParameterAnnotations_attribute) attributes.get(Attribute.RuntimeInvisibleParameterAnnotations), method);
+ }
+
+ public void visitRuntimeAnnotations(RuntimeAnnotations_attribute attr, Klass.Method method) {
+ if (attr == null) {
+ return;
+ }
+
+ for (int i = 0; i < attr.annotations.length; i++) {
+ addAnnotation(attr.annotations[i], method);
+ }
+ }
+
+ public void visitRuntimeTypeAnnotations(RuntimeTypeAnnotations_attribute attr, Klass.Method method) {
+ if (attr == null) {
+ return;
+ }
+
+ for (int i = 0; i < attr.annotations.length; i++) {
+ addAnnotation(attr.annotations[i], method);
+ }
+ }
+
+ public void visitRuntimeParameterAnnotations(RuntimeParameterAnnotations_attribute attr, Klass.Method method) {
+ if (attr == null) {
+ return;
+ }
+
+ for (int param = 0; param < attr.parameter_annotations.length; param++) {
+ for (int i = 0; i < attr.parameter_annotations[param].length; i++) {
+ addAnnotation(attr.parameter_annotations[param][i], method);
+ }
+ }
+ }
+
+ void parseAttributes(Attributes attributes) {
+ parseAttributes(attributes, null);
+ }
+
+ public static void main(String[] args) throws Exception {
+ String jdkhome = null;
+ String output = ".";
+
+ // process arguments
+ int i = 0;
+ while (i < args.length) {
+ String arg = args[i++];
+ if (arg.equals("-jdkhome")) {
+ if (i < args.length) {
+ jdkhome = args[i++];
+ } else {
+ usage();
+ }
+ } else if (arg.equals("-output")) {
+ output = args[i++];
+ } else {
+ usage();
+ }
+ }
+ if (jdkhome == null) {
+ usage();
+ }
+
+ // parse annotation and code attribute to find all references
+ // to Class.forName etc
+ CodeAttributeParser.setParseCodeAttribute(true);
+ AnnotationParser.setParseAnnotation(true);
+
+ ClassPath.setJDKHome(jdkhome);
+ ClassPath.parseAllClassFiles();
+
+ PrintWriter writer = new PrintWriter(new File(output, "jdk7.depconfig"));
+
+ try {
+ for (Klass k : Klass.getAllClasses()) {
+ for (AnnotatedDependency dep : k.getAnnotatedDeps()) {
+ if (dep.isEmpty()) {
+ continue;
+ }
+ writer.format("# %s \n", dep.method == null ? dep.from : dep.method);
+ writer.format("%s\n\n", dep);
+ }
+ }
+ } finally {
+ writer.close();
+ }
+
+ writer = new PrintWriter(new File(output, "optional.depconfig"));
+ try {
+ AnnotatedDependency prev = null;
+ for (AnnotatedDependency dep : AnnotatedDependency.optionalDependencies) {
+ if (prev != null && !dep.equals(prev)) {
+ writer.format("%s\n\n", prev);
+ }
+ writer.format("# %s \n", dep.method == null ? dep.from : dep.method);
+ prev = dep;
+ }
+ if (prev != null) {
+ writer.format("%s\n\n", prev);
+ }
+ } finally {
+ writer.close();
+ }
+
+ writer = new PrintWriter(new File(output, "runtime.references"));
+ try {
+ for (Map.Entry> entry : CodeAttributeParser.runtimeReferences.entrySet()) {
+ writer.format("References to %s\n", entry.getKey());
+ Klass prev = null;
+ for (Klass.Method m : entry.getValue()) {
+ if (prev == null || prev != m.getKlass()) {
+ writer.format(" %-50s # %s\n", m.getKlass(), m);
+ } else if (prev == m.getKlass()) {
+ writer.format(" %-50s # %s\n", "", m);
+ }
+ prev = m.getKlass();
+ }
+ }
+ } finally {
+ writer.close();
+ }
+ }
+
+ private static void usage() {
+ System.out.println("Usage: AnnotationParser ");
+ System.out.println("Options: ");
+ System.out.println("\t-jdkhome where all jars will be parsed");
+ System.out.println("\t-depconfig