Partial support of synchronized methods

This commit is contained in:
Alexey Andreev 2015-03-29 19:17:55 +03:00
parent a4cb94df2f
commit 98247b9927
5 changed files with 78 additions and 1 deletions

View File

@ -15,6 +15,7 @@
*/ */
package org.teavm.dependency; package org.teavm.dependency;
import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.HashSet; import java.util.HashSet;
import java.util.List; import java.util.List;
@ -109,6 +110,40 @@ class DependencyGraphBuilder {
} }
} }
} }
if (method.hasModifier(ElementModifier.SYNCHRONIZED)) {
List<DependencyNode> syncNodes = new ArrayList<>();
MethodDependency methodDep = dependencyChecker.linkMethod(
new MethodReference(Object.class, "monitorEnter", Object.class, void.class), null);
syncNodes.add(methodDep.getVariable(1));
methodDep.use();
methodDep = dependencyChecker.linkMethod(
new MethodReference(Object.class, "monitorEnterSync", Object.class, void.class), null);
syncNodes.add(methodDep.getVariable(1));
methodDep.use();
methodDep = dependencyChecker.linkMethod(
new MethodReference(Object.class, "monitorExit", Object.class, void.class), null);
syncNodes.add(methodDep.getVariable(1));
methodDep.use();
methodDep = dependencyChecker.linkMethod(
new MethodReference(Object.class, "monitorExitSync", Object.class, void.class), null);
syncNodes.add(methodDep.getVariable(1));
methodDep.use();
if (method.hasModifier(ElementModifier.STATIC)) {
for (DependencyNode node : syncNodes) {
node.propagate(dependencyChecker.getType("java.lang.Class"));
}
} else {
for (DependencyNode node : syncNodes) {
nodes[0].connect(node);
}
}
}
} }
private ExceptionConsumer createExceptionConsumer(MethodDependency methodDep, BasicBlockReader block) { private ExceptionConsumer createExceptionConsumer(MethodDependency methodDep, BasicBlockReader block) {

View File

@ -383,6 +383,9 @@ public class Decompiler {
if (modifiers.contains(ElementModifier.ENUM)) { if (modifiers.contains(ElementModifier.ENUM)) {
result.add(NodeModifier.ENUM); result.add(NodeModifier.ENUM);
} }
if (modifiers.contains(ElementModifier.SYNCHRONIZED)) {
result.add(NodeModifier.SYNCHRONIZED);
}
return result; return result;
} }

View File

@ -725,18 +725,43 @@ public class Renderer implements ExprVisitor, StatementVisitor, RenderingContext
writer.softNewLine(); writer.softNewLine();
writer.outdent().append("}").softNewLine(); writer.outdent().append("}").softNewLine();
if (methodNode.getModifiers().contains(NodeModifier.SYNCHRONIZED)) {
writer.append("try").ws().append('{').indent().softNewLine();
}
writer.append(mainLoopName()).append(":").ws().append("while").ws().append("(true)") writer.append(mainLoopName()).append(":").ws().append("while").ws().append("(true)")
.ws().append("{").ws(); .ws().append("{").ws();
writer.append("switch").ws().append("(").append(pointerName()).append(")").ws() writer.append("switch").ws().append("(").append(pointerName()).append(")").ws()
.append('{').softNewLine(); .append('{').softNewLine();
for (int i = 0; i < methodNode.getBody().size(); ++i) { for (int i = 0; i < methodNode.getBody().size(); ++i) {
writer.append("case ").append(i).append(":").indent().softNewLine(); writer.append("case ").append(i).append(":").indent().softNewLine();
if (i == 0 && methodNode.getModifiers().contains(NodeModifier.SYNCHRONIZED)) {
writer.appendMethodBody(new MethodReference(Object.class, "monitorEnter",
Object.class, void.class));
writer.append("(");
appendMonitor(methodNode);
writer.append(");").softNewLine();
emitSuspendChecker();
}
AsyncMethodPart part = methodNode.getBody().get(i); AsyncMethodPart part = methodNode.getBody().get(i);
part.getStatement().acceptVisitor(Renderer.this); part.getStatement().acceptVisitor(Renderer.this);
writer.outdent(); writer.outdent();
} }
writer.append("default:").ws().appendFunction("$rt_invalidPointer").append("();").softNewLine(); writer.append("default:").ws().appendFunction("$rt_invalidPointer").append("();").softNewLine();
writer.append("}}").softNewLine(); writer.append("}}").softNewLine();
if (methodNode.getModifiers().contains(NodeModifier.SYNCHRONIZED)) {
writer.outdent().append("}").ws().append("finally").ws().append('{').indent().softNewLine();
writer.append("if").ws().append("(!").appendFunction("$rt_suspending").append("())")
.ws().append("{").indent().softNewLine();
writer.appendMethodBody(new MethodReference(Object.class, "monitorExit",
Object.class, void.class));
writer.append("(");
appendMonitor(methodNode);
writer.append(");").softNewLine();
writer.outdent().append('}').softNewLine();
writer.outdent().append('}').softNewLine();
}
writer.appendFunction("$rt_nativeThread").append("().").append(pushName).append("("); writer.appendFunction("$rt_nativeThread").append("().").append(pushName).append("(");
for (int i = firstToSave; i < variableCount; ++i) { for (int i = firstToSave; i < variableCount; ++i) {
writer.append(variableName(i)).append(',').ws(); writer.append(variableName(i)).append(',').ws();
@ -794,6 +819,15 @@ public class Renderer implements ExprVisitor, StatementVisitor, RenderingContext
} }
} }
private void appendMonitor(MethodNode methodNode) throws IOException {
if (methodNode.getModifiers().contains(NodeModifier.STATIC)) {
writer.appendFunction("$rt_cls").append("(")
.appendClass(methodNode.getReference().getClassName()).append(")");
} else {
writer.append(variableName(0));
}
}
private void pushLocation(NodeLocation location) { private void pushLocation(NodeLocation location) {
LocationStackEntry prevEntry = locationStack.peek(); LocationStackEntry prevEntry = locationStack.peek();
if (location != null) { if (location != null) {

View File

@ -22,5 +22,6 @@ package org.teavm.javascript.ast;
public enum NodeModifier { public enum NodeModifier {
STATIC, STATIC,
INTERFACE, INTERFACE,
ENUM ENUM,
SYNCHRONIZED
} }

View File

@ -72,6 +72,10 @@ public class AsyncMethodFinder {
if (asyncMethods.contains(method.getReference()) || method.getProgram() == null) { if (asyncMethods.contains(method.getReference()) || method.getProgram() == null) {
continue; continue;
} }
if (method.hasModifier(ElementModifier.SYNCHRONIZED)) {
add(method.getReference());
continue;
}
ProgramReader program = method.getProgram(); ProgramReader program = method.getProgram();
AsyncInstructionReader insnReader = new AsyncInstructionReader(); AsyncInstructionReader insnReader = new AsyncInstructionReader();
for (int i = 0; i < program.basicBlockCount(); ++i) { for (int i = 0; i < program.basicBlockCount(); ++i) {