From 62e846549d6d60adf90233aef7bd3ca46d3d83ec Mon Sep 17 00:00:00 2001 From: Athijegannathan Sundararajan Date: Thu, 14 Aug 2014 18:54:54 +0530 Subject: [PATCH] 8055107: Extension directives to turn on callsite profiling, tracing, AST print and other debug features locally Reviewed-by: attila, jlaskey --- .../internal/codegen/CodeGenerator.java | 23 ++- .../internal/codegen/CompilationPhase.java | 4 +- .../jdk/nashorn/internal/ir/FunctionNode.java | 100 ++++++++++ .../jdk/nashorn/internal/parser/Parser.java | 23 ++- .../jdk/nashorn/internal/runtime/Context.java | 4 +- nashorn/test/script/trusted/JDK-8055107.js | 179 ++++++++++++++++++ 6 files changed, 315 insertions(+), 18 deletions(-) create mode 100644 nashorn/test/script/trusted/JDK-8055107.js diff --git a/nashorn/src/jdk/nashorn/internal/codegen/CodeGenerator.java b/nashorn/src/jdk/nashorn/internal/codegen/CodeGenerator.java index 73dfdaa41be..35ad298aaaa 100644 --- a/nashorn/src/jdk/nashorn/internal/codegen/CodeGenerator.java +++ b/nashorn/src/jdk/nashorn/internal/codegen/CodeGenerator.java @@ -289,7 +289,7 @@ final class CodeGenerator extends NodeOperatorVisitor" : function.getIdent().getName())); + printSymbols(block, function, (isFunctionBody ? "Function " : "Block in ") + (function.getIdent() == null ? "" : function.getIdent().getName())); } /** @@ -4106,19 +4106,18 @@ final class CodeGenerator extends NodeOperatorVisitor"); + } + out.println(); } - - final PrintWriter out = compiler.getScriptEnvironment().getErr(); - out.println("[BLOCK in '" + ident + "']"); - if (!block.printSymbols(out)) { - out.println(""); - } - out.println(); } diff --git a/nashorn/src/jdk/nashorn/internal/codegen/CompilationPhase.java b/nashorn/src/jdk/nashorn/internal/codegen/CompilationPhase.java index fde3986545b..5fba3c1b1d4 100644 --- a/nashorn/src/jdk/nashorn/internal/codegen/CompilationPhase.java +++ b/nashorn/src/jdk/nashorn/internal/codegen/CompilationPhase.java @@ -280,12 +280,12 @@ enum CompilationPhase { final PrintWriter err = senv.getErr(); //TODO separate phase for the debug printouts for abstraction and clarity - if (senv._print_lower_ast) { + if (senv._print_lower_ast || fn.getFlag(FunctionNode.IS_PRINT_LOWER_AST)) { err.println("Lower AST for: " + quote(newFunctionNode.getName())); err.println(new ASTWriter(newFunctionNode)); } - if (senv._print_lower_parse) { + if (senv._print_lower_parse || fn.getFlag(FunctionNode.IS_PRINT_LOWER_PARSE)) { err.println("Lower AST for: " + quote(newFunctionNode.getName())); err.println(new PrintVisitor(newFunctionNode)); } diff --git a/nashorn/src/jdk/nashorn/internal/ir/FunctionNode.java b/nashorn/src/jdk/nashorn/internal/ir/FunctionNode.java index 5643b488ff5..711e9add322 100644 --- a/nashorn/src/jdk/nashorn/internal/ir/FunctionNode.java +++ b/nashorn/src/jdk/nashorn/internal/ir/FunctionNode.java @@ -25,6 +25,8 @@ package jdk.nashorn.internal.ir; +import static jdk.nashorn.internal.runtime.linker.NashornCallSiteDescriptor.*; + import java.util.Collections; import java.util.EnumSet; import java.util.HashSet; @@ -228,6 +230,37 @@ public final class FunctionNode extends LexicalContextExpression implements Flag /** Is this declared in a dynamic context */ public static final int IN_DYNAMIC_CONTEXT = 1 << 17; + /** + * The following flags are derived from directive comments within this function. + * Note that even IS_STRICT is one such flag but that requires special handling. + */ + + // parser, lower debugging this function + public static final int IS_PRINT_PARSE = 1 << 18; + public static final int IS_PRINT_LOWER_PARSE = 1 << 19; + public static final int IS_PRINT_AST = 1 << 20; + public static final int IS_PRINT_LOWER_AST = 1 << 21; + public static final int IS_PRINT_SYMBOLS = 1 << 22; + + /** profile callsites in this function? */ + public static final int IS_PROFILE = 1 << 23; + + // callsite tracing, profiling within this function + /** trace callsite enterexit in this function? */ + public static final int IS_TRACE_ENTEREXIT = 1 << 24; + + /** trace callsite misses in this function? */ + public static final int IS_TRACE_MISSES = 1 << 25; + + /** trace callsite values in this function? */ + public static final int IS_TRACE_VALUES = 1 << 26; + + /** extension callsite flags mask */ + public static final int EXTENSION_CALLSITE_FLAGS = IS_PRINT_PARSE | + IS_PRINT_LOWER_PARSE | IS_PRINT_AST | IS_PRINT_LOWER_AST | + IS_PRINT_SYMBOLS | IS_PROFILE | IS_TRACE_ENTEREXIT | + IS_TRACE_MISSES | IS_TRACE_VALUES; + /** Does this function or any nested functions contain an eval? */ private static final int HAS_DEEP_EVAL = HAS_EVAL | HAS_NESTED_EVAL; @@ -353,6 +386,41 @@ public final class FunctionNode extends LexicalContextExpression implements Flag return Node.accept(visitor, parameters); } + /** + * Get additional callsite flags to be used specific to this function. + * + * @return callsite flags + */ + public int getCallSiteFlags() { + int callsiteFlags = 0; + if (getFlag(IS_STRICT)) { + callsiteFlags |= CALLSITE_STRICT; + } + + // quick check for extension callsite flags turned on by directives. + if ((flags & EXTENSION_CALLSITE_FLAGS) == 0) { + return callsiteFlags; + } + + if (getFlag(IS_PROFILE)) { + callsiteFlags |= CALLSITE_PROFILE; + } + + if (getFlag(IS_TRACE_MISSES)) { + callsiteFlags |= CALLSITE_TRACE | CALLSITE_TRACE_MISSES; + } + + if (getFlag(IS_TRACE_VALUES)) { + callsiteFlags |= CALLSITE_TRACE | CALLSITE_TRACE_ENTEREXIT | CALLSITE_TRACE_VALUES; + } + + if (getFlag(IS_TRACE_ENTEREXIT)) { + callsiteFlags |= CALLSITE_TRACE | CALLSITE_TRACE_ENTEREXIT; + } + + return callsiteFlags; + } + /** * Get the source for this function * @return the source @@ -389,6 +457,38 @@ public final class FunctionNode extends LexicalContextExpression implements Flag return explicitURL != null ? explicitURL : source.getName(); } + /** + * Function to parse nashorn per-function extension directive comments. + * + * @param directive nashorn extension directive string + * @return integer flag for the given directive. + */ + public static int getDirectiveFlag(final String directive) { + switch (directive) { + case "nashorn callsite trace enterexit": + return IS_TRACE_ENTEREXIT; + case "nashorn callsite trace misses": + return IS_TRACE_MISSES; + case "nashorn callsite trace objects": + return IS_TRACE_VALUES; + case "nashorn callsite profile": + return IS_PROFILE; + case "nashorn print parse": + return IS_PRINT_PARSE; + case "nashorn print lower parse": + return IS_PRINT_LOWER_PARSE; + case "nashorn print ast": + return IS_PRINT_AST; + case "nashorn print lower ast": + return IS_PRINT_LOWER_AST; + case "nashorn print symbols": + return IS_PRINT_SYMBOLS; + default: + // unknown/unsupported directive + return 0; + } + } + /** * Returns the line number. * @return the line number. diff --git a/nashorn/src/jdk/nashorn/internal/parser/Parser.java b/nashorn/src/jdk/nashorn/internal/parser/Parser.java index 93869cc00fd..3e0d1e632c6 100644 --- a/nashorn/src/jdk/nashorn/internal/parser/Parser.java +++ b/nashorn/src/jdk/nashorn/internal/parser/Parser.java @@ -106,6 +106,8 @@ import jdk.nashorn.internal.ir.UnaryNode; import jdk.nashorn.internal.ir.VarNode; import jdk.nashorn.internal.ir.WhileNode; import jdk.nashorn.internal.ir.WithNode; +import jdk.nashorn.internal.ir.debug.ASTWriter; +import jdk.nashorn.internal.ir.debug.PrintVisitor; import jdk.nashorn.internal.runtime.Context; import jdk.nashorn.internal.runtime.ErrorManager; import jdk.nashorn.internal.runtime.JSErrorType; @@ -346,9 +348,10 @@ public class Parser extends AbstractParser implements Loggable { expect(EOF); function.setFinish(source.getLength() - 1); - function = restoreFunctionNode(function, token); //commit code function = function.setBody(lc, function.getBody().setNeedsScope(lc)); + + printAST(function); return function; } catch (final Exception e) { handleParseException(e); @@ -800,6 +803,12 @@ loop: verifyStrictIdent(param, "function parameter"); } } + } else if (Context.DEBUG) { + final int flag = FunctionNode.getDirectiveFlag(directive); + if (flag != 0) { + final FunctionNode function = lc.getCurrentFunction(); + lc.setFlag(function, flag); + } } } } @@ -2809,14 +2818,24 @@ loop: lastToken = token; expect(RBRACE); functionNode.setFinish(finish); - } } finally { functionNode = restoreFunctionNode(functionNode, lastToken); } + printAST(functionNode); return functionNode; } + private void printAST(final FunctionNode functionNode) { + if (functionNode.getFlag(FunctionNode.IS_PRINT_AST)) { + env.getErr().println(new ASTWriter(functionNode)); + } + + if (functionNode.getFlag(FunctionNode.IS_PRINT_PARSE)) { + env.getErr().println(new PrintVisitor(functionNode, true, false)); + } + } + private void addFunctionDeclarations(final FunctionNode functionNode) { assert lc.peek() == lc.getFunctionBody(functionNode); VarNode lastDecl = null; diff --git a/nashorn/src/jdk/nashorn/internal/runtime/Context.java b/nashorn/src/jdk/nashorn/internal/runtime/Context.java index 96e0c4e047e..d3d00da1acd 100644 --- a/nashorn/src/jdk/nashorn/internal/runtime/Context.java +++ b/nashorn/src/jdk/nashorn/internal/runtime/Context.java @@ -1104,11 +1104,11 @@ public final class Context { return null; } - if (env._print_ast) { + if (env._print_ast || functionNode.getFlag(FunctionNode.IS_PRINT_AST)) { getErr().println(new ASTWriter(functionNode)); } - if (env._print_parse) { + if (env._print_parse || functionNode.getFlag(FunctionNode.IS_PRINT_PARSE)) { getErr().println(new PrintVisitor(functionNode, true, false)); } } diff --git a/nashorn/test/script/trusted/JDK-8055107.js b/nashorn/test/script/trusted/JDK-8055107.js new file mode 100644 index 00000000000..bcc3cba218b --- /dev/null +++ b/nashorn/test/script/trusted/JDK-8055107.js @@ -0,0 +1,179 @@ +/* + * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/** + * JDK-8055107: Extension directives to turn on callsite profiling, tracing, AST print and other debug features locally + * + * @test + * @option -Dnashorn.debug=true + * @option -scripting + * @run + * @fork + */ + +function runScriptEngine(code) { + var imports = new JavaImporter( + java.io, java.lang, java.util, javax.script); + + with(imports) { + var m = new ScriptEngineManager(); + // get current System.err + var oldErr = System.err; + var baos = new ByteArrayOutputStream(); + var newErr = new PrintStream(baos); + try { + // set new standard err + System.setErr(newErr); + var engine = m.getEngineByName("nashorn"); + engine.eval(code); + newErr.flush(); + return new java.lang.String(baos.toByteArray()); + } finally { + // restore System.err to old value + System.setErr(oldErr); + } + } +} + +// nashorn callsite trace enterexit +var str = runScriptEngine(<