wasm gc: fix bugs with Class

This commit is contained in:
Alexey Andreev 2024-09-11 20:07:05 +02:00
parent d12637f959
commit eccfaff889
12 changed files with 114 additions and 31 deletions

View File

@ -46,9 +46,7 @@ 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;
@ -101,8 +99,10 @@ 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) {
if (PlatformDetector.isWebAssemblyGC()) {
return obj != null && isAssignableFrom((TClass<?>) (Object) obj.getClass());
}
return Platform.isInstance(Platform.getPlatformObject(obj), platformClass); return Platform.isInstance(Platform.getPlatformObject(obj), platformClass);
} }
@ -112,7 +112,6 @@ 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);
} }
@ -268,7 +267,9 @@ public final class TClass<T> extends TObject implements TAnnotatedElement, TType
} }
private boolean isSynthetic() { private boolean isSynthetic() {
if (PlatformDetector.isJavaScript()) { if (PlatformDetector.isWebAssemblyGC()) {
return (getWasmGCFlags() & WasmGCClassFlags.SYNTHETIC) != 0;
} else if (PlatformDetector.isJavaScript()) {
return (platformClass.getMetadata().getAccessLevel() & Flags.SYNTHETIC) != 0; return (platformClass.getMetadata().getAccessLevel() & Flags.SYNTHETIC) != 0;
} else { } else {
return (RuntimeClass.getClass(Address.ofObject(this).toStructure()).flags & RuntimeClass.SYNTHETIC) != 0; return (RuntimeClass.getClass(Address.ofObject(this).toStructure()).flags & RuntimeClass.SYNTHETIC) != 0;

View File

@ -92,6 +92,8 @@ import org.teavm.backend.wasm.model.expression.WasmInt64Constant;
import org.teavm.backend.wasm.model.expression.WasmIntBinary; import org.teavm.backend.wasm.model.expression.WasmIntBinary;
import org.teavm.backend.wasm.model.expression.WasmIntBinaryOperation; import org.teavm.backend.wasm.model.expression.WasmIntBinaryOperation;
import org.teavm.backend.wasm.model.expression.WasmIntType; import org.teavm.backend.wasm.model.expression.WasmIntType;
import org.teavm.backend.wasm.model.expression.WasmIntUnary;
import org.teavm.backend.wasm.model.expression.WasmIntUnaryOperation;
import org.teavm.backend.wasm.model.expression.WasmReturn; import org.teavm.backend.wasm.model.expression.WasmReturn;
import org.teavm.backend.wasm.model.expression.WasmSetLocal; import org.teavm.backend.wasm.model.expression.WasmSetLocal;
import org.teavm.backend.wasm.model.expression.WasmSwitch; import org.teavm.backend.wasm.model.expression.WasmSwitch;
@ -1446,7 +1448,7 @@ public abstract class BaseWasmGenerationVisitor implements StatementVisitor, Exp
} }
} }
var result = new WasmIntBinary(WasmIntType.INT32, WasmIntBinaryOperation.EQ, expr, new WasmInt32Constant(0)); var result = new WasmIntUnary(WasmIntType.INT32, WasmIntUnaryOperation.EQZ, expr);
result.setLocation(expr.getLocation()); result.setLocation(expr.getLocation());
return result; return result;
} }

View File

