Adds try/catch support in simple cases

This commit is contained in:
konsoletyper 2014-02-26 16:42:31 +04:00
parent de245613c4
commit 62686878c6
22 changed files with 264 additions and 46 deletions

View File

@ -15,6 +15,7 @@
*/
package org.teavm.classlib.java.lang;
import org.teavm.classlib.java.io.TPrintStream;
import org.teavm.javascript.ni.Remove;
import org.teavm.javascript.ni.Rename;
import org.teavm.javascript.ni.Superclass;
@ -107,4 +108,13 @@ public class TThrowable extends RuntimeException {
this.cause = cause;
return this;
}
@Override
public void printStackTrace() {
printStackTrace(TSystem.err);
}
public void printStackTrace(TPrintStream stream) {
stream.println(TString.wrap(getClass().getName() + ": " + getMessage()));
}
}

View File

@ -105,4 +105,14 @@ class BlockRefCountVisitor implements StatementVisitor {
@Override
public void visit(InitClassStatement statement) {
}
@Override
public void visit(TryCatchStatement statement) {
for (Statement part : statement.getProtectedBody()) {
part.acceptVisitor(this);
}
for (Statement part : statement.getHandler()) {
part.acceptVisitor(this);
}
}
}

View File

@ -111,4 +111,9 @@ class BreakToContinueReplacer implements StatementVisitor {
public void visit(InitClassStatement statement) {
}
@Override
public void visit(TryCatchStatement statement) {
visitSequence(statement.getProtectedBody());
visitSequence(statement.getHandler());
}
}

View File

@ -171,7 +171,8 @@ public class Decompiler {
public RegularMethodNode decompileRegular(MethodHolder method) {
lastBlockId = 1;
indexer = new GraphIndexer(ProgramUtils.buildControlFlowGraph(method.getProgram()));
graph = ProgramUtils.buildControlFlowGraph(method.getProgram());
indexer = new GraphIndexer(graph);
graph = indexer.getGraph();
loopGraph = new LoopGraph(this.graph);
unflatCode();
@ -218,6 +219,18 @@ public class Decompiler {
insn.acceptVisitor(generator);
}
block.body.addAll(generator.statements);
for (TryCatchBlock tryCatch : generator.currentBlock.getTryCatchBlocks()) {
TryCatchStatement tryCatchStmt = new TryCatchStatement();
tryCatchStmt.setExceptionType(tryCatch.getExceptionType());
tryCatchStmt.setExceptionVariable(tryCatch.getExceptionVariable().getIndex());
tryCatchStmt.getProtectedBody().addAll(block.body);
block.body.clear();
block.body.add(tryCatchStmt);
Statement handlerStmt = generator.generateJumpStatement(tryCatch.getHandler());
if (handlerStmt != null) {
tryCatchStmt.getHandler().add(handlerStmt);
}
}
}
}
SequentialStatement result = new SequentialStatement();

View File

@ -548,4 +548,11 @@ class OptimizingVisitor implements StatementVisitor, ExprVisitor {
public void visit(InitClassStatement statement) {
resultStmt = statement;
}
@Override
public void visit(TryCatchStatement statement) {
processSequence(statement.getProtectedBody());
processSequence(statement.getHandler());
resultStmt = statement;
}
}

View File

@ -119,4 +119,10 @@ class RedundantLabelEliminator implements StatementVisitor {
@Override
public void visit(InitClassStatement statement) {
}
@Override
public void visit(TryCatchStatement statement) {
visitSequence(statement.getProtectedBody());
visitSequence(statement.getHandler());
}
}

View File

@ -109,4 +109,14 @@ class ReferenceCountingVisitor implements StatementVisitor {
@Override
public void visit(InitClassStatement statement) {
}
@Override
public void visit(TryCatchStatement statement) {
for (Statement part : statement.getProtectedBody()) {
part.acceptVisitor(this);
}
for (Statement part : statement.getHandler()) {
part.acceptVisitor(this);
}
}
}

View File

