WASM: add support for Enum.valueOf and Class.isEnum

This commit is contained in:
Alexey Andreev 2017-04-10 22:27:24 +03:00
parent d09affce85
commit 3ad16e80c7
6 changed files with 84 additions and 9 deletions

View File

@ -111,7 +111,7 @@ public class TClass<T> extends TObject implements TAnnotatedElement {
} }
public boolean isEnum() { public boolean isEnum() {
return platformClass.getMetadata().isEnum(); return Platform.isEnum(platformClass);
} }
public TClass<?> getComponentType() { public TClass<?> getComponentType() {

View File

@ -18,11 +18,6 @@ package org.teavm.classlib.java.lang;
import org.teavm.classlib.java.io.TSerializable; import org.teavm.classlib.java.io.TSerializable;
import org.teavm.interop.Rename; import org.teavm.interop.Rename;
/**
*
* @author Alexey Andreev
* @param <E> type of enum.
*/
public abstract class TEnum<E extends TEnum<E>> extends TObject implements TComparable<E>, TSerializable { public abstract class TEnum<E extends TEnum<E>> extends TObject implements TComparable<E>, TSerializable {
private TString name; private TString name;
private int ordinal; private int ordinal;

View File

@ -107,10 +107,8 @@ public class BinaryWriter {
public byte[] getData() { public byte[] getData() {
byte[] result = new byte[address]; byte[] result = new byte[address];
int offset = 0; int offset = 0;
int index = 0;
for (DataValue value : values) { for (DataValue value : values) {
offset = writeData(result, offset, value); offset = writeData(result, offset, value);
++index;
} }
return Arrays.copyOf(result, offset); return Arrays.copyOf(result, offset);
} }

View File

@ -73,6 +73,7 @@ public class WasmClassGenerator {
DataPrimitives.ADDRESS, /* array type */ DataPrimitives.ADDRESS, /* array type */
DataPrimitives.INT, /* isInstance function */ DataPrimitives.INT, /* isInstance function */
DataPrimitives.ADDRESS, /* parent */ DataPrimitives.ADDRESS, /* parent */
DataPrimitives.ADDRESS, /* enum values */
DataPrimitives.ADDRESS /* layout */); DataPrimitives.ADDRESS /* layout */);
private IntegerArray staticGcRoots = new IntegerArray(1); private IntegerArray staticGcRoots = new IntegerArray(1);
private int staticGcRootsAddress; private int staticGcRootsAddress;
@ -86,7 +87,8 @@ public class WasmClassGenerator {
private static final int CLASS_ARRAY_TYPE = 7; private static final int CLASS_ARRAY_TYPE = 7;
private static final int CLASS_IS_INSTANCE = 8; private static final int CLASS_IS_INSTANCE = 8;
private static final int CLASS_PARENT = 9; 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, public WasmClassGenerator(ClassReaderSource classSource, VirtualTableProvider vtableProvider,
TagRegistry tagRegistry, BinaryWriter binaryWriter) { TagRegistry tagRegistry, BinaryWriter binaryWriter) {
@ -193,6 +195,7 @@ public class WasmClassGenerator {
: 0; : 0;
String name = ((ValueType.Object) binaryData.type).getClassName(); String name = ((ValueType.Object) binaryData.type).getClassName();
int flags = 0;
VirtualTable vtable = vtableProvider.lookup(name); VirtualTable vtable = vtableProvider.lookup(name);
int vtableSize = vtable != null ? vtable.getEntries().size() : 0; int vtableSize = vtable != null ? vtable.getEntries().size() : 0;
@ -238,9 +241,34 @@ public class WasmClassGenerator {
staticGcRoots.add(binaryData.fieldLayout.get(field.getFieldName())); 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; 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<FieldReference> getReferenceFields(ClassReader cls) { private List<FieldReference> getReferenceFields(ClassReader cls) {
return cls.getFields().stream() return cls.getFields().stream()
.filter(field -> !field.hasModifier(ElementModifier.STATIC)) .filter(field -> !field.hasModifier(ElementModifier.STATIC))

View File

@ -21,6 +21,7 @@ import org.teavm.interop.Unmanaged;
public class RuntimeClass extends RuntimeJavaObject { public class RuntimeClass extends RuntimeJavaObject {
public static final int INITIALIZED = 1; public static final int INITIALIZED = 1;
public static final int PRIMITIVE = 2; public static final int PRIMITIVE = 2;
public static final int ENUM = 4;
public int size; public int size;
public int flags; public int flags;
@ -31,6 +32,7 @@ public class RuntimeClass extends RuntimeJavaObject {
public RuntimeClass arrayType; public RuntimeClass arrayType;
public IsSupertypeFunction isSupertypeOf; public IsSupertypeFunction isSupertypeOf;
public RuntimeClass parent; public RuntimeClass parent;
public Address enumValues;
public Address layout; public Address layout;
@Unmanaged @Unmanaged

View File

@ -19,7 +19,9 @@ import java.lang.annotation.Annotation;
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.dependency.PluggableDependency; import org.teavm.dependency.PluggableDependency;
import org.teavm.interop.Address;
import org.teavm.interop.DelegateTo; import org.teavm.interop.DelegateTo;
import org.teavm.interop.Unmanaged;
import org.teavm.jso.JSBody; import org.teavm.jso.JSBody;
import org.teavm.jso.JSObject; import org.teavm.jso.JSObject;
import org.teavm.jso.browser.Window; import org.teavm.jso.browser.Window;
@ -49,6 +51,7 @@ public final class Platform {
} }
@SuppressWarnings("unused") @SuppressWarnings("unused")
@Unmanaged
private static boolean isInstanceLowLevel(RuntimeClass self, RuntimeObject object) { private static boolean isInstanceLowLevel(RuntimeClass self, RuntimeObject object) {
return isAssignableLowLevel(RuntimeClass.getClass(object), self); return isAssignableLowLevel(RuntimeClass.getClass(object), self);
} }
@ -71,6 +74,7 @@ public final class Platform {
} }
@SuppressWarnings("unused") @SuppressWarnings("unused")
@Unmanaged
private static boolean isAssignableLowLevel(RuntimeClass from, RuntimeClass to) { private static boolean isAssignableLowLevel(RuntimeClass from, RuntimeClass to) {
return to.isSupertypeOf.apply(from); return to.isSupertypeOf.apply(from);
} }
@ -119,8 +123,44 @@ public final class Platform {
@GeneratedBy(PlatformGenerator.class) @GeneratedBy(PlatformGenerator.class)
@PluggableDependency(PlatformGenerator.class) @PluggableDependency(PlatformGenerator.class)
@DelegateTo("getEnumConstantsLowLevel")
public static native Enum<?>[] getEnumConstants(PlatformClass cls); 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) @GeneratedBy(PlatformGenerator.class)
@PluggableDependency(PlatformGenerator.class) @PluggableDependency(PlatformGenerator.class)
public static native Annotation[] getAnnotations(PlatformClass cls); public static native Annotation[] getAnnotations(PlatformClass cls);
@ -158,16 +198,28 @@ public final class Platform {
} }
@SuppressWarnings("unused") @SuppressWarnings("unused")
@Unmanaged
private static boolean isPrimitiveLowLevel(RuntimeClass cls) { private static boolean isPrimitiveLowLevel(RuntimeClass cls) {
return (cls.flags & RuntimeClass.PRIMITIVE) != 0; 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") @DelegateTo("getArrayItemLowLevel")
public static PlatformClass getArrayItem(PlatformClass cls) { public static PlatformClass getArrayItem(PlatformClass cls) {
return cls.getMetadata().getArrayItem(); return cls.getMetadata().getArrayItem();
} }
@SuppressWarnings("unused") @SuppressWarnings("unused")
@Unmanaged
private static RuntimeClass getArrayItemLowLevel(RuntimeClass cls) { private static RuntimeClass getArrayItemLowLevel(RuntimeClass cls) {
return cls.itemType; return cls.itemType;
} }