| // 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.utils.positions; |
| |
| import static com.android.tools.r8.utils.positions.PositionUtils.remapAndAdd; |
| |
| import com.android.tools.r8.cf.code.CfInstruction; |
| import com.android.tools.r8.cf.code.CfLabel; |
| import com.android.tools.r8.cf.code.CfPosition; |
| import com.android.tools.r8.graph.AppView; |
| import com.android.tools.r8.graph.CfCode; |
| import com.android.tools.r8.graph.DexMethod; |
| import com.android.tools.r8.graph.ProgramMethod; |
| import com.android.tools.r8.ir.code.Position; |
| import com.android.tools.r8.ir.code.Position.SyntheticPosition; |
| import com.android.tools.r8.utils.Pair; |
| import java.util.ArrayList; |
| import java.util.List; |
| |
| public class ClassFilePositionToMappedRangeMapper implements PositionToMappedRangeMapper { |
| |
| private final AppView<?> appView; |
| |
| public ClassFilePositionToMappedRangeMapper(AppView<?> appView) { |
| this.appView = appView; |
| } |
| |
| @Override |
| public List<MappedPosition> getMappedPositions( |
| ProgramMethod method, |
| PositionRemapper positionRemapper, |
| boolean hasOverloads, |
| boolean canUseDexPc, |
| int pcEncodingCutoff) { |
| return appView.options().getTestingOptions().usePcEncodingInCfForTesting |
| ? getPcEncodedPositions(method, positionRemapper) |
| : getMappedPositionsRemapped(method, positionRemapper, hasOverloads); |
| } |
| |
| @Override |
| public void updateDebugInfoInCodeObjects() { |
| // Intentionally empty. |
| } |
| |
| private List<MappedPosition> getMappedPositionsRemapped( |
| ProgramMethod method, PositionRemapper positionRemapper, boolean hasOverloads) { |
| List<MappedPosition> mappedPositions = new ArrayList<>(); |
| // Do the actual processing for each method. |
| CfCode oldCode = method.getDefinition().getCode().asCfCode(); |
| List<CfInstruction> oldInstructions = oldCode.getInstructions(); |
| List<CfInstruction> newInstructions = new ArrayList<>(oldInstructions.size()); |
| boolean seenPosition = false; |
| for (CfInstruction oldInstruction : oldInstructions) { |
| CfInstruction newInstruction; |
| if (oldInstruction.isPosition()) { |
| seenPosition = true; |
| CfPosition cfPosition = oldInstruction.asPosition(); |
| newInstruction = |
| new CfPosition( |
| cfPosition.getLabel(), |
| remapAndAdd(cfPosition.getPosition(), positionRemapper, mappedPositions)); |
| } else { |
| newInstruction = oldInstruction; |
| } |
| newInstructions.add(newInstruction); |
| } |
| if (!seenPosition && hasOverloads) { |
| // If a method with overloads does not have an actual position then map it to the implicit |
| // preamble position. |
| DexMethod reference = method.getReference(); |
| DexMethod original = appView.graphLens().getOriginalMethodSignature(reference); |
| CfPosition preamblePositionForOverload = |
| new CfPosition( |
| new CfLabel(), |
| remapAndAdd( |
| SyntheticPosition.builder().setMethod(original).setLine(0).build(), |
| positionRemapper, |
| mappedPositions)); |
| List<CfInstruction> shiftedPositions = new ArrayList<>(oldInstructions.size() + 2); |
| shiftedPositions.add(preamblePositionForOverload); |
| shiftedPositions.add(preamblePositionForOverload.getLabel()); |
| shiftedPositions.addAll(newInstructions); |
| newInstructions = shiftedPositions; |
| } |
| method.setCode( |
| new CfCode( |
| method.getHolderType(), |
| oldCode.getMaxStack(), |
| oldCode.getMaxLocals(), |
| newInstructions, |
| oldCode.getTryCatchRanges(), |
| oldCode.getLocalVariables()), |
| appView); |
| return mappedPositions; |
| } |
| |
| private List<MappedPosition> getPcEncodedPositions( |
| ProgramMethod method, PositionRemapper positionRemapper) { |
| List<MappedPosition> mappedPositions = new ArrayList<>(); |
| // Do the actual processing for each method. |
| CfCode oldCode = method.getDefinition().getCode().asCfCode(); |
| List<CfInstruction> oldInstructions = oldCode.getInstructions(); |
| List<CfInstruction> newInstructions = new ArrayList<>(oldInstructions.size() * 3); |
| Position currentPosition = null; |
| boolean isFirstEntry = false; |
| for (CfInstruction oldInstruction : oldInstructions) { |
| if (oldInstruction.isPosition()) { |
| CfPosition cfPosition = oldInstruction.asPosition(); |
| currentPosition = cfPosition.getPosition(); |
| isFirstEntry = true; |
| } else { |
| if (currentPosition != null) { |
| Pair<Position, Position> remappedPosition = |
| positionRemapper.createRemappedPosition(currentPosition); |
| Position oldPosition = remappedPosition.getFirst(); |
| Position newPosition = remappedPosition.getSecond(); |
| mappedPositions.add(new MappedPosition(oldPosition, newPosition.getLine())); |
| CfPosition position = new CfPosition(new CfLabel(), newPosition); |
| newInstructions.add(position); |
| newInstructions.add(position.getLabel()); |
| } |
| isFirstEntry = false; |
| newInstructions.add(oldInstruction); |
| } |
| } |
| method.setCode( |
| new CfCode( |
| method.getHolderType(), |
| oldCode.getMaxStack(), |
| oldCode.getMaxLocals(), |
| newInstructions, |
| oldCode.getTryCatchRanges(), |
| oldCode.getLocalVariables()), |
| appView); |
| return mappedPositions; |
| } |
| } |