mirror of
https://github.com/Eaglercraft-TeaVM-Fork/eagler-teavm.git
synced 2024-12-22 08:14:09 -08:00
wasm gc: support emitting disassembly in HTML with link references, add setting to emit disassembly in JUnit tests
This commit is contained in:
parent
a8b999f8d9
commit
31d89ebec2
|
@ -102,23 +102,33 @@ public abstract class BaseDisassemblyListener {
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void writeGlobalRef(int index) {
|
protected void writeGlobalRef(int index) {
|
||||||
|
writer.startLink("g" + index);
|
||||||
writeRef(nameProvider.global(index), index);
|
writeRef(nameProvider.global(index), index);
|
||||||
|
writer.endLink();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void writeFunctionRef(int index) {
|
protected void writeFunctionRef(int index) {
|
||||||
|
writer.startLink("f" + index);
|
||||||
writeRef(nameProvider.function(index), index);
|
writeRef(nameProvider.function(index), index);
|
||||||
|
writer.endLink();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void writeTypeRef(int index) {
|
protected void writeTypeRef(int index) {
|
||||||
|
writer.startLink("t" + index);
|
||||||
writeRef(nameProvider.type(index), index);
|
writeRef(nameProvider.type(index), index);
|
||||||
|
writer.endLink();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void writeFieldRef(int typeIndex, int index) {
|
protected void writeFieldRef(int typeIndex, int index) {
|
||||||
|
writer.startLink("f" + typeIndex + "." + index);
|
||||||
writeRef(nameProvider.field(typeIndex, index), index);
|
writeRef(nameProvider.field(typeIndex, index), index);
|
||||||
|
writer.endLink();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void writeLocalRef(int functionIndex, int index) {
|
protected void writeLocalRef(int functionIndex, int index) {
|
||||||
|
writer.startLink("l" + functionIndex + "." + index);
|
||||||
writeRef(nameProvider.local(functionIndex, index), index);
|
writeRef(nameProvider.local(functionIndex, index), index);
|
||||||
|
writer.endLink();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void writeRef(String name, int index) {
|
private void writeRef(String name, int index) {
|
||||||
|
|
|
@ -16,10 +16,9 @@
|
||||||
package org.teavm.backend.wasm.disasm;
|
package org.teavm.backend.wasm.disasm;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
|
import java.io.FileOutputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.OutputStreamWriter;
|
|
||||||
import java.io.PrintWriter;
|
import java.io.PrintWriter;
|
||||||
import java.io.Writer;
|
|
||||||
import java.nio.file.Files;
|
import java.nio.file.Files;
|
||||||
import java.util.function.Consumer;
|
import java.util.function.Consumer;
|
||||||
import org.teavm.backend.wasm.parser.AddressListener;
|
import org.teavm.backend.wasm.parser.AddressListener;
|
||||||
|
@ -35,12 +34,10 @@ import org.teavm.common.AsyncInputStream;
|
||||||
import org.teavm.common.ByteArrayAsyncInputStream;
|
import org.teavm.common.ByteArrayAsyncInputStream;
|
||||||
|
|
||||||
public final class Disassembler {
|
public final class Disassembler {
|
||||||
private PrintWriter out;
|
|
||||||
private DisassemblyWriter writer;
|
private DisassemblyWriter writer;
|
||||||
|
|
||||||
public Disassembler(Writer writer) {
|
public Disassembler(DisassemblyWriter writer) {
|
||||||
out = new PrintWriter(writer);
|
this.writer = writer;
|
||||||
this.writer = new DisassemblyWriter(out, true);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void startModule() {
|
public void startModule() {
|
||||||
|
@ -52,9 +49,11 @@ public final class Disassembler {
|
||||||
}
|
}
|
||||||
|
|
||||||
public void disassemble(byte[] bytes) {
|
public void disassemble(byte[] bytes) {
|
||||||
|
writer.prologue();
|
||||||
startModule();
|
startModule();
|
||||||
read(bytes);
|
read(bytes);
|
||||||
endModule();
|
endModule();
|
||||||
|
writer.epilogue();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void read(byte[] bytes) {
|
public void read(byte[] bytes) {
|
||||||
|
@ -97,12 +96,12 @@ public final class Disassembler {
|
||||||
};
|
};
|
||||||
if (code == 1) {
|
if (code == 1) {
|
||||||
return bytes -> {
|
return bytes -> {
|
||||||
writer.write("(; type section size: " + bytes.length + " ;)");
|
writer.write("(; type section size: " + bytes.length + " ;)").eol();
|
||||||
var typeWriter = new DisassemblyTypeSectionListener(writer, nameProvider);
|
var typeWriter = new DisassemblyTypeSectionListener(writer, nameProvider);
|
||||||
writer.setAddressOffset(pos);
|
writer.setAddressOffset(pos);
|
||||||
var sectionParser = new TypeSectionParser(typeWriter);
|
var sectionParser = new TypeSectionParser(typeWriter);
|
||||||
sectionParser.parse(writer.addressListener, bytes);
|
sectionParser.parse(writer.addressListener, bytes);
|
||||||
out.flush();
|
writer.flush();
|
||||||
};
|
};
|
||||||
} else if (code == 2) {
|
} else if (code == 2) {
|
||||||
return bytes -> {
|
return bytes -> {
|
||||||
|
@ -111,23 +110,23 @@ public final class Disassembler {
|
||||||
};
|
};
|
||||||
} else if (code == 6) {
|
} else if (code == 6) {
|
||||||
return bytes -> {
|
return bytes -> {
|
||||||
writer.write("(; global section size: " + bytes.length + " ;)");
|
writer.write("(; global section size: " + bytes.length + " ;)").eol();
|
||||||
var globalWriter = new DisassemblyGlobalSectionListener(writer, nameProvider);
|
var globalWriter = new DisassemblyGlobalSectionListener(writer, nameProvider);
|
||||||
writer.setAddressOffset(pos);
|
writer.setAddressOffset(pos);
|
||||||
var sectionParser = new GlobalSectionParser(globalWriter);
|
var sectionParser = new GlobalSectionParser(globalWriter);
|
||||||
sectionParser.setFunctionIndexOffset(importListener.count);
|
sectionParser.setFunctionIndexOffset(importListener.count);
|
||||||
sectionParser.parse(writer.addressListener, bytes);
|
sectionParser.parse(writer.addressListener, bytes);
|
||||||
out.flush();
|
writer.flush();
|
||||||
};
|
};
|
||||||
} else if (code == 10) {
|
} else if (code == 10) {
|
||||||
return bytes -> {
|
return bytes -> {
|
||||||
var disassembler = new DisassemblyCodeSectionListener(writer, nameProvider);
|
var disassembler = new DisassemblyCodeSectionListener(writer, nameProvider);
|
||||||
writer.setAddressOffset(pos);
|
writer.setAddressOffset(pos);
|
||||||
writer.write("(; code section size: " + bytes.length + " ;)");
|
writer.write("(; code section size: " + bytes.length + " ;)").eol();
|
||||||
var sectionParser = new CodeSectionParser(disassembler);
|
var sectionParser = new CodeSectionParser(disassembler);
|
||||||
sectionParser.setFunctionIndexOffset(importListener.count);
|
sectionParser.setFunctionIndexOffset(importListener.count);
|
||||||
sectionParser.parse(writer.addressListener, bytes);
|
sectionParser.parse(writer.addressListener, bytes);
|
||||||
out.flush();
|
writer.flush();
|
||||||
};
|
};
|
||||||
} else {
|
} else {
|
||||||
return null;
|
return null;
|
||||||
|
@ -146,9 +145,34 @@ public final class Disassembler {
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void main(String[] args) throws IOException {
|
public static void main(String[] args) throws IOException {
|
||||||
var file = new File(args[0]);
|
String fileName = null;
|
||||||
|
String outFileName = null;
|
||||||
|
var htmlMode = false;
|
||||||
|
for (var i = 0; i < args.length; i++) {
|
||||||
|
var arg = args[i];
|
||||||
|
if (arg.equals("--html")) {
|
||||||
|
htmlMode = true;
|
||||||
|
} else if (arg.equals("--output") || arg.equals("-o")) {
|
||||||
|
outFileName = args[++i];
|
||||||
|
} else {
|
||||||
|
fileName = arg;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
var file = new File(fileName);
|
||||||
var bytes = Files.readAllBytes(file.toPath());
|
var bytes = Files.readAllBytes(file.toPath());
|
||||||
var disassembler = new Disassembler(new OutputStreamWriter(System.out));
|
var output = outFileName != null ? new FileOutputStream(outFileName) : System.out;
|
||||||
|
var writer = new PrintWriter(output);
|
||||||
|
var disassemblyWriter = htmlMode
|
||||||
|
? new DisassemblyHTMLWriter(writer)
|
||||||
|
: new DisassemblyTextWriter(writer);
|
||||||
|
disassemblyWriter.setWithAddress(true);
|
||||||
|
if (htmlMode) {
|
||||||
|
disassemblyWriter.write("<html><body><pre>").eol();
|
||||||
|
}
|
||||||
|
var disassembler = new Disassembler(disassemblyWriter);
|
||||||
disassembler.disassemble(bytes);
|
disassembler.disassemble(bytes);
|
||||||
|
if (htmlMode) {
|
||||||
|
disassemblyWriter.write("</pre></body></html>").eol();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -43,6 +43,10 @@ public class DisassemblyCodeListener extends BaseDisassemblyListener implements
|
||||||
this.currentFunctionId = currentFunctionId;
|
this.currentFunctionId = currentFunctionId;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void reset() {
|
||||||
|
blockIdGen = 0;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void error(int depth) {
|
public void error(int depth) {
|
||||||
writer.address();
|
writer.address();
|
||||||
|
@ -56,7 +60,9 @@ public class DisassemblyCodeListener extends BaseDisassemblyListener implements
|
||||||
public int startBlock(boolean loop, WasmHollowType type) {
|
public int startBlock(boolean loop, WasmHollowType type) {
|
||||||
writer.address();
|
writer.address();
|
||||||
var label = blockIdGen++;
|
var label = blockIdGen++;
|
||||||
writer.write(loop ? "loop" : "block").write(" $label_" + label);
|
writer.startLinkTarget("start" + label).startLink("end" + label).write(loop ? "loop" : "block")
|
||||||
|
.endLink().endLinkTarget();
|
||||||
|
writer.write(" $label_" + label);
|
||||||
writeBlockType(type);
|
writeBlockType(type);
|
||||||
writer.indent().eol();
|
writer.indent().eol();
|
||||||
return label;
|
return label;
|
||||||
|
@ -66,7 +72,8 @@ public class DisassemblyCodeListener extends BaseDisassemblyListener implements
|
||||||
public int startConditionalBlock(WasmHollowType type) {
|
public int startConditionalBlock(WasmHollowType type) {
|
||||||
writer.address();
|
writer.address();
|
||||||
var label = blockIdGen++;
|
var label = blockIdGen++;
|
||||||
writer.write("if ").write(" $label_" + label);
|
writer.startLinkTarget("start" + label).startLink("end" + label).write("if").endLink().endLinkTarget();
|
||||||
|
writer.write(" $label_" + label);
|
||||||
writeBlockType(type);
|
writeBlockType(type);
|
||||||
writer.indent().eol();
|
writer.indent().eol();
|
||||||
return label;
|
return label;
|
||||||
|
@ -75,14 +82,16 @@ public class DisassemblyCodeListener extends BaseDisassemblyListener implements
|
||||||
@Override
|
@Override
|
||||||
public void startElseSection(int token) {
|
public void startElseSection(int token) {
|
||||||
writer.address();
|
writer.address();
|
||||||
writer.outdent().write("else (; $label_" + token + " ;)").indent().eol();
|
writer.outdent().startLink("start" + token).write("else").endLink();
|
||||||
|
writer.write(" (; $label_" + token + " ;)").indent().eol();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int startTry(WasmHollowType type) {
|
public int startTry(WasmHollowType type) {
|
||||||
writer.address();
|
writer.address();
|
||||||
var label = blockIdGen++;
|
var label = blockIdGen++;
|
||||||
writer.write("try ").write(" $label_" + label);
|
writer.startLinkTarget("start" + label).startLink("end" + label).write("try").endLink().endLinkTarget();
|
||||||
|
writer.write(" $label_" + label);
|
||||||
writeBlockType(type);
|
writeBlockType(type);
|
||||||
writer.indent().eol();
|
writer.indent().eol();
|
||||||
return label;
|
return label;
|
||||||
|
@ -96,12 +105,14 @@ public class DisassemblyCodeListener extends BaseDisassemblyListener implements
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void endBlock(int token, boolean loop) {
|
public void endBlock(int token, boolean loop) {
|
||||||
writer.address().outdent().write("end (; $label_" + token + " ;)").eol();
|
writer.address().outdent();
|
||||||
|
writer.startLinkTarget("end" + token).startLink("start" + token).write("end").endLink().endLinkTarget();
|
||||||
|
writer.write(" (; $label_" + token + " ;)").eol();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void branch(BranchOpcode opcode, int depth, int target) {
|
public void branch(BranchOpcode opcode, int depth, int target) {
|
||||||
writer.address();
|
writer.address().startLink("start" + target);
|
||||||
switch (opcode) {
|
switch (opcode) {
|
||||||
case BR:
|
case BR:
|
||||||
writer.write("br");
|
writer.write("br");
|
||||||
|
@ -110,7 +121,7 @@ public class DisassemblyCodeListener extends BaseDisassemblyListener implements
|
||||||
writer.write("br_if");
|
writer.write("br_if");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
writer.write(" $label_" + target).eol();
|
writer.endLink().write(" $label_" + target).eol();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -202,7 +213,9 @@ public class DisassemblyCodeListener extends BaseDisassemblyListener implements
|
||||||
@Override
|
@Override
|
||||||
public void callReference(int typeIndex) {
|
public void callReference(int typeIndex) {
|
||||||
writer.address();
|
writer.address();
|
||||||
writer.write("call_ref " + typeIndex).eol();
|
writer.write("call_ref ");
|
||||||
|
writeTypeRef(typeIndex);
|
||||||
|
writer.eol();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -31,12 +31,13 @@ public class DisassemblyCodeSectionListener extends BaseDisassemblyListener impl
|
||||||
@Override
|
@Override
|
||||||
public boolean functionStart(int index, int size) {
|
public boolean functionStart(int index, int size) {
|
||||||
currentFunctionId = index;
|
currentFunctionId = index;
|
||||||
writer.address().write("(func ").write("(; " + index + " ;)");
|
writer.address().write("(func ");
|
||||||
|
writer.startLinkTarget("f" + index).write("(; " + index + " ;)");
|
||||||
var name = nameProvider.function(index);
|
var name = nameProvider.function(index);
|
||||||
if (name != null) {
|
if (name != null) {
|
||||||
writer.write(" $").write(name);
|
writer.write(" $").write(name);
|
||||||
}
|
}
|
||||||
writer.indent().eol();
|
writer.endLinkTarget().indent().eol();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -49,11 +50,14 @@ public class DisassemblyCodeSectionListener extends BaseDisassemblyListener impl
|
||||||
public void local(int start, int count, WasmHollowType type) {
|
public void local(int start, int count, WasmHollowType type) {
|
||||||
writer.address();
|
writer.address();
|
||||||
for (int i = 0; i < count; ++i) {
|
for (int i = 0; i < count; ++i) {
|
||||||
writer.write("(local (; " + (i + start) + " ;) ");
|
writer.write("(local ");
|
||||||
var name = nameProvider.local(currentFunctionId, i + start);
|
var id = i + start;
|
||||||
|
writer.startLinkTarget("l" + currentFunctionId + "." + id).write("(; " + id + " ;)");
|
||||||
|
var name = nameProvider.local(currentFunctionId, id);
|
||||||
if (name != null) {
|
if (name != null) {
|
||||||
writer.write("$").write(name).write(" ");
|
writer.write(" ").write("$").write(name);
|
||||||
}
|
}
|
||||||
|
writer.endLinkTarget().write(" ");
|
||||||
writeType(type);
|
writeType(type);
|
||||||
writer.write(")").eol();
|
writer.write(")").eol();
|
||||||
}
|
}
|
||||||
|
@ -62,6 +66,7 @@ public class DisassemblyCodeSectionListener extends BaseDisassemblyListener impl
|
||||||
@Override
|
@Override
|
||||||
public CodeListener code() {
|
public CodeListener code() {
|
||||||
codeListener.setCurrentFunctionId(currentFunctionId);
|
codeListener.setCurrentFunctionId(currentFunctionId);
|
||||||
|
codeListener.reset();
|
||||||
return codeListener;
|
return codeListener;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -29,11 +29,13 @@ public class DisassemblyGlobalSectionListener extends BaseDisassemblyListener im
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public CodeListener startGlobal(int index, WasmHollowType type, boolean mutable) {
|
public CodeListener startGlobal(int index, WasmHollowType type, boolean mutable) {
|
||||||
writer.address().write("(global (; ").write(String.valueOf(index)).write(" ;) ");
|
writer.address().write("(global ");
|
||||||
|
writer.startLinkTarget("g" + index).write("(; ").write(String.valueOf(index)).write(" ;)");
|
||||||
var name = nameProvider.global(index);
|
var name = nameProvider.global(index);
|
||||||
if (name != null) {
|
if (name != null) {
|
||||||
writer.write("$").write(name).write(" ");
|
writer.write("$").write(name);
|
||||||
}
|
}
|
||||||
|
writer.endLinkTarget().write(" ");
|
||||||
if (mutable) {
|
if (mutable) {
|
||||||
writer.write("(mut ");
|
writer.write("(mut ");
|
||||||
writeType(type);
|
writeType(type);
|
||||||
|
@ -42,6 +44,7 @@ public class DisassemblyGlobalSectionListener extends BaseDisassemblyListener im
|
||||||
writeType(type);
|
writeType(type);
|
||||||
}
|
}
|
||||||
writer.indent().eol();
|
writer.indent().eol();
|
||||||
|
codeListener.reset();
|
||||||
return codeListener;
|
return codeListener;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,85 @@
|
||||||
|
/*
|
||||||
|
* 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.disasm;
|
||||||
|
|
||||||
|
import java.io.PrintWriter;
|
||||||
|
|
||||||
|
public class DisassemblyHTMLWriter extends DisassemblyWriter {
|
||||||
|
public DisassemblyHTMLWriter(PrintWriter out) {
|
||||||
|
super(out);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public DisassemblyWriter prologue() {
|
||||||
|
return writeExact("<html><body><pre>");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public DisassemblyWriter epilogue() {
|
||||||
|
return writeExact("</pre></body></html>");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public DisassemblyWriter startLink(String s) {
|
||||||
|
writeExact("<a href=\"#").writeExact(s).writeExact("\">");
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public DisassemblyWriter endLink() {
|
||||||
|
writeExact("</a>");
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public DisassemblyWriter startLinkTarget(String s) {
|
||||||
|
writeExact("<a name=\"").writeExact(s).writeExact("\">");
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public DisassemblyWriter endLinkTarget() {
|
||||||
|
writeExact("</a>");
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public DisassemblyWriter write(String s) {
|
||||||
|
StringBuilder sb = null;
|
||||||
|
var i = 0;
|
||||||
|
for (; i < s.length(); ++i) {
|
||||||
|
var c = s.charAt(i);
|
||||||
|
if (c == '<') {
|
||||||
|
sb = new StringBuilder();
|
||||||
|
sb.append(s, 0, i);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (sb != null) {
|
||||||
|
for (; i < s.length(); ++i) {
|
||||||
|
var c = s.charAt(i);
|
||||||
|
if (c == '<') {
|
||||||
|
sb.append("<");
|
||||||
|
} else {
|
||||||
|
sb.append(c);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
s = sb.toString();
|
||||||
|
}
|
||||||
|
writeExact(s);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,54 @@
|
||||||
|
/*
|
||||||
|
* 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.disasm;
|
||||||
|
|
||||||
|
import java.io.PrintWriter;
|
||||||
|
|
||||||
|
public class DisassemblyTextWriter extends DisassemblyWriter {
|
||||||
|
public DisassemblyTextWriter(PrintWriter out) {
|
||||||
|
super(out);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public DisassemblyWriter startLink(String s) {
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public DisassemblyWriter endLink() {
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public DisassemblyWriter startLinkTarget(String s) {
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public DisassemblyWriter endLinkTarget() {
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public DisassemblyWriter prologue() {
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public DisassemblyWriter epilogue() {
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
}
|
|
@ -43,11 +43,13 @@ public class DisassemblyTypeSectionListener extends BaseDisassemblyListener impl
|
||||||
@Override
|
@Override
|
||||||
public void startType(int index, boolean open, int[] supertypes) {
|
public void startType(int index, boolean open, int[] supertypes) {
|
||||||
currentTypeIndex = index;
|
currentTypeIndex = index;
|
||||||
writer.address().write("(type (; ").write(String.valueOf(index)).write(" ;) ");
|
writer.address().write("(type ");
|
||||||
|
writer.startLinkTarget("t" + index).write("(; ").write(String.valueOf(index)).write(" ;) ");
|
||||||
var name = nameProvider.type(index);
|
var name = nameProvider.type(index);
|
||||||
if (name != null) {
|
if (name != null) {
|
||||||
writer.write("$").write(name).write(" ");
|
writer.write("$").write(name);
|
||||||
}
|
}
|
||||||
|
writer.endLinkTarget().write(" ");
|
||||||
if (!open || supertypes.length > 0) {
|
if (!open || supertypes.length > 0) {
|
||||||
currentTypeNeedsClosing = true;
|
currentTypeNeedsClosing = true;
|
||||||
writer.write("(sub ");
|
writer.write("(sub ");
|
||||||
|
@ -81,11 +83,13 @@ public class DisassemblyTypeSectionListener extends BaseDisassemblyListener impl
|
||||||
public void field(WasmHollowStorageType hollowType, boolean mutable) {
|
public void field(WasmHollowStorageType hollowType, boolean mutable) {
|
||||||
writer.address().write("(field ");
|
writer.address().write("(field ");
|
||||||
if (needsFieldIndex) {
|
if (needsFieldIndex) {
|
||||||
writer.write("(; " + fieldIndex++ + " ;) ");
|
var index = fieldIndex++;
|
||||||
var name = nameProvider.field(currentTypeIndex, fieldIndex);
|
writer.startLinkTarget("f" + currentTypeIndex + "." + index).write("(; " + index + " ;)");
|
||||||
|
var name = nameProvider.field(currentTypeIndex, index);
|
||||||
if (name != null) {
|
if (name != null) {
|
||||||
writer.write("$").write(name);
|
writer.write(" ").write("$").write(name);
|
||||||
}
|
}
|
||||||
|
writer.endLinkTarget().write(" ");
|
||||||
}
|
}
|
||||||
if (mutable) {
|
if (mutable) {
|
||||||
writer.write("(mut ");
|
writer.write("(mut ");
|
||||||
|
|
|
@ -18,7 +18,7 @@ package org.teavm.backend.wasm.disasm;
|
||||||
import java.io.PrintWriter;
|
import java.io.PrintWriter;
|
||||||
import org.teavm.backend.wasm.parser.AddressListener;
|
import org.teavm.backend.wasm.parser.AddressListener;
|
||||||
|
|
||||||
public class DisassemblyWriter {
|
public abstract class DisassemblyWriter {
|
||||||
private PrintWriter out;
|
private PrintWriter out;
|
||||||
private boolean withAddress;
|
private boolean withAddress;
|
||||||
private int indentLevel;
|
private int indentLevel;
|
||||||
|
@ -27,8 +27,11 @@ public class DisassemblyWriter {
|
||||||
private boolean lineStarted;
|
private boolean lineStarted;
|
||||||
private int addressOffset;
|
private int addressOffset;
|
||||||
|
|
||||||
public DisassemblyWriter(PrintWriter out, boolean withAddress) {
|
public DisassemblyWriter(PrintWriter out) {
|
||||||
this.out = out;
|
this.out = out;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setWithAddress(boolean withAddress) {
|
||||||
this.withAddress = withAddress;
|
this.withAddress = withAddress;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -84,11 +87,31 @@ public class DisassemblyWriter {
|
||||||
}
|
}
|
||||||
|
|
||||||
public DisassemblyWriter write(String s) {
|
public DisassemblyWriter write(String s) {
|
||||||
|
return writeExact(s);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected DisassemblyWriter writeExact(String s) {
|
||||||
startLine();
|
startLine();
|
||||||
out.print(s);
|
out.print(s);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public abstract DisassemblyWriter startLink(String s);
|
||||||
|
|
||||||
|
public abstract DisassemblyWriter endLink();
|
||||||
|
|
||||||
|
public abstract DisassemblyWriter startLinkTarget(String s);
|
||||||
|
|
||||||
|
public abstract DisassemblyWriter endLinkTarget();
|
||||||
|
|
||||||
|
public abstract DisassemblyWriter prologue();
|
||||||
|
|
||||||
|
public abstract DisassemblyWriter epilogue();
|
||||||
|
|
||||||
|
public void flush() {
|
||||||
|
out.flush();
|
||||||
|
}
|
||||||
|
|
||||||
public final AddressListener addressListener = new AddressListener() {
|
public final AddressListener addressListener = new AddressListener() {
|
||||||
@Override
|
@Override
|
||||||
public void address(int address) {
|
public void address(int address) {
|
||||||
|
|
|
@ -61,6 +61,8 @@ tasks.test {
|
||||||
|
|
||||||
systemProperty("teavm.junit.wasm-gc", providers.gradleProperty("teavm.tests.wasm-gc").orElse("false").get())
|
systemProperty("teavm.junit.wasm-gc", providers.gradleProperty("teavm.tests.wasm-gc").orElse("false").get())
|
||||||
systemProperty("teavm.junit.wasm-gc.runner", browser)
|
systemProperty("teavm.junit.wasm-gc.runner", browser)
|
||||||
|
systemProperty("teavm.junit.wasm-gc.disasm", providers.gradleProperty("teavm.tests.wasm-gc.disasm")
|
||||||
|
.orElse("false").get())
|
||||||
|
|
||||||
systemProperty("teavm.junit.wasi", providers.gradleProperty("teavm.tests.wasi").orElse("true").get())
|
systemProperty("teavm.junit.wasi", providers.gradleProperty("teavm.tests.wasi").orElse("true").get())
|
||||||
systemProperty("teavm.junit.wasi.runner", providers.gradleProperty("teavm.tests.wasi.runner")
|
systemProperty("teavm.junit.wasi.runner", providers.gradleProperty("teavm.tests.wasi.runner")
|
||||||
|
|
|
@ -26,6 +26,7 @@ final class PropertyNames {
|
||||||
static final String WASI_ENABLED = "teavm.junit.wasi";
|
static final String WASI_ENABLED = "teavm.junit.wasi";
|
||||||
static final String WASI_RUNNER = "teavm.junit.wasi.runner";
|
static final String WASI_RUNNER = "teavm.junit.wasi.runner";
|
||||||
static final String WASM_GC_ENABLED = "teavm.junit.wasm-gc";
|
static final String WASM_GC_ENABLED = "teavm.junit.wasm-gc";
|
||||||
|
static final String WASM_GC_DISASM = "teavm.junit.wasm-gc.disasm";
|
||||||
static final String C_COMPILER = "teavm.junit.c.compiler";
|
static final String C_COMPILER = "teavm.junit.c.compiler";
|
||||||
static final String C_LINE_NUMBERS = "teavm.junit.c.lineNumbers";
|
static final String C_LINE_NUMBERS = "teavm.junit.c.lineNumbers";
|
||||||
static final String MINIFIED = "teavm.junit.minified";
|
static final String MINIFIED = "teavm.junit.minified";
|
||||||
|
|
|
@ -106,7 +106,8 @@ public class TeaVMTestRunner extends Runner implements Filterable {
|
||||||
|
|
||||||
platforms.add(new JSPlatformSupport(classSource, referenceCache));
|
platforms.add(new JSPlatformSupport(classSource, referenceCache));
|
||||||
platforms.add(new WebAssemblyPlatformSupport(classSource, referenceCache));
|
platforms.add(new WebAssemblyPlatformSupport(classSource, referenceCache));
|
||||||
platforms.add(new WebAssemblyGCPlatformSupport(classSource, referenceCache));
|
platforms.add(new WebAssemblyGCPlatformSupport(classSource, referenceCache,
|
||||||
|
Boolean.parseBoolean(System.getProperty(PropertyNames.WASM_GC_DISASM))));
|
||||||
platforms.add(new WasiPlatformSupport(classSource, referenceCache));
|
platforms.add(new WasiPlatformSupport(classSource, referenceCache));
|
||||||
platforms.add(new CPlatformSupport(classSource, referenceCache));
|
platforms.add(new CPlatformSupport(classSource, referenceCache));
|
||||||
|
|
||||||
|
|
|
@ -20,8 +20,12 @@ import static org.teavm.junit.PropertyNames.SOURCE_DIRS;
|
||||||
import static org.teavm.junit.PropertyNames.WASM_GC_ENABLED;
|
import static org.teavm.junit.PropertyNames.WASM_GC_ENABLED;
|
||||||
import static org.teavm.junit.PropertyNames.WASM_RUNNER;
|
import static org.teavm.junit.PropertyNames.WASM_RUNNER;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
|
import java.io.FileOutputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.io.OutputStreamWriter;
|
||||||
|
import java.io.PrintWriter;
|
||||||
import java.lang.reflect.AnnotatedElement;
|
import java.lang.reflect.AnnotatedElement;
|
||||||
|
import java.nio.file.Files;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
@ -29,6 +33,8 @@ import java.util.StringTokenizer;
|
||||||
import java.util.function.Consumer;
|
import java.util.function.Consumer;
|
||||||
import java.util.function.Supplier;
|
import java.util.function.Supplier;
|
||||||
import org.teavm.backend.wasm.WasmGCTarget;
|
import org.teavm.backend.wasm.WasmGCTarget;
|
||||||
|
import org.teavm.backend.wasm.disasm.Disassembler;
|
||||||
|
import org.teavm.backend.wasm.disasm.DisassemblyHTMLWriter;
|
||||||
import org.teavm.browserrunner.BrowserRunner;
|
import org.teavm.browserrunner.BrowserRunner;
|
||||||
import org.teavm.model.ClassHolderSource;
|
import org.teavm.model.ClassHolderSource;
|
||||||
import org.teavm.model.MethodReference;
|
import org.teavm.model.MethodReference;
|
||||||
|
@ -36,8 +42,11 @@ import org.teavm.model.ReferenceCache;
|
||||||
import org.teavm.vm.TeaVM;
|
import org.teavm.vm.TeaVM;
|
||||||
|
|
||||||
class WebAssemblyGCPlatformSupport extends TestPlatformSupport<WasmGCTarget> {
|
class WebAssemblyGCPlatformSupport extends TestPlatformSupport<WasmGCTarget> {
|
||||||
WebAssemblyGCPlatformSupport(ClassHolderSource classSource, ReferenceCache referenceCache) {
|
private boolean disassembly;
|
||||||
|
|
||||||
|
WebAssemblyGCPlatformSupport(ClassHolderSource classSource, ReferenceCache referenceCache, boolean disassembly) {
|
||||||
super(classSource, referenceCache);
|
super(classSource, referenceCache);
|
||||||
|
this.disassembly = disassembly;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -117,6 +126,9 @@ class WebAssemblyGCPlatformSupport extends TestPlatformSupport<WasmGCTarget> {
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
throw new RuntimeException(e);
|
throw new RuntimeException(e);
|
||||||
}
|
}
|
||||||
|
if (disassembly) {
|
||||||
|
writeDisassembly(outputPath, "classTest", configuration);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -130,5 +142,20 @@ class WebAssemblyGCPlatformSupport extends TestPlatformSupport<WasmGCTarget> {
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
throw new RuntimeException(e);
|
throw new RuntimeException(e);
|
||||||
}
|
}
|
||||||
|
if (disassembly) {
|
||||||
|
writeDisassembly(outputPathForMethod, "test", configuration);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void writeDisassembly(File outputPath, String name, TeaVMTestConfiguration<?> configuration) {
|
||||||
|
var binPath = getOutputFile(outputPath, name, configuration.getSuffix(), getExtension());
|
||||||
|
var htmlPath = getOutputFile(outputPath, name, configuration.getSuffix(), ".wast.html");
|
||||||
|
try (var writer = new OutputStreamWriter(new FileOutputStream(htmlPath))) {
|
||||||
|
var disasmWriter = new DisassemblyHTMLWriter(new PrintWriter(writer));
|
||||||
|
disasmWriter.setWithAddress(true);
|
||||||
|
new Disassembler(disasmWriter).disassemble(Files.readAllBytes(binPath.toPath()));
|
||||||
|
} catch (IOException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user