Merge branch '8u152_1'
diff --git a/.hgtags b/.hgtags
index 03d9b9d..aac38dc 100644
--- a/.hgtags
+++ b/.hgtags
@@ -372,6 +372,7 @@
 c2dd88e89edc85b1bcb731d3296d0fcec1b78447 jdk8u40-b27
 e05552220ba82e465a1abfee90224b5b247e37bc jdk8u40-b31
 e1cc0fe0fd50fc4582e729897d7095ffce0f97ad jdk8u40-b32
+0130b5cb16e009195127cc13f828d6cf899fc4c7 jdk8u40-b33
 05a3614ed5276e5db2a73cce918be04b1a2922fb jdk8u45-b00
 21ec16eb7e6346c78b4fa67ccd6d2a9c58f0b696 jdk8u45-b01
 37b3ef9a07323afd2556d6837824db154cccc874 jdk8u45-b02
@@ -519,17 +520,26 @@
 81e48503b62fd8814135f642905fe38056aaf2a9 jdk8u72-b13
 e48d06eeff82bea512cea44fa14d59b88067ef83 jdk8u72-b14
 769b21d1b85cfb57c11c89bbc8f185f9e520df66 jdk8u72-b15
+c90794ad4d12eeeae5d9bbfce65fa0043a313548 jdk8u72-b31
 e9b46178f2e35d9ed2cd5b2f7279cf5e4e954222 jdk8u73-b00
 eeb5306edb7a0140117fe346782cce19c4c562a7 jdk8u73-b01
 955689d050b9f3f61b90ca063fe13704a82f5394 jdk8u73-b02
 2a36c3c61f905c5b389ae1d62f446e57f96be3a2 jdk8u74-b00
 ae6c74c1197afcbd83d393aa6f96221d759022a2 jdk8u74-b01
 3107cf87696f0516d6f5fa7cdc416069e2800d02 jdk8u74-b02
+4608bbcc94f73059680acd0f486744ff26485ee9 jdk8u74-b31
+7d0f4c8fc2754e25c1c148ff47bb79aa880c2874 jdk8u74-b32
+7bce03d47545e6a5341a2722168cd6bf697c4132 jdk8u77-b00
+678b645aa10aaf27895c87872c399c15daa026a1 jdk8u77-b01
+09abd795d1d143933224bcb3f12f5d4686b65373 jdk8u77-b02
+b6ee21a35619ce4d3b46a9b825438a3bc9bb63cd jdk8u77-b03
+961f73438a3cdacc6197663b2495b73c08805f24 jdk8u77-b31
 c90794ad4d12eeeae5d9bbfce65fa0043a313548 jdk8u72-b31
 c7eddafb2ee2cc9d62f20c4d821ccac03bd4617d jdk8u75-b00
 69fa156c1ebe6a8d6587147967e8e27f6de37d99 jdk8u75-b01
 9cce1ba325c4bd8e922380c911d1a9ace79d6717 jdk8u75-b02
 541de42b57098a5009055cc92f1139473e32f19d jdk8u75-b03
+16d657d6cb22e832139a1cbc2ec23a5cf9db8985 jdk8u101-b00
 16d657d6cb22e832139a1cbc2ec23a5cf9db8985 jdk8u75-b04
 dfa12474455fa6f4c48a6dee986c24db257161ad jdk8u75-b05
 1f85973e9533f7c9b1bae1e00b76a2184c5eed4c jdk8u75-b06
@@ -545,6 +555,7 @@
 a2c005a7b33abed886cfb4309a846dd80c87bd4e jdk8u91-b00
 22925b345dffe4ba96fe2f429c4185cda1b30239 jdk8u91-b13
 6296644a2c9c30db0062117fc776341e937ca1f9 jdk8u91-b14
+32b80df71ca2a6ae827ba7042cea868f40e0a0dd jdk8u91-b15
 7bce03d47545e6a5341a2722168cd6bf697c4132 jdk8u77-b00
 678b645aa10aaf27895c87872c399c15daa026a1 jdk8u77-b01
 09abd795d1d143933224bcb3f12f5d4686b65373 jdk8u77-b02
@@ -565,12 +576,100 @@
 256922f1e9e7648eb5af5a9da82ff8032b3855bc jdk8u92-b00
 e2294411edbda51165bc1a10261c246cb4d3c5c5 jdk8u92-b13
 d2af8d0297223ff16d59ee64b7058cafef8f3bb8 jdk8u92-b14
+ff47e8b14690edada1d0a4386e63bb4bc2f38ab4 jdk8u92-b31
+895bb16c7f9fe0c74317afef671a0d5ccde58afa jdk8u92-b32
+6c3f8e359668ec22e9c577d875cdb5a918534498 jdk8u92-b33
+59d90c3cc2bfdfda7664877d0e2529ef6c558558 jdk8u92-b34
+16d657d6cb22e832139a1cbc2ec23a5cf9db8985 jdk8u81-b00
+793156da7cc9c74489ab5fa5f5598bba172846e2 jdk8u101-b01
+79fc469a68bbe03f69919f4cebe0381df1b1d2a3 jdk8u101-b02
+d93088bdd15d507b35bc4ced85c6c748705511fc jdk8u101-b03
+9bd5aadd8e739d4ad4bb2e30741cdbe9ae2bae66 jdk8u101-b04
+a347853dbf17605c650532c4291bb9117d80f568 jdk8u101-b05
+3bc08e0d23a3965937e634d00e84ea69505e2653 jdk8u101-b06
+313c90baea02c1c8c162bea894c7adf6dc33a05b jdk8u101-b07
+926025d895a459bec2031a17e674c4aa5ebe6fe1 jdk8u101-b08
+47209e0bae1d65243158b3d8c2f6602cc265832c jdk8u101-b09
+740d8d604c0ef2b12d9835d2842f60dcc08fee0d jdk8u101-b10
+de5fdc537134ec505958a66d79c0ff68282520d2 jdk8u101-b11
+2f506194a131597352bbe1a08492266a8aed13f8 jdk8u101-b12
+44e4e6cbe15bf1674cfd7a03acfb962dd4339767 jdk8u101-b13
 120c1b8b458170ed017d2ee60cc9d63896eeb4b9 jdk8u102-b00
 120c1b8b458170ed017d2ee60cc9d63896eeb4b9 jdk8u82-b00
 79dcbdb92a8c39de6d1417557af9e6c2c03f806d jdk8u102-b01
 17416ae62bd720ebb53d20bb24272991084633bd jdk8u102-b02
 75728277aeee30f31c9418f37faf8f4216c539d7 jdk8u102-b03
 8ebcaf17bc745aa581aa8eff807da97f2f74058e jdk8u102-b04
