blob: ed4cfbe1545311d72a6e6c549b38ba95a2c47714 [file] [log] [blame]
package com.android.tools.r8.ir.desugar;
import com.android.tools.r8.graph.AppView;
import com.android.tools.r8.graph.DexEncodedMethod;
import com.android.tools.r8.graph.DexField;
import com.android.tools.r8.graph.DexMethod;
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.InvokeDirect;
import com.android.tools.r8.ir.code.InvokeMethod;
import com.android.tools.r8.ir.code.InvokeStatic;
import com.android.tools.r8.ir.code.Value;
import java.util.ArrayList;
import java.util.IdentityHashMap;
import java.util.List;
import java.util.ListIterator;
import java.util.Map;
public class NestBasedAccessDesugaringRewriter extends NestBasedAccessDesugaring {
private Map<DexMethod, DexMethod> methodMap = new IdentityHashMap<>();
private Map<DexMethod, DexMethod> initializerMap = new IdentityHashMap<>();
private final Map<DexField, DexMethod> staticGetToMethodMap = new IdentityHashMap<>();
private final Map<DexField, DexMethod> staticPutToMethodMap = new IdentityHashMap<>();
private final Map<DexField, DexMethod> instanceGetToMethodMap = new IdentityHashMap<>();
private final Map<DexField, DexMethod> instancePutToMethodMap = new IdentityHashMap<>();
public NestBasedAccessDesugaringRewriter(AppView<?> appView) {
super(appView);
}
@Override
protected void shouldRewriteCalls(DexMethod method, DexMethod bridge) {
methodMap.put(method, bridge);
}
@Override
protected void shouldRewriteInitializers(DexMethod method, DexMethod bridge) {
initializerMap.put(method, bridge);
}
@Override
protected void shouldRewriteStaticGetFields(DexField field, DexMethod bridge) {
staticGetToMethodMap.put(field, bridge);
}
@Override
protected void shouldRewriteStaticPutFields(DexField field, DexMethod bridge) {
staticPutToMethodMap.put(field, bridge);
}
@Override
protected void shouldRewriteInstanceGetFields(DexField field, DexMethod bridge) {
instanceGetToMethodMap.put(field, bridge);
}
@Override
protected void shouldRewriteInstancePutFields(DexField field, DexMethod bridge) {
instancePutToMethodMap.put(field, bridge);
}
private void rewriteFieldAccess(
Instruction instruction,
InstructionListIterator instructions,
DexMethod method,
Map<DexField, DexMethod> fieldToMethodMap) {
DexField field = instruction.asFieldInstruction().getField();
DexMethod newTarget = fieldToMethodMap.get(field);
if (newTarget != null && method != newTarget) {
instructions.replaceCurrentInstruction(
new InvokeStatic(newTarget, instruction.outValue(), instruction.inValues()));
}
}
public void rewriteNestBasedAccesses(
DexEncodedMethod encodedMethod, IRCode code, AppView<?> appView) {
ListIterator<BasicBlock> blocks = code.listIterator();
while (blocks.hasNext()) {
BasicBlock block = blocks.next();
InstructionListIterator instructions = block.listIterator();
while (instructions.hasNext()) {
Instruction instruction = instructions.next();
if (instruction.isInvokeMethod() && !instruction.isInvokeSuper()) {
InvokeMethod invokeMethod = instruction.asInvokeMethod();
DexMethod methodCalled = invokeMethod.getInvokedMethod();
DexMethod newTarget = methodMap.get(methodCalled);
if (newTarget != null && encodedMethod.method != newTarget) {
instructions.replaceCurrentInstruction(
new InvokeStatic(newTarget, invokeMethod.outValue(), invokeMethod.arguments()));
} else {
newTarget = initializerMap.get(methodCalled);
if (newTarget != null && encodedMethod.method != newTarget) {
// insert extra null value and replace call.
instructions.previous();
Value extraNullValue =
instructions.insertConstNullInstruction(code, appView.options());
instructions.next();
List<Value> parameters = new ArrayList<>(invokeMethod.arguments());
parameters.add(extraNullValue);
instructions.replaceCurrentInstruction(
new InvokeDirect(newTarget, invokeMethod.outValue(), parameters));
}
}
} else if (instruction.isInstanceGet()) {
rewriteFieldAccess(
instruction, instructions, encodedMethod.method, instanceGetToMethodMap);
} else if (instruction.isInstancePut()) {
rewriteFieldAccess(
instruction, instructions, encodedMethod.method, instancePutToMethodMap);
} else if (instruction.isStaticGet()) {
rewriteFieldAccess(instruction, instructions, encodedMethod.method, staticGetToMethodMap);
} else if (instruction.isStaticPut()) {
rewriteFieldAccess(instruction, instructions, encodedMethod.method, staticPutToMethodMap);
}
}
}
}
}