blob: 5ee91d015e87ce72509a9ac58ac24b8743ef972f [file] [log] [blame]
// Copyright (c) 2019, 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.ir.optimize;
import com.android.tools.r8.graph.AppView;
import com.android.tools.r8.graph.DexClass;
import com.android.tools.r8.graph.DexDefinitionSupplier;
import com.android.tools.r8.graph.DexEncodedMethod;
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.ir.code.IRCode;
import com.android.tools.r8.ir.code.Instruction;
import com.android.tools.r8.ir.code.InstructionListIterator;
import com.android.tools.r8.ir.code.InvokeDirect;
import com.android.tools.r8.ir.code.InvokeInterface;
import com.android.tools.r8.ir.code.InvokeMethod;
import com.android.tools.r8.ir.code.InvokeVirtual;
public class NestUtils {
public static boolean sameNest(DexType type1, DexType type2, DexDefinitionSupplier definitions) {
if (type1 == type2) {
return true;
}
DexClass clazz1 = definitions.definitionFor(type1);
if (clazz1 == null) {
// Conservatively return false
return false;
}
if (!clazz1.isInANest()) {
return false;
}
DexClass clazz2 = definitions.definitionFor(type2);
if (clazz2 == null) {
// Conservatively return false
return false;
}
return clazz1.getNestHost() == clazz2.getNestHost();
}
public static void rewriteNestCallsForInlining(
IRCode code, ProgramMethod callerContext, AppView<?> appView) {
// This method is called when inlining code into the nest member callerHolder.
InstructionListIterator iterator = code.instructionListIterator();
assert code.context().getHolder() != callerContext.getHolder();
while (iterator.hasNext()) {
Instruction instruction = iterator.next();
if (instruction.isInvokeDirect()) {
InvokeDirect invoke = instruction.asInvokeDirect();
DexMethod method = invoke.getInvokedMethod();
DexClass holder = appView.definitionForHolder(method);
DexEncodedMethod encodedMethod = method.lookupOnClass(holder);
if (encodedMethod != null && !encodedMethod.isInstanceInitializer()) {
assert encodedMethod.isPrivateMethod();
// Call to private method which has now to be interface/virtual
// (Now call to nest member private method).
if (invoke.getInterfaceBit()) {
iterator.replaceCurrentInstruction(
new InvokeInterface(method, invoke.outValue(), invoke.arguments()));
} else {
iterator.replaceCurrentInstruction(
new InvokeVirtual(method, invoke.outValue(), invoke.arguments()));
}
}
} else if (instruction.isInvokeInterface() || instruction.isInvokeVirtual()) {
InvokeMethod invoke = instruction.asInvokeMethod();
DexMethod method = invoke.getInvokedMethod();
if (method.holder == callerContext.getHolderType()) {
DexClass holder = appView.definitionForHolder(method);
DexEncodedMethod encodedMethod = method.lookupOnClass(holder);
if (encodedMethod != null && encodedMethod.isPrivateMethod()) {
// Interface/virtual nest member call to private method,
// which has now to be a direct call
// (Now call to same class private method).
iterator.replaceCurrentInstruction(
new InvokeDirect(
method,
invoke.outValue(),
invoke.arguments(),
callerContext.getHolder().isInterface()));
}
}
}
}
}
}