From 75bead66b3b6f372a2ad489439a0668f5a5f88be Mon Sep 17 00:00:00 2001 From: Alexey Andreev Date: Wed, 31 Jul 2024 17:31:39 +0200 Subject: [PATCH] wasm: support instructions that were recently implemented in generator --- .../wasm/debug/parser/ControlFlowParser.java | 6 +- .../DisassemblyCodeSectionListener.java | 167 ++++++++++++++++-- .../backend/wasm/parser/CodeListener.java | 55 +++++- .../wasm/parser/CodeSectionListener.java | 4 +- .../wasm/parser/CodeSectionParser.java | 158 ++++++++++++++++- .../org/teavm/backend/wasm/parser/Opcode.java | 4 +- .../backend/wasm/parser/WasmHollowType.java | 98 ++++++++++ 7 files changed, 458 insertions(+), 34 deletions(-) create mode 100644 core/src/main/java/org/teavm/backend/wasm/parser/WasmHollowType.java diff --git a/core/src/main/java/org/teavm/backend/wasm/debug/parser/ControlFlowParser.java b/core/src/main/java/org/teavm/backend/wasm/debug/parser/ControlFlowParser.java index 9ce54ce35..575ff58b9 100644 --- a/core/src/main/java/org/teavm/backend/wasm/debug/parser/ControlFlowParser.java +++ b/core/src/main/java/org/teavm/backend/wasm/debug/parser/ControlFlowParser.java @@ -21,12 +21,12 @@ import java.util.List; import org.teavm.backend.wasm.debug.info.ControlFlowInfo; import org.teavm.backend.wasm.debug.info.FunctionControlFlow; 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.BranchOpcode; import org.teavm.backend.wasm.parser.CodeListener; import org.teavm.backend.wasm.parser.CodeSectionListener; import org.teavm.backend.wasm.parser.Opcode; +import org.teavm.backend.wasm.parser.WasmHollowType; public class ControlFlowParser implements CodeSectionListener, CodeListener, AddressListener { private int previousAddress; @@ -60,12 +60,12 @@ public class ControlFlowParser implements CodeSectionListener, CodeListener, Add } @Override - public int startBlock(boolean loop, WasmType type) { + public int startBlock(boolean loop, WasmHollowType type) { return startBlock(loop); } @Override - public int startConditionalBlock(WasmType type) { + public int startConditionalBlock(WasmHollowType type) { return startBlock(false); } diff --git a/core/src/main/java/org/teavm/backend/wasm/disasm/DisassemblyCodeSectionListener.java b/core/src/main/java/org/teavm/backend/wasm/disasm/DisassemblyCodeSectionListener.java index 1e18ca2fa..4aedda8ee 100644 --- a/core/src/main/java/org/teavm/backend/wasm/disasm/DisassemblyCodeSectionListener.java +++ b/core/src/main/java/org/teavm/backend/wasm/disasm/DisassemblyCodeSectionListener.java @@ -21,7 +21,6 @@ import java.io.PrintWriter; import java.nio.file.Files; import java.util.function.Consumer; 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.WasmFloatType; 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.WasmIntType; 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.BranchOpcode; 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.ModuleParser; import org.teavm.backend.wasm.parser.Opcode; +import org.teavm.backend.wasm.parser.WasmHollowType; import org.teavm.common.ByteArrayAsyncInputStream; public class DisassemblyCodeSectionListener implements AddressListener, CodeSectionListener, CodeListener { private DisassemblyWriter writer; private int address; + private int addressOffset; private int blockIdGen; public DisassemblyCodeSectionListener(DisassemblyWriter writer) { this.writer = writer; } + public void setAddressOffset(int addressOffset) { + this.addressOffset = addressOffset; + } + @Override public void address(int address) { - this.address = address; + this.address = address + addressOffset; } @Override @@ -61,7 +67,7 @@ public class DisassemblyCodeSectionListener implements AddressListener, CodeSect @Override 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; } @@ -71,10 +77,10 @@ public class DisassemblyCodeSectionListener implements AddressListener, CodeSect } @Override - public void local(int start, int count, WasmType type) { + public void local(int start, int count, WasmHollowType type) { writer.address(address); 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(); } - private String blockTypeToString(WasmType type) { + private String blockTypeToString(WasmHollowType type) { if (type == null) { return ""; } 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 instanceof WasmType.Number) { - switch (((WasmType.Number) type).number) { + if (type instanceof WasmHollowType.Number) { + switch (((WasmHollowType.Number) type).number) { case INT32: return "i32"; case INT64: @@ -117,8 +123,23 @@ public class DisassemblyCodeSectionListener implements AddressListener, CodeSect default: break; } - } else if (type instanceof WasmType.Reference) { - return "ref"; + } else if (type instanceof WasmHollowType.SpecialReference) { + 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"; @@ -134,7 +155,7 @@ public class DisassemblyCodeSectionListener implements AddressListener, CodeSect } @Override - public int startBlock(boolean loop, WasmType type) { + public int startBlock(boolean loop, WasmHollowType type) { writer.address(address); var label = blockIdGen++; writer.write(loop ? "loop" : "block").write(" $label_" + label).write(blockTypeToString(type)) @@ -143,7 +164,7 @@ public class DisassemblyCodeSectionListener implements AddressListener, CodeSect } @Override - public int startConditionalBlock(WasmType type) { + public int startConditionalBlock(WasmHollowType type) { writer.address(address); var label = blockIdGen++; 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(); } + @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 public void endBlock(int token, boolean loop) { writer.address(address).outdent().write("end (; $label_" + token + " ;)").eol(); @@ -185,6 +220,12 @@ public class DisassemblyCodeSectionListener implements AddressListener, CodeSect writer.write(" $label_" + defaultTarget).eol(); } + @Override + public void throwInstruction(int tagIndex) { + writer.address(address); + writer.write("throw ").write(String.valueOf(tagIndex)).eol(); + } + @Override public void opcode(Opcode opcode) { writer.address(address); @@ -201,6 +242,12 @@ public class DisassemblyCodeSectionListener implements AddressListener, CodeSect case DROP: writer.write("drop"); break; + case REF_EQ: + writer.write("ref.eq"); + break; + case ARRAY_LENGTH: + writer.write("array.length"); + break; } writer.eol(); } @@ -216,20 +263,35 @@ public class DisassemblyCodeSectionListener implements AddressListener, CodeSect writer.write("local.set"); 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 public void call(int functionIndex) { writer.address(address); - writer.write("call $fun_" + functionIndex).eol(); + writer.write("call " + functionIndex).eol(); } @Override public void indirectCall(int typeIndex, int tableIndex) { writer.address(address); - //TODO: type signature must be printed - writer.write("call_indirect $table_" + tableIndex + " $type_" + typeIndex).eol(); + writer.write("call_indirect " + tableIndex + " " + typeIndex).eol(); + } + + @Override + public void callReference(int typeIndex) { + writer.address(address); + writer.write("call_ref " + typeIndex).eol(); } @Override @@ -429,6 +491,9 @@ public class DisassemblyCodeSectionListener implements AddressListener, CodeSect case CTZ: writer.write("ctz"); break; + case EQZ: + writer.write("eqz"); + break; case POPCNT: writer.write("popcnt"); break; @@ -758,6 +823,73 @@ public class DisassemblyCodeSectionListener implements AddressListener, CodeSect 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 { var file = new File(args[0]); var bytes = Files.readAllBytes(file.toPath()); @@ -770,6 +902,7 @@ public class DisassemblyCodeSectionListener implements AddressListener, CodeSect var out = new PrintWriter(System.out); var writer = new DisassemblyWriter(out, true); var disassembler = new DisassemblyCodeSectionListener(writer); + disassembler.setAddressOffset(pos); var sectionParser = new CodeSectionParser(disassembler, disassembler); sectionParser.parse(bytes); out.flush(); diff --git a/core/src/main/java/org/teavm/backend/wasm/parser/CodeListener.java b/core/src/main/java/org/teavm/backend/wasm/parser/CodeListener.java index ca5424c96..2afe61efc 100644 --- a/core/src/main/java/org/teavm/backend/wasm/parser/CodeListener.java +++ b/core/src/main/java/org/teavm/backend/wasm/parser/CodeListener.java @@ -16,7 +16,6 @@ package org.teavm.backend.wasm.parser; 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.WasmFloatType; 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.WasmIntType; import org.teavm.backend.wasm.model.expression.WasmIntUnaryOperation; +import org.teavm.backend.wasm.model.expression.WasmSignedType; public interface CodeListener { default void error(int depth) { } - default int startBlock(boolean loop, WasmType type) { + default int startBlock(boolean loop, WasmHollowType type) { return 0; } - default int startConditionalBlock(WasmType type) { + default int startConditionalBlock(WasmHollowType type) { return 0; } default void startElseSection(int token) { } + default int startTry(WasmHollowType type) { + return 0; + } + + default void startCatch(int tagIndex) { + } + 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 throwInstruction(int tagIndex) { + } + default void opcode(Opcode opcode) { } @@ -121,4 +131,43 @@ public interface CodeListener { 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) { + } } diff --git a/core/src/main/java/org/teavm/backend/wasm/parser/CodeSectionListener.java b/core/src/main/java/org/teavm/backend/wasm/parser/CodeSectionListener.java index 8166516c3..9fa37a535 100644 --- a/core/src/main/java/org/teavm/backend/wasm/parser/CodeSectionListener.java +++ b/core/src/main/java/org/teavm/backend/wasm/parser/CodeSectionListener.java @@ -15,8 +15,6 @@ */ package org.teavm.backend.wasm.parser; -import org.teavm.backend.wasm.model.WasmType; - public interface CodeSectionListener { default void sectionStart(int functionCount) { } @@ -28,7 +26,7 @@ public interface CodeSectionListener { 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() { diff --git a/core/src/main/java/org/teavm/backend/wasm/parser/CodeSectionParser.java b/core/src/main/java/org/teavm/backend/wasm/parser/CodeSectionParser.java index bfa2801fa..488708d4a 100644 --- a/core/src/main/java/org/teavm/backend/wasm/parser/CodeSectionParser.java +++ b/core/src/main/java/org/teavm/backend/wasm/parser/CodeSectionParser.java @@ -18,7 +18,6 @@ package org.teavm.backend.wasm.parser; import java.util.ArrayList; import java.util.List; 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.WasmFloatType; 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.WasmIntType; import org.teavm.backend.wasm.model.expression.WasmIntUnaryOperation; +import org.teavm.backend.wasm.model.expression.WasmSignedType; public class CodeSectionParser { private AddressListener addressListener; @@ -125,6 +125,11 @@ public class CodeSectionParser { return parseBlock(true); case 0x04: return parseConditional(); + case 0x06: + return parseTryCatch(); + case 0x8: + codeListener.throwInstruction(readLEB()); + break; case 0x0C: parseBranch(BranchOpcode.BR); break; @@ -143,6 +148,9 @@ public class CodeSectionParser { case 0x11: codeListener.indirectCall(readLEB(), readLEB()); break; + case 0x14: + codeListener.callReference(readLEB()); + break; case 0x1A: codeListener.opcode(Opcode.DROP); @@ -155,6 +163,13 @@ public class CodeSectionParser { codeListener.local(LocalOpcode.SET, readLEB()); break; + case 0x23: + codeListener.getGlobal(readLEB()); + break; + case 0x24: + codeListener.setGlobal(readLEB()); + break; + case 0x28: codeListener.loadInt32(WasmInt32Subtype.INT32, 1 << readLEB(), readLEB()); break; @@ -617,6 +632,20 @@ public class CodeSectionParser { codeListener.convert(WasmNumType.INT64, WasmNumType.FLOAT64, false, true); 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: 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) { var type = readType(); var token = codeListener.startBlock(isLoop, type); @@ -693,6 +777,35 @@ public class CodeSectionParser { 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) { var depth = readLEB(); var target = blockStack.get(blockStack.size() - depth - 1); @@ -713,19 +826,50 @@ public class CodeSectionParser { codeListener.tableBranch(depths, targets, defaultDepth, defaultTarget); } - private WasmType readType() { + private WasmHollowType readType() { var typeId = data[ptr++]; switch (typeId) { case 0x7F: - return WasmType.INT32; + return WasmHollowType.INT32; case 0x7E: - return WasmType.INT64; + return WasmHollowType.INT64; case 0x7D: - return WasmType.FLOAT32; + return WasmHollowType.FLOAT32; case 0x7C: - return WasmType.FLOAT64; - default: + return WasmHollowType.FLOAT64; + case 0x63: + return readHeapType(); + case 0x40: 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); } } diff --git a/core/src/main/java/org/teavm/backend/wasm/parser/Opcode.java b/core/src/main/java/org/teavm/backend/wasm/parser/Opcode.java index 522a03380..3ea33378c 100644 --- a/core/src/main/java/org/teavm/backend/wasm/parser/Opcode.java +++ b/core/src/main/java/org/teavm/backend/wasm/parser/Opcode.java @@ -19,5 +19,7 @@ public enum Opcode { UNREACHABLE, NOP, RETURN, - DROP + DROP, + REF_EQ, + ARRAY_LENGTH } diff --git a/core/src/main/java/org/teavm/backend/wasm/parser/WasmHollowType.java b/core/src/main/java/org/teavm/backend/wasm/parser/WasmHollowType.java new file mode 100644 index 000000000..84fe76328 --- /dev/null +++ b/core/src/main/java/org/teavm/backend/wasm/parser/WasmHollowType.java @@ -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; + } + } +}