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) {
|
||||
VirtualTableBuilder builder = new VirtualTableBuilder(classes);
|
||||
builder.setMethodsUsedAtCallSites(VirtualTableBuilder.getMethodsUsedOnCallSites(classes));
|
||||
builder.setMethodsUsedAtCallSites(VirtualTableBuilder.getMethodsUsedOnCallSites(classes, true));
|
||||
builder.setMethodCalledVirtually(controller::isVirtual);
|
||||
return builder.build();
|
||||
}
|
||||
|
|
|
@ -1070,7 +1070,7 @@ public class WasmTarget implements TeaVMTarget, TeaVMWasmHost {
|
|||
|
||||
private VirtualTableProvider createVirtualTableProvider(ListableClassHolderSource classes) {
|
||||
var builder = new VirtualTableBuilder(classes);
|
||||
builder.setMethodsUsedAtCallSites(VirtualTableBuilder.getMethodsUsedOnCallSites(classes));
|
||||
builder.setMethodsUsedAtCallSites(VirtualTableBuilder.getMethodsUsedOnCallSites(classes, true));
|
||||
builder.setMethodCalledVirtually(controller::isVirtual);
|
||||
return builder.build();
|
||||
}
|
||||
|
|
|
@ -34,12 +34,12 @@ public final class WasmGCUtil {
|
|||
if (firstPath.get(0) != secondPath.get(0)) {
|
||||
return "java.lang.Object";
|
||||
}
|
||||
var max = Math.max(firstPath.size(), secondPath.size());
|
||||
var min = Math.min(firstPath.size(), secondPath.size());
|
||||
var index = 1;
|
||||
while (index < max && firstPath.get(index) == secondPath.get(index)) {
|
||||
while (index < min && firstPath.get(index) == secondPath.get(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) {
|
||||
|
|
|
@ -29,7 +29,6 @@ import org.teavm.ast.QualificationExpr;
|
|||
import org.teavm.ast.Statement;
|
||||
import org.teavm.ast.SubscriptExpr;
|
||||
import org.teavm.ast.TryCatchStatement;
|
||||
import org.teavm.ast.UnwrapArrayExpr;
|
||||
import org.teavm.backend.wasm.WasmFunctionRepository;
|
||||
import org.teavm.backend.wasm.WasmFunctionTypes;
|
||||
import org.teavm.backend.wasm.WasmHeap;
|
||||
|
@ -299,7 +298,7 @@ public class WasmGenerationVisitor extends BaseWasmGenerationVisitor {
|
|||
}
|
||||
|
||||
@Override
|
||||
protected WasmExpression nullLiteral() {
|
||||
protected WasmExpression nullLiteral(Expr expr) {
|
||||
return new WasmInt32Constant(0);
|
||||
}
|
||||
|
||||
|
@ -371,11 +370,6 @@ public class WasmGenerationVisitor extends BaseWasmGenerationVisitor {
|
|||
return new WasmIntBinary(WasmIntType.INT32, WasmIntBinaryOperation.ADD, array, index);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(UnwrapArrayExpr expr) {
|
||||
accept(expr.getArray());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected WasmExpression invocation(InvocationExpr expr, List<WasmExpression> resultConsumer, boolean willDrop) {
|
||||
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.TryCatchStatement;
|
||||
import org.teavm.ast.UnaryExpr;
|
||||
import org.teavm.ast.UnwrapArrayExpr;
|
||||
import org.teavm.ast.VariableExpr;
|
||||
import org.teavm.ast.WhileStatement;
|
||||
import org.teavm.backend.wasm.WasmRuntime;
|
||||
|
@ -453,7 +454,7 @@ public abstract class BaseWasmGenerationVisitor implements StatementVisitor, Exp
|
|||
accept(value);
|
||||
result.acceptVisitor(typeInference);
|
||||
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);
|
||||
check.setResult(cachedValue.expr());
|
||||
|
@ -555,7 +556,7 @@ public abstract class BaseWasmGenerationVisitor implements StatementVisitor, Exp
|
|||
@Override
|
||||
public void visit(ConstantExpr expr) {
|
||||
if (expr.getValue() == null) {
|
||||
result = nullLiteral();
|
||||
result = nullLiteral(expr);
|
||||
} else if (expr.getValue() instanceof Integer) {
|
||||
result = new WasmInt32Constant((Integer) expr.getValue());
|
||||
} else if (expr.getValue() instanceof Long) {
|
||||
|
@ -574,7 +575,7 @@ public abstract class BaseWasmGenerationVisitor implements StatementVisitor, Exp
|
|||
result.setLocation(expr.getLocation());
|
||||
}
|
||||
|
||||
protected abstract WasmExpression nullLiteral();
|
||||
protected abstract WasmExpression nullLiteral(Expr expr);
|
||||
|
||||
protected abstract WasmExpression stringLiteral(String s);
|
||||
|
||||
|
@ -894,12 +895,14 @@ public abstract class BaseWasmGenerationVisitor implements StatementVisitor, Exp
|
|||
return block;
|
||||
} else {
|
||||
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 block = new WasmBlock(false);
|
||||
block.setType(mapType(reference.getReturnType()));
|
||||
|
||||
var instanceVar = tempVars.acquire(WasmType.INT32);
|
||||
var instanceVar = tempVars.acquire(instanceWasmType);
|
||||
block.getBody().add(new WasmSetLocal(instanceVar, instance));
|
||||
instance = new WasmGetLocal(instanceVar);
|
||||
|
||||
|
@ -1066,7 +1069,8 @@ public abstract class BaseWasmGenerationVisitor implements StatementVisitor, Exp
|
|||
|
||||
for (int i = 0; i < expr.getData().size(); ++i) {
|
||||
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));
|
||||
|
@ -1126,7 +1130,8 @@ public abstract class BaseWasmGenerationVisitor implements StatementVisitor, Exp
|
|||
block.setType(WasmType.INT32);
|
||||
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);
|
||||
ifNull.setResult(new WasmInt32Constant(0));
|
||||
|
@ -1545,6 +1550,17 @@ public abstract class BaseWasmGenerationVisitor implements StatementVisitor, Exp
|
|||
|
||||
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 {
|
||||
public abstract void generateRegister(List<WasmExpression> consumer, TextLocation location);
|
||||
|
||||
|
|
|
@ -140,7 +140,7 @@ public class WasmGCDeclarationsGenerator {
|
|||
private static VirtualTableProvider createVirtualTableProvider(ListableClassHolderSource classes,
|
||||
Predicate<MethodReference> virtualMethods) {
|
||||
var builder = new VirtualTableBuilder(classes);
|
||||
builder.setMethodsUsedAtCallSites(VirtualTableBuilder.getMethodsUsedOnCallSites(classes));
|
||||
builder.setMethodsUsedAtCallSites(VirtualTableBuilder.getMethodsUsedOnCallSites(classes, false));
|
||||
builder.setMethodCalledVirtually(virtualMethods);
|
||||
return builder.build();
|
||||
}
|
||||
|
|
|
@ -81,7 +81,6 @@ public class WasmGCClassGenerator implements WasmGCClassInfoProvider, WasmGCInit
|
|||
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;
|
||||
|
@ -195,8 +194,7 @@ public class WasmGCClassGenerator implements WasmGCClassInfoProvider, WasmGCInit
|
|||
classInfo.structure = new WasmStructure(name != null ? names.forClass(name) : null);
|
||||
if (name != null) {
|
||||
var classReader = classSource.get(name);
|
||||
if (classReader == null || !classReader.hasModifier(ElementModifier.ABSTRACT)
|
||||
&& !classReader.hasModifier(ElementModifier.INTERFACE)) {
|
||||
if (classReader == null || !classReader.hasModifier(ElementModifier.INTERFACE)) {
|
||||
virtualTable = virtualTables.lookup(name);
|
||||
}
|
||||
if (classReader != null && classReader.getParent() != null) {
|
||||
|
@ -237,6 +235,11 @@ public class WasmGCClassGenerator implements WasmGCClassInfoProvider, WasmGCInit
|
|||
return classArrayItemOffset;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getVirtualMethodsOffset() {
|
||||
return virtualTableFieldOffset;
|
||||
}
|
||||
|
||||
private void initPrimitiveClass(WasmGCClassInfo classInfo, ValueType.Primitive type) {
|
||||
classInfo.initializer = target -> {
|
||||
int kind;
|
||||
|
@ -327,6 +330,10 @@ public class WasmGCClassGenerator implements WasmGCClassInfoProvider, WasmGCInit
|
|||
|
||||
private int fillVirtualTableMethods(List<WasmExpression> target, WasmStructure structure, WasmGlobal global,
|
||||
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()) {
|
||||
var entry = virtualTable.getEntry(method);
|
||||
if (entry != null && entry.getImplementor() != null && filled.add(method)) {
|
||||
|
@ -337,24 +344,21 @@ public class WasmGCClassGenerator implements WasmGCClassInfoProvider, WasmGCInit
|
|||
module.functions.add(wrapperFunction);
|
||||
var call = new WasmCall(function);
|
||||
var instanceParam = new WasmLocal(getClassInfo(virtualTable.getClassName()).getType());
|
||||
wrapperFunction.getLocalVariables().add(instanceParam);
|
||||
wrapperFunction.add(instanceParam);
|
||||
var castTarget = getClassInfo(entry.getImplementor().getClassName()).getType();
|
||||
call.getArguments().add(new WasmCast(new WasmGetLocal(instanceParam), castTarget));
|
||||
var params = new WasmLocal[method.parameterCount()];
|
||||
for (var i = 0; i < method.parameterCount(); ++i) {
|
||||
params[i] = new WasmLocal(typeMapper.mapType(method.parameterType(i)));
|
||||
call.getArguments().add(new WasmGetLocal(params[i]));
|
||||
wrapperFunction.add(params[i]);
|
||||
}
|
||||
wrapperFunction.getLocalVariables().addAll(List.of(params));
|
||||
}
|
||||
function.setReferenced(true);
|
||||
var ref = new WasmFunctionReference(function);
|
||||
target.add(new WasmStructSet(structure, new WasmGetGlobal(global), index, ref));
|
||||
}
|
||||
}
|
||||
if (virtualTable.getParent() != null) {
|
||||
index = fillVirtualTableMethods(target, structure, global, virtualTable.getParent(), index, origin,
|
||||
filled);
|
||||
++index;
|
||||
}
|
||||
return index;
|
||||
}
|
||||
|
@ -376,12 +380,14 @@ public class WasmGCClassGenerator implements WasmGCClassInfoProvider, WasmGCInit
|
|||
addVirtualTableFields(structure, virtualTable.getParent());
|
||||
}
|
||||
for (var methodDesc : virtualTable.getMethods()) {
|
||||
if (methodDesc == null) {
|
||||
structure.getFields().add(WasmType.Reference.FUNC.asStorage());
|
||||
} else {
|
||||
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());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private WasmFunctionType getFunctionType(String className, MethodDescriptor methodDesc) {
|
||||
var returnType = typeMapper.mapType(methodDesc.getResultType());
|
||||
|
@ -454,15 +460,6 @@ public class WasmGCClassGenerator implements WasmGCClassInfoProvider, WasmGCInit
|
|||
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) {
|
||||
var fields = classInfo.structure.getFields();
|
||||
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.model.FieldReference;
|
||||
import org.teavm.model.MethodReference;
|
||||
import org.teavm.model.ValueType;
|
||||
|
||||
public interface WasmGCClassInfoProvider {
|
||||
|
@ -32,7 +31,7 @@ public interface WasmGCClassInfoProvider {
|
|||
|
||||
WasmGlobal getStaticFieldLocation(FieldReference fieldRef);
|
||||
|
||||
int getVirtualMethodIndex(MethodReference methodRef);
|
||||
int getVirtualMethodsOffset();
|
||||
|
||||
default WasmGCClassInfo getClassInfo(String name) {
|
||||
return getClassInfo(ValueType.object(name));
|
||||
|
|
|
@ -15,6 +15,12 @@
|
|||
*/
|
||||
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.WasmFunctionTypes;
|
||||
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.model.ClassHierarchy;
|
||||
import org.teavm.model.ClassReaderSource;
|
||||
import org.teavm.model.ElementModifier;
|
||||
import org.teavm.model.ListableClassReaderSource;
|
||||
import org.teavm.model.MethodReference;
|
||||
import org.teavm.model.classes.VirtualTableProvider;
|
||||
|
||||
|
@ -43,7 +51,7 @@ public class WasmGCGenerationContext implements BaseWasmGenerationContext {
|
|||
private VirtualTableProvider virtualTables;
|
||||
private WasmGCTypeMapper typeMapper;
|
||||
private WasmFunctionTypes functionTypes;
|
||||
private ClassReaderSource classes;
|
||||
private ListableClassReaderSource classes;
|
||||
private ClassHierarchy hierarchy;
|
||||
private BaseWasmFunctionRepository functions;
|
||||
private WasmGCSupertypeFunctionProvider supertypeFunctions;
|
||||
|
@ -55,9 +63,10 @@ public class WasmGCGenerationContext implements BaseWasmGenerationContext {
|
|||
private WasmFunction cceMethod;
|
||||
private WasmGlobal exceptionGlobal;
|
||||
private WasmTag exceptionTag;
|
||||
private Map<String, Set<String>> interfaceImplementors;
|
||||
|
||||
public WasmGCGenerationContext(WasmModule module, VirtualTableProvider virtualTables,
|
||||
WasmGCTypeMapper typeMapper, WasmFunctionTypes functionTypes, ClassReaderSource classes,
|
||||
WasmGCTypeMapper typeMapper, WasmFunctionTypes functionTypes, ListableClassReaderSource classes,
|
||||
ClassHierarchy hierarchy, BaseWasmFunctionRepository functions,
|
||||
WasmGCSupertypeFunctionProvider supertypeFunctions, WasmGCClassInfoProvider classInfoProvider,
|
||||
WasmGCStandardClasses standardClasses, WasmGCStringProvider strings,
|
||||
|
@ -180,4 +189,36 @@ public class WasmGCGenerationContext implements BaseWasmGenerationContext {
|
|||
public WasmGCMethodReturnTypes 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.QualificationExpr;
|
||||
import org.teavm.ast.SubscriptExpr;
|
||||
import org.teavm.ast.UnwrapArrayExpr;
|
||||
import org.teavm.backend.wasm.BaseWasmFunctionRepository;
|
||||
import org.teavm.backend.wasm.WasmFunctionTypes;
|
||||
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.WasmUnreachable;
|
||||
import org.teavm.model.ClassHierarchy;
|
||||
import org.teavm.model.ElementModifier;
|
||||
import org.teavm.model.FieldReference;
|
||||
import org.teavm.model.MethodDescriptor;
|
||||
import org.teavm.model.MethodReference;
|
||||
import org.teavm.model.TextLocation;
|
||||
import org.teavm.model.ValueType;
|
||||
import org.teavm.model.classes.VirtualTable;
|
||||
|
||||
public class WasmGCGenerationVisitor extends BaseWasmGenerationVisitor {
|
||||
private WasmGCGenerationContext context;
|
||||
|
@ -136,13 +138,7 @@ public class WasmGCGenerationVisitor extends BaseWasmGenerationVisitor {
|
|||
}
|
||||
|
||||
@Override
|
||||
public void visit(UnwrapArrayExpr expr) {
|
||||
accept(expr.getArray());
|
||||
result = unwrapArray(result);
|
||||
result.setLocation(expr.getLocation());
|
||||
}
|
||||
|
||||
private WasmExpression unwrapArray(WasmExpression array) {
|
||||
protected WasmExpression unwrapArray(WasmExpression array) {
|
||||
array.acceptVisitor(typeInference);
|
||||
var arrayType = (WasmType.CompositeReference) typeInference.getResult();
|
||||
var arrayStruct = (WasmStructure) arrayType.composite;
|
||||
|
@ -202,9 +198,16 @@ public class WasmGCGenerationVisitor extends BaseWasmGenerationVisitor {
|
|||
}
|
||||
|
||||
@Override
|
||||
protected WasmExpression nullLiteral() {
|
||||
return new WasmNullConstant(expectedType instanceof WasmType.Reference
|
||||
? (WasmType.Reference) expectedType
|
||||
protected WasmExpression nullLiteral(Expr expr) {
|
||||
var type = 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);
|
||||
}
|
||||
|
||||
|
@ -252,15 +255,22 @@ public class WasmGCGenerationVisitor extends BaseWasmGenerationVisitor {
|
|||
if (vtable == null) {
|
||||
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);
|
||||
var instanceType = (WasmType.CompositeReference) typeInference.getResult();
|
||||
var instanceStruct = (WasmStructure) instanceType.composite;
|
||||
if (cls.hasModifier(ElementModifier.INTERFACE)) {
|
||||
vtable = pickVirtualTableForInterfaceCall(vtable, method.getDescriptor());
|
||||
}
|
||||
|
||||
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),
|
||||
WasmGCClassInfoProvider.CLASS_FIELD_OFFSET);
|
||||
var index = context.classInfoProvider().getVirtualMethodIndex(method);
|
||||
var index = context.classInfoProvider().getVirtualMethodsOffset() + vtableIndex;
|
||||
var vtableStruct = context.classInfoProvider().getClassInfo(vtable.getClassName())
|
||||
.getVirtualTableStructure();
|
||||
classRef = new WasmCast(classRef, vtableStruct.getReference());
|
||||
|
@ -272,6 +282,20 @@ public class WasmGCGenerationVisitor extends BaseWasmGenerationVisitor {
|
|||
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
|
||||
protected void allocateObject(String className, TextLocation location, WasmLocal local,
|
||||
List<WasmExpression> target) {
|
||||
|
|
|
@ -45,8 +45,8 @@ 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.ListableClassHolderSource;
|
||||
import org.teavm.model.MethodHolder;
|
||||
import org.teavm.model.MethodReader;
|
||||
import org.teavm.model.MethodReference;
|
||||
|
@ -58,7 +58,7 @@ import org.teavm.model.util.RegisterAllocator;
|
|||
public class WasmGCMethodGenerator implements BaseWasmFunctionRepository {
|
||||
private WasmModule module;
|
||||
private ClassHierarchy hierarchy;
|
||||
private ClassHolderSource classes;
|
||||
private ListableClassHolderSource classes;
|
||||
private VirtualTableProvider virtualTables;
|
||||
private ClassInitializerInfo classInitInfo;
|
||||
private WasmFunctionTypes functionTypes;
|
||||
|
@ -83,7 +83,7 @@ public class WasmGCMethodGenerator implements BaseWasmFunctionRepository {
|
|||
public WasmGCMethodGenerator(
|
||||
WasmModule module,
|
||||
ClassHierarchy hierarchy,
|
||||
ClassHolderSource classes,
|
||||
ListableClassHolderSource classes,
|
||||
VirtualTableProvider virtualTables,
|
||||
ClassInitializerInfo classInitInfo,
|
||||
WasmFunctionTypes functionTypes,
|
||||
|
|
|
@ -127,7 +127,7 @@ public class VirtualTableBuilder {
|
|||
}
|
||||
}
|
||||
|
||||
List<MethodDescriptor> methodsAtCallSites = methodsUsedAtCallSites.get(className);
|
||||
var methodsAtCallSites = methodsUsedAtCallSites.get(className);
|
||||
if (methodsAtCallSites != null) {
|
||||
for (MethodDescriptor methodDesc : methodsAtCallSites) {
|
||||
if (cls.hasModifier(ElementModifier.FINAL) && !table.entries.containsKey(methodDesc)) {
|
||||
|
@ -162,7 +162,7 @@ public class VirtualTableBuilder {
|
|||
}
|
||||
|
||||
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());
|
||||
targetEntry.addParent(entry.getValue());
|
||||
if (entry.getValue().implementor != null && targetEntry.implementor == null) {
|
||||
|
@ -197,7 +197,7 @@ public class VirtualTableBuilder {
|
|||
|
||||
private void liftEntries() {
|
||||
buildClassTree();
|
||||
for (Map.Entry<MethodDescriptor, List<String>> group : groupMethods().entrySet()) {
|
||||
for (var group : groupMethods().entrySet()) {
|
||||
String commonSuperclass = commonSuperclass(group.getValue());
|
||||
Set<String> visited = new HashSet<>();
|
||||
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<>();
|
||||
for (MethodDescriptor method : newMethods) {
|
||||
if (method != null) {
|
||||
methodSet.add(method);
|
||||
}
|
||||
}
|
||||
List<? extends MethodDescriptor> readonlyNewMethods = Collections.unmodifiableList(
|
||||
Arrays.asList(newMethods.toArray(new MethodDescriptor[0])));
|
||||
VirtualTable resultTable = new VirtualTable(className, parent, readonlyNewMethods,
|
||||
methodSet, resultEntries);
|
||||
var readonlyNewMethods = Collections.unmodifiableList(Arrays.asList(
|
||||
newMethods.toArray(new MethodDescriptor[0])));
|
||||
var resultTable = new VirtualTable(className, parent, readonlyNewMethods, methodSet, resultEntries);
|
||||
result.virtualTables.put(className, resultTable);
|
||||
|
||||
List<String> children = classChildren.get(className);
|
||||
|
@ -489,10 +488,9 @@ public class VirtualTableBuilder {
|
|||
methodSet.add(method);
|
||||
}
|
||||
|
||||
List<? extends MethodDescriptor> readonlyNewMethods = Collections.unmodifiableList(
|
||||
var readonlyMethods = Collections.unmodifiableList(
|
||||
Arrays.asList(methods.toArray(new MethodDescriptor[0])));
|
||||
VirtualTable resultTable = new VirtualTable(className, null, readonlyNewMethods,
|
||||
methodSet, Collections.emptyMap());
|
||||
var resultTable = new VirtualTable(className, null, readonlyMethods, methodSet, Map.of());
|
||||
result.virtualTables.put(className, resultTable);
|
||||
}
|
||||
}
|
||||
|
@ -523,7 +521,8 @@ public class VirtualTableBuilder {
|
|||
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>();
|
||||
|
||||
for (var className : classes.getClassNames()) {
|
||||
|
@ -542,12 +541,14 @@ public class VirtualTableBuilder {
|
|||
virtualMethods.add(invoke.getMethod());
|
||||
}
|
||||
} else if (insn instanceof CloneArrayInstruction) {
|
||||
if (withCloneArray) {
|
||||
virtualMethods.add(new MethodReference(Object.class, "clone", Object.class));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return virtualMethods;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue
Block a user