From 1e6e9dc0c6f6815196453949fd4958ca07b94b88 Mon Sep 17 00:00:00 2001 From: Athijegannathan Sundararajan Date: Wed, 3 Jul 2013 19:20:29 +0530 Subject: [PATCH 1/4] 8019814: Add regression test for passing cases Reviewed-by: jlaskey, lagergren --- .../nashorn/internal/runtime/ListAdapter.java | 25 +++++++ nashorn/test/script/basic/JDK-8019814.js | 73 +++++++++++++++++++ .../test/script/basic/JDK-8019814.js.EXPECTED | 6 ++ 3 files changed, 104 insertions(+) create mode 100644 nashorn/test/script/basic/JDK-8019814.js create mode 100644 nashorn/test/script/basic/JDK-8019814.js.EXPECTED diff --git a/nashorn/src/jdk/nashorn/internal/runtime/ListAdapter.java b/nashorn/src/jdk/nashorn/internal/runtime/ListAdapter.java index 428cb555fb0..194bd132000 100644 --- a/nashorn/src/jdk/nashorn/internal/runtime/ListAdapter.java +++ b/nashorn/src/jdk/nashorn/internal/runtime/ListAdapter.java @@ -1,3 +1,28 @@ +/* + * 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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * 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. + */ + package jdk.nashorn.internal.runtime; import java.util.AbstractList; diff --git a/nashorn/test/script/basic/JDK-8019814.js b/nashorn/test/script/basic/JDK-8019814.js new file mode 100644 index 00000000000..24abf53b77e --- /dev/null +++ b/nashorn/test/script/basic/JDK-8019814.js @@ -0,0 +1,73 @@ +/* + * 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-8019814: Add regression test for passing cases + * + * @test + * @run + */ + +// java.lang.VerifyError: Bad type on operand stack +Function("switch([]) { case 7: }"); + +// java.lang.AssertionError: expecting integer type or object for jump, but found double +Function("with(\nnull == (this % {}))( /x/g );"); + +// java.lang.AssertionError: expecting equivalent types on stack but got double and int +try { + eval('Function("/*infloop*/while(((function ()4.)([z1,,], [,,]) - true++))switch(1e+81.x) { default: break; \u0009 }")'); +} catch (e) { + print(e.toString().replace(/\\/g, '/')); +} + +// java.lang.VerifyError: get long/double overflows locals +Function("var x = x -= '' "); + +// java.lang.AssertionError: object is not compatible with boolean +Function("return (null != [,,] <= this);"); + +// java.lang.AssertionError: Only return value on stack allowed at return point +// - depth=2 stack = jdk.nashorn.internal.codegen.Label$Stack@4bd0d62f +Function("x = 0.1, x\ntrue\n~this"); + +// java.lang.AssertionError: node NaN ~ window class jdk.nashorn.internal.ir.BinaryNode +// has no symbol! [object] function _L1() +Function("throw NaN\n~window;"); + +// java.lang.AssertionError: array element type doesn't match array type +Function("if(([(this >>> 4.)].map(gc))) x;"); + +try { + eval('Function("if(--) y;")'); +} catch (e) { + print(e.toString().replace(/\\/g, '/')); +} + +// java.lang.AssertionError: stacks jdk.nashorn.internal.codegen.Label$Stack@4918f90f +// is not equivalent with jdk.nashorn.internal.codegen.Label$Stack@5f9b21a1 at join point +Function("if((null ^ [1]) !== (this.yoyo(false))) {var NaN, x;x\n~[,,z1] }"); + +// java.lang.AssertionError +// at jdk.nashorn.internal.codegen.Attr.enterFunctionBody(Attr.java:276) +Function("return (void ({ set each (x2)y }));"); diff --git a/nashorn/test/script/basic/JDK-8019814.js.EXPECTED b/nashorn/test/script/basic/JDK-8019814.js.EXPECTED new file mode 100644 index 00000000000..51db7b5e953 --- /dev/null +++ b/nashorn/test/script/basic/JDK-8019814.js.EXPECTED @@ -0,0 +1,6 @@ +ReferenceError: :1:50 Invalid left hand side for assignment +/*infloop*/while(((function ()4.)([z1,,], [,,]) - true++))switch(1e+81.x) { default: break; } + ^ +SyntaxError: :1:5 Expected l-value but found ) +if(--) y; + ^ From 75501c69930ef905a0ea2997e29a2c3a978b09c1 Mon Sep 17 00:00:00 2001 From: Attila Szegedi Date: Wed, 3 Jul 2013 18:10:12 +0200 Subject: [PATCH 2/4] 8017768: allow dot as inner class name separator for Java.type Reviewed-by: jlaskey, sundar --- .../docs/JavaScriptingProgrammersGuide.html | 9 +++- .../nashorn/internal/objects/NativeJava.java | 45 +++++++++++++++++-- nashorn/test/script/basic/JDK-8017768.js | 35 +++++++++++++++ .../test/script/basic/JDK-8017768.js.EXPECTED | 4 ++ .../jdk/nashorn/test/models/OuterClass.java | 4 ++ 5 files changed, 91 insertions(+), 6 deletions(-) create mode 100644 nashorn/test/script/basic/JDK-8017768.js create mode 100644 nashorn/test/script/basic/JDK-8017768.js.EXPECTED diff --git a/nashorn/docs/JavaScriptingProgrammersGuide.html b/nashorn/docs/JavaScriptingProgrammersGuide.html index 18ae823d82e..dd74d74903e 100644 --- a/nashorn/docs/JavaScriptingProgrammersGuide.html +++ b/nashorn/docs/JavaScriptingProgrammersGuide.html @@ -501,14 +501,19 @@ or var anArrayListWithSize = new ArrayList(16) -In the special case of inner classes, you need to use the JVM fully qualified name, meaning using $ sign in the class name: +In the special case of inner classes, you can either use the JVM fully qualified name, meaning using the dollar sign in the class name, or you can use the dot:

  var ftype = Java.type("java.awt.geom.Arc2D$Float")
 