@ -1249,6 +1249,46 @@ public class Renderer implements ExprVisitor, StatementVisitor {
}
}
@Override
public void visit(TryCatchStatement statement) {
try {
writer.append("try").ws().append("{").softNewLine().indent();
List<TryCatchStatement> sequence = new ArrayList<>();
sequence.add(statement);
List<Statement> protectedBody = statement.getProtectedBody();
while (protectedBody.size() == 1 && protectedBody.get(0) instanceof TryCatchStatement) {
TryCatchStatement nextStatement = (TryCatchStatement)protectedBody.get(0);
sequence.add(nextStatement);
protectedBody = nextStatement.getProtectedBody();
}
for (Statement part : protectedBody) {
part.acceptVisitor(this);
}
String var = variableName(statement.getExceptionVariable());
writer.outdent().append("}").ws().append("catch").ws().append("(").append(var).append(")")
.ws().append("{").indent().softNewLine();
for (TryCatchStatement catchClause : sequence) {
writer.append("if").ws().append("(").append(var).append(" instanceof ")
.appendClass(catchClause.getExceptionType()).append(")").ws().append("{")
.indent().softNewLine();
if (statement.getExceptionVariable() != catchClause.getExceptionVariable()) {
writer.append(variableName(catchClause.getExceptionVariable())).ws().append("=").ws()
.append(var).append(";").softNewLine();
}
for (Statement part : statement.getHandler()) {
part.acceptVisitor(this);
}
writer.outdent().append("}").ws().append("else ");
}
writer.append("{").indent().softNewLine();
writer.append("throw ").append(var).append(";").softNewLine();
writer.outdent().append("}").softNewLine();
writer.outdent().append("}").softNewLine();
} catch (IOException e) {
throw new RenderingException("IO error occured", e);
}
}
private Injector getInjector(MethodReference ref) {
InjectorHolder holder = injectorMap.get(ref);
if (holder == null) {

View File

@ -573,7 +573,7 @@ class StatementGenerator implements InstructionVisitor {
assign(castToInteger(Expr.binary(op, Expr.var(first), Expr.var(second))), result);
}
private Statement generateJumpStatement(BasicBlock target) {
Statement generateJumpStatement(BasicBlock target) {
if (nextBlock == target) {
return null;
}

View File

@ -215,4 +215,14 @@ class UnusedVariableEliminator implements ExprVisitor, StatementVisitor {
@Override
public void visit(InitClassStatement statement) {
}
@Override
public void visit(TryCatchStatement statement) {
for (Statement part : statement.getProtectedBody()) {
part.acceptVisitor(this);
}
for (Statement part : statement.getHandler()) {
part.acceptVisitor(this);
}
}
}

View File

@ -189,4 +189,15 @@ public class RenamingVisitor implements StatementVisitor, ExprVisitor {
@Override
public void visit(InitClassStatement statement) {
}
@Override
public void visit(TryCatchStatement statement) {
for (Statement part : statement.getProtectedBody()) {
part.acceptVisitor(this);
}
for (Statement part : statement.getHandler()) {
part.acceptVisitor(this);
}
statement.setExceptionVariable(varNames[statement.getExceptionVariable()]);
}
}

View File

@ -45,4 +45,6 @@ public interface StatementVisitor {
void visit(IncrementStatement statement);
void visit(InitClassStatement statement);
void visit(TryCatchStatement statement);
}

View File

@ -0,0 +1,59 @@
/*
* Copyright 2014 Alexey Andreev.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.teavm.javascript.ast;
import java.util.ArrayList;
import java.util.List;
/**
*
* @author Alexey Andreev
*/
public class TryCatchStatement extends Statement {
private List<Statement> protectedBody = new ArrayList<>();
private List<Statement> handler = new ArrayList<>();
private String exceptionType;
private int exceptionVariable;
public List<Statement> getProtectedBody() {
return protectedBody;
}
public List<Statement> getHandler() {
return handler;
}
public String getExceptionType() {
return exceptionType;
}
public void setExceptionType(String exceptionType) {
this.exceptionType = exceptionType;
}
public int getExceptionVariable() {
return exceptionVariable;
}
public void setExceptionVariable(int exceptionVariable) {
this.exceptionVariable = exceptionVariable;
}
@Override
public void acceptVisitor(StatementVisitor visitor) {
visitor.visit(this);
}
}

View File

@ -198,14 +198,15 @@ public class BasicBlock implements BasicBlockReader {
return tryCatchBlocks.size();
}
@Override public void add(int index, TryCatchBlock element) {
if (!element.protectedBlocks.add(BasicBlock.this)) {
if (element.protectedBlock == BasicBlock.this) {
throw new IllegalStateException("This try/catch block is already added to basic block");
}
element.protectedBlock = BasicBlock.this;
tryCatchBlocks.add(index, element);
}
@Override public TryCatchBlock remove(int index) {
TryCatchBlock tryCatch = tryCatchBlocks.remove(index);
tryCatch.protectedBlocks.remove(BasicBlock.this);
tryCatch.protectedBlock = null;
return tryCatch;
}
@Override public TryCatchBlock set(int index, TryCatchBlock element) {
@ -213,17 +214,17 @@ public class BasicBlock implements BasicBlockReader {
if (oldTryCatch == element) {
return oldTryCatch;
}
if (element.protectedBlocks.contains(BasicBlock.this)) {
if (element.protectedBlock == BasicBlock.this) {
throw new IllegalStateException("This try/catch block is already added to basic block");
}
oldTryCatch.protectedBlocks.remove(BasicBlock.this);
element.protectedBlocks.add(BasicBlock.this);
oldTryCatch.protectedBlock = null;
element.protectedBlock = BasicBlock.this;
tryCatchBlocks.set(index, element);
return oldTryCatch;
}
@Override public void clear() {
for (TryCatchBlock tryCatch : tryCatchBlocks) {
tryCatch.protectedBlocks.remove(BasicBlock.this);
tryCatch.protectedBlock = null;
}
tryCatchBlocks.clear();
}

View File

@ -15,16 +15,12 @@
*/
package org.teavm.model;
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;
/**
*
* @author Alexey Andreev <konsoletyper@gmail.com>
*/
public class TryCatchBlock implements TryCatchBlockReader {
Set<BasicBlock> protectedBlocks = new HashSet<>();
BasicBlock protectedBlock;
private BasicBlock handler;
private String exceptionType;
private Variable exceptionVariable;
@ -56,10 +52,8 @@ public class TryCatchBlock implements TryCatchBlockReader {
this.exceptionVariable = exceptionVariable;
}
private Set<BasicBlock> immutableProtectedBLocks = Collections.unmodifiableSet(protectedBlocks);
@Override
public Set<BasicBlock> readProtectedBlocks() {
return immutableProtectedBLocks;
public BasicBlock getProtectedBlock() {
return protectedBlock;
}
}

View File

@ -15,14 +15,12 @@
*/
package org.teavm.model;
import java.util.Set;
/**
*
* @author Alexey Andreev <konsoletyper@gmail.com>
*/
public interface TryCatchBlockReader {
Set<? extends BasicBlockReader> readProtectedBlocks();
BasicBlockReader getProtectedBlock();
BasicBlockReader getHandler();

View File

@ -15,10 +15,7 @@
*/
package org.teavm.model.util;
import org.teavm.model.BasicBlock;
import org.teavm.model.Incoming;
import org.teavm.model.Phi;
import org.teavm.model.Program;
import org.teavm.model.*;
import org.teavm.model.instructions.*;
/**
@ -37,6 +34,9 @@ public abstract class BasicBlockMapper implements InstructionVisitor {
incoming.setSource(map(incoming.getSource()));
}
}
for (TryCatchBlock tryCatch : block.getTryCatchBlocks()) {
tryCatch.setHandler(map(tryCatch.getHandler()));
}
}
}

View File

@ -15,8 +15,6 @@
*/
package org.teavm.model.util;
import java.util.HashMap;
import java.util.Map;
import org.teavm.common.Graph;
import org.teavm.common.GraphBuilder;
import org.teavm.model.*;
@ -58,7 +56,6 @@ public class ProgramUtils {
for (int i = 0; i < program.basicBlockCount(); ++i) {
copy.createBasicBlock();
}
Map<TryCatchBlock, TryCatchBlock> tryCatchCopies = new HashMap<>();
for (int i = 0; i < program.basicBlockCount(); ++i) {
BasicBlock block = program.basicBlockAt(i);
BasicBlock blockCopy = copy.basicBlockAt(i);
@ -78,13 +75,10 @@ public class ProgramUtils {
blockCopy.getPhis().add(phiCopy);
}
for (TryCatchBlock tryCatch : block.getTryCatchBlocks()) {
TryCatchBlock tryCatchCopy = tryCatchCopies.get(tryCatch);
if (tryCatchCopy == null) {
tryCatchCopy = new TryCatchBlock();
tryCatchCopy.setExceptionType(tryCatchCopy.getExceptionType());
tryCatchCopy.setHandler(copy.basicBlockAt(tryCatch.getHandler().getIndex()));
tryCatchCopies.put(tryCatch, tryCatchCopy);
}
TryCatchBlock tryCatchCopy = new TryCatchBlock();
tryCatchCopy.setExceptionType(tryCatch.getExceptionType());
tryCatchCopy.setExceptionVariable(copy.variableAt(tryCatch.getExceptionVariable().getIndex()));
tryCatchCopy.setHandler(copy.basicBlockAt(tryCatch.getHandler().getIndex()));
blockCopy.getTryCatchBlocks().add(tryCatchCopy);
}
}

View File

@ -76,12 +76,16 @@ public class RegisterAllocator {
Map<BasicBlock, BasicBlock> blockMap = new HashMap<>();
for (Phi phi : program.basicBlockAt(i).getPhis()) {
for (Incoming incoming : phi.getIncomings()) {
insertCopy(incoming, blockMap);
if (!isExceptionHandler(incoming)) {
insertCopy(incoming, blockMap);
}
}
}
for (Phi phi : program.basicBlockAt(i).getPhis()) {
for (Incoming incoming : phi.getIncomings()) {
insertCopy(incoming, blockMap);
if (!isExceptionHandler(incoming)) {
insertCopy(incoming, blockMap);
}
}
}
}
@ -122,6 +126,15 @@ public class RegisterAllocator {
incoming.setValue(copyInstruction.getReceiver());
}
private boolean isExceptionHandler(Incoming incoming) {
for (TryCatchBlock tryCatch : incoming.getSource().getTryCatchBlocks()) {
if (tryCatch.getExceptionVariable() == incoming.getValue()) {
return true;
}
}
return false;
}
private void removeRedundantCopies(Program program, List<MutableGraphNode> interferenceGraph,
DisjointSet congruenceClasses) {
for (int i = 0; i < program.basicBlockCount(); ++i) {
@ -187,6 +200,10 @@ public class RegisterAllocator {
incoming.setValue(program.variableAt(varMap[incoming.getValue().getIndex()]));
}
}
for (TryCatchBlock tryCatch : block.getTryCatchBlocks()) {
tryCatch.setExceptionVariable(program.variableAt(
varMap[tryCatch.getExceptionVariable().getIndex()]));
}
}
}

View File

@ -101,6 +101,10 @@ public class CommonSubexpressionElimination implements MethodOptimization {
int value = map[incoming.getValue().getIndex()];
incoming.setValue(program.variableAt(value));
}
for (TryCatchBlock tryCatch : block.getTryCatchBlocks()) {
int var = map[tryCatch.getExceptionVariable().getIndex()];
tryCatch.setExceptionVariable(program.variableAt(var));
}
for (int succ : dom.outgoingEdges(v)) {
stack[top++] = succ;
}

View File

@ -213,10 +213,6 @@ public class ProgramParser {
}
for (Object obj : method.tryCatchBlocks) {
TryCatchBlockNode tryCatchNode = (TryCatchBlockNode)obj;
TryCatchBlock tryCatch = new TryCatchBlock();
tryCatch.setExceptionType(tryCatchNode.type.replace('/', '.'));
tryCatch.setHandler(getBasicBlock(labelIndexes.get(tryCatchNode.handler.getLabel())));
tryCatch.setExceptionVariable(getVariable(minLocal + method.maxLocals));
int start = labelIndexes.get(tryCatchNode.start.getLabel());
int end = labelIndexes.get(tryCatchNode.end.getLabel());
getBasicBlock(start);
@ -224,6 +220,12 @@ public class ProgramParser {
for (int i = start; i < end; ++i) {
BasicBlock block = basicBlocks.get(i);
if (block != null) {
TryCatchBlock tryCatch = new TryCatchBlock();
if (tryCatchNode.type != null) {
tryCatch.setExceptionType(tryCatchNode.type.replace('/', '.'));
}
tryCatch.setHandler(getBasicBlock(labelIndexes.get(tryCatchNode.handler.getLabel())));
tryCatch.setExceptionVariable(getVariable(minLocal + method.maxLocals));
block.getTryCatchBlocks().add(tryCatch);
}
}

View File

@ -15,9 +15,10 @@
*/
package org.teavm.parsing;
import java.util.Arrays;
import java.util.List;
import org.teavm.common.*;
import java.util.*;
import org.teavm.common.DominatorTree;
import org.teavm.common.Graph;
import org.teavm.common.GraphUtils;
import org.teavm.model.*;
import org.teavm.model.instructions.*;
import org.teavm.model.util.DefinitionExtractor;
@ -114,6 +115,17 @@ public class SSATransformer {
}
}
List<List<TryCatchBlock>> caughtBlocks = new ArrayList<>();
List<List<Phi>> specialPhis = new ArrayList<>();
for (int i = 0; i < program.basicBlockCount(); ++i) {
caughtBlocks.add(new ArrayList<TryCatchBlock>());
specialPhis.add(new ArrayList<Phi>());
}
for (int i = 0; i < program.basicBlockCount(); ++i) {
for (TryCatchBlock tryCatch : program.basicBlockAt(i).getTryCatchBlocks()) {
caughtBlocks.get(tryCatch.getHandler().getIndex()).add(tryCatch);
}
}
boolean[] processed = new boolean[program.basicBlockCount()];
while (head > 0) {
Task task = stack[--head];
@ -128,12 +140,22 @@ public class SSATransformer {
variableMap[phi.getReceiver().getIndex()] = var;
phi.setReceiver(var);
}
if (!caughtBlocks.get(currentBlock.getIndex()).isEmpty()) {
Phi phi = new Phi();
phi.setReceiver(program.createVariable());
for (TryCatchBlock tryCatch : caughtBlocks.get(currentBlock.getIndex())) {
variableMap[tryCatch.getExceptionVariable().getIndex()] = phi.getReceiver();
tryCatch.setExceptionVariable(program.createVariable());
Incoming incoming = new Incoming();
incoming.setSource(tryCatch.getProtectedBlock());
incoming.setValue(tryCatch.getExceptionVariable());
phi.getIncomings().add(incoming);
}
specialPhis.get(currentBlock.getIndex()).add(phi);
}
for (Instruction insn : currentBlock.getInstructions()) {
insn.acceptVisitor(consumer);
}
for (TryCatchBlock tryCatch : currentBlock.getTryCatchBlocks()) {
define(tryCatch.getExceptionVariable());
}
int[] successors = domGraph.outgoingEdges(currentBlock.getIndex());
for (int i = 0; i < successors.length; ++i) {
Task next = new Task();
@ -157,6 +179,9 @@ public class SSATransformer {
}
}
}
for (int i = 0; i < specialPhis.size(); ++i) {
program.basicBlockAt(i).getPhis().addAll(specialPhis.get(i));
}
}
private void markAssignment(Variable var) {