mirror of
https://github.com/konsoletyper/teavm.git
synced 2024-11-21 01:00:54 +08:00
wasm gc: draft Wasm GC backend
This commit is contained in:
parent
9f12917de9
commit
a281c19363
@ -32,6 +32,11 @@ public final class PlatformDetector {
|
||||
return false;
|
||||
}
|
||||
|
||||
@PlatformMarker(Platforms.WEBASSEMBLY_GC)
|
||||
public static boolean isWebAssemblyGC() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@PlatformMarker(Platforms.JAVASCRIPT)
|
||||
public static boolean isJavaScript() {
|
||||
return false;
|
||||
|
@ -16,6 +16,7 @@
|
||||
package org.teavm.classlib.impl.console;
|
||||
|
||||
import org.teavm.backend.c.intrinsic.RuntimeInclude;
|
||||
import org.teavm.backend.wasm.runtime.WasmGCSupport;
|
||||
import org.teavm.backend.wasm.runtime.WasmSupport;
|
||||
import org.teavm.classlib.PlatformDetector;
|
||||
import org.teavm.interop.Address;
|
||||
@ -35,6 +36,10 @@ public final class Console {
|
||||
}
|
||||
} else if (PlatformDetector.isWebAssembly()) {
|
||||
WasmSupport.putCharsStderr(Address.ofData(data).add(off), len);
|
||||
} else if (PlatformDetector.isWebAssemblyGC()) {
|
||||
for (var i = 0; i < len; ++i) {
|
||||
WasmGCSupport.putCharStderr((char) data[off + i]);
|
||||
}
|
||||
} else {
|
||||
for (int i = 0; i < len; ++i) {
|
||||
byte b = data[i + off];
|
||||
@ -51,6 +56,10 @@ public final class Console {
|
||||
}
|
||||
} else if (PlatformDetector.isWebAssembly()) {
|
||||
WasmSupport.putCharsStdout(Address.ofData(data).add(off), len);
|
||||
} else if (PlatformDetector.isWebAssemblyGC()) {
|
||||
for (var i = 0; i < len; ++i) {
|
||||
WasmGCSupport.putCharStdout((char) data[off + i]);
|
||||
}
|
||||
} else {
|
||||
for (int i = 0; i < len; ++i) {
|
||||
byte b = data[i + off];
|
||||
|
@ -15,12 +15,20 @@
|
||||
*/
|
||||
package org.teavm.classlib.impl.console;
|
||||
|
||||
import org.teavm.backend.wasm.runtime.WasmGCSupport;
|
||||
import org.teavm.classlib.PlatformDetector;
|
||||
import org.teavm.jso.JSBody;
|
||||
|
||||
public class JSStderrPrintStream extends JsConsolePrintStream {
|
||||
@Override
|
||||
public void print(String s) {
|
||||
writeJs(s);
|
||||
if (PlatformDetector.isWebAssemblyGC()) {
|
||||
for (int i = 0; i < s.length(); ++i) {
|
||||
WasmGCSupport.putCharStderr(s.charAt(i));
|
||||
}
|
||||
} else {
|
||||
writeJs(s);
|
||||
}
|
||||
}
|
||||
|
||||
@JSBody(params = "b", script = "$rt_putStderr(b);")
|
||||
|
@ -15,12 +15,20 @@
|
||||
*/
|
||||
package org.teavm.classlib.impl.console;
|
||||
|
||||
import org.teavm.backend.wasm.runtime.WasmGCSupport;
|
||||
import org.teavm.classlib.PlatformDetector;
|
||||
import org.teavm.jso.JSBody;
|
||||
|
||||
public class JSStdoutPrintStream extends JsConsolePrintStream {
|
||||
@Override
|
||||
public void print(String s) {
|
||||
writeJs(s);
|
||||
if (PlatformDetector.isWebAssemblyGC()) {
|
||||
for (int i = 0; i < s.length(); ++i) {
|
||||
WasmGCSupport.putCharStderr(s.charAt(i));
|
||||
}
|
||||
} else {
|
||||
writeJs(s);
|
||||
}
|
||||
}
|
||||
|
||||
@JSBody(params = "b", script = "$rt_putStdout(b);")
|
||||
|
@ -56,7 +56,7 @@ public final class TSystem extends TObject {
|
||||
|
||||
public static TPrintStream out() {
|
||||
if (outCache == null) {
|
||||
if (PlatformDetector.isJavaScript()) {
|
||||
if (PlatformDetector.isJavaScript() || PlatformDetector.isWebAssemblyGC()) {
|
||||
outCache = (TPrintStream) (Object) new JSStdoutPrintStream();
|
||||
} else {
|
||||
outCache = new TPrintStream(StdoutOutputStream.INSTANCE, false);
|
||||
@ -67,7 +67,7 @@ public final class TSystem extends TObject {
|
||||
|
||||
public static TPrintStream err() {
|
||||
if (errCache == null) {
|
||||
if (PlatformDetector.isJavaScript()) {
|
||||
if (PlatformDetector.isJavaScript() || PlatformDetector.isWebAssemblyGC()) {
|
||||
errCache = (TPrintStream) (Object) new JSStderrPrintStream();
|
||||
} else {
|
||||
errCache = new TPrintStream(StderrOutputStream.INSTANCE, false);
|
||||
|
@ -19,14 +19,20 @@ import org.teavm.model.util.VariableType;
|
||||
|
||||
public class VariableNode {
|
||||
private int index;
|
||||
private int originalIndex;
|
||||
private VariableType type;
|
||||
private String name;
|
||||
|
||||
public VariableNode(int index, VariableType type) {
|
||||
this.index = index;
|
||||
this.originalIndex = index;
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
public int getOriginalIndex() {
|
||||
return originalIndex;
|
||||
}
|
||||
|
||||
public int getIndex() {
|
||||
return index;
|
||||
}
|
||||
|
@ -92,18 +92,15 @@ import org.teavm.dependency.DependencyAnalyzer;
|
||||
import org.teavm.dependency.DependencyListener;
|
||||
import org.teavm.interop.Address;
|
||||
import org.teavm.interop.Platforms;
|
||||
import org.teavm.model.BasicBlock;
|
||||
import org.teavm.model.ClassHierarchy;
|
||||
import org.teavm.model.ClassHolder;
|
||||
import org.teavm.model.ClassHolderTransformer;
|
||||
import org.teavm.model.ClassReader;
|
||||
import org.teavm.model.FieldReader;
|
||||
import org.teavm.model.FieldReference;
|
||||
import org.teavm.model.Instruction;
|
||||
import org.teavm.model.ListableClassHolderSource;
|
||||
import org.teavm.model.ListableClassReaderSource;
|
||||
import org.teavm.model.MethodDescriptor;
|
||||
import org.teavm.model.MethodHolder;
|
||||
import org.teavm.model.MethodReader;
|
||||
import org.teavm.model.MethodReference;
|
||||
import org.teavm.model.Program;
|
||||
@ -111,9 +108,6 @@ import org.teavm.model.ValueType;
|
||||
import org.teavm.model.classes.TagRegistry;
|
||||
import org.teavm.model.classes.VirtualTableBuilder;
|
||||
import org.teavm.model.classes.VirtualTableProvider;
|
||||
import org.teavm.model.instructions.CloneArrayInstruction;
|
||||
import org.teavm.model.instructions.InvocationType;
|
||||
import org.teavm.model.instructions.InvokeInstruction;
|
||||
import org.teavm.model.lowlevel.CallSiteDescriptor;
|
||||
import org.teavm.model.lowlevel.Characteristics;
|
||||
import org.teavm.model.lowlevel.ClassInitializerEliminator;
|
||||
@ -623,40 +617,11 @@ public class CTarget implements TeaVMTarget, TeaVMCHost {
|
||||
|
||||
private VirtualTableProvider createVirtualTableProvider(ListableClassHolderSource classes) {
|
||||
VirtualTableBuilder builder = new VirtualTableBuilder(classes);
|
||||
builder.setMethodsUsedAtCallSites(getMethodsUsedOnCallSites(classes));
|
||||
builder.setMethodsUsedAtCallSites(VirtualTableBuilder.getMethodsUsedOnCallSites(classes));
|
||||
builder.setMethodCalledVirtually(controller::isVirtual);
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
private Set<MethodReference> getMethodsUsedOnCallSites(ListableClassHolderSource classes) {
|
||||
Set<MethodReference> virtualMethods = new HashSet<>();
|
||||
|
||||
for (String className : classes.getClassNames()) {
|
||||
ClassHolder cls = classes.get(className);
|
||||
for (MethodHolder method : cls.getMethods()) {
|
||||
Program program = method.getProgram();
|
||||
if (program == null) {
|
||||
continue;
|
||||
}
|
||||
for (int i = 0; i < program.basicBlockCount(); ++i) {
|
||||
BasicBlock block = program.basicBlockAt(i);
|
||||
for (Instruction insn : block) {
|
||||
if (insn instanceof InvokeInstruction) {
|
||||
InvokeInstruction invoke = (InvokeInstruction) insn;
|
||||
if (invoke.getType() == InvocationType.VIRTUAL) {
|
||||
virtualMethods.add(invoke.getMethod());
|
||||
}
|
||||
} else if (insn instanceof CloneArrayInstruction) {
|
||||
virtualMethods.add(new MethodReference(Object.class, "clone", Object.class));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return virtualMethods;
|
||||
}
|
||||
|
||||
private void generateSpecialFunctions(GenerationContext context, CodeWriter writer) {
|
||||
IncludeManager includes = new SimpleIncludeManager(context.getFileNames(), writer);
|
||||
includes.init("special.c");
|
||||
|
@ -0,0 +1,25 @@
|
||||
/*
|
||||
* Copyright 2024 Alexey Andreev.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.teavm.backend.wasm;
|
||||
|
||||
import org.teavm.backend.wasm.model.WasmFunction;
|
||||
import org.teavm.model.MethodReference;
|
||||
|
||||
public interface BaseWasmFunctionRepository {
|
||||
WasmFunction forStaticMethod(MethodReference methodReference);
|
||||
|
||||
WasmFunction forInstanceMethod(MethodReference methodReference);
|
||||
}
|
@ -1,323 +0,0 @@
|
||||
/*
|
||||
* Copyright 2016 Alexey Andreev.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.teavm.backend.wasm;
|
||||
|
||||
import java.lang.reflect.Array;
|
||||
import java.math.BigInteger;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import org.teavm.model.ValueType;
|
||||
|
||||
public final class Example {
|
||||
private Example() {
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
testFibonacci();
|
||||
testClasses();
|
||||
testVirtualCall();
|
||||
testInstanceOf();
|
||||
testPrimitiveArray();
|
||||
testLazyInitialization();
|
||||
testHashCode();
|
||||
testArrayList();
|
||||
testArrayCopy();
|
||||
testArrayIsObject();
|
||||
testIsAssignableFrom();
|
||||
testExceptions();
|
||||
testArrayReflection();
|
||||
testBigInteger();
|
||||
testGC();
|
||||
}
|
||||
|
||||
private static void testBigInteger() {
|
||||
System.out.println("Running BigInteger benchmark");
|
||||
BigInteger result = BigInteger.ONE;
|
||||
for (int j = 0; j < 100; ++j) {
|
||||
long start = System.currentTimeMillis();
|
||||
|
||||
for (int k = 0; k < 5000; ++k) {
|
||||
BigInteger a = BigInteger.ZERO;
|
||||
BigInteger b = BigInteger.ONE;
|
||||
for (int i = 0; i < 1000; ++i) {
|
||||
BigInteger c = a.add(b);
|
||||
a = b;
|
||||
b = c;
|
||||
}
|
||||
result = a;
|
||||
}
|
||||
|
||||
long end = System.currentTimeMillis();
|
||||
|
||||
System.out.println("Operation took " + (end - start) + " milliseconds");
|
||||
}
|
||||
System.out.println(result.toString());
|
||||
}
|
||||
|
||||
private static void testFibonacci() {
|
||||
int a = 0;
|
||||
int b = 1;
|
||||
System.out.println("Fibonacci numbers:");
|
||||
for (int i = 0; i < 30; ++i) {
|
||||
int c = a + b;
|
||||
a = b;
|
||||
b = c;
|
||||
System.out.println(String.valueOf(a));
|
||||
}
|
||||
}
|
||||
|
||||
private static void testClasses() {
|
||||
System.out.println("A(2) + A(3) = " + (new A(2).getValue() + new A(3).getValue()));
|
||||
}
|
||||
|
||||
private static void testVirtualCall() {
|
||||
for (int i = 0; i < 4; ++i) {
|
||||
System.out.println("instance(" + i + ") = " + instance(i).foo());
|
||||
}
|
||||
|
||||
Base[] array = { new Derived1(), new Derived2() };
|
||||
System.out.println("array.length = " + array.length);
|
||||
for (Base elem : array) {
|
||||
System.out.println("array[i] = " + elem.foo());
|
||||
}
|
||||
}
|
||||
|
||||
private static void testInstanceOf() {
|
||||
System.out.println("Derived2 instanceof Base = " + (new Derived2() instanceof Base));
|
||||
System.out.println("Derived3 instanceof Base = " + (new Derived3() instanceof Base));
|
||||
System.out.println("Derived2 instanceof Derived1 = " + ((Object) new Derived2() instanceof Derived1));
|
||||
System.out.println("Derived2 instanceof A = " + ((Object) new Derived2() instanceof A));
|
||||
System.out.println("A instanceof Base = " + (new A(23) instanceof Base));
|
||||
}
|
||||
|
||||
private static void testPrimitiveArray() {
|
||||
byte[] bytes = { 5, 6, 10, 15 };
|
||||
for (byte bt : bytes) {
|
||||
System.out.println("bytes[i] = " + bt);
|
||||
}
|
||||
}
|
||||
|
||||
private static void testLazyInitialization() {
|
||||
Initialized.foo();
|
||||
Initialized.foo();
|
||||
Initialized.foo();
|
||||
}
|
||||
|
||||
private static void testHashCode() {
|
||||
Object o = new Object();
|
||||
System.out.println("hashCode1 = " + o.hashCode());
|
||||
System.out.println("hashCode1 = " + o.hashCode());
|
||||
System.out.println("hashCode2 = " + new Object().hashCode());
|
||||
System.out.println("hashCode3 = " + new Object().hashCode());
|
||||
}
|
||||
|
||||
private static void testArrayList() {
|
||||
List<Integer> list = new ArrayList<>(Arrays.asList(333, 444, 555));
|
||||
list.add(1234);
|
||||
list.remove((Integer) 444);
|
||||
|
||||
for (int item : list) {
|
||||
System.out.println("list[i] = " + item);
|
||||
}
|
||||
}
|
||||
|
||||
private static void testArrayCopy() {
|
||||
byte[] array = new byte[100];
|
||||
byte[] negatives = new byte[100];
|
||||
for (int i = 0; i < array.length; ++i) {
|
||||
array[i] = (byte) i;
|
||||
negatives[i] = (byte) (-i - 1);
|
||||
}
|
||||
System.arraycopy(negatives, 0, array, 4, 12);
|
||||
System.arraycopy(negatives, 1, array, 21, 12);
|
||||
System.arraycopy(negatives, 2, array, 35, 12);
|
||||
System.arraycopy(negatives, 1, array, 8, 3);
|
||||
System.arraycopy(array, 50, array, 54, 12);
|
||||
StringBuilder sb = new StringBuilder("arrayCopy result:");
|
||||
for (int i = 0; i < array.length; ++i) {
|
||||
sb.append(" ").append(array[i]);
|
||||
}
|
||||
System.out.println(sb.toString());
|
||||
}
|
||||
|
||||
private static void testArrayIsObject() {
|
||||
byte[] array = new byte[] { 1, 2, 3 };
|
||||
byte[] copy = array.clone();
|
||||
System.out.println("array.hashCode() = " + array.hashCode());
|
||||
System.out.println("copy.hashCode() = " + copy.hashCode());
|
||||
System.out.println("array.equals(array) = " + array.equals(array));
|
||||
System.out.println("array.equals(copy) = " + array.equals(copy));
|
||||
}
|
||||
|
||||
private static void testIsAssignableFrom() {
|
||||
System.out.println("Object.isAssignableFrom(byte[]) = "
|
||||
+ Object.class.isAssignableFrom(new byte[0].getClass()));
|
||||
System.out.println("Object[].isAssignableFrom(Integer[]) = "
|
||||
+ Object[].class.isAssignableFrom(new Integer[0].getClass()));
|
||||
System.out.println("Object[].isAssignableFrom(Integer) = "
|
||||
+ Object[].class.isAssignableFrom(Integer.class));
|
||||
System.out.println("byte[].isAssignableFrom(Object) = "
|
||||
+ byte[].class.isAssignableFrom(ValueType.Object.class));
|
||||
System.out.println("Base.isAssignableFrom(Derived1) = "
|
||||
+ Base.class.isAssignableFrom(Derived1.class));
|
||||
System.out.println("Base.isAssignableFrom(A) = "
|
||||
+ Base.class.isAssignableFrom(A.class));
|
||||
}
|
||||
|
||||
private static void testGC() {
|
||||
List<Integer> list = new ArrayList<>();
|
||||
for (int i = 0; i < 4000000; ++i) {
|
||||
list.add(i);
|
||||
if (list.size() == 1000) {
|
||||
list = new ArrayList<>();
|
||||
}
|
||||
}
|
||||
System.out.println("GC complete");
|
||||
}
|
||||
|
||||
private static void testExceptions() {
|
||||
try {
|
||||
throwsException();
|
||||
} catch (IllegalStateException e) {
|
||||
System.out.println("Caught 1: " + e.getMessage());
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
int x = 0;
|
||||
try {
|
||||
x = 1;
|
||||
doesNotThrow();
|
||||
x = 2;
|
||||
throwsException();
|
||||
x = 3;
|
||||
} catch (IllegalStateException e) {
|
||||
System.out.println("Caught 2: " + e.getMessage());
|
||||
System.out.println("x = " + x);
|
||||
}
|
||||
|
||||
try {
|
||||
throwsWithFinally();
|
||||
} catch (IllegalStateException e) {
|
||||
System.out.println("Caught 3: " + e.getMessage());
|
||||
}
|
||||
|
||||
Object[] objects = { "a", null };
|
||||
for (Object o : objects) {
|
||||
try {
|
||||
System.out.println(o.toString());
|
||||
} catch (RuntimeException e) {
|
||||
System.out.println("Caught NPE");
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void testArrayReflection() {
|
||||
Object[] arrays = new Object[] {
|
||||
new int[] { 23, 42 },
|
||||
new byte[] { (byte) 1, (byte) 2, (byte) 3 },
|
||||
new String[] { "foo", "bar" },
|
||||
};
|
||||
|
||||
for (Object array : arrays) {
|
||||
int sz = Array.getLength(array);
|
||||
System.out.println("Array type: " + array.getClass().getName() + ", length " + sz);
|
||||
for (int i = 0; i < sz; ++i) {
|
||||
Object item = Array.get(array, i);
|
||||
System.out.println(" [" + i + "] = " + item + ": " + item.getClass().getName());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void doesNotThrow() {
|
||||
}
|
||||
|
||||
private static void throwsWithFinally() {
|
||||
try {
|
||||
throwsException();
|
||||
} finally {
|
||||
System.out.println("Finally reached");
|
||||
}
|
||||
}
|
||||
|
||||
private static void throwsException() {
|
||||
throw new IllegalStateException("exception message");
|
||||
}
|
||||
|
||||
private static Base instance(int index) {
|
||||
switch (index) {
|
||||
case 0:
|
||||
return new Derived1();
|
||||
case 1:
|
||||
return new Derived2();
|
||||
case 2:
|
||||
return new Derived3();
|
||||
default:
|
||||
return new Derived4();
|
||||
}
|
||||
}
|
||||
|
||||
private static class A {
|
||||
private int value;
|
||||
|
||||
public A(int value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public int getValue() {
|
||||
return value;
|
||||
}
|
||||
}
|
||||
|
||||
interface Base {
|
||||
int foo();
|
||||
}
|
||||
|
||||
static class Derived1 implements Base {
|
||||
@Override
|
||||
public int foo() {
|
||||
return 234;
|
||||
}
|
||||
}
|
||||
|
||||
static class Derived2 implements Base {
|
||||
@Override
|
||||
public int foo() {
|
||||
return 345;
|
||||
}
|
||||
}
|
||||
|
||||
static class Derived3 extends Derived2 {
|
||||
}
|
||||
|
||||
static class Derived4 extends Derived1 {
|
||||
@Override
|
||||
public int foo() {
|
||||
return 123;
|
||||
}
|
||||
}
|
||||
|
||||
static class Initialized {
|
||||
static {
|
||||
System.out.println("Initialized.<clinit>()");
|
||||
}
|
||||
|
||||
public static void foo() {
|
||||
System.out.println("Initialized.foo()");
|
||||
}
|
||||
}
|
||||
}
|
@ -27,7 +27,7 @@ import org.teavm.model.MethodReader;
|
||||
import org.teavm.model.MethodReference;
|
||||
import org.teavm.model.ValueType;
|
||||
|
||||
public class WasmFunctionRepository {
|
||||
public class WasmFunctionRepository implements BaseWasmFunctionRepository {
|
||||
private WasmModule module;
|
||||
private WasmFunctionTypes functionTypes;
|
||||
private NameProvider nameProvider;
|
||||
@ -50,6 +50,7 @@ public class WasmFunctionRepository {
|
||||
return isStatic ? forStaticMethod(reference) : forInstanceMethod(reference);
|
||||
}
|
||||
|
||||
@Override
|
||||
public WasmFunction forStaticMethod(MethodReference reference) {
|
||||
return staticMethods.computeIfAbsent(reference, key -> {
|
||||
var wasmParams = new WasmType[key.parameterCount()];
|
||||
@ -65,6 +66,7 @@ public class WasmFunctionRepository {
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public WasmFunction forInstanceMethod(MethodReference reference) {
|
||||
return instanceMethods.computeIfAbsent(reference, key -> {
|
||||
var wasmParams = new WasmType[key.parameterCount() + 1];
|
||||
|
@ -0,0 +1,98 @@
|
||||
/*
|
||||
* Copyright 2024 Alexey Andreev.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.teavm.backend.wasm;
|
||||
|
||||
import org.teavm.backend.wasm.generate.TemporaryVariablePool;
|
||||
import org.teavm.backend.wasm.generate.gc.WasmGCDeclarationsGenerator;
|
||||
import org.teavm.backend.wasm.generate.gc.methods.WasmGCGenerationUtil;
|
||||
import org.teavm.backend.wasm.model.WasmFunction;
|
||||
import org.teavm.backend.wasm.model.WasmGlobal;
|
||||
import org.teavm.backend.wasm.model.expression.WasmCall;
|
||||
import org.teavm.backend.wasm.model.expression.WasmCallReference;
|
||||
import org.teavm.backend.wasm.model.expression.WasmExpression;
|
||||
import org.teavm.backend.wasm.model.expression.WasmFunctionReference;
|
||||
import org.teavm.backend.wasm.model.expression.WasmGetGlobal;
|
||||
import org.teavm.backend.wasm.model.expression.WasmGetLocal;
|
||||
import org.teavm.backend.wasm.model.expression.WasmInt32Constant;
|
||||
import org.teavm.backend.wasm.model.expression.WasmReturn;
|
||||
import org.teavm.backend.wasm.model.expression.WasmSetGlobal;
|
||||
import org.teavm.model.MethodReference;
|
||||
import org.teavm.model.ValueType;
|
||||
|
||||
public class WasmGCModuleGenerator {
|
||||
private final WasmGCTarget wasmGCTarget;
|
||||
private WasmGCDeclarationsGenerator declarationsGenerator;
|
||||
private WasmFunction initializer;
|
||||
private WasmGlobal initializerRef;
|
||||
|
||||
public WasmGCModuleGenerator(WasmGCTarget wasmGCTarget, WasmGCDeclarationsGenerator declarationsGenerator) {
|
||||
this.wasmGCTarget = wasmGCTarget;
|
||||
this.declarationsGenerator = declarationsGenerator;
|
||||
}
|
||||
|
||||
public void generate() {
|
||||
declarationsGenerator.generate();
|
||||
if (initializer != null) {
|
||||
fillInitializer();
|
||||
}
|
||||
}
|
||||
|
||||
private void fillInitializer() {
|
||||
declarationsGenerator.contributeToInitializer(initializer);
|
||||
initializer.getBody().add(new WasmReturn());
|
||||
}
|
||||
|
||||
public WasmFunction generateMainFunction(String entryPoint) {
|
||||
var mainFunction = declarationsGenerator.functions().forStaticMethod(new MethodReference(entryPoint,
|
||||
"main", ValueType.parse(String[].class), ValueType.VOID));
|
||||
var mainFunctionCaller = new WasmFunction(declarationsGenerator.functionTypes.of(null));
|
||||
mainFunctionCaller.getBody().add(callInitializer());
|
||||
|
||||
var tempVars = new TemporaryVariablePool(mainFunctionCaller);
|
||||
var genUtil = new WasmGCGenerationUtil(declarationsGenerator.classInfoProvider(), tempVars);
|
||||
var stringArrayType = declarationsGenerator.typeMapper()
|
||||
.mapType(ValueType.parse(String[].class))
|
||||
.asUnpackedType();
|
||||
var arrayVar = tempVars.acquire(stringArrayType);
|
||||
genUtil.allocateArray(ValueType.parse(String.class), new WasmInt32Constant(0), null,
|
||||
arrayVar, mainFunctionCaller.getBody());
|
||||
var callToMainFunction = new WasmCall(mainFunction, new WasmGetLocal(arrayVar));
|
||||
mainFunctionCaller.getBody().add(callToMainFunction);
|
||||
mainFunctionCaller.getBody().add(new WasmReturn());
|
||||
tempVars.release(arrayVar);
|
||||
|
||||
return mainFunctionCaller;
|
||||
}
|
||||
|
||||
private void createInitializer() {
|
||||
if (initializer != null) {
|
||||
return;
|
||||
}
|
||||
var functionType = declarationsGenerator.functionTypes.of(null);
|
||||
initializer = new WasmFunction(functionType);
|
||||
declarationsGenerator.module.functions.add(initializer);
|
||||
initializerRef = new WasmGlobal("teavm_initializer", functionType.getReference(),
|
||||
new WasmFunctionReference(initializer));
|
||||
declarationsGenerator.module.globals.add(initializerRef);
|
||||
initializer.getBody().add(new WasmSetGlobal(initializerRef,
|
||||
new WasmFunctionReference(declarationsGenerator.dummyInitializer())));
|
||||
}
|
||||
|
||||
private WasmExpression callInitializer() {
|
||||
createInitializer();
|
||||
return new WasmCallReference(new WasmGetGlobal(initializerRef), declarationsGenerator.functionTypes.of(null));
|
||||
}
|
||||
}
|
143
core/src/main/java/org/teavm/backend/wasm/WasmGCTarget.java
Normal file
143
core/src/main/java/org/teavm/backend/wasm/WasmGCTarget.java
Normal file
@ -0,0 +1,143 @@
|
||||
/*
|
||||
* Copyright 2024 Alexey Andreev.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.teavm.backend.wasm;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
import org.teavm.backend.wasm.gc.WasmGCDependencies;
|
||||
import org.teavm.backend.wasm.generate.gc.WasmGCDeclarationsGenerator;
|
||||
import org.teavm.backend.wasm.generators.gc.WasmGCCustomGenerators;
|
||||
import org.teavm.backend.wasm.model.WasmModule;
|
||||
import org.teavm.backend.wasm.render.WasmBinaryRenderer;
|
||||
import org.teavm.backend.wasm.render.WasmBinaryStatsCollector;
|
||||
import org.teavm.backend.wasm.render.WasmBinaryVersion;
|
||||
import org.teavm.backend.wasm.render.WasmBinaryWriter;
|
||||
import org.teavm.dependency.DependencyAnalyzer;
|
||||
import org.teavm.dependency.DependencyListener;
|
||||
import org.teavm.interop.Platforms;
|
||||
import org.teavm.model.ClassHolderTransformer;
|
||||
import org.teavm.model.ListableClassHolderSource;
|
||||
import org.teavm.model.MethodReader;
|
||||
import org.teavm.model.Program;
|
||||
import org.teavm.model.transformation.BoundCheckInsertion;
|
||||
import org.teavm.model.transformation.NullCheckFilter;
|
||||
import org.teavm.model.transformation.NullCheckInsertion;
|
||||
import org.teavm.model.util.VariableCategoryProvider;
|
||||
import org.teavm.vm.BuildTarget;
|
||||
import org.teavm.vm.TeaVMTarget;
|
||||
import org.teavm.vm.TeaVMTargetController;
|
||||
import org.teavm.vm.spi.TeaVMHostExtension;
|
||||
|
||||
public class WasmGCTarget implements TeaVMTarget {
|
||||
private TeaVMTargetController controller;
|
||||
private NullCheckInsertion nullCheckInsertion;
|
||||
private BoundCheckInsertion boundCheckInsertion = new BoundCheckInsertion();
|
||||
private boolean obfuscated;
|
||||
|
||||
public void setObfuscated(boolean obfuscated) {
|
||||
this.obfuscated = obfuscated;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setController(TeaVMTargetController controller) {
|
||||
this.controller = controller;
|
||||
nullCheckInsertion = new NullCheckInsertion(NullCheckFilter.EMPTY);
|
||||
}
|
||||
|
||||
@Override
|
||||
public VariableCategoryProvider variableCategoryProvider() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<DependencyListener> getDependencyListeners() {
|
||||
return List.of();
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<ClassHolderTransformer> getTransformers() {
|
||||
return List.of();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void contributeDependencies(DependencyAnalyzer dependencyAnalyzer) {
|
||||
new WasmGCDependencies(dependencyAnalyzer).contribute();
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<TeaVMHostExtension> getHostExtensions() {
|
||||
return List.of();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void beforeOptimizations(Program program, MethodReader method) {
|
||||
/*
|
||||
nullCheckInsertion.transformProgram(program, method.getReference());
|
||||
boundCheckInsertion.transformProgram(program, method.getReference());
|
||||
*/
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterOptimizations(Program program, MethodReader method) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public String[] getPlatformTags() {
|
||||
return new String[] { Platforms.WEBASSEMBLY_GC };
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAsyncSupported() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void emit(ListableClassHolderSource classes, BuildTarget buildTarget, String outputName) throws IOException {
|
||||
var module = new WasmModule();
|
||||
var customGenerators = new WasmGCCustomGenerators();
|
||||
var declarationsGenerator = new WasmGCDeclarationsGenerator(
|
||||
module,
|
||||
classes,
|
||||
controller::isVirtual,
|
||||
controller.getClassInitializerInfo(),
|
||||
controller.getDependencyInfo(),
|
||||
controller.getDiagnostics(),
|
||||
customGenerators
|
||||
);
|
||||
declarationsGenerator.setFriendlyToDebugger(controller.isFriendlyToDebugger());
|
||||
var moduleGenerator = new WasmGCModuleGenerator(this, declarationsGenerator);
|
||||
var mainFunction = moduleGenerator.generateMainFunction(controller.getEntryPoint());
|
||||
mainFunction.setExportName(controller.getEntryPointName());
|
||||
mainFunction.setName(controller.getEntryPointName());
|
||||
moduleGenerator.generate();
|
||||
|
||||
emitWasmFile(module, buildTarget, outputName);
|
||||
}
|
||||
|
||||
private void emitWasmFile(WasmModule module, BuildTarget buildTarget, String outputName) throws IOException {
|
||||
var binaryWriter = new WasmBinaryWriter();
|
||||
var binaryRenderer = new WasmBinaryRenderer(binaryWriter, WasmBinaryVersion.V_0x1, obfuscated,
|
||||
null, null, null, null, WasmBinaryStatsCollector.EMPTY);
|
||||
binaryRenderer.render(module);
|
||||
var data = binaryWriter.getData();
|
||||
if (!outputName.endsWith(".wasm")) {
|
||||
outputName += ".wasm";
|
||||
}
|
||||
try (var output = buildTarget.createResource(outputName)) {
|
||||
output.write(data);
|
||||
}
|
||||
}
|
||||
}
|
@ -130,7 +130,6 @@ import org.teavm.interop.Import;
|
||||
import org.teavm.interop.Platforms;
|
||||
import org.teavm.interop.StaticInit;
|
||||
import org.teavm.model.AnnotationHolder;
|
||||
import org.teavm.model.BasicBlock;
|
||||
import org.teavm.model.CallLocation;
|
||||
import org.teavm.model.ClassHierarchy;
|
||||
import org.teavm.model.ClassHolder;
|
||||
@ -139,7 +138,6 @@ import org.teavm.model.ClassReader;
|
||||
import org.teavm.model.ClassReaderSource;
|
||||
import org.teavm.model.ElementModifier;
|
||||
import org.teavm.model.FieldReference;
|
||||
import org.teavm.model.Instruction;
|
||||
import org.teavm.model.ListableClassHolderSource;
|
||||
import org.teavm.model.ListableClassReaderSource;
|
||||
import org.teavm.model.MethodDescriptor;
|
||||
@ -152,9 +150,6 @@ import org.teavm.model.analysis.ClassMetadataRequirements;
|
||||
import org.teavm.model.classes.TagRegistry;
|
||||
import org.teavm.model.classes.VirtualTableBuilder;
|
||||
import org.teavm.model.classes.VirtualTableProvider;
|
||||
import org.teavm.model.instructions.CloneArrayInstruction;
|
||||
import org.teavm.model.instructions.InvocationType;
|
||||
import org.teavm.model.instructions.InvokeInstruction;
|
||||
import org.teavm.model.lowlevel.Characteristics;
|
||||
import org.teavm.model.lowlevel.ClassInitializerEliminator;
|
||||
import org.teavm.model.lowlevel.ClassInitializerTransformer;
|
||||
@ -1075,40 +1070,11 @@ public class WasmTarget implements TeaVMTarget, TeaVMWasmHost {
|
||||
|
||||
private VirtualTableProvider createVirtualTableProvider(ListableClassHolderSource classes) {
|
||||
var builder = new VirtualTableBuilder(classes);
|
||||
builder.setMethodsUsedAtCallSites(getMethodsUsedOnCallSites(classes));
|
||||
builder.setMethodsUsedAtCallSites(VirtualTableBuilder.getMethodsUsedOnCallSites(classes));
|
||||
builder.setMethodCalledVirtually(controller::isVirtual);
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
private Set<MethodReference> getMethodsUsedOnCallSites(ListableClassHolderSource classes) {
|
||||
var virtualMethods = new HashSet<MethodReference>();
|
||||
|
||||
for (String className : classes.getClassNames()) {
|
||||
ClassHolder cls = classes.get(className);
|
||||
for (MethodHolder method : cls.getMethods()) {
|
||||
Program program = method.getProgram();
|
||||
if (program == null) {
|
||||
continue;
|
||||
}
|
||||
for (int i = 0; i < program.basicBlockCount(); ++i) {
|
||||
BasicBlock block = program.basicBlockAt(i);
|
||||
for (Instruction insn : block) {
|
||||
if (insn instanceof InvokeInstruction) {
|
||||
InvokeInstruction invoke = (InvokeInstruction) insn;
|
||||
if (invoke.getType() == InvocationType.VIRTUAL) {
|
||||
virtualMethods.add(invoke.getMethod());
|
||||
}
|
||||
} else if (insn instanceof CloneArrayInstruction) {
|
||||
virtualMethods.add(new MethodReference(Object.class, "clone", Object.class));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return virtualMethods;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String[] getPlatformTags() {
|
||||
return new String[] { Platforms.WEBASSEMBLY, Platforms.LOW_LEVEL };
|
||||
|
@ -0,0 +1,129 @@
|
||||
/*
|
||||
* Copyright 2024 Alexey Andreev.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.teavm.backend.wasm.gc;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import org.teavm.model.ClassHierarchy;
|
||||
import org.teavm.model.ClassReader;
|
||||
import org.teavm.model.MethodReference;
|
||||
import org.teavm.model.Program;
|
||||
import org.teavm.model.ValueType;
|
||||
import org.teavm.model.analysis.BaseTypeInference;
|
||||
|
||||
public class PreciseTypeInference extends BaseTypeInference<ValueType> {
|
||||
public static final ValueType OBJECT_TYPE = ValueType.object("java.lang.Object");
|
||||
private ClassHierarchy hierarchy;
|
||||
|
||||
public PreciseTypeInference(Program program, MethodReference reference, ClassHierarchy hierarchy) {
|
||||
super(program, reference);
|
||||
this.hierarchy = hierarchy;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ValueType mapType(ValueType type) {
|
||||
return type;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ValueType nullType() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ValueType merge(ValueType a, ValueType b) {
|
||||
if (a == null) {
|
||||
return b;
|
||||
} else if (b == null) {
|
||||
return a;
|
||||
} else {
|
||||
if (a instanceof ValueType.Primitive && b instanceof ValueType.Primitive) {
|
||||
if (a != b) {
|
||||
return OBJECT_TYPE;
|
||||
} else {
|
||||
return a;
|
||||
}
|
||||
} else if (a instanceof ValueType.Array) {
|
||||
if (b instanceof ValueType.Array) {
|
||||
var p = ((ValueType.Array) a).getItemType();
|
||||
var q = ((ValueType.Array) b).getItemType();
|
||||
return ValueType.arrayOf(merge(p, q));
|
||||
} else {
|
||||
return OBJECT_TYPE;
|
||||
}
|
||||
} else if (b instanceof ValueType.Array) {
|
||||
return OBJECT_TYPE;
|
||||
} else if (a instanceof ValueType.Object) {
|
||||
if (b instanceof ValueType.Object) {
|
||||
var p = ((ValueType.Object) a).getClassName();
|
||||
var q = ((ValueType.Object) b).getClassName();
|
||||
if (p.equals(q)) {
|
||||
return a;
|
||||
}
|
||||
var first = hierarchy.getClassSource().get(p);
|
||||
if (first == null) {
|
||||
p = "java.lang.Object";
|
||||
}
|
||||
var second = hierarchy.getClassSource().get(q);
|
||||
if (second == null) {
|
||||
q = "java.lang.Object";
|
||||
}
|
||||
if (hierarchy.isSuperType(p, q, false)) {
|
||||
return a;
|
||||
} else if (hierarchy.isSuperType(q, p, false)) {
|
||||
return b;
|
||||
}
|
||||
return ValueType.object(findCommonSuperclass(first, second));
|
||||
} else {
|
||||
return OBJECT_TYPE;
|
||||
}
|
||||
} else {
|
||||
return OBJECT_TYPE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private String findCommonSuperclass(ClassReader a, ClassReader b) {
|
||||
var firstPath = findPathToRoot(a);
|
||||
Collections.reverse(firstPath);
|
||||
var secondPath = findPathToRoot(b);
|
||||
Collections.reverse(secondPath);
|
||||
if (firstPath.get(0) != secondPath.get(0)) {
|
||||
return "java.lang.Object";
|
||||
}
|
||||
var max = Math.max(firstPath.size(), secondPath.size());
|
||||
var index = 1;
|
||||
while (index < max && firstPath.get(index) == secondPath.get(index)) {
|
||||
++index;
|
||||
}
|
||||
return firstPath.get(index).getName();
|
||||
}
|
||||
|
||||
private List<ClassReader> findPathToRoot(ClassReader cls) {
|
||||
var path = new ArrayList<ClassReader>();
|
||||
while (cls != null) {
|
||||
path.add(cls);
|
||||
cls = cls.getParent() != null ? hierarchy.getClassSource().get(cls.getParent()) : null;
|
||||
}
|
||||
return path;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ValueType elementType(ValueType valueType) {
|
||||
return ((ValueType.Array) valueType).getItemType();
|
||||
}
|
||||
}
|
@ -0,0 +1,63 @@
|
||||
/*
|
||||
* Copyright 2024 Alexey Andreev.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.teavm.backend.wasm.gc;
|
||||
|
||||
import java.util.Arrays;
|
||||
import org.teavm.backend.wasm.WasmRuntime;
|
||||
import org.teavm.backend.wasm.generate.gc.strings.WasmGCStringPool;
|
||||
import org.teavm.backend.wasm.runtime.WasmGCSupport;
|
||||
import org.teavm.dependency.DependencyAnalyzer;
|
||||
import org.teavm.model.MethodReference;
|
||||
|
||||
public class WasmGCDependencies {
|
||||
private DependencyAnalyzer analyzer;
|
||||
|
||||
public WasmGCDependencies(DependencyAnalyzer analyzer) {
|
||||
this.analyzer = analyzer;
|
||||
}
|
||||
|
||||
public void contribute() {
|
||||
contributeMathUtils();
|
||||
contributeExceptionUtils();
|
||||
contributeInitializerUtils();
|
||||
}
|
||||
|
||||
private void contributeMathUtils() {
|
||||
for (var type : Arrays.asList(int.class, long.class, float.class, double.class)) {
|
||||
var method = new MethodReference(WasmRuntime.class, "compare", type, type, int.class);
|
||||
analyzer.linkMethod(method).use();
|
||||
}
|
||||
for (var type : Arrays.asList(int.class, long.class)) {
|
||||
var method = new MethodReference(WasmRuntime.class, "compareUnsigned", type, type, int.class);
|
||||
analyzer.linkMethod(method).use();
|
||||
}
|
||||
|
||||
for (var type : Arrays.asList(float.class, double.class)) {
|
||||
var method = new MethodReference(WasmRuntime.class, "remainder", type, type, type);
|
||||
analyzer.linkMethod(method).use();
|
||||
}
|
||||
}
|
||||
|
||||
private void contributeExceptionUtils() {
|
||||
analyzer.linkMethod(new MethodReference(WasmGCSupport.class, "npe", NullPointerException.class));
|
||||
analyzer.linkMethod(new MethodReference(WasmGCSupport.class, "aiiobe", ArrayIndexOutOfBoundsException.class));
|
||||
analyzer.linkMethod(new MethodReference(WasmGCSupport.class, "cce", ClassCastException.class));
|
||||
}
|
||||
|
||||
private void contributeInitializerUtils() {
|
||||
analyzer.linkMethod(new MethodReference(WasmGCStringPool.class, "nextCharArray", char[].class));
|
||||
}
|
||||
}
|
@ -0,0 +1,45 @@
|
||||
/*
|
||||
* Copyright 2024 Alexey Andreev.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.teavm.backend.wasm.gc;
|
||||
|
||||
import org.teavm.model.ClassHierarchy;
|
||||
import org.teavm.model.MethodReference;
|
||||
import org.teavm.model.Program;
|
||||
import org.teavm.model.util.VariableCategoryProvider;
|
||||
|
||||
public class WasmGCVariableCategoryProvider implements VariableCategoryProvider {
|
||||
private ClassHierarchy hierarchy;
|
||||
private PreciseTypeInference inference;
|
||||
|
||||
public WasmGCVariableCategoryProvider(ClassHierarchy hierarchy) {
|
||||
this.hierarchy = hierarchy;
|
||||
}
|
||||
|
||||
public PreciseTypeInference getTypeInference() {
|
||||
return inference;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object[] getCategories(Program program, MethodReference method) {
|
||||
inference = new PreciseTypeInference(program, method, hierarchy);
|
||||
var result = new Object[program.variableCount()];
|
||||
for (int i = 0; i < program.variableCount(); ++i) {
|
||||
var type = inference.typeOf(program.variableAt(i));
|
||||
result[i] = type != null ? type : PreciseTypeInference.OBJECT_TYPE;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
@ -90,7 +90,7 @@ public class WasmGenerationContext implements BaseWasmGenerationContext {
|
||||
}
|
||||
|
||||
@Override
|
||||
public ClassReaderSource classSource() {
|
||||
public ClassReaderSource classes() {
|
||||
return classSource;
|
||||
}
|
||||
|
||||
|
@ -15,17 +15,17 @@
|
||||
*/
|
||||
package org.teavm.backend.wasm.generate.common.methods;
|
||||
|
||||
import org.teavm.backend.wasm.WasmFunctionRepository;
|
||||
import org.teavm.backend.wasm.BaseWasmFunctionRepository;
|
||||
import org.teavm.backend.wasm.WasmFunctionTypes;
|
||||
import org.teavm.backend.wasm.model.WasmTag;
|
||||
import org.teavm.model.ClassReaderSource;
|
||||
|
||||
public interface BaseWasmGenerationContext {
|
||||
WasmFunctionRepository functions();
|
||||
BaseWasmFunctionRepository functions();
|
||||
|
||||
WasmFunctionTypes functionTypes();
|
||||
|
||||
WasmTag getExceptionTag();
|
||||
|
||||
ClassReaderSource classSource();
|
||||
ClassReaderSource classes();
|
||||
}
|
||||
|
@ -832,9 +832,11 @@ public abstract class BaseWasmGenerationVisitor implements StatementVisitor, Exp
|
||||
|
||||
protected WasmExpression generateInvocation(InvocationExpr expr, CallSiteIdentifier callSiteId) {
|
||||
if (expr.getType() == InvocationType.STATIC || expr.getType() == InvocationType.SPECIAL) {
|
||||
var method = context.classSource().resolve(expr.getMethod());
|
||||
var method = context.classes().resolve(expr.getMethod());
|
||||
var reference = method != null ? method.getReference() : expr.getMethod();
|
||||
var function = context.functions().forMethod(reference, expr.getType() == InvocationType.STATIC);
|
||||
var function = expr.getType() == InvocationType.STATIC
|
||||
? context.functions().forStaticMethod(reference)
|
||||
: context.functions().forInstanceMethod(reference);
|
||||
|
||||
var call = new WasmCall(function);
|
||||
for (var argument : expr.getArguments()) {
|
||||
|
@ -0,0 +1,143 @@
|
||||
/*
|
||||
* Copyright 2024 Alexey Andreev.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.teavm.backend.wasm.generate.gc;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.function.Predicate;
|
||||
import org.teavm.backend.wasm.BaseWasmFunctionRepository;
|
||||
import org.teavm.backend.wasm.WasmFunctionTypes;
|
||||
import org.teavm.backend.wasm.generate.WasmNameProvider;
|
||||
import org.teavm.backend.wasm.generate.gc.classes.WasmGCClassGenerator;
|
||||
import org.teavm.backend.wasm.generate.gc.classes.WasmGCClassInfoProvider;
|
||||
import org.teavm.backend.wasm.generate.gc.classes.WasmGCSupertypeFunctionProvider;
|
||||
import org.teavm.backend.wasm.generate.gc.classes.WasmGCTypeMapper;
|
||||
import org.teavm.backend.wasm.generate.gc.methods.WasmGCCustomGeneratorProvider;
|
||||
import org.teavm.backend.wasm.generate.gc.methods.WasmGCMethodGenerator;
|
||||
import org.teavm.backend.wasm.model.WasmFunction;
|
||||
import org.teavm.backend.wasm.model.WasmModule;
|
||||
import org.teavm.dependency.DependencyInfo;
|
||||
import org.teavm.diagnostics.Diagnostics;
|
||||
import org.teavm.model.ClassHierarchy;
|
||||
import org.teavm.model.ListableClassHolderSource;
|
||||
import org.teavm.model.MethodReference;
|
||||
import org.teavm.model.analysis.ClassInitializerInfo;
|
||||
import org.teavm.model.analysis.ClassMetadataRequirements;
|
||||
import org.teavm.model.classes.TagRegistry;
|
||||
import org.teavm.model.classes.VirtualTableBuilder;
|
||||
import org.teavm.model.classes.VirtualTableProvider;
|
||||
|
||||
public class WasmGCDeclarationsGenerator {
|
||||
public final ClassHierarchy hierarchy;
|
||||
public final WasmModule module;
|
||||
public final WasmFunctionTypes functionTypes;
|
||||
private final WasmGCClassGenerator classGenerator;
|
||||
private final WasmGCMethodGenerator methodGenerator;
|
||||
|
||||
public WasmGCDeclarationsGenerator(
|
||||
WasmModule module,
|
||||
ListableClassHolderSource classes,
|
||||
Predicate<MethodReference> virtualMethods,
|
||||
ClassInitializerInfo classInitializerInfo,
|
||||
DependencyInfo dependencyInfo,
|
||||
Diagnostics diagnostics,
|
||||
WasmGCCustomGeneratorProvider customGenerators
|
||||
) {
|
||||
this.module = module;
|
||||
hierarchy = new ClassHierarchy(classes);
|
||||
var virtualTables = createVirtualTableProvider(classes, virtualMethods);
|
||||
functionTypes = new WasmFunctionTypes(module);
|
||||
var names = new WasmNameProvider();
|
||||
methodGenerator = new WasmGCMethodGenerator(
|
||||
module,
|
||||
hierarchy,
|
||||
classes,
|
||||
virtualTables,
|
||||
classInitializerInfo,
|
||||
functionTypes,
|
||||
names,
|
||||
diagnostics,
|
||||
customGenerators
|
||||
);
|
||||
var tags = new TagRegistry(classes, hierarchy);
|
||||
var metadataRequirements = new ClassMetadataRequirements(dependencyInfo);
|
||||
classGenerator = new WasmGCClassGenerator(
|
||||
module,
|
||||
classes,
|
||||
functionTypes,
|
||||
tags,
|
||||
metadataRequirements,
|
||||
virtualTables,
|
||||
methodGenerator,
|
||||
names,
|
||||
classInitializerInfo
|
||||
);
|
||||
methodGenerator.setClassInfoProvider(classGenerator);
|
||||
methodGenerator.setStrings(classGenerator.strings);
|
||||
methodGenerator.setSupertypeFunctions(classGenerator.getSupertypeProvider());
|
||||
methodGenerator.setStandardClasses(classGenerator.standardClasses);
|
||||
methodGenerator.setTypeMapper(classGenerator.typeMapper);
|
||||
}
|
||||
|
||||
public void setFriendlyToDebugger(boolean friendlyToDebugger) {
|
||||
methodGenerator.setFriendlyToDebugger(friendlyToDebugger);
|
||||
}
|
||||
|
||||
public WasmGCClassInfoProvider classInfoProvider() {
|
||||
return classGenerator;
|
||||
}
|
||||
|
||||
public WasmGCTypeMapper typeMapper() {
|
||||
return classGenerator.typeMapper;
|
||||
}
|
||||
|
||||
public BaseWasmFunctionRepository functions() {
|
||||
return methodGenerator;
|
||||
}
|
||||
|
||||
public WasmGCSupertypeFunctionProvider supertypeFunctions() {
|
||||
return classGenerator.getSupertypeProvider();
|
||||
}
|
||||
|
||||
public void generate() {
|
||||
boolean somethingGenerated;
|
||||
do {
|
||||
somethingGenerated = false;
|
||||
somethingGenerated |= methodGenerator.process();
|
||||
somethingGenerated |= classGenerator.process();
|
||||
} while (somethingGenerated);
|
||||
}
|
||||
|
||||
public void contributeToInitializer(WasmFunction function) {
|
||||
classGenerator.contributeToInitializer(function);
|
||||
var contributors = List.of(classGenerator, classGenerator.strings);
|
||||
for (var contributor : contributors) {
|
||||
contributor.contributeToInitializerDefinitions(function);
|
||||
contributor.contributeToInitializer(function);
|
||||
}
|
||||
}
|
||||
|
||||
private static VirtualTableProvider createVirtualTableProvider(ListableClassHolderSource classes,
|
||||
Predicate<MethodReference> virtualMethods) {
|
||||
var builder = new VirtualTableBuilder(classes);
|
||||
builder.setMethodsUsedAtCallSites(VirtualTableBuilder.getMethodsUsedOnCallSites(classes));
|
||||
builder.setMethodCalledVirtually(virtualMethods);
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
public WasmFunction dummyInitializer() {
|
||||
return methodGenerator.getDummyInitializer();
|
||||
}
|
||||
}
|
@ -13,7 +13,7 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.teavm.backend.wasm.generate.gc.initialization;
|
||||
package org.teavm.backend.wasm.generate.gc;
|
||||
|
||||
import org.teavm.backend.wasm.model.WasmFunction;
|
||||
|
@ -17,13 +17,18 @@ package org.teavm.backend.wasm.generate.gc.classes;
|
||||
|
||||
import com.carrotsearch.hppc.ObjectIntHashMap;
|
||||
import com.carrotsearch.hppc.ObjectIntMap;
|
||||
import java.util.ArrayDeque;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Queue;
|
||||
import java.util.function.Consumer;
|
||||
import org.teavm.backend.lowlevel.generate.NameProvider;
|
||||
import org.teavm.backend.wasm.BaseWasmFunctionRepository;
|
||||
import org.teavm.backend.wasm.WasmFunctionTypes;
|
||||
import org.teavm.backend.wasm.generate.gc.initialization.WasmGCInitializerContributor;
|
||||
import org.teavm.backend.wasm.generate.gc.methods.WasmGCFunctionProvider;
|
||||
import org.teavm.backend.wasm.generate.gc.WasmGCInitializerContributor;
|
||||
import org.teavm.backend.wasm.generate.gc.strings.WasmGCStringPool;
|
||||
import org.teavm.backend.wasm.model.WasmArray;
|
||||
import org.teavm.backend.wasm.model.WasmFunction;
|
||||
@ -70,17 +75,20 @@ public class WasmGCClassGenerator implements WasmGCClassInfoProvider, WasmGCInit
|
||||
private TagRegistry tagRegistry;
|
||||
private ClassMetadataRequirements metadataRequirements;
|
||||
private VirtualTableProvider virtualTables;
|
||||
private WasmGCFunctionProvider functionProvider;
|
||||
private BaseWasmFunctionRepository functionProvider;
|
||||
private Map<ValueType, WasmGCClassInfo> classInfoMap = new LinkedHashMap<>();
|
||||
private Queue<WasmGCClassInfo> classInfoQueue = new ArrayDeque<>();
|
||||
private ObjectIntMap<FieldReference> fieldIndexes = new ObjectIntHashMap<>();
|
||||
private ObjectIntMap<MethodReference> methodIndexes = new ObjectIntHashMap<>();
|
||||
private Map<FieldReference, WasmGlobal> staticFieldLocations = new HashMap<>();
|
||||
private List<Consumer<WasmFunction>> staticFieldInitializers = new ArrayList<>();
|
||||
private ClassInitializerInfo classInitializerInfo;
|
||||
|
||||
public final WasmGCStringPool strings;
|
||||
public final WasmGCStandardClasses standardClasses;
|
||||
private final WasmGCTypeMapper typeMapper;
|
||||
public final WasmGCTypeMapper typeMapper;
|
||||
private final NameProvider names;
|
||||
private WasmFunction initializer;
|
||||
private List<WasmExpression> initializerFunctionStatements = new ArrayList<>();
|
||||
private WasmFunction createPrimitiveClassFunction;
|
||||
private WasmFunction createArrayClassFunction;
|
||||
private final WasmGCSupertypeFunctionGenerator supertypeGenerator;
|
||||
@ -97,7 +105,7 @@ public class WasmGCClassGenerator implements WasmGCClassInfoProvider, WasmGCInit
|
||||
public WasmGCClassGenerator(WasmModule module, ClassReaderSource classSource,
|
||||
WasmFunctionTypes functionTypes, TagRegistry tagRegistry,
|
||||
ClassMetadataRequirements metadataRequirements, VirtualTableProvider virtualTables,
|
||||
WasmGCFunctionProvider functionProvider, NameProvider names,
|
||||
BaseWasmFunctionRepository functionProvider, NameProvider names,
|
||||
ClassInitializerInfo classInitializerInfo) {
|
||||
this.module = module;
|
||||
this.classSource = classSource;
|
||||
@ -114,6 +122,22 @@ public class WasmGCClassGenerator implements WasmGCClassInfoProvider, WasmGCInit
|
||||
typeMapper = new WasmGCTypeMapper(this);
|
||||
}
|
||||
|
||||
public WasmGCSupertypeFunctionProvider getSupertypeProvider() {
|
||||
return supertypeGenerator;
|
||||
}
|
||||
|
||||
public boolean process() {
|
||||
if (classInfoQueue.isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
while (!classInfoQueue.isEmpty()) {
|
||||
var classInfo = classInfoQueue.remove();
|
||||
classInfo.initializer.accept(initializerFunctionStatements);
|
||||
classInfo.initializer = null;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void contributeToInitializerDefinitions(WasmFunction function) {
|
||||
for (var classInfo : classInfoMap.values()) {
|
||||
@ -125,8 +149,9 @@ public class WasmGCClassGenerator implements WasmGCClassInfoProvider, WasmGCInit
|
||||
@Override
|
||||
public void contributeToInitializer(WasmFunction function) {
|
||||
var classClass = standardClasses.classClass();
|
||||
function.getBody().addAll(initializerFunctionStatements);
|
||||
initializerFunctionStatements.clear();
|
||||
for (var classInfo : classInfoMap.values()) {
|
||||
classInfo.initializer.accept(function.getBody());
|
||||
var supertypeFunction = supertypeGenerator.getIsSupertypeFunction(classInfo.getValueType());
|
||||
function.getBody().add(setClassField(classInfo, classSupertypeFunctionOffset,
|
||||
new WasmFunctionReference(supertypeFunction)));
|
||||
@ -134,12 +159,15 @@ public class WasmGCClassGenerator implements WasmGCClassInfoProvider, WasmGCInit
|
||||
new WasmGetGlobal(classClass.pointer)));
|
||||
if (classInfo.initializerPointer != null) {
|
||||
var className = ((ValueType.Object) classInfo.getValueType()).getClassName();
|
||||
var initFunction = functionProvider.getStaticFunction(new MethodReference(className,
|
||||
var initFunction = functionProvider.forStaticMethod(new MethodReference(className,
|
||||
CLINIT_METHOD_DESC));
|
||||
function.getBody().add(new WasmSetGlobal(classInfo.initializerPointer,
|
||||
new WasmFunctionReference(initFunction)));
|
||||
}
|
||||
}
|
||||
for (var consumer : staticFieldInitializers) {
|
||||
consumer.accept(function);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -147,6 +175,7 @@ public class WasmGCClassGenerator implements WasmGCClassInfoProvider, WasmGCInit
|
||||
var classInfo = classInfoMap.get(type);
|
||||
if (classInfo == null) {
|
||||
classInfo = new WasmGCClassInfo(type);
|
||||
classInfoQueue.add(classInfo);
|
||||
classInfoMap.put(type, classInfo);
|
||||
if (!(type instanceof ValueType.Primitive)) {
|
||||
var name = type instanceof ValueType.Object
|
||||
@ -154,6 +183,7 @@ public class WasmGCClassGenerator implements WasmGCClassInfoProvider, WasmGCInit
|
||||
: null;
|
||||
classInfo.structure = new WasmStructure(name);
|
||||
classInfo.structure.getFields().add(standardClasses.classClass().getType().asStorage());
|
||||
module.types.add(classInfo.structure);
|
||||
fillFields(classInfo.structure.getFields(), type);
|
||||
}
|
||||
var pointerName = names.forClassInstance(type);
|
||||
@ -241,6 +271,7 @@ public class WasmGCClassGenerator implements WasmGCClassInfoProvider, WasmGCInit
|
||||
var clinitType = functionTypes.of(null);
|
||||
classInfo.initializerPointer = new WasmGlobal(null, clinitType.getReference(),
|
||||
new WasmNullConstant(clinitType.getReference()));
|
||||
module.globals.add(classInfo.initializerPointer);
|
||||
}
|
||||
}
|
||||
classInfo.initializer = target -> {
|
||||
@ -276,7 +307,7 @@ public class WasmGCClassGenerator implements WasmGCClassInfoProvider, WasmGCInit
|
||||
for (var method : virtualTable.getMethods()) {
|
||||
var entry = virtualTable.getEntry(method);
|
||||
if (entry != null && entry.getImplementor() != null) {
|
||||
var function = functionProvider.getMemberFunction(entry.getImplementor());
|
||||
var function = functionProvider.forInstanceMethod(entry.getImplementor());
|
||||
if (!origin.equals(entry.getImplementor().getClassName())) {
|
||||
var functionType = getFunctionType(virtualTable.getClassName(), method);
|
||||
var wrapperFunction = new WasmFunction(functionType);
|
||||
@ -361,6 +392,33 @@ public class WasmGCClassGenerator implements WasmGCClassInfoProvider, WasmGCInit
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public WasmGlobal getStaticFieldLocation(FieldReference fieldRef) {
|
||||
return staticFieldLocations.computeIfAbsent(fieldRef, this::generateStaticFieldLocation);
|
||||
}
|
||||
|
||||
private WasmGlobal generateStaticFieldLocation(FieldReference fieldRef) {
|
||||
ValueType javaType = null;
|
||||
Object initValue = null;
|
||||
var cls = classSource.get(fieldRef.getClassName());
|
||||
if (cls != null) {
|
||||
var field = cls.getField(fieldRef.getFieldName());
|
||||
if (field != null) {
|
||||
javaType = field.getType();
|
||||
initValue = field.getInitialValue();
|
||||
}
|
||||
}
|
||||
if (javaType == null) {
|
||||
javaType = ValueType.object("java.lang.Object");
|
||||
}
|
||||
|
||||
var type = typeMapper.mapType(javaType).asUnpackedType();
|
||||
var global = new WasmGlobal(names.forStaticField(fieldRef), type, WasmExpression.defaultValueOfType(type));
|
||||
module.globals.add(global);
|
||||
|
||||
return global;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getVirtualMethodIndex(MethodReference methodRef) {
|
||||
var result = methodIndexes.getOrDefault(methodRef, -1);
|
||||
@ -442,13 +500,14 @@ public class WasmGCClassGenerator implements WasmGCClassInfoProvider, WasmGCInit
|
||||
);
|
||||
var function = new WasmFunction(functionType);
|
||||
function.setName("_teavm_fill_primitive_class_");
|
||||
module.functions.add(function);
|
||||
|
||||
var targetVar = new WasmLocal(standardClasses.classClass().getType(), "target");
|
||||
var nameVar = new WasmLocal(standardClasses.objectClass().getType(), "name");
|
||||
var kindVar = new WasmLocal(WasmType.INT32, "kind");
|
||||
function.getLocalVariables().add(targetVar);
|
||||
function.getLocalVariables().add(nameVar);
|
||||
function.getLocalVariables().add(kindVar);
|
||||
function.add(targetVar);
|
||||
function.add(nameVar);
|
||||
function.add(kindVar);
|
||||
|
||||
var flagsExpr = new WasmIntBinary(
|
||||
WasmIntType.INT32,
|
||||
@ -497,12 +556,13 @@ public class WasmGCClassGenerator implements WasmGCClassInfoProvider, WasmGCInit
|
||||
standardClasses.classClass().getType()
|
||||
);
|
||||
var function = new WasmFunction(functionType);
|
||||
module.functions.add(function);
|
||||
function.setName("_teavm_fill_array_class_");
|
||||
|
||||
var targetVar = new WasmLocal(standardClasses.classClass().getType(), "target");
|
||||
var itemVar = new WasmLocal(standardClasses.classClass().getType(), "item");
|
||||
function.getLocalVariables().add(targetVar);
|
||||
function.getLocalVariables().add(itemVar);
|
||||
function.add(targetVar);
|
||||
function.add(itemVar);
|
||||
|
||||
function.getBody().add(new WasmStructSet(
|
||||
standardClasses.classClass().getStructure(),
|
||||
@ -538,15 +598,6 @@ public class WasmGCClassGenerator implements WasmGCClassInfoProvider, WasmGCInit
|
||||
}
|
||||
|
||||
|
||||
private WasmFunction getInitializer() {
|
||||
if (initializer == null) {
|
||||
initializer = new WasmFunction(functionTypes.of(null));
|
||||
initializer.setName("_teavm_init_classes_");
|
||||
module.functions.add(initializer);
|
||||
}
|
||||
return initializer;
|
||||
}
|
||||
|
||||
private WasmExpression setClassField(WasmGCClassInfo classInfo, int fieldIndex, WasmExpression value) {
|
||||
return new WasmStructSet(
|
||||
standardClasses.classClass().getStructure(),
|
||||
|
@ -15,6 +15,7 @@
|
||||
*/
|
||||
package org.teavm.backend.wasm.generate.gc.classes;
|
||||
|
||||
import org.teavm.backend.wasm.model.WasmGlobal;
|
||||
import org.teavm.model.FieldReference;
|
||||
import org.teavm.model.MethodReference;
|
||||
import org.teavm.model.ValueType;
|
||||
@ -22,12 +23,15 @@ import org.teavm.model.ValueType;
|
||||
public interface WasmGCClassInfoProvider {
|
||||
int CLASS_FIELD_OFFSET = 0;
|
||||
int MONITOR_FIELD_OFFSET = 1;
|
||||
int CUSTOM_FIELD_OFFSETS = 2;
|
||||
int ARRAY_DATA_FIELD_OFFSET = 2;
|
||||
|
||||
WasmGCClassInfo getClassInfo(ValueType type);
|
||||
|
||||
int getFieldIndex(FieldReference fieldRef);
|
||||
|
||||
WasmGlobal getStaticFieldLocation(FieldReference fieldRef);
|
||||
|
||||
int getVirtualMethodIndex(MethodReference methodRef);
|
||||
|
||||
default WasmGCClassInfo getClassInfo(String name) {
|
||||
|
@ -15,8 +15,6 @@
|
||||
*/
|
||||
package org.teavm.backend.wasm.generate.gc.classes;
|
||||
|
||||
import com.carrotsearch.hppc.ObjectIntHashMap;
|
||||
import com.carrotsearch.hppc.ObjectIntMap;
|
||||
import java.util.Comparator;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
@ -45,8 +43,7 @@ import org.teavm.backend.wasm.model.expression.WasmStructGet;
|
||||
import org.teavm.model.ValueType;
|
||||
import org.teavm.model.classes.TagRegistry;
|
||||
|
||||
public class WasmGCSupertypeFunctionGenerator {
|
||||
private ObjectIntMap<ValueType> tableIndexes = new ObjectIntHashMap<>();
|
||||
public class WasmGCSupertypeFunctionGenerator implements WasmGCSupertypeFunctionProvider {
|
||||
private Map<ValueType, WasmFunction> functions = new HashMap<>();
|
||||
private WasmModule module;
|
||||
private WasmGCClassGenerator classGenerator;
|
||||
@ -69,6 +66,7 @@ public class WasmGCSupertypeFunctionGenerator {
|
||||
this.functionTypes = functionTypes;
|
||||
}
|
||||
|
||||
@Override
|
||||
public WasmFunction getIsSupertypeFunction(ValueType type) {
|
||||
var result = functions.get(type);
|
||||
if (result == null) {
|
||||
|
@ -0,0 +1,23 @@
|
||||
/*
|
||||
* Copyright 2024 Alexey Andreev.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.teavm.backend.wasm.generate.gc.classes;
|
||||
|
||||
import org.teavm.backend.wasm.model.WasmFunction;
|
||||
import org.teavm.model.ValueType;
|
||||
|
||||
public interface WasmGCSupertypeFunctionProvider {
|
||||
WasmFunction getIsSupertypeFunction(ValueType type);
|
||||
}
|
@ -15,11 +15,9 @@
|
||||
*/
|
||||
package org.teavm.backend.wasm.generate.gc.methods;
|
||||
|
||||
import org.teavm.backend.wasm.model.WasmFunction;
|
||||
import org.teavm.backend.wasm.generators.gc.WasmGCCustomGenerator;
|
||||
import org.teavm.model.MethodReference;
|
||||
|
||||
public interface WasmGCFunctionProvider {
|
||||
WasmFunction getMemberFunction(MethodReference methodRef);
|
||||
|
||||
WasmFunction getStaticFunction(MethodReference methodRef);
|
||||
public interface WasmGCCustomGeneratorProvider {
|
||||
WasmGCCustomGenerator get(MethodReference method);
|
||||
}
|
@ -13,13 +13,14 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.teavm.backend.wasm.generate.gc;
|
||||
package org.teavm.backend.wasm.generate.gc.methods;
|
||||
|
||||
import org.teavm.backend.wasm.WasmFunctionRepository;
|
||||
import org.teavm.backend.wasm.BaseWasmFunctionRepository;
|
||||
import org.teavm.backend.wasm.WasmFunctionTypes;
|
||||
import org.teavm.backend.wasm.generate.common.methods.BaseWasmGenerationContext;
|
||||
import org.teavm.backend.wasm.generate.gc.classes.WasmGCClassInfoProvider;
|
||||
import org.teavm.backend.wasm.generate.gc.classes.WasmGCStandardClasses;
|
||||
import org.teavm.backend.wasm.generate.gc.classes.WasmGCSupertypeFunctionProvider;
|
||||
import org.teavm.backend.wasm.generate.gc.classes.WasmGCTypeMapper;
|
||||
import org.teavm.backend.wasm.generate.gc.strings.WasmGCStringProvider;
|
||||
import org.teavm.backend.wasm.model.WasmFunction;
|
||||
@ -39,20 +40,33 @@ public class WasmGCGenerationContext implements BaseWasmGenerationContext {
|
||||
private WasmGCStringProvider strings;
|
||||
private VirtualTableProvider virtualTables;
|
||||
private WasmGCTypeMapper typeMapper;
|
||||
private WasmFunctionTypes functionTypes;
|
||||
private ClassReaderSource classes;
|
||||
private BaseWasmFunctionRepository functions;
|
||||
private WasmGCSupertypeFunctionProvider supertypeFunctions;
|
||||
private WasmGCCustomGeneratorProvider customGenerators;
|
||||
private WasmFunction npeMethod;
|
||||
private WasmFunction aaiobeMethod;
|
||||
private WasmFunction cceMethod;
|
||||
private WasmGlobal exceptionGlobal;
|
||||
private WasmTag exceptionTag;
|
||||
|
||||
public WasmGCGenerationContext(WasmModule module, WasmGCClassInfoProvider classInfoProvider,
|
||||
WasmGCStandardClasses standardClasses, WasmGCStringProvider strings, VirtualTableProvider virtualTables,
|
||||
WasmGCTypeMapper typeMapper) {
|
||||
public WasmGCGenerationContext(WasmModule module, VirtualTableProvider virtualTables,
|
||||
WasmGCTypeMapper typeMapper, WasmFunctionTypes functionTypes, ClassReaderSource classes,
|
||||
BaseWasmFunctionRepository functions, WasmGCSupertypeFunctionProvider supertypeFunctions,
|
||||
WasmGCClassInfoProvider classInfoProvider, WasmGCStandardClasses standardClasses,
|
||||
WasmGCStringProvider strings, WasmGCCustomGeneratorProvider customGenerators) {
|
||||
this.module = module;
|
||||
this.virtualTables = virtualTables;
|
||||
this.typeMapper = typeMapper;
|
||||
this.functionTypes = functionTypes;
|
||||
this.classes = classes;
|
||||
this.functions = functions;
|
||||
this.supertypeFunctions = supertypeFunctions;
|
||||
this.classInfoProvider = classInfoProvider;
|
||||
this.standardClasses = standardClasses;
|
||||
this.strings = strings;
|
||||
this.virtualTables = virtualTables;
|
||||
this.typeMapper = typeMapper;
|
||||
this.customGenerators = customGenerators;
|
||||
}
|
||||
|
||||
public WasmGCClassInfoProvider classInfoProvider() {
|
||||
@ -76,23 +90,31 @@ public class WasmGCGenerationContext implements BaseWasmGenerationContext {
|
||||
}
|
||||
|
||||
@Override
|
||||
public WasmFunctionRepository functions() {
|
||||
return null;
|
||||
public BaseWasmFunctionRepository functions() {
|
||||
return functions;
|
||||
}
|
||||
|
||||
public WasmGCSupertypeFunctionProvider supertypeFunctions() {
|
||||
return supertypeFunctions;
|
||||
}
|
||||
|
||||
@Override
|
||||
public WasmFunctionTypes functionTypes() {
|
||||
return null;
|
||||
return functionTypes;
|
||||
}
|
||||
|
||||
@Override
|
||||
public WasmTag getExceptionTag() {
|
||||
return null;
|
||||
if (exceptionTag == null) {
|
||||
exceptionTag = new WasmTag(functionTypes.of(null));
|
||||
module.tags.add(exceptionTag);
|
||||
}
|
||||
return exceptionTag;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ClassReaderSource classSource() {
|
||||
return null;
|
||||
public ClassReaderSource classes() {
|
||||
return classes;
|
||||
}
|
||||
|
||||
public WasmFunction npeMethod() {
|
||||
@ -127,4 +149,8 @@ public class WasmGCGenerationContext implements BaseWasmGenerationContext {
|
||||
}
|
||||
return exceptionGlobal;
|
||||
}
|
||||
|
||||
public WasmGCCustomGeneratorProvider customGenerators() {
|
||||
return customGenerators;
|
||||
}
|
||||
}
|
@ -0,0 +1,83 @@
|
||||
/*
|
||||
* Copyright 2024 Alexey Andreev.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.teavm.backend.wasm.generate.gc.methods;
|
||||
|
||||
import java.util.List;
|
||||
import org.teavm.backend.wasm.generate.TemporaryVariablePool;
|
||||
import org.teavm.backend.wasm.generate.gc.classes.WasmGCClassInfoProvider;
|
||||
import org.teavm.backend.wasm.model.WasmArray;
|
||||
import org.teavm.backend.wasm.model.WasmLocal;
|
||||
import org.teavm.backend.wasm.model.WasmType;
|
||||
import org.teavm.backend.wasm.model.expression.WasmArrayNewDefault;
|
||||
import org.teavm.backend.wasm.model.expression.WasmBlock;
|
||||
import org.teavm.backend.wasm.model.expression.WasmExpression;
|
||||
import org.teavm.backend.wasm.model.expression.WasmGetGlobal;
|
||||
import org.teavm.backend.wasm.model.expression.WasmGetLocal;
|
||||
import org.teavm.backend.wasm.model.expression.WasmSetLocal;
|
||||
import org.teavm.backend.wasm.model.expression.WasmStructNewDefault;
|
||||
import org.teavm.backend.wasm.model.expression.WasmStructSet;
|
||||
import org.teavm.model.TextLocation;
|
||||
import org.teavm.model.ValueType;
|
||||
|
||||
public class WasmGCGenerationUtil {
|
||||
private WasmGCClassInfoProvider classInfoProvider;
|
||||
private TemporaryVariablePool tempVars;
|
||||
|
||||
public WasmGCGenerationUtil(WasmGCClassInfoProvider classInfoProvider, TemporaryVariablePool tempVars) {
|
||||
this.classInfoProvider = classInfoProvider;
|
||||
this.tempVars = tempVars;
|
||||
}
|
||||
|
||||
public void allocateArray(ValueType itemType, WasmExpression length, TextLocation location, WasmLocal local,
|
||||
List<WasmExpression> target) {
|
||||
var classInfo = classInfoProvider.getClassInfo(ValueType.arrayOf(itemType));
|
||||
var block = new WasmBlock(false);
|
||||
block.setType(classInfo.getType());
|
||||
var targetVar = local;
|
||||
if (targetVar == null) {
|
||||
targetVar = tempVars.acquire(classInfo.getType());
|
||||
}
|
||||
|
||||
var structNew = new WasmSetLocal(targetVar, new WasmStructNewDefault(classInfo.getStructure()));
|
||||
structNew.setLocation(location);
|
||||
target.add(structNew);
|
||||
|
||||
var initClassField = new WasmStructSet(classInfo.getStructure(), new WasmGetLocal(targetVar),
|
||||
WasmGCClassInfoProvider.CLASS_FIELD_OFFSET, new WasmGetGlobal(classInfo.getPointer()));
|
||||
initClassField.setLocation(location);
|
||||
target.add(initClassField);
|
||||
|
||||
var wasmArrayType = (WasmType.CompositeReference) classInfo.getStructure().getFields()
|
||||
.get(WasmGCClassInfoProvider.ARRAY_DATA_FIELD_OFFSET)
|
||||
.asUnpackedType();
|
||||
var wasmArray = (WasmArray) wasmArrayType.composite;
|
||||
var initArrayField = new WasmStructSet(
|
||||
classInfo.getStructure(),
|
||||
new WasmGetLocal(targetVar),
|
||||
WasmGCClassInfoProvider.ARRAY_DATA_FIELD_OFFSET,
|
||||
new WasmArrayNewDefault(wasmArray, length)
|
||||
);
|
||||
initArrayField.setLocation(location);
|
||||
target.add(initArrayField);
|
||||
|
||||
if (local == null) {
|
||||
var getLocal = new WasmGetLocal(targetVar);
|
||||
getLocal.setLocation(location);
|
||||
target.add(getLocal);
|
||||
tempVars.release(targetVar);
|
||||
}
|
||||
}
|
||||
}
|
@ -23,7 +23,6 @@ import org.teavm.ast.QualificationExpr;
|
||||
import org.teavm.ast.SubscriptExpr;
|
||||
import org.teavm.ast.UnwrapArrayExpr;
|
||||
import org.teavm.backend.wasm.generate.common.methods.BaseWasmGenerationVisitor;
|
||||
import org.teavm.backend.wasm.generate.gc.WasmGCGenerationContext;
|
||||
import org.teavm.backend.wasm.generate.gc.classes.WasmGCClassInfoProvider;
|
||||
import org.teavm.backend.wasm.model.WasmArray;
|
||||
import org.teavm.backend.wasm.model.WasmFunction;
|
||||
@ -33,7 +32,6 @@ import org.teavm.backend.wasm.model.WasmStructure;
|
||||
import org.teavm.backend.wasm.model.WasmType;
|
||||
import org.teavm.backend.wasm.model.expression.WasmArrayGet;
|
||||
import org.teavm.backend.wasm.model.expression.WasmArrayLength;
|
||||
import org.teavm.backend.wasm.model.expression.WasmArrayNewDefault;
|
||||
import org.teavm.backend.wasm.model.expression.WasmArraySet;
|
||||
import org.teavm.backend.wasm.model.expression.WasmBlock;
|
||||
import org.teavm.backend.wasm.model.expression.WasmCall;
|
||||
@ -57,11 +55,13 @@ import org.teavm.model.ValueType;
|
||||
|
||||
public class WasmGCGenerationVisitor extends BaseWasmGenerationVisitor {
|
||||
private WasmGCGenerationContext context;
|
||||
private WasmGCGenerationUtil generationUtil;
|
||||
|
||||
public WasmGCGenerationVisitor(WasmGCGenerationContext context, WasmFunction function,
|
||||
int firstVariable, boolean async) {
|
||||
super(context, function, firstVariable, async);
|
||||
this.context = context;
|
||||
generationUtil = new WasmGCGenerationUtil(context.classInfoProvider(), tempVars);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -130,20 +130,29 @@ public class WasmGCGenerationVisitor extends BaseWasmGenerationVisitor {
|
||||
|
||||
@Override
|
||||
protected void storeField(Expr qualified, FieldReference field, Expr value, TextLocation location) {
|
||||
accept(qualified);
|
||||
var target = result;
|
||||
accept(value);
|
||||
var wasmValue = result;
|
||||
if (qualified == null) {
|
||||
accept(value);
|
||||
var wasmValue = result;
|
||||
var global = context.classInfoProvider().getStaticFieldLocation(field);
|
||||
var result = new WasmSetGlobal(global, wasmValue);
|
||||
result.setLocation(location);
|
||||
resultConsumer.add(result);
|
||||
} else {
|
||||
accept(qualified);
|
||||
var target = result;
|
||||
accept(value);
|
||||
var wasmValue = result;
|
||||
|
||||
target.acceptVisitor(typeInference);
|
||||
var type = (WasmType.CompositeReference) typeInference.getResult();
|
||||
var struct = (WasmStructure) type.composite;
|
||||
target.acceptVisitor(typeInference);
|
||||
var type = (WasmType.CompositeReference) typeInference.getResult();
|
||||
var struct = (WasmStructure) type.composite;
|
||||
|
||||
var fieldIndex = context.classInfoProvider().getFieldIndex(field);
|
||||
var fieldIndex = context.classInfoProvider().getFieldIndex(field);
|
||||
|
||||
var expr = new WasmStructSet(struct, target, fieldIndex, wasmValue);
|
||||
expr.setLocation(location);
|
||||
resultConsumer.add(expr);
|
||||
var expr = new WasmStructSet(struct, target, fieldIndex, wasmValue);
|
||||
expr.setLocation(location);
|
||||
resultConsumer.add(expr);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -230,42 +239,7 @@ public class WasmGCGenerationVisitor extends BaseWasmGenerationVisitor {
|
||||
@Override
|
||||
protected void allocateArray(ValueType itemType, WasmExpression length, TextLocation location, WasmLocal local,
|
||||
List<WasmExpression> target) {
|
||||
var classInfo = context.classInfoProvider().getClassInfo(ValueType.arrayOf(itemType));
|
||||
var block = new WasmBlock(false);
|
||||
block.setType(classInfo.getType());
|
||||
var targetVar = local;
|
||||
if (targetVar == null) {
|
||||
targetVar = tempVars.acquire(classInfo.getType());
|
||||
}
|
||||
|
||||
var structNew = new WasmSetLocal(targetVar, new WasmStructNewDefault(classInfo.getStructure()));
|
||||
structNew.setLocation(location);
|
||||
target.add(structNew);
|
||||
|
||||
var initClassField = new WasmStructSet(classInfo.getStructure(), new WasmGetLocal(targetVar),
|
||||
WasmGCClassInfoProvider.CLASS_FIELD_OFFSET, new WasmGetGlobal(classInfo.getPointer()));
|
||||
initClassField.setLocation(location);
|
||||
target.add(initClassField);
|
||||
|
||||
var wasmArrayType = (WasmType.CompositeReference) classInfo.getStructure().getFields()
|
||||
.get(WasmGCClassInfoProvider.ARRAY_DATA_FIELD_OFFSET)
|
||||
.asUnpackedType();
|
||||
var wasmArray = (WasmArray) wasmArrayType.composite;
|
||||
var initArrayField = new WasmStructSet(
|
||||
classInfo.getStructure(),
|
||||
new WasmGetLocal(targetVar),
|
||||
WasmGCClassInfoProvider.ARRAY_DATA_FIELD_OFFSET,
|
||||
new WasmArrayNewDefault(wasmArray, length)
|
||||
);
|
||||
initArrayField.setLocation(location);
|
||||
target.add(initArrayField);
|
||||
|
||||
if (local == null) {
|
||||
var getLocal = new WasmGetLocal(targetVar);
|
||||
getLocal.setLocation(location);
|
||||
target.add(getLocal);
|
||||
tempVars.release(targetVar);
|
||||
}
|
||||
generationUtil.allocateArray(itemType, length, location, local, target);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -277,7 +251,7 @@ public class WasmGCGenerationVisitor extends BaseWasmGenerationVisitor {
|
||||
@Override
|
||||
protected WasmExpression generateInstanceOf(WasmExpression expression, ValueType type) {
|
||||
context.classInfoProvider().getClassInfo(type);
|
||||
var supertypeCall = new WasmCall(context.functions().forSupertype(type));
|
||||
var supertypeCall = new WasmCall(context.supertypeFunctions().getIsSupertypeFunction(type));
|
||||
var classRef = new WasmStructGet(
|
||||
context.standardClasses().objectClass().getStructure(),
|
||||
expression,
|
||||
@ -352,17 +326,23 @@ public class WasmGCGenerationVisitor extends BaseWasmGenerationVisitor {
|
||||
|
||||
@Override
|
||||
public void visit(QualificationExpr expr) {
|
||||
accept(expr.getQualified());
|
||||
var target = result;
|
||||
if (expr.getQualified() == null) {
|
||||
var global = context.classInfoProvider().getStaticFieldLocation(expr.getField());
|
||||
result = new WasmGetGlobal(global);
|
||||
result.setLocation(expr.getLocation());
|
||||
} else {
|
||||
accept(expr.getQualified());
|
||||
var target = result;
|
||||
|
||||
target.acceptVisitor(typeInference);
|
||||
var type = (WasmType.CompositeReference) typeInference.getResult();
|
||||
var struct = (WasmStructure) type.composite;
|
||||
target.acceptVisitor(typeInference);
|
||||
var type = (WasmType.CompositeReference) typeInference.getResult();
|
||||
var struct = (WasmStructure) type.composite;
|
||||
|
||||
var fieldIndex = context.classInfoProvider().getFieldIndex(expr.getField());
|
||||
var fieldIndex = context.classInfoProvider().getFieldIndex(expr.getField());
|
||||
|
||||
result = new WasmStructGet(struct, target, fieldIndex);
|
||||
result.setLocation(expr.getLocation());
|
||||
result = new WasmStructGet(struct, target, fieldIndex);
|
||||
result.setLocation(expr.getLocation());
|
||||
}
|
||||
}
|
||||
|
||||
private class SimpleCallSite extends CallSiteIdentifier {
|
||||
|
@ -0,0 +1,319 @@
|
||||
/*
|
||||
* Copyright 2024 Alexey Andreev.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.teavm.backend.wasm.generate.gc.methods;
|
||||
|
||||
import java.util.ArrayDeque;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Queue;
|
||||
import java.util.Set;
|
||||
import org.teavm.ast.decompilation.Decompiler;
|
||||
import org.teavm.backend.lowlevel.generate.NameProvider;
|
||||
import org.teavm.backend.wasm.BaseWasmFunctionRepository;
|
||||
import org.teavm.backend.wasm.WasmFunctionTypes;
|
||||
import org.teavm.backend.wasm.gc.WasmGCVariableCategoryProvider;
|
||||
import org.teavm.backend.wasm.generate.gc.classes.WasmGCClassInfoProvider;
|
||||
import org.teavm.backend.wasm.generate.gc.classes.WasmGCStandardClasses;
|
||||
import org.teavm.backend.wasm.generate.gc.classes.WasmGCSupertypeFunctionProvider;
|
||||
import org.teavm.backend.wasm.generate.gc.classes.WasmGCTypeMapper;
|
||||
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.WasmLocal;
|
||||
import org.teavm.backend.wasm.model.WasmModule;
|
||||
import org.teavm.backend.wasm.model.WasmType;
|
||||
import org.teavm.backend.wasm.model.expression.WasmFunctionReference;
|
||||
import org.teavm.backend.wasm.model.expression.WasmReturn;
|
||||
import org.teavm.backend.wasm.model.expression.WasmSetGlobal;
|
||||
import org.teavm.diagnostics.Diagnostics;
|
||||
import org.teavm.interop.Import;
|
||||
import org.teavm.model.CallLocation;
|
||||
import org.teavm.model.ClassHierarchy;
|
||||
import org.teavm.model.ClassHolderSource;
|
||||
import org.teavm.model.ElementModifier;
|
||||
import org.teavm.model.MethodHolder;
|
||||
import org.teavm.model.MethodReader;
|
||||
import org.teavm.model.MethodReference;
|
||||
import org.teavm.model.ValueType;
|
||||
import org.teavm.model.analysis.ClassInitializerInfo;
|
||||
import org.teavm.model.classes.VirtualTableProvider;
|
||||
import org.teavm.model.util.RegisterAllocator;
|
||||
|
||||
public class WasmGCMethodGenerator implements BaseWasmFunctionRepository {
|
||||
private WasmModule module;
|
||||
private ClassHierarchy hierarchy;
|
||||
private ClassHolderSource classes;
|
||||
private VirtualTableProvider virtualTables;
|
||||
private ClassInitializerInfo classInitInfo;
|
||||
private WasmFunctionTypes functionTypes;
|
||||
private WasmGCSupertypeFunctionProvider supertypeFunctions;
|
||||
private NameProvider names;
|
||||
private Diagnostics diagnostics;
|
||||
private WasmGCTypeMapper typeMapper;
|
||||
private WasmGCCustomGeneratorProvider customGenerators;
|
||||
private Queue<Runnable> queue = new ArrayDeque<>();
|
||||
private Map<MethodReference, WasmFunction> staticMethods = new HashMap<>();
|
||||
private Map<MethodReference, WasmFunction> instanceMethods = new HashMap<>();
|
||||
private boolean friendlyToDebugger;
|
||||
private Decompiler decompiler;
|
||||
private WasmGCGenerationContext context;
|
||||
private WasmFunction dummyInitializer;
|
||||
private WasmGCClassInfoProvider classInfoProvider;
|
||||
private WasmGCStandardClasses standardClasses;
|
||||
private WasmGCStringProvider strings;
|
||||
|
||||
public WasmGCMethodGenerator(
|
||||
WasmModule module,
|
||||
ClassHierarchy hierarchy,
|
||||
ClassHolderSource classes,
|
||||
VirtualTableProvider virtualTables,
|
||||
ClassInitializerInfo classInitInfo,
|
||||
WasmFunctionTypes functionTypes,
|
||||
NameProvider names,
|
||||
Diagnostics diagnostics,
|
||||
WasmGCCustomGeneratorProvider customGenerators
|
||||
) {
|
||||
this.module = module;
|
||||
this.hierarchy = hierarchy;
|
||||
this.classes = classes;
|
||||
this.virtualTables = virtualTables;
|
||||
this.classInitInfo = classInitInfo;
|
||||
this.functionTypes = functionTypes;
|
||||
this.names = names;
|
||||
this.diagnostics = diagnostics;
|
||||
this.customGenerators = customGenerators;
|
||||
}
|
||||
|
||||
public void setTypeMapper(WasmGCTypeMapper typeMapper) {
|
||||
this.typeMapper = typeMapper;
|
||||
}
|
||||
|
||||
public void setFriendlyToDebugger(boolean friendlyToDebugger) {
|
||||
this.friendlyToDebugger = friendlyToDebugger;
|
||||
}
|
||||
|
||||
public void setClassInfoProvider(WasmGCClassInfoProvider classInfoProvider) {
|
||||
this.classInfoProvider = classInfoProvider;
|
||||
}
|
||||
|
||||
public void setStandardClasses(WasmGCStandardClasses standardClasses) {
|
||||
this.standardClasses = standardClasses;
|
||||
}
|
||||
|
||||
public void setSupertypeFunctions(WasmGCSupertypeFunctionProvider supertypeFunctions) {
|
||||
this.supertypeFunctions = supertypeFunctions;
|
||||
}
|
||||
|
||||
public void setStrings(WasmGCStringProvider strings) {
|
||||
this.strings = strings;
|
||||
}
|
||||
|
||||
public boolean process() {
|
||||
if (queue.isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
while (!queue.isEmpty()) {
|
||||
queue.remove().run();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public WasmFunction forStaticMethod(MethodReference methodReference) {
|
||||
return staticMethods.computeIfAbsent(methodReference, this::createStaticFunction);
|
||||
}
|
||||
|
||||
private WasmFunction createStaticFunction(MethodReference methodReference) {
|
||||
var returnType = typeMapper.mapType(methodReference.getReturnType()).asUnpackedType();
|
||||
var parameterTypes = new WasmType[methodReference.parameterCount()];
|
||||
for (var i = 0; i < parameterTypes.length; ++i) {
|
||||
parameterTypes[i] = typeMapper.mapType(methodReference.parameterType(i)).asUnpackedType();
|
||||
}
|
||||
var function = new WasmFunction(functionTypes.of(returnType, parameterTypes));
|
||||
function.setName(names.forMethod(methodReference));
|
||||
module.functions.add(function);
|
||||
function.setJavaMethod(methodReference);
|
||||
|
||||
var cls = classes.get(methodReference.getClassName());
|
||||
if (cls != null) {
|
||||
var method = cls.getMethod(methodReference.getDescriptor());
|
||||
if (method != null && method.hasModifier(ElementModifier.STATIC)) {
|
||||
queue.add(() -> generateMethodBody(method, function));
|
||||
}
|
||||
}
|
||||
|
||||
return function;
|
||||
}
|
||||
|
||||
@Override
|
||||
public WasmFunction forInstanceMethod(MethodReference methodReference) {
|
||||
return instanceMethods.computeIfAbsent(methodReference, this::createInstanceFunction);
|
||||
}
|
||||
|
||||
private WasmFunction createInstanceFunction(MethodReference methodReference) {
|
||||
var returnType = typeMapper.mapType(methodReference.getReturnType()).asUnpackedType();
|
||||
var parameterTypes = new WasmType[methodReference.parameterCount() + 1];
|
||||
parameterTypes[0] = typeMapper.mapType(ValueType.object(methodReference.getClassName())).asUnpackedType();
|
||||
for (var i = 0; i < methodReference.parameterCount(); ++i) {
|
||||
parameterTypes[i + 1] = typeMapper.mapType(methodReference.parameterType(i)).asUnpackedType();
|
||||
}
|
||||
var function = new WasmFunction(functionTypes.of(returnType, parameterTypes));
|
||||
function.setName(names.forMethod(methodReference));
|
||||
module.functions.add(function);
|
||||
function.setJavaMethod(methodReference);
|
||||
|
||||
var cls = classes.get(methodReference.getClassName());
|
||||
if (cls != null) {
|
||||
var method = cls.getMethod(methodReference.getDescriptor());
|
||||
if (method != null && !method.hasModifier(ElementModifier.STATIC)) {
|
||||
queue.add(() -> generateMethodBody(method, function));
|
||||
}
|
||||
}
|
||||
|
||||
return function;
|
||||
}
|
||||
|
||||
private void generateMethodBody(MethodHolder method, WasmFunction function) {
|
||||
var customGenerator = customGenerators.get(method.getReference());
|
||||
if (customGenerator != null) {
|
||||
generateCustomMethodBody(customGenerator, method.getReference(), function);
|
||||
} else if (!method.hasModifier(ElementModifier.NATIVE)) {
|
||||
generateRegularMethodBody(method, function);
|
||||
} else {
|
||||
generateNativeMethodBody(method, function);
|
||||
}
|
||||
}
|
||||
|
||||
private void generateCustomMethodBody(WasmGCCustomGenerator customGenerator, MethodReference method,
|
||||
WasmFunction function) {
|
||||
customGenerator.apply(method, function, customGeneratorContext);
|
||||
}
|
||||
|
||||
private void generateRegularMethodBody(MethodHolder method, WasmFunction function) {
|
||||
var decompiler = getDecompiler();
|
||||
var categoryProvider = new WasmGCVariableCategoryProvider(hierarchy);
|
||||
var allocator = new RegisterAllocator(categoryProvider);
|
||||
allocator.allocateRegisters(method.getReference(), method.getProgram(), friendlyToDebugger);
|
||||
var ast = decompiler.decompileRegular(method);
|
||||
var firstVar = method.hasModifier(ElementModifier.STATIC) ? 1 : 0;
|
||||
var typeInference = categoryProvider.getTypeInference();
|
||||
|
||||
var registerCount = 0;
|
||||
for (var i = 0; i < method.getProgram().variableCount(); ++i) {
|
||||
registerCount = Math.max(registerCount, method.getProgram().variableAt(i).getRegister() + 1);
|
||||
}
|
||||
var originalIndexToIndex = new int[registerCount];
|
||||
Arrays.fill(originalIndexToIndex, -1);
|
||||
for (var varNode : ast.getVariables()) {
|
||||
originalIndexToIndex[varNode.getOriginalIndex()] = varNode.getIndex();
|
||||
}
|
||||
|
||||
var variableRepresentatives = new int[registerCount];
|
||||
Arrays.fill(variableRepresentatives, -1);
|
||||
for (var i = 0; i < method.getProgram().variableCount(); ++i) {
|
||||
var variable = method.getProgram().variableAt(i);
|
||||
var varNodeIndex = variable.getRegister() >= 0 ? originalIndexToIndex[variable.getRegister()] : -1;
|
||||
if (varNodeIndex >= 0 && variableRepresentatives[varNodeIndex] < 0) {
|
||||
variableRepresentatives[varNodeIndex] = variable.getIndex();
|
||||
}
|
||||
}
|
||||
|
||||
for (var i = firstVar; i < ast.getVariables().size(); ++i) {
|
||||
var localVar = ast.getVariables().get(i);
|
||||
var representative = method.getProgram().variableAt(variableRepresentatives[i]);
|
||||
var type = typeMapper.mapType(typeInference.typeOf(representative)).asUnpackedType();
|
||||
var wasmLocal = new WasmLocal(type, localVar.getName());
|
||||
function.add(wasmLocal);
|
||||
}
|
||||
|
||||
addInitializerErase(method, function);
|
||||
var visitor = new WasmGCGenerationVisitor(getGenerationContext(), function, firstVar, false);
|
||||
visitor.generate(ast.getBody(), function.getBody());
|
||||
}
|
||||
|
||||
private void generateNativeMethodBody(MethodHolder method, WasmFunction function) {
|
||||
var importAnnot = method.getAnnotations().get(Import.class.getName());
|
||||
if (importAnnot == null) {
|
||||
diagnostics.error(new CallLocation(method.getReference()), "Method is not annotated with {{c0}}",
|
||||
Import.class.getName());
|
||||
return;
|
||||
}
|
||||
|
||||
function.setImportName(importAnnot.getValue("name").getString());
|
||||
var moduleName = importAnnot.getValue("module");
|
||||
function.setImportModule(moduleName != null ? moduleName.getString() : "teavm");
|
||||
}
|
||||
|
||||
private void addInitializerErase(MethodReader method, WasmFunction function) {
|
||||
if (method.hasModifier(ElementModifier.STATIC) && method.getName().equals("<clinit>")
|
||||
&& method.parameterCount() == 0 && classInitInfo.isDynamicInitializer(method.getOwnerName())) {
|
||||
var classInfo = classInfoProvider.getClassInfo(method.getOwnerName());
|
||||
var erase = new WasmSetGlobal(classInfo.getInitializerPointer(),
|
||||
new WasmFunctionReference(getDummyInitializer()));
|
||||
function.getBody().add(erase);
|
||||
}
|
||||
}
|
||||
|
||||
private Decompiler getDecompiler() {
|
||||
if (decompiler == null) {
|
||||
decompiler = new Decompiler(classes, Set.of(), friendlyToDebugger);
|
||||
}
|
||||
return decompiler;
|
||||
}
|
||||
|
||||
private WasmGCGenerationContext getGenerationContext() {
|
||||
if (context == null) {
|
||||
context = new WasmGCGenerationContext(
|
||||
module,
|
||||
virtualTables,
|
||||
typeMapper,
|
||||
functionTypes,
|
||||
classes,
|
||||
this,
|
||||
supertypeFunctions,
|
||||
classInfoProvider,
|
||||
standardClasses,
|
||||
strings,
|
||||
customGenerators
|
||||
);
|
||||
}
|
||||
return context;
|
||||
}
|
||||
|
||||
public WasmFunction getDummyInitializer() {
|
||||
if (dummyInitializer == null) {
|
||||
dummyInitializer = new WasmFunction(functionTypes.of(null));
|
||||
dummyInitializer.getBody().add(new WasmReturn());
|
||||
dummyInitializer.setName("teavm_dummy_initializer");
|
||||
module.functions.add(dummyInitializer);
|
||||
}
|
||||
return dummyInitializer;
|
||||
}
|
||||
|
||||
private WasmGCCustomGeneratorContext customGeneratorContext = new WasmGCCustomGeneratorContext() {
|
||||
@Override
|
||||
public WasmModule module() {
|
||||
return module;
|
||||
}
|
||||
|
||||
@Override
|
||||
public WasmFunctionTypes functionTypes() {
|
||||
return functionTypes;
|
||||
}
|
||||
};
|
||||
}
|
@ -18,15 +18,20 @@ package org.teavm.backend.wasm.generate.gc.strings;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
import org.teavm.backend.wasm.BaseWasmFunctionRepository;
|
||||
import org.teavm.backend.wasm.generate.gc.WasmGCInitializerContributor;
|
||||
import org.teavm.backend.wasm.generate.gc.classes.WasmGCClassInfoProvider;
|
||||
import org.teavm.backend.wasm.generate.gc.classes.WasmGCStandardClasses;
|
||||
import org.teavm.backend.wasm.generate.gc.initialization.WasmGCInitializerContributor;
|
||||
import org.teavm.backend.wasm.generate.gc.methods.WasmGCFunctionProvider;
|
||||
import org.teavm.backend.wasm.model.WasmFunction;
|
||||
import org.teavm.backend.wasm.model.WasmGlobal;
|
||||
import org.teavm.backend.wasm.model.WasmMemorySegment;
|
||||
import org.teavm.backend.wasm.model.WasmModule;
|
||||
import org.teavm.backend.wasm.model.expression.WasmCall;
|
||||
import org.teavm.backend.wasm.model.expression.WasmExpression;
|
||||
import org.teavm.backend.wasm.model.expression.WasmGetGlobal;
|
||||
import org.teavm.backend.wasm.model.expression.WasmSetGlobal;
|
||||
import org.teavm.backend.wasm.model.expression.WasmStructNewDefault;
|
||||
import org.teavm.backend.wasm.model.expression.WasmStructSet;
|
||||
import org.teavm.backend.wasm.render.WasmBinaryWriter;
|
||||
import org.teavm.model.MethodReference;
|
||||
|
||||
@ -35,10 +40,10 @@ public class WasmGCStringPool implements WasmGCStringProvider, WasmGCInitializer
|
||||
private WasmModule module;
|
||||
private WasmBinaryWriter binaryWriter = new WasmBinaryWriter();
|
||||
private Map<String, WasmGCStringConstant> stringMap = new LinkedHashMap<>();
|
||||
private WasmGCFunctionProvider functionProvider;
|
||||
private BaseWasmFunctionRepository functionProvider;
|
||||
|
||||
public WasmGCStringPool(WasmGCStandardClasses standardClasses, WasmModule module,
|
||||
WasmGCFunctionProvider functionProvider) {
|
||||
BaseWasmFunctionRepository functionProvider) {
|
||||
this.standardClasses = standardClasses;
|
||||
this.module = module;
|
||||
this.functionProvider = functionProvider;
|
||||
@ -46,6 +51,9 @@ public class WasmGCStringPool implements WasmGCStringProvider, WasmGCInitializer
|
||||
|
||||
@Override
|
||||
public void contributeToInitializerDefinitions(WasmFunction function) {
|
||||
var segment = new WasmMemorySegment();
|
||||
module.getSegments().add(segment);
|
||||
segment.setData(binaryWriter.getData());
|
||||
for (var str : stringMap.values()) {
|
||||
var newStruct = new WasmStructNewDefault(standardClasses.stringClass().getStructure());
|
||||
function.getBody().add(new WasmSetGlobal(str.global, newStruct));
|
||||
@ -54,8 +62,14 @@ public class WasmGCStringPool implements WasmGCStringProvider, WasmGCInitializer
|
||||
|
||||
@Override
|
||||
public void contributeToInitializer(WasmFunction function) {
|
||||
var nextCharArrayFunction = functionProvider.getStaticFunction(new MethodReference(WasmGCStringPool.class,
|
||||
var nextCharArrayFunction = functionProvider.forStaticMethod(new MethodReference(WasmGCStringPool.class,
|
||||
"nextCharArray", char[].class));
|
||||
var stringStruct = standardClasses.stringClass().getStructure();
|
||||
for (var str : stringMap.values()) {
|
||||
var value = new WasmCall(nextCharArrayFunction);
|
||||
function.getBody().add(new WasmStructSet(stringStruct, new WasmGetGlobal(str.global),
|
||||
WasmGCClassInfoProvider.CUSTOM_FIELD_OFFSETS, value));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -0,0 +1,23 @@
|
||||
/*
|
||||
* Copyright 2024 Alexey Andreev.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.teavm.backend.wasm.generators.gc;
|
||||
|
||||
import org.teavm.backend.wasm.model.WasmFunction;
|
||||
import org.teavm.model.MethodReference;
|
||||
|
||||
public interface WasmGCCustomGenerator {
|
||||
void apply(MethodReference method, WasmFunction function, WasmGCCustomGeneratorContext context);
|
||||
}
|
@ -0,0 +1,25 @@
|
||||
/*
|
||||
* Copyright 2024 Alexey Andreev.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.teavm.backend.wasm.generators.gc;
|
||||
|
||||
import org.teavm.backend.wasm.WasmFunctionTypes;
|
||||
import org.teavm.backend.wasm.model.WasmModule;
|
||||
|
||||
public interface WasmGCCustomGeneratorContext {
|
||||
WasmModule module();
|
||||
|
||||
WasmFunctionTypes functionTypes();
|
||||
}
|
@ -0,0 +1,42 @@
|
||||
/*
|
||||
* Copyright 2024 Alexey Andreev.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.teavm.backend.wasm.generators.gc;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import org.teavm.backend.wasm.generate.gc.methods.WasmGCCustomGeneratorProvider;
|
||||
import org.teavm.backend.wasm.generate.gc.strings.WasmGCStringPool;
|
||||
import org.teavm.model.MethodReference;
|
||||
|
||||
public class WasmGCCustomGenerators implements WasmGCCustomGeneratorProvider {
|
||||
private Map<MethodReference, WasmGCCustomGenerator> generators = new HashMap<>();
|
||||
|
||||
public WasmGCCustomGenerators() {
|
||||
fillStringPool();
|
||||
}
|
||||
|
||||
private void fillStringPool() {
|
||||
generators.put(
|
||||
new MethodReference(WasmGCStringPool.class, "nextByte", byte.class),
|
||||
new WasmGCStringPoolGenerator()
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public WasmGCCustomGenerator get(MethodReference method) {
|
||||
return generators.get(method);
|
||||
}
|
||||
}
|
@ -0,0 +1,46 @@
|
||||
/*
|
||||
* Copyright 2024 Alexey Andreev.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.teavm.backend.wasm.generators.gc;
|
||||
|
||||
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.WasmType;
|
||||
import org.teavm.backend.wasm.model.expression.WasmGetGlobal;
|
||||
import org.teavm.backend.wasm.model.expression.WasmInt32Constant;
|
||||
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.WasmReturn;
|
||||
import org.teavm.backend.wasm.model.expression.WasmSetLocal;
|
||||
import org.teavm.model.MethodReference;
|
||||
|
||||
public class WasmGCStringPoolGenerator implements WasmGCCustomGenerator {
|
||||
@Override
|
||||
public void apply(MethodReference method, WasmFunction function, WasmGCCustomGeneratorContext context) {
|
||||
var module = context.module();
|
||||
var pointer = new WasmGlobal("teavm_string_pool_pointer", WasmType.INT32, new WasmInt32Constant(0));
|
||||
module.globals.add(pointer);
|
||||
|
||||
var resultLocal = new WasmLocal(WasmType.INT32);
|
||||
function.add(resultLocal);
|
||||
|
||||
var increment = new WasmIntBinary(WasmIntType.INT32, WasmIntBinaryOperation.ADD,
|
||||
new WasmGetGlobal(pointer), new WasmInt32Constant(1));
|
||||
function.getBody().add(new WasmSetLocal(resultLocal, increment));
|
||||
function.getBody().add(new WasmReturn(new WasmGetGlobal(pointer)));
|
||||
}
|
||||
}
|
@ -15,10 +15,11 @@
|
||||
*/
|
||||
package org.teavm.backend.wasm.model;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class WasmStructure extends WasmCompositeType {
|
||||
private List<WasmStorageType> fields;
|
||||
private List<WasmStorageType> fields = new ArrayList<>();
|
||||
|
||||
public WasmStructure(String name) {
|
||||
super(name);
|
||||
|
@ -19,6 +19,7 @@ import org.teavm.backend.wasm.model.WasmArray;
|
||||
import org.teavm.backend.wasm.model.WasmCompositeTypeVisitor;
|
||||
import org.teavm.backend.wasm.model.WasmFunctionType;
|
||||
import org.teavm.backend.wasm.model.WasmModule;
|
||||
import org.teavm.backend.wasm.model.WasmStorageType;
|
||||
import org.teavm.backend.wasm.model.WasmStructure;
|
||||
|
||||
public class WasmCompositeTypeBinaryRenderer implements WasmCompositeTypeVisitor {
|
||||
@ -26,17 +27,24 @@ public class WasmCompositeTypeBinaryRenderer implements WasmCompositeTypeVisitor
|
||||
private WasmBinaryWriter section;
|
||||
|
||||
public WasmCompositeTypeBinaryRenderer(WasmModule module, WasmBinaryWriter section) {
|
||||
this.module = module;
|
||||
this.section = section;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(WasmStructure type) {
|
||||
|
||||
section.writeByte(0x5F);
|
||||
section.writeLEB(type.getFields().size());
|
||||
for (var fieldType : type.getFields()) {
|
||||
writeStorageType(fieldType);
|
||||
section.writeLEB(0x01); // mutable
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(WasmArray type) {
|
||||
|
||||
writeStorageType(type.getElementType());
|
||||
section.writeLEB(0x01); // mutable
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -53,4 +61,19 @@ public class WasmCompositeTypeBinaryRenderer implements WasmCompositeTypeVisitor
|
||||
section.writeByte(0);
|
||||
}
|
||||
}
|
||||
|
||||
private void writeStorageType(WasmStorageType storageType) {
|
||||
if (storageType instanceof WasmStorageType.Packed) {
|
||||
switch (((WasmStorageType.Packed) storageType).type) {
|
||||
case INT8:
|
||||
section.writeByte(0x78);
|
||||
break;
|
||||
case INT16:
|
||||
section.writeByte(0x77);
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
section.writeType(storageType.asUnpackedType(), module);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -15,6 +15,8 @@
|
||||
*/
|
||||
package org.teavm.backend.wasm.runtime;
|
||||
|
||||
import org.teavm.interop.Import;
|
||||
|
||||
public class WasmGCSupport {
|
||||
private WasmGCSupport() {
|
||||
}
|
||||
@ -30,4 +32,10 @@ public class WasmGCSupport {
|
||||
public static ClassCastException cce() {
|
||||
return new ClassCastException();
|
||||
}
|
||||
|
||||
@Import(name = "putcharStdout")
|
||||
public static native void putCharStdout(char c);
|
||||
|
||||
@Import(name = "putcharStderr")
|
||||
public static native void putCharStderr(char c);
|
||||
}
|
||||
|
@ -64,7 +64,7 @@ public class MethodDescriptor implements Serializable {
|
||||
|
||||
public ValueType parameterType(int index) {
|
||||
if (index >= signature.length - 1) {
|
||||
throw new IndexOutOfBoundsException(String.valueOf(index) + "/" + (signature.length - 1));
|
||||
throw new IndexOutOfBoundsException(index + "/" + (signature.length - 1));
|
||||
}
|
||||
return signature[index];
|
||||
}
|
||||
|
@ -36,10 +36,14 @@ import org.teavm.common.LCATree;
|
||||
import org.teavm.model.AccessLevel;
|
||||
import org.teavm.model.ClassReader;
|
||||
import org.teavm.model.ElementModifier;
|
||||
import org.teavm.model.ListableClassHolderSource;
|
||||
import org.teavm.model.ListableClassReaderSource;
|
||||
import org.teavm.model.MethodDescriptor;
|
||||
import org.teavm.model.MethodReader;
|
||||
import org.teavm.model.MethodReference;
|
||||
import org.teavm.model.instructions.CloneArrayInstruction;
|
||||
import org.teavm.model.instructions.InvocationType;
|
||||
import org.teavm.model.instructions.InvokeInstruction;
|
||||
import org.teavm.model.util.GraphColorer;
|
||||
|
||||
public class VirtualTableBuilder {
|
||||
@ -518,4 +522,33 @@ public class VirtualTableBuilder {
|
||||
IntArrayList colors = new IntArrayList();
|
||||
List<MethodDescriptor> methods = new ArrayList<>();
|
||||
}
|
||||
|
||||
public static Set<MethodReference> getMethodsUsedOnCallSites(ListableClassHolderSource classes) {
|
||||
var virtualMethods = new HashSet<MethodReference>();
|
||||
|
||||
for (var className : classes.getClassNames()) {
|
||||
var cls = classes.get(className);
|
||||
for (var method : cls.getMethods()) {
|
||||
var program = method.getProgram();
|
||||
if (program == null) {
|
||||
continue;
|
||||
}
|
||||
for (int i = 0; i < program.basicBlockCount(); ++i) {
|
||||
var block = program.basicBlockAt(i);
|
||||
for (var insn : block) {
|
||||
if (insn instanceof InvokeInstruction) {
|
||||
var invoke = (InvokeInstruction) insn;
|
||||
if (invoke.getType() == InvocationType.VIRTUAL) {
|
||||
virtualMethods.add(invoke.getMethod());
|
||||
}
|
||||
} else if (insn instanceof CloneArrayInstruction) {
|
||||
virtualMethods.add(new MethodReference(Object.class, "clone", Object.class));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return virtualMethods;
|
||||
}
|
||||
}
|
||||
|
@ -16,11 +16,11 @@
|
||||
package org.teavm.model.util;
|
||||
|
||||
import org.teavm.model.MethodReference;
|
||||
import org.teavm.model.ProgramReader;
|
||||
import org.teavm.model.Program;
|
||||
|
||||
public class DefaultVariableCategoryProvider implements VariableCategoryProvider {
|
||||
@Override
|
||||
public Object[] getCategories(ProgramReader program, MethodReference method) {
|
||||
public Object[] getCategories(Program program, MethodReference method) {
|
||||
TypeInferer inferer = new TypeInferer();
|
||||
inferer.inferTypes(program, method);
|
||||
var categories = new Object[program.variableCount()];
|
||||
|
@ -16,8 +16,8 @@
|
||||
package org.teavm.model.util;
|
||||
|
||||
import org.teavm.model.MethodReference;
|
||||
import org.teavm.model.ProgramReader;
|
||||
import org.teavm.model.Program;
|
||||
|
||||
public interface VariableCategoryProvider {
|
||||
Object[] getCategories(ProgramReader program, MethodReference method);
|
||||
Object[] getCategories(Program program, MethodReference method);
|
||||
}
|
||||
|
@ -60,5 +60,4 @@ public interface TeaVMTargetController {
|
||||
void addVirtualMethods(Predicate<MethodReference> methods);
|
||||
|
||||
ClassInitializerInfo getClassInitializerInfo();
|
||||
|
||||
}
|
||||
|
@ -23,4 +23,5 @@ public final class Platforms {
|
||||
public static final String WEBASSEMBLY = "webassembly";
|
||||
public static final String C = "c";
|
||||
public static final String LOW_LEVEL = "low_level";
|
||||
public static final String WEBASSEMBLY_GC = "webassembly-gc";
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user