wasm gc: trying to generate types according to unclear spec

This commit is contained in:
Alexey Andreev 2024-07-28 21:04:18 +02:00
parent a281c19363
commit ea29208b6c
8 changed files with 161 additions and 4 deletions

View File

@ -131,6 +131,7 @@ public class WasmGCTarget implements TeaVMTarget {
var binaryWriter = new WasmBinaryWriter(); var binaryWriter = new WasmBinaryWriter();
var binaryRenderer = new WasmBinaryRenderer(binaryWriter, WasmBinaryVersion.V_0x1, obfuscated, var binaryRenderer = new WasmBinaryRenderer(binaryWriter, WasmBinaryVersion.V_0x1, obfuscated,
null, null, null, null, WasmBinaryStatsCollector.EMPTY); null, null, null, null, WasmBinaryStatsCollector.EMPTY);
module.prepareForRendering();
binaryRenderer.render(module); binaryRenderer.render(module);
var data = binaryWriter.getData(); var data = binaryWriter.getData();
if (!outputName.endsWith(".wasm")) { if (!outputName.endsWith(".wasm")) {

View File

@ -30,6 +30,10 @@ public class WasmCollection<T extends WasmEntity> implements Iterable<T> {
WasmCollection() { WasmCollection() {
} }
public T get(int index) {
return items.get(index);
}
public int size() { public int size() {
return items.size(); return items.size();
} }
@ -57,6 +61,13 @@ public class WasmCollection<T extends WasmEntity> implements Iterable<T> {
} }
} }
public void clear() {
for (var item : items) {
item.collection = null;
}
items.clear();
}
void invalidateIndexes() { void invalidateIndexes() {
indexesInvalid = true; indexesInvalid = true;
} }

View File

@ -18,6 +18,8 @@ package org.teavm.backend.wasm.model;
public abstract class WasmCompositeType extends WasmEntity { public abstract class WasmCompositeType extends WasmEntity {
private String name; private String name;
private WasmType.CompositeReference reference; private WasmType.CompositeReference reference;
int indexInRecursiveType = -1;
int recursiveTypeCount = -1;
WasmCompositeType(String name) { WasmCompositeType(String name) {
this.name = name; this.name = name;
@ -34,5 +36,13 @@ public abstract class WasmCompositeType extends WasmEntity {
return reference; return reference;
} }
public int getIndexInRecursiveType() {
return indexInRecursiveType;
}
public int getRecursiveTypeCount() {
return recursiveTypeCount;
}
public abstract void acceptVisitor(WasmCompositeTypeVisitor visitor); public abstract void acceptVisitor(WasmCompositeTypeVisitor visitor);
} }

View File

@ -20,6 +20,7 @@ import java.util.Collections;
import java.util.LinkedHashMap; import java.util.LinkedHashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import org.teavm.common.GraphUtils;
public class WasmModule { public class WasmModule {
private int minMemorySize; private int minMemorySize;
@ -90,4 +91,34 @@ public class WasmModule {
public void setStartFunction(WasmFunction startFunction) { public void setStartFunction(WasmFunction startFunction) {
this.startFunction = startFunction; this.startFunction = startFunction;
} }
public void prepareForRendering() {
prepareRecursiveTypes();
}
private void prepareRecursiveTypes() {
var typeGraph = WasmTypeGraphBuilder.buildTypeGraph(types, types.size());
var newList = new ArrayList<WasmCompositeType>();
var typesInScc = new boolean[types.size()];
for (var scc : GraphUtils.findStronglyConnectedComponents(typeGraph)) {
var firstType = types.get(scc[0]);
firstType.recursiveTypeCount = scc.length;
for (var i = 0; i < scc.length; i++) {
var index = scc[i];
var type = types.get(index);
newList.add(type);
type.indexInRecursiveType = i;
typesInScc[index] = true;
}
}
for (var type : types) {
if (!typesInScc[type.index]) {
newList.add(type);
}
}
types.clear();
for (var type : newList) {
types.add(type);
}
}
} }

View File

@ -0,0 +1,72 @@
/*
* 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.model;
import org.teavm.common.Graph;
import org.teavm.common.GraphBuilder;
final class WasmTypeGraphBuilder {
private WasmTypeGraphBuilder() {
}
static Graph buildTypeGraph(Iterable<WasmCompositeType> types, int size) {
var graphBuilder = new GraphBuilder(size);
var visitor = new GraphBuilderVisitor(graphBuilder);
for (var type : types) {
visitor.currentIndex = type.index;
type.acceptVisitor(visitor);
}
return graphBuilder.build();
}
private static class GraphBuilderVisitor implements WasmCompositeTypeVisitor {
final GraphBuilder graphBuilder;
int currentIndex;
GraphBuilderVisitor(GraphBuilder graphBuilder) {
this.graphBuilder = graphBuilder;
}
@Override
public void visit(WasmStructure type) {
for (var field : type.getFields()) {
addEdge(field.asUnpackedType());
}
}
@Override
public void visit(WasmArray type) {
addEdge(type.getElementType().asUnpackedType());
}
@Override
public void visit(WasmFunctionType type) {
for (var parameter : type.getParameterTypes()) {
addEdge(parameter);
}
if (type.getReturnType() != null) {
addEdge(type.getReturnType());
}
}
private void addEdge(WasmType type) {
if (type instanceof WasmType.CompositeReference) {
var composite = ((WasmType.CompositeReference) type).composite;
graphBuilder.addEdge(currentIndex, composite.index);
}
}
}
}

View File

@ -103,9 +103,30 @@ public class WasmBinaryRenderer {
var section = new WasmBinaryWriter(); var section = new WasmBinaryWriter();
var typeRenderer = new WasmCompositeTypeBinaryRenderer(module, section); var typeRenderer = new WasmCompositeTypeBinaryRenderer(module, section);
section.writeLEB(module.types.size()); var recTypeCount = 0;
for (var type : module.types) { for (var i = 0; i < module.types.size();) {
type.acceptVisitor(typeRenderer); var type = module.types.get(i);
if (type.getRecursiveTypeCount() > 0) {
i += type.getRecursiveTypeCount();
} else {
++i;
}
recTypeCount++;
}
section.writeLEB(recTypeCount);
for (var i = 0; i < module.types.size();) {
var type = module.types.get(i);
if (type.getRecursiveTypeCount() > 0) {
section.writeByte(0x4E);
section.writeLEB(type.getRecursiveTypeCount());
for (var j = 0; j < type.getRecursiveTypeCount(); ++j) {
var subtype = module.types.get(i++);
subtype.acceptVisitor(typeRenderer);
}
} else {
type.acceptVisitor(typeRenderer);
++i;
}
} }
writeSection(SECTION_TYPE, "type", section.getData()); writeSection(SECTION_TYPE, "type", section.getData());

View File

@ -30,6 +30,10 @@ public class WasmBinaryWriter {
} }
public void writeType(WasmType type, WasmModule module) { public void writeType(WasmType type, WasmModule module) {
writeType(type, module, false);
}
public void writeType(WasmType type, WasmModule module, boolean isRecursiveMember) {
if (type == null) { if (type == null) {
writeByte(0x40); writeByte(0x40);
return; return;
@ -55,7 +59,12 @@ public class WasmBinaryWriter {
break; break;
} }
} else if (type instanceof WasmType.CompositeReference) { } else if (type instanceof WasmType.CompositeReference) {
writeSignedLEB(module.types.indexOf(((WasmType.CompositeReference) type).composite)); writeByte(0x63);
var composite = ((WasmType.CompositeReference) type).composite;
var index = isRecursiveMember
? composite.getIndexInRecursiveType()
: module.types.indexOf(composite);
writeSignedLEB(index);
} }
} }

View File

@ -25,6 +25,7 @@ import org.teavm.backend.wasm.model.WasmStructure;
public class WasmCompositeTypeBinaryRenderer implements WasmCompositeTypeVisitor { public class WasmCompositeTypeBinaryRenderer implements WasmCompositeTypeVisitor {
private WasmModule module; private WasmModule module;
private WasmBinaryWriter section; private WasmBinaryWriter section;
private boolean reference;
public WasmCompositeTypeBinaryRenderer(WasmModule module, WasmBinaryWriter section) { public WasmCompositeTypeBinaryRenderer(WasmModule module, WasmBinaryWriter section) {
this.module = module; this.module = module;
@ -43,6 +44,7 @@ public class WasmCompositeTypeBinaryRenderer implements WasmCompositeTypeVisitor
@Override @Override
public void visit(WasmArray type) { public void visit(WasmArray type) {
section.writeByte(0x5E);
writeStorageType(type.getElementType()); writeStorageType(type.getElementType());
section.writeLEB(0x01); // mutable section.writeLEB(0x01); // mutable
} }