mirror of
https://github.com/Eaglercraft-TeaVM-Fork/eagler-teavm.git
synced 2024-12-22 08:14:09 -08:00
wasm: support exception handling via native exception handling spec
This commit is contained in:
parent
d40bd9989b
commit
1b412073b9
|
@ -87,6 +87,7 @@ import org.teavm.backend.wasm.model.WasmFunction;
|
||||||
import org.teavm.backend.wasm.model.WasmLocal;
|
import org.teavm.backend.wasm.model.WasmLocal;
|
||||||
import org.teavm.backend.wasm.model.WasmMemorySegment;
|
import org.teavm.backend.wasm.model.WasmMemorySegment;
|
||||||
import org.teavm.backend.wasm.model.WasmModule;
|
import org.teavm.backend.wasm.model.WasmModule;
|
||||||
|
import org.teavm.backend.wasm.model.WasmTag;
|
||||||
import org.teavm.backend.wasm.model.WasmType;
|
import org.teavm.backend.wasm.model.WasmType;
|
||||||
import org.teavm.backend.wasm.model.expression.WasmBlock;
|
import org.teavm.backend.wasm.model.expression.WasmBlock;
|
||||||
import org.teavm.backend.wasm.model.expression.WasmBranch;
|
import org.teavm.backend.wasm.model.expression.WasmBranch;
|
||||||
|
@ -118,6 +119,7 @@ import org.teavm.backend.wasm.transformation.IndirectCallTraceTransformation;
|
||||||
import org.teavm.backend.wasm.transformation.MemoryAccessTraceTransformation;
|
import org.teavm.backend.wasm.transformation.MemoryAccessTraceTransformation;
|
||||||
import org.teavm.backend.wasm.transformation.WasiFileSystemProviderTransformer;
|
import org.teavm.backend.wasm.transformation.WasiFileSystemProviderTransformer;
|
||||||
import org.teavm.backend.wasm.transformation.WasiSupportClassTransformer;
|
import org.teavm.backend.wasm.transformation.WasiSupportClassTransformer;
|
||||||
|
import org.teavm.backend.wasm.transformation.WasmExceptionHandlingTransform;
|
||||||
import org.teavm.common.ServiceRepository;
|
import org.teavm.common.ServiceRepository;
|
||||||
import org.teavm.dependency.DependencyAnalyzer;
|
import org.teavm.dependency.DependencyAnalyzer;
|
||||||
import org.teavm.dependency.DependencyListener;
|
import org.teavm.dependency.DependencyListener;
|
||||||
|
@ -164,7 +166,6 @@ 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.model.util.AsyncMethodFinder;
|
||||||
import org.teavm.model.util.TransitionExtractor;
|
|
||||||
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;
|
||||||
|
@ -209,6 +210,7 @@ public class WasmTarget implements TeaVMTarget, TeaVMWasmHost {
|
||||||
private WasmRuntimeType runtimeType = WasmRuntimeType.TEAVM;
|
private WasmRuntimeType runtimeType = WasmRuntimeType.TEAVM;
|
||||||
private ReportingWasmBinaryStatsCollector statsCollector;
|
private ReportingWasmBinaryStatsCollector statsCollector;
|
||||||
private SourceFileResolver sourceFileResolver;
|
private SourceFileResolver sourceFileResolver;
|
||||||
|
private boolean exceptionsUsed;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setController(TeaVMTargetController controller) {
|
public void setController(TeaVMTargetController controller) {
|
||||||
|
@ -247,6 +249,9 @@ public class WasmTarget implements TeaVMTarget, TeaVMWasmHost {
|
||||||
transformers.add(new WasiSupportClassTransformer());
|
transformers.add(new WasiSupportClassTransformer());
|
||||||
transformers.add(new WasiFileSystemProviderTransformer());
|
transformers.add(new WasiFileSystemProviderTransformer());
|
||||||
}
|
}
|
||||||
|
if (exceptionsUsed) {
|
||||||
|
transformers.add(new WasmExceptionHandlingTransform());
|
||||||
|
}
|
||||||
return transformers;
|
return transformers;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -313,6 +318,10 @@ public class WasmTarget implements TeaVMTarget, TeaVMWasmHost {
|
||||||
this.sourceFileResolver = sourceFileResolver;
|
this.sourceFileResolver = sourceFileResolver;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setExceptionsUsed(boolean exceptionsUsed) {
|
||||||
|
this.exceptionsUsed = exceptionsUsed;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public WasmRuntimeType getRuntimeType() {
|
public WasmRuntimeType getRuntimeType() {
|
||||||
return runtimeType;
|
return runtimeType;
|
||||||
|
@ -388,6 +397,8 @@ public class WasmTarget implements TeaVMTarget, TeaVMWasmHost {
|
||||||
|
|
||||||
dependencyAnalyzer.linkMethod(new MethodReference(ExceptionHandling.class, "catchException",
|
dependencyAnalyzer.linkMethod(new MethodReference(ExceptionHandling.class, "catchException",
|
||||||
Throwable.class)).use();
|
Throwable.class)).use();
|
||||||
|
dependencyAnalyzer.linkMethod(new MethodReference(ExceptionHandling.class, "peekException",
|
||||||
|
Throwable.class)).use();
|
||||||
|
|
||||||
dependencyAnalyzer.linkField(new FieldReference("java.lang.Object", "monitor"));
|
dependencyAnalyzer.linkField(new FieldReference("java.lang.Object", "monitor"));
|
||||||
|
|
||||||
|
@ -454,25 +465,9 @@ public class WasmTarget implements TeaVMTarget, TeaVMWasmHost {
|
||||||
new CoroutineTransformation(controller.getUnprocessedClassSource(), asyncMethods, hasThreads)
|
new CoroutineTransformation(controller.getUnprocessedClassSource(), asyncMethods, hasThreads)
|
||||||
.apply(program, method.getReference());
|
.apply(program, method.getReference());
|
||||||
shadowStackTransformer.apply(program, method);
|
shadowStackTransformer.apply(program, method);
|
||||||
//checkPhis(program, method);
|
|
||||||
writeBarrierInsertion.apply(program);
|
writeBarrierInsertion.apply(program);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void checkPhis(Program program, MethodReader method) {
|
|
||||||
var transitionExtractor = new TransitionExtractor();
|
|
||||||
for (var block : program.getBasicBlocks()) {
|
|
||||||
for (var phi : block.getPhis()) {
|
|
||||||
for (var incoming : phi.getIncomings()) {
|
|
||||||
incoming.getSource().getLastInstruction().acceptVisitor(transitionExtractor);
|
|
||||||
if (!Arrays.asList(transitionExtractor.getTargets()).contains(block)) {
|
|
||||||
throw new RuntimeException("Method " + method.getReference() + ", block "
|
|
||||||
+ block.getIndex() + ", from " + incoming.getSource().getIndex());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void emit(ListableClassHolderSource classes, BuildTarget buildTarget, String outputName)
|
public void emit(ListableClassHolderSource classes, BuildTarget buildTarget, String outputName)
|
||||||
throws IOException {
|
throws IOException {
|
||||||
|
@ -502,8 +497,13 @@ public class WasmTarget implements TeaVMTarget, TeaVMWasmHost {
|
||||||
|
|
||||||
Decompiler decompiler = new Decompiler(classes, new HashSet<>(), false);
|
Decompiler decompiler = new Decompiler(classes, new HashSet<>(), false);
|
||||||
var stringPool = classGenerator.getStringPool();
|
var stringPool = classGenerator.getStringPool();
|
||||||
|
WasmTag exceptionTag = null;
|
||||||
|
if (exceptionsUsed) {
|
||||||
|
exceptionTag = new WasmTag();
|
||||||
|
module.addTag(exceptionTag);
|
||||||
|
}
|
||||||
var context = new WasmGenerationContext(classes, module, controller.getDiagnostics(),
|
var context = new WasmGenerationContext(classes, module, controller.getDiagnostics(),
|
||||||
vtableProvider, tagRegistry, stringPool, names, characteristics);
|
vtableProvider, tagRegistry, stringPool, names, characteristics, exceptionTag);
|
||||||
|
|
||||||
context.addIntrinsic(new AddressIntrinsic(classGenerator));
|
context.addIntrinsic(new AddressIntrinsic(classGenerator));
|
||||||
context.addIntrinsic(new StructureIntrinsic(classes, classGenerator));
|
context.addIntrinsic(new StructureIntrinsic(classes, classGenerator));
|
||||||
|
|
|
@ -24,6 +24,7 @@ import org.teavm.backend.wasm.generators.WasmMethodGenerator;
|
||||||
import org.teavm.backend.wasm.intrinsics.WasmIntrinsic;
|
import org.teavm.backend.wasm.intrinsics.WasmIntrinsic;
|
||||||
import org.teavm.backend.wasm.model.WasmFunction;
|
import org.teavm.backend.wasm.model.WasmFunction;
|
||||||
import org.teavm.backend.wasm.model.WasmModule;
|
import org.teavm.backend.wasm.model.WasmModule;
|
||||||
|
import org.teavm.backend.wasm.model.WasmTag;
|
||||||
import org.teavm.diagnostics.Diagnostics;
|
import org.teavm.diagnostics.Diagnostics;
|
||||||
import org.teavm.interop.Import;
|
import org.teavm.interop.Import;
|
||||||
import org.teavm.model.AnnotationReader;
|
import org.teavm.model.AnnotationReader;
|
||||||
|
@ -54,11 +55,12 @@ public class WasmGenerationContext {
|
||||||
private List<WasmMethodGenerator> generators = new ArrayList<>();
|
private List<WasmMethodGenerator> generators = new ArrayList<>();
|
||||||
private Map<MethodReference, IntrinsicHolder> intrinsicCache = new HashMap<>();
|
private Map<MethodReference, IntrinsicHolder> intrinsicCache = new HashMap<>();
|
||||||
private Map<MethodReference, GeneratorHolder> generatorCache = new HashMap<>();
|
private Map<MethodReference, GeneratorHolder> generatorCache = new HashMap<>();
|
||||||
|
private WasmTag exceptionTag;
|
||||||
public final List<CallSiteDescriptor> callSites = new ArrayList<>();
|
public final List<CallSiteDescriptor> callSites = new ArrayList<>();
|
||||||
|
|
||||||
public WasmGenerationContext(ClassReaderSource classSource, WasmModule module, Diagnostics diagnostics,
|
public WasmGenerationContext(ClassReaderSource classSource, WasmModule module, Diagnostics diagnostics,
|
||||||
VirtualTableProvider vtableProvider, TagRegistry tagRegistry, WasmStringPool stringPool,
|
VirtualTableProvider vtableProvider, TagRegistry tagRegistry, WasmStringPool stringPool,
|
||||||
NameProvider names, Characteristics characteristics) {
|
NameProvider names, Characteristics characteristics, WasmTag exceptionTag) {
|
||||||
this.classSource = classSource;
|
this.classSource = classSource;
|
||||||
this.module = module;
|
this.module = module;
|
||||||
this.diagnostics = diagnostics;
|
this.diagnostics = diagnostics;
|
||||||
|
@ -67,6 +69,7 @@ public class WasmGenerationContext {
|
||||||
this.stringPool = stringPool;
|
this.stringPool = stringPool;
|
||||||
this.names = names;
|
this.names = names;
|
||||||
this.characteristics = characteristics;
|
this.characteristics = characteristics;
|
||||||
|
this.exceptionTag = exceptionTag;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void addIntrinsic(WasmIntrinsic intrinsic) {
|
public void addIntrinsic(WasmIntrinsic intrinsic) {
|
||||||
|
@ -162,6 +165,10 @@ public class WasmGenerationContext {
|
||||||
return diagnostics;
|
return diagnostics;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public WasmTag getExceptionTag() {
|
||||||
|
return exceptionTag;
|
||||||
|
}
|
||||||
|
|
||||||
public static class ImportedMethod {
|
public static class ImportedMethod {
|
||||||
public final String name;
|
public final String name;
|
||||||
public final String module;
|
public final String module;
|
||||||
|
|
|
@ -74,11 +74,13 @@ import org.teavm.backend.wasm.binary.DataPrimitives;
|
||||||
import org.teavm.backend.wasm.intrinsics.WasmIntrinsicManager;
|
import org.teavm.backend.wasm.intrinsics.WasmIntrinsicManager;
|
||||||
import org.teavm.backend.wasm.model.WasmFunction;
|
import org.teavm.backend.wasm.model.WasmFunction;
|
||||||
import org.teavm.backend.wasm.model.WasmLocal;
|
import org.teavm.backend.wasm.model.WasmLocal;
|
||||||
|
import org.teavm.backend.wasm.model.WasmTag;
|
||||||
import org.teavm.backend.wasm.model.WasmType;
|
import org.teavm.backend.wasm.model.WasmType;
|
||||||
import org.teavm.backend.wasm.model.expression.WasmBlock;
|
import org.teavm.backend.wasm.model.expression.WasmBlock;
|
||||||
import org.teavm.backend.wasm.model.expression.WasmBranch;
|
import org.teavm.backend.wasm.model.expression.WasmBranch;
|
||||||
import org.teavm.backend.wasm.model.expression.WasmBreak;
|
import org.teavm.backend.wasm.model.expression.WasmBreak;
|
||||||
import org.teavm.backend.wasm.model.expression.WasmCall;
|
import org.teavm.backend.wasm.model.expression.WasmCall;
|
||||||
|
import org.teavm.backend.wasm.model.expression.WasmCatch;
|
||||||
import org.teavm.backend.wasm.model.expression.WasmConditional;
|
import org.teavm.backend.wasm.model.expression.WasmConditional;
|
||||||
import org.teavm.backend.wasm.model.expression.WasmConversion;
|
import org.teavm.backend.wasm.model.expression.WasmConversion;
|
||||||
import org.teavm.backend.wasm.model.expression.WasmDrop;
|
import org.teavm.backend.wasm.model.expression.WasmDrop;
|
||||||
|
@ -111,6 +113,8 @@ import org.teavm.backend.wasm.model.expression.WasmStoreFloat64;
|
||||||
import org.teavm.backend.wasm.model.expression.WasmStoreInt32;
|
import org.teavm.backend.wasm.model.expression.WasmStoreInt32;
|
||||||
import org.teavm.backend.wasm.model.expression.WasmStoreInt64;
|
import org.teavm.backend.wasm.model.expression.WasmStoreInt64;
|
||||||
import org.teavm.backend.wasm.model.expression.WasmSwitch;
|
import org.teavm.backend.wasm.model.expression.WasmSwitch;
|
||||||
|
import org.teavm.backend.wasm.model.expression.WasmThrow;
|
||||||
|
import org.teavm.backend.wasm.model.expression.WasmTry;
|
||||||
import org.teavm.backend.wasm.model.expression.WasmUnreachable;
|
import org.teavm.backend.wasm.model.expression.WasmUnreachable;
|
||||||
import org.teavm.backend.wasm.render.WasmTypeInference;
|
import org.teavm.backend.wasm.render.WasmTypeInference;
|
||||||
import org.teavm.diagnostics.Diagnostics;
|
import org.teavm.diagnostics.Diagnostics;
|
||||||
|
@ -143,6 +147,8 @@ class WasmGenerationVisitor implements StatementVisitor, ExprVisitor {
|
||||||
"monitorExit", Object.class, void.class);
|
"monitorExit", Object.class, void.class);
|
||||||
private static final MethodReference CATCH_METHOD = new MethodReference(ExceptionHandling.class,
|
private static final MethodReference CATCH_METHOD = new MethodReference(ExceptionHandling.class,
|
||||||
"catchException", Throwable.class);
|
"catchException", Throwable.class);
|
||||||
|
private static final MethodReference PEEK_EXCEPTION_METHOD = new MethodReference(ExceptionHandling.class,
|
||||||
|
"peekException", Throwable.class);
|
||||||
private static final MethodReference THROW_METHOD = new MethodReference(ExceptionHandling.class,
|
private static final MethodReference THROW_METHOD = new MethodReference(ExceptionHandling.class,
|
||||||
"throwException", Throwable.class, void.class);
|
"throwException", Throwable.class, void.class);
|
||||||
private static final MethodReference THROW_CCE_METHOD = new MethodReference(ExceptionHandling.class,
|
private static final MethodReference THROW_CCE_METHOD = new MethodReference(ExceptionHandling.class,
|
||||||
|
@ -195,6 +201,7 @@ class WasmGenerationVisitor implements StatementVisitor, ExprVisitor {
|
||||||
this.managed = context.characteristics.isManaged(currentMethod);
|
this.managed = context.characteristics.isManaged(currentMethod);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void generate(Statement statement, List<WasmExpression> target) {
|
void generate(Statement statement, List<WasmExpression> target) {
|
||||||
var lastTargetSize = target.size();
|
var lastTargetSize = target.size();
|
||||||
resultConsumer = target;
|
resultConsumer = target;
|
||||||
|
@ -512,7 +519,6 @@ class WasmGenerationVisitor implements StatementVisitor, ExprVisitor {
|
||||||
block.setType(WasmType.INT32);
|
block.setType(WasmType.INT32);
|
||||||
block.setLocation(location);
|
block.setLocation(location);
|
||||||
|
|
||||||
|
|
||||||
accept(value);
|
accept(value);
|
||||||
var cachedValue = exprCache.create(result, WasmType.INT32, location, block.getBody());
|
var cachedValue = exprCache.create(result, WasmType.INT32, location, block.getBody());
|
||||||
|
|
||||||
|
@ -526,13 +532,17 @@ class WasmGenerationVisitor implements StatementVisitor, ExprVisitor {
|
||||||
var call = new WasmCall(context.names.forMethod(THROW_NPE_METHOD));
|
var call = new WasmCall(context.names.forMethod(THROW_NPE_METHOD));
|
||||||
block.getBody().add(call);
|
block.getBody().add(call);
|
||||||
|
|
||||||
var target = throwJumpTarget();
|
if (context.getExceptionTag() == null) {
|
||||||
var breakExpr = new WasmBreak(target);
|
var target = throwJumpTarget();
|
||||||
if (target != rethrowBlock) {
|
var breakExpr = new WasmBreak(target);
|
||||||
breakExpr.setResult(generateGetHandlerId(callSiteId, location));
|
if (target != rethrowBlock) {
|
||||||
block.getBody().add(new WasmDrop(breakExpr));
|
breakExpr.setResult(generateGetHandlerId(callSiteId, location));
|
||||||
|
block.getBody().add(new WasmDrop(breakExpr));
|
||||||
|
} else {
|
||||||
|
block.getBody().add(breakExpr);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
block.getBody().add(breakExpr);
|
block.getBody().add(new WasmUnreachable());
|
||||||
}
|
}
|
||||||
|
|
||||||
cachedValue.release();
|
cachedValue.release();
|
||||||
|
@ -1072,7 +1082,9 @@ class WasmGenerationVisitor implements StatementVisitor, ExprVisitor {
|
||||||
targetList.add(drop);
|
targetList.add(drop);
|
||||||
}
|
}
|
||||||
|
|
||||||
checkHandlerId(targetList, callSiteId, expr.getLocation());
|
if (context.getExceptionTag() == null) {
|
||||||
|
checkHandlerId(targetList, callSiteId, expr.getLocation());
|
||||||
|
}
|
||||||
if (resultVar != null) {
|
if (resultVar != null) {
|
||||||
var getLocal = new WasmGetLocal(resultVar);
|
var getLocal = new WasmGetLocal(resultVar);
|
||||||
getLocal.setLocation(expr.getLocation());
|
getLocal.setLocation(expr.getLocation());
|
||||||
|
@ -1653,17 +1665,22 @@ class WasmGenerationVisitor implements StatementVisitor, ExprVisitor {
|
||||||
ifNull.setResult(new WasmInt32Constant(0));
|
ifNull.setResult(new WasmInt32Constant(0));
|
||||||
block.getBody().add(new WasmDrop(ifNull));
|
block.getBody().add(new WasmDrop(ifNull));
|
||||||
|
|
||||||
WasmCall supertypeCall = new WasmCall(context.names.forSupertypeFunction(expr.getType()));
|
block.getBody().add(instanceOfImpl(cachedObject.expr(), type));
|
||||||
WasmExpression classRef = new WasmLoadInt32(4, cachedObject.expr(), WasmInt32Subtype.INT32);
|
|
||||||
classRef = new WasmIntBinary(WasmIntType.INT32, WasmIntBinaryOperation.SHL, classRef, new WasmInt32Constant(3));
|
|
||||||
supertypeCall.getArguments().add(classRef);
|
|
||||||
block.getBody().add(supertypeCall);
|
|
||||||
|
|
||||||
cachedObject.release();
|
cachedObject.release();
|
||||||
|
|
||||||
result = block;
|
result = block;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private WasmExpression instanceOfImpl(WasmExpression expression, ValueType type) {
|
||||||
|
WasmCall supertypeCall = new WasmCall(context.names.forSupertypeFunction(type));
|
||||||
|
WasmExpression classRef = new WasmLoadInt32(4, expression, WasmInt32Subtype.INT32);
|
||||||
|
classRef = new WasmIntBinary(WasmIntType.INT32, WasmIntBinaryOperation.SHL, classRef,
|
||||||
|
new WasmInt32Constant(3));
|
||||||
|
supertypeCall.getArguments().add(classRef);
|
||||||
|
return supertypeCall;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void visit(ThrowStatement statement) {
|
public void visit(ThrowStatement statement) {
|
||||||
var callSiteId = generateCallSiteId(statement.getLocation());
|
var callSiteId = generateCallSiteId(statement.getLocation());
|
||||||
|
@ -1674,13 +1691,17 @@ class WasmGenerationVisitor implements StatementVisitor, ExprVisitor {
|
||||||
call.setLocation(statement.getLocation());
|
call.setLocation(statement.getLocation());
|
||||||
resultConsumer.add(call);
|
resultConsumer.add(call);
|
||||||
|
|
||||||
var target = throwJumpTarget();
|
if (context.getExceptionTag() == null) {
|
||||||
var breakExpr = new WasmBreak(target);
|
var target = throwJumpTarget();
|
||||||
breakExpr.setLocation(statement.getLocation());
|
var breakExpr = new WasmBreak(target);
|
||||||
if (target != rethrowBlock) {
|
breakExpr.setLocation(statement.getLocation());
|
||||||
breakExpr.setResult(generateGetHandlerId(callSiteId, statement.getLocation()));
|
if (target != rethrowBlock) {
|
||||||
|
breakExpr.setResult(generateGetHandlerId(callSiteId, statement.getLocation()));
|
||||||
|
}
|
||||||
|
resultConsumer.add(breakExpr);
|
||||||
|
} else {
|
||||||
|
resultConsumer.add(new WasmUnreachable());
|
||||||
}
|
}
|
||||||
resultConsumer.add(breakExpr);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -1723,12 +1744,16 @@ class WasmGenerationVisitor implements StatementVisitor, ExprVisitor {
|
||||||
var call = new WasmCall(context.names.forMethod(THROW_CCE_METHOD));
|
var call = new WasmCall(context.names.forMethod(THROW_CCE_METHOD));
|
||||||
block.getBody().add(call);
|
block.getBody().add(call);
|
||||||
|
|
||||||
var target = throwJumpTarget();
|
if (context.getExceptionTag() == null) {
|
||||||
var breakExpr = new WasmBreak(target);
|
var target = throwJumpTarget();
|
||||||
if (target != rethrowBlock) {
|
var breakExpr = new WasmBreak(target);
|
||||||
breakExpr.setResult(generateGetHandlerId(callSiteId, expr.getLocation()));
|
if (target != rethrowBlock) {
|
||||||
|
breakExpr.setResult(generateGetHandlerId(callSiteId, expr.getLocation()));
|
||||||
|
}
|
||||||
|
block.getBody().add(breakExpr);
|
||||||
|
} else {
|
||||||
|
block.getBody().add(new WasmUnreachable());
|
||||||
}
|
}
|
||||||
block.getBody().add(breakExpr);
|
|
||||||
|
|
||||||
valueToCast.release();
|
valueToCast.release();
|
||||||
result = block;
|
result = block;
|
||||||
|
@ -1743,7 +1768,9 @@ class WasmGenerationVisitor implements StatementVisitor, ExprVisitor {
|
||||||
var callSiteId = generateCallSiteId(statement.getLocation());
|
var callSiteId = generateCallSiteId(statement.getLocation());
|
||||||
resultConsumer.add(generateRegisterCallSite(callSiteId, statement.getLocation()));
|
resultConsumer.add(generateRegisterCallSite(callSiteId, statement.getLocation()));
|
||||||
resultConsumer.add(call);
|
resultConsumer.add(call);
|
||||||
checkHandlerId(resultConsumer, callSiteId, statement.getLocation());
|
if (context.getExceptionTag() == null) {
|
||||||
|
checkHandlerId(resultConsumer, callSiteId, statement.getLocation());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1771,6 +1798,14 @@ class WasmGenerationVisitor implements StatementVisitor, ExprVisitor {
|
||||||
}
|
}
|
||||||
tryCatchStatements.add(statement);
|
tryCatchStatements.add(statement);
|
||||||
|
|
||||||
|
if (context.getExceptionTag() == null) {
|
||||||
|
emulatedTry(tryCatchStatements, statement.getProtectedBody());
|
||||||
|
} else {
|
||||||
|
builtInTry(tryCatchStatements, statement.getProtectedBody());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void emulatedTry(List<TryCatchStatement> tryCatchStatements, List<Statement> protectedBody) {
|
||||||
int firstId = handlers.size();
|
int firstId = handlers.size();
|
||||||
|
|
||||||
var innerCatchBlock = new WasmBlock(false);
|
var innerCatchBlock = new WasmBlock(false);
|
||||||
|
@ -1794,7 +1829,7 @@ class WasmGenerationVisitor implements StatementVisitor, ExprVisitor {
|
||||||
|
|
||||||
var lastTryBlockBackup = lastTryBlock;
|
var lastTryBlockBackup = lastTryBlock;
|
||||||
lastTryBlock = bodyBlock;
|
lastTryBlock = bodyBlock;
|
||||||
visitMany(statement.getProtectedBody(), bodyBlock.getBody());
|
visitMany(protectedBody, bodyBlock.getBody());
|
||||||
lastTryBlock = lastTryBlockBackup;
|
lastTryBlock = lastTryBlockBackup;
|
||||||
handlers.subList(firstId, handlers.size()).clear();
|
handlers.subList(firstId, handlers.size()).clear();
|
||||||
|
|
||||||
|
@ -1834,6 +1869,69 @@ class WasmGenerationVisitor implements StatementVisitor, ExprVisitor {
|
||||||
resultConsumer.add(outerCatchBlock);
|
resultConsumer.add(outerCatchBlock);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void builtInTry(List<TryCatchStatement> tryCatchStatements, List<Statement> protectedBody) {
|
||||||
|
var innerCatchBlock = new WasmBlock(false);
|
||||||
|
|
||||||
|
var catchBlocks = new ArrayList<WasmBlock>();
|
||||||
|
for (int i = 0; i < tryCatchStatements.size(); ++i) {
|
||||||
|
catchBlocks.add(new WasmBlock(false));
|
||||||
|
}
|
||||||
|
var outerCatchBlock = catchBlocks.get(0);
|
||||||
|
|
||||||
|
var tryBlock = new WasmTry();
|
||||||
|
visitMany(protectedBody, tryBlock.getBody());
|
||||||
|
if (!tryBlock.isTerminating()) {
|
||||||
|
tryBlock.getBody().add(new WasmBreak(outerCatchBlock));
|
||||||
|
}
|
||||||
|
var catchClause = new WasmCatch(context.getExceptionTag());
|
||||||
|
tryBlock.getCatches().add(catchClause);
|
||||||
|
innerCatchBlock.getBody().add(tryBlock);
|
||||||
|
|
||||||
|
var obj = exprCache.create(new WasmCall(context.names.forMethod(PEEK_EXCEPTION_METHOD)), WasmType.INT32,
|
||||||
|
null, innerCatchBlock.getBody());
|
||||||
|
var currentBlock = innerCatchBlock;
|
||||||
|
boolean catchesAll = false;
|
||||||
|
for (int i = tryCatchStatements.size() - 1; i >= 0; --i) {
|
||||||
|
var tryCatch = tryCatchStatements.get(i);
|
||||||
|
var catchBlock = catchBlocks.get(i);
|
||||||
|
if (tryCatch.getExceptionType() != null && !tryCatch.getExceptionType().equals(Throwable.class.getName())) {
|
||||||
|
var exceptionType = ValueType.object(tryCatch.getExceptionType());
|
||||||
|
classGenerator.getClassPointer(exceptionType);
|
||||||
|
var isMatched = instanceOfImpl(obj.expr(), exceptionType);
|
||||||
|
innerCatchBlock.getBody().add(new WasmBranch(isMatched, currentBlock));
|
||||||
|
} else {
|
||||||
|
innerCatchBlock.getBody().add(new WasmBreak(currentBlock));
|
||||||
|
catchesAll = true;
|
||||||
|
}
|
||||||
|
currentBlock = catchBlock;
|
||||||
|
}
|
||||||
|
if (!catchesAll) {
|
||||||
|
innerCatchBlock.getBody().add(new WasmThrow(context.getExceptionTag()));
|
||||||
|
}
|
||||||
|
obj.release();
|
||||||
|
|
||||||
|
currentBlock = innerCatchBlock;
|
||||||
|
for (int i = tryCatchStatements.size() - 1; i >= 0; --i) {
|
||||||
|
var tryCatch = tryCatchStatements.get(i);
|
||||||
|
var catchBlock = catchBlocks.get(i);
|
||||||
|
catchBlock.getBody().add(currentBlock);
|
||||||
|
|
||||||
|
var catchMethodName = context.names.forMethod(CATCH_METHOD);
|
||||||
|
var catchCall = new WasmCall(catchMethodName);
|
||||||
|
var catchWrapper = tryCatch.getExceptionVariable() != null
|
||||||
|
? new WasmSetLocal(localVar(tryCatch.getExceptionVariable()), catchCall)
|
||||||
|
: new WasmDrop(catchCall);
|
||||||
|
catchBlock.getBody().add(catchWrapper);
|
||||||
|
visitMany(tryCatch.getHandler(), catchBlock.getBody());
|
||||||
|
if (!catchBlock.isTerminating() && catchBlock != outerCatchBlock) {
|
||||||
|
catchBlock.getBody().add(new WasmBreak(outerCatchBlock));
|
||||||
|
}
|
||||||
|
currentBlock = catchBlock;
|
||||||
|
}
|
||||||
|
|
||||||
|
resultConsumer.add(outerCatchBlock);
|
||||||
|
}
|
||||||
|
|
||||||
private WasmBlock rethrowBlock() {
|
private WasmBlock rethrowBlock() {
|
||||||
if (rethrowBlock == null) {
|
if (rethrowBlock == null) {
|
||||||
rethrowBlock = new WasmBlock(false);
|
rethrowBlock = new WasmBlock(false);
|
||||||
|
@ -1924,11 +2022,15 @@ class WasmGenerationVisitor implements StatementVisitor, ExprVisitor {
|
||||||
var callSiteId = generateCallSiteId(expr.getLocation());
|
var callSiteId = generateCallSiteId(expr.getLocation());
|
||||||
block.getBody().add(generateRegisterCallSite(callSiteId, expr.getLocation()));
|
block.getBody().add(generateRegisterCallSite(callSiteId, expr.getLocation()));
|
||||||
block.getBody().add(new WasmCall(context.names.forMethod(THROW_AIOOBE_METHOD)));
|
block.getBody().add(new WasmCall(context.names.forMethod(THROW_AIOOBE_METHOD)));
|
||||||
var br = new WasmBreak(throwJumpTarget());
|
if (context.getExceptionTag() == null) {
|
||||||
if (br.getTarget() != rethrowBlock) {
|
var br = new WasmBreak(throwJumpTarget());
|
||||||
br.setResult(generateGetHandlerId(callSiteId, expr.getLocation()));
|
if (br.getTarget() != rethrowBlock) {
|
||||||
|
br.setResult(generateGetHandlerId(callSiteId, expr.getLocation()));
|
||||||
|
}
|
||||||
|
block.getBody().add(br);
|
||||||
|
} else {
|
||||||
|
block.getBody().add(new WasmUnreachable());
|
||||||
}
|
}
|
||||||
block.getBody().add(br);
|
|
||||||
|
|
||||||
result = block;
|
result = block;
|
||||||
}
|
}
|
||||||
|
@ -2154,6 +2256,11 @@ class WasmGenerationVisitor implements StatementVisitor, ExprVisitor {
|
||||||
public WasmExpression generateRegisterCallSite(int callSite, TextLocation location) {
|
public WasmExpression generateRegisterCallSite(int callSite, TextLocation location) {
|
||||||
return WasmGenerationVisitor.this.generateRegisterCallSite(callSite, location);
|
return WasmGenerationVisitor.this.generateRegisterCallSite(callSite, location);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public WasmTag getExceptionTag() {
|
||||||
|
return context.getExceptionTag();
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
private WasmExpression getReferenceToClass(WasmExpression instance) {
|
private WasmExpression getReferenceToClass(WasmExpression instance) {
|
||||||
|
|
|
@ -24,6 +24,7 @@ import org.teavm.backend.wasm.binary.BinaryWriter;
|
||||||
import org.teavm.backend.wasm.debug.info.VariableType;
|
import org.teavm.backend.wasm.debug.info.VariableType;
|
||||||
import org.teavm.backend.wasm.model.WasmFunction;
|
import org.teavm.backend.wasm.model.WasmFunction;
|
||||||
import org.teavm.backend.wasm.model.WasmLocal;
|
import org.teavm.backend.wasm.model.WasmLocal;
|
||||||
|
import org.teavm.backend.wasm.model.WasmTag;
|
||||||
import org.teavm.backend.wasm.model.WasmType;
|
import org.teavm.backend.wasm.model.WasmType;
|
||||||
import org.teavm.interop.Export;
|
import org.teavm.interop.Export;
|
||||||
import org.teavm.model.AnnotationReader;
|
import org.teavm.model.AnnotationReader;
|
||||||
|
@ -42,6 +43,7 @@ public class WasmGenerator {
|
||||||
private BinaryWriter binaryWriter;
|
private BinaryWriter binaryWriter;
|
||||||
private NameProvider names;
|
private NameProvider names;
|
||||||
private Predicate<MethodReference> asyncMethods;
|
private Predicate<MethodReference> asyncMethods;
|
||||||
|
private WasmTag exceptionTag;
|
||||||
|
|
||||||
public WasmGenerator(Decompiler decompiler, ClassHolderSource classSource,
|
public WasmGenerator(Decompiler decompiler, ClassHolderSource classSource,
|
||||||
WasmGenerationContext context, WasmClassGenerator classGenerator, BinaryWriter binaryWriter,
|
WasmGenerationContext context, WasmClassGenerator classGenerator, BinaryWriter binaryWriter,
|
||||||
|
|
|
@ -30,6 +30,7 @@ import org.teavm.backend.wasm.model.expression.WasmIntBinary;
|
||||||
import org.teavm.backend.wasm.model.expression.WasmIntBinaryOperation;
|
import org.teavm.backend.wasm.model.expression.WasmIntBinaryOperation;
|
||||||
import org.teavm.backend.wasm.model.expression.WasmIntType;
|
import org.teavm.backend.wasm.model.expression.WasmIntType;
|
||||||
import org.teavm.backend.wasm.model.expression.WasmStoreInt32;
|
import org.teavm.backend.wasm.model.expression.WasmStoreInt32;
|
||||||
|
import org.teavm.backend.wasm.model.expression.WasmThrow;
|
||||||
import org.teavm.backend.wasm.model.expression.WasmUnreachable;
|
import org.teavm.backend.wasm.model.expression.WasmUnreachable;
|
||||||
import org.teavm.model.FieldReference;
|
import org.teavm.model.FieldReference;
|
||||||
import org.teavm.model.MethodReference;
|
import org.teavm.model.MethodReference;
|
||||||
|
@ -59,6 +60,7 @@ public class ExceptionHandlingIntrinsic implements WasmIntrinsic {
|
||||||
case "jumpToFrame":
|
case "jumpToFrame":
|
||||||
case "abort":
|
case "abort":
|
||||||
case "isObfuscated":
|
case "isObfuscated":
|
||||||
|
case "throwExceptionPlatformNative":
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
|
@ -101,6 +103,9 @@ public class ExceptionHandlingIntrinsic implements WasmIntrinsic {
|
||||||
case "abort":
|
case "abort":
|
||||||
return new WasmUnreachable();
|
return new WasmUnreachable();
|
||||||
|
|
||||||
|
case "throwExceptionPlatformNative":
|
||||||
|
return new WasmThrow(manager.getExceptionTag());
|
||||||
|
|
||||||
default:
|
default:
|
||||||
throw new IllegalArgumentException("Unknown method: " + invocation.getMethod());
|
throw new IllegalArgumentException("Unknown method: " + invocation.getMethod());
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,6 +20,7 @@ import org.teavm.backend.lowlevel.generate.NameProvider;
|
||||||
import org.teavm.backend.wasm.binary.BinaryWriter;
|
import org.teavm.backend.wasm.binary.BinaryWriter;
|
||||||
import org.teavm.backend.wasm.generate.WasmStringPool;
|
import org.teavm.backend.wasm.generate.WasmStringPool;
|
||||||
import org.teavm.backend.wasm.model.WasmLocal;
|
import org.teavm.backend.wasm.model.WasmLocal;
|
||||||
|
import org.teavm.backend.wasm.model.WasmTag;
|
||||||
import org.teavm.backend.wasm.model.WasmType;
|
import org.teavm.backend.wasm.model.WasmType;
|
||||||
import org.teavm.backend.wasm.model.expression.WasmExpression;
|
import org.teavm.backend.wasm.model.expression.WasmExpression;
|
||||||
import org.teavm.diagnostics.Diagnostics;
|
import org.teavm.diagnostics.Diagnostics;
|
||||||
|
@ -55,5 +56,5 @@ public interface WasmIntrinsicManager {
|
||||||
|
|
||||||
WasmExpression generateRegisterCallSite(int callSite, TextLocation location);
|
WasmExpression generateRegisterCallSite(int callSite, TextLocation location);
|
||||||
|
|
||||||
|
WasmTag getExceptionTag();
|
||||||
}
|
}
|
||||||
|
|
|
@ -31,6 +31,8 @@ public class WasmModule {
|
||||||
private WasmFunction startFunction;
|
private WasmFunction startFunction;
|
||||||
private Map<String, WasmCustomSection> customSections = new LinkedHashMap<>();
|
private Map<String, WasmCustomSection> customSections = new LinkedHashMap<>();
|
||||||
private Map<String, WasmCustomSection> readonlyCustomSections = Collections.unmodifiableMap(customSections);
|
private Map<String, WasmCustomSection> readonlyCustomSections = Collections.unmodifiableMap(customSections);
|
||||||
|
private List<WasmTag> tags = new ArrayList<>();
|
||||||
|
private List<? extends WasmTag> readonlyTags = Collections.unmodifiableList(tags);
|
||||||
|
|
||||||
public void add(WasmFunction function) {
|
public void add(WasmFunction function) {
|
||||||
if (functions.containsKey(function.getName())) {
|
if (functions.containsKey(function.getName())) {
|
||||||
|
@ -110,4 +112,17 @@ public class WasmModule {
|
||||||
public void setStartFunction(WasmFunction startFunction) {
|
public void setStartFunction(WasmFunction startFunction) {
|
||||||
this.startFunction = startFunction;
|
this.startFunction = startFunction;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void addTag(WasmTag tag) {
|
||||||
|
if (tag.module != null) {
|
||||||
|
throw new IllegalArgumentException("Given tag already belongs to some module");
|
||||||
|
}
|
||||||
|
tags.add(tag);
|
||||||
|
tag.module = this;
|
||||||
|
tag.index = tags.size() - 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<? extends WasmTag> getTags() {
|
||||||
|
return tags;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
33
core/src/main/java/org/teavm/backend/wasm/model/WasmTag.java
Normal file
33
core/src/main/java/org/teavm/backend/wasm/model/WasmTag.java
Normal file
|
@ -0,0 +1,33 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2024 Alexey Andreev.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package org.teavm.backend.wasm.model;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class WasmTag {
|
||||||
|
private List<WasmType> values = new ArrayList<>();
|
||||||
|
WasmModule module;
|
||||||
|
int index;
|
||||||
|
|
||||||
|
public List<WasmType> getValues() {
|
||||||
|
return values;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getIndex() {
|
||||||
|
return index;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,43 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2024 Alexey Andreev.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package org.teavm.backend.wasm.model.expression;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Objects;
|
||||||
|
import org.teavm.backend.wasm.model.WasmTag;
|
||||||
|
|
||||||
|
public class WasmCatch {
|
||||||
|
private WasmTag tag;
|
||||||
|
private List<WasmExpression> body = new ArrayList<>();
|
||||||
|
|
||||||
|
public WasmCatch(WasmTag tag) {
|
||||||
|
Objects.requireNonNull(tag);
|
||||||
|
this.tag = tag;
|
||||||
|
}
|
||||||
|
|
||||||
|
public WasmTag getTag() {
|
||||||
|
return tag;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setTag(WasmTag tag) {
|
||||||
|
this.tag = tag;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<WasmExpression> getBody() {
|
||||||
|
return body;
|
||||||
|
}
|
||||||
|
}
|
|
@ -199,4 +199,23 @@ public class WasmDefaultExpressionVisitor implements WasmExpressionVisitor {
|
||||||
expression.getSourceIndex().acceptVisitor(this);
|
expression.getSourceIndex().acceptVisitor(this);
|
||||||
expression.getCount().acceptVisitor(this);
|
expression.getCount().acceptVisitor(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void visit(WasmTry expression) {
|
||||||
|
for (var part : expression.getBody()) {
|
||||||
|
part.acceptVisitor(this);
|
||||||
|
}
|
||||||
|
for (var catchClause : expression.getCatches()) {
|
||||||
|
for (var part : catchClause.getBody()) {
|
||||||
|
part.acceptVisitor(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void visit(WasmThrow expression) {
|
||||||
|
for (var arg : expression.getArguments()) {
|
||||||
|
arg.acceptVisitor(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -79,4 +79,8 @@ public interface WasmExpressionVisitor {
|
||||||
void visit(WasmFill expression);
|
void visit(WasmFill expression);
|
||||||
|
|
||||||
void visit(WasmCopy expression);
|
void visit(WasmCopy expression);
|
||||||
|
|
||||||
|
void visit(WasmTry expression);
|
||||||
|
|
||||||
|
void visit(WasmThrow expression);
|
||||||
}
|
}
|
||||||
|
|
|
@ -251,4 +251,17 @@ public class WasmReplacingExpressionVisitor implements WasmExpressionVisitor {
|
||||||
expression.getCount().acceptVisitor(this);
|
expression.getCount().acceptVisitor(this);
|
||||||
expression.setCount(mapper.apply(expression.getCount()));
|
expression.setCount(mapper.apply(expression.getCount()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void visit(WasmTry expression) {
|
||||||
|
replaceExpressions(expression.getBody());
|
||||||
|
for (var catchClause : expression.getCatches()) {
|
||||||
|
replaceExpressions(catchClause.getBody());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void visit(WasmThrow expression) {
|
||||||
|
replaceExpressions(expression.getArguments());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,46 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2024 Alexey Andreev.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package org.teavm.backend.wasm.model.expression;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import org.teavm.backend.wasm.model.WasmTag;
|
||||||
|
|
||||||
|
public class WasmThrow extends WasmExpression {
|
||||||
|
private WasmTag tag;
|
||||||
|
private List<WasmExpression> arguments = new ArrayList<>();
|
||||||
|
|
||||||
|
public WasmThrow(WasmTag tag) {
|
||||||
|
this.tag = tag;
|
||||||
|
}
|
||||||
|
|
||||||
|
public WasmTag getTag() {
|
||||||
|
return tag;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setTag(WasmTag tag) {
|
||||||
|
this.tag = tag;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<WasmExpression> getArguments() {
|
||||||
|
return arguments;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void acceptVisitor(WasmExpressionVisitor visitor) {
|
||||||
|
visitor.visit(this);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,52 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2024 Alexey Andreev.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package org.teavm.backend.wasm.model.expression;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import org.teavm.backend.wasm.model.WasmType;
|
||||||
|
|
||||||
|
public class WasmTry extends WasmExpression {
|
||||||
|
private List<WasmExpression> body = new ArrayList<>();
|
||||||
|
private List<WasmCatch> catches = new ArrayList<>();
|
||||||
|
private WasmType type;
|
||||||
|
|
||||||
|
public List<WasmExpression> getBody() {
|
||||||
|
return body;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<WasmCatch> getCatches() {
|
||||||
|
return catches;
|
||||||
|
}
|
||||||
|
|
||||||
|
public WasmType getType() {
|
||||||
|
return type;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setType(WasmType type) {
|
||||||
|
this.type = type;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void acceptVisitor(WasmExpressionVisitor visitor) {
|
||||||
|
visitor.visit(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isTerminating() {
|
||||||
|
return !body.isEmpty() && body.get(body.size() - 1).isTerminating();
|
||||||
|
}
|
||||||
|
}
|
|
@ -46,6 +46,7 @@ public class WasmBinaryRenderer {
|
||||||
private static final int SECTION_ELEMENT = 9;
|
private static final int SECTION_ELEMENT = 9;
|
||||||
private static final int SECTION_CODE = 10;
|
private static final int SECTION_CODE = 10;
|
||||||
private static final int SECTION_DATA = 11;
|
private static final int SECTION_DATA = 11;
|
||||||
|
private static final int SECTION_TAGS = 13;
|
||||||
|
|
||||||
private static final int EXTERNAL_KIND_FUNCTION = 0;
|
private static final int EXTERNAL_KIND_FUNCTION = 0;
|
||||||
private static final int EXTERNAL_KIND_MEMORY = 2;
|
private static final int EXTERNAL_KIND_MEMORY = 2;
|
||||||
|
@ -92,6 +93,7 @@ public class WasmBinaryRenderer {
|
||||||
renderFunctions(module);
|
renderFunctions(module);
|
||||||
renderTable(module);
|
renderTable(module);
|
||||||
renderMemory(module);
|
renderMemory(module);
|
||||||
|
renderTags(module);
|
||||||
renderExport(module);
|
renderExport(module);
|
||||||
renderStart(module);
|
renderStart(module);
|
||||||
renderElement(module);
|
renderElement(module);
|
||||||
|
@ -113,6 +115,9 @@ public class WasmBinaryRenderer {
|
||||||
part.acceptVisitor(signatureCollector);
|
part.acceptVisitor(signatureCollector);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
for (var tag : module.getTags()) {
|
||||||
|
registerSignature(WasmSignature.fromTag(tag));
|
||||||
|
}
|
||||||
|
|
||||||
section.writeLEB(signatures.size());
|
section.writeLEB(signatures.size());
|
||||||
for (WasmSignature signature : signatures) {
|
for (WasmSignature signature : signatures) {
|
||||||
|
@ -394,6 +399,21 @@ public class WasmBinaryRenderer {
|
||||||
writeSection(SECTION_DATA, "data", section.getData());
|
writeSection(SECTION_DATA, "data", section.getData());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void renderTags(WasmModule module) {
|
||||||
|
if (module.getTags().isEmpty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var section = new WasmBinaryWriter();
|
||||||
|
section.writeLEB(module.getTags().size());
|
||||||
|
for (var tag : module.getTags()) {
|
||||||
|
section.writeByte(0);
|
||||||
|
section.writeLEB(signatureIndexes.get(WasmSignature.fromTag(tag)));
|
||||||
|
}
|
||||||
|
|
||||||
|
writeSection(SECTION_TAGS, "tags", section.getData());
|
||||||
|
}
|
||||||
|
|
||||||
private void renderNames(WasmModule module) {
|
private void renderNames(WasmModule module) {
|
||||||
WasmBinaryWriter section = new WasmBinaryWriter();
|
WasmBinaryWriter section = new WasmBinaryWriter();
|
||||||
|
|
||||||
|
|
|
@ -57,6 +57,8 @@ import org.teavm.backend.wasm.model.expression.WasmStoreFloat64;
|
||||||
import org.teavm.backend.wasm.model.expression.WasmStoreInt32;
|
import org.teavm.backend.wasm.model.expression.WasmStoreInt32;
|
||||||
import org.teavm.backend.wasm.model.expression.WasmStoreInt64;
|
import org.teavm.backend.wasm.model.expression.WasmStoreInt64;
|
||||||
import org.teavm.backend.wasm.model.expression.WasmSwitch;
|
import org.teavm.backend.wasm.model.expression.WasmSwitch;
|
||||||
|
import org.teavm.backend.wasm.model.expression.WasmThrow;
|
||||||
|
import org.teavm.backend.wasm.model.expression.WasmTry;
|
||||||
import org.teavm.backend.wasm.model.expression.WasmUnreachable;
|
import org.teavm.backend.wasm.model.expression.WasmUnreachable;
|
||||||
import org.teavm.model.MethodReference;
|
import org.teavm.model.MethodReference;
|
||||||
import org.teavm.model.TextLocation;
|
import org.teavm.model.TextLocation;
|
||||||
|
@ -931,6 +933,7 @@ class WasmBinaryRenderingVisitor implements WasmExpressionVisitor {
|
||||||
writer.writeByte(0xFC);
|
writer.writeByte(0xFC);
|
||||||
writer.writeLEB(11);
|
writer.writeLEB(11);
|
||||||
writer.writeByte(0);
|
writer.writeByte(0);
|
||||||
|
popLocation();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -943,6 +946,38 @@ class WasmBinaryRenderingVisitor implements WasmExpressionVisitor {
|
||||||
writer.writeLEB(10);
|
writer.writeLEB(10);
|
||||||
writer.writeByte(0);
|
writer.writeByte(0);
|
||||||
writer.writeByte(0);
|
writer.writeByte(0);
|
||||||
|
popLocation();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void visit(WasmTry expression) {
|
||||||
|
pushLocation(expression);
|
||||||
|
writer.writeByte(0x06);
|
||||||
|
writeBlockType(expression.getType());
|
||||||
|
++depth;
|
||||||
|
for (var part : expression.getBody()) {
|
||||||
|
part.acceptVisitor(this);
|
||||||
|
}
|
||||||
|
--depth;
|
||||||
|
for (var catchClause : expression.getCatches()) {
|
||||||
|
writer.writeByte(0x07);
|
||||||
|
writer.writeLEB(catchClause.getTag().getIndex());
|
||||||
|
for (var part : catchClause.getBody()) {
|
||||||
|
part.acceptVisitor(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
writer.writeByte(0xB);
|
||||||
|
popLocation();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void visit(WasmThrow expression) {
|
||||||
|
for (var arg : expression.getArguments()) {
|
||||||
|
arg.acceptVisitor(this);
|
||||||
|
}
|
||||||
|
pushLocation(expression);
|
||||||
|
writer.writeByte(0x8);
|
||||||
|
writer.writeLEB(expression.getTag().getIndex());
|
||||||
}
|
}
|
||||||
|
|
||||||
private int alignment(int value) {
|
private int alignment(int value) {
|
||||||
|
|
|
@ -61,6 +61,8 @@ import org.teavm.backend.wasm.model.expression.WasmStoreFloat64;
|
||||||
import org.teavm.backend.wasm.model.expression.WasmStoreInt32;
|
import org.teavm.backend.wasm.model.expression.WasmStoreInt32;
|
||||||
import org.teavm.backend.wasm.model.expression.WasmStoreInt64;
|
import org.teavm.backend.wasm.model.expression.WasmStoreInt64;
|
||||||
import org.teavm.backend.wasm.model.expression.WasmSwitch;
|
import org.teavm.backend.wasm.model.expression.WasmSwitch;
|
||||||
|
import org.teavm.backend.wasm.model.expression.WasmThrow;
|
||||||
|
import org.teavm.backend.wasm.model.expression.WasmTry;
|
||||||
import org.teavm.backend.wasm.model.expression.WasmUnreachable;
|
import org.teavm.backend.wasm.model.expression.WasmUnreachable;
|
||||||
import org.teavm.model.TextLocation;
|
import org.teavm.model.TextLocation;
|
||||||
|
|
||||||
|
@ -1110,6 +1112,16 @@ class WasmCRenderingVisitor implements WasmExpressionVisitor {
|
||||||
value = result;
|
value = result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void visit(WasmTry expression) {
|
||||||
|
value = new CExpression("/* TRY */");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void visit(WasmThrow expression) {
|
||||||
|
value = new CExpression("/* THROW */");
|
||||||
|
}
|
||||||
|
|
||||||
private CExpression checkAddress(CExpression index) {
|
private CExpression checkAddress(CExpression index) {
|
||||||
if (!memoryAccessChecked) {
|
if (!memoryAccessChecked) {
|
||||||
return index;
|
return index;
|
||||||
|
|
|
@ -61,6 +61,8 @@ import org.teavm.backend.wasm.model.expression.WasmStoreFloat64;
|
||||||
import org.teavm.backend.wasm.model.expression.WasmStoreInt32;
|
import org.teavm.backend.wasm.model.expression.WasmStoreInt32;
|
||||||
import org.teavm.backend.wasm.model.expression.WasmStoreInt64;
|
import org.teavm.backend.wasm.model.expression.WasmStoreInt64;
|
||||||
import org.teavm.backend.wasm.model.expression.WasmSwitch;
|
import org.teavm.backend.wasm.model.expression.WasmSwitch;
|
||||||
|
import org.teavm.backend.wasm.model.expression.WasmThrow;
|
||||||
|
import org.teavm.backend.wasm.model.expression.WasmTry;
|
||||||
import org.teavm.backend.wasm.model.expression.WasmUnreachable;
|
import org.teavm.backend.wasm.model.expression.WasmUnreachable;
|
||||||
|
|
||||||
class WasmRenderingVisitor implements WasmExpressionVisitor {
|
class WasmRenderingVisitor implements WasmExpressionVisitor {
|
||||||
|
@ -620,6 +622,37 @@ class WasmRenderingVisitor implements WasmExpressionVisitor {
|
||||||
close();
|
close();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void visit(WasmTry expression) {
|
||||||
|
open().append("try");
|
||||||
|
if (expression.getType() != null) {
|
||||||
|
append(" " + type(expression.getType()));
|
||||||
|
}
|
||||||
|
for (var part : expression.getBody()) {
|
||||||
|
line(part);
|
||||||
|
}
|
||||||
|
for (var catchClause : expression.getCatches()) {
|
||||||
|
lf().append("(catch ").append(String.valueOf(catchClause.getTag().getIndex()))
|
||||||
|
.append(" ").indent();
|
||||||
|
for (var part : catchClause.getBody()) {
|
||||||
|
line(part);
|
||||||
|
}
|
||||||
|
lf().outdent().append(")");
|
||||||
|
}
|
||||||
|
|
||||||
|
close();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void visit(WasmThrow expression) {
|
||||||
|
open().append("throw");
|
||||||
|
append(" ").append(String.valueOf(expression.getTag().getIndex()));
|
||||||
|
for (var arg : expression.getArguments()) {
|
||||||
|
line(arg);
|
||||||
|
}
|
||||||
|
close();
|
||||||
|
}
|
||||||
|
|
||||||
private String type(WasmType type) {
|
private String type(WasmType type) {
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case INT32:
|
case INT32:
|
||||||
|
|
|
@ -17,6 +17,7 @@ package org.teavm.backend.wasm.render;
|
||||||
|
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import org.teavm.backend.wasm.model.WasmFunction;
|
import org.teavm.backend.wasm.model.WasmFunction;
|
||||||
|
import org.teavm.backend.wasm.model.WasmTag;
|
||||||
import org.teavm.backend.wasm.model.WasmType;
|
import org.teavm.backend.wasm.model.WasmType;
|
||||||
|
|
||||||
final class WasmSignature {
|
final class WasmSignature {
|
||||||
|
@ -43,7 +44,7 @@ final class WasmSignature {
|
||||||
return Arrays.hashCode(types);
|
return Arrays.hashCode(types);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static WasmSignature fromFunction(WasmFunction function) {
|
static WasmSignature fromFunction(WasmFunction function) {
|
||||||
WasmType[] types = new WasmType[function.getParameters().size() + 1];
|
WasmType[] types = new WasmType[function.getParameters().size() + 1];
|
||||||
types[0] = function.getResult();
|
types[0] = function.getResult();
|
||||||
for (int i = 0; i < function.getParameters().size(); ++i) {
|
for (int i = 0; i < function.getParameters().size(); ++i) {
|
||||||
|
@ -51,4 +52,12 @@ final class WasmSignature {
|
||||||
}
|
}
|
||||||
return new WasmSignature(types);
|
return new WasmSignature(types);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static WasmSignature fromTag(WasmTag tag) {
|
||||||
|
var types = new WasmType[tag.getValues().size() + 1];
|
||||||
|
for (var i = 0; i < tag.getValues().size(); i++) {
|
||||||
|
types[i + 1] = tag.getValues().get(i);
|
||||||
|
}
|
||||||
|
return new WasmSignature(types);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -52,6 +52,8 @@ import org.teavm.backend.wasm.model.expression.WasmStoreFloat64;
|
||||||
import org.teavm.backend.wasm.model.expression.WasmStoreInt32;
|
import org.teavm.backend.wasm.model.expression.WasmStoreInt32;
|
||||||
import org.teavm.backend.wasm.model.expression.WasmStoreInt64;
|
import org.teavm.backend.wasm.model.expression.WasmStoreInt64;
|
||||||
import org.teavm.backend.wasm.model.expression.WasmSwitch;
|
import org.teavm.backend.wasm.model.expression.WasmSwitch;
|
||||||
|
import org.teavm.backend.wasm.model.expression.WasmThrow;
|
||||||
|
import org.teavm.backend.wasm.model.expression.WasmTry;
|
||||||
import org.teavm.backend.wasm.model.expression.WasmUnreachable;
|
import org.teavm.backend.wasm.model.expression.WasmUnreachable;
|
||||||
|
|
||||||
public class WasmTypeInference implements WasmExpressionVisitor {
|
public class WasmTypeInference implements WasmExpressionVisitor {
|
||||||
|
@ -227,6 +229,16 @@ public class WasmTypeInference implements WasmExpressionVisitor {
|
||||||
result = null;
|
result = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void visit(WasmTry expression) {
|
||||||
|
result = expression.getType();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void visit(WasmThrow expression) {
|
||||||
|
result = null;
|
||||||
|
}
|
||||||
|
|
||||||
private static WasmType map(WasmIntType type) {
|
private static WasmType map(WasmIntType type) {
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case INT32:
|
case INT32:
|
||||||
|
|
|
@ -0,0 +1,41 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2024 Alexey Andreev.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package org.teavm.backend.wasm.transformation;
|
||||||
|
|
||||||
|
import org.teavm.model.ClassHolder;
|
||||||
|
import org.teavm.model.ClassHolderTransformer;
|
||||||
|
import org.teavm.model.ClassHolderTransformerContext;
|
||||||
|
import org.teavm.model.MethodDescriptor;
|
||||||
|
import org.teavm.model.MethodReference;
|
||||||
|
import org.teavm.model.emit.ProgramEmitter;
|
||||||
|
import org.teavm.runtime.ExceptionHandling;
|
||||||
|
|
||||||
|
public class WasmExceptionHandlingTransform implements ClassHolderTransformer {
|
||||||
|
@Override
|
||||||
|
public void transformClass(ClassHolder cls, ClassHolderTransformerContext context) {
|
||||||
|
if (cls.getName().equals(ExceptionHandling.class.getName())) {
|
||||||
|
processClass(cls, context);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void processClass(ClassHolder cls, ClassHolderTransformerContext context) {
|
||||||
|
var method = cls.getMethod(new MethodDescriptor("throwException", Throwable.class, void.class));
|
||||||
|
var pm = ProgramEmitter.create(method, context.getHierarchy());
|
||||||
|
pm.invoke(new MethodReference(ExceptionHandling.class, "throwExceptionPlatform", Throwable.class, void.class),
|
||||||
|
pm.var(1, Throwable.class));
|
||||||
|
pm.exit();
|
||||||
|
}
|
||||||
|
}
|
|
@ -90,6 +90,20 @@ public final class ExceptionHandling {
|
||||||
return exception;
|
return exception;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Unmanaged
|
||||||
|
public static Throwable peekException() {
|
||||||
|
return thrownException;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Unmanaged
|
||||||
|
public static void throwExceptionPlatform(Throwable exception) {
|
||||||
|
thrownException = exception;
|
||||||
|
throwExceptionPlatformNative();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Unmanaged
|
||||||
|
public static native void throwExceptionPlatformNative();
|
||||||
|
|
||||||
@Unmanaged
|
@Unmanaged
|
||||||
public static void throwException(Throwable exception) {
|
public static void throwException(Throwable exception) {
|
||||||
thrownException = exception;
|
thrownException = exception;
|
||||||
|
|
|
@ -127,6 +127,10 @@ public final class TeaVMRunner {
|
||||||
.hasArg()
|
.hasArg()
|
||||||
.desc("WebAssembly binary version (currently, only 1 is supported)")
|
.desc("WebAssembly binary version (currently, only 1 is supported)")
|
||||||
.build());
|
.build());
|
||||||
|
options.addOption(Option.builder()
|
||||||
|
.longOpt("wasm-use-exceptions")
|
||||||
|
.desc("Specifies that WebAssembly exception handling instructions can be used")
|
||||||
|
.build());
|
||||||
options.addOption(Option.builder("e")
|
options.addOption(Option.builder("e")
|
||||||
.longOpt("entry-point")
|
.longOpt("entry-point")
|
||||||
.argName("name")
|
.argName("name")
|
||||||
|
@ -352,6 +356,9 @@ public final class TeaVMRunner {
|
||||||
printUsage();
|
printUsage();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (commandLine.hasOption("wasm-use-exceptions")) {
|
||||||
|
tool.setWasmExceptionsUsed(true);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void parseCOptions() {
|
private void parseCOptions() {
|
||||||
|
|
|
@ -107,6 +107,7 @@ public class TeaVMTool {
|
||||||
private JavaScriptTarget javaScriptTarget;
|
private JavaScriptTarget javaScriptTarget;
|
||||||
private WasmTarget webAssemblyTarget;
|
private WasmTarget webAssemblyTarget;
|
||||||
private WasmBinaryVersion wasmVersion = WasmBinaryVersion.V_0x1;
|
private WasmBinaryVersion wasmVersion = WasmBinaryVersion.V_0x1;
|
||||||
|
private boolean wasmExceptionsUsed;
|
||||||
private CTarget cTarget;
|
private CTarget cTarget;
|
||||||
private Set<File> generatedFiles = new HashSet<>();
|
private Set<File> generatedFiles = new HashSet<>();
|
||||||
private int minHeapSize = 4 * (1 << 20);
|
private int minHeapSize = 4 * (1 << 20);
|
||||||
|
@ -275,6 +276,10 @@ public class TeaVMTool {
|
||||||
this.wasmVersion = wasmVersion;
|
this.wasmVersion = wasmVersion;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setWasmExceptionsUsed(boolean wasmExceptionsUsed) {
|
||||||
|
this.wasmExceptionsUsed = wasmExceptionsUsed;
|
||||||
|
}
|
||||||
|
|
||||||
public void setHeapDump(boolean heapDump) {
|
public void setHeapDump(boolean heapDump) {
|
||||||
this.heapDump = heapDump;
|
this.heapDump = heapDump;
|
||||||
}
|
}
|
||||||
|
@ -360,6 +365,7 @@ public class TeaVMTool {
|
||||||
webAssemblyTarget.setMinHeapSize(minHeapSize);
|
webAssemblyTarget.setMinHeapSize(minHeapSize);
|
||||||
webAssemblyTarget.setMaxHeapSize(maxHeapSize);
|
webAssemblyTarget.setMaxHeapSize(maxHeapSize);
|
||||||
webAssemblyTarget.setObfuscated(obfuscated);
|
webAssemblyTarget.setObfuscated(obfuscated);
|
||||||
|
webAssemblyTarget.setExceptionsUsed(wasmExceptionsUsed);
|
||||||
return webAssemblyTarget;
|
return webAssemblyTarget;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -81,6 +81,8 @@ public interface BuildStrategy {
|
||||||
|
|
||||||
void setWasmVersion(WasmBinaryVersion wasmVersion);
|
void setWasmVersion(WasmBinaryVersion wasmVersion);
|
||||||
|
|
||||||
|
void setWasmExceptionsUsed(boolean wasmExceptionsUsed);
|
||||||
|
|
||||||
void setMinHeapSize(int minHeapSize);
|
void setMinHeapSize(int minHeapSize);
|
||||||
|
|
||||||
void setMaxHeapSize(int maxHeapSize);
|
void setMaxHeapSize(int maxHeapSize);
|
||||||
|
|
|
@ -61,6 +61,7 @@ public class InProcessBuildStrategy implements BuildStrategy {
|
||||||
private String[] transformers = new String[0];
|
private String[] transformers = new String[0];
|
||||||
private String[] classesToPreserve = new String[0];
|
private String[] classesToPreserve = new String[0];
|
||||||
private WasmBinaryVersion wasmVersion = WasmBinaryVersion.V_0x1;
|
private WasmBinaryVersion wasmVersion = WasmBinaryVersion.V_0x1;
|
||||||
|
private boolean wasmExceptionsUsed;
|
||||||
private int minHeapSize = 4 * 1024 * 1024;
|
private int minHeapSize = 4 * 1024 * 1024;
|
||||||
private int maxHeapSize = 128 * 1024 * 1024;
|
private int maxHeapSize = 128 * 1024 * 1024;
|
||||||
private final List<SourceFileProvider> sourceFileProviders = new ArrayList<>();
|
private final List<SourceFileProvider> sourceFileProviders = new ArrayList<>();
|
||||||
|
@ -213,6 +214,11 @@ public class InProcessBuildStrategy implements BuildStrategy {
|
||||||
this.wasmVersion = wasmVersion;
|
this.wasmVersion = wasmVersion;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setWasmExceptionsUsed(boolean wasmExceptionsUsed) {
|
||||||
|
this.wasmExceptionsUsed = wasmExceptionsUsed;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setMinHeapSize(int minHeapSize) {
|
public void setMinHeapSize(int minHeapSize) {
|
||||||
this.minHeapSize = minHeapSize;
|
this.minHeapSize = minHeapSize;
|
||||||
|
@ -266,6 +272,7 @@ public class InProcessBuildStrategy implements BuildStrategy {
|
||||||
tool.getClassesToPreserve().addAll(Arrays.asList(classesToPreserve));
|
tool.getClassesToPreserve().addAll(Arrays.asList(classesToPreserve));
|
||||||
tool.setCacheDirectory(cacheDirectory != null ? new File(cacheDirectory) : null);
|
tool.setCacheDirectory(cacheDirectory != null ? new File(cacheDirectory) : null);
|
||||||
tool.setWasmVersion(wasmVersion);
|
tool.setWasmVersion(wasmVersion);
|
||||||
|
tool.setWasmExceptionsUsed(wasmExceptionsUsed);
|
||||||
tool.setMinHeapSize(minHeapSize);
|
tool.setMinHeapSize(minHeapSize);
|
||||||
tool.setMaxHeapSize(maxHeapSize);
|
tool.setMaxHeapSize(maxHeapSize);
|
||||||
tool.setHeapDump(heapDump);
|
tool.setHeapDump(heapDump);
|
||||||
|
|
|
@ -187,6 +187,11 @@ public class RemoteBuildStrategy implements BuildStrategy {
|
||||||
request.wasmVersion = wasmVersion;
|
request.wasmVersion = wasmVersion;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setWasmExceptionsUsed(boolean wasmExceptionsUsed) {
|
||||||
|
request.wasmExceptionsUsed = wasmExceptionsUsed;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setMinHeapSize(int minHeapSize) {
|
public void setMinHeapSize(int minHeapSize) {
|
||||||
request.minHeapSize = minHeapSize;
|
request.minHeapSize = minHeapSize;
|
||||||
|
|
|
@ -161,6 +161,7 @@ public class BuildDaemon extends UnicastRemoteObject implements RemoteBuildServi
|
||||||
tool.setJsModuleType(request.jsModuleType);
|
tool.setJsModuleType(request.jsModuleType);
|
||||||
tool.setStrict(request.strict);
|
tool.setStrict(request.strict);
|
||||||
tool.setWasmVersion(request.wasmVersion);
|
tool.setWasmVersion(request.wasmVersion);
|
||||||
|
tool.setWasmExceptionsUsed(request.wasmExceptionsUsed);
|
||||||
tool.setMinHeapSize(request.minHeapSize);
|
tool.setMinHeapSize(request.minHeapSize);
|
||||||
tool.setMaxHeapSize(request.maxHeapSize);
|
tool.setMaxHeapSize(request.maxHeapSize);
|
||||||
tool.setHeapDump(request.heapDump);
|
tool.setHeapDump(request.heapDump);
|
||||||
|
|
|
@ -49,6 +49,7 @@ public class RemoteBuildRequest implements Serializable {
|
||||||
public TeaVMOptimizationLevel optimizationLevel;
|
public TeaVMOptimizationLevel optimizationLevel;
|
||||||
public boolean fastDependencyAnalysis;
|
public boolean fastDependencyAnalysis;
|
||||||
public WasmBinaryVersion wasmVersion;
|
public WasmBinaryVersion wasmVersion;
|
||||||
|
public boolean wasmExceptionsUsed;
|
||||||
public int minHeapSize;
|
public int minHeapSize;
|
||||||
public int maxHeapSize;
|
public int maxHeapSize;
|
||||||
public boolean heapDump;
|
public boolean heapDump;
|
||||||
|
|
|
@ -92,6 +92,7 @@ class TeaVMExtensionImpl extends TeaVMBaseExtensionImpl implements TeaVMExtensio
|
||||||
.orElse(OptimizationLevel.AGGRESSIVE));
|
.orElse(OptimizationLevel.AGGRESSIVE));
|
||||||
wasm.getTargetFileName().convention(project.provider(() -> project.getName() + ".wasm"));
|
wasm.getTargetFileName().convention(project.provider(() -> project.getName() + ".wasm"));
|
||||||
wasm.getAddedToWebApp().convention(property("wasm.addedToWebApp").map(Boolean::parseBoolean).orElse(false));
|
wasm.getAddedToWebApp().convention(property("wasm.addedToWebApp").map(Boolean::parseBoolean).orElse(false));
|
||||||
|
wasm.getExceptionsUsed().convention(property("wasm.exceptionsUsed").map(Boolean::parseBoolean).orElse(true));
|
||||||
}
|
}
|
||||||
|
|
||||||
private void setupWasiDefaults() {
|
private void setupWasiDefaults() {
|
||||||
|
@ -101,6 +102,7 @@ class TeaVMExtensionImpl extends TeaVMBaseExtensionImpl implements TeaVMExtensio
|
||||||
wasi.getOptimization().convention(property("wasi.optimization").map(OptimizationLevel::valueOf)
|
wasi.getOptimization().convention(property("wasi.optimization").map(OptimizationLevel::valueOf)
|
||||||
.orElse(OptimizationLevel.AGGRESSIVE));
|
.orElse(OptimizationLevel.AGGRESSIVE));
|
||||||
wasi.getTargetFileName().convention(project.provider(() -> project.getName() + ".wasm"));
|
wasi.getTargetFileName().convention(project.provider(() -> project.getName() + ".wasm"));
|
||||||
|
wasi.getExceptionsUsed().convention(property("wasi.exceptionsUsed").map(Boolean::parseBoolean).orElse(false));
|
||||||
}
|
}
|
||||||
|
|
||||||
private void setupCDefaults() {
|
private void setupCDefaults() {
|
||||||
|
|
|
@ -191,6 +191,7 @@ public class TeaVMPlugin implements Plugin<Project> {
|
||||||
project.getTasks().create(WASM_TASK_NAME, GenerateWasmTask.class, task -> {
|
project.getTasks().create(WASM_TASK_NAME, GenerateWasmTask.class, task -> {
|
||||||
var wasm = extension.getWasm();
|
var wasm = extension.getWasm();
|
||||||
applyToTask(wasm, task, configuration);
|
applyToTask(wasm, task, configuration);
|
||||||
|
task.getExceptionsUsed().convention(wasm.getExceptionsUsed());
|
||||||
task.getTargetFileName().convention(wasm.getTargetFileName());
|
task.getTargetFileName().convention(wasm.getTargetFileName());
|
||||||
task.getMinHeapSize().convention(wasm.getMinHeapSize());
|
task.getMinHeapSize().convention(wasm.getMinHeapSize());
|
||||||
task.getMaxHeapSize().convention(wasm.getMaxHeapSize());
|
task.getMaxHeapSize().convention(wasm.getMaxHeapSize());
|
||||||
|
@ -202,6 +203,7 @@ public class TeaVMPlugin implements Plugin<Project> {
|
||||||
project.getTasks().create(WASI_TASK_NAME, GenerateWasiTask.class, task -> {
|
project.getTasks().create(WASI_TASK_NAME, GenerateWasiTask.class, task -> {
|
||||||
var wasi = extension.getWasi();
|
var wasi = extension.getWasi();
|
||||||
applyToTask(wasi, task, configuration);
|
applyToTask(wasi, task, configuration);
|
||||||
|
task.getExceptionsUsed().convention(wasi.getExceptionsUsed());
|
||||||
task.getTargetFileName().convention(wasi.getTargetFileName());
|
task.getTargetFileName().convention(wasi.getTargetFileName());
|
||||||
task.getMinHeapSize().convention(wasi.getMinHeapSize());
|
task.getMinHeapSize().convention(wasi.getMinHeapSize());
|
||||||
task.getMaxHeapSize().convention(wasi.getMaxHeapSize());
|
task.getMaxHeapSize().convention(wasi.getMaxHeapSize());
|
||||||
|
|
|
@ -18,5 +18,7 @@ package org.teavm.gradle.api;
|
||||||
import org.gradle.api.provider.Property;
|
import org.gradle.api.provider.Property;
|
||||||
|
|
||||||
public interface TeaVMWasmBaseConfiguration extends TeaVMCommonConfiguration, TeaVMNativeBaseConfiguration {
|
public interface TeaVMWasmBaseConfiguration extends TeaVMCommonConfiguration, TeaVMNativeBaseConfiguration {
|
||||||
|
Property<Boolean> getExceptionsUsed();
|
||||||
|
|
||||||
Property<String> getTargetFileName();
|
Property<String> getTargetFileName();
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,6 +28,9 @@ public abstract class GenerateWasiTask extends TeaVMTask {
|
||||||
getMaxHeapSize().convention(16);
|
getMaxHeapSize().convention(16);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Input
|
||||||
|
public abstract Property<Boolean> getExceptionsUsed();
|
||||||
|
|
||||||
@Input
|
@Input
|
||||||
public abstract Property<Integer> getMinHeapSize();
|
public abstract Property<Integer> getMinHeapSize();
|
||||||
|
|
||||||
|
@ -36,6 +39,7 @@ public abstract class GenerateWasiTask extends TeaVMTask {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void setupBuilder(BuildStrategy builder) {
|
protected void setupBuilder(BuildStrategy builder) {
|
||||||
|
builder.setWasmExceptionsUsed(getExceptionsUsed().get());
|
||||||
builder.setTargetType(TeaVMTargetType.WEBASSEMBLY_WASI);
|
builder.setTargetType(TeaVMTargetType.WEBASSEMBLY_WASI);
|
||||||
builder.setMinHeapSize(getMinHeapSize().get() * MB);
|
builder.setMinHeapSize(getMinHeapSize().get() * MB);
|
||||||
builder.setMaxHeapSize(getMaxHeapSize().get() * MB);
|
builder.setMaxHeapSize(getMaxHeapSize().get() * MB);
|
||||||
|
|
|
@ -24,10 +24,14 @@ public abstract class GenerateWasmTask extends TeaVMTask {
|
||||||
private static final int MB = 1024 * 1024;
|
private static final int MB = 1024 * 1024;
|
||||||
|
|
||||||
public GenerateWasmTask() {
|
public GenerateWasmTask() {
|
||||||
|
getExceptionsUsed().convention(false);
|
||||||
getMinHeapSize().convention(1);
|
getMinHeapSize().convention(1);
|
||||||
getMaxHeapSize().convention(16);
|
getMaxHeapSize().convention(16);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Input
|
||||||
|
public abstract Property<Boolean> getExceptionsUsed();
|
||||||
|
|
||||||
@Input
|
@Input
|
||||||
public abstract Property<Integer> getMinHeapSize();
|
public abstract Property<Integer> getMinHeapSize();
|
||||||
|
|
||||||
|
@ -37,6 +41,7 @@ public abstract class GenerateWasmTask extends TeaVMTask {
|
||||||
@Override
|
@Override
|
||||||
protected void setupBuilder(BuildStrategy builder) {
|
protected void setupBuilder(BuildStrategy builder) {
|
||||||
builder.setTargetType(TeaVMTargetType.WEBASSEMBLY);
|
builder.setTargetType(TeaVMTargetType.WEBASSEMBLY);
|
||||||
|
builder.setWasmExceptionsUsed(getExceptionsUsed().get());
|
||||||
builder.setMinHeapSize(getMinHeapSize().get() * MB);
|
builder.setMinHeapSize(getMinHeapSize().get() * MB);
|
||||||
builder.setMaxHeapSize(getMaxHeapSize().get() * MB);
|
builder.setMaxHeapSize(getMaxHeapSize().get() * MB);
|
||||||
}
|
}
|
||||||
|
|
|
@ -41,12 +41,17 @@ abstract class BaseWebAssemblyPlatformSupport extends TestPlatformSupport<WasmTa
|
||||||
|
|
||||||
protected abstract WasmRuntimeType getRuntimeType();
|
protected abstract WasmRuntimeType getRuntimeType();
|
||||||
|
|
||||||
|
protected boolean exceptionsUsed() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
CompileResult compile(Consumer<TeaVM> additionalProcessing, String baseName,
|
CompileResult compile(Consumer<TeaVM> additionalProcessing, String baseName,
|
||||||
TeaVMTestConfiguration<WasmTarget> configuration, File path, AnnotatedElement element) {
|
TeaVMTestConfiguration<WasmTarget> configuration, File path, AnnotatedElement element) {
|
||||||
Supplier<WasmTarget> targetSupplier = () -> {
|
Supplier<WasmTarget> targetSupplier = () -> {
|
||||||
WasmTarget target = new WasmTarget();
|
WasmTarget target = new WasmTarget();
|
||||||
target.setRuntimeType(getRuntimeType());
|
target.setRuntimeType(getRuntimeType());
|
||||||
|
target.setExceptionsUsed(exceptionsUsed());
|
||||||
var sourceDirs = System.getProperty(SOURCE_DIRS);
|
var sourceDirs = System.getProperty(SOURCE_DIRS);
|
||||||
if (sourceDirs != null) {
|
if (sourceDirs != null) {
|
||||||
var dirs = new ArrayList<File>();
|
var dirs = new ArrayList<File>();
|
||||||
|
|
|
@ -41,6 +41,11 @@ class WebAssemblyPlatformSupport extends BaseWebAssemblyPlatformSupport {
|
||||||
: null;
|
: null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected boolean exceptionsUsed() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
TestPlatform getPlatform() {
|
TestPlatform getPlatform() {
|
||||||
return TestPlatform.WEBASSEMBLY;
|
return TestPlatform.WEBASSEMBLY;
|
||||||
|
|
|
@ -144,6 +144,9 @@ public class TeaVMCompileMojo extends AbstractMojo {
|
||||||
@Parameter(property = "teavm.wasmVersion", defaultValue = "V_0x1")
|
@Parameter(property = "teavm.wasmVersion", defaultValue = "V_0x1")
|
||||||
private WasmBinaryVersion wasmVersion = WasmBinaryVersion.V_0x1;
|
private WasmBinaryVersion wasmVersion = WasmBinaryVersion.V_0x1;
|
||||||
|
|
||||||
|
@Parameter(property = "teavm.wasmExceptionsUsed", defaultValue = "false")
|
||||||
|
private boolean wasmExceptionsUsed;
|
||||||
|
|
||||||
@Parameter(property = "teavm.minHeapSize", defaultValue = "4")
|
@Parameter(property = "teavm.minHeapSize", defaultValue = "4")
|
||||||
private int minHeapSize;
|
private int minHeapSize;
|
||||||
|
|
||||||
|
@ -303,6 +306,7 @@ public class TeaVMCompileMojo extends AbstractMojo {
|
||||||
builder.setCacheDirectory(cacheDirectory.getAbsolutePath());
|
builder.setCacheDirectory(cacheDirectory.getAbsolutePath());
|
||||||
builder.setTargetType(targetType);
|
builder.setTargetType(targetType);
|
||||||
builder.setWasmVersion(wasmVersion);
|
builder.setWasmVersion(wasmVersion);
|
||||||
|
builder.setWasmExceptionsUsed(wasmExceptionsUsed);
|
||||||
builder.setHeapDump(heapDump);
|
builder.setHeapDump(heapDump);
|
||||||
BuildResult result;
|
BuildResult result;
|
||||||
result = builder.build();
|
result = builder.build();
|
||||||
|
|
Loading…
Reference in New Issue
Block a user