changeset 830:03b2757e2eba

8038406: Testability: as a first step of moving loggers away from the process global space, the Debug object now supports logging POJOs from log entries as an event queue, which can be introspected from test scripts. This is way better than screen scraping brittle and subject-to-change log output. Reviewed-by: attila, hannesw, sundar
author lagergren
date Thu, 27 Mar 2014 11:45:54 +0100
parents 95fed751dc0e
children fa068c865e46
files bin/runoptdualcatch.sh buildtools/nasgen/src/jdk/nashorn/internal/tools/nasgen/StringConstants.java src/jdk/nashorn/api/scripting/NashornScriptEngine.java src/jdk/nashorn/api/scripting/NashornScriptEngineFactory.java src/jdk/nashorn/internal/codegen/Attr.java src/jdk/nashorn/internal/codegen/CodeGenerator.java src/jdk/nashorn/internal/codegen/CompilationPhase.java src/jdk/nashorn/internal/codegen/Compiler.java src/jdk/nashorn/internal/codegen/DumpBytecode.java src/jdk/nashorn/internal/codegen/ObjectClassGenerator.java src/jdk/nashorn/internal/codegen/Splitter.java src/jdk/nashorn/internal/ir/IdentNode.java src/jdk/nashorn/internal/objects/Global.java src/jdk/nashorn/internal/objects/NativeArrayBuffer.java src/jdk/nashorn/internal/objects/NativeDebug.java src/jdk/nashorn/internal/runtime/AccessorProperty.java src/jdk/nashorn/internal/runtime/CompiledFunction.java src/jdk/nashorn/internal/runtime/Context.java src/jdk/nashorn/internal/runtime/DebugLogger.java src/jdk/nashorn/internal/runtime/JSONFunctions.java src/jdk/nashorn/internal/runtime/ListAdapter.java src/jdk/nashorn/internal/runtime/Logging.java src/jdk/nashorn/internal/runtime/PropertyListeners.java src/jdk/nashorn/internal/runtime/RecompilableScriptFunctionData.java src/jdk/nashorn/internal/runtime/RewriteException.java src/jdk/nashorn/internal/runtime/RuntimeEvent.java src/jdk/nashorn/internal/runtime/ScriptFunction.java src/jdk/nashorn/internal/runtime/ScriptFunctionData.java src/jdk/nashorn/internal/runtime/ScriptObject.java src/jdk/nashorn/internal/runtime/linker/NashornCallSiteDescriptor.java src/jdk/nashorn/internal/runtime/linker/NashornGuards.java src/jdk/nashorn/internal/runtime/linker/NashornPrimitiveLinker.java src/jdk/nashorn/internal/runtime/linker/PrimitiveLookup.java src/jdk/nashorn/tools/Shell.java test/script/trusted/JDK-8006529.js test/script/trusted/event_queue.js test/script/trusted/event_queue.js.EXPECTED test/src/jdk/nashorn/internal/runtime/NoPersistenceCachingTest.java
diffstat 38 files changed, 830 insertions(+), 165 deletions(-) [+]
line wrap: on
line diff
--- a/bin/runoptdualcatch.sh	Wed Mar 26 15:00:32 2014 +0100
+++ b/bin/runoptdualcatch.sh	Thu Mar 27 11:45:54 2014 +0100
@@ -1,6 +1,7 @@
 #!/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"
+#FLAGS="-Djava.security.manager -Djava.security.policy=../build/nashorn.policy -Dnashorn.debug"
 
 FILENAME="./optimistic_dual_catch_$(date|sed "s/ /_/g"|sed "s/:/_/g").jfr"
 
--- a/buildtools/nasgen/src/jdk/nashorn/internal/tools/nasgen/StringConstants.java	Wed Mar 26 15:00:32 2014 +0100
+++ b/buildtools/nasgen/src/jdk/nashorn/internal/tools/nasgen/StringConstants.java	Thu Mar 27 11:45:54 2014 +0100
@@ -26,7 +26,6 @@
 package jdk.nashorn.internal.tools.nasgen;
 
 import java.lang.invoke.MethodHandle;
-import java.lang.reflect.Method;
 import java.util.Collection;
 import java.util.ArrayList;
 import java.util.Collections;
--- a/src/jdk/nashorn/api/scripting/NashornScriptEngine.java	Wed Mar 26 15:00:32 2014 +0100
+++ b/src/jdk/nashorn/api/scripting/NashornScriptEngine.java	Thu Mar 27 11:45:54 2014 +0100
@@ -388,7 +388,7 @@
         }
 
         // Arbitrary user Bindings implementation. Look for NASHORN_GLOBAL in it!
-        Object scope = bindings.get(NASHORN_GLOBAL);
+        final Object scope = bindings.get(NASHORN_GLOBAL);
         if (scope instanceof ScriptObjectMirror) {
             final Global glob = globalFromMirror((ScriptObjectMirror)scope);
             if (glob != null) {
@@ -405,7 +405,7 @@
 
     // Retrieve nashorn Global object from a given ScriptObjectMirror
     private Global globalFromMirror(final ScriptObjectMirror mirror) {
-        ScriptObject sobj = mirror.getScriptObject();
+        final ScriptObject sobj = mirror.getScriptObject();
         if (sobj instanceof Global && isOfContext((Global)sobj, nashornContext)) {
             return (Global)sobj;
         }
@@ -643,7 +643,7 @@
                 continue;
             }
 
-            Object obj = sobj.get(method.getName());
+            final Object obj = sobj.get(method.getName());
             if (! (obj instanceof ScriptFunction)) {
                 return false;
             }
--- a/src/jdk/nashorn/api/scripting/NashornScriptEngineFactory.java	Wed Mar 26 15:00:32 2014 +0100
+++ b/src/jdk/nashorn/api/scripting/NashornScriptEngineFactory.java	Thu Mar 27 11:45:54 2014 +0100
@@ -220,7 +220,7 @@
         // Revisit: script engine implementation needs the capability to
         // find the class loader of the context in which the script engine
         // is running so that classes will be found and loaded properly
-        ClassLoader ccl = Thread.currentThread().getContextClassLoader();
+        final ClassLoader ccl = Thread.currentThread().getContextClassLoader();
         return (ccl == null)? NashornScriptEngineFactory.class.getClassLoader() : ccl;
     }
 }
--- a/src/jdk/nashorn/internal/codegen/Attr.java	Wed Mar 26 15:00:32 2014 +0100
+++ b/src/jdk/nashorn/internal/codegen/Attr.java	Thu Mar 27 11:45:54 2014 +0100
@@ -172,11 +172,11 @@
     }
 
     @Override
