wasm/c: add support for class flags

This commit is contained in:
Alexey Andreev 2023-11-08 21:02:31 +01:00
parent 7ef7926519
commit 083ecbdad2
8 changed files with 73 additions and 15 deletions

View File

@ -740,12 +740,24 @@ public class ClassGenerator {
sizeExpr = "0"; sizeExpr = "0";
} }
if (cls != null) { if (cls != null) {
if (cls.hasModifier(ElementModifier.ENUM)) { if (cls.hasModifier(ElementModifier.ABSTRACT)) {
flags |= RuntimeClass.ENUM; flags |= RuntimeClass.ABSTRACT;
}
if (cls.hasModifier(ElementModifier.INTERFACE)) {
flags |= RuntimeClass.INTERFACE;
}
if (cls.hasModifier(ElementModifier.FINAL)) {
flags |= RuntimeClass.FINAL;
}
if (cls.hasModifier(ElementModifier.ANNOTATION)) {
flags |= RuntimeClass.ANNOTATION;
} }
if (cls.hasModifier(ElementModifier.SYNTHETIC)) { if (cls.hasModifier(ElementModifier.SYNTHETIC)) {
flags |= RuntimeClass.SYNTHETIC; flags |= RuntimeClass.SYNTHETIC;
} }
if (cls.hasModifier(ElementModifier.ENUM)) {
flags |= RuntimeClass.ENUM;
}
} }
List<TagRegistry.Range> ranges = tagRegistry != null ? tagRegistry.getRanges(className) : null; List<TagRegistry.Range> ranges = tagRegistry != null ? tagRegistry.getRanges(className) : null;
tag = !context.isIncremental() && ranges != null && !ranges.isEmpty() ? ranges.get(0).lower : 0; tag = !context.isIncremental() && ranges != null && !ranges.isEmpty() ? ranges.get(0).lower : 0;

View File

@ -45,6 +45,7 @@ public class PlatformClassIntrinsic implements Intrinsic {
break; break;
case "setJavaClass": case "setJavaClass":
break; break;
case "getFlags":
} }
} }
} }

View File

@ -34,6 +34,8 @@ public class PlatformClassMetadataIntrinsic implements Intrinsic {
RuntimeClass.class.getName(), "declaringClass"); RuntimeClass.class.getName(), "declaringClass");
private static final FieldReference ENCLOSING_CLASS_FIELD = new FieldReference( private static final FieldReference ENCLOSING_CLASS_FIELD = new FieldReference(
RuntimeClass.class.getName(), "enclosingClass"); RuntimeClass.class.getName(), "enclosingClass");
private static final FieldReference FLAGS_FIELD = new FieldReference(
RuntimeClass.class.getName(), "flags");
@Override @Override
public boolean canHandle(MethodReference method) { public boolean canHandle(MethodReference method) {
@ -47,6 +49,7 @@ public class PlatformClassMetadataIntrinsic implements Intrinsic {
case "getSimpleName": case "getSimpleName":
case "getDeclaringClass": case "getDeclaringClass":
case "getEnclosingClass": case "getEnclosingClass":
case "getFlags":
return true; return true;
} }
return false; return false;
@ -81,6 +84,11 @@ public class PlatformClassMetadataIntrinsic implements Intrinsic {
case "getEnclosingClass": case "getEnclosingClass":
printFieldAccess(context, invocation, ENCLOSING_CLASS_FIELD); printFieldAccess(context, invocation, ENCLOSING_CLASS_FIELD);
break; break;
case "getFlags":
context.writer().print("(");
printFieldAccess(context, invocation, FLAGS_FIELD);
context.writer().print(" >> " + RuntimeClass.FLAGS_SHIFT + ")");
break;
} }
} }

View File

