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 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<T> 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<T> 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));

View File

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

View File

@ -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<WasmGCIntrinsicFactory> intrinsicFactories = new ArrayList<>();
private Map<MethodReference, WasmGCIntrinsic> 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

View File

@ -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, "<init>", void.class)).use();
}
private void contributeInitializerUtils() {

View File

@ -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");

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.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<WasmExpression> arguments
);
private boolean needsCallSiteId() {
protected boolean needsCallSiteId() {
return isManaged();
}

View File

@ -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();

View File

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

View File

@ -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;

View File

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

View File

@ -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;
}

View File

@ -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);

View File

@ -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();
}

View File

@ -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;

View File

@ -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() {
}

View File

@ -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);

View File

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