8038426: Move all loggers from process wide scope into Global scope
authorlagergren
Wed, 23 Apr 2014 16:13:47 +0200
changeset 24744 5290da85fc3d
parent 24743 138ee369abd8
child 24745 3a6e1477362b
8038426: Move all loggers from process wide scope into Global scope Reviewed-by: attila, hannesw
nashorn/src/jdk/nashorn/internal/codegen/ApplySpecialization.java
nashorn/src/jdk/nashorn/internal/codegen/Attr.java
nashorn/src/jdk/nashorn/internal/codegen/CodeGenerator.java
nashorn/src/jdk/nashorn/internal/codegen/CompilationPhase.java
nashorn/src/jdk/nashorn/internal/codegen/Compiler.java
nashorn/src/jdk/nashorn/internal/codegen/DumpBytecode.java
nashorn/src/jdk/nashorn/internal/codegen/FinalizeTypes.java
nashorn/src/jdk/nashorn/internal/codegen/FindScopeDepths.java
nashorn/src/jdk/nashorn/internal/codegen/FoldConstants.java
nashorn/src/jdk/nashorn/internal/codegen/Lower.java
nashorn/src/jdk/nashorn/internal/codegen/MethodEmitter.java
nashorn/src/jdk/nashorn/internal/codegen/ObjectClassGenerator.java
nashorn/src/jdk/nashorn/internal/codegen/RangeAnalyzer.java
nashorn/src/jdk/nashorn/internal/codegen/Splitter.java
nashorn/src/jdk/nashorn/internal/codegen/types/Range.java
nashorn/src/jdk/nashorn/internal/ir/IdentNode.java
nashorn/src/jdk/nashorn/internal/lookup/MethodHandleFactory.java
nashorn/src/jdk/nashorn/internal/lookup/MethodHandleFunctionality.java
nashorn/src/jdk/nashorn/internal/objects/Global.java
nashorn/src/jdk/nashorn/internal/parser/Parser.java
nashorn/src/jdk/nashorn/internal/runtime/AccessorProperty.java
nashorn/src/jdk/nashorn/internal/runtime/CompiledFunction.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/Logging.java
nashorn/src/jdk/nashorn/internal/runtime/PropertyHashMap.java
nashorn/src/jdk/nashorn/internal/runtime/RecompilableScriptFunctionData.java
nashorn/src/jdk/nashorn/internal/runtime/ScriptEnvironment.java
nashorn/src/jdk/nashorn/internal/runtime/ScriptFunction.java
nashorn/src/jdk/nashorn/internal/runtime/ScriptObject.java
nashorn/src/jdk/nashorn/internal/runtime/arrays/ContinuousArrayData.java
nashorn/src/jdk/nashorn/internal/runtime/arrays/TypedArrayData.java
nashorn/src/jdk/nashorn/internal/runtime/events/RecompilationEvent.java
nashorn/src/jdk/nashorn/internal/runtime/logging/DebugLogger.java
nashorn/src/jdk/nashorn/internal/runtime/logging/Loggable.java
nashorn/src/jdk/nashorn/internal/runtime/logging/Logger.java
nashorn/src/jdk/nashorn/internal/runtime/options/KeyValueOption.java
nashorn/src/jdk/nashorn/internal/runtime/options/LoggingOption.java
nashorn/src/jdk/nashorn/internal/runtime/options/Options.java
nashorn/src/jdk/nashorn/tools/Shell.java
nashorn/test/src/jdk/nashorn/internal/parser/ParserTest.java
nashorn/test/src/jdk/nashorn/internal/test/framework/ParallelTestRunner.java
--- a/nashorn/src/jdk/nashorn/internal/codegen/ApplySpecialization.java	Tue Apr 22 14:09:46 2014 +0200
+++ b/nashorn/src/jdk/nashorn/internal/codegen/ApplySpecialization.java	Wed Apr 23 16:13:47 2014 +0200
@@ -45,7 +45,9 @@
 import jdk.nashorn.internal.ir.Node;
 import jdk.nashorn.internal.ir.visitor.NodeVisitor;
 import jdk.nashorn.internal.objects.Global;
-import jdk.nashorn.internal.runtime.DebugLogger;
+import jdk.nashorn.internal.runtime.logging.DebugLogger;
+import jdk.nashorn.internal.runtime.logging.Loggable;
+import jdk.nashorn.internal.runtime.logging.Logger;
 import jdk.nashorn.internal.runtime.RecompilableScriptFunctionData;
 import jdk.nashorn.internal.runtime.options.Options;
 
@@ -80,7 +82,8 @@
  * </pre>
  */
 
-public final class ApplySpecialization {
+@Logger(name="apply2call")
+public final class ApplySpecialization implements Loggable {
 
     private static final boolean USE_APPLY2CALL = Options.getBooleanProperty("nashorn.apply2call", true);
 
@@ -90,7 +93,7 @@
 
     private final MethodType actualCallSiteType;
 
-    private static final DebugLogger LOG = new DebugLogger("apply2call");
+    private final DebugLogger log;
 
     private static final String ARGUMENTS = ARGUMENTS_VAR.symbolName();
 
@@ -99,14 +102,6 @@
     private boolean finished;
 
     /**
-     * Return the apply to call specialization logger g
-     * @return the logger
-     */
-    public static DebugLogger getLogger() {
-        return LOG;
-    }
-
-    /**
      * Apply specialization optimization. Try to explode arguments and call
      * applies as calls if they just pass on the "arguments" array and
      * "arguments" doesn't escape.
@@ -116,9 +111,20 @@
      * @param actualCallSiteType  actual call site type that we use (not Object[] varargs)
      */
     public ApplySpecialization(final RecompilableScriptFunctionData data, final FunctionNode functionNode, final MethodType actualCallSiteType) {
-        this.data = data;
-        this.functionNode = functionNode;
+        this.data               = data;
+        this.functionNode       = functionNode;
         this.actualCallSiteType = actualCallSiteType;
+        this.log                = initLogger(Global.instance());
+    }
+
+    @Override
+    public DebugLogger getLogger() {
+        return log;
+    }
+
+    @Override
+    public DebugLogger initLogger(final Global global) {
+        return global.getLogger(this.getClass());
     }
 
     /**
@@ -176,7 +182,7 @@
                 }
             });
         } catch (final UnsupportedOperationException e) {
-            LOG.fine("'arguments' escapes, is not used in standard call dispatch, or is reassigned in '" + functionNode.getName() + "'. Aborting");
+            log.fine("'arguments' escapes, is not used in standard call dispatch, or is reassigned in '" + functionNode.getName() + "'. Aborting");
             return true; //bad
         }
 
@@ -204,7 +210,7 @@
         changed = false;
 
         if (!Global.instance().isSpecialNameValid("apply")) {
-            LOG.fine("Apply transform disabled: apply/call overridden");
+            log.fine("Apply transform disabled: apply/call overridden");
             assert !Global.instance().isSpecialNameValid("call") : "call and apply should have the same SwitchPoint";
             return finish();
         }
@@ -251,7 +257,7 @@
                     changed = true;
 
                     final CallNode newCallNode = callNode.setArgs(newArgs).setIsApplyToCall();
-                    LOG.fine("Transformed " + callNode + " from apply to call => " + newCallNode + " in '" + functionNode.getName() + "'");
+                    log.fine("Transformed " + callNode + " from apply to call => " + newCallNode + " in '" + functionNode.getName() + "'");
                     return newCallNode;
                 }
 
@@ -265,7 +271,7 @@
                     setParameters(null, newParams);
         }
 
-        LOG.info("Successfully specialized apply to call in '" + functionNode.getName() + "' id=" + functionNode.getId() + " signature=" + actualCallSiteType);
+        log.info("Successfully specialized apply to call in '" + functionNode.getName() + "' id=" + functionNode.getId() + " signature=" + actualCallSiteType);
 
         return finish();
     }
--- a/nashorn/src/jdk/nashorn/internal/codegen/Attr.java	Tue Apr 22 14:09:46 2014 +0200
+++ b/nashorn/src/jdk/nashorn/internal/codegen/Attr.java	Wed Apr 23 16:13:47 2014 +0200
@@ -59,6 +59,7 @@
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
+
 import jdk.nashorn.internal.codegen.types.Type;
 import jdk.nashorn.internal.ir.AccessNode;
 import jdk.nashorn.internal.ir.BinaryNode;
@@ -99,13 +100,16 @@
 import jdk.nashorn.internal.ir.WithNode;
 import jdk.nashorn.internal.ir.visitor.NodeOperatorVisitor;
 import jdk.nashorn.internal.ir.visitor.NodeVisitor;
+import jdk.nashorn.internal.objects.Global;
 import jdk.nashorn.internal.parser.TokenType;
 import jdk.nashorn.internal.runtime.Context;
 import jdk.nashorn.internal.runtime.Debug;
-import jdk.nashorn.internal.runtime.DebugLogger;
 import jdk.nashorn.internal.runtime.JSType;
 import jdk.nashorn.internal.runtime.Property;
 import jdk.nashorn.internal.runtime.PropertyMap;
+import jdk.nashorn.internal.runtime.logging.DebugLogger;
+import jdk.nashorn.internal.runtime.logging.Loggable;
+import jdk.nashorn.internal.runtime.logging.Logger;
 
 /**
  * This is the attribution pass of the code generator. Attr takes Lowered IR,
@@ -121,8 +125,8 @@
  * but in general, this is where the main symbol type information is
  * computed.
  */
-
-final class Attr extends NodeOperatorVisitor<OptimisticLexicalContext> {
+@Logger(name="Attr")
+final class Attr extends NodeOperatorVisitor<OptimisticLexicalContext> implements Loggable {
 
     private final CompilationEnvironment env;
 
@@ -146,8 +150,8 @@
 
     private int catchNestingLevel;
 
-    private static final DebugLogger LOG   = new DebugLogger("attr");
-    private static final boolean     DEBUG = LOG.isEnabled();
+    private final DebugLogger log;
+    private final boolean     debug;
 
     private final TemporarySymbols temporarySymbols;
 
@@ -160,6 +164,18 @@
         this.temporarySymbols = temporarySymbols;
         this.localDefs        = new ArrayDeque<>();
         this.localUses        = new ArrayDeque<>();
+        this.log              = initLogger(Global.instance());
+        this.debug            = log.isEnabled();
+    }
+
+    @Override
+    public DebugLogger getLogger() {
+        return log;
+    }
+
+    @Override
+    public DebugLogger initLogger(final Global global) {
+        return global.getLogger(this.getClass());
     }
 
     @Override
@@ -564,7 +580,7 @@
 
         if (newFunctionNode.usesSelfSymbol()) {
             syntheticInitializers = new ArrayList<>(2);
-            LOG.info("Accepting self symbol init for ", newFunctionNode.getName());
+            log.info("Accepting self symbol init for ", newFunctionNode.getName());
             // "var fn = :callee"
             syntheticInitializers.add(createSyntheticInitializer(newFunctionNode.getIdent(), CALLEE, newFunctionNode));
         }
@@ -628,8 +644,8 @@
         if (identNode.isPropertyName()) {
             // assign a pseudo symbol to property name
             final Symbol pseudoSymbol = pseudoSymbol(name);
-            LOG.info("IdentNode is property name -> assigning pseudo symbol ", pseudoSymbol);
-            LOG.unindent();
+            log.info("IdentNode is property name -> assigning pseudo symbol ", pseudoSymbol);
+            log.unindent();
             return end(identNode.setSymbol(lc, pseudoSymbol));
         }
 
@@ -639,7 +655,7 @@
 
         //If an existing symbol with the name is found, use that otherwise, declare a new one
         if (symbol != null) {
-            LOG.info("Existing symbol = ", symbol);
+            log.info("Existing symbol = ", symbol);
             if (symbol.isFunctionSelf()) {
                 final FunctionNode functionNode = lc.getDefiningFunction(symbol);
                 assert functionNode != null;
@@ -667,7 +683,7 @@
             // if symbol is non-local or we're in a with block, we need to put symbol in scope (if it isn't already)
             maybeForceScope(symbol);
         } else {
-            LOG.info("No symbol exists. Declare undefined: ", symbol);
+            log.info("No symbol exists. Declare undefined: ", symbol);
             symbol = defineGlobalSymbol(block, name);
             // we have never seen this before, it can be undefined
             newType(symbol, Type.OBJECT); // TODO unknown -we have explicit casts anyway?
@@ -1686,7 +1702,7 @@
 
             final Type callSiteParamType = env.getParamType(functionNode, pos);
             if (callSiteParamType != null) {
-                LOG.info("Callsite type override for parameter " + pos + " " + paramSymbol + " => " + callSiteParamType);
+                log.info("Callsite type override for parameter " + pos + " " + paramSymbol + " => " + callSiteParamType);
                 newType(paramSymbol, callSiteParamType);
             } else {
                 // When we're using optimistic compilation, we'll generate specialized versions of the functions anyway
@@ -1699,7 +1715,7 @@
                 // with Type.UNKNOWN.
                 newType(paramSymbol, isOptimistic ? Type.OBJECT : Type.UNKNOWN);
             }
-            LOG.info("Initialized param ", pos, "=", paramSymbol);
+            log.info("Initialized param ", pos, "=", paramSymbol);
             pos++;
         }
 
@@ -1771,7 +1787,7 @@
             final String key    = property.getKey();
             final Symbol symbol = defineGlobalSymbol(block, key);
             newType(symbol, Type.OBJECT);
-            LOG.info("Added global symbol from property map ", symbol);
+            log.info("Added global symbol from property map ", symbol);
         }
     }
 
@@ -1811,8 +1827,8 @@
                     }
                     final Type from = node.getType();
                     if (!Type.areEquivalent(from, to) && Type.widest(from, to) == to) {
-                        if (LOG.isEnabled()) {
-                            LOG.fine("Had to post pass widen '", node, "' ", Debug.id(node), " from ", node.getType(), " to ", to);
+                        if (log.isEnabled()) {
+                            log.fine("Had to post pass widen '", node, "' ", Debug.id(node), " from ", node.getType(), " to ", to);
                         }
                         Symbol symbol = node.getSymbol();
                         if (symbol.isShared() && symbol.wouldChangeType(to)) {
@@ -1983,7 +1999,7 @@
     }
 
     private Expression ensureSymbol(final Expression expr, final Type type) {
-        LOG.info("New TEMPORARY added to ", lc.getCurrentFunction().getName(), " type=", type);
+        log.info("New TEMPORARY added to ", lc.getCurrentFunction().getName(), " type=", type);
         return temporarySymbols.ensureSymbol(lc, type, expr);
     }
 
@@ -2030,14 +2046,14 @@
      */
     private void tagNeverOptimistic(final Expression expr) {
         if (expr instanceof Optimistic) {
-            LOG.info("Tagging TypeOverride node '" + expr + "' never optimistic");
+            log.info("Tagging TypeOverride node '" + expr + "' never optimistic");
             neverOptimistic.add(tag((Optimistic)expr));
         }
     }
 
     private void tagOptimistic(final Expression expr) {
         if (expr instanceof Optimistic) {
-            LOG.info("Tagging TypeOverride node '" + expr + "' as optimistic");
+            log.info("Tagging TypeOverride node '" + expr + "' as optimistic");
             optimistic.add(tag((Optimistic)expr));
         }
     }
@@ -2106,7 +2122,7 @@
                         expr = (T)expr.setSymbol(lc, symbol.createUnshared(symbol.getName()));
                     }
                 }
-                LOG.fine(expr, " turned optimistic with type=", optimisticType);
+                log.fine(expr, " turned optimistic with type=", optimisticType);
                 assert ((Optimistic)expr).isOptimistic();
             }
         }
@@ -2118,17 +2134,17 @@
         return defineSymbol(lc.getCurrentBlock(), name, IS_VAR | IS_INTERNAL).setType(type); //NASHORN-73
     }
 
-    private static void newType(final Symbol symbol, final Type type) {
+    private void newType(final Symbol symbol, final Type type) {
         final Type oldType = symbol.getSymbolType();
         symbol.setType(type);
 
         if (symbol.getSymbolType() != oldType) {
-            LOG.info("New TYPE ", type, " for ", symbol," (was ", oldType, ")");
+            log.info("New TYPE ", type, " for ", symbol," (was ", oldType, ")");
         }
 
         if (symbol.isParam()) {
             symbol.setType(type);
-            LOG.info("Param type change ", symbol);
+            log.info("Param type change ", symbol);
         }
     }
 
@@ -2156,12 +2172,12 @@
     }
 
     private void addLocalDef(final String name) {
-        LOG.info("Adding local def of symbol: '", name, "'");
+        log.info("Adding local def of symbol: '", name, "'");
         localDefs.peek().add(name);
     }
 
     private void removeLocalDef(final String name) {
-        LOG.info("Removing local def of symbol: '", name, "'");
+        log.info("Removing local def of symbol: '", name, "'");
         localDefs.peek().remove(name);
     }
 
@@ -2170,7 +2186,7 @@
     }
 
     private void addLocalUse(final String name) {
-        LOG.info("Adding local use of symbol: '", name, "'");
+        log.info("Adding local use of symbol: '", name, "'");
         localUses.peek().add(name);
     }
 
@@ -2183,7 +2199,7 @@
                 return;
             }
             if (symbolType != type) {
-               LOG.info("Infer parameter type " + symbol + " ==> " + type + " " + lc.getCurrentFunction().getSource().getName() + " " + lc.getCurrentFunction().getName());
+               log.info("Infer parameter type " + symbol + " ==> " + type + " " + lc.getCurrentFunction().getSource().getName() + " " + lc.getCurrentFunction().getName());
             }
             symbol.setType(type); //will be overwritten by object later if pessimistic anyway
             lc.logOptimisticAssumption(symbol, type);
@@ -2230,7 +2246,7 @@
     }
 
     private boolean start(final Node node, final boolean printNode) {
-        if (DEBUG) {
+        if (debug) {
             final StringBuilder sb = new StringBuilder();
 
             sb.append("[ENTER ").
@@ -2240,8 +2256,8 @@
                 append(" in '").
                 append(lc.getCurrentFunction().getName()).
                 append("'");
-            LOG.info(sb);
-            LOG.indent();
+            log.info(sb);
+            log.indent();
         }
 
         return true;
@@ -2256,7 +2272,7 @@
             // If we're done with a statement, all temporaries can be reused.
             temporarySymbols.reuse();
         }
-        if (DEBUG) {
+        if (debug) {
             final StringBuilder sb = new StringBuilder();
 
             sb.append("[LEAVE ").
@@ -2276,8 +2292,8 @@
                 }
             }
 
-            LOG.unindent();
-            LOG.info(sb);
+            log.unindent();
+            log.info(sb);
         }
 
         return node;
--- a/nashorn/src/jdk/nashorn/internal/codegen/CodeGenerator.java	Tue Apr 22 14:09:46 2014 +0200
+++ b/nashorn/src/jdk/nashorn/internal/codegen/CodeGenerator.java	Wed Apr 23 16:13:47 2014 +0200
@@ -133,7 +133,6 @@
 import jdk.nashorn.internal.parser.TokenType;
 import jdk.nashorn.internal.runtime.Context;
 import jdk.nashorn.internal.runtime.Debug;
-import jdk.nashorn.internal.runtime.DebugLogger;
 import jdk.nashorn.internal.runtime.ECMAException;
 import jdk.nashorn.internal.runtime.JSType;
 import jdk.nashorn.internal.runtime.OptimisticReturnFilters;
@@ -149,6 +148,9 @@
 import jdk.nashorn.internal.runtime.UnwarrantedOptimismException;
 import jdk.nashorn.internal.runtime.arrays.ArrayData;
 import jdk.nashorn.internal.runtime.linker.LinkerCallSite;
+import jdk.nashorn.internal.runtime.logging.DebugLogger;
+import jdk.nashorn.internal.runtime.logging.Loggable;
+import jdk.nashorn.internal.runtime.logging.Logger;
 import jdk.nashorn.internal.runtime.options.Options;
 
 /**
@@ -170,7 +172,8 @@
  * The CodeGenerator visits nodes only once, tags them as resolved and emits
  * bytecode for them.
  */
