diff --git a/classlib/src/main/java/org/teavm/classlib/java/lang/TClass.java b/classlib/src/main/java/org/teavm/classlib/java/lang/TClass.java index f35be8e55..f2de87a73 100644 --- a/classlib/src/main/java/org/teavm/classlib/java/lang/TClass.java +++ b/classlib/src/main/java/org/teavm/classlib/java/lang/TClass.java @@ -28,6 +28,7 @@ import java.util.Objects; import java.util.Set; import org.teavm.backend.javascript.spi.GeneratedBy; import org.teavm.backend.javascript.spi.InjectedBy; +import org.teavm.backend.wasm.generate.gc.classes.WasmGCClassFlags; import org.teavm.classlib.PlatformDetector; import org.teavm.classlib.impl.reflection.ClassSupport; import org.teavm.classlib.impl.reflection.Flags; @@ -292,6 +293,9 @@ public final class TClass extends TObject implements TAnnotatedElement, TType } public boolean isPrimitive() { + if (PlatformDetector.isWebAssemblyGC()) { + return (getWasmGCFlags() & WasmGCClassFlags.PRIMITIVE) != 0; + } return Platform.isPrimitive(platformClass); } @@ -303,22 +307,33 @@ public final class TClass extends TObject implements TAnnotatedElement, TType } public boolean isEnum() { + if (PlatformDetector.isWebAssemblyGC()) { + return (getWasmGCFlags() & WasmGCClassFlags.ENUM) != 0; + } return Platform.isEnum(platformClass); } public boolean isInterface() { + if (PlatformDetector.isWebAssemblyGC()) { + return (getWasmGCFlags() & WasmGCClassFlags.INTERFACE) != 0; + } return (platformClass.getMetadata().getFlags() & Flags.INTERFACE) != 0; + } public boolean isLocalClass() { - return (platformClass.getMetadata().getFlags() & Flags.SYNTHETIC) != 0 - && getEnclosingClass() != null; + if (PlatformDetector.isWebAssemblyGC()) { + return (getWasmGCFlags() & WasmGCClassFlags.SYNTHETIC) != 0 && getEnclosingClass() != null; + } + return (platformClass.getMetadata().getFlags() & Flags.SYNTHETIC) != 0 && getEnclosingClass() != null; } public boolean isMemberClass() { return getDeclaringClass() != null; } + private native int getWasmGCFlags(); + @PluggableDependency(ClassGenerator.class) public TClass getComponentType() { return getClass(Platform.getArrayItem(platformClass)); diff --git a/classlib/src/main/java/org/teavm/classlib/java/util/TDate.java b/classlib/src/main/java/org/teavm/classlib/java/util/TDate.java index 5dfeaf5b3..0ca8c3fbd 100644 --- a/classlib/src/main/java/org/teavm/classlib/java/util/TDate.java +++ b/classlib/src/main/java/org/teavm/classlib/java/util/TDate.java @@ -369,6 +369,7 @@ public class TDate implements TComparable { } @Override + @UnsupportedOn(Platforms.WEBASSEMBLY_GC) public String toString() { if (PlatformDetector.isC()) { return toStringC(value); diff --git a/core/src/main/java/org/teavm/backend/wasm/WasmGCTarget.java b/core/src/main/java/org/teavm/backend/wasm/WasmGCTarget.java index da341b096..c2503a834 100644 --- a/core/src/main/java/org/teavm/backend/wasm/WasmGCTarget.java +++ b/core/src/main/java/org/teavm/backend/wasm/WasmGCTarget.java @@ -53,8 +53,9 @@ import org.teavm.vm.spi.TeaVMHostExtension; public class WasmGCTarget implements TeaVMTarget, TeaVMWasmGCHost { private TeaVMTargetController controller; - private NullCheckInsertion nullCheckInsertion; + private NullCheckInsertion nullCheckInsertion = new NullCheckInsertion(NullCheckFilter.EMPTY); private BoundCheckInsertion boundCheckInsertion = new BoundCheckInsertion(); + private boolean strict; private boolean obfuscated; private List intrinsicFactories = new ArrayList<>(); private Map customIntrinsics = new HashMap<>(); @@ -64,6 +65,10 @@ public class WasmGCTarget implements TeaVMTarget, TeaVMWasmGCHost { this.obfuscated = obfuscated; } + public void setStrict(boolean strict) { + this.strict = strict; + } + @Override public void addIntrinsicFactory(WasmGCIntrinsicFactory intrinsicFactory) { intrinsicFactories.add(intrinsicFactory); @@ -82,7 +87,6 @@ public class WasmGCTarget implements TeaVMTarget, TeaVMWasmGCHost { @Override public void setController(TeaVMTargetController controller) { this.controller = controller; - nullCheckInsertion = new NullCheckInsertion(NullCheckFilter.EMPTY); } @Override @@ -116,10 +120,10 @@ public class WasmGCTarget implements TeaVMTarget, TeaVMWasmGCHost { @Override public void beforeOptimizations(Program program, MethodReader method) { - /* - nullCheckInsertion.transformProgram(program, method.getReference()); - boundCheckInsertion.transformProgram(program, method.getReference()); - */ + if (strict) { + nullCheckInsertion.transformProgram(program, method.getReference()); + boundCheckInsertion.transformProgram(program, method.getReference()); + } } @Override diff --git a/core/src/main/java/org/teavm/backend/wasm/gc/WasmGCDependencies.java b/core/src/main/java/org/teavm/backend/wasm/gc/WasmGCDependencies.java index 6cbc2bb84..68ae28a47 100644 --- a/core/src/main/java/org/teavm/backend/wasm/gc/WasmGCDependencies.java +++ b/core/src/main/java/org/teavm/backend/wasm/gc/WasmGCDependencies.java @@ -98,8 +98,9 @@ public class WasmGCDependencies { analyzer.linkMethod(new MethodReference(WasmGCSupport.class, "aiiobe", ArrayIndexOutOfBoundsException.class)) .use(); analyzer.linkMethod(new MethodReference(WasmGCSupport.class, "cce", ClassCastException.class)).use(); - analyzer.linkMethod(new MethodReference(WasmGCSupport.class, "defaultClone", Object.class, - Object.class)).use(); + analyzer.linkMethod(new MethodReference(WasmGCSupport.class, "throwCloneNotSupportedException", + void.class)).use(); + analyzer.linkMethod(new MethodReference(NullPointerException.class, "", void.class)).use(); } private void contributeInitializerUtils() { diff --git a/core/src/main/java/org/teavm/backend/wasm/generate/WasmGenerationVisitor.java b/core/src/main/java/org/teavm/backend/wasm/generate/WasmGenerationVisitor.java index 6857d55d8..1ff61f29e 100644 --- a/core/src/main/java/org/teavm/backend/wasm/generate/WasmGenerationVisitor.java +++ b/core/src/main/java/org/teavm/backend/wasm/generate/WasmGenerationVisitor.java @@ -594,10 +594,6 @@ public class WasmGenerationVisitor extends BaseWasmGenerationVisitor { return lastTryBlock != null ? lastTryBlock : rethrowBlock(); } - private boolean needsCallSiteId() { - return managed; - } - private void generateAllocStack(Expr sizeExpr) { if (stackVariable != null) { throw new IllegalStateException("Call to ShadowStack.allocStack must be done only once"); diff --git a/core/src/main/java/org/teavm/backend/wasm/generate/common/methods/BaseWasmGenerationVisitor.java b/core/src/main/java/org/teavm/backend/wasm/generate/common/methods/BaseWasmGenerationVisitor.java index 1411a449d..9a3489905 100644 --- a/core/src/main/java/org/teavm/backend/wasm/generate/common/methods/BaseWasmGenerationVisitor.java +++ b/core/src/main/java/org/teavm/backend/wasm/generate/common/methods/BaseWasmGenerationVisitor.java @@ -97,6 +97,7 @@ import org.teavm.backend.wasm.model.expression.WasmSetLocal; import org.teavm.backend.wasm.model.expression.WasmSwitch; import org.teavm.backend.wasm.model.expression.WasmThrow; import org.teavm.backend.wasm.model.expression.WasmTry; +import org.teavm.backend.wasm.model.expression.WasmUnreachable; import org.teavm.backend.wasm.render.WasmTypeInference; import org.teavm.model.FieldReference; import org.teavm.model.MethodReference; @@ -450,11 +451,14 @@ public abstract class BaseWasmGenerationVisitor implements StatementVisitor, Exp block.setLocation(location); accept(value); + if (result instanceof WasmUnreachable) { + return result; + } result.acceptVisitor(typeInference); block.setType(typeInference.getResult()); var cachedValue = exprCache.create(result, typeInference.getResult(), location, block.getBody()); - var check = new WasmBranch(cachedValue.expr(), block); + var check = new WasmBranch(negate(genIsNull(cachedValue.expr())), block); check.setResult(cachedValue.expr()); block.getBody().add(new WasmDrop(check)); @@ -945,7 +949,7 @@ public abstract class BaseWasmGenerationVisitor implements StatementVisitor, Exp List arguments ); - private boolean needsCallSiteId() { + protected boolean needsCallSiteId() { return isManaged(); } diff --git a/core/src/main/java/org/teavm/backend/wasm/generate/gc/classes/WasmGCClassGenerator.java b/core/src/main/java/org/teavm/backend/wasm/generate/gc/classes/WasmGCClassGenerator.java index 298373dba..1dae9e03d 100644 --- a/core/src/main/java/org/teavm/backend/wasm/generate/gc/classes/WasmGCClassGenerator.java +++ b/core/src/main/java/org/teavm/backend/wasm/generate/gc/classes/WasmGCClassGenerator.java @@ -362,6 +362,12 @@ public class WasmGCClassGenerator implements WasmGCClassInfoProvider, WasmGCInit return classArrayItemOffset; } + @Override + public int getClassFlagsOffset() { + standardClasses.classClass().getStructure().init(); + return classFlagsOffset; + } + @Override public int getClassSupertypeFunctionOffset() { standardClasses.classClass().getStructure().init(); diff --git a/core/src/main/java/org/teavm/backend/wasm/generate/gc/classes/WasmGCClassInfoProvider.java b/core/src/main/java/org/teavm/backend/wasm/generate/gc/classes/WasmGCClassInfoProvider.java index 448875c92..9213e8d16 100644 --- a/core/src/main/java/org/teavm/backend/wasm/generate/gc/classes/WasmGCClassInfoProvider.java +++ b/core/src/main/java/org/teavm/backend/wasm/generate/gc/classes/WasmGCClassInfoProvider.java @@ -38,6 +38,8 @@ public interface WasmGCClassInfoProvider { int getClassArrayItemOffset(); + int getClassFlagsOffset(); + int getClassSupertypeFunctionOffset(); int getClassEnclosingClassOffset(); diff --git a/core/src/main/java/org/teavm/backend/wasm/generate/gc/methods/WasmGCGenerationContext.java b/core/src/main/java/org/teavm/backend/wasm/generate/gc/methods/WasmGCGenerationContext.java index e892d868a..5e148ffa5 100644 --- a/core/src/main/java/org/teavm/backend/wasm/generate/gc/methods/WasmGCGenerationContext.java +++ b/core/src/main/java/org/teavm/backend/wasm/generate/gc/methods/WasmGCGenerationContext.java @@ -161,7 +161,7 @@ public class WasmGCGenerationContext implements BaseWasmGenerationContext { public WasmFunction aaiobeMethod() { if (aaiobeMethod == null) { - aaiobeMethod = functions().forStaticMethod(new MethodReference(WasmGCSupport.class, "aaiobe", + aaiobeMethod = functions().forStaticMethod(new MethodReference(WasmGCSupport.class, "aiiobe", ArrayIndexOutOfBoundsException.class)); } return aaiobeMethod; diff --git a/core/src/main/java/org/teavm/backend/wasm/generate/gc/methods/WasmGCGenerationVisitor.java b/core/src/main/java/org/teavm/backend/wasm/generate/gc/methods/WasmGCGenerationVisitor.java index 927fd6db5..ecde44c9d 100644 --- a/core/src/main/java/org/teavm/backend/wasm/generate/gc/methods/WasmGCGenerationVisitor.java +++ b/core/src/main/java/org/teavm/backend/wasm/generate/gc/methods/WasmGCGenerationVisitor.java @@ -105,6 +105,11 @@ public class WasmGCGenerationVisitor extends BaseWasmGenerationVisitor { @Override protected boolean isManaged() { + return true; + } + + @Override + protected boolean needsCallSiteId() { return false; } diff --git a/core/src/main/java/org/teavm/backend/wasm/intrinsics/gc/ClassIntrinsic.java b/core/src/main/java/org/teavm/backend/wasm/intrinsics/gc/ClassIntrinsic.java index 992d87361..9c26536ee 100644 --- a/core/src/main/java/org/teavm/backend/wasm/intrinsics/gc/ClassIntrinsic.java +++ b/core/src/main/java/org/teavm/backend/wasm/intrinsics/gc/ClassIntrinsic.java @@ -24,6 +24,13 @@ public class ClassIntrinsic implements WasmGCIntrinsic { @Override public WasmExpression apply(InvocationExpr invocation, WasmGCIntrinsicContext context) { switch (invocation.getMethod().getName()) { + case "getWasmGCFlags": { + 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().getClassFlagsOffset()); + result.setLocation(invocation.getLocation()); + return result; + } case "getComponentType": { var cls = context.generate(invocation.getArguments().get(0)); var clsStruct = context.classInfoProvider().getClassInfo("java.lang.Class").getStructure(); @@ -43,7 +50,8 @@ public class ClassIntrinsic implements WasmGCIntrinsic { 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()); + var result = new WasmStructGet(clsStruct, cls, + context.classInfoProvider().getClassParentOffset()); result.setLocation(invocation.getLocation()); return result; } diff --git a/core/src/main/java/org/teavm/backend/wasm/intrinsics/gc/WasmGCIntrinsics.java b/core/src/main/java/org/teavm/backend/wasm/intrinsics/gc/WasmGCIntrinsics.java index 83e4b3b64..df918f576 100644 --- a/core/src/main/java/org/teavm/backend/wasm/intrinsics/gc/WasmGCIntrinsics.java +++ b/core/src/main/java/org/teavm/backend/wasm/intrinsics/gc/WasmGCIntrinsics.java @@ -82,6 +82,7 @@ public class WasmGCIntrinsics implements WasmGCIntrinsicProvider { private void fillClass() { var intrinsic = new ClassIntrinsic(); add(new MethodReference(Class.class, "getComponentType", Class.class), intrinsic); + add(new MethodReference(Class.class, "getWasmGCFlags", int.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, "getEnclosingClass", Class.class), intrinsic); diff --git a/core/src/main/java/org/teavm/backend/wasm/runtime/WasmGCSupport.java b/core/src/main/java/org/teavm/backend/wasm/runtime/WasmGCSupport.java index b51e5c2ad..62a2538a3 100644 --- a/core/src/main/java/org/teavm/backend/wasm/runtime/WasmGCSupport.java +++ b/core/src/main/java/org/teavm/backend/wasm/runtime/WasmGCSupport.java @@ -35,7 +35,7 @@ public class WasmGCSupport { return new ClassCastException(); } - public static Object defaultClone(Object value) throws CloneNotSupportedException { + public static void throwCloneNotSupportedException() throws CloneNotSupportedException { throw new CloneNotSupportedException(); } diff --git a/core/src/main/java/org/teavm/runtime/Fiber.java b/core/src/main/java/org/teavm/runtime/Fiber.java index 2da76ec98..4863e6a01 100644 --- a/core/src/main/java/org/teavm/runtime/Fiber.java +++ b/core/src/main/java/org/teavm/runtime/Fiber.java @@ -17,10 +17,13 @@ package org.teavm.runtime; import java.util.Arrays; import org.teavm.interop.AsyncCallback; +import org.teavm.interop.Platforms; import org.teavm.interop.StaticInit; import org.teavm.interop.Unmanaged; +import org.teavm.interop.UnsupportedOn; @StaticInit +@UnsupportedOn(Platforms.WEBASSEMBLY_GC) public class Fiber { public static final int STATE_RUNNING = 0; public static final int STATE_SUSPENDING = 1; diff --git a/platform/src/main/java/org/teavm/platform/Platform.java b/platform/src/main/java/org/teavm/platform/Platform.java index fc70c361f..9d88be9dc 100644 --- a/platform/src/main/java/org/teavm/platform/Platform.java +++ b/platform/src/main/java/org/teavm/platform/Platform.java @@ -26,6 +26,7 @@ import org.teavm.interop.NoSideEffects; import org.teavm.interop.PlatformMarker; import org.teavm.interop.Platforms; import org.teavm.interop.Unmanaged; +import org.teavm.interop.UnsupportedOn; import org.teavm.jso.JSBody; import org.teavm.jso.JSObject; import org.teavm.jso.browser.Window; @@ -35,6 +36,7 @@ import org.teavm.platform.plugin.PlatformGenerator; import org.teavm.runtime.RuntimeClass; import org.teavm.runtime.RuntimeObject; +@UnsupportedOn(Platforms.WEBASSEMBLY_GC) public final class Platform { private Platform() { } diff --git a/tests/src/test/java/org/teavm/classlib/java/lang/ref/WeakReferenceTest.java b/tests/src/test/java/org/teavm/classlib/java/lang/ref/WeakReferenceTest.java index e162f0952..e3997ef9f 100644 --- a/tests/src/test/java/org/teavm/classlib/java/lang/ref/WeakReferenceTest.java +++ b/tests/src/test/java/org/teavm/classlib/java/lang/ref/WeakReferenceTest.java @@ -34,7 +34,8 @@ import org.teavm.junit.TestPlatform; @EachTestCompiledSeparately public class WeakReferenceTest { @Test - @SkipPlatform({ TestPlatform.JAVASCRIPT, TestPlatform.WEBASSEMBLY, TestPlatform.WASI }) + @SkipPlatform({ TestPlatform.JAVASCRIPT, TestPlatform.WEBASSEMBLY, TestPlatform.WASI, + TestPlatform.WEBASSEMBLY_GC }) public void deref() { var ref = createAndTestRef(null); GCSupport.tryToTriggerGC(ref); @@ -42,7 +43,7 @@ public class WeakReferenceTest { } @Test - @SkipPlatform({ TestPlatform.JAVASCRIPT, TestPlatform.WEBASSEMBLY, TestPlatform.WASI }) + @SkipPlatform({ TestPlatform.JAVASCRIPT, TestPlatform.WEBASSEMBLY, TestPlatform.WASI, TestPlatform.WEBASSEMBLY_GC }) public void refQueue() { var queue = new ReferenceQueue<>(); var ref = createAndTestRef(queue); @@ -70,7 +71,7 @@ public class WeakReferenceTest { } @Test - @SkipPlatform({ TestPlatform.C, TestPlatform.WEBASSEMBLY, TestPlatform.WASI }) + @SkipPlatform({ TestPlatform.C, TestPlatform.WEBASSEMBLY, TestPlatform.WASI, TestPlatform.WEBASSEMBLY_GC }) public void queueRemove() throws InterruptedException { var queue = new ReferenceQueue<>(); var ref = createAndTestRef(queue); diff --git a/tools/junit/src/main/java/org/teavm/junit/WebAssemblyGCPlatformSupport.java b/tools/junit/src/main/java/org/teavm/junit/WebAssemblyGCPlatformSupport.java index c7475778a..6fb04b7aa 100644 --- a/tools/junit/src/main/java/org/teavm/junit/WebAssemblyGCPlatformSupport.java +++ b/tools/junit/src/main/java/org/teavm/junit/WebAssemblyGCPlatformSupport.java @@ -68,6 +68,7 @@ class WebAssemblyGCPlatformSupport extends TestPlatformSupport { Supplier targetSupplier = () -> { var target = new WasmGCTarget(); target.setObfuscated(false); + target.setStrict(true); var sourceDirs = System.getProperty(SOURCE_DIRS); if (sourceDirs != null) { var dirs = new ArrayList();