-    public boolean enterAccessNode(AccessNode accessNode) {
+    public boolean enterAccessNode(final AccessNode accessNode) {
         tagNeverOptimistic(accessNode.getBase());
         tagNeverOptimistic(accessNode.getProperty());
         return true;
-    };
+    }
 
     @Override
     public Node leaveAccessNode(final AccessNode accessNode) {
@@ -423,7 +423,7 @@
     private Symbol defineSymbol(final Block block, final String name, final int symbolFlags) {
         int     flags    = symbolFlags;
         Symbol  symbol   = findSymbol(block, name); // Locate symbol.
-        boolean isGlobal = (flags & KINDMASK) == IS_GLOBAL;
+        final boolean isGlobal = (flags & KINDMASK) == IS_GLOBAL;
 
         if (isGlobal) {
             flags |= IS_SCOPE;
@@ -805,7 +805,7 @@
     }
 
     @Override
-    public boolean enterIndexNode(IndexNode indexNode) {
+    public boolean enterIndexNode(final IndexNode indexNode) {
         tagNeverOptimistic(indexNode.getBase());
         return true;
     }
--- a/src/jdk/nashorn/internal/codegen/CodeGenerator.java	Wed Mar 26 15:00:32 2014 +0100
+++ b/src/jdk/nashorn/internal/codegen/CodeGenerator.java	Thu Mar 27 11:45:54 2014 +0100
@@ -3493,7 +3493,6 @@
      * @param block the block we are in
      * @param ident identifier for block or function where applicable
      */
-    @SuppressWarnings("resource")
     private void printSymbols(final Block block, final String ident) {
         if (!compiler.getEnv()._print_symbols) {
             return;
@@ -4287,6 +4286,7 @@
                 } else {
                     method.invoke(INIT_REWRITE_EXCEPTION);
                 }
+
                 method.athrow();
             }
         }
@@ -4398,10 +4398,10 @@
         method.lineNumber(0);
 
         final Type[] lvarTypes = ci.localVariableTypes;
-        final int lvarCount = lvarTypes.length;
-
-        final Type exceptionType = Type.typeFor(RewriteException.class);
-        method.load(exceptionType, 0);
+        final int    lvarCount = lvarTypes.length;
+
+        final Type rewriteExceptionType = Type.typeFor(RewriteException.class);
+        method.load(rewriteExceptionType, 0);
         method.dup();
         // Get local variable array
         method.invoke(RewriteException.GET_BYTECODE_SLOTS);
@@ -4424,7 +4424,7 @@
         final boolean isStackEmpty = stackStoreSpec.length == 0;
         if(!isStackEmpty) {
             // Store the RewriteException into an unused local variable slot.
-            method.store(exceptionType, lvarCount);
+            method.store(rewriteExceptionType, lvarCount);
             // Load arguments on the stack
             for(int i = 0; i < stackStoreSpec.length; ++i) {
                 final int slot = stackStoreSpec[i];
--- a/src/jdk/nashorn/internal/codegen/CompilationPhase.java	Wed Mar 26 15:00:32 2014 +0100
+++ b/src/jdk/nashorn/internal/codegen/CompilationPhase.java	Thu Mar 27 11:45:54 2014 +0100
@@ -1,5 +1,6 @@
 package jdk.nashorn.internal.codegen;
 
+import static jdk.nashorn.internal.codegen.Compiler.info;
 import static jdk.nashorn.internal.ir.FunctionNode.CompilationState.ATTR;
 import static jdk.nashorn.internal.ir.FunctionNode.CompilationState.CONSTANT_FOLDED;
 import static jdk.nashorn.internal.ir.FunctionNode.CompilationState.FINALIZED;
@@ -127,7 +128,7 @@
                         accept(new Attr(compiler.getCompilationEnvironment(), ts));
 
             if (compiler.getEnv()._print_mem_usage) {
-                Compiler.LOG.info("Attr temporary symbol count: " + ts.getTotalSymbolCount());
+                info("Attr temporary symbol count:", ts.getTotalSymbolCount());
             }
 
             return newFunctionNode;
--- a/src/jdk/nashorn/internal/codegen/Compiler.java	Wed Mar 26 15:00:32 2014 +0100
+++ b/src/jdk/nashorn/internal/codegen/Compiler.java	Thu Mar 27 11:45:54 2014 +0100
@@ -104,7 +104,15 @@
 
     /** logger for compiler, trampolines, splits and related code generation events
      *  that affect classes */
-    public static final DebugLogger LOG = new DebugLogger("compiler");
+    private static final DebugLogger LOG = new DebugLogger("compiler");
+
+    /**
+     * Get the logger used for this compiler
+     * @return logger
+     */
+    public static DebugLogger getLogger() {
+        return LOG;
+    }
 
     static {
         if (!ScriptEnvironment.globalOptimistic()) {
@@ -170,21 +178,28 @@
     }
 
     private static void printMemoryUsage(final String phaseName, final FunctionNode functionNode) {
-        LOG.info(phaseName + " finished. Doing IR size calculation...");
+        if (!LOG.isEnabled()) {
+            return;
+        }
+
+        info(phaseName, "finished. Doing IR size calculation...");
 
         final ObjectSizeCalculator osc = new ObjectSizeCalculator(ObjectSizeCalculator.getEffectiveMemoryLayoutSpecification());
         osc.calculateObjectSize(functionNode);
 
-        final List<ClassHistogramElement> list = osc.getClassHistogram();
+        final List<ClassHistogramElement> list      = osc.getClassHistogram();
+        final StringBuilder               sb        = new StringBuilder();
+        final long                        totalSize = osc.calculateObjectSize(functionNode);
 
-        final StringBuilder sb = new StringBuilder();
-        final long totalSize = osc.calculateObjectSize(functionNode);
-        sb.append(phaseName).append(" Total size = ").append(totalSize / 1024 / 1024).append("MB");
+        sb.append(phaseName).
+            append(" Total size = ").
+            append(totalSize / 1024 / 1024).
+            append("MB");
         LOG.info(sb);
 
         Collections.sort(list, new Comparator<ClassHistogramElement>() {
             @Override
-            public int compare(ClassHistogramElement o1, ClassHistogramElement o2) {
+            public int compare(final ClassHistogramElement o1, final ClassHistogramElement o2) {
                 final long diff = o1.getBytes() - o2.getBytes();
                 if (diff < 0) {
                     return 1;
@@ -197,9 +212,9 @@
         });
         for (final ClassHistogramElement e : list) {
             final String line = String.format("    %-48s %10d bytes (%8d instances)", e.getClazz(), e.getBytes(), e.getInstances());
-            LOG.info(line);
+            info(line);
             if (e.getBytes() < totalSize / 200) {
-                LOG.info("    ...");
+                info("    ...");
                 break; // never mind, so little memory anyway
             }
         }
@@ -507,4 +522,36 @@
     public static String binaryName(final String name) {
         return name.replace('/', '.');
     }
+
+    /**
+     * Log hook; level finest
+     * @param args args
+     */
+    public static void finest(final Object... args) {
+        LOG.finest(args);
+    }
+
+    /**
+     * Log hook; level fine
+     * @param args args
+     */
+    public static void fine(final Object... args) {
+        LOG.fine(args);
+    }
+
+    /**
+     * Log hook; level info
+     * @param args args
+     */
+    public static void info(final Object... args) {
+        LOG.info(args);
+    }
+
+    /**
+     * Log hook; level warning
+     * @param args args
+     */
+    public static void warning(final Object... args) {
+        LOG.warning(args);
+    }
 }
--- a/src/jdk/nashorn/internal/codegen/DumpBytecode.java	Wed Mar 26 15:00:32 2014 +0100
+++ b/src/jdk/nashorn/internal/codegen/DumpBytecode.java	Thu Mar 27 11:45:54 2014 +0100
@@ -25,6 +25,9 @@
 
 package jdk.nashorn.internal.codegen;
 
+import static jdk.nashorn.internal.codegen.Compiler.info;
+import static jdk.nashorn.internal.codegen.Compiler.warning;
+
 import java.io.File;
 import java.io.FileOutputStream;
 import java.io.IOException;
@@ -98,10 +101,10 @@
                 try (final FileOutputStream fos = new FileOutputStream(file)) {
                     fos.write(bytecode);
                 }
-                Compiler.LOG.info("Wrote class to '" + file.getAbsolutePath() + '\'');
+                info("Wrote class to '" + file.getAbsolutePath() + '\'');
             }
         } catch (final IOException e) {
-            Compiler.LOG.warning("Skipping class dump for ",
+            warning("Skipping class dump for ",
                     className,
                     ": ",
                     ECMAErrors.getMessage(
@@ -109,5 +112,4 @@
                         dir.toString()));
         }
     }
-
 }
--- a/src/jdk/nashorn/internal/codegen/ObjectClassGenerator.java	Wed Mar 26 15:00:32 2014 +0100
+++ b/src/jdk/nashorn/internal/codegen/ObjectClassGenerator.java	Thu Mar 27 11:45:54 2014 +0100
@@ -89,7 +89,15 @@
      * Debug field logger
      * Should we print debugging information for fields when they are generated and getters/setters are called?
      */
-    public static final DebugLogger LOG = new DebugLogger("fields", "nashorn.fields.debug");
+    private static final DebugLogger LOG = new DebugLogger("fields", "nashorn.fields.debug");
+
+    /**
+     * Get the field logger
+     * @return logger
+     */
+    public static DebugLogger getLogger() {
+        return LOG;
+    }
 
     private static final Set<String> FIELDS_TO_INSTRUMENT;
     static {
--- a/src/jdk/nashorn/internal/codegen/Splitter.java	Wed Mar 26 15:00:32 2014 +0100
+++ b/src/jdk/nashorn/internal/codegen/Splitter.java	Thu Mar 27 11:45:54 2014 +0100
@@ -26,6 +26,7 @@
 package jdk.nashorn.internal.codegen;
 
 import static jdk.nashorn.internal.codegen.CompilerConstants.SPLIT_PREFIX;
+import static jdk.nashorn.internal.codegen.Compiler.finest;
 
 import java.util.ArrayList;
 import java.util.HashMap;
@@ -42,7 +43,6 @@
 import jdk.nashorn.internal.ir.SplitNode;
 import jdk.nashorn.internal.ir.Statement;
 import jdk.nashorn.internal.ir.visitor.NodeVisitor;
-import jdk.nashorn.internal.runtime.DebugLogger;
 import jdk.nashorn.internal.runtime.options.Options;
 
 /**
@@ -64,8 +64,6 @@
     /** Weight threshold for when to start a split. */
     public static final long SPLIT_THRESHOLD = Options.getIntProperty("nashorn.compiler.splitter.threshold", 32 * 1024);
 
-    private static final DebugLogger LOG = Compiler.LOG;
-
     /**
      * Constructor.
      *
@@ -85,10 +83,10 @@
      * @param fn the function to split
      * @param top whether this is the topmost compiled function (it's either a program, or we're doing a recompilation).
      */
-    FunctionNode split(final FunctionNode fn, boolean top) {
+    FunctionNode split(final FunctionNode fn, final boolean top) {
         FunctionNode functionNode = fn;
 
-        LOG.finest("Initiating split of '", functionNode.getName(), "'");
+        finest("Initiating split of '", functionNode.getName(), "'");
 
         long weight = WeighNodes.weigh(functionNode);
 
@@ -97,7 +95,7 @@
         assert lc.isEmpty() : "LexicalContext not empty";
 
         if (weight >= SPLIT_THRESHOLD) {
-            LOG.finest("Splitting '", functionNode.getName(), "' as its weight ", weight, " exceeds split threshold ", SPLIT_THRESHOLD);
+            finest("Splitting '", functionNode.getName(), "' as its weight ", weight, " exceeds split threshold ", SPLIT_THRESHOLD);
             functionNode = (FunctionNode)functionNode.accept(this);
 
             if (functionNode.isSplit()) {
@@ -134,7 +132,7 @@
 
             @Override
             public Node leaveFunctionNode(final FunctionNode nestedFunction) {
-                FunctionNode split = new Splitter(compiler, nestedFunction, outermostCompileUnit).split(nestedFunction, false);
+                final FunctionNode split = new Splitter(compiler, nestedFunction, outermostCompileUnit).split(nestedFunction, false);
                 lc.replace(nestedFunction, split);
                 return split;
             }
--- a/src/jdk/nashorn/internal/ir/IdentNode.java	Wed Mar 26 15:00:32 2014 +0100
+++ b/src/jdk/nashorn/internal/ir/IdentNode.java	Thu Mar 27 11:45:54 2014 +0100
@@ -220,7 +220,7 @@
             return this;
         }
         if (DEBUG_FIELDS && ObjectClassGenerator.shouldInstrument(getName()) && getSymbol() != null && !Type.areEquivalent(getSymbol().getSymbolType(), callSiteType)) {
-            ObjectClassGenerator.LOG.info(getClass().getName(), " ", this, " => ", callSiteType, " instead of ", getType());
+            ObjectClassGenerator.getLogger().info(getClass().getName(), " ", this, " => ", callSiteType, " instead of ", getType());
         }
         return new IdentNode(this, name, callSiteType, flags, programPoint);
     }
--- a/src/jdk/nashorn/internal/objects/Global.java	Wed Mar 26 15:00:32 2014 +0100
+++ b/src/jdk/nashorn/internal/objects/Global.java	Thu Mar 27 11:45:54 2014 +0100
@@ -38,6 +38,7 @@
 import java.util.Map;
 import java.util.concurrent.Callable;
 import java.util.concurrent.ConcurrentHashMap;
+
 import jdk.internal.dynalink.linker.GuardedInvocation;
 import jdk.internal.dynalink.linker.LinkRequest;
 import jdk.nashorn.internal.lookup.Lookup;
@@ -54,7 +55,6 @@
 import jdk.nashorn.internal.runtime.Scope;
 import jdk.nashorn.internal.runtime.ScriptEnvironment;
 import jdk.nashorn.internal.runtime.ScriptFunction;
-import jdk.nashorn.internal.runtime.ScriptFunctionData;
 import jdk.nashorn.internal.runtime.ScriptObject;
 import jdk.nashorn.internal.runtime.ScriptRuntime;
 import jdk.nashorn.internal.runtime.ScriptingFunctions;
@@ -490,20 +490,6 @@
     }
 
     /**
-     * Create a new ScriptFunction object
-     *
-     * @param name   function name
-     * @param handle invocation handle for function
-     * @param scope  the scope
-     * @param strict are we in strict mode
-     *
-     * @return new script function
-     */
-    public ScriptFunction newScriptFunction(final String name, final MethodHandle handle, final ScriptObject scope, final boolean strict) {
-        return new ScriptFunctionImpl(name, handle, scope, null, strict ? ScriptFunctionData.IS_STRICT_CONSTRUCTOR : ScriptFunctionData.IS_CONSTRUCTOR);
-    }
-
-    /**
      * Wrap a Java object as corresponding script object
      *
      * @param obj object to wrap
@@ -538,7 +524,7 @@
      *
      * @return guarded invocation
      */
-    public GuardedInvocation primitiveLookup(final LinkRequest request, final Object self) {
+    public static GuardedInvocation primitiveLookup(final LinkRequest request, final Object self) {
         if (self instanceof String || self instanceof ConsString) {
             return NativeString.lookupPrimitive(request, self);
         } else if (self instanceof Number) {
@@ -730,6 +716,7 @@
      * @param value of the data property
      * @param configurable is the property configurable?
      * @param enumerable is the property enumerable?
+     * @param writable is the property writable?
      * @return newly created DataPropertyDescriptor object
      */
     public PropertyDescriptor newDataDescriptor(final Object value, final boolean configurable, final boolean enumerable, final boolean writable) {
@@ -1829,7 +1816,6 @@
         this.addOwnProperty("Debug", Attribute.NOT_ENUMERABLE, initConstructor("Debug"));
     }
 
-    @SuppressWarnings("resource")
     private static Object printImpl(final boolean newLine, final Object... objects) {
         final PrintWriter out = Global.getEnv().getOut();
         final StringBuilder sb = new StringBuilder();
--- a/src/jdk/nashorn/internal/objects/NativeArrayBuffer.java	Wed Mar 26 15:00:32 2014 +0100
+++ b/src/jdk/nashorn/internal/objects/NativeArrayBuffer.java	Thu Mar 27 11:45:54 2014 +0100
@@ -50,19 +50,6 @@
     // initialized by nasgen
     private static PropertyMap $nasgenmap$;
 
-    @Constructor(arity = 1)
-    public static Object constructor(final boolean newObj, final Object self, final Object... args) {
-        if (!newObj) {
-            throw typeError("constructor.requires.new", "ArrayBuffer");
-        }
-
-        if (args.length == 0) {
-            throw new RuntimeException("missing length argument");
-        }
-
-        return new NativeArrayBuffer(JSType.toInt32(args[0]));
-    }
-
     /**
      * Constructor
      * @param nb native byte buffer to wrap
@@ -100,7 +87,27 @@
         this(cloneBuffer(other.getNioBuffer(), begin, end));
     }
 
-    private static ByteBuffer cloneBuffer(ByteBuffer original, final int begin, final int end) {
+    /**
+     * Constructor
+     * @param newObj is this invoked with new
+     * @param self   self reference
+     * @param args   arguments to constructor
+     * @return new NativeArrayBuffer
+     */
+    @Constructor(arity = 1)
+    public static Object constructor(final boolean newObj, final Object self, final Object... args) {
+        if (!newObj) {
+            throw typeError("constructor.requires.new", "ArrayBuffer");
+        }
+
+        if (args.length == 0) {
+            throw new RuntimeException("missing length argument");
+        }
+
+        return new NativeArrayBuffer(JSType.toInt32(args[0]));
+    }
+
+    private static ByteBuffer cloneBuffer(final ByteBuffer original, final int begin, final int end) {
         final ByteBuffer clone = ByteBuffer.allocateDirect(original.capacity());
         original.rewind();//copy from the beginning
         clone.put(original);
--- a/src/jdk/nashorn/internal/objects/NativeDebug.java	Wed Mar 26 15:00:32 2014 +0100
+++ b/src/jdk/nashorn/internal/objects/NativeDebug.java	Thu Mar 27 11:45:54 2014 +0100
@@ -28,14 +28,18 @@
 import static jdk.nashorn.internal.runtime.ScriptRuntime.UNDEFINED;
 
 import java.io.PrintWriter;
+import java.util.LinkedList;
 import java.util.Objects;
+
 import jdk.nashorn.internal.objects.annotations.Attribute;
 import jdk.nashorn.internal.objects.annotations.Function;
 import jdk.nashorn.internal.objects.annotations.ScriptClass;
 import jdk.nashorn.internal.objects.annotations.Where;
 import jdk.nashorn.internal.runtime.Context;
+import jdk.nashorn.internal.runtime.JSType;
 import jdk.nashorn.internal.runtime.PropertyListeners;
 import jdk.nashorn.internal.runtime.PropertyMap;
+import jdk.nashorn.internal.runtime.RuntimeEvent;
 import jdk.nashorn.internal.runtime.ScriptFunction;
 import jdk.nashorn.internal.runtime.ScriptObject;
 import jdk.nashorn.internal.runtime.linker.LinkerCallSite;
@@ -206,7 +210,6 @@
      * @param self self reference
      * @return undefined
      */
-    @SuppressWarnings("resource")
     @Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR)
     public static Object dumpCounters(final Object self) {
         final PrintWriter out = Context.getCurrentErr();
@@ -233,4 +236,133 @@
 
         return UNDEFINED;
     }
+
+    /*
+     * Framework for logging runtime events
+     */
+
+    private static final String EVENT_QUEUE          = "__eventQueue__";
+    private static final String EVENT_QUEUE_CAPACITY = "__eventQueueCapacity__";
+
+    /**
+     * Get the capacity of the event queue
+     * @param self self reference
+     * @return capacity of event queue as an integer
+     */
+    @Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR)
+    public static Object getEventQueueCapacity(final Object self) {
+        final ScriptObject sobj = (ScriptObject)self;
+        Integer cap;
+        if (sobj.has(EVENT_QUEUE_CAPACITY)) {
+            cap = JSType.toInt32(sobj.get(EVENT_QUEUE_CAPACITY));
+        } else {
+            setEventQueueCapacity(self, cap = RuntimeEvent.RUNTIME_EVENT_QUEUE_SIZE);
+        }
+        return cap;
+    }
+
+    /**
+     * Set the event queue capacity
+     * @param self
+     * @param newCapacity
+     */
+    @Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR)
+    public static void setEventQueueCapacity(final Object self, final Object newCapacity) {
+        ((ScriptObject)self).set(EVENT_QUEUE_CAPACITY, newCapacity, true);
+    }
+
+    /**
+     * Add a runtime event to the runtime event queue. The queue has a fixed
+     * size {@link RuntimeEvent#RUNTIME_EVENT_QUEUE_SIZE} and the oldest
+     * entry will be thrown out of the queue is about to overflow
+     * @param self self reference
+     * @param event event to add
+     */
+    @Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR)
+    public static void addRuntimeEvent(final Object self, final Object event) {
+        final LinkedList<RuntimeEvent<?>> q = getEventQueue(self);
+        final int cap = (Integer)getEventQueueCapacity(self);
+        while (q.size() >= cap) {
+            q.removeFirst();
+        }
+        q.addLast(getEvent(event));
+    }
+
+    /**
+     * Expands the event queue capacity, or truncates if capacity is lower than
+     * current capacity. Then only the newest entries are kept
+     * @param self self reference
+     * @param newCapacity new capacity
+     */
+    @Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR)
+    public static void expandEventQueueCapacity(final Object self, final Object newCapacity) {
+        final LinkedList<RuntimeEvent<?>> q = getEventQueue(self);
+        final int nc = JSType.toInt32(newCapacity);
+        while (q.size() > nc) {
+            q.removeFirst();
+        }
+        setEventQueueCapacity(self, nc);
+    }
+
+    /**
+     * Clear the runtime event queue
+     * @param self self reference
+     */
+    @Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR)
+    public static void clearRuntimeEvents(final Object self) {
+        final LinkedList<RuntimeEvent<?>> q = getEventQueue(self);
+        q.clear();
+    }
+
+    /**
+     * Remove a specific runtime event from the event queue
+     * @param self self reference
+     * @param event event to remove
+     */
+    @Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR)
+    public static void removeRuntimeEvent(final Object self, final Object event) {
+        final LinkedList<RuntimeEvent<?>> q  = getEventQueue(self);
+        final RuntimeEvent<?>             re = getEvent(event);
+        if (!q.remove(re)) {
+            throw new IllegalStateException("runtime event " + re + " was not in event queue");
+        }
+    }
+
+    /**
+     * Return all runtime events in the queue as an array
+     * @param self self reference
+     * @return array of events
+     */
+    @Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR)
+    public static RuntimeEvent<?>[] getRuntimeEvents(final Object self) {
+        final LinkedList<RuntimeEvent<?>> q = getEventQueue(self);
+        return q.toArray(new RuntimeEvent<?>[q.size()]);
+    }
+
+    /**
+     * Return the last runtime event in the queue
+     * @param self self reference
+     * @return the freshest event, null if queue is empty
+     */
+    @Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR)
+    public static RuntimeEvent<?> getLastRuntimeEvent(final Object self) {
+        final LinkedList<RuntimeEvent<?>> q = getEventQueue(self);
+        return q.isEmpty() ? null : q.getLast();
+    }
+
+    @SuppressWarnings("unchecked")
+    private static LinkedList<RuntimeEvent<?>> getEventQueue(final Object self) {
+        final ScriptObject sobj = (ScriptObject)self;
+        LinkedList<RuntimeEvent<?>> q;
+        if (sobj.has(EVENT_QUEUE)) {
+            q = (LinkedList<RuntimeEvent<?>>)((ScriptObject)self).get(EVENT_QUEUE);
+        } else {
+            ((ScriptObject)self).set(EVENT_QUEUE, q = new LinkedList<>(), true);
+        }
+        return q;
+    }
+
+    private static RuntimeEvent<?> getEvent(final Object event) {
+        return (RuntimeEvent<?>)event;
+    }
 }
--- a/src/jdk/nashorn/internal/runtime/AccessorProperty.java	Wed Mar 26 15:00:32 2014 +0100
+++ b/src/jdk/nashorn/internal/runtime/AccessorProperty.java	Thu Mar 27 11:45:54 2014 +0100
@@ -26,7 +26,6 @@
 package jdk.nashorn.internal.runtime;
 
 import static jdk.nashorn.internal.codegen.ObjectClassGenerator.DEBUG_FIELDS;
-import static jdk.nashorn.internal.codegen.ObjectClassGenerator.LOG;
 import static jdk.nashorn.internal.codegen.ObjectClassGenerator.OBJECT_FIELDS_ONLY;
 import static jdk.nashorn.internal.codegen.ObjectClassGenerator.PRIMITIVE_FIELD_TYPE;
 import static jdk.nashorn.internal.codegen.ObjectClassGenerator.createGetter;
@@ -58,6 +57,8 @@
 
     private static final int NOOF_TYPES = getNumberOfAccessorTypes();
 
+    private static final DebugLogger LOG = ObjectClassGenerator.getLogger();
+
     /**
      * Properties in different maps for the same structure class will share their field getters and setters. This could
      * be further extended to other method handles that are looked up in the AccessorProperty constructor, but right now
--- a/src/jdk/nashorn/internal/runtime/CompiledFunction.java	Wed Mar 26 15:00:32 2014 +0100
+++ b/src/jdk/nashorn/internal/runtime/CompiledFunction.java	Thu Mar 27 11:45:54 2014 +0100
@@ -27,7 +27,6 @@
 import static jdk.nashorn.internal.lookup.Lookup.MH;
 import static jdk.nashorn.internal.runtime.UnwarrantedOptimismException.INVALID_PROGRAM_POINT;
 import static jdk.nashorn.internal.runtime.UnwarrantedOptimismException.isValid;
-
 import java.lang.invoke.CallSite;
 import java.lang.invoke.MethodHandle;
 import java.lang.invoke.MethodHandles;
@@ -36,6 +35,8 @@
 import java.lang.invoke.SwitchPoint;
 import java.util.Map;
 import java.util.TreeMap;
+import java.util.logging.Level;
+
 import jdk.internal.dynalink.support.CatchExceptionCombinator;
 import jdk.nashorn.internal.codegen.types.ArrayType;
 import jdk.nashorn.internal.codegen.types.Type;
@@ -60,7 +61,7 @@
     private static final MethodHandle HANDLE_REWRITE_EXCEPTION = findOwnMH("handleRewriteException", MethodHandle.class, CompiledFunction.class, OptimismInfo.class, RewriteException.class);
     private static final MethodHandle RESTOF_INVOKER = MethodHandles.exactInvoker(MethodType.methodType(Object.class, RewriteException.class));
 
-    private static final DebugLogger LOG = new DebugLogger("recompile", "nashorn.codegen.debug");
+    private static final DebugLogger LOG = RecompilableScriptFunctionData.getLogger();
 
     /**
      * The method type may be more specific than the invoker, if. e.g.
@@ -561,7 +562,9 @@
         final MethodType callSiteType = type.parameterType(0) == ScriptFunction.class ? type : type.insertParameterTypes(0, ScriptFunction.class);
 
         final FunctionNode fn = oldOptimismInfo.recompile(callSiteType, re);
-        LOG.info("    RewriteException ", re.getMessageShort());
+        if (LOG.isEnabled()) {
+            LOG.info(new RuntimeEvent<>(Level.INFO, re), "\tRewriteException ", re.getMessageShort());
+        }
 
         // It didn't necessarily recompile, e.g. for an outer invocation of a recursive function if we already
         // recompiled a deoptimized version for an inner invocation.
@@ -578,7 +581,7 @@
             invoker = newInvoker.asType(type.changeReturnType(newInvoker.type().returnType()));
             constructor = null; // Will be regenerated when needed
             // Note that we only adjust the switch point after we set the invoker/constructor. This is important.
-            if(isOptimistic) {
+            if (isOptimistic) {
                 // Otherwise, set a new switch point.
                 oldOptimismInfo.newOptimisticAssumptions();
             } else {
--- a/src/jdk/nashorn/internal/runtime/Context.java	Wed Mar 26 15:00:32 2014 +0100
+++ b/src/jdk/nashorn/internal/runtime/Context.java	Thu Mar 27 11:45:54 2014 +0100
@@ -49,6 +49,8 @@
 import java.util.LinkedHashMap;
 import java.util.Map;
 import java.util.concurrent.atomic.AtomicLong;
+import java.util.logging.Level;
+
 import jdk.internal.org.objectweb.asm.ClassReader;
 import jdk.internal.org.objectweb.asm.util.CheckClassAdapter;
 import jdk.nashorn.api.scripting.ScriptObjectMirror;
@@ -910,7 +912,10 @@
 
         Class<?> script = findCachedClass(source);
         if (script != null) {
-            Compiler.LOG.fine("Code cache hit for ", source, " avoiding recompile.");
+            final DebugLogger LOG = Compiler.getLogger();
+            if (LOG.isEnabled()) {
+                LOG.fine(new RuntimeEvent<>(Level.INFO, source), "Code cache hit for ", source, " avoiding recompile.");
+            }
             return script;
         }
 
@@ -978,7 +983,7 @@
         private final int size;
         private final ReferenceQueue<Class<?>> queue;
 
-        ClassCache(int size) {
+        ClassCache(final int size) {
             super(size, 0.75f, true);
             this.size = size;
             this.queue = new ReferenceQueue<>();
@@ -994,7 +999,7 @@
         }
 
         @Override
-        public ClassReference get(Object key) {
+        public ClassReference get(final Object key) {
             for (ClassReference ref; (ref = (ClassReference)queue.poll()) != null; ) {
                 remove(ref.source);
             }
@@ -1014,7 +1019,7 @@
 
     // Class cache management
     private Class<?> findCachedClass(final Source source) {
-        ClassReference ref = classCache == null ? null : classCache.get(source);
+        final ClassReference ref = classCache == null ? null : classCache.get(source);
         return ref != null ? ref.get() : null;
     }
 
--- a/src/jdk/nashorn/internal/runtime/DebugLogger.java	Wed Mar 26 15:00:32 2014 +0100
+++ b/src/jdk/nashorn/internal/runtime/DebugLogger.java	Thu Mar 27 11:45:54 2014 +0100
@@ -28,6 +28,9 @@
 import java.io.PrintWriter;
 import java.util.logging.Level;
 import java.util.logging.Logger;
+
+import jdk.nashorn.internal.objects.Global;
+import jdk.nashorn.internal.runtime.RuntimeEvent;
 import jdk.nashorn.internal.runtime.options.Options;
 
 /**
@@ -42,6 +45,9 @@
 
     private static final int INDENT_SPACE = 4;
 
+    /** A quiet logger only logs {@link RuntimeEvent}s and does't output any text, regardless of level */
+    private final boolean isQuiet;
+
     /**
      * Constructor
      *
@@ -65,6 +71,7 @@
         } else {
             this.logger = Logging.getLogger(loggerName);
         }
+        this.isQuiet = Logging.loggerIsQuiet(loggerName);
         assert logger != null;
         this.isEnabled = getLevel() != Level.OFF;
     }
@@ -92,6 +99,37 @@
     }
 
     /**
+     * Add quotes around a string
+     * @param str string
+     * @return quoted string
+     */
+    public static String quote(final String str) {
+        if (str.isEmpty()) {
+            return "''";
+        }
+
+        char startQuote = '\0';
+        char endQuote   = '\0';
+        char quote      = '\0';
+
+        if (str.startsWith("\\") || str.startsWith("\"")) {
+            startQuote = str.charAt(0);
+        }
+        if (str.endsWith("\\") || str.endsWith("\"")) {
+            endQuote = str.charAt(str.length() - 1);
+        }
+
+        if (startQuote == '\0' || endQuote == '\0') {
+            quote = startQuote == '\0' ? endQuote : startQuote;
+        }
+        if (quote == '\0') {
+            quote = '\'';
+        }
+
+        return (startQuote == '\0' ? "" : startQuote) + str + (endQuote == '\0' ? "" : endQuote);
+    }
+
+    /**
      * Check if the logger is enabled
      * @return true if enabled
      */
@@ -128,6 +166,17 @@
         }
     }
 
