mirror of
https://github.com/Eaglercraft-TeaVM-Fork/eagler-teavm.git
synced 2024-12-22 16:14:10 -08:00
Add exception support to async methods
This commit is contained in:
parent
8a11239436
commit
73721e5b31
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -257,6 +257,10 @@ public class DiskRegularMethodNodeCache implements RegularMethodNodeCache {
|
|||
@Override
|
||||
public void visit(StaticClassExpr expr) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(RestoreAsyncStatement statement) {
|
||||
}
|
||||
}
|
||||
|
||||
static class Item {
|
||||
|
|
|
@ -112,4 +112,8 @@ class BreakToContinueReplacer implements StatementVisitor {
|
|||
visitSequence(statement.getProtectedBody());
|
||||
visitSequence(statement.getHandler());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(RestoreAsyncStatement statement) {
|
||||
}
|
||||
}
|
||||
|
|
|
@ -107,4 +107,8 @@ class CertainBlockCountVisitor implements StatementVisitor {
|
|||
visit(statement.getProtectedBody());
|
||||
visit(statement.getHandler());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(RestoreAsyncStatement statement) {
|
||||
}
|
||||
}
|
||||
|
|
|
@ -204,8 +204,15 @@ public class Decompiler {
|
|||
splitter.split(method.getProgram());
|
||||
List<Program> 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<Instruction> 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);
|
||||
}
|
||||
|
|
|
@ -577,4 +577,9 @@ class OptimizingVisitor implements StatementVisitor, ExprVisitor {
|
|||
statement.getHandler().addAll(statements);
|
||||
resultStmt = statement;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(RestoreAsyncStatement statement) {
|
||||
resultStmt = statement;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -117,4 +117,8 @@ class RedundantLabelEliminator implements StatementVisitor {
|
|||
visitSequence(statement.getProtectedBody());
|
||||
visitSequence(statement.getHandler());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(RestoreAsyncStatement statement) {
|
||||
}
|
||||
}
|
||||
|
|
|
@ -111,4 +111,8 @@ class ReferenceCountingVisitor implements StatementVisitor {
|
|||
part.acceptVisitor(this);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(RestoreAsyncStatement statement) {
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -110,4 +110,8 @@ class TryCatchFinder implements StatementVisitor {
|
|||
public void visit(TryCatchStatement statement) {
|
||||
tryCatchFound = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(RestoreAsyncStatement statement) {
|
||||
}
|
||||
}
|
||||
|
|
|
@ -224,4 +224,8 @@ class UnusedVariableEliminator implements ExprVisitor, StatementVisitor {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(RestoreAsyncStatement statement) {
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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<AsyncMethodCatch> 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<AsyncMethodCatch> getCatches() {
|
||||
return catches;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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()]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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<Statement> handler = new ArrayList<>();
|
||||
private String exceptionType;
|
||||
private Integer exceptionVariable;
|
||||
public class RestoreAsyncStatement extends Statement {
|
||||
private Integer receiver;
|
||||
|
||||
public List<Statement> 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);
|
||||
}
|
||||
}
|
|
@ -43,4 +43,6 @@ public interface StatementVisitor {
|
|||
void visit(InitClassStatement statement);
|
||||
|
||||
void visit(TryCatchStatement statement);
|
||||
|
||||
void visit(RestoreAsyncStatement statement);
|
||||
}
|
||||
|
|
|
@ -34,7 +34,5 @@ public interface GeneratorContext extends ServiceRepository {
|
|||
|
||||
boolean isAsync();
|
||||
|
||||
String getErrorContinuation();
|
||||
|
||||
String getCompleteContinuation();
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -21,7 +21,7 @@
|
|||
<script type="text/javascript" charset="utf-8" src="teavm/runtime.js"></script>
|
||||
<script type="text/javascript" charset="utf-8" src="teavm/classes.js"></script>
|
||||
</head>
|
||||
<body onload="main()">
|
||||
<body onload="main(null)">
|
||||
<p>Please, open developer's console to view program's output</p>
|
||||
</body>
|
||||
</html>
|
Loading…
Reference in New Issue
Block a user