提交 5bb0a44f 编写于 作者: L lana

Merge

...@@ -143,3 +143,5 @@ b71d1acfae5240d8c1359443cd02b5ddb587231c jdk8-b17 ...@@ -143,3 +143,5 @@ b71d1acfae5240d8c1359443cd02b5ddb587231c jdk8-b17
3778f85773055e81eab6c5ef828935ecca241810 jdk8-b19 3778f85773055e81eab6c5ef828935ecca241810 jdk8-b19
39e938cd1b82ec3aab0a9aa66fd8a0457cd0c9c2 jdk8-b20 39e938cd1b82ec3aab0a9aa66fd8a0457cd0c9c2 jdk8-b20
664fa4fb0ee411ef048903c479f8b962fcdb2f4b jdk8-b21 664fa4fb0ee411ef048903c479f8b962fcdb2f4b jdk8-b21
dda27c73d8db4a9c7a23872b6f0c5106edcb2021 jdk8-b22
54202e0148ec7d4570cab5bc9b00d216a7677569 jdk8-b23
...@@ -65,7 +65,7 @@ FILES_export = \ ...@@ -65,7 +65,7 @@ FILES_export = \
$(MIDIFILES_export) \ $(MIDIFILES_export) \
$(PORTFILES_export) $(PORTFILES_export)
LDFLAGS += -lasound OTHER_LDLIBS += -lasound
CPPFLAGS += \ CPPFLAGS += \
-DUSE_DAUDIO=TRUE \ -DUSE_DAUDIO=TRUE \
......
...@@ -367,7 +367,8 @@ else ...@@ -367,7 +367,8 @@ else
FONTCONFIGS_SRC = $(CLOSED_SRC)/solaris/classes/sun/awt/fontconfigs FONTCONFIGS_SRC = $(CLOSED_SRC)/solaris/classes/sun/awt/fontconfigs
_FONTCONFIGS = \ _FONTCONFIGS = \
fontconfig.properties \ fontconfig.properties \
fontconfig.RedHat.5.5.properties \ fontconfig.RedHat.5.properties \
fontconfig.RedHat.6.properties \
fontconfig.Turbo.properties \ fontconfig.Turbo.properties \
fontconfig.SuSE.10.properties \ fontconfig.SuSE.10.properties \
fontconfig.SuSE.11.properties fontconfig.SuSE.11.properties
......
...@@ -154,7 +154,7 @@ public final class TypeResolver { ...@@ -154,7 +154,7 @@ public final class TypeResolver {
* @see #resolve(Type) * @see #resolve(Type)
*/ */
public static Type resolve(Type actual, Type formal) { public static Type resolve(Type actual, Type formal) {
return new TypeResolver(actual).resolve(formal); return getTypeResolver(actual).resolve(formal);
} }
/** /**
...@@ -169,7 +169,7 @@ public final class TypeResolver { ...@@ -169,7 +169,7 @@ public final class TypeResolver {
* @see #resolve(Type[]) * @see #resolve(Type[])
*/ */
public static Type[] resolve(Type actual, Type[] formals) { public static Type[] resolve(Type actual, Type[] formals) {
return new TypeResolver(actual).resolve(formals); return getTypeResolver(actual).resolve(formals);
} }
/** /**
...@@ -228,9 +228,20 @@ public final class TypeResolver { ...@@ -228,9 +228,20 @@ public final class TypeResolver {
return classes; return classes;
} }
public static TypeResolver getTypeResolver(Type type) {
synchronized (CACHE) {
TypeResolver resolver = CACHE.get(type);
if (resolver == null) {
resolver = new TypeResolver(type);
CACHE.put(type, resolver);
}
return resolver;
}
}
private static final WeakCache<Type, TypeResolver> CACHE = new WeakCache<>();
private final Map<TypeVariable<?>, Type> map private final Map<TypeVariable<?>, Type> map = new HashMap<>();
= new HashMap<TypeVariable<?>, Type>();
/** /**
* Constructs the type resolver for the given actual type. * Constructs the type resolver for the given actual type.
......
...@@ -802,9 +802,12 @@ public class AWTKeyStroke implements Serializable { ...@@ -802,9 +802,12 @@ public class AWTKeyStroke implements Serializable {
*/ */
protected Object readResolve() throws java.io.ObjectStreamException { protected Object readResolve() throws java.io.ObjectStreamException {
synchronized (AWTKeyStroke.class) { synchronized (AWTKeyStroke.class) {
if (getClass().equals(getAWTKeyStrokeClass())) {
return getCachedStroke(keyChar, keyCode, modifiers, onKeyRelease); return getCachedStroke(keyChar, keyCode, modifiers, onKeyRelease);
} }
} }
return this;
}
private static int mapOldModifiers(int modifiers) { private static int mapOldModifiers(int modifiers) {
if ((modifiers & InputEvent.SHIFT_MASK) != 0) { if ((modifiers & InputEvent.SHIFT_MASK) != 0) {
......
...@@ -3118,4 +3118,9 @@ public final ...@@ -3118,4 +3118,9 @@ public final
AnnotationType getAnnotationType() { AnnotationType getAnnotationType() {
return annotationType; return annotationType;
} }
/* Backing store of user-defined values pertaining to this class.
* Maintained by the ClassValue class.
*/
transient ClassValue.ClassValueMap classValueMap;
} }
...@@ -25,9 +25,14 @@ ...@@ -25,9 +25,14 @@
package java.lang; package java.lang;
import java.lang.ClassValue.ClassValueMap;
import java.util.WeakHashMap; import java.util.WeakHashMap;
import java.lang.ref.WeakReference;
import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicInteger;
import static java.lang.ClassValue.ClassValueMap.probeHomeLocation;
import static java.lang.ClassValue.ClassValueMap.probeBackupLocations;
/** /**
* Lazily associate a computed value with (potentially) every type. * Lazily associate a computed value with (potentially) every type.
* For example, if a dynamic language needs to construct a message dispatch * For example, if a dynamic language needs to construct a message dispatch
...@@ -92,14 +97,22 @@ public abstract class ClassValue<T> { ...@@ -92,14 +97,22 @@ public abstract class ClassValue<T> {
* @see #computeValue * @see #computeValue
*/ */
public T get(Class<?> type) { public T get(Class<?> type) {
ClassValueMap map = getMap(type); // non-racing this.hashCodeForCache : final int
if (map != null) { Entry<?>[] cache;
Object x = map.get(this); Entry<T> e = probeHomeLocation(cache = getCacheCarefully(type), this);
if (x != null) { // racing e : current value <=> stale value from current cache or from stale cache
return (T) map.unmaskNull(x); // invariant: e is null or an Entry with readable Entry.version and Entry.value
} if (match(e))
} // invariant: No false positive matches. False negatives are OK if rare.
return setComputedValue(type); // The key fact that makes this work: if this.version == e.version,
// then this thread has a right to observe (final) e.value.
return e.value();
// The fast path can fail for any of these reasons:
// 1. no entry has been computed yet
// 2. hash code collision (before or after reduction mod cache.length)
// 3. an entry has been removed (either on this type or another)
// 4. the GC has somehow managed to delete e.version and clear the reference
return getFromBackup(cache, type);
} }
/** /**
...@@ -157,83 +170,582 @@ public abstract class ClassValue<T> { ...@@ -157,83 +170,582 @@ public abstract class ClassValue<T> {
*/ */
public void remove(Class<?> type) { public void remove(Class<?> type) {
ClassValueMap map = getMap(type); ClassValueMap map = getMap(type);
if (map != null) { map.removeEntry(this);
synchronized (map) {
map.remove(this);
}
} }
// Possible functionality for JSR 292 MR 1
/*public*/ void put(Class<?> type, T value) {
ClassValueMap map = getMap(type);
map.changeEntry(this, value);
} }
/// --------
/// Implementation... /// Implementation...
// FIXME: Use a data structure here similar that of ThreadLocal (7030453). /// --------
private static final AtomicInteger STORE_BARRIER = new AtomicInteger(); /** Return the cache, if it exists, else a dummy empty cache. */
private static Entry<?>[] getCacheCarefully(Class<?> type) {
// racing type.classValueMap{.cacheArray} : null => new Entry[X] <=> new Entry[Y]
ClassValueMap map = type.classValueMap;
if (map == null) return EMPTY_CACHE;
Entry<?>[] cache = map.getCache();
return cache;
// invariant: returned value is safe to dereference and check for an Entry
}
/** Slow path for {@link #get}. */ /** Initial, one-element, empty cache used by all Class instances. Must never be filled. */
private T setComputedValue(Class<?> type) { private static final Entry<?>[] EMPTY_CACHE = { null };
/**
* Slow tail of ClassValue.get to retry at nearby locations in the cache,
* or take a slow lock and check the hash table.
* Called only if the first probe was empty or a collision.
* This is a separate method, so compilers can process it independently.
*/
private T getFromBackup(Entry<?>[] cache, Class<?> type) {
Entry<T> e = probeBackupLocations(cache, this);
if (e != null)
return e.value();
return getFromHashMap(type);
}
// Hack to suppress warnings on the (T) cast, which is a no-op.
@SuppressWarnings("unchecked")
Entry<T> castEntry(Entry<?> e) { return (Entry<T>) e; }
/** Called when the fast path of get fails, and cache reprobe also fails.
*/
private T getFromHashMap(Class<?> type) {
// The fail-safe recovery is to fall back to the underlying classValueMap.
ClassValueMap map = getMap(type); ClassValueMap map = getMap(type);
if (map == null) { for (;;) {
map = initializeMap(type); Entry<T> e = map.startEntry(this);
if (!e.isPromise())
return e.value();
try {
// Try to make a real entry for the promised version.
e = makeEntry(e.version(), computeValue(type));
} finally {
// Whether computeValue throws or returns normally,
// be sure to remove the empty entry.
e = map.finishEntry(this, e);
} }
T value = computeValue(type); if (e != null)
STORE_BARRIER.lazySet(0); return e.value();
// All stores pending from computeValue are completed. // else try again, in case a racing thread called remove (so e == null)
synchronized (map) {
// Warm up the table with a null entry.
map.preInitializeEntry(this);
} }
STORE_BARRIER.lazySet(0);
// All stores pending from table expansion are completed.
synchronized (map) {
value = (T) map.initializeEntry(this, value);
// One might fear a possible race condition here
// if the code for map.put has flushed the write
// to map.table[*] before the writes to the Map.Entry
// are done. This is not possible, since we have
// warmed up the table with an empty entry.
} }
return value;
/** Check that e is non-null, matches this ClassValue, and is live. */
boolean match(Entry<?> e) {
// racing e.version : null (blank) => unique Version token => null (GC-ed version)
// non-racing this.version : v1 => v2 => ... (updates are read faithfully from volatile)
return (e != null && e.get() == this.version);
// invariant: No false positives on version match. Null is OK for false negative.
// invariant: If version matches, then e.value is readable (final set in Entry.<init>)
}
/** Internal hash code for accessing Class.classValueMap.cacheArray. */
final int hashCodeForCache = nextHashCode.getAndAdd(HASH_INCREMENT) & HASH_MASK;
/** Value stream for hashCodeForCache. See similar structure in ThreadLocal. */
private static final AtomicInteger nextHashCode = new AtomicInteger();
/** Good for power-of-two tables. See similar structure in ThreadLocal. */
private static final int HASH_INCREMENT = 0x61c88647;
/** Mask a hash code to be positive but not too large, to prevent wraparound. */
static final int HASH_MASK = (-1 >>> 2);
/**
* Private key for retrieval of this object from ClassValueMap.
*/
static class Identity {
}
/**
* This ClassValue's identity, expressed as an opaque object.
* The main object {@code ClassValue.this} is incorrect since
* subclasses may override {@code ClassValue.equals}, which
* could confuse keys in the ClassValueMap.
*/
final Identity identity = new Identity();
/**
* Current version for retrieving this class value from the cache.
* Any number of computeValue calls can be cached in association with one version.
* But the version changes when a remove (on any type) is executed.
* A version change invalidates all cache entries for the affected ClassValue,
* by marking them as stale. Stale cache entries do not force another call
* to computeValue, but they do require a synchronized visit to a backing map.
* <p>
* All user-visible state changes on the ClassValue take place under
* a lock inside the synchronized methods of ClassValueMap.
* Readers (of ClassValue.get) are notified of such state changes
* when this.version is bumped to a new token.
* This variable must be volatile so that an unsynchronized reader
* will receive the notification without delay.
* <p>
* If version were not volatile, one thread T1 could persistently hold onto
* a stale value this.value == V1, while while another thread T2 advances
* (under a lock) to this.value == V2. This will typically be harmless,
* but if T1 and T2 interact causally via some other channel, such that
* T1's further actions are constrained (in the JMM) to happen after
* the V2 event, then T1's observation of V1 will be an error.
* <p>
* The practical effect of making this.version be volatile is that it cannot
* be hoisted out of a loop (by an optimizing JIT) or otherwise cached.
* Some machines may also require a barrier instruction to execute
* before this.version.
*/
private volatile Version<T> version = new Version<>(this);
Version<T> version() { return version; }
void bumpVersion() { version = new Version<>(this); }
static class Version<T> {
private final ClassValue<T> classValue;
private final Entry<T> promise = new Entry<>(this);
Version(ClassValue<T> classValue) { this.classValue = classValue; }
ClassValue<T> classValue() { return classValue; }
Entry<T> promise() { return promise; }
boolean isLive() { return classValue.version() == this; }
} }
// Replace this map by a per-class slot. /** One binding of a value to a class via a ClassValue.
private static final WeakHashMap<Class<?>, ClassValueMap> ROOT * States are:<ul>
= new WeakHashMap<Class<?>, ClassValueMap>(); * <li> promise if value == Entry.this
* <li> else dead if version == null
* <li> else stale if version != classValue.version
* <li> else live </ul>
* Promises are never put into the cache; they only live in the
* backing map while a computeValue call is in flight.
* Once an entry goes stale, it can be reset at any time
* into the dead state.
*/
static class Entry<T> extends WeakReference<Version<T>> {
final Object value; // usually of type T, but sometimes (Entry)this
Entry(Version<T> version, T value) {
super(version);
this.value = value; // for a regular entry, value is of type T
}
private void assertNotPromise() { assert(!isPromise()); }
/** For creating a promise. */
Entry(Version<T> version) {
super(version);
this.value = this; // for a promise, value is not of type T, but Entry!
}
/** Fetch the value. This entry must not be a promise. */
@SuppressWarnings("unchecked") // if !isPromise, type is T
T value() { assertNotPromise(); return (T) value; }
boolean isPromise() { return value == this; }
Version<T> version() { return get(); }
ClassValue<T> classValueOrNull() {
Version<T> v = version();
return (v == null) ? null : v.classValue();
}
boolean isLive() {
Version<T> v = version();
if (v == null) return false;
if (v.isLive()) return true;
clear();
return false;
}
Entry<T> refreshVersion(Version<T> v2) {
assertNotPromise();
@SuppressWarnings("unchecked") // if !isPromise, type is T
Entry<T> e2 = new Entry<>(v2, (T) value);
clear();
// value = null -- caller must drop
return e2;
}
static final Entry<?> DEAD_ENTRY = new Entry<>(null, null);
}
/** Return the backing map associated with this type. */
private static ClassValueMap getMap(Class<?> type) { private static ClassValueMap getMap(Class<?> type) {
type.getClass(); // test for null // racing type.classValueMap : null (blank) => unique ClassValueMap
return ROOT.get(type); // if a null is observed, a map is created (lazily, synchronously, uniquely)
// all further access to that map is synchronized
ClassValueMap map = type.classValueMap;
if (map != null) return map;
return initializeMap(type);
} }
private static final Object CRITICAL_SECTION = new Object();
private static ClassValueMap initializeMap(Class<?> type) { private static ClassValueMap initializeMap(Class<?> type) {
synchronized (ClassValue.class) { ClassValueMap map;
ClassValueMap map = ROOT.get(type); synchronized (CRITICAL_SECTION) { // private object to avoid deadlocks
if (map == null) // happens about once per type
ROOT.put(type, map = new ClassValueMap()); if ((map = type.classValueMap) == null)
type.classValueMap = map = new ClassValueMap(type);
}
return map; return map;
} }
static <T> Entry<T> makeEntry(Version<T> explicitVersion, T value) {
// Note that explicitVersion might be different from this.version.
return new Entry<>(explicitVersion, value);
// As soon as the Entry is put into the cache, the value will be
// reachable via a data race (as defined by the Java Memory Model).
// This race is benign, assuming the value object itself can be
// read safely by multiple threads. This is up to the user.
//
// The entry and version fields themselves can be safely read via
// a race because they are either final or have controlled states.
// If the pointer from the entry to the version is still null,
// or if the version goes immediately dead and is nulled out,
// the reader will take the slow path and retry under a lock.
} }
static class ClassValueMap extends WeakHashMap<ClassValue, Object> { // The following class could also be top level and non-public:
/** Make sure this table contains an Entry for the given key, even if it is empty. */
void preInitializeEntry(ClassValue key) { /** A backing map for all ClassValues, relative a single given type.
if (!this.containsKey(key)) * Gives a fully serialized "true state" for each pair (ClassValue cv, Class type).
this.put(key, null); * Also manages an unserialized fast-path cache.
*/
static class ClassValueMap extends WeakHashMap<ClassValue.Identity, Entry<?>> {
private final Class<?> type;
private Entry<?>[] cacheArray;
private int cacheLoad, cacheLoadLimit;
/** Number of entries initially allocated to each type when first used with any ClassValue.
* It would be pointless to make this much smaller than the Class and ClassValueMap objects themselves.
* Must be a power of 2.
*/
private static final int INITIAL_ENTRIES = 32;
/** Build a backing map for ClassValues, relative the given type.
* Also, create an empty cache array and install it on the class.
*/
ClassValueMap(Class<?> type) {
this.type = type;
sizeCache(INITIAL_ENTRIES);
}
Entry<?>[] getCache() { return cacheArray; }
/** Initiate a query. Store a promise (placeholder) if there is no value yet. */
synchronized
<T> Entry<T> startEntry(ClassValue<T> classValue) {
@SuppressWarnings("unchecked") // one map has entries for all value types <T>
Entry<T> e = (Entry<T>) get(classValue.identity);
Version<T> v = classValue.version();
if (e == null) {
e = v.promise();
// The presence of a promise means that a value is pending for v.
// Eventually, finishEntry will overwrite the promise.
put(classValue.identity, e);
// Note that the promise is never entered into the cache!
return e;
} else if (e.isPromise()) {
// Somebody else has asked the same question.
// Let the races begin!
if (e.version() != v) {
e = v.promise();
put(classValue.identity, e);
}
return e;
} else {
// there is already a completed entry here; report it
if (e.version() != v) {
// There is a stale but valid entry here; make it fresh again.
// Once an entry is in the hash table, we don't care what its version is.
e = e.refreshVersion(v);
put(classValue.identity, e);
} }
/** Make sure this table contains a non-empty Entry for the given key. */ // Add to the cache, to enable the fast path, next time.
Object initializeEntry(ClassValue key, Object value) { checkCacheLoad();
Object prior = this.get(key); addToCache(classValue, e);
if (prior != null) { return e;
return unmaskNull(prior);
} }
this.put(key, maskNull(value));
return value;
} }
Object maskNull(Object x) { /** Finish a query. Overwrite a matching placeholder. Drop stale incoming values. */
return x == null ? this : x; synchronized
<T> Entry<T> finishEntry(ClassValue<T> classValue, Entry<T> e) {
@SuppressWarnings("unchecked") // one map has entries for all value types <T>
Entry<T> e0 = (Entry<T>) get(classValue.identity);
if (e == e0) {
// We can get here during exception processing, unwinding from computeValue.
assert(e.isPromise());
remove(classValue.identity);
return null;
} else if (e0 != null && e0.isPromise() && e0.version() == e.version()) {
// If e0 matches the intended entry, there has not been a remove call
// between the previous startEntry and now. So now overwrite e0.
Version<T> v = classValue.version();
if (e.version() != v)
e = e.refreshVersion(v);
put(classValue.identity, e);
// Add to the cache, to enable the fast path, next time.
checkCacheLoad();
addToCache(classValue, e);
return e;
} else {
// Some sort of mismatch; caller must try again.
return null;
} }
Object unmaskNull(Object x) {
return x == this ? null : x;
} }
/** Remove an entry. */
synchronized
void removeEntry(ClassValue<?> classValue) {
// make all cache elements for this guy go stale:
if (remove(classValue.identity) != null) {
classValue.bumpVersion();
removeStaleEntries(classValue);
}
}
/** Change the value for an entry. */
synchronized
<T> void changeEntry(ClassValue<T> classValue, T value) {
@SuppressWarnings("unchecked") // one map has entries for all value types <T>
Entry<T> e0 = (Entry<T>) get(classValue.identity);
Version<T> version = classValue.version();
if (e0 != null) {
if (e0.version() == version && e0.value() == value)
// no value change => no version change needed
return;
classValue.bumpVersion();
removeStaleEntries(classValue);
}
Entry<T> e = makeEntry(version, value);
put(classValue.identity, e);
// Add to the cache, to enable the fast path, next time.
checkCacheLoad();
addToCache(classValue, e);
}
/// --------
/// Cache management.
/// --------
// Statics do not need synchronization.
/** Load the cache entry at the given (hashed) location. */
static Entry<?> loadFromCache(Entry<?>[] cache, int i) {
// non-racing cache.length : constant
// racing cache[i & (mask)] : null <=> Entry
return cache[i & (cache.length-1)];
// invariant: returned value is null or well-constructed (ready to match)
}
/** Look in the cache, at the home location for the given ClassValue. */
static <T> Entry<T> probeHomeLocation(Entry<?>[] cache, ClassValue<T> classValue) {
return classValue.castEntry(loadFromCache(cache, classValue.hashCodeForCache));
}
/** Given that first probe was a collision, retry at nearby locations. */
static <T> Entry<T> probeBackupLocations(Entry<?>[] cache, ClassValue<T> classValue) {
if (PROBE_LIMIT <= 0) return null;
// Probe the cache carefully, in a range of slots.
int mask = (cache.length-1);
int home = (classValue.hashCodeForCache & mask);
Entry<?> e2 = cache[home]; // victim, if we find the real guy
if (e2 == null) {
return null; // if nobody is at home, no need to search nearby
}
// assume !classValue.match(e2), but do not assert, because of races
int pos2 = -1;
for (int i = home + 1; i < home + PROBE_LIMIT; i++) {
Entry<?> e = cache[i & mask];
if (e == null) {
break; // only search within non-null runs
}
if (classValue.match(e)) {
// relocate colliding entry e2 (from cache[home]) to first empty slot
cache[home] = e;
if (pos2 >= 0) {
cache[i & mask] = Entry.DEAD_ENTRY;
} else {
pos2 = i;
}
cache[pos2 & mask] = ((entryDislocation(cache, pos2, e2) < PROBE_LIMIT)
? e2 // put e2 here if it fits
: Entry.DEAD_ENTRY);
return classValue.castEntry(e);
}
// Remember first empty slot, if any:
if (!e.isLive() && pos2 < 0) pos2 = i;
}
return null;
}
/** How far out of place is e? */
private static int entryDislocation(Entry<?>[] cache, int pos, Entry<?> e) {
ClassValue<?> cv = e.classValueOrNull();
if (cv == null) return 0; // entry is not live!
int mask = (cache.length-1);
return (pos - cv.hashCodeForCache) & mask;
}
/// --------
/// Below this line all functions are private, and assume synchronized access.
/// --------
private void sizeCache(int length) {
assert((length & (length-1)) == 0); // must be power of 2
cacheLoad = 0;
cacheLoadLimit = (int) ((double) length * CACHE_LOAD_LIMIT / 100);
cacheArray = new Entry<?>[length];
}
/** Make sure the cache load stays below its limit, if possible. */
private void checkCacheLoad() {
if (cacheLoad >= cacheLoadLimit) {
reduceCacheLoad();
}
}
private void reduceCacheLoad() {
removeStaleEntries();
if (cacheLoad < cacheLoadLimit)
return; // win
Entry<?>[] oldCache = getCache();
if (oldCache.length > HASH_MASK)
return; // lose
sizeCache(oldCache.length * 2);
for (Entry<?> e : oldCache) {
if (e != null && e.isLive()) {
addToCache(e);
}
}
}
/** Remove stale entries in the given range.
* Should be executed under a Map lock.
*/
private void removeStaleEntries(Entry<?>[] cache, int begin, int count) {
if (PROBE_LIMIT <= 0) return;
int mask = (cache.length-1);
int removed = 0;
for (int i = begin; i < begin + count; i++) {
Entry<?> e = cache[i & mask];
if (e == null || e.isLive())
continue; // skip null and live entries
Entry<?> replacement = null;
if (PROBE_LIMIT > 1) {
// avoid breaking up a non-null run
replacement = findReplacement(cache, i);
}
cache[i & mask] = replacement;
if (replacement == null) removed += 1;
}
cacheLoad = Math.max(0, cacheLoad - removed);
}
/** Clearing a cache slot risks disconnecting following entries
* from the head of a non-null run, which would allow them
* to be found via reprobes. Find an entry after cache[begin]
* to plug into the hole, or return null if none is needed.
*/
private Entry<?> findReplacement(Entry<?>[] cache, int home1) {
Entry<?> replacement = null;
int haveReplacement = -1, replacementPos = 0;
int mask = (cache.length-1);
for (int i2 = home1 + 1; i2 < home1 + PROBE_LIMIT; i2++) {
Entry<?> e2 = cache[i2 & mask];
if (e2 == null) break; // End of non-null run.
if (!e2.isLive()) continue; // Doomed anyway.
int dis2 = entryDislocation(cache, i2, e2);
if (dis2 == 0) continue; // e2 already optimally placed
int home2 = i2 - dis2;
if (home2 <= home1) {
// e2 can replace entry at cache[home1]
if (home2 == home1) {
// Put e2 exactly where he belongs.
haveReplacement = 1;
replacementPos = i2;
replacement = e2;
} else if (haveReplacement <= 0) {
haveReplacement = 0;
replacementPos = i2;
replacement = e2;
}
// And keep going, so we can favor larger dislocations.
}
}
if (haveReplacement >= 0) {
if (cache[(replacementPos+1) & mask] != null) {
// Be conservative, to avoid breaking up a non-null run.
cache[replacementPos & mask] = (Entry<?>) Entry.DEAD_ENTRY;
} else {
cache[replacementPos & mask] = null;
cacheLoad -= 1;
}
}
return replacement;
}
/** Remove stale entries in the range near classValue. */
private void removeStaleEntries(ClassValue<?> classValue) {
removeStaleEntries(getCache(), classValue.hashCodeForCache, PROBE_LIMIT);
}
/** Remove all stale entries, everywhere. */
private void removeStaleEntries() {
Entry[] cache = getCache();
removeStaleEntries(cache, 0, cache.length + PROBE_LIMIT - 1);
}
/** Add the given entry to the cache, in its home location, unless it is out of date. */
private <T> void addToCache(Entry<T> e) {
ClassValue<T> classValue = e.classValueOrNull();
if (classValue != null)
addToCache(classValue, e);
}
/** Add the given entry to the cache, in its home location. */
private <T> void addToCache(ClassValue<T> classValue, Entry<T> e) {
if (PROBE_LIMIT <= 0) return; // do not fill cache
// Add e to the cache.
Entry<?>[] cache = getCache();
int mask = (cache.length-1);
int home = classValue.hashCodeForCache & mask;
Entry<?> e2 = placeInCache(cache, home, e, false);
if (e2 == null) return; // done
if (PROBE_LIMIT > 1) {
// try to move e2 somewhere else in his probe range
int dis2 = entryDislocation(cache, home, e2);
int home2 = home - dis2;
for (int i2 = home2; i2 < home2 + PROBE_LIMIT; i2++) {
if (placeInCache(cache, i2 & mask, e2, true) == null) {
return;
}
}
}
// Note: At this point, e2 is just dropped from the cache.
}
/** Store the given entry. Update cacheLoad, and return any live victim.
* 'Gently' means return self rather than dislocating a live victim.
*/
private Entry<?> placeInCache(Entry<?>[] cache, int pos, Entry<?> e, boolean gently) {
Entry<?> e2 = overwrittenEntry(cache[pos]);
if (gently && e2 != null) {
// do not overwrite a live entry
return e;
} else {
cache[pos] = e;
return e2;
}
}
/** Note an entry that is about to be overwritten.
* If it is not live, quietly replace it by null.
* If it is an actual null, increment cacheLoad,
* because the caller is going to store something
* in its place.
*/
private <T> Entry<T> overwrittenEntry(Entry<T> e2) {
if (e2 == null) cacheLoad += 1;
else if (e2.isLive()) return e2;
return null;
}
/** Percent loading of cache before resize. */
private static final int CACHE_LOAD_LIMIT = 67; // 0..100
/** Maximum number of probes to attempt. */
private static final int PROBE_LIMIT = 6; // 1..
// N.B. Set PROBE_LIMIT=0 to disable all fast paths.
} }
} }
...@@ -378,6 +378,7 @@ class AdapterMethodHandle extends BoundMethodHandle { ...@@ -378,6 +378,7 @@ class AdapterMethodHandle extends BoundMethodHandle {
} }
/** Construct an adapter conversion descriptor for a single-argument conversion. */ /** Construct an adapter conversion descriptor for a single-argument conversion. */
@SuppressWarnings("cast") // some (int) casts below provide clarity but trigger warnings
private static long makeConv(int convOp, int argnum, int src, int dest) { private static long makeConv(int convOp, int argnum, int src, int dest) {
assert(src == (src & CONV_TYPE_MASK)); assert(src == (src & CONV_TYPE_MASK));
assert(dest == (dest & CONV_TYPE_MASK)); assert(dest == (dest & CONV_TYPE_MASK));
...@@ -390,6 +391,7 @@ class AdapterMethodHandle extends BoundMethodHandle { ...@@ -390,6 +391,7 @@ class AdapterMethodHandle extends BoundMethodHandle {
insertStackMove(stackMove) insertStackMove(stackMove)
); );
} }
@SuppressWarnings("cast") // some (int) casts below provide clarity but trigger warnings
private static long makeDupConv(int convOp, int argnum, int stackMove) { private static long makeDupConv(int convOp, int argnum, int stackMove) {
// simple argument motion, requiring one slot to specify // simple argument motion, requiring one slot to specify
assert(convOp == OP_DUP_ARGS || convOp == OP_DROP_ARGS); assert(convOp == OP_DUP_ARGS || convOp == OP_DROP_ARGS);
...@@ -401,6 +403,7 @@ class AdapterMethodHandle extends BoundMethodHandle { ...@@ -401,6 +403,7 @@ class AdapterMethodHandle extends BoundMethodHandle {
insertStackMove(stackMove) insertStackMove(stackMove)
); );
} }
@SuppressWarnings("cast") // some (int) casts below provide clarity but trigger warnings
private static long makeSwapConv(int convOp, int srcArg, byte srcType, int destSlot, byte destType) { private static long makeSwapConv(int convOp, int srcArg, byte srcType, int destSlot, byte destType) {
// more complex argument motion, requiring two slots to specify // more complex argument motion, requiring two slots to specify
assert(convOp == OP_SWAP_ARGS || convOp == OP_ROT_ARGS); assert(convOp == OP_SWAP_ARGS || convOp == OP_ROT_ARGS);
...@@ -411,6 +414,7 @@ class AdapterMethodHandle extends BoundMethodHandle { ...@@ -411,6 +414,7 @@ class AdapterMethodHandle extends BoundMethodHandle {
(int) destSlot << CONV_VMINFO_SHIFT (int) destSlot << CONV_VMINFO_SHIFT
); );
} }
@SuppressWarnings("cast") // some (int) casts below provide clarity but trigger warnings
private static long makeSpreadConv(int convOp, int argnum, int src, int dest, int stackMove) { private static long makeSpreadConv(int convOp, int argnum, int src, int dest, int stackMove) {
// spreading or collecting, at a particular slot location // spreading or collecting, at a particular slot location
assert(convOp == OP_SPREAD_ARGS || convOp == OP_COLLECT_ARGS || convOp == OP_FOLD_ARGS); assert(convOp == OP_SPREAD_ARGS || convOp == OP_COLLECT_ARGS || convOp == OP_FOLD_ARGS);
......
...@@ -353,7 +353,7 @@ import static java.lang.invoke.MethodHandleStatics.*; ...@@ -353,7 +353,7 @@ import static java.lang.invoke.MethodHandleStatics.*;
assert(isResolved()); assert(isResolved());
} }
/** Create a name for the given reflected constructor. The resulting name will be in a resolved state. */ /** Create a name for the given reflected constructor. The resulting name will be in a resolved state. */
public MemberName(Constructor ctor) { public MemberName(Constructor<?> ctor) {
Object[] typeInfo = { void.class, ctor.getParameterTypes() }; Object[] typeInfo = { void.class, ctor.getParameterTypes() };
init(ctor.getDeclaringClass(), CONSTRUCTOR_NAME, typeInfo, flagsMods(IS_CONSTRUCTOR, ctor.getModifiers())); init(ctor.getDeclaringClass(), CONSTRUCTOR_NAME, typeInfo, flagsMods(IS_CONSTRUCTOR, ctor.getModifiers()));
// fill in vmtarget, vmindex while we have ctor in hand: // fill in vmtarget, vmindex while we have ctor in hand:
......
...@@ -112,7 +112,7 @@ import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP; ...@@ -112,7 +112,7 @@ import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP;
assert(cookedConstructor.type().equals(ctype)); assert(cookedConstructor.type().equals(ctype));
ctype = ctype.dropParameterTypes(0, 1); ctype = ctype.dropParameterTypes(0, 1);
cookedConstructor = AdapterMethodHandle.makeCollectArguments(cookedConstructor, returner, 0, true); cookedConstructor = AdapterMethodHandle.makeCollectArguments(cookedConstructor, returner, 0, true);
MethodHandle allocator = new AllocateObject(allocateClass); AllocateObject allocator = new AllocateObject(allocateClass);
// allocate() => new C(void) // allocate() => new C(void)
assert(allocator.type().equals(MethodType.methodType(allocateClass))); assert(allocator.type().equals(MethodType.methodType(allocateClass)));
ctype = ctype.dropParameterTypes(0, 1); ctype = ctype.dropParameterTypes(0, 1);
...@@ -120,19 +120,19 @@ import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP; ...@@ -120,19 +120,19 @@ import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP;
return fold; return fold;
} }
static final class AllocateObject<C> extends BoundMethodHandle { static final class AllocateObject /*<C>*/ extends BoundMethodHandle {
private static final Unsafe unsafe = Unsafe.getUnsafe(); private static final Unsafe unsafe = Unsafe.getUnsafe();
private final Class<C> allocateClass; private final Class<?> /*<C>*/ allocateClass;
// for allocation only: // for allocation only:
private AllocateObject(Class<C> allocateClass) { private AllocateObject(Class<?> /*<C>*/ allocateClass) {
super(ALLOCATE.asType(MethodType.methodType(allocateClass, AllocateObject.class))); super(ALLOCATE.asType(MethodType.methodType(allocateClass, AllocateObject.class)));
this.allocateClass = allocateClass; this.allocateClass = allocateClass;
} }
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
private C allocate() throws InstantiationException { private Object /*C*/ allocate() throws InstantiationException {
return (C) unsafe.allocateInstance(allocateClass); return unsafe.allocateInstance(allocateClass);
} }
static final MethodHandle ALLOCATE; static final MethodHandle ALLOCATE;
static { static {
...@@ -148,8 +148,8 @@ import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP; ...@@ -148,8 +148,8 @@ import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP;
MethodHandle accessField(MemberName member, boolean isSetter, MethodHandle accessField(MemberName member, boolean isSetter,
Class<?> lookupClass) { Class<?> lookupClass) {
// Use sun. misc.Unsafe to dig up the dirt on the field. // Use sun. misc.Unsafe to dig up the dirt on the field.
MethodHandle mh = new FieldAccessor(member, isSetter); FieldAccessor accessor = new FieldAccessor(member, isSetter);
return mh; return accessor;
} }
static static
...@@ -175,7 +175,7 @@ import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP; ...@@ -175,7 +175,7 @@ import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP;
return mhs[isSetter ? 1 : 0]; return mhs[isSetter ? 1 : 0];
} }
static final class FieldAccessor<C,V> extends BoundMethodHandle { static final class FieldAccessor /*<C,V>*/ extends BoundMethodHandle {
private static final Unsafe unsafe = Unsafe.getUnsafe(); private static final Unsafe unsafe = Unsafe.getUnsafe();
final Object base; // for static refs only final Object base; // for static refs only
final long offset; final long offset;
...@@ -190,26 +190,24 @@ import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP; ...@@ -190,26 +190,24 @@ import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP;
@Override @Override
String debugString() { return addTypeString(name, this); } String debugString() { return addTypeString(name, this); }
int getFieldI(C obj) { return unsafe.getInt(obj, offset); } int getFieldI(Object /*C*/ obj) { return unsafe.getInt(obj, offset); }
void setFieldI(C obj, int x) { unsafe.putInt(obj, offset, x); } void setFieldI(Object /*C*/ obj, int x) { unsafe.putInt(obj, offset, x); }
long getFieldJ(C obj) { return unsafe.getLong(obj, offset); } long getFieldJ(Object /*C*/ obj) { return unsafe.getLong(obj, offset); }
void setFieldJ(C obj, long x) { unsafe.putLong(obj, offset, x); } void setFieldJ(Object /*C*/ obj, long x) { unsafe.putLong(obj, offset, x); }
float getFieldF(C obj) { return unsafe.getFloat(obj, offset); } float getFieldF(Object /*C*/ obj) { return unsafe.getFloat(obj, offset); }
void setFieldF(C obj, float x) { unsafe.putFloat(obj, offset, x); } void setFieldF(Object /*C*/ obj, float x) { unsafe.putFloat(obj, offset, x); }
double getFieldD(C obj) { return unsafe.getDouble(obj, offset); } double getFieldD(Object /*C*/ obj) { return unsafe.getDouble(obj, offset); }
void setFieldD(C obj, double x) { unsafe.putDouble(obj, offset, x); } void setFieldD(Object /*C*/ obj, double x) { unsafe.putDouble(obj, offset, x); }
boolean getFieldZ(C obj) { return unsafe.getBoolean(obj, offset); } boolean getFieldZ(Object /*C*/ obj) { return unsafe.getBoolean(obj, offset); }
void setFieldZ(C obj, boolean x) { unsafe.putBoolean(obj, offset, x); } void setFieldZ(Object /*C*/ obj, boolean x) { unsafe.putBoolean(obj, offset, x); }
byte getFieldB(C obj) { return unsafe.getByte(obj, offset); } byte getFieldB(Object /*C*/ obj) { return unsafe.getByte(obj, offset); }
void setFieldB(C obj, byte x) { unsafe.putByte(obj, offset, x); } void setFieldB(Object /*C*/ obj, byte x) { unsafe.putByte(obj, offset, x); }
short getFieldS(C obj) { return unsafe.getShort(obj, offset); } short getFieldS(Object /*C*/ obj) { return unsafe.getShort(obj, offset); }
void setFieldS(C obj, short x) { unsafe.putShort(obj, offset, x); } void setFieldS(Object /*C*/ obj, short x) { unsafe.putShort(obj, offset, x); }
char getFieldC(C obj) { return unsafe.getChar(obj, offset); } char getFieldC(Object /*C*/ obj) { return unsafe.getChar(obj, offset); }
void setFieldC(C obj, char x) { unsafe.putChar(obj, offset, x); } void setFieldC(Object /*C*/ obj, char x) { unsafe.putChar(obj, offset, x); }
@SuppressWarnings("unchecked") Object /*V*/ getFieldL(Object /*C*/ obj) { return unsafe.getObject(obj, offset); }
V getFieldL(C obj) { return (V) unsafe.getObject(obj, offset); } void setFieldL(Object /*C*/ obj, Object /*V*/ x) { unsafe.putObject(obj, offset, x); }
@SuppressWarnings("unchecked")
void setFieldL(C obj, V x) { unsafe.putObject(obj, offset, x); }
// cast (V) is OK here, since we wrap convertArguments around the MH. // cast (V) is OK here, since we wrap convertArguments around the MH.
static Object staticBase(final MemberName field) { static Object staticBase(final MemberName field) {
...@@ -244,8 +242,9 @@ import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP; ...@@ -244,8 +242,9 @@ import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP;
void setStaticS(short x) { unsafe.putShort(base, offset, x); } void setStaticS(short x) { unsafe.putShort(base, offset, x); }
char getStaticC() { return unsafe.getChar(base, offset); } char getStaticC() { return unsafe.getChar(base, offset); }
void setStaticC(char x) { unsafe.putChar(base, offset, x); } void setStaticC(char x) { unsafe.putChar(base, offset, x); }
V getStaticL() { return (V) unsafe.getObject(base, offset); } @SuppressWarnings("unchecked") // (V) is for internal clarity but triggers warning
void setStaticL(V x) { unsafe.putObject(base, offset, x); } Object /*V*/ getStaticL() { return unsafe.getObject(base, offset); }
void setStaticL(Object /*V*/ x) { unsafe.putObject(base, offset, x); }
static String fname(Class<?> vclass, boolean isSetter, boolean isStatic) { static String fname(Class<?> vclass, boolean isSetter, boolean isStatic) {
String stem; String stem;
......
...@@ -150,7 +150,7 @@ public class MethodHandleProxies { ...@@ -150,7 +150,7 @@ public class MethodHandleProxies {
} }
return intfc.cast(Proxy.newProxyInstance( return intfc.cast(Proxy.newProxyInstance(
intfc.getClassLoader(), intfc.getClassLoader(),
new Class[]{ intfc, WrapperInstance.class }, new Class<?>[]{ intfc, WrapperInstance.class },
new InvocationHandler() { new InvocationHandler() {
private Object getArg(String name) { private Object getArg(String name) {
if ((Object)name == "getWrapperInstanceTarget") return target; if ((Object)name == "getWrapperInstanceTarget") return target;
......
...@@ -948,10 +948,11 @@ return mh1; ...@@ -948,10 +948,11 @@ return mh1;
public MethodHandle unreflect(Method m) throws IllegalAccessException { public MethodHandle unreflect(Method m) throws IllegalAccessException {
MemberName method = new MemberName(m); MemberName method = new MemberName(m);
assert(method.isMethod()); assert(method.isMethod());
if (!m.isAccessible()) checkMethod(method.getDeclaringClass(), method, method.isStatic()); if (m.isAccessible())
return MethodHandleImpl.findMethod(method, true, /*no lookupClass*/ null);
checkMethod(method.getDeclaringClass(), method, method.isStatic());
MethodHandle mh = MethodHandleImpl.findMethod(method, true, lookupClassOrNull()); MethodHandle mh = MethodHandleImpl.findMethod(method, true, lookupClassOrNull());
if (!m.isAccessible()) mh = restrictProtectedReceiver(method, mh); return restrictProtectedReceiver(method, mh);
return mh;
} }
/** /**
...@@ -1006,11 +1007,17 @@ return mh1; ...@@ -1006,11 +1007,17 @@ return mh1;
* is set and {@code asVarargsCollector} fails * is set and {@code asVarargsCollector} fails
* @throws NullPointerException if the argument is null * @throws NullPointerException if the argument is null
*/ */
@SuppressWarnings("rawtypes") // Will be Constructor<?> after JSR 292 MR
public MethodHandle unreflectConstructor(Constructor c) throws IllegalAccessException { public MethodHandle unreflectConstructor(Constructor c) throws IllegalAccessException {
MemberName ctor = new MemberName(c); MemberName ctor = new MemberName(c);
assert(ctor.isConstructor()); assert(ctor.isConstructor());
if (!c.isAccessible()) checkAccess(c.getDeclaringClass(), ctor); MethodHandle rawCtor;
MethodHandle rawCtor = MethodHandleImpl.findMethod(ctor, false, lookupClassOrNull()); if (c.isAccessible()) {
rawCtor = MethodHandleImpl.findMethod(ctor, false, /*no lookupClass*/ null);
} else {
checkAccess(c.getDeclaringClass(), ctor);
rawCtor = MethodHandleImpl.findMethod(ctor, false, lookupClassOrNull());
}
MethodHandle allocator = MethodHandleImpl.makeAllocator(rawCtor); MethodHandle allocator = MethodHandleImpl.makeAllocator(rawCtor);
return fixVarargs(allocator, rawCtor); return fixVarargs(allocator, rawCtor);
} }
...@@ -1225,7 +1232,7 @@ return mh1; ...@@ -1225,7 +1232,7 @@ return mh1;
? "expected a static field" ? "expected a static field"
: "expected a non-static field", this); : "expected a non-static field", this);
if (trusted) if (trusted)
return MethodHandleImpl.accessField(field, isSetter, lookupClassOrNull()); return MethodHandleImpl.accessField(field, isSetter, /*no lookupClass*/ null);
checkAccess(refc, field); checkAccess(refc, field);
MethodHandle mh = MethodHandleImpl.accessField(field, isSetter, lookupClassOrNull()); MethodHandle mh = MethodHandleImpl.accessField(field, isSetter, lookupClassOrNull());
return restrictProtectedReceiver(field, mh); return restrictProtectedReceiver(field, mh);
......
...@@ -1932,6 +1932,7 @@ public class BasicTreeUI extends TreeUI ...@@ -1932,6 +1932,7 @@ public class BasicTreeUI extends TreeUI
else { else {
Rectangle beginRect = getPathBounds(tree, getPathForRow Rectangle beginRect = getPathBounds(tree, getPathForRow
(tree, beginRow)); (tree, beginRow));
if (beginRect != null) {
Rectangle visRect = tree.getVisibleRect(); Rectangle visRect = tree.getVisibleRect();
Rectangle testRect = beginRect; Rectangle testRect = beginRect;
int beginY = beginRect.y; int beginY = beginRect.y;
...@@ -1949,6 +1950,7 @@ public class BasicTreeUI extends TreeUI ...@@ -1949,6 +1950,7 @@ public class BasicTreeUI extends TreeUI
} }
} }
} }
}
/** Sets the preferred minimum size. /** Sets the preferred minimum size.
*/ */
...@@ -3485,7 +3487,7 @@ public class BasicTreeUI extends TreeUI ...@@ -3485,7 +3487,7 @@ public class BasicTreeUI extends TreeUI
} }
Rectangle bounds = getPathBounds(tree, path); Rectangle bounds = getPathBounds(tree, path);
if (y > (bounds.y + bounds.height)) { if (bounds == null || y > (bounds.y + bounds.height)) {
return false; return false;
} }
......
...@@ -55,9 +55,9 @@ public class ValueConversions { ...@@ -55,9 +55,9 @@ public class ValueConversions {
private static final Lookup IMPL_LOOKUP = MethodHandles.lookup(); private static final Lookup IMPL_LOOKUP = MethodHandles.lookup();
private static EnumMap<Wrapper, MethodHandle>[] newWrapperCaches(int n) { private static EnumMap<Wrapper, MethodHandle>[] newWrapperCaches(int n) {
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked") // generic array creation
EnumMap<Wrapper, MethodHandle>[] caches EnumMap<Wrapper, MethodHandle>[] caches
= (EnumMap<Wrapper, MethodHandle>[]) new EnumMap[n]; // unchecked warning expected here = (EnumMap<Wrapper, MethodHandle>[]) new EnumMap<?,?>[n];
for (int i = 0; i < n; i++) for (int i = 0; i < n; i++)
caches[i] = new EnumMap<>(Wrapper.class); caches[i] = new EnumMap<>(Wrapper.class);
return caches; return caches;
...@@ -1097,7 +1097,7 @@ public class ValueConversions { ...@@ -1097,7 +1097,7 @@ public class ValueConversions {
} }
private static MethodHandle buildNewArray(int nargs) { private static MethodHandle buildNewArray(int nargs) {
return MethodHandles.insertArguments(NEW_ARRAY, 0, (int) nargs); return MethodHandles.insertArguments(NEW_ARRAY, 0, nargs);
} }
private static final MethodHandle[] FILLERS = new MethodHandle[MAX_ARITY+1]; private static final MethodHandle[] FILLERS = new MethodHandle[MAX_ARITY+1];
...@@ -1122,7 +1122,7 @@ public class ValueConversions { ...@@ -1122,7 +1122,7 @@ public class ValueConversions {
} }
MethodHandle leftFill = filler(leftLen); // recursive fill MethodHandle leftFill = filler(leftLen); // recursive fill
MethodHandle rightFill = FILL_ARRAYS[rightLen]; MethodHandle rightFill = FILL_ARRAYS[rightLen];
rightFill = MethodHandles.insertArguments(rightFill, 1, (int) leftLen); // [leftLen..nargs-1] rightFill = MethodHandles.insertArguments(rightFill, 1, leftLen); // [leftLen..nargs-1]
// Combine the two fills: right(left(newArray(nargs), x1..x20), x21..x23) // Combine the two fills: right(left(newArray(nargs), x1..x20), x21..x23)
MethodHandle mh = filler(0); // identity function produces result MethodHandle mh = filler(0); // identity function produces result
......
...@@ -31,7 +31,7 @@ public enum Wrapper { ...@@ -31,7 +31,7 @@ public enum Wrapper {
BYTE(Byte.class, byte.class, 'B', (Byte)(byte)0, new byte[0], Format.signed(8)), BYTE(Byte.class, byte.class, 'B', (Byte)(byte)0, new byte[0], Format.signed(8)),
SHORT(Short.class, short.class, 'S', (Short)(short)0, new short[0], Format.signed(16)), SHORT(Short.class, short.class, 'S', (Short)(short)0, new short[0], Format.signed(16)),
CHAR(Character.class, char.class, 'C', (Character)(char)0, new char[0], Format.unsigned(16)), CHAR(Character.class, char.class, 'C', (Character)(char)0, new char[0], Format.unsigned(16)),
INT(Integer.class, int.class, 'I', (Integer)(int)0, new int[0], Format.signed(32)), INT(Integer.class, int.class, 'I', (Integer)/*(int)*/0, new int[0], Format.signed(32)),
LONG(Long.class, long.class, 'J', (Long)(long)0, new long[0], Format.signed(64)), LONG(Long.class, long.class, 'J', (Long)(long)0, new long[0], Format.signed(64)),
FLOAT(Float.class, float.class, 'F', (Float)(float)0, new float[0], Format.floating(32)), FLOAT(Float.class, float.class, 'F', (Float)(float)0, new float[0], Format.floating(32)),
DOUBLE(Double.class, double.class, 'D', (Double)(double)0, new double[0], Format.floating(64)), DOUBLE(Double.class, double.class, 'D', (Double)(double)0, new double[0], Format.floating(64)),
...@@ -539,7 +539,7 @@ public enum Wrapper { ...@@ -539,7 +539,7 @@ public enum Wrapper {
switch (basicTypeChar) { switch (basicTypeChar) {
case 'L': throw newIllegalArgumentException("cannot wrap to object type"); case 'L': throw newIllegalArgumentException("cannot wrap to object type");
case 'V': return null; case 'V': return null;
case 'I': return Integer.valueOf((int)x); case 'I': return Integer.valueOf(x);
case 'J': return Long.valueOf(x); case 'J': return Long.valueOf(x);
case 'F': return Float.valueOf(x); case 'F': return Float.valueOf(x);
case 'D': return Double.valueOf(x); case 'D': return Double.valueOf(x);
......
...@@ -76,9 +76,12 @@ class GtkFileDialogPeer extends XDialogPeer implements FileDialogPeer { ...@@ -76,9 +76,12 @@ class GtkFileDialogPeer extends XDialogPeer implements FileDialogPeer {
accessor.setFiles(fd, null, null); accessor.setFiles(fd, null, null);
} else { } else {
// Fix 6987233: add the trailing slash if it's absent // Fix 6987233: add the trailing slash if it's absent
accessor.setDirectory(fd, directory + String with_separator = directory;
(directory.endsWith(File.separator) ? if (directory != null) {
"" : File.separator)); with_separator = directory.endsWith(File.separator) ?
directory : (directory + File.separator);
}
accessor.setDirectory(fd, with_separator);
accessor.setFile(fd, filenames[0]); accessor.setFile(fd, filenames[0]);
accessor.setFiles(fd, directory, filenames); accessor.setFiles(fd, directory, filenames);
} }
......
...@@ -28,6 +28,9 @@ package sun.java2d.xr; ...@@ -28,6 +28,9 @@ package sun.java2d.xr;
import java.awt.*; import java.awt.*;
import java.awt.geom.*; import java.awt.geom.*;
import java.security.AccessController;
import java.security.PrivilegedAction;
import sun.font.*; import sun.font.*;
import sun.java2d.*; import sun.java2d.*;
import sun.java2d.jules.*; import sun.java2d.jules.*;
...@@ -83,7 +86,13 @@ public class XRCompositeManager { ...@@ -83,7 +86,13 @@ public class XRCompositeManager {
con = new XRBackendNative(); con = new XRBackendNative();
// con = XRBackendJava.getInstance(); // con = XRBackendJava.getInstance();
String gradProp = System.getProperty("sun.java2d.xrgradcache"); String gradProp =
AccessController.doPrivileged(new PrivilegedAction<String>() {
public String run() {
return System.getProperty("sun.java2d.xrgradcache");
}
});
enableGradCache = gradProp == null || enableGradCache = gradProp == null ||
!(gradProp.equalsIgnoreCase("false") || !(gradProp.equalsIgnoreCase("false") ||
gradProp.equalsIgnoreCase("f")); gradProp.equalsIgnoreCase("f"));
......
...@@ -43,7 +43,7 @@ import static java.lang.invoke.MethodHandles.*; ...@@ -43,7 +43,7 @@ import static java.lang.invoke.MethodHandles.*;
import static java.lang.invoke.MethodType.*; import static java.lang.invoke.MethodType.*;
public class CallSiteTest { public class CallSiteTest {
private final static Class CLASS = CallSiteTest.class; private final static Class<?> CLASS = CallSiteTest.class;
private static CallSite mcs; private static CallSite mcs;
private static CallSite vcs; private static CallSite vcs;
......
...@@ -38,10 +38,6 @@ ...@@ -38,10 +38,6 @@
package test.java.lang.invoke; package test.java.lang.invoke;
import java.util.*;
import java.lang.invoke.*;
import org.junit.*; import org.junit.*;
import static org.junit.Assert.*; import static org.junit.Assert.*;
...@@ -61,7 +57,7 @@ public class ClassValueTest { ...@@ -61,7 +57,7 @@ public class ClassValueTest {
} }
} }
static final Class[] CLASSES = { static final Class<?>[] CLASSES = {
String.class, String.class,
Integer.class, Integer.class,
int.class, int.class,
...@@ -73,11 +69,11 @@ public class ClassValueTest { ...@@ -73,11 +69,11 @@ public class ClassValueTest {
@Test @Test
public void testGet() { public void testGet() {
countForCV1 = 0; countForCV1 = 0;
for (Class c : CLASSES) { for (Class<?> c : CLASSES) {
assertEquals(nameForCV1(c), CV1.get(c)); assertEquals(nameForCV1(c), CV1.get(c));
} }
assertEquals(CLASSES.length, countForCV1); assertEquals(CLASSES.length, countForCV1);
for (Class c : CLASSES) { for (Class<?> c : CLASSES) {
assertEquals(nameForCV1(c), CV1.get(c)); assertEquals(nameForCV1(c), CV1.get(c));
} }
assertEquals(CLASSES.length, countForCV1); assertEquals(CLASSES.length, countForCV1);
...@@ -85,7 +81,7 @@ public class ClassValueTest { ...@@ -85,7 +81,7 @@ public class ClassValueTest {
@Test @Test
public void testRemove() { public void testRemove() {
for (Class c : CLASSES) { for (Class<?> c : CLASSES) {
CV1.get(c); CV1.get(c);
} }
countForCV1 = 0; countForCV1 = 0;
...@@ -94,7 +90,7 @@ public class ClassValueTest { ...@@ -94,7 +90,7 @@ public class ClassValueTest {
CV1.remove(CLASSES[i]); CV1.remove(CLASSES[i]);
} }
assertEquals(0, countForCV1); // no change assertEquals(0, countForCV1); // no change
for (Class c : CLASSES) { for (Class<?> c : CLASSES) {
assertEquals(nameForCV1(c), CV1.get(c)); assertEquals(nameForCV1(c), CV1.get(c));
} }
assertEquals(REMCOUNT, countForCV1); assertEquals(REMCOUNT, countForCV1);
...@@ -124,7 +120,7 @@ public class ClassValueTest { ...@@ -124,7 +120,7 @@ public class ClassValueTest {
for (int pass = 0; pass <= 2; pass++) { for (int pass = 0; pass <= 2; pass++) {
for (int i1 = 0; i1 < CVN_COUNT1; i1++) { for (int i1 = 0; i1 < CVN_COUNT1; i1++) {
eachClass: eachClass:
for (Class c : CLASSES) { for (Class<?> c : CLASSES) {
for (int i2 = 0; i2 < CVN_COUNT2; i2++) { for (int i2 = 0; i2 < CVN_COUNT2; i2++) {
int n = i1*CVN_COUNT2 + i2; int n = i1*CVN_COUNT2 + i2;
assertEquals(0, countForCVN); assertEquals(0, countForCVN);
...@@ -156,8 +152,10 @@ public class ClassValueTest { ...@@ -156,8 +152,10 @@ public class ClassValueTest {
} }
} }
assertEquals(countForCVN, 0); assertEquals(countForCVN, 0);
for (int n = 0; n < cvns.length; n++) { System.out.println("[rechecking values]");
for (Class c : CLASSES) { for (int i = 0; i < cvns.length * 10; i++) {
int n = i % cvns.length;
for (Class<?> c : CLASSES) {
assertEquals(nameForCVN(c, n), cvns[n].get(c)); assertEquals(nameForCVN(c, n), cvns[n].get(c));
} }
} }
......
...@@ -45,6 +45,7 @@ import static org.junit.Assume.*; ...@@ -45,6 +45,7 @@ import static org.junit.Assume.*;
* *
* @author jrose * @author jrose
*/ */
@SuppressWarnings("cast") // various casts help emphasize arguments to invokeExact
public class InvokeGenericTest { public class InvokeGenericTest {
// How much output? // How much output?
static int verbosity = 0; static int verbosity = 0;
...@@ -129,7 +130,7 @@ public class InvokeGenericTest { ...@@ -129,7 +130,7 @@ public class InvokeGenericTest {
} }
} }
static List<Object> calledLog = new ArrayList<Object>(); static List<Object> calledLog = new ArrayList<>();
static Object logEntry(String name, Object... args) { static Object logEntry(String name, Object... args) {
return Arrays.asList(name, Arrays.asList(args)); return Arrays.asList(name, Arrays.asList(args));
} }
...@@ -237,8 +238,7 @@ public class InvokeGenericTest { ...@@ -237,8 +238,7 @@ public class InvokeGenericTest {
else else
try { try {
return param.newInstance(); return param.newInstance();
} catch (InstantiationException ex) { } catch (InstantiationException | IllegalAccessException ex) {
} catch (IllegalAccessException ex) {
} }
return null; // random class not Object, String, Integer, etc. return null; // random class not Object, String, Integer, etc.
} }
...@@ -274,9 +274,11 @@ public class InvokeGenericTest { ...@@ -274,9 +274,11 @@ public class InvokeGenericTest {
return zeroArgs(params.toArray(new Class<?>[0])); return zeroArgs(params.toArray(new Class<?>[0]));
} }
@SafeVarargs @SuppressWarnings("varargs")
static <T, E extends T> T[] array(Class<T[]> atype, E... a) { static <T, E extends T> T[] array(Class<T[]> atype, E... a) {
return Arrays.copyOf(a, a.length, atype); return Arrays.copyOf(a, a.length, atype);
} }
@SafeVarargs @SuppressWarnings("varargs")
static <T> T[] cat(T[] a, T... b) { static <T> T[] cat(T[] a, T... b) {
int alen = a.length, blen = b.length; int alen = a.length, blen = b.length;
if (blen == 0) return a; if (blen == 0) return a;
...@@ -311,7 +313,7 @@ public class InvokeGenericTest { ...@@ -311,7 +313,7 @@ public class InvokeGenericTest {
int beg, int end, Class<?> argType) { int beg, int end, Class<?> argType) {
MethodType targetType = target.type(); MethodType targetType = target.type();
end = Math.min(end, targetType.parameterCount()); end = Math.min(end, targetType.parameterCount());
ArrayList<Class<?>> argTypes = new ArrayList<Class<?>>(targetType.parameterList()); ArrayList<Class<?>> argTypes = new ArrayList<>(targetType.parameterList());
Collections.fill(argTypes.subList(beg, end), argType); Collections.fill(argTypes.subList(beg, end), argType);
MethodType ttype2 = MethodType.methodType(targetType.returnType(), argTypes); MethodType ttype2 = MethodType.methodType(targetType.returnType(), argTypes);
return target.asType(ttype2); return target.asType(ttype2);
...@@ -320,7 +322,7 @@ public class InvokeGenericTest { ...@@ -320,7 +322,7 @@ public class InvokeGenericTest {
// This lookup is good for all members in and under InvokeGenericTest. // This lookup is good for all members in and under InvokeGenericTest.
static final Lookup LOOKUP = MethodHandles.lookup(); static final Lookup LOOKUP = MethodHandles.lookup();
Map<List<Class<?>>, MethodHandle> CALLABLES = new HashMap<List<Class<?>>, MethodHandle>(); Map<List<Class<?>>, MethodHandle> CALLABLES = new HashMap<>();
MethodHandle callable(List<Class<?>> params) { MethodHandle callable(List<Class<?>> params) {
MethodHandle mh = CALLABLES.get(params); MethodHandle mh = CALLABLES.get(params);
if (mh == null) { if (mh == null) {
...@@ -353,8 +355,8 @@ public class InvokeGenericTest { ...@@ -353,8 +355,8 @@ public class InvokeGenericTest {
countTest(); countTest();
String[] args = { "one", "two" }; String[] args = { "one", "two" };
MethodHandle mh = callable(Object.class, String.class); MethodHandle mh = callable(Object.class, String.class);
Object res; List resl; Object res; List<?> resl;
res = resl = (List) mh.invoke((String)args[0], (Object)args[1]); res = resl = (List<?>) mh.invoke((String)args[0], (Object)args[1]);
//System.out.println(res); //System.out.println(res);
assertEquals(Arrays.asList(args), res); assertEquals(Arrays.asList(args), res);
} }
...@@ -365,8 +367,8 @@ public class InvokeGenericTest { ...@@ -365,8 +367,8 @@ public class InvokeGenericTest {
countTest(); countTest();
int[] args = { 1, 2 }; int[] args = { 1, 2 };
MethodHandle mh = callable(Object.class, Object.class); MethodHandle mh = callable(Object.class, Object.class);
Object res; List resl; Object res; List<?> resl;
res = resl = (List) mh.invoke(args[0], args[1]); res = resl = (List<?>) mh.invoke(args[0], args[1]);
//System.out.println(res); //System.out.println(res);
assertEquals(Arrays.toString(args), res.toString()); assertEquals(Arrays.toString(args), res.toString());
} }
...@@ -377,8 +379,8 @@ public class InvokeGenericTest { ...@@ -377,8 +379,8 @@ public class InvokeGenericTest {
countTest(); countTest();
String[] args = { "one", "two" }; String[] args = { "one", "two" };
MethodHandle mh = callable(Object.class, String.class); MethodHandle mh = callable(Object.class, String.class);
Object res; List resl; Object res; List<?> resl;
res = resl = (List) mh.invoke((String)args[0], (Object)args[1]); res = resl = (List<?>) mh.invoke((String)args[0], (Object)args[1]);
//System.out.println(res); //System.out.println(res);
assertEquals(Arrays.asList(args), res); assertEquals(Arrays.asList(args), res);
} }
...@@ -440,9 +442,9 @@ public class InvokeGenericTest { ...@@ -440,9 +442,9 @@ public class InvokeGenericTest {
* A void return type is possible iff the first type is void.class. * A void return type is possible iff the first type is void.class.
*/ */
static List<MethodType> allMethodTypes(int minargc, int maxargc, Class<?>... types) { static List<MethodType> allMethodTypes(int minargc, int maxargc, Class<?>... types) {
ArrayList<MethodType> result = new ArrayList<MethodType>(); ArrayList<MethodType> result = new ArrayList<>();
if (types.length > 0) { if (types.length > 0) {
ArrayList<MethodType> argcTypes = new ArrayList<MethodType>(); ArrayList<MethodType> argcTypes = new ArrayList<>();
// build arity-zero types first // build arity-zero types first
for (Class<?> rtype : types) { for (Class<?> rtype : types) {
argcTypes.add(MethodType.methodType(rtype)); argcTypes.add(MethodType.methodType(rtype));
...@@ -456,7 +458,7 @@ public class InvokeGenericTest { ...@@ -456,7 +458,7 @@ public class InvokeGenericTest {
if (argc >= maxargc) if (argc >= maxargc)
break; break;
ArrayList<MethodType> prevTypes = argcTypes; ArrayList<MethodType> prevTypes = argcTypes;
argcTypes = new ArrayList<MethodType>(); argcTypes = new ArrayList<>();
for (MethodType prevType : prevTypes) { for (MethodType prevType : prevTypes) {
for (Class<?> ptype : types) { for (Class<?> ptype : types) {
argcTypes.add(prevType.insertParameterTypes(argc, ptype)); argcTypes.add(prevType.insertParameterTypes(argc, ptype));
...@@ -524,8 +526,8 @@ public class InvokeGenericTest { ...@@ -524,8 +526,8 @@ public class InvokeGenericTest {
countTest(); countTest();
Object[] args = { 1, 2 }; Object[] args = { 1, 2 };
MethodHandle mh = callable(Object.class, int.class); MethodHandle mh = callable(Object.class, int.class);
Object res; List resl; int resi; Object res; List<?> resl; int resi;
res = resl = (List) mh.invoke((int)args[0], (Object)args[1]); res = resl = (List<?>) mh.invoke((int)args[0], (Object)args[1]);
//System.out.println(res); //System.out.println(res);
assertEquals(Arrays.asList(args), res); assertEquals(Arrays.asList(args), res);
mh = MethodHandles.identity(int.class); mh = MethodHandles.identity(int.class);
......
...@@ -54,6 +54,7 @@ import static org.junit.Assert.*; ...@@ -54,6 +54,7 @@ import static org.junit.Assert.*;
/** /**
* @author jrose * @author jrose
*/ */
@SuppressWarnings("LocalVariableHidesMemberVariable")
public class JavaDocExamplesTest { public class JavaDocExamplesTest {
/** Wrapper for running the JUnit tests in this module. /** Wrapper for running the JUnit tests in this module.
* Put JUnit on the classpath! * Put JUnit on the classpath!
...@@ -336,6 +337,7 @@ assertEquals("[123]", (String) longsToString.invokeExact((long)123)); ...@@ -336,6 +337,7 @@ assertEquals("[123]", (String) longsToString.invokeExact((long)123));
}} }}
} }
@SuppressWarnings("rawtypes")
@Test public void testAsVarargsCollector() throws Throwable { @Test public void testAsVarargsCollector() throws Throwable {
{{ {{
{} /// JAVADOC {} /// JAVADOC
......
...@@ -176,7 +176,7 @@ public class MethodHandlesTest { ...@@ -176,7 +176,7 @@ public class MethodHandlesTest {
} }
} }
static List<Object> calledLog = new ArrayList<Object>(); static List<Object> calledLog = new ArrayList<>();
static Object logEntry(String name, Object... args) { static Object logEntry(String name, Object... args) {
return Arrays.asList(name, Arrays.asList(args)); return Arrays.asList(name, Arrays.asList(args));
} }
...@@ -211,6 +211,7 @@ public class MethodHandlesTest { ...@@ -211,6 +211,7 @@ public class MethodHandlesTest {
return dst.cast(value); return dst.cast(value);
} }
@SuppressWarnings("cast") // primitive cast to (long) is part of the pattern
static Object castToWrapperOrNull(long value, Class<?> dst) { static Object castToWrapperOrNull(long value, Class<?> dst) {
if (dst == int.class || dst == Integer.class) if (dst == int.class || dst == Integer.class)
return (int)(value); return (int)(value);
...@@ -284,8 +285,7 @@ public class MethodHandlesTest { ...@@ -284,8 +285,7 @@ public class MethodHandlesTest {
else else
try { try {
return param.newInstance(); return param.newInstance();
} catch (InstantiationException ex) { } catch (InstantiationException | IllegalAccessException ex) {
} catch (IllegalAccessException ex) {
} }
return null; // random class not Object, String, Integer, etc. return null; // random class not Object, String, Integer, etc.
} }
...@@ -302,9 +302,11 @@ public class MethodHandlesTest { ...@@ -302,9 +302,11 @@ public class MethodHandlesTest {
return args; return args;
} }
@SafeVarargs @SuppressWarnings("varargs")
static <T, E extends T> T[] array(Class<T[]> atype, E... a) { static <T, E extends T> T[] array(Class<T[]> atype, E... a) {
return Arrays.copyOf(a, a.length, atype); return Arrays.copyOf(a, a.length, atype);
} }
@SafeVarargs @SuppressWarnings("varargs")
static <T> T[] cat(T[] a, T... b) { static <T> T[] cat(T[] a, T... b) {
int alen = a.length, blen = b.length; int alen = a.length, blen = b.length;
if (blen == 0) return a; if (blen == 0) return a;
...@@ -354,14 +356,14 @@ public class MethodHandlesTest { ...@@ -354,14 +356,14 @@ public class MethodHandlesTest {
try { try {
LIST_TO_STRING = PRIVATE.findStatic(PRIVATE.lookupClass(), "listToString", LIST_TO_STRING = PRIVATE.findStatic(PRIVATE.lookupClass(), "listToString",
MethodType.methodType(String.class, List.class)); MethodType.methodType(String.class, List.class));
} catch (Exception ex) { throw new RuntimeException(ex); } } catch (NoSuchMethodException | IllegalAccessException ex) { throw new RuntimeException(ex); }
list = MethodHandles.filterReturnValue(list, LIST_TO_STRING); list = MethodHandles.filterReturnValue(list, LIST_TO_STRING);
} else if (rtype.isPrimitive()) { } else if (rtype.isPrimitive()) {
if (LIST_TO_INT == null) if (LIST_TO_INT == null)
try { try {
LIST_TO_INT = PRIVATE.findStatic(PRIVATE.lookupClass(), "listToInt", LIST_TO_INT = PRIVATE.findStatic(PRIVATE.lookupClass(), "listToInt",
MethodType.methodType(int.class, List.class)); MethodType.methodType(int.class, List.class));
} catch (Exception ex) { throw new RuntimeException(ex); } } catch (NoSuchMethodException | IllegalAccessException ex) { throw new RuntimeException(ex); }
list = MethodHandles.filterReturnValue(list, LIST_TO_INT); list = MethodHandles.filterReturnValue(list, LIST_TO_INT);
list = MethodHandles.explicitCastArguments(list, listType); list = MethodHandles.explicitCastArguments(list, listType);
} else { } else {
...@@ -370,8 +372,8 @@ public class MethodHandlesTest { ...@@ -370,8 +372,8 @@ public class MethodHandlesTest {
return list.asType(listType); return list.asType(listType);
} }
private static MethodHandle LIST_TO_STRING, LIST_TO_INT; private static MethodHandle LIST_TO_STRING, LIST_TO_INT;
private static String listToString(List x) { return x.toString(); } private static String listToString(List<?> x) { return x.toString(); }
private static int listToInt(List x) { return x.toString().hashCode(); } private static int listToInt(List<?> x) { return x.toString().hashCode(); }
static MethodHandle changeArgTypes(MethodHandle target, Class<?> argType) { static MethodHandle changeArgTypes(MethodHandle target, Class<?> argType) {
return changeArgTypes(target, 0, 999, argType); return changeArgTypes(target, 0, 999, argType);
...@@ -380,7 +382,7 @@ public class MethodHandlesTest { ...@@ -380,7 +382,7 @@ public class MethodHandlesTest {
int beg, int end, Class<?> argType) { int beg, int end, Class<?> argType) {
MethodType targetType = target.type(); MethodType targetType = target.type();
end = Math.min(end, targetType.parameterCount()); end = Math.min(end, targetType.parameterCount());
ArrayList<Class<?>> argTypes = new ArrayList<Class<?>>(targetType.parameterList()); ArrayList<Class<?>> argTypes = new ArrayList<>(targetType.parameterList());
Collections.fill(argTypes.subList(beg, end), argType); Collections.fill(argTypes.subList(beg, end), argType);
MethodType ttype2 = MethodType.methodType(targetType.returnType(), argTypes); MethodType ttype2 = MethodType.methodType(targetType.returnType(), argTypes);
return target.asType(ttype2); return target.asType(ttype2);
...@@ -405,6 +407,7 @@ public class MethodHandlesTest { ...@@ -405,6 +407,7 @@ public class MethodHandlesTest {
final String name; final String name;
public Example() { name = "Example#"+nextArg(); } public Example() { name = "Example#"+nextArg(); }
protected Example(String name) { this.name = name; } protected Example(String name) { this.name = name; }
@SuppressWarnings("LeakingThisInConstructor")
protected Example(int x) { this(); called("protected <init>", this, x); } protected Example(int x) { this(); called("protected <init>", this, x); }
@Override public String toString() { return name; } @Override public String toString() { return name; }
...@@ -441,6 +444,7 @@ public class MethodHandlesTest { ...@@ -441,6 +444,7 @@ public class MethodHandlesTest {
static class SubExample extends Example { static class SubExample extends Example {
@Override public void v0() { called("Sub/v0", this); } @Override public void v0() { called("Sub/v0", this); }
@Override void pkg_v0() { called("Sub/pkg_v0", this); } @Override void pkg_v0() { called("Sub/pkg_v0", this); }
@SuppressWarnings("LeakingThisInConstructor")
private SubExample(int x) { called("<init>", this, x); } private SubExample(int x) { called("<init>", this, x); }
public SubExample() { super("SubExample#"+nextArg()); } public SubExample() { super("SubExample#"+nextArg()); }
} }
...@@ -912,7 +916,7 @@ public class MethodHandlesTest { ...@@ -912,7 +916,7 @@ public class MethodHandlesTest {
static final Object[][] CASES; static final Object[][] CASES;
static { static {
ArrayList<Object[]> cases = new ArrayList<Object[]>(); ArrayList<Object[]> cases = new ArrayList<>();
Object types[][] = { Object types[][] = {
{'L',Object.class}, {'R',String.class}, {'L',Object.class}, {'R',String.class},
{'I',int.class}, {'J',long.class}, {'I',int.class}, {'J',long.class},
...@@ -931,12 +935,12 @@ public class MethodHandlesTest { ...@@ -931,12 +935,12 @@ public class MethodHandlesTest {
Field field; Field field;
try { try {
field = HasFields.class.getDeclaredField(name); field = HasFields.class.getDeclaredField(name);
} catch (Exception ex) { } catch (NoSuchFieldException | SecurityException ex) {
throw new InternalError("no field HasFields."+name); throw new InternalError("no field HasFields."+name);
} }
try { try {
value = field.get(fields); value = field.get(fields);
} catch (Exception ex) { } catch (IllegalArgumentException | IllegalAccessException ex) {
throw new InternalError("cannot fetch field HasFields."+name); throw new InternalError("cannot fetch field HasFields."+name);
} }
if (type == float.class) { if (type == float.class) {
...@@ -1257,7 +1261,7 @@ public class MethodHandlesTest { ...@@ -1257,7 +1261,7 @@ public class MethodHandlesTest {
List<Object> array2list(Object array) { List<Object> array2list(Object array) {
int length = Array.getLength(array); int length = Array.getLength(array);
ArrayList<Object> model = new ArrayList<Object>(length); ArrayList<Object> model = new ArrayList<>(length);
for (int i = 0; i < length; i++) for (int i = 0; i < length; i++)
model.add(Array.get(array, i)); model.add(Array.get(array, i));
return model; return model;
...@@ -1288,7 +1292,7 @@ public class MethodHandlesTest { ...@@ -1288,7 +1292,7 @@ public class MethodHandlesTest {
String name = pfx+"id"; String name = pfx+"id";
try { try {
return PRIVATE.findStatic(Callee.class, name, type); return PRIVATE.findStatic(Callee.class, name, type);
} catch (Exception ex) { } catch (NoSuchMethodException | IllegalAccessException ex) {
throw new RuntimeException(ex); throw new RuntimeException(ex);
} }
} }
...@@ -1365,7 +1369,7 @@ public class MethodHandlesTest { ...@@ -1365,7 +1369,7 @@ public class MethodHandlesTest {
MethodHandle vac = vac0.asVarargsCollector(Object[].class); MethodHandle vac = vac0.asVarargsCollector(Object[].class);
testConvert(true, vac.asType(MethodType.genericMethodType(0)), null, "vac"); testConvert(true, vac.asType(MethodType.genericMethodType(0)), null, "vac");
testConvert(true, vac.asType(MethodType.genericMethodType(0)), null, "vac"); testConvert(true, vac.asType(MethodType.genericMethodType(0)), null, "vac");
for (Class<?> at : new Class[] { Object.class, String.class, Integer.class }) { for (Class<?> at : new Class<?>[] { Object.class, String.class, Integer.class }) {
testConvert(true, vac.asType(MethodType.genericMethodType(1)), null, "vac", at); testConvert(true, vac.asType(MethodType.genericMethodType(1)), null, "vac", at);
testConvert(true, vac.asType(MethodType.genericMethodType(2)), null, "vac", at, at); testConvert(true, vac.asType(MethodType.genericMethodType(2)), null, "vac", at, at);
} }
...@@ -1514,7 +1518,7 @@ public class MethodHandlesTest { ...@@ -1514,7 +1518,7 @@ public class MethodHandlesTest {
public void testSpreadArguments() throws Throwable { public void testSpreadArguments() throws Throwable {
if (CAN_SKIP_WORKING) return; if (CAN_SKIP_WORKING) return;
startTest("spreadArguments"); startTest("spreadArguments");
for (Class<?> argType : new Class[]{Object.class, Integer.class, int.class}) { for (Class<?> argType : new Class<?>[]{Object.class, Integer.class, int.class}) {
if (verbosity >= 3) if (verbosity >= 3)
System.out.println("spreadArguments "+argType); System.out.println("spreadArguments "+argType);
for (int nargs = 0; nargs < 50; nargs++) { for (int nargs = 0; nargs < 50; nargs++) {
...@@ -1538,7 +1542,7 @@ public class MethodHandlesTest { ...@@ -1538,7 +1542,7 @@ public class MethodHandlesTest {
Object[] args = randomArgs(target2.type().parameterArray()); Object[] args = randomArgs(target2.type().parameterArray());
// make sure the target does what we think it does: // make sure the target does what we think it does:
if (pos == 0 && nargs < 5 && !argType.isPrimitive()) { if (pos == 0 && nargs < 5 && !argType.isPrimitive()) {
Object[] check = (Object[]) (Object) target.invokeWithArguments(args); Object[] check = (Object[]) target.invokeWithArguments(args);
assertArrayEquals(args, check); assertArrayEquals(args, check);
switch (nargs) { switch (nargs) {
case 0: case 0:
...@@ -1555,7 +1559,7 @@ public class MethodHandlesTest { ...@@ -1555,7 +1559,7 @@ public class MethodHandlesTest {
break; break;
} }
} }
List<Class<?>> newParams = new ArrayList<Class<?>>(target2.type().parameterList()); List<Class<?>> newParams = new ArrayList<>(target2.type().parameterList());
{ // modify newParams in place { // modify newParams in place
List<Class<?>> spreadParams = newParams.subList(pos, nargs); List<Class<?>> spreadParams = newParams.subList(pos, nargs);
spreadParams.clear(); spreadParams.add(arrayType); spreadParams.clear(); spreadParams.add(arrayType);
...@@ -1608,7 +1612,7 @@ public class MethodHandlesTest { ...@@ -1608,7 +1612,7 @@ public class MethodHandlesTest {
public void testCollectArguments() throws Throwable { public void testCollectArguments() throws Throwable {
if (CAN_SKIP_WORKING) return; if (CAN_SKIP_WORKING) return;
startTest("collectArguments"); startTest("collectArguments");
for (Class<?> argType : new Class[]{Object.class, Integer.class, int.class}) { for (Class<?> argType : new Class<?>[]{Object.class, Integer.class, int.class}) {
if (verbosity >= 3) if (verbosity >= 3)
System.out.println("collectArguments "+argType); System.out.println("collectArguments "+argType);
for (int nargs = 0; nargs < 50; nargs++) { for (int nargs = 0; nargs < 50; nargs++) {
...@@ -1670,12 +1674,13 @@ public class MethodHandlesTest { ...@@ -1670,12 +1674,13 @@ public class MethodHandlesTest {
MethodHandle target = varargsArray(nargs + ins); MethodHandle target = varargsArray(nargs + ins);
Object[] args = randomArgs(target.type().parameterArray()); Object[] args = randomArgs(target.type().parameterArray());
List<Object> resList = Arrays.asList(args); List<Object> resList = Arrays.asList(args);
List<Object> argsToPass = new ArrayList<Object>(resList); List<Object> argsToPass = new ArrayList<>(resList);
List<Object> argsToInsert = argsToPass.subList(pos, pos + ins); List<Object> argsToInsert = argsToPass.subList(pos, pos + ins);
if (verbosity >= 3) if (verbosity >= 3)
System.out.println("insert: "+argsToInsert+" into "+target); System.out.println("insert: "+argsToInsert+" into "+target);
@SuppressWarnings("cast") // cast to spread Object... is helpful
MethodHandle target2 = MethodHandles.insertArguments(target, pos, MethodHandle target2 = MethodHandles.insertArguments(target, pos,
(Object[]) argsToInsert.toArray()); (Object[]/*...*/) argsToInsert.toArray());
argsToInsert.clear(); // remove from argsToInsert argsToInsert.clear(); // remove from argsToInsert
Object res2 = target2.invokeWithArguments(argsToPass); Object res2 = target2.invokeWithArguments(argsToPass);
Object res2List = Arrays.asList((Object[])res2); Object res2List = Arrays.asList((Object[])res2);
...@@ -1693,7 +1698,7 @@ public class MethodHandlesTest { ...@@ -1693,7 +1698,7 @@ public class MethodHandlesTest {
Class<?> classOfVCList = varargsList(1).invokeWithArguments(0).getClass(); Class<?> classOfVCList = varargsList(1).invokeWithArguments(0).getClass();
assertTrue(List.class.isAssignableFrom(classOfVCList)); assertTrue(List.class.isAssignableFrom(classOfVCList));
for (int nargs = 0; nargs <= 3; nargs++) { for (int nargs = 0; nargs <= 3; nargs++) {
for (Class<?> rtype : new Class[] { Object.class, for (Class<?> rtype : new Class<?>[] { Object.class,
List.class, List.class,
int.class, int.class,
byte.class, byte.class,
...@@ -1790,7 +1795,7 @@ public class MethodHandlesTest { ...@@ -1790,7 +1795,7 @@ public class MethodHandlesTest {
System.out.println("fold "+target+" with "+combine); System.out.println("fold "+target+" with "+combine);
MethodHandle target2 = MethodHandles.foldArguments(target, combine); MethodHandle target2 = MethodHandles.foldArguments(target, combine);
// Simulate expected effect of combiner on arglist: // Simulate expected effect of combiner on arglist:
List<Object> expected = new ArrayList<Object>(argsToPass); List<Object> expected = new ArrayList<>(argsToPass);
List<Object> argsToFold = expected.subList(pos, pos + fold); List<Object> argsToFold = expected.subList(pos, pos + fold);
if (verbosity >= 3) if (verbosity >= 3)
System.out.println("fold: "+argsToFold+" into "+target2); System.out.println("fold: "+argsToFold+" into "+target2);
...@@ -1822,9 +1827,9 @@ public class MethodHandlesTest { ...@@ -1822,9 +1827,9 @@ public class MethodHandlesTest {
MethodHandle target = varargsArray(nargs); MethodHandle target = varargsArray(nargs);
Object[] args = randomArgs(target.type().parameterArray()); Object[] args = randomArgs(target.type().parameterArray());
MethodHandle target2 = MethodHandles.dropArguments(target, pos, MethodHandle target2 = MethodHandles.dropArguments(target, pos,
Collections.nCopies(drop, Object.class).toArray(new Class[0])); Collections.nCopies(drop, Object.class).toArray(new Class<?>[0]));
List<Object> resList = Arrays.asList(args); List<Object> resList = Arrays.asList(args);
List<Object> argsToDrop = new ArrayList<Object>(resList); List<Object> argsToDrop = new ArrayList<>(resList);
for (int i = drop; i > 0; i--) { for (int i = drop; i > 0; i--) {
argsToDrop.add(pos, "blort#"+i); argsToDrop.add(pos, "blort#"+i);
} }
...@@ -1840,11 +1845,11 @@ public class MethodHandlesTest { ...@@ -1840,11 +1845,11 @@ public class MethodHandlesTest {
if (CAN_SKIP_WORKING) return; if (CAN_SKIP_WORKING) return;
startTest("exactInvoker, genericInvoker, varargsInvoker, dynamicInvoker"); startTest("exactInvoker, genericInvoker, varargsInvoker, dynamicInvoker");
// exactInvoker, genericInvoker, varargsInvoker[0..N], dynamicInvoker // exactInvoker, genericInvoker, varargsInvoker[0..N], dynamicInvoker
Set<MethodType> done = new HashSet<MethodType>(); Set<MethodType> done = new HashSet<>();
for (int i = 0; i <= 6; i++) { for (int i = 0; i <= 6; i++) {
if (CAN_TEST_LIGHTLY && i > 3) break; if (CAN_TEST_LIGHTLY && i > 3) break;
MethodType gtype = MethodType.genericMethodType(i); MethodType gtype = MethodType.genericMethodType(i);
for (Class<?> argType : new Class[]{Object.class, Integer.class, int.class}) { for (Class<?> argType : new Class<?>[]{Object.class, Integer.class, int.class}) {
for (int j = -1; j < i; j++) { for (int j = -1; j < i; j++) {
MethodType type = gtype; MethodType type = gtype;
if (j < 0) if (j < 0)
...@@ -1873,7 +1878,7 @@ public class MethodHandlesTest { ...@@ -1873,7 +1878,7 @@ public class MethodHandlesTest {
assertTrue(target.isVarargsCollector()); assertTrue(target.isVarargsCollector());
target = target.asType(type); target = target.asType(type);
Object[] args = randomArgs(type.parameterArray()); Object[] args = randomArgs(type.parameterArray());
List<Object> targetPlusArgs = new ArrayList<Object>(Arrays.asList(args)); List<Object> targetPlusArgs = new ArrayList<>(Arrays.asList(args));
targetPlusArgs.add(0, target); targetPlusArgs.add(0, target);
int code = (Integer) invokee(args); int code = (Integer) invokee(args);
Object log = logEntry("invokee", args); Object log = logEntry("invokee", args);
...@@ -1960,7 +1965,7 @@ public class MethodHandlesTest { ...@@ -1960,7 +1965,7 @@ public class MethodHandlesTest {
.appendParameterTypes(Object[].class) .appendParameterTypes(Object[].class)
.insertParameterTypes(0, MethodHandle.class)); .insertParameterTypes(0, MethodHandle.class));
assertEquals(expType, inv.type()); assertEquals(expType, inv.type());
List<Object> targetPlusVarArgs = new ArrayList<Object>(targetPlusArgs); List<Object> targetPlusVarArgs = new ArrayList<>(targetPlusArgs);
List<Object> tailList = targetPlusVarArgs.subList(1+k, 1+nargs); List<Object> tailList = targetPlusVarArgs.subList(1+k, 1+nargs);
Object[] tail = tailList.toArray(); Object[] tail = tailList.toArray();
tailList.clear(); tailList.add(tail); tailList.clear(); tailList.add(tail);
...@@ -2191,7 +2196,7 @@ public class MethodHandlesTest { ...@@ -2191,7 +2196,7 @@ public class MethodHandlesTest {
if (throwMode == THROW_NOTHING) { if (throwMode == THROW_NOTHING) {
assertSame(arg0, returned); assertSame(arg0, returned);
} else if (throwMode == THROW_CAUGHT) { } else if (throwMode == THROW_CAUGHT) {
List<Object> catchArgs = new ArrayList<Object>(Arrays.asList(args)); List<Object> catchArgs = new ArrayList<>(Arrays.asList(args));
// catcher receives an initial subsequence of target arguments: // catcher receives an initial subsequence of target arguments:
catchArgs.subList(nargs - catchDrops, nargs).clear(); catchArgs.subList(nargs - catchDrops, nargs).clear();
// catcher also receives the exception, prepended: // catcher also receives the exception, prepended:
...@@ -2317,12 +2322,13 @@ public class MethodHandlesTest { ...@@ -2317,12 +2322,13 @@ public class MethodHandlesTest {
INT_IDENTITY = PRIVATE.findStatic( INT_IDENTITY = PRIVATE.findStatic(
Surprise.class, "intIdentity", Surprise.class, "intIdentity",
MethodType.methodType(int.class, int.class)); MethodType.methodType(int.class, int.class));
} catch (Exception ex) { } catch (NoSuchMethodException | IllegalAccessException ex) {
throw new RuntimeException(ex); throw new RuntimeException(ex);
} }
} }
} }
@SuppressWarnings("ConvertToStringSwitch")
void testCastFailure(String mode, int okCount) throws Throwable { void testCastFailure(String mode, int okCount) throws Throwable {
countTest(false); countTest(false);
if (verbosity > 2) System.out.println("mode="+mode); if (verbosity > 2) System.out.println("mode="+mode);
...@@ -2419,12 +2425,13 @@ public class MethodHandlesTest { ...@@ -2419,12 +2425,13 @@ public class MethodHandlesTest {
public interface Fooable { public interface Fooable {
// overloads: // overloads:
Object foo(Object x, String y); Object foo(Object x, String y);
List foo(String x, int y); List<?> foo(String x, int y);
Object foo(String x); Object foo(String x);
} }
static Object fooForFooable(String x, Object... y) { static Object fooForFooable(String x, Object... y) {
return called("fooForFooable/"+x, y); return called("fooForFooable/"+x, y);
} }
@SuppressWarnings("serial") // not really a public API, just a test case
public static class MyCheckedException extends Exception { public static class MyCheckedException extends Exception {
} }
public interface WillThrow { public interface WillThrow {
...@@ -2453,7 +2460,7 @@ public class MethodHandlesTest { ...@@ -2453,7 +2460,7 @@ public class MethodHandlesTest {
{ {
countTest(); countTest();
if (verbosity >= 2) System.out.println("Appendable"); if (verbosity >= 2) System.out.println("Appendable");
ArrayList<List> appendResults = new ArrayList<List>(); ArrayList<List<?>> appendResults = new ArrayList<>();
MethodHandle append = lookup.bind(appendResults, "add", MethodType.methodType(boolean.class, Object.class)); MethodHandle append = lookup.bind(appendResults, "add", MethodType.methodType(boolean.class, Object.class));
append = append.asType(MethodType.methodType(void.class, List.class)); // specialize the type append = append.asType(MethodType.methodType(void.class, List.class)); // specialize the type
MethodHandle asList = lookup.findStatic(Arrays.class, "asList", MethodType.methodType(List.class, Object[].class)); MethodHandle asList = lookup.findStatic(Arrays.class, "asList", MethodType.methodType(List.class, Object[].class));
...@@ -2475,11 +2482,11 @@ public class MethodHandlesTest { ...@@ -2475,11 +2482,11 @@ public class MethodHandlesTest {
formatter.format(fmt, fmtArgs); formatter.format(fmt, fmtArgs);
String actual = ""; String actual = "";
if (verbosity >= 3) System.out.println("appendResults="+appendResults); if (verbosity >= 3) System.out.println("appendResults="+appendResults);
for (List l : appendResults) { for (List<?> l : appendResults) {
Object x = l.get(0); Object x = l.get(0);
switch (l.size()) { switch (l.size()) {
case 1: actual += x; continue; case 1: actual += x; continue;
case 3: actual += ((String)x).substring((int)l.get(1), (int)l.get(2)); continue; case 3: actual += ((String)x).substring((int)(Object)l.get(1), (int)(Object)l.get(2)); continue;
} }
actual += l; actual += l;
} }
...@@ -2551,7 +2558,7 @@ public class MethodHandlesTest { ...@@ -2551,7 +2558,7 @@ public class MethodHandlesTest {
} }
} }
// Test error checking on bad interfaces: // Test error checking on bad interfaces:
for (Class<?> nonSMI : new Class[] { Object.class, for (Class<?> nonSMI : new Class<?>[] { Object.class,
String.class, String.class,
CharSequence.class, CharSequence.class,
java.io.Serializable.class, java.io.Serializable.class,
...@@ -2579,7 +2586,7 @@ public class MethodHandlesTest { ...@@ -2579,7 +2586,7 @@ public class MethodHandlesTest {
} }
} }
// Test error checking on interfaces with the wrong method type: // Test error checking on interfaces with the wrong method type:
for (Class<?> intfc : new Class[] { Runnable.class /*arity 0*/, for (Class<?> intfc : new Class<?>[] { Runnable.class /*arity 0*/,
Fooable.class /*arity 1 & 2*/ }) { Fooable.class /*arity 1 & 2*/ }) {
int badArity = 1; // known to be incompatible int badArity = 1; // known to be incompatible
if (verbosity > 2) System.out.println(intfc.getName()); if (verbosity > 2) System.out.println(intfc.getName());
...@@ -2657,7 +2664,7 @@ class ValueConversions { ...@@ -2657,7 +2664,7 @@ class ValueConversions {
Object a8, Object a9) Object a8, Object a9)
{ return makeArray(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9); } { return makeArray(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9); }
static MethodHandle[] makeArrays() { static MethodHandle[] makeArrays() {
ArrayList<MethodHandle> arrays = new ArrayList<MethodHandle>(); ArrayList<MethodHandle> arrays = new ArrayList<>();
MethodHandles.Lookup lookup = IMPL_LOOKUP; MethodHandles.Lookup lookup = IMPL_LOOKUP;
for (;;) { for (;;) {
int nargs = arrays.size(); int nargs = arrays.size();
...@@ -2746,7 +2753,7 @@ class ValueConversions { ...@@ -2746,7 +2753,7 @@ class ValueConversions {
Object a8, Object a9) Object a8, Object a9)
{ return makeList(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9); } { return makeList(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9); }
static MethodHandle[] makeLists() { static MethodHandle[] makeLists() {
ArrayList<MethodHandle> lists = new ArrayList<MethodHandle>(); ArrayList<MethodHandle> lists = new ArrayList<>();
MethodHandles.Lookup lookup = IMPL_LOOKUP; MethodHandles.Lookup lookup = IMPL_LOOKUP;
for (;;) { for (;;) {
int nargs = lists.size(); int nargs = lists.size();
...@@ -2769,7 +2776,7 @@ class ValueConversions { ...@@ -2769,7 +2776,7 @@ class ValueConversions {
static { static {
try { try {
AS_LIST = IMPL_LOOKUP.findStatic(Arrays.class, "asList", MethodType.methodType(List.class, Object[].class)); AS_LIST = IMPL_LOOKUP.findStatic(Arrays.class, "asList", MethodType.methodType(List.class, Object[].class));
} catch (Exception ex) { throw new RuntimeException(ex); } } catch (NoSuchMethodException | IllegalAccessException ex) { throw new RuntimeException(ex); }
} }
/** Return a method handle that takes the indicated number of Object /** Return a method handle that takes the indicated number of Object
......
...@@ -29,6 +29,7 @@ ...@@ -29,6 +29,7 @@
package test.java.lang.invoke; package test.java.lang.invoke;
import java.io.IOException;
import java.lang.invoke.MethodType; import java.lang.invoke.MethodType;
import java.lang.reflect.Method; import java.lang.reflect.Method;
...@@ -378,7 +379,7 @@ public class MethodTypeTest { ...@@ -378,7 +379,7 @@ public class MethodTypeTest {
public void testHashCode() { public void testHashCode() {
System.out.println("hashCode"); System.out.println("hashCode");
MethodType instance = mt_viS; MethodType instance = mt_viS;
ArrayList<Class<?>> types = new ArrayList<Class<?>>(); ArrayList<Class<?>> types = new ArrayList<>();
types.add(instance.returnType()); types.add(instance.returnType());
types.addAll(instance.parameterList()); types.addAll(instance.parameterList());
int expResult = types.hashCode(); int expResult = types.hashCode();
...@@ -556,7 +557,7 @@ public class MethodTypeTest { ...@@ -556,7 +557,7 @@ public class MethodTypeTest {
Object decode; Object decode;
try { try {
decode = readSerial(wire); decode = readSerial(wire);
} catch (Exception ex) { } catch (IOException | ClassNotFoundException ex) {
decode = ex; // oops! decode = ex; // oops!
} }
assertEquals(mt, decode); assertEquals(mt, decode);
......
...@@ -45,7 +45,7 @@ import static java.lang.invoke.MethodHandles.*; ...@@ -45,7 +45,7 @@ import static java.lang.invoke.MethodHandles.*;
import static java.lang.invoke.MethodType.*; import static java.lang.invoke.MethodType.*;
public class PermuteArgsTest { public class PermuteArgsTest {
private static final Class CLASS = PermuteArgsTest.class; private static final Class<?> CLASS = PermuteArgsTest.class;
private static final int MAX_ARITY = Integer.getInteger(CLASS.getSimpleName()+".MAX_ARITY", 8); private static final int MAX_ARITY = Integer.getInteger(CLASS.getSimpleName()+".MAX_ARITY", 8);
private static final boolean DRY_RUN = Boolean.getBoolean(CLASS.getSimpleName()+".DRY_RUN"); private static final boolean DRY_RUN = Boolean.getBoolean(CLASS.getSimpleName()+".DRY_RUN");
private static final boolean VERBOSE = Boolean.getBoolean(CLASS.getSimpleName()+".VERBOSE") || DRY_RUN; private static final boolean VERBOSE = Boolean.getBoolean(CLASS.getSimpleName()+".VERBOSE") || DRY_RUN;
...@@ -99,12 +99,12 @@ public class PermuteArgsTest { ...@@ -99,12 +99,12 @@ public class PermuteArgsTest {
return Arrays.asList(w, x, y, z); return Arrays.asList(w, x, y, z);
} }
static Object listI_etc(int... va) { static Object listI_etc(int... va) {
ArrayList<Object> res = new ArrayList<Object>(); ArrayList<Object> res = new ArrayList<>();
for (int x : va) res.add(x); for (int x : va) res.add(x);
return res; return res;
} }
static Object listIJL_etc(int x, long y, Object z, Object... va) { static Object listIJL_etc(int x, long y, Object z, Object... va) {
ArrayList<Object> res = new ArrayList<Object>(); ArrayList<Object> res = new ArrayList<>();
res.addAll(Arrays.asList(x, y, z)); res.addAll(Arrays.asList(x, y, z));
res.addAll(Arrays.asList(va)); res.addAll(Arrays.asList(va));
return res; return res;
...@@ -168,7 +168,7 @@ public class PermuteArgsTest { ...@@ -168,7 +168,7 @@ public class PermuteArgsTest {
mh1 = adjustArity(mh, arity); mh1 = adjustArity(mh, arity);
} catch (IllegalArgumentException ex) { } catch (IllegalArgumentException ex) {
System.out.println("*** mh = "+name+" : "+mh+"; arity = "+arity+" => "+ex); System.out.println("*** mh = "+name+" : "+mh+"; arity = "+arity+" => "+ex);
ex.printStackTrace(); ex.printStackTrace(System.out);
break; // cannot get this arity for this type break; // cannot get this arity for this type
} }
test("("+arity+")"+name, mh1); test("("+arity+")"+name, mh1);
...@@ -213,7 +213,7 @@ public class PermuteArgsTest { ...@@ -213,7 +213,7 @@ public class PermuteArgsTest {
} }
static void testPermutations(MethodHandle mh) throws Throwable { static void testPermutations(MethodHandle mh) throws Throwable {
HashSet<String> done = new HashSet<String>(); HashSet<String> done = new HashSet<>();
MethodType mt = mh.type(); MethodType mt = mh.type();
int[] perm = nullPerm(mt.parameterCount()); int[] perm = nullPerm(mt.parameterCount());
final int MARGIN = (perm.length <= 10 ? 2 : 0); final int MARGIN = (perm.length <= 10 ? 2 : 0);
...@@ -326,8 +326,8 @@ public class PermuteArgsTest { ...@@ -326,8 +326,8 @@ public class PermuteArgsTest {
Class<?> pt = ptypes[i]; Class<?> pt = ptypes[i];
Object arg; Object arg;
if (pt == Void.class) arg = null; if (pt == Void.class) arg = null;
else if (pt == int.class) arg = (int) i + 101; else if (pt == int.class) arg = i + 101;
else if (pt == long.class) arg = (long) i + 10_000_000_001L; else if (pt == long.class) arg = i + 10_000_000_001L;
else arg = "#" + (i + 1); else arg = "#" + (i + 1);
args[i] = arg; args[i] = arg;
} }
......
...@@ -40,7 +40,6 @@ import org.junit.*; ...@@ -40,7 +40,6 @@ import org.junit.*;
import static java.lang.invoke.MethodType.*; import static java.lang.invoke.MethodType.*;
import static java.lang.invoke.MethodHandles.*; import static java.lang.invoke.MethodHandles.*;
import static org.junit.Assert.*; import static org.junit.Assert.*;
import static org.junit.Assume.*;
/** /**
...@@ -48,7 +47,7 @@ import static org.junit.Assume.*; ...@@ -48,7 +47,7 @@ import static org.junit.Assume.*;
* @author jrose * @author jrose
*/ */
public class RicochetTest { public class RicochetTest {
private static final Class CLASS = RicochetTest.class; private static final Class<?> CLASS = RicochetTest.class;
private static final int MAX_ARITY = Integer.getInteger(CLASS.getSimpleName()+".MAX_ARITY", 40); private static final int MAX_ARITY = Integer.getInteger(CLASS.getSimpleName()+".MAX_ARITY", 40);
public static void main(String... av) throws Throwable { public static void main(String... av) throws Throwable {
...@@ -148,7 +147,7 @@ public class RicochetTest { ...@@ -148,7 +147,7 @@ public class RicochetTest {
for (int nargs = 0; nargs <= MAX; nargs++) { for (int nargs = 0; nargs <= MAX; nargs++) {
if (nargs > 30 && nargs < MAX-20) nargs += 10; if (nargs > 30 && nargs < MAX-20) nargs += 10;
int[] args = new int[nargs]; int[] args = new int[nargs];
for (int j = 0; j < args.length; j++) args[j] = (int)(j + 11); for (int j = 0; j < args.length; j++) args[j] = j + 11;
//System.out.println("testIntSpreads "+Arrays.toString(args)); //System.out.println("testIntSpreads "+Arrays.toString(args));
int[] args1 = (int[]) id.invokeExact(args); int[] args1 = (int[]) id.invokeExact(args);
assertArrayEquals(args, args1); assertArrayEquals(args, args1);
...@@ -388,6 +387,7 @@ public class RicochetTest { ...@@ -388,6 +387,7 @@ public class RicochetTest {
java.util.Random random; java.util.Random random;
final MethodHandle[] fns; final MethodHandle[] fns;
int depth; int depth;
@SuppressWarnings("LeakingThisInConstructor")
RFCB(int seed) throws Throwable { RFCB(int seed) throws Throwable {
this.random = new java.util.Random(seed); this.random = new java.util.Random(seed);
this.fns = new MethodHandle[Math.max(29, (1 << MAX_DEPTH-2)/3)]; this.fns = new MethodHandle[Math.max(29, (1 << MAX_DEPTH-2)/3)];
...@@ -408,7 +408,7 @@ public class RicochetTest { ...@@ -408,7 +408,7 @@ public class RicochetTest {
case 1: case 1:
Throwable ex = new RuntimeException(); Throwable ex = new RuntimeException();
ex.fillInStackTrace(); ex.fillInStackTrace();
if (VERBOSITY >= 2) ex.printStackTrace(); if (VERBOSITY >= 2) ex.printStackTrace(System.out);
x = "ST; " + x; x = "ST; " + x;
break; break;
case 2: case 2:
...@@ -467,7 +467,7 @@ public class RicochetTest { ...@@ -467,7 +467,7 @@ public class RicochetTest {
return mh.invokeWithArguments(args); return mh.invokeWithArguments(args);
} catch (Throwable ex) { } catch (Throwable ex) {
System.out.println("threw: "+mh+Arrays.asList(args)); System.out.println("threw: "+mh+Arrays.asList(args));
ex.printStackTrace(); ex.printStackTrace(System.out);
return ex; return ex;
} }
} }
...@@ -515,8 +515,8 @@ public class RicochetTest { ...@@ -515,8 +515,8 @@ public class RicochetTest {
private static long opJ(long x) { return (long) opI((int)x); } private static long opJ(long x) { return (long) opI((int)x); }
private static Object opL2(Object x, Object y) { return (Object) opI2((int)x, (int)y); } private static Object opL2(Object x, Object y) { return (Object) opI2((int)x, (int)y); }
private static Object opL(Object x) { return (Object) opI((int)x); } private static Object opL(Object x) { return (Object) opI((int)x); }
private static int opL2_I(Object x, Object y) { return (int) opI2((int)x, (int)y); } private static int opL2_I(Object x, Object y) { return opI2((int)x, (int)y); }
private static int opL_I(Object x) { return (int) opI((int)x); } private static int opL_I(Object x) { return opI((int)x); }
private static long opL_J(Object x) { return (long) opI((int)x); } private static long opL_J(Object x) { return (long) opI((int)x); }
private static final MethodHandle opI, opI2, opI3, opI4, opI_L, opJ, opJ2, opJ3, opL2, opL, opL2_I, opL_I, opL_J; private static final MethodHandle opI, opI2, opI3, opI4, opI_L, opJ, opJ2, opJ3, opL2, opL, opL2_I, opL_I, opL_J;
static { static {
...@@ -570,8 +570,8 @@ public class RicochetTest { ...@@ -570,8 +570,8 @@ public class RicochetTest {
INT_LISTERS[i] = lister; INT_LISTERS[i] = lister;
LONG_LISTERS[i] = llister; LONG_LISTERS[i] = llister;
if (i == 0) break; if (i == 0) break;
lister = insertArguments(lister, i-1, (int)0); lister = insertArguments(lister, i-1, 0);
llister = insertArguments(llister, i-1, (long)0); llister = insertArguments(llister, i-1, 0L);
} }
} }
......
...@@ -40,7 +40,7 @@ import static java.lang.invoke.MethodHandles.*; ...@@ -40,7 +40,7 @@ import static java.lang.invoke.MethodHandles.*;
import static java.lang.invoke.MethodType.*; import static java.lang.invoke.MethodType.*;
public class ThrowExceptionsTest { public class ThrowExceptionsTest {
private static final Class CLASS = ThrowExceptionsTest.class; private static final Class<?> CLASS = ThrowExceptionsTest.class;
private static final Lookup LOOKUP = lookup(); private static final Lookup LOOKUP = lookup();
public static void main(String argv[]) throws Throwable { public static void main(String argv[]) throws Throwable {
...@@ -132,9 +132,9 @@ public class ThrowExceptionsTest { ...@@ -132,9 +132,9 @@ public class ThrowExceptionsTest {
int tc = testCases; int tc = testCases;
try { try {
m.invoke(this); m.invoke(this);
} catch (Throwable ex) { } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException ex) {
System.out.println("*** "+ex); System.out.println("*** "+ex);
ex.printStackTrace(); ex.printStackTrace(System.out);
} }
if (testCases == tc) testCases++; if (testCases == tc) testCases++;
} }
......
/*
* Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* @test
* @bug 4885629
* @summary With JSplitPane in VERTICAL_SPLIT, SplitPaneBorder draws bottom edge of divider
* @author Andrey Pikalev
*/
import sun.awt.SunToolkit;
import javax.swing.*;
import javax.swing.border.Border;
import javax.swing.border.EmptyBorder;
import javax.swing.plaf.basic.BasicBorders;
import javax.swing.plaf.basic.BasicLookAndFeel;
import javax.swing.plaf.basic.BasicSplitPaneUI;
import java.awt.*;
public class bug4885629 {
private static final Color darkShadow = new Color(100,120,200);
private static final Color darkHighlight = new Color(200,120,50);
private static final Color lightHighlight = darkHighlight.brighter();
private static final Color BGCOLOR = Color.blue;
private static JSplitPane sp;
public static void main(String[] args) throws Exception {
UIManager.setLookAndFeel(new BasicLookAndFeel() {
public boolean isSupportedLookAndFeel(){ return true; }
public boolean isNativeLookAndFeel(){ return false; }
public String getDescription() { return "Foo"; }
public String getID() { return "FooID"; }
public String getName() { return "FooName"; }
});
SwingUtilities.invokeAndWait(new Runnable() {
public void run() {
JFrame frame = new JFrame();
JComponent a = new JPanel();
a.setBackground(Color.white);
a.setMinimumSize(new Dimension(10, 10));
JComponent b = new JPanel();
b.setBackground(Color.white);
b.setMinimumSize(new Dimension(10, 10));
sp = new JSplitPane(JSplitPane.VERTICAL_SPLIT, a, b);
sp.setPreferredSize(new Dimension(20, 20));
sp.setBackground(BGCOLOR);
Border bo = new BasicBorders.SplitPaneBorder(lightHighlight,
Color.red);
Border ibo = new EmptyBorder(0, 0, 0, 0);
sp.setBorder(bo);
sp.setMinimumSize(new Dimension(200, 200));
((BasicSplitPaneUI) sp.getUI()).getDivider().setBorder(ibo);
frame.getContentPane().setLayout(new FlowLayout());
frame.getContentPane().setBackground(darkShadow);
frame.getContentPane().add(sp);
frame.setSize(200, 200);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
}
});
((SunToolkit) SunToolkit.getDefaultToolkit()).realSync();
final Robot robot = new Robot();
robot.delay(1000);
SwingUtilities.invokeAndWait(new Runnable() {
public void run() {
Rectangle rect = ((BasicSplitPaneUI) sp.getUI()).getDivider().getBounds();
Point p = rect.getLocation();
SwingUtilities.convertPointToScreen(p, sp);
for (int i = 0; i < rect.width; i++) {
if (!BGCOLOR.equals(robot.getPixelColor(p.x + i, p.y + rect.height - 1))) {
throw new Error("The divider's area has incorrect color.");
}
}
}
});
}
}
/*
* Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* @test
* @bug 4697612 6244705
* @author Peter Zhelezniakov
* @library ../../regtesthelpers
* @build Util
* @run main bug4697612
*/
import java.io.*;
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.text.BadLocationException;
import sun.awt.SunToolkit;
public class bug4697612 {
static final int FRAME_WIDTH = 300;
static final int FRAME_HEIGHT = 300;
static final int FONT_HEIGHT = 16;
private static volatile int frameHeight;
private static volatile int fontHeight;
private static JFrame frame;
private static JTextArea text;
private static JScrollPane scroller;
public static void main(String[] args) throws Throwable {
SunToolkit toolkit = (SunToolkit) Toolkit.getDefaultToolkit();
Robot robot = new Robot();
robot.setAutoDelay(100);
SwingUtilities.invokeAndWait(new Runnable() {
@Override
public void run() {
createAndShowGUI();
}
});
toolkit.realSync();
SwingUtilities.invokeAndWait(new Runnable() {
@Override
public void run() {
text.requestFocus();
}
});
toolkit.realSync();
// 4697612: pressing PgDn + PgUp should not alter caret position
Util.hitKeys(robot, KeyEvent.VK_HOME);
Util.hitKeys(robot, KeyEvent.VK_PAGE_DOWN);
int pos0 = getTextCaretPosition();
int caretHeight = getTextCaretHeight();
fontHeight = FONT_HEIGHT;
// iterate two times, for different (even and odd) font height
for (int i = 0; i < 2; i++) {
SwingUtilities.invokeAndWait(new Runnable() {
public void run() {
text.setFont(text.getFont().deriveFont(fontHeight));
}
});
frameHeight = FRAME_HEIGHT;
for (int j = 0; j < caretHeight; j++) {
SwingUtilities.invokeAndWait(new Runnable() {
public void run() {
frame.setSize(FRAME_WIDTH, frameHeight);
}
});
toolkit.realSync();
Util.hitKeys(robot, KeyEvent.VK_PAGE_DOWN);
Util.hitKeys(robot, KeyEvent.VK_PAGE_UP);
toolkit.realSync();
int pos = getTextCaretPosition();
if (pos0 != pos) {
throw new RuntimeException("Failed 4697612: PgDn & PgUp keys scroll by different amounts");
}
frameHeight++;
}
fontHeight++;
}
// 6244705: pressing PgDn at the very bottom should not scroll
LookAndFeel laf = UIManager.getLookAndFeel();
if (laf.getID().equals("Aqua")) {
Util.hitKeys(robot, KeyEvent.VK_END);
} else {
Util.hitKeys(robot, KeyEvent.VK_CONTROL, KeyEvent.VK_END);
}
toolkit.realSync();
pos0 = getScrollerViewPosition();
Util.hitKeys(robot, KeyEvent.VK_PAGE_DOWN);
toolkit.realSync();
int pos = getScrollerViewPosition();
if (pos0 != pos) {
throw new RuntimeException("Failed 6244705: PgDn at the bottom causes scrolling");
}
}
private static int getTextCaretPosition() throws Exception {
final int[] result = new int[1];
SwingUtilities.invokeAndWait(new Runnable() {
@Override
public void run() {
result[0] = text.getCaretPosition();
}
});
return result[0];
}
private static int getTextCaretHeight() throws Exception {
final int[] result = new int[1];
SwingUtilities.invokeAndWait(new Runnable() {
@Override
public void run() {
try {
int pos0 = text.getCaretPosition();
Rectangle dotBounds = text.modelToView(pos0);
result[0] = dotBounds.height;
} catch (BadLocationException ex) {
throw new RuntimeException(ex);
}
}
});
return result[0];
}
private static int getScrollerViewPosition() throws Exception {
final int[] result = new int[1];
SwingUtilities.invokeAndWait(new Runnable() {
@Override
public void run() {
result[0] = scroller.getViewport().getViewPosition().y;
}
});
return result[0];
}
private static void createAndShowGUI() {
frame = new JFrame();
frame.setSize(FRAME_WIDTH, FRAME_HEIGHT);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
text = new JTextArea();
try {
InputStream is =
bug4697612.class.getResourceAsStream("bug4697612.txt");
text.read(new InputStreamReader(is), null);
} catch (IOException e) {
throw new Error(e);
}
scroller = new JScrollPane(text);
frame.getContentPane().add(scroller);
frame.pack();
frame.setVisible(true);
}
}
README
Java(TM) 2 SDK, Standard Edition
Version 1.4.2 Beta
For a more extensive HTML version of this file, see README.html.
Contents
* Introduction
* Release Notes
* Bug Reports and Feedback
* Java 2 SDK Documentation
* Redistribution
* Web Pages
Introduction
Thank you for downloading this release of the Java(TM) 2 SDK,
Standard Edition. The Java 2 SDK is a development environment for
building applications, applets, and components that can be
deployed on the Java platform.
The Java 2 SDK software includes tools useful for developing and
testing programs written in the Java programming language and
running on the Java platform. These tools are designed to be used
from the command line. Except for appletviewer, these tools do not
provide a graphical user interface.
Release Notes
See the Release Notes on the Java Software web site for additional
information pertaining to this release.
http://java.sun.com/j2se/1.4.2/relnotes.html
The on-line release notes will be updated as needed, so you should
check it occasionally for the latest information.
Bug Reports and Feedback
The Bug Parade Web Page on the Java Developer Connection(SM) web
site lets you search for and examine existing bug reports, submit
your own bug reports, and tell us which bug fixes matter most to you.
http://java.sun.com/jdc/bugParade/
To directly submit a bug or request a feature, fill out this form:
http://java.sun.com/cgi-bin/bugreport.cgi
You can also send comments directly to Java Software engineering
team email addresses.
http://java.sun.com/mail/
Java 2 SDK Documentation
The on-line Java 2 SDK Documentation contains API specifications,
feature descriptions, developer guides, tool reference pages, demos,
and links to related information. It is located at
http://java.sun.com/j2se/1.4.2/docs/
The Java 2 SDK documentation is also available in a download bundle
which you can install locally on your machine. See the
Java 2 SDK download page:
http://java.sun.com/j2se/1.4.2/download.html
Redistribution
The term "vendors" used here refers to licensees, developers,
and independent software vendors (ISVs) who license and
distribute the Java 2 Runtime Environment with their programs.
Vendors must follow the terms of the Java 2 SDK, Standard
Edition, Binary Code License agreement.
Required vs. Optional Files
The files that make up the Java 2 SDK, Standard Edition, are
divided into two categories: required and optional. Optional
files may be excluded from redistributions of the Java 2 SDK
at the vendor's discretion. The following section contains a
list of the files and directories that may optionally be
omitted from redistributions of the Java 2 SDK. All files not
in these lists of optional files must be included in
redistributions of the Java 2 SDK.
Optional Files and Directories
The following files may be optionally excluded from
redistributions:
jre/lib/charsets.jar
Character conversion classes
jre/lib/ext/
sunjce_provider.jar - the SunJCE provider for Java
Cryptography APIs
localedata.jar - contains many of the resources
needed for non US English locales
ldapsec.jar - contains security features supported
by the LDAP service provider
dnsns.jar - for the InetAddress wrapper of JNDI DNS
provider
bin/rmid and jre/bin/rmid
Java RMI Activation System Daemon
bin/rmiregistry and jre/bin/rmiregistry
Java Remote Object Registry
bin/tnameserv and jre/bin/tnameserv
Java IDL Name Server
bin/keytool and jre/bin/keytool
Key and Certificate Management Tool
bin/kinit and jre/bin/kinit
Used to obtain and cache Kerberos ticket-granting tickets
bin/klist and jre/bin/klist
Kerberos display entries in credentials cache and keytab
bin/ktab and jre/bin/ktab
Kerberos key table manager
bin/policytool and jre/bin/policytool
Policy File Creation and Management Tool
bin/orbd and jre/bin/orbd
Object Request Broker Daemon
bin/servertool and jre/bin/servertool
Java IDL Server Tool
src.zip
Archive of source files
In addition, the Java Web Start product may be excluded from
redistributions. The Java Web Start product is contained in a
file named javaws-1_2-solaris-sparc-i.zip,
javaws-1_2-solaris-i586-i.zip,
javaws-1_2-linux-i586-i.zip, or
javaws-1_2-windows-i586-i.exe, depending on the platform.
Unlimited Strength Java Cryptography Extension
Due to import control restrictions for some countries, the
Java Cryptography Extension (JCE) policy files shipped with
the Java 2 SDK, Standard Edition and the Java 2 Runtime
Environment allow strong but limited cryptography to be
used. These files are located at
<java-home>/lib/security/local_policy.jar
<java-home>/lib/security/US_export_policy.jar
where <java-home> is the jre directory of the Java 2
SDK or the top-level directory of the Java 2 Runtime
Environment.
An unlimited strength version of these files indicating
no restrictions on cryptographic strengths is available
on the Java 2 SDK web site for those living in eligible
countries. Those living in eligible countries may download
the unlimited strength version and replace the strong
cryptography jar files with the unlimited strength files.
Endorsed Standards Override Mechanism
An endorsed standard is a Java API defined through a standards
process other than the Java Community Process(SM) (JCP(SM)).
Because endorsed standards are defined outside the JCP, it is
anticipated that such standards will be revised between
releases of the Java 2 Platform. In order to take advantage of
new revisions to endorsed standards, developers and software
vendors may use the Endorsed Standards Override Mechanism to
provide newer versions of an endorsed standard than those
included in the Java 2 Platform as released by Sun Microsystems.
For more information on the Endorsed Standards Override
Mechanism, including the list of platform packages that it may
be used to override, see
http://java.sun.com/j2se/1.4.2/docs/guide/standards/
Classes in the packages listed on that web page may be replaced
only by classes implementing a more recent version of the API
as defined by the appropriate standards body.
In addition to the packages listed in the document at the above
URL, which are part of the Java 2 Platform, Standard Edition
(J2SE(TM)) specification, redistributors of Sun's J2SE
Reference Implementation are allowed to override classes whose
sole purpose is to implement the functionality provided by
public APIs defined in these Endorsed Standards packages.
Redistributors may also override classes in the org.w3c.dom.*
packages, or other classes whose sole purpose is to implement
these APIs.
Sun Java Web Pages
For additional information, refer to these Sun Microsystems pages
on the World Wide Web:
http://java.sun.com/
The Java Software web site, with the latest information on
Java technology, product information, news, and features.
http://java.sun.com/docs
Java Platform Documentation provides access to white papers,
the Java Tutorial and other documents.
http://java.sun.com/jdc
The Java Developer Connection(SM) web site. (Free registration
required.) Additional technical information, news, and
features; user forums; support information, and much more.
http://java.sun.com/products/
Java Technology Products & API
------------------------------------------------------------------------
The Java 2 SDK, Standard Edition, is a product of Sun Microsystems(TM),
Inc. This product includes code licensed from RSA Security.
Copyright 2003 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
California 95054, U.S.A. All rights reserved.
/*
* Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* @test
* @bug 6505523
* @summary NullPointerException in BasicTreeUI when a node is removed by expansion listener
* @author Alexandr Scherbatiy
* @run main bug6505523
*/
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.Robot;
import java.awt.Toolkit;
import java.awt.event.InputEvent;
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTree;
import javax.swing.SwingUtilities;
import javax.swing.event.TreeExpansionEvent;
import javax.swing.event.TreeExpansionListener;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.DefaultTreeModel;
import javax.swing.tree.TreeNode;
import sun.awt.SunToolkit;
public class bug6505523 {
private static JTree tree;
public static void main(String[] args) throws Exception {
SunToolkit toolkit = (SunToolkit) Toolkit.getDefaultToolkit();
Robot robot = new Robot();
robot.setAutoDelay(50);
SwingUtilities.invokeAndWait(new Runnable() {
@Override
public void run() {
createAndShowGUI();
}
});
toolkit.realSync();
Point point = getRowPointToClick(2);
robot.mouseMove(point.x, point.y);
robot.mousePress(InputEvent.BUTTON1_MASK);
robot.mouseRelease(InputEvent.BUTTON1_MASK);
toolkit.realSync();
}
private static Point getRowPointToClick(final int row) throws Exception {
final Point[] result = new Point[1];
SwingUtilities.invokeAndWait(new Runnable() {
@Override
public void run() {
Rectangle rect = tree.getRowBounds(row);
Point point = new Point(rect.x - 5, rect.y + rect.height / 2);
SwingUtilities.convertPointToScreen(point, tree);
result[0] = point;
}
});
return result[0];
}
private static void createAndShowGUI() {
final DefaultMutableTreeNode root = new DefaultMutableTreeNode("Problem with NPE under JDK 1.6");
final DefaultMutableTreeNode problematic = new DefaultMutableTreeNode("Expand me and behold a NPE in stderr");
problematic.add(new DefaultMutableTreeNode("some content"));
root.add(new DefaultMutableTreeNode("irrelevant..."));
root.add(problematic);
final DefaultTreeModel model = new DefaultTreeModel(root);
tree = new JTree(model);
tree.setRootVisible(true);
tree.setShowsRootHandles(true);
tree.expandRow(0);
tree.collapseRow(2);
// this is critical - without dragEnabled everything works
tree.setDragEnabled(true);
tree.addTreeExpansionListener(new TreeExpansionListener() {
@Override
public void treeExpanded(TreeExpansionEvent event) {
TreeNode parent = problematic.getParent();
if (parent instanceof DefaultMutableTreeNode) {
model.removeNodeFromParent(problematic);
}
}
@Override
public void treeCollapsed(TreeExpansionEvent event) {
}
});
JFrame frame = new JFrame("JTree Problem");
frame.add(new JScrollPane(tree));
frame.setSize(500, 300);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
}
\ No newline at end of file
...@@ -27,11 +27,9 @@ import sun.invoke.util.ValueConversions; ...@@ -27,11 +27,9 @@ import sun.invoke.util.ValueConversions;
import sun.invoke.util.Wrapper; import sun.invoke.util.Wrapper;
import java.lang.invoke.MethodType; import java.lang.invoke.MethodType;
import java.lang.invoke.MethodHandle; import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.io.Serializable; import java.io.Serializable;
import java.util.Arrays; import java.util.Arrays;
import java.util.Collections; import java.util.Collections;
import org.junit.Ignore;
import org.junit.Test; import org.junit.Test;
import static org.junit.Assert.*; import static org.junit.Assert.*;
...@@ -52,7 +50,7 @@ import static org.junit.Assert.*; ...@@ -52,7 +50,7 @@ import static org.junit.Assert.*;
* @author jrose * @author jrose
*/ */
public class ValueConversionsTest { public class ValueConversionsTest {
private static final Class CLASS = ValueConversionsTest.class; private static final Class<?> CLASS = ValueConversionsTest.class;
private static final int MAX_ARITY = Integer.getInteger(CLASS.getSimpleName()+".MAX_ARITY", 40); private static final int MAX_ARITY = Integer.getInteger(CLASS.getSimpleName()+".MAX_ARITY", 40);
private static final int START_ARITY = Integer.getInteger(CLASS.getSimpleName()+".START_ARITY", 0); private static final int START_ARITY = Integer.getInteger(CLASS.getSimpleName()+".START_ARITY", 0);
private static final boolean EXHAUSTIVE = Boolean.getBoolean(CLASS.getSimpleName()+".EXHAUSTIVE"); private static final boolean EXHAUSTIVE = Boolean.getBoolean(CLASS.getSimpleName()+".EXHAUSTIVE");
...@@ -165,7 +163,7 @@ public class ValueConversionsTest { ...@@ -165,7 +163,7 @@ public class ValueConversionsTest {
Object expResult = box; Object expResult = box;
Object result = null; Object result = null;
switch (w) { switch (w) {
case INT: result = boxer.invokeExact((int)n); break; case INT: result = boxer.invokeExact(/*int*/n); break;
case LONG: result = boxer.invokeExact((long)n); break; case LONG: result = boxer.invokeExact((long)n); break;
case FLOAT: result = boxer.invokeExact((float)n); break; case FLOAT: result = boxer.invokeExact((float)n); break;
case DOUBLE: result = boxer.invokeExact((double)n); break; case DOUBLE: result = boxer.invokeExact((double)n); break;
...@@ -361,6 +359,7 @@ public class ValueConversionsTest { ...@@ -361,6 +359,7 @@ public class ValueConversionsTest {
assert(stype == MethodType.methodType(arrayType, arrayType)); assert(stype == MethodType.methodType(arrayType, arrayType));
if (nargs <= 5) { if (nargs <= 5) {
// invoke target as a spreader also: // invoke target as a spreader also:
@SuppressWarnings("cast")
Object res2 = spreader.invokeWithArguments((Object)res); Object res2 = spreader.invokeWithArguments((Object)res);
String res2String = toArrayString(res2); String res2String = toArrayString(res2);
assertEquals(Arrays.toString(args), res2String); assertEquals(Arrays.toString(args), res2String);
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册