+    private static void logEvent(final RuntimeEvent<?> event) {
+        if (event != null) {
+            final Global global = Context.getGlobal();
+            if (global.has("Debug")) {
+                final ScriptObject debug = (ScriptObject)global.get("Debug");
+                final ScriptFunction addRuntimeEvent = (ScriptFunction)debug.get("addRuntimeEvent");
+                ScriptRuntime.apply(addRuntimeEvent, debug, event);
+            }
+        }
+    }
+
     /**
      * Check if the logger is above the level of detail given
      * @see java.util.logging.Level
@@ -191,6 +240,16 @@
     }
 
     /**
+     * Shorthand for outputting a log string as log level {@link java.util.logging.Level#FINEST} on this logger
+     * @param event optional runtime event to log
+     * @param str the string to log
+     */
+    public void finest(final RuntimeEvent<?> event, final String str) {
+        finest(str);
+        logEvent(event);
+    }
+
+    /**
      * Shorthand for outputting a log string as log level
      * {@link java.util.logging.Level#FINEST} on this logger
      * @param objs object array to log - use this to perform lazy concatenation to avoid unconditional toString overhead
@@ -201,6 +260,17 @@
 
     /**
      * Shorthand for outputting a log string as log level
+     * {@link java.util.logging.Level#FINEST} on this logger
+     * @param event optional runtime event to log
+     * @param objs object array to log - use this to perform lazy concatenation to avoid unconditional toString overhead
+     */
+    public void finest(final RuntimeEvent<?> event, final Object... objs) {
+        finest(objs);
+        logEvent(event);
+    }
+
+    /**
+     * Shorthand for outputting a log string as log level
      * {@link java.util.logging.Level#FINER} on this logger
      * @param str the string to log
      */
