mirror of
https://github.com/Eaglercraft-TeaVM-Fork/eagler-teavm.git
synced 2024-12-22 16:14:10 -08:00
C backend: make more tests pass
This commit is contained in:
parent
fa07100024
commit
18eb3ee058
|
@ -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;
|
||||||
|
|
|
@ -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();
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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();
|
||||||
|
|
||||||
methodDep = dependencyAnalyzer.linkMethod(
|
if (dependencyAnalyzer.asyncSupported) {
|
||||||
new MethodReference(Object.class, "monitorExit", Object.class, void.class), null);
|
methodDep = dependencyAnalyzer.linkMethod(
|
||||||
syncNodes.add(methodDep.getVariable(1));
|
new MethodReference(Object.class, "monitorExit", Object.class, void.class), null);
|
||||||
methodDep.use();
|
syncNodes.add(methodDep.getVariable(1));
|
||||||
|
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,25 +701,29 @@ class DependencyGraphBuilder {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void monitorEnter(VariableReader objectRef) {
|
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);
|
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();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void monitorExit(VariableReader objectRef) {
|
public void monitorExit(VariableReader objectRef) {
|
||||||
MethodDependency methodDep = dependencyAnalyzer.linkMethod(
|
if (dependencyAnalyzer.asyncSupported) {
|
||||||
new MethodReference(Object.class, "monitorExit", Object.class, void.class), null);
|
MethodDependency methodDep = dependencyAnalyzer.linkMethod(
|
||||||
nodes[objectRef.getIndex()].connect(methodDep.getVariable(1));
|
new MethodReference(Object.class, "monitorExit", Object.class, void.class), null);
|
||||||
methodDep.use();
|
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);
|
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();
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
|
@ -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();
|
||||||
|
|
|
@ -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();
|
||||||
}
|
}
|
||||||
|
|
|
@ -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();
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user