blob: 40f80b48d486d7d26c2865845983b1304e030dbb [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.utils.positions;
import com.android.tools.r8.debuginfo.DebugRepresentation;
import com.android.tools.r8.graph.AppView;
import com.android.tools.r8.graph.DexCode;
import com.android.tools.r8.graph.DexDebugEvent;
import com.android.tools.r8.graph.DexDebugEvent.Default;
import com.android.tools.r8.graph.DexDebugEventVisitor;
import com.android.tools.r8.graph.DexDebugInfo;
import com.android.tools.r8.graph.DexDebugInfo.EventBasedDebugInfo;
import com.android.tools.r8.graph.DexDebugPositionState;
import com.android.tools.r8.graph.DexEncodedMethod;
import com.android.tools.r8.graph.ProgramMethod;
import com.android.tools.r8.ir.code.Position;
import com.android.tools.r8.utils.IntBox;
import com.android.tools.r8.utils.Pair;
import com.android.tools.r8.utils.positions.PositionToMappedRangeMapper.PcBasedDebugInfoRecorder;
import java.util.ArrayList;
import java.util.List;
public class DexPositionToPcMappedRangeMapper {
private final AppView<?> appView;
private final PcBasedDebugInfoRecorder pcBasedDebugInfo;
public DexPositionToPcMappedRangeMapper(
AppView<?> appView, PcBasedDebugInfoRecorder pcBasedDebugInfo) {
this.appView = appView;
this.pcBasedDebugInfo = pcBasedDebugInfo;
}
public List<MappedPosition> optimizeDexCodePositionsForPc(
ProgramMethod method, PositionRemapper positionRemapper, int pcEncodingCutoff) {
List<MappedPosition> mappedPositions = new ArrayList<>();
// Do the actual processing for each method.
DexCode dexCode = method.getDefinition().getCode().asDexCode();
EventBasedDebugInfo debugInfo =
getEventBasedDebugInfo(method.getDefinition(), dexCode, appView);
IntBox firstDefaultEventPc = new IntBox(-1);
Pair<Integer, Position> lastPosition = new Pair<>();
DexDebugEventVisitor visitor =
new DexDebugPositionState(
debugInfo.startLine,
appView.graphLens().getOriginalMethodSignature(method.getReference())) {
@Override
public void visit(Default defaultEvent) {
super.visit(defaultEvent);
assert getCurrentLine() >= 0;
if (firstDefaultEventPc.get() < 0) {
firstDefaultEventPc.set(getCurrentPc());
}
Position currentPosition = getPosition();
if (lastPosition.getSecond() != null) {
remapAndAddForPc(
pcBasedDebugInfo,
lastPosition.getFirst(),
getCurrentPc(),
lastPosition.getSecond(),
positionRemapper,
mappedPositions);
}
lastPosition.setFirst(getCurrentPc());
lastPosition.setSecond(currentPosition);
}
};
for (DexDebugEvent event : debugInfo.events) {
event.accept(visitor);
}
int lastInstructionPc = DebugRepresentation.getLastExecutableInstruction(dexCode).getOffset();
if (lastPosition.getSecond() != null) {
remapAndAddForPc(
pcBasedDebugInfo,
lastPosition.getFirst(),
lastInstructionPc + 1,
lastPosition.getSecond(),
positionRemapper,
mappedPositions);
}
assert !mappedPositions.isEmpty() || dexCode.instructions.length == 1;
pcBasedDebugInfo.recordPcMappingFor(method, pcEncodingCutoff);
return mappedPositions;
}
private static void remapAndAddForPc(
PcBasedDebugInfoRecorder debugInfoProvider,
int startPc,
int endPc,
Position position,
PositionRemapper remapper,
List<MappedPosition> mappedPositions) {
Pair<Position, Position> remappedPosition = remapper.createRemappedPosition(position);
Position oldPosition = remappedPosition.getFirst();
for (int currentPc = startPc; currentPc < endPc; currentPc++) {
mappedPositions.add(
new MappedPosition(oldPosition, debugInfoProvider.getPcEncoding(currentPc)));
}
}
// This conversion *always* creates an event based debug info encoding as any non-info will
// be created as an implicit PC encoding.
private static EventBasedDebugInfo getEventBasedDebugInfo(
DexEncodedMethod method, DexCode dexCode, AppView<?> appView) {
// TODO(b/213411850): Do we need to reconsider conversion here to support pc-based D8 merging?
if (dexCode.getDebugInfo() == null) {
return DexDebugInfo.createEventBasedInfoForMethodWithoutDebugInfo(
method, appView.dexItemFactory());
}
assert method.getParameters().size() == dexCode.getDebugInfo().getParameterCount();
EventBasedDebugInfo debugInfo =
DexDebugInfo.convertToEventBased(dexCode, appView.dexItemFactory());
assert debugInfo != null;
return debugInfo;
}
private static boolean verifyIdentityMapping(
EventBasedDebugInfo originalDebugInfo, EventBasedDebugInfo optimizedDebugInfo) {
assert optimizedDebugInfo.startLine == originalDebugInfo.startLine;
assert optimizedDebugInfo.events.length == originalDebugInfo.events.length;
for (int i = 0; i < originalDebugInfo.events.length; ++i) {
assert optimizedDebugInfo.events[i].equals(originalDebugInfo.events[i]);
}
return true;
}
}