wasm gc: generate array constructor using ref.struct_new

This commit is contained in:
Alexey Andreev 2024-09-26 19:32:02 +02:00
parent 4d416af7dc
commit 054d4c2a24
9 changed files with 109 additions and 183 deletions

View File

@ -18,7 +18,6 @@ package org.teavm.classlib.impl;
import java.util.ArrayList;
import java.util.Collection;
import java.util.ServiceLoader;
import org.teavm.backend.wasm.generate.TemporaryVariablePool;
import org.teavm.backend.wasm.generate.gc.classes.WasmGCClassInfoProvider;
import org.teavm.backend.wasm.generate.gc.methods.WasmGCGenerationUtil;
import org.teavm.backend.wasm.generators.gc.WasmGCCustomGenerator;
@ -129,17 +128,14 @@ public class ServiceLoaderWasmGCSupport implements WasmGCCustomGeneratorFactory
function.setName(context.names().topLevel(context.names().suggestForClass(interfaceName) + "@services"));
function.setReferenced(true);
context.module().functions.add(function);
var tempVars = new TemporaryVariablePool(function);
var util = new WasmGCGenerationUtil(context.classInfoProvider(), tempVars);
var block = new WasmBlock(false);
block.setType(context.typeMapper().mapType(ValueType.parse(Object[].class)));
util.allocateArrayWithElements(ValueType.parse(Object.class), () -> {
var util = new WasmGCGenerationUtil(context.classInfoProvider());
function.getBody().add(util.allocateArrayWithElements(ValueType.parse(Object.class), () -> {
var items = new ArrayList<WasmExpression>();
for (var implementationName : implementations) {
items.add(instantiateService(context, function, implementationName));
}
return items;
}, null, null, function.getBody());
}));
return function;
}

View File

