@SuppressWarnings("unchecked") private <T extends LoopNode> T checkEscape(final T loopNode) { final boolean escapes = controlFlowEscapes(lc, loopNode.getBody()); if (escapes) { return (T)loopNode. setBody(lc, loopNode.getBody().setIsTerminal(lc, false)). setControlFlowEscapes(lc, escapes); } return loopNode; }
private LoopNode checkEscape(final LoopNode loopNode) { final boolean escapes = controlFlowEscapes(lc, loopNode.getBody()); if (escapes) { return loopNode. setBody(lc, loopNode.getBody().setIsTerminal(lc, false)). setControlFlowEscapes(lc, escapes); } return loopNode; }
/** * Check for a loop counter. This is currently quite conservative, in that it only handles * x <= counter and x < counter. * * @param node loop node to check * @return */ private static Symbol findLoopCounter(final LoopNode node) { final Expression test = node.getTest(); if (test != null && test.isComparison()) { final BinaryNode binaryNode = (BinaryNode)test; final Expression lhs = binaryNode.lhs(); final Expression rhs = binaryNode.rhs(); //detect ident cmp int_literal if (lhs instanceof IdentNode && rhs instanceof LiteralNode && ((LiteralNode<?>)rhs).getType().isInteger()) { final Symbol symbol = lhs.getSymbol(); final int margin = ((LiteralNode<?>)rhs).getInt32(); final TokenType op = test.tokenType(); switch (op) { case LT: case LE: symbol.setRange(RANGE.join(symbol.getRange(), Range.createRange(op == TokenType.LT ? margin - 1 : margin))); return symbol; case GT: case GE: //setRange(lhs, Range.createRange(op == TokenType.GT ? margin + 1 : margin)); //return symbol; default: break; } } } return null; }
@Override public boolean enterContinueNode(final ContinueNode continueNode) { lineNumber(continueNode); final LoopNode continueTo = lc.getContinueTo(continueNode.getLabel()); for (int i = 0; i < lc.getScopeNestingLevelTo(continueTo); i++) { closeWith(); } method.splitAwareGoto(lc, continueTo.getContinueLabel()); return false; }
/** * ContinueStatement : * continue Identifier? ; // [no LineTerminator here] * * See 12.7 * * Parse CONTINUE statement. */ private void continueStatement() { // Capture CONTINUE token. final int continueLine = line; final long continueToken = token; // CONTINUE tested in caller. nextOrEOL(); LabelNode labelNode = null; // SEMICOLON or label. switch (type) { case RBRACE: case SEMICOLON: case EOL: case EOF: break; default: final IdentNode ident = getIdent(); labelNode = lc.findLabel(ident.getName()); if (labelNode == null) { throw error(AbstractParser.message("undefined.label", ident.getName()), ident.getToken()); } break; } final String labelName = labelNode == null ? null : labelNode.getLabelName(); final LoopNode targetNode = lc.getContinueTo(labelName); if (targetNode == null) { throw error(AbstractParser.message("illegal.continue.stmt"), continueToken); } endOfLine(); // Construct and add CONTINUE node. appendStatement(new ContinueNode(continueLine, continueToken, finish, labelName)); }
private void tagNeverOptimisticLoopTest(final LoopNode loopNode) { final JoinPredecessorExpression test = loopNode.getTest(); if(test != null) { tagNeverOptimistic(test.getExpression()); } }
private void enterTestFirstLoop(final LoopNode loopNode, final JoinPredecessorExpression modify, final Expression iteratorValues, final boolean iteratorValuesAreObject) { final JoinPredecessorExpression test = loopNode.getTest(); if(isAlwaysFalse(test)) { test.accept(this); return; } final Label continueLabel = loopNode.getContinueLabel(); final Label breakLabel = loopNode.getBreakLabel(); final Label repeatLabel = modify == null ? continueLabel : new Label(""); final Map<Symbol, LvarType> beforeLoopTypes = localVariableTypes; for(;;) { jumpToLabel(loopNode, repeatLabel, beforeLoopTypes); final Map<Symbol, LvarType> beforeRepeatTypes = localVariableTypes; if(test != null) { test.accept(this); } if(!isAlwaysTrue(test)) { jumpToLabel(test, breakLabel); } if(iteratorValues instanceof IdentNode) { final IdentNode ident = (IdentNode)iteratorValues; // Receives iterator values; the optimistic type of the iterator values is tracked on the // identifier, but we override optimism if it's known that the object being iterated over will // never have primitive property names. onAssignment(ident, iteratorValuesAreObject ? LvarType.OBJECT : toLvarType(compiler.getOptimisticType(ident))); } final Block body = loopNode.getBody(); body.accept(this); if(reachable) { jumpToLabel(body, continueLabel); } joinOnLabel(continueLabel); if(!reachable) { break; } if(modify != null) { modify.accept(this); jumpToLabel(modify, repeatLabel); joinOnLabel(repeatLabel); } if(localVariableTypes.equals(beforeRepeatTypes)) { break; } // Reset the join points and repeat the analysis resetJoinPoint(continueLabel); resetJoinPoint(breakLabel); resetJoinPoint(repeatLabel); } if(isAlwaysTrue(test) && iteratorValues == null) { doesNotContinueSequentially(); } leaveBreakable(loopNode); }
private void enterForOrWhile(final LoopNode loopNode, final JoinPredecessorExpression modify) { // NOTE: the usual pattern for compiling test-first loops is "GOTO test; body; test; IFNE body". We use the less // conventional "test; IFEQ break; body; GOTO test; break;". It has one extra unconditional GOTO in each repeat // of the loop, but it's not a problem for modern JIT compilers. We do this because our local variable type // tracking is unfortunately not really prepared for out-of-order execution, e.g. compiling the following // contrived but legal JavaScript code snippet would fail because the test changes the type of "i" from object // to double: var i = {valueOf: function() { return 1} }; while(--i >= 0) { ... } // Instead of adding more complexity to the local variable type tracking, we instead choose to emit this // different code shape. final int liveLocalsOnBreak = method.getUsedSlotsWithLiveTemporaries(); final JoinPredecessorExpression test = loopNode.getTest(); if(Expression.isAlwaysFalse(test)) { loadAndDiscard(test); return; } method.beforeJoinPoint(loopNode); final Label continueLabel = loopNode.getContinueLabel(); final Label repeatLabel = modify != null ? new Label("for_repeat") : continueLabel; method.label(repeatLabel); final int liveLocalsOnContinue = method.getUsedSlotsWithLiveTemporaries(); final Block body = loopNode.getBody(); final Label breakLabel = loopNode.getBreakLabel(); final boolean testHasLiveConversion = test != null && LocalVariableConversion.hasLiveConversion(test); if(Expression.isAlwaysTrue(test)) { if(test != null) { loadAndDiscard(test); if(testHasLiveConversion) { method.beforeJoinPoint(test); } } } else if (test != null) { if (testHasLiveConversion) { emitBranch(test.getExpression(), body.getEntryLabel(), true); method.beforeJoinPoint(test); method._goto(breakLabel); } else { emitBranch(test.getExpression(), breakLabel, false); } } body.accept(this); if(repeatLabel != continueLabel) { emitContinueLabel(continueLabel, liveLocalsOnContinue); } if (loopNode.hasPerIterationScope() && lc.getCurrentBlock().needsScope()) { // ES6 for loops with LET init need a new scope for each iteration. We just create a shallow copy here. method.loadCompilerConstant(SCOPE); method.invoke(virtualCallNoLookup(ScriptObject.class, "copy", ScriptObject.class)); method.storeCompilerConstant(SCOPE); } if(method.isReachable()) { if(modify != null) { lineNumber(loopNode); loadAndDiscard(modify); method.beforeJoinPoint(modify); } method._goto(repeatLabel); } method.breakLabel(breakLabel, liveLocalsOnBreak); }
private void enterTestFirstLoop(final LoopNode loopNode, final JoinPredecessorExpression modify, final Expression iteratorValues, final boolean iteratorValuesAreObject) { final JoinPredecessorExpression test = loopNode.getTest(); if(isAlwaysFalse(test)) { visitExpressionOnEmptyStack(test); return; } final Label continueLabel = loopNode.getContinueLabel(); final Label breakLabel = loopNode.getBreakLabel(); final Label repeatLabel = modify == null ? continueLabel : new Label(""); final Map<Symbol, LvarType> beforeLoopTypes = localVariableTypes; for(;;) { jumpToLabel(loopNode, repeatLabel, beforeLoopTypes); final Map<Symbol, LvarType> beforeRepeatTypes = localVariableTypes; if(test != null) { visitExpressionOnEmptyStack(test); } if(!isAlwaysTrue(test)) { jumpToLabel(test, breakLabel); } if(iteratorValues instanceof IdentNode) { final IdentNode ident = (IdentNode)iteratorValues; // Receives iterator values; the optimistic type of the iterator values is tracked on the // identifier, but we override optimism if it's known that the object being iterated over will // never have primitive property names. onAssignment(ident, iteratorValuesAreObject ? LvarType.OBJECT : toLvarType(compiler.getOptimisticType(ident))); } final Block body = loopNode.getBody(); body.accept(this); if(reachable) { jumpToLabel(body, continueLabel); } joinOnLabel(continueLabel); if(!reachable) { break; } if(modify != null) { visitExpressionOnEmptyStack(modify); jumpToLabel(modify, repeatLabel); joinOnLabel(repeatLabel); } if(localVariableTypes.equals(beforeRepeatTypes)) { break; } // Reset the join points and repeat the analysis resetJoinPoint(continueLabel); resetJoinPoint(breakLabel); resetJoinPoint(repeatLabel); } if(isAlwaysTrue(test) && iteratorValues == null) { doesNotContinueSequentially(); } leaveBreakable(loopNode); }