From 7324e99e6a34acf2af1f85e395bd0ff5598530bf Mon Sep 17 00:00:00 2001 From: Alexey Andreev Date: Tue, 27 Aug 2024 20:03:22 +0200 Subject: [PATCH] wasm gc: produce better names for declarations, generate locals in names section --- .../backend/wasm/WasmGCModuleGenerator.java | 22 +-- .../gc/WasmGCDeclarationsGenerator.java | 3 +- .../wasm/generate/gc/WasmGCNameProvider.java | 157 ++++++++++++++++++ .../gc/classes/WasmGCClassGenerator.java | 90 ++++++---- .../WasmGCNewArrayFunctionGenerator.java | 11 +- .../WasmGCSupertypeFunctionGenerator.java | 8 +- .../gc/methods/WasmGCGenerationContext.java | 9 +- .../gc/methods/WasmGCMethodGenerator.java | 20 ++- .../generate/gc/strings/WasmGCStringPool.java | 9 +- .../gc/WasmGCCustomGeneratorContext.java | 3 + .../gc/WasmGCStringPoolGenerator.java | 3 +- .../backend/wasm/model/WasmStructure.java | 4 + .../wasm/render/WasmBinaryRenderer.java | 24 +++ 13 files changed, 298 insertions(+), 65 deletions(-) create mode 100644 core/src/main/java/org/teavm/backend/wasm/generate/gc/WasmGCNameProvider.java diff --git a/core/src/main/java/org/teavm/backend/wasm/WasmGCModuleGenerator.java b/core/src/main/java/org/teavm/backend/wasm/WasmGCModuleGenerator.java index 9483035f3..ab42e2d98 100644 --- a/core/src/main/java/org/teavm/backend/wasm/WasmGCModuleGenerator.java +++ b/core/src/main/java/org/teavm/backend/wasm/WasmGCModuleGenerator.java @@ -85,7 +85,7 @@ public class WasmGCModuleGenerator { var function = declarationsGenerator.functions().forStaticMethod(new MethodReference( WasmGCSupport.class, "createStringArray", int.class, String[].class)); var caller = new WasmFunction(function.getType()); - var sizeLocal = new WasmLocal(WasmType.INT32); + var sizeLocal = new WasmLocal(WasmType.INT32, "length"); caller.add(sizeLocal); caller.getBody().add(callInitializer()); caller.getBody().add(new WasmReturn(new WasmCall(function, new WasmGetLocal(sizeLocal)))); @@ -98,8 +98,8 @@ public class WasmGCModuleGenerator { StringBuilder.class, "append", char.class, StringBuilder.class)); var stringBuilderType = declarationsGenerator.typeMapper().mapType(ValueType.parse(StringBuilder.class)); var caller = new WasmFunction(declarationsGenerator.functionTypes.of(null, stringBuilderType, WasmType.INT32)); - var stringBuilderLocal = new WasmLocal(stringBuilderType); - var codeLocal = new WasmLocal(WasmType.INT32); + var stringBuilderLocal = new WasmLocal(stringBuilderType, "stringBuilder"); + var codeLocal = new WasmLocal(WasmType.INT32, "charCode"); caller.add(stringBuilderLocal); caller.add(codeLocal); caller.getBody().add(callInitializer()); @@ -116,7 +116,7 @@ public class WasmGCModuleGenerator { var stringBuilderType = declarationsGenerator.typeMapper().mapType(ValueType.parse(StringBuilder.class)); var stringType = declarationsGenerator.typeMapper().mapType(ValueType.parse(String.class)); var caller = new WasmFunction(declarationsGenerator.functionTypes.of(stringType, stringBuilderType)); - var stringBuilderLocal = new WasmLocal(stringBuilderType); + var stringBuilderLocal = new WasmLocal(stringBuilderType, "stringBuilder"); caller.add(stringBuilderLocal); caller.getBody().add(callInitializer()); caller.getBody().add(new WasmReturn(new WasmCall(function, new WasmGetLocal(stringBuilderLocal)))); @@ -130,9 +130,9 @@ public class WasmGCModuleGenerator { var stringArrayType = declarationsGenerator.typeMapper().mapType(ValueType.parse(String[].class)); var stringType = declarationsGenerator.typeMapper().mapType(ValueType.parse(String.class)); var caller = new WasmFunction(function.getType()); - var arrayLocal = new WasmLocal(stringArrayType); - var indexLocal = new WasmLocal(WasmType.INT32); - var valueLocal = new WasmLocal(stringType); + var arrayLocal = new WasmLocal(stringArrayType, "array"); + var indexLocal = new WasmLocal(WasmType.INT32, "index"); + var valueLocal = new WasmLocal(stringType, "string"); caller.add(arrayLocal); caller.add(indexLocal); caller.add(valueLocal); @@ -148,7 +148,7 @@ public class WasmGCModuleGenerator { String.class, "length", int.class)); var stringType = declarationsGenerator.typeMapper().mapType(ValueType.parse(String.class)); var caller = new WasmFunction(function.getType()); - var stringLocal = new WasmLocal(stringType); + var stringLocal = new WasmLocal(stringType, "string"); caller.add(stringLocal); caller.getBody().add(callInitializer()); caller.getBody().add(new WasmReturn(new WasmCall(function, new WasmGetLocal(stringLocal)))); @@ -161,8 +161,8 @@ public class WasmGCModuleGenerator { String.class, "charAt", int.class, char.class)); var stringType = declarationsGenerator.typeMapper().mapType(ValueType.parse(String.class)); var caller = new WasmFunction(function.getType()); - var stringLocal = new WasmLocal(stringType); - var indexLocal = new WasmLocal(WasmType.INT32); + var stringLocal = new WasmLocal(stringType, "string"); + var indexLocal = new WasmLocal(WasmType.INT32, "index"); caller.add(stringLocal); caller.add(indexLocal); caller.getBody().add(callInitializer()); @@ -180,7 +180,7 @@ public class WasmGCModuleGenerator { initializer = new WasmFunction(functionType); initializer.setReferenced(true); declarationsGenerator.module.functions.add(initializer); - initializerRef = new WasmGlobal("teavm_initializer", functionType.getReference(), + initializerRef = new WasmGlobal("teavm@initializer", functionType.getReference(), new WasmFunctionReference(initializer)); declarationsGenerator.module.globals.add(initializerRef); initializer.getBody().add(new WasmSetGlobal(initializerRef, diff --git a/core/src/main/java/org/teavm/backend/wasm/generate/gc/WasmGCDeclarationsGenerator.java b/core/src/main/java/org/teavm/backend/wasm/generate/gc/WasmGCDeclarationsGenerator.java index 5a7c57bc6..acca35b92 100644 --- a/core/src/main/java/org/teavm/backend/wasm/generate/gc/WasmGCDeclarationsGenerator.java +++ b/core/src/main/java/org/teavm/backend/wasm/generate/gc/WasmGCDeclarationsGenerator.java @@ -20,7 +20,6 @@ import java.util.function.Predicate; import org.teavm.backend.wasm.BaseWasmFunctionRepository; import org.teavm.backend.wasm.WasmFunctionTypes; import org.teavm.backend.wasm.gc.vtable.WasmGCVirtualTableProvider; -import org.teavm.backend.wasm.generate.WasmNameProvider; import org.teavm.backend.wasm.generate.gc.classes.WasmGCClassGenerator; import org.teavm.backend.wasm.generate.gc.classes.WasmGCClassInfoProvider; import org.teavm.backend.wasm.generate.gc.classes.WasmGCSupertypeFunctionProvider; @@ -61,7 +60,7 @@ public class WasmGCDeclarationsGenerator { hierarchy = new ClassHierarchy(classes); var virtualTables = createVirtualTableProvider(classes, isVirtual); functionTypes = new WasmFunctionTypes(module); - var names = new WasmNameProvider(); + var names = new WasmGCNameProvider(); methodGenerator = new WasmGCMethodGenerator( module, hierarchy, diff --git a/core/src/main/java/org/teavm/backend/wasm/generate/gc/WasmGCNameProvider.java b/core/src/main/java/org/teavm/backend/wasm/generate/gc/WasmGCNameProvider.java new file mode 100644 index 000000000..2c9eaa344 --- /dev/null +++ b/core/src/main/java/org/teavm/backend/wasm/generate/gc/WasmGCNameProvider.java @@ -0,0 +1,157 @@ +/* + * 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.generate.gc; + +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; +import org.teavm.model.FieldReference; +import org.teavm.model.MethodDescriptor; +import org.teavm.model.MethodReference; +import org.teavm.model.ValueType; + +public class WasmGCNameProvider { + private Set occupiedTopLevelNames = new HashSet<>(); + private Set occupiedStructNames = new HashSet<>(); + + private Map virtualMethodNames = new HashMap<>(); + private Map memberFieldNames = new HashMap<>(); + + public String topLevel(String name) { + return pickUnoccupied(name); + } + + public String structureField(String name) { + return pickUnoccupied(name, occupiedStructNames); + } + + public String forVirtualMethod(MethodDescriptor method) { + return virtualMethodNames.computeIfAbsent(method, + k -> pickUnoccupied(sanitize(k.getName()), occupiedStructNames)); + } + + public String forMemberField(FieldReference field) { + return memberFieldNames.computeIfAbsent(field, + k -> pickUnoccupied(sanitize(field.getFieldName()), occupiedStructNames)); + } + + public String suggestForMethod(MethodReference method) { + StringBuilder sb = new StringBuilder(); + sb.append(sanitize(method.getClassName())); + sb.append("::"); + sb.append(sanitize(method.getName())); + return sb.toString(); + } + + public String suggestForStaticField(FieldReference field) { + StringBuilder sb = new StringBuilder(); + sb.append(sanitize(field.getClassName())); + sb.append('#'); + sb.append(sanitize(field.getFieldName())); + return sb.toString(); + } + + public String suggestForClass(String className) { + return sanitize(className); + } + + public String suggestForType(ValueType type) { + StringBuilder sb = new StringBuilder(); + suggestForType(type, sb); + return sb.toString(); + } + + private void suggestForType(ValueType type, StringBuilder sb) { + if (type instanceof ValueType.Object) { + sb.append(suggestForClass(((ValueType.Object) type).getClassName())); + } else if (type instanceof ValueType.Array) { + sb.append("Array<"); + suggestForType(((ValueType.Array) type).getItemType(), sb); + sb.append(">"); + } else { + sb.append("&").append(type.toString()); + } + } + + public static String sanitize(String name) { + char[] chars = null; + var i = 0; + for (; i < name.length(); ++i) { + var c = name.charAt(i); + if (!isIdentifierPart(c)) { + chars = new char[name.length()]; + name.getChars(0, i, chars, 0); + chars[i++] = '_'; + break; + } + } + if (chars == null) { + return name; + } + for (; i < name.length(); ++i) { + var c = name.charAt(i); + chars[i] = isIdentifierPart(c) ? c : '_'; + } + return new String(chars); + } + + public static boolean isIdentifierPart(char c) { + switch (c) { + case '!': + case '#': + case '$': + case '%': + case '&': + case '`': + case '*': + case '+': + case '-': + case '.': + case '/': + case ':': + case '<': + case '=': + case '>': + case '?': + case '@': + case '\\': + case '^': + case '_': + case '\'': + case '|': + case '~': + return true; + default: + return c >= 'A' && c <= 'Z' || c >= 'a' && c <= 'z' || c >= '0' && c <= '9'; + } + + } + + private String pickUnoccupied(String name) { + return pickUnoccupied(name, occupiedTopLevelNames); + } + + private String pickUnoccupied(String name, Set occupied) { + String result = name; + int index = 0; + while (!occupied.add(result)) { + result = name + "_" + index++; + } + + return result; + } +} 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 046bf1f1b..992c6051f 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 @@ -25,13 +25,13 @@ import java.util.List; import java.util.Map; import java.util.Queue; import java.util.function.Consumer; -import org.teavm.backend.lowlevel.generate.NameProvider; import org.teavm.backend.wasm.BaseWasmFunctionRepository; import org.teavm.backend.wasm.WasmFunctionTypes; import org.teavm.backend.wasm.gc.vtable.WasmGCVirtualTable; import org.teavm.backend.wasm.gc.vtable.WasmGCVirtualTableEntry; import org.teavm.backend.wasm.gc.vtable.WasmGCVirtualTableProvider; import org.teavm.backend.wasm.generate.gc.WasmGCInitializerContributor; +import org.teavm.backend.wasm.generate.gc.WasmGCNameProvider; import org.teavm.backend.wasm.generate.gc.strings.WasmGCStringPool; import org.teavm.backend.wasm.model.WasmArray; import org.teavm.backend.wasm.model.WasmField; @@ -106,12 +106,13 @@ public class WasmGCClassGenerator implements WasmGCClassInfoProvider, WasmGCInit public final WasmGCStringPool strings; public final WasmGCStandardClasses standardClasses; public final WasmGCTypeMapper typeMapper; - private final NameProvider names; + private final WasmGCNameProvider names; private List initializerFunctionStatements = new ArrayList<>(); private WasmFunction createPrimitiveClassFunction; private WasmFunction createArrayClassFunction; private final WasmGCSupertypeFunctionGenerator supertypeGenerator; private final WasmGCNewArrayFunctionGenerator newArrayGenerator; + private String arrayDataFieldName; private int classTagOffset; private int classFlagsOffset; @@ -134,7 +135,7 @@ public class WasmGCClassGenerator implements WasmGCClassInfoProvider, WasmGCInit public WasmGCClassGenerator(WasmModule module, ClassReaderSource classSource, WasmFunctionTypes functionTypes, TagRegistry tagRegistry, ClassMetadataRequirements metadataRequirements, WasmGCVirtualTableProvider virtualTables, - BaseWasmFunctionRepository functionProvider, NameProvider names, + BaseWasmFunctionRepository functionProvider, WasmGCNameProvider names, ClassInitializerInfo classInitializerInfo) { this.module = module; this.classSource = classSource; @@ -146,9 +147,9 @@ public class WasmGCClassGenerator implements WasmGCClassInfoProvider, WasmGCInit this.names = names; this.classInitializerInfo = classInitializerInfo; standardClasses = new WasmGCStandardClasses(this); - strings = new WasmGCStringPool(standardClasses, module, functionProvider); + strings = new WasmGCStringPool(standardClasses, module, functionProvider, names); supertypeGenerator = new WasmGCSupertypeFunctionGenerator(module, this, names, tagRegistry, functionTypes); - newArrayGenerator = new WasmGCNewArrayFunctionGenerator(module, functionTypes, this); + newArrayGenerator = new WasmGCNewArrayFunctionGenerator(module, functionTypes, this, names); typeMapper = new WasmGCTypeMapper(classSource, this, functionTypes, module); } @@ -279,7 +280,8 @@ public class WasmGCClassGenerator implements WasmGCClassInfoProvider, WasmGCInit } } if (classInfo.structure == null) { - classInfo.structure = new WasmStructure(name != null ? names.forClass(name) : null, + var structName = names.topLevel(names.suggestForType(type)); + classInfo.structure = new WasmStructure(structName, fields -> fillFields(finalClassInfo, fields, type)); module.types.add(classInfo.structure); nonInitializedStructures.add(classInfo.structure); @@ -297,7 +299,7 @@ public class WasmGCClassGenerator implements WasmGCClassInfoProvider, WasmGCInit classInfo.structure.setSupertype(standardClasses.objectClass().structure); } } - var pointerName = names.forClassInstance(type); + var pointerName = names.topLevel(names.suggestForType(type) + "@class"); classInfo.hasOwnVirtualTable = virtualTable != null && !virtualTable.getEntries().isEmpty(); WasmStructure classStructure; if (classInfo.hasOwnVirtualTable) { @@ -419,7 +421,8 @@ public class WasmGCClassGenerator implements WasmGCClassInfoProvider, WasmGCInit if (classInitializerInfo.isDynamicInitializer(name)) { if (cls != null && cls.getMethod(CLINIT_METHOD_DESC) != null) { var clinitType = functionTypes.of(null); - classInfo.initializerPointer = new WasmGlobal(null, clinitType.getReference(), + var wasmName = names.topLevel(names.suggestForClass(name) + "@initializer"); + classInfo.initializerPointer = new WasmGlobal(wasmName, clinitType.getReference(), new WasmNullConstant(clinitType.getReference())); module.globals.add(classInfo.initializerPointer); } @@ -467,10 +470,11 @@ public class WasmGCClassGenerator implements WasmGCClassInfoProvider, WasmGCInit WasmStructure objectStructure) { var virtualTable = virtualTables.lookup("java.lang.Object"); var structure = getArrayVirtualTableStructure(); + var itemType = ((ValueType.Array) type).getItemType(); for (var entry : virtualTable.getEntries()) { if (entry.getMethod().getName().equals("clone")) { - var function = generateArrayCloneMethod(objectStructure); + var function = generateArrayCloneMethod(objectStructure, itemType); function.setReferenced(true); var ref = new WasmFunctionReference(function); var fieldIndex = virtualTableFieldOffset + entry.getIndex(); @@ -480,7 +484,6 @@ public class WasmGCClassGenerator implements WasmGCClassInfoProvider, WasmGCInit } } - var itemType = ((ValueType.Array) type).getItemType(); var info = metadataRequirements.getInfo(type); if (info.arrayLength()) { var lengthFunction = getArrayLengthFunction(objectStructure); @@ -502,19 +505,20 @@ public class WasmGCClassGenerator implements WasmGCClassInfoProvider, WasmGCInit var elementType = arrayType.getElementType().asUnpackedType(); if (elementType instanceof WasmType.Reference) { if (arrayLengthObjectFunction == null) { - arrayLengthObjectFunction = getArrayLengthFunction(objectStructure, arrayType); + arrayLengthObjectFunction = createArrayLengthFunction(objectStructure); } return arrayLengthObjectFunction; } - return getArrayLengthFunction(objectStructure, arrayType); + return createArrayLengthFunction(objectStructure); } - private WasmFunction getArrayLengthFunction(WasmStructure objectStructure, WasmArray arrayType) { + private WasmFunction createArrayLengthFunction(WasmStructure objectStructure) { var function = new WasmFunction(functionTypes.of(WasmType.INT32, standardClasses.objectClass().getType())); function.setReferenced(true); + function.setName(names.topLevel("Array<*>::length")); module.functions.add(function); - var objectLocal = new WasmLocal(standardClasses.objectClass().getType()); + var objectLocal = new WasmLocal(standardClasses.objectClass().getType(), "object"); function.add(objectLocal); var castObject = new WasmCast(new WasmGetLocal(objectLocal), objectStructure.getReference()); @@ -534,6 +538,8 @@ public class WasmGCClassGenerator implements WasmGCClassInfoProvider, WasmGCInit private WasmFunction getArrayGetObjectFunction() { if (arrayGetObjectFunction == null) { arrayGetObjectFunction = new WasmFunction(getArrayGetType()); + arrayGetObjectFunction.setName(names.topLevel("Array<" + names.suggestForClass("java.lang.Object") + + "::get")); module.functions.add(arrayGetObjectFunction); arrayGetObjectFunction.setReferenced(true); @@ -541,8 +547,8 @@ public class WasmGCClassGenerator implements WasmGCClassInfoProvider, WasmGCInit var arrayDataTypeRef = (WasmType.CompositeReference) arrayStruct.getFields() .get(ARRAY_DATA_FIELD_OFFSET).getUnpackedType(); var arrayDataType = (WasmArray) arrayDataTypeRef.composite; - var objectLocal = new WasmLocal(standardClasses.objectClass().getType()); - var indexLocal = new WasmLocal(WasmType.INT32); + var objectLocal = new WasmLocal(standardClasses.objectClass().getType(), "object"); + var indexLocal = new WasmLocal(WasmType.INT32, "index"); arrayGetObjectFunction.add(objectLocal); arrayGetObjectFunction.add(indexLocal); @@ -556,6 +562,8 @@ public class WasmGCClassGenerator implements WasmGCClassInfoProvider, WasmGCInit private WasmFunction generateArrayGetPrimitiveFunction(PrimitiveType type) { var function = new WasmFunction(getArrayGetType()); + arrayGetObjectFunction.setName(names.topLevel("Array<" + names.suggestForType(ValueType.primitive(type)) + + ">::get")); module.functions.add(function); function.setReferenced(true); @@ -563,8 +571,8 @@ public class WasmGCClassGenerator implements WasmGCClassInfoProvider, WasmGCInit var arrayDataTypeRef = (WasmType.CompositeReference) arrayStruct.getFields() .get(ARRAY_DATA_FIELD_OFFSET).getUnpackedType(); var arrayDataType = (WasmArray) arrayDataTypeRef.composite; - var objectLocal = new WasmLocal(standardClasses.objectClass().getType()); - var indexLocal = new WasmLocal(WasmType.INT32); + var objectLocal = new WasmLocal(standardClasses.objectClass().getType(), "object"); + var indexLocal = new WasmLocal(WasmType.INT32, "index"); function.add(objectLocal); function.add(indexLocal); @@ -644,6 +652,7 @@ public class WasmGCClassGenerator implements WasmGCClassInfoProvider, WasmGCInit if (!entry.getOrigin().getClassName().equals(implementor.getClassName()) || expectedFunctionType != function.getType()) { var wrapperFunction = new WasmFunction(expectedFunctionType); + wrapperFunction.setName(names.topLevel(names.suggestForMethod(implementor) + "@caller")); module.functions.add(wrapperFunction); var call = new WasmCall(function); var instanceParam = new WasmLocal(getClassInfo(virtualTable.getClassName()).getType()); @@ -665,19 +674,20 @@ public class WasmGCClassGenerator implements WasmGCClassInfoProvider, WasmGCInit } } - private WasmFunction generateArrayCloneMethod(WasmStructure objectStructure) { + private WasmFunction generateArrayCloneMethod(WasmStructure objectStructure, ValueType itemType) { var arrayTypeRef = (WasmType.CompositeReference) objectStructure.getFields().get( WasmGCClassInfoProvider.ARRAY_DATA_FIELD_OFFSET).getUnpackedType(); var arrayType = (WasmArray) arrayTypeRef.composite; var type = typeMapper.getFunctionType(standardClasses.objectClass().getType(), CLONE_METHOD_DESC, false); var function = new WasmFunction(type); + function.setName(names.topLevel("Array<" + names.suggestForType(itemType) + ">::clone")); module.functions.add(function); - var instanceLocal = new WasmLocal(standardClasses.objectClass().getType()); - var originalLocal = new WasmLocal(objectStructure.getReference()); - var resultLocal = new WasmLocal(objectStructure.getReference()); - var originalDataLocal = new WasmLocal(arrayType.getReference()); - var dataCopyLocal = new WasmLocal(arrayType.getReference()); + var instanceLocal = new WasmLocal(standardClasses.objectClass().getType(), "instance"); + var originalLocal = new WasmLocal(objectStructure.getReference(), "original"); + var resultLocal = new WasmLocal(objectStructure.getReference(), "result"); + var originalDataLocal = new WasmLocal(arrayType.getReference(), "originalData"); + var dataCopyLocal = new WasmLocal(arrayType.getReference(), "resultData"); function.add(instanceLocal); function.add(originalLocal); function.add(resultLocal); @@ -712,7 +722,8 @@ public class WasmGCClassGenerator implements WasmGCClassInfoProvider, WasmGCInit private WasmStructure initRegularClassStructure(String className) { var virtualTable = virtualTables.lookup(className); - var structure = new WasmStructure(names.forClassClass(className), fields -> { + var wasmName = names.topLevel("Class<" + names.suggestForClass(className) + ">"); + var structure = new WasmStructure(wasmName, fields -> { addSystemFields(fields); fillSimpleClassFields(fields, "java.lang.Class"); addVirtualTableFields(fields, virtualTable); @@ -744,19 +755,22 @@ public class WasmGCClassGenerator implements WasmGCClassInfoProvider, WasmGCInit @Override public WasmStructure getArrayVirtualTableStructure() { if (arrayVirtualTableStruct == null) { - arrayVirtualTableStruct = new WasmStructure(null, fields -> { + var wasmName = names.topLevel("Class>"); + arrayVirtualTableStruct = new WasmStructure(wasmName, fields -> { addSystemFields(fields); fillSimpleClassFields(fields, "java.lang.Class"); addVirtualTableFields(fields, virtualTables.lookup("java.lang.Object")); if (metadataRequirements.hasArrayLength()) { arrayLengthOffset = fields.size(); var arrayLengthType = getArrayLengthType(); - fields.add(new WasmField(arrayLengthType.getReference().asStorage())); + fields.add(new WasmField(arrayLengthType.getReference().asStorage(), + names.structureField("@arrayLength"))); } if (metadataRequirements.hasArrayGet()) { arrayGetOffset = fields.size(); var arrayGetType = getArrayGetType(); - fields.add(new WasmField(arrayGetType.getReference().asStorage())); + fields.add(new WasmField(arrayGetType.getReference().asStorage(), + names.structureField("@arrayGet"))); } }); arrayVirtualTableStruct.setSupertype(standardClasses.objectClass().getVirtualTableStructure()); @@ -830,7 +844,8 @@ public class WasmGCClassGenerator implements WasmGCClassInfoProvider, WasmGCInit var type = typeMapper.mapType(javaType); var wasmInitialValue = initValue != null ? initialValue(initValue) : WasmExpression.defaultValueOfType(type); - var global = new WasmGlobal(names.forStaticField(fieldRef), type, wasmInitialValue); + var wasmName = names.topLevel(names.suggestForStaticField(fieldRef)); + var global = new WasmGlobal(wasmName, type, wasmInitialValue); dynamicInitialValue(global, initValue); module.globals.add(global); @@ -968,9 +983,18 @@ public class WasmGCClassGenerator implements WasmGCClassInfoProvider, WasmGCInit } else { wasmElementType = standardClasses.objectClass().getType().asStorage(); } - var wasmArray = new WasmArray(null, wasmElementType); + var wasmArrayName = names.topLevel(names.suggestForType(classInfo.getValueType()) + "$Data"); + var wasmArray = new WasmArray(wasmArrayName, wasmElementType); module.types.add(wasmArray); - classInfo.structure.getFields().add(new WasmField(wasmArray.getReference().asStorage(), "data")); + classInfo.structure.getFields().add(new WasmField(wasmArray.getReference().asStorage(), + arrayDataFieldName())); + } + + private String arrayDataFieldName() { + if (arrayDataFieldName == null) { + arrayDataFieldName = names.structureField("@data"); + } + return arrayDataFieldName; } private WasmFunction getCreatePrimitiveClassFunction() { @@ -988,7 +1012,7 @@ public class WasmGCClassGenerator implements WasmGCClassInfoProvider, WasmGCInit WasmType.INT32 ); var function = new WasmFunction(functionType); - function.setName("teavm_fill_primitive_class"); + function.setName(names.topLevel("teavm@fill_primitive_class")); module.functions.add(function); var targetVar = new WasmLocal(standardClasses.classClass().getType(), "target"); @@ -1047,7 +1071,7 @@ public class WasmGCClassGenerator implements WasmGCClassInfoProvider, WasmGCInit ); var function = new WasmFunction(functionType); module.functions.add(function); - function.setName("teavm_fill_array_class"); + function.setName(names.topLevel("teavm@fillArrayClass")); var targetVar = new WasmLocal(standardClasses.classClass().getType(), "target"); var itemVar = new WasmLocal(standardClasses.classClass().getType(), "item"); diff --git a/core/src/main/java/org/teavm/backend/wasm/generate/gc/classes/WasmGCNewArrayFunctionGenerator.java b/core/src/main/java/org/teavm/backend/wasm/generate/gc/classes/WasmGCNewArrayFunctionGenerator.java index 30d7fe9ed..d47cbee5c 100644 --- a/core/src/main/java/org/teavm/backend/wasm/generate/gc/classes/WasmGCNewArrayFunctionGenerator.java +++ b/core/src/main/java/org/teavm/backend/wasm/generate/gc/classes/WasmGCNewArrayFunctionGenerator.java @@ -17,6 +17,7 @@ package org.teavm.backend.wasm.generate.gc.classes; import org.teavm.backend.wasm.WasmFunctionTypes; import org.teavm.backend.wasm.generate.TemporaryVariablePool; +import org.teavm.backend.wasm.generate.gc.WasmGCNameProvider; import org.teavm.backend.wasm.generate.gc.methods.WasmGCGenerationUtil; import org.teavm.backend.wasm.model.WasmFunction; import org.teavm.backend.wasm.model.WasmFunctionType; @@ -32,22 +33,26 @@ class WasmGCNewArrayFunctionGenerator { private WasmFunctionTypes functionTypes; private WasmGCClassInfoProvider classInfoProvider; private WasmFunctionType newArrayFunctionType; + private WasmGCNameProvider names; WasmGCNewArrayFunctionGenerator(WasmModule module, WasmFunctionTypes functionTypes, - WasmGCClassInfoProvider classInfoProvider) { + WasmGCClassInfoProvider classInfoProvider, WasmGCNameProvider names) { this.module = module; this.functionTypes = functionTypes; this.classInfoProvider = classInfoProvider; + this.names = names; } WasmFunction generateNewArrayFunction(ValueType itemType) { var function = new WasmFunction(getNewArrayFunctionType()); + function.setName(names.topLevel("Array<" + names.suggestForType(itemType) + ">@new")); module.functions.add(function); - var sizeLocal = new WasmLocal(WasmType.INT32); + var sizeLocal = new WasmLocal(WasmType.INT32, "length"); function.add(sizeLocal); var tempVars = new TemporaryVariablePool(function); var genUtil = new WasmGCGenerationUtil(classInfoProvider, tempVars); - var targetVar = new WasmLocal(classInfoProvider.getClassInfo(ValueType.arrayOf(itemType)).getType()); + var targetVar = new WasmLocal(classInfoProvider.getClassInfo(ValueType.arrayOf(itemType)).getType(), + "result"); function.add(targetVar); genUtil.allocateArray(itemType, new WasmGetLocal(sizeLocal), null, targetVar, function.getBody()); function.getBody().add(new WasmReturn(new WasmGetLocal(targetVar))); diff --git a/core/src/main/java/org/teavm/backend/wasm/generate/gc/classes/WasmGCSupertypeFunctionGenerator.java b/core/src/main/java/org/teavm/backend/wasm/generate/gc/classes/WasmGCSupertypeFunctionGenerator.java index 0378bcfdc..0abca345b 100644 --- a/core/src/main/java/org/teavm/backend/wasm/generate/gc/classes/WasmGCSupertypeFunctionGenerator.java +++ b/core/src/main/java/org/teavm/backend/wasm/generate/gc/classes/WasmGCSupertypeFunctionGenerator.java @@ -19,8 +19,8 @@ import java.util.Comparator; import java.util.HashMap; import java.util.List; import java.util.Map; -import org.teavm.backend.lowlevel.generate.NameProvider; import org.teavm.backend.wasm.WasmFunctionTypes; +import org.teavm.backend.wasm.generate.gc.WasmGCNameProvider; import org.teavm.backend.wasm.model.WasmFunction; import org.teavm.backend.wasm.model.WasmFunctionType; import org.teavm.backend.wasm.model.WasmLocal; @@ -47,7 +47,7 @@ public class WasmGCSupertypeFunctionGenerator implements WasmGCSupertypeFunction private Map functions = new HashMap<>(); private WasmModule module; private WasmGCClassGenerator classGenerator; - private NameProvider nameProvider; + private WasmGCNameProvider nameProvider; private TagRegistry tagRegistry; private WasmFunctionTypes functionTypes; private WasmFunctionType functionType; @@ -55,7 +55,7 @@ public class WasmGCSupertypeFunctionGenerator implements WasmGCSupertypeFunction WasmGCSupertypeFunctionGenerator( WasmModule module, WasmGCClassGenerator classGenerator, - NameProvider nameProvider, + WasmGCNameProvider nameProvider, TagRegistry tagRegistry, WasmFunctionTypes functionTypes ) { @@ -78,7 +78,7 @@ public class WasmGCSupertypeFunctionGenerator implements WasmGCSupertypeFunction private WasmFunction generateIsSupertypeFunction(ValueType type) { var function = new WasmFunction(getFunctionType()); - function.setName(nameProvider.forSupertypeFunction(type)); + function.setName(nameProvider.topLevel(nameProvider.suggestForType(type) + "@isSupertypes")); var subtypeVar = new WasmLocal(classGenerator.standardClasses.classClass().getType(), "subtype"); function.add(subtypeVar); module.functions.add(function); diff --git a/core/src/main/java/org/teavm/backend/wasm/generate/gc/methods/WasmGCGenerationContext.java b/core/src/main/java/org/teavm/backend/wasm/generate/gc/methods/WasmGCGenerationContext.java index b0fa0847f..10207e39e 100644 --- a/core/src/main/java/org/teavm/backend/wasm/generate/gc/methods/WasmGCGenerationContext.java +++ b/core/src/main/java/org/teavm/backend/wasm/generate/gc/methods/WasmGCGenerationContext.java @@ -25,6 +25,7 @@ import org.teavm.backend.wasm.BaseWasmFunctionRepository; import org.teavm.backend.wasm.WasmFunctionTypes; import org.teavm.backend.wasm.gc.vtable.WasmGCVirtualTableProvider; import org.teavm.backend.wasm.generate.common.methods.BaseWasmGenerationContext; +import org.teavm.backend.wasm.generate.gc.WasmGCNameProvider; import org.teavm.backend.wasm.generate.gc.classes.WasmGCClassInfoProvider; import org.teavm.backend.wasm.generate.gc.classes.WasmGCStandardClasses; import org.teavm.backend.wasm.generate.gc.classes.WasmGCSupertypeFunctionProvider; @@ -62,13 +63,15 @@ public class WasmGCGenerationContext implements BaseWasmGenerationContext { private WasmGlobal exceptionGlobal; private WasmTag exceptionTag; private Map> interfaceImplementors; + private WasmGCNameProvider names; public WasmGCGenerationContext(WasmModule module, WasmGCVirtualTableProvider virtualTables, WasmGCTypeMapper typeMapper, WasmFunctionTypes functionTypes, ListableClassReaderSource classes, ClassHierarchy hierarchy, BaseWasmFunctionRepository functions, WasmGCSupertypeFunctionProvider supertypeFunctions, WasmGCClassInfoProvider classInfoProvider, WasmGCStandardClasses standardClasses, WasmGCStringProvider strings, - WasmGCCustomGeneratorProvider customGenerators, WasmGCIntrinsicProvider intrinsics) { + WasmGCCustomGeneratorProvider customGenerators, WasmGCIntrinsicProvider intrinsics, + WasmGCNameProvider names) { this.module = module; this.virtualTables = virtualTables; this.typeMapper = typeMapper; @@ -82,6 +85,7 @@ public class WasmGCGenerationContext implements BaseWasmGenerationContext { this.strings = strings; this.customGenerators = customGenerators; this.intrinsics = intrinsics; + this.names = names; } public WasmGCClassInfoProvider classInfoProvider() { @@ -164,7 +168,8 @@ public class WasmGCGenerationContext implements BaseWasmGenerationContext { public WasmGlobal exceptionGlobal() { if (exceptionGlobal == null) { var type = classInfoProvider.getClassInfo("java.lang.Throwable").getType(); - exceptionGlobal = new WasmGlobal("teavm_thrown_exception", type, new WasmNullConstant(type)); + exceptionGlobal = new WasmGlobal(names.topLevel("teavm@thrownException"), type, + new WasmNullConstant(type)); module.globals.add(exceptionGlobal); } return exceptionGlobal; diff --git a/core/src/main/java/org/teavm/backend/wasm/generate/gc/methods/WasmGCMethodGenerator.java b/core/src/main/java/org/teavm/backend/wasm/generate/gc/methods/WasmGCMethodGenerator.java index 8d3eff452..c0f558cbc 100644 --- a/core/src/main/java/org/teavm/backend/wasm/generate/gc/methods/WasmGCMethodGenerator.java +++ b/core/src/main/java/org/teavm/backend/wasm/generate/gc/methods/WasmGCMethodGenerator.java @@ -23,11 +23,11 @@ import java.util.Objects; import java.util.Queue; import java.util.Set; import org.teavm.ast.decompilation.Decompiler; -import org.teavm.backend.lowlevel.generate.NameProvider; import org.teavm.backend.wasm.BaseWasmFunctionRepository; import org.teavm.backend.wasm.WasmFunctionTypes; import org.teavm.backend.wasm.gc.WasmGCVariableCategoryProvider; import org.teavm.backend.wasm.gc.vtable.WasmGCVirtualTableProvider; +import org.teavm.backend.wasm.generate.gc.WasmGCNameProvider; import org.teavm.backend.wasm.generate.gc.classes.WasmGCClassInfoProvider; import org.teavm.backend.wasm.generate.gc.classes.WasmGCStandardClasses; import org.teavm.backend.wasm.generate.gc.classes.WasmGCSupertypeFunctionProvider; @@ -63,7 +63,7 @@ public class WasmGCMethodGenerator implements BaseWasmFunctionRepository { private ClassInitializerInfo classInitInfo; private WasmFunctionTypes functionTypes; private WasmGCSupertypeFunctionProvider supertypeFunctions; - private NameProvider names; + private WasmGCNameProvider names; private Diagnostics diagnostics; private WasmGCTypeMapper typeMapper; private WasmGCCustomGeneratorProvider customGenerators; @@ -86,7 +86,7 @@ public class WasmGCMethodGenerator implements BaseWasmFunctionRepository { WasmGCVirtualTableProvider virtualTables, ClassInitializerInfo classInitInfo, WasmFunctionTypes functionTypes, - NameProvider names, + WasmGCNameProvider names, Diagnostics diagnostics, WasmGCCustomGeneratorProvider customGenerators, WasmGCIntrinsicProvider intrinsics @@ -149,7 +149,7 @@ public class WasmGCMethodGenerator implements BaseWasmFunctionRepository { parameterTypes[i] = typeMapper.mapType(methodReference.parameterType(i)); } var function = new WasmFunction(functionTypes.of(returnType, parameterTypes)); - function.setName(names.forMethod(methodReference)); + function.setName(names.topLevel(names.suggestForMethod(methodReference))); module.functions.add(function); function.setJavaMethod(methodReference); @@ -177,7 +177,7 @@ public class WasmGCMethodGenerator implements BaseWasmFunctionRepository { parameterTypes[i + 1] = typeMapper.mapType(methodReference.parameterType(i)); } var function = new WasmFunction(functionTypes.of(returnType, parameterTypes)); - function.setName(names.forMethod(methodReference)); + function.setName(names.topLevel(names.suggestForMethod(methodReference))); module.functions.add(function); function.setJavaMethod(methodReference); @@ -304,7 +304,8 @@ public class WasmGCMethodGenerator implements BaseWasmFunctionRepository { standardClasses, strings, customGenerators, - intrinsics + intrinsics, + names ); } return context; @@ -314,7 +315,7 @@ public class WasmGCMethodGenerator implements BaseWasmFunctionRepository { if (dummyInitializer == null) { dummyInitializer = new WasmFunction(functionTypes.of(null)); dummyInitializer.getBody().add(new WasmReturn()); - dummyInitializer.setName("teavm_dummy_initializer"); + dummyInitializer.setName(names.topLevel("teavm@dummyInitializer")); dummyInitializer.setReferenced(true); module.functions.add(dummyInitializer); } @@ -341,5 +342,10 @@ public class WasmGCMethodGenerator implements BaseWasmFunctionRepository { public WasmGCClassInfoProvider classInfoProvider() { return classInfoProvider; } + + @Override + public WasmGCNameProvider names() { + return names; + } }; } diff --git a/core/src/main/java/org/teavm/backend/wasm/generate/gc/strings/WasmGCStringPool.java b/core/src/main/java/org/teavm/backend/wasm/generate/gc/strings/WasmGCStringPool.java index eb99b97cb..4afa1866b 100644 --- a/core/src/main/java/org/teavm/backend/wasm/generate/gc/strings/WasmGCStringPool.java +++ b/core/src/main/java/org/teavm/backend/wasm/generate/gc/strings/WasmGCStringPool.java @@ -20,6 +20,7 @@ import java.util.LinkedHashMap; import java.util.Map; import org.teavm.backend.wasm.BaseWasmFunctionRepository; import org.teavm.backend.wasm.generate.gc.WasmGCInitializerContributor; +import org.teavm.backend.wasm.generate.gc.WasmGCNameProvider; import org.teavm.backend.wasm.generate.gc.classes.WasmGCClassInfoProvider; import org.teavm.backend.wasm.generate.gc.classes.WasmGCStandardClasses; import org.teavm.backend.wasm.model.WasmFunction; @@ -43,12 +44,14 @@ public class WasmGCStringPool implements WasmGCStringProvider, WasmGCInitializer private Map stringMap = new LinkedHashMap<>(); private BaseWasmFunctionRepository functionProvider; private WasmFunction nextCharArrayFunction; + private WasmGCNameProvider names; public WasmGCStringPool(WasmGCStandardClasses standardClasses, WasmModule module, - BaseWasmFunctionRepository functionProvider) { + BaseWasmFunctionRepository functionProvider, WasmGCNameProvider names) { this.standardClasses = standardClasses; this.module = module; this.functionProvider = functionProvider; + this.names = names; } @Override @@ -86,7 +89,9 @@ public class WasmGCStringPool implements WasmGCStringProvider, WasmGCInitializer } binaryWriter.writeLEB(string.length()); binaryWriter.writeBytes(string.getBytes(StandardCharsets.UTF_8)); - var globalName = "teavm_java_string_" + stringMap.size(); + var brief = string.length() > 16 ? string.substring(0, 16) : string; + var globalName = names.topLevel("teavm@string<" + stringMap.size() + ">" + + WasmGCNameProvider.sanitize(brief)); var globalType = standardClasses.stringClass().getType(); var global = new WasmGlobal(globalName, globalType, WasmExpression.defaultValueOfType(globalType)); module.globals.add(global); diff --git a/core/src/main/java/org/teavm/backend/wasm/generators/gc/WasmGCCustomGeneratorContext.java b/core/src/main/java/org/teavm/backend/wasm/generators/gc/WasmGCCustomGeneratorContext.java index 5ba27bc16..e76616b9d 100644 --- a/core/src/main/java/org/teavm/backend/wasm/generators/gc/WasmGCCustomGeneratorContext.java +++ b/core/src/main/java/org/teavm/backend/wasm/generators/gc/WasmGCCustomGeneratorContext.java @@ -16,6 +16,7 @@ package org.teavm.backend.wasm.generators.gc; import org.teavm.backend.wasm.WasmFunctionTypes; +import org.teavm.backend.wasm.generate.gc.WasmGCNameProvider; import org.teavm.backend.wasm.generate.gc.classes.WasmGCClassInfoProvider; import org.teavm.backend.wasm.generate.gc.classes.WasmGCTypeMapper; import org.teavm.backend.wasm.model.WasmModule; @@ -28,4 +29,6 @@ public interface WasmGCCustomGeneratorContext { WasmGCTypeMapper typeMapper(); WasmGCClassInfoProvider classInfoProvider(); + + WasmGCNameProvider names(); } diff --git a/core/src/main/java/org/teavm/backend/wasm/generators/gc/WasmGCStringPoolGenerator.java b/core/src/main/java/org/teavm/backend/wasm/generators/gc/WasmGCStringPoolGenerator.java index d4512ca8a..a18c37051 100644 --- a/core/src/main/java/org/teavm/backend/wasm/generators/gc/WasmGCStringPoolGenerator.java +++ b/core/src/main/java/org/teavm/backend/wasm/generators/gc/WasmGCStringPoolGenerator.java @@ -36,7 +36,8 @@ public class WasmGCStringPoolGenerator implements WasmGCCustomGenerator { @Override public void apply(MethodReference method, WasmFunction function, WasmGCCustomGeneratorContext context) { var module = context.module(); - var pointer = new WasmGlobal("teavm_string_pool_pointer", WasmType.INT32, new WasmInt32Constant(0)); + var pointer = new WasmGlobal(context.names().topLevel("teavm@stringPoolPointer"), WasmType.INT32, + new WasmInt32Constant(0)); module.globals.add(pointer); var resultLocal = new WasmLocal(WasmType.INT32); 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 8480c4f84..b579b3218 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 @@ -71,6 +71,10 @@ public class WasmStructure extends WasmCompositeType { var supplier = fieldsSupplier; fieldsSupplier = null; supplier.accept(fieldsStorage); + for (var field : fieldsStorage) { + field.structure = this; + } + indexesValid = false; } } diff --git a/core/src/main/java/org/teavm/backend/wasm/render/WasmBinaryRenderer.java b/core/src/main/java/org/teavm/backend/wasm/render/WasmBinaryRenderer.java index ced1b80a9..ee2ba2a5b 100644 --- a/core/src/main/java/org/teavm/backend/wasm/render/WasmBinaryRenderer.java +++ b/core/src/main/java/org/teavm/backend/wasm/render/WasmBinaryRenderer.java @@ -476,6 +476,30 @@ public class WasmBinaryRenderer { section.writeLEB(payload.length); section.writeBytes(payload); + var functionsWithLocalNames = module.functions.stream() + .filter(fn -> fn.getLocalVariables().stream().anyMatch(v -> v.getName() != null)) + .collect(Collectors.toList()); + if (!functionsWithLocalNames.isEmpty()) { + var subsection = new WasmBinaryWriter(); + subsection.writeLEB(functionsWithLocalNames.size()); + for (var function : functionsWithLocalNames) { + subsection.writeLEB(module.functions.indexOf(function)); + var locals = function.getLocalVariables().stream() + .filter(t -> t.getName() != null) + .collect(Collectors.toList()); + subsection.writeLEB(locals.size()); + for (var local : locals) { + subsection.writeLEB(local.getIndex()); + subsection.writeAsciiString(local.getName()); + } + } + + payload = subsection.getData(); + section.writeLEB(2); + section.writeLEB(payload.length); + section.writeBytes(payload); + } + var types = module.types.stream() .filter(t -> t.getName() != null) .collect(Collectors.toList());