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; return VOID;
case 'L': case 'L':
if (!string.endsWith(";")) { if (!string.endsWith(";")) {
throw new IllegalArgumentException("Wrong type descriptor"); return null;
} }
return object(string.substring(1, string.length() - 1).replace('/', '.')); return object(string.substring(1, string.length() - 1).replace('/', '.'));
default: default:

View File

@ -78,14 +78,17 @@ public class ListingBuilder {
sb.append(prefix).append(" ").append(insnSb).append("\n"); sb.append(prefix).append(" ").append(insnSb).append("\n");
} }
for (TryCatchBlockReader tryCatch : block.readTryCatchBlocks()) { for (TryCatchBlockReader tryCatch : block.readTryCatchBlocks()) {
sb.append(prefix).append(" catch ").append(tryCatch.getExceptionType()) sb.append(prefix).append(" catch ");
.append(" -> $").append(tryCatch.getHandler().getIndex()); if (tryCatch.getExceptionType() != null) {
InstructionStringifier.escapeStringLiteral(tryCatch.getExceptionType(), sb);
}
sb.append(" goto $").append(tryCatch.getHandler().getIndex());
sb.append("\n"); sb.append("\n");
for (TryCatchJointReader joint : tryCatch.readJoints()) { 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()) sb.append(joint.readSourceVariables().stream().map(sourceVar -> "@" + sourceVar.getIndex())
.collect(Collectors.joining(", "))); .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.Phi;
import org.teavm.model.Program; import org.teavm.model.Program;
import org.teavm.model.TextLocation; import org.teavm.model.TextLocation;
import org.teavm.model.TryCatchBlock;
import org.teavm.model.TryCatchJoint;
import org.teavm.model.ValueType; import org.teavm.model.ValueType;
import org.teavm.model.Variable; import org.teavm.model.Variable;
import org.teavm.model.instructions.ArrayElementType; import org.teavm.model.instructions.ArrayElementType;
@ -88,6 +90,7 @@ public class ListingParser {
private Set<String> declaredBlocks = new HashSet<>(); private Set<String> declaredBlocks = new HashSet<>();
private TextLocation currentLocation; private TextLocation currentLocation;
private BasicBlock currentBlock; private BasicBlock currentBlock;
private TryCatchBlock currentTryCatch;
public Program parse(Reader reader) throws IOException, ListingParseException { public Program parse(Reader reader) throws IOException, ListingParseException {
try { try {
@ -173,6 +176,7 @@ public class ListingParser {
b.setLabel(k); b.setLabel(k);
return b; return b;
}); });
currentTryCatch = null;
currentLocation = null; currentLocation = null;
do { do {
@ -268,6 +272,11 @@ public class ListingParser {
parseSwitch(); parseSwitch();
break; break;
} }
case "catch": {
lexer.nextToken();
parseCatch();
break;
}
default: default:
unexpected(); unexpected();
break; break;
@ -344,6 +353,10 @@ public class ListingParser {
lexer.nextToken(); lexer.nextToken();
parsePhi(receiver); parsePhi(receiver);
break; break;
case "ephi":
lexer.nextToken();
parseExceptionPhi(receiver);
break;
case "classOf": case "classOf":
lexer.nextToken(); lexer.nextToken();
parseClassLiteral(receiver); parseClassLiteral(receiver);
@ -402,6 +415,15 @@ public class ListingParser {
parseFieldGet(receiver); parseFieldGet(receiver);
break; 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: default:
unexpected(); unexpected();
break; break;
@ -563,6 +585,24 @@ public class ListingParser {
currentBlock.getPhis().add(phi); 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 { private void parseClassLiteral(Variable receiver) throws IOException, ListingParseException {
ValueType type = expectValueType(); ValueType type = expectValueType();
ClassConstantInstruction insn = new ClassConstantInstruction(); 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 { private void parseCast(Variable receiver) throws IOException, ListingParseException {
lexer.nextToken(); lexer.nextToken();
Variable value = expectVariable(); Variable value = expectVariable();
@ -1109,7 +1161,8 @@ public class ListingParser {
throw new ListingParseException("Unexpected token " + lexer.getToken(), lexer.getTokenStart()); 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); instruction.setLocation(currentLocation);
currentBlock.getInstructions().add(instruction); currentBlock.getInstructions().add(instruction);
} }

View File

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