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 a5f5fb45a..1b158a225 100644 --- a/core/src/main/java/org/teavm/backend/wasm/WasmTarget.java +++ b/core/src/main/java/org/teavm/backend/wasm/WasmTarget.java @@ -670,9 +670,10 @@ public class WasmTarget implements TeaVMTarget { gcIntrinsic.setRegionsAddress(address); gcIntrinsic.setRegionMaxCount(regionCount); - gcMemory -= regionCount * 2; address += regionCount * 2; address = (address + 4) >> 2 << 2; + + gcMemory = module.getMemorySize() * 65536 - address; gcIntrinsic.setHeapAddress(address); gcIntrinsic.setAvailableBytes(gcMemory); } 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 d2062906d..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 @@ -22,11 +22,6 @@ import org.teavm.backend.wasm.binary.BinaryWriter; import org.teavm.backend.wasm.model.WasmFunction; import org.teavm.backend.wasm.model.WasmLocal; import org.teavm.backend.wasm.model.WasmType; -import org.teavm.backend.wasm.model.expression.WasmExpression; -import org.teavm.backend.wasm.model.expression.WasmFloat32Constant; -import org.teavm.backend.wasm.model.expression.WasmFloat64Constant; -import org.teavm.backend.wasm.model.expression.WasmInt32Constant; -import org.teavm.backend.wasm.model.expression.WasmInt64Constant; import org.teavm.interop.Export; import org.teavm.model.AnnotationReader; import org.teavm.model.ClassHolder; @@ -90,27 +85,6 @@ public class WasmGenerator { methodAst.getBody().acceptVisitor(visitor); function.getBody().add(visitor.result); - if (function.getResult() != null) { - WasmExpression finalExpr; - switch (function.getResult()) { - case INT32: - finalExpr = new WasmInt32Constant(0); - break; - case INT64: - finalExpr = new WasmInt64Constant(0); - break; - case FLOAT32: - finalExpr = new WasmFloat32Constant(0); - break; - case FLOAT64: - finalExpr = new WasmFloat64Constant(0); - break; - default: - throw new AssertionError(); - } - function.getBody().add(finalExpr); - } - AnnotationReader exportAnnot = method.getAnnotations().get(Export.class.getName()); if (exportAnnot != null) { function.setExportName(exportAnnot.getValue("name").getString()); diff --git a/core/src/main/java/org/teavm/backend/wasm/render/WasmRenderer.java b/core/src/main/java/org/teavm/backend/wasm/render/WasmRenderer.java index e9453c089..58ac4ecfb 100644 --- a/core/src/main/java/org/teavm/backend/wasm/render/WasmRenderer.java +++ b/core/src/main/java/org/teavm/backend/wasm/render/WasmRenderer.java @@ -55,28 +55,24 @@ public class WasmRenderer { public void render(WasmModule module) { visitor.open().append("module"); - renderMemory(module); renderTypes(module); - for (WasmFunction function : module.getFunctions().values()) { - if (function.getImportName() == null) { - continue; - } - lf().renderImport(function); - } for (WasmFunction function : module.getFunctions().values()) { if (function.getImportName() != null) { - continue; + lf().render(function); } - lf().render(function); } for (WasmFunction function : module.getFunctions().values()) { - if (function.getExportName() == null) { - continue; + if (function.getImportName() == null) { + lf().render(function); } - lf().renderExport(function); } + renderTable(module); + renderMemory(module); + renderElement(module); + renderData(module); + if (module.getStartFunction() != null) { visitor.lf().open().append("start $" + module.getStartFunction().getName()).close().lf(); } @@ -85,9 +81,12 @@ public class WasmRenderer { public void renderMemory(WasmModule module) { visitor.lf(); - visitor.open().append("memory " + module.getMemorySize()); + visitor.open().append("memory " + module.getMemorySize()).close().lf(); + } + + public void renderData(WasmModule module) { for (WasmMemorySegment segment : module.getSegments()) { - visitor.lf().open().append("segment " + segment.getOffset()); + visitor.lf().open().append("data (i32.const " + segment.getOffset() + ")"); visitor.indent(); for (int i = 0; i < segment.getLength(); i += 256) { visitor.lf().append("\""); @@ -110,26 +109,21 @@ public class WasmRenderer { visitor.outdent(); visitor.close(); } - visitor.close().lf(); - } - - public void renderImport(WasmFunction function) { - String importModule = function.getImportModule(); - if (importModule == null) { - importModule = ""; - } - visitor.open().append("import $" + function.getName() + " \"" + importModule + "\" " - + "\"" + function.getImportName() + "\""); - renderSignature(function); - visitor.close(); - } - - public void renderExport(WasmFunction function) { - visitor.open().append("export \"" + function.getExportName() + "\" $" + function.getName()).close(); } public void render(WasmFunction function) { visitor.open().append("func $" + function.getName()); + + if (function.getImportName() != null) { + String importModule = function.getImportModule(); + if (importModule == null) { + importModule = ""; + } + visitor.append(" (import \"" + importModule + "\" \"" + function.getImportName() + "\")"); + } else if (function.getExportName() != null) { + visitor.append(" (export \"" + function.getExportName() + "\")"); + } + renderSignature(function); int firstLocalVariable = function.getParameters().size(); @@ -142,6 +136,9 @@ public class WasmRenderer { } visitor.close(); } + for (WasmExpression part : function.getBody()) { + visitor.preprocess(part); + } for (WasmExpression part : function.getBody()) { visitor.line(part); } @@ -195,7 +192,15 @@ public class WasmRenderer { return; } - visitor.lf().open().append("table"); + visitor.lf().open().append("table " + module.getFunctionTable().size() + " anyfunc").close().lf(); + } + + private void renderElement(WasmModule module) { + if (module.getFunctionTable().isEmpty()) { + return; + } + + visitor.lf().open().append("elem (i32.const 0)"); for (WasmFunction function : module.getFunctionTable()) { visitor.lf().append("$" + function.getName()); } diff --git a/core/src/main/java/org/teavm/backend/wasm/render/WasmRenderingVisitor.java b/core/src/main/java/org/teavm/backend/wasm/render/WasmRenderingVisitor.java index 2a44e8c0e..6f68d2174 100644 --- a/core/src/main/java/org/teavm/backend/wasm/render/WasmRenderingVisitor.java +++ b/core/src/main/java/org/teavm/backend/wasm/render/WasmRenderingVisitor.java @@ -29,6 +29,7 @@ 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.WasmDefaultExpressionVisitor; import org.teavm.backend.wasm.model.expression.WasmDrop; import org.teavm.backend.wasm.model.expression.WasmExpression; import org.teavm.backend.wasm.model.expression.WasmExpressionVisitor; @@ -71,6 +72,35 @@ class WasmRenderingVisitor implements WasmExpressionVisitor { List signatureList = new ArrayList<>(); Map signatureMap = new HashMap<>(); + void preprocess(WasmExpression expression) { + expression.acceptVisitor(new WasmDefaultExpressionVisitor() { + @Override + public void visit(WasmBranch expression) { + super.visit(expression); + register(expression.getTarget()); + } + + @Override + public void visit(WasmBreak expression) { + super.visit(expression); + register(expression.getTarget()); + } + + @Override + public void visit(WasmSwitch expression) { + super.visit(expression); + for (WasmBlock target : expression.getTargets()) { + register(target); + } + register(expression.getDefaultTarget()); + } + + private void register(WasmBlock block) { + blockIdentifiers.computeIfAbsent(block, key -> "block_" + blockIdentifiers.size()); + } + }); + } + void clear() { blockIdentifiers.clear(); usedIdentifiers.clear(); @@ -135,13 +165,18 @@ class WasmRenderingVisitor implements WasmExpressionVisitor { @Override public void visit(WasmBlock expression) { - renderBlock(expression, expression.isLoop() ? "loop" : "block"); + renderBlock(expression, expression.isLoop() ? "loop" : "block", true); } - private void renderBlock(WasmBlock block, String name) { - String id = getIdentifier("@block"); - blockIdentifiers.put(block, id); - open().append(name + " $" + id); + private void renderBlock(WasmBlock block, String name, boolean signature) { + open().append(name); + String id = blockIdentifiers.get(block); + if (id != null) { + append(" $" + id); + } + if (signature && block.getType() != null) { + append(" " + type(block.getType())); + } for (WasmExpression part : block.getBody()) { line(part); } @@ -183,14 +218,19 @@ class WasmRenderingVisitor implements WasmExpressionVisitor { @Override public void visit(WasmConditional expression) { open().append("if"); + + if (expression.getType() != null) { + append(" " + type(expression.getType())); + } + line(expression.getCondition()); lf(); - renderBlock(expression.getThenBlock(), "then"); + renderBlock(expression.getThenBlock(), "then", false); if (!expression.getElseBlock().getBody().isEmpty()) { lf(); - renderBlock(expression.getElseBlock(), "else"); + renderBlock(expression.getElseBlock(), "else", false); } close(); @@ -343,7 +383,7 @@ class WasmRenderingVisitor implements WasmExpressionVisitor { @Override public void visit(WasmCall expression) { - open().append(expression.isImported() ? "call_import" : "call").append(" $" + expression.getFunctionName()); + open().append("call").append(" $" + expression.getFunctionName()); for (WasmExpression argument : expression.getArguments()) { line(argument); } diff --git a/core/src/main/java/org/teavm/runtime/GC.java b/core/src/main/java/org/teavm/runtime/GC.java index aaef08171..c4387baae 100644 --- a/core/src/main/java/org/teavm/runtime/GC.java +++ b/core/src/main/java/org/teavm/runtime/GC.java @@ -70,12 +70,15 @@ public final class GC { next = currentChunk.toAddress().add(size); } int freeSize = current.size; - currentChunk = next.toStructure(); freeSize -= size; if (freeSize > 0) { - currentChunk.classReference = 0; + currentChunk = next.toStructure(); currentChunk.size = freeSize; + } else { + freeMemory -= size; + getAvailableChunkIfPossible(currentChunk.size + 1); } + currentChunk.classReference = 0; freeMemory -= size; return current; } @@ -89,6 +92,9 @@ public final class GC { } private static boolean getAvailableChunkIfPossible(int size) { + if (freeChunks == 0) { + return false; + } while (true) { if (currentChunk.toAddress().add(size) == currentChunkLimit) { break;