+and + +

+ var ftype = Java.type("java.awt.geom.Arc2D.Float")
+
-However, once you retrieved the outer class, you can access the inner class as a property on it: +both work. Note however that using the dollar sign is faster, as Java.type first tries to resolve the class name as it is originally specified, and the internal JVM names for inner classes use the dollar sign. If you use the dot, Java.type will internally get a ClassNotFoundException and subsequently retry by changing the last dot to dollar sign. As a matter of fact, it'll keep replacing dots with dollar signs until it either successfully loads the class or runs out of all dots in the name. This way it can correctly resolve and load even multiply nested inner classes with the dot notation. Again, this will be slower than using the dollar signs in the name. An alternative way to access the inner class is as a property of the outer class:

  var arctype = Java.type("java.awt.geom.Arc2D")
diff --git a/nashorn/src/jdk/nashorn/internal/objects/NativeJava.java b/nashorn/src/jdk/nashorn/internal/objects/NativeJava.java
index 288770b45ef..8303c39367a 100644
--- a/nashorn/src/jdk/nashorn/internal/objects/NativeJava.java
+++ b/nashorn/src/jdk/nashorn/internal/objects/NativeJava.java
@@ -39,6 +39,7 @@ import jdk.nashorn.internal.objects.annotations.Attribute;
 import jdk.nashorn.internal.objects.annotations.Function;
 import jdk.nashorn.internal.objects.annotations.ScriptClass;
 import jdk.nashorn.internal.objects.annotations.Where;
+import jdk.nashorn.internal.runtime.Context;
 import jdk.nashorn.internal.runtime.JSType;
 import jdk.nashorn.internal.runtime.ListAdapter;
 import jdk.nashorn.internal.runtime.PropertyMap;
