8027043: Turn global accesses into MethodHandle.constant, with one chance of reassignment, e.g. x = value occuring once in the global scope is ok, twice is not.
authorlagergren
Mon, 31 Mar 2014 14:13:34 +0200
changeset 24733 1e825be55fd1
parent 24732 e7d905b01c08
child 24734 da070553a8e1
8027043: Turn global accesses into MethodHandle.constant, with one chance of reassignment, e.g. x = value occuring once in the global scope is ok, twice is not. Reviewed-by: attila, sundar, jlaskey
nashorn/bin/runoptdualcatch9.sh
nashorn/src/jdk/nashorn/api/scripting/NashornScriptEngine.java
nashorn/src/jdk/nashorn/internal/codegen/CompilationEnvironment.java
nashorn/src/jdk/nashorn/internal/codegen/ObjectClassGenerator.java
nashorn/src/jdk/nashorn/internal/codegen/SpillObjectCreator.java
nashorn/src/jdk/nashorn/internal/lookup/MethodHandleFactory.java
nashorn/src/jdk/nashorn/internal/objects/ArrayBufferView.java
nashorn/src/jdk/nashorn/internal/objects/Global.java
nashorn/src/jdk/nashorn/internal/objects/NativeArray.java
nashorn/src/jdk/nashorn/internal/objects/NativeDataView.java
nashorn/src/jdk/nashorn/internal/objects/NativeError.java
nashorn/src/jdk/nashorn/internal/runtime/AccessorProperty.java
nashorn/src/jdk/nashorn/internal/runtime/Context.java
nashorn/src/jdk/nashorn/internal/runtime/DebugLogger.java
nashorn/src/jdk/nashorn/internal/runtime/GlobalConstants.java
nashorn/src/jdk/nashorn/internal/runtime/JSType.java
nashorn/src/jdk/nashorn/internal/runtime/RecompilableScriptFunctionData.java
nashorn/src/jdk/nashorn/internal/runtime/RewriteException.java
nashorn/src/jdk/nashorn/internal/runtime/RuntimeEvent.java
nashorn/src/jdk/nashorn/internal/runtime/ScriptFunctionData.java
nashorn/src/jdk/nashorn/internal/runtime/ScriptObject.java
nashorn/src/jdk/nashorn/internal/runtime/ScriptRuntime.java
nashorn/src/jdk/nashorn/internal/runtime/SetMethodCreator.java
nashorn/src/jdk/nashorn/internal/runtime/WithObject.java
nashorn/src/jdk/nashorn/internal/runtime/linker/NashornGuards.java
nashorn/test/script/basic/JDK-8010697.js
nashorn/test/script/basic/JDK-8010697.js.EXPECTED
nashorn/test/script/basic/JDK-8022903.js
nashorn/test/script/basic/JDK-8022903.js.EXPECTED
nashorn/test/script/basic/JDK-8027042.js
nashorn/test/script/basic/JDK-8027042.js.EXPECTED
nashorn/test/script/currently-failing/JDK-8010697.js
nashorn/test/script/currently-failing/JDK-8010697.js.EXPECTED
nashorn/test/src/jdk/nashorn/api/scripting/ScopeTest.java
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/bin/runoptdualcatch9.sh	Mon Mar 31 14:13:34 2014 +0200
@@ -0,0 +1,32 @@
+#!/bin/sh
+
+#FLAGS="-Djava.lang.invoke.MethodHandle.COMPILE_THRESHOLD=3 -Djava.lang.invoke.MethodHandle.DUMP_CLASS_FILES=true -Djava.lang.invoke.MethodHandle.TRACE_METHOD_LINKAGE=true -Djava.lang.invoke.MethodHandle.TRACE_INTERPRETER=true"
+
+FILENAME="./optimistic_dual_catch_$(date|sed "s/ /_/g"|sed "s/:/_/g").jfr"
+
+DIR=..
+FAST_CATCH_COMBINATOR=
+#$DIR/bin/fastCatchCombinator.jar
+NASHORN_JAR=$DIR/dist/nashorn.jar
+
+$JAVA_HOME/bin/java \
+$FLAGS \
+-ea \
+-esa \
+-Xbootclasspath/p:$FAST_CATCH_COMBINATOR:$NASHORN_JAR \
+-Xms2G -Xmx2G \
+-XX:+UnlockCommercialFeatures \
+-XX:TypeProfileLevel=222 \
+-XX:+UnlockExperimentalVMOptions \
+-XX:+UnlockDiagnosticVMOptions \
+-cp $CLASSPATH:../build/test/classes/ \
+jdk.nashorn.tools.Shell ${@}
+
+#-XX:+FlightRecorder \
+#-XX:FlightRecorderOptions=defaultrecording=true,disk=true,dumponexit=true,dumponexitpath=$FILENAME,stackdepth=1024 \
+#-XX:+UseTypeSpeculation \
+#-XX:+UseMathExactIntrinsics \
+#-XX:+ShowHiddenFrames \
+#-XX:+PrintOptoAssembly \
+#-XX:-TieredCompilation \
+#-XX:CICompilerCount=1 \
--- a/nashorn/src/jdk/nashorn/api/scripting/NashornScriptEngine.java	Thu Mar 27 14:09:40 2014 +0100
+++ b/nashorn/src/jdk/nashorn/api/scripting/NashornScriptEngine.java	Mon Mar 31 14:13:34 2014 +0200
@@ -126,7 +126,6 @@
     }
 
     // load engine.js and return content as a char[]
