Merge branch 'synchronized-methods'

This commit is contained in:
Alexey Andreev 2015-04-05 21:50:33 +03:00
commit a89a6b1748
6 changed files with 85 additions and 2 deletions

View File

@ -15,6 +15,7 @@
*/
package org.teavm.dependency;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
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) {

View File

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

View File

@ -725,18 +725,43 @@ public class Renderer implements ExprVisitor, StatementVisitor, RenderingContext
writer.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)")
.ws().append("{").ws();
writer.append("switch").ws().append("(").append(pointerName()).append(")").ws()
.append('{').softNewLine();
for (int i = 0; i < methodNode.getBody().size(); ++i) {
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);
part.getStatement().acceptVisitor(Renderer.this);
writer.outdent();
}
writer.append("default:").ws().appendFunction("$rt_invalidPointer").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("(");
for (int i = firstToSave; i < variableCount; ++i) {
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) {
LocationStackEntry prevEntry = locationStack.peek();
if (location != null) {

View File

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

View File

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

View File

@ -15,6 +15,8 @@
*/
package org.teavm.model.util;
import com.carrotsearch.hppc.IntOpenHashSet;
import com.carrotsearch.hppc.IntSet;
import java.util.ArrayDeque;
import java.util.BitSet;
import java.util.Deque;
@ -51,17 +53,21 @@ public class LivenessAnalyzer {
BasicBlock block = program.basicBlockAt(i);
for (Instruction insn : block.getInstructions()) {
insn.acceptVisitor(usageExtractor);
IntSet usedVars = new IntOpenHashSet();
for (Variable var : usageExtractor.getUsedVariables()) {
Task task = new Task();
task.block = i;
task.var = var.getIndex();
stack.push(task);
usedVars.add(var.getIndex());
}
insn.acceptVisitor(defExtractor);
for (Variable var : defExtractor.getDefinedVariables()) {
if (!usedVars.contains(var.getIndex())) {
definitions[var.getIndex()] = i;
}
}
}
for (TryCatchBlock tryCatch : block.getTryCatchBlocks()) {
if (tryCatch.getExceptionVariable() != null) {
definitions[tryCatch.getExceptionVariable().getIndex()] = i;