diff --git a/teavm-core/src/main/java/org/teavm/dependency/DependencyGraphBuilder.java b/teavm-core/src/main/java/org/teavm/dependency/DependencyGraphBuilder.java index 02ce79b18..4acacd28c 100644 --- a/teavm-core/src/main/java/org/teavm/dependency/DependencyGraphBuilder.java +++ b/teavm-core/src/main/java/org/teavm/dependency/DependencyGraphBuilder.java @@ -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 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) { diff --git a/teavm-core/src/main/java/org/teavm/javascript/Decompiler.java b/teavm-core/src/main/java/org/teavm/javascript/Decompiler.java index 71349ba54..b0e285331 100644 --- a/teavm-core/src/main/java/org/teavm/javascript/Decompiler.java +++ b/teavm-core/src/main/java/org/teavm/javascript/Decompiler.java @@ -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; } diff --git a/teavm-core/src/main/java/org/teavm/javascript/Renderer.java b/teavm-core/src/main/java/org/teavm/javascript/Renderer.java index e9f5544a4..cd89dc1d6 100644 --- a/teavm-core/src/main/java/org/teavm/javascript/Renderer.java +++ b/teavm-core/src/main/java/org/teavm/javascript/Renderer.java @@ -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) { diff --git a/teavm-core/src/main/java/org/teavm/javascript/ast/NodeModifier.java b/teavm-core/src/main/java/org/teavm/javascript/ast/NodeModifier.java index 724b060c0..70312473c 100644 --- a/teavm-core/src/main/java/org/teavm/javascript/ast/NodeModifier.java +++ b/teavm-core/src/main/java/org/teavm/javascript/ast/NodeModifier.java @@ -22,5 +22,6 @@ package org.teavm.javascript.ast; public enum NodeModifier { STATIC, INTERFACE, - ENUM + ENUM, + SYNCHRONIZED } diff --git a/teavm-core/src/main/java/org/teavm/model/util/AsyncMethodFinder.java b/teavm-core/src/main/java/org/teavm/model/util/AsyncMethodFinder.java index d17297756..da24ecbb8 100644 --- a/teavm-core/src/main/java/org/teavm/model/util/AsyncMethodFinder.java +++ b/teavm-core/src/main/java/org/teavm/model/util/AsyncMethodFinder.java @@ -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) { diff --git a/teavm-core/src/main/java/org/teavm/model/util/LivenessAnalyzer.java b/teavm-core/src/main/java/org/teavm/model/util/LivenessAnalyzer.java index cfb3ca677..665ff717d 100644 --- a/teavm-core/src/main/java/org/teavm/model/util/LivenessAnalyzer.java +++ b/teavm-core/src/main/java/org/teavm/model/util/LivenessAnalyzer.java @@ -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,15 +53,19 @@ 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()) { - definitions[var.getIndex()] = i; + if (!usedVars.contains(var.getIndex())) { + definitions[var.getIndex()] = i; + } } } for (TryCatchBlock tryCatch : block.getTryCatchBlocks()) {