mirror of
https://github.com/Eaglercraft-TeaVM-Fork/eagler-teavm.git
synced 2024-12-22 16:14:10 -08:00
Fix monitorenter
This commit is contained in:
parent
f35f06097c
commit
f93b35ce80
|
@ -15,6 +15,7 @@
|
|||
*/
|
||||
package org.teavm.classlib.java.lang;
|
||||
|
||||
import org.teavm.dom.browser.TimerHandler;
|
||||
import org.teavm.dom.browser.Window;
|
||||
import org.teavm.javascript.spi.Async;
|
||||
import org.teavm.javascript.spi.Rename;
|
||||
|
@ -32,40 +33,50 @@ import org.teavm.platform.async.AsyncCallback;
|
|||
@Superclass("")
|
||||
public class TObject {
|
||||
private static final Window window = (Window)JS.getGlobal();
|
||||
private TThread owner;
|
||||
private TObject monitorLock;
|
||||
private int monitorCount;
|
||||
private JSArray<NotifyListener> notifyListeners;
|
||||
private Lock lock;
|
||||
|
||||
private static class Lock {
|
||||
TThread owner;
|
||||
int count;
|
||||
|
||||
public Lock() {
|
||||
this.owner = TThread.currentThread();
|
||||
count = 1;
|
||||
}
|
||||
}
|
||||
|
||||
interface NotifyListener extends JSObject {
|
||||
void handleNotify();
|
||||
boolean handleNotify();
|
||||
}
|
||||
|
||||
static void monitorEnter(TObject o){
|
||||
if (o.monitorLock == null ){
|
||||
o.monitorLock = new TObject();
|
||||
static void monitorEnter(TObject o) {
|
||||
if (o.lock == null) {
|
||||
o.lock = new Lock();
|
||||
return;
|
||||
}
|
||||
while (o.owner != null && o.owner != TThread.currentThread()) {
|
||||
if (o.lock.owner != TThread.currentThread()) {
|
||||
while (o.lock != null) {
|
||||
try {
|
||||
o.monitorLock.wait();
|
||||
o.lock.wait();
|
||||
} catch (InterruptedException ex) {
|
||||
|
||||
}
|
||||
}
|
||||
o.owner = TThread.currentThread();
|
||||
o.monitorCount++;
|
||||
o.lock = new Lock();
|
||||
} else {
|
||||
o.lock.count++;
|
||||
}
|
||||
}
|
||||
|
||||
static void monitorExit(TObject o){
|
||||
o.monitorCount--;
|
||||
if (o.monitorCount == 0 && o.monitorLock != null) {
|
||||
o.owner = null;
|
||||
o.monitorLock.notifyAll();
|
||||
if (o.lock != null && o.lock.count-- == 0) {
|
||||
o.lock.notifyAll();
|
||||
o.lock = null;
|
||||
}
|
||||
}
|
||||
|
||||
static boolean holdsLock(TObject o){
|
||||
return o.owner == TThread.currentThread();
|
||||
return o.lock != null && o.lock.owner == TThread.currentThread();
|
||||
}
|
||||
|
||||
@Rename("fakeInit")
|
||||
|
@ -114,11 +125,15 @@ public class TObject {
|
|||
|
||||
@Rename("notify")
|
||||
public final void notify0(){
|
||||
if (notifyListeners != null && notifyListeners.getLength() > 0){
|
||||
notifyListeners.shift().handleNotify();
|
||||
if (notifyListeners != null) {
|
||||
while (notifyListeners.getLength() > 0 && notifyListeners.shift().handleNotify()) {
|
||||
// repeat loop
|
||||
}
|
||||
if (notifyListeners.getLength() == 0) {
|
||||
notifyListeners = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Rename("notifyAll")
|
||||
public final void notifyAll0(){
|
||||
|
@ -127,6 +142,7 @@ public class TObject {
|
|||
while (notifyListeners.getLength() > 0) {
|
||||
listeners.push(notifyListeners.shift());
|
||||
}
|
||||
notifyListeners = null;
|
||||
while (listeners.getLength() > 0) {
|
||||
listeners.shift().handleNotify();
|
||||
}
|
||||
|
@ -144,7 +160,7 @@ public class TObject {
|
|||
|
||||
@Async
|
||||
@Rename("wait")
|
||||
public native final void wait0(long timeout, int nanos) throws TInterruptedException;
|
||||
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) {
|
||||
|
@ -152,24 +168,55 @@ public class TObject {
|
|||
notifyListeners = window.newArray();
|
||||
}
|
||||
final TThread currentThread = TThread.currentThread();
|
||||
notifyListeners.push(new NotifyListener() {
|
||||
final NotifyListenerImpl listener = new NotifyListenerImpl(callback, currentThread);
|
||||
notifyListeners.push(listener);
|
||||
if (timeout == 0 && nanos == 0) {
|
||||
return;
|
||||
}
|
||||
listener.timerId = window.setTimeout(listener, timeout);
|
||||
}
|
||||
|
||||
private static class NotifyListenerImpl implements NotifyListener, TimerHandler {
|
||||
final AsyncCallback<Void> callback;
|
||||
final TThread currentThread;
|
||||
int timerId = -1;
|
||||
boolean finished;
|
||||
|
||||
public NotifyListenerImpl(AsyncCallback<Void> callback, TThread currentThread) {
|
||||
this.callback = callback;
|
||||
this.currentThread = currentThread;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleNotify() {
|
||||
public boolean handleNotify() {
|
||||
if (finished) {
|
||||
return false;
|
||||
}
|
||||
TThread.setCurrentThread(currentThread);
|
||||
if (timerId >= 0) {
|
||||
window.clearTimeout(timerId);
|
||||
timerId = -1;
|
||||
}
|
||||
finished = true;
|
||||
try {
|
||||
callback.complete(null);
|
||||
} finally {
|
||||
TThread.setCurrentThread(TThread.getMainThread());
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onTimer() {
|
||||
handleNotify();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Rename("wait")
|
||||
public final void wait0() throws TInterruptedException {
|
||||
try {
|
||||
wait(0l);
|
||||
} catch ( InterruptedException ex){
|
||||
} catch (InterruptedException ex) {
|
||||
throw new TInterruptedException();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -73,22 +73,21 @@ public class Renderer implements ExprVisitor, StatementVisitor, RenderingContext
|
|||
|
||||
@Override
|
||||
public void visit(MonitorEnterStatement statement) {
|
||||
if (async){
|
||||
try {
|
||||
MethodReference monitorEnterRef = new MethodReference(
|
||||
Object.class, "monitorEnter", Object.class, void.class);
|
||||
writer.appendMethodBody(monitorEnterRef).append("(");
|
||||
statement.getObjectRef().acceptVisitor(this);
|
||||
writer.append(",").ws();
|
||||
writer.append("$rt_continue($part_").append(statement.getAsyncTarget()).append(')');
|
||||
writer.append(");").softNewLine();
|
||||
} catch (IOException ex){
|
||||
throw new RenderingException("IO error occured", ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(MonitorExitStatement statement) {
|
||||
if (async){
|
||||
try {
|
||||
MethodReference monitorExitRef = new MethodReference(
|
||||
Object.class, "monitorExit", Object.class, void.class);
|
||||
|
@ -99,7 +98,6 @@ public class Renderer implements ExprVisitor, StatementVisitor, RenderingContext
|
|||
throw new RenderingException("IO error occured", ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static class InjectorHolder {
|
||||
public final Injector injector;
|
||||
|
@ -938,7 +936,7 @@ public class Renderer implements ExprVisitor, StatementVisitor, RenderingContext
|
|||
StringBuilder sb = new StringBuilder();
|
||||
int index = blockIdMap.size();
|
||||
do {
|
||||
sb.append(variablePartNames.charAt(index % variableNames.length()));
|
||||
sb.append(variablePartNames.charAt(index % variablePartNames.length()));
|
||||
index /= variablePartNames.length();
|
||||
} while (index > 0);
|
||||
name = "$b" + sb;
|
||||
|
|
|
@ -669,11 +669,10 @@ class StatementGenerator implements InstructionVisitor {
|
|||
|
||||
@Override
|
||||
public void visit(MonitorEnterInstruction insn) {
|
||||
|
||||
MonitorEnterStatement stmt = new MonitorEnterStatement();
|
||||
stmt.setLocation(currentLocation);
|
||||
|
||||
stmt.setObjectRef(Expr.var(insn.getObjectRef().getIndex()));
|
||||
stmt.setAsyncTarget(asyncTarget);
|
||||
statements.add(stmt);
|
||||
}
|
||||
|
||||
|
@ -681,7 +680,6 @@ class StatementGenerator implements InstructionVisitor {
|
|||
public void visit(MonitorExitInstruction insn) {
|
||||
MonitorExitStatement stmt = new MonitorExitStatement();
|
||||
stmt.setLocation(currentLocation);
|
||||
|
||||
stmt.setObjectRef(Expr.var(insn.getObjectRef().getIndex()));
|
||||
statements.add(stmt);
|
||||
}
|
||||
|
|
|
@ -20,41 +20,36 @@ package org.teavm.javascript.ast;
|
|||
* @author shannah
|
||||
*/
|
||||
public class MonitorEnterStatement extends Statement {
|
||||
|
||||
private NodeLocation location;
|
||||
private Expr objectRef;
|
||||
private Integer asyncTarget;
|
||||
|
||||
@Override
|
||||
public void acceptVisitor(StatementVisitor visitor) {
|
||||
visitor.visit(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the location
|
||||
*/
|
||||
public NodeLocation getLocation() {
|
||||
return location;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param location the location to set
|
||||
*/
|
||||
public void setLocation(NodeLocation location) {
|
||||
this.location = location;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the objectRef
|
||||
*/
|
||||
public Expr getObjectRef() {
|
||||
return objectRef;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param objectRef the objectRef to set
|
||||
*/
|
||||
public void setObjectRef(Expr objectRef) {
|
||||
this.objectRef = objectRef;
|
||||
}
|
||||
|
||||
public Integer getAsyncTarget() {
|
||||
return asyncTarget;
|
||||
}
|
||||
|
||||
public void setAsyncTarget(Integer asyncTarget) {
|
||||
this.asyncTarget = asyncTarget;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -20,41 +20,28 @@ package org.teavm.javascript.ast;
|
|||
* @author shannah
|
||||
*/
|
||||
public class MonitorExitStatement extends Statement {
|
||||
|
||||
private NodeLocation location;
|
||||
private Expr objectRef;
|
||||
private Integer asyncTarget;
|
||||
|
||||
@Override
|
||||
public void acceptVisitor(StatementVisitor visitor) {
|
||||
visitor.visit(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the location
|
||||
*/
|
||||
public NodeLocation getLocation() {
|
||||
return location;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param location the location to set
|
||||
*/
|
||||
public void setLocation(NodeLocation location) {
|
||||
this.location = location;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the objectRef
|
||||
*/
|
||||
public Expr getObjectRef() {
|
||||
return objectRef;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param objectRef the objectRef to set
|
||||
*/
|
||||
public void setObjectRef(Expr objectRef) {
|
||||
this.objectRef = objectRef;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -24,6 +24,7 @@ import org.teavm.javascript.spi.Async;
|
|||
import org.teavm.javascript.spi.InjectedBy;
|
||||
import org.teavm.javascript.spi.Sync;
|
||||
import org.teavm.model.*;
|
||||
import org.teavm.model.instructions.*;
|
||||
|
||||
/**
|
||||
*
|
||||
|
@ -61,6 +62,17 @@ public class AsyncMethodFinder {
|
|||
}
|
||||
if (method.getAnnotations().get(Async.class.getName()) != null) {
|
||||
add(method.getReference());
|
||||
} else if (method.getProgram() != null) {
|
||||
ProgramReader program = method.getProgram();
|
||||
AsyncInstructionFinder insnFinder = new AsyncInstructionFinder();
|
||||
for (int i = 0; i < program.basicBlockCount(); ++i) {
|
||||
BasicBlockReader block = program.basicBlockAt(i);
|
||||
block.readAllInstructions(insnFinder);
|
||||
if (insnFinder.hasAsync) {
|
||||
add(method.getReference());
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -174,4 +186,166 @@ public class AsyncMethodFinder {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
private class AsyncInstructionFinder implements InstructionReader {
|
||||
boolean hasAsync;
|
||||
|
||||
@Override
|
||||
public void location(InstructionLocation location) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void nop() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void classConstant(VariableReader receiver, ValueType cst) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void nullConstant(VariableReader receiver) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void integerConstant(VariableReader receiver, int cst) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void longConstant(VariableReader receiver, long cst) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void floatConstant(VariableReader receiver, float cst) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void doubleConstant(VariableReader receiver, double cst) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void stringConstant(VariableReader receiver, String cst) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void binary(BinaryOperation op, VariableReader receiver, VariableReader first, VariableReader second,
|
||||
NumericOperandType type) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void negate(VariableReader receiver, VariableReader operand, NumericOperandType type) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void assign(VariableReader receiver, VariableReader assignee) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void cast(VariableReader receiver, VariableReader value, ValueType targetType) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void cast(VariableReader receiver, VariableReader value, NumericOperandType sourceType,
|
||||
NumericOperandType targetType) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void cast(VariableReader receiver, VariableReader value, IntegerSubtype type,
|
||||
CastIntegerDirection targetType) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void jumpIf(BranchingCondition cond, VariableReader operand, BasicBlockReader consequent,
|
||||
BasicBlockReader alternative) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void jumpIf(BinaryBranchingCondition cond, VariableReader first, VariableReader second,
|
||||
BasicBlockReader consequent, BasicBlockReader alternative) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void jump(BasicBlockReader target) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void choose(VariableReader condition, List<? extends SwitchTableEntryReader> table,
|
||||
BasicBlockReader defaultTarget) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void exit(VariableReader valueToReturn) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void raise(VariableReader exception) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void createArray(VariableReader receiver, ValueType itemType, VariableReader size) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void createArray(VariableReader receiver, ValueType itemType,
|
||||
List<? extends VariableReader> dimensions) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void create(VariableReader receiver, String type) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void getField(VariableReader receiver, VariableReader instance, FieldReference field,
|
||||
ValueType fieldType) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void putField(VariableReader instance, FieldReference field, VariableReader value) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void arrayLength(VariableReader receiver, VariableReader array) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void cloneArray(VariableReader receiver, VariableReader array) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unwrapArray(VariableReader receiver, VariableReader array, ArrayElementType elementType) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void getElement(VariableReader receiver, VariableReader array, VariableReader index) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void putElement(VariableReader array, VariableReader index, VariableReader value) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void invoke(VariableReader receiver, VariableReader instance, MethodReference method,
|
||||
List<? extends VariableReader> arguments, InvocationType type) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void isInstance(VariableReader receiver, VariableReader value, ValueType type) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void initClass(String className) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void nullCheck(VariableReader receiver, VariableReader value) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void monitorEnter(VariableReader objectRef) {
|
||||
hasAsync = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void monitorExit(VariableReader objectRef) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -19,6 +19,7 @@ import java.util.*;
|
|||
import org.teavm.model.*;
|
||||
import org.teavm.model.instructions.InvokeInstruction;
|
||||
import org.teavm.model.instructions.JumpInstruction;
|
||||
import org.teavm.model.instructions.MonitorEnterInstruction;
|
||||
|
||||
/**
|
||||
*
|
||||
|
@ -58,14 +59,21 @@ public class AsyncProgramSplitter {
|
|||
int last = 0;
|
||||
for (int i = 0; i < sourceBlock.getInstructions().size(); ++i) {
|
||||
Instruction insn = sourceBlock.getInstructions().get(i);
|
||||
Integer receiver;
|
||||
if (insn instanceof InvokeInstruction) {
|
||||
InvokeInstruction invoke = (InvokeInstruction)insn;
|
||||
if (!asyncMethods.contains(invoke.getMethod())) {
|
||||
continue;
|
||||
}
|
||||
receiver = invoke.getReceiver() != null ? invoke.getReceiver().getIndex() : null;
|
||||
} else if (insn instanceof MonitorEnterInstruction) {
|
||||
receiver = null;
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
|
||||
// If we met asynchronous invocation...
|
||||
// Copy portion of current block from last occurence (or from start) to i'th instruction.
|
||||
// Copy portion of current block from last occurrence (or from start) to i'th instruction.
|
||||
targetBlock.getInstructions().addAll(ProgramUtils.copyInstructions(sourceBlock,
|
||||
last, i + 1, targetBlock.getProgram()));
|
||||
targetBlock.getTryCatchBlocks().addAll(ProgramUtils.copyTryCatches(sourceBlock,
|
||||
|
@ -91,7 +99,7 @@ public class AsyncProgramSplitter {
|
|||
// Create a new part
|
||||
Program nextProgram = createStubCopy(program);
|
||||
Part part = new Part();
|
||||
part.input = invoke.getReceiver() != null ? invoke.getReceiver().getIndex() : null;
|
||||
part.input = receiver;
|
||||
part.program = nextProgram;
|
||||
int partId = parts.size();
|
||||
parts.add(part);
|
||||
|
@ -113,7 +121,6 @@ public class AsyncProgramSplitter {
|
|||
}
|
||||
step.targetPart = part;
|
||||
}
|
||||
}
|
||||
targetBlock.getInstructions().addAll(ProgramUtils.copyInstructions(sourceBlock,
|
||||
last, sourceBlock.getInstructions().size(), targetBlock.getProgram()));
|
||||
targetBlock.getTryCatchBlocks().addAll(ProgramUtils.copyTryCatches(sourceBlock, targetBlock.getProgram()));
|
||||
|
|
|
@ -313,12 +313,10 @@ public class MissingItemsProcessor {
|
|||
|
||||
@Override
|
||||
public void visit(MonitorEnterInstruction insn) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(MonitorExitInstruction insn) {
|
||||
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
|
@ -214,6 +214,6 @@ public class UsageExtractor implements InstructionVisitor {
|
|||
|
||||
@Override
|
||||
public void visit(MonitorExitInstruction insn) {
|
||||
usedVariables = new Variable[] {insn.getObjectRef()};
|
||||
usedVariables = new Variable[] {insn.getObjectRef() };
|
||||
}
|
||||
}
|
||||
|
|
|
@ -574,12 +574,10 @@ public class LoopInvariantMotion implements MethodOptimization {
|
|||
|
||||
@Override
|
||||
public void visit(MonitorEnterInstruction insn) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(MonitorExitInstruction insn) {
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -207,12 +207,12 @@ public final class VariableEscapeAnalyzer {
|
|||
|
||||
@Override
|
||||
public void visit(MonitorEnterInstruction insn) {
|
||||
|
||||
escaping[insn.getObjectRef().getIndex()] = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(MonitorExitInstruction insn) {
|
||||
|
||||
escaping[insn.getObjectRef().getIndex()] = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue
Block a user