wasm gc: fix issues related to virtual calls

This commit is contained in:
Alexey Andreev 2024-08-13 19:57:48 +02:00
parent 73edc0cf6e
commit a84c5fc77f
12 changed files with 150 additions and 78 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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