mirror of
https://github.com/Eaglercraft-TeaVM-Fork/eagler-teavm.git
synced 2024-12-22 16:14:10 -08:00
wasm gc: improve disassembler to print type section
This commit is contained in:
parent
7324e99e6a
commit
5a513fd6fd
|
@ -0,0 +1,117 @@
|
||||||
|
/*
|
||||||
|
* 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.AddressListener;
|
||||||
|
import org.teavm.backend.wasm.parser.WasmHollowStorageType;
|
||||||
|
import org.teavm.backend.wasm.parser.WasmHollowType;
|
||||||
|
|
||||||
|
public abstract class BaseDisassemblyListener implements AddressListener {
|
||||||
|
protected final DisassemblyWriter writer;
|
||||||
|
protected int address;
|
||||||
|
private int addressOffset;
|
||||||
|
|
||||||
|
public BaseDisassemblyListener(DisassemblyWriter writer) {
|
||||||
|
this.writer = writer;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setAddressOffset(int addressOffset) {
|
||||||
|
this.addressOffset = addressOffset;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void address(int address) {
|
||||||
|
this.address = address + addressOffset;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void writeBlockType(WasmHollowType type) {
|
||||||
|
if (type != null) {
|
||||||
|
writer.write(" ");
|
||||||
|
writeType(type);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void writeType(WasmHollowStorageType type) {
|
||||||
|
if (type instanceof WasmHollowStorageType.Packed) {
|
||||||
|
switch (((WasmHollowStorageType.Packed) type).type) {
|
||||||
|
case INT8:
|
||||||
|
writer.write("i8");
|
||||||
|
return;
|
||||||
|
case INT16:
|
||||||
|
writer.write("i16");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
writeType(type.asUnpackedType());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void writeType(WasmHollowType type) {
|
||||||
|
if (type != null) {
|
||||||
|
if (type instanceof WasmHollowType.Number) {
|
||||||
|
switch (((WasmHollowType.Number) type).number) {
|
||||||
|
case INT32:
|
||||||
|
writer.write("i32");
|
||||||
|
return;
|
||||||
|
case INT64:
|
||||||
|
writer.write("i64");
|
||||||
|
return;
|
||||||
|
case FLOAT32:
|
||||||
|
writer.write("f32");
|
||||||
|
return;
|
||||||
|
case FLOAT64:
|
||||||
|
writer.write("f64");
|
||||||
|
return;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} else if (type instanceof WasmHollowType.SpecialReference) {
|
||||||
|
switch (((WasmHollowType.SpecialReference) type).kind) {
|
||||||
|
case ANY:
|
||||||
|
writer.write("anyref");
|
||||||
|
return;
|
||||||
|
case FUNC:
|
||||||
|
writer.write("funcref");
|
||||||
|
return;
|
||||||
|
case ARRAY:
|
||||||
|
writer.write("arrayref");
|
||||||
|
return;
|
||||||
|
case EXTERN:
|
||||||
|
writer.write("externref");
|
||||||
|
return;
|
||||||
|
case STRUCT:
|
||||||
|
writer.write("structref");
|
||||||
|
return;
|
||||||
|
case I31:
|
||||||
|
writer.write("i31ref");
|
||||||
|
return;
|
||||||
|
default:
|
||||||
|
throw new IllegalArgumentException();
|
||||||
|
}
|
||||||
|
} else if (type instanceof WasmHollowType.CompositeReference) {
|
||||||
|
writer.write("(ref null ");
|
||||||
|
writeTypeId(((WasmHollowType.CompositeReference) type).index);
|
||||||
|
writer.write(")");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
writer.write("unknown");
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void writeTypeId(int index) {
|
||||||
|
writer.write(String.valueOf(index));
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,97 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2024 konsoletyper.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package org.teavm.backend.wasm.disasm;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.OutputStreamWriter;
|
||||||
|
import java.io.PrintWriter;
|
||||||
|
import java.io.Writer;
|
||||||
|
import java.nio.file.Files;
|
||||||
|
import java.util.function.Consumer;
|
||||||
|
import org.teavm.backend.wasm.parser.CodeSectionParser;
|
||||||
|
import org.teavm.backend.wasm.parser.ModuleParser;
|
||||||
|
import org.teavm.backend.wasm.parser.TypeSectionParser;
|
||||||
|
import org.teavm.common.AsyncInputStream;
|
||||||
|
import org.teavm.common.ByteArrayAsyncInputStream;
|
||||||
|
|
||||||
|
public final class Disassembler {
|
||||||
|
private PrintWriter out;
|
||||||
|
private DisassemblyWriter writer;
|
||||||
|
|
||||||
|
public Disassembler(Writer writer) {
|
||||||
|
out = new PrintWriter(writer);
|
||||||
|
this.writer = new DisassemblyWriter(out, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void startModule() {
|
||||||
|
writer.write("(module").indent().eol();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void endModule() {
|
||||||
|
writer.write(")").eol();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void disassemble(byte[] bytes) {
|
||||||
|
startModule();
|
||||||
|
read(bytes);
|
||||||
|
endModule();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void read(byte[] bytes) {
|
||||||
|
var input = new ByteArrayAsyncInputStream(bytes);
|
||||||
|
var parser = createParser(input);
|
||||||
|
input.readFully(parser::parse);
|
||||||
|
}
|
||||||
|
|
||||||
|
public ModuleParser createParser(AsyncInputStream input) {
|
||||||
|
return new ModuleParser(input) {
|
||||||
|
@Override
|
||||||
|
protected Consumer<byte[]> getSectionConsumer(int code, int pos, String name) {
|
||||||
|
return Disassembler.this.getSectionConsumer(code, pos, name);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public Consumer<byte[]> getSectionConsumer(int code, int pos, String name) {
|
||||||
|
if (code == 1) {
|
||||||
|
return bytes -> {
|
||||||
|
var disassembler = new DisassemblyTypeSectionListener(writer);
|
||||||
|
disassembler.setAddressOffset(pos);
|
||||||
|
var sectionParser = new TypeSectionParser(disassembler, disassembler);
|
||||||
|
sectionParser.parse(bytes);
|
||||||
|
out.flush();
|
||||||
|
};
|
||||||
|
} else if (code == 10) {
|
||||||
|
return bytes -> {
|
||||||
|
var disassembler = new DisassemblyCodeSectionListener(writer);
|
||||||
|
disassembler.setAddressOffset(pos);
|
||||||
|
var sectionParser = new CodeSectionParser(disassembler, disassembler);
|
||||||
|
sectionParser.parse(bytes);
|
||||||
|
out.flush();
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void main(String[] args) throws IOException {
|
||||||
|
var file = new File(args[0]);
|
||||||
|
var bytes = Files.readAllBytes(file.toPath());
|
||||||
|
var disassembler = new Disassembler(new OutputStreamWriter(System.out));
|
||||||
|
disassembler.disassemble(bytes);
|
||||||
|
}
|
||||||
|
}
|
|
@ -15,11 +15,6 @@
|
||||||
*/
|
*/
|
||||||
package org.teavm.backend.wasm.disasm;
|
package org.teavm.backend.wasm.disasm;
|
||||||
|
|
||||||
import java.io.File;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.PrintWriter;
|
|
||||||
import java.nio.file.Files;
|
|
||||||
import java.util.function.Consumer;
|
|
||||||
import org.teavm.backend.wasm.model.WasmNumType;
|
import org.teavm.backend.wasm.model.WasmNumType;
|
||||||
import org.teavm.backend.wasm.model.expression.WasmFloatBinaryOperation;
|
import org.teavm.backend.wasm.model.expression.WasmFloatBinaryOperation;
|
||||||
import org.teavm.backend.wasm.model.expression.WasmFloatType;
|
import org.teavm.backend.wasm.model.expression.WasmFloatType;
|
||||||
|
@ -34,35 +29,16 @@ import org.teavm.backend.wasm.parser.AddressListener;
|
||||||
import org.teavm.backend.wasm.parser.BranchOpcode;
|
import org.teavm.backend.wasm.parser.BranchOpcode;
|
||||||
import org.teavm.backend.wasm.parser.CodeListener;
|
import org.teavm.backend.wasm.parser.CodeListener;
|
||||||
import org.teavm.backend.wasm.parser.CodeSectionListener;
|
import org.teavm.backend.wasm.parser.CodeSectionListener;
|
||||||
import org.teavm.backend.wasm.parser.CodeSectionParser;
|
|
||||||
import org.teavm.backend.wasm.parser.LocalOpcode;
|
import org.teavm.backend.wasm.parser.LocalOpcode;
|
||||||
import org.teavm.backend.wasm.parser.ModuleParser;
|
|
||||||
import org.teavm.backend.wasm.parser.Opcode;
|
import org.teavm.backend.wasm.parser.Opcode;
|
||||||
import org.teavm.backend.wasm.parser.WasmHollowType;
|
import org.teavm.backend.wasm.parser.WasmHollowType;
|
||||||
import org.teavm.common.ByteArrayAsyncInputStream;
|
|
||||||
|
|
||||||
public class DisassemblyCodeSectionListener implements AddressListener, CodeSectionListener, CodeListener {
|
public class DisassemblyCodeSectionListener extends BaseDisassemblyListener implements AddressListener,
|
||||||
private DisassemblyWriter writer;
|
CodeSectionListener, CodeListener {
|
||||||
private int address;
|
|
||||||
private int addressOffset;
|
|
||||||
private int blockIdGen;
|
private int blockIdGen;
|
||||||
|
|
||||||
public DisassemblyCodeSectionListener(DisassemblyWriter writer) {
|
public DisassemblyCodeSectionListener(DisassemblyWriter writer) {
|
||||||
this.writer = writer;
|
super(writer);
|
||||||
}
|
|
||||||
|
|
||||||
public void setAddressOffset(int addressOffset) {
|
|
||||||
this.addressOffset = addressOffset;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void address(int address) {
|
|
||||||
this.address = address + addressOffset;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void sectionStart(int functionCount) {
|
|
||||||
writer.address(address).write("(; code section ;)").eol();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -80,7 +56,9 @@ public class DisassemblyCodeSectionListener implements AddressListener, CodeSect
|
||||||
public void local(int start, int count, WasmHollowType type) {
|
public void local(int start, int count, WasmHollowType type) {
|
||||||
writer.address(address);
|
writer.address(address);
|
||||||
for (int i = 0; i < count; ++i) {
|
for (int i = 0; i < count; ++i) {
|
||||||
writer.write("(local (; " + (i + start) + " ;) " + typeToString(type) + ")").eol();
|
writer.write("(local (; " + (i + start) + " ;) ");
|
||||||
|
writeType(type);
|
||||||
|
writer.write(")").eol();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -100,52 +78,6 @@ public class DisassemblyCodeSectionListener implements AddressListener, CodeSect
|
||||||
writer.outdent().write(")").eol();
|
writer.outdent().write(")").eol();
|
||||||
}
|
}
|
||||||
|
|
||||||
private String blockTypeToString(WasmHollowType type) {
|
|
||||||
if (type == null) {
|
|
||||||
return "";
|
|
||||||
} else {
|
|
||||||
return " " + typeToString(type);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private String typeToString(WasmHollowType type) {
|
|
||||||
if (type != null) {
|
|
||||||
if (type instanceof WasmHollowType.Number) {
|
|
||||||
switch (((WasmHollowType.Number) type).number) {
|
|
||||||
case INT32:
|
|
||||||
return "i32";
|
|
||||||
case INT64:
|
|
||||||
return "i64";
|
|
||||||
case FLOAT32:
|
|
||||||
return "f32";
|
|
||||||
case FLOAT64:
|
|
||||||
return "f64";
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
} else if (type instanceof WasmHollowType.SpecialReference) {
|
|
||||||
switch (((WasmHollowType.SpecialReference) type).kind) {
|
|
||||||
case ANY:
|
|
||||||
return "any";
|
|
||||||
case FUNC:
|
|
||||||
return "func";
|
|
||||||
case ARRAY:
|
|
||||||
return "array";
|
|
||||||
case EXTERN:
|
|
||||||
return "extern";
|
|
||||||
case STRUCT:
|
|
||||||
return "struct";
|
|
||||||
case I31:
|
|
||||||
return "i31";
|
|
||||||
default:
|
|
||||||
throw new IllegalArgumentException();
|
|
||||||
}
|
|
||||||
} else if (type instanceof WasmHollowType.CompositeReference) {
|
|
||||||
return String.valueOf(((WasmHollowType.CompositeReference) type).index);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return "unknown";
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void error(int depth) {
|
public void error(int depth) {
|
||||||
|
@ -160,8 +92,9 @@ public class DisassemblyCodeSectionListener implements AddressListener, CodeSect
|
||||||
public int startBlock(boolean loop, WasmHollowType type) {
|
public int startBlock(boolean loop, WasmHollowType type) {
|
||||||
writer.address(address);
|
writer.address(address);
|
||||||
var label = blockIdGen++;
|
var label = blockIdGen++;
|
||||||
writer.write(loop ? "loop" : "block").write(" $label_" + label).write(blockTypeToString(type))
|
writer.write(loop ? "loop" : "block").write(" $label_" + label);
|
||||||
.indent().eol();
|
writeBlockType(type);
|
||||||
|
writer.indent().eol();
|
||||||
return label;
|
return label;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -169,7 +102,9 @@ public class DisassemblyCodeSectionListener implements AddressListener, CodeSect
|
||||||
public int startConditionalBlock(WasmHollowType type) {
|
public int startConditionalBlock(WasmHollowType type) {
|
||||||
writer.address(address);
|
writer.address(address);
|
||||||
var label = blockIdGen++;
|
var label = blockIdGen++;
|
||||||
writer.write("if ").write(" $label_" + label).write(blockTypeToString(type)).indent().eol();
|
writer.write("if ").write(" $label_" + label);
|
||||||
|
writeBlockType(type);
|
||||||
|
writer.indent().eol();
|
||||||
return label;
|
return label;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -183,7 +118,9 @@ public class DisassemblyCodeSectionListener implements AddressListener, CodeSect
|
||||||
public int startTry(WasmHollowType type) {
|
public int startTry(WasmHollowType type) {
|
||||||
writer.address(address);
|
writer.address(address);
|
||||||
var label = blockIdGen++;
|
var label = blockIdGen++;
|
||||||
writer.write("try ").write(" $label_" + label).write(blockTypeToString(type)).indent().eol();
|
writer.write("try ").write(" $label_" + label);
|
||||||
|
writeBlockType(type);
|
||||||
|
writer.indent().eol();
|
||||||
return label;
|
return label;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -827,7 +764,9 @@ public class DisassemblyCodeSectionListener implements AddressListener, CodeSect
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void nullConstant(WasmHollowType.Reference type) {
|
public void nullConstant(WasmHollowType.Reference type) {
|
||||||
writer.address(address).write("ref.null ").write(typeToString(type)).eol();
|
writer.address(address).write("ref.null ");
|
||||||
|
writeType(type);
|
||||||
|
writer.eol();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -836,7 +775,8 @@ public class DisassemblyCodeSectionListener implements AddressListener, CodeSect
|
||||||
if (!nullable) {
|
if (!nullable) {
|
||||||
writer.write("null ");
|
writer.write("null ");
|
||||||
}
|
}
|
||||||
writer.write(typeToString(type)).write(")").eol();
|
writeType(type);
|
||||||
|
writer.write(")").eol();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -845,7 +785,8 @@ public class DisassemblyCodeSectionListener implements AddressListener, CodeSect
|
||||||
if (!nullable) {
|
if (!nullable) {
|
||||||
writer.write("null ");
|
writer.write("null ");
|
||||||
}
|
}
|
||||||
writer.write(typeToString(type)).write(")").eol();
|
writeType(type);
|
||||||
|
writer.write(")").eol();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -914,28 +855,4 @@ public class DisassemblyCodeSectionListener implements AddressListener, CodeSect
|
||||||
public void int31Get(WasmSignedType signedType) {
|
public void int31Get(WasmSignedType signedType) {
|
||||||
writer.address(address).write("ref.i31_").write(signedType == WasmSignedType.SIGNED ? "s" : "u").eol();
|
writer.address(address).write("ref.i31_").write(signedType == WasmSignedType.SIGNED ? "s" : "u").eol();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void main(String[] args) throws IOException {
|
|
||||||
var file = new File(args[0]);
|
|
||||||
var bytes = Files.readAllBytes(file.toPath());
|
|
||||||
var input = new ByteArrayAsyncInputStream(bytes);
|
|
||||||
var parser = new ModuleParser(input) {
|
|
||||||
@Override
|
|
||||||
protected Consumer<byte[]> getSectionConsumer(int code, int pos, String name) {
|
|
||||||
if (code == 10) {
|
|
||||||
return bytes -> {
|
|
||||||
var out = new PrintWriter(System.out);
|
|
||||||
var writer = new DisassemblyWriter(out, true);
|
|
||||||
var disassembler = new DisassemblyCodeSectionListener(writer);
|
|
||||||
disassembler.setAddressOffset(pos);
|
|
||||||
var sectionParser = new CodeSectionParser(disassembler, disassembler);
|
|
||||||
sectionParser.parse(bytes);
|
|
||||||
out.flush();
|
|
||||||
};
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
input.readFully(parser::parse);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,130 @@
|
||||||
|
/*
|
||||||
|
* 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.AddressListener;
|
||||||
|
import org.teavm.backend.wasm.parser.TypeSectionListener;
|
||||||
|
import org.teavm.backend.wasm.parser.WasmHollowStorageType;
|
||||||
|
import org.teavm.backend.wasm.parser.WasmHollowType;
|
||||||
|
|
||||||
|
public class DisassemblyTypeSectionListener extends BaseDisassemblyListener implements AddressListener,
|
||||||
|
TypeSectionListener {
|
||||||
|
private boolean currentTypeNeedsClosing;
|
||||||
|
private boolean emittingReturn;
|
||||||
|
private int fieldIndex;
|
||||||
|
private boolean needsFieldIndex;
|
||||||
|
|
||||||
|
public DisassemblyTypeSectionListener(DisassemblyWriter writer) {
|
||||||
|
super(writer);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void startRecType(int count) {
|
||||||
|
writer.address(address).write("(rec ").indent().eol();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void endRecType() {
|
||||||
|
writer.outdent().write(")").eol();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void startType(int index, boolean open, int[] supertypes) {
|
||||||
|
writer.address(address).write("(type (; ").write(String.valueOf(index)).write(" ;) ");
|
||||||
|
if (!open || supertypes.length > 0) {
|
||||||
|
currentTypeNeedsClosing = true;
|
||||||
|
writer.write("(sub ");
|
||||||
|
if (!open) {
|
||||||
|
writer.write("final");
|
||||||
|
}
|
||||||
|
for (var supertype : supertypes) {
|
||||||
|
writer.write(supertype + " ");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
writer.indent().eol();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void startArrayType() {
|
||||||
|
writer.address(address).write("(array ").indent().eol();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void endArrayType() {
|
||||||
|
writer.outdent().write(")").eol();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void startStructType(int fieldCount) {
|
||||||
|
needsFieldIndex = true;
|
||||||
|
writer.address(address).write("(struct ").indent().eol();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void field(WasmHollowStorageType hollowType, boolean mutable) {
|
||||||
|
writer.address(address).write("(field ");
|
||||||
|
if (needsFieldIndex) {
|
||||||
|
writer.write("(; " + fieldIndex++ + " ;) ");
|
||||||
|
}
|
||||||
|
if (mutable) {
|
||||||
|
writer.write("(mut ");
|
||||||
|
}
|
||||||
|
writeType(hollowType);
|
||||||
|
if (mutable) {
|
||||||
|
writer.write(")");
|
||||||
|
}
|
||||||
|
writer.write(")").eol();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void endStructType() {
|
||||||
|
writer.outdent().write(")").eol();
|
||||||
|
fieldIndex = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void funcType(int paramCount) {
|
||||||
|
writer.address(address).write("(struct ").indent().eol();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void funcTypeResults(int returnCount) {
|
||||||
|
emittingReturn = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void resultType(WasmHollowType type) {
|
||||||
|
writer.address(address).write("(").write(emittingReturn ? "result" : "param").write(" ");
|
||||||
|
writeType(type);
|
||||||
|
writer.write(")").eol();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void endFuncType() {
|
||||||
|
emittingReturn = false;
|
||||||
|
writer.outdent().write(")").eol();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void endType() {
|
||||||
|
writer.outdent();
|
||||||
|
if (currentTypeNeedsClosing) {
|
||||||
|
writer.write(")");
|
||||||
|
currentTypeNeedsClosing = false;
|
||||||
|
}
|
||||||
|
writer.write(")").eol();
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,191 @@
|
||||||
|
/*
|
||||||
|
* 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 abstract class BaseSectionParser {
|
||||||
|
protected AddressListener addressListener;
|
||||||
|
protected byte[] data;
|
||||||
|
protected int ptr;
|
||||||
|
private int lastReportedPtr = -1;
|
||||||
|
|
||||||
|
public BaseSectionParser(AddressListener addressListener) {
|
||||||
|
this.addressListener = addressListener;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void parse(byte[] data) {
|
||||||
|
this.data = data;
|
||||||
|
ptr = 0;
|
||||||
|
try {
|
||||||
|
parseContent();
|
||||||
|
} finally {
|
||||||
|
this.data = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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() {
|
||||||
|
if (ptr != lastReportedPtr) {
|
||||||
|
lastReportedPtr = ptr;
|
||||||
|
if (addressListener != null) {
|
||||||
|
addressListener.address(ptr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected int readFixedInt() {
|
||||||
|
return ((data[ptr++] & 0xFF) << 24)
|
||||||
|
| ((data[ptr++] & 0xFF) << 16)
|
||||||
|
| ((data[ptr++] & 0xFF) << 8)
|
||||||
|
| (data[ptr++] & 0xFF);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected 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);
|
||||||
|
}
|
||||||
|
}
|
|
@ -15,10 +15,7 @@
|
||||||
*/
|
*/
|
||||||
package org.teavm.backend.wasm.parser;
|
package org.teavm.backend.wasm.parser;
|
||||||
|
|
||||||
public interface CodeSectionListener {
|
public interface CodeSectionListener extends SectionListener {
|
||||||
default void sectionStart(int functionCount) {
|
|
||||||
}
|
|
||||||
|
|
||||||
default boolean functionStart(int index, int size) {
|
default boolean functionStart(int index, int size) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -35,7 +32,4 @@ public interface CodeSectionListener {
|
||||||
|
|
||||||
default void functionEnd() {
|
default void functionEnd() {
|
||||||
}
|
}
|
||||||
|
|
||||||
default void sectionEnd() {
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,31 +28,18 @@ import org.teavm.backend.wasm.model.expression.WasmIntType;
|
||||||
import org.teavm.backend.wasm.model.expression.WasmIntUnaryOperation;
|
import org.teavm.backend.wasm.model.expression.WasmIntUnaryOperation;
|
||||||
import org.teavm.backend.wasm.model.expression.WasmSignedType;
|
import org.teavm.backend.wasm.model.expression.WasmSignedType;
|
||||||
|
|
||||||
public class CodeSectionParser {
|
public class CodeSectionParser extends BaseSectionParser {
|
||||||
private AddressListener addressListener;
|
|
||||||
private CodeSectionListener listener;
|
private CodeSectionListener listener;
|
||||||
private byte[] data;
|
|
||||||
private int ptr;
|
|
||||||
private CodeListener codeListener;
|
private CodeListener codeListener;
|
||||||
private int lastReportedPtr = -1;
|
|
||||||
private List<Block> blockStack = new ArrayList<>();
|
private List<Block> blockStack = new ArrayList<>();
|
||||||
|
|
||||||
public CodeSectionParser(AddressListener addressListener, CodeSectionListener listener) {
|
public CodeSectionParser(AddressListener addressListener, CodeSectionListener listener) {
|
||||||
this.addressListener = addressListener;
|
super(addressListener);
|
||||||
this.listener = listener;
|
this.listener = listener;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void parse(byte[] data) {
|
@Override
|
||||||
this.data = data;
|
protected void parseContent() {
|
||||||
ptr = 0;
|
|
||||||
try {
|
|
||||||
parseFunctions();
|
|
||||||
} finally {
|
|
||||||
this.data = null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void parseFunctions() {
|
|
||||||
reportAddress();
|
reportAddress();
|
||||||
int count = readLEB();
|
int count = readLEB();
|
||||||
listener.sectionStart(count);
|
listener.sectionStart(count);
|
||||||
|
@ -853,144 +840,6 @@ public class CodeSectionParser {
|
||||||
codeListener.tableBranch(depths, targets, defaultDepth, defaultTarget);
|
codeListener.tableBranch(depths, targets, defaultDepth, defaultTarget);
|
||||||
}
|
}
|
||||||
|
|
||||||
private 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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private WasmHollowType.Reference readHeapType() {
|
|
||||||
var typeId = data[ptr];
|
|
||||||
if ((typeId & 0xC0) == 0x40) {
|
|
||||||
var result = readAbsHeapType(typeId);
|
|
||||||
++ptr;
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
return new WasmHollowType.CompositeReference(readLEB());
|
|
||||||
}
|
|
||||||
|
|
||||||
private WasmHollowType.SpecialReference readAbsHeapType(int typeId) {
|
|
||||||
switch (typeId) {
|
|
||||||
case 0x70:
|
|
||||||
return WasmHollowType.Reference.FUNC;
|
|
||||||
case 0x6F:
|
|
||||||
return WasmHollowType.Reference.EXTERN;
|
|
||||||
case 0x6E:
|
|
||||||
return WasmHollowType.Reference.ANY;
|
|
||||||
case 0x6C:
|
|
||||||
return WasmHollowType.Reference.I31;
|
|
||||||
case 0x6B:
|
|
||||||
return WasmHollowType.Reference.STRUCT;
|
|
||||||
case 0x6A:
|
|
||||||
return WasmHollowType.Reference.ARRAY;
|
|
||||||
default:
|
|
||||||
throw new ParseException("Unknown type", ptr);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void reportAddress() {
|
|
||||||
if (ptr != lastReportedPtr) {
|
|
||||||
lastReportedPtr = ptr;
|
|
||||||
if (addressListener != null) {
|
|
||||||
addressListener.address(ptr);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private 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;
|
|
||||||
}
|
|
||||||
|
|
||||||
private 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;
|
|
||||||
}
|
|
||||||
|
|
||||||
private 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;
|
|
||||||
}
|
|
||||||
|
|
||||||
private 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;
|
|
||||||
}
|
|
||||||
|
|
||||||
private int readFixedInt() {
|
|
||||||
return ((data[ptr++] & 0xFF) << 24)
|
|
||||||
| ((data[ptr++] & 0xFF) << 16)
|
|
||||||
| ((data[ptr++] & 0xFF) << 8)
|
|
||||||
| (data[ptr++] & 0xFF);
|
|
||||||
}
|
|
||||||
|
|
||||||
private long readFixedLong() {
|
|
||||||
return ((data[ptr++] & 0xFFL) << 56)
|
|
||||||
| ((data[ptr++] & 0xFFL) << 48)
|
|
||||||
| ((data[ptr++] & 0xFFL) << 40)
|
|
||||||
| ((data[ptr++] & 0xFFL) << 32)
|
|
||||||
| ((data[ptr++] & 0xFFL) << 24)
|
|
||||||
| ((data[ptr++] & 0xFF) << 16)
|
|
||||||
| ((data[ptr++] & 0xFF) << 8)
|
|
||||||
| (data[ptr++] & 0xFF);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static class Block {
|
private static class Block {
|
||||||
int token;
|
int token;
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,24 @@
|
||||||
|
/*
|
||||||
|
* 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 SectionListener {
|
||||||
|
default void sectionStart(int functionCount) {
|
||||||
|
}
|
||||||
|
|
||||||
|
default void sectionEnd() {
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,57 @@
|
||||||
|
/*
|
||||||
|
* 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 TypeSectionListener extends SectionListener {
|
||||||
|
default void startRecType(int count) {
|
||||||
|
}
|
||||||
|
|
||||||
|
default void endRecType() {
|
||||||
|
}
|
||||||
|
|
||||||
|
default void startType(int index, boolean open, int[] supertypes) {
|
||||||
|
}
|
||||||
|
|
||||||
|
default void startArrayType() {
|
||||||
|
}
|
||||||
|
|
||||||
|
default void endArrayType() {
|
||||||
|
}
|
||||||
|
|
||||||
|
default void startStructType(int fieldCount) {
|
||||||
|
}
|
||||||
|
|
||||||
|
default void field(WasmHollowStorageType hollowType, boolean mutable) {
|
||||||
|
}
|
||||||
|
|
||||||
|
default void endStructType() {
|
||||||
|
}
|
||||||
|
|
||||||
|
default void funcType(int paramCount) {
|
||||||
|
}
|
||||||
|
|
||||||
|
default void funcTypeResults(int returnCount) {
|
||||||
|
}
|
||||||
|
|
||||||
|
default void resultType(WasmHollowType type) {
|
||||||
|
}
|
||||||
|
|
||||||
|
default void endFuncType() {
|
||||||
|
}
|
||||||
|
|
||||||
|
default void endType() {
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,138 @@
|
||||||
|
/*
|
||||||
|
* 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 TypeSectionParser extends BaseSectionParser {
|
||||||
|
private TypeSectionListener listener;
|
||||||
|
private int typeIndex;
|
||||||
|
|
||||||
|
public TypeSectionParser(AddressListener addressListener, TypeSectionListener listener) {
|
||||||
|
super(addressListener);
|
||||||
|
this.listener = listener;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void parseContent() {
|
||||||
|
reportAddress();
|
||||||
|
int count = readLEB();
|
||||||
|
listener.sectionStart(count);
|
||||||
|
for (var i = 0; i < count; ++i) {
|
||||||
|
parseType();
|
||||||
|
}
|
||||||
|
reportAddress();
|
||||||
|
listener.sectionEnd();
|
||||||
|
typeIndex = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void parseType() {
|
||||||
|
if (data[ptr] == 0x4E) {
|
||||||
|
parseRecType();
|
||||||
|
} else {
|
||||||
|
parseSubtype();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void parseRecType() {
|
||||||
|
reportAddress();
|
||||||
|
++ptr;
|
||||||
|
var count = readLEB();
|
||||||
|
listener.startRecType(count);
|
||||||
|
for (var i = 0; i < count; ++i) {
|
||||||
|
parseSubtype();
|
||||||
|
}
|
||||||
|
listener.endRecType();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void parseSubtype() {
|
||||||
|
switch (data[ptr]) {
|
||||||
|
case 0x50:
|
||||||
|
reportAddress();
|
||||||
|
++ptr;
|
||||||
|
parseCompositeType(true, readSupertypes());
|
||||||
|
break;
|
||||||
|
case 0x4F:
|
||||||
|
reportAddress();
|
||||||
|
++ptr;
|
||||||
|
parseCompositeType(false, readSupertypes());
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
parseCompositeType(true, new int[0]);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void parseCompositeType(boolean open, int[] supertypes) {
|
||||||
|
reportAddress();
|
||||||
|
listener.startType(typeIndex++, open, supertypes);
|
||||||
|
switch (data[ptr]) {
|
||||||
|
case 0x5E:
|
||||||
|
reportAddress();
|
||||||
|
++ptr;
|
||||||
|
listener.startArrayType();
|
||||||
|
parseField();
|
||||||
|
listener.endArrayType();
|
||||||
|
break;
|
||||||
|
case 0x5F: {
|
||||||
|
reportAddress();
|
||||||
|
++ptr;
|
||||||
|
var fieldCount = readLEB();
|
||||||
|
listener.startStructType(fieldCount);
|
||||||
|
for (var i = 0; i < fieldCount; ++i) {
|
||||||
|
parseField();
|
||||||
|
}
|
||||||
|
listener.endStructType();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 0x60: {
|
||||||
|
reportAddress();
|
||||||
|
++ptr;
|
||||||
|
var paramCount = readLEB();
|
||||||
|
listener.funcType(paramCount);
|
||||||
|
for (var i = 0; i < paramCount; ++i) {
|
||||||
|
reportAddress();
|
||||||
|
listener.resultType(readType());
|
||||||
|
}
|
||||||
|
var resultCount = readLEB();
|
||||||
|
listener.funcTypeResults(resultCount);
|
||||||
|
for (var i = 0; i < resultCount; ++i) {
|
||||||
|
reportAddress();
|
||||||
|
listener.resultType(readType());
|
||||||
|
}
|
||||||
|
listener.endFuncType();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
throw new ParseException("Unknown type declaration", ptr);
|
||||||
|
}
|
||||||
|
listener.endType();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void parseField() {
|
||||||
|
reportAddress();
|
||||||
|
var type = readStorageType();
|
||||||
|
var mutable = data[ptr++] != 0;
|
||||||
|
listener.field(type, mutable);
|
||||||
|
}
|
||||||
|
|
||||||
|
private int[] readSupertypes() {
|
||||||
|
var count = readLEB();
|
||||||
|
var result = new int[count];
|
||||||
|
for (var i = 0; i < count; ++i) {
|
||||||
|
result[i] = readLEB();
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,65 @@
|
||||||
|
/*
|
||||||
|
* 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 org.teavm.backend.wasm.model.WasmPackedType;
|
||||||
|
|
||||||
|
public abstract class WasmHollowStorageType {
|
||||||
|
public static final Packed INT16 = new Packed(WasmPackedType.INT16);
|
||||||
|
public static final Packed INT8 = new Packed(WasmPackedType.INT8);
|
||||||
|
|
||||||
|
private WasmHollowStorageType() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public abstract WasmHollowType asUnpackedType();
|
||||||
|
|
||||||
|
public static Packed packed(WasmPackedType type) {
|
||||||
|
switch (type) {
|
||||||
|
case INT8:
|
||||||
|
return INT8;
|
||||||
|
case INT16:
|
||||||
|
return INT16;
|
||||||
|
default:
|
||||||
|
throw new IllegalArgumentException();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static final class Regular extends WasmHollowStorageType {
|
||||||
|
public final WasmHollowType type;
|
||||||
|
|
||||||
|
Regular(WasmHollowType type) {
|
||||||
|
this.type = type;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public WasmHollowType asUnpackedType() {
|
||||||
|
return type;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static final class Packed extends WasmHollowStorageType {
|
||||||
|
public final WasmPackedType type;
|
||||||
|
|
||||||
|
private Packed(WasmPackedType type) {
|
||||||
|
this.type = type;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public WasmHollowType asUnpackedType() {
|
||||||
|
return WasmHollowType.INT32;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user