@ -129,12 +129,14 @@ public class WasmGCClassGenerator implements WasmGCClassInfoProvider, WasmGCInit
private int classFlagsOffset; private int classFlagsOffset;
private int classNameOffset; private int classNameOffset;
private int classSimpleNameOffset; private int classSimpleNameOffset;
private int classCanonicalNameOffset;
private int classParentOffset; private int classParentOffset;
private int classArrayOffset; private int classArrayOffset;
private int classArrayItemOffset; private int classArrayItemOffset;
private int classNewArrayOffset; private int classNewArrayOffset;
private int classSupertypeFunctionOffset; private int classSupertypeFunctionOffset;
private int classEnclosingClassOffset; private int classEnclosingClassOffset;
private int classDeclaringClassOffset;
private int virtualTableFieldOffset; private int virtualTableFieldOffset;
private int enumConstantsFunctionOffset; private int enumConstantsFunctionOffset;
private int arrayLengthOffset = -1; private int arrayLengthOffset = -1;
@ -380,6 +382,12 @@ public class WasmGCClassGenerator implements WasmGCClassInfoProvider, WasmGCInit
return classEnclosingClassOffset; return classEnclosingClassOffset;
} }
@Override
public int getClassDeclaringClassOffset() {
standardClasses.classClass().getStructure().init();
return classDeclaringClassOffset;
}
@Override @Override
public int getClassParentOffset() { public int getClassParentOffset() {
standardClasses.classClass().getStructure().init(); standardClasses.classClass().getStructure().init();
@ -398,6 +406,12 @@ public class WasmGCClassGenerator implements WasmGCClassInfoProvider, WasmGCInit
return classSimpleNameOffset; return classSimpleNameOffset;
} }
@Override
public int getClassCanonicalNameOffset() {
standardClasses.classClass().getStructure().init();
return classCanonicalNameOffset;
}
@Override @Override
public int getNewArrayFunctionOffset() { public int getNewArrayFunctionOffset() {
standardClasses.classClass().getStructure().init(); standardClasses.classClass().getStructure().init();
@ -498,10 +512,14 @@ public class WasmGCClassGenerator implements WasmGCClassInfoProvider, WasmGCInit
var parent = getClassInfo(cls.getParent()); var parent = getClassInfo(cls.getParent());
target.add(setClassField(classInfo, classParentOffset, new WasmGetGlobal(parent.pointer))); target.add(setClassField(classInfo, classParentOffset, new WasmGetGlobal(parent.pointer)));
} }
if (cls.getOwnerName() != null && metadataReq.superclass()) { if (cls.getOwnerName() != null && metadataReq.enclosingClass()) {
var owner = getClassInfo(cls.getOwnerName()); var owner = getClassInfo(cls.getOwnerName());
target.add(setClassField(classInfo, classEnclosingClassOffset, new WasmGetGlobal(owner.pointer))); target.add(setClassField(classInfo, classEnclosingClassOffset, new WasmGetGlobal(owner.pointer)));
} }
if (cls.getDeclaringClassName() != null && metadataReq.declaringClass()) {
var owner = getClassInfo(cls.getDeclaringClassName());
target.add(setClassField(classInfo, classDeclaringClassOffset, new WasmGetGlobal(owner.pointer)));
}
if (metadataReq.cloneMethod()) { if (metadataReq.cloneMethod()) {
WasmFunction cloneFunction; WasmFunction cloneFunction;
if (hierarchy.isSuperType("java.lang.Cloneable", name, false)) { if (hierarchy.isSuperType("java.lang.Cloneable", name, false)) {
@ -1067,10 +1085,14 @@ public class WasmGCClassGenerator implements WasmGCClassInfoProvider, WasmGCInit
"createArrayInstance")); "createArrayInstance"));
classEnclosingClassOffset = fields.size(); classEnclosingClassOffset = fields.size();
fields.add(createClassField(standardClasses.classClass().getType().asStorage(), "enclosingClass")); fields.add(createClassField(standardClasses.classClass().getType().asStorage(), "enclosingClass"));
classDeclaringClassOffset = fields.size();
fields.add(createClassField(standardClasses.classClass().getType().asStorage(), "declaringClass"));
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();
fields.add(createClassField(standardClasses.stringClass().getType().asStorage(), "simpleName")); fields.add(createClassField(standardClasses.stringClass().getType().asStorage(), "simpleName"));
classCanonicalNameOffset = fields.size();
fields.add(createClassField(standardClasses.stringClass().getType().asStorage(), "canonicalName"));
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"));

View File

