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 2560d7931..3c2c8b5bd 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 @@ -37,13 +37,13 @@ public class ThreadNativeGenerator implements Generator { private void generateSleep(GeneratorContext context, SourceWriter writer) throws IOException { writer.append("setTimeout(function() {").indent().softNewLine(); - writer.append(context.getCompleteContinuation()).append("();").softNewLine(); + writer.append(context.getCompleteContinuation()).append("($rt_asyncResult(null));").softNewLine(); writer.outdent().append("},").ws().append(context.getParameterName(1)).append(");").softNewLine(); } private void generateYield(GeneratorContext context, SourceWriter writer) throws IOException { writer.append("setTimeout(function() {").indent().softNewLine(); - writer.append(context.getCompleteContinuation()).append("();").softNewLine(); + writer.append(context.getCompleteContinuation()).append("($rt_asyncResult(null));").softNewLine(); writer.outdent().append("},").ws().append("0);").softNewLine(); } } diff --git a/teavm-core/src/main/java/org/teavm/cache/AstIO.java b/teavm-core/src/main/java/org/teavm/cache/AstIO.java index b750fddb4..3fda51324 100644 --- a/teavm-core/src/main/java/org/teavm/cache/AstIO.java +++ b/teavm-core/src/main/java/org/teavm/cache/AstIO.java @@ -306,6 +306,16 @@ public class AstIO { } } + @Override + public void visit(RestoreAsyncStatement statement) { + try { + output.writeByte(17); + output.writeShort(statement.getReceiver() != null ? statement.getReceiver() : -1); + } catch (IOException e) { + throw new IOExceptionWrapper(e); + } + } + @Override public void visit(BinaryExpr expr) { try { @@ -651,6 +661,12 @@ public class AstIO { readSequence(input, stmt.getHandler()); return stmt; } + case 17: { + short var = input.readShort(); + RestoreAsyncStatement stmt = new RestoreAsyncStatement(); + stmt.setReceiver(var >= 0 ? (int)var : null); + return stmt; + } default: throw new RuntimeException("Unexpected statement type: " + type); } diff --git a/teavm-core/src/main/java/org/teavm/cache/DiskRegularMethodNodeCache.java b/teavm-core/src/main/java/org/teavm/cache/DiskRegularMethodNodeCache.java index 718ef40ca..33253cd80 100644 --- a/teavm-core/src/main/java/org/teavm/cache/DiskRegularMethodNodeCache.java +++ b/teavm-core/src/main/java/org/teavm/cache/DiskRegularMethodNodeCache.java @@ -257,6 +257,10 @@ public class DiskRegularMethodNodeCache implements RegularMethodNodeCache { @Override public void visit(StaticClassExpr expr) { } + + @Override + public void visit(RestoreAsyncStatement statement) { + } } static class Item { diff --git a/teavm-core/src/main/java/org/teavm/javascript/BreakToContinueReplacer.java b/teavm-core/src/main/java/org/teavm/javascript/BreakToContinueReplacer.java index 63bbfab24..de500d61f 100644 --- a/teavm-core/src/main/java/org/teavm/javascript/BreakToContinueReplacer.java +++ b/teavm-core/src/main/java/org/teavm/javascript/BreakToContinueReplacer.java @@ -112,4 +112,8 @@ class BreakToContinueReplacer implements StatementVisitor { visitSequence(statement.getProtectedBody()); visitSequence(statement.getHandler()); } + + @Override + public void visit(RestoreAsyncStatement statement) { + } } diff --git a/teavm-core/src/main/java/org/teavm/javascript/CertainBlockCountVisitor.java b/teavm-core/src/main/java/org/teavm/javascript/CertainBlockCountVisitor.java index 7274337c9..bd475a54a 100644 --- a/teavm-core/src/main/java/org/teavm/javascript/CertainBlockCountVisitor.java +++ b/teavm-core/src/main/java/org/teavm/javascript/CertainBlockCountVisitor.java @@ -107,4 +107,8 @@ class CertainBlockCountVisitor implements StatementVisitor { visit(statement.getProtectedBody()); visit(statement.getHandler()); } + + @Override + public void visit(RestoreAsyncStatement statement) { + } } 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 b700f9e53..affd53dd4 100644 --- a/teavm-core/src/main/java/org/teavm/javascript/Decompiler.java +++ b/teavm-core/src/main/java/org/teavm/javascript/Decompiler.java @@ -204,8 +204,15 @@ public class Decompiler { splitter.split(method.getProgram()); List partPrograms = new ArrayList<>(); for (int i = 0; i < splitter.size(); ++i) { - AsyncMethodPart part = getRegularMethodStatement(splitter.getProgram(i), splitter.getBlockSuccessors(i)); - part.setInputVariable(splitter.getInput(i)); + Integer input = null; + if (i > 0) { + input = splitter.getInput(i); + if (input == null) { + input = -1; + } + } + AsyncMethodPart part = getRegularMethodStatement(splitter.getProgram(i), splitter.getBlockSuccessors(i), + input); node.getBody().add(part); partPrograms.add(splitter.getProgram(i)); } @@ -229,7 +236,7 @@ public class Decompiler { Program program = method.getProgram(); int[] targetBlocks = new int[program.basicBlockCount()]; Arrays.fill(targetBlocks, -1); - methodNode.setBody(getRegularMethodStatement(program, targetBlocks).getStatement()); + methodNode.setBody(getRegularMethodStatement(program, targetBlocks, null).getStatement()); for (int i = 0; i < program.variableCount(); ++i) { methodNode.getVariables().add(program.variableAt(i).getRegister()); } @@ -244,7 +251,7 @@ public class Decompiler { return methodNode; } - private AsyncMethodPart getRegularMethodStatement(Program program, int[] targetBlocks) { + private AsyncMethodPart getRegularMethodStatement(Program program, int[] targetBlocks, Integer inputVar) { AsyncMethodPart result = new AsyncMethodPart(); lastBlockId = 1; graph = ProgramUtils.buildControlFlowGraph(program); @@ -297,11 +304,15 @@ public class Decompiler { int tmp = indexer.nodeAt(next); generator.nextBlock = tmp >= 0 && next < indexer.size() ? program.basicBlockAt(tmp) : null; generator.statements.clear(); + if (node == 0 && inputVar != null) { + RestoreAsyncStatement restoreStmt = new RestoreAsyncStatement(); + restoreStmt.setReceiver(inputVar >= 0 ? inputVar : null); + generator.statements.add(restoreStmt); + } generator.asyncTarget = null; InstructionLocation lastLocation = null; NodeLocation nodeLocation = null; List instructions = generator.currentBlock.getInstructions(); - boolean asyncInvocation = false; for (int j = 0; j < instructions.size(); ++j) { Instruction insn = generator.currentBlock.getInstructions().get(j); if (insn.getLocation() != null && lastLocation != insn.getLocation()) { @@ -313,41 +324,20 @@ public class Decompiler { } if (targetBlocks[node] >= 0 && j == instructions.size() - 1) { generator.asyncTarget = targetBlocks[node]; - asyncInvocation = true; } insn.acceptVisitor(generator); } - boolean hasAsyncCatch = false; for (TryCatchBlock tryCatch : generator.currentBlock.getTryCatchBlocks()) { - if (asyncInvocation) { - TryCatchStatement tryCatchStmt = new TryCatchStatement(); - tryCatchStmt.setExceptionType(tryCatch.getExceptionType()); - tryCatchStmt.setExceptionVariable(tryCatch.getExceptionVariable().getIndex()); - tryCatchStmt.getProtectedBody().addAll(generator.statements); - generator.statements.clear(); - generator.statements.add(tryCatchStmt); - Statement handlerStmt = generator.generateJumpStatement(tryCatch.getHandler()); - if (handlerStmt != null) { - tryCatchStmt.getHandler().add(handlerStmt); - } - } else { - AsyncMethodCatch asyncCatch = new AsyncMethodCatch(); - asyncCatch.setExceptionType(tryCatch.getExceptionType()); - asyncCatch.setExceptionVariable(tryCatch.getExceptionVariable().getIndex()); - Statement handlerStmt = generator.generateJumpStatement(tryCatch.getHandler()); - if (handlerStmt != null) { - asyncCatch.getHandler().add(handlerStmt); - } - result.getCatches().add(asyncCatch); - hasAsyncCatch = true; - } - } - if (hasAsyncCatch) { - TryCatchStatement guardTryCatch = new TryCatchStatement(); - guardTryCatch.setAsync(true); - guardTryCatch.getProtectedBody().addAll(generator.statements); + TryCatchStatement tryCatchStmt = new TryCatchStatement(); + tryCatchStmt.setExceptionType(tryCatch.getExceptionType()); + tryCatchStmt.setExceptionVariable(tryCatch.getExceptionVariable().getIndex()); + tryCatchStmt.getProtectedBody().addAll(generator.statements); generator.statements.clear(); - generator.statements.add(guardTryCatch); + generator.statements.add(tryCatchStmt); + Statement handlerStmt = generator.generateJumpStatement(tryCatch.getHandler()); + if (handlerStmt != null) { + tryCatchStmt.getHandler().add(handlerStmt); + } } block.body.addAll(generator.statements); } diff --git a/teavm-core/src/main/java/org/teavm/javascript/OptimizingVisitor.java b/teavm-core/src/main/java/org/teavm/javascript/OptimizingVisitor.java index 2d8dd3528..2d57ee859 100644 --- a/teavm-core/src/main/java/org/teavm/javascript/OptimizingVisitor.java +++ b/teavm-core/src/main/java/org/teavm/javascript/OptimizingVisitor.java @@ -577,4 +577,9 @@ class OptimizingVisitor implements StatementVisitor, ExprVisitor { statement.getHandler().addAll(statements); resultStmt = statement; } + + @Override + public void visit(RestoreAsyncStatement statement) { + resultStmt = statement; + } } diff --git a/teavm-core/src/main/java/org/teavm/javascript/RedundantLabelEliminator.java b/teavm-core/src/main/java/org/teavm/javascript/RedundantLabelEliminator.java index 92af7a2b8..30111b45d 100644 --- a/teavm-core/src/main/java/org/teavm/javascript/RedundantLabelEliminator.java +++ b/teavm-core/src/main/java/org/teavm/javascript/RedundantLabelEliminator.java @@ -117,4 +117,8 @@ class RedundantLabelEliminator implements StatementVisitor { visitSequence(statement.getProtectedBody()); visitSequence(statement.getHandler()); } + + @Override + public void visit(RestoreAsyncStatement statement) { + } } diff --git a/teavm-core/src/main/java/org/teavm/javascript/ReferenceCountingVisitor.java b/teavm-core/src/main/java/org/teavm/javascript/ReferenceCountingVisitor.java index f08dfcbb0..1e5f742af 100644 --- a/teavm-core/src/main/java/org/teavm/javascript/ReferenceCountingVisitor.java +++ b/teavm-core/src/main/java/org/teavm/javascript/ReferenceCountingVisitor.java @@ -111,4 +111,8 @@ class ReferenceCountingVisitor implements StatementVisitor { part.acceptVisitor(this); } } + + @Override + public void visit(RestoreAsyncStatement statement) { + } } 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 e2ae3b11b..545a26032 100644 --- a/teavm-core/src/main/java/org/teavm/javascript/Renderer.java +++ b/teavm-core/src/main/java/org/teavm/javascript/Renderer.java @@ -529,7 +529,7 @@ public class Renderer implements ExprVisitor, StatementVisitor, RenderingContext if (startParam < ref.parameterCount() + 1) { writer.append(',').ws(); } - writer.append("$return,").ws().append("$throw"); + writer.append("$return"); } writer.append(")").ws().append("{").softNewLine().indent(); method.acceptVisitor(new MethodBodyRenderer()); @@ -609,6 +609,16 @@ public class Renderer implements ExprVisitor, StatementVisitor, RenderingContext for (int i = ref.parameterCount() + 1; i < variableCount; ++i) { variableNames.add(variableName(i)); } + TryCatchFinder tryCatchFinder = new TryCatchFinder(); + for (AsyncMethodPart part : methodNode.getBody()) { + if (!tryCatchFinder.tryCatchFound) { + part.getStatement().acceptVisitor(tryCatchFinder); + } + } + boolean hasTryCatch = tryCatchFinder.tryCatchFound; + if (hasTryCatch) { + variableNames.add("$je"); + } if (!variableNames.isEmpty()) { writer.append("var "); for (int i = 0; i < variableNames.size(); ++i) { @@ -620,15 +630,18 @@ public class Renderer implements ExprVisitor, StatementVisitor, RenderingContext writer.append(";").softNewLine(); } for (int i = 0; i < methodNode.getBody().size(); ++i) { - writer.append("function $part_").append(i).append("($input)").ws().append('{') - .indent().softNewLine(); - AsyncMethodPart part = methodNode.getBody().get(i); - if (part.getInputVariable() != null) { - writer.append(variableName(part.getInputVariable())).ws().append('=').ws().append("$input;") - .softNewLine(); + writer.append("function $part_").append(i).append("("); + if (i > 0) { + writer.append("$restore"); } + writer.append(")").ws().append('{').indent().softNewLine(); + writer.append("try {").indent().softNewLine(); + AsyncMethodPart part = methodNode.getBody().get(i); part.getStatement().acceptVisitor(Renderer.this); - writer.outdent().append('}').softNewLine(); + writer.outdent().append("} catch ($guard) {").indent().softNewLine(); + writer.append("return $return($rt_asyncError($guard));").softNewLine(); + writer.outdent().append("}").softNewLine(); + writer.outdent().append("}").softNewLine(); } writer.append("return $part_0();").softNewLine(); } catch (IOException e) { @@ -666,11 +679,6 @@ public class Renderer implements ExprVisitor, StatementVisitor, RenderingContext return async; } - @Override - public String getErrorContinuation() { - return "$throw"; - } - @Override public String getCompleteContinuation() { return "$return"; @@ -912,7 +920,7 @@ public class Renderer implements ExprVisitor, StatementVisitor, RenderingContext } writer.append("return"); if (async) { - writer.append(" $return("); + writer.append(" $return($rt_asyncResult("); } if (statement.getResult() != null) { writer.append(' '); @@ -921,7 +929,7 @@ public class Renderer implements ExprVisitor, StatementVisitor, RenderingContext debugEmitter.emitCallSite(); } if (async) { - writer.append(')'); + writer.append("))"); } writer.append(";").softNewLine(); if (statement.getLocation() != null) { @@ -1754,6 +1762,18 @@ public class Renderer implements ExprVisitor, StatementVisitor, RenderingContext } } + @Override + public void visit(RestoreAsyncStatement statement) { + try { + if (statement.getReceiver() != null) { + writer.append(variableName(statement.getReceiver())).ws().append('=').ws(); + } + writer.append("$restore();").softNewLine(); + } catch (IOException e) { + throw new RenderingException("IO error occured", e); + } + } + private Injector getInjector(MethodReference ref) { InjectorHolder holder = injectorMap.get(ref); if (holder == null) { diff --git a/teavm-core/src/main/java/org/teavm/javascript/TryCatchFinder.java b/teavm-core/src/main/java/org/teavm/javascript/TryCatchFinder.java index 1c53f647f..7618fb355 100644 --- a/teavm-core/src/main/java/org/teavm/javascript/TryCatchFinder.java +++ b/teavm-core/src/main/java/org/teavm/javascript/TryCatchFinder.java @@ -110,4 +110,8 @@ class TryCatchFinder implements StatementVisitor { public void visit(TryCatchStatement statement) { tryCatchFound = true; } + + @Override + public void visit(RestoreAsyncStatement statement) { + } } diff --git a/teavm-core/src/main/java/org/teavm/javascript/UnusedVariableEliminator.java b/teavm-core/src/main/java/org/teavm/javascript/UnusedVariableEliminator.java index 9fecea076..719a1a842 100644 --- a/teavm-core/src/main/java/org/teavm/javascript/UnusedVariableEliminator.java +++ b/teavm-core/src/main/java/org/teavm/javascript/UnusedVariableEliminator.java @@ -224,4 +224,8 @@ class UnusedVariableEliminator implements ExprVisitor, StatementVisitor { } } } + + @Override + public void visit(RestoreAsyncStatement statement) { + } } diff --git a/teavm-core/src/main/java/org/teavm/javascript/ast/AsyncMethodPart.java b/teavm-core/src/main/java/org/teavm/javascript/ast/AsyncMethodPart.java index 85f216951..d55e653b8 100644 --- a/teavm-core/src/main/java/org/teavm/javascript/ast/AsyncMethodPart.java +++ b/teavm-core/src/main/java/org/teavm/javascript/ast/AsyncMethodPart.java @@ -15,17 +15,12 @@ */ package org.teavm.javascript.ast; -import java.util.ArrayList; -import java.util.List; - /** * * @author Alexey Andreev */ public class AsyncMethodPart { private Statement statement; - private Integer inputVariable; - private List catches = new ArrayList<>(); public Statement getStatement() { return statement; @@ -34,16 +29,4 @@ public class AsyncMethodPart { public void setStatement(Statement statement) { this.statement = statement; } - - public Integer getInputVariable() { - return inputVariable; - } - - public void setInputVariable(Integer inputVariable) { - this.inputVariable = inputVariable; - } - - public List getCatches() { - return catches; - } } diff --git a/teavm-core/src/main/java/org/teavm/javascript/ast/RenamingVisitor.java b/teavm-core/src/main/java/org/teavm/javascript/ast/RenamingVisitor.java index bb0e1afd4..cb3b363ec 100644 --- a/teavm-core/src/main/java/org/teavm/javascript/ast/RenamingVisitor.java +++ b/teavm-core/src/main/java/org/teavm/javascript/ast/RenamingVisitor.java @@ -191,4 +191,11 @@ public class RenamingVisitor implements StatementVisitor, ExprVisitor { } statement.setExceptionVariable(varNames[statement.getExceptionVariable()]); } + + @Override + public void visit(RestoreAsyncStatement statement) { + if (statement.getReceiver() != null) { + statement.setReceiver(varNames[statement.getReceiver()]); + } + } } diff --git a/teavm-core/src/main/java/org/teavm/javascript/ast/AsyncMethodCatch.java b/teavm-core/src/main/java/org/teavm/javascript/ast/RestoreAsyncStatement.java similarity index 51% rename from teavm-core/src/main/java/org/teavm/javascript/ast/AsyncMethodCatch.java rename to teavm-core/src/main/java/org/teavm/javascript/ast/RestoreAsyncStatement.java index 09d79fa25..4f903fd9b 100644 --- a/teavm-core/src/main/java/org/teavm/javascript/ast/AsyncMethodCatch.java +++ b/teavm-core/src/main/java/org/teavm/javascript/ast/RestoreAsyncStatement.java @@ -15,35 +15,23 @@ */ package org.teavm.javascript.ast; -import java.util.ArrayList; -import java.util.List; - /** * * @author Alexey Andreev */ -public class AsyncMethodCatch { - private List handler = new ArrayList<>(); - private String exceptionType; - private Integer exceptionVariable; +public class RestoreAsyncStatement extends Statement { + private Integer receiver; - public List getHandler() { - return handler; + public Integer getReceiver() { + return receiver; } - public String getExceptionType() { - return exceptionType; + public void setReceiver(Integer receiver) { + this.receiver = receiver; } - public void setExceptionType(String exceptionType) { - this.exceptionType = exceptionType; - } - - public Integer getExceptionVariable() { - return exceptionVariable; - } - - public void setExceptionVariable(Integer exceptionVariable) { - this.exceptionVariable = exceptionVariable; + @Override + public void acceptVisitor(StatementVisitor visitor) { + visitor.visit(this); } } diff --git a/teavm-core/src/main/java/org/teavm/javascript/ast/StatementVisitor.java b/teavm-core/src/main/java/org/teavm/javascript/ast/StatementVisitor.java index 62fcc8fbb..8d984747f 100644 --- a/teavm-core/src/main/java/org/teavm/javascript/ast/StatementVisitor.java +++ b/teavm-core/src/main/java/org/teavm/javascript/ast/StatementVisitor.java @@ -43,4 +43,6 @@ public interface StatementVisitor { void visit(InitClassStatement statement); void visit(TryCatchStatement statement); + + void visit(RestoreAsyncStatement statement); } diff --git a/teavm-core/src/main/java/org/teavm/javascript/ni/GeneratorContext.java b/teavm-core/src/main/java/org/teavm/javascript/ni/GeneratorContext.java index c28756a55..047d67c0c 100644 --- a/teavm-core/src/main/java/org/teavm/javascript/ni/GeneratorContext.java +++ b/teavm-core/src/main/java/org/teavm/javascript/ni/GeneratorContext.java @@ -34,7 +34,5 @@ public interface GeneratorContext extends ServiceRepository { boolean isAsync(); - String getErrorContinuation(); - String getCompleteContinuation(); } 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 602a58c15..9734e2c19 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 @@ -68,7 +68,8 @@ public class AsyncProgramSplitter { // 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()); + targetBlock.getTryCatchBlocks().addAll(ProgramUtils.copyTryCatches(sourceBlock, + targetBlock.getProgram())); for (TryCatchBlock tryCatch : targetBlock.getTryCatchBlocks()) { if (tryCatch.getHandler() != null) { Step next = new Step(); @@ -107,12 +108,15 @@ public class AsyncProgramSplitter { JumpInstruction jumpToNextBlock = new JumpInstruction(); jumpToNextBlock.setTarget(targetBlock); nextProgram.basicBlockAt(0).getInstructions().add(jumpToNextBlock); + nextProgram.basicBlockAt(0).getTryCatchBlocks().addAll(ProgramUtils.copyTryCatches(sourceBlock, + nextProgram)); } step.targetPart = part; } } targetBlock.getInstructions().addAll(ProgramUtils.copyInstructions(sourceBlock, last, sourceBlock.getInstructions().size(), targetBlock.getProgram())); + targetBlock.getTryCatchBlocks().addAll(ProgramUtils.copyTryCatches(sourceBlock, targetBlock.getProgram())); for (TryCatchBlock tryCatch : targetBlock.getTryCatchBlocks()) { if (tryCatch.getHandler() != null) { Step next = new Step(); diff --git a/teavm-core/src/main/java/org/teavm/parsing/ProgramParser.java b/teavm-core/src/main/java/org/teavm/parsing/ProgramParser.java index dd87b0c4b..f3ab0237b 100644 --- a/teavm-core/src/main/java/org/teavm/parsing/ProgramParser.java +++ b/teavm-core/src/main/java/org/teavm/parsing/ProgramParser.java @@ -21,6 +21,7 @@ import org.objectweb.asm.tree.*; import org.teavm.model.*; import org.teavm.model.instructions.*; import org.teavm.model.util.InstructionTransitionExtractor; +import org.teavm.model.util.ProgramUtils; /** * @@ -112,6 +113,8 @@ public class ProgramParser implements VariableDebugInformation { while (program.variableCount() <= signatureVars) { program.createVariable(); } + program.basicBlockAt(0).getTryCatchBlocks().addAll(ProgramUtils.copyTryCatches( + program.basicBlockAt(1), program)); return program; } 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 e71694365..0fd948135 100644 --- a/teavm-core/src/main/resources/org/teavm/javascript/runtime.js +++ b/teavm-core/src/main/resources/org/teavm/javascript/runtime.js @@ -392,25 +392,41 @@ function $rt_virtualMethods(cls) { } } } +function $rt_asyncResult(value) { + return function() { + return value; + } +} +function $rt_asyncError(e) { + return function() { + throw e; + } +} function $rt_asyncAdapter(f) { return function() { var e; + var result; var args = Array.prototype.slice.apply(arguments); - var $throw = args.pop(); var $return = args.pop(); try { - var result = f.apply(this, args); + result = f.apply(this, args); } catch (e) { - return $throw(e); + return $rt_asyncError(e); } - return $return(result); + return $rt_asyncResult(result); } } -function $rt_rootInvocationAdapter(f) { +function $rt_rootInvocationAdapter(f, extraArgs) { return function() { var args = Array.prototype.slice.apply(arguments); - args.push(function() {}); - args.push(function() {}); + if (extraArgs) { + for (var i = 0; i < extraArts.length; ++i) { + args.push(extraArgs[i]); + } + } + args.push(function(result) { + result(); + }); return f.apply(this, args); } } diff --git a/teavm-core/src/main/resources/org/teavm/tooling/test/res/runtime.js b/teavm-core/src/main/resources/org/teavm/tooling/test/res/runtime.js deleted file mode 100644 index 4ab5dea35..000000000 --- a/teavm-core/src/main/resources/org/teavm/tooling/test/res/runtime.js +++ /dev/null @@ -1,732 +0,0 @@ -/* - * Copyright 2013 Alexey Andreev. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -$rt_lastObjectId = 0; -$rt_nextId = function() { - return $rt_lastObjectId++; -} -$rt_compare = function(a, b) { - return a > b ? 1 : a < b ? -1 : 0; -} -$rt_isInstance = function(obj, cls) { - return obj != null && obj.constructor.$meta && $rt_isAssignable(obj.constructor, cls); -} -$rt_isAssignable = function(from, to) { - if (from === to) { - return true; - } - var supertypes = from.$meta.supertypes; - for (var i = 0; i < supertypes.length; i = (i + 1) | 0) { - if ($rt_isAssignable(supertypes[i], to)) { - return true; - } - } - return false; -} -$rt_createArray = function(cls, sz) { - var data = new Array(sz); - var arr = new ($rt_arraycls(cls))(data); - for (var i = 0; i < sz; i = (i + 1) | 0) { - data[i] = null; - } - return arr; -} -$rt_wrapArray = function(cls, data) { - var arr = new ($rt_arraycls(cls))(data); - return arr; -} -$rt_createUnfilledArray = function(cls, sz) { - return new ($rt_arraycls(cls))(new Array(sz)); -} -$rt_createLongArray = function(sz) { - var data = new Array(sz); - var arr = new ($rt_arraycls($rt_longcls()))(data); - for (var i = 0; i < sz; i = (i + 1) | 0) { - data[i] = Long.ZERO; - } - return arr; -} -if (ArrayBuffer) { - $rt_createNumericArray = function(cls, nativeArray) { - return new ($rt_arraycls(cls))(nativeArray); - } - $rt_createByteArray = function(sz) { - return $rt_createNumericArray($rt_bytecls(), new Int8Array(new ArrayBuffer(sz)), 0); - }; - $rt_createShortArray = function(sz) { - return $rt_createNumericArray($rt_shortcls(), new Int16Array(new ArrayBuffer(sz << 1)), 0); - }; - $rt_createIntArray = function(sz) { - return $rt_createNumericArray($rt_intcls(), new Int32Array(new ArrayBuffer(sz << 2)), 0); - }; - $rt_createBooleanArray = function(sz) { - return $rt_createNumericArray($rt_booleancls(), new Int8Array(new ArrayBuffer(sz)), 0); - }; - $rt_createFloatArray = function(sz) { - return $rt_createNumericArray($rt_floatcls(), new Float32Array(new ArrayBuffer(sz << 2)), 0); - }; - $rt_createDoubleArray = function(sz) { - return $rt_createNumericArray($rt_doublecls(), new Float64Array(new ArrayBuffer(sz << 3)), 0); - }; - $rt_createCharArray = function(sz) { - return $rt_createNumericArray($rt_charcls(), new Uint16Array(new ArrayBuffer(sz << 1)), 0); - }; -} else { - $rt_createNumericArray = function(cls, sz) { - var data = new Array(sz); - var arr = new ($rt_arraycls(cls))(data); - for (var i = 0; i < sz; i = (i + 1) | 0) { - data[i] = 0; - } - return arr; - } - $rt_createByteArray = function(sz) { return $rt_createNumericArray($rt_bytecls(), sz); } - $rt_createShortArray = function(sz) { return $rt_createNumericArray($rt_shortcls(), sz); } - $rt_createIntArray = function(sz) { return $rt_createNumericArray($rt_intcls(), sz); } - $rt_createBooleanArray = function(sz) { return $rt_createNumericArray($rt_booleancls(), sz); } - $rt_createFloatArray = function(sz) { return $rt_createNumericArray($rt_floatcls(), sz); } - $rt_createDoubleArray = function(sz) { return $rt_createNumericArray($rt_doublecls(), sz); } - $rt_createCharArray = function(sz) { return $rt_createNumericArray($rt_charcls(), sz); } -} -$rt_arraycls = function(cls) { - if (cls.$array == undefined) { - var arraycls = function(data) { - this.data = data; - this.$id = $rt_nextId(); - }; - arraycls.prototype = new ($rt_objcls())(); - arraycls.prototype.constructor = arraycls; - arraycls.$meta = { item : cls, supertypes : [$rt_objcls()], primitive : false, superclass : $rt_objcls() }; - cls.$array = arraycls; - } - return cls.$array; -} -$rt_createcls = function() { - return { - $meta : { - supertypes : [] - } - }; -} -$rt_booleanclsCache = null; -$rt_booleancls = function() { - if ($rt_booleanclsCache == null) { - $rt_booleanclsCache = $rt_createcls(); - $rt_booleanclsCache.primitive = true; - $rt_booleanclsCache.name = "boolean"; - } - return $rt_booleanclsCache; -} -$rt_charclsCache = null; -$rt_charcls = function() { - if ($rt_charclsCache == null) { - $rt_charclsCache = $rt_createcls(); - $rt_charclsCache.primitive = true; - $rt_charclsCache.name = "char"; - } - return $rt_charclsCache; -} -$rt_byteclsCache = null; -$rt_bytecls = function() { - if ($rt_byteclsCache == null) { - $rt_byteclsCache = $rt_createcls(); - $rt_byteclsCache.primitive = true; - $rt_byteclsCache.name = "byte"; - } - return $rt_byteclsCache; -} -$rt_shortclsCache = null; -$rt_shortcls = function() { - if ($rt_shortclsCache == null) { - $rt_shortclsCache = $rt_createcls(); - $rt_shortclsCache.primitive = true; - $rt_shortclsCache.name = "short"; - } - return $rt_shortclsCache; -} -$rt_intclsCache = null; -$rt_intcls = function() { - if ($rt_intclsCache === null) { - $rt_intclsCache = $rt_createcls(); - $rt_intclsCache.primitive = true; - $rt_intclsCache.name = "int"; - } - return $rt_intclsCache; -} -$rt_longclsCache = null; -$rt_longcls = function() { - if ($rt_longclsCache === null) { - $rt_longclsCache = $rt_createcls(); - $rt_longclsCache.primitive = true; - $rt_longclsCache.name = "long"; - } - return $rt_longclsCache; -} -$rt_floatclsCache = null; -$rt_floatcls = function() { - if ($rt_floatclsCache === null) { - $rt_floatclsCache = $rt_createcls(); - $rt_floatclsCache.primitive = true; - $rt_floatclsCache.name = "float"; - } - return $rt_floatclsCache; -} -$rt_doubleclsCache = null; -$rt_doublecls = function() { - if ($rt_doubleclsCache === null) { - $rt_doubleclsCache = $rt_createcls(); - $rt_doubleclsCache.primitive = true; - $rt_doubleclsCache.name = "double"; - } - return $rt_doubleclsCache; -} -$rt_voidclsCache = null; -$rt_voidcls = function() { - if ($rt_voidclsCache === null) { - $rt_voidclsCache = $rt_createcls(); - $rt_voidclsCache.primitive = true; - $rt_voidclsCache.name = "void"; - } - return $rt_voidclsCache; -} -$rt_equals = function(a, b) { - if (a === b) { - return true; - } - if (a === null || b === null) { - return false; - } - if (typeof(a) == 'object') { - return a.equals(b); - } else { - return false; - } -} -$rt_clinit = function(cls) { - if (cls.$clinit) { - var f = cls.$clinit; - delete cls.$clinit; - f(); - } - return cls; -} -$rt_init = function(cls, constructor, args) { - var obj = new cls(); - cls.prototype[constructor].apply(obj, args); - return obj; -} -$rt_throw = function(ex) { - var err = ex.$jsException; - if (!err) { - var err = new Error("Java exception thrown"); - err.$javaException = ex; - ex.$jsException = err; - } - throw err; -} -$rt_byteToInt = function(value) { - return value > 0xFF ? value | 0xFFFFFF00 : value; -} -$rt_shortToInt = function(value) { - return value > 0xFFFF ? value | 0xFFFF0000 : value; -} -$rt_createMultiArray = function(cls, dimensions) { - var arrays = new Array($rt_primitiveArrayCount(dimensions)); - var firstDim = dimensions[0] | 0; - for (var i = 0 | 0; i < arrays.length; i = (i + 1) | 0) { - arrays[i] = $rt_createArray(cls, firstDim); - } - return $rt_createMultiArrayImpl(cls, arrays, dimensions); -} -$rt_createByteMultiArray = function(dimensions) { - var arrays = new Array($rt_primitiveArrayCount(dimensions)); - var firstDim = dimensions[0] | 0; - for (var i = 0 | 0; i < arrays.length; i = (i + 1) | 0) { - arrays[i] = $rt_createByteArray(firstDim); - } - return $rt_createMultiArrayImpl($rt_bytecls(), arrays, dimensions); -} -$rt_createBooleanMultiArray = function(dimensions) { - var arrays = new Array($rt_primitiveArrayCount(dimensions)); - var firstDim = dimensions[0] | 0; - for (var i = 0 | 0; i < arrays.length; i = (i + 1) | 0) { - arrays[i] = $rt_createBooleanArray(firstDim); - } - return $rt_createMultiArrayImpl($rt_booleancls(), arrays, dimensions); -} -$rt_createShortMultiArray = function(dimensions) { - var arrays = new Array($rt_primitiveArrayCount(dimensions)); - var firstDim = dimensions[0] | 0; - for (var i = 0 | 0; i < arrays.length; i = (i + 1) | 0) { - arrays[i] = $rt_createShortArray(firstDim); - } - return $rt_createMultiArrayImpl($rt_shortcls(), arrays, dimensions); -} -$rt_createIntMultiArray = function(dimensions) { - var arrays = new Array($rt_primitiveArrayCount(dimensions)); - var firstDim = dimensions[0] | 0; - for (var i = 0 | 0; i < arrays.length; i = (i + 1) | 0) { - arrays[i] = $rt_createIntArray(firstDim); - } - return $rt_createMultiArrayImpl($rt_intcls(), arrays, dimensions); -} -$rt_createLongMultiArray = function(dimensions) { - var arrays = new Array($rt_primitiveArrayCount(dimensions)); - var firstDim = dimensions[0] | 0; - for (var i = 0 | 0; i < arrays.length; i = (i + 1) | 0) { - arrays[i] = $rt_createLongArray(firstDim); - } - return $rt_createMultiArrayImpl($rt_longcls(), arrays, dimensions); -} -$rt_createFloatMultiArray = function(dimensions) { - var arrays = new Array($rt_primitiveArrayCount(dimensions)); - var firstDim = dimensions[0] | 0; - for (var i = 0 | 0; i < arrays.length; i = (i + 1) | 0) { - arrays[i] = $rt_createFloatArray(firstDim); - } - return $rt_createMultiArrayImpl($rt_floatcls(), arrays, dimensions); -} -$rt_createDoubleMultiArray = function(dimensions) { - var arrays = new Array($rt_primitiveArrayCount(dimensions)); - var firstDim = dimensions[0] | 0; - for (var i = 0 | 0; i < arrays.length; i = (i + 1) | 0) { - arrays[i] = $rt_createDoubleArray(firstDim); - } - return $rt_createMultiArrayImpl($rt_doublecls(), arrays, dimensions); -} -$rt_primitiveArrayCount = function(dimensions) { - var val = dimensions[1] | 0; - for (var i = 2 | 0; i < dimensions.length; i = (i + 1) | 0) { - val = (val * (dimensions[i] | 0)) | 0; - } - return val; -} -$rt_createMultiArrayImpl = function(cls, arrays, dimensions) { - var limit = arrays.length; - for (var i = 1 | 0; i < dimensions.length; i = (i + 1) | 0) { - cls = $rt_arraycls(cls); - var dim = dimensions[i]; - var index = 0; - var packedIndex = 0; - while (index < limit) { - var arr = $rt_createUnfilledArray(cls, dim); - for (var j = 0; j < dim; j = (j + 1) | 0) { - arr.data[j] = arrays[index]; - index = (index + 1) | 0; - } - arrays[packedIndex] = arr; - packedIndex = (packedIndex + 1) | 0; - } - limit = packedIndex; - } - return arrays[0]; -} -$rt_assertNotNaN = function(value) { - if (typeof value == 'number' && isNaN(value)) { - throw "NaN"; - } - return value; -} -$rt_methodStubs = function(clinit, names) { - for (var i = 0; i < names.length; i = (i + 1) | 0) { - window[names[i]] = (function(name) { - return function() { - clinit(); - return window[name].apply(window, arguments); - } - })(names[i]); - } -} -$rt_stdoutBuffer = ""; -$rt_putStdout = function(ch) { - if (ch === 0xA) { - if (console) { - console.info($rt_stdoutBuffer); - } - $rt_stdoutBuffer = ""; - } else { - $rt_stdoutBuffer += String.fromCharCode(ch); - } -} -$rt_stderrBuffer = ""; -$rt_putStderr = function(ch) { - if (ch === 0xA) { - if (console) { - console.info($rt_stderrBuffer); - } - $rt_stderrBuffer = ""; - } else { - $rt_stderrBuffer += String.fromCharCode(ch); - } -} -function $rt_declClass(cls, data) { - cls.name = data.name; - cls.$meta = {}; - cls.$meta.superclass = data.superclass; - cls.$meta.supertypes = data.interfaces ? data.interfaces.slice() : []; - if (data.superclass) { - cls.$meta.supertypes.push(data.superclass); - cls.prototype = new data.superclass(); - } else { - cls.prototype = new Object(); - } - cls.$meta.name = data.name; - cls.$meta.enum = data.enum; - cls.prototype.constructor = cls; - cls.$clinit = data.clinit; -} -function $rt_virtualMethods(cls) { - for (var i = 1; i < arguments.length; i += 2) { - var name = arguments[i]; - var func = arguments[i + 1]; - if (typeof name == 'string') { - cls.prototype[name] = func; - } else { - for (var j = 0; j < name.length; ++j) { - cls.prototype[name[j]] = func; - } - } - } -} - -Long = function(lo, hi) { - this.lo = lo | 0; - this.hi = hi | 0; -} -Long_ZERO = new Long(0, 0); -Long_fromInt = function(val) { - return val >= 0 ? new Long(val, 0) : new Long(val, -1); -} -Long_fromNumber = function(val) { - return new Long(val | 0, (val / 0x100000000) | 0); -} -Long_toNumber = function(val) { - return val.hi >= 0 ? val.lo + 0x100000000 * val.hi : -0x100000000 * (val.hi ^ 0xFFFFFFFF) + val.lo; -} -Long_add = function(a, b) { - var a_lolo = a.lo & 0xFFFF; - var a_lohi = a.lo >>> 16; - var a_hilo = a.hi & 0xFFFF; - var a_hihi = a.hi >>> 16; - var b_lolo = b.lo & 0xFFFF; - var b_lohi = b.lo >>> 16; - var b_hilo = b.hi & 0xFFFF; - var b_hihi = b.hi >>> 16; - - var lolo = (a_lolo + b_lolo) | 0; - var lohi = (a_lohi + b_lohi + (lolo >> 16)) | 0; - var hilo = (a_hilo + b_hilo + (lohi >> 16)) | 0; - var hihi = (a_hihi + b_hihi + (hilo >> 16)) | 0; - return new Long((lolo & 0xFFFF) | ((lohi & 0xFFFF) << 16), - (hilo & 0xFFFF) | ((hihi & 0xFFFF) << 16)); -} -Long_inc = function(a) { - var lo = (a.lo + 1) | 0; - var hi = a.hi; - if (lo === 0) { - hi = (hi + 1) | 0; - } - return new Long(lo, hi); -} -Long_dec = function(a) { - var lo = (a.lo - 1) | 0; - var hi = a.hi; - if (lo === -1) { - hi = (hi - 1) | 0; - } - return new Long(lo, hi); -} -Long_neg = function(a) { - return Long_inc(new Long(a.lo ^ 0xFFFFFFFF, a.hi ^ 0xFFFFFFFF)); -} -Long_sub = function(a, b) { - var a_lolo = a.lo & 0xFFFF; - var a_lohi = a.lo >>> 16; - var a_hilo = a.hi & 0xFFFF; - var a_hihi = a.hi >>> 16; - var b_lolo = b.lo & 0xFFFF; - var b_lohi = b.lo >>> 16; - var b_hilo = b.hi & 0xFFFF; - var b_hihi = b.hi >>> 16; - - var lolo = (a_lolo - b_lolo) | 0; - var lohi = (a_lohi - b_lohi + (lolo >> 16)) | 0; - var hilo = (a_hilo - b_hilo + (lohi >> 16)) | 0; - var hihi = (a_hihi - b_hihi + (hilo >> 16)) | 0; - return new Long((lolo & 0xFFFF) | ((lohi & 0xFFFF) << 16), - (hilo & 0xFFFF) | ((hihi & 0xFFFF) << 16)); -} -Long_compare = function(a, b) { - var r = a.hi - b.hi; - if (r !== 0) { - return r; - } - var r = (a.lo >>> 1) - (b.lo >>> 1); - if (r !== 0) { - return r; - } - return (a.lo & 1) - (b.lo & 1); -} -Long_isPositive = function(a) { - return (a.hi & 0x80000000) === 0; -} -Long_isNegative = function(a) { - return (a.hi & 0x80000000) !== 0; -} -Long_mul = function(a, b) { - var positive = Long_isNegative(a) === Long_isNegative(b); - if (Long_isNegative(a)) { - a = Long_neg(a); - } - if (Long_isNegative(b)) { - b = Long_neg(b); - } - var a_lolo = a.lo & 0xFFFF; - var a_lohi = a.lo >>> 16; - var a_hilo = a.hi & 0xFFFF; - var a_hihi = a.hi >>> 16; - var b_lolo = b.lo & 0xFFFF; - var b_lohi = b.lo >>> 16; - var b_hilo = b.hi & 0xFFFF; - var b_hihi = b.hi >>> 16; - - var lolo = (a_lolo * b_lolo) | 0; - var lohi = (a_lohi * b_lolo + a_lolo * b_lohi + (lolo >> 16)) | 0; - var hilo = (a_hilo * b_lolo + a_lohi * b_lohi + a_lolo * b_hilo + (lohi >> 16)) | 0; - var hihi = (a_hihi * b_lolo + a_hilo * b_lohi + a_lohi * b_hilo + a_lolo * b_hihi + (hilo >> 16)) | 0; - var result = new Long((lolo & 0xFFFF) | ((lohi & 0xFFFF) << 16), (hilo & 0xFFFF) | ((hihi & 0xFFFF) << 16)); - return positive ? result : Long_neg(result); -} -Long_div = function(a, b) { - return Long_divRem(a, b)[0]; -} -Long_rem = function(a, b) { - return Long_divRem(a, b)[1]; -} -Long_divRem = function(a, b) { - var positive = Long_isNegative(a) === Long_isNegative(b); - if (Long_isNegative(a)) { - a = Long_neg(a); - } - if (Long_isNegative(b)) { - b = Long_neg(b); - } - a = new LongInt(a.lo, a.hi, 0); - b = new LongInt(b.lo, b.hi, 0); - var q = LongInt_div(a, b); - a = new Long(a.lo, a.hi); - q = new Long(q.lo, q.hi); - return positive ? [q, a] : [Long_neg(q), Long_neg(a)]; -} -Long_shiftLeft16 = function(a) { - return new Long(a.lo << 16, (a.lo >>> 16) | (a.hi << 16)); -} -Long_shiftRight16 = function(a) { - return new Long((a.lo >>> 16) | (a.hi << 16), a.hi >>> 16); -} -Long_and = function(a, b) { - return new Long(a.lo & b.lo, a.hi & b.hi); -} -Long_or = function(a, b) { - return new Long(a.lo | b.lo, a.hi | b.hi); -} -Long_xor = function(a, b) { - return new Long(a.lo ^ b.lo, a.hi ^ b.hi); -} -Long_shl = function(a, b) { - if (b < 32) { - return new Long(a.lo << b, (a.lo >>> (32 - b)) | (a.hi << b)); - } else { - return new Long(0, a.lo << (b - 32)); - } -} -Long_shr = function(a, b) { - if (b < 32) { - return new Long((a.lo >>> b) | (a.hi << (32 - b)), a.hi >> b); - } else { - return new Long((a.hi >> (b - 32)), -1); - } -} -Long_shru = function(a, b) { - if (b < 32) { - return new Long((a.lo >>> b) | (a.hi << (32 - b)), a.hi >>> b); - } else { - return new Long((a.hi >>> (b - 32)), 0); - } -} - -// Represents a mutable 80-bit unsigned integer -LongInt = function(lo, hi, sup) { - this.lo = lo; - this.hi = hi; - this.sup = sup; -} -LongInt_mul = function(a, b) { - var a_lolo = ((a.lo & 0xFFFF) * b) | 0; - var a_lohi = ((a.lo >>> 16) * b) | 0; - var a_hilo = ((a.hi & 0xFFFF) * b) | 0; - var a_hihi = ((a.hi >>> 16) * b) | 0; - var sup = (a.sup * b) | 0; - - a_lohi = (a_lohi + (a_lolo >> 16)) | 0; - a_hilo = (a_hilo + (a_lohi >> 16)) | 0; - a_hihi = (a_hihi + (a_hilo >> 16)) | 0; - sup = (sup + (a_hihi >> 16)) | 0; - a.lo = (a_lolo & 0xFFFF) | (a_lohi << 16); - a.hi = (a_hilo & 0xFFFF) | (a_hihi << 16); - a.sup = sup & 0xFFFF; -} -LongInt_sub = function(a, b) { - var a_lolo = a.lo & 0xFFFF; - var a_lohi = a.lo >>> 16; - var a_hilo = a.hi & 0xFFFF; - var a_hihi = a.hi >>> 16; - var b_lolo = b.lo & 0xFFFF; - var b_lohi = b.lo >>> 16; - var b_hilo = b.hi & 0xFFFF; - var b_hihi = b.hi >>> 16; - - a_lolo = (a_lolo - b_lolo) | 0; - a_lohi = (a_lohi - b_lohi + (a_lolo >> 16)) | 0; - a_hilo = (a_hilo - b_hilo + (a_lohi >> 16)) | 0; - a_hihi = (a_hihi - b_hihi + (a_hilo >> 16)) | 0; - sup = (a.sup - b.sup + (a_hihi >> 16)) | 0; - a.lo = (a_lolo & 0xFFFF) | ((a_lohi & 0xFFFF) << 16); - a.hi = (a_hilo & 0xFFFF) | ((a_hihi & 0xFFFF) << 16); - a.sup = sup; -} -LongInt_add = function(a, b) { - var a_lolo = a.lo & 0xFFFF; - var a_lohi = a.lo >>> 16; - var a_hilo = a.hi & 0xFFFF; - var a_hihi = a.hi >>> 16; - var b_lolo = b.lo & 0xFFFF; - var b_lohi = b.lo >>> 16; - var b_hilo = b.hi & 0xFFFF; - var b_hihi = b.hi >>> 16; - - a_lolo = (a_lolo + b_lolo) | 0; - a_lohi = (a_lohi + b_lohi + (a_lolo >> 16)) | 0; - a_hilo = (a_hilo + b_hilo + (a_lohi >> 16)) | 0; - a_hihi = (a_hihi + b_hihi + (a_hilo >> 16)) | 0; - sup = (a.sup + b.sup + (a_hihi >> 16)) | 0; - a.lo = (a_lolo & 0xFFFF) | (a_lohi << 16); - a.hi = (a_hilo & 0xFFFF) | (a_hihi << 16); - a.sup = sup; -} -LongInt_ucompare = function(a, b) { - var r = (a.sup - b.sup); - if (r != 0) { - return r; - } - var r = (a.hi >>> 1) - (b.hi >>> 1); - if (r != 0) { - return r; - } - var r = (a.hi & 1) - (b.hi & 1); - if (r != 0) { - return r; - } - var r = (a.lo >>> 1) - (b.lo >>> 1); - if (r != 0) { - return r; - } - return (a.lo & 1) - (b.lo & 1); -} -LongInt_numOfLeadingZeroBits = function(a) { - var n = 0; - var d = 16; - while (d > 0) { - if ((a >>> d) !== 0) { - a >>>= d; - n = (n + d) | 0; - } - d = (d / 2) | 0; - } - return 31 - n; -} -LongInt_shl = function(a, b) { - if (b < 32) { - a.sup = ((a.hi >>> (32 - b)) | (a.sup << b)) & 0xFFFF; - a.hi = (a.lo >>> (32 - b)) | (a.hi << b); - a.lo <<= b; - } else if (b < 64) { - a.sup = ((a.lo >>> (64 - b)) | (a.hi << (b - 32))) & 0xFFFF; - a.hi = a.lo << b; - a.lo = 0; - } else { - a.sup = (a.lo << (b - 64)) & 0xFFFF; - a.hi = 0; - a.lo = 0; - } -} -LongInt_shr = function(a, b) { - if (b < 32) { - a.lo = (a.lo >>> b) | (a.hi << (32 - b)); - a.hi = (a.hi >>> b) | (a.sup << (32 - b)); - a.sup >>>= b; - } else if (b < 64) { - a.lo = (a.hi >>> (b - 32)) | (a.sup << (64 - b)); - a.hi = a.sup >>> (b - 32); - a.sup = 0; - } else { - a.lo = a.sup >>> (b - 64); - a.hi = 0; - a.sup = 0; - } -} -LongInt_copy = function(a) { - return new LongInt(a.lo, a.hi, a.sup); -} -LongInt_div = function(a, b) { - // Normalize divisor - var bits = b.hi !== 0 ? LongInt_numOfLeadingZeroBits(b.hi) : LongInt_numOfLeadingZeroBits(b.lo) + 32; - var sz = 1 + ((bits / 16) | 0); - var dividentBits = bits % 16; - LongInt_shl(b, bits); - LongInt_shl(a, dividentBits); - q = new LongInt(0, 0, 0); - while (sz-- > 0) { - LongInt_shl(q, 16); - // Calculate approximate q - var digitA = (a.hi >>> 16) + (0x10000 * a.sup); - var digitB = b.hi >>> 16; - var digit = (digitA / digitB) | 0; - var t = LongInt_copy(b); - LongInt_mul(t, digit); - // Adjust q either down or up - if (LongInt_ucompare(t, a) >= 0) { - while (LongInt_ucompare(t, a) > 0) { - LongInt_sub(t, b); - q = (q - 1) | 0; - } - } else { - while (true) { - var nextT = LongInt_copy(t); - LongInt_add(nextT, b); - if (LongInt_ucompare(nextT, a) > 0) { - break; - } - t = nextT; - q = (q + 1) | 0; - } - } - LongInt_sub(a, t); - q.lo |= digit; - LongInt_shl(a, 16); - } - LongInt_shr(a, bits + 16); - return q; -} \ No newline at end of file diff --git a/teavm-samples/teavm-samples-async/src/main/java/org/teavm/samples/async/AsyncProgram.java b/teavm-samples/teavm-samples-async/src/main/java/org/teavm/samples/async/AsyncProgram.java index fca37cc4a..dc1fa0fc3 100644 --- a/teavm-samples/teavm-samples-async/src/main/java/org/teavm/samples/async/AsyncProgram.java +++ b/teavm-samples/teavm-samples-async/src/main/java/org/teavm/samples/async/AsyncProgram.java @@ -55,5 +55,18 @@ public final class AsyncProgram { } } System.out.println("Complete async"); + + System.out.println("Throwing exception"); + try { + throwException(); + } catch (IllegalStateException e) { + System.out.println("Exception caught"); + } + } + + private static void throwException() { + Thread.yield(); + System.out.println("Thread.yield called"); + throw new IllegalStateException(); } } diff --git a/teavm-samples/teavm-samples-async/src/main/webapp/index.html b/teavm-samples/teavm-samples-async/src/main/webapp/index.html index 96817c4a0..9f7151523 100644 --- a/teavm-samples/teavm-samples-async/src/main/webapp/index.html +++ b/teavm-samples/teavm-samples-async/src/main/webapp/index.html @@ -21,7 +21,7 @@ - +

Please, open developer's console to view program's output

\ No newline at end of file