wasm gc: fix issues related to class metadata

This commit is contained in:
Alexey Andreev 2024-09-11 15:45:37 +02:00
parent 1533794cf1
commit d12637f959
7 changed files with 29 additions and 13 deletions

View File

@ -46,7 +46,9 @@ import org.teavm.dependency.PluggableDependency;
import org.teavm.interop.Address; import org.teavm.interop.Address;
import org.teavm.interop.DelegateTo; import org.teavm.interop.DelegateTo;
import org.teavm.interop.NoSideEffects; import org.teavm.interop.NoSideEffects;
import org.teavm.interop.Platforms;
import org.teavm.interop.Unmanaged; import org.teavm.interop.Unmanaged;
import org.teavm.interop.UnsupportedOn;
import org.teavm.jso.core.JSArray; import org.teavm.jso.core.JSArray;
import org.teavm.platform.Platform; import org.teavm.platform.Platform;
import org.teavm.platform.PlatformClass; import org.teavm.platform.PlatformClass;
@ -99,6 +101,7 @@ public final class TClass<T> extends TObject implements TAnnotatedElement, TType
} }
@DelegateTo("isInstanceLowLevel") @DelegateTo("isInstanceLowLevel")
@UnsupportedOn(Platforms.WEBASSEMBLY_GC)
public boolean isInstance(TObject obj) { public boolean isInstance(TObject obj) {
return Platform.isInstance(Platform.getPlatformObject(obj), platformClass); return Platform.isInstance(Platform.getPlatformObject(obj), platformClass);
} }
@ -109,6 +112,7 @@ public final class TClass<T> extends TObject implements TAnnotatedElement, TType
} }
@DelegateTo("isAssignableFromLowLevel") @DelegateTo("isAssignableFromLowLevel")
@UnsupportedOn(Platforms.WEBASSEMBLY_GC)
public boolean isAssignableFrom(TClass<?> obj) { public boolean isAssignableFrom(TClass<?> obj) {
return Platform.isAssignable(obj.getPlatformClass(), platformClass); return Platform.isAssignable(obj.getPlatformClass(), platformClass);
} }

View File

@ -919,6 +919,10 @@ public class WasmGCClassGenerator implements WasmGCClassInfoProvider, WasmGCInit
cloneFunction.setReferenced(true); cloneFunction.setReferenced(true);
target.add(setClassField(classInfo, cloneOffset, new WasmFunctionReference(cloneFunction))); target.add(setClassField(classInfo, cloneOffset, new WasmFunctionReference(cloneFunction)));
} }
if (metadataReq.name() && type.getItemType() instanceof ValueType.Primitive) {
var name = strings.getStringConstant(type.toString());
target.add(setClassField(classInfo, classNameOffset, new WasmGetGlobal(name.global)));
}
}; };
} }
@ -1062,7 +1066,7 @@ public class WasmGCClassGenerator implements WasmGCClassInfoProvider, WasmGCInit
fields.add(createClassField(newArrayGenerator.getNewArrayFunctionType().getReference().asStorage(), fields.add(createClassField(newArrayGenerator.getNewArrayFunctionType().getReference().asStorage(),
"createArrayInstance")); "createArrayInstance"));
classEnclosingClassOffset = fields.size(); classEnclosingClassOffset = fields.size();
fields.add(createClassField(standardClasses.stringClass().getType().asStorage(), "enclosingClass")); fields.add(createClassField(standardClasses.classClass().getType().asStorage(), "enclosingClass"));
classNameOffset = fields.size(); classNameOffset = fields.size();
fields.add(createClassField(standardClasses.stringClass().getType().asStorage(), "name")); fields.add(createClassField(standardClasses.stringClass().getType().asStorage(), "name"));
classSimpleNameOffset = fields.size(); classSimpleNameOffset = fields.size();

View File

@ -50,7 +50,7 @@ public class ClassGenerators implements WasmGCCustomGenerator {
function.add(objectVar); function.add(objectVar);
var conditional = new WasmConditional(new WasmReferencesEqual(new WasmGetLocal(objectVar), var conditional = new WasmConditional(new WasmReferencesEqual(new WasmGetLocal(objectVar),
new WasmNullConstant(WasmType.Reference.ANY))); new WasmNullConstant(WasmType.Reference.STRUCT)));
conditional.setType(WasmType.INT32); conditional.setType(WasmType.INT32);
conditional.getThenBlock().getBody().add(new WasmInt32Constant(0)); conditional.getThenBlock().getBody().add(new WasmInt32Constant(0));

View File

@ -477,7 +477,8 @@ class DependencyGraphBuilder {
if (cls != null && cls.getParent() != null) { if (cls != null && cls.getParent() != null) {
receiverNode.getClassValueNode().propagate(dependencyAnalyzer.getType(cls.getParent())); receiverNode.getClassValueNode().propagate(dependencyAnalyzer.getType(cls.getParent()));
} }
methodDep.getVariable(0).propagate(type); methodDep.getVariable(0).getClassValueNode().propagate(type);
methodDep.getVariable(0).propagate(dependencyAnalyzer.getType("java.lang.Class"));
}); });
} }

View File

