blob: d835003c201d87b91070553a1873ca4f25deea7d [file] [log] [blame]
// Copyright (c) 2017, 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;
import com.android.tools.r8.ToolHelper;
import com.android.tools.r8.graph.AppView;
import com.android.tools.r8.graph.DexApplication;
import com.android.tools.r8.graph.DexEncodedMethod;
import com.android.tools.r8.ir.code.BasicBlock;
import com.android.tools.r8.ir.code.IRCode;
import com.android.tools.r8.ir.code.Instruction;
import com.android.tools.r8.ir.code.InstructionIterator;
import com.android.tools.r8.ir.code.InstructionListIterator;
import com.android.tools.r8.ir.code.NumberGenerator;
import com.android.tools.r8.ir.code.Phi;
import com.android.tools.r8.ir.conversion.IRConverter;
import com.android.tools.r8.ir.conversion.MethodConversionOptions;
import com.android.tools.r8.smali.SmaliBuilder.MethodSignature;
import com.android.tools.r8.smali.SmaliTestBase;
import com.android.tools.r8.utils.AndroidApp;
import com.android.tools.r8.utils.AndroidAppConsumers;
import com.android.tools.r8.utils.InternalOptions;
import com.android.tools.r8.utils.ListUtils;
import com.android.tools.r8.utils.Timing;
import com.android.tools.r8.utils.codeinspector.CodeInspector;
import com.android.tools.r8.utils.codeinspector.MethodSubject;
import com.google.common.collect.ImmutableList;
import java.io.IOException;
import java.util.List;
import java.util.concurrent.ExecutionException;
import java.util.function.Function;
public class IrInjectionTestBase extends SmaliTestBase {
protected MethodSubject getMethodSubject(DexApplication application, MethodSignature signature) {
return getMethodSubject(
application,
signature.clazz,
signature.returnType,
signature.name,
signature.parameterTypes);
}
protected MethodSubject getMethodSubject(
DexApplication application,
String className,
String returnType,
String methodName,
List<String> parameters) {
CodeInspector inspector = new CodeInspector(application);
return getMethodSubject(inspector, className, returnType, methodName, parameters);
}
public class TestApplication {
public final DexApplication application;
public final AppView<?> appView;
public final DexEncodedMethod method;
public final IRCode code;
public final List<IRCode> additionalCode;
public final AndroidAppConsumers consumers;
public final NumberGenerator valueNumberGenerator = new NumberGenerator();
public TestApplication(AppView<?> appView, MethodSubject method) {
this(appView, method, ImmutableList.of());
}
public TestApplication(
AppView<?> appView,
MethodSubject method,
List<Function<AppView<?>, IRCode>> additionalCode) {
this.application = appView.appInfo().app();
this.appView = appView;
this.method = method.getMethod();
appView.testing().skipLirPhasesForTestingFinalOutput();
this.code =
method
.getProgramMethod()
.buildIR(appView, MethodConversionOptions.forPostLirPhase(appView));
code.removeRedundantBlocks();
this.additionalCode = ListUtils.map(additionalCode, fn -> fn.apply(appView));
this.consumers = new AndroidAppConsumers(appView.options());
int largestValueNumber = -1;
for (BasicBlock block : code.blocks) {
for (Phi phi : block.getPhis()) {
largestValueNumber = Math.max(largestValueNumber, phi.getNumber());
}
for (Instruction instruction : block.getInstructions()) {
if (instruction.hasOutValue()) {
largestValueNumber = Math.max(largestValueNumber, instruction.outValue().getNumber());
}
}
}
while (valueNumberGenerator.peek() <= largestValueNumber) {
valueNumberGenerator.next();
}
}
public int countArgumentInstructions() {
int count = 0;
InstructionIterator iterator = code.entryBlock().iterator();
while (iterator.next().isArgument()) {
count++;
}
return count;
}
public InstructionListIterator listIteratorAt(BasicBlock block, int index) {
InstructionListIterator iterator = block.listIterator(code);
for (int i = 0; i < index; i++) {
iterator.next();
}
return iterator;
}
private AndroidApp writeDex() {
try {
InternalOptions options = appView.options();
ToolHelper.writeApplication(appView);
options.signalFinishedToConsumers();
return consumers.build();
} catch (ExecutionException e) {
throw new RuntimeException(e);
}
}
public String run() throws IOException {
Timing timing = Timing.empty();
IRConverter converter = new IRConverter(appView);
code.removeRedundantBlocks();
converter.replaceCodeForTesting(code);
AndroidApp app = writeDex();
return runOnArtRaw(app, DEFAULT_MAIN_CLASS_NAME).stdout;
}
}
}