mirror of
https://github.com/Eaglercraft-TeaVM-Fork/eagler-teavm.git
synced 2024-12-22 08:14:09 -08:00
wasm: support instructions that were recently implemented in generator
This commit is contained in:
parent
5572d4b5d7
commit
75bead66b3
|
@ -21,12 +21,12 @@ import java.util.List;
|
||||||
import org.teavm.backend.wasm.debug.info.ControlFlowInfo;
|
import org.teavm.backend.wasm.debug.info.ControlFlowInfo;
|
||||||
import org.teavm.backend.wasm.debug.info.FunctionControlFlow;
|
import org.teavm.backend.wasm.debug.info.FunctionControlFlow;
|
||||||
import org.teavm.backend.wasm.debug.info.FunctionControlFlowBuilder;
|
import org.teavm.backend.wasm.debug.info.FunctionControlFlowBuilder;
|
||||||
import org.teavm.backend.wasm.model.WasmType;
|
|
||||||
import org.teavm.backend.wasm.parser.AddressListener;
|
import org.teavm.backend.wasm.parser.AddressListener;
|
||||||
import org.teavm.backend.wasm.parser.BranchOpcode;
|
import org.teavm.backend.wasm.parser.BranchOpcode;
|
||||||
import org.teavm.backend.wasm.parser.CodeListener;
|
import org.teavm.backend.wasm.parser.CodeListener;
|
||||||
import org.teavm.backend.wasm.parser.CodeSectionListener;
|
import org.teavm.backend.wasm.parser.CodeSectionListener;
|
||||||
import org.teavm.backend.wasm.parser.Opcode;
|
import org.teavm.backend.wasm.parser.Opcode;
|
||||||
|
import org.teavm.backend.wasm.parser.WasmHollowType;
|
||||||
|
|
||||||
public class ControlFlowParser implements CodeSectionListener, CodeListener, AddressListener {
|
public class ControlFlowParser implements CodeSectionListener, CodeListener, AddressListener {
|
||||||
private int previousAddress;
|
private int previousAddress;
|
||||||
|
@ -60,12 +60,12 @@ public class ControlFlowParser implements CodeSectionListener, CodeListener, Add
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int startBlock(boolean loop, WasmType type) {
|
public int startBlock(boolean loop, WasmHollowType type) {
|
||||||
return startBlock(loop);
|
return startBlock(loop);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int startConditionalBlock(WasmType type) {
|
public int startConditionalBlock(WasmHollowType type) {
|
||||||
return startBlock(false);
|
return startBlock(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -21,7 +21,6 @@ import java.io.PrintWriter;
|
||||||
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.model.WasmNumType;
|
import org.teavm.backend.wasm.model.WasmNumType;
|
||||||
import org.teavm.backend.wasm.model.WasmType;
|
|
||||||
import org.teavm.backend.wasm.model.expression.WasmFloatBinaryOperation;
|
import org.teavm.backend.wasm.model.expression.WasmFloatBinaryOperation;
|
||||||
import org.teavm.backend.wasm.model.expression.WasmFloatType;
|
import org.teavm.backend.wasm.model.expression.WasmFloatType;
|
||||||
import org.teavm.backend.wasm.model.expression.WasmFloatUnaryOperation;
|
import org.teavm.backend.wasm.model.expression.WasmFloatUnaryOperation;
|
||||||
|
@ -30,6 +29,7 @@ import org.teavm.backend.wasm.model.expression.WasmInt64Subtype;
|
||||||
import org.teavm.backend.wasm.model.expression.WasmIntBinaryOperation;
|
import org.teavm.backend.wasm.model.expression.WasmIntBinaryOperation;
|
||||||
import org.teavm.backend.wasm.model.expression.WasmIntType;
|
import org.teavm.backend.wasm.model.expression.WasmIntType;
|
||||||
import org.teavm.backend.wasm.model.expression.WasmIntUnaryOperation;
|
import org.teavm.backend.wasm.model.expression.WasmIntUnaryOperation;
|
||||||
|
import org.teavm.backend.wasm.model.expression.WasmSignedType;
|
||||||
import org.teavm.backend.wasm.parser.AddressListener;
|
import org.teavm.backend.wasm.parser.AddressListener;
|
||||||
import org.teavm.backend.wasm.parser.BranchOpcode;
|
import org.teavm.backend.wasm.parser.BranchOpcode;
|
||||||
import org.teavm.backend.wasm.parser.CodeListener;
|
import org.teavm.backend.wasm.parser.CodeListener;
|
||||||
|
@ -38,20 +38,26 @@ import org.teavm.backend.wasm.parser.CodeSectionParser;
|
||||||
import org.teavm.backend.wasm.parser.LocalOpcode;
|
import org.teavm.backend.wasm.parser.LocalOpcode;
|
||||||
import org.teavm.backend.wasm.parser.ModuleParser;
|
import org.teavm.backend.wasm.parser.ModuleParser;
|
||||||
import org.teavm.backend.wasm.parser.Opcode;
|
import org.teavm.backend.wasm.parser.Opcode;
|
||||||
|
import org.teavm.backend.wasm.parser.WasmHollowType;
|
||||||
import org.teavm.common.ByteArrayAsyncInputStream;
|
import org.teavm.common.ByteArrayAsyncInputStream;
|
||||||
|
|
||||||
public class DisassemblyCodeSectionListener implements AddressListener, CodeSectionListener, CodeListener {
|
public class DisassemblyCodeSectionListener implements AddressListener, CodeSectionListener, CodeListener {
|
||||||
private DisassemblyWriter writer;
|
private DisassemblyWriter writer;
|
||||||
private int address;
|
private int address;
|
||||||
|
private int addressOffset;
|
||||||
private int blockIdGen;
|
private int blockIdGen;
|
||||||
|
|
||||||
public DisassemblyCodeSectionListener(DisassemblyWriter writer) {
|
public DisassemblyCodeSectionListener(DisassemblyWriter writer) {
|
||||||
this.writer = writer;
|
this.writer = writer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setAddressOffset(int addressOffset) {
|
||||||
|
this.addressOffset = addressOffset;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void address(int address) {
|
public void address(int address) {
|
||||||
this.address = address;
|
this.address = address + addressOffset;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -61,7 +67,7 @@ public class DisassemblyCodeSectionListener implements AddressListener, CodeSect
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean functionStart(int index, int size) {
|
public boolean functionStart(int index, int size) {
|
||||||
writer.address(address).write("(func $fun_" + index).indent().eol();
|
writer.address(address).write("(func (; " + index + " ;)").indent().eol();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -71,10 +77,10 @@ public class DisassemblyCodeSectionListener implements AddressListener, CodeSect
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void local(int start, int count, WasmType type) {
|
public void local(int start, int count, WasmHollowType type) {
|
||||||
writer.address(address);
|
writer.address(address);
|
||||||
for (int i = 0; i < count; ++i) {
|
for (int i = 0; i < count; ++i) {
|
||||||
writer.write("(local $loc_" + (i + start) + " " + typeToString(type) + ")").eol();
|
writer.write("(local (; " + (i + start) + " ;) " + typeToString(type) + ")").eol();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -94,7 +100,7 @@ public class DisassemblyCodeSectionListener implements AddressListener, CodeSect
|
||||||
writer.outdent().write(")").eol();
|
writer.outdent().write(")").eol();
|
||||||
}
|
}
|
||||||
|
|
||||||
private String blockTypeToString(WasmType type) {
|
private String blockTypeToString(WasmHollowType type) {
|
||||||
if (type == null) {
|
if (type == null) {
|
||||||
return "";
|
return "";
|
||||||
} else {
|
} else {
|
||||||
|
@ -102,10 +108,10 @@ public class DisassemblyCodeSectionListener implements AddressListener, CodeSect
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private String typeToString(WasmType type) {
|
private String typeToString(WasmHollowType type) {
|
||||||
if (type != null) {
|
if (type != null) {
|
||||||
if (type instanceof WasmType.Number) {
|
if (type instanceof WasmHollowType.Number) {
|
||||||
switch (((WasmType.Number) type).number) {
|
switch (((WasmHollowType.Number) type).number) {
|
||||||
case INT32:
|
case INT32:
|
||||||
return "i32";
|
return "i32";
|
||||||
case INT64:
|
case INT64:
|
||||||
|
@ -117,8 +123,23 @@ public class DisassemblyCodeSectionListener implements AddressListener, CodeSect
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
} else if (type instanceof WasmType.Reference) {
|
} else if (type instanceof WasmHollowType.SpecialReference) {
|
||||||
return "ref";
|
switch (((WasmHollowType.SpecialReference) type).kind) {
|
||||||
|
case ANY:
|
||||||
|
return "any";
|
||||||
|
case FUNC:
|
||||||
|
return "func";
|
||||||
|
case ARRAY:
|
||||||
|
return "array";
|
||||||
|
case EXTERN:
|
||||||
|
return "extern";
|
||||||
|
case STRUCT:
|
||||||
|
return "struct";
|
||||||
|
default:
|
||||||
|
throw new IllegalArgumentException();
|
||||||
|
}
|
||||||
|
} else if (type instanceof WasmHollowType.CompositeReference) {
|
||||||
|
return String.valueOf(((WasmHollowType.CompositeReference) type).index);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return "unknown";
|
return "unknown";
|
||||||
|
@ -134,7 +155,7 @@ public class DisassemblyCodeSectionListener implements AddressListener, CodeSect
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int startBlock(boolean loop, WasmType type) {
|
public int startBlock(boolean loop, WasmHollowType type) {
|
||||||
writer.address(address);
|
writer.address(address);
|
||||||
var label = blockIdGen++;
|
var label = blockIdGen++;
|
||||||
writer.write(loop ? "loop" : "block").write(" $label_" + label).write(blockTypeToString(type))
|
writer.write(loop ? "loop" : "block").write(" $label_" + label).write(blockTypeToString(type))
|
||||||
|
@ -143,7 +164,7 @@ public class DisassemblyCodeSectionListener implements AddressListener, CodeSect
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int startConditionalBlock(WasmType type) {
|
public int startConditionalBlock(WasmHollowType type) {
|
||||||
writer.address(address);
|
writer.address(address);
|
||||||
var label = blockIdGen++;
|
var label = blockIdGen++;
|
||||||
writer.write("if ").write(" $label_" + label).write(blockTypeToString(type)).indent().eol();
|
writer.write("if ").write(" $label_" + label).write(blockTypeToString(type)).indent().eol();
|
||||||
|
@ -156,6 +177,20 @@ public class DisassemblyCodeSectionListener implements AddressListener, CodeSect
|
||||||
writer.outdent().write("else (; $label_" + token + " ;)").indent().eol();
|
writer.outdent().write("else (; $label_" + token + " ;)").indent().eol();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int startTry(WasmHollowType type) {
|
||||||
|
writer.address(address);
|
||||||
|
var label = blockIdGen++;
|
||||||
|
writer.write("try ").write(" $label_" + label).write(blockTypeToString(type)).indent().eol();
|
||||||
|
return label;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void startCatch(int tagIndex) {
|
||||||
|
writer.outdent().address(address);
|
||||||
|
writer.write("catch ").write(String.valueOf(tagIndex)).indent().eol();
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void endBlock(int token, boolean loop) {
|
public void endBlock(int token, boolean loop) {
|
||||||
writer.address(address).outdent().write("end (; $label_" + token + " ;)").eol();
|
writer.address(address).outdent().write("end (; $label_" + token + " ;)").eol();
|
||||||
|
@ -185,6 +220,12 @@ public class DisassemblyCodeSectionListener implements AddressListener, CodeSect
|
||||||
writer.write(" $label_" + defaultTarget).eol();
|
writer.write(" $label_" + defaultTarget).eol();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void throwInstruction(int tagIndex) {
|
||||||
|
writer.address(address);
|
||||||
|
writer.write("throw ").write(String.valueOf(tagIndex)).eol();
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void opcode(Opcode opcode) {
|
public void opcode(Opcode opcode) {
|
||||||
writer.address(address);
|
writer.address(address);
|
||||||
|
@ -201,6 +242,12 @@ public class DisassemblyCodeSectionListener implements AddressListener, CodeSect
|
||||||
case DROP:
|
case DROP:
|
||||||
writer.write("drop");
|
writer.write("drop");
|
||||||
break;
|
break;
|
||||||
|
case REF_EQ:
|
||||||
|
writer.write("ref.eq");
|
||||||
|
break;
|
||||||
|
case ARRAY_LENGTH:
|
||||||
|
writer.write("array.length");
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
writer.eol();
|
writer.eol();
|
||||||
}
|
}
|
||||||
|
@ -216,20 +263,35 @@ public class DisassemblyCodeSectionListener implements AddressListener, CodeSect
|
||||||
writer.write("local.set");
|
writer.write("local.set");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
writer.write(" $loc_" + index).eol();
|
writer.write(" " + index).eol();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void getGlobal(int globalIndex) {
|
||||||
|
writer.address(address).write("global.get ").write(Integer.toString(globalIndex)).eol();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setGlobal(int globalIndex) {
|
||||||
|
writer.address(address).write("global.set ").write(Integer.toString(globalIndex)).eol();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void call(int functionIndex) {
|
public void call(int functionIndex) {
|
||||||
writer.address(address);
|
writer.address(address);
|
||||||
writer.write("call $fun_" + functionIndex).eol();
|
writer.write("call " + functionIndex).eol();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void indirectCall(int typeIndex, int tableIndex) {
|
public void indirectCall(int typeIndex, int tableIndex) {
|
||||||
writer.address(address);
|
writer.address(address);
|
||||||
//TODO: type signature must be printed
|
writer.write("call_indirect " + tableIndex + " " + typeIndex).eol();
|
||||||
writer.write("call_indirect $table_" + tableIndex + " $type_" + typeIndex).eol();
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void callReference(int typeIndex) {
|
||||||
|
writer.address(address);
|
||||||
|
writer.write("call_ref " + typeIndex).eol();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -429,6 +491,9 @@ public class DisassemblyCodeSectionListener implements AddressListener, CodeSect
|
||||||
case CTZ:
|
case CTZ:
|
||||||
writer.write("ctz");
|
writer.write("ctz");
|
||||||
break;
|
break;
|
||||||
|
case EQZ:
|
||||||
|
writer.write("eqz");
|
||||||
|
break;
|
||||||
case POPCNT:
|
case POPCNT:
|
||||||
writer.write("popcnt");
|
writer.write("popcnt");
|
||||||
break;
|
break;
|
||||||
|
@ -758,6 +823,73 @@ public class DisassemblyCodeSectionListener implements AddressListener, CodeSect
|
||||||
writer.address(address).write("f64.const " + Double.toHexString(value)).eol();
|
writer.address(address).write("f64.const " + Double.toHexString(value)).eol();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void nullConstant(WasmHollowType.Reference type) {
|
||||||
|
writer.address(address).write("ref.null ").write(typeToString(type)).eol();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void cast(WasmHollowType.Reference type) {
|
||||||
|
writer.address(address).write("ref.cast ").write(typeToString(type)).eol();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void structNew(int typeIndex) {
|
||||||
|
writer.address(address).write("struct.new ").write(Integer.toString(typeIndex)).eol();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void structNewDefault(int typeIndex) {
|
||||||
|
writer.address(address).write("struct.new_default ").write(Integer.toString(typeIndex)).eol();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void structGet(WasmSignedType signedType, int typeIndex, int fieldIndex) {
|
||||||
|
writer.address(address);
|
||||||
|
if (signedType == null) {
|
||||||
|
writer.write("struct.get");
|
||||||
|
} else if (signedType == WasmSignedType.SIGNED) {
|
||||||
|
writer.write("struct.get_s");
|
||||||
|
} else {
|
||||||
|
writer.write("struct.get_u");
|
||||||
|
}
|
||||||
|
writer.write(" ").write(Integer.toString(typeIndex)).write(" ").write(Integer.toString(fieldIndex)).eol();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void structSet(int typeIndex, int fieldIndex) {
|
||||||
|
writer.address(address).write("struct.set ").write(Integer.toString(typeIndex)).write(" ")
|
||||||
|
.write(Integer.toString(fieldIndex)).eol();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void arrayNewDefault(int typeIndex) {
|
||||||
|
writer.address(address).write("array.new_default ").write(Integer.toString(typeIndex)).eol();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void arrayGet(WasmSignedType signedType, int typeIndex) {
|
||||||
|
writer.address(address);
|
||||||
|
if (signedType == null) {
|
||||||
|
writer.write("array.get");
|
||||||
|
} else if (signedType == WasmSignedType.SIGNED) {
|
||||||
|
writer.write("array.get_s");
|
||||||
|
} else {
|
||||||
|
writer.write("array.get_u");
|
||||||
|
}
|
||||||
|
writer.write(" ").write(Integer.toString(typeIndex)).eol();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void arraySet(int typeIndex) {
|
||||||
|
writer.address(address).write("array.set ").write(Integer.toString(typeIndex)).eol();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void functionReference(int functionIndex) {
|
||||||
|
writer.address(address).write("ref.func ").write(Integer.toString(functionIndex)).eol();
|
||||||
|
}
|
||||||
|
|
||||||
public static void main(String[] args) throws IOException {
|
public static void main(String[] args) throws IOException {
|
||||||
var file = new File(args[0]);
|
var file = new File(args[0]);
|
||||||
var bytes = Files.readAllBytes(file.toPath());
|
var bytes = Files.readAllBytes(file.toPath());
|
||||||
|
@ -770,6 +902,7 @@ public class DisassemblyCodeSectionListener implements AddressListener, CodeSect
|
||||||
var out = new PrintWriter(System.out);
|
var out = new PrintWriter(System.out);
|
||||||
var writer = new DisassemblyWriter(out, true);
|
var writer = new DisassemblyWriter(out, true);
|
||||||
var disassembler = new DisassemblyCodeSectionListener(writer);
|
var disassembler = new DisassemblyCodeSectionListener(writer);
|
||||||
|
disassembler.setAddressOffset(pos);
|
||||||
var sectionParser = new CodeSectionParser(disassembler, disassembler);
|
var sectionParser = new CodeSectionParser(disassembler, disassembler);
|
||||||
sectionParser.parse(bytes);
|
sectionParser.parse(bytes);
|
||||||
out.flush();
|
out.flush();
|
||||||
|
|
|
@ -16,7 +16,6 @@
|
||||||
package org.teavm.backend.wasm.parser;
|
package org.teavm.backend.wasm.parser;
|
||||||
|
|
||||||
import org.teavm.backend.wasm.model.WasmNumType;
|
import org.teavm.backend.wasm.model.WasmNumType;
|
||||||
import org.teavm.backend.wasm.model.WasmType;
|
|
||||||
import org.teavm.backend.wasm.model.expression.WasmFloatBinaryOperation;
|
import org.teavm.backend.wasm.model.expression.WasmFloatBinaryOperation;
|
||||||
import org.teavm.backend.wasm.model.expression.WasmFloatType;
|
import org.teavm.backend.wasm.model.expression.WasmFloatType;
|
||||||
import org.teavm.backend.wasm.model.expression.WasmFloatUnaryOperation;
|
import org.teavm.backend.wasm.model.expression.WasmFloatUnaryOperation;
|
||||||
|
@ -25,22 +24,30 @@ import org.teavm.backend.wasm.model.expression.WasmInt64Subtype;
|
||||||
import org.teavm.backend.wasm.model.expression.WasmIntBinaryOperation;
|
import org.teavm.backend.wasm.model.expression.WasmIntBinaryOperation;
|
||||||
import org.teavm.backend.wasm.model.expression.WasmIntType;
|
import org.teavm.backend.wasm.model.expression.WasmIntType;
|
||||||
import org.teavm.backend.wasm.model.expression.WasmIntUnaryOperation;
|
import org.teavm.backend.wasm.model.expression.WasmIntUnaryOperation;
|
||||||
|
import org.teavm.backend.wasm.model.expression.WasmSignedType;
|
||||||
|
|
||||||
public interface CodeListener {
|
public interface CodeListener {
|
||||||
default void error(int depth) {
|
default void error(int depth) {
|
||||||
}
|
}
|
||||||
|
|
||||||
default int startBlock(boolean loop, WasmType type) {
|
default int startBlock(boolean loop, WasmHollowType type) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
default int startConditionalBlock(WasmType type) {
|
default int startConditionalBlock(WasmHollowType type) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
default void startElseSection(int token) {
|
default void startElseSection(int token) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
default int startTry(WasmHollowType type) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
default void startCatch(int tagIndex) {
|
||||||
|
}
|
||||||
|
|
||||||
default void endBlock(int token, boolean loop) {
|
default void endBlock(int token, boolean loop) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -50,6 +57,9 @@ public interface CodeListener {
|
||||||
default void tableBranch(int[] depths, int[] targets, int defaultDepth, int defaultTarget) {
|
default void tableBranch(int[] depths, int[] targets, int defaultDepth, int defaultTarget) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
default void throwInstruction(int tagIndex) {
|
||||||
|
}
|
||||||
|
|
||||||
default void opcode(Opcode opcode) {
|
default void opcode(Opcode opcode) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -121,4 +131,43 @@ public interface CodeListener {
|
||||||
|
|
||||||
default void float64Constant(double value) {
|
default void float64Constant(double value) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
default void nullConstant(WasmHollowType.Reference type) {
|
||||||
|
}
|
||||||
|
|
||||||
|
default void cast(WasmHollowType.Reference type) {
|
||||||
|
}
|
||||||
|
|
||||||
|
default void structNew(int typeIndex) {
|
||||||
|
}
|
||||||
|
|
||||||
|
default void structNewDefault(int typeIndex) {
|
||||||
|
}
|
||||||
|
|
||||||
|
default void structGet(WasmSignedType signedType, int typeIndex, int fieldIndex) {
|
||||||
|
}
|
||||||
|
|
||||||
|
default void structSet(int typeIndex, int fieldIndex) {
|
||||||
|
}
|
||||||
|
|
||||||
|
default void arrayNewDefault(int typeIndex) {
|
||||||
|
}
|
||||||
|
|
||||||
|
default void arrayGet(WasmSignedType signedType, int typeIndex) {
|
||||||
|
}
|
||||||
|
|
||||||
|
default void arraySet(int typeIndex) {
|
||||||
|
}
|
||||||
|
|
||||||
|
default void getGlobal(int globalIndex) {
|
||||||
|
}
|
||||||
|
|
||||||
|
default void setGlobal(int globalIndex) {
|
||||||
|
}
|
||||||
|
|
||||||
|
default void callReference(int typeIndex) {
|
||||||
|
}
|
||||||
|
|
||||||
|
default void functionReference(int functionIndex) {
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,8 +15,6 @@
|
||||||
*/
|
*/
|
||||||
package org.teavm.backend.wasm.parser;
|
package org.teavm.backend.wasm.parser;
|
||||||
|
|
||||||
import org.teavm.backend.wasm.model.WasmType;
|
|
||||||
|
|
||||||
public interface CodeSectionListener {
|
public interface CodeSectionListener {
|
||||||
default void sectionStart(int functionCount) {
|
default void sectionStart(int functionCount) {
|
||||||
}
|
}
|
||||||
|
@ -28,7 +26,7 @@ public interface CodeSectionListener {
|
||||||
default void localsStart(int count) {
|
default void localsStart(int count) {
|
||||||
}
|
}
|
||||||
|
|
||||||
default void local(int start, int count, WasmType type) {
|
default void local(int start, int count, WasmHollowType type) {
|
||||||
}
|
}
|
||||||
|
|
||||||
default CodeListener code() {
|
default CodeListener code() {
|
||||||
|
|
|
@ -18,7 +18,6 @@ package org.teavm.backend.wasm.parser;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import org.teavm.backend.wasm.model.WasmNumType;
|
import org.teavm.backend.wasm.model.WasmNumType;
|
||||||
import org.teavm.backend.wasm.model.WasmType;
|
|
||||||
import org.teavm.backend.wasm.model.expression.WasmFloatBinaryOperation;
|
import org.teavm.backend.wasm.model.expression.WasmFloatBinaryOperation;
|
||||||
import org.teavm.backend.wasm.model.expression.WasmFloatType;
|
import org.teavm.backend.wasm.model.expression.WasmFloatType;
|
||||||
import org.teavm.backend.wasm.model.expression.WasmFloatUnaryOperation;
|
import org.teavm.backend.wasm.model.expression.WasmFloatUnaryOperation;
|
||||||
|
@ -27,6 +26,7 @@ import org.teavm.backend.wasm.model.expression.WasmInt64Subtype;
|
||||||
import org.teavm.backend.wasm.model.expression.WasmIntBinaryOperation;
|
import org.teavm.backend.wasm.model.expression.WasmIntBinaryOperation;
|
||||||
import org.teavm.backend.wasm.model.expression.WasmIntType;
|
import org.teavm.backend.wasm.model.expression.WasmIntType;
|
||||||
import org.teavm.backend.wasm.model.expression.WasmIntUnaryOperation;
|
import org.teavm.backend.wasm.model.expression.WasmIntUnaryOperation;
|
||||||
|
import org.teavm.backend.wasm.model.expression.WasmSignedType;
|
||||||
|
|
||||||
public class CodeSectionParser {
|
public class CodeSectionParser {
|
||||||
private AddressListener addressListener;
|
private AddressListener addressListener;
|
||||||
|
@ -125,6 +125,11 @@ public class CodeSectionParser {
|
||||||
return parseBlock(true);
|
return parseBlock(true);
|
||||||
case 0x04:
|
case 0x04:
|
||||||
return parseConditional();
|
return parseConditional();
|
||||||
|
case 0x06:
|
||||||
|
return parseTryCatch();
|
||||||
|
case 0x8:
|
||||||
|
codeListener.throwInstruction(readLEB());
|
||||||
|
break;
|
||||||
case 0x0C:
|
case 0x0C:
|
||||||
parseBranch(BranchOpcode.BR);
|
parseBranch(BranchOpcode.BR);
|
||||||
break;
|
break;
|
||||||
|
@ -143,6 +148,9 @@ public class CodeSectionParser {
|
||||||
case 0x11:
|
case 0x11:
|
||||||
codeListener.indirectCall(readLEB(), readLEB());
|
codeListener.indirectCall(readLEB(), readLEB());
|
||||||
break;
|
break;
|
||||||
|
case 0x14:
|
||||||
|
codeListener.callReference(readLEB());
|
||||||
|
break;
|
||||||
|
|
||||||
case 0x1A:
|
case 0x1A:
|
||||||
codeListener.opcode(Opcode.DROP);
|
codeListener.opcode(Opcode.DROP);
|
||||||
|
@ -155,6 +163,13 @@ public class CodeSectionParser {
|
||||||
codeListener.local(LocalOpcode.SET, readLEB());
|
codeListener.local(LocalOpcode.SET, readLEB());
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case 0x23:
|
||||||
|
codeListener.getGlobal(readLEB());
|
||||||
|
break;
|
||||||
|
case 0x24:
|
||||||
|
codeListener.setGlobal(readLEB());
|
||||||
|
break;
|
||||||
|
|
||||||
case 0x28:
|
case 0x28:
|
||||||
codeListener.loadInt32(WasmInt32Subtype.INT32, 1 << readLEB(), readLEB());
|
codeListener.loadInt32(WasmInt32Subtype.INT32, 1 << readLEB(), readLEB());
|
||||||
break;
|
break;
|
||||||
|
@ -617,6 +632,20 @@ public class CodeSectionParser {
|
||||||
codeListener.convert(WasmNumType.INT64, WasmNumType.FLOAT64, false, true);
|
codeListener.convert(WasmNumType.INT64, WasmNumType.FLOAT64, false, true);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case 0xD0:
|
||||||
|
codeListener.nullConstant(readHeapType());
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0xD2:
|
||||||
|
codeListener.functionReference(readLEB());
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0xD3:
|
||||||
|
codeListener.opcode(Opcode.REF_EQ);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0xFB:
|
||||||
|
return parseExtExpr2();
|
||||||
case 0xFC:
|
case 0xFC:
|
||||||
return parseExtExpr();
|
return parseExtExpr();
|
||||||
|
|
||||||
|
@ -648,6 +677,61 @@ public class CodeSectionParser {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private boolean parseExtExpr2() {
|
||||||
|
switch (readLEB()) {
|
||||||
|
case 0:
|
||||||
|
codeListener.structNew(readLEB());
|
||||||
|
return true;
|
||||||
|
|
||||||
|
case 1:
|
||||||
|
codeListener.structNewDefault(readLEB());
|
||||||
|
return true;
|
||||||
|
|
||||||
|
case 2:
|
||||||
|
codeListener.structGet(null, readLEB(), readLEB());
|
||||||
|
return true;
|
||||||
|
case 3:
|
||||||
|
codeListener.structGet(WasmSignedType.SIGNED, readLEB(), readLEB());
|
||||||
|
return true;
|
||||||
|
case 4:
|
||||||
|
codeListener.structGet(WasmSignedType.UNSIGNED, readLEB(), readLEB());
|
||||||
|
return true;
|
||||||
|
|
||||||
|
case 5:
|
||||||
|
codeListener.structSet(readLEB(), readLEB());
|
||||||
|
return true;
|
||||||
|
|
||||||
|
case 7:
|
||||||
|
codeListener.arrayNewDefault(readLEB());
|
||||||
|
return true;
|
||||||
|
|
||||||
|
case 11:
|
||||||
|
codeListener.arrayGet(null, readLEB());
|
||||||
|
return true;
|
||||||
|
case 12:
|
||||||
|
codeListener.arrayGet(WasmSignedType.SIGNED, readLEB());
|
||||||
|
return true;
|
||||||
|
case 13:
|
||||||
|
codeListener.arrayGet(WasmSignedType.UNSIGNED, readLEB());
|
||||||
|
return true;
|
||||||
|
|
||||||
|
case 14:
|
||||||
|
codeListener.arraySet(readLEB());
|
||||||
|
return true;
|
||||||
|
|
||||||
|
case 15:
|
||||||
|
codeListener.opcode(Opcode.ARRAY_LENGTH);
|
||||||
|
return true;
|
||||||
|
|
||||||
|
case 23:
|
||||||
|
codeListener.cast(readHeapType());
|
||||||
|
return true;
|
||||||
|
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private boolean parseBlock(boolean isLoop) {
|
private boolean parseBlock(boolean isLoop) {
|
||||||
var type = readType();
|
var type = readType();
|
||||||
var token = codeListener.startBlock(isLoop, type);
|
var token = codeListener.startBlock(isLoop, type);
|
||||||
|
@ -693,6 +777,35 @@ public class CodeSectionParser {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private boolean parseTryCatch() {
|
||||||
|
var type = readType();
|
||||||
|
var token = codeListener.startTry(type);
|
||||||
|
blockStack.add(new Block(token));
|
||||||
|
loop: while (true) {
|
||||||
|
switch (data[ptr]) {
|
||||||
|
case 0x0B:
|
||||||
|
break loop;
|
||||||
|
case 0x07: {
|
||||||
|
reportAddress();
|
||||||
|
var tagIndex = readLEB();
|
||||||
|
++ptr;
|
||||||
|
codeListener.startCatch(tagIndex);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
if (!parseExpr()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
blockStack.remove(blockStack.size() - 1);
|
||||||
|
reportAddress();
|
||||||
|
codeListener.endBlock(token, false);
|
||||||
|
++ptr;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
private void parseBranch(BranchOpcode opcode) {
|
private void parseBranch(BranchOpcode opcode) {
|
||||||
var depth = readLEB();
|
var depth = readLEB();
|
||||||
var target = blockStack.get(blockStack.size() - depth - 1);
|
var target = blockStack.get(blockStack.size() - depth - 1);
|
||||||
|
@ -713,19 +826,50 @@ public class CodeSectionParser {
|
||||||
codeListener.tableBranch(depths, targets, defaultDepth, defaultTarget);
|
codeListener.tableBranch(depths, targets, defaultDepth, defaultTarget);
|
||||||
}
|
}
|
||||||
|
|
||||||
private WasmType readType() {
|
private WasmHollowType readType() {
|
||||||
var typeId = data[ptr++];
|
var typeId = data[ptr++];
|
||||||
switch (typeId) {
|
switch (typeId) {
|
||||||
case 0x7F:
|
case 0x7F:
|
||||||
return WasmType.INT32;
|
return WasmHollowType.INT32;
|
||||||
case 0x7E:
|
case 0x7E:
|
||||||
return WasmType.INT64;
|
return WasmHollowType.INT64;
|
||||||
case 0x7D:
|
case 0x7D:
|
||||||
return WasmType.FLOAT32;
|
return WasmHollowType.FLOAT32;
|
||||||
case 0x7C:
|
case 0x7C:
|
||||||
return WasmType.FLOAT64;
|
return WasmHollowType.FLOAT64;
|
||||||
default:
|
case 0x63:
|
||||||
|
return readHeapType();
|
||||||
|
case 0x40:
|
||||||
return null;
|
return null;
|
||||||
|
default:
|
||||||
|
return readAbsHeapType(typeId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private WasmHollowType.Reference readHeapType() {
|
||||||
|
var typeId = data[ptr];
|
||||||
|
if ((typeId & 0xC0) == 0x40) {
|
||||||
|
var result = readAbsHeapType(typeId);
|
||||||
|
++ptr;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
return new WasmHollowType.CompositeReference(readLEB());
|
||||||
|
}
|
||||||
|
|
||||||
|
private WasmHollowType.SpecialReference readAbsHeapType(int typeId) {
|
||||||
|
switch (typeId) {
|
||||||
|
case 0x70:
|
||||||
|
return WasmHollowType.Reference.FUNC;
|
||||||
|
case 0x6F:
|
||||||
|
return WasmHollowType.Reference.EXTERN;
|
||||||
|
case 0x6E:
|
||||||
|
return WasmHollowType.Reference.ANY;
|
||||||
|
case 0x6B:
|
||||||
|
return WasmHollowType.Reference.STRUCT;
|
||||||
|
case 0x6A:
|
||||||
|
return WasmHollowType.Reference.ARRAY;
|
||||||
|
default:
|
||||||
|
throw new ParseException("Unknown type", ptr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -19,5 +19,7 @@ public enum Opcode {
|
||||||
UNREACHABLE,
|
UNREACHABLE,
|
||||||
NOP,
|
NOP,
|
||||||
RETURN,
|
RETURN,
|
||||||
DROP
|
DROP,
|
||||||
|
REF_EQ,
|
||||||
|
ARRAY_LENGTH
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,98 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2024 konsoletyper.
|
||||||
|
*
|
||||||
|
* 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.parser;
|
||||||
|
|
||||||
|
import java.util.Objects;
|
||||||
|
import org.teavm.backend.wasm.model.WasmNumType;
|
||||||
|
import org.teavm.backend.wasm.model.WasmStorageType;
|
||||||
|
import org.teavm.backend.wasm.model.WasmType;
|
||||||
|
|
||||||
|
public class WasmHollowType {
|
||||||
|
public static final Number INT32 = new Number(WasmNumType.INT32);
|
||||||
|
public static final Number INT64 = new Number(WasmNumType.INT64);
|
||||||
|
public static final Number FLOAT32 = new Number(WasmNumType.FLOAT32);
|
||||||
|
public static final Number FLOAT64 = new Number(WasmNumType.FLOAT64);
|
||||||
|
|
||||||
|
private WasmStorageType.Regular storageType;
|
||||||
|
|
||||||
|
private WasmHollowType() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Number num(WasmNumType number) {
|
||||||
|
switch (number) {
|
||||||
|
case INT32:
|
||||||
|
return INT32;
|
||||||
|
case INT64:
|
||||||
|
return INT64;
|
||||||
|
case FLOAT32:
|
||||||
|
return FLOAT32;
|
||||||
|
case FLOAT64:
|
||||||
|
return FLOAT64;
|
||||||
|
default:
|
||||||
|
throw new IllegalArgumentException();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static final class Number extends WasmHollowType {
|
||||||
|
public final WasmNumType number;
|
||||||
|
|
||||||
|
private Number(WasmNumType number) {
|
||||||
|
this.number = number;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public static abstract class Reference extends WasmHollowType {
|
||||||
|
public static final SpecialReference FUNC = new SpecialReference(WasmType.SpecialReferenceKind.FUNC);
|
||||||
|
public static final SpecialReference ANY = new SpecialReference(WasmType.SpecialReferenceKind.ANY);
|
||||||
|
public static final SpecialReference EXTERN = new SpecialReference(WasmType.SpecialReferenceKind.EXTERN);
|
||||||
|
public static final SpecialReference STRUCT = new SpecialReference(WasmType.SpecialReferenceKind.STRUCT);
|
||||||
|
public static final SpecialReference ARRAY = new SpecialReference(WasmType.SpecialReferenceKind.ARRAY);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static final class CompositeReference extends WasmHollowType.Reference {
|
||||||
|
public final int index;
|
||||||
|
|
||||||
|
public CompositeReference(int index) {
|
||||||
|
this.index = index;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object o) {
|
||||||
|
if (this == o) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (!(o instanceof CompositeReference)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
CompositeReference that = (CompositeReference) o;
|
||||||
|
return index == that.index;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
return Objects.hashCode(index);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static final class SpecialReference extends WasmHollowType.Reference {
|
||||||
|
public final WasmType.SpecialReferenceKind kind;
|
||||||
|
|
||||||
|
SpecialReference(WasmType.SpecialReferenceKind kind) {
|
||||||
|
this.kind = kind;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user