diff --git a/core/src/main/java/org/teavm/backend/wasm/generate/gc/classes/WasmGCClassGenerator.java b/core/src/main/java/org/teavm/backend/wasm/generate/gc/classes/WasmGCClassGenerator.java index 7c3afeb83..0fd395c4c 100644 --- a/core/src/main/java/org/teavm/backend/wasm/generate/gc/classes/WasmGCClassGenerator.java +++ b/core/src/main/java/org/teavm/backend/wasm/generate/gc/classes/WasmGCClassGenerator.java @@ -300,6 +300,7 @@ public class WasmGCClassGenerator implements WasmGCClassInfoProvider, WasmGCInit var structName = names.topLevel(names.suggestForType(type)); classInfo.structure = new WasmStructure(structName, fields -> fillFields(finalClassInfo, fields, type)); + classInfo.structure.setNominal(true); module.types.add(classInfo.structure); nonInitializedStructures.add(classInfo.structure); } diff --git a/core/src/main/java/org/teavm/backend/wasm/generate/gc/methods/WasmGCGenerationVisitor.java b/core/src/main/java/org/teavm/backend/wasm/generate/gc/methods/WasmGCGenerationVisitor.java index 1f82b39ed..d55660aa2 100644 --- a/core/src/main/java/org/teavm/backend/wasm/generate/gc/methods/WasmGCGenerationVisitor.java +++ b/core/src/main/java/org/teavm/backend/wasm/generate/gc/methods/WasmGCGenerationVisitor.java @@ -81,6 +81,7 @@ import org.teavm.backend.wasm.model.expression.WasmTest; import org.teavm.backend.wasm.model.expression.WasmThrow; import org.teavm.backend.wasm.model.expression.WasmUnreachable; import org.teavm.model.ClassHierarchy; +import org.teavm.model.ElementModifier; import org.teavm.model.FieldReference; import org.teavm.model.MethodReference; import org.teavm.model.TextLocation; @@ -517,7 +518,7 @@ public class WasmGCGenerationVisitor extends BaseWasmGenerationVisitor { } private boolean canCastNatively(ValueType type) { - /*if (type instanceof ValueType.Array) { + if (type instanceof ValueType.Array) { return true; } var className = ((ValueType.Object) type).getClassName(); @@ -525,8 +526,7 @@ public class WasmGCGenerationVisitor extends BaseWasmGenerationVisitor { if (cls == null) { return false; } - return !cls.hasModifier(ElementModifier.INTERFACE);*/ - return false; + return !cls.hasModifier(ElementModifier.INTERFACE); } @Override diff --git a/core/src/main/java/org/teavm/backend/wasm/model/WasmStructure.java b/core/src/main/java/org/teavm/backend/wasm/model/WasmStructure.java index b579b3218..26d94b563 100644 --- a/core/src/main/java/org/teavm/backend/wasm/model/WasmStructure.java +++ b/core/src/main/java/org/teavm/backend/wasm/model/WasmStructure.java @@ -25,6 +25,7 @@ public class WasmStructure extends WasmCompositeType { private List fieldsStorage = new ArrayList<>(); private WasmStructure supertype; private boolean indexesValid = true; + private boolean nominal; public WasmStructure(String name) { super(name); @@ -57,6 +58,14 @@ public class WasmStructure extends WasmCompositeType { return false; } + public boolean isNominal() { + return nominal; + } + + public void setNominal(boolean nominal) { + this.nominal = nominal; + } + void ensureIndexes() { if (!indexesValid) { indexesValid = true; diff --git a/core/src/main/java/org/teavm/backend/wasm/model/WasmTypeGraphBuilder.java b/core/src/main/java/org/teavm/backend/wasm/model/WasmTypeGraphBuilder.java index 25462b5e7..60018365b 100644 --- a/core/src/main/java/org/teavm/backend/wasm/model/WasmTypeGraphBuilder.java +++ b/core/src/main/java/org/teavm/backend/wasm/model/WasmTypeGraphBuilder.java @@ -15,6 +15,9 @@ */ package org.teavm.backend.wasm.model; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; import org.teavm.common.Graph; import org.teavm.common.GraphBuilder; @@ -29,9 +32,63 @@ final class WasmTypeGraphBuilder { visitor.currentIndex = module.types.indexOf(type); type.acceptVisitor(visitor); } + + addNominalStructures(module, types, graphBuilder); + return graphBuilder.build(); } + private static void addNominalStructures(WasmModule module, Iterable types, + GraphBuilder graphBuilder) { + var subStructures = new HashMap>(); + var topLevelStructures = new ArrayList(); + for (var type : types) { + if (type instanceof WasmStructure) { + var structure = (WasmStructure) type; + if (structure.isNominal()) { + if (structure.getSupertype() != null) { + subStructures.computeIfAbsent(structure.getSupertype(), k -> new ArrayList<>()).add(structure); + } else { + topLevelStructures.add(structure); + } + } + } + } + mergeNominalStructures(module, topLevelStructures, 0, graphBuilder); + for (var entry : subStructures.entrySet()) { + mergeNominalStructures(module, entry.getValue(), entry.getKey().getFields().size(), graphBuilder); + } + } + + private static void mergeNominalStructures(WasmModule module, List structures, int parentFieldCount, + GraphBuilder graphBuilder) { + outer: for (var i = 0; i < structures.size(); i++) { + for (var j = i + 1; j < structures.size(); j++) { + var a = structures.get(i); + var b = structures.get(j); + if (areSameStructures(parentFieldCount, a, b)) { + var p = module.types.indexOf(a); + var q = module.types.indexOf(b); + graphBuilder.addEdge(p, q); + graphBuilder.addEdge(q, p); + continue outer; + } + } + } + } + + private static boolean areSameStructures(int start, WasmStructure a, WasmStructure b) { + if (a.getFields().size() != b.getFields().size()) { + return false; + } + for (var i = start; i < a.getFields().size(); i++) { + if (a.getFields().get(i).getType() != b.getFields().get(i).getType()) { + return false; + } + } + return true; + } + private static class GraphBuilderVisitor implements WasmCompositeTypeVisitor { final WasmModule module; final GraphBuilder graphBuilder;