mirror of
https://github.com/Eaglercraft-TeaVM-Fork/eagler-teavm.git
synced 2025-01-05 06:34:11 -08:00
Fix coroutine transformation. Make emulated threads work in Wasm
This commit is contained in:
parent
eb495182d2
commit
9df897d298
|
@ -120,8 +120,8 @@ public class CoroutineTransformation {
|
||||||
processBlock(program.basicBlockAt(i));
|
processBlock(program.basicBlockAt(i));
|
||||||
}
|
}
|
||||||
splitter.fixProgram();
|
splitter.fixProgram();
|
||||||
new PhiUpdater().updatePhis(program, methodReference.parameterCount() + 1);
|
|
||||||
processIrreducibleCfg();
|
processIrreducibleCfg();
|
||||||
|
new PhiUpdater().updatePhis(program, methodReference.parameterCount() + 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void createSplitPrologue() {
|
private void createSplitPrologue() {
|
||||||
|
@ -475,7 +475,6 @@ public class CoroutineTransformation {
|
||||||
weights[i] = program.basicBlockAt(i).instructionCount();
|
weights[i] = program.basicBlockAt(i).instructionCount();
|
||||||
}
|
}
|
||||||
GraphUtils.splitIrreducibleGraph(graph, weights, splittingBackend);
|
GraphUtils.splitIrreducibleGraph(graph, weights, splittingBackend);
|
||||||
new PhiUpdater().updatePhis(program, parameterCount + 1);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
class SplittingBackend implements GraphSplittingBackend {
|
class SplittingBackend implements GraphSplittingBackend {
|
||||||
|
|
|
@ -37,6 +37,7 @@ import org.teavm.backend.lowlevel.analyze.LowLevelInliningFilterFactory;
|
||||||
import org.teavm.backend.lowlevel.dependency.StringsDependencyListener;
|
import org.teavm.backend.lowlevel.dependency.StringsDependencyListener;
|
||||||
import org.teavm.backend.lowlevel.generate.NameProvider;
|
import org.teavm.backend.lowlevel.generate.NameProvider;
|
||||||
import org.teavm.backend.lowlevel.generate.NameProviderWithSpecialNames;
|
import org.teavm.backend.lowlevel.generate.NameProviderWithSpecialNames;
|
||||||
|
import org.teavm.backend.lowlevel.transform.CoroutineTransformation;
|
||||||
import org.teavm.backend.wasm.binary.BinaryWriter;
|
import org.teavm.backend.wasm.binary.BinaryWriter;
|
||||||
import org.teavm.backend.wasm.generate.WasmClassGenerator;
|
import org.teavm.backend.wasm.generate.WasmClassGenerator;
|
||||||
import org.teavm.backend.wasm.generate.WasmDependencyListener;
|
import org.teavm.backend.wasm.generate.WasmDependencyListener;
|
||||||
|
@ -154,6 +155,7 @@ import org.teavm.model.optimization.InliningFilterFactory;
|
||||||
import org.teavm.model.transformation.BoundCheckInsertion;
|
import org.teavm.model.transformation.BoundCheckInsertion;
|
||||||
import org.teavm.model.transformation.ClassPatch;
|
import org.teavm.model.transformation.ClassPatch;
|
||||||
import org.teavm.model.transformation.NullCheckInsertion;
|
import org.teavm.model.transformation.NullCheckInsertion;
|
||||||
|
import org.teavm.model.util.AsyncMethodFinder;
|
||||||
import org.teavm.runtime.Allocator;
|
import org.teavm.runtime.Allocator;
|
||||||
import org.teavm.runtime.EventQueue;
|
import org.teavm.runtime.EventQueue;
|
||||||
import org.teavm.runtime.ExceptionHandling;
|
import org.teavm.runtime.ExceptionHandling;
|
||||||
|
@ -194,6 +196,8 @@ public class WasmTarget implements TeaVMTarget, TeaVMWasmHost {
|
||||||
private int minHeapSize = 2 * 1024 * 1024;
|
private int minHeapSize = 2 * 1024 * 1024;
|
||||||
private int maxHeapSize = 128 * 1024 * 1024;
|
private int maxHeapSize = 128 * 1024 * 1024;
|
||||||
private boolean obfuscated;
|
private boolean obfuscated;
|
||||||
|
private Set<MethodReference> asyncMethods;
|
||||||
|
private boolean hasThreads;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setController(TeaVMTargetController controller) {
|
public void setController(TeaVMTargetController controller) {
|
||||||
|
@ -380,6 +384,16 @@ public class WasmTarget implements TeaVMTarget, TeaVMWasmHost {
|
||||||
dependencyAnalyzer.addDependencyListener(new StringsDependencyListener());
|
dependencyAnalyzer.addDependencyListener(new StringsDependencyListener());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void analyzeBeforeOptimizations(ListableClassReaderSource classSource) {
|
||||||
|
AsyncMethodFinder asyncFinder = new AsyncMethodFinder(controller.getDependencyInfo().getCallGraph(),
|
||||||
|
controller.getDependencyInfo());
|
||||||
|
asyncFinder.find(classSource);
|
||||||
|
asyncMethods = new HashSet<>(asyncFinder.getAsyncMethods());
|
||||||
|
asyncMethods.addAll(asyncFinder.getAsyncFamilyMethods());
|
||||||
|
hasThreads = asyncFinder.hasAsyncMethods();
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void beforeOptimizations(Program program, MethodReader method) {
|
public void beforeOptimizations(Program program, MethodReader method) {
|
||||||
nullCheckInsertion.transformProgram(program, method.getReference());
|
nullCheckInsertion.transformProgram(program, method.getReference());
|
||||||
|
@ -390,6 +404,8 @@ public class WasmTarget implements TeaVMTarget, TeaVMWasmHost {
|
||||||
public void afterOptimizations(Program program, MethodReader method) {
|
public void afterOptimizations(Program program, MethodReader method) {
|
||||||
classInitializerEliminator.apply(program);
|
classInitializerEliminator.apply(program);
|
||||||
classInitializerTransformer.transform(program);
|
classInitializerTransformer.transform(program);
|
||||||
|
new CoroutineTransformation(controller.getUnprocessedClassSource(), asyncMethods, hasThreads)
|
||||||
|
.apply(program, method.getReference());
|
||||||
checkTransformation.apply(program, method.getResultType());
|
checkTransformation.apply(program, method.getResultType());
|
||||||
shadowStackTransformer.apply(program, method);
|
shadowStackTransformer.apply(program, method);
|
||||||
writeBarrierInsertion.apply(program);
|
writeBarrierInsertion.apply(program);
|
||||||
|
@ -456,7 +472,8 @@ public class WasmTarget implements TeaVMTarget, TeaVMWasmHost {
|
||||||
classGenerator, stringPool, obfuscated);
|
classGenerator, stringPool, obfuscated);
|
||||||
context.addIntrinsic(exceptionHandlingIntrinsic);
|
context.addIntrinsic(exceptionHandlingIntrinsic);
|
||||||
|
|
||||||
WasmGenerator generator = new WasmGenerator(decompiler, classes, context, classGenerator, binaryWriter);
|
WasmGenerator generator = new WasmGenerator(decompiler, classes, context, classGenerator, binaryWriter,
|
||||||
|
asyncMethods::contains);
|
||||||
|
|
||||||
generateMethods(classes, context, generator, classGenerator, binaryWriter, module);
|
generateMethods(classes, context, generator, classGenerator, binaryWriter, module);
|
||||||
new WasmInteropFunctionGenerator(classGenerator).generateFunctions(module);
|
new WasmInteropFunctionGenerator(classGenerator).generateFunctions(module);
|
||||||
|
|
|
@ -126,6 +126,14 @@ import org.teavm.runtime.RuntimeClass;
|
||||||
import org.teavm.runtime.ShadowStack;
|
import org.teavm.runtime.ShadowStack;
|
||||||
|
|
||||||
class WasmGenerationVisitor implements StatementVisitor, ExprVisitor {
|
class WasmGenerationVisitor implements StatementVisitor, ExprVisitor {
|
||||||
|
private static final MethodReference MONITOR_ENTER_SYNC = new MethodReference(Object.class,
|
||||||
|
"monitorEnterSync", Object.class, void.class);
|
||||||
|
private static final MethodReference MONITOR_EXIT_SYNC = new MethodReference(Object.class,
|
||||||
|
"monitorExitSync", Object.class, void.class);
|
||||||
|
private static final MethodReference MONITOR_ENTER = new MethodReference(Object.class,
|
||||||
|
"monitorEnter", Object.class, void.class);
|
||||||
|
private static final MethodReference MONITOR_EXIT = new MethodReference(Object.class,
|
||||||
|
"monitorExit", Object.class, void.class);
|
||||||
private static final int SWITCH_TABLE_THRESHOLD = 256;
|
private static final int SWITCH_TABLE_THRESHOLD = 256;
|
||||||
private WasmGenerationContext context;
|
private WasmGenerationContext context;
|
||||||
private WasmClassGenerator classGenerator;
|
private WasmClassGenerator classGenerator;
|
||||||
|
@ -140,10 +148,11 @@ class WasmGenerationVisitor implements StatementVisitor, ExprVisitor {
|
||||||
private List<Deque<WasmLocal>> temporaryVariablesByType = new ArrayList<>();
|
private List<Deque<WasmLocal>> temporaryVariablesByType = new ArrayList<>();
|
||||||
private WasmLocal stackVariable;
|
private WasmLocal stackVariable;
|
||||||
private BinaryWriter binaryWriter;
|
private BinaryWriter binaryWriter;
|
||||||
|
private boolean async;
|
||||||
WasmExpression result;
|
WasmExpression result;
|
||||||
|
|
||||||
WasmGenerationVisitor(WasmGenerationContext context, WasmClassGenerator classGenerator,
|
WasmGenerationVisitor(WasmGenerationContext context, WasmClassGenerator classGenerator,
|
||||||
BinaryWriter binaryWriter, WasmFunction function, int firstVariable) {
|
BinaryWriter binaryWriter, WasmFunction function, int firstVariable, boolean async) {
|
||||||
this.context = context;
|
this.context = context;
|
||||||
this.classGenerator = classGenerator;
|
this.classGenerator = classGenerator;
|
||||||
this.binaryWriter = binaryWriter;
|
this.binaryWriter = binaryWriter;
|
||||||
|
@ -154,6 +163,7 @@ class WasmGenerationVisitor implements StatementVisitor, ExprVisitor {
|
||||||
temporaryVariablesByType.add(new ArrayDeque<>());
|
temporaryVariablesByType.add(new ArrayDeque<>());
|
||||||
}
|
}
|
||||||
typeInference = new WasmTypeInference(context);
|
typeInference = new WasmTypeInference(context);
|
||||||
|
this.async = async;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void accept(Expr expr) {
|
private void accept(Expr expr) {
|
||||||
|
@ -1420,12 +1430,20 @@ class WasmGenerationVisitor implements StatementVisitor, ExprVisitor {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void visit(MonitorEnterStatement statement) {
|
public void visit(MonitorEnterStatement statement) {
|
||||||
result = emptyStatement(statement.getLocation());
|
WasmCall call = new WasmCall(context.names.forMethod(async ? MONITOR_ENTER : MONITOR_ENTER_SYNC));
|
||||||
|
call.setLocation(statement.getLocation());
|
||||||
|
statement.getObjectRef().acceptVisitor(this);
|
||||||
|
call.getArguments().add(result);
|
||||||
|
result = call;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void visit(MonitorExitStatement statement) {
|
public void visit(MonitorExitStatement statement) {
|
||||||
result = emptyStatement(statement.getLocation());
|
WasmCall call = new WasmCall(context.names.forMethod(async ? MONITOR_EXIT : MONITOR_EXIT_SYNC));
|
||||||
|
call.setLocation(statement.getLocation());
|
||||||
|
statement.getObjectRef().acceptVisitor(this);
|
||||||
|
call.getArguments().add(result);
|
||||||
|
result = call;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -15,6 +15,7 @@
|
||||||
*/
|
*/
|
||||||
package org.teavm.backend.wasm.generate;
|
package org.teavm.backend.wasm.generate;
|
||||||
|
|
||||||
|
import java.util.function.Predicate;
|
||||||
import org.teavm.ast.RegularMethodNode;
|
import org.teavm.ast.RegularMethodNode;
|
||||||
import org.teavm.ast.VariableNode;
|
import org.teavm.ast.VariableNode;
|
||||||
import org.teavm.ast.decompilation.Decompiler;
|
import org.teavm.ast.decompilation.Decompiler;
|
||||||
|
@ -40,15 +41,18 @@ public class WasmGenerator {
|
||||||
private WasmClassGenerator classGenerator;
|
private WasmClassGenerator classGenerator;
|
||||||
private BinaryWriter binaryWriter;
|
private BinaryWriter binaryWriter;
|
||||||
private NameProvider names;
|
private NameProvider names;
|
||||||
|
private Predicate<MethodReference> asyncMethods;
|
||||||
|
|
||||||
public WasmGenerator(Decompiler decompiler, ClassHolderSource classSource,
|
public WasmGenerator(Decompiler decompiler, ClassHolderSource classSource,
|
||||||
WasmGenerationContext context, WasmClassGenerator classGenerator, BinaryWriter binaryWriter) {
|
WasmGenerationContext context, WasmClassGenerator classGenerator, BinaryWriter binaryWriter,
|
||||||
|
Predicate<MethodReference> asyncMethods) {
|
||||||
this.decompiler = decompiler;
|
this.decompiler = decompiler;
|
||||||
this.classSource = classSource;
|
this.classSource = classSource;
|
||||||
this.context = context;
|
this.context = context;
|
||||||
this.classGenerator = classGenerator;
|
this.classGenerator = classGenerator;
|
||||||
this.binaryWriter = binaryWriter;
|
this.binaryWriter = binaryWriter;
|
||||||
names = classGenerator.names;
|
names = classGenerator.names;
|
||||||
|
this.asyncMethods = asyncMethods;
|
||||||
}
|
}
|
||||||
|
|
||||||
public WasmFunction generateDefinition(MethodReference methodReference) {
|
public WasmFunction generateDefinition(MethodReference methodReference) {
|
||||||
|
@ -85,7 +89,7 @@ public class WasmGenerator {
|
||||||
}
|
}
|
||||||
|
|
||||||
WasmGenerationVisitor visitor = new WasmGenerationVisitor(context, classGenerator, binaryWriter, function,
|
WasmGenerationVisitor visitor = new WasmGenerationVisitor(context, classGenerator, binaryWriter, function,
|
||||||
firstVariable);
|
firstVariable, asyncMethods.test(methodReference));
|
||||||
methodAst.getBody().acceptVisitor(visitor);
|
methodAst.getBody().acceptVisitor(visitor);
|
||||||
if (visitor.result instanceof WasmBlock) {
|
if (visitor.result instanceof WasmBlock) {
|
||||||
((WasmBlock) visitor.result).setType(function.getResult());
|
((WasmBlock) visitor.result).setType(function.getResult());
|
||||||
|
|
Loading…
Reference in New Issue
Block a user