changeset 633:8c617a092d68

8026016: too many relinks dominate avatar.js http benchmark Reviewed-by: sundar, jlaskey, attila
author hannesw
date Mon, 14 Oct 2013 11:45:15 +0200
parents 6cb4f20d971f
children d155c4a7703c
files src/jdk/nashorn/internal/runtime/ScriptObject.java test/script/basic/JDK-8026016.js test/script/basic/JDK-8026016.js.EXPECTED
diffstat 3 files changed, 471 insertions(+), 194 deletions(-) [+]
line wrap: on
line diff
--- a/src/jdk/nashorn/internal/runtime/ScriptObject.java	Fri Oct 11 14:54:16 2013 +0200
+++ b/src/jdk/nashorn/internal/runtime/ScriptObject.java	Mon Oct 14 11:45:15 2013 +0200
@@ -37,6 +37,8 @@
 import static jdk.nashorn.internal.runtime.PropertyDescriptor.VALUE;
 import static jdk.nashorn.internal.runtime.PropertyDescriptor.WRITABLE;
 import static jdk.nashorn.internal.runtime.ScriptRuntime.UNDEFINED;
+import static jdk.nashorn.internal.runtime.arrays.ArrayIndex.getArrayIndex;
+import static jdk.nashorn.internal.runtime.arrays.ArrayIndex.isValidArrayIndex;
 
 import java.lang.invoke.MethodHandle;
 import java.lang.invoke.MethodHandles;
@@ -131,6 +133,7 @@
 
     static final MethodHandle GETPROTO           = findOwnMH("getProto", ScriptObject.class);
     static final MethodHandle SETPROTOCHECK      = findOwnMH("setProtoCheck", void.class, Object.class);
+    static final MethodHandle MEGAMORPHIC_GET    = findOwnMH("megamorphicGet", Object.class, String.class, boolean.class);
 
     static final MethodHandle SETFIELD           = findOwnMH("setField",         void.class, CallSiteDescriptor.class, PropertyMap.class, PropertyMap.class, MethodHandle.class, Object.class, Object.class);
     static final MethodHandle SETSPILL           = findOwnMH("setSpill",         void.class, CallSiteDescriptor.class, PropertyMap.class, PropertyMap.class, int.class, Object.class, Object.class);
@@ -388,7 +391,7 @@
             return global.newDataDescriptor(getWithProperty(property), configurable, enumerable, writable);
         }
 