@@ -105,12 +106,22 @@ public final class NativeJava {
      * var anArrayList = new ArrayList
      * var anArrayListWithSize = new ArrayList(16)
      * 
- * In the special case of inner classes, you need to use the JVM fully qualified name, meaning using {@code $} sign - * in the class name: + * In the special case of inner classes, you can either use the JVM fully qualified name, meaning using {@code $} + * sign in the class name, or you can use the dot: *
      * var ftype = Java.type("java.awt.geom.Arc2D$Float")
      * 
- * However, once you retrieved the outer class, you can access the inner class as a property on it: + * and + *
+     * var ftype = Java.type("java.awt.geom.Arc2D.Float")
+     * 
+ * both work. Note however that using the dollar sign is faster, as Java.type first tries to resolve the class name + * as it is originally specified, and the internal JVM names for inner classes use the dollar sign. If you use the + * dot, Java.type will internally get a ClassNotFoundException and subsequently retry by changing the last dot to + * dollar sign. As a matter of fact, it'll keep replacing dots with dollar signs until it either successfully loads + * the class or runs out of all dots in the name. This way it can correctly resolve and load even multiply nested + * inner classes with the dot notation. Again, this will be slower than using the dollar signs in the name. An + * alternative way to access the inner class is as a property of the outer class: *
      * var arctype = Java.type("java.awt.geom.Arc2D")
      * var ftype = arctype.Float
@@ -390,7 +401,33 @@ public final class NativeJava {
 
     private static Class simpleType(final String typeName) throws ClassNotFoundException {
         final Class primClass = TypeUtilities.getPrimitiveTypeByName(typeName);
-        return primClass != null ? primClass : Global.getThisContext().findClass(typeName);
+        if(primClass != null) {
+            return primClass;
+        }
+        final Context ctx = Global.getThisContext();
+        try {
+            return ctx.findClass(typeName);
+        } catch(ClassNotFoundException e) {
+            // The logic below compensates for a frequent user error - when people use dot notation to separate inner
+            // class names, i.e. "java.lang.Character.UnicodeBlock" vs."java.lang.Character$UnicodeBlock". The logic
+            // below will try alternative class names, replacing dots at the end of the name with dollar signs.
+            final StringBuilder nextName = new StringBuilder(typeName);
+            int lastDot = nextName.length();
+            for(;;) {
+                lastDot = nextName.lastIndexOf(".", lastDot - 1);
+                if(lastDot == -1) {
+                    // Exhausted the search space, class not found - rethrow the original exception.
+                    throw e;
+                }
+                nextName.setCharAt(lastDot, '$');
+                try {
+                    return ctx.findClass(nextName.toString());
+                } catch(ClassNotFoundException cnfe) {
+                    // Intentionally ignored, so the loop retries with the next name
+                }
+            }
+        }
+
     }
 
     private static Class arrayType(final String typeName) throws ClassNotFoundException {
diff --git a/nashorn/test/script/basic/JDK-8017768.js b/nashorn/test/script/basic/JDK-8017768.js
new file mode 100644
index 00000000000..c91f6d1f74a
--- /dev/null
+++ b/nashorn/test/script/basic/JDK-8017768.js
@@ -0,0 +1,35 @@
+/*
+ * 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-8017768: Allow use of dot notation for inner class names.
+ * 
+ * @test
+ * @run
+ */
+
+print(Java.type("java.awt.geom.Arc2D.Float") === Java.type("java.awt.geom.Arc2D$Float"))
+var iisc = Java.type("jdk.nashorn.test.models.OuterClass$InnerStaticClass$InnerInnerStaticClass")
+print(Java.type("jdk.nashorn.test.models.OuterClass.InnerStaticClass.InnerInnerStaticClass") === iisc)
+print(Java.type("jdk.nashorn.test.models.OuterClass$InnerStaticClass.InnerInnerStaticClass") === iisc)
+print(Java.type("jdk.nashorn.test.models.OuterClass.InnerStaticClass$InnerInnerStaticClass") === iisc)
diff --git a/nashorn/test/script/basic/JDK-8017768.js.EXPECTED b/nashorn/test/script/basic/JDK-8017768.js.EXPECTED
new file mode 100644
index 00000000000..1140ff52e2b
--- /dev/null
+++ b/nashorn/test/script/basic/JDK-8017768.js.EXPECTED
@@ -0,0 +1,4 @@
+true
+true
+true
+true
diff --git a/nashorn/test/src/jdk/nashorn/test/models/OuterClass.java b/nashorn/test/src/jdk/nashorn/test/models/OuterClass.java
index 5db86f28c1b..fc280f65734 100644
--- a/nashorn/test/src/jdk/nashorn/test/models/OuterClass.java
+++ b/nashorn/test/src/jdk/nashorn/test/models/OuterClass.java
@@ -33,6 +33,10 @@ public class OuterClass {
     }
 
     public static class InnerStaticClass {
+
+        public static class InnerInnerStaticClass {
+        }
+
         private final String value;
 
         public InnerStaticClass(String value) {

From 8ebb701354d6b1eca995cceba78eb0b36b17de5e Mon Sep 17 00:00:00 2001
From: James Laskey 
Date: Wed, 3 Jul 2013 13:41:18 -0300
Subject: [PATCH 3/4] 8011629: Object.defineProperty performance issue

Reviewed-by: sundar, attila
---
 .../internal/runtime/AccessorProperty.java    | 55 ++++++++++---------
 1 file changed, 30 insertions(+), 25 deletions(-)

diff --git a/nashorn/src/jdk/nashorn/internal/runtime/AccessorProperty.java b/nashorn/src/jdk/nashorn/internal/runtime/AccessorProperty.java
index bfdfa71995d..1144eb630bd 100644
--- a/nashorn/src/jdk/nashorn/internal/runtime/AccessorProperty.java
+++ b/nashorn/src/jdk/nashorn/internal/runtime/AccessorProperty.java
@@ -75,6 +75,8 @@ public class AccessorProperty extends Property {
 
     private static final MethodType[] ACCESSOR_GETTER_TYPES = new MethodType[NOOF_TYPES];
     private static final MethodType[] ACCESSOR_SETTER_TYPES = new MethodType[NOOF_TYPES];
+    private static final MethodType ACCESSOR_GETTER_PRIMITIVE_TYPE;
+    private static final MethodType ACCESSOR_SETTER_PRIMITIVE_TYPE;
     private static final MethodHandle SPILL_ELEMENT_GETTER;
     private static final MethodHandle SPILL_ELEMENT_SETTER;
 
@@ -82,13 +84,25 @@ public class AccessorProperty extends Property {
     private static final MethodHandle[] SPILL_ACCESSORS = new MethodHandle[SPILL_CACHE_SIZE * 2];
 
     static {
+        MethodType getterPrimitiveType = null;
+        MethodType setterPrimitiveType = null;
+
         for (int i = 0; i < NOOF_TYPES; i++) {
             final Type type = ACCESSOR_TYPES.get(i);
             ACCESSOR_GETTER_TYPES[i] = MH.type(type.getTypeClass(), Object.class);
             ACCESSOR_SETTER_TYPES[i] = MH.type(void.class, Object.class, type.getTypeClass());
+
+            if (type == PRIMITIVE_TYPE) {
+                getterPrimitiveType = ACCESSOR_GETTER_TYPES[i];
+                setterPrimitiveType = ACCESSOR_SETTER_TYPES[i];
+            }
         }
 
-        final MethodHandle spillGetter = MH.getter(MethodHandles.lookup(), ScriptObject.class, "spill", Object[].class);
+        ACCESSOR_GETTER_PRIMITIVE_TYPE = getterPrimitiveType;
+        ACCESSOR_SETTER_PRIMITIVE_TYPE = setterPrimitiveType;
+
+        final MethodType spillGetterType = MethodType.methodType(Object[].class, Object.class);
+        final MethodHandle spillGetter = MH.asType(MH.getter(MethodHandles.lookup(), ScriptObject.class, "spill", Object[].class), spillGetterType);
         SPILL_ELEMENT_GETTER = MH.filterArguments(MH.arrayElementGetter(Object[].class), 0, spillGetter);
         SPILL_ELEMENT_SETTER = MH.filterArguments(MH.arrayElementSetter(Object[].class), 0, spillGetter);
     }
@@ -177,9 +191,8 @@ public class AccessorProperty extends Property {
                     ACCESSOR_GETTER_TYPES[i]);
             }
         } else {
-            //this will work as the object setter and getter will be converted appropriately
-            objectGetter = getter;
-            objectSetter = setter;
+            objectGetter = getter.type() != Lookup.GET_OBJECT_TYPE ? MH.asType(getter, Lookup.GET_OBJECT_TYPE) : getter;
+            objectSetter = setter != null && setter.type() != Lookup.SET_OBJECT_TYPE ? MH.asType(setter, Lookup.SET_OBJECT_TYPE) : setter;
         }
 
         setCurrentType(getterType);
@@ -195,8 +208,8 @@ public class AccessorProperty extends Property {
             setters = new MethodHandle[fieldCount];
             for(int i = 0; i < fieldCount; ++i) {
                 final String fieldName = ObjectClassGenerator.getFieldName(i, Type.OBJECT);
-                getters[i] = MH.getter(lookup, structure, fieldName, Type.OBJECT.getTypeClass());
-                setters[i] = MH.setter(lookup, structure, fieldName, Type.OBJECT.getTypeClass());
+                getters[i] = MH.asType(MH.getter(lookup, structure, fieldName, Type.OBJECT.getTypeClass()), Lookup.GET_OBJECT_TYPE);
+                setters[i] = MH.asType(MH.setter(lookup, structure, fieldName, Type.OBJECT.getTypeClass()), Lookup.SET_OBJECT_TYPE);
             }
         }
     }
@@ -224,17 +237,18 @@ public class AccessorProperty extends Property {
             final MethodHandle arguments   = MH.getter(lookup, structure, "arguments", Object.class);
             final MethodHandle argumentsSO = MH.asType(arguments, arguments.type().changeReturnType(ScriptObject.class));
 
-            objectGetter = MH.insertArguments(MH.filterArguments(ScriptObject.GET_ARGUMENT.methodHandle(), 0, argumentsSO), 1, slot);
-            objectSetter = MH.insertArguments(MH.filterArguments(ScriptObject.SET_ARGUMENT.methodHandle(), 0, argumentsSO), 1, slot);
+            objectGetter = MH.asType(MH.insertArguments(MH.filterArguments(ScriptObject.GET_ARGUMENT.methodHandle(), 0, argumentsSO), 1, slot), Lookup.GET_OBJECT_TYPE);
+            objectSetter = MH.asType(MH.insertArguments(MH.filterArguments(ScriptObject.SET_ARGUMENT.methodHandle(), 0, argumentsSO), 1, slot), Lookup.SET_OBJECT_TYPE);
         } else {
             final GettersSetters gs = GETTERS_SETTERS.get(structure);
             objectGetter = gs.getters[slot];
             objectSetter = gs.setters[slot];
 
             if (!OBJECT_FIELDS_ONLY) {
-                final String fieldNamePrimitive = ObjectClassGenerator.getFieldName(slot, ObjectClassGenerator.PRIMITIVE_TYPE);
-                primitiveGetter = MH.getter(lookup, structure, fieldNamePrimitive, PRIMITIVE_TYPE.getTypeClass());
-                primitiveSetter = MH.setter(lookup, structure, fieldNamePrimitive, PRIMITIVE_TYPE.getTypeClass());
+                final String fieldNamePrimitive = ObjectClassGenerator.getFieldName(slot, PRIMITIVE_TYPE);
+                final Class typeClass = PRIMITIVE_TYPE.getTypeClass();
+                primitiveGetter = MH.asType(MH.getter(lookup, structure, fieldNamePrimitive, typeClass), ACCESSOR_GETTER_PRIMITIVE_TYPE);
+                primitiveSetter = MH.asType(MH.setter(lookup, structure, fieldNamePrimitive, typeClass), ACCESSOR_SETTER_PRIMITIVE_TYPE);
             }
         }
 
@@ -325,16 +339,8 @@ public class AccessorProperty extends Property {
         final int i = getAccessorTypeIndex(type);
         if (getters[i] == null) {
             getters[i] = debug(
-                MH.asType(
-                    createGetter(
-                        currentType,
-                        type,
-                        primitiveGetter,
-                        objectGetter),
-                    ACCESSOR_GETTER_TYPES[i]),
-                currentType,
-                type,
-                "get");
+                createGetter(currentType, type, primitiveGetter, objectGetter),
+                currentType, type, "get");
         }
 
         return getters[i];
@@ -370,7 +376,6 @@ public class AccessorProperty extends Property {
             objectSetter = getSpillSetter();
         }
         MethodHandle mh = createSetter(forType, type, primitiveSetter, objectSetter);
-        mh = MH.asType(mh, ACCESSOR_SETTER_TYPES[getAccessorTypeIndex(type)]); //has to be the case for invokeexact to work in ScriptObject
         mh = debug(mh, currentType, type, "set");
         return mh;
     }
@@ -423,9 +428,9 @@ public class AccessorProperty extends Property {
         final int slot = getSlot();
         MethodHandle getter = slot < SPILL_CACHE_SIZE ? SPILL_ACCESSORS[slot * 2] : null;
         if (getter == null) {
-            getter = MH.asType(MH.insertArguments(SPILL_ELEMENT_GETTER, 1, slot), Lookup.GET_OBJECT_TYPE);
+            getter = MH.insertArguments(SPILL_ELEMENT_GETTER, 1, slot);
             if (slot < SPILL_CACHE_SIZE) {
-                SPILL_ACCESSORS[slot * 2] = getter;
+                SPILL_ACCESSORS[slot * 2 + 0] = getter;
             }
         }
         return getter;
@@ -435,7 +440,7 @@ public class AccessorProperty extends Property {
         final int slot = getSlot();
         MethodHandle setter = slot < SPILL_CACHE_SIZE ? SPILL_ACCESSORS[slot * 2 + 1] : null;
         if (setter == null) {
-            setter = MH.asType(MH.insertArguments(SPILL_ELEMENT_SETTER, 1, slot), Lookup.SET_OBJECT_TYPE);
+            setter = MH.insertArguments(SPILL_ELEMENT_SETTER, 1, slot);
             if (slot < SPILL_CACHE_SIZE) {
                 SPILL_ACCESSORS[slot * 2 + 1] = setter;
             }

From f495ca639cb298ccf27dc44ac5fac0f9070eb790 Mon Sep 17 00:00:00 2001
From: Attila Szegedi 
Date: Thu, 4 Jul 2013 14:10:18 +0200
Subject: [PATCH 4/4] 8019809: return after break incorrectly sets the block as
 terminal

Reviewed-by: jlaskey, lagergren
---
 .../jdk/nashorn/internal/codegen/Lower.java   | 24 ++++++++++++++-----
 .../internal/ir/BlockLexicalContext.java      | 19 ++++++++++-----
 .../JDK-8019809.js                            |  0
 3 files changed, 31 insertions(+), 12 deletions(-)
 rename nashorn/test/script/{currently-failing => basic}/JDK-8019809.js (100%)

diff --git a/nashorn/src/jdk/nashorn/internal/codegen/Lower.java b/nashorn/src/jdk/nashorn/internal/codegen/Lower.java
index 013564c2760..880fea67640 100644
--- a/nashorn/src/jdk/nashorn/internal/codegen/Lower.java
+++ b/nashorn/src/jdk/nashorn/internal/codegen/Lower.java
@@ -32,6 +32,7 @@ import static jdk.nashorn.internal.codegen.CompilerConstants.THIS;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.List;
+import java.util.ListIterator;
 import jdk.nashorn.internal.ir.BaseNode;
 import jdk.nashorn.internal.ir.BinaryNode;
 import jdk.nashorn.internal.ir.Block;
@@ -115,6 +116,21 @@ final class Lower extends NodeOperatorVisitor {
                 }
                 return newStatements;
             }
+
+            @Override
+            protected Block afterSetStatements(final Block block) {
+                final List stmts = block.getStatements();
+                for(final ListIterator li = stmts.listIterator(stmts.size()); li.hasPrevious();) {
+                    final Statement stmt = li.previous();
+                    // popStatements() guarantees that the only thing after a terminal statement are uninitialized
+                    // VarNodes. We skip past those, and set the terminal state of the block to the value of the
+                    // terminal state of the first statement that is not an uninitialized VarNode.
+                    if(!(stmt instanceof VarNode && ((VarNode)stmt).getInit() == null)) {
+                        return block.setIsTerminal(this, stmt.isTerminal());
+                    }
+                }
+                return block.setIsTerminal(this, false);
+            }
         });
     }
 
@@ -132,11 +148,11 @@ final class Lower extends NodeOperatorVisitor {
         //now we have committed the entire statement list to the block, but we need to truncate
         //whatever is after the last terminal. block append won't append past it
 
-        Statement last = lc.getLastStatement();
 
         if (lc.isFunctionBody()) {
             final FunctionNode currentFunction = lc.getCurrentFunction();
             final boolean isProgram = currentFunction.isProgram();
+            final Statement last = lc.getLastStatement();
             final ReturnNode returnNode = new ReturnNode(
                 last == null ? block.getLineNumber() : last.getLineNumber(), //TODO?
                 currentFunction.getToken(),
@@ -145,11 +161,7 @@ final class Lower extends NodeOperatorVisitor {
                     compilerConstant(RETURN) :
                     LiteralNode.newInstance(block, ScriptRuntime.UNDEFINED));
 
-            last = (Statement)returnNode.accept(this);
-        }
-
-        if (last != null && last.isTerminal()) {
-            return block.setIsTerminal(lc, true);
+            returnNode.accept(this);
         }
 
         return block;
diff --git a/nashorn/src/jdk/nashorn/internal/ir/BlockLexicalContext.java b/nashorn/src/jdk/nashorn/internal/ir/BlockLexicalContext.java
index 71c80a6b04f..8fecddd0b90 100644
--- a/nashorn/src/jdk/nashorn/internal/ir/BlockLexicalContext.java
+++ b/nashorn/src/jdk/nashorn/internal/ir/BlockLexicalContext.java
@@ -29,7 +29,6 @@ import java.util.ArrayDeque;
 import java.util.ArrayList;
 import java.util.Deque;
 import java.util.List;
-import java.util.ListIterator;
 
 /**
  * This is a subclass of lexical context used for filling
@@ -63,6 +62,16 @@ public class BlockLexicalContext extends LexicalContext {
         return sstack.pop();
     }
 
+    /**
+     * Override this method to perform some additional processing on the block after its statements have been set. By
+     * default does nothing and returns the original block.
+     * @param block the block to operate on
+     * @return a modified block.
+     */
+    protected Block afterSetStatements(Block block) {
+        return block;
+    }
+
     @SuppressWarnings("unchecked")
     @Override
     public  T pop(final T node) {
@@ -70,6 +79,7 @@ public class BlockLexicalContext extends LexicalContext {
         if (node instanceof Block) {
             final List newStatements = popStatements();
             expected = (T)((Block)node).setStatements(this, newStatements);
+            expected = (T)afterSetStatements((Block)expected);
             if (!sstack.isEmpty()) {
                 lastStatement = lastStatement(sstack.peek());
             }
@@ -107,10 +117,7 @@ public class BlockLexicalContext extends LexicalContext {
     }
 
     private static Statement lastStatement(final List statements) {
-        for (final ListIterator iter = statements.listIterator(statements.size()); iter.hasPrevious(); ) {
-            final Statement node = iter.previous();
-            return node;
-        }
-        return null;
+        final int s = statements.size();
+        return s == 0 ? null : statements.get(s - 1);
     }
 }
diff --git a/nashorn/test/script/currently-failing/JDK-8019809.js b/nashorn/test/script/basic/JDK-8019809.js
similarity index 100%
rename from nashorn/test/script/currently-failing/JDK-8019809.js
rename to nashorn/test/script/basic/JDK-8019809.js