mirror of
https://github.com/Eaglercraft-TeaVM-Fork/eagler-teavm.git
synced 2024-12-22 08:14:09 -08:00
wasm gc: fix issues related to virtual calls
This commit is contained in:
parent
73edc0cf6e
commit
a84c5fc77f
|
@ -617,7 +617,7 @@ public class CTarget implements TeaVMTarget, TeaVMCHost {
|
||||||
|
|
||||||
private VirtualTableProvider createVirtualTableProvider(ListableClassHolderSource classes) {
|
private VirtualTableProvider createVirtualTableProvider(ListableClassHolderSource classes) {
|
||||||
VirtualTableBuilder builder = new VirtualTableBuilder(classes);
|
VirtualTableBuilder builder = new VirtualTableBuilder(classes);
|
||||||
builder.setMethodsUsedAtCallSites(VirtualTableBuilder.getMethodsUsedOnCallSites(classes));
|
builder.setMethodsUsedAtCallSites(VirtualTableBuilder.getMethodsUsedOnCallSites(classes, true));
|
||||||
builder.setMethodCalledVirtually(controller::isVirtual);
|
builder.setMethodCalledVirtually(controller::isVirtual);
|
||||||
return builder.build();
|
return builder.build();
|
||||||
}
|
}
|
||||||
|
|
|
@ -1070,7 +1070,7 @@ public class WasmTarget implements TeaVMTarget, TeaVMWasmHost {
|
||||||
|
|
||||||
private VirtualTableProvider createVirtualTableProvider(ListableClassHolderSource classes) {
|
private VirtualTableProvider createVirtualTableProvider(ListableClassHolderSource classes) {
|
||||||
var builder = new VirtualTableBuilder(classes);
|
var builder = new VirtualTableBuilder(classes);
|
||||||
builder.setMethodsUsedAtCallSites(VirtualTableBuilder.getMethodsUsedOnCallSites(classes));
|
builder.setMethodsUsedAtCallSites(VirtualTableBuilder.getMethodsUsedOnCallSites(classes, true));
|
||||||
builder.setMethodCalledVirtually(controller::isVirtual);
|
builder.setMethodCalledVirtually(controller::isVirtual);
|
||||||
return builder.build();
|
return builder.build();
|
||||||
}
|
}
|
||||||
|
|
|
@ -34,12 +34,12 @@ public final class WasmGCUtil {
|
||||||
if (firstPath.get(0) != secondPath.get(0)) {
|
if (firstPath.get(0) != secondPath.get(0)) {
|
||||||
return "java.lang.Object";
|
return "java.lang.Object";
|
||||||
}
|
}
|
||||||
var max = Math.max(firstPath.size(), secondPath.size());
|
var min = Math.min(firstPath.size(), secondPath.size());
|
||||||
var index = 1;
|
var index = 1;
|
||||||
while (index < max && firstPath.get(index) == secondPath.get(index)) {
|
while (index < min && firstPath.get(index) == secondPath.get(index)) {
|
||||||
++index;
|
++index;
|
||||||
}
|
}
|
||||||
return firstPath.get(index).getName();
|
return index < firstPath.size() ? firstPath.get(index).getName() : secondPath.get(index).getName();
|
||||||
}
|
}
|
||||||
|
|
||||||
private static List<ClassReader> findPathToRoot(ClassHierarchy hierarchy, ClassReader cls) {
|
private static List<ClassReader> findPathToRoot(ClassHierarchy hierarchy, ClassReader cls) {
|
||||||
|
|
|
@ -29,7 +29,6 @@ import org.teavm.ast.QualificationExpr;
|
||||||
import org.teavm.ast.Statement;
|
import org.teavm.ast.Statement;
|
||||||
import org.teavm.ast.SubscriptExpr;
|
import org.teavm.ast.SubscriptExpr;
|
||||||
import org.teavm.ast.TryCatchStatement;
|
import org.teavm.ast.TryCatchStatement;
|
||||||
import org.teavm.ast.UnwrapArrayExpr;
|
|
||||||
import org.teavm.backend.wasm.WasmFunctionRepository;
|
import org.teavm.backend.wasm.WasmFunctionRepository;
|
||||||
import org.teavm.backend.wasm.WasmFunctionTypes;
|
import org.teavm.backend.wasm.WasmFunctionTypes;
|
||||||
import org.teavm.backend.wasm.WasmHeap;
|
import org.teavm.backend.wasm.WasmHeap;
|
||||||
|
@ -299,7 +298,7 @@ public class WasmGenerationVisitor extends BaseWasmGenerationVisitor {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected WasmExpression nullLiteral() {
|
protected WasmExpression nullLiteral(Expr expr) {
|
||||||
return new WasmInt32Constant(0);
|
return new WasmInt32Constant(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -371,11 +370,6 @@ public class WasmGenerationVisitor extends BaseWasmGenerationVisitor {
|
||||||
return new WasmIntBinary(WasmIntType.INT32, WasmIntBinaryOperation.ADD, array, index);
|
return new WasmIntBinary(WasmIntType.INT32, WasmIntBinaryOperation.ADD, array, index);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void visit(UnwrapArrayExpr expr) {
|
|
||||||
accept(expr.getArray());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected WasmExpression invocation(InvocationExpr expr, List<WasmExpression> resultConsumer, boolean willDrop) {
|
protected WasmExpression invocation(InvocationExpr expr, List<WasmExpression> resultConsumer, boolean willDrop) {
|
||||||
if (expr.getMethod().getClassName().equals(ShadowStack.class.getName())) {
|
if (expr.getMethod().getClassName().equals(ShadowStack.class.getName())) {
|
||||||
|
|
|
@ -60,6 +60,7 @@ import org.teavm.ast.SwitchStatement;
|
||||||
import org.teavm.ast.ThrowStatement;
|
import org.teavm.ast.ThrowStatement;
|
||||||
import org.teavm.ast.TryCatchStatement;
|
import org.teavm.ast.TryCatchStatement;
|
||||||
import org.teavm.ast.UnaryExpr;
|
import org.teavm.ast.UnaryExpr;
|
||||||
|
import org.teavm.ast.UnwrapArrayExpr;
|
||||||
import org.teavm.ast.VariableExpr;
|
import org.teavm.ast.VariableExpr;
|
||||||
import org.teavm.ast.WhileStatement;
|
import org.teavm.ast.WhileStatement;
|
||||||
import org.teavm.backend.wasm.WasmRuntime;
|
import org.teavm.backend.wasm.WasmRuntime;
|
||||||
|
@ -453,7 +454,7 @@ public abstract class BaseWasmGenerationVisitor implements StatementVisitor, Exp
|
||||||
accept(value);
|
accept(value);
|
||||||
result.acceptVisitor(typeInference);
|
result.acceptVisitor(typeInference);
|
||||||
block.setType(typeInference.getResult());
|
block.setType(typeInference.getResult());
|
||||||
var cachedValue = exprCache.create(result, WasmType.INT32, location, block.getBody());
|
var cachedValue = exprCache.create(result, typeInference.getResult(), location, block.getBody());
|
||||||
|
|
||||||
var check = new WasmBranch(cachedValue.expr(), block);
|
var check = new WasmBranch(cachedValue.expr(), block);
|
||||||
check.setResult(cachedValue.expr());
|
check.setResult(cachedValue.expr());
|
||||||
|
@ -555,7 +556,7 @@ public abstract class BaseWasmGenerationVisitor implements StatementVisitor, Exp
|
||||||
@Override
|
@Override
|
||||||
public void visit(ConstantExpr expr) {
|
public void visit(ConstantExpr expr) {
|
||||||
if (expr.getValue() == null) {
|
if (expr.getValue() == null) {
|
||||||
result = nullLiteral();
|
result = nullLiteral(expr);
|
||||||
} else if (expr.getValue() instanceof Integer) {
|
} else if (expr.getValue() instanceof Integer) {
|
||||||
result = new WasmInt32Constant((Integer) expr.getValue());
|
result = new WasmInt32Constant((Integer) expr.getValue());
|
||||||
} else if (expr.getValue() instanceof Long) {
|
} else if (expr.getValue() instanceof Long) {
|
||||||
|
@ -574,7 +575,7 @@ public abstract class BaseWasmGenerationVisitor implements StatementVisitor, Exp
|
||||||
result.setLocation(expr.getLocation());
|
result.setLocation(expr.getLocation());
|
||||||
}
|
}
|
||||||
|
|
||||||
protected abstract WasmExpression nullLiteral();
|
protected abstract WasmExpression nullLiteral(Expr expr);
|
||||||
|
|
||||||
protected abstract WasmExpression stringLiteral(String s);
|
protected abstract WasmExpression stringLiteral(String s);
|
||||||
|
|
||||||
|
@ -894,12 +895,14 @@ public abstract class BaseWasmGenerationVisitor implements StatementVisitor, Exp
|
||||||
return block;
|
return block;
|
||||||
} else {
|
} else {
|
||||||
var reference = expr.getMethod();
|
var reference = expr.getMethod();
|
||||||
acceptWithType(expr.getArguments().get(0), ValueType.object(expr.getMethod().getClassName()));
|
var instanceType = ValueType.object(expr.getMethod().getClassName());
|
||||||
|
acceptWithType(expr.getArguments().get(0), instanceType);
|
||||||
|
var instanceWasmType = mapType(instanceType);
|
||||||
var instance = result;
|
var instance = result;
|
||||||
var block = new WasmBlock(false);
|
var block = new WasmBlock(false);
|
||||||
block.setType(mapType(reference.getReturnType()));
|
block.setType(mapType(reference.getReturnType()));
|
||||||
|
|
||||||
var instanceVar = tempVars.acquire(WasmType.INT32);
|
var instanceVar = tempVars.acquire(instanceWasmType);
|
||||||
block.getBody().add(new WasmSetLocal(instanceVar, instance));
|
block.getBody().add(new WasmSetLocal(instanceVar, instance));
|
||||||
instance = new WasmGetLocal(instanceVar);
|
instance = new WasmGetLocal(instanceVar);
|
||||||
|
|
||||||
|
@ -1066,7 +1069,8 @@ public abstract class BaseWasmGenerationVisitor implements StatementVisitor, Exp
|
||||||
|
|
||||||
for (int i = 0; i < expr.getData().size(); ++i) {
|
for (int i = 0; i < expr.getData().size(); ++i) {
|
||||||
expr.getData().get(i).acceptVisitor(this);
|
expr.getData().get(i).acceptVisitor(this);
|
||||||
block.getBody().add(storeArrayItem(new WasmGetLocal(array), new WasmInt32Constant(i), result, arrayType));
|
var arrayData = unwrapArray(new WasmGetLocal(array));
|
||||||
|
block.getBody().add(storeArrayItem(arrayData, new WasmInt32Constant(i), result, arrayType));
|
||||||
}
|
}
|
||||||
|
|
||||||
block.getBody().add(new WasmGetLocal(array));
|
block.getBody().add(new WasmGetLocal(array));
|
||||||
|
@ -1126,7 +1130,8 @@ public abstract class BaseWasmGenerationVisitor implements StatementVisitor, Exp
|
||||||
block.setType(WasmType.INT32);
|
block.setType(WasmType.INT32);
|
||||||
block.setLocation(expr.getLocation());
|
block.setLocation(expr.getLocation());
|
||||||
|
|
||||||
var cachedObject = exprCache.create(result, WasmType.INT32, expr.getLocation(), block.getBody());
|
result.acceptVisitor(typeInference);
|
||||||
|
var cachedObject = exprCache.create(result, typeInference.getResult(), expr.getLocation(), block.getBody());
|
||||||
|
|
||||||
var ifNull = new WasmBranch(genIsZero(cachedObject.expr()), block);
|
var ifNull = new WasmBranch(genIsZero(cachedObject.expr()), block);
|
||||||
ifNull.setResult(new WasmInt32Constant(0));
|
ifNull.setResult(new WasmInt32Constant(0));
|
||||||
|
@ -1545,6 +1550,17 @@ public abstract class BaseWasmGenerationVisitor implements StatementVisitor, Exp
|
||||||
|
|
||||||
protected abstract WasmType mapType(ValueType type);
|
protected abstract WasmType mapType(ValueType type);
|
||||||
|
|
||||||
|
protected WasmExpression unwrapArray(WasmExpression array) {
|
||||||
|
return array;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void visit(UnwrapArrayExpr expr) {
|
||||||
|
accept(expr.getArray());
|
||||||
|
result = unwrapArray(result);
|
||||||
|
result.setLocation(expr.getLocation());
|
||||||
|
}
|
||||||
|
|
||||||
protected abstract class CallSiteIdentifier {
|
protected abstract class CallSiteIdentifier {
|
||||||
public abstract void generateRegister(List<WasmExpression> consumer, TextLocation location);
|
public abstract void generateRegister(List<WasmExpression> consumer, TextLocation location);
|
||||||
|
|
||||||
|
|
|
@ -140,7 +140,7 @@ public class WasmGCDeclarationsGenerator {
|
||||||
private static VirtualTableProvider createVirtualTableProvider(ListableClassHolderSource classes,
|
private static VirtualTableProvider createVirtualTableProvider(ListableClassHolderSource classes,
|
||||||
Predicate<MethodReference> virtualMethods) {
|
Predicate<MethodReference> virtualMethods) {
|
||||||
var builder = new VirtualTableBuilder(classes);
|
var builder = new VirtualTableBuilder(classes);
|
||||||
builder.setMethodsUsedAtCallSites(VirtualTableBuilder.getMethodsUsedOnCallSites(classes));
|
builder.setMethodsUsedAtCallSites(VirtualTableBuilder.getMethodsUsedOnCallSites(classes, false));
|
||||||
builder.setMethodCalledVirtually(virtualMethods);
|
builder.setMethodCalledVirtually(virtualMethods);
|
||||||
return builder.build();
|
return builder.build();
|
||||||
}
|
}
|
||||||
|
|
|
@ -81,7 +81,6 @@ public class WasmGCClassGenerator implements WasmGCClassInfoProvider, WasmGCInit
|
||||||
private Map<ValueType, WasmGCClassInfo> classInfoMap = new LinkedHashMap<>();
|
private Map<ValueType, WasmGCClassInfo> classInfoMap = new LinkedHashMap<>();
|
||||||
private Queue<WasmGCClassInfo> classInfoQueue = new ArrayDeque<>();
|
private Queue<WasmGCClassInfo> classInfoQueue = new ArrayDeque<>();
|
||||||
private ObjectIntMap<FieldReference> fieldIndexes = new ObjectIntHashMap<>();
|
private ObjectIntMap<FieldReference> fieldIndexes = new ObjectIntHashMap<>();
|
||||||
private ObjectIntMap<MethodReference> methodIndexes = new ObjectIntHashMap<>();
|
|
||||||
private Map<FieldReference, WasmGlobal> staticFieldLocations = new HashMap<>();
|
private Map<FieldReference, WasmGlobal> staticFieldLocations = new HashMap<>();
|
||||||
private List<Consumer<WasmFunction>> staticFieldInitializers = new ArrayList<>();
|
private List<Consumer<WasmFunction>> staticFieldInitializers = new ArrayList<>();
|
||||||
private ClassInitializerInfo classInitializerInfo;
|
private ClassInitializerInfo classInitializerInfo;
|
||||||
|
@ -195,8 +194,7 @@ public class WasmGCClassGenerator implements WasmGCClassInfoProvider, WasmGCInit
|
||||||
classInfo.structure = new WasmStructure(name != null ? names.forClass(name) : null);
|
classInfo.structure = new WasmStructure(name != null ? names.forClass(name) : null);
|
||||||
if (name != null) {
|
if (name != null) {
|
||||||
var classReader = classSource.get(name);
|
var classReader = classSource.get(name);
|
||||||
if (classReader == null || !classReader.hasModifier(ElementModifier.ABSTRACT)
|
if (classReader == null || !classReader.hasModifier(ElementModifier.INTERFACE)) {
|
||||||
&& !classReader.hasModifier(ElementModifier.INTERFACE)) {
|
|
||||||
virtualTable = virtualTables.lookup(name);
|
virtualTable = virtualTables.lookup(name);
|
||||||
}
|
}
|
||||||
if (classReader != null && classReader.getParent() != null) {
|
if (classReader != null && classReader.getParent() != null) {
|
||||||
|
@ -237,6 +235,11 @@ public class WasmGCClassGenerator implements WasmGCClassInfoProvider, WasmGCInit
|
||||||
return classArrayItemOffset;
|
return classArrayItemOffset;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getVirtualMethodsOffset() {
|
||||||
|
return virtualTableFieldOffset;
|
||||||
|
}
|
||||||
|
|
||||||
private void initPrimitiveClass(WasmGCClassInfo classInfo, ValueType.Primitive type) {
|
private void initPrimitiveClass(WasmGCClassInfo classInfo, ValueType.Primitive type) {
|
||||||
classInfo.initializer = target -> {
|
classInfo.initializer = target -> {
|
||||||
int kind;
|
int kind;
|
||||||
|
@ -327,6 +330,10 @@ public class WasmGCClassGenerator implements WasmGCClassInfoProvider, WasmGCInit
|
||||||
|
|
||||||
private int fillVirtualTableMethods(List<WasmExpression> target, WasmStructure structure, WasmGlobal global,
|
private int fillVirtualTableMethods(List<WasmExpression> target, WasmStructure structure, WasmGlobal global,
|
||||||
VirtualTable virtualTable, int index, String origin, Set<MethodDescriptor> filled) {
|
VirtualTable virtualTable, int index, String origin, Set<MethodDescriptor> filled) {
|
||||||
|
if (virtualTable.getParent() != null) {
|
||||||
|
index = fillVirtualTableMethods(target, structure, global, virtualTable.getParent(), index, origin,
|
||||||
|
filled);
|
||||||
|
}
|
||||||
for (var method : virtualTable.getMethods()) {
|
for (var method : virtualTable.getMethods()) {
|
||||||
var entry = virtualTable.getEntry(method);
|
var entry = virtualTable.getEntry(method);
|
||||||
if (entry != null && entry.getImplementor() != null && filled.add(method)) {
|
if (entry != null && entry.getImplementor() != null && filled.add(method)) {
|
||||||
|
@ -337,24 +344,21 @@ public class WasmGCClassGenerator implements WasmGCClassInfoProvider, WasmGCInit
|
||||||
module.functions.add(wrapperFunction);
|
module.functions.add(wrapperFunction);
|
||||||
var call = new WasmCall(function);
|
var call = new WasmCall(function);
|
||||||
var instanceParam = new WasmLocal(getClassInfo(virtualTable.getClassName()).getType());
|
var instanceParam = new WasmLocal(getClassInfo(virtualTable.getClassName()).getType());
|
||||||
wrapperFunction.getLocalVariables().add(instanceParam);
|
wrapperFunction.add(instanceParam);
|
||||||
var castTarget = getClassInfo(entry.getImplementor().getClassName()).getType();
|
var castTarget = getClassInfo(entry.getImplementor().getClassName()).getType();
|
||||||
call.getArguments().add(new WasmCast(new WasmGetLocal(instanceParam), castTarget));
|
call.getArguments().add(new WasmCast(new WasmGetLocal(instanceParam), castTarget));
|
||||||
var params = new WasmLocal[method.parameterCount()];
|
var params = new WasmLocal[method.parameterCount()];
|
||||||
for (var i = 0; i < method.parameterCount(); ++i) {
|
for (var i = 0; i < method.parameterCount(); ++i) {
|
||||||
params[i] = new WasmLocal(typeMapper.mapType(method.parameterType(i)));
|
params[i] = new WasmLocal(typeMapper.mapType(method.parameterType(i)));
|
||||||
call.getArguments().add(new WasmGetLocal(params[i]));
|
call.getArguments().add(new WasmGetLocal(params[i]));
|
||||||
|
wrapperFunction.add(params[i]);
|
||||||
}
|
}
|
||||||
wrapperFunction.getLocalVariables().addAll(List.of(params));
|
|
||||||
}
|
}
|
||||||
function.setReferenced(true);
|
function.setReferenced(true);
|
||||||
var ref = new WasmFunctionReference(function);
|
var ref = new WasmFunctionReference(function);
|
||||||
target.add(new WasmStructSet(structure, new WasmGetGlobal(global), index, ref));
|
target.add(new WasmStructSet(structure, new WasmGetGlobal(global), index, ref));
|
||||||
}
|
}
|
||||||
}
|
++index;
|
||||||
if (virtualTable.getParent() != null) {
|
|
||||||
index = fillVirtualTableMethods(target, structure, global, virtualTable.getParent(), index, origin,
|
|
||||||
filled);
|
|
||||||
}
|
}
|
||||||
return index;
|
return index;
|
||||||
}
|
}
|
||||||
|
@ -376,12 +380,14 @@ public class WasmGCClassGenerator implements WasmGCClassInfoProvider, WasmGCInit
|
||||||
addVirtualTableFields(structure, virtualTable.getParent());
|
addVirtualTableFields(structure, virtualTable.getParent());
|
||||||
}
|
}
|
||||||
for (var methodDesc : virtualTable.getMethods()) {
|
for (var methodDesc : virtualTable.getMethods()) {
|
||||||
|
if (methodDesc == null) {
|
||||||
|
structure.getFields().add(WasmType.Reference.FUNC.asStorage());
|
||||||
|
} else {
|
||||||
var functionType = getFunctionType(virtualTable.getClassName(), methodDesc);
|
var functionType = getFunctionType(virtualTable.getClassName(), methodDesc);
|
||||||
var methodRef = new MethodReference(virtualTable.getClassName(), methodDesc);
|
|
||||||
methodIndexes.put(methodRef, structure.getFields().size());
|
|
||||||
structure.getFields().add(functionType.getReference().asStorage());
|
structure.getFields().add(functionType.getReference().asStorage());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private WasmFunctionType getFunctionType(String className, MethodDescriptor methodDesc) {
|
private WasmFunctionType getFunctionType(String className, MethodDescriptor methodDesc) {
|
||||||
var returnType = typeMapper.mapType(methodDesc.getResultType());
|
var returnType = typeMapper.mapType(methodDesc.getResultType());
|
||||||
|
@ -454,15 +460,6 @@ public class WasmGCClassGenerator implements WasmGCClassInfoProvider, WasmGCInit
|
||||||
return global;
|
return global;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public int getVirtualMethodIndex(MethodReference methodRef) {
|
|
||||||
var result = methodIndexes.getOrDefault(methodRef, -1);
|
|
||||||
if (result < 0) {
|
|
||||||
throw new IllegalStateException("Can't get offset of method " + methodRef);
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void fillFields(WasmGCClassInfo classInfo, ValueType type) {
|
private void fillFields(WasmGCClassInfo classInfo, ValueType type) {
|
||||||
var fields = classInfo.structure.getFields();
|
var fields = classInfo.structure.getFields();
|
||||||
fields.add(standardClasses.classClass().getType().asStorage());
|
fields.add(standardClasses.classClass().getType().asStorage());
|
||||||
|
|
|
@ -17,7 +17,6 @@ package org.teavm.backend.wasm.generate.gc.classes;
|
||||||
|
|
||||||
import org.teavm.backend.wasm.model.WasmGlobal;
|
import org.teavm.backend.wasm.model.WasmGlobal;
|
||||||
import org.teavm.model.FieldReference;
|
import org.teavm.model.FieldReference;
|
||||||
import org.teavm.model.MethodReference;
|
|
||||||
import org.teavm.model.ValueType;
|
import org.teavm.model.ValueType;
|
||||||
|
|
||||||
public interface WasmGCClassInfoProvider {
|
public interface WasmGCClassInfoProvider {
|
||||||
|
@ -32,7 +31,7 @@ public interface WasmGCClassInfoProvider {
|
||||||
|
|
||||||
WasmGlobal getStaticFieldLocation(FieldReference fieldRef);
|
WasmGlobal getStaticFieldLocation(FieldReference fieldRef);
|
||||||
|
|
||||||
int getVirtualMethodIndex(MethodReference methodRef);
|
int getVirtualMethodsOffset();
|
||||||
|
|
||||||
default WasmGCClassInfo getClassInfo(String name) {
|
default WasmGCClassInfo getClassInfo(String name) {
|
||||||
return getClassInfo(ValueType.object(name));
|
return getClassInfo(ValueType.object(name));
|
||||||
|
|
|
@ -15,6 +15,12 @@
|
||||||
*/
|
*/
|
||||||
package org.teavm.backend.wasm.generate.gc.methods;
|
package org.teavm.backend.wasm.generate.gc.methods;
|
||||||
|
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.LinkedHashSet;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Set;
|
||||||
import org.teavm.backend.wasm.BaseWasmFunctionRepository;
|
import org.teavm.backend.wasm.BaseWasmFunctionRepository;
|
||||||
import org.teavm.backend.wasm.WasmFunctionTypes;
|
import org.teavm.backend.wasm.WasmFunctionTypes;
|
||||||
import org.teavm.backend.wasm.gc.WasmGCMethodReturnTypes;
|
import org.teavm.backend.wasm.gc.WasmGCMethodReturnTypes;
|
||||||
|
@ -32,6 +38,8 @@ import org.teavm.backend.wasm.model.expression.WasmNullConstant;
|
||||||
import org.teavm.backend.wasm.runtime.WasmGCSupport;
|
import org.teavm.backend.wasm.runtime.WasmGCSupport;
|
||||||
import org.teavm.model.ClassHierarchy;
|
import org.teavm.model.ClassHierarchy;
|
||||||
import org.teavm.model.ClassReaderSource;
|
import org.teavm.model.ClassReaderSource;
|
||||||
|
import org.teavm.model.ElementModifier;
|
||||||
|
import org.teavm.model.ListableClassReaderSource;
|
||||||
import org.teavm.model.MethodReference;
|
import org.teavm.model.MethodReference;
|
||||||
import org.teavm.model.classes.VirtualTableProvider;
|
import org.teavm.model.classes.VirtualTableProvider;
|
||||||
|
|
||||||
|
@ -43,7 +51,7 @@ public class WasmGCGenerationContext implements BaseWasmGenerationContext {
|
||||||
private VirtualTableProvider virtualTables;
|
private VirtualTableProvider virtualTables;
|
||||||
private WasmGCTypeMapper typeMapper;
|
private WasmGCTypeMapper typeMapper;
|
||||||
private WasmFunctionTypes functionTypes;
|
private WasmFunctionTypes functionTypes;
|
||||||
private ClassReaderSource classes;
|
private ListableClassReaderSource classes;
|
||||||
private ClassHierarchy hierarchy;
|
private ClassHierarchy hierarchy;
|
||||||
private BaseWasmFunctionRepository functions;
|
private BaseWasmFunctionRepository functions;
|
||||||
private WasmGCSupertypeFunctionProvider supertypeFunctions;
|
private WasmGCSupertypeFunctionProvider supertypeFunctions;
|
||||||
|
@ -55,9 +63,10 @@ public class WasmGCGenerationContext implements BaseWasmGenerationContext {
|
||||||
private WasmFunction cceMethod;
|
private WasmFunction cceMethod;
|
||||||
private WasmGlobal exceptionGlobal;
|
private WasmGlobal exceptionGlobal;
|
||||||
private WasmTag exceptionTag;
|
private WasmTag exceptionTag;
|
||||||
|
private Map<String, Set<String>> interfaceImplementors;
|
||||||
|
|
||||||
public WasmGCGenerationContext(WasmModule module, VirtualTableProvider virtualTables,
|
public WasmGCGenerationContext(WasmModule module, VirtualTableProvider virtualTables,
|
||||||
WasmGCTypeMapper typeMapper, WasmFunctionTypes functionTypes, ClassReaderSource classes,
|
WasmGCTypeMapper typeMapper, WasmFunctionTypes functionTypes, ListableClassReaderSource classes,
|
||||||
ClassHierarchy hierarchy, BaseWasmFunctionRepository functions,
|
ClassHierarchy hierarchy, BaseWasmFunctionRepository functions,
|
||||||
WasmGCSupertypeFunctionProvider supertypeFunctions, WasmGCClassInfoProvider classInfoProvider,
|
WasmGCSupertypeFunctionProvider supertypeFunctions, WasmGCClassInfoProvider classInfoProvider,
|
||||||
WasmGCStandardClasses standardClasses, WasmGCStringProvider strings,
|
WasmGCStandardClasses standardClasses, WasmGCStringProvider strings,
|
||||||
|
@ -180,4 +189,36 @@ public class WasmGCGenerationContext implements BaseWasmGenerationContext {
|
||||||
public WasmGCMethodReturnTypes returnTypes() {
|
public WasmGCMethodReturnTypes returnTypes() {
|
||||||
return returnTypes;
|
return returnTypes;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Collection<String> getInterfaceImplementors(String className) {
|
||||||
|
if (interfaceImplementors == null) {
|
||||||
|
fillInterfaceImplementors();
|
||||||
|
}
|
||||||
|
var result = interfaceImplementors.get(className);
|
||||||
|
return result != null ? result : List.of();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void fillInterfaceImplementors() {
|
||||||
|
interfaceImplementors = new HashMap<>();
|
||||||
|
for (var className : classes.getClassNames()) {
|
||||||
|
var cls = classes.get(className);
|
||||||
|
if (!cls.hasModifier(ElementModifier.INTERFACE)) {
|
||||||
|
for (var itf : cls.getInterfaces()) {
|
||||||
|
addInterfaceImplementor(className, itf);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void addInterfaceImplementor(String implementorName, String interfaceName) {
|
||||||
|
var implementorsByKey = interfaceImplementors.computeIfAbsent(interfaceName, k -> new LinkedHashSet<>());
|
||||||
|
if (implementorsByKey.add(implementorName)) {
|
||||||
|
var itf = classes.get(implementorName);
|
||||||
|
if (itf != null) {
|
||||||
|
for (var parentItf : itf.getInterfaces()) {
|
||||||
|
addInterfaceImplementor(implementorName, parentItf);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,7 +23,6 @@ import org.teavm.ast.InvocationExpr;
|
||||||
import org.teavm.ast.InvocationType;
|
import org.teavm.ast.InvocationType;
|
||||||
import org.teavm.ast.QualificationExpr;
|
import org.teavm.ast.QualificationExpr;
|
||||||
import org.teavm.ast.SubscriptExpr;
|
import org.teavm.ast.SubscriptExpr;
|
||||||
import org.teavm.ast.UnwrapArrayExpr;
|
|
||||||
import org.teavm.backend.wasm.BaseWasmFunctionRepository;
|
import org.teavm.backend.wasm.BaseWasmFunctionRepository;
|
||||||
import org.teavm.backend.wasm.WasmFunctionTypes;
|
import org.teavm.backend.wasm.WasmFunctionTypes;
|
||||||
import org.teavm.backend.wasm.gc.PreciseTypeInference;
|
import org.teavm.backend.wasm.gc.PreciseTypeInference;
|
||||||
|
@ -63,10 +62,13 @@ import org.teavm.backend.wasm.model.expression.WasmStructSet;
|
||||||
import org.teavm.backend.wasm.model.expression.WasmThrow;
|
import org.teavm.backend.wasm.model.expression.WasmThrow;
|
||||||
import org.teavm.backend.wasm.model.expression.WasmUnreachable;
|
import org.teavm.backend.wasm.model.expression.WasmUnreachable;
|
||||||
import org.teavm.model.ClassHierarchy;
|
import org.teavm.model.ClassHierarchy;
|
||||||
|
import org.teavm.model.ElementModifier;
|
||||||
import org.teavm.model.FieldReference;
|
import org.teavm.model.FieldReference;
|
||||||
|
import org.teavm.model.MethodDescriptor;
|
||||||
import org.teavm.model.MethodReference;
|
import org.teavm.model.MethodReference;
|
||||||
import org.teavm.model.TextLocation;
|
import org.teavm.model.TextLocation;
|
||||||
import org.teavm.model.ValueType;
|
import org.teavm.model.ValueType;
|
||||||
|
import org.teavm.model.classes.VirtualTable;
|
||||||
|
|
||||||
public class WasmGCGenerationVisitor extends BaseWasmGenerationVisitor {
|
public class WasmGCGenerationVisitor extends BaseWasmGenerationVisitor {
|
||||||
private WasmGCGenerationContext context;
|
private WasmGCGenerationContext context;
|
||||||
|
@ -136,13 +138,7 @@ public class WasmGCGenerationVisitor extends BaseWasmGenerationVisitor {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void visit(UnwrapArrayExpr expr) {
|
protected WasmExpression unwrapArray(WasmExpression array) {
|
||||||
accept(expr.getArray());
|
|
||||||
result = unwrapArray(result);
|
|
||||||
result.setLocation(expr.getLocation());
|
|
||||||
}
|
|
||||||
|
|
||||||
private WasmExpression unwrapArray(WasmExpression array) {
|
|
||||||
array.acceptVisitor(typeInference);
|
array.acceptVisitor(typeInference);
|
||||||
var arrayType = (WasmType.CompositeReference) typeInference.getResult();
|
var arrayType = (WasmType.CompositeReference) typeInference.getResult();
|
||||||
var arrayStruct = (WasmStructure) arrayType.composite;
|
var arrayStruct = (WasmStructure) arrayType.composite;
|
||||||
|
@ -202,9 +198,16 @@ public class WasmGCGenerationVisitor extends BaseWasmGenerationVisitor {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected WasmExpression nullLiteral() {
|
protected WasmExpression nullLiteral(Expr expr) {
|
||||||
return new WasmNullConstant(expectedType instanceof WasmType.Reference
|
var type = expectedType;
|
||||||
? (WasmType.Reference) expectedType
|
if (expr.getVariableIndex() >= 0) {
|
||||||
|
var javaType = types.typeOf(expr.getVariableIndex());
|
||||||
|
if (javaType != null) {
|
||||||
|
type = mapType(javaType.valueType);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return new WasmNullConstant(type instanceof WasmType.Reference
|
||||||
|
? (WasmType.Reference) type
|
||||||
: WasmType.Reference.STRUCT);
|
: WasmType.Reference.STRUCT);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -252,15 +255,22 @@ public class WasmGCGenerationVisitor extends BaseWasmGenerationVisitor {
|
||||||
if (vtable == null) {
|
if (vtable == null) {
|
||||||
return new WasmUnreachable();
|
return new WasmUnreachable();
|
||||||
}
|
}
|
||||||
method = new MethodReference(vtable.getClassName(), method.getDescriptor());
|
var cls = context.classes().get(method.getClassName());
|
||||||
|
assert cls != null : "Virtual table can't be generated for absent class";
|
||||||
|
|
||||||
arguments.get(0).acceptVisitor(typeInference);
|
if (cls.hasModifier(ElementModifier.INTERFACE)) {
|
||||||
var instanceType = (WasmType.CompositeReference) typeInference.getResult();
|
vtable = pickVirtualTableForInterfaceCall(vtable, method.getDescriptor());
|
||||||
var instanceStruct = (WasmStructure) instanceType.composite;
|
}
|
||||||
|
|
||||||
|
int vtableIndex = vtable.getMethods().indexOf(method.getDescriptor());
|
||||||
|
if (vtable.getParent() != null) {
|
||||||
|
vtableIndex += vtable.getParent().size();
|
||||||
|
}
|
||||||
|
var instanceStruct = context.classInfoProvider().getClassInfo(vtable.getClassName()).getStructure();
|
||||||
|
|
||||||
WasmExpression classRef = new WasmStructGet(instanceStruct, new WasmGetLocal(instance),
|
WasmExpression classRef = new WasmStructGet(instanceStruct, new WasmGetLocal(instance),
|
||||||
WasmGCClassInfoProvider.CLASS_FIELD_OFFSET);
|
WasmGCClassInfoProvider.CLASS_FIELD_OFFSET);
|
||||||
var index = context.classInfoProvider().getVirtualMethodIndex(method);
|
var index = context.classInfoProvider().getVirtualMethodsOffset() + vtableIndex;
|
||||||
var vtableStruct = context.classInfoProvider().getClassInfo(vtable.getClassName())
|
var vtableStruct = context.classInfoProvider().getClassInfo(vtable.getClassName())
|
||||||
.getVirtualTableStructure();
|
.getVirtualTableStructure();
|
||||||
classRef = new WasmCast(classRef, vtableStruct.getReference());
|
classRef = new WasmCast(classRef, vtableStruct.getReference());
|
||||||
|
@ -272,6 +282,20 @@ public class WasmGCGenerationVisitor extends BaseWasmGenerationVisitor {
|
||||||
return invoke;
|
return invoke;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private VirtualTable pickVirtualTableForInterfaceCall(VirtualTable virtualTable, MethodDescriptor descriptor) {
|
||||||
|
var implementors = context.getInterfaceImplementors(virtualTable.getClassName());
|
||||||
|
for (var implementor : implementors) {
|
||||||
|
var implementorVtable = context.virtualTables().lookup(implementor);
|
||||||
|
if (implementorVtable != null && implementorVtable.hasMethod(descriptor)) {
|
||||||
|
while (implementorVtable.getParent() != null && implementorVtable.getParent().hasMethod(descriptor)) {
|
||||||
|
implementorVtable = implementorVtable.getParent();
|
||||||
|
}
|
||||||
|
return implementorVtable;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
throw new IllegalStateException();
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void allocateObject(String className, TextLocation location, WasmLocal local,
|
protected void allocateObject(String className, TextLocation location, WasmLocal local,
|
||||||
List<WasmExpression> target) {
|
List<WasmExpression> target) {
|
||||||
|
|
|
@ -45,8 +45,8 @@ import org.teavm.diagnostics.Diagnostics;
|
||||||
import org.teavm.interop.Import;
|
import org.teavm.interop.Import;
|
||||||
import org.teavm.model.CallLocation;
|
import org.teavm.model.CallLocation;
|
||||||
import org.teavm.model.ClassHierarchy;
|
import org.teavm.model.ClassHierarchy;
|
||||||
import org.teavm.model.ClassHolderSource;
|
|
||||||
import org.teavm.model.ElementModifier;
|
import org.teavm.model.ElementModifier;
|
||||||
|
import org.teavm.model.ListableClassHolderSource;
|
||||||
import org.teavm.model.MethodHolder;
|
import org.teavm.model.MethodHolder;
|
||||||
import org.teavm.model.MethodReader;
|
import org.teavm.model.MethodReader;
|
||||||
import org.teavm.model.MethodReference;
|
import org.teavm.model.MethodReference;
|
||||||
|
@ -58,7 +58,7 @@ import org.teavm.model.util.RegisterAllocator;
|
||||||
public class WasmGCMethodGenerator implements BaseWasmFunctionRepository {
|
public class WasmGCMethodGenerator implements BaseWasmFunctionRepository {
|
||||||
private WasmModule module;
|
private WasmModule module;
|
||||||
private ClassHierarchy hierarchy;
|
private ClassHierarchy hierarchy;
|
||||||
private ClassHolderSource classes;
|
private ListableClassHolderSource classes;
|
||||||
private VirtualTableProvider virtualTables;
|
private VirtualTableProvider virtualTables;
|
||||||
private ClassInitializerInfo classInitInfo;
|
private ClassInitializerInfo classInitInfo;
|
||||||
private WasmFunctionTypes functionTypes;
|
private WasmFunctionTypes functionTypes;
|
||||||
|
@ -83,7 +83,7 @@ public class WasmGCMethodGenerator implements BaseWasmFunctionRepository {
|
||||||
public WasmGCMethodGenerator(
|
public WasmGCMethodGenerator(
|
||||||
WasmModule module,
|
WasmModule module,
|
||||||
ClassHierarchy hierarchy,
|
ClassHierarchy hierarchy,
|
||||||
ClassHolderSource classes,
|
ListableClassHolderSource classes,
|
||||||
VirtualTableProvider virtualTables,
|
VirtualTableProvider virtualTables,
|
||||||
ClassInitializerInfo classInitInfo,
|
ClassInitializerInfo classInitInfo,
|
||||||
WasmFunctionTypes functionTypes,
|
WasmFunctionTypes functionTypes,
|
||||||
|
|
|
@ -127,7 +127,7 @@ public class VirtualTableBuilder {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
List<MethodDescriptor> methodsAtCallSites = methodsUsedAtCallSites.get(className);
|
var methodsAtCallSites = methodsUsedAtCallSites.get(className);
|
||||||
if (methodsAtCallSites != null) {
|
if (methodsAtCallSites != null) {
|
||||||
for (MethodDescriptor methodDesc : methodsAtCallSites) {
|
for (MethodDescriptor methodDesc : methodsAtCallSites) {
|
||||||
if (cls.hasModifier(ElementModifier.FINAL) && !table.entries.containsKey(methodDesc)) {
|
if (cls.hasModifier(ElementModifier.FINAL) && !table.entries.containsKey(methodDesc)) {
|
||||||
|
@ -162,7 +162,7 @@ public class VirtualTableBuilder {
|
||||||
}
|
}
|
||||||
|
|
||||||
private void copyEntries(TableBuilder source, TableBuilder target) {
|
private void copyEntries(TableBuilder source, TableBuilder target) {
|
||||||
for (Map.Entry<MethodDescriptor, EntryBuilder> entry : source.entries.entrySet()) {
|
for (var entry : source.entries.entrySet()) {
|
||||||
EntryBuilder targetEntry = target.entries.computeIfAbsent(entry.getKey(), k -> new EntryBuilder());
|
EntryBuilder targetEntry = target.entries.computeIfAbsent(entry.getKey(), k -> new EntryBuilder());
|
||||||
targetEntry.addParent(entry.getValue());
|
targetEntry.addParent(entry.getValue());
|
||||||
if (entry.getValue().implementor != null && targetEntry.implementor == null) {
|
if (entry.getValue().implementor != null && targetEntry.implementor == null) {
|
||||||
|
@ -197,7 +197,7 @@ public class VirtualTableBuilder {
|
||||||
|
|
||||||
private void liftEntries() {
|
private void liftEntries() {
|
||||||
buildClassTree();
|
buildClassTree();
|
||||||
for (Map.Entry<MethodDescriptor, List<String>> group : groupMethods().entrySet()) {
|
for (var group : groupMethods().entrySet()) {
|
||||||
String commonSuperclass = commonSuperclass(group.getValue());
|
String commonSuperclass = commonSuperclass(group.getValue());
|
||||||
Set<String> visited = new HashSet<>();
|
Set<String> visited = new HashSet<>();
|
||||||
for (String cls : group.getValue()) {
|
for (String cls : group.getValue()) {
|
||||||
|
@ -397,17 +397,16 @@ public class VirtualTableBuilder {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
List<MethodDescriptor> newMethods = context.methods.subList(methodsStart, context.methods.size());
|
var newMethods = context.methods.subList(methodsStart, context.methods.size());
|
||||||
Set<MethodDescriptor> methodSet = new HashSet<>();
|
Set<MethodDescriptor> methodSet = new HashSet<>();
|
||||||
for (MethodDescriptor method : newMethods) {
|
for (MethodDescriptor method : newMethods) {
|
||||||
if (method != null) {
|
if (method != null) {
|
||||||
methodSet.add(method);
|
methodSet.add(method);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
List<? extends MethodDescriptor> readonlyNewMethods = Collections.unmodifiableList(
|
var readonlyNewMethods = Collections.unmodifiableList(Arrays.asList(
|
||||||
Arrays.asList(newMethods.toArray(new MethodDescriptor[0])));
|
newMethods.toArray(new MethodDescriptor[0])));
|
||||||
VirtualTable resultTable = new VirtualTable(className, parent, readonlyNewMethods,
|
var resultTable = new VirtualTable(className, parent, readonlyNewMethods, methodSet, resultEntries);
|
||||||
methodSet, resultEntries);
|
|
||||||
result.virtualTables.put(className, resultTable);
|
result.virtualTables.put(className, resultTable);
|
||||||
|
|
||||||
List<String> children = classChildren.get(className);
|
List<String> children = classChildren.get(className);
|
||||||
|
@ -489,10 +488,9 @@ public class VirtualTableBuilder {
|
||||||
methodSet.add(method);
|
methodSet.add(method);
|
||||||
}
|
}
|
||||||
|
|
||||||
List<? extends MethodDescriptor> readonlyNewMethods = Collections.unmodifiableList(
|
var readonlyMethods = Collections.unmodifiableList(
|
||||||
Arrays.asList(methods.toArray(new MethodDescriptor[0])));
|
Arrays.asList(methods.toArray(new MethodDescriptor[0])));
|
||||||
VirtualTable resultTable = new VirtualTable(className, null, readonlyNewMethods,
|
var resultTable = new VirtualTable(className, null, readonlyMethods, methodSet, Map.of());
|
||||||
methodSet, Collections.emptyMap());
|
|
||||||
result.virtualTables.put(className, resultTable);
|
result.virtualTables.put(className, resultTable);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -523,7 +521,8 @@ public class VirtualTableBuilder {
|
||||||
List<MethodDescriptor> methods = new ArrayList<>();
|
List<MethodDescriptor> methods = new ArrayList<>();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Set<MethodReference> getMethodsUsedOnCallSites(ListableClassHolderSource classes) {
|
public static Set<MethodReference> getMethodsUsedOnCallSites(ListableClassHolderSource classes,
|
||||||
|
boolean withCloneArray) {
|
||||||
var virtualMethods = new HashSet<MethodReference>();
|
var virtualMethods = new HashSet<MethodReference>();
|
||||||
|
|
||||||
for (var className : classes.getClassNames()) {
|
for (var className : classes.getClassNames()) {
|
||||||
|
@ -542,12 +541,14 @@ public class VirtualTableBuilder {
|
||||||
virtualMethods.add(invoke.getMethod());
|
virtualMethods.add(invoke.getMethod());
|
||||||
}
|
}
|
||||||
} else if (insn instanceof CloneArrayInstruction) {
|
} else if (insn instanceof CloneArrayInstruction) {
|
||||||
|
if (withCloneArray) {
|
||||||
virtualMethods.add(new MethodReference(Object.class, "clone", Object.class));
|
virtualMethods.add(new MethodReference(Object.class, "clone", Object.class));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return virtualMethods;
|
return virtualMethods;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user