changeset 1527:8c16b50db8ee

Merge.
author Doug Simon <doug.simon@oracle.com>
date Thu, 26 Nov 2015 01:06:51 +0100
parents dcacbe3d3048 c15ff29c1295
children 11951a3d5dea
files src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/NumberToString.java
diffstat 105 files changed, 308632 insertions(+), 1229 deletions(-) [+]
line wrap: on
line diff
--- a/.hgtags	Mon Nov 23 15:32:02 2015 +0100
+++ b/.hgtags	Thu Nov 26 01:06:51 2015 +0100
@@ -325,3 +325,4 @@
 62641244c378c17183b7208f3f1d75ba5f248a79 jdk9-b89
 bc92163c4e0aa3fcca51a290c55715c54a5faa5f jdk9-b90
 fee4d2015e24ced4f28f4dcf93076a4fbd03844d jdk9-b91
+34b77a618e98c5da59a760341f43af6aefc56efb jdk9-b92
--- a/docs/DEVELOPER_README	Mon Nov 23 15:32:02 2015 +0100
+++ b/docs/DEVELOPER_README	Thu Nov 26 01:06:51 2015 +0100
@@ -35,12 +35,14 @@
 
 SYSTEM PROPERTY: -Dnashorn.unstable.relink.threshold=x
 
-This property controls how many call site misses are allowed before a 
-callsite is relinked with "apply" semantics to never change again. 
-In the case of megamorphic callsites, this is necessary, or the 
-program would spend all its time swapping out callsite targets. Dynalink 
-has a default value (currently 8 relinks) for this property if it 
-is not explicitly set.
+NOTE: This property is deprecated in favor of the 
+"--unstable-relink-threshold" command line option. It controls how many
+call site misses are allowed before a callsite is relinked with "apply"
+semantics to never change again. In the case of megamorphic callsites, 
+this is necessary, or the program would spend all its time swapping out 
+callsite targets. When neither the system property nor the command line
+option are specified, defaults to 8, or 16 with optimistic types turned
+on.
 
 
 SYSTEM PROPERTY: -Dnashorn.compiler.splitter.threshold=x
@@ -607,6 +609,10 @@
 	                         enterexit [trace callsite enter/exit], objects [print object properties].)
 		param: [=[option,]*]   
 
+	-urt, --unstable-relink-threshold (Number of times a dynamic call site has to be relinked before it 
+	                                  is considered unstable, when the runtime will try to link it as 
+	                                  if it is megamorphic.)
+
 	--verify-code (Verify byte code before running.)
 		param: [true|false]   default: false
 
--- a/make/build.xml	Mon Nov 23 15:32:02 2015 +0100
+++ b/make/build.xml	Thu Nov 26 01:06:51 2015 +0100
@@ -311,6 +311,10 @@
        <fileset dir="${test.src.dir}/jdk/nashorn/internal/runtime/test/resources"/>
     </copy>
 
+    <copy todir="${build.test.classes.dir}/jdk/nashorn/internal/runtime/doubleconv/test/resources">
+      <fileset dir="${test.src.dir}/jdk/nashorn/internal/runtime/doubleconv/test/resources"/>
+    </copy>
+
     <copy todir="${build.test.classes.dir}/jdk/nashorn/api/scripting/test/resources">
        <fileset dir="${test.src.dir}/jdk/nashorn/api/scripting/test/resources"/>
     </copy>
@@ -436,6 +440,7 @@
           <include name="**/runtime/test/*Test.class"/>
           <include name="**/runtime/regexp/test/*Test.class"/>
           <include name="**/runtime/regexp/joni/test/*Test.class"/>
+          <include name="**/runtime/doubleconv/test/*Test.class"/>
           <include name="**/framework/*Test.class"/>
      </fileset>
   </target>
--- a/src/jdk.scripting.nashorn.shell/share/classes/jdk/nashorn/tools/jjs/Main.java	Mon Nov 23 15:32:02 2015 +0100
+++ b/src/jdk.scripting.nashorn.shell/share/classes/jdk/nashorn/tools/jjs/Main.java	Thu Nov 26 01:06:51 2015 +0100
@@ -165,7 +165,7 @@
                 try {
                     final Object res = context.eval(global, source, global, "<shell>");
                     if (res != ScriptRuntime.UNDEFINED) {
-                        err.println(JSType.toString(res));
+                        err.println(toString(res, global));
                     }
                 } catch (final Exception exp) {
                     // Is this a ECMAScript SyntaxError at last column (of the single line)?
--- a/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/CompositeOperation.java	Mon Nov 23 15:32:02 2015 +0100
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/CompositeOperation.java	Thu Nov 26 01:06:51 2015 +0100
@@ -139,7 +139,7 @@
  * {@code SET_ELEMENT}; other standard operations should not be combined. The
  * constructor will allow any combination of operations, though.
  */
-public class CompositeOperation implements Operation {
+public final class CompositeOperation implements Operation {
     private final Operation[] operations;
 
     /**
@@ -228,10 +228,10 @@
      */
     @Override
     public boolean equals(final Object obj) {
-        if (obj == null || obj.getClass() != CompositeOperation.class) {
-            return false;
+        if (obj instanceof CompositeOperation) {
+            return Arrays.equals(operations, ((CompositeOperation)obj).operations);
         }
-        return Arrays.equals(operations, ((CompositeOperation)obj).operations);
+        return false;
     }
 
     /**
--- a/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/DynamicLinkerFactory.java	Mon Nov 23 15:32:02 2015 +0100
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/DynamicLinkerFactory.java	Thu Nov 26 01:06:51 2015 +0100
@@ -137,7 +137,7 @@
      * Default value for {@link #setUnstableRelinkThreshold(int) unstable relink
      * threshold}.
      */
-    public static final int DEFAULT_UNSTABLE_RELINK_THRESHOLD = 8;
+    private static final int DEFAULT_UNSTABLE_RELINK_THRESHOLD = 8;
 
     private boolean classLoaderExplicitlySet = false;
     private ClassLoader classLoader;
@@ -272,7 +272,7 @@
     /**
      * Sets the unstable relink threshold; the number of times a call site is
      * relinked after which it will be considered unstable, and subsequent link
-     * requests for it will indicate this.
+     * requests for it will indicate this. Defaults to 8 when not set explicitly.
      * @param unstableRelinkThreshold the new threshold. Must not be less than
      * zero. The value of zero means that call sites will never be considered
      * unstable.
--- a/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/NamedOperation.java	Mon Nov 23 15:32:02 2015 +0100
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/NamedOperation.java	Thu Nov 26 01:06:51 2015 +0100
@@ -98,7 +98,7 @@
  * the documentation for all {@link StandardOperation} members describes how
  * they are affected by being incorporated into a named operation.
  */
-public class NamedOperation implements Operation {
+public final class NamedOperation implements Operation {
     private final Operation baseOperation;
     private final Object name;
 
@@ -145,13 +145,11 @@
      */
     @Override
     public boolean equals(final Object obj) {
-        if (obj == null) {
-            return false;
-        } else if(obj.getClass() != NamedOperation.class) {
-            return false;
+        if (obj instanceof NamedOperation) {
+            final NamedOperation other = (NamedOperation)obj;
+            return baseOperation.equals(other.baseOperation) && name.equals(other.name);
         }
-        final NamedOperation other = (NamedOperation)obj;
-        return baseOperation.equals(other.baseOperation) && name.equals(other.name);
+        return false;
     }
 
     /**
--- a/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/beans/AbstractJavaLinker.java	Mon Nov 23 15:32:02 2015 +0100
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/beans/AbstractJavaLinker.java	Thu Nov 26 01:06:51 2015 +0100
@@ -93,11 +93,11 @@
 import java.lang.reflect.Method;
 import java.lang.reflect.Modifier;
 import java.util.Arrays;
-import java.util.Collection;
 import java.util.Collections;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
+import java.util.Set;
 import jdk.internal.dynalink.CallSiteDescriptor;
 import jdk.internal.dynalink.CompositeOperation;
 import jdk.internal.dynalink.NamedOperation;
@@ -200,20 +200,20 @@
 
     abstract FacetIntrospector createFacetIntrospector();
 
-    Collection<String> getReadablePropertyNames() {
+    Set<String> getReadablePropertyNames() {
         return getUnmodifiableKeys(propertyGetters);
     }
 
-    Collection<String> getWritablePropertyNames() {
+    Set<String> getWritablePropertyNames() {
         return getUnmodifiableKeys(propertySetters);
     }
 
-    Collection<String> getMethodNames() {
+    Set<String> getMethodNames() {
         return getUnmodifiableKeys(methods);
     }
 
-    private static Collection<String> getUnmodifiableKeys(final Map<String, ?> m) {
-        return Collections.unmodifiableCollection(m.keySet());
+    private static Set<String> getUnmodifiableKeys(final Map<String, ?> m) {
+        return Collections.unmodifiableSet(m.keySet());
     }
 
     /**
@@ -416,9 +416,7 @@
         return new GuardedInvocationComponent(invocation, getClassGuard(type), clazz, ValidationType.EXACT_CLASS);
     }
 
-    SingleDynamicMethod getConstructorMethod(final String signature) {
-        return null;
-    }
+    abstract SingleDynamicMethod getConstructorMethod(final String signature);
 
     private MethodHandle getAssignableGuard(final MethodType type) {
         return Guards.asType(assignableGuard, type);
--- a/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/beans/BeanLinker.java	Mon Nov 23 15:32:02 2015 +0100
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/beans/BeanLinker.java	Thu Nov 26 01:06:51 2015 +0100
@@ -152,6 +152,11 @@
         return null;
     }
 
+    @Override
+    SingleDynamicMethod getConstructorMethod(final String signature) {
+        return null;
+    }
+
     private static final MethodHandle GET_LIST_ELEMENT = Lookup.PUBLIC.findVirtual(List.class, "get",
             MethodType.methodType(Object.class, int.class));
 
--- a/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/beans/BeansLinker.java	Mon Nov 23 15:32:02 2015 +0100
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/beans/BeansLinker.java	Thu Nov 26 01:06:51 2015 +0100
@@ -84,8 +84,8 @@
 package jdk.internal.dynalink.beans;
 
 import java.lang.invoke.MethodHandles.Lookup;
-import java.util.Collection;
 import java.util.Collections;
+import java.util.Set;
 import jdk.internal.dynalink.DynamicLinkerFactory;
 import jdk.internal.dynalink.StandardOperation;
 import jdk.internal.dynalink.linker.GuardedInvocation;
@@ -229,11 +229,11 @@
     }
 
     /**
-     * Returns a collection of names of all readable instance properties of a class.
+     * Returns a set of names of all readable instance properties of a class.
      * @param clazz the class
-     * @return a collection of names of all readable instance properties of a class.
+     * @return a set of names of all readable instance properties of a class.
      */
-    public static Collection<String> getReadableInstancePropertyNames(final Class<?> clazz) {
+    public static Set<String> getReadableInstancePropertyNames(final Class<?> clazz) {
         final TypeBasedGuardingDynamicLinker linker = getLinkerForClass(clazz);
         if(linker instanceof BeanLinker) {
             return ((BeanLinker)linker).getReadablePropertyNames();
@@ -242,11 +242,11 @@
     }
 
     /**
-     * Returns a collection of names of all writable instance properties of a class.
+     * Returns a set of names of all writable instance properties of a class.
      * @param clazz the class
-     * @return a collection of names of all writable instance properties of a class.
+     * @return a set of names of all writable instance properties of a class.
      */
-    public static Collection<String> getWritableInstancePropertyNames(final Class<?> clazz) {
+    public static Set<String> getWritableInstancePropertyNames(final Class<?> clazz) {
         final TypeBasedGuardingDynamicLinker linker = getLinkerForClass(clazz);
         if(linker instanceof BeanLinker) {
             return ((BeanLinker)linker).getWritablePropertyNames();
@@ -255,11 +255,11 @@
     }
 
     /**
-     * Returns a collection of names of all instance methods of a class.
+     * Returns a set of names of all instance methods of a class.
      * @param clazz the class
-     * @return a collection of names of all instance methods of a class.
+     * @return a set of names of all instance methods of a class.
      */
-    public static Collection<String> getInstanceMethodNames(final Class<?> clazz) {
+    public static Set<String> getInstanceMethodNames(final Class<?> clazz) {
         final TypeBasedGuardingDynamicLinker linker = getLinkerForClass(clazz);
         if(linker instanceof BeanLinker) {
             return ((BeanLinker)linker).getMethodNames();
@@ -268,29 +268,29 @@
     }
 
     /**
-     * Returns a collection of names of all readable static properties of a class.
+     * Returns a set of names of all readable static properties of a class.
      * @param clazz the class
-     * @return a collection of names of all readable static properties of a class.
+     * @return a set of names of all readable static properties of a class.
      */
-    public static Collection<String> getReadableStaticPropertyNames(final Class<?> clazz) {
+    public static Set<String> getReadableStaticPropertyNames(final Class<?> clazz) {
         return StaticClassLinker.getReadableStaticPropertyNames(clazz);
     }
 
     /**
-     * Returns a collection of names of all writable static properties of a class.
+     * Returns a set of names of all writable static properties of a class.
      * @param clazz the class
-     * @return a collection of names of all writable static properties of a class.
+     * @return a set of names of all writable static properties of a class.
      */
-    public static Collection<String> getWritableStaticPropertyNames(final Class<?> clazz) {
+    public static Set<String> getWritableStaticPropertyNames(final Class<?> clazz) {
         return StaticClassLinker.getWritableStaticPropertyNames(clazz);
     }
 
     /**
-     * Returns a collection of names of all static methods of a class.
+     * Returns a set of names of all static methods of a class.
      * @param clazz the class
-     * @return a collection of names of all static methods of a class.
+     * @return a set of names of all static methods of a class.
      */
-    public static Collection<String> getStaticMethodNames(final Class<?> clazz) {
+    public static Set<String> getStaticMethodNames(final Class<?> clazz) {
         return StaticClassLinker.getStaticMethodNames(clazz);
     }
 
--- a/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/beans/StaticClass.java	Mon Nov 23 15:32:02 2015 +0100
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/beans/StaticClass.java	Thu Nov 26 01:06:51 2015 +0100
@@ -136,6 +136,10 @@
 
     private static final long serialVersionUID = 1L;
 
+    /**
+     * The runtime {@code Class} object whose static members this
+     * {@code StaticClass} represents.
+     */
     private final Class<?> clazz;
 
     /*private*/ StaticClass(final Class<?> clazz) {
@@ -164,6 +168,11 @@
         return "StaticClass[" + clazz.getName() + "]";
     }
 
+    /**
+     * Returns {@link #forClass(Class)} for the underlying {@code clazz} field
+     * ensuring that deserialization doesn't create non-canonical instances.
+     * @return {@link #forClass(Class)} for the underlying {@code clazz} field.
+     */
     private Object readResolve() {
         return forClass(clazz);
     }
--- a/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/beans/StaticClassLinker.java	Mon Nov 23 15:32:02 2015 +0100
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/beans/StaticClassLinker.java	Thu Nov 26 01:06:51 2015 +0100
@@ -88,7 +88,7 @@
 import java.lang.invoke.MethodType;
 import java.lang.reflect.Array;
 import java.util.Arrays;
-import java.util.Collection;
+import java.util.Set;
 import jdk.internal.dynalink.CallSiteDescriptor;
 import jdk.internal.dynalink.NamedOperation;
 import jdk.internal.dynalink.StandardOperation;
@@ -171,15 +171,15 @@
         return linkers.get(clazz).getConstructorMethod(signature);
     }
 
-    static Collection<String> getReadableStaticPropertyNames(final Class<?> clazz) {
+    static Set<String> getReadableStaticPropertyNames(final Class<?> clazz) {
         return linkers.get(clazz).getReadablePropertyNames();
     }
 
-    static Collection<String> getWritableStaticPropertyNames(final Class<?> clazz) {
+    static Set<String> getWritableStaticPropertyNames(final Class<?> clazz) {
         return linkers.get(clazz).getWritablePropertyNames();
     }
 
-    static Collection<String> getStaticMethodNames(final Class<?> clazz) {
+    static Set<String> getStaticMethodNames(final Class<?> clazz) {
         return linkers.get(clazz).getMethodNames();
     }
 
--- a/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/linker/support/CompositeGuardingDynamicLinker.java	Mon Nov 23 15:32:02 2015 +0100
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/linker/support/CompositeGuardingDynamicLinker.java	Thu Nov 26 01:06:51 2015 +0100
@@ -83,7 +83,6 @@
 
 package jdk.internal.dynalink.linker.support;
 
-import java.io.Serializable;
 import java.util.LinkedList;
 import java.util.List;
 import java.util.Objects;
@@ -97,9 +96,7 @@
  * other guarding dynamic linkers in its
  * {@link #getGuardedInvocation(LinkRequest, LinkerServices)}.
  */
-public class CompositeGuardingDynamicLinker implements GuardingDynamicLinker, Serializable {
-
-    private static final long serialVersionUID = 1L;
+public class CompositeGuardingDynamicLinker implements GuardingDynamicLinker {
 
     private final GuardingDynamicLinker[] linkers;
 
--- a/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/linker/support/CompositeTypeBasedGuardingDynamicLinker.java	Mon Nov 23 15:32:02 2015 +0100
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/linker/support/CompositeTypeBasedGuardingDynamicLinker.java	Thu Nov 26 01:06:51 2015 +0100
@@ -83,7 +83,6 @@
 
 package jdk.internal.dynalink.linker.support;
 
-import java.io.Serializable;
 import java.util.Collections;
 import java.util.LinkedList;
 import java.util.List;
@@ -102,9 +101,7 @@
  * type is encountered, the linking is delegated to those linkers only, speeding
  * up dispatch.
  */
-public class CompositeTypeBasedGuardingDynamicLinker implements TypeBasedGuardingDynamicLinker, Serializable {
-    private static final long serialVersionUID = 1L;
-
+public class CompositeTypeBasedGuardingDynamicLinker implements TypeBasedGuardingDynamicLinker {
     // Using a separate static class instance so there's no strong reference from the class value back to the composite
     // linker.
     private static class ClassToLinker extends ClassValue<List<TypeBasedGuardingDynamicLinker>> {
--- a/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/linker/support/TypeUtilities.java	Mon Nov 23 15:32:02 2015 +0100
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/linker/support/TypeUtilities.java	Thu Nov 26 01:06:51 2015 +0100
@@ -94,7 +94,7 @@
 /**
  * Various static utility methods for working with Java types.
  */
-public class TypeUtilities {
+public final class TypeUtilities {
     static final Class<Object> OBJECT_CLASS = Object.class;
 
     private TypeUtilities() {
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/WeakValueCache.java	Thu Nov 26 01:06:51 2015 +0100
@@ -0,0 +1,98 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.nashorn.internal;
+
+import java.lang.ref.ReferenceQueue;
+import java.lang.ref.WeakReference;
+import java.util.HashMap;
+import java.util.function.Function;
+
+/**
+ * This class provides a map based cache with weakly referenced values. Cleared references are
+ * purged from the underlying map when values are retrieved or created.
+ * It uses a {@link java.util.HashMap} to store values and needs to be externally synchronized.
+ *
+ * @param <K> the key type
+ * @param <V> the value type
+ */
+public final class WeakValueCache<K, V> {
+
+    private final HashMap<K, KeyValueReference<K, V>> map = new HashMap<>();
+    private final ReferenceQueue<V> refQueue = new ReferenceQueue<>();
+
+    /**
+     * Returns the value associated with {@code key}, or {@code null} if no such value exists.
+     *
+     * @param key the key
+     * @return the value or null if none exists
+     */
+    public V get(final K key) {
+        // Remove cleared entries
+        for (;;) {
+            final KeyValueReference<?, ?> ref = (KeyValueReference) refQueue.poll();
+            if (ref == null) {
+                break;
+            }
+            map.remove(ref.key, ref);
+        }
+
+        final KeyValueReference<K, V> ref = map.get(key);
+        if (ref != null) {
+            return ref.get();
+        }
+        return null;
+    }
+
+    /**
+     * Returns the value associated with {@code key}, or creates and returns a new value if
+     * no value exists using the {@code creator} function.
+     *
+     * @param key the key
+     * @param creator function to create a new value
+     * @return the existing value, or a new one if none existed
+     */
+    public V getOrCreate(final K key, final Function<? super K, ? extends V> creator) {
+        V value = get(key);
+
+        if (value == null) {
+            // Define a new value if it does not exist
+            value = creator.apply(key);
+            map.put(key, new KeyValueReference<>(key, value));
+        }
+
+        return value;
+    }
+
+    private static class KeyValueReference<K, V> extends WeakReference<V> {
+        final K key;
+
+        KeyValueReference(final K key, final V value) {
+            super(value);
+            this.key = key;
+        }
+    }
+
+}
--- a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/CodeGenerator.java	Mon Nov 23 15:32:02 2015 +0100
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/CodeGenerator.java	Thu Nov 26 01:06:51 2015 +0100
@@ -550,7 +550,10 @@
             if (swap) {
                 method.swap();
             }
-            for (int i = 0; i < depth; i++) {
+            if (depth > 1) {
+                method.load(depth);
+                method.invoke(ScriptObject.GET_PROTO_DEPTH);
+            } else {
                 method.invoke(ScriptObject.GET_PROTO);
             }
             if (swap) {
@@ -1379,7 +1382,10 @@
             return;
         }
         method.loadCompilerConstant(SCOPE);
-        for(int i = 0; i < count; ++i) {
+        if (count > 1) {
+            method.load(count);
+            method.invoke(ScriptObject.GET_PROTO_DEPTH);
+        } else {
             method.invoke(ScriptObject.GET_PROTO);
         }
         method.storeCompilerConstant(SCOPE);
@@ -3317,9 +3323,6 @@
 
         if (needsScope) {
             method.loadCompilerConstant(SCOPE);
-        }
-
-        if (needsScope) {
             loadExpressionUnbounded(init);
             // block scoped variables need a DECLARE flag to signal end of temporal dead zone (TDZ)
             final int flags = getScopeCallSiteFlags(identSymbol) | (varNode.isBlockScoped() ? CALLSITE_DECLARE : 0);
--- a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/Compiler.java	Mon Nov 23 15:32:02 2015 +0100
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/Compiler.java	Thu Nov 26 01:06:51 2015 +0100
@@ -46,6 +46,7 @@
 import java.util.Map;
 import java.util.Set;
 import java.util.TreeMap;
+import java.util.concurrent.TimeUnit;
 import java.util.concurrent.atomic.AtomicInteger;
 import java.util.function.Consumer;
 import java.util.logging.Level;
@@ -684,7 +685,7 @@
 
             if (time > 0L && timeLogger != null) {
                 assert env.isTimingEnabled();
-                sb.append(" in ").append(time).append(" ms");
+                sb.append(" in ").append(TimeUnit.NANOSECONDS.toMillis(time)).append(" ms");
             }
             log.info(sb);
         }
--- a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/MethodEmitter.java	Mon Nov 23 15:32:02 2015 +0100
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/MethodEmitter.java	Thu Nov 26 01:06:51 2015 +0100
@@ -738,7 +738,7 @@
      * @param recovery start label for catch
      */
     void _try(final Label entry, final Label exit, final Label recovery) {
-        _try(entry, exit, recovery, (String)null, false);
+        _try(entry, exit, recovery, null, false);
     }
 
     void markLabelAsOptimisticCatchHandler(final Label label, final int liveLocalCount) {
--- a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/SpillObjectCreator.java	Mon Nov 23 15:32:02 2015 +0100
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/SpillObjectCreator.java	Thu Nov 26 01:06:51 2015 +0100
@@ -173,9 +173,10 @@
                 loadTuple(method, tuple);
                 method.dynamicSetIndex(callSiteFlags);
             } else {
+                assert property.getKey() instanceof String; // symbol keys not yet supported in object literals
                 method.dup();
                 loadTuple(method, tuple);
-                method.dynamicSet(property.getKey(), codegen.getCallSiteFlags(), false);
+                method.dynamicSet((String) property.getKey(), codegen.getCallSiteFlags(), false);
             }
         }
     }
--- a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/FunctionNode.java	Mon Nov 23 15:32:02 2015 +0100
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/FunctionNode.java	Thu Nov 26 01:06:51 2015 +0100
@@ -239,7 +239,7 @@
     private static final int HAS_DEEP_EVAL = HAS_EVAL | HAS_NESTED_EVAL;
 
     /** Does this function need to store all its variables in scope? */
-    private static final int HAS_ALL_VARS_IN_SCOPE = HAS_DEEP_EVAL;
+    public static final int HAS_ALL_VARS_IN_SCOPE = HAS_DEEP_EVAL;
 
     /** Does this function potentially need "arguments"? Note that this is not a full test, as further negative check of REDEFINES_ARGS is needed. */
     private static final int MAYBE_NEEDS_ARGUMENTS = USES_ARGUMENTS | HAS_EVAL;
--- a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/Global.java	Mon Nov 23 15:32:02 2015 +0100
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/Global.java	Thu Nov 26 01:06:51 2015 +0100
@@ -75,6 +75,7 @@
 import jdk.nashorn.internal.runtime.ScriptRuntime;
 import jdk.nashorn.internal.runtime.ScriptingFunctions;
 import jdk.nashorn.internal.runtime.Specialization;
+import jdk.nashorn.internal.runtime.Symbol;
 import jdk.nashorn.internal.runtime.arrays.ArrayData;
 import jdk.nashorn.internal.runtime.linker.Bootstrap;
 import jdk.nashorn.internal.runtime.linker.InvokeByName;
@@ -94,8 +95,8 @@
     // (__FILE__, __DIR__, __LINE__)
     private static final Object LAZY_SENTINEL = new Object();
 
-    private final InvokeByName TO_STRING = new InvokeByName("toString", ScriptObject.class);
-    private final InvokeByName VALUE_OF  = new InvokeByName("valueOf",  ScriptObject.class);
+    private InvokeByName TO_STRING;
+    private InvokeByName VALUE_OF;
 
     /**
      * Optimistic builtin names that require switchpoint invalidation
@@ -221,6 +222,10 @@
     @Property(name = "Number", attributes = Attribute.NOT_ENUMERABLE)
     public volatile Object number;
 
+    /** ECMA 2016 19.4.1 - Symbol constructor */
+    @Property(name = "Symbol", attributes = Attribute.NOT_ENUMERABLE)
+    public volatile Object symbol;
+
     /**
      * Getter for ECMA 15.1.4.7 Date property
      *
@@ -901,6 +906,7 @@
     private ScriptFunction builtinUint32Array;
     private ScriptFunction builtinFloat32Array;
     private ScriptFunction builtinFloat64Array;
+    private ScriptFunction builtinSymbol;
 
     /*
      * ECMA section 13.2.3 The [[ThrowTypeError]] Function Object
@@ -1073,6 +1079,9 @@
             return;
         }
 
+        TO_STRING = new InvokeByName("toString", ScriptObject.class);
+        VALUE_OF  = new InvokeByName("valueOf",  ScriptObject.class);
+
         this.engine = eng;
         if (this.engine != null) {
             this.scontext = new ThreadLocal<>();
@@ -1103,6 +1112,8 @@
             return new NativeArray(ArrayData.allocate((int[]) obj), this);
         } else if (obj instanceof ArrayData) {
             return new NativeArray((ArrayData) obj, this);
+        } else if (obj instanceof Symbol) {
+            return new NativeSymbol((Symbol) obj, this);
         } else {
             // FIXME: more special cases? Map? List?
             return obj;
@@ -1357,18 +1368,27 @@
         return desc;
     }
 
-    private static <T> T getLazilyCreatedValue(final Object key, final Callable<T> creator, final Map<Object, T> map) {
+    private <T> T getLazilyCreatedValue(final Object key, final Callable<T> creator, final Map<Object, T> map) {
         final T obj = map.get(key);
         if (obj != null) {
             return obj;
         }
 
+        final Global oldGlobal = Context.getGlobal();
+        final boolean differentGlobal = oldGlobal != this;
         try {
+            if (differentGlobal) {
+                Context.setGlobal(this);
+            }
             final T newObj = creator.call();
             final T existingObj = map.putIfAbsent(key, newObj);
             return existingObj != null ? existingObj : newObj;
         } catch (final Exception exp) {
             throw new RuntimeException(exp);
+        } finally {
+            if (differentGlobal) {
+                Context.setGlobal(oldGlobal);
+            }
         }
     }
 
@@ -1574,7 +1594,7 @@
 
     /**
      * Get the builtin Object prototype.
-     * @return the object prototype.
+     * @return the Object prototype.
      */
     public ScriptObject getObjectPrototype() {
         return ScriptFunction.getPrototype(builtinObject);
@@ -1582,13 +1602,17 @@
 
     /**
      * Get the builtin Function prototype.
-     * @return the Function.prototype.
+     * @return the Function prototype.
      */
     public ScriptObject getFunctionPrototype() {
         return ScriptFunction.getPrototype(builtinFunction);
     }
 
-    ScriptObject getArrayPrototype() {
+    /**
+     * Get the builtin Array prototype.
+     * @return the Array prototype
+     */
+    public ScriptObject getArrayPrototype() {
         return ScriptFunction.getPrototype(builtinArray);
     }
 
@@ -1648,6 +1672,10 @@
         return ScriptFunction.getPrototype(getBuiltinJSAdapter());
     }
 
+    ScriptObject getSymbolPrototype() {
+        return ScriptFunction.getPrototype(builtinSymbol);
+    }
+
     private synchronized ScriptFunction getBuiltinArrayBuffer() {
         if (this.builtinArrayBuffer == null) {
             this.builtinArrayBuffer = initConstructorAndSwitchPoint("ArrayBuffer", ScriptFunction.class);
@@ -2115,11 +2143,11 @@
                 // ES6 15.1.8 steps 6. and 7.
                 final jdk.nashorn.internal.runtime.Property globalProperty = ownMap.findProperty(property.getKey());
                 if (globalProperty != null && !globalProperty.isConfigurable() && property.isLexicalBinding()) {
-                    throw ECMAErrors.syntaxError("redeclare.variable", property.getKey());
+                    throw ECMAErrors.syntaxError("redeclare.variable", property.getKey().toString());
                 }
                 final jdk.nashorn.internal.runtime.Property lexicalProperty = lexicalMap.findProperty(property.getKey());
                 if (lexicalProperty != null && !property.isConfigurable()) {
-                    throw ECMAErrors.syntaxError("redeclare.variable", property.getKey());
+                    throw ECMAErrors.syntaxError("redeclare.variable", property.getKey().toString());
                 }
             }
         }
@@ -2174,7 +2202,7 @@
     }
 
     @Override
-    protected FindProperty findProperty(final String key, final boolean deep, final ScriptObject start) {
+    protected FindProperty findProperty(final Object key, final boolean deep, final ScriptObject start) {
         if (lexicalScope != null && start != this && start.isScope()) {
             final FindProperty find = lexicalScope.findProperty(key, false);
             if (find != null) {
@@ -2294,6 +2322,14 @@
         this.builtinString    = initConstructorAndSwitchPoint("String", ScriptFunction.class);
         this.builtinMath      = initConstructorAndSwitchPoint("Math", ScriptObject.class);
 
+        if (env._es6) {
+            this.builtinSymbol = initConstructorAndSwitchPoint("Symbol", ScriptFunction.class);
+        } else {
+            // We need to manually delete nasgen-generated properties we don't want
+            this.delete("Symbol", false);
+            this.builtinObject.delete("getOwnPropertySymbols", false);
+        }
+
         // initialize String.prototype.length to 0
         // add String.prototype.length
         final ScriptObject stringPrototype = getStringPrototype();
@@ -2502,6 +2538,7 @@
         this.string            = this.builtinString;
         this.syntaxError       = this.builtinSyntaxError;
         this.typeError         = this.builtinTypeError;
+        this.symbol            = this.builtinSymbol;
     }
 
     private void initDebug() {
--- a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeArguments.java	Mon Nov 23 15:32:02 2015 +0100
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeArguments.java	Thu Nov 26 01:06:51 2015 +0100
@@ -151,7 +151,7 @@
      * ECMA 10.6 for Arguments object.
      */
     @Override
-    public boolean defineOwnProperty(final String key, final Object propertyDesc, final boolean reject) {
+    public boolean defineOwnProperty(final Object key, final Object propertyDesc, final boolean reject) {
         final int index = ArrayIndex.getArrayIndex(key);
         if (index >= 0) {
             final boolean isMapped = isMapped(index);
@@ -159,7 +159,7 @@
 
             if (!super.defineOwnProperty(key, propertyDesc, false)) {
                 if (reject) {
-                    throw typeError("cant.redefine.property",  key, ScriptRuntime.safeToString(this));
+                    throw typeError("cant.redefine.property",  key.toString(), ScriptRuntime.safeToString(this));
                 }
                 return false;
             }
--- a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeArray.java	Mon Nov 23 15:32:02 2015 +0100
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeArray.java	Thu Nov 26 01:06:51 2015 +0100
@@ -328,7 +328,7 @@
      * ECMA 15.4.5.1 [[DefineOwnProperty]] ( P, Desc, Throw )
      */
     @Override
-    public boolean defineOwnProperty(final String key, final Object propertyDesc, final boolean reject) {
+    public boolean defineOwnProperty(final Object key, final Object propertyDesc, final boolean reject) {
         final PropertyDescriptor desc = toPropertyDescriptor(Global.instance(), propertyDesc);
 
         // never be undefined as "length" is always defined and can't be deleted for arrays
@@ -369,7 +369,7 @@
             // Step 4d
             if (!succeeded) {
                 if (reject) {
-                    throw typeError("cant.redefine.property", key, ScriptRuntime.safeToString(this));
+                    throw typeError("cant.redefine.property", key.toString(), ScriptRuntime.safeToString(this));
                 }
                 return false;
             }
--- a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeDebug.java	Mon Nov 23 15:32:02 2015 +0100
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeDebug.java	Thu Nov 26 01:06:51 2015 +0100
@@ -224,6 +224,18 @@
     }
 
     /**
+     * Returns {@code true} if passed object is a function that is fully debuggable (has all vars in scope).
+     *
+     * @param self self reference
+     * @param obj  object
+     * @return true {@code obj} is a debuggable function
+     */
+    @Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR)
+    public static Object isDebuggableFunction(final Object self, final Object obj) {
+        return  (obj instanceof ScriptFunction && ((ScriptFunction) obj).hasAllVarsInScope());
+    }
+
+    /**
      * Returns the property listener count for a script object
      *
      * @param self self reference
--- a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeJavaImporter.java	Mon Nov 23 15:32:02 2015 +0100
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeJavaImporter.java	Thu Nov 26 01:06:51 2015 +0100
@@ -135,8 +135,11 @@
     }
 
     @Override
-    protected Object invokeNoSuchProperty(final String name, final boolean isScope, final int programPoint) {
-        final Object retval = createProperty(name);
+    protected Object invokeNoSuchProperty(final Object key, final boolean isScope, final int programPoint) {
+        if (!(key instanceof String)) {
+            return super.invokeNoSuchProperty(key, isScope, programPoint);
+        }
+        final Object retval = createProperty((String) key);
         if (isValid(programPoint)) {
             throw new UnwarrantedOptimismException(retval, programPoint);
         }
--- a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeNumber.java	Mon Nov 23 15:32:02 2015 +0100
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeNumber.java	Thu Nov 26 01:06:51 2015 +0100
@@ -49,6 +49,7 @@
 import jdk.nashorn.internal.runtime.PropertyMap;
 import jdk.nashorn.internal.runtime.ScriptObject;
 import jdk.nashorn.internal.runtime.ScriptRuntime;
+import jdk.nashorn.internal.runtime.doubleconv.DoubleConversion;
 import jdk.nashorn.internal.runtime.linker.PrimitiveLookup;
 
 /**
@@ -184,13 +185,7 @@
             return JSType.toString(x);
         }
 
-        final NumberFormat format = NumberFormat.getNumberInstance(Locale.US);
-        format.setMinimumFractionDigits(fractionDigits);
-        format.setMaximumFractionDigits(fractionDigits);
-        format.setGroupingUsed(false);
-        format.setRoundingMode(RoundingMode.HALF_UP);
-
-        return format.format(x);
+        return DoubleConversion.toFixed(x, fractionDigits);
     }
 
     /**
@@ -267,7 +262,7 @@
             return "0";
         }
 
-        return fixExponent(String.format(Locale.US, "%." + p + "g", x), false);
+        return DoubleConversion.toPrecision(x, p);
     }
 
     /**
--- a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeObject.java	Mon Nov 23 15:32:02 2015 +0100
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeObject.java	Thu Nov 26 01:06:51 2015 +0100
@@ -252,6 +252,23 @@
     }
 
     /**
+     * ECMA 2 19.1.2.8 Object.getOwnPropertySymbols ( O )
+     *
+     * @param self self reference
+     * @param obj  object to query for property names
+     * @return array of property names
+     */
+    @Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR)
+    public static ScriptObject getOwnPropertySymbols(final Object self, final Object obj) {
+        if (obj instanceof ScriptObject) {
+            return new NativeArray(((ScriptObject)obj).getOwnSymbols(true));
+        } else {
+            // TODO: we don't support this on ScriptObjectMirror objects yet
+            throw notAnObject(obj);
+        }
+    }
+
+    /**
      * ECMA 15.2.3.5 Object.create ( O [, Properties] )
      *
      * @param self  self reference
@@ -288,7 +305,7 @@
     @Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR)
     public static ScriptObject defineProperty(final Object self, final Object obj, final Object prop, final Object attr) {
         final ScriptObject sobj = Global.checkObject(obj);
-        sobj.defineOwnProperty(JSType.toString(prop), attr, true);
+        sobj.defineOwnProperty(JSType.toPropertyKey(prop), attr, true);
         return sobj;
     }
 
@@ -465,6 +482,7 @@
             case BOOLEAN:
             case NUMBER:
             case STRING:
+            case SYMBOL:
                 return Global.toObject(value);
             case OBJECT:
                 return value;
--- a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeString.java	Mon Nov 23 15:32:02 2015 +0100
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeString.java	Thu Nov 26 01:06:51 2015 +0100
@@ -33,6 +33,7 @@
 import java.lang.invoke.MethodHandle;
 import java.lang.invoke.MethodHandles;
 import java.lang.invoke.MethodType;
+import java.lang.reflect.Array;
 import java.text.Collator;
 import java.util.ArrayList;
 import java.util.Arrays;
@@ -106,20 +107,6 @@
         return getStringValue();
     }
 
-    @Override
-    public boolean equals(final Object other) {
-        if (other instanceof NativeString) {
-            return getStringValue().equals(((NativeString) other).getStringValue());
-        }
-
-        return false;
-    }
-
-    @Override
-    public int hashCode() {
-        return getStringValue().hashCode();
-    }
-
     private String getStringValue() {
         return value instanceof String ? (String) value : value.toString();
     }
@@ -382,7 +369,7 @@
     }
 
     @Override
-    public Object getOwnPropertyDescriptor(final String key) {
+    public Object getOwnPropertyDescriptor(final Object key) {
         final int index = ArrayIndex.getArrayIndex(key);
         if (index >= 0 && index < value.length()) {
             final Global global = Global.instance();
@@ -400,7 +387,12 @@
      * @return Array of keys.
      */
     @Override
-    protected String[] getOwnKeys(final boolean all, final Set<String> nonEnumerable) {
+    @SuppressWarnings("unchecked")
+    protected <T> T[] getOwnKeys(final Class<T> type, final boolean all, final Set<T> nonEnumerable) {
+        if (type != String.class) {
+            return super.getOwnKeys(type, all, nonEnumerable);
+        }
+
         final List<Object> keys = new ArrayList<>();
 
         // add string index keys
@@ -409,8 +401,8 @@
         }
 
         // add super class properties
-        keys.addAll(Arrays.asList(super.getOwnKeys(all, nonEnumerable)));
-        return keys.toArray(new String[keys.size()]);
+        keys.addAll(Arrays.asList(super.getOwnKeys(type, all, nonEnumerable)));
+        return keys.toArray((T[]) Array.newInstance(type, keys.size()));
     }
 
     /**
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeSymbol.java	Thu Nov 26 01:06:51 2015 +0100
@@ -0,0 +1,152 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.nashorn.internal.objects;
+
+import static jdk.nashorn.internal.runtime.ECMAErrors.typeError;
+
+import jdk.nashorn.internal.WeakValueCache;
+import jdk.nashorn.internal.objects.annotations.Attribute;
+import jdk.nashorn.internal.objects.annotations.Constructor;
+import jdk.nashorn.internal.objects.annotations.Function;
+import jdk.nashorn.internal.objects.annotations.ScriptClass;
+import jdk.nashorn.internal.objects.annotations.Where;
+import jdk.nashorn.internal.runtime.JSType;
+import jdk.nashorn.internal.runtime.PropertyMap;
+import jdk.nashorn.internal.runtime.ScriptObject;
+import jdk.nashorn.internal.runtime.ScriptRuntime;
+import jdk.nashorn.internal.runtime.Symbol;
+import jdk.nashorn.internal.runtime.Undefined;
+
+/**
+ * ECMAScript 6 - 19.4 Symbol Objects
+ */
+@ScriptClass("Symbol")
+public final class NativeSymbol extends ScriptObject {
+
+    private final Symbol symbol;
+
+    // initialized by nasgen
+    private static PropertyMap $nasgenmap$;
+
+    /** See ES6 19.4.2.1 */
+    private static WeakValueCache<String, Symbol> globalSymbolRegistry = new WeakValueCache<>();
+
+    NativeSymbol(final Symbol symbol, final Global global) {
+        this(symbol, global.getSymbolPrototype(), $nasgenmap$);
+    }
+
+    private NativeSymbol(final Symbol symbol, final ScriptObject prototype, final PropertyMap map) {
+        super(prototype, map);
+        this.symbol = symbol;
+    }
+
+    private static Symbol getSymbolValue(final Object self) {
+        if (self instanceof Symbol) {
+            return (Symbol) self;
+        } else if (self instanceof NativeSymbol) {
+            return ((NativeSymbol) self).symbol;
+        } else {
+            throw typeError("not.a.symbol");
+        }
+    }
+
+    // ECMA 6 19.4.3.4 Symbol.prototype [ @@toPrimitive ] ( hint )
+    @Override
+    public Object getDefaultValue(final Class<?> typeHint) {
+        // Just return the symbol value.
+        return symbol;
+    }
+
+    /**
+     * ECMA 6 19.4.3.2 Symbol.prototype.toString ( )
+     *
+     * @param self self reference
+     * @return localized string for this Number
+     */
+    @Function(attributes = Attribute.NOT_ENUMERABLE)
+    public static String toString(final Object self) {
+        return getSymbolValue(self).toString();
+    }
+
+
+    /**
+     * ECMA 6 19.4.3.3  Symbol.prototype.valueOf ( )
+     *
+     * @param self self reference
+     * @return number value for this Number
+     */
+    @Function(attributes = Attribute.NOT_ENUMERABLE)
+    public static Object valueOf(final Object self) {
+        return getSymbolValue(self);
+    }
+
+    /**
+     * ECMA 6 19.4.1.1 Symbol ( [ description ] )
+     *
+     * @param newObj is this function invoked with the new operator
+     * @param self   self reference
+     * @param args   arguments
+     * @return new symbol value
+     */
+    @Constructor(arity = 1)
+    public static Object constructor(final boolean newObj, final Object self, final Object... args) {
+        if (newObj) {
+            throw typeError("symbol.as.constructor");
+        }
+        final String description = args.length > 0 && args[0] != Undefined.getUndefined() ?
+                JSType.toString(args[0]) : "";
+        return new Symbol(description);
+    }
+
+    /**
+     * ES6 19.4.2.1 Symbol.for ( key )
+     *
+     * @param self self reference
+     * @param arg the argument
+     * @return the symbol value
+     */
+    @Function(name = "for", attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR)
+    public synchronized static Object _for(final Object self, final Object arg) {
+        final String name = JSType.toString(arg);
+        return globalSymbolRegistry.getOrCreate(name, Symbol::new);
+    }
+
+    /**
+     * ES6 19.4.2.5 Symbol.keyFor ( sym )
+     *
+     * @param self self reference
+     * @param arg the argument
+     * @return the symbol name
+     */
+    @Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR)
+    public synchronized static Object keyFor(final Object self, final Object arg) {
+        if (!(arg instanceof Symbol)) {
+            throw typeError("not.a.symbol", ScriptRuntime.safeToString(arg));
+        }
+        final String name = ((Symbol) arg).getName();
+        return globalSymbolRegistry.get(name) == arg ? name : Undefined.getUndefined();
+    }
+}
--- a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/parser/AbstractParser.java	Mon Nov 23 15:32:02 2015 +0100
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/parser/AbstractParser.java	Thu Nov 26 01:06:51 2015 +0100
@@ -103,6 +103,9 @@
      * @param lineOffset Offset from which lines should be counted
      */
     protected AbstractParser(final Source source, final ErrorManager errors, final boolean strict, final int lineOffset) {
+        if (source.getLength() > Token.LENGTH_MASK) {
+            throw new RuntimeException("Source exceeds size limit of " + Token.LENGTH_MASK + " bytes");
+        }
         this.source       = source;
         this.errors       = errors;
         this.k            = -1;
--- a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/parser/Lexer.java	Mon Nov 23 15:32:02 2015 +0100
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/parser/Lexer.java	Thu Nov 26 01:06:51 2015 +0100
@@ -213,7 +213,6 @@
      * function body. This is used with the feature where the parser is skipping nested function bodies to
      * avoid reading ahead unnecessarily when we skip the function bodies.
      */
-
     public Lexer(final Source source, final int start, final int len, final TokenStream stream, final boolean scripting, final boolean es6, final boolean pauseOnFunctionBody) {
         super(source.getContent(), 1, start, len);
         this.source      = source;
--- a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/parser/Parser.java	Mon Nov 23 15:32:02 2015 +0100
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/parser/Parser.java	Thu Nov 26 01:06:51 2015 +0100
@@ -2941,6 +2941,10 @@
         try {
             // Create a new function block.
             body = newBlock();
+            if (env._debug_scopes) {
+                // debug scope options forces everything to be in scope
+                markEval(lc);
+            }
             assert functionNode != null;
             final int functionId = functionNode.getId();
             parseBody = reparsedFunction == null || functionId <= reparsedFunction.getFunctionNodeId();
--- a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/parser/Token.java	Mon Nov 23 15:32:02 2015 +0100
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/parser/Token.java	Thu Nov 26 01:06:51 2015 +0100
@@ -30,11 +30,21 @@
 import jdk.nashorn.internal.runtime.Source;
 
 /**
- * Basic parse/lex unit.
- *
+ * A token is a 64 bit long value that represents a basic parse/lex unit.
+ * This class provides static methods to manipulate lexer tokens.
  */
 public class Token {
 
+    /**
+     * We use 28 bits for the position and 28 bits for the length of the token.
+     * This limits the maximal length of code we can handle to 2 ^ 28 - 1 bytes.
+     */
+    public final static int LENGTH_MASK = 0xfffffff;
+
+    // The first 8 bits are used for the token type, followed by length and position
+    private final static int LENGTH_SHIFT = 8;
+    private final static int POSITION_SHIFT  = 36;
+
     private Token() {
     }
 
@@ -46,8 +56,9 @@
      * @return Token descriptor.
      */
     public static long toDesc(final TokenType type, final int position, final int length) {
-        return (long)position << 32 |
-               (long)length   << 8  |
+        assert position <= LENGTH_MASK && length <= LENGTH_MASK;
+        return (long)position << POSITION_SHIFT |
+               (long)length   << LENGTH_SHIFT  |
                type.ordinal();
     }
 
@@ -57,7 +68,7 @@
      * @return Start position of the token in the source.
      */
     public static int descPosition(final long token) {
-        return (int)(token >>> 32);
+        return (int)(token >>> POSITION_SHIFT);
     }
 
     /**
@@ -98,7 +109,7 @@
      * @return Length of the token.
      */
     public static int descLength(final long token) {
-        return (int)token >>> 8;
+        return (int)((token >>> LENGTH_SHIFT) & LENGTH_MASK);
     }
 
     /**
--- a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/AccessorProperty.java	Mon Nov 23 15:32:02 2015 +0100
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/AccessorProperty.java	Thu Nov 26 01:06:51 2015 +0100
@@ -180,7 +180,7 @@
      * @param objectSetter    object setter
      */
     protected AccessorProperty(
-            final String key,
+            final Object key,
             final int flags,
             final int slot,
             final MethodHandle primitiveGetter,
@@ -209,7 +209,7 @@
      * @param getter the property getter
      * @param setter the property setter or null if non writable, non configurable
      */
-    private AccessorProperty(final String key, final int flags, final int slot, final MethodHandle getter, final MethodHandle setter) {
+    private AccessorProperty(final Object key, final int flags, final int slot, final MethodHandle getter, final MethodHandle setter) {
         super(key, flags | IS_BUILTIN | DUAL_FIELDS | (getter.type().returnType().isPrimitive() ? IS_NASGEN_PRIMITIVE : 0), slot);
         assert !isSpill();
 
@@ -249,7 +249,7 @@
      * @param structure        structure for objects associated with this property
      * @param slot             property field number or spill slot
      */
-    public AccessorProperty(final String key, final int flags, final Class<?> structure, final int slot) {
+    public AccessorProperty(final Object key, final int flags, final Class<?> structure, final int slot) {
         super(key, flags, slot);
 
         initGetterSetter(structure);
@@ -292,7 +292,7 @@
      * @param owner        owner of property
      * @param initialValue initial value to which the property can be set
      */
-    protected AccessorProperty(final String key, final int flags, final int slot, final ScriptObject owner, final Object initialValue) {
+    protected AccessorProperty(final Object key, final int flags, final int slot, final ScriptObject owner, final Object initialValue) {
         this(key, flags, owner.getClass(), slot);
         setInitialValue(owner, initialValue);
     }
@@ -307,7 +307,7 @@
      * @param slot         field slot index
      * @param initialType  initial type of the property
      */
-    public AccessorProperty(final String key, final int flags, final Class<?> structure, final int slot, final Class<?> initialType) {
+    public AccessorProperty(final Object key, final int flags, final Class<?> structure, final int slot, final Class<?> initialType) {
         this(key, flags, structure, slot);
         setType(hasDualFields() ? initialType : Object.class);
     }
@@ -603,7 +603,7 @@
     private void checkUndeclared() {
         if ((getFlags() & NEEDS_DECLARATION) != 0) {
             // a lexically defined variable that hasn't seen its declaration - throw ReferenceError
-            throw ECMAErrors.referenceError("not.defined", getKey());
+            throw ECMAErrors.referenceError("not.defined", getKey().toString());
         }
     }
 
@@ -659,7 +659,7 @@
         }
 
         if (isBuiltin()) {
-           mh = MH.filterArguments(mh, 0, debugInvalidate(MH.insertArguments(INVALIDATE_SP, 0, this), getKey()));
+           mh = MH.filterArguments(mh, 0, debugInvalidate(MH.insertArguments(INVALIDATE_SP, 0, this), getKey().toString()));
         }
 
         assert mh.type().returnType() == void.class : mh.type();
--- a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/Context.java	Mon Nov 23 15:32:02 2015 +0100
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/Context.java	Thu Nov 26 01:06:51 2015 +0100
@@ -42,10 +42,8 @@
 import java.lang.invoke.MethodHandles;
 import java.lang.invoke.MethodType;
 import java.lang.invoke.SwitchPoint;
-import java.lang.ref.Reference;
 import java.lang.ref.ReferenceQueue;
 import java.lang.ref.SoftReference;
-import java.lang.ref.WeakReference;
 import java.lang.reflect.Field;
 import java.lang.reflect.Modifier;
 import java.net.MalformedURLException;
@@ -73,12 +71,14 @@
 import java.util.function.Supplier;
 import java.util.logging.Level;
 import javax.script.ScriptEngine;
+import jdk.internal.dynalink.DynamicLinker;
 import jdk.internal.org.objectweb.asm.ClassReader;
 import jdk.internal.org.objectweb.asm.ClassWriter;
 import jdk.internal.org.objectweb.asm.Opcodes;
 import jdk.internal.org.objectweb.asm.util.CheckClassAdapter;
 import jdk.nashorn.api.scripting.ClassFilter;
 import jdk.nashorn.api.scripting.ScriptObjectMirror;
+import jdk.nashorn.internal.WeakValueCache;
 import jdk.nashorn.internal.codegen.Compiler;
 import jdk.nashorn.internal.codegen.Compiler.CompilationPhases;
 import jdk.nashorn.internal.codegen.ObjectClassGenerator;
@@ -89,12 +89,13 @@
 import jdk.nashorn.internal.objects.Global;
 import jdk.nashorn.internal.parser.Parser;
 import jdk.nashorn.internal.runtime.events.RuntimeEvent;
+import jdk.nashorn.internal.runtime.linker.Bootstrap;
 import jdk.nashorn.internal.runtime.logging.DebugLogger;
 import jdk.nashorn.internal.runtime.logging.Loggable;
 import jdk.nashorn.internal.runtime.logging.Logger;
 import jdk.nashorn.internal.runtime.options.LoggingOption.LoggerInfo;
 import jdk.nashorn.internal.runtime.options.Options;
-import sun.misc.Unsafe;
+import jdk.internal.misc.Unsafe;
 
 /**
  * This class manages the global state of execution. Context is immutable.
@@ -301,47 +302,7 @@
         }
     }
 
-    private final Map<CodeSource, HostClassReference> anonymousHostClasses = new HashMap<>();
-    private final ReferenceQueue<Class<?>> anonymousHostClassesRefQueue = new ReferenceQueue<>();
-
-    private static class HostClassReference extends WeakReference<Class<?>> {
-        final CodeSource codeSource;
-
-        HostClassReference(final CodeSource codeSource, final Class<?> clazz, final ReferenceQueue<Class<?>> refQueue) {
-            super(clazz, refQueue);
-            this.codeSource = codeSource;
-        }
-    }
-
-    private synchronized Class<?> getAnonymousHostClass(final CodeSource codeSource) {
-        // Remove cleared entries
-        for(;;) {
-            final HostClassReference clearedRef = (HostClassReference)anonymousHostClassesRefQueue.poll();
-            if (clearedRef == null) {
-                break;
-            }
-            anonymousHostClasses.remove(clearedRef.codeSource, clearedRef);
-        }
-
-        // Try to find an existing host class
-        final Reference<Class<?>> ref = anonymousHostClasses.get(codeSource);
-        if (ref != null) {
-            final Class<?> existingHostClass = ref.get();
-            if (existingHostClass != null) {
-                return existingHostClass;
-            }
-        }
-
-        // Define a new host class if existing is not found
-        final Class<?> newHostClass = createNewLoader().installClass(
-                // NOTE: we're defining these constants in AnonymousContextCodeInstaller so they are not
-                // initialized if we don't use AnonymousContextCodeInstaller. As this method is only ever
-                // invoked from AnonymousContextCodeInstaller, this is okay.
-                AnonymousContextCodeInstaller.ANONYMOUS_HOST_CLASS_NAME,
-                AnonymousContextCodeInstaller.ANONYMOUS_HOST_CLASS_BYTES, codeSource);
-        anonymousHostClasses.put(codeSource, new HostClassReference(codeSource, newHostClass, anonymousHostClassesRefQueue));
-        return newHostClass;
-    }
+    private final WeakValueCache<CodeSource, Class<?>> anonymousHostClasses = new WeakValueCache<>();
 
     private static final class AnonymousContextCodeInstaller extends ContextCodeInstaller {
         private static final Unsafe UNSAFE = getUnsafe();
@@ -507,14 +468,14 @@
     final boolean _strict;
 
     /** class loader to resolve classes from script. */
-    private final ClassLoader  appLoader;
-
-    /** Class loader to load classes from -classpath option, if set. */
-    private final ClassLoader  classPathLoader;
+    private final ClassLoader appLoader;
 
     /** Class loader to load classes compiled from scripts. */
     private final ScriptLoader scriptLoader;
 
+    /** Dynamic linker for linking call sites in script code loaded by this context */
+    private final DynamicLinker dynamicLinker;
+
     /** Current error manager. */
     private final ErrorManager errors;
 
@@ -626,7 +587,6 @@
         this.classFilter = classFilter;
         this.env       = new ScriptEnvironment(options, out, err);
         this._strict   = env._strict;
-        this.appLoader = appLoader;
         if (env._loader_per_compile) {
             this.scriptLoader = null;
             this.uniqueScriptId = null;
@@ -636,18 +596,19 @@
         }
         this.errors    = errors;
 
-        // if user passed -classpath option, make a class loader with that and set it as
-        // thread context class loader so that script can access classes from that path.
+        // if user passed -classpath option, make a URLClassLoader with that and
+        // the app loader as the parent.
         final String classPath = options.getString("classpath");
         if (!env._compile_only && classPath != null && !classPath.isEmpty()) {
             // make sure that caller can create a class loader.
             if (sm != null) {
-                sm.checkPermission(new RuntimePermission("createClassLoader"));
+                sm.checkCreateClassLoader();
             }
-            this.classPathLoader = NashornLoader.createClassLoader(classPath);
+            this.appLoader = NashornLoader.createClassLoader(classPath, appLoader);
         } else {
-            this.classPathLoader = null;
+            this.appLoader = appLoader;
         }
+        this.dynamicLinker = Bootstrap.createDynamicLinker(this.appLoader, env._unstable_relink_threshold);
 
         final int cacheSize = env._class_cache_size;
         if (cacheSize > 0) {
@@ -1181,15 +1142,6 @@
             checkPackageAccess(sm, fullName);
         }
 
-        // try the script -classpath loader, if that is set
-        if (classPathLoader != null) {
-            try {
-                return Class.forName(fullName, true, classPathLoader);
-            } catch (final ClassNotFoundException ignored) {
-                // ignore, continue search
-            }
-        }
-
         // Try finding using the "app" loader.
         return Class.forName(fullName, true, appLoader);
     }
@@ -1308,6 +1260,26 @@
         return getContext(getGlobal());
     }
 
+    /**
+     * Gets the Nashorn dynamic linker for the specified class. If the class is
+     * a script class, the dynamic linker associated with its context is
+     * returned. Otherwise the dynamic linker associated with the current
+     * context is returned.
+     * @param clazz the class for which we want to retrieve a dynamic linker.
+     * @return the Nashorn dynamic linker for the specified class.
+     */
+    public static DynamicLinker getDynamicLinker(final Class<?> clazz) {
+        return fromClass(clazz).dynamicLinker;
+    }
+
+    /**
+     * Gets the Nashorn dynamic linker associated with the current context.
+     * @return the Nashorn dynamic linker for the current context.
+     */
+    public static DynamicLinker getDynamicLinker() {
+        return getContextTrusted().dynamicLinker;
+    }
+
     static Context getContextTrustedOrNull() {
         final Global global = Context.getGlobal();
         return global == null ? null : getContext(global);
@@ -1338,15 +1310,10 @@
     }
 
     private URL getResourceURL(final String resName) {
-        // try the classPathLoader if we have and then
-        // try the appLoader if non-null.
-        if (classPathLoader != null) {
-            return classPathLoader.getResource(resName);
-        } else if (appLoader != null) {
+        if (appLoader != null) {
             return appLoader.getResource(resName);
         }
-
-        return null;
+        return ClassLoader.getSystemResource(resName);
     }
 
     private Object evaluateSource(final Source source, final ScriptObject scope, final ScriptObject thiz) {
@@ -1447,7 +1414,14 @@
             final ScriptLoader loader = env._loader_per_compile ? createNewLoader() : scriptLoader;
             installer = new NamedContextCodeInstaller(this, cs, loader);
         } else {
-            installer = new AnonymousContextCodeInstaller(this, cs, getAnonymousHostClass(cs));
+            installer = new AnonymousContextCodeInstaller(this, cs,
+                    anonymousHostClasses.getOrCreate(cs, (key) ->
+                            createNewLoader().installClass(
+                                    // NOTE: we're defining these constants in AnonymousContextCodeInstaller so they are not
+                                    // initialized if we don't use AnonymousContextCodeInstaller. As this method is only ever
+                                    // invoked from AnonymousContextCodeInstaller, this is okay.
+                                    AnonymousContextCodeInstaller.ANONYMOUS_HOST_CLASS_NAME,
+                                    AnonymousContextCodeInstaller.ANONYMOUS_HOST_CLASS_BYTES, cs)));
         }
 
         if (storedScript == null) {
@@ -1683,5 +1657,4 @@
     public SwitchPoint getBuiltinSwitchPoint(final String name) {
         return builtinSwitchPoints.get(name);
     }
-
 }
--- a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/GlobalConstants.java	Mon Nov 23 15:32:02 2015 +0100
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/GlobalConstants.java	Thu Nov 26 01:06:51 2015 +0100
@@ -105,7 +105,7 @@
      * Access map for this global - associates a symbol name with an Access object, with getter
      * and invalidation information
      */
-    private final Map<String, Access> map = new HashMap<>();
+    private final Map<Object, Access> map = new HashMap<>();
 
     private final AtomicBoolean invalidatedForever = new AtomicBoolean(false);
 
@@ -301,7 +301,7 @@
      * that might be linked as MethodHandle.constant and force relink
      * @param name name of property
      */
-    void delete(final String name) {
+    void delete(final Object name) {
         if (!invalidatedForever.get()) {
             synchronized (this) {
                 final Access acc = map.get(name);
--- a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/JSType.java	Mon Nov 23 15:32:02 2015 +0100
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/JSType.java	Thu Nov 26 01:06:51 2015 +0100
@@ -40,8 +40,10 @@
 import jdk.nashorn.internal.codegen.CompilerConstants.Call;
 import jdk.nashorn.internal.codegen.types.Type;
 import jdk.nashorn.internal.objects.Global;
+import jdk.nashorn.internal.objects.NativeSymbol;
 import jdk.nashorn.internal.parser.Lexer;
 import jdk.nashorn.internal.runtime.arrays.ArrayLikeIterator;
+import jdk.nashorn.internal.runtime.doubleconv.DoubleConversion;
 import jdk.nashorn.internal.runtime.linker.Bootstrap;
 
 /**
@@ -67,7 +69,10 @@
     OBJECT("object"),
 
     /** The function type */
-    FUNCTION("function");
+    FUNCTION("function"),
+
+    /** The symbol type */
+    SYMBOL("symbol");
 
     /** The type name as returned by ECMAScript "typeof" operator*/
     private final String typeName;
@@ -311,6 +316,10 @@
             return JSType.NUMBER;
         }
 
+        if (obj instanceof Symbol) {
+            return JSType.SYMBOL;
+        }
+
         if (obj == ScriptRuntime.UNDEFINED) {
             return JSType.UNDEFINED;
         }
@@ -353,6 +362,10 @@
             return JSType.UNDEFINED;
         }
 
+        if (obj instanceof Symbol) {
+            return JSType.SYMBOL;
+        }
+
         return JSType.OBJECT;
     }
 
@@ -469,9 +482,10 @@
     public static boolean isPrimitive(final Object obj) {
         return obj == null ||
                obj == ScriptRuntime.UNDEFINED ||
+               isString(obj) ||
+               obj instanceof Number ||
                obj instanceof Boolean ||
-               obj instanceof Number ||
-               isString(obj);
+               obj instanceof Symbol;
     }
 
    /**
@@ -613,6 +627,15 @@
     }
 
     /**
+     * See ES6 #7.1.14
+     * @param obj key object
+     * @return property key
+     */
+    public static Object toPropertyKey(final Object obj) {
+        return obj instanceof Symbol ? obj : toStringImpl(obj, false);
+    }
+
+    /**
      * If obj is an instance of {@link ConsString} cast to CharSequence, else return
      * result of {@link #toString(Object)}.
      *
@@ -687,7 +710,7 @@
             return "NaN";
         }
 
-        return NumberToString.stringFor(num);
+        return DoubleConversion.toShortestString(num);
     }
 
     /**
@@ -786,7 +809,9 @@
      * @return a number
      */
     public static double toNumberForEq(final Object obj) {
-        return obj == null ? Double.NaN : toNumber(obj);
+        // we are not able to detect Symbol objects from codegen, so we need to
+        // handle them here to avoid throwing an error in toNumber conversion.
+        return obj == null || obj instanceof Symbol || obj instanceof NativeSymbol ? Double.NaN : toNumber(obj);
     }
 
     /**
@@ -1403,6 +1428,13 @@
             return obj.toString();
         }
 
+        if (obj instanceof Symbol) {
+            if (safe) {
+                return obj.toString();
+            }
+            throw typeError("symbol.to.string");
+        }
+
         if (safe && obj instanceof ScriptObject) {
             final ScriptObject sobj = (ScriptObject)obj;
             final Global gobj = Context.getGlobal();
@@ -1915,6 +1947,10 @@
             return Double.NaN;
         }
 
+        if (obj instanceof Symbol) {
+            throw typeError("symbol.to.number");
+        }
+
         return toNumber(toPrimitive(obj, Number.class));
     }
 
--- a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/NashornLoader.java	Mon Nov 23 15:32:02 2015 +0100
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/NashornLoader.java	Thu Nov 26 01:06:51 2015 +0100
@@ -35,7 +35,6 @@
 import java.security.PermissionCollection;
 import java.security.Permissions;
 import java.security.SecureClassLoader;
-import jdk.nashorn.tools.Shell;
 
 /**
  * Superclass for Nashorn class loader classes.
@@ -103,10 +102,10 @@
     /**
      * Create a secure URL class loader for the given classpath
      * @param classPath classpath for the loader to search from
+     * @param parent the parent class loader for the new class loader
      * @return the class loader
      */
-    static ClassLoader createClassLoader(final String classPath) {
-        final ClassLoader parent = Shell.class.getClassLoader();
+    static ClassLoader createClassLoader(final String classPath, final ClassLoader parent) {
         final URL[] urls = pathToURLs(classPath);
         return URLClassLoader.newInstance(urls, parent);
     }
--- a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/NativeJavaPackage.java	Mon Nov 23 15:32:02 2015 +0100
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/NativeJavaPackage.java	Thu Nov 26 01:06:51 2015 +0100
@@ -207,8 +207,11 @@
     }
 
     @Override
-    protected Object invokeNoSuchProperty(final String key, final boolean isScope, final int programPoint) {
-        final Object retval = createProperty(key);
+    protected Object invokeNoSuchProperty(final Object key, final boolean isScope, final int programPoint) {
+        if (!(key instanceof String)) {
+            return super.invokeNoSuchProperty(key, isScope, programPoint);
+        }
+        final Object retval = createProperty((String) key);
         if (isValid(programPoint)) {
             throw new UnwarrantedOptimismException(retval, programPoint);
         }
--- a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/NumberToString.java	Mon Nov 23 15:32:02 2015 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,786 +0,0 @@
-/*
- * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.  Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-package jdk.nashorn.internal.runtime;
-
-import java.math.BigInteger;
-
-/**
- * JavaScript number to string conversion, refinement of sun.misc.FloatingDecimal.
- */
-public final class NumberToString {
-    /** Is not a number flag */
-    private final boolean isNaN;
-
-    /** Is a negative number flag. */
-    private boolean isNegative;
-
-    /** Decimal exponent value (for E notation.) */
-    private int decimalExponent;
-
-    /** Actual digits. */
-    private char digits[];
-
-    /** Number of digits to use. (nDigits <= digits.length). */
-    private int nDigits;
-
-    /*
-     * IEEE-754 constants.
-     */
-
-    //private static final long   signMask           = 0x8000000000000000L;
-    private static final int    expMask            = 0x7FF;
-    private static final long   fractMask          = 0x000F_FFFF_FFFF_FFFFL;
-    private static final int    expShift           = 52;
-    private static final int    expBias            = 1_023;
-    private static final long   fractHOB           = (1L << expShift);
-    private static final long   expOne             = ((long)expBias) << expShift;
-    private static final int    maxSmallBinExp     = 62;
-    private static final int    minSmallBinExp     = -(63 / 3);
-
-    /** Powers of 5 fitting a long. */
-    private static final long powersOf5[] = {
-        1L,
-        5L,
-        5L * 5,
-        5L * 5 * 5,
-        5L * 5 * 5 * 5,
-        5L * 5 * 5 * 5 * 5,
-        5L * 5 * 5 * 5 * 5 * 5,
-        5L * 5 * 5 * 5 * 5 * 5 * 5,
-        5L * 5 * 5 * 5 * 5 * 5 * 5 * 5,
-        5L * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5,
-        5L * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5,
-        5L * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5,
-        5L * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5,
-        5L * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5,
-        5L * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5,
-        5L * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5,
-        5L * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5,
-        5L * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5,
-        5L * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5,
-        5L * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5,
-        5L * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5,
-        5L * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5,
-        5L * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5,
-        5L * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5,
-        5L * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5,
-        5L * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5,
-        5L * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5
-    };
-
-    // Approximately ceil(log2(longPowers5[i])).
-    private static final int nBitsPowerOf5[] = {
-        0,
-        3,
-        5,
-        7,
-        10,
-        12,
-        14,
-        17,
-        19,
-        21,
-        24,
-        26,
-        28,
-        31,
-        33,
-        35,
-        38,
-        40,
-        42,
-        45,
-        47,
-        49,
-        52,
-        54,
-        56,
-        59,
-        61
-    };
-
-    /** Digits used for infinity result. */
-    private static final char infinityDigits[]   = { 'I', 'n', 'f', 'i', 'n', 'i', 't', 'y' };
-
-    /** Digits used for NaN result. */
-    private static final char nanDigits[]        = { 'N', 'a', 'N' };
-
-    /** Zeros used to pad result. */
-    private static final char zeroes[]           = { '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0' };
-
-
-    /**
-     * Convert a number into a JavaScript string.
-     * @param value Double to convert.
-     * @return JavaScript formated number.
-     */
-    public static String stringFor(final double value) {
-        return new NumberToString(value).toString();
-    }
-
-    /*
-     * Constructor.
-     */
-
-    private NumberToString(final double value) {
-        // Double as bits.
-        long bits = Double.doubleToLongBits(value);
-
-        // Get upper word.
-        final int upper = (int)(bits >> 32);
-
-        // Detect sign.
-        isNegative = upper < 0;
-
-        // Extract exponent.
-        int exponent = (upper >> (expShift - 32)) & expMask;
-
-        // Clear sign and exponent.
-        bits &= fractMask;
-
-        // Detect NaN.
-        if (exponent == expMask) {
-            isNaN = true;
-
-            // Detect Infinity.
-            if (bits == 0L) {
-                digits =  infinityDigits;
-            } else {
-                digits = nanDigits;
-                isNegative = false;
-            }
-
-            nDigits = digits.length;
-
-            return;
-        }
-
-        // We have a working double.
-        isNaN = false;
-
-        int nSignificantBits;
-
-        // Detect denormalized value.
-        if (exponent == 0) {
-            // Detect zero value.
-            if (bits == 0L) {
-                decimalExponent = 0;
-                digits = zeroes;
-                nDigits = 1;
-
-                return;
-            }
-
-            // Normalize value, using highest significant bit as HOB.
-            while ((bits & fractHOB) == 0L) {
-                bits <<= 1;
-                exponent -= 1;
-            }
-
-            // Compute number of significant bits.
-            nSignificantBits = expShift + exponent +1;
-            // Bias exponent by HOB.
-            exponent += 1;
-        } else {
-            // Add implicit HOB.
-            bits |= fractHOB;
-            // Compute number of significant bits.
-            nSignificantBits = expShift + 1;
-        }
-
-        // Unbias exponent (represents bit shift).
-        exponent -= expBias;
-
-        // Determine the number of significant bits in the fraction.
-        final int nFractBits = countSignificantBits(bits);
-
-        // Number of bits to the right of the decimal.
-        final int nTinyBits = Math.max(0, nFractBits - exponent - 1);
-
-        // Computed decimal exponent.
-        int decExponent;
-
-        if (exponent <= maxSmallBinExp && exponent >= minSmallBinExp) {
-            // Look more closely at the number to decide if,
-            // with scaling by 10^nTinyBits, the result will fit in
-            // a long.
-            if (nTinyBits < powersOf5.length && (nFractBits + nBitsPowerOf5[nTinyBits]) < 64) {
-                /*
-                 * We can do this:
-                 * take the fraction bits, which are normalized.
-                 * (a) nTinyBits == 0: Shift left or right appropriately
-                 *     to align the binary point at the extreme right, i.e.
-                 *     where a long int point is expected to be. The integer
-                 *     result is easily converted to a string.
-                 * (b) nTinyBits > 0: Shift right by expShift - nFractBits,
-                 *     which effectively converts to long and scales by
-                 *     2^nTinyBits. Then multiply by 5^nTinyBits to
-                 *     complete the scaling. We know this won't overflow
-                 *     because we just counted the number of bits necessary
-                 *     in the result. The integer you get from this can
-                 *     then be converted to a string pretty easily.
-                 */
-
-                if (nTinyBits == 0) {
-                    long halfULP;
-
-                    if (exponent > nSignificantBits) {
-                        halfULP = 1L << (exponent - nSignificantBits - 1);
-                    } else {
-                        halfULP = 0L;
-                    }
-
-                    if (exponent >= expShift) {
-                        bits <<= exponent - expShift;
-                    } else {
-                        bits >>>= expShift - exponent;
-                    }
-
-                    // Discard non-significant low-order bits, while rounding,
-                    // up to insignificant value.
-                    int i;
-                    for (i = 0; halfULP >= 10L; i++) {
-                        halfULP /= 10L;
-                    }
-
-                    /**
-                     * This is the easy subcase --
-                     * all the significant bits, after scaling, are held in bits.
-                     * isNegative and decExponent tell us what processing and scaling
-                     * has already been done. Exceptional cases have already been
-                     * stripped out.
-                     * In particular:
-                     *      bits is a finite number (not Infinite, nor NaN)
-                     *      bits > 0L (not zero, nor negative).
-                     *
-                     * The only reason that we develop the digits here, rather than
-                     * calling on Long.toString() is that we can do it a little faster,
-                     * and besides want to treat trailing 0s specially. If Long.toString
-                     * changes, we should re-evaluate this strategy!
-                     */
-
-                    int decExp = 0;
-
-                    if (i != 0) {
-                         // 10^i == 5^i * 2^i
-                        final long powerOf10 = powersOf5[i] << i;
-                        final long residue = bits % powerOf10;
-                        bits /= powerOf10;
-                        decExp += i;
-
-                        if (residue >= (powerOf10 >> 1)) {
-                            // Round up based on the low-order bits we're discarding.
-                            bits++;
-                        }
-                    }
-
-                    int ndigits = 20;
-                    final char[] digits0 = new char[26];
-                    int digitno = ndigits - 1;
-                    int c = (int)(bits % 10L);
-                    bits /= 10L;
-
-                    while (c == 0) {
-                        decExp++;
-                        c = (int)(bits % 10L);
-                        bits /= 10L;
-                    }
-
-                    while (bits != 0L) {
-                        digits0[digitno--] = (char)(c + '0');
-                        decExp++;
-                        c = (int)(bits % 10L);
-                        bits /= 10;
-                    }
-
-                    digits0[digitno] = (char)(c + '0');
-
-                    ndigits -= digitno;
-                    final char[] result = new char[ndigits];
-                    System.arraycopy(digits0, digitno, result, 0, ndigits);
-
-                    this.digits          = result;
-                    this.decimalExponent = decExp + 1;
-                    this.nDigits         = ndigits;
-
-                    return;
-                }
-            }
-        }
-
-        /*
-         * This is the hard case. We are going to compute large positive
-         * integers B and S and integer decExp, s.t.
-         *      d = (B / S) * 10^decExp
-         *      1 <= B / S < 10
-         * Obvious choices are:
-         *      decExp = floor(log10(d))
-         *      B      = d * 2^nTinyBits * 10^max(0, -decExp)
-         *      S      = 10^max(0, decExp) * 2^nTinyBits
-         * (noting that nTinyBits has already been forced to non-negative)
-         * I am also going to compute a large positive integer
-         *      M      = (1/2^nSignificantBits) * 2^nTinyBits * 10^max(0, -decExp)
-         * i.e. M is (1/2) of the ULP of d, scaled like B.
-         * When we iterate through dividing B/S and picking off the
-         * quotient bits, we will know when to stop when the remainder
-         * is <= M.
-         *
-         * We keep track of powers of 2 and powers of 5.
-         */
-
-        /*
-         * Estimate decimal exponent. (If it is small-ish,
-         * we could double-check.)
-         *
-         * First, scale the mantissa bits such that 1 <= d2 < 2.
-         * We are then going to estimate
-         *          log10(d2) ~=~  (d2-1.5)/1.5 + log(1.5)
-         * and so we can estimate
-         *      log10(d) ~=~ log10(d2) + binExp * log10(2)
-         * take the floor and call it decExp.
-         */
-        final double d2 = Double.longBitsToDouble(expOne | (bits & ~fractHOB));
-        decExponent = (int)Math.floor((d2 - 1.5D) * 0.289529654D + 0.176091259D + exponent * 0.301029995663981D);
-
-        // Powers of 2 and powers of 5, respectively, in B.
-        final int B5 = Math.max(0, -decExponent);
-        int B2 = B5 + nTinyBits + exponent;
-
-        // Powers of 2 and powers of 5, respectively, in S.
-        final int S5 = Math.max(0, decExponent);
-        int S2 = S5 + nTinyBits;
-
-        // Powers of 2 and powers of 5, respectively, in M.
-        final int M5 = B5;
-        int M2 = B2 - nSignificantBits;
-
-        /*
-         * The long integer fractBits contains the (nFractBits) interesting
-         * bits from the mantissa of d (hidden 1 added if necessary) followed
-         * by (expShift + 1 - nFractBits) zeros. In the interest of compactness,
-         * I will shift out those zeros before turning fractBits into a
-         * BigInteger. The resulting whole number will be
-         *      d * 2^(nFractBits - 1 - binExp).
-         */
-
-        bits >>>= expShift + 1 - nFractBits;
-        B2 -= nFractBits - 1;
-        final int common2factor = Math.min(B2, S2);
-        B2 -= common2factor;
-        S2 -= common2factor;
-        M2 -= common2factor;
-
-        /*
-         * HACK!!For exact powers of two, the next smallest number
-         * is only half as far away as we think (because the meaning of
-         * ULP changes at power-of-two bounds) for this reason, we
-         * hack M2. Hope this works.
-         */
-        if (nFractBits == 1) {
-            M2 -= 1;
-        }
-
-        if (M2 < 0) {
-            // Oops.  Since we cannot scale M down far enough,
-            // we must scale the other values up.
-            B2 -= M2;
-            S2 -= M2;
-            M2 =  0;
-        }
-
-        /*
-         * Construct, Scale, iterate.
-         * Some day, we'll write a stopping test that takes
-         * account of the asymmetry of the spacing of floating-point
-         * numbers below perfect powers of 2
-         * 26 Sept 96 is not that day.
-         * So we use a symmetric test.
-         */
-
-        final char digits0[] = this.digits = new char[32];
-        int  ndigit;
-        boolean low, high;
-        long lowDigitDifference;
-        int  q;
-
-        /*
-         * Detect the special cases where all the numbers we are about
-         * to compute will fit in int or long integers.
-         * In these cases, we will avoid doing BigInteger arithmetic.
-         * We use the same algorithms, except that we "normalize"
-         * our FDBigInts before iterating. This is to make division easier,
-         * as it makes our fist guess (quotient of high-order words)
-         * more accurate!
-         */
-
-        // Binary digits needed to represent B, approx.
-        final int Bbits = nFractBits + B2 + ((B5 < nBitsPowerOf5.length) ? nBitsPowerOf5[B5] : (B5*3));
-        // Binary digits needed to represent 10*S, approx.
-        final int tenSbits = S2 + 1 + (((S5 + 1) < nBitsPowerOf5.length) ? nBitsPowerOf5[(S5 + 1)] : ((S5 + 1) * 3));
-
-        if (Bbits < 64 && tenSbits < 64) {
-            long b = (bits * powersOf5[B5]) << B2;
-            final long s = powersOf5[S5] << S2;
-            long m = powersOf5[M5] << M2;
-            final long tens = s * 10L;
-
-            /*
-             * Unroll the first iteration. If our decExp estimate
-             * was too high, our first quotient will be zero. In this
-             * case, we discard it and decrement decExp.
-             */
-
-            ndigit = 0;
-            q = (int)(b / s);
-            b = 10L * (b % s);
-            m *= 10L;
-            low  = b <  m;
-            high = (b + m) > tens;
-
-            if (q == 0 && !high) {
-                // Ignore leading zero.
-                decExponent--;
-            } else {
-                digits0[ndigit++] = (char)('0' + q);
-            }
-
-            if (decExponent < -3 || decExponent >= 8) {
-                high = low = false;
-            }
-
-            while (!low && !high) {
-                q = (int)(b / s);
-                b = 10 * (b % s);
-                m *= 10;
-
-                if (m > 0L) {
-                    low  = b < m;
-                    high = (b + m) > tens;
-                } else {
-                    low = true;
-                    high = true;
-                }
-
-                if (low && q == 0) {
-                    break;
-                }
-                digits0[ndigit++] = (char)('0' + q);
-            }
-
-            lowDigitDifference = (b << 1) - tens;
-        } else {
-            /*
-             * We must do BigInteger arithmetic.
-             * First, construct our BigInteger initial values.
-             */
-
-            BigInteger Bval = multiplyPowerOf5And2(BigInteger.valueOf(bits), B5, B2);
-            BigInteger Sval = constructPowerOf5And2(S5, S2);
-            BigInteger Mval = constructPowerOf5And2(M5, M2);
-
-
-            // Normalize so that BigInteger division works better.
-            final int shiftBias = Long.numberOfLeadingZeros(bits) - 4;
-            Bval = Bval.shiftLeft(shiftBias);
-            Mval = Mval.shiftLeft(shiftBias);
-            Sval = Sval.shiftLeft(shiftBias);
-            final BigInteger tenSval = Sval.multiply(BigInteger.TEN);
-
-            /*
-             * Unroll the first iteration. If our decExp estimate
-             * was too high, our first quotient will be zero. In this
-             * case, we discard it and decrement decExp.
-             */
-
-            ndigit = 0;
-
-            BigInteger[] quoRem = Bval.divideAndRemainder(Sval);
-            q    = quoRem[0].intValue();
-            Bval = quoRem[1].multiply(BigInteger.TEN);
-            Mval = Mval.multiply(BigInteger.TEN);
-            low  = (Bval.compareTo(Mval) < 0);
-            high = (Bval.add(Mval).compareTo(tenSval) > 0);
-
-            if (q == 0 && !high) {
-                // Ignore leading zero.
-                decExponent--;
-            } else {
-                digits0[ndigit++] = (char)('0' + q);
-            }
-
-            if (decExponent < -3 || decExponent >= 8) {
-                high = low = false;
-            }
-
-            while(!low && !high) {
-                quoRem = Bval.divideAndRemainder(Sval);
-                q = quoRem[0].intValue();
-                Bval = quoRem[1].multiply(BigInteger.TEN);
-                Mval = Mval.multiply(BigInteger.TEN);
-                low  = (Bval.compareTo(Mval) < 0);
-                high = (Bval.add(Mval).compareTo(tenSval) > 0);
-
-                if (low && q == 0) {
-                    break;
-                }
-                digits0[ndigit++] = (char)('0' + q);
-            }
-
-            if (high && low) {
-                Bval = Bval.shiftLeft(1);
-                lowDigitDifference = Bval.compareTo(tenSval);
-            } else {
-                lowDigitDifference = 0L;
-            }
-        }
-
-        this.decimalExponent = decExponent + 1;
-        this.digits          = digits0;
-        this.nDigits         = ndigit;
-
-        /*
-         * Last digit gets rounded based on stopping condition.
-         */
-
-        if (high) {
-            if (low) {
-                if (lowDigitDifference == 0L) {
-                    // it's a tie!
-                    // choose based on which digits we like.
-                    if ((digits0[nDigits - 1] & 1) != 0) {
-                        roundup();
-                    }
-                } else if (lowDigitDifference > 0) {
-                    roundup();
-                }
-            } else {
-                roundup();
-            }
-        }
-    }
-
-    /**
-     * Count number of significant bits.
-     * @param bits Double's fraction.
-     * @return Number of significant bits.
-     */
-    private static int countSignificantBits(final long bits) {
-        if (bits != 0) {
-            return 64 - Long.numberOfLeadingZeros(bits) - Long.numberOfTrailingZeros(bits);
-        }
-
-        return 0;
-    }
-
-    /*
-     * Cache big powers of 5 handy for future reference.
-     */
-    private static BigInteger powerOf5Cache[];
-
-    /**
-     * Determine the largest power of 5 needed (as BigInteger.)
-     * @param power Power of 5.
-     * @return BigInteger of power of 5.
-     */
-    private static BigInteger bigPowerOf5(final int power) {
-        if (powerOf5Cache == null) {
-            powerOf5Cache = new BigInteger[power + 1];
-        } else if (powerOf5Cache.length <= power) {
-            final BigInteger t[] = new BigInteger[ power+1 ];
-            System.arraycopy(powerOf5Cache, 0, t, 0, powerOf5Cache.length);
-            powerOf5Cache = t;
-        }
-
-        if (powerOf5Cache[power] != null) {
-            return powerOf5Cache[power];
-        } else if (power < powersOf5.length) {
-            return powerOf5Cache[power] = BigInteger.valueOf(powersOf5[power]);
-        } else {
-            // Construct the value recursively.
-            // in order to compute 5^p,
-            // compute its square root, 5^(p/2) and square.
-            // or, let q = p / 2, r = p -q, then
-            // 5^p = 5^(q+r) = 5^q * 5^r
-            final int q = power >> 1;
-            final int r = power - q;
-            BigInteger bigQ = powerOf5Cache[q];
-
-            if (bigQ == null) {
-                bigQ = bigPowerOf5(q);
-            }
-
-            if (r < powersOf5.length) {
-                return (powerOf5Cache[power] = bigQ.multiply(BigInteger.valueOf(powersOf5[r])));
-            }
-            BigInteger bigR = powerOf5Cache[ r ];
-
-            if (bigR == null) {
-                bigR = bigPowerOf5(r);
-            }
-
-            return (powerOf5Cache[power] = bigQ.multiply(bigR));
-        }
-    }
-
-    /**
-     * Multiply BigInteger by powers of 5 and 2 (i.e., 10)
-     * @param value Value to multiply.
-     * @param p5    Power of 5.
-     * @param p2    Power of 2.
-     * @return Result.
-     */
-    private static BigInteger multiplyPowerOf5And2(final BigInteger value, final int p5, final int p2) {
-        BigInteger returnValue = value;
-
-        if (p5 != 0) {
-            returnValue = returnValue.multiply(bigPowerOf5(p5));
-        }
-
-        if (p2 != 0) {
-            returnValue = returnValue.shiftLeft(p2);
-        }
-
-        return returnValue;
-    }
-
-    /**
-     * Construct a BigInteger power of 5 and 2 (i.e., 10)
-     * @param p5    Power of 5.
-     * @param p2    Power of 2.
-     * @return Result.
-     */
-    private static BigInteger constructPowerOf5And2(final int p5, final int p2) {
-        BigInteger v = bigPowerOf5(p5);
-
-        if (p2 != 0) {
-            v = v.shiftLeft(p2);
-        }
-
-        return v;
-    }
-
-    /**
-     * Round up last digit by adding one to the least significant digit.
-     * In the unlikely event there is a carry out, deal with it.
-     * assert that this will only happen where there
-     * is only one digit, e.g. (float)1e-44 seems to do it.
-     */
-    private void roundup() {
-        int i;
-        int q = digits[ i = (nDigits-1)];
-
-        while (q == '9' && i > 0) {
-            if (decimalExponent < 0) {
-                nDigits--;
-            } else {
-                digits[i] = '0';
-            }
-
-            q = digits[--i];
-        }
-
-        if (q == '9') {
-            // Carryout! High-order 1, rest 0s, larger exp.
-            decimalExponent += 1;
-            digits[0] = '1';
-
-            return;
-        }
-
-        digits[i] = (char)(q + 1);
-    }
-
-    /**
-     * Format final number string.
-     * @return Formatted string.
-     */
-    @Override
-    public String toString() {
-        final StringBuilder sb = new StringBuilder(32);
-
-        if (isNegative) {
-            sb.append('-');
-        }
-
-        if (isNaN) {
-            sb.append(digits, 0, nDigits);
-        } else {
-            if (decimalExponent > 0 && decimalExponent <= 21) {
-                final int charLength = Math.min(nDigits, decimalExponent);
-                sb.append(digits, 0, charLength);
-
-                if (charLength < decimalExponent) {
-                    sb.append(zeroes, 0, decimalExponent - charLength);
-                } else if (charLength < nDigits) {
-                    sb.append('.');
-                    sb.append(digits, charLength, nDigits - charLength);
-                }
-            } else if (decimalExponent <=0 && decimalExponent > -6) {
-                sb.append('0');
-                sb.append('.');
-
-                if (decimalExponent != 0) {
-                    sb.append(zeroes, 0, -decimalExponent);
-                }
-
-                sb.append(digits, 0, nDigits);
-            } else {
-                sb.append(digits[0]);
-
-                if (nDigits > 1) {
-                    sb.append('.');
-                    sb.append(digits, 1, nDigits - 1);
-                }
-
-                sb.append('e');
-                final int exponent;
-                int e;
-
-                if (decimalExponent <= 0) {
-                    sb.append('-');
-                    exponent = e = -decimalExponent + 1;
-                } else {
-                    sb.append('+');
-                    exponent = e = decimalExponent - 1;
-                }
-
-                if (exponent > 99) {
-                    sb.append((char)(e / 100 + '0'));
-                    e %= 100;
-                }
-
-                if (exponent > 9) {
-                    sb.append((char)(e / 10 + '0'));
-                    e %= 10;
-                }
-
-                sb.append((char)(e + '0'));
-            }
-        }
-
-        return sb.toString();
-    }
-}
--- a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/Property.java	Mon Nov 23 15:32:02 2015 +0100
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/Property.java	Thu Nov 26 01:06:51 2015 +0100
@@ -100,7 +100,7 @@
     public static final int DUAL_FIELDS             = 1 << 11;
 
     /** Property key. */
-    private final String key;
+    private final Object key;
 
     /** Property flags. */
     private int flags;
@@ -127,7 +127,7 @@
      * @param flags property flags
      * @param slot  property field number or spill slot
      */
-    Property(final String key, final int flags, final int slot) {
+    Property(final Object key, final int flags, final int slot) {
         assert key != null;
         this.key   = key;
         this.flags = flags;
@@ -420,7 +420,7 @@
      * Get the key for this property. This key is an ordinary string. The "name".
      * @return key for property
      */
-    public String getKey() {
+    public Object getKey() {
         return key;
     }
 
@@ -627,7 +627,7 @@
         final StringBuilder sb   = new StringBuilder();
         final Class<?>      t = getLocalType();
 
-        sb.append(indent(getKey(), 20)).
+        sb.append(indent(getKey().toString(), 20)).
             append(" id=").
             append(Debug.id(this)).
             append(" (0x").
--- a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/PropertyHashMap.java	Mon Nov 23 15:32:02 2015 +0100
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/PropertyHashMap.java	Thu Nov 26 01:06:51 2015 +0100
@@ -102,7 +102,7 @@
  * immutable hash map, addition is constant time.  For LinkedHashMap it's O(N+C)
  * since we have to clone the older map.
  */
-public final class PropertyHashMap implements Map <String, Property> {
+public final class PropertyHashMap implements Map <Object, Property> {
     /** Number of initial bins. Power of 2. */
     private static final int INITIAL_BINS = 32;
 
@@ -243,7 +243,7 @@
      *
      * @return New {@link PropertyHashMap}.
      */
-    public PropertyHashMap immutableRemove(final String key) {
+    public PropertyHashMap immutableRemove(final Object key) {
         if (bins != null) {
             final int binIndex = binIndex(bins, key);
             final Element bin = bins[binIndex];
@@ -271,7 +271,7 @@
      *
      * @return {@link Property} matching key or {@code null} if not found.
      */
-    public Property find(final String key) {
+    public Property find(final Object key) {
         final Element element = findElement(key);
         return element != null ? element.getProperty() : null;
     }
@@ -301,7 +301,7 @@
      *
      * @return The bin index.
      */
-    private static int binIndex(final Element[] bins, final String key) {
+    private static int binIndex(final Element[] bins, final Object key) {
         return  key.hashCode() & bins.length - 1;
     }
 
@@ -340,7 +340,7 @@
         final Element[] newBins = new Element[binSize];
         for (Element element = list; element != null; element = element.getLink()) {
             final Property property = element.getProperty();
-            final String   key      = property.getKey();
+            final Object   key      = property.getKey();
             final int      binIndex = binIndex(newBins, key);
 
             newBins[binIndex] = new Element(newBins[binIndex], property);
@@ -355,7 +355,7 @@
      *
      * @return {@link Element} matching key or {@code null} if not found.
      */
-    private Element findElement(final String key) {
+    private Element findElement(final Object key) {
         if (bins != null) {
             final int binIndex = binIndex(bins, key);
             return findElement(bins[binIndex], key);
@@ -370,7 +370,7 @@
      * @param key         {@link Element} key.
      * @return {@link Element} matching key or {@code null} if not found.
      */
-    private static Element findElement(final Element elementList, final String key) {
+    private static Element findElement(final Element elementList, final Object key) {
         final int hashCode = key.hashCode();
         for (Element element = elementList; element != null; element = element.getLink()) {
             if (element.match(key, hashCode)) {
@@ -416,7 +416,7 @@
      */
     private PropertyHashMap addNoClone(final Property property) {
         int newSize = size;
-        final String key = property.getKey();
+        final Object key = property.getKey();
         Element newList = list;
         if (bins != null) {
             final int binIndex = binIndex(bins, key);
@@ -437,7 +437,7 @@
         return new PropertyHashMap(newSize, bins, newList);
     }
 
-    private PropertyHashMap replaceNoClone(final String key, final Property property) {
+    private PropertyHashMap replaceNoClone(final Object key, final Property property) {
         if (bins != null) {
             final int binIndex = binIndex(bins, key);
             Element bin = bins[binIndex];
@@ -457,7 +457,7 @@
      *
      * @return New list with {@link Element} removed.
      */
-    private static Element removeFromList(final Element list, final String key) {
+    private static Element removeFromList(final Element list, final Object key) {
         if (list == null) {
             return null;
         }
@@ -480,7 +480,7 @@
     }
 
     // for element x. if x get link matches,
-    private static Element replaceInList(final Element list, final String key, final Property property) {
+    private static Element replaceInList(final Element list, final Object key, final Property property) {
         assert list != null;
         final int hashCode = key.hashCode();
 
@@ -519,21 +519,7 @@
 
     @Override
     public boolean containsKey(final Object key) {
-        if (key instanceof String) {
-            return findElement((String)key) != null;
-        }
-        assert key instanceof String;
-        return false;
-    }
-
-    /**
-     * Check if the map contains a key.
-     *
-     * @param key {@link Property} key.
-     *
-     * @return {@code true} of key is in {@link PropertyHashMap}.
-     */
-    public boolean containsKey(final String key) {
+        assert key instanceof String || key instanceof Symbol;
         return findElement(key) != null;
     }
 
@@ -549,29 +535,13 @@
 
     @Override
     public Property get(final Object key) {
-        if (key instanceof String) {
-            final Element element = findElement((String)key);
-            return element != null ? element.getProperty() : null;
-        }
-        assert key instanceof String;
-        return null;
-    }
-
-    /**
-     * Get the {@link Property} given a key that is an explicit {@link String}.
-     * See also {@link PropertyHashMap#get(Object)}
-     *
-     * @param key {@link Property} key.
-     *
-     * @return {@link Property}, or {@code null} if no property with that key was found.
-     */
-    public Property get(final String key) {
+        assert key instanceof String || key instanceof Symbol;
         final Element element = findElement(key);
         return element != null ? element.getProperty() : null;
     }
 
     @Override
-    public Property put(final String key, final Property value) {
+    public Property put(final Object key, final Property value) {
         throw new UnsupportedOperationException("Immutable map.");
     }
 
@@ -581,7 +551,7 @@
     }
 
     @Override
-    public void putAll(final Map<? extends String, ? extends Property> m) {
+    public void putAll(final Map<? extends Object, ? extends Property> m) {
         throw new UnsupportedOperationException("Immutable map.");
     }
 
@@ -591,8 +561,8 @@
     }
 
     @Override
-    public Set<String> keySet() {
-        final HashSet<String> set = new HashSet<>();
+    public Set<Object> keySet() {
+        final HashSet<Object> set = new HashSet<>();
         for (Element element = list; element != null; element = element.getLink()) {
             set.add(element.getKey());
         }
@@ -605,8 +575,8 @@
     }
 
     @Override
-    public Set<Entry<String, Property>> entrySet() {
-        final HashSet<Entry<String, Property>> set = new HashSet<>();
+    public Set<Entry<Object, Property>> entrySet() {
+        final HashSet<Entry<Object, Property>> set = new HashSet<>();
         for (Element element = list; element != null; element = element.getLink()) {
             set.add(element);
         }
@@ -616,7 +586,7 @@
     /**
      * List map element.
      */
-    static final class Element implements Entry<String, Property> {
+    static final class Element implements Entry<Object, Property> {
         /** Link for list construction. */
         private Element link;
 
@@ -624,7 +594,7 @@
         private final Property property;
 
         /** Element key. Kept separate for performance.) */
-        private final String key;
+        private final Object key;
 
         /** Element key hash code. */
         private final int hashCode;
@@ -640,7 +610,7 @@
             this.hashCode = this.key.hashCode();
         }
 
-        boolean match(final String otherKey, final int otherHashCode) {
+        boolean match(final Object otherKey, final int otherHashCode) {
             return this.hashCode == otherHashCode && this.key.equals(otherKey);
         }
 
@@ -655,7 +625,7 @@
         }
 
         @Override
-        public String getKey() {
+        public Object getKey() {
             return key;
         }
 
--- a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/PropertyListeners.java	Mon Nov 23 15:32:02 2015 +0100
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/PropertyListeners.java	Thu Nov 26 01:06:51 2015 +0100
@@ -35,7 +35,7 @@
  */
 public class PropertyListeners {
 
-    private Map<String, WeakPropertyMapSet> listeners;
+    private Map<Object, WeakPropertyMapSet> listeners;
 
     // These counters are updated in debug mode
     private static LongAdder listenersAdded;
--- a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/PropertyMap.java	Mon Nov 23 15:32:02 2015 +0100
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/PropertyMap.java	Thu Nov 26 01:06:51 2015 +0100
@@ -96,7 +96,7 @@
     private transient SharedPropertyMap sharedProtoMap;
 
     /** {@link SwitchPoint}s for gets on inherited properties. */
-    private transient HashMap<String, SwitchPoint> protoSwitches;
+    private transient HashMap<Object, SwitchPoint> protoSwitches;
 
     /** History of maps, used to limit map duplication. */
     private transient WeakHashMap<Property, Reference<PropertyMap>> history;
@@ -354,7 +354,7 @@
      *
      * @param key {@link Property} key to invalidate.
      */
-    synchronized void invalidateProtoSwitchPoint(final String key) {
+    synchronized void invalidateProtoSwitchPoint(final Object key) {
         if (protoSwitches != null) {
             final SwitchPoint sp = protoSwitches.get(key);
             if (sp != null) {
@@ -496,7 +496,7 @@
     public final synchronized PropertyMap deleteProperty(final Property property) {
         propertyDeleted(property, true);
         PropertyMap newMap = checkHistory(property);
-        final String key = property.getKey();
+        final Object key = property.getKey();
 
         if (newMap == null && properties.containsKey(key)) {
             final PropertyHashMap newProperties = properties.immutableRemove(key);
@@ -577,7 +577,7 @@
      * @param propertyFlags attribute flags of the property
      * @return the newly created UserAccessorProperty
      */
-    public final UserAccessorProperty newUserAccessors(final String key, final int propertyFlags) {
+    public final UserAccessorProperty newUserAccessors(final Object key, final int propertyFlags) {
         return new UserAccessorProperty(key, propertyFlags, getFreeSpillSlot());
     }
 
@@ -588,7 +588,7 @@
      *
      * @return {@link Property} matching key.
      */
-    public final Property findProperty(final String key) {
+    public final Property findProperty(final Object key) {
         return properties.find(key);
     }
 
--- a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/ScriptEnvironment.java	Mon Nov 23 15:32:02 2015 +0100
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/ScriptEnvironment.java	Thu Nov 26 01:06:51 2015 +0100
@@ -81,6 +81,9 @@
     /** Generate line number table in class files */
     public final boolean _debug_lines;
 
+    /** Put all variables in scopes to make them debuggable */
+    public final boolean _debug_scopes;
+
     /** Directory in which source files and generated class files are dumped */
     public final String  _dest_dir;
 
@@ -105,6 +108,12 @@
     /** Enable experimental ECMAScript 6 features. */
     public final boolean _es6;
 
+
+    /** Number of times a dynamic call site has to be relinked before it is
+     * considered unstable (and thus should be linked as if it were megamorphic).
+     */
+    public final int _unstable_relink_threshold;
+
     /** Argument passed to compile only if optimistic compilation should take place */
     public static final String COMPILE_ONLY_OPTIMISTIC_ARG = "optimistic";
 
@@ -240,6 +249,7 @@
         _compile_only         = options.getBoolean("compile.only");
         _const_as_var         = options.getBoolean("const.as.var");
         _debug_lines          = options.getBoolean("debug.lines");
+        _debug_scopes         = options.getBoolean("debug.scopes");
         _dest_dir             = options.getString("d");
         _dump_on_error        = options.getBoolean("doe");
         _early_lvalue_error   = options.getBoolean("early.lvalue.error");
@@ -287,6 +297,25 @@
         _version              = options.getBoolean("version");
         _verify_code          = options.getBoolean("verify.code");
 
+        final int configuredUrt = options.getInteger("unstable.relink.threshold");
+        // The default for this property is -1, so we can easily detect when
+        // it is not specified on command line.
+        if (configuredUrt < 0) {
+            // In this case, use a default of 8, or 16 for optimistic types.
+            // Optimistic types come with dual fields, and in order to get
+            // performance on benchmarks with a lot of object instantiation and
+            // then field reassignment, it can take slightly more relinks to
+            // become stable with type changes swapping out an entire property
+            // map and making a map guard fail. Also, honor the "nashorn.*"
+            // system property for now. It was documented in DEVELOPER_README
+            // so we should recognize it for the time being.
+            _unstable_relink_threshold = Options.getIntProperty(
+                    "nashorn.unstable.relink.threshold",
+                    _optimistic_types ? 16 : 8);
+        } else {
+            _unstable_relink_threshold = configuredUrt;
+        }
+
         final String anonClasses = options.getString("anonymous.classes");
         if (anonClasses == null || anonClasses.equals("auto")) {
             _anonymousClasses = AnonymousClasses.AUTO;
--- a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/ScriptFunction.java	Mon Nov 23 15:32:02 2015 +0100
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/ScriptFunction.java	Thu Nov 26 01:06:51 2015 +0100
@@ -51,6 +51,7 @@
 import jdk.nashorn.internal.codegen.ApplySpecialization;
 import jdk.nashorn.internal.codegen.Compiler;
 import jdk.nashorn.internal.codegen.CompilerConstants.Call;
+import jdk.nashorn.internal.ir.FunctionNode;
 import jdk.nashorn.internal.objects.Global;
 import jdk.nashorn.internal.objects.NativeFunction;
 import jdk.nashorn.internal.objects.annotations.SpecializedFunction.LinkLogic;
@@ -472,6 +473,15 @@
     }
 
     /**
+     * Is this is a function with all variables in scope?
+     * @return true if function has all
+     */
+    public boolean hasAllVarsInScope() {
+        return data instanceof RecompilableScriptFunctionData &&
+                (((RecompilableScriptFunctionData) data).getFunctionFlags() & FunctionNode.HAS_ALL_VARS_IN_SCOPE) != 0;
+    }
+
+    /**
      * Returns true if this is a non-strict, non-built-in function that requires
      * non-primitive this argument according to ECMA 10.4.3.
      *
--- a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/ScriptObject.java	Mon Nov 23 15:32:02 2015 +0100
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/ScriptObject.java	Thu Nov 26 01:06:51 2015 +0100
@@ -53,6 +53,7 @@
 import java.lang.invoke.MethodHandles;
 import java.lang.invoke.MethodType;
 import java.lang.invoke.SwitchPoint;
+import java.lang.reflect.Array;
 import java.util.AbstractMap;
 import java.util.ArrayList;
 import java.util.Arrays;
@@ -310,11 +311,11 @@
      */
     protected PropertyMap addBoundProperty(final PropertyMap propMap, final ScriptObject source, final Property property, final boolean extensible) {
         PropertyMap newMap = propMap;
-        final String key = property.getKey();
+        final Object key = property.getKey();
         final Property oldProp = newMap.findProperty(key);
         if (oldProp == null) {
             if (! extensible) {
-                throw typeError("object.non.extensible", key, ScriptRuntime.safeToString(this));
+                throw typeError("object.non.extensible", key.toString(), ScriptRuntime.safeToString(this));
             }
 
             if (property instanceof UserAccessorProperty) {
@@ -330,7 +331,7 @@
             if (property.isFunctionDeclaration() && !oldProp.isConfigurable()) {
                 if (oldProp instanceof UserAccessorProperty ||
                         !(oldProp.isWritable() && oldProp.isEnumerable())) {
-                    throw typeError("cant.redefine.property", key, ScriptRuntime.safeToString(this));
+                    throw typeError("cant.redefine.property", key.toString(), ScriptRuntime.safeToString(this));
                 }
             }
         }
@@ -348,11 +349,11 @@
         final boolean extensible = newMap.isExtensible();
 
         for (final AccessorProperty property : properties) {
-            final String key = property.getKey();
+            final Object key = property.getKey();
 
             if (newMap.findProperty(key) == null) {
                 if (! extensible) {
-                    throw typeError("object.non.extensible", key, ScriptRuntime.safeToString(this));
+                    throw typeError("object.non.extensible", key.toString(), ScriptRuntime.safeToString(this));
                 }
                 newMap = newMap.addPropertyBind(property, source);
             }
@@ -456,7 +457,7 @@
      * @return Returns the Property Descriptor of the named own property of this
      * object, or undefined if absent.
      */
-    public Object getOwnPropertyDescriptor(final String key) {
+    public Object getOwnPropertyDescriptor(final Object key) {
         final Property property = getMap().findProperty(key);
 
         final Global global = Context.getGlobal();
@@ -518,7 +519,7 @@
      * Invalidate any existing global constant method handles that may exist for {@code key}.
      * @param key the property name
      */
-    protected void invalidateGlobalConstant(final String key) {
+    protected void invalidateGlobalConstant(final Object key) {
         final GlobalConstants globalConstants = getGlobalConstants();
         if (globalConstants != null) {
             globalConstants.delete(key);
@@ -534,11 +535,10 @@
      *
      * @return true if property was successfully defined
      */
-    public boolean defineOwnProperty(final String key, final Object propertyDesc, final boolean reject) {
+    public boolean defineOwnProperty(final Object key, final Object propertyDesc, final boolean reject) {
         final Global             global  = Context.getGlobal();
         final PropertyDescriptor desc    = toPropertyDescriptor(global, propertyDesc);
         final Object             current = getOwnPropertyDescriptor(key);
-        final String             name    = JSType.toString(key);
 
         invalidateGlobalConstant(key);
 
@@ -550,7 +550,7 @@
             }
             // new property added to non-extensible object
             if (reject) {
-                throw typeError(global, "object.non.extensible", name, ScriptRuntime.safeToString(this));
+                throw typeError(global, "object.non.extensible", key.toString(), ScriptRuntime.safeToString(this));
             }
             return false;
         }
@@ -573,7 +573,7 @@
             if (newDesc.has(CONFIGURABLE) && newDesc.isConfigurable()) {
                 // not configurable can not be made configurable
                 if (reject) {
-                    throw typeError(global, "cant.redefine.property", name, ScriptRuntime.safeToString(this));
+                    throw typeError(global, "cant.redefine.property", key.toString(), ScriptRuntime.safeToString(this));
                 }
                 return false;
             }
@@ -582,7 +582,7 @@
                 currentDesc.isEnumerable() != newDesc.isEnumerable()) {
                 // cannot make non-enumerable as enumerable or vice-versa
                 if (reject) {
-                    throw typeError(global, "cant.redefine.property", name, ScriptRuntime.safeToString(this));
+                    throw typeError(global, "cant.redefine.property", key.toString(), ScriptRuntime.safeToString(this));
                 }
                 return false;
             }
@@ -598,7 +598,7 @@
                 if (newDesc.has(WRITABLE) && newDesc.isWritable() ||
                     newDesc.has(VALUE) && !ScriptRuntime.sameValue(currentDesc.getValue(), newDesc.getValue())) {
                     if (reject) {
-                        throw typeError(global, "cant.redefine.property", name, ScriptRuntime.safeToString(this));
+                        throw typeError(global, "cant.redefine.property", key.toString(), ScriptRuntime.safeToString(this));
                     }
                     return false;
                 }
@@ -636,7 +636,7 @@
                 if (newDesc.has(PropertyDescriptor.GET) && !ScriptRuntime.sameValue(currentDesc.getGetter(), newDesc.getGetter()) ||
                     newDesc.has(PropertyDescriptor.SET) && !ScriptRuntime.sameValue(currentDesc.getSetter(), newDesc.getSetter())) {
                     if (reject) {
-                        throw typeError(global, "cant.redefine.property", name, ScriptRuntime.safeToString(this));
+                        throw typeError(global, "cant.redefine.property", key.toString(), ScriptRuntime.safeToString(this));
                     }
                     return false;
                 }
@@ -650,7 +650,7 @@
             if (!currentDesc.isConfigurable()) {
                 // not configurable can not be made configurable
                 if (reject) {
-                    throw typeError(global, "cant.redefine.property", name, ScriptRuntime.safeToString(this));
+                    throw typeError(global, "cant.redefine.property", key.toString(), ScriptRuntime.safeToString(this));
                 }
                 return false;
             }
@@ -716,7 +716,7 @@
         setArray(getArray().set(index, value, false));
     }
 
-    private void checkIntegerKey(final String key) {
+    private void checkIntegerKey(final Object key) {
         final int index = getArrayIndex(key);
 
         if (isValidArrayIndex(index)) {
@@ -734,7 +734,7 @@
       * @param key          property key
       * @param propertyDesc property descriptor for property
       */
-    public final void addOwnProperty(final String key, final PropertyDescriptor propertyDesc) {
+    public final void addOwnProperty(final Object key, final PropertyDescriptor propertyDesc) {
         // Already checked that there is no own property with that key.
         PropertyDescriptor pdesc = propertyDesc;
 
@@ -776,7 +776,7 @@
      *
      * @return FindPropertyData or null if not found.
      */
-    public final FindProperty findProperty(final String key, final boolean deep) {
+    public final FindProperty findProperty(final Object key, final boolean deep) {
         return findProperty(key, deep, this);
     }
 
@@ -798,7 +798,7 @@
      *
      * @return FindPropertyData or null if not found.
      */
-    protected FindProperty findProperty(final String key, final boolean deep, final ScriptObject start) {
+    protected FindProperty findProperty(final Object key, final boolean deep, final ScriptObject start) {
 
         final PropertyMap selfMap  = getMap();
         final Property    property = selfMap.findProperty(key);
@@ -820,13 +820,13 @@
     }
 
     /**
-     * Low level property API. This is similar to {@link #findProperty(String, boolean)} but returns a
+     * Low level property API. This is similar to {@link #findProperty(Object, boolean)} but returns a
      * {@code boolean} value instead of a {@link FindProperty} object.
      * @param key  Property key.
      * @param deep Whether the search should look up proto chain.
      * @return true if the property was found.
      */
-    boolean hasProperty(final String key, final boolean deep) {
+    boolean hasProperty(final Object key, final boolean deep) {
         if (getMap().findProperty(key) != null) {
             return true;
         }
@@ -841,7 +841,7 @@
         return false;
     }
 
-    private SwitchPoint findBuiltinSwitchPoint(final String key) {
+    private SwitchPoint findBuiltinSwitchPoint(final Object key) {
         for (ScriptObject myProto = getProto(); myProto != null; myProto = myProto.getProto()) {
             final Property prop = myProto.getMap().findProperty(key);
             if (prop != null) {
@@ -866,7 +866,7 @@
      *
      * @return New property.
      */
-    public final Property addOwnProperty(final String key, final int propertyFlags, final ScriptFunction getter, final ScriptFunction setter) {
+    public final Property addOwnProperty(final Object key, final int propertyFlags, final ScriptFunction getter, final ScriptFunction setter) {
         return addOwnProperty(newUserAccessors(key, propertyFlags, getter, setter));
     }
 
@@ -881,7 +881,7 @@
      *
      * @return New property.
      */
-    public final Property addOwnProperty(final String key, final int propertyFlags, final Object value) {
+    public final Property addOwnProperty(final Object key, final int propertyFlags, final Object value) {
         return addSpillProperty(key, propertyFlags, value, true);
     }
 
@@ -1244,7 +1244,7 @@
     public final ScriptObject getProto(final int n) {
         assert n > 0;
         ScriptObject p = getProto();
-        for (int i = n; i-- > 0;) {
+        for (int i = n; --i > 0;) {
             p = p.getProto();
         }
         return p;
@@ -1349,42 +1349,60 @@
         final Set<String> keys = new HashSet<>();
         final Set<String> nonEnumerable = new HashSet<>();
         for (ScriptObject self = this; self != null; self = self.getProto()) {
-            keys.addAll(Arrays.asList(self.getOwnKeys(true, nonEnumerable)));
+            keys.addAll(Arrays.asList(self.getOwnKeys(String.class, true, nonEnumerable)));
         }
         return keys.toArray(new String[keys.size()]);
     }
 
     /**
-     * return an array of own property keys associated with the object.
+     * Return an array of own property keys associated with the object.
      *
      * @param all True if to include non-enumerable keys.
      * @return Array of keys.
      */
     public final String[] getOwnKeys(final boolean all) {
-        return getOwnKeys(all, null);
+        return getOwnKeys(String.class, all, null);
+    }
+
+    /**
+     * Return an array of own property keys associated with the object.
+     *
+     * @param all True if to include non-enumerable keys.
+     * @return Array of keys.
+     */
+    public final Symbol[] getOwnSymbols(final boolean all) {
+        return getOwnKeys(Symbol.class, all, null);
     }
 
     /**
      * return an array of own property keys associated with the object.
      *
+     * @param <T> the type returned keys.
+     * @param type the type of keys to return, either {@code String.class} or {@code Symbol.class}.
      * @param all True if to include non-enumerable keys.
-     * @param nonEnumerable set of non-enumerable properties seen already.Used
-       to filter out shadowed, but enumerable properties from proto children.
+     * @param nonEnumerable set of non-enumerable properties seen already. Used to
+     *                      filter out shadowed, but enumerable properties from proto children.
      * @return Array of keys.
      */
-    protected String[] getOwnKeys(final boolean all, final Set<String> nonEnumerable) {
+    @SuppressWarnings("unchecked")
+    protected <T> T[] getOwnKeys(final Class<T> type, final boolean all, final Set<T> nonEnumerable) {
         final List<Object> keys    = new ArrayList<>();
         final PropertyMap  selfMap = this.getMap();
 
         final ArrayData array  = getArray();
 
-        for (final Iterator<Long> iter = array.indexIterator(); iter.hasNext(); ) {
-            keys.add(JSType.toString(iter.next().longValue()));
+        if (type == String.class) {
+            for (final Iterator<Long> iter = array.indexIterator(); iter.hasNext(); ) {
+                keys.add(JSType.toString(iter.next().longValue()));
+            }
         }
 
         for (final Property property : selfMap.getProperties()) {
             final boolean enumerable = property.isEnumerable();
-            final String key = property.getKey();
+            final Object key = property.getKey();
+            if (!type.isInstance(key)) {
+                continue;
+            }
             if (all) {
                 keys.add(key);
             } else if (enumerable) {
@@ -1396,12 +1414,12 @@
             } else {
                 // store this non-enumerable property for later proto walk
                 if (nonEnumerable != null) {
-                    nonEnumerable.add(key);
+                    nonEnumerable.add((T) key);
                 }
             }
         }
 
-        return keys.toArray(new String[keys.size()]);
+        return keys.toArray((T[]) Array.newInstance(type, keys.size()));
     }
 
     /**
@@ -2397,12 +2415,12 @@
 
     /**
      * Invoke fall back if a property is not found.
-     * @param name Name of property.
+     * @param key Name of property.
      * @param isScope is this a scope access?
      * @param programPoint program point
      * @return Result from call.
      */
-    protected Object invokeNoSuchProperty(final String name, final boolean isScope, final int programPoint) {
+    protected Object invokeNoSuchProperty(final Object key, final boolean isScope, final int programPoint) {
         final FindProperty find = findProperty(NO_SUCH_PROPERTY_NAME, true);
         final Object func = (find != null)? find.getObjectValue() : null;
 
@@ -2410,9 +2428,9 @@
         if (func instanceof ScriptFunction) {
             final ScriptFunction sfunc = (ScriptFunction)func;
             final Object self = isScope && sfunc.isStrict()? UNDEFINED : this;
-            ret = ScriptRuntime.apply(sfunc, self, name);
+            ret = ScriptRuntime.apply(sfunc, self, key);
         } else if (isScope) {
-            throw referenceError("not.defined", name);
+            throw referenceError("not.defined", key.toString());
         }
 
         if (isValid(programPoint)) {
@@ -2502,7 +2520,7 @@
             final Set<String> keys = new LinkedHashSet<>();
             final Set<String> nonEnumerable = new HashSet<>();
             for (ScriptObject self = object; self != null; self = self.getProto()) {
-                keys.addAll(Arrays.asList(self.getOwnKeys(false, nonEnumerable)));
+                keys.addAll(Arrays.asList(self.getOwnKeys(String.class, false, nonEnumerable)));
             }
             this.values = keys.toArray(new String[keys.size()]);
         }
@@ -2518,7 +2536,7 @@
             final ArrayList<Object> valueList = new ArrayList<>();
             final Set<String> nonEnumerable = new HashSet<>();
             for (ScriptObject self = object; self != null; self = self.getProto()) {
-                for (final String key : self.getOwnKeys(false, nonEnumerable)) {
+                for (final String key : self.getOwnKeys(String.class, false, nonEnumerable)) {
                     valueList.add(self.get(key));
                 }
             }
@@ -2532,7 +2550,7 @@
      * @param flags  Property flags.
      * @return Added property.
      */
-    private Property addSpillProperty(final String key, final int flags, final Object value, final boolean hasInitialValue) {
+    private Property addSpillProperty(final Object key, final int flags, final Object value, final boolean hasInitialValue) {
         final PropertyMap propertyMap = getMap();
         final int fieldSlot  = propertyMap.getFreeFieldSlot();
         final int propertyFlags = flags | (useDualFields() ? Property.DUAL_FIELDS : 0);
@@ -2726,7 +2744,7 @@
        }
     }
 
-    private int getInt(final int index, final String key, final int programPoint) {
+    private int getInt(final int index, final Object key, final int programPoint) {
         if (isValidArrayIndex(index)) {
             for (ScriptObject object = this; ; ) {
                 if (object.getMap().containsArrayKeys()) {
@@ -2770,7 +2788,7 @@
             return isValid(programPoint) ? array.getIntOptimistic(index, programPoint) : array.getInt(index);
         }
 
-        return getInt(index, JSType.toString(primitiveKey), programPoint);
+        return getInt(index, JSType.toPropertyKey(primitiveKey), programPoint);
     }
 
     @Override
@@ -2809,7 +2827,7 @@
         return getInt(index, JSType.toString(key), programPoint);
     }
 
-    private long getLong(final int index, final String key, final int programPoint) {
+    private long getLong(final int index, final Object key, final int programPoint) {
         if (isValidArrayIndex(index)) {
             for (ScriptObject object = this; ; ) {
                 if (object.getMap().containsArrayKeys()) {
@@ -2852,7 +2870,7 @@
             return isValid(programPoint) ? array.getLongOptimistic(index, programPoint) : array.getLong(index);
         }
 
-        return getLong(index, JSType.toString(primitiveKey), programPoint);
+        return getLong(index, JSType.toPropertyKey(primitiveKey), programPoint);
     }
 
     @Override
@@ -2891,7 +2909,7 @@
         return getLong(index, JSType.toString(key), programPoint);
     }
 
-    private double getDouble(final int index, final String key, final int programPoint) {
+    private double getDouble(final int index, final Object key, final int programPoint) {
         if (isValidArrayIndex(index)) {
             for (ScriptObject object = this; ; ) {
                 if (object.getMap().containsArrayKeys()) {
@@ -2934,7 +2952,7 @@
             return isValid(programPoint) ? array.getDoubleOptimistic(index, programPoint) : array.getDouble(index);
         }
 
-        return getDouble(index, JSType.toString(primitiveKey), programPoint);
+        return getDouble(index, JSType.toPropertyKey(primitiveKey), programPoint);
     }
 
     @Override
@@ -2973,7 +2991,7 @@
         return getDouble(index, JSType.toString(key), programPoint);
     }
 
-    private Object get(final int index, final String key) {
+    private Object get(final int index, final Object key) {
         if (isValidArrayIndex(index)) {
             for (ScriptObject object = this; ; ) {
                 if (object.getMap().containsArrayKeys()) {
@@ -3015,7 +3033,7 @@
             return array.getObject(index);
         }
 
-        return get(index, JSType.toString(primitiveKey));
+        return get(index, JSType.toPropertyKey(primitiveKey));
     }
 
     @Override
@@ -3161,7 +3179,7 @@
      * @param key           property key
      * @param value         property value
      */
-    public final void setObject(final FindProperty find, final int callSiteFlags, final String key, final Object value) {
+    public final void setObject(final FindProperty find, final int callSiteFlags, final Object key, final Object value) {
         FindProperty f = find;
 
         invalidateGlobalConstant(key);
@@ -3189,10 +3207,10 @@
         if (f != null) {
             if (!f.getProperty().isWritable()) {
                 if (isScopeFlag(callSiteFlags) && f.getProperty().isLexicalBinding()) {
-                    throw typeError("assign.constant", key); // Overwriting ES6 const should throw also in non-strict mode.
+                    throw typeError("assign.constant", key.toString()); // Overwriting ES6 const should throw also in non-strict mode.
                 }
                 if (isStrictFlag(callSiteFlags)) {
-                    throw typeError("property.not.writable", key, ScriptRuntime.safeToString(this));
+                    throw typeError("property.not.writable", key.toString(), ScriptRuntime.safeToString(this));
                 }
                 return;
             }
@@ -3201,7 +3219,7 @@
 
         } else if (!isExtensible()) {
             if (isStrictFlag(callSiteFlags)) {
-                throw typeError("object.non.extensible", key, ScriptRuntime.safeToString(this));
+                throw typeError("object.non.extensible", key.toString(), ScriptRuntime.safeToString(this));
             }
         } else {
             ScriptObject sobj = this;
@@ -3235,7 +3253,7 @@
             return;
         }
 
-        final String propName = JSType.toString(primitiveKey);
+        final Object propName = JSType.toPropertyKey(primitiveKey);
         setObject(findProperty(propName, true), callSiteFlags, propName, JSType.toObject(value));
     }
 
@@ -3255,7 +3273,7 @@
             return;
         }
 
-        final String propName = JSType.toString(primitiveKey);
+        final Object propName = JSType.toPropertyKey(primitiveKey);
         setObject(findProperty(propName, true), callSiteFlags, propName, JSType.toObject(value));
     }
 
@@ -3275,7 +3293,7 @@
             return;
         }
 
-        final String propName = JSType.toString(primitiveKey);
+        final Object propName = JSType.toPropertyKey(primitiveKey);
         setObject(findProperty(propName, true), callSiteFlags, propName, JSType.toObject(value));
     }
 
@@ -3295,7 +3313,7 @@
             return;
         }
 
-        final String propName = JSType.toString(primitiveKey);
+        final Object propName = JSType.toPropertyKey(primitiveKey);
         setObject(findProperty(propName, true), callSiteFlags, propName, value);
     }
 
@@ -3529,7 +3547,7 @@
     public boolean has(final Object key) {
         final Object primitiveKey = JSType.toPrimitive(key);
         final int    index        = getArrayIndex(primitiveKey);
-        return isValidArrayIndex(index) ? hasArrayProperty(index) : hasProperty(JSType.toString(primitiveKey), true);
+        return isValidArrayIndex(index) ? hasArrayProperty(index) : hasProperty(JSType.toPropertyKey(primitiveKey), true);
     }
 
     @Override
@@ -3567,7 +3585,7 @@
     public boolean hasOwnProperty(final Object key) {
         final Object primitiveKey = JSType.toPrimitive(key, String.class);
         final int    index        = getArrayIndex(primitiveKey);
-        return isValidArrayIndex(index) ? hasOwnArrayProperty(index) : hasProperty(JSType.toString(primitiveKey), false);
+        return isValidArrayIndex(index) ? hasOwnArrayProperty(index) : hasProperty(JSType.toPropertyKey(primitiveKey), false);
     }
 
     @Override
@@ -3657,7 +3675,7 @@
     }
 
     private boolean deleteObject(final Object key, final boolean strict) {
-        final String propName = JSType.toString(key);
+        final Object propName = JSType.toPropertyKey(key);
         final FindProperty find = findProperty(propName, false);
 
         if (find == null) {
@@ -3666,7 +3684,7 @@
 
         if (!find.getProperty().isConfigurable()) {
             if (strict) {
-                throw typeError("cant.delete.property", propName, ScriptRuntime.safeToString(this));
+                throw typeError("cant.delete.property", propName.toString(), ScriptRuntime.safeToString(this));
             }
             return false;
         }
@@ -3712,7 +3730,7 @@
      * @param setter setter function for the property
      * @return the newly created UserAccessorProperty
      */
-    protected final UserAccessorProperty newUserAccessors(final String key, final int propertyFlags, final ScriptFunction getter, final ScriptFunction setter) {
+    protected final UserAccessorProperty newUserAccessors(final Object key, final int propertyFlags, final ScriptFunction getter, final ScriptFunction setter) {
         final UserAccessorProperty uc = getMap().newUserAccessors(key, propertyFlags);
         //property.getSetter(Object.class, getMap());
         uc.setAccessors(this, getMap(), new UserAccessorProperty.Accessors(getter, setter));
--- a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/ScriptRuntime.java	Mon Nov 23 15:32:02 2015 +0100
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/ScriptRuntime.java	Thu Nov 26 01:06:51 2015 +0100
@@ -836,11 +836,11 @@
         } else if (yType == JSType.BOOLEAN) {
             // Can reverse order as y is primitive
             return equalBooleanToAny(y, x);
-        } else if (isNumberOrStringAndObject(xType, yType)) {
-            return equalNumberOrStringToObject(x, y);
-        } else if (isNumberOrStringAndObject(yType, xType)) {
+        } else if (isPrimitiveAndObject(xType, yType)) {
+            return equalWrappedPrimitiveToObject(x, y);
+        } else if (isPrimitiveAndObject(yType, xType)) {
             // Can reverse order as y is primitive
-            return equalNumberOrStringToObject(y, x);
+            return equalWrappedPrimitiveToObject(y, x);
         }
 
         return false;
@@ -854,8 +854,8 @@
         return xType == JSType.NUMBER && yType == JSType.STRING;
     }
 
-    private static boolean isNumberOrStringAndObject(final JSType xType, final JSType yType) {
-        return (xType == JSType.NUMBER || xType == JSType.STRING) && yType == JSType.OBJECT;
+    private static boolean isPrimitiveAndObject(final JSType xType, final JSType yType) {
+        return (xType == JSType.NUMBER || xType == JSType.STRING || xType == JSType.SYMBOL) && yType == JSType.OBJECT;
     }
 
     private static boolean equalNumberToString(final Object num, final Object str) {
@@ -869,7 +869,7 @@
         return equals(JSType.toNumber((Boolean)bool), any);
     }
 
-    private static boolean equalNumberOrStringToObject(final Object numOrStr, final Object any) {
+    private static boolean equalWrappedPrimitiveToObject(final Object numOrStr, final Object any) {
         return equals(numOrStr, JSType.toPrimitive(any));
     }
 
--- a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/SpillProperty.java	Mon Nov 23 15:32:02 2015 +0100
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/SpillProperty.java	Thu Nov 26 01:06:51 2015 +0100
@@ -158,7 +158,7 @@
      * @param flags  the property flags
      * @param slot   spill slot
      */
-    public SpillProperty(final String key, final int flags, final int slot) {
+    public SpillProperty(final Object key, final int flags, final int slot) {
         super(key, flags, slot, primitiveGetter(slot, flags), primitiveSetter(slot, flags), objectGetter(slot), objectSetter(slot));
     }
 
@@ -174,7 +174,7 @@
         setType(hasDualFields() ? initialType : Object.class);
     }
 
-    SpillProperty(final String key, final int flags, final int slot, final ScriptObject owner, final Object initialValue) {
+    SpillProperty(final Object key, final int flags, final int slot, final ScriptObject owner, final Object initialValue) {
         this(key, flags, slot);
         setInitialValue(owner, initialValue);
     }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/Symbol.java	Thu Nov 26 01:06:51 2015 +0100
@@ -0,0 +1,85 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.nashorn.internal.runtime;
+
+import java.io.Serializable;
+import jdk.nashorn.internal.objects.NativeSymbol;
+
+/**
+ * This class represents a unique, non-String Object property key as defined in ECMAScript 6.
+ */
+public final class Symbol implements Serializable {
+
+    private final String name;
+
+    private static final long serialVersionUID = -2988436597549486913L;
+
+    /**
+     * Symbol constructor
+     * @param name symbol name
+     */
+    public Symbol(final String name) {
+        this.name = name;
+    }
+
+    @Override
+    public String toString() {
+        return "Symbol(" + name + ")";
+    }
+
+    /**
+     * Return the symbol's name
+     * @return the name
+     */
+    public final String getName() {
+        return name;
+    }
+
+    private Object writeReplace() {
+        // If this symbol is a globally registered one, replace it with a
+        // GlobalSymbol in serialized stream.
+        return NativeSymbol.keyFor(null, this) == name ? new GlobalSymbol(name) : this;
+    }
+
+    /**
+     * Represents a globally registered (with NativeSymbol._for) symbol in the
+     * serialized stream. Upon deserialization, it resolves to the globally
+     * registered symbol.
+     */
+    private static class GlobalSymbol implements Serializable {
+        private static final long serialVersionUID = 1L;
+
+        private final String name;
+
+        GlobalSymbol(final String name) {
+            this.name = name;
+        }
+
+        private Object readResolve() {
+            return NativeSymbol._for(null, name);
+        }
+    }
+}
--- a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/UserAccessorProperty.java	Mon Nov 23 15:32:02 2015 +0100
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/UserAccessorProperty.java	Thu Nov 26 01:06:51 2015 +0100
@@ -120,7 +120,7 @@
      * @param flags property flags
      * @param slot  spill slot
      */
-    UserAccessorProperty(final String key, final int flags, final int slot) {
+    UserAccessorProperty(final Object key, final int flags, final int slot) {
         super(key, flags, slot);
     }
 
@@ -226,7 +226,7 @@
     @Override
     public void setValue(final ScriptObject self, final ScriptObject owner, final Object value, final boolean strict) {
         try {
-            invokeObjectSetter(getAccessors((owner != null) ? owner : self), getObjectSetterInvoker(), strict ? getKey() : null, self, value);
+            invokeObjectSetter(getAccessors((owner != null) ? owner : self), getObjectSetterInvoker(), strict ? getKey().toString() : null, self, value);
         } catch (final Error | RuntimeException t) {
             throw t;
         } catch (final Throwable t) {
--- a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/WithObject.java	Mon Nov 23 15:32:02 2015 +0100
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/WithObject.java	Thu Nov 26 01:06:51 2015 +0100
@@ -198,7 +198,7 @@
      * @return FindPropertyData or null if not found.
      */
     @Override
-    protected FindProperty findProperty(final String key, final boolean deep, final ScriptObject start) {
+    protected FindProperty findProperty(final Object key, final boolean deep, final ScriptObject start) {
         // We call findProperty on 'expression' with 'expression' itself as start parameter.
         // This way in ScriptObject.setObject we can tell the property is from a 'with' expression
         // (as opposed from another non-scope object in the proto chain such as Object.prototype).
@@ -210,18 +210,18 @@
     }
 
     @Override
-    protected Object invokeNoSuchProperty(final String name, final boolean isScope, final int programPoint) {
+    protected Object invokeNoSuchProperty(final Object key, final boolean isScope, final int programPoint) {
         final FindProperty find = expression.findProperty(NO_SUCH_PROPERTY_NAME, true);
         if (find != null) {
             final Object func = find.getObjectValue();
             if (func instanceof ScriptFunction) {
                 final ScriptFunction sfunc = (ScriptFunction)func;
                 final Object self = isScope && sfunc.isStrict()? UNDEFINED : expression;
-                return ScriptRuntime.apply(sfunc, self, name);
+                return ScriptRuntime.apply(sfunc, self, key);
             }
         }
 
-        return getProto().invokeNoSuchProperty(name, isScope, programPoint);
+        return getProto().invokeNoSuchProperty(key, isScope, programPoint);
     }
 
     @Override
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/doubleconv/Bignum.java	Thu Nov 26 01:06:51 2015 +0100
@@ -0,0 +1,842 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  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.
+ */
+
+// This file is available under and governed by the GNU General Public
+// License version 2 only, as published by the Free Software Foundation.
+// However, the following notice accompanied the original version of this
+// file:
+//
+// Copyright 2010 the V8 project authors. 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 Google Inc. 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.
+
+package jdk.nashorn.internal.runtime.doubleconv;
+
+import java.util.Arrays;
+
+class Bignum {
+
+    // 3584 = 128 * 28. We can represent 2^3584 > 10^1000 accurately.
+    // This bignum can encode much bigger numbers, since it contains an
+    // exponent.
+    static final int kMaxSignificantBits = 3584;
+
+    static final int kChunkSize = 32;       // size of int
+    static final int kDoubleChunkSize = 64; // size of long
+    // With bigit size of 28 we loose some bits, but a double still fits easily
+    // into two ints, and more importantly we can use the Comba multiplication.
+    static final int kBigitSize = 28;
+    static final int kBigitMask = (1 << kBigitSize) - 1;
+    // Every instance allocates kbigitLength ints on the stack. Bignums cannot
+    // grow. There are no checks if the stack-allocated space is sufficient.
+    static final int kBigitCapacity = kMaxSignificantBits / kBigitSize;
+
+    private int[] bigits_ = new int[kBigitCapacity];
+    // A vector backed by bigits_buffer_. This way accesses to the array are
+    // checked for out-of-bounds errors.
+    // Vector<int> bigits_;
+    private int used_digits_;
+    // The Bignum's value equals value(bigits_) * 2^(exponent_ * kBigitSize).
+    private int exponent_;
+
+    Bignum() {}
+
+    void times10() { multiplyByUInt32(10); }
+
+    static boolean equal(final Bignum a, final Bignum b) {
+        return compare(a, b) == 0;
+    }
+    static boolean lessEqual(final Bignum a, final Bignum b) {
+        return compare(a, b) <= 0;
+    }
+    static boolean less(final Bignum a, final Bignum b) {
+        return compare(a, b) < 0;
+    }
+
+    // Returns a + b == c
+    static boolean plusEqual(final Bignum a, final Bignum b, final Bignum c) {
+        return plusCompare(a, b, c) == 0;
+    }
+    // Returns a + b <= c
+    static boolean plusLessEqual(final Bignum a, final Bignum b, final Bignum c) {
+        return plusCompare(a, b, c) <= 0;
+    }
+    // Returns a + b < c
+    static boolean plusLess(final Bignum a, final Bignum b, final Bignum c) {
+        return plusCompare(a, b, c) < 0;
+    }
+
+    private void ensureCapacity(final int size) {
+        if (size > kBigitCapacity) {
+            throw new RuntimeException();
+        }
+    }
+
+    // BigitLength includes the "hidden" digits encoded in the exponent.
+    int bigitLength() { return used_digits_ + exponent_; }
+
+    // Guaranteed to lie in one Bigit.
+    void assignUInt16(final char value) {
+        assert (kBigitSize >= 16);
+        zero();
+        if (value == 0) return;
+
+        ensureCapacity(1);
+        bigits_[0] = value;
+        used_digits_ = 1;
+    }
+
+
+    void assignUInt64(long value) {
+        final  int kUInt64Size = 64;
+
+        zero();
+        if (value == 0) return;
+
+        final int needed_bigits = kUInt64Size / kBigitSize + 1;
+        ensureCapacity(needed_bigits);
+        for (int i = 0; i < needed_bigits; ++i) {
+            bigits_[i] = (int) (value & kBigitMask);
+            value = value >>> kBigitSize;
+        }
+        used_digits_ = needed_bigits;
+        clamp();
+    }
+
+
+    void assignBignum(final Bignum other) {
+        exponent_ = other.exponent_;
+        for (int i = 0; i < other.used_digits_; ++i) {
+            bigits_[i] = other.bigits_[i];
+        }
+        // Clear the excess digits (if there were any).
+        for (int i = other.used_digits_; i < used_digits_; ++i) {
+            bigits_[i] = 0;
+        }
+        used_digits_ = other.used_digits_;
+    }
+
+
+    static long readUInt64(final String str,
+                           final int from,
+                           final int digits_to_read) {
+        long result = 0;
+        for (int i = from; i < from + digits_to_read; ++i) {
+            final int digit = str.charAt(i) - '0';
+            assert (0 <= digit && digit <= 9);
+            result = result * 10 + digit;
+        }
+        return result;
+    }
+
+
+    void assignDecimalString(final String str) {
+        // 2^64 = 18446744073709551616 > 10^19
+        final int kMaxUint64DecimalDigits = 19;
+        zero();
+        int length = str.length();
+        int pos = 0;
+        // Let's just say that each digit needs 4 bits.
+        while (length >= kMaxUint64DecimalDigits) {
+            final long digits = readUInt64(str, pos, kMaxUint64DecimalDigits);
+            pos += kMaxUint64DecimalDigits;
+            length -= kMaxUint64DecimalDigits;
+            multiplyByPowerOfTen(kMaxUint64DecimalDigits);
+            addUInt64(digits);
+        }
+        final long digits = readUInt64(str, pos, length);
+        multiplyByPowerOfTen(length);
+        addUInt64(digits);
+        clamp();
+    }
+
+
+    static int hexCharValue(final char c) {
+        if ('0' <= c && c <= '9') return c - '0';
+        if ('a' <= c && c <= 'f') return 10 + c - 'a';
+        assert ('A' <= c && c <= 'F');
+        return 10 + c - 'A';
+    }
+
+
+    void assignHexString(final String str) {
+        zero();
+        final int length = str.length();
+
+        final int needed_bigits = length * 4 / kBigitSize + 1;
+        ensureCapacity(needed_bigits);
+        int string_index = length - 1;
+        for (int i = 0; i < needed_bigits - 1; ++i) {
+            // These bigits are guaranteed to be "full".
+            int current_bigit = 0;
+            for (int j = 0; j < kBigitSize / 4; j++) {
+                current_bigit += hexCharValue(str.charAt(string_index--)) << (j * 4);
+            }
+            bigits_[i] = current_bigit;
+        }
+        used_digits_ = needed_bigits - 1;
+
+        int most_significant_bigit = 0;  // Could be = 0;
+        for (int j = 0; j <= string_index; ++j) {
+            most_significant_bigit <<= 4;
+            most_significant_bigit += hexCharValue(str.charAt(j));
+        }
+        if (most_significant_bigit != 0) {
+            bigits_[used_digits_] = most_significant_bigit;
+            used_digits_++;
+        }
+        clamp();
+    }
+
+
+    void addUInt64(final long operand) {
+        if (operand == 0) return;
+        final Bignum other = new Bignum();
+        other.assignUInt64(operand);
+        addBignum(other);
+    }
+
+
+    void addBignum(final Bignum other) {
+        assert (isClamped());
+        assert (other.isClamped());
+
+        // If this has a greater exponent than other append zero-bigits to this.
+        // After this call exponent_ <= other.exponent_.
+        align(other);
+
+        // There are two possibilities:
+        //   aaaaaaaaaaa 0000  (where the 0s represent a's exponent)
+        //     bbbbb 00000000
+        //   ----------------
+        //   ccccccccccc 0000
+        // or
+        //    aaaaaaaaaa 0000
+        //  bbbbbbbbb 0000000
+        //  -----------------
+        //  cccccccccccc 0000
+        // In both cases we might need a carry bigit.
+
+        ensureCapacity(1 + Math.max(bigitLength(), other.bigitLength()) - exponent_);
+        int carry = 0;
+        int bigit_pos = other.exponent_ - exponent_;
+        assert (bigit_pos >= 0);
+        for (int i = 0; i < other.used_digits_; ++i) {
+            final int sum = bigits_[bigit_pos] + other.bigits_[i] + carry;
+            bigits_[bigit_pos] = sum & kBigitMask;
+            carry = sum >>> kBigitSize;
+            bigit_pos++;
+        }
+
+        while (carry != 0) {
+            final int sum = bigits_[bigit_pos] + carry;
+            bigits_[bigit_pos] = sum & kBigitMask;
+            carry = sum >>> kBigitSize;
+            bigit_pos++;
+        }
+        used_digits_ = Math.max(bigit_pos, used_digits_);
+        assert (isClamped());
+    }
+
+
+    void subtractBignum(final Bignum other) {
+        assert (isClamped());
+        assert (other.isClamped());
+        // We require this to be bigger than other.
+        assert (lessEqual(other, this));
+
+        align(other);
+
+        final int offset = other.exponent_ - exponent_;
+        int borrow = 0;
+        int i;
+        for (i = 0; i < other.used_digits_; ++i) {
+            assert ((borrow == 0) || (borrow == 1));
+            final int difference = bigits_[i + offset] - other.bigits_[i] - borrow;
+            bigits_[i + offset] = difference & kBigitMask;
+            borrow = difference >>> (kChunkSize - 1);
+        }
+        while (borrow != 0) {
+            final int difference = bigits_[i + offset] - borrow;
+            bigits_[i + offset] = difference & kBigitMask;
+            borrow = difference >>> (kChunkSize - 1);
+            ++i;
+        }
+        clamp();
+    }
+
+
+    void shiftLeft(final int shift_amount) {
+        if (used_digits_ == 0) return;
+        exponent_ += shift_amount / kBigitSize;
+        final int local_shift = shift_amount % kBigitSize;
+        ensureCapacity(used_digits_ + 1);
+        bigitsShiftLeft(local_shift);
+    }
+
+
+    void multiplyByUInt32(final int factor) {
+        if (factor == 1) return;
+        if (factor == 0) {
+            zero();
+            return;
+        }
+        if (used_digits_ == 0) return;
+
+        // The product of a bigit with the factor is of size kBigitSize + 32.
+        // Assert that this number + 1 (for the carry) fits into double int.
+        assert (kDoubleChunkSize >= kBigitSize + 32 + 1);
+        long carry = 0;
+        for (int i = 0; i < used_digits_; ++i) {
+            final long product = (factor & 0xFFFFFFFFL) * bigits_[i] + carry;
+            bigits_[i] = (int) (product & kBigitMask);
+            carry = product >>> kBigitSize;
+        }
+        while (carry != 0) {
+            ensureCapacity(used_digits_ + 1);
+            bigits_[used_digits_] = (int) (carry & kBigitMask);
+            used_digits_++;
+            carry >>>= kBigitSize;
+        }
+    }
+
+
+    void multiplyByUInt64(final long factor) {
+        if (factor == 1) return;
+        if (factor == 0) {
+            zero();
+            return;
+        }
+        assert (kBigitSize < 32);
+        long carry = 0;
+        final long low = factor & 0xFFFFFFFFL;
+        final long high = factor >>> 32;
+        for (int i = 0; i < used_digits_; ++i) {
+            final long product_low = low * bigits_[i];
+            final long product_high = high * bigits_[i];
+            final long tmp = (carry & kBigitMask) + product_low;
+            bigits_[i] = (int) (tmp & kBigitMask);
+            carry = (carry >>> kBigitSize) + (tmp >>> kBigitSize) +
+                    (product_high << (32 - kBigitSize));
+        }
+        while (carry != 0) {
+            ensureCapacity(used_digits_ + 1);
+            bigits_[used_digits_] = (int) (carry & kBigitMask);
+            used_digits_++;
+            carry >>>= kBigitSize;
+        }
+    }
+
+
+    void multiplyByPowerOfTen(final int exponent) {
+        final long kFive27 = 0x6765c793fa10079dL;
+        final int kFive1 = 5;
+        final int kFive2 = kFive1 * 5;
+        final int kFive3 = kFive2 * 5;
+        final int kFive4 = kFive3 * 5;
+        final int kFive5 = kFive4 * 5;
+        final int kFive6 = kFive5 * 5;
+        final int kFive7 = kFive6 * 5;
+        final int kFive8 = kFive7 * 5;
+        final int kFive9 = kFive8 * 5;
+        final int kFive10 = kFive9 * 5;
+        final int kFive11 = kFive10 * 5;
+        final int kFive12 = kFive11 * 5;
+        final int kFive13 = kFive12 * 5;
+        final int kFive1_to_12[] =
+                { kFive1, kFive2, kFive3, kFive4, kFive5, kFive6,
+                        kFive7, kFive8, kFive9, kFive10, kFive11, kFive12 };
+
+        assert (exponent >= 0);
+        if (exponent == 0) return;
+        if (used_digits_ == 0) return;
+
+        // We shift by exponent at the end just before returning.
+        int remaining_exponent = exponent;
+        while (remaining_exponent >= 27) {
+            multiplyByUInt64(kFive27);
+            remaining_exponent -= 27;
+        }
+        while (remaining_exponent >= 13) {
+            multiplyByUInt32(kFive13);
+            remaining_exponent -= 13;
+        }
+        if (remaining_exponent > 0) {
+            multiplyByUInt32(kFive1_to_12[remaining_exponent - 1]);
+        }
+        shiftLeft(exponent);
+    }
+
+
+    void square() {
+        assert (isClamped());
+        final int product_length = 2 * used_digits_;
+        ensureCapacity(product_length);
+
+        // Comba multiplication: compute each column separately.
+        // Example: r = a2a1a0 * b2b1b0.
+        //    r =  1    * a0b0 +
+        //        10    * (a1b0 + a0b1) +
+        //        100   * (a2b0 + a1b1 + a0b2) +
+        //        1000  * (a2b1 + a1b2) +
+        //        10000 * a2b2
+        //
+        // In the worst case we have to accumulate nb-digits products of digit*digit.
+        //
+        // Assert that the additional number of bits in a DoubleChunk are enough to
+        // sum up used_digits of Bigit*Bigit.
+        if ((1L << (2 * (kChunkSize - kBigitSize))) <= used_digits_) {
+            throw new RuntimeException("unimplemented");
+        }
+        long accumulator = 0;
+        // First shift the digits so we don't overwrite them.
+        final int copy_offset = used_digits_;
+        for (int i = 0; i < used_digits_; ++i) {
+            bigits_[copy_offset + i] = bigits_[i];
+        }
+        // We have two loops to avoid some 'if's in the loop.
+        for (int i = 0; i < used_digits_; ++i) {
+            // Process temporary digit i with power i.
+            // The sum of the two indices must be equal to i.
+            int bigit_index1 = i;
+            int bigit_index2 = 0;
+            // Sum all of the sub-products.
+            while (bigit_index1 >= 0) {
+                final int int1 = bigits_[copy_offset + bigit_index1];
+                final int int2 = bigits_[copy_offset + bigit_index2];
+                accumulator += ((long) int1) * int2;
+                bigit_index1--;
+                bigit_index2++;
+            }
+            bigits_[i] = (int) (accumulator & kBigitMask);
+            accumulator >>>= kBigitSize;
+        }
+        for (int i = used_digits_; i < product_length; ++i) {
+            int bigit_index1 = used_digits_ - 1;
+            int bigit_index2 = i - bigit_index1;
+            // Invariant: sum of both indices is again equal to i.
+            // Inner loop runs 0 times on last iteration, emptying accumulator.
+            while (bigit_index2 < used_digits_) {
+                final int int1 = bigits_[copy_offset + bigit_index1];
+                final int int2 = bigits_[copy_offset + bigit_index2];
+                accumulator += ((long) int1) * int2;
+                bigit_index1--;
+                bigit_index2++;
+            }
+            // The overwritten bigits_[i] will never be read in further loop iterations,
+            // because bigit_index1 and bigit_index2 are always greater
+            // than i - used_digits_.
+            bigits_[i] = (int) (accumulator & kBigitMask);
+            accumulator >>>= kBigitSize;
+        }
+        // Since the result was guaranteed to lie inside the number the
+        // accumulator must be 0 now.
+        assert (accumulator == 0);
+
+        // Don't forget to update the used_digits and the exponent.
+        used_digits_ = product_length;
+        exponent_ *= 2;
+        clamp();
+    }
+
+
+    void assignPowerUInt16(int base, final int power_exponent) {
+        assert (base != 0);
+        assert (power_exponent >= 0);
+        if (power_exponent == 0) {
+            assignUInt16((char) 1);
+            return;
+        }
+        zero();
+        int shifts = 0;
+        // We expect base to be in range 2-32, and most often to be 10.
+        // It does not make much sense to implement different algorithms for counting
+        // the bits.
+        while ((base & 1) == 0) {
+            base >>>= 1;
+            shifts++;
+        }
+        int bit_size = 0;
+        int tmp_base = base;
+        while (tmp_base != 0) {
+            tmp_base >>>= 1;
+            bit_size++;
+        }
+        final int final_size = bit_size * power_exponent;
+        // 1 extra bigit for the shifting, and one for rounded final_size.
+        ensureCapacity(final_size / kBigitSize + 2);
+
+        // Left to Right exponentiation.
+        int mask = 1;
+        while (power_exponent >= mask) mask <<= 1;
+
+        // The mask is now pointing to the bit above the most significant 1-bit of
+        // power_exponent.
+        // Get rid of first 1-bit;
+        mask >>>= 2;
+        long this_value = base;
+
+        boolean delayed_multipliciation = false;
+        final long max_32bits = 0xFFFFFFFFL;
+        while (mask != 0 && this_value <= max_32bits) {
+            this_value = this_value * this_value;
+            // Verify that there is enough space in this_value to perform the
+            // multiplication.  The first bit_size bits must be 0.
+            if ((power_exponent & mask) != 0) {
+                final long base_bits_mask =
+                        ~((1L << (64 - bit_size)) - 1);
+                final boolean high_bits_zero = (this_value & base_bits_mask) == 0;
+                if (high_bits_zero) {
+                    this_value *= base;
+                } else {
+                    delayed_multipliciation = true;
+                }
+            }
+            mask >>>= 1;
+        }
+        assignUInt64(this_value);
+        if (delayed_multipliciation) {
+            multiplyByUInt32(base);
+        }
+
+        // Now do the same thing as a bignum.
+        while (mask != 0) {
+            square();
+            if ((power_exponent & mask) != 0) {
+                multiplyByUInt32(base);
+            }
+            mask >>>= 1;
+        }
+
+        // And finally add the saved shifts.
+        shiftLeft(shifts * power_exponent);
+    }
+
+
+    // Precondition: this/other < 16bit.
+    char divideModuloIntBignum(final Bignum other) {
+        assert (isClamped());
+        assert (other.isClamped());
+        assert (other.used_digits_ > 0);
+
+        // Easy case: if we have less digits than the divisor than the result is 0.
+        // Note: this handles the case where this == 0, too.
+        if (bigitLength() < other.bigitLength()) {
+            return 0;
+        }
+
+        align(other);
+
+        char result = 0;
+
+        // Start by removing multiples of 'other' until both numbers have the same
+        // number of digits.
+        while (bigitLength() > other.bigitLength()) {
+            // This naive approach is extremely inefficient if `this` divided by other
+            // is big. This function is implemented for doubleToString where
+            // the result should be small (less than 10).
+            assert (other.bigits_[other.used_digits_ - 1] >= ((1 << kBigitSize) / 16));
+            assert (bigits_[used_digits_ - 1] < 0x10000);
+            // Remove the multiples of the first digit.
+            // Example this = 23 and other equals 9. -> Remove 2 multiples.
+            result += (bigits_[used_digits_ - 1]);
+            subtractTimes(other, bigits_[used_digits_ - 1]);
+        }
+
+        assert (bigitLength() == other.bigitLength());
+
+        // Both bignums are at the same length now.
+        // Since other has more than 0 digits we know that the access to
+        // bigits_[used_digits_ - 1] is safe.
+        final int this_bigit = bigits_[used_digits_ - 1];
+        final int other_bigit = other.bigits_[other.used_digits_ - 1];
+
+        if (other.used_digits_ == 1) {
+            // Shortcut for easy (and common) case.
+            final int quotient = Integer.divideUnsigned(this_bigit, other_bigit);
+            bigits_[used_digits_ - 1] = this_bigit - other_bigit * quotient;
+            assert (Integer.compareUnsigned(quotient, 0x10000) < 0);
+            result += quotient;
+            clamp();
+            return result;
+        }
+
+        final int division_estimate = Integer.divideUnsigned(this_bigit, (other_bigit + 1));
+        assert (Integer.compareUnsigned(division_estimate, 0x10000) < 0);
+        result += division_estimate;
+        subtractTimes(other, division_estimate);
+
+        if (other_bigit * (division_estimate + 1) > this_bigit) {
+            // No need to even try to subtract. Even if other's remaining digits were 0
+            // another subtraction would be too much.
+            return result;
+        }
+
+        while (lessEqual(other, this)) {
+            subtractBignum(other);
+            result++;
+        }
+        return result;
+    }
+
+
+    static int sizeInHexChars(int number) {
+        assert (number > 0);
+        int result = 0;
+        while (number != 0) {
+            number >>>= 4;
+            result++;
+        }
+        return result;
+    }
+
+
+    static char hexCharOfValue(final int value) {
+        assert (0 <= value && value <= 16);
+        if (value < 10) return (char) (value + '0');
+        return (char) (value - 10 + 'A');
+    }
+
+
+    String toHexString() {
+        assert (isClamped());
+        // Each bigit must be printable as separate hex-character.
+        assert (kBigitSize % 4 == 0);
+        final int kHexCharsPerBigit = kBigitSize / 4;
+
+        if (used_digits_ == 0) {
+            return "0";
+        }
+
+        final int needed_chars = (bigitLength() - 1) * kHexCharsPerBigit +
+                sizeInHexChars(bigits_[used_digits_ - 1]);
+        final StringBuilder buffer = new StringBuilder(needed_chars);
+        buffer.setLength(needed_chars);
+
+        int string_index = needed_chars - 1;
+        for (int i = 0; i < exponent_; ++i) {
+            for (int j = 0; j < kHexCharsPerBigit; ++j) {
+                buffer.setCharAt(string_index--, '0');
+            }
+        }
+        for (int i = 0; i < used_digits_ - 1; ++i) {
+            int current_bigit = bigits_[i];
+            for (int j = 0; j < kHexCharsPerBigit; ++j) {
+                buffer.setCharAt(string_index--, hexCharOfValue(current_bigit & 0xF));
+                current_bigit >>>= 4;
+            }
+        }
+        // And finally the last bigit.
+        int most_significant_bigit = bigits_[used_digits_ - 1];
+        while (most_significant_bigit != 0) {
+            buffer.setCharAt(string_index--, hexCharOfValue(most_significant_bigit & 0xF));
+            most_significant_bigit >>>= 4;
+        }
+        return buffer.toString();
+    }
+
+
+    int bigitAt(final int index) {
+        if (index >= bigitLength()) return 0;
+        if (index < exponent_) return 0;
+        return bigits_[index - exponent_];
+    }
+
+
+    static int compare(final Bignum a, final Bignum b) {
+        assert (a.isClamped());
+        assert (b.isClamped());
+        final int bigit_length_a = a.bigitLength();
+        final int bigit_length_b = b.bigitLength();
+        if (bigit_length_a < bigit_length_b) return -1;
+        if (bigit_length_a > bigit_length_b) return +1;
+        for (int i = bigit_length_a - 1; i >= Math.min(a.exponent_, b.exponent_); --i) {
+            final int bigit_a = a.bigitAt(i);
+            final int bigit_b = b.bigitAt(i);
+            if (bigit_a < bigit_b) return -1;
+            if (bigit_a > bigit_b) return +1;
+            // Otherwise they are equal up to this digit. Try the next digit.
+        }
+        return 0;
+    }
+
+
+    static int plusCompare(final Bignum a, final Bignum b, final Bignum c) {
+        assert (a.isClamped());
+        assert (b.isClamped());
+        assert (c.isClamped());
+        if (a.bigitLength() < b.bigitLength()) {
+            return plusCompare(b, a, c);
+        }
+        if (a.bigitLength() + 1 < c.bigitLength()) return -1;
+        if (a.bigitLength() > c.bigitLength()) return +1;
+        // The exponent encodes 0-bigits. So if there are more 0-digits in 'a' than
+        // 'b' has digits, then the bigit-length of 'a'+'b' must be equal to the one
+        // of 'a'.
+        if (a.exponent_ >= b.bigitLength() && a.bigitLength() < c.bigitLength()) {
+            return -1;
+        }
+
+        int borrow = 0;
+        // Starting at min_exponent all digits are == 0. So no need to compare them.
+        final int min_exponent = Math.min(Math.min(a.exponent_, b.exponent_), c.exponent_);
+        for (int i = c.bigitLength() - 1; i >= min_exponent; --i) {
+            final int int_a = a.bigitAt(i);
+            final int int_b = b.bigitAt(i);
+            final int int_c = c.bigitAt(i);
+            final int sum = int_a + int_b;
+            if (sum > int_c + borrow) {
+                return +1;
+            } else {
+                borrow = int_c + borrow - sum;
+                if (borrow > 1) return -1;
+                borrow <<= kBigitSize;
+            }
+        }
+        if (borrow == 0) return 0;
+        return -1;
+    }
+
+
+    void clamp() {
+        while (used_digits_ > 0 && bigits_[used_digits_ - 1] == 0) {
+            used_digits_--;
+        }
+        if (used_digits_ == 0) {
+            // Zero.
+            exponent_ = 0;
+        }
+    }
+
+
+    boolean isClamped() {
+        return used_digits_ == 0 || bigits_[used_digits_ - 1] != 0;
+    }
+
+
+    void zero() {
+        for (int i = 0; i < used_digits_; ++i) {
+            bigits_[i] = 0;
+        }
+        used_digits_ = 0;
+        exponent_ = 0;
+    }
+
+
+    void align(final Bignum other) {
+        if (exponent_ > other.exponent_) {
+            // If "X" represents a "hidden" digit (by the exponent) then we are in the
+            // following case (a == this, b == other):
+            // a:  aaaaaaXXXX   or a:   aaaaaXXX
+            // b:     bbbbbbX      b: bbbbbbbbXX
+            // We replace some of the hidden digits (X) of a with 0 digits.
+            // a:  aaaaaa000X   or a:   aaaaa0XX
+            final int zero_digits = exponent_ - other.exponent_;
+            ensureCapacity(used_digits_ + zero_digits);
+            for (int i = used_digits_ - 1; i >= 0; --i) {
+                bigits_[i + zero_digits] = bigits_[i];
+            }
+            for (int i = 0; i < zero_digits; ++i) {
+                bigits_[i] = 0;
+            }
+            used_digits_ += zero_digits;
+            exponent_ -= zero_digits;
+            assert (used_digits_ >= 0);
+            assert (exponent_ >= 0);
+        }
+    }
+
+
+    void bigitsShiftLeft(final int shift_amount) {
+        assert (shift_amount < kBigitSize);
+        assert (shift_amount >= 0);
+        int carry = 0;
+        for (int i = 0; i < used_digits_; ++i) {
+            final int new_carry = bigits_[i] >>> (kBigitSize - shift_amount);
+            bigits_[i] = ((bigits_[i] << shift_amount) + carry) & kBigitMask;
+            carry = new_carry;
+        }
+        if (carry != 0) {
+            bigits_[used_digits_] = carry;
+            used_digits_++;
+        }
+    }
+
+
+    void subtractTimes(final Bignum other, final int factor) {
+        assert (exponent_ <= other.exponent_);
+        if (factor < 3) {
+            for (int i = 0; i < factor; ++i) {
+                subtractBignum(other);
+            }
+            return;
+        }
+        int borrow = 0;
+        final int exponent_diff = other.exponent_ - exponent_;
+        for (int i = 0; i < other.used_digits_; ++i) {
+            final long product = ((long) factor) * other.bigits_[i];
+            final long remove = borrow + product;
+            final int difference = bigits_[i + exponent_diff] - (int) (remove & kBigitMask);
+            bigits_[i + exponent_diff] = difference & kBigitMask;
+            borrow = (int) ((difference >>> (kChunkSize - 1)) +
+                    (remove >>> kBigitSize));
+        }
+        for (int i = other.used_digits_ + exponent_diff; i < used_digits_; ++i) {
+            if (borrow == 0) return;
+            final int difference = bigits_[i] - borrow;
+            bigits_[i] = difference & kBigitMask;
+            borrow = difference >>> (kChunkSize - 1);
+        }
+        clamp();
+    }
+
+    @Override
+    public String toString() {
+        return "Bignum" + Arrays.toString(bigits_);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/doubleconv/BignumDtoa.java	Thu Nov 26 01:06:51 2015 +0100
@@ -0,0 +1,647 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  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.
+ */
+
+// This file is available under and governed by the GNU General Public
+// License version 2 only, as published by the Free Software Foundation.
+// However, the following notice accompanied the original version of this
+// file:
+//
+// Copyright 2010 the V8 project authors. 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 Google Inc. 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.
+
+package jdk.nashorn.internal.runtime.doubleconv;
+
+// Dtoa implementation based on our own Bignum implementation, supporting
+// all conversion modes but slightly slower than the specialized implementations.
+class BignumDtoa {
+
+    private static int normalizedExponent(long significand, int exponent) {
+        assert (significand != 0);
+        while ((significand & IeeeDouble.kHiddenBit) == 0) {
+            significand = significand << 1;
+            exponent = exponent - 1;
+        }
+        return exponent;
+    }
+
+    // Converts the given double 'v' to ascii.
+    // The result should be interpreted as buffer * 10^(point-length).
+    // The buffer will be null-terminated.
+    //
+    // The input v must be > 0 and different from NaN, and Infinity.
+    //
+    // The output depends on the given mode:
+    //  - SHORTEST: produce the least amount of digits for which the internal
+    //   identity requirement is still satisfied. If the digits are printed
+    //   (together with the correct exponent) then reading this number will give
+    //   'v' again. The buffer will choose the representation that is closest to
+    //   'v'. If there are two at the same distance, than the number is round up.
+    //   In this mode the 'requested_digits' parameter is ignored.
+    //  - FIXED: produces digits necessary to print a given number with
+    //   'requested_digits' digits after the decimal point. The produced digits
+    //   might be too short in which case the caller has to fill the gaps with '0's.
+    //   Example: toFixed(0.001, 5) is allowed to return buffer="1", point=-2.
+    //   Halfway cases are rounded up. The call toFixed(0.15, 2) thus returns
+    //     buffer="2", point=0.
+    //   Note: the length of the returned buffer has no meaning wrt the significance
+    //   of its digits. That is, just because it contains '0's does not mean that
+    //   any other digit would not satisfy the internal identity requirement.
+    //  - PRECISION: produces 'requested_digits' where the first digit is not '0'.
+    //   Even though the length of produced digits usually equals
+    //   'requested_digits', the function is allowed to return fewer digits, in
+    //   which case the caller has to fill the missing digits with '0's.
+    //   Halfway cases are again rounded up.
+    // 'BignumDtoa' expects the given buffer to be big enough to hold all digits
+    // and a terminating null-character.
+    static void bignumDtoa(final double v, final DtoaMode mode, final int requested_digits,
+                    final DtoaBuffer buffer) {
+        assert (v > 0);
+        assert (!IeeeDouble.isSpecial(IeeeDouble.doubleToLong(v)));
+        final long significand;
+        final int exponent;
+        final boolean lower_boundary_is_closer;
+
+        final long l = IeeeDouble.doubleToLong(v);
+        significand = IeeeDouble.significand(l);
+        exponent = IeeeDouble.exponent(l);
+        lower_boundary_is_closer = IeeeDouble.lowerBoundaryIsCloser(l);
+
+        final boolean need_boundary_deltas = mode == DtoaMode.SHORTEST;
+
+        final boolean is_even = (significand & 1) == 0;
+        assert (significand != 0);
+        final int normalizedExponent = normalizedExponent(significand, exponent);
+        // estimated_power might be too low by 1.
+        final int estimated_power = estimatePower(normalizedExponent);
+
+        // Shortcut for Fixed.
+        // The requested digits correspond to the digits after the point. If the
+        // number is much too small, then there is no need in trying to get any
+        // digits.
+        if (mode == DtoaMode.FIXED && -estimated_power - 1 > requested_digits) {
+            buffer.reset();
+            // Set decimal-point to -requested_digits. This is what Gay does.
+            // Note that it should not have any effect anyways since the string is
+            // empty.
+            buffer.decimalPoint = -requested_digits;
+            return;
+        }
+
+        final Bignum numerator = new Bignum();
+        final Bignum denominator = new Bignum();
+        final Bignum delta_minus = new Bignum();
+        final Bignum delta_plus = new Bignum();
+        // Make sure the bignum can grow large enough. The smallest double equals
+        // 4e-324. In this case the denominator needs fewer than 324*4 binary digits.
+        // The maximum double is 1.7976931348623157e308 which needs fewer than
+        // 308*4 binary digits.
+        assert (Bignum.kMaxSignificantBits >= 324*4);
+        initialScaledStartValues(significand, exponent, lower_boundary_is_closer,
+                estimated_power, need_boundary_deltas,
+                numerator, denominator,
+                delta_minus, delta_plus);
+        // We now have v = (numerator / denominator) * 10^estimated_power.
+        buffer.decimalPoint = fixupMultiply10(estimated_power, is_even,
+                numerator, denominator,
+                delta_minus, delta_plus);
+        // We now have v = (numerator / denominator) * 10^(decimal_point-1), and
+        //  1 <= (numerator + delta_plus) / denominator < 10
+        switch (mode) {
+            case SHORTEST:
+                generateShortestDigits(numerator, denominator,
+                        delta_minus, delta_plus,
+                        is_even, buffer);
+                break;
+            case FIXED:
+                bignumToFixed(requested_digits,
+                        numerator, denominator,
+                        buffer);
+                break;
+            case PRECISION:
+                generateCountedDigits(requested_digits,
+                        numerator, denominator,
+                        buffer);
+                break;
+            default:
+                throw new RuntimeException();
+        }
+    }
+
+
+    // The procedure starts generating digits from the left to the right and stops
+    // when the generated digits yield the shortest decimal representation of v. A
+    // decimal representation of v is a number lying closer to v than to any other
+    // double, so it converts to v when read.
+    //
+    // This is true if d, the decimal representation, is between m- and m+, the
+    // upper and lower boundaries. d must be strictly between them if !is_even.
+    //           m- := (numerator - delta_minus) / denominator
+    //           m+ := (numerator + delta_plus) / denominator
+    //
+    // Precondition: 0 <= (numerator+delta_plus) / denominator < 10.
+    //   If 1 <= (numerator+delta_plus) / denominator < 10 then no leading 0 digit
+    //   will be produced. This should be the standard precondition.
+    static void generateShortestDigits(final Bignum numerator, final Bignum denominator,
+                                       final Bignum delta_minus, Bignum delta_plus,
+                                       final boolean is_even,
+                                       final DtoaBuffer buffer) {
+        // Small optimization: if delta_minus and delta_plus are the same just reuse
+        // one of the two bignums.
+        if (Bignum.equal(delta_minus, delta_plus)) {
+            delta_plus = delta_minus;
+        }
+        for (;;) {
+            final char digit;
+            digit = numerator.divideModuloIntBignum(denominator);
+            assert (digit <= 9);  // digit is a uint16_t and therefore always positive.
+            // digit = numerator / denominator (integer division).
+            // numerator = numerator % denominator.
+            buffer.append((char) (digit + '0'));
+
+            // Can we stop already?
+            // If the remainder of the division is less than the distance to the lower
+            // boundary we can stop. In this case we simply round down (discarding the
+            // remainder).
+            // Similarly we test if we can round up (using the upper boundary).
+            final boolean in_delta_room_minus;
+            final boolean in_delta_room_plus;
+            if (is_even) {
+                in_delta_room_minus = Bignum.lessEqual(numerator, delta_minus);
+            } else {
+                in_delta_room_minus = Bignum.less(numerator, delta_minus);
+            }
+            if (is_even) {
+                in_delta_room_plus =
+                        Bignum.plusCompare(numerator, delta_plus, denominator) >= 0;
+            } else {
+                in_delta_room_plus =
+                        Bignum.plusCompare(numerator, delta_plus, denominator) > 0;
+            }
+            if (!in_delta_room_minus && !in_delta_room_plus) {
+                // Prepare for next iteration.
+                numerator.times10();
+                delta_minus.times10();
+                // We optimized delta_plus to be equal to delta_minus (if they share the
+                // same value). So don't multiply delta_plus if they point to the same
+                // object.
+                if (delta_minus != delta_plus) {
+                    delta_plus.times10();
+                }
+            } else if (in_delta_room_minus && in_delta_room_plus) {
+                // Let's see if 2*numerator < denominator.
+                // If yes, then the next digit would be < 5 and we can round down.
+                final int compare = Bignum.plusCompare(numerator, numerator, denominator);
+                if (compare < 0) {
+                    // Remaining digits are less than .5. -> Round down (== do nothing).
+                } else if (compare > 0) {
+                    // Remaining digits are more than .5 of denominator. -> Round up.
+                    // Note that the last digit could not be a '9' as otherwise the whole
+                    // loop would have stopped earlier.
+                    // We still have an assert here in case the preconditions were not
+                    // satisfied.
+                    assert (buffer.chars[buffer.length - 1] != '9');
+                    buffer.chars[buffer.length - 1]++;
+                } else {
+                    // Halfway case.
+                    // TODO(floitsch): need a way to solve half-way cases.
+                    //   For now let's round towards even (since this is what Gay seems to
+                    //   do).
+
+                    if ((buffer.chars[buffer.length - 1] - '0') % 2 == 0) {
+                        // Round down => Do nothing.
+                    } else {
+                        assert (buffer.chars[buffer.length - 1] != '9');
+                        buffer.chars[buffer.length - 1]++;
+                    }
+                }
+                return;
+            } else if (in_delta_room_minus) {
+                // Round down (== do nothing).
+                return;
+            } else {  // in_delta_room_plus
+                // Round up.
+                // Note again that the last digit could not be '9' since this would have
+                // stopped the loop earlier.
+                // We still have an ASSERT here, in case the preconditions were not
+                // satisfied.
+                assert (buffer.chars[buffer.length -1] != '9');
+                buffer.chars[buffer.length - 1]++;
+                return;
+            }
+        }
+    }
+
+
+    // Let v = numerator / denominator < 10.
+    // Then we generate 'count' digits of d = x.xxxxx... (without the decimal point)
+    // from left to right. Once 'count' digits have been produced we decide wether
+    // to round up or down. Remainders of exactly .5 round upwards. Numbers such
+    // as 9.999999 propagate a carry all the way, and change the
+    // exponent (decimal_point), when rounding upwards.
+    static void generateCountedDigits(final int count,
+                                      final Bignum numerator, final Bignum denominator,
+                                      final DtoaBuffer buffer) {
+        assert (count >= 0);
+        for (int i = 0; i < count - 1; ++i) {
+            final char digit;
+            digit = numerator.divideModuloIntBignum(denominator);
+            assert (digit <= 9);  // digit is a uint16_t and therefore always positive.
+            // digit = numerator / denominator (integer division).
+            // numerator = numerator % denominator.
+            buffer.chars[i] = (char)(digit + '0');
+            // Prepare for next iteration.
+            numerator.times10();
+        }
+        // Generate the last digit.
+        char digit;
+        digit = numerator.divideModuloIntBignum(denominator);
+        if (Bignum.plusCompare(numerator, numerator, denominator) >= 0) {
+            digit++;
+        }
+        assert (digit <= 10);
+        buffer.chars[count - 1] = (char) (digit + '0');
+        // Correct bad digits (in case we had a sequence of '9's). Propagate the
+        // carry until we hat a non-'9' or til we reach the first digit.
+        for (int i = count - 1; i > 0; --i) {
+            if (buffer.chars[i] != '0' + 10) break;
+            buffer.chars[i] = '0';
+            buffer.chars[i - 1]++;
+        }
+        if (buffer.chars[0] == '0' + 10) {
+            // Propagate a carry past the top place.
+            buffer.chars[0] = '1';
+            buffer.decimalPoint++;
+        }
+        buffer.length = count;
+    }
+
+
+    // Generates 'requested_digits' after the decimal point. It might omit
+    // trailing '0's. If the input number is too small then no digits at all are
+    // generated (ex.: 2 fixed digits for 0.00001).
+    //
+    // Input verifies:  1 <= (numerator + delta) / denominator < 10.
+    static void bignumToFixed(final int requested_digits,
+                              final Bignum numerator, final Bignum denominator,
+                              final DtoaBuffer buffer) {
+        // Note that we have to look at more than just the requested_digits, since
+        // a number could be rounded up. Example: v=0.5 with requested_digits=0.
+        // Even though the power of v equals 0 we can't just stop here.
+        if (-buffer.decimalPoint > requested_digits) {
+            // The number is definitively too small.
+            // Ex: 0.001 with requested_digits == 1.
+            // Set decimal-decimalPoint to -requested_digits. This is what Gay does.
+            // Note that it should not have any effect anyways since the string is
+            // empty.
+            buffer.decimalPoint = -requested_digits;
+            buffer.length = 0;
+            // return;
+        } else if (-buffer.decimalPoint == requested_digits) {
+            // We only need to verify if the number rounds down or up.
+            // Ex: 0.04 and 0.06 with requested_digits == 1.
+            assert (buffer.decimalPoint == -requested_digits);
+            // Initially the fraction lies in range (1, 10]. Multiply the denominator
+            // by 10 so that we can compare more easily.
+            denominator.times10();
+            if (Bignum.plusCompare(numerator, numerator, denominator) >= 0) {
+                // If the fraction is >= 0.5 then we have to include the rounded
+                // digit.
+                buffer.chars[0] = '1';
+                buffer.length = 1;
+                buffer.decimalPoint++;
+            } else {
+                // Note that we caught most of similar cases earlier.
+                buffer.length = 0;
+            }
+            // return;
+        } else {
+            // The requested digits correspond to the digits after the point.
+            // The variable 'needed_digits' includes the digits before the point.
+            final int needed_digits = buffer.decimalPoint + requested_digits;
+            generateCountedDigits(needed_digits,
+                    numerator, denominator,
+                    buffer);
+        }
+    }
+
+
+    // Returns an estimation of k such that 10^(k-1) <= v < 10^k where
+    // v = f * 2^exponent and 2^52 <= f < 2^53.
+    // v is hence a normalized double with the given exponent. The output is an
+    // approximation for the exponent of the decimal approimation .digits * 10^k.
+    //
+    // The result might undershoot by 1 in which case 10^k <= v < 10^k+1.
+    // Note: this property holds for v's upper boundary m+ too.
+    //    10^k <= m+ < 10^k+1.
+    //   (see explanation below).
+    //
+    // Examples:
+    //  EstimatePower(0)   => 16
+    //  EstimatePower(-52) => 0
+    //
+    // Note: e >= 0 => EstimatedPower(e) > 0. No similar claim can be made for e<0.
+    static int estimatePower(final int exponent) {
+        // This function estimates log10 of v where v = f*2^e (with e == exponent).
+        // Note that 10^floor(log10(v)) <= v, but v <= 10^ceil(log10(v)).
+        // Note that f is bounded by its container size. Let p = 53 (the double's
+        // significand size). Then 2^(p-1) <= f < 2^p.
+        //
+        // Given that log10(v) == log2(v)/log2(10) and e+(len(f)-1) is quite close
+        // to log2(v) the function is simplified to (e+(len(f)-1)/log2(10)).
+        // The computed number undershoots by less than 0.631 (when we compute log3
+        // and not log10).
+        //
+        // Optimization: since we only need an approximated result this computation
+        // can be performed on 64 bit integers. On x86/x64 architecture the speedup is
+        // not really measurable, though.
+        //
+        // Since we want to avoid overshooting we decrement by 1e10 so that
+        // floating-point imprecisions don't affect us.
+        //
+        // Explanation for v's boundary m+: the computation takes advantage of
+        // the fact that 2^(p-1) <= f < 2^p. Boundaries still satisfy this requirement
+        // (even for denormals where the delta can be much more important).
+
+        final double k1Log10 = 0.30102999566398114;  // 1/lg(10)
+
+        // For doubles len(f) == 53 (don't forget the hidden bit).
+        final int kSignificandSize = IeeeDouble.kSignificandSize;
+        final double estimate = Math.ceil((exponent + kSignificandSize - 1) * k1Log10 - 1e-10);
+        return (int) estimate;
+    }
+
+
+    // See comments for InitialScaledStartValues.
+    static void initialScaledStartValuesPositiveExponent(
+            final long significand, final int exponent,
+            final int estimated_power, final boolean need_boundary_deltas,
+            final Bignum numerator, final Bignum denominator,
+            final Bignum delta_minus, final Bignum delta_plus) {
+        // A positive exponent implies a positive power.
+        assert (estimated_power >= 0);
+        // Since the estimated_power is positive we simply multiply the denominator
+        // by 10^estimated_power.
+
+        // numerator = v.
+        numerator.assignUInt64(significand);
+        numerator.shiftLeft(exponent);
+        // denominator = 10^estimated_power.
+        denominator.assignPowerUInt16(10, estimated_power);
+
+        if (need_boundary_deltas) {
+            // Introduce a common denominator so that the deltas to the boundaries are
+            // integers.
+            denominator.shiftLeft(1);
+            numerator.shiftLeft(1);
+            // Let v = f * 2^e, then m+ - v = 1/2 * 2^e; With the common
+            // denominator (of 2) delta_plus equals 2^e.
+            delta_plus.assignUInt16((char) 1);
+            delta_plus.shiftLeft(exponent);
+            // Same for delta_minus. The adjustments if f == 2^p-1 are done later.
+            delta_minus.assignUInt16((char) 1);
+            delta_minus.shiftLeft(exponent);
+        }
+    }
+
+
+    // See comments for InitialScaledStartValues
+    static void initialScaledStartValuesNegativeExponentPositivePower(
+            final long significand, final int exponent,
+            final int estimated_power, final boolean need_boundary_deltas,
+            final Bignum numerator, final Bignum denominator,
+            final Bignum delta_minus, final Bignum delta_plus) {
+        // v = f * 2^e with e < 0, and with estimated_power >= 0.
+        // This means that e is close to 0 (have a look at how estimated_power is
+        // computed).
+
+        // numerator = significand
+        //  since v = significand * 2^exponent this is equivalent to
+        //  numerator = v * / 2^-exponent
+        numerator.assignUInt64(significand);
+        // denominator = 10^estimated_power * 2^-exponent (with exponent < 0)
+        denominator.assignPowerUInt16(10, estimated_power);
+        denominator.shiftLeft(-exponent);
+
+        if (need_boundary_deltas) {
+            // Introduce a common denominator so that the deltas to the boundaries are
+            // integers.
+            denominator.shiftLeft(1);
+            numerator.shiftLeft(1);
+            // Let v = f * 2^e, then m+ - v = 1/2 * 2^e; With the common
+            // denominator (of 2) delta_plus equals 2^e.
+            // Given that the denominator already includes v's exponent the distance
+            // to the boundaries is simply 1.
+            delta_plus.assignUInt16((char) 1);
+            // Same for delta_minus. The adjustments if f == 2^p-1 are done later.
+            delta_minus.assignUInt16((char) 1);
+        }
+    }
+
+
+    // See comments for InitialScaledStartValues
+    static void initialScaledStartValuesNegativeExponentNegativePower(
+            final long significand, final int exponent,
+            final int estimated_power, final boolean need_boundary_deltas,
+            final Bignum numerator, final Bignum denominator,
+            final Bignum delta_minus, final Bignum delta_plus) {
+        // Instead of multiplying the denominator with 10^estimated_power we
+        // multiply all values (numerator and deltas) by 10^-estimated_power.
+
+        // Use numerator as temporary container for power_ten.
+        final Bignum power_ten = numerator;
+        power_ten.assignPowerUInt16(10, -estimated_power);
+
+        if (need_boundary_deltas) {
+            // Since power_ten == numerator we must make a copy of 10^estimated_power
+            // before we complete the computation of the numerator.
+            // delta_plus = delta_minus = 10^estimated_power
+            delta_plus.assignBignum(power_ten);
+            delta_minus.assignBignum(power_ten);
+        }
+
+        // numerator = significand * 2 * 10^-estimated_power
+        //  since v = significand * 2^exponent this is equivalent to
+        // numerator = v * 10^-estimated_power * 2 * 2^-exponent.
+        // Remember: numerator has been abused as power_ten. So no need to assign it
+        //  to itself.
+        assert (numerator == power_ten);
+        numerator.multiplyByUInt64(significand);
+
+        // denominator = 2 * 2^-exponent with exponent < 0.
+        denominator.assignUInt16((char) 1);
+        denominator.shiftLeft(-exponent);
+
+        if (need_boundary_deltas) {
+            // Introduce a common denominator so that the deltas to the boundaries are
+            // integers.
+            numerator.shiftLeft(1);
+            denominator.shiftLeft(1);
+            // With this shift the boundaries have their correct value, since
+            // delta_plus = 10^-estimated_power, and
+            // delta_minus = 10^-estimated_power.
+            // These assignments have been done earlier.
+            // The adjustments if f == 2^p-1 (lower boundary is closer) are done later.
+        }
+    }
+
+
+    // Let v = significand * 2^exponent.
+    // Computes v / 10^estimated_power exactly, as a ratio of two bignums, numerator
+    // and denominator. The functions GenerateShortestDigits and
+    // GenerateCountedDigits will then convert this ratio to its decimal
+    // representation d, with the required accuracy.
+    // Then d * 10^estimated_power is the representation of v.
+    // (Note: the fraction and the estimated_power might get adjusted before
+    // generating the decimal representation.)
+    //
+    // The initial start values consist of:
+    //  - a scaled numerator: s.t. numerator/denominator == v / 10^estimated_power.
+    //  - a scaled (common) denominator.
+    //  optionally (used by GenerateShortestDigits to decide if it has the shortest
+    //  decimal converting back to v):
+    //  - v - m-: the distance to the lower boundary.
+    //  - m+ - v: the distance to the upper boundary.
+    //
+    // v, m+, m-, and therefore v - m- and m+ - v all share the same denominator.
+    //
+    // Let ep == estimated_power, then the returned values will satisfy:
+    //  v / 10^ep = numerator / denominator.
+    //  v's boundarys m- and m+:
+    //    m- / 10^ep == v / 10^ep - delta_minus / denominator
+    //    m+ / 10^ep == v / 10^ep + delta_plus / denominator
+    //  Or in other words:
+    //    m- == v - delta_minus * 10^ep / denominator;
+    //    m+ == v + delta_plus * 10^ep / denominator;
+    //
+    // Since 10^(k-1) <= v < 10^k    (with k == estimated_power)
+    //  or       10^k <= v < 10^(k+1)
+    //  we then have 0.1 <= numerator/denominator < 1
+    //           or    1 <= numerator/denominator < 10
+    //
+    // It is then easy to kickstart the digit-generation routine.
+    //
+    // The boundary-deltas are only filled if the mode equals BIGNUM_DTOA_SHORTEST
+    // or BIGNUM_DTOA_SHORTEST_SINGLE.
+
+    static void initialScaledStartValues(final long significand,
+                                         final int exponent,
+                                         final boolean lower_boundary_is_closer,
+                                         final int estimated_power,
+                                         final boolean need_boundary_deltas,
+                                         final Bignum numerator,
+                                         final Bignum denominator,
+                                         final Bignum delta_minus,
+                                         final Bignum delta_plus) {
+        if (exponent >= 0) {
+            initialScaledStartValuesPositiveExponent(
+                    significand, exponent, estimated_power, need_boundary_deltas,
+                    numerator, denominator, delta_minus, delta_plus);
+        } else if (estimated_power >= 0) {
+            initialScaledStartValuesNegativeExponentPositivePower(
+                    significand, exponent, estimated_power, need_boundary_deltas,
+                    numerator, denominator, delta_minus, delta_plus);
+        } else {
+            initialScaledStartValuesNegativeExponentNegativePower(
+                    significand, exponent, estimated_power, need_boundary_deltas,
+                    numerator, denominator, delta_minus, delta_plus);
+        }
+
+        if (need_boundary_deltas && lower_boundary_is_closer) {
+            // The lower boundary is closer at half the distance of "normal" numbers.
+            // Increase the common denominator and adapt all but the delta_minus.
+            denominator.shiftLeft(1);  // *2
+            numerator.shiftLeft(1);    // *2
+            delta_plus.shiftLeft(1);   // *2
+        }
+    }
+
+
+    // This routine multiplies numerator/denominator so that its values lies in the
+    // range 1-10. That is after a call to this function we have:
+    //    1 <= (numerator + delta_plus) /denominator < 10.
+    // Let numerator the input before modification and numerator' the argument
+    // after modification, then the output-parameter decimal_point is such that
+    //  numerator / denominator * 10^estimated_power ==
+    //    numerator' / denominator' * 10^(decimal_point - 1)
+    // In some cases estimated_power was too low, and this is already the case. We
+    // then simply adjust the power so that 10^(k-1) <= v < 10^k (with k ==
+    // estimated_power) but do not touch the numerator or denominator.
+    // Otherwise the routine multiplies the numerator and the deltas by 10.
+    static int fixupMultiply10(final int estimated_power, final boolean is_even,
+                                final Bignum numerator, final Bignum denominator,
+                                final Bignum delta_minus, final Bignum delta_plus) {
+        final boolean in_range;
+        final int decimal_point;
+        if (is_even) {
+            // For IEEE doubles half-way cases (in decimal system numbers ending with 5)
+            // are rounded to the closest floating-point number with even significand.
+            in_range = Bignum.plusCompare(numerator, delta_plus, denominator) >= 0;
+        } else {
+            in_range = Bignum.plusCompare(numerator, delta_plus, denominator) > 0;
+        }
+        if (in_range) {
+            // Since numerator + delta_plus >= denominator we already have
+            // 1 <= numerator/denominator < 10. Simply update the estimated_power.
+            decimal_point = estimated_power + 1;
+        } else {
+            decimal_point = estimated_power;
+            numerator.times10();
+            if (Bignum.equal(delta_minus, delta_plus)) {
+                delta_minus.times10();
+                delta_plus.assignBignum(delta_minus);
+            } else {
+                delta_minus.times10();
+                delta_plus.times10();
+            }
+        }
+        return decimal_point;
+    }
+
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/doubleconv/CachedPowers.java	Thu Nov 26 01:06:51 2015 +0100
@@ -0,0 +1,204 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  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.
+ */
+
+// This file is available under and governed by the GNU General Public
+// License version 2 only, as published by the Free Software Foundation.
+// However, the following notice accompanied the original version of this
+// file:
+//
+// Copyright 2010 the V8 project authors. 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 Google Inc. 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.
+
+package jdk.nashorn.internal.runtime.doubleconv;
+
+public class CachedPowers {
+
+    static class CachedPower {
+        final private long significand;
+        final private int binaryExponent;
+        final private int decimalExponent;
+
+        CachedPower(final long significand, final int binaryExponent, final int decimalExponent) {
+            this.significand = significand;
+            this.binaryExponent = binaryExponent;
+            this.decimalExponent = decimalExponent;
+        }
+    }
+
+    static private final CachedPower[] kCachedPowers = {
+            new CachedPower(0xfa8fd5a0081c0288L, -1220, -348),
+            new CachedPower(0xbaaee17fa23ebf76L, -1193, -340),
+            new CachedPower(0x8b16fb203055ac76L, -1166, -332),
+            new CachedPower(0xcf42894a5dce35eaL, -1140, -324),
+            new CachedPower(0x9a6bb0aa55653b2dL, -1113, -316),
+            new CachedPower(0xe61acf033d1a45dfL, -1087, -308),
+            new CachedPower(0xab70fe17c79ac6caL, -1060, -300),
+            new CachedPower(0xff77b1fcbebcdc4fL, -1034, -292),
+            new CachedPower(0xbe5691ef416bd60cL, -1007, -284),
+            new CachedPower(0x8dd01fad907ffc3cL, -980, -276),
+            new CachedPower(0xd3515c2831559a83L, -954, -268),
+            new CachedPower(0x9d71ac8fada6c9b5L, -927, -260),
+            new CachedPower(0xea9c227723ee8bcbL, -901, -252),
+            new CachedPower(0xaecc49914078536dL, -874, -244),
+            new CachedPower(0x823c12795db6ce57L, -847, -236),
+            new CachedPower(0xc21094364dfb5637L, -821, -228),
+            new CachedPower(0x9096ea6f3848984fL, -794, -220),
+            new CachedPower(0xd77485cb25823ac7L, -768, -212),
+            new CachedPower(0xa086cfcd97bf97f4L, -741, -204),
+            new CachedPower(0xef340a98172aace5L, -715, -196),
+            new CachedPower(0xb23867fb2a35b28eL, -688, -188),
+            new CachedPower(0x84c8d4dfd2c63f3bL, -661, -180),
+            new CachedPower(0xc5dd44271ad3cdbaL, -635, -172),
+            new CachedPower(0x936b9fcebb25c996L, -608, -164),
+            new CachedPower(0xdbac6c247d62a584L, -582, -156),
+            new CachedPower(0xa3ab66580d5fdaf6L, -555, -148),
+            new CachedPower(0xf3e2f893dec3f126L, -529, -140),
+            new CachedPower(0xb5b5ada8aaff80b8L, -502, -132),
+            new CachedPower(0x87625f056c7c4a8bL, -475, -124),
+            new CachedPower(0xc9bcff6034c13053L, -449, -116),
+            new CachedPower(0x964e858c91ba2655L, -422, -108),
+            new CachedPower(0xdff9772470297ebdL, -396, -100),
+            new CachedPower(0xa6dfbd9fb8e5b88fL, -369, -92),
+            new CachedPower(0xf8a95fcf88747d94L, -343, -84),
+            new CachedPower(0xb94470938fa89bcfL, -316, -76),
+            new CachedPower(0x8a08f0f8bf0f156bL, -289, -68),
+            new CachedPower(0xcdb02555653131b6L, -263, -60),
+            new CachedPower(0x993fe2c6d07b7facL, -236, -52),
+            new CachedPower(0xe45c10c42a2b3b06L, -210, -44),
+            new CachedPower(0xaa242499697392d3L, -183, -36),
+            new CachedPower(0xfd87b5f28300ca0eL, -157, -28),
+            new CachedPower(0xbce5086492111aebL, -130, -20),
+            new CachedPower(0x8cbccc096f5088ccL, -103, -12),
+            new CachedPower(0xd1b71758e219652cL, -77, -4),
+            new CachedPower(0x9c40000000000000L, -50, 4),
+            new CachedPower(0xe8d4a51000000000L, -24, 12),
+            new CachedPower(0xad78ebc5ac620000L, 3, 20),
+            new CachedPower(0x813f3978f8940984L, 30, 28),
+            new CachedPower(0xc097ce7bc90715b3L, 56, 36),
+            new CachedPower(0x8f7e32ce7bea5c70L, 83, 44),
+            new CachedPower(0xd5d238a4abe98068L, 109, 52),
+            new CachedPower(0x9f4f2726179a2245L, 136, 60),
+            new CachedPower(0xed63a231d4c4fb27L, 162, 68),
+            new CachedPower(0xb0de65388cc8ada8L, 189, 76),
+            new CachedPower(0x83c7088e1aab65dbL, 216, 84),
+            new CachedPower(0xc45d1df942711d9aL, 242, 92),
+            new CachedPower(0x924d692ca61be758L, 269, 100),
+            new CachedPower(0xda01ee641a708deaL, 295, 108),
+            new CachedPower(0xa26da3999aef774aL, 322, 116),
+            new CachedPower(0xf209787bb47d6b85L, 348, 124),
+            new CachedPower(0xb454e4a179dd1877L, 375, 132),
+            new CachedPower(0x865b86925b9bc5c2L, 402, 140),
+            new CachedPower(0xc83553c5c8965d3dL, 428, 148),
+            new CachedPower(0x952ab45cfa97a0b3L, 455, 156),
+            new CachedPower(0xde469fbd99a05fe3L, 481, 164),
+            new CachedPower(0xa59bc234db398c25L, 508, 172),
+            new CachedPower(0xf6c69a72a3989f5cL, 534, 180),
+            new CachedPower(0xb7dcbf5354e9beceL, 561, 188),
+            new CachedPower(0x88fcf317f22241e2L, 588, 196),
+            new CachedPower(0xcc20ce9bd35c78a5L, 614, 204),
+            new CachedPower(0x98165af37b2153dfL, 641, 212),
+            new CachedPower(0xe2a0b5dc971f303aL, 667, 220),
+            new CachedPower(0xa8d9d1535ce3b396L, 694, 228),
+            new CachedPower(0xfb9b7cd9a4a7443cL, 720, 236),
+            new CachedPower(0xbb764c4ca7a44410L, 747, 244),
+            new CachedPower(0x8bab8eefb6409c1aL, 774, 252),
+            new CachedPower(0xd01fef10a657842cL, 800, 260),
+            new CachedPower(0x9b10a4e5e9913129L, 827, 268),
+            new CachedPower(0xe7109bfba19c0c9dL, 853, 276),
+            new CachedPower(0xac2820d9623bf429L, 880, 284),
+            new CachedPower(0x80444b5e7aa7cf85L, 907, 292),
+            new CachedPower(0xbf21e44003acdd2dL, 933, 300),
+            new CachedPower(0x8e679c2f5e44ff8fL, 960, 308),
+            new CachedPower(0xd433179d9c8cb841L, 986, 316),
+            new CachedPower(0x9e19db92b4e31ba9L, 1013, 324),
+            new CachedPower(0xeb96bf6ebadf77d9L, 1039, 332),
+            new CachedPower(0xaf87023b9bf0ee6bL, 1066, 340)
+    };
+
+    static final int kCachedPowersOffset = 348;  // -1 * the first decimal_exponent.
+    static final double kD_1_LOG2_10 = 0.30102999566398114;  //  1 / lg(10)
+    // Difference between the decimal exponents in the table above.
+    static final int kDecimalExponentDistance = 8;
+    static final int kMinDecimalExponent = -348;
+    static final int kMaxDecimalExponent = 340;
+
+    static int getCachedPowerForBinaryExponentRange(
+            final int min_exponent,
+            final int max_exponent,
+            final DiyFp power) {
+        final int kQ = DiyFp.kSignificandSize;
+        final double k = Math.ceil((min_exponent + kQ - 1) * kD_1_LOG2_10);
+        final int index =
+                (kCachedPowersOffset + (int) k - 1) / kDecimalExponentDistance + 1;
+        assert (0 <= index && index < kCachedPowers.length);
+        final CachedPower cached_power = kCachedPowers[index];
+        assert (min_exponent <= cached_power.binaryExponent);
+        assert (cached_power.binaryExponent <= max_exponent);
+        power.setF(cached_power.significand);
+        power.setE(cached_power.binaryExponent);
+        return cached_power.decimalExponent;
+    }
+
+
+    static int getCachedPowerForDecimalExponent(final int requested_exponent,
+                                                final DiyFp power) {
+        assert (kMinDecimalExponent <= requested_exponent);
+        assert (requested_exponent < kMaxDecimalExponent + kDecimalExponentDistance);
+        final int index =
+                (requested_exponent + kCachedPowersOffset) / kDecimalExponentDistance;
+        final CachedPower cached_power = kCachedPowers[index];
+        power.setF(cached_power.significand);
+        power.setE(cached_power.binaryExponent);
+        final int found_exponent = cached_power.decimalExponent;
+        assert (found_exponent <= requested_exponent);
+        assert (requested_exponent < found_exponent + kDecimalExponentDistance);
+        return cached_power.decimalExponent;
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/doubleconv/DiyFp.java	Thu Nov 26 01:06:51 2015 +0100
@@ -0,0 +1,172 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  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.
+ */
+
+// This file is available under and governed by the GNU General Public
+// License version 2 only, as published by the Free Software Foundation.
+// However, the following notice accompanied the original version of this
+// file:
+//
+// Copyright 2010 the V8 project authors. 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 Google Inc. 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.
+
+package jdk.nashorn.internal.runtime.doubleconv;
+
+// This "Do It Yourself Floating Point" class implements a floating-point number
+// with a uint64 significand and an int exponent. Normalized DiyFp numbers will
+// have the most significant bit of the significand set.
+// Multiplication and Subtraction do not normalize their results.
+// DiyFp are not designed to contain special doubles (NaN and Infinity).
+class DiyFp {
+
+    private long f_;
+    private int e_;
+
+    static final int kSignificandSize = 64;
+    static final long kUint64MSB = 0x8000000000000000L;
+
+
+    DiyFp() {
+        this.f_ = 0;
+        this.e_ = 0;
+    }
+
+    DiyFp(final long f, final int e) {
+        this.f_ = f;
+        this.e_ = e;
+    }
+
+    // this = this - other.
+    // The exponents of both numbers must be the same and the significand of this
+    // must be bigger than the significand of other.
+    // The result will not be normalized.
+    void subtract(final DiyFp other) {
+        assert (e_ == other.e_);
+        assert Long.compareUnsigned(f_, other.f_) >= 0;
+        f_ -= other.f_;
+    }
+
+    // Returns a - b.
+    // The exponents of both numbers must be the same and this must be bigger
+    // than other. The result will not be normalized.
+    static DiyFp minus(final DiyFp a, final DiyFp b) {
+        final DiyFp result = new DiyFp(a.f_, a.e_);
+        result.subtract(b);
+        return result;
+    }
+
+
+    // this = this * other.
+    final void multiply(final DiyFp other) {
+        // Simply "emulates" a 128 bit multiplication.
+        // However: the resulting number only contains 64 bits. The least
+        // significant 64 bits are only used for rounding the most significant 64
+        // bits.
+        final long kM32 = 0xFFFFFFFFL;
+        final long a = f_ >>> 32;
+        final long b = f_ & kM32;
+        final long c = other.f_ >>> 32;
+        final long d = other.f_ & kM32;
+        final long ac = a * c;
+        final long bc = b * c;
+        final long ad = a * d;
+        final long bd = b * d;
+        long tmp = (bd >>> 32) + (ad & kM32) + (bc & kM32);
+        // By adding 1U << 31 to tmp we round the final result.
+        // Halfway cases will be round up.
+        tmp += 1L << 31;
+        final long result_f = ac + (ad >>> 32) + (bc >>> 32) + (tmp >>> 32);
+        e_ += other.e_ + 64;
+        f_ = result_f;
+    }
+
+    // returns a * b;
+    static DiyFp times(final DiyFp a, final DiyFp b) {
+        final DiyFp result = new DiyFp(a.f_, a.e_);
+        result.multiply(b);
+        return result;
+    }
+
+    void normalize() {
+        assert(f_ != 0);
+        long significand = this.f_;
+        int exponent = this.e_;
+
+        // This method is mainly called for normalizing boundaries. In general
+        // boundaries need to be shifted by 10 bits. We thus optimize for this case.
+        final long k10MSBits = 0xFFC00000L << 32;
+        while ((significand & k10MSBits) == 0) {
+            significand <<= 10;
+            exponent -= 10;
+        }
+        while ((significand & kUint64MSB) == 0) {
+            significand <<= 1;
+            exponent--;
+        }
+        this.f_ = significand;
+        this.e_ = exponent;
+    }
+
+    static DiyFp normalize(final DiyFp a) {
+        final DiyFp result = new DiyFp(a.f_, a.e_);
+        result.normalize();
+        return result;
+    }
+
+    long f() { return f_; }
+    int e() { return e_; }
+
+    void setF(final long new_value) { f_ = new_value; }
+    void setE(final int new_value) { e_ = new_value; }
+
+    @Override
+    public String toString() {
+        return "DiyFp[f=" + f_ + ", e=" + e_ + "]";
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/doubleconv/DoubleConversion.java	Thu Nov 26 01:06:51 2015 +0100
@@ -0,0 +1,214 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  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.
+ */
+
+// This file is available under and governed by the GNU General Public
+// License version 2 only, as published by the Free Software Foundation.
+// However, the following notice accompanied the original version of this
+// file:
+//
+// Copyright 2011 the V8 project authors. 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 Google Inc. 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.
+
+package jdk.nashorn.internal.runtime.doubleconv;
+
+/**
+ * This class provides the public API for the double conversion package.
+ */
+public final class DoubleConversion {
+
+    private final static int BUFFER_LENGTH = 30;
+
+    /**
+     * Converts a double number to its shortest string representation.
+     *
+     * @param value number to convert
+     * @return formatted number
+     */
+    public static String toShortestString(final double value) {
+        final DtoaBuffer buffer = new DtoaBuffer(FastDtoa.kFastDtoaMaximalLength);
+        final double absValue = Math.abs(value);
+
+        if (value < 0) {
+            buffer.isNegative = true;
+        }
+
+        if (!fastDtoaShortest(absValue, buffer)) {
+            buffer.reset();
+            bignumDtoa(absValue, DtoaMode.SHORTEST, 0, buffer);
+        }
+
+        return buffer.format(DtoaMode.SHORTEST, 0);
+    }
+
+    /**
+     * Converts a double number to a string representation with a fixed number of digits
+     * after the decimal point.
+     *
+     * @param value number to convert.
+     * @param requestedDigits number of digits after decimal point
+     * @return formatted number
+     */
+    public static String toFixed(final double value, final int requestedDigits) {
+        final DtoaBuffer buffer = new DtoaBuffer(BUFFER_LENGTH);
+        final double absValue = Math.abs(value);
+
+        if (value < 0) {
+            buffer.isNegative = true;
+        }
+
+        if (value == 0) {
+            buffer.append('0');
+            buffer.decimalPoint = 1;
+        } else if (!fixedDtoa(absValue, requestedDigits, buffer)) {
+            buffer.reset();
+            bignumDtoa(absValue, DtoaMode.FIXED, requestedDigits, buffer);
+        }
+
+        return buffer.format(DtoaMode.FIXED, requestedDigits);
+    }
+
+    /**
+     * Converts a double number to a string representation with a fixed number of digits.
+     *
+     * @param value number to convert
+     * @param precision number of digits to create
+     * @return formatted number
+     */
+    public static String toPrecision(final double value, final int precision) {
+        final DtoaBuffer buffer = new DtoaBuffer(precision);
+        final double absValue = Math.abs(value);
+
+        if (value < 0) {
+            buffer.isNegative = true;
+        }
+
+        if (value == 0) {
+            for (int i = 0; i < precision; i++) {
+                buffer.append('0');
+            }
+            buffer.decimalPoint = 1;
+
+        } else if (!fastDtoaCounted(absValue, precision, buffer)) {
+            buffer.reset();
+            bignumDtoa(absValue, DtoaMode.PRECISION, precision, buffer);
+        }
+
+        return buffer.format(DtoaMode.PRECISION, 0);
+    }
+
+    /**
+     * Converts a double number to a string representation using the
+     * {@code BignumDtoa} algorithm and the specified conversion mode
+     * and number of digits.
+     *
+     * @param v number to convert
+     * @param mode conversion mode
+     * @param digits number of digits
+     * @param buffer buffer to use
+     */
+    public static void bignumDtoa(final double v, final DtoaMode mode, final int digits, final DtoaBuffer buffer) {
+        assert(v > 0);
+        assert(!Double.isNaN(v));
+        assert(!Double.isInfinite(v));
+
+        BignumDtoa.bignumDtoa(v, mode, digits, buffer);
+    }
+
+    /**
+     * Converts a double number to its shortest string representation
+     * using the {@code FastDtoa} algorithm.
+     *
+     * @param v number to convert
+     * @param buffer buffer to use
+     * @return true if conversion succeeded
+     */
+    public static boolean fastDtoaShortest(final double v, final DtoaBuffer buffer) {
+        assert(v > 0);
+        assert(!Double.isNaN(v));
+        assert(!Double.isInfinite(v));
+
+        return FastDtoa.grisu3(v, buffer);
+    }
+
+    /**
+     * Converts a double number to a string representation with the
+     * given number of digits using the {@code FastDtoa} algorithm.
+     *
+     * @param v number to convert
+     * @param precision number of digits to generate
+     * @param buffer buffer to use
+     * @return true if conversion succeeded
+     */
+    public static boolean fastDtoaCounted(final double v, final int precision, final DtoaBuffer buffer) {
+        assert(v > 0);
+        assert(!Double.isNaN(v));
+        assert(!Double.isInfinite(v));
+
+        return FastDtoa.grisu3Counted(v, precision, buffer);
+    }
+
+    /**
+     * Converts a double number to a string representation with a
+     * fixed number of digits after the decimal point using the
+     * {@code FixedDtoa} algorithm.
+     *
+     * @param v number to convert.
+     * @param digits number of digits after the decimal point
+     * @param buffer buffer to use
+     * @return true if conversion succeeded
+     */
+    public static boolean fixedDtoa(final double v, final int digits, final DtoaBuffer buffer) {
+        assert(v > 0);
+        assert(!Double.isNaN(v));
+        assert(!Double.isInfinite(v));
+
+        return FixedDtoa.fastFixedDtoa(v, digits, buffer);
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/doubleconv/DtoaBuffer.java	Thu Nov 26 01:06:51 2015 +0100
@@ -0,0 +1,223 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  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.
+ */
+
+// This file is available under and governed by the GNU General Public
+// License version 2 only, as published by the Free Software Foundation.
+// However, the following notice accompanied the original version of this
+// file:
+//
+// Copyright 2010 the V8 project authors. 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 Google Inc. 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.
+
+package jdk.nashorn.internal.runtime.doubleconv;
+
+/**
+ * A buffer for generating string representations of doubles.
+ */
+public class DtoaBuffer {
+
+    // The character buffer
+    final char[] chars;
+
+    // The number of characters in the buffer
+    int length = 0;
+
+    // The position of the decimal point
+    int decimalPoint = 0;
+
+    // Is this a negative number?
+    boolean isNegative = false;
+
+    /**
+     * Maximal length of numbers converted by FastDtoa
+     */
+    public static final int kFastDtoaMaximalLength = FastDtoa.kFastDtoaMaximalLength;
+
+    /**
+     * Create a buffer with the given capacity.
+     * @param capacity the capacity of the buffer.
+     */
+    public DtoaBuffer(final int capacity) {
+        chars = new char[capacity];
+    }
+
+    /**
+     * Append a character to the buffer, increasing its length.
+     * @param c character
+     */
+    void append(final char c) {
+        chars[length++] = c;
+    }
+
+    /**
+     * Clear the buffer contents and set its length to {@code 0}.
+     */
+    public void reset() {
+        length = 0;
+        decimalPoint = 0;
+    }
+
+    /**
+     * Get the raw digits of this buffer as string.
+     * @return the raw buffer contents
+     */
+    public String getRawDigits() {
+        return new String(chars, 0, length);
+    }
+
+    /**
+     * Get the position of the decimal point.
+     * @return the decimal point position
+     */
+    public int getDecimalPoint() {
+        return decimalPoint;
+    }
+
+    /**
+     * Returns the number of characters in the buffer.
+     * @return buffer length
+     */
+    public int getLength() {
+        return length;
+    }
+
+    /**
+     * Returns the formatted buffer content as string, using the specified conversion mode
+     * and padding.
+     *
+     * @param mode conversion mode
+     * @param digitsAfterPoint number of digits after point
+     * @return formatted string
+     */
+    public String format(final DtoaMode mode, final int digitsAfterPoint) {
+        final StringBuilder buffer = new StringBuilder();
+        if (isNegative) {
+            buffer.append('-');
+        }
+
+        // check for minus sign
+        switch (mode) {
+            case SHORTEST:
+                if (decimalPoint < -5 || decimalPoint > 21) {
+                    toExponentialFormat(buffer);
+                } else {
+                    toFixedFormat(buffer, digitsAfterPoint);
+                }
+                break;
+            case FIXED:
+                toFixedFormat(buffer, digitsAfterPoint);
+                break;
+            case PRECISION:
+                if (decimalPoint < -5 || decimalPoint > length) {
+                    toExponentialFormat(buffer);
+                } else {
+                    toFixedFormat(buffer, digitsAfterPoint);
+                }
+                break;
+        }
+
+        return buffer.toString();
+    }
+
+    private void toFixedFormat(final StringBuilder buffer, final int digitsAfterPoint) {
+        if (decimalPoint <= 0) {
+            // < 1,
+            buffer.append('0');
+            if (length > 0) {
+                buffer.append('.');
+                final int padding = -decimalPoint;
+                for (int i = 0; i < padding; i++) {
+                    buffer.append('0');
+                }
+                buffer.append(chars, 0, length);
+            }
+        } else if (decimalPoint >= length) {
+            // large integer, add trailing zeroes
+            buffer.append(chars, 0, length);
+            for (int i = length; i < decimalPoint; i++) {
+                buffer.append('0');
+            }
+        } else if (decimalPoint < length) {
+            // >= 1, split decimals and insert decimalPoint
+            buffer.append(chars, 0, decimalPoint);
+            buffer.append('.');
+            buffer.append(chars, decimalPoint, length - decimalPoint);
+        }
+
+        // Create trailing zeros if requested
+        if (digitsAfterPoint > 0) {
+            if (decimalPoint >= length) {
+                buffer.append('.');
+            }
+            for (int i = Math.max(0, length - decimalPoint); i < digitsAfterPoint; i++) {
+                buffer.append('0');
+            }
+        }
+    }
+
+    private void toExponentialFormat(final StringBuilder buffer) {
+        buffer.append(chars[0]);
+        if (length > 1) {
+            // insert decimal decimalPoint if more than one digit was produced
+            buffer.append('.');
+            buffer.append(chars, 1, length - 1);
+        }
+        buffer.append('e');
+        final int exponent = decimalPoint - 1;
+        if (exponent > 0) {
+            buffer.append('+');
+        }
+        buffer.append(exponent);
+    }
+
+    @Override
+    public String toString() {
+        return "[chars:" + new String(chars, 0, length) + ", decimalPoint:" + decimalPoint + "]";
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/doubleconv/DtoaMode.java	Thu Nov 26 01:06:51 2015 +0100
@@ -0,0 +1,82 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  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.
+ */
+
+// This file is available under and governed by the GNU General Public
+// License version 2 only, as published by the Free Software Foundation.
+// However, the following notice accompanied the original version of this
+// file:
+//
+// Copyright 2010 the V8 project authors. 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 Google Inc. 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.
+
+package jdk.nashorn.internal.runtime.doubleconv;
+
+/**
+ * This defines the string conversion modes supported by this package.
+ * The original C++ library also supports SHORTEST-SINGLE for single
+ * precision floats but we don't since we always operate with doubles.
+ */
+public enum DtoaMode {
+    /**
+     * Produce the shortest correct representation.
+     * For example the output of 0.299999999999999988897 is (the less accurate
+     * but correct) 0.3.
+     */
+    SHORTEST,
+    /**
+     * Produce a fixed number of digits after the decimal point.
+     * For instance fixed(0.1, 4) becomes 0.1000
+     * If the input number is big, the output will be big.
+     */
+    FIXED,
+    /**
+     * Fixed number of digits (independent of the decimal point).
+     */
+    PRECISION
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/doubleconv/FastDtoa.java	Thu Nov 26 01:06:51 2015 +0100
@@ -0,0 +1,651 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  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.
+ */
+
+// This file is available under and governed by the GNU General Public
+// License version 2 only, as published by the Free Software Foundation.
+// However, the following notice accompanied the original version of this
+// file:
+//
+// Copyright 2010 the V8 project authors. 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 Google Inc. 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.
+
+package jdk.nashorn.internal.runtime.doubleconv;
+
+// Fast Dtoa implementation supporting shortest and precision modes. Does not
+// work for all numbers so BugnumDtoa is used as fallback.
+class FastDtoa {
+
+    // FastDtoa will produce at most kFastDtoaMaximalLength digits. This does not
+    // include the terminating '\0' character.
+    static final int kFastDtoaMaximalLength = 17;
+
+    // The minimal and maximal target exponent define the range of w's binary
+    // exponent, where 'w' is the result of multiplying the input by a cached power
+    // of ten.
+    //
+    // A different range might be chosen on a different platform, to optimize digit
+    // generation, but a smaller range requires more powers of ten to be cached.
+    static final int kMinimalTargetExponent = -60;
+    static final int kMaximalTargetExponent = -32;
+
+
+    // Adjusts the last digit of the generated number, and screens out generated
+    // solutions that may be inaccurate. A solution may be inaccurate if it is
+    // outside the safe interval, or if we cannot prove that it is closer to the
+    // input than a neighboring representation of the same length.
+    //
+    // Input: * buffer containing the digits of too_high / 10^kappa
+    //        * distance_too_high_w == (too_high - w).f() * unit
+    //        * unsafe_interval == (too_high - too_low).f() * unit
+    //        * rest = (too_high - buffer * 10^kappa).f() * unit
+    //        * ten_kappa = 10^kappa * unit
+    //        * unit = the common multiplier
+    // Output: returns true if the buffer is guaranteed to contain the closest
+    //    representable number to the input.
+    //  Modifies the generated digits in the buffer to approach (round towards) w.
+    static boolean roundWeed(final DtoaBuffer buffer,
+                             final long distance_too_high_w,
+                             final long unsafe_interval,
+                             long rest,
+                             final long ten_kappa,
+                             final long unit) {
+        final long small_distance = distance_too_high_w - unit;
+        final long big_distance = distance_too_high_w + unit;
+        // Let w_low  = too_high - big_distance, and
+        //     w_high = too_high - small_distance.
+        // Note: w_low < w < w_high
+        //
+        // The real w (* unit) must lie somewhere inside the interval
+        // ]w_low; w_high[ (often written as "(w_low; w_high)")
+
+        // Basically the buffer currently contains a number in the unsafe interval
+        // ]too_low; too_high[ with too_low < w < too_high
+        //
+        //  too_high - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+        //                     ^v 1 unit            ^      ^                 ^      ^
+        //  boundary_high ---------------------     .      .                 .      .
+        //                     ^v 1 unit            .      .                 .      .
+        //   - - - - - - - - - - - - - - - - - - -  +  - - + - - - - - -     .      .
+        //                                          .      .         ^       .      .
+        //                                          .  big_distance  .       .      .
+        //                                          .      .         .       .    rest
+        //                              small_distance     .         .       .      .
+        //                                          v      .         .       .      .
+        //  w_high - - - - - - - - - - - - - - - - - -     .         .       .      .
+        //                     ^v 1 unit                   .         .       .      .
+        //  w ----------------------------------------     .         .       .      .
+        //                     ^v 1 unit                   v         .       .      .
+        //  w_low  - - - - - - - - - - - - - - - - - - - - -         .       .      .
+        //                                                           .       .      v
+        //  buffer --------------------------------------------------+-------+--------
+        //                                                           .       .
+        //                                                  safe_interval    .
+        //                                                           v       .
+        //   - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -     .
+        //                     ^v 1 unit                                     .
+        //  boundary_low -------------------------                     unsafe_interval
+        //                     ^v 1 unit                                     v
+        //  too_low  - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+        //
+        //
+        // Note that the value of buffer could lie anywhere inside the range too_low
+        // to too_high.
+        //
+        // boundary_low, boundary_high and w are approximations of the real boundaries
+        // and v (the input number). They are guaranteed to be precise up to one unit.
+        // In fact the error is guaranteed to be strictly less than one unit.
+        //
+        // Anything that lies outside the unsafe interval is guaranteed not to round
+        // to v when read again.
+        // Anything that lies inside the safe interval is guaranteed to round to v
+        // when read again.
+        // If the number inside the buffer lies inside the unsafe interval but not
+        // inside the safe interval then we simply do not know and bail out (returning
+        // false).
+        //
+        // Similarly we have to take into account the imprecision of 'w' when finding
+        // the closest representation of 'w'. If we have two potential
+        // representations, and one is closer to both w_low and w_high, then we know
+        // it is closer to the actual value v.
+        //
+        // By generating the digits of too_high we got the largest (closest to
+        // too_high) buffer that is still in the unsafe interval. In the case where
+        // w_high < buffer < too_high we try to decrement the buffer.
+        // This way the buffer approaches (rounds towards) w.
+        // There are 3 conditions that stop the decrementation process:
+        //   1) the buffer is already below w_high
+        //   2) decrementing the buffer would make it leave the unsafe interval
+        //   3) decrementing the buffer would yield a number below w_high and farther
+        //      away than the current number. In other words:
+        //              (buffer{-1} < w_high) && w_high - buffer{-1} > buffer - w_high
+        // Instead of using the buffer directly we use its distance to too_high.
+        // Conceptually rest ~= too_high - buffer
+        // We need to do the following tests in this order to avoid over- and
+        // underflows.
+        assert (Long.compareUnsigned(rest, unsafe_interval) <= 0);
+        while (Long.compareUnsigned(rest, small_distance) < 0 &&  // Negated condition 1
+                Long.compareUnsigned(unsafe_interval - rest, ten_kappa) >= 0 &&  // Negated condition 2
+                (Long.compareUnsigned(rest + ten_kappa, small_distance) < 0 ||  // buffer{-1} > w_high
+                        Long.compareUnsigned(small_distance - rest, rest + ten_kappa - small_distance) >= 0)) {
+            buffer.chars[buffer.length - 1]--;
+            rest += ten_kappa;
+        }
+
+        // We have approached w+ as much as possible. We now test if approaching w-
+        // would require changing the buffer. If yes, then we have two possible
+        // representations close to w, but we cannot decide which one is closer.
+        if (Long.compareUnsigned(rest, big_distance) < 0 &&
+                Long.compareUnsigned(unsafe_interval - rest, ten_kappa) >= 0 &&
+                (Long.compareUnsigned(rest + ten_kappa, big_distance) < 0 ||
+                        Long.compareUnsigned(big_distance - rest, rest + ten_kappa - big_distance) > 0)) {
+            return false;
+        }
+
+        // Weeding test.
+        //   The safe interval is [too_low + 2 ulp; too_high - 2 ulp]
+        //   Since too_low = too_high - unsafe_interval this is equivalent to
+        //      [too_high - unsafe_interval + 4 ulp; too_high - 2 ulp]
+        //   Conceptually we have: rest ~= too_high - buffer
+        return Long.compareUnsigned(2 * unit, rest) <= 0 && Long.compareUnsigned(rest, unsafe_interval - 4 * unit) <= 0;
+    }
+
+    // Rounds the buffer upwards if the result is closer to v by possibly adding
+    // 1 to the buffer. If the precision of the calculation is not sufficient to
+    // round correctly, return false.
+    // The rounding might shift the whole buffer in which case the kappa is
+    // adjusted. For example "99", kappa = 3 might become "10", kappa = 4.
+    //
+    // If 2*rest > ten_kappa then the buffer needs to be round up.
+    // rest can have an error of +/- 1 unit. This function accounts for the
+    // imprecision and returns false, if the rounding direction cannot be
+    // unambiguously determined.
+    //
+    // Precondition: rest < ten_kappa.
+    // Changed return type to int to let caller know they should increase kappa (return value 2)
+    static int roundWeedCounted(final char[] buffer,
+                                final int length,
+                                final long rest,
+                                final long  ten_kappa,
+                                final long  unit) {
+        assert(Long.compareUnsigned(rest, ten_kappa) < 0);
+        // The following tests are done in a specific order to avoid overflows. They
+        // will work correctly with any uint64 values of rest < ten_kappa and unit.
+        //
+        // If the unit is too big, then we don't know which way to round. For example
+        // a unit of 50 means that the real number lies within rest +/- 50. If
+        // 10^kappa == 40 then there is no way to tell which way to round.
+        if (Long.compareUnsigned(unit, ten_kappa) >= 0) return 0;
+        // Even if unit is just half the size of 10^kappa we are already completely
+        // lost. (And after the previous test we know that the expression will not
+        // over/underflow.)
+        if (Long.compareUnsigned(ten_kappa - unit, unit) <= 0) return 0;
+        // If 2 * (rest + unit) <= 10^kappa we can safely round down.
+        if (Long.compareUnsigned(ten_kappa - rest, rest) > 0 && Long.compareUnsigned(ten_kappa - 2 * rest, 2 * unit) >= 0) {
+            return 1;
+        }
+        // If 2 * (rest - unit) >= 10^kappa, then we can safely round up.
+        if (Long.compareUnsigned(rest, unit) > 0 && Long.compareUnsigned(ten_kappa - (rest - unit), (rest - unit)) <= 0) {
+            // Increment the last digit recursively until we find a non '9' digit.
+            buffer[length - 1]++;
+            for (int i = length - 1; i > 0; --i) {
+                if (buffer[i] != '0' + 10) break;
+                buffer[i] = '0';
+                buffer[i - 1]++;
+            }
+            // If the first digit is now '0'+ 10 we had a buffer with all '9's. With the
+            // exception of the first digit all digits are now '0'. Simply switch the
+            // first digit to '1' and adjust the kappa. Example: "99" becomes "10" and
+            // the power (the kappa) is increased.
+            if (buffer[0] == '0' + 10) {
+                buffer[0] = '1';
+                // Return value of 2 tells caller to increase (*kappa) += 1
+                return 2;
+            }
+            return 1;
+        }
+        return 0;
+    }
+
+    // Returns the biggest power of ten that is less than or equal to the given
+    // number. We furthermore receive the maximum number of bits 'number' has.
+    //
+    // Returns power == 10^(exponent_plus_one-1) such that
+    //    power <= number < power * 10.
+    // If number_bits == 0 then 0^(0-1) is returned.
+    // The number of bits must be <= 32.
+    // Precondition: number < (1 << (number_bits + 1)).
+
+    // Inspired by the method for finding an integer log base 10 from here:
+    // http://graphics.stanford.edu/~seander/bithacks.html#IntegerLog10
+    static final int kSmallPowersOfTen[] =
+    {0, 1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000,
+            1000000000};
+
+    // Returns the biggest power of ten that is less than or equal than the given
+    // number. We furthermore receive the maximum number of bits 'number' has.
+    // If number_bits == 0 then 0^-1 is returned
+    // The number of bits must be <= 32.
+    // Precondition: (1 << number_bits) <= number < (1 << (number_bits + 1)).
+    static long biggestPowerTen(final int number,
+                                final int number_bits) {
+        final int power, exponent_plus_one;
+        assert ((number & 0xFFFFFFFFL) < (1l << (number_bits + 1)));
+        // 1233/4096 is approximately 1/lg(10).
+        int exponent_plus_one_guess = ((number_bits + 1) * 1233 >>> 12);
+        // We increment to skip over the first entry in the kPowersOf10 table.
+        // Note: kPowersOf10[i] == 10^(i-1).
+        exponent_plus_one_guess++;
+        // We don't have any guarantees that 2^number_bits <= number.
+        if (number < kSmallPowersOfTen[exponent_plus_one_guess]) {
+            exponent_plus_one_guess--;
+        }
+        power = kSmallPowersOfTen[exponent_plus_one_guess];
+        exponent_plus_one = exponent_plus_one_guess;
+
+        return ((long) power << 32) | (long) exponent_plus_one;
+    }
+
+    // Generates the digits of input number w.
+    // w is a floating-point number (DiyFp), consisting of a significand and an
+    // exponent. Its exponent is bounded by kMinimalTargetExponent and
+    // kMaximalTargetExponent.
+    //       Hence -60 <= w.e() <= -32.
+    //
+    // Returns false if it fails, in which case the generated digits in the buffer
+    // should not be used.
+    // Preconditions:
+    //  * low, w and high are correct up to 1 ulp (unit in the last place). That
+    //    is, their error must be less than a unit of their last digits.
+    //  * low.e() == w.e() == high.e()
+    //  * low < w < high, and taking into account their error: low~ <= high~
+    //  * kMinimalTargetExponent <= w.e() <= kMaximalTargetExponent
+    // Postconditions: returns false if procedure fails.
+    //   otherwise:
+    //     * buffer is not null-terminated, but len contains the number of digits.
+    //     * buffer contains the shortest possible decimal digit-sequence
+    //       such that LOW < buffer * 10^kappa < HIGH, where LOW and HIGH are the
+    //       correct values of low and high (without their error).
+    //     * if more than one decimal representation gives the minimal number of
+    //       decimal digits then the one closest to W (where W is the correct value
+    //       of w) is chosen.
+    // Remark: this procedure takes into account the imprecision of its input
+    //   numbers. If the precision is not enough to guarantee all the postconditions
+    //   then false is returned. This usually happens rarely (~0.5%).
+    //
+    // Say, for the sake of example, that
+    //   w.e() == -48, and w.f() == 0x1234567890abcdef
+    // w's value can be computed by w.f() * 2^w.e()
+    // We can obtain w's integral digits by simply shifting w.f() by -w.e().
+    //  -> w's integral part is 0x1234
+    //  w's fractional part is therefore 0x567890abcdef.
+    // Printing w's integral part is easy (simply print 0x1234 in decimal).
+    // In order to print its fraction we repeatedly multiply the fraction by 10 and
+    // get each digit. Example the first digit after the point would be computed by
+    //   (0x567890abcdef * 10) >> 48. -> 3
+    // The whole thing becomes slightly more complicated because we want to stop
+    // once we have enough digits. That is, once the digits inside the buffer
+    // represent 'w' we can stop. Everything inside the interval low - high
+    // represents w. However we have to pay attention to low, high and w's
+    // imprecision.
+    static boolean digitGen(final DiyFp low,
+                            final DiyFp w,
+                            final DiyFp high,
+                            final DtoaBuffer buffer,
+                            final int mk) {
+        assert(low.e() == w.e() && w.e() == high.e());
+        assert Long.compareUnsigned(low.f() + 1, high.f() - 1) <= 0;
+        assert(kMinimalTargetExponent <= w.e() && w.e() <= kMaximalTargetExponent);
+        // low, w and high are imprecise, but by less than one ulp (unit in the last
+        // place).
+        // If we remove (resp. add) 1 ulp from low (resp. high) we are certain that
+        // the new numbers are outside of the interval we want the final
+        // representation to lie in.
+        // Inversely adding (resp. removing) 1 ulp from low (resp. high) would yield
+        // numbers that are certain to lie in the interval. We will use this fact
+        // later on.
+        // We will now start by generating the digits within the uncertain
+        // interval. Later we will weed out representations that lie outside the safe
+        // interval and thus _might_ lie outside the correct interval.
+        long unit = 1;
+        final DiyFp too_low = new DiyFp(low.f() - unit, low.e());
+        final DiyFp too_high = new DiyFp(high.f() + unit, high.e());
+        // too_low and too_high are guaranteed to lie outside the interval we want the
+        // generated number in.
+        final DiyFp unsafe_interval = DiyFp.minus(too_high, too_low);
+        // We now cut the input number into two parts: the integral digits and the
+        // fractionals. We will not write any decimal separator though, but adapt
+        // kappa instead.
+        // Reminder: we are currently computing the digits (stored inside the buffer)
+        // such that:   too_low < buffer * 10^kappa < too_high
+        // We use too_high for the digit_generation and stop as soon as possible.
+        // If we stop early we effectively round down.
+        final DiyFp one = new DiyFp(1l << -w.e(), w.e());
+        // Division by one is a shift.
+        int integrals = (int)(too_high.f() >>> -one.e());
+        // Modulo by one is an and.
+        long fractionals = too_high.f() & (one.f() - 1);
+        int divisor;
+        final int divisor_exponent_plus_one;
+        final long result = biggestPowerTen(integrals, DiyFp.kSignificandSize - (-one.e()));
+        divisor = (int) (result >>> 32);
+        divisor_exponent_plus_one = (int) result;
+        int kappa = divisor_exponent_plus_one;
+        // Loop invariant: buffer = too_high / 10^kappa  (integer division)
+        // The invariant holds for the first iteration: kappa has been initialized
+        // with the divisor exponent + 1. And the divisor is the biggest power of ten
+        // that is smaller than integrals.
+        while (kappa > 0) {
+            final int digit = integrals / divisor;
+            assert (digit <= 9);
+            buffer.append((char) ('0' + digit));
+            integrals %= divisor;
+            kappa--;
+            // Note that kappa now equals the exponent of the divisor and that the
+            // invariant thus holds again.
+            final long rest =
+                    ((long) integrals << -one.e()) + fractionals;
+            // Invariant: too_high = buffer * 10^kappa + DiyFp(rest, one.e())
+            // Reminder: unsafe_interval.e() == one.e()
+            if (Long.compareUnsigned(rest, unsafe_interval.f()) < 0) {
+                // Rounding down (by not emitting the remaining digits) yields a number
+                // that lies within the unsafe interval.
+                buffer.decimalPoint = buffer.length - mk + kappa;
+                return roundWeed(buffer, DiyFp.minus(too_high, w).f(),
+                        unsafe_interval.f(), rest,
+                        (long) divisor << -one.e(), unit);
+            }
+            divisor /= 10;
+        }
+
+        // The integrals have been generated. We are at the point of the decimal
+        // separator. In the following loop we simply multiply the remaining digits by
+        // 10 and divide by one. We just need to pay attention to multiply associated
+        // data (like the interval or 'unit'), too.
+        // Note that the multiplication by 10 does not overflow, because w.e >= -60
+        // and thus one.e >= -60.
+        assert (one.e() >= -60);
+        assert (fractionals < one.f());
+        assert (Long.compareUnsigned(Long.divideUnsigned(0xFFFFFFFFFFFFFFFFL, 10), one.f()) >= 0);
+        for (;;) {
+            fractionals *= 10;
+            unit *= 10;
+            unsafe_interval.setF(unsafe_interval.f() * 10);
+            // Integer division by one.
+            final int digit = (int) (fractionals >>> -one.e());
+            assert (digit <= 9);
+            buffer.append((char) ('0' + digit));
+            fractionals &= one.f() - 1;  // Modulo by one.
+            kappa--;
+            if (Long.compareUnsigned(fractionals, unsafe_interval.f()) < 0) {
+                buffer.decimalPoint = buffer.length - mk + kappa;
+                return roundWeed(buffer, DiyFp.minus(too_high, w).f() * unit,
+                        unsafe_interval.f(), fractionals, one.f(), unit);
+            }
+        }
+    }
+
+    // Generates (at most) requested_digits digits of input number w.
+    // w is a floating-point number (DiyFp), consisting of a significand and an
+    // exponent. Its exponent is bounded by kMinimalTargetExponent and
+    // kMaximalTargetExponent.
+    //       Hence -60 <= w.e() <= -32.
+    //
+    // Returns false if it fails, in which case the generated digits in the buffer
+    // should not be used.
+    // Preconditions:
+    //  * w is correct up to 1 ulp (unit in the last place). That
+    //    is, its error must be strictly less than a unit of its last digit.
+    //  * kMinimalTargetExponent <= w.e() <= kMaximalTargetExponent
+    //
+    // Postconditions: returns false if procedure fails.
+    //   otherwise:
+    //     * buffer is not null-terminated, but length contains the number of
+    //       digits.
+    //     * the representation in buffer is the most precise representation of
+    //       requested_digits digits.
+    //     * buffer contains at most requested_digits digits of w. If there are less
+    //       than requested_digits digits then some trailing '0's have been removed.
+    //     * kappa is such that
+    //            w = buffer * 10^kappa + eps with |eps| < 10^kappa / 2.
+    //
+    // Remark: This procedure takes into account the imprecision of its input
+    //   numbers. If the precision is not enough to guarantee all the postconditions
+    //   then false is returned. This usually happens rarely, but the failure-rate
+    //   increases with higher requested_digits.
+    static boolean digitGenCounted(final DiyFp w,
+                                   int requested_digits,
+                                   final DtoaBuffer buffer,
+                                   final int mk) {
+        assert (kMinimalTargetExponent <= w.e() && w.e() <= kMaximalTargetExponent);
+        assert (kMinimalTargetExponent >= -60);
+        assert (kMaximalTargetExponent <= -32);
+        // w is assumed to have an error less than 1 unit. Whenever w is scaled we
+        // also scale its error.
+        long w_error = 1;
+        // We cut the input number into two parts: the integral digits and the
+        // fractional digits. We don't emit any decimal separator, but adapt kappa
+        // instead. Example: instead of writing "1.2" we put "12" into the buffer and
+        // increase kappa by 1.
+        final DiyFp one = new DiyFp(1l << -w.e(), w.e());
+        // Division by one is a shift.
+        int integrals = (int) (w.f() >>> -one.e());
+        // Modulo by one is an and.
+        long fractionals = w.f() & (one.f() - 1);
+        int divisor;
+        final int divisor_exponent_plus_one;
+        final long biggestPower = biggestPowerTen(integrals, DiyFp.kSignificandSize - (-one.e()));
+        divisor = (int) (biggestPower >>> 32);
+        divisor_exponent_plus_one = (int) biggestPower;
+        int kappa = divisor_exponent_plus_one;
+
+        // Loop invariant: buffer = w / 10^kappa  (integer division)
+        // The invariant holds for the first iteration: kappa has been initialized
+        // with the divisor exponent + 1. And the divisor is the biggest power of ten
+        // that is smaller than 'integrals'.
+        while (kappa > 0) {
+            final int digit = integrals / divisor;
+            assert (digit <= 9);
+            buffer.append((char) ('0' + digit));
+            requested_digits--;
+            integrals %= divisor;
+            kappa--;
+            // Note that kappa now equals the exponent of the divisor and that the
+            // invariant thus holds again.
+            if (requested_digits == 0) break;
+            divisor /= 10;
+        }
+
+        if (requested_digits == 0) {
+            final long rest =
+                    ((long) (integrals) << -one.e()) + fractionals;
+            final int result = roundWeedCounted(buffer.chars, buffer.length, rest,
+                    (long) divisor << -one.e(), w_error);
+            buffer.decimalPoint = buffer.length - mk + kappa + (result == 2 ? 1 : 0);
+            return result > 0;
+        }
+
+        // The integrals have been generated. We are at the decimalPoint of the decimal
+        // separator. In the following loop we simply multiply the remaining digits by
+        // 10 and divide by one. We just need to pay attention to multiply associated
+        // data (the 'unit'), too.
+        // Note that the multiplication by 10 does not overflow, because w.e >= -60
+        // and thus one.e >= -60.
+        assert (one.e() >= -60);
+        assert (fractionals < one.f());
+        assert (Long.compareUnsigned(Long.divideUnsigned(0xFFFFFFFFFFFFFFFFL, 10), one.f()) >= 0);
+        while (requested_digits > 0 && fractionals > w_error) {
+            fractionals *= 10;
+            w_error *= 10;
+            // Integer division by one.
+            final int digit = (int) (fractionals >>> -one.e());
+            assert (digit <= 9);
+            buffer.append((char) ('0' + digit));
+            requested_digits--;
+            fractionals &= one.f() - 1;  // Modulo by one.
+            kappa--;
+        }
+        if (requested_digits != 0) return false;
+        final int result = roundWeedCounted(buffer.chars, buffer.length, fractionals, one.f(), w_error);
+        buffer.decimalPoint = buffer.length - mk + kappa + (result == 2 ? 1 : 0);
+        return result > 0;
+    }
+
+
+    // Provides a decimal representation of v.
+    // Returns true if it succeeds, otherwise the result cannot be trusted.
+    // There will be *length digits inside the buffer (not null-terminated).
+    // If the function returns true then
+    //        v == (double) (buffer * 10^decimal_exponent).
+    // The digits in the buffer are the shortest representation possible: no
+    // 0.09999999999999999 instead of 0.1. The shorter representation will even be
+    // chosen even if the longer one would be closer to v.
+    // The last digit will be closest to the actual v. That is, even if several
+    // digits might correctly yield 'v' when read again, the closest will be
+    // computed.
+    static boolean grisu3(final double v, final DtoaBuffer buffer) {
+        final long d64 = IeeeDouble.doubleToLong(v);
+        final DiyFp w = IeeeDouble.asNormalizedDiyFp(d64);
+        // boundary_minus and boundary_plus are the boundaries between v and its
+        // closest floating-point neighbors. Any number strictly between
+        // boundary_minus and boundary_plus will round to v when convert to a double.
+        // Grisu3 will never output representations that lie exactly on a boundary.
+        final DiyFp boundary_minus = new DiyFp(), boundary_plus = new DiyFp();
+        IeeeDouble.normalizedBoundaries(d64, boundary_minus, boundary_plus);
+        assert(boundary_plus.e() == w.e());
+        final DiyFp ten_mk = new DiyFp();  // Cached power of ten: 10^-k
+        final int mk;                      // -k
+        final int ten_mk_minimal_binary_exponent =
+                kMinimalTargetExponent - (w.e() + DiyFp.kSignificandSize);
+        final int ten_mk_maximal_binary_exponent =
+                kMaximalTargetExponent - (w.e() + DiyFp.kSignificandSize);
+        mk = CachedPowers.getCachedPowerForBinaryExponentRange(
+                ten_mk_minimal_binary_exponent,
+                ten_mk_maximal_binary_exponent,
+           ten_mk);
+        assert(kMinimalTargetExponent <= w.e() + ten_mk.e() +
+                DiyFp.kSignificandSize &&
+                kMaximalTargetExponent >= w.e() + ten_mk.e() +
+                        DiyFp.kSignificandSize);
+        // Note that ten_mk is only an approximation of 10^-k. A DiyFp only contains a
+        // 64 bit significand and ten_mk is thus only precise up to 64 bits.
+
+        // The DiyFp::Times procedure rounds its result, and ten_mk is approximated
+        // too. The variable scaled_w (as well as scaled_boundary_minus/plus) are now
+        // off by a small amount.
+        // In fact: scaled_w - w*10^k < 1ulp (unit in the last place) of scaled_w.
+        // In other words: let f = scaled_w.f() and e = scaled_w.e(), then
+        //           (f-1) * 2^e < w*10^k < (f+1) * 2^e
+        final DiyFp scaled_w = DiyFp.times(w, ten_mk);
+        assert(scaled_w.e() ==
+                boundary_plus.e() + ten_mk.e() + DiyFp.kSignificandSize);
+        // In theory it would be possible to avoid some recomputations by computing
+        // the difference between w and boundary_minus/plus (a power of 2) and to
+        // compute scaled_boundary_minus/plus by subtracting/adding from
+        // scaled_w. However the code becomes much less readable and the speed
+        // enhancements are not terriffic.
+        final DiyFp scaled_boundary_minus = DiyFp.times(boundary_minus, ten_mk);
+        final DiyFp scaled_boundary_plus  = DiyFp.times(boundary_plus,  ten_mk);
+
+        // DigitGen will generate the digits of scaled_w. Therefore we have
+        // v == (double) (scaled_w * 10^-mk).
+        // Set decimal_exponent == -mk and pass it to DigitGen. If scaled_w is not an
+        // integer than it will be updated. For instance if scaled_w == 1.23 then
+        // the buffer will be filled with "123" und the decimal_exponent will be
+        // decreased by 2.
+        final boolean result = digitGen(scaled_boundary_minus, scaled_w, scaled_boundary_plus,
+                buffer, mk);
+        return result;
+    }
+
+    // The "counted" version of grisu3 (see above) only generates requested_digits
+    // number of digits. This version does not generate the shortest representation,
+    // and with enough requested digits 0.1 will at some point print as 0.9999999...
+    // Grisu3 is too imprecise for real halfway cases (1.5 will not work) and
+    // therefore the rounding strategy for halfway cases is irrelevant.
+    static boolean grisu3Counted(final double v,
+                                 final int requested_digits,
+                                 final DtoaBuffer buffer) {
+        final long d64 = IeeeDouble.doubleToLong(v);
+        final DiyFp w = IeeeDouble.asNormalizedDiyFp(d64);
+        final DiyFp ten_mk = new DiyFp();  // Cached power of ten: 10^-k
+        final int mk;                      // -k
+        final int ten_mk_minimal_binary_exponent =
+                kMinimalTargetExponent - (w.e() + DiyFp.kSignificandSize);
+        final int ten_mk_maximal_binary_exponent =
+                kMaximalTargetExponent - (w.e() + DiyFp.kSignificandSize);
+        mk = CachedPowers.getCachedPowerForBinaryExponentRange(
+                ten_mk_minimal_binary_exponent,
+                ten_mk_maximal_binary_exponent,
+                ten_mk);
+        assert ((kMinimalTargetExponent <= w.e() + ten_mk.e() +
+                DiyFp.kSignificandSize) &&
+                (kMaximalTargetExponent >= w.e() + ten_mk.e() +
+                        DiyFp.kSignificandSize));
+        // Note that ten_mk is only an approximation of 10^-k. A DiyFp only contains a
+        // 64 bit significand and ten_mk is thus only precise up to 64 bits.
+
+        // The DiyFp::Times procedure rounds its result, and ten_mk is approximated
+        // too. The variable scaled_w (as well as scaled_boundary_minus/plus) are now
+        // off by a small amount.
+        // In fact: scaled_w - w*10^k < 1ulp (unit in the last place) of scaled_w.
+        // In other words: let f = scaled_w.f() and e = scaled_w.e(), then
+        //           (f-1) * 2^e < w*10^k < (f+1) * 2^e
+        final DiyFp scaled_w = DiyFp.times(w, ten_mk);
+
+        // We now have (double) (scaled_w * 10^-mk).
+        // DigitGen will generate the first requested_digits digits of scaled_w and
+        // return together with a kappa such that scaled_w ~= buffer * 10^kappa. (It
+        // will not always be exactly the same since DigitGenCounted only produces a
+        // limited number of digits.)
+        final boolean result = digitGenCounted(scaled_w, requested_digits,
+                buffer, mk);
+        return result;
+    }
+
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/doubleconv/FixedDtoa.java	Thu Nov 26 01:06:51 2015 +0100
@@ -0,0 +1,425 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  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.
+ */
+
+// This file is available under and governed by the GNU General Public
+// License version 2 only, as published by the Free Software Foundation.
+// However, the following notice accompanied the original version of this
+// file:
+//
+// Copyright 2010 the V8 project authors. 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 Google Inc. 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.
+
+package jdk.nashorn.internal.runtime.doubleconv;
+
+class FixedDtoa {
+
+    // Represents a 128bit type. This class should be replaced by a native type on
+    // platforms that support 128bit integers.
+    static class UInt128 {
+
+        private static final long kMask32 = 0xFFFFFFFFL;
+        // Value == (high_bits_ << 64) + low_bits_
+        private long high_bits_;
+        private long low_bits_;
+
+        UInt128(final long high_bits, final long low_bits) {
+            this.high_bits_ = high_bits;
+            this.low_bits_ = low_bits;
+        }
+
+        void multiply(final int multiplicand) {
+            long accumulator;
+
+            accumulator = (low_bits_ & kMask32) * multiplicand;
+            long part = accumulator & kMask32;
+            accumulator >>>= 32;
+            accumulator = accumulator + (low_bits_ >>> 32) * multiplicand;
+            low_bits_ = (accumulator << 32) + part;
+            accumulator >>>= 32;
+            accumulator = accumulator + (high_bits_ & kMask32) * multiplicand;
+            part = accumulator & kMask32;
+            accumulator >>>= 32;
+            accumulator = accumulator + (high_bits_ >>> 32) * multiplicand;
+            high_bits_ = (accumulator << 32) + part;
+            assert ((accumulator >>> 32) == 0);
+        }
+
+        void shift(final int shift_amount) {
+            assert (-64 <= shift_amount && shift_amount <= 64);
+            if (shift_amount == 0) {
+                return;
+            } else if (shift_amount == -64) {
+                high_bits_ = low_bits_;
+                low_bits_ = 0;
+            } else if (shift_amount == 64) {
+                low_bits_ = high_bits_;
+                high_bits_ = 0;
+            } else if (shift_amount <= 0) {
+                high_bits_ <<= -shift_amount;
+                high_bits_ += low_bits_ >>> (64 + shift_amount);
+                low_bits_ <<= -shift_amount;
+            } else {
+                low_bits_ >>>= shift_amount;
+                low_bits_ += high_bits_ << (64 - shift_amount);
+                high_bits_ >>>= shift_amount;
+            }
+        }
+
+        // Modifies *this to *this MOD (2^power).
+        // Returns *this DIV (2^power).
+        int divModPowerOf2(final int power) {
+            if (power >= 64) {
+                final int result = (int) (high_bits_ >>> (power - 64));
+                high_bits_ -= (long) (result) << (power - 64);
+                return result;
+            } else {
+                final long part_low = low_bits_ >>> power;
+                final long part_high = high_bits_ << (64 - power);
+                final int result = (int) (part_low + part_high);
+                high_bits_ = 0;
+                low_bits_ -= part_low << power;
+                return result;
+            }
+        }
+
+        boolean isZero() {
+            return high_bits_ == 0 && low_bits_ == 0;
+        }
+
+        int bitAt(final int position) {
+            if (position >= 64) {
+                return (int) (high_bits_ >>> (position - 64)) & 1;
+            } else {
+                return (int) (low_bits_ >>> position) & 1;
+            }
+        }
+
+    };
+
+
+    static final  int kDoubleSignificandSize = 53;  // Includes the hidden bit.
+
+
+    static void fillDigits32FixedLength(int number, final int requested_length,
+                                        final DtoaBuffer buffer) {
+        for (int i = requested_length - 1; i >= 0; --i) {
+            buffer.chars[buffer.length + i] = (char) ('0' + Integer.remainderUnsigned(number, 10));
+            number = Integer.divideUnsigned(number, 10);
+        }
+        buffer.length += requested_length;
+    }
+
+
+    static void fillDigits32(int number, final DtoaBuffer buffer) {
+        int number_length = 0;
+        // We fill the digits in reverse order and exchange them afterwards.
+        while (number != 0) {
+            final int digit = Integer.remainderUnsigned(number, 10);
+            number = Integer.divideUnsigned(number, 10);
+            buffer.chars[buffer.length + number_length] = (char) ('0' + digit);
+            number_length++;
+        }
+        // Exchange the digits.
+        int i = buffer.length;
+        int j = buffer.length + number_length - 1;
+        while (i < j) {
+            final char tmp = buffer.chars[i];
+            buffer.chars[i] = buffer.chars[j];
+            buffer.chars[j] = tmp;
+            i++;
+            j--;
+        }
+        buffer.length += number_length;
+    }
+
+
+    static void fillDigits64FixedLength(long number, final DtoaBuffer buffer) {
+        final int kTen7 = 10000000;
+        // For efficiency cut the number into 3 uint32_t parts, and print those.
+        final int part2 = (int) Long.remainderUnsigned(number, kTen7);
+        number = Long.divideUnsigned(number, kTen7);
+        final int part1 = (int) Long.remainderUnsigned(number, kTen7);
+        final int part0 = (int) Long.divideUnsigned(number, kTen7);
+
+        fillDigits32FixedLength(part0, 3, buffer);
+        fillDigits32FixedLength(part1, 7, buffer);
+        fillDigits32FixedLength(part2, 7, buffer);
+    }
+
+
+    static void FillDigits64(long number, final DtoaBuffer buffer) {
+        final int kTen7 = 10000000;
+        // For efficiency cut the number into 3 uint32_t parts, and print those.
+        final int part2 = (int) Long.remainderUnsigned(number, kTen7);
+        number = Long.divideUnsigned(number, kTen7);
+        final int part1 = (int) Long.remainderUnsigned(number, kTen7);
+        final int part0 = (int) Long.divideUnsigned(number, kTen7);
+
+        if (part0 != 0) {
+            fillDigits32(part0, buffer);
+            fillDigits32FixedLength(part1, 7, buffer);
+            fillDigits32FixedLength(part2, 7, buffer);
+        } else if (part1 != 0) {
+            fillDigits32(part1, buffer);
+            fillDigits32FixedLength(part2, 7, buffer);
+        } else {
+            fillDigits32(part2, buffer);
+        }
+    }
+
+
+    static void roundUp(final DtoaBuffer buffer) {
+        // An empty buffer represents 0.
+        if (buffer.length == 0) {
+            buffer.chars[0] = '1';
+            buffer.decimalPoint = 1;
+            buffer.length = 1;
+            return;
+        }
+        // Round the last digit until we either have a digit that was not '9' or until
+        // we reached the first digit.
+        buffer.chars[buffer.length - 1]++;
+        for (int i = buffer.length - 1; i > 0; --i) {
+            if (buffer.chars[i] != '0' + 10) {
+                return;
+            }
+            buffer.chars[i] = '0';
+            buffer.chars[i - 1]++;
+        }
+        // If the first digit is now '0' + 10, we would need to set it to '0' and add
+        // a '1' in front. However we reach the first digit only if all following
+        // digits had been '9' before rounding up. Now all trailing digits are '0' and
+        // we simply switch the first digit to '1' and update the decimal-point
+        // (indicating that the point is now one digit to the right).
+        if (buffer.chars[0] == '0' + 10) {
+            buffer.chars[0] = '1';
+            buffer.decimalPoint++;
+        }
+    }
+
+
+    // The given fractionals number represents a fixed-point number with binary
+    // point at bit (-exponent).
+    // Preconditions:
+    //   -128 <= exponent <= 0.
+    //   0 <= fractionals * 2^exponent < 1
+    //   The buffer holds the result.
+    // The function will round its result. During the rounding-process digits not
+    // generated by this function might be updated, and the decimal-point variable
+    // might be updated. If this function generates the digits 99 and the buffer
+    // already contained "199" (thus yielding a buffer of "19999") then a
+    // rounding-up will change the contents of the buffer to "20000".
+    static void fillFractionals(long fractionals, final int exponent,
+                                final int fractional_count, final DtoaBuffer buffer) {
+        assert (-128 <= exponent && exponent <= 0);
+        // 'fractionals' is a fixed-decimalPoint number, with binary decimalPoint at bit
+        // (-exponent). Inside the function the non-converted remainder of fractionals
+        // is a fixed-decimalPoint number, with binary decimalPoint at bit 'decimalPoint'.
+        if (-exponent <= 64) {
+            // One 64 bit number is sufficient.
+            assert (fractionals >>> 56 == 0);
+            int point = -exponent;
+            for (int i = 0; i < fractional_count; ++i) {
+                if (fractionals == 0) break;
+                // Instead of multiplying by 10 we multiply by 5 and adjust the point
+                // location. This way the fractionals variable will not overflow.
+                // Invariant at the beginning of the loop: fractionals < 2^point.
+                // Initially we have: point <= 64 and fractionals < 2^56
+                // After each iteration the point is decremented by one.
+                // Note that 5^3 = 125 < 128 = 2^7.
+                // Therefore three iterations of this loop will not overflow fractionals
+                // (even without the subtraction at the end of the loop body). At this
+                // time point will satisfy point <= 61 and therefore fractionals < 2^point
+                // and any further multiplication of fractionals by 5 will not overflow.
+                fractionals *= 5;
+                point--;
+                final int digit = (int) (fractionals >>> point);
+                assert (digit <= 9);
+                buffer.chars[buffer.length] = (char) ('0' + digit);
+                buffer.length++;
+                fractionals -= (long) (digit) << point;
+            }
+            // If the first bit after the point is set we have to round up.
+            if (((fractionals >>> (point - 1)) & 1) == 1) {
+                roundUp(buffer);
+            }
+        } else {  // We need 128 bits.
+            assert (64 < -exponent && -exponent <= 128);
+            final UInt128 fractionals128 = new UInt128(fractionals, 0);
+            fractionals128.shift(-exponent - 64);
+            int point = 128;
+            for (int i = 0; i < fractional_count; ++i) {
+                if (fractionals128.isZero()) break;
+                // As before: instead of multiplying by 10 we multiply by 5 and adjust the
+                // point location.
+                // This multiplication will not overflow for the same reasons as before.
+                fractionals128.multiply(5);
+                point--;
+                final int digit = fractionals128.divModPowerOf2(point);
+                assert (digit <= 9);
+                buffer.chars[buffer.length] = (char) ('0' + digit);
+                buffer.length++;
+            }
+            if (fractionals128.bitAt(point - 1) == 1) {
+                roundUp(buffer);
+            }
+        }
+    }
+
+
+    // Removes leading and trailing zeros.
+    // If leading zeros are removed then the decimal point position is adjusted.
+    static void trimZeros(final DtoaBuffer buffer) {
+        while (buffer.length > 0 && buffer.chars[buffer.length - 1] == '0') {
+            buffer.length--;
+        }
+        int first_non_zero = 0;
+        while (first_non_zero < buffer.length && buffer.chars[first_non_zero] == '0') {
+            first_non_zero++;
+        }
+        if (first_non_zero != 0) {
+            for (int i = first_non_zero; i < buffer.length; ++i) {
+                buffer.chars[i - first_non_zero] = buffer.chars[i];
+            }
+            buffer.length -= first_non_zero;
+            buffer.decimalPoint -= first_non_zero;
+        }
+    }
+
+
+    static boolean fastFixedDtoa(final double v,
+                                 final int fractional_count,
+                                 final DtoaBuffer buffer) {
+        final long kMaxUInt32 = 0xFFFFFFFFL;
+        final long l = IeeeDouble.doubleToLong(v);
+        long significand = IeeeDouble.significand(l);
+        final int exponent = IeeeDouble.exponent(l);
+        // v = significand * 2^exponent (with significand a 53bit integer).
+        // If the exponent is larger than 20 (i.e. we may have a 73bit number) then we
+        // don't know how to compute the representation. 2^73 ~= 9.5*10^21.
+        // If necessary this limit could probably be increased, but we don't need
+        // more.
+        if (exponent > 20) return false;
+        if (fractional_count > 20) return false;
+        // At most kDoubleSignificandSize bits of the significand are non-zero.
+        // Given a 64 bit integer we have 11 0s followed by 53 potentially non-zero
+        // bits:  0..11*..0xxx..53*..xx
+        if (exponent + kDoubleSignificandSize > 64) {
+            // The exponent must be > 11.
+            //
+            // We know that v = significand * 2^exponent.
+            // And the exponent > 11.
+            // We simplify the task by dividing v by 10^17.
+            // The quotient delivers the first digits, and the remainder fits into a 64
+            // bit number.
+            // Dividing by 10^17 is equivalent to dividing by 5^17*2^17.
+            final long kFive17 = 0xB1A2BC2EC5L;  // 5^17
+            long divisor = kFive17;
+            final int divisor_power = 17;
+            long dividend = significand;
+            final int quotient;
+            final long remainder;
+            // Let v = f * 2^e with f == significand and e == exponent.
+            // Then need q (quotient) and r (remainder) as follows:
+            //   v            = q * 10^17       + r
+            //   f * 2^e      = q * 10^17       + r
+            //   f * 2^e      = q * 5^17 * 2^17 + r
+            // If e > 17 then
+            //   f * 2^(e-17) = q * 5^17        + r/2^17
+            // else
+            //   f  = q * 5^17 * 2^(17-e) + r/2^e
+            if (exponent > divisor_power) {
+                // We only allow exponents of up to 20 and therefore (17 - e) <= 3
+                dividend <<= exponent - divisor_power;
+                quotient = (int) Long.divideUnsigned(dividend, divisor);
+                remainder = Long.remainderUnsigned(dividend, divisor) << divisor_power;
+            } else {
+                divisor <<= divisor_power - exponent;
+                quotient = (int) Long.divideUnsigned(dividend, divisor);
+                remainder = Long.remainderUnsigned(dividend, divisor) << exponent;
+            }
+            fillDigits32(quotient, buffer);
+            fillDigits64FixedLength(remainder, buffer);
+            buffer.decimalPoint = buffer.length;
+        } else if (exponent >= 0) {
+            // 0 <= exponent <= 11
+            significand <<= exponent;
+            FillDigits64(significand, buffer);
+            buffer.decimalPoint = buffer.length;
+        } else if (exponent > -kDoubleSignificandSize) {
+            // We have to cut the number.
+            final long integrals = significand >>> -exponent;
+            final long fractionals = significand - (integrals << -exponent);
+            if (Long.compareUnsigned(integrals, kMaxUInt32) > 0) {
+                FillDigits64(integrals, buffer);
+            } else {
+                fillDigits32((int) (integrals), buffer);
+            }
+            buffer.decimalPoint = buffer.length;
+            fillFractionals(fractionals, exponent, fractional_count, buffer);
+        } else if (exponent < -128) {
+            // This configuration (with at most 20 digits) means that all digits must be
+            // 0.
+            assert (fractional_count <= 20);
+            buffer.reset();
+            buffer.decimalPoint = -fractional_count;
+        } else {
+            buffer.decimalPoint = 0;
+            fillFractionals(significand, exponent, fractional_count, buffer);
+        }
+        trimZeros(buffer);
+        if (buffer.length == 0) {
+            // The string is empty and the decimal_point thus has no importance. Mimick
+            // Gay's dtoa and and set it to -fractional_count.
+            buffer.decimalPoint = -fractional_count;
+        }
+        return true;
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/doubleconv/IeeeDouble.java	Thu Nov 26 01:06:51 2015 +0100
@@ -0,0 +1,233 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  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.
+ */
+
+// This file is available under and governed by the GNU General Public
+// License version 2 only, as published by the Free Software Foundation.
+// However, the following notice accompanied the original version of this
+// file:
+//
+// Copyright 2010 the V8 project authors. 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 Google Inc. 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.
+
+package jdk.nashorn.internal.runtime.doubleconv;
+
+// Helper functions for doubles.
+class IeeeDouble {
+
+    // We assume that doubles and long have the same endianness.
+    static long doubleToLong(final double d)   { return Double.doubleToRawLongBits(d); }
+    static double longToDouble(final long d64) { return Double.longBitsToDouble(d64); }
+
+    static final long kSignMask = 0x8000000000000000L;
+    static final long kExponentMask = 0x7FF0000000000000L;
+    static final long kSignificandMask = 0x000FFFFFFFFFFFFFL;
+    static final long kHiddenBit = 0x0010000000000000L;
+    static final int kPhysicalSignificandSize = 52;  // Excludes the hidden bit.
+    static final int kSignificandSize = 53;
+
+    static private final int kExponentBias = 0x3FF + kPhysicalSignificandSize;
+    static private final int kDenormalExponent = -kExponentBias + 1;
+    static private final int kMaxExponent = 0x7FF - kExponentBias;
+    static private final long kInfinity = 0x7FF0000000000000L;
+    static private final long kNaN = 0x7FF8000000000000L;
+
+    static DiyFp asDiyFp(final long d64) {
+        assert (!isSpecial(d64));
+        return new DiyFp(significand(d64), exponent(d64));
+    }
+
+    // The value encoded by this Double must be strictly greater than 0.
+    static DiyFp asNormalizedDiyFp(final long d64) {
+        assert (value(d64) > 0.0);
+        long f = significand(d64);
+        int e = exponent(d64);
+
+        // The current double could be a denormal.
+        while ((f & kHiddenBit) == 0) {
+            f <<= 1;
+            e--;
+        }
+        // Do the final shifts in one go.
+        f <<= DiyFp.kSignificandSize - kSignificandSize;
+        e -= DiyFp.kSignificandSize - kSignificandSize;
+
+        return new DiyFp(f, e);
+    }
+
+    // Returns the next greater double. Returns +infinity on input +infinity.
+    static double nextDouble(final long d64) {
+        if (d64 == kInfinity) return longToDouble(kInfinity);
+        if (sign(d64) < 0 && significand(d64) == 0) {
+            // -0.0
+            return 0.0;
+        }
+        if (sign(d64) < 0) {
+            return longToDouble(d64 - 1);
+        } else {
+            return longToDouble(d64 + 1);
+        }
+    }
+
+    static double previousDouble(final long d64) {
+        if (d64 == (kInfinity | kSignMask)) return -longToDouble(kInfinity);
+        if (sign(d64) < 0) {
+            return longToDouble(d64 + 1);
+        } else {
+            if (significand(d64) == 0) return -0.0;
+            return longToDouble(d64 - 1);
+        }
+    }
+
+    static int exponent(final long d64) {
+        if (isDenormal(d64)) return kDenormalExponent;
+
+        final int biased_e = (int) ((d64 & kExponentMask) >>> kPhysicalSignificandSize);
+        return biased_e - kExponentBias;
+    }
+
+    static long significand(final long d64) {
+        final long significand = d64 & kSignificandMask;
+        if (!isDenormal(d64)) {
+            return significand + kHiddenBit;
+        } else {
+            return significand;
+        }
+    }
+
+    // Returns true if the double is a denormal.
+    static boolean isDenormal(final long d64) {
+        return (d64 & kExponentMask) == 0L;
+    }
+
+    // We consider denormals not to be special.
+    // Hence only Infinity and NaN are special.
+    static boolean isSpecial(final long d64) {
+        return (d64 & kExponentMask) == kExponentMask;
+    }
+
+    static boolean isNaN(final long d64) {
+        return ((d64 & kExponentMask) == kExponentMask) &&
+                ((d64 & kSignificandMask) != 0L);
+    }
+
+
+    static boolean isInfinite(final long d64) {
+        return ((d64 & kExponentMask) == kExponentMask) &&
+                ((d64 & kSignificandMask) == 0L);
+    }
+
+
+    static int sign(final long d64) {
+        return (d64 & kSignMask) == 0L ? 1 : -1;
+    }
+
+
+    // Computes the two boundaries of this.
+    // The bigger boundary (m_plus) is normalized. The lower boundary has the same
+    // exponent as m_plus.
+    // Precondition: the value encoded by this Double must be greater than 0.
+    static void normalizedBoundaries(final long d64, final DiyFp m_minus, final DiyFp m_plus) {
+        assert (value(d64) > 0.0);
+        final DiyFp v = asDiyFp(d64);
+        m_plus.setF((v.f() << 1) + 1);
+        m_plus.setE(v.e() - 1);
+        m_plus.normalize();
+        if (lowerBoundaryIsCloser(d64)) {
+            m_minus.setF((v.f() << 2) - 1);
+            m_minus.setE(v.e() - 2);
+        } else {
+            m_minus.setF((v.f() << 1) - 1);
+            m_minus.setE(v.e() - 1);
+        }
+        m_minus.setF(m_minus.f() << (m_minus.e() - m_plus.e()));
+        m_minus.setE(m_plus.e());
+    }
+
+    static boolean lowerBoundaryIsCloser(final long d64) {
+        // The boundary is closer if the significand is of the form f == 2^p-1 then
+        // the lower boundary is closer.
+        // Think of v = 1000e10 and v- = 9999e9.
+        // Then the boundary (== (v - v-)/2) is not just at a distance of 1e9 but
+        // at a distance of 1e8.
+        // The only exception is for the smallest normal: the largest denormal is
+        // at the same distance as its successor.
+        // Note: denormals have the same exponent as the smallest normals.
+        final boolean physical_significand_is_zero = ((d64 & kSignificandMask) == 0);
+        return physical_significand_is_zero && (exponent(d64) != kDenormalExponent);
+    }
+
+    static double value(final long d64) {
+        return longToDouble(d64);
+    }
+
+    // Returns the significand size for a given order of magnitude.
+    // If v = f*2^e with 2^p-1 <= f <= 2^p then p+e is v's order of magnitude.
+    // This function returns the number of significant binary digits v will have
+    // once it's encoded into a double. In almost all cases this is equal to
+    // kSignificandSize. The only exceptions are denormals. They start with
+    // leading zeroes and their effective significand-size is hence smaller.
+    static int significandSizeForOrderOfMagnitude(final int order) {
+        if (order >= (kDenormalExponent + kSignificandSize)) {
+            return kSignificandSize;
+        }
+        if (order <= kDenormalExponent) return 0;
+        return order - kDenormalExponent;
+    }
+
+    static double Infinity() {
+        return longToDouble(kInfinity);
+    }
+
+    static double NaN() {
+        return longToDouble(kNaN);
+    }
+
+}
+
+
--- a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/linker/Bootstrap.java	Mon Nov 23 15:32:02 2015 +0100
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/linker/Bootstrap.java	Thu Nov 26 01:06:51 2015 +0100
@@ -49,12 +49,12 @@
 import jdk.nashorn.internal.codegen.CompilerConstants.Call;
 import jdk.nashorn.internal.lookup.MethodHandleFactory;
 import jdk.nashorn.internal.lookup.MethodHandleFunctionality;
+import jdk.nashorn.internal.runtime.Context;
 import jdk.nashorn.internal.runtime.ECMAException;
 import jdk.nashorn.internal.runtime.JSType;
 import jdk.nashorn.internal.runtime.OptimisticReturnFilters;
 import jdk.nashorn.internal.runtime.ScriptFunction;
 import jdk.nashorn.internal.runtime.ScriptRuntime;
-import jdk.nashorn.internal.runtime.options.Options;
 
 /**
  * This class houses bootstrap method for invokedynamic instructions generated by compiler.
@@ -67,28 +67,19 @@
 
     private static final MethodHandle VOID_TO_OBJECT = MH.constant(Object.class, ScriptRuntime.UNDEFINED);
 
-    /**
-     * The default dynalink relink threshold for megamorphism is 8. In the case
-     * of object fields only, it is fine. However, with dual fields, in order to get
-     * performance on benchmarks with a lot of object instantiation and then field
-     * reassignment, it can take slightly more relinks to become stable with type
-     * changes swapping out an entire property map and making a map guard fail.
-     * Since we need to set this value statically it must work with possibly changing
-     * optimistic types and dual fields settings. A higher value does not seem to have
-     * any other negative performance implication when running with object-only fields,
-     * so we choose a higher value here.
-     *
-     * See for example octane.gbemu, run with --log=fields:warning to study
-     * megamorphic behavior
-     */
-    private static final int NASHORN_DEFAULT_UNSTABLE_RELINK_THRESHOLD = 16;
-
     // do not create me!!
     private Bootstrap() {
     }
 
-    private static final DynamicLinker dynamicLinker;
-    static {
+    /**
+     * Creates a Nashorn dynamic linker with the given app class loader.
+     * @param appLoader the app class loader. It will be used to discover
+     * additional language runtime linkers (if any).
+     * @param unstableRelinkThreshold the unstable relink threshold
+     * @return a newly created dynamic linker.
+     */
+    public static DynamicLinker createDynamicLinker(final ClassLoader appLoader,
+            final int unstableRelinkThreshold) {
         final DynamicLinkerFactory factory = new DynamicLinkerFactory();
         final NashornBeansLinker nashornBeansLinker = new NashornBeansLinker();
         factory.setPrioritizedLinkers(
@@ -116,15 +107,11 @@
             }
         });
         factory.setInternalObjectsFilter(NashornBeansLinker.createHiddenObjectFilter());
-        final int relinkThreshold = Options.getIntProperty("nashorn.unstable.relink.threshold", NASHORN_DEFAULT_UNSTABLE_RELINK_THRESHOLD);
-        if (relinkThreshold > -1) {
-            factory.setUnstableRelinkThreshold(relinkThreshold);
-        }
+        factory.setUnstableRelinkThreshold(unstableRelinkThreshold);
 
         // Linkers for any additional language runtimes deployed alongside Nashorn will be picked up by the factory.
-        factory.setClassLoader(Bootstrap.class.getClassLoader());
-
-        dynamicLinker = factory.createLinker();
+        factory.setClassLoader(appLoader);
+        return factory.createLinker();
     }
 
     /**
@@ -202,7 +189,7 @@
      * @return CallSite with MethodHandle to appropriate method or null if not found.
      */
     public static CallSite bootstrap(final Lookup lookup, final String opDesc, final MethodType type, final int flags) {
-        return dynamicLinker.link(LinkerCallSite.newLinkerCallSite(lookup, opDesc, type, flags));
+        return Context.getDynamicLinker(lookup.lookupClass()).link(LinkerCallSite.newLinkerCallSite(lookup, opDesc, type, flags));
     }
 
     /**
@@ -461,7 +448,7 @@
      * @return Nashorn's internal dynamic linker's services object.
      */
     public static LinkerServices getLinkerServices() {
-        return dynamicLinker.getLinkerServices();
+        return Context.getDynamicLinker().getLinkerServices();
     }
 
     /**
--- a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/resources/Messages.properties	Mon Nov 23 15:32:02 2015 +0100
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/resources/Messages.properties	Thu Nov 26 01:06:51 2015 +0100
@@ -154,6 +154,11 @@
 type.error.java.array.conversion.failed=Java.to conversion to array type {0} failed
 type.error.constructor.requires.new=Constructor {0} requires "new".
 type.error.new.on.nonpublic.javatype=new cannot be used with non-public java type {0}.
+type.error.invalid.weak.key=invalid value {0} used as weak key.
+type.error.symbol.to.string=Can not convert Symbol value to string.
+type.error.symbol.to.number=Can not convert Symbol value to number.
+type.error.not.a.symbol={0} is not a symbol.
+type.error.symbol.as.constructor=Symbol is not a constructor.
 
 range.error.dataview.constructor.offset=Wrong offset or length in DataView constructor
 range.error.dataview.offset=Offset is outside the bounds of the DataView
--- a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/resources/Options.properties	Mon Nov 23 15:32:02 2015 +0100
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/resources/Options.properties	Thu Nov 26 01:06:51 2015 +0100
@@ -77,6 +77,15 @@
     desc="Print extended help for command line flags." \
 }
 
+nashorn.option.anonymous.classes = {                      \
+    name="--anonymous-classes",                           \
+    is_undocumented=true,                                 \
+    params=[auto|true|false],                             \
+    default=auto,                                         \
+    type=string,                                          \
+    desc="Use VM anonymous classes for compiled scripts." \
+}
+
 nashorn.option.class.cache.size ={                            \
     name="--class-cache-size",                                \
     short_name="-ccs",                                        \
@@ -118,6 +127,31 @@
     type=String                                                  \
 }
 
+nashorn.option.D = {                                                          \
+    name="-D",                                                                \
+    desc="-Dname=value. Set a system property. This option can be repeated.", \
+    type=String                                                               \
+}
+
+nashorn.option.debug.lines = {                          \
+    name="--debug-lines",                               \
+    is_undocumented=true,                               \
+    desc="Generate line number table in .class files.", \
+    default=true                                        \
+}
+
+nashorn.option.debug.locals = {                           \
+    name="--debug-locals",                                \
+    is_undocumented=true,                                 \
+    desc="Generate local variable table in .class files." \
+}
+
+nashorn.option.debug.scopes = {                                 \
+    name="--debug-scopes",                                      \
+    is_undocumented=true,                                       \
+    desc="Put all variables in scopes to make them debuggable." \
+}
+
 nashorn.option.doe = {                   \
     name="-dump-on-error",               \
     short_name="-doe",                   \
@@ -172,6 +206,14 @@
     default=false                               \
 }
 
+nashorn.option.language = {                      \
+    name="--language",                           \
+    type=String,                                 \
+    params=[es5|es6],                            \
+    default=es5,                                 \
+    desc="Specify ECMAScript language version."  \
+}
+
 nashorn.option.log = {                                                       \
     name="--log",                                                            \
     is_undocumented=true,                                                    \
@@ -181,19 +223,6 @@
     type=Log                                                                 \
 }
 
-nashorn.option.debug.lines = {                          \
-    name="--debug-lines",                               \
-    is_undocumented=true,                               \
-    desc="Generate line number table in .class files.", \
-    default=true                                        \
-}
-
-nashorn.option.debug.locals = {                           \
-    name="--debug-locals",                                \
-    is_undocumented=true,                                 \
-    desc="Generate local variable table in .class files." \
-}
-
 nashorn.option.lazy.compilation = {                                                                      \
     name="--lazy-compilation",                                                                           \
     is_undocumented=true,                                                                                \
@@ -201,13 +230,6 @@
     default=true                                   \
 }
 
-nashorn.option.optimistic.types = {                                                                      \
-    name="--optimistic-types",                                                                           \
-    short_name="-ot",                                                                                    \
-    desc="Use optimistic type assumptions with deoptimizing recompilation. This makes the compiler try, for any program symbol whose type cannot be proven at compile time, to type it as narrow and primitive as possible. If the runtime encounters an error because symbol type is too narrow, a wider method will be generated until steady stage is reached. While this produces as optimal Java Bytecode as possible, erroneous type guesses will lead to longer warmup. Optimistic typing is currently enabled by default, but can be disabled for faster startup performance.",                     \
-    default=true                                                                                         \
-}
-
 nashorn.option.loader.per.compile = {              \
     name="--loader-per-compile",                   \
     is_undocumented=true,                          \
@@ -239,6 +261,13 @@
     default=false                                  \
 }
 
+nashorn.option.optimistic.types = {                                                                      \
+    name="--optimistic-types",                                                                           \
+    short_name="-ot",                                                                                    \
+    desc="Use optimistic type assumptions with deoptimizing recompilation. This makes the compiler try, for any program symbol whose type cannot be proven at compile time, to type it as narrow and primitive as possible. If the runtime encounters an error because symbol type is too narrow, a wider method will be generated until steady stage is reached. While this produces as optimal Java Bytecode as possible, erroneous type guesses will lead to longer warmup. Optimistic typing is currently enabled by default, but can be disabled for faster startup performance.",                     \
+    default=true                                                                                         \
+}
+
 nashorn.option.parse.only = {       \
     name="--parse-only",            \
     is_undocumented=true,           \
@@ -313,12 +342,6 @@
     desc="Print the symbol table." \
 }
 
-nashorn.option.D = {                                                          \
-    name="-D",                                                                \
-    desc="-Dname=value. Set a system property. This option can be repeated.", \
-    type=String                                                               \
-}
-
 nashorn.option.strict = {              \
     name="-strict",                    \
     desc="Run scripts in strict mode." \
@@ -329,14 +352,6 @@
     desc="Enable scripting features."   \
 }
 
-nashorn.option.language = {                      \
-    name="--language",                           \
-    type=String,                                 \
-    params=[es5|es6],                            \
-    default=es5,                                 \
-    desc="Specify ECMAScript language version."  \
-}
-
 nashorn.option.stdout = {                                                \
     name="--stdout",                                                     \
     is_undocumented=true,                                                \
@@ -380,15 +395,18 @@
     enterexit [trace callsite enter/exit], objects [print object properties]."   \
 }
 
-nashorn.option.anonymous.classes = {                      \
-    name="--anonymous-classes",                           \
-    is_undocumented=true,                                 \
-    params=[auto|true|false],                             \
-    default=auto,                                         \
-    type=string,                                          \
-    desc="Use VM anonymous classes for compiled scripts." \
+nashorn.option.unstable.relink.threshold ={                   \
+    name="--unstable-relink-threshold",                       \
+    short_name="-urt",                                        \
+    desc="Number of times a dynamic call site has to be       \
+    relinked before it is considered unstable, when the       \
+    runtime will try to link it as if it is megamorphic.",    \
+    is_undocumented=true,                                     \
+    type=Integer,                                             \
+    default=-1                                                \
 }
 
+
 nashorn.option.verify.code = {              \
     name="--verify-code",                   \
     is_undocumented=true,                   \
--- a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/tools/Shell.java	Mon Nov 23 15:32:02 2015 +0100
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/tools/Shell.java	Thu Nov 26 01:06:51 2015 +0100
@@ -36,6 +36,7 @@
 import java.io.OutputStream;
 import java.io.PrintStream;
 import java.io.PrintWriter;
+import java.util.Iterator;
 import java.util.List;
 import java.util.Locale;
 import java.util.ResourceBundle;
@@ -47,6 +48,7 @@
 import jdk.nashorn.internal.ir.debug.ASTWriter;
 import jdk.nashorn.internal.ir.debug.PrintVisitor;
 import jdk.nashorn.internal.objects.Global;
+import jdk.nashorn.internal.objects.NativeSymbol;
 import jdk.nashorn.internal.parser.Parser;
 import jdk.nashorn.internal.runtime.Context;
 import jdk.nashorn.internal.runtime.ErrorManager;
@@ -54,7 +56,10 @@
 import jdk.nashorn.internal.runtime.Property;
 import jdk.nashorn.internal.runtime.ScriptEnvironment;
 import jdk.nashorn.internal.runtime.ScriptFunction;
+import jdk.nashorn.internal.runtime.ScriptObject;
 import jdk.nashorn.internal.runtime.ScriptRuntime;
+import jdk.nashorn.internal.runtime.Symbol;
+import jdk.nashorn.internal.runtime.arrays.ArrayLikeIterator;
 import jdk.nashorn.internal.runtime.options.Options;
 
 /**
@@ -474,7 +479,7 @@
                 try {
                     final Object res = context.eval(global, source, global, "<shell>");
                     if (res != ScriptRuntime.UNDEFINED) {
-                        err.println(JSType.toString(res));
+                        err.println(toString(res, global));
                     }
                 } catch (final Exception e) {
                     err.println(e);
@@ -491,4 +496,56 @@
 
         return SUCCESS;
     }
+
+    /**
+     * Converts {@code result} to a printable string. The reason we don't use {@link JSType#toString(Object)}
+     * or {@link ScriptRuntime#safeToString(Object)} is that we want to be able to render Symbol values
+     * even if they occur within an Array, and therefore have to implement our own Array to String
+     * conversion.
+     *
+     * @param result the result
+     * @param global the global object
+     * @return the string representation
+     */
+    protected static String toString(final Object result, final Global global) {
+        if (result instanceof Symbol) {
+            // Normal implicit conversion of symbol to string would throw TypeError
+            return result.toString();
+        }
+
+        if (result instanceof NativeSymbol) {
+            return JSType.toPrimitive(result).toString();
+        }
+
+        if (isArrayWithDefaultToString(result, global)) {
+            // This should yield the same string as Array.prototype.toString but
+            // will not throw if the array contents include symbols.
+            final StringBuilder sb = new StringBuilder();
+            final Iterator<Object> iter = ArrayLikeIterator.arrayLikeIterator(result, true);
+
+            while (iter.hasNext()) {
+                final Object obj = iter.next();
+
+                if (obj != null && obj != ScriptRuntime.UNDEFINED) {
+                    sb.append(toString(obj, global));
+                }
+
+                if (iter.hasNext()) {
+                    sb.append(',');
+                }
+            }
+
+            return sb.toString();
+        }
+
+        return JSType.toString(result);
+    }
+
+    private static boolean isArrayWithDefaultToString(final Object result, final Global global) {
+        if (result instanceof ScriptObject) {
+            final ScriptObject sobj = (ScriptObject) result;
+            return sobj.isArray() && sobj.get("toString") == global.getArrayPrototype().get("toString");
+        }
+        return false;
+    }
 }
--- a/test/script/basic/JDK-8011578.js	Mon Nov 23 15:32:02 2015 +0100
+++ b/test/script/basic/JDK-8011578.js	Thu Nov 26 01:06:51 2015 +0100
@@ -25,7 +25,7 @@
  * JDK-8011578 : -Dnashorn.unstable.relink.threshold=1 causes tests to fail.
  *
  * @test
- * @option -Dnashorn.unstable.relink.threshold=1
+ * @option --unstable-relink-threshold=1
  * @run
  */
 
--- a/test/script/basic/JDK-8044750.js	Mon Nov 23 15:32:02 2015 +0100
+++ b/test/script/basic/JDK-8044750.js	Thu Nov 26 01:06:51 2015 +0100
@@ -25,8 +25,7 @@
  * JDK-8044750: megamorphic getter for scope objects does not call __noSuchProperty__ hook
  *
  * @test
- * @fork
- * @option -Dnashorn.unstable.relink.threshold=16
+ * @option --unstable-relink-threshold=16
  * @run
  */
 
--- a/test/script/basic/JDK-8047369.js	Mon Nov 23 15:32:02 2015 +0100
+++ b/test/script/basic/JDK-8047369.js	Thu Nov 26 01:06:51 2015 +0100
@@ -167,8 +167,8 @@
 CODE, "set \":\"(a) {}");
 
 // bug JDK-8047366
-// evalExpectValue("(1000000000000000128).toString()", "1000000000000000100");
-// evalExpectValue("(1000000000000000128).toFixed().toString()", "1000000000000000128");
+evalExpectValue("(1000000000000000128).toString()", "1000000000000000100");
+evalExpectValue("(1000000000000000128).toFixed().toString()", "1000000000000000128");
 
 try {
     Function("-", {
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/script/basic/JDK-8059934.js	Thu Nov 26 01:06:51 2015 +0100
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ * 
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ * 
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ * 
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ * 
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/**
+ * JDK-8059934: Random failures when script size exceeds token limits
+ *
+ * @test
+ * @run
+ */
+
+// Make sure that we can successfully evaluate a 100 MB string.
+// We don't go beyond that as we'd likely hit heap size limits.
+var src = "var x = 'ok';";
+for (var i = 0; i < 1000000; i++) {
+    src += "                                                                                                    ";
+}
+src += "x;";
+
+Assert.assertEquals(100000015, src.length);
+Assert.assertEquals("ok", eval(src));
+
--- a/test/script/basic/JDK-8062141.js.EXPECTED	Mon Nov 23 15:32:02 2015 +0100
+++ b/test/script/basic/JDK-8062141.js.EXPECTED	Thu Nov 26 01:06:51 2015 +0100
@@ -114,7 +114,7 @@
 {"a":truer}
          ^
 [1,2,3]
-[9223372036854773800,9223372036854774800,9223372036854776000]
+[9223372036854774000,9223372036854775000,9223372036854776000]
 [1.1,1.2,1.3]
 [1,1.2,9223372036854776000,null,true]
 {"a":"string","b":1,"c":1.2,"d":9223372036854776000,"e":null,"f":true}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/script/basic/JDK-8131929.js	Thu Nov 26 01:06:51 2015 +0100
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ * 
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ * 
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ * 
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ * 
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/**
+ * JDK-8131929: Add option for debuggable scopes
+ *
+ * @test
+ * @run
+ * @option --debug-scopes=true
+ * @option -Dnashorn.debug
+ * @fork
+ */
+
+
+function f1(x, y) {
+    var a = x * 2 , b = y + 3;
+    print(a, b);
+    return a + b;
+}
+
+function f2() {}
+
+Assert.assertTrue(Debug.isDebuggableFunction(f1));
+Assert.assertTrue(Debug.isDebuggableFunction(f2));
+Assert.assertTrue(Debug.isDebuggableFunction((function() { return function() {}})()));
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/script/basic/JDK-8131929_prototype.js	Thu Nov 26 01:06:51 2015 +0100
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ * 
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ * 
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ * 
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ * 
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/**
+ * JDK-8131929: Add option for debuggable scopes
+ *
+ * @test
+ * @runif external.prototype
+ * @option --debug-scopes=true
+ * @fork
+ */
+
+load(__DIR__ + 'prototype.js');
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/script/basic/JDK-8131929_prototype.js.EXPECTED	Thu Nov 26 01:06:51 2015 +0100
@@ -0,0 +1,1 @@
+parsed and compiled ok prototype.js
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/script/basic/JDK-8131929_yui.js	Thu Nov 26 01:06:51 2015 +0100
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ * 
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ * 
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ * 
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ * 
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/**
+ * JDK-8131929: Add option for debuggable scopes
+ *
+ * @test
+ * @runif external.yui
+ * @option --debug-scopes=true
+ * @fork
+ */
+
+load(__DIR__ + 'yui.js');
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/script/basic/JDK-8131929_yui.js.EXPECTED	Thu Nov 26 01:06:51 2015 +0100
@@ -0,0 +1,2 @@
+parsed and compiled ok yui-min.js
+parsed and compiled ok yui.js
--- a/test/script/basic/JDK-8136544.js	Mon Nov 23 15:32:02 2015 +0100
+++ b/test/script/basic/JDK-8136544.js	Thu Nov 26 01:06:51 2015 +0100
@@ -25,8 +25,7 @@
  * JDK-8136544: Call site switching to megamorphic causes incorrect property read
  *
  * @test
- * @fork
- * @option -Dnashorn.unstable.relink.threshold=8
+ * @option --unstable-relink-threshold=8
  * @run
  */
 
--- a/test/script/basic/JDK-8136694.js	Mon Nov 23 15:32:02 2015 +0100
+++ b/test/script/basic/JDK-8136694.js	Thu Nov 26 01:06:51 2015 +0100
@@ -25,8 +25,7 @@
  * JDK-8136694: Megemorphic scope access does not throw ReferenceError when property is missing
  *
  * @test
- * @fork
- * @option -Dnashorn.unstable.relink.threshold=16
+ * @option --unstable-relink-threshold=16
  * @run
  */
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/script/basic/JDK-8141505.js	Thu Nov 26 01:06:51 2015 +0100
@@ -0,0 +1,32 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ * 
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ * 
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ * 
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ * 
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/**
+ * JDK-8141505: floating point parse incorrect on big integer
+ *
+ * @test
+ * @run
+ */
+
+Assert.assertEquals(String(-3.33333333333333e+18), "-3333333333333330000");
+
--- a/test/script/basic/NASHORN-389.js	Mon Nov 23 15:32:02 2015 +0100
+++ b/test/script/basic/NASHORN-389.js	Thu Nov 26 01:06:51 2015 +0100
@@ -35,6 +35,6 @@
 var y = -1.23456789e+20;
 print(x.toFixed(9));
 print(y.toFixed(9).indexOf(",") === -1); // no grouping
-//print(y.toFixed(9)); // FIXME expected: -123456788999999995904.000000000
-//print(1000000000000000128); // FIXME expected: 1000000000000000100
-//print((1000000000000000128).toFixed(0)); // FIXME expected: 1000000000000000128
+print(y.toFixed(9));
+print(1000000000000000128); 
+print((1000000000000000128).toFixed(0));
--- a/test/script/basic/NASHORN-389.js.EXPECTED	Mon Nov 23 15:32:02 2015 +0100
+++ b/test/script/basic/NASHORN-389.js.EXPECTED	Thu Nov 26 01:06:51 2015 +0100
@@ -3,3 +3,6 @@
 0.00001
 -1.23456789e+21
 true
+-123456788999999995904.000000000
+1000000000000000100
+1000000000000000128
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/script/basic/es6.js	Thu Nov 26 01:06:51 2015 +0100
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ * 
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ * 
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ * 
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ * 
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/**
+ * Make sure ECMAScript 6 features are not available in ES5 mode.
+ *
+ * @test
+ * @run
+ */
+
+if (typeof Symbol !== 'undefined' || 'Symbol' in this) {
+    Assert.fail('Symbol is defined in global scope');
+}
+
+if (typeof Object.getOwnPropertySymbols !== 'undefined' || 'getOwnPropertySymbols' in Object) {
+    Assert.fail('getOwnPropertySymbols is defined in global Object');
+}
+
+function expectError(src, msg, error) {
+    try {
+        eval(src);
+        Assert.fail(msg);
+    } catch (e) {
+        if (e.name !== error) {
+            Assert.fail('Unexpected error: ' + e);
+        }
+    }
+}
+
+expectError('let i = 0', 'let', 'SyntaxError');
+expectError('const i = 0', 'const', 'SyntaxError');
+expectError('for (let i = 0; i < 10; i++) print(i)', 'for-let', 'SyntaxError');
+expectError('0b0', 'numeric literal', 'SyntaxError');
+expectError('0o0', 'numeric litera', 'SyntaxError');
+expectError('`text`', 'template literal', 'SyntaxError');
+expectError('`${ x }`', 'template literal', 'SyntaxError');
+expectError('`text ${ x } text`', 'template literal', 'SyntaxError');
+expectError('f`text`', 'template literal', 'SyntaxError');
--- a/test/script/basic/es6/let.js	Mon Nov 23 15:32:02 2015 +0100
+++ b/test/script/basic/es6/let.js	Thu Nov 26 01:06:51 2015 +0100
@@ -26,7 +26,8 @@
  *
  * @test
  * @run
- * @option --language=es6 */
+ * @option --language=es6
+ */
 
 "use strict";
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/script/basic/es6/symbols.js	Thu Nov 26 01:06:51 2015 +0100
@@ -0,0 +1,146 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ * 
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ * 
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ * 
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ * 
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/**
+ * JDK-8141702: Add support for Symbol property keys
+ *
+ * @test
+ * @run
+ * @option --language=es6
+ */
+
+Assert.assertTrue(typeof Symbol === 'function');
+Assert.assertTrue(typeof Symbol() === 'symbol');
+
+Assert.assertTrue(Symbol().toString() === 'Symbol()');
+Assert.assertTrue(Symbol('foo').toString() === 'Symbol(foo)');
+Assert.assertTrue(Symbol(1).toString() === 'Symbol(1)');
+Assert.assertTrue(Symbol(true).toString() === 'Symbol(true)');
+Assert.assertTrue(Symbol([1, 2, 3]).toString() === 'Symbol(1,2,3)');
+Assert.assertTrue(Symbol(null).toString() === 'Symbol(null)');
+Assert.assertTrue(Symbol(undefined).toString() === 'Symbol()');
+
+var s1 = Symbol();
+var s2 = Symbol("s2");
+Assert.assertFalse(s1 instanceof Symbol); // not an object
+
+var obj = {};
+obj['foo'] = 'foo';
+obj[s1] = s1;
+obj['bar'] = 'bar';
+obj[1] = 1;
+obj[s2] = s2;
+
+Assert.assertTrue(obj['foo'] === 'foo');
+Assert.assertTrue(obj[s1] === s1);
+Assert.assertTrue(obj['bar'] === 'bar');
+Assert.assertTrue(obj[1] === 1);
+Assert.assertTrue(obj[s2] === s2);
+
+var expectedNames = ['1', 'foo', 'bar'];
+var expectedSymbols = [s1, s2];
+var actualNames = Object.getOwnPropertyNames(obj);
+var actualSymbols = Object.getOwnPropertySymbols(obj);
+Assert.assertTrue(expectedNames.length == actualNames.length);
+Assert.assertTrue(expectedSymbols.length == actualSymbols.length);
+
+for (var key in expectedNames) {
+    Assert.assertTrue(expectedNames[key] === actualNames[key]);
+}
+for (var key in expectedSymbols) {
+    Assert.assertTrue(expectedSymbols[key] === actualSymbols[key]);
+}
+
+// Delete
+Assert.assertTrue(delete obj[s1]);
+Assert.assertTrue(Object.getOwnPropertySymbols(obj).length === 1);
+Assert.assertTrue(Object.getOwnPropertySymbols(obj)[0] === s2);
+
+// Object.defineProperty
+Object.defineProperty(obj, s1, {value : 'hello'});
+Assert.assertTrue(obj[s1] === 'hello');
+actualSymbols = Object.getOwnPropertySymbols(obj);
+Assert.assertTrue(Object.getOwnPropertySymbols(obj).length === 2);
+Assert.assertTrue(Object.getOwnPropertySymbols(obj)[1] === s1);
+
+// Symbol called as constructor
+try {
+    new Symbol();
+    Assert.fail("Symbol invoked as constructor");
+} catch (e) {
+    if (e.name !== "TypeError" || e.message !== "Symbol is not a constructor.") {
+        Assert.fail("Unexpected error: " + e);
+    }
+}
+
+// Implicit conversion to string or number should throw
+try {
+    ' ' + s1;
+    Assert.fail("Symbol converted to string");
+} catch (e) {
+    if (e.name !== "TypeError" || e.message !== "Can not convert Symbol value to string.") {
+        Assert.fail("Unexpected error: " + e);
+    }
+}
+
+try {
+    4 * s1;
+    Assert.fail("Symbol converted to number");
+} catch (e) {
+    if (e.name !== "TypeError" || e.message !== "Can not convert Symbol value to number.") {
+        Assert.fail("Unexpected error: " + e);
+    }
+}
+
+// Symbol.for and Symbol.keyFor
+
+var uncached = Symbol('foo');
+var cached = Symbol.for('foo');
+
+Assert.assertTrue(uncached !== cached);
+Assert.assertTrue(Symbol.keyFor(uncached) === undefined);
+Assert.assertTrue(Symbol.keyFor(cached) === 'foo');
+Assert.assertTrue(cached === Symbol.for('foo'));
+Assert.assertTrue(cached === Symbol.for('f' + 'oo'));
+
+// Object wrapper
+
+var o = Object(s1);
+obj = {};
+obj[s1] = "s1";
+Assert.assertTrue(o == s1);
+Assert.assertTrue(o !== s1);
+Assert.assertTrue(typeof o === 'object');
+Assert.assertTrue(o instanceof Symbol);
+Assert.assertTrue(obj[o] == 's1');
+Assert.assertTrue(o in obj);
+
+// various non-strict comparisons that should fail
+
+Assert.assertFalse(0 == Symbol());
+Assert.assertFalse(1 == Symbol(1));
+Assert.assertFalse(null == Symbol());
+Assert.assertFalse(undefined == Symbol);
+Assert.assertFalse('Symbol()' == Symbol());
+Assert.assertFalse('Symbol(foo)' == Symbol('foo'));
+
--- a/test/script/basic/prototype.js	Mon Nov 23 15:32:02 2015 +0100
+++ b/test/script/basic/prototype.js	Thu Nov 26 01:06:51 2015 +0100
@@ -22,7 +22,7 @@
  */
 
 /**
- * NASHORN-467 - check that prootype.js parses and compiles
+ * NASHORN-467 - check that prototype.js parses and compiles
  *
  * @test
  * @runif external.prototype
--- a/test/src/jdk/nashorn/api/javaaccess/test/ArrayConversionTest.java	Mon Nov 23 15:32:02 2015 +0100
+++ b/test/src/jdk/nashorn/api/javaaccess/test/ArrayConversionTest.java	Thu Nov 26 01:06:51 2015 +0100
@@ -40,6 +40,10 @@
 import org.testng.annotations.BeforeClass;
 import org.testng.annotations.Test;
 
+/**
+ * @test
+ * @run testng/othervm jdk.nashorn.api.javaaccess.test.ArrayConversionTest
+ */
 @SuppressWarnings("javadoc")
 public class ArrayConversionTest {
     private static ScriptEngine e = null;
--- a/test/src/jdk/nashorn/api/javaaccess/test/ConsStringTest.java	Mon Nov 23 15:32:02 2015 +0100
+++ b/test/src/jdk/nashorn/api/javaaccess/test/ConsStringTest.java	Thu Nov 26 01:06:51 2015 +0100
@@ -39,6 +39,10 @@
 import org.testng.annotations.BeforeClass;
 import org.testng.annotations.Test;
 
+/**
+ * @test
+ * @run testng jdk.nashorn.api.javaaccess.test.ConsStringTest
+ */
 @SuppressWarnings("javadoc")
 public class ConsStringTest {
     private static ScriptEngine e = null;
--- a/test/src/jdk/nashorn/api/scripting/test/InvocableTest.java	Mon Nov 23 15:32:02 2015 +0100
+++ b/test/src/jdk/nashorn/api/scripting/test/InvocableTest.java	Thu Nov 26 01:06:51 2015 +0100
@@ -40,6 +40,10 @@
 
 /**
  * Tests for javax.script.Invocable implementation of nashorn.
+ *
+ * @test
+ * @build jdk.nashorn.api.scripting.test.VariableArityTestInterface jdk.nashorn.api.scripting.test.InvocableTest
+ * @run testng jdk.nashorn.api.scripting.test.InvocableTest
  */
 @SuppressWarnings("javadoc")
 public class InvocableTest {
--- a/test/src/jdk/nashorn/api/scripting/test/JSONCompatibleTest.java	Mon Nov 23 15:32:02 2015 +0100
+++ b/test/src/jdk/nashorn/api/scripting/test/JSONCompatibleTest.java	Thu Nov 26 01:06:51 2015 +0100
@@ -39,6 +39,10 @@
 import org.testng.Assert;
 import org.testng.annotations.Test;
 
+/**
+ * @test
+ * @run testng jdk.nashorn.api.scripting.test.JSONCompatibleTest
+ */
 public class JSONCompatibleTest {
 
     /**
--- a/test/src/jdk/nashorn/api/scripting/test/PluggableJSObjectTest.java	Mon Nov 23 15:32:02 2015 +0100
+++ b/test/src/jdk/nashorn/api/scripting/test/PluggableJSObjectTest.java	Thu Nov 26 01:06:51 2015 +0100
@@ -47,6 +47,9 @@
  *
  * JDK-8024615: Refactor ScriptObjectMirror and JSObject to support external
  * JSObject implementations.
+ *
+ * @test
+ * @run testng jdk.nashorn.api.scripting.test.PluggableJSObjectTest
  */
 @SuppressWarnings("javadoc")
 public class PluggableJSObjectTest {
--- a/test/src/jdk/nashorn/api/scripting/test/ScriptEngineSecurityTest.java	Mon Nov 23 15:32:02 2015 +0100
+++ b/test/src/jdk/nashorn/api/scripting/test/ScriptEngineSecurityTest.java	Thu Nov 26 01:06:51 2015 +0100
@@ -38,6 +38,9 @@
 
 /**
  * jsr223 tests for security access checks.
+ *
+ * @test
+ * @run testng/othervm jdk.nashorn.api.scripting.test.ScriptEngineSecurityTest
  */
 @SuppressWarnings("javadoc")
 public class ScriptEngineSecurityTest {
@@ -244,7 +247,7 @@
         final ScriptEngineManager m = new ScriptEngineManager();
         final ScriptEngine e = m.getEngineByName("nashorn");
         final Runnable r = (Runnable)Proxy.newProxyInstance(
-            ScriptEngineTest.class.getClassLoader(),
+            ScriptEngineSecurityTest.class.getClassLoader(),
             new Class[] { Runnable.class },
             new InvocationHandler() {
                 @Override
--- a/test/src/jdk/nashorn/api/scripting/test/ScriptObjectMirrorTest.java	Mon Nov 23 15:32:02 2015 +0100
+++ b/test/src/jdk/nashorn/api/scripting/test/ScriptObjectMirrorTest.java	Thu Nov 26 01:06:51 2015 +0100
@@ -47,6 +47,9 @@
 
 /**
  * Tests to check jdk.nashorn.api.scripting.ScriptObjectMirror API.
+ *
+ * @test
+ * @run testng jdk.nashorn.api.scripting.test.ScriptObjectMirrorTest
  */
 @SuppressWarnings("javadoc")
 public class ScriptObjectMirrorTest {
--- a/test/src/jdk/nashorn/api/tree/test/ParseAPITest.java	Mon Nov 23 15:32:02 2015 +0100
+++ b/test/src/jdk/nashorn/api/tree/test/ParseAPITest.java	Thu Nov 26 01:06:51 2015 +0100
@@ -37,17 +37,38 @@
 
 /**
  * Test for nashorn Parser API (jdk.nashorn.api.tree.*)
+ *
+ * @test
+ * @run testng jdk.nashorn.api.tree.test.ParseAPITest
  */
 public class ParseAPITest {
 
     private static final boolean VERBOSE   = Boolean.valueOf(System.getProperty("parserapitest.verbose"));
     private static final boolean TEST262   = Boolean.valueOf(System.getProperty("parserapitest.test262"));
 
-    private static final String TEST_BASIC_DIR     = System.getProperty("test.basic.dir");
-    private static final String TEST_MAPTESTS_DIR  = System.getProperty("test.maptests.dir");
-    private static final String TEST_SANDBOX_DIR   = System.getProperty("test.sandbox.dir");
-    private static final String TEST_TRUSTED_DIR   = System.getProperty("test.trusted.dir");
-    private static final String TEST262_SUITE_DIR  = System.getProperty("test262.suite.dir");
+    private static final String TEST_BASIC_DIR;
+    private static final String TEST_MAPTESTS_DIR;
+    private static final String TEST_SANDBOX_DIR;
+    private static final String TEST_TRUSTED_DIR;
+    private static final String TEST262_SUITE_DIR;
+
+    static {
+        String testSrc = System.getProperty("test.src");
+        if (testSrc != null) {
+            String testScriptDir = testSrc + "/../../../../../../script/";
+            TEST_BASIC_DIR    = testScriptDir + "basic";
+            TEST_MAPTESTS_DIR = testScriptDir + "maptests";
+            TEST_SANDBOX_DIR  = testScriptDir + "sandbox";
+            TEST_TRUSTED_DIR  = testScriptDir + "trusted";
+            TEST262_SUITE_DIR = testScriptDir + "external/test262/test/suite";
+        } else {
+            TEST_BASIC_DIR     = System.getProperty("test.basic.dir");
+            TEST_MAPTESTS_DIR  = System.getProperty("test.maptests.dir");
+            TEST_SANDBOX_DIR   = System.getProperty("test.sandbox.dir");
+            TEST_TRUSTED_DIR   = System.getProperty("test.trusted.dir");
+            TEST262_SUITE_DIR  = System.getProperty("test262.suite.dir");
+        }
+    }
 
     interface TestFilter {
         public boolean exclude(File file, String content);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/src/jdk/nashorn/internal/runtime/doubleconv/test/BignumDtoaTest.java	Thu Nov 26 01:06:51 2015 +0100
@@ -0,0 +1,352 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  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.
+ */
+
+// This file is available under and governed by the GNU General Public
+// License version 2 only, as published by the Free Software Foundation.
+// However, the following notice accompanied the original version of this
+// file:
+//
+// Copyright 2012 the V8 project authors. 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 Google Inc. 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.
+
+package jdk.nashorn.internal.runtime.doubleconv.test;
+
+import java.io.BufferedReader;
+import java.io.InputStreamReader;
+import jdk.nashorn.internal.runtime.doubleconv.DoubleConversion;
+import jdk.nashorn.internal.runtime.doubleconv.DtoaBuffer;
+import jdk.nashorn.internal.runtime.doubleconv.DtoaMode;
+
+import org.testng.annotations.Test;
+
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertTrue;
+
+/**
+ * FastDtoa tests
+ */
+@SuppressWarnings("javadoc")
+public class BignumDtoaTest {
+
+    final static private int BUFFER_SIZE = 100;
+
+    // Removes trailing '0' digits.
+    // Can return the empty string if all digits are 0.
+    private static String trimRepresentation(final String representation) {
+        final int len = representation.length();
+        int i;
+        for (i = len - 1; i >= 0; --i) {
+            if (representation.charAt(i) != '0') break;
+        }
+        return representation.substring(0, i + 1);
+    }
+
+    @Test
+    public void testBignumVarious() {
+        final DtoaBuffer buffer = new DtoaBuffer(BUFFER_SIZE);
+
+        DoubleConversion.bignumDtoa(1, DtoaMode.SHORTEST, 0, buffer);
+        assertEquals("1", buffer.getRawDigits());
+        assertEquals(1, buffer.getDecimalPoint());
+        buffer.reset();
+
+        DoubleConversion.bignumDtoa(1.0, DtoaMode.FIXED, 3, buffer);
+        assertTrue(3 >= buffer.getLength() - buffer.getDecimalPoint());
+        assertEquals("1", trimRepresentation(buffer.getRawDigits()));
+        assertEquals(1, buffer.getDecimalPoint());
+        buffer.reset();
+
+        DoubleConversion.bignumDtoa(1.0, DtoaMode.PRECISION, 3, buffer);
+        assertTrue(3 >= buffer.getLength());
+        assertEquals("1", trimRepresentation(buffer.getRawDigits()));
+        assertEquals(1, buffer.getDecimalPoint());
+        buffer.reset();
+
+        DoubleConversion.bignumDtoa(1.5, DtoaMode.SHORTEST, 0, buffer);
+        assertEquals("15", buffer.getRawDigits());
+        assertEquals(1, buffer.getDecimalPoint());
+        buffer.reset();
+
+        DoubleConversion.bignumDtoa(1.5, DtoaMode.FIXED, 10, buffer);
+        assertTrue(10 >= buffer.getLength() - buffer.getDecimalPoint());
+        assertEquals("15", trimRepresentation(buffer.getRawDigits()));
+        assertEquals(1, buffer.getDecimalPoint());
+        buffer.reset();
+
+        DoubleConversion.bignumDtoa(1.5, DtoaMode.PRECISION, 10, buffer);
+        assertTrue(10 >= buffer.getLength());
+        assertEquals("15", trimRepresentation(buffer.getRawDigits()));
+        assertEquals(1, buffer.getDecimalPoint());
+        buffer.reset();
+
+        final double min_double = 5e-324;
+        DoubleConversion.bignumDtoa(min_double, DtoaMode.SHORTEST, 0, buffer);
+        assertEquals("5", buffer.getRawDigits());
+        assertEquals(-323, buffer.getDecimalPoint());
+        buffer.reset();
+
+        DoubleConversion.bignumDtoa(min_double, DtoaMode.FIXED, 5, buffer);
+        assertTrue(5 >= buffer.getLength() - buffer.getDecimalPoint());
+        assertEquals("", trimRepresentation(buffer.getRawDigits()));
+        buffer.reset();
+
+        DoubleConversion.bignumDtoa(min_double, DtoaMode.PRECISION, 5, buffer);
+        assertTrue(5 >= buffer.getLength());
+        assertEquals("49407", trimRepresentation(buffer.getRawDigits()));
+        assertEquals(-323, buffer.getDecimalPoint());
+        buffer.reset();
+
+        final double max_double = 1.7976931348623157e308;
+        DoubleConversion.bignumDtoa(max_double, DtoaMode.SHORTEST, 0, buffer);
+        assertEquals("17976931348623157", buffer.getRawDigits());
+        assertEquals(309, buffer.getDecimalPoint());
+        buffer.reset();
+
+        DoubleConversion.bignumDtoa(max_double, DtoaMode.PRECISION, 7, buffer);
+        assertTrue(7 >= buffer.getLength());
+        assertEquals("1797693", trimRepresentation(buffer.getRawDigits()));
+        assertEquals(309, buffer.getDecimalPoint());
+        buffer.reset();
+
+        DoubleConversion.bignumDtoa(4294967272.0, DtoaMode.SHORTEST, 0, buffer);
+        assertEquals("4294967272", buffer.getRawDigits());
+        assertEquals(10, buffer.getDecimalPoint());
+        buffer.reset();
+
+        DoubleConversion.bignumDtoa(4294967272.0, DtoaMode.FIXED, 5, buffer);
+        assertEquals("429496727200000", buffer.getRawDigits());
+        assertEquals(10, buffer.getDecimalPoint());
+        buffer.reset();
+
+        DoubleConversion.bignumDtoa(4294967272.0, DtoaMode.PRECISION, 14, buffer);
+        assertTrue(14 >= buffer.getLength());
+        assertEquals("4294967272", trimRepresentation(buffer.getRawDigits()));
+        assertEquals(10, buffer.getDecimalPoint());
+        buffer.reset();
+
+        DoubleConversion.bignumDtoa(4.1855804968213567e298, DtoaMode.SHORTEST, 0, buffer);
+        assertEquals("4185580496821357", buffer.getRawDigits());
+        assertEquals(299, buffer.getDecimalPoint());
+        buffer.reset();
+
+        DoubleConversion.bignumDtoa(4.1855804968213567e298, DtoaMode.PRECISION, 20, buffer);
+        assertTrue(20 >= buffer.getLength());
+        assertEquals("41855804968213567225", trimRepresentation(buffer.getRawDigits()));
+        assertEquals(299, buffer.getDecimalPoint());
+        buffer.reset();
+
+        DoubleConversion.bignumDtoa(5.5626846462680035e-309, DtoaMode.SHORTEST, 0, buffer);
+        assertEquals("5562684646268003", buffer.getRawDigits());
+        assertEquals(-308, buffer.getDecimalPoint());
+        buffer.reset();
+
+        DoubleConversion.bignumDtoa(5.5626846462680035e-309, DtoaMode.PRECISION, 1, buffer);
+        assertTrue(1 >= buffer.getLength());
+        assertEquals("6", trimRepresentation(buffer.getRawDigits()));
+        assertEquals(-308, buffer.getDecimalPoint());
+        buffer.reset();
+
+        DoubleConversion.bignumDtoa(2147483648.0, DtoaMode.SHORTEST, 0, buffer);
+        assertEquals("2147483648", buffer.getRawDigits());
+        assertEquals(10, buffer.getDecimalPoint());
+        buffer.reset();
+
+        DoubleConversion.bignumDtoa(2147483648.0, DtoaMode.FIXED, 2, buffer);
+        assertTrue(2 >= buffer.getLength() - buffer.getDecimalPoint());
+        assertEquals("2147483648", trimRepresentation(buffer.getRawDigits()));
+        assertEquals(10, buffer.getDecimalPoint());
+        buffer.reset();
+
+        DoubleConversion.bignumDtoa(2147483648.0, DtoaMode.PRECISION, 5, buffer);
+        assertTrue(5 >= buffer.getLength());
+        assertEquals("21475", trimRepresentation(buffer.getRawDigits()));
+        assertEquals(10, buffer.getDecimalPoint());
+        buffer.reset();
+
+        DoubleConversion.bignumDtoa(3.5844466002796428e+298, DtoaMode.SHORTEST, 0, buffer);
+        assertEquals("35844466002796428", buffer.getRawDigits());
+        assertEquals(299, buffer.getDecimalPoint());
+        buffer.reset();
+
+        DoubleConversion.bignumDtoa(3.5844466002796428e+298, DtoaMode.PRECISION, 10, buffer);
+        assertTrue(10 >= buffer.getLength());
+        assertEquals("35844466", trimRepresentation(buffer.getRawDigits()));
+        assertEquals(299, buffer.getDecimalPoint());
+        buffer.reset();
+
+        final long smallest_normal64 = 0x0010000000000000L;
+        double v = Double.longBitsToDouble(smallest_normal64);
+        DoubleConversion.bignumDtoa(v, DtoaMode.SHORTEST, 0, buffer);
+        assertEquals("22250738585072014", buffer.getRawDigits());
+        assertEquals(-307, buffer.getDecimalPoint());
+        buffer.reset();
+
+        DoubleConversion.bignumDtoa(v, DtoaMode.PRECISION, 20, buffer);
+        assertTrue(20 >= buffer.getLength());
+        assertEquals("22250738585072013831", trimRepresentation(buffer.getRawDigits()));
+        assertEquals(-307, buffer.getDecimalPoint());
+        buffer.reset();
+
+        final long largest_denormal64 = 0x000FFFFFFFFFFFFFL;
+        v = Double.longBitsToDouble(largest_denormal64);
+        DoubleConversion.bignumDtoa(v, DtoaMode.SHORTEST, 0, buffer);
+        assertEquals("2225073858507201", buffer.getRawDigits());
+        assertEquals(-307, buffer.getDecimalPoint());
+        buffer.reset();
+
+        DoubleConversion.bignumDtoa(v, DtoaMode.PRECISION, 20, buffer);
+        assertTrue(20 >= buffer.getLength());
+        assertEquals("2225073858507200889", trimRepresentation(buffer.getRawDigits()));
+        assertEquals(-307, buffer.getDecimalPoint());
+        buffer.reset();
+
+        DoubleConversion.bignumDtoa(4128420500802942e-24, DtoaMode.SHORTEST, 0, buffer);
+        assertEquals("4128420500802942", buffer.getRawDigits());
+        assertEquals(-8, buffer.getDecimalPoint());
+        buffer.reset();
+
+        DoubleConversion.bignumDtoa(3.9292015898194142585311918e-10, DtoaMode.SHORTEST, 0, buffer);
+        assertEquals("39292015898194143", buffer.getRawDigits());
+        buffer.reset();
+
+        v = 4194304.0;
+        DoubleConversion.bignumDtoa(v, DtoaMode.FIXED, 5, buffer);
+        assertTrue(5 >= buffer.getLength() - buffer.getDecimalPoint());
+        assertEquals("4194304", trimRepresentation(buffer.getRawDigits()));
+        buffer.reset();
+
+        v = 3.3161339052167390562200598e-237;
+        DoubleConversion.bignumDtoa(v, DtoaMode.PRECISION, 19, buffer);
+        assertTrue(19 >= buffer.getLength());
+        assertEquals("3316133905216739056", trimRepresentation(buffer.getRawDigits()));
+        assertEquals(-236, buffer.getDecimalPoint());
+        buffer.reset();
+
+        v = 7.9885183916008099497815232e+191;
+        DoubleConversion.bignumDtoa(v, DtoaMode.PRECISION, 4, buffer);
+        assertTrue(4 >= buffer.getLength());
+        assertEquals("7989", trimRepresentation(buffer.getRawDigits()));
+        assertEquals(192, buffer.getDecimalPoint());
+        buffer.reset();
+
+        v = 1.0000000000000012800000000e+17;
+        DoubleConversion.bignumDtoa(v, DtoaMode.FIXED, 1, buffer);
+        assertTrue(1 >= buffer.getLength() - buffer.getDecimalPoint());
+        assertEquals("100000000000000128", trimRepresentation(buffer.getRawDigits()));
+        assertEquals(18, buffer.getDecimalPoint());
+        buffer.reset();
+    }
+
+
+    @Test
+    public void testBignumShortest() {
+        new BufferedReader(new InputStreamReader(getClass().getResourceAsStream("resources/gay-shortest.txt")))
+                .lines()
+                .forEach(line -> {
+                    if (line.isEmpty() || line.startsWith("//")) {
+                        return; // comment or empty line
+                    }
+                    final String[] tokens = line.split(",\\s+");
+                    assertEquals(tokens.length, 3, "*" + line + "*");
+                    final double v = Double.parseDouble(tokens[0]);
+                    final String str = tokens[1].replace('"', ' ').trim();;
+                    final int point = Integer.parseInt(tokens[2]);
+                    final DtoaBuffer buffer = new DtoaBuffer(BUFFER_SIZE);
+
+                    DoubleConversion.bignumDtoa(v, DtoaMode.SHORTEST, 0, buffer);
+                    assertEquals(str, buffer.getRawDigits());
+                    assertEquals(point, buffer.getDecimalPoint());
+                });
+    }
+
+    @Test
+    public void testBignumFixed()  {
+        new BufferedReader(new InputStreamReader(getClass().getResourceAsStream("resources/gay-fixed.txt")))
+                .lines()
+                .forEach(line -> {
+                    if (line.isEmpty() || line.startsWith("//")) {
+                        return; // comment or empty line
+                    }
+                    final String[] tokens = line.split(",\\s+");
+                    assertEquals(tokens.length, 4);
+                    final double v = Double.parseDouble(tokens[0]);
+                    final int digits = Integer.parseInt(tokens[1]);
+                    final String str = tokens[2].replace('"', ' ').trim();
+                    final int point = Integer.parseInt(tokens[3]);
+                    final DtoaBuffer buffer = new DtoaBuffer(BUFFER_SIZE);
+
+                    DoubleConversion.bignumDtoa(v, DtoaMode.FIXED, digits, buffer);
+                    assertEquals(str, trimRepresentation(buffer.getRawDigits()));
+                    assertEquals(point, buffer.getDecimalPoint());
+                });
+    }
+
+    @Test
+    public void testBignumPrecision() {
+        new BufferedReader(new InputStreamReader(getClass().getResourceAsStream("resources/gay-precision.txt")))
+                .lines()
+                .forEach(line -> {
+                    if (line.isEmpty() || line.startsWith("//")) {
+                        return; // comment or empty line
+                    }
+                    final String[] tokens = line.split(",\\s+");
+                    assertEquals(tokens.length, 4);
+                    final double v = Double.parseDouble(tokens[0]);
+                    final int digits = Integer.parseInt(tokens[1]);
+                    final String str = tokens[2].replace('"', ' ').trim();
+                    final int point = Integer.parseInt(tokens[3]);
+                    final DtoaBuffer buffer = new DtoaBuffer(BUFFER_SIZE);
+
+                    DoubleConversion.bignumDtoa(v, DtoaMode.PRECISION, digits, buffer);
+                    assertEquals(str, trimRepresentation(buffer.getRawDigits()));
+                    assertEquals(point, buffer.getDecimalPoint());
+                });
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/src/jdk/nashorn/internal/runtime/doubleconv/test/BignumTest.java	Thu Nov 26 01:06:51 2015 +0100
@@ -0,0 +1,1486 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  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.
+ */
+
+// This file is available under and governed by the GNU General Public
+// License version 2 only, as published by the Free Software Foundation.
+// However, the following notice accompanied the original version of this
+// file:
+//
+// Copyright 2010 the V8 project authors. 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 Google Inc. 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.
+
+package jdk.nashorn.internal.runtime.doubleconv.test;
+
+import org.testng.annotations.Test;
+
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Method;
+
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertTrue;
+
+/**
+ * Bignum class tests
+ *
+ * @test
+ * @run testng jdk.nashorn.internal.runtime.doubleconv.test.BignumTest
+ */
+@SuppressWarnings("javadoc")
+public class BignumTest {
+
+    static final Class<?> Bignum;
+    static final Constructor<?> ctor;
+
+    static {
+        try {
+            Bignum = Class.forName("jdk.nashorn.internal.runtime.doubleconv.Bignum");
+            ctor = Bignum.getDeclaredConstructor();
+            ctor.setAccessible(true);
+        } catch (final Exception e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    private static Method method(final String name, final Class<?>... params) throws NoSuchMethodException {
+        final Method m = Bignum.getDeclaredMethod(name, params);
+        m.setAccessible(true);
+        return m;
+    }
+
+    @Test
+    public void testAssign() throws Exception {
+
+        Object bignum = ctor.newInstance();
+        Object bignum2 = ctor.newInstance();
+
+        final Method assignUInt16 = method("assignUInt16", char.class);
+        final Method assignUInt64 = method("assignUInt64", long.class);
+        final Method assignDecimalString = method("assignDecimalString", String.class);
+        final Method assignHexString = method("assignHexString", String.class);
+        final Method toHexString = method("toHexString");
+
+        assignUInt16.invoke(bignum, (char) 0);
+        assertEquals(toHexString.invoke(bignum), "0");
+        assignUInt16.invoke(bignum, (char) 0xA);
+        assertEquals(toHexString.invoke(bignum), "A");
+        assignUInt16.invoke(bignum, (char) 0x20);
+        assertEquals(toHexString.invoke(bignum), "20");
+
+        assignUInt64.invoke(bignum, 0);
+        assertEquals(toHexString.invoke(bignum), "0");
+        assignUInt64.invoke(bignum, 0xA);
+        assertEquals(toHexString.invoke(bignum), "A");
+        assignUInt64.invoke(bignum, 0x20);
+        assertEquals(toHexString.invoke(bignum), "20");
+        assignUInt64.invoke(bignum, 0x100);
+        assertEquals(toHexString.invoke(bignum), "100");
+
+        // The first real test, since this will not fit into one bigit.
+        assignUInt64.invoke(bignum, 0x12345678L);
+        assertEquals(toHexString.invoke(bignum), "12345678");
+
+        assignUInt64.invoke(bignum, 0xFFFFFFFFFFFFFFFFL);
+        assertEquals(toHexString.invoke(bignum), "FFFFFFFFFFFFFFFF");
+
+        assignUInt64.invoke(bignum, 0x123456789ABCDEF0L);
+        assertEquals(toHexString.invoke(bignum), "123456789ABCDEF0");
+
+        assignUInt64.invoke(bignum2, 0x123456789ABCDEF0L);
+        assertEquals(toHexString.invoke(bignum2), "123456789ABCDEF0");
+
+        assignDecimalString.invoke(bignum, "0");
+        assertEquals(toHexString.invoke(bignum), "0");
+
+        assignDecimalString.invoke(bignum, "1");
+        assertEquals(toHexString.invoke(bignum), "1");
+
+        assignDecimalString.invoke(bignum, "1234567890");
+        assertEquals(toHexString.invoke(bignum), "499602D2");
+
+        assignHexString.invoke(bignum, "0");
+        assertEquals(toHexString.invoke(bignum), "0");
+
+        assignHexString.invoke(bignum, "123456789ABCDEF0");
+        assertEquals(toHexString.invoke(bignum), "123456789ABCDEF0");
+    }
+
+    @Test
+    public void testShiftLeft() throws Exception {
+
+        final Object bignum = ctor.newInstance();
+
+        final Method assignHexString = method("assignHexString", String.class);
+        final Method shiftLeft = method("shiftLeft", int.class);
+        final Method toHexString = method("toHexString");
+
+
+        assignHexString.invoke(bignum, "0");
+        shiftLeft.invoke(bignum, 100);
+        assertEquals(toHexString.invoke(bignum), "0");
+
+        assignHexString.invoke(bignum, "1");
+        shiftLeft.invoke(bignum, 1);
+        assertEquals(toHexString.invoke(bignum), "2");
+
+        assignHexString.invoke(bignum, "1");
+        shiftLeft.invoke(bignum, 4);
+        assertEquals(toHexString.invoke(bignum), "10");
+
+        assignHexString.invoke(bignum, "1");
+        shiftLeft.invoke(bignum, 32);
+        assertEquals(toHexString.invoke(bignum), "100000000");
+
+        assignHexString.invoke(bignum, "1");
+        shiftLeft.invoke(bignum, 64);
+        assertEquals(toHexString.invoke(bignum), "10000000000000000");
+
+        assignHexString.invoke(bignum, "123456789ABCDEF");
+        shiftLeft.invoke(bignum, 64);
+        assertEquals(toHexString.invoke(bignum), "123456789ABCDEF0000000000000000");
+        shiftLeft.invoke(bignum, 1);
+        assertEquals(toHexString.invoke(bignum), "2468ACF13579BDE0000000000000000");
+    }
+
+
+
+    @Test
+    public void testAddUInt64() throws Exception {
+
+        final Object bignum = ctor.newInstance();
+
+        final Method addUInt64 = method("addUInt64", long.class);
+        final Method assignUInt16 = method("assignUInt16", char.class);
+        final Method assignHexString = method("assignHexString", String.class);
+        final Method shiftLeft = method("shiftLeft", int.class);
+        final Method toHexString = method("toHexString");
+
+        assignHexString.invoke(bignum, "0");
+        addUInt64.invoke(bignum, 0xA);
+        assertEquals(toHexString.invoke(bignum), "A");
+
+        assignHexString.invoke(bignum, "1");
+        addUInt64.invoke(bignum, 0xA);
+        assertEquals(toHexString.invoke(bignum), "B");
+
+        assignHexString.invoke(bignum, "1");
+        addUInt64.invoke(bignum, 0x100);
+        assertEquals(toHexString.invoke(bignum), "101");
+
+        assignHexString.invoke(bignum, "1");
+        addUInt64.invoke(bignum, 0xFFFF);
+        assertEquals(toHexString.invoke(bignum), "10000");
+
+        assignHexString.invoke(bignum, "FFFFFFF");
+        addUInt64.invoke(bignum, 0x1);
+        assertEquals(toHexString.invoke(bignum), "10000000");
+
+        assignHexString.invoke(bignum, "10000000000000000000000000000000000000000000");
+        addUInt64.invoke(bignum, 0xFFFF);
+        assertEquals(toHexString.invoke(bignum), "1000000000000000000000000000000000000000FFFF");
+
+        assignHexString.invoke(bignum, "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF");
+        addUInt64.invoke(bignum, 0x1);
+        assertEquals(toHexString.invoke(bignum), "100000000000000000000000000000000000000000000");
+
+        assignHexString.invoke(bignum, "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF");
+        addUInt64.invoke(bignum, 0x1);
+        assertEquals(toHexString.invoke(bignum), "100000000000000000000000000000000000000000000");
+
+        assignUInt16.invoke(bignum, (char) 0x1);
+        shiftLeft.invoke(bignum, 100);
+        addUInt64.invoke(bignum, 1);
+        assertEquals(toHexString.invoke(bignum), "10000000000000000000000001");
+
+        assignUInt16.invoke(bignum, (char) 0x1);
+        shiftLeft.invoke(bignum, 100);
+        addUInt64.invoke(bignum, 0xFFFF);
+        assertEquals(toHexString.invoke(bignum), "1000000000000000000000FFFF");
+
+        assignHexString.invoke(bignum, "0");
+        addUInt64.invoke(bignum, 0xA00000000L);
+        assertEquals(toHexString.invoke(bignum), "A00000000");
+
+        assignHexString.invoke(bignum, "1");
+        addUInt64.invoke(bignum, 0xA00000000L);
+        assertEquals(toHexString.invoke(bignum), "A00000001");
+
+        assignHexString.invoke(bignum, "1");
+        addUInt64.invoke(bignum, 0x10000000000L);
+        assertEquals(toHexString.invoke(bignum), "10000000001");
+
+        assignHexString.invoke(bignum, "1");
+        addUInt64.invoke(bignum, 0xFFFF00000000L);
+        assertEquals(toHexString.invoke(bignum), "FFFF00000001");
+
+        assignHexString.invoke(bignum, "FFFFFFF");
+        addUInt64.invoke(bignum, 0x100000000L);
+        assertEquals(toHexString.invoke(bignum), "10FFFFFFF");
+
+        assignHexString.invoke(bignum, "10000000000000000000000000000000000000000000");
+        addUInt64.invoke(bignum, 0xFFFF00000000L);
+        assertEquals(toHexString.invoke(bignum), "10000000000000000000000000000000FFFF00000000");
+
+        assignHexString.invoke(bignum, "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF");
+        addUInt64.invoke(bignum, 0x100000000L);
+        assertEquals(toHexString.invoke(bignum), "1000000000000000000000000000000000000FFFFFFFF");
+
+        assignUInt16.invoke(bignum, (char) 0x1);
+        shiftLeft.invoke(bignum, 100);
+        addUInt64.invoke(bignum, 0x100000000L);
+        assertEquals(toHexString.invoke(bignum), "10000000000000000100000000");
+
+        assignUInt16.invoke(bignum, (char) 0x1);
+        shiftLeft.invoke(bignum, 100);
+        addUInt64.invoke(bignum, 0xFFFF00000000L);
+        assertEquals(toHexString.invoke(bignum), "10000000000000FFFF00000000");
+    }
+
+    @Test
+    public void testAddBignum() throws Exception {
+
+        final Object bignum = ctor.newInstance();
+        final Object other = ctor.newInstance();
+
+        final Method addBignum = method("addBignum", Bignum);
+        final Method assignUInt16 = method("assignUInt16", char.class);
+        final Method assignHexString = method("assignHexString", String.class);
+        final Method shiftLeft = method("shiftLeft", int.class);
+        final Method toHexString = method("toHexString");
+
+        assignHexString.invoke(other, "1");
+        assignHexString.invoke(bignum, "0");
+        addBignum.invoke(bignum, other);
+        assertEquals(toHexString.invoke(bignum), "1");
+
+        assignHexString.invoke(bignum, "1");
+        addBignum.invoke(bignum, other);
+        assertEquals(toHexString.invoke(bignum), "2");
+
+        assignHexString.invoke(bignum, "FFFFFFF");
+        addBignum.invoke(bignum, other);
+        assertEquals(toHexString.invoke(bignum), "10000000");
+
+        assignHexString.invoke(bignum, "FFFFFFFFFFFFFF");
+        addBignum.invoke(bignum, other);
+        assertEquals(toHexString.invoke(bignum), "100000000000000");
+
+        assignHexString.invoke(bignum, "10000000000000000000000000000000000000000000");
+        addBignum.invoke(bignum, other);
+        assertEquals(toHexString.invoke(bignum), "10000000000000000000000000000000000000000001");
+
+        assignHexString.invoke(other, "1000000000000");
+
+        assignHexString.invoke(bignum, "1");
+        addBignum.invoke(bignum, other);
+        assertEquals(toHexString.invoke(bignum), "1000000000001");
+
+        assignHexString.invoke(bignum, "FFFFFFF");
+        addBignum.invoke(bignum, other);
+        assertEquals(toHexString.invoke(bignum), "100000FFFFFFF");
+
+        assignHexString.invoke(bignum, "10000000000000000000000000000000000000000000");
+        addBignum.invoke(bignum, other);
+        assertEquals(toHexString.invoke(bignum), "10000000000000000000000000000001000000000000");
+
+        assignHexString.invoke(bignum, "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF");
+        addBignum.invoke(bignum, other);
+        assertEquals(toHexString.invoke(bignum), "1000000000000000000000000000000FFFFFFFFFFFF");
+
+        assignUInt16.invoke(bignum, (char) 0x1);
+        shiftLeft.invoke(bignum, 100);
+        addBignum.invoke(bignum, other);
+        assertEquals(toHexString.invoke(bignum), "10000000000001000000000000");
+
+        shiftLeft.invoke(other, 64);
+        // other == "10000000000000000000000000000"
+
+        assignUInt16.invoke(bignum, (char) 0x1);
+        addBignum.invoke(bignum, other);
+        assertEquals(toHexString.invoke(bignum), "10000000000000000000000000001");
+
+        assignHexString.invoke(bignum, "FFFFFFF");
+        addBignum.invoke(bignum, other);
+        assertEquals(toHexString.invoke(bignum), "1000000000000000000000FFFFFFF");
+
+        assignHexString.invoke(bignum, "10000000000000000000000000000000000000000000");
+        addBignum.invoke(bignum, other);
+        assertEquals(toHexString.invoke(bignum), "10000000000000010000000000000000000000000000");
+
+        assignHexString.invoke(bignum, "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF");
+        addBignum.invoke(bignum, other);
+        assertEquals(toHexString.invoke(bignum), "100000000000000FFFFFFFFFFFFFFFFFFFFFFFFFFFF");
+
+        assignUInt16.invoke(bignum, (char) 0x1);
+        shiftLeft.invoke(bignum, 100);
+        addBignum.invoke(bignum, other);
+        assertEquals(toHexString.invoke(bignum), "10010000000000000000000000000");
+    }
+
+
+    @Test
+    public void testSubtractBignum() throws Exception {
+
+        final Object bignum = ctor.newInstance();
+        final Object other = ctor.newInstance();
+
+        final Method assignUInt16 = method("assignUInt16", char.class);
+        final Method assignHexString = method("assignHexString", String.class);
+        final Method shiftLeft = method("shiftLeft", int.class);
+        final Method subtractBignum = method("subtractBignum", Bignum);
+
+        final Method toHexString = method("toHexString");
+
+        assignHexString.invoke(bignum, "1");
+        assignHexString.invoke(other, "0");
+        subtractBignum.invoke(bignum, other);
+        assertEquals(toHexString.invoke(bignum), "1");
+
+        assignHexString.invoke(bignum, "2");
+        assignHexString.invoke(other, "0");
+        subtractBignum.invoke(bignum, other);
+        assertEquals(toHexString.invoke(bignum), "2");
+
+        assignHexString.invoke(bignum, "10000000");
+        assignHexString.invoke(other, "1");
+        subtractBignum.invoke(bignum, other);
+        assertEquals(toHexString.invoke(bignum), "FFFFFFF");
+
+        assignHexString.invoke(bignum, "100000000000000");
+        assignHexString.invoke(other, "1");
+        subtractBignum.invoke(bignum, other);
+        assertEquals(toHexString.invoke(bignum), "FFFFFFFFFFFFFF");
+
+        assignHexString.invoke(bignum, "10000000000000000000000000000000000000000001");
+        assignHexString.invoke(other, "1");
+        subtractBignum.invoke(bignum, other);
+        assertEquals(toHexString.invoke(bignum), "10000000000000000000000000000000000000000000");
+
+        assignHexString.invoke(bignum, "1000000000001");
+        assignHexString.invoke(other, "1000000000000");
+        subtractBignum.invoke(bignum, other);
+        assertEquals(toHexString.invoke(bignum), "1");
+
+        assignHexString.invoke(bignum, "100000FFFFFFF");
+        assignHexString.invoke(other, "1000000000000");
+        subtractBignum.invoke(bignum, other);
+        assertEquals(toHexString.invoke(bignum), "FFFFFFF");
+
+        assignHexString.invoke(bignum, "10000000000000000000000000000001000000000000");
+        assignHexString.invoke(other, "1000000000000");
+        subtractBignum.invoke(bignum, other);
+        assertEquals(toHexString.invoke(bignum), "10000000000000000000000000000000000000000000");
+
+        assignHexString.invoke(bignum, "1000000000000000000000000000000FFFFFFFFFFFF");
+        assignHexString.invoke(other, "1000000000000");
+        subtractBignum.invoke(bignum, other);
+        assertEquals(toHexString.invoke(bignum), "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF");
+
+        assignUInt16.invoke(bignum, (char) 0x1);
+        shiftLeft.invoke(bignum, 100);
+        // "10 0000 0000 0000 0000 0000 0000"
+        assignHexString.invoke(other, "1000000000000");
+        subtractBignum.invoke(bignum, other);
+        assertEquals(toHexString.invoke(bignum), "FFFFFFFFFFFFF000000000000");
+
+        assignHexString.invoke(other, "1000000000000");
+        shiftLeft.invoke(other, 48);
+        // other == "1000000000000000000000000"
+
+        assignUInt16.invoke(bignum, (char) 0x1);
+        shiftLeft.invoke(bignum, 100);
+        // bignum == "10000000000000000000000000"
+        subtractBignum.invoke(bignum, other);
+        assertEquals(toHexString.invoke(bignum), "F000000000000000000000000");
+
+        assignUInt16.invoke(other, (char) 0x1);
+        shiftLeft.invoke(other, 35);
+        // other == "800000000"
+        assignHexString.invoke(bignum, "FFFFFFF");
+        shiftLeft.invoke(bignum, 60);
+        // bignum = FFFFFFF000000000000000
+        subtractBignum.invoke(bignum, other);
+        assertEquals(toHexString.invoke(bignum), "FFFFFFEFFFFFF800000000");
+
+        assignHexString.invoke(bignum, "10000000000000000000000000000000000000000000");
+        subtractBignum.invoke(bignum, other);
+        assertEquals(toHexString.invoke(bignum), "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF800000000");
+
+        assignHexString.invoke(bignum, "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF");
+        subtractBignum.invoke(bignum, other);
+        assertEquals(toHexString.invoke(bignum), "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF7FFFFFFFF");
+    }
+
+
+    @Test
+    public void testMultiplyUInt32() throws Exception {
+
+        final Object bignum = ctor.newInstance();
+
+        final Method assignHexString = method("assignHexString", String.class);
+        final Method assignDecimalString = method("assignDecimalString", String.class);
+        final Method assignUInt16 = method("assignUInt16", char.class);
+        final Method multiplyByUInt32 = method("multiplyByUInt32", int.class);
+        final Method shiftLeft = method("shiftLeft", int.class);
+        final Method toHexString = method("toHexString");
+
+        assignHexString.invoke(bignum, "0");
+        multiplyByUInt32.invoke(bignum, 0x25);
+        assertEquals(toHexString.invoke(bignum), "0");
+
+        assignHexString.invoke(bignum, "2");
+        multiplyByUInt32.invoke(bignum, 0x5);
+        assertEquals(toHexString.invoke(bignum), "A");
+
+        assignHexString.invoke(bignum, "10000000");
+        multiplyByUInt32.invoke(bignum, 0x9);
+        assertEquals(toHexString.invoke(bignum), "90000000");
+
+        assignHexString.invoke(bignum, "100000000000000");
+        multiplyByUInt32.invoke(bignum, 0xFFFF);
+        assertEquals(toHexString.invoke(bignum), "FFFF00000000000000");
+
+        assignHexString.invoke(bignum, "100000000000000");
+        multiplyByUInt32.invoke(bignum, 0xFFFFFFFF);
+        assertEquals(toHexString.invoke(bignum), "FFFFFFFF00000000000000");
+
+        assignHexString.invoke(bignum, "1234567ABCD");
+        multiplyByUInt32.invoke(bignum, 0xFFF);
+        assertEquals(toHexString.invoke(bignum), "12333335552433");
+
+        assignHexString.invoke(bignum, "1234567ABCD");
+        multiplyByUInt32.invoke(bignum, 0xFFFFFFF);
+        assertEquals(toHexString.invoke(bignum), "12345679998A985433");
+
+
+        assignHexString.invoke(bignum, "FFFFFFFFFFFFFFFF");
+        multiplyByUInt32.invoke(bignum, 0x2);
+        assertEquals(toHexString.invoke(bignum), "1FFFFFFFFFFFFFFFE");
+
+        assignHexString.invoke(bignum, "FFFFFFFFFFFFFFFF");
+        multiplyByUInt32.invoke(bignum, 0x4);
+        assertEquals(toHexString.invoke(bignum), "3FFFFFFFFFFFFFFFC");
+
+        assignHexString.invoke(bignum, "FFFFFFFFFFFFFFFF");
+        multiplyByUInt32.invoke(bignum, 0xF);
+        assertEquals(toHexString.invoke(bignum), "EFFFFFFFFFFFFFFF1");
+
+        assignHexString.invoke(bignum, "FFFFFFFFFFFFFFFF");
+        multiplyByUInt32.invoke(bignum, 0xFFFFFF);
+        assertEquals(toHexString.invoke(bignum), "FFFFFEFFFFFFFFFF000001");
+
+        assignUInt16.invoke(bignum, (char) 0x1);
+        shiftLeft.invoke(bignum, 100);
+        // "10 0000 0000 0000 0000 0000 0000"
+        multiplyByUInt32.invoke(bignum, 2);
+        assertEquals(toHexString.invoke(bignum), "20000000000000000000000000");
+
+        assignUInt16.invoke(bignum, (char) 0x1);
+        shiftLeft.invoke(bignum, 100);
+        // "10 0000 0000 0000 0000 0000 0000"
+        multiplyByUInt32.invoke(bignum, 0xF);
+        assertEquals(toHexString.invoke(bignum), "F0000000000000000000000000");
+
+        assignUInt16.invoke(bignum, (char) 0xFFFF);
+        shiftLeft.invoke(bignum, 100);
+        // "FFFF0 0000 0000 0000 0000 0000 0000"
+        multiplyByUInt32.invoke(bignum, 0xFFFF);
+        assertEquals(toHexString.invoke(bignum), "FFFE00010000000000000000000000000");
+
+        assignUInt16.invoke(bignum, (char) 0xFFFF);
+        shiftLeft.invoke(bignum, 100);
+        // "FFFF0 0000 0000 0000 0000 0000 0000"
+        multiplyByUInt32.invoke(bignum, 0xFFFFFFFF);
+        assertEquals(toHexString.invoke(bignum), "FFFEFFFF00010000000000000000000000000");
+
+        assignUInt16.invoke(bignum, (char) 0xFFFF);
+        shiftLeft.invoke(bignum, 100);
+        // "FFFF0 0000 0000 0000 0000 0000 0000"
+        multiplyByUInt32.invoke(bignum, 0xFFFFFFFF);
+        assertEquals(toHexString.invoke(bignum), "FFFEFFFF00010000000000000000000000000");
+
+        assignDecimalString.invoke(bignum, "15611230384529777");
+        multiplyByUInt32.invoke(bignum, 10000000);
+        assertEquals(toHexString.invoke(bignum), "210EDD6D4CDD2580EE80");
+    }
+
+
+
+    @Test
+    public void testMultiplyUInt64() throws Exception {
+
+        final Object bignum = ctor.newInstance();
+
+        final Method assignUInt16 = method("assignUInt16", char.class);
+        final Method assignDecimalString = method("assignDecimalString", String.class);
+        final Method assignHexString = method("assignHexString", String.class);
+        final Method multiplyByUInt64 = method("multiplyByUInt64", long.class);
+        final Method shiftLeft = method("shiftLeft", int.class);
+        final Method toHexString = method("toHexString");
+
+        assignHexString.invoke(bignum, "0");
+        multiplyByUInt64.invoke(bignum, 0x25);
+        assertEquals(toHexString.invoke(bignum), "0");
+
+        assignHexString.invoke(bignum, "2");
+        multiplyByUInt64.invoke(bignum, 0x5);
+        assertEquals(toHexSt