mirror of
https://github.com/openjdk/jdk.git
synced 2026-02-25 17:50:45 +00:00
8055107: Extension directives to turn on callsite profiling, tracing, AST print and other debug features locally
Reviewed-by: attila, jlaskey
This commit is contained in:
parent
dbb42efd61
commit
62e846549d
@ -289,7 +289,7 @@ final class CodeGenerator extends NodeOperatorVisitor<CodeGeneratorLexicalContex
|
||||
* @return the correct flags for a call site in the current function
|
||||
*/
|
||||
int getCallSiteFlags() {
|
||||
return lc.getCurrentFunction().isStrict() ? callSiteFlags | CALLSITE_STRICT : callSiteFlags;
|
||||
return lc.getCurrentFunction().getCallSiteFlags() | callSiteFlags;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1764,7 +1764,7 @@ final class CodeGenerator extends NodeOperatorVisitor<CodeGeneratorLexicalContex
|
||||
}
|
||||
|
||||
// Debugging: print symbols? @see --print-symbols flag
|
||||
printSymbols(block, (isFunctionBody ? "Function " : "Block in ") + (function.getIdent() == null ? "<anonymous>" : function.getIdent().getName()));
|
||||
printSymbols(block, function, (isFunctionBody ? "Function " : "Block in ") + (function.getIdent() == null ? "<anonymous>" : function.getIdent().getName()));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -4106,19 +4106,18 @@ final class CodeGenerator extends NodeOperatorVisitor<CodeGeneratorLexicalContex
|
||||
* Debug code used to print symbols
|
||||
*
|
||||
* @param block the block we are in
|
||||
* @param function the function we are in
|
||||
* @param ident identifier for block or function where applicable
|
||||
*/
|
||||
private void printSymbols(final Block block, final String ident) {
|
||||
if (!compiler.getScriptEnvironment()._print_symbols) {
|
||||
return;
|
||||
private void printSymbols(final Block block, final FunctionNode function, final String ident) {
|
||||
if (compiler.getScriptEnvironment()._print_symbols || function.getFlag(FunctionNode.IS_PRINT_SYMBOLS)) {
|
||||
final PrintWriter out = compiler.getScriptEnvironment().getErr();
|
||||
out.println("[BLOCK in '" + ident + "']");
|
||||
if (!block.printSymbols(out)) {
|
||||
out.println("<no symbols>");
|
||||
}
|
||||
out.println();
|
||||
}
|
||||
|
||||
final PrintWriter out = compiler.getScriptEnvironment().getErr();
|
||||
out.println("[BLOCK in '" + ident + "']");
|
||||
if (!block.printSymbols(out)) {
|
||||
out.println("<no symbols>");
|
||||
}
|
||||
out.println();
|
||||
}
|
||||
|
||||
|
||||
|
||||
@ -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));
|
||||
}
|
||||
|
||||
@ -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.
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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));
|
||||
}
|
||||
}
|
||||
|
||||
179
nashorn/test/script/trusted/JDK-8055107.js
Normal file
179
nashorn/test/script/trusted/JDK-8055107.js
Normal file
@ -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(<<CODE
|
||||
function func() {
|
||||
"nashorn callsite trace enterexit";
|
||||
k();
|
||||
}
|
||||
|
||||
function k() {
|
||||
var x = "hello";
|
||||
}
|
||||
|
||||
func();
|
||||
CODE);
|
||||
|
||||
if (!str.contains(" ENTER ")) {
|
||||
fail("expected 'ENTER' in trace mode output");
|
||||
}
|
||||
|
||||
if (!str.contains(" EXIT ")) {
|
||||
fail("expected 'EXIT' in trace mode output");
|
||||
}
|
||||
|
||||
// nashorn callsite trace objects
|
||||
var str = runScriptEngine(<<CODE
|
||||
"nashorn callsite trace objects";
|
||||
function func(x) {
|
||||
}
|
||||
|
||||
func("hello");
|
||||
CODE);
|
||||
|
||||
if (!str.contains(" ENTER ")) {
|
||||
fail("expected 'ENTER' in trace mode output");
|
||||
}
|
||||
|
||||
if (!str.contains(" EXIT ")) {
|
||||
fail("expected 'EXIT' in trace mode output");
|
||||
}
|
||||
|
||||
if (!str.contains("hello")) {
|
||||
fail("expected argument to be traced in trace objects mode");
|
||||
}
|
||||
|
||||
// nashorn callsite trace misses
|
||||
str = runScriptEngine(<<CODE
|
||||
function f() {
|
||||
"nashorn callsite trace misses";
|
||||
k();
|
||||
}
|
||||
|
||||
function k() {}
|
||||
f();
|
||||
CODE);
|
||||
|
||||
if (!str.contains(" MISS ")) {
|
||||
fail("expected callsite MISS trace messages");
|
||||
}
|
||||
|
||||
// nashorn print lower ast
|
||||
str = runScriptEngine(<<CODE
|
||||
function foo() {
|
||||
"nashorn print lower ast";
|
||||
var x = 'hello';
|
||||
}
|
||||
foo();
|
||||
CODE);
|
||||
|
||||
if (!str.contains("Lower AST for: 'foo'") ||
|
||||
!str.contains("nashorn print lower ast")) {
|
||||
fail("expected Lower AST to be printed for 'foo'");
|
||||
}
|
||||
|
||||
// nashorn print ast
|
||||
str = runScriptEngine(<<CODE
|
||||
function foo() {
|
||||
"nashorn print ast";
|
||||
}
|
||||
CODE);
|
||||
if (!str.contains("[function ") ||
|
||||
!str.contains("nashorn print ast")) {
|
||||
fail("expected AST to be printed");
|
||||
}
|
||||
|
||||
// nashorn print symbols
|
||||
str = runScriptEngine(<<CODE
|
||||
function bar(a) {
|
||||
"nashorn print symbols";
|
||||
if (a) print(a);
|
||||
}
|
||||
|
||||
bar();
|
||||
CODE)
|
||||
|
||||
if (!str.contains("[BLOCK in 'Function bar']")) {
|
||||
fail("expected symbols to be printed for 'bar'");
|
||||
}
|
||||
|
||||
// nashorn print parse
|
||||
str = runScriptEngine(<<CODE
|
||||
"nashorn print parse";
|
||||
|
||||
function func() {}
|
||||
CODE);
|
||||
|
||||
if (!str.contains("function func") ||
|
||||
!str.contains("nashorn print parse")) {
|
||||
fail("expected nashorn print parse output");
|
||||
}
|
||||
|
||||
// nashorn print lower parse
|
||||
str = runScriptEngine(<<CODE
|
||||
"nashorn print lower parse";
|
||||
|
||||
function func() {}
|
||||
|
||||
func()
|
||||
CODE);
|
||||
|
||||
if (!str.contains("function {U%}func") ||
|
||||
!str.contains("nashorn print lower parse")) {
|
||||
fail("expected nashorn print lower parse output");
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user