private LocalVariableConversion createConversion(final Symbol symbol, final LvarType branchLvarType, final Map<Symbol, LvarType> joinLvarTypes, final LocalVariableConversion next) { final LvarType targetType = joinLvarTypes.get(symbol); assert targetType != null; if(targetType == branchLvarType) { return next; } // NOTE: we could naively just use symbolIsUsed(symbol, branchLvarType) here, but that'd be wrong. While // technically a conversion will read the value of the symbol with that type, but it will also write it to a new // type, and that type might be dead (we can't know yet). For this reason, we don't treat conversion reads as // real uses until we know their target type is live. If we didn't do this, and just did a symbolIsUsed here, // we'd introduce false live variables which could nevertheless turn into dead ones in a subsequent // deoptimization, causing a shift in the list of live locals that'd cause erroneous restoration of // continuations (since RewriteException's byteCodeSlots carries an array and not a name-value map). symbolIsConverted(symbol, branchLvarType, targetType); //symbolIsUsed(symbol, branchLvarType); return new LocalVariableConversion(symbol, branchLvarType.type, targetType.type, next); }
private LocalVariableConversion createConversion(final Symbol symbol, final LvarType branchLvarType, final Map<Symbol, LvarType> joinLvarTypes, final LocalVariableConversion next) { if (invalidatedSymbols.contains(symbol)) { return next; } final LvarType targetType = joinLvarTypes.get(symbol); assert targetType != null; if(targetType == branchLvarType) { return next; } // NOTE: we could naively just use symbolIsUsed(symbol, branchLvarType) here, but that'd be wrong. While // technically a conversion will read the value of the symbol with that type, but it will also write it to a new // type, and that type might be dead (we can't know yet). For this reason, we don't treat conversion reads as // real uses until we know their target type is live. If we didn't do this, and just did a symbolIsUsed here, // we'd introduce false live variables which could nevertheless turn into dead ones in a subsequent // deoptimization, causing a shift in the list of live locals that'd cause erroneous restoration of // continuations (since RewriteException's byteCodeSlots carries an array and not a name-value map). symbolIsConverted(symbol, branchLvarType, targetType); return new LocalVariableConversion(symbol, branchLvarType.type, targetType.type, next); }
private LocalVariableConversion createConversion(final Symbol symbol, final LvarType branchLvarType, final Map<Symbol, LvarType> joinLvarTypes, final LocalVariableConversion next) { final LvarType targetType = joinLvarTypes.get(symbol); assert targetType != null; if(targetType == branchLvarType) { return next; } // NOTE: we could naively just use symbolIsUsed(symbol, branchLvarType) here, but that'd be wrong. While // technically a conversion will read the value of the symbol with that type, but it will also write it to a new // type, and that type might be dead (we can't know yet). For this reason, we don't treat conversion reads as // real uses until we know their target type is live. If we didn't do this, and just did a symbolIsUsed here, // we'd introduce false live variables which could nevertheless turn into dead ones in a subsequent // deoptimization, causing a shift in the list of live locals that'd cause erroneous restoration of // continuations (since RewriteException's byteCodeSlots carries an array and not a name-value map). symbolIsConverted(symbol, branchLvarType, targetType); return new LocalVariableConversion(symbol, branchLvarType.type, targetType.type, next); }
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(); } }
void beforeTry(final TryNode tryNode, final Label recovery) { LocalVariableConversion next = tryNode.getLocalVariableConversion(); while(next != null) { if(next.isLive()) { final Type to = emitLocalVariableConversion(next, false); recovery.getStack().onLocalStore(to, next.getSymbol().getSlot(to), true); } next = next.getNext(); } }
private Type emitLocalVariableConversion(final LocalVariableConversion conversion, final boolean onlySymbolLiveValue) { final Type from = conversion.getFrom(); final Type to = conversion.getTo(); final Symbol symbol = conversion.getSymbol(); assert symbol.isBytecodeLocal(); if(from == Type.UNDEFINED) { loadUndefined(to); } else { load(symbol, from).convert(to); } store(symbol, to, onlySymbolLiveValue); return to; }
private void optimizeLogicalOperand(final Expression expr, final Label label, final boolean state, final boolean isRhs) { final JoinPredecessorExpression jpexpr = (JoinPredecessorExpression)expr; if(LocalVariableConversion.hasLiveConversion(jpexpr)) { final Label after = new Label("after"); branchOptimizer(jpexpr.getExpression(), after, !state); method.beforeJoinPoint(jpexpr); method._goto(label); method.label(after); if(isRhs) { method.beforeJoinPoint(jpexpr); } } else { branchOptimizer(jpexpr.getExpression(), label, state); } }
private void enterDoWhile(final WhileNode whileNode) { final int liveLocalsOnContinueOrBreak = method.getUsedSlotsWithLiveTemporaries(); method.beforeJoinPoint(whileNode); final Block body = whileNode.getBody(); body.accept(this); emitContinueLabel(whileNode.getContinueLabel(), liveLocalsOnContinueOrBreak); if(method.isReachable()) { lineNumber(whileNode); final JoinPredecessorExpression test = whileNode.getTest(); final Label bodyEntryLabel = body.getEntryLabel(); final boolean testHasLiveConversion = LocalVariableConversion.hasLiveConversion(test); if(Expression.isAlwaysFalse(test)) { loadAndDiscard(test); if(testHasLiveConversion) { method.beforeJoinPoint(test); } } else if(testHasLiveConversion) { // If we have conversions after the test in do-while, they need to be effected on both branches. final Label beforeExit = new Label("do_while_preexit"); emitBranch(test.getExpression(), beforeExit, false); method.beforeJoinPoint(test); method._goto(bodyEntryLabel); method.label(beforeExit); method.beforeJoinPoint(test); } else { emitBranch(test.getExpression(), bodyEntryLabel, true); } } method.breakLabel(whileNode.getBreakLabel(), liveLocalsOnContinueOrBreak); }