C backend: make more tests pass

This commit is contained in:
Alexey Andreev 2018-04-27 00:47:38 +03:00
parent fa07100024
commit 18eb3ee058
14 changed files with 99 additions and 21 deletions

View File

@ -41,6 +41,7 @@ import org.teavm.classlib.java.lang.reflect.TModifier;
import org.teavm.dependency.PluggableDependency;
import org.teavm.interop.Address;
import org.teavm.interop.DelegateTo;
import org.teavm.interop.Unmanaged;
import org.teavm.jso.core.JSArray;
import org.teavm.platform.Platform;
import org.teavm.platform.PlatformClass;
@ -82,14 +83,26 @@ public class TClass<T> extends TObject implements TAnnotatedElement {
return platformClass;
}
@DelegateTo("isInstanceLowLevel")
public boolean isInstance(TObject obj) {
return Platform.isInstance(Platform.getPlatformObject(obj), platformClass);
}
@Unmanaged
private boolean isInstanceLowLevel(RuntimeObject obj) {
return obj != null && isAssignableFromLowLevel(RuntimeClass.getClass(obj));
}
@DelegateTo("isAssignableFromLowLevel")
public boolean isAssignableFrom(TClass<?> obj) {
return Platform.isAssignable(obj.getPlatformClass(), platformClass);
}
@Unmanaged
private boolean isAssignableFromLowLevel(RuntimeClass other) {
return Address.ofObject(this).<RuntimeClass>toStructure().isSupertypeOf.apply(other);
}
@DelegateTo("getNameLowLevel")
public TString getName() {
if (name == null) {
@ -98,6 +111,7 @@ public class TClass<T> extends TObject implements TAnnotatedElement {
return name;
}
@Unmanaged
private RuntimeObject getNameLowLevel() {
RuntimeClass runtimeClass = Address.ofObject(this).toStructure();
return runtimeClass.name;

View File

@ -22,6 +22,7 @@ import org.teavm.ast.RegularMethodNode;
import org.teavm.common.Graph;
import org.teavm.model.BasicBlock;
import org.teavm.model.Instruction;
import org.teavm.model.MethodReference;
import org.teavm.model.Program;
import org.teavm.model.Variable;
import org.teavm.model.util.AsyncProgramSplitter;
@ -40,6 +41,8 @@ public class Optimizer {
public void optimize(RegularMethodNode method, Program program, boolean friendlyToDebugger) {
ReadWriteStatsBuilder stats = new ReadWriteStatsBuilder(method.getVariables().size());
stats.analyze(program);
applyParametersToWriteStats(stats, method.getReference());
boolean[] preservedVars = new boolean[stats.writes.length];
BreakEliminator breakEliminator = new BreakEliminator();
breakEliminator.eliminate(method.getBody());
@ -72,6 +75,7 @@ public class Optimizer {
boolean[] preservedVars = new boolean[method.getVariables().size()];
ReadWriteStatsBuilder stats = new ReadWriteStatsBuilder(method.getVariables().size());
stats.analyze(splitter.getProgram(i));
applyParametersToWriteStats(stats, method.getReference());
AsyncMethodPart part = method.getBody().get(i);
BreakEliminator breakEliminator = new BreakEliminator();
@ -101,6 +105,12 @@ public class Optimizer {
}
}
private void applyParametersToWriteStats(ReadWriteStatsBuilder stats, MethodReference method) {
for (int i = 0; i <= method.parameterCount(); ++i) {
stats.writes[i]++;
}
}
private void findEscapingLiveVars(LivenessAnalyzer liveness, Graph cfg, AsyncProgramSplitter splitter,
int partIndex, boolean[] output) {
Program originalProgram = splitter.getOriginalProgram();

View File

@ -68,6 +68,7 @@ class OptimizingVisitor implements StatementVisitor, ExprVisitor {
Statement resultStmt;
private final boolean[] preservedVars;
private final int[] writeFrequencies;
private final int[] initialWriteFrequences;
private final int[] readFrequencies;
private final Object[] constants;
private List<Statement> resultSequence;
@ -80,6 +81,7 @@ class OptimizingVisitor implements StatementVisitor, ExprVisitor {
boolean friendlyToDebugger) {
this.preservedVars = preservedVars;
this.writeFrequencies = writeFrequencies;
this.initialWriteFrequences = writeFrequencies.clone();
this.readFrequencies = readFrequencies;
this.constants = constants;
this.friendlyToDebugger = friendlyToDebugger;
@ -276,7 +278,7 @@ class OptimizingVisitor implements StatementVisitor, ExprVisitor {
return;
}
if (constants[index] != null) {
if (!preservedVars[index] && initialWriteFrequences[index] == 1 && constants[index] != null) {
ConstantExpr constantExpr = new ConstantExpr();
constantExpr.setValue(constants[index]);
constantExpr.setLocation(expr.getLocation());
@ -555,7 +557,8 @@ class OptimizingVisitor implements StatementVisitor, ExprVisitor {
left = resultExpr;
} else {
int varIndex = ((VariableExpr) statement.getLeftValue()).getIndex();
if (writeFrequencies[varIndex] == 1 && constants[varIndex] != null) {
if (!preservedVars[varIndex] && initialWriteFrequences[varIndex] == 1
&& constants[varIndex] != null) {
resultStmt = new SequentialStatement();
return;
}

View File

@ -422,4 +422,9 @@ public class CTarget implements TeaVMTarget {
public String[] getPlatformTags() {
return new String[] { PlatformMarkers.C, PlatformMarkers.LOW_LEVEL };
}
@Override
public boolean isAsyncSupported() {
return false;
}
}

View File

@ -71,6 +71,12 @@ public class StringPoolGenerator {
for (int j = 0; j < string.length(); ++j) {
char c = string.charAt(j);
switch (c) {
case '\\':
writer.print("\\\\");
break;
case '"':
writer.print("\\\"");
break;
case '\r':
writer.print("\\r");
break;
@ -81,7 +87,9 @@ public class StringPoolGenerator {
writer.print("\\t");
break;
default:
if (c < 32 || c > 127) {
if (c < 32) {
writer.print("\\x" + Character.forDigit(c >> 4, 16) + Character.forDigit(c & 0xF, 16));
} else if (c > 127) {
writer.print("\\u"
+ Character.forDigit(c >> 12, 16)
+ Character.forDigit((c >> 8) & 15, 16)

View File

@ -30,6 +30,7 @@ public class PlatformIntrinsic implements Intrinsic {
switch (method.getName()) {
case "getPlatformObject":
case "asJavaClass":
case "createQueue":
return true;
}
return false;
@ -42,6 +43,9 @@ public class PlatformIntrinsic implements Intrinsic {
case "asJavaClass":
context.emit(invocation.getArguments().get(0));
break;
case "createQueue":
context.writer().print("NULL");
break;
}
}
}

View File

@ -458,4 +458,9 @@ public class JavaScriptTarget implements TeaVMTarget, TeaVMJavaScriptHost {
public String[] getPlatformTags() {
return new String[] { PlatformMarkers.JAVASCRIPT };
}
@Override
public boolean isAsyncSupported() {
return true;
}
}

View File

@ -749,4 +749,9 @@ public class WasmTarget implements TeaVMTarget, TeaVMWasmHost {
public String[] getPlatformTags() {
return new String[] { PlatformMarkers.WEBASSEMBLY, PlatformMarkers.LOW_LEVEL };
}
@Override
public boolean isAsyncSupported() {
return false;
}
}

View File

@ -87,6 +87,7 @@ public class DependencyAnalyzer implements DependencyInfo {
Map<MethodReference, DependencyPlugin> dependencyPlugins = new HashMap<>();
private boolean completing;
private Map<String, SuperClassFilter> superClassFilters = new HashMap<>();
boolean asyncSupported;
public DependencyAnalyzer(ClassReaderSource classSource, ClassLoader classLoader, ServiceRepository services,
Diagnostics diagnostics) {
@ -116,6 +117,10 @@ public class DependencyAnalyzer implements DependencyInfo {
agent = new DependencyAgent(this);
}
public void setAsyncSupported(boolean asyncSupported) {
this.asyncSupported = asyncSupported;
}
public DependencyAgent getAgent() {
return agent;
}

View File

@ -148,20 +148,25 @@ class DependencyGraphBuilder {
if (method.hasModifier(ElementModifier.SYNCHRONIZED)) {
List<DependencyNode> syncNodes = new ArrayList<>();
MethodDependency methodDep = dependencyAnalyzer.linkMethod(
MethodDependency methodDep;
if (dependencyAnalyzer.asyncSupported) {
methodDep = dependencyAnalyzer.linkMethod(
new MethodReference(Object.class, "monitorEnter", Object.class, void.class), null);
syncNodes.add(methodDep.getVariable(1));
methodDep.use();
syncNodes.add(methodDep.getVariable(1));
methodDep.use();
}
methodDep = dependencyAnalyzer.linkMethod(
new MethodReference(Object.class, "monitorEnterSync", Object.class, void.class), null);
syncNodes.add(methodDep.getVariable(1));
methodDep.use();
methodDep = dependencyAnalyzer.linkMethod(
new MethodReference(Object.class, "monitorExit", Object.class, void.class), null);
syncNodes.add(methodDep.getVariable(1));
methodDep.use();
if (dependencyAnalyzer.asyncSupported) {
methodDep = dependencyAnalyzer.linkMethod(
new MethodReference(Object.class, "monitorExit", Object.class, void.class), null);
syncNodes.add(methodDep.getVariable(1));
methodDep.use();
}
methodDep = dependencyAnalyzer.linkMethod(
new MethodReference(Object.class, "monitorExitSync", Object.class, void.class), null);
@ -696,25 +701,29 @@ class DependencyGraphBuilder {
@Override
public void monitorEnter(VariableReader objectRef) {
MethodDependency methodDep = dependencyAnalyzer.linkMethod(
if (dependencyAnalyzer.asyncSupported) {
MethodDependency methodDep = dependencyAnalyzer.linkMethod(
new MethodReference(Object.class, "monitorEnter", Object.class, void.class), null);
nodes[objectRef.getIndex()].connect(methodDep.getVariable(1));
methodDep.use();
nodes[objectRef.getIndex()].connect(methodDep.getVariable(1));
methodDep.use();
}
methodDep = dependencyAnalyzer.linkMethod(
MethodDependency methodDep = dependencyAnalyzer.linkMethod(
new MethodReference(Object.class, "monitorEnterSync", Object.class, void.class), null);
nodes[objectRef.getIndex()].connect(methodDep.getVariable(1));
methodDep.use();
nodes[objectRef.getIndex()].connect(methodDep.getVariable(1));
methodDep.use();
}
@Override
public void monitorExit(VariableReader objectRef) {
MethodDependency methodDep = dependencyAnalyzer.linkMethod(
new MethodReference(Object.class, "monitorExit", Object.class, void.class), null);
nodes[objectRef.getIndex()].connect(methodDep.getVariable(1));
methodDep.use();
if (dependencyAnalyzer.asyncSupported) {
MethodDependency methodDep = dependencyAnalyzer.linkMethod(
new MethodReference(Object.class, "monitorExit", Object.class, void.class), null);
nodes[objectRef.getIndex()].connect(methodDep.getVariable(1));
methodDep.use();
}
methodDep = dependencyAnalyzer.linkMethod(
MethodDependency methodDep = dependencyAnalyzer.linkMethod(
new MethodReference(Object.class, "monitorExitSync", Object.class, void.class), null);
nodes[objectRef.getIndex()].connect(methodDep.getVariable(1));
methodDep.use();

View File

@ -47,6 +47,7 @@ public class RuntimeClass extends RuntimeObject {
public RuntimeClass parent;
public Address enumValues;
public Address layout;
public RuntimeObject simpleName;
@Unmanaged
public static int computeCanary(int size, int tag) {

View File

@ -358,6 +358,7 @@ public class TeaVM implements TeaVMHost, ServiceRepository {
return;
}
dependencyAnalyzer.setAsyncSupported(target.isAsyncSupported());
dependencyAnalyzer.setInterruptor(() -> progressListener.progressReached(0) == TeaVMProgressFeedback.CONTINUE);
target.contributeDependencies(dependencyAnalyzer);
dependencyAnalyzer.processDependencies();

View File

@ -46,4 +46,6 @@ public interface TeaVMTarget {
void emit(ListableClassHolderSource classes, BuildTarget buildTarget, String outputName) throws IOException;
String[] getPlatformTags();
boolean isAsyncSupported();
}

View File

@ -234,10 +234,16 @@ public final class Platform {
return cls.itemType;
}
@DelegateTo("getNameLowLevel")
public static String getName(PlatformClass cls) {
return cls.getMetadata().getName();
}
@Unmanaged
private static RuntimeObject getNameLowLevel(RuntimeClass cls) {
return cls.name;
}
@JSBody(script = "return $rt_global;")
private static native JSObject getGlobal();
}