Fix support of async <clinit> when called by getstatic/putstatic

This commit is contained in:
Alexey Andreev 2016-11-20 17:50:47 +03:00
parent c023ac2053
commit 24efd1f49c
5 changed files with 61 additions and 26 deletions

View File

@ -20,6 +20,7 @@ import org.teavm.model.TextLocation;
public class InitClassStatement extends Statement {
private TextLocation location;
private String className;
private boolean async;
public String getClassName() {
return className;
@ -37,6 +38,14 @@ public class InitClassStatement extends Statement {
this.location = location;
}
public boolean isAsync() {
return async;
}
public void setAsync(boolean async) {
this.async = async;
}
@Override
public void acceptVisitor(StatementVisitor visitor) {
visitor.visit(this);

View File

@ -328,11 +328,7 @@ class StatementGenerator implements InstructionVisitor {
Map<Integer, List<Integer>> switchMap = new HashMap<>();
for (int i = 0; i < insn.getEntries().size(); ++i) {
SwitchTableEntry entry = insn.getEntries().get(i);
List<Integer> conditions = switchMap.get(entry.getTarget().getIndex());
if (conditions == null) {
conditions = new ArrayList<>();
switchMap.put(entry.getTarget().getIndex(), conditions);
}
List<Integer> conditions = switchMap.computeIfAbsent(entry.getTarget().getIndex(), k -> new ArrayList<>());
conditions.add(entry.getCondition());
}
List<Integer> targets = new ArrayList<>(switchMap.keySet());
@ -590,6 +586,8 @@ class StatementGenerator implements InstructionVisitor {
public void visit(InitClassInstruction insn) {
InitClassStatement stmt = Statement.initClass(insn.getClassName());
stmt.setLocation(currentLocation);
stmt.setAsync(async);
async = false;
statements.add(stmt);
}

View File

@ -121,18 +121,10 @@ public class StatementRenderer implements ExprVisitor, StatementVisitor {
this.async = async;
}
public MethodNode getCurrentMethod() {
return currentMethod;
}
public void setCurrentMethod(MethodNode currentMethod) {
this.currentMethod = currentMethod;
}
public int getCurrentPart() {
return currentPart;
}
public void setCurrentPart(int currentPart) {
this.currentPart = currentPart;
}
@ -433,6 +425,9 @@ public class StatementRenderer implements ExprVisitor, StatementVisitor {
pushLocation(statement.getLocation());
}
writer.appendClass(statement.getClassName()).append("_$callClinit();").softNewLine();
if (statement.isAsync()) {
emitSuspendChecker();
}
if (statement.getLocation() != null) {
popLocation();
}

View File

@ -15,17 +15,35 @@
*/
package org.teavm.model.util;
import java.util.*;
import org.teavm.common.*;
import org.teavm.model.*;
import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Queue;
import java.util.Set;
import org.teavm.common.Graph;
import org.teavm.common.GraphSplittingBackend;
import org.teavm.common.GraphUtils;
import org.teavm.common.IntegerArray;
import org.teavm.model.BasicBlock;
import org.teavm.model.ClassReader;
import org.teavm.model.ClassReaderSource;
import org.teavm.model.Instruction;
import org.teavm.model.MethodDescriptor;
import org.teavm.model.MethodReader;
import org.teavm.model.MethodReference;
import org.teavm.model.Program;
import org.teavm.model.TryCatchBlock;
import org.teavm.model.ValueType;
import org.teavm.model.Variable;
import org.teavm.model.instructions.InitClassInstruction;
import org.teavm.model.instructions.InvokeInstruction;
import org.teavm.model.instructions.JumpInstruction;
import org.teavm.model.instructions.MonitorEnterInstruction;
/**
*
* @author Alexey Andreev
*/
public class AsyncProgramSplitter {
private List<Part> parts = new ArrayList<>();
private Map<Long, Integer> partMap = new HashMap<>();
@ -68,6 +86,10 @@ public class AsyncProgramSplitter {
if (!asyncMethods.contains(findRealMethod(invoke.getMethod()))) {
continue;
}
} else if (insn instanceof InitClassInstruction) {
if (!isSplittingClassInitializer(((InitClassInstruction) insn).getClassName())) {
continue;
}
} else if (!(insn instanceof MonitorEnterInstruction)) {
continue;
}
@ -164,6 +186,16 @@ public class AsyncProgramSplitter {
partMap.clear();
}
private boolean isSplittingClassInitializer(String className) {
ClassReader cls = classSource.get(className);
if (cls == null) {
return false;
}
MethodReader method = cls.getMethod(new MethodDescriptor("<clinit>", ValueType.VOID));
return method != null && asyncMethods.contains(method.getReference());
}
private MethodReference findRealMethod(MethodReference method) {
String clsName = method.getClassName();
while (clsName != null) {
@ -215,10 +247,6 @@ public class AsyncProgramSplitter {
return Arrays.copyOf(result, result.length);
}
public int getBlockSuccessor(int index, int blockIndex) {
return parts.get(index).blockSuccessors[blockIndex];
}
public int[] getSplitPoints(int index) {
return parts.get(index).splitPoints.clone();
}

View File

@ -121,10 +121,15 @@ public class VMTest {
assertEquals(0, initCount);
assertEquals("foo", AsyncClinitClass.foo());
assertEquals(1, initCount);
assertEquals(AsyncClinitClass.state, "ok");
assertEquals("ok", AsyncClinitClass.state);
assertEquals("bar", AsyncClinitClass.bar());
assertEquals(1, initCount);
assertEquals(AsyncClinitClass.state, "ok");
assertEquals("ok", AsyncClinitClass.state);
}
@Test
public void asyncClinitField() {
assertEquals("ok", AsyncClinitClass.state);
}
static int initCount = 0;