mirror of
https://github.com/Eaglercraft-TeaVM-Fork/eagler-teavm.git
synced 2024-12-22 08:14:09 -08:00
wasm gc: implement enum constants
This commit is contained in:
parent
8184c46bae
commit
2d8556d0a2
|
@ -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.classlib.impl.reflection;
|
||||||
|
|
||||||
|
import org.teavm.interop.NoSideEffects;
|
||||||
|
|
||||||
|
public final class ClassSupport {
|
||||||
|
private ClassSupport() {
|
||||||
|
}
|
||||||
|
|
||||||
|
@NoSideEffects
|
||||||
|
public static native Enum<?>[] getEnumConstants(Class<?> cls);
|
||||||
|
}
|
|
@ -29,6 +29,7 @@ import java.util.Set;
|
||||||
import org.teavm.backend.javascript.spi.GeneratedBy;
|
import org.teavm.backend.javascript.spi.GeneratedBy;
|
||||||
import org.teavm.backend.javascript.spi.InjectedBy;
|
import org.teavm.backend.javascript.spi.InjectedBy;
|
||||||
import org.teavm.classlib.PlatformDetector;
|
import org.teavm.classlib.PlatformDetector;
|
||||||
|
import org.teavm.classlib.impl.reflection.ClassSupport;
|
||||||
import org.teavm.classlib.impl.reflection.Flags;
|
import org.teavm.classlib.impl.reflection.Flags;
|
||||||
import org.teavm.classlib.impl.reflection.JSClass;
|
import org.teavm.classlib.impl.reflection.JSClass;
|
||||||
import org.teavm.classlib.impl.reflection.JSField;
|
import org.teavm.classlib.impl.reflection.JSField;
|
||||||
|
@ -692,8 +693,12 @@ public final class TClass<T> extends TObject implements TAnnotatedElement, TType
|
||||||
if (!isEnum()) {
|
if (!isEnum()) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
Platform.initClass(platformClass);
|
if (PlatformDetector.isWebAssemblyGC()) {
|
||||||
return (T[]) Platform.getEnumConstants(platformClass).clone();
|
return (T[]) ClassSupport.getEnumConstants((Class<?>) (Object) this);
|
||||||
|
} else {
|
||||||
|
Platform.initClass(platformClass);
|
||||||
|
return (T[]) Platform.getEnumConstants(platformClass).clone();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
|
|
|
@ -18,6 +18,8 @@ package org.teavm.classlib.java.util;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
|
import org.teavm.classlib.PlatformDetector;
|
||||||
|
import org.teavm.classlib.impl.reflection.ClassSupport;
|
||||||
import org.teavm.classlib.java.lang.TClass;
|
import org.teavm.classlib.java.lang.TClass;
|
||||||
import org.teavm.platform.Platform;
|
import org.teavm.platform.Platform;
|
||||||
import org.teavm.platform.PlatformClass;
|
import org.teavm.platform.PlatformClass;
|
||||||
|
@ -43,9 +45,13 @@ class TGenericEnumSet<E extends Enum<E>> extends TEnumSet<E> {
|
||||||
}
|
}
|
||||||
|
|
||||||
static Enum<?>[] getConstants(Class<?> cls) {
|
static Enum<?>[] getConstants(Class<?> cls) {
|
||||||
PlatformClass platformClass = ((TClass<?>) (Object) cls).getPlatformClass();
|
if (PlatformDetector.isWebAssemblyGC()) {
|
||||||
Platform.initClass(platformClass);
|
return ClassSupport.getEnumConstants(cls);
|
||||||
return Platform.getEnumConstants(platformClass);
|
} else {
|
||||||
|
PlatformClass platformClass = ((TClass<?>) (Object) cls).getPlatformClass();
|
||||||
|
Platform.initClass(platformClass);
|
||||||
|
return Platform.getEnumConstants(platformClass);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -98,8 +98,8 @@ public class WasmGCDependencies {
|
||||||
analyzer.linkMethod(new MethodReference(WasmGCSupport.class, "aiiobe", ArrayIndexOutOfBoundsException.class))
|
analyzer.linkMethod(new MethodReference(WasmGCSupport.class, "aiiobe", ArrayIndexOutOfBoundsException.class))
|
||||||
.use();
|
.use();
|
||||||
analyzer.linkMethod(new MethodReference(WasmGCSupport.class, "cce", ClassCastException.class)).use();
|
analyzer.linkMethod(new MethodReference(WasmGCSupport.class, "cce", ClassCastException.class)).use();
|
||||||
analyzer.linkMethod(new MethodReference(WasmGCSupport.class, "throwCloneNotSupportedException",
|
analyzer.linkMethod(new MethodReference(WasmGCSupport.class, "defaultClone", Object.class,
|
||||||
void.class)).use();
|
Object.class)).use();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void contributeInitializerUtils() {
|
private void contributeInitializerUtils() {
|
||||||
|
|
|
@ -31,8 +31,10 @@ import org.teavm.backend.wasm.WasmFunctionTypes;
|
||||||
import org.teavm.backend.wasm.gc.vtable.WasmGCVirtualTable;
|
import org.teavm.backend.wasm.gc.vtable.WasmGCVirtualTable;
|
||||||
import org.teavm.backend.wasm.gc.vtable.WasmGCVirtualTableEntry;
|
import org.teavm.backend.wasm.gc.vtable.WasmGCVirtualTableEntry;
|
||||||
import org.teavm.backend.wasm.gc.vtable.WasmGCVirtualTableProvider;
|
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.WasmGCInitializerContributor;
|
||||||
import org.teavm.backend.wasm.generate.gc.WasmGCNameProvider;
|
import org.teavm.backend.wasm.generate.gc.WasmGCNameProvider;
|
||||||
|
import org.teavm.backend.wasm.generate.gc.methods.WasmGCGenerationUtil;
|
||||||
import org.teavm.backend.wasm.generate.gc.strings.WasmGCStringPool;
|
import org.teavm.backend.wasm.generate.gc.strings.WasmGCStringPool;
|
||||||
import org.teavm.backend.wasm.model.WasmArray;
|
import org.teavm.backend.wasm.model.WasmArray;
|
||||||
import org.teavm.backend.wasm.model.WasmField;
|
import org.teavm.backend.wasm.model.WasmField;
|
||||||
|
@ -48,7 +50,9 @@ import org.teavm.backend.wasm.model.expression.WasmArrayCopy;
|
||||||
import org.teavm.backend.wasm.model.expression.WasmArrayGet;
|
import org.teavm.backend.wasm.model.expression.WasmArrayGet;
|
||||||
import org.teavm.backend.wasm.model.expression.WasmArrayLength;
|
import org.teavm.backend.wasm.model.expression.WasmArrayLength;
|
||||||
import org.teavm.backend.wasm.model.expression.WasmArrayNewDefault;
|
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.WasmCall;
|
||||||
|
import org.teavm.backend.wasm.model.expression.WasmCallReference;
|
||||||
import org.teavm.backend.wasm.model.expression.WasmCast;
|
import org.teavm.backend.wasm.model.expression.WasmCast;
|
||||||
import org.teavm.backend.wasm.model.expression.WasmExpression;
|
import org.teavm.backend.wasm.model.expression.WasmExpression;
|
||||||
import org.teavm.backend.wasm.model.expression.WasmFloat32Constant;
|
import org.teavm.backend.wasm.model.expression.WasmFloat32Constant;
|
||||||
|
@ -72,6 +76,7 @@ import org.teavm.backend.wasm.model.expression.WasmStructNewDefault;
|
||||||
import org.teavm.backend.wasm.model.expression.WasmStructSet;
|
import org.teavm.backend.wasm.model.expression.WasmStructSet;
|
||||||
import org.teavm.backend.wasm.runtime.WasmGCSupport;
|
import org.teavm.backend.wasm.runtime.WasmGCSupport;
|
||||||
import org.teavm.model.ClassHierarchy;
|
import org.teavm.model.ClassHierarchy;
|
||||||
|
import org.teavm.model.ClassReader;
|
||||||
import org.teavm.model.ClassReaderSource;
|
import org.teavm.model.ClassReaderSource;
|
||||||
import org.teavm.model.ElementModifier;
|
import org.teavm.model.ElementModifier;
|
||||||
import org.teavm.model.FieldReference;
|
import org.teavm.model.FieldReference;
|
||||||
|
@ -131,6 +136,7 @@ public class WasmGCClassGenerator implements WasmGCClassInfoProvider, WasmGCInit
|
||||||
private int classSupertypeFunctionOffset;
|
private int classSupertypeFunctionOffset;
|
||||||
private int classEnclosingClassOffset;
|
private int classEnclosingClassOffset;
|
||||||
private int virtualTableFieldOffset;
|
private int virtualTableFieldOffset;
|
||||||
|
private int enumConstantsFunctionOffset;
|
||||||
private int arrayLengthOffset = -1;
|
private int arrayLengthOffset = -1;
|
||||||
private int arrayGetOffset = -1;
|
private int arrayGetOffset = -1;
|
||||||
private int cloneOffset = -1;
|
private int cloneOffset = -1;
|
||||||
|
@ -140,6 +146,8 @@ public class WasmGCClassGenerator implements WasmGCClassInfoProvider, WasmGCInit
|
||||||
private WasmFunctionType arrayGetType;
|
private WasmFunctionType arrayGetType;
|
||||||
private WasmFunctionType arrayLengthType;
|
private WasmFunctionType arrayLengthType;
|
||||||
private List<WasmStructure> nonInitializedStructures = new ArrayList<>();
|
private List<WasmStructure> nonInitializedStructures = new ArrayList<>();
|
||||||
|
private WasmArray objectArrayType;
|
||||||
|
private WasmArray enumConstantArray;
|
||||||
|
|
||||||
public WasmGCClassGenerator(WasmModule module, ClassReaderSource classSource,
|
public WasmGCClassGenerator(WasmModule module, ClassReaderSource classSource,
|
||||||
ClassHierarchy hierarchy,
|
ClassHierarchy hierarchy,
|
||||||
|
@ -494,11 +502,15 @@ public class WasmGCClassGenerator implements WasmGCClassInfoProvider, WasmGCInit
|
||||||
cloneFunction = generateCloneFunction(classInfo, name);
|
cloneFunction = generateCloneFunction(classInfo, name);
|
||||||
} else {
|
} else {
|
||||||
cloneFunction = functionProvider.forStaticMethod(new MethodReference(
|
cloneFunction = functionProvider.forStaticMethod(new MethodReference(
|
||||||
WasmGCSupport.class, "throwCloneNotSupportedException", void.class));
|
WasmGCSupport.class, "defaultClone", Object.class, Object.class));
|
||||||
}
|
}
|
||||||
cloneFunction.setReferenced(true);
|
cloneFunction.setReferenced(true);
|
||||||
target.add(setClassField(classInfo, cloneOffset, new WasmFunctionReference(cloneFunction)));
|
target.add(setClassField(classInfo, cloneOffset, new WasmFunctionReference(cloneFunction)));
|
||||||
}
|
}
|
||||||
|
if (metadataReq.enumConstants() && cls.hasModifier(ElementModifier.ENUM)) {
|
||||||
|
target.add(setClassField(classInfo, enumConstantsFunctionOffset,
|
||||||
|
new WasmFunctionReference(createEnumConstantsFunction(classInfo, cls))));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (virtualTable != null && virtualTable.isConcrete()) {
|
if (virtualTable != null && virtualTable.isConcrete()) {
|
||||||
fillVirtualTableMethods(target, classStructure, classInfo.pointer, virtualTable);
|
fillVirtualTableMethods(target, classStructure, classInfo.pointer, virtualTable);
|
||||||
|
@ -881,6 +893,11 @@ public class WasmGCClassGenerator implements WasmGCClassInfoProvider, WasmGCInit
|
||||||
return arrayGetOffset;
|
return arrayGetOffset;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getEnumConstantsFunctionOffset() {
|
||||||
|
return enumConstantsFunctionOffset;
|
||||||
|
}
|
||||||
|
|
||||||
private void initArrayClass(WasmGCClassInfo classInfo, ValueType.Array type) {
|
private void initArrayClass(WasmGCClassInfo classInfo, ValueType.Array type) {
|
||||||
classInfo.initializer = target -> {
|
classInfo.initializer = target -> {
|
||||||
var itemTypeInfo = getClassInfo(type.getItemType());
|
var itemTypeInfo = getClassInfo(type.getItemType());
|
||||||
|
@ -1047,6 +1064,13 @@ public class WasmGCClassGenerator implements WasmGCClassInfoProvider, WasmGCInit
|
||||||
cloneOffset = fields.size();
|
cloneOffset = fields.size();
|
||||||
fields.add(createClassField(functionTypes.of(standardClasses.objectClass().getType(),
|
fields.add(createClassField(functionTypes.of(standardClasses.objectClass().getType(),
|
||||||
standardClasses.objectClass().getType()).getReference().asStorage(), "clone"));
|
standardClasses.objectClass().getType()).getReference().asStorage(), "clone"));
|
||||||
|
fields.add(createClassField(WasmType.INT32.asStorage(), "enumConstantCount"));
|
||||||
|
if (metadataRequirements.hasEnumConstants()) {
|
||||||
|
enumConstantsFunctionOffset = fields.size();
|
||||||
|
var enumArrayType = getClassInfo(ValueType.arrayOf(ValueType.object("java.lang.Enum"))).getType();
|
||||||
|
var enumConstantsType = functionTypes.of(enumArrayType);
|
||||||
|
fields.add(createClassField(enumConstantsType.getReference().asStorage(), "getEnumConstants"));
|
||||||
|
}
|
||||||
virtualTableFieldOffset = fields.size();
|
virtualTableFieldOffset = fields.size();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1057,6 +1081,7 @@ public class WasmGCClassGenerator implements WasmGCClassInfoProvider, WasmGCInit
|
||||||
|
|
||||||
private void fillArrayFields(WasmGCClassInfo classInfo, ValueType elementType) {
|
private void fillArrayFields(WasmGCClassInfo classInfo, ValueType elementType) {
|
||||||
WasmStorageType wasmElementType;
|
WasmStorageType wasmElementType;
|
||||||
|
WasmArray wasmArray;
|
||||||
if (elementType instanceof ValueType.Primitive) {
|
if (elementType instanceof ValueType.Primitive) {
|
||||||
switch (((ValueType.Primitive) elementType).getKind()) {
|
switch (((ValueType.Primitive) elementType).getKind()) {
|
||||||
case BOOLEAN:
|
case BOOLEAN:
|
||||||
|
@ -1082,12 +1107,21 @@ public class WasmGCClassGenerator implements WasmGCClassInfoProvider, WasmGCInit
|
||||||
default:
|
default:
|
||||||
throw new IllegalArgumentException();
|
throw new IllegalArgumentException();
|
||||||
}
|
}
|
||||||
|
var wasmArrayName = names.topLevel(names.suggestForType(classInfo.getValueType()) + "$Data");
|
||||||
|
wasmArray = new WasmArray(wasmArrayName, wasmElementType);
|
||||||
|
module.types.add(wasmArray);
|
||||||
} else {
|
} else {
|
||||||
wasmElementType = standardClasses.objectClass().getType().asStorage();
|
wasmElementType = standardClasses.objectClass().getType().asStorage();
|
||||||
|
wasmArray = objectArrayType;
|
||||||
|
if (wasmArray == null) {
|
||||||
|
var wasmArrayName = names.topLevel(names.suggestForType(ValueType.arrayOf(
|
||||||
|
ValueType.object("java.lang.Object"))) + "$Data");
|
||||||
|
wasmArray = new WasmArray(wasmArrayName, wasmElementType);
|
||||||
|
module.types.add(wasmArray);
|
||||||
|
objectArrayType = wasmArray;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
var wasmArrayName = names.topLevel(names.suggestForType(classInfo.getValueType()) + "$Data");
|
|
||||||
var wasmArray = new WasmArray(wasmArrayName, wasmElementType);
|
|
||||||
module.types.add(wasmArray);
|
|
||||||
classInfo.structure.getFields().add(new WasmField(wasmArray.getReference().asStorage(),
|
classInfo.structure.getFields().add(new WasmField(wasmArray.getReference().asStorage(),
|
||||||
arrayDataFieldName()));
|
arrayDataFieldName()));
|
||||||
}
|
}
|
||||||
|
@ -1214,6 +1248,35 @@ public class WasmGCClassGenerator implements WasmGCClassInfoProvider, WasmGCInit
|
||||||
return function;
|
return function;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private WasmFunction createEnumConstantsFunction(WasmGCClassInfo classInfo, ClassReader cls) {
|
||||||
|
var enumArrayStruct = getClassInfo(ValueType.parse(Enum[].class)).structure;
|
||||||
|
var function = new WasmFunction(functionTypes.of(enumArrayStruct.getReference()));
|
||||||
|
function.setName(names.topLevel(cls.getName() + "@constants"));
|
||||||
|
module.functions.add(function);
|
||||||
|
function.setReferenced(true);
|
||||||
|
|
||||||
|
var fields = cls.getFields().stream()
|
||||||
|
.filter(field -> field.hasModifier(ElementModifier.ENUM))
|
||||||
|
.filter(field -> field.hasModifier(ElementModifier.STATIC))
|
||||||
|
.map(field -> new WasmGetGlobal(getStaticFieldLocation(field.getReference())))
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
|
||||||
|
if (classInfo.getInitializerPointer() != null) {
|
||||||
|
function.getBody().add(new WasmCallReference(new WasmGetGlobal(classInfo.getInitializerPointer()),
|
||||||
|
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.allocateArray(ValueType.parse(Enum.class), fields, null, null, block.getBody());
|
||||||
|
function.getBody().add(new WasmReturn(block));
|
||||||
|
tempVars.release(local);
|
||||||
|
|
||||||
|
return function;
|
||||||
|
}
|
||||||
|
|
||||||
private WasmExpression setClassField(WasmGCClassInfo classInfo, int fieldIndex, WasmExpression value) {
|
private WasmExpression setClassField(WasmGCClassInfo classInfo, int fieldIndex, WasmExpression value) {
|
||||||
return new WasmStructSet(
|
return new WasmStructSet(
|
||||||
|
|
|
@ -54,6 +54,8 @@ public interface WasmGCClassInfoProvider {
|
||||||
|
|
||||||
int getArrayLengthOffset();
|
int getArrayLengthOffset();
|
||||||
|
|
||||||
|
int getEnumConstantsFunctionOffset();
|
||||||
|
|
||||||
int getCloneOffset();
|
int getCloneOffset();
|
||||||
|
|
||||||
default WasmGCClassInfo getClassInfo(String name) {
|
default WasmGCClassInfo getClassInfo(String name) {
|
||||||
|
|
|
@ -16,12 +16,14 @@
|
||||||
package org.teavm.backend.wasm.generate.gc.methods;
|
package org.teavm.backend.wasm.generate.gc.methods;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.function.Function;
|
||||||
import org.teavm.backend.wasm.generate.TemporaryVariablePool;
|
import org.teavm.backend.wasm.generate.TemporaryVariablePool;
|
||||||
import org.teavm.backend.wasm.generate.gc.classes.WasmGCClassInfoProvider;
|
import org.teavm.backend.wasm.generate.gc.classes.WasmGCClassInfoProvider;
|
||||||
import org.teavm.backend.wasm.model.WasmArray;
|
import org.teavm.backend.wasm.model.WasmArray;
|
||||||
import org.teavm.backend.wasm.model.WasmLocal;
|
import org.teavm.backend.wasm.model.WasmLocal;
|
||||||
import org.teavm.backend.wasm.model.WasmType;
|
import org.teavm.backend.wasm.model.WasmType;
|
||||||
import org.teavm.backend.wasm.model.expression.WasmArrayNewDefault;
|
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.WasmBlock;
|
||||||
import org.teavm.backend.wasm.model.expression.WasmExpression;
|
import org.teavm.backend.wasm.model.expression.WasmExpression;
|
||||||
import org.teavm.backend.wasm.model.expression.WasmGetGlobal;
|
import org.teavm.backend.wasm.model.expression.WasmGetGlobal;
|
||||||
|
@ -43,6 +45,20 @@ public class WasmGCGenerationUtil {
|
||||||
|
|
||||||
public void allocateArray(ValueType itemType, WasmExpression length, TextLocation location, WasmLocal local,
|
public void allocateArray(ValueType itemType, WasmExpression length, TextLocation location, WasmLocal local,
|
||||||
List<WasmExpression> target) {
|
List<WasmExpression> target) {
|
||||||
|
allocateArray(itemType, location, local, target, arrayType -> new WasmArrayNewDefault(arrayType, length));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void allocateArray(ValueType itemType, List<? extends WasmExpression> data, TextLocation location,
|
||||||
|
WasmLocal local, List<WasmExpression> target) {
|
||||||
|
allocateArray(itemType, location, local, target, arrayType -> {
|
||||||
|
var expr = new WasmArrayNewFixed(arrayType);
|
||||||
|
expr.getElements().addAll(data);
|
||||||
|
return expr;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public void allocateArray(ValueType itemType, TextLocation location,
|
||||||
|
WasmLocal local, List<WasmExpression> target, Function<WasmArray, WasmExpression> data) {
|
||||||
var classInfo = classInfoProvider.getClassInfo(ValueType.arrayOf(itemType));
|
var classInfo = classInfoProvider.getClassInfo(ValueType.arrayOf(itemType));
|
||||||
var block = new WasmBlock(false);
|
var block = new WasmBlock(false);
|
||||||
block.setType(classInfo.getType());
|
block.setType(classInfo.getType());
|
||||||
|
@ -68,7 +84,7 @@ public class WasmGCGenerationUtil {
|
||||||
classInfo.getStructure(),
|
classInfo.getStructure(),
|
||||||
new WasmGetLocal(targetVar),
|
new WasmGetLocal(targetVar),
|
||||||
WasmGCClassInfoProvider.ARRAY_DATA_FIELD_OFFSET,
|
WasmGCClassInfoProvider.ARRAY_DATA_FIELD_OFFSET,
|
||||||
new WasmArrayNewDefault(wasmArray, length)
|
data.apply(wasmArray)
|
||||||
);
|
);
|
||||||
initArrayField.setLocation(location);
|
initArrayField.setLocation(location);
|
||||||
target.add(initArrayField);
|
target.add(initArrayField);
|
||||||
|
|
|
@ -43,8 +43,7 @@ public class ClassIntrinsic implements WasmGCIntrinsic {
|
||||||
case "getSuperclass": {
|
case "getSuperclass": {
|
||||||
var cls = context.generate(invocation.getArguments().get(0));
|
var cls = context.generate(invocation.getArguments().get(0));
|
||||||
var clsStruct = context.classInfoProvider().getClassInfo("java.lang.Class").getStructure();
|
var clsStruct = context.classInfoProvider().getClassInfo("java.lang.Class").getStructure();
|
||||||
var result = new WasmStructGet(clsStruct, cls,
|
var result = new WasmStructGet(clsStruct, cls, context.classInfoProvider().getClassParentOffset());
|
||||||
context.classInfoProvider().getClassParentOffset());
|
|
||||||
result.setLocation(invocation.getLocation());
|
result.setLocation(invocation.getLocation());
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,35 @@
|
||||||
|
/*
|
||||||
|
* 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.intrinsics.gc;
|
||||||
|
|
||||||
|
import org.teavm.ast.InvocationExpr;
|
||||||
|
import org.teavm.backend.wasm.model.expression.WasmCallReference;
|
||||||
|
import org.teavm.backend.wasm.model.expression.WasmExpression;
|
||||||
|
import org.teavm.backend.wasm.model.expression.WasmStructGet;
|
||||||
|
import org.teavm.model.ValueType;
|
||||||
|
|
||||||
|
public class ClassSupportIntrinsic implements WasmGCIntrinsic {
|
||||||
|
@Override
|
||||||
|
public WasmExpression apply(InvocationExpr invocation, WasmGCIntrinsicContext context) {
|
||||||
|
var enumArrayStruct = context.classInfoProvider().getClassInfo(ValueType.arrayOf(
|
||||||
|
ValueType.object("java.lang.Enum"))).getStructure();
|
||||||
|
var clsStruct = context.classInfoProvider().getClassInfo("java.lang.Class").getStructure();
|
||||||
|
var cls = context.generate(invocation.getArguments().get(0));
|
||||||
|
var fieldIndex = context.classInfoProvider().getEnumConstantsFunctionOffset();
|
||||||
|
var functionRef = new WasmStructGet(clsStruct, cls, fieldIndex);
|
||||||
|
return new WasmCallReference(functionRef, context.functionTypes().of(enumArrayStruct.getReference()));
|
||||||
|
}
|
||||||
|
}
|
|
@ -39,6 +39,7 @@ public class WasmGCIntrinsics implements WasmGCIntrinsicProvider {
|
||||||
fillWasmRuntime();
|
fillWasmRuntime();
|
||||||
fillObject();
|
fillObject();
|
||||||
fillClass();
|
fillClass();
|
||||||
|
fillClassSupport();
|
||||||
fillSystem();
|
fillSystem();
|
||||||
fillLongAndInteger();
|
fillLongAndInteger();
|
||||||
fillFloat();
|
fillFloat();
|
||||||
|
@ -89,6 +90,13 @@ public class WasmGCIntrinsics implements WasmGCIntrinsicProvider {
|
||||||
add(new MethodReference(Class.class, "setSimpleNameCache", Class.class, String.class, void.class), intrinsic);
|
add(new MethodReference(Class.class, "setSimpleNameCache", Class.class, String.class, void.class), intrinsic);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void fillClassSupport() {
|
||||||
|
var intrinsic = new ClassSupportIntrinsic();
|
||||||
|
add(new MethodReference("org.teavm.classlib.impl.reflection.ClassSupport",
|
||||||
|
"getEnumConstants", ValueType.object("java.lang.Class"),
|
||||||
|
ValueType.arrayOf(ValueType.object("java.lang.Enum"))), intrinsic);
|
||||||
|
}
|
||||||
|
|
||||||
private void fillSystem() {
|
private void fillSystem() {
|
||||||
add(new MethodReference(System.class, "arraycopy", Object.class, int.class, Object.class,
|
add(new MethodReference(System.class, "arraycopy", Object.class, int.class, Object.class,
|
||||||
int.class, int.class, void.class), new SystemArrayCopyIntrinsic());
|
int.class, int.class, void.class), new SystemArrayCopyIntrinsic());
|
||||||
|
|
|
@ -35,7 +35,7 @@ public class WasmGCSupport {
|
||||||
return new ClassCastException();
|
return new ClassCastException();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void throwCloneNotSupportedException() throws CloneNotSupportedException {
|
public static Object defaultClone(Object value) throws CloneNotSupportedException {
|
||||||
throw new CloneNotSupportedException();
|
throw new CloneNotSupportedException();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -16,6 +16,7 @@
|
||||||
package org.teavm.model.analysis;
|
package org.teavm.model.analysis;
|
||||||
|
|
||||||
import java.lang.reflect.Array;
|
import java.lang.reflect.Array;
|
||||||
|
import java.util.Arrays;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import org.teavm.dependency.DependencyInfo;
|
import org.teavm.dependency.DependencyInfo;
|
||||||
|
@ -45,6 +46,7 @@ public class ClassMetadataRequirements {
|
||||||
private Map<ValueType, ClassInfo> requirements = new HashMap<>();
|
private Map<ValueType, ClassInfo> requirements = new HashMap<>();
|
||||||
private boolean hasArrayGet;
|
private boolean hasArrayGet;
|
||||||
private boolean hasArrayLength;
|
private boolean hasArrayLength;
|
||||||
|
private boolean hasEnumConstants;
|
||||||
|
|
||||||
public ClassMetadataRequirements(DependencyInfo dependencyInfo) {
|
public ClassMetadataRequirements(DependencyInfo dependencyInfo) {
|
||||||
MethodDependencyInfo getNameMethod = dependencyInfo.getMethod(GET_NAME_METHOD);
|
MethodDependencyInfo getNameMethod = dependencyInfo.getMethod(GET_NAME_METHOD);
|
||||||
|
@ -128,6 +130,22 @@ public class ClassMetadataRequirements {
|
||||||
requirements.computeIfAbsent(decodeType(className), k -> new ClassInfo()).cloneMethod = true;
|
requirements.computeIfAbsent(decodeType(className), k -> new ClassInfo()).cloneMethod = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var enumConstants = Arrays.asList(
|
||||||
|
dependencyInfo.getMethod(new MethodReference("org.teavm.platform.Platform", "getEnumConstants",
|
||||||
|
ValueType.object("org.teavm.platform.PlatformClass"), ValueType.parse(Enum[].class))),
|
||||||
|
dependencyInfo.getMethod(new MethodReference("org.teavm.classlib.impl.reflection.ClassSupport",
|
||||||
|
"getEnumConstants", ValueType.parse(Class.class), ValueType.parse(Enum[].class)))
|
||||||
|
);
|
||||||
|
for (var enumConstantsDep : enumConstants) {
|
||||||
|
if (enumConstantsDep != null) {
|
||||||
|
hasEnumConstants = true;
|
||||||
|
var classNames = enumConstantsDep.getVariable(1).getClassValueNode().getTypes();
|
||||||
|
for (var className : classNames) {
|
||||||
|
requirements.computeIfAbsent(decodeType(className), k -> new ClassInfo()).enumConstants = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public Info getInfo(String className) {
|
public Info getInfo(String className) {
|
||||||
|
@ -150,6 +168,10 @@ public class ClassMetadataRequirements {
|
||||||
return hasArrayLength;
|
return hasArrayLength;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean hasEnumConstants() {
|
||||||
|
return hasEnumConstants;
|
||||||
|
}
|
||||||
|
|
||||||
private void addClassesRequiringName(Map<ValueType, ClassInfo> target, String[] source) {
|
private void addClassesRequiringName(Map<ValueType, ClassInfo> target, String[] source) {
|
||||||
for (String typeName : source) {
|
for (String typeName : source) {
|
||||||
target.computeIfAbsent(decodeType(typeName), k -> new ClassInfo()).name = true;
|
target.computeIfAbsent(decodeType(typeName), k -> new ClassInfo()).name = true;
|
||||||
|
@ -177,6 +199,7 @@ public class ClassMetadataRequirements {
|
||||||
boolean arrayLength;
|
boolean arrayLength;
|
||||||
boolean arrayGet;
|
boolean arrayGet;
|
||||||
boolean cloneMethod;
|
boolean cloneMethod;
|
||||||
|
boolean enumConstants;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean name() {
|
public boolean name() {
|
||||||
|
@ -227,6 +250,11 @@ public class ClassMetadataRequirements {
|
||||||
public boolean cloneMethod() {
|
public boolean cloneMethod() {
|
||||||
return cloneMethod;
|
return cloneMethod;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean enumConstants() {
|
||||||
|
return enumConstants;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public interface Info {
|
public interface Info {
|
||||||
|
@ -249,5 +277,7 @@ public class ClassMetadataRequirements {
|
||||||
boolean arrayGet();
|
boolean arrayGet();
|
||||||
|
|
||||||
boolean cloneMethod();
|
boolean cloneMethod();
|
||||||
|
|
||||||
|
boolean enumConstants();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -46,7 +46,7 @@ public class EnumDependencySupport extends AbstractDependencyListener {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void methodReached(DependencyAgent agent, MethodDependency method) {
|
public void methodReached(DependencyAgent agent, MethodDependency method) {
|
||||||
if (method.getReference().getClassName().equals(Platform.class.getName())
|
if (isEnumSupportClass(method.getMethod().getOwnerName())
|
||||||
&& method.getReference().getName().equals("getEnumConstants")) {
|
&& method.getReference().getName().equals("getEnumConstants")) {
|
||||||
allEnums.connect(method.getResult().getArrayItem());
|
allEnums.connect(method.getResult().getArrayItem());
|
||||||
final MethodReference ref = method.getReference();
|
final MethodReference ref = method.getReference();
|
||||||
|
@ -66,4 +66,9 @@ public class EnumDependencySupport extends AbstractDependencyListener {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private boolean isEnumSupportClass(String className) {
|
||||||
|
return className.equals(Platform.class.getName())
|
||||||
|
|| className.endsWith("org.teavm.classlib.impl.reflection.ClassSupport");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user