mirror of
https://github.com/Eaglercraft-TeaVM-Fork/eagler-teavm.git
synced 2024-12-22 00:04:10 -08:00
wasm gc: generate field names and write them to name section
This commit is contained in:
parent
29f29cea1d
commit
eb0eb1f146
|
@ -33,6 +33,7 @@ import org.teavm.backend.wasm.WasmFunctionTypes;
|
|||
import org.teavm.backend.wasm.generate.gc.WasmGCInitializerContributor;
|
||||
import org.teavm.backend.wasm.generate.gc.strings.WasmGCStringPool;
|
||||
import org.teavm.backend.wasm.model.WasmArray;
|
||||
import org.teavm.backend.wasm.model.WasmField;
|
||||
import org.teavm.backend.wasm.model.WasmFunction;
|
||||
import org.teavm.backend.wasm.model.WasmFunctionType;
|
||||
import org.teavm.backend.wasm.model.WasmGlobal;
|
||||
|
@ -73,6 +74,8 @@ public class WasmGCClassGenerator implements WasmGCClassInfoProvider, WasmGCInit
|
|||
private static final MethodDescriptor CLINIT_METHOD_DESC = new MethodDescriptor("<clinit>", ValueType.VOID);
|
||||
private static final MethodDescriptor GET_CLASS_METHOD = new MethodDescriptor("getClass",
|
||||
ValueType.parse(Class.class));
|
||||
private static final FieldReference FAKE_CLASS_FIELD = new FieldReference(Object.class.getName(), "class");
|
||||
private static final FieldReference FAKE_MONITOR_FIELD = new FieldReference(Object.class.getName(), "monitor");
|
||||
|
||||
private final WasmModule module;
|
||||
private ClassReaderSource classSource;
|
||||
|
@ -259,7 +262,7 @@ public class WasmGCClassGenerator implements WasmGCClassInfoProvider, WasmGCInit
|
|||
}
|
||||
if (!isInterface) {
|
||||
fillFields(classInfo, type);
|
||||
}
|
||||
}
|
||||
}
|
||||
var pointerName = names.forClassInstance(type);
|
||||
classInfo.hasOwnVirtualTable = virtualTable != null && virtualTable.hasValidEntries();
|
||||
|
@ -411,7 +414,7 @@ public class WasmGCClassGenerator implements WasmGCClassInfoProvider, WasmGCInit
|
|||
&& !method.equals(GET_CLASS_METHOD)) {
|
||||
var fieldIndex = virtualTableFieldOffset + entry.getIndex();
|
||||
var expectedType = (WasmType.CompositeReference) structure.getFields().get(fieldIndex)
|
||||
.asUnpackedType();
|
||||
.getUnpackedType();
|
||||
var expectedFunctionType = (WasmFunctionType) expectedType.composite;
|
||||
var function = functionProvider.forInstanceMethod(entry.getImplementor());
|
||||
if (!virtualTable.getClassName().equals(entry.getImplementor().getClassName())
|
||||
|
@ -444,24 +447,34 @@ public class WasmGCClassGenerator implements WasmGCClassInfoProvider, WasmGCInit
|
|||
var structure = new WasmStructure(names.forClassClass(className));
|
||||
structure.setSupertype(standardClasses.classClass().getStructure());
|
||||
module.types.add(structure);
|
||||
structure.getFields().add(standardClasses.classClass().getType().asStorage());
|
||||
structure.getFields().add(WasmType.Reference.ANY.asStorage());
|
||||
addSystemFields(structure.getFields());
|
||||
fillSimpleClassFields(structure.getFields(), "java.lang.Class");
|
||||
addVirtualTableFields(structure, virtualTable);
|
||||
return structure;
|
||||
}
|
||||
|
||||
private void addSystemFields(List<WasmField> fields) {
|
||||
var classField = new WasmField(standardClasses.classClass().getType().asStorage());
|
||||
classField.setName(names.forMemberField(FAKE_CLASS_FIELD));
|
||||
fields.add(classField);
|
||||
var monitorField = new WasmField(WasmType.Reference.ANY.asStorage());
|
||||
monitorField.setName(names.forMemberField(FAKE_MONITOR_FIELD));
|
||||
fields.add(monitorField);
|
||||
}
|
||||
|
||||
private void addVirtualTableFields(WasmStructure structure, VirtualTable virtualTable) {
|
||||
if (virtualTable.getParent() != null) {
|
||||
addVirtualTableFields(structure, virtualTable.getParent());
|
||||
}
|
||||
for (var methodDesc : virtualTable.getMethods()) {
|
||||
if (methodDesc == null) {
|
||||
structure.getFields().add(WasmType.Reference.FUNC.asStorage());
|
||||
structure.getFields().add(new WasmField(WasmType.Reference.FUNC.asStorage()));
|
||||
} else {
|
||||
var originalVirtualTable = virtualTable.findMethodContainer(methodDesc);
|
||||
var functionType = typeMapper.getFunctionType(originalVirtualTable.getClassName(), methodDesc, false);
|
||||
structure.getFields().add(functionType.getReference().asStorage());
|
||||
var field = new WasmField(functionType.getReference().asStorage());
|
||||
field.setName(names.forVirtualMethod(methodDesc));
|
||||
structure.getFields().add(field);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -528,8 +541,7 @@ public class WasmGCClassGenerator implements WasmGCClassInfoProvider, WasmGCInit
|
|||
|
||||
private void fillFields(WasmGCClassInfo classInfo, ValueType type) {
|
||||
var fields = classInfo.structure.getFields();
|
||||
fields.add(standardClasses.classClass().getType().asStorage());
|
||||
fields.add(WasmType.Reference.ANY.asStorage());
|
||||
addSystemFields(fields);
|
||||
if (type instanceof ValueType.Object) {
|
||||
fillClassFields(fields, ((ValueType.Object) type).getClassName());
|
||||
} else if (type instanceof ValueType.Array) {
|
||||
|
@ -537,7 +549,7 @@ public class WasmGCClassGenerator implements WasmGCClassInfoProvider, WasmGCInit
|
|||
}
|
||||
}
|
||||
|
||||
private void fillClassFields(List<WasmStorageType> fields, String className) {
|
||||
private void fillClassFields(List<WasmField> fields, String className) {
|
||||
var classReader = classSource.get(className);
|
||||
if (classReader == null || classReader.hasModifier(ElementModifier.INTERFACE)) {
|
||||
fillSimpleClassFields(fields, "java.lang.Object");
|
||||
|
@ -546,7 +558,7 @@ public class WasmGCClassGenerator implements WasmGCClassInfoProvider, WasmGCInit
|
|||
}
|
||||
}
|
||||
|
||||
private void fillSimpleClassFields(List<WasmStorageType> fields, String className) {
|
||||
private void fillSimpleClassFields(List<WasmField> fields, String className) {
|
||||
var classReader = classSource.get(className);
|
||||
if (classReader.getParent() != null) {
|
||||
fillClassFields(fields, classReader.getParent());
|
||||
|
@ -562,29 +574,37 @@ public class WasmGCClassGenerator implements WasmGCClassInfoProvider, WasmGCInit
|
|||
continue;
|
||||
}
|
||||
fieldIndexes.putIfAbsent(field.getReference(), fields.size());
|
||||
fields.add(typeMapper.mapStorageType(field.getType()));
|
||||
var wasmField = new WasmField(typeMapper.mapStorageType(field.getType()),
|
||||
names.forMemberField(field.getReference()));
|
||||
fields.add(wasmField);
|
||||
}
|
||||
if (className.equals("java.lang.Class")) {
|
||||
classFlagsOffset = fields.size();
|
||||
fields.add(WasmType.INT32.asStorage());
|
||||
fields.add(createClassField(WasmType.INT32.asStorage(), "lowerIndex"));
|
||||
classTagOffset = fields.size();
|
||||
fields.add(WasmType.INT32.asStorage());
|
||||
fields.add(createClassField(WasmType.INT32.asStorage(), "upperIndex"));
|
||||
classParentOffset = fields.size();
|
||||
fields.add(standardClasses.classClass().getType().asStorage());
|
||||
fields.add(createClassField(standardClasses.classClass().getType().asStorage(), "parent"));
|
||||
classArrayItemOffset = fields.size();
|
||||
fields.add(standardClasses.classClass().getType().asStorage());
|
||||
fields.add(createClassField(standardClasses.classClass().getType().asStorage(), "arrayItem"));
|
||||
classArrayOffset = fields.size();
|
||||
fields.add(standardClasses.classClass().getType().asStorage());
|
||||
fields.add(createClassField(standardClasses.classClass().getType().asStorage(), "array"));
|
||||
classSupertypeFunctionOffset = fields.size();
|
||||
fields.add(supertypeGenerator.getFunctionType().getReference().asStorage());
|
||||
fields.add(createClassField(supertypeGenerator.getFunctionType().getReference().asStorage(),
|
||||
"isSupertype"));
|
||||
classNewArrayOffset = fields.size();
|
||||
fields.add(newArrayGenerator.getNewArrayFunctionType().getReference().asStorage());
|
||||
fields.add(createClassField(newArrayGenerator.getNewArrayFunctionType().getReference().asStorage(),
|
||||
"createArrayInstance"));
|
||||
classNameOffset = fields.size();
|
||||
fields.add(standardClasses.stringClass().getType().asStorage());
|
||||
fields.add(createClassField(standardClasses.stringClass().getType().asStorage(), "name"));
|
||||
virtualTableFieldOffset = fields.size();
|
||||
}
|
||||
}
|
||||
|
||||
private WasmField createClassField(WasmStorageType type, String name) {
|
||||
return new WasmField(type, names.forMemberField(new FieldReference("java.lang.Class", name)));
|
||||
}
|
||||
|
||||
private void fillArrayFields(WasmGCClassInfo classInfo, ValueType elementType) {
|
||||
WasmStorageType wasmElementType;
|
||||
if (elementType instanceof ValueType.Primitive) {
|
||||
|
@ -617,7 +637,7 @@ public class WasmGCClassGenerator implements WasmGCClassInfoProvider, WasmGCInit
|
|||
}
|
||||
var wasmArray = new WasmArray(null, wasmElementType);
|
||||
module.types.add(wasmArray);
|
||||
classInfo.structure.getFields().add(wasmArray.getReference().asStorage());
|
||||
classInfo.structure.getFields().add(new WasmField(wasmArray.getReference().asStorage(), "data"));
|
||||
classInfo.array = wasmArray;
|
||||
}
|
||||
|
||||
|
|
|
@ -62,7 +62,7 @@ public class WasmGCGenerationUtil {
|
|||
|
||||
var wasmArrayType = (WasmType.CompositeReference) classInfo.getStructure().getFields()
|
||||
.get(WasmGCClassInfoProvider.ARRAY_DATA_FIELD_OFFSET)
|
||||
.asUnpackedType();
|
||||
.getUnpackedType();
|
||||
var wasmArray = (WasmArray) wasmArrayType.composite;
|
||||
var initArrayField = new WasmStructSet(
|
||||
classInfo.getStructure(),
|
||||
|
|
|
@ -176,7 +176,7 @@ public class WasmGCGenerationVisitor extends BaseWasmGenerationVisitor {
|
|||
var struct = (WasmStructure) type.composite;
|
||||
var fieldIndex = context.classInfoProvider().getFieldIndex(field);
|
||||
|
||||
accept(value, struct.getFields().get(fieldIndex).asUnpackedType());
|
||||
accept(value, struct.getFields().get(fieldIndex).getUnpackedType());
|
||||
var wasmValue = result;
|
||||
|
||||
var expr = new WasmStructSet(struct, target, fieldIndex, wasmValue);
|
||||
|
@ -284,7 +284,7 @@ public class WasmGCGenerationVisitor extends BaseWasmGenerationVisitor {
|
|||
classRef = new WasmCast(classRef, vtableStruct.getReference());
|
||||
|
||||
var functionRef = new WasmStructGet(vtableStruct, classRef, index);
|
||||
var functionTypeRef = (WasmType.CompositeReference) vtableStruct.getFields().get(index).asUnpackedType();
|
||||
var functionTypeRef = (WasmType.CompositeReference) vtableStruct.getFields().get(index).getUnpackedType();
|
||||
var invoke = new WasmCallReference(functionRef, (WasmFunctionType) functionTypeRef.composite);
|
||||
WasmExpression instanceRef = new WasmGetLocal(instance);
|
||||
var instanceType = (WasmType.CompositeReference) instance.getType();
|
||||
|
|
|
@ -85,9 +85,9 @@ public class SystemArrayCopyIntrinsic implements WasmGCIntrinsic {
|
|||
var wasmSize = context.generate(invocation.getArguments().get(4));
|
||||
|
||||
var wasmTargetArrayTypeRef = (WasmType.CompositeReference) wasmTargetArrayStruct.getFields()
|
||||
.get(WasmGCClassInfoProvider.ARRAY_DATA_FIELD_OFFSET).asUnpackedType();
|
||||
.get(WasmGCClassInfoProvider.ARRAY_DATA_FIELD_OFFSET).getUnpackedType();
|
||||
var wasmSourceArrayTypeRef = (WasmType.CompositeReference) wasmSourceArrayStruct.getFields()
|
||||
.get(WasmGCClassInfoProvider.ARRAY_DATA_FIELD_OFFSET).asUnpackedType();
|
||||
.get(WasmGCClassInfoProvider.ARRAY_DATA_FIELD_OFFSET).getUnpackedType();
|
||||
|
||||
return new WasmArrayCopy((WasmArray) wasmTargetArrayTypeRef.composite, wasmTargetArray, wasmTargetIndex,
|
||||
(WasmArray) wasmSourceArrayTypeRef.composite, wasmSourceArray, wasmSourceIndex, wasmSize);
|
||||
|
|
|
@ -0,0 +1,66 @@
|
|||
/*
|
||||
* 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.model;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
public class WasmField {
|
||||
WasmStructure structure;
|
||||
int index;
|
||||
private String name;
|
||||
private WasmStorageType type;
|
||||
|
||||
public WasmField(WasmStorageType type, String name) {
|
||||
this(type);
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public WasmField(WasmStorageType type) {
|
||||
this.type = Objects.requireNonNull(type);
|
||||
}
|
||||
|
||||
public WasmStructure getStructure() {
|
||||
return structure;
|
||||
}
|
||||
|
||||
public WasmStorageType getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
public WasmType getUnpackedType() {
|
||||
return type.asUnpackedType();
|
||||
}
|
||||
|
||||
public void setType(WasmStorageType type) {
|
||||
this.type = Objects.requireNonNull(type);
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public int getIndex() {
|
||||
if (structure == null) {
|
||||
return -1;
|
||||
}
|
||||
structure.ensureIndexes();
|
||||
return index;
|
||||
}
|
||||
}
|
|
@ -15,18 +15,20 @@
|
|||
*/
|
||||
package org.teavm.backend.wasm.model;
|
||||
|
||||
import java.util.AbstractList;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class WasmStructure extends WasmCompositeType {
|
||||
private List<WasmStorageType> fields = new ArrayList<>();
|
||||
private List<WasmField> fieldsStorage = new ArrayList<>();
|
||||
private WasmStructure supertype;
|
||||
private boolean indexesValid = true;
|
||||
|
||||
public WasmStructure(String name) {
|
||||
super(name);
|
||||
}
|
||||
|
||||
public List<WasmStorageType> getFields() {
|
||||
public List<WasmField> getFields() {
|
||||
return fields;
|
||||
}
|
||||
|
||||
|
@ -48,8 +50,80 @@ public class WasmStructure extends WasmCompositeType {
|
|||
return false;
|
||||
}
|
||||
|
||||
void ensureIndexes() {
|
||||
if (!indexesValid) {
|
||||
indexesValid = true;
|
||||
for (var i = 0; i < fieldsStorage.size(); ++i) {
|
||||
fieldsStorage.get(i).index = i;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void acceptVisitor(WasmCompositeTypeVisitor visitor) {
|
||||
visitor.visit(this);
|
||||
}
|
||||
|
||||
private List<WasmField> fields = new AbstractList<WasmField>() {
|
||||
@Override
|
||||
public WasmField get(int index) {
|
||||
return fieldsStorage.get(index);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int size() {
|
||||
return fieldsStorage.size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void add(int index, WasmField element) {
|
||||
if (element.structure != null) {
|
||||
throw new IllegalArgumentException("This field already belongs to structure");
|
||||
}
|
||||
element.structure = WasmStructure.this;
|
||||
indexesValid = false;
|
||||
fieldsStorage.add(index, element);
|
||||
}
|
||||
|
||||
@Override
|
||||
public WasmField remove(int index) {
|
||||
var result = fieldsStorage.remove(index);
|
||||
indexesValid = false;
|
||||
result.structure = null;
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void removeRange(int fromIndex, int toIndex) {
|
||||
var sublist = fieldsStorage.subList(fromIndex, toIndex);
|
||||
for (var field : sublist) {
|
||||
field.structure = null;
|
||||
}
|
||||
indexesValid = false;
|
||||
sublist.clear();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clear() {
|
||||
for (var field : fieldsStorage) {
|
||||
field.structure = null;
|
||||
}
|
||||
indexesValid = true;
|
||||
fieldsStorage.clear();
|
||||
}
|
||||
|
||||
@Override
|
||||
public WasmField set(int index, WasmField element) {
|
||||
if (element.structure != null) {
|
||||
throw new IllegalArgumentException("This field already belongs to structure");
|
||||
}
|
||||
var former = fieldsStorage.set(index, element);
|
||||
former.structure = null;
|
||||
if (indexesValid) {
|
||||
element.index = former.index;
|
||||
}
|
||||
element.structure = WasmStructure.this;
|
||||
return former;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
|
@ -48,7 +48,7 @@ final class WasmTypeGraphBuilder {
|
|||
addEdge(type.getSupertype().getReference());
|
||||
}
|
||||
for (var field : type.getFields()) {
|
||||
addEdge(field.asUnpackedType());
|
||||
addEdge(field.getUnpackedType());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -170,7 +170,7 @@ public class UnusedTypeElimination {
|
|||
@Override
|
||||
public void visit(WasmStructure type) {
|
||||
for (var field : type.getFields()) {
|
||||
visit(field);
|
||||
visit(field.getType());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -29,6 +29,7 @@ import org.teavm.backend.wasm.model.WasmCustomSection;
|
|||
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.WasmStructure;
|
||||
import org.teavm.backend.wasm.model.WasmType;
|
||||
|
||||
public class WasmBinaryRenderer {
|
||||
|
@ -509,6 +510,31 @@ public class WasmBinaryRenderer {
|
|||
section.writeBytes(payload);
|
||||
}
|
||||
|
||||
var typesWithNamedFields = module.types.stream()
|
||||
.filter(t -> t instanceof WasmStructure)
|
||||
.filter(t -> ((WasmStructure) t).getFields().stream().anyMatch(f -> f.getName() != null))
|
||||
.collect(Collectors.toList());
|
||||
if (!typesWithNamedFields.isEmpty()) {
|
||||
var subsection = new WasmBinaryWriter();
|
||||
subsection.writeLEB(typesWithNamedFields.size());
|
||||
for (var type : typesWithNamedFields) {
|
||||
subsection.writeLEB(module.types.indexOf(type));
|
||||
var fields = ((WasmStructure) type).getFields().stream()
|
||||
.filter(t -> t.getName() != null)
|
||||
.collect(Collectors.toList());
|
||||
subsection.writeLEB(fields.size());
|
||||
for (var field : fields) {
|
||||
subsection.writeLEB(field.getIndex());
|
||||
subsection.writeAsciiString(field.getName());
|
||||
}
|
||||
}
|
||||
|
||||
payload = subsection.getData();
|
||||
section.writeLEB(10);
|
||||
section.writeLEB(payload.length);
|
||||
section.writeBytes(payload);
|
||||
}
|
||||
|
||||
writeSection(SECTION_UNKNOWN, "name", section.getData());
|
||||
}
|
||||
|
||||
|
|
|
@ -43,7 +43,7 @@ public class WasmCompositeTypeBinaryRenderer implements WasmCompositeTypeVisitor
|
|||
section.writeByte(0x5F);
|
||||
section.writeLEB(type.getFields().size());
|
||||
for (var fieldType : type.getFields()) {
|
||||
writeStorageType(fieldType);
|
||||
writeStorageType(fieldType.getType());
|
||||
section.writeLEB(0x01); // mutable
|
||||
}
|
||||
}
|
||||
|
|
|
@ -290,7 +290,7 @@ public class WasmTypeInference implements WasmExpressionVisitor {
|
|||
|
||||
@Override
|
||||
public void visit(WasmStructGet expression) {
|
||||
result = expression.getType().getFields().get(expression.getFieldIndex()).asUnpackedType();
|
||||
result = expression.getType().getFields().get(expression.getFieldIndex()).getUnpackedType();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
Loading…
Reference in New Issue
Block a user