-final class CodeGenerator extends NodeOperatorVisitor<CodeGeneratorLexicalContext> {
+@Logger(name="codegen")
+final class CodeGenerator extends NodeOperatorVisitor<CodeGeneratorLexicalContext> implements Loggable {
 
     private static final Type SCOPE_TYPE = Type.typeFor(ScriptObject.class);
 
@@ -214,7 +217,7 @@
     /** Current compile unit */
     private CompileUnit unit;
 
-    private static final DebugLogger LOG   = new DebugLogger("codegen", "nashorn.codegen.debug");
+    private final DebugLogger log;
 
     /** From what size should we use spill instead of fields for JavaScript objects? */
     private static final int OBJECT_SPILL_THRESHOLD = Options.getIntProperty("nashorn.spill.threshold", 256);
@@ -237,6 +240,17 @@
         super(new CodeGeneratorLexicalContext());
         this.compiler      = compiler;
         this.callSiteFlags = compiler.getEnv()._callsite_flags;
+        this.log           = initLogger(Global.instance());
+    }
+
+    @Override
+    public DebugLogger getLogger() {
+        return log;
+    }
+
+    @Override
+    public DebugLogger initLogger(final Global global) {
+        return global.getLogger(this.getClass());
     }
 
     /**
@@ -1511,7 +1525,7 @@
         // exact type closure and deduplicate based on that, or just decide that functions in finally blocks aren't
         // worth it, and generate one method with most generic type closure.
         if (!emittedMethods.contains(fnName)) {
-            LOG.info("=== BEGIN ", fnName);
+            log.info("=== BEGIN ", fnName);
 
             assert functionNode.getCompileUnit() != null : "no compile unit for " + fnName + " " + Debug.id(functionNode);
             unit = lc.pushCompileUnit(functionNode.getCompileUnit());
@@ -1550,7 +1564,7 @@
                 method.end(); // wrap up this method
                 unit   = lc.popCompileUnit(functionNode.getCompileUnit());
                 method = lc.popMethodEmitter(method);
-                LOG.info("=== END ", functionNode.getName());
+                log.info("=== END ", functionNode.getName());
             } else {
                 markOptimistic = false;
             }
--- a/nashorn/src/jdk/nashorn/internal/codegen/CompilationPhase.java	Tue Apr 22 14:09:46 2014 +0200
+++ b/nashorn/src/jdk/nashorn/internal/codegen/CompilationPhase.java	Wed Apr 23 16:13:47 2014 +0200
@@ -1,6 +1,30 @@
+/*
+ * 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.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;
@@ -29,6 +53,7 @@
 import jdk.nashorn.internal.ir.debug.ASTWriter;
 import jdk.nashorn.internal.ir.debug.PrintVisitor;
 import jdk.nashorn.internal.ir.visitor.NodeVisitor;
+import jdk.nashorn.internal.objects.Global;
 import jdk.nashorn.internal.runtime.ScriptEnvironment;
 import jdk.nashorn.internal.runtime.Timing;
 
@@ -128,7 +153,7 @@
                         accept(new Attr(compiler.getCompilationEnvironment(), ts));
 
             if (compiler.getEnv()._print_mem_usage) {
-                info("Attr temporary symbol count:", ts.getTotalSymbolCount());
+                compiler.getLogger().info("Attr temporary symbol count:", ts.getTotalSymbolCount());
             }
 
             return newFunctionNode;
@@ -213,7 +238,7 @@
 
                             final Type rangeType  = range.getType();
                             if (!rangeType.isUnknown() && !Type.areEquivalent(symbolType, rangeType) && Type.widest(symbolType, rangeType) == symbolType) { //we can narrow range
-                                RangeAnalyzer.LOG.info("[", lc.getCurrentFunction().getName(), "] ", symbol, " can be ", range.getType(), " ", symbol.getRange());
+                                Global.instance().getLogger(RangeAnalyzer.class).info("[", lc.getCurrentFunction().getName(), "] ", symbol, " can be ", range.getType(), " ", symbol.getRange());
                                 return expr.setSymbol(lc, symbol.setTypeOverrideShared(range.getType(), compiler.getTemporarySymbols()));
                             }
                         }
@@ -332,7 +357,7 @@
                     compiler.getCodeInstaller().verify(bytecode);
                 }
 
-                DumpBytecode.dumpBytecode(env, bytecode, className);
+                DumpBytecode.dumpBytecode(env, compiler, bytecode, className);
             }
 
             return newFunctionNode;
--- a/nashorn/src/jdk/nashorn/internal/codegen/Compiler.java	Tue Apr 22 14:09:46 2014 +0200
+++ b/nashorn/src/jdk/nashorn/internal/codegen/Compiler.java	Wed Apr 23 16:13:47 2014 +0200
@@ -51,6 +51,7 @@
 import java.util.Set;
 import java.util.TreeSet;
 import java.util.logging.Level;
+
 import jdk.internal.dynalink.support.NameCodec;
 import jdk.nashorn.internal.codegen.ClassEmitter.Flag;
 import jdk.nashorn.internal.codegen.CompilationEnvironment.CompilationPhases;
@@ -60,12 +61,15 @@
 import jdk.nashorn.internal.ir.TemporarySymbols;
 import jdk.nashorn.internal.ir.debug.ClassHistogramElement;
 import jdk.nashorn.internal.ir.debug.ObjectSizeCalculator;
+import jdk.nashorn.internal.objects.Global;
 import jdk.nashorn.internal.runtime.CodeInstaller;
-import jdk.nashorn.internal.runtime.DebugLogger;
 import jdk.nashorn.internal.runtime.RecompilableScriptFunctionData;
 import jdk.nashorn.internal.runtime.ScriptEnvironment;
 import jdk.nashorn.internal.runtime.Source;
 import jdk.nashorn.internal.runtime.Timing;
+import jdk.nashorn.internal.runtime.logging.DebugLogger;
+import jdk.nashorn.internal.runtime.logging.Loggable;
+import jdk.nashorn.internal.runtime.logging.Logger;
 
 /**
  * Responsible for converting JavaScripts to java byte code. Main entry
@@ -73,7 +77,8 @@
  * predefined Code installation policy, given to it at construction time.
  * @see CodeInstaller
  */
-public final class Compiler {
+@Logger(name="compiler")
+public final class Compiler implements Loggable {
 
     /** Name of the scripts package */
     public static final String SCRIPTS_PACKAGE = "jdk/nashorn/internal/scripts";
@@ -104,21 +109,9 @@
 
     /** logger for compiler, trampolines, splits and related code generation events
      *  that affect classes */
-    private static final DebugLogger LOG = new DebugLogger("compiler");
+    private final DebugLogger log;
 
-    /**
-     * Get the logger used for this compiler
-     * @return logger
-     */
-    public static DebugLogger getLogger() {
-        return LOG;
-    }
-
-    static {
-        if (!ScriptEnvironment.globalOptimistic()) {
-            LOG.warning("Running without optimistic types. This is a configuration that may be deprecated.");
-        }
-    }
+    private static boolean initialized = false;
 
     /**
      * This array contains names that need to be reserved at the start
@@ -157,6 +150,16 @@
         this.constantData   = new ConstantData();
         this.compileUnits   = new TreeSet<>();
         this.bytecode       = new LinkedHashMap<>();
+        this.log            = initLogger(Global.instance());
+
+        synchronized (Compiler.class) {
+            if (!initialized) {
+                initialized = true;
+                if (!ScriptEnvironment.globalOptimistic()) {
+                    log.warning("Running without optimistic types. This is a configuration that may be deprecated.");
+                }
+            }
+        }
     }
 
     /**
@@ -177,12 +180,22 @@
         this(new CompilationEnvironment(CompilationPhases.EAGER, scriptEnv._strict), scriptEnv, null);
     }
 
-    private static void printMemoryUsage(final String phaseName, final FunctionNode functionNode) {
-        if (!LOG.isEnabled()) {
+    @Override
+    public DebugLogger getLogger() {
+        return log;
+    }
+
+    @Override
+    public DebugLogger initLogger(final Global global) {
+        return global.getLogger(this.getClass());
+    }
+
+    private void printMemoryUsage(final String phaseName, final FunctionNode functionNode) {
+        if (!log.isEnabled()) {
             return;
         }
 
-        info(phaseName, "finished. Doing IR size calculation...");
+        log.info(phaseName, "finished. Doing IR size calculation...");
 
         final ObjectSizeCalculator osc = new ObjectSizeCalculator(ObjectSizeCalculator.getEffectiveMemoryLayoutSpecification());
         osc.calculateObjectSize(functionNode);
@@ -195,7 +208,7 @@
             append(" Total size = ").
             append(totalSize / 1024 / 1024).
             append("MB");
-        LOG.info(sb);
+        log.info(sb);
 
         Collections.sort(list, new Comparator<ClassHistogramElement>() {
             @Override
@@ -212,9 +225,9 @@
         });
         for (final ClassHistogramElement e : list) {
             final String line = String.format("    %-48s %10d bytes (%8d instances)", e.getClazz(), e.getBytes(), e.getInstances());
-            info(line);
+            log.info(line);
             if (e.getBytes() < totalSize / 200) {
-                info("    ...");
+                log.info("    ...");
                 break; // never mind, so little memory anyway
             }
         }
@@ -258,8 +271,8 @@
             newFunctionNode.uniqueName(reservedName);
         }
 
-        final boolean fine = LOG.levelFinerThanOrEqual(Level.FINE);
-        final boolean info = LOG.levelFinerThanOrEqual(Level.INFO);
+        final boolean fine = log.levelFinerThanOrEqual(Level.FINE);
+        final boolean info = log.levelFinerThanOrEqual(Level.INFO);
 
         long time = 0L;
 
@@ -287,7 +300,7 @@
                         append(" ms ");
                 }
 
-                LOG.fine(sb);
+                log.fine(sb);
             }
         }
 
@@ -305,14 +318,14 @@
                     append(" ms");
             }
 
-            LOG.info(sb);
+            log.info(sb);
         }
 
         return newFunctionNode;
     }
 
     private Class<?> install(final String className, final byte[] code) {
-        LOG.fine("Installing class ", className);
+        log.fine("Installing class ", className);
 
         final Class<?> clazz = installer.install(Compiler.binaryName(className), code);
 
@@ -384,7 +397,7 @@
         }
 
         final StringBuilder sb;
-        if (LOG.isEnabled()) {
+        if (log.isEnabled()) {
             sb = new StringBuilder();
             sb.append("Installed class '").
                 append(rootClass.getSimpleName()).
@@ -408,7 +421,7 @@
         }
 
         if (sb != null) {
-            LOG.fine(sb);
+            log.fine(sb);
         }
 
         return rootClass;
@@ -482,7 +495,7 @@
     private CompileUnit addCompileUnit(final String unitClassName, final long initialWeight) {
         final CompileUnit compileUnit = initCompileUnit(unitClassName, initialWeight);
         compileUnits.add(compileUnit);
-        LOG.fine("Added compile unit ", compileUnit);
+        log.fine("Added compile unit ", compileUnit);
         return compileUnit;
     }
 
@@ -523,35 +536,4 @@
         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/nashorn/src/jdk/nashorn/internal/codegen/DumpBytecode.java	Tue Apr 22 14:09:46 2014 +0200
+++ b/nashorn/src/jdk/nashorn/internal/codegen/DumpBytecode.java	Wed Apr 23 16:13:47 2014 +0200
@@ -25,9 +25,6 @@
 
 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;
@@ -39,7 +36,7 @@
  * Class that facilitates dumping bytecode to disk
  */
 final class DumpBytecode {
-    static void dumpBytecode(final ScriptEnvironment env, final byte[] bytecode, final String className) {
+    static void dumpBytecode(final ScriptEnvironment env, final Compiler compiler, final byte[] bytecode, final String className) {
         File dir = null;
         try {
             // should could be printed to stderr for generate class?
@@ -54,7 +51,7 @@
                 if (env._print_code_dir != null) {
 
                     String name = className;
-                    int dollar = name.lastIndexOf('$');
+                    final int dollar = name.lastIndexOf('$');
                     if (dollar != -1) {
                         name = name.substring(dollar + 1);
                     }
@@ -101,10 +98,10 @@
                 try (final FileOutputStream fos = new FileOutputStream(file)) {
                     fos.write(bytecode);
                 }
-                info("Wrote class to '" + file.getAbsolutePath() + '\'');
+                compiler.getLogger().info("Wrote class to '" + file.getAbsolutePath() + '\'');
             }
         } catch (final IOException e) {
-            warning("Skipping class dump for ",
+            compiler.getLogger().warning("Skipping class dump for ",
                     className,
                     ": ",
                     ECMAErrors.getMessage(
--- a/nashorn/src/jdk/nashorn/internal/codegen/FinalizeTypes.java	Tue Apr 22 14:09:46 2014 +0200
+++ b/nashorn/src/jdk/nashorn/internal/codegen/FinalizeTypes.java	Wed Apr 23 16:13:47 2014 +0200
@@ -42,9 +42,12 @@
 import jdk.nashorn.internal.ir.Symbol;
 import jdk.nashorn.internal.ir.UnaryNode;
 import jdk.nashorn.internal.ir.visitor.NodeOperatorVisitor;
+import jdk.nashorn.internal.objects.Global;
 import jdk.nashorn.internal.parser.Token;
 import jdk.nashorn.internal.parser.TokenType;
-import jdk.nashorn.internal.runtime.DebugLogger;
+import jdk.nashorn.internal.runtime.logging.DebugLogger;
+import jdk.nashorn.internal.runtime.logging.Loggable;
+import jdk.nashorn.internal.runtime.logging.Logger;
 
 /**
  * Lower to more primitive operations. After lowering, an AST has symbols and
@@ -58,13 +61,24 @@
  * that scope and slot information is correct. This enables e.g. AccessSpecialization
  * and frame optimizations
  */
+@Logger(name="finalize")
+final class FinalizeTypes extends NodeOperatorVisitor<LexicalContext> implements Loggable {
 
-final class FinalizeTypes extends NodeOperatorVisitor<LexicalContext> {
-
-    private static final DebugLogger LOG = new DebugLogger("finalize");
+    private final DebugLogger log;
 
     FinalizeTypes() {
         super(new LexicalContext());
+        this.log = initLogger(Global.instance());
+    }
+
+    @Override
+    public DebugLogger getLogger() {
+        return log;
+    }
+
+    @Override
+    public DebugLogger initLogger(final Global global) {
+        return global.getLogger(this.getClass());
     }
 
     @Override
@@ -176,13 +190,13 @@
         return functionNode.setState(lc, CompilationState.FINALIZED);
     }
 
-    private static void updateSymbolsLog(final FunctionNode functionNode, final Symbol symbol, final boolean loseSlot) {
-        if (LOG.isEnabled()) {
+    private void updateSymbolsLog(final FunctionNode functionNode, final Symbol symbol, final boolean loseSlot) {
+        if (log.isEnabled()) {
             if (!symbol.isScope()) {
-                LOG.finest("updateSymbols: ", symbol, " => scope, because all vars in ", functionNode.getName(), " are in scope");
+                log.finest("updateSymbols: ", symbol, " => scope, because all vars in ", functionNode.getName(), " are in scope");
             }
             if (loseSlot && symbol.hasSlot()) {
-                LOG.finest("updateSymbols: ", symbol, " => no slot, because all vars in ", functionNode.getName(), " are in scope");
+                log.finest("updateSymbols: ", symbol, " => no slot, because all vars in ", functionNode.getName(), " are in scope");
             }
         }
     }
--- a/nashorn/src/jdk/nashorn/internal/codegen/FindScopeDepths.java	Tue Apr 22 14:09:46 2014 +0200
+++ b/nashorn/src/jdk/nashorn/internal/codegen/FindScopeDepths.java	Wed Apr 23 16:13:47 2014 +0200
@@ -42,9 +42,12 @@
 import jdk.nashorn.internal.ir.Node;
 import jdk.nashorn.internal.ir.Symbol;
 import jdk.nashorn.internal.ir.visitor.NodeVisitor;
-import jdk.nashorn.internal.runtime.DebugLogger;
+import jdk.nashorn.internal.objects.Global;
 import jdk.nashorn.internal.runtime.PropertyMap;
 import jdk.nashorn.internal.runtime.RecompilableScriptFunctionData;
+import jdk.nashorn.internal.runtime.logging.DebugLogger;
+import jdk.nashorn.internal.runtime.logging.Loggable;
+import jdk.nashorn.internal.runtime.logging.Logger;
 
 /**
  * Establishes depth of scope for non local symbols at the start of method.
@@ -52,8 +55,8 @@
  * stored in the RecompilableScriptFunctionData and is transferred to the
  * FunctionNode being compiled
  */
-
-final class FindScopeDepths extends NodeVisitor<LexicalContext> {
+@Logger(name="scopedepths")
+final class FindScopeDepths extends NodeVisitor<LexicalContext> implements Loggable {
 
     private final Compiler compiler;
     private final CompilationEnvironment env;
@@ -61,12 +64,23 @@
     private final Map<Integer, Map<String, Integer>> externalSymbolDepths = new HashMap<>();
     private final Map<Integer, Set<String>> internalSymbols = new HashMap<>();
 
-    private final static DebugLogger LOG = new DebugLogger("scopedepths");
+    private final DebugLogger log;
 
     FindScopeDepths(final Compiler compiler) {
         super(new LexicalContext());
         this.compiler = compiler;
-        this.env = compiler.getCompilationEnvironment();
+        this.env      = compiler.getCompilationEnvironment();
+        this.log      = initLogger(Global.instance());
+    }
+
+    @Override
+    public DebugLogger getLogger() {
+        return log;
+    }
+
+    @Override
+    public DebugLogger initLogger(final Global global) {
+        return global.getLogger(this.getClass());
     }
 
     static int findScopesToStart(final LexicalContext lc, final FunctionNode fn, final Block block) {
@@ -266,8 +280,8 @@
 
         addInternalSymbols(fn, internals.keySet());
 
-        if (LOG.isEnabled()) {
-            LOG.info(fn.getName() + " internals=" + internals + " externals=" + externalSymbolDepths.get(fn.getId()));
+        if (log.isEnabled()) {
+            log.info(fn.getName() + " internals=" + internals + " externals=" + externalSymbolDepths.get(fn.getId()));
         }
 
         return true;
--- a/nashorn/src/jdk/nashorn/internal/codegen/FoldConstants.java	Tue Apr 22 14:09:46 2014 +0200
+++ b/nashorn/src/jdk/nashorn/internal/codegen/FoldConstants.java	Wed Apr 23 16:13:47 2014 +0200
@@ -27,6 +27,7 @@
 
 import java.util.ArrayList;
 import java.util.List;
+
 import jdk.nashorn.internal.codegen.types.Type;
 import jdk.nashorn.internal.ir.BinaryNode;
 import jdk.nashorn.internal.ir.Block;
@@ -44,26 +45,41 @@
 import jdk.nashorn.internal.ir.UnaryNode;
 import jdk.nashorn.internal.ir.VarNode;
 import jdk.nashorn.internal.ir.visitor.NodeVisitor;
-import jdk.nashorn.internal.runtime.DebugLogger;
+import jdk.nashorn.internal.objects.Global;
 import jdk.nashorn.internal.runtime.JSType;
 import jdk.nashorn.internal.runtime.ScriptRuntime;
+import jdk.nashorn.internal.runtime.logging.DebugLogger;
+import jdk.nashorn.internal.runtime.logging.Loggable;
+import jdk.nashorn.internal.runtime.logging.Logger;
 
 /**
  * Simple constant folding pass, executed before IR is starting to be lowered.
  */
-final class FoldConstants extends NodeVisitor<LexicalContext> {
+@Logger(name="fold")
+final class FoldConstants extends NodeVisitor<LexicalContext> implements Loggable {
 
-    private static final DebugLogger LOG = new DebugLogger("fold");
+    private final DebugLogger log;
 
     FoldConstants() {
         super(new LexicalContext());
+        this.log = initLogger(Global.instance());
+    }
+
+    @Override
+    public DebugLogger getLogger() {
+        return log;
+    }
+
+    @Override
+    public DebugLogger initLogger(final Global global) {
+        return global.getLogger(this.getClass());
     }
 
     @Override
     public Node leaveUnaryNode(final UnaryNode unaryNode) {
         final LiteralNode<?> literalNode = new UnaryNodeConstantEvaluator(unaryNode).eval();
         if (literalNode != null) {
-            LOG.info("Unary constant folded ", unaryNode, " to ", literalNode);
+            log.info("Unary constant folded ", unaryNode, " to ", literalNode);
             return literalNode;
         }
         return unaryNode;
@@ -73,7 +89,7 @@
     public Node leaveBinaryNode(final BinaryNode binaryNode) {
         final LiteralNode<?> literalNode = new BinaryNodeConstantEvaluator(binaryNode).eval();
         if (literalNode != null) {
-            LOG.info("Binary constant folded ", binaryNode, " to ", literalNode);
+            log.info("Binary constant folded ", binaryNode, " to ", literalNode);
             return literalNode;
         }
         return binaryNode;
@@ -144,7 +160,7 @@
         final LexicalContext lc = new LexicalContext();
         block.accept(lc, new NodeVisitor<LexicalContext>(lc) {
             @Override
-            public boolean enterVarNode(VarNode varNode) {
+            public boolean enterVarNode(final VarNode varNode) {
                 statements.add(varNode.setInit(null));
                 return false;
             }
@@ -256,7 +272,7 @@
                 break;
             case ADD:
                 if ((lhs.isString() || rhs.isNumeric()) && (rhs.isString() || rhs.isNumeric())) {
-                    Object res = ScriptRuntime.ADD(lhs.getObject(), rhs.getObject());
+                    final Object res = ScriptRuntime.ADD(lhs.getObject(), rhs.getObject());
                     if (res instanceof Number) {
                         value = ((Number)res).doubleValue();
                         break;
--- a/nashorn/src/jdk/nashorn/internal/codegen/Lower.java	Tue Apr 22 14:09:46 2014 +0200
+++ b/nashorn/src/jdk/nashorn/internal/codegen/Lower.java	Wed Apr 23 16:13:47 2014 +0200
@@ -34,6 +34,7 @@
 import java.util.Collections;
 import java.util.List;
 import java.util.ListIterator;
+
 import jdk.nashorn.internal.ir.BaseNode;
 import jdk.nashorn.internal.ir.BinaryNode;
 import jdk.nashorn.internal.ir.Block;
@@ -67,12 +68,15 @@
 import jdk.nashorn.internal.ir.WithNode;
 import jdk.nashorn.internal.ir.visitor.NodeOperatorVisitor;
 import jdk.nashorn.internal.ir.visitor.NodeVisitor;
+import jdk.nashorn.internal.objects.Global;
 import jdk.nashorn.internal.parser.Token;
 import jdk.nashorn.internal.parser.TokenType;
 import jdk.nashorn.internal.runtime.CodeInstaller;
-import jdk.nashorn.internal.runtime.DebugLogger;
 import jdk.nashorn.internal.runtime.ScriptRuntime;
 import jdk.nashorn.internal.runtime.Source;
+import jdk.nashorn.internal.runtime.logging.DebugLogger;
+import jdk.nashorn.internal.runtime.logging.Loggable;
+import jdk.nashorn.internal.runtime.logging.Logger;
 
 /**
  * Lower to more primitive operations. After lowering, an AST still has no symbols
@@ -83,10 +87,10 @@
  * harder and context dependent to do any code copying after symbols have been
  * finalized.
  */
+@Logger(name="lower")
+final class Lower extends NodeOperatorVisitor<BlockLexicalContext> implements Loggable {
 
-final class Lower extends NodeOperatorVisitor<BlockLexicalContext> {
-
-    private static final DebugLogger LOG = new DebugLogger("lower");
+    private final DebugLogger log;
 
     // needed only to get unique eval id
     private final CodeInstaller<?> installer;
@@ -137,7 +141,19 @@
                 return block.setIsTerminal(this, false);
             }
         });
+
         this.installer = installer;
+        this.log = initLogger(Global.instance());
+    }
+
+    @Override
+    public DebugLogger getLogger() {
+        return log;
+    }
+
+    @Override
+    public DebugLogger initLogger(final Global global) {
+        return global.getLogger(this.getClass());
     }
 
     @Override
@@ -223,7 +239,7 @@
     }
 
     @Override
-    public Node leaveBlockStatement(BlockStatement blockStatement) {
+    public Node leaveBlockStatement(final BlockStatement blockStatement) {
         return addStatement(blockStatement);
     }
 
@@ -252,7 +268,7 @@
 
     @Override
     public Node leaveFunctionNode(final FunctionNode functionNode) {
-        LOG.info("END FunctionNode: ", functionNode.getName());
+        log.info("END FunctionNode: ", functionNode.getName());
         return functionNode.setState(lc, CompilationState.LOWERED);
     }
 
@@ -478,7 +494,7 @@
         if (tryNode.getCatchBlocks().isEmpty()) {
             newTryNode = tryNode.setFinallyBody(null);
         } else {
-            Block outerBody = new Block(tryNode.getToken(), tryNode.getFinish(), tryNode.setFinallyBody(null));
+            final Block outerBody = new Block(tryNode.getToken(), tryNode.getFinish(), tryNode.setFinallyBody(null));
             newTryNode = tryNode.setBody(outerBody).setCatchBlocks(null);
         }
 
@@ -667,7 +683,7 @@
      * @return true if an assignment to eval result, false otherwise
      */
     private static boolean isEvalResultAssignment(final Node expression) {
-        Node e = expression;
+        final Node e = expression;
         assert e.tokenType() != TokenType.DISCARD; //there are no discards this early anymore
         if (e instanceof BinaryNode) {
             final Node lhs = ((BinaryNode)e).lhs();
--- a/nashorn/src/jdk/nashorn/internal/codegen/MethodEmitter.java	Tue Apr 22 14:09:46 2014 +0200
+++ b/nashorn/src/jdk/nashorn/internal/codegen/MethodEmitter.java	Wed Apr 23 16:13:47 2014 +0200
@@ -98,12 +98,12 @@
 import jdk.nashorn.internal.objects.Global;
 import jdk.nashorn.internal.runtime.ArgumentSetter;
 import jdk.nashorn.internal.runtime.Debug;
-import jdk.nashorn.internal.runtime.DebugLogger;
 import jdk.nashorn.internal.runtime.JSType;
 import jdk.nashorn.internal.runtime.RewriteException;
 import jdk.nashorn.internal.runtime.ScriptEnvironment;
 import jdk.nashorn.internal.runtime.ScriptObject;
 import jdk.nashorn.internal.runtime.linker.Bootstrap;
+import jdk.nashorn.internal.runtime.logging.DebugLogger;
 import jdk.nashorn.internal.runtime.options.Options;
 
 /**
@@ -144,8 +144,8 @@
     static final int LARGE_STRING_THRESHOLD = 32 * 1024;
 
     /** Debug flag, should we dump all generated bytecode along with stacks? */
-    private static final DebugLogger LOG   = new DebugLogger("codegen", "nashorn.codegen.debug");
-    private static final boolean     DEBUG = LOG.isEnabled();
+    private final DebugLogger log   = Global.instance().getLogger(CodeGenerator.class);
+    private final boolean     debug = log.isEnabled();
 
     /** dump stack on a particular line, or -1 if disabled */
     private static final int DEBUG_TRACE_LINE;
@@ -2301,7 +2301,7 @@
      * @param args debug information to print
      */
     private void debug(final Object... args) {
-        if (DEBUG) {
+        if (debug) {
             debug(30, args);
         }
     }
@@ -2313,13 +2313,13 @@
      * @param args debug information to print
      */
     private void debug_label(final Object... args) {
-        if (DEBUG) {
+        if (debug) {
             debug(22, args);
         }
     }
 
     private void debug(final int padConstant, final Object... args) {
-        if (DEBUG) {
+        if (debug) {
             final StringBuilder sb = new StringBuilder();
             int pad;
 
@@ -2386,9 +2386,9 @@
             }
 
             if (env != null) { //early bootstrap code doesn't have inited context yet
-                LOG.info(sb);
+                log.info(sb);
                 if (DEBUG_TRACE_LINE == linePrefix) {
-                    new Throwable().printStackTrace(LOG.getOutputStream());
+                    new Throwable().printStackTrace(log.getOutputStream());
                 }
             }
         }
--- a/nashorn/src/jdk/nashorn/internal/codegen/ObjectClassGenerator.java	Tue Apr 22 14:09:46 2014 +0200
+++ b/nashorn/src/jdk/nashorn/internal/codegen/ObjectClassGenerator.java	Wed Apr 23 16:13:47 2014 +0200
@@ -50,30 +50,30 @@
 import java.lang.invoke.MethodHandles;
 import java.lang.invoke.MethodType;
 import java.util.EnumSet;
-import java.util.HashSet;
 import java.util.Iterator;
 import java.util.LinkedList;
 import java.util.List;
-import java.util.Set;
-import java.util.StringTokenizer;
-
 import jdk.nashorn.internal.codegen.ClassEmitter.Flag;
 import jdk.nashorn.internal.codegen.types.Type;
+import jdk.nashorn.internal.objects.Global;
 import jdk.nashorn.internal.runtime.AccessorProperty;
 import jdk.nashorn.internal.runtime.Context;
-import jdk.nashorn.internal.runtime.DebugLogger;
 import jdk.nashorn.internal.runtime.FunctionScope;
 import jdk.nashorn.internal.runtime.PropertyMap;
 import jdk.nashorn.internal.runtime.ScriptEnvironment;
 import jdk.nashorn.internal.runtime.ScriptObject;
 import jdk.nashorn.internal.runtime.Undefined;
 import jdk.nashorn.internal.runtime.UnwarrantedOptimismException;
+import jdk.nashorn.internal.runtime.logging.DebugLogger;
+import jdk.nashorn.internal.runtime.logging.Loggable;
+import jdk.nashorn.internal.runtime.logging.Logger;
 import jdk.nashorn.internal.runtime.options.Options;
 
 /**
  * Generates the ScriptObject subclass structure with fields for a user objects.
  */
-public final class ObjectClassGenerator {
+@Logger(name="fields")
+public final class ObjectClassGenerator implements Loggable {
 
     /**
      * Type guard to make sure we don't unnecessarily explode field storages. Rather unbox e.g.
@@ -96,44 +96,12 @@
      * Debug field logger
      * Should we print debugging information for fields when they are generated and getters/setters are called?
      */
-    private static final DebugLogger LOG = new DebugLogger("fields", "nashorn.fields.debug");
-
-    /**
-     * Get the field logger
-     * @return logger
-     */
-    public static DebugLogger getLogger() {
-        return LOG;
-    }
+    private final DebugLogger log;
 
-    private static final Set<String> FIELDS_TO_INSTRUMENT;
-    static {
-        final String fields = Options.getStringProperty("nashorn.fields", null);
-        final Set<String> fti = new HashSet<>();
-        if (fields != null) {
-            final StringTokenizer st = new StringTokenizer(fields, ",");
-            while (st.hasMoreTokens()) {
-                fti.add(st.nextToken());
-            }
-        }
-        FIELDS_TO_INSTRUMENT = fti.isEmpty() ? null : fti;
-    }
-
-    /**
-     * Should this particular field be instrumented with --log=fields
-     * Internal use only
-     * @param field field name
-     * @return true if it should be instrumented
-     */
-    public static boolean shouldInstrument(final String field) {
-        //if no explicit fields to imstrument are given, instrument all fields
-        return FIELDS_TO_INSTRUMENT == null || FIELDS_TO_INSTRUMENT.contains(field);
-    }
     /**
      * is field debugging enabled. Several modules in codegen and properties use this, hence
      * public access.
      */
-    public static final boolean DEBUG_FIELDS = LOG.isEnabled();
 
     private static final boolean EXPLICIT_OBJECT = Options.getBooleanProperty("nashorn.fields.objects");
 
@@ -163,11 +131,10 @@
     static {
         if (!OBJECT_FIELDS_ONLY) {
             FIELD_TYPES.add(PRIMITIVE_FIELD_TYPE);
-        } else {
-            LOG.warning("Running with object fields only - this is a deprecated configuration.");
         }
         FIELD_TYPES.add(Type.OBJECT);
     }
+    private static boolean initialized = false;
 
     /** The context */
     private final Context context;
@@ -180,6 +147,25 @@
     public ObjectClassGenerator(final Context context) {
         this.context = context;
         assert context != null;
+        this.log = initLogger(Global.instance());
+        synchronized (ObjectClassGenerator.class) {
+            if (!initialized) {
+                initialized = true;
+                if (OBJECT_FIELDS_ONLY) {
+                    log.warning("Running with object fields only - this is a deprecated configuration.");
+                }
+            }
+        }
+    }
+
+    @Override
+    public DebugLogger getLogger() {
+        return log;
+    }
+
+    @Override
+    public DebugLogger initLogger(final Global global) {
+        return global.getLogger(this.getClass());
     }
 
     /**
--- a/nashorn/src/jdk/nashorn/internal/codegen/RangeAnalyzer.java	Tue Apr 22 14:09:46 2014 +0200
+++ b/nashorn/src/jdk/nashorn/internal/codegen/RangeAnalyzer.java	Wed Apr 23 16:13:47 2014 +0200
@@ -47,8 +47,11 @@
 import jdk.nashorn.internal.ir.VarNode;
 import jdk.nashorn.internal.ir.visitor.NodeOperatorVisitor;
 import jdk.nashorn.internal.ir.visitor.NodeVisitor;
+import jdk.nashorn.internal.objects.Global;
 import jdk.nashorn.internal.parser.TokenType;
-import jdk.nashorn.internal.runtime.DebugLogger;
+import jdk.nashorn.internal.runtime.logging.DebugLogger;
+import jdk.nashorn.internal.runtime.logging.Loggable;
+import jdk.nashorn.internal.runtime.logging.Logger;
 
 /**
  * Range analysis and narrowing of type where it can be proven
@@ -63,15 +66,28 @@
  *
  *  Proves that the multiplication never exceeds 24 bits and can thus be an int
  */
-final class RangeAnalyzer extends NodeOperatorVisitor<LexicalContext> {
-    static final DebugLogger LOG = new DebugLogger("ranges");
+@Logger(name="ranges")
+final class RangeAnalyzer extends NodeOperatorVisitor<LexicalContext> implements Loggable {
+    private final DebugLogger log;
 
-    private static final Range.Functionality RANGE = new Range.Functionality(LOG);
+    private final Range.Functionality func;
 
     private final Map<LoopNode, Symbol> loopCounters = new HashMap<>();
 
     RangeAnalyzer() {
         super(new LexicalContext());
+        this.log  = initLogger(Global.instance());
+        this.func = new Range.Functionality(log);
+    }
+
+    @Override
+    public DebugLogger getLogger() {
+        return log;
+    }
+
+    @Override
+    public DebugLogger initLogger(final Global global) {
+        return global.getLogger(this.getClass());
     }
 
     @Override
@@ -80,7 +96,7 @@
         //properly identified and that no optimizations can be made with it - its range is
         //simply unknown in that case, if it is assigned in the loop
         final Symbol counter = findLoopCounter(forNode);
-        LOG.fine("Entering forNode " + forNode + " counter = " + counter);
+        log.fine("Entering forNode " + forNode + " counter = " + counter);
         if (counter != null && !assignedInLoop(forNode,  counter)) {
             loopCounters.put(forNode, counter);
         }
@@ -96,7 +112,7 @@
         final Symbol symbol = dest.getSymbol();
         assert symbol != null : dest + " " + dest.getClass() + " has no symbol";
         assert symbol.getRange() != null : symbol + " has no range";
-        final Range symRange = RANGE.join(symbol.getRange(), range);
+        final Range symRange = func.join(symbol.getRange(), range);
 
         //anything assigned in the loop, not being the safe loop counter(s) invalidates its entire range
         if (lc.inLoop() && !isLoopCounter(lc.getCurrentLoop(), symbol)) {
@@ -105,7 +121,7 @@
         }
 
         if (!symRange.equals(symbol.getRange())) {
-            LOG.fine("Modify range for " + dest + " " + symbol + " from " + symbol.getRange() + " to " + symRange + " (in node = " + dest + ")" );
+            log.fine("Modify range for " + dest + " " + symbol + " from " + symbol.getRange() + " to " + symRange + " (in node = " + dest + ")" );
             symbol.setRange(symRange);
         }
 
@@ -114,67 +130,67 @@
 
     @Override
     public Node leaveADD(final BinaryNode node) {
-        setRange(node, RANGE.add(node.lhs().getSymbol().getRange(), node.rhs().getSymbol().getRange()));
+        setRange(node, func.add(node.lhs().getSymbol().getRange(), node.rhs().getSymbol().getRange()));
         return node;
     }
 
     @Override
     public Node leaveSUB(final BinaryNode node) {
-        setRange(node, RANGE.sub(node.lhs().getSymbol().getRange(), node.rhs().getSymbol().getRange()));
+        setRange(node, func.sub(node.lhs().getSymbol().getRange(), node.rhs().getSymbol().getRange()));
         return node;
     }
 
     @Override
     public Node leaveMUL(final BinaryNode node) {
-        setRange(node, RANGE.mul(node.lhs().getSymbol().getRange(), node.rhs().getSymbol().getRange()));
+        setRange(node, func.mul(node.lhs().getSymbol().getRange(), node.rhs().getSymbol().getRange()));
         return node;
     }
 
     @Override
     public Node leaveDIV(final BinaryNode node) {
-        setRange(node, RANGE.div(node.lhs().getSymbol().getRange(), node.rhs().getSymbol().getRange()));
+        setRange(node, func.div(node.lhs().getSymbol().getRange(), node.rhs().getSymbol().getRange()));
         return node;
     }
 
     @Override
     public Node leaveMOD(final BinaryNode node) {
-        setRange(node, RANGE.mod(node.lhs().getSymbol().getRange(), node.rhs().getSymbol().getRange()));
+        setRange(node, func.mod(node.lhs().getSymbol().getRange(), node.rhs().getSymbol().getRange()));
         return node;
     }
 
     @Override
     public Node leaveBIT_AND(final BinaryNode node) {
-        setRange(node, RANGE.and(node.lhs().getSymbol().getRange(), node.rhs().getSymbol().getRange()));
+        setRange(node, func.and(node.lhs().getSymbol().getRange(), node.rhs().getSymbol().getRange()));
         return node;
     }
 
     @Override
     public Node leaveBIT_OR(final BinaryNode node) {
-        setRange(node, RANGE.or(node.lhs().getSymbol().getRange(), node.rhs().getSymbol().getRange()));
+        setRange(node, func.or(node.lhs().getSymbol().getRange(), node.rhs().getSymbol().getRange()));
         return node;
     }
 
     @Override
     public Node leaveBIT_XOR(final BinaryNode node) {
-        setRange(node, RANGE.xor(node.lhs().getSymbol().getRange(), node.rhs().getSymbol().getRange()));
+        setRange(node, func.xor(node.lhs().getSymbol().getRange(), node.rhs().getSymbol().getRange()));
         return node;
     }
 
     @Override
     public Node leaveSAR(final BinaryNode node) {
-        setRange(node, RANGE.sar(node.lhs().getSymbol().getRange(), node.rhs().getSymbol().getRange()));
+        setRange(node, func.sar(node.lhs().getSymbol().getRange(), node.rhs().getSymbol().getRange()));
         return node;
     }
 
     @Override
     public Node leaveSHL(final BinaryNode node) {
-        setRange(node, RANGE.shl(node.lhs().getSymbol().getRange(), node.rhs().getSymbol().getRange()));
+        setRange(node, func.shl(node.lhs().getSymbol().getRange(), node.rhs().getSymbol().getRange()));
         return node;
     }
 
     @Override
     public Node leaveSHR(final BinaryNode node) {
-        setRange(node, RANGE.shr(node.lhs().getSymbol().getRange(), node.rhs().getSymbol().getRange()));
+        setRange(node, func.shr(node.lhs().getSymbol().getRange(), node.rhs().getSymbol().getRange()));
         return node;
     }
 
@@ -250,17 +266,17 @@
 
     @Override
     public Node leaveASSIGN_ADD(final BinaryNode node) {
-        return leaveSelfModifyingAssign(node, RANGE.add(node.lhs().getSymbol().getRange(), node.rhs().getSymbol().getRange()));
+        return leaveSelfModifyingAssign(node, func.add(node.lhs().getSymbol().getRange(), node.rhs().getSymbol().getRange()));
     }
 
     @Override
     public Node leaveASSIGN_SUB(final BinaryNode node) {
-        return leaveSelfModifyingAssign(node, RANGE.sub(node.lhs().getSymbol().getRange(), node.rhs().getSymbol().getRange()));
+        return leaveSelfModifyingAssign(node, func.sub(node.lhs().getSymbol().getRange(), node.rhs().getSymbol().getRange()));
     }
 
     @Override
     public Node leaveASSIGN_MUL(final BinaryNode node) {
-        return leaveSelfModifyingAssign(node, RANGE.mul(node.lhs().getSymbol().getRange(), node.rhs().getSymbol().getRange()));
+        return leaveSelfModifyingAssign(node, func.mul(node.lhs().getSymbol().getRange(), node.rhs().getSymbol().getRange()));
     }
 
     @Override
@@ -275,32 +291,32 @@
 
     @Override
     public Node leaveASSIGN_BIT_AND(final BinaryNode node) {
-        return leaveSelfModifyingAssign(node, RANGE.and(node.lhs().getSymbol().getRange(), node.rhs().getSymbol().getRange()));
+        return leaveSelfModifyingAssign(node, func.and(node.lhs().getSymbol().getRange(), node.rhs().getSymbol().getRange()));
     }
 
     @Override
     public Node leaveASSIGN_BIT_OR(final BinaryNode node) {
-        return leaveSelfModifyingAssign(node, RANGE.or(node.lhs().getSymbol().getRange(), node.rhs().getSymbol().getRange()));
+        return leaveSelfModifyingAssign(node, func.or(node.lhs().getSymbol().getRange(), node.rhs().getSymbol().getRange()));
     }
 
     @Override
     public Node leaveASSIGN_BIT_XOR(final BinaryNode node) {
-        return leaveSelfModifyingAssign(node, RANGE.xor(node.lhs().getSymbol().getRange(), node.rhs().getSymbol().getRange()));
+        return leaveSelfModifyingAssign(node, func.xor(node.lhs().getSymbol().getRange(), node.rhs().getSymbol().getRange()));
     }
 
     @Override
     public Node leaveASSIGN_SAR(final BinaryNode node) {
-        return leaveSelfModifyingAssign(node, RANGE.sar(node.lhs().getSymbol().getRange(), node.rhs().getSymbol().getRange()));
+        return leaveSelfModifyingAssign(node, func.sar(node.lhs().getSymbol().getRange(), node.rhs().getSymbol().getRange()));
     }
 
     @Override
     public Node leaveASSIGN_SHR(final BinaryNode node) {
-        return leaveSelfModifyingAssign(node, RANGE.shr(node.lhs().getSymbol().getRange(), node.rhs().getSymbol().getRange()));
+        return leaveSelfModifyingAssign(node, func.shr(node.lhs().getSymbol().getRange(), node.rhs().getSymbol().getRange()));
     }
 
     @Override
     public Node leaveASSIGN_SHL(final BinaryNode node) {
-        return leaveSelfModifyingAssign(node, RANGE.shl(node.lhs().getSymbol().getRange(), node.rhs().getSymbol().getRange()));
+        return leaveSelfModifyingAssign(node, func.shl(node.lhs().getSymbol().getRange(), node.rhs().getSymbol().getRange()));
     }
 
     @Override
@@ -308,10 +324,10 @@
         switch (node.tokenType()) {
         case DECPREFIX:
         case DECPOSTFIX:
-            return leaveSelfModifyingAssign(node, RANGE.sub(node.getExpression().getSymbol().getRange(), Range.createRange(1)));
+            return leaveSelfModifyingAssign(node, func.sub(node.getExpression().getSymbol().getRange(), Range.createRange(1)));
         case INCPREFIX:
         case INCPOSTFIX:
-            return leaveSelfModifyingAssign(node, RANGE.add(node.getExpression().getSymbol().getRange(), Range.createRange(1)));
+            return leaveSelfModifyingAssign(node, func.add(node.getExpression().getSymbol().getRange(), Range.createRange(1)));
         default:
             throw new UnsupportedOperationException("" + node.tokenType());
         }
@@ -341,7 +357,7 @@
 
     @Override
     public Node leaveSUB(final UnaryNode node) {
-        setRange(node, RANGE.neg(node.getExpression().getSymbol().getRange()));
+        setRange(node, func.neg(node.getExpression().getSymbol().getRange()));
         return node;
     }
 
@@ -436,7 +452,7 @@
      * @param node loop node to check
      * @return
      */
-    private static Symbol findLoopCounter(final LoopNode node) {
+    private Symbol findLoopCounter(final LoopNode node) {
         final Expression test = node.getTest();
 
         if (test != null && test.isComparison()) {
@@ -453,7 +469,7 @@
                 switch (op) {
                 case LT:
                 case LE:
-                    symbol.setRange(RANGE.join(symbol.getRange(), Range.createRange(op == TokenType.LT ? margin - 1 : margin)));
+                    symbol.setRange(func.join(symbol.getRange(), Range.createRange(op == TokenType.LT ? margin - 1 : margin)));
                     return symbol;
                 case GT:
                 case GE:
--- a/nashorn/src/jdk/nashorn/internal/codegen/Splitter.java	Tue Apr 22 14:09:46 2014 +0200
+++ b/nashorn/src/jdk/nashorn/internal/codegen/Splitter.java	Wed Apr 23 16:13:47 2014 +0200
@@ -26,12 +26,12 @@
 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;
 import java.util.List;
 import java.util.Map;
+
 import jdk.nashorn.internal.ir.Block;
 import jdk.nashorn.internal.ir.FunctionNode;
 import jdk.nashorn.internal.ir.FunctionNode.CompilationState;
@@ -43,6 +43,7 @@
 import jdk.nashorn.internal.ir.SplitNode;
 import jdk.nashorn.internal.ir.Statement;
 import jdk.nashorn.internal.ir.visitor.NodeVisitor;
+import jdk.nashorn.internal.runtime.logging.DebugLogger;
 import jdk.nashorn.internal.runtime.options.Options;
 
 /**
@@ -64,6 +65,8 @@
     /** Weight threshold for when to start a split. */
     public static final long SPLIT_THRESHOLD = Options.getIntProperty("nashorn.compiler.splitter.threshold", 32 * 1024);
 
+    private final DebugLogger log;
+
     /**
      * Constructor.
      *
@@ -76,6 +79,7 @@
         this.compiler             = compiler;
         this.outermost            = functionNode;
         this.outermostCompileUnit = outermostCompileUnit;
+        this.log                  = compiler.getLogger();
     }
 
     /**
@@ -86,7 +90,7 @@
     FunctionNode split(final FunctionNode fn, final boolean top) {
         FunctionNode functionNode = fn;
 
-        finest("Initiating split of '", functionNode.getName(), "'");
+        log.finest("Initiating split of '", functionNode.getName(), "'");
 
         long weight = WeighNodes.weigh(functionNode);
 
@@ -95,7 +99,7 @@
         assert lc.isEmpty() : "LexicalContext not empty";
 
         if (weight >= SPLIT_THRESHOLD) {
-            finest("Splitting '", functionNode.getName(), "' as its weight ", weight, " exceeds split threshold ", SPLIT_THRESHOLD);
+            log.finest("Splitting '", functionNode.getName(), "' as its weight ", weight, " exceeds split threshold ", SPLIT_THRESHOLD);
             functionNode = (FunctionNode)functionNode.accept(this);
 
             if (functionNode.isSplit()) {
--- a/nashorn/src/jdk/nashorn/internal/codegen/types/Range.java	Tue Apr 22 14:09:46 2014 +0200
+++ b/nashorn/src/jdk/nashorn/internal/codegen/types/Range.java	Wed Apr 23 16:13:47 2014 +0200
@@ -29,7 +29,7 @@
 import java.util.Collections;
 import java.util.List;
 
-import jdk.nashorn.internal.runtime.DebugLogger;
+import jdk.nashorn.internal.runtime.logging.DebugLogger;
 import jdk.nashorn.internal.runtime.JSType;
 
 /**
@@ -544,8 +544,8 @@
                 final long         shift = ((IntegerRange) b).getMin() & 0x1f;
                 final IntegerRange left  = (IntegerRange)(a.isIntegerType() ? a : createTypeRange(Type.INT));
                 if (left.getMin() >= 0) {
-                    long min = left.getMin() >>> shift;
-                    long max = left.getMax() >>> shift;
+                    final long min = left.getMin() >>> shift;
+                    final long max = left.getMax() >>> shift;
                     return createIntegerRange(min, max);
                 } else if (shift >= 1) {
                     return createIntegerRange(0, JSType.MAX_UINT >>> shift);
--- a/nashorn/src/jdk/nashorn/internal/ir/IdentNode.java	Tue Apr 22 14:09:46 2014 +0200
+++ b/nashorn/src/jdk/nashorn/internal/ir/IdentNode.java	Wed Apr 23 16:13:47 2014 +0200
@@ -28,9 +28,6 @@
 import static jdk.nashorn.internal.codegen.CompilerConstants.__DIR__;
 import static jdk.nashorn.internal.codegen.CompilerConstants.__FILE__;
 import static jdk.nashorn.internal.codegen.CompilerConstants.__LINE__;
-import static jdk.nashorn.internal.codegen.ObjectClassGenerator.DEBUG_FIELDS;
-
-import jdk.nashorn.internal.codegen.ObjectClassGenerator;
 import jdk.nashorn.internal.codegen.types.Type;
 import jdk.nashorn.internal.ir.annotations.Immutable;
 import jdk.nashorn.internal.ir.visitor.NodeVisitor;
@@ -219,9 +216,6 @@
         if (this.optimisticType == callSiteType) {
             return this;
         }
-        if (DEBUG_FIELDS && ObjectClassGenerator.shouldInstrument(getName()) && getSymbol() != null && !Type.areEquivalent(getSymbol().getSymbolType(), callSiteType)) {
-            ObjectClassGenerator.getLogger().info(getClass().getName(), " ", this, " => ", callSiteType, " instead of ", getType());
-        }
         return new IdentNode(this, name, callSiteType, flags, programPoint);
     }
 
--- a/nashorn/src/jdk/nashorn/internal/lookup/MethodHandleFactory.java	Tue Apr 22 14:09:46 2014 +0200
+++ b/nashorn/src/jdk/nashorn/internal/lookup/MethodHandleFactory.java	Wed Apr 23 16:13:47 2014 +0200
@@ -37,9 +37,12 @@
 import java.util.List;
 import java.util.logging.Level;
 
+import jdk.nashorn.internal.objects.Global;
 import jdk.nashorn.internal.runtime.ConsString;
 import jdk.nashorn.internal.runtime.Debug;
-import jdk.nashorn.internal.runtime.DebugLogger;
+import jdk.nashorn.internal.runtime.logging.DebugLogger;
+import jdk.nashorn.internal.runtime.logging.Loggable;
+import jdk.nashorn.internal.runtime.logging.Logger;
 import jdk.nashorn.internal.runtime.ScriptObject;
 import jdk.nashorn.internal.runtime.options.Options;
 
@@ -97,38 +100,20 @@
         return obj.toString();
     }
 
-    private static final MethodHandleFunctionality STANDARD = new StandardMethodHandleFunctionality();
-    private static final MethodHandleFunctionality FUNC;
-
-    private static final String DEBUG_PROPERTY = "nashorn.methodhandles.debug";
-    private static final DebugLogger LOG = new DebugLogger("methodhandles", DEBUG_PROPERTY);
-
-    static {
-        if (LOG.isEnabled() || Options.getBooleanProperty(DEBUG_PROPERTY)) {
-            if (Options.getStringProperty(DEBUG_PROPERTY, "").equals("create")) {
-                FUNC = new TraceCreateMethodHandleFunctionality();
-            } else {
-                FUNC = new TraceMethodHandleFunctionality();
-            }
-        } else {
-            FUNC  = STANDARD;
-        }
-    }
-
+    private static final MethodHandleFunctionality FUNC = new StandardMethodHandleFunctionality();
     private static final boolean PRINT_STACKTRACE = Options.getBooleanProperty("nashorn.methodhandles.debug.stacktrace");
 
-
     /**
      * Return the method handle functionality used for all method handle operations
      * @return a method handle functionality implementation
      */
-    public static MethodHandleFunctionality getFunctionality() {
+    public static synchronized MethodHandleFunctionality getFunctionality() {
         return FUNC;
     }
 
-    private static final MethodHandle TRACE             = STANDARD.findStatic(LOOKUP, MethodHandleFactory.class, "traceArgs",   MethodType.methodType(void.class, DebugLogger.class, String.class, int.class, Object[].class));
-    private static final MethodHandle TRACE_RETURN      = STANDARD.findStatic(LOOKUP, MethodHandleFactory.class, "traceReturn", MethodType.methodType(Object.class, DebugLogger.class, Object.class));
-    private static final MethodHandle TRACE_RETURN_VOID = STANDARD.findStatic(LOOKUP, MethodHandleFactory.class, "traceReturnVoid", MethodType.methodType(void.class, DebugLogger.class));
+    private static final MethodHandle TRACE             = FUNC.findStatic(LOOKUP, MethodHandleFactory.class, "traceArgs",   MethodType.methodType(void.class, DebugLogger.class, String.class, int.class, Object[].class));
+    private static final MethodHandle TRACE_RETURN      = FUNC.findStatic(LOOKUP, MethodHandleFactory.class, "traceReturn", MethodType.methodType(Object.class, DebugLogger.class, Object.class));
+    private static final MethodHandle TRACE_RETURN_VOID = FUNC.findStatic(LOOKUP, MethodHandleFactory.class, "traceReturnVoid", MethodType.methodType(void.class, DebugLogger.class));
 
     private static final String VOID_TAG = "[VOID]";
 
@@ -234,7 +219,6 @@
         return addDebugPrintout(logger, level, mh, 0, true, tag);
     }
 
-
     /**
      * Add a debug printout to a method handle, tracing parameters and return values
      *
@@ -283,194 +267,34 @@
     }
 
     /**
-     * The standard class that marshalls all method handle operations to the java.lang.invoke
+     * Class that marshalls all method handle operations to the java.lang.invoke
      * package. This exists only so that it can be subclassed and method handles created from
      * Nashorn made possible to instrument.
      *
      * All Nashorn classes should use the MethodHandleFactory for their method handle operations
      */
-    private static class StandardMethodHandleFunctionality implements MethodHandleFunctionality {
-
-        @Override
-        public MethodHandle filterArguments(final MethodHandle target, final int pos, final MethodHandle... filters) {
-            return MethodHandles.filterArguments(target, pos, filters);
-        }
-
-        @Override
-        public MethodHandle filterReturnValue(final MethodHandle target, final MethodHandle filter) {
-            return MethodHandles.filterReturnValue(target, filter);
-        }
-
-        @Override
-        public MethodHandle guardWithTest(final MethodHandle test, final MethodHandle target, final MethodHandle fallback) {
-            return MethodHandles.guardWithTest(test, target, fallback);
-        }
-
-        @Override
-        public MethodHandle insertArguments(final MethodHandle target, final int pos, final Object... values) {
-            return MethodHandles.insertArguments(target, pos, values);
-        }
-
-        @Override
-        public MethodHandle dropArguments(final MethodHandle target, final int pos, final Class<?>... valueTypes) {
-            return MethodHandles.dropArguments(target, pos, valueTypes);
-        }
-
-        @Override
-        public MethodHandle dropArguments(final MethodHandle target, final int pos, final List<Class<?>> valueTypes) {
-            return MethodHandles.dropArguments(target, pos, valueTypes);
-        }
-
-        @Override
-        public MethodHandle asType(final MethodHandle handle, final MethodType type) {
-            return handle.asType(type);
-        }
-
-        @Override
-        public MethodHandle bindTo(final MethodHandle handle, final Object x) {
-            return handle.bindTo(x);
-        }
+    @Logger(name="methodhandles")
+    private static class StandardMethodHandleFunctionality implements MethodHandleFunctionality, Loggable {
 
-        @Override
-        public MethodHandle foldArguments(final MethodHandle target, final MethodHandle combiner) {
-            return MethodHandles.foldArguments(target, combiner);
-        }
-
-        @Override
-        public MethodHandle explicitCastArguments(final MethodHandle target, final MethodType type) {
-            return MethodHandles.explicitCastArguments(target, type);
-        }
-
-        @Override
-        public MethodHandle arrayElementGetter(final Class<?> type) {
-            return MethodHandles.arrayElementGetter(type);
-        }
-
-        @Override
-        public MethodHandle arrayElementSetter(final Class<?> type) {
-            return MethodHandles.arrayElementSetter(type);
-        }
+        // for bootstrapping reasons, because a lot of static fields use MH for lookups, we
+        // need to set the logger when the Global object is finished. This means that we don't
+        // get instrumentation for public static final MethodHandle SOMETHING = MH... in the builtin
+        // classes, but that doesn't matter, because this is usually not where we want it
+        private DebugLogger log = DebugLogger.DISABLED_LOGGER;
 
-        @Override
-        public MethodHandle throwException(final Class<?> returnType, final Class<? extends Throwable> exType) {
-            return MethodHandles.throwException(returnType, exType);
-        }
-
-        @Override
-        public MethodHandle catchException(final MethodHandle target, final Class<? extends Throwable> exType, final MethodHandle handler) {
-            return MethodHandles.catchException(target, exType, handler);
-        }
-
-        @Override
-        public MethodHandle constant(final Class<?> type, final Object value) {
-            return MethodHandles.constant(type, value);
-        }
-
-        @Override
-        public MethodHandle asCollector(final MethodHandle handle, final Class<?> arrayType, final int arrayLength) {
-            return handle.asCollector(arrayType, arrayLength);
-        }
-
-        @Override
-        public MethodHandle asSpreader(final MethodHandle handle, final Class<?> arrayType, final int arrayLength) {
-            return handle.asSpreader(arrayType, arrayLength);
+        public StandardMethodHandleFunctionality() {
         }
 
         @Override
-        public MethodHandle getter(final MethodHandles.Lookup explicitLookup, final Class<?> clazz, final String name, final Class<?> type) {
-            try {
-                return explicitLookup.findGetter(clazz, name, type);
-            } catch (final NoSuchFieldException | IllegalAccessException e) {
-                throw new LookupException(e);
-            }
-        }
-
-        @Override
-        public MethodHandle staticGetter(final MethodHandles.Lookup explicitLookup, final Class<?> clazz, final String name, final Class<?> type) {
-            try {
-                return explicitLookup.findStaticGetter(clazz, name, type);
-            } catch (final NoSuchFieldException | IllegalAccessException e) {
-                throw new LookupException(e);
-            }
-        }
-
-
-        @Override
-        public MethodHandle setter(final MethodHandles.Lookup explicitLookup, final Class<?> clazz, final String name, final Class<?> type) {
-            try {
-                return explicitLookup.findSetter(clazz, name, type);
-            } catch (final NoSuchFieldException | IllegalAccessException e) {
-                throw new LookupException(e);
-            }
-        }
-
-        @Override
-        public MethodHandle staticSetter(final MethodHandles.Lookup explicitLookup, final Class<?> clazz, final String name, final Class<?> type) {
-            try {
-                return explicitLookup.findStaticSetter(clazz, name, type);
-            } catch (final NoSuchFieldException | IllegalAccessException e) {
-                throw new LookupException(e);
-            }
-        }
-
-        @Override
-        public MethodHandle find(final Method method) {
-            try {
-                return PUBLIC_LOOKUP.unreflect(method);
-            } catch (final IllegalAccessException e) {
-                throw new LookupException(e);
-            }
+        public DebugLogger initLogger(final Global global) {
+            return this.log = global.getLogger(this.getClass());
         }
 
         @Override
-        public MethodHandle findStatic(final MethodHandles.Lookup explicitLookup, final Class<?> clazz, final String name, final MethodType type) {
-            try {
-                return explicitLookup.findStatic(clazz, name, type);
-            } catch (final NoSuchMethodException | IllegalAccessException e) {
-                throw new LookupException(e);
-            }
-        }
-
-        @Override
-        public MethodHandle findSpecial(final MethodHandles.Lookup explicitLookup, final Class<?> clazz, final String name, final MethodType type, final Class<?> thisClass) {
-            try {
-                return explicitLookup.findSpecial(clazz, name, type, thisClass);
-            } catch (final NoSuchMethodException | IllegalAccessException e) {
-                throw new LookupException(e);
-            }
+        public DebugLogger getLogger() {
+            return log;
         }
 
-        @Override
-        public MethodHandle findVirtual(final MethodHandles.Lookup explicitLookup, final Class<?> clazz, final String name, final MethodType type) {
-            try {
-                return explicitLookup.findVirtual(clazz, name, type);
-            } catch (final NoSuchMethodException | IllegalAccessException e) {
-                throw new LookupException(e);
-            }
-        }
-
-        @Override
-        public SwitchPoint createSwitchPoint() {
-            return new SwitchPoint();
-        }
-
-        @Override
-        public MethodHandle guardWithTest(final SwitchPoint sp, final MethodHandle before, final MethodHandle after) {
-            return sp.guardWithTest(before, after);
-        }
-
-        @Override
-        public MethodType type(final Class<?> returnType, final Class<?>... paramTypes) {
-            return MethodType.methodType(returnType, paramTypes);
-        }
-
-    }
-
-    /**
-     * Class used for instrumenting and debugging Nashorn generated method handles
-     */
-    private static class TraceMethodHandleFunctionality extends StandardMethodHandleFunctionality {
-
         protected static String describe(final Object... data) {
             final StringBuilder sb = new StringBuilder();
 
@@ -503,183 +327,215 @@
         }
 
         public MethodHandle debug(final MethodHandle master, final String str, final Object... args) {
-            return addDebugPrintout(LOG, Level.INFO, master, Integer.MAX_VALUE, false, str + ' ' + describe(args));
+            if (log.isEnabled()) {
+                if (PRINT_STACKTRACE) {
+                    stacktrace(log);
+                }
+                return addDebugPrintout(log, Level.INFO, master, Integer.MAX_VALUE, false, str + ' ' + describe(args));
+            }
+            return master;
         }
 
         @Override
         public MethodHandle filterArguments(final MethodHandle target, final int pos, final MethodHandle... filters) {
-            final MethodHandle mh = super.filterArguments(target, pos, filters);
+            final MethodHandle mh = MethodHandles.filterArguments(target, pos, filters);
             return debug(mh, "filterArguments", target, pos, filters);
         }
 
         @Override
         public MethodHandle filterReturnValue(final MethodHandle target, final MethodHandle filter) {
-            final MethodHandle mh = super.filterReturnValue(target, filter);
+            final MethodHandle mh = MethodHandles.filterReturnValue(target, filter);
             return debug(mh, "filterReturnValue", target, filter);
         }
 
         @Override
         public MethodHandle guardWithTest(final MethodHandle test, final MethodHandle target, final MethodHandle fallback) {
-            final MethodHandle mh = super.guardWithTest(test, target, fallback);
+            final MethodHandle mh = MethodHandles.guardWithTest(test, target, fallback);
             return debug(mh, "guardWithTest", test, target, fallback);
         }
 
         @Override
         public MethodHandle insertArguments(final MethodHandle target, final int pos, final Object... values) {
-            final MethodHandle mh = super.insertArguments(target, pos, values);
+            final MethodHandle mh = MethodHandles.insertArguments(target, pos, values);
             return debug(mh, "insertArguments", target, pos, values);
         }
 
         @Override
         public MethodHandle dropArguments(final MethodHandle target, final int pos, final Class<?>... values) {
-            final MethodHandle mh = super.dropArguments(target, pos, values);
+            final MethodHandle mh = MethodHandles.dropArguments(target, pos, values);
             return debug(mh, "dropArguments", target, pos, values);
         }
 
         @Override
         public MethodHandle dropArguments(final MethodHandle target, final int pos, final List<Class<?>> values) {
-            final MethodHandle mh = super.dropArguments(target, pos, values);
+            final MethodHandle mh = MethodHandles.dropArguments(target, pos, values);
             return debug(mh, "dropArguments", target, pos, values);
         }
 
         @Override
         public MethodHandle asType(final MethodHandle handle, final MethodType type) {
-            final MethodHandle mh = super.asType(handle, type);
+            final MethodHandle mh = handle.asType(type);
             return debug(mh, "asType", handle, type);
         }
 
         @Override
         public MethodHandle bindTo(final MethodHandle handle, final Object x) {
-            final MethodHandle mh = super.bindTo(handle, x);
+            final MethodHandle mh = handle.bindTo(x);
             return debug(mh, "bindTo", handle, x);
         }
 
         @Override
         public MethodHandle foldArguments(final MethodHandle target, final MethodHandle combiner) {
-            final MethodHandle mh = super.foldArguments(target, combiner);
+            final MethodHandle mh = MethodHandles.foldArguments(target, combiner);
             return debug(mh, "foldArguments", target, combiner);
         }
 
         @Override
         public MethodHandle explicitCastArguments(final MethodHandle target, final MethodType type) {
-            final MethodHandle mh = super.explicitCastArguments(target, type);
+            final MethodHandle mh = MethodHandles.explicitCastArguments(target, type);
             return debug(mh, "explicitCastArguments", target, type);
         }
 
         @Override
         public MethodHandle arrayElementGetter(final Class<?> type) {
-            final MethodHandle mh = super.arrayElementGetter(type);
+            final MethodHandle mh = MethodHandles.arrayElementGetter(type);
             return debug(mh, "arrayElementGetter", type);
         }
 
         @Override
         public MethodHandle arrayElementSetter(final Class<?> type) {
-            final MethodHandle mh = super.arrayElementSetter(type);
+            final MethodHandle mh = MethodHandles.arrayElementSetter(type);
             return debug(mh, "arrayElementSetter", type);
         }
 
         @Override
         public MethodHandle throwException(final Class<?> returnType, final Class<? extends Throwable> exType) {
-            final MethodHandle mh = super.throwException(returnType, exType);
+            final MethodHandle mh = MethodHandles.throwException(returnType, exType);
             return debug(mh, "throwException", returnType, exType);
         }
 
         @Override
         public MethodHandle catchException(final MethodHandle target, final Class<? extends Throwable> exType, final MethodHandle handler) {
-            final MethodHandle mh = super.catchException(target, exType, handler);
+            final MethodHandle mh = MethodHandles.catchException(target, exType, handler);
             return debug(mh, "catchException", exType);
         }
 
         @Override
         public MethodHandle constant(final Class<?> type, final Object value) {
-            final MethodHandle mh = super.constant(type, value);
+            final MethodHandle mh = MethodHandles.constant(type, value);
             return debug(mh, "constant", type, value);
         }
 
         @Override
         public MethodHandle asCollector(final MethodHandle handle, final Class<?> arrayType, final int arrayLength) {
-            final MethodHandle mh = super.asCollector(handle, arrayType, arrayLength);
+            final MethodHandle mh = handle.asCollector(arrayType, arrayLength);
             return debug(mh, "asCollector", handle, arrayType, arrayLength);
         }
 
         @Override
         public MethodHandle asSpreader(final MethodHandle handle, final Class<?> arrayType, final int arrayLength) {
-            final MethodHandle mh = super.asSpreader(handle, arrayType, arrayLength);
+            final MethodHandle mh = handle.asSpreader(arrayType, arrayLength);
             return debug(mh, "asSpreader", handle, arrayType, arrayLength);
         }
 
         @Override
         public MethodHandle getter(final MethodHandles.Lookup explicitLookup, final Class<?> clazz, final String name, final Class<?> type) {
-            final MethodHandle mh = super.getter(explicitLookup, clazz, name, type);
-            return debug(mh, "getter", explicitLookup, clazz, name, type);
+            try {
+                final MethodHandle mh = explicitLookup.findGetter(clazz, name, type);
+                return debug(mh, "getter", explicitLookup, clazz, name, type);
+            } catch (final NoSuchFieldException | IllegalAccessException e) {
+                throw new LookupException(e);
+            }
         }
 
         @Override
         public MethodHandle staticGetter(final MethodHandles.Lookup explicitLookup, final Class<?> clazz, final String name, final Class<?> type) {
-            final MethodHandle mh = super.staticGetter(explicitLookup, clazz, name, type);
-            return debug(mh, "static getter", explicitLookup, clazz, name, type);
+            try {
+                final MethodHandle mh = explicitLookup.findStaticGetter(clazz, name, type);
+                return debug(mh, "static getter", explicitLookup, clazz, name, type);
+            } catch (final NoSuchFieldException | IllegalAccessException e) {
+                throw new LookupException(e);
+            }
         }
 
         @Override
         public MethodHandle setter(final MethodHandles.Lookup explicitLookup, final Class<?> clazz, final String name, final Class<?> type) {
-            final MethodHandle mh = super.setter(explicitLookup, clazz, name, type);
-            return debug(mh, "setter", explicitLookup, clazz, name, type);
+            try {
+                final MethodHandle mh = explicitLookup.findSetter(clazz, name, type);
+                return debug(mh, "setter", explicitLookup, clazz, name, type);
+            } catch (final NoSuchFieldException | IllegalAccessException e) {
+                throw new LookupException(e);
+            }
         }
 
         @Override
         public MethodHandle staticSetter(final MethodHandles.Lookup explicitLookup, final Class<?> clazz, final String name, final Class<?> type) {
-            final MethodHandle mh = super.staticSetter(explicitLookup, clazz, name, type);
-            return debug(mh, "static setter", explicitLookup, clazz, name, type);
+            try {
+                final MethodHandle mh = explicitLookup.findStaticSetter(clazz, name, type);
+                return debug(mh, "static setter", explicitLookup, clazz, name, type);
+            } catch (final NoSuchFieldException | IllegalAccessException e) {
+                throw new LookupException(e);
+            }
         }
 
         @Override
         public MethodHandle find(final Method method) {
-            final MethodHandle mh = super.find(method);
-            return debug(mh, "find", method);
+            try {
+                final MethodHandle mh = PUBLIC_LOOKUP.unreflect(method);
+                return debug(mh, "find", method);
+            } catch (final IllegalAccessException e) {
+                throw new LookupException(e);
+            }
         }
 
         @Override
         public MethodHandle findStatic(final MethodHandles.Lookup explicitLookup, final Class<?> clazz, final String name, final MethodType type) {
-            final MethodHandle mh = super.findStatic(explicitLookup, clazz, name, type);
-            return debug(mh, "findStatic", explicitLookup, clazz, name, type);
+            try {
+                final MethodHandle mh = explicitLookup.findStatic(clazz, name, type);
+                return debug(mh, "findStatic", explicitLookup, clazz, name, type);
+            } catch (final NoSuchMethodException | IllegalAccessException e) {
+                throw new LookupException(e);
+            }
+        }
+
+        @Override
+        public MethodHandle findSpecial(final MethodHandles.Lookup explicitLookup, final Class<?> clazz, final String name, final MethodType type, final Class<?> thisClass) {
+            try {
+                final MethodHandle mh = explicitLookup.findSpecial(clazz, name, type, thisClass);
+                return debug(mh, "findSpecial", explicitLookup, clazz, name, type);
+            } catch (final NoSuchMethodException | IllegalAccessException e) {
+                throw new LookupException(e);
+            }
         }
 
         @Override
         public MethodHandle findVirtual(final MethodHandles.Lookup explicitLookup, final Class<?> clazz, final String name, final MethodType type) {
-            final MethodHandle mh = super.findVirtual(explicitLookup, clazz, name, type);
-            return debug(mh, "findVirtual", explicitLookup, clazz, name, type);
+            try {
+                final MethodHandle mh = explicitLookup.findVirtual(clazz, name, type);
+                return debug(mh, "findVirtual", explicitLookup, clazz, name, type);
+            } catch (final NoSuchMethodException | IllegalAccessException e) {
+                throw new LookupException(e);
+            }
         }
 
         @Override
         public SwitchPoint createSwitchPoint() {
-            final SwitchPoint sp = super.createSwitchPoint();
-            LOG.log(TRACE_LEVEL, "createSwitchPoint ", sp);
+            final SwitchPoint sp = new SwitchPoint();
+            log.log(TRACE_LEVEL, "createSwitchPoint ", sp);
             return sp;
         }
 
         @Override
         public MethodHandle guardWithTest(final SwitchPoint sp, final MethodHandle before, final MethodHandle after) {
-            final MethodHandle mh = super.guardWithTest(sp, before, after);
+            final MethodHandle mh = sp.guardWithTest(before, after);
             return debug(mh, "guardWithTest", sp, before, after);
         }
 
         @Override
         public MethodType type(final Class<?> returnType, final Class<?>... paramTypes) {
-            final MethodType mt = super.type(returnType, paramTypes);
-            LOG.log(TRACE_LEVEL, "methodType ", returnType, " ", Arrays.toString(paramTypes), " ", mt);
+            final MethodType mt = MethodType.methodType(returnType, paramTypes);
+            log.log(TRACE_LEVEL, "methodType ", returnType, " ", Arrays.toString(paramTypes), " ", mt);
             return mt;
         }
     }
-
-    /**
-     * Class used for debugging Nashorn generated method handles
-     */
-    private static class TraceCreateMethodHandleFunctionality extends TraceMethodHandleFunctionality {
-        @Override
-        public MethodHandle debug(final MethodHandle master, final String str, final Object... args) {
-            LOG.log(TRACE_LEVEL, str, " ", describe(args));
-            stacktrace(LOG);
-            return master;
-        }
-    }
 }
--- a/nashorn/src/jdk/nashorn/internal/lookup/MethodHandleFunctionality.java	Tue Apr 22 14:09:46 2014 +0200
+++ b/nashorn/src/jdk/nashorn/internal/lookup/MethodHandleFunctionality.java	Wed Apr 23 16:13:47 2014 +0200
@@ -337,5 +337,6 @@
      * @return the method type
      */
     public MethodType type(Class<?> returnType, Class<?>... paramTypes);
+
 }
 
--- a/nashorn/src/jdk/nashorn/internal/objects/Global.java	Tue Apr 22 14:09:46 2014 +0200
+++ b/nashorn/src/jdk/nashorn/internal/objects/Global.java	Wed Apr 23 16:13:47 2014 +0200
@@ -44,12 +44,15 @@
 import java.util.Map;
 import java.util.concurrent.Callable;
 import java.util.concurrent.ConcurrentHashMap;
+import java.util.function.Supplier;
+import java.util.logging.Level;
 
 import jdk.internal.dynalink.linker.GuardedInvocation;
 import jdk.internal.dynalink.linker.LinkRequest;
 import jdk.nashorn.internal.codegen.ApplySpecialization;
 import jdk.nashorn.internal.codegen.CompilerConstants.Call;
 import jdk.nashorn.internal.lookup.Lookup;
+import jdk.nashorn.internal.lookup.MethodHandleFactory;
 import jdk.nashorn.internal.objects.annotations.Attribute;
 import jdk.nashorn.internal.objects.annotations.Property;
 import jdk.nashorn.internal.objects.annotations.ScriptClass;
@@ -70,7 +73,11 @@
 import jdk.nashorn.internal.runtime.arrays.ArrayData;
 import jdk.nashorn.internal.runtime.linker.Bootstrap;
 import jdk.nashorn.internal.runtime.linker.InvokeByName;
+import jdk.nashorn.internal.runtime.options.LoggingOption.LoggerInfo;
 import jdk.nashorn.internal.runtime.regexp.RegExpResult;
+import jdk.nashorn.internal.runtime.logging.DebugLogger;
+import jdk.nashorn.internal.runtime.logging.Logger;
+import jdk.nashorn.internal.runtime.logging.Loggable;
 import jdk.nashorn.internal.scripts.JO;
 
 /**
@@ -430,6 +437,13 @@
     // context to which this global belongs to
     private final Context context;
 
+    // logging
+    private final Map<String, DebugLogger> loggers = new HashMap<>();
+
+    private void initLoggers() {
+        ((Loggable)MethodHandleFactory.getFunctionality()).initLogger(this);
+    }
+
     @Override
     protected Context getContext() {
         return context;
@@ -465,7 +479,8 @@
         this.context = context;
         this.setIsScope();
         this.optimisticFunctionMap = new HashMap<>();
-        GlobalConstants.instance().invalidateAll();
+        final GlobalConstants gc = GlobalConstants.instance(this);
+        gc.invalidateAll();
     }
 
     /**
@@ -480,6 +495,14 @@
     }
 
     /**
+     * Check if we have a Global instance
+     * @return true if one exists
+     */
+    public static boolean hasInstance() {
+        return Context.getGlobal() != null;
+    }
+
+    /**
      * Script access to {@link ScriptEnvironment}
      *
      * @return the script environment
@@ -1691,6 +1714,8 @@
             // synonym for "arguments" in scripting mode
             addOwnProperty("$ARG", argumentsFlags, argumentsObject);
         }
+
+        initLoggers();
     }
 
     private void initErrorObjects() {
@@ -2072,7 +2097,7 @@
     public void invalidateReservedName(final String name) {
         final SwitchPoint sp = getChangeCallback(name);
         if (sp != null) {
-            ApplySpecialization.getLogger().info("Overwrote special name '" + name +"' - invalidating switchpoint");
+            getLogger(ApplySpecialization.class).info("Overwrote special name '" + name +"' - invalidating switchpoint");
             SwitchPoint.invalidateAll(new SwitchPoint[] { sp });
         }
     }
@@ -2088,4 +2113,73 @@
         final MethodHandle target = MH.insertArguments(Global.instance().INVALIDATE_RESERVED_NAME, 0, name);
         return new ConstantCallSite(target);
     }
+
+    /**
+     * Get a logger, given a loggable class
+     * @param clazz a Loggable class
+     * @return debuglogger associated with that class
+     */
+    public DebugLogger getLogger(final Class<? extends Loggable> clazz) {
+        final String name = getLoggerName(clazz);
+        DebugLogger logger = loggers.get(name);
+        if (logger == null) {
+            final ScriptEnvironment env = context.getEnv();
+            if (!env.hasLogger(name)) {
+                return DebugLogger.DISABLED_LOGGER;
+            }
+            final LoggerInfo info = env._loggers.get(name);
+            logger = new DebugLogger(name, info.getLevel(), info.isQuiet());
+            loggers.put(name, logger);
+        }
+        return logger;
+    }
+
+    /**
+     * Given a Loggable class, weave debug info info a method handle for that logger.
+     * Level.INFO is used
+     *
+     * @param clazz loggable
+     * @param mh    method handle
+     * @param text  debug printout to add
+     *
+     * @return instrumented method handle, or null if logger not enabled
+     */
+    public MethodHandle addLoggingToHandle(final Class<? extends Loggable> clazz, final MethodHandle mh, final Supplier<String> text) {
+        return addLoggingToHandle(clazz, Level.INFO, mh, Integer.MAX_VALUE, false, text);
+    }
+
+    /**
+     * Given a Loggable class, weave debug info info a method handle for that logger.
+     *
+     * @param clazz            loggable
+     * @param level            log level
+     * @param mh               method handle
+     * @param paramStart       first parameter to print
+     * @param printReturnValue should we print the return vaulue?
+     * @param text             debug printout to add
+     *
+     * @return instrumented method handle, or null if logger not enabled
+     */
+    public MethodHandle addLoggingToHandle(final Class<? extends Loggable> clazz, final Level level, final MethodHandle mh, final int paramStart, final boolean printReturnValue, final Supplier<String> text) {
+        final DebugLogger log = getLogger(clazz);
+        if (log.isEnabled()) {
+            return MethodHandleFactory.addDebugPrintout(log, level, mh, paramStart, printReturnValue, text.get());
+        }
+        return mh;
+    }
+
+    private static String getLoggerName(final Class<?> clazz) {
+        Class<?> current = clazz;
+        while (current != null) {
+            final Logger log = current.getAnnotation(Logger.class);
+            if (log != null) {
+                assert !"".equals(log.name());
+                return log.name();
+            }
+            current = current.getSuperclass();
+        }
+        assert false;
+        return null;
+    }
+
 }
--- a/nashorn/src/jdk/nashorn/internal/parser/Parser.java	Tue Apr 22 14:09:46 2014 +0200
+++ b/nashorn/src/jdk/nashorn/internal/parser/Parser.java	Wed Apr 23 16:13:47 2014 +0200
@@ -105,7 +105,7 @@
 import jdk.nashorn.internal.ir.VarNode;
 import jdk.nashorn.internal.ir.WhileNode;
 import jdk.nashorn.internal.ir.WithNode;
-import jdk.nashorn.internal.runtime.DebugLogger;
+import jdk.nashorn.internal.objects.Global;
 import jdk.nashorn.internal.runtime.ErrorManager;
 import jdk.nashorn.internal.runtime.JSErrorType;
 import jdk.nashorn.internal.runtime.ParserException;
@@ -114,11 +114,15 @@
 import jdk.nashorn.internal.runtime.ScriptingFunctions;
 import jdk.nashorn.internal.runtime.Source;
 import jdk.nashorn.internal.runtime.Timing;
+import jdk.nashorn.internal.runtime.logging.DebugLogger;
+import jdk.nashorn.internal.runtime.logging.Loggable;
+import jdk.nashorn.internal.runtime.logging.Logger;
 
 /**
  * Builds the IR.
  */
-public class Parser extends AbstractParser {
+@Logger(name="parser")
+public class Parser extends AbstractParser implements Loggable {
     private static final String ARGUMENTS_NAME = CompilerConstants.ARGUMENTS_VAR.symbolName();
 
     /** Current script environment. */
@@ -135,7 +139,7 @@
     /** Namespace for function names where not explicitly given */
     private final Namespace namespace;
 
-    private static final DebugLogger LOG = new DebugLogger("parser");
+    private final DebugLogger log;
 
     /** to receive line information from Lexer when scanning multine literals. */
     protected final Lexer.LineInfoReceiver lineInfoReceiver;
@@ -194,6 +198,18 @@
             // non-scripting mode script can't have multi-line literals
             this.lineInfoReceiver = null;
         }
+
+        this.log = !Global.hasInstance() ? DebugLogger.DISABLED_LOGGER : initLogger(Global.instance());
+    }
+
+    @Override
+    public DebugLogger getLogger() {
+        return log;
+    }
+
+    @Override
+    public DebugLogger initLogger(final Global global) {
+        return global.getLogger(this.getClass());
     }
 
     /**
@@ -250,7 +266,7 @@
      */
     public FunctionNode parse(final String scriptName, final int startPos, final int len, final boolean allowPropertyFunction) {
         final long t0 = Timing.isEnabled() ? System.currentTimeMillis() : 0L;
-        LOG.info(this, " begin for '", scriptName, "'");
+        log.info(this, " begin for '", scriptName, "'");
 
         try {
             stream = new TokenStream();
@@ -271,9 +287,9 @@
             final String end = this + " end '" + scriptName + "'";
             if (Timing.isEnabled()) {
                 Timing.accumulateTime(toString(), System.currentTimeMillis() - t0);
-                LOG.info(end, "' in ", System.currentTimeMillis() - t0, " ms");
+                log.info(end, "' in ", System.currentTimeMillis() - t0, " ms");
             } else {
-                LOG.info(end);
+                log.info(end);
             }
         }
     }
@@ -2538,7 +2554,7 @@
         return nodeList;
     }
 
-    private static <T> List<T> optimizeList(ArrayList<T> list) {
+    private static <T> List<T> optimizeList(final ArrayList<T> list) {
         switch(list.size()) {
             case 0: {
                 return Collections.emptyList();
@@ -2668,7 +2684,7 @@
         return isValidIdentifier(defaultFunctionName) ? defaultFunctionName : ANON_FUNCTION_PREFIX.symbolName() + functionLine;
     }
 
-    private static boolean isValidIdentifier(String name) {
+    private static boolean isValidIdentifier(final String name) {
         if(name == null || name.isEmpty()) {
             return false;
         }
--- a/nashorn/src/jdk/nashorn/internal/runtime/AccessorProperty.java	Tue Apr 22 14:09:46 2014 +0200
+++ b/nashorn/src/jdk/nashorn/internal/runtime/AccessorProperty.java	Wed Apr 23 16:13:47 2014 +0200
@@ -25,14 +25,12 @@
 
 package jdk.nashorn.internal.runtime;
 
-import static jdk.nashorn.internal.codegen.ObjectClassGenerator.DEBUG_FIELDS;
 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;
 import static jdk.nashorn.internal.codegen.ObjectClassGenerator.createSetter;
 import static jdk.nashorn.internal.codegen.ObjectClassGenerator.getFieldCount;
 import static jdk.nashorn.internal.codegen.ObjectClassGenerator.getFieldName;
-import static jdk.nashorn.internal.codegen.ObjectClassGenerator.shouldInstrument;
 import static jdk.nashorn.internal.lookup.Lookup.MH;
 import static jdk.nashorn.internal.lookup.MethodHandleFactory.stripName;
 import static jdk.nashorn.internal.runtime.JSType.getAccessorTypeIndex;
@@ -42,12 +40,12 @@
 import java.lang.invoke.MethodHandle;
 import java.lang.invoke.MethodHandles;
 import java.lang.invoke.SwitchPoint;
+import java.util.function.Supplier;
 import java.util.logging.Level;
 
 import jdk.nashorn.internal.codegen.ObjectClassGenerator;
 import jdk.nashorn.internal.codegen.types.Type;
 import jdk.nashorn.internal.lookup.Lookup;
-import jdk.nashorn.internal.lookup.MethodHandleFactory;
 import jdk.nashorn.internal.objects.Global;
 
 /**
@@ -56,14 +54,14 @@
  */
 public class AccessorProperty extends Property {
     private static final MethodHandles.Lookup LOOKUP = MethodHandles.lookup();
-    private static final MethodHandle REPLACE_MAP = findOwnMH("replaceMap", Object.class, Object.class, PropertyMap.class, String.class, Class.class, Class.class);
+
+    private static final MethodHandle REPLACE_MAP   = findOwnMH_S("replaceMap", Object.class, Object.class, PropertyMap.class);
+    private static final MethodHandle INVALIDATE_SP = findOwnMH_S("invalidateSwitchPoint", Object.class, Object.class, SwitchPoint.class);
+
+    private static final SwitchPoint NO_CHANGE_CALLBACK = new SwitchPoint();
 
     private static final int NOOF_TYPES = getNumberOfAccessorTypes();
 
-    private static final DebugLogger LOG = ObjectClassGenerator.getLogger();
-
-    private static final MethodHandle INVALIDATE_SP  = findOwnMH("invalidateSwitchPoint", Object.class, Object.class, SwitchPoint.class, String.class);
-
     /**
      * 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
@@ -376,9 +374,6 @@
             if (!canBeUndefined()) { //todo if !canBeUndefined it means that we have an exact initialType
                 initialType = int.class;
             }
-            if (shouldInstrument(getKey())) {
-                info(getKey(), canBeUndefined() ? " can be undefined" : " is always defined");
-            }
         }
         setCurrentType(initialType);
     }
@@ -594,27 +589,19 @@
 
     // the final three arguments are for debug printout purposes only
     @SuppressWarnings("unused")
-    private static Object replaceMap(final Object sobj, final PropertyMap newMap, final String key, final Class<?> oldType, final Class<?> newType) {
-        if (DEBUG_FIELDS && shouldInstrument(key)) {
-            final PropertyMap oldMap = ((ScriptObject)sobj).getMap();
-            info("Type change for '" + key + "' " + oldType + "=>" + newType);
-            finest("setting map " + key+ " => " + sobj + " from " + Debug.id(oldMap) + " to " + Debug.id(newMap) + " " + oldMap + " => " + newMap);
-        }
+    private static Object replaceMap(final Object sobj, final PropertyMap newMap) {
         ((ScriptObject)sobj).setMap(newMap);
         return sobj;
     }
 
     @SuppressWarnings("unused")
-    private static Object invalidateSwitchPoint(final Object obj, final SwitchPoint sp, final String key) {
-        LOG.info("Field change callback for " + key + " triggered: " + sp);
+    private static Object invalidateSwitchPoint(final Object obj, final SwitchPoint sp) {
         SwitchPoint.invalidateAll(new SwitchPoint[] { sp });
         return obj;
     }
 
     private MethodHandle generateSetter(final Class<?> forType, final Class<?> type) {
-        MethodHandle mh = createSetter(forType, type, primitiveSetter, objectSetter);
-        mh = debug(mh, getCurrentType(), type, "set");
-        return mh;
+        return debug(createSetter(forType, type, primitiveSetter, objectSetter), getCurrentType(), type, "set");
     }
 
     /**
@@ -638,8 +625,8 @@
             final PropertyMap  newMap      = getWiderMap(currentMap, newProperty);
 
             final MethodHandle widerSetter = newProperty.getSetter(type, newMap);
-            final Class<?>   ct = getCurrentType();
-            mh = MH.filterArguments(widerSetter, 0, MH.insertArguments(REPLACE_MAP, 1, newMap, getKey(), ct, type));
+            final Class<?>     ct = getCurrentType();
+            mh = MH.filterArguments(widerSetter, 0, MH.insertArguments(debugReplace(ct, type, currentMap, newMap) , 1, newMap));
             if (ct != null && ct.isPrimitive() && !type.isPrimitive()) {
                  mh = ObjectClassGenerator.createGuardBoxedPrimitiveSetter(ct, generateSetter(ct, ct), mh);
             }
@@ -652,16 +639,14 @@
          */
         final SwitchPoint ccb = getChangeCallback();
         if (ccb != null && ccb != NO_CHANGE_CALLBACK) {
-            mh = MH.filterArguments(mh, 0, MH.insertArguments(INVALIDATE_SP, 1, changeCallback, getKey()));
+            mh = MH.filterArguments(mh, 0, MH.insertArguments(debugInvalidate(getKey(), ccb), 1, changeCallback));
         }
 
-        assert mh.type().returnType() == void.class;
+        assert mh.type().returnType() == void.class : mh.type();
 
         return mh;
     }
 
-    private static final SwitchPoint NO_CHANGE_CALLBACK = new SwitchPoint();
-
     /**
      * Get the change callback for this property
      * @return switchpoint that is invalidated when property changes
@@ -693,32 +678,6 @@
         return canChangeType() && ti > fti;
     }
 
-    // for loggers below, don't bother generating potentially expensive string concat
-    // operations that will be thrown away anyway, if the level isn't finer than ior
-    // equal to info
-    private static void finest(final String... strs) {
-        if (DEBUG_FIELDS && LOG.levelFinerThanOrEqual(Level.INFO)) {
-            LOG.finest((Object[])strs);
-        }
-    }
-
-    private static void info(final String... strs) {
-        if (DEBUG_FIELDS && LOG.levelFinerThanOrEqual(Level.INFO)) {
-            LOG.info((Object[])strs);
-        }
-    }
-
-    private MethodHandle debug(final MethodHandle mh, final Class<?> forType, final Class<?> type, final String tag) {
-        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) + ')');
-        }
-        return mh;
-    }
-
     @Override
     public final void setCurrentType(final Class<?> currentType) {
         assert currentType != boolean.class : "no boolean storage support yet - fix this";
@@ -730,8 +689,74 @@
         return currentType;
     }
 
-    private static MethodHandle findOwnMH(final String name, final Class<?> rtype, final Class<?>... types) {
+
+    private MethodHandle debug(final MethodHandle mh, final Class<?> forType, final Class<?> type, final String tag) {
+        if (Global.hasInstance()) {
+            return Global.instance().addLoggingToHandle(
+                    ObjectClassGenerator.class,
+                    Level.INFO,
+                    mh,
+                    0,
+                    true,
+                    new Supplier<String>() {
+                        @Override
+                        public String get() {
+                            return tag + " '" + getKey() + "' (property="+ Debug.id(this) + ", slot=" + getSlot() + " " + getClass().getSimpleName() + " forType=" + stripName(forType) + ", type=" + stripName(type) + ')';
+                        }
+                    });
+        }
+
+        return mh;
+    }
+
+    private MethodHandle debugReplace(final Class<?> oldType, final Class<?> newType, final PropertyMap oldMap, final PropertyMap newMap) {
+        if (Global.hasInstance()) {
+            final Global global = Global.instance();
+            MethodHandle mh = global.addLoggingToHandle(
+                    ObjectClassGenerator.class,
+                    REPLACE_MAP,
+                    new Supplier<String>() {
+                        @Override
+                        public String get() {
+                            return "Type change for '" + getKey() + "' " + oldType + "=>" + newType;
+                        }
+                    });
+
+            mh = global.addLoggingToHandle(
+                    ObjectClassGenerator.class,
+                    Level.FINEST,
+                    mh,
+                    Integer.MAX_VALUE,
+                    false,
+                    new Supplier<String>() {
+                        @Override
+                        public String get() {
+                            return "Setting map " + Debug.id(oldMap) + " => " + Debug.id(newMap) + " " + oldMap + " => " + newMap;
+                        }
+                    });
+            return mh;
+        }
+
+        return REPLACE_MAP;
+    }
+
+    private static MethodHandle debugInvalidate(final String key, final SwitchPoint sp) {
+        if (Global.hasInstance()) {
+            return Global.instance().addLoggingToHandle(
+                    ObjectClassGenerator.class,
+                    INVALIDATE_SP,
+                    new Supplier<String>() {
+                        @Override
+                        public String get() {
+                            return "Field change callback for " + key + " triggered: " + sp;
+                        }
+                    });
+        }
+
+        return INVALIDATE_SP;
+    }
+
+    private static MethodHandle findOwnMH_S(final String name, final Class<?> rtype, final Class<?>... types) {
         return MH.findStatic(LOOKUP, AccessorProperty.class, name, MH.type(rtype, types));
     }
-
 }
--- a/nashorn/src/jdk/nashorn/internal/runtime/CompiledFunction.java	Tue Apr 22 14:09:46 2014 +0200
+++ b/nashorn/src/jdk/nashorn/internal/runtime/CompiledFunction.java	Wed Apr 23 16:13:47 2014 +0200
@@ -41,8 +41,10 @@
 import jdk.nashorn.internal.codegen.types.ArrayType;
 import jdk.nashorn.internal.codegen.types.Type;
 import jdk.nashorn.internal.ir.FunctionNode;
+import jdk.nashorn.internal.objects.Global;
 import jdk.nashorn.internal.runtime.events.RecompilationEvent;
 import jdk.nashorn.internal.runtime.linker.Bootstrap;
+import jdk.nashorn.internal.runtime.logging.DebugLogger;
 
 /**
  * An version of a JavaScript function, native or JavaScript.
@@ -55,7 +57,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 = RecompilableScriptFunctionData.getLogger();
+    private final DebugLogger log;
 
     /**
      * The method type may be more specific than the invoker, if. e.g.
@@ -71,6 +73,7 @@
 
     CompiledFunction(final MethodHandle invoker) {
         this.invoker = invoker;
+        this.log = Global.instance().getLogger(RecompilableScriptFunctionData.class);
     }
 
     static CompiledFunction createBuiltInConstructor(final MethodHandle invoker) {
@@ -576,8 +579,8 @@
         final MethodType callSiteType = type.parameterType(0) == ScriptFunction.class ? type : type.insertParameterTypes(0, ScriptFunction.class);
 
         final FunctionNode fn = oldOptimismInfo.recompile(callSiteType, re);
-        if (LOG.isEnabled()) {
-            LOG.info(new RecompilationEvent(Level.INFO, re, re.getReturnValueNonDestructive()), "\tRewriteException ", re.getMessageShort());
+        if (log.isEnabled()) {
+            log.info(new RecompilationEvent(Level.INFO, re, re.getReturnValueNonDestructive()), "\tRewriteException ", re.getMessageShort());
         }
 
         // It didn't necessarily recompile, e.g. for an outer invocation of a recursive function if we already
@@ -588,8 +591,8 @@
             //is recompiled
             assert optimismInfo == oldOptimismInfo;
             isOptimistic = fn.isOptimistic();
-            if (LOG.isEnabled()) {
-                LOG.info("Recompiled '", fn.getName(), "' (", Debug.id(this), ")", isOptimistic ? " remains optimistic." : " is no longer optimistic.");
+            if (log.isEnabled()) {
+                log.info("Recompiled '", fn.getName(), "' (", Debug.id(this), ")", isOptimistic ? " remains optimistic." : " is no longer optimistic.");
             }
             final MethodHandle newInvoker = oldOptimismInfo.data.lookup(fn);
             invoker = newInvoker.asType(type.changeReturnType(newInvoker.type().returnType()));
@@ -617,6 +620,7 @@
         private final RecompilableScriptFunctionData data;
         private final Map<Integer, Type> invalidatedProgramPoints = new TreeMap<>();
         private SwitchPoint optimisticAssumptions;
+        private final DebugLogger log = Global.instance().getLogger(RecompilableScriptFunctionData.class);
 
         OptimismInfo(final RecompilableScriptFunctionData data) {
             this.data = data;
@@ -633,7 +637,7 @@
             if (previousFailedType != null && !previousFailedType.narrowerThan(retType)) {
                 final StackTraceElement[] stack = e.getStackTrace();
                 final String functionId = stack.length == 0 ? data.getName() : stack[0].getClassName() + "." + stack[0].getMethodName();
-                LOG.info("RewriteException for an already invalidated program point ", e.getProgramPoint(), " in ", functionId, ". This is okay for a recursive function invocation, but a bug otherwise.");
+                log.info("RewriteException for an already invalidated program point ", e.getProgramPoint(), " in ", functionId, ". This is okay for a recursive function invocation, but a bug otherwise.");
                 return null;
             }
             SwitchPoint.invalidateAll(new SwitchPoint[] { optimisticAssumptions });
--- a/nashorn/src/jdk/nashorn/internal/runtime/Context.java	Tue Apr 22 14:09:46 2014 +0200
+++ b/nashorn/src/jdk/nashorn/internal/runtime/Context.java	Wed Apr 23 16:13:47 2014 +0200
@@ -65,6 +65,7 @@
 import jdk.nashorn.internal.objects.Global;
 import jdk.nashorn.internal.parser.Parser;
 import jdk.nashorn.internal.runtime.events.RuntimeEvent;
+import jdk.nashorn.internal.runtime.logging.DebugLogger;
 import jdk.nashorn.internal.runtime.options.Options;
 
 /**
@@ -195,7 +196,7 @@
         // 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();
+        GlobalConstants.instance(global).invalidateAll();
         currentGlobal.set(global);
     }
 
@@ -915,9 +916,9 @@
 
         Class<?> script = findCachedClass(source);
         if (script != null) {
-            final DebugLogger LOG = Compiler.getLogger();
-            if (LOG.isEnabled()) {
-                LOG.fine(new RuntimeEvent<>(Level.INFO, source), "Code cache hit for ", source, " avoiding recompile.");
+            final DebugLogger log = Global.instance().getLogger(Compiler.class);
+            if (log.isEnabled()) {
+                log.fine(new RuntimeEvent<>(Level.INFO, source), "Code cache hit for ", source, " avoiding recompile.");
             }
             return script;
         }
--- a/nashorn/src/jdk/nashorn/internal/runtime/DebugLogger.java	Tue Apr 22 14:09:46 2014 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,546 +0,0 @@
-/*
- * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.  Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-package jdk.nashorn.internal.runtime;
-
-import java.io.PrintWriter;
-import java.util.logging.Level;
-import java.util.logging.Logger;
-
-import jdk.nashorn.internal.objects.Global;
-import jdk.nashorn.internal.runtime.events.RuntimeEvent;
-import jdk.nashorn.internal.runtime.options.Options;
-
-/**
- * Wrapper class for Logging system. This is how you are supposed to register a logger and use it
- */
-
-public final class DebugLogger {
-    private final Logger  logger;
-    private final boolean isEnabled;
-
-    private int indent;
-
-    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
-     *
-     * @param loggerName name of logger - this is the unique key with which it can be identified
-     */
-    public DebugLogger(final String loggerName) {
-        this(loggerName, null);
-    }
-
-    /**
-     * Constructor
-     *
-     * A logger can be paired with a property, e.g. {@code --log:codegen:info} is equivalent to {@code -Dnashorn.codegen.log}
-     *
-     * @param loggerName name of logger - this is the unique key with which it can be identified
-     * @param property   system property activating the logger on {@code info} level
-     */
-    public DebugLogger(final String loggerName, final String property) {
-        if (property != null && Options.getBooleanProperty(property)) {
-            this.logger = Logging.getOrCreateLogger(loggerName, Level.INFO);
-        } else {
-            this.logger = Logging.getLogger(loggerName);
-        }
-        this.isQuiet = Logging.loggerIsQuiet(loggerName);
-        assert logger != null;
-        this.isEnabled = getLevel() != Level.OFF;
-    }
-
-    /**
-     * Do not currently support chaining this with parent logger. Logger level null
-     * means disabled
-     * @return level
-     */
-    private Level getLevel() {
-        return logger.getLevel() == null ? Level.OFF : logger.getLevel();
-    }
-
-    /**
-     * Get the output writer for the logger. Loggers always default to
-     * stderr for output as they are used mainly to output debug info
-     *
-     * Can be inherited so this should not be static.
-     *
-     * @return print writer for log output.
-     */
-    @SuppressWarnings("static-method")
-    public PrintWriter getOutputStream() {
-        return Context.getCurrentErr();
-    }
-
-    /**
-     * 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' ? quote : startQuote) + str + (endQuote == '\0' ? quote : endQuote);
-    }
-
-    /**
-     * Check if the logger is enabled
-     * @return true if enabled
-     */
-    public boolean isEnabled() {
-        return isEnabled;
-    }
-
-    /**
-     * If you want to change the indent level of your logger, call indent with a new position.
-     * Positions start at 0 and are increased by one for a new "tab"
-     *
-     * @param pos indent position
-     */
-    public void indent(final int pos) {
-        if (isEnabled) {
-           indent += pos * INDENT_SPACE;
-        }
-    }
-
-    /**
-     * Add an indent position
-     */
-    public void indent() {
-        indent += INDENT_SPACE;
-    }
-
-    /**
-     * Unindent a position
-     */
-    public void unindent() {
-        indent -= INDENT_SPACE;
-        if (indent < 0) {
-            indent = 0;
-        }
-    }
-
-    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
-     *
-     * The higher the level, the more severe the warning
-     *
-     * @param level logging level
-     * @return true if level is above the given one
-     */
-    public boolean levelCoarserThan(final Level level) {
-        return getLevel().intValue() > level.intValue();
-    }
-
-    /**
-     * Check if the logger is above or equal to the level
-     * of detail given
-     * @see java.util.logging.Level
-     *
-     * The higher the level, the more severe the warning
-     *
-     * @param level logging level
-     * @return true if level is above the given one
-     */
-    public boolean levelCoarserThanOrEqual(final Level level) {
-        return getLevel().intValue() >= level.intValue();
-    }
-
-    /**
-     * Check if the logger is below the level of detail given
-     * @see java.util.logging.Level
-     *
-     * The higher the level, the more severe the warning
-     *
-     * @param level logging level
-     * @return true if level is above the given one
-     */
-    public boolean levelFinerThan(final Level level) {
-        return getLevel().intValue() < level.intValue();
-    }
-
-    /**
-     * Check if the logger is below or equal to the level
-     * of detail given
-     * @see java.util.logging.Level
-     *
-     * The higher the level, the more severe the warning
-     *
-     * @param level logging level
-     * @return true if level is above the given one
-     */
-    public boolean levelFinerThanOrEqual(final Level level) {
-        return getLevel().intValue() <= level.intValue();
-    }
-
-    /**
-     * Shorthand for outputting a log string as log level {@link java.util.logging.Level#FINEST} on this logger
-     * @param str the string to log
-     */
-    public void finest(final String str) {
-        log(Level.FINEST, str);
-    }
-
-    /**
-     * 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
-     */
-    public void finest(final Object... objs) {
-        log(Level.FINEST, objs);
-    }
-
-    /**
-     * 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
-     */
-    public void finer(final String str) {
-        log(Level.FINER, str);
-    }
-
-    /**
-     * 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) {
-        log(Level.FINER, objs);
-    }
-
-    /**
-     * 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
-     */
-    public void fine(final String str) {
-        log(Level.FINE, str);
-    }
-
-    /**
-     * 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) {
-        log(Level.FINE, objs);
-    }
-
-    /**
-     * 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
-     */
-    public void config(final String str) {
-        log(Level.CONFIG, str);
-    }
-
-    /**
-     * 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) {
-        log(Level.CONFIG, objs);
-    }
-
-    /**
-     * 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
-     */
-    public void info(final String str) {
-        log(Level.INFO, str);
-    }
-
-    /**
-     * 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
-     */
-    public void info(final Object... objs) {
-        log(Level.INFO, objs);
-    }
-
-    /**
-     * 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
-     */
-    public void warning(final String str) {
-        log(Level.WARNING, str);
-    }
-
-    /**
-     * 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
-     */
-    public void warning(final Object... objs) {
-        log(Level.WARNING, objs);
-    }
-
-    /**
-     * 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
-     */
-    public void severe(final String str) {
-        log(Level.SEVERE, str);
-    }
-
-    /**
-     * 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
-     */
-    public void severe(final Object... objs) {
-        log(Level.SEVERE, objs);
-    }
-
-    /**
-     * 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
-     *
-     * @param level minimum log level required for logging to take place
-     * @param str   string to log
-     */
-    public void log(final Level level, final String str) {
-        if (isEnabled && !isQuiet) {
-            final StringBuilder sb = new StringBuilder();
-            for (int i = 0 ; i < indent ; i++) {
-                sb.append(' ');
-            }
-            sb.append(str);
-            logger.log(level, sb.toString());
-        }
-    }
-
-    /**
-     * Output log line on this logger at a given level of verbosity
-     * @see java.util.logging.Level
-     *
-     * @param level minimum log level required for logging to take place
-     * @param objs  objects for which to invoke toString and concatenate to log
-     */
-    public void log(final Level level, final Object... objs) {
-        if (isEnabled && !isQuiet) {
-            final StringBuilder sb = new StringBuilder();
-            for (final Object obj : objs) {
-                sb.append(obj);
-            }
-            log(level, sb.toString());
-        }
-    }
-}
--- a/nashorn/src/jdk/nashorn/internal/runtime/GlobalConstants.java	Tue Apr 22 14:09:46 2014 +0200
+++ b/nashorn/src/jdk/nashorn/internal/runtime/GlobalConstants.java	Wed Apr 23 16:13:47 2014 +0200
@@ -26,7 +26,8 @@
 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.codegen.CompilerConstants.virtualCall;
+import static jdk.nashorn.internal.runtime.logging.DebugLogger.quote;
 import static jdk.nashorn.internal.lookup.Lookup.MH;
 
 import java.lang.invoke.MethodHandle;
@@ -43,7 +44,11 @@
 import jdk.internal.dynalink.linker.LinkRequest;
 import jdk.nashorn.internal.lookup.Lookup;
 import jdk.nashorn.internal.lookup.MethodHandleFactory;
+import jdk.nashorn.internal.objects.Global;
 import jdk.nashorn.internal.runtime.linker.NashornCallSiteDescriptor;
+import jdk.nashorn.internal.runtime.logging.DebugLogger;
+import jdk.nashorn.internal.runtime.logging.Loggable;
+import jdk.nashorn.internal.runtime.logging.Logger;
 
 /**
  * Each global owns one of these. This is basically table of accessors
@@ -67,21 +72,10 @@
  * 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();
+@Logger(name="const")
+public final class GlobalConstants implements Loggable {
+    /** singleton per global */
+    private static GlobalConstants instance;
 
     /**
      * Should we only try to link globals as constants, and not generic script objects.
@@ -92,11 +86,11 @@
 
     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 INVALIDATE_SP  = virtualCall(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");
+    private final DebugLogger log;
 
     /**
      * Access map for this global - associates a symbol name with an Access object, with getter
@@ -104,6 +98,32 @@
      */
     private final Map<String, Access> map = new HashMap<>();
 
+    private GlobalConstants(final Global global) {
+        this.log = initLogger(global);
+    }
+
+    @Override
+    public DebugLogger getLogger() {
+        return log;
+    }
+
+    @Override
+    public DebugLogger initLogger(final Global global) {
+        return global.getLogger(this.getClass());
+    }
+
+    /**
+     * Return the singleton global constant pool
+     * @param global global
+     * @return singleton global constant pool
+     */
+    public static synchronized GlobalConstants instance(final Global global) {
+        if (instance == null) {
+            instance = new GlobalConstants(global);
+        }
+        return instance;
+    }
+
     /**
      * Information about a constant access and its potential invalidations
      */
@@ -205,7 +225,7 @@
      * will have changed.
      */
     public void invalidateAll() {
-        LOG.info("New global created - invalidating all constant callsites without increasing invocation count.");
+        log.info("New global created - invalidating all constant callsites without increasing invocation count.");
         for (final Access acc : map.values()) {
             acc.invalidateUncounted();
         }
@@ -221,19 +241,19 @@
      * @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);
+    private 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.");
+            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.");
+            if (log.isEnabled()) {
+                log.info("This was the last time I allowed " + quote(acc.getName()) + " to relink as constant.");
             }
         }
         return obj;
@@ -310,32 +330,33 @@
 
         final Access acc  = getOrCreateSwitchPoint(name);
 
-        if (LOG.isEnabled()) {
-            LOG.fine("Trying to link constant SETTER ", acc);
+        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());
+            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);
+            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));
+        final MethodHandle target           = inv.getInvocation();
+        final Class<?>     receiverType     = target.type().parameterType(0);
+        final MethodHandle boundInvalidator = MH.bindTo(INVALIDATE_SP,  this);
+        final MethodHandle invalidator      = MH.asType(boundInvalidator, boundInvalidator.type().changeParameterType(0, receiverType).changeReturnType(receiverType));
+        final MethodHandle mh               = MH.filterArguments(inv.getInvocation(), 0, MH.insertArguments(invalidator, 1, acc));
 
         assert inv.getSwitchPoints() == null : Arrays.asList(inv.getSwitchPoints());
-        LOG.info("Linked setter " + quote(name) + " " + acc.getSwitchPoint());
+        log.info("Linked setter " + quote(name) + " " + acc.getSwitchPoint());
         return new GuardedInvocation(mh, inv.getGuard(), acc.getSwitchPoint(), inv.getException());
     }
 
@@ -373,15 +394,15 @@
 
         final Access acc = getOrCreateSwitchPoint(name);
 
-        LOG.fine("Starting to look up object value " + 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 (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");
+            log.fine("*** GET: Giving up on " + quote(name) + " - retry count has exceeded");
             return null;
         }
 
@@ -409,9 +430,9 @@
             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);
+        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/Logging.java	Tue Apr 22 14:09:46 2014 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,194 +0,0 @@
-/*
- * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.  Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-package jdk.nashorn.internal.runtime;
-
-import java.security.AccessControlContext;
-import java.security.AccessController;
-import java.security.Permissions;
-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;
-import java.util.logging.Level;
-import java.util.logging.LogRecord;
-import java.util.logging.Logger;
-import java.util.logging.LoggingPermission;
-
-/**
- * Logging system for getting loggers for arbitrary subsystems as
- * specified on the command line. Supports all standard log levels
- *
- */
-public final class Logging {
-
-    private Logging() {
-    }
-
-    /** Loggers */
-
-    private static final Logger disabledLogger = Logger.getLogger("disabled");
-
-    private static AccessControlContext createLoggerControlAccCtxt() {
-        final Permissions perms = new Permissions();
-        perms.add(new LoggingPermission("control", null));
-        return new AccessControlContext(new ProtectionDomain[] { new ProtectionDomain(null, perms) });
-    }
-
-    static {
-        AccessController.doPrivileged(new PrivilegedAction<Void>() {
-            @Override
-            public Void run() {
-                Logging.disabledLogger.setLevel(Level.OFF);
-                return null;
-            }
-        }, createLoggerControlAccCtxt());
-    }
-
-    /** 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) {
-            return packageName;
-        }
-        return parts[parts.length - 1];
-    }
-
-    /**
-     * Get a logger for a given class, generating a logger name based on the
-     * class name
-     *
-     * @param name the name to use as key for the logger
-     * @return the logger
-     */
-    public static Logger getLogger(final String name) {
-        final Logger logger = Logging.loggers.get(name);
-        if (logger != null) {
-            return logger;
-        }
-        return Logging.disabledLogger;
-    }
-
-    /**
-     * Get a logger for a given name or create it if not already there, typically
-     * used for mapping system properties to loggers
-     *
-     * @param name the name to use as key
-     * @param level log lever to reset existing logger with, or create new logger with
-     * @return the logger
-     */
-    public static Logger getOrCreateLogger(final String name, final Level level) {
-        final Logger logger = Logging.loggers.get(name);
-        if (logger == null) {
-            return instantiateLogger(name, level);
-        }
-        logger.setLevel(level);
-        return logger;
-    }
-
-    /**
-     * 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
-     *
-     * @param map a map where the key is a logger name and the value a logging level
-     * @throws IllegalArgumentException if level or names cannot be parsed
-     */
-    public static void initialize(final Map<String, String> map) throws IllegalArgumentException {
-        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 Logger logger = instantiateLogger(name, level);
-                Logging.loggers.put(name, logger);
-            }
-        } catch (final IllegalArgumentException | SecurityException e) {
-            throw e;
-        }
-    }
-
-    private static Logger instantiateLogger(final String name, final Level level) {
-        final Logger logger = java.util.logging.Logger.getLogger(name);
-        for (final Handler h : logger.getHandlers()) {
-            logger.removeHandler(h);
-        }
-
-        logger.setLevel(level);
-        logger.setUseParentHandlers(false);
-        final Handler c = new ConsoleHandler();
-
-        c.setFormatter(new Formatter() {
-            @Override
-            public String format(final LogRecord record) {
-                final StringBuilder sb = new StringBuilder();
-
-                sb.append('[')
-                   .append(record.getLoggerName())
-                   .append("] ")
-                   .append(record.getMessage())
-                   .append('\n');
-
-                return sb.toString();
-            }
-        });
-        logger.addHandler(c);
-        c.setLevel(level);
-
-        return logger;
-    }
-
-}
--- a/nashorn/src/jdk/nashorn/internal/runtime/PropertyHashMap.java	Tue Apr 22 14:09:46 2014 +0200
+++ b/nashorn/src/jdk/nashorn/internal/runtime/PropertyHashMap.java	Wed Apr 23 16:13:47 2014 +0200
@@ -172,7 +172,6 @@
      */
     public PropertyHashMap immutableReplace(final Property property, final Property newProperty) {
         assert property.getKey().equals(newProperty.getKey()) : "replacing properties with different keys: '" + property.getKey() + "' != '" + newProperty.getKey() + "'";
-        assert property.hashCode() != newProperty.hashCode()  : "replacing identical properties: '" + property + "'";
         assert findElement(property.getKey()) != null         : "replacing property that doesn't exist in map: '" + property.getKey() + "'";
         return cloneMap().replaceNoClone(property.getKey(), newProperty);
     }
--- a/nashorn/src/jdk/nashorn/internal/runtime/RecompilableScriptFunctionData.java	Tue Apr 22 14:09:46 2014 +0200
+++ b/nashorn/src/jdk/nashorn/internal/runtime/RecompilableScriptFunctionData.java	Wed Apr 23 16:13:47 2014 +0200
@@ -50,9 +50,13 @@
 import jdk.nashorn.internal.ir.FunctionNode;
 import jdk.nashorn.internal.ir.LexicalContext;
 import jdk.nashorn.internal.ir.visitor.NodeVisitor;
+import jdk.nashorn.internal.objects.Global;
 import jdk.nashorn.internal.parser.Parser;
 import jdk.nashorn.internal.parser.Token;
 import jdk.nashorn.internal.parser.TokenType;
+import jdk.nashorn.internal.runtime.logging.DebugLogger;
+import jdk.nashorn.internal.runtime.logging.Loggable;
+import jdk.nashorn.internal.runtime.logging.Logger;
 import jdk.nashorn.internal.runtime.options.Options;
 
 /**
@@ -61,7 +65,8 @@
  * The common denominator is that it can get new invokers during its lifespan,
  * unlike {@code FinalScriptFunctionData}
  */
-public final class RecompilableScriptFunctionData extends ScriptFunctionData {
+@Logger(name="recompile")
+public final class RecompilableScriptFunctionData extends ScriptFunctionData implements Loggable {
     /** Is lazy compilation enabled? TODO: this should be the default */
     public static final boolean LAZY_COMPILATION = Options.getBooleanProperty("nashorn.lazy");
 
@@ -112,15 +117,7 @@
     /** Unique id for classes needed to wrap recompiled script functions */
     private static final AtomicInteger RECOMPILE_ID = new AtomicInteger(0);
 
-    private static final DebugLogger LOG = new DebugLogger("recompile");
-
-    /**
-     * Get the recompilation logger
-     * @return the logger
-     */
-    public static DebugLogger getLogger() {
-        return LOG;
-    }
+    private final DebugLogger log;
 
     private final Map<String, Integer> externalScopeDepths;
 
@@ -174,6 +171,18 @@
             assert nfn.getParent() == null;
             nfn.setParent(this);
         }
+
+        this.log = initLogger(Global.instance());
+    }
+
+    @Override
+    public DebugLogger getLogger() {
+        return log;
+    }
+
+    @Override
+    public DebugLogger initLogger(final Global global) {
+        return global.getLogger(this.getClass());
     }
 
     /**
@@ -400,8 +409,8 @@
     }
 
     MethodHandle compileRestOfMethod(final MethodType fnCallSiteType, final Map<Integer, Type> invalidatedProgramPoints, final int[] continuationEntryPoints, final ScriptObject runtimeScope, final FunctionNodeTransform tr) {
-        if (LOG.isEnabled()) {
-            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";
@@ -434,8 +443,8 @@
         final String scriptName = RECOMPILATION_PREFIX + RECOMPILE_ID.incrementAndGet();
         final MethodType fnCallSiteType = actualCallSiteType == null ? null : actualCallSiteType.changeParameterType(0, ScriptFunction.class);
 
-        if (LOG.isEnabled()) {
-            LOG.info(reason, " of '", functionName, "' signature: ", fnCallSiteType, " ", stringifyInvalidations(invalidatedProgramPoints));
+        if (log.isEnabled()) {
+            log.info(reason, " of '", functionName, "' signature: ", fnCallSiteType, " ", stringifyInvalidations(invalidatedProgramPoints));
         }
 
         FunctionNode fn = tr.apply(reparse(scriptName));
--- a/nashorn/src/jdk/nashorn/internal/runtime/ScriptEnvironment.java	Tue Apr 22 14:09:46 2014 +0200
+++ b/nashorn/src/jdk/nashorn/internal/runtime/ScriptEnvironment.java	Wed Apr 23 16:13:47 2014 +0200
@@ -26,15 +26,20 @@
 package jdk.nashorn.internal.runtime;
 
 import java.io.PrintWriter;
+import java.util.HashMap;
 import java.util.HashSet;
 import java.util.List;
 import java.util.Locale;
+import java.util.Map;
 import java.util.Set;
 import java.util.StringTokenizer;
 import java.util.TimeZone;
+
 import jdk.nashorn.internal.codegen.Namespace;
 import jdk.nashorn.internal.runtime.linker.NashornCallSiteDescriptor;
 import jdk.nashorn.internal.runtime.options.KeyValueOption;
+import jdk.nashorn.internal.runtime.options.LoggingOption;
+import jdk.nashorn.internal.runtime.options.LoggingOption.LoggerInfo;
 import jdk.nashorn.internal.runtime.options.Option;
 import jdk.nashorn.internal.runtime.options.Options;
 
@@ -197,6 +202,9 @@
     /** Local for error messages */
     public final Locale _locale;
 
+    /** Logging */
+    public final Map<String, LoggerInfo> _loggers;
+
     /**
      * Constructor
      *
@@ -310,6 +318,9 @@
         } else {
             this._locale = Locale.getDefault();
         }
+
+        final LoggingOption lo = (LoggingOption)options.get("log");
+        this._loggers = lo == null ? new HashMap<String, LoggerInfo>() : lo.getLoggers();
     }
 
     /**
@@ -367,4 +378,15 @@
         return options.getArguments();
     }
 
+    /**
+     * Check if there is a logger registered for a particular name: typically
+     * the "name" attribute of a Loggable annotation on a class
+     *
+     * @param name logger name
+     * @return true, if a logger exists for that name, false otherwise
+     */
+    public boolean hasLogger(final String name) {
+        return _loggers.get(name) != null;
+    }
+
 }
--- a/nashorn/src/jdk/nashorn/internal/runtime/ScriptFunction.java	Tue Apr 22 14:09:46 2014 +0200
+++ b/nashorn/src/jdk/nashorn/internal/runtime/ScriptFunction.java	Wed Apr 23 16:13:47 2014 +0200
@@ -681,7 +681,7 @@
         if (isApplyToCall) {
             if (isFailedApplyToCall) {
                 //take the real arguments that were passed to a call and force them into the apply instead
-                ApplySpecialization.getLogger().info("Collection arguments to revert call to apply in " + appliedFn);
+                Global.instance().getLogger(ApplySpecialization.class).info("Collection arguments to revert call to apply in " + appliedFn);
                 inv = MH.asCollector(inv, Object[].class, realArgCount);
             } else {
                 appliedInvocation = appliedInvocation.addSwitchPoint(applyToCallSwitchPoint);
--- a/nashorn/src/jdk/nashorn/internal/runtime/ScriptObject.java	Tue Apr 22 14:09:46 2014 +0200
+++ b/nashorn/src/jdk/nashorn/internal/runtime/ScriptObject.java	Wed Apr 23 16:13:47 2014 +0200
@@ -918,7 +918,7 @@
                 if (property instanceof UserAccessorProperty) {
                     ((UserAccessorProperty)property).setAccessors(this, getMap(), null);
                 }
-                GlobalConstants.instance().delete(property.getKey());
+                GlobalConstants.instance(Global.instance()).delete(property.getKey());
                 return true;
             }
         }
@@ -1930,7 +1930,7 @@
             }
         }
 
-        final GuardedInvocation cinv = GlobalConstants.instance().findGetMethod(find, this, desc, request, operator);
+        final GuardedInvocation cinv = GlobalConstants.instance(Global.instance()).findGetMethod(find, this, desc, request, operator);
         if (cinv != null) {
             return cinv;
         }
@@ -1971,7 +1971,7 @@
     }
 
     private static GuardedInvocation findMegaMorphicGetMethod(final CallSiteDescriptor desc, final String name, final boolean isMethod, final boolean isScope) {
-        ObjectClassGenerator.getLogger().warning("Megamorphic getter: " + desc + " " + name + " " +isMethod);
+        Global.instance().getLogger(ObjectClassGenerator.class).warning("Megamorphic getter: " + desc + " " + name + " " +isMethod);
         final MethodHandle invoker = MH.insertArguments(MEGAMORPHIC_GET, 1, name, isMethod, isScope);
         final MethodHandle guard   = getScriptObjectGuard(desc.getMethodType(), true);
         return new GuardedInvocation(invoker, guard);
@@ -2121,7 +2121,7 @@
 
         final GuardedInvocation inv = new SetMethodCreator(this, find, desc, explicitInstanceOfCheck).createGuardedInvocation();
 
-        final GuardedInvocation cinv = GlobalConstants.instance().findSetMethod(find, this, inv, desc, request);
+        final GuardedInvocation cinv = GlobalConstants.instance(Global.instance()).findSetMethod(find, this, inv, desc, request);
         if (cinv != null) {
             return cinv;
         }
--- a/nashorn/src/jdk/nashorn/internal/runtime/arrays/ContinuousArrayData.java	Tue Apr 22 14:09:46 2014 +0200
+++ b/nashorn/src/jdk/nashorn/internal/runtime/arrays/ContinuousArrayData.java	Wed Apr 23 16:13:47 2014 +0200
@@ -41,18 +41,22 @@
 import jdk.internal.dynalink.linker.GuardedInvocation;
 import jdk.internal.dynalink.linker.LinkRequest;
 import jdk.nashorn.internal.lookup.Lookup;
-import jdk.nashorn.internal.runtime.DebugLogger;
+import jdk.nashorn.internal.objects.Global;
 import jdk.nashorn.internal.runtime.ScriptObject;
 import jdk.nashorn.internal.runtime.linker.NashornCallSiteDescriptor;
+import jdk.nashorn.internal.runtime.logging.DebugLogger;
+import jdk.nashorn.internal.runtime.logging.Loggable;
+import jdk.nashorn.internal.runtime.logging.Logger;
 
 /**
  * Interface implemented by all arrays that are directly accessible as underlying
  * native arrays
  */
-public abstract class ContinuousArrayData extends ArrayData {
+@Logger(name="arrays")
+public abstract class ContinuousArrayData extends ArrayData implements Loggable {
 
     /** Logger for array accessor linkage */
-    protected static DebugLogger LOG = new DebugLogger("arrays");
+    protected final DebugLogger log;
 
     private SwitchPoint sp;
 
@@ -62,6 +66,17 @@
      */
     protected ContinuousArrayData(final long length) {
         super(length);
+        this.log = initLogger(Global.instance());
+    }
+
+    @Override
+    public DebugLogger getLogger() {
+        return log;
+    }
+
+    @Override
+    public DebugLogger initLogger(final Global global) {
+        return global.getLogger(this.getClass());
     }
 
     private SwitchPoint ensureSwitchPointExists() {
@@ -234,8 +249,8 @@
             }
         }
 
-        if (LOG.isEnabled()) {
-            LOG.info(getClass().getSimpleName() + ": Missed fast GETTER " + clazz.getSimpleName() + " " + desc + " " + " line:" + DynamicLinker.getLinkedCallSiteLocation().getLineNumber());
+        if (log.isEnabled()) {
+            log.info(getClass().getSimpleName() + ": Missed fast GETTER " + clazz.getSimpleName() + " " + desc + " " + " line:" + DynamicLinker.getLinkedCallSiteLocation().getLineNumber());
         }
 
         return null;
@@ -275,8 +290,8 @@
             }
         }
 
-        if (LOG.isEnabled()) {
-            LOG.info(getClass().getSimpleName() + ": Missed fast SETTER " + clazz.getSimpleName() + " " + desc + " " + " line:" + DynamicLinker.getLinkedCallSiteLocation().getLineNumber());
+        if (log.isEnabled()) {
+            log.info(getClass().getSimpleName() + ": Missed fast SETTER " + clazz.getSimpleName() + " " + desc + " " + " line:" + DynamicLinker.getLinkedCallSiteLocation().getLineNumber());
         }
 
         return null;
--- a/nashorn/src/jdk/nashorn/internal/runtime/arrays/TypedArrayData.java	Tue Apr 22 14:09:46 2014 +0200
+++ b/nashorn/src/jdk/nashorn/internal/runtime/arrays/TypedArrayData.java	Wed Apr 23 16:13:47 2014 +0200
@@ -190,8 +190,8 @@
             return inv;
         }
 
-        if (LOG.isEnabled()) {
-            LOG.info(clazz.getSimpleName() + ": Missed fast GETTER " + clazz.getSimpleName() + " " + desc + " " + " line:" + DynamicLinker.getLinkedCallSiteLocation().getLineNumber());
+        if (log.isEnabled()) {
+            log.info(clazz.getSimpleName() + ": Missed fast GETTER " + clazz.getSimpleName() + " " + desc + " " + " line:" + DynamicLinker.getLinkedCallSiteLocation().getLineNumber());
         }
 
         return null;
@@ -205,8 +205,8 @@
             return inv;
         }
 
-        if (LOG.isEnabled()) {
-            LOG.info(clazz.getSimpleName() + ": Missed fast SETTER " + clazz.getSimpleName() + " " + desc + " " + " line:" + DynamicLinker.getLinkedCallSiteLocation().getLineNumber());
+        if (log.isEnabled()) {
+            log.info(clazz.getSimpleName() + ": Missed fast SETTER " + clazz.getSimpleName() + " " + desc + " " + " line:" + DynamicLinker.getLinkedCallSiteLocation().getLineNumber());
         }
 
         return null;
--- a/nashorn/src/jdk/nashorn/internal/runtime/events/RecompilationEvent.java	Tue Apr 22 14:09:46 2014 +0200
+++ b/nashorn/src/jdk/nashorn/internal/runtime/events/RecompilationEvent.java	Wed Apr 23 16:13:47 2014 +0200
@@ -27,6 +27,7 @@
 
 import java.util.logging.Level;
 
+import jdk.nashorn.internal.objects.Global;
 import jdk.nashorn.internal.runtime.RecompilableScriptFunctionData;
 import jdk.nashorn.internal.runtime.RewriteException;
 
@@ -50,9 +51,10 @@
      *     {@link RewriteException#getReturnValueNonDestructive()} public, we pass it as
      *     an extra parameter, rather than querying the getter from another package.
      */
+    @SuppressWarnings("javadoc")
     public RecompilationEvent(final Level level, final RewriteException rewriteException, final Object returnValue) {
         super(level, rewriteException);
-        assert RecompilableScriptFunctionData.getLogger().isEnabled() :
+        assert Global.instance().getLogger(RecompilableScriptFunctionData.class).isEnabled() :
             "Unit test/instrumentation purpose only: RecompilationEvent instances should not be created without '--log=recompile', or we will leak memory in the general case";
         this.returnValue = returnValue;
     }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/src/jdk/nashorn/internal/runtime/logging/DebugLogger.java	Wed Apr 23 16:13:47 2014 +0200
@@ -0,0 +1,598 @@
+/*
+ * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.nashorn.internal.runtime.logging;
+
+import java.io.PrintWriter;
+import java.security.AccessControlContext;
+import java.security.AccessController;
+import java.security.Permissions;
+import java.security.PrivilegedAction;
+import java.security.ProtectionDomain;
+import java.util.logging.ConsoleHandler;
+import java.util.logging.Formatter;
+import java.util.logging.Handler;
+import java.util.logging.Level;
+import java.util.logging.LogRecord;
+import java.util.logging.Logger;
+import java.util.logging.LoggingPermission;
+
+import jdk.nashorn.internal.objects.Global;
+import jdk.nashorn.internal.runtime.Context;
+import jdk.nashorn.internal.runtime.ScriptFunction;
+import jdk.nashorn.internal.runtime.ScriptObject;
+import jdk.nashorn.internal.runtime.ScriptRuntime;
+import jdk.nashorn.internal.runtime.events.RuntimeEvent;
+
+/**
+ * Wrapper class for Logging system. This is how you are supposed to register a logger and use it
+ */
+
+public final class DebugLogger {
+
+    /** Disabled logger used for all loggers that need an instance, but shouldn't output anything */
+    public static final DebugLogger DISABLED_LOGGER = new DebugLogger("disabled", Level.OFF, false);
+
+    private final Logger  logger;
+    private final boolean isEnabled;
+
+    private int indent;
+
+    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
+     *
+     * A logger can be paired with a property, e.g. {@code --log:codegen:info} is equivalent to {@code -Dnashorn.codegen.log}
+     *
+     * @param loggerName  name of logger - this is the unique key with which it can be identified
+     * @param loggerLevel level of the logger
+     * @param isQuiet     is this a quiet logger, i.e. enabled for things like e.g. RuntimeEvent:s, but quiet otherwise
+     */
+    public DebugLogger(final String loggerName, final Level loggerLevel, final boolean isQuiet) {
+        this.logger  = instantiateLogger(loggerName, loggerLevel);
+        this.isQuiet = isQuiet;
+        assert logger != null;
+        this.isEnabled = getLevel() != Level.OFF;
+    }
+
+    private static Logger instantiateLogger(final String name, final Level level) {
+        final Logger logger = java.util.logging.Logger.getLogger(name);
+        AccessController.doPrivileged(new PrivilegedAction<Void>() {
+            @Override
+            public Void run() {
+                for (final Handler h : logger.getHandlers()) {
+                    logger.removeHandler(h);
+                }
+
+                logger.setLevel(level);
+                logger.setUseParentHandlers(false);
+                final Handler c = new ConsoleHandler();
+
+                c.setFormatter(new Formatter() {
+                    @Override
+                    public String format(final LogRecord record) {
+                        final StringBuilder sb = new StringBuilder();
+
+                        sb.append('[')
+                           .append(record.getLoggerName())
+                           .append("] ")
+                           .append(record.getMessage())
+                           .append('\n');
+
+                        return sb.toString();
+                    }
+                });
+                logger.addHandler(c);
+                c.setLevel(level);
+                return null;
+            }
+        }, createLoggerControlAccCtxt());
+
+        return logger;
+    }
+
+    /**
+     * Do not currently support chaining this with parent logger. Logger level null
+     * means disabled
+     * @return level
+     */
+    public Level getLevel() {
+        return logger.getLevel() == null ? Level.OFF : logger.getLevel();
+    }
+
+    /**
+     * Get the output writer for the logger. Loggers always default to
+     * stderr for output as they are used mainly to output debug info
+     *
+     * Can be inherited so this should not be static.
+     *
+     * @return print writer for log output.
+     */
+    @SuppressWarnings("static-method")
+    public PrintWriter getOutputStream() {
+        return Context.getCurrentErr();
+    }
+
+    /**
+     * 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' ? quote : startQuote) + str + (endQuote == '\0' ? quote : endQuote);
+    }
+
+    /**
+     * Check if the logger is enabled
+     * @return true if enabled
+     */
+    public boolean isEnabled() {
+        return isEnabled;
+    }
+
+    /**
+     * If you want to change the indent level of your logger, call indent with a new position.
+     * Positions start at 0 and are increased by one for a new "tab"
+     *
+     * @param pos indent position
+     */
+    public void indent(final int pos) {
+        if (isEnabled) {
+           indent += pos * INDENT_SPACE;
+        }
+    }
+
+    /**
+     * Add an indent position
+     */
+    public void indent() {
+        indent += INDENT_SPACE;
+    }
+
+    /**
+     * Unindent a position
+     */
+    public void unindent() {
+        indent -= INDENT_SPACE;
+        if (indent < 0) {
+            indent = 0;
+        }
+    }
+
+    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
+     *
+     * The higher the level, the more severe the warning
+     *
+     * @param level logging level
+     * @return true if level is above the given one
+     */
+    public boolean levelCoarserThan(final Level level) {
+        return getLevel().intValue() > level.intValue();
+    }
+
+    /**
+     * Check if the logger is above or equal to the level
+     * of detail given
+     * @see java.util.logging.Level
+     *
+     * The higher the level, the more severe the warning
+     *
+     * @param level logging level
+     * @return true if level is above the given one
+     */
+    public boolean levelCoarserThanOrEqual(final Level level) {
+        return getLevel().intValue() >= level.intValue();
+    }
+
+    /**
+     * Check if the logger is below the level of detail given
+     * @see java.util.logging.Level
+     *
+     * The higher the level, the more severe the warning
+     *
+     * @param level logging level
+     * @return true if level is above the given one
+     */
+    public boolean levelFinerThan(final Level level) {
+        return getLevel().intValue() < level.intValue();
+    }
+
+    /**
+     * Check if the logger is below or equal to the level
+     * of detail given
+     * @see java.util.logging.Level
+     *
+     * The higher the level, the more severe the warning
+     *
+     * @param level logging level
+     * @return true if level is above the given one
+     */
+    public boolean levelFinerThanOrEqual(final Level level) {
+        return getLevel().intValue() <= level.intValue();
+    }
+
+    /**
+     * Shorthand for outputting a log string as log level {@link java.util.logging.Level#FINEST} on this logger
+     * @param str the string to log
+     */
+    public void finest(final String str) {
+        log(Level.FINEST, str);
+    }
+
+    /**
+     * 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
+     */
+    public void finest(final Object... objs) {
+        log(Level.FINEST, objs);
+    }
+
+    /**
+     * 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
+     */
+    public void finer(final String str) {
+        log(Level.FINER, str);
+    }
+
+    /**
+     * 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) {
+        log(Level.FINER, objs);
+    }
+
+    /**
+     * 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
+     */
+    public void fine(final String str) {
+        log(Level.FINE, str);
+    }
+
+    /**
+     * 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) {
+        log(Level.FINE, objs);
+    }
+
+    /**
+     * 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
+     */
+    public void config(final String str) {
+        log(Level.CONFIG, str);
+    }
+
+    /**
+     * 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) {
+        log(Level.CONFIG, objs);
+    }
+
+    /**
+     * 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
+     */
+    public void info(final String str) {
+        log(Level.INFO, str);
+    }
+
+    /**
+     * 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
+     */
+    public void info(final Object... objs) {
+        log(Level.INFO, objs);
+    }
+
+    /**
+     * 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
+     */
+    public void warning(final String str) {
+        log(Level.WARNING, str);
+    }
+
+    /**
+     * 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
+     */
+    public void warning(final Object... objs) {
+        log(Level.WARNING, objs);
+    }
+
+    /**
+     * 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
+     */
+    public void severe(final String str) {
+        log(Level.SEVERE, str);
+    }
+
+    /**
+     * 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
+     */
+    public void severe(final Object... objs) {
+        log(Level.SEVERE, objs);
+    }
+
+    /**
+     * 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
+     *
+     * @param level minimum log level required for logging to take place
+     * @param str   string to log
+     */
+    public void log(final Level level, final String str) {
+        if (isEnabled && !isQuiet) {
+            final StringBuilder sb = new StringBuilder();
+            for (int i = 0 ; i < indent ; i++) {
+                sb.append(' ');
+            }
+            sb.append(str);
+            logger.log(level, sb.toString());
+        }
+    }
+
+    /**
+     * Output log line on this logger at a given level of verbosity
+     * @see java.util.logging.Level
+     *
+     * @param level minimum log level required for logging to take place
+     * @param objs  objects for which to invoke toString and concatenate to log
+     */
+    public void log(final Level level, final Object... objs) {
+        if (isEnabled && !isQuiet) {
+            final StringBuilder sb = new StringBuilder();
+            for (final Object obj : objs) {
+                sb.append(obj);
+            }
+            log(level, sb.toString());
+        }
+    }
+
+    /**
+     * Access control context for logger level and instantiation permissions
+     * @return access control context
+     */
+    private static AccessControlContext createLoggerControlAccCtxt() {
+        final Permissions perms = new Permissions();
+        perms.add(new LoggingPermission("control", null));
+        return new AccessControlContext(new ProtectionDomain[] { new ProtectionDomain(null, perms) });
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/src/jdk/nashorn/internal/runtime/logging/Loggable.java	Wed Apr 23 16:13:47 2014 +0200
@@ -0,0 +1,56 @@
+/*
+ * 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.logging;
+
+import jdk.nashorn.internal.objects.Global;
+
+/**
+ * Interface implemented by classes that are loggable.
+ * Their instances will provide functionality for initializing
+ * a logger (usually by asking Global for it, with a reference
+ * to this.getClass()) and a method to return the logger in
+ * use
+ *
+ * Typically a class implementing this interface also has the
+ * Logger annotation
+ *
+ * @see Logger
+ */
+public interface Loggable {
+    /**
+     * Initialize a logger, by asking Global to get or create it
+     * and then keep it in a table by name
+     *
+     * @param global global
+     * @return the initialized logger
+     */
+    public DebugLogger initLogger(final Global global);
+
+    /**
+     * Return the logger in use
+     * @return logger
+     */
+    public DebugLogger getLogger();
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/src/jdk/nashorn/internal/runtime/logging/Logger.java	Wed Apr 23 16:13:47 2014 +0200
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2010, 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  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.logging;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/**
+ * This annotation is associated with a class that has a logger.
+ * It contains a name property of the logger name. e.g. a class
+ * whose logger can be initialized by --log:fields, should be
+ * annotated @Logger(name="fields"). Multiple classes can have
+ * the same annotation, which will make them use the same logger
+ * object. Usually a class with this annotation is also a Loggable,
+ * but it is not a hard demand
+ *
+ * @see Loggable
+ */
+@Retention(RetentionPolicy.RUNTIME)
+public @interface Logger {
+    /**
+     * Get the name of the logger
+     * @return logger name
+     */
+    public String name() default "";
+}
--- a/nashorn/src/jdk/nashorn/internal/runtime/options/KeyValueOption.java	Tue Apr 22 14:09:46 2014 +0200
+++ b/nashorn/src/jdk/nashorn/internal/runtime/options/KeyValueOption.java	Wed Apr 23 16:13:47 2014 +0200
@@ -36,7 +36,7 @@
  *
  * {@code --log=module1:level1,module2:level2... }
  */
-public final class KeyValueOption extends Option<String> {
+public class KeyValueOption extends Option<String> {
     /**
      * Map of keys given
      */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/src/jdk/nashorn/internal/runtime/options/LoggingOption.java	Wed Apr 23 16:13:47 2014 +0200
@@ -0,0 +1,133 @@
+/*
+ * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.nashorn.internal.runtime.options;
+
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Locale;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.logging.Level;
+
+/**
+ * Class that collects logging options like --log=compiler:finest,fields,recompile:fine into
+ * a map form that can be used to instantiate loggers in the Global object on demand
+ */
+public class LoggingOption extends KeyValueOption {
+
+    /**
+     * Logging info. Basically a logger name maps to this,
+     * which is a tuple of log level and the "is quiet" flag,
+     * which is a special log level used to collect RuntimeEvents
+     * only, but not output anything
+     */
+    public static class LoggerInfo {
+        private final Level level;
+        private final boolean isQuiet;
+
+        LoggerInfo(final Level level, final boolean isQuiet) {
+            this.level = level;
+            this.isQuiet = isQuiet;
+        }
+
+        /**
+         * Get the log level
+         * @return log level
+         */
+        public Level getLevel() {
+            return level;
+        }
+
+        /**
+         * Get the quiet flag
+         * @return true if quiet flag is set
+         */
+        public boolean isQuiet() {
+            return isQuiet;
+        }
+    }
+
+    private final Map<String, LoggerInfo> loggers = new HashMap<>();
+
+    LoggingOption(final String value) {
+        super(value);
+        initialize(getValues());
+    }
+
+    /**
+     * Return the logger info collected from this command line option
+     *
+     * @return map of logger name to logger info
+     */
+    public Map<String, LoggerInfo> getLoggers() {
+        return Collections.unmodifiableMap(loggers);
+    }
+
+    /**
+     * Initialization function that is called to instantiate the logging system. It takes
+     * logger names (keys) and logging labels respectively
+     *
+     * @param map a map where the key is a logger name and the value a logging level
+     * @throws IllegalArgumentException if level or names cannot be parsed
+     */
+    private void initialize(final Map<String, String> logMap) throws IllegalArgumentException {
+        try {
+            for (final Entry<String, String> entry : logMap.entrySet()) {
+                Level level;
+                final String name        = lastPart(entry.getKey());
+                final String levelString = entry.getValue().toUpperCase(Locale.ENGLISH);
+                final boolean isQuiet;
+
+                if ("".equals(levelString)) {
+                    level = Level.INFO;
+                    isQuiet = false;
+                } else if ("QUIET".equals(levelString)) {
+                    level = Level.INFO;
+                    isQuiet = true;
+                } else {
+                    level = Level.parse(levelString);
+                    isQuiet = false;
+                }
+
+                loggers.put(name, new LoggerInfo(level, isQuiet));
+            }
+        } catch (final IllegalArgumentException | SecurityException e) {
+            throw e;
+        }
+    }
+
+
+
+    private static String lastPart(final String packageName) {
+        final String[] parts = packageName.split("\\.");
+        if (parts.length == 0) {
+            return packageName;
+        }
+        return parts[parts.length - 1];
+    }
+
+
+}
--- a/nashorn/src/jdk/nashorn/internal/runtime/options/Options.java	Tue Apr 22 14:09:46 2014 +0200
+++ b/nashorn/src/jdk/nashorn/internal/runtime/options/Options.java	Wed Apr 23 16:13:47 2014 +0200
@@ -48,7 +48,6 @@
 import java.util.TimeZone;
 import java.util.TreeMap;
 import java.util.TreeSet;
-import jdk.nashorn.internal.runtime.Logging;
 import jdk.nashorn.internal.runtime.QuotedStringTokenizer;
 
 /**
@@ -532,9 +531,7 @@
         case "keyvalues":
             return new KeyValueOption(value);
         case "log":
-            final KeyValueOption kv = new KeyValueOption(value);
-            Logging.initialize(kv.getValues());
-            return kv;
+            return new LoggingOption(value);
         case "boolean":
             return new Option<>(value != null && Boolean.parseBoolean(value));
         case "integer":
--- a/nashorn/src/jdk/nashorn/tools/Shell.java	Tue Apr 22 14:09:46 2014 +0200
+++ b/nashorn/src/jdk/nashorn/tools/Shell.java	Wed Apr 23 16:13:47 2014 +0200
@@ -178,7 +178,6 @@
      *
      * @return null if there are problems with option parsing.
      */
-    @SuppressWarnings("resource")
     private static Context makeContext(final InputStream in, final OutputStream out, final OutputStream err, final String[] args) {
         final PrintStream pout = out instanceof PrintStream ? (PrintStream) out : new PrintStream(out);
         final PrintStream perr = err instanceof PrintStream ? (PrintStream) err : new PrintStream(err);
@@ -392,7 +391,6 @@
      * @param global  global scope object to use
      * @return return code
      */
-    @SuppressWarnings("resource")
     private static int readEvalPrint(final Context context, final Global global) {
         final String prompt = bundle.getString("shell.prompt");
         final BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
--- a/nashorn/test/src/jdk/nashorn/internal/parser/ParserTest.java	Tue Apr 22 14:09:46 2014 +0200
+++ b/nashorn/test/src/jdk/nashorn/internal/parser/ParserTest.java	Wed Apr 23 16:13:47 2014 +0200
@@ -50,7 +50,7 @@
         public boolean exclude(File file, String content);
     }
 
-    private void log(String msg) {
+    private static void log(final String msg) {
         org.testng.Reporter.log(msg, true);
     }
 
@@ -63,7 +63,7 @@
         options.set("parse.only", true);
         options.set("scripting", true);
 
-        ErrorManager errors = new ErrorManager();
+        final ErrorManager errors = new ErrorManager();
         this.context = new Context(options, errors, Thread.currentThread().getContextClassLoader());
     }
 
@@ -153,7 +153,7 @@
                 }
             };
             errors.setLimit(0);
-            final Source            source   = new Source(file.getAbsolutePath(), buffer);
+            final Source source = new Source(file.getAbsolutePath(), buffer);
             new Parser(context.getEnv(), source, errors, context.getEnv()._strict).parse();
             if (errors.getNumberOfErrors() > 0) {
                 log("Parse failed: " + file.getAbsolutePath());
@@ -162,6 +162,7 @@
                 passed++;
             }
         } catch (final Throwable exp) {
+            exp.printStackTrace();
             log("Parse failed: " + file.getAbsolutePath() + " : " + exp);
             if (VERBOSE) {
                 exp.printStackTrace(System.out);
--- a/nashorn/test/src/jdk/nashorn/internal/test/framework/ParallelTestRunner.java	Tue Apr 22 14:09:46 2014 +0200
+++ b/nashorn/test/src/jdk/nashorn/internal/test/framework/ParallelTestRunner.java	Wed Apr 23 16:13:47 2014 +0200
@@ -149,7 +149,7 @@
         }
 
         @Override
-        protected void log(String msg) {
+        protected void log(final String msg) {
             System.err.println(msg);
         }
 
@@ -235,6 +235,7 @@
                             outputFile.write(out.toByteArray());
                             errorFile.write(err.toByteArray());
                         }
+                        ex.printStackTrace();
                         throw ex;
                     }
                 }
@@ -280,6 +281,7 @@
             } catch (final Throwable ex) {
                 result.exception = ex;
                 result.passed = false;
+                ex.printStackTrace();
             }
             return result;
         }
@@ -306,12 +308,12 @@
 
         final TestFactory<ScriptRunnable> testFactory = new TestFactory<ScriptRunnable>() {
             @Override
-            public ScriptRunnable createTest(String framework, File testFile, List<String> engineOptions, Map<String, String> testOptions, List<String> arguments) {
+            public ScriptRunnable createTest(final String framework, final File testFile, final List<String> engineOptions, final Map<String, String> testOptions, final List<String> arguments) {
                 return new ScriptRunnable(framework, testFile, engineOptions, testOptions, arguments);
             }
 
             @Override
-            public void log(String msg) {
+            public void log(final String msg) {
                 System.err.println(msg);
             }
         };
@@ -431,7 +433,9 @@
     public static void main(final String[] args) throws Exception {
         parseArgs(args);
 
-        while(new ParallelTestRunner().run());
+        while(new ParallelTestRunner().run()) {
+            ;
+        }
     }
 
     private static void parseArgs(final String[] args) {