Fix monitorenter

This commit is contained in:
konsoletyper 2015-02-14 00:24:24 +04:00
parent f35f06097c
commit f93b35ce80
11 changed files with 349 additions and 147 deletions

View File

@ -15,6 +15,7 @@
*/ */
package org.teavm.classlib.java.lang; package org.teavm.classlib.java.lang;
import org.teavm.dom.browser.TimerHandler;
import org.teavm.dom.browser.Window; import org.teavm.dom.browser.Window;
import org.teavm.javascript.spi.Async; import org.teavm.javascript.spi.Async;
import org.teavm.javascript.spi.Rename; import org.teavm.javascript.spi.Rename;
@ -32,40 +33,50 @@ import org.teavm.platform.async.AsyncCallback;
@Superclass("") @Superclass("")
public class TObject { public class TObject {
private static final Window window = (Window)JS.getGlobal(); private static final Window window = (Window)JS.getGlobal();
private TThread owner;
private TObject monitorLock;
private int monitorCount;
private JSArray<NotifyListener> notifyListeners; 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 { interface NotifyListener extends JSObject {
void handleNotify(); boolean handleNotify();
} }
static void monitorEnter(TObject o){ static void monitorEnter(TObject o) {
if (o.monitorLock == null ){ if (o.lock == null) {
o.monitorLock = new TObject(); o.lock = new Lock();
return;
} }
while (o.owner != null && o.owner != TThread.currentThread()) { if (o.lock.owner != TThread.currentThread()) {
while (o.lock != null) {
try { try {
o.monitorLock.wait(); o.lock.wait();
} catch (InterruptedException ex) { } catch (InterruptedException ex) {
} }
} }
o.owner = TThread.currentThread(); o.lock = new Lock();
o.monitorCount++; } else {
o.lock.count++;
}
} }
static void monitorExit(TObject o){ static void monitorExit(TObject o){
o.monitorCount--; if (o.lock != null && o.lock.count-- == 0) {
if (o.monitorCount == 0 && o.monitorLock != null) { o.lock.notifyAll();
o.owner = null; o.lock = null;
o.monitorLock.notifyAll();
} }
} }
static boolean holdsLock(TObject o){ static boolean holdsLock(TObject o){
return o.owner == TThread.currentThread(); return o.lock != null && o.lock.owner == TThread.currentThread();
} }
@Rename("fakeInit") @Rename("fakeInit")
@ -114,11 +125,15 @@ public class TObject {
@Rename("notify") @Rename("notify")
public final void notify0(){ public final void notify0(){
if (notifyListeners != null && notifyListeners.getLength() > 0){ if (notifyListeners != null) {
notifyListeners.shift().handleNotify(); while (notifyListeners.getLength() > 0 && notifyListeners.shift().handleNotify()) {
// repeat loop
}
if (notifyListeners.getLength() == 0) {
notifyListeners = null;
}
} }
} }
@Rename("notifyAll") @Rename("notifyAll")
public final void notifyAll0(){ public final void notifyAll0(){
@ -127,6 +142,7 @@ public class TObject {
while (notifyListeners.getLength() > 0) { while (notifyListeners.getLength() > 0) {
listeners.push(notifyListeners.shift()); listeners.push(notifyListeners.shift());
} }
notifyListeners = null;
while (listeners.getLength() > 0) { while (listeners.getLength() > 0) {
listeners.shift().handleNotify(); listeners.shift().handleNotify();
} }
@ -144,7 +160,7 @@ public class TObject {
@Async @Async
@Rename("wait") @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") @Rename("wait")
public final void wait0(long timeout, int nanos, final AsyncCallback<Void> callback) { public final void wait0(long timeout, int nanos, final AsyncCallback<Void> callback) {
@ -152,24 +168,55 @@ public class TObject {
notifyListeners = window.newArray(); notifyListeners = window.newArray();
} }
final TThread currentThread = TThread.currentThread(); 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 @Override
public void handleNotify() { public boolean handleNotify() {
if (finished) {
return false;
}
TThread.setCurrentThread(currentThread); TThread.setCurrentThread(currentThread);
if (timerId >= 0) {
window.clearTimeout(timerId);
timerId = -1;
}
finished = true;
try { try {
callback.complete(null); callback.complete(null);
} finally { } finally {
TThread.setCurrentThread(TThread.getMainThread()); TThread.setCurrentThread(TThread.getMainThread());
} }
return true;
}
@Override
public void onTimer() {
handleNotify();
} }
});
} }
@Rename("wait") @Rename("wait")
public final void wait0() throws TInterruptedException { public final void wait0() throws TInterruptedException {
try { try {
wait(0l); wait(0l);
} catch ( InterruptedException ex){ } catch (InterruptedException ex) {
throw new TInterruptedException(); throw new TInterruptedException();
} }
} }

View File

@ -73,22 +73,21 @@ public class Renderer implements ExprVisitor, StatementVisitor, RenderingContext
@Override @Override
public void visit(MonitorEnterStatement statement) { public void visit(MonitorEnterStatement statement) {
if (async){
try { try {
MethodReference monitorEnterRef = new MethodReference( MethodReference monitorEnterRef = new MethodReference(
Object.class, "monitorEnter", Object.class, void.class); Object.class, "monitorEnter", Object.class, void.class);
writer.appendMethodBody(monitorEnterRef).append("("); writer.appendMethodBody(monitorEnterRef).append("(");
statement.getObjectRef().acceptVisitor(this); statement.getObjectRef().acceptVisitor(this);
writer.append(",").ws();
writer.append("$rt_continue($part_").append(statement.getAsyncTarget()).append(')');
writer.append(");").softNewLine(); writer.append(");").softNewLine();
} catch (IOException ex){ } catch (IOException ex){
throw new RenderingException("IO error occured", ex); throw new RenderingException("IO error occured", ex);
} }
} }
}
@Override @Override
public void visit(MonitorExitStatement statement) { public void visit(MonitorExitStatement statement) {
if (async){
try { try {
MethodReference monitorExitRef = new MethodReference( MethodReference monitorExitRef = new MethodReference(
Object.class, "monitorExit", Object.class, void.class); 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); throw new RenderingException("IO error occured", ex);
} }
} }
}
private static class InjectorHolder { private static class InjectorHolder {
public final Injector injector; public final Injector injector;
@ -938,7 +936,7 @@ public class Renderer implements ExprVisitor, StatementVisitor, RenderingContext
StringBuilder sb = new StringBuilder(); StringBuilder sb = new StringBuilder();
int index = blockIdMap.size(); int index = blockIdMap.size();
do { do {
sb.append(variablePartNames.charAt(index % variableNames.length())); sb.append(variablePartNames.charAt(index % variablePartNames.length()));
index /= variablePartNames.length(); index /= variablePartNames.length();
} while (index > 0); } while (index > 0);
name = "$b" + sb; name = "$b" + sb;

View File

@ -669,11 +669,10 @@ class StatementGenerator implements InstructionVisitor {
@Override @Override
public void visit(MonitorEnterInstruction insn) { public void visit(MonitorEnterInstruction insn) {
MonitorEnterStatement stmt = new MonitorEnterStatement(); MonitorEnterStatement stmt = new MonitorEnterStatement();
stmt.setLocation(currentLocation); stmt.setLocation(currentLocation);
stmt.setObjectRef(Expr.var(insn.getObjectRef().getIndex())); stmt.setObjectRef(Expr.var(insn.getObjectRef().getIndex()));
stmt.setAsyncTarget(asyncTarget);
statements.add(stmt); statements.add(stmt);
} }
@ -681,7 +680,6 @@ class StatementGenerator implements InstructionVisitor {
public void visit(MonitorExitInstruction insn) { public void visit(MonitorExitInstruction insn) {
MonitorExitStatement stmt = new MonitorExitStatement(); MonitorExitStatement stmt = new MonitorExitStatement();
stmt.setLocation(currentLocation); stmt.setLocation(currentLocation);
stmt.setObjectRef(Expr.var(insn.getObjectRef().getIndex())); stmt.setObjectRef(Expr.var(insn.getObjectRef().getIndex()));
statements.add(stmt); statements.add(stmt);
} }

View File

@ -20,41 +20,36 @@ package org.teavm.javascript.ast;
* @author shannah * @author shannah
*/ */
public class MonitorEnterStatement extends Statement { public class MonitorEnterStatement extends Statement {
private NodeLocation location; private NodeLocation location;
private Expr objectRef; private Expr objectRef;
private Integer asyncTarget;
@Override @Override
public void acceptVisitor(StatementVisitor visitor) { public void acceptVisitor(StatementVisitor visitor) {
visitor.visit(this); visitor.visit(this);
} }
/**
* @return the location
*/
public NodeLocation getLocation() { public NodeLocation getLocation() {
return location; return location;
} }
/**
* @param location the location to set
*/
public void setLocation(NodeLocation location) { public void setLocation(NodeLocation location) {
this.location = location; this.location = location;
} }
/**
* @return the objectRef
*/
public Expr getObjectRef() { public Expr getObjectRef() {
return objectRef; return objectRef;
} }
/**
* @param objectRef the objectRef to set
*/
public void setObjectRef(Expr objectRef) { public void setObjectRef(Expr objectRef) {
this.objectRef = objectRef; this.objectRef = objectRef;
} }
public Integer getAsyncTarget() {
return asyncTarget;
}
public void setAsyncTarget(Integer asyncTarget) {
this.asyncTarget = asyncTarget;
}
} }

View File

@ -20,41 +20,28 @@ package org.teavm.javascript.ast;
* @author shannah * @author shannah
*/ */
public class MonitorExitStatement extends Statement { public class MonitorExitStatement extends Statement {
private NodeLocation location; private NodeLocation location;
private Expr objectRef; private Expr objectRef;
private Integer asyncTarget;
@Override @Override
public void acceptVisitor(StatementVisitor visitor) { public void acceptVisitor(StatementVisitor visitor) {
visitor.visit(this); visitor.visit(this);
} }
/**
* @return the location
*/
public NodeLocation getLocation() { public NodeLocation getLocation() {
return location; return location;
} }
/**
* @param location the location to set
*/
public void setLocation(NodeLocation location) { public void setLocation(NodeLocation location) {
this.location = location; this.location = location;
} }
/**
* @return the objectRef
*/
public Expr getObjectRef() { public Expr getObjectRef() {
return objectRef; return objectRef;
} }
/**
* @param objectRef the objectRef to set
*/
public void setObjectRef(Expr objectRef) { public void setObjectRef(Expr objectRef) {
this.objectRef = objectRef; this.objectRef = objectRef;
} }
} }

View File

@ -24,6 +24,7 @@ import org.teavm.javascript.spi.Async;
import org.teavm.javascript.spi.InjectedBy; import org.teavm.javascript.spi.InjectedBy;
import org.teavm.javascript.spi.Sync; import org.teavm.javascript.spi.Sync;
import org.teavm.model.*; import org.teavm.model.*;
import org.teavm.model.instructions.*;
/** /**
* *
@ -61,6 +62,17 @@ public class AsyncMethodFinder {
} }
if (method.getAnnotations().get(Async.class.getName()) != null) { if (method.getAnnotations().get(Async.class.getName()) != null) {
add(method.getReference()); 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) {
}
}
} }

View File

@ -19,6 +19,7 @@ import java.util.*;
import org.teavm.model.*; import org.teavm.model.*;
import org.teavm.model.instructions.InvokeInstruction; import org.teavm.model.instructions.InvokeInstruction;
import org.teavm.model.instructions.JumpInstruction; import org.teavm.model.instructions.JumpInstruction;
import org.teavm.model.instructions.MonitorEnterInstruction;
/** /**
* *
@ -58,14 +59,21 @@ public class AsyncProgramSplitter {
int last = 0; int last = 0;
for (int i = 0; i < sourceBlock.getInstructions().size(); ++i) { for (int i = 0; i < sourceBlock.getInstructions().size(); ++i) {
Instruction insn = sourceBlock.getInstructions().get(i); Instruction insn = sourceBlock.getInstructions().get(i);
Integer receiver;
if (insn instanceof InvokeInstruction) { if (insn instanceof InvokeInstruction) {
InvokeInstruction invoke = (InvokeInstruction)insn; InvokeInstruction invoke = (InvokeInstruction)insn;
if (!asyncMethods.contains(invoke.getMethod())) { if (!asyncMethods.contains(invoke.getMethod())) {
continue; continue;
} }
receiver = invoke.getReceiver() != null ? invoke.getReceiver().getIndex() : null;
} else if (insn instanceof MonitorEnterInstruction) {
receiver = null;
} else {
continue;
}
// If we met asynchronous invocation... // 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, targetBlock.getInstructions().addAll(ProgramUtils.copyInstructions(sourceBlock,
last, i + 1, targetBlock.getProgram())); last, i + 1, targetBlock.getProgram()));
targetBlock.getTryCatchBlocks().addAll(ProgramUtils.copyTryCatches(sourceBlock, targetBlock.getTryCatchBlocks().addAll(ProgramUtils.copyTryCatches(sourceBlock,
@ -91,7 +99,7 @@ public class AsyncProgramSplitter {
// Create a new part // Create a new part
Program nextProgram = createStubCopy(program); Program nextProgram = createStubCopy(program);
Part part = new Part(); Part part = new Part();
part.input = invoke.getReceiver() != null ? invoke.getReceiver().getIndex() : null; part.input = receiver;
part.program = nextProgram; part.program = nextProgram;
int partId = parts.size(); int partId = parts.size();
parts.add(part); parts.add(part);
@ -113,7 +121,6 @@ public class AsyncProgramSplitter {
} }
step.targetPart = part; step.targetPart = part;
} }
}
targetBlock.getInstructions().addAll(ProgramUtils.copyInstructions(sourceBlock, targetBlock.getInstructions().addAll(ProgramUtils.copyInstructions(sourceBlock,
last, sourceBlock.getInstructions().size(), targetBlock.getProgram())); last, sourceBlock.getInstructions().size(), targetBlock.getProgram()));
targetBlock.getTryCatchBlocks().addAll(ProgramUtils.copyTryCatches(sourceBlock, targetBlock.getProgram())); targetBlock.getTryCatchBlocks().addAll(ProgramUtils.copyTryCatches(sourceBlock, targetBlock.getProgram()));

View File

@ -313,12 +313,10 @@ public class MissingItemsProcessor {
@Override @Override
public void visit(MonitorEnterInstruction insn) { public void visit(MonitorEnterInstruction insn) {
} }
@Override @Override
public void visit(MonitorExitInstruction insn) { public void visit(MonitorExitInstruction insn) {
} }
}; };
} }

View File

@ -214,6 +214,6 @@ public class UsageExtractor implements InstructionVisitor {
@Override @Override
public void visit(MonitorExitInstruction insn) { public void visit(MonitorExitInstruction insn) {
usedVariables = new Variable[] {insn.getObjectRef()}; usedVariables = new Variable[] {insn.getObjectRef() };
} }
} }

View File

@ -574,12 +574,10 @@ public class LoopInvariantMotion implements MethodOptimization {
@Override @Override
public void visit(MonitorEnterInstruction insn) { public void visit(MonitorEnterInstruction insn) {
} }
@Override @Override
public void visit(MonitorExitInstruction insn) { public void visit(MonitorExitInstruction insn) {
} }
} }
} }

View File

@ -207,12 +207,12 @@ public final class VariableEscapeAnalyzer {
@Override @Override
public void visit(MonitorEnterInstruction insn) { public void visit(MonitorEnterInstruction insn) {
escaping[insn.getObjectRef().getIndex()] = true;
} }
@Override @Override
public void visit(MonitorExitInstruction insn) { public void visit(MonitorExitInstruction insn) {
escaping[insn.getObjectRef().getIndex()] = true;
} }
} }
} }