mirror of
https://github.com/Eaglercraft-TeaVM-Fork/eagler-teavm.git
synced 2024-12-22 08:14:09 -08:00
wasm gc: draft first parts of Wasm GC backend
* class metadata generator * string pool generator
This commit is contained in:
parent
efcb22b639
commit
7efb3c97a0
|
@ -73,6 +73,7 @@ import org.teavm.model.instructions.IsInstanceInstruction;
|
|||
import org.teavm.model.instructions.StringConstantInstruction;
|
||||
import org.teavm.model.lowlevel.CallSiteDescriptor;
|
||||
import org.teavm.model.lowlevel.Characteristics;
|
||||
import org.teavm.model.util.ReflectionUtil;
|
||||
import org.teavm.runtime.CallSite;
|
||||
import org.teavm.runtime.RuntimeArray;
|
||||
import org.teavm.runtime.RuntimeClass;
|
||||
|
@ -1295,26 +1296,7 @@ public class ClassGenerator {
|
|||
|
||||
public String nameOfType(ValueType type) {
|
||||
if (type instanceof ValueType.Primitive) {
|
||||
switch (((ValueType.Primitive) type).getKind()) {
|
||||
case BOOLEAN:
|
||||
return "boolean";
|
||||
case BYTE:
|
||||
return "byte";
|
||||
case SHORT:
|
||||
return "short";
|
||||
case CHARACTER:
|
||||
return "char";
|
||||
case INTEGER:
|
||||
return "int";
|
||||
case LONG:
|
||||
return "long";
|
||||
case FLOAT:
|
||||
return "float";
|
||||
case DOUBLE:
|
||||
return "double";
|
||||
default:
|
||||
throw new AssertionError();
|
||||
}
|
||||
return ReflectionUtil.typeName(((ValueType.Primitive) type).getKind());
|
||||
} else if (type instanceof ValueType.Array) {
|
||||
if (isArrayOfPrimitives(type)) {
|
||||
return type.toString().replace('/', '.');
|
||||
|
|
|
@ -55,6 +55,7 @@ import org.teavm.model.classes.VirtualTable;
|
|||
import org.teavm.model.classes.VirtualTableEntry;
|
||||
import org.teavm.model.classes.VirtualTableProvider;
|
||||
import org.teavm.model.lowlevel.Characteristics;
|
||||
import org.teavm.model.util.ReflectionUtil;
|
||||
import org.teavm.runtime.RuntimeClass;
|
||||
import org.teavm.runtime.RuntimeObject;
|
||||
|
||||
|
@ -250,34 +251,7 @@ public class WasmClassGenerator {
|
|||
if (type == ValueType.VOID) {
|
||||
name = "void";
|
||||
} else {
|
||||
switch (((ValueType.Primitive) type).getKind()) {
|
||||
case BOOLEAN:
|
||||
name = "boolean";
|
||||
break;
|
||||
case BYTE:
|
||||
name = "byte";
|
||||
break;
|
||||
case SHORT:
|
||||
name = "short";
|
||||
break;
|
||||
case CHARACTER:
|
||||
name = "char";
|
||||
break;
|
||||
case INTEGER:
|
||||
name = "int";
|
||||
break;
|
||||
case LONG:
|
||||
name = "long";
|
||||
break;
|
||||
case FLOAT:
|
||||
name = "float";
|
||||
break;
|
||||
case DOUBLE:
|
||||
name = "double";
|
||||
break;
|
||||
default:
|
||||
name = "";
|
||||
}
|
||||
name = ReflectionUtil.typeName(((ValueType.Primitive) type).getKind());
|
||||
}
|
||||
|
||||
value.setAddress(CLASS_NAME, stringPool.getStringPointer(name));
|
||||
|
|
|
@ -0,0 +1,49 @@
|
|||
/*
|
||||
* 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.classes;
|
||||
|
||||
public final class WasmGCClassFlags {
|
||||
public static final int ABSTRACT = 1;
|
||||
public static final int INTERFACE = 1 << 1;
|
||||
public static final int FINAL = 1 << 2;
|
||||
public static final int ENUM = 1 << 3;
|
||||
public static final int ANNOTATION = 1 << 4;
|
||||
public static final int SYNTHETIC = 1 << 5;
|
||||
public static final int BRIDGE = 1 << 6;
|
||||
public static final int DEPRECATED = 1 << 7;
|
||||
public static final int NATIVE = 1 << 8;
|
||||
public static final int STATIC = 1 << 9;
|
||||
public static final int STRICT = 1 << 10;
|
||||
public static final int SYNCHRONIZED = 1 << 11;
|
||||
public static final int TRANSIENT = 1 << 12;
|
||||
public static final int VARARGS = 1 << 13;
|
||||
public static final int VOLATILE = 1 << 14;
|
||||
public static final int PRIMITIVE = 1 << 15;
|
||||
|
||||
public static final int PRIMITIVE_KIND_SHIFT = 16;
|
||||
public static final int PRIMITIVE_BOOLEAN = 0;
|
||||
public static final int PRIMITIVE_BYTE = 1;
|
||||
public static final int PRIMITIVE_SHORT = 2;
|
||||
public static final int PRIMITIVE_CHAR = 3;
|
||||
public static final int PRIMITIVE_INT = 4;
|
||||
public static final int PRIMITIVE_LONG = 5;
|
||||
public static final int PRIMITIVE_FLOAT = 6;
|
||||
public static final int PRIMITIVE_DOUBLE = 7;
|
||||
public static final int PRIMITIVE_VOID = 8;
|
||||
|
||||
private WasmGCClassFlags() {
|
||||
}
|
||||
}
|
|
@ -0,0 +1,538 @@
|
|||
/*
|
||||
* 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.classes;
|
||||
|
||||
import com.carrotsearch.hppc.ObjectIntHashMap;
|
||||
import com.carrotsearch.hppc.ObjectIntMap;
|
||||
import java.util.LinkedHashMap;
|
||||
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.initialization.WasmGCInitializerContributor;
|
||||
import org.teavm.backend.wasm.generate.gc.method.WasmGCFunctionProvider;
|
||||
import org.teavm.backend.wasm.generate.gc.strings.WasmGCStringPool;
|
||||
import org.teavm.backend.wasm.model.WasmArray;
|
||||
import org.teavm.backend.wasm.model.WasmFunction;
|
||||
import org.teavm.backend.wasm.model.WasmFunctionType;
|
||||
import org.teavm.backend.wasm.model.WasmGlobal;
|
||||
import org.teavm.backend.wasm.model.WasmLocal;
|
||||
import org.teavm.backend.wasm.model.WasmModule;
|
||||
import org.teavm.backend.wasm.model.WasmStorageType;
|
||||
import org.teavm.backend.wasm.model.WasmStructure;
|
||||
import org.teavm.backend.wasm.model.WasmType;
|
||||
import org.teavm.backend.wasm.model.expression.WasmCall;
|
||||
import org.teavm.backend.wasm.model.expression.WasmCast;
|
||||
import org.teavm.backend.wasm.model.expression.WasmExpression;
|
||||
import org.teavm.backend.wasm.model.expression.WasmFunctionReference;
|
||||
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;
|
||||
import org.teavm.backend.wasm.model.expression.WasmIntType;
|
||||
import org.teavm.backend.wasm.model.expression.WasmNullConstant;
|
||||
import org.teavm.backend.wasm.model.expression.WasmSetGlobal;
|
||||
import org.teavm.backend.wasm.model.expression.WasmStructNewDefault;
|
||||
import org.teavm.backend.wasm.model.expression.WasmStructSet;
|
||||
import org.teavm.model.ClassReaderSource;
|
||||
import org.teavm.model.ElementModifier;
|
||||
import org.teavm.model.FieldReference;
|
||||
import org.teavm.model.MethodDescriptor;
|
||||
import org.teavm.model.MethodReference;
|
||||
import org.teavm.model.ValueType;
|
||||
import org.teavm.model.analysis.ClassMetadataRequirements;
|
||||
import org.teavm.model.classes.TagRegistry;
|
||||
import org.teavm.model.classes.VirtualTable;
|
||||
import org.teavm.model.classes.VirtualTableProvider;
|
||||
import org.teavm.model.util.ReflectionUtil;
|
||||
|
||||
public class WasmGCClassGenerator implements WasmGCClassInfoProvider, WasmGCInitializerContributor {
|
||||
public static final int CLASS_FIELD_OFFSET = 0;
|
||||
|
||||
private final WasmModule module;
|
||||
private ClassReaderSource classSource;
|
||||
private WasmFunctionTypes functionTypes;
|
||||
private TagRegistry tagRegistry;
|
||||
private ClassMetadataRequirements metadataRequirements;
|
||||
private VirtualTableProvider virtualTables;
|
||||
private WasmGCFunctionProvider functionProvider;
|
||||
private Map<ValueType, WasmGCClassInfo> classInfoMap = new LinkedHashMap<>();
|
||||
private ObjectIntMap<FieldReference> fieldIndexes = new ObjectIntHashMap<>();
|
||||
private ObjectIntMap<MethodReference> methodIndexes = new ObjectIntHashMap<>();
|
||||
|
||||
public final WasmGCStringPool strings;
|
||||
public final WasmGCStandardClasses standardClasses;
|
||||
private final WasmGCTypeMapper typeMapper;
|
||||
private final NameProvider names;
|
||||
private WasmFunction initializer;
|
||||
private WasmFunction createPrimitiveClassFunction;
|
||||
private WasmFunction createArrayClassFunction;
|
||||
private final WasmGCSupertypeFunctionGenerator supertypeGenerator;
|
||||
|
||||
private int classTagOffset;
|
||||
private int classFlagsOffset;
|
||||
private int classNameOffset;
|
||||
private int classParentOffset;
|
||||
private int classArrayOffset;
|
||||
private int classArrayItemOffset;
|
||||
private int classSupertypeFunctionOffset;
|
||||
private int virtualTableFieldOffset;
|
||||
|
||||
public WasmGCClassGenerator(WasmModule module, ClassReaderSource classSource,
|
||||
WasmFunctionTypes functionTypes, TagRegistry tagRegistry,
|
||||
ClassMetadataRequirements metadataRequirements, VirtualTableProvider virtualTables,
|
||||
WasmGCFunctionProvider functionProvider, NameProvider names) {
|
||||
this.module = module;
|
||||
this.classSource = classSource;
|
||||
this.functionTypes = functionTypes;
|
||||
this.tagRegistry = tagRegistry;
|
||||
this.metadataRequirements = metadataRequirements;
|
||||
this.virtualTables = virtualTables;
|
||||
this.functionProvider = functionProvider;
|
||||
this.names = names;
|
||||
standardClasses = new WasmGCStandardClasses(this);
|
||||
strings = new WasmGCStringPool(standardClasses, module, functionProvider);
|
||||
supertypeGenerator = new WasmGCSupertypeFunctionGenerator(module, this, names, tagRegistry, functionTypes);
|
||||
typeMapper = new WasmGCTypeMapper(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void contributeToInitializerDefinitions(WasmFunction function) {
|
||||
for (var classInfo : classInfoMap.values()) {
|
||||
var newStruct = new WasmStructNewDefault(standardClasses.classClass().getStructure());
|
||||
function.getBody().add(new WasmSetGlobal(classInfo.pointer, newStruct));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void contributeToInitializer(WasmFunction function) {
|
||||
var classClass = standardClasses.classClass();
|
||||
for (var classInfo : classInfoMap.values()) {
|
||||
classInfo.initializer.accept(function.getBody());
|
||||
var supertypeFunction = supertypeGenerator.getIsSupertypeFunction(classInfo.getValueType());
|
||||
function.getBody().add(setClassField(classInfo, classSupertypeFunctionOffset,
|
||||
new WasmFunctionReference(supertypeFunction)));
|
||||
function.getBody().add(setClassField(classInfo, CLASS_FIELD_OFFSET,
|
||||
new WasmGetGlobal(classClass.pointer)));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public WasmGCClassInfo getClassInfo(ValueType type) {
|
||||
var classInfo = classInfoMap.get(type);
|
||||
if (classInfo == null) {
|
||||
classInfo = new WasmGCClassInfo(type);
|
||||
classInfoMap.put(type, classInfo);
|
||||
if (!(type instanceof ValueType.Primitive)) {
|
||||
var name = type instanceof ValueType.Object
|
||||
? ((ValueType.Object) type).getClassName()
|
||||
: null;
|
||||
classInfo.structure = new WasmStructure(name);
|
||||
classInfo.structure.getFields().add(standardClasses.classClass().getType().asStorage());
|
||||
fillFields(classInfo.structure.getFields(), type);
|
||||
}
|
||||
var pointerName = names.forClassInstance(type);
|
||||
var classStructure = type instanceof ValueType.Object
|
||||
? initRegularClassStructure(((ValueType.Object) type).getClassName())
|
||||
: standardClasses.classClass().getStructure();
|
||||
classInfo.virtualTableStructure = classStructure;
|
||||
classInfo.pointer = new WasmGlobal(pointerName, classStructure.getReference(),
|
||||
new WasmNullConstant(classStructure.getReference()));
|
||||
module.globals.add(classInfo.pointer);
|
||||
if (type instanceof ValueType.Primitive) {
|
||||
initPrimitiveClass(classInfo, (ValueType.Primitive) type);
|
||||
} else if (type instanceof ValueType.Void) {
|
||||
initVoidClass(classInfo);
|
||||
} else if (type instanceof ValueType.Array) {
|
||||
initArrayClass(classInfo, (ValueType.Array) type);
|
||||
} else if (type instanceof ValueType.Object) {
|
||||
initRegularClass(classInfo, classStructure, ((ValueType.Object) type).getClassName());
|
||||
}
|
||||
}
|
||||
return classInfo;
|
||||
}
|
||||
|
||||
public int getClassTagOffset() {
|
||||
return classTagOffset;
|
||||
}
|
||||
|
||||
public int getClassArrayItemOffset() {
|
||||
return classArrayItemOffset;
|
||||
}
|
||||
|
||||
private void initPrimitiveClass(WasmGCClassInfo classInfo, ValueType.Primitive type) {
|
||||
classInfo.initializer = target -> {
|
||||
int kind;
|
||||
switch (type.getKind()) {
|
||||
case BOOLEAN:
|
||||
kind = WasmGCClassFlags.PRIMITIVE_BOOLEAN;
|
||||
break;
|
||||
case BYTE:
|
||||
kind = WasmGCClassFlags.PRIMITIVE_BYTE;
|
||||
break;
|
||||
case SHORT:
|
||||
kind = WasmGCClassFlags.PRIMITIVE_SHORT;
|
||||
break;
|
||||
case CHARACTER:
|
||||
kind = WasmGCClassFlags.PRIMITIVE_CHAR;
|
||||
break;
|
||||
case INTEGER:
|
||||
kind = WasmGCClassFlags.PRIMITIVE_INT;
|
||||
break;
|
||||
case LONG:
|
||||
kind = WasmGCClassFlags.PRIMITIVE_LONG;
|
||||
break;
|
||||
case FLOAT:
|
||||
kind = WasmGCClassFlags.PRIMITIVE_FLOAT;
|
||||
break;
|
||||
case DOUBLE:
|
||||
kind = WasmGCClassFlags.PRIMITIVE_DOUBLE;
|
||||
break;
|
||||
default:
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
target.add(fillPrimitiveClass(
|
||||
classInfo.pointer,
|
||||
ReflectionUtil.typeName(type.getKind()),
|
||||
kind
|
||||
));
|
||||
};
|
||||
}
|
||||
|
||||
private void initVoidClass(WasmGCClassInfo classInfo) {
|
||||
classInfo.initializer = target -> {
|
||||
target.add(fillPrimitiveClass(
|
||||
classInfo.pointer,
|
||||
"void",
|
||||
WasmGCClassFlags.PRIMITIVE_VOID
|
||||
));
|
||||
};
|
||||
}
|
||||
|
||||
private void initRegularClass(WasmGCClassInfo classInfo, WasmStructure classStructure, String name) {
|
||||
classInfo.initializer = target -> {
|
||||
var ranges = tagRegistry.getRanges(name);
|
||||
int tag = ranges.stream().mapToInt(range -> range.lower).min().orElse(0);
|
||||
target.add(setClassField(classInfo, classTagOffset, new WasmInt32Constant(tag)));
|
||||
var metadataReg = metadataRequirements.getInfo(name);
|
||||
if (metadataReg.name()) {
|
||||
var namePtr = strings.getStringConstant(name).global;
|
||||
target.add(setClassField(classInfo, classNameOffset, new WasmGetGlobal(namePtr)));
|
||||
}
|
||||
var cls = classSource.get(name);
|
||||
if (cls != null) {
|
||||
if (metadataReg.simpleName() && cls.getSimpleName() != null) {
|
||||
var namePtr = strings.getStringConstant(cls.getSimpleName()).global;
|
||||
target.add(setClassField(classInfo, classNameOffset, new WasmGetGlobal(namePtr)));
|
||||
}
|
||||
if (cls.getParent() != null) {
|
||||
var parent = getClassInfo(cls.getParent());
|
||||
target.add(setClassField(classInfo, classParentOffset, new WasmGetGlobal(parent.pointer)));
|
||||
}
|
||||
}
|
||||
var virtualTable = virtualTables.lookup(name);
|
||||
fillVirtualTableMethods(target, classStructure, classInfo.pointer, virtualTable, virtualTableFieldOffset,
|
||||
name);
|
||||
};
|
||||
}
|
||||
|
||||
private int fillVirtualTableMethods(List<WasmExpression> target, WasmStructure structure, WasmGlobal global,
|
||||
VirtualTable virtualTable, int index, String origin) {
|
||||
if (virtualTable.getParent() != null) {
|
||||
index = fillVirtualTableMethods(target, structure, global, virtualTable.getParent(), index, origin);
|
||||
}
|
||||
for (var method : virtualTable.getMethods()) {
|
||||
var entry = virtualTable.getEntry(method);
|
||||
if (entry != null && entry.getImplementor() != null) {
|
||||
var function = functionProvider.getMemberFunction(entry.getImplementor());
|
||||
if (!origin.equals(entry.getImplementor().getClassName())) {
|
||||
var functionType = getFunctionType(virtualTable.getClassName(), method);
|
||||
var wrapperFunction = new WasmFunction(functionType);
|
||||
module.functions.add(wrapperFunction);
|
||||
var call = new WasmCall(function);
|
||||
var instanceParam = new WasmLocal(getClassInfo(virtualTable.getClassName()).getType());
|
||||
wrapperFunction.getLocalVariables().add(instanceParam);
|
||||
var castTarget = getClassInfo(entry.getImplementor().getClassName()).getType();
|
||||
call.getArguments().add(new WasmCast(new WasmGetLocal(instanceParam), castTarget));
|
||||
var params = new WasmLocal[method.parameterCount()];
|
||||
for (var i = 0; i < method.parameterCount(); ++i) {
|
||||
params[i] = new WasmLocal(typeMapper.mapType(method.parameterType(i)).asUnpackedType());
|
||||
call.getArguments().add(new WasmGetLocal(params[i]));
|
||||
}
|
||||
wrapperFunction.getLocalVariables().addAll(List.of(params));
|
||||
}
|
||||
var ref = new WasmFunctionReference(function);
|
||||
target.add(new WasmStructSet(structure, new WasmGetGlobal(global), index, ref));
|
||||
}
|
||||
}
|
||||
return index;
|
||||
}
|
||||
|
||||
private WasmStructure initRegularClassStructure(String className) {
|
||||
var virtualTable = virtualTables.lookup(className);
|
||||
var structure = new WasmStructure(names.forClassClass(className));
|
||||
module.types.add(structure);
|
||||
addVirtualTableFields(structure, virtualTable);
|
||||
fillClassFields(structure.getFields(), "java.lang.Class");
|
||||
return structure;
|
||||
}
|
||||
|
||||
private void addVirtualTableFields(WasmStructure structure, VirtualTable virtualTable) {
|
||||
if (virtualTable.getParent() != null) {
|
||||
addVirtualTableFields(structure, virtualTable.getParent());
|
||||
}
|
||||
for (var methodDesc : virtualTable.getMethods()) {
|
||||
var functionType = getFunctionType(virtualTable.getClassName(), methodDesc);
|
||||
var methodRef = new MethodReference(virtualTable.getClassName(), methodDesc);
|
||||
methodIndexes.put(methodRef, structure.getFields().size());
|
||||
structure.getFields().add(functionType.getReference().asStorage());
|
||||
}
|
||||
}
|
||||
|
||||
private WasmFunctionType getFunctionType(String className, MethodDescriptor methodDesc) {
|
||||
var returnType = typeMapper.mapType(methodDesc.getResultType()).asUnpackedType();
|
||||
var javaParamTypes = methodDesc.getParameterTypes();
|
||||
var paramTypes = new WasmType[javaParamTypes.length + 1];
|
||||
paramTypes[0] = getClassInfo(className).getType();
|
||||
for (var i = 0; i < javaParamTypes.length; ++i) {
|
||||
paramTypes[i + 1] = typeMapper.mapType(javaParamTypes[i]).asUnpackedType();
|
||||
}
|
||||
return functionTypes.of(returnType, paramTypes);
|
||||
}
|
||||
|
||||
private void initArrayClass(WasmGCClassInfo classInfo, ValueType.Array type) {
|
||||
classInfo.initializer = target -> {
|
||||
var itemTypeInfo = getClassInfo(type.getItemType());
|
||||
target.add(new WasmCall(
|
||||
getCreateArrayClassFunction(),
|
||||
new WasmGetGlobal(classInfo.pointer),
|
||||
new WasmGetGlobal(itemTypeInfo.pointer)
|
||||
));
|
||||
};
|
||||
}
|
||||
|
||||
private WasmExpression fillPrimitiveClass(WasmGlobal global, String name, int kind) {
|
||||
return new WasmCall(
|
||||
getCreatePrimitiveClassFunction(),
|
||||
new WasmGetGlobal(global),
|
||||
new WasmGetGlobal(strings.getStringConstant(name).global),
|
||||
new WasmInt32Constant(kind)
|
||||
);
|
||||
}
|
||||
|
||||
public int getFieldIndex(FieldReference fieldRef) {
|
||||
var result = fieldIndexes.getOrDefault(fieldRef, -1);
|
||||
if (result < 0) {
|
||||
throw new IllegalStateException("Can't get offset of field " + fieldRef);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public int getVirtualMethodIndex(MethodReference methodRef) {
|
||||
var result = methodIndexes.getOrDefault(methodRef, -1);
|
||||
if (result < 0) {
|
||||
throw new IllegalStateException("Can't get offset of method " + methodRef);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private void fillFields(List<WasmStorageType> fields, ValueType type) {
|
||||
fields.add(standardClasses.classClass().getType().asStorage());
|
||||
if (type instanceof ValueType.Object) {
|
||||
fillClassFields(fields, ((ValueType.Object) type).getClassName());
|
||||
} else if (type instanceof ValueType.Array) {
|
||||
fillArrayField(fields, ((ValueType.Array) type).getItemType());
|
||||
}
|
||||
}
|
||||
|
||||
private void fillClassFields(List<WasmStorageType> fields, String className) {
|
||||
var classReader = classSource.get(className);
|
||||
if (classReader.hasModifier(ElementModifier.INTERFACE)) {
|
||||
fillSimpleClassFields(fields, "java.lang.Object");
|
||||
} else {
|
||||
fillSimpleClassFields(fields, className);
|
||||
}
|
||||
}
|
||||
|
||||
private void fillSimpleClassFields(List<WasmStorageType> fields, String className) {
|
||||
var classReader = classSource.get(className);
|
||||
if (classReader.getParent() != null) {
|
||||
fillClassFields(fields, classReader.getParent());
|
||||
} else {
|
||||
fields.add(standardClasses.classClass().getType().asStorage());
|
||||
}
|
||||
for (var field : classReader.getFields()) {
|
||||
if (field.hasModifier(ElementModifier.STATIC)) {
|
||||
continue;
|
||||
}
|
||||
fieldIndexes.putIfAbsent(field.getReference(), fields.size());
|
||||
fields.add(typeMapper.mapType(field.getType()));
|
||||
}
|
||||
if (className.equals("java.lang.Class")) {
|
||||
classFlagsOffset = fields.size();
|
||||
fields.add(WasmType.INT32.asStorage());
|
||||
classTagOffset = fields.size();
|
||||
fields.add(WasmType.INT32.asStorage());
|
||||
classParentOffset = fields.size();
|
||||
fields.add(standardClasses.classClass().getType().asStorage());
|
||||
classArrayItemOffset = fields.size();
|
||||
fields.add(standardClasses.classClass().getType().asStorage());
|
||||
classArrayOffset = fields.size();
|
||||
fields.add(standardClasses.classClass().getType().asStorage());
|
||||
classSupertypeFunctionOffset = fields.size();
|
||||
fields.add(supertypeGenerator.getFunctionType().getReference().asStorage());
|
||||
virtualTableFieldOffset = fields.size();
|
||||
classNameOffset = fieldIndexes.get(new FieldReference(className, "name"));
|
||||
}
|
||||
}
|
||||
|
||||
private void fillArrayField(List<WasmStorageType> fields, ValueType elementType) {
|
||||
var wasmArray = new WasmArray(null, () -> typeMapper.mapType(elementType));
|
||||
module.types.add(wasmArray);
|
||||
fields.add(wasmArray.getReference().asStorage());
|
||||
}
|
||||
|
||||
private WasmFunction getCreatePrimitiveClassFunction() {
|
||||
if (createPrimitiveClassFunction == null) {
|
||||
createPrimitiveClassFunction = createCreatePrimitiveClassFunction();
|
||||
}
|
||||
return createPrimitiveClassFunction;
|
||||
}
|
||||
|
||||
private WasmFunction createCreatePrimitiveClassFunction() {
|
||||
var functionType = functionTypes.of(
|
||||
null,
|
||||
standardClasses.classClass().getType(),
|
||||
standardClasses.stringClass().getType(),
|
||||
WasmType.INT32
|
||||
);
|
||||
var function = new WasmFunction(functionType);
|
||||
function.setName("_teavm_fill_primitive_class_");
|
||||
|
||||
var targetVar = new WasmLocal(standardClasses.classClass().getType(), "target");
|
||||
var nameVar = new WasmLocal(standardClasses.objectClass().getType(), "name");
|
||||
var kindVar = new WasmLocal(WasmType.INT32, "kind");
|
||||
function.getLocalVariables().add(targetVar);
|
||||
function.getLocalVariables().add(nameVar);
|
||||
function.getLocalVariables().add(kindVar);
|
||||
|
||||
var flagsExpr = new WasmIntBinary(
|
||||
WasmIntType.INT32,
|
||||
WasmIntBinaryOperation.SHL,
|
||||
new WasmGetLocal(kindVar),
|
||||
new WasmInt32Constant(WasmGCClassFlags.PRIMITIVE_KIND_SHIFT)
|
||||
);
|
||||
flagsExpr = new WasmIntBinary(
|
||||
WasmIntType.INT32,
|
||||
WasmIntBinaryOperation.OR,
|
||||
flagsExpr,
|
||||
new WasmInt32Constant(WasmGCClassFlags.FINAL | WasmGCClassFlags.PRIMITIVE)
|
||||
);
|
||||
function.getBody().add(new WasmStructSet(
|
||||
standardClasses.classClass().getStructure(),
|
||||
new WasmGetLocal(targetVar),
|
||||
classFlagsOffset,
|
||||
flagsExpr
|
||||
));
|
||||
function.getBody().add(new WasmStructSet(
|
||||
standardClasses.classClass().getStructure(),
|
||||
new WasmGetLocal(targetVar),
|
||||
classNameOffset,
|
||||
new WasmGetLocal(nameVar)
|
||||
));
|
||||
function.getBody().add(new WasmStructSet(
|
||||
standardClasses.classClass().getStructure(),
|
||||
new WasmGetLocal(targetVar),
|
||||
classTagOffset,
|
||||
new WasmInt32Constant(Integer.MAX_VALUE)
|
||||
));
|
||||
return function;
|
||||
}
|
||||
|
||||
private WasmFunction getCreateArrayClassFunction() {
|
||||
if (createArrayClassFunction == null) {
|
||||
createArrayClassFunction = createCreateArrayClassFunction();
|
||||
}
|
||||
return createCreateArrayClassFunction();
|
||||
}
|
||||
|
||||
private WasmFunction createCreateArrayClassFunction() {
|
||||
var functionType = functionTypes.of(
|
||||
null,
|
||||
standardClasses.classClass().getType(),
|
||||
standardClasses.classClass().getType()
|
||||
);
|
||||
var function = new WasmFunction(functionType);
|
||||
function.setName("_teavm_fill_array_class_");
|
||||
|
||||
var targetVar = new WasmLocal(standardClasses.classClass().getType(), "target");
|
||||
var itemVar = new WasmLocal(standardClasses.classClass().getType(), "item");
|
||||
function.getLocalVariables().add(targetVar);
|
||||
function.getLocalVariables().add(itemVar);
|
||||
|
||||
function.getBody().add(new WasmStructSet(
|
||||
standardClasses.classClass().getStructure(),
|
||||
new WasmGetLocal(targetVar),
|
||||
classFlagsOffset,
|
||||
new WasmInt32Constant(WasmGCClassFlags.FINAL)
|
||||
));
|
||||
function.getBody().add(new WasmStructSet(
|
||||
standardClasses.classClass().getStructure(),
|
||||
new WasmGetLocal(targetVar),
|
||||
classArrayItemOffset,
|
||||
new WasmGetLocal(itemVar)
|
||||
));
|
||||
function.getBody().add(new WasmStructSet(
|
||||
standardClasses.classClass().getStructure(),
|
||||
new WasmGetLocal(itemVar),
|
||||
classArrayOffset,
|
||||
new WasmGetLocal(targetVar)
|
||||
));
|
||||
function.getBody().add(new WasmStructSet(
|
||||
standardClasses.classClass().getStructure(),
|
||||
new WasmGetLocal(targetVar),
|
||||
classTagOffset,
|
||||
new WasmInt32Constant(0)
|
||||
));
|
||||
function.getBody().add(new WasmStructSet(
|
||||
standardClasses.classClass().getStructure(),
|
||||
new WasmGetLocal(targetVar),
|
||||
classParentOffset,
|
||||
new WasmGetGlobal(standardClasses.classClass().pointer)
|
||||
));
|
||||
return function;
|
||||
}
|
||||
|
||||
|
||||
private WasmFunction getInitializer() {
|
||||
if (initializer == null) {
|
||||
initializer = new WasmFunction(functionTypes.of(null));
|
||||
initializer.setName("_teavm_init_classes_");
|
||||
module.functions.add(initializer);
|
||||
}
|
||||
return initializer;
|
||||
}
|
||||
|
||||
private WasmExpression setClassField(WasmGCClassInfo classInfo, int fieldIndex, WasmExpression value) {
|
||||
return new WasmStructSet(
|
||||
standardClasses.classClass().getStructure(),
|
||||
new WasmGetGlobal(classInfo.pointer),
|
||||
fieldIndex,
|
||||
value
|
||||
);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,56 @@
|
|||
/*
|
||||
* 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.classes;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.function.Consumer;
|
||||
import org.teavm.backend.wasm.model.WasmGlobal;
|
||||
import org.teavm.backend.wasm.model.WasmStructure;
|
||||
import org.teavm.backend.wasm.model.WasmType;
|
||||
import org.teavm.backend.wasm.model.expression.WasmExpression;
|
||||
import org.teavm.model.ValueType;
|
||||
|
||||
public class WasmGCClassInfo {
|
||||
private ValueType valueType;
|
||||
WasmStructure structure;
|
||||
WasmStructure virtualTableStructure;
|
||||
WasmGlobal pointer;
|
||||
Consumer<List<WasmExpression>> initializer;
|
||||
|
||||
WasmGCClassInfo(ValueType valueType) {
|
||||
this.valueType = valueType;
|
||||
}
|
||||
|
||||
public ValueType getValueType() {
|
||||
return valueType;
|
||||
}
|
||||
|
||||
public WasmStructure getStructure() {
|
||||
return structure;
|
||||
}
|
||||
|
||||
public WasmStructure getVirtualTableStructure() {
|
||||
return virtualTableStructure;
|
||||
}
|
||||
|
||||
public WasmType.CompositeReference getType() {
|
||||
return getStructure().getReference();
|
||||
}
|
||||
|
||||
public WasmGlobal getPointer() {
|
||||
return pointer;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,26 @@
|
|||
/*
|
||||
* 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.classes;
|
||||
|
||||
import org.teavm.model.ValueType;
|
||||
|
||||
public interface WasmGCClassInfoProvider {
|
||||
WasmGCClassInfo getClassInfo(ValueType type);
|
||||
|
||||
default WasmGCClassInfo getClassInfo(String name) {
|
||||
return getClassInfo(ValueType.object(name));
|
||||
}
|
||||
}
|
|
@ -0,0 +1,48 @@
|
|||
/*
|
||||
* 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.classes;
|
||||
|
||||
public class WasmGCStandardClasses {
|
||||
private WasmGCClassInfoProvider classGenerator;
|
||||
private WasmGCClassInfo classClassInfo;
|
||||
private WasmGCClassInfo stringClassInfo;
|
||||
private WasmGCClassInfo objectClassInfo;
|
||||
|
||||
public WasmGCStandardClasses(WasmGCClassInfoProvider classGenerator) {
|
||||
this.classGenerator = classGenerator;
|
||||
}
|
||||
|
||||
public WasmGCClassInfo classClass() {
|
||||
if (classClassInfo == null) {
|
||||
classClassInfo = classGenerator.getClassInfo("java.lang.Class");
|
||||
}
|
||||
return classClassInfo;
|
||||
}
|
||||
|
||||
public WasmGCClassInfo stringClass() {
|
||||
if (stringClassInfo == null) {
|
||||
stringClassInfo = classGenerator.getClassInfo("java.lang.Class");
|
||||
}
|
||||
return stringClassInfo;
|
||||
}
|
||||
|
||||
public WasmGCClassInfo objectClass() {
|
||||
if (objectClassInfo == null) {
|
||||
objectClassInfo = classGenerator.getClassInfo("java.lang.Object");
|
||||
}
|
||||
return objectClassInfo;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,186 @@
|
|||
/*
|
||||
* 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.classes;
|
||||
|
||||
import com.carrotsearch.hppc.ObjectIntHashMap;
|
||||
import com.carrotsearch.hppc.ObjectIntMap;
|
||||
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.model.WasmFunction;
|
||||
import org.teavm.backend.wasm.model.WasmFunctionType;
|
||||
import org.teavm.backend.wasm.model.WasmLocal;
|
||||
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.WasmConditional;
|
||||
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;
|
||||
import org.teavm.backend.wasm.model.expression.WasmIntType;
|
||||
import org.teavm.backend.wasm.model.expression.WasmIntUnary;
|
||||
import org.teavm.backend.wasm.model.expression.WasmIntUnaryOperation;
|
||||
import org.teavm.backend.wasm.model.expression.WasmReturn;
|
||||
import org.teavm.backend.wasm.model.expression.WasmSetLocal;
|
||||
import org.teavm.backend.wasm.model.expression.WasmStructGet;
|
||||
import org.teavm.model.ValueType;
|
||||
import org.teavm.model.classes.TagRegistry;
|
||||
|
||||
public class WasmGCSupertypeFunctionGenerator {
|
||||
private ObjectIntMap<ValueType> tableIndexes = new ObjectIntHashMap<>();
|
||||
private Map<ValueType, WasmFunction> functions = new HashMap<>();
|
||||
private WasmModule module;
|
||||
private WasmGCClassGenerator classGenerator;
|
||||
private NameProvider nameProvider;
|
||||
private TagRegistry tagRegistry;
|
||||
private WasmFunctionTypes functionTypes;
|
||||
private WasmFunctionType functionType;
|
||||
|
||||
WasmGCSupertypeFunctionGenerator(
|
||||
WasmModule module,
|
||||
WasmGCClassGenerator classGenerator,
|
||||
NameProvider nameProvider,
|
||||
TagRegistry tagRegistry,
|
||||
WasmFunctionTypes functionTypes
|
||||
) {
|
||||
this.module = module;
|
||||
this.classGenerator = classGenerator;
|
||||
this.nameProvider = nameProvider;
|
||||
this.tagRegistry = tagRegistry;
|
||||
this.functionTypes = functionTypes;
|
||||
}
|
||||
|
||||
public WasmFunction getIsSupertypeFunction(ValueType type) {
|
||||
var result = functions.get(type);
|
||||
if (result == null) {
|
||||
result = generateIsSupertypeFunction(type);
|
||||
functions.put(type, result);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private WasmFunction generateIsSupertypeFunction(ValueType type) {
|
||||
var function = new WasmFunction(getFunctionType());
|
||||
function.setName(nameProvider.forSupertypeFunction(type));
|
||||
var subtypeVar = new WasmLocal(WasmType.INT32, "subtype");
|
||||
function.add(subtypeVar);
|
||||
module.functions.add(function);
|
||||
|
||||
if (type instanceof ValueType.Object) {
|
||||
var className = ((ValueType.Object) type).getClassName();
|
||||
generateIsClass(subtypeVar, className, function.getBody());
|
||||
} else if (type instanceof ValueType.Array) {
|
||||
ValueType itemType = ((ValueType.Array) type).getItemType();
|
||||
generateIsArray(subtypeVar, itemType, function.getBody());
|
||||
} else {
|
||||
var expected = classGenerator.getClassInfo(type).pointer;
|
||||
var condition = new WasmIntBinary(WasmIntType.INT32, WasmIntBinaryOperation.EQ,
|
||||
new WasmGetLocal(subtypeVar), new WasmGetGlobal(expected));
|
||||
function.getBody().add(new WasmReturn(condition));
|
||||
}
|
||||
|
||||
return function;
|
||||
}
|
||||
|
||||
private void generateIsClass(WasmLocal subtypeVar, String className, List<WasmExpression> body) {
|
||||
var ranges = tagRegistry.getRanges(className);
|
||||
if (ranges.isEmpty()) {
|
||||
body.add(new WasmReturn(new WasmInt32Constant(0)));
|
||||
return;
|
||||
}
|
||||
|
||||
int tagOffset = classGenerator.getClassTagOffset();
|
||||
|
||||
var tagExpression = getClassField(new WasmGetLocal(subtypeVar), tagOffset);
|
||||
body.add(new WasmSetLocal(subtypeVar, tagExpression));
|
||||
|
||||
ranges.sort(Comparator.comparingInt(range -> range.lower));
|
||||
|
||||
int lower = ranges.get(0).lower;
|
||||
int upper = ranges.get(ranges.size() - 1).upper;
|
||||
|
||||
var lowerCondition = new WasmIntBinary(WasmIntType.INT32, WasmIntBinaryOperation.LT_SIGNED,
|
||||
new WasmGetLocal(subtypeVar), new WasmInt32Constant(lower));
|
||||
var testLower = new WasmConditional(lowerCondition);
|
||||
testLower.getThenBlock().getBody().add(new WasmReturn(new WasmInt32Constant(0)));
|
||||
body.add(testLower);
|
||||
|
||||
var upperCondition = new WasmIntBinary(WasmIntType.INT32, WasmIntBinaryOperation.GE_SIGNED,
|
||||
new WasmGetLocal(subtypeVar), new WasmInt32Constant(upper));
|
||||
var testUpper = new WasmConditional(upperCondition);
|
||||
testUpper.getThenBlock().getBody().add(new WasmReturn(new WasmInt32Constant(0)));
|
||||
body.add(testUpper);
|
||||
|
||||
for (int i = 1; i < ranges.size(); ++i) {
|
||||
int lowerHole = ranges.get(i - 1).upper;
|
||||
int upperHole = ranges.get(i).lower;
|
||||
|
||||
lowerCondition = new WasmIntBinary(WasmIntType.INT32, WasmIntBinaryOperation.GE_SIGNED,
|
||||
new WasmGetLocal(subtypeVar), new WasmInt32Constant(lowerHole));
|
||||
testLower = new WasmConditional(lowerCondition);
|
||||
body.add(testLower);
|
||||
|
||||
upperCondition = new WasmIntBinary(WasmIntType.INT32, WasmIntBinaryOperation.LT_SIGNED,
|
||||
new WasmGetLocal(subtypeVar), new WasmInt32Constant(upperHole));
|
||||
testUpper = new WasmConditional(upperCondition);
|
||||
testUpper.getThenBlock().getBody().add(new WasmReturn(new WasmInt32Constant(0)));
|
||||
|
||||
testLower.getThenBlock().getBody().add(testUpper);
|
||||
}
|
||||
|
||||
body.add(new WasmReturn(new WasmInt32Constant(1)));
|
||||
}
|
||||
|
||||
private void generateIsArray(WasmLocal subtypeVar, ValueType itemType, List<WasmExpression> body) {
|
||||
int itemOffset = classGenerator.getClassArrayItemOffset();
|
||||
|
||||
var itemExpression = getClassField(new WasmGetLocal(subtypeVar), itemOffset);
|
||||
body.add(new WasmSetLocal(subtypeVar, itemExpression));
|
||||
|
||||
var itemTest = new WasmConditional(new WasmIntUnary(WasmIntType.INT32, WasmIntUnaryOperation.EQZ,
|
||||
new WasmGetLocal(subtypeVar)));
|
||||
itemTest.setType(WasmType.INT32);
|
||||
itemTest.getThenBlock().getBody().add(new WasmInt32Constant(0));
|
||||
|
||||
var delegateToItem = new WasmCall(getIsSupertypeFunction(itemType));
|
||||
delegateToItem.getArguments().add(new WasmGetLocal(subtypeVar));
|
||||
itemTest.getElseBlock().getBody().add(delegateToItem);
|
||||
|
||||
body.add(new WasmReturn(itemTest));
|
||||
}
|
||||
|
||||
public WasmFunctionType getFunctionType() {
|
||||
if (functionType == null) {
|
||||
functionType = functionTypes.of(WasmType.INT32, classGenerator.standardClasses.classClass().getType());
|
||||
}
|
||||
return functionType;
|
||||
}
|
||||
|
||||
|
||||
private WasmExpression getClassField(WasmExpression instance, int fieldIndex) {
|
||||
return new WasmStructGet(
|
||||
classGenerator.standardClasses.classClass().getStructure(),
|
||||
instance,
|
||||
fieldIndex
|
||||
);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,54 @@
|
|||
/*
|
||||
* 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.classes;
|
||||
|
||||
import org.teavm.backend.wasm.model.WasmPackedType;
|
||||
import org.teavm.backend.wasm.model.WasmStorageType;
|
||||
import org.teavm.backend.wasm.model.WasmType;
|
||||
import org.teavm.model.ValueType;
|
||||
|
||||
public class WasmGCTypeMapper {
|
||||
private WasmGCClassInfoProvider classInfoProvider;
|
||||
|
||||
WasmGCTypeMapper(WasmGCClassInfoProvider classInfoProvider) {
|
||||
this.classInfoProvider = classInfoProvider;
|
||||
}
|
||||
|
||||
public WasmStorageType mapType(ValueType type) {
|
||||
if (type instanceof ValueType.Primitive) {
|
||||
switch (((ValueType.Primitive) type).getKind()) {
|
||||
case BYTE:
|
||||
case BOOLEAN:
|
||||
return WasmStorageType.packed(WasmPackedType.INT8);
|
||||
case SHORT:
|
||||
case CHARACTER:
|
||||
return WasmStorageType.packed(WasmPackedType.INT8);
|
||||
case INTEGER:
|
||||
return WasmType.INT32.asStorage();
|
||||
case LONG:
|
||||
return WasmType.INT64.asStorage();
|
||||
case FLOAT:
|
||||
return WasmType.FLOAT32.asStorage();
|
||||
case DOUBLE:
|
||||
return WasmType.FLOAT64.asStorage();
|
||||
default:
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
} else {
|
||||
return classInfoProvider.getClassInfo(type).getType().asStorage();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,24 @@
|
|||
/*
|
||||
* 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.initialization;
|
||||
|
||||
import org.teavm.backend.wasm.model.WasmFunction;
|
||||
|
||||
public interface WasmGCInitializerContributor {
|
||||
void contributeToInitializerDefinitions(WasmFunction function);
|
||||
|
||||
void contributeToInitializer(WasmFunction function);
|
||||
}
|
|
@ -0,0 +1,25 @@
|
|||
/*
|
||||
* 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.method;
|
||||
|
||||
import org.teavm.backend.wasm.model.WasmFunction;
|
||||
import org.teavm.model.MethodReference;
|
||||
|
||||
public interface WasmGCFunctionProvider {
|
||||
WasmFunction getMemberFunction(MethodReference methodRef);
|
||||
|
||||
WasmFunction getStaticFunction(MethodReference methodRef);
|
||||
}
|
|
@ -0,0 +1,28 @@
|
|||
/*
|
||||
* 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.strings;
|
||||
|
||||
import org.teavm.backend.wasm.model.WasmGlobal;
|
||||
|
||||
public class WasmGCStringConstant {
|
||||
public final int index;
|
||||
public final WasmGlobal global;
|
||||
|
||||
public WasmGCStringConstant(int index, WasmGlobal global) {
|
||||
this.index = index;
|
||||
this.global = global;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,120 @@
|
|||
/*
|
||||
* 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.strings;
|
||||
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
import org.teavm.backend.wasm.generate.gc.classes.WasmGCStandardClasses;
|
||||
import org.teavm.backend.wasm.generate.gc.initialization.WasmGCInitializerContributor;
|
||||
import org.teavm.backend.wasm.generate.gc.method.WasmGCFunctionProvider;
|
||||
import org.teavm.backend.wasm.model.WasmFunction;
|
||||
import org.teavm.backend.wasm.model.WasmGlobal;
|
||||
import org.teavm.backend.wasm.model.WasmModule;
|
||||
import org.teavm.backend.wasm.model.expression.WasmExpression;
|
||||
import org.teavm.backend.wasm.model.expression.WasmSetGlobal;
|
||||
import org.teavm.backend.wasm.model.expression.WasmStructNewDefault;
|
||||
import org.teavm.backend.wasm.render.WasmBinaryWriter;
|
||||
import org.teavm.model.MethodReference;
|
||||
|
||||
public class WasmGCStringPool implements WasmGCStringProvider, WasmGCInitializerContributor {
|
||||
private WasmGCStandardClasses standardClasses;
|
||||
private WasmModule module;
|
||||
private WasmBinaryWriter binaryWriter = new WasmBinaryWriter();
|
||||
private Map<String, WasmGCStringConstant> stringMap = new LinkedHashMap<>();
|
||||
private WasmGCFunctionProvider functionProvider;
|
||||
|
||||
public WasmGCStringPool(WasmGCStandardClasses standardClasses, WasmModule module,
|
||||
WasmGCFunctionProvider functionProvider) {
|
||||
this.standardClasses = standardClasses;
|
||||
this.module = module;
|
||||
this.functionProvider = functionProvider;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void contributeToInitializerDefinitions(WasmFunction function) {
|
||||
for (var str : stringMap.values()) {
|
||||
var newStruct = new WasmStructNewDefault(standardClasses.stringClass().getStructure());
|
||||
function.getBody().add(new WasmSetGlobal(str.global, newStruct));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void contributeToInitializer(WasmFunction function) {
|
||||
var nextCharArrayFunction = functionProvider.getStaticFunction(new MethodReference(WasmGCStringPool.class,
|
||||
"nextCharArray", char[].class));
|
||||
}
|
||||
|
||||
@Override
|
||||
public WasmGCStringConstant getStringConstant(String string) {
|
||||
return stringMap.computeIfAbsent(string, s -> {
|
||||
binaryWriter.writeInt32(string.length());
|
||||
binaryWriter.writeBytes(string.getBytes(StandardCharsets.UTF_8));
|
||||
var globalName = "_teavm_java_string_" + stringMap.size();
|
||||
var globalType = standardClasses.stringClass().getType();
|
||||
var global = new WasmGlobal(globalName, globalType, WasmExpression.defaultValueOfType(globalType));
|
||||
module.globals.add(global);
|
||||
return new WasmGCStringConstant(stringMap.size(), global);
|
||||
});
|
||||
}
|
||||
|
||||
static char[] nextCharArray() {
|
||||
var length = nextLEB();
|
||||
var result = new char[length];
|
||||
var pos = 0;
|
||||
while (pos < length) {
|
||||
var b = nextByte();
|
||||
if ((b & 0x80) == 0) {
|
||||
result[pos++] = (char) b;
|
||||
} else if ((b & 0xE0) == 0xC0) {
|
||||
var b2 = nextByte();
|
||||
result[pos++] = (char) (((b & 0x1F) << 6) | (b2 & 0x3F));
|
||||
} else if ((b & 0xF0) == 0xE0) {
|
||||
var b2 = nextByte();
|
||||
var b3 = nextByte();
|
||||
var c = (char) (((b & 0x0F) << 12) | ((b2 & 0x3f) << 6) | (b3 & 0x3F));
|
||||
result[pos++] = c;
|
||||
} else if ((b & 0xF8) == 0xF0) {
|
||||
var b2 = nextByte();
|
||||
var b3 = nextByte();
|
||||
var b4 = nextByte();
|
||||
var code = ((b & 0x07) << 18) | ((b2 & 0x3f) << 12) | ((b3 & 0x3F) << 6) | (b4 & 0x3F);
|
||||
result[pos++] = Character.highSurrogate(code);
|
||||
result[pos++] = Character.lowSurrogate(code);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private static int nextLEB() {
|
||||
var shift = 0;
|
||||
var result = 0;
|
||||
while (true) {
|
||||
var b = nextByte();
|
||||
var digit = b & 0x7F;
|
||||
result |= digit << shift;
|
||||
if ((b & 0x80) == 0) {
|
||||
break;
|
||||
}
|
||||
shift += 7;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private static native byte nextByte();
|
||||
|
||||
private static native void error();
|
||||
}
|
|
@ -0,0 +1,20 @@
|
|||
/*
|
||||
* 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.strings;
|
||||
|
||||
public interface WasmGCStringProvider {
|
||||
WasmGCStringConstant getStringConstant(String string);
|
||||
}
|
|
@ -17,7 +17,7 @@ package org.teavm.backend.wasm.model;
|
|||
|
||||
public abstract class WasmCompositeType extends WasmEntity {
|
||||
private String name;
|
||||
private WasmType.Reference reference;
|
||||
private WasmType.CompositeReference reference;
|
||||
|
||||
WasmCompositeType(String name) {
|
||||
this.name = name;
|
||||
|
@ -27,9 +27,9 @@ public abstract class WasmCompositeType extends WasmEntity {
|
|||
return name;
|
||||
}
|
||||
|
||||
public WasmType.Reference getReference() {
|
||||
public WasmType.CompositeReference getReference() {
|
||||
if (reference == null) {
|
||||
reference = new WasmType.Reference(this);
|
||||
reference = new WasmType.CompositeReference(this);
|
||||
}
|
||||
return reference;
|
||||
}
|
||||
|
|
|
@ -16,27 +16,15 @@
|
|||
package org.teavm.backend.wasm.model;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
public class WasmStructure extends WasmCompositeType {
|
||||
private List<? extends WasmStorageType> fields;
|
||||
private Supplier<List<? extends WasmStorageType>> fieldsSupplier;
|
||||
private List<WasmStorageType> fields;
|
||||
|
||||
public WasmStructure(String name, List<? extends WasmStorageType> fields) {
|
||||
public WasmStructure(String name) {
|
||||
super(name);
|
||||
this.fields = List.copyOf(fields);
|
||||
}
|
||||
|
||||
public WasmStructure(String name, Supplier<List<? extends WasmStorageType>> fieldsSupplier) {
|
||||
super(name);
|
||||
this.fieldsSupplier = fieldsSupplier;
|
||||
}
|
||||
|
||||
public List<? extends WasmStorageType> getFields() {
|
||||
if (fields == null) {
|
||||
fields = List.copyOf(fieldsSupplier.get());
|
||||
fieldsSupplier = null;
|
||||
}
|
||||
public List<WasmStorageType> getFields() {
|
||||
return fields;
|
||||
}
|
||||
|
||||
|
|
|
@ -56,11 +56,44 @@ public abstract class WasmType {
|
|||
}
|
||||
}
|
||||
|
||||
public static final class Reference extends WasmType {
|
||||
public static abstract class Reference extends WasmType {
|
||||
public static final SpecialReference FUNC = SpecialReferenceKind.FUNC.asType();
|
||||
public static final SpecialReference ANY = SpecialReferenceKind.ANY.asType();
|
||||
public static final SpecialReference EXTERN = SpecialReferenceKind.EXTERN.asType();
|
||||
public static final SpecialReference STRUCT = SpecialReferenceKind.STRUCT.asType();
|
||||
public static final SpecialReference ARRAY = SpecialReferenceKind.ARRAY.asType();
|
||||
}
|
||||
|
||||
public static final class CompositeReference extends Reference {
|
||||
public final WasmCompositeType composite;
|
||||
|
||||
Reference(WasmCompositeType composite) {
|
||||
CompositeReference(WasmCompositeType composite) {
|
||||
this.composite = composite;
|
||||
}
|
||||
}
|
||||
|
||||
public static final class SpecialReference extends WasmType {
|
||||
public final SpecialReferenceKind kind;
|
||||
|
||||
private SpecialReference(SpecialReferenceKind kind) {
|
||||
this.kind = kind;
|
||||
}
|
||||
}
|
||||
|
||||
public enum SpecialReferenceKind {
|
||||
FUNC,
|
||||
ANY,
|
||||
EXTERN,
|
||||
STRUCT,
|
||||
ARRAY;
|
||||
|
||||
private SpecialReference type;
|
||||
|
||||
final SpecialReference asType() {
|
||||
if (type == null) {
|
||||
type = new SpecialReference(this);
|
||||
}
|
||||
return type;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,57 @@
|
|||
/*
|
||||
* 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.model.expression;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import org.teavm.backend.wasm.model.WasmFunctionType;
|
||||
|
||||
public class WasmCallReference extends WasmExpression {
|
||||
private WasmFunctionType type;
|
||||
private WasmExpression functionReference;
|
||||
private List<WasmExpression> arguments = new ArrayList<>();
|
||||
|
||||
public WasmCallReference(WasmExpression functionReference, WasmFunctionType type) {
|
||||
this.functionReference = Objects.requireNonNull(functionReference);
|
||||
this.type = Objects.requireNonNull(type);
|
||||
}
|
||||
|
||||
public WasmExpression getFunctionReference() {
|
||||
return functionReference;
|
||||
}
|
||||
|
||||
public void setFunctionReference(WasmExpression functionReference) {
|
||||
this.functionReference = Objects.requireNonNull(functionReference);
|
||||
}
|
||||
|
||||
public List<WasmExpression> getArguments() {
|
||||
return arguments;
|
||||
}
|
||||
|
||||
public WasmFunctionType getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
public void setType(WasmFunctionType type) {
|
||||
this.type = Objects.requireNonNull(type);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void acceptVisitor(WasmExpressionVisitor visitor) {
|
||||
visitor.visit(this);
|
||||
}
|
||||
}
|
|
@ -145,6 +145,14 @@ public class WasmDefaultExpressionVisitor implements WasmExpressionVisitor {
|
|||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(WasmCallReference expression) {
|
||||
expression.getFunctionReference().acceptVisitor(this);
|
||||
for (var argument : expression.getArguments()) {
|
||||
argument.acceptVisitor(this);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(WasmDrop expression) {
|
||||
expression.getOperand().acceptVisitor(this);
|
||||
|
@ -250,6 +258,10 @@ public class WasmDefaultExpressionVisitor implements WasmExpressionVisitor {
|
|||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(WasmStructNewDefault expression) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(WasmStructGet expression) {
|
||||
expression.getInstance().acceptVisitor(this);
|
||||
|
@ -283,4 +295,8 @@ public class WasmDefaultExpressionVisitor implements WasmExpressionVisitor {
|
|||
public void visit(WasmArrayLength expression) {
|
||||
expression.getInstance().acceptVisitor(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(WasmFunctionReference expression) {
|
||||
}
|
||||
}
|
||||
|
|
|
@ -56,7 +56,7 @@ public abstract class WasmExpression {
|
|||
throw new IllegalArgumentException();
|
||||
}
|
||||
} else if (type instanceof WasmType.Reference) {
|
||||
return new WasmNullConstant(((WasmType.Reference) type).composite);
|
||||
return new WasmNullConstant((WasmType.Reference) type);
|
||||
} else {
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
|
|
|
@ -62,6 +62,8 @@ public interface WasmExpressionVisitor {
|
|||
|
||||
void visit(WasmIndirectCall expression);
|
||||
|
||||
void visit(WasmCallReference expression);
|
||||
|
||||
void visit(WasmDrop expression);
|
||||
|
||||
void visit(WasmLoadInt32 expression);
|
||||
|
@ -96,6 +98,8 @@ public interface WasmExpressionVisitor {
|
|||
|
||||
void visit(WasmStructNew expression);
|
||||
|
||||
void visit(WasmStructNewDefault expression);
|
||||
|
||||
void visit(WasmStructGet expression);
|
||||
|
||||
void visit(WasmStructSet expression);
|
||||
|
@ -107,4 +111,6 @@ public interface WasmExpressionVisitor {
|
|||
void visit(WasmArraySet expression);
|
||||
|
||||
void visit(WasmArrayLength expression);
|
||||
|
||||
void visit(WasmFunctionReference expression);
|
||||
}
|
||||
|
|
|
@ -0,0 +1,40 @@
|
|||
/*
|
||||
* 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.model.expression;
|
||||
|
||||
import java.util.Objects;
|
||||
import org.teavm.backend.wasm.model.WasmFunction;
|
||||
|
||||
public class WasmFunctionReference extends WasmExpression {
|
||||
private WasmFunction function;
|
||||
|
||||
public WasmFunctionReference(WasmFunction function) {
|
||||
this.function = Objects.requireNonNull(function);
|
||||
}
|
||||
|
||||
public WasmFunction getFunction() {
|
||||
return function;
|
||||
}
|
||||
|
||||
public void setFunction(WasmFunction function) {
|
||||
this.function = Objects.requireNonNull(function);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void acceptVisitor(WasmExpressionVisitor visitor) {
|
||||
visitor.visit(this);
|
||||
}
|
||||
}
|
|
@ -15,20 +15,20 @@
|
|||
*/
|
||||
package org.teavm.backend.wasm.model.expression;
|
||||
|
||||
import org.teavm.backend.wasm.model.WasmCompositeType;
|
||||
import org.teavm.backend.wasm.model.WasmType;
|
||||
|
||||
public class WasmNullConstant extends WasmExpression {
|
||||
public WasmCompositeType type;
|
||||
public WasmType.Reference type;
|
||||
|
||||
public WasmNullConstant(WasmCompositeType type) {
|
||||
public WasmNullConstant(WasmType.Reference type) {
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
public WasmCompositeType getType() {
|
||||
public WasmType.Reference getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
public void setType(WasmCompositeType type) {
|
||||
public void setType(WasmType.Reference type) {
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
|
|
|
@ -173,6 +173,13 @@ public class WasmReplacingExpressionVisitor implements WasmExpressionVisitor {
|
|||
replaceExpressions(expression.getArguments());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(WasmCallReference expression) {
|
||||
expression.getFunctionReference().acceptVisitor(this);
|
||||
expression.setFunctionReference(mapper.apply(expression.getFunctionReference()));
|
||||
replaceExpressions(expression.getArguments());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(WasmDrop expression) {
|
||||
expression.getOperand().acceptVisitor(this);
|
||||
|
@ -295,6 +302,11 @@ public class WasmReplacingExpressionVisitor implements WasmExpressionVisitor {
|
|||
|
||||
@Override
|
||||
public void visit(WasmStructNew expression) {
|
||||
replaceExpressions(expression.getInitializers());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(WasmStructNewDefault expression) {
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -344,4 +356,8 @@ public class WasmReplacingExpressionVisitor implements WasmExpressionVisitor {
|
|||
expression.getInstance().acceptVisitor(this);
|
||||
expression.setInstance(mapper.apply(expression.getInstance()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(WasmFunctionReference expression) {
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,43 @@
|
|||
/*
|
||||
* 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.model.expression;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import org.teavm.backend.wasm.model.WasmStructure;
|
||||
|
||||
public class WasmStructNewDefault extends WasmExpression {
|
||||
private WasmStructure type;
|
||||
private List<WasmExpression> initializers = new ArrayList<>();
|
||||
|
||||
public WasmStructNewDefault(WasmStructure type) {
|
||||
this.type = Objects.requireNonNull(type);
|
||||
}
|
||||
|
||||
public WasmStructure getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
public void setType(WasmStructure type) {
|
||||
this.type = Objects.requireNonNull(type);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void acceptVisitor(WasmExpressionVisitor visitor) {
|
||||
visitor.visit(this);
|
||||
}
|
||||
}
|
|
@ -25,6 +25,7 @@ import org.teavm.backend.wasm.model.expression.WasmCall;
|
|||
import org.teavm.backend.wasm.model.expression.WasmDefaultExpressionVisitor;
|
||||
import org.teavm.backend.wasm.model.expression.WasmExpression;
|
||||
import org.teavm.backend.wasm.model.expression.WasmExpressionVisitor;
|
||||
import org.teavm.backend.wasm.model.expression.WasmFunctionReference;
|
||||
|
||||
public class UnusedFunctionElimination {
|
||||
private WasmModule module;
|
||||
|
@ -64,10 +65,13 @@ public class UnusedFunctionElimination {
|
|||
@Override
|
||||
public void visit(WasmCall expression) {
|
||||
super.visit(expression);
|
||||
var function = expression.getFunction();
|
||||
if (function != null) {
|
||||
use(function);
|
||||
}
|
||||
use(expression.getFunction());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(WasmFunctionReference expression) {
|
||||
super.visit(expression);
|
||||
use(expression.getFunction());
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
|
@ -27,9 +27,19 @@ import org.teavm.backend.wasm.model.WasmModule;
|
|||
import org.teavm.backend.wasm.model.WasmStorageType;
|
||||
import org.teavm.backend.wasm.model.WasmStructure;
|
||||
import org.teavm.backend.wasm.model.WasmType;
|
||||
import org.teavm.backend.wasm.model.expression.WasmArrayGet;
|
||||
import org.teavm.backend.wasm.model.expression.WasmArraySet;
|
||||
import org.teavm.backend.wasm.model.expression.WasmCallReference;
|
||||
import org.teavm.backend.wasm.model.expression.WasmCast;
|
||||
import org.teavm.backend.wasm.model.expression.WasmDefaultExpressionVisitor;
|
||||
import org.teavm.backend.wasm.model.expression.WasmExpressionVisitor;
|
||||
import org.teavm.backend.wasm.model.expression.WasmFunctionReference;
|
||||
import org.teavm.backend.wasm.model.expression.WasmIndirectCall;
|
||||
import org.teavm.backend.wasm.model.expression.WasmNullConstant;
|
||||
import org.teavm.backend.wasm.model.expression.WasmStructGet;
|
||||
import org.teavm.backend.wasm.model.expression.WasmStructNew;
|
||||
import org.teavm.backend.wasm.model.expression.WasmStructNewDefault;
|
||||
import org.teavm.backend.wasm.model.expression.WasmStructSet;
|
||||
|
||||
public class UnusedTypeElimination {
|
||||
private WasmModule module;
|
||||
|
@ -51,15 +61,27 @@ public class UnusedTypeElimination {
|
|||
for (var tag : module.tags) {
|
||||
use(tag.getType());
|
||||
}
|
||||
for (var global : module.globals) {
|
||||
use(global.getType());
|
||||
}
|
||||
}
|
||||
|
||||
private void useFrom(WasmFunction function) {
|
||||
use(function.getType());
|
||||
for (var local : function.getLocalVariables()) {
|
||||
use(local.getType());
|
||||
}
|
||||
for (var part : function.getBody()) {
|
||||
part.acceptVisitor(exprVisitor);
|
||||
}
|
||||
}
|
||||
|
||||
private void use(WasmType type) {
|
||||
if (type instanceof WasmType.CompositeReference) {
|
||||
use(((WasmType.CompositeReference) type).composite);
|
||||
}
|
||||
}
|
||||
|
||||
private void use(WasmCompositeType type) {
|
||||
if (!usedTypes.add(type)) {
|
||||
return;
|
||||
|
@ -73,6 +95,67 @@ public class UnusedTypeElimination {
|
|||
super.visit(expression);
|
||||
use(expression.getType());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(WasmCast expression) {
|
||||
super.visit(expression);
|
||||
use(expression.getTargetType());
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void visit(WasmArrayGet expression) {
|
||||
super.visit(expression);
|
||||
use(expression.getType());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(WasmArraySet expression) {
|
||||
super.visit(expression);
|
||||
use(expression.getType());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(WasmStructNew expression) {
|
||||
super.visit(expression);
|
||||
use(expression.getType());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(WasmStructNewDefault expression) {
|
||||
super.visit(expression);
|
||||
use(expression.getType());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(WasmStructGet expression) {
|
||||
super.visit(expression);
|
||||
use(expression.getType());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(WasmStructSet expression) {
|
||||
super.visit(expression);
|
||||
use(expression.getType());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(WasmNullConstant expression) {
|
||||
super.visit(expression);
|
||||
use(expression.getType());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(WasmFunctionReference expression) {
|
||||
super.visit(expression);
|
||||
useFrom(expression.getFunction());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(WasmCallReference expression) {
|
||||
super.visit(expression);
|
||||
use(expression.getType());
|
||||
}
|
||||
};
|
||||
|
||||
private WasmCompositeTypeVisitor typeVisitor = new WasmDefaultCompositeTypeVisitor() {
|
||||
|
@ -105,8 +188,8 @@ public class UnusedTypeElimination {
|
|||
}
|
||||
|
||||
private void visit(WasmType type) {
|
||||
if (type instanceof WasmType.Reference) {
|
||||
use(((WasmType.Reference) type).composite);
|
||||
if (type instanceof WasmType.CompositeReference) {
|
||||
use(((WasmType.CompositeReference) type).composite);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
|
@ -33,6 +33,7 @@ import org.teavm.backend.wasm.model.expression.WasmBlock;
|
|||
import org.teavm.backend.wasm.model.expression.WasmBranch;
|
||||
import org.teavm.backend.wasm.model.expression.WasmBreak;
|
||||
import org.teavm.backend.wasm.model.expression.WasmCall;
|
||||
import org.teavm.backend.wasm.model.expression.WasmCallReference;
|
||||
import org.teavm.backend.wasm.model.expression.WasmCast;
|
||||
import org.teavm.backend.wasm.model.expression.WasmConditional;
|
||||
import org.teavm.backend.wasm.model.expression.WasmConversion;
|
||||
|
@ -45,6 +46,7 @@ import org.teavm.backend.wasm.model.expression.WasmFloat32Constant;
|
|||
import org.teavm.backend.wasm.model.expression.WasmFloat64Constant;
|
||||
import org.teavm.backend.wasm.model.expression.WasmFloatBinary;
|
||||
import org.teavm.backend.wasm.model.expression.WasmFloatUnary;
|
||||
import org.teavm.backend.wasm.model.expression.WasmFunctionReference;
|
||||
import org.teavm.backend.wasm.model.expression.WasmGetGlobal;
|
||||
import org.teavm.backend.wasm.model.expression.WasmGetLocal;
|
||||
import org.teavm.backend.wasm.model.expression.WasmIndirectCall;
|
||||
|
@ -68,6 +70,7 @@ import org.teavm.backend.wasm.model.expression.WasmStoreInt32;
|
|||
import org.teavm.backend.wasm.model.expression.WasmStoreInt64;
|
||||
import org.teavm.backend.wasm.model.expression.WasmStructGet;
|
||||
import org.teavm.backend.wasm.model.expression.WasmStructNew;
|
||||
import org.teavm.backend.wasm.model.expression.WasmStructNewDefault;
|
||||
import org.teavm.backend.wasm.model.expression.WasmStructSet;
|
||||
import org.teavm.backend.wasm.model.expression.WasmSwitch;
|
||||
import org.teavm.backend.wasm.model.expression.WasmThrow;
|
||||
|
@ -250,7 +253,7 @@ class WasmBinaryRenderingVisitor implements WasmExpressionVisitor {
|
|||
public void visit(WasmNullConstant expression) {
|
||||
pushLocation(expression);
|
||||
writer.writeByte(0xD0);
|
||||
writer.writeSignedLEB(module.types.indexOf(expression.getType()));
|
||||
writeBlockType(expression.getType());
|
||||
popLocation();
|
||||
}
|
||||
|
||||
|
@ -776,6 +779,18 @@ class WasmBinaryRenderingVisitor implements WasmExpressionVisitor {
|
|||
popLocation();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(WasmCallReference expression) {
|
||||
pushLocation(expression);
|
||||
for (var argument : expression.getArguments()) {
|
||||
argument.acceptVisitor(this);
|
||||
}
|
||||
expression.getFunctionReference().acceptVisitor(this);
|
||||
writer.writeByte(0x14);
|
||||
writer.writeLEB(module.types.indexOf(expression.getType()));
|
||||
popLocation();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(WasmDrop expression) {
|
||||
pushLocation(expression);
|
||||
|
@ -1031,6 +1046,15 @@ class WasmBinaryRenderingVisitor implements WasmExpressionVisitor {
|
|||
popLocation();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(WasmStructNewDefault expression) {
|
||||
pushLocation(expression);
|
||||
writer.writeByte(0xfb);
|
||||
writer.writeByte(1);
|
||||
writer.writeInt32(module.types.indexOf(expression.getType()));
|
||||
popLocation();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(WasmStructGet expression) {
|
||||
pushLocation(expression);
|
||||
|
@ -1118,6 +1142,14 @@ class WasmBinaryRenderingVisitor implements WasmExpressionVisitor {
|
|||
popLocation();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(WasmFunctionReference expression) {
|
||||
pushLocation(expression);
|
||||
writer.writeByte(0xd2);
|
||||
writer.writeInt32(module.functions.indexOf(expression.getFunction()));
|
||||
popLocation();
|
||||
}
|
||||
|
||||
private int alignment(int value) {
|
||||
return 31 - Integer.numberOfLeadingZeros(Math.max(1, value));
|
||||
}
|
||||
|
|
|
@ -36,8 +36,26 @@ public class WasmBinaryWriter {
|
|||
}
|
||||
if (type instanceof WasmType.Number) {
|
||||
writeType(((WasmType.Number) type).number);
|
||||
} else if (type instanceof WasmType.Reference) {
|
||||
writeSignedLEB(module.types.indexOf(((WasmType.Reference) type).composite));
|
||||
} else if (type instanceof WasmType.SpecialReference) {
|
||||
switch (((WasmType.SpecialReference) type).kind) {
|
||||
case ANY:
|
||||
writeByte(0x6e);
|
||||
break;
|
||||
case EXTERN:
|
||||
writeByte(0x6f);
|
||||
break;
|
||||
case FUNC:
|
||||
writeByte(0x70);
|
||||
break;
|
||||
case STRUCT:
|
||||
writeByte(0x6b);
|
||||
break;
|
||||
case ARRAY:
|
||||
writeByte(0x6a);
|
||||
break;
|
||||
}
|
||||
} else if (type instanceof WasmType.CompositeReference) {
|
||||
writeSignedLEB(module.types.indexOf(((WasmType.CompositeReference) type).composite));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -35,6 +35,7 @@ import org.teavm.backend.wasm.model.expression.WasmBlock;
|
|||
import org.teavm.backend.wasm.model.expression.WasmBranch;
|
||||
import org.teavm.backend.wasm.model.expression.WasmBreak;
|
||||
import org.teavm.backend.wasm.model.expression.WasmCall;
|
||||
import org.teavm.backend.wasm.model.expression.WasmCallReference;
|
||||
import org.teavm.backend.wasm.model.expression.WasmCast;
|
||||
import org.teavm.backend.wasm.model.expression.WasmConditional;
|
||||
import org.teavm.backend.wasm.model.expression.WasmConversion;
|
||||
|
@ -48,6 +49,7 @@ import org.teavm.backend.wasm.model.expression.WasmFloat64Constant;
|
|||
import org.teavm.backend.wasm.model.expression.WasmFloatBinary;
|
||||
import org.teavm.backend.wasm.model.expression.WasmFloatType;
|
||||
import org.teavm.backend.wasm.model.expression.WasmFloatUnary;
|
||||
import org.teavm.backend.wasm.model.expression.WasmFunctionReference;
|
||||
import org.teavm.backend.wasm.model.expression.WasmGetGlobal;
|
||||
import org.teavm.backend.wasm.model.expression.WasmGetLocal;
|
||||
import org.teavm.backend.wasm.model.expression.WasmIndirectCall;
|
||||
|
@ -72,6 +74,7 @@ import org.teavm.backend.wasm.model.expression.WasmStoreInt32;
|
|||
import org.teavm.backend.wasm.model.expression.WasmStoreInt64;
|
||||
import org.teavm.backend.wasm.model.expression.WasmStructGet;
|
||||
import org.teavm.backend.wasm.model.expression.WasmStructNew;
|
||||
import org.teavm.backend.wasm.model.expression.WasmStructNewDefault;
|
||||
import org.teavm.backend.wasm.model.expression.WasmStructSet;
|
||||
import org.teavm.backend.wasm.model.expression.WasmSwitch;
|
||||
import org.teavm.backend.wasm.model.expression.WasmThrow;
|
||||
|
@ -783,6 +786,11 @@ class WasmCRenderingVisitor implements WasmExpressionVisitor {
|
|||
value = result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(WasmCallReference expression) {
|
||||
unsupported();
|
||||
}
|
||||
|
||||
private void translateArguments(List<? extends WasmExpression> wasmArguments, List<? extends WasmType> signature,
|
||||
CExpression result, StringBuilder sb) {
|
||||
if (wasmArguments.isEmpty()) {
|
||||
|
@ -1166,6 +1174,11 @@ class WasmCRenderingVisitor implements WasmExpressionVisitor {
|
|||
unsupported();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(WasmStructNewDefault expression) {
|
||||
unsupported();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(WasmStructGet expression) {
|
||||
unsupported();
|
||||
|
@ -1196,6 +1209,11 @@ class WasmCRenderingVisitor implements WasmExpressionVisitor {
|
|||
unsupported();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(WasmFunctionReference expression) {
|
||||
unsupported();
|
||||
}
|
||||
|
||||
private void unsupported() {
|
||||
value = new CExpression("/* unsupported */");
|
||||
}
|
||||
|
|
|
@ -31,6 +31,7 @@ import org.teavm.backend.wasm.model.expression.WasmBlock;
|
|||
import org.teavm.backend.wasm.model.expression.WasmBranch;
|
||||
import org.teavm.backend.wasm.model.expression.WasmBreak;
|
||||
import org.teavm.backend.wasm.model.expression.WasmCall;
|
||||
import org.teavm.backend.wasm.model.expression.WasmCallReference;
|
||||
import org.teavm.backend.wasm.model.expression.WasmCast;
|
||||
import org.teavm.backend.wasm.model.expression.WasmConditional;
|
||||
import org.teavm.backend.wasm.model.expression.WasmConversion;
|
||||
|
@ -47,6 +48,7 @@ import org.teavm.backend.wasm.model.expression.WasmFloatBinaryOperation;
|
|||
import org.teavm.backend.wasm.model.expression.WasmFloatType;
|
||||
import org.teavm.backend.wasm.model.expression.WasmFloatUnary;
|
||||
import org.teavm.backend.wasm.model.expression.WasmFloatUnaryOperation;
|
||||
import org.teavm.backend.wasm.model.expression.WasmFunctionReference;
|
||||
import org.teavm.backend.wasm.model.expression.WasmGetGlobal;
|
||||
import org.teavm.backend.wasm.model.expression.WasmGetLocal;
|
||||
import org.teavm.backend.wasm.model.expression.WasmIndirectCall;
|
||||
|
@ -73,6 +75,7 @@ import org.teavm.backend.wasm.model.expression.WasmStoreInt32;
|
|||
import org.teavm.backend.wasm.model.expression.WasmStoreInt64;
|
||||
import org.teavm.backend.wasm.model.expression.WasmStructGet;
|
||||
import org.teavm.backend.wasm.model.expression.WasmStructNew;
|
||||
import org.teavm.backend.wasm.model.expression.WasmStructNewDefault;
|
||||
import org.teavm.backend.wasm.model.expression.WasmStructSet;
|
||||
import org.teavm.backend.wasm.model.expression.WasmSwitch;
|
||||
import org.teavm.backend.wasm.model.expression.WasmThrow;
|
||||
|
@ -288,7 +291,7 @@ class WasmRenderingVisitor implements WasmExpressionVisitor {
|
|||
|
||||
@Override
|
||||
public void visit(WasmNullConstant expression) {
|
||||
open().append("ref.null " + module.types.indexOf(expression.getType())).close();
|
||||
open().append("ref.null " + type(expression.getType())).close();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -446,6 +449,16 @@ class WasmRenderingVisitor implements WasmExpressionVisitor {
|
|||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(WasmCallReference expression) {
|
||||
open().append("call_ref ").append(type(expression.getType().getReference()));
|
||||
line(expression.getFunctionReference());
|
||||
for (var argument : expression.getArguments()) {
|
||||
line(argument);
|
||||
}
|
||||
close();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(WasmDrop expression) {
|
||||
open().append("drop").lf();
|
||||
|
@ -696,6 +709,11 @@ class WasmRenderingVisitor implements WasmExpressionVisitor {
|
|||
close();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(WasmStructNewDefault expression) {
|
||||
open().append("struct.new_default ").append(expression.getType().getReference()).close();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(WasmStructGet expression) {
|
||||
open();
|
||||
|
@ -773,11 +791,32 @@ class WasmRenderingVisitor implements WasmExpressionVisitor {
|
|||
close();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(WasmFunctionReference expression) {
|
||||
open().append("ref.func ").append(" $" + module.functions.indexOf(expression.getFunction()));
|
||||
close();
|
||||
}
|
||||
|
||||
private String type(WasmType type) {
|
||||
if (type instanceof WasmType.Number) {
|
||||
return type(((WasmType.Number) type).number);
|
||||
} else if (type instanceof WasmType.Reference) {
|
||||
return "(ref " + typeName(((WasmType.Reference) type).composite) + ")";
|
||||
} else if (type instanceof WasmType.SpecialReference) {
|
||||
switch (((WasmType.SpecialReference) type).kind) {
|
||||
case ANY:
|
||||
return "anyref";
|
||||
case EXTERN:
|
||||
return "externref";
|
||||
case STRUCT:
|
||||
return "structref";
|
||||
case FUNC:
|
||||
return "funcref";
|
||||
case ARRAY:
|
||||
return "arrayref";
|
||||
default:
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
} else if (type instanceof WasmType.CompositeReference) {
|
||||
return "(ref " + typeName(((WasmType.CompositeReference) type).composite) + ")";
|
||||
} else {
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
|
|
|
@ -24,6 +24,7 @@ import org.teavm.backend.wasm.model.expression.WasmBlock;
|
|||
import org.teavm.backend.wasm.model.expression.WasmBranch;
|
||||
import org.teavm.backend.wasm.model.expression.WasmBreak;
|
||||
import org.teavm.backend.wasm.model.expression.WasmCall;
|
||||
import org.teavm.backend.wasm.model.expression.WasmCallReference;
|
||||
import org.teavm.backend.wasm.model.expression.WasmCast;
|
||||
import org.teavm.backend.wasm.model.expression.WasmConditional;
|
||||
import org.teavm.backend.wasm.model.expression.WasmConversion;
|
||||
|
@ -36,6 +37,7 @@ import org.teavm.backend.wasm.model.expression.WasmFloat64Constant;
|
|||
import org.teavm.backend.wasm.model.expression.WasmFloatBinary;
|
||||
import org.teavm.backend.wasm.model.expression.WasmFloatType;
|
||||
import org.teavm.backend.wasm.model.expression.WasmFloatUnary;
|
||||
import org.teavm.backend.wasm.model.expression.WasmFunctionReference;
|
||||
import org.teavm.backend.wasm.model.expression.WasmGetGlobal;
|
||||
import org.teavm.backend.wasm.model.expression.WasmGetLocal;
|
||||
import org.teavm.backend.wasm.model.expression.WasmIndirectCall;
|
||||
|
@ -60,6 +62,7 @@ import org.teavm.backend.wasm.model.expression.WasmStoreInt32;
|
|||
import org.teavm.backend.wasm.model.expression.WasmStoreInt64;
|
||||
import org.teavm.backend.wasm.model.expression.WasmStructGet;
|
||||
import org.teavm.backend.wasm.model.expression.WasmStructNew;
|
||||
import org.teavm.backend.wasm.model.expression.WasmStructNewDefault;
|
||||
import org.teavm.backend.wasm.model.expression.WasmStructSet;
|
||||
import org.teavm.backend.wasm.model.expression.WasmSwitch;
|
||||
import org.teavm.backend.wasm.model.expression.WasmThrow;
|
||||
|
@ -175,7 +178,7 @@ public class WasmTypeInference implements WasmExpressionVisitor {
|
|||
|
||||
@Override
|
||||
public void visit(WasmNullConstant expression) {
|
||||
result = expression.type.getReference();
|
||||
result = expression.type;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -189,6 +192,11 @@ public class WasmTypeInference implements WasmExpressionVisitor {
|
|||
result = expression.getType().getReturnType();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(WasmCallReference expression) {
|
||||
result = expression.getType().getReturnType();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(WasmDrop expression) {
|
||||
result = null;
|
||||
|
@ -274,6 +282,11 @@ public class WasmTypeInference implements WasmExpressionVisitor {
|
|||
result = expression.getType().getReference();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(WasmStructNewDefault expression) {
|
||||
result = expression.getType().getReference();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(WasmStructGet expression) {
|
||||
result = expression.getType().getFields().get(expression.getFieldIndex()).asUnpackedType();
|
||||
|
@ -304,6 +317,11 @@ public class WasmTypeInference implements WasmExpressionVisitor {
|
|||
result = WasmType.INT32;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(WasmFunctionReference expression) {
|
||||
result = expression.getFunction().getType().getReference();
|
||||
}
|
||||
|
||||
private static WasmType map(WasmIntType type) {
|
||||
switch (type) {
|
||||
case INT32:
|
||||
|
|
46
core/src/main/java/org/teavm/model/util/ReflectionUtil.java
Normal file
46
core/src/main/java/org/teavm/model/util/ReflectionUtil.java
Normal file
|
@ -0,0 +1,46 @@
|
|||
/*
|
||||
* 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.model.util;
|
||||
|
||||
import org.teavm.model.PrimitiveType;
|
||||
|
||||
public final class ReflectionUtil {
|
||||
private ReflectionUtil() {
|
||||
}
|
||||
|
||||
public static String typeName(PrimitiveType type) {
|
||||
switch (type) {
|
||||
case BOOLEAN:
|
||||
return "boolean";
|
||||
case BYTE:
|
||||
return "byte";
|
||||
case SHORT:
|
||||
return "short";
|
||||
case CHARACTER:
|
||||
return "char";
|
||||
case INTEGER:
|
||||
return "int";
|
||||
case LONG:
|
||||
return "long";
|
||||
case FLOAT:
|
||||
return "float";
|
||||
case DOUBLE:
|
||||
return "double";
|
||||
default:
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user