changeset 402:421b98214f0d

rebase after pushing 4 changesets to hotspot-comp
author jrose
date Thu, 12 Jul 2012 02:21:22 -0700
parents 0a120a3124fe
children 4d38d18ba364
files cval-7153157.patch meth-7087658.patch meth-7127687.patch meth-7129034.patch series
diffstat 5 files changed, 10 insertions(+), 815 deletions(-) [+]
line wrap: on
line diff
--- a/cval-7153157.patch	Thu Jul 12 00:47:59 2012 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,28 +0,0 @@
-7153157: ClassValue.get does not return if computeValue calls remove
-Summary: Track intermediate states more precisely, according to spec.
-Reviewed-by: twisti, forax
-
-diff --git a/src/share/classes/java/lang/ClassValue.java b/src/share/classes/java/lang/ClassValue.java
---- a/src/share/classes/java/lang/ClassValue.java
-+++ b/src/share/classes/java/lang/ClassValue.java
-@@ -489,9 +489,18 @@
-         /** Remove an entry. */
-         synchronized
-         void removeEntry(ClassValue<?> classValue) {
--            // make all cache elements for this guy go stale:
--            if (remove(classValue.identity) != null) {
-+            Entry<?> e = remove(classValue.identity);
-+            if (e == null) {
-+                // Uninitialized, and no pending calls to computeValue.  No change.
-+            } else if (e.isPromise()) {
-+                // State is uninitialized, with a pending call to finishEntry.
-+                // Since remove is a no-op in such a state, keep the promise
-+                // by putting it back into the map.
-+                put(classValue.identity, e);
-+            } else {
-+                // In an initialized state.  Bump forward, and de-initialize.
-                 classValue.bumpVersion();
-+                // Make all cache elements for this guy go stale.
-                 removeStaleEntries(classValue);
-             }
-         }
--- a/meth-7087658.patch	Thu Jul 12 00:47:59 2012 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,21 +0,0 @@
-7087658: MethodHandles.Lookup.findVirtual is confused by interface methods that are multiply inherited
-Reviewed-by: twisti
-
-diff --git a/src/share/classes/java/lang/invoke/MemberName.java b/src/share/classes/java/lang/invoke/MemberName.java
---- a/src/share/classes/java/lang/invoke/MemberName.java
-+++ b/src/share/classes/java/lang/invoke/MemberName.java
-@@ -622,8 +622,12 @@
-             MemberName[] buf = { m };
-             int n = MethodHandleNatives.getMembers(m.getDeclaringClass(),
-                     m.getName(), matchSig, matchFlags, lookupClass, 0, buf);
--            if (n != 1)  return false;
--            return m.isResolved();
-+            if (n == 0 || !m.isResolved())
-+                return false;  // no result
-+            else if (n == 1 || m.clazz.isInterface())
-+                return true;   // unique result, or multiple inheritance is OK
-+            else
-+                return false;  // ambiguous result (can this happen?)
-         }
-         /** Produce a resolved version of the given member.
-          *  Super types are searched (for inherited members) if {@code searchSupers} is true.
--- a/meth-7127687.patch	Thu Jul 12 00:47:59 2012 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,339 +0,0 @@
-7127687: MethodType leaks memory due to interning
-Summary: Replace internTable with a weak-reference version.
-Reviewed-by: sundar, forax, brutisso
-Contributed-by: james.laskey@oracle.com
-
-diff --git a/src/share/classes/java/lang/invoke/MethodType.java b/src/share/classes/java/lang/invoke/MethodType.java
---- a/src/share/classes/java/lang/invoke/MethodType.java
-+++ b/src/share/classes/java/lang/invoke/MethodType.java
-@@ -1,5 +1,5 @@
- /*
-- * Copyright (c) 2008, 2011, Oracle and/or its affiliates. All rights reserved.
-+ * Copyright (c) 2008, 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
-@@ -26,9 +26,10 @@
- package java.lang.invoke;
- 
- import sun.invoke.util.Wrapper;
-+import java.lang.ref.WeakReference;
-+import java.lang.ref.ReferenceQueue;
- import java.util.Arrays;
- import java.util.Collections;
--import java.util.HashMap;
- import java.util.List;
- import sun.invoke.util.BytecodeDescriptor;
- import static java.lang.invoke.MethodHandleStatics.*;
-@@ -135,8 +136,7 @@
-         return new IndexOutOfBoundsException(num.toString());
-     }
- 
--    static final HashMap<MethodType,MethodType> internTable
--            = new HashMap<MethodType, MethodType>();
-+    static final WeakInternSet internTable = new WeakInternSet();
- 
-     static final Class<?>[] NO_PTYPES = {};
- 
-@@ -239,11 +239,9 @@
-         }
-         MethodType mt1 = new MethodType(rtype, ptypes);
-         MethodType mt0;
--        synchronized (internTable) {
--            mt0 = internTable.get(mt1);
--            if (mt0 != null)
--                return mt0;
--        }
-+        mt0 = internTable.get(mt1);
-+        if (mt0 != null)
-+            return mt0;
-         if (!trusted)
-             // defensively copy the array passed in by the user
-             mt1 = new MethodType(rtype, ptypes.clone());
-@@ -254,15 +252,8 @@
-             // This is a principal (erased) type; show it to the JVM.
-             MethodHandleNatives.init(mt1);
-         }
--        synchronized (internTable) {
--            mt0 = internTable.get(mt1);
--            if (mt0 != null)
--                return mt0;
--            internTable.put(mt1, mt1);
--        }
--        return mt1;
-+        return internTable.add(mt1);
-     }
--
-     private static final MethodType[] objectOnlyTypes = new MethodType[20];
- 
-     /**
-@@ -919,4 +910,269 @@
-         // Verify all operands, and make sure ptypes is unshared:
-         return methodType(rtype, ptypes);
-     }
-+
-+    /**
-+     * Weak intern set based on implementation of the <tt>HashSet</tt> and
-+     * <tt>WeakHashMap</tt>, with <em>weak values</em>.  Note: <tt>null</tt>
-+     * values will yield <tt>NullPointerException</tt>
-+     * Refer to implementation of WeakInternSet for details.
-+     *
-+     * @see         java.util.HashMap
-+     * @see         java.util.HashSet
-+     * @see         java.util.WeakHashMap
-+     * @see         java.lang.ref.WeakReference
-+     */
-+    private static class WeakInternSet {
-+        // The default initial capacity -- MUST be a power of two.
-+        private static final int DEFAULT_INITIAL_CAPACITY = 16;
-+
-+        // The maximum capacity, used if a higher value is implicitly specified
-+        // by either of the constructors with arguments.
-+        // MUST be a power of two <= 1<<30.
-+        private static final int MAXIMUM_CAPACITY = 1 << 30;
-+
-+        // The load factor used when none specified in constructor.
-+        private static final float DEFAULT_LOAD_FACTOR = 0.75f;
-+
-+        // The table, resized as necessary. Length MUST Always be a power of two.
-+        private Entry[] table;
-+
-+        // The number of entries contained in this set.
-+        private int size;
-+
-+        // The next size value at which to resize (capacity * load factor).
-+        private int threshold;
-+
-+        // The load factor for the hash table.
-+        private final float loadFactor;
-+
-+        // Reference queue for cleared WeakEntries
-+        private final ReferenceQueue<Object> queue = new ReferenceQueue<>();
-+
-+        private Entry[] newTable(int n) {
-+            return new Entry[n];
-+        }
-+
-+        /**
-+         * Constructs a new, empty <tt>WeakInternSet</tt> with the default initial
-+         * capacity (16) and load factor (0.75).
-+         */
-+        WeakInternSet() {
-+            this.loadFactor = DEFAULT_LOAD_FACTOR;
-+            threshold = DEFAULT_INITIAL_CAPACITY;
-+            table = newTable(DEFAULT_INITIAL_CAPACITY);
-+        }
-+
-+        /**
-+         * Applies a supplemental hash function to a given hashCode, which
-+         * defends against poor quality hash functions.  This is critical
-+         * because hashing uses power-of-two length hash tables, that
-+         * otherwise encounter collisions for hashCodes that do not differ
-+         * in lower bits.
-+         * @param h preliminary hash code value
-+         * @return supplemental hash code value
-+         */
-+        private static int hash(int h) {
-+            // This function ensures that hashCodes that differ only by
-+            // constant multiples at each bit position have a bounded
-+            // number of collisions (approximately 8 at default load factor).
-+            h ^= (h >>> 20) ^ (h >>> 12);
-+            return h ^ (h >>> 7) ^ (h >>> 4);
-+        }
-+
-+        /**
-+         * Checks for equality of non-null reference x and possibly-null y.  By
-+         * default uses Object.equals.
-+         * @param x first object to compare
-+         * @param y second object to compare
-+         * @return <tt>true</tt> if objects are equal
-+         */
-+        private static boolean eq(Object x, Object y) {
-+            return x == y || x.equals(y);
-+        }
-+
-+        /**
-+         * Returns index for hash code h.
-+         * @param h      raw hash code
-+         * @param length length of table (power of 2)
-+         * @return index in table
-+         */
-+        private static int indexFor(int h, int length) {
-+            return h & (length-1);
-+        }
-+
-+        /**
-+         * Expunges stale entries from the table.
-+         */
-+        private void expungeStaleEntries() {
-+            for (Object x; (x = queue.poll()) != null; ) {
-+                synchronized (queue) {
-+                    Entry entry = (Entry) x;
-+                    int i = indexFor(entry.hash, table.length);
-+                    Entry prev = table[i];
-+                    Entry p = prev;
-+                    while (p != null) {
-+                        Entry next = p.next;
-+                        if (p == entry) {
-+                            if (prev == entry)
-+                                table[i] = next;
-+                            else
-+                                prev.next = next;
-+                            entry.next = null;
-+                            size--;
-+                            break;
-+                        }
-+                        prev = p;
-+                        p = next;
-+                    }
-+                }
-+            }
-+        }
-+
-+        /**
-+         * Returns the table after first expunging stale entries.
-+         * @return an expunged hash table
-+         */
-+        private Entry[] getTable() {
-+            expungeStaleEntries();
-+            return table;
-+        }
-+
-+        /**
-+         * Returns the entry to which the specified value is mapped,
-+         * or {@code null} if this set contains no entry for the value.
-+         *
-+         * <p>More formally, if this set contains an entry for value
-+         * {@code entry} to a value {@code value} such that
-+         * {@code entry.equals(value)}, then this method returns {@code entry};
-+         * otherwise it returns {@code null}.
-+         *
-+         * @param value value to search for in set
-+         * @return interned value if in set, otherwise <tt>null</tt>
-+         */
-+        synchronized MethodType get(MethodType value) {
-+            int h = hash(value.hashCode());
-+            Entry[] tab = getTable();
-+            int index = indexFor(h, tab.length);
-+            Entry e = tab[index];
-+            MethodType g;
-+            while (e != null) {
-+                if (e.hash == h && eq(value, g = e.get()))
-+                    return g;
-+                e = e.next;
-+            }
-+            return null;
-+        }
-+
-+        /**
-+         * Attempts to add the specified value to the set and returns same value.
-+         * If the set previously contained an entry for this value, the old
-+         * value is left untouched and returned as the result.
-+         *
-+         * @param value value to be added
-+         * @return the previous entry associated with <tt>value</tt>, or
-+         *         <tt>value</tt> if there was no previous entry found
-+         */
-+        synchronized MethodType add(MethodType value) {
-+            int h = hash(value.hashCode());
-+            Entry[] tab = getTable();
-+            int i = indexFor(h, tab.length);
-+            MethodType g;
-+            for (Entry e = tab[i]; e != null; e = e.next) {
-+                if (h == e.hash && eq(value, g = e.get())) {
-+                    return g;
-+                }
-+            }
-+            Entry e = tab[i];
-+            tab[i] = new Entry(value, queue, h, e);
-+            if (++size >= threshold)
-+                resize(tab.length * 2);
-+            return value;
-+        }
-+
-+        /**
-+         * Rehashes the contents of this set into a new array with a
-+         * larger capacity.  This method is called automatically when the
-+         * number of keys in this set reaches its threshold.
-+         *
-+         * If current capacity is MAXIMUM_CAPACITY, this method does not
-+         * resize the set, but sets threshold to Integer.MAX_VALUE.
-+         * This has the effect of preventing future calls.
-+         *
-+         * @param newCapacity the new capacity, MUST be a power of two;
-+         *        must be greater than current capacity unless current
-+         *        capacity is MAXIMUM_CAPACITY (in which case value
-+         *        is irrelevant)
-+         */
-+        private void resize(int newCapacity) {
-+            Entry[] oldTable = getTable();
-+            int oldCapacity = oldTable.length;
-+            if (oldCapacity == MAXIMUM_CAPACITY) {
-+                threshold = Integer.MAX_VALUE;
-+                return;
-+            }
-+
-+            Entry[] newTable = newTable(newCapacity);
-+            transfer(oldTable, newTable);
-+            table = newTable;
-+
-+            /*
-+             * If ignoring null elements and processing ref queue caused massive
-+             * shrinkage, then restore old table.  This should be rare, but avoids
-+             * unbounded expansion of garbage-filled tables.
-+             */
-+            if (size >= threshold / 2) {
-+                threshold = (int)(newCapacity * loadFactor);
-+            } else {
-+                expungeStaleEntries();
-+                transfer(newTable, oldTable);
-+                table = oldTable;
-+            }
-+        }
-+
-+        /**
-+         * Transfers all entries from src to dest tables
-+         * @param src  original table
-+         * @param dest new table
-+         */
-+        private void transfer(Entry[] src, Entry[] dest) {
-+            for (int j = 0; j < src.length; ++j) {
-+                Entry e = src[j];
-+                src[j] = null;
-+                while (e != null) {
-+                    Entry next = e.next;
-+                    MethodType key = e.get();
-+                    if (key == null) {
-+                        e.next = null;  // Help GC
-+                        size--;
-+                    } else {
-+                        int i = indexFor(e.hash, dest.length);
-+                        e.next = dest[i];
-+                        dest[i] = e;
-+                    }
-+                    e = next;
-+                }
-+            }
-+        }
-+
-+        /**
-+         * The entries in this hash table extend WeakReference, using its main ref
-+         * field as the key.
-+         */
-+        private static class Entry extends WeakReference<MethodType> {
-+            final int hash;
-+            Entry next;
-+
-+            /**
-+             * Creates new entry.
-+             */
-+            Entry(MethodType key,
-+                  ReferenceQueue<Object> queue,
-+                  int hash, Entry next) {
-+                super(key, queue);
-+                this.hash  = hash;
-+                this.next  = next;
-+            }
-+        }
-+    }
- }
--- a/meth-7129034.patch	Thu Jul 12 00:47:59 2012 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,413 +0,0 @@
-7129034: VM crash with a field setter method with a filterArguments
-Summary: add null checks before unsafe calls that take a variable base reference; update unit tests
-Reviewed-by: kvn, twisti
-
-diff --git a/src/share/classes/java/lang/invoke/MethodHandleImpl.java b/src/share/classes/java/lang/invoke/MethodHandleImpl.java
---- a/src/share/classes/java/lang/invoke/MethodHandleImpl.java
-+++ b/src/share/classes/java/lang/invoke/MethodHandleImpl.java
-@@ -190,32 +190,36 @@
-         @Override
-         String debugString() { return addTypeString(name, this); }
- 
--        int getFieldI(Object /*C*/ obj) { return unsafe.getInt(obj, offset); }
--        void setFieldI(Object /*C*/ obj, int x) { unsafe.putInt(obj, offset, x); }
--        long getFieldJ(Object /*C*/ obj) { return unsafe.getLong(obj, offset); }
--        void setFieldJ(Object /*C*/ obj, long x) { unsafe.putLong(obj, offset, x); }
--        float getFieldF(Object /*C*/ obj) { return unsafe.getFloat(obj, offset); }
--        void setFieldF(Object /*C*/ obj, float x) { unsafe.putFloat(obj, offset, x); }
--        double getFieldD(Object /*C*/ obj) { return unsafe.getDouble(obj, offset); }
--        void setFieldD(Object /*C*/ obj, double x) { unsafe.putDouble(obj, offset, x); }
--        boolean getFieldZ(Object /*C*/ obj) { return unsafe.getBoolean(obj, offset); }
--        void setFieldZ(Object /*C*/ obj, boolean x) { unsafe.putBoolean(obj, offset, x); }
--        byte getFieldB(Object /*C*/ obj) { return unsafe.getByte(obj, offset); }
--        void setFieldB(Object /*C*/ obj, byte x) { unsafe.putByte(obj, offset, x); }
--        short getFieldS(Object /*C*/ obj) { return unsafe.getShort(obj, offset); }
--        void setFieldS(Object /*C*/ obj, short x) { unsafe.putShort(obj, offset, x); }
--        char getFieldC(Object /*C*/ obj) { return unsafe.getChar(obj, offset); }
--        void setFieldC(Object /*C*/ obj, char x) { unsafe.putChar(obj, offset, x); }
--        Object /*V*/ getFieldL(Object /*C*/ obj) { return unsafe.getObject(obj, offset); }
--        void setFieldL(Object /*C*/ obj, Object /*V*/ x) { unsafe.putObject(obj, offset, x); }
--        // cast (V) is OK here, since we wrap convertArguments around the MH.
-+        private static Object nullCheck(Object obj) {
-+            obj.getClass();  // NPE
-+            return obj;
-+        }
-+
-+        int getFieldI(Object /*C*/ obj) { return unsafe.getInt(nullCheck(obj), offset); }
-+        void setFieldI(Object /*C*/ obj, int x) { unsafe.putInt(nullCheck(obj), offset, x); }
-+        long getFieldJ(Object /*C*/ obj) { return unsafe.getLong(nullCheck(obj), offset); }
-+        void setFieldJ(Object /*C*/ obj, long x) { unsafe.putLong(nullCheck(obj), offset, x); }
-+        float getFieldF(Object /*C*/ obj) { return unsafe.getFloat(nullCheck(obj), offset); }
-+        void setFieldF(Object /*C*/ obj, float x) { unsafe.putFloat(nullCheck(obj), offset, x); }
-+        double getFieldD(Object /*C*/ obj) { return unsafe.getDouble(nullCheck(obj), offset); }
-+        void setFieldD(Object /*C*/ obj, double x) { unsafe.putDouble(nullCheck(obj), offset, x); }
-+        boolean getFieldZ(Object /*C*/ obj) { return unsafe.getBoolean(nullCheck(obj), offset); }
-+        void setFieldZ(Object /*C*/ obj, boolean x) { unsafe.putBoolean(nullCheck(obj), offset, x); }
-+        byte getFieldB(Object /*C*/ obj) { return unsafe.getByte(nullCheck(obj), offset); }
-+        void setFieldB(Object /*C*/ obj, byte x) { unsafe.putByte(nullCheck(obj), offset, x); }
-+        short getFieldS(Object /*C*/ obj) { return unsafe.getShort(nullCheck(obj), offset); }
-+        void setFieldS(Object /*C*/ obj, short x) { unsafe.putShort(nullCheck(obj), offset, x); }
-+        char getFieldC(Object /*C*/ obj) { return unsafe.getChar(nullCheck(obj), offset); }
-+        void setFieldC(Object /*C*/ obj, char x) { unsafe.putChar(nullCheck(obj), offset, x); }
-+        Object /*V*/ getFieldL(Object /*C*/ obj) { return unsafe.getObject(nullCheck(obj), offset); }
-+        void setFieldL(Object /*C*/ obj, Object /*V*/ x) { unsafe.putObject(nullCheck(obj), offset, x); }
- 
-         static Object staticBase(final MemberName field) {
-             if (!field.isStatic())  return null;
-             return AccessController.doPrivileged(new PrivilegedAction<Object>() {
-                     public Object run() {
-                         try {
--                            Class c = field.getDeclaringClass();
-+                            Class<?> c = field.getDeclaringClass();
-                             // FIXME:  Should not have to create 'f' to get this value.
-                             java.lang.reflect.Field f = c.getDeclaredField(field.getName());
-                             return unsafe.staticFieldBase(f);
-@@ -242,7 +246,6 @@
-         void setStaticS(short x) { unsafe.putShort(base, offset, x); }
-         char getStaticC() { return unsafe.getChar(base, offset); }
-         void setStaticC(char x) { unsafe.putChar(base, offset, x); }
--        @SuppressWarnings("unchecked")  // (V) is for internal clarity but triggers warning
-         Object /*V*/ getStaticL() { return unsafe.getObject(base, offset); }
-         void setStaticL(Object /*V*/ x) { unsafe.putObject(base, offset, x); }
- 
-diff --git a/test/java/lang/invoke/MethodHandlesTest.java b/test/java/lang/invoke/MethodHandlesTest.java
---- a/test/java/lang/invoke/MethodHandlesTest.java
-+++ b/test/java/lang/invoke/MethodHandlesTest.java
-@@ -280,6 +280,8 @@
-                     { param = c; break; }
-             }
-         }
-+        if (param.isInterface() && param.isAssignableFrom(List.class))
-+            return Arrays.asList("#"+nextArg());
-         if (param.isInterface() || param.isAssignableFrom(String.class))
-             return "#"+nextArg();
-         else
-@@ -457,6 +459,7 @@
-             @Override public String toString() { return name; }
-         }
-     }
-+    static interface SubIntExample extends IntExample { }
- 
-     static final Object[][][] ACCESS_CASES = {
-         { { false, PUBLIC }, { false, PACKAGE }, { false, PRIVATE }, { false, EXAMPLE } }, //[0]: all false
-@@ -960,7 +963,7 @@
-         }
-     }
- 
--    static final int TEST_UNREFLECT = 1, TEST_FIND_FIELD = 2, TEST_FIND_STATIC = 3, TEST_SETTER = 0x10;
-+    static final int TEST_UNREFLECT = 1, TEST_FIND_FIELD = 2, TEST_FIND_STATIC = 3, TEST_SETTER = 0x10, TEST_NPE = 0x20;
-     static boolean testModeMatches(int testMode, boolean isStatic) {
-         switch (testMode) {
-         case TEST_FIND_STATIC:          return isStatic;
-@@ -990,6 +993,8 @@
-         for (Object[] c : HasFields.CASES) {
-             boolean positive = (c[1] != Error.class);
-             testGetter(positive, lookup, c[0], c[1], testMode);
-+            if (positive)
-+                testGetter(positive, lookup, c[0], c[1], testMode | TEST_NPE);
-         }
-         testGetter(true, lookup,
-                    new Object[]{ true,  System.class, "out", java.io.PrintStream.class },
-@@ -1005,12 +1010,14 @@
-         testAccessor(positive, lookup, fieldRef, value, testMode);
-     }
- 
--    public void testAccessor(boolean positive, MethodHandles.Lookup lookup,
-+    public void testAccessor(boolean positive0, MethodHandles.Lookup lookup,
-                              Object fieldRef, Object value, int testMode0) throws Throwable {
-         if (verbosity >= 4)
--            System.out.println("testAccessor"+Arrays.asList(positive, lookup, fieldRef, value, testMode0));
-+            System.out.println("testAccessor"+Arrays.deepToString(new Object[]{positive0, lookup, fieldRef, value, testMode0}));
-         boolean isGetter = ((testMode0 & TEST_SETTER) == 0);
--        int testMode = testMode0 & ~TEST_SETTER;
-+        boolean testNPE  = ((testMode0 & TEST_NPE) != 0);
-+        int testMode = testMode0 & ~(TEST_SETTER | TEST_NPE);
-+        boolean positive = positive0 && !testNPE;
-         boolean isStatic;
-         Class<?> fclass;
-         String   fname;
-@@ -1035,6 +1042,7 @@
-         }
-         if (!testModeMatches(testMode, isStatic))  return;
-         if (f == null && testMode == TEST_UNREFLECT)  return;
-+        if (testNPE && isStatic)  return;
-         countTest(positive);
-         MethodType expType;
-         if (isGetter)
-@@ -1045,7 +1053,7 @@
-         Exception noAccess = null;
-         MethodHandle mh;
-         try {
--            switch (testMode0) {
-+            switch (testMode0 & ~TEST_NPE) {
-             case TEST_UNREFLECT:   mh = lookup.unreflectGetter(f);                      break;
-             case TEST_FIND_FIELD:  mh = lookup.findGetter(fclass, fname, ftype);        break;
-             case TEST_FIND_STATIC: mh = lookup.findStaticGetter(fclass, fname, ftype);  break;
-@@ -1070,15 +1078,17 @@
-             System.out.println("find"+(isStatic?"Static":"")+(isGetter?"Getter":"Setter")+" "+fclass.getName()+"."+fname+"/"+ftype
-                                +" => "+mh
-                                +(noAccess == null ? "" : " !! "+noAccess));
--        if (positive && noAccess != null)  throw new RuntimeException(noAccess);
--        assertEquals(positive ? "positive test" : "negative test erroneously passed", positive, mh != null);
--        if (!positive)  return; // negative test failed as expected
-+        if (positive && !testNPE && noAccess != null)  throw new RuntimeException(noAccess);
-+        assertEquals(positive0 ? "positive test" : "negative test erroneously passed", positive0, mh != null);
-+        if (!positive && !testNPE)  return; // negative access test failed as expected
-         assertEquals((isStatic ? 0 : 1)+(isGetter ? 0 : 1), mh.type().parameterCount());
- 
- 
-         assertSame(mh.type(), expType);
-         assertNameStringContains(mh, fname);
-         HasFields fields = new HasFields();
-+        HasFields fieldsForMH = fields;
-+        if (testNPE)  fieldsForMH = null;  // perturb MH argument to elicit expected error
-         Object sawValue;
-         Class<?> vtype = ftype;
-         if (ftype != int.class)  vtype = Object.class;
-@@ -1094,6 +1104,7 @@
-         if (f != null && f.getDeclaringClass() == HasFields.class) {
-             assertEquals(f.get(fields), value);  // clean to start with
-         }
-+        Throwable caughtEx = null;
-         if (isGetter) {
-             Object expValue = value;
-             for (int i = 0; i <= 1; i++) {
-@@ -1103,10 +1114,18 @@
-                     else
-                         sawValue = mh.invokeExact();
-                 } else {
--                    if (ftype == int.class)
--                        sawValue = (int) mh.invokeExact((Object) fields);
--                    else
--                        sawValue = mh.invokeExact((Object) fields);
-+                    sawValue = null;  // make DA rules happy under try/catch
-+                    try {
-+                        if (ftype == int.class)
-+                            sawValue = (int) mh.invokeExact((Object) fieldsForMH);
-+                        else
-+                            sawValue = mh.invokeExact((Object) fieldsForMH);
-+                    } catch (RuntimeException ex) {
-+                        if (ex instanceof NullPointerException && testNPE) {
-+                            caughtEx = ex;
-+                            break;
-+                        }
-+                    }
-                 }
-                 assertEquals(sawValue, expValue);
-                 if (f != null && f.getDeclaringClass() == HasFields.class
-@@ -1127,10 +1146,17 @@
-                     else
-                         mh.invokeExact(putValue);
-                 } else {
--                    if (ftype == int.class)
--                        mh.invokeExact((Object) fields, (int)putValue);
--                    else
--                        mh.invokeExact((Object) fields, putValue);
-+                    try {
-+                        if (ftype == int.class)
-+                            mh.invokeExact((Object) fieldsForMH, (int)putValue);
-+                        else
-+                            mh.invokeExact((Object) fieldsForMH, putValue);
-+                    } catch (RuntimeException ex) {
-+                        if (ex instanceof NullPointerException && testNPE) {
-+                            caughtEx = ex;
-+                            break;
-+                        }
-+                    }
-                 }
-                 if (f != null && f.getDeclaringClass() == HasFields.class) {
-                     assertEquals(f.get(fields), putValue);
-@@ -1140,6 +1166,14 @@
-         if (f != null && f.getDeclaringClass() == HasFields.class) {
-             f.set(fields, value);  // put it back
-         }
-+        if (testNPE) {
-+            if (caughtEx == null || !(caughtEx instanceof NullPointerException))
-+                throw new RuntimeException("failed to catch NPE exception"+(caughtEx == null ? " (caughtEx=null)" : ""), caughtEx);
-+            caughtEx = null;  // nullify expected exception
-+        }
-+        if (caughtEx != null) {
-+            throw new RuntimeException("unexpected exception", caughtEx);
-+        }
-     }
- 
- 
-@@ -1164,6 +1198,8 @@
-         for (Object[] c : HasFields.CASES) {
-             boolean positive = (c[1] != Error.class);
-             testSetter(positive, lookup, c[0], c[1], testMode);
-+            if (positive)
-+                testSetter(positive, lookup, c[0], c[1], testMode | TEST_NPE);
-         }
-         for (int isStaticN = 0; isStaticN <= 1; isStaticN++) {
-             testSetter(false, lookup,
-@@ -1188,24 +1224,71 @@
-         testArrayElementGetterSetter(true);
-     }
- 
-+    private static final int TEST_ARRAY_NONE = 0, TEST_ARRAY_NPE = 1, TEST_ARRAY_OOB = 2, TEST_ARRAY_ASE = 3;
-+
-     public void testArrayElementGetterSetter(boolean testSetter) throws Throwable {
--        testArrayElementGetterSetter(new Object[10], testSetter);
--        testArrayElementGetterSetter(new String[10], testSetter);
--        testArrayElementGetterSetter(new boolean[10], testSetter);
--        testArrayElementGetterSetter(new byte[10], testSetter);
--        testArrayElementGetterSetter(new char[10], testSetter);
--        testArrayElementGetterSetter(new short[10], testSetter);
--        testArrayElementGetterSetter(new int[10], testSetter);
--        testArrayElementGetterSetter(new float[10], testSetter);
--        testArrayElementGetterSetter(new long[10], testSetter);
--        testArrayElementGetterSetter(new double[10], testSetter);
-+        testArrayElementGetterSetter(testSetter, TEST_ARRAY_NONE);
-     }
- 
--    public void testArrayElementGetterSetter(Object array, boolean testSetter) throws Throwable {
--        countTest(true);
--        if (verbosity > 2)  System.out.println("array type = "+array.getClass().getComponentType().getName()+"["+Array.getLength(array)+"]");
-+    @Test
-+    public void testArrayElementErrors() throws Throwable {
-+        startTest("arrayElementErrors");
-+        testArrayElementGetterSetter(false, TEST_ARRAY_NPE);
-+        testArrayElementGetterSetter(true, TEST_ARRAY_NPE);
-+        testArrayElementGetterSetter(false, TEST_ARRAY_OOB);
-+        testArrayElementGetterSetter(true, TEST_ARRAY_OOB);
-+        testArrayElementGetterSetter(new Object[10], true, TEST_ARRAY_ASE);
-+        testArrayElementGetterSetter(new Example[10], true, TEST_ARRAY_ASE);
-+        testArrayElementGetterSetter(new IntExample[10], true, TEST_ARRAY_ASE);
-+    }
-+
-+    public void testArrayElementGetterSetter(boolean testSetter, int negTest) throws Throwable {
-+        testArrayElementGetterSetter(new String[10], testSetter, negTest);
-+        testArrayElementGetterSetter(new Iterable<?>[10], testSetter, negTest);
-+        testArrayElementGetterSetter(new Example[10], testSetter, negTest);
-+        testArrayElementGetterSetter(new IntExample[10], testSetter, negTest);
-+        testArrayElementGetterSetter(new Object[10], testSetter, negTest);
-+        testArrayElementGetterSetter(new boolean[10], testSetter, negTest);
-+        testArrayElementGetterSetter(new byte[10], testSetter, negTest);
-+        testArrayElementGetterSetter(new char[10], testSetter, negTest);
-+        testArrayElementGetterSetter(new short[10], testSetter, negTest);
-+        testArrayElementGetterSetter(new int[10], testSetter, negTest);
-+        testArrayElementGetterSetter(new float[10], testSetter, negTest);
-+        testArrayElementGetterSetter(new long[10], testSetter, negTest);
-+        testArrayElementGetterSetter(new double[10], testSetter, negTest);
-+    }
-+
-+    public void testArrayElementGetterSetter(Object array, boolean testSetter, int negTest) throws Throwable {
-+        boolean positive = (negTest == TEST_ARRAY_NONE);
-+        int length = java.lang.reflect.Array.getLength(array);
-         Class<?> arrayType = array.getClass();
-         Class<?> elemType = arrayType.getComponentType();
-+        Object arrayToMH = array;
-+        // this stanza allows negative tests to make argument perturbations:
-+        switch (negTest) {
-+        case TEST_ARRAY_NPE:
-+            arrayToMH = null;
-+            break;
-+        case TEST_ARRAY_OOB:
-+            assert(length > 0);
-+            arrayToMH = java.lang.reflect.Array.newInstance(elemType, 0);
-+            break;
-+        case TEST_ARRAY_ASE:
-+            assert(testSetter && !elemType.isPrimitive());
-+            if (elemType == Object.class)
-+                arrayToMH = new StringBuffer[length];  // very random subclass of Object!
-+            else if (elemType == Example.class)
-+                arrayToMH = new SubExample[length];
-+            else if (elemType == IntExample.class)
-+                arrayToMH = new SubIntExample[length];
-+            else
-+                return;  // can't make an ArrayStoreException test
-+            assert(arrayType.isInstance(arrayToMH))
-+                : Arrays.asList(arrayType, arrayToMH.getClass(), testSetter, negTest);
-+            break;
-+        }
-+        countTest(positive);
-+        if (verbosity > 2)  System.out.println("array type = "+array.getClass().getComponentType().getName()+"["+length+"]"+(positive ? "" : " negative test #"+negTest+" using "+Arrays.deepToString(new Object[]{arrayToMH})));
-         MethodType expType = !testSetter
-                 ? MethodType.methodType(elemType,   arrayType, int.class)
-                 : MethodType.methodType(void.class, arrayType, int.class, elemType);
-@@ -1214,25 +1297,29 @@
-                 : MethodHandles.arrayElementSetter(arrayType);
-         assertSame(mh.type(), expType);
-         if (elemType != int.class && elemType != boolean.class) {
--            // FIXME: change Integer.class and (Integer) below to int.class and (int) below.
--            MethodType gtype = mh.type().generic().changeParameterType(1, Integer.class);
-+            MethodType gtype = mh.type().generic().changeParameterType(1, int.class);
-             if (testSetter)  gtype = gtype.changeReturnType(void.class);
-             mh = mh.asType(gtype);
-         }
-         Object sawValue, expValue;
-         List<Object> model = array2list(array);
--        int length = Array.getLength(array);
-+        Throwable caughtEx = null;
-         for (int i = 0; i < length; i++) {
-             // update array element
-             Object random = randomArg(elemType);
-             model.set(i, random);
-             if (testSetter) {
--                if (elemType == int.class)
--                    mh.invokeExact((int[]) array, i, (int)random);
--                else if (elemType == boolean.class)
--                    mh.invokeExact((boolean[]) array, i, (boolean)random);
--                else
--                    mh.invokeExact(array, (Integer)i, random);
-+                try {
-+                    if (elemType == int.class)
-+                        mh.invokeExact((int[]) arrayToMH, i, (int)random);
-+                    else if (elemType == boolean.class)
-+                        mh.invokeExact((boolean[]) arrayToMH, i, (boolean)random);
-+                    else
-+                        mh.invokeExact(arrayToMH, i, random);
-+                } catch (RuntimeException ex) {
-+                    caughtEx = ex;
-+                    break;
-+                }
-                 assertEquals(model, array2list(array));
-             } else {
-                 Array.set(array, i, random);
-@@ -1247,16 +1334,39 @@
-             sawValue = Array.get(array, i);
-             if (!testSetter) {
-                 expValue = sawValue;
--                if (elemType == int.class)
--                    sawValue = (int) mh.invokeExact((int[]) array, i);
--                else if (elemType == boolean.class)
--                    sawValue = (boolean) mh.invokeExact((boolean[]) array, i);
--                else
--                    sawValue = mh.invokeExact(array, (Integer)i);
-+                try {
-+                    if (elemType == int.class)
-+                        sawValue = (int) mh.invokeExact((int[]) arrayToMH, i);
-+                    else if (elemType == boolean.class)
-+                        sawValue = (boolean) mh.invokeExact((boolean[]) arrayToMH, i);
-+                    else
-+                        sawValue = mh.invokeExact(arrayToMH, i);
-+                } catch (RuntimeException ex) {
-+                    caughtEx = ex;
-+                    break;
-+                }
-                 assertEquals(sawValue, expValue);
-                 assertEquals(model, array2list(array));
-             }
-         }
-+        if (!positive) {
-+            if (caughtEx == null)
-+                throw new RuntimeException("failed to catch exception for negTest="+negTest);
-+            // test the kind of exception
-+            Class<?> reqType = null;
-+            switch (negTest) {
-+            case TEST_ARRAY_ASE:  reqType = ArrayStoreException.class; break;
-+            case TEST_ARRAY_OOB:  reqType = ArrayIndexOutOfBoundsException.class; break;
-+            case TEST_ARRAY_NPE:  reqType = NullPointerException.class; break;
-+            default:              assert(false);
-+            }
-+            if (reqType.isInstance(caughtEx)) {
-+                caughtEx = null;  // nullify expected exception
-+            }
-+        }
-+        if (caughtEx != null) {
-+            throw new RuntimeException("unexpected exception", caughtEx);
-+        }
-     }
- 
-     List<Object> array2list(Object array) {
--- a/series	Thu Jul 12 00:47:59 2012 +0200
+++ b/series	Thu Jul 12 02:21:22 2012 -0700
@@ -1,29 +1,25 @@
-# base = 9d1738ef61d6 in http://hg.openjdk.java.net/hsx/hotspot-comp/jdk [2012-07-05]
+# base = 78f1f4e4e9c7 in http://hg.openjdk.java.net/hsx/hotspot-comp/jdk [2012-07-12]
 
 # review complete for hotspot-comp:
-cval-7153157.patch              #+9d1738ef61d6
-meth-7129034.patch              #+9d1738ef61d6
-meth-7087658.patch              #+9d1738ef61d6
+# (none)
 
 # review pending before push to hotspot-comp:
-# (none)
-meth-7127687.patch              #+9d1738ef61d6
-meth-7177472.patch              #(9d1738ef61d6) #-buildable
+meth-7177472.patch              #(78f1f4e4e9c7) #-buildable
 
 # non-pushed files are under review or development, or merely experimental:
-indy.pack.patch                 #-/meth #+9d1738ef61d6 #-buildable
-meth.patch                      #-/meth #+9d1738ef61d6
-meth-lazy-7023639.patch         #-/meth #+9d1738ef61d6 #-testable
-meth-lazy-7023639.xbmh.patch    #-/meth #+9d1738ef61d6 #-testable
+indy.pack.patch                 #-/meth #+78f1f4e4e9c7 #-buildable
+meth.patch                      #-/meth #+78f1f4e4e9c7
+meth-lazy-7023639.patch         #-/meth #+78f1f4e4e9c7 #-testable
+meth-lazy-7023639.xbmh.patch    #-/meth #+78f1f4e4e9c7 #-testable
 
 # Keep these separate, for debugging and review:
 dyncast.patch   #+dyncast       #-/dyncast
 inti.patch      #+inti          #-/inti #-buildable
 callcc_old.patch #+callcc_old   #-/callcc_old
-continuation.patch #+continuation #-/continuation #(9d1738ef61d6)
+continuation.patch #+continuation #-/continuation #(78f1f4e4e9c7)
 tailc.patch     #+tailc         #-/tailc
-anonk.patch                     #-/anonk #+9d1738ef61d6
+anonk.patch                     #-/anonk #+78f1f4e4e9c7
 
-coro.patch      #+coro          #-/coro #(9d1738ef61d6)
+coro.patch      #+coro          #-/coro #(78f1f4e4e9c7)
 
 tuple-tsig.patch                #-/tuple #-testable