blob: 639be58be07074c16bfec09f0e304c48c2b670a5 [file] [log] [blame]
// Copyright (c) 2022, the R8 project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8.horizontalclassmerging;
import static com.android.tools.r8.ir.analysis.type.Nullability.definitelyNotNull;
import com.android.tools.r8.errors.Unreachable;
import com.android.tools.r8.graph.AppInfoWithClassHierarchy;
import com.android.tools.r8.graph.AppView;
import com.android.tools.r8.graph.DexField;
import com.android.tools.r8.graph.DexMethod;
import com.android.tools.r8.graph.DexType;
import com.android.tools.r8.graph.ProgramMethod;
import com.android.tools.r8.graph.lens.GraphLens;
import com.android.tools.r8.horizontalclassmerging.VirtualMethodMerger.SuperMethodReference;
import com.android.tools.r8.ir.analysis.type.TypeElement;
import com.android.tools.r8.ir.code.Value;
import com.android.tools.r8.lightir.LirBuilder;
import com.android.tools.r8.lightir.LirCode;
import com.android.tools.r8.lightir.LirEncodingStrategy;
import com.android.tools.r8.lightir.LirStrategy;
import com.android.tools.r8.utils.BooleanUtils;
import it.unimi.dsi.fastutil.ints.Int2ReferenceSortedMap;
import it.unimi.dsi.fastutil.ints.IntBidirectionalIterator;
import java.util.ArrayList;
import java.util.List;
/**
* A short-lived piece of code that will be converted into {@link LirCode} using the method {@link
* IncompleteHorizontalClassMergerCode#toLirCode(AppView, ProgramMethod,
* HorizontalClassMergerGraphLens)}.
*/
public class IncompleteVirtuallyMergedMethodCode extends IncompleteHorizontalClassMergerCode {
private final DexField classIdField;
private final Int2ReferenceSortedMap<DexMethod> mappedMethods;
private final SuperMethodReference superMethod;
public IncompleteVirtuallyMergedMethodCode(
DexField classIdField,
Int2ReferenceSortedMap<DexMethod> mappedMethods,
SuperMethodReference superMethod) {
this.mappedMethods = mappedMethods;
this.classIdField = classIdField;
this.superMethod = superMethod;
}
@Override
public void addExtraUnusedArguments(int numberOfUnusedArguments) {
throw new Unreachable();
}
public boolean hasSuperMethod() {
return superMethod != null;
}
public SuperMethodReference getSuperMethod() {
return superMethod;
}
@Override
public LirCode<Integer> toLirCode(
AppView<? extends AppInfoWithClassHierarchy> appView,
ProgramMethod method,
HorizontalClassMergerGraphLens lens) {
LirEncodingStrategy<Value, Integer> strategy =
LirStrategy.getDefaultStrategy().getEncodingStrategy();
LirBuilder<Value, Integer> lirBuilder =
LirCode.builder(
method.getReference(),
method.getDefinition().isD8R8Synthesized(),
strategy,
appView.options());
int instructionIndex = 0;
List<Value> argumentValues = new ArrayList<>();
TypeElement returnType =
method.getReturnType().isVoidType() ? null : method.getReturnType().toTypeElement(appView);
// Add receiver argument.
DexType receiverType = method.getHolderType();
TypeElement receiverTypeElement = receiverType.toTypeElement(appView, definitelyNotNull());
Value receiverValue = Value.createNoDebugLocal(instructionIndex, receiverTypeElement);
argumentValues.add(receiverValue);
strategy.defineValue(receiverValue, receiverValue.getNumber());
lirBuilder.addArgument(receiverValue.getNumber(), false);
instructionIndex++;
// Add non-receiver arguments.
for (; instructionIndex < method.getDefinition().getNumberOfArguments(); instructionIndex++) {
DexType argumentType = method.getArgumentType(instructionIndex);
TypeElement argumentTypeElement = argumentType.toTypeElement(appView);
Value argumentValue = Value.createNoDebugLocal(instructionIndex, argumentTypeElement);
argumentValues.add(argumentValue);
strategy.defineValue(argumentValue, argumentValue.getNumber());
lirBuilder.addArgument(argumentValue.getNumber(), argumentType.isBooleanType());
}
// Read class id field from receiver.
TypeElement classIdValueType = TypeElement.getInt();
Value classIdValue = Value.createNoDebugLocal(instructionIndex, classIdValueType);
strategy.defineValue(classIdValue, classIdValue.getNumber());
lirBuilder.addInstanceGet(classIdField, receiverValue);
instructionIndex++;
// Emit switch.
IntBidirectionalIterator classIdIterator = mappedMethods.keySet().iterator();
int[] keys = new int[mappedMethods.size() - BooleanUtils.intValue(!hasSuperMethod())];
int[] targets = new int[keys.length];
int nextTarget = instructionIndex - argumentValues.size() + 3;
for (int i = 0; i < keys.length; i++) {
keys[i] = classIdIterator.nextInt();
targets[i] = nextTarget;
nextTarget += 2;
}
lirBuilder.addIntSwitch(classIdValue, keys, targets);
instructionIndex++;
// Emit switch fallthrough.
if (hasSuperMethod()) {
lirBuilder.addInvokeSuper(
superMethod.getRewrittenReference(lens, method), argumentValues, false);
} else {
DexMethod fallthroughTarget =
lens.getNextMethodSignature(mappedMethods.get(mappedMethods.lastIntKey()));
if (method.getHolder().isInterface()) {
lirBuilder.addInvokeInterface(fallthroughTarget, argumentValues);
} else {
lirBuilder.addInvokeVirtual(fallthroughTarget, argumentValues);
}
}
if (method.getReturnType().isVoidType()) {
lirBuilder.addReturnVoid();
} else {
Value returnValue = Value.createNoDebugLocal(instructionIndex, returnType);
strategy.defineValue(returnValue, returnValue.getNumber());
lirBuilder.addReturn(returnValue);
}
instructionIndex += 2;
// Emit switch cases.
for (int classId : keys) {
DexMethod target = lens.getNextMethodSignature(mappedMethods.get(classId));
if (method.getHolder().isInterface()) {
lirBuilder.addInvokeInterface(target, argumentValues);
} else {
lirBuilder.addInvokeVirtual(target, argumentValues);
}
if (method.getReturnType().isVoidType()) {
lirBuilder.addReturnVoid();
} else {
Value returnValue = Value.createNoDebugLocal(instructionIndex, returnType);
strategy.defineValue(returnValue, returnValue.getNumber());
lirBuilder.addReturn(returnValue);
}
instructionIndex += 2;
}
return new LirCode<>(lirBuilder.build()) {
@Override
public boolean hasExplicitCodeLens() {
return true;
}
@Override
public GraphLens getCodeLens(AppView<?> appView) {
return lens;
}
};
}
@Override
public String toString() {
return "IncompleteVirtuallyMergedMethodCode";
}
}