changeset 1129:6ec61d249428 jdk8u40-b19 jdk8u60-b00

Merge
author lana
date Thu, 11 Dec 2014 13:40:21 -0800
parents 1b54a95a8c77 (current diff) ec1fd6967009 (diff)
children 4d240320929f
files
diffstat 37 files changed, 986 insertions(+), 122 deletions(-) [+]
line wrap: on
line diff
--- a/THIRD_PARTY_README	Wed Dec 10 14:36:00 2014 -0800
+++ b/THIRD_PARTY_README	Thu Dec 11 13:40:21 2014 -0800
@@ -3385,7 +3385,7 @@
 included with JRE 8, JDK 8, and OpenJDK 8.
 
   Apache Commons Math 3.2
-  Apache Derby 10.10.1.3        
+  Apache Derby 10.11.1.2
   Apache Jakarta BCEL 5.1 
   Apache Jakarta Regexp 1.4 
   Apache Santuario XML Security for Java 1.5.4
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/samples/browser_dom.js	Thu Dec 11 13:40:21 2014 -0800
@@ -0,0 +1,91 @@
+#// Usage: jjs -fx browser.js
+
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ *   - Redistributions of source code must retain the above copyright
+ *     notice, this list of conditions and the following disclaimer.
+ *
+ *   - Redistributions in binary form must reproduce the above copyright
+ *     notice, this list of conditions and the following disclaimer in the
+ *     documentation and/or other materials provided with the distribution.
+ *
+ *   - Neither the name of Oracle nor the names of its
+ *     contributors may be used to endorse or promote products derived
+ *     from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+if (!$OPTIONS._fx) {
+    print("Usage: jjs -fx browser.js");
+    exit(1);
+}
+
+// JavaFX classes used
+var ChangeListener = Java.type("javafx.beans.value.ChangeListener");
+var Scene     = Java.type("javafx.scene.Scene");
+var WebView   = Java.type("javafx.scene.web.WebView");
+var EventListener = Java.type("org.w3c.dom.events.EventListener");
+
+// JavaFX start method
+function start(stage) {
+    start.title = "Web View";
+    var wv = new WebView();
+    wv.engine.loadContent(<<EOF
+<html>
+<head>
+<title>
+This is the title
+</title>
+<script>
+// click count for OK button
+var okCount = 0;
+</script>
+</head>
+<body>
+Button from the input html<br>
+<button type="button" onclick="okCount++">OK</button><br>
+</body>
+</html>
+EOF, "text/html");
+
+    // attach onload handler
+    wv.engine.loadWorker.stateProperty().addListener(
+        new ChangeListener() {
+            changed: function() {
+               // DOM document element
+               var document = wv.engine.document;
+               // DOM manipulation
+               var btn = document.createElement("button");
+               var n = 0;
+               // attach a button handler - nashorn function!
+               btn.onclick = new EventListener(function() {
+                   n++; print("You clicked " + n + " time(s)");
+                   print("you clicked OK " + wv.engine.executeScript("okCount"));
+               });
+               // attach text to button
+               var t = document.createTextNode("Click Me!"); 
+               btn.appendChild(t);
+               // attach button to the document
+               document.body.appendChild(btn); 
+           }
+        }
+    );
+    stage.scene = new Scene(wv, 750, 500);
+    stage.show();
+}
--- a/src/jdk/nashorn/internal/codegen/AssignSymbols.java	Wed Dec 10 14:36:00 2014 -0800
+++ b/src/jdk/nashorn/internal/codegen/AssignSymbols.java	Thu Dec 11 13:40:21 2014 -0800
@@ -910,7 +910,7 @@
     @Override
     public Node leaveSwitchNode(final SwitchNode switchNode) {
         // We only need a symbol for the tag if it's not an integer switch node
-        if(!switchNode.isInteger()) {
+        if(!switchNode.isUniqueInteger()) {
             switchNode.setTag(newObjectInternal(SWITCH_TAG_PREFIX));
         }
         return switchNode;
--- a/src/jdk/nashorn/internal/codegen/AstSerializer.java	Wed Dec 10 14:36:00 2014 -0800
+++ b/src/jdk/nashorn/internal/codegen/AstSerializer.java	Thu Dec 11 13:40:21 2014 -0800
@@ -48,11 +48,13 @@
     private static final int COMPRESSION_LEVEL = Options.getIntProperty("nashorn.serialize.compression", 4);
     static byte[] serialize(final FunctionNode fn) {
         final ByteArrayOutputStream out = new ByteArrayOutputStream();
-        try (final ObjectOutputStream oout = new ObjectOutputStream(new DeflaterOutputStream(out,
-                new Deflater(COMPRESSION_LEVEL)))) {
+        final Deflater deflater = new Deflater(COMPRESSION_LEVEL);
+        try (final ObjectOutputStream oout = new ObjectOutputStream(new DeflaterOutputStream(out, deflater))) {
             oout.writeObject(removeInnerFunctionBodies(fn));
         } catch (final IOException e) {
             throw new AssertionError("Unexpected exception serializing function", e);
+        } finally {
+            deflater.end();
         }
         return out.toByteArray();
     }
--- a/src/jdk/nashorn/internal/codegen/CodeGenerator.java	Wed Dec 10 14:36:00 2014 -0800
+++ b/src/jdk/nashorn/internal/codegen/CodeGenerator.java	Thu Dec 11 13:40:21 2014 -0800
@@ -465,10 +465,10 @@
             // If this is either __FILE__, __DIR__, or __LINE__ then load the property initially as Object as we'd convert
             // it anyway for replaceLocationPropertyPlaceholder.
             if(identNode.isCompileTimePropertyName()) {
-                method.dynamicGet(Type.OBJECT, identNode.getSymbol().getName(), flags, identNode.isFunction());
+                method.dynamicGet(Type.OBJECT, identNode.getSymbol().getName(), flags, identNode.isFunction(), false);
                 replaceCompileTimeProperty();
             } else {
-                dynamicGet(identNode.getSymbol().getName(), flags, identNode.isFunction());
+                dynamicGet(identNode.getSymbol().getName(), flags, identNode.isFunction(), false);
             }
         }
     }
@@ -486,7 +486,7 @@
 
     private MethodEmitter storeFastScopeVar(final Symbol symbol, final int flags) {
         loadFastScopeProto(symbol, true);
-        method.dynamicSet(symbol.getName(), flags | CALLSITE_FAST_SCOPE);
+        method.dynamicSet(symbol.getName(), flags | CALLSITE_FAST_SCOPE, false);
         return method;
     }
 
@@ -571,9 +571,11 @@
 
         // Operands' load type should not be narrower than the narrowest of the individual operand types, nor narrower
         // than the lower explicit bound, but it should also not be wider than
-        final Type narrowestOperandType = Type.narrowest(Type.widest(lhs.getType(), rhs.getType()), explicitOperandBounds.widest);
+        final Type lhsType = undefinedToNumber(lhs.getType());
+        final Type rhsType = undefinedToNumber(rhs.getType());
+        final Type narrowestOperandType = Type.narrowest(Type.widest(lhsType, rhsType), explicitOperandBounds.widest);
         final TypeBounds operandBounds = explicitOperandBounds.notNarrowerThan(narrowestOperandType);
-        if (noToPrimitiveConversion(lhs.getType(), explicitOperandBounds.widest) || rhs.isLocal()) {
+        if (noToPrimitiveConversion(lhsType, explicitOperandBounds.widest) || rhs.isLocal()) {
             // Can reorder. We might still need to separate conversion, but at least we can do it with reordering
             if (forceConversionSeparation) {
                 // Can reorder, but can't move conversion into the operand as the operation depends on operands
@@ -594,10 +596,10 @@
             // Can't reorder. Load and convert separately.
             final TypeBounds safeConvertBounds = TypeBounds.UNBOUNDED.notNarrowerThan(narrowestOperandType);
             loadExpression(lhs, safeConvertBounds, baseAlreadyOnStack);
-            final Type lhsType = method.peekType();
+            final Type lhsLoadedType = method.peekType();
             loadExpression(rhs, safeConvertBounds, false);
             final Type convertedLhsType = operandBounds.within(method.peekType());
-            if (convertedLhsType != lhsType) {
+            if (convertedLhsType != lhsLoadedType) {
                 // Do it conditionally, so that if conversion is a no-op we don't introduce a SWAP, SWAP.
                 method.swap().convert(convertedLhsType).swap();
             }
@@ -609,6 +611,10 @@
         return method;
     }
 
+    private static final Type undefinedToNumber(final Type type) {
+        return type == Type.UNDEFINED ? Type.NUMBER : type;
+    }
+
     private static final class TypeBounds {
         final Type narrowest;
         final Type widest;
@@ -739,7 +745,7 @@
                     @Override
                     void consumeStack() {
                         final int flags = getCallSiteFlags();
-                        dynamicGet(accessNode.getProperty(), flags, accessNode.isFunction());
+                        dynamicGet(accessNode.getProperty(), flags, accessNode.isFunction(), accessNode.isIndex());
                     }
                 }.emit(baseAlreadyOnStack ? 1 : 0);
                 return false;
@@ -1443,7 +1449,7 @@
                         // NOTE: not using a nested OptimisticOperation on this dynamicGet, as we expect to get back
                         // a callable object. Nobody in their right mind would optimistically type this call site.
                         assert !node.isOptimistic();
-                        method.dynamicGet(node.getType(), node.getProperty(), flags, true);
+                        method.dynamicGet(node.getType(), node.getProperty(), flags, true, node.isIndex());
                         method.swap();
                         argCount = loadArgs(args);
                     }
@@ -2015,6 +2021,19 @@
         final Expression test = ifNode.getTest();
         final Block pass = ifNode.getPass();
         final Block fail = ifNode.getFail();
+
+        if (Expression.isAlwaysTrue(test)) {
+            loadAndDiscard(test);
+            pass.accept(this);
+            return false;
+        } else if (Expression.isAlwaysFalse(test)) {
+            loadAndDiscard(test);
+            if (fail != null) {
+                fail.accept(this);
+            }
+            return false;
+        }
+
         final boolean hasFailConversion = LocalVariableConversion.hasLiveConversion(ifNode);
 
         final Label failLabel  = new Label("if_fail");
@@ -2034,7 +2053,7 @@
             method.beforeJoinPoint(ifNode);
         }
 
-        if(afterLabel != null) {
+        if(afterLabel != null && afterLabel.isReachable()) {
             method.label(afterLabel);
         }
 
@@ -2811,7 +2830,7 @@
         Label defaultLabel = defaultCase != null ? defaultCase.getEntry() : breakLabel;
         final boolean hasSkipConversion = LocalVariableConversion.hasLiveConversion(switchNode);
 
-        if (switchNode.isInteger()) {
+        if (switchNode.isUniqueInteger()) {
             // Tree for sorting values.
             final TreeMap<Integer, Label> tree = new TreeMap<>();
 
@@ -3145,14 +3164,13 @@
             if (isFastScope(identSymbol)) {
                 storeFastScopeVar(identSymbol, flags);
             } else {
-                method.dynamicSet(identNode.getName(), flags);
+                method.dynamicSet(identNode.getName(), flags, false);
             }
         } else {
             final Type identType = identNode.getType();
             if(identType == Type.UNDEFINED) {
-                // The symbol must not be slotted; the initializer is either itself undefined (explicit assignment of
-                // undefined to undefined), or the left hand side is a dead variable.
-                assert !identNode.getSymbol().isScope();
+                // The initializer is either itself undefined (explicit assignment of undefined to undefined),
+                // or the left hand side is a dead variable.
                 assert init.getType() == Type.UNDEFINED || identNode.getSymbol().slotCount() == 0;
                 loadAndDiscard(init);
                 return false;
@@ -3264,7 +3282,7 @@
             emitContinueLabel(continueLabel, liveLocalsOnContinue);
         }
 
-        if (loopNode.hasPerIterationScope() && lc.getParentBlock().needsScope()) {
+        if (loopNode.hasPerIterationScope() && lc.getCurrentBlock().needsScope()) {
             // ES6 for loops with LET init need a new scope for each iteration. We just create a shallow copy here.
             method.loadCompilerConstant(SCOPE);
             method.invoke(virtualCallNoLookup(ScriptObject.class, "copy", ScriptObject.class));
@@ -3575,9 +3593,9 @@
                     operandBounds = new TypeBounds(binaryNode.getType(), Type.OBJECT);
                 } else {
                     // Non-optimistic, non-FP +. Allow it to overflow.
-                    operandBounds = new TypeBounds(Type.narrowest(binaryNode.getWidestOperandType(), resultBounds.widest),
-                            Type.OBJECT);
-                    forceConversionSeparation = binaryNode.getWidestOperationType().narrowerThan(resultBounds.widest);
+                    final Type widestOperationType = binaryNode.getWidestOperationType();
+                    operandBounds = new TypeBounds(Type.narrowest(binaryNode.getWidestOperandType(), resultBounds.widest), widestOperationType);
+                    forceConversionSeparation = widestOperationType.narrowerThan(resultBounds.widest);
                 }
                 loadBinaryOperands(binaryNode.lhs(), binaryNode.rhs(), operandBounds, false, forceConversionSeparation);
             }
@@ -3692,8 +3710,7 @@
             final Expression lhs = assignNode.lhs();
             final Expression rhs = assignNode.rhs();
             final Type widestOperationType = assignNode.getWidestOperationType();
-            final Type widest = assignNode.isTokenType(TokenType.ASSIGN_ADD) ? Type.OBJECT : widestOperationType;
-            final TypeBounds bounds = new TypeBounds(assignNode.getType(), widest);
+            final TypeBounds bounds = new TypeBounds(assignNode.getType(), widestOperationType);
             new OptimisticOperation(assignNode, bounds) {
                 @Override
                 void loadStack() {
@@ -4251,7 +4268,7 @@
                         if (isFastScope(symbol)) {
                             storeFastScopeVar(symbol, flags);
                         } else {
-                            method.dynamicSet(node.getName(), flags);
+                            method.dynamicSet(node.getName(), flags, false);
                         }
                     } else {
                         final Type storeType = assignNode.getType();
@@ -4268,7 +4285,7 @@
 
                 @Override
                 public boolean enterAccessNode(final AccessNode node) {
-                    method.dynamicSet(node.getProperty(), getCallSiteFlags());
+                    method.dynamicSet(node.getProperty(), getCallSiteFlags(), node.isIndex());
                     return false;
                 }
 
@@ -4606,11 +4623,11 @@
          * @param isMethod whether we're preferrably retrieving a function
          * @return the current method emitter
          */
-        MethodEmitter dynamicGet(final String name, final int flags, final boolean isMethod) {
+        MethodEmitter dynamicGet(final String name, final int flags, final boolean isMethod, final boolean isIndex) {
             if(isOptimistic) {
-                return method.dynamicGet(getOptimisticCoercedType(), name, getOptimisticFlags(flags), isMethod);
-            }
-            return method.dynamicGet(resultBounds.within(expression.getType()), name, nonOptimisticFlags(flags), isMethod);
+                return method.dynamicGet(getOptimisticCoercedType(), name, getOptimisticFlags(flags), isMethod, isIndex);
+            }
+            return method.dynamicGet(resultBounds.within(expression.getType()), name, nonOptimisticFlags(flags), isMethod, isIndex);
         }
 
         MethodEmitter dynamicGetIndex(final int flags, final boolean isMethod) {
--- a/src/jdk/nashorn/internal/codegen/FoldConstants.java	Wed Dec 10 14:36:00 2014 -0800
+++ b/src/jdk/nashorn/internal/codegen/FoldConstants.java	Thu Dec 11 13:40:21 2014 -0800
@@ -26,12 +26,16 @@
 package jdk.nashorn.internal.codegen;
 
 import java.util.ArrayList;
+import java.util.HashSet;
 import java.util.List;
+import java.util.Set;
 import jdk.nashorn.internal.codegen.types.Type;
 import jdk.nashorn.internal.ir.BinaryNode;
 import jdk.nashorn.internal.ir.Block;
 import jdk.nashorn.internal.ir.BlockStatement;
+import jdk.nashorn.internal.ir.CaseNode;
 import jdk.nashorn.internal.ir.EmptyNode;
+import jdk.nashorn.internal.ir.Expression;
 import jdk.nashorn.internal.ir.FunctionNode;
 import jdk.nashorn.internal.ir.FunctionNode.CompilationState;
 import jdk.nashorn.internal.ir.IfNode;
@@ -40,6 +44,7 @@
 import jdk.nashorn.internal.ir.LiteralNode.ArrayLiteralNode;
 import jdk.nashorn.internal.ir.Node;
 import jdk.nashorn.internal.ir.Statement;
+import jdk.nashorn.internal.ir.SwitchNode;
 import jdk.nashorn.internal.ir.TernaryNode;
 import jdk.nashorn.internal.ir.UnaryNode;
 import jdk.nashorn.internal.ir.VarNode;
@@ -126,11 +131,37 @@
     public Node leaveTernaryNode(final TernaryNode ternaryNode) {
         final Node test = ternaryNode.getTest();
         if (test instanceof LiteralNode.PrimitiveLiteralNode) {
-            return ((LiteralNode.PrimitiveLiteralNode<?>)test).isTrue() ? ternaryNode.getTrueExpression() : ternaryNode.getFalseExpression();
+            return (((LiteralNode.PrimitiveLiteralNode<?>)test).isTrue() ? ternaryNode.getTrueExpression() : ternaryNode.getFalseExpression()).getExpression();
         }
         return ternaryNode;
     }
 
+    @Override
+    public Node leaveSwitchNode(final SwitchNode switchNode) {
+        return switchNode.setUniqueInteger(lc, isUniqueIntegerSwitchNode(switchNode));
+    }
+
+    private static boolean isUniqueIntegerSwitchNode(final SwitchNode switchNode) {
+        final Set<Integer> alreadySeen = new HashSet<>();
+        for (final CaseNode caseNode : switchNode.getCases()) {
+            final Expression test = caseNode.getTest();
+            if (test != null && !isUniqueIntegerLiteral(test, alreadySeen)) {
+                return false;
+            }
+        }
+        return true;
+    }
+
+    private static boolean isUniqueIntegerLiteral(final Expression expr, final Set<Integer> alreadySeen) {
+        if (expr instanceof LiteralNode) {
+            final Object value = ((LiteralNode<?>)expr).getValue();
+            if (value instanceof Integer) {
+                return alreadySeen.add((Integer)value);
+            }
+        }
+        return false;
+    }
+
     /**
      * Helper class to evaluate constant expressions at compile time This is
      * also a simplifier used by BinaryNode visits, UnaryNode visits and
--- a/src/jdk/nashorn/internal/codegen/LocalVariableTypesCalculator.java	Wed Dec 10 14:36:00 2014 -0800
+++ b/src/jdk/nashorn/internal/codegen/LocalVariableTypesCalculator.java	Thu Dec 11 13:40:21 2014 -0800
@@ -28,6 +28,7 @@
 import static jdk.nashorn.internal.codegen.CompilerConstants.RETURN;
 import static jdk.nashorn.internal.ir.Expression.isAlwaysFalse;
 import static jdk.nashorn.internal.ir.Expression.isAlwaysTrue;
+
 import java.util.ArrayDeque;
 import java.util.ArrayList;
 import java.util.Collections;
@@ -82,7 +83,6 @@
 import jdk.nashorn.internal.ir.VarNode;
 import jdk.nashorn.internal.ir.WhileNode;
 import jdk.nashorn.internal.ir.visitor.NodeVisitor;
-import jdk.nashorn.internal.parser.Token;
 import jdk.nashorn.internal.parser.TokenType;
 
 /**
@@ -93,6 +93,13 @@
  * variable to its widest used type after the join point. That would eliminate some widenings of undefined variables to
  * object, most notably those used only in loops. We need a full liveness analysis for that. Currently, we can establish
  * per-type liveness, which eliminates most of unwanted dead widenings.
+ * NOTE: the way this class is implemented, it actually processes the AST in two passes. The first pass is top-down and
+ * implemented in {@code enterXxx} methods. This pass does not mutate the AST (except for one occurrence, noted below),
+ * as being able to find relevant labels for control flow joins is sensitive to their reference identity, and mutated
+ * label-carrying nodes will create copies of their labels. A second bottom-up pass applying the changes is implemented
+ * in the separate visitor sitting in {@link #leaveFunctionNode(FunctionNode)}. This visitor will also instantiate new
+ * instances of the calculator to be run on nested functions (when not lazy compiling).
+ *
  */
 final class LocalVariableTypesCalculator extends NodeVisitor<LexicalContext>{
 
@@ -398,48 +405,53 @@
 
     @Override
     public boolean enterBinaryNode(final BinaryNode binaryNode) {
+        // NOTE: regardless of operator's lexical associativity, lhs is always evaluated first.
         final Expression lhs = binaryNode.lhs();
-        final Expression rhs = binaryNode.rhs();
         final boolean isAssignment = binaryNode.isAssignment();
-
-        final TokenType tokenType = Token.descType(binaryNode.getToken());
-        if(tokenType.isLeftAssociative()) {
-            assert !isAssignment;
-            final boolean isLogical = binaryNode.isLogical();
-            final Label joinLabel = isLogical ? new Label("") : null;
-            lhs.accept(this);
-            if(isLogical) {
-                jumpToLabel((JoinPredecessor)lhs, joinLabel);
-            }
-            rhs.accept(this);
-            if(isLogical) {
-                jumpToLabel((JoinPredecessor)rhs, joinLabel);
-            }
-            joinOnLabel(joinLabel);
-        } else {
-            rhs.accept(this);
-            if(isAssignment) {
-                if(lhs instanceof BaseNode) {
-                    ((BaseNode)lhs).getBase().accept(this);
-                    if(lhs instanceof IndexNode) {
-                        ((IndexNode)lhs).getIndex().accept(this);
-                    } else {
-                        assert lhs instanceof AccessNode;
-                    }
+        LvarType lhsTypeOnLoad = null;
+        if(isAssignment) {
+            if(lhs instanceof BaseNode) {
+                ((BaseNode)lhs).getBase().accept(this);
+                if(lhs instanceof IndexNode) {
+                    ((IndexNode)lhs).getIndex().accept(this);
                 } else {
-                    assert lhs instanceof IdentNode;
-                    if(binaryNode.isSelfModifying()) {
-                        ((IdentNode)lhs).accept(this);
-                    }
+                    assert lhs instanceof AccessNode;
                 }
             } else {
-                lhs.accept(this);
+                assert lhs instanceof IdentNode;
+                if(binaryNode.isSelfModifying()) {
+                    final IdentNode ident = ((IdentNode)lhs);
+                    ident.accept(this);
+                    // Self-assignment can cause a change in the type of the variable. For purposes of evaluating
+                    // the type of the operation, we must use its type as it was when it was loaded. If we didn't
+                    // do this, some awkward expressions would end up being calculated incorrectly, e.g.
+                    // "var x; x += x = 0;". In this case we have undefined+int so the result type is double (NaN).
+                    // However, if we used the type of "x" on LHS after we evaluated RHS, we'd see int+int, so the
+                    // result type would be either optimistic int or pessimistic long, which would be wrong.
+                    lhsTypeOnLoad = getLocalVariableTypeIfBytecode(ident.getSymbol());
+                }
             }
+        } else {
+            lhs.accept(this);
         }
 
+        final boolean isLogical = binaryNode.isLogical();
+        assert !(isAssignment && isLogical); // there are no logical assignment operators in JS
+        final Label joinLabel = isLogical ? new Label("") : null;
+        if(isLogical) {
+            jumpToLabel((JoinPredecessor)lhs, joinLabel);
+        }
+
+        final Expression rhs = binaryNode.rhs();
+        rhs.accept(this);
+        if(isLogical) {
+            jumpToLabel((JoinPredecessor)rhs, joinLabel);
+        }
+        joinOnLabel(joinLabel);
+
         if(isAssignment && lhs instanceof IdentNode) {
             if(binaryNode.isSelfModifying()) {
-                onSelfAssignment((IdentNode)lhs, binaryNode);
+                onSelfAssignment((IdentNode)lhs, binaryNode, lhsTypeOnLoad);
             } else {
                 onAssignment((IdentNode)lhs, rhs);
             }
@@ -704,7 +716,7 @@
 
         // Control flow is different for all-integer cases where we dispatch by switch table, and for all other cases
         // where we do sequential comparison. Note that CaseNode objects act as join points.
-        final boolean isInteger = switchNode.isInteger();
+        final boolean isInteger = switchNode.isUniqueInteger();
         final Label breakLabel = switchNode.getBreakLabel();
         final boolean hasDefault = switchNode.getDefaultCase() != null;
 
@@ -919,7 +931,8 @@
 
         if(unaryNode.isSelfModifying()) {
             if(expr instanceof IdentNode) {
-                onSelfAssignment((IdentNode)expr, unaryNode);
+                final IdentNode ident = (IdentNode)expr;
+                onSelfAssignment(ident, unaryNode, getLocalVariableTypeIfBytecode(ident.getSymbol()));
             }
         }
         return false;
@@ -973,12 +986,41 @@
         return types;
     }
 
+    /**
+     * Returns the current type of the local variable represented by the symbol. This is the most strict of all
+     * {@code getLocalVariableType*} methods, as it will throw an assertion if the type is null. Therefore, it is only
+     * safe to be invoked on symbols known to be bytecode locals, and only after they have been initialized.
+     * Regardless, it is recommended to use this method in majority of cases, as because of its strictness it is the
+     * best suited for catching missing type calculation bugs early.
+     * @param symbol a symbol representing a bytecode local variable.
+     * @return the current type of the local variable represented by the symbol
+     */
     private LvarType getLocalVariableType(final Symbol symbol) {
         final LvarType type = getLocalVariableTypeOrNull(symbol);
         assert type != null;
         return type;
     }
 
+    /**
+     * Gets the type for a local variable if it is a bytecode local, otherwise null. Can be used in circumstances where
+     * the type is irrelevant if the symbol is not a bytecode local. Note that for bytecode locals, it delegates to
+     * {@link #getLocalVariableType(Symbol)}, so it will still assert that the type for such variable is already
+     * defined (that is, not null).
+     * @param symbol the symbol representing the variable.
+     * @return the current variable type, if it is a bytecode local, otherwise null.
+     */
+    private LvarType getLocalVariableTypeIfBytecode(final Symbol symbol) {
+        return symbol.isBytecodeLocal() ? getLocalVariableType(symbol) : null;
+    }
+
+    /**
+     * Gets the type for a variable represented by a symbol, or null if the type is not know. This is the least strict
+     * of all local variable type getters, and as such its use is discouraged except in initialization scenarios (where
+     * a just-defined symbol might still be null).
+     * @param symbol the symbol
+     * @return the current type for the symbol, or null if the type is not known either because the symbol has not been
+     * initialized, or because the symbol does not represent a bytecode local variable.
+     */
     private LvarType getLocalVariableTypeOrNull(final Symbol symbol) {
         return localVariableTypes.get(symbol);
     }
@@ -1358,13 +1400,13 @@
         jumpToCatchBlock(identNode);
     }
 
-    private void onSelfAssignment(final IdentNode identNode, final Expression assignment) {
+    private void onSelfAssignment(final IdentNode identNode, final Expression assignment, final LvarType typeOnLoad) {
         final Symbol symbol = identNode.getSymbol();
         assert symbol != null : identNode.getName();
         if(!symbol.isBytecodeLocal()) {
             return;
         }
-        final LvarType type = toLvarType(getType(assignment));
+        final LvarType type = toLvarType(getType(assignment, symbol, typeOnLoad.type));
         // Self-assignment never produce either a boolean or undefined
         assert type != null && type != LvarType.UNDEFINED && type != LvarType.BOOLEAN;
         setType(symbol, type);
@@ -1445,13 +1487,24 @@
         symbolIsUsed(symbol, getLocalVariableType(symbol));
     }
 
+    /**
+     * Gets the type of the expression, dependent on the current types of the local variables.
+     *
+     * @param expr the expression
+     * @return the current type of the expression dependent on the current types of the local variables.
+     */
     private Type getType(final Expression expr) {
         return expr.getType(getSymbolToType());
     }
 
+    /**
+     * Returns a function object from symbols to their types, used by the expressions to evaluate their type.
+     * {@link BinaryNode} specifically uses identity of the function to cache type calculations. This method makes
+     * sure to return the same function object while the local variable types don't change, and create a new function
+     * object if the local variable types have been changed.
+     * @return a function object representing a mapping from symbols to their types.
+     */
     private Function<Symbol, Type> getSymbolToType() {
-        // BinaryNode uses identity of the function to cache type calculations. Therefore, we must use different
-        // function instances for different localVariableTypes instances.
         if(symbolToType.isStale()) {
             symbolToType = new SymbolToType();
         }
@@ -1469,4 +1522,41 @@
             return boundTypes != localVariableTypes;
         }
     }
+
+    /**
+     * Gets the type of the expression, dependent on the current types of the local variables and a single overridden
+     * symbol type. Used by type calculation on compound operators to ensure the type of the LHS at the time it was
+     * loaded (which can potentially be different after RHS evaluation, e.g. "var x; x += x = 0;") is preserved for
+     * the calculation.
+     *
+     * @param expr the expression
+     * @param overriddenSymbol the overridden symbol
+     * @param overriddenType the overridden type
+     * @return the current type of the expression dependent on the current types of the local variables and the single
+     * potentially overridden type.
+     */
+    private Type getType(final Expression expr, final Symbol overriddenSymbol, final Type overriddenType) {
+        return expr.getType(getSymbolToType(overriddenSymbol, overriddenType));
+    }
+
+    private Function<Symbol, Type> getSymbolToType(final Symbol overriddenSymbol, final Type overriddenType) {
+        return getLocalVariableType(overriddenSymbol).type == overriddenType ? getSymbolToType() :
+            new SymbolToTypeOverride(overriddenSymbol, overriddenType);
+    }
+
+    private class SymbolToTypeOverride implements Function<Symbol, Type> {
+        private final Function<Symbol, Type> originalSymbolToType = getSymbolToType();
+        private final Symbol overriddenSymbol;
+        private final Type overriddenType;
+
+        SymbolToTypeOverride(final Symbol overriddenSymbol, final Type overriddenType) {
+            this.overriddenSymbol = overriddenSymbol;
+            this.overriddenType = overriddenType;
+        }
+
+        @Override
+        public Type apply(final Symbol symbol) {
+            return symbol == overriddenSymbol ? overriddenType : originalSymbolToType.apply(symbol);
+        }
+    }
 }
--- a/src/jdk/nashorn/internal/codegen/Lower.java	Wed Dec 10 14:36:00 2014 -0800
+++ b/src/jdk/nashorn/internal/codegen/Lower.java	Thu Dec 11 13:40:21 2014 -0800
@@ -34,6 +34,8 @@
 import java.util.Collections;
 import java.util.List;
 import java.util.ListIterator;
+import java.util.regex.Pattern;
+import jdk.nashorn.internal.ir.AccessNode;
 import jdk.nashorn.internal.ir.BaseNode;
 import jdk.nashorn.internal.ir.BinaryNode;
 import jdk.nashorn.internal.ir.Block;
@@ -52,6 +54,7 @@
 import jdk.nashorn.internal.ir.FunctionNode.CompilationState;
 import jdk.nashorn.internal.ir.IdentNode;
 import jdk.nashorn.internal.ir.IfNode;
+import jdk.nashorn.internal.ir.IndexNode;
 import jdk.nashorn.internal.ir.JumpStatement;
 import jdk.nashorn.internal.ir.LabelNode;
 import jdk.nashorn.internal.ir.LexicalContext;
@@ -93,6 +96,10 @@
 
     private final DebugLogger log;
 
+    // Conservative pattern to test if element names consist of characters valid for identifiers.
+    // This matches any non-zero length alphanumeric string including _ and $ and not starting with a digit.
+    private static Pattern SAFE_PROPERTY_NAME = Pattern.compile("[a-zA-Z_$][\\w$]*");
+
     /**
      * Constructor.
      */
@@ -140,7 +147,7 @@
             }
         });
 
-        this.log       = initLogger(compiler.getContext());
+        this.log = initLogger(compiler.getContext());
     }
 
     @Override
@@ -181,6 +188,28 @@
     }
 
     @Override
+    public Node leaveIndexNode(final IndexNode indexNode) {
+        final String name = getConstantPropertyName(indexNode.getIndex());
+        if (name != null) {
+            // If index node is a constant property name convert index node to access node.
+            assert Token.descType(indexNode.getToken()) == TokenType.LBRACKET;
+            return new AccessNode(indexNode.getToken(), indexNode.getFinish(), indexNode.getBase(), name);
+        }
+        return super.leaveIndexNode(indexNode);
+    }
+
+    // If expression is a primitive literal that is not an array index and does return its string value. Else return null.
+    private static String getConstantPropertyName(final Expression expression) {
+        if (expression instanceof LiteralNode.PrimitiveLiteralNode) {
+            final Object value = ((LiteralNode) expression).getValue();
+            if (value instanceof String && SAFE_PROPERTY_NAME.matcher((String) value).matches()) {
+                return (String) value;
+            }
+        }
+        return null;
+    }
+
+    @Override
     public Node leaveExpressionStatement(final ExpressionStatement expressionStatement) {
         final Expression expr = expressionStatement.getExpression();
         ExpressionStatement node = expressionStatement;
@@ -275,7 +304,7 @@
 
     @Override
     public Node leaveSwitchNode(final SwitchNode switchNode) {
-        if(!switchNode.isInteger()) {
+        if(!switchNode.isUniqueInteger()) {
             // Wrap it in a block so its internally created tag is restricted in scope
             addStatementEnclosedInBlock(switchNode);
         } else {
--- a/src/jdk/nashorn/internal/codegen/MethodEmitter.java	Wed Dec 10 14:36:00 2014 -0800
+++ b/src/jdk/nashorn/internal/codegen/MethodEmitter.java	Thu Dec 11 13:40:21 2014 -0800
@@ -2214,10 +2214,10 @@
      * @param name      name of property
      * @param flags     call site flags
      * @param isMethod  should it prefer retrieving methods
-     *
+     * @param isIndex   is this an index operation?
      * @return the method emitter
      */
-    MethodEmitter dynamicGet(final Type valueType, final String name, final int flags, final boolean isMethod) {
+    MethodEmitter dynamicGet(final Type valueType, final String name, final int flags, final boolean isMethod, final boolean isIndex) {
         debug("dynamic_get", name, valueType, getProgramPoint(flags));
 
         Type type = valueType;
@@ -2226,8 +2226,8 @@
         }
 
         popType(Type.SCOPE);
-        method.visitInvokeDynamicInsn((isMethod ? "dyn:getMethod|getProp|getElem:" : "dyn:getProp|getElem|getMethod:") +
-                NameCodec.encode(name), Type.getMethodDescriptor(type, Type.OBJECT), LINKERBOOTSTRAP, flags);
+        method.visitInvokeDynamicInsn(dynGetOperation(isMethod, isIndex) + ':' + NameCodec.encode(name),
+                Type.getMethodDescriptor(type, Type.OBJECT), LINKERBOOTSTRAP, flags);
 
         pushType(type);
         convert(valueType); //most probably a nop
@@ -2240,8 +2240,9 @@
      *
      * @param name  name of property
      * @param flags call site flags
+     * @param isIndex is this an index operation?
      */
-     void dynamicSet(final String name, final int flags) {
+    void dynamicSet(final String name, final int flags, final boolean isIndex) {
          assert !isOptimistic(flags);
          debug("dynamic_set", name, peekType());
 
@@ -2253,7 +2254,8 @@
         popType(type);
         popType(Type.SCOPE);
 
-        method.visitInvokeDynamicInsn("dyn:setProp|setElem:" + NameCodec.encode(name), methodDescriptor(void.class, Object.class, type.getTypeClass()), LINKERBOOTSTRAP, flags);
+        method.visitInvokeDynamicInsn(dynSetOperation(isIndex) + ':' + NameCodec.encode(name),
+                methodDescriptor(void.class, Object.class, type.getTypeClass()), LINKERBOOTSTRAP, flags);
     }
 
      /**
@@ -2286,7 +2288,7 @@
 
         final String signature = Type.getMethodDescriptor(resultType, Type.OBJECT /*e.g STRING->OBJECT*/, index);
 
-        method.visitInvokeDynamicInsn(isMethod ? "dyn:getMethod|getElem|getProp" : "dyn:getElem|getProp|getMethod", signature, LINKERBOOTSTRAP, flags);
+        method.visitInvokeDynamicInsn(dynGetOperation(isMethod, true), signature, LINKERBOOTSTRAP, flags);
         pushType(resultType);
 
         if (result.isBoolean()) {
@@ -2500,6 +2502,18 @@
         }
     }
 
+    private static String dynGetOperation(final boolean isMethod, final boolean isIndex) {
+        if (isMethod) {
+            return isIndex ? "dyn:getMethod|getElem|getProp" : "dyn:getMethod|getProp|getElem";
+        } else {
+            return isIndex ? "dyn:getElem|getProp|getMethod" : "dyn:getProp|getElem|getMethod";
+        }
+    }
+
+    private static String dynSetOperation(final boolean isIndex) {
+        return isIndex ? "dyn:setElem|setProp" : "dyn:setProp|setElem";
+    }
+
     private Type emitLocalVariableConversion(final LocalVariableConversion conversion, final boolean onlySymbolLiveValue) {
         final Type from = conversion.getFrom();
         final Type to = conversion.getTo();
--- a/src/jdk/nashorn/internal/codegen/SharedScopeCall.java	Wed Dec 10 14:36:00 2014 -0800
+++ b/src/jdk/nashorn/internal/codegen/SharedScopeCall.java	Thu Dec 11 13:40:21 2014 -0800
@@ -156,7 +156,7 @@
         assert !isCall || valueType.isObject(); // Callables are always objects
         // If flags are optimistic, but we're doing a call, remove optimistic flags from the getter, as they obviously
         // only apply to the call.
-        method.dynamicGet(valueType, symbol.getName(), isCall ? CodeGenerator.nonOptimisticFlags(flags) : flags, isCall);
+        method.dynamicGet(valueType, symbol.getName(), isCall ? CodeGenerator.nonOptimisticFlags(flags) : flags, isCall, false);
 
         // If this is a get we're done, otherwise call the value as function.
         if (isCall) {
--- a/src/jdk/nashorn/internal/ir/AccessNode.java	Wed Dec 10 14:36:00 2014 -0800
+++ b/src/jdk/nashorn/internal/ir/AccessNode.java	Thu Dec 11 13:40:21 2014 -0800
@@ -28,6 +28,8 @@
 import jdk.nashorn.internal.codegen.types.Type;
 import jdk.nashorn.internal.ir.annotations.Immutable;
 import jdk.nashorn.internal.ir.visitor.NodeVisitor;
+import jdk.nashorn.internal.parser.Token;
+import jdk.nashorn.internal.parser.TokenType;
 
 /**
  * IR representation of a property access (period operator.)
@@ -101,6 +103,14 @@
         return property;
     }
 
+    /**
+     * Return true if this node represents an index operation normally represented as {@link IndexNode}.
+     * @return true if an index access.
+     */
+    public boolean isIndex() {
+        return Token.descType(getToken()) == TokenType.LBRACKET;
+    }
+
     private AccessNode setBase(final Expression base) {
         if (this.base == base) {
             return this;
--- a/src/jdk/nashorn/internal/ir/BinaryNode.java	Wed Dec 10 14:36:00 2014 -0800
+++ b/src/jdk/nashorn/internal/ir/BinaryNode.java	Thu Dec 11 13:40:21 2014 -0800
@@ -341,10 +341,7 @@
     @Override
     public Node accept(final NodeVisitor<? extends LexicalContext> visitor) {
         if (visitor.enterBinaryNode(this)) {
-            if(tokenType().isLeftAssociative()) {
-                return visitor.leaveBinaryNode(setLHS((Expression)lhs.accept(visitor)).setRHS((Expression)rhs.accept(visitor)));
-            }
-            return visitor.leaveBinaryNode(setRHS((Expression)rhs.accept(visitor)).setLHS((Expression)lhs.accept(visitor)));
+            return visitor.leaveBinaryNode(setLHS((Expression)lhs.accept(visitor)).setRHS((Expression)rhs.accept(visitor)));
         }
 
         return this;
--- a/src/jdk/nashorn/internal/ir/RuntimeNode.java	Wed Dec 10 14:36:00 2014 -0800
+++ b/src/jdk/nashorn/internal/ir/RuntimeNode.java	Thu Dec 11 13:40:21 2014 -0800
@@ -27,7 +27,6 @@
 
 import static jdk.nashorn.internal.runtime.UnwarrantedOptimismException.INVALID_PROGRAM_POINT;
 
-import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collections;
 import java.util.List;
@@ -468,11 +467,7 @@
     @Override
     public Node accept(final NodeVisitor<? extends LexicalContext> visitor) {
         if (visitor.enterRuntimeNode(this)) {
-            final List<Expression> newArgs = new ArrayList<>();
-            for (final Node arg : args) {
-                newArgs.add((Expression)arg.accept(visitor));
-            }
-            return visitor.leaveRuntimeNode(setArgs(newArgs));
+            return visitor.leaveRuntimeNode(setArgs(Node.accept(visitor, args)));
         }
 
         return this;
--- a/src/jdk/nashorn/internal/ir/SwitchNode.java	Wed Dec 10 14:36:00 2014 -0800
+++ b/src/jdk/nashorn/internal/ir/SwitchNode.java	Thu Dec 11 13:40:21 2014 -0800
@@ -48,6 +48,10 @@
     /** Switch default index. */
     private final int defaultCaseIndex;
 
+    /** True if all cases are 32-bit signed integer constants, without repetitions. It's a prerequisite for
+     * using a tableswitch/lookupswitch when generating code. */
+    private final boolean uniqueInteger;
+
     /** Tag symbol. */
     private Symbol tag;
 
@@ -66,15 +70,17 @@
         this.expression       = expression;
         this.cases            = cases;
         this.defaultCaseIndex = defaultCase == null ? -1 : cases.indexOf(defaultCase);
+        this.uniqueInteger    = false;
     }
 
     private SwitchNode(final SwitchNode switchNode, final Expression expression, final List<CaseNode> cases,
-            final int defaultCaseIndex, final LocalVariableConversion conversion) {
+            final int defaultCaseIndex, final LocalVariableConversion conversion, final boolean uniqueInteger) {
         super(switchNode, conversion);
         this.expression       = expression;
         this.cases            = cases;
         this.defaultCaseIndex = defaultCaseIndex;
-        this.tag              = switchNode.getTag(); //TODO are symbols inhereted as references?
+        this.tag              = switchNode.getTag(); //TODO are symbols inherited as references?
+        this.uniqueInteger    = uniqueInteger;
     }
 
     @Override
@@ -83,7 +89,7 @@
         for (final CaseNode caseNode : cases) {
             newCases.add(new CaseNode(caseNode, caseNode.getTest(), caseNode.getBody(), caseNode.getLocalVariableConversion()));
         }
-        return Node.replaceInLexicalContext(lc, this, new SwitchNode(this, expression, newCases, defaultCaseIndex, conversion));
+        return Node.replaceInLexicalContext(lc, this, new SwitchNode(this, expression, newCases, defaultCaseIndex, conversion, uniqueInteger));
     }
 
     @Override
@@ -151,7 +157,7 @@
         if (this.cases == cases) {
             return this;
         }
-        return Node.replaceInLexicalContext(lc, this, new SwitchNode(this, expression, cases, defaultCaseIndex, conversion));
+        return Node.replaceInLexicalContext(lc, this, new SwitchNode(this, expression, cases, defaultCaseIndex, conversion, uniqueInteger));
     }
 
     /**
@@ -183,7 +189,7 @@
         if (this.expression == expression) {
             return this;
         }
-        return Node.replaceInLexicalContext(lc, this, new SwitchNode(this, expression, cases, defaultCaseIndex, conversion));
+        return Node.replaceInLexicalContext(lc, this, new SwitchNode(this, expression, cases, defaultCaseIndex, conversion, uniqueInteger));
     }
 
     /**
@@ -205,25 +211,30 @@
     }
 
     /**
-     * Returns true if all cases of this switch statement are 32-bit signed integer constants.
-     * @return true if all cases of this switch statement are 32-bit signed integer constants.
+     * Returns true if all cases of this switch statement are 32-bit signed integer constants, without repetitions.
+     * @return true if all cases of this switch statement are 32-bit signed integer constants, without repetitions.
      */
-    public boolean isInteger() {
-        for (final CaseNode caseNode : cases) {
-            final Expression test = caseNode.getTest();
-            if (test != null && !isIntegerLiteral(test)) {
-                return false;
-            }
+    public boolean isUniqueInteger() {
+        return uniqueInteger;
+    }
+
+    /**
+     * Sets whether all cases of this switch statement are 32-bit signed integer constants, without repetitions.
+     * @param lc lexical context
+     * @param uniqueInteger if true, all cases of this switch statement have been determined to be 32-bit signed
+     * integer constants, without repetitions.
+     * @return this switch node, if the value didn't change, or a new switch node with the changed value
+     */
+    public SwitchNode setUniqueInteger(final LexicalContext lc, final boolean uniqueInteger) {
+        if(this.uniqueInteger == uniqueInteger) {
+            return this;
         }
-        return true;
+        return Node.replaceInLexicalContext(lc, this, new SwitchNode(this, expression, cases, defaultCaseIndex, conversion, uniqueInteger));
     }
 
     @Override
     JoinPredecessor setLocalVariableConversionChanged(final LexicalContext lc, final LocalVariableConversion conversion) {
-        return Node.replaceInLexicalContext(lc, this, new SwitchNode(this, expression, cases, defaultCaseIndex, conversion));
+        return Node.replaceInLexicalContext(lc, this, new SwitchNode(this, expression, cases, defaultCaseIndex, conversion, uniqueInteger));
     }
 
-    private static boolean isIntegerLiteral(final Expression expr) {
-        return expr instanceof LiteralNode && ((LiteralNode<?>)expr).getValue() instanceof Integer;
-    }
 }
--- a/src/jdk/nashorn/internal/parser/Parser.java	Wed Dec 10 14:36:00 2014 -0800
+++ b/src/jdk/nashorn/internal/parser/Parser.java	Thu Dec 11 13:40:21 2014 -0800
@@ -2644,7 +2644,7 @@
         // name is null, generate anonymous name
         boolean isAnonymous = false;
         if (name == null) {
-            final String tmpName = getDefaultValidFunctionName(functionLine);
+            final String tmpName = getDefaultValidFunctionName(functionLine, isStatement);
             name = new IdentNode(functionToken, Token.descPosition(functionToken), tmpName);
             isAnonymous = true;
         }
@@ -2653,7 +2653,15 @@
         final List<IdentNode> parameters = formalParameterList();
         expect(RPAREN);
 
-        FunctionNode functionNode = functionBody(functionToken, name, parameters, FunctionNode.Kind.NORMAL, functionLine);
+        FunctionNode functionNode;
+        // Hide the current default name across function boundaries. E.g. "x3 = function x1() { function() {}}"
+        // If we didn't hide the current default name, then the innermost anonymous function would receive "x3".
+        hideDefaultName();
+        try {
+            functionNode = functionBody(functionToken, name, parameters, FunctionNode.Kind.NORMAL, functionLine);
+        } finally {
+            defaultNames.pop();
+        }
 
         if (isStatement) {
             if (topLevel || useBlockScope()) {
@@ -2722,9 +2730,17 @@
         return functionNode;
     }
 
-    private String getDefaultValidFunctionName(final int functionLine) {
+    private String getDefaultValidFunctionName(final int functionLine, final boolean isStatement) {
         final String defaultFunctionName = getDefaultFunctionName();
-        return isValidIdentifier(defaultFunctionName) ? defaultFunctionName : ANON_FUNCTION_PREFIX.symbolName() + functionLine;
+        if (isValidIdentifier(defaultFunctionName)) {
+            if (isStatement) {
+                // The name will be used as the LHS of a symbol assignment. We add the anonymous function
+                // prefix to ensure that it can't clash with another variable.
+                return ANON_FUNCTION_PREFIX.symbolName() + defaultFunctionName;
+            }
+            return defaultFunctionName;
+        }
+        return ANON_FUNCTION_PREFIX.symbolName() + functionLine;
     }
 
     private static boolean isValidIdentifier(final String name) {
@@ -2758,6 +2774,10 @@
 
     private void markDefaultNameUsed() {
         defaultNames.pop();
+        hideDefaultName();
+    }
+
+    private void hideDefaultName() {
         // Can be any value as long as getDefaultFunctionName doesn't recognize it as something it can extract a value
         // from. Can't be null
         defaultNames.push("");
--- a/src/jdk/nashorn/internal/runtime/ScriptObject.java	Wed Dec 10 14:36:00 2014 -0800
+++ b/src/jdk/nashorn/internal/runtime/ScriptObject.java	Thu Dec 11 13:40:21 2014 -0800
@@ -2001,12 +2001,11 @@
 
         if (find == null) {
             switch (operator) {
+            case "getElem": // getElem only gets here if element name is constant, so treat it like a property access
             case "getProp":
                 return noSuchProperty(desc, request);
             case "getMethod":
                 return noSuchMethod(desc, request);
-            case "getElem":
-                return createEmptyGetter(desc, explicitInstanceOfCheck, name);
             default:
                 throw new AssertionError(operator); // never invoked with any other operation
             }
@@ -2333,8 +2332,9 @@
         }
 
         final ScriptFunction func = (ScriptFunction)value;
-        final Object         thiz = scopeCall && func.isStrict() ? ScriptRuntime.UNDEFINED : this;
+        final Object         thiz = scopeCall && func.isStrict() ? UNDEFINED : this;
         // TODO: It'd be awesome if we could bind "name" without binding "this".
+        // Since we're binding this we must use an identity guard here.
         return new GuardedInvocation(
                 MH.dropArguments(
                         MH.constant(
@@ -2342,9 +2342,9 @@
                                 func.makeBoundFunction(thiz, new Object[] { name })),
                         0,
                         Object.class),
-                NashornGuards.getMapGuard(getMap(), explicitInstanceOfCheck),
-                (SwitchPoint)null,
-                explicitInstanceOfCheck ? null : ClassCastException.class);
+                NashornGuards.combineGuards(
+                        NashornGuards.getIdentityGuard(this),
+                        NashornGuards.getMapGuard(getMap(), true)));
     }
 
     /**
@@ -3710,7 +3710,9 @@
         final ScriptObject clone = (ScriptObject) super.clone();
         if (objectSpill != null) {
             clone.objectSpill = objectSpill.clone();
-            clone.primitiveSpill = primitiveSpill.clone();
+            if (primitiveSpill != null) {
+                clone.primitiveSpill = primitiveSpill.clone();
+            }
         }
         clone.arrayData = arrayData.copy();
         return clone;
--- a/src/jdk/nashorn/internal/runtime/linker/BrowserJSObjectLinker.java	Wed Dec 10 14:36:00 2014 -0800
+++ b/src/jdk/nashorn/internal/runtime/linker/BrowserJSObjectLinker.java	Thu Dec 11 13:40:21 2014 -0800
@@ -29,6 +29,7 @@
 import static jdk.nashorn.internal.runtime.linker.BrowserJSObjectLinker.JSObjectHandles.JSOBJECT_GETSLOT;
 import static jdk.nashorn.internal.runtime.linker.BrowserJSObjectLinker.JSObjectHandles.JSOBJECT_SETMEMBER;
 import static jdk.nashorn.internal.runtime.linker.BrowserJSObjectLinker.JSObjectHandles.JSOBJECT_SETSLOT;
+import static jdk.nashorn.internal.runtime.linker.BrowserJSObjectLinker.JSObjectHandles.JSOBJECT_CALL;
 import java.lang.invoke.MethodHandle;
 import java.lang.invoke.MethodHandles;
 import jdk.internal.dynalink.CallSiteDescriptor;
@@ -123,6 +124,8 @@
             case "setProp":
             case "setElem":
                 return c > 2 ? findSetMethod(desc) : findSetIndexMethod();
+            case "call":
+                return findCallMethod(desc);
             default:
                 return null;
         }
@@ -148,6 +151,11 @@
         return new GuardedInvocation(JSOBJECTLINKER_PUT, IS_JSOBJECT_GUARD);
     }
 
+    private static GuardedInvocation findCallMethod(final CallSiteDescriptor desc) {
+        final MethodHandle call = MH.insertArguments(JSOBJECT_CALL, 1, "call");
+        return new GuardedInvocation(MH.asCollector(call, Object[].class, desc.getMethodType().parameterCount() - 1), IS_JSOBJECT_GUARD);
+    }
+
     @SuppressWarnings("unused")
     private static boolean isJSObject(final Object self) {
         return jsObjectClass.isInstance(self);
@@ -207,6 +215,7 @@
         static final MethodHandle JSOBJECT_GETSLOT       = findJSObjectMH_V("getSlot", Object.class, int.class).asType(MH.type(Object.class, Object.class, int.class));
         static final MethodHandle JSOBJECT_SETMEMBER     = findJSObjectMH_V("setMember", Void.TYPE, String.class, Object.class).asType(MH.type(Void.TYPE, Object.class, String.class, Object.class));
         static final MethodHandle JSOBJECT_SETSLOT       = findJSObjectMH_V("setSlot", Void.TYPE, int.class, Object.class).asType(MH.type(Void.TYPE, Object.class, int.class, Object.class));
+        static final MethodHandle JSOBJECT_CALL          = findJSObjectMH_V("call", Object.class, String.class, Object[].class).asType(MH.type(Object.class, Object.class, String.class, Object[].class));
 
         private static MethodHandle findJSObjectMH_V(final String name, final Class<?> rtype, final Class<?>... types) {
             checkJSObjectClass();
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/script/basic/JDK-8066221.js	Thu Dec 11 13:40:21 2014 -0800
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) 2014 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-8066221: anonymous function statement name clashes with another symbol
+ * (compile-only test)
+ *
+ * @test
+ */
+
+x3 = function x1(x3) { function (){} };
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/script/basic/JDK-8066224.js	Thu Dec 11 13:40:21 2014 -0800
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2014 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-8066224: fixes for folding a constant-test ternary operator
+ *
+ * @test
+ * @run
+ */
+
+print((function(){ 
+    if(false ? 0 : '') {
+        throw false;
+    } else if (x = this) {
+        var x = x; 
+    }
+    return x === this;
+})())
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/script/basic/JDK-8066224.js.EXPECTED	Thu Dec 11 13:40:21 2014 -0800
@@ -0,0 +1,1 @@
+true
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/script/basic/JDK-8066225.js	Thu Dec 11 13:40:21 2014 -0800
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2014 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-8066225: NPE in MethodEmitter with duplicate integer switch cases
+ *
+ * @test
+ * @run
+ */
+
+(function (x){
+    switch(x) { 
+       case 44: for (var x in {}) {x}; print("1"); 
+       case 44: print("2");
+    }
+})(44);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/script/basic/JDK-8066225.js.EXPECTED	Thu Dec 11 13:40:21 2014 -0800
@@ -0,0 +1,2 @@
+1
+2
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/script/basic/JDK-8066227.js	Thu Dec 11 13:40:21 2014 -0800
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2014 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-8066227: CodeGenerator load unitialized slot
+ *
+ * @test
+ * @run
+ */
+
+print((function () { var x; (x += x = 0); return x; })());
+print((function () { var x; (x -= x = 0); return x; })());
+print((function () { var x; (x *= x = 0); return x; })());
+print((function () { var x; (x /= x = 0); return x; })());
+print((function () { var x; (x %= x = 0); return x; })());
+print((function () { var x; (x <<= x = 0); return x; })());
+print((function () { var x; (x >>= x = 0); return x; })());
+print((function () { var x; (x >>>= x = 0); return x; })());
+print((function () { var x; (x |= x = 0); return x; })());
+print((function () { var x; (x &= x = 0); return x; })());
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/script/basic/JDK-8066227.js.EXPECTED	Thu Dec 11 13:40:21 2014 -0800
@@ -0,0 +1,10 @@
+NaN
+NaN
+NaN
+NaN
+NaN
+0
+0
+0
+0
+0
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/script/basic/JDK-8066230.js	Thu Dec 11 13:40:21 2014 -0800
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2014 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-8066230: Undefined object type assertion when computing TypeBounds
+ *
+ * @test
+ * @run
+ */
+
+(function() { void null + 0; })();
+(function() { var x; x += void x; })();
+(function() { var a = true + x, x; })();
+print("SUCCESS");
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/script/basic/JDK-8066230.js.EXPECTED	Thu Dec 11 13:40:21 2014 -0800
@@ -0,0 +1,1 @@
+SUCCESS
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/script/basic/JDK-8066236.js	Thu Dec 11 13:40:21 2014 -0800
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 2014 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-8066236: RuntimeNode forces copy creation on visitation
+ *
+ * @test
+ * @run
+ */
+
+// Note: we're using Function("code") instead of (function(){ code }) so that
+// we don't trigger parser API validation in JDK-8008448 tests. The test code
+// encapsulated in functions below can't be correctly handled by the parser API
+// currently, as it contains parser-generated REFERENCE_ERROR runtime nodes.
+try {
+    Function("L: {this = x;break L}")();
+} catch (e) {
+   print("threw ReferenceError: " + (e instanceof ReferenceError));
+}
+try {
+    Function("L:with(this--)break L;")();
+} catch (e) {
+   print("threw ReferenceError: " + (e instanceof ReferenceError));
+}
+Function("L:with(Object in Object)break L;")();
+print("SUCCESS");
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/script/basic/JDK-8066236.js.EXPECTED	Thu Dec 11 13:40:21 2014 -0800
@@ -0,0 +1,3 @@
+threw ReferenceError: true
+threw ReferenceError: true
+SUCCESS
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/script/basic/JDK-8066669.js	Thu Dec 11 13:40:21 2014 -0800
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 2010, 2014, 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-8066669: dust.js performance regression caused by primitive field conversion
+ *
+ * @test
+ * @run
+ */
+
+// Make sure index access on Java objects is working as expected.
+var map = new java.util.HashMap();
+
+map["foo"] = "bar";
+map[1] = 2;
+map[false] = true;
+map[null] = 0;
+
+print(map);
+
+var keys =  map.keySet().iterator();
+
+while(keys.hasNext()) {
+    var key = keys.next();
+    print(typeof key, key);
+}
+
+print(typeof map["foo"], map["foo"]);
+print(typeof map[1], map[1]);
+print(typeof map[false], map[false]);
+print(typeof map[null], map[null]);
+
+print(map.foo);
+print(map.false);
+print(map.null);
+
+map.foo = "baz";
+print(map);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/script/basic/JDK-8066669.js.EXPECTED	Thu Dec 11 13:40:21 2014 -0800
@@ -0,0 +1,13 @@
+{null=0, 1=2, false=true, foo=bar}
+object null
+number 1
+boolean false
+string foo
+string bar
+number 2
+boolean true
+number 0
+bar
+null
+null
+{null=0, 1=2, false=true, foo=baz}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/script/basic/JDK-8066932.js	Thu Dec 11 13:40:21 2014 -0800
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2010, 2014, 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-8066932: __noSuchMethod__ binds to this-object without proper guard
+ *
+ * @test
+ * @run
+ */
+
+function C(id) {
+    this.id = id;
+}
+
+C.prototype.__noSuchMethod__ = function(name, args) {
+    return this.id;
+};
+
+function test(id) {
+    var c = new C(id);
+    return c.nonExistingMethod();
+}
+
+for (var i = 0; i < 30; i++) {
+    if (test(i) !== i) {
+        throw new Error("Wrong result from noSuchMethod in iteration " + i);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/script/basic/JDK-8067136.js	Thu Dec 11 13:40:21 2014 -0800
@@ -0,0 +1,69 @@
+/*
+ * Copyright (c) 2014, 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-8067136: BrowserJSObjectLinker does not handle call on JSObjects
+ *
+ * @test
+ * @option -scripting
+ * @run
+ */
+
+// call on netscape.javascript.JSObject
+
+function main() {
+    var JSObject;
+    try {
+        JSObject = Java.type("netscape.javascript.JSObject");
+    } catch (e) {
+        if (e instanceof java.lang.ClassNotFoundException) {
+            // pass vacuously by emitting the .EXPECTED file content
+            var str = readFully(__DIR__ + "JDK-8067136.js.EXPECTED");
+            print(str.substring(0, str.length - 1));
+            return;
+        } else{
+            fail("unexpected exception for JSObject", e);
+        }
+    }
+    test(JSObject);
+}
+
+function test(JSObject) {
+    var obj = new (Java.extend(JSObject))() {
+        getMember: function(name) {
+            if (name == "func") {
+                return new (Java.extend(JSObject)) {
+                    call: function(n) {
+                        print("func called");
+                    }
+                }
+            }
+            return name.toUpperCase();
+        },
+
+    };
+
+    obj.func();
+}
+
+main();
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/script/basic/JDK-8067136.js.EXPECTED	Thu Dec 11 13:40:21 2014 -0800
@@ -0,0 +1,1 @@
+func called
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/script/basic/es6/for-let-object-fields.js	Thu Dec 11 13:40:21 2014 -0800
@@ -0,0 +1,81 @@
+/*
+ * Copyright (c) 2010, 2014, 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-8067219: NPE in ScriptObject.clone() when running with object fields
+ *
+ * @test
+ * @run
+ * @fork
+ * @option -Dnashorn.fields.objects=true
+ * @option --language=es6
+ */
+
+"use strict";
+
+for (let i = 0; i < 10; i++) {
+    print(i);
+}
+
+try {
+    print(i);
+} catch (e) {
+    print(e);
+}
+
+let a = [];
+
+for (let i = 0; i < 10; i++) {
+    a.push(function() { print(i); });
+}
+
+a.forEach(function(f) { f(); });
+
+a = [];
+
+for (let i = 0; i < 10; i++) {
+    if (i == 5) {
+        i = "foo";
+    }
+    a.push(function() { print(i); });
+}
+
+a.forEach(function(f) { f(); });
+
+try {
+    print(i);
+} catch (e) {
+    print(e);
+}
+
+a = [];
+
+for (let i = 0; i < 20; i++) {
+    if (i % 2 == 1) {
+        i += 2;
+        continue;
+    }
+    a.push(function() { print(i); });
+}
+
+a.forEach(function(f) { f(); });
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/script/basic/es6/for-let-object-fields.js.EXPECTED	Thu Dec 11 13:40:21 2014 -0800
@@ -0,0 +1,33 @@
+0
+1
+2
+3
+4
+5
+6
+7
+8
+9
+ReferenceError: "i" is not defined
+0
+1
+2
+3
+4
+5
+6
+7
+8
+9
+0
+1
+2
+3
+4
+foo
+ReferenceError: "i" is not defined
+0
+4
+8
+12
+16
--- a/test/script/basic/es6/for-let.js	Wed Dec 10 14:36:00 2014 -0800
+++ b/test/script/basic/es6/for-let.js	Thu Dec 11 13:40:21 2014 -0800
@@ -26,7 +26,8 @@
  *
  * @test
  * @run
- * @option --language=es6 */
+ * @option --language=es6
+ */
 
 "use strict";
 
--- a/test/script/basic/list.js.EXPECTED	Wed Dec 10 14:36:00 2014 -0800
+++ b/test/script/basic/list.js.EXPECTED	Thu Dec 11 13:40:21 2014 -0800
@@ -10,7 +10,7 @@
 l[0]=foo
 l[1]=a
 l[0.9]=null
-l['blah']=null
+l['blah']=undefined
 l[size_name]()=2
 java.lang.IndexOutOfBoundsException: Index: 2, Size: 2
 java.lang.IndexOutOfBoundsException: Index: Infinity, Size: 2