src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/Lower.java

Print this page




  28 import static jdk.nashorn.internal.codegen.CompilerConstants.EVAL;
  29 import static jdk.nashorn.internal.codegen.CompilerConstants.RETURN;
  30 import static jdk.nashorn.internal.ir.Expression.isAlwaysTrue;
  31 
  32 import java.util.ArrayList;
  33 import java.util.Arrays;
  34 import java.util.Collections;
  35 import java.util.List;
  36 import java.util.ListIterator;
  37 import java.util.regex.Pattern;
  38 import jdk.nashorn.internal.ir.AccessNode;
  39 import jdk.nashorn.internal.ir.BaseNode;
  40 import jdk.nashorn.internal.ir.BinaryNode;
  41 import jdk.nashorn.internal.ir.Block;
  42 import jdk.nashorn.internal.ir.BlockLexicalContext;
  43 import jdk.nashorn.internal.ir.BlockStatement;
  44 import jdk.nashorn.internal.ir.BreakNode;
  45 import jdk.nashorn.internal.ir.CallNode;
  46 import jdk.nashorn.internal.ir.CaseNode;
  47 import jdk.nashorn.internal.ir.CatchNode;

  48 import jdk.nashorn.internal.ir.ContinueNode;
  49 import jdk.nashorn.internal.ir.EmptyNode;
  50 import jdk.nashorn.internal.ir.Expression;
  51 import jdk.nashorn.internal.ir.ExpressionStatement;
  52 import jdk.nashorn.internal.ir.ForNode;
  53 import jdk.nashorn.internal.ir.FunctionNode;
  54 import jdk.nashorn.internal.ir.FunctionNode.CompilationState;
  55 import jdk.nashorn.internal.ir.IdentNode;
  56 import jdk.nashorn.internal.ir.IfNode;
  57 import jdk.nashorn.internal.ir.IndexNode;
  58 import jdk.nashorn.internal.ir.JumpStatement;
  59 import jdk.nashorn.internal.ir.JumpToInlinedFinally;
  60 import jdk.nashorn.internal.ir.LabelNode;
  61 import jdk.nashorn.internal.ir.LexicalContext;
  62 import jdk.nashorn.internal.ir.LiteralNode;
  63 import jdk.nashorn.internal.ir.LiteralNode.PrimitiveLiteralNode;
  64 import jdk.nashorn.internal.ir.LoopNode;
  65 import jdk.nashorn.internal.ir.Node;
  66 import jdk.nashorn.internal.ir.ReturnNode;
  67 import jdk.nashorn.internal.ir.RuntimeNode;


 168         return false;
 169     }
 170 
 171     @Override
 172     public Node leaveCallNode(final CallNode callNode) {
 173         return checkEval(callNode.setFunction(markerFunction(callNode.getFunction())));
 174     }
 175 
 176     @Override
 177     public Node leaveCatchNode(final CatchNode catchNode) {
 178         return addStatement(catchNode);
 179     }
 180 
 181     @Override
 182     public boolean enterContinueNode(final ContinueNode continueNode) {
 183         addStatement(continueNode);
 184         return false;
 185     }
 186 
 187     @Override









 188     public boolean enterJumpToInlinedFinally(final JumpToInlinedFinally jumpToInlinedFinally) {
 189         addStatement(jumpToInlinedFinally);
 190         return false;
 191     }
 192 
 193     @Override
 194     public boolean enterEmptyNode(final EmptyNode emptyNode) {
 195         return false;
 196     }
 197 
 198     @Override
 199     public Node leaveIndexNode(final IndexNode indexNode) {
 200         final String name = getConstantPropertyName(indexNode.getIndex());
 201         if (name != null) {
 202             // If index node is a constant property name convert index node to access node.
 203             assert Token.descType(indexNode.getToken()) == TokenType.LBRACKET;
 204             return new AccessNode(indexNode.getToken(), indexNode.getFinish(), indexNode.getBase(), name);
 205         }
 206         return super.leaveIndexNode(indexNode);
 207     }


 429                     return createJumpToInlinedFinally(fn, inlinedFinallies, prependFinally(finallyBlock, jump));
 430                 }
 431                 return jump;
 432             }
 433 
 434             @Override
 435             public Node leaveReturnNode(final ReturnNode returnNode) {
 436                 final Expression expr = returnNode.getExpression();
 437                 if (isTerminalFinally(finallyBlock)) {
 438                     if (expr == null) {
 439                         // Terminal finally; no return expression.
 440                         return createJumpToInlinedFinally(fn, inlinedFinallies, ensureUniqueNamesIn(finallyBlock));
 441                     }
 442                     // Terminal finally; has a return expression.
 443                     final List<Statement> newStatements = new ArrayList<>(2);
 444                     final int retLineNumber = returnNode.getLineNumber();
 445                     final long retToken = returnNode.getToken();
 446                     // Expression is evaluated for side effects.
 447                     newStatements.add(new ExpressionStatement(retLineNumber, retToken, returnNode.getFinish(), expr));
 448                     newStatements.add(createJumpToInlinedFinally(fn, inlinedFinallies, ensureUniqueNamesIn(finallyBlock)));
 449                     return new BlockStatement(retLineNumber, new Block(retToken, finallyBlock.getFinish(), newStatements));
 450                 } else if (expr == null || expr instanceof PrimitiveLiteralNode<?> || (expr instanceof IdentNode && RETURN.symbolName().equals(((IdentNode)expr).getName()))) {
 451                     // Nonterminal finally; no return expression, or returns a primitive literal, or returns :return.
 452                     // Just move the return expression into the finally block.
 453                     return createJumpToInlinedFinally(fn, inlinedFinallies, prependFinally(finallyBlock, returnNode));
 454                 } else {
 455                     // We need to evaluate the result of the return in case it is complex while still in the try block,
 456                     // store it in :return, and return it afterwards.
 457                     final List<Statement> newStatements = new ArrayList<>();
 458                     final int retLineNumber = returnNode.getLineNumber();
 459                     final long retToken = returnNode.getToken();
 460                     final int retFinish = returnNode.getFinish();
 461                     final Expression resultNode = new IdentNode(expr.getToken(), expr.getFinish(), RETURN.symbolName());
 462                     // ":return = <expr>;"
 463                     newStatements.add(new ExpressionStatement(retLineNumber, retToken, retFinish, new BinaryNode(Token.recast(returnNode.getToken(), TokenType.ASSIGN), resultNode, expr)));
 464                     // inline finally and end it with "return :return;"
 465                     newStatements.add(createJumpToInlinedFinally(fn, inlinedFinallies, prependFinally(finallyBlock, returnNode.setExpression(resultNode))));
 466                     return new BlockStatement(retLineNumber, new Block(retToken, retFinish, newStatements));
 467                 }
 468             }
 469         });
 470         addStatement(inlinedFinallies.isEmpty() ? newTryNode : newTryNode.setInlinedFinallies(lc, inlinedFinallies));
 471         // TODO: if finallyStatement is terminal, we could just have sites of inlined finallies jump here.
 472         addStatement(new BlockStatement(finallyBlock));
 473 
 474         return newTryNode;
 475     }
 476 
 477     private static JumpToInlinedFinally createJumpToInlinedFinally(final FunctionNode fn, final List<Block> inlinedFinallies, final Block finallyBlock) {
 478         final String labelName = fn.uniqueName(":finally");
 479         final long token = finallyBlock.getToken();
 480         final int finish = finallyBlock.getFinish();
 481         inlinedFinallies.add(new Block(token, finish, new LabelNode(finallyBlock.getFirstStatementLineNumber(),
 482                 token, finish, labelName, finallyBlock)));
 483         return new JumpToInlinedFinally(labelName);
 484     }
 485 
 486     private static Block prependFinally(final Block finallyBlock, final Statement statement) {




  28 import static jdk.nashorn.internal.codegen.CompilerConstants.EVAL;
  29 import static jdk.nashorn.internal.codegen.CompilerConstants.RETURN;
  30 import static jdk.nashorn.internal.ir.Expression.isAlwaysTrue;
  31 
  32 import java.util.ArrayList;
  33 import java.util.Arrays;
  34 import java.util.Collections;
  35 import java.util.List;
  36 import java.util.ListIterator;
  37 import java.util.regex.Pattern;
  38 import jdk.nashorn.internal.ir.AccessNode;
  39 import jdk.nashorn.internal.ir.BaseNode;
  40 import jdk.nashorn.internal.ir.BinaryNode;
  41 import jdk.nashorn.internal.ir.Block;
  42 import jdk.nashorn.internal.ir.BlockLexicalContext;
  43 import jdk.nashorn.internal.ir.BlockStatement;
  44 import jdk.nashorn.internal.ir.BreakNode;
  45 import jdk.nashorn.internal.ir.CallNode;
  46 import jdk.nashorn.internal.ir.CaseNode;
  47 import jdk.nashorn.internal.ir.CatchNode;
  48 import jdk.nashorn.internal.ir.DebuggerNode;
  49 import jdk.nashorn.internal.ir.ContinueNode;
  50 import jdk.nashorn.internal.ir.EmptyNode;
  51 import jdk.nashorn.internal.ir.Expression;
  52 import jdk.nashorn.internal.ir.ExpressionStatement;
  53 import jdk.nashorn.internal.ir.ForNode;
  54 import jdk.nashorn.internal.ir.FunctionNode;
  55 import jdk.nashorn.internal.ir.FunctionNode.CompilationState;
  56 import jdk.nashorn.internal.ir.IdentNode;
  57 import jdk.nashorn.internal.ir.IfNode;
  58 import jdk.nashorn.internal.ir.IndexNode;
  59 import jdk.nashorn.internal.ir.JumpStatement;
  60 import jdk.nashorn.internal.ir.JumpToInlinedFinally;
  61 import jdk.nashorn.internal.ir.LabelNode;
  62 import jdk.nashorn.internal.ir.LexicalContext;
  63 import jdk.nashorn.internal.ir.LiteralNode;
  64 import jdk.nashorn.internal.ir.LiteralNode.PrimitiveLiteralNode;
  65 import jdk.nashorn.internal.ir.LoopNode;
  66 import jdk.nashorn.internal.ir.Node;
  67 import jdk.nashorn.internal.ir.ReturnNode;
  68 import jdk.nashorn.internal.ir.RuntimeNode;


 169         return false;
 170     }
 171 
 172     @Override
 173     public Node leaveCallNode(final CallNode callNode) {
 174         return checkEval(callNode.setFunction(markerFunction(callNode.getFunction())));
 175     }
 176 
 177     @Override
 178     public Node leaveCatchNode(final CatchNode catchNode) {
 179         return addStatement(catchNode);
 180     }
 181 
 182     @Override
 183     public boolean enterContinueNode(final ContinueNode continueNode) {
 184         addStatement(continueNode);
 185         return false;
 186     }
 187 
 188     @Override
 189     public boolean enterDebuggerNode(final DebuggerNode debuggerNode) {
 190         final int line = debuggerNode.getLineNumber();
 191         final long token = debuggerNode.getToken();
 192         final int finish = debuggerNode.getFinish();
 193         addStatement(new ExpressionStatement(line, token, finish, new RuntimeNode(token, finish, RuntimeNode.Request.DEBUGGER, new ArrayList<Expression>())));
 194         return false;
 195     }
 196 
 197     @Override
 198     public boolean enterJumpToInlinedFinally(final JumpToInlinedFinally jumpToInlinedFinally) {
 199         addStatement(jumpToInlinedFinally);
 200         return false;
 201     }
 202 
 203     @Override
 204     public boolean enterEmptyNode(final EmptyNode emptyNode) {
 205         return false;
 206     }
 207 
 208     @Override
 209     public Node leaveIndexNode(final IndexNode indexNode) {
 210         final String name = getConstantPropertyName(indexNode.getIndex());
 211         if (name != null) {
 212             // If index node is a constant property name convert index node to access node.
 213             assert Token.descType(indexNode.getToken()) == TokenType.LBRACKET;
 214             return new AccessNode(indexNode.getToken(), indexNode.getFinish(), indexNode.getBase(), name);
 215         }
 216         return super.leaveIndexNode(indexNode);
 217     }


 439                     return createJumpToInlinedFinally(fn, inlinedFinallies, prependFinally(finallyBlock, jump));
 440                 }
 441                 return jump;
 442             }
 443 
 444             @Override
 445             public Node leaveReturnNode(final ReturnNode returnNode) {
 446                 final Expression expr = returnNode.getExpression();
 447                 if (isTerminalFinally(finallyBlock)) {
 448                     if (expr == null) {
 449                         // Terminal finally; no return expression.
 450                         return createJumpToInlinedFinally(fn, inlinedFinallies, ensureUniqueNamesIn(finallyBlock));
 451                     }
 452                     // Terminal finally; has a return expression.
 453                     final List<Statement> newStatements = new ArrayList<>(2);
 454                     final int retLineNumber = returnNode.getLineNumber();
 455                     final long retToken = returnNode.getToken();
 456                     // Expression is evaluated for side effects.
 457                     newStatements.add(new ExpressionStatement(retLineNumber, retToken, returnNode.getFinish(), expr));
 458                     newStatements.add(createJumpToInlinedFinally(fn, inlinedFinallies, ensureUniqueNamesIn(finallyBlock)));
 459                     return new BlockStatement(retLineNumber, new Block(retToken, finallyBlock.getFinish(), newStatements), true);
 460                 } else if (expr == null || expr instanceof PrimitiveLiteralNode<?> || (expr instanceof IdentNode && RETURN.symbolName().equals(((IdentNode)expr).getName()))) {
 461                     // Nonterminal finally; no return expression, or returns a primitive literal, or returns :return.
 462                     // Just move the return expression into the finally block.
 463                     return createJumpToInlinedFinally(fn, inlinedFinallies, prependFinally(finallyBlock, returnNode));
 464                 } else {
 465                     // We need to evaluate the result of the return in case it is complex while still in the try block,
 466                     // store it in :return, and return it afterwards.
 467                     final List<Statement> newStatements = new ArrayList<>();
 468                     final int retLineNumber = returnNode.getLineNumber();
 469                     final long retToken = returnNode.getToken();
 470                     final int retFinish = returnNode.getFinish();
 471                     final Expression resultNode = new IdentNode(expr.getToken(), expr.getFinish(), RETURN.symbolName());
 472                     // ":return = <expr>;"
 473                     newStatements.add(new ExpressionStatement(retLineNumber, retToken, retFinish, new BinaryNode(Token.recast(returnNode.getToken(), TokenType.ASSIGN), resultNode, expr)));
 474                     // inline finally and end it with "return :return;"
 475                     newStatements.add(createJumpToInlinedFinally(fn, inlinedFinallies, prependFinally(finallyBlock, returnNode.setExpression(resultNode))));
 476                     return new BlockStatement(retLineNumber, new Block(retToken, retFinish, newStatements), true);
 477                 }
 478             }
 479         });
 480         addStatement(inlinedFinallies.isEmpty() ? newTryNode : newTryNode.setInlinedFinallies(lc, inlinedFinallies));
 481         // TODO: if finallyStatement is terminal, we could just have sites of inlined finallies jump here.
 482         addStatement(new BlockStatement(finallyBlock));
 483 
 484         return newTryNode;
 485     }
 486 
 487     private static JumpToInlinedFinally createJumpToInlinedFinally(final FunctionNode fn, final List<Block> inlinedFinallies, final Block finallyBlock) {
 488         final String labelName = fn.uniqueName(":finally");
 489         final long token = finallyBlock.getToken();
 490         final int finish = finallyBlock.getFinish();
 491         inlinedFinallies.add(new Block(token, finish, new LabelNode(finallyBlock.getFirstStatementLineNumber(),
 492                 token, finish, labelName, finallyBlock)));
 493         return new JumpToInlinedFinally(labelName);
 494     }
 495 
 496     private static Block prependFinally(final Block finallyBlock, final Statement statement) {