wasm gc: reduce size of array construction

This commit is contained in:
Alexey Andreev 2024-09-14 19:34:56 +02:00
parent e5d6603503
commit 86e8cfd0db
6 changed files with 65 additions and 5 deletions

View File

@ -254,7 +254,7 @@ public class WasmGCClassGenerator implements WasmGCClassInfoProvider, WasmGCInit
new WasmFunctionReference(supertypeFunction))); new WasmFunctionReference(supertypeFunction)));
} }
if (req.newArray()) { if (req.newArray()) {
var newArrayFunction = newArrayGenerator.generateNewArrayFunction(classInfo.getValueType()); var newArrayFunction = getArrayConstructor(ValueType.arrayOf(classInfo.getValueType()));
newArrayFunction.setReferenced(true); newArrayFunction.setReferenced(true);
function.getBody().add(setClassField(classInfo, classNewArrayOffset, function.getBody().add(setClassField(classInfo, classNewArrayOffset,
new WasmFunctionReference(newArrayFunction))); new WasmFunctionReference(newArrayFunction)));
@ -350,6 +350,15 @@ public class WasmGCClassGenerator implements WasmGCClassInfoProvider, WasmGCInit
return classInfo; 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() { public int getClassTagOffset() {
standardClasses.classClass().getStructure().init(); standardClasses.classClass().getStructure().init();
return classTagOffset; return classTagOffset;

View File

@ -18,6 +18,7 @@ package org.teavm.backend.wasm.generate.gc.classes;
import java.util.List; import java.util.List;
import java.util.function.Consumer; import java.util.function.Consumer;
import org.teavm.backend.wasm.model.WasmArray; 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.WasmGlobal;
import org.teavm.backend.wasm.model.WasmStructure; import org.teavm.backend.wasm.model.WasmStructure;
import org.teavm.backend.wasm.model.WasmType; import org.teavm.backend.wasm.model.WasmType;
@ -31,6 +32,7 @@ public class WasmGCClassInfo {
WasmGlobal pointer; WasmGlobal pointer;
WasmGlobal initializerPointer; WasmGlobal initializerPointer;
Consumer<List<WasmExpression>> initializer; Consumer<List<WasmExpression>> initializer;
WasmFunction newArrayFunction;
WasmGCClassInfo(ValueType valueType) { WasmGCClassInfo(ValueType valueType) {
this.valueType = valueType; this.valueType = valueType;

View File

@ -15,6 +15,7 @@
*/ */
package org.teavm.backend.wasm.generate.gc.classes; 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.WasmGlobal;
import org.teavm.backend.wasm.model.WasmStructure; import org.teavm.backend.wasm.model.WasmStructure;
import org.teavm.model.FieldReference; import org.teavm.model.FieldReference;
@ -34,6 +35,8 @@ public interface WasmGCClassInfoProvider {
WasmGlobal getStaticFieldLocation(FieldReference fieldRef); WasmGlobal getStaticFieldLocation(FieldReference fieldRef);
WasmFunction getArrayConstructor(ValueType.Array type);
int getVirtualMethodsOffset(); int getVirtualMethodsOffset();
int getClassArrayItemOffset(); int getClassArrayItemOffset();

View File

@ -15,6 +15,7 @@
*/ */
package org.teavm.backend.wasm.generate.gc.classes; package org.teavm.backend.wasm.generate.gc.classes;
import java.util.List;
import org.teavm.backend.wasm.WasmFunctionTypes; import org.teavm.backend.wasm.WasmFunctionTypes;
import org.teavm.backend.wasm.generate.TemporaryVariablePool; import org.teavm.backend.wasm.generate.TemporaryVariablePool;
import org.teavm.backend.wasm.generate.gc.WasmGCNameProvider; import org.teavm.backend.wasm.generate.gc.WasmGCNameProvider;
@ -44,15 +45,19 @@ class WasmGCNewArrayFunctionGenerator {
} }
WasmFunction generateNewArrayFunction(ValueType itemType) { 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")); function.setName(names.topLevel("Array<" + names.suggestForType(itemType) + ">@new"));
module.functions.add(function); module.functions.add(function);
var sizeLocal = new WasmLocal(WasmType.INT32, "length"); var sizeLocal = new WasmLocal(WasmType.INT32, "length");
function.add(sizeLocal); function.add(sizeLocal);
var tempVars = new TemporaryVariablePool(function); var tempVars = new TemporaryVariablePool(function);
var genUtil = new WasmGCGenerationUtil(classInfoProvider, tempVars); var genUtil = new WasmGCGenerationUtil(classInfoProvider, tempVars);
var targetVar = new WasmLocal(classInfoProvider.getClassInfo(ValueType.arrayOf(itemType)).getType(), var targetVar = new WasmLocal(classInfo.getType(), "result");
"result");
function.add(targetVar); function.add(targetVar);
genUtil.allocateArray(itemType, () -> new WasmGetLocal(sizeLocal), null, targetVar, function.getBody()); genUtil.allocateArray(itemType, () -> new WasmGetLocal(sizeLocal), null, targetVar, function.getBody());
function.getBody().add(new WasmReturn(new WasmGetLocal(targetVar))); function.getBody().add(new WasmReturn(new WasmGetLocal(targetVar)));
@ -63,6 +68,7 @@ class WasmGCNewArrayFunctionGenerator {
if (newArrayFunctionType == null) { if (newArrayFunctionType == null) {
newArrayFunctionType = functionTypes.of(classInfoProvider.getClassInfo("java.lang.Object").getType(), newArrayFunctionType = functionTypes.of(classInfoProvider.getClassInfo("java.lang.Object").getType(),
WasmType.INT32); WasmType.INT32);
newArrayFunctionType.setFinal(false);
} }
return newArrayFunctionType; return newArrayFunctionType;
} }

View File

@ -15,8 +15,10 @@
*/ */
package org.teavm.backend.wasm.generate.gc.methods; package org.teavm.backend.wasm.generate.gc.methods;
import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.function.Supplier; import java.util.function.Supplier;
import org.teavm.ast.ArrayFromDataExpr;
import org.teavm.ast.ArrayType; import org.teavm.ast.ArrayType;
import org.teavm.ast.BinaryExpr; import org.teavm.ast.BinaryExpr;
import org.teavm.ast.CastExpr; import org.teavm.ast.CastExpr;
@ -25,6 +27,7 @@ import org.teavm.ast.Expr;
import org.teavm.ast.InstanceOfExpr; import org.teavm.ast.InstanceOfExpr;
import org.teavm.ast.InvocationExpr; import org.teavm.ast.InvocationExpr;
import org.teavm.ast.InvocationType; import org.teavm.ast.InvocationType;
import org.teavm.ast.NewArrayExpr;
import org.teavm.ast.QualificationExpr; import org.teavm.ast.QualificationExpr;
import org.teavm.ast.SubscriptExpr; import org.teavm.ast.SubscriptExpr;
import org.teavm.ast.TryCatchStatement; import org.teavm.ast.TryCatchStatement;
@ -242,6 +245,7 @@ public class WasmGCGenerationVisitor extends BaseWasmGenerationVisitor {
return new WasmIsNull(value); return new WasmIsNull(value);
} }
@Override
protected WasmExpression nullCheck(Expr value, TextLocation location) { protected WasmExpression nullCheck(Expr value, TextLocation location) {
var block = new WasmBlock(false); var block = new WasmBlock(false);
block.setLocation(location); 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<WasmExpression>();
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 @Override
protected void allocateArray(ValueType itemType, Supplier<WasmExpression> length, TextLocation location, protected void allocateArray(ValueType itemType, Supplier<WasmExpression> length, TextLocation location,
WasmLocal local, List<WasmExpression> target) { WasmLocal local, List<WasmExpression> target) {

View File

@ -240,7 +240,7 @@ public abstract class ValueType implements Serializable {
return new Object(cls); return new Object(cls);
} }
public static ValueType arrayOf(ValueType type) { public static ValueType.Array arrayOf(ValueType type) {
return new Array(type); return new Array(type);
} }