mirror of
https://github.com/Eaglercraft-TeaVM-Fork/eagler-teavm.git
synced 2024-12-22 00:04:10 -08:00
wasm gc: fix bugs with Class
This commit is contained in:
parent
d12637f959
commit
eccfaff889
|
@ -46,9 +46,7 @@ import org.teavm.dependency.PluggableDependency;
|
|||
import org.teavm.interop.Address;
|
||||
import org.teavm.interop.DelegateTo;
|
||||
import org.teavm.interop.NoSideEffects;
|
||||
import org.teavm.interop.Platforms;
|
||||
import org.teavm.interop.Unmanaged;
|
||||
import org.teavm.interop.UnsupportedOn;
|
||||
import org.teavm.jso.core.JSArray;
|
||||
import org.teavm.platform.Platform;
|
||||
import org.teavm.platform.PlatformClass;
|
||||
|
@ -101,8 +99,10 @@ public final class TClass<T> extends TObject implements TAnnotatedElement, TType
|
|||
}
|
||||
|
||||
@DelegateTo("isInstanceLowLevel")
|
||||
@UnsupportedOn(Platforms.WEBASSEMBLY_GC)
|
||||
public boolean isInstance(TObject obj) {
|
||||
if (PlatformDetector.isWebAssemblyGC()) {
|
||||
return obj != null && isAssignableFrom((TClass<?>) (Object) obj.getClass());
|
||||
}
|
||||
return Platform.isInstance(Platform.getPlatformObject(obj), platformClass);
|
||||
}
|
||||
|
||||
|
@ -112,7 +112,6 @@ public final class TClass<T> extends TObject implements TAnnotatedElement, TType
|
|||
}
|
||||
|
||||
@DelegateTo("isAssignableFromLowLevel")
|
||||
@UnsupportedOn(Platforms.WEBASSEMBLY_GC)
|
||||
public boolean isAssignableFrom(TClass<?> obj) {
|
||||
return Platform.isAssignable(obj.getPlatformClass(), platformClass);
|
||||
}
|
||||
|
@ -268,7 +267,9 @@ public final class TClass<T> extends TObject implements TAnnotatedElement, TType
|
|||
}
|
||||
|
||||
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;
|
||||
} else {
|
||||
return (RuntimeClass.getClass(Address.ofObject(this).toStructure()).flags & RuntimeClass.SYNTHETIC) != 0;
|
||||
|
|
|
@ -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.WasmIntBinaryOperation;
|
||||
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.WasmSetLocal;
|
||||
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());
|
||||
return result;
|
||||
}
|
||||
|
|
|
@ -129,12 +129,14 @@ public class WasmGCClassGenerator implements WasmGCClassInfoProvider, WasmGCInit
|
|||
private int classFlagsOffset;
|
||||
private int classNameOffset;
|
||||
private int classSimpleNameOffset;
|
||||
private int classCanonicalNameOffset;
|
||||
private int classParentOffset;
|
||||
private int classArrayOffset;
|
||||
private int classArrayItemOffset;
|
||||
private int classNewArrayOffset;
|
||||
private int classSupertypeFunctionOffset;
|
||||
private int classEnclosingClassOffset;
|
||||
private int classDeclaringClassOffset;
|
||||
private int virtualTableFieldOffset;
|
||||
private int enumConstantsFunctionOffset;
|
||||
private int arrayLengthOffset = -1;
|
||||
|
@ -380,6 +382,12 @@ public class WasmGCClassGenerator implements WasmGCClassInfoProvider, WasmGCInit
|
|||
return classEnclosingClassOffset;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getClassDeclaringClassOffset() {
|
||||
standardClasses.classClass().getStructure().init();
|
||||
return classDeclaringClassOffset;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getClassParentOffset() {
|
||||
standardClasses.classClass().getStructure().init();
|
||||
|
@ -398,6 +406,12 @@ public class WasmGCClassGenerator implements WasmGCClassInfoProvider, WasmGCInit
|
|||
return classSimpleNameOffset;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getClassCanonicalNameOffset() {
|
||||
standardClasses.classClass().getStructure().init();
|
||||
return classCanonicalNameOffset;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getNewArrayFunctionOffset() {
|
||||
standardClasses.classClass().getStructure().init();
|
||||
|
@ -498,10 +512,14 @@ public class WasmGCClassGenerator implements WasmGCClassInfoProvider, WasmGCInit
|
|||
var parent = getClassInfo(cls.getParent());
|
||||
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());
|
||||
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()) {
|
||||
WasmFunction cloneFunction;
|
||||
if (hierarchy.isSuperType("java.lang.Cloneable", name, false)) {
|
||||
|
@ -1067,10 +1085,14 @@ public class WasmGCClassGenerator implements WasmGCClassInfoProvider, WasmGCInit
|
|||
"createArrayInstance"));
|
||||
classEnclosingClassOffset = fields.size();
|
||||
fields.add(createClassField(standardClasses.classClass().getType().asStorage(), "enclosingClass"));
|
||||
classDeclaringClassOffset = fields.size();
|
||||
fields.add(createClassField(standardClasses.classClass().getType().asStorage(), "declaringClass"));
|
||||
classNameOffset = fields.size();
|
||||
fields.add(createClassField(standardClasses.stringClass().getType().asStorage(), "name"));
|
||||
classSimpleNameOffset = fields.size();
|
||||
fields.add(createClassField(standardClasses.stringClass().getType().asStorage(), "simpleName"));
|
||||
classCanonicalNameOffset = fields.size();
|
||||
fields.add(createClassField(standardClasses.stringClass().getType().asStorage(), "canonicalName"));
|
||||
cloneOffset = fields.size();
|
||||
fields.add(createClassField(functionTypes.of(standardClasses.objectClass().getType(),
|
||||
standardClasses.objectClass().getType()).getReference().asStorage(), "clone"));
|
||||
|
|
|
@ -44,6 +44,8 @@ public interface WasmGCClassInfoProvider {
|
|||
|
||||
int getClassEnclosingClassOffset();
|
||||
|
||||
int getClassDeclaringClassOffset();
|
||||
|
||||
int getClassParentOffset();
|
||||
|
||||
int getNewArrayFunctionOffset();
|
||||
|
@ -52,6 +54,8 @@ public interface WasmGCClassInfoProvider {
|
|||
|
||||
int getClassSimpleNameOffset();
|
||||
|
||||
int getClassCanonicalNameOffset();
|
||||
|
||||
int getArrayGetOffset();
|
||||
|
||||
int getArrayLengthOffset();
|
||||
|
|
|
@ -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.WasmGCCustomGeneratorContext;
|
||||
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.WasmModule;
|
||||
import org.teavm.backend.wasm.model.WasmTag;
|
||||
import org.teavm.backend.wasm.model.WasmType;
|
||||
import org.teavm.backend.wasm.model.expression.WasmFunctionReference;
|
||||
import org.teavm.backend.wasm.model.expression.WasmReturn;
|
||||
|
@ -364,5 +366,20 @@ public class WasmGCMethodGenerator implements BaseWasmFunctionRepository {
|
|||
public WasmGCNameProvider names() {
|
||||
return names;
|
||||
}
|
||||
|
||||
@Override
|
||||
public WasmGlobal exceptionGlobal() {
|
||||
return context.exceptionGlobal();
|
||||
}
|
||||
|
||||
@Override
|
||||
public WasmTag exceptionTag() {
|
||||
return context.getExceptionTag();
|
||||
}
|
||||
|
||||
@Override
|
||||
public BaseWasmFunctionRepository functions() {
|
||||
return WasmGCMethodGenerator.this;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
|
@ -15,55 +15,55 @@
|
|||
*/
|
||||
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.WasmLocal;
|
||||
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.WasmConditional;
|
||||
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.WasmReferencesEqual;
|
||||
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.WasmThrow;
|
||||
import org.teavm.backend.wasm.runtime.WasmGCSupport;
|
||||
import org.teavm.model.MethodReference;
|
||||
|
||||
public class ClassGenerators implements WasmGCCustomGenerator {
|
||||
@Override
|
||||
public void apply(MethodReference method, WasmFunction function, WasmGCCustomGeneratorContext context) {
|
||||
switch (method.getName()) {
|
||||
case "isInstance":
|
||||
generateIsInstance(function, context);
|
||||
case "isAssignableFrom":
|
||||
generateIsAssignable(function, context);
|
||||
break;
|
||||
default:
|
||||
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 objectCls = context.classInfoProvider().getClassInfo("java.lang.Object");
|
||||
var thisVar = new WasmLocal(classCls.getType());
|
||||
var objectVar = new WasmLocal(objectCls.getType());
|
||||
var otherClassVar = new WasmLocal(classCls.getType());
|
||||
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)));
|
||||
conditional.setType(WasmType.INT32);
|
||||
conditional.getThenBlock().getBody().add(new WasmInt32Constant(0));
|
||||
function.getBody().add(conditional);
|
||||
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),
|
||||
context.classInfoProvider().getClassSupertypeFunctionOffset());
|
||||
var call = new WasmCallReference(functionRef,
|
||||
context.functionTypes().of(WasmType.INT32, classCls.getType()));
|
||||
call.getArguments().add(objectClass);
|
||||
conditional.getElseBlock().getBody().add(call);
|
||||
call.getArguments().add(new WasmGetLocal(otherClassVar));
|
||||
|
||||
function.getBody().add(new WasmReturn(conditional));
|
||||
function.getBody().add(new WasmReturn(call));
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -15,11 +15,14 @@
|
|||
*/
|
||||
package org.teavm.backend.wasm.generators.gc;
|
||||
|
||||
import org.teavm.backend.wasm.BaseWasmFunctionRepository;
|
||||
import org.teavm.backend.wasm.WasmFunctionTypes;
|
||||
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.WasmGCTypeMapper;
|
||||
import org.teavm.backend.wasm.model.WasmGlobal;
|
||||
import org.teavm.backend.wasm.model.WasmModule;
|
||||
import org.teavm.backend.wasm.model.WasmTag;
|
||||
|
||||
public interface WasmGCCustomGeneratorContext {
|
||||
WasmModule module();
|
||||
|
@ -31,4 +34,10 @@ public interface WasmGCCustomGeneratorContext {
|
|||
WasmGCClassInfoProvider classInfoProvider();
|
||||
|
||||
WasmGCNameProvider names();
|
||||
|
||||
WasmGlobal exceptionGlobal();
|
||||
|
||||
BaseWasmFunctionRepository functions();
|
||||
|
||||
WasmTag exceptionTag();
|
||||
}
|
||||
|
|
|
@ -34,7 +34,8 @@ public class WasmGCCustomGenerators implements WasmGCCustomGeneratorProvider {
|
|||
|
||||
private void fillClass() {
|
||||
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() {
|
||||
|
|
|
@ -47,11 +47,18 @@ public class ClassIntrinsic implements WasmGCIntrinsic {
|
|||
result.setLocation(invocation.getLocation());
|
||||
return result;
|
||||
}
|
||||
case "getSuperclass": {
|
||||
case "getDeclaringClass": {
|
||||
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());
|
||||
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());
|
||||
return result;
|
||||
}
|
||||
|
@ -63,6 +70,10 @@ public class ClassIntrinsic implements WasmGCIntrinsic {
|
|||
return generateGetSimpleName(invocation, context);
|
||||
case "setSimpleNameCache":
|
||||
return generateSetSimpleName(invocation, context);
|
||||
case "getCanonicalNameCache":
|
||||
return generateGetCanonicalName(invocation, context);
|
||||
case "setCanonicalNameCache":
|
||||
return generateSetCanonicalName(invocation, context);
|
||||
default:
|
||||
throw new IllegalArgumentException("Unsupported invocation method: " + invocation.getMethod());
|
||||
}
|
||||
|
@ -95,4 +106,19 @@ public class ClassIntrinsic implements WasmGCIntrinsic {
|
|||
return new WasmStructSet(classCls.getStructure(), arg,
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -86,9 +86,12 @@ public class WasmGCIntrinsics implements WasmGCIntrinsicProvider {
|
|||
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, "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, "getSimpleNameCache", Class.class, String.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() {
|
||||
|
|
|
@ -69,8 +69,9 @@ public class BaseClassesTransformation implements ClassHolderTransformer {
|
|||
for (var method : cls.getMethods()) {
|
||||
switch (method.getName()) {
|
||||
case "getComponentType":
|
||||
case "isInstance":
|
||||
case "isAssignableFrom":
|
||||
case "getEnclosingClass":
|
||||
case "getDeclaringClass":
|
||||
case "getSimpleNameCache":
|
||||
case "setSimpleNameCache":
|
||||
case "getSuperclass":
|
||||
|
|
|
@ -103,14 +103,12 @@ public class ClassTest {
|
|||
}
|
||||
|
||||
@Test
|
||||
@SkipPlatform(TestPlatform.WEBASSEMBLY_GC)
|
||||
public void castingAppropriateObject() {
|
||||
Object obj = 23;
|
||||
assertEquals(Integer.valueOf(23), Integer.class.cast(obj));
|
||||
}
|
||||
|
||||
@Test(expected = ClassCastException.class)
|
||||
@SkipPlatform(TestPlatform.WEBASSEMBLY_GC)
|
||||
public void inappropriateObjectCastingFails() {
|
||||
Object obj = 23;
|
||||
Float.class.cast(obj);
|
||||
|
@ -150,7 +148,6 @@ public class ClassTest {
|
|||
}
|
||||
|
||||
@Test
|
||||
@SkipPlatform(TestPlatform.WEBASSEMBLY_GC)
|
||||
public void classProperties() {
|
||||
class B {
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue
Block a user