wasm gc: add strict mode, fix some bugs

This commit is contained in:
Alexey Andreev 2024-09-10 20:35:00 +02:00
parent 2d8556d0a2
commit 1533794cf1
17 changed files with 72 additions and 22 deletions

View File

@ -28,6 +28,7 @@ import java.util.Objects;
import java.util.Set; import java.util.Set;
import org.teavm.backend.javascript.spi.GeneratedBy; import org.teavm.backend.javascript.spi.GeneratedBy;
import org.teavm.backend.javascript.spi.InjectedBy; 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.PlatformDetector;
import org.teavm.classlib.impl.reflection.ClassSupport; import org.teavm.classlib.impl.reflection.ClassSupport;
import org.teavm.classlib.impl.reflection.Flags; import org.teavm.classlib.impl.reflection.Flags;
@ -292,6 +293,9 @@ public final class TClass<T> extends TObject implements TAnnotatedElement, TType
} }
public boolean isPrimitive() { public boolean isPrimitive() {
if (PlatformDetector.isWebAssemblyGC()) {
return (getWasmGCFlags() & WasmGCClassFlags.PRIMITIVE) != 0;
}
return Platform.isPrimitive(platformClass); return Platform.isPrimitive(platformClass);
} }
@ -303,22 +307,33 @@ public final class TClass<T> extends TObject implements TAnnotatedElement, TType
} }
public boolean isEnum() { public boolean isEnum() {
if (PlatformDetector.isWebAssemblyGC()) {
return (getWasmGCFlags() & WasmGCClassFlags.ENUM) != 0;
}
return Platform.isEnum(platformClass); return Platform.isEnum(platformClass);
} }
public boolean isInterface() { public boolean isInterface() {
if (PlatformDetector.isWebAssemblyGC()) {
return (getWasmGCFlags() & WasmGCClassFlags.INTERFACE) != 0;
}
return (platformClass.getMetadata().getFlags() & Flags.INTERFACE) != 0; return (platformClass.getMetadata().getFlags() & Flags.INTERFACE) != 0;
} }
public boolean isLocalClass() { public boolean isLocalClass() {
return (platformClass.getMetadata().getFlags() & Flags.SYNTHETIC) != 0 if (PlatformDetector.isWebAssemblyGC()) {
&& getEnclosingClass() != null; return (getWasmGCFlags() & WasmGCClassFlags.SYNTHETIC) != 0 && getEnclosingClass() != null;
}
return (platformClass.getMetadata().getFlags() & Flags.SYNTHETIC) != 0 && getEnclosingClass() != null;
} }
public boolean isMemberClass() { public boolean isMemberClass() {
return getDeclaringClass() != null; return getDeclaringClass() != null;
} }
private native int getWasmGCFlags();
@PluggableDependency(ClassGenerator.class) @PluggableDependency(ClassGenerator.class)
public TClass<?> getComponentType() { public TClass<?> getComponentType() {
return getClass(Platform.getArrayItem(platformClass)); return getClass(Platform.getArrayItem(platformClass));

View File

@ -369,6 +369,7 @@ public class TDate implements TComparable<TDate> {
} }
@Override @Override
@UnsupportedOn(Platforms.WEBASSEMBLY_GC)
public String toString() { public String toString() {
if (PlatformDetector.isC()) { if (PlatformDetector.isC()) {
return toStringC(value); return toStringC(value);

View File

@ -53,8 +53,9 @@ import org.teavm.vm.spi.TeaVMHostExtension;
public class WasmGCTarget implements TeaVMTarget, TeaVMWasmGCHost { public class WasmGCTarget implements TeaVMTarget, TeaVMWasmGCHost {
private TeaVMTargetController controller; private TeaVMTargetController controller;
private NullCheckInsertion nullCheckInsertion; private NullCheckInsertion nullCheckInsertion = new NullCheckInsertion(NullCheckFilter.EMPTY);
private BoundCheckInsertion boundCheckInsertion = new BoundCheckInsertion(); private BoundCheckInsertion boundCheckInsertion = new BoundCheckInsertion();
private boolean strict;
private boolean obfuscated; private boolean obfuscated;
private List<WasmGCIntrinsicFactory> intrinsicFactories = new ArrayList<>(); private List<WasmGCIntrinsicFactory> intrinsicFactories = new ArrayList<>();
private Map<MethodReference, WasmGCIntrinsic> customIntrinsics = new HashMap<>(); private Map<MethodReference, WasmGCIntrinsic> customIntrinsics = new HashMap<>();
@ -64,6 +65,10 @@ public class WasmGCTarget implements TeaVMTarget, TeaVMWasmGCHost {
this.obfuscated = obfuscated; this.obfuscated = obfuscated;
} }
public void setStrict(boolean strict) {
this.strict = strict;
}
@Override @Override
public void addIntrinsicFactory(WasmGCIntrinsicFactory intrinsicFactory) { public void addIntrinsicFactory(WasmGCIntrinsicFactory intrinsicFactory) {
intrinsicFactories.add(intrinsicFactory); intrinsicFactories.add(intrinsicFactory);
@ -82,7 +87,6 @@ public class WasmGCTarget implements TeaVMTarget, TeaVMWasmGCHost {
@Override @Override
public void setController(TeaVMTargetController controller) { public void setController(TeaVMTargetController controller) {
this.controller = controller; this.controller = controller;
nullCheckInsertion = new NullCheckInsertion(NullCheckFilter.EMPTY);
} }
@Override @Override
@ -116,10 +120,10 @@ public class WasmGCTarget implements TeaVMTarget, TeaVMWasmGCHost {
@Override @Override
public void beforeOptimizations(Program program, MethodReader method) { public void beforeOptimizations(Program program, MethodReader method) {
/* if (strict) {
nullCheckInsertion.transformProgram(program, method.getReference()); nullCheckInsertion.transformProgram(program, method.getReference());
boundCheckInsertion.transformProgram(program, method.getReference()); boundCheckInsertion.transformProgram(program, method.getReference());
*/ }
} }
@Override @Override

View File

@ -98,8 +98,9 @@ public class WasmGCDependencies {
analyzer.linkMethod(new MethodReference(WasmGCSupport.class, "aiiobe", ArrayIndexOutOfBoundsException.class)) analyzer.linkMethod(new MethodReference(WasmGCSupport.class, "aiiobe", ArrayIndexOutOfBoundsException.class))
.use(); .use();
analyzer.linkMethod(new MethodReference(WasmGCSupport.class, "cce", ClassCastException.class)).use(); analyzer.linkMethod(new MethodReference(WasmGCSupport.class, "cce", ClassCastException.class)).use();
analyzer.linkMethod(new MethodReference(WasmGCSupport.class, "defaultClone", Object.class, analyzer.linkMethod(new MethodReference(WasmGCSupport.class, "throwCloneNotSupportedException",
Object.class)).use(); void.class)).use();
analyzer.linkMethod(new MethodReference(NullPointerException.class, "<init>", void.class)).use();
} }
private void contributeInitializerUtils() { private void contributeInitializerUtils() {

View File

@ -594,10 +594,6 @@ public class WasmGenerationVisitor extends BaseWasmGenerationVisitor {
return lastTryBlock != null ? lastTryBlock : rethrowBlock(); return lastTryBlock != null ? lastTryBlock : rethrowBlock();
} }
private boolean needsCallSiteId() {
return managed;
}
private void generateAllocStack(Expr sizeExpr) { private void generateAllocStack(Expr sizeExpr) {
if (stackVariable != null) { if (stackVariable != null) {
throw new IllegalStateException("Call to ShadowStack.allocStack must be done only once"); throw new IllegalStateException("Call to ShadowStack.allocStack must be done only once");

View File

@ -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.WasmSwitch;
import org.teavm.backend.wasm.model.expression.WasmThrow; import org.teavm.backend.wasm.model.expression.WasmThrow;
import org.teavm.backend.wasm.model.expression.WasmTry; 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.backend.wasm.render.WasmTypeInference;
import org.teavm.model.FieldReference; import org.teavm.model.FieldReference;
import org.teavm.model.MethodReference; import org.teavm.model.MethodReference;
@ -450,11 +451,14 @@ public abstract class BaseWasmGenerationVisitor implements StatementVisitor, Exp
block.setLocation(location); block.setLocation(location);
accept(value); accept(value);
if (result instanceof WasmUnreachable) {
return result;
}
result.acceptVisitor(typeInference); result.acceptVisitor(typeInference);
block.setType(typeInference.getResult()); block.setType(typeInference.getResult());
var cachedValue = exprCache.create(result, typeInference.getResult(), location, block.getBody()); 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()); check.setResult(cachedValue.expr());
block.getBody().add(new WasmDrop(check)); block.getBody().add(new WasmDrop(check));
@ -945,7 +949,7 @@ public abstract class BaseWasmGenerationVisitor implements StatementVisitor, Exp
List<WasmExpression> arguments List<WasmExpression> arguments
); );
private boolean needsCallSiteId() { protected boolean needsCallSiteId() {
return isManaged(); return isManaged();
} }

View File

@ -362,6 +362,12 @@ public class WasmGCClassGenerator implements WasmGCClassInfoProvider, WasmGCInit
return classArrayItemOffset; return classArrayItemOffset;
} }
@Override
public int getClassFlagsOffset() {
standardClasses.classClass().getStructure().init();
return classFlagsOffset;
}
@Override @Override
public int getClassSupertypeFunctionOffset() { public int getClassSupertypeFunctionOffset() {
standardClasses.classClass().getStructure().init(); standardClasses.classClass().getStructure().init();

View File

@ -38,6 +38,8 @@ public interface WasmGCClassInfoProvider {
int getClassArrayItemOffset(); int getClassArrayItemOffset();
int getClassFlagsOffset();
int getClassSupertypeFunctionOffset(); int getClassSupertypeFunctionOffset();
int getClassEnclosingClassOffset(); int getClassEnclosingClassOffset();

View File

@ -161,7 +161,7 @@ public class WasmGCGenerationContext implements BaseWasmGenerationContext {
public WasmFunction aaiobeMethod() { public WasmFunction aaiobeMethod() {
if (aaiobeMethod == null) { if (aaiobeMethod == null) {
aaiobeMethod = functions().forStaticMethod(new MethodReference(WasmGCSupport.class, "aaiobe", aaiobeMethod = functions().forStaticMethod(new MethodReference(WasmGCSupport.class, "aiiobe",
ArrayIndexOutOfBoundsException.class)); ArrayIndexOutOfBoundsException.class));
} }
return aaiobeMethod; return aaiobeMethod;

View File

@ -105,6 +105,11 @@ public class WasmGCGenerationVisitor extends BaseWasmGenerationVisitor {
@Override @Override
protected boolean isManaged() { protected boolean isManaged() {
return true;
}
@Override
protected boolean needsCallSiteId() {
return false; return false;
} }

View File

@ -24,6 +24,13 @@ public class ClassIntrinsic implements WasmGCIntrinsic {
@Override @Override
public WasmExpression apply(InvocationExpr invocation, WasmGCIntrinsicContext context) { public WasmExpression apply(InvocationExpr invocation, WasmGCIntrinsicContext context) {
switch (invocation.getMethod().getName()) { 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": { case "getComponentType": {
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();
@ -43,7 +50,8 @@ public class ClassIntrinsic implements WasmGCIntrinsic {
case "getSuperclass": { case "getSuperclass": {
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, context.classInfoProvider().getClassParentOffset()); var result = new WasmStructGet(clsStruct, cls,
context.classInfoProvider().getClassParentOffset());
result.setLocation(invocation.getLocation()); result.setLocation(invocation.getLocation());
return result; return result;
} }

View File

@ -82,6 +82,7 @@ public class WasmGCIntrinsics implements WasmGCIntrinsicProvider {
private void fillClass() { private void fillClass() {
var intrinsic = new ClassIntrinsic(); var intrinsic = new ClassIntrinsic();
add(new MethodReference(Class.class, "getComponentType", Class.class), intrinsic); 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, "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);

View File

@ -35,7 +35,7 @@ public class WasmGCSupport {
return new ClassCastException(); return new ClassCastException();
} }
public static Object defaultClone(Object value) throws CloneNotSupportedException { public static void throwCloneNotSupportedException() throws CloneNotSupportedException {
throw new CloneNotSupportedException(); throw new CloneNotSupportedException();
} }

View File

@ -17,10 +17,13 @@ package org.teavm.runtime;
import java.util.Arrays; import java.util.Arrays;
import org.teavm.interop.AsyncCallback; import org.teavm.interop.AsyncCallback;
import org.teavm.interop.Platforms;
import org.teavm.interop.StaticInit; import org.teavm.interop.StaticInit;
import org.teavm.interop.Unmanaged; import org.teavm.interop.Unmanaged;
import org.teavm.interop.UnsupportedOn;
@StaticInit @StaticInit
@UnsupportedOn(Platforms.WEBASSEMBLY_GC)
public class Fiber { public class Fiber {
public static final int STATE_RUNNING = 0; public static final int STATE_RUNNING = 0;
public static final int STATE_SUSPENDING = 1; public static final int STATE_SUSPENDING = 1;

View File

@ -26,6 +26,7 @@ import org.teavm.interop.NoSideEffects;
import org.teavm.interop.PlatformMarker; import org.teavm.interop.PlatformMarker;
import org.teavm.interop.Platforms; import org.teavm.interop.Platforms;
import org.teavm.interop.Unmanaged; import org.teavm.interop.Unmanaged;
import org.teavm.interop.UnsupportedOn;
import org.teavm.jso.JSBody; import org.teavm.jso.JSBody;
import org.teavm.jso.JSObject; import org.teavm.jso.JSObject;
import org.teavm.jso.browser.Window; 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.RuntimeClass;
import org.teavm.runtime.RuntimeObject; import org.teavm.runtime.RuntimeObject;
@UnsupportedOn(Platforms.WEBASSEMBLY_GC)
public final class Platform { public final class Platform {
private Platform() { private Platform() {
} }

View File

@ -34,7 +34,8 @@ import org.teavm.junit.TestPlatform;
@EachTestCompiledSeparately @EachTestCompiledSeparately
public class WeakReferenceTest { public class WeakReferenceTest {
@Test @Test
@SkipPlatform({ TestPlatform.JAVASCRIPT, TestPlatform.WEBASSEMBLY, TestPlatform.WASI }) @SkipPlatform({ TestPlatform.JAVASCRIPT, TestPlatform.WEBASSEMBLY, TestPlatform.WASI,
TestPlatform.WEBASSEMBLY_GC })
public void deref() { public void deref() {
var ref = createAndTestRef(null); var ref = createAndTestRef(null);
GCSupport.tryToTriggerGC(ref); GCSupport.tryToTriggerGC(ref);
@ -42,7 +43,7 @@ public class WeakReferenceTest {
} }
@Test @Test
@SkipPlatform({ TestPlatform.JAVASCRIPT, TestPlatform.WEBASSEMBLY, TestPlatform.WASI }) @SkipPlatform({ TestPlatform.JAVASCRIPT, TestPlatform.WEBASSEMBLY, TestPlatform.WASI, TestPlatform.WEBASSEMBLY_GC })
public void refQueue() { public void refQueue() {
var queue = new ReferenceQueue<>(); var queue = new ReferenceQueue<>();
var ref = createAndTestRef(queue); var ref = createAndTestRef(queue);
@ -70,7 +71,7 @@ public class WeakReferenceTest {
} }
@Test @Test
@SkipPlatform({ TestPlatform.C, TestPlatform.WEBASSEMBLY, TestPlatform.WASI }) @SkipPlatform({ TestPlatform.C, TestPlatform.WEBASSEMBLY, TestPlatform.WASI, TestPlatform.WEBASSEMBLY_GC })
public void queueRemove() throws InterruptedException { public void queueRemove() throws InterruptedException {
var queue = new ReferenceQueue<>(); var queue = new ReferenceQueue<>();
var ref = createAndTestRef(queue); var ref = createAndTestRef(queue);

View File

@ -68,6 +68,7 @@ class WebAssemblyGCPlatformSupport extends TestPlatformSupport<WasmGCTarget> {
Supplier<WasmGCTarget> targetSupplier = () -> { Supplier<WasmGCTarget> targetSupplier = () -> {
var target = new WasmGCTarget(); var target = new WasmGCTarget();
target.setObfuscated(false); target.setObfuscated(false);
target.setStrict(true);
var sourceDirs = System.getProperty(SOURCE_DIRS); var sourceDirs = System.getProperty(SOURCE_DIRS);
if (sourceDirs != null) { if (sourceDirs != null) {
var dirs = new ArrayList<File>(); var dirs = new ArrayList<File>();