From 7ca6a4d64e24116963ec8730b747fcc92ac687d3 Mon Sep 17 00:00:00 2001 From: Alexey Andreev Date: Sun, 4 Dec 2016 18:28:30 +0300 Subject: [PATCH] Add IR parser of catch blocks --- .../main/java/org/teavm/model/ValueType.java | 2 +- .../org/teavm/model/text/ListingBuilder.java | 11 ++-- .../org/teavm/model/text/ListingParser.java | 55 ++++++++++++++++++- .../java/org/teavm/model/text/ParserTest.java | 5 ++ .../test/resources/model/text/exceptions.txt | 14 +++++ 5 files changed, 81 insertions(+), 6 deletions(-) create mode 100644 core/src/test/resources/model/text/exceptions.txt diff --git a/core/src/main/java/org/teavm/model/ValueType.java b/core/src/main/java/org/teavm/model/ValueType.java index 4ca238188..bf7fc948d 100644 --- a/core/src/main/java/org/teavm/model/ValueType.java +++ b/core/src/main/java/org/teavm/model/ValueType.java @@ -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: diff --git a/core/src/main/java/org/teavm/model/text/ListingBuilder.java b/core/src/main/java/org/teavm/model/text/ListingBuilder.java index ba97e595f..460941588 100644 --- a/core/src/main/java/org/teavm/model/text/ListingBuilder.java +++ b/core/src/main/java/org/teavm/model/text/ListingBuilder.java @@ -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"); } } } diff --git a/core/src/main/java/org/teavm/model/text/ListingParser.java b/core/src/main/java/org/teavm/model/text/ListingParser.java index 151d7828e..bc52f5bed 100644 --- a/core/src/main/java/org/teavm/model/text/ListingParser.java +++ b/core/src/main/java/org/teavm/model/text/ListingParser.java @@ -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 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); } diff --git a/core/src/test/java/org/teavm/model/text/ParserTest.java b/core/src/test/java/org/teavm/model/text/ParserTest.java index ecbb82f5b..e4258ffaf 100644 --- a/core/src/test/java/org/teavm/model/text/ParserTest.java +++ b/core/src/test/java/org/teavm/model/text/ParserTest.java @@ -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"; diff --git a/core/src/test/resources/model/text/exceptions.txt b/core/src/test/resources/model/text/exceptions.txt new file mode 100644 index 000000000..08112a485 --- /dev/null +++ b/core/src/test/resources/model/text/exceptions.txt @@ -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 \ No newline at end of file