mirror of
https://github.com/Eaglercraft-TeaVM-Fork/eagler-teavm.git
synced 2024-12-22 16:14:10 -08:00
Wasm: working on parser
This commit is contained in:
parent
b58dd1a37b
commit
aaed8e312a
|
@ -0,0 +1,105 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2022 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 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.WasmType;
|
||||||
|
import org.teavm.backend.wasm.parser.CodeSectionListener;
|
||||||
|
import org.teavm.backend.wasm.parser.CodeSectionParser;
|
||||||
|
import org.teavm.backend.wasm.parser.ModuleParser;
|
||||||
|
import org.teavm.common.ByteArrayAsyncInputStream;
|
||||||
|
|
||||||
|
public class DisasmCodeSectionListener implements CodeSectionListener {
|
||||||
|
private PrintWriter writer;
|
||||||
|
|
||||||
|
public DisasmCodeSectionListener(PrintWriter writer) {
|
||||||
|
this.writer = writer;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void address(int address) {
|
||||||
|
writer.print("(; ");
|
||||||
|
for (int i = 7; i >= 0; --i) {
|
||||||
|
var digit = (address >>> (i * 4)) & 0xF;
|
||||||
|
writer.print(Character.forDigit(digit, 16));
|
||||||
|
}
|
||||||
|
writer.print(" ;)");
|
||||||
|
writer.println();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void sectionStart(int functionCount) {
|
||||||
|
writer.println(" .code functions=" + functionCount);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean functionStart(int index, int size) {
|
||||||
|
writer.println(" function fn_" + index);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void localsStart(int count) {
|
||||||
|
writer.println(" locals " + count);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void local(int start, int count, WasmType type) {
|
||||||
|
for (int i = 0; i < count; ++i) {
|
||||||
|
writer.println(" local " + (i + start) + ": " + type);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void localsEnd() {
|
||||||
|
writer.println(" end_locals");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void functionEnd() {
|
||||||
|
writer.println(" end_function");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void sectionEnd() {
|
||||||
|
writer.println(" end_code");
|
||||||
|
}
|
||||||
|
|
||||||
|
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 writer = new PrintWriter(System.out);
|
||||||
|
var sectionParser = new CodeSectionParser(new DisasmCodeSectionListener(writer));
|
||||||
|
sectionParser.parse(bytes);
|
||||||
|
writer.flush();
|
||||||
|
};
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
input.readFully(parser::parse);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,36 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2022 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.WasmType;
|
||||||
|
|
||||||
|
public interface CodeSectionListener {
|
||||||
|
void address(int address);
|
||||||
|
|
||||||
|
void sectionStart(int functionCount);
|
||||||
|
|
||||||
|
boolean functionStart(int index, int size);
|
||||||
|
|
||||||
|
void localsStart(int count);
|
||||||
|
|
||||||
|
void local(int start, int count, WasmType type);
|
||||||
|
|
||||||
|
void localsEnd();
|
||||||
|
|
||||||
|
void functionEnd();
|
||||||
|
|
||||||
|
void sectionEnd();
|
||||||
|
}
|
|
@ -0,0 +1,115 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2022 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.WasmType;
|
||||||
|
|
||||||
|
public class CodeSectionParser {
|
||||||
|
private CodeSectionListener listener;
|
||||||
|
private byte[] data;
|
||||||
|
private int ptr;
|
||||||
|
private int lastReportedPtr = -1;
|
||||||
|
|
||||||
|
public CodeSectionParser(CodeSectionListener listener) {
|
||||||
|
this.listener = listener;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void parse(byte[] data) {
|
||||||
|
this.data = data;
|
||||||
|
ptr = 0;
|
||||||
|
try {
|
||||||
|
parseFunctions();
|
||||||
|
} finally {
|
||||||
|
this.data = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void parseFunctions() {
|
||||||
|
reportAddress();
|
||||||
|
int count = readLEB();
|
||||||
|
listener.sectionStart(count);
|
||||||
|
for (var i = 0; i < count; ++i) {
|
||||||
|
parseFunction(i);
|
||||||
|
}
|
||||||
|
reportAddress();
|
||||||
|
listener.sectionEnd();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void parseFunction(int index) {
|
||||||
|
reportAddress();
|
||||||
|
var functionSize = readLEB();
|
||||||
|
var end = ptr + functionSize;
|
||||||
|
if (listener.functionStart(index, functionSize)) {
|
||||||
|
parseLocals();
|
||||||
|
}
|
||||||
|
ptr = end;
|
||||||
|
reportAddress();
|
||||||
|
listener.functionEnd();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void parseLocals() {
|
||||||
|
reportAddress();
|
||||||
|
var localEntries = readLEB();
|
||||||
|
listener.localsStart(localEntries);
|
||||||
|
var localIndex = 0;
|
||||||
|
for (int i = 0; i < localEntries; ++i) {
|
||||||
|
reportAddress();
|
||||||
|
var countInGroup = readLEB();
|
||||||
|
var type = readType();
|
||||||
|
listener.local(localIndex, countInGroup, type);
|
||||||
|
localIndex += countInGroup;
|
||||||
|
}
|
||||||
|
reportAddress();
|
||||||
|
listener.localsEnd();
|
||||||
|
}
|
||||||
|
|
||||||
|
private WasmType readType() {
|
||||||
|
var typeId = data[ptr];
|
||||||
|
switch (typeId) {
|
||||||
|
case 0x7F:
|
||||||
|
return WasmType.INT32;
|
||||||
|
case 0x7E:
|
||||||
|
return WasmType.INT64;
|
||||||
|
case 0x7D:
|
||||||
|
return WasmType.FLOAT32;
|
||||||
|
case 0x7C:
|
||||||
|
return WasmType.FLOAT64;
|
||||||
|
default:
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void reportAddress() {
|
||||||
|
if (ptr != lastReportedPtr) {
|
||||||
|
lastReportedPtr = ptr;
|
||||||
|
listener.address(ptr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user