From 86e8cfd0db5467586da39ab2526d22d01205e975 Mon Sep 17 00:00:00 2001 From: Alexey Andreev Date: Sat, 14 Sep 2024 19:34:56 +0200 Subject: [PATCH] wasm gc: reduce size of array construction --- .../gc/classes/WasmGCClassGenerator.java | 11 ++++- .../generate/gc/classes/WasmGCClassInfo.java | 2 + .../gc/classes/WasmGCClassInfoProvider.java | 3 ++ .../WasmGCNewArrayFunctionGenerator.java | 12 ++++-- .../gc/methods/WasmGCGenerationVisitor.java | 40 +++++++++++++++++++ .../main/java/org/teavm/model/ValueType.java | 2 +- 6 files changed, 65 insertions(+), 5 deletions(-) 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 594c3356f..3b7e64364 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 @@ -254,7 +254,7 @@ public class WasmGCClassGenerator implements WasmGCClassInfoProvider, WasmGCInit new WasmFunctionReference(supertypeFunction))); } if (req.newArray()) { - var newArrayFunction = newArrayGenerator.generateNewArrayFunction(classInfo.getValueType()); + var newArrayFunction = getArrayConstructor(ValueType.arrayOf(classInfo.getValueType())); newArrayFunction.setReferenced(true); function.getBody().add(setClassField(classInfo, classNewArrayOffset, new WasmFunctionReference(newArrayFunction))); @@ -350,6 +350,15 @@ public class WasmGCClassGenerator implements WasmGCClassInfoProvider, WasmGCInit return classInfo; } + @Override + public WasmFunction getArrayConstructor(ValueType.Array type) { + var arrayInfo = getClassInfo(type); + if (arrayInfo.newArrayFunction == null) { + arrayInfo.newArrayFunction = newArrayGenerator.generateNewArrayFunction(type.getItemType()); + } + return arrayInfo.newArrayFunction; + } + public int getClassTagOffset() { standardClasses.classClass().getStructure().init(); return classTagOffset; diff --git a/core/src/main/java/org/teavm/backend/wasm/generate/gc/classes/WasmGCClassInfo.java b/core/src/main/java/org/teavm/backend/wasm/generate/gc/classes/WasmGCClassInfo.java index 84e9561cc..1eb8bf7b3 100644 --- a/core/src/main/java/org/teavm/backend/wasm/generate/gc/classes/WasmGCClassInfo.java +++ b/core/src/main/java/org/teavm/backend/wasm/generate/gc/classes/WasmGCClassInfo.java @@ -18,6 +18,7 @@ package org.teavm.backend.wasm.generate.gc.classes; import java.util.List; import java.util.function.Consumer; import org.teavm.backend.wasm.model.WasmArray; +import org.teavm.backend.wasm.model.WasmFunction; import org.teavm.backend.wasm.model.WasmGlobal; import org.teavm.backend.wasm.model.WasmStructure; import org.teavm.backend.wasm.model.WasmType; @@ -31,6 +32,7 @@ public class WasmGCClassInfo { WasmGlobal pointer; WasmGlobal initializerPointer; Consumer> initializer; + WasmFunction newArrayFunction; WasmGCClassInfo(ValueType valueType) { this.valueType = valueType; diff --git a/core/src/main/java/org/teavm/backend/wasm/generate/gc/classes/WasmGCClassInfoProvider.java b/core/src/main/java/org/teavm/backend/wasm/generate/gc/classes/WasmGCClassInfoProvider.java index ce5820cbe..5dee166d6 100644 --- a/core/src/main/java/org/teavm/backend/wasm/generate/gc/classes/WasmGCClassInfoProvider.java +++ b/core/src/main/java/org/teavm/backend/wasm/generate/gc/classes/WasmGCClassInfoProvider.java @@ -15,6 +15,7 @@ */ package org.teavm.backend.wasm.generate.gc.classes; +import org.teavm.backend.wasm.model.WasmFunction; import org.teavm.backend.wasm.model.WasmGlobal; import org.teavm.backend.wasm.model.WasmStructure; import org.teavm.model.FieldReference; @@ -34,6 +35,8 @@ public interface WasmGCClassInfoProvider { WasmGlobal getStaticFieldLocation(FieldReference fieldRef); + WasmFunction getArrayConstructor(ValueType.Array type); + int getVirtualMethodsOffset(); int getClassArrayItemOffset(); 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 d3496fd7e..0dee70222 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 @@ -15,6 +15,7 @@ */ package org.teavm.backend.wasm.generate.gc.classes; +import java.util.List; import org.teavm.backend.wasm.WasmFunctionTypes; import org.teavm.backend.wasm.generate.TemporaryVariablePool; import org.teavm.backend.wasm.generate.gc.WasmGCNameProvider; @@ -44,15 +45,19 @@ class WasmGCNewArrayFunctionGenerator { } WasmFunction generateNewArrayFunction(ValueType itemType) { - var function = new WasmFunction(getNewArrayFunctionType()); + var classInfo = classInfoProvider.getClassInfo(ValueType.arrayOf(itemType)); + var functionType = new WasmFunctionType(null, classInfo.getType(), List.of(WasmType.INT32)); + module.types.add(functionType); + functionType.setFinal(true); + functionType.getSupertypes().add(getNewArrayFunctionType()); + var function = new WasmFunction(functionType); function.setName(names.topLevel("Array<" + names.suggestForType(itemType) + ">@new")); module.functions.add(function); 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(), - "result"); + var targetVar = new WasmLocal(classInfo.getType(), "result"); function.add(targetVar); genUtil.allocateArray(itemType, () -> new WasmGetLocal(sizeLocal), null, targetVar, function.getBody()); function.getBody().add(new WasmReturn(new WasmGetLocal(targetVar))); @@ -63,6 +68,7 @@ class WasmGCNewArrayFunctionGenerator { if (newArrayFunctionType == null) { newArrayFunctionType = functionTypes.of(classInfoProvider.getClassInfo("java.lang.Object").getType(), WasmType.INT32); + newArrayFunctionType.setFinal(false); } return newArrayFunctionType; } 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 76116fca0..b2515e903 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 @@ -15,8 +15,10 @@ */ package org.teavm.backend.wasm.generate.gc.methods; +import java.util.ArrayList; import java.util.List; import java.util.function.Supplier; +import org.teavm.ast.ArrayFromDataExpr; import org.teavm.ast.ArrayType; import org.teavm.ast.BinaryExpr; import org.teavm.ast.CastExpr; @@ -25,6 +27,7 @@ import org.teavm.ast.Expr; import org.teavm.ast.InstanceOfExpr; import org.teavm.ast.InvocationExpr; import org.teavm.ast.InvocationType; +import org.teavm.ast.NewArrayExpr; import org.teavm.ast.QualificationExpr; import org.teavm.ast.SubscriptExpr; import org.teavm.ast.TryCatchStatement; @@ -242,6 +245,7 @@ public class WasmGCGenerationVisitor extends BaseWasmGenerationVisitor { return new WasmIsNull(value); } + @Override protected WasmExpression nullCheck(Expr value, TextLocation location) { var block = new WasmBlock(false); block.setLocation(location); @@ -360,6 +364,42 @@ public class WasmGCGenerationVisitor extends BaseWasmGenerationVisitor { } } + @Override + public void visit(ArrayFromDataExpr expr) { + var wasmArrayType = (WasmType.CompositeReference) mapType(ValueType.arrayOf(expr.getType())); + var block = new WasmBlock(false); + block.setType(wasmArrayType); + var wasmArrayStruct = (WasmStructure) wasmArrayType.composite; + var wasmArrayDataType = (WasmType.CompositeReference) wasmArrayStruct.getFields() + .get(WasmGCClassInfoProvider.ARRAY_DATA_FIELD_OFFSET).getUnpackedType(); + var wasmArray = (WasmArray) wasmArrayDataType.composite; + var array = tempVars.acquire(wasmArrayType); + + generationUtil.allocateArrayWithElements(expr.getType(), () -> { + var items = new ArrayList(); + for (int i = 0; i < expr.getData().size(); ++i) { + accept(expr.getData().get(i), wasmArray.getElementType().asUnpackedType()); + items.add(result); + } + return items; + }, expr.getLocation(), array, block.getBody()); + + block.getBody().add(new WasmGetLocal(array)); + block.setLocation(expr.getLocation()); + tempVars.release(array); + + result = block; + } + + @Override + public void visit(NewArrayExpr expr) { + accept(expr.getLength(), WasmType.INT32); + var function = context.classInfoProvider().getArrayConstructor(ValueType.arrayOf(expr.getType())); + var call = new WasmCall(function, result); + call.setLocation(expr.getLocation()); + result = call; + } + @Override protected void allocateArray(ValueType itemType, Supplier length, TextLocation location, WasmLocal local, List target) { diff --git a/core/src/main/java/org/teavm/model/ValueType.java b/core/src/main/java/org/teavm/model/ValueType.java index 67d89e18b..c24c329cf 100644 --- a/core/src/main/java/org/teavm/model/ValueType.java +++ b/core/src/main/java/org/teavm/model/ValueType.java @@ -240,7 +240,7 @@ public abstract class ValueType implements Serializable { return new Object(cls); } - public static ValueType arrayOf(ValueType type) { + public static ValueType.Array arrayOf(ValueType type) { return new Array(type); }