diff --git a/teavm-classlib/src/test/java/org/teavm/classlib/java/lang/StringBuilderTest.java b/teavm-classlib/src/test/java/org/teavm/classlib/java/lang/StringBuilderTest.java index 9ccbac567..2aa07ca1c 100644 --- a/teavm-classlib/src/test/java/org/teavm/classlib/java/lang/StringBuilderTest.java +++ b/teavm-classlib/src/test/java/org/teavm/classlib/java/lang/StringBuilderTest.java @@ -365,4 +365,9 @@ public class StringBuilderTest { assertEquals(3, sb.lastIndexOf("345")); assertEquals(-1, sb.lastIndexOf("35")); } + + @Test + public void substringWithUpperBoundAtEndWorks() { + assertEquals("23", "123".substring(1, 3)); + } } diff --git a/teavm-classlib/src/test/java/org/teavm/classlib/java/lang/VMTest.java b/teavm-classlib/src/test/java/org/teavm/classlib/java/lang/VMTest.java index ef419e99f..a8963c000 100644 --- a/teavm-classlib/src/test/java/org/teavm/classlib/java/lang/VMTest.java +++ b/teavm-classlib/src/test/java/org/teavm/classlib/java/lang/VMTest.java @@ -67,4 +67,20 @@ public class VMTest { // do nothing } } + + @Test + public void setsVariableBeforeTryCatch() { + int a = 23; + try { + a = Integer.parseInt("not a number"); + } catch (NumberFormatException e) { + // do nothing + } + assertEquals(23, a); + } + + @Test + public void surrogateInStringLiteralsWork() { + assertEquals(0xDDC2, "a\uDDC2b".charAt(1)); + } } diff --git a/teavm-core/src/main/java/org/teavm/javascript/Decompiler.java b/teavm-core/src/main/java/org/teavm/javascript/Decompiler.java index 06c351f80..db467814f 100644 --- a/teavm-core/src/main/java/org/teavm/javascript/Decompiler.java +++ b/teavm-core/src/main/java/org/teavm/javascript/Decompiler.java @@ -245,7 +245,7 @@ public class Decompiler { if (node >= 0) { generator.currentBlock = program.basicBlockAt(node); int tmp = indexer.nodeAt(next); - generator.nextBlock = next < indexer.size() ? program.basicBlockAt(tmp) : null; + generator.nextBlock = tmp >= 0 && next < indexer.size() ? program.basicBlockAt(tmp) : null; generator.statements.clear(); InstructionLocation lastLocation = null; NodeLocation nodeLocation = null; diff --git a/teavm-core/src/main/java/org/teavm/javascript/Renderer.java b/teavm-core/src/main/java/org/teavm/javascript/Renderer.java index eebdb2261..9395963ba 100644 --- a/teavm-core/src/main/java/org/teavm/javascript/Renderer.java +++ b/teavm-core/src/main/java/org/teavm/javascript/Renderer.java @@ -1252,6 +1252,12 @@ public class Renderer implements ExprVisitor, StatementVisitor, RenderingContext if (c < ' ') { sb.append("\\u00").append(Character.forDigit(c / 16, 16)) .append(Character.forDigit(c % 16, 16)); + } else if (Character.isLowSurrogate(c) || Character.isHighSurrogate(c)) { + sb.append("\\u") + .append(Character.forDigit(c / 0x1000, 0x10)) + .append(Character.forDigit((c / 0x100) % 0x10, 0x10)) + .append(Character.forDigit((c / 0x10) % 0x10, 0x10)) + .append(Character.forDigit(c % 0x10, 0x10)); } else { sb.append(c); } diff --git a/teavm-core/src/main/java/org/teavm/model/util/ProgramUtils.java b/teavm-core/src/main/java/org/teavm/model/util/ProgramUtils.java index 6acc9c20c..e3ca78d8e 100644 --- a/teavm-core/src/main/java/org/teavm/model/util/ProgramUtils.java +++ b/teavm-core/src/main/java/org/teavm/model/util/ProgramUtils.java @@ -29,7 +29,7 @@ public final class ProgramUtils { private ProgramUtils() { } - public static Graph buildControlFlowGraphWithoutTryCatch(Program program) { + public static Graph buildControlFlowGraph(Program program) { GraphBuilder graphBuilder = new GraphBuilder(program.basicBlockCount()); InstructionTransitionExtractor transitionExtractor = new InstructionTransitionExtractor(); for (int i = 0; i < program.basicBlockCount(); ++i) { @@ -43,11 +43,14 @@ public final class ProgramUtils { } } } + for (TryCatchBlock tryCatch : block.getTryCatchBlocks()) { + graphBuilder.addEdge(i, tryCatch.getHandler().getIndex()); + } } return graphBuilder.build(); } - public static Graph buildControlFlowGraph(Program program) { + public static Graph buildControlFlowGraphWithTryCatch(Program program) { GraphBuilder graphBuilder = new GraphBuilder(program.basicBlockCount()); InstructionTransitionExtractor transitionExtractor = new InstructionTransitionExtractor(); for (int i = 0; i < program.basicBlockCount(); ++i) { @@ -58,6 +61,9 @@ public final class ProgramUtils { if (transitionExtractor.getTargets() != null) { for (BasicBlock successor : transitionExtractor.getTargets()) { graphBuilder.addEdge(i, successor.getIndex()); + for (TryCatchBlock succTryCatch : successor.getTryCatchBlocks()) { + graphBuilder.addEdge(i, succTryCatch.getHandler().getIndex()); + } } } } diff --git a/teavm-core/src/main/java/org/teavm/parsing/SSATransformer.java b/teavm-core/src/main/java/org/teavm/parsing/SSATransformer.java index c61f74869..1060d5beb 100644 --- a/teavm-core/src/main/java/org/teavm/parsing/SSATransformer.java +++ b/teavm-core/src/main/java/org/teavm/parsing/SSATransformer.java @@ -49,7 +49,7 @@ public class SSATransformer { this.variableDebugInfo = variableDebugInfo; this.arguments = arguments; variableDebugMap.clear(); - cfg = ProgramUtils.buildControlFlowGraphWithoutTryCatch(program); + cfg = ProgramUtils.buildControlFlowGraphWithTryCatch(program); domTree = GraphUtils.buildDominatorTree(cfg); domFrontiers = new int[cfg.size()][]; variableMap = new Variable[program.variableCount()];