# HG changeset patch # User lagergren # Date 1367930597 -7200 # Node ID fb1d7ea3e1b66578c284a3a69aa1f28c4a749993 # Parent 544e17632e964d5d8b47be64833341a7fb380ce1 8013914: Removed explicit LineNumberNodes that were too brittle when code moves around, and also introduced unnecessary footprint. Introduced the Statement node and fixed dead code elimination issues that were discovered by the absense of labels for LineNumberNodes. Reviewed-by: jlaskey, attila diff -r 544e17632e96 -r fb1d7ea3e1b6 make/project.properties --- a/make/project.properties Tue May 07 14:36:57 2013 +0200 +++ b/make/project.properties Tue May 07 14:43:17 2013 +0200 @@ -214,7 +214,7 @@ # -XX:+PrintCompilation -XX:+UnlockDiagnosticVMOptions -XX:+PrintNMethods # add '-Dtest.js.outofprocess' to run each test in a new sub-process -run.test.jvmargs.main=-server -Xmx${run.test.xmx} -XX:-TieredCompilation -ea -Dnashorn.debug=true -Dfile.encoding=UTF-8 +run.test.jvmargs.main=-server -Xmx${run.test.xmx} -XX:+TieredCompilation -ea -Dnashorn.debug=true -Dfile.encoding=UTF-8 #-XX:+HeapDumpOnOutOfMemoryError -XX:-UseCompressedKlassPointers -XX:+PrintHeapAtGC -XX:ClassMetaspaceSize=300M run.test.jvmargs.octane.main=-Xms${run.test.xms} ${run.test.jvmargs.main} diff -r 544e17632e96 -r fb1d7ea3e1b6 src/jdk/nashorn/internal/codegen/Attr.java --- a/src/jdk/nashorn/internal/codegen/Attr.java Tue May 07 14:36:57 2013 +0200 +++ b/src/jdk/nashorn/internal/codegen/Attr.java Tue May 07 14:43:17 2013 +0200 @@ -78,6 +78,7 @@ import jdk.nashorn.internal.ir.ReturnNode; import jdk.nashorn.internal.ir.RuntimeNode; import jdk.nashorn.internal.ir.RuntimeNode.Request; +import jdk.nashorn.internal.ir.Statement; import jdk.nashorn.internal.ir.SwitchNode; import jdk.nashorn.internal.ir.Symbol; import jdk.nashorn.internal.ir.TernaryNode; @@ -154,7 +155,9 @@ @Override public Node leaveAccessNode(final AccessNode accessNode) { - //While Object type is assigned here, Access Specialization in FinalizeTypes may narrow this + //While Object type is assigned here, Access Specialization in FinalizeTypes may narrow this, that + //is why we can't set the access node base to be an object here, that will ruin access specialization + //for example for a.x | 17. return end(ensureSymbol(Type.OBJECT, accessNode)); } @@ -435,6 +438,7 @@ final IdentNode callee = compilerConstant(CALLEE); VarNode selfInit = new VarNode( + newFunctionNode.getLineNumber(), newFunctionNode.getToken(), newFunctionNode.getFinish(), newFunctionNode.getIdent(), @@ -442,7 +446,7 @@ LOG.info("Accepting self symbol init ", selfInit, " for ", newFunctionNode.getName()); - final List newStatements = new ArrayList<>(); + final List newStatements = new ArrayList<>(); assert callee.getSymbol() != null && callee.getSymbol().hasSlot(); final IdentNode name = selfInit.getName(); @@ -492,7 +496,7 @@ final Symbol pseudoSymbol = pseudoSymbol(name); LOG.info("IdentNode is property name -> assigning pseudo symbol ", pseudoSymbol); LOG.unindent(); - return identNode.setSymbol(lc, pseudoSymbol); + return end(identNode.setSymbol(lc, pseudoSymbol)); } final Block block = lc.getCurrentBlock(); @@ -658,7 +662,7 @@ if (literalNode instanceof ArrayLiteralNode) { ((ArrayLiteralNode)literalNode).analyze(); } - return literalNode.setSymbol(getLexicalContext(), symbol); + return end(literalNode.setSymbol(getLexicalContext(), symbol)); } @Override @@ -779,17 +783,18 @@ final IdentNode ident = newVarNode.getName(); final String name = ident.getName(); + final LexicalContext lc = getLexicalContext(); + final Symbol symbol = findSymbol(lc.getCurrentBlock(), ident.getName()); + if (init == null) { // var x; with no init will be treated like a use of x by // leaveIdentNode unless we remove the name from the localdef list. removeLocalDef(name); - return newVarNode; + return newVarNode.setSymbol(lc, symbol); } addLocalDef(name); - final LexicalContext lc = getLexicalContext(); - final Symbol symbol = findSymbol(lc.getCurrentBlock(), ident.getName()); assert symbol != null; final IdentNode newIdent = (IdentNode)ident.setSymbol(lc, symbol); @@ -1398,7 +1403,9 @@ private FunctionNode finalizeParameters(final FunctionNode functionNode) { final List newParams = new ArrayList<>(); final boolean isVarArg = functionNode.isVarArg(); + final int nparams = functionNode.getParameters().size(); + int specialize = 0; int pos = 0; for (final IdentNode param : functionNode.getParameters()) { final Symbol paramSymbol = functionNode.getBody().getExistingSymbol(param.getName()); @@ -1414,9 +1421,13 @@ // if we know that a parameter is only used as a certain type throughout // this function, we can tell the runtime system that no matter what the - // call site is, use this information. TODO - if (!paramSymbol.getSymbolType().isObject()) { + // call site is, use this information: + // we also need more than half of the parameters to be specializable + // for the heuristic to be worth it, and we need more than one use of + // the parameter to consider it, i.e. function(x) { call(x); } doens't count + if (paramSymbol.getUseCount() > 1 && !paramSymbol.getSymbolType().isObject()) { LOG.finest("Parameter ", param, " could profit from specialization to ", paramSymbol.getSymbolType()); + specialize++; } newType(paramSymbol, Type.widest(type, paramSymbol.getSymbolType())); @@ -1429,7 +1440,13 @@ pos++; } - return functionNode.setParameters(getLexicalContext(), newParams); + FunctionNode newFunctionNode = functionNode; + + if (nparams == 0 || (specialize * 2) < nparams) { + newFunctionNode = newFunctionNode.clearSnapshot(getLexicalContext()); + } + + return newFunctionNode.setParameters(getLexicalContext(), newParams); } /** diff -r 544e17632e96 -r fb1d7ea3e1b6 src/jdk/nashorn/internal/codegen/CodeGenerator.java --- a/src/jdk/nashorn/internal/codegen/CodeGenerator.java Tue May 07 14:36:57 2013 +0200 +++ b/src/jdk/nashorn/internal/codegen/CodeGenerator.java Tue May 07 14:43:17 2013 +0200 @@ -63,6 +63,7 @@ import java.util.List; import java.util.Map; import java.util.TreeMap; + import jdk.nashorn.internal.codegen.ClassEmitter.Flag; import jdk.nashorn.internal.codegen.CompilerConstants.Call; import jdk.nashorn.internal.codegen.RuntimeCallSite.SpecializedRuntimeNode; @@ -88,7 +89,6 @@ import jdk.nashorn.internal.ir.IndexNode; import jdk.nashorn.internal.ir.LexicalContext; import jdk.nashorn.internal.ir.LexicalContextNode; -import jdk.nashorn.internal.ir.LineNumberNode; import jdk.nashorn.internal.ir.LiteralNode; import jdk.nashorn.internal.ir.LiteralNode.ArrayLiteralNode; import jdk.nashorn.internal.ir.LiteralNode.ArrayLiteralNode.ArrayUnit; @@ -100,6 +100,7 @@ import jdk.nashorn.internal.ir.RuntimeNode; import jdk.nashorn.internal.ir.RuntimeNode.Request; import jdk.nashorn.internal.ir.SplitNode; +import jdk.nashorn.internal.ir.Statement; import jdk.nashorn.internal.ir.SwitchNode; import jdk.nashorn.internal.ir.Symbol; import jdk.nashorn.internal.ir.TernaryNode; @@ -191,6 +192,8 @@ /** Current compile unit */ private CompileUnit unit; + private int lastLineNumber = -1; + /** When should we stop caching regexp expressions in fields to limit bytecode size? */ private static final int MAX_REGEX_FIELDS = 2 * 1024; @@ -619,6 +622,8 @@ @Override public boolean enterBreakNode(final BreakNode breakNode) { + lineNumber(breakNode); + final BreakableNode breakFrom = getLexicalContext().getBreakable(breakNode.getLabel()); for (int i = 0; i < getLexicalContext().getScopeNestingLevelTo(breakFrom); i++) { closeWith(); @@ -663,6 +668,8 @@ @Override public boolean enterCallNode(final CallNode callNode) { + lineNumber(callNode); + final List args = callNode.getArgs(); final Node function = callNode.getFunction(); final Block currentBlock = getLexicalContext().getCurrentBlock(); @@ -836,6 +843,8 @@ @Override public boolean enterContinueNode(final ContinueNode continueNode) { + lineNumber(continueNode); + final LoopNode continueTo = getLexicalContext().getContinueTo(continueNode.getLabel()); for (int i = 0; i < getLexicalContext().getScopeNestingLevelTo(continueTo); i++) { closeWith(); @@ -847,11 +856,15 @@ @Override public boolean enterEmptyNode(final EmptyNode emptyNode) { + lineNumber(emptyNode); + return false; } @Override public boolean enterExecuteNode(final ExecuteNode executeNode) { + lineNumber(executeNode); + final Node expression = executeNode.getExpression(); expression.accept(this); @@ -860,6 +873,8 @@ @Override public boolean enterForNode(final ForNode forNode) { + lineNumber(forNode); + final Node test = forNode.getTest(); final Block body = forNode.getBody(); final Node modify = forNode.getModify(); @@ -1148,6 +1163,8 @@ @Override public boolean enterIfNode(final IfNode ifNode) { + lineNumber(ifNode); + final Node test = ifNode.getTest(); final Block pass = ifNode.getPass(); final Block fail = ifNode.getFail(); @@ -1187,12 +1204,12 @@ return false; } - @Override - public boolean enterLineNumberNode(final LineNumberNode lineNumberNode) { - final Label label = new Label((String)null); - method.label(label); - method.lineNumber(lineNumberNode.getLineNumber(), label); - return false; + private void lineNumber(final Statement statement) { + final int lineNumber = statement.getLineNumber(); + if (lineNumber != lastLineNumber) { + method.lineNumber(statement.getLineNumber()); + } + lastLineNumber = lineNumber; } /** @@ -1524,6 +1541,8 @@ @Override public boolean enterReturnNode(final ReturnNode returnNode) { + lineNumber(returnNode); + method.registerReturn(); final Type returnType = getLexicalContext().getCurrentFunction().getReturnType(); @@ -1733,6 +1752,8 @@ @Override public boolean enterSplitNode(final SplitNode splitNode) { + lineNumber(splitNode); + final CompileUnit splitCompileUnit = splitNode.getCompileUnit(); final FunctionNode fn = getLexicalContext().getCurrentFunction(); @@ -1876,6 +1897,8 @@ @Override public boolean enterSwitchNode(final SwitchNode switchNode) { + lineNumber(switchNode); + final Node expression = switchNode.getExpression(); final Symbol tag = switchNode.getTag(); final boolean allInteger = tag.getSymbolType().isInteger(); @@ -1958,7 +1981,6 @@ method.tableswitch(lo, hi, defaultLabel, table); } else { final int[] ints = new int[size]; - for (int i = 0; i < size; i++) { ints[i] = values[i]; } @@ -2004,6 +2026,8 @@ @Override public boolean enterThrowNode(final ThrowNode throwNode) { + lineNumber(throwNode); + method._new(ECMAException.class).dup(); final Source source = getLexicalContext().getCurrentFunction().getSource(); @@ -2028,6 +2052,8 @@ @Override public boolean enterTryNode(final TryNode tryNode) { + lineNumber(tryNode); + final Block body = tryNode.getBody(); final List catchBlocks = tryNode.getCatchBlocks(); final Symbol symbol = tryNode.getException(); @@ -2124,12 +2150,15 @@ @Override public boolean enterVarNode(final VarNode varNode) { + final Node init = varNode.getInit(); if (init == null) { return false; } + lineNumber(varNode); + final Symbol varSymbol = varNode.getSymbol(); assert varSymbol != null : "variable node " + varNode + " requires a symbol"; @@ -2162,6 +2191,8 @@ @Override public boolean enterWhileNode(final WhileNode whileNode) { + lineNumber(whileNode); + final Node test = whileNode.getTest(); final Block body = whileNode.getBody(); final Label breakLabel = whileNode.getBreakLabel(); @@ -2184,7 +2215,7 @@ } private void closeWith() { - if(method.hasScope()) { + if (method.hasScope()) { method.loadCompilerConstant(SCOPE); method.invoke(ScriptRuntime.CLOSE_WITH); method.storeCompilerConstant(SCOPE); @@ -2227,7 +2258,7 @@ // Always process body body.accept(this); - if(hasScope) { + if (hasScope) { // Ensure we always close the WithObject final Label endLabel = new Label("with_end"); final Label catchLabel = new Label("with_catch"); @@ -3010,6 +3041,7 @@ * @param block the block we are in * @param ident identifier for block or function where applicable */ + @SuppressWarnings("resource") private void printSymbols(final Block block, final String ident) { if (!compiler.getEnv()._print_symbols) { return; @@ -3190,9 +3222,6 @@ return; } - //System.err.println("Store with out discard that shouldn't just return " + assignNode); - //new Throwable().printStackTrace(); - final Symbol symbol = assignNode.getSymbol(); if (symbol.hasSlot()) { method.dup().store(symbol); @@ -3288,7 +3317,7 @@ // Such immediately-called functions are invoked using INVOKESTATIC (see enterFunctionNode() of the embedded // visitor of enterCallNode() for details), and if they don't need a callee, they don't have it on their // static method's parameter list. - if(lc.getOutermostFunction() == functionNode || + if (lc.getOutermostFunction() == functionNode || (!functionNode.needsCallee()) && lc.isFunctionDefinedInCurrentCall(originalFunctionNode)) { return; } diff -r 544e17632e96 -r fb1d7ea3e1b6 src/jdk/nashorn/internal/codegen/FinalizeTypes.java --- a/src/jdk/nashorn/internal/codegen/FinalizeTypes.java Tue May 07 14:36:57 2013 +0200 +++ b/src/jdk/nashorn/internal/codegen/FinalizeTypes.java Tue May 07 14:43:17 2013 +0200 @@ -228,19 +228,19 @@ } @Override - public Node leaveBIT_AND(BinaryNode binaryNode) { + public Node leaveBIT_AND(final BinaryNode binaryNode) { assert binaryNode.getSymbol() != null && binaryNode.getSymbol().getSymbolType().isInteger() : "int coercion expected: " + binaryNode.getSymbol(); return leaveBinary(binaryNode, Type.INT, Type.INT); } @Override - public Node leaveBIT_OR(BinaryNode binaryNode) { + public Node leaveBIT_OR(final BinaryNode binaryNode) { assert binaryNode.getSymbol() != null && binaryNode.getSymbol().getSymbolType().isInteger() : "int coercion expected: " + binaryNode.getSymbol(); return leaveBinary(binaryNode, Type.INT, Type.INT); } @Override - public Node leaveBIT_XOR(BinaryNode binaryNode) { + public Node leaveBIT_XOR(final BinaryNode binaryNode) { assert binaryNode.getSymbol() != null && binaryNode.getSymbol().getSymbolType().isInteger() : "int coercion expected: " + binaryNode.getSymbol(); return leaveBinary(binaryNode, Type.INT, Type.INT); } diff -r 544e17632e96 -r fb1d7ea3e1b6 src/jdk/nashorn/internal/codegen/FoldConstants.java --- a/src/jdk/nashorn/internal/codegen/FoldConstants.java Tue May 07 14:36:57 2013 +0200 +++ b/src/jdk/nashorn/internal/codegen/FoldConstants.java Tue May 07 14:43:17 2013 +0200 @@ -88,7 +88,7 @@ if (test instanceof LiteralNode) { final Block shortCut = ((LiteralNode)test).isTrue() ? ifNode.getPass() : ifNode.getFail(); if (shortCut != null) { - return new ExecuteNode(shortCut); + return new ExecuteNode(shortCut.getLineNumber(), shortCut.getToken(), shortCut.getFinish(), shortCut); } return new EmptyNode(ifNode); } diff -r 544e17632e96 -r fb1d7ea3e1b6 src/jdk/nashorn/internal/codegen/Label.java --- a/src/jdk/nashorn/internal/codegen/Label.java Tue May 07 14:36:57 2013 +0200 +++ b/src/jdk/nashorn/internal/codegen/Label.java Tue May 07 14:43:17 2013 +0200 @@ -27,6 +27,7 @@ import java.util.ArrayDeque; import jdk.nashorn.internal.codegen.types.Type; +import jdk.nashorn.internal.runtime.Debug; /** * Abstraction for labels, separating a label from the underlying @@ -35,13 +36,16 @@ * * see -Dnashorn.codegen.debug, --log=codegen */ -public class Label extends jdk.internal.org.objectweb.asm.Label { +public final class Label { /** Name of this label */ private final String name; /** Type stack at this label */ private ArrayDeque stack; + /** ASM representation of this label */ + private jdk.internal.org.objectweb.asm.Label label; + /** * Constructor * @@ -62,6 +66,14 @@ this.name = label.name; } + + jdk.internal.org.objectweb.asm.Label getLabel() { + if (this.label == null) { + this.label = new jdk.internal.org.objectweb.asm.Label(); + } + return label; + } + ArrayDeque getStack() { return stack; } @@ -72,12 +84,7 @@ @Override public String toString() { - final StringBuilder sb = new StringBuilder(); - String s = super.toString(); - s = s.substring(1, s.length()); - sb.append(name).append('_').append(Long.toHexString(Long.parseLong(s))); - - return sb.toString(); + return name + '_' + Debug.id(this); } } diff -r 544e17632e96 -r fb1d7ea3e1b6 src/jdk/nashorn/internal/codegen/Lower.java --- a/src/jdk/nashorn/internal/codegen/Lower.java Tue May 07 14:36:57 2013 +0200 +++ b/src/jdk/nashorn/internal/codegen/Lower.java Tue May 07 14:43:17 2013 +0200 @@ -32,6 +32,7 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.List; + import jdk.nashorn.internal.ir.BaseNode; import jdk.nashorn.internal.ir.BinaryNode; import jdk.nashorn.internal.ir.Block; @@ -49,16 +50,15 @@ import jdk.nashorn.internal.ir.IfNode; import jdk.nashorn.internal.ir.LabelNode; import jdk.nashorn.internal.ir.LexicalContext; -import jdk.nashorn.internal.ir.LineNumberNode; import jdk.nashorn.internal.ir.LiteralNode; import jdk.nashorn.internal.ir.LoopNode; import jdk.nashorn.internal.ir.Node; import jdk.nashorn.internal.ir.ReturnNode; +import jdk.nashorn.internal.ir.Statement; import jdk.nashorn.internal.ir.SwitchNode; import jdk.nashorn.internal.ir.Symbol; import jdk.nashorn.internal.ir.ThrowNode; import jdk.nashorn.internal.ir.TryNode; -import jdk.nashorn.internal.ir.UnaryNode; import jdk.nashorn.internal.ir.VarNode; import jdk.nashorn.internal.ir.WhileNode; import jdk.nashorn.internal.ir.WithNode; @@ -93,21 +93,25 @@ super(new BlockLexicalContext() { @Override - public List popStatements() { - List newStatements = new ArrayList<>(); + public List popStatements() { + final List newStatements = new ArrayList<>(); boolean terminated = false; - final List statements = super.popStatements(); - for (final Node statement : statements) { + final List statements = super.popStatements(); + for (final Statement statement : statements) { if (!terminated) { newStatements.add(statement); - if (statement.isTerminal()) { + if (statement.isTerminal() || statement instanceof BreakNode || statement instanceof ContinueNode) { //TODO hasGoto? But some Loops are hasGoto too - why? terminated = true; } } else { - if (statement instanceof VarNode) { - newStatements.add(((VarNode)statement).setInit(null)); - } + statement.accept(new NodeVisitor() { + @Override + public boolean enterVarNode(final VarNode varNode) { + newStatements.add(varNode.setInit(null)); + return false; + } + }); } } return newStatements; @@ -120,7 +124,7 @@ final LexicalContext lc = getLexicalContext(); final FunctionNode function = lc.getCurrentFunction(); if (lc.isFunctionBody() && function.isProgram() && !function.hasDeclaredFunctions()) { - new ExecuteNode(block.getToken(), block.getFinish(), LiteralNode.newInstance(block, ScriptRuntime.UNDEFINED)).accept(this); + new ExecuteNode(block.getLineNumber(), block.getToken(), block.getFinish(), LiteralNode.newInstance(block, ScriptRuntime.UNDEFINED)).accept(this); } return true; } @@ -132,19 +136,20 @@ final BlockLexicalContext lc = (BlockLexicalContext)getLexicalContext(); - Node last = lc.getLastStatement(); + Statement last = lc.getLastStatement(); if (lc.isFunctionBody()) { final FunctionNode currentFunction = getLexicalContext().getCurrentFunction(); final boolean isProgram = currentFunction.isProgram(); final ReturnNode returnNode = new ReturnNode( + last == null ? block.getLineNumber() : last.getLineNumber(), //TODO? currentFunction.getToken(), currentFunction.getFinish(), isProgram ? compilerConstant(RETURN) : LiteralNode.newInstance(block, ScriptRuntime.UNDEFINED)); - last = returnNode.accept(this); + last = (Statement)returnNode.accept(this); } if (last != null && last.isTerminal()) { @@ -239,12 +244,6 @@ } @Override - public boolean enterLineNumberNode(final LineNumberNode lineNumberNode) { - addStatement(lineNumberNode); // don't put it in lastStatement cache - return false; - } - - @Override public Node leaveReturnNode(final ReturnNode returnNode) { addStatement(returnNode); //ReturnNodes are always terminal, marked as such in constructor return returnNode; @@ -271,10 +270,10 @@ }); } - private static List copyFinally(final Block finallyBody) { - final List newStatements = new ArrayList<>(); - for (final Node statement : finallyBody.getStatements()) { - newStatements.add(ensureUniqueLabelsIn(statement)); + private static List copyFinally(final Block finallyBody) { + final List newStatements = new ArrayList<>(); + for (final Statement statement : finallyBody.getStatements()) { + newStatements.add((Statement)ensureUniqueLabelsIn(statement)); if (statement.hasTerminalFlags()) { return newStatements; } @@ -283,16 +282,17 @@ } private Block catchAllBlock(final TryNode tryNode) { - final long token = tryNode.getToken(); - final int finish = tryNode.getFinish(); + final int lineNumber = tryNode.getLineNumber(); + final long token = tryNode.getToken(); + final int finish = tryNode.getFinish(); final IdentNode exception = new IdentNode(token, finish, getLexicalContext().getCurrentFunction().uniqueName("catch_all")); - final Block catchBody = new Block(token, finish, new ThrowNode(token, finish, new IdentNode(exception))). + final Block catchBody = new Block(lineNumber, token, finish, new ThrowNode(lineNumber, token, finish, new IdentNode(exception))). setIsTerminal(getLexicalContext(), true); //ends with throw, so terminal - final CatchNode catchAllNode = new CatchNode(token, finish, new IdentNode(exception), null, catchBody); - final Block catchAllBlock = new Block(token, finish, catchAllNode); + final CatchNode catchAllNode = new CatchNode(lineNumber, token, finish, new IdentNode(exception), null, catchBody); + final Block catchAllBlock = new Block(lineNumber, token, finish, catchAllNode); //catchallblock -> catchallnode (catchnode) -> exception -> throw @@ -304,7 +304,7 @@ return new IdentNode(functionNode.getToken(), functionNode.getFinish(), cc.symbolName()); } - private static boolean isTerminal(final List statements) { + private static boolean isTerminal(final List statements) { return !statements.isEmpty() && statements.get(statements.size() - 1).hasTerminalFlags(); } @@ -316,7 +316,7 @@ * @return new try node after splicing finally code (same if nop) */ private Node spliceFinally(final TryNode tryNode, final List rethrows, final Block finallyBody) { - final int finish = tryNode.getFinish(); + final int finish = tryNode.getFinish(); assert tryNode.getFinallyBody() == null; @@ -338,11 +338,11 @@ @Override public Node leaveThrowNode(final ThrowNode throwNode) { if (rethrows.contains(throwNode)) { - final List newStatements = copyFinally(finallyBody); + final List newStatements = copyFinally(finallyBody); if (!isTerminal(newStatements)) { newStatements.add(throwNode); } - return new Block(throwNode.getToken(), throwNode.getFinish(), newStatements); + return new Block(throwNode.getLineNumber(), throwNode.getToken(), throwNode.getFinish(), newStatements); } return throwNode; } @@ -360,14 +360,14 @@ @Override public Node leaveReturnNode(final ReturnNode returnNode) { final Node expr = returnNode.getExpression(); - final List newStatements = new ArrayList<>(); + final List newStatements = new ArrayList<>(); final Node resultNode; if (expr != null) { //we need to evaluate the result of the return in case it is complex while //still in the try block, store it in a result value and return it afterwards resultNode = new IdentNode(Lower.this.compilerConstant(RETURN)); - newStatements.add(new ExecuteNode(new BinaryNode(Token.recast(returnNode.getToken(), TokenType.ASSIGN), resultNode, expr))); + newStatements.add(new ExecuteNode(returnNode.getLineNumber(), returnNode.getToken(), returnNode.getFinish(), new BinaryNode(Token.recast(returnNode.getToken(), TokenType.ASSIGN), resultNode, expr))); } else { resultNode = null; } @@ -377,16 +377,16 @@ newStatements.add(expr == null ? returnNode : returnNode.setExpression(resultNode)); } - return new ExecuteNode(new Block(returnNode.getToken(), getLexicalContext().getCurrentBlock().getFinish(), newStatements)); + return new ExecuteNode(returnNode.getLineNumber(), returnNode.getToken(), returnNode.getFinish(), new Block(returnNode.getLineNumber(), returnNode.getToken(), getLexicalContext().getCurrentBlock().getFinish(), newStatements)); } - private Node copy(final Node endpoint, final Node targetNode) { + private Node copy(final Statement endpoint, final Node targetNode) { if (!insideTry.contains(targetNode)) { - final List newStatements = copyFinally(finallyBody); + final List newStatements = copyFinally(finallyBody); if (!isTerminal(newStatements)) { newStatements.add(endpoint); } - return new ExecuteNode(new Block(endpoint.getToken(), finish, newStatements)); + return new ExecuteNode(endpoint.getLineNumber(), endpoint.getToken(), endpoint.getFinish(), new Block(endpoint.getLineNumber(), endpoint.getToken(), finish, newStatements)); } return endpoint; } @@ -394,7 +394,7 @@ addStatement(newTryNode); for (final Node statement : finallyBody.getStatements()) { - addStatement(statement); + addStatement((Statement)statement); } return newTryNode; @@ -448,7 +448,7 @@ if (tryNode.getCatchBlocks().isEmpty()) { newTryNode = tryNode.setFinallyBody(null); } else { - Block outerBody = new Block(tryNode.getToken(), tryNode.getFinish(), new ArrayList(Arrays.asList(tryNode.setFinallyBody(null)))); + Block outerBody = new Block(tryNode.getLineNumber(), tryNode.getToken(), tryNode.getFinish(), new ArrayList(Arrays.asList(tryNode.setFinallyBody(null)))); newTryNode = tryNode.setBody(outerBody).setCatchBlocks(null); } @@ -465,7 +465,7 @@ public Node leaveVarNode(final VarNode varNode) { addStatement(varNode); if (varNode.getFlag(VarNode.IS_LAST_FUNCTION_DECLARATION) && getLexicalContext().getCurrentFunction().isProgram()) { - new ExecuteNode(varNode.getToken(), varNode.getFinish(), new IdentNode(varNode.getName())).accept(this); + new ExecuteNode(varNode.getLineNumber(), varNode.getToken(), varNode.getFinish(), new IdentNode(varNode.getName())).accept(this); } return varNode; } @@ -477,7 +477,7 @@ if (conservativeAlwaysTrue(test)) { //turn it into a for node without a test. - final ForNode forNode = (ForNode)new ForNode(whileNode.getToken(), whileNode.getFinish(), null, null, body, null, ForNode.IS_FOR).accept(this); + final ForNode forNode = (ForNode)new ForNode(whileNode.getLineNumber(), whileNode.getToken(), whileNode.getFinish(), null, null, body, null, ForNode.IS_FOR).accept(this); getLexicalContext().replace(whileNode, forNode); return forNode; } @@ -490,16 +490,6 @@ return addStatement(withNode); } - @Override - public Node leaveDELETE(final UnaryNode unaryNode) { - final Node rhs = unaryNode.rhs(); - if (rhs instanceof IdentNode || rhs instanceof BaseNode) { - return unaryNode; - } - addStatement(new ExecuteNode(rhs)); - return LiteralNode.newInstance(unaryNode, true); - } - /** * Given a function node that is a callee in a CallNode, replace it with * the appropriate marker function. This is used by {@link CodeGenerator} @@ -616,7 +606,7 @@ } - private Node addStatement(final Node statement) { + private Node addStatement(final Statement statement) { ((BlockLexicalContext)getLexicalContext()).appendStatement(statement); return statement; } diff -r 544e17632e96 -r fb1d7ea3e1b6 src/jdk/nashorn/internal/codegen/MethodEmitter.java --- a/src/jdk/nashorn/internal/codegen/MethodEmitter.java Tue May 07 14:36:57 2013 +0200 +++ b/src/jdk/nashorn/internal/codegen/MethodEmitter.java Tue May 07 14:43:17 2013 +0200 @@ -71,6 +71,7 @@ import java.util.EnumSet; import java.util.Iterator; import java.util.List; + import jdk.internal.dynalink.support.NameCodec; import jdk.internal.org.objectweb.asm.Handle; import jdk.internal.org.objectweb.asm.MethodVisitor; @@ -189,7 +190,7 @@ @Override public void begin() { classEmitter.beginMethod(this); - stack = new ArrayDeque<>(); + newStack(); method.visitCode(); } @@ -205,6 +206,10 @@ classEmitter.endMethod(this); } + private void newStack() { + stack = new ArrayDeque<>(); + } + @Override public String toString() { return "methodEmitter: " + (functionNode == null ? method : functionNode.getName()).toString() + ' ' + Debug.id(this); @@ -484,7 +489,7 @@ name = THIS_DEBUGGER.symbolName(); } - method.visitLocalVariable(name, symbol.getSymbolType().getDescriptor(), null, start, end, symbol.getSlot()); + method.visitLocalVariable(name, symbol.getSymbolType().getDescriptor(), null, start.getLabel(), end.getLabel(), symbol.getSlot()); } /** @@ -509,17 +514,6 @@ } /** - * Associate a variable with a given range - * - * @param name name of the variable - * @param start start - * @param end end - */ - void markerVariable(final String name, final Label start, final Label end) { - method.visitLocalVariable(name, Type.OBJECT.getDescriptor(), null, start, end, 0); - } - - /** * Pops two integer types from the stack, performs a bitwise and and pushes * the result * @@ -626,7 +620,7 @@ * @param typeDescriptor type descriptor for exception */ void _try(final Label entry, final Label exit, final Label recovery, final String typeDescriptor) { - method.visitTryCatchBlock(entry, exit, recovery, typeDescriptor); + method.visitTryCatchBlock(entry.getLabel(), exit.getLabel(), recovery.getLabel(), typeDescriptor); } /** @@ -638,7 +632,7 @@ * @param clazz exception class */ void _try(final Label entry, final Label exit, final Label recovery, final Class clazz) { - method.visitTryCatchBlock(entry, exit, recovery, CompilerConstants.className(clazz)); + method.visitTryCatchBlock(entry.getLabel(), exit.getLabel(), recovery.getLabel(), CompilerConstants.className(clazz)); } /** @@ -1228,6 +1222,14 @@ return invoke(INVOKEINTERFACE, className, methodName, methodDescriptor, true); } + static jdk.internal.org.objectweb.asm.Label[] getLabels(final Label... table) { + final jdk.internal.org.objectweb.asm.Label[] internalLabels = new jdk.internal.org.objectweb.asm.Label[table.length]; + for (int i = 0; i < table.length; i++) { + internalLabels[i] = table[i].getLabel(); + } + return internalLabels; + } + /** * Generate a lookup switch, popping the switch value from the stack * @@ -1235,10 +1237,10 @@ * @param values case values for the table * @param table default label */ - void lookupswitch(final Label defaultLabel, final int[] values, final Label[] table) { + void lookupswitch(final Label defaultLabel, final int[] values, final Label... table) {//Collection