@ -44,6 +44,8 @@ public interface WasmGCClassInfoProvider {
int getClassEnclosingClassOffset(); int getClassEnclosingClassOffset();
int getClassDeclaringClassOffset();
int getClassParentOffset(); int getClassParentOffset();
int getNewArrayFunctionOffset(); int getNewArrayFunctionOffset();
@ -52,6 +54,8 @@ public interface WasmGCClassInfoProvider {
int getClassSimpleNameOffset(); int getClassSimpleNameOffset();
int getClassCanonicalNameOffset();
int getArrayGetOffset(); int getArrayGetOffset();
int getArrayLengthOffset(); int getArrayLengthOffset();

View File

@ -37,8 +37,10 @@ import org.teavm.backend.wasm.generate.gc.strings.WasmGCStringProvider;
import org.teavm.backend.wasm.generators.gc.WasmGCCustomGenerator; import org.teavm.backend.wasm.generators.gc.WasmGCCustomGenerator;
import org.teavm.backend.wasm.generators.gc.WasmGCCustomGeneratorContext; import org.teavm.backend.wasm.generators.gc.WasmGCCustomGeneratorContext;
import org.teavm.backend.wasm.model.WasmFunction; import org.teavm.backend.wasm.model.WasmFunction;
import org.teavm.backend.wasm.model.WasmGlobal;
import org.teavm.backend.wasm.model.WasmLocal; import org.teavm.backend.wasm.model.WasmLocal;
import org.teavm.backend.wasm.model.WasmModule; import org.teavm.backend.wasm.model.WasmModule;
import org.teavm.backend.wasm.model.WasmTag;
import org.teavm.backend.wasm.model.WasmType; import org.teavm.backend.wasm.model.WasmType;
import org.teavm.backend.wasm.model.expression.WasmFunctionReference; import org.teavm.backend.wasm.model.expression.WasmFunctionReference;
import org.teavm.backend.wasm.model.expression.WasmReturn; import org.teavm.backend.wasm.model.expression.WasmReturn;
@ -364,5 +366,20 @@ public class WasmGCMethodGenerator implements BaseWasmFunctionRepository {
public WasmGCNameProvider names() { public WasmGCNameProvider names() {
return names; return names;
} }
@Override
public WasmGlobal exceptionGlobal() {
return context.exceptionGlobal();
}
@Override
public WasmTag exceptionTag() {
return context.getExceptionTag();
}
@Override
public BaseWasmFunctionRepository functions() {
return WasmGCMethodGenerator.this;
}
}; };
} }

View File

@ -15,55 +15,55 @@
*/ */
package org.teavm.backend.wasm.generators.gc; package org.teavm.backend.wasm.generators.gc;
import org.teavm.backend.wasm.generate.gc.classes.WasmGCClassInfoProvider;
import org.teavm.backend.wasm.model.WasmFunction; import org.teavm.backend.wasm.model.WasmFunction;
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.WasmCall;
import org.teavm.backend.wasm.model.expression.WasmCallReference; import org.teavm.backend.wasm.model.expression.WasmCallReference;
import org.teavm.backend.wasm.model.expression.WasmConditional; import org.teavm.backend.wasm.model.expression.WasmConditional;
import org.teavm.backend.wasm.model.expression.WasmGetLocal; import org.teavm.backend.wasm.model.expression.WasmGetLocal;
import org.teavm.backend.wasm.model.expression.WasmInt32Constant;
import org.teavm.backend.wasm.model.expression.WasmNullConstant; import org.teavm.backend.wasm.model.expression.WasmNullConstant;
import org.teavm.backend.wasm.model.expression.WasmReferencesEqual; import org.teavm.backend.wasm.model.expression.WasmReferencesEqual;
import org.teavm.backend.wasm.model.expression.WasmReturn; import org.teavm.backend.wasm.model.expression.WasmReturn;
import org.teavm.backend.wasm.model.expression.WasmSetGlobal;
import org.teavm.backend.wasm.model.expression.WasmStructGet; import org.teavm.backend.wasm.model.expression.WasmStructGet;
import org.teavm.backend.wasm.model.expression.WasmThrow;
import org.teavm.backend.wasm.runtime.WasmGCSupport;
import org.teavm.model.MethodReference; import org.teavm.model.MethodReference;
public class ClassGenerators implements WasmGCCustomGenerator { public class ClassGenerators implements WasmGCCustomGenerator {
@Override @Override
public void apply(MethodReference method, WasmFunction function, WasmGCCustomGeneratorContext context) { public void apply(MethodReference method, WasmFunction function, WasmGCCustomGeneratorContext context) {
switch (method.getName()) { switch (method.getName()) {
case "isInstance": case "isAssignableFrom":
generateIsInstance(function, context); generateIsAssignable(function, context);
break; break;
default: default:
throw new IllegalArgumentException("Unsupported method: " + method); throw new IllegalArgumentException("Unsupported method: " + method);
} }
} }
private void generateIsInstance(WasmFunction function, WasmGCCustomGeneratorContext context) { private void generateIsAssignable(WasmFunction function, WasmGCCustomGeneratorContext context) {
var classCls = context.classInfoProvider().getClassInfo("java.lang.Class"); var classCls = context.classInfoProvider().getClassInfo("java.lang.Class");
var objectCls = context.classInfoProvider().getClassInfo("java.lang.Object");
var thisVar = new WasmLocal(classCls.getType()); var thisVar = new WasmLocal(classCls.getType());
var objectVar = new WasmLocal(objectCls.getType()); var otherClassVar = new WasmLocal(classCls.getType());
function.add(thisVar); function.add(thisVar);
function.add(objectVar); function.add(otherClassVar);
var conditional = new WasmConditional(new WasmReferencesEqual(new WasmGetLocal(objectVar), var conditional = new WasmConditional(new WasmReferencesEqual(new WasmGetLocal(otherClassVar),
new WasmNullConstant(WasmType.Reference.STRUCT))); new WasmNullConstant(WasmType.Reference.STRUCT)));
conditional.setType(WasmType.INT32); function.getBody().add(conditional);
conditional.getThenBlock().getBody().add(new WasmInt32Constant(0)); var npe = new WasmCall(context.functions().forStaticMethod(new MethodReference(WasmGCSupport.class, "npe",
NullPointerException.class)));
conditional.getThenBlock().getBody().add(new WasmSetGlobal(context.exceptionGlobal(), npe));
conditional.getThenBlock().getBody().add(new WasmThrow(context.exceptionTag()));
var objectClass = new WasmStructGet(objectCls.getStructure(), new WasmGetLocal(objectVar),
WasmGCClassInfoProvider.CLASS_FIELD_OFFSET);
var functionRef = new WasmStructGet(classCls.getStructure(), new WasmGetLocal(thisVar), var functionRef = new WasmStructGet(classCls.getStructure(), new WasmGetLocal(thisVar),
context.classInfoProvider().getClassSupertypeFunctionOffset()); context.classInfoProvider().getClassSupertypeFunctionOffset());
var call = new WasmCallReference(functionRef, var call = new WasmCallReference(functionRef,
context.functionTypes().of(WasmType.INT32, classCls.getType())); context.functionTypes().of(WasmType.INT32, classCls.getType()));
call.getArguments().add(objectClass); call.getArguments().add(new WasmGetLocal(otherClassVar));
conditional.getElseBlock().getBody().add(call);
function.getBody().add(new WasmReturn(conditional)); function.getBody().add(new WasmReturn(call));
} }
} }

