changeset 203:e599a1cad89a

8011578: -Dnashorn.unstable.relink.threshold=1 causes tests to fail. Reviewed-by: sundar, lagergren Contributed-by: james.laskey@oracle.com
author jlaskey
date Sat, 20 Apr 2013 08:54:13 -0300
parents 3a209cbd1d8f
children ead94bc57939
files src/jdk/nashorn/internal/runtime/FindProperty.java src/jdk/nashorn/internal/runtime/ScriptObject.java src/jdk/nashorn/internal/runtime/WithObject.java test/script/basic/JDK-8011578.js test/script/basic/JDK-8011578.js.EXPECTED
diffstat 5 files changed, 203 insertions(+), 254 deletions(-) [+]
line wrap: on
line diff
--- a/src/jdk/nashorn/internal/runtime/FindProperty.java	Fri Apr 19 16:11:16 2013 +0200
+++ b/src/jdk/nashorn/internal/runtime/FindProperty.java	Sat Apr 20 08:54:13 2013 -0300
@@ -105,6 +105,22 @@
     }
 
     /**
+     * Return the appropriate receiver for a getter.
+     * @return appropriate receiver
+     */
+    public ScriptObject getGetterReceiver() {
+        return property != null && property.hasGetterFunction() ? self : prototype;
+    }
+
+   /**
+     * Return the appropriate receiver for a setter.
+     * @return appropriate receiver
+     */
+    public ScriptObject getSetterReceiver() {
+        return property != null && property.hasSetterFunction() ? self : prototype;
+    }
+
+    /**
      * Return the property that was found
      * @return property
      */