+676a870491e5934e88d40cf2c68bef646c63b4ea jdk8u102-b05
+114e7557d33ce9e5f1bf982f45977a630c44d8a5 jdk8u102-b06
+13a10967cff181a71933a4f1508691553f43304b jdk8u102-b07
+31c898437a15f4feef6c1502d3f1eaf8a3d9de48 jdk8u102-b08
+e4f74a337545a0283f9b7bb6a85ce1b2c4a5fdd6 jdk8u102-b09
+3b84415442d7b4eaa4a7da75b9d428e81e8be575 jdk8u102-b10
+7bd6f4f266f66d32e4ce743928d7c4021c23c477 jdk8u102-b11
+e3db6994bbbd654be3ebd677b2cc80469f7133a3 jdk8u102-b12
+a010893ca6ee93c1a4832d1c484be6a119ca7ae4 jdk8u102-b13
+0948e61a3722ea7519323dffcce4f26430fe2881 jdk8u102-b14
+908d77c3a01687e99fb426cff41cf000f3f28e68 jdk8u102-b31
+4510fa72a613e8bd8b02f7519362de60907ca652 jdk8u102-b32
+36e3c21b5fcaaa138da59d3b1e72239a2c8b13f6 jdk8u102-b33
+de8a9d055c88ae9373a7be118231b7ccfc662ccb jdk8u102-b34
+8ee63d04b05cd961d6319d852fc0fc47a025ba28 jdk8u102-b35
+9bd5aadd8e739d4ad4bb2e30741cdbe9ae2bae66 jdk8u111-b00
+61e68e59fede0e4700e62b4899ef4553ecbe6bae jdk8u111-b01
+3c500f61258def21887e4026c37353745ce81ab5 jdk8u111-b02
+caf5e25a08571db612acd42b319f8e300e3aa0ee jdk8u111-b03
+b88377d4c4599c36d75352142086faa9ded042b8 jdk8u111-b04
+1a484cc1d2ed0540543b0af4ebb8ad83bcb1c667 jdk8u111-b05
+b70ae846275e5a237bdf4fe5a7299bf610374497 jdk8u111-b06
+7dae05ba63d4b98675d1e4488a714438d2afdf46 jdk8u111-b07
+56229b59fd80141f97e7af21ddfd7e59b4a5b445 jdk8u111-b08
+4465b272a90205f896378df45d8ae6c3d8671953 jdk8u111-b09
+9e3095f8930a8d8aa2c99f38a7d7507fb8fe7fb3 jdk8u111-b10
+c340ee5e5fd1d1a6ed57b3650ab46594dfccfc1d jdk8u111-b11
+76bf7299d622029f1a579667611deeccc405e81a jdk8u111-b12
+7ed1a5c5e45a1d576cc76dc96b3f0699bfe0a642 jdk8u111-b13
+97770cfdb942dce0a7c461175bce4fddac5ad339 jdk8u111-b14
 1bf96637e4bbbc31f7c560c16d62ce2ed9020e03 jdk8u112-b00
 be4ef6af7d3d67380d9df3348f75324ff6d8c971 jdk8u112-b01
 29f97057e4e10194263902a6406f65d789944c5e jdk8u112-b02
+16bc4cb8f50b251aa648c6aae5ca063c0893b44b jdk8u112-b03
+bc02dfd3deccefbcfcb71969ff56ae58ef80c686 jdk8u112-b04
+2432a2e9de108e12c3be6e52f37d7702a9a87d49 jdk8u112-b06
+d591fb5e1d37d1186290521cd31d5795d74cfa5b jdk8u112-b07
+910a02770fc92745517e63018345be36dc8d7d0c jdk8u112-b08
+51e59a0544a0be24ed72b43fc9483ffded8cdad2 jdk8u112-b09
+319eba518b6ec84fe3ff4811e66319cdb7e6f33e jdk8u112-b10
+081aa69ac6faaa8ebb9a21d9a0c617d34e03b447 jdk8u112-b11
+21b35ff81519584f5af010e852c14b6db88c1ebd jdk8u112-b12
+001041e75430b132f0e0ba96b98f3891435c4440 jdk8u112-b13
+b0aa9a71f5fbcb0d58fa009fd9bd3ea0897b315e jdk8u112-b14
+adc75eca17418a42357776339b390533a94541d6 jdk8u112-b15
+d1f2cab06d35f6b7ac29f5c3eebd74a74a01b8fb jdk8u112-b16
+d4beac03b1230ff8c96af79dcd10c56bdc475ebb jdk8u112-b31
+1a484cc1d2ed0540543b0af4ebb8ad83bcb1c667 jdk8u121-b00
+8f5fafa7e43b0b2472b077ea8f9b241976e1ea82 jdk8u121-b01
+33bf988e6f1a2a2fa1dcec66da79a5411df6dcd5 jdk8u121-b02
+112c17eb13c7c1952b9ccb377185268f77edc97e jdk8u121-b03
+31dad6c4e1be1b0ec7e4365932bb783c643b7c53 jdk8u121-b04
+465b06ac76296f329049a34d33d1ec00c800511b jdk8u121-b05
+c8fe62b47c8f065029c710e35aa61562b6550da1 jdk8u121-b06
+a32b4f984a18a7f9f6b412bf91c1a382df40d5ab jdk8u121-b07
+937cd79f7cfb27134f4ae24ad9f57bd1d9ed0f83 jdk8u121-b08
+3b222c098080d9fba2ad028b64e0edfef4d9dfcd jdk8u121-b09
+23970322bf063b36c0aefe103540618bb64a82af jdk8u121-b10
+fe53d09bdd8f4309ce3f79e9dc4c512639de2610 jdk8u121-b11
+89c0a71eeb4ae2011e7ed10f36e79b5184c7827b jdk8u121-b12
+fd548ea7e156aba26836084b838df5e90b90b6ba jdk8u121-b13
+18eb73eb84c5395b3efcafa43ce224565eca02b3 jdk8u122-b00
+9e615ea961fe5732813ed7b273606e7337ea2234 jdk8u122-b01
+2f0b11882cb7ddb10e35682ab9e8343919a71c54 jdk8u122-b02
+df2a2824284f97c5edb9b9c2e6d18bb4ff838199 jdk8u122-b03
+df2a2824284f97c5edb9b9c2e6d18bb4ff838199 jdk8u122-b03
+0000000000000000000000000000000000000000 jdk8u122-b03
+0000000000000000000000000000000000000000 jdk8u122-b03
+12650d23a8fd1b27a0d28c6a276fdecf01805294 jdk8u122-b03
+3c3b4e793e7c6255a840844db077ef466940035c jdk8u122-b04
+30dc0c72f3d0aff34b6d421208b18f384d05d761 jdk8u132-b00
+91d33aea2714e63796eeab0e63e38c9d2568c00c jdk8u152-b00
+50dac2fd8689dbb820d887ce3919708d5d042891 jdk8u152-b01
diff --git a/ASSEMBLY_EXCEPTION b/ASSEMBLY_EXCEPTION
index 8b7ac1d..065b8d9 100644
--- a/ASSEMBLY_EXCEPTION
+++ b/ASSEMBLY_EXCEPTION
@@ -1,27 +1,27 @@
 
 OPENJDK ASSEMBLY EXCEPTION
 
-The OpenJDK source code made available by Sun at openjdk.java.net and
-openjdk.dev.java.net ("OpenJDK Code") is distributed under the terms of the
-GNU General Public License <http://www.gnu.org/copyleft/gpl.html> version 2
+The OpenJDK source code made available by Oracle America, Inc. (Oracle) at
+openjdk.java.net ("OpenJDK Code") is distributed under the terms of the GNU
+General Public License <http://www.gnu.org/copyleft/gpl.html> version 2
 only ("GPL2"), with the following clarification and special exception.
 
     Linking this OpenJDK Code statically or dynamically with other code
     is making a combined work based on this library.  Thus, the terms
     and conditions of GPL2 cover the whole combination.
 
-    As a special exception, Sun gives you permission to link this
-    OpenJDK Code with certain code licensed by Sun as indicated at
+    As a special exception, Oracle gives you permission to link this
+    OpenJDK Code with certain code licensed by Oracle as indicated at
     http://openjdk.java.net/legal/exception-modules-2007-05-08.html
     ("Designated Exception Modules") to produce an executable,
     regardless of the license terms of the Designated Exception Modules,
     and to copy and distribute the resulting executable under GPL2,
     provided that the Designated Exception Modules continue to be
-    governed by the licenses under which they were offered by Sun.
+    governed by the licenses under which they were offered by Oracle.
 
-As such, it allows licensees and sublicensees of Sun's GPL2 OpenJDK Code to
-build an executable that includes those portions of necessary code that Sun
-could not provide under GPL2 (or that Sun has provided under GPL2 with the
-Classpath exception).  If you modify or add to the OpenJDK code, that new
-GPL2 code may still be combined with Designated Exception Modules if the
-new code is made subject to this exception by its copyright holder.
+As such, it allows licensees and sublicensees of Oracle's GPL2 OpenJDK Code
+to build an executable that includes those portions of necessary code that
+Oracle could not provide under GPL2 (or that Oracle has provided under GPL2
+with the Classpath exception).  If you modify or add to the OpenJDK code,
+that new GPL2 code may still be combined with Designated Exception Modules
+if the new code is made subject to this exception by its copyright holder.
diff --git a/src/jdk/nashorn/internal/codegen/CodeGenerator.java b/src/jdk/nashorn/internal/codegen/CodeGenerator.java
index 9e1148f..6b9b731 100644
--- a/src/jdk/nashorn/internal/codegen/CodeGenerator.java
+++ b/src/jdk/nashorn/internal/codegen/CodeGenerator.java
@@ -2454,11 +2454,6 @@
                     }
 
                     @Override
