Outline of upcoming improvements of continuations

This commit is contained in:
Alexey Andreev 2015-03-10 12:49:00 +04:00
parent 7f33f64d25
commit 93e43456d1
11 changed files with 164 additions and 260 deletions

View File

@ -72,10 +72,7 @@ public class TObject {
monitorEnter(o, 1);
}
@Async
static native void monitorEnter(TObject o, int count);
static void monitorEnter(final TObject o, final int count, final AsyncCallback<Void> callback) {
static void monitorEnter(TObject o, int count) {
if (o.monitor == null) {
o.monitor = new Monitor();
}
@ -83,21 +80,27 @@ public class TObject {
o.monitor.owner = TThread.currentThread();
}
if (o.monitor.owner != TThread.currentThread()) {
final TThread thread = TThread.currentThread();
o.monitor.enteringThreads.add(new PlatformRunnable() {
@Override public void run() {
TThread.setCurrentThread(thread);
o.monitor.owner = thread;
o.monitor.count += count;
callback.complete(null);
}
});
monitorEnterWait(o, count);
} else {
o.monitor.count += count;
callback.complete(null);
}
}
@Async
static native void monitorEnterWait(TObject o, int count);
static void monitorEnterWait(final TObject o, final int count, final AsyncCallback<Void> callback) {
final TThread thread = TThread.currentThread();
o.monitor.enteringThreads.add(new PlatformRunnable() {
@Override public void run() {
TThread.setCurrentThread(thread);
o.monitor.owner = thread;
o.monitor.count += count;
callback.complete(null);
}
});
}
@Sync
static void monitorExit(final TObject o) {
monitorExit(o, 1);
@ -230,15 +233,18 @@ public class TObject {
}
}
@Async
@Rename("wait")
private native final void wait0(long timeout, int nanos) throws TInterruptedException;
@Rename("wait")
public final void wait0(long timeout, int nanos, final AsyncCallback<Void> callback) {
private final void wait0(long timeout, int nanos) throws TInterruptedException {
if (!holdsLock(this)) {
throw new TIllegalMonitorStateException();
}
waitImpl(timeout, nanos);
}
@Async
private native final void waitImpl(long timeout, int nanos) throws TInterruptedException;
public final void waitImpl(long timeout, int nanos, final AsyncCallback<Void> callback) {
final NotifyListenerImpl listener = new NotifyListenerImpl(this, callback, monitor.count);
monitor.notifyListeners.add(listener);
if (timeout > 0 || nanos > 0) {
@ -288,7 +294,7 @@ public class TObject {
timerId = -1;
}
TThread.setCurrentThread(currentThread);
monitorEnter(obj, lockCount, callback);
monitorEnterWait(obj, lockCount, callback);
}
}

View File

@ -23,7 +23,6 @@ import org.teavm.platform.Platform;
import org.teavm.platform.PlatformRunnable;
import org.teavm.platform.async.AsyncCallback;
/**
*
* @author Alexey Andreev
@ -36,6 +35,7 @@ public class TThread extends TObject implements TRunnable {
private static int activeCount = 1;
private long id;
private int priority = 0;
private long timeSliceStart;
private TString name;
TRunnable target;
@ -55,10 +55,10 @@ public class TThread extends TObject implements TRunnable {
public TThread(TRunnable target, TString name ) {
this.name = name;
this.target = target;
id=nextId++;
id = nextId++;
}
public void start(){
public void start() {
Platform.startThread(new PlatformRunnable() {
@Override
public void run() {
@ -74,8 +74,11 @@ public class TThread extends TObject implements TRunnable {
});
}
static void setCurrentThread(TThread thread){
currentThread = thread;
static void setCurrentThread(TThread thread) {
if (currentThread != thread) {
currentThread = thread;
currentThread.timeSliceStart = System.currentTimeMillis();
}
}
static TThread getMainThread(){
return mainThread;
@ -96,11 +99,26 @@ public class TThread extends TObject implements TRunnable {
return name;
}
@Async
public static native void yield();
public static void yield() {
if (currentThread.timeSliceStart + 100 < System.currentTimeMillis()) {
switchContext();
}
}
private static void yield(final AsyncCallback<Void> callback) {
callback.complete(null);
@Async
static native void switchContext();
private static void switchContext(final AsyncCallback<Void> callback) {
final TThread thread = currentThread();
Platform.startThread(new PlatformRunnable() {
@Override public void run() {
setCurrentThread(thread);
callback.complete(null);
}
});
}
private static void yieldImpl() {
}
public void interrupt() {
@ -138,11 +156,11 @@ public class TThread extends TObject implements TRunnable {
}
}, millis);
}
public final void setPriority(int newPriority){
this.priority = newPriority;
}
public final int getPriority(){
return this.priority;
}

View File

@ -58,12 +58,7 @@ public class DefaultNamingStrategy implements NamingStrategy {
@Override
public String getNameFor(MethodDescriptor method) {
return getNameFor(method, 'S');
}
@Override
public String getNameForAsync(MethodDescriptor method) throws NamingException {
return getNameFor(method, 'A');
return getNameFor(method, 'M');
}
private String getNameFor(MethodDescriptor method, char classifier) {
@ -78,12 +73,7 @@ public class DefaultNamingStrategy implements NamingStrategy {
@Override
public String getFullNameFor(MethodReference method) throws NamingException {
return getFullNameFor(method, 'S');
}
@Override
public String getFullNameForAsync(MethodReference method) throws NamingException {
return getFullNameFor(method, 'A');
return getFullNameFor(method, 'M');
}
@Override

View File

@ -26,14 +26,10 @@ import org.teavm.model.MethodReference;
public interface NameFrequencyConsumer {
void consume(MethodReference method);
void consumeAsync(MethodReference method);
void consumeInit(MethodReference method);
void consume(MethodDescriptor method);
void consumeAsync(MethodDescriptor method);
void consume(String className);
void consume(FieldReference field);

View File

@ -43,21 +43,6 @@ public class NamingOrderer implements NameFrequencyConsumer {
entry.frequency++;
}
@Override
public void consumeAsync(final MethodReference method) {
String key = "A:" + method;
Entry entry = entries.get(key);
if (entry == null) {
entry = new Entry();
entry.operation = new NamingOperation() {
@Override public void perform(NamingStrategy naming) {
naming.getFullNameForAsync(method);
}
};
entries.put(key, entry);
}
entry.frequency++;
}
@Override
public void consumeInit(final MethodReference method) {
@ -91,22 +76,6 @@ public class NamingOrderer implements NameFrequencyConsumer {
entry.frequency++;
}
@Override
public void consumeAsync(final MethodDescriptor method) {
String key = "a:" + method;
Entry entry = entries.get(key);
if (entry == null) {
entry = new Entry();
entry.operation = new NamingOperation() {
@Override public void perform(NamingStrategy naming) {
naming.getNameForAsync(method);
}
};
entries.put(key, entry);
}
entry.frequency++;
}
@Override
public void consume(final String className) {
String key = "c:" + className;

View File

@ -28,14 +28,10 @@ public interface NamingStrategy {
String getNameFor(MethodDescriptor method) throws NamingException;
String getNameForAsync(MethodDescriptor method) throws NamingException;
String getNameForInit(MethodReference method) throws NamingException;
String getFullNameFor(MethodReference method) throws NamingException;
String getFullNameForAsync(MethodReference method) throws NamingException;
String getNameFor(FieldReference field) throws NamingException;
String getNameForFunction(String name) throws NamingException;

View File

@ -63,38 +63,17 @@ public class NameFrequencyEstimator implements StatementVisitor, ExprVisitor, Me
MethodReader clinit = classSource.get(cls.getName()).getMethod(
new MethodDescriptor("<clinit>", ValueType.VOID));
for (MethodNode method : cls.getMethods()) {
if (method.isAsync()) {
consumer.consumeAsync(method.getReference());
} else {
consumer.consume(method.getReference());
if (asyncFamilyMethods.contains(method.getReference())) {
consumer.consume(method.getReference());
if (asyncFamilyMethods.contains(method.getReference())) {
consumer.consume(method.getReference());
consumer.consumeAsync(method.getReference());
consumer.consumeFunction("$rt_asyncError");
consumer.consumeFunction("$rt_asyncResult");
}
}
if (clinit != null && (method.getModifiers().contains(NodeModifier.STATIC) ||
method.getReference().getName().equals("<init>"))) {
if (!method.isAsync()) {
consumer.consume(method.getReference());
}
if (asyncFamilyMethods.contains(method.getReference())) {
consumer.consumeAsync(method.getReference());
}
method.getReference().getName().equals("<init>"))) {
consumer.consume(method.getReference());
}
if (!method.getModifiers().contains(NodeModifier.STATIC)) {
if (method.isAsync()) {
consumer.consumeAsync(method.getReference().getDescriptor());
consumer.consumeAsync(method.getReference());
} else {
consumer.consume(method.getReference().getDescriptor());
consumer.consume(method.getReference());
if (asyncFamilyMethods.contains(method.getReference())) {
consumer.consumeAsync(method.getReference().getDescriptor());
consumer.consumeAsync(method.getReference());
}
}
consumer.consume(method.getReference().getDescriptor());
consumer.consume(method.getReference());
}
}
@ -217,7 +196,7 @@ public class NameFrequencyEstimator implements StatementVisitor, ExprVisitor, Me
if (async) {
MethodReference monitorEnterRef = new MethodReference(
Object.class, "monitorEnter", Object.class, void.class);
consumer.consumeAsync(monitorEnterRef);
consumer.consume(monitorEnterRef);
} else {
MethodReference monitorEnterRef = new MethodReference(
Object.class, "monitorEnterSync", Object.class, void.class);
@ -230,7 +209,7 @@ public class NameFrequencyEstimator implements StatementVisitor, ExprVisitor, Me
if (async) {
MethodReference monitorEnterRef = new MethodReference(
Object.class, "monitorExit", Object.class, void.class);
consumer.consumeAsync(monitorEnterRef);
consumer.consume(monitorEnterRef);
} else {
MethodReference monitorEnterRef = new MethodReference(
Object.class, "monitorExitSync", Object.class, void.class);
@ -308,30 +287,18 @@ public class NameFrequencyEstimator implements StatementVisitor, ExprVisitor, Me
if (injectedMethods.contains(expr.getMethod())) {
return;
}
boolean asyncCall = expr.getAsyncTarget() != null;
switch (expr.getType()) {
case SPECIAL:
case STATIC:
if (asyncCall) {
consumer.consumeAsync(expr.getMethod());
} else {
consumer.consume(expr.getMethod());
}
consumer.consume(expr.getMethod());
break;
case CONSTRUCTOR:
consumer.consumeInit(expr.getMethod());
break;
case DYNAMIC:
if (asyncCall) {
consumer.consumeAsync(expr.getMethod().getDescriptor());
} else {
consumer.consume(expr.getMethod().getDescriptor());
}
consumer.consume(expr.getMethod().getDescriptor());
break;
}
if (asyncCall) {
consumer.consumeFunction("$rt_continue");
}
}
@Override

View File

@ -452,12 +452,7 @@ public class Renderer implements ExprVisitor, StatementVisitor, RenderingContext
for (MethodNode method : cls.getMethods()) {
if (clinit != null && (method.getModifiers().contains(NodeModifier.STATIC) ||
method.getReference().getName().equals("<init>"))) {
if (!method.isAsync()) {
stubNames.add(naming.getFullNameFor(method.getReference()));
}
if (asyncFamilyMethods.contains(method.getReference())) {
stubNames.add(naming.getFullNameForAsync(method.getReference()));
}
stubNames.add(naming.getFullNameFor(method.getReference()));
}
if (!method.getModifiers().contains(NodeModifier.STATIC)) {
virtualMethods.add(method);
@ -546,32 +541,20 @@ public class Renderer implements ExprVisitor, StatementVisitor, RenderingContext
writer.append(",").ws();
}
first = false;
if (method.isAsync()) {
emitVirtualDeclaration(ref, true);
} else {
emitVirtualDeclaration(ref, false);
if (asyncFamilyMethods.contains(ref)) {
writer.append(",").ws();
emitVirtualDeclaration(ref, true);
}
}
emitVirtualDeclaration(ref);
debugEmitter.emitMethod(null);
}
writer.append("]");
}
private void emitVirtualDeclaration(MethodReference ref, boolean async) throws IOException {
String methodName = async ? naming.getNameForAsync(ref.getDescriptor()) :
naming.getNameFor(ref.getDescriptor());
private void emitVirtualDeclaration(MethodReference ref) throws IOException {
String methodName = naming.getNameFor(ref.getDescriptor());
writer.append("\"").append(methodName).append("\"");
writer.append(",").ws().append("function(");
List<String> args = new ArrayList<>();
for (int i = 1; i <= ref.parameterCount(); ++i) {
args.add(variableName(i));
}
if (async) {
args.add(getReturnVariable());
}
for (int i = 0; i < args.size(); ++i) {
if (i > 0) {
writer.append(",").ws();
@ -582,7 +565,7 @@ public class Renderer implements ExprVisitor, StatementVisitor, RenderingContext
if (ref.getDescriptor().getResultType() != ValueType.VOID) {
writer.append("return ");
}
writer.append(async ? naming.getFullNameForAsync(ref) : naming.getFullNameFor(ref)).append("(");
writer.appendMethodBody(ref).append("(");
writer.append("this");
for (int i = 0; i < args.size(); ++i) {
writer.append(",").ws().append(args.get(i));
@ -590,23 +573,11 @@ public class Renderer implements ExprVisitor, StatementVisitor, RenderingContext
writer.append(");").ws().append("}");
}
private String getPartVariable(int index) {
if (minifying) {
return "$p" + indexToId(index);
} else {
return "$part_" + index;
}
}
private String getReturnVariable() {
return minifying ? "$r" : "$return";
}
public void renderBody(MethodNode method, boolean inner) throws IOException {
blockIdMap.clear();
MethodReference ref = method.getReference();
debugEmitter.emitMethod(ref.getDescriptor());
String name = method.isAsync() ? naming.getFullNameForAsync(ref) : naming.getFullNameFor(ref);
String name = naming.getFullNameFor(ref);
if (inner) {
writer.append(name).ws().append("=").ws().append("function(");
} else {
@ -622,12 +593,6 @@ public class Renderer implements ExprVisitor, StatementVisitor, RenderingContext
}
writer.append(variableName(i));
}
if (method.isAsync()) {
if (startParam < ref.parameterCount() + 1) {
writer.append(',').ws();
}
writer.append(getReturnVariable());
}
writer.append(")").ws().append("{").softNewLine().indent();
method.acceptVisitor(new MethodBodyRenderer());
writer.outdent().append("}");
@ -635,42 +600,6 @@ public class Renderer implements ExprVisitor, StatementVisitor, RenderingContext
writer.append(';');
}
writer.newLine();
if (!method.isAsync() && asyncFamilyMethods.contains(method.getReference())) {
if (inner) {
writer.append(naming.getFullNameForAsync(ref)).ws().append("=").ws().append("function(");
} else {
writer.append("function ").append(naming.getFullNameForAsync(ref)).append("(");
}
for (int i = startParam; i <= ref.parameterCount(); ++i) {
writer.append(variableName(i));
writer.append(",").ws();
}
writer.append(getReturnVariable()).append(")").ws().append("{").softNewLine().indent();
writer.append("var $x;").softNewLine();
writer.append("try").ws().append('{').indent().softNewLine();
writer.append("$x").ws().append("=").ws().appendMethodBody(ref).append('(');
for (int i = startParam; i <= ref.parameterCount(); ++i) {
if (i > startParam) {
writer.append(",").ws();
}
writer.append(variableName(i));
}
writer.append(");").softNewLine();
writer.outdent().append("}").ws().append("catch").ws().append("($e)").ws()
.append("{").indent().softNewLine();
writer.append("return ").append(getReturnVariable()).append("(").appendFunction("$rt_asyncError")
.append("($e));").softNewLine();
writer.outdent().append("}");
writer.append(getReturnVariable()).append("(").appendFunction("$rt_asyncResult").append("($x));")
.softNewLine();
writer.outdent().append("}");
if (inner) {
writer.append(';');
}
writer.newLine();
}
debugEmitter.emitMethod(null);
}
@ -756,6 +685,7 @@ public class Renderer implements ExprVisitor, StatementVisitor, RenderingContext
if (hasTryCatch) {
variableNames.add("$je");
}
variableNames.add("$ptr");
if (!variableNames.isEmpty()) {
writer.append("var ");
for (int i = 0; i < variableNames.size(); ++i) {
@ -766,18 +696,34 @@ public class Renderer implements ExprVisitor, StatementVisitor, RenderingContext
}
writer.append(";").softNewLine();
}
writer.append("function $save()").ws().append("{").indent().softNewLine();
writer.append("var $").ws().append('=').ws().append("$rt_stack();").softNewLine();
for (int i = ref.parameterCount() + 1; i < variableCount; ++i) {
writer.append("$.push(").append(variableName(i)).append(");");
}
writer.append("$.push($ptr)");
writer.softNewLine();
writer.outdent().append("}").softNewLine();
writer.append("$ptr").ws().append('=').ws().append("0;").softNewLine();
writer.append("if").ws().append("($rt_isRestoring())").ws().append("{").indent().softNewLine();
writer.append("var $s").ws().append('=').ws().append("$rt_stack();").softNewLine();
writer.append("var $ptr").ws().append('=').append("$s.pop();");
for (int i = variableCount - 1; i > ref.parameterCount(); --i) {
writer.append(variableName(i)).ws().append('=').ws().append("$.pop();");
}
writer.softNewLine();
writer.outdent().append("}").softNewLine();
writer.append("$main: switch").ws().append("($ptr)").ws().append('{').softNewLine();
for (int i = 0; i < methodNode.getBody().size(); ++i) {
writer.append("var ").append(getPartVariable(i)).ws().append("=").ws()
.appendFunction("$rt_guardAsync").append("(function(");
if (i > 0) {
writer.append("$restore");
}
writer.append(")").ws().append("{").indent().softNewLine();
writer.append("case ").append(i).append(":").indent().softNewLine();
AsyncMethodPart part = methodNode.getBody().get(i);
part.getStatement().acceptVisitor(Renderer.this);
writer.outdent().append("},").ws().append(getReturnVariable()).append(");").softNewLine();
writer.outdent();
}
writer.append("return ").append(getPartVariable(0)).append("();").softNewLine();
writer.append("}").softNewLine();
} catch (IOException e) {
throw new RenderingException("IO error occured", e);
}
@ -823,11 +769,6 @@ public class Renderer implements ExprVisitor, StatementVisitor, RenderingContext
return asyncFamilyMethods.contains(method);
}
@Override
public String getCompleteContinuation() {
return getReturnVariable();
}
@Override
public Diagnostics getDiagnostics() {
return diagnostics;
@ -1097,23 +1038,14 @@ public class Renderer implements ExprVisitor, StatementVisitor, RenderingContext
pushLocation(statement.getLocation());
}
writer.append("return");
if (async) {
writer.append(' ').append(getReturnVariable()).append("(").appendFunction("$rt_asyncResult")
.append("(");
}
if (statement.getResult() != null) {
if (!async) {
writer.append(' ');
}
writer.append(' ');
prevCallSite = debugEmitter.emitCallSite();
priority = Priority.COMMA;
associativity = Associativity.NONE;
statement.getResult().acceptVisitor(this);
debugEmitter.emitCallSite();
}
if (async) {
writer.append("))");
}
writer.append(";").softNewLine();
if (statement.getLocation() != null) {
popLocation();
@ -1693,43 +1625,33 @@ public class Renderer implements ExprVisitor, StatementVisitor, RenderingContext
if (injector != null) {
injector.generate(new InjectorContextImpl(expr.getArguments()), expr.getMethod());
} else {
boolean asyncCall = expr.getAsyncTarget() != null;
if (asyncCall) {
writer.append("return ");
}
if (expr.getType() == InvocationType.DYNAMIC) {
expr.getArguments().get(0).acceptVisitor(this);
}
MethodReference method = expr.getMethod();
String name = asyncCall ? naming.getNameForAsync(method.getDescriptor()) :
naming.getNameFor(method.getDescriptor());
String name = naming.getNameFor(method.getDescriptor());
DeferredCallSite callSite = prevCallSite;
boolean shouldEraseCallSite = lastCallSite == null;
if (lastCallSite == null) {
lastCallSite = callSite;
}
boolean virtual = false;
boolean hasParams = false;
enterPriority(Priority.COMMA, Associativity.NONE, false);
switch (expr.getType()) {
case STATIC:
writer.append(asyncCall ? naming.getFullNameForAsync(method) :
naming.getFullNameFor(method)).append("(");
writer.append(naming.getFullNameFor(method)).append("(");
prevCallSite = debugEmitter.emitCallSite();
for (int i = 0; i < expr.getArguments().size(); ++i) {
if (i > 0) {
writer.append(",").ws();
}
expr.getArguments().get(i).acceptVisitor(this);
hasParams = true;
}
break;
case SPECIAL:
writer.append(asyncCall ? naming.getFullNameForAsync(method) :
naming.getFullNameFor(method)).append("(");
writer.append(naming.getFullNameFor(method)).append("(");
prevCallSite = debugEmitter.emitCallSite();
expr.getArguments().get(0).acceptVisitor(this);
hasParams = true;
for (int i = 1; i < expr.getArguments().size(); ++i) {
writer.append(",").ws();
expr.getArguments().get(i).acceptVisitor(this);
@ -1742,7 +1664,6 @@ public class Renderer implements ExprVisitor, StatementVisitor, RenderingContext
if (i > 1) {
writer.append(",").ws();
}
hasParams = true;
expr.getArguments().get(i).acceptVisitor(this);
}
virtual = true;
@ -1754,20 +1675,21 @@ public class Renderer implements ExprVisitor, StatementVisitor, RenderingContext
if (i > 0) {
writer.append(",").ws();
}
hasParams = true;
expr.getArguments().get(i).acceptVisitor(this);
}
break;
}
if (expr.getAsyncTarget() != null) {
if (hasParams) {
writer.append(',').ws();
}
writer.appendFunction("$rt_continue").append("(").append(getPartVariable(expr.getAsyncTarget()))
.append(')');
}
writer.append(')');
exitPriority();
if (expr.getAsyncTarget() != null) {
writer.append(';').softNewLine();
writer.append("$ptr").ws().append("=").ws().append(expr.getAsyncTarget()).append(";")
.softNewLine();
writer.append("if").ws().append("($rt_suspending())").ws().append("{").indent();
writer.append("return $save();").softNewLine();
writer.outdent().append("}").softNewLine();
writer.append("break $main;").softNewLine();
}
if (lastCallSite != null) {
if (virtual) {
lastCallSite.setVirtualMethod(expr.getMethod());
@ -2061,11 +1983,8 @@ public class Renderer implements ExprVisitor, StatementVisitor, RenderingContext
if (async) {
MethodReference monitorEnterRef = new MethodReference(
Object.class, "monitorEnter", Object.class, void.class);
writer.append("return ").append(naming.getFullNameForAsync(monitorEnterRef)).append("(");
writer.appendMethodBody(monitorEnterRef).append("(");
statement.getObjectRef().acceptVisitor(this);
writer.append(",").ws();
writer.appendFunction("$rt_continue").append("(").append(getPartVariable(statement.getAsyncTarget()))
.append(')');
writer.append(");").softNewLine();
} else {
MethodReference monitorEnterRef = new MethodReference(

View File

@ -36,8 +36,6 @@ public interface GeneratorContext extends ServiceRepository {
boolean isAsync();
String getCompleteContinuation();
boolean isAsync(MethodReference method);
boolean isAsyncFamily(MethodReference method);

View File

@ -437,13 +437,7 @@ public class TeaVM implements TeaVMHost, ServiceRepository {
for (Map.Entry<String, TeaVMEntryPoint> entry : entryPoints.entrySet()) {
sourceWriter.append("var ").append(entry.getKey()).ws().append("=").ws();
MethodReference ref = entry.getValue().reference;
boolean asyncMethod = asyncMethods.contains(ref);
boolean wrapAsync = !asyncMethod && entry.getValue().isAsync();
if (wrapAsync) {
sourceWriter.append("$rt_staticAsyncAdapter(").appendMethodBody(ref).append(')');
} else {
sourceWriter.append(asyncMethod ? naming.getFullNameForAsync(ref) : naming.getFullNameFor(ref));
}
sourceWriter.append(naming.getFullNameFor(ref));
sourceWriter.append(";").newLine();
}
for (Map.Entry<String, String> entry : exportedClasses.entrySet()) {

View File

@ -517,6 +517,57 @@ function $rt_guardAsync(f, continuation) {
}
}
}
function TeaVMThread(runner) {
this.status = 3;
this.stack = [];
this.suspendCallback = null;
this.runner = runner;
}
TeaVMThread.push = function(value) {
this.stack.push[value];
}
TeaVMThread.isResuming = function() {
return this.status == 1;
}
TeaVMThread.isSuspending = function() {
return this.status == 2;
}
TeaVMThread.suspend(callback) {
this.suspendCallback = callback;
this.status = 1;
}
TeaVMThread.start = function() {
if (this.status != 3) {
throw new Error("Thread already started");
}
this.status = 0;
this.run();
}
TeaVMThread.resume = function() {
this.status = 2;
this.run();
}
TeaVMThread.run = function() {
this.runner();
if (this.suspendCallback !== null) {
var self = this;
this.suspendCallback(function() {
self.resume();
});
}
}
function $rt_nativeThread(thread) {
if (!thread.hasNativeProperty("$teavm_thread")) {
thread.$teavm_thread = new TeaVMThread();
}
}
function $rt_suspending() {
return $rt_nativeThread($rt_getThread()).isSuspending();
}
function $rt_resuming() {
return $rt_nativeThread($rt_getThread()).isResuming();
}
function TeaVMAsyncError(cause) {
this.message = "Async error occured";
this.cause = cause;