Fix coroutine transformation. Make emulated threads work in Wasm

This commit is contained in:
Alexey Andreev 2021-03-22 21:28:50 +03:00
parent eb495182d2
commit 9df897d298
4 changed files with 46 additions and 8 deletions

View File

@ -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 {

View File

@ -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);

View File

@ -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

View File

@ -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());