diff --git a/teavm-classlib/src/main/java/org/teavm/classlib/java/lang/ThreadNativeGenerator.java b/teavm-classlib/src/main/java/org/teavm/classlib/java/lang/ThreadNativeGenerator.java index 56ca7bfa3..2560d7931 100644 --- a/teavm-classlib/src/main/java/org/teavm/classlib/java/lang/ThreadNativeGenerator.java +++ b/teavm-classlib/src/main/java/org/teavm/classlib/java/lang/ThreadNativeGenerator.java @@ -36,14 +36,14 @@ public class ThreadNativeGenerator implements Generator { } private void generateSleep(GeneratorContext context, SourceWriter writer) throws IOException { - writer.append("setTimer(function() {").indent().softNewLine(); + writer.append("setTimeout(function() {").indent().softNewLine(); writer.append(context.getCompleteContinuation()).append("();").softNewLine(); - writer.outdent().append(',').ws().append(context.getParameterName(1)).append(");").softNewLine(); + writer.outdent().append("},").ws().append(context.getParameterName(1)).append(");").softNewLine(); } private void generateYield(GeneratorContext context, SourceWriter writer) throws IOException { - writer.append("setTimer(function() {").indent().softNewLine(); + writer.append("setTimeout(function() {").indent().softNewLine(); writer.append(context.getCompleteContinuation()).append("();").softNewLine(); - writer.outdent().append(',').ws().append("0);").softNewLine(); + writer.outdent().append("},").ws().append("0);").softNewLine(); } } 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 af8aaf9a0..e11b7c07a 100644 --- a/teavm-core/src/main/java/org/teavm/javascript/Decompiler.java +++ b/teavm-core/src/main/java/org/teavm/javascript/Decompiler.java @@ -205,7 +205,7 @@ public class Decompiler { for (int i = 0; i < splitter.size(); ++i) { AsyncMethodPart part = new AsyncMethodPart(); part.setInputVariable(splitter.getInput(i)); - part.setStatement(getRegularMethodStatement(splitter.getProgram(i), i, splitter.getBlockSuccessors(i))); + part.setStatement(getRegularMethodStatement(splitter.getProgram(i), splitter.getBlockSuccessors(i))); node.getBody().add(part); } Program program = method.getProgram(); @@ -226,7 +226,7 @@ public class Decompiler { public RegularMethodNode decompileRegularCacheMiss(MethodHolder method) { RegularMethodNode methodNode = new RegularMethodNode(method.getReference()); Program program = method.getProgram(); - methodNode.setBody(getRegularMethodStatement(program, 0, new int[program.basicBlockCount()])); + methodNode.setBody(getRegularMethodStatement(program, new int[program.basicBlockCount()])); for (int i = 0; i < program.variableCount(); ++i) { methodNode.getVariables().add(program.variableAt(i).getRegister()); } @@ -241,7 +241,7 @@ public class Decompiler { return methodNode; } - private Statement getRegularMethodStatement(Program program, int currentPart, int[] targetBlocks) { + private Statement getRegularMethodStatement(Program program, int[] targetBlocks) { lastBlockId = 1; graph = ProgramUtils.buildControlFlowGraph(program); indexer = new GraphIndexer(graph); @@ -306,8 +306,8 @@ public class Decompiler { if (insn.getLocation() != null) { generator.setCurrentLocation(nodeLocation); } - if (targetBlocks[i] != currentPart && j == instructions.size() - 1) { - generator.asyncTarget = targetBlocks[i]; + if (targetBlocks[node] >= 0 && j == instructions.size() - 1) { + generator.asyncTarget = targetBlocks[node]; } insn.acceptVisitor(generator); } diff --git a/teavm-core/src/main/java/org/teavm/model/util/AsyncProgramSplitter.java b/teavm-core/src/main/java/org/teavm/model/util/AsyncProgramSplitter.java index da46951ac..41628de0a 100644 --- a/teavm-core/src/main/java/org/teavm/model/util/AsyncProgramSplitter.java +++ b/teavm-core/src/main/java/org/teavm/model/util/AsyncProgramSplitter.java @@ -39,6 +39,7 @@ public class AsyncProgramSplitter { Part initialPart = new Part(); initialPart.program = initialProgram; initialPart.blockSuccessors = new int[program.basicBlockCount()]; + Arrays.fill(initialPart.blockSuccessors, -1); parts.add(initialPart); partMap.put(0L, 0); Step initialStep = new Step(); @@ -47,79 +48,80 @@ public class AsyncProgramSplitter { Queue queue = new ArrayDeque<>(); queue.add(initialStep); - while (!queue.isEmpty()) { + taskLoop: while (!queue.isEmpty()) { Step step = queue.remove(); BasicBlock targetBlock = step.targetPart.program.basicBlockAt(step.source); if (targetBlock.instructionCount() > 0) { continue; } BasicBlock sourceBlock = program.basicBlockAt(step.source); - int end = step.sourceIndex; - boolean asyncOccured = false; - for (int i = step.sourceIndex; i < sourceBlock.getInstructions().size(); ++i) { - end = i; + int last = 0; + for (int i = 0; i < sourceBlock.getInstructions().size(); ++i) { Instruction insn = sourceBlock.getInstructions().get(i); if (insn instanceof InvokeInstruction) { InvokeInstruction invoke = (InvokeInstruction)insn; - if (asyncMethods.contains(invoke.getMethod())) { - asyncOccured = true; - long key = ((long)step.source << 32) | i; - if (partMap.containsKey(key)) { - step.targetPart.blockSuccessors[step.sourceIndex] = partMap.get(key); - break; - } - Program nextProgram = createStubCopy(program); - BasicBlock nextBlock = nextProgram.basicBlockAt(step.source); - if (step.source > 0) { - JumpInstruction jumpToNextBlock = new JumpInstruction(); - jumpToNextBlock.setTarget(nextBlock); - nextProgram.basicBlockAt(0).getInstructions().add(jumpToNextBlock); - } - Part part = new Part(); - part.input = invoke.getReceiver() != null ? invoke.getReceiver().getIndex() : null; - part.program = nextProgram; - int partId = parts.size(); - part.blockSuccessors = new int[program.basicBlockCount()]; - Arrays.fill(part.blockSuccessors, partId); - partMap.put(key, partId); - step.targetPart.blockSuccessors[step.source] = partId; - parts.add(part); - Step next = new Step(); - next.source = step.source; - next.sourceIndex = i + 1; - next.targetPart = part; - queue.add(next); - break; + if (!asyncMethods.contains(invoke.getMethod())) { + continue; } + + // If we met asynchronous invocation... + // Copy portion of current block from last occurence (or from start) to i'th instruction. + targetBlock.getInstructions().addAll(ProgramUtils.copyInstructions(sourceBlock, + last, i + 1, targetBlock.getProgram())); + ProgramUtils.copyTryCatches(sourceBlock, targetBlock.getProgram()); + last = i + 1; + + // If this instruction already separates program, end with current block and refer to the + // existing part + long key = ((long)step.source << 32) | i; + if (partMap.containsKey(key)) { + step.targetPart.blockSuccessors[targetBlock.getIndex()] = partMap.get(key); + continue taskLoop; + } + + // Create a new part + Program nextProgram = createStubCopy(program); + Part part = new Part(); + part.input = invoke.getReceiver() != null ? invoke.getReceiver().getIndex() : null; + part.program = nextProgram; + int partId = parts.size(); + parts.add(part); + part.blockSuccessors = new int[program.basicBlockCount() + 1]; + Arrays.fill(part.blockSuccessors, -1); + + // Mark current instruction as a separator and remember which part is in charge. + partMap.put(key, partId); + step.targetPart.blockSuccessors[targetBlock.getIndex()] = partId; + + // Continue with a new block in the new part + targetBlock = nextProgram.createBasicBlock(); + if (step.source > 0) { + JumpInstruction jumpToNextBlock = new JumpInstruction(); + jumpToNextBlock.setTarget(targetBlock); + nextProgram.basicBlockAt(0).getInstructions().add(jumpToNextBlock); + } + step.targetPart = part; } } - targetBlock.getInstructions().addAll(ProgramUtils.copyInstructions(sourceBlock, step.sourceIndex, end + 1, - targetBlock.getProgram())); - if (step.sourceIndex == 0) { - targetBlock.getPhis().addAll(ProgramUtils.copyPhis(sourceBlock, targetBlock.getProgram())); - } - ProgramUtils.copyTryCatches(sourceBlock, targetBlock.getProgram()); + targetBlock.getInstructions().addAll(ProgramUtils.copyInstructions(sourceBlock, + last, sourceBlock.getInstructions().size(), targetBlock.getProgram())); for (TryCatchBlock tryCatch : targetBlock.getTryCatchBlocks()) { if (tryCatch.getHandler() != null) { Step next = new Step(); next.source = tryCatch.getHandler().getIndex(); - next.sourceIndex = 0; next.targetPart = step.targetPart; queue.add(next); } } - if (!asyncOccured) { - InstructionTransitionExtractor successorExtractor = new InstructionTransitionExtractor(); - sourceBlock.getLastInstruction().acceptVisitor(successorExtractor); - for (BasicBlock successor : successorExtractor.getTargets()) { - BasicBlock targetSuccessor = targetBlock.getProgram().basicBlockAt(successor.getIndex()); - if (targetSuccessor.instructionCount() == 0) { - Step next = new Step(); - next.source = successor.getIndex(); - next.sourceIndex = 0; - next.targetPart = step.targetPart; - queue.add(next); - } + InstructionTransitionExtractor successorExtractor = new InstructionTransitionExtractor(); + sourceBlock.getLastInstruction().acceptVisitor(successorExtractor); + for (BasicBlock successor : successorExtractor.getTargets()) { + BasicBlock targetSuccessor = targetBlock.getProgram().basicBlockAt(successor.getIndex()); + if (targetSuccessor.instructionCount() == 0) { + Step next = new Step(); + next.source = successor.getIndex(); + next.targetPart = step.targetPart; + queue.add(next); } } } @@ -164,6 +166,5 @@ public class AsyncProgramSplitter { private static class Step { Part targetPart; int source; - int sourceIndex; } } diff --git a/teavm-core/src/main/resources/org/teavm/javascript/runtime.js b/teavm-core/src/main/resources/org/teavm/javascript/runtime.js index c95809d7c..e4ade6e48 100644 --- a/teavm-core/src/main/resources/org/teavm/javascript/runtime.js +++ b/teavm-core/src/main/resources/org/teavm/javascript/runtime.js @@ -397,7 +397,7 @@ function $rt_asyncAdapter(f) { var e; var args = Array.prototype.slice.apply(arguments); var $throw = args.pop(); - var $return args.pop(); + var $return = args.pop(); try { var result = f.apply(this, args); } catch (e) {