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

View File

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

View File

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

View File

@ -422,4 +422,9 @@ public class CTarget implements TeaVMTarget {
public String[] getPlatformTags() { public String[] getPlatformTags() {
return new String[] { PlatformMarkers.C, PlatformMarkers.LOW_LEVEL }; 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) { for (int j = 0; j < string.length(); ++j) {
char c = string.charAt(j); char c = string.charAt(j);
switch (c) { switch (c) {
case '\\':
writer.print("\\\\");
break;
case '"':
writer.print("\\\"");
break;
case '\r': case '\r':
writer.print("\\r"); writer.print("\\r");
break; break;
@ -81,7 +87,9 @@ public class StringPoolGenerator {
writer.print("\\t"); writer.print("\\t");
break; break;
default: 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" writer.print("\\u"
+ Character.forDigit(c >> 12, 16) + Character.forDigit(c >> 12, 16)
+ Character.forDigit((c >> 8) & 15, 16) + Character.forDigit((c >> 8) & 15, 16)

View File

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

View File

@ -458,4 +458,9 @@ public class JavaScriptTarget implements TeaVMTarget, TeaVMJavaScriptHost {
public String[] getPlatformTags() { public String[] getPlatformTags() {
return new String[] { PlatformMarkers.JAVASCRIPT }; 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() { public String[] getPlatformTags() {
return new String[] { PlatformMarkers.WEBASSEMBLY, PlatformMarkers.LOW_LEVEL }; 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<>(); Map<MethodReference, DependencyPlugin> dependencyPlugins = new HashMap<>();
private boolean completing; private boolean completing;
private Map<String, SuperClassFilter> superClassFilters = new HashMap<>(); private Map<String, SuperClassFilter> superClassFilters = new HashMap<>();
boolean asyncSupported;
public DependencyAnalyzer(ClassReaderSource classSource, ClassLoader classLoader, ServiceRepository services, public DependencyAnalyzer(ClassReaderSource classSource, ClassLoader classLoader, ServiceRepository services,
Diagnostics diagnostics) { Diagnostics diagnostics) {
@ -116,6 +117,10 @@ public class DependencyAnalyzer implements DependencyInfo {
agent = new DependencyAgent(this); agent = new DependencyAgent(this);
} }
public void setAsyncSupported(boolean asyncSupported) {
this.asyncSupported = asyncSupported;
}
public DependencyAgent getAgent() { public DependencyAgent getAgent() {
return agent; return agent;
} }

View File

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

View File

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

View File

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

View File

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

View File

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