-    @SuppressWarnings("resource")
     private static char[] loadEngineJSSource() {
         final String script = "resources/engine.js";
         try {
--- a/nashorn/src/jdk/nashorn/internal/codegen/CompilationEnvironment.java	Thu Mar 27 14:09:40 2014 +0100
+++ b/nashorn/src/jdk/nashorn/internal/codegen/CompilationEnvironment.java	Mon Mar 31 14:13:34 2014 +0200
@@ -42,6 +42,7 @@
 import jdk.nashorn.internal.ir.IndexNode;
 import jdk.nashorn.internal.ir.Optimistic;
 import jdk.nashorn.internal.objects.NativeArray;
+import jdk.nashorn.internal.runtime.JSType;
 import jdk.nashorn.internal.runtime.FindProperty;
 import jdk.nashorn.internal.runtime.Property;
 import jdk.nashorn.internal.runtime.RecompilableScriptFunctionData;
@@ -435,10 +436,10 @@
 
         // Safely evaluate the property, and return the narrowest type for the actual value (e.g. Type.INT for a boxed
         // integer).
-        return Type.typeFor(ObjectClassGenerator.unboxedFieldType(property.getObjectValue(owner, owner)));
+        return Type.typeFor(JSType.unboxedFieldType(property.getObjectValue(owner, owner)));
     }
 
-    private Object evaluateSafely(Expression expr) {
+    private Object evaluateSafely(final Expression expr) {
         if(expr instanceof IdentNode) {
             return runtimeScope == null ? null : evaluatePropertySafely(runtimeScope, ((IdentNode)expr).getName());
         } else if(expr instanceof AccessNode) {
--- a/nashorn/src/jdk/nashorn/internal/codegen/ObjectClassGenerator.java	Thu Mar 27 14:09:40 2014 +0100
+++ b/nashorn/src/jdk/nashorn/internal/codegen/ObjectClassGenerator.java	Mon Mar 31 14:13:34 2014 +0200
@@ -779,29 +779,6 @@
     }
 
     /**
-     * Get the unboxed (primitive) type for an object
-     * @param o object
-     * @return primive type or Object.class if not primitive
-     */
-    public static Class<?> unboxedFieldType(final Object o) {
-        if (OBJECT_FIELDS_ONLY) {
-            return Object.class;
-        }
-
-        if (o == null) {
-            return Object.class;
-        } else if (o.getClass() == Integer.class) {
-            return int.class;
-        } else if (o.getClass() == Long.class) {
-            return long.class;
-        } else if (o.getClass() == Double.class) {
-            return double.class;
-        } else {
-            return Object.class;
-        }
-    }
-
-    /**
      * Add padding to field count to avoid creating too many classes and have some spare fields
      * @param count the field count
      * @return the padded field count
--- a/nashorn/src/jdk/nashorn/internal/codegen/SpillObjectCreator.java	Thu Mar 27 14:09:40 2014 +0100
+++ b/nashorn/src/jdk/nashorn/internal/codegen/SpillObjectCreator.java	Mon Mar 31 14:13:34 2014 +0200
@@ -28,13 +28,12 @@
 import static jdk.nashorn.internal.codegen.CompilerConstants.constructorNoLookup;
 import static jdk.nashorn.internal.codegen.CompilerConstants.virtualCallNoLookup;
 import static jdk.nashorn.internal.codegen.ObjectClassGenerator.OBJECT_FIELDS_ONLY;
-import static jdk.nashorn.internal.codegen.ObjectClassGenerator.unboxedFieldType;
-
 import java.util.LinkedHashSet;
 import java.util.List;
 import java.util.Set;
 import jdk.nashorn.internal.ir.Expression;
 import jdk.nashorn.internal.ir.LiteralNode;
+import jdk.nashorn.internal.runtime.JSType;
 import jdk.nashorn.internal.runtime.Property;
 import jdk.nashorn.internal.runtime.PropertyMap;
 import jdk.nashorn.internal.runtime.ScriptObject;
@@ -84,7 +83,7 @@
                     final Property property = propertyMap.findProperty(key);
                     if (property != null) {
                         // normal property key
-                        property.setCurrentType(unboxedFieldType(constantValue));
+                        property.setCurrentType(JSType.unboxedFieldType(constantValue));
                         final int slot = property.getSlot();
                         if (!OBJECT_FIELDS_ONLY && constantValue instanceof Number) {
                             jpresetValues[slot] = ObjectClassGenerator.pack((Number)constantValue);
--- a/nashorn/src/jdk/nashorn/internal/lookup/MethodHandleFactory.java	Thu Mar 27 14:09:40 2014 +0100
+++ b/nashorn/src/jdk/nashorn/internal/lookup/MethodHandleFactory.java	Mon Mar 31 14:13:34 2014 +0200
@@ -139,12 +139,11 @@
      * @return return value unmodified
      */
     static Object traceReturn(final DebugLogger logger, final Object value) {
-        final String str = "\treturn" +
+        final String str = "    return" +
                 (VOID_TAG.equals(value) ?
                     ";" :
                     " " + stripName(value) + "; // [type=" + (value == null ? "null" : stripName(value.getClass()) + ']'));
         logger.log(TRACE_LEVEL, str);
-        logger.log(TRACE_LEVEL, Debug.firstJSFrame());
         return value;
     }
 
@@ -225,12 +224,13 @@
      * Add a debug printout to a method handle, tracing parameters and return values
      *
      * @param logger a specific logger to which to write the output
+     * @param level level over which to print
      * @param mh  method handle to trace
      * @param tag start of trace message
      * @return traced method handle
      */
-    public static MethodHandle addDebugPrintout(final DebugLogger logger, final MethodHandle mh, final Object tag) {
-        return addDebugPrintout(logger, mh, 0, true, tag);
+    public static MethodHandle addDebugPrintout(final DebugLogger logger, final Level level, final MethodHandle mh, final Object tag) {
+        return addDebugPrintout(logger, level, mh, 0, true, tag);
     }
 
 
@@ -238,18 +238,19 @@
      * Add a debug printout to a method handle, tracing parameters and return values
      *
      * @param logger a specific logger to which to write the output
+     * @param level level over which to print
      * @param mh  method handle to trace
      * @param paramStart first param to print/trace
      * @param printReturnValue should we print/trace return value if available?
      * @param tag start of trace message
      * @return  traced method handle
      */
-    public static MethodHandle addDebugPrintout(final DebugLogger logger, final MethodHandle mh, final int paramStart, final boolean printReturnValue, final Object tag) {
+    public static MethodHandle addDebugPrintout(final DebugLogger logger, final Level level, final MethodHandle mh, final int paramStart, final boolean printReturnValue, final Object tag) {
         final MethodType type = mh.type();
 
         //if there is no logger, or if it's set to log only coarser events
         //than the trace level, skip and return
-        if (logger != null && logger.levelCoarserThan(TRACE_LEVEL)) {
+        if (logger != null && logger.levelCoarserThan(level)) {
             return mh;
         }
 
@@ -501,7 +502,7 @@
         }
 
         public MethodHandle debug(final MethodHandle master, final String str, final Object... args) {
-            return addDebugPrintout(LOG, master, Integer.MAX_VALUE, false, str + ' ' + describe(args));
+            return addDebugPrintout(LOG, Level.INFO, master, Integer.MAX_VALUE, false, str + ' ' + describe(args));
         }
 
         @Override
--- a/nashorn/src/jdk/nashorn/internal/objects/ArrayBufferView.java	Thu Mar 27 14:09:40 2014 +0100
+++ b/nashorn/src/jdk/nashorn/internal/objects/ArrayBufferView.java	Mon Mar 31 14:13:34 2014 +0200
@@ -201,7 +201,7 @@
     }
 
     protected static Object setImpl(final Object self, final Object array, final Object offset0) {
-        final ArrayBufferView dest = ((ArrayBufferView)self);
+        final ArrayBufferView dest = (ArrayBufferView)self;
         final int length;
         if (array instanceof ArrayBufferView) {
             // void set(TypedArray array, optional unsigned long offset)
@@ -245,7 +245,7 @@
     }
 
     protected static Object subarrayImpl(final Object self, final Object begin0, final Object end0) {
-        final ArrayBufferView arrayView       = ((ArrayBufferView)self);
+        final ArrayBufferView arrayView       = (ArrayBufferView)self;
         final int             byteOffset      = arrayView.byteOffset;
         final int             bytesPerElement = arrayView.bytesPerElement();
         final int             elementLength   = arrayView.elementLength();
--- a/nashorn/src/jdk/nashorn/internal/objects/Global.java	Thu Mar 27 14:09:40 2014 +0100
+++ b/nashorn/src/jdk/nashorn/internal/objects/Global.java	Mon Mar 31 14:13:34 2014 +0200
@@ -47,6 +47,7 @@
 import jdk.nashorn.internal.objects.annotations.ScriptClass;
 import jdk.nashorn.internal.runtime.ConsString;
 import jdk.nashorn.internal.runtime.Context;
+import jdk.nashorn.internal.runtime.GlobalConstants;
 import jdk.nashorn.internal.runtime.GlobalFunctions;
 import jdk.nashorn.internal.runtime.JSType;
 import jdk.nashorn.internal.runtime.NativeJavaPackage;
@@ -425,6 +426,7 @@
         super(checkAndGetMap(context));
         this.context = context;
         this.setIsScope();
+        GlobalConstants.instance().invalidateAll();
     }
 
     /**
@@ -890,7 +892,7 @@
      * @param self  self reference
      * @param code  exit code
      *
-     * @return undefined (will never be reacheD)
+     * @return undefined (will never be reached)
      */
     public static Object exit(final Object self, final Object code) {
         System.exit(JSType.toInt32(code));
@@ -1867,6 +1869,8 @@
                 res.setInitialProto(getObjectPrototype());
             }
 
+            res.setIsBuiltin();
+
             return res;
 
         } catch (final ClassNotFoundException | InstantiationException | IllegalAccessException e) {
@@ -1973,4 +1977,9 @@
         this.lastRegExpResult = regExpResult;
     }
 
+    @Override
+    protected boolean isGlobal() {
+        return true;
+    }
+
 }
--- a/nashorn/src/jdk/nashorn/internal/objects/NativeArray.java	Thu Mar 27 14:09:40 2014 +0100
+++ b/nashorn/src/jdk/nashorn/internal/objects/NativeArray.java	Mon Mar 31 14:13:34 2014 +0200
@@ -134,8 +134,8 @@
 
     NativeArray(final ArrayData arrayData, final Global global) {
         super(global.getArrayPrototype(), $nasgenmap$);
-        this.setArray(arrayData);
-        this.setIsArray();
+        setArray(arrayData);
+        setIsArray();
     }
 
     @Override
@@ -307,7 +307,7 @@
             }
 
             // Step 3h and 3i
-            final boolean newWritable = (!newLenDesc.has(WRITABLE) || newLenDesc.isWritable());
+            final boolean newWritable = !newLenDesc.has(WRITABLE) || newLenDesc.isWritable();
             if (!newWritable) {
                 newLenDesc.setWritable(true);
             }
@@ -405,7 +405,7 @@
      */
     @Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR)
     public static Object isArray(final Object self, final Object arg) {
-        return isArray(arg) || (arg instanceof JSObject && ((JSObject)arg).isArray());
+        return isArray(arg) || arg instanceof JSObject && ((JSObject)arg).isArray();
     }
 
     /**
@@ -716,7 +716,7 @@
     private static void concatToList(final ArrayList<Object> list, final Object obj) {
         final boolean isScriptArray = isArray(obj);
         final boolean isScriptObject = isScriptArray || obj instanceof ScriptObject;
-        if (isScriptArray || obj instanceof Iterable || (obj != null && obj.getClass().isArray())) {
+        if (isScriptArray || obj instanceof Iterable || obj != null && obj.getClass().isArray()) {
             final Iterator<Object> iter = arrayLikeIterator(obj, true);
             if (iter.hasNext()) {
                 for (int i = 0; iter.hasNext(); ++i) {
@@ -979,7 +979,7 @@
             } else {
                 boolean hasPrevious = true;
                 for (long k = 1; k < len; k++) {
-                    boolean hasCurrent = sobj.has(k);
+                    final boolean hasCurrent = sobj.has(k);
                     if (hasCurrent) {
                         sobj.set(k - 1, sobj.get(k), true);
                     } else if (hasPrevious) {
@@ -1016,7 +1016,7 @@
         final ScriptObject sobj                = (ScriptObject)obj;
         final long         len                 = JSType.toUint32(sobj.getLength());
         final long         relativeStart       = JSType.toLong(start);
-        final long         relativeEnd         = (end == ScriptRuntime.UNDEFINED) ? len : JSType.toLong(end);
+        final long         relativeEnd         = end == ScriptRuntime.UNDEFINED ? len : JSType.toLong(end);
 
         long k = relativeStart < 0 ? Math.max(len + relativeStart, 0) : Math.min(relativeStart, len);
         final long finale = relativeEnd < 0 ? Math.max(len + relativeEnd, 0) : Math.min(relativeEnd, len);
@@ -1146,8 +1146,8 @@
             return ScriptRuntime.UNDEFINED;
         }
 
-        final Object start = (args.length > 0) ? args[0] : ScriptRuntime.UNDEFINED;
-        final Object deleteCount = (args.length > 1) ? args[1] : ScriptRuntime.UNDEFINED;
+        final Object start = args.length > 0 ? args[0] : ScriptRuntime.UNDEFINED;
+        final Object deleteCount = args.length > 1 ? args[1] : ScriptRuntime.UNDEFINED;
 
         Object[] items;
 
@@ -1176,7 +1176,7 @@
                 for (int i = 0; i < items.length; i++, k++) {
                     sobj.defineOwnProperty(k, items[i]);
                 }
-            } catch (UnsupportedOperationException uoe) {
+            } catch (final UnsupportedOperationException uoe) {
                 returnValue = slowSplice(sobj, actualStart, actualDeleteCount, items, len);
             }
         } else {
@@ -1199,7 +1199,7 @@
         }
 
         if (items.length < deleteCount) {
-            for (long k = start; k < (len - deleteCount); k++) {
+            for (long k = start; k < len - deleteCount; k++) {
                 final long from = k + deleteCount;
                 final long to   = k + items.length;
 
@@ -1210,7 +1210,7 @@
                 }
             }
 
-            for (long k = len; k > (len - deleteCount + items.length); k--) {
+            for (long k = len; k > len - deleteCount + items.length; k--) {
                 sobj.delete(k - 1, true);
             }
         } else if (items.length > deleteCount) {
@@ -1313,7 +1313,7 @@
             }
 
 
-            for (long k = Math.max(0, (n < 0) ? (len - Math.abs(n)) : n); k < len; k++) {
+            for (long k = Math.max(0, n < 0 ? len - Math.abs(n) : n); k < len; k++) {
                 if (sobj.has(k)) {
                     if (ScriptRuntime.EQ_STRICT(sobj.get(k), searchElement)) {
                         return k;
@@ -1344,10 +1344,10 @@
                 return -1;
             }
 
-            final Object searchElement = (args.length > 0) ? args[0] : ScriptRuntime.UNDEFINED;
-            final long   n             = (args.length > 1) ? JSType.toLong(args[1]) : (len - 1);
+            final Object searchElement = args.length > 0 ? args[0] : ScriptRuntime.UNDEFINED;
+            final long   n             = args.length > 1 ? JSType.toLong(args[1]) : len - 1;
 
-            for (long k = (n < 0) ? (len - Math.abs(n)) : Math.min(n, len - 1); k >= 0; k--) {
+            for (long k = n < 0 ? len - Math.abs(n) : Math.min(n, len - 1); k >= 0; k--) {
                 if (sobj.has(k)) {
                     if (ScriptRuntime.EQ_STRICT(sobj.get(k), searchElement)) {
                         return k;
@@ -1380,7 +1380,7 @@
 
             @Override
             protected boolean forEach(final Object val, final long i) throws Throwable {
-                return (result = (boolean)everyInvoker.invokeExact(callbackfn, thisArg, val, i, self));
+                return result = (boolean)everyInvoker.invokeExact(callbackfn, thisArg, val, i, self);
             }
         }.apply();
     }
--- a/nashorn/src/jdk/nashorn/internal/objects/NativeDataView.java	Thu Mar 27 14:09:40 2014 +0100
+++ b/nashorn/src/jdk/nashorn/internal/objects/NativeDataView.java	Mon Mar 31 14:13:34 2014 +0200
@@ -88,15 +88,15 @@
     // underlying ByteBuffer
     private final ByteBuffer buf;
 
-    private NativeDataView(NativeArrayBuffer arrBuf) {
+    private NativeDataView(final NativeArrayBuffer arrBuf) {
         this(arrBuf, arrBuf.getBuffer(), 0);
     }
 
-    private NativeDataView(NativeArrayBuffer arrBuf, int offset) {
+    private NativeDataView(final NativeArrayBuffer arrBuf, final int offset) {
         this(arrBuf, bufferFrom(arrBuf, offset), offset);
     }
 
-    private NativeDataView(NativeArrayBuffer arrBuf, int offset, int length) {
+    private NativeDataView(final NativeArrayBuffer arrBuf, final int offset, final int length) {
         this(arrBuf, bufferFrom(arrBuf, offset, length), offset, length);
     }
 
@@ -235,7 +235,7 @@
     @Function(attributes = Attribute.NOT_ENUMERABLE)
     public static int getUint8(final Object self, final Object byteOffset) {
         try {
-            return (0xFF & getBuffer(self).get(JSType.toInt32(byteOffset)));
+            return 0xFF & getBuffer(self).get(JSType.toInt32(byteOffset));
         } catch (final IllegalArgumentException iae) {
             throw rangeError(iae, "dataview.offset");
         }
@@ -251,7 +251,7 @@
     @SpecializedFunction
     public static int getUint8(final Object self, final int byteOffset) {
         try {
-            return (0xFF & getBuffer(self).get(byteOffset));
+            return 0xFF & getBuffer(self).get(byteOffset);
         } catch (final IllegalArgumentException iae) {
             throw rangeError(iae, "dataview.offset");
         }
--- a/nashorn/src/jdk/nashorn/internal/objects/NativeError.java	Thu Mar 27 14:09:40 2014 +0100
+++ b/nashorn/src/jdk/nashorn/internal/objects/NativeError.java	Mon Mar 31 14:13:34 2014 +0200
@@ -316,7 +316,7 @@
 
         final Object exception = ECMAException.getException(sobj);
         if (exception instanceof Throwable) {
-            Object value = getScriptStackString(sobj, (Throwable)exception);
+            final Object value = getScriptStackString(sobj, (Throwable)exception);
             sobj.put(STACK, value, false);
             return value;
         }
--- a/nashorn/src/jdk/nashorn/internal/runtime/AccessorProperty.java	Thu Mar 27 14:09:40 2014 +0100
+++ b/nashorn/src/jdk/nashorn/internal/runtime/AccessorProperty.java	Mon Mar 31 14:13:34 2014 +0200
@@ -349,7 +349,7 @@
      * @param initialValue initial value
      */
     protected final void setInitialValue(final ScriptObject owner, final Object initialValue) {
-        setCurrentType(ObjectClassGenerator.unboxedFieldType(initialValue));
+        setCurrentType(JSType.unboxedFieldType(initialValue));
         if (initialValue instanceof Integer) {
             invokeSetter(owner, ((Integer)initialValue).intValue());
         } else if (initialValue instanceof Long) {
@@ -669,6 +669,7 @@
         if (DEBUG_FIELDS && LOG.levelFinerThanOrEqual(Level.INFO) && shouldInstrument(getKey())) {
            return MethodHandleFactory.addDebugPrintout(
                LOG,
+               Level.INFO,
                mh,
                tag + " '" + getKey() + "' (property="+ Debug.id(this) + ", slot=" + getSlot() + " " + getClass().getSimpleName() + " forType=" + stripName(forType) + ", type=" + stripName(type) + ')');
         }
--- a/nashorn/src/jdk/nashorn/internal/runtime/Context.java	Thu Mar 27 14:09:40 2014 +0100
+++ b/nashorn/src/jdk/nashorn/internal/runtime/Context.java	Mon Mar 31 14:13:34 2014 +0200
@@ -192,6 +192,9 @@
     public static void setGlobal(final Global global) {
         // This class in a package.access protected package.
         // Trusted code only can call this method.
+        assert getGlobal() != global;
+        //same code can be cached between globals, then we need to invalidate method handle constants
+        GlobalConstants.instance().invalidateAll();
         currentGlobal.set(global);
     }
 
@@ -232,7 +235,6 @@
      * @param str  text to write
      * @param crlf write a carriage return/new line after text
      */
-    @SuppressWarnings("resource")
     public static void err(final String str, final boolean crlf) {
         final PrintWriter err = Context.getCurrentErr();
         if (err != null) {
@@ -1028,6 +1030,4 @@
             classCache.cache(source, clazz);
         }
     }
-
-
 }
--- a/nashorn/src/jdk/nashorn/internal/runtime/DebugLogger.java	Thu Mar 27 14:09:40 2014 +0100
+++ b/nashorn/src/jdk/nashorn/internal/runtime/DebugLogger.java	Mon Mar 31 14:13:34 2014 +0200
@@ -126,7 +126,7 @@
             quote = '\'';
         }
 
-        return (startQuote == '\0' ? "" : startQuote) + str + (endQuote == '\0' ? "" : endQuote);
+        return (startQuote == '\0' ? quote : startQuote) + str + (endQuote == '\0' ? quote : endQuote);
     }
 
     /**
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/src/jdk/nashorn/internal/runtime/GlobalConstants.java	Mon Mar 31 14:13:34 2014 +0200
@@ -0,0 +1,418 @@
+/*
+ * Copyright (c) 2010, 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  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 static jdk.nashorn.internal.codegen.CompilerConstants.staticCall;
+import static jdk.nashorn.internal.runtime.DebugLogger.quote;
+import static jdk.nashorn.internal.lookup.Lookup.MH;
+
+import java.lang.invoke.MethodHandle;
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.SwitchPoint;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.logging.Level;
+
+import jdk.internal.dynalink.CallSiteDescriptor;
+import jdk.internal.dynalink.DynamicLinker;
+import jdk.internal.dynalink.linker.GuardedInvocation;
+import jdk.internal.dynalink.linker.LinkRequest;
+import jdk.nashorn.internal.lookup.Lookup;
+import jdk.nashorn.internal.lookup.MethodHandleFactory;
+import jdk.nashorn.internal.runtime.linker.NashornCallSiteDescriptor;
+
+/**
+ * Each global owns one of these. This is basically table of accessors
+ * for global properties. A global constant is evaluated to a MethodHandle.constant
+ * for faster access and to avoid walking to proto chain looking for it.
+ *
+ * We put a switchpoint on the global setter, which invalidates the
+ * method handle constant getters, and reverts to the standard access strategy
+ *
+ * However, there is a twist - while certain globals like "undefined" and "Math"
+ * are usually never reassigned, a global value can be reset once, and never again.
+ * This is a rather common pattern, like:
+ *
+ * x = function(something) { ...
+ *
+ * Thus everything registered as a global constant gets an extra chance. Set once,
+ * reregister the switchpoint. Set twice or more - don't try again forever, or we'd
+ * just end up relinking our way into megamorphisism.
+ *
+ * We can extend this to ScriptObjects in general (GLOBAL_ONLY=false), which requires
+ * a receiver guard on the constant getter, but it currently leaks memory and its benefits
+ * have not yet been investigated property.
+ */
+public final class GlobalConstants {
+
+    private GlobalConstants() {
+        //singleton
+    }
+
+    /**
+     * Return the singleton global constant pool
+     * @return singleton global constant pool
+     */
+    public static GlobalConstants instance() {
+        return instance;
+    }
+
+    private static final GlobalConstants instance = new GlobalConstants();
+
+    /**
+     * Should we only try to link globals as constants, and not generic script objects.
+     * Script objects require a receiver guard, which is memory intensive, so this is currently
+     * disabled. We might implement a weak reference based approach to this later.
+     */
+    private static final boolean GLOBAL_ONLY = true;
+
+    private static final MethodHandles.Lookup LOOKUP = MethodHandles.lookup();
+
+    private static final MethodHandle INVALIDATE_SP  = staticCall(LOOKUP, GlobalConstants.class, "invalidateSwitchPoint", Object.class, Object.class, Access.class).methodHandle();
+    private static final MethodHandle RECEIVER_GUARD = staticCall(LOOKUP, GlobalConstants.class, "receiverGuard", boolean.class, Access.class, Object.class, Object.class).methodHandle();
+
+    /** Logger for constant getters */
+    private static final DebugLogger LOG = new DebugLogger("const");
+
+    /**
+     * 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<>();
+
+    /**
+     * Information about a constant access and its potential invalidations
+     */
+    private static class Access {
+        /** name of symbol */
+        private final String name;
+
+        /** switchpoint that invalidates the getters and setters for this access */
+        private SwitchPoint sp;
+
+        /** invalidation count for this access, i.e. how many times has this property been reset */
+        private int invalidations;
+
+        /** has a guard guarding this property getter failed? */
+        private boolean guardFailed;
+
+        private static final int MAX_RETRIES = 2;
+
+        private Access(final String name, final SwitchPoint sp) {
+            this.name      = name;
+            this.sp        = sp;
+        }
+
+        private boolean hasBeenInvalidated() {
+            return sp.hasBeenInvalidated();
+        }
+
+        private boolean guardFailed() {
+            return guardFailed;
+        }
+
+        private void failGuard() {
+            invalidateOnce();
+            guardFailed = true;
+        }
+
+        private void newSwitchPoint() {
+            assert hasBeenInvalidated();
+            sp = new SwitchPoint();
+        }
+
+        private void invalidate(final int count) {
+            if (!sp.hasBeenInvalidated()) {
+                SwitchPoint.invalidateAll(new SwitchPoint[] { sp });
+                invalidations += count;
+            }
+        }
+
+        /**
+         * Invalidate the access, but do not contribute to the invalidation count
+         */
+        private void invalidateUncounted() {
+            invalidate(0);
+        }
+
+        /**
+         * Invalidate the access, and contribute 1 to the invalidation count
+         */
+        private void invalidateOnce() {
+            invalidate(1);
+        }
+
+        /**
+         * Invalidate the access and make sure that we never try to turn this into
+         * a MethodHandle.constant getter again
+         */
+        private void invalidateForever() {
+            invalidate(MAX_RETRIES);
+        }
+
+        /**
+         * Are we allowed to relink this as constant getter, even though it
+         * it has been reset
+         * @return true if we can relink as constant, one retry is allowed
+         */
+        private boolean mayRetry() {
+            return invalidations < MAX_RETRIES;
+        }
+
+        @Override
+        public String toString() {
+            return "[" + quote(name) + " <id=" + Debug.id(this) + "> inv#=" + invalidations + '/' + MAX_RETRIES + " sp_inv=" + sp.hasBeenInvalidated() + ']';
+        }
+
+        String getName() {
+            return name;
+        }
+
+        SwitchPoint getSwitchPoint() {
+            return sp;
+        }
+    }
+
+    /**
+     * To avoid an expensive global guard "is this the same global", similar to the
+     * receiver guard on the ScriptObject level, we invalidate all getters once
+     * when we switch globals. This is used from the class cache. We _can_ reuse
+     * the same class for a new global, but the builtins and global scoped variables
+     * will have changed.
+     */
+    public void invalidateAll() {
+        LOG.info("New global created - invalidating all constant callsites without increasing invocation count.");
+        for (final Access acc : map.values()) {
+            acc.invalidateUncounted();
+        }
+    }
+
+    /**
+     * Invalidate the switchpoint of an access - we have written to
+     * the property
+     *
+     * @param obj receiver
+     * @param acc access
+     *
+     * @return receiver, so this can be used as param filter
+     */
+    @SuppressWarnings("unused")
+    private static Object invalidateSwitchPoint(final Object obj, final Access acc) {
+        if (LOG.isEnabled()) {
+            LOG.info("*** Invalidating switchpoint " + acc.getSwitchPoint() + " for receiver=" + obj + " access=" + acc);
+        }
+        acc.invalidateOnce();
+        if (acc.mayRetry()) {
+            if (LOG.isEnabled()) {
+                LOG.info("Retry is allowed for " + acc + "... Creating a new switchpoint.");
+            }
+            acc.newSwitchPoint();
+        } else {
+            if (LOG.isEnabled()) {
+                LOG.info("This was the last time I allowed " + quote(acc.getName()) + " to relink as constant.");
+            }
+        }
+        return obj;
+    }
+
+    private Access getOrCreateSwitchPoint(final String name) {
+        Access acc = map.get(name);
+        if (acc != null) {
+            return acc;
+        }
+        final SwitchPoint sp = new SwitchPoint();
+        map.put(name, acc = new Access(name, sp));
+        return acc;
+    }
+
+    /**
+     * Called from script object on property deletion to erase a property
+     * that might be linked as MethodHandle.constant and force relink
+     * @param name name of property
+     */
+    void delete(final String name) {
+        final Access acc = map.get(name);
+        if (acc != null) {
+            acc.invalidateForever();
+        }
+    }
+
+    /**
+     * Receiver guard is used if we extend the global constants to script objects in general.
+     * As the property can have different values in different script objects, while Global is
+     * by definition a singleton, we need this for ScriptObject constants (currently disabled)
+     *
+     * TODO: Note - this seems to cause memory leaks. Use weak references? But what is leaking seems
+     * to be the Access objects, which isn't the case for Globals. Weird.
+     *
+     * @param acc            access
+     * @param boundReceiver  the receiver bound to the callsite
+     * @param receiver       the receiver to check against
+     *
+     * @return true if this receiver is still the one we bound to the callsite
+     */
+    @SuppressWarnings("unused")
+    private static boolean receiverGuard(final Access acc, final Object boundReceiver, final Object receiver) {
+        final boolean id = receiver == boundReceiver;
+        if (!id) {
+            acc.failGuard();
+        }
+        return id;
+    }
+
+    private static boolean isGlobalSetter(final ScriptObject receiver, final FindProperty find) {
+        if (find == null) {
+            return receiver.isScope();
+        }
+        return find.getOwner().isGlobal();
+    }
+
+    /**
+     * Augment a setter with switchpoint for invalidating its getters, should the setter be called
+     *
+     * @param find    property lookup
+     * @param inv     normal guarded invocation for this setter, as computed by the ScriptObject linker
+     * @param desc    callsite descriptr
+     * @param request link request
+     *
+     * @return null if failed to set up constant linkage
+     */
+    GuardedInvocation findSetMethod(final FindProperty find, final ScriptObject receiver, final GuardedInvocation inv, final CallSiteDescriptor desc, final LinkRequest request) {
+        if (GLOBAL_ONLY && !isGlobalSetter(receiver, find)) {
+            return null;
+        }
+
+        final String name = desc.getNameToken(CallSiteDescriptor.NAME_OPERAND);
+
+        final Access acc  = getOrCreateSwitchPoint(name);
+
+        if (LOG.isEnabled()) {
+            LOG.fine("Trying to link constant SETTER ", acc);
+        }
+
+        if (!acc.mayRetry()) {
+            LOG.info("*** SET: Giving up on " + quote(name) + " - retry count has exceeded " + DynamicLinker.getLinkedCallSiteLocation());
+            return null;
+        }
+
+        assert acc.mayRetry();
+
+        if (acc.hasBeenInvalidated()) {
+            LOG.info("New chance for " + acc);
+            acc.newSwitchPoint();
+        }
+
+        assert !acc.hasBeenInvalidated();
+
+        // if we haven't given up on this symbol, add a switchpoint invalidation filter to the receiver parameter
+        final MethodHandle target       = inv.getInvocation();
+        final Class<?>     receiverType = target.type().parameterType(0);
+        final MethodHandle invalidator  = MH.asType(INVALIDATE_SP, INVALIDATE_SP.type().changeParameterType(0, receiverType).changeReturnType(receiverType));
+        final MethodHandle mh           = MH.filterArguments(inv.getInvocation(), 0, MH.insertArguments(invalidator, 1, acc));
+
+        assert inv.getSwitchPoint() == null : inv.getSwitchPoint();
+        LOG.info("Linked setter " + quote(name) + " " + acc.getSwitchPoint());
+        return new GuardedInvocation(mh, inv.getGuard(), acc.getSwitchPoint(), inv.getException());
+    }
+
+    /**
+     * Try to reuse constant method handles for getters
+     * @param c constant value
+     * @return method handle (with dummy receiver) that returns this constant
+     */
+    private static MethodHandle constantGetter(final Object c) {
+        return MH.dropArguments(JSType.unboxConstant(c), 0, Object.class);
+    }
+
+    /**
+     * Try to turn a getter into a MethodHandle.constant, if possible
+     *
+     * @param find      property lookup
+     * @param receiver  receiver
+     * @param desc      callsite descriptor
+     * @param request   link request
+     * @param operator  operator
+     *
+     * @return resulting getter, or null if failed to create constant
+     */
+    GuardedInvocation findGetMethod(final FindProperty find, final ScriptObject receiver, final CallSiteDescriptor desc, final LinkRequest request, final String operator) {
+        if (GLOBAL_ONLY && !find.getOwner().isGlobal()) {
+            return null;
+        }
+
+        final int programPoint         = NashornCallSiteDescriptor.isOptimistic(desc) ?
+            NashornCallSiteDescriptor.getProgramPoint(desc) :
+            UnwarrantedOptimismException.INVALID_PROGRAM_POINT;
+        final boolean     isOptimistic = programPoint != UnwarrantedOptimismException.INVALID_PROGRAM_POINT;
+        final Class<?>    retType      = desc.getMethodType().returnType();
+        final String      name         = desc.getNameToken(CallSiteDescriptor.NAME_OPERAND);
+
+        final Access acc = getOrCreateSwitchPoint(name);
+
+        LOG.fine("Starting to look up object value " + name);
+        final Object c = find.getObjectValue();
+
+        if (LOG.isEnabled()) {
+            LOG.fine("Trying to link constant GETTER " + acc + " value = " + c);
+        }
+
+        if (acc.hasBeenInvalidated() || acc.guardFailed()) {
+            LOG.fine("*** GET: Giving up on " + quote(name) + " - retry count has exceeded");
+            return null;
+        }
+
+        final MethodHandle cmh = constantGetter(c);
+
+        MethodHandle mh;
+        MethodHandle guard;
+
+        if (isOptimistic) {
+            if (JSType.getAccessorTypeIndex(cmh.type().returnType()) <= JSType.getAccessorTypeIndex(retType)) {
+                //widen return type - this is pessimistic, so it will always work
+                mh = MH.asType(cmh, cmh.type().changeReturnType(retType));
+            } else {
+                //immediately invalidate - we asked for a too wide constant as a narrower one
+                mh = MH.dropArguments(MH.insertArguments(JSType.THROW_UNWARRANTED.methodHandle(), 0, c, programPoint), 0, Object.class);
+            }
+        } else {
+            //pessimistic return type filter
+            mh = Lookup.filterReturnType(cmh, retType);
+        }
+
+        if (find.getOwner().isGlobal()) {
+            guard = null;
+        } else {
+            guard = MH.insertArguments(RECEIVER_GUARD, 0, acc, receiver);
+        }
+
+        if (LOG.isEnabled()) {
+            LOG.info("Linked getter " + quote(name) + " as MethodHandle.constant() -> " + c + " " + acc.getSwitchPoint());
+            mh = MethodHandleFactory.addDebugPrintout(LOG, Level.FINE, mh, "get const " + acc);
+        }
+
+        return new GuardedInvocation(mh, guard, acc.getSwitchPoint(), null);
+    }
+}
--- a/nashorn/src/jdk/nashorn/internal/runtime/JSType.java	Thu Mar 27 14:09:40 2014 +0100
+++ b/nashorn/src/jdk/nashorn/internal/runtime/JSType.java	Mon Mar 31 14:13:34 2014 +0200
@@ -26,6 +26,7 @@
 package jdk.nashorn.internal.runtime;
 
 import static jdk.nashorn.internal.codegen.CompilerConstants.staticCall;
+import static jdk.nashorn.internal.codegen.ObjectClassGenerator.OBJECT_FIELDS_ONLY;
 import static jdk.nashorn.internal.lookup.Lookup.MH;
 import static jdk.nashorn.internal.runtime.ECMAErrors.typeError;
 
@@ -280,7 +281,7 @@
         }
 
         if (obj instanceof ScriptObject) {
-            return (obj instanceof ScriptFunction) ? JSType.FUNCTION : JSType.OBJECT;
+            return obj instanceof ScriptFunction ? JSType.FUNCTION : JSType.OBJECT;
         }
 
         if (obj instanceof Boolean) {
@@ -438,7 +439,7 @@
      *
      * @return the string form of the primitive form of the object
      */
-    public static String toPrimitiveToString(Object obj) {
+    public static String toPrimitiveToString(final Object obj) {
         return toString(toPrimitive(obj));
     }
 
@@ -900,7 +901,7 @@
     }
 
     // Minimum and maximum range between which every long value can be precisely represented as a double.
-    private static final long MAX_PRECISE_DOUBLE = (1L << 53);
+    private static final long MAX_PRECISE_DOUBLE = 1L << 53;
     private static final long MIN_PRECISE_DOUBLE = -MAX_PRECISE_DOUBLE;
 
     /**
@@ -972,7 +973,7 @@
      * @return a uint16
      */
     public static int toUint16(final long num) {
-        return ((int)num) & 0xffff;
+        return (int)num & 0xffff;
     }
 
     /**
@@ -982,7 +983,7 @@
      * @return a uint16
      */
     public static int toUint16(final double num) {
-        return ((int)doubleToInt32(num)) & 0xffff;
+        return (int)doubleToInt32(num) & 0xffff;
     }
 
     private static long doubleToInt32(final double num) {
@@ -996,7 +997,7 @@
             return 0;
         }
         // This is rather slow and could probably be sped up using bit-fiddling.
-        final double d = (num >= 0) ? Math.floor(num) : Math.ceil(num);
+        final double d = num >= 0 ? Math.floor(num) : Math.ceil(num);
         return (long)(d % INT32_LIMIT);
     }
 