View File

@ -15,11 +15,14 @@
*/ */
package org.teavm.backend.wasm.generators.gc; package org.teavm.backend.wasm.generators.gc;
import org.teavm.backend.wasm.BaseWasmFunctionRepository;
import org.teavm.backend.wasm.WasmFunctionTypes; import org.teavm.backend.wasm.WasmFunctionTypes;
import org.teavm.backend.wasm.generate.gc.WasmGCNameProvider; import org.teavm.backend.wasm.generate.gc.WasmGCNameProvider;
import org.teavm.backend.wasm.generate.gc.classes.WasmGCClassInfoProvider; import org.teavm.backend.wasm.generate.gc.classes.WasmGCClassInfoProvider;
import org.teavm.backend.wasm.generate.gc.classes.WasmGCTypeMapper; import org.teavm.backend.wasm.generate.gc.classes.WasmGCTypeMapper;
import org.teavm.backend.wasm.model.WasmGlobal;
import org.teavm.backend.wasm.model.WasmModule; import org.teavm.backend.wasm.model.WasmModule;
import org.teavm.backend.wasm.model.WasmTag;
public interface WasmGCCustomGeneratorContext { public interface WasmGCCustomGeneratorContext {
WasmModule module(); WasmModule module();
@ -31,4 +34,10 @@ public interface WasmGCCustomGeneratorContext {
WasmGCClassInfoProvider classInfoProvider(); WasmGCClassInfoProvider classInfoProvider();
WasmGCNameProvider names(); WasmGCNameProvider names();
WasmGlobal exceptionGlobal();
BaseWasmFunctionRepository functions();
WasmTag exceptionTag();
} }

View File

@ -34,7 +34,8 @@ public class WasmGCCustomGenerators implements WasmGCCustomGeneratorProvider {
private void fillClass() { private void fillClass() {
var classGenerators = new ClassGenerators(); var classGenerators = new ClassGenerators();
generators.put(new MethodReference(Class.class, "isInstance", Object.class, boolean.class), classGenerators); generators.put(new MethodReference(Class.class, "isAssignableFrom", Class.class, boolean.class),
classGenerators);
} }
private void fillStringPool() { private void fillStringPool() {

View File

@ -47,11 +47,18 @@ public class ClassIntrinsic implements WasmGCIntrinsic {
result.setLocation(invocation.getLocation()); result.setLocation(invocation.getLocation());
return result; return result;
} }
case "getSuperclass": { case "getDeclaringClass": {
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().getClassDeclaringClassOffset());
result.setLocation(invocation.getLocation());
return result;
}
case "getSuperclass": {
var cls = context.generate(invocation.getArguments().get(0));
var clsStruct = context.classInfoProvider().getClassInfo("java.lang.Class").getStructure();
var result = new WasmStructGet(clsStruct, cls, context.classInfoProvider().getClassParentOffset());
result.setLocation(invocation.getLocation()); result.setLocation(invocation.getLocation());
return result; return result;
} }
@ -63,6 +70,10 @@ public class ClassIntrinsic implements WasmGCIntrinsic {
return generateGetSimpleName(invocation, context); return generateGetSimpleName(invocation, context);
case "setSimpleNameCache": case "setSimpleNameCache":
return generateSetSimpleName(invocation, context); return generateSetSimpleName(invocation, context);
case "getCanonicalNameCache":
return generateGetCanonicalName(invocation, context);
case "setCanonicalNameCache":
return generateSetCanonicalName(invocation, context);
default: default:
throw new IllegalArgumentException("Unsupported invocation method: " + invocation.getMethod()); throw new IllegalArgumentException("Unsupported invocation method: " + invocation.getMethod());
} }
@ -95,4 +106,19 @@ public class ClassIntrinsic implements WasmGCIntrinsic {
return new WasmStructSet(classCls.getStructure(), arg, return new WasmStructSet(classCls.getStructure(), arg,
context.classInfoProvider().getClassSimpleNameOffset(), value); context.classInfoProvider().getClassSimpleNameOffset(), value);
} }
private WasmExpression generateGetCanonicalName(InvocationExpr invocation, WasmGCIntrinsicContext context) {
var classCls = context.classInfoProvider().getClassInfo("java.lang.Class");
var arg = context.generate(invocation.getArguments().get(0));
return new WasmStructGet(classCls.getStructure(), arg,
context.classInfoProvider().getClassCanonicalNameOffset());
}
private WasmExpression generateSetCanonicalName(InvocationExpr invocation, WasmGCIntrinsicContext context) {
var classCls = context.classInfoProvider().getClassInfo("java.lang.Class");
var arg = context.generate(invocation.getArguments().get(0));
var value = context.generate(invocation.getArguments().get(1));
return new WasmStructSet(classCls.getStructure(), arg,
context.classInfoProvider().getClassCanonicalNameOffset(), value);
}
} }

