8136694: Megemorphic scope access does not throw ReferenceError when property is missing
authorsundar
Thu, 17 Sep 2015 18:23:53 +0530 (2015-09-17)
changeset 32698 927e0fd20492
parent 32697 d8416054e691
child 32699 4bd8ea2059a1
8136694: Megemorphic scope access does not throw ReferenceError when property is missing Reviewed-by: attila, hannesw
nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/ScriptObject.java
nashorn/test/script/basic/JDK-8044750.js
nashorn/test/script/basic/JDK-8136694.js
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/ScriptObject.java	Wed Sep 16 18:44:47 2015 +0200
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/ScriptObject.java	Thu Sep 17 18:23:53 2015 +0530
@@ -2402,17 +2402,15 @@
      */
     protected Object invokeNoSuchProperty(final String name, final boolean isScope, final int programPoint) {
         final FindProperty find = findProperty(NO_SUCH_PROPERTY_NAME, true);
+        final Object func = (find != null)? find.getObjectValue() : null;
 
         Object ret = UNDEFINED;
-
-        if (find != null) {
-            final Object func = find.getObjectValue();
-
-            if (func instanceof ScriptFunction) {
-                final ScriptFunction sfunc = (ScriptFunction)func;
-                final Object self = isScope && sfunc.isStrict()? UNDEFINED : this;
-                ret = ScriptRuntime.apply(sfunc, self, name);
-            }
+        if (func instanceof ScriptFunction) {
+            final ScriptFunction sfunc = (ScriptFunction)func;
+            final Object self = isScope && sfunc.isStrict()? UNDEFINED : this;
+            ret = ScriptRuntime.apply(sfunc, self, name);
+        } else if (isScope) {
+            throw referenceError("not.defined", name);
         }
 
         if (isValid(programPoint)) {
@@ -2438,6 +2436,9 @@
 
         final Object value = find.getObjectValue();
         if (!(value instanceof ScriptFunction)) {
+            if (isScope) {
+                throw referenceError("not.defined", name);
+            }
             return UNDEFINED;
         }
 
--- a/nashorn/test/script/basic/JDK-8044750.js	Wed Sep 16 18:44:47 2015 +0200
+++ b/nashorn/test/script/basic/JDK-8044750.js	Thu Sep 17 18:23:53 2015 +0530
@@ -25,6 +25,8 @@
  * JDK-8044750: megamorphic getter for scope objects does not call __noSuchProperty__ hook
  *
  * @test
+ * @fork
+ * @option -Dnashorn.unstable.relink.threshold=16
  * @run
  */
 
@@ -40,7 +42,9 @@
     }
 }
 
-for (var i = 0; i < 20; i++) {
+var LIMIT = 20; // should be more than megamorphic threshold set via @option
+
+for (var i = 0; i < LIMIT; i++) {
     var obj = {};
     obj.foo = i;
     obj[i] = i;
@@ -51,3 +55,30 @@
 // callsite inside func should see __noSuchProperty__
 // hook on global scope object.
 func({});
+
+function checkFoo() {
+    with({}) {
+        try {
+            foo;
+            return true;
+        } catch (e) {
+            return false;
+        }
+    }
+}
+
+var oldNoSuchProperty = this.__noSuchProperty__;
+delete this.__noSuchProperty__;
+
+// keep deleting/restorting __noSuchProperty__ alternatively
+// to make "foo" access in checkFoo function megamorphic!
+
+for (var i = 0; i < LIMIT; i++) {
+    // no __noSuchProperty__ and 'with' scope object has no 'foo'
+    delete __noSuchProperty__;
+    Assert.assertFalse(checkFoo(), "Expected false in iteration " + i);
+
+    // __noSuchProperty__ is exists but 'with' scope object has no 'foo'
+    this.__noSuchProperty__ = oldNoSuchProperty;
+    Assert.assertTrue(checkFoo(), "Expected true in iteration " + i);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/script/basic/JDK-8136694.js	Thu Sep 17 18:23:53 2015 +0530
@@ -0,0 +1,74 @@
+/*
+ * Copyright (c) 2015, 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-8136694: Megemorphic scope access does not throw ReferenceError when property is missing
+ *
+ * @test
+ * @fork
+ * @option -Dnashorn.unstable.relink.threshold=16
+ * @run
+ */
+
+function checkFoo() {
+    try {
+        // The 'foo' access becomes megamorphic
+        foo;
+        return true;
+    } catch (e) {
+        return false;
+    }
+}
+
+
+// Similar check for 'with' blocks as well.
+function checkFooInWith() {
+    with({}) {
+        try {
+            // The 'foo' access becomes megamorphic
+            foo;
+            return true;
+        } catch (e) {
+            return false;
+        }
+    }
+}
+
+function loop(checker) {
+    // LIMIT has to be more than the megamorphic threashold
+    // set via @option in this test header!
+    var LIMIT = 20;
+    for (var i = 0; i < LIMIT; i++) {
+        // make sure global has no "foo"
+        delete foo;
+        Assert.assertFalse(checker(), "Expected false in interation " + i);
+
+        // now add 'foo' in global
+        foo = 44;
+        Assert.assertTrue(checker(), "Expected true in interation " + i);
+    }
+}
+
+
+loop(checkFoo);
+loop(checkFooInWith);