@ -20,12 +20,14 @@ import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.function.Supplier;
import org.teavm.ast.ArrayFromDataExpr;
import org.teavm.ast.ArrayType;
import org.teavm.ast.CastExpr;
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.Statement;
import org.teavm.ast.SubscriptExpr;
@ -767,7 +769,26 @@ public class WasmGenerationVisitor extends BaseWasmGenerationVisitor {
}
@Override
protected void allocateArray(ValueType itemType, Supplier<WasmExpression> length, TextLocation location,
public void visit(NewArrayExpr expr) {
var block = new WasmBlock(false);
block.setType(mapType(ValueType.arrayOf(expr.getType())));
var callSiteId = generateCallSiteId(expr.getLocation());
callSiteId.generateRegister(block.getBody(), expr.getLocation());
allocateArray(expr.getType(), () -> {
accept(expr.getLength());
return result;
}, expr.getLocation(), null, block.getBody());
if (block.getBody().size() == 1) {
result = block.getBody().get(0);
} else {
result = block;
}
}
private void allocateArray(ValueType itemType, Supplier<WasmExpression> length, TextLocation location,
WasmLocal local, List<WasmExpression> target) {
int classPointer = classGenerator.getClassPointer(ValueType.arrayOf(itemType));
var allocFunction = context.functions().forStaticMethod(new MethodReference(Allocator.class, "allocateArray",
@ -783,6 +804,61 @@ public class WasmGenerationVisitor extends BaseWasmGenerationVisitor {
}
}
@Override
public void visit(ArrayFromDataExpr expr) {
var type = expr.getType();
var arrayType = ArrayType.OBJECT;
if (type instanceof ValueType.Primitive) {
switch (((ValueType.Primitive) type).getKind()) {
case BOOLEAN:
case BYTE:
arrayType = ArrayType.BYTE;
break;
case SHORT:
arrayType = ArrayType.SHORT;
break;
case CHARACTER:
arrayType = ArrayType.CHAR;
break;
case INTEGER:
arrayType = ArrayType.INT;
break;
case LONG:
arrayType = ArrayType.LONG;
break;
case FLOAT:
arrayType = ArrayType.FLOAT;
break;
case DOUBLE:
arrayType = ArrayType.DOUBLE;
break;
}
}
var wasmArrayType = mapType(ValueType.arrayOf(expr.getType()));
var block = new WasmBlock(false);
block.setType(wasmArrayType);
var callSiteId = generateCallSiteId(expr.getLocation());
callSiteId.generateRegister(block.getBody(), expr.getLocation());
var array = tempVars.acquire(wasmArrayType);
allocateArray(expr.getType(), () -> new WasmInt32Constant(expr.getData().size()), expr.getLocation(), array,
block.getBody());
for (int i = 0; i < expr.getData().size(); ++i) {
var arrayData = unwrapArray(new WasmGetLocal(array));
block.getBody().add(storeArrayItem(arrayData, new WasmInt32Constant(i), expr.getData().get(i),
arrayType));
}
block.getBody().add(new WasmGetLocal(array));
block.setLocation(expr.getLocation());
tempVars.release(array);
result = block;
}
@Override
protected WasmExpression allocateMultiArray(List<WasmExpression> target, ValueType arrayType,
Supplier<List<WasmExpression>> dimensions, TextLocation location) {

View File

@ -24,7 +24,6 @@ import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.function.Supplier;
import org.teavm.ast.ArrayFromDataExpr;
import org.teavm.ast.ArrayType;
import org.teavm.ast.AssignmentStatement;
import org.teavm.ast.BinaryExpr;
@ -46,7 +45,6 @@ import org.teavm.ast.InvocationExpr;
import org.teavm.ast.InvocationType;
import org.teavm.ast.MonitorEnterStatement;
import org.teavm.ast.MonitorExitStatement;
import org.teavm.ast.NewArrayExpr;
import org.teavm.ast.NewExpr;
import org.teavm.ast.NewMultiArrayExpr;
import org.teavm.ast.OperationType;
@ -1018,87 +1016,9 @@ public abstract class BaseWasmGenerationVisitor implements StatementVisitor, Exp
protected abstract void allocateObject(String className, TextLocation location, WasmLocal local,
List<WasmExpression> target);
@Override
public void visit(NewArrayExpr expr) {
var block = new WasmBlock(false);
block.setType(mapType(ValueType.arrayOf(expr.getType())));
var callSiteId = generateCallSiteId(expr.getLocation());
callSiteId.generateRegister(block.getBody(), expr.getLocation());
allocateArray(expr.getType(), () -> {
accept(expr.getLength());
return result;
}, expr.getLocation(), null, block.getBody());
if (block.getBody().size() == 1) {
result = block.getBody().get(0);
} else {
result = block;
}
}
protected abstract void allocateArray(ValueType itemType, Supplier<WasmExpression> length, TextLocation location,
WasmLocal local, List<WasmExpression> target);
protected abstract WasmExpression allocateMultiArray(List<WasmExpression> target, ValueType arrayType,
Supplier<List<WasmExpression>> dimensions, TextLocation location);
@Override
public void visit(ArrayFromDataExpr expr) {
var type = expr.getType();
var arrayType = ArrayType.OBJECT;
if (type instanceof ValueType.Primitive) {
switch (((ValueType.Primitive) type).getKind()) {
case BOOLEAN:
case BYTE:
arrayType = ArrayType.BYTE;
break;
case SHORT:
arrayType = ArrayType.SHORT;
break;
case CHARACTER:
arrayType = ArrayType.CHAR;
break;
case INTEGER:
arrayType = ArrayType.INT;
break;
case LONG:
arrayType = ArrayType.LONG;
break;
case FLOAT:
arrayType = ArrayType.FLOAT;
break;
case DOUBLE:
arrayType = ArrayType.DOUBLE;
break;
}
}
var wasmArrayType = mapType(ValueType.arrayOf(expr.getType()));
var block = new WasmBlock(false);
block.setType(wasmArrayType);
var callSiteId = generateCallSiteId(expr.getLocation());
callSiteId.generateRegister(block.getBody(), expr.getLocation());
var array = tempVars.acquire(wasmArrayType);
allocateArray(expr.getType(), () -> new WasmInt32Constant(expr.getData().size()), expr.getLocation(), array,
block.getBody());
for (int i = 0; i < expr.getData().size(); ++i) {
var arrayData = unwrapArray(new WasmGetLocal(array));
block.getBody().add(storeArrayItem(arrayData, new WasmInt32Constant(i), expr.getData().get(i),
arrayType));
}
block.getBody().add(new WasmGetLocal(array));
block.setLocation(expr.getLocation());
tempVars.release(array);
result = block;
}
@Override
public void visit(NewMultiArrayExpr expr) {
var block = new WasmBlock(false);

View File

@ -33,7 +33,6 @@ 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.TemporaryVariablePool;
import org.teavm.backend.wasm.generate.gc.WasmGCInitializerContributor;
import org.teavm.backend.wasm.generate.gc.WasmGCNameProvider;
import org.teavm.backend.wasm.generate.gc.methods.WasmGCGenerationUtil;
@ -52,7 +51,6 @@ import org.teavm.backend.wasm.model.expression.WasmArrayCopy;
import org.teavm.backend.wasm.model.expression.WasmArrayGet;
import org.teavm.backend.wasm.model.expression.WasmArrayLength;
import org.teavm.backend.wasm.model.expression.WasmArrayNewDefault;
import org.teavm.backend.wasm.model.expression.WasmBlock;
import org.teavm.backend.wasm.model.expression.WasmCall;
import org.teavm.backend.wasm.model.expression.WasmCallReference;
import org.teavm.backend.wasm.model.expression.WasmCast;
@ -1543,14 +1541,8 @@ public class WasmGCClassGenerator implements WasmGCClassInfoProvider, WasmGCInit
functionTypes.of(null)));
}
var tempVars = new TemporaryVariablePool(function);
var util = new WasmGCGenerationUtil(this, tempVars);
var local = tempVars.acquire(enumArrayStruct.getReference());
var block = new WasmBlock(false);
block.setType(enumArrayStruct.getReference());
util.allocateArrayWithElements(ValueType.parse(Enum.class), () -> fields, null, null, block.getBody());
function.getBody().add(block);
tempVars.release(local);
var util = new WasmGCGenerationUtil(this);
function.getBody().add(util.allocateArrayWithElements(ValueType.parse(Enum.class), () -> fields));
return function;
}

View File

@ -19,7 +19,6 @@ import java.util.Arrays;
import java.util.List;
import java.util.Queue;
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.WasmArray;
@ -75,12 +74,10 @@ class WasmGCNewArrayFunctionGenerator {
queue.add(() -> {
var sizeLocal = new WasmLocal(WasmType.INT32, "length");
function.add(sizeLocal);
var tempVars = new TemporaryVariablePool(function);
var genUtil = new WasmGCGenerationUtil(classInfoProvider, tempVars);
var genUtil = new WasmGCGenerationUtil(classInfoProvider);
var targetVar = new WasmLocal(classInfo.getType(), "result");
function.add(targetVar);
genUtil.allocateArray(itemType, () -> new WasmGetLocal(sizeLocal), null, targetVar, function.getBody());
function.getBody().add(new WasmGetLocal(targetVar));
function.getBody().add(genUtil.allocateArray(itemType, () -> new WasmGetLocal(sizeLocal)));
});
return function;
}

View File

@ -104,8 +104,8 @@ public class WasmGCTypeMapper {
if (type instanceof ValueType.Object) {
var className = ((ValueType.Object) type).getClassName();
var cls = classes.get(className);
if (cls != null) {
className = "java.lang.Object";
if (cls == null) {
type = ValueType.object("java.lang.Object");
}
}
while (degree-- > 0) {

View File

@ -18,83 +18,49 @@ package org.teavm.backend.wasm.generate.gc.methods;
import java.util.List;
import java.util.function.Function;
import java.util.function.Supplier;
import org.teavm.backend.wasm.generate.TemporaryVariablePool;
import org.teavm.backend.wasm.generate.gc.classes.WasmGCClassInfoProvider;
import org.teavm.backend.wasm.model.WasmArray;
import org.teavm.backend.wasm.model.WasmLocal;
import org.teavm.backend.wasm.model.WasmType;
import org.teavm.backend.wasm.model.expression.WasmArrayNewDefault;
import org.teavm.backend.wasm.model.expression.WasmArrayNewFixed;
import org.teavm.backend.wasm.model.expression.WasmBlock;
import org.teavm.backend.wasm.model.expression.WasmExpression;
import org.teavm.backend.wasm.model.expression.WasmGetGlobal;
import org.teavm.backend.wasm.model.expression.WasmGetLocal;
import org.teavm.backend.wasm.model.expression.WasmSetLocal;
import org.teavm.backend.wasm.model.expression.WasmStructNewDefault;
import org.teavm.backend.wasm.model.expression.WasmStructSet;
import org.teavm.model.TextLocation;
import org.teavm.backend.wasm.model.expression.WasmNullConstant;
import org.teavm.backend.wasm.model.expression.WasmStructNew;
import org.teavm.model.ValueType;
public class WasmGCGenerationUtil {
private WasmGCClassInfoProvider classInfoProvider;
private TemporaryVariablePool tempVars;
public WasmGCGenerationUtil(WasmGCClassInfoProvider classInfoProvider, TemporaryVariablePool tempVars) {
public WasmGCGenerationUtil(WasmGCClassInfoProvider classInfoProvider) {
this.classInfoProvider = classInfoProvider;
this.tempVars = tempVars;
}
public void allocateArray(ValueType itemType, Supplier<WasmExpression> length, TextLocation location,
WasmLocal local, List<WasmExpression> target) {
allocateArray(itemType, location, local, target, arrayType -> new WasmArrayNewDefault(arrayType, length.get()));
public WasmExpression allocateArray(ValueType itemType, Supplier<WasmExpression> length) {
return allocateArray(itemType, arrayType -> new WasmArrayNewDefault(arrayType, length.get()));
}
public void allocateArrayWithElements(ValueType itemType, Supplier<List<? extends WasmExpression>> data,
TextLocation location, WasmLocal local, List<WasmExpression> target) {
allocateArray(itemType, location, local, target, arrayType -> {
public WasmExpression allocateArrayWithElements(ValueType itemType,
Supplier<List<? extends WasmExpression>> data) {
return allocateArray(itemType, arrayType -> {
var expr = new WasmArrayNewFixed(arrayType);
expr.getElements().addAll(data.get());
return expr;
});
}
public void allocateArray(ValueType itemType, TextLocation location,
WasmLocal local, List<WasmExpression> target, Function<WasmArray, WasmExpression> data) {
public WasmExpression allocateArray(ValueType itemType, Function<WasmArray, WasmExpression> data) {
var classInfo = classInfoProvider.getClassInfo(ValueType.arrayOf(itemType));
var block = new WasmBlock(false);
block.setType(classInfo.getType());
var targetVar = local;
if (targetVar == null) {
targetVar = tempVars.acquire(classInfo.getType());
}
var structNew = new WasmSetLocal(targetVar, new WasmStructNewDefault(classInfo.getStructure()));
structNew.setLocation(location);
target.add(structNew);
var initClassField = new WasmStructSet(classInfo.getStructure(), new WasmGetLocal(targetVar),
WasmGCClassInfoProvider.CLASS_FIELD_OFFSET, new WasmGetGlobal(classInfo.getPointer()));
initClassField.setLocation(location);
target.add(initClassField);
var wasmArrayType = (WasmType.CompositeReference) classInfo.getStructure().getFields()
.get(WasmGCClassInfoProvider.ARRAY_DATA_FIELD_OFFSET)
.getUnpackedType();
var wasmArray = (WasmArray) wasmArrayType.composite;
var initArrayField = new WasmStructSet(
classInfo.getStructure(),
new WasmGetLocal(targetVar),
WasmGCClassInfoProvider.ARRAY_DATA_FIELD_OFFSET,
data.apply(wasmArray)
);
initArrayField.setLocation(location);
target.add(initArrayField);
if (local == null) {
var getLocal = new WasmGetLocal(targetVar);
getLocal.setLocation(location);
target.add(getLocal);
tempVars.release(targetVar);
}
var structNew = new WasmStructNew(classInfo.getStructure());
structNew.getInitializers().add(new WasmGetGlobal(classInfo.getPointer()));
structNew.getInitializers().add(new WasmNullConstant(WasmType.Reference.EQ));
structNew.getInitializers().add(data.apply(wasmArray));
return structNew;
}
}

View File

@ -99,7 +99,7 @@ public class WasmGCGenerationVisitor extends BaseWasmGenerationVisitor {
WasmFunction function, int firstVariable, boolean async, PreciseTypeInference types) {
super(context, currentMethod, function, firstVariable, async);
this.context = context;
generationUtil = new WasmGCGenerationUtil(context.classInfoProvider(), tempVars);
generationUtil = new WasmGCGenerationUtil(context.classInfoProvider());
this.types = types;
}
@ -370,28 +370,22 @@ 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 array = 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());
});
array.setLocation(expr.getLocation());
block.getBody().add(new WasmGetLocal(array));
block.setLocation(expr.getLocation());
tempVars.release(array);
result = block;
result = array;
}
@Override
@ -403,12 +397,6 @@ public class WasmGCGenerationVisitor extends BaseWasmGenerationVisitor {
result = call;
}
@Override
protected void allocateArray(ValueType itemType, Supplier<WasmExpression> length, TextLocation location,
WasmLocal local, List<WasmExpression> target) {
generationUtil.allocateArray(itemType, length, location, local, target);
}
@Override
protected WasmExpression allocateMultiArray(List<WasmExpression> target, ValueType arrayType,
Supplier<List<WasmExpression>> dimensions, TextLocation location) {

View File

@ -23,18 +23,15 @@ import java.util.Arrays;
import java.util.LinkedHashSet;
import java.util.Properties;
import java.util.ServiceLoader;
import org.teavm.backend.wasm.generate.TemporaryVariablePool;
import org.teavm.backend.wasm.generate.gc.methods.WasmGCGenerationUtil;
import org.teavm.backend.wasm.model.WasmFunction;
import org.teavm.backend.wasm.model.WasmGlobal;
import org.teavm.backend.wasm.model.WasmLocal;
import org.teavm.backend.wasm.model.WasmMemorySegment;
import org.teavm.backend.wasm.model.WasmModule;
import org.teavm.backend.wasm.model.WasmType;
import org.teavm.backend.wasm.model.expression.WasmCall;
import org.teavm.backend.wasm.model.expression.WasmExpression;
import org.teavm.backend.wasm.model.expression.WasmGetGlobal;
import org.teavm.backend.wasm.model.expression.WasmGetLocal;
import org.teavm.backend.wasm.model.expression.WasmInt32Constant;
import org.teavm.backend.wasm.model.expression.WasmIntBinary;
import org.teavm.backend.wasm.model.expression.WasmIntBinaryOperation;
@ -105,13 +102,11 @@ public class WasmGCResourcesGenerator implements WasmGCCustomGenerator {
WasmType.INT32, new WasmInt32Constant(0));
context.module().globals.add(baseGlobal);
var genUtil = new WasmGCGenerationUtil(context.classInfoProvider(), new TemporaryVariablePool(function));
var local = new WasmLocal(context.typeMapper().mapType(ValueType.parse(WasmGCResources.Resource[].class)));
function.add(local);
var genUtil = new WasmGCGenerationUtil(context.classInfoProvider());
var constructor = context.functions().forStaticMethod(new MethodReference(WasmGCResources.class,
"create", String.class, int.class, int.class, WasmGCResources.Resource.class));
genUtil.allocateArrayWithElements(
function.getBody().add(genUtil.allocateArrayWithElements(
ValueType.parse(WasmGCResources.Resource.class),
() -> {
var items = new ArrayList<WasmExpression>();
@ -123,12 +118,8 @@ public class WasmGCResourcesGenerator implements WasmGCCustomGenerator {
items.add(new WasmCall(constructor, new WasmGetGlobal(name.global), offset, end));
}
return items;
},
null,
local,
function.getBody()
);
function.getBody().add(new WasmGetLocal(local));
}
));
}
}