View File

@ -86,9 +86,12 @@ public class WasmGCIntrinsics implements WasmGCIntrinsicProvider {
add(new MethodReference(Class.class, "getNameImpl", String.class), intrinsic); add(new MethodReference(Class.class, "getNameImpl", String.class), intrinsic);
add(new MethodReference(Class.class, "setNameImpl", String.class, void.class), intrinsic); add(new MethodReference(Class.class, "setNameImpl", String.class, void.class), intrinsic);
add(new MethodReference(Class.class, "getEnclosingClass", Class.class), intrinsic); add(new MethodReference(Class.class, "getEnclosingClass", Class.class), intrinsic);
add(new MethodReference(Class.class, "getDeclaringClass", Class.class), intrinsic);
add(new MethodReference(Class.class, "getSuperclass", Class.class), intrinsic); add(new MethodReference(Class.class, "getSuperclass", Class.class), intrinsic);
add(new MethodReference(Class.class, "getSimpleNameCache", Class.class, String.class), intrinsic); add(new MethodReference(Class.class, "getSimpleNameCache", Class.class, String.class), intrinsic);
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);
add(new MethodReference(Class.class, "getCanonicalNameCache", String.class), intrinsic);
add(new MethodReference(Class.class, "setCanonicalNameCache", String.class, void.class), intrinsic);
} }
private void fillClassSupport() { private void fillClassSupport() {

View File

@ -69,8 +69,9 @@ public class BaseClassesTransformation implements ClassHolderTransformer {
for (var method : cls.getMethods()) { for (var method : cls.getMethods()) {
switch (method.getName()) { switch (method.getName()) {
case "getComponentType": case "getComponentType":
case "isInstance": case "isAssignableFrom":
case "getEnclosingClass": case "getEnclosingClass":
case "getDeclaringClass":
case "getSimpleNameCache": case "getSimpleNameCache":
case "setSimpleNameCache": case "setSimpleNameCache":
case "getSuperclass": case "getSuperclass":

View File

@ -103,14 +103,12 @@ 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);
@ -150,7 +148,6 @@ public class ClassTest {
} }
@Test @Test
@SkipPlatform(TestPlatform.WEBASSEMBLY_GC)
public void classProperties() { public void classProperties() {
class B { class B {
} }