@Override public boolean enterTernaryNode(final TernaryNode ternaryNode) { final Expression test = ternaryNode.getTest(); final Expression trueExpr = ternaryNode.getTrueExpression(); final Expression falseExpr = ternaryNode.getFalseExpression(); test.accept(this); final Map<Symbol, LvarType> testExitLvarTypes = localVariableTypes; if(!isAlwaysFalse(test)) { trueExpr.accept(this); } final Map<Symbol, LvarType> trueExitLvarTypes = localVariableTypes; localVariableTypes = testExitLvarTypes; if(!isAlwaysTrue(test)) { falseExpr.accept(this); } final Map<Symbol, LvarType> falseExitLvarTypes = localVariableTypes; localVariableTypes = getUnionTypes(trueExitLvarTypes, falseExitLvarTypes); setConversion((JoinPredecessor)trueExpr, trueExitLvarTypes, localVariableTypes); setConversion((JoinPredecessor)falseExpr, falseExitLvarTypes, localVariableTypes); return false; }
void beforeJoinPoint(final JoinPredecessor joinPredecessor) { LocalVariableConversion next = joinPredecessor.getLocalVariableConversion(); while(next != null) { final Symbol symbol = next.getSymbol(); if(next.isLive()) { emitLocalVariableConversion(next, true); } else { markDeadLocalVariable(symbol); } next = next.getNext(); } }
/** * If we're in a try/catch block, add an edge from the specified node to the try node's pre-catch label. */ private void jumpToCatchBlock(final JoinPredecessor jumpOrigin) { final Label currentCatchLabel = catchLabels.peek(); if(currentCatchLabel != null) { jumpToLabel(jumpOrigin, currentCatchLabel); } }
@Override public boolean enterBinaryNode(final BinaryNode binaryNode) { // NOTE: regardless of operator's lexical associativity, lhs is always evaluated first. final Expression lhs = binaryNode.lhs(); final LvarType lhsType; if (!(lhs instanceof IdentNode && binaryNode.isTokenType(TokenType.ASSIGN))) { lhsType = visitExpression(lhs); } else { // Can't visit IdentNode on LHS of a simple assignment, as visits imply use, and this is def. // The type is irrelevant, as only RHS is used to determine the type anyway. lhsType = LvarType.UNDEFINED; } final boolean isLogical = binaryNode.isLogical(); final Label joinLabel = isLogical ? new Label("") : null; if(isLogical) { jumpToLabel((JoinPredecessor)lhs, joinLabel); } final Expression rhs = binaryNode.rhs(); final LvarType rhsType = visitExpression(rhs); if(isLogical) { jumpToLabel((JoinPredecessor)rhs, joinLabel); } joinOnLabel(joinLabel); final LvarType type = toLvarType(binaryNode.setOperands(lhsType.typeExpression, rhsType.typeExpression).getType()); if(binaryNode.isAssignment() && lhs instanceof IdentNode) { if(binaryNode.isSelfModifying()) { onSelfAssignment((IdentNode)lhs, type); } else { onAssignment((IdentNode)lhs, type); } } typeStack.push(type); return false; }
@Override public boolean enterTernaryNode(final TernaryNode ternaryNode) { final Expression test = ternaryNode.getTest(); final Expression trueExpr = ternaryNode.getTrueExpression(); final Expression falseExpr = ternaryNode.getFalseExpression(); visitExpression(test); final Map<Symbol, LvarType> testExitLvarTypes = localVariableTypes; final LvarType trueType; if(!isAlwaysFalse(test)) { trueType = visitExpression(trueExpr); } else { trueType = null; } final Map<Symbol, LvarType> trueExitLvarTypes = localVariableTypes; localVariableTypes = testExitLvarTypes; final LvarType falseType; if(!isAlwaysTrue(test)) { falseType = visitExpression(falseExpr); } else { falseType = null; } final Map<Symbol, LvarType> falseExitLvarTypes = localVariableTypes; localVariableTypes = getUnionTypes(trueExitLvarTypes, falseExitLvarTypes); setConversion((JoinPredecessor)trueExpr, trueExitLvarTypes, localVariableTypes); setConversion((JoinPredecessor)falseExpr, falseExitLvarTypes, localVariableTypes); typeStack.push(trueType != null ? falseType != null ? widestLvarType(trueType, falseType) : trueType : assertNotNull(falseType)); return false; }
private void printLocalVariableConversion(final JoinPredecessor joinPredecessor) { LocalVariableConversion.toString(joinPredecessor.getLocalVariableConversion(), sb); }
JumpOrigin(final JoinPredecessor node, final Map<Symbol, LvarType> types) { this.node = node; this.types = types; }
void addOrigin(final JoinPredecessor originNode, final Map<Symbol, LvarType> originTypes) { origins.add(new JumpOrigin(originNode, originTypes)); this.types = getUnionTypes(this.types, originTypes); }
private void jumpToLabel(final JoinPredecessor jumpOrigin, final Label label) { jumpToLabel(jumpOrigin, label, localVariableTypes); }
private void jumpToLabel(final JoinPredecessor jumpOrigin, final Label label, final Map<Symbol, LvarType> types) { getOrCreateJumpTarget(label).addOrigin(jumpOrigin, types); }
@SuppressWarnings("unchecked") private <T extends JoinPredecessor> T setLocalVariableConversion(final JoinPredecessor original, final T jp) { // NOTE: can't use Map.remove() as our copy-on-write AST semantics means some nodes appear twice (in // finally blocks), so we need to be able to access conversions for them multiple times. return (T)jp.setLocalVariableConversion(lc, localVariableConversions.get(original)); }
void addOrigin(final JoinPredecessor originNode, final Map<Symbol, LvarType> originTypes, final LocalVariableTypesCalculator calc) { origins.add(new JumpOrigin(originNode, originTypes)); this.types = calc.getUnionTypes(this.types, originTypes); }
private void jumpToLabel(final JoinPredecessor jumpOrigin, final Label label, final Map<Symbol, LvarType> types) { getOrCreateJumpTarget(label).addOrigin(jumpOrigin, types, this); }