-        final int index = ArrayIndex.getArrayIndex(key);
+        final int index = getArrayIndex(key);
         final ArrayData array = getArray();
 
         if (array.has(index)) {
@@ -592,7 +595,7 @@
      * @param value value to define
      */
     protected final void defineOwnProperty(final int index, final Object value) {
-        assert ArrayIndex.isValidArrayIndex(index) : "invalid array index";
+        assert isValidArrayIndex(index) : "invalid array index";
         final long longIndex = ArrayIndex.toLongIndex(index);
         if (longIndex >= getArray().length()) {
             // make array big enough to hold..
@@ -602,9 +605,9 @@
     }
 
     private void checkIntegerKey(final String key) {
-        final int index = ArrayIndex.getArrayIndex(key);
-
-        if (ArrayIndex.isValidArrayIndex(index)) {
+        final int index = getArrayIndex(key);
+
+        if (isValidArrayIndex(index)) {
             final ArrayData data = getArray();
 
             if (data.has(index)) {
@@ -614,7 +617,7 @@
     }
 
     private void removeArraySlot(final String key) {
-        final int index = ArrayIndex.getArrayIndex(key);
+        final int index = getArrayIndex(key);
         final ArrayData array = getArray();
 
         if (array.has(index)) {
@@ -717,6 +720,28 @@
     }
 
     /**
+     * Low level property API. This is similar to {@link #findProperty(String, boolean)} but returns a
+     * {@code boolean} value instead of a {@link FindProperty} object.
+     * @param key  Property key.
+     * @param deep Whether the search should look up proto chain.
+     * @return true if the property was found.
+     */
+    boolean hasProperty(final String key, final boolean deep) {
+        if (getMap().findProperty(key) != null) {
+            return true;
+        }
+
+        if (deep) {
+            final ScriptObject myProto = getProto();
+            if (myProto != null) {
+                return myProto.hasProperty(key, deep);
+            }
+        }
+
+        return false;
+    }
+
+    /**
      * Add a new property to the object.
      * <p>
      * This a more "low level" way that doesn't involve {@link PropertyDescriptor}s
@@ -1708,8 +1733,11 @@
      */
     protected GuardedInvocation findGetMethod(final CallSiteDescriptor desc, final LinkRequest request, final String operator) {
         final String name = desc.getNameToken(CallSiteDescriptor.NAME_OPERAND);
+        if (request.isCallSiteUnstable()) {
+            return findMegaMorphicGetMethod(desc, name, "getMethod".equals(operator));
+        }
+
         final FindProperty find = findProperty(name, true);
-
         MethodHandle methodHandle;
 
         if (find == null) {
@@ -1727,10 +1755,6 @@
             throw new AssertionError(); // never invoked with any other operation
         }
 
-        if (request.isCallSiteUnstable()) {
-            return findMegaMorphicGetMethod(desc, name);
-        }
-
         final Class<?> returnType = desc.getMethodType().returnType();
         final Property property = find.getProperty();
         methodHandle = find.getGetter(returnType);
@@ -1757,11 +1781,21 @@
         return new GuardedInvocation(Lookup.emptyGetter(returnType), getMap().getProtoGetSwitchPoint(proto, name), guard);
     }
 
-    private static GuardedInvocation findMegaMorphicGetMethod(final CallSiteDescriptor desc, final String name) {
-        final MethodType mhType = desc.getMethodType().insertParameterTypes(1, Object.class);
-        final GuardedInvocation inv = findGetIndexMethod(mhType);
-
-        return inv.replaceMethods(MH.insertArguments(inv.getInvocation(), 1, name), inv.getGuard());
+    private static GuardedInvocation findMegaMorphicGetMethod(final CallSiteDescriptor desc, final String name, final boolean isMethod) {
+        final MethodHandle invoker = MH.insertArguments(MEGAMORPHIC_GET, 1, name, isMethod);
+        final MethodHandle guard = getScriptObjectGuard(desc.getMethodType());
+        return new GuardedInvocation(invoker, guard);
+    }
+
+    @SuppressWarnings("unused")
+    private Object megamorphicGet(final String key, final boolean isMethod) {
+        final FindProperty find = findProperty(key, true);
+
+        if (find != null) {
+            return getObjectValue(find);
+        }
+
+        return isMethod ? getNoSuchMethod(key) : invokeNoSuchProperty(key);
     }
 
     /**
@@ -1810,7 +1844,7 @@
      */
     protected GuardedInvocation findSetMethod(final CallSiteDescriptor desc, final LinkRequest request) {
         final String name = desc.getNameToken(CallSiteDescriptor.NAME_OPERAND);
-        if(request.isCallSiteUnstable()) {
+        if (request.isCallSiteUnstable()) {
             return findMegaMorphicSetMethod(desc, name);
         }
 
@@ -2045,6 +2079,26 @@
         return UNDEFINED;
     }
 
+    /**
+     * Get __noSuchMethod__ as a function bound to this object and {@code name} if it is defined.
+     * @param name the method name
+     * @return the bound function, or undefined
+     */
+    private Object getNoSuchMethod(final String name) {
+        final FindProperty find = findProperty(NO_SUCH_METHOD_NAME, true);
+
+        if (find == null) {
+            return invokeNoSuchProperty(name);
+        }
+
+        final Object value = getObjectValue(find);
+        if (! (value instanceof ScriptFunction)) {
+            return UNDEFINED;
+        }
+
+        return ((ScriptFunction)value).makeBoundFunction(this, new Object[] {name});
+    }
+
     private GuardedInvocation createEmptyGetter(final CallSiteDescriptor desc, final String name) {
         return new GuardedInvocation(Lookup.emptyGetter(desc.getMethodType().returnType()), getMap().getProtoGetSwitchPoint(proto, name), NashornGuards.getMapGuard(getMap()));
     }
@@ -2308,7 +2362,7 @@
     }
 
     private int getInt(final int index, final String key) {
-        if (ArrayIndex.isValidArrayIndex(index)) {
+        if (isValidArrayIndex(index)) {
              for (ScriptObject object = this; ; ) {
                 final FindProperty find = object.findProperty(key, false, false, this);
 
@@ -2339,7 +2393,7 @@
 
     @Override
     public int getInt(final Object key) {
-        final int index = ArrayIndex.getArrayIndex(key);
+        final int index = getArrayIndex(key);
         final ArrayData array = getArray();
 
         if (array.has(index)) {
@@ -2351,7 +2405,7 @@
 
     @Override
     public int getInt(final double key) {
-        final int index = ArrayIndex.getArrayIndex(key);
+        final int index = getArrayIndex(key);
         final ArrayData array = getArray();
 
         if (array.has(index)) {
@@ -2363,7 +2417,7 @@
 
     @Override
     public int getInt(final long key) {
-        final int index = ArrayIndex.getArrayIndex(key);
+        final int index = getArrayIndex(key);
         final ArrayData array = getArray();
 
         if (array.has(index)) {
@@ -2385,7 +2439,7 @@
     }
 
     private long getLong(final int index, final String key) {
-        if (ArrayIndex.isValidArrayIndex(index)) {
+        if (isValidArrayIndex(index)) {
             for (ScriptObject object = this; ; ) {
                 final FindProperty find = object.findProperty(key, false, false, this);
 
@@ -2416,7 +2470,7 @@
 
     @Override
     public long getLong(final Object key) {
-        final int index = ArrayIndex.getArrayIndex(key);
+        final int index = getArrayIndex(key);
         final ArrayData array = getArray();
 
         if (array.has(index)) {
@@ -2428,7 +2482,7 @@
 
     @Override
     public long getLong(final double key) {
-        final int index = ArrayIndex.getArrayIndex(key);
+        final int index = getArrayIndex(key);
         final ArrayData array = getArray();
 
         if (array.has(index)) {
@@ -2440,7 +2494,7 @@
 
     @Override
     public long getLong(final long key) {
-        final int index = ArrayIndex.getArrayIndex(key);
+        final int index = getArrayIndex(key);
         final ArrayData array = getArray();
 
         if (array.has(index)) {
@@ -2462,7 +2516,7 @@
     }
 
     private double getDouble(final int index, final String key) {
-        if (ArrayIndex.isValidArrayIndex(index)) {
+        if (isValidArrayIndex(index)) {
             for (ScriptObject object = this; ; ) {
                 final FindProperty find = object.findProperty(key, false, false, this);
 
@@ -2493,7 +2547,7 @@
 
     @Override
     public double getDouble(final Object key) {
-        final int index = ArrayIndex.getArrayIndex(key);
+        final int index = getArrayIndex(key);
         final ArrayData array = getArray();
 
         if (array.has(index)) {
@@ -2505,7 +2559,7 @@
 
     @Override
     public double getDouble(final double key) {
-        final int index = ArrayIndex.getArrayIndex(key);
+        final int index = getArrayIndex(key);
         final ArrayData array = getArray();
 
         if (array.has(index)) {
@@ -2517,7 +2571,7 @@
 
     @Override
     public double getDouble(final long key) {
-        final int index = ArrayIndex.getArrayIndex(key);
+        final int index = getArrayIndex(key);
         final ArrayData array = getArray();
 
         if (array.has(index)) {
@@ -2539,7 +2593,7 @@
     }
 
     private Object get(final int index, final String key) {
-        if (ArrayIndex.isValidArrayIndex(index)) {
+        if (isValidArrayIndex(index)) {
             for (ScriptObject object = this; ; ) {
                 final FindProperty find = object.findProperty(key, false, false, this);
 
@@ -2570,7 +2624,7 @@
 
     @Override
     public Object get(final Object key) {
-        final int index = ArrayIndex.getArrayIndex(key);
+        final int index = getArrayIndex(key);
         final ArrayData array = getArray();
 
         if (array.has(index)) {
@@ -2582,7 +2636,7 @@
 
     @Override
     public Object get(final double key) {
-        final int index = ArrayIndex.getArrayIndex(key);
+        final int index = getArrayIndex(key);
         final ArrayData array = getArray();
 
         if (array.has(index)) {
@@ -2594,7 +2648,7 @@
 
     @Override
     public Object get(final long key) {
-        final int index = ArrayIndex.getArrayIndex(key);
+        final int index = getArrayIndex(key);
         final ArrayData array = getArray();
 
         if (array.has(index)) {
@@ -2710,9 +2764,9 @@
 
     @Override
     public void set(final Object key, final int value, final boolean strict) {
-        final int index = ArrayIndex.getArrayIndex(key);
-
-        if (ArrayIndex.isValidArrayIndex(index)) {
+        final int index = getArrayIndex(key);
+
+        if (isValidArrayIndex(index)) {
             if (getArray().has(index)) {
                 setArray(getArray().set(index, value, strict));
             } else {
@@ -2722,14 +2776,15 @@
             return;
         }
 
-        set(key, JSType.toObject(value), strict);
+        final String propName = JSType.toString(key);
+        setObject(findProperty(propName, true), strict, propName, JSType.toObject(value));
     }
 
     @Override
     public void set(final Object key, final long value, final boolean strict) {
-        final int index = ArrayIndex.getArrayIndex(key);
-
-        if (ArrayIndex.isValidArrayIndex(index)) {
+        final int index = getArrayIndex(key);
+
+        if (isValidArrayIndex(index)) {
             if (getArray().has(index)) {
                 setArray(getArray().set(index, value, strict));
             } else {
@@ -2739,14 +2794,15 @@
             return;
         }
 
-        set(key, JSType.toObject(value), strict);
+        final String propName = JSType.toString(key);
+        setObject(findProperty(propName, true), strict, propName, JSType.toObject(value));
     }
 
     @Override
     public void set(final Object key, final double value, final boolean strict) {
-        final int index = ArrayIndex.getArrayIndex(key);
-
-        if (ArrayIndex.isValidArrayIndex(index)) {
+        final int index = getArrayIndex(key);
+
+        if (isValidArrayIndex(index)) {
             if (getArray().has(index)) {
                 setArray(getArray().set(index, value, strict));
             } else {
@@ -2756,14 +2812,15 @@
             return;
         }
 
-        set(key, JSType.toObject(value), strict);
+        final String propName = JSType.toString(key);
+        setObject(findProperty(propName, true), strict, propName, JSType.toObject(value));
     }
 
     @Override
     public void set(final Object key, final Object value, final boolean strict) {
-        final int index = ArrayIndex.getArrayIndex(key);
-
-        if (ArrayIndex.isValidArrayIndex(index)) {
+        final int index = getArrayIndex(key);
+
+        if (isValidArrayIndex(index)) {
             if (getArray().has(index)) {
                 setArray(getArray().set(index, value, strict));
             } else {
@@ -2773,17 +2830,15 @@
             return;
         }
 
-        final String       propName = JSType.toString(key);
-        final FindProperty find     = findProperty(propName, true);
-
-        setObject(find, strict, propName, value);
+        final String propName = JSType.toString(key);
+        setObject(findProperty(propName, true), strict, propName, value);
     }
 
     @Override
     public void set(final double key, final int value, final boolean strict) {
-        final int index = ArrayIndex.getArrayIndex(key);
-
-        if (ArrayIndex.isValidArrayIndex(index)) {
+        final int index = getArrayIndex(key);
+
+        if (isValidArrayIndex(index)) {
             if (getArray().has(index)) {
                 setArray(getArray().set(index, value, strict));
             } else {
@@ -2793,14 +2848,15 @@
             return;
         }
 
-        set(JSType.toObject(key), JSType.toObject(value), strict);
+        final String propName = JSType.toString(key);
+        setObject(findProperty(propName, true), strict, propName, JSType.toObject(value));
     }
 
     @Override
     public void set(final double key, final long value, final boolean strict) {
-        final int index = ArrayIndex.getArrayIndex(key);
-
-        if (ArrayIndex.isValidArrayIndex(index)) {
+        final int index = getArrayIndex(key);
+
+        if (isValidArrayIndex(index)) {
             if (getArray().has(index)) {
                 setArray(getArray().set(index, value, strict));
             } else {
@@ -2810,14 +2866,15 @@
             return;
         }
 
-        set(JSType.toObject(key), JSType.toObject(value), strict);
+        final String propName = JSType.toString(key);
+        setObject(findProperty(propName, true), strict, propName, JSType.toObject(value));
     }
 
     @Override
     public void set(final double key, final double value, final boolean strict) {
-        final int index = ArrayIndex.getArrayIndex(key);
-
-        if (ArrayIndex.isValidArrayIndex(index)) {
+        final int index = getArrayIndex(key);
+
+        if (isValidArrayIndex(index)) {
             if (getArray().has(index)) {
                 setArray(getArray().set(index, value, strict));
             } else {
@@ -2827,14 +2884,15 @@
             return;
         }
 
-        set(JSType.toObject(key), JSType.toObject(value), strict);
+        final String propName = JSType.toString(key);
+        setObject(findProperty(propName, true), strict, propName, JSType.toObject(value));
     }
 
     @Override
     public void set(final double key, final Object value, final boolean strict) {
-        final int index = ArrayIndex.getArrayIndex(key);
-
-        if (ArrayIndex.isValidArrayIndex(index)) {
+        final int index = getArrayIndex(key);
+
+        if (isValidArrayIndex(index)) {
             if (getArray().has(index)) {
                 setArray(getArray().set(index, value, strict));
             } else {
@@ -2844,14 +2902,15 @@
             return;
         }
 
-        set(JSType.toObject(key), value, strict);
+        final String propName = JSType.toString(key);
+        setObject(findProperty(propName, true), strict, propName, value);
     }
 
     @Override
     public void set(final long key, final int value, final boolean strict) {
-        final int index = ArrayIndex.getArrayIndex(key);
-
-        if (ArrayIndex.isValidArrayIndex(index)) {
+        final int index = getArrayIndex(key);
+
+        if (isValidArrayIndex(index)) {
             if (getArray().has(index)) {
                 setArray(getArray().set(index, value, strict));
             } else {
@@ -2861,31 +2920,15 @@
             return;
         }
 
-        set(JSType.toObject(key), JSType.toObject(value), strict);
+        final String propName = JSType.toString(key);
+        setObject(findProperty(propName, true), strict, propName, JSType.toObject(value));
     }
 
     @Override
     public void set(final long key, final long value, final boolean strict) {
-        final int index = ArrayIndex.getArrayIndex(key);
-
-        if (ArrayIndex.isValidArrayIndex(index)) {
-            if (getArray().has(index)) {
-                setArray(getArray().set(index, value, strict));
-            } else {
-                doesNotHave(index, value, strict);
-            }
-
-            return;
-        }
-
-        set(JSType.toObject(key), JSType.toObject(value), strict);
-    }
-
-    @Override
-    public void set(final long key, final double value, final boolean strict) {
-        final int index = ArrayIndex.getArrayIndex(key);
-
-        if (ArrayIndex.isValidArrayIndex(index)) {
+        final int index = getArrayIndex(key);
+
+        if (isValidArrayIndex(index)) {
             if (getArray().has(index)) {
                 setArray(getArray().set(index, value, strict));
             } else {
@@ -2895,14 +2938,15 @@
             return;
         }
 
-        set(JSType.toObject(key), JSType.toObject(value), strict);
+        final String propName = JSType.toString(key);
+        setObject(findProperty(propName, true), strict, propName, JSType.toObject(value));
     }
 
     @Override
-    public void set(final long key, final Object value, final boolean strict) {
-        final int index = ArrayIndex.getArrayIndex(key);
-
-        if (ArrayIndex.isValidArrayIndex(index)) {
+    public void set(final long key, final double value, final boolean strict) {
+        final int index = getArrayIndex(key);
+
+        if (isValidArrayIndex(index)) {
             if (getArray().has(index)) {
                 setArray(getArray().set(index, value, strict));
             } else {
@@ -2912,14 +2956,15 @@
             return;
         }
 
-        set(JSType.toObject(key), value, strict);
+        final String propName = JSType.toString(key);
+        setObject(findProperty(propName, true), strict, propName, JSType.toObject(value));
     }
 
     @Override
-    public void set(final int key, final int value, final boolean strict) {
-        final int index = ArrayIndex.getArrayIndex(key);
-
-        if (ArrayIndex.isValidArrayIndex(index)) {
+    public void set(final long key, final Object value, final boolean strict) {
+        final int index = getArrayIndex(key);
+
+        if (isValidArrayIndex(index)) {
             if (getArray().has(index)) {
                 setArray(getArray().set(index, value, strict));
             } else {
@@ -2929,14 +2974,15 @@
             return;
         }
 
-        set(JSType.toObject(key), JSType.toObject(value), strict);
+        final String propName = JSType.toString(key);
+        setObject(findProperty(propName, true), strict, propName, value);
     }
 
     @Override
-    public void set(final int key, final long value, final boolean strict) {
-        final int index = ArrayIndex.getArrayIndex(key);
-
-        if (ArrayIndex.isValidArrayIndex(index)) {
+    public void set(final int key, final int value, final boolean strict) {
+        final int index = getArrayIndex(key);
+
+        if (isValidArrayIndex(index)) {
             if (getArray().has(index)) {
                 setArray(getArray().set(index, value, strict));
             } else {
@@ -2946,14 +2992,15 @@
             return;
         }
 
-        set(JSType.toObject(key), JSType.toObject(value), strict);
+        final String propName = JSType.toString(key);
+        setObject(findProperty(propName, true), strict, propName, JSType.toObject(value));
     }
 
     @Override
-    public void set(final int key, final double value, final boolean strict) {
-        final int index = ArrayIndex.getArrayIndex(key);
-
-        if (ArrayIndex.isValidArrayIndex(index)) {
+    public void set(final int key, final long value, final boolean strict) {
+        final int index = getArrayIndex(key);
+
+        if (isValidArrayIndex(index)) {
             if (getArray().has(index)) {
                 setArray(getArray().set(index, value, strict));
             } else {
@@ -2963,14 +3010,15 @@
             return;
         }
 
-        set(JSType.toObject(key), JSType.toObject(value), strict);
+        final String propName = JSType.toString(key);
+        setObject(findProperty(propName, true), strict, propName, JSType.toObject(value));
     }
 
     @Override
-    public void set(final int key, final Object value, final boolean strict) {
-        final int index = ArrayIndex.getArrayIndex(key);
-
-        if (ArrayIndex.isValidArrayIndex(index)) {
+    public void set(final int key, final double value, final boolean strict) {
+        final int index = getArrayIndex(key);
+
+        if (isValidArrayIndex(index)) {
             if (getArray().has(index)) {
                 setArray(getArray().set(index, value, strict));
             } else {
@@ -2980,14 +3028,33 @@
             return;
         }
 
-        set(JSType.toObject(key), value, strict);
+        final String propName = JSType.toString(key);
+        setObject(findProperty(propName, true), strict, propName, JSType.toObject(value));
+    }
+
+    @Override
+    public void set(final int key, final Object value, final boolean strict) {
+        final int index = getArrayIndex(key);
+
+        if (isValidArrayIndex(index)) {
+            if (getArray().has(index)) {
+                setArray(getArray().set(index, value, strict));
+            } else {
+                doesNotHave(index, value, strict);
+            }
+
+            return;
+        }
+
+        final String propName = JSType.toString(key);
+        setObject(findProperty(propName, true), strict, propName, value);
     }
 
     @Override
     public boolean has(final Object key) {
-        final int index = ArrayIndex.getArrayIndex(key);
-
-        if (ArrayIndex.isValidArrayIndex(index)) {
+        final int index = getArrayIndex(key);
+
+        if (isValidArrayIndex(index)) {
             for (ScriptObject self = this; self != null; self = self.getProto()) {
                 if (self.getArray().has(index)) {
                     return true;
@@ -2995,33 +3062,14 @@
             }
         }
 
-        final FindProperty find = findProperty(JSType.toString(key), true);
-
-        return find != null;
+        return hasProperty(JSType.toString(key), true);
     }
 
     @Override
     public boolean has(final double key) {
-        final int index = ArrayIndex.getArrayIndex(key);
-
-        if (ArrayIndex.isValidArrayIndex(index)) {
-            for (ScriptObject self = this; self != null; self = self.getProto()) {
-                if (self.getArray().has(index)) {
-                    return true;
-                }
-            }
-        }
-
-        final FindProperty find = findProperty(JSType.toString(key), true);
-
-        return find != null;
-    }
-
-    @Override
-    public boolean has(final long key) {
-        final int index = ArrayIndex.getArrayIndex(key);
-
-        if (ArrayIndex.isValidArrayIndex(index)) {
+        final int index = getArrayIndex(key);
+
+        if (isValidArrayIndex(index)) {
             for (ScriptObject self = this; self != null; self = self.getProto()) {
                 if (self.getArray().has(index)) {
                     return true;
@@ -3029,16 +3077,14 @@
             }
         }
 
-        final FindProperty find = findProperty(JSType.toString(key), true);
-
-        return find != null;
+        return hasProperty(JSType.toString(key), true);
     }
 
     @Override
-    public boolean has(final int key) {
-        final int index = ArrayIndex.getArrayIndex(key);
-
-        if (ArrayIndex.isValidArrayIndex(index)) {
+    public boolean has(final long key) {
+        final int index = getArrayIndex(key);
+
+        if (isValidArrayIndex(index)) {
             for (ScriptObject self = this; self != null; self = self.getProto()) {
                 if (self.getArray().has(index)) {
                     return true;
@@ -3046,66 +3092,47 @@
             }
         }
 
-        final FindProperty find = findProperty(JSType.toString(key), true);
-
-        return find != null;
+        return hasProperty(JSType.toString(key), true);
+    }
+
+    @Override
+    public boolean has(final int key) {
+        final int index = getArrayIndex(key);
+
+        if (isValidArrayIndex(index)) {
+            for (ScriptObject self = this; self != null; self = self.getProto()) {
+                if (self.getArray().has(index)) {
+                    return true;
+                }
+            }
+        }
+
+        return hasProperty(JSType.toString(key), true);
     }
 
     @Override
     public boolean hasOwnProperty(final Object key) {
-        final int index = ArrayIndex.getArrayIndex(key);
-
-        if (getArray().has(index)) {
-            return true;
-        }
-
-        final FindProperty find = findProperty(JSType.toString(key), false);
-
-        return find != null;
+        return getArray().has(getArrayIndex(key)) || hasProperty(JSType.toString(key), false);
     }
 
     @Override
     public boolean hasOwnProperty(final int key) {
-        final int index = ArrayIndex.getArrayIndex(key);
-
-        if (getArray().has(index)) {
-            return true;
-        }
-
-        final FindProperty find = findProperty(JSType.toString(key), false);
-
-        return find != null;
+        return getArray().has(getArrayIndex(key)) || hasProperty(JSType.toString(key), false);
     }
 
     @Override
     public boolean hasOwnProperty(final long key) {
-        final int index = ArrayIndex.getArrayIndex(key);
-
-        if (getArray().has(index)) {
-            return true;
-        }
-
-        final FindProperty find = findProperty(JSType.toString(key), false);
-
-        return find != null;
+        return getArray().has(getArrayIndex(key)) || hasProperty(JSType.toString(key), false);
     }
 
     @Override
     public boolean hasOwnProperty(final double key) {
-        final int index = ArrayIndex.getArrayIndex(key);
-
-        if (getArray().has(index)) {
-            return true;
-        }
-
-        final FindProperty find = findProperty(JSType.toString(key), false);
-
-        return find != null;
+        return getArray().has(getArrayIndex(key)) || hasProperty(JSType.toString(key), false);
     }
 
     @Override
     public boolean delete(final int key, final boolean strict) {
-        final int index = ArrayIndex.getArrayIndex(key);
+        final int index = getArrayIndex(key);
         final ArrayData array = getArray();
 
         if (array.has(index)) {
@@ -3121,7 +3148,7 @@
 
     @Override
     public boolean delete(final long key, final boolean strict) {
-        final int index = ArrayIndex.getArrayIndex(key);
+        final int index = getArrayIndex(key);
         final ArrayData array = getArray();
 
         if (array.has(index)) {
@@ -3137,7 +3164,7 @@
 
     @Override
     public boolean delete(final double key, final boolean strict) {
-        final int index = ArrayIndex.getArrayIndex(key);
+        final int index = getArrayIndex(key);
         final ArrayData array = getArray();
 
         if (array.has(index)) {
@@ -3153,7 +3180,7 @@
 
     @Override
     public boolean delete(final Object key, final boolean strict) {
-        final int index = ArrayIndex.getArrayIndex(key);
+        final int index = getArrayIndex(key);
         final ArrayData array = getArray();
 
         if (array.has(index)) {
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/script/basic/JDK-8026016.js	Mon Oct 14 11:45:15 2013 +0200
@@ -0,0 +1,68 @@
+/*
+ * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ * 
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ * 
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ * 
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ * 
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/**
+ * JDK-8026016: too many relinks dominate avatar.js http benchmark
+ *
+ * @test
+ * @run
+ */
+
+function accessMegamorphic() {
+    for (var i = 0; i < 26; i++) {
+        var o = {};
+        o[String.fromCharCode(i + 97)] = 1;
+        o._;
+    }
+}
+
+function invokeMegamorphic() {
+    for (var i = 0; i < 26; i++) {
+        var o = {};
+        o[String.fromCharCode(i + 97)] = 1;
+        try {
+            o._(i);
+        } catch (e) {
+            print(e);
+        }
+    }
+}
+
+Object.prototype.__noSuchProperty__ = function() {
+    print("no such property", Array.prototype.slice.call(arguments));
+};
+
+invokeMegamorphic();
+accessMegamorphic();
+
+Object.prototype.__noSuchMethod__ = function() {
+    print("no such method", Array.prototype.slice.call(arguments));
+};
+
+invokeMegamorphic();
+accessMegamorphic();
+
+Object.prototype.__noSuchMethod__ = "nofunction";
+
+invokeMegamorphic();
+accessMegamorphic();
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/script/basic/JDK-8026016.js.EXPECTED	Mon Oct 14 11:45:15 2013 +0200
@@ -0,0 +1,182 @@
+no such property _
+TypeError: Cannot call undefined
+no such property _
+TypeError: Cannot call undefined
+no such property _
+TypeError: Cannot call undefined
+no such property _
+TypeError: Cannot call undefined
+no such property _
+TypeError: Cannot call undefined
+no such property _
+TypeError: Cannot call undefined
+no such property _
+TypeError: Cannot call undefined
+no such property _
+TypeError: Cannot call undefined
+no such property _
+TypeError: Cannot call undefined
+no such property _
+TypeError: Cannot call undefined
+no such property _
+TypeError: Cannot call undefined
+no such property _
+TypeError: Cannot call undefined
+no such property _
+TypeError: Cannot call undefined
+no such property _
+TypeError: Cannot call undefined
+no such property _
+TypeError: Cannot call undefined
+no such property _
+TypeError: Cannot call undefined
+no such property _
+TypeError: Cannot call undefined
+no such property _
+TypeError: Cannot call undefined
+no such property _
+TypeError: Cannot call undefined
+no such property _
+TypeError: Cannot call undefined
+no such property _
+TypeError: Cannot call undefined
+no such property _
+TypeError: Cannot call undefined
+no such property _
+TypeError: Cannot call undefined
+no such property _
+TypeError: Cannot call undefined
+no such property _
+TypeError: Cannot call undefined
+no such property _
+TypeError: Cannot call undefined
+no such property _
+no such property _
+no such property _
+no such property _
+no such property _
+no such property _
+no such property _
+no such property _
+no such property _
+no such property _
+no such property _
+no such property _
+no such property _
+no such property _
+no such property _
+no such property _
+no such property _
+no such property _
+no such property _
+no such property _
+no such property _
+no such property _
+no such property _
+no such property _
+no such property _
+no such property _
+no such method _,0
+no such method _,1
+no such method _,2
+no such method _,3
+no such method _,4
+no such method _,5
+no such method _,6
+no such method _,7
+no such method _,8
+no such method _,9
+no such method _,10
+no such method _,11
+no such method _,12
+no such method _,13
+no such method _,14
+no such method _,15
+no such method _,16
+no such method _,17
+no such method _,18
+no such method _,19
+no such method _,20
+no such method _,21
+no such method _,22
+no such method _,23
+no such method _,24
+no such method _,25
+no such property _
+no such property _
+no such property _
+no such property _
+no such property _
+no such property _
+no such property _
+no such property _
+no such property _
+no such property _
+no such property _
+no such property _
+no such property _
+no such property _
+no such property _
+no such property _
+no such property _
+no such property _
+no such property _
+no such property _
+no such property _
+no such property _
+no such property _
+no such property _
+no such property _
+no such property _
+TypeError: Cannot call undefined
+TypeError: Cannot call undefined
+TypeError: Cannot call undefined
+TypeError: Cannot call undefined
+TypeError: Cannot call undefined
+TypeError: Cannot call undefined
+TypeError: Cannot call undefined
+TypeError: Cannot call undefined
+TypeError: Cannot call undefined
+TypeError: Cannot call undefined
+TypeError: Cannot call undefined
+TypeError: Cannot call undefined
+TypeError: Cannot call undefined
+TypeError: Cannot call undefined
+TypeError: Cannot call undefined
+TypeError: Cannot call undefined
+TypeError: Cannot call undefined
+TypeError: Cannot call undefined
+TypeError: Cannot call undefined
+TypeError: Cannot call undefined
+TypeError: Cannot call undefined
+TypeError: Cannot call undefined
+TypeError: Cannot call undefined
+TypeError: Cannot call undefined
+TypeError: Cannot call undefined
+TypeError: Cannot call undefined
+no such property _
+no such property _
+no such property _
+no such property _
+no such property _
+no such property _
+no such property _
+no such property _
+no such property _
+no such property _
+no such property _
+no such property _
+no such property _
+no such property _
+no such property _
+no such property _
+no such property _
+no such property _
+no such property _
+no such property _
+no such property _
+no such property _
+no such property _
+no such property _
+no such property _
+no such property _