From 44204b952dc406fd71075812bdf605022e2e24fa Mon Sep 17 00:00:00 2001 From: Alexey Andreev Date: Sun, 4 Dec 2022 20:43:32 +0100 Subject: [PATCH] Wasm: working on binary parser --- .../DisassemblyCodeSectionListener.java | 511 +++++++++++++++++- .../wasm/disasm/DisassemblyWriter.java | 6 +- .../backend/wasm/parser/CodeListener.java | 93 +++- .../wasm/parser/CodeSectionParser.java | 501 ++++++++++++++++- .../org/teavm/backend/wasm/parser/Opcode.java | 4 +- 5 files changed, 1078 insertions(+), 37 deletions(-) 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 70dc24620..373eb537c 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 @@ -23,8 +23,12 @@ import java.util.function.Consumer; 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; +import org.teavm.backend.wasm.model.expression.WasmInt32Subtype; +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.parser.AddressListener; import org.teavm.backend.wasm.parser.BranchOpcode; import org.teavm.backend.wasm.parser.CodeListener; @@ -183,9 +187,15 @@ public class DisassemblyCodeSectionListener implements AddressListener, CodeSect case UNREACHABLE: writer.write("unreachable"); break; + case NOP: + writer.write("nop"); + break; case RETURN: writer.write("return"); break; + case DROP: + writer.write("drop"); + break; } writer.eol(); } @@ -205,13 +215,512 @@ public class DisassemblyCodeSectionListener implements AddressListener, CodeSect } @Override - public void binary(WasmIntBinaryOperation opcode, WasmIntType type) { + public void call(int functionIndex) { + writer.address(address); + writer.write("call $fun_" + 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(); + } + + @Override + public void loadInt32(WasmInt32Subtype convertFrom, int align, int offset) { + writer.address(address); + var defaultAlign = 0; + switch (convertFrom) { + case INT8: + writer.write("i32.load8_s"); + defaultAlign = 1; + break; + case UINT8: + writer.write("i32.load8_u"); + defaultAlign = 1; + break; + case INT16: + writer.write("i32.load16_s"); + defaultAlign = 2; + break; + case UINT16: + writer.write("i32.load16_u"); + defaultAlign = 2; + break; + case INT32: + writer.write("i32.load"); + defaultAlign = 4; + break; + } + writeMemArg(align, defaultAlign, offset); + writer.eol(); + } + + @Override + public void storeInt32(WasmInt32Subtype convertTo, int align, int offset) { + writer.address(address); + var defaultAlign = 0; + switch (convertTo) { + case INT8: + case UINT8: + writer.write("i32.store8"); + defaultAlign = 1; + break; + case INT16: + case UINT16: + writer.write("i32.store16"); + defaultAlign = 2; + break; + case INT32: + writer.write("i32.store"); + defaultAlign = 4; + break; + } + writeMemArg(align, defaultAlign, offset); + writer.eol(); + } + + @Override + public void loadInt64(WasmInt64Subtype convertFrom, int align, int offset) { + writer.address(address); + var defaultAlign = 0; + switch (convertFrom) { + case INT8: + writer.write("i64.load8_s"); + defaultAlign = 1; + break; + case UINT8: + writer.write("i64.load8_u"); + defaultAlign = 1; + break; + case INT16: + writer.write("i64.load16_s"); + defaultAlign = 2; + break; + case UINT16: + writer.write("i64.load16_u"); + defaultAlign = 2; + break; + case INT32: + writer.write("i64.load32_s"); + defaultAlign = 4; + break; + case UINT32: + writer.write("i64.load32_u"); + defaultAlign = 4; + break; + case INT64: + writer.write("i64.load"); + defaultAlign = 8; + break; + } + writeMemArg(align, defaultAlign, offset); + writer.eol(); + } + + @Override + public void storeInt64(WasmInt64Subtype convertTo, int align, int offset) { + writer.address(address); + var defaultAlign = 0; + switch (convertTo) { + case INT8: + case UINT8: + writer.write("i64.store8"); + defaultAlign = 1; + break; + case INT16: + case UINT16: + writer.write("i64.store16"); + defaultAlign = 2; + break; + case INT32: + case UINT32: + writer.write("i64.store32"); + defaultAlign = 4; + break; + case INT64: + writer.write("i64.store"); + defaultAlign = 8; + break; + } + writeMemArg(align, defaultAlign, offset); + writer.eol(); + } + + @Override + public void loadFloat32(int align, int offset) { + writer.address(address).write("f32.load"); + writeMemArg(align, 4, offset); + writer.eol(); + } + + @Override + public void storeFloat32(int align, int offset) { + writer.address(address).write("f32.store"); + writeMemArg(align, 4, offset); + writer.eol(); + } + + + @Override + public void loadFloat64(int align, int offset) { + writer.address(address).write("f64.load"); + writeMemArg(align, 8, offset); + writer.eol(); + } + + @Override + public void storeFloat64(int align, int offset) { + writer.address(address).write("f64.store"); + writeMemArg(align, 8, offset); + writer.eol(); + } + + @Override + public void memoryGrow() { + writer.address(address).write("memory.grow").eol(); + } + + private void writeMemArg(int align, int defaultAlign, int offset) { + var needsComma = false; + if (align != defaultAlign) { + writer.write(" align=" + align); + needsComma = true; + } + if (offset != 0) { + if (needsComma) { + writer.write(","); + } + writer.write(" offset=" + offset); + } + } + + @Override + public void unary(WasmIntUnaryOperation opcode, WasmIntType type) { + writer.address(address); + switch (type) { + case INT32: + writer.write("i32."); + break; + case INT64: + writer.write("i64."); + break; + } + switch (opcode) { + case CLZ: + writer.write("clz"); + break; + case CTZ: + writer.write("ctz"); + break; + case POPCNT: + writer.write("popcnt"); + break; + } + writer.eol(); + } + + @Override + public void unary(WasmFloatUnaryOperation opcode, WasmFloatType type) { + writer.address(address); + switch (type) { + case FLOAT32: + writer.write("f32."); + break; + case FLOAT64: + writer.write("f64."); + break; + } + switch (opcode) { + case ABS: + writer.write("abs"); + break; + case NEG: + writer.write("neg"); + break; + case FLOOR: + writer.write("floor"); + break; + case CEIL: + writer.write("ceil"); + break; + case TRUNC: + writer.write("trunc"); + break; + case NEAREST: + writer.write("nearest"); + break; + case SQRT: + writer.write("sqrt"); + break; + case COPYSIGN: + writer.write("copysign"); + break; + } + writer.eol(); + } + + @Override + public void binary(WasmIntBinaryOperation opcode, WasmIntType type) { + writer.address(address); + switch (type) { + case INT32: + writer.write("i32."); + break; + case INT64: + writer.write("i64."); + break; + } + switch (opcode) { + case ADD: + writer.write("add"); + break; + case SUB: + writer.write("sub"); + break; + case MUL: + writer.write("mul"); + break; + case DIV_SIGNED: + writer.write("div_s"); + break; + case DIV_UNSIGNED: + writer.write("div_u"); + break; + case REM_SIGNED: + writer.write("rem_s"); + break; + case REM_UNSIGNED: + writer.write("rem_u"); + break; + case AND: + writer.write("and"); + break; + case OR: + writer.write("or"); + break; + case XOR: + writer.write("xor"); + break; + case SHL: + writer.write("shl"); + break; + case SHR_SIGNED: + writer.write("shr_s"); + break; + case SHR_UNSIGNED: + writer.write("shr_u"); + break; + case ROTL: + writer.write("rotl"); + break; + case ROTR: + writer.write("rotr"); + break; + case EQ: + writer.write("eq"); + break; + case NE: + writer.write("ne"); + break; + case LT_SIGNED: + writer.write("lt_s"); + break; + case LT_UNSIGNED: + writer.write("lt_u"); + break; + case GT_SIGNED: + writer.write("gt_s"); + break; + case GT_UNSIGNED: + writer.write("gt_u"); + break; + case LE_SIGNED: + writer.write("le_s"); + break; + case LE_UNSIGNED: + writer.write("le_u"); + break; + case GE_SIGNED: + writer.write("ge_s"); + break; + case GE_UNSIGNED: + writer.write("ge_u"); + break; + } + writer.eol(); } @Override public void binary(WasmFloatBinaryOperation opcode, WasmFloatType type) { + writer.address(address); + switch (type) { + case FLOAT32: + writer.write("f32."); + break; + case FLOAT64: + writer.write("f64."); + break; + } + switch (opcode) { + case ADD: + writer.write("add"); + break; + case SUB: + writer.write("sub"); + break; + case MUL: + writer.write("mul"); + break; + case DIV: + writer.write("div"); + break; + case MIN: + writer.write("min"); + break; + case MAX: + writer.write("max"); + break; + case EQ: + writer.write("eq"); + break; + case NE: + writer.write("ne"); + break; + case LT: + writer.write("lt"); + break; + case GT: + writer.write("gt"); + break; + case LE: + writer.write("le"); + break; + case GE: + writer.write("ge"); + break; + } + writer.eol(); + } + @Override + public void convert(WasmType sourceType, WasmType targetType, boolean signed, boolean reinterpret) { + switch (targetType) { + case INT32: + writer.write("i32."); + switch (sourceType) { + case FLOAT32: + if (reinterpret) { + writer.write("reinterpret_f32"); + } else if (signed) { + writer.write("trunc_f32_s"); + } else { + writer.write("trunc_f32_u"); + } + break; + case FLOAT64: + if (signed) { + writer.write("trunc_f64_s"); + } else { + writer.write("trunc_f64_u"); + } + break; + case INT64: + writer.write("wrap_i64"); + break; + default: + writer.write("error"); + break; + } + break; + case INT64: + writer.write("i64."); + switch (sourceType) { + case FLOAT32: + if (signed) { + writer.write("trunc_f32_s"); + } else { + writer.write("trunc_f32_u"); + } + break; + case FLOAT64: + if (reinterpret) { + writer.write("reinterpret_f64"); + } else if (signed) { + writer.write("trunc_f64_s"); + } else { + writer.write("trunc_f64_u"); + } + break; + case INT32: + if (signed) { + writer.write("extend_i32_s"); + } else { + writer.write("extend_i32_u"); + } + break; + default: + writer.write("error"); + break; + } + break; + case FLOAT32: + writer.write("f32."); + switch (sourceType) { + case INT32: + if (reinterpret) { + writer.write("reinterpret_i32"); + } else if (signed) { + writer.write("convert_i32_s"); + } else { + writer.write("convert_i32_u"); + } + break; + case INT64: + if (signed) { + writer.write("convert_i64_s"); + } else { + writer.write("convert_i64_u"); + } + break; + case FLOAT64: + writer.write("demote_f64"); + break; + default: + writer.write("error"); + break; + } + break; + case FLOAT64: + writer.write("f64."); + switch (sourceType) { + case INT32: + if (signed) { + writer.write("convert_i32_s"); + } else { + writer.write("convert_i32_u"); + } + break; + case INT64: + if (reinterpret) { + writer.write("reinterpret_i64"); + } else if (signed) { + writer.write("convert_i64_s"); + } else { + writer.write("convert_i64_u"); + } + break; + case FLOAT32: + writer.write("promote_f32"); + break; + default: + writer.write("error"); + break; + } + break; + } + writer.eol(); } @Override diff --git a/core/src/main/java/org/teavm/backend/wasm/disasm/DisassemblyWriter.java b/core/src/main/java/org/teavm/backend/wasm/disasm/DisassemblyWriter.java index de727e5f8..b6b34d148 100644 --- a/core/src/main/java/org/teavm/backend/wasm/disasm/DisassemblyWriter.java +++ b/core/src/main/java/org/teavm/backend/wasm/disasm/DisassemblyWriter.java @@ -63,9 +63,9 @@ public class DisassemblyWriter { out.print(" "); } } - } - for (int i = 0; i < indentLevel; ++i) { - out.print(" "); + for (int i = 0; i < indentLevel; ++i) { + out.print(" "); + } } } 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 c918ac3a4..2f5e18940 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 @@ -18,37 +18,100 @@ package org.teavm.backend.wasm.parser; 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; +import org.teavm.backend.wasm.model.expression.WasmInt32Subtype; +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; public interface CodeListener { - void error(int depth); + default void error(int depth) { + } - int startBlock(boolean loop, WasmType type); + default int startBlock(boolean loop, WasmType type) { + return 0; + } - int startConditionalBlock(WasmType type); + default int startConditionalBlock(WasmType type) { + return 0; + } - void startElseSection(int token); + default void startElseSection(int token) { + } - void endBlock(int token); + default void endBlock(int token) { + } - void branch(BranchOpcode opcode, int depth, int target); + default void branch(BranchOpcode opcode, int depth, int target) { + } - void tableBranch(int[] depths, int[] targets, int defaultDepth, int defaultTarget); + default void tableBranch(int[] depths, int[] targets, int defaultDepth, int defaultTarget) { + } - void opcode(Opcode opcode); + default void opcode(Opcode opcode) { + } - void local(LocalOpcode opcode, int index); + default void local(LocalOpcode opcode, int index) { + } - void binary(WasmIntBinaryOperation opcode, WasmIntType type); + default void unary(WasmIntUnaryOperation opcode, WasmIntType type) { + } - void binary(WasmFloatBinaryOperation opcode, WasmFloatType type); + default void unary(WasmFloatUnaryOperation opcode, WasmFloatType type) { + } - void int32Constant(int value); + default void binary(WasmIntBinaryOperation opcode, WasmIntType type) { + } - void int64Constant(long value); + default void binary(WasmFloatBinaryOperation opcode, WasmFloatType type) { + } - void float32Constant(float value); + default void call(int functionIndex) { + } - void float64Constant(double value); + default void indirectCall(int typeIndex, int tableIndex) { + } + + default void loadInt32(WasmInt32Subtype convertFrom, int align, int offset) { + } + + default void storeInt32(WasmInt32Subtype convertTo, int align, int offset) { + } + + default void loadInt64(WasmInt64Subtype convertFrom, int align, int offset) { + } + + default void storeInt64(WasmInt64Subtype convertTo, int align, int offset) { + } + + default void loadFloat32(int align, int offset) { + } + + default void storeFloat32(int align, int offset) { + } + + default void loadFloat64(int align, int offset) { + } + + default void storeFloat64(int align, int offset) { + } + + default void convert(WasmType sourceType, WasmType targetType, boolean signed, boolean reinterpret) { + } + + default void memoryGrow() { + } + + default void int32Constant(int value) { + } + + default void int64Constant(long value) { + } + + default void float32Constant(float value) { + } + + default void float64Constant(double value) { + } } 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 138863bb8..58de59a91 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,6 +18,14 @@ package org.teavm.backend.wasm.parser; import java.util.ArrayList; import java.util.List; 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; +import org.teavm.backend.wasm.model.expression.WasmInt32Subtype; +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; public class CodeSectionParser { private AddressListener addressListener; @@ -103,10 +111,13 @@ public class CodeSectionParser { private boolean parseExpr() { reportAddress(); - switch (data[ptr++]) { + switch (data[ptr++] & 0xFF) { case 0x00: codeListener.opcode(Opcode.UNREACHABLE); break; + case 0x01: + codeListener.opcode(Opcode.NOP); + break; case 0x02: return parseBlock(false); case 0x03: @@ -123,14 +134,100 @@ public class CodeSectionParser { parseTableBranch(); break; case 0x0F: - codeListener.opcode(Opcode.UNREACHABLE); + codeListener.opcode(Opcode.RETURN); break; + case 0x10: + codeListener.call(readLEB()); + break; + case 0x11: + codeListener.indirectCall(readLEB(), readLEB()); + break; + + case 0x1A: + codeListener.opcode(Opcode.DROP); + break; + case 0x20: codeListener.local(LocalOpcode.GET, readLEB()); break; case 0x21: codeListener.local(LocalOpcode.SET, readLEB()); break; + + case 0x28: + codeListener.loadInt32(WasmInt32Subtype.INT32, 1 << readLEB(), readLEB()); + break; + case 0x29: + codeListener.loadInt64(WasmInt64Subtype.INT64, 1 << readLEB(), readLEB()); + break; + case 0x2A: + codeListener.loadFloat32(1 << readLEB(), readLEB()); + break; + case 0x2B: + codeListener.loadFloat64(1 << readLEB(), readLEB()); + break; + case 0x2C: + codeListener.loadInt32(WasmInt32Subtype.INT8, 1 << readLEB(), readLEB()); + break; + case 0x2D: + codeListener.loadInt32(WasmInt32Subtype.UINT8, 1 << readLEB(), readLEB()); + break; + case 0x2E: + codeListener.loadInt32(WasmInt32Subtype.INT16, 1 << readLEB(), readLEB()); + break; + case 0x2F: + codeListener.loadInt32(WasmInt32Subtype.UINT16, 1 << readLEB(), readLEB()); + break; + case 0x30: + codeListener.loadInt64(WasmInt64Subtype.INT8, 1 << readLEB(), readLEB()); + break; + case 0x31: + codeListener.loadInt64(WasmInt64Subtype.UINT8, 1 << readLEB(), readLEB()); + break; + case 0x32: + codeListener.loadInt64(WasmInt64Subtype.INT16, 1 << readLEB(), readLEB()); + break; + case 0x33: + codeListener.loadInt64(WasmInt64Subtype.UINT16, 1 << readLEB(), readLEB()); + break; + case 0x34: + codeListener.loadInt64(WasmInt64Subtype.INT32, 1 << readLEB(), readLEB()); + break; + case 0x35: + codeListener.loadInt64(WasmInt64Subtype.UINT32, 1 << readLEB(), readLEB()); + break; + case 0x36: + codeListener.storeInt32(WasmInt32Subtype.INT32, 1 << readLEB(), readLEB()); + break; + case 0x37: + codeListener.storeInt64(WasmInt64Subtype.INT64, 1 << readLEB(), readLEB()); + break; + case 0x38: + codeListener.storeFloat32(1 << readLEB(), readLEB()); + break; + case 0x39: + codeListener.storeFloat64(1 << readLEB(), readLEB()); + break; + case 0x3A: + codeListener.storeInt32(WasmInt32Subtype.INT8, 1 << readLEB(), readLEB()); + break; + case 0x3B: + codeListener.storeInt32(WasmInt32Subtype.INT16, 1 << readLEB(), readLEB()); + break; + case 0x3C: + codeListener.storeInt64(WasmInt64Subtype.INT8, 1 << readLEB(), readLEB()); + break; + case 0x3D: + codeListener.storeInt64(WasmInt64Subtype.INT16, 1 << readLEB(), readLEB()); + break; + case 0x3E: + codeListener.storeInt64(WasmInt64Subtype.INT32, 1 << readLEB(), readLEB()); + break; + case 0x40: + readLEB(); + codeListener.memoryGrow(); + break; + case 0x41: codeListener.int32Constant(readSignedLEB()); break; @@ -143,6 +240,376 @@ public class CodeSectionParser { case 0x44: codeListener.float64Constant(Double.longBitsToDouble(readFixedLong())); break; + + case 0x46: + codeListener.binary(WasmIntBinaryOperation.EQ, WasmIntType.INT32); + break; + case 0x47: + codeListener.binary(WasmIntBinaryOperation.NE, WasmIntType.INT32); + break; + case 0x48: + codeListener.binary(WasmIntBinaryOperation.LT_SIGNED, WasmIntType.INT32); + break; + case 0x49: + codeListener.binary(WasmIntBinaryOperation.LT_UNSIGNED, WasmIntType.INT32); + break; + case 0x4A: + codeListener.binary(WasmIntBinaryOperation.GT_SIGNED, WasmIntType.INT32); + break; + case 0x4B: + codeListener.binary(WasmIntBinaryOperation.GT_UNSIGNED, WasmIntType.INT32); + break; + case 0x4C: + codeListener.binary(WasmIntBinaryOperation.LE_SIGNED, WasmIntType.INT32); + break; + case 0x4D: + codeListener.binary(WasmIntBinaryOperation.LE_UNSIGNED, WasmIntType.INT32); + break; + case 0x4E: + codeListener.binary(WasmIntBinaryOperation.GE_SIGNED, WasmIntType.INT32); + break; + case 0x4F: + codeListener.binary(WasmIntBinaryOperation.GE_UNSIGNED, WasmIntType.INT32); + break; + + case 0x51: + codeListener.binary(WasmIntBinaryOperation.EQ, WasmIntType.INT64); + break; + case 0x52: + codeListener.binary(WasmIntBinaryOperation.NE, WasmIntType.INT64); + break; + case 0x53: + codeListener.binary(WasmIntBinaryOperation.LT_SIGNED, WasmIntType.INT64); + break; + case 0x54: + codeListener.binary(WasmIntBinaryOperation.LT_UNSIGNED, WasmIntType.INT64); + break; + case 0x55: + codeListener.binary(WasmIntBinaryOperation.GT_SIGNED, WasmIntType.INT64); + break; + case 0x56: + codeListener.binary(WasmIntBinaryOperation.GT_UNSIGNED, WasmIntType.INT64); + break; + case 0x57: + codeListener.binary(WasmIntBinaryOperation.LE_SIGNED, WasmIntType.INT64); + break; + case 0x58: + codeListener.binary(WasmIntBinaryOperation.LE_UNSIGNED, WasmIntType.INT64); + break; + case 0x59: + codeListener.binary(WasmIntBinaryOperation.GE_SIGNED, WasmIntType.INT64); + break; + case 0x5A: + codeListener.binary(WasmIntBinaryOperation.GE_UNSIGNED, WasmIntType.INT64); + break; + + case 0x5B: + codeListener.binary(WasmFloatBinaryOperation.EQ, WasmFloatType.FLOAT32); + break; + case 0x5C: + codeListener.binary(WasmFloatBinaryOperation.NE, WasmFloatType.FLOAT32); + break; + case 0x5D: + codeListener.binary(WasmFloatBinaryOperation.LT, WasmFloatType.FLOAT32); + break; + case 0x5E: + codeListener.binary(WasmFloatBinaryOperation.GT, WasmFloatType.FLOAT32); + break; + case 0x5F: + codeListener.binary(WasmFloatBinaryOperation.LE, WasmFloatType.FLOAT32); + break; + case 0x60: + codeListener.binary(WasmFloatBinaryOperation.GE, WasmFloatType.FLOAT32); + break; + + case 0x61: + codeListener.binary(WasmFloatBinaryOperation.EQ, WasmFloatType.FLOAT64); + break; + case 0x62: + codeListener.binary(WasmFloatBinaryOperation.NE, WasmFloatType.FLOAT64); + break; + case 0x63: + codeListener.binary(WasmFloatBinaryOperation.LT, WasmFloatType.FLOAT64); + break; + case 0x64: + codeListener.binary(WasmFloatBinaryOperation.GT, WasmFloatType.FLOAT64); + break; + case 0x65: + codeListener.binary(WasmFloatBinaryOperation.LE, WasmFloatType.FLOAT64); + break; + case 0x66: + codeListener.binary(WasmFloatBinaryOperation.GE, WasmFloatType.FLOAT64); + break; + + case 0x67: + codeListener.unary(WasmIntUnaryOperation.CLZ, WasmIntType.INT32); + break; + case 0x68: + codeListener.unary(WasmIntUnaryOperation.CTZ, WasmIntType.INT32); + break; + case 0x69: + codeListener.unary(WasmIntUnaryOperation.POPCNT, WasmIntType.INT32); + break; + case 0x6A: + codeListener.binary(WasmIntBinaryOperation.ADD, WasmIntType.INT32); + break; + case 0x6B: + codeListener.binary(WasmIntBinaryOperation.SUB, WasmIntType.INT32); + break; + case 0x6C: + codeListener.binary(WasmIntBinaryOperation.MUL, WasmIntType.INT32); + break; + case 0x6D: + codeListener.binary(WasmIntBinaryOperation.DIV_SIGNED, WasmIntType.INT32); + break; + case 0x6E: + codeListener.binary(WasmIntBinaryOperation.DIV_UNSIGNED, WasmIntType.INT32); + break; + case 0x6F: + codeListener.binary(WasmIntBinaryOperation.REM_SIGNED, WasmIntType.INT32); + break; + case 0x70: + codeListener.binary(WasmIntBinaryOperation.REM_UNSIGNED, WasmIntType.INT32); + break; + case 0x71: + codeListener.binary(WasmIntBinaryOperation.AND, WasmIntType.INT32); + break; + case 0x72: + codeListener.binary(WasmIntBinaryOperation.OR, WasmIntType.INT32); + break; + case 0x73: + codeListener.binary(WasmIntBinaryOperation.XOR, WasmIntType.INT32); + break; + case 0x74: + codeListener.binary(WasmIntBinaryOperation.SHL, WasmIntType.INT32); + break; + case 0x75: + codeListener.binary(WasmIntBinaryOperation.SHR_SIGNED, WasmIntType.INT32); + break; + case 0x76: + codeListener.binary(WasmIntBinaryOperation.SHR_UNSIGNED, WasmIntType.INT32); + break; + case 0x77: + codeListener.binary(WasmIntBinaryOperation.ROTL, WasmIntType.INT32); + break; + case 0x78: + codeListener.binary(WasmIntBinaryOperation.ROTR, WasmIntType.INT32); + break; + + case 0x79: + codeListener.unary(WasmIntUnaryOperation.CLZ, WasmIntType.INT64); + break; + case 0x7A: + codeListener.unary(WasmIntUnaryOperation.CTZ, WasmIntType.INT64); + break; + case 0x7B: + codeListener.unary(WasmIntUnaryOperation.POPCNT, WasmIntType.INT64); + break; + case 0x7C: + codeListener.binary(WasmIntBinaryOperation.ADD, WasmIntType.INT64); + break; + case 0x7D: + codeListener.binary(WasmIntBinaryOperation.SUB, WasmIntType.INT64); + break; + case 0x7E: + codeListener.binary(WasmIntBinaryOperation.MUL, WasmIntType.INT64); + break; + case 0x7F: + codeListener.binary(WasmIntBinaryOperation.DIV_SIGNED, WasmIntType.INT64); + break; + case 0x80: + codeListener.binary(WasmIntBinaryOperation.DIV_UNSIGNED, WasmIntType.INT64); + break; + case 0x81: + codeListener.binary(WasmIntBinaryOperation.REM_SIGNED, WasmIntType.INT64); + break; + case 0x82: + codeListener.binary(WasmIntBinaryOperation.REM_UNSIGNED, WasmIntType.INT64); + break; + case 0x83: + codeListener.binary(WasmIntBinaryOperation.AND, WasmIntType.INT64); + break; + case 0x84: + codeListener.binary(WasmIntBinaryOperation.OR, WasmIntType.INT64); + break; + case 0x85: + codeListener.binary(WasmIntBinaryOperation.XOR, WasmIntType.INT64); + break; + case 0x86: + codeListener.binary(WasmIntBinaryOperation.SHL, WasmIntType.INT64); + break; + case 0x87: + codeListener.binary(WasmIntBinaryOperation.SHR_UNSIGNED, WasmIntType.INT64); + break; + case 0x88: + codeListener.binary(WasmIntBinaryOperation.SHR_UNSIGNED, WasmIntType.INT64); + break; + case 0x89: + codeListener.binary(WasmIntBinaryOperation.ROTL, WasmIntType.INT64); + break; + case 0x8A: + codeListener.binary(WasmIntBinaryOperation.ROTR, WasmIntType.INT64); + break; + + case 0x8B: + codeListener.unary(WasmFloatUnaryOperation.ABS, WasmFloatType.FLOAT32); + break; + case 0x8C: + codeListener.unary(WasmFloatUnaryOperation.NEG, WasmFloatType.FLOAT32); + break; + case 0x8D: + codeListener.unary(WasmFloatUnaryOperation.CEIL, WasmFloatType.FLOAT32); + break; + case 0x8E: + codeListener.unary(WasmFloatUnaryOperation.FLOOR, WasmFloatType.FLOAT32); + break; + case 0x8F: + codeListener.unary(WasmFloatUnaryOperation.TRUNC, WasmFloatType.FLOAT32); + break; + case 0x90: + codeListener.unary(WasmFloatUnaryOperation.NEAREST, WasmFloatType.FLOAT32); + break; + case 0x91: + codeListener.unary(WasmFloatUnaryOperation.SQRT, WasmFloatType.FLOAT32); + break; + case 0x92: + codeListener.binary(WasmFloatBinaryOperation.ADD, WasmFloatType.FLOAT32); + break; + case 0x93: + codeListener.binary(WasmFloatBinaryOperation.SUB, WasmFloatType.FLOAT32); + break; + case 0x94: + codeListener.binary(WasmFloatBinaryOperation.MUL, WasmFloatType.FLOAT32); + break; + case 0x95: + codeListener.binary(WasmFloatBinaryOperation.DIV, WasmFloatType.FLOAT32); + break; + case 0x96: + codeListener.binary(WasmFloatBinaryOperation.MIN, WasmFloatType.FLOAT32); + break; + case 0x97: + codeListener.binary(WasmFloatBinaryOperation.MAX, WasmFloatType.FLOAT32); + break; + case 0x98: + codeListener.unary(WasmFloatUnaryOperation.COPYSIGN, WasmFloatType.FLOAT32); + break; + + case 0x99: + codeListener.unary(WasmFloatUnaryOperation.ABS, WasmFloatType.FLOAT64); + break; + case 0x9A: + codeListener.unary(WasmFloatUnaryOperation.NEG, WasmFloatType.FLOAT64); + break; + case 0x9B: + codeListener.unary(WasmFloatUnaryOperation.CEIL, WasmFloatType.FLOAT64); + break; + case 0x9C: + codeListener.unary(WasmFloatUnaryOperation.FLOOR, WasmFloatType.FLOAT64); + break; + case 0x9D: + codeListener.unary(WasmFloatUnaryOperation.TRUNC, WasmFloatType.FLOAT64); + break; + case 0x9E: + codeListener.unary(WasmFloatUnaryOperation.NEAREST, WasmFloatType.FLOAT64); + break; + case 0x9F: + codeListener.unary(WasmFloatUnaryOperation.SQRT, WasmFloatType.FLOAT64); + break; + case 0xA0: + codeListener.binary(WasmFloatBinaryOperation.ADD, WasmFloatType.FLOAT64); + break; + case 0xA1: + codeListener.binary(WasmFloatBinaryOperation.SUB, WasmFloatType.FLOAT64); + break; + case 0xA2: + codeListener.binary(WasmFloatBinaryOperation.MUL, WasmFloatType.FLOAT64); + break; + case 0xA3: + codeListener.binary(WasmFloatBinaryOperation.DIV, WasmFloatType.FLOAT64); + break; + case 0xA4: + codeListener.binary(WasmFloatBinaryOperation.MIN, WasmFloatType.FLOAT64); + break; + case 0xA5: + codeListener.binary(WasmFloatBinaryOperation.MAX, WasmFloatType.FLOAT64); + break; + case 0xA6: + codeListener.unary(WasmFloatUnaryOperation.COPYSIGN, WasmFloatType.FLOAT64); + break; + + case 0xA7: + codeListener.convert(WasmType.INT64, WasmType.INT32, false, false); + break; + case 0xA8: + codeListener.convert(WasmType.FLOAT32, WasmType.INT32, false, false); + break; + case 0xA9: + codeListener.convert(WasmType.FLOAT32, WasmType.INT32, true, false); + break; + case 0xAA: + codeListener.convert(WasmType.FLOAT64, WasmType.INT32, false, false); + break; + case 0xAB: + codeListener.convert(WasmType.FLOAT64, WasmType.INT32, true, false); + break; + case 0xAC: + codeListener.convert(WasmType.INT32, WasmType.INT64, false, false); + break; + case 0xAD: + codeListener.convert(WasmType.INT32, WasmType.INT64, true, false); + break; + case 0xAE: + codeListener.convert(WasmType.FLOAT32, WasmType.INT64, false, false); + break; + case 0xAF: + codeListener.convert(WasmType.FLOAT32, WasmType.INT64, true, false); + break; + case 0xB0: + codeListener.convert(WasmType.FLOAT64, WasmType.INT64, false, false); + break; + case 0xB1: + codeListener.convert(WasmType.FLOAT64, WasmType.INT64, true, false); + break; + case 0xB2: + codeListener.convert(WasmType.INT32, WasmType.FLOAT32, false, false); + break; + case 0xB3: + codeListener.convert(WasmType.INT32, WasmType.FLOAT32, true, false); + break; + case 0xB4: + codeListener.convert(WasmType.INT64, WasmType.FLOAT32, false, false); + break; + case 0xB5: + codeListener.convert(WasmType.INT64, WasmType.FLOAT32, true, false); + break; + case 0xB6: + codeListener.convert(WasmType.FLOAT64, WasmType.FLOAT32, true, false); + break; + case 0xB7: + codeListener.convert(WasmType.INT32, WasmType.FLOAT64, false, false); + break; + case 0xB8: + codeListener.convert(WasmType.INT32, WasmType.FLOAT64, true, false); + break; + case 0xB9: + codeListener.convert(WasmType.INT64, WasmType.FLOAT64, false, false); + break; + case 0xBA: + codeListener.convert(WasmType.INT64, WasmType.FLOAT64, true, false); + break; + case 0xBC: + codeListener.convert(WasmType.FLOAT32, WasmType.INT32, false, true); + break; + case 0xBD: + codeListener.convert(WasmType.FLOAT64, WasmType.INT64, false, true); + break; + case 0xBE: + codeListener.convert(WasmType.INT32, WasmType.FLOAT32, false, true); + break; + case 0xBF: + codeListener.convert(WasmType.INT64, WasmType.FLOAT64, false, true); + break; + default: return false; } @@ -196,7 +663,7 @@ public class CodeSectionParser { private void parseBranch(BranchOpcode opcode) { var depth = readLEB(); - var target = blockStack.get(blockStack.size() - depth); + var target = blockStack.get(blockStack.size() - depth - 1); codeListener.branch(opcode, depth, target.token); } @@ -207,10 +674,10 @@ public class CodeSectionParser { for (var i = 0; i < count; ++i) { var depth = readLEB(); depths[i] = depth; - targets[i] = blockStack.get(blockStack.size() - depth).token; + targets[i] = blockStack.get(blockStack.size() - depth - 1).token; } var defaultDepth = readLEB(); - var defaultTarget = blockStack.get(blockStack.size() - defaultDepth).token; + var defaultTarget = blockStack.get(blockStack.size() - defaultDepth - 1).token; codeListener.tableBranch(depths, targets, defaultDepth, defaultTarget); } @@ -302,21 +769,21 @@ public class CodeSectionParser { } private int readFixedInt() { - return ((data[ptr] & 0xFF) << 24) - | ((data[ptr] & 0xFF) << 16) - | ((data[ptr] & 0xFF) << 8) - | (data[ptr] & 0xFF); + return ((data[ptr++] & 0xFF) << 24) + | ((data[ptr++] & 0xFF) << 16) + | ((data[ptr++] & 0xFF) << 8) + | (data[ptr++] & 0xFF); } private long readFixedLong() { - return ((data[ptr] & 0xFFL) << 56) - | ((data[ptr] & 0xFFL) << 48) - | ((data[ptr] & 0xFFL) << 40) - | ((data[ptr] & 0xFFL) << 32) - | ((data[ptr] & 0xFFL) << 24) - | ((data[ptr] & 0xFF) << 16) - | ((data[ptr] & 0xFF) << 8) - | (data[ptr] & 0xFF); + return ((data[ptr++] & 0xFFL) << 56) + | ((data[ptr++] & 0xFFL) << 48) + | ((data[ptr++] & 0xFFL) << 40) + | ((data[ptr++] & 0xFFL) << 32) + | ((data[ptr++] & 0xFFL) << 24) + | ((data[ptr++] & 0xFF) << 16) + | ((data[ptr++] & 0xFF) << 8) + | (data[ptr++] & 0xFF); } private static class Block { 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 b41be1a34..522a03380 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 @@ -17,5 +17,7 @@ package org.teavm.backend.wasm.parser; public enum Opcode { UNREACHABLE, - RETURN + NOP, + RETURN, + DROP }