mirror of
https://github.com/Eaglercraft-TeaVM-Fork/eagler-teavm.git
synced 2024-12-22 08:14:09 -08:00
wasm gc: support global section in disassembler
This commit is contained in:
parent
d6b2afd096
commit
a8b999f8d9
|
@ -72,8 +72,8 @@ public class DebugInfoParser extends ModuleParser {
|
||||||
|
|
||||||
private void parseCode(byte[] data) {
|
private void parseCode(byte[] data) {
|
||||||
var builder = new ControlFlowParser();
|
var builder = new ControlFlowParser();
|
||||||
var codeParser = new CodeSectionParser(builder, builder);
|
var codeParser = new CodeSectionParser(builder);
|
||||||
codeParser.parse(data);
|
codeParser.parse(builder, data);
|
||||||
controlFlow = builder.build();
|
controlFlow = builder.build();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -15,30 +15,18 @@
|
||||||
*/
|
*/
|
||||||
package org.teavm.backend.wasm.disasm;
|
package org.teavm.backend.wasm.disasm;
|
||||||
|
|
||||||
import org.teavm.backend.wasm.parser.AddressListener;
|
|
||||||
import org.teavm.backend.wasm.parser.WasmHollowStorageType;
|
import org.teavm.backend.wasm.parser.WasmHollowStorageType;
|
||||||
import org.teavm.backend.wasm.parser.WasmHollowType;
|
import org.teavm.backend.wasm.parser.WasmHollowType;
|
||||||
|
|
||||||
public abstract class BaseDisassemblyListener implements AddressListener {
|
public abstract class BaseDisassemblyListener {
|
||||||
protected final DisassemblyWriter writer;
|
protected final DisassemblyWriter writer;
|
||||||
protected final NameProvider nameProvider;
|
protected final NameProvider nameProvider;
|
||||||
protected int address;
|
|
||||||
private int addressOffset;
|
|
||||||
|
|
||||||
public BaseDisassemblyListener(DisassemblyWriter writer, NameProvider nameProvider) {
|
public BaseDisassemblyListener(DisassemblyWriter writer, NameProvider nameProvider) {
|
||||||
this.writer = writer;
|
this.writer = writer;
|
||||||
this.nameProvider = nameProvider;
|
this.nameProvider = nameProvider;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setAddressOffset(int addressOffset) {
|
|
||||||
this.addressOffset = addressOffset;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void address(int address) {
|
|
||||||
this.address = address + addressOffset;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void writeBlockType(WasmHollowType type) {
|
protected void writeBlockType(WasmHollowType type) {
|
||||||
if (type != null) {
|
if (type != null) {
|
||||||
writer.write(" ");
|
writer.write(" ");
|
||||||
|
|
|
@ -24,6 +24,7 @@ import java.nio.file.Files;
|
||||||
import java.util.function.Consumer;
|
import java.util.function.Consumer;
|
||||||
import org.teavm.backend.wasm.parser.AddressListener;
|
import org.teavm.backend.wasm.parser.AddressListener;
|
||||||
import org.teavm.backend.wasm.parser.CodeSectionParser;
|
import org.teavm.backend.wasm.parser.CodeSectionParser;
|
||||||
|
import org.teavm.backend.wasm.parser.GlobalSectionParser;
|
||||||
import org.teavm.backend.wasm.parser.ImportSectionListener;
|
import org.teavm.backend.wasm.parser.ImportSectionListener;
|
||||||
import org.teavm.backend.wasm.parser.ImportSectionParser;
|
import org.teavm.backend.wasm.parser.ImportSectionParser;
|
||||||
import org.teavm.backend.wasm.parser.ModuleParser;
|
import org.teavm.backend.wasm.parser.ModuleParser;
|
||||||
|
@ -96,23 +97,36 @@ public final class Disassembler {
|
||||||
};
|
};
|
||||||
if (code == 1) {
|
if (code == 1) {
|
||||||
return bytes -> {
|
return bytes -> {
|
||||||
|
writer.write("(; type section size: " + bytes.length + " ;)");
|
||||||
var typeWriter = new DisassemblyTypeSectionListener(writer, nameProvider);
|
var typeWriter = new DisassemblyTypeSectionListener(writer, nameProvider);
|
||||||
typeWriter.setAddressOffset(pos);
|
writer.setAddressOffset(pos);
|
||||||
var sectionParser = new TypeSectionParser(typeWriter, typeWriter);
|
var sectionParser = new TypeSectionParser(typeWriter);
|
||||||
sectionParser.parse(bytes);
|
sectionParser.parse(writer.addressListener, bytes);
|
||||||
out.flush();
|
out.flush();
|
||||||
};
|
};
|
||||||
} else if (code == 2) {
|
} else if (code == 2) {
|
||||||
return bytes -> {
|
return bytes -> {
|
||||||
var parser = new ImportSectionParser(AddressListener.EMPTY, importListener);
|
var parser = new ImportSectionParser(importListener);
|
||||||
parser.parse(bytes);
|
parser.parse(AddressListener.EMPTY, bytes);
|
||||||
|
};
|
||||||
|
} else if (code == 6) {
|
||||||
|
return bytes -> {
|
||||||
|
writer.write("(; global section size: " + bytes.length + " ;)");
|
||||||
|
var globalWriter = new DisassemblyGlobalSectionListener(writer, nameProvider);
|
||||||
|
writer.setAddressOffset(pos);
|
||||||
|
var sectionParser = new GlobalSectionParser(globalWriter);
|
||||||
|
sectionParser.setFunctionIndexOffset(importListener.count);
|
||||||
|
sectionParser.parse(writer.addressListener, bytes);
|
||||||
|
out.flush();
|
||||||
};
|
};
|
||||||
} else if (code == 10) {
|
} else if (code == 10) {
|
||||||
return bytes -> {
|
return bytes -> {
|
||||||
var disassembler = new DisassemblyCodeSectionListener(writer, nameProvider);
|
var disassembler = new DisassemblyCodeSectionListener(writer, nameProvider);
|
||||||
disassembler.setAddressOffset(pos);
|
writer.setAddressOffset(pos);
|
||||||
var sectionParser = new CodeSectionParser(disassembler, disassembler);
|
writer.write("(; code section size: " + bytes.length + " ;)");
|
||||||
sectionParser.parse(bytes);
|
var sectionParser = new CodeSectionParser(disassembler);
|
||||||
|
sectionParser.setFunctionIndexOffset(importListener.count);
|
||||||
|
sectionParser.parse(writer.addressListener, bytes);
|
||||||
out.flush();
|
out.flush();
|
||||||
};
|
};
|
||||||
} else {
|
} else {
|
||||||
|
@ -124,7 +138,7 @@ public final class Disassembler {
|
||||||
if (code == 0 && name.equals("name")) {
|
if (code == 0 && name.equals("name")) {
|
||||||
return bytes -> {
|
return bytes -> {
|
||||||
var parser = new NameSectionParser(listener);
|
var parser = new NameSectionParser(listener);
|
||||||
parser.parse(bytes);
|
parser.parse(AddressListener.EMPTY, bytes);
|
||||||
};
|
};
|
||||||
} else {
|
} else {
|
||||||
return null;
|
return null;
|
||||||
|
|
|
@ -0,0 +1,849 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2024 Alexey Andreev.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package org.teavm.backend.wasm.disasm;
|
||||||
|
|
||||||
|
import org.teavm.backend.wasm.model.WasmNumType;
|
||||||
|
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.model.expression.WasmSignedType;
|
||||||
|
import org.teavm.backend.wasm.parser.BranchOpcode;
|
||||||
|
import org.teavm.backend.wasm.parser.CodeListener;
|
||||||
|
import org.teavm.backend.wasm.parser.LocalOpcode;
|
||||||
|
import org.teavm.backend.wasm.parser.Opcode;
|
||||||
|
import org.teavm.backend.wasm.parser.WasmHollowType;
|
||||||
|
|
||||||
|
public class DisassemblyCodeListener extends BaseDisassemblyListener implements CodeListener {
|
||||||
|
private int blockIdGen;
|
||||||
|
private int currentFunctionId;
|
||||||
|
|
||||||
|
public DisassemblyCodeListener(DisassemblyWriter writer, NameProvider nameProvider) {
|
||||||
|
super(writer, nameProvider);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setCurrentFunctionId(int currentFunctionId) {
|
||||||
|
this.currentFunctionId = currentFunctionId;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void error(int depth) {
|
||||||
|
writer.address();
|
||||||
|
writer.write("error").eol();
|
||||||
|
for (int i = 0; i < depth; ++i) {
|
||||||
|
writer.outdent();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int startBlock(boolean loop, WasmHollowType type) {
|
||||||
|
writer.address();
|
||||||
|
var label = blockIdGen++;
|
||||||
|
writer.write(loop ? "loop" : "block").write(" $label_" + label);
|
||||||
|
writeBlockType(type);
|
||||||
|
writer.indent().eol();
|
||||||
|
return label;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int startConditionalBlock(WasmHollowType type) {
|
||||||
|
writer.address();
|
||||||
|
var label = blockIdGen++;
|
||||||
|
writer.write("if ").write(" $label_" + label);
|
||||||
|
writeBlockType(type);
|
||||||
|
writer.indent().eol();
|
||||||
|
return label;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void startElseSection(int token) {
|
||||||
|
writer.address();
|
||||||
|
writer.outdent().write("else (; $label_" + token + " ;)").indent().eol();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int startTry(WasmHollowType type) {
|
||||||
|
writer.address();
|
||||||
|
var label = blockIdGen++;
|
||||||
|
writer.write("try ").write(" $label_" + label);
|
||||||
|
writeBlockType(type);
|
||||||
|
writer.indent().eol();
|
||||||
|
return label;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void startCatch(int tagIndex) {
|
||||||
|
writer.outdent().address();
|
||||||
|
writer.write("catch ").write(String.valueOf(tagIndex)).indent().eol();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void endBlock(int token, boolean loop) {
|
||||||
|
writer.address().outdent().write("end (; $label_" + token + " ;)").eol();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void branch(BranchOpcode opcode, int depth, int target) {
|
||||||
|
writer.address();
|
||||||
|
switch (opcode) {
|
||||||
|
case BR:
|
||||||
|
writer.write("br");
|
||||||
|
break;
|
||||||
|
case BR_IF:
|
||||||
|
writer.write("br_if");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
writer.write(" $label_" + target).eol();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void tableBranch(int[] depths, int[] targets, int defaultDepth, int defaultTarget) {
|
||||||
|
writer.address();
|
||||||
|
writer.write("br_table");
|
||||||
|
for (var target : targets) {
|
||||||
|
writer.write(" $label_" + target);
|
||||||
|
}
|
||||||
|
writer.write(" $label_" + defaultTarget).eol();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void throwInstruction(int tagIndex) {
|
||||||
|
writer.address();
|
||||||
|
writer.write("throw ").write(String.valueOf(tagIndex)).eol();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void opcode(Opcode opcode) {
|
||||||
|
writer.address();
|
||||||
|
switch (opcode) {
|
||||||
|
case UNREACHABLE:
|
||||||
|
writer.write("unreachable");
|
||||||
|
break;
|
||||||
|
case NOP:
|
||||||
|
writer.write("nop");
|
||||||
|
break;
|
||||||
|
case RETURN:
|
||||||
|
writer.write("return");
|
||||||
|
break;
|
||||||
|
case DROP:
|
||||||
|
writer.write("drop");
|
||||||
|
break;
|
||||||
|
case REF_EQ:
|
||||||
|
writer.write("ref.eq");
|
||||||
|
break;
|
||||||
|
case ARRAY_LENGTH:
|
||||||
|
writer.write("array.length");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
writer.eol();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void local(LocalOpcode opcode, int index) {
|
||||||
|
writer.address();
|
||||||
|
switch (opcode) {
|
||||||
|
case GET:
|
||||||
|
writer.write("local.get");
|
||||||
|
break;
|
||||||
|
case SET:
|
||||||
|
writer.write("local.set");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
writer.write(" ");
|
||||||
|
writeLocalRef(currentFunctionId, index);
|
||||||
|
writer.eol();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void getGlobal(int globalIndex) {
|
||||||
|
writer.address().write("global.get ");
|
||||||
|
writeGlobalRef(globalIndex);
|
||||||
|
writer.eol();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setGlobal(int globalIndex) {
|
||||||
|
writer.address().write("global.set ");
|
||||||
|
writeGlobalRef(globalIndex);
|
||||||
|
writer.eol();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void call(int functionIndex) {
|
||||||
|
writer.address();
|
||||||
|
writer.write("call ");
|
||||||
|
writeFunctionRef(functionIndex);
|
||||||
|
writer.eol();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void indirectCall(int typeIndex, int tableIndex) {
|
||||||
|
writer.address();
|
||||||
|
writer.write("call_indirect " + tableIndex + " " + typeIndex).eol();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void callReference(int typeIndex) {
|
||||||
|
writer.address();
|
||||||
|
writer.write("call_ref " + typeIndex).eol();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void loadInt32(WasmInt32Subtype convertFrom, int align, int offset) {
|
||||||
|
writer.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();
|
||||||
|
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();
|
||||||
|
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();
|
||||||
|
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().write("f32.load");
|
||||||
|
writeMemArg(align, 4, offset);
|
||||||
|
writer.eol();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void storeFloat32(int align, int offset) {
|
||||||
|
writer.address().write("f32.store");
|
||||||
|
writeMemArg(align, 4, offset);
|
||||||
|
writer.eol();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void loadFloat64(int align, int offset) {
|
||||||
|
writer.address().write("f64.load");
|
||||||
|
writeMemArg(align, 8, offset);
|
||||||
|
writer.eol();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void storeFloat64(int align, int offset) {
|
||||||
|
writer.address().write("f64.store");
|
||||||
|
writeMemArg(align, 8, offset);
|
||||||
|
writer.eol();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void memoryGrow() {
|
||||||
|
writer.address().write("memory.grow").eol();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void memoryFill() {
|
||||||
|
writer.address().write("memory.fill").eol();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void memoryCopy() {
|
||||||
|
writer.address().write("memory.copy").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();
|
||||||
|
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 EQZ:
|
||||||
|
writer.write("eqz");
|
||||||
|
break;
|
||||||
|
case POPCNT:
|
||||||
|
writer.write("popcnt");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
writer.eol();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void unary(WasmFloatUnaryOperation opcode, WasmFloatType type) {
|
||||||
|
writer.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();
|
||||||
|
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();
|
||||||
|
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(WasmNumType sourceType, WasmNumType 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
|
||||||
|
public void int32Constant(int value) {
|
||||||
|
writer.address().write("i32.const " + value).eol();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void int64Constant(long value) {
|
||||||
|
writer.address().write("i64.const " + value).eol();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void float32Constant(float value) {
|
||||||
|
writer.address().write("f32.const " + Float.toHexString(value)).eol();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void float64Constant(double value) {
|
||||||
|
writer.address().write("f64.const " + Double.toHexString(value)).eol();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void nullConstant(WasmHollowType.Reference type) {
|
||||||
|
writer.address().write("ref.null ");
|
||||||
|
writeType(type);
|
||||||
|
writer.eol();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void cast(WasmHollowType.Reference type, boolean nullable) {
|
||||||
|
writer.address().write("ref.cast (ref ");
|
||||||
|
if (!nullable) {
|
||||||
|
writer.write("null ");
|
||||||
|
}
|
||||||
|
writeType(type);
|
||||||
|
writer.write(")").eol();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void test(WasmHollowType.Reference type, boolean nullable) {
|
||||||
|
writer.address().write("ref.test (ref ");
|
||||||
|
if (!nullable) {
|
||||||
|
writer.write("null ");
|
||||||
|
}
|
||||||
|
writeType(type);
|
||||||
|
writer.write(")").eol();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void structNew(int typeIndex) {
|
||||||
|
writer.address().write("struct.new ");
|
||||||
|
writeTypeRef(typeIndex);
|
||||||
|
writer.eol();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void structNewDefault(int typeIndex) {
|
||||||
|
writer.address().write("struct.new_default ");
|
||||||
|
writeTypeRef(typeIndex);
|
||||||
|
writer.eol();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void structGet(WasmSignedType signedType, int typeIndex, int fieldIndex) {
|
||||||
|
writer.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(" ");
|
||||||
|
writeTypeRef(typeIndex);
|
||||||
|
writer.write(" ");
|
||||||
|
writeFieldRef(typeIndex, fieldIndex);
|
||||||
|
writer.eol();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void structSet(int typeIndex, int fieldIndex) {
|
||||||
|
writer.address().write("struct.set ");
|
||||||
|
writeTypeRef(typeIndex);
|
||||||
|
writer.write(" ");
|
||||||
|
writeFieldRef(typeIndex, fieldIndex);
|
||||||
|
writer.eol();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void arrayNewDefault(int typeIndex) {
|
||||||
|
writer.address().write("array.new_default ");
|
||||||
|
writeTypeRef(typeIndex);
|
||||||
|
writer.eol();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void arrayGet(WasmSignedType signedType, int typeIndex) {
|
||||||
|
writer.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(" ");
|
||||||
|
writeTypeRef(typeIndex);
|
||||||
|
writer.eol();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void arraySet(int typeIndex) {
|
||||||
|
writer.address().write("array.set ");
|
||||||
|
writeTypeRef(typeIndex);
|
||||||
|
writer.eol();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void functionReference(int functionIndex) {
|
||||||
|
writer.address().write("ref.func ");
|
||||||
|
writeFunctionRef(functionIndex);
|
||||||
|
writer.eol();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void int31Reference() {
|
||||||
|
writer.address().write("ref.i31").eol();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void int31Get(WasmSignedType signedType) {
|
||||||
|
writer.address().write("ref.i31_").write(signedType == WasmSignedType.SIGNED ? "s" : "u").eol();
|
||||||
|
}
|
||||||
|
}
|
|
@ -15,37 +15,23 @@
|
||||||
*/
|
*/
|
||||||
package org.teavm.backend.wasm.disasm;
|
package org.teavm.backend.wasm.disasm;
|
||||||
|
|
||||||
import org.teavm.backend.wasm.model.WasmNumType;
|
|
||||||
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.model.expression.WasmSignedType;
|
|
||||||
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.CodeListener;
|
||||||
import org.teavm.backend.wasm.parser.CodeSectionListener;
|
import org.teavm.backend.wasm.parser.CodeSectionListener;
|
||||||
import org.teavm.backend.wasm.parser.LocalOpcode;
|
|
||||||
import org.teavm.backend.wasm.parser.Opcode;
|
|
||||||
import org.teavm.backend.wasm.parser.WasmHollowType;
|
import org.teavm.backend.wasm.parser.WasmHollowType;
|
||||||
|
|
||||||
public class DisassemblyCodeSectionListener extends BaseDisassemblyListener implements AddressListener,
|
public class DisassemblyCodeSectionListener extends BaseDisassemblyListener implements CodeSectionListener {
|
||||||
CodeSectionListener, CodeListener {
|
|
||||||
private int blockIdGen;
|
|
||||||
private int currentFunctionId;
|
private int currentFunctionId;
|
||||||
|
private DisassemblyCodeListener codeListener;
|
||||||
|
|
||||||
public DisassemblyCodeSectionListener(DisassemblyWriter writer, NameProvider nameProvider) {
|
public DisassemblyCodeSectionListener(DisassemblyWriter writer, NameProvider nameProvider) {
|
||||||
super(writer, nameProvider);
|
super(writer, nameProvider);
|
||||||
|
codeListener = new DisassemblyCodeListener(writer, nameProvider);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean functionStart(int index, int size) {
|
public boolean functionStart(int index, int size) {
|
||||||
currentFunctionId = index;
|
currentFunctionId = index;
|
||||||
writer.address(address).write("(func ").write("(; " + index + " ;)");
|
writer.address().write("(func ").write("(; " + index + " ;)");
|
||||||
var name = nameProvider.function(index);
|
var name = nameProvider.function(index);
|
||||||
if (name != null) {
|
if (name != null) {
|
||||||
writer.write(" $").write(name);
|
writer.write(" $").write(name);
|
||||||
|
@ -56,12 +42,12 @@ public class DisassemblyCodeSectionListener extends BaseDisassemblyListener impl
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void localsStart(int count) {
|
public void localsStart(int count) {
|
||||||
writer.address(address).write("(; locals " + count + " ;)").eol();
|
writer.address().write("(; locals " + count + " ;)").eol();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void local(int start, int count, WasmHollowType type) {
|
public void local(int start, int count, WasmHollowType type) {
|
||||||
writer.address(address);
|
writer.address();
|
||||||
for (int i = 0; i < count; ++i) {
|
for (int i = 0; i < count; ++i) {
|
||||||
writer.write("(local (; " + (i + start) + " ;) ");
|
writer.write("(local (; " + (i + start) + " ;) ");
|
||||||
var name = nameProvider.local(currentFunctionId, i + start);
|
var name = nameProvider.local(currentFunctionId, i + start);
|
||||||
|
@ -75,8 +61,8 @@ public class DisassemblyCodeSectionListener extends BaseDisassemblyListener impl
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public CodeListener code() {
|
public CodeListener code() {
|
||||||
blockIdGen = 0;
|
codeListener.setCurrentFunctionId(currentFunctionId);
|
||||||
return this;
|
return codeListener;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -88,809 +74,4 @@ public class DisassemblyCodeSectionListener extends BaseDisassemblyListener impl
|
||||||
public void sectionEnd() {
|
public void sectionEnd() {
|
||||||
writer.outdent().write(")").eol();
|
writer.outdent().write(")").eol();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void error(int depth) {
|
|
||||||
writer.address(address);
|
|
||||||
writer.write("error").eol();
|
|
||||||
for (int i = 0; i < depth; ++i) {
|
|
||||||
writer.outdent();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int startBlock(boolean loop, WasmHollowType type) {
|
|
||||||
writer.address(address);
|
|
||||||
var label = blockIdGen++;
|
|
||||||
writer.write(loop ? "loop" : "block").write(" $label_" + label);
|
|
||||||
writeBlockType(type);
|
|
||||||
writer.indent().eol();
|
|
||||||
return label;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int startConditionalBlock(WasmHollowType type) {
|
|
||||||
writer.address(address);
|
|
||||||
var label = blockIdGen++;
|
|
||||||
writer.write("if ").write(" $label_" + label);
|
|
||||||
writeBlockType(type);
|
|
||||||
writer.indent().eol();
|
|
||||||
return label;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void startElseSection(int token) {
|
|
||||||
writer.address(address);
|
|
||||||
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);
|
|
||||||
writeBlockType(type);
|
|
||||||
writer.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();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void branch(BranchOpcode opcode, int depth, int target) {
|
|
||||||
writer.address(address);
|
|
||||||
switch (opcode) {
|
|
||||||
case BR:
|
|
||||||
writer.write("br");
|
|
||||||
break;
|
|
||||||
case BR_IF:
|
|
||||||
writer.write("br_if");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
writer.write(" $label_" + target).eol();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void tableBranch(int[] depths, int[] targets, int defaultDepth, int defaultTarget) {
|
|
||||||
writer.address(address);
|
|
||||||
writer.write("br_table");
|
|
||||||
for (var target : targets) {
|
|
||||||
writer.write(" $label_" + target);
|
|
||||||
}
|
|
||||||
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);
|
|
||||||
switch (opcode) {
|
|
||||||
case UNREACHABLE:
|
|
||||||
writer.write("unreachable");
|
|
||||||
break;
|
|
||||||
case NOP:
|
|
||||||
writer.write("nop");
|
|
||||||
break;
|
|
||||||
case RETURN:
|
|
||||||
writer.write("return");
|
|
||||||
break;
|
|
||||||
case DROP:
|
|
||||||
writer.write("drop");
|
|
||||||
break;
|
|
||||||
case REF_EQ:
|
|
||||||
writer.write("ref.eq");
|
|
||||||
break;
|
|
||||||
case ARRAY_LENGTH:
|
|
||||||
writer.write("array.length");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
writer.eol();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void local(LocalOpcode opcode, int index) {
|
|
||||||
writer.address(address);
|
|
||||||
switch (opcode) {
|
|
||||||
case GET:
|
|
||||||
writer.write("local.get");
|
|
||||||
break;
|
|
||||||
case SET:
|
|
||||||
writer.write("local.set");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
writer.write(" ");
|
|
||||||
writeLocalRef(currentFunctionId, index);
|
|
||||||
writer.eol();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void getGlobal(int globalIndex) {
|
|
||||||
writer.address(address).write("global.get ");
|
|
||||||
writeGlobalRef(globalIndex);
|
|
||||||
writer.eol();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setGlobal(int globalIndex) {
|
|
||||||
writer.address(address).write("global.set ");
|
|
||||||
writeGlobalRef(globalIndex);
|
|
||||||
writer.eol();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void call(int functionIndex) {
|
|
||||||
writer.address(address);
|
|
||||||
writer.write("call ");
|
|
||||||
writeFunctionRef(functionIndex);
|
|
||||||
writer.eol();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void indirectCall(int typeIndex, int tableIndex) {
|
|
||||||
writer.address(address);
|
|
||||||
writer.write("call_indirect " + tableIndex + " " + typeIndex).eol();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void callReference(int typeIndex) {
|
|
||||||
writer.address(address);
|
|
||||||
writer.write("call_ref " + 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();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void memoryFill() {
|
|
||||||
writer.address(address).write("memory.fill").eol();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void memoryCopy() {
|
|
||||||
writer.address(address).write("memory.copy").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 EQZ:
|
|
||||||
writer.write("eqz");
|
|
||||||
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(WasmNumType sourceType, WasmNumType 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
|
|
||||||
public void int32Constant(int value) {
|
|
||||||
writer.address(address).write("i32.const " + value).eol();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void int64Constant(long value) {
|
|
||||||
writer.address(address).write("i64.const " + value).eol();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void float32Constant(float value) {
|
|
||||||
writer.address(address).write("f32.const " + Float.toHexString(value)).eol();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void float64Constant(double value) {
|
|
||||||
writer.address(address).write("f64.const " + Double.toHexString(value)).eol();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void nullConstant(WasmHollowType.Reference type) {
|
|
||||||
writer.address(address).write("ref.null ");
|
|
||||||
writeType(type);
|
|
||||||
writer.eol();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void cast(WasmHollowType.Reference type, boolean nullable) {
|
|
||||||
writer.address(address).write("ref.cast (ref ");
|
|
||||||
if (!nullable) {
|
|
||||||
writer.write("null ");
|
|
||||||
}
|
|
||||||
writeType(type);
|
|
||||||
writer.write(")").eol();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void test(WasmHollowType.Reference type, boolean nullable) {
|
|
||||||
writer.address(address).write("ref.test (ref ");
|
|
||||||
if (!nullable) {
|
|
||||||
writer.write("null ");
|
|
||||||
}
|
|
||||||
writeType(type);
|
|
||||||
writer.write(")").eol();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void structNew(int typeIndex) {
|
|
||||||
writer.address(address).write("struct.new ");
|
|
||||||
writeTypeRef(typeIndex);
|
|
||||||
writer.eol();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void structNewDefault(int typeIndex) {
|
|
||||||
writer.address(address).write("struct.new_default ");
|
|
||||||
writeTypeRef(typeIndex);
|
|
||||||
writer.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(" ");
|
|
||||||
writeTypeRef(typeIndex);
|
|
||||||
writer.write(" ");
|
|
||||||
writeFieldRef(typeIndex, fieldIndex);
|
|
||||||
writer.eol();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void structSet(int typeIndex, int fieldIndex) {
|
|
||||||
writer.address(address).write("struct.set ");
|
|
||||||
writeTypeRef(typeIndex);
|
|
||||||
writer.write(" ");
|
|
||||||
writeFieldRef(typeIndex, fieldIndex);
|
|
||||||
writer.eol();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void arrayNewDefault(int typeIndex) {
|
|
||||||
writer.address(address).write("array.new_default ");
|
|
||||||
writeTypeRef(typeIndex);
|
|
||||||
writer.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(" ");
|
|
||||||
writeTypeRef(typeIndex);
|
|
||||||
writer.eol();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void arraySet(int typeIndex) {
|
|
||||||
writer.address(address).write("array.set ");
|
|
||||||
writeTypeRef(typeIndex);
|
|
||||||
writer.eol();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void functionReference(int functionIndex) {
|
|
||||||
writer.address(address).write("ref.func ");
|
|
||||||
writeFunctionRef(functionIndex);
|
|
||||||
writer.eol();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void int31Reference() {
|
|
||||||
writer.address(address).write("ref.i31").eol();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void int31Get(WasmSignedType signedType) {
|
|
||||||
writer.address(address).write("ref.i31_").write(signedType == WasmSignedType.SIGNED ? "s" : "u").eol();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,52 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2024 Alexey Andreev.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package org.teavm.backend.wasm.disasm;
|
||||||
|
|
||||||
|
import org.teavm.backend.wasm.parser.CodeListener;
|
||||||
|
import org.teavm.backend.wasm.parser.GlobalSectionListener;
|
||||||
|
import org.teavm.backend.wasm.parser.WasmHollowType;
|
||||||
|
|
||||||
|
public class DisassemblyGlobalSectionListener extends BaseDisassemblyListener implements GlobalSectionListener {
|
||||||
|
private DisassemblyCodeListener codeListener;
|
||||||
|
|
||||||
|
public DisassemblyGlobalSectionListener(DisassemblyWriter writer, NameProvider nameProvider) {
|
||||||
|
super(writer, nameProvider);
|
||||||
|
codeListener = new DisassemblyCodeListener(writer, nameProvider);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public CodeListener startGlobal(int index, WasmHollowType type, boolean mutable) {
|
||||||
|
writer.address().write("(global (; ").write(String.valueOf(index)).write(" ;) ");
|
||||||
|
var name = nameProvider.global(index);
|
||||||
|
if (name != null) {
|
||||||
|
writer.write("$").write(name).write(" ");
|
||||||
|
}
|
||||||
|
if (mutable) {
|
||||||
|
writer.write("(mut ");
|
||||||
|
writeType(type);
|
||||||
|
writer.write(")");
|
||||||
|
} else {
|
||||||
|
writeType(type);
|
||||||
|
}
|
||||||
|
writer.indent().eol();
|
||||||
|
return codeListener;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void endGlobal() {
|
||||||
|
writer.outdent().write(")").eol();
|
||||||
|
}
|
||||||
|
}
|
|
@ -15,13 +15,11 @@
|
||||||
*/
|
*/
|
||||||
package org.teavm.backend.wasm.disasm;
|
package org.teavm.backend.wasm.disasm;
|
||||||
|
|
||||||
import org.teavm.backend.wasm.parser.AddressListener;
|
|
||||||
import org.teavm.backend.wasm.parser.TypeSectionListener;
|
import org.teavm.backend.wasm.parser.TypeSectionListener;
|
||||||
import org.teavm.backend.wasm.parser.WasmHollowStorageType;
|
import org.teavm.backend.wasm.parser.WasmHollowStorageType;
|
||||||
import org.teavm.backend.wasm.parser.WasmHollowType;
|
import org.teavm.backend.wasm.parser.WasmHollowType;
|
||||||
|
|
||||||
public class DisassemblyTypeSectionListener extends BaseDisassemblyListener implements AddressListener,
|
public class DisassemblyTypeSectionListener extends BaseDisassemblyListener implements TypeSectionListener {
|
||||||
TypeSectionListener {
|
|
||||||
private boolean currentTypeNeedsClosing;
|
private boolean currentTypeNeedsClosing;
|
||||||
private boolean emittingReturn;
|
private boolean emittingReturn;
|
||||||
private int currentTypeIndex;
|
private int currentTypeIndex;
|
||||||
|
@ -34,7 +32,7 @@ public class DisassemblyTypeSectionListener extends BaseDisassemblyListener impl
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void startRecType(int count) {
|
public void startRecType(int count) {
|
||||||
writer.address(address).write("(rec ").indent().eol();
|
writer.address().write("(rec ").indent().eol();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -45,7 +43,7 @@ public class DisassemblyTypeSectionListener extends BaseDisassemblyListener impl
|
||||||
@Override
|
@Override
|
||||||
public void startType(int index, boolean open, int[] supertypes) {
|
public void startType(int index, boolean open, int[] supertypes) {
|
||||||
currentTypeIndex = index;
|
currentTypeIndex = index;
|
||||||
writer.address(address).write("(type (; ").write(String.valueOf(index)).write(" ;) ");
|
writer.address().write("(type (; ").write(String.valueOf(index)).write(" ;) ");
|
||||||
var name = nameProvider.type(index);
|
var name = nameProvider.type(index);
|
||||||
if (name != null) {
|
if (name != null) {
|
||||||
writer.write("$").write(name).write(" ");
|
writer.write("$").write(name).write(" ");
|
||||||
|
@ -65,7 +63,7 @@ public class DisassemblyTypeSectionListener extends BaseDisassemblyListener impl
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void startArrayType() {
|
public void startArrayType() {
|
||||||
writer.address(address).write("(array ").indent().eol();
|
writer.address().write("(array ").indent().eol();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -76,12 +74,12 @@ public class DisassemblyTypeSectionListener extends BaseDisassemblyListener impl
|
||||||
@Override
|
@Override
|
||||||
public void startStructType(int fieldCount) {
|
public void startStructType(int fieldCount) {
|
||||||
needsFieldIndex = true;
|
needsFieldIndex = true;
|
||||||
writer.address(address).write("(struct ").indent().eol();
|
writer.address().write("(struct ").indent().eol();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void field(WasmHollowStorageType hollowType, boolean mutable) {
|
public void field(WasmHollowStorageType hollowType, boolean mutable) {
|
||||||
writer.address(address).write("(field ");
|
writer.address().write("(field ");
|
||||||
if (needsFieldIndex) {
|
if (needsFieldIndex) {
|
||||||
writer.write("(; " + fieldIndex++ + " ;) ");
|
writer.write("(; " + fieldIndex++ + " ;) ");
|
||||||
var name = nameProvider.field(currentTypeIndex, fieldIndex);
|
var name = nameProvider.field(currentTypeIndex, fieldIndex);
|
||||||
|
@ -107,7 +105,7 @@ public class DisassemblyTypeSectionListener extends BaseDisassemblyListener impl
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void funcType(int paramCount) {
|
public void funcType(int paramCount) {
|
||||||
writer.address(address).write("(func ").indent().eol();
|
writer.address().write("(func ").indent().eol();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -117,7 +115,7 @@ public class DisassemblyTypeSectionListener extends BaseDisassemblyListener impl
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void resultType(WasmHollowType type) {
|
public void resultType(WasmHollowType type) {
|
||||||
writer.address(address).write("(").write(emittingReturn ? "result" : "param").write(" ");
|
writer.address().write("(").write(emittingReturn ? "result" : "param").write(" ");
|
||||||
writeType(type);
|
writeType(type);
|
||||||
writer.write(")").eol();
|
writer.write(")").eol();
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,6 +16,7 @@
|
||||||
package org.teavm.backend.wasm.disasm;
|
package org.teavm.backend.wasm.disasm;
|
||||||
|
|
||||||
import java.io.PrintWriter;
|
import java.io.PrintWriter;
|
||||||
|
import org.teavm.backend.wasm.parser.AddressListener;
|
||||||
|
|
||||||
public class DisassemblyWriter {
|
public class DisassemblyWriter {
|
||||||
private PrintWriter out;
|
private PrintWriter out;
|
||||||
|
@ -24,14 +25,18 @@ public class DisassemblyWriter {
|
||||||
private int address;
|
private int address;
|
||||||
private boolean hasAddress;
|
private boolean hasAddress;
|
||||||
private boolean lineStarted;
|
private boolean lineStarted;
|
||||||
|
private int addressOffset;
|
||||||
|
|
||||||
public DisassemblyWriter(PrintWriter out, boolean withAddress) {
|
public DisassemblyWriter(PrintWriter out, boolean withAddress) {
|
||||||
this.out = out;
|
this.out = out;
|
||||||
this.withAddress = withAddress;
|
this.withAddress = withAddress;
|
||||||
}
|
}
|
||||||
|
|
||||||
public DisassemblyWriter address(int address) {
|
public void setAddressOffset(int addressOffset) {
|
||||||
this.address = address;
|
this.addressOffset = addressOffset;
|
||||||
|
}
|
||||||
|
|
||||||
|
public DisassemblyWriter address() {
|
||||||
hasAddress = true;
|
hasAddress = true;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
@ -83,4 +88,11 @@ public class DisassemblyWriter {
|
||||||
out.print(s);
|
out.print(s);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public final AddressListener addressListener = new AddressListener() {
|
||||||
|
@Override
|
||||||
|
public void address(int address) {
|
||||||
|
DisassemblyWriter.this.address = address + addressOffset;
|
||||||
|
}
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,186 +15,53 @@
|
||||||
*/
|
*/
|
||||||
package org.teavm.backend.wasm.parser;
|
package org.teavm.backend.wasm.parser;
|
||||||
|
|
||||||
import java.nio.charset.StandardCharsets;
|
|
||||||
|
|
||||||
public abstract class BaseSectionParser {
|
public abstract class BaseSectionParser {
|
||||||
protected AddressListener addressListener;
|
protected WasmBinaryReader reader;
|
||||||
protected byte[] data;
|
|
||||||
protected int ptr;
|
|
||||||
private int lastReportedPtr = -1;
|
|
||||||
|
|
||||||
public BaseSectionParser(AddressListener addressListener) {
|
public void parse(AddressListener addressListener, byte[] data) {
|
||||||
this.addressListener = addressListener;
|
parse(new WasmBinaryReader(addressListener, data));
|
||||||
}
|
}
|
||||||
|
|
||||||
public void parse(byte[] data) {
|
public void parse(WasmBinaryReader reader) {
|
||||||
this.data = data;
|
this.reader = reader;
|
||||||
ptr = 0;
|
|
||||||
try {
|
try {
|
||||||
parseContent();
|
parseContent();
|
||||||
} finally {
|
} finally {
|
||||||
this.data = null;
|
this.reader = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected abstract void parseContent();
|
protected abstract void parseContent();
|
||||||
|
|
||||||
protected WasmHollowStorageType readStorageType() {
|
|
||||||
var typeId = data[ptr];
|
|
||||||
switch (typeId) {
|
|
||||||
case 0x78:
|
|
||||||
++ptr;
|
|
||||||
return WasmHollowStorageType.INT8;
|
|
||||||
case 0x77:
|
|
||||||
++ptr;
|
|
||||||
return WasmHollowStorageType.INT16;
|
|
||||||
default:
|
|
||||||
return new WasmHollowStorageType.Regular(readType());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected WasmHollowType readType() {
|
|
||||||
var typeId = data[ptr++];
|
|
||||||
switch (typeId) {
|
|
||||||
case 0x7F:
|
|
||||||
return WasmHollowType.INT32;
|
|
||||||
case 0x7E:
|
|
||||||
return WasmHollowType.INT64;
|
|
||||||
case 0x7D:
|
|
||||||
return WasmHollowType.FLOAT32;
|
|
||||||
case 0x7C:
|
|
||||||
return WasmHollowType.FLOAT64;
|
|
||||||
case 0x63:
|
|
||||||
return readHeapType();
|
|
||||||
case 0x40:
|
|
||||||
return null;
|
|
||||||
default:
|
|
||||||
return readAbsHeapType(typeId);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected WasmHollowType.Reference readHeapType() {
|
|
||||||
var typeId = data[ptr];
|
|
||||||
if ((typeId & 0xC0) == 0x40) {
|
|
||||||
var result = readAbsHeapType(typeId);
|
|
||||||
++ptr;
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
return new WasmHollowType.CompositeReference(readLEB());
|
|
||||||
}
|
|
||||||
|
|
||||||
protected 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 0x6C:
|
|
||||||
return WasmHollowType.Reference.I31;
|
|
||||||
case 0x6B:
|
|
||||||
return WasmHollowType.Reference.STRUCT;
|
|
||||||
case 0x6A:
|
|
||||||
return WasmHollowType.Reference.ARRAY;
|
|
||||||
default:
|
|
||||||
throw new ParseException("Unknown type", ptr);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void reportAddress() {
|
protected void reportAddress() {
|
||||||
if (ptr != lastReportedPtr) {
|
reader.reportAddress();
|
||||||
lastReportedPtr = ptr;
|
|
||||||
if (addressListener != null) {
|
|
||||||
addressListener.address(ptr);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected int readSignedLEB() {
|
protected int readSignedLEB() {
|
||||||
var result = 0;
|
return reader.readSignedLEB();
|
||||||
var shift = 0;
|
|
||||||
while (true) {
|
|
||||||
var digit = data[ptr++];
|
|
||||||
result |= (digit & 0x7F) << shift;
|
|
||||||
if ((digit & 0x80) == 0) {
|
|
||||||
if ((digit & 0x40) != 0) {
|
|
||||||
result |= -1 << (shift + 7);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
shift += 7;
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected int readLEB() {
|
protected int readLEB() {
|
||||||
var result = 0;
|
return reader.readLEB();
|
||||||
var shift = 0;
|
|
||||||
while (true) {
|
|
||||||
var digit = data[ptr++];
|
|
||||||
result |= (digit & 0x7F) << shift;
|
|
||||||
if ((digit & 0x80) == 0) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
shift += 7;
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected long readSignedLongLEB() {
|
protected long readSignedLongLEB() {
|
||||||
var result = 0L;
|
return reader.readSignedLongLEB();
|
||||||
var shift = 0;
|
|
||||||
while (true) {
|
|
||||||
var digit = data[ptr++];
|
|
||||||
result |= (digit & 0x7FL) << shift;
|
|
||||||
if ((digit & 0x80) == 0) {
|
|
||||||
if ((digit & 0x40) != 0) {
|
|
||||||
result |= -1L << (shift + 7);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
shift += 7;
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected long readLongLEB() {
|
protected long readLongLEB() {
|
||||||
var result = 0L;
|
return reader.readLongLEB();
|
||||||
var shift = 0;
|
|
||||||
while (true) {
|
|
||||||
var digit = data[ptr++];
|
|
||||||
result |= (digit & 0x7FL) << shift;
|
|
||||||
if ((digit & 0x80) == 0) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
shift += 7;
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected int readFixedInt() {
|
protected int readFixedInt() {
|
||||||
return ((data[ptr++] & 0xFF) << 24)
|
return reader.readFixedInt();
|
||||||
| ((data[ptr++] & 0xFF) << 16)
|
|
||||||
| ((data[ptr++] & 0xFF) << 8)
|
|
||||||
| (data[ptr++] & 0xFF);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected long readFixedLong() {
|
protected long readFixedLong() {
|
||||||
return ((data[ptr++] & 0xFFL) << 56)
|
return reader.readFixedLong();
|
||||||
| ((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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected String readString() {
|
protected String readString() {
|
||||||
var size = readLEB();
|
return reader.readString();
|
||||||
var result = new String(data, ptr, size, StandardCharsets.UTF_8);
|
|
||||||
ptr += size;
|
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -182,4 +182,7 @@ public interface CodeListener {
|
||||||
|
|
||||||
default void int31Get(WasmSignedType signedType) {
|
default void int31Get(WasmSignedType signedType) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
CodeListener EMPTY = new CodeListener() {
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
824
core/src/main/java/org/teavm/backend/wasm/parser/CodeParser.java
Normal file
824
core/src/main/java/org/teavm/backend/wasm/parser/CodeParser.java
Normal file
|
@ -0,0 +1,824 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2024 Alexey Andreev.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package org.teavm.backend.wasm.parser;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import org.teavm.backend.wasm.model.WasmNumType;
|
||||||
|
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.model.expression.WasmSignedType;
|
||||||
|
|
||||||
|
public class CodeParser extends BaseSectionParser {
|
||||||
|
private CodeListener codeListener;
|
||||||
|
private final List<Block> blockStack = new ArrayList<>();
|
||||||
|
private int functionIndexOffset;
|
||||||
|
|
||||||
|
public void setCodeListener(CodeListener codeListener) {
|
||||||
|
this.codeListener = codeListener;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setFunctionIndexOffset(int functionIndexOffset) {
|
||||||
|
this.functionIndexOffset = functionIndexOffset;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void parseContent() {
|
||||||
|
parseCode();
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean parseSingleExpression(WasmBinaryReader reader) {
|
||||||
|
this.reader = reader;
|
||||||
|
try {
|
||||||
|
return parseExpressions();
|
||||||
|
} finally {
|
||||||
|
this.reader = reader;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void parseCode() {
|
||||||
|
if (!parseExpressions()) {
|
||||||
|
codeListener.error(blockStack.size());
|
||||||
|
blockStack.clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean parseExpressions() {
|
||||||
|
while (reader.data[reader.ptr] != 0x0B) {
|
||||||
|
if (!parseExpr()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean parseExpr() {
|
||||||
|
reportAddress();
|
||||||
|
switch (reader.data[reader.ptr++] & 0xFF) {
|
||||||
|
case 0x00:
|
||||||
|
codeListener.opcode(Opcode.UNREACHABLE);
|
||||||
|
break;
|
||||||
|
case 0x01:
|
||||||
|
codeListener.opcode(Opcode.NOP);
|
||||||
|
break;
|
||||||
|
case 0x02:
|
||||||
|
return parseBlock(false);
|
||||||
|
case 0x03:
|
||||||
|
return parseBlock(true);
|
||||||
|
case 0x04:
|
||||||
|
return parseConditional();
|
||||||
|
case 0x06:
|
||||||
|
return parseTryCatch();
|
||||||
|
case 0x8:
|
||||||
|
codeListener.throwInstruction(readLEB());
|
||||||
|
break;
|
||||||
|
case 0x0C:
|
||||||
|
parseBranch(BranchOpcode.BR);
|
||||||
|
break;
|
||||||
|
case 0x0D:
|
||||||
|
parseBranch(BranchOpcode.BR_IF);
|
||||||
|
break;
|
||||||
|
case 0x0E:
|
||||||
|
parseTableBranch();
|
||||||
|
break;
|
||||||
|
case 0x0F:
|
||||||
|
codeListener.opcode(Opcode.RETURN);
|
||||||
|
break;
|
||||||
|
case 0x10:
|
||||||
|
codeListener.call(readLEB() + functionIndexOffset);
|
||||||
|
break;
|
||||||
|
case 0x11:
|
||||||
|
codeListener.indirectCall(readLEB(), readLEB());
|
||||||
|
break;
|
||||||
|
case 0x14:
|
||||||
|
codeListener.callReference(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 0x23:
|
||||||
|
codeListener.getGlobal(readLEB());
|
||||||
|
break;
|
||||||
|
case 0x24:
|
||||||
|
codeListener.setGlobal(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;
|
||||||
|
case 0x42:
|
||||||
|
codeListener.int64Constant(readSignedLongLEB());
|
||||||
|
break;
|
||||||
|
case 0x43:
|
||||||
|
codeListener.float32Constant(Float.intBitsToFloat(readFixedInt()));
|
||||||
|
break;
|
||||||
|
case 0x44:
|
||||||
|
codeListener.float64Constant(Double.longBitsToDouble(readFixedLong()));
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0x45:
|
||||||
|
codeListener.unary(WasmIntUnaryOperation.EQZ, WasmIntType.INT32);
|
||||||
|
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 0x50:
|
||||||
|
codeListener.unary(WasmIntUnaryOperation.EQZ, WasmIntType.INT64);
|
||||||
|
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(WasmNumType.INT64, WasmNumType.INT32, false, false);
|
||||||
|
break;
|
||||||
|
case 0xA8:
|
||||||
|
codeListener.convert(WasmNumType.FLOAT32, WasmNumType.INT32, false, false);
|
||||||
|
break;
|
||||||
|
case 0xA9:
|
||||||
|
codeListener.convert(WasmNumType.FLOAT32, WasmNumType.INT32, true, false);
|
||||||
|
break;
|
||||||
|
case 0xAA:
|
||||||
|
codeListener.convert(WasmNumType.FLOAT64, WasmNumType.INT32, false, false);
|
||||||
|
break;
|
||||||
|
case 0xAB:
|
||||||
|
codeListener.convert(WasmNumType.FLOAT64, WasmNumType.INT32, true, false);
|
||||||
|
break;
|
||||||
|
case 0xAC:
|
||||||
|
codeListener.convert(WasmNumType.INT32, WasmNumType.INT64, false, false);
|
||||||
|
break;
|
||||||
|
case 0xAD:
|
||||||
|
codeListener.convert(WasmNumType.INT32, WasmNumType.INT64, true, false);
|
||||||
|
break;
|
||||||
|
case 0xAE:
|
||||||
|
codeListener.convert(WasmNumType.FLOAT32, WasmNumType.INT64, false, false);
|
||||||
|
break;
|
||||||
|
case 0xAF:
|
||||||
|
codeListener.convert(WasmNumType.FLOAT32, WasmNumType.INT64, true, false);
|
||||||
|
break;
|
||||||
|
case 0xB0:
|
||||||
|
codeListener.convert(WasmNumType.FLOAT64, WasmNumType.INT64, false, false);
|
||||||
|
break;
|
||||||
|
case 0xB1:
|
||||||
|
codeListener.convert(WasmNumType.FLOAT64, WasmNumType.INT64, true, false);
|
||||||
|
break;
|
||||||
|
case 0xB2:
|
||||||
|
codeListener.convert(WasmNumType.INT32, WasmNumType.FLOAT32, false, false);
|
||||||
|
break;
|
||||||
|
case 0xB3:
|
||||||
|
codeListener.convert(WasmNumType.INT32, WasmNumType.FLOAT32, true, false);
|
||||||
|
break;
|
||||||
|
case 0xB4:
|
||||||
|
codeListener.convert(WasmNumType.INT64, WasmNumType.FLOAT32, false, false);
|
||||||
|
break;
|
||||||
|
case 0xB5:
|
||||||
|
codeListener.convert(WasmNumType.INT64, WasmNumType.FLOAT32, true, false);
|
||||||
|
break;
|
||||||
|
case 0xB6:
|
||||||
|
codeListener.convert(WasmNumType.FLOAT64, WasmNumType.FLOAT32, true, false);
|
||||||
|
break;
|
||||||
|
case 0xB7:
|
||||||
|
codeListener.convert(WasmNumType.INT32, WasmNumType.FLOAT64, false, false);
|
||||||
|
break;
|
||||||
|
case 0xB8:
|
||||||
|
codeListener.convert(WasmNumType.INT32, WasmNumType.FLOAT64, true, false);
|
||||||
|
break;
|
||||||
|
case 0xB9:
|
||||||
|
codeListener.convert(WasmNumType.INT64, WasmNumType.FLOAT64, false, false);
|
||||||
|
break;
|
||||||
|
case 0xBA:
|
||||||
|
codeListener.convert(WasmNumType.INT64, WasmNumType.FLOAT64, true, false);
|
||||||
|
break;
|
||||||
|
case 0xBC:
|
||||||
|
codeListener.convert(WasmNumType.FLOAT32, WasmNumType.INT32, false, true);
|
||||||
|
break;
|
||||||
|
case 0xBD:
|
||||||
|
codeListener.convert(WasmNumType.FLOAT64, WasmNumType.INT64, false, true);
|
||||||
|
break;
|
||||||
|
case 0xBE:
|
||||||
|
codeListener.convert(WasmNumType.INT32, WasmNumType.FLOAT32, false, true);
|
||||||
|
break;
|
||||||
|
case 0xBF:
|
||||||
|
codeListener.convert(WasmNumType.INT64, WasmNumType.FLOAT64, false, true);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0xD0:
|
||||||
|
codeListener.nullConstant(reader.readHeapType());
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0xD2:
|
||||||
|
codeListener.functionReference(readLEB() + functionIndexOffset);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0xD3:
|
||||||
|
codeListener.opcode(Opcode.REF_EQ);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0xFB:
|
||||||
|
return parseExtExpr2();
|
||||||
|
case 0xFC:
|
||||||
|
return parseExtExpr();
|
||||||
|
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean parseExtExpr() {
|
||||||
|
switch (readLEB()) {
|
||||||
|
case 10: {
|
||||||
|
if (reader.data[reader.ptr++] != 0 || reader.data[reader.ptr++] != 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
codeListener.memoryCopy();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
case 11: {
|
||||||
|
if (reader.data[reader.ptr++] != 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
codeListener.memoryFill();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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 17:
|
||||||
|
codeListener.arrayCopy(readLEB(), readLEB());
|
||||||
|
return true;
|
||||||
|
|
||||||
|
case 20:
|
||||||
|
codeListener.test(reader.readHeapType(), false);
|
||||||
|
return true;
|
||||||
|
|
||||||
|
case 21:
|
||||||
|
codeListener.test(reader.readHeapType(), true);
|
||||||
|
return true;
|
||||||
|
|
||||||
|
case 22:
|
||||||
|
codeListener.cast(reader.readHeapType(), false);
|
||||||
|
return true;
|
||||||
|
|
||||||
|
case 23:
|
||||||
|
codeListener.cast(reader.readHeapType(), true);
|
||||||
|
return true;
|
||||||
|
|
||||||
|
case 28:
|
||||||
|
codeListener.int31Reference();
|
||||||
|
return true;
|
||||||
|
|
||||||
|
case 29:
|
||||||
|
codeListener.int31Get(WasmSignedType.SIGNED);
|
||||||
|
return true;
|
||||||
|
case 30:
|
||||||
|
codeListener.int31Get(WasmSignedType.UNSIGNED);
|
||||||
|
return true;
|
||||||
|
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean parseBlock(boolean isLoop) {
|
||||||
|
var type = reader.readType();
|
||||||
|
var token = codeListener.startBlock(isLoop, type);
|
||||||
|
blockStack.add(new Block(token));
|
||||||
|
if (!parseExpressions()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
blockStack.remove(blockStack.size() - 1);
|
||||||
|
reportAddress();
|
||||||
|
codeListener.endBlock(token, isLoop);
|
||||||
|
++reader.ptr;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean parseConditional() {
|
||||||
|
var type = reader.readType();
|
||||||
|
var token = codeListener.startConditionalBlock(type);
|
||||||
|
blockStack.add(new Block(token));
|
||||||
|
var hasElse = false;
|
||||||
|
loop: while (true) {
|
||||||
|
switch (reader.data[reader.ptr]) {
|
||||||
|
case 0x0B:
|
||||||
|
break loop;
|
||||||
|
case 0x05:
|
||||||
|
if (hasElse) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
reportAddress();
|
||||||
|
codeListener.startElseSection(blockStack.get(blockStack.size() - 1).token);
|
||||||
|
++reader.ptr;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
if (!parseExpr()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
blockStack.remove(blockStack.size() - 1);
|
||||||
|
reportAddress();
|
||||||
|
codeListener.endBlock(token, false);
|
||||||
|
++reader.ptr;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean parseTryCatch() {
|
||||||
|
var type = reader.readType();
|
||||||
|
var token = codeListener.startTry(type);
|
||||||
|
blockStack.add(new Block(token));
|
||||||
|
loop: while (true) {
|
||||||
|
switch (reader.data[reader.ptr]) {
|
||||||
|
case 0x0B:
|
||||||
|
break loop;
|
||||||
|
case 0x07: {
|
||||||
|
reportAddress();
|
||||||
|
var tagIndex = readLEB();
|
||||||
|
++reader.ptr;
|
||||||
|
codeListener.startCatch(tagIndex);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
if (!parseExpr()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
blockStack.remove(blockStack.size() - 1);
|
||||||
|
reportAddress();
|
||||||
|
codeListener.endBlock(token, false);
|
||||||
|
++reader.ptr;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void parseBranch(BranchOpcode opcode) {
|
||||||
|
var depth = readLEB();
|
||||||
|
var target = blockStack.get(blockStack.size() - depth - 1);
|
||||||
|
codeListener.branch(opcode, depth, target.token);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void parseTableBranch() {
|
||||||
|
var count = readLEB();
|
||||||
|
var depths = new int[count];
|
||||||
|
var targets = new int[count];
|
||||||
|
for (var i = 0; i < count; ++i) {
|
||||||
|
var depth = readLEB();
|
||||||
|
depths[i] = depth;
|
||||||
|
targets[i] = blockStack.get(blockStack.size() - depth - 1).token;
|
||||||
|
}
|
||||||
|
var defaultDepth = readLEB();
|
||||||
|
var defaultTarget = blockStack.get(blockStack.size() - defaultDepth - 1).token;
|
||||||
|
codeListener.tableBranch(depths, targets, defaultDepth, defaultTarget);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class Block {
|
||||||
|
int token;
|
||||||
|
|
||||||
|
Block(int token) {
|
||||||
|
this.token = token;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -15,27 +15,12 @@
|
||||||
*/
|
*/
|
||||||
package org.teavm.backend.wasm.parser;
|
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.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.model.expression.WasmSignedType;
|
|
||||||
|
|
||||||
public class CodeSectionParser extends BaseSectionParser {
|
public class CodeSectionParser extends BaseSectionParser {
|
||||||
private CodeSectionListener listener;
|
private CodeSectionListener listener;
|
||||||
private CodeListener codeListener;
|
|
||||||
private List<Block> blockStack = new ArrayList<>();
|
|
||||||
private int functionIndexOffset;
|
private int functionIndexOffset;
|
||||||
|
private CodeParser codeParser = new CodeParser();
|
||||||
|
|
||||||
public CodeSectionParser(AddressListener addressListener, CodeSectionListener listener) {
|
public CodeSectionParser(CodeSectionListener listener) {
|
||||||
super(addressListener);
|
|
||||||
this.listener = listener;
|
this.listener = listener;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -58,15 +43,17 @@ public class CodeSectionParser extends BaseSectionParser {
|
||||||
private void parseFunction(int index) {
|
private void parseFunction(int index) {
|
||||||
reportAddress();
|
reportAddress();
|
||||||
var functionSize = readLEB();
|
var functionSize = readLEB();
|
||||||
var end = ptr + functionSize;
|
var end = reader.ptr + functionSize;
|
||||||
if (listener.functionStart(index + functionIndexOffset, functionSize)) {
|
if (listener.functionStart(index + functionIndexOffset, functionSize)) {
|
||||||
parseLocals();
|
parseLocals();
|
||||||
codeListener = listener.code();
|
var codeListener = listener.code();
|
||||||
if (codeListener != null) {
|
if (codeListener != null) {
|
||||||
parseCode();
|
codeParser.setCodeListener(codeListener);
|
||||||
|
codeParser.setFunctionIndexOffset(functionIndexOffset);
|
||||||
|
codeParser.parse(reader);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ptr = end;
|
reader.ptr = end;
|
||||||
reportAddress();
|
reportAddress();
|
||||||
listener.functionEnd();
|
listener.functionEnd();
|
||||||
}
|
}
|
||||||
|
@ -79,777 +66,10 @@ public class CodeSectionParser extends BaseSectionParser {
|
||||||
for (int i = 0; i < localEntries; ++i) {
|
for (int i = 0; i < localEntries; ++i) {
|
||||||
reportAddress();
|
reportAddress();
|
||||||
var countInGroup = readLEB();
|
var countInGroup = readLEB();
|
||||||
var type = readType();
|
var type = reader.readType();
|
||||||
listener.local(localIndex, countInGroup, type);
|
listener.local(localIndex, countInGroup, type);
|
||||||
localIndex += countInGroup;
|
localIndex += countInGroup;
|
||||||
}
|
}
|
||||||
reportAddress();
|
reportAddress();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void parseCode() {
|
|
||||||
if (!parseExpressions()) {
|
|
||||||
codeListener.error(blockStack.size());
|
|
||||||
blockStack.clear();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean parseExpressions() {
|
|
||||||
while (data[ptr] != 0x0B) {
|
|
||||||
if (!parseExpr()) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean parseExpr() {
|
|
||||||
reportAddress();
|
|
||||||
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:
|
|
||||||
return parseBlock(true);
|
|
||||||
case 0x04:
|
|
||||||
return parseConditional();
|
|
||||||
case 0x06:
|
|
||||||
return parseTryCatch();
|
|
||||||
case 0x8:
|
|
||||||
codeListener.throwInstruction(readLEB());
|
|
||||||
break;
|
|
||||||
case 0x0C:
|
|
||||||
parseBranch(BranchOpcode.BR);
|
|
||||||
break;
|
|
||||||
case 0x0D:
|
|
||||||
parseBranch(BranchOpcode.BR_IF);
|
|
||||||
break;
|
|
||||||
case 0x0E:
|
|
||||||
parseTableBranch();
|
|
||||||
break;
|
|
||||||
case 0x0F:
|
|
||||||
codeListener.opcode(Opcode.RETURN);
|
|
||||||
break;
|
|
||||||
case 0x10:
|
|
||||||
codeListener.call(readLEB() + functionIndexOffset);
|
|
||||||
break;
|
|
||||||
case 0x11:
|
|
||||||
codeListener.indirectCall(readLEB(), readLEB());
|
|
||||||
break;
|
|
||||||
case 0x14:
|
|
||||||
codeListener.callReference(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 0x23:
|
|
||||||
codeListener.getGlobal(readLEB());
|
|
||||||
break;
|
|
||||||
case 0x24:
|
|
||||||
codeListener.setGlobal(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;
|
|
||||||
case 0x42:
|
|
||||||
codeListener.int64Constant(readSignedLongLEB());
|
|
||||||
break;
|
|
||||||
case 0x43:
|
|
||||||
codeListener.float32Constant(Float.intBitsToFloat(readFixedInt()));
|
|
||||||
break;
|
|
||||||
case 0x44:
|
|
||||||
codeListener.float64Constant(Double.longBitsToDouble(readFixedLong()));
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 0x45:
|
|
||||||
codeListener.unary(WasmIntUnaryOperation.EQZ, WasmIntType.INT32);
|
|
||||||
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 0x50:
|
|
||||||
codeListener.unary(WasmIntUnaryOperation.EQZ, WasmIntType.INT64);
|
|
||||||
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(WasmNumType.INT64, WasmNumType.INT32, false, false);
|
|
||||||
break;
|
|
||||||
case 0xA8:
|
|
||||||
codeListener.convert(WasmNumType.FLOAT32, WasmNumType.INT32, false, false);
|
|
||||||
break;
|
|
||||||
case 0xA9:
|
|
||||||
codeListener.convert(WasmNumType.FLOAT32, WasmNumType.INT32, true, false);
|
|
||||||
break;
|
|
||||||
case 0xAA:
|
|
||||||
codeListener.convert(WasmNumType.FLOAT64, WasmNumType.INT32, false, false);
|
|
||||||
break;
|
|
||||||
case 0xAB:
|
|
||||||
codeListener.convert(WasmNumType.FLOAT64, WasmNumType.INT32, true, false);
|
|
||||||
break;
|
|
||||||
case 0xAC:
|
|
||||||
codeListener.convert(WasmNumType.INT32, WasmNumType.INT64, false, false);
|
|
||||||
break;
|
|
||||||
case 0xAD:
|
|
||||||
codeListener.convert(WasmNumType.INT32, WasmNumType.INT64, true, false);
|
|
||||||
break;
|
|
||||||
case 0xAE:
|
|
||||||
codeListener.convert(WasmNumType.FLOAT32, WasmNumType.INT64, false, false);
|
|
||||||
break;
|
|
||||||
case 0xAF:
|
|
||||||
codeListener.convert(WasmNumType.FLOAT32, WasmNumType.INT64, true, false);
|
|
||||||
break;
|
|
||||||
case 0xB0:
|
|
||||||
codeListener.convert(WasmNumType.FLOAT64, WasmNumType.INT64, false, false);
|
|
||||||
break;
|
|
||||||
case 0xB1:
|
|
||||||
codeListener.convert(WasmNumType.FLOAT64, WasmNumType.INT64, true, false);
|
|
||||||
break;
|
|
||||||
case 0xB2:
|
|
||||||
codeListener.convert(WasmNumType.INT32, WasmNumType.FLOAT32, false, false);
|
|
||||||
break;
|
|
||||||
case 0xB3:
|
|
||||||
codeListener.convert(WasmNumType.INT32, WasmNumType.FLOAT32, true, false);
|
|
||||||
break;
|
|
||||||
case 0xB4:
|
|
||||||
codeListener.convert(WasmNumType.INT64, WasmNumType.FLOAT32, false, false);
|
|
||||||
break;
|
|
||||||
case 0xB5:
|
|
||||||
codeListener.convert(WasmNumType.INT64, WasmNumType.FLOAT32, true, false);
|
|
||||||
break;
|
|
||||||
case 0xB6:
|
|
||||||
codeListener.convert(WasmNumType.FLOAT64, WasmNumType.FLOAT32, true, false);
|
|
||||||
break;
|
|
||||||
case 0xB7:
|
|
||||||
codeListener.convert(WasmNumType.INT32, WasmNumType.FLOAT64, false, false);
|
|
||||||
break;
|
|
||||||
case 0xB8:
|
|
||||||
codeListener.convert(WasmNumType.INT32, WasmNumType.FLOAT64, true, false);
|
|
||||||
break;
|
|
||||||
case 0xB9:
|
|
||||||
codeListener.convert(WasmNumType.INT64, WasmNumType.FLOAT64, false, false);
|
|
||||||
break;
|
|
||||||
case 0xBA:
|
|
||||||
codeListener.convert(WasmNumType.INT64, WasmNumType.FLOAT64, true, false);
|
|
||||||
break;
|
|
||||||
case 0xBC:
|
|
||||||
codeListener.convert(WasmNumType.FLOAT32, WasmNumType.INT32, false, true);
|
|
||||||
break;
|
|
||||||
case 0xBD:
|
|
||||||
codeListener.convert(WasmNumType.FLOAT64, WasmNumType.INT64, false, true);
|
|
||||||
break;
|
|
||||||
case 0xBE:
|
|
||||||
codeListener.convert(WasmNumType.INT32, WasmNumType.FLOAT32, false, true);
|
|
||||||
break;
|
|
||||||
case 0xBF:
|
|
||||||
codeListener.convert(WasmNumType.INT64, WasmNumType.FLOAT64, false, true);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 0xD0:
|
|
||||||
codeListener.nullConstant(readHeapType());
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 0xD2:
|
|
||||||
codeListener.functionReference(readLEB() + functionIndexOffset);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 0xD3:
|
|
||||||
codeListener.opcode(Opcode.REF_EQ);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 0xFB:
|
|
||||||
return parseExtExpr2();
|
|
||||||
case 0xFC:
|
|
||||||
return parseExtExpr();
|
|
||||||
|
|
||||||
default:
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean parseExtExpr() {
|
|
||||||
switch (readLEB()) {
|
|
||||||
case 10: {
|
|
||||||
if (data[ptr++] != 0 || data[ptr++] != 0) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
codeListener.memoryCopy();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
case 11: {
|
|
||||||
if (data[ptr++] != 0) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
codeListener.memoryFill();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
default:
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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 17:
|
|
||||||
codeListener.arrayCopy(readLEB(), readLEB());
|
|
||||||
return true;
|
|
||||||
|
|
||||||
case 20:
|
|
||||||
codeListener.test(readHeapType(), false);
|
|
||||||
return true;
|
|
||||||
|
|
||||||
case 21:
|
|
||||||
codeListener.test(readHeapType(), true);
|
|
||||||
return true;
|
|
||||||
|
|
||||||
case 22:
|
|
||||||
codeListener.cast(readHeapType(), false);
|
|
||||||
return true;
|
|
||||||
|
|
||||||
case 23:
|
|
||||||
codeListener.cast(readHeapType(), true);
|
|
||||||
return true;
|
|
||||||
|
|
||||||
case 28:
|
|
||||||
codeListener.int31Reference();
|
|
||||||
return true;
|
|
||||||
|
|
||||||
case 29:
|
|
||||||
codeListener.int31Get(WasmSignedType.SIGNED);
|
|
||||||
return true;
|
|
||||||
case 30:
|
|
||||||
codeListener.int31Get(WasmSignedType.UNSIGNED);
|
|
||||||
return true;
|
|
||||||
|
|
||||||
default:
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean parseBlock(boolean isLoop) {
|
|
||||||
var type = readType();
|
|
||||||
var token = codeListener.startBlock(isLoop, type);
|
|
||||||
blockStack.add(new Block(token));
|
|
||||||
if (!parseExpressions()) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
blockStack.remove(blockStack.size() - 1);
|
|
||||||
reportAddress();
|
|
||||||
codeListener.endBlock(token, isLoop);
|
|
||||||
++ptr;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean parseConditional() {
|
|
||||||
var type = readType();
|
|
||||||
var token = codeListener.startConditionalBlock(type);
|
|
||||||
blockStack.add(new Block(token));
|
|
||||||
var hasElse = false;
|
|
||||||
loop: while (true) {
|
|
||||||
switch (data[ptr]) {
|
|
||||||
case 0x0B:
|
|
||||||
break loop;
|
|
||||||
case 0x05:
|
|
||||||
if (hasElse) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
reportAddress();
|
|
||||||
codeListener.startElseSection(blockStack.get(blockStack.size() - 1).token);
|
|
||||||
++ptr;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
if (!parseExpr()) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
blockStack.remove(blockStack.size() - 1);
|
|
||||||
reportAddress();
|
|
||||||
codeListener.endBlock(token, false);
|
|
||||||
++ptr;
|
|
||||||
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);
|
|
||||||
codeListener.branch(opcode, depth, target.token);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void parseTableBranch() {
|
|
||||||
var count = readLEB();
|
|
||||||
var depths = new int[count];
|
|
||||||
var targets = new int[count];
|
|
||||||
for (var i = 0; i < count; ++i) {
|
|
||||||
var depth = readLEB();
|
|
||||||
depths[i] = depth;
|
|
||||||
targets[i] = blockStack.get(blockStack.size() - depth - 1).token;
|
|
||||||
}
|
|
||||||
var defaultDepth = readLEB();
|
|
||||||
var defaultTarget = blockStack.get(blockStack.size() - defaultDepth - 1).token;
|
|
||||||
codeListener.tableBranch(depths, targets, defaultDepth, defaultTarget);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static class Block {
|
|
||||||
int token;
|
|
||||||
|
|
||||||
Block(int token) {
|
|
||||||
this.token = token;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,22 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2024 Alexey Andreev.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package org.teavm.backend.wasm.parser;
|
||||||
|
|
||||||
|
public interface GlobalSectionListener {
|
||||||
|
CodeListener startGlobal(int index, WasmHollowType type, boolean mutable);
|
||||||
|
|
||||||
|
void endGlobal();
|
||||||
|
}
|
|
@ -0,0 +1,52 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2024 Alexey Andreev.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package org.teavm.backend.wasm.parser;
|
||||||
|
|
||||||
|
public class GlobalSectionParser extends BaseSectionParser {
|
||||||
|
private final GlobalSectionListener listener;
|
||||||
|
private CodeParser codeParser;
|
||||||
|
private int functionIndexOffset;
|
||||||
|
|
||||||
|
public GlobalSectionParser(GlobalSectionListener listener) {
|
||||||
|
this.listener = listener;
|
||||||
|
codeParser = new CodeParser();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setFunctionIndexOffset(int functionIndexOffset) {
|
||||||
|
this.functionIndexOffset = functionIndexOffset;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void parseContent() {
|
||||||
|
var count = readLEB();
|
||||||
|
for (var i = 0; i < count; ++i) {
|
||||||
|
reportAddress();
|
||||||
|
var type = reader.readType();
|
||||||
|
var mutable = reader.data[reader.ptr++] != 0;
|
||||||
|
var codeListener = listener.startGlobal(i, type, mutable);
|
||||||
|
if (codeListener == null) {
|
||||||
|
codeListener = CodeListener.EMPTY;
|
||||||
|
}
|
||||||
|
codeParser.setCodeListener(codeListener);
|
||||||
|
codeParser.setFunctionIndexOffset(functionIndexOffset);
|
||||||
|
if (!codeParser.parseSingleExpression(reader)) {
|
||||||
|
throw new ParseException("Error parsing global initializer", reader.ptr);
|
||||||
|
}
|
||||||
|
reader.ptr++;
|
||||||
|
listener.endGlobal();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -18,8 +18,7 @@ package org.teavm.backend.wasm.parser;
|
||||||
public class ImportSectionParser extends BaseSectionParser {
|
public class ImportSectionParser extends BaseSectionParser {
|
||||||
private final ImportSectionListener listener;
|
private final ImportSectionListener listener;
|
||||||
|
|
||||||
public ImportSectionParser(AddressListener addressListener, ImportSectionListener listener) {
|
public ImportSectionParser(ImportSectionListener listener) {
|
||||||
super(addressListener);
|
|
||||||
this.listener = listener;
|
this.listener = listener;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -37,12 +36,12 @@ public class ImportSectionParser extends BaseSectionParser {
|
||||||
var name = readString();
|
var name = readString();
|
||||||
listener.startEntry(module, name);
|
listener.startEntry(module, name);
|
||||||
reportAddress();
|
reportAddress();
|
||||||
var type = data[ptr++];
|
var type = reader.data[reader.ptr++];
|
||||||
if (type == 0) {
|
if (type == 0) {
|
||||||
var typeIndex = readLEB();
|
var typeIndex = readLEB();
|
||||||
listener.function(typeIndex);
|
listener.function(typeIndex);
|
||||||
} else {
|
} else {
|
||||||
throw new ParseException("Unsupported import type", ptr);
|
throw new ParseException("Unsupported import type", reader.ptr);
|
||||||
}
|
}
|
||||||
listener.endEntry();
|
listener.endEntry();
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,16 +19,15 @@ public class NameSectionParser extends BaseSectionParser {
|
||||||
private final NameSectionListener listener;
|
private final NameSectionListener listener;
|
||||||
|
|
||||||
public NameSectionParser(NameSectionListener listener) {
|
public NameSectionParser(NameSectionListener listener) {
|
||||||
super(AddressListener.EMPTY);
|
|
||||||
this.listener = listener;
|
this.listener = listener;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void parseContent() {
|
protected void parseContent() {
|
||||||
while (ptr < data.length) {
|
while (reader.ptr < reader.data.length) {
|
||||||
var sectionType = data[ptr++];
|
var sectionType = reader.data[reader.ptr++];
|
||||||
var sectionLength = readLEB();
|
var sectionLength = readLEB();
|
||||||
var next = ptr + sectionLength;
|
var next = reader.ptr + sectionLength;
|
||||||
switch (sectionType) {
|
switch (sectionType) {
|
||||||
case 1:
|
case 1:
|
||||||
parseNameMapSubsection(listener.functions());
|
parseNameMapSubsection(listener.functions());
|
||||||
|
@ -46,7 +45,7 @@ public class NameSectionParser extends BaseSectionParser {
|
||||||
parseIndirectNameMap(listener.fields());
|
parseIndirectNameMap(listener.fields());
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
ptr = next;
|
reader.ptr = next;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -19,8 +19,7 @@ public class TypeSectionParser extends BaseSectionParser {
|
||||||
private TypeSectionListener listener;
|
private TypeSectionListener listener;
|
||||||
private int typeIndex;
|
private int typeIndex;
|
||||||
|
|
||||||
public TypeSectionParser(AddressListener addressListener, TypeSectionListener listener) {
|
public TypeSectionParser(TypeSectionListener listener) {
|
||||||
super(addressListener);
|
|
||||||
this.listener = listener;
|
this.listener = listener;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -38,7 +37,7 @@ public class TypeSectionParser extends BaseSectionParser {
|
||||||
}
|
}
|
||||||
|
|
||||||
private void parseType() {
|
private void parseType() {
|
||||||
if (data[ptr] == 0x4E) {
|
if (reader.data[reader.ptr] == 0x4E) {
|
||||||
parseRecType();
|
parseRecType();
|
||||||
} else {
|
} else {
|
||||||
parseSubtype();
|
parseSubtype();
|
||||||
|
@ -47,7 +46,7 @@ public class TypeSectionParser extends BaseSectionParser {
|
||||||
|
|
||||||
private void parseRecType() {
|
private void parseRecType() {
|
||||||
reportAddress();
|
reportAddress();
|
||||||
++ptr;
|
++reader.ptr;
|
||||||
var count = readLEB();
|
var count = readLEB();
|
||||||
listener.startRecType(count);
|
listener.startRecType(count);
|
||||||
for (var i = 0; i < count; ++i) {
|
for (var i = 0; i < count; ++i) {
|
||||||
|
@ -57,15 +56,15 @@ public class TypeSectionParser extends BaseSectionParser {
|
||||||
}
|
}
|
||||||
|
|
||||||
private void parseSubtype() {
|
private void parseSubtype() {
|
||||||
switch (data[ptr]) {
|
switch (reader.data[reader.ptr]) {
|
||||||
case 0x50:
|
case 0x50:
|
||||||
reportAddress();
|
reportAddress();
|
||||||
++ptr;
|
++reader.ptr;
|
||||||
parseCompositeType(true, readSupertypes());
|
parseCompositeType(true, readSupertypes());
|
||||||
break;
|
break;
|
||||||
case 0x4F:
|
case 0x4F:
|
||||||
reportAddress();
|
reportAddress();
|
||||||
++ptr;
|
++reader.ptr;
|
||||||
parseCompositeType(false, readSupertypes());
|
parseCompositeType(false, readSupertypes());
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
@ -77,17 +76,17 @@ public class TypeSectionParser extends BaseSectionParser {
|
||||||
private void parseCompositeType(boolean open, int[] supertypes) {
|
private void parseCompositeType(boolean open, int[] supertypes) {
|
||||||
reportAddress();
|
reportAddress();
|
||||||
listener.startType(typeIndex++, open, supertypes);
|
listener.startType(typeIndex++, open, supertypes);
|
||||||
switch (data[ptr]) {
|
switch (reader.data[reader.ptr]) {
|
||||||
case 0x5E:
|
case 0x5E:
|
||||||
reportAddress();
|
reportAddress();
|
||||||
++ptr;
|
++reader.ptr;
|
||||||
listener.startArrayType();
|
listener.startArrayType();
|
||||||
parseField();
|
parseField();
|
||||||
listener.endArrayType();
|
listener.endArrayType();
|
||||||
break;
|
break;
|
||||||
case 0x5F: {
|
case 0x5F: {
|
||||||
reportAddress();
|
reportAddress();
|
||||||
++ptr;
|
++reader.ptr;
|
||||||
var fieldCount = readLEB();
|
var fieldCount = readLEB();
|
||||||
listener.startStructType(fieldCount);
|
listener.startStructType(fieldCount);
|
||||||
for (var i = 0; i < fieldCount; ++i) {
|
for (var i = 0; i < fieldCount; ++i) {
|
||||||
|
@ -98,32 +97,32 @@ public class TypeSectionParser extends BaseSectionParser {
|
||||||
}
|
}
|
||||||
case 0x60: {
|
case 0x60: {
|
||||||
reportAddress();
|
reportAddress();
|
||||||
++ptr;
|
++reader.ptr;
|
||||||
var paramCount = readLEB();
|
var paramCount = readLEB();
|
||||||
listener.funcType(paramCount);
|
listener.funcType(paramCount);
|
||||||
for (var i = 0; i < paramCount; ++i) {
|
for (var i = 0; i < paramCount; ++i) {
|
||||||
reportAddress();
|
reportAddress();
|
||||||
listener.resultType(readType());
|
listener.resultType(reader.readType());
|
||||||
}
|
}
|
||||||
var resultCount = readLEB();
|
var resultCount = readLEB();
|
||||||
listener.funcTypeResults(resultCount);
|
listener.funcTypeResults(resultCount);
|
||||||
for (var i = 0; i < resultCount; ++i) {
|
for (var i = 0; i < resultCount; ++i) {
|
||||||
reportAddress();
|
reportAddress();
|
||||||
listener.resultType(readType());
|
listener.resultType(reader.readType());
|
||||||
}
|
}
|
||||||
listener.endFuncType();
|
listener.endFuncType();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
throw new ParseException("Unknown type declaration", ptr);
|
throw new ParseException("Unknown type declaration", reader.ptr);
|
||||||
}
|
}
|
||||||
listener.endType();
|
listener.endType();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void parseField() {
|
private void parseField() {
|
||||||
reportAddress();
|
reportAddress();
|
||||||
var type = readStorageType();
|
var type = reader.readStorageType();
|
||||||
var mutable = data[ptr++] != 0;
|
var mutable = reader.data[reader.ptr++] != 0;
|
||||||
listener.field(type, mutable);
|
listener.field(type, mutable);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,189 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2024 Alexey Andreev.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package org.teavm.backend.wasm.parser;
|
||||||
|
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
|
||||||
|
public class WasmBinaryReader {
|
||||||
|
private final AddressListener addressListener;
|
||||||
|
public final byte[] data;
|
||||||
|
public int ptr;
|
||||||
|
private int lastReportedPtr = -1;
|
||||||
|
|
||||||
|
public WasmBinaryReader(AddressListener addressListener, byte[] data) {
|
||||||
|
this.addressListener = addressListener;
|
||||||
|
this.data = data;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void reportAddress() {
|
||||||
|
if (ptr != lastReportedPtr) {
|
||||||
|
lastReportedPtr = ptr;
|
||||||
|
if (addressListener != null) {
|
||||||
|
addressListener.address(ptr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public WasmHollowStorageType readStorageType() {
|
||||||
|
var typeId = data[ptr];
|
||||||
|
switch (typeId) {
|
||||||
|
case 0x78:
|
||||||
|
++ptr;
|
||||||
|
return WasmHollowStorageType.INT8;
|
||||||
|
case 0x77:
|
||||||
|
++ptr;
|
||||||
|
return WasmHollowStorageType.INT16;
|
||||||
|
default:
|
||||||
|
return new WasmHollowStorageType.Regular(readType());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public WasmHollowType readType() {
|
||||||
|
var typeId = data[ptr++];
|
||||||
|
switch (typeId) {
|
||||||
|
case 0x7F:
|
||||||
|
return WasmHollowType.INT32;
|
||||||
|
case 0x7E:
|
||||||
|
return WasmHollowType.INT64;
|
||||||
|
case 0x7D:
|
||||||
|
return WasmHollowType.FLOAT32;
|
||||||
|
case 0x7C:
|
||||||
|
return WasmHollowType.FLOAT64;
|
||||||
|
case 0x63:
|
||||||
|
return readHeapType();
|
||||||
|
case 0x40:
|
||||||
|
return null;
|
||||||
|
default:
|
||||||
|
return readAbsHeapType(typeId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public WasmHollowType.Reference readHeapType() {
|
||||||
|
var typeId = data[ptr];
|
||||||
|
if ((typeId & 0xC0) == 0x40) {
|
||||||
|
var result = readAbsHeapType(typeId);
|
||||||
|
++ptr;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
return new WasmHollowType.CompositeReference(readLEB());
|
||||||
|
}
|
||||||
|
|
||||||
|
public 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 0x6C:
|
||||||
|
return WasmHollowType.Reference.I31;
|
||||||
|
case 0x6B:
|
||||||
|
return WasmHollowType.Reference.STRUCT;
|
||||||
|
case 0x6A:
|
||||||
|
return WasmHollowType.Reference.ARRAY;
|
||||||
|
default:
|
||||||
|
throw new ParseException("Unknown type", ptr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public int readSignedLEB() {
|
||||||
|
var result = 0;
|
||||||
|
var shift = 0;
|
||||||
|
while (true) {
|
||||||
|
var digit = data[ptr++];
|
||||||
|
result |= (digit & 0x7F) << shift;
|
||||||
|
if ((digit & 0x80) == 0) {
|
||||||
|
if ((digit & 0x40) != 0) {
|
||||||
|
result |= -1 << (shift + 7);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
shift += 7;
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int readLEB() {
|
||||||
|
var result = 0;
|
||||||
|
var shift = 0;
|
||||||
|
while (true) {
|
||||||
|
var digit = data[ptr++];
|
||||||
|
result |= (digit & 0x7F) << shift;
|
||||||
|
if ((digit & 0x80) == 0) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
shift += 7;
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public long readSignedLongLEB() {
|
||||||
|
var result = 0L;
|
||||||
|
var shift = 0;
|
||||||
|
while (true) {
|
||||||
|
var digit = data[ptr++];
|
||||||
|
result |= (digit & 0x7FL) << shift;
|
||||||
|
if ((digit & 0x80) == 0) {
|
||||||
|
if ((digit & 0x40) != 0) {
|
||||||
|
result |= -1L << (shift + 7);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
shift += 7;
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public long readLongLEB() {
|
||||||
|
var result = 0L;
|
||||||
|
var shift = 0;
|
||||||
|
while (true) {
|
||||||
|
var digit = data[ptr++];
|
||||||
|
result |= (digit & 0x7FL) << shift;
|
||||||
|
if ((digit & 0x80) == 0) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
shift += 7;
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int readFixedInt() {
|
||||||
|
return ((data[ptr++] & 0xFF) << 24)
|
||||||
|
| ((data[ptr++] & 0xFF) << 16)
|
||||||
|
| ((data[ptr++] & 0xFF) << 8)
|
||||||
|
| (data[ptr++] & 0xFF);
|
||||||
|
}
|
||||||
|
|
||||||
|
public 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);
|
||||||
|
}
|
||||||
|
|
||||||
|
public String readString() {
|
||||||
|
var size = readLEB();
|
||||||
|
var result = new String(data, ptr, size, StandardCharsets.UTF_8);
|
||||||
|
ptr += size;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user