--- a/src/jdk/nashorn/internal/runtime/ScriptObject.java	Fri Apr 19 16:11:16 2013 +0200
+++ b/src/jdk/nashorn/internal/runtime/ScriptObject.java	Sat Apr 20 08:54:13 2013 -0300
@@ -901,7 +901,7 @@
         final MethodHandle getter = find.getGetter(int.class);
         if (getter != null) {
             try {
-                return (int)getter.invokeExact((Object)find.getOwner());
+                return (int)getter.invokeExact((Object)find.getGetterReceiver());
             } catch (final Error|RuntimeException e) {
                 throw e;
             } catch (final Throwable e) {
@@ -916,7 +916,7 @@
         final MethodHandle getter = find.getGetter(long.class);
         if (getter != null) {
             try {
-                return (long)getter.invokeExact((Object)find.getOwner());
+                return (long)getter.invokeExact((Object)find.getGetterReceiver());
             } catch (final Error|RuntimeException e) {
                 throw e;
             } catch (final Throwable e) {
@@ -931,7 +931,7 @@
         final MethodHandle getter = find.getGetter(double.class);
         if (getter != null) {
             try {
-                return (double)getter.invokeExact((Object)find.getOwner());
+                return (double)getter.invokeExact((Object)find.getGetterReceiver());
             } catch (final Error|RuntimeException e) {
                 throw e;
             } catch (final Throwable e) {
@@ -953,7 +953,7 @@
         final MethodHandle getter = find.getGetter(Object.class);
         if (getter != null) {
             try {
-                return getter.invokeExact((Object)find.getOwner());
+                return getter.invokeExact((Object)find.getGetterReceiver());
             } catch (final Error|RuntimeException e) {
                 throw e;
             } catch (final Throwable e) {
@@ -1679,12 +1679,7 @@
      * @return GuardedInvocation to be invoked at call site.
      */
     protected GuardedInvocation findGetMethod(final CallSiteDescriptor desc, final LinkRequest request, final String operator) {
-        final String name = desc.getNameToken(2);
-
-        if (request.isCallSiteUnstable()) {
-            return findMegaMorphicGetMethod(desc, name);
-        }
-
+        final String name = desc.getNameToken(CallSiteDescriptor.NAME_OPERAND);
         final FindProperty find = findProperty(name, true);
 
         MethodHandle methodHandle;
@@ -1700,6 +1695,10 @@
             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);
@@ -1727,7 +1726,9 @@
     }
 
     private static GuardedInvocation findMegaMorphicGetMethod(final CallSiteDescriptor desc, final String name) {
-        final GuardedInvocation inv = findGetIndexMethod(desc.getMethodType().insertParameterTypes(1, Object.class));
+        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());
     }
 
@@ -1890,8 +1891,8 @@
     }
 
     private static GuardedInvocation findMegaMorphicSetMethod(final CallSiteDescriptor desc, final String name) {
-        final GuardedInvocation inv = findSetIndexMethod(desc.getMethodType().insertParameterTypes(1, Object.class),
-                NashornCallSiteDescriptor.isStrict(desc));
+        final MethodType type = desc.getMethodType().insertParameterTypes(1, Object.class);
+        final GuardedInvocation inv = findSetIndexMethod(type, NashornCallSiteDescriptor.isStrict(desc)).asType(type);
         return inv.replaceMethods(MH.insertArguments(inv.getInvocation(), 1, name), inv.getGuard());
     }
 
@@ -1949,7 +1950,7 @@
      * @return GuardedInvocation to be invoked at call site.
      */
     public GuardedInvocation noSuchProperty(final CallSiteDescriptor desc, final LinkRequest request) {
-        final String name = desc.getNameToken(2);
+        final String name = desc.getNameToken(CallSiteDescriptor.NAME_OPERAND);
         final FindProperty find = findProperty(NO_SUCH_PROPERTY_NAME, true);
         final boolean scopeAccess = isScope() && NashornCallSiteDescriptor.isScope(desc);
 
@@ -1973,6 +1974,24 @@
 
         return createEmptyGetter(desc, name);
     }
+    /**
+     * Invoke fall back if a property is not found.
+     * @param name Name of property.
+     * @return Result from call.
+     */
+    private Object invokeNoSuchProperty(final String name) {
+        final FindProperty find = findProperty(NO_SUCH_PROPERTY_NAME, true);
+
+        if (find != null) {
+            final Object func = getObjectValue(find);
+
+            if (func instanceof ScriptFunction) {
+                return ScriptRuntime.apply((ScriptFunction)func, this, name);
+            }
+        }
+
+        return UNDEFINED;
+    }
 
     private GuardedInvocation createEmptyGetter(final CallSiteDescriptor desc, final String name) {
         return new GuardedInvocation(Lookup.emptyGetter(desc.getMethodType().returnType()), getMap().getProtoGetSwitchPoint(name), NashornGuards.getMapGuard(getMap()));
@@ -2239,310 +2258,158 @@
            setArray(getArray().shrink(newLength));
            getArray().setLength(newLength);
        }
-   }
+    }
+
+    private int getInt(final int index, final String key) {
+        for (ScriptObject object = this; object != null; object = object.getProto()) {
+            final ArrayData array = object.getArray();
+
+            if (array.has(index)) {
+                return array.getInt(index);
+            }
+
+            final FindProperty find = object.findProperty(key, false);
+
+            if (find != null) {
+                return getIntValue(new FindProperty(this, find.getOwner(), find.getProperty()));
+            }
+        }
+
+        return JSType.toInt32(invokeNoSuchProperty(key));
+    }
 
     @Override
     public int getInt(final Object key) {
-        final int index = getArrayIndexNoThrow(key);
-
-        if (getArray().has(index)) {
-            return getArray().getInt(index);
-        }
-
-        final FindProperty find = findProperty(convertKey(key), false);
-
-        if (find != null) {
-            return getIntValue(find);
-        }
-
-        final ScriptObject proto = this.getProto();
-
-        return proto != null ? proto.getInt(key) : 0;
+        return getInt(getArrayIndexNoThrow(key), convertKey(key));
     }
 
     @Override
     public int getInt(final double key) {
-        final int index = getArrayIndexNoThrow(key);
-
-        if (getArray().has(index)) {
-            return getArray().getInt(index);
-        }
-
-        final FindProperty find = findProperty(convertKey(key), false);
-
-        if (find != null) {
-            return getIntValue(find);
-        }
-
-        final ScriptObject proto = this.getProto();
-
-        return proto != null ? proto.getInt(key) : 0;
+        return getInt(getArrayIndexNoThrow(key), convertKey(key));
     }
 
     @Override
     public int getInt(final long key) {
-        final int index = getArrayIndexNoThrow(key);
-
-        if (getArray().has(index)) {
-            return getArray().getInt(index);
-        }
-
-        final FindProperty find = findProperty(convertKey(key), false);
-
-        if (find != null) {
-            return getIntValue(find);
-        }
-
-        final ScriptObject proto = this.getProto();
-
-        return proto != null ? proto.getInt(key) : 0;
+        return getInt(getArrayIndexNoThrow(key), convertKey(key));
     }
 
     @Override
     public int getInt(final int key) {
-        final int index = getArrayIndexNoThrow(key);
-
-        if (getArray().has(index)) {
-            return getArray().getInt(index);
+        return getInt(getArrayIndexNoThrow(key), convertKey(key));
+    }
+
+    private long getLong(final int index, final String key) {
+        for (ScriptObject object = this; object != null; object = object.getProto()) {
+            final ArrayData array = object.getArray();
+
+            if (array.has(index)) {
+                return array.getLong(index);
+            }
+
+            final FindProperty find = object.findProperty(key, false);
+
+            if (find != null) {
+                return getLongValue(new FindProperty(this, find.getOwner(), find.getProperty()));
+            }
         }
 
-        final FindProperty find = findProperty(convertKey(key), false);
-
-        if (find != null) {
-            return getIntValue(find);
-        }
-
-        final ScriptObject proto = this.getProto();
-
-        return proto != null ? proto.getInt(key) : 0;
+        return JSType.toLong(invokeNoSuchProperty(key));
     }
 
     @Override
     public long getLong(final Object key) {
-        final int index = getArrayIndexNoThrow(key);
-
-        if (getArray().has(index)) {
-            return getArray().getLong(index);
-        }
-
-        final FindProperty find = findProperty(convertKey(key), false);
-
-        if (find != null) {
-            return getLongValue(find);
-        }
-
-        final ScriptObject proto = this.getProto();
-
-        return proto != null ? proto.getLong(key) : 0L;
+        return getLong(getArrayIndexNoThrow(key), convertKey(key));
     }
 
     @Override
     public long getLong(final double key) {
-        final int index = getArrayIndexNoThrow(key);
-
-        if (getArray().has(index)) {
-            return getArray().getLong(index);
-        }
-
-        final FindProperty find = findProperty(convertKey(key), false);
-
-        if (find != null) {
-            return getLongValue(find);
-        }
-
-        final ScriptObject proto = this.getProto();
-
-        return proto != null ? proto.getLong(key) : 0L;
+        return getLong(getArrayIndexNoThrow(key), convertKey(key));
     }
 
     @Override
     public long getLong(final long key) {
-        final int index = getArrayIndexNoThrow(key);
-
-        if (getArray().has(index)) {
-            return getArray().getLong(index);
-        }
-
-        final FindProperty find = findProperty(convertKey(key), false);
-
-        if (find != null) {
-            return getLongValue(find);
-        }
-
-        final ScriptObject proto = this.getProto();
-
-        return proto != null ? proto.getLong(key) : 0L;
+        return getLong(getArrayIndexNoThrow(key), convertKey(key));
     }
 
     @Override
     public long getLong(final int key) {
-        final int index = getArrayIndexNoThrow(key);
-
-        if (getArray().has(index)) {
-            return getArray().getLong(index);
+        return getLong(getArrayIndexNoThrow(key), convertKey(key));
+    }
+
+    private double getDouble(final int index, final String key) {
+        for (ScriptObject object = this; object != null; object = object.getProto()) {
+            final ArrayData array = object.getArray();
+
+            if (array.has(index)) {
+                return array.getDouble(index);
+            }
+
+            final FindProperty find = object.findProperty(key, false);
+
+            if (find != null) {
+                return getDoubleValue(new FindProperty(this, find.getOwner(), find.getProperty()));
+            }
         }
 
-        final FindProperty find = findProperty(convertKey(key), false);
-
-        if (find != null) {
-            return getLongValue(find);
-        }
-
-        final ScriptObject proto = this.getProto();
-
-        return proto != null ? proto.getLong(key) : 0L;
+        return JSType.toNumber(invokeNoSuchProperty(key));
     }
 
     @Override
     public double getDouble(final Object key) {
-        final int index = getArrayIndexNoThrow(key);
-
-        if (getArray().has(index)) {
-            return getArray().getDouble(index);
-        }
-
-        final FindProperty find = findProperty(convertKey(key), false);
-
-        if (find != null) {
-            return getDoubleValue(find);
-        }
-
-        final ScriptObject proto = this.getProto();
-
-        return proto != null ? proto.getDouble(key) : Double.NaN;
+        return getDouble(getArrayIndexNoThrow(key), convertKey(key));
     }
 
     @Override
     public double getDouble(final double key) {
-        final int index = getArrayIndexNoThrow(key);
-
-        if (getArray().has(index)) {
-            return getArray().getDouble(index);
-        }
-
-        final FindProperty find = findProperty(convertKey(key), false);
-
-        if (find != null) {
-            return getDoubleValue(find);
-        }
-
-        final ScriptObject proto = this.getProto();
-
-        return proto != null ? proto.getDouble(key) : Double.NaN;
+        return getDouble(getArrayIndexNoThrow(key), convertKey(key));
     }
 
     @Override
     public double getDouble(final long key) {
-        final int index = getArrayIndexNoThrow(key);
-
-        if (getArray().has(index)) {
-            return getArray().getDouble(index);
-        }
-
-        final FindProperty find = findProperty(convertKey(key), false);
-
-        if (find != null) {
-            return getDoubleValue(find);
-        }
-
-        final ScriptObject proto = this.getProto();
-
-        return proto != null ? proto.getDouble(key) : Double.NaN;
+        return getDouble(getArrayIndexNoThrow(key), convertKey(key));
     }
 
     @Override
     public double getDouble(final int key) {
-        final int index = getArrayIndexNoThrow(key);
-
-        if (getArray().has(index)) {
-            return getArray().getDouble(index);
+        return getDouble(getArrayIndexNoThrow(key), convertKey(key));
+    }
+
+    private Object get(final int index, final String key) {
+        for (ScriptObject object = this; object != null; object = object.getProto()) {
+            final ArrayData array = object.getArray();
+
+            if (array.has(index)) {
+                return array.getObject(index);
+            }
+
+            final FindProperty find = object.findProperty(key, false);
+
+            if (find != null) {
+                return getObjectValue(new FindProperty(this, find.getOwner(), find.getProperty()));
+            }
         }
 
-        final FindProperty find = findProperty(convertKey(key), false);
-
-        if (find != null) {
-            return getDoubleValue(find);
-        }
-
-        final ScriptObject proto = this.getProto();
-
-        return proto != null ? proto.getDouble(key) : Double.NaN;
+        return invokeNoSuchProperty(key);
     }
 
     @Override
     public Object get(final Object key) {
-        final int index = getArrayIndexNoThrow(key);
-
-        if (getArray().has(index)) {
-            return getArray().getObject(index);
-        }
-
-        final FindProperty find = findProperty(convertKey(key), false);
-
-        if (find != null) {
-            return getObjectValue(find);
-        }
-
-        final ScriptObject proto = this.getProto();
-
-        return proto != null ? proto.get(key) : UNDEFINED;
+        return get(getArrayIndexNoThrow(key), convertKey(key));
     }
 
     @Override
     public Object get(final double key) {
-        final int index = getArrayIndexNoThrow(key);
-
-        if (getArray().has(index)) {
-            return getArray().getObject(index);
-        }
-
-        final FindProperty find = findProperty(convertKey(key), false);
-
-        if (find != null) {
-            return getObjectValue(find);
-        }
-
-        final ScriptObject proto = this.getProto();
-
-        return proto != null ? proto.get(key) : UNDEFINED;
+        return get(getArrayIndexNoThrow(key), convertKey(key));
     }
 
     @Override
     public Object get(final long key) {
-        final int index = getArrayIndexNoThrow(key);
-
-        if (getArray().has(index)) {
-            return getArray().getObject(index);
-        }
-
-        final FindProperty find = findProperty(convertKey(key), false);
-
-        if (find != null) {
-            return getObjectValue(find);
-        }
-
-        final ScriptObject proto = this.getProto();
-
-        return proto != null ? proto.get(key) : UNDEFINED;
+        return get(getArrayIndexNoThrow(key), convertKey(key));
     }
 
     @Override
     public Object get(final int key) {
-        final int index = getArrayIndexNoThrow(key);
-
-        if (getArray().has(index)) {
-            return getArray().getObject(index);
-        }
-
-        final FindProperty find = findProperty(convertKey(key), false);
-
-        if (find != null) {
-            return getObjectValue(find);
-        }
-
-        final ScriptObject proto = this.getProto();
-
-        return proto != null ? proto.get(key) : UNDEFINED;
+        return get(getArrayIndexNoThrow(key), convertKey(key));
     }
 
     /**
@@ -2613,8 +2480,6 @@
             f = null;
         }
 
-        MethodHandle setter;
-
         if (f != null) {
             if (!f.getProperty().isWritable()) {
                 if (strict) {
@@ -2624,9 +2489,9 @@
                 return;
             }
 
-            setter = f.getSetter(Object.class, strict); //TODO specfields
             try {
-                setter.invokeExact((Object)f.getOwner(), value);
+                final MethodHandle setter = f.getSetter(Object.class, strict); //TODO specfields
+                setter.invokeExact((Object)f.getSetterReceiver(), value);
             } catch (final Error|RuntimeException e) {
                 throw e;
             } catch (final Throwable e) {
--- a/src/jdk/nashorn/internal/runtime/WithObject.java	Fri Apr 19 16:11:16 2013 +0200
+++ b/src/jdk/nashorn/internal/runtime/WithObject.java	Sat Apr 20 08:54:13 2013 -0300
@@ -252,7 +252,11 @@
     }
 
     private static GuardedInvocation fixScopeCallSite(final GuardedInvocation link) {
-        return link.replaceMethods(filter(link.getInvocation(), WITHSCOPEFILTER), filterGuard(link, WITHSCOPEFILTER));
+        // The receiver may be an object or a ScriptObject.
+        final MethodType invType = link.getInvocation().type();
+        final MethodType newInvType = invType.changeParameterType(0, WITHSCOPEFILTER.type().returnType());
+        final GuardedInvocation newLink = link.asType(newInvType);
+        return link.replaceMethods(filter(newLink.getInvocation(), WITHSCOPEFILTER), filterGuard(newLink, WITHSCOPEFILTER));
     }
 
     private static MethodHandle filterGuard(final GuardedInvocation link, final MethodHandle filter) {
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/script/basic/JDK-8011578.js	Sat Apr 20 08:54:13 2013 -0300
@@ -0,0 +1,42 @@
+/*
+ * 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-8011578 : -Dnashorn.unstable.relink.threshold=1 causes tests to fail.
+ *
+ * @test
+ * @option -Dnashorn.unstable.relink.threshold=1
+ * @run
+ */
+
+load(__DIR__ + "NASHORN-296.js");
+load(__DIR__ + "NASHORN-691.js");
+load(__DIR__ + "calllink.js");
+load(__DIR__ + "nosuchproperty.js");
+
+__noSuchProperty__ = function(x) {
+    print(x);
+    return x;
+}
+
+print(this["find"]);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/script/basic/JDK-8011578.js.EXPECTED	Sat Apr 20 08:54:13 2013 -0300
@@ -0,0 +1,22 @@
+o.foo = 33
+o.foo = 44
+o.foo = 3
+o.foo = hello
+obj1.func called
+obj2.func called
+no such method: func
+obj4's prototype func called
+MyConstructor.prototype.func
+MyConstructor.prototype.func
+obj1.func called
+obj2.func called
+new obj3.func called
+new obj4.func called
+all new MyConstructor.prototype.func
+all new MyConstructor.prototype.func
+obj.__noSuchProperty__ for foo
+new obj.__noSuchProperty__ for foo
+proto.__noSuchProperty__ for foo
+new proto.__noSuchProperty__ for foo
+find
+find