blob: e464f9c0136253654ad6d1cd9561eddb6f94c5c8 [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.contexts.CompilationContext.MethodProcessingContext;
import com.android.tools.r8.graph.AppView;
import com.android.tools.r8.graph.DexItemFactory;
import com.android.tools.r8.graph.DexMethod;
import com.android.tools.r8.graph.DexProto;
import com.android.tools.r8.graph.MethodAccessFlags;
import com.android.tools.r8.graph.ProgramMethod;
import com.android.tools.r8.ir.analysis.type.DynamicType;
import com.android.tools.r8.ir.analysis.type.Nullability;
import com.android.tools.r8.ir.analysis.type.TypeAnalysis;
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.InstructionListIterator;
import com.android.tools.r8.ir.code.InvokeStatic;
import com.android.tools.r8.ir.code.NewInstance;
import com.android.tools.r8.ir.code.Value;
import com.android.tools.r8.ir.conversion.MethodProcessor;
import com.android.tools.r8.ir.desugar.backports.BackportedMethods;
import com.android.tools.r8.ir.optimize.info.OptimizationFeedback;
import com.android.tools.r8.utils.InternalOptions;
import com.google.common.collect.Sets;
import java.util.ArrayList;
import java.util.List;
import java.util.ListIterator;
import java.util.Set;
public class AssertionErrorTwoArgsConstructorRewriter {
private final AppView<?> appView;
private final DexItemFactory dexItemFactory;
private final InternalOptions options;
public AssertionErrorTwoArgsConstructorRewriter(AppView<?> appView) {
this.appView = appView;
this.options = appView.options();
this.dexItemFactory = appView.dexItemFactory();
}
public void rewrite(
IRCode code,
MethodProcessor methodProcessor,
MethodProcessingContext methodProcessingContext) {
if (options.canUseAssertionErrorTwoArgumentConstructor()) {
return;
}
Set<Value> newOutValues = Sets.newIdentityHashSet();
ListIterator<BasicBlock> blockIterator = code.listIterator();
while (blockIterator.hasNext()) {
BasicBlock block = blockIterator.next();
InstructionListIterator insnIterator = block.listIterator(code);
List<NewInstance> newInstancesToRemove = new ArrayList<>();
while (insnIterator.hasNext()) {
Instruction current = insnIterator.next();
if (current.isInvokeMethod()) {
DexMethod invokedMethod = current.asInvokeMethod().getInvokedMethod();
if (invokedMethod == dexItemFactory.assertionErrorMethods.initMessageAndCause) {
List<Value> inValues = current.inValues();
assert inValues.size() == 3; // receiver, message, cause
Value newInstanceValue = current.getFirstOperand();
Instruction definition = newInstanceValue.getDefinition();
if (!definition.isNewInstance()) {
continue;
}
InvokeStatic invoke =
InvokeStatic.builder()
.setMethod(
createSynthetic(methodProcessor, methodProcessingContext).getReference())
.setFreshOutValue(
code, dexItemFactory.assertionErrorType.toTypeElement(appView))
.setPosition(current)
.setArguments(inValues.subList(1, 3))
.build();
insnIterator.replaceCurrentInstruction(invoke);
newInstanceValue.replaceUsers(invoke.outValue());
newOutValues.add(invoke.outValue());
newInstancesToRemove.add(definition.asNewInstance());
}
}
}
newInstancesToRemove.forEach(
newInstance -> newInstance.removeOrReplaceByDebugLocalRead(code));
}
if (!newOutValues.isEmpty()) {
new TypeAnalysis(appView).widening(newOutValues);
}
assert code.isConsistentSSA(appView);
}
private final List<ProgramMethod> synthesizedMethods = new ArrayList<>();
public List<ProgramMethod> getSynthesizedMethods() {
return synthesizedMethods;
}
private ProgramMethod createSynthetic(
MethodProcessor methodProcessor, MethodProcessingContext methodProcessingContext) {
DexItemFactory factory = appView.dexItemFactory();
DexProto proto =
factory.createProto(factory.assertionErrorType, factory.stringType, factory.throwableType);
ProgramMethod method =
appView
.getSyntheticItems()
.createMethod(
kinds -> kinds.BACKPORT,
methodProcessingContext.createUniqueContext(),
appView,
builder ->
builder
.setApiLevelForCode(appView.computedMinApiLevel())
.setProto(proto)
.setAccessFlags(MethodAccessFlags.createPublicStaticSynthetic())
.setCode(
methodSig ->
BackportedMethods.AssertionErrorMethods_createAssertionError(
factory, methodSig)));
synchronized (synthesizedMethods) {
synthesizedMethods.add(method);
OptimizationFeedback.getSimpleFeedback()
.setDynamicReturnType(
method,
appView,
DynamicType.createExact(
dexItemFactory
.assertionErrorType
.toTypeElement(appView, Nullability.definitelyNotNull())
.asClassType()));
}
methodProcessor
.getEventConsumer()
.acceptAssertionErrorCreateMethod(method, methodProcessingContext.getMethodContext());
return method;
}
}