@ -18,6 +18,10 @@ package org.teavm.backend.wasm.intrinsics;
import org.teavm.ast.InvocationExpr; import org.teavm.ast.InvocationExpr;
import org.teavm.ast.QualificationExpr; import org.teavm.ast.QualificationExpr;
import org.teavm.backend.wasm.model.expression.WasmExpression; import org.teavm.backend.wasm.model.expression.WasmExpression;
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.WasmUnreachable; import org.teavm.backend.wasm.model.expression.WasmUnreachable;
import org.teavm.model.FieldReference; import org.teavm.model.FieldReference;
import org.teavm.model.MethodReference; import org.teavm.model.MethodReference;
@ -32,6 +36,7 @@ public class PlatformClassMetadataIntrinsic implements WasmIntrinsic {
private static final FieldReference SIMPLE_NAME_FIELD = new FieldReference(RUNTIME_CLASS, "simpleName"); private static final FieldReference SIMPLE_NAME_FIELD = new FieldReference(RUNTIME_CLASS, "simpleName");
private static final FieldReference ENCLOSING_CLASS_FIELD = new FieldReference(RUNTIME_CLASS, "enclosingClass"); private static final FieldReference ENCLOSING_CLASS_FIELD = new FieldReference(RUNTIME_CLASS, "enclosingClass");
private static final FieldReference DECLARING_CLASS_FIELD = new FieldReference(RUNTIME_CLASS, "declaringClass"); private static final FieldReference DECLARING_CLASS_FIELD = new FieldReference(RUNTIME_CLASS, "declaringClass");
private static final FieldReference FLAGS_FIELD = new FieldReference(RUNTIME_CLASS, "flags");
@Override @Override
public boolean isApplicable(MethodReference methodReference) { public boolean isApplicable(MethodReference methodReference) {
@ -45,6 +50,7 @@ public class PlatformClassMetadataIntrinsic implements WasmIntrinsic {
case "getSimpleName": case "getSimpleName":
case "getEnclosingClass": case "getEnclosingClass":
case "getDeclaringClass": case "getDeclaringClass":
case "getFlags":
return true; return true;
} }
return false; return false;
@ -65,6 +71,11 @@ public class PlatformClassMetadataIntrinsic implements WasmIntrinsic {
return fieldAccess(manager, invocation, ENCLOSING_CLASS_FIELD); return fieldAccess(manager, invocation, ENCLOSING_CLASS_FIELD);
case "getDeclaringClass": case "getDeclaringClass":
return fieldAccess(manager, invocation, DECLARING_CLASS_FIELD); return fieldAccess(manager, invocation, DECLARING_CLASS_FIELD);
case "getFlags": {
var flags = fieldAccess(manager, invocation, FLAGS_FIELD);
return new WasmIntBinary(WasmIntType.INT32, WasmIntBinaryOperation.SHR_UNSIGNED, flags,
new WasmInt32Constant(RuntimeClass.FLAGS_SHIFT));
}
default: default:
return new WasmUnreachable(); return new WasmUnreachable();
} }

View File

@ -21,14 +21,29 @@ import org.teavm.interop.Unmanaged;
public class RuntimeClass extends RuntimeObject { public class RuntimeClass extends RuntimeObject {
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 static final int SYNTHETIC = 1024;
public static final int PRIMITIVE_SHIFT = 3; public static final int PRIMITIVE_SHIFT = 2;
public static final int PRIMITIVE_MASK = 15; public static final int PRIMITIVE_MASK = 15;
public static final int VM_TYPE_SHIFT = 7; public static final int VM_TYPE_SHIFT = 6;
public static final int VM_TYPE_MASK = 7; public static final int VM_TYPE_MASK = 7;
public static final int FLAGS_SHIFT = 9;
public static final int ABSTRACT = 1 << FLAGS_SHIFT;
public static final int INTERFACE = 1 << (FLAGS_SHIFT + 1);
public static final int FINAL = 1 << (FLAGS_SHIFT + 2);
public static final int ENUM = 1 << (FLAGS_SHIFT + 3);
public static final int ANNOTATION = 1 << (FLAGS_SHIFT + 4);
public static final int SYNTHETIC = 1 << (FLAGS_SHIFT + 5);
public static final int BRIDGE = 1 << (FLAGS_SHIFT + 6);
public static final int DEPRECATED = 1 << (FLAGS_SHIFT + 7);
public static final int NATIVE = 1 << (FLAGS_SHIFT + 8);
public static final int STATIC = 1 << (FLAGS_SHIFT + 9);
public static final int STRICT = 1 << (FLAGS_SHIFT + 10);
public static final int SYNCHRONIZED = 1 << (FLAGS_SHIFT + 11);
public static final int TRANSIENT = 1 << (FLAGS_SHIFT + 12);
public static final int VARARGS = 1 << (FLAGS_SHIFT + 13);
public static final int VOLATILE = 1 << (FLAGS_SHIFT + 14);
public static final int BOOLEAN_PRIMITIVE = 0; public static final int BOOLEAN_PRIMITIVE = 0;
public static final int BYTE_PRIMITIVE = 1; public static final int BYTE_PRIMITIVE = 1;
public static final int SHORT_PRIMITIVE = 2; public static final int SHORT_PRIMITIVE = 2;

View File

@ -32,7 +32,6 @@ import org.teavm.junit.TeaVMTestRunner;
import org.teavm.junit.TestPlatform; import org.teavm.junit.TestPlatform;
@RunWith(TeaVMTestRunner.class) @RunWith(TeaVMTestRunner.class)
@SkipPlatform({TestPlatform.C, TestPlatform.WEBASSEMBLY, TestPlatform.WASI})
public class ClassTest { public class ClassTest {
@Test @Test
public void classNameEvaluated() { public void classNameEvaluated() {
@ -115,6 +114,7 @@ public class ClassTest {
} }
@Test @Test
@SkipPlatform({TestPlatform.C, TestPlatform.WEBASSEMBLY, TestPlatform.WASI})
public void instanceCreatedThroughReflection() throws Exception { public void instanceCreatedThroughReflection() throws Exception {
Runnable instance = (Runnable) Class.forName(TestObject.class.getName()).newInstance(); Runnable instance = (Runnable) Class.forName(TestObject.class.getName()).newInstance();
instance.run(); instance.run();
@ -123,6 +123,7 @@ public class ClassTest {
} }
@Test @Test
@SkipPlatform({TestPlatform.C, TestPlatform.WEBASSEMBLY, TestPlatform.WASI})
public void instanceCreatedThoughReflectionWithConstantName() throws Exception { public void instanceCreatedThoughReflectionWithConstantName() throws Exception {
var cls = Class.forName("org.teavm.classlib.java.lang.ClassTest$ClassReferredByConstantName"); var cls = Class.forName("org.teavm.classlib.java.lang.ClassTest$ClassReferredByConstantName");
assertArrayEquals(new Class<?>[] { Supplier.class }, cls.getInterfaces()); assertArrayEquals(new Class<?>[] { Supplier.class }, cls.getInterfaces());
@ -137,6 +138,7 @@ public class ClassTest {
} }
@Test @Test
@SkipPlatform({TestPlatform.C, TestPlatform.WEBASSEMBLY, TestPlatform.WASI})
public void instanceCreatedThroughReflectionAsync() throws Exception { public void instanceCreatedThroughReflectionAsync() throws Exception {
Runnable instance = TestObjectAsync.class.newInstance(); Runnable instance = TestObjectAsync.class.newInstance();
instance.run(); instance.run();
@ -178,6 +180,7 @@ public class ClassTest {
} }
@Test @Test
@SkipPlatform({TestPlatform.C, TestPlatform.WEBASSEMBLY})
public void annotationsExposed() { public void annotationsExposed() {
Annotation[] annotations = A.class.getAnnotations(); Annotation[] annotations = A.class.getAnnotations();
assertEquals(1, annotations.length); assertEquals(1, annotations.length);
@ -185,6 +188,7 @@ public class ClassTest {
} }
@Test @Test
@SkipPlatform({TestPlatform.C, TestPlatform.WEBASSEMBLY})
public void annotationFieldsExposed() { public void annotationFieldsExposed() {
AnnotWithDefaultField annot = B.class.getAnnotation(AnnotWithDefaultField.class); AnnotWithDefaultField annot = B.class.getAnnotation(AnnotWithDefaultField.class);
assertEquals(2, annot.x()); assertEquals(2, annot.x());
@ -193,6 +197,7 @@ public class ClassTest {
} }
@Test @Test
@SkipPlatform({TestPlatform.C, TestPlatform.WEBASSEMBLY})
public void annotationFieldTypesSupported() { public void annotationFieldTypesSupported() {
AnnotWithVariousFields annot = D.class.getAnnotation(AnnotWithVariousFields.class); AnnotWithVariousFields annot = D.class.getAnnotation(AnnotWithVariousFields.class);
assertEquals(true, annot.a()); assertEquals(true, annot.a());
@ -213,6 +218,7 @@ public class ClassTest {
} }
@Test @Test
@SkipPlatform({TestPlatform.C, TestPlatform.WEBASSEMBLY})
public void getInterfaces() { public void getInterfaces() {
assertEquals(0, SuperclassWithoutInterfaces.class.getInterfaces().length); assertEquals(0, SuperclassWithoutInterfaces.class.getInterfaces().length);
assertEquals(Set.of(TestInterface1.class, TestInterface2.class), assertEquals(Set.of(TestInterface1.class, TestInterface2.class),

View File

@ -36,9 +36,7 @@ import java.util.Objects;
import java.util.Set; import java.util.Set;
import org.junit.Test; import org.junit.Test;
import org.junit.runner.RunWith; import org.junit.runner.RunWith;
import org.teavm.junit.SkipPlatform;
import org.teavm.junit.TeaVMTestRunner; import org.teavm.junit.TeaVMTestRunner;
import org.teavm.junit.TestPlatform;
@RunWith(TeaVMTestRunner.class) @RunWith(TeaVMTestRunner.class)
public class EnumMapTest { public class EnumMapTest {
@ -295,7 +293,6 @@ public class EnumMapTest {
@Test @Test
@SuppressWarnings({ "unchecked", "rawtypes" }) @SuppressWarnings({ "unchecked", "rawtypes" })
@SkipPlatform({TestPlatform.WEBASSEMBLY, TestPlatform.WASI})
public void putAll() { public void putAll() {
EnumMap enumColorMap = new EnumMap(Color.class); EnumMap enumColorMap = new EnumMap(Color.class);
enumColorMap.put(Color.Green, 2); enumColorMap.put(Color.Green, 2);

View File

@ -15,13 +15,22 @@
*/ */
package org.teavm.classlib.java.util; package org.teavm.classlib.java.util;
import static org.junit.Assert.*; import static org.junit.Assert.assertEquals;
import java.util.*; import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotSame;
import static org.junit.Assert.assertSame;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.EnumSet;
import java.util.Iterator;
import java.util.List;
import java.util.NoSuchElementException;
import java.util.Set;
import org.junit.Test; import org.junit.Test;
import org.junit.runner.RunWith; import org.junit.runner.RunWith;
import org.teavm.junit.SkipPlatform;
import org.teavm.junit.TeaVMTestRunner; import org.teavm.junit.TeaVMTestRunner;
import org.teavm.junit.TestPlatform;
@RunWith(TeaVMTestRunner.class) @RunWith(TeaVMTestRunner.class)
public class EnumSetTest { public class EnumSetTest {
@ -199,7 +208,6 @@ public class EnumSetTest {
} }
@Test @Test
@SkipPlatform({ TestPlatform.WEBASSEMBLY, TestPlatform.WASI })
public void iterator() { public void iterator() {
Set<EnumFoo> set = EnumSet.noneOf(EnumFoo.class); Set<EnumFoo> set = EnumSet.noneOf(EnumFoo.class);
set.add(EnumFoo.a); set.add(EnumFoo.a);