Add IR parser of catch blocks

This commit is contained in:
Alexey Andreev 2016-12-04 18:28:30 +03:00
parent 6883b59fc3
commit 7ca6a4d64e
5 changed files with 81 additions and 6 deletions

View File

@ -321,7 +321,7 @@ public abstract class ValueType {
return VOID;
case 'L':
if (!string.endsWith(";")) {
throw new IllegalArgumentException("Wrong type descriptor");
return null;
}
return object(string.substring(1, string.length() - 1).replace('/', '.'));
default:

View File

@ -78,14 +78,17 @@ public class ListingBuilder {
sb.append(prefix).append(" ").append(insnSb).append("\n");
}
for (TryCatchBlockReader tryCatch : block.readTryCatchBlocks()) {
sb.append(prefix).append(" catch ").append(tryCatch.getExceptionType())
.append(" -> $").append(tryCatch.getHandler().getIndex());
sb.append(prefix).append(" catch ");
if (tryCatch.getExceptionType() != null) {
InstructionStringifier.escapeStringLiteral(tryCatch.getExceptionType(), sb);
}
sb.append(" goto $").append(tryCatch.getHandler().getIndex());
sb.append("\n");
for (TryCatchJointReader joint : tryCatch.readJoints()) {
sb.append(" @").append(joint.getReceiver().getIndex()).append(" := e-phi(");
sb.append(" @").append(joint.getReceiver().getIndex()).append(" := ephi ");
sb.append(joint.readSourceVariables().stream().map(sourceVar -> "@" + sourceVar.getIndex())
.collect(Collectors.joining(", ")));
sb.append(")\n");
sb.append("\n");
}
}
}

View File

@ -33,6 +33,8 @@ import org.teavm.model.MethodReference;
import org.teavm.model.Phi;
import org.teavm.model.Program;
import org.teavm.model.TextLocation;
import org.teavm.model.TryCatchBlock;
import org.teavm.model.TryCatchJoint;
import org.teavm.model.ValueType;
import org.teavm.model.Variable;
import org.teavm.model.instructions.ArrayElementType;
@ -88,6 +90,7 @@ public class ListingParser {
private Set<String> declaredBlocks = new HashSet<>();
private TextLocation currentLocation;
private BasicBlock currentBlock;
private TryCatchBlock currentTryCatch;
public Program parse(Reader reader) throws IOException, ListingParseException {
try {
@ -173,6 +176,7 @@ public class ListingParser {
b.setLabel(k);
return b;
});
currentTryCatch = null;
currentLocation = null;
do {
@ -268,6 +272,11 @@ public class ListingParser {
parseSwitch();
break;
}
case "catch": {
lexer.nextToken();
parseCatch();
break;
}
default:
unexpected();
break;
@ -344,6 +353,10 @@ public class ListingParser {
lexer.nextToken();
parsePhi(receiver);
break;
case "ephi":
lexer.nextToken();
parseExceptionPhi(receiver);
break;
case "classOf":
lexer.nextToken();
parseClassLiteral(receiver);
@ -402,6 +415,15 @@ public class ListingParser {
parseFieldGet(receiver);
break;
}
case "exception": {
lexer.nextToken();
if (!currentBlock.getInstructions().isEmpty() || currentBlock.getExceptionVariable() != null) {
throw new ListingParseException("Exception can be read as a first instruction",
lexer.getTokenStart());
}
currentBlock.setExceptionVariable(receiver);
break;
}
default:
unexpected();
break;
@ -563,6 +585,24 @@ public class ListingParser {
currentBlock.getPhis().add(phi);
}
private void parseExceptionPhi(Variable receiver) throws IOException, ListingParseException {
int phiStart = lexer.getIndex();
TryCatchJoint joint = new TryCatchJoint();
joint.setReceiver(receiver);
joint.getSourceVariables().add(expectVariable());
while (lexer.getToken() == ListingToken.COMMA) {
lexer.nextToken();
joint.getSourceVariables().add(expectVariable());
}
if (currentTryCatch == null) {
throw new ListingParseException("Exception phi must appear right after catch block", phiStart);
}
currentTryCatch.getJoints().add(joint);
}
private void parseClassLiteral(Variable receiver) throws IOException, ListingParseException {
ValueType type = expectValueType();
ClassConstantInstruction insn = new ClassConstantInstruction();
@ -736,6 +776,18 @@ public class ListingParser {
}
}
private void parseCatch() throws IOException, ListingParseException {
TryCatchBlock tryCatch = new TryCatchBlock();
if (lexer.getToken() == ListingToken.IDENTIFIER) {
tryCatch.setExceptionType((String) lexer.getTokenValue());
lexer.nextToken();
}
expectKeyword("goto");
tryCatch.setHandler(expectBlock());
currentTryCatch = tryCatch;
currentBlock.getTryCatchBlocks().add(tryCatch);
}
private void parseCast(Variable receiver) throws IOException, ListingParseException {
lexer.nextToken();
Variable value = expectVariable();
@ -1109,7 +1161,8 @@ public class ListingParser {
throw new ListingParseException("Unexpected token " + lexer.getToken(), lexer.getTokenStart());
}
private void addInstruction(Instruction instruction) {
private void addInstruction(Instruction instruction) throws ListingParseException {
currentTryCatch = null;
instruction.setLocation(currentLocation);
currentBlock.getInstructions().add(instruction);
}

View File

@ -146,6 +146,11 @@ public class ParserTest {
runTest("switchInsn");
}
@Test
public void exceptions() throws Exception {
runTest("exceptions");
}
private Program runTest(String name) throws IOException {
ClassLoader classLoader = ParserTest.class.getClassLoader();
String path = "model/text/" + name + ".txt";

View File

@ -0,0 +1,14 @@
$start
@a_1 := 0
invokeStatic `foo.Bar.baz()I`
@a_2 := 1
invokeStatic `foo.Bar.baz()I`
@a_3 := 2
return @a_3
catch java.lang.Exception goto $handler
@a_h := ephi @a_1, @a_2, @a_3
$handler
@e := exception
@out := field `java.lang.String.out` as `Ljava/io/PrintStream;`
invokeVirtual `java.io.PrintStream.println(Ljava/lang/Object;)V` @out, @e
return @a_h