mirror of
https://github.com/Eaglercraft-TeaVM-Fork/eagler-teavm.git
synced 2025-01-08 16:04:10 -08:00
Further work on WASM binary format generator
This commit is contained in:
parent
c70ba8f16d
commit
d0def96dba
|
@ -17,8 +17,6 @@ package org.teavm.backend.wasm;
|
|||
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.io.OutputStreamWriter;
|
||||
import java.io.Writer;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
|
@ -66,7 +64,8 @@ import org.teavm.backend.wasm.model.expression.WasmReturn;
|
|||
import org.teavm.backend.wasm.model.expression.WasmSetLocal;
|
||||
import org.teavm.backend.wasm.model.expression.WasmStoreInt32;
|
||||
import org.teavm.backend.wasm.patches.ClassPatch;
|
||||
import org.teavm.backend.wasm.render.WasmCRenderer;
|
||||
import org.teavm.backend.wasm.render.WasmBinaryRenderer;
|
||||
import org.teavm.backend.wasm.render.WasmBinaryWriter;
|
||||
import org.teavm.dependency.ClassDependency;
|
||||
import org.teavm.dependency.DependencyChecker;
|
||||
import org.teavm.dependency.DependencyListener;
|
||||
|
@ -272,14 +271,13 @@ public class WasmTarget implements TeaVMTarget {
|
|||
module.getFunctionTable().add(module.getFunctions().get(function));
|
||||
}
|
||||
|
||||
WasmCRenderer renderer = new WasmCRenderer();
|
||||
renderer.setOutputLineNumbers(debugging);
|
||||
WasmBinaryWriter writer = new WasmBinaryWriter();
|
||||
WasmBinaryRenderer renderer = new WasmBinaryRenderer(writer);
|
||||
renderer.render(module);
|
||||
|
||||
try {
|
||||
Writer writer = new OutputStreamWriter(output, "UTF-8");
|
||||
writer.append(renderer.toString());
|
||||
writer.flush();
|
||||
output.write(writer.getData());
|
||||
output.flush();
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
|
|
|
@ -0,0 +1,290 @@
|
|||
/*
|
||||
* Copyright 2016 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.render;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Collectors;
|
||||
import org.teavm.backend.wasm.model.WasmFunction;
|
||||
import org.teavm.backend.wasm.model.WasmMemorySegment;
|
||||
import org.teavm.backend.wasm.model.WasmModule;
|
||||
import org.teavm.backend.wasm.model.WasmType;
|
||||
import org.teavm.backend.wasm.model.expression.WasmExpression;
|
||||
|
||||
public class WasmBinaryRenderer {
|
||||
private WasmBinaryWriter output;
|
||||
private List<WasmSignature> signatures = new ArrayList<>();
|
||||
private Map<WasmSignature, Integer> signatureIndexes = new HashMap<>();
|
||||
private Map<String, Integer> importIndexes = new HashMap<>();
|
||||
private Map<String, Integer> functionIndexes = new HashMap<>();
|
||||
|
||||
public WasmBinaryRenderer(WasmBinaryWriter output) {
|
||||
this.output = output;
|
||||
}
|
||||
|
||||
public void render(WasmModule module) {
|
||||
output.writeInt32(0x6d736100);
|
||||
output.writeInt32(11);
|
||||
renderSignatures(module);
|
||||
renderImports(module);
|
||||
renderFunctions(module);
|
||||
renderTable(module);
|
||||
renderMemory(module);
|
||||
renderExport(module);
|
||||
renderStart(module);
|
||||
renderCode(module);
|
||||
renderData(module);
|
||||
}
|
||||
|
||||
private void renderSignatures(WasmModule module) {
|
||||
WasmBinaryWriter section = new WasmBinaryWriter();
|
||||
WasmSignatureCollector signatureCollector = new WasmSignatureCollector(this::registerSignature);
|
||||
|
||||
for (WasmFunction function : module.getFunctions().values()) {
|
||||
registerSignature(WasmSignature.fromFunction(function));
|
||||
for (WasmExpression part : function.getBody()) {
|
||||
part.acceptVisitor(signatureCollector);
|
||||
}
|
||||
}
|
||||
|
||||
section.writeLEB(signatures.size());
|
||||
for (WasmSignature signature : signatures) {
|
||||
section.writeByte(0x40);
|
||||
section.writeLEB(signature.types.length - 1);
|
||||
for (int i = 1; i < signature.types.length; ++i) {
|
||||
section.writeType(signature.types[i]);
|
||||
}
|
||||
if (signature.types[0] != null) {
|
||||
section.writeByte(1);
|
||||
section.writeType(signature.types[0]);
|
||||
} else {
|
||||
section.writeByte(0);
|
||||
}
|
||||
}
|
||||
|
||||
writeSection("type", section.getData());
|
||||
}
|
||||
|
||||
private void renderImports(WasmModule module) {
|
||||
int index = 0;
|
||||
List<WasmFunction> functions = new ArrayList<>();
|
||||
for (WasmFunction function : module.getFunctions().values()) {
|
||||
if (function.getImportName() == null) {
|
||||
continue;
|
||||
}
|
||||
functions.add(function);
|
||||
importIndexes.put(function.getName(), index++);
|
||||
}
|
||||
if (functions.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
WasmBinaryWriter section = new WasmBinaryWriter();
|
||||
|
||||
section.writeLEB(functions.size());
|
||||
for (WasmFunction function : functions) {
|
||||
WasmSignature signature = WasmSignature.fromFunction(function);
|
||||
section.writeLEB(signatureIndexes.get(signature));
|
||||
|
||||
String moduleName = function.getImportModule();
|
||||
if (moduleName == null) {
|
||||
moduleName = "";
|
||||
}
|
||||
section.writeAsciiString(moduleName);
|
||||
|
||||
section.writeAsciiString(function.getImportName());
|
||||
}
|
||||
|
||||
writeSection("import", section.getData());
|
||||
}
|
||||
|
||||
private void renderFunctions(WasmModule module) {
|
||||
WasmBinaryWriter section = new WasmBinaryWriter();
|
||||
|
||||
int index = 0;
|
||||
List<WasmFunction> functions = module.getFunctions().values().stream()
|
||||
.filter(function -> function.getImportName() == null)
|
||||
.collect(Collectors.toList());
|
||||
for (WasmFunction function : functions) {
|
||||
functionIndexes.put(function.getName(), index++);
|
||||
}
|
||||
|
||||
section.writeLEB(functions.size());
|
||||
for (WasmFunction function : functions) {
|
||||
WasmSignature signature = WasmSignature.fromFunction(function);
|
||||
section.writeLEB(signatureIndexes.get(signature));
|
||||
}
|
||||
|
||||
writeSection("function", section.getData());
|
||||
}
|
||||
|
||||
private void renderTable(WasmModule module) {
|
||||
if (module.getFunctionTable().isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
WasmBinaryWriter section = new WasmBinaryWriter();
|
||||
|
||||
section.writeLEB(module.getFunctionTable().size());
|
||||
for (WasmFunction function : module.getFunctionTable()) {
|
||||
section.writeLEB(functionIndexes.get(function.getName()));
|
||||
}
|
||||
|
||||
writeSection("table", section.getData());
|
||||
}
|
||||
|
||||
private void renderMemory(WasmModule module) {
|
||||
WasmBinaryWriter section = new WasmBinaryWriter();
|
||||
|
||||
section.writeLEB(module.getMemorySize());
|
||||
section.writeLEB(module.getMemorySize());
|
||||
section.writeByte(0);
|
||||
|
||||
writeSection("memory", section.getData());
|
||||
}
|
||||
|
||||
private void renderExport(WasmModule module) {
|
||||
List<WasmFunction> functions = module.getFunctions().values().stream()
|
||||
.filter(function -> function.getExportName() != null)
|
||||
.collect(Collectors.toList());
|
||||
if (functions.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
WasmBinaryWriter section = new WasmBinaryWriter();
|
||||
|
||||
section.writeLEB(functions.size());
|
||||
for (WasmFunction function : functions) {
|
||||
section.writeLEB(functionIndexes.get(function.getName()));
|
||||
|
||||
section.writeAsciiString(function.getExportName());
|
||||
}
|
||||
|
||||
writeSection("export", section.getData());
|
||||
}
|
||||
|
||||
private void renderStart(WasmModule module) {
|
||||
if (module.getStartFunction() == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
WasmBinaryWriter section = new WasmBinaryWriter();
|
||||
section.writeLEB(functionIndexes.get(module.getStartFunction().getName()));
|
||||
|
||||
writeSection("start", section.getData());
|
||||
}
|
||||
|
||||
private void renderCode(WasmModule module) {
|
||||
WasmBinaryWriter section = new WasmBinaryWriter();
|
||||
|
||||
List<WasmFunction> functions = module.getFunctions().values().stream()
|
||||
.filter(function -> function.getImportName() == null)
|
||||
.collect(Collectors.toList());
|
||||
|
||||
section.writeLEB(functions.size());
|
||||
for (WasmFunction function : functions) {
|
||||
if (function.getLocalVariables().isEmpty()) {
|
||||
section.writeLEB(0);
|
||||
} else {
|
||||
List<LocalEntry> localEntries = new ArrayList<>();
|
||||
LocalEntry currentEntry = new LocalEntry(function.getLocalVariables().get(0).getType());
|
||||
for (int i = 1; i < function.getLocalVariables().size(); ++i) {
|
||||
WasmType type = function.getLocalVariables().get(i).getType();
|
||||
if (currentEntry.type == type) {
|
||||
currentEntry.count++;
|
||||
} else {
|
||||
localEntries.add(currentEntry);
|
||||
currentEntry = new LocalEntry(type);
|
||||
}
|
||||
}
|
||||
localEntries.add(currentEntry);
|
||||
|
||||
section.writeLEB(localEntries.size());
|
||||
for (LocalEntry entry : localEntries) {
|
||||
section.writeLEB(entry.count);
|
||||
section.writeType(entry.type);
|
||||
}
|
||||
}
|
||||
|
||||
System.out.println(function.getName() + ": " + (output.getPosition() + section.getPosition()));
|
||||
|
||||
byte[] body = renderFunction(function);
|
||||
section.writeLEB(body.length);
|
||||
section.writeBytes(body);
|
||||
}
|
||||
|
||||
writeSection("code", section.getData());
|
||||
}
|
||||
|
||||
private byte[] renderFunction(WasmFunction function) {
|
||||
WasmBinaryWriter code = new WasmBinaryWriter();
|
||||
|
||||
WasmBinaryRenderingVisitor visitor = new WasmBinaryRenderingVisitor(code, functionIndexes, importIndexes,
|
||||
signatureIndexes);
|
||||
for (WasmExpression part : function.getBody()) {
|
||||
part.acceptVisitor(visitor);
|
||||
}
|
||||
|
||||
return code.getData();
|
||||
}
|
||||
|
||||
private void renderData(WasmModule module) {
|
||||
if (module.getSegments().isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
WasmBinaryWriter section = new WasmBinaryWriter();
|
||||
|
||||
section.writeLEB(module.getSegments().size());
|
||||
for (WasmMemorySegment segment : module.getSegments()) {
|
||||
section.writeLEB(segment.getOffset());
|
||||
section.writeLEB(segment.getLength());
|
||||
int chunkSize = 65536;
|
||||
for (int i = 0; i < segment.getLength(); i += chunkSize) {
|
||||
int next = Math.min(i + chunkSize, segment.getLength());
|
||||
section.writeBytes(segment.getData(i, next - i));
|
||||
}
|
||||
}
|
||||
|
||||
writeSection("data", section.getData());
|
||||
}
|
||||
|
||||
static class LocalEntry {
|
||||
WasmType type;
|
||||
int count = 1;
|
||||
|
||||
public LocalEntry(WasmType type) {
|
||||
this.type = type;
|
||||
}
|
||||
}
|
||||
|
||||
private void registerSignature(WasmSignature signature) {
|
||||
signatureIndexes.computeIfAbsent(signature, key -> {
|
||||
int result = signatures.size();
|
||||
signatures.add(key);
|
||||
return result;
|
||||
});
|
||||
}
|
||||
|
||||
private void writeSection(String id, byte[] data) {
|
||||
output.writeAsciiString(id);
|
||||
|
||||
output.writeLEB(data.length);
|
||||
output.writeBytes(data);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,784 @@
|
|||
/*
|
||||
* Copyright 2016 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.render;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import org.teavm.backend.wasm.model.WasmType;
|
||||
import org.teavm.backend.wasm.model.expression.WasmBlock;
|
||||
import org.teavm.backend.wasm.model.expression.WasmBranch;
|
||||
import org.teavm.backend.wasm.model.expression.WasmBreak;
|
||||
import org.teavm.backend.wasm.model.expression.WasmCall;
|
||||
import org.teavm.backend.wasm.model.expression.WasmConditional;
|
||||
import org.teavm.backend.wasm.model.expression.WasmConversion;
|
||||
import org.teavm.backend.wasm.model.expression.WasmDrop;
|
||||
import org.teavm.backend.wasm.model.expression.WasmExpression;
|
||||
import org.teavm.backend.wasm.model.expression.WasmExpressionVisitor;
|
||||
import org.teavm.backend.wasm.model.expression.WasmFloat32Constant;
|
||||
import org.teavm.backend.wasm.model.expression.WasmFloat64Constant;
|
||||
import org.teavm.backend.wasm.model.expression.WasmFloatBinary;
|
||||
import org.teavm.backend.wasm.model.expression.WasmFloatUnary;
|
||||
import org.teavm.backend.wasm.model.expression.WasmGetLocal;
|
||||
import org.teavm.backend.wasm.model.expression.WasmIndirectCall;
|
||||
import org.teavm.backend.wasm.model.expression.WasmInt32Constant;
|
||||
import org.teavm.backend.wasm.model.expression.WasmInt64Constant;
|
||||
import org.teavm.backend.wasm.model.expression.WasmIntBinary;
|
||||
import org.teavm.backend.wasm.model.expression.WasmIntUnary;
|
||||
import org.teavm.backend.wasm.model.expression.WasmLoadFloat32;
|
||||
import org.teavm.backend.wasm.model.expression.WasmLoadFloat64;
|
||||
import org.teavm.backend.wasm.model.expression.WasmLoadInt32;
|
||||
import org.teavm.backend.wasm.model.expression.WasmLoadInt64;
|
||||
import org.teavm.backend.wasm.model.expression.WasmReturn;
|
||||
import org.teavm.backend.wasm.model.expression.WasmSetLocal;
|
||||
import org.teavm.backend.wasm.model.expression.WasmStoreFloat32;
|
||||
import org.teavm.backend.wasm.model.expression.WasmStoreFloat64;
|
||||
import org.teavm.backend.wasm.model.expression.WasmStoreInt32;
|
||||
import org.teavm.backend.wasm.model.expression.WasmStoreInt64;
|
||||
import org.teavm.backend.wasm.model.expression.WasmSwitch;
|
||||
import org.teavm.backend.wasm.model.expression.WasmUnreachable;
|
||||
|
||||
class WasmBinaryRenderingVisitor implements WasmExpressionVisitor {
|
||||
private WasmBinaryWriter writer;
|
||||
private Map<String, Integer> functionIndexes;
|
||||
private Map<String, Integer> importedIndexes;
|
||||
private Map<WasmSignature, Integer> signatureIndexes;
|
||||
private int depth;
|
||||
private Map<WasmBlock, Integer> blockDepths = new HashMap<>();
|
||||
|
||||
WasmBinaryRenderingVisitor(WasmBinaryWriter writer, Map<String, Integer> functionIndexes,
|
||||
Map<String, Integer> importedIndexes, Map<WasmSignature, Integer> signatureIndexes) {
|
||||
this.writer = writer;
|
||||
this.functionIndexes = functionIndexes;
|
||||
this.importedIndexes = importedIndexes;
|
||||
this.signatureIndexes = signatureIndexes;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(WasmBlock expression) {
|
||||
++depth;
|
||||
blockDepths.put(expression, depth);
|
||||
writer.writeByte(0x01);
|
||||
for (WasmExpression part : expression.getBody()) {
|
||||
part.acceptVisitor(this);
|
||||
}
|
||||
writer.writeByte(0x0F);
|
||||
blockDepths.remove(expression);
|
||||
--depth;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(WasmBranch expression) {
|
||||
if (expression.getResult() != null) {
|
||||
expression.getResult().acceptVisitor(this);
|
||||
}
|
||||
expression.getCondition().acceptVisitor(this);
|
||||
writer.writeByte(0x07);
|
||||
writer.writeByte(expression.getResult() != null ? 1 : 0);
|
||||
writeLabel(expression.getTarget());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(WasmBreak expression) {
|
||||
if (expression.getResult() != null) {
|
||||
expression.getResult().acceptVisitor(this);
|
||||
}
|
||||
writer.writeByte(0x06);
|
||||
writer.writeByte(expression.getResult() != null ? 1 : 0);
|
||||
writeLabel(expression.getTarget());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(WasmSwitch expression) {
|
||||
expression.getSelector().acceptVisitor(this);
|
||||
writer.writeByte(0x08);
|
||||
writer.writeByte(0);
|
||||
writer.writeLEB(expression.getTargets().size());
|
||||
expression.getTargets().forEach(this::writeLabel);
|
||||
writeLabel(expression.getDefaultTarget());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(WasmConditional expression) {
|
||||
expression.getCondition().acceptVisitor(this);
|
||||
writer.writeByte(0x03);
|
||||
|
||||
++depth;
|
||||
blockDepths.put(expression.getThenBlock(), depth);
|
||||
for (WasmExpression part : expression.getThenBlock().getBody()) {
|
||||
part.acceptVisitor(this);
|
||||
}
|
||||
blockDepths.remove(expression.getThenBlock());
|
||||
|
||||
if (!expression.getElseBlock().getBody().isEmpty()) {
|
||||
writer.writeByte(0x04);
|
||||
blockDepths.put(expression.getElseBlock(), depth);
|
||||
for (WasmExpression part : expression.getElseBlock().getBody()) {
|
||||
part.acceptVisitor(this);
|
||||
}
|
||||
blockDepths.remove(expression.getElseBlock());
|
||||
}
|
||||
--depth;
|
||||
|
||||
writer.writeByte(0x0F);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(WasmReturn expression) {
|
||||
if (expression.getValue() != null) {
|
||||
expression.getValue().acceptVisitor(this);
|
||||
}
|
||||
writer.writeByte(0x09);
|
||||
writer.writeByte(expression.getValue() != null ? 1 : 0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(WasmUnreachable expression) {
|
||||
writer.writeByte(0x0A);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(WasmInt32Constant expression) {
|
||||
writer.writeByte(0x10);
|
||||
writer.writeSignedLEB(expression.getValue());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(WasmInt64Constant expression) {
|
||||
writer.writeByte(0x11);
|
||||
writer.writeSignedLEB(expression.getValue());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(WasmFloat32Constant expression) {
|
||||
writer.writeByte(0x13);
|
||||
writer.writeLEB(Float.floatToRawIntBits(expression.getValue()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(WasmFloat64Constant expression) {
|
||||
writer.writeByte(0x12);
|
||||
writer.writeLEB(Double.doubleToRawLongBits(expression.getValue()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(WasmGetLocal expression) {
|
||||
writer.writeByte(0x14);
|
||||
writer.writeLEB(expression.getLocal().getIndex());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(WasmSetLocal expression) {
|
||||
expression.getValue().acceptVisitor(this);
|
||||
writer.writeByte(0x15);
|
||||
writer.writeLEB(expression.getLocal().getIndex());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(WasmIntBinary expression) {
|
||||
expression.getFirst().acceptVisitor(this);
|
||||
expression.getSecond().acceptVisitor(this);
|
||||
switch (expression.getType()) {
|
||||
case INT32:
|
||||
switch (expression.getOperation()) {
|
||||
case ADD:
|
||||
writer.writeByte(0x40);
|
||||
break;
|
||||
case SUB:
|
||||
writer.writeByte(0x41);
|
||||
break;
|
||||
case MUL:
|
||||
writer.writeByte(0x42);
|
||||
break;
|
||||
case DIV_SIGNED:
|
||||
writer.writeByte(0x43);
|
||||
break;
|
||||
case DIV_UNSIGNED:
|
||||
writer.writeByte(0x44);
|
||||
break;
|
||||
case REM_SIGNED:
|
||||
writer.writeByte(0x45);
|
||||
break;
|
||||
case REM_UNSIGNED:
|
||||
writer.writeByte(0x46);
|
||||
break;
|
||||
case AND:
|
||||
writer.writeByte(0x47);
|
||||
break;
|
||||
case OR:
|
||||
writer.writeByte(0x48);
|
||||
break;
|
||||
case XOR:
|
||||
writer.writeByte(0x49);
|
||||
break;
|
||||
case SHL:
|
||||
writer.writeByte(0x4A);
|
||||
break;
|
||||
case SHR_UNSIGNED:
|
||||
writer.writeByte(0x4B);
|
||||
break;
|
||||
case SHR_SIGNED:
|
||||
writer.writeByte(0x4C);
|
||||
break;
|
||||
case ROTR:
|
||||
writer.writeByte(0xB6);
|
||||
break;
|
||||
case ROTL:
|
||||
writer.writeByte(0xB7);
|
||||
break;
|
||||
case EQ:
|
||||
writer.writeByte(0x4D);
|
||||
break;
|
||||
case NE:
|
||||
writer.writeByte(0x4E);
|
||||
break;
|
||||
case LT_SIGNED:
|
||||
writer.writeByte(0x4F);
|
||||
break;
|
||||
case LE_SIGNED:
|
||||
writer.writeByte(0x50);
|
||||
break;
|
||||
case LT_UNSIGNED:
|
||||
writer.writeByte(0x51);
|
||||
break;
|
||||
case LE_UNSIGNED:
|
||||
writer.writeByte(0x52);
|
||||
break;
|
||||
case GT_SIGNED:
|
||||
writer.writeByte(0x53);
|
||||
break;
|
||||
case GE_SIGNED:
|
||||
writer.writeByte(0x54);
|
||||
break;
|
||||
case GT_UNSIGNED:
|
||||
writer.writeByte(0x55);
|
||||
break;
|
||||
case GE_UNSIGNED:
|
||||
writer.writeByte(0x56);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case INT64:
|
||||
switch (expression.getOperation()) {
|
||||
case ADD:
|
||||
writer.writeByte(0x5B);
|
||||
break;
|
||||
case SUB:
|
||||
writer.writeByte(0x5C);
|
||||
break;
|
||||
case MUL:
|
||||
writer.writeByte(0x5D);
|
||||
break;
|
||||
case DIV_SIGNED:
|
||||
writer.writeByte(0x5E);
|
||||
break;
|
||||
case DIV_UNSIGNED:
|
||||
writer.writeByte(0x5F);
|
||||
break;
|
||||
case REM_SIGNED:
|
||||
writer.writeByte(0x60);
|
||||
break;
|
||||
case REM_UNSIGNED:
|
||||
writer.writeByte(0x61);
|
||||
break;
|
||||
case AND:
|
||||
writer.writeByte(0x62);
|
||||
break;
|
||||
case OR:
|
||||
writer.writeByte(0x63);
|
||||
break;
|
||||
case XOR:
|
||||
writer.writeByte(0x64);
|
||||
break;
|
||||
case SHL:
|
||||
writer.writeByte(0x65);
|
||||
break;
|
||||
case SHR_UNSIGNED:
|
||||
writer.writeByte(0x66);
|
||||
break;
|
||||
case SHR_SIGNED:
|
||||
writer.writeByte(0x67);
|
||||
break;
|
||||
case ROTR:
|
||||
writer.writeByte(0xB8);
|
||||
break;
|
||||
case ROTL:
|
||||
writer.writeByte(0xB9);
|
||||
break;
|
||||
case EQ:
|
||||
writer.writeByte(0x68);
|
||||
break;
|
||||
case NE:
|
||||
writer.writeByte(0x69);
|
||||
break;
|
||||
case LT_SIGNED:
|
||||
writer.writeByte(0x6A);
|
||||
break;
|
||||
case LE_SIGNED:
|
||||
writer.writeByte(0x6B);
|
||||
break;
|
||||
case LT_UNSIGNED:
|
||||
writer.writeByte(0x6C);
|
||||
break;
|
||||
case LE_UNSIGNED:
|
||||
writer.writeByte(0x6D);
|
||||
break;
|
||||
case GT_SIGNED:
|
||||
writer.writeByte(0x6E);
|
||||
break;
|
||||
case GE_SIGNED:
|
||||
writer.writeByte(0x6F);
|
||||
break;
|
||||
case GT_UNSIGNED:
|
||||
writer.writeByte(0x70);
|
||||
break;
|
||||
case GE_UNSIGNED:
|
||||
writer.writeByte(0x71);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(WasmFloatBinary expression) {
|
||||
expression.getFirst().acceptVisitor(this);
|
||||
expression.getSecond().acceptVisitor(this);
|
||||
switch (expression.getType()) {
|
||||
case FLOAT32:
|
||||
switch (expression.getOperation()) {
|
||||
case ADD:
|
||||
writer.writeByte(0x75);
|
||||
break;
|
||||
case SUB:
|
||||
writer.writeByte(0x76);
|
||||
break;
|
||||
case MUL:
|
||||
writer.writeByte(0x77);
|
||||
break;
|
||||
case DIV:
|
||||
writer.writeByte(0x78);
|
||||
break;
|
||||
case MIN:
|
||||
writer.writeByte(0x79);
|
||||
break;
|
||||
case MAX:
|
||||
writer.writeByte(0x7A);
|
||||
break;
|
||||
case EQ:
|
||||
writer.writeByte(0x83);
|
||||
break;
|
||||
case NE:
|
||||
writer.writeByte(0x84);
|
||||
break;
|
||||
case LT:
|
||||
writer.writeByte(0x85);
|
||||
break;
|
||||
case LE:
|
||||
writer.writeByte(0x86);
|
||||
break;
|
||||
case GT:
|
||||
writer.writeByte(0x87);
|
||||
break;
|
||||
case GE:
|
||||
writer.writeByte(0x88);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case FLOAT64:
|
||||
switch (expression.getOperation()) {
|
||||
case ADD:
|
||||
writer.writeByte(0x89);
|
||||
break;
|
||||
case SUB:
|
||||
writer.writeByte(0x8A);
|
||||
break;
|
||||
case MUL:
|
||||
writer.writeByte(0x8B);
|
||||
break;
|
||||
case DIV:
|
||||
writer.writeByte(0x8C);
|
||||
break;
|
||||
case MIN:
|
||||
writer.writeByte(0x8D);
|
||||
break;
|
||||
case MAX:
|
||||
writer.writeByte(0x8E);
|
||||
break;
|
||||
case EQ:
|
||||
writer.writeByte(0x97);
|
||||
break;
|
||||
case NE:
|
||||
writer.writeByte(0x98);
|
||||
break;
|
||||
case LT:
|
||||
writer.writeByte(0x99);
|
||||
break;
|
||||
case LE:
|
||||
writer.writeByte(0x9A);
|
||||
break;
|
||||
case GT:
|
||||
writer.writeByte(0x9B);
|
||||
break;
|
||||
case GE:
|
||||
writer.writeByte(0x9C);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(WasmIntUnary expression) {
|
||||
expression.getOperand().acceptVisitor(this);
|
||||
switch (expression.getType()) {
|
||||
case INT32:
|
||||
switch (expression.getOperation()) {
|
||||
case CLZ:
|
||||
writer.writeByte(0x57);
|
||||
break;
|
||||
case CTZ:
|
||||
writer.writeByte(0x58);
|
||||
break;
|
||||
case POPCNT:
|
||||
writer.writeByte(0x59);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case INT64:
|
||||
switch (expression.getOperation()) {
|
||||
case CLZ:
|
||||
writer.writeByte(0x72);
|
||||
break;
|
||||
case CTZ:
|
||||
writer.writeByte(0x73);
|
||||
break;
|
||||
case POPCNT:
|
||||
writer.writeByte(0x74);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(WasmFloatUnary expression) {
|
||||
expression.getOperand().acceptVisitor(this);
|
||||
switch (expression.getType()) {
|
||||
case FLOAT32:
|
||||
switch (expression.getOperation()) {
|
||||
case ABS:
|
||||
writer.writeByte(0x7B);
|
||||
break;
|
||||
case NEG:
|
||||
writer.writeByte(0x7C);
|
||||
break;
|
||||
case COPYSIGN:
|
||||
writer.writeByte(0x7D);
|
||||
break;
|
||||
case CEIL:
|
||||
writer.writeByte(0x7E);
|
||||
break;
|
||||
case FLOOR:
|
||||
writer.writeByte(0x7F);
|
||||
break;
|
||||
case TRUNC:
|
||||
writer.writeByte(0x80);
|
||||
break;
|
||||
case NEAREST:
|
||||
writer.writeByte(0x81);
|
||||
break;
|
||||
case SQRT:
|
||||
writer.writeByte(0x82);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case FLOAT64:
|
||||
switch (expression.getOperation()) {
|
||||
case ABS:
|
||||
writer.writeByte(0x8F);
|
||||
break;
|
||||
case NEG:
|
||||
writer.writeByte(0x90);
|
||||
break;
|
||||
case COPYSIGN:
|
||||
writer.writeByte(0x91);
|
||||
break;
|
||||
case CEIL:
|
||||
writer.writeByte(0x92);
|
||||
break;
|
||||
case FLOOR:
|
||||
writer.writeByte(0x93);
|
||||
break;
|
||||
case TRUNC:
|
||||
writer.writeByte(0x94);
|
||||
break;
|
||||
case NEAREST:
|
||||
writer.writeByte(0x95);
|
||||
break;
|
||||
case SQRT:
|
||||
writer.writeByte(0x96);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(WasmConversion expression) {
|
||||
expression.getOperand().acceptVisitor(this);
|
||||
|
||||
switch (expression.getSourceType()) {
|
||||
case INT32:
|
||||
switch (expression.getTargetType()) {
|
||||
case INT32:
|
||||
break;
|
||||
case INT64:
|
||||
writer.writeByte(expression.isSigned() ? 0xA6 : 0xA7);
|
||||
break;
|
||||
case FLOAT32:
|
||||
writer.writeByte(expression.isSigned() ? 0xA8 : 0xA9);
|
||||
break;
|
||||
case FLOAT64:
|
||||
writer.writeByte(expression.isSigned() ? 0xAE : 0xAF);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case INT64:
|
||||
switch (expression.getTargetType()) {
|
||||
case INT32:
|
||||
writer.writeByte(0xA1);
|
||||
break;
|
||||
case INT64:
|
||||
break;
|
||||
case FLOAT32:
|
||||
writer.writeByte(expression.isSigned() ? 0xAA : 0xAB);
|
||||
break;
|
||||
case FLOAT64:
|
||||
writer.writeByte(expression.isSigned() ? 0xB0 : 0xB1);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case FLOAT32:
|
||||
switch (expression.getTargetType()) {
|
||||
case INT32:
|
||||
writer.writeByte(expression.isSigned() ? 0x9D : 0x9F);
|
||||
break;
|
||||
case INT64:
|
||||
writer.writeByte(expression.isSigned() ? 0xA2 : 0xA4);
|
||||
break;
|
||||
case FLOAT32:
|
||||
break;
|
||||
case FLOAT64:
|
||||
writer.writeByte(0xB2);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case FLOAT64:
|
||||
switch (expression.getTargetType()) {
|
||||
case INT32:
|
||||
writer.writeByte(expression.isSigned() ? 0x9E : 0xA0);
|
||||
break;
|
||||
case INT64:
|
||||
writer.writeByte(expression.isSigned() ? 0xA3 : 0xA5);
|
||||
break;
|
||||
case FLOAT32:
|
||||
writer.writeByte(0xAC);
|
||||
break;
|
||||
case FLOAT64:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(WasmCall expression) {
|
||||
for (WasmExpression argument : expression.getArguments()) {
|
||||
argument.acceptVisitor(this);
|
||||
}
|
||||
writer.writeByte(!expression.isImported() ? 0x16 : 0x18);
|
||||
writer.writeLEB(expression.getArguments().size());
|
||||
writer.writeLEB(!expression.isImported()
|
||||
? functionIndexes.get(expression.getFunctionName())
|
||||
: importedIndexes.get(expression.getFunctionName()));
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(WasmIndirectCall expression) {
|
||||
expression.getSelector().acceptVisitor(this);
|
||||
for (WasmExpression argument : expression.getArguments()) {
|
||||
argument.acceptVisitor(this);
|
||||
}
|
||||
writer.writeByte(0x17);
|
||||
writer.writeLEB(expression.getArguments().size());
|
||||
|
||||
WasmType[] signatureTypes = new WasmType[expression.getParameterTypes().size() + 1];
|
||||
signatureTypes[0] = expression.getReturnType();
|
||||
for (int i = 0; i < expression.getParameterTypes().size(); ++i) {
|
||||
signatureTypes[i + 1] = expression.getParameterTypes().get(i);
|
||||
}
|
||||
writer.writeLEB(signatureIndexes.get(new WasmSignature(signatureTypes)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(WasmDrop expression) {
|
||||
expression.getOperand().acceptVisitor(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(WasmLoadInt32 expression) {
|
||||
expression.getIndex().acceptVisitor(this);
|
||||
switch (expression.getConvertFrom()) {
|
||||
case INT8:
|
||||
writer.writeByte(0x20);
|
||||
break;
|
||||
case UINT8:
|
||||
writer.writeByte(0x21);
|
||||
break;
|
||||
case INT16:
|
||||
writer.writeByte(0x22);
|
||||
break;
|
||||
case UINT16:
|
||||
writer.writeByte(0x23);
|
||||
break;
|
||||
case INT32:
|
||||
writer.writeByte(0x2A);
|
||||
break;
|
||||
}
|
||||
writer.writeByte(getAlignment(expression.getAlignment()));
|
||||
writer.writeByte(0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(WasmLoadInt64 expression) {
|
||||
expression.getIndex().acceptVisitor(this);
|
||||
switch (expression.getConvertFrom()) {
|
||||
case INT8:
|
||||
writer.writeByte(0x24);
|
||||
break;
|
||||
case UINT8:
|
||||
writer.writeByte(0x25);
|
||||
break;
|
||||
case INT16:
|
||||
writer.writeByte(0x26);
|
||||
break;
|
||||
case UINT16:
|
||||
writer.writeByte(0x27);
|
||||
break;
|
||||
case INT32:
|
||||
writer.writeByte(0x28);
|
||||
break;
|
||||
case UINT32:
|
||||
writer.writeByte(0x29);
|
||||
break;
|
||||
case INT64:
|
||||
writer.writeByte(0x2B);
|
||||
break;
|
||||
}
|
||||
writer.writeByte(getAlignment(expression.getAlignment()));
|
||||
writer.writeByte(0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(WasmLoadFloat32 expression) {
|
||||
expression.getIndex().acceptVisitor(this);
|
||||
writer.writeByte(0x2C);
|
||||
writer.writeByte(getAlignment(expression.getAlignment()));
|
||||
writer.writeByte(0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(WasmLoadFloat64 expression) {
|
||||
expression.getIndex().acceptVisitor(this);
|
||||
writer.writeByte(0x2D);
|
||||
writer.writeByte(getAlignment(expression.getAlignment()));
|
||||
writer.writeByte(0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(WasmStoreInt32 expression) {
|
||||
expression.getIndex().acceptVisitor(this);
|
||||
expression.getValue().acceptVisitor(this);
|
||||
switch (expression.getConvertTo()) {
|
||||
case INT8:
|
||||
case UINT8:
|
||||
writer.writeByte(0x2E);
|
||||
break;
|
||||
case INT16:
|
||||
case UINT16:
|
||||
writer.writeByte(0x2F);
|
||||
break;
|
||||
case INT32:
|
||||
writer.writeByte(0x33);
|
||||
break;
|
||||
}
|
||||
writer.writeByte(getAlignment(expression.getAlignment()));
|
||||
writer.writeByte(0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(WasmStoreInt64 expression) {
|
||||
expression.getIndex().acceptVisitor(this);
|
||||
expression.getValue().acceptVisitor(this);
|
||||
switch (expression.getConvertTo()) {
|
||||
case INT8:
|
||||
case UINT8:
|
||||
writer.writeByte(0x30);
|
||||
break;
|
||||
case INT16:
|
||||
case UINT16:
|
||||
writer.writeByte(0x31);
|
||||
break;
|
||||
case INT32:
|
||||
case UINT32:
|
||||
writer.writeByte(0x32);
|
||||
break;
|
||||
case INT64:
|
||||
writer.writeByte(0x34);
|
||||
break;
|
||||
}
|
||||
writer.writeByte(getAlignment(expression.getAlignment()));
|
||||
writer.writeByte(0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(WasmStoreFloat32 expression) {
|
||||
expression.getIndex().acceptVisitor(this);
|
||||
expression.getValue().acceptVisitor(this);
|
||||
writer.writeByte(0x35);
|
||||
writer.writeByte(getAlignment(expression.getAlignment()));
|
||||
writer.writeByte(0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(WasmStoreFloat64 expression) {
|
||||
expression.getIndex().acceptVisitor(this);
|
||||
expression.getValue().acceptVisitor(this);
|
||||
writer.writeByte(0x36);
|
||||
writer.writeByte(getAlignment(expression.getAlignment()));
|
||||
writer.writeByte(0);
|
||||
}
|
||||
|
||||
private int getAlignment(int alignment) {
|
||||
return 31 - Integer.numberOfLeadingZeros(Math.min(1, alignment));
|
||||
}
|
||||
|
||||
private void writeLabel(WasmBlock target) {
|
||||
int blockDepth = blockDepths.get(target);
|
||||
writer.writeLEB(depth - blockDepth);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,157 @@
|
|||
/*
|
||||
* Copyright 2016 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.render;
|
||||
|
||||
import java.util.Arrays;
|
||||
import org.teavm.backend.wasm.model.WasmType;
|
||||
|
||||
public class WasmBinaryWriter {
|
||||
private byte[] data = new byte[1024];
|
||||
private int pointer;
|
||||
|
||||
public void writeByte(int v) {
|
||||
alloc(1);
|
||||
data[pointer++] = (byte) v;
|
||||
}
|
||||
|
||||
public void writeType(WasmType type) {
|
||||
switch (type) {
|
||||
case INT32:
|
||||
writeByte(1);
|
||||
break;
|
||||
case INT64:
|
||||
writeByte(2);
|
||||
break;
|
||||
case FLOAT32:
|
||||
writeByte(3);
|
||||
break;
|
||||
case FLOAT64:
|
||||
writeByte(4);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public int getPosition() {
|
||||
return pointer;
|
||||
}
|
||||
|
||||
public void writeBytes(byte[] bytes) {
|
||||
alloc(bytes.length);
|
||||
System.arraycopy(bytes, 0, data, pointer, bytes.length);
|
||||
pointer += bytes.length;
|
||||
}
|
||||
|
||||
public void writeAsciiString(String str) {
|
||||
writeLEB(str.length());
|
||||
byte[] bytes = new byte[str.length()];
|
||||
for (int i = 0; i < str.length(); ++i) {
|
||||
bytes[i] = (byte) str.charAt(i);
|
||||
}
|
||||
writeBytes(bytes);
|
||||
}
|
||||
|
||||
public void writeInt32(int v) {
|
||||
alloc(4);
|
||||
for (int i = 0; i < 4; ++i) {
|
||||
data[pointer++] = (byte) (v & 0xFF);
|
||||
v >>>= 8;
|
||||
}
|
||||
}
|
||||
|
||||
public void writeLEB(int v) {
|
||||
alloc(5);
|
||||
while (true) {
|
||||
int digit = v & 0x7F;
|
||||
int next = v >>> 7;
|
||||
boolean last = next == 0;
|
||||
if (!last) {
|
||||
digit |= 0xFFFFFF80;
|
||||
}
|
||||
data[pointer++] = (byte) digit;
|
||||
if (last) {
|
||||
break;
|
||||
}
|
||||
v = next;
|
||||
}
|
||||
}
|
||||
|
||||
public void writeSignedLEB(int v) {
|
||||
alloc(5);
|
||||
boolean negative = v < 0;
|
||||
while (true) {
|
||||
int digit = (!negative ? v : (v << 25 >> 25)) & 0x7F;
|
||||
int next = v >>> 7;
|
||||
boolean last = next == 0;
|
||||
if (!last) {
|
||||
digit |= 0xFFFFFF80;
|
||||
}
|
||||
data[pointer++] = (byte) digit;
|
||||
if (last) {
|
||||
break;
|
||||
}
|
||||
v = next;
|
||||
}
|
||||
}
|
||||
|
||||
public void writeLEB(long v) {
|
||||
alloc(10);
|
||||
while (true) {
|
||||
int digit = (int) (v & 0x7F);
|
||||
long next = v >>> 7;
|
||||
boolean last = next == 0;
|
||||
if (!last) {
|
||||
digit |= 0xFFFFFF80;
|
||||
}
|
||||
data[pointer++] = (byte) digit;
|
||||
if (last) {
|
||||
break;
|
||||
}
|
||||
v = next;
|
||||
}
|
||||
}
|
||||
|
||||
public void writeSignedLEB(long v) {
|
||||
alloc(10);
|
||||
boolean negative = v < 0;
|
||||
while (true) {
|
||||
int digit = (int) ((!negative ? v : (v << 25 >> 25)) & 0x7F);
|
||||
long next = v >>> 7;
|
||||
boolean last = next == 0;
|
||||
if (!last) {
|
||||
digit |= 0xFFFFFF80;
|
||||
}
|
||||
data[pointer++] = (byte) digit;
|
||||
if (last) {
|
||||
break;
|
||||
}
|
||||
v = next;
|
||||
}
|
||||
}
|
||||
|
||||
private void alloc(int size) {
|
||||
if (data.length - pointer < size) {
|
||||
int newLength = data.length * 2;
|
||||
if (newLength < pointer + size) {
|
||||
newLength = (pointer + size) * 2;
|
||||
}
|
||||
data = Arrays.copyOf(data, newLength);
|
||||
}
|
||||
}
|
||||
|
||||
public byte[] getData() {
|
||||
return Arrays.copyOf(data, pointer);
|
||||
}
|
||||
}
|
|
@ -20,7 +20,6 @@ import org.teavm.backend.wasm.model.WasmFunction;
|
|||
import org.teavm.backend.wasm.model.WasmLocal;
|
||||
import org.teavm.backend.wasm.model.WasmMemorySegment;
|
||||
import org.teavm.backend.wasm.model.WasmModule;
|
||||
import org.teavm.backend.wasm.model.WasmType;
|
||||
import org.teavm.backend.wasm.model.expression.WasmExpression;
|
||||
|
||||
public class WasmRenderer {
|
||||
|
@ -143,23 +142,14 @@ public class WasmRenderer {
|
|||
}
|
||||
|
||||
private void renderSignature(WasmFunction function) {
|
||||
WasmSignature signature = signatureFromFunction(function);
|
||||
WasmSignature signature = WasmSignature.fromFunction(function);
|
||||
visitor.append(" ").open().append("type $type" + visitor.getSignatureIndex(signature)).close();
|
||||
}
|
||||
|
||||
private WasmSignature signatureFromFunction(WasmFunction function) {
|
||||
WasmType[] types = new WasmType[function.getParameters().size() + 1];
|
||||
types[0] = function.getResult();
|
||||
for (int i = 0; i < function.getParameters().size(); ++i) {
|
||||
types[i + 1] = function.getParameters().get(i);
|
||||
}
|
||||
return new WasmSignature(types);
|
||||
}
|
||||
|
||||
private void renderTypes(WasmModule module) {
|
||||
WasmSignatureCollector signatureCollector = new WasmSignatureCollector(visitor);
|
||||
WasmSignatureCollector signatureCollector = new WasmSignatureCollector(visitor::getSignatureIndex);
|
||||
for (WasmFunction function : module.getFunctions().values()) {
|
||||
visitor.getSignatureIndex(signatureFromFunction(function));
|
||||
visitor.getSignatureIndex(WasmSignature.fromFunction(function));
|
||||
for (WasmExpression part : function.getBody()) {
|
||||
part.acceptVisitor(signatureCollector);
|
||||
}
|
||||
|
|
|
@ -16,12 +16,13 @@
|
|||
package org.teavm.backend.wasm.render;
|
||||
|
||||
import java.util.Arrays;
|
||||
import org.teavm.backend.wasm.model.WasmFunction;
|
||||
import org.teavm.backend.wasm.model.WasmType;
|
||||
|
||||
class WasmSignature {
|
||||
final class WasmSignature {
|
||||
WasmType[] types;
|
||||
|
||||
public WasmSignature(WasmType[] types) {
|
||||
WasmSignature(WasmType[] types) {
|
||||
this.types = types;
|
||||
}
|
||||
|
||||
|
@ -41,4 +42,13 @@ class WasmSignature {
|
|||
public int hashCode() {
|
||||
return Arrays.hashCode(types);
|
||||
}
|
||||
|
||||
public static WasmSignature fromFunction(WasmFunction function) {
|
||||
WasmType[] types = new WasmType[function.getParameters().size() + 1];
|
||||
types[0] = function.getResult();
|
||||
for (int i = 0; i < function.getParameters().size(); ++i) {
|
||||
types[i + 1] = function.getParameters().get(i);
|
||||
}
|
||||
return new WasmSignature(types);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -15,15 +15,16 @@
|
|||
*/
|
||||
package org.teavm.backend.wasm.render;
|
||||
|
||||
import java.util.function.Consumer;
|
||||
import org.teavm.backend.wasm.model.WasmType;
|
||||
import org.teavm.backend.wasm.model.expression.WasmDefaultExpressionVisitor;
|
||||
import org.teavm.backend.wasm.model.expression.WasmIndirectCall;
|
||||
|
||||
class WasmSignatureCollector extends WasmDefaultExpressionVisitor {
|
||||
WasmRenderingVisitor renderingVisitor;
|
||||
private Consumer<WasmSignature> consumer;
|
||||
|
||||
public WasmSignatureCollector(WasmRenderingVisitor renderingVisitor) {
|
||||
this.renderingVisitor = renderingVisitor;
|
||||
public WasmSignatureCollector(Consumer<WasmSignature> consumer) {
|
||||
this.consumer = consumer;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -34,6 +35,6 @@ class WasmSignatureCollector extends WasmDefaultExpressionVisitor {
|
|||
types[i + 1] = expression.getParameterTypes().get(i);
|
||||
}
|
||||
|
||||
renderingVisitor.getSignatureIndex(new WasmSignature(types));
|
||||
consumer.accept(new WasmSignature(types));
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue
Block a user