blob: 9cffada40249fc2caf1b58ade663e3a6e3b2fcfe [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.ir.optimize;
import com.android.tools.r8.graph.AppInfoWithClassHierarchy;
import com.android.tools.r8.graph.AppView;
import com.android.tools.r8.graph.DexClassAndMethod;
import com.android.tools.r8.graph.ProgramMethod;
import com.android.tools.r8.ir.code.BasicBlock;
import com.android.tools.r8.ir.code.BasicBlockIterator;
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.InvokeMethod;
import com.android.tools.r8.ir.code.Value;
public class CheckNotNullConverter {
public static void runIfNecessary(AppView<?> appView, IRCode code) {
if (appView.enableWholeProgramOptimizations()) {
run(appView.withClassHierarchy(), code);
}
}
/**
* Replace all calls to methods marked as a check-not-null method by a call to Object.getClass(),
* using the first argument as the receiver for the new call.
*
* <p>If the invoke has an out-value, the out-value is replaced by the first argument to allow
* removing the invoke.
*/
private static void run(AppView<? extends AppInfoWithClassHierarchy> appView, IRCode code) {
BasicBlockIterator blockIterator = code.listIterator();
while (blockIterator.hasNext()) {
BasicBlock block = blockIterator.next();
InstructionListIterator instructionIterator = block.listIterator(code);
while (instructionIterator.hasNext()) {
Instruction instruction = instructionIterator.next();
if (instruction.isInvokeMethod()) {
rewriteInvoke(appView, code, instructionIterator, instruction.asInvokeMethod());
}
}
}
}
private static void rewriteInvoke(
AppView<? extends AppInfoWithClassHierarchy> appView,
IRCode code,
InstructionListIterator instructionIterator,
InvokeMethod invoke) {
ProgramMethod context = code.context();
DexClassAndMethod singleTarget = invoke.lookupSingleTarget(appView, context);
if (singleTarget == null || !singleTarget.getOptimizationInfo().isConvertCheckNotNull()) {
return;
}
Value checkNotNullValue = invoke.getFirstNonReceiverArgument();
if (invoke.hasUsedOutValue()) {
invoke.outValue().replaceUsers(checkNotNullValue);
}
if (checkNotNullValue.getType().nullability().isDefinitelyNotNull()) {
instructionIterator.removeOrReplaceByDebugLocalRead();
} else {
instructionIterator.replaceCurrentInstructionWithNullCheck(appView, checkNotNullValue);
}
}
}