@@ -211,6 +281,17 @@
     /**
      * Shorthand for outputting a log string as log level
      * {@link java.util.logging.Level#FINER} on this logger
+     * @param event optional runtime event to log
+     * @param str the string to log
+     */
+    public void finer(final RuntimeEvent<?> event, final String str) {
+        finer(str);
+        logEvent(event);
+    }
+
+    /**
+     * Shorthand for outputting a log string as log level
+     * {@link java.util.logging.Level#FINER} on this logger
      * @param objs object array to log - use this to perform lazy concatenation to avoid unconditional toString overhead
      */
     public void finer(final Object... objs) {
@@ -219,6 +300,17 @@
 
     /**
      * Shorthand for outputting a log string as log level
+     * {@link java.util.logging.Level#FINER} on this logger
+     * @param event optional runtime event to log
+     * @param objs object array to log - use this to perform lazy concatenation to avoid unconditional toString overhead
+     */
+    public void finer(final RuntimeEvent<?> event, final Object... objs) {
+        finer(objs);
+        logEvent(event);
+    }
+
+    /**
+     * Shorthand for outputting a log string as log level
      * {@link java.util.logging.Level#FINE} on this logger
      * @param str the string to log
      */
@@ -229,6 +321,17 @@
     /**
      * Shorthand for outputting a log string as log level
      * {@link java.util.logging.Level#FINE} on this logger
+     * @param event optional runtime event to log
+     * @param str the string to log
+     */
+    public void fine(final RuntimeEvent<?> event, final String str) {
+        fine(str);
+        logEvent(event);
+    }
+
+    /**
+     * Shorthand for outputting a log string as log level
+     * {@link java.util.logging.Level#FINE} on this logger
      * @param objs object array to log - use this to perform lazy concatenation to avoid unconditional toString overhead
      */
     public void fine(final Object... objs) {
@@ -237,6 +340,17 @@
 
     /**
      * Shorthand for outputting a log string as log level
+     * {@link java.util.logging.Level#FINE} on this logger
+     * @param event optional runtime event to log
+     * @param objs object array to log - use this to perform lazy concatenation to avoid unconditional toString overhead
+     */
+    public void fine(final RuntimeEvent<?> event, final Object... objs) {
+        fine(objs);
+        logEvent(event);
+    }
+
+    /**
+     * Shorthand for outputting a log string as log level
      * {@link java.util.logging.Level#CONFIG} on this logger
      * @param str the string to log
      */
@@ -247,6 +361,17 @@
     /**
      * Shorthand for outputting a log string as log level
      * {@link java.util.logging.Level#CONFIG} on this logger
+     * @param event optional runtime event to log
+     * @param str the string to log
+     */
+    public void config(final RuntimeEvent<?> event, final String str) {
+        config(str);
+        logEvent(event);
+    }
+
+    /**
+     * Shorthand for outputting a log string as log level
+     * {@link java.util.logging.Level#CONFIG} on this logger
      * @param objs object array to log - use this to perform lazy concatenation to avoid unconditional toString overhead
      */
     public void config(final Object... objs) {
@@ -255,6 +380,17 @@
 
     /**
      * Shorthand for outputting a log string as log level
+     * {@link java.util.logging.Level#CONFIG} on this logger
+     * @param event optional runtime event to log
+     * @param objs object array to log - use this to perform lazy concatenation to avoid unconditional toString overhead
+     */
+    public void config(final RuntimeEvent<?> event, final Object... objs) {
+        config(objs);
+        logEvent(event);
+    }
+
+    /**
+     * Shorthand for outputting a log string as log level
      * {@link java.util.logging.Level#INFO} on this logger
      * @param str the string to log
      */
@@ -264,6 +400,17 @@
 
     /**
      * Shorthand for outputting a log string as log level
+     * {@link java.util.logging.Level#INFO} on this logger
+     * @param event optional runtime event to log
+     * @param str the string to log
+     */
+    public void info(final RuntimeEvent<?> event, final String str) {
+        info(str);
+        logEvent(event);
+    }
+
+    /**
+     * Shorthand for outputting a log string as log level
      * {@link java.util.logging.Level#FINE} on this logger
      * @param objs object array to log - use this to perform lazy concatenation to avoid unconditional toString overhead
      */
@@ -273,6 +420,17 @@
 
     /**
      * Shorthand for outputting a log string as log level
+     * {@link java.util.logging.Level#FINE} on this logger
+     * @param event optional runtime event to log
+     * @param objs object array to log - use this to perform lazy concatenation to avoid unconditional toString overhead
+     */
+    public void info(final RuntimeEvent<?> event, final Object... objs) {
+        info(objs);
+        logEvent(event);
+    }
+
+    /**
+     * Shorthand for outputting a log string as log level
      * {@link java.util.logging.Level#WARNING} on this logger
      * @param str the string to log
      */
@@ -282,6 +440,17 @@
 
     /**
      * Shorthand for outputting a log string as log level
+     * {@link java.util.logging.Level#WARNING} on this logger
+     * @param event optional runtime event to log
+     * @param str the string to log
+     */
+    public void warning(final RuntimeEvent<?> event, final String str) {
+        warning(str);
+        logEvent(event);
+    }
+
+    /**
+     * Shorthand for outputting a log string as log level
      * {@link java.util.logging.Level#FINE} on this logger
      * @param objs object array to log - use this to perform lazy concatenation to avoid unconditional toString overhead
      */
@@ -291,6 +460,17 @@
 
     /**
      * Shorthand for outputting a log string as log level
+     * {@link java.util.logging.Level#FINE} on this logger
+     * @param objs object array to log - use this to perform lazy concatenation to avoid unconditional toString overhead
+     * @param event optional runtime event to log
+     */
+    public void warning(final RuntimeEvent<?> event, final Object... objs) {
+        warning(objs);
+        logEvent(event);
+    }
+
+    /**
+     * Shorthand for outputting a log string as log level
      * {@link java.util.logging.Level#SEVERE} on this logger
      * @param str the string to log
      */
@@ -300,6 +480,17 @@
 
     /**
      * Shorthand for outputting a log string as log level
+     * {@link java.util.logging.Level#SEVERE} on this logger
+     * @param str the string to log
+     * @param event optional runtime event to log
+     */
+    public void severe(final RuntimeEvent<?> event, final String str) {
+        severe(str);
+        logEvent(event);
+    }
+
+    /**
+     * Shorthand for outputting a log string as log level
      * {@link java.util.logging.Level#FINE} on this logger
      * @param objs object array to log - use this to perform lazy concatenation to avoid unconditional toString overhead
      */
@@ -308,6 +499,17 @@
     }
 
     /**
+     * Shorthand for outputting a log string as log level
+     * {@link java.util.logging.Level#FINE} on this logger
+     * @param event optional runtime event to log
+     * @param objs object array to log - use this to perform lazy concatenation to avoid unconditional toString overhead
+     */
+    public void severe(final RuntimeEvent<?> event, final Object... objs) {
+        severe(objs);
+        logEvent(event);
+    }
+
+    /**
      * Output log line on this logger at a given level of verbosity
      * @see java.util.logging.Level
      *
@@ -315,7 +517,7 @@
      * @param str   string to log
      */
     public void log(final Level level, final String str) {
-        if (isEnabled) {
+        if (isEnabled && !isQuiet) {
             final StringBuilder sb = new StringBuilder();
             for (int i = 0 ; i < indent ; i++) {
                 sb.append(' ');
@@ -333,15 +535,12 @@
      * @param objs  objects for which to invoke toString and concatenate to log
      */
     public void log(final Level level, final Object... objs) {
-        if (isEnabled) {
+        if (isEnabled && !isQuiet) {
             final StringBuilder sb = new StringBuilder();
-            for (int i = 0 ; i < indent ; i++) {
-                sb.append(' ');
-            }
             for (final Object obj : objs) {
                 sb.append(obj);
             }
-            logger.log(level, sb.toString());
+            log(level, sb.toString());
         }
     }
 }
--- a/src/jdk/nashorn/internal/runtime/JSONFunctions.java	Wed Mar 26 15:00:32 2014 +0100
+++ b/src/jdk/nashorn/internal/runtime/JSONFunctions.java	Thu Mar 27 11:45:54 2014 +0100
@@ -90,7 +90,7 @@
         }
 
         final Global global = Context.getGlobal();
-        Object unfiltered = convertNode(global, node);
+        final Object unfiltered = convertNode(global, node);
         return applyReviver(global, unfiltered, reviver);
     }
 
@@ -101,7 +101,6 @@
     // apply 'reviver' function if available
     private static Object applyReviver(final Global global, final Object unfiltered, final Object reviver) {
         if (reviver instanceof ScriptFunction) {
-            assert global instanceof Global;
             final ScriptObject root = global.newObject();
             root.addOwnProperty("", Property.WRITABLE_ENUMERABLE_CONFIGURABLE, unfiltered);
             return walk(root, "", (ScriptFunction)reviver);
@@ -140,8 +139,6 @@
 
     // Converts IR node to runtime value
     private static Object convertNode(final Global global, final Node node) {
-        assert global instanceof Global;
-
         if (node instanceof LiteralNode) {
             // check for array literal
             if (node.tokenType() == TokenType.ARRAY) {
--- a/src/jdk/nashorn/internal/runtime/ListAdapter.java	Wed Mar 26 15:00:32 2014 +0100
+++ b/src/jdk/nashorn/internal/runtime/ListAdapter.java	Thu Mar 27 11:45:54 2014 +0100
@@ -34,7 +34,6 @@
 import java.util.concurrent.Callable;
 import jdk.nashorn.api.scripting.JSObject;
 import jdk.nashorn.api.scripting.ScriptObjectMirror;
-import jdk.nashorn.internal.objects.Global;
 import jdk.nashorn.internal.runtime.linker.Bootstrap;
 import jdk.nashorn.internal.runtime.linker.InvokeByName;
 
@@ -174,7 +173,7 @@
      */
     protected abstract void setAt(final int index, final Object element);
 
-    private void checkRange(int index) {
+    private void checkRange(final int index) {
         if(index < 0 || index >= size()) {
             throw invalidIndex(index);
         }
@@ -200,7 +199,7 @@
             unshiftInvoker.getInvoker().invokeExact(fn, obj, e);
         } catch(RuntimeException | Error ex) {
             throw ex;
-        } catch(Throwable t) {
+        } catch(final Throwable t) {
             throw new RuntimeException(t);
         }
     }
@@ -214,7 +213,7 @@
             pushInvoker.getInvoker().invokeExact(fn, obj, e);
         } catch(RuntimeException | Error ex) {
             throw ex;
-        } catch(Throwable t) {
+        } catch(final Throwable t) {
             throw new RuntimeException(t);
         }
     }
@@ -328,7 +327,7 @@
             return shiftInvoker.getInvoker().invokeExact(fn, obj);
         } catch(RuntimeException | Error ex) {
             throw ex;
-        } catch(Throwable t) {
+        } catch(final Throwable t) {
             throw new RuntimeException(t);
         }
     }
@@ -341,7 +340,7 @@
             return popInvoker.getInvoker().invokeExact(fn, obj);
         } catch(RuntimeException | Error ex) {
             throw ex;
-        } catch(Throwable t) {
+        } catch(final Throwable t) {
             throw new RuntimeException(t);
         }
     }
@@ -359,7 +358,7 @@
             spliceRemoveInvoker.getInvoker().invokeExact(fn, obj, fromIndex, count);
         } catch(RuntimeException | Error ex) {
             throw ex;
-        } catch(Throwable t) {
+        } catch(final Throwable t) {
             throw new RuntimeException(t);
         }
     }
--- a/src/jdk/nashorn/internal/runtime/Logging.java	Wed Mar 26 15:00:32 2014 +0100
+++ b/src/jdk/nashorn/internal/runtime/Logging.java	Thu Mar 27 11:45:54 2014 +0100
@@ -31,9 +31,11 @@
 import java.security.PrivilegedAction;
 import java.security.ProtectionDomain;
 import java.util.HashMap;
+import java.util.HashSet;
 import java.util.Locale;
 import java.util.Map;
 import java.util.Map.Entry;
+import java.util.Set;
 import java.util.logging.ConsoleHandler;
 import java.util.logging.Formatter;
 import java.util.logging.Handler;
@@ -75,6 +77,8 @@
     /** Maps logger name to loggers. Names are typically per package */
     private static final Map<String, Logger> loggers = new HashMap<>();
 
+    private static final Set<String> quietLoggers = new HashSet<>();
+
     private static String lastPart(final String packageName) {
         final String[] parts = packageName.split("\\.");
         if (parts.length == 0) {
@@ -116,6 +120,16 @@
     }
 
     /**
+     * Is this logger "quiet", i.e. does it put events in the debug event
+     * queue, but refrains from printing anything?
+     * @param name logger name
+     * @return true if quiet
+     */
+    public static boolean loggerIsQuiet(final String name) {
+        return quietLoggers.contains(name);
+    }
+
+    /**
      * Initialization function that is called to instantiate the logging system. It takes
      * logger names (keys) and logging labels respectively
      *
@@ -126,18 +140,20 @@
         try {
             for (final Entry<String, String> entry : map.entrySet()) {
                 Level level;
-
                 final String key   = entry.getKey();
                 final String value = entry.getValue();
+                final String name = Logging.lastPart(key);
+
                 if ("".equals(value)) {
                     level = Level.INFO;
+                } else if ("quiet".equals(value)) {
+                    level = Level.INFO;
+                    quietLoggers.add(name);
                 } else {
                     level = Level.parse(value.toUpperCase(Locale.ENGLISH));
                 }
 
-                final String name = Logging.lastPart(key);
                 final Logger logger = instantiateLogger(name, level);
-
                 Logging.loggers.put(name, logger);
             }
         } catch (final IllegalArgumentException | SecurityException e) {
--- a/src/jdk/nashorn/internal/runtime/PropertyListeners.java	Wed Mar 26 15:00:32 2014 +0100
+++ b/src/jdk/nashorn/internal/runtime/PropertyListeners.java	Thu Mar 27 11:45:54 2014 +0100
@@ -111,7 +111,7 @@
         if (listeners == null) {
             return false;
         }
-        WeakPropertyMapSet set = listeners.get(key);
+        final WeakPropertyMapSet set = listeners.get(key);
         return set != null && set.contains(propertyMap);
     }
 
@@ -145,9 +145,9 @@
      */
     public synchronized void propertyAdded(final Property prop) {
         if (listeners != null) {
-            WeakPropertyMapSet set = listeners.get(prop.getKey());
+            final WeakPropertyMapSet set = listeners.get(prop.getKey());
             if (set != null) {
-                for (PropertyMap propertyMap : set.elements()) {
+                for (final PropertyMap propertyMap : set.elements()) {
                     propertyMap.propertyAdded(prop);
                 }
                 listeners.remove(prop.getKey());
@@ -162,9 +162,9 @@
      */
     public synchronized void propertyDeleted(final Property prop) {
         if (listeners != null) {
-            WeakPropertyMapSet set = listeners.get(prop.getKey());
+            final WeakPropertyMapSet set = listeners.get(prop.getKey());
             if (set != null) {
-                for (PropertyMap propertyMap : set.elements()) {
+                for (final PropertyMap propertyMap : set.elements()) {
                     propertyMap.propertyDeleted(prop);
                 }
                 listeners.remove(prop.getKey());
@@ -181,9 +181,9 @@
      */
     public synchronized void propertyModified(final Property oldProp, final Property newProp) {
         if (listeners != null) {
-            WeakPropertyMapSet set = listeners.get(oldProp.getKey());
+            final WeakPropertyMapSet set = listeners.get(oldProp.getKey());
             if (set != null) {
-                for (PropertyMap propertyMap : set.elements()) {
+                for (final PropertyMap propertyMap : set.elements()) {
                     propertyMap.propertyModified(oldProp, newProp);
                 }
                 listeners.remove(oldProp.getKey());
@@ -191,10 +191,13 @@
         }
     }
 
+    /**
+     * Callback for when a proto is changed
+     */
     public synchronized void protoChanged() {
         if (listeners != null) {
-            for (WeakPropertyMapSet set : listeners.values()) {
-                for (PropertyMap propertyMap : set.elements()) {
+            for (final WeakPropertyMapSet set : listeners.values()) {
+                for (final PropertyMap propertyMap : set.elements()) {
                     propertyMap.protoChanged();
                 }
             }
@@ -204,7 +207,7 @@
 
     private static class WeakPropertyMapSet {
 
-        private WeakHashMap<PropertyMap, Boolean> map = new WeakHashMap<>();
+        private final WeakHashMap<PropertyMap, Boolean> map = new WeakHashMap<>();
 
         void add(final PropertyMap propertyMap) {
             map.put(propertyMap, Boolean.TRUE);
--- a/src/jdk/nashorn/internal/runtime/RecompilableScriptFunctionData.java	Wed Mar 26 15:00:32 2014 +0100
+++ b/src/jdk/nashorn/internal/runtime/RecompilableScriptFunctionData.java	Thu Mar 27 11:45:54 2014 +0100
@@ -36,6 +36,7 @@
 import java.util.Map;
 import java.util.Set;
 import java.util.concurrent.atomic.AtomicInteger;
+
 import jdk.internal.dynalink.support.NameCodec;
 import jdk.nashorn.internal.codegen.CompilationEnvironment;
 import jdk.nashorn.internal.codegen.CompilationEnvironment.CompilationPhases;
@@ -112,6 +113,14 @@
 
     private static final DebugLogger LOG = new DebugLogger("recompile");
 
+    /**
+     * Get the recompilation logger
+     * @return the logger
+     */
+    public static DebugLogger getLogger() {
+        return LOG;
+    }
+
     private final Map<String, Integer> externalScopeDepths;
 
     private static final int GET_SET_PREFIX_LENGTH = "*et ".length();
@@ -310,7 +319,7 @@
             final Map.Entry<Integer, Type> entry = iter.next();
             sb.append('[').
                     append(entry.getKey()).
-                    append("=>").
+                    append("->").
                     append(entry.getValue().getShortDescriptor()).
                     append(']');
             if (iter.hasNext()) {
@@ -321,7 +330,9 @@
     }
 
     MethodHandle compileRestOfMethod(final MethodType fnCallSiteType, final Map<Integer, Type> invalidatedProgramPoints, final int[] continuationEntryPoints, final ScriptObject runtimeScope) {
-        LOG.info("Rest-of compilation of '", functionName, "' signature: ", fnCallSiteType, " ", stringifyInvalidations(invalidatedProgramPoints));
+        if (LOG.isEnabled()) {
+            LOG.info("Rest-of compilation of '", functionName, "' signature: ", fnCallSiteType, " ", stringifyInvalidations(invalidatedProgramPoints));
+        }
 
         final String scriptName = RECOMPILATION_PREFIX + RECOMPILE_ID.incrementAndGet() + "$restOf";
         FunctionNode fn = reparse(scriptName);
@@ -343,6 +354,7 @@
 
         compiler.install(fn);
 
+        // look up the rest of method
         return lookupWithExplicitType(fn, MethodType.methodType(fn.getReturnType().getTypeClass(), RewriteException.class));
     }
 
@@ -353,7 +365,10 @@
     FunctionNode compile(final MethodType actualCallSiteType, final Map<Integer, Type> invalidatedProgramPoints, final ScriptObject runtimeScope, final String reason) {
         final String scriptName = RECOMPILATION_PREFIX + RECOMPILE_ID.incrementAndGet();
         final MethodType fnCallSiteType = actualCallSiteType == null ? null : actualCallSiteType.changeParameterType(0, ScriptFunction.class);
-        LOG.info(reason, " of '", functionName, "' signature: ", fnCallSiteType, " ", stringifyInvalidations(invalidatedProgramPoints));
+
+        if (LOG.isEnabled()) {
+            LOG.info(reason, " of '", functionName, "' signature: ", fnCallSiteType, " ", stringifyInvalidations(invalidatedProgramPoints));
+        }
         FunctionNode fn = reparse(scriptName);
 
         final CompilationPhases phases = CompilationPhases.EAGER;
@@ -509,7 +524,7 @@
 
     @Override
     CompiledFunction getBest(final MethodType callSiteType, final ScriptObject runtimeScope) {
-        synchronized(code) {
+        synchronized (code) {
             final CompiledFunction existingBest = super.getBest(callSiteType, runtimeScope);
             // TODO: what if callSiteType is vararg?
             return existingBest != null ? existingBest : addCode(compileTypeSpecialization(callSiteType, runtimeScope), callSiteType);
--- a/src/jdk/nashorn/internal/runtime/RewriteException.java	Wed Mar 26 15:00:32 2014 +0100
+++ b/src/jdk/nashorn/internal/runtime/RewriteException.java	Thu Mar 27 11:45:54 2014 +0100
@@ -52,7 +52,9 @@
     // optimistic assumptions (which will lead to unnecessary deoptimizing recompilations).
     private ScriptObject runtimeScope;
     //contents of bytecode slots
+
     private Object[] byteCodeSlots;
+
     private final int[] previousContinuationEntryPoints;
 
     /** Methodhandle for getting the contents of the bytecode slots in the exception */
@@ -68,6 +70,42 @@
     private static final Call POPULATE_ARRAY           = staticCall(MethodHandles.lookup(), RewriteException.class, "populateArray", Object[].class, Object[].class, int.class, Object[].class);
 
     /**
+     * Constructor for a rewrite exception thrown from an optimistic function.
+     * @param e the {@link UnwarrantedOptimismException} that triggered this exception.
+     * @param byteCodeSlots contents of local variable slots at the time of rewrite at the program point
+     * @param byteCodeSymbolNames byte code symbol names
+     * @param runtimeScope the runtime scope used for known type information when recompiling
+     */
+    public RewriteException(
+            final UnwarrantedOptimismException e,
+            final Object[] byteCodeSlots,
+            final String[] byteCodeSymbolNames,
+            final ScriptObject runtimeScope) {
+        this(e, byteCodeSlots, byteCodeSymbolNames, runtimeScope, null);
+    }
+
+    /**
+     * Constructor for a rewrite exception thrown from a rest-of method.
+     * @param e the {@link UnwarrantedOptimismException} that triggered this exception.
+     * @param byteCodeSymbolNames byte code symbol names
+     * @param byteCodeSlots contents of local variable slots at the time of rewrite at the program point
+     * @param runtimeScope the runtime scope used for known type information when recompiling
+     * @param previousContinuationEntryPoints an array of continuation entry points that were already executed during
+     * one logical invocation of the function (a rest-of triggering a rest-of triggering a...)
+     */
+    public RewriteException(
+            final UnwarrantedOptimismException e,
+            final Object[] byteCodeSlots,
+            final String[] byteCodeSymbolNames,
+            final ScriptObject runtimeScope,
+            final int[] previousContinuationEntryPoints) {
+        super("", e, false, Context.DEBUG);
+        this.byteCodeSlots = byteCodeSlots;
+        this.runtimeScope  = mergeSlotsWithScope(byteCodeSlots, byteCodeSymbolNames, runtimeScope);
+        this.previousContinuationEntryPoints = previousContinuationEntryPoints;
+    }
+
+    /**
      * Bootstrap method for populate array
      * @param lookup     lookup
      * @param name       name (ignored)
@@ -83,29 +121,6 @@
         return new ConstantCallSite(mh);
     }
 
-    /**
-     * Constructor for a rewrite exception thrown from an optimistic function.
-     * @param e the {@link UnwarrantedOptimismException} that triggered this exception.
-     * @param byteCodeSlots contents of local variable slots at the time of rewrite at the program point
-     */
-    public RewriteException(final UnwarrantedOptimismException e, final Object[] byteCodeSlots, final String[] byteCodeSymbolNames, final ScriptObject runtimeScope) {
-        this(e, byteCodeSlots, byteCodeSymbolNames, runtimeScope, null);
-    }
-
-    /**
-     * Constructor for a rewrite exception thrown from a rest-of method.
-     * @param e the {@link UnwarrantedOptimismException} that triggered this exception.
-     * @param byteCodeSlots contents of local variable slots at the time of rewrite at the program point
-     * @param previousContinuationEntryPoints an array of continuation entry points that were already executed during
-     * one logical invocation of the function (a rest-of triggering a rest-of triggering a...)
-     */
-    public RewriteException(final UnwarrantedOptimismException e, final Object[] byteCodeSlots, final String[] byteCodeSymbolNames, final ScriptObject runtimeScope, final int[] previousContinuationEntryPoints) {
-        super("", e, false, Context.DEBUG);
-        this.byteCodeSlots = byteCodeSlots;
-        this.runtimeScope = mergeSlotsWithScope(byteCodeSlots, byteCodeSymbolNames, runtimeScope);
-        this.previousContinuationEntryPoints = previousContinuationEntryPoints;
-    }
-
     private static ScriptObject mergeSlotsWithScope(final Object[] byteCodeSlots, final String[] byteCodeSymbolNames,
             final ScriptObject runtimeScope) {
         final ScriptObject locals = Global.newEmptyInstance();
@@ -204,7 +219,7 @@
 
     @Override
     public String getMessage() {
-        return "programPoint=" + getProgramPoint() + " slots=" + Arrays.asList(byteCodeSlots) + ", returnValue=" + stringify(getReturnValueNonDestructive()) + ", returnType=" + getReturnType();
+        return "programPoint=" + getProgramPoint() + " slots=" + (byteCodeSlots == null ? "null" : Arrays.asList(byteCodeSlots)) + ", returnValue=" + stringify(getReturnValueNonDestructive()) + ", returnType=" + getReturnType();
     }
 
     /**
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk/nashorn/internal/runtime/RuntimeEvent.java	Thu Mar 27 11:45:54 2014 +0100
@@ -0,0 +1,62 @@
+package jdk.nashorn.internal.runtime;
+
+import java.util.logging.Level;
+
+import jdk.nashorn.internal.objects.NativeDebug;
+import jdk.nashorn.internal.runtime.options.Options;
+
+/**
+ * Class for representing a runtime event, giving less global dependencies than logger.
+ * Every {@link NativeDebug} object keeps a queue of RuntimeEvents that can be explored
+ * through the debug API.
+ *
+ * @param <T> class of the value this event wraps
+ */
+public class RuntimeEvent<T> {
+    /** Queue size for the runtime event buffer */
+    public static final int RUNTIME_EVENT_QUEUE_SIZE = Options.getIntProperty("nashorn.runtime.event.queue.size", 1024);
+
+    private final Level level;
+    private final T value;
+
+    /**
+     * Constructor
+     * @param level  log level for runtime event to create
+     * @param object object to wrap
+     */
+    public RuntimeEvent(final Level level, final T object) {
+        this.level = level;
+        this.value = object;
+    }
+
+    /**
+     * Return the value wrapped in this runtime event
+     * @return value
+     */
+    public T getValue() {
+        return value;
+    }
+
+    @Override
+    public String toString() {
+        final StringBuilder sb = new StringBuilder();
+
+        sb.append('[').
+            append(level).
+            append("] ").
+            append(value == null ? "null" : getValueClass().getSimpleName()).
+            append(" value=").
+            append(value);
+
+        return sb.toString();
+    }
+
+    /**
+     * Descriptor for this runtime event, must be overridden and
+     * implemented, e.g. "RewriteException"
+     * @return event name
+     */
+    public final Class<?> getValueClass() {
+        return value.getClass();
+    }
+}
--- a/src/jdk/nashorn/internal/runtime/ScriptFunction.java	Wed Mar 26 15:00:32 2014 +0100
+++ b/src/jdk/nashorn/internal/runtime/ScriptFunction.java	Thu Mar 27 11:45:54 2014 +0100
@@ -68,7 +68,7 @@
 
     private static final MethodHandle WRAPFILTER = findOwnMH_S("wrapFilter", Object.class, Object.class);
 
-    private static final MethodHandle GLOBALFILTER = findOwnMH_S("globalFilter", Object.class, Object.class);
+    private static final MethodHandle SCRIPTFUNCTION_GLOBALFILTER = findOwnMH_S("globalFilter", Object.class, Object.class);
 
     /** method handle to scope getter for this ScriptFunction */
     public static final Call GET_SCOPE = virtualCallNoLookup(ScriptFunction.class, "getScope", ScriptObject.class);
@@ -554,7 +554,7 @@
         if (data.needsCallee()) {
             if (scopeCall && needsWrappedThis()) {
                 // (callee, this, args...) => (callee, [this], args...)
-                boundHandle = MH.filterArguments(callHandle, 1, GLOBALFILTER);
+                boundHandle = MH.filterArguments(callHandle, 1, SCRIPTFUNCTION_GLOBALFILTER);
             } else {
                 // It's already (callee, this, args...), just what we need
                 boundHandle = callHandle;
@@ -566,7 +566,7 @@
         } else if (scopeCall && needsWrappedThis()) {
             // Make a handle that drops the passed "this" argument and substitutes either Global or Undefined
             // (this, args...) => ([this], args...)
-            boundHandle = MH.filterArguments(callHandle, 0, GLOBALFILTER);
+            boundHandle = MH.filterArguments(callHandle, 0, SCRIPTFUNCTION_GLOBALFILTER);
             // ([this], args...) => ([callee], [this], args...)
             boundHandle = MH.dropArguments(boundHandle, 0, type.parameterType(0));
         } else {
@@ -684,7 +684,7 @@
      private static MethodHandle bindImplicitThis(final Object fn, final MethodHandle mh) {
          final MethodHandle bound;
          if(fn instanceof ScriptFunction && ((ScriptFunction)fn).needsWrappedThis()) {
-             bound = MH.filterArguments(mh, 1, GLOBALFILTER);
+             bound = MH.filterArguments(mh, 1, SCRIPTFUNCTION_GLOBALFILTER);
          } else {
              bound = mh;
          }
--- a/src/jdk/nashorn/internal/runtime/ScriptFunctionData.java	Wed Mar 26 15:00:32 2014 +0100
+++ b/src/jdk/nashorn/internal/runtime/ScriptFunctionData.java	Thu Mar 27 11:45:54 2014 +0100
@@ -219,8 +219,7 @@
 
     /**
      * If we can have lazy code generation, this is a hook to ensure that the code has been compiled.
-     * This does not guarantee the code been installed in this {@code ScriptFunctionData} instance;
-     * use {@link #ensureCodeGenerated()} to install the actual method handles.
+     * This does not guarantee the code been installed in this {@code ScriptFunctionData} instance
      */
     protected void ensureCompiled() {
         //empty
--- a/src/jdk/nashorn/internal/runtime/ScriptObject.java	Wed Mar 26 15:00:32 2014 +0100
+++ b/src/jdk/nashorn/internal/runtime/ScriptObject.java	Thu Mar 27 11:45:54 2014 +0100
@@ -1890,7 +1890,7 @@
 
         mh = find.getGetter(returnType, programPoint);
         // Get the appropriate guard for this callsite and property.
-        MethodHandle guard = NashornGuards.getGuard(this, property, desc, explicitInstanceOfCheck);
+        final MethodHandle guard = NashornGuards.getGuard(this, property, desc, explicitInstanceOfCheck);
         final ScriptObject owner = find.getOwner();
         final Class<ClassCastException> exception = explicitInstanceOfCheck ? null : ClassCastException.class;
 
@@ -1915,11 +1915,10 @@
                 exception);
     }
 
-    private static GuardedInvocation findMegaMorphicGetMethod(final CallSiteDescriptor desc, final String name,
-                                                              final boolean isMethod, final boolean isScope) {
-    ObjectClassGenerator.LOG.warning("Megamorphic getter: " + desc + " " + name + " " +isMethod);
+    private static GuardedInvocation findMegaMorphicGetMethod(final CallSiteDescriptor desc, final String name, final boolean isMethod, final boolean isScope) {
+        ObjectClassGenerator.getLogger().warning("Megamorphic getter: " + desc + " " + name + " " +isMethod);
         final MethodHandle invoker = MH.insertArguments(MEGAMORPHIC_GET, 1, name, isMethod, isScope);
-        final MethodHandle guard = getScriptObjectGuard(desc.getMethodType(), true);
+        final MethodHandle guard   = getScriptObjectGuard(desc.getMethodType(), true);
         return new GuardedInvocation(invoker, guard);
     }
 
@@ -2004,7 +2003,7 @@
         }
 
         for (ScriptObject obj = this; obj != owner && obj.getProto() != null; obj = obj.getProto()) {
-            ScriptObject parent = obj.getProto();
+            final ScriptObject parent = obj.getProto();
             parent.getMap().addListener(name, obj.getMap());
         }
 
--- a/src/jdk/nashorn/internal/runtime/linker/NashornCallSiteDescriptor.java	Wed Mar 26 15:00:32 2014 +0100
+++ b/src/jdk/nashorn/internal/runtime/linker/NashornCallSiteDescriptor.java	Thu Mar 27 11:45:54 2014 +0100
@@ -30,9 +30,11 @@
 import java.lang.invoke.MethodType;
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.ConcurrentMap;
+
 import jdk.internal.dynalink.CallSiteDescriptor;
 import jdk.internal.dynalink.support.AbstractCallSiteDescriptor;
 import jdk.internal.dynalink.support.CallSiteDescriptorFactory;
+import jdk.nashorn.internal.ir.debug.NashornTextifier;
 
 /**
  * Nashorn-specific implementation of Dynalink's {@link CallSiteDescriptor}. The reason we have our own subclass is that
@@ -96,7 +98,7 @@
     private static final ClassValue<ConcurrentMap<NashornCallSiteDescriptor, NashornCallSiteDescriptor>> canonicals =
             new ClassValue<ConcurrentMap<NashornCallSiteDescriptor,NashornCallSiteDescriptor>>() {
         @Override
-        protected ConcurrentMap<NashornCallSiteDescriptor, NashornCallSiteDescriptor> computeValue(Class<?> type) {
+        protected ConcurrentMap<NashornCallSiteDescriptor, NashornCallSiteDescriptor> computeValue(final Class<?> type) {
             return new ConcurrentHashMap<>();
         }
     };
@@ -107,6 +109,12 @@
     private final MethodType methodType;
     private final int flags;
 
+    /**
+     * Function used by {@link NashornTextifier} to represent call site flags in
+     * human readable form
+     * @param flags call site flags
+     * @return human readable form of this callsite descriptor
+     */
     public static String toString(final int flags) {
         final StringBuilder sb = new StringBuilder();
         if ((flags & CALLSITE_SCOPE) != 0) {
--- a/src/jdk/nashorn/internal/runtime/linker/NashornGuards.java	Wed Mar 26 15:00:32 2014 +0100
+++ b/src/jdk/nashorn/internal/runtime/linker/NashornGuards.java	Thu Mar 27 11:45:54 2014 +0100
@@ -49,7 +49,8 @@
     private static final MethodHandle IS_INSTANCEOF_2     = findOwnMH("isInstanceOf2", boolean.class, Object.class, Class.class, Class.class);
     private static final MethodHandle IS_SCRIPTOBJECT     = findOwnMH("isScriptObject", boolean.class, Object.class);
     private static final MethodHandle SAME_OBJECT       = findOwnMH("sameObject", boolean.class, Object.class, WeakReference.class);
-    private static final MethodHandle IS_SCRIPTFUNCTION = findOwnMH("isScriptFunction", boolean.class, Object.class);
+    //TODO - maybe put this back in ScriptFunction instead of the ClassCastException.class relinkage
+    //private static final MethodHandle IS_SCRIPTFUNCTION = findOwnMH("isScriptFunction", boolean.class, Object.class);
 
     private static final boolean CCE_ONLY = Options.getBooleanProperty("nashorn.cce");
 
--- a/src/jdk/nashorn/internal/runtime/linker/NashornPrimitiveLinker.java	Wed Mar 26 15:00:32 2014 +0100
+++ b/src/jdk/nashorn/internal/runtime/linker/NashornPrimitiveLinker.java	Thu Mar 27 11:45:54 2014 +0100
@@ -39,7 +39,6 @@
 import jdk.internal.dynalink.support.TypeUtilities;
 import jdk.nashorn.internal.objects.Global;
 import jdk.nashorn.internal.runtime.ConsString;
-import jdk.nashorn.internal.runtime.Context;
 
 /**
  * Internal linker for String, Boolean, and Number objects, only ever used by Nashorn engine and not exposed to other
@@ -62,10 +61,9 @@
         final LinkRequest request = origRequest.withoutRuntimeContext(); // Nashorn has no runtime context
 
         final Object self = request.getReceiver();
-        final Global global = Context.getGlobal();
         final NashornCallSiteDescriptor desc = (NashornCallSiteDescriptor) request.getCallSiteDescriptor();
 
-        return Bootstrap.asTypeSafeReturn(global.primitiveLookup(request, self), linkerServices, desc);
+        return Bootstrap.asTypeSafeReturn(Global.primitiveLookup(request, self), linkerServices, desc);
     }
 
     /**
--- a/src/jdk/nashorn/internal/runtime/linker/PrimitiveLookup.java	Wed Mar 26 15:00:32 2014 +0100
+++ b/src/jdk/nashorn/internal/runtime/linker/PrimitiveLookup.java	Thu Mar 27 11:45:54 2014 +0100
@@ -59,6 +59,7 @@
      * creates a transient native wrapper of the same type as {@code wrappedReceiver} for subsequent invocations of the
      * method - it will be combined into the returned invocation as an argument filter on the receiver.
      * @return a guarded invocation representing the operation at the call site when performed on a JavaScript primitive
+     * @param protoFilter A method handle that walks up the proto chain of this receiver object
      * type {@code receiverClass}.
      */
     public static GuardedInvocation lookupPrimitive(final LinkRequest request, final Class<?> receiverClass,
@@ -77,6 +78,7 @@
      * @param wrapFilter A method handle that takes a primitive value of type guarded by the {@code guard} and
      * creates a transient native wrapper of the same type as {@code wrappedReceiver} for subsequent invocations of the
      * method - it will be combined into the returned invocation as an argument filter on the receiver.
+     * @param protoFilter A method handle that walks up the proto chain of this receiver object
      * @return a guarded invocation representing the operation at the call site when performed on a JavaScript primitive
      * type (that is implied by both {@code guard} and {@code wrappedReceiver}).
      */
@@ -86,7 +88,7 @@
         final CallSiteDescriptor desc = request.getCallSiteDescriptor();
         final String operator = CallSiteDescriptorFactory.tokenizeOperators(desc).get(0);
         if ("setProp".equals(operator) || "setElem".equals(operator)) {
-            MethodType type = desc.getMethodType();
+            final MethodType type = desc.getMethodType();
             MethodHandle method = MH.asType(Lookup.EMPTY_SETTER, MH.type(void.class, Object.class, type.parameterType(1)));
             if (type.parameterCount() == 3) {
                 method = MH.dropArguments(method, 2, type.parameterType(2));
--- a/src/jdk/nashorn/tools/Shell.java	Wed Mar 26 15:00:32 2014 +0100
+++ b/src/jdk/nashorn/tools/Shell.java	Thu Mar 27 11:45:54 2014 +0100
@@ -52,7 +52,6 @@
 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.Source;
 import jdk.nashorn.internal.runtime.options.Options;
--- a/test/script/trusted/JDK-8006529.js	Wed Mar 26 15:00:32 2014 +0100
+++ b/test/script/trusted/JDK-8006529.js	Thu Mar 27 11:45:54 2014 +0100
@@ -39,7 +39,7 @@
  * and FunctionNode because of package-access check and so reflective calls.
  */
 
-var forName = java.lang.Class["forName(String)"];
+var forName             = java.lang.Class["forName(String)"];
 var Parser              = forName("jdk.nashorn.internal.parser.Parser").static
 var Compiler            = forName("jdk.nashorn.internal.codegen.Compiler").static
 var Context             = forName("jdk.nashorn.internal.runtime.Context").static
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/script/trusted/event_queue.js	Thu Mar 27 11:45:54 2014 +0100
@@ -0,0 +1,122 @@
+/*
+ * Copyright (c) 2010, 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/**
+ * Debug.eventqueue test - instead of screen scraping, test the concept of asking Debug for
+ * an event log of favourable events. 
+ * 
+ * @test
+ * @fork
+ * @option -Dnashorn.debug=true
+ * @option --log=recompile:quiet
+ */
+
+print(Debug);
+print();
+
+var forName       = java.lang.Class["forName(String)"];
+var RuntimeEvent  = forName("jdk.nashorn.internal.runtime.RuntimeEvent").static;
+var getValue      = RuntimeEvent.class.getMethod("getValue"); 
+var getValueClass = RuntimeEvent.class.getMethod("getValueClass"); 
+
+print(RuntimeEvent);
+
+var RewriteException = forName("jdk.nashorn.internal.runtime.RewriteException").static;
+var getReturnType    = RewriteException.class.getMethod("getReturnType");
+
+print(RewriteException);
+
+var a = [1.1, 2.2];
+function f() {
+    var sum = 2;
+    for (var i = 0; i < a.length; i++) {
+	sum *= a[i];
+    }
+    return sum;
+}
+
+function g() {
+    var diff = 17;
+    for (var i = 0; i < a.length; i++) {
+	diff -= a[i];
+    }
+    return diff;
+}
+
+//kill anything that may already be in the event queue from earlier debug runs
+Debug.clearRuntimeEvents();
+
+print();
+print(f());
+print(g());
+
+print();
+events = Debug.getRuntimeEvents();
+print("Done with " + events.length + " in the event queue");
+//make sure we got runtime events
+print("events = " + (events.toString().indexOf("RuntimeEvent") != -1));
+print("events.length = " + events.length);
+
+var lastInLoop = undefined;
+for (var i = 0; i < events.length; i++) {
+    var e = events[i];
+    print("event #" + i);
+    print("\tevent class=" + e.getClass());
+    print("\tvalueClass in event=" + getValueClass.invoke(e));
+    var v = getValue.invoke(e);
+    print("\tclass of value=" + v.getClass());
+    print("\treturn type=" + getReturnType.invoke(v));
+    lastInLoop = events[i];
+}
+
+print();
+print("in loop last class = " + lastInLoop.getClass());
+print("in loop last value class = " + getValueClass.invoke(lastInLoop));
+var rexInLoop = getValue.invoke(lastInLoop);
+print("in loop rex class = " + rexInLoop.getClass());
+print("in loop rex return type = " + getReturnType.invoke(rexInLoop));
+
+//try last runtime events
+var last = Debug.getLastRuntimeEvent();
+//the code after the loop creates additional rewrite exceptions
+print();
+print(last !== lastInLoop);
+print();
+
+print("last class = " + last.getClass());
+print("last value class = " + getValueClass.invoke(last));
+var rex = getValue.invoke(last);
+print("rex class = " + rex.getClass());
+print("rex return type = " + getReturnType.invoke(rex));
+
+//try the capacity setter
+print();
+print(Debug.getEventQueueCapacity());
+Debug.setEventQueueCapacity(2048);
+print(Debug.getEventQueueCapacity());
+
+//try clear events
+print();
+Debug.clearRuntimeEvents();
+print(Debug.getRuntimeEvents().length);
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/script/trusted/event_queue.js.EXPECTED	Thu Mar 27 11:45:54 2014 +0100
@@ -0,0 +1,38 @@
+[object Debug]
+
+[JavaClass jdk.nashorn.internal.runtime.RuntimeEvent]
+[JavaClass jdk.nashorn.internal.runtime.RewriteException]
+
+4.840000000000001
+13.7
+
+Done with 2 in the event queue
+events = true
+events.length = 2
+event #0
+	event class=class jdk.nashorn.internal.runtime.RuntimeEvent
+	valueClass in event=class jdk.nashorn.internal.runtime.RewriteException
+	class of value=class jdk.nashorn.internal.runtime.RewriteException
+	return type=double
+event #1
+	event class=class jdk.nashorn.internal.runtime.RuntimeEvent
+	valueClass in event=class jdk.nashorn.internal.runtime.RewriteException
+	class of value=class jdk.nashorn.internal.runtime.RewriteException
+	return type=double
+
+in loop last class = class jdk.nashorn.internal.runtime.RuntimeEvent
+in loop last value class = class jdk.nashorn.internal.runtime.RewriteException
+in loop rex class = class jdk.nashorn.internal.runtime.RewriteException
+in loop rex return type = double
+
+true
+
+last class = class jdk.nashorn.internal.runtime.RuntimeEvent
+last value class = class jdk.nashorn.internal.runtime.RewriteException
+rex class = class jdk.nashorn.internal.runtime.RewriteException
+rex return type = object
+
+1024
+2048
+
+0
--- a/test/src/jdk/nashorn/internal/runtime/NoPersistenceCachingTest.java	Wed Mar 26 15:00:32 2014 +0100
+++ b/test/src/jdk/nashorn/internal/runtime/NoPersistenceCachingTest.java	Thu Mar 27 11:45:54 2014 +0100
@@ -59,8 +59,8 @@
       prevStderr = System.err;
       System.setErr(new PrintStream(stderr));
       NashornScriptEngineFactory nashornFactory = null;
-      ScriptEngineManager sm = new ScriptEngineManager();
-      for (ScriptEngineFactory fac : sm.getEngineFactories()) {
+      final ScriptEngineManager sm = new ScriptEngineManager();
+      for (final ScriptEngineFactory fac : sm.getEngineFactories()) {
          if (fac instanceof NashornScriptEngineFactory) {
             nashornFactory = (NashornScriptEngineFactory) fac;
             break;
@@ -69,7 +69,10 @@
       if (nashornFactory == null) {
          fail("Cannot find nashorn factory!");
       }
-      String[] options = new String[]{"--log=compiler:finest"};
+      // fine is enough for cache hits, finest produces way too much information
+      // TODO this should be ported to use the RuntimeEvents instead of screen scraping
+      // logs, as obviously this is very brittle
+      final String[] options = new String[]{"--log=compiler:fine"};
       engine = nashornFactory.getScriptEngine(options);
       context1 = engine.getContext();
       context2 = new SimpleScriptContext();
@@ -83,18 +86,18 @@
       System.setErr(prevStderr);
    }
 
-   public void runTest(int numberOfContext, String expectedOutputPattern,
-                       int expectedPatternOccurrence) {
+   public void runTest(final int numberOfContext, final String expectedOutputPattern,
+                       final int expectedPatternOccurrence) {
 
       try {
          switch (numberOfContext) {
          case 2:
-            String scriptTwoContexts = "print('HelloTwoContexts')";
+            final String scriptTwoContexts = "print('HelloTwoContexts')";
             engine.eval(scriptTwoContexts, context1);
             engine.eval(scriptTwoContexts, context2);
             break;
          case 3:
-            String scriptThreeContexts = "print('HelloThreeContexts')";
+            final String scriptThreeContexts = "print('HelloThreeContexts')";
             engine.eval(scriptThreeContexts, context1);
             engine.eval(scriptThreeContexts, context2);
             engine.eval(scriptThreeContexts, context3);
@@ -104,8 +107,8 @@
          se.printStackTrace();
          fail(se.getMessage());
       }
-      Pattern deoptimizing = Pattern.compile(expectedOutputPattern);
-      Matcher matcher = deoptimizing.matcher(stderr.toString());
+      final Pattern deoptimizing = Pattern.compile(expectedOutputPattern);
+      final Matcher matcher = deoptimizing.matcher(stderr.toString());
       int matches = 0;
       while (matcher.find()) {
          matches++;