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 f89c04986..8d44f0c3e 100644 --- a/core/src/main/java/org/teavm/backend/wasm/WasmTarget.java +++ b/core/src/main/java/org/teavm/backend/wasm/WasmTarget.java @@ -60,7 +60,7 @@ import org.teavm.backend.wasm.model.expression.WasmReturn; import org.teavm.backend.wasm.model.expression.WasmStoreInt32; import org.teavm.backend.wasm.patches.ClassPatch; import org.teavm.backend.wasm.patches.ObjectPatch; -import org.teavm.backend.wasm.render.WasmRenderer; +import org.teavm.backend.wasm.render.WasmCRenderer; import org.teavm.dependency.ClassDependency; import org.teavm.dependency.DependencyChecker; import org.teavm.dependency.DependencyListener; @@ -103,6 +103,7 @@ import org.teavm.vm.spi.TeaVMHostExtension; public class WasmTarget implements TeaVMTarget { private TeaVMTargetController controller; + private boolean debugging; @Override public void setController(TeaVMTargetController controller) { @@ -134,6 +135,14 @@ public class WasmTarget implements TeaVMTarget { return listeners; } + public boolean isDebugging() { + return debugging; + } + + public void setDebugging(boolean debugging) { + this.debugging = debugging; + } + @Override public void contributeDependencies(DependencyChecker dependencyChecker) { for (Class type : Arrays.asList(int.class, long.class, float.class, double.class)) { @@ -301,7 +310,8 @@ public class WasmTarget implements TeaVMTarget { module.getFunctionTable().add(module.getFunctions().get(function)); } - WasmRenderer renderer = new WasmRenderer(); + WasmCRenderer renderer = new WasmCRenderer(); + renderer.setOutputLineNumbers(debugging); renderer.render(module); try { diff --git a/core/src/main/java/org/teavm/backend/wasm/render/CBlock.java b/core/src/main/java/org/teavm/backend/wasm/render/CBlock.java index ba0c89326..46f64b8de 100644 --- a/core/src/main/java/org/teavm/backend/wasm/render/CBlock.java +++ b/core/src/main/java/org/teavm/backend/wasm/render/CBlock.java @@ -31,4 +31,13 @@ class CBlock extends CLine { public List getLines() { return lines; } + + @Override + void render(WasmCRenderer target) { + target.indent(); + for (CLine line : lines) { + line.render(target); + } + target.outdent(); + } } diff --git a/core/src/main/java/org/teavm/backend/wasm/render/CExpression.java b/core/src/main/java/org/teavm/backend/wasm/render/CExpression.java index abbdeff94..d4ef77ccf 100644 --- a/core/src/main/java/org/teavm/backend/wasm/render/CExpression.java +++ b/core/src/main/java/org/teavm/backend/wasm/render/CExpression.java @@ -17,6 +17,7 @@ package org.teavm.backend.wasm.render; import java.util.ArrayList; import java.util.List; +import org.teavm.model.TextLocation; class CExpression { private String text; @@ -50,6 +51,14 @@ class CExpression { return lines; } + public void addLine(String text, TextLocation location) { + lines.add(new CSingleLine(text, location)); + } + + public void addLine(String text) { + addLine(text, null); + } + public static CExpression relocatable(String text) { CExpression expression = new CExpression(text); expression.setRelocatable(true); diff --git a/core/src/main/java/org/teavm/backend/wasm/render/CLine.java b/core/src/main/java/org/teavm/backend/wasm/render/CLine.java index 66b282208..71396e11a 100644 --- a/core/src/main/java/org/teavm/backend/wasm/render/CLine.java +++ b/core/src/main/java/org/teavm/backend/wasm/render/CLine.java @@ -16,4 +16,5 @@ package org.teavm.backend.wasm.render; abstract class CLine { + abstract void render(WasmCRenderer target); } diff --git a/core/src/main/java/org/teavm/backend/wasm/render/CSingleLine.java b/core/src/main/java/org/teavm/backend/wasm/render/CSingleLine.java index 829b970ae..1505d604e 100644 --- a/core/src/main/java/org/teavm/backend/wasm/render/CSingleLine.java +++ b/core/src/main/java/org/teavm/backend/wasm/render/CSingleLine.java @@ -15,14 +15,52 @@ */ package org.teavm.backend.wasm.render; +import java.util.Objects; +import org.teavm.model.TextLocation; + class CSingleLine extends CLine { private String text; + private TextLocation location; public CSingleLine(String text) { + this(text, null); + } + + public CSingleLine(String text, TextLocation location) { this.text = text; + this.location = location; } public String getText() { return text; } + + public TextLocation getLocation() { + return location; + } + + public void setLocation(TextLocation location) { + this.location = location; + } + + @Override + void render(WasmCRenderer target) { + if (target.outputLineNumbers) { + TextLocation location = this.location; + if (location == null) { + location = target.lastReportedLocation; + } + if (location != null) { + if (!Objects.equals(target.currentFile, location.getFileName())) { + target.line("#line " + (location.getLine() - 1) + " \"" + location.getFileName() + "\""); + } else if (location.getLine() != target.currentLine) { + target.line("#line " + (location.getLine() - 1)); + } + target.currentFile = location.getFileName(); + target.currentLine = location.getLine() + 1; + target.lastReportedLocation = location; + } + } + target.line(text); + } } diff --git a/core/src/main/java/org/teavm/backend/wasm/render/WasmCRenderer.java b/core/src/main/java/org/teavm/backend/wasm/render/WasmCRenderer.java index eafc8997e..925fa745c 100644 --- a/core/src/main/java/org/teavm/backend/wasm/render/WasmCRenderer.java +++ b/core/src/main/java/org/teavm/backend/wasm/render/WasmCRenderer.java @@ -15,5 +15,187 @@ */ package org.teavm.backend.wasm.render; +import java.util.ArrayList; +import java.util.List; +import org.teavm.backend.wasm.model.WasmFunction; +import org.teavm.backend.wasm.model.WasmLocal; +import org.teavm.backend.wasm.model.WasmMemorySegment; +import org.teavm.backend.wasm.model.WasmModule; +import org.teavm.backend.wasm.model.expression.WasmExpression; +import org.teavm.model.TextLocation; + public class WasmCRenderer { + private StringBuilder out = new StringBuilder(); + private int indentLevel; + String currentFile = ""; + int currentLine = -1; + boolean outputLineNumbers; + TextLocation lastReportedLocation; + + public boolean isOutputLineNumbers() { + return outputLineNumbers; + } + + public void setOutputLineNumbers(boolean outputLineNumbers) { + this.outputLineNumbers = outputLineNumbers; + } + + void indent() { + ++indentLevel; + } + + void outdent() { + --indentLevel; + } + + void line(String line) { + for (int i = 0; i < indentLevel; ++i) { + out.append(" "); + } + out.append(line).append("\n"); + } + + public void render(WasmModule module) { + line("#include "); + line("#include "); + line("#include "); + line("#include "); + line(""); + + renderFunctionDeclarations(module); + line("static int8_t *wasm_heap;"); + renderFunctionTable(module); + + for (WasmFunction function : module.getFunctions().values()) { + if (function.getImportName() == null) { + renderFunction(function); + } + } + + line("void main() {"); + indent(); + + renderHeap(module); + if (module.getStartFunction() != null) { + line(module.getStartFunction().getName() + "();"); + } + + for (WasmFunction function : module.getFunctions().values()) { + if (function.getExportName() != null && function.getExportName().equals("main")) { + line(function.getName() + "(0);"); + } + } + + outdent(); + line("}"); + } + + private void renderHeap(WasmModule module) { + line("wasm_heap = malloc(" + 65535 * module.getMemorySize() + ");"); + for (WasmMemorySegment segment : module.getSegments()) { + line("memcpy(wasm_heap + " + segment.getOffset() + ","); + indent(); + for (int i = 0; i < segment.getLength(); i += 48) { + byte[] data = segment.getData(i, Math.min(i + 48, segment.getLength()) - i); + boolean last = i + data.length >= segment.getLength(); + StringBuilder sb = new StringBuilder("\""); + for (int j = 0; j < data.length; ++j) { + byte b = data[j]; + sb.append("\\x") + .append(Character.forDigit((b >>> 4) & 0xF, 16)) + .append(Character.forDigit(b & 0xF, 16)); + } + sb.append("\""); + if (last) { + sb.append(", " + segment.getLength() + ");"); + } + line(sb.toString()); + } + outdent(); + } + } + + private void renderFunctionTable(WasmModule module) { + line("static void *wasm_table[] = {"); + if (!module.getFunctionTable().isEmpty()) { + indent(); + for (int i = 0; i < module.getFunctionTable().size() - 1; ++i) { + WasmFunction function = module.getFunctionTable().get(i); + line(function.getName() + ","); + } + line(module.getFunctionTable().get(module.getFunctionTable().size() - 1).getName()); + outdent(); + } + line("};"); + line(""); + } + + private void renderFunctionDeclarations(WasmModule module) { + for (WasmFunction function : module.getFunctions().values()) { + line(functionDeclaration(function) + ";"); + } + } + + private void renderFunction(WasmFunction function) { + line(functionDeclaration(function) + " {"); + indent(); + + List variables = function.getLocalVariables().subList(function.getParameters().size(), + function.getLocalVariables().size()); + for (WasmLocal variable : variables) { + line(WasmCRenderingVisitor.mapType(variable.getType()) + " var_" + variable.getIndex() + ";"); + } + + WasmCRenderingVisitor visitor = new WasmCRenderingVisitor(function.getResult(), function.getModule()); + List body = function.getBody(); + List lines = new ArrayList<>(); + if (!body.isEmpty()) { + for (int i = 0; i < body.size() - 1; ++i) { + visitor.setRequiredType(null); + body.get(i).acceptVisitor(visitor); + lines.addAll(visitor.getValue().getLines()); + } + + visitor.setRequiredType(function.getResult()); + body.get(body.size() - 1).acceptVisitor(visitor); + lines.addAll(visitor.getValue().getLines()); + if (visitor.getValue().getText() != null) { + lines.add(new CSingleLine(visitor.getValue().getText())); + } + } + + for (CLine line : lines) { + line.render(this); + } + + outdent(); + line("}"); + line(""); + } + + private String functionDeclaration(WasmFunction function) { + StringBuilder sb = new StringBuilder(); + if (function.getImportName() != null) { + sb.append("extern "); + } else if (function.getExportName() == null) { + sb.append("static "); + } + sb.append(WasmCRenderingVisitor.mapType(function.getResult())).append(' '); + sb.append(function.getName()).append("("); + for (int i = 0; i < function.getParameters().size(); ++i) { + if (i > 0) { + sb.append(", "); + } + sb.append(WasmCRenderingVisitor.mapType(function.getParameters().get(i))); + sb.append(" var_" + i); + } + sb.append(")"); + + return sb.toString(); + } + + @Override + public String toString() { + return out.toString(); + } } diff --git a/core/src/main/java/org/teavm/backend/wasm/render/WasmCRenderingVisitor.java b/core/src/main/java/org/teavm/backend/wasm/render/WasmCRenderingVisitor.java index 99ed05543..579942648 100644 --- a/core/src/main/java/org/teavm/backend/wasm/render/WasmCRenderingVisitor.java +++ b/core/src/main/java/org/teavm/backend/wasm/render/WasmCRenderingVisitor.java @@ -67,7 +67,7 @@ class WasmCRenderingVisitor implements WasmExpressionVisitor { private WasmType functionType; private WasmModule module; - public WasmCRenderingVisitor(WasmType functionType, WasmModule module) { + WasmCRenderingVisitor(WasmType functionType, WasmModule module) { this.functionType = functionType; this.module = module; } @@ -76,6 +76,10 @@ class WasmCRenderingVisitor implements WasmExpressionVisitor { return value; } + void setRequiredType(WasmType requiredType) { + this.requiredType = requiredType; + } + @Override public void visit(WasmBlock expression) { BlockInfo info = new BlockInfo(); @@ -99,7 +103,7 @@ class WasmCRenderingVisitor implements WasmExpressionVisitor { result.getLines().addAll(value.getLines()); if (info.type != null) { if (info.temporaryVariable != null) { - result.getLines().add(new CSingleLine(info.temporaryVariable + " = " + result.getText())); + result.getLines().add(new CSingleLine(info.temporaryVariable + " = " + value.getText() + ";")); result.setText(info.temporaryVariable); } else { result.setText(value.getText()); @@ -110,14 +114,15 @@ class WasmCRenderingVisitor implements WasmExpressionVisitor { result.getLines().add(0, declareVariable(info.temporaryVariable, info.type)); } - if (info.label != null || expression.isLoop()) { + if (expression.isLoop()) { List lines = new ArrayList<>(); - String header = expression.isLoop() ? "for(;;) " : ""; - lines.add(new CSingleLine(info.label + ": " + header + "{")); + lines.add(new CSingleLine(getLabel(info) + ": do {")); lines.add(new CBlock(result.getLines())); - lines.add(new CSingleLine("}")); + lines.add(new CSingleLine("} while(0);")); result.getLines().clear(); result.getLines().addAll(lines); + } else if (info.label != null) { + result.getLines().add(new CSingleLine(info.label + ": ;")); } } @@ -132,9 +137,9 @@ class WasmCRenderingVisitor implements WasmExpressionVisitor { requiredType = WasmType.INT32; expression.getCondition().acceptVisitor(this); result.getLines().addAll(value.getLines()); - reportLocation(expression.getLocation(), result.getLines()); - result.getLines().add(new CSingleLine("if (" + value.getText() + ") {")); - CBlock breakBlock = new CBlock(generateBreak(expression.getResult(), expression.getTarget())); + result.addLine("if (" + value.getText() + ") {", expression.getLocation()); + CBlock breakBlock = new CBlock(generateBreak(expression.getResult(), expression.getTarget(), + expression.getLocation())); result.getLines().add(breakBlock); result.getLines().add(new CSingleLine("}")); @@ -144,11 +149,12 @@ class WasmCRenderingVisitor implements WasmExpressionVisitor { @Override public void visit(WasmBreak expression) { CExpression result = new CExpression(); - result.getLines().addAll(generateBreak(expression.getResult(), expression.getTarget())); + result.getLines().addAll(generateBreak(expression.getResult(), expression.getTarget(), + expression.getLocation())); value = result; } - private List generateBreak(WasmExpression result, WasmBlock target) { + private List generateBreak(WasmExpression result, WasmBlock target, TextLocation location) { List lines = new ArrayList<>(); BlockInfo targetInfo = blockInfoMap.get(target); @@ -156,25 +162,24 @@ class WasmCRenderingVisitor implements WasmExpressionVisitor { if (targetInfo.temporaryVariable == null) { targetInfo.temporaryVariable = "tmp_" + temporaryIndex++; } - if (targetInfo.label == null) { - targetInfo.label = "block_" + blockIndex++; - } requiredType = targetInfo.type; result.acceptVisitor(this); lines.addAll(value.getLines()); - reportLocation(result.getLocation(), lines); - lines.add(new CSingleLine(targetInfo.temporaryVariable + " = " + value.getText() + ";")); - } - reportLocation(result.getLocation(), lines); - if (target.isLoop()) { - lines.add(new CSingleLine("break " + targetInfo.label + ";")); - } else { - lines.add(new CSingleLine("continue " + targetInfo.label + ";")); + lines.add(new CSingleLine(targetInfo.temporaryVariable + " = " + value.getText() + ";", + result.getLocation())); } + lines.add(new CSingleLine("goto " + getLabel(targetInfo) + ";", location)); return lines; } + private String getLabel(BlockInfo blockInfo) { + if (blockInfo.label == null) { + blockInfo.label = "block_" + blockIndex++; + } + return blockInfo.label; + } + @Override public void visit(WasmSwitch expression) { CExpression result = new CExpression(); @@ -182,24 +187,17 @@ class WasmCRenderingVisitor implements WasmExpressionVisitor { requiredType = WasmType.INT32; expression.getSelector().acceptVisitor(this); result.getLines().addAll(value.getLines()); - reportLocation(expression.getLocation(), result.getLines()); - result.getLines().add(new CSingleLine("switch (" + value.getLines() + ") {")); + result.addLine("switch (" + value.getText() + ") {", expression.getLocation()); CBlock switchBlock = new CBlock(); result.getLines().add(switchBlock); for (int i = 0; i < expression.getTargets().size(); ++i) { BlockInfo targetInfo = blockInfoMap.get(expression.getTargets().get(i)); - if (targetInfo.label == null) { - targetInfo.label = "block_" + blockIndex++; - } - switchBlock.getLines().add(new CSingleLine("case " + i + ": break " + targetInfo.label + ";")); + switchBlock.getLines().add(new CSingleLine("case " + i + ": goto " + getLabel(targetInfo) + ";")); } BlockInfo defaultTargetInfo = blockInfoMap.get(expression.getDefaultTarget()); - if (defaultTargetInfo.label == null) { - defaultTargetInfo.label = "block_" + blockIndex++; - } - switchBlock.getLines().add(new CSingleLine("default: break " + defaultTargetInfo.label + ";")); + switchBlock.getLines().add(new CSingleLine("default: goto " + getLabel(defaultTargetInfo) + ";")); result.getLines().add(new CSingleLine("}")); @@ -241,17 +239,18 @@ class WasmCRenderingVisitor implements WasmExpressionVisitor { CBlock thenBlock = new CBlock(); thenBlock.getLines().addAll(thenExpression.getLines()); if (temporary != null) { - thenBlock.getLines().add(new CSingleLine(temporary + " = " + thenExpression.getText())); + thenBlock.getLines().add(new CSingleLine(temporary + " = " + thenExpression.getText() + ";")); } result.getLines().add(thenBlock); - if (!elseExpression.getText().isEmpty() || elseExpression.getText() != null) { + if (elseExpression.getText() != null || !elseExpression.getLines().isEmpty()) { result.getLines().add(new CSingleLine("} else {")); CBlock elseBlock = new CBlock(); - elseBlock.getLines().addAll(elseBlock.getLines()); + elseBlock.getLines().addAll(elseExpression.getLines()); if (temporary != null) { - elseBlock.getLines().add(new CSingleLine(temporary + " = " + elseExpression.getText())); + elseBlock.getLines().add(new CSingleLine(temporary + " = " + elseExpression.getText() + ";")); } + result.getLines().add(elseBlock); } result.getLines().add(new CSingleLine("}")); @@ -267,11 +266,9 @@ class WasmCRenderingVisitor implements WasmExpressionVisitor { requiredType = functionType; expression.getValue().acceptVisitor(this); result.getLines().addAll(value.getLines()); - reportLocation(expression.getLocation(), result.getLines()); - result.getLines().add(new CSingleLine("return " + value.getText() + ";")); + result.addLine("return " + value.getText() + ";", expression.getLocation()); } else { - reportLocation(expression.getLocation(), result.getLines()); - result.getLines().add(new CSingleLine("return;")); + result.addLine("return;", expression.getLocation()); } value = result; @@ -280,8 +277,7 @@ class WasmCRenderingVisitor implements WasmExpressionVisitor { @Override public void visit(WasmUnreachable expression) { CExpression result = new CExpression(); - reportLocation(expression.getLocation(), result.getLines()); - result.getLines().add(new CSingleLine("assert(false);")); + result.addLine("assert(0);", expression.getLocation()); value = result; } @@ -317,7 +313,8 @@ class WasmCRenderingVisitor implements WasmExpressionVisitor { expression.getValue().acceptVisitor(this); result.getLines().addAll(value.getLines()); - reportLocation(expression.getLocation(), result.getLines()); + result.addLine("var_" + expression.getLocal().getIndex() + " = " + value.getText() + ";", + expression.getLocation()); value = result; } @@ -514,7 +511,7 @@ class WasmCRenderingVisitor implements WasmExpressionVisitor { if (expression.isRelocatable()) { return expression; } - String var = "tmp_" + temporaryIndex; + String var = "tmp_" + temporaryIndex++; target.getLines().add(new CSingleLine(mapType(type) + " " + var + " = " + expression.getText() + ";")); return CExpression.relocatable(var); } @@ -615,7 +612,7 @@ class WasmCRenderingVisitor implements WasmExpressionVisitor { CExpression operand = value; result.getLines().addAll(operand.getLines()); - if (type != null && expression.getSourceType() != expression.getSourceType()) { + if (type != null && expression.getSourceType() != expression.getTargetType()) { switch (expression.getTargetType()) { case INT32: if (expression.isSigned()) { @@ -652,7 +649,7 @@ class WasmCRenderingVisitor implements WasmExpressionVisitor { } } - value = operand; + value = result; } @Override @@ -668,8 +665,7 @@ class WasmCRenderingVisitor implements WasmExpressionVisitor { result.setText(sb.toString()); if (type == null) { - reportLocation(expression.getLocation(), result.getLines()); - result.getLines().add(new CSingleLine(result.getText())); + result.addLine(result.getText() + ";", expression.getLocation()); result.setText(null); } value = result; @@ -688,19 +684,19 @@ class WasmCRenderingVisitor implements WasmExpressionVisitor { } sb.append(mapType(expression.getParameterTypes().get(i))); } - sb.append(") "); + sb.append(")) "); requiredType = WasmType.INT32; expression.getSelector().acceptVisitor(this); value = cacheIfNeeded(WasmType.INT32, value, result); result.getLines().addAll(value.getLines()); - sb.append("wasm_table[" + result.getText() + "])("); + sb.append("wasm_table[" + value.getText() + "])("); translateArguments(expression.getArguments(), expression.getParameterTypes(), result, sb); sb.append(")"); + result.setText(sb.toString()); if (type == null) { - reportLocation(expression.getLocation(), result.getLines()); - result.getLines().add(new CSingleLine(result.getText())); + result.addLine(result.getText() + ";", expression.getLocation()); result.setText(null); } value = result; @@ -742,7 +738,6 @@ class WasmCRenderingVisitor implements WasmExpressionVisitor { public void visit(WasmDrop expression) { CExpression result = new CExpression(); requiredType = null; - reportLocation(expression.getLocation(), result.getLines()); expression.getOperand().acceptVisitor(this); result.getLines().addAll(value.getLines()); value = result; @@ -754,7 +749,7 @@ class WasmCRenderingVisitor implements WasmExpressionVisitor { WasmType type = requiredType; requiredType = WasmType.INT32; - expression.getIndex(); + expression.getIndex().acceptVisitor(this); CExpression index = value; if (type == null) { value = index; @@ -764,19 +759,19 @@ class WasmCRenderingVisitor implements WasmExpressionVisitor { result.getLines().addAll(index.getLines()); switch (expression.getConvertFrom()) { case INT8: - result.setText("(int32_t) (int8_t) wasm_heap[" + index + "]"); + result.setText("(int32_t) (int8_t) wasm_heap[" + index.getText() + "]"); break; case UINT8: - result.setText("(int32_t) (uint8_t) wasm_heap[" + index + "]"); + result.setText("(int32_t) (uint8_t) wasm_heap[" + index.getText() + "]"); break; case INT16: - result.setText("(int32_t) *((int16_t *) &wasm_heap[" + index + "])"); + result.setText("(int32_t) *((int16_t *) &wasm_heap[" + index.getText() + "])"); break; case UINT16: - result.setText("(int32_t) *((uint16_t *) &wasm_heap[" + index + "])"); + result.setText("(int32_t) *((uint16_t *) &wasm_heap[" + index.getText() + "])"); break; case INT32: - result.setText("*((int32_t *) &wasm_heap[" + index + "])"); + result.setText("*((int32_t *) &wasm_heap[" + index.getText() + "])"); break; } @@ -789,7 +784,7 @@ class WasmCRenderingVisitor implements WasmExpressionVisitor { WasmType type = requiredType; requiredType = WasmType.INT32; - expression.getIndex(); + expression.getIndex().acceptVisitor(this); CExpression index = value; if (type == null) { value = index; @@ -799,25 +794,25 @@ class WasmCRenderingVisitor implements WasmExpressionVisitor { result.getLines().addAll(index.getLines()); switch (expression.getConvertFrom()) { case INT8: - result.setText("(int64_t) (int8_t) wasm_heap[" + index + "]"); + result.setText("(int64_t) (int8_t) wasm_heap[" + index.getText() + "]"); break; case UINT8: - result.setText("(int64_t) (uint8_t) wasm_heap[" + index + "]"); + result.setText("(int64_t) (uint8_t) wasm_heap[" + index.getText() + "]"); break; case INT16: - result.setText("(int64_t) *((int16_t *) &wasm_heap[" + index + "])"); + result.setText("(int64_t) *((int16_t *) &wasm_heap[" + index.getText() + "])"); break; case UINT16: - result.setText("(int64_t) *((uint16_t *) &wasm_heap[" + index + "])"); + result.setText("(int64_t) *((uint16_t *) &wasm_heap[" + index.getText() + "])"); break; case INT32: - result.setText("(int64_t) *((int32_t *) &wasm_heap[" + index + "])"); + result.setText("(int64_t) *((int32_t *) &wasm_heap[" + index.getText() + "])"); break; case UINT32: - result.setText("(int64_t) *((uint32_t *) &wasm_heap[" + index + "])"); + result.setText("(int64_t) *((uint32_t *) &wasm_heap[" + index.getText() + "])"); break; case INT64: - result.setText("*((int64_t *) &wasm_heap[" + index + "])"); + result.setText("*((int64_t *) &wasm_heap[" + index.getText() + "])"); break; } @@ -830,7 +825,7 @@ class WasmCRenderingVisitor implements WasmExpressionVisitor { WasmType type = requiredType; requiredType = WasmType.INT32; - expression.getIndex(); + expression.getIndex().acceptVisitor(this); CExpression index = value; if (type == null) { value = index; @@ -838,7 +833,7 @@ class WasmCRenderingVisitor implements WasmExpressionVisitor { } result.getLines().addAll(index.getLines()); - result.setText("*((float *) &wasm_heap[" + index + "])"); + result.setText("*((float *) &wasm_heap[" + index.getText() + "])"); value = result; } @@ -849,7 +844,7 @@ class WasmCRenderingVisitor implements WasmExpressionVisitor { WasmType type = requiredType; requiredType = WasmType.INT32; - expression.getIndex(); + expression.getIndex().acceptVisitor(this); CExpression index = value; if (type == null) { value = index; @@ -857,42 +852,145 @@ class WasmCRenderingVisitor implements WasmExpressionVisitor { } result.getLines().addAll(index.getLines()); - result.setText("*((double *) &wasm_heap[" + index + "])"); + result.setText("*((double *) &wasm_heap[" + index.getText() + "])"); value = result; } @Override public void visit(WasmStoreInt32 expression) { + CExpression result = new CExpression(); + requiredType = WasmType.INT32; + expression.getIndex().acceptVisitor(this); + CExpression index = value; + + requiredType = WasmType.INT32; + expression.getValue().acceptVisitor(this); + CExpression valueToStore = value; + + result.getLines().addAll(index.getLines()); + result.getLines().addAll(valueToStore.getLines()); + + String line; + switch (expression.getConvertTo()) { + case INT8: + line = "wasm_heap[" + index.getText() + "] = " + valueToStore.getText() + ";"; + break; + case UINT8: + line = "*((uint8_t *) &wasm_heap[" + index.getText() + "]) = " + valueToStore.getText() + ";"; + break; + case INT16: + line = "*((int16_t *) &wasm_heap[" + index.getText() + "]) = " + valueToStore.getText() + ";"; + break; + case UINT16: + line = "*((uint16_t *) &wasm_heap[" + index.getText() + "]) = " + valueToStore.getText() + ";"; + break; + case INT32: + line = "*((int32_t *) &wasm_heap[" + index.getText() + "]) = " + valueToStore.getText() + ";"; + break; + default: + throw new AssertionError(expression.getConvertTo().toString()); + } + result.addLine(line, expression.getLocation()); + + value = result; } @Override public void visit(WasmStoreInt64 expression) { + CExpression result = new CExpression(); + requiredType = WasmType.INT32; + expression.getIndex().acceptVisitor(this); + CExpression index = value; + + requiredType = WasmType.INT64; + expression.getValue().acceptVisitor(this); + CExpression valueToStore = value; + + result.getLines().addAll(index.getLines()); + result.getLines().addAll(valueToStore.getLines()); + + String line; + switch (expression.getConvertTo()) { + case INT8: + line = "wasm_heap[" + index.getText() + "] = " + valueToStore.getText(); + break; + case UINT8: + line = "*((uint8_t *) &wasm_heap[" + index.getText() + "]) = " + valueToStore.getText() + ";"; + break; + case INT16: + line = "*((int16_t *) &wasm_heap[" + index.getText() + "]) = " + valueToStore.getText() + ";"; + break; + case UINT16: + line = "*((uint16_t *) &wasm_heap[" + index.getText() + "]) = " + valueToStore.getText() + ";"; + break; + case INT32: + line = "*((int32_t *) &wasm_heap[" + index.getText() + "]) = " + valueToStore.getText() + ";"; + break; + case UINT32: + line = "*((uint32_t *) &wasm_heap[" + index.getText() + "]) = " + valueToStore.getText() + ";"; + break; + case INT64: + line = "*((int64_t *) &wasm_heap[" + index.getText() + "]) = " + valueToStore.getText() + ";"; + break; + default: + throw new AssertionError(); + } + + result.addLine(line, expression.getLocation()); + + value = result; } @Override public void visit(WasmStoreFloat32 expression) { + CExpression result = new CExpression(); + requiredType = WasmType.INT32; + expression.getIndex().acceptVisitor(this); + CExpression index = value; + + requiredType = WasmType.FLOAT32; + expression.getValue().acceptVisitor(this); + CExpression valueToStore = value; + + result.getLines().addAll(index.getLines()); + result.getLines().addAll(valueToStore.getLines()); + + result.addLine("*((float *) &wasm_heap[" + index.getText() + "]) = " + valueToStore.getText() + ";", + expression.getLocation()); + + value = result; } @Override public void visit(WasmStoreFloat64 expression) { + CExpression result = new CExpression(); + requiredType = WasmType.INT32; + expression.getIndex().acceptVisitor(this); + CExpression index = value; + + requiredType = WasmType.FLOAT64; + expression.getValue().acceptVisitor(this); + CExpression valueToStore = value; + + result.getLines().addAll(index.getLines()); + result.getLines().addAll(valueToStore.getLines()); + + result.addLine("*((double *) &wasm_heap[" + index.getText() + "]) = " + valueToStore.getText() + ";", + expression.getLocation()); + + value = result; } private CLine declareVariable(String name, WasmType type) { return new CSingleLine(mapType(type) + " " + name + ";"); } - private void reportLocation(TextLocation location, List lines) { - if (location != null) { - lines.add(new CSingleLine("#line " + location.getFileName() + " " + location.getLine())); - } - } - - private static String mapType(WasmType type) { + static String mapType(WasmType type) { if (type == null) { return "void"; } @@ -929,7 +1027,7 @@ class WasmCRenderingVisitor implements WasmExpressionVisitor { throw new AssertionError(type.toString()); } - static class BlockInfo { + private static class BlockInfo { int index; String label; String temporaryVariable; 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 22053d2c6..0ddd401bf 100644 --- a/tools/core/src/main/java/org/teavm/tooling/TeaVMTool.java +++ b/tools/core/src/main/java/org/teavm/tooling/TeaVMTool.java @@ -320,6 +320,7 @@ public class TeaVMTool implements BaseTeaVMTool { private WasmTarget prepareWebAssemblyTarget() { webAssemblyTarget = new WasmTarget(); + webAssemblyTarget.setDebugging(debugInformationGenerated); return webAssemblyTarget; }