-                    public boolean enterObjectNode(final ObjectNode objectNode) {
-                        return false;
-                    }
-
-                    @Override
                     public boolean enterDefault(final Node node) {
                         if (contains) {
                             return false;
@@ -2526,7 +2521,8 @@
             oc = new FieldObjectCreator<Expression>(this, tuples) {
                 @Override
                 protected void loadValue(final Expression node, final Type type) {
-                    loadExpressionAsType(node, type);
+                    // Use generic type in order to avoid conversion between object types
+                    loadExpressionAsType(node, Type.generic(type));
                 }};
         }
 
@@ -2542,10 +2538,7 @@
         //handler
         if (restOfProperty) {
             final ContinuationInfo ci = getContinuationInfo();
-            // Can be set at most once for a single rest-of method
-            assert ci.getObjectLiteralMap() == null;
-            ci.setObjectLiteralMap(oc.getMap());
-            ci.setObjectLiteralStackDepth(method.getStackSize());
+            ci.setObjectLiteralMap(method.getStackSize(), oc.getMap());
         }
 
         method.dup();
@@ -4023,7 +4016,7 @@
                     void loadStack() {
                         assert assignNode.getWidestOperandType() == Type.INT;
                         if (isRhsZero(binaryNode)) {
-                            loadExpressionAsType(binaryNode.lhs(), Type.INT);
+                            loadExpression(binaryNode.lhs(), TypeBounds.INT, true);
                         } else {
                             loadBinaryOperands(binaryNode.lhs(), binaryNode.rhs(), TypeBounds.INT, true, false);
                             method.shr();
@@ -5259,10 +5252,8 @@
         private Type[] stackTypes;
         // If non-null, this node should perform the requisite type conversion
         private Type returnValueType;
-        // If we are in the middle of an object literal initialization, we need to update the map
-        private PropertyMap objectLiteralMap;
-        // Object literal stack depth for object literal - not necessarily top if property is a tree
-        private int objectLiteralStackDepth = -1;
+        // If we are in the middle of an object literal initialization, we need to update the property maps
+        private Map<Integer, PropertyMap> objectLiteralMaps;
         // The line number at the continuation point
         private int lineNumber;
         // The active catch label, in case the continuation point is in a try/catch block
@@ -5314,20 +5305,15 @@
             this.returnValueType = returnValueType;
         }
 
-        int getObjectLiteralStackDepth() {
-            return objectLiteralStackDepth;
+        void setObjectLiteralMap(final int objectLiteralStackDepth, final PropertyMap objectLiteralMap) {
+            if (objectLiteralMaps == null) {
+                objectLiteralMaps = new HashMap<>();
+            }
+            objectLiteralMaps.put(objectLiteralStackDepth, objectLiteralMap);
         }
 
-        void setObjectLiteralStackDepth(final int objectLiteralStackDepth) {
-            this.objectLiteralStackDepth = objectLiteralStackDepth;
-        }
-
-        PropertyMap getObjectLiteralMap() {
-            return objectLiteralMap;
-        }
-
-        void setObjectLiteralMap(final PropertyMap objectLiteralMap) {
-            this.objectLiteralMap = objectLiteralMap;
+        PropertyMap getObjectLiteralMap(final int stackDepth) {
+            return objectLiteralMaps == null ? null : objectLiteralMaps.get(stackDepth);
         }
 
         @Override
@@ -5417,10 +5403,9 @@
         final int[]   stackStoreSpec = ci.getStackStoreSpec();
         final Type[]  stackTypes     = ci.getStackTypes();
         final boolean isStackEmpty   = stackStoreSpec.length == 0;
-        boolean replacedObjectLiteralMap = false;
+        int replacedObjectLiteralMaps = 0;
         if(!isStackEmpty) {
             // Load arguments on the stack
-            final int objectLiteralStackDepth = ci.getObjectLiteralStackDepth();
             for(int i = 0; i < stackStoreSpec.length; ++i) {
                 final int slot = stackStoreSpec[i];
                 method.load(lvarTypes.get(slot), slot);
@@ -5428,18 +5413,18 @@
                 // stack: s0=object literal being initialized
                 // change map of s0 so that the property we are initializing when we failed
                 // is now ci.returnValueType
-                if (i == objectLiteralStackDepth) {
+                final PropertyMap map = ci.getObjectLiteralMap(i);
+                if (map != null) {
                     method.dup();
-                    assert ci.getObjectLiteralMap() != null;
                     assert ScriptObject.class.isAssignableFrom(method.peekType().getTypeClass()) : method.peekType().getTypeClass() + " is not a script object";
-                    loadConstant(ci.getObjectLiteralMap());
+                    loadConstant(map);
                     method.invoke(ScriptObject.SET_MAP);
-                    replacedObjectLiteralMap = true;
+                    replacedObjectLiteralMaps++;
                 }
             }
         }
-        // Must have emitted the code for replacing the map of an object literal if we have a set object literal stack depth
-        assert ci.getObjectLiteralStackDepth() == -1 || replacedObjectLiteralMap;
+        // Must have emitted the code for replacing all object literal maps
+        assert ci.objectLiteralMaps == null || ci.objectLiteralMaps.size() == replacedObjectLiteralMaps;
         // Load RewriteException back.
         method.load(rewriteExceptionType, lvarCount);
         // Get rid of the stored reference
diff --git a/src/jdk/nashorn/internal/codegen/LocalVariableTypesCalculator.java b/src/jdk/nashorn/internal/codegen/LocalVariableTypesCalculator.java
index 310a087..63bafa7 100644
--- a/src/jdk/nashorn/internal/codegen/LocalVariableTypesCalculator.java
+++ b/src/jdk/nashorn/internal/codegen/LocalVariableTypesCalculator.java
@@ -33,6 +33,7 @@
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.Deque;
+import java.util.HashMap;
 import java.util.HashSet;
 import java.util.IdentityHashMap;
 import java.util.Iterator;
@@ -122,9 +123,9 @@
         private final List<JumpOrigin> origins = new LinkedList<>();
         private Map<Symbol, LvarType> types = Collections.emptyMap();
 
-        void addOrigin(final JoinPredecessor originNode, final Map<Symbol, LvarType> originTypes) {
+        void addOrigin(final JoinPredecessor originNode, final Map<Symbol, LvarType> originTypes, final LocalVariableTypesCalculator calc) {
             origins.add(new JumpOrigin(originNode, originTypes));
-            this.types = getUnionTypes(this.types, originTypes);
+            this.types = calc.getUnionTypes(this.types, originTypes);
         }
     }
     private enum LvarType {
@@ -185,12 +186,15 @@
     }
 
     @SuppressWarnings("unchecked")
-    private static IdentityHashMap<Symbol, LvarType> cloneMap(final Map<Symbol, LvarType> map) {
-        return (IdentityHashMap<Symbol, LvarType>)((IdentityHashMap<?,?>)map).clone();
+    private static HashMap<Symbol, LvarType> cloneMap(final Map<Symbol, LvarType> map) {
+        return (HashMap<Symbol, LvarType>)((HashMap<?,?>)map).clone();
     }
 
     private LocalVariableConversion createConversion(final Symbol symbol, final LvarType branchLvarType,
             final Map<Symbol, LvarType> joinLvarTypes, final LocalVariableConversion next) {
+        if (invalidatedSymbols.contains(symbol)) {
+            return next;
+        }
         final LvarType targetType = joinLvarTypes.get(symbol);
         assert targetType != null;
         if(targetType == branchLvarType) {
@@ -208,7 +212,7 @@
         return new LocalVariableConversion(symbol, branchLvarType.type, targetType.type, next);
     }
 
-    private static Map<Symbol, LvarType> getUnionTypes(final Map<Symbol, LvarType> types1, final Map<Symbol, LvarType> types2) {
+    private Map<Symbol, LvarType> getUnionTypes(final Map<Symbol, LvarType> types1, final Map<Symbol, LvarType> types2) {
         if(types1 == types2 || types1.isEmpty()) {
             return types2;
         } else if(types2.isEmpty()) {
@@ -261,6 +265,11 @@
             final LvarType type2 = types2.get(symbol);
             union.put(symbol, widestLvarType(type1,  type2));
         }
+        // If the two sets of symbols differ, there's a good chance that some of
+        // symbols only appearing in one of the sets are lexically invalidated,
+        // so we remove them from further consideration.
+        // This is not strictly necessary, just a working set size optimization.
+        union.keySet().removeAll(invalidatedSymbols);
         return union;
     }
 
@@ -359,8 +368,6 @@
         if(t1.ordinal() < LvarType.INT.ordinal() || t2.ordinal() < LvarType.INT.ordinal()) {
             return LvarType.OBJECT;
         }
-        // NOTE: we allow "widening" of long to double even though it can lose precision. ECMAScript doesn't have an
-        // Int64 type anyway, so this loss of precision is actually more conformant to the specification...
         return LvarType.values()[Math.max(t1.ordinal(), t2.ordinal())];
     }
     private final Compiler compiler;
@@ -368,7 +375,10 @@
     // Local variable type mapping at the currently evaluated point. No map instance is ever modified; setLvarType() always
     // allocates a new map. Immutability of maps allows for cheap snapshots by just keeping the reference to the current
     // value.
-    private Map<Symbol, LvarType> localVariableTypes = new IdentityHashMap<>();
+    private Map<Symbol, LvarType> localVariableTypes = Collections.emptyMap();
+    // Set of symbols whose lexical scope has already ended.
+    private final Set<Symbol> invalidatedSymbols = new HashSet<>();
+
     // Stack for evaluated expression types.
     private final Deque<LvarType> typeStack = new ArrayDeque<>();
 
@@ -464,9 +474,19 @@
 
     @Override
     public boolean enterBlock(final Block block) {
+        boolean cloned = false;
         for(final Symbol symbol: block.getSymbols()) {
-            if(symbol.isBytecodeLocal() && getLocalVariableTypeOrNull(symbol) == null) {
-                setType(symbol, LvarType.UNDEFINED);
+            if(symbol.isBytecodeLocal()) {
+                if (getLocalVariableTypeOrNull(symbol) == null) {
+                    if (!cloned) {
+                        cloneOrNewLocalVariableTypes();
+                        cloned = true;
+                    }
+                    localVariableTypes.put(symbol, LvarType.UNDEFINED);
+                }
+                // In case we're repeating analysis of a lexical scope (e.g. it's in a loop),
+                // make sure all symbols lexically scoped by the block become valid again.
+                invalidatedSymbols.remove(symbol);
             }
         }
         return true;
@@ -1046,15 +1066,11 @@
             // throw an exception.
             reachable = true;
             catchBody.accept(this);
-            final Symbol exceptionSymbol = exception.getSymbol();
             if(reachable) {
-                localVariableTypes = cloneMap(localVariableTypes);
-                localVariableTypes.remove(exceptionSymbol);
                 jumpToLabel(catchBody, endLabel);
                 canExit = true;
             }
-            localVariableTypes = cloneMap(afterConditionTypes);
-            localVariableTypes.remove(exceptionSymbol);
+            localVariableTypes = afterConditionTypes;
         }
         // NOTE: if we had one or more conditional catch blocks with no unconditional catch block following them, then
         // there will be an unconditional rethrow, so the join point can never be reached from the last
@@ -1204,7 +1220,7 @@
     }
 
     private void jumpToLabel(final JoinPredecessor jumpOrigin, final Label label, final Map<Symbol, LvarType> types) {
-        getOrCreateJumpTarget(label).addOrigin(jumpOrigin, types);
+        getOrCreateJumpTarget(label).addOrigin(jumpOrigin, types, this);
     }
 
     @Override
@@ -1226,16 +1242,18 @@
 
         boolean cloned = false;
         for(final Symbol symbol: block.getSymbols()) {
-            // Undefine the symbol outside the block
-            if(localVariableTypes.containsKey(symbol)) {
-                if(!cloned) {
-                    localVariableTypes = cloneMap(localVariableTypes);
-                    cloned = true;
-                }
-                localVariableTypes.remove(symbol);
-            }
-
             if(symbol.hasSlot()) {
+                // Invalidate the symbol when its defining block ends
+                if (symbol.isBytecodeLocal()) {
+                    if(localVariableTypes.containsKey(symbol)) {
+                        if(!cloned) {
+                            localVariableTypes = cloneMap(localVariableTypes);
+                            cloned = true;
+                        }
+                    }
+                    invalidateSymbol(symbol);
+                }
+
                 final SymbolConversions conversions = symbolConversions.get(symbol);
                 if(conversions != null) {
                     // Potentially make some currently dead types live if they're needed as a source of a type
@@ -1605,10 +1623,19 @@
         }
         assert symbol.hasSlot();
         assert !symbol.isGlobal();
-        localVariableTypes = localVariableTypes.isEmpty() ? new IdentityHashMap<Symbol, LvarType>() : cloneMap(localVariableTypes);
+        cloneOrNewLocalVariableTypes();
         localVariableTypes.put(symbol, type);
     }
 
+    private void cloneOrNewLocalVariableTypes() {
+        localVariableTypes = localVariableTypes.isEmpty() ? new HashMap<Symbol, LvarType>() : cloneMap(localVariableTypes);
+    }
+
+    private void invalidateSymbol(final Symbol symbol) {
+        localVariableTypes.remove(symbol);
+        invalidatedSymbols.add(symbol);
+    }
+
     /**
      * Set a flag in the symbol marking it as needing to be able to store a value of a particular type. Every symbol for
      * a local variable will be assigned between 1 and 6 local variable slots for storing all types it is known to need
diff --git a/src/jdk/nashorn/internal/codegen/SpillObjectCreator.java b/src/jdk/nashorn/internal/codegen/SpillObjectCreator.java
index 3783ad8..22dc72e 100644
--- a/src/jdk/nashorn/internal/codegen/SpillObjectCreator.java
+++ b/src/jdk/nashorn/internal/codegen/SpillObjectCreator.java
@@ -188,7 +188,8 @@
 
     @Override
     protected void loadValue(final Expression expr, final Type type) {
-        codegen.loadExpressionAsType(expr, type);
+        // Use generic type in order to avoid conversion between object types
+        codegen.loadExpressionAsType(expr, Type.generic(type));
     }
 
     @Override
diff --git a/src/jdk/nashorn/internal/ir/debug/PrintVisitor.java b/src/jdk/nashorn/internal/ir/debug/PrintVisitor.java
index bb8d61a..fccad15 100644
--- a/src/jdk/nashorn/internal/ir/debug/PrintVisitor.java
+++ b/src/jdk/nashorn/internal/ir/debug/PrintVisitor.java
@@ -397,7 +397,7 @@
 
     @Override
     public boolean enterVarNode(final VarNode varNode) {
-        sb.append("var ");
+        sb.append(varNode.isConst() ? "const " : varNode.isLet() ? "let " : "var ");
         varNode.getName().toString(sb, printTypes);
         printLocalVariableConversion(varNode.getName());
         final Node init = varNode.getInit();
diff --git a/src/jdk/nashorn/internal/runtime/JSType.java b/src/jdk/nashorn/internal/runtime/JSType.java
index 9ca599c..89e5cb5 100644
--- a/src/jdk/nashorn/internal/runtime/JSType.java
+++ b/src/jdk/nashorn/internal/runtime/JSType.java
@@ -457,6 +457,8 @@
             return toPrimitive((ScriptObject)obj, hint);
         } else if (isPrimitive(obj)) {
             return obj;
+        } else if (hint == Number.class && obj instanceof Number) {
+            return ((Number) obj).doubleValue();
         } else if (obj instanceof JSObject) {
             return toPrimitive((JSObject)obj, hint);
         } else if (obj instanceof StaticClass) {
diff --git a/src/jdk/nashorn/internal/runtime/arrays/ArrayData.java b/src/jdk/nashorn/internal/runtime/arrays/ArrayData.java
index 331a8f5..7966659 100644
--- a/src/jdk/nashorn/internal/runtime/arrays/ArrayData.java
+++ b/src/jdk/nashorn/internal/runtime/arrays/ArrayData.java
@@ -107,14 +107,13 @@
 
         @Override
         public ArrayData ensure(final long safeIndex) {
-            if (safeIndex > 0L) {
-                if (safeIndex >= SparseArrayData.MAX_DENSE_LENGTH) {
-                    return new SparseArrayData(this, safeIndex + 1);
-                }
-                //known to fit in int
-                return toRealArrayData((int)safeIndex);
-           }
-           return this;
+            assert safeIndex >= 0L;
+            if (safeIndex >= SparseArrayData.MAX_DENSE_LENGTH) {
+                return new SparseArrayData(this, safeIndex + 1);
+            }
+            //known to fit in int
+            return toRealArrayData((int)safeIndex);
+
         }
 
         @Override
@@ -133,8 +132,8 @@
         }
 
         @Override
-        public void shiftLeft(final int by) {
-            //nop, always empty or we wouldn't be of this class
+        public ArrayData shiftLeft(final int by) {
+            return this; //nop, always empty or we wouldn't be of this class
         }
 
         @Override
@@ -451,13 +450,13 @@
     /**
      * Shift the array data left
      *
-     * TODO: explore start at an index and not at zero, to make these operations
-     * even faster. Offset everything from the index. Costs memory but is probably
-     * worth it
+     * TODO: This is used for Array.prototype.shift() which only shifts by 1,
+     * so we might consider dropping the offset parameter.
      *
      * @param by offset to shift
+     * @return New arraydata (or same)
      */
-    public abstract void shiftLeft(final int by);
+    public abstract ArrayData shiftLeft(final int by);
 
     /**
      * Shift the array right
diff --git a/src/jdk/nashorn/internal/runtime/arrays/ArrayFilter.java b/src/jdk/nashorn/internal/runtime/arrays/ArrayFilter.java
index 19ecec2..47e6454 100644
--- a/src/jdk/nashorn/internal/runtime/arrays/ArrayFilter.java
+++ b/src/jdk/nashorn/internal/runtime/arrays/ArrayFilter.java
@@ -68,9 +68,10 @@
     }
 
     @Override
-    public void shiftLeft(final int by) {
+    public ArrayData shiftLeft(final int by) {
         underlying.shiftLeft(by);
         setLength(underlying.length());
+        return this;
     }
 
     @Override
diff --git a/src/jdk/nashorn/internal/runtime/arrays/ByteBufferArrayData.java b/src/jdk/nashorn/internal/runtime/arrays/ByteBufferArrayData.java
index f18b4a4..2b03265 100644
--- a/src/jdk/nashorn/internal/runtime/arrays/ByteBufferArrayData.java
+++ b/src/jdk/nashorn/internal/runtime/arrays/ByteBufferArrayData.java
@@ -82,7 +82,7 @@
     }
 
     @Override
-    public void shiftLeft(final int by) {
+    public ArrayData shiftLeft(final int by) {
         throw unsupported("shiftLeft");
     }
 
diff --git a/src/jdk/nashorn/internal/runtime/arrays/DeletedArrayFilter.java b/src/jdk/nashorn/internal/runtime/arrays/DeletedArrayFilter.java
index bd706c7..62e1ced 100644
--- a/src/jdk/nashorn/internal/runtime/arrays/DeletedArrayFilter.java
+++ b/src/jdk/nashorn/internal/runtime/arrays/DeletedArrayFilter.java
@@ -76,9 +76,10 @@
     }
 
     @Override
-    public void shiftLeft(final int by) {
+    public ArrayData shiftLeft(final int by) {
         super.shiftLeft(by);
         deleted.shiftLeft(by, length());
+        return this;
     }
 
     @Override
diff --git a/src/jdk/nashorn/internal/runtime/arrays/DeletedRangeArrayFilter.java b/src/jdk/nashorn/internal/runtime/arrays/DeletedRangeArrayFilter.java
index 7a6f098..d471031 100644
--- a/src/jdk/nashorn/internal/runtime/arrays/DeletedRangeArrayFilter.java
+++ b/src/jdk/nashorn/internal/runtime/arrays/DeletedRangeArrayFilter.java
@@ -101,10 +101,12 @@
     }
 
     @Override
-    public void shiftLeft(final int by) {
+    public ArrayData shiftLeft(final int by) {
         super.shiftLeft(by);
         lo = Math.max(0, lo - by);
         hi = Math.max(-1, hi - by);
+
+        return isEmpty() ? getUnderlying() : this;
     }
 
     @Override
diff --git a/src/jdk/nashorn/internal/runtime/arrays/IntArrayData.java b/src/jdk/nashorn/internal/runtime/arrays/IntArrayData.java
index b157e09..0f7d245 100644
--- a/src/jdk/nashorn/internal/runtime/arrays/IntArrayData.java
+++ b/src/jdk/nashorn/internal/runtime/arrays/IntArrayData.java
@@ -176,8 +176,15 @@
     }
 
     @Override
-    public void shiftLeft(final int by) {
-        System.arraycopy(array, by, array, 0, array.length - by);
+    public ArrayData shiftLeft(final int by) {
+        if (by >= length()) {
+            shrink(0);
+        } else {
+            System.arraycopy(array, by, array, 0, array.length - by);
+        }
+        setLength(Math.max(0, length() - by));
+
+        return this;
     }
 
     @Override
diff --git a/src/jdk/nashorn/internal/runtime/arrays/NumberArrayData.java b/src/jdk/nashorn/internal/runtime/arrays/NumberArrayData.java
index 7276b9a..9f3e866 100644
--- a/src/jdk/nashorn/internal/runtime/arrays/NumberArrayData.java
+++ b/src/jdk/nashorn/internal/runtime/arrays/NumberArrayData.java
@@ -121,8 +121,14 @@
     }
 
     @Override
-    public void shiftLeft(final int by) {
-        System.arraycopy(array, by, array, 0, array.length - by);
+    public ArrayData shiftLeft(final int by) {
+        if (by >= length()) {
+            shrink(0);
+        } else {
+            System.arraycopy(array, by, array, 0, array.length - by);
+        }
+        setLength(Math.max(0, length() - by));
+        return this;
     }
 
     @Override
diff --git a/src/jdk/nashorn/internal/runtime/arrays/ObjectArrayData.java b/src/jdk/nashorn/internal/runtime/arrays/ObjectArrayData.java
index cb99de8..027bd6b 100644
--- a/src/jdk/nashorn/internal/runtime/arrays/ObjectArrayData.java
+++ b/src/jdk/nashorn/internal/runtime/arrays/ObjectArrayData.java
@@ -98,8 +98,14 @@
     }
 
     @Override
-    public void shiftLeft(final int by) {
-        System.arraycopy(array, by, array, 0, array.length - by);
+    public ArrayData shiftLeft(final int by) {
+        if (by >= length()) {
+            shrink(0);
+        } else {
+            System.arraycopy(array, by, array, 0, array.length - by);
+        }
+        setLength(Math.max(0, length() - by));
+        return this;
     }
 
     @Override
diff --git a/src/jdk/nashorn/internal/runtime/arrays/SparseArrayData.java b/src/jdk/nashorn/internal/runtime/arrays/SparseArrayData.java
index 4d32bd4..26d89d4 100644
--- a/src/jdk/nashorn/internal/runtime/arrays/SparseArrayData.java
+++ b/src/jdk/nashorn/internal/runtime/arrays/SparseArrayData.java
@@ -36,7 +36,8 @@
  * Handle arrays where the index is very large.
  */
 class SparseArrayData extends ArrayData {
-    static final int MAX_DENSE_LENGTH = 1024 * 1024;
+    /** Maximum size for dense arrays */
+    static final int MAX_DENSE_LENGTH = 128 * 1024;
 
     /** Underlying array. */
     private ArrayData underlying;
@@ -51,11 +52,11 @@
         this(underlying, length, new TreeMap<Long, Object>());
     }
 
-    SparseArrayData(final ArrayData underlying, final long length, final TreeMap<Long, Object> sparseMap) {
+    private SparseArrayData(final ArrayData underlying, final long length, final TreeMap<Long, Object> sparseMap) {
         super(length);
         assert underlying.length() <= length;
         this.underlying = underlying;
-        this.maxDenseLength = Math.max(MAX_DENSE_LENGTH, underlying.length());
+        this.maxDenseLength = underlying.length();
         this.sparseMap = sparseMap;
     }
 
@@ -89,38 +90,49 @@
     }
 
     @Override
-    public void shiftLeft(final int by) {
-        underlying.shiftLeft(by);
+    public ArrayData shiftLeft(final int by) {
+        underlying = underlying.shiftLeft(by);
 
         final TreeMap<Long, Object> newSparseMap = new TreeMap<>();
 
         for (final Map.Entry<Long, Object> entry : sparseMap.entrySet()) {
             final long newIndex = entry.getKey().longValue() - by;
-            if (newIndex < maxDenseLength) {
-                underlying = underlying.set((int) newIndex, entry.getValue(), false);
-            } else if (newIndex >= 0) {
-                newSparseMap.put(Long.valueOf(newIndex), entry.getValue());
+            if (newIndex >= 0) {
+                if (newIndex < maxDenseLength) {
+                    final long oldLength = underlying.length();
+                    underlying = underlying.ensure(newIndex)
+                            .set((int) newIndex, entry.getValue(), false)
+                            .safeDelete(oldLength, newIndex - 1, false);
+                } else {
+                    newSparseMap.put(Long.valueOf(newIndex), entry.getValue());
+                }
             }
         }
 
         sparseMap = newSparseMap;
         setLength(Math.max(length() - by, 0));
+
+        return sparseMap.isEmpty() ? underlying : this;
     }
 
     @Override
     public ArrayData shiftRight(final int by) {
         final TreeMap<Long, Object> newSparseMap = new TreeMap<>();
+        // Move elements from underlying to sparse map if necessary
         final long len = underlying.length();
         if (len + by > maxDenseLength) {
-            for (long i = maxDenseLength - by; i < len; i++) {
+            // Length of underlying array after shrinking, before right-shifting
+            final long tempLength = Math.max(0, maxDenseLength - by);
+            for (long i = tempLength; i < len; i++) {
                 if (underlying.has((int) i)) {
                     newSparseMap.put(Long.valueOf(i + by), underlying.getObject((int) i));
                 }
             }
-            underlying = underlying.shrink((int) (maxDenseLength - by));
+            underlying = underlying.shrink((int) tempLength);
+            underlying.setLength(tempLength);
         }
 
-        underlying.shiftRight(by);
+        underlying = underlying.shiftRight(by);
 
         for (final Map.Entry<Long, Object> entry : sparseMap.entrySet()) {
             final long newIndex = entry.getKey().longValue() + by;
@@ -135,14 +147,6 @@
 
     @Override
     public ArrayData ensure(final long safeIndex) {
-        // Usually #ensure only needs to be called if safeIndex is greater or equal current length.
-        // SparseArrayData is an exception as an index smaller than our current length may still
-        // exceed the underlying ArrayData's capacity. Because of this, SparseArrayData invokes
-        // its ensure method internally in various places where other ArrayData subclasses don't,
-        // making it safe for outside uses to only call ensure(safeIndex) if safeIndex >= length.
-        if (safeIndex < maxDenseLength && underlying.length() <= safeIndex) {
-            underlying = underlying.ensure(safeIndex);
-        }
         if (safeIndex >= length()) {
             setLength(safeIndex + 1);
         }
@@ -167,8 +171,7 @@
     public ArrayData set(final int index, final Object value, final boolean strict) {
         if (index >= 0 && index < maxDenseLength) {
             final long oldLength = underlying.length();
-            ensure(index);
-            underlying = underlying.set(index, value, strict).safeDelete(oldLength, index - 1, strict);
+            underlying = underlying.ensure(index).set(index, value, strict).safeDelete(oldLength, index - 1, strict);
             setLength(Math.max(underlying.length(), length()));
         } else {
             final Long longIndex = indexToKey(index);
@@ -183,8 +186,7 @@
     public ArrayData set(final int index, final int value, final boolean strict) {
         if (index >= 0 && index < maxDenseLength) {
             final long oldLength = underlying.length();
-            ensure(index);
-            underlying = underlying.set(index, value, strict).safeDelete(oldLength, index - 1, strict);
+            underlying = underlying.ensure(index).set(index, value, strict).safeDelete(oldLength, index - 1, strict);
             setLength(Math.max(underlying.length(), length()));
         } else {
             final Long longIndex = indexToKey(index);
@@ -198,8 +200,7 @@
     public ArrayData set(final int index, final double value, final boolean strict) {
         if (index >= 0 && index < maxDenseLength) {
             final long oldLength = underlying.length();
-            ensure(index);
-            underlying = underlying.set(index, value, strict).safeDelete(oldLength, index - 1, strict);
+            underlying = underlying.ensure(index).set(index, value, strict).safeDelete(oldLength, index - 1, strict);
             setLength(Math.max(underlying.length(), length()));
         } else {
             final Long longIndex = indexToKey(index);
diff --git a/src/jdk/nashorn/internal/runtime/arrays/TypedArrayData.java b/src/jdk/nashorn/internal/runtime/arrays/TypedArrayData.java
index 56b9157..55e26b2 100644
--- a/src/jdk/nashorn/internal/runtime/arrays/TypedArrayData.java
+++ b/src/jdk/nashorn/internal/runtime/arrays/TypedArrayData.java
@@ -98,7 +98,7 @@
     }
 
     @Override
-    public void shiftLeft(final int by) {
+    public ArrayData shiftLeft(final int by) {
         throw new UnsupportedOperationException();
     }
 
diff --git a/src/jdk/nashorn/internal/runtime/arrays/UndefinedArrayFilter.java b/src/jdk/nashorn/internal/runtime/arrays/UndefinedArrayFilter.java
index 977b9e9..c6b1bd9 100644
--- a/src/jdk/nashorn/internal/runtime/arrays/UndefinedArrayFilter.java
+++ b/src/jdk/nashorn/internal/runtime/arrays/UndefinedArrayFilter.java
@@ -77,9 +77,10 @@
     }
 
     @Override
-    public void shiftLeft(final int by) {
+    public ArrayData shiftLeft(final int by) {
         super.shiftLeft(by);
         undefined.shiftLeft(by, length());
+        return this;
     }
 
     @Override
diff --git a/src/jdk/nashorn/internal/runtime/linker/JSObjectLinker.java b/src/jdk/nashorn/internal/runtime/linker/JSObjectLinker.java
index e8e493b..8de9197 100644
--- a/src/jdk/nashorn/internal/runtime/linker/JSObjectLinker.java
+++ b/src/jdk/nashorn/internal/runtime/linker/JSObjectLinker.java
@@ -39,9 +39,13 @@
 import jdk.internal.dynalink.linker.TypeBasedGuardingDynamicLinker;
 import jdk.internal.dynalink.support.CallSiteDescriptorFactory;
 import jdk.nashorn.api.scripting.JSObject;
+import jdk.nashorn.api.scripting.ScriptObjectMirror;
 import jdk.nashorn.internal.lookup.MethodHandleFactory;
 import jdk.nashorn.internal.lookup.MethodHandleFunctionality;
+import jdk.nashorn.internal.runtime.Context;
 import jdk.nashorn.internal.runtime.JSType;
+import jdk.nashorn.internal.runtime.ScriptRuntime;
+import jdk.nashorn.internal.objects.Global;
 
 /**
  * A Dynalink linker to handle web browser built-in JS (DOM etc.) objects as well
@@ -141,9 +145,9 @@
     }
 
     private static GuardedInvocation findCallMethod(final CallSiteDescriptor desc) {
-        MethodHandle mh = JSOBJECT_CALL;
+        MethodHandle mh = NashornCallSiteDescriptor.isScope(desc)? JSOBJECT_SCOPE_CALL : JSOBJECT_CALL;
         if (NashornCallSiteDescriptor.isApplyToCall(desc)) {
-            mh = MH.insertArguments(JSOBJECT_CALL_TO_APPLY, 0, JSOBJECT_CALL);
+            mh = MH.insertArguments(JSOBJECT_CALL_TO_APPLY, 0, mh);
         }
         final MethodType type = desc.getMethodType();
         mh = type.parameterType(type.parameterCount() - 1) == Object[].class ?
@@ -171,6 +175,8 @@
             final int index = getIndex((Number)key);
             if (index > -1) {
                 return ((JSObject)jsobj).getSlot(index);
+            } else {
+                return ((JSObject)jsobj).getMember(JSType.toString(key));
             }
         } else if (isString(key)) {
             final String name = key.toString();
@@ -188,7 +194,12 @@
         if (key instanceof Integer) {
             ((JSObject)jsobj).setSlot((Integer)key, value);
         } else if (key instanceof Number) {
-            ((JSObject)jsobj).setSlot(getIndex((Number)key), value);
+            final int index = getIndex((Number)key);
+            if (index > -1) {
+                ((JSObject)jsobj).setSlot(index, value);
+            } else {
+                ((JSObject)jsobj).setMember(JSType.toString(key), value);
+            }
         } else if (isString(key)) {
             ((JSObject)jsobj).setMember(key.toString(), value);
         }
@@ -214,6 +225,19 @@
         }
     }
 
+    // This is used when a JSObject is called as scope call to do undefined -> Global this translation.
+    @SuppressWarnings("unused")
+    private static Object jsObjectScopeCall(final JSObject jsObj, final Object thiz, final Object[] args) {
+        final Object modifiedThiz;
+        if (thiz == ScriptRuntime.UNDEFINED && !jsObj.isStrictFunction()) {
+            final Global global = Context.getGlobal();
+            modifiedThiz = ScriptObjectMirror.wrap(global, global);
+        } else {
+            modifiedThiz = thiz;
+        }
+        return jsObj.call(modifiedThiz, args);
+    }
+
     private static final MethodHandleFunctionality MH = MethodHandleFactory.getFunctionality();
 
     // method handles of the current class
@@ -225,6 +249,7 @@
     private static final MethodHandle JSOBJECT_GETMEMBER     = findJSObjectMH_V("getMember", Object.class, String.class);
     private static final MethodHandle JSOBJECT_SETMEMBER     = findJSObjectMH_V("setMember", Void.TYPE, String.class, Object.class);
     private static final MethodHandle JSOBJECT_CALL          = findJSObjectMH_V("call", Object.class, Object.class, Object[].class);
+    private static final MethodHandle JSOBJECT_SCOPE_CALL    = findOwnMH_S("jsObjectScopeCall", Object.class, JSObject.class, Object.class, Object[].class);
     private static final MethodHandle JSOBJECT_CALL_TO_APPLY = findOwnMH_S("callToApply", Object.class, MethodHandle.class, JSObject.class, Object.class, Object[].class);
     private static final MethodHandle JSOBJECT_NEW           = findJSObjectMH_V("newObject", Object.class, Object[].class);
 
diff --git a/src/jdk/nashorn/internal/runtime/linker/NashornLinker.java b/src/jdk/nashorn/internal/runtime/linker/NashornLinker.java
index ddcbae1..b8e01ff 100644
--- a/src/jdk/nashorn/internal/runtime/linker/NashornLinker.java
+++ b/src/jdk/nashorn/internal/runtime/linker/NashornLinker.java
@@ -251,15 +251,15 @@
     @Override
     public Comparison compareConversion(final Class<?> sourceType, final Class<?> targetType1, final Class<?> targetType2) {
         if(sourceType == NativeArray.class) {
-            // Prefer lists, as they're less costly to create than arrays.
-            if(isList(targetType1)) {
-                if(!isList(targetType2)) {
+            // Prefer those types we can convert to with just a wrapper (cheaper than Java array creation).
+            if(isArrayPreferredTarget(targetType1)) {
+                if(!isArrayPreferredTarget(targetType2)) {
                     return Comparison.TYPE_1_BETTER;
                 }
-            } else if(isList(targetType2)) {
+            } else if(isArrayPreferredTarget(targetType2)) {
                 return Comparison.TYPE_2_BETTER;
             }
-            // Then prefer arrays
+            // Then prefer Java arrays
             if(targetType1.isArray()) {
                 if(!targetType2.isArray()) {
                     return Comparison.TYPE_1_BETTER;
@@ -281,8 +281,8 @@
         return Comparison.INDETERMINATE;
     }
 
-    private static boolean isList(final Class<?> clazz) {
-        return clazz == List.class || clazz == Deque.class;
+    private static boolean isArrayPreferredTarget(final Class<?> clazz) {
+        return clazz == List.class || clazz == Collection.class || clazz == Queue.class || clazz == Deque.class;
     }
 
     private static final MethodHandle IS_SCRIPT_OBJECT = Guards.isInstance(ScriptObject.class, MH.type(Boolean.TYPE, Object.class));
diff --git a/test/script/basic/JDK-8163945.js b/test/script/basic/JDK-8163945.js
new file mode 100644
index 0000000..781dd94
--- /dev/null
+++ b/test/script/basic/JDK-8163945.js
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2016, 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-8163945: Honor Number type hint in toPrimitive on Numbers
+ *
+ * @test
+ * @run
+ */
+
+function assertLessThan(a, b) {
+    Assert.assertTrue(a < b);
+    Assert.assertTrue(a <= b);
+    Assert.assertFalse(a >= b);
+    Assert.assertFalse(a > b);
+}
+
+assertLessThan(new java.lang.Long(2), new java.lang.Long(10));
+assertLessThan(new java.lang.Long(2), 10);
+assertLessThan(2, new java.lang.Long(10));
+
+assertLessThan(new java.math.BigInteger(2), new java.math.BigInteger(10));
+assertLessThan(new java.math.BigInteger(2), 10);
+assertLessThan(2, new java.math.BigInteger(10));
+
+assertLessThan(new java.util.concurrent.atomic.AtomicInteger(2), new java.util.concurrent.atomic.AtomicInteger(10));
+assertLessThan(new java.util.concurrent.atomic.AtomicInteger(2), 10);
+assertLessThan(2, new java.util.concurrent.atomic.AtomicInteger(10));
diff --git a/test/script/basic/JDK-8166902.js b/test/script/basic/JDK-8166902.js
new file mode 100644
index 0000000..fb16450
--- /dev/null
+++ b/test/script/basic/JDK-8166902.js
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 2016, 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-8166902: Nested object literal property maps not reset in optimistic recompilation
+ *
+ * @test
+ * @run
+ */
+
+var o = {
+    a: "A",
+    b: "B"
+};
+
+var m = {
+    x: { z: o.a },
+    y: o.b
+};
+
+Assert.assertEquals(m.x.z, "A");
+Assert.assertEquals(m.y, "B");
+
diff --git a/test/script/basic/JDK-8170594.js b/test/script/basic/JDK-8170594.js
new file mode 100644
index 0000000..6365500
--- /dev/null
+++ b/test/script/basic/JDK-8170594.js
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2016 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-8170594: >>>=0 generates invalid bytecode for BaseNode LHS
+ *
+ * @test
+ * @run
+ */
+
+var obj1 = {x: "100"};
+(function (o, p) {
+ if (p) {
+   o.x >>>= 0;
+ }
+})(obj1, true)
+Assert.assertTrue(obj1.x === 100)
+
+var obj2 = ["100"];
+(function (o, p) {
+ if (p) {
+   o[0] >>>= 0;
+ }
+})(obj2, true)
+Assert.assertTrue(obj2[0] === 100)
diff --git a/test/script/basic/JDK-8171219.js b/test/script/basic/JDK-8171219.js
new file mode 100644
index 0000000..6c1cf72
--- /dev/null
+++ b/test/script/basic/JDK-8171219.js
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 2016, 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-8171219: Missing checks in sparse array shift() implementation
+ *
+ * @test
+ * @run
+ */
+
+var a = [];
+a[1048577] = 1;
+a.shift();
+a[1] = 2;
+a.shift();
+var ka = Object.keys(a);
+Assert.assertTrue(ka.length === 2);
+Assert.assertTrue(ka[0] === '0');
+Assert.assertTrue(ka[1] === '1048575');
+Assert.assertTrue(a.length === 1048576);
+Assert.assertTrue(a[0] === 2);
+Assert.assertTrue(a[1048575] = 1);
+
+var b = [];
+b[1048577] = 1;
+b.unshift(2);
+b.shift();
+b[1] = 3;
+b.shift();
+var kb = Object.keys(b);
+Assert.assertTrue(kb.length === 2);
+Assert.assertTrue(kb[0] === '0');
+Assert.assertTrue(kb[1] === '1048576');
+Assert.assertTrue(b.length === 1048577);
+Assert.assertTrue(b[0] === 3);
+Assert.assertTrue(b[1048576] = 1);
+
diff --git a/test/script/basic/JDK-8171849.js b/test/script/basic/JDK-8171849.js
new file mode 100644
index 0000000..febc97c
--- /dev/null
+++ b/test/script/basic/JDK-8171849.js
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2016 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-8171849: Collection and Queue conversions not prioritized for Arrays
+ *
+ * @test
+ * @run
+ */
+
+var acp = new (Java.type("jdk.nashorn.test.models.ArrayConversionPreferences"))
+
+var a = [1, "", {}]
+
+Assert.assertTrue(acp.testCollectionOverMap(a))
+Assert.assertTrue(acp.testCollectionOverArray(a))
+Assert.assertTrue(acp.testListOverMap(a))
+Assert.assertTrue(acp.testListOverArray(a))
+Assert.assertTrue(acp.testListOverCollection(a))
+Assert.assertTrue(acp.testQueueOverMap(a))
+Assert.assertTrue(acp.testQueueOverArray(a))
+Assert.assertTrue(acp.testQueueOverCollection(a))
+Assert.assertTrue(acp.testDequeOverMap(a))
+Assert.assertTrue(acp.testDequeOverArray(a))
+Assert.assertTrue(acp.testDequeOverCollection(a))
+Assert.assertTrue(acp.testDequeOverQueue(a))
+Assert.assertTrue(acp.testArrayOverMap(a))
diff --git a/test/script/basic/JDK-8176511.js b/test/script/basic/JDK-8176511.js
new file mode 100644
index 0000000..08fbd55
--- /dev/null
+++ b/test/script/basic/JDK-8176511.js
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2017, 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-8176511: JSObject property access is broken for numeric keys outside the int range
+ *
+ * @test
+ * @run
+ */
+
+
+var reassignWithNewGlobal = loadWithNewGlobal({
+    script: '(function (o, i) { o[i] = o[i]; })', name: 'internal.js'
+
+});
+
+function test(i) {
+    var o = {};
+    o[i] = true;
+    var before = JSON.stringify(o);
+    reassignWithNewGlobal(o, i);
+    var after = JSON.stringify(o);
+    Assert.assertEquals(before, after);
+}
+
+test(-2147483649);
+test(-2147483648);
+test(2147483647);
+test(2147483648);
+
diff --git a/test/script/basic/es6/JDK-8168373.js b/test/script/basic/es6/JDK-8168373.js
new file mode 100644
index 0000000..af26e73
--- /dev/null
+++ b/test/script/basic/es6/JDK-8168373.js
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 2016 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-8168373: don't emit conversions for symbols outside their lexical scope
+ *
+ * @test
+ * @run
+ * @option --language=es6
+ */
+
+function p() { return false } // "predicate"
+function r(x) { return x } // "read"
+
+(function() {
+  try { // Try creates control flow edges from assignments into catch blocks.
+    // Lexically scoped, never read int variable (undefined at catch block) but still with a cf edge into catch block.
+    // Since it's never read, it's not written either (Nashorn optimizes some dead writes).
+    let x = 0; 
+    if (p()) { throw {}; } // We need `p()` so this block doesn't get optimized away, for possibility of a `throw` 
+    x = 0.0; // change the type of x to double
+    r(x); // read x otherwise it's optimized away
+  } catch (e) {} // under the bug, "throw" will try to widen unwritten int x to double for here and cause a verifier error
+})()
diff --git a/test/src/jdk/nashorn/api/scripting/test/ScriptObjectMirrorTest.java b/test/src/jdk/nashorn/api/scripting/test/ScriptObjectMirrorTest.java
index f9c78fc..7656dc6 100644
--- a/test/src/jdk/nashorn/api/scripting/test/ScriptObjectMirrorTest.java
+++ b/test/src/jdk/nashorn/api/scripting/test/ScriptObjectMirrorTest.java
@@ -41,6 +41,7 @@
 import javax.script.ScriptEngine;
 import javax.script.ScriptEngineManager;
 import javax.script.ScriptException;
+import jdk.nashorn.api.scripting.AbstractJSObject;
 import jdk.nashorn.api.scripting.JSObject;
 import jdk.nashorn.api.scripting.ScriptObjectMirror;
 import org.testng.annotations.Test;
@@ -386,4 +387,41 @@
         assertTrue(func.isFunction());
         assertEquals(func.call(e.eval("this"), "hello"), "hello world");
     }
+
+    // @bug 8170565: JSObject call() is passed undefined for the argument 'thiz'
+    @Test
+    public void jsObjectThisTest() throws Exception {
+        final ScriptEngineManager engineManager = new ScriptEngineManager();
+        final ScriptEngine e = engineManager.getEngineByName("nashorn");
+        e.put("func", new AbstractJSObject() {
+            @Override
+            public boolean isFunction() { return true; }
+
+            @Override
+            public Object call(Object thiz, Object...args) {
+                return thiz;
+            }
+        });
+
+        assertTrue((boolean)e.eval("func() === this"));
+
+        // check that there is no blind undefined->Global translation!
+        assertTrue((boolean)e.eval("typeof(Function.prototype.call.call(func, undefined)) == 'undefined'"));
+
+        // make sure that strict functions don't get translated this for scope calls!
+        e.put("sfunc", new AbstractJSObject() {
+            @Override
+            public boolean isFunction() { return true; }
+
+            @Override
+            public boolean isStrictFunction() { return true; }
+
+            @Override
+            public Object call(Object thiz, Object...args) {
+                return thiz;
+            }
+        });
+
+        assertTrue((boolean)e.eval("typeof sfunc() == 'undefined'"));
+    }
 }
diff --git a/test/src/jdk/nashorn/test/models/ArrayConversionPreferences.java b/test/src/jdk/nashorn/test/models/ArrayConversionPreferences.java
new file mode 100644
index 0000000..a88f3c3
--- /dev/null
+++ b/test/src/jdk/nashorn/test/models/ArrayConversionPreferences.java
@@ -0,0 +1,74 @@
+/*
+ * Copyright (c) 2016, 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.test.models;
+
+import java.util.Collection;
+import java.util.Deque;
+import java.util.List;
+import java.util.Map;
+import java.util.Queue;
+
+public class ArrayConversionPreferences {
+    public boolean testCollectionOverMap(final Collection x) { return true; }
+    public boolean testCollectionOverMap(final Map x) { return false; }
+
+    public boolean testCollectionOverArray(final Collection x) { return true; }
+    public boolean testCollectionOverArray(final Object[] x) { return false; }
+
+    public boolean testListOverMap(final List x) { return true; }
+    public boolean testListOverMap(final Map x) { return false; }
+
+    public boolean testListOverArray(final List x) { return true; }
+    public boolean testListOverArray(final Object[] x) { return false; }
+
+    public boolean testListOverCollection(final List x) { return true; }
+    public boolean testListOverCollection(final Collection x) { return false; }
+
+    public boolean testQueueOverMap(final Queue x) { return true; }
+    public boolean testQueueOverMap(final Map x) { return false; }
+
+    public boolean testQueueOverArray(final Queue x) { return true; }
+    public boolean testQueueOverArray(final Object[] x) { return false; }
+
+    public boolean testQueueOverCollection(final Queue x) { return true; }
+    public boolean testQueueOverCollection(final Collection x) { return false; }
+
+    public boolean testDequeOverMap(final Deque x) { return true; }
+    public boolean testDequeOverMap(final Map x) { return false; }
+
+    public boolean testDequeOverArray(final Deque x) { return true; }
+    public boolean testDequeOverArray(final Object[] x) { return false; }
+
+    public boolean testDequeOverCollection(final Deque x) { return true; }
+    public boolean testDequeOverCollection(final Collection x) { return false; }
+
+    public boolean testDequeOverQueue(final Deque x) { return true; }
+    public boolean testDequeOverQueue(final Queue x) { return false; }
+
+    public boolean testArrayOverMap(final Object[] x) { return true; }
+    public boolean testArrayOverMap(final Map x) { return false; }
+}
+