Skip to content

Commit

Permalink
wasm gc: generate field names and write them to name section
Browse files Browse the repository at this point in the history
  • Loading branch information
konsoletyper committed Aug 20, 2024
1 parent 29f29ce commit eb0eb1f
Show file tree
Hide file tree
Showing 11 changed files with 217 additions and 31 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
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;
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -259,7 +262,7 @@ public WasmGCClassInfo getClassInfo(ValueType type) {
}
if (!isInterface) {
fillFields(classInfo, type);
}
}
}
var pointerName = names.forClassInstance(type);
classInfo.hasOwnVirtualTable = virtualTable != null && virtualTable.hasValidEntries();
Expand Down Expand Up @@ -411,7 +414,7 @@ private void fillVirtualTableMethods(List<WasmExpression> target, WasmStructure
&& !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())
Expand Down Expand Up @@ -444,24 +447,34 @@ private WasmStructure initRegularClassStructure(String className) {
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);
}
}
}
Expand Down Expand Up @@ -528,16 +541,15 @@ private WasmGlobal generateStaticFieldLocation(FieldReference fieldRef) {

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) {
fillArrayFields(classInfo, ((ValueType.Array) type).getItemType());
}
}

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");
Expand All @@ -546,7 +558,7 @@ private void fillClassFields(List<WasmStorageType> fields, String className) {
}
}

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());
Expand All @@ -562,29 +574,37 @@ private void fillSimpleClassFields(List<WasmStorageType> fields, String classNam
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) {
Expand Down Expand Up @@ -617,7 +637,7 @@ private void fillArrayFields(WasmGCClassInfo classInfo, ValueType elementType) {
}
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;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ public void allocateArray(ValueType itemType, WasmExpression length, TextLocatio

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(),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -176,7 +176,7 @@ protected void storeField(Expr qualified, FieldReference field, Expr value, Text
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);
Expand Down Expand Up @@ -284,7 +284,7 @@ protected WasmExpression generateVirtualCall(WasmLocal instance, MethodReference
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();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -85,9 +85,9 @@ private WasmExpression tryGenerateSpecialCase(InvocationExpr invocation, WasmGCI
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);
Expand Down
66 changes: 66 additions & 0 deletions core/src/main/java/org/teavm/backend/wasm/model/WasmField.java
Original file line number Diff line number Diff line change
@@ -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;
}
}
78 changes: 76 additions & 2 deletions core/src/main/java/org/teavm/backend/wasm/model/WasmStructure.java
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}

Expand All @@ -48,8 +50,80 @@ public boolean isSupertypeOf(WasmStructure subtype) {
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;
}
};
}
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ public void visit(WasmStructure type) {
addEdge(type.getSupertype().getReference());
}
for (var field : type.getFields()) {
addEdge(field.asUnpackedType());
addEdge(field.getUnpackedType());
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -170,7 +170,7 @@ public void visit(WasmArrayCopy expression) {
@Override
public void visit(WasmStructure type) {
for (var field : type.getFields()) {
visit(field);
visit(field.getType());
}
}

Expand Down
Loading

0 comments on commit eb0eb1f

Please sign in to comment.