@ -69,7 +69,7 @@ public class ClassMetadataRequirements {
if (getSuperclassMethod != null) { if (getSuperclassMethod != null) {
var classNames = getSuperclassMethod.getVariable(0).getClassValueNode().getTypes(); var classNames = getSuperclassMethod.getVariable(0).getClassValueNode().getTypes();
for (var className : classNames) { for (var className : classNames) {
requirements.computeIfAbsent(decodeType(className), k -> new ClassInfo()).declaringClass = true; requirements.computeIfAbsent(decodeType(className), k -> new ClassInfo()).superclass = true;
} }
} }

View File

@ -103,19 +103,21 @@ public class ClassTest {
} }
@Test @Test
@SkipPlatform(TestPlatform.WEBASSEMBLY_GC)
public void castingAppropriateObject() { public void castingAppropriateObject() {
Object obj = 23; Object obj = 23;
assertEquals(Integer.valueOf(23), Integer.class.cast(obj)); assertEquals(Integer.valueOf(23), Integer.class.cast(obj));
} }
@Test(expected = ClassCastException.class) @Test(expected = ClassCastException.class)
@SkipPlatform(TestPlatform.WEBASSEMBLY_GC)
public void inappropriateObjectCastingFails() { public void inappropriateObjectCastingFails() {
Object obj = 23; Object obj = 23;
Float.class.cast(obj); Float.class.cast(obj);
} }
@Test @Test
@SkipPlatform({TestPlatform.C, TestPlatform.WEBASSEMBLY, TestPlatform.WASI}) @SkipPlatform({TestPlatform.C, TestPlatform.WEBASSEMBLY, TestPlatform.WASI, TestPlatform.WEBASSEMBLY_GC})
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();
@ -124,7 +126,7 @@ public class ClassTest {
} }
@Test @Test
@SkipPlatform({TestPlatform.C, TestPlatform.WEBASSEMBLY, TestPlatform.WASI}) @SkipPlatform({TestPlatform.C, TestPlatform.WEBASSEMBLY, TestPlatform.WASI, TestPlatform.WEBASSEMBLY_GC})
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());
@ -139,7 +141,7 @@ public class ClassTest {
} }
@Test @Test
@SkipPlatform({TestPlatform.C, TestPlatform.WEBASSEMBLY, TestPlatform.WASI}) @SkipPlatform({TestPlatform.C, TestPlatform.WEBASSEMBLY, TestPlatform.WASI, TestPlatform.WEBASSEMBLY_GC})
public void instanceCreatedThroughReflectionAsync() throws Exception { public void instanceCreatedThroughReflectionAsync() throws Exception {
Runnable instance = TestObjectAsync.class.newInstance(); Runnable instance = TestObjectAsync.class.newInstance();
instance.run(); instance.run();
@ -148,6 +150,7 @@ public class ClassTest {
} }
@Test @Test
@SkipPlatform(TestPlatform.WEBASSEMBLY_GC)
public void classProperties() { public void classProperties() {
class B { class B {
} }
@ -181,14 +184,14 @@ public class ClassTest {
} }
@Test @Test
@SkipPlatform({TestPlatform.C, TestPlatform.WEBASSEMBLY, TestPlatform.WASI}) @SkipPlatform({TestPlatform.C, TestPlatform.WEBASSEMBLY, TestPlatform.WASI, TestPlatform.WEBASSEMBLY_GC})
public void annotationsExposed() { public void annotationsExposed() {
var annotations = A.class.getAnnotations(); var annotations = A.class.getAnnotations();
assertTrue(Stream.of(annotations).anyMatch(a -> a instanceof TestAnnot)); assertTrue(Stream.of(annotations).anyMatch(a -> a instanceof TestAnnot));
} }
@Test @Test
@SkipPlatform({TestPlatform.C, TestPlatform.WEBASSEMBLY, TestPlatform.WASI}) @SkipPlatform({TestPlatform.C, TestPlatform.WEBASSEMBLY, TestPlatform.WASI, TestPlatform.WEBASSEMBLY_GC})
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());
@ -197,7 +200,7 @@ public class ClassTest {
} }
@Test @Test
@SkipPlatform({TestPlatform.C, TestPlatform.WEBASSEMBLY, TestPlatform.WASI}) @SkipPlatform({TestPlatform.C, TestPlatform.WEBASSEMBLY, TestPlatform.WASI, TestPlatform.WEBASSEMBLY_GC})
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());
@ -218,7 +221,7 @@ public class ClassTest {
} }
@Test @Test
@SkipPlatform({TestPlatform.C, TestPlatform.WEBASSEMBLY, TestPlatform.WASI}) @SkipPlatform({TestPlatform.C, TestPlatform.WEBASSEMBLY, TestPlatform.WASI, TestPlatform.WEBASSEMBLY_GC})
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),
@ -226,7 +229,7 @@ public class ClassTest {
} }
@Test @Test
@SkipPlatform({TestPlatform.C, TestPlatform.WEBASSEMBLY, TestPlatform.WASI}) @SkipPlatform({TestPlatform.C, TestPlatform.WEBASSEMBLY, TestPlatform.WASI, TestPlatform.WEBASSEMBLY_GC})
public void inheritedAnnotation() { public void inheritedAnnotation() {
assertTrue(A.class.isAnnotationPresent(InheritedAnnot.class)); assertTrue(A.class.isAnnotationPresent(InheritedAnnot.class));
assertTrue(A.class.isAnnotationPresent(TestAnnot.class)); assertTrue(A.class.isAnnotationPresent(TestAnnot.class));

View File

@ -23,6 +23,7 @@
<body> <body>
<script type="text/javascript" src="${SCRIPT}-runtime.js"></script> <script type="text/javascript" src="${SCRIPT}-runtime.js"></script>
<script type="text/javascript"> <script type="text/javascript">
let instance;
TeaVM.wasm.load("${SCRIPT}", { TeaVM.wasm.load("${SCRIPT}", {
installImports(o) { installImports(o) {
o.teavmTest = { o.teavmTest = {
@ -43,7 +44,10 @@
} }
}; };
} }
}).then(teavm => teavm.main(["${IDENTIFIER}"])); }).then(teavm => {
instance = teavm.instance;
teavm.main(["${IDENTIFIER}"])
});
</script> </script>
</body> </body>
</html> </html>