diff --git a/classlib/src/main/java/org/teavm/classlib/java/lang/TClass.java b/classlib/src/main/java/org/teavm/classlib/java/lang/TClass.java index 0b148e178..8243bcb6c 100644 --- a/classlib/src/main/java/org/teavm/classlib/java/lang/TClass.java +++ b/classlib/src/main/java/org/teavm/classlib/java/lang/TClass.java @@ -111,7 +111,7 @@ public class TClass extends TObject implements TAnnotatedElement { } public boolean isEnum() { - return platformClass.getMetadata().isEnum(); + return Platform.isEnum(platformClass); } public TClass getComponentType() { diff --git a/classlib/src/main/java/org/teavm/classlib/java/lang/TEnum.java b/classlib/src/main/java/org/teavm/classlib/java/lang/TEnum.java index 0eecf3240..e77639fc9 100644 --- a/classlib/src/main/java/org/teavm/classlib/java/lang/TEnum.java +++ b/classlib/src/main/java/org/teavm/classlib/java/lang/TEnum.java @@ -18,11 +18,6 @@ package org.teavm.classlib.java.lang; import org.teavm.classlib.java.io.TSerializable; import org.teavm.interop.Rename; -/** - * - * @author Alexey Andreev - * @param type of enum. - */ public abstract class TEnum> extends TObject implements TComparable, TSerializable { private TString name; private int ordinal; diff --git a/core/src/main/java/org/teavm/backend/wasm/binary/BinaryWriter.java b/core/src/main/java/org/teavm/backend/wasm/binary/BinaryWriter.java index e67f0c3d6..79a089a03 100644 --- a/core/src/main/java/org/teavm/backend/wasm/binary/BinaryWriter.java +++ b/core/src/main/java/org/teavm/backend/wasm/binary/BinaryWriter.java @@ -107,10 +107,8 @@ public class BinaryWriter { public byte[] getData() { byte[] result = new byte[address]; int offset = 0; - int index = 0; for (DataValue value : values) { offset = writeData(result, offset, value); - ++index; } return Arrays.copyOf(result, offset); } diff --git a/core/src/main/java/org/teavm/backend/wasm/generate/WasmClassGenerator.java b/core/src/main/java/org/teavm/backend/wasm/generate/WasmClassGenerator.java index 164941abe..7b3a2b1a9 100644 --- a/core/src/main/java/org/teavm/backend/wasm/generate/WasmClassGenerator.java +++ b/core/src/main/java/org/teavm/backend/wasm/generate/WasmClassGenerator.java @@ -73,6 +73,7 @@ public class WasmClassGenerator { DataPrimitives.ADDRESS, /* array type */ DataPrimitives.INT, /* isInstance function */ DataPrimitives.ADDRESS, /* parent */ + DataPrimitives.ADDRESS, /* enum values */ DataPrimitives.ADDRESS /* layout */); private IntegerArray staticGcRoots = new IntegerArray(1); private int staticGcRootsAddress; @@ -86,7 +87,8 @@ public class WasmClassGenerator { private static final int CLASS_ARRAY_TYPE = 7; private static final int CLASS_IS_INSTANCE = 8; private static final int CLASS_PARENT = 9; - private static final int CLASS_LAYOUT = 10; + private static final int CLASS_ENUM_VALUES = 10; + private static final int CLASS_LAYOUT = 11; public WasmClassGenerator(ClassReaderSource classSource, VirtualTableProvider vtableProvider, TagRegistry tagRegistry, BinaryWriter binaryWriter) { @@ -193,6 +195,7 @@ public class WasmClassGenerator { : 0; String name = ((ValueType.Object) binaryData.type).getClassName(); + int flags = 0; VirtualTable vtable = vtableProvider.lookup(name); int vtableSize = vtable != null ? vtable.getEntries().size() : 0; @@ -238,9 +241,34 @@ public class WasmClassGenerator { staticGcRoots.add(binaryData.fieldLayout.get(field.getFieldName())); } + ClassReader cls = classSource.get(name); + if (cls != null && cls.hasModifier(ElementModifier.ENUM)) { + header.setAddress(CLASS_ENUM_VALUES, generateEnumValues(cls, binaryData)); + flags |= RuntimeClass.ENUM; + } + + header.setInt(CLASS_FLAGS, flags); + return vtable != null ? wrapper : header; } + private int generateEnumValues(ClassReader cls, ClassBinaryData binaryData) { + FieldReader[] fields = cls.getFields().stream() + .filter(field -> field.hasModifier(ElementModifier.ENUM)) + .toArray(FieldReader[]::new); + DataValue sizeValue = DataPrimitives.ADDRESS.createValue(); + sizeValue.setAddress(0, fields.length); + int valuesAddress = binaryWriter.append(sizeValue); + + for (FieldReader field : fields) { + DataValue fieldRefValue = DataPrimitives.ADDRESS.createValue(); + fieldRefValue.setAddress(0, binaryData.fieldLayout.get(field.getName())); + binaryWriter.append(fieldRefValue); + } + + return valuesAddress; + } + private List getReferenceFields(ClassReader cls) { return cls.getFields().stream() .filter(field -> !field.hasModifier(ElementModifier.STATIC)) diff --git a/core/src/main/java/org/teavm/runtime/RuntimeClass.java b/core/src/main/java/org/teavm/runtime/RuntimeClass.java index 67f092298..5a44da28b 100644 --- a/core/src/main/java/org/teavm/runtime/RuntimeClass.java +++ b/core/src/main/java/org/teavm/runtime/RuntimeClass.java @@ -21,6 +21,7 @@ import org.teavm.interop.Unmanaged; public class RuntimeClass extends RuntimeJavaObject { public static final int INITIALIZED = 1; public static final int PRIMITIVE = 2; + public static final int ENUM = 4; public int size; public int flags; @@ -31,6 +32,7 @@ public class RuntimeClass extends RuntimeJavaObject { public RuntimeClass arrayType; public IsSupertypeFunction isSupertypeOf; public RuntimeClass parent; + public Address enumValues; public Address layout; @Unmanaged diff --git a/platform/src/main/java/org/teavm/platform/Platform.java b/platform/src/main/java/org/teavm/platform/Platform.java index 854436780..91a6e3b37 100644 --- a/platform/src/main/java/org/teavm/platform/Platform.java +++ b/platform/src/main/java/org/teavm/platform/Platform.java @@ -19,7 +19,9 @@ import java.lang.annotation.Annotation; import org.teavm.backend.javascript.spi.GeneratedBy; import org.teavm.backend.javascript.spi.InjectedBy; import org.teavm.dependency.PluggableDependency; +import org.teavm.interop.Address; import org.teavm.interop.DelegateTo; +import org.teavm.interop.Unmanaged; import org.teavm.jso.JSBody; import org.teavm.jso.JSObject; import org.teavm.jso.browser.Window; @@ -49,6 +51,7 @@ public final class Platform { } @SuppressWarnings("unused") + @Unmanaged private static boolean isInstanceLowLevel(RuntimeClass self, RuntimeObject object) { return isAssignableLowLevel(RuntimeClass.getClass(object), self); } @@ -71,6 +74,7 @@ public final class Platform { } @SuppressWarnings("unused") + @Unmanaged private static boolean isAssignableLowLevel(RuntimeClass from, RuntimeClass to) { return to.isSupertypeOf.apply(from); } @@ -119,8 +123,44 @@ public final class Platform { @GeneratedBy(PlatformGenerator.class) @PluggableDependency(PlatformGenerator.class) + @DelegateTo("getEnumConstantsLowLevel") public static native Enum[] getEnumConstants(PlatformClass cls); + private static Enum[] getEnumConstantsLowLevel(PlatformClass cls) { + int size = getEnumConstantsSize(cls); + if (size < 0) { + return null; + } + + Enum[] constants = new Enum[size]; + fillEnumConstants(cls, constants); + return constants; + } + + @DelegateTo("getEnumConstantsSizeImpl") + private static native int getEnumConstantsSize(PlatformClass cls); + + @Unmanaged + private static int getEnumConstantsSizeImpl(RuntimeClass cls) { + Address enumValues = cls.enumValues; + if (enumValues == null) { + return -1; + } + return enumValues.getAddress().toInt(); + } + + @DelegateTo("fillEnumConstantsImpl") + private static native void fillEnumConstants(PlatformClass cls, Enum[] array); + + @Unmanaged + private static void fillEnumConstantsImpl(RuntimeClass cls, Address[] array) { + Address enumValues = cls.enumValues; + for (int i = 0; i < array.length; i++) { + enumValues = enumValues.add(Address.sizeOf()); + array[i] = enumValues.getAddress().getAddress(); + } + } + @GeneratedBy(PlatformGenerator.class) @PluggableDependency(PlatformGenerator.class) public static native Annotation[] getAnnotations(PlatformClass cls); @@ -158,16 +198,28 @@ public final class Platform { } @SuppressWarnings("unused") + @Unmanaged private static boolean isPrimitiveLowLevel(RuntimeClass cls) { return (cls.flags & RuntimeClass.PRIMITIVE) != 0; } + @DelegateTo("isEnumLowLevel") + public static boolean isEnum(PlatformClass cls) { + return cls.getMetadata().isEnum(); + } + + @Unmanaged + private static boolean isEnumLowLevel(RuntimeClass cls) { + return (cls.flags & RuntimeClass.ENUM) != 0; + } + @DelegateTo("getArrayItemLowLevel") public static PlatformClass getArrayItem(PlatformClass cls) { return cls.getMetadata().getArrayItem(); } @SuppressWarnings("unused") + @Unmanaged private static RuntimeClass getArrayItemLowLevel(RuntimeClass cls) { return cls.itemType; }