@@ -1285,7 +1286,7 @@
     public static int addExact(final int x, final int y, final int programPoint) throws UnwarrantedOptimismException {
         try {
             return Math.addExact(x, y);
-        } catch (ArithmeticException e) {
+        } catch (final ArithmeticException e) {
             throw new UnwarrantedOptimismException((long)x + (long)y, programPoint);
         }
     }
@@ -1305,7 +1306,7 @@
     public static long addExact(final long x, final long y, final int programPoint) throws UnwarrantedOptimismException {
         try {
             return Math.addExact(x, y);
-        } catch (ArithmeticException e) {
+        } catch (final ArithmeticException e) {
             throw new UnwarrantedOptimismException((double)x + (double)y, programPoint);
         }
     }
@@ -1325,7 +1326,7 @@
     public static int subExact(final int x, final int y, final int programPoint) throws UnwarrantedOptimismException {
         try {
             return Math.subtractExact(x, y);
-        } catch (ArithmeticException e) {
+        } catch (final ArithmeticException e) {
             throw new UnwarrantedOptimismException((long)x - (long)y, programPoint);
         }
     }
@@ -1345,7 +1346,7 @@
     public static long subExact(final long x, final long y, final int programPoint) throws UnwarrantedOptimismException {
         try {
             return Math.subtractExact(x, y);
-        } catch (ArithmeticException e) {
+        } catch (final ArithmeticException e) {
             throw new UnwarrantedOptimismException((double)x - (double)y, programPoint);
         }
     }
@@ -1365,7 +1366,7 @@
     public static int mulExact(final int x, final int y, final int programPoint) throws UnwarrantedOptimismException {
         try {
             return Math.multiplyExact(x, y);
-        } catch (ArithmeticException e) {
+        } catch (final ArithmeticException e) {
             throw new UnwarrantedOptimismException((long)x * (long)y, programPoint);
         }
     }
@@ -1682,4 +1683,47 @@
         }
     }
 
+    /**
+     * Create a method handle constant of the correct primitive type
+     * for a constant object
+     * @param o object
+     * @return constant function that returns object
+     */
+    public static MethodHandle unboxConstant(final Object o) {
+        if (o != null) {
+            if (o.getClass() == Integer.class) {
+                return MH.constant(int.class, ((Integer)o).intValue());
+            } else if (o.getClass() == Long.class) {
+                return MH.constant(long.class, ((Long)o).longValue());
+            } else if (o.getClass() == Double.class) {
+                return MH.constant(double.class, ((Double)o).doubleValue());
+            }
+        }
+        return MH.constant(Object.class, o);
+    }
+
+    /**
+     * Get the unboxed (primitive) type for an object
+     * @param o object
+     * @return primive type or Object.class if not primitive
+     */
+    public static Class<?> unboxedFieldType(final Object o) {
+        if (OBJECT_FIELDS_ONLY) {
+            return Object.class;
+        }
+
+        if (o == null) {
+            return Object.class;
+        } else if (o.getClass() == Integer.class) {
+            return int.class;
+        } else if (o.getClass() == Long.class) {
+            return long.class;
+        } else if (o.getClass() == Double.class) {
+            return double.class;
+        } else {
+            return Object.class;
+        }
+    }
+
+
 }
--- a/nashorn/src/jdk/nashorn/internal/runtime/RecompilableScriptFunctionData.java	Thu Mar 27 14:09:40 2014 +0100
+++ b/nashorn/src/jdk/nashorn/internal/runtime/RecompilableScriptFunctionData.java	Mon Mar 31 14:13:34 2014 +0200
@@ -213,6 +213,11 @@
 
     @Override
     public String toString() {
+        return super.toString() + '@' + functionNodeId;
+    }
+
+    @Override
+    public String toStringVerbose() {
         final StringBuilder sb = new StringBuilder();
 
         sb.append("fid=").append(functionNodeId).append(' ');
@@ -309,6 +314,13 @@
         return (isProgram ? program : extractFunctionFromScript(program)).setName(null, functionName).setSourceURL(null,  sourceURL);
     }
 
+    private static String getShortDescriptor(final Object value) {
+        if (value.getClass() == Object.class) {
+            return "O";
+        }
+        return value.getClass().getSimpleName();
+    }
+
     private static String stringifyInvalidations(final Map<Integer, Type> ipp) {
         if (ipp == null) {
             return "";
@@ -320,7 +332,7 @@
             sb.append('[').
                     append(entry.getKey()).
                     append("->").
-                    append(entry.getValue().getShortDescriptor()).
+                    append(getShortDescriptor(entry.getValue())).
                     append(']');
             if (iter.hasNext()) {
                 sb.append(' ');
--- a/nashorn/src/jdk/nashorn/internal/runtime/RewriteException.java	Thu Mar 27 14:09:40 2014 +0100
+++ b/nashorn/src/jdk/nashorn/internal/runtime/RewriteException.java	Mon Mar 31 14:13:34 2014 +0200
@@ -35,6 +35,7 @@
 import java.lang.invoke.MethodHandles.Lookup;
 import java.lang.invoke.MethodType;
 import java.util.Arrays;
+
 import jdk.nashorn.internal.codegen.CompilerConstants.Call;
 import jdk.nashorn.internal.codegen.types.Type;
 import jdk.nashorn.internal.lookup.MethodHandleFactory;
@@ -169,6 +170,7 @@
     private Object getReturnValueNonDestructive() {
         return getUOE().getReturnValueNonDestructive();
     }
+
     /**
      * Get return type
      * @return return type
@@ -213,13 +215,18 @@
         if (returnValue == null) {
             return "null";
         }
-        final String str = returnValue.toString();
-        return returnValue instanceof Long ? (str + 'L') : str;
+        String str = returnValue.toString();
+        if (returnValue instanceof String) {
+            str = '\'' + str + '\'';
+        } else if (returnValue instanceof Long) {
+            str = str + 'l';
+        }
+        return str;
     }
 
     @Override
     public String getMessage() {
-        return "programPoint=" + getProgramPoint() + " slots=" + (byteCodeSlots == null ? "null" : Arrays.asList(byteCodeSlots)) + ", returnValue=" + stringify(getReturnValueNonDestructive()) + ", returnType=" + getReturnType();
+        return getMessage(false);
     }
 
     /**
@@ -227,7 +234,38 @@
      * @return short message
      */
     public String getMessageShort() {
-        return "[programPoint=" + getProgramPoint() + " returnType=" + getReturnType() + " (" + stringify(getReturnValueNonDestructive()) + ")]";
+        return getMessage(true);
+    }
+
+    private String getMessage(final boolean isShort) {
+        final StringBuilder sb = new StringBuilder();
+
+        //program point
+        sb.append("[pp=").
+            append(getProgramPoint()).
+            append(", ");
+
+        //slot contents
+        if (!isShort) {
+            final Object[] slots = getByteCodeSlots();
+            if (slots != null) {
+                sb.append("slots=").
+                    append(Arrays.asList(slots)).
+                    append(", ");
+            }
+        }
+
+        //return type
+        sb.append("type=").
+            append(getReturnType()).
+            append(", ");
+
+        //return value
+        sb.append("value=").
+            append(stringify(getReturnValueNonDestructive())).
+            append(")]");
+
+        return sb.toString();
     }
 
 }
--- a/nashorn/src/jdk/nashorn/internal/runtime/RuntimeEvent.java	Thu Mar 27 14:09:40 2014 +0100
+++ b/nashorn/src/jdk/nashorn/internal/runtime/RuntimeEvent.java	Mon Mar 31 14:13:34 2014 +0200
@@ -1,3 +1,28 @@
+/*
+ * Copyright (c) 2010, 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
 package jdk.nashorn.internal.runtime;
 
 import java.util.logging.Level;
--- a/nashorn/src/jdk/nashorn/internal/runtime/ScriptFunctionData.java	Thu Mar 27 14:09:40 2014 +0100
+++ b/nashorn/src/jdk/nashorn/internal/runtime/ScriptFunctionData.java	Mon Mar 31 14:13:34 2014 +0200
@@ -179,6 +179,14 @@
      */
     @Override
     public String toString() {
+        return name.isEmpty() ? "<anonymous>" : name;
+    }
+
+    /**
+     * Verbose description of data
+     * @return verbose description
+     */
+    public String toStringVerbose() {
         final StringBuilder sb = new StringBuilder();
 
         sb.append("name='").
--- a/nashorn/src/jdk/nashorn/internal/runtime/ScriptObject.java	Thu Mar 27 14:09:40 2014 +0100
+++ b/nashorn/src/jdk/nashorn/internal/runtime/ScriptObject.java	Mon Mar 31 14:13:34 2014 +0200
@@ -62,6 +62,7 @@
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
+
 import jdk.internal.dynalink.CallSiteDescriptor;
 import jdk.internal.dynalink.linker.GuardedInvocation;
 import jdk.internal.dynalink.linker.LinkRequest;
@@ -119,6 +120,9 @@
     /** Is length property not-writable? */
     public static final int IS_LENGTH_NOT_WRITABLE = 1 << 3;
 
+    /** Is this a builtin object? */
+    public static final int IS_BUILTIN = 1 << 4;
+
     /**
      * Spill growth rate - by how many elements does {@link ScriptObject#primitiveSpill} and
      * {@link ScriptObject#objectSpill} when full
@@ -254,6 +258,14 @@
         this.spillLength = spillAllocationLength(primitiveSpill.length);
     }
 
+    /**
+     * Check whether this is a global object
+     * @return true if global
+     */
+    protected boolean isGlobal() {
+        return false;
+    }
+
     private static int alignUp(final int size, final int alignment) {
         return size + alignment - 1 & ~(alignment - 1);
     }
@@ -906,9 +918,11 @@
                 if (property instanceof UserAccessorProperty) {
                     ((UserAccessorProperty)property).setAccessors(this, getMap(), null);
                 }
+                GlobalConstants.instance().delete(property.getKey());
                 return true;
             }
         }
+
     }
 
     /**
@@ -1550,6 +1564,21 @@
     }
 
     /**
+     * Tag this script object as built in
+     */
+    public final void setIsBuiltin() {
+        flags |= IS_BUILTIN;
+    }
+
+    /**
+     * Check if this script object is built in
+     * @return true if build in
+     */
+    public final boolean isBuiltin() {
+        return (flags & IS_BUILTIN) != 0;
+    }
+
+    /**
      * Clears the properties from a ScriptObject
      * (java.util.Map-like method to help ScriptObjectMirror implementation)
      *
@@ -1879,7 +1908,12 @@
             default:
                 throw new AssertionError(operator); // never invoked with any other operation
             }
-       }
+        }
+
+        final GuardedInvocation inv = GlobalConstants.instance().findGetMethod(find, this, desc, request, operator);
+        if (inv != null) {
+            return inv;
+        }
 
         final Class<?> returnType = desc.getMethodType().returnType();
         final Property property   = find.getProperty();
@@ -2064,7 +2098,14 @@
             }
         }
 
-        return new SetMethodCreator(this, find, desc, explicitInstanceOfCheck).createGuardedInvocation();
+        final GuardedInvocation inv = new SetMethodCreator(this, find, desc, explicitInstanceOfCheck).createGuardedInvocation();
+
+        final GuardedInvocation cinv = GlobalConstants.instance().findSetMethod(find, this, inv, desc, request);
+        if (cinv != null) {
+            return cinv;
+        }
+
+        return inv;
     }
 
     private GuardedInvocation createEmptySetMethod(final CallSiteDescriptor desc, final boolean explicitInstanceOfCheck, final String strictErrorMessage, final boolean canBeFastScope) {
--- a/nashorn/src/jdk/nashorn/internal/runtime/ScriptRuntime.java	Thu Mar 27 14:09:40 2014 +0100
+++ b/nashorn/src/jdk/nashorn/internal/runtime/ScriptRuntime.java	Mon Mar 31 14:13:34 2014 +0200
@@ -42,6 +42,7 @@
 import java.util.Map;
 import java.util.NoSuchElementException;
 import java.util.Objects;
+
 import jdk.internal.dynalink.beans.StaticClass;
 import jdk.nashorn.api.scripting.JSObject;
 import jdk.nashorn.api.scripting.ScriptObjectMirror;
@@ -119,7 +120,6 @@
                 return (int)d;
             }
         }
-
         return deflt;
     }
 
--- a/nashorn/src/jdk/nashorn/internal/runtime/SetMethodCreator.java	Thu Mar 27 14:09:40 2014 +0100
+++ b/nashorn/src/jdk/nashorn/internal/runtime/SetMethodCreator.java	Mon Mar 31 14:13:34 2014 +0200
@@ -174,7 +174,7 @@
         final String      name     = desc.getNameToken(CallSiteDescriptor.NAME_OPERAND);
 
         //fast type specific setter
-        MethodHandle fastSetter = property.getSetter(type, newMap); //0 sobj, 1 value, slot folded for spill property already
+        final MethodHandle fastSetter = property.getSetter(type, newMap); //0 sobj, 1 value, slot folded for spill property already
 
         //slow setter, that calls ScriptObject.set with appropraite type and key name
         MethodHandle slowSetter = ScriptObject.SET_SLOW[getAccessorTypeIndex(type)];
@@ -188,7 +188,7 @@
         MethodHandle casMap = MH.insertArguments(ScriptObject.CAS_MAP, 1, oldMap, newMap);
         casMap = MH.dropArguments(casMap, 1, type);
         casMap = MH.asType(casMap, casMap.type().changeParameterType(0, Object.class));
-        MethodHandle casGuard = MH.guardWithTest(casMap, fastSetter, slowSetter);
+        final MethodHandle casGuard = MH.guardWithTest(casMap, fastSetter, slowSetter);
 
         //outermost level needs an extendable check. if object can be extended, guard is true and
         //we can run the cas setter. The setter goes to "nop" VOID_RETURN if false or throws an
--- a/nashorn/src/jdk/nashorn/internal/runtime/WithObject.java	Thu Mar 27 14:09:40 2014 +0100
+++ b/nashorn/src/jdk/nashorn/internal/runtime/WithObject.java	Mon Mar 31 14:13:34 2014 +0200
@@ -270,9 +270,16 @@
     }
 
     private GuardedInvocation fixScopeCallSite(final GuardedInvocation link, final String name, final ScriptObject owner) {
-        final GuardedInvocation newLink = fixReceiverType(link, WITHSCOPEFILTER);
-        return link.replaceMethods(filterReceiver(newLink.getInvocation(), WITHSCOPEFILTER),
-                NashornGuards.combineGuards(expressionGuard(name, owner), filterGuardReceiver(newLink, WITHSCOPEFILTER)));
+        final GuardedInvocation newLink             = fixReceiverType(link, WITHSCOPEFILTER);
+        final MethodHandle      expressionGuard     = expressionGuard(name, owner);
+        final MethodHandle      filterGuardReceiver = filterGuardReceiver(newLink, WITHSCOPEFILTER);
+        return link.replaceMethods(
+                filterReceiver(
+                        newLink.getInvocation(),
+                        WITHSCOPEFILTER),
+                NashornGuards.combineGuards(
+                        expressionGuard,
+                        filterGuardReceiver));
     }
 
     private static MethodHandle filterGuardReceiver(final GuardedInvocation link, final MethodHandle receiverFilter) {
--- a/nashorn/src/jdk/nashorn/internal/runtime/linker/NashornGuards.java	Thu Mar 27 14:09:40 2014 +0100
+++ b/nashorn/src/jdk/nashorn/internal/runtime/linker/NashornGuards.java	Mon Mar 31 14:13:34 2014 +0200
@@ -174,7 +174,13 @@
      * @return true if both guard1 and guard2 returned true
      */
     public static MethodHandle combineGuards(final MethodHandle guard1, final MethodHandle guard2) {
-        return MH.guardWithTest(guard1, guard2, MH.dropArguments(MH.constant(boolean.class, false), 0, Object.class));
+        if (guard1 == null) {
+            return guard2;
+        } else if (guard2 == null) {
+            return guard1;
+        } else {
+            return MH.guardWithTest(guard1, guard2, MH.dropArguments(MH.constant(boolean.class, false), 0, Object.class));
+        }
     }
 
     @SuppressWarnings("unused")
--- a/nashorn/test/script/basic/JDK-8010697.js	Thu Mar 27 14:09:40 2014 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,59 +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.
- *
- * 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-8010697: DeletedArrayFilter seems to leak memory
- *
- * @test
- * @run
- */
-
-var N = 1000;
-
-var array = new Array(N);
-var WeakReferenceArray = Java.type("java.lang.ref.WeakReference[]");
-var refArray = new WeakReferenceArray(N);
-
-for (var i = 0; i < N; i ++) {
-    var object = new java.lang.Object();
-    array[i] = object;
-    refArray[i] = new java.lang.ref.WeakReference(object);
-}
-
-object = null;
-
-for (var i = 0; i < N; i ++) {
-    delete array[i];
-}
-
-java.lang.System.gc();
-java.lang.System.gc();
-
-for (var i = 0; i < N; i ++) {
-    if (refArray[i].get() != null) {
-        print("Reference found at " + i);
-        exit(0);
-    }
-}
-
-print("All references gone");
--- a/nashorn/test/script/basic/JDK-8010697.js.EXPECTED	Thu Mar 27 14:09:40 2014 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,1 +0,0 @@
-All references gone
--- a/nashorn/test/script/basic/JDK-8022903.js	Thu Mar 27 14:09:40 2014 +0100
+++ b/nashorn/test/script/basic/JDK-8022903.js	Mon Mar 31 14:13:34 2014 +0200
@@ -43,7 +43,7 @@
 
 var capitals = new java.util.LinkedHashMap()
 capitals.Sweden = "Stockholm"
-capitals.Hungary = "Budapet"
+capitals.Hungary = "Budapest"
 capitals.Croatia = "Zagreb"
 
 for(var key in capitals) {
--- a/nashorn/test/script/basic/JDK-8022903.js.EXPECTED	Thu Mar 27 14:09:40 2014 +0100
+++ b/nashorn/test/script/basic/JDK-8022903.js.EXPECTED	Mon Mar 31 14:13:34 2014 +0200
@@ -5,8 +5,8 @@
 purple
 pink
 capital of Sweden is Stockholm
-capital of Hungary is Budapet
+capital of Hungary is Budapest
 capital of Croatia is Zagreb
 Stockholm
-Budapet
+Budapest
 Zagreb
--- a/nashorn/test/script/basic/JDK-8027042.js	Thu Mar 27 14:09:40 2014 +0100
+++ b/nashorn/test/script/basic/JDK-8027042.js	Mon Mar 31 14:13:34 2014 +0200
@@ -26,33 +26,35 @@
  *
  * @test
  * @run
+ * @fork
  */
 
 // var with getter side effect
-Object.defineProperty(this, "a", { get: function() {print("get a"); return 1; }});
+Object.defineProperty(this, "a1", { get: function() {print("get a"); return 1; }});
 
 // var with both getter and conversion side effect
-Object.defineProperty(this, "b", { get: function() {print("get b"); return {valueOf: function() { print("conv b"); return 10; }}; }});
+Object.defineProperty(this, "b1", { get: function() {print("get b"); return {valueOf: function() { print("conv b"); return 10; }}; }});
 
 (function() {
     // var with toPrimitive conversion side effect
-    var c = {valueOf: function() { print("conv c"); return 100; }};
-
-    print(b + (c + a));
-    print(b + (c + b));
-    print(b + (a + b));
-    print(b + (b + c));
-    print(b + (b + c));
-    print(b + (c + (a - b)));
-    print(b + (c + (c - b)));
-    print(b + (c + (b - c)));
-    print(b + (b + (a ? 2 : 3)));
-    print(b + (b + (b ? 2 : 3)));
-    print(b + (b + (c ? 2 : 3)));
-    print(b + ((-c) + (-a)));
-    print(b + ((-c) + (-b)));
-    print(b + ((-c) + (-c)));
-    try { print(b + new a); } catch (e) {}
-    try { print(b + new b); } catch (e) {}
-    try { print(b + new c); } catch (e) {}
+    var c1 = {valueOf: function() { print("conv c"); return 100; }};
+    print("start");
+    print(b1 + (c1 + a1));
+    print("done with first");
+    print(b1 + (c1 + b1));
+    print(b1 + (a1 + b1));
+    print(b1 + (b1 + c1));
+    print(b1 + (b1 + c1));
+    print(b1 + (c1 + (a1 - b1)));
+    print(b1 + (c1 + (c1 - b1)));
+    print(b1 + (c1 + (b1 - c1)));
+    print(b1 + (b1 + (a1 ? 2 : 3)));
+    print(b1 + (b1 + (b1 ? 2 : 3)));
+    print(b1 + (b1 + (c1 ? 2 : 3)));
+    print(b1 + ((-c1) + (-a1)));
+    print(b1 + ((-c1) + (-b1)));
+    print(b1 + ((-c1) + (-c1)));
+    try { print(b1 + new a1); } catch (e) {}
+    try { print(b1 + new b1); } catch (e) {}
+    try { print(b1 + new c1); } catch (e) {}
 })();
--- a/nashorn/test/script/basic/JDK-8027042.js.EXPECTED	Thu Mar 27 14:09:40 2014 +0100
+++ b/nashorn/test/script/basic/JDK-8027042.js.EXPECTED	Mon Mar 31 14:13:34 2014 +0200
@@ -1,8 +1,10 @@
+start
 get b
 get a
 conv c
 conv b
 111
+done with first
 get b
 get b
 conv c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/script/currently-failing/JDK-8010697.js	Mon Mar 31 14:13:34 2014 +0200
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/**
+ * JDK-8010697: DeletedArrayFilter seems to leak memory
+ *
+ * @test
+ * @run
+ */
+
+var N = 1000;
+
+var array = new Array(N);
+var WeakReferenceArray = Java.type("java.lang.ref.WeakReference[]");
+var refArray = new WeakReferenceArray(N);
+
+for (var i = 0; i < N; i ++) {
+    var object = new java.awt.Color(0,0,0);//lang.Object();
+    array[i] = object;
+    refArray[i] = new java.lang.ref.WeakReference(object);
+}
+
+object = null;
+
+for (var i = 0; i < N; i ++) {
+    delete array[i];
+}
+
+java.lang.System.gc();
+java.lang.System.gc();
+java.lang.System.gc();
+
+for (var i = 0; i < N; i ++) {
+    if (refArray[i].get() != null) {
+        print("Reference found at " + i + " " + refArray + " " + refArray[i].get());
+    }
+}
+
+print("All references gone");
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/script/currently-failing/JDK-8010697.js.EXPECTED	Mon Mar 31 14:13:34 2014 +0200
@@ -0,0 +1,1 @@
+All references gone
--- a/nashorn/test/src/jdk/nashorn/api/scripting/ScopeTest.java	Thu Mar 27 14:09:40 2014 +0100
+++ b/nashorn/test/src/jdk/nashorn/api/scripting/ScopeTest.java	Mon Mar 31 14:13:34 2014 +0200
@@ -47,7 +47,7 @@
     public void createBindingsTest() {
         final ScriptEngineManager m = new ScriptEngineManager();
         final ScriptEngine e = m.getEngineByName("nashorn");
-        Bindings b = e.createBindings();
+        final Bindings b = e.createBindings();
         b.put("foo", 42.0);
         Object res = null;
         try {
@@ -64,7 +64,7 @@
     public void engineScopeTest() {
         final ScriptEngineManager m = new ScriptEngineManager();
         final ScriptEngine e = m.getEngineByName("nashorn");
-        Bindings engineScope = e.getBindings(ScriptContext.ENGINE_SCOPE);
+        final Bindings engineScope = e.getBindings(ScriptContext.ENGINE_SCOPE);
 
         // check few ECMA standard built-in global properties
         assertNotNull(engineScope.get("Object"));
@@ -112,8 +112,8 @@
         newCtxt.setBindings(b, ScriptContext.ENGINE_SCOPE);
 
         try {
-            Object obj1 = e.eval("Object");
-            Object obj2 = e.eval("Object", newCtxt);
+            final Object obj1 = e.eval("Object");
+            final Object obj2 = e.eval("Object", newCtxt);
             Assert.assertNotEquals(obj1, obj2);
             Assert.assertNotNull(obj1);
             Assert.assertNotNull(obj2);
@@ -138,10 +138,12 @@
             e.eval("y = new Object()");
             e.eval("y = new Object()", origCtxt);
 
-            Object y1 = origCtxt.getAttribute("y");
-            Object y2 = newCtxt.getAttribute("y");
+            final Object y1 = origCtxt.getAttribute("y");
+            final Object y2 = newCtxt.getAttribute("y");
             Assert.assertNotEquals(y1, y2);
-            Assert.assertNotEquals(e.eval("y"), e.eval("y", origCtxt));
+            final Object yeval1 = e.eval("y");
+            final Object yeval2 = e.eval("y", origCtxt);
+            Assert.assertNotEquals(yeval1, yeval2);
             Assert.assertEquals("[object Object]", y1.toString());
             Assert.assertEquals("[object Object]", y2.toString());
         } catch (final ScriptException se) {
@@ -159,7 +161,7 @@
         final ScriptContext newContext = new SimpleScriptContext();
         newContext.setBindings(new SimpleBindings(), ScriptContext.ENGINE_SCOPE);
         // we are using a new bindings - so it should have 'func' defined
-        Object value = e.eval("typeof func", newContext);
+        final Object value = e.eval("typeof func", newContext);
         assertTrue(value.equals("undefined"));
     }
 
@@ -210,7 +212,7 @@
         assertTrue(value instanceof ScriptObjectMirror && ((ScriptObjectMirror)value).isFunction());
 
         // check new global instance created has engine.js definitions
-        Bindings b = e.createBindings();
+        final Bindings b = e.createBindings();
         value = b.get("__noSuchProperty__");
         assertTrue(value instanceof ScriptObjectMirror && ((ScriptObjectMirror)value).isFunction());
         value = b.get("print");
@@ -231,7 +233,7 @@
         assertTrue(e.eval("x", ctx).equals("hello"));
 
         // try some arbitray Bindings for ENGINE_SCOPE
-        Bindings sb = new SimpleBindings();
+        final Bindings sb = new SimpleBindings();
         ctx.setBindings(sb, ScriptContext.ENGINE_SCOPE);
 
         // GLOBAL_SCOPE mapping should be visible from non-default ScriptContext eval
@@ -305,7 +307,7 @@
         t1.join();
         t2.join();
 
-        Object obj3 = e.eval("delete foo; foo = 'newer context';", newCtxt);
+        final Object obj3 = e.eval("delete foo; foo = 'newer context';", newCtxt);
         assertEquals(obj3, "newer context");
         final Thread t3 = new Thread(new ScriptRunner(e, origContext, sharedScript, "original context", 1000));
         final Thread t4 = new Thread(new ScriptRunner(e, newCtxt, sharedScript, "newer context", 1000));
@@ -342,7 +344,7 @@
                     for (int i = 0; i < 1000; i++) {
                         assertEquals(e.eval(sharedScript, origContext), (double)i);
                     }
-                } catch (ScriptException se) {
+                } catch (final ScriptException se) {
                     fail(se.toString());
                 }
             }
@@ -354,7 +356,7 @@
                     for (int i = 2; i < 1000; i++) {
                         assertEquals(e.eval(sharedScript, newCtxt), (double)i);
                     }
-                } catch (ScriptException se) {
+                } catch (final ScriptException se) {
                     fail(se.toString());
                 }
             }
@@ -377,8 +379,8 @@
         final ScriptContext newCtxt = new SimpleScriptContext();
         newCtxt.setBindings(b, ScriptContext.ENGINE_SCOPE);
 
-        Object obj1 = e.eval("String.prototype.foo = 'original context';", origContext);
-        Object obj2 = e.eval("String.prototype.foo = 'new context';", newCtxt);
+        final Object obj1 = e.eval("String.prototype.foo = 'original context';", origContext);
+        final Object obj2 = e.eval("String.prototype.foo = 'new context';", newCtxt);
         assertEquals(obj1, "original context");
         assertEquals(obj2, "new context");
         final String sharedScript = "''.foo";
@@ -390,7 +392,7 @@
         t1.join();
         t2.join();
 
-        Object obj3 = e.eval("delete String.prototype.foo; Object.prototype.foo = 'newer context';", newCtxt);
+        final Object obj3 = e.eval("delete String.prototype.foo; Object.prototype.foo = 'newer context';", newCtxt);
         assertEquals(obj3, "newer context");
         final Thread t3 = new Thread(new ScriptRunner(e, origContext, sharedScript, "original context", 1000));
         final Thread t4 = new Thread(new ScriptRunner(e, newCtxt, sharedScript, "newer context", 1000));
@@ -555,7 +557,7 @@
                 for (int i = 0; i < iterations; i++) {
                     assertEquals(engine.eval(source, context), expected);
                 }
-            } catch (ScriptException se) {
+            } catch (final ScriptException se) {
                 throw new RuntimeException(se);
             }
         }