diff --git a/core/src/main/java/org/teavm/backend/wasm/WasmTarget.java b/core/src/main/java/org/teavm/backend/wasm/WasmTarget.java index 22b3954ae..149e7316c 100644 --- a/core/src/main/java/org/teavm/backend/wasm/WasmTarget.java +++ b/core/src/main/java/org/teavm/backend/wasm/WasmTarget.java @@ -32,7 +32,6 @@ import org.teavm.backend.wasm.generate.WasmClassGenerator; import org.teavm.backend.wasm.generate.WasmDependencyListener; import org.teavm.backend.wasm.generate.WasmGenerationContext; import org.teavm.backend.wasm.generate.WasmGenerator; -import org.teavm.backend.wasm.generate.WasmGeneratorUtil; import org.teavm.backend.wasm.generate.WasmMangling; import org.teavm.backend.wasm.generate.WasmStringPool; import org.teavm.backend.wasm.intrinsics.AddressIntrinsic; @@ -57,7 +56,6 @@ import org.teavm.backend.wasm.model.expression.WasmBlock; import org.teavm.backend.wasm.model.expression.WasmBranch; import org.teavm.backend.wasm.model.expression.WasmCall; import org.teavm.backend.wasm.model.expression.WasmConditional; -import org.teavm.backend.wasm.model.expression.WasmDrop; import org.teavm.backend.wasm.model.expression.WasmExpression; import org.teavm.backend.wasm.model.expression.WasmGetLocal; import org.teavm.backend.wasm.model.expression.WasmInt32Constant; @@ -72,6 +70,7 @@ import org.teavm.backend.wasm.model.expression.WasmStoreInt32; import org.teavm.backend.wasm.optimization.UnusedFunctionElimination; import org.teavm.backend.wasm.patches.ClassPatch; import org.teavm.backend.wasm.render.WasmBinaryRenderer; +import org.teavm.backend.wasm.render.WasmBinaryVersion; import org.teavm.backend.wasm.render.WasmBinaryWriter; import org.teavm.backend.wasm.render.WasmCRenderer; import org.teavm.backend.wasm.render.WasmRenderer; @@ -131,6 +130,7 @@ public class WasmTarget implements TeaVMTarget { private ClassInitializerTransformer classInitializerTransformer; private ShadowStackTransformer shadowStackTransformer; private MethodDescriptor clinitDescriptor = new MethodDescriptor("", void.class); + private WasmBinaryVersion version = WasmBinaryVersion.V_0xC; @Override public void setController(TeaVMTargetController controller) { @@ -189,6 +189,14 @@ public class WasmTarget implements TeaVMTarget { this.cEmitted = cEmitted; } + public WasmBinaryVersion getVersion() { + return version; + } + + public void setVersion(WasmBinaryVersion version) { + this.version = version; + } + @Override public void contributeDependencies(DependencyChecker dependencyChecker) { for (Class type : Arrays.asList(int.class, long.class, float.class, double.class)) { @@ -291,7 +299,7 @@ public class WasmTarget implements TeaVMTarget { Decompiler decompiler = new Decompiler(classes, controller.getClassLoader(), new HashSet<>(), new HashSet<>()); WasmStringPool stringPool = new WasmStringPool(classGenerator, binaryWriter); - WasmGenerationContext context = new WasmGenerationContext(classes, controller.getDiagnostics(), + WasmGenerationContext context = new WasmGenerationContext(classes, module, controller.getDiagnostics(), vtableProvider, tagRegistry, stringPool); context.addIntrinsic(new AddressIntrinsic(classGenerator)); @@ -369,7 +377,7 @@ public class WasmTarget implements TeaVMTarget { } WasmBinaryWriter writer = new WasmBinaryWriter(); - WasmBinaryRenderer renderer = new WasmBinaryRenderer(writer); + WasmBinaryRenderer renderer = new WasmBinaryRenderer(writer, version); renderer.render(module); try (OutputStream output = buildTarget.createResource(outputName)) { @@ -413,52 +421,59 @@ public class WasmTarget implements TeaVMTarget { private void generateMethods(ListableClassHolderSource classes, WasmGenerationContext context, WasmGenerator generator, WasmModule module) { + List methods = new ArrayList<>(); for (String className : classes.getClassNames()) { ClassHolder cls = classes.get(className); for (MethodHolder method : cls.getMethods()) { if (context.getIntrinsic(method.getReference()) != null) { continue; } + module.add(generator.generateDefinition(method.getReference())); + methods.add(method); + } + } - MethodHolder implementor = method; - AnnotationHolder delegateAnnot = method.getAnnotations().get(DelegateTo.class.getName()); - if (delegateAnnot != null) { - String methodName = delegateAnnot.getValue("value").getString(); - boolean found = false; - for (MethodHolder candidate : cls.getMethods()) { - if (candidate.getName().equals(methodName)) { - if (found) { - controller.getDiagnostics().error(new CallLocation(method.getReference()), - "Method is delegated to " + methodName + " but several implementations " - + "found"); - break; - } - implementor = candidate; - found = true; + for (MethodHolder method : methods) { + ClassHolder cls = classes.get(method.getOwnerName()); + + MethodHolder implementor = method; + AnnotationHolder delegateAnnot = method.getAnnotations().get(DelegateTo.class.getName()); + if (delegateAnnot != null) { + String methodName = delegateAnnot.getValue("value").getString(); + boolean found = false; + for (MethodHolder candidate : cls.getMethods()) { + if (candidate.getName().equals(methodName)) { + if (found) { + controller.getDiagnostics().error(new CallLocation(method.getReference()), + "Method is delegated to " + methodName + " but several implementations " + + "found"); + break; } + implementor = candidate; + found = true; } } + } - if (implementor.hasModifier(ElementModifier.NATIVE)) { - if (context.getImportedMethod(method.getReference()) == null) { - CallLocation location = new CallLocation(method.getReference()); - controller.getDiagnostics().error(location, "Method {{m0}} is native but " - + "has no {{c1}} annotation on it", method.getReference(), Import.class.getName()); - } - module.add(generator.generateNative(method.getReference())); - continue; - } - if (implementor.getProgram() == null || implementor.getProgram().basicBlockCount() == 0) { - continue; - } - if (method == implementor) { - module.add(generator.generate(method.getReference(), implementor)); - } else { - module.add(generateStub(method, implementor)); - } - if (controller.wasCancelled()) { - return; + if (implementor.hasModifier(ElementModifier.NATIVE)) { + if (context.getImportedMethod(method.getReference()) == null) { + CallLocation location = new CallLocation(method.getReference()); + controller.getDiagnostics().error(location, "Method {{m0}} is native but " + + "has no {{c1}} annotation on it", method.getReference(), Import.class.getName()); } + generator.generateNative(method.getReference()); + continue; + } + if (implementor.getProgram() == null || implementor.getProgram().basicBlockCount() == 0) { + continue; + } + if (method == implementor) { + generator.generate(method.getReference(), implementor); + } else { + generateStub(module, method, implementor); + } + if (controller.wasCancelled()) { + return; } } } @@ -513,12 +528,14 @@ public class WasmTarget implements TeaVMTarget { WasmExpression lowerCondition = new WasmIntBinary(WasmIntType.INT32, WasmIntBinaryOperation.LT_SIGNED, new WasmGetLocal(subtypeVar), new WasmInt32Constant(lower)); WasmConditional testLower = new WasmConditional(lowerCondition); + testLower.setType(WasmType.INT32); testLower.getThenBlock().getBody().add(new WasmReturn(new WasmInt32Constant(0))); body.add(testLower); WasmExpression upperCondition = new WasmIntBinary(WasmIntType.INT32, WasmIntBinaryOperation.GT_SIGNED, new WasmGetLocal(subtypeVar), new WasmInt32Constant(upper)); WasmConditional testUpper = new WasmConditional(upperCondition); + testLower.setType(WasmType.INT32); testUpper.getThenBlock().getBody().add(new WasmReturn(new WasmInt32Constant(0))); body.add(testUpper); @@ -555,6 +572,7 @@ public class WasmTarget implements TeaVMTarget { WasmExpression itemCondition = new WasmIntBinary(WasmIntType.INT32, WasmIntBinaryOperation.EQ, new WasmGetLocal(subtypeVar), new WasmInt32Constant(0)); WasmConditional itemTest = new WasmConditional(itemCondition); + itemTest.setType(WasmType.INT32); itemTest.getThenBlock().getBody().add(new WasmInt32Constant(0)); WasmCall delegateToItem = new WasmCall(WasmMangling.mangleIsSupertype(itemType)); @@ -564,15 +582,8 @@ public class WasmTarget implements TeaVMTarget { body.add(new WasmReturn(itemTest)); } - private WasmFunction generateStub(MethodHolder method, MethodHolder implementor) { - WasmFunction function = new WasmFunction(WasmMangling.mangleMethod(method.getReference())); - if (!method.hasModifier(ElementModifier.STATIC)) { - function.getParameters().add(WasmType.INT32); - } - ValueType[] parameterTypes = method.getParameterTypes(); - for (ValueType parameterType : parameterTypes) { - function.getParameters().add(WasmGeneratorUtil.mapType(parameterType)); - } + private WasmFunction generateStub(WasmModule module, MethodHolder method, MethodHolder implementor) { + WasmFunction function = module.getFunctions().get(WasmMangling.mangleMethod(method.getReference())); WasmCall call = new WasmCall(WasmMangling.mangleMethod(implementor.getReference())); for (WasmType param : function.getParameters()) { @@ -581,10 +592,8 @@ public class WasmTarget implements TeaVMTarget { call.getArguments().add(new WasmGetLocal(local)); } - function.setResult(WasmGeneratorUtil.mapType(method.getResultType())); - if (method.getResultType() == ValueType.VOID) { - function.getBody().add(new WasmDrop(call)); + function.getBody().add(call); } else { function.getBody().add(new WasmReturn(call)); } diff --git a/core/src/main/java/org/teavm/backend/wasm/generate/WasmGenerationContext.java b/core/src/main/java/org/teavm/backend/wasm/generate/WasmGenerationContext.java index 8bb10ab57..3fef6b600 100644 --- a/core/src/main/java/org/teavm/backend/wasm/generate/WasmGenerationContext.java +++ b/core/src/main/java/org/teavm/backend/wasm/generate/WasmGenerationContext.java @@ -20,6 +20,8 @@ import java.util.HashMap; import java.util.List; import java.util.Map; import org.teavm.backend.wasm.intrinsics.WasmIntrinsic; +import org.teavm.backend.wasm.model.WasmFunction; +import org.teavm.backend.wasm.model.WasmModule; import org.teavm.diagnostics.Diagnostics; import org.teavm.interop.Import; import org.teavm.model.AnnotationReader; @@ -36,6 +38,7 @@ import org.teavm.model.classes.VirtualTableProvider; public class WasmGenerationContext { private ClassReaderSource classSource; + private WasmModule module; private Diagnostics diagnostics; private VirtualTableProvider vtableProvider; private TagRegistry tagRegistry; @@ -44,9 +47,10 @@ public class WasmGenerationContext { private List intrinsics = new ArrayList<>(); private Map intrinsicCache = new HashMap<>(); - public WasmGenerationContext(ClassReaderSource classSource, Diagnostics diagnostics, + public WasmGenerationContext(ClassReaderSource classSource, WasmModule module, Diagnostics diagnostics, VirtualTableProvider vtableProvider, TagRegistry tagRegistry, WasmStringPool stringPool) { this.classSource = classSource; + this.module = module; this.diagnostics = diagnostics; this.vtableProvider = vtableProvider; this.tagRegistry = tagRegistry; @@ -97,6 +101,10 @@ public class WasmGenerationContext { }); } + public WasmFunction getFunction(String name) { + return module.getFunctions().get(name); + } + public ClassReaderSource getClassSource() { return classSource; } diff --git a/core/src/main/java/org/teavm/backend/wasm/generate/WasmGenerationVisitor.java b/core/src/main/java/org/teavm/backend/wasm/generate/WasmGenerationVisitor.java index d9bcea9e7..81b74d0a2 100644 --- a/core/src/main/java/org/teavm/backend/wasm/generate/WasmGenerationVisitor.java +++ b/core/src/main/java/org/teavm/backend/wasm/generate/WasmGenerationVisitor.java @@ -106,6 +106,7 @@ import org.teavm.backend.wasm.model.expression.WasmStoreInt32; import org.teavm.backend.wasm.model.expression.WasmStoreInt64; import org.teavm.backend.wasm.model.expression.WasmSwitch; import org.teavm.backend.wasm.model.expression.WasmUnreachable; +import org.teavm.backend.wasm.render.WasmTypeInference; import org.teavm.interop.Address; import org.teavm.model.FieldReference; import org.teavm.model.MethodReference; @@ -122,6 +123,7 @@ class WasmGenerationVisitor implements StatementVisitor, ExprVisitor { private static FieldReference tagField = new FieldReference(RuntimeClass.class.getName(), "tag"); private WasmGenerationContext context; private WasmClassGenerator classGenerator; + private WasmTypeInference typeInference; private WasmFunction function; private int firstVariable; private IdentifiedStatement currentContinueTarget; @@ -145,6 +147,7 @@ class WasmGenerationVisitor implements StatementVisitor, ExprVisitor { for (int i = 0; i < typeCount; ++i) { temporaryVariablesByType.add(new ArrayDeque<>()); } + typeInference = new WasmTypeInference(context); } private void accept(Expr expr) { @@ -330,6 +333,7 @@ class WasmGenerationVisitor implements StatementVisitor, ExprVisitor { private void generateAnd(BinaryExpr expr) { WasmBlock block = new WasmBlock(false); + block.setType(WasmType.INT32); accept(expr.getFirstOperand()); WasmBranch branch = new WasmBranch(negate(result), block); @@ -348,6 +352,7 @@ class WasmGenerationVisitor implements StatementVisitor, ExprVisitor { private void generateOr(BinaryExpr expr) { WasmBlock block = new WasmBlock(false); + block.setType(WasmType.INT32); accept(expr.getFirstOperand()); WasmBranch branch = new WasmBranch(result, block); @@ -450,8 +455,11 @@ class WasmGenerationVisitor implements StatementVisitor, ExprVisitor { Expr left = statement.getLeftValue(); if (left == null) { accept(statement.getRightValue()); - result = new WasmDrop(result); - result.setLocation(statement.getLocation()); + result.acceptVisitor(typeInference); + if (typeInference.getResult() != null) { + result = new WasmDrop(result); + result.setLocation(statement.getLocation()); + } } else if (left instanceof VariableExpr) { VariableExpr varExpr = (VariableExpr) left; WasmLocal local = function.getLocalVariables().get(varExpr.getIndex() - firstVariable); @@ -552,6 +560,13 @@ class WasmGenerationVisitor implements StatementVisitor, ExprVisitor { accept(expr.getAlternative()); conditional.getElseBlock().getBody().add(result); + conditional.getThenBlock().acceptVisitor(typeInference); + WasmType thenType = typeInference.getResult(); + conditional.getElseBlock().acceptVisitor(typeInference); + WasmType elseType = typeInference.getResult(); + assert thenType == elseType; + conditional.setType(thenType); + result = conditional; } @@ -833,6 +848,8 @@ class WasmGenerationVisitor implements StatementVisitor, ExprVisitor { result = call; } else if (expr.getType() == InvocationType.CONSTRUCTOR) { WasmBlock block = new WasmBlock(false); + block.setType(WasmType.INT32); + WasmLocal tmp = getTemporary(WasmType.INT32); block.getBody().add(new WasmSetLocal(tmp, allocateObject(expr.getMethod().getClassName(), expr.getLocation()))); @@ -854,6 +871,7 @@ class WasmGenerationVisitor implements StatementVisitor, ExprVisitor { accept(expr.getArguments().get(0)); WasmExpression instance = result; WasmBlock block = new WasmBlock(false); + block.setType(WasmGeneratorUtil.mapType(expr.getMethod().getReturnType())); WasmLocal instanceVar = getTemporary(WasmType.INT32); block.getBody().add(new WasmSetLocal(instanceVar, instance)); @@ -1135,6 +1153,8 @@ class WasmGenerationVisitor implements StatementVisitor, ExprVisitor { ValueType type = expr.getType(); WasmBlock block = new WasmBlock(false); + block.setType(WasmType.INT32); + int dimensionList = -1; for (Expr dimension : expr.getDimensions()) { int dimensionAddress = binaryWriter.append(DataPrimitives.INT.createValue()); @@ -1180,7 +1200,9 @@ class WasmGenerationVisitor implements StatementVisitor, ExprVisitor { ranges.sort(Comparator.comparingInt(range -> range.lower)); WasmBlock block = new WasmBlock(false); + block.setType(WasmType.INT32); block.setLocation(expr.getLocation()); + WasmLocal tagVar = getTemporary(WasmType.INT32); int tagOffset = classGenerator.getFieldOffset(tagField); WasmExpression tagPtr = new WasmIntBinary(WasmIntType.INT32, WasmIntBinaryOperation.ADD, @@ -1204,6 +1226,7 @@ class WasmGenerationVisitor implements StatementVisitor, ExprVisitor { WasmIntBinaryOperation.GT_SIGNED, new WasmGetLocal(tagVar), new WasmInt32Constant(ranges.get(i - 1).upper)); WasmConditional conditional = new WasmConditional(upperThanExcluded); + conditional.setType(WasmType.INT32); WasmExpression lowerThanExcluded = new WasmIntBinary(WasmIntType.INT32, WasmIntBinaryOperation.LT_SIGNED, new WasmGetLocal(tagVar), new WasmInt32Constant(ranges.get(i).lower)); diff --git a/core/src/main/java/org/teavm/backend/wasm/generate/WasmGenerator.java b/core/src/main/java/org/teavm/backend/wasm/generate/WasmGenerator.java index f805dd1f4..33854cb13 100644 --- a/core/src/main/java/org/teavm/backend/wasm/generate/WasmGenerator.java +++ b/core/src/main/java/org/teavm/backend/wasm/generate/WasmGenerator.java @@ -47,12 +47,30 @@ public class WasmGenerator { this.binaryWriter = binaryWriter; } + public WasmFunction generateDefinition(MethodReference methodReference) { + ClassHolder cls = classSource.get(methodReference.getClassName()); + MethodHolder method = cls.getMethod(methodReference.getDescriptor()); + WasmFunction function = new WasmFunction(WasmMangling.mangleMethod(method.getReference())); + + if (!method.hasModifier(ElementModifier.STATIC)) { + function.getParameters().add(WasmType.INT32); + } + for (int i = 0; i < method.parameterCount(); ++i) { + function.getParameters().add(WasmGeneratorUtil.mapType(method.parameterType(i))); + } + if (method.getResultType() != ValueType.VOID) { + function.setResult(WasmGeneratorUtil.mapType(method.getResultType())); + } + + return function; + } + public WasmFunction generate(MethodReference methodReference, MethodHolder bodyMethod) { ClassHolder cls = classSource.get(methodReference.getClassName()); MethodHolder method = cls.getMethod(methodReference.getDescriptor()); RegularMethodNode methodAst = decompiler.decompileRegular(bodyMethod); - WasmFunction function = new WasmFunction(WasmMangling.mangleMethod(methodReference)); + WasmFunction function = context.getFunction(WasmMangling.mangleMethod(methodReference)); int firstVariable = method.hasModifier(ElementModifier.STATIC) ? 1 : 0; for (int i = firstVariable; i < methodAst.getVariables().size(); ++i) { VariableNode variable = methodAst.getVariables().get(i); @@ -62,13 +80,6 @@ public class WasmGenerator { function.add(new WasmLocal(type, variable.getName())); } - for (int i = firstVariable; i <= methodReference.parameterCount(); ++i) { - function.getParameters().add(function.getLocalVariables().get(i - firstVariable).getType()); - } - if (methodReference.getReturnType() != ValueType.VOID) { - function.setResult(WasmGeneratorUtil.mapType(methodReference.getReturnType())); - } - WasmGenerationVisitor visitor = new WasmGenerationVisitor(context, classGenerator, binaryWriter, function, firstVariable); methodAst.getBody().acceptVisitor(visitor); @@ -83,12 +94,7 @@ public class WasmGenerator { } public WasmFunction generateNative(MethodReference methodReference) { - WasmFunction function = new WasmFunction(WasmMangling.mangleMethod(methodReference)); - for (int i = 0; i < methodReference.parameterCount(); ++i) { - WasmType paramType = WasmGeneratorUtil.mapType(methodReference.parameterType(i)); - function.getParameters().add(paramType); - } - function.setResult(WasmGeneratorUtil.mapType(methodReference.getReturnType())); + WasmFunction function = context.getFunction(WasmMangling.mangleMethod(methodReference)); WasmGenerationContext.ImportedMethod importedMethod = context.getImportedMethod(methodReference); if (importedMethod != null) { diff --git a/core/src/main/java/org/teavm/backend/wasm/model/expression/WasmBlock.java b/core/src/main/java/org/teavm/backend/wasm/model/expression/WasmBlock.java index 8f039f5a7..568a9c3aa 100644 --- a/core/src/main/java/org/teavm/backend/wasm/model/expression/WasmBlock.java +++ b/core/src/main/java/org/teavm/backend/wasm/model/expression/WasmBlock.java @@ -17,10 +17,12 @@ package org.teavm.backend.wasm.model.expression; import java.util.ArrayList; import java.util.List; +import org.teavm.backend.wasm.model.WasmType; public class WasmBlock extends WasmExpression { private boolean loop; private List body = new ArrayList<>(); + private WasmType type; public WasmBlock(boolean loop) { this.loop = loop; @@ -38,6 +40,14 @@ public class WasmBlock extends WasmExpression { return body; } + public WasmType getType() { + return type; + } + + public void setType(WasmType type) { + this.type = type; + } + @Override public void acceptVisitor(WasmExpressionVisitor visitor) { visitor.visit(this); diff --git a/core/src/main/java/org/teavm/backend/wasm/model/expression/WasmConditional.java b/core/src/main/java/org/teavm/backend/wasm/model/expression/WasmConditional.java index 2f0d35586..8fb17a5b8 100644 --- a/core/src/main/java/org/teavm/backend/wasm/model/expression/WasmConditional.java +++ b/core/src/main/java/org/teavm/backend/wasm/model/expression/WasmConditional.java @@ -16,11 +16,13 @@ package org.teavm.backend.wasm.model.expression; import java.util.Objects; +import org.teavm.backend.wasm.model.WasmType; public class WasmConditional extends WasmExpression { private WasmExpression condition; private WasmBlock thenBlock = new WasmBlock(false); private WasmBlock elseBlock = new WasmBlock(false); + private WasmType type; public WasmConditional(WasmExpression condition) { Objects.requireNonNull(condition); @@ -44,6 +46,14 @@ public class WasmConditional extends WasmExpression { return elseBlock; } + public WasmType getType() { + return type; + } + + public void setType(WasmType type) { + this.type = type; + } + @Override public void acceptVisitor(WasmExpressionVisitor visitor) { visitor.visit(this); diff --git a/core/src/main/java/org/teavm/backend/wasm/render/WasmBinaryRenderer.java b/core/src/main/java/org/teavm/backend/wasm/render/WasmBinaryRenderer.java index 45246b6a7..0d92eb8bc 100644 --- a/core/src/main/java/org/teavm/backend/wasm/render/WasmBinaryRenderer.java +++ b/core/src/main/java/org/teavm/backend/wasm/render/WasmBinaryRenderer.java @@ -28,19 +28,43 @@ import org.teavm.backend.wasm.model.WasmType; import org.teavm.backend.wasm.model.expression.WasmExpression; public class WasmBinaryRenderer { + private static final int SECTION_UNKNOWN = 0; + private static final int SECTION_TYPE = 1; + private static final int SECTION_IMPORT = 2; + private static final int SECTION_FUNCTION = 3; + private static final int SECTION_TABLE = 4; + private static final int SECTION_MEMORY = 5; + private static final int SECTION_EXPORT = 7; + private static final int SECTION_START = 8; + private static final int SECTION_ELEMENT = 9; + private static final int SECTION_CODE = 10; + private static final int SECTION_DATA = 11; + + private static final int EXTERNAL_KIND_FUNCTION = 0; + private WasmBinaryWriter output; + private WasmBinaryVersion version; private List signatures = new ArrayList<>(); private Map signatureIndexes = new HashMap<>(); private Map importIndexes = new HashMap<>(); private Map functionIndexes = new HashMap<>(); - public WasmBinaryRenderer(WasmBinaryWriter output) { + public WasmBinaryRenderer(WasmBinaryWriter output, WasmBinaryVersion version) { this.output = output; + this.version = version; } public void render(WasmModule module) { output.writeInt32(0x6d736100); - output.writeInt32(11); + switch (version) { + case V_0xB: + output.writeInt32(0xB); + break; + case V_0xC: + output.writeInt32(0xC); + break; + } + renderSignatures(module); renderImports(module); renderFunctions(module); @@ -48,6 +72,7 @@ public class WasmBinaryRenderer { renderMemory(module); renderExport(module); renderStart(module); + renderElement(module); renderCode(module); renderData(module); renderNames(module); @@ -79,7 +104,7 @@ public class WasmBinaryRenderer { } } - writeSection("type", section.getData()); + writeSection(SECTION_TYPE, "type", section.getData()); } private void renderImports(WasmModule module) { @@ -90,7 +115,11 @@ public class WasmBinaryRenderer { continue; } functions.add(function); - importIndexes.put(function.getName(), index++); + if (version == WasmBinaryVersion.V_0xB) { + importIndexes.put(function.getName(), index++); + } else { + functionIndexes.put(function.getName(), functions.size()); + } } if (functions.isEmpty()) { return; @@ -101,7 +130,10 @@ public class WasmBinaryRenderer { section.writeLEB(functions.size()); for (WasmFunction function : functions) { WasmSignature signature = WasmSignature.fromFunction(function); - section.writeLEB(signatureIndexes.get(signature)); + int signatureIndex = signatureIndexes.get(signature); + if (version == WasmBinaryVersion.V_0xB) { + section.writeLEB(signatureIndex); + } String moduleName = function.getImportModule(); if (moduleName == null) { @@ -110,9 +142,14 @@ public class WasmBinaryRenderer { section.writeAsciiString(moduleName); section.writeAsciiString(function.getImportName()); + + if (version == WasmBinaryVersion.V_0xC) { + section.writeByte(EXTERNAL_KIND_FUNCTION); + section.writeLEB(signatureIndex); + } } - writeSection("import", section.getData()); + writeSection(SECTION_IMPORT, "import", section.getData()); } private void renderFunctions(WasmModule module) { @@ -132,7 +169,7 @@ public class WasmBinaryRenderer { section.writeLEB(signatureIndexes.get(signature)); } - writeSection("function", section.getData()); + writeSection(SECTION_FUNCTION, "function", section.getData()); } private void renderTable(WasmModule module) { @@ -142,22 +179,35 @@ public class WasmBinaryRenderer { WasmBinaryWriter section = new WasmBinaryWriter(); - section.writeLEB(module.getFunctionTable().size()); - for (WasmFunction function : module.getFunctionTable()) { - section.writeLEB(functionIndexes.get(function.getName())); + if (version == WasmBinaryVersion.V_0xB) { + section.writeLEB(module.getFunctionTable().size()); + for (WasmFunction function : module.getFunctionTable()) { + section.writeLEB(functionIndexes.get(function.getName())); + } + } else { + section.writeByte(1); + section.writeByte(0x20); + section.writeByte(1); + section.writeLEB(functionIndexes.size()); + //section.writeLEB(functionIndexes.size()); } - - writeSection("table", section.getData()); + writeSection(SECTION_TABLE, "table", section.getData()); } private void renderMemory(WasmModule module) { WasmBinaryWriter section = new WasmBinaryWriter(); + if (version == WasmBinaryVersion.V_0xC) { + section.writeByte(1); + section.writeByte(3); + } section.writeLEB(module.getMemorySize()); section.writeLEB(module.getMemorySize()); - section.writeByte(1); + if (version == WasmBinaryVersion.V_0xB) { + section.writeByte(1); + } - writeSection("memory", section.getData()); + writeSection(SECTION_MEMORY, "memory", section.getData()); } private void renderExport(WasmModule module) { @@ -172,12 +222,20 @@ public class WasmBinaryRenderer { section.writeLEB(functions.size()); for (WasmFunction function : functions) { - section.writeLEB(functionIndexes.get(function.getName())); + int functionIndex = functionIndexes.get(function.getName()); + if (version == WasmBinaryVersion.V_0xB) { + section.writeLEB(functionIndex); + } section.writeAsciiString(function.getExportName()); + + if (version == WasmBinaryVersion.V_0xC) { + section.writeByte(EXTERNAL_KIND_FUNCTION); + section.writeLEB(functionIndex); + } } - writeSection("export", section.getData()); + writeSection(SECTION_EXPORT, "export", section.getData()); } private void renderStart(WasmModule module) { @@ -188,7 +246,28 @@ public class WasmBinaryRenderer { WasmBinaryWriter section = new WasmBinaryWriter(); section.writeLEB(functionIndexes.get(module.getStartFunction().getName())); - writeSection("start", section.getData()); + writeSection(SECTION_START, "start", section.getData()); + } + + private void renderElement(WasmModule module) { + if (module.getFunctionTable().isEmpty() || version != WasmBinaryVersion.V_0xC) { + return; + } + + WasmBinaryWriter section = new WasmBinaryWriter(); + section.writeLEB(1); + section.writeLEB(0); + + section.writeByte(0x10); + section.writeLEB(0); + section.writeByte(0x0F); + + section.writeLEB(module.getFunctionTable().size()); + for (WasmFunction function : module.getFunctionTable()) { + section.writeLEB(functionIndexes.get(function.getName())); + } + + writeSection(SECTION_ELEMENT, "element", section.getData()); } private void renderCode(WasmModule module) { @@ -205,7 +284,7 @@ public class WasmBinaryRenderer { section.writeBytes(body); } - writeSection("code", section.getData()); + writeSection(SECTION_CODE, "code", section.getData()); } private byte[] renderFunction(WasmFunction function) { @@ -236,8 +315,8 @@ public class WasmBinaryRenderer { } } - WasmBinaryRenderingVisitor visitor = new WasmBinaryRenderingVisitor(code, functionIndexes, importIndexes, - signatureIndexes); + WasmBinaryRenderingVisitor visitor = new WasmBinaryRenderingVisitor(code, version, functionIndexes, + importIndexes, signatureIndexes); for (WasmExpression part : function.getBody()) { part.acceptVisitor(visitor); } @@ -263,7 +342,7 @@ public class WasmBinaryRenderer { } } - writeSection("data", section.getData()); + writeSection(SECTION_DATA, "data", section.getData()); } private void renderNames(WasmModule module) { @@ -280,7 +359,7 @@ public class WasmBinaryRenderer { section.writeLEB(0); } - writeSection("name", section.getData()); + writeSection(SECTION_UNKNOWN, "name", section.getData()); } static class LocalEntry { @@ -300,10 +379,22 @@ public class WasmBinaryRenderer { }); } - private void writeSection(String id, byte[] data) { - output.writeAsciiString(id); + private void writeSection(int id, String name, byte[] data) { + if (version == WasmBinaryVersion.V_0xC) { + output.writeByte(id); + int length = data.length; + if (id == 0) { + length += name.length() + 1; + } + output.writeLEB(length); + if (id == 0) { + output.writeAsciiString(name); + } + } else { + output.writeAsciiString(name); + output.writeLEB(data.length); + } - output.writeLEB(data.length); output.writeBytes(data); } } diff --git a/core/src/main/java/org/teavm/backend/wasm/render/WasmBinaryRenderingVisitor.java b/core/src/main/java/org/teavm/backend/wasm/render/WasmBinaryRenderingVisitor.java index 3a20b4130..f9c0105a5 100644 --- a/core/src/main/java/org/teavm/backend/wasm/render/WasmBinaryRenderingVisitor.java +++ b/core/src/main/java/org/teavm/backend/wasm/render/WasmBinaryRenderingVisitor.java @@ -52,15 +52,17 @@ import org.teavm.backend.wasm.model.expression.WasmUnreachable; class WasmBinaryRenderingVisitor implements WasmExpressionVisitor { private WasmBinaryWriter writer; + private WasmBinaryVersion version; private Map functionIndexes; private Map importedIndexes; private Map signatureIndexes; private int depth; private Map blockDepths = new HashMap<>(); - WasmBinaryRenderingVisitor(WasmBinaryWriter writer, Map functionIndexes, + WasmBinaryRenderingVisitor(WasmBinaryWriter writer, WasmBinaryVersion version, Map functionIndexes, Map importedIndexes, Map signatureIndexes) { this.writer = writer; + this.version = version; this.functionIndexes = functionIndexes; this.importedIndexes = importedIndexes; this.signatureIndexes = signatureIndexes; @@ -71,6 +73,7 @@ class WasmBinaryRenderingVisitor implements WasmExpressionVisitor { depth += expression.isLoop() ? 2 : 1; blockDepths.put(expression, depth); writer.writeByte(expression.isLoop() ? 0x02 : 0x01); + writeBlockType(expression.getType()); for (WasmExpression part : expression.getBody()) { part.acceptVisitor(this); } @@ -79,6 +82,12 @@ class WasmBinaryRenderingVisitor implements WasmExpressionVisitor { depth -= expression.isLoop() ? 2 : 1; } + private void writeBlockType(WasmType type) { + if (version == WasmBinaryVersion.V_0xC) { + writer.writeType(type); + } + } + @Override public void visit(WasmBranch expression) { if (expression.getResult() != null) { @@ -86,7 +95,9 @@ class WasmBinaryRenderingVisitor implements WasmExpressionVisitor { } expression.getCondition().acceptVisitor(this); writer.writeByte(0x07); - writer.writeByte(expression.getResult() != null ? 1 : 0); + if (version == WasmBinaryVersion.V_0xB) { + writer.writeByte(expression.getResult() != null ? 1 : 0); + } writeLabel(expression.getTarget()); } @@ -96,7 +107,9 @@ class WasmBinaryRenderingVisitor implements WasmExpressionVisitor { expression.getResult().acceptVisitor(this); } writer.writeByte(0x06); - writer.writeByte(expression.getResult() != null ? 1 : 0); + if (version == WasmBinaryVersion.V_0xB) { + writer.writeByte(expression.getResult() != null ? 1 : 0); + } writeLabel(expression.getTarget()); } @@ -104,20 +117,33 @@ class WasmBinaryRenderingVisitor implements WasmExpressionVisitor { public void visit(WasmSwitch expression) { expression.getSelector().acceptVisitor(this); writer.writeByte(0x08); - writer.writeByte(0); + if (version == WasmBinaryVersion.V_0xB) { + writer.writeByte(0); + } writer.writeLEB(expression.getTargets().size()); for (WasmBlock target : expression.getTargets()) { int targetDepth = blockDepths.get(target); - writer.writeFixed(depth - targetDepth); + int relativeDepth = depth - targetDepth; + if (version == WasmBinaryVersion.V_0xC) { + writer.writeLEB(relativeDepth); + } else { + writer.writeFixed(relativeDepth); + } } int defaultDepth = blockDepths.get(expression.getDefaultTarget()); - writer.writeFixed(depth - defaultDepth); + int relativeDepth = depth - defaultDepth; + if (version == WasmBinaryVersion.V_0xC) { + writer.writeLEB(relativeDepth); + } else { + writer.writeFixed(relativeDepth); + } } @Override public void visit(WasmConditional expression) { expression.getCondition().acceptVisitor(this); writer.writeByte(0x03); + writeBlockType(expression.getType()); ++depth; blockDepths.put(expression.getThenBlock(), depth); @@ -145,12 +171,18 @@ class WasmBinaryRenderingVisitor implements WasmExpressionVisitor { expression.getValue().acceptVisitor(this); } writer.writeByte(0x09); - writer.writeByte(expression.getValue() != null ? 1 : 0); + if (version == WasmBinaryVersion.V_0xB) { + writer.writeByte(expression.getValue() != null ? 1 : 0); + } } @Override public void visit(WasmUnreachable expression) { - writer.writeByte(0x0A); + if (version == WasmBinaryVersion.V_0xB) { + writer.writeByte(0x0A); + } else { + writer.writeByte(0x0); + } } @Override @@ -613,7 +645,7 @@ class WasmBinaryRenderingVisitor implements WasmExpressionVisitor { for (WasmExpression argument : expression.getArguments()) { argument.acceptVisitor(this); } - Integer functionIndex = !expression.isImported() + Integer functionIndex = !expression.isImported() || version == WasmBinaryVersion.V_0xC ? functionIndexes.get(expression.getFunctionName()) : importedIndexes.get(expression.getFunctionName()); if (functionIndex == null) { @@ -621,8 +653,12 @@ class WasmBinaryRenderingVisitor implements WasmExpressionVisitor { return; } - writer.writeByte(!expression.isImported() ? 0x16 : 0x18); - writer.writeLEB(expression.getArguments().size()); + if (version == WasmBinaryVersion.V_0xB) { + writer.writeByte(!expression.isImported() ? 0x16 : 0x18); + writer.writeLEB(expression.getArguments().size()); + } else { + writer.writeByte(0x16); + } writer.writeLEB(functionIndex); } @@ -633,7 +669,9 @@ class WasmBinaryRenderingVisitor implements WasmExpressionVisitor { argument.acceptVisitor(this); } writer.writeByte(0x17); - writer.writeLEB(expression.getArguments().size()); + if (version == WasmBinaryVersion.V_0xB) { + writer.writeLEB(expression.getArguments().size()); + } WasmType[] signatureTypes = new WasmType[expression.getParameterTypes().size() + 1]; signatureTypes[0] = expression.getReturnType(); @@ -646,6 +684,9 @@ class WasmBinaryRenderingVisitor implements WasmExpressionVisitor { @Override public void visit(WasmDrop expression) { expression.getOperand().acceptVisitor(this); + if (version == WasmBinaryVersion.V_0xC) { + writer.writeByte(0x0B); + } } @Override diff --git a/core/src/main/java/org/teavm/backend/wasm/render/WasmBinaryVersion.java b/core/src/main/java/org/teavm/backend/wasm/render/WasmBinaryVersion.java new file mode 100644 index 000000000..43058cada --- /dev/null +++ b/core/src/main/java/org/teavm/backend/wasm/render/WasmBinaryVersion.java @@ -0,0 +1,21 @@ +/* + * Copyright 2016 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.render; + +public enum WasmBinaryVersion { + V_0xB, + V_0xC +} diff --git a/core/src/main/java/org/teavm/backend/wasm/render/WasmBinaryWriter.java b/core/src/main/java/org/teavm/backend/wasm/render/WasmBinaryWriter.java index 5f6f8a6c9..6decb28dd 100644 --- a/core/src/main/java/org/teavm/backend/wasm/render/WasmBinaryWriter.java +++ b/core/src/main/java/org/teavm/backend/wasm/render/WasmBinaryWriter.java @@ -28,6 +28,10 @@ public class WasmBinaryWriter { } public void writeType(WasmType type) { + if (type == null) { + writeByte(0); + return; + } switch (type) { case INT32: writeByte(1); diff --git a/core/src/main/java/org/teavm/backend/wasm/render/WasmTypeInference.java b/core/src/main/java/org/teavm/backend/wasm/render/WasmTypeInference.java new file mode 100644 index 000000000..6f7911829 --- /dev/null +++ b/core/src/main/java/org/teavm/backend/wasm/render/WasmTypeInference.java @@ -0,0 +1,233 @@ +/* + * Copyright 2016 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.render; + +import org.teavm.backend.wasm.generate.WasmGenerationContext; +import org.teavm.backend.wasm.model.WasmFunction; +import org.teavm.backend.wasm.model.WasmType; +import org.teavm.backend.wasm.model.expression.WasmBlock; +import org.teavm.backend.wasm.model.expression.WasmBranch; +import org.teavm.backend.wasm.model.expression.WasmBreak; +import org.teavm.backend.wasm.model.expression.WasmCall; +import org.teavm.backend.wasm.model.expression.WasmConditional; +import org.teavm.backend.wasm.model.expression.WasmConversion; +import org.teavm.backend.wasm.model.expression.WasmDrop; +import org.teavm.backend.wasm.model.expression.WasmExpressionVisitor; +import org.teavm.backend.wasm.model.expression.WasmFloat32Constant; +import org.teavm.backend.wasm.model.expression.WasmFloat64Constant; +import org.teavm.backend.wasm.model.expression.WasmFloatBinary; +import org.teavm.backend.wasm.model.expression.WasmFloatType; +import org.teavm.backend.wasm.model.expression.WasmFloatUnary; +import org.teavm.backend.wasm.model.expression.WasmGetLocal; +import org.teavm.backend.wasm.model.expression.WasmIndirectCall; +import org.teavm.backend.wasm.model.expression.WasmInt32Constant; +import org.teavm.backend.wasm.model.expression.WasmInt64Constant; +import org.teavm.backend.wasm.model.expression.WasmIntBinary; +import org.teavm.backend.wasm.model.expression.WasmIntType; +import org.teavm.backend.wasm.model.expression.WasmIntUnary; +import org.teavm.backend.wasm.model.expression.WasmLoadFloat32; +import org.teavm.backend.wasm.model.expression.WasmLoadFloat64; +import org.teavm.backend.wasm.model.expression.WasmLoadInt32; +import org.teavm.backend.wasm.model.expression.WasmLoadInt64; +import org.teavm.backend.wasm.model.expression.WasmReturn; +import org.teavm.backend.wasm.model.expression.WasmSetLocal; +import org.teavm.backend.wasm.model.expression.WasmStoreFloat32; +import org.teavm.backend.wasm.model.expression.WasmStoreFloat64; +import org.teavm.backend.wasm.model.expression.WasmStoreInt32; +import org.teavm.backend.wasm.model.expression.WasmStoreInt64; +import org.teavm.backend.wasm.model.expression.WasmSwitch; +import org.teavm.backend.wasm.model.expression.WasmUnreachable; + +public class WasmTypeInference implements WasmExpressionVisitor { + private WasmGenerationContext context; + private WasmType result; + + public WasmTypeInference(WasmGenerationContext context) { + this.context = context; + } + + public WasmType getResult() { + return result; + } + + @Override + public void visit(WasmBlock expression) { + result = expression.getType(); + } + + @Override + public void visit(WasmBranch expression) { + result = null; + } + + @Override + public void visit(WasmBreak expression) { + result = null; + } + + @Override + public void visit(WasmSwitch expression) { + result = null; + } + + @Override + public void visit(WasmConditional expression) { + result = expression.getType(); + } + + @Override + public void visit(WasmReturn expression) { + result = null; + } + + @Override + public void visit(WasmUnreachable expression) { + result = null; + } + + @Override + public void visit(WasmInt32Constant expression) { + result = WasmType.INT32; + } + + @Override + public void visit(WasmInt64Constant expression) { + result = WasmType.INT64; + } + + @Override + public void visit(WasmFloat32Constant expression) { + result = WasmType.FLOAT32; + } + + @Override + public void visit(WasmFloat64Constant expression) { + result = WasmType.FLOAT64; + } + + @Override + public void visit(WasmGetLocal expression) { + result = expression.getLocal().getType(); + } + + @Override + public void visit(WasmSetLocal expression) { + result = null; + } + + @Override + public void visit(WasmIntBinary expression) { + result = map(expression.getType()); + } + + @Override + public void visit(WasmFloatBinary expression) { + result = map(expression.getType()); + } + + @Override + public void visit(WasmIntUnary expression) { + result = map(expression.getType()); + } + + @Override + public void visit(WasmFloatUnary expression) { + result = map(expression.getType()); + } + + @Override + public void visit(WasmConversion expression) { + result = expression.getTargetType(); + } + + @Override + public void visit(WasmCall expression) { + WasmFunction function = context.getFunction(expression.getFunctionName()); + result = function == null ? null : function.getResult(); + } + + @Override + public void visit(WasmIndirectCall expression) { + result = expression.getReturnType(); + } + + @Override + public void visit(WasmDrop expression) { + result = null; + } + + @Override + public void visit(WasmLoadInt32 expression) { + result = WasmType.INT32; + } + + @Override + public void visit(WasmLoadInt64 expression) { + result = WasmType.INT64; + } + + @Override + public void visit(WasmLoadFloat32 expression) { + result = WasmType.FLOAT32; + } + + @Override + public void visit(WasmLoadFloat64 expression) { + result = WasmType.FLOAT64; + } + + @Override + public void visit(WasmStoreInt32 expression) { + result = null; + } + + @Override + public void visit(WasmStoreInt64 expression) { + result = null; + } + + @Override + public void visit(WasmStoreFloat32 expression) { + result = null; + } + + @Override + public void visit(WasmStoreFloat64 expression) { + result = null; + } + + private static WasmType map(WasmIntType type) { + switch (type) { + case INT32: + return WasmType.INT32; + case INT64: + return WasmType.INT64; + default: + throw new IllegalArgumentException(type.toString()); + } + } + + private static WasmType map(WasmFloatType type) { + switch (type) { + case FLOAT32: + return WasmType.FLOAT32; + case FLOAT64: + return WasmType.FLOAT64; + default: + throw new IllegalArgumentException(type.toString()); + } + } +} diff --git a/tools/cli/src/main/java/org/teavm/cli/TeaVMRunner.java b/tools/cli/src/main/java/org/teavm/cli/TeaVMRunner.java index 8506292ee..bc0aeedb4 100644 --- a/tools/cli/src/main/java/org/teavm/cli/TeaVMRunner.java +++ b/tools/cli/src/main/java/org/teavm/cli/TeaVMRunner.java @@ -20,6 +20,7 @@ import java.net.MalformedURLException; import java.net.URL; import java.net.URLClassLoader; import org.apache.commons.cli.*; +import org.teavm.backend.wasm.render.WasmBinaryVersion; import org.teavm.tooling.RuntimeCopyOperation; import org.teavm.tooling.TeaVMTargetType; import org.teavm.tooling.TeaVMTool; @@ -105,6 +106,12 @@ public final class TeaVMRunner { .withDescription("Additional classpath that will be reloaded by TeaVM each time in wait mode") .withLongOpt("classpath") .create('p')); + options.addOption(OptionBuilder + .withArgName("wasm-version") + .hasArg() + .withDescription("WebAssembly binary version (11, 12)") + .withLongOpt("version") + .create()); if (args.length == 0) { printUsage(options); @@ -209,6 +216,8 @@ public final class TeaVMRunner { } boolean interactive = commandLine.hasOption('w'); + setupWasm(tool, commandLine, options); + args = commandLine.getArgs(); if (args.length > 1) { System.err.println("Unexpected arguments"); @@ -275,6 +284,29 @@ public final class TeaVMRunner { System.out.println("Build complete for " + ((System.currentTimeMillis() - startTime) / 1000.0) + " seconds"); } + private static void setupWasm(TeaVMTool tool, CommandLine commandLine, Options options) { + if (commandLine.hasOption("wasm-version")) { + String value = commandLine.getOptionValue("wasm-version"); + try { + int version = Integer.parseInt(value); + switch (version) { + case 11: + tool.setWasmVersion(WasmBinaryVersion.V_0xB); + break; + case 12: + tool.setWasmVersion(WasmBinaryVersion.V_0xC); + break; + default: + System.err.print("Wrong version value"); + printUsage(options); + } + } catch (NumberFormatException e) { + System.err.print("Wrong version value"); + printUsage(options); + } + } + } + private static void resetClassLoader(TeaVMTool tool) { if (classPath == null || classPath.length == 0) { return; diff --git a/tools/core/src/main/java/org/teavm/tooling/TeaVMTool.java b/tools/core/src/main/java/org/teavm/tooling/TeaVMTool.java index 92974f1aa..0ecaaf992 100644 --- a/tools/core/src/main/java/org/teavm/tooling/TeaVMTool.java +++ b/tools/core/src/main/java/org/teavm/tooling/TeaVMTool.java @@ -36,6 +36,7 @@ import org.apache.commons.io.IOUtils; import org.teavm.backend.javascript.JavaScriptTarget; import org.teavm.backend.javascript.rendering.RenderingManager; import org.teavm.backend.wasm.WasmTarget; +import org.teavm.backend.wasm.render.WasmBinaryVersion; import org.teavm.cache.DiskCachedClassHolderSource; import org.teavm.cache.DiskProgramCache; import org.teavm.cache.DiskRegularMethodNodeCache; @@ -98,6 +99,7 @@ public class TeaVMTool implements BaseTeaVMTool { private DebugInformationBuilder debugEmitter; private JavaScriptTarget javaScriptTarget; private WasmTarget webAssemblyTarget; + private WasmBinaryVersion wasmVersion = WasmBinaryVersion.V_0xC; public File getTargetDirectory() { return targetDirectory; @@ -245,6 +247,14 @@ public class TeaVMTool implements BaseTeaVMTool { this.classLoader = classLoader; } + public WasmBinaryVersion getWasmVersion() { + return wasmVersion; + } + + public void setWasmVersion(WasmBinaryVersion wasmVersion) { + this.wasmVersion = wasmVersion; + } + public void setProgressListener(TeaVMProgressListener progressListener) { this.progressListener = progressListener; } @@ -332,6 +342,7 @@ public class TeaVMTool implements BaseTeaVMTool { webAssemblyTarget.setDebugging(debugInformationGenerated); webAssemblyTarget.setCEmitted(debugInformationGenerated); webAssemblyTarget.setWastEmitted(debugInformationGenerated); + webAssemblyTarget.setVersion(wasmVersion); return webAssemblyTarget; } diff --git a/tools/maven/plugin/src/main/java/org/teavm/maven/TeaVMCompileMojo.java b/tools/maven/plugin/src/main/java/org/teavm/maven/TeaVMCompileMojo.java index eb82ba574..eb63ca31b 100644 --- a/tools/maven/plugin/src/main/java/org/teavm/maven/TeaVMCompileMojo.java +++ b/tools/maven/plugin/src/main/java/org/teavm/maven/TeaVMCompileMojo.java @@ -24,6 +24,7 @@ import org.apache.maven.plugins.annotations.LifecyclePhase; import org.apache.maven.plugins.annotations.Mojo; import org.apache.maven.plugins.annotations.Parameter; import org.apache.maven.plugins.annotations.ResolutionScope; +import org.teavm.backend.wasm.render.WasmBinaryVersion; import org.teavm.tooling.ClassAlias; import org.teavm.tooling.MethodAlias; import org.teavm.tooling.RuntimeCopyOperation; @@ -76,6 +77,9 @@ public class TeaVMCompileMojo extends AbstractTeaVMMojo { private TeaVMTool tool = new TeaVMTool(); + @Parameter + private WasmBinaryVersion wasmVersion; + @Override protected File getTargetDirectory() { return targetDirectory; @@ -102,6 +106,7 @@ public class TeaVMCompileMojo extends AbstractTeaVMMojo { } tool.setCacheDirectory(cacheDirectory); tool.setTargetType(targetType); + tool.setWasmVersion(wasmVersion); tool.generate(); if (stopOnErrors && !tool.getProblemProvider().getSevereProblems().isEmpty()) { throw new MojoExecutionException("Build error");