mirror of
https://github.com/konsoletyper/teavm.git
synced 2024-11-21 01:00:54 +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));
|
||||
}
|
||||
splitter.fixProgram();
|
||||
new PhiUpdater().updatePhis(program, methodReference.parameterCount() + 1);
|
||||
processIrreducibleCfg();
|
||||
new PhiUpdater().updatePhis(program, methodReference.parameterCount() + 1);
|
||||
}
|
||||
|
||||
private void createSplitPrologue() {
|
||||
@ -475,7 +475,6 @@ public class CoroutineTransformation {
|
||||
weights[i] = program.basicBlockAt(i).instructionCount();
|
||||
}
|
||||
GraphUtils.splitIrreducibleGraph(graph, weights, splittingBackend);
|
||||
new PhiUpdater().updatePhis(program, parameterCount + 1);
|
||||
}
|
||||
|
||||
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.generate.NameProvider;
|
||||
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.generate.WasmClassGenerator;
|
||||
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.ClassPatch;
|
||||
import org.teavm.model.transformation.NullCheckInsertion;
|
||||
import org.teavm.model.util.AsyncMethodFinder;
|
||||
import org.teavm.runtime.Allocator;
|
||||
import org.teavm.runtime.EventQueue;
|
||||
import org.teavm.runtime.ExceptionHandling;
|
||||
@ -194,6 +196,8 @@ public class WasmTarget implements TeaVMTarget, TeaVMWasmHost {
|
||||
private int minHeapSize = 2 * 1024 * 1024;
|
||||
private int maxHeapSize = 128 * 1024 * 1024;
|
||||
private boolean obfuscated;
|
||||
private Set<MethodReference> asyncMethods;
|
||||
private boolean hasThreads;
|
||||
|
||||
@Override
|
||||
public void setController(TeaVMTargetController controller) {
|
||||
@ -380,6 +384,16 @@ public class WasmTarget implements TeaVMTarget, TeaVMWasmHost {
|
||||
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
|
||||
public void beforeOptimizations(Program program, MethodReader method) {
|
||||
nullCheckInsertion.transformProgram(program, method.getReference());
|
||||
@ -390,6 +404,8 @@ public class WasmTarget implements TeaVMTarget, TeaVMWasmHost {
|
||||
public void afterOptimizations(Program program, MethodReader method) {
|
||||
classInitializerEliminator.apply(program);
|
||||
classInitializerTransformer.transform(program);
|
||||
new CoroutineTransformation(controller.getUnprocessedClassSource(), asyncMethods, hasThreads)
|
||||
.apply(program, method.getReference());
|
||||
checkTransformation.apply(program, method.getResultType());
|
||||
shadowStackTransformer.apply(program, method);
|
||||
writeBarrierInsertion.apply(program);
|
||||
@ -456,7 +472,8 @@ public class WasmTarget implements TeaVMTarget, TeaVMWasmHost {
|
||||
classGenerator, stringPool, obfuscated);
|
||||
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);
|
||||
new WasmInteropFunctionGenerator(classGenerator).generateFunctions(module);
|
||||
|
@ -126,6 +126,14 @@ import org.teavm.runtime.RuntimeClass;
|
||||
import org.teavm.runtime.ShadowStack;
|
||||
|
||||
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 WasmGenerationContext context;
|
||||
private WasmClassGenerator classGenerator;
|
||||
@ -140,10 +148,11 @@ class WasmGenerationVisitor implements StatementVisitor, ExprVisitor {
|
||||
private List<Deque<WasmLocal>> temporaryVariablesByType = new ArrayList<>();
|
||||
private WasmLocal stackVariable;
|
||||
private BinaryWriter binaryWriter;
|
||||
private boolean async;
|
||||
WasmExpression result;
|
||||
|
||||
WasmGenerationVisitor(WasmGenerationContext context, WasmClassGenerator classGenerator,
|
||||
BinaryWriter binaryWriter, WasmFunction function, int firstVariable) {
|
||||
BinaryWriter binaryWriter, WasmFunction function, int firstVariable, boolean async) {
|
||||
this.context = context;
|
||||
this.classGenerator = classGenerator;
|
||||
this.binaryWriter = binaryWriter;
|
||||
@ -154,6 +163,7 @@ class WasmGenerationVisitor implements StatementVisitor, ExprVisitor {
|
||||
temporaryVariablesByType.add(new ArrayDeque<>());
|
||||
}
|
||||
typeInference = new WasmTypeInference(context);
|
||||
this.async = async;
|
||||
}
|
||||
|
||||
private void accept(Expr expr) {
|
||||
@ -1420,12 +1430,20 @@ class WasmGenerationVisitor implements StatementVisitor, ExprVisitor {
|
||||
|
||||
@Override
|
||||
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
|
||||
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
|
||||
|
@ -15,6 +15,7 @@
|
||||
*/
|
||||
package org.teavm.backend.wasm.generate;
|
||||
|
||||
import java.util.function.Predicate;
|
||||
import org.teavm.ast.RegularMethodNode;
|
||||
import org.teavm.ast.VariableNode;
|
||||
import org.teavm.ast.decompilation.Decompiler;
|
||||
@ -40,15 +41,18 @@ public class WasmGenerator {
|
||||
private WasmClassGenerator classGenerator;
|
||||
private BinaryWriter binaryWriter;
|
||||
private NameProvider names;
|
||||
private Predicate<MethodReference> asyncMethods;
|
||||
|
||||
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.classSource = classSource;
|
||||
this.context = context;
|
||||
this.classGenerator = classGenerator;
|
||||
this.binaryWriter = binaryWriter;
|
||||
names = classGenerator.names;
|
||||
this.asyncMethods = asyncMethods;
|
||||
}
|
||||
|
||||
public WasmFunction generateDefinition(MethodReference methodReference) {
|
||||
@ -85,7 +89,7 @@ public class WasmGenerator {
|
||||
}
|
||||
|
||||
WasmGenerationVisitor visitor = new WasmGenerationVisitor(context, classGenerator, binaryWriter, function,
|
||||
firstVariable);
|
||||
firstVariable, asyncMethods.test(methodReference));
|
||||
methodAst.getBody().acceptVisitor(visitor);
|
||||
if (visitor.result instanceof WasmBlock) {
|
||||
((WasmBlock) visitor.result).setType(function.getResult());
|
||||
|
Loading…
Reference in New Issue
Block a user