blob: 914b1742783f716d69e6c8dc12ad29881275196c [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.DexDebugInfo;
import com.android.tools.r8.graph.ProgramMethod;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
public interface PositionToMappedRangeMapper {
List<MappedPosition> getMappedPositions(
ProgramMethod method,
PositionRemapper positionRemapper,
boolean hasOverloads,
boolean canUseDexPc,
int pcEncodingCutoff);
void updateDebugInfoInCodeObjects();
static PositionToMappedRangeMapper create(AppView<?> appView) {
return appView.options().isGeneratingClassFiles()
? new ClassFilePositionToMappedRangeMapper(appView)
: new DexPositionToMappedRangeMapper(appView);
}
class DexPositionToMappedRangeMapper implements PositionToMappedRangeMapper {
private final DexPositionToNoPcMappedRangeMapper noPcMapper;
private final DexPositionToPcMappedRangeMapper pcMapper;
private final PcBasedDebugInfoRecorder pcBasedDebugInfoRecorder;
private DexPositionToMappedRangeMapper(AppView<?> appView) {
pcBasedDebugInfoRecorder =
appView.options().canUseNativeDexPcInsteadOfDebugInfo()
? new NativePcSupport()
: new Pc2PcMappingSupport();
noPcMapper = new DexPositionToNoPcMappedRangeMapper(appView);
pcMapper = new DexPositionToPcMappedRangeMapper(appView, pcBasedDebugInfoRecorder);
}
@Override
public List<MappedPosition> getMappedPositions(
ProgramMethod method,
PositionRemapper positionRemapper,
boolean hasOverloads,
boolean canUseDexPc,
int pcEncodingCutoff) {
return canUseDexPc
? pcMapper.optimizeDexCodePositionsForPc(method, positionRemapper, pcEncodingCutoff)
: noPcMapper.optimizeDexCodePositions(method, positionRemapper, hasOverloads);
}
@Override
public void updateDebugInfoInCodeObjects() {
pcBasedDebugInfoRecorder.updateDebugInfoInCodeObjects();
}
}
interface PcBasedDebugInfoRecorder {
/** Callback to record a code object with a given max instruction PC and parameter count. */
void recordPcMappingFor(ProgramMethod method, int maxEncodingPc);
/**
* Install the correct debug info objects.
*
* <p>Must be called after all recordings have been given to allow computing the debug info
* items to be installed.
*/
void updateDebugInfoInCodeObjects();
int getPcEncoding(int pc);
}
class Pc2PcMappingSupport implements PcBasedDebugInfoRecorder {
private static class UpdateInfo {
final DexCode code;
final int paramCount;
final int maxEncodingPc;
public UpdateInfo(DexCode code, int paramCount, int maxEncodingPc) {
this.code = code;
this.paramCount = paramCount;
this.maxEncodingPc = maxEncodingPc;
}
// Used as key when building the shared debug info map.
// Only param and max-pc are part of the key.
@Override
public boolean equals(Object o) {
UpdateInfo that = (UpdateInfo) o;
return paramCount == that.paramCount && maxEncodingPc == that.maxEncodingPc;
}
@Override
public int hashCode() {
return Objects.hash(paramCount, maxEncodingPc);
}
}
private final List<UpdateInfo> codesToUpdate = new ArrayList<>();
@Override
public int getPcEncoding(int pc) {
assert pc >= 0;
return pc + 1;
}
@Override
public void recordPcMappingFor(ProgramMethod method, int maxEncodingPc) {
assert method.getDefinition().getCode().isDexCode();
int parameterCount = method.getParameters().size();
DexCode code = method.getDefinition().getCode().asDexCode();
assert DebugRepresentation.verifyLastExecutableInstructionWithinBound(code, maxEncodingPc);
codesToUpdate.add(new UpdateInfo(code, parameterCount, maxEncodingPc));
}
@Override
public void updateDebugInfoInCodeObjects() {
Map<UpdateInfo, DexDebugInfo> debugInfos = new HashMap<>();
codesToUpdate.forEach(
entry -> {
assert DebugRepresentation.verifyLastExecutableInstructionWithinBound(
entry.code, entry.maxEncodingPc);
DexDebugInfo debugInfo =
debugInfos.computeIfAbsent(entry, Pc2PcMappingSupport::buildPc2PcDebugInfo);
assert debugInfo.asPcBasedInfo().getMaxPc() == entry.maxEncodingPc;
entry.code.setDebugInfo(debugInfo);
});
}
private static DexDebugInfo buildPc2PcDebugInfo(UpdateInfo info) {
return new DexDebugInfo.PcBasedDebugInfo(info.paramCount, info.maxEncodingPc);
}
}
class NativePcSupport implements PcBasedDebugInfoRecorder {
@Override
public int getPcEncoding(int pc) {
assert pc >= 0;
return pc;
}
private void clearDebugInfo(ProgramMethod method) {
// Always strip the info in full as the runtime will emit the PC directly.
method.getDefinition().getCode().asDexCode().setDebugInfo(null);
}
@Override
public void recordPcMappingFor(ProgramMethod method, int maxEncodingPc) {
clearDebugInfo(method);
}
@Override
public void updateDebugInfoInCodeObjects() {
// Already null